25 use,
intrinsic :: ieee_exceptions
28 use,
intrinsic :: iso_fortran_env
40 minimize_multidim_nograd, &
41 minimize_multidim_nlopt
44 integer,
public,
parameter :: &
45 MINMETHOD_STEEPEST_DESCENT = 1, &
67 integer,
intent(in) :: n
68 real(real64),
intent(in) :: x(n)
69 real(real64),
intent(inout) :: val
70 integer,
intent(in) :: getgrad
71 real(real64),
intent(inout) :: grad(n)
73 subroutine info_i(iter, n, val, maxdr, maxgrad, x)
76 integer,
intent(in) :: iter
77 integer,
intent(in) :: n
78 real(real64),
intent(in) :: val
79 real(real64),
intent(in) :: maxdr
80 real(real64),
intent(in) :: maxgrad
81 real(real64),
intent(in) :: x(n)
86 integer,
intent(in) :: iter
87 integer,
intent(in) :: n
88 real(real64),
intent(in) :: val
89 real(real64),
intent(in) :: maxdr
90 real(real64),
intent(in) :: x(n)
96 subroutine oct_1dminimize(a, b, m, f, status)
99 real(real64),
intent(inout) :: a, b, m
104 real(real64),
intent(in) :: x
105 real(real64),
intent(out) :: fx
108 integer,
intent(out) :: status
109 end subroutine oct_1dminimize
112 interface loct_minimize
113 integer function oct_minimize(method, dim, x, step, line_tol, &
114 tolgrad, toldr, maxiter, f, write_iter_info, minimum)
117 integer,
intent(in) :: method
118 integer,
intent(in) :: dim
119 real(real64),
intent(inout) :: x
120 real(real64),
intent(in) :: step
121 real(real64),
intent(in) :: line_tol
122 real(real64),
intent(in) :: tolgrad
123 real(real64),
intent(in) :: toldr
124 integer,
intent(in) :: maxiter
125 procedure(minimizer_with_grad_i) :: f
126 procedure(info_i) :: write_iter_info
127 real(real64),
intent(out) :: minimum
128 end function oct_minimize
129 end interface loct_minimize
131 interface loct_minimize_direct
132 function oct_minimize_direct(method, dim, x, step, toldr, maxiter, f, write_iter_info, minimum)
135 integer :: oct_minimize_direct
136 integer,
intent(in) :: method
137 integer,
intent(in) :: dim
138 real(real64),
intent(inout) :: x
139 real(real64),
intent(in) :: step
140 real(real64),
intent(in) :: toldr
141 integer,
intent(in) :: maxiter
144 real(real64),
intent(out) :: minimum
145 end function oct_minimize_direct
146 end interface loct_minimize_direct
150 subroutine minimize_multidim_nograd(method, dim, x, step, toldr, maxiter, f, write_iter_info, minimum, ierr)
151 integer,
intent(in) :: method
152 integer,
intent(in) :: dim
153 real(real64),
intent(inout) :: x(:)
154 real(real64),
intent(in) :: step
155 real(real64),
intent(in) :: toldr
156 integer,
intent(in) :: maxiter
159 real(real64),
intent(out) :: minimum
160 integer,
intent(out) :: ierr
162 push_sub(minimize_multidim_nograd)
164 assert(ubound(x, dim = 1) >= dim)
169 ierr = loct_minimize_direct(method, dim, x(1), step, toldr, maxiter, f, write_iter_info, minimum)
172 pop_sub(minimize_multidim_nograd)
174 end subroutine minimize_multidim_nograd
177 subroutine minimize_multidim_nlopt(ierr, method, dim, x, step, toldr, maxiter, f, minimum, lb, ub)
178 integer,
intent(out) :: ierr
179 integer,
intent(in) :: method
180 integer,
intent(in) :: dim
181 real(real64),
contiguous,
intent(inout) :: x(:)
182 real(real64),
intent(in) :: step
183 real(real64),
intent(in) :: toldr
184 integer,
intent(in) :: maxiter
186 subroutine f(val, n, x, grad, need_gradient, f_data)
188 real(c_double),
intent(out) :: val
189 integer(c_int),
intent(in) :: n
190 real(c_double),
intent(in) :: x(*)
191 real(c_double),
intent(out) :: grad(*)
192 integer(c_int),
intent(in) :: need_gradient
193 type(c_ptr),
intent(in) :: f_data
196 real(real64),
intent(out) :: minimum
197 real(real64),
intent(in),
optional :: lb(:), ub(:)
198#if defined(HAVE_NLOPT)
201 subroutine nlo_create(opt, alg, n)
203 type(c_ptr),
intent(out) :: opt
204 integer(c_int),
intent(in) :: alg
205 integer(c_int),
intent(in) :: n
206 end subroutine nlo_create
208 subroutine nlo_set_lower_bounds(ret, opt, lower_bounds)
210 integer(c_int),
intent(out) :: ret
211 type(c_ptr),
intent(inout) :: opt
212 real(c_double),
intent(in) :: lower_bounds(*)
213 end subroutine nlo_set_lower_bounds
215 subroutine nlo_set_upper_bounds(ret, opt, upper_bounds)
217 integer(c_int),
intent(out) :: ret
218 type(c_ptr),
intent(inout) :: opt
219 real(c_double),
intent(in) :: upper_bounds(*)
220 end subroutine nlo_set_upper_bounds
222 subroutine nlo_set_min_objective(ret, opt, f, f_data)
224 integer(c_int),
intent(out) :: ret
225 type(c_ptr),
intent(inout) :: opt
227 subroutine f(val, n, x, grad, need_gradient, f_data)
229 real(c_double),
intent(out) :: val
230 integer(c_int),
intent(in) :: n
231 real(c_double),
intent(in) :: x(*)
232 real(c_double),
intent(out) :: grad(*)
233 integer(c_int),
intent(in) :: need_gradient
234 type(c_ptr),
intent(in) :: f_data
237 type(c_ptr),
intent(in) :: f_data
238 end subroutine nlo_set_min_objective
240 subroutine nlo_set_xtol_abs1(ret, opt, xtol_abs)
242 integer(c_int),
intent(out) :: ret
243 type(c_ptr),
intent(inout) :: opt
244 real(c_double),
intent(in) :: xtol_abs
245 end subroutine nlo_set_xtol_abs1
247 subroutine nlo_set_initial_step1(ret, opt, initial_step1)
249 integer(c_int),
intent(out) :: ret
250 type(c_ptr),
intent(inout) :: opt
251 real(c_double),
intent(in) :: initial_step1
252 end subroutine nlo_set_initial_step1
254 subroutine nlo_set_maxeval(ret, opt, maxeval)
256 integer(c_int),
intent(out) :: ret
257 type(c_ptr),
intent(inout) :: opt
258 integer(c_int),
intent(in) :: maxeval
259 end subroutine nlo_set_maxeval
261 subroutine nlo_optimize(ret, opt, x, optf)
263 integer(c_int),
intent(out) :: ret
264 type(c_ptr),
intent(inout) :: opt
265 real(c_double),
intent(inout) :: x(*)
266 real(c_double),
intent(out) :: optf
267 end subroutine nlo_optimize
269 subroutine nlo_destroy(opt)
271 type(c_ptr),
intent(inout) :: opt
272 end subroutine nlo_destroy
274 integer(c_int) function nlopt_algorithm_from_string(name)
bind(c)
276 character(kind=c_char),
intent(in) :: name(*)
277 end function nlopt_algorithm_from_string
282 integer(c_int) :: algorithm
284 logical :: halting_mode(size(ieee_all))
290 call ieee_get_halting_mode(ieee_all, halting_mode)
291 call ieee_set_halting_mode(ieee_all, .false.)
298 algorithm = nlopt_algorithm_from_string(
"LN_BOBYQA"//c_null_char)
300 algorithm = nlopt_algorithm_from_string(
"LD_LBFGS"//c_null_char)
304 if (algorithm < 0_c_int)
then
305 message(1) =
"The requested algorithm is not available in the linked NLopt library."
310 call nlo_create(opt, algorithm, dim)
312 if (
present(lb))
then
313 call nlo_set_lower_bounds(ires, opt, lb)
315 if (
present(ub))
then
316 call nlo_set_upper_bounds(ires, opt, ub)
319 call nlo_set_min_objective(ires, opt,
f, c_null_ptr)
323 call nlo_set_xtol_abs1(ires, opt, toldr)
324 call nlo_set_initial_step1(ires, opt, step)
325 call nlo_set_maxeval(ires, opt, maxiter)
327 call nlo_optimize(ires, opt, x, minimum)
329 call nlo_destroy(opt)
331 call ieee_set_halting_mode(ieee_all, halting_mode)
337 end subroutine minimize_multidim_nlopt
341 subroutine minimize_multidim(method, dim, x, step, line_tol, tolgrad, toldr, maxiter, f, write_iter_info, minimum, ierr)
342 integer,
intent(in) :: method
343 integer,
intent(in) :: dim
344 real(real64),
intent(inout) :: x(:)
345 real(real64),
intent(in) :: step
346 real(real64),
intent(in) :: line_tol
347 real(real64),
intent(in) :: tolgrad
348 real(real64),
intent(in) :: toldr
349 integer,
intent(in) :: maxiter
351 procedure(
info_i) :: write_iter_info
352 real(real64),
intent(out) :: minimum
353 integer,
intent(out) :: ierr
355 push_sub(minimize_multidim)
357 assert(ubound(x, dim = 1) >= dim)
361 call minimize_sd(dim, x, step, maxiter, f, write_iter_info, minimum, ierr)
364 ierr = loct_minimize(method, dim, x(1), step, line_tol, tolgrad, toldr, maxiter, f, write_iter_info, minimum)
368 pop_sub(minimize_multidim)
370 end subroutine minimize_multidim
374 subroutine minimize_sd(dim, x, step, maxiter, f, write_iter_info, minimum, ierr)
375 integer,
intent(in) :: dim
376 real(real64),
intent(inout) :: x(:)
377 real(real64),
intent(in) :: step
378 integer,
intent(in) :: maxiter
380 procedure(
info_i) :: write_iter_info
381 real(real64),
intent(out) :: minimum
382 integer,
intent(out) :: ierr
385 real(real64),
allocatable :: grad(:)
386 real(real64) :: step2, maxgrad
388 push_sub(minimize_sd)
390 safe_allocate(grad(1:dim))
392 step2 = step*10.0_real64
394 call f(dim, x, minimum, 1, grad)
396 maxgrad = maxval(abs(grad))
398 call write_iter_info(iter, dim, minimum, maxgrad*step2, maxgrad, x)
400 x(1:dim) = x(1:dim) - step2*grad(1:dim)
402 step2 = step2*0.99_real64
407 end subroutine minimize_sd
423 subroutine minimize_fire(dim, space_dim, x, step, tolgrad, maxiter, gradf, write_iter_info, en, ierr, mass, integrator)
424 integer,
intent(in) :: dim
425 integer,
intent(in) :: space_dim
426 real(real64),
intent(inout) :: x(:)
427 real(real64),
intent(in) :: step
428 real(real64),
intent(in) :: tolgrad
429 integer,
intent(in) :: maxiter
431 procedure(
info_i) :: write_iter_info
432 real(real64),
intent(out) :: en
433 integer,
intent(out) :: ierr
434 real(real64),
intent(in) :: mass(:)
435 integer,
intent(in) :: integrator
437 real(real64),
allocatable :: grad(:)
439 integer :: p_times, n_times, iter, ia
440 real(real64) :: dt, alpha, p_value, dt_max, dt_min, mix
441 real(real64),
allocatable :: grad_atoms(:), vel(:), dr_i(:), x_old(:), dr_atoms(:)
444 integer,
parameter :: n_min = 5, n_decrease_max = 500
445 real(real64),
parameter :: f_alpha = 0.99_real64
446 real(real64),
parameter :: f_inc = 1.1_real64
447 real(real64),
parameter :: f_dec = 0.5_real64
448 real(real64),
parameter :: alpha_start = 0.25_real64
450 real(real64),
parameter :: tol_zero_forces = 1e-10_real64
452 push_sub(minimize_fire)
455 assert(mod(dim,space_dim) == 0)
456 assert(
size(x) == dim)
458 safe_allocate(grad_atoms(1:dim/space_dim))
459 safe_allocate(grad(1:dim))
460 safe_allocate(vel(1:dim))
461 safe_allocate(dr_atoms(1:dim/space_dim))
462 safe_allocate(x_old(1:dim))
463 safe_allocate(dr_i(1:dim))
471 dt_max = 10.0_real64 * dt
472 dt_min = 0.02_real64 * dt
475 call gradf(dim, x, en, 1, grad)
481 p_value = dot_product(grad, vel)
484 if (p_value >
m_zero)
then
485 p_times = p_times + 1
487 if (p_times > n_min)
then
488 dt = min(dt * f_inc , dt_max)
489 alpha = alpha * f_alpha
493 n_times = n_times + 1
495 if (n_times > n_decrease_max)
exit
497 if (iter >= n_min)
then
498 dt = max(dt * f_dec, dt_min)
514 if (mix > tol_zero_forces)
then
520 select case (integrator)
521 case (option__gofireintegrator__verlet)
523 vel = vel +
m_half * grad * dt / mass
526 if (p_value >
m_zero)
then
527 vel = (
m_one - alpha) * vel + alpha * mix * grad *
lalg_nrm2(dim, vel)
532 call prevent_large_changes(dim, space_dim, dr_i, dr_atoms)
536 call gradf(dim, x, en, 1, grad)
540 vel = vel +
m_half * grad * dt / mass
542 case (option__gofireintegrator__euler)
544 if (p_value >
m_zero)
then
545 vel = (
m_one - alpha) * vel + alpha * mix * grad *
lalg_nrm2(dim, vel)
550 call prevent_large_changes(dim, space_dim, dr_i, dr_atoms)
554 call gradf(dim, x, en, 1, grad)
558 vel = vel + grad * dt / mass
561 case (option__gofireintegrator__semi_implicit_euler)
563 vel = vel + grad * dt / mass
566 if (p_value >
m_zero)
then
572 call prevent_large_changes(dim, space_dim, dr_i, dr_atoms)
576 call gradf(dim, x, en, 1, grad)
581 do ia = 0, dim/space_dim - 1
582 grad_atoms(ia+1) = norm2(grad(space_dim*ia+1:space_dim*ia+space_dim))
586 call write_iter_info(iter, dim, en, maxval(dr_atoms), maxval(abs(grad_atoms)), x)
589 if (maxval(abs(grad_atoms(1:))) < tolgrad)
exit
594 safe_deallocate_a(dr_atoms)
595 safe_deallocate_a(x_old)
596 safe_deallocate_a(dr_i)
597 safe_deallocate_a(vel)
598 safe_deallocate_a(grad)
599 safe_deallocate_a(grad_atoms)
601 pop_sub(minimize_fire)
602 end subroutine minimize_fire
607 subroutine prevent_large_changes(dim, space_dim, dr_i, dr_atoms)
608 integer,
intent(in) :: dim
609 integer,
intent(in) :: space_dim
610 real(real64),
intent(inout) :: dr_i(:), dr_atoms(:)
612 integer :: i1, i2, ia
614 real(real64),
parameter :: maxmove = 0.2_real64 *
p_ang
617 do ia = 0, dim/space_dim - 1
619 i2 = space_dim*ia+space_dim
620 dr_atoms(ia+1) = norm2(dr_i(i1:i2))
622 if (dr_atoms(ia+1) > maxmove)
then
623 dr_i(i1:i2) = maxmove * dr_i(i1:i2) / dr_atoms(ia+1)
624 dr_atoms(ia+1) = maxmove
627 end subroutine prevent_large_changes
Returns the euclidean norm of a vector.
real(real64), parameter, public m_huge
real(real64), parameter, public m_zero
real(real64), parameter, public p_ang
real(real64), parameter, public m_half
real(real64), parameter, public m_one
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
integer, parameter, public minmethod_fr_cg
integer, parameter, public minmethod_bfgs
integer, parameter, public minmethod_nmsimplex
integer, parameter, public minmethod_bfgs2
integer, parameter, public minmethod_nlopt_bobyqa
integer, parameter, public minmethod_nlopt_lbfgs
integer, parameter, public minmethod_pr_cg
integer, parameter, public minmethod_fire
integer, parameter, public minmethod_sd_native
static double f(double w, void *p)