Octopus
target_velocity.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 global_oct_m
27 use grid_oct_m
29 use, intrinsic :: iso_fortran_env
30 use io_oct_m
31 use ions_oct_m
37 use output_oct_m
39 use parser_oct_m
41 use space_oct_m
43 use string_oct_m
45 use td_oct_m
46
47 implicit none
48
49 private
50 public :: &
57
58
59contains
60
61 ! ----------------------------------------------------------------------
63 subroutine target_init_velocity(gr, namespace, ions, tg, oct, td, ep)
64 type(grid_t), intent(in) :: gr
65 type(namespace_t), intent(in) :: namespace
66 type(ions_t), intent(in) :: ions
67 type(target_t), intent(inout) :: tg
68 type(oct_t), intent(in) :: oct
69 type(td_t), intent(in) :: td
70 type(epot_t), intent(in) :: ep
71
72 integer :: iatom, ist, jst, jj
73 real(real64), allocatable :: vl(:), vl_grad(:,:)
74 type(block_t) :: blk
75 character(len=1024) :: expression
76
77 push_sub(target_init_velocity)
78
79 !%Variable OCTVelocityTarget
80 !%Type block
81 !%Section Calculation Modes::Optimal Control
82 !%Description
83 !% If <tt>OCTTargetOperator = oct_tg_velocity</tt>, then one must supply the
84 !% target to optimize in terms of the ionic velocities. This is done by
85 !% supplying a string through the block <tt>OCTVelocityTarget</tt>.
86 !% Each velocity component is supplied by <tt>"v[n_atom,vec_comp]"</tt>,
87 !% where <tt>n_atom</tt> is the atom number, corresponding to the
88 !% <tt>Coordinates</tt> block, and <tt>vec_comp</tt> is the corresponding
89 !% vector component of the velocity. The target string can be
90 !% supplied by using several lines in this block.
91 !% As an example, the following target can be used to maximize the
92 !% velocity difference between atom 1 and 2 (in a 3D system):
93 !%
94 !% <tt>%OCTVelocityTarget
95 !% <br> "(v[1,1]-v[2,1])^2 + (v[1,2]-v[2,2])^2 + "
96 !% <br> "(v[1,3]-v[2,3])^2"
97 !% <br>%</tt>
98 !%
99 !%End
100
101 !%Variable OCTVelocityDerivatives
102 !%Type block
103 !%Section Calculation Modes::Optimal Control
104 !%Description
105 !% If <tt>OCTTargetOperator = oct_tg_velocity</tt>, and
106 !% <tt>OCTScheme = oct_cg</tt> or <tt>OCTScheme = oct_bfgs</tt>
107 !% then you must supply the target in terms of the ionic velocities AND
108 !% the derivatives of the target with respect to the ionic velocity components.
109 !% The derivatives are supplied via strings through the block
110 !% <tt>OCTVelocityDerivatives</tt>.
111 !% Each velocity component is supplied by <tt>"v[n_atom,vec_comp]"</tt>,
112 !% while <tt>n_atom</tt> is the atom number, corresponding to the
113 !% <tt>Coordinates</tt> block, and <tt>vec_comp</tt> is the corresponding
114 !% vector component of the velocity. The first line of the
115 !% <tt>OCTVelocityDerivatives</tt> block contains the derivatives
116 !% with respect to <tt>v[1,*]</tt>, the second with respect to <tt>v[2,*]</tt> and so
117 !% on. The first column contains all derivatives with respect <tt>v[*,1]</tt>,
118 !% the second with respect to <tt>v[*,2]</tt> and the third w.r.t. <tt>v[*,3]</tt>.
119 !% As an example, we show the <tt>OCTVelocityDerivatives</tt> block
120 !% corresponding to the target shown in the <tt>OCTVelocityTarget</tt>
121 !% help section:
122 !%
123 !% <tt>%OCTVelocityDerivatives
124 !% <br> " 2*(v[1,1]-v[2,1])" | " 2*(v[1,2]-v[2,2])" | " 2*(v[1,3]-v[2,3])"
125 !% <br> "-2*(v[1,1]-v[2,1])" | "-2*(v[1,2]-v[2,2])" | "-2*(v[1,3]-v[2,3])"
126 !% <br>%</tt>
127 !%
128 !%End
129
130 if (parse_block(namespace, 'OCTVelocityTarget', blk) == 0) then
131 tg%vel_input_string = " "
132 do jj=0, parse_block_n(blk)-1
133 call parse_block_string(blk, jj, 0, expression)
134 tg%vel_input_string = trim(tg%vel_input_string) // trim(expression)
135 end do
136 call parse_block_end(blk)
137 else
138 message(1) = 'If OCTTargetOperator = oct_tg_velocity, then you must give the shape'
139 message(2) = 'of this target in the block "OCTVelocityTarget".'
140 call messages_fatal(2, namespace=namespace)
141 end if
142
143 tg%move_ions = ion_dynamics_ions_move(td%ions_dyn)
144 if (tg%move_ions) then
145 message(1) = 'If OCTTargetOperator = oct_tg_velocity, then you must not allow the ions'
146 message(2) = 'to move. If you want to move the ions, then you can get the same functionality'
147 message(3) = 'with OCTTargetOperator = oct_tg_classical.'
148 call messages_fatal(3, namespace=namespace)
149 end if
150
151 if (oct%algorithm == option__octscheme__oct_cg .or. oct%algorithm == option__octscheme__oct_bfgs) then
152 if (parse_block(namespace, 'OCTVelocityDerivatives', blk) == 0) then
153 safe_allocate(tg%vel_der_array(1:ions%natoms,1:gr%box%dim))
154 do ist=0, ions%natoms-1
155 do jst=0, gr%box%dim-1
156 call parse_block_string(blk, ist, jst, tg%vel_der_array(ist+1, jst+1))
157 end do
158 end do
159 call parse_block_end(blk)
160 else
161 message(1) = 'If OCTTargetOperator = oct_tg_velocity, and'
162 message(2) = 'OCTScheme = oct_cg, or OCTScheme = oct_bfgs then you must define the'
163 message(3) = 'blocks "OCTVelocityTarget" AND "OCTVelocityDerivatives"'
164 call messages_fatal(3, namespace=namespace)
165 end if
166 end if
167
168 safe_allocate(tg%grad_local_pot(1:ions%natoms, 1:gr%np, 1:gr%box%dim))
169 safe_allocate(vl(1:gr%np_part))
170 safe_allocate(vl_grad(1:gr%np, 1:gr%box%dim))
171 safe_allocate(tg%rho(1:gr%np))
172
173 ! calculate gradient of each species potential
174 do iatom = 1, ions%natoms
175 vl(:) = m_zero
176 vl_grad(:,:) = m_zero
177 call epot_local_potential(ep, namespace, ions%space, ions%latt, gr, ions%atom(iatom)%species, &
178 ions%pos(:, iatom), iatom, vl)
179 call dderivatives_grad(gr%der, vl, vl_grad)
180 do ist = 1, gr%np
181 do jst=1, gr%box%dim
182 tg%grad_local_pot(iatom, ist, jst) = vl_grad(ist, jst)
183 end do
184 end do
185 end do
186 safe_deallocate_a(vl)
187 safe_deallocate_a(vl_grad)
188
189 ! Note that the calculation of the gradient of the potential
190 ! is wrong at the borders of the box, since it assumes zero boundary
191 ! conditions. The best way to solve this problems is to define the
192 ! target making use of the definition of the forces based on the gradient
193 ! of the density, rather than on the gradient of the potential.
194
195 tg%dt = td%dt
196 safe_allocate(tg%td_fitness(0:td%max_iter))
197 tg%td_fitness = m_zero
198
199 pop_sub(target_init_velocity)
200 end subroutine target_init_velocity
201
202
203 ! ----------------------------------------------------------------------
205 subroutine target_end_velocity(tg, oct)
206 type(target_t), intent(inout) :: tg
207 type(oct_t), intent(in) :: oct
208
209 push_sub(target_end_velocity)
210
211 if (oct%algorithm == option__octscheme__oct_cg .or. oct%algorithm == option__octscheme__oct_bfgs) then
212 safe_deallocate_a(tg%vel_der_array)
213 safe_deallocate_a(tg%grad_local_pot)
214 safe_deallocate_a(tg%rho)
215 end if
216 safe_deallocate_a(tg%td_fitness)
217
218 pop_sub(target_end_velocity)
219 end subroutine target_end_velocity
220
221
222 ! ----------------------------------------------------------------------
223 subroutine target_output_velocity(tg, namespace, space, gr, dir, ions, hm, outp)
224 type(target_t), intent(in) :: tg
225 type(namespace_t), intent(in) :: namespace
226 class(space_t), intent(in) :: space
227 type(grid_t), intent(in) :: gr
228 character(len=*), intent(in) :: dir
229 type(ions_t), intent(in) :: ions
230 type(hamiltonian_elec_t), intent(in) :: hm
231 type(output_t), intent(in) :: outp
232
233 push_sub(target_output_velocity)
234
235 call io_mkdir(trim(dir), namespace)
236 call output_states(outp, namespace, space, trim(dir), tg%st, gr, ions, hm, -1)
237
239 end subroutine target_output_velocity
240 ! ----------------------------------------------------------------------
241
242
243 ! ----------------------------------------------------------------------
245 real(real64) function target_j1_velocity(tg, ions) result(j1)
246 type(target_t), intent(in) :: tg
247 type(ions_t), intent(in) :: ions
248
249 integer :: i
250 real(real64) :: f_re, dummy(3)
251 real(real64), allocatable :: x(:, :)
252 character(len=4096) :: inp_string
253 push_sub(target_j1_velocity)
254
255 safe_allocate(x(1:ions%natoms, 1:ions%space%dim))
256 do i = 1, ions%natoms
257 x(i, :) = ions%vel(:, i)
258 end do
259
260 f_re = m_zero
261 dummy(:) = m_zero
262 inp_string = tg%vel_input_string
263 call parse_array(inp_string, x, 'v')
264 call conv_to_c_string(inp_string)
265 call parse_expression(f_re, dummy(1), 1, dummy(1:3), dummy(1), dummy(1), inp_string)
266 j1 = f_re
267
268 safe_deallocate_a(x)
269 pop_sub(target_j1_velocity)
270 end function target_j1_velocity
271
272
273 ! ----------------------------------------------------------------------
275 subroutine target_chi_velocity(gr, tg, chi_out, ions)
276 type(grid_t), intent(in) :: gr
277 type(target_t), intent(inout) :: tg
278 type(states_elec_t), intent(inout) :: chi_out
279 type(ions_t), intent(in) :: ions
280
281 integer :: ip, ist, jst, ik, ib
282 character(len=1024) :: temp_string
283 real(real64) :: df_dv, dummy(3)
284 real(real64), allocatable :: x(:, :)
285 push_sub(target_chi_velocity)
286
287 !we have a time-dependent target --> Chi(T)=0
288 do ik = chi_out%d%kpt%start, chi_out%d%kpt%end
289 do ib = chi_out%group%block_start, chi_out%group%block_end
290 call batch_set_zero(chi_out%group%psib(ib, ik))
291 end do
292 end do
293
294 safe_allocate(x(1:ions%natoms, 1:ions%space%dim))
295 do ip = 1, ions%natoms
296 x(ip, :) = ions%vel(:, ip)
297 end do
299 !calculate dF/dn, which is the time-independent part of the inhomogenous term for the propagation of Chi
300 df_dv = m_zero
301 dummy(:) = m_zero
302 tg%rho(:) = m_zero
303 do ist = 1, ions%natoms
304 do jst=1, gr%box%dim
305 temp_string = tg%vel_der_array(ist, jst)
306 call parse_array(temp_string, x, 'v')
307 call conv_to_c_string(temp_string)
308 call parse_expression(df_dv, dummy(1), 1, dummy(1:3), dummy(1), dummy(1), temp_string)
309 tg%rho(:) = tg%rho(:) + df_dv*tg%grad_local_pot(ist,:,jst)/ions%mass(ist)
310 end do
311 end do
312
313 safe_deallocate_a(x)
314 pop_sub(target_chi_velocity)
315 end subroutine target_chi_velocity
317
318 ! ---------------------------------------------------------
321 subroutine target_tdcalc_velocity(tg, hm, gr, ions, psi, time, max_time)
322 type(target_t), intent(inout) :: tg
323 type(hamiltonian_elec_t), intent(in) :: hm
324 type(grid_t), intent(in) :: gr
325 type(ions_t), intent(inout) :: ions
326 type(states_elec_t), intent(in) :: psi
327 integer, intent(in) :: time
328 integer, intent(in) :: max_time
329
330 complex(real64), allocatable :: opsi(:, :), zpsi(:, :)
331 integer :: iatom, ik, ist, idim
332 real(real64) :: dt
333 push_sub(target_tdcalc_velocity)
334
335 tg%td_fitness(time) = m_zero
336
337 safe_allocate(zpsi(1:gr%np_part, 1))
338 safe_allocate(opsi(1:gr%np_part, 1))
339 opsi = m_z0
340 ! WARNING This does not work for spinors.
341 do iatom = 1, ions%natoms
342 ions%tot_force(:, iatom) = hm%ep%fii(1:gr%box%dim, iatom)
343 do ik = 1, psi%nik
344 do ist = 1, psi%nst
345 do idim = 1, gr%box%dim
346 call states_elec_get_state(psi, gr, ist, ik, zpsi)
347 opsi(1:gr%np, 1) = tg%grad_local_pot(iatom, 1:gr%np, idim)*zpsi(1:gr%np, 1)
348 ions%tot_force(idim, iatom) = ions%tot_force(idim, iatom) &
349 + real(psi%occ(ist, ik)*zmf_dotp(gr, psi%d%dim, opsi, zpsi), real64)
350 end do
351 end do
352 end do
353 end do
354 safe_deallocate_a(opsi)
355 safe_deallocate_a(zpsi)
356
357 dt = tg%dt
358 if ((time == 0) .or. (time == max_time)) dt = tg%dt * m_half
359 do iatom = 1, ions%natoms
360 ions%vel(:, iatom) = ions%vel(:, iatom) + ions%tot_force(:, iatom) * dt / ions%mass(iatom)
361 end do
362
364 end subroutine target_tdcalc_velocity
365 ! ----------------------------------------------------------------------
366
367end module target_velocity_oct_m
369!! Local Variables:
370!! mode: f90
371!! coding: utf-8
372!! End:
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
real(real64), parameter, public m_zero
Definition: global.F90:188
This module implements the underlying real-space grid.
Definition: grid.F90:117
Definition: io.F90:114
subroutine, public io_mkdir(fname, namespace, parents)
Definition: io.F90:311
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
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
subroutine, public parse_array(inp_string, x, arraychar)
A very primitive way to "preprocess" a string that contains reference to the elements of a two-dimens...
Definition: parser.F90:700
integer function, public parse_block(namespace, name, blk, check_varinfo_)
Definition: parser.F90:618
subroutine, public conv_to_c_string(str)
converts to c string
Definition: string.F90:252
real(real64) function, public target_j1_velocity(tg, ions)
subroutine, public target_chi_velocity(gr, tg, chi_out, ions)
subroutine, public target_output_velocity(tg, namespace, space, gr, dir, ions, hm, outp)
subroutine, public target_tdcalc_velocity(tg, hm, gr, ions, psi, time, max_time)
subroutine, public target_init_velocity(gr, namespace, ions, tg, oct, td, ep)
subroutine, public target_end_velocity(tg, oct)
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