31 #include "./base/base_uses.f90"
37 CHARACTER(len=*),
PARAMETER,
PRIVATE :: moduleN =
'linesearch'
39 PUBLIC :: linesearch_type
41 INTEGER,
PARAMETER :: linesearch_method_adapt = 1
42 INTEGER,
PARAMETER :: linesearch_method_2pnt = 2
43 INTEGER,
PARAMETER :: linesearch_method_3pnt = 3
44 INTEGER,
PARAMETER :: linesearch_method_gold = 4
45 INTEGER,
PARAMETER :: linesearch_method_none = 5
47 TYPE linesearch_2pnt_type
48 REAL(KIND=
dp),
DIMENSION(2) :: energies = 0.0
49 REAL(KIND=
dp) :: scan_step = 0.0
50 REAL(KIND=
dp) :: last_step_size = 0.0
51 REAL(KIND=
dp) :: max_step_size = 0.0
53 END TYPE linesearch_2pnt_type
55 TYPE linesearch_3pnt_type
56 REAL(KIND=
dp),
DIMENSION(3) :: energies = 0.0
57 REAL(KIND=
dp),
DIMENSION(3) :: scan_steps = 0.0
58 REAL(KIND=
dp) :: last_step_size = 0.0
59 REAL(KIND=
dp) :: max_step_size = 0.0
60 REAL(KIND=
dp) :: tiny_step_size = 0.0
62 END TYPE linesearch_3pnt_type
64 TYPE linesearch_adapt_type
65 REAL(KIND=
dp) :: last_step_size = 0.0
66 REAL(KIND=
dp) :: left_x = 0.0
67 REAL(KIND=
dp) :: middle_x = 0.0
68 REAL(KIND=
dp) :: right_x = 0.0
69 REAL(KIND=
dp) :: left_e = 0.0
70 REAL(KIND=
dp) :: middle_e = 0.0
71 REAL(KIND=
dp) :: right_e = 0.0
72 LOGICAL :: have_left = .false.
73 LOGICAL :: have_middle = .false.
74 LOGICAL :: have_right = .false.
76 END TYPE linesearch_adapt_type
78 TYPE linesearch_gold_type
79 REAL(KIND=
dp) :: scan_steps = 0.0
80 REAL(KIND=
dp) :: last_step_size = 0.0
81 REAL(KIND=
dp) :: eps_step_size = 0.0
82 REAL(KIND=
dp) :: left_x = 0.0
83 REAL(KIND=
dp) :: middle_x = 0.0
84 REAL(KIND=
dp) :: right_x = 0.0
85 REAL(KIND=
dp) :: left_e = 0.0
86 REAL(KIND=
dp) :: middle_e = 0.0
87 REAL(KIND=
dp) :: right_e = 0.0
88 LOGICAL :: have_left = .false.
89 LOGICAL :: have_middle = .false.
90 LOGICAL :: have_right = .false.
91 LOGICAL :: gave_up = .false.
92 END TYPE linesearch_gold_type
96 REAL(KIND=
dp),
PUBLIC :: step_size = 0.0_dp
97 LOGICAL,
PUBLIC :: starts = .false.
98 TYPE(linesearch_adapt_type),
POINTER :: state_adapt => null()
99 TYPE(linesearch_2pnt_type),
POINTER :: state_2pnt => null()
100 TYPE(linesearch_3pnt_type),
POINTER :: state_3pnt => null()
101 TYPE(linesearch_gold_type),
POINTER :: state_gold => null()
103 INTEGER :: method = -1
104 CHARACTER(LEN=10) :: label =
""
105 REAL(KIND=
dp) :: init_step_size = 0.0_dp
106 REAL(dp) :: eps_step_size = 0.0_dp
107 REAL(dp) :: max_step_size = 0.0_dp
108 REAL(dp) :: tiny_step_size = 0.0_dp
109 END TYPE linesearch_type
122 TYPE(section_type),
POINTER :: section
124 TYPE(keyword_type),
POINTER :: keyword
125 TYPE(section_type),
POINTER :: print_section, printkey
127 NULLIFY (keyword, print_section, printkey)
129 cpassert(.NOT.
ASSOCIATED(section))
130 CALL section_create(section, __location__, name=
"LINE_SEARCH", repeats=.false., &
131 description=
"Detail settings or linesearch method.")
134 keyword, __location__, name=
"METHOD", &
135 description=
"Linesearch method.", &
136 default_i_val=linesearch_method_adapt, &
137 enum_c_vals=s2a(
"ADAPT",
"3PNT",
"2PNT",
"GOLD",
"NONE"), &
138 enum_desc=s2a(
"extrapolates usually based on 3 points, uses additional points on demand, very robust.", &
139 "extrapolate based on 3 points", &
140 "extrapolate based on 2 points and the slope (super fast, but might get stuck at saddle points)", &
141 "perform 1D golden section search of the minimum (very expensive)", &
142 "always take steps of fixed INITIAL_STEP_SIZE"), &
143 enum_i_vals=(/linesearch_method_adapt, linesearch_method_3pnt, linesearch_method_2pnt, &
144 linesearch_method_gold, linesearch_method_none/))
148 CALL keyword_create(keyword, __location__, name=
"INITIAL_STEP_SIZE", &
149 description=
"Initial step length", &
150 default_r_val=0.1_dp)
154 CALL keyword_create(keyword, __location__, name=
"MAX_STEP_SIZE", &
155 description=
"Maximum step length", &
156 default_r_val=3.0_dp)
160 CALL keyword_create(keyword, __location__, name=
"TINY_STEP_SIZE", &
161 description=
"Step length taken if negative step is suggested.", &
162 default_r_val=0.002_dp)
166 CALL keyword_create(keyword, __location__, name=
"EPS_STEP_SIZE", &
167 description=
"Convergence criterion of GOLD method.", &
168 default_r_val=0.1_dp)
173 description=
"Print section", &
174 n_keywords=0, n_subsections=1, repeats=.true.)
177 description=
"General run information", &
195 TYPE(linesearch_type),
INTENT(INOUT) :: this
196 TYPE(section_vals_type),
POINTER :: section
197 CHARACTER(LEN=*) :: label
199 TYPE(cp_logger_type),
POINTER :: logger
207 cpassert(len_trim(label) <= 10)
211 extension=
".linesearchlog")
213 CALL linesearch_init_low(this)
222 SUBROUTINE linesearch_init_low(this)
223 TYPE(linesearch_type),
INTENT(INOUT) :: this
225 this%step_size = 0.0_dp
228 SELECT CASE (this%method)
229 CASE (linesearch_method_adapt)
230 ALLOCATE (this%state_adapt)
231 this%state_adapt%last_step_size = this%init_step_size
232 CASE (linesearch_method_2pnt)
233 ALLOCATE (this%state_2pnt)
234 this%state_2pnt%max_step_size = this%max_step_size
235 this%state_2pnt%last_step_size = this%init_step_size
236 CASE (linesearch_method_3pnt)
237 ALLOCATE (this%state_3pnt)
238 this%state_3pnt%last_step_size = this%init_step_size
239 this%state_3pnt%max_step_size = this%max_step_size
240 this%state_3pnt%tiny_step_size = this%tiny_step_size
241 CASE (linesearch_method_gold)
242 ALLOCATE (this%state_gold)
243 this%state_gold%last_step_size = this%init_step_size
244 this%state_gold%eps_step_size = this%eps_step_size
245 CASE (linesearch_method_none)
248 cpabort(
"unknown method")
251 END SUBROUTINE linesearch_init_low
259 TYPE(linesearch_type),
INTENT(INOUT) :: this
261 SELECT CASE (this%method)
262 CASE (linesearch_method_adapt)
263 DEALLOCATE (this%state_adapt)
264 CASE (linesearch_method_2pnt)
265 DEALLOCATE (this%state_2pnt)
266 CASE (linesearch_method_3pnt)
267 DEALLOCATE (this%state_3pnt)
268 CASE (linesearch_method_gold)
269 DEALLOCATE (this%state_gold)
270 CASE (linesearch_method_none)
273 cpabort(
"unknown method")
285 TYPE(linesearch_type),
INTENT(INOUT) :: this
288 CALL linesearch_init_low(this)
299 TYPE(linesearch_type),
INTENT(INOUT) :: this
300 REAL(kind=
dp),
INTENT(IN) :: energy, slope
303 REAL(kind=
dp) :: step_size
305 SELECT CASE (this%method)
306 CASE (linesearch_method_adapt)
307 CALL linesearch_adapt(this%state_adapt, energy, step_size, is_done, this%iw, trim(this%label))
308 CASE (linesearch_method_2pnt)
309 CALL linesearch_2pnt(this%state_2pnt, energy, slope, step_size, is_done, this%iw, trim(this%label))
310 CASE (linesearch_method_3pnt)
311 CALL linesearch_3pnt(this%state_3pnt, energy, step_size, is_done, this%iw, trim(this%label))
312 CASE (linesearch_method_gold)
313 CALL linesearch_gold(this%state_gold, energy, step_size, is_done, this%iw, trim(this%label))
314 CASE (linesearch_method_none)
315 step_size = this%init_step_size
318 cpabort(
"unknown method")
321 this%step_size = step_size
322 this%starts = is_done
336 SUBROUTINE linesearch_2pnt(this, energy, slope, step_size, is_done, unit_nr, label)
337 TYPE(linesearch_2pnt_type),
INTENT(INOUT) :: this
338 REAL(kind=
dp),
INTENT(IN) :: energy, slope
339 REAL(kind=
dp),
INTENT(OUT) :: step_size
340 LOGICAL,
INTENT(OUT) :: is_done
341 INTEGER,
INTENT(IN) :: unit_nr
342 CHARACTER(len=*),
INTENT(IN) :: label
344 REAL(kind=
dp) :: a, b, c, pred_energy, x2
346 this%energies(this%count) = energy
349 SELECT CASE (this%count)
351 step_size = 2.0_dp*this%last_step_size
352 this%scan_step = step_size
358 a = (this%energies(2) - b*x2 - c)/(x2**2)
361 IF (unit_nr > 0)
WRITE (unit_nr, *) label,
"LS| had to quench curvature"
365 step_size = -b/(2.0_dp*a)
366 pred_energy = a*step_size**2 + b*step_size + c
368 IF (unit_nr > 0)
WRITE (unit_nr, *) label,
"LS| 2pnt suggested step_size: ", step_size
369 IF (unit_nr > 0)
WRITE (unit_nr, *) label,
"LS| 2pnt predicted energy", pred_energy
371 IF (pred_energy > this%energies(1) .OR. pred_energy > this%energies(2))
THEN
372 cpabort(label//
"LS| predicted energy not below test points")
375 IF (step_size > this%max_step_size)
THEN
376 step_size = this%max_step_size
377 IF (unit_nr > 0)
WRITE (unit_nr, *) label,
"LS| limiting step_size to MAX_STEP_SIZE"
380 this%last_step_size = step_size
384 cpabort(
"this should not happen")
387 END SUBROUTINE linesearch_2pnt
399 SUBROUTINE linesearch_3pnt(this, energy, step_size, is_done, unit_nr, label)
400 TYPE(linesearch_3pnt_type),
INTENT(INOUT) :: this
401 REAL(kind=
dp),
INTENT(IN) :: energy
402 REAL(kind=
dp),
INTENT(OUT) :: step_size
403 LOGICAL,
INTENT(OUT) :: is_done
404 INTEGER,
INTENT(IN) :: unit_nr
405 CHARACTER(len=*),
INTENT(IN) :: label
407 REAL(kind=
dp) :: a, b, c, denom, pred_energy, x1, x2, x3, &
410 this%energies(this%count) = energy
413 SELECT CASE (this%count)
415 step_size = (2.0_dp/3.0_dp)*this%last_step_size
416 IF (step_size < this%tiny_step_size)
THEN
417 IF (unit_nr > 0)
WRITE (unit_nr, *) label,
"LS| initial step size too small, using TINY_STEP_SIZE"
418 step_size = this%tiny_step_size
420 this%scan_steps(1) = 0.0_dp
421 this%scan_steps(2) = step_size
424 IF (this%energies(1) > this%energies(2))
THEN
425 step_size = 2.0_dp*this%scan_steps(2)
427 step_size = 0.5_dp*this%scan_steps(2)
429 this%scan_steps(3) = step_size
433 y1 = this%energies(1); y2 = this%energies(2); y3 = this%energies(3)
434 x1 = this%scan_steps(1); x2 = this%scan_steps(2); x3 = this%scan_steps(3)
436 IF (unit_nr > 0)
WRITE (unit_nr, *) label,
"LS| 3pnt scan_steps: ", this%scan_steps
437 IF (unit_nr > 0)
WRITE (unit_nr, *) label,
"LS| 3pnt energies: ", this%energies
440 denom = (x1 - x2)*(x1 - x3)*(x2 - x3)
441 a = (x3*(y2 - y1) + x2*(y1 - y3) + x1*(y3 - y2))/denom
442 b = (x3**2*(y1 - y2) + x2**2*(y3 - y1) + x1**2*(y2 - y3))/denom
443 c = (x2*x3*(x2 - x3)*y1 + x3*x1*(x3 - x1)*y2 + x1*x2*(x1 - x2)*y3)/denom
445 step_size = -b/(2.0_dp*a)
446 pred_energy = a*step_size**2 + b*step_size + c
447 IF (unit_nr > 0)
WRITE (unit_nr, *) label,
"LS| 3pnt suggested step_size: ", step_size
448 IF (unit_nr > 0)
WRITE (unit_nr, *) label,
"LS| 3pnt predicted energy", pred_energy
451 step_size = -2.0_dp*step_size
452 IF (unit_nr > 0)
WRITE (unit_nr, *) label,
"LS| inverting step size"
455 IF (step_size < 0)
THEN
456 step_size = this%tiny_step_size
457 IF (unit_nr > 0)
WRITE (unit_nr, *) label,
"LS| makeing a step of size TINY_STEP_SIZE"
460 IF (step_size > this%max_step_size)
THEN
461 step_size = this%max_step_size
462 IF (unit_nr > 0)
WRITE (unit_nr, *) label,
"LS| limiting step_size to MAX_STEP_SIZE"
465 this%last_step_size = step_size
469 cpabort(
"this should not happen")
472 END SUBROUTINE linesearch_3pnt
484 SUBROUTINE linesearch_adapt(this, energy, step_size, is_done, unit_nr, label)
485 TYPE(linesearch_adapt_type),
INTENT(INOUT) :: this
486 REAL(kind=
dp),
INTENT(IN) :: energy
487 REAL(kind=
dp),
INTENT(OUT) :: step_size
488 LOGICAL,
INTENT(OUT) :: is_done
489 INTEGER,
INTENT(IN) :: unit_nr
490 CHARACTER(len=*),
INTENT(IN) :: label
492 REAL(kind=
dp),
PARAMETER :: grow_factor = 2.0_dp, &
493 shrink_factor = 0.5_dp
495 REAL(kind=
dp) :: a, b, c, denom, pred_energy, x1, x2, x3, &
499 this%count = this%count + 1
501 IF (.NOT. this%have_left)
THEN
504 this%have_left = .true.
505 step_size = this%last_step_size
507 ELSE IF (.NOT. (this%have_middle .OR. this%have_right))
THEN
508 IF (energy < this%left_e)
THEN
509 this%middle_e = energy
510 this%middle_x = this%last_step_size
511 this%have_middle = .true.
512 step_size = this%middle_x*grow_factor
514 this%right_e = energy
515 this%right_x = this%last_step_size
516 this%have_right = .true.
517 step_size = this%right_x*shrink_factor
520 ELSE IF (.NOT. this%have_right)
THEN
521 IF (energy < this%middle_e)
THEN
522 this%middle_e = energy
523 this%middle_x = this%last_step_size
524 step_size = this%middle_x*grow_factor
526 this%right_e = energy
527 this%right_x = this%last_step_size
528 this%have_right = .true.
531 ELSE IF (.NOT. this%have_middle)
THEN
532 IF (energy > this%left_e)
THEN
533 this%right_e = energy
534 this%right_x = this%last_step_size
535 step_size = this%right_x*shrink_factor
537 this%middle_e = energy
538 this%middle_x = this%last_step_size
539 this%have_middle = .true.
543 IF (this%count > 3)
THEN
544 IF (unit_nr > 0)
WRITE (unit_nr, *) label,
"LS| Need extra step"
546 IF (unit_nr > 0)
WRITE (unit_nr, *) label,
"LS| adapt: ", this%have_left, this%have_middle, this%have_right
547 IF (unit_nr > 0)
WRITE (unit_nr, *) label,
"LS| adapt: scan_steps: ", this%left_x, this%middle_x, this%right_x
548 IF (unit_nr > 0)
WRITE (unit_nr, *) label,
"LS| adapt: energies: ", this%left_e, this%middle_e, this%right_e
550 IF (this%have_left .AND. this%have_middle .AND. this%have_right)
THEN
552 y1 = this%left_e; y2 = this%middle_e; y3 = this%right_e
553 x1 = this%left_x; x2 = this%middle_x; x3 = this%right_x
556 denom = (x1 - x2)*(x1 - x3)*(x2 - x3)
557 a = (x3*(y2 - y1) + x2*(y1 - y3) + x1*(y3 - y2))/denom
558 b = (x3**2*(y1 - y2) + x2**2*(y3 - y1) + x1**2*(y2 - y3))/denom
559 c = (x2*x3*(x2 - x3)*y1 + x3*x1*(x3 - x1)*y2 + x1*x2*(x1 - x2)*y3)/denom
561 IF (abs(a) /= 0.0_dp)
THEN
562 step_size = -b/(2.0_dp*a)
567 cpassert(step_size >= 0.0_dp)
568 pred_energy = a*step_size**2 + b*step_size + c
569 IF (unit_nr > 0)
WRITE (unit_nr, *) label,
"LS| adapt: suggested step_size: ", step_size
570 IF (unit_nr > 0)
WRITE (unit_nr, *) label,
"LS| adapt: predicted energy", pred_energy
575 this%have_left = .false.
576 this%have_middle = .false.
577 this%have_right = .false.
586 this%last_step_size = step_size
587 END SUBROUTINE linesearch_adapt
599 SUBROUTINE linesearch_gold(this, energy, step_size, is_done, unit_nr, label)
600 TYPE(linesearch_gold_type),
INTENT(INOUT) :: this
601 REAL(kind=
dp),
INTENT(IN) :: energy
602 REAL(kind=
dp),
INTENT(OUT) :: step_size
603 LOGICAL,
INTENT(OUT) :: is_done
604 INTEGER,
INTENT(IN) :: unit_nr
605 CHARACTER(len=*),
INTENT(IN) :: label
607 REAL(kind=
dp),
PARAMETER :: phi = (1.0_dp + sqrt(5.0_dp))/2.0_dp
609 REAL(kind=
dp) :: a, b, d
614 cpabort(
"had to give up, should not be called again")
616 IF (.NOT. this%have_left)
THEN
619 this%have_left = .true.
620 step_size = this%last_step_size
622 ELSE IF (.NOT. (this%have_middle .OR. this%have_right))
THEN
623 IF (energy < this%left_e)
THEN
624 this%middle_e = energy
625 this%middle_x = this%scan_steps
626 this%have_middle = .true.
627 step_size = this%middle_x*phi
629 this%right_e = energy
630 this%right_x = this%scan_steps
631 this%have_right = .true.
632 step_size = this%right_x/phi
635 ELSE IF (.NOT. this%have_right)
THEN
636 IF (energy < this%middle_e)
THEN
637 this%middle_e = energy
638 this%middle_x = this%scan_steps
639 step_size = this%middle_x*phi
641 this%right_e = energy
642 this%right_x = this%scan_steps
643 this%have_right = .true.
646 ELSE IF (.NOT. this%have_middle)
THEN
647 IF (energy > this%left_e)
THEN
648 this%right_e = energy
649 this%right_x = this%scan_steps
650 step_size = this%right_x/phi
652 this%middle_e = energy
653 this%middle_x = this%scan_steps
654 this%have_middle = .true.
658 a = this%middle_x - this%left_x
659 b = this%right_x - this%middle_x
660 IF (energy < this%middle_e)
THEN
662 this%left_e = this%middle_e
663 this%left_x = this%middle_x
665 this%right_e = this%middle_e
666 this%right_x = this%middle_x
668 this%middle_e = energy
669 this%middle_x = this%scan_steps
672 this%right_e = energy
673 this%right_x = this%scan_steps
676 this%left_x = this%scan_steps
681 IF (unit_nr > 0)
WRITE (unit_nr, *) label,
"LS| gold: ", this%have_left, this%have_middle, this%have_right
682 IF (unit_nr > 0)
WRITE (unit_nr, *) label,
"LS| gold: ", this%left_x, this%middle_x, this%right_x
683 IF (unit_nr > 0)
WRITE (unit_nr, *) label,
"LS| gold: ", this%left_e, this%middle_e, this%right_e
685 IF (this%have_left .AND. this%have_middle .AND. this%have_right)
THEN
686 a = this%middle_x - this%left_x
687 b = this%right_x - this%middle_x
688 IF (abs(min(a, b)*phi - max(a, b)) > 1.0e-10) &
689 cpabort(
"golden-ratio gone")
692 step_size = this%middle_x + a/phi
694 step_size = this%middle_x - b/phi
697 d = abs(this%right_x - this%left_x)/(abs(this%middle_x) + abs(step_size))
698 IF (d < this%eps_step_size)
THEN
699 step_size = this%middle_x
700 this%last_step_size = step_size
703 IF (unit_nr > 0)
WRITE (unit_nr, *) label,
"LS| gold done, step-size: ", step_size
705 this%have_left = .false.
706 this%have_middle = .false.
707 this%have_right = .false.
718 IF (step_size < 1e-10) cpabort(
"linesearch failed / done")
720 this%scan_steps = step_size
721 END SUBROUTINE linesearch_gold
various routines to log and control the output. The idea is that decisions about where to log should ...
type(cp_logger_type) function, pointer, public cp_get_default_logger()
returns the default logger
routines to handle the output, The idea is to remove the decision of wheter to output and what to out...
integer function, public cp_print_key_unit_nr(logger, basis_section, print_key_path, extension, middle_name, local, log_filename, ignore_should_output, file_form, file_position, file_action, file_status, do_backup, on_file, is_new_file, mpi_io, fout)
...
integer, parameter, public low_print_level
integer, parameter, public add_last_numeric
subroutine, public cp_print_key_section_create(print_key_section, location, name, description, print_level, each_iter_names, each_iter_values, add_last, filename, common_iter_levels, citations, unit_str)
creates a print_key section
Defines the basic variable types.
integer, parameter, public dp
A generic framework to calculate step lengths for 1D line search.
subroutine, public linesearch_create_section(section)
Declare the line search input section.
subroutine, public linesearch_finalize(this)
Finzalize line search machinery.
subroutine, public linesearch_init(this, section, label)
Initialize linesearch from given input section.
subroutine, public linesearch_reset(this)
Reset line search to initial state.
subroutine, public linesearch_step(this, energy, slope)
Calculate step length of next line search step.
Utilities for string manipulations.