Octopus
opt_control_iter.F90
Go to the documentation of this file.
1!! Copyright (C) 2002-2006 M. Marques, A. Castro, A. Rubio, G. Bertsch
2!!
3!! This program is free software; you can redistribute it and/or modify
4!! it under the terms of the GNU General Public License as published by
5!! the Free Software Foundation; either version 2, or (at your option)
6!! any later version.
7!!
8!! This program is distributed in the hope that it will be useful,
9!! but WITHOUT ANY WARRANTY; without even the implied warranty of
10!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11!! GNU General Public License for more details.
12!!
13!! You should have received a copy of the GNU General Public License
14!! along with this program; if not, write to the Free Software
15!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16!! 02110-1301, USA.
17!!
18
19#include "global.h"
20
23 use debug_oct_m
24 use global_oct_m
25 use grid_oct_m
26 use io_oct_m
27 use, intrinsic :: iso_fortran_env
30 use parser_oct_m
33
34 implicit none
35
36 private
37 public :: &
49
50
52 private
53 real(real64) :: eps
54 integer :: ctr_iter_max
55 integer :: ctr_iter
56 integer :: ctr_iter_main
57 real(real64) :: bestJ1
58 real(real64) :: bestJ1_fluence
59 real(real64) :: bestJ1_J
60 integer :: bestJ1_ctr_iter
61 type(controlfunction_t) :: best_par
62 integer :: convergence_iunit
63 integer :: velocities_iunit
64 logical :: dump_intermediate
65 end type oct_iterator_t
66
67contains
68
69
70 ! ---------------------------------------------------------
71 subroutine oct_iterator_init(iterator, namespace, par)
72 type(oct_iterator_t), intent(inout) :: iterator
73 type(namespace_t), intent(in) :: namespace
74 type(controlfunction_t), intent(in) :: par
75
76 push_sub(oct_iterator_init)
77
78 !%Variable OCTEps
79 !%Type float
80 !%Section Calculation Modes::Optimal Control
81 !%Default 1.0e-6
82 !%Description
83 !% Define the convergence threshold. It computes the difference between the "input"
84 !% field in the iterative procedure, and the "output" field. If this difference is
85 !% less than <tt>OCTEps</tt> the iteration is stopped. This difference is defined as:
86 !%
87 !% <math>
88 !% D[\varepsilon^{in},\varepsilon^{out}] = \int_0^T dt \left| \varepsilon^{in}(t)-\varepsilon^{out}(t)\right|^2
89 !% </math>
90 !%
91 !% (If there are several control fields, this difference is defined as the sum over
92 !% all the individual differences.)
93 !%
94 !% Whenever this condition is satisfied, it means that we have reached a solution point
95 !% of the QOCT equations, <i>i.e.</i> a critical point of the QOCT functional (not
96 !% necessarily a maximum, and not necessarily the global maximum).
97 !%End
98 call parse_variable(namespace, 'OCTEps', 1.0e-6_real64, iterator%eps)
99 if (iterator%eps < m_zero) iterator%eps = tiny(m_one)
100
101 !%Variable OCTMaxIter
102 !%Type integer
103 !%Section Calculation Modes::Optimal Control
104 !%Default 10
105 !%Description
106 !% The maximum number of iterations.
107 !% Typical values range from 10-100.
108 !%End
109 call parse_variable(namespace, 'OCTMaxIter', 10, iterator%ctr_iter_max)
110
111 if (iterator%ctr_iter_max < 0 .and. iterator%eps < m_zero) then
112 message(1) = "OCTMaxIter and OCTEps cannot be both < 0."
113 call messages_fatal(1, namespace=namespace)
114 end if
115 if (iterator%ctr_iter_max < 0) iterator%ctr_iter_max = huge(iterator%ctr_iter_max)
116
117 !%Variable OCTDumpIntermediate
118 !%Type logical
119 !%Section Calculation Modes::Optimal Control
120 !%Default true
121 !%Description
122 !% Writes to disk the laser pulse data during the OCT algorithm at intermediate steps.
123 !% These are files called <tt>opt_control/laser.xxxx</tt>, where <tt>xxxx</tt> is the iteration number.
124 !%End
125 call parse_variable(namespace, 'OCTDumpIntermediate', .false., iterator%dump_intermediate)
126 call messages_print_var_value("OCTDumpIntermediate", iterator%dump_intermediate, namespace=namespace)
127
128 iterator%ctr_iter = 0
129 iterator%ctr_iter_main = 0
130 iterator%bestJ1 = -huge(iterator%bestJ1)
131 iterator%bestJ1_fluence = m_zero
132 iterator%bestJ1_J = m_zero
133 iterator%bestJ1_ctr_iter = 0
134
135 call controlfunction_copy(iterator%best_par, par)
136
137 iterator%convergence_iunit = io_open(oct_dir//'convergence', namespace, action='write')
138
139 write(iterator%convergence_iunit, '(91(''#''))')
140 write(iterator%convergence_iunit, '(5(a))') '# iteration', ' J[Psi,chi,epsilon]', &
141 ' J_1[Psi]', &
142 ' J_2[epsilon]', &
143 ' Delta'
144 write(iterator%convergence_iunit, '(91(''#''))')
145
146 if (parse_is_defined(namespace, 'OCTVelocityTarget')) then
147 iterator%velocities_iunit = io_open(oct_dir//'velocities', namespace, action='write')
148 end if
151 end subroutine oct_iterator_init
152 ! ---------------------------------------------------------
155 ! ---------------------------------------------------------
156 subroutine oct_iterator_end(iterator, namespace)
157 type(oct_iterator_t), intent(inout) :: iterator
158 type(namespace_t), intent(in) :: namespace
159
160 push_sub(oct_iterator_end)
161
162 call controlfunction_write(oct_dir//'laser.bestJ1', iterator%best_par, namespace)
163
164 call controlfunction_end(iterator%best_par)
165 write(iterator%convergence_iunit, '(91("#"))')
166 call io_close(iterator%convergence_iunit)
167
168 if (parse_is_defined(namespace, 'OCTVelocityTarget')) then
169 call io_close(iterator%velocities_iunit)
170 end if
171
172 pop_sub(oct_iterator_end)
173 end subroutine oct_iterator_end
174 ! ---------------------------------------------------------
175
176
177 ! ---------------------------------------------------------
178 logical function iteration_manager(namespace, j1, par, par_prev, iterator) result(stoploop)
179 type(namespace_t), intent(in) :: namespace
180 real(real64), intent(in) :: j1
181 type(controlfunction_t), intent(in) :: par
182 type(controlfunction_t), intent(in) :: par_prev
183 type(oct_iterator_t), intent(inout) :: iterator
184
185 real(real64) :: fluence, jfunctional, j2, delta
186 logical :: bestj1
187
188 push_sub(iteration_manager)
189
190 if (iterator%dump_intermediate) call iterator_write(namespace, iterator, par)
191
192 stoploop = .false.
193
194 fluence = controlfunction_fluence(par)
195 j2 = controlfunction_j2(par)
196 jfunctional = j1 + j2
197 delta = controlfunction_diff(par, par_prev)
198
199 if (iterator%ctr_iter == iterator%ctr_iter_max) then
200 message(1) = "Info: Maximum number of iterations reached."
201 call messages_info(1, namespace=namespace)
202 stoploop = .true.
203 end if
204
205 if ((iterator%eps > m_zero) .and. &
206 (delta < iterator%eps) .and. &
207 (iterator%ctr_iter > 0)) then
208 message(1) = "Info: Convergence threshold reached."
209 call messages_info(1, namespace=namespace)
210 stoploop = .true.
211 end if
212
213 write(message(1), '(a,i5)') 'Optimal control iteration #', iterator%ctr_iter
214 call messages_print_with_emphasis(msg=trim(message(1)), namespace=namespace)
215
216 write(message(1), '(6x,a,f12.5)') " => J1 = ", j1
217 write(message(2), '(6x,a,f12.5)') " => J = ", jfunctional
218 write(message(3), '(6x,a,f12.5)') " => J2 = ", j2
219 write(message(4), '(6x,a,f12.5)') " => Fluence = ", fluence
220 write(message(5), '(6x,a,f12.5)') " => Penalty = ", controlfunction_alpha(par, 1)
221 write(message(6), '(6x,a,es12.2)') " => D[e,e'] = ", delta
222 if (iterator%ctr_iter /= 0) then
223 call messages_info(6, namespace=namespace)
224 else
225 call messages_info(5, namespace=namespace)
226 end if
227 call messages_print_with_emphasis(namespace=namespace)
228
229 bestj1 = (j1 > iterator%bestj1)
230 ! store field with best J1
231 if (bestj1) then
232 iterator%bestJ1 = j1
233 iterator%bestJ1_J = jfunctional
234 iterator%bestJ1_fluence = fluence
235 iterator%bestJ1_ctr_iter = iterator%ctr_iter
236 call controlfunction_end(iterator%best_par)
237 call controlfunction_copy(iterator%best_par, par)
238 if (.not. iterator%dump_intermediate) call controlfunction_write(oct_dir//'laser.bestJ1', &
239 iterator%best_par, namespace)
240 end if
241
242 write(iterator%convergence_iunit, '(i11,4f20.8)') &
243 iterator%ctr_iter, jfunctional, j1, j2, controlfunction_diff(par, par_prev)
244
245 iterator%ctr_iter = iterator%ctr_iter + 1
246
247 pop_sub(iteration_manager)
248 end function iteration_manager
249 ! ---------------------------------------------------------
250
251
252 ! ---------------------------------------------------------
253 subroutine iteration_manager_direct(j, par, iterator, sys, dx)
254 real(real64), intent(in) :: j
255 type(controlfunction_t), intent(in) :: par
256 type(oct_iterator_t), intent(inout) :: iterator
257 type(electrons_t), intent(in) :: sys
258 real(real64), optional, intent(in) :: dx
259
260 real(real64) :: j1, j2, fluence, delta
262
263 if (iterator%dump_intermediate) call iterator_write(sys%namespace, iterator, par)
264
265 fluence = controlfunction_fluence(par)
266 j2 = controlfunction_j2(par)
267 j1 = j - j2
268
269 if (present(dx)) then
270 delta = dx
271 else
272 delta = m_zero
273 end if
274
275 if (iterator%ctr_iter == 0) then
276 call messages_print_with_emphasis(msg='Initial-guess field', namespace=sys%namespace)
277 else
278 write(message(1), '(a,i5)') 'Function evaluation #', iterator%ctr_iter
279 call messages_print_with_emphasis(msg=trim(message(1)), namespace=sys%namespace)
280 end if
281
282 write(message(1), '(6x,a,f12.5)') " => J1 = ", j1
283 write(message(2), '(6x,a,f12.5)') " => J = ", j
284 write(message(3), '(6x,a,f12.5)') " => J2 = ", j2
285 write(message(4), '(6x,a,f12.5)') " => Fluence = ", fluence
286 call messages_info(4, namespace=sys%namespace)
287 if (present(dx)) then
288 write(message(1), '(6x,a,f12.5)') " => Delta = ", dx
289 call messages_info(1, namespace=sys%namespace)
290 end if
291 call messages_print_with_emphasis(namespace=sys%namespace)
292
293 ! store field with best J1
294 if (j1 > iterator%bestJ1) then
295 iterator%bestJ1 = j1
296 iterator%bestJ1_J = j
297 iterator%bestJ1_fluence = fluence
298 iterator%bestJ1_ctr_iter = iterator%ctr_iter
299 call controlfunction_end(iterator%best_par)
300 call controlfunction_copy(iterator%best_par, par)
301 if (.not. iterator%dump_intermediate) call controlfunction_write(oct_dir//'laser.bestJ1', &
302 iterator%best_par, sys%namespace)
303 end if
304
305 write(iterator%convergence_iunit, '(i11,4f20.8)') &
306 iterator%ctr_iter, j, j1, j2, delta
307
308 if (parse_is_defined(sys%namespace, 'OCTVelocityTarget')) then
309 call velocities_write(iterator, sys)
310 end if
311
312 iterator%ctr_iter = iterator%ctr_iter + 1
313
315 end subroutine iteration_manager_direct
316 ! ---------------------------------------------------------
317
318
319 ! ---------------------------------------------------------
320 subroutine iteration_manager_main(iterator, j, j1, j2, delta)
321 type(oct_iterator_t), intent(inout) :: iterator
322
323 real(real64), intent(in) :: j, j1, j2, delta
324
325 push_sub(iteration_manager_main)
326
327 iterator%ctr_iter_main = iterator%ctr_iter_main + 1
328 write(iterator%convergence_iunit, '("### MAIN ITERATION")')
329 write(iterator%convergence_iunit, '(a2,i9,4f20.8)') &
330 '##', iterator%ctr_iter_main, j, j1, j2, delta
331 write(iterator%convergence_iunit, '("###")')
332
334 end subroutine iteration_manager_main
335 ! ---------------------------------------------------------
336
337
338 ! ---------------------------------------------------------
339 subroutine iterator_write(namespace, iterator, par)
340 type(namespace_t), intent(in) :: namespace
341 type(oct_iterator_t), intent(in) :: iterator
342 type(controlfunction_t), intent(in) :: par
343
344 character(len=80) :: filename
345
347
348 write(filename,'(a,i4.4)') oct_dir//'laser.', iterator%ctr_iter
349 call controlfunction_write(filename, par, namespace)
350
351 pop_sub(iterator_write)
352 end subroutine iterator_write
353 ! ---------------------------------------------------------
354
355
356 ! ---------------------------------------------------------
357 subroutine oct_iterator_bestpar(par, iterator)
358 type(oct_iterator_t), target, intent(inout) :: iterator
359 type(controlfunction_t), pointer :: par
360
361 push_sub(oct_iterator_bestpar)
362 par => iterator%best_par
363
364 pop_sub(oct_iterator_bestpar)
365 end subroutine oct_iterator_bestpar
366 ! ---------------------------------------------------------
367
368
369 ! ---------------------------------------------------------
370 integer pure function oct_iterator_current(iterator)
371 type(oct_iterator_t), intent(in) :: iterator
372 oct_iterator_current = iterator%ctr_iter
373 end function oct_iterator_current
374 ! ---------------------------------------------------------
375
376
377 ! ---------------------------------------------------------
378 integer pure function oct_iterator_maxiter(iterator)
379 type(oct_iterator_t), intent(in) :: iterator
380 oct_iterator_maxiter = iterator%ctr_iter_max
381 end function oct_iterator_maxiter
382 ! ---------------------------------------------------------
383
384
385 ! ---------------------------------------------------------
386 real(real64) pure function oct_iterator_tolerance(iterator)
387 type(oct_iterator_t), intent(in) :: iterator
388 oct_iterator_tolerance = iterator%eps
389 end function oct_iterator_tolerance
390 ! ---------------------------------------------------------
391
392
393 ! ---------------------------------------------------------
394 subroutine velocities_write(iterator, sys)
395 type(oct_iterator_t), intent(in) :: iterator
396 type(electrons_t), intent(in) :: sys
397
398 character (len=100) :: temp_str
399 character (len=2) :: atoms_str
400 character (len=1) :: dim_str
401 integer :: i, j, n_atoms, dim
402
403 push_sub(velocities_write)
404
405 n_atoms = sys%ions%natoms
406 dim = sys%space%dim
407
408 ! write header of the velocities output file
409 if (iterator%ctr_iter == 0) then
410 write(iterator%velocities_iunit,'(100("#"))')
411 write(iterator%velocities_iunit,'("# iter")',advance='no')
412 do i = 1, n_atoms
413 write(atoms_str,'(i2.2)') i
414 do j = 1, dim
415 write(dim_str,'(i1)') j
416 temp_str = "v[" // atoms_str // "," // dim_str // "]"
417 write(iterator%velocities_iunit,'(a16)',advance='no') trim(temp_str)
418 end do
419 end do
420 write(iterator%velocities_iunit,'("")')
421 write(iterator%velocities_iunit,'(100("#"))')
422 end if
423
424 ! write data
425 write(iterator%velocities_iunit,'(i7)',advance='no') iterator%ctr_iter
426 do i = 1, n_atoms
427 do j = 1, dim
428 write(iterator%velocities_iunit,'(4(" "),(f12.10))',advance='no') sys%ions%vel(j, i)
429 end do
430 end do
431 write(iterator%velocities_iunit,'("")')
433 pop_sub(velocities_write)
434 end subroutine velocities_write
435 ! ---------------------------------------------------------
436
437
438end module opt_control_iter_oct_m
439
440!! Local Variables:
441!! mode: f90
442!! coding: utf-8
443!! End:
Prints out to iunit a message in the form: ["InputVariable" = value] where "InputVariable" is given b...
Definition: messages.F90:180
This module contains the definition of the data type that holds a "control function" used for OCT run...
real(real64) function, public controlfunction_diff(pp, qq)
real(real64) function, public controlfunction_fluence(par)
subroutine, public controlfunction_write(filename, cp, namespace)
subroutine, public controlfunction_end(cp)
real(real64) function, public controlfunction_j2(par)
real(real64) pure function, public controlfunction_alpha(par, ipar)
subroutine, public controlfunction_copy(cp_out, cp_in)
real(real64), parameter, public m_zero
Definition: global.F90:187
real(real64), parameter, public m_one
Definition: global.F90:188
character(len= *), parameter, public oct_dir
Definition: global.F90:258
This module implements the underlying real-space grid.
Definition: grid.F90:117
Definition: io.F90:114
subroutine, public io_close(iunit, grp)
Definition: io.F90:468
integer function, public io_open(file, namespace, action, status, form, position, die, recl, grp)
Definition: io.F90:395
subroutine, public messages_print_with_emphasis(msg, iunit, namespace)
Definition: messages.F90:930
character(len=512), private msg
Definition: messages.F90:165
subroutine, public messages_info(no_lines, iunit, verbose_limit, stress, all_nodes, namespace)
Definition: messages.F90:624
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:160
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:420
subroutine, public oct_iterator_bestpar(par, iterator)
logical function, public iteration_manager(namespace, j1, par, par_prev, iterator)
subroutine, public iteration_manager_main(iterator, j, j1, j2, delta)
subroutine, public oct_iterator_init(iterator, namespace, par)
integer pure function, public oct_iterator_maxiter(iterator)
subroutine iterator_write(namespace, iterator, par)
subroutine, public oct_iterator_end(iterator, namespace)
integer pure function, public oct_iterator_current(iterator)
subroutine, public iteration_manager_direct(j, par, iterator, sys, dx)
real(real64) pure function, public oct_iterator_tolerance(iterator)
subroutine, public velocities_write(iterator, sys)
logical function, public parse_is_defined(namespace, name)
Definition: parser.F90:502
This is the data type used to hold a control function.
Class describing the electron system.
Definition: electrons.F90:214
int true(void)