Octopus
target_hhg.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
25 use epot_oct_m
26 use fft_oct_m
27 use global_oct_m
28 use grid_oct_m
30 use io_oct_m
31 use ions_oct_m
34 use, intrinsic :: iso_fortran_env
39 use output_oct_m
41 use parser_oct_m
43 use space_oct_m
47 use td_oct_m
49
50
51 implicit none
52
53 private
54 public :: &
65
66
67contains
68
69
70
71 ! ----------------------------------------------------------------------
73 subroutine target_init_hhg(tg, namespace, td, w0)
74 type(target_t), intent(inout) :: tg
75 type(namespace_t), intent(in) :: namespace
76 type(td_t), intent(in) :: td
77 real(real64), intent(in) :: w0
78
79 integer :: jj
80 type(block_t) :: blk
81 push_sub(target_init_hhg)
82
83 tg%move_ions = ion_dynamics_ions_move(td%ions_dyn)
84
85 !%Variable OCTOptimizeHarmonicSpectrum
86 !%Type block
87 !%Default no
88 !%Section Calculation Modes::Optimal Control
89 !%Description
90 !% (Experimental)
91 !% If <tt>OCTTargetOperator = oct_tg_hhg</tt>, the target is the harmonic emission spectrum.
92 !% In that case, you must supply an <tt>OCTOptimizeHarmonicSpectrum</tt> block in the <tt>inp</tt>
93 !% file. The target is given, in general, by:
94 !%
95 !% <math>J_1 = \int_0^\infty d\omega \alpha(\omega) H(\omega)</math>,
96 !%
97 !% where <math>H(\omega)</math> is the harmonic spectrum generated by the system, and
98 !% <math>\alpha(\omega)</math> is some function that determines what exactly we want
99 !% to optimize. The role of the <tt>OCTOptimizeHarmonicSpectrum</tt> block is to determine
100 !% this <math>\alpha(\omega)</math> function. Currently, this function is defined as:
101 !%
102 !% <math>\alpha(\omega) = \sum_{L=1}^{M} \frac{\alpha_L}{a_L} \sqcap( (\omega - L\omega_0)/a_L )</math>,
103 !%
104 !% where <math>\omega_0</math> is the carrier frequency. <math>M</math> is
105 !% the number of columns in the <tt>OCTOptimizeHarmonicSpectrum</tt> block. The values of <i>L</i> will be listed
106 !% in the first row of this block; <math>\alpha_L</math> in the second row, and <math>a_L</math> in
107 !% the third.
108 !%
109 !% Example:
110 !%
111 !% <tt>%OCTOptimizeHarmonicSpectrum
112 !% <br>&nbsp;&nbsp; 7 | 9 | 11
113 !% <br>&nbsp;&nbsp; -1 | 1 | -1
114 !% <br>&nbsp;&nbsp; 0.01 | 0.01 | 0.01
115 !% <br>%</tt>
116 !%
117 !%End
118 if (parse_is_defined(namespace, 'OCTOptimizeHarmonicSpectrum')) then
119 if (parse_block(namespace, 'OCTOptimizeHarmonicSpectrum', blk) == 0) then
120 tg%hhg_nks = parse_block_cols(blk, 0)
121 safe_allocate( tg%hhg_k(1:tg%hhg_nks))
122 safe_allocate(tg%hhg_alpha(1:tg%hhg_nks))
123 safe_allocate( tg%hhg_a(1:tg%hhg_nks))
124 do jj = 1, tg%hhg_nks
125 call parse_block_integer(blk, 0, jj - 1, tg%hhg_k(jj))
126 call parse_block_float(blk, 1, jj - 1, tg%hhg_alpha(jj))
127 call parse_block_float(blk, 2, jj - 1, tg%hhg_a(jj))
128 end do
129 call parse_block_end(blk)
130 else
131 message(1) = '"OCTOptimizeHarmonicSpectrum" has to be specified as a block.'
132 call messages_info(1, namespace=namespace)
133 call messages_input_error(namespace, 'OCTOptimizeHarmonicSpectrum')
134 end if
135 else
136 write(message(1), '(a)') 'If "OCTTargetMode = oct_targetmode_hhg", you must supply an'
137 write(message(2), '(a)') '"OCTOptimizeHarmonicSpectrum" block.'
138 call messages_fatal(2, namespace=namespace)
139 end if
140
141 tg%hhg_w0 = w0
142 tg%dt = td%dt
143 safe_allocate(tg%td_fitness(0:td%max_iter))
144 tg%td_fitness = m_zero
145
146 pop_sub(target_init_hhg)
147 end subroutine target_init_hhg
148
149
150 ! ----------------------------------------------------------------------
152 subroutine target_init_hhgnew(gr, namespace, tg, td, ions, ep)
153 type(grid_t), intent(in) :: gr
154 type(namespace_t), intent(in) :: namespace
155 type(target_t), intent(inout) :: tg
156 type(td_t), intent(in) :: td
157 type(ions_t), intent(in) :: ions
158 type(epot_t), intent(in) :: ep
159
160 integer :: ist, jst, iunit, jj, nn(3), optimize_parity(3)
161 logical :: optimize(3)
162 real(real64) :: dw, psi_re, psi_im, ww
163 real(real64), allocatable :: vl(:), vl_grad(:,:)
164 push_sub(target_init_hhgnew)
165
166 tg%move_ions = ion_dynamics_ions_move(td%ions_dyn)
167
168 ! We allocate many things that are perhaps not necessary if we use a direct optimization scheme.
169 safe_allocate(tg%vel(1:td%max_iter+1, 1:gr%box%dim))
170 safe_allocate(tg%acc(1:td%max_iter+1, 1:gr%box%dim))
171 safe_allocate(tg%gvec(1:td%max_iter+1, 1:gr%box%dim))
172 safe_allocate(tg%alpha(1:td%max_iter))
173
174 ! The following is a temporary hack, that assumes only one atom at the origin of coordinates.
175 if (ions%natoms > 1) then
176 message(1) = 'If "OCTTargetOperator = oct_tg_hhgnew", then you can only have one atom.'
177 call messages_fatal(1, namespace=namespace)
178 end if
179
180 ! The following is a temporary hack, that assumes only one atom at the origin of coordinates.
181 if (ions%natoms > 1) then
182 message(1) = 'If "OCTTargetOperator = oct_tg_hhgnew", then you can only have one atom.'
183 call messages_fatal(1, namespace=namespace)
184 end if
185
186 safe_allocate(tg%grad_local_pot(1:ions%natoms, 1:gr%np, 1:gr%box%dim))
187 safe_allocate(vl(1:gr%np_part))
188 safe_allocate(vl_grad(1:gr%np, 1:gr%box%dim))
189 safe_allocate(tg%rho(1:gr%np))
190
191 vl(:) = m_zero
192 vl_grad(:,:) = m_zero
193 call epot_local_potential(ep, namespace, ions%space, ions%latt, gr, ions%atom(1)%species, &
194 ions%pos(:, 1), 1, vl)
195 call dderivatives_grad(gr%der, vl, vl_grad)
196 do jst=1, gr%box%dim
197 do ist = 1, gr%np
198 tg%grad_local_pot(1, ist, jst) = vl_grad(ist, jst)
199 end do
200 end do
201 ! Note that the calculation of the gradient of the potential
202 ! is wrong at the borders of the box, since it assumes zero boundary
203 ! conditions. The best way to solve this problems is to define the
204 ! target making use of the definition of the forces based on the gradient
205 ! of the density, rather than on the gradient of the potential.
206
207
208 !%Variable OCTHarmonicWeight
209 !%Type string
210 !%Default "1"
211 !%Section Calculation Modes::Optimal Control
212 !%Description
213 !% (Experimental) If <tt>OCTTargetOperator = oct_tg_plateau</tt>, then the function to optimize is the integral of the
214 !% harmonic spectrum <math>H(\omega)</math>, weighted with a function <math>f(\omega)</math>
215 !% that is defined as a string here. For example, if
216 !% you set <tt>OCTHarmonicWeight = "step(w-1)"</tt>, the function to optimize is
217 !% the integral of <math>step(\omega-1)*H(\omega)</math>, <i>i.e.</i>
218 !% <math>\int_1^{\infty} H \left( \omega \right) d\omega</math>.
219 !% In practice, it is better if you also set an upper limit, <i>e.g.</i>
220 !% <math>f(\omega) = step(\omega-1) step(2-\omega)</math>.
221 !%End
222 call parse_variable(namespace, 'OCTHarmonicWeight', '1', tg%plateau_string)
223 tg%dt = td%dt
224 safe_allocate(tg%td_fitness(0:td%max_iter))
225 tg%td_fitness = m_zero
226
227 iunit = io_open('.alpha', namespace, action='write')
228 dw = (m_two * m_pi) / (td%max_iter * tg%dt)
229 do jj = 0, td%max_iter - 1
230 ww = jj * dw
231 call parse_expression(psi_re, psi_im, "w", ww, tg%plateau_string)
232 tg%alpha(jj+1) = psi_re
233 write(iunit, *) ww, psi_re
234 end do
235 call io_close(iunit)
236
237 nn(1:3) = (/ td%max_iter, 1, 1 /)
238 optimize(1:3) = .false.
239 optimize_parity(1:3) = -1
240 call fft_init(tg%fft_handler, nn(1:3), 1, fft_complex, fftlib_fftw, optimize, optimize_parity)
241
242 pop_sub(target_init_hhgnew)
243 end subroutine target_init_hhgnew
244
246 ! ----------------------------------------------------------------------
248 subroutine target_end_hhg(tg)
249 type(target_t), intent(inout) :: tg
250
251 push_sub(target_end_hhg)
252
253 safe_deallocate_a(tg%hhg_k)
254 safe_deallocate_a(tg%hhg_alpha)
255 safe_deallocate_a(tg%hhg_a)
256 safe_deallocate_a(tg%td_fitness)
257
258 pop_sub(target_end_hhg)
259 end subroutine target_end_hhg
260
261
262 ! ----------------------------------------------------------------------
263 subroutine target_output_hhg(tg, namespace, space, gr, dir, ions, hm, outp)
264 type(target_t), intent(in) :: tg
265 type(namespace_t), intent(in) :: namespace
266 class(space_t), intent(in) :: space
267 type(grid_t), intent(in) :: gr
268 character(len=*), intent(in) :: dir
269 type(ions_t), intent(in) :: ions
270 type(hamiltonian_elec_t), intent(in) :: hm
271 type(output_t), intent(in) :: outp
272
273 push_sub(target_output_hhg)
274
275 call io_mkdir(trim(dir), namespace)
276 call output_states(outp, namespace, space, trim(dir), tg%st, gr, ions, hm, -1)
277
278 pop_sub(target_output_hhg)
279 end subroutine target_output_hhg
280 ! ----------------------------------------------------------------------
281
282
283 ! ----------------------------------------------------------------------
285 subroutine target_end_hhgnew(tg, oct)
286 type(target_t), intent(inout) :: tg
287 type(oct_t), intent(in) :: oct
288
289 push_sub(target_end_hhgnew)
290
291 if ((oct%algorithm == option__octscheme__oct_cg) .or. (oct%algorithm == option__octscheme__oct_bfgs)) then
292 safe_deallocate_a(tg%grad_local_pot)
293 safe_deallocate_a(tg%rho)
294 safe_deallocate_a(tg%vel)
295 safe_deallocate_a(tg%acc)
296 safe_deallocate_a(tg%gvec)
297 safe_deallocate_a(tg%alpha)
298 safe_deallocate_a(tg%td_fitness)
299 call fft_end(tg%fft_handler)
300 end if
301
302 pop_sub(target_end_hhgnew)
303 end subroutine target_end_hhgnew
304
305
306 ! ----------------------------------------------------------------------
308 real(real64) function target_j1_hhg(tg, namespace) result(j1)
309 type(target_t), intent(in) :: tg
310 type(namespace_t), intent(in) :: namespace
311
312 integer :: maxiter, jj
313 real(real64) :: aa, ww, maxhh, omega
314 complex(real64), allocatable :: ddipole(:)
315 push_sub(target_j1_hhg)
316
317 maxiter = size(tg%td_fitness) - 1
318 safe_allocate(ddipole(0:maxiter))
319 ddipole = m_z0
320 ddipole = tg%td_fitness
321
322 j1 = m_zero
323
324 call spectrum_hsfunction_init(tg%dt, 0, maxiter, maxiter, ddipole)
325 do jj = 1, tg%hhg_nks
326 aa = tg%hhg_a(jj) * tg%hhg_w0
327 ww = tg%hhg_k(jj) * tg%hhg_w0
328 call spectrum_hsfunction_min(namespace, ww - aa, ww + aa, omega, maxhh)
329 j1 = j1 + tg%hhg_alpha(jj) * log(-maxhh)
330 end do
332
333 safe_deallocate_a(ddipole)
334 pop_sub(target_j1_hhg)
335 end function target_j1_hhg
336
337
338 ! ----------------------------------------------------------------------
340 real(real64) function target_j1_hhgnew(gr, tg) result(j1)
341 type(grid_t), intent(in) :: gr
342 type(target_t), intent(in) :: tg
343
344 integer :: maxiter, i
345 real(real64) :: dw, ww
346 push_sub(target_j1_hhgnew)
347
348 maxiter = size(tg%td_fitness) - 1
349 dw = (m_two * m_pi) / (maxiter * tg%dt)
350 j1 = m_zero
351 do i = 0, maxiter - 1
352 ww = i * dw
353 j1 = j1 + dw * tg%alpha(i+1) * sum(abs(tg%vel(i+1, 1:gr%box%dim))**2)
354 end do
355
357 end function target_j1_hhgnew
358
359
360 ! ----------------------------------------------------------------------
362 subroutine target_chi_hhg(chi_out)
363 type(states_elec_t), intent(inout) :: chi_out
364
365 integer :: ik, ib
366 push_sub(target_chi_hhg)
367
368 !we have a time-dependent target --> Chi(T)=0
369 do ik = chi_out%d%kpt%start, chi_out%d%kpt%end
370 do ib = chi_out%group%block_start, chi_out%group%block_end
371 call batch_set_zero(chi_out%group%psib(ib, ik))
372 end do
373 end do
374
375 pop_sub(target_chi_hhg)
376 end subroutine target_chi_hhg
377
379 ! ---------------------------------------------------------
382 subroutine target_tdcalc_hhgnew(tg, gr, psi, time, max_time)
383 type(target_t), intent(inout) :: tg
384 type(grid_t), intent(in) :: gr
385 type(states_elec_t), intent(in) :: psi
386 integer, intent(in) :: time
387 integer, intent(in) :: max_time
388
389 complex(real64), allocatable :: opsi(:, :), zpsi(:, :)
390 integer :: iw, ia, ist, idim, ik
391 real(real64) :: acc(gr%box%dim), dt, dw
392
393 push_sub(target_tdcalc_hhgnew)
394
395 tg%td_fitness(time) = m_zero
396
397 ! If the ions move, the tg is computed in the propagation routine.
398 if (.not. target_move_ions(tg)) then
399
400 safe_allocate(opsi(1:gr%np_part, 1))
401 safe_allocate(zpsi(1:gr%np_part, 1))
402
403 opsi = m_z0
404 ! WARNING This does not work for spinors.
405 ! The following is a temporary hack. It assumes only one atom at the origin.
406 do ik = 1, psi%nik
407 do ist = 1, psi%nst
408 call states_elec_get_state(psi, gr, ist, ik, zpsi)
409 do idim = 1, gr%box%dim
410 opsi(1:gr%np, 1) = tg%grad_local_pot(1, 1:gr%np, idim)*zpsi(1:gr%np, 1)
411 acc(idim) = acc(idim) + real( psi%occ(ist, ik) * zmf_dotp(gr, psi%d%dim, opsi, zpsi), real64)
412 tg%acc(time+1, idim) = tg%acc(time+1, idim) + psi%occ(ist, ik)*zmf_dotp(gr, psi%d%dim, opsi, zpsi)
413 end do
414 end do
415 end do
416
417 safe_deallocate_a(opsi)
418 safe_deallocate_a(zpsi)
419
420 end if
421
422 dt = tg%dt
423 dw = (m_two * m_pi/(max_time * tg%dt))
424 if (time == max_time) then
425 tg%acc(1, 1:gr%box%dim) = m_half * (tg%acc(1, 1:gr%box%dim) + tg%acc(max_time+1, 1:gr%box%dim))
426 do ia = 1, gr%box%dim
427 call zfft_forward(tg%fft_handler, tg%acc(1:max_time, ia), tg%vel(1:max_time, ia))
428 end do
429 tg%vel = tg%vel * tg%dt
430 do iw = 1, max_time
431 ! We add the one-half dt term because when doing the propagation we want the value at interpolated times.
432
433 tg%acc(iw, 1:gr%box%dim) = tg%vel(iw, 1:gr%box%dim) * tg%alpha(iw) * exp(m_zi * (iw-1) * dw * m_half * dt)
434 end do
435 do ia = 1, gr%box%dim
436 call zfft_backward(tg%fft_handler, tg%acc(1:max_time, ia), tg%gvec(1:max_time, ia))
437 end do
438 tg%gvec(max_time + 1, 1:gr%box%dim) = tg%gvec(1, 1:gr%box%dim)
439 tg%gvec = tg%gvec * (m_two * m_pi/ tg%dt)
440 end if
441
442 pop_sub(target_tdcalc_hhgnew)
443 end subroutine target_tdcalc_hhgnew
444 ! ----------------------------------------------------------------------
445
446
447 ! ---------------------------------------------------------
450 subroutine target_tdcalc_hhg(tg, namespace, space, hm, gr, ions, ext_partners, psi, time)
451 type(target_t), intent(inout) :: tg
452 type(namespace_t), intent(in) :: namespace
453 class(space_t), intent(in) :: space
454 type(hamiltonian_elec_t), intent(in) :: hm
455 type(grid_t), intent(in) :: gr
456 type(ions_t), intent(inout) :: ions
457 type(partner_list_t), intent(in) :: ext_partners
458 type(states_elec_t), intent(in) :: psi
459 integer, intent(in) :: time
460
461 real(real64) :: acc(space%dim)
462
463 push_sub(target_tdcalc_hhg)
464
465 call td_calc_tacc(namespace, space, gr, ions, ext_partners, psi, hm, acc, time*tg%dt)
466 tg%td_fitness(time) = acc(1)
467
468 pop_sub(target_tdcalc_hhg)
469 end subroutine target_tdcalc_hhg
470 ! ----------------------------------------------------------------------
471
472end module target_hhg_oct_m
473
474!! Local Variables:
475!! mode: f90
476!! coding: utf-8
477!! End:
double log(double __x) __attribute__((__nothrow__
double exp(double __x) __attribute__((__nothrow__
This module implements common operations on batches of mesh functions.
Definition: batch_ops.F90:116
This module calculates the derivatives (gradients, Laplacians, etc.) of a function.
subroutine, public dderivatives_grad(der, ff, op_ff, ghost_update, set_bc, to_cartesian)
apply the gradient to a mesh function
subroutine, public epot_local_potential(ep, namespace, space, latt, mesh, species, pos, iatom, vpsl)
Definition: epot.F90:490
Fast Fourier Transform module. This module provides a single interface that works with different FFT ...
Definition: fft.F90:118
subroutine, public fft_init(this, nn, dim, type, library, optimize, optimize_parity, comm, mpi_grp, use_aligned)
Definition: fft.F90:418
subroutine, public fft_end(this)
Definition: fft.F90:996
integer, parameter, public fft_complex
Definition: fft.F90:178
integer, parameter, public fftlib_fftw
Definition: fft.F90:183
real(real64), parameter, public m_two
Definition: global.F90:190
real(real64), parameter, public m_zero
Definition: global.F90:188
real(real64), parameter, public m_pi
some mathematical constants
Definition: global.F90:186
complex(real64), parameter, public m_z0
Definition: global.F90:198
This module implements the underlying real-space grid.
Definition: grid.F90:117
This module defines classes and functions for interaction partners.
Definition: io.F90:114
subroutine, public io_close(iunit, grp)
Definition: io.F90:418
subroutine, public io_mkdir(fname, namespace, parents)
Definition: io.F90:311
integer function, public io_open(file, namespace, action, status, form, position, die, recl, grp)
Definition: io.F90:352
logical pure function, public ion_dynamics_ions_move(this)
This module defines various routines, operating on mesh functions.
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:414
subroutine, public messages_input_error(namespace, var, details, row, column)
Definition: messages.F90:713
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:616
This module contains the definition of the oct_t data type, which contains some of the basic informat...
this module contains the low-level part of the output system
Definition: output_low.F90:115
this module contains the output system
Definition: output.F90:115
subroutine, public output_states(outp, namespace, space, dir, st, gr, ions, hm, iter)
Definition: output.F90:1888
logical function, public parse_is_defined(namespace, name)
Definition: parser.F90:502
integer function, public parse_block(namespace, name, blk, check_varinfo_)
Definition: parser.F90:618
subroutine, public spectrum_hsfunction_min(namespace, aa, bb, omega_min, func_min)
Definition: spectrum.F90:1583
subroutine, public spectrum_hsfunction_init(dt, is, ie, niter, acc)
Definition: spectrum.F90:1534
subroutine, public spectrum_hsfunction_end
Definition: spectrum.F90:1569
subroutine, public target_end_hhg(tg)
Definition: target_hhg.F90:342
subroutine, public target_init_hhg(tg, namespace, td, w0)
Definition: target_hhg.F90:167
subroutine, public target_tdcalc_hhgnew(tg, gr, psi, time, max_time)
Definition: target_hhg.F90:476
subroutine, public target_tdcalc_hhg(tg, namespace, space, hm, gr, ions, ext_partners, psi, time)
Definition: target_hhg.F90:544
subroutine, public target_chi_hhg(chi_out)
Definition: target_hhg.F90:456
real(real64) function, public target_j1_hhg(tg, namespace)
Definition: target_hhg.F90:402
subroutine, public target_init_hhgnew(gr, namespace, tg, td, ions, ep)
Definition: target_hhg.F90:246
real(real64) function, public target_j1_hhgnew(gr, tg)
Definition: target_hhg.F90:434
subroutine, public target_end_hhgnew(tg, oct)
Definition: target_hhg.F90:379
subroutine, public target_output_hhg(tg, namespace, space, gr, dir, ions, hm, outp)
Definition: target_hhg.F90:357
Definition: td.F90:114
Description of the grid, containing information on derivatives, stencil, and symmetries.
Definition: grid.F90:168
!brief The oct_t datatype stores the basic information about how the OCT run is done.
output handler class
Definition: output_low.F90:164