Line data Source code
1 : !--------------------------------------------------------------------------------------------------!
2 : ! CP2K: A general program to perform molecular dynamics simulations !
3 : ! Copyright 2000-2026 CP2K developers group <https://cp2k.org> !
4 : ! !
5 : ! SPDX-License-Identifier: GPL-2.0-or-later !
6 : !--------------------------------------------------------------------------------------------------!
7 :
8 : ! **************************************************************************************************
9 : !> \brief Collection of utilities for setting-up and handle velocities in MD
10 : !> runs
11 : !> \author CJM
12 : !> \author Teodoro Laino [tlaino] - University of Zurich - 10.2008
13 : !> reorganization of the original routines/modules
14 : !> Teodoro Laino [tlaino] 12.2008 - Preparing for VIRTUAL SITE constraints
15 : !> (patch by Marcel Baer)
16 : ! **************************************************************************************************
17 : MODULE md_vel_utils
18 : USE atomic_kind_list_types, ONLY: atomic_kind_list_type
19 : USE atomic_kind_types, ONLY: atomic_kind_type,&
20 : get_atomic_kind,&
21 : get_atomic_kind_set
22 : USE bibliography, ONLY: West2006,&
23 : cite_reference
24 : USE cell_types, ONLY: &
25 : cell_transform_input_cartesian, cell_type, use_perd_none, use_perd_x, use_perd_xy, &
26 : use_perd_xyz, use_perd_xz, use_perd_y, use_perd_yz, use_perd_z
27 : USE cp_linked_list_input, ONLY: cp_sll_val_next,&
28 : cp_sll_val_type
29 : USE cp_log_handling, ONLY: cp_get_default_logger,&
30 : cp_logger_type
31 : USE cp_output_handling, ONLY: cp_print_key_finished_output,&
32 : cp_print_key_unit_nr
33 : USE cp_subsys_types, ONLY: cp_subsys_get,&
34 : cp_subsys_type
35 : USE cp_units, ONLY: cp_unit_from_cp2k
36 : USE extended_system_types, ONLY: npt_info_type
37 : USE force_env_methods, ONLY: force_env_calc_energy_force
38 : USE force_env_types, ONLY: force_env_get,&
39 : force_env_type
40 : USE force_env_utils, ONLY: force_env_rattle,&
41 : force_env_shake
42 : USE global_types, ONLY: global_environment_type
43 : USE input_constants, ONLY: &
44 : md_init_default, md_init_vib, npe_f_ensemble, npe_i_ensemble, &
45 : nph_uniaxial_damped_ensemble, nph_uniaxial_ensemble, npt_f_ensemble, npt_i_ensemble, &
46 : npt_ia_ensemble, reftraj_ensemble
47 : USE input_cp2k_binary_restarts, ONLY: read_binary_velocities
48 : USE input_restart_force_eval, ONLY: update_subsys
49 : USE input_section_types, ONLY: section_vals_get,&
50 : section_vals_get_subs_vals,&
51 : section_vals_list_get,&
52 : section_vals_type,&
53 : section_vals_val_get
54 : USE input_val_types, ONLY: val_get,&
55 : val_type
56 : USE kinds, ONLY: default_string_length,&
57 : dp
58 : USE mathconstants, ONLY: pi
59 : USE mathlib, ONLY: diamat_all
60 : USE md_ener_types, ONLY: md_ener_type
61 : USE md_environment_types, ONLY: get_md_env,&
62 : md_environment_type
63 : USE md_util, ONLY: read_vib_eigs_unformatted
64 : USE message_passing, ONLY: mp_para_env_type
65 : USE molecule_kind_list_types, ONLY: molecule_kind_list_type
66 : USE molecule_kind_types, ONLY: fixd_constraint_type,&
67 : get_molecule_kind,&
68 : get_molecule_kind_set,&
69 : molecule_kind_type
70 : USE parallel_rng_types, ONLY: UNIFORM,&
71 : rng_stream_type
72 : USE particle_list_types, ONLY: particle_list_type
73 : USE particle_types, ONLY: particle_type
74 : USE physcon, ONLY: kelvin
75 : USE shell_opt, ONLY: optimize_shell_core
76 : USE shell_potential_types, ONLY: shell_kind_type
77 : USE simpar_types, ONLY: simpar_type
78 : USE thermal_region_types, ONLY: thermal_region_type,&
79 : thermal_regions_type
80 : #include "../base/base_uses.f90"
81 :
82 : IMPLICIT NONE
83 :
84 : PRIVATE
85 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'md_vel_utils'
86 :
87 : PUBLIC :: temperature_control, &
88 : comvel_control, &
89 : angvel_control, &
90 : setup_velocities
91 :
92 : CONTAINS
93 :
94 : ! **************************************************************************************************
95 : !> \brief compute center of mass position
96 : !> *** is only used by initialize_velocities below ***
97 : !> \param part ...
98 : !> \param is_fixed ...
99 : !> \param rcom ...
100 : !> \par History
101 : !> 2007-11-6: created
102 : !> \author Toon Verstraelen <Toon.Verstraelen@gmail.com>
103 : ! **************************************************************************************************
104 108 : SUBROUTINE compute_rcom(part, is_fixed, rcom)
105 : TYPE(particle_type), DIMENSION(:), POINTER :: part
106 : INTEGER, DIMENSION(:), INTENT(IN) :: is_fixed
107 : REAL(KIND=dp), DIMENSION(3), INTENT(OUT) :: rcom
108 :
109 : INTEGER :: i
110 : REAL(KIND=dp) :: denom, mass
111 : TYPE(atomic_kind_type), POINTER :: atomic_kind
112 :
113 108 : rcom(:) = 0.0_dp
114 108 : denom = 0.0_dp
115 1269 : DO i = 1, SIZE(part)
116 1161 : atomic_kind => part(i)%atomic_kind
117 1161 : CALL get_atomic_kind(atomic_kind=atomic_kind, mass=mass)
118 1269 : SELECT CASE (is_fixed(i))
119 : CASE (use_perd_x, use_perd_y, use_perd_z, use_perd_xy, use_perd_xz, use_perd_yz, use_perd_none)
120 1161 : rcom(1) = rcom(1) + part(i)%r(1)*mass
121 1161 : rcom(2) = rcom(2) + part(i)%r(2)*mass
122 1161 : rcom(3) = rcom(3) + part(i)%r(3)*mass
123 1161 : denom = denom + mass
124 : END SELECT
125 : END DO
126 432 : rcom = rcom/denom
127 :
128 108 : END SUBROUTINE compute_rcom
129 :
130 : ! **************************************************************************************************
131 : !> \brief compute center of mass velocity
132 : !> *** is only used by initialize_velocities below ***
133 : !> \param part ...
134 : !> \param is_fixed ...
135 : !> \param vcom ...
136 : !> \param ecom ...
137 : !> \par History
138 : !> 2007-11-6: created
139 : !> \author Toon Verstraelen <Toon.Verstraelen@gmail.com>
140 : ! **************************************************************************************************
141 3179 : SUBROUTINE compute_vcom(part, is_fixed, vcom, ecom)
142 : TYPE(particle_type), DIMENSION(:), POINTER :: part
143 : INTEGER, DIMENSION(:), INTENT(IN) :: is_fixed
144 : REAL(KIND=dp), DIMENSION(3), INTENT(OUT) :: vcom
145 : REAL(KIND=dp), INTENT(OUT), OPTIONAL :: ecom
146 :
147 : INTEGER :: i
148 : REAL(KIND=dp) :: denom, mass
149 : TYPE(atomic_kind_type), POINTER :: atomic_kind
150 :
151 3179 : vcom = 0.0_dp
152 3179 : denom = 0.0_dp
153 747154 : DO i = 1, SIZE(part)
154 743975 : atomic_kind => part(i)%atomic_kind
155 743975 : CALL get_atomic_kind(atomic_kind=atomic_kind, mass=mass)
156 747154 : IF (mass /= 0.0) THEN
157 1480582 : SELECT CASE (is_fixed(i))
158 : CASE (use_perd_x, use_perd_y, use_perd_z, use_perd_xy, use_perd_xz, use_perd_yz, use_perd_none)
159 737933 : vcom(1) = vcom(1) + part(i)%v(1)*mass
160 737933 : vcom(2) = vcom(2) + part(i)%v(2)*mass
161 737933 : vcom(3) = vcom(3) + part(i)%v(3)*mass
162 742649 : denom = denom + mass
163 : END SELECT
164 : END IF
165 : END DO
166 12716 : vcom = vcom/denom
167 3179 : IF (PRESENT(ecom)) THEN
168 4364 : ecom = 0.5_dp*denom*SUM(vcom*vcom)
169 : END IF
170 :
171 3179 : END SUBROUTINE compute_vcom
172 :
173 : ! **************************************************************************************************
174 : !> \brief Copy atom velocities into core and shell velocities
175 : !> *** is only used by initialize_velocities below ***
176 : !> \param part ...
177 : !> \param shell_part ...
178 : !> \param core_part ...
179 : !> \par History
180 : !> 2007-11-6: created
181 : !> \author Toon Verstraelen <Toon.Verstraelen@gmail.com>
182 : ! **************************************************************************************************
183 8 : SUBROUTINE clone_core_shell_vel(part, shell_part, core_part)
184 : TYPE(particle_type), DIMENSION(:), POINTER :: part, shell_part, core_part
185 :
186 : INTEGER :: i
187 : LOGICAL :: is_shell
188 : TYPE(atomic_kind_type), POINTER :: atomic_kind
189 :
190 776 : DO i = 1, SIZE(part)
191 768 : atomic_kind => part(i)%atomic_kind
192 768 : CALL get_atomic_kind(atomic_kind=atomic_kind, shell_active=is_shell)
193 776 : IF (is_shell) THEN
194 6144 : shell_part(part(i)%shell_index)%v(:) = part(i)%v(:)
195 6144 : core_part(part(i)%shell_index)%v(:) = part(i)%v(:)
196 : END IF
197 : END DO
198 :
199 8 : END SUBROUTINE clone_core_shell_vel
200 :
201 : ! **************************************************************************************************
202 : !> \brief Compute the kinetic energy. Does not subtract the center of mass kinetic
203 : !> energy.
204 : !> *** is only used by initialize_velocities below ***
205 : !> \param part ...
206 : !> \param ireg ...
207 : !> \return ...
208 : !> \par History
209 : !> 2007-11-6: created
210 : !> \author Toon Verstraelen <Toon.Verstraelen@gmail.com>
211 : ! **************************************************************************************************
212 3445 : FUNCTION compute_ekin(part, ireg) RESULT(ekin)
213 : TYPE(particle_type), DIMENSION(:), POINTER :: part
214 : INTEGER, INTENT(IN), OPTIONAL :: ireg
215 : REAL(KIND=dp) :: ekin
216 :
217 : INTEGER :: i
218 : REAL(KIND=dp) :: mass
219 : TYPE(atomic_kind_type), POINTER :: atomic_kind
220 :
221 3445 : NULLIFY (atomic_kind)
222 3445 : ekin = 0.0_dp
223 3445 : IF (PRESENT(ireg)) THEN
224 13756 : DO i = 1, SIZE(part)
225 13756 : IF (part(i)%t_region_index == ireg) THEN
226 4560 : atomic_kind => part(i)%atomic_kind
227 4560 : CALL get_atomic_kind(atomic_kind=atomic_kind, mass=mass)
228 18240 : ekin = ekin + 0.5_dp*mass*SUM(part(i)%v(:)*part(i)%v(:))
229 : END IF
230 : END DO
231 : ELSE
232 746960 : DO i = 1, SIZE(part)
233 743783 : atomic_kind => part(i)%atomic_kind
234 743783 : CALL get_atomic_kind(atomic_kind=atomic_kind, mass=mass)
235 2978309 : ekin = ekin + 0.5_dp*mass*SUM(part(i)%v(:)*part(i)%v(:))
236 : END DO
237 : END IF
238 :
239 3445 : END FUNCTION compute_ekin
240 :
241 : ! **************************************************************************************************
242 : !> \brief Rescale the velocity to mimic the given external kinetic temperature.
243 : !> Optionally also rescale vcom.
244 : !> *** is only used by initialize_velocities below ***
245 : !> \param part ...
246 : !> \param simpar ...
247 : !> \param ekin ...
248 : !> \param vcom ...
249 : !> \param ireg ...
250 : !> \param nfree ...
251 : !> \param temp ...
252 : !> \par History
253 : !> 2007-11-6: created
254 : !> \author Toon Verstraelen <Toon.Verstraelen@gmail.com>
255 : ! **************************************************************************************************
256 2116 : SUBROUTINE rescale_vel(part, simpar, ekin, vcom, ireg, nfree, temp)
257 : TYPE(particle_type), DIMENSION(:), POINTER :: part
258 : TYPE(simpar_type), POINTER :: simpar
259 : REAL(KIND=dp), INTENT(INOUT) :: ekin
260 : REAL(KIND=dp), DIMENSION(3), INTENT(INOUT), &
261 : OPTIONAL :: vcom
262 : INTEGER, INTENT(IN), OPTIONAL :: ireg, nfree
263 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: temp
264 :
265 : INTEGER :: i, my_ireg, my_nfree
266 : REAL(KIND=dp) :: factor, my_temp
267 :
268 2116 : IF (PRESENT(ireg) .AND. PRESENT(nfree) .AND. PRESENT(temp)) THEN
269 6 : my_ireg = ireg
270 6 : my_nfree = nfree
271 6 : my_temp = temp
272 2110 : ELSE IF (PRESENT(nfree)) THEN
273 0 : my_ireg = 0
274 0 : my_nfree = nfree
275 0 : my_temp = simpar%temp_ext
276 : ELSE
277 2110 : my_ireg = 0
278 2110 : my_nfree = simpar%nfree
279 2110 : my_temp = simpar%temp_ext
280 : END IF
281 2116 : IF (my_nfree /= 0) THEN
282 2104 : factor = my_temp/(2.0_dp*ekin)*REAL(my_nfree, KIND=dp)
283 : ELSE
284 : factor = 0.0_dp
285 : END IF
286 : ! Note:
287 : ! this rescaling is still wrong, it should take the masses into account
288 : ! rescaling is generally not correct, so needs fixing
289 2116 : ekin = ekin*factor
290 2116 : factor = SQRT(factor)
291 2116 : IF (PRESENT(ireg)) THEN
292 582 : DO i = 1, SIZE(part)
293 1158 : IF (part(i)%t_region_index == my_ireg) part(i)%v(:) = factor*part(i)%v(:)
294 : END DO
295 : ELSE
296 445292 : DO i = 1, SIZE(part)
297 1774838 : part(i)%v(:) = factor*part(i)%v(:)
298 : END DO
299 2110 : IF (PRESENT(vcom)) THEN
300 96 : vcom = factor*vcom
301 : END IF
302 : END IF
303 :
304 2116 : END SUBROUTINE rescale_vel
305 :
306 : ! **************************************************************************************************
307 : !> \brief Rescale the velocity of separated regions independently
308 : !> \param part ...
309 : !> \param md_env ...
310 : !> \param simpar ...
311 : !> \par History
312 : !> 2008-11
313 : !> \author MI
314 : ! **************************************************************************************************
315 2 : SUBROUTINE rescale_vel_region(part, md_env, simpar)
316 :
317 : TYPE(particle_type), DIMENSION(:), POINTER :: part
318 : TYPE(md_environment_type), POINTER :: md_env
319 : TYPE(simpar_type), POINTER :: simpar
320 :
321 : INTEGER :: ireg, nfree, nfree0, nfree_done
322 : REAL(KIND=dp) :: ekin, temp
323 : TYPE(thermal_region_type), POINTER :: t_region
324 : TYPE(thermal_regions_type), POINTER :: thermal_regions
325 :
326 2 : NULLIFY (thermal_regions, t_region)
327 :
328 2 : CALL get_md_env(md_env, thermal_regions=thermal_regions)
329 2 : nfree_done = 0
330 6 : DO ireg = 1, thermal_regions%nregions
331 4 : NULLIFY (t_region)
332 4 : t_region => thermal_regions%thermal_region(ireg)
333 4 : nfree = t_region%npart*3
334 4 : ekin = compute_ekin(part, ireg)
335 4 : temp = t_region%temp_expected
336 4 : CALL rescale_vel(part, simpar, ekin, ireg=ireg, nfree=nfree, temp=temp)
337 4 : nfree_done = nfree_done + nfree
338 4 : ekin = compute_ekin(part, ireg)
339 4 : temp = 2.0_dp*ekin/REAL(nfree, dp)*kelvin
340 6 : t_region%temperature = temp
341 : END DO
342 2 : nfree0 = simpar%nfree - nfree_done
343 2 : IF (nfree0 > 0) THEN
344 2 : ekin = compute_ekin(part, 0)
345 2 : CALL rescale_vel(part, simpar, ekin, ireg=0, nfree=nfree0, temp=simpar%temp_ext)
346 2 : ekin = compute_ekin(part, 0)
347 2 : temp = 2.0_dp*ekin/REAL(nfree0, dp)*kelvin
348 2 : thermal_regions%temp_reg0 = temp
349 : END IF
350 2 : END SUBROUTINE rescale_vel_region
351 :
352 : ! **************************************************************************************************
353 : !> \brief subtract center of mass velocity
354 : !> *** is only used by initialize_velocities below ***
355 : !> \param part ...
356 : !> \param is_fixed ...
357 : !> \param vcom ...
358 : !> \par History
359 : !> 2007-11-6: created
360 : !> \author Toon Verstraelen <Toon.Verstraelen@gmail.com>
361 : ! **************************************************************************************************
362 2088 : SUBROUTINE subtract_vcom(part, is_fixed, vcom)
363 : TYPE(particle_type), DIMENSION(:), POINTER :: part
364 : INTEGER, DIMENSION(:), INTENT(IN) :: is_fixed
365 : REAL(KIND=dp), DIMENSION(3), INTENT(IN) :: vcom
366 :
367 : INTEGER :: i
368 :
369 443592 : DO i = 1, SIZE(part)
370 2088 : SELECT CASE (is_fixed(i))
371 : CASE (use_perd_x)
372 512 : part(i)%v(2) = part(i)%v(2) - vcom(2)
373 512 : part(i)%v(3) = part(i)%v(3) - vcom(3)
374 : CASE (use_perd_y)
375 512 : part(i)%v(1) = part(i)%v(1) - vcom(1)
376 512 : part(i)%v(3) = part(i)%v(3) - vcom(3)
377 : CASE (use_perd_z)
378 512 : part(i)%v(1) = part(i)%v(1) - vcom(1)
379 512 : part(i)%v(2) = part(i)%v(2) - vcom(2)
380 : CASE (use_perd_xy)
381 512 : part(i)%v(3) = part(i)%v(3) - vcom(3)
382 : CASE (use_perd_xz)
383 0 : part(i)%v(2) = part(i)%v(2) - vcom(2)
384 : CASE (use_perd_yz)
385 0 : part(i)%v(1) = part(i)%v(1) - vcom(1)
386 : CASE (use_perd_none)
387 1750518 : part(i)%v(:) = part(i)%v(:) - vcom(:)
388 : END SELECT
389 : END DO
390 2088 : END SUBROUTINE subtract_vcom
391 :
392 : ! **************************************************************************************************
393 : !> \brief compute the angular velocity
394 : !> *** is only used by initialize_velocities below ***
395 : !> \param part ...
396 : !> \param is_fixed ...
397 : !> \param rcom ...
398 : !> \param vang ...
399 : !> \par History
400 : !> 2007-11-9: created
401 : !> \author Toon Verstraelen <Toon.Verstraelen@gmail.com>
402 : ! **************************************************************************************************
403 110 : SUBROUTINE compute_vang(part, is_fixed, rcom, vang)
404 : TYPE(particle_type), DIMENSION(:), POINTER :: part
405 : INTEGER, DIMENSION(:), INTENT(IN) :: is_fixed
406 : REAL(KIND=dp), DIMENSION(3), INTENT(IN) :: rcom
407 : REAL(KIND=dp), DIMENSION(3), INTENT(OUT) :: vang
408 :
409 : INTEGER :: i
410 : REAL(KIND=dp) :: mass, proj
411 : REAL(KIND=dp), DIMENSION(3) :: evals, mang, r
412 : REAL(KIND=dp), DIMENSION(3, 3) :: iner
413 : TYPE(atomic_kind_type), POINTER :: atomic_kind
414 :
415 110 : NULLIFY (atomic_kind)
416 110 : mang(:) = 0.0_dp
417 110 : iner(:, :) = 0.0_dp
418 1299 : DO i = 1, SIZE(part)
419 : ! compute angular momentum and inertia tensor
420 110 : SELECT CASE (is_fixed(i))
421 : CASE (use_perd_x, use_perd_y, use_perd_z, use_perd_xy, use_perd_xz, use_perd_yz, use_perd_none)
422 4756 : r(:) = part(i)%r(:) - rcom(:)
423 1189 : atomic_kind => part(i)%atomic_kind
424 1189 : CALL get_atomic_kind(atomic_kind=atomic_kind, mass=mass)
425 1189 : mang(1) = mang(1) + mass*(r(2)*part(i)%v(3) - r(3)*part(i)%v(2))
426 1189 : mang(2) = mang(2) + mass*(r(3)*part(i)%v(1) - r(1)*part(i)%v(3))
427 1189 : mang(3) = mang(3) + mass*(r(1)*part(i)%v(2) - r(2)*part(i)%v(1))
428 :
429 1189 : iner(1, 1) = iner(1, 1) + mass*(r(2)*r(2) + r(3)*r(3))
430 1189 : iner(2, 2) = iner(2, 2) + mass*(r(3)*r(3) + r(1)*r(1))
431 1189 : iner(3, 3) = iner(3, 3) + mass*(r(1)*r(1) + r(2)*r(2))
432 :
433 1189 : iner(1, 2) = iner(1, 2) - mass*r(1)*r(2)
434 1189 : iner(2, 3) = iner(2, 3) - mass*r(2)*r(3)
435 2378 : iner(3, 1) = iner(3, 1) - mass*r(3)*r(1)
436 : END SELECT
437 : END DO
438 110 : iner(2, 1) = iner(1, 2)
439 110 : iner(3, 2) = iner(2, 3)
440 110 : iner(1, 3) = iner(3, 1)
441 :
442 : ! Take the safest route, i.e. diagonalize the inertia tensor and solve
443 : ! the angular velocity only with the non-zero eigenvalues. A plain inversion
444 : ! would fail for linear molecules.
445 110 : CALL diamat_all(iner, evals)
446 :
447 110 : vang(:) = 0.0_dp
448 440 : DO i = 1, 3
449 440 : IF (evals(i) > 0.0_dp) THEN
450 1276 : proj = SUM(iner(:, i)*mang)/evals(i)
451 319 : vang(1) = vang(1) + proj*iner(1, i)
452 319 : vang(2) = vang(2) + proj*iner(2, i)
453 319 : vang(3) = vang(3) + proj*iner(3, i)
454 : END IF
455 : END DO
456 :
457 110 : END SUBROUTINE compute_vang
458 :
459 : ! **************************************************************************************************
460 : !> \brief subtract the angular velocity
461 : !> *** is only used by initialize_velocities below ***
462 : !> \param part ...
463 : !> \param is_fixed ...
464 : !> \param rcom ...
465 : !> \param vang ...
466 : !> \par History
467 : !> 2007-11-9: created
468 : !> \author Toon Verstraelen <Toon.Verstraelen@gmail.com>
469 : ! **************************************************************************************************
470 6 : SUBROUTINE subtract_vang(part, is_fixed, rcom, vang)
471 : TYPE(particle_type), DIMENSION(:), POINTER :: part
472 : INTEGER, DIMENSION(:), INTENT(IN) :: is_fixed
473 : REAL(KIND=dp), DIMENSION(3), INTENT(IN) :: rcom, vang
474 :
475 : INTEGER :: i
476 : REAL(KIND=dp), DIMENSION(3) :: r
477 :
478 52 : DO i = 1, SIZE(part)
479 184 : r(:) = part(i)%r(:) - rcom(:)
480 6 : SELECT CASE (is_fixed(i))
481 : CASE (use_perd_x)
482 0 : part(i)%v(2) = part(i)%v(2) - (vang(3)*r(1) - vang(1)*r(3))
483 0 : part(i)%v(3) = part(i)%v(3) - (vang(1)*r(2) - vang(2)*r(1))
484 : CASE (use_perd_y)
485 0 : part(i)%v(1) = part(i)%v(1) - (vang(2)*r(3) - vang(3)*r(2))
486 0 : part(i)%v(3) = part(i)%v(3) - (vang(1)*r(2) - vang(2)*r(1))
487 : CASE (use_perd_z)
488 0 : part(i)%v(1) = part(i)%v(1) - (vang(2)*r(3) - vang(3)*r(2))
489 0 : part(i)%v(2) = part(i)%v(2) - (vang(3)*r(1) - vang(1)*r(3))
490 : CASE (use_perd_xy)
491 0 : part(i)%v(3) = part(i)%v(3) - (vang(1)*r(2) - vang(2)*r(1))
492 : CASE (use_perd_xz)
493 0 : part(i)%v(2) = part(i)%v(2) - (vang(3)*r(1) - vang(1)*r(3))
494 : CASE (use_perd_yz)
495 0 : part(i)%v(1) = part(i)%v(1) - (vang(2)*r(3) - vang(3)*r(2))
496 : CASE (use_perd_none)
497 46 : part(i)%v(1) = part(i)%v(1) - (vang(2)*r(3) - vang(3)*r(2))
498 46 : part(i)%v(2) = part(i)%v(2) - (vang(3)*r(1) - vang(1)*r(3))
499 46 : part(i)%v(3) = part(i)%v(3) - (vang(1)*r(2) - vang(2)*r(1))
500 : END SELECT
501 : END DO
502 :
503 6 : END SUBROUTINE subtract_vang
504 :
505 : ! **************************************************************************************************
506 : !> \brief Initializes the velocities to the Maxwellian distribution
507 : !> \param simpar ...
508 : !> \param part ...
509 : !> \param force_env ...
510 : !> \param globenv ...
511 : !> \param md_env ...
512 : !> \param molecule_kinds ...
513 : !> \param label ...
514 : !> \param print_section ...
515 : !> \param subsys_section ...
516 : !> \param shell_present ...
517 : !> \param shell_part ...
518 : !> \param core_part ...
519 : !> \param force_rescaling ...
520 : !> \param para_env ...
521 : !> \param write_binary_restart_file ...
522 : !> \par History
523 : !> - is_fixed removed from particle_type
524 : !> - 2007-11-07: Cleanup (TV)
525 : !> - 2007-11-09: Added angvel_zero feature
526 : !> \author CJM,MK,Toon Verstraelen <Toon.Verstraelen@gmail.com>
527 : ! **************************************************************************************************
528 1794 : SUBROUTINE initialize_velocities(simpar, &
529 : part, &
530 : force_env, &
531 : globenv, &
532 : md_env, &
533 : molecule_kinds, &
534 : label, &
535 : print_section, &
536 : subsys_section, &
537 : shell_present, &
538 : shell_part, &
539 : core_part, &
540 : force_rescaling, &
541 : para_env, &
542 : write_binary_restart_file)
543 :
544 : TYPE(simpar_type), POINTER :: simpar
545 : TYPE(particle_type), DIMENSION(:), POINTER :: part
546 : TYPE(force_env_type), POINTER :: force_env
547 : TYPE(global_environment_type), POINTER :: globenv
548 : TYPE(md_environment_type), POINTER :: md_env
549 : TYPE(molecule_kind_list_type), POINTER :: molecule_kinds
550 : CHARACTER(LEN=*), INTENT(IN) :: label
551 : TYPE(section_vals_type), POINTER :: print_section, subsys_section
552 : LOGICAL, INTENT(IN) :: shell_present
553 : TYPE(particle_type), DIMENSION(:), POINTER :: shell_part, core_part
554 : LOGICAL, INTENT(IN) :: force_rescaling
555 : TYPE(mp_para_env_type), POINTER :: para_env
556 : LOGICAL, INTENT(IN) :: write_binary_restart_file
557 :
558 : CHARACTER(LEN=*), PARAMETER :: routineN = 'initialize_velocities'
559 :
560 : INTEGER :: handle, i, ifixd, imolecule_kind, iw, &
561 : natoms
562 : INTEGER, ALLOCATABLE, DIMENSION(:) :: is_fixed
563 : LOGICAL :: success
564 : REAL(KIND=dp) :: ecom, ekin, mass, mass_tot, temp, tmp_r1
565 : REAL(KIND=dp), DIMENSION(3) :: rcom, vang, vcom
566 : TYPE(atomic_kind_type), POINTER :: atomic_kind
567 : TYPE(cell_type), POINTER :: cell
568 : TYPE(cp_logger_type), POINTER :: logger
569 1794 : TYPE(fixd_constraint_type), DIMENSION(:), POINTER :: fixd_list
570 1794 : TYPE(molecule_kind_type), DIMENSION(:), POINTER :: molecule_kind_set
571 : TYPE(molecule_kind_type), POINTER :: molecule_kind
572 : TYPE(section_vals_type), POINTER :: md_section, root_section, vib_section
573 :
574 1794 : CALL timeset(routineN, handle)
575 :
576 : ! Initializing parameters
577 1794 : natoms = SIZE(part)
578 1794 : NULLIFY (atomic_kind, fixd_list, logger, molecule_kind)
579 1794 : NULLIFY (molecule_kind_set)
580 :
581 : ! Logging
582 1794 : logger => cp_get_default_logger()
583 1794 : iw = cp_print_key_unit_nr(logger, print_section, "PROGRAM_RUN_INFO", extension=".log")
584 :
585 : ! Build a list of all fixed atoms (if any)
586 5382 : ALLOCATE (is_fixed(natoms))
587 :
588 1794 : is_fixed = use_perd_none
589 1794 : molecule_kind_set => molecule_kinds%els
590 66614 : DO imolecule_kind = 1, molecule_kinds%n_els
591 64820 : molecule_kind => molecule_kind_set(imolecule_kind)
592 64820 : CALL get_molecule_kind(molecule_kind=molecule_kind, fixd_list=fixd_list)
593 66614 : IF (ASSOCIATED(fixd_list)) THEN
594 5432 : DO ifixd = 1, SIZE(fixd_list)
595 5432 : IF (.NOT. fixd_list(ifixd)%restraint%active) is_fixed(fixd_list(ifixd)%fixd) = fixd_list(ifixd)%itype
596 : END DO
597 : END IF
598 : END DO
599 :
600 : ! Compute the total mass when needed
601 1794 : IF (simpar%ensemble == nph_uniaxial_ensemble .OR. &
602 : simpar%ensemble == nph_uniaxial_damped_ensemble) THEN
603 : mass_tot = 0.0_dp
604 1006 : DO i = 1, natoms
605 1000 : atomic_kind => part(i)%atomic_kind
606 1000 : CALL get_atomic_kind(atomic_kind=atomic_kind, mass=mass)
607 1006 : mass_tot = mass_tot + mass
608 : END DO
609 6 : simpar%v_shock = simpar%v_shock*SQRT(mass_tot)
610 : END IF
611 :
612 : CALL read_input_velocities(simpar, part, force_env, md_env, subsys_section, &
613 1794 : shell_present, shell_part, core_part, force_rescaling, para_env, is_fixed, success)
614 1794 : IF (.NOT. success) THEN
615 3058 : SELECT CASE (simpar%initialization_method)
616 : CASE (md_init_default)
617 : CALL generate_velocities(simpar, part, force_env, globenv, md_env, shell_present, &
618 1528 : shell_part, core_part, is_fixed, iw)
619 : CASE (md_init_vib)
620 2 : CALL force_env_get(force_env=force_env, root_section=root_section)
621 2 : md_section => section_vals_get_subs_vals(root_section, "MOTION%MD")
622 2 : vib_section => section_vals_get_subs_vals(root_section, "VIBRATIONAL_ANALYSIS")
623 : CALL generate_coords_vels_vib(simpar, &
624 : part, &
625 : md_section, &
626 : vib_section, &
627 : force_env, &
628 : globenv, &
629 : shell_present, &
630 : shell_part, &
631 : core_part, &
632 2 : is_fixed)
633 : ! update restart file for the modified coordinates and velocities
634 1532 : CALL update_subsys(subsys_section, force_env, .FALSE., write_binary_restart_file)
635 : END SELECT
636 : END IF
637 :
638 1794 : IF (iw > 0) THEN
639 : WRITE (iw, '(/,T2,A)') &
640 826 : 'MD_VEL| '//TRIM(ADJUSTL(label))
641 : ! Recompute vcom, ecom and ekin for IO
642 826 : CALL compute_vcom(part, is_fixed, vcom, ecom)
643 826 : ekin = compute_ekin(part) - ecom
644 826 : IF (simpar%nfree == 0) THEN
645 6 : CPASSERT(ekin == 0.0_dp)
646 6 : temp = 0.0_dp
647 : ELSE
648 820 : temp = 2.0_dp*ekin/REAL(simpar%nfree, KIND=dp)
649 : END IF
650 826 : tmp_r1 = cp_unit_from_cp2k(temp, "K")
651 : WRITE (iw, '(T2,A,T61,F20.6)') &
652 826 : 'MD_VEL| Initial temperature [K]', tmp_r1
653 : WRITE (iw, '(T2,A,T30,3(1X,F16.10))') &
654 826 : 'MD_VEL| COM velocity', vcom(1:3)
655 :
656 : ! compute and log rcom and vang if not periodic
657 826 : CALL force_env_get(force_env, cell=cell)
658 3304 : IF (SUM(cell%perd(1:3)) == 0) THEN
659 64 : CALL compute_rcom(part, is_fixed, rcom)
660 64 : CALL compute_vang(part, is_fixed, rcom, vang)
661 : WRITE (iw, '(T2,A,T30,3(1X,F16.10))') &
662 64 : 'MD_VEL| COM position', rcom(1:3)
663 : WRITE (iw, '(T2,A,T30,3(1X,F16.10))') &
664 64 : 'MD_VEL| Angular velocity', vang(1:3)
665 : END IF
666 : END IF
667 :
668 1794 : DEALLOCATE (is_fixed)
669 1794 : CALL cp_print_key_finished_output(iw, logger, print_section, "PROGRAM_RUN_INFO")
670 1794 : CALL timestop(handle)
671 :
672 3588 : END SUBROUTINE initialize_velocities
673 :
674 : ! **************************************************************************************************
675 : !> \brief Read velocities from binary restart file if available
676 : !> \param simpar ...
677 : !> \param part ...
678 : !> \param force_env ...
679 : !> \param md_env ...
680 : !> \param subsys_section ...
681 : !> \param shell_present ...
682 : !> \param shell_part ...
683 : !> \param core_part ...
684 : !> \param force_rescaling ...
685 : !> \param para_env ...
686 : !> \param is_fixed ...
687 : !> \param success ...
688 : !> \author CJM,MK,Toon Verstraelen <Toon.Verstraelen@gmail.com>
689 : ! **************************************************************************************************
690 12558 : SUBROUTINE read_input_velocities(simpar, part, force_env, md_env, subsys_section, &
691 1794 : shell_present, shell_part, core_part, force_rescaling, para_env, is_fixed, success)
692 : TYPE(simpar_type), POINTER :: simpar
693 : TYPE(particle_type), DIMENSION(:), POINTER :: part
694 : TYPE(force_env_type), POINTER :: force_env
695 : TYPE(md_environment_type), POINTER :: md_env
696 : TYPE(section_vals_type), POINTER :: subsys_section
697 : LOGICAL, INTENT(IN) :: shell_present
698 : TYPE(particle_type), DIMENSION(:), POINTER :: shell_part, core_part
699 : LOGICAL, INTENT(IN) :: force_rescaling
700 : TYPE(mp_para_env_type), POINTER :: para_env
701 : INTEGER, DIMENSION(:), INTENT(INOUT) :: is_fixed
702 : LOGICAL, INTENT(OUT) :: success
703 :
704 : INTEGER :: i, natoms, nshell, shell_index
705 : LOGICAL :: atomvel_explicit, atomvel_read, corevel_explicit, corevel_read, is_ok, &
706 : rescale_regions, shellvel_explicit, shellvel_read
707 : REAL(KIND=dp) :: ecom, ekin, fac_massc, fac_masss, mass
708 : REAL(KIND=dp), DIMENSION(3) :: vc, vcom, vs
709 1794 : REAL(KIND=dp), DIMENSION(:), POINTER :: vel
710 : TYPE(atomic_kind_type), POINTER :: atomic_kind
711 : TYPE(cell_type), POINTER :: cell
712 : TYPE(cp_sll_val_type), POINTER :: atom_list, core_list, shell_list
713 : TYPE(section_vals_type), POINTER :: atomvel_section, corevel_section, &
714 : shellvel_section
715 : TYPE(shell_kind_type), POINTER :: shell
716 : TYPE(thermal_regions_type), POINTER :: thermal_regions
717 : TYPE(val_type), POINTER :: val
718 :
719 : ! Initializing parameters
720 :
721 1794 : success = .FALSE.
722 1794 : natoms = SIZE(part)
723 : atomvel_read = .FALSE.
724 : corevel_read = .FALSE.
725 : shellvel_read = .FALSE.
726 1794 : NULLIFY (vel, atomic_kind, atom_list, core_list, shell_list)
727 1794 : NULLIFY (atomvel_section, shellvel_section, corevel_section)
728 1794 : NULLIFY (cell, shell, thermal_regions, val)
729 1794 : CALL force_env_get(force_env, cell=cell)
730 :
731 : ! Core-Shell Model
732 1794 : nshell = 0
733 1794 : IF (shell_present) THEN
734 132 : CPASSERT(ASSOCIATED(core_part))
735 132 : CPASSERT(ASSOCIATED(shell_part))
736 132 : nshell = SIZE(shell_part)
737 : END IF
738 :
739 1794 : atomvel_section => section_vals_get_subs_vals(subsys_section, "VELOCITY")
740 1794 : shellvel_section => section_vals_get_subs_vals(subsys_section, "SHELL_VELOCITY")
741 1794 : corevel_section => section_vals_get_subs_vals(subsys_section, "CORE_VELOCITY")
742 :
743 : ! Read or initialize the particle velocities
744 1794 : CALL section_vals_get(atomvel_section, explicit=atomvel_explicit)
745 1794 : CALL section_vals_get(shellvel_section, explicit=shellvel_explicit)
746 1794 : CALL section_vals_get(corevel_section, explicit=corevel_explicit)
747 1794 : CPASSERT(shellvel_explicit .EQV. corevel_explicit)
748 :
749 : CALL read_binary_velocities("", part, force_env%root_section, para_env, &
750 1794 : subsys_section, atomvel_read, cell)
751 : CALL read_binary_velocities("SHELL", shell_part, force_env%root_section, para_env, &
752 1794 : subsys_section, shellvel_read, cell)
753 : CALL read_binary_velocities("CORE", core_part, force_env%root_section, para_env, &
754 1794 : subsys_section, corevel_read, cell)
755 :
756 1794 : IF (.NOT. (atomvel_explicit .OR. atomvel_read)) RETURN
757 264 : success = .TRUE.
758 :
759 264 : IF (.NOT. atomvel_read) THEN
760 : ! Read the atom velocities if explicitly given in the input file
761 218 : CALL section_vals_list_get(atomvel_section, "_DEFAULT_KEYWORD_", list=atom_list)
762 52296 : DO i = 1, natoms
763 52078 : is_ok = cp_sll_val_next(atom_list, val)
764 52078 : CALL val_get(val, r_vals=vel)
765 364546 : part(i)%v = vel
766 52296 : CALL cell_transform_input_cartesian(cell, part(i)%v)
767 : END DO
768 : END IF
769 56758 : DO i = 1, natoms
770 264 : SELECT CASE (is_fixed(i))
771 : CASE (use_perd_x)
772 0 : part(i)%v(1) = 0.0_dp
773 : CASE (use_perd_y)
774 0 : part(i)%v(2) = 0.0_dp
775 : CASE (use_perd_z)
776 0 : part(i)%v(3) = 0.0_dp
777 : CASE (use_perd_xy)
778 0 : part(i)%v(1) = 0.0_dp
779 0 : part(i)%v(2) = 0.0_dp
780 : CASE (use_perd_xz)
781 0 : part(i)%v(1) = 0.0_dp
782 0 : part(i)%v(3) = 0.0_dp
783 : CASE (use_perd_yz)
784 0 : part(i)%v(2) = 0.0_dp
785 0 : part(i)%v(3) = 0.0_dp
786 : CASE (use_perd_xyz)
787 56572 : part(i)%v = 0.0_dp
788 : END SELECT
789 : END DO
790 264 : IF (shell_present) THEN
791 48 : IF (shellvel_explicit) THEN
792 : ! If the atoms positions are given (?) and core and shell velocities are
793 : ! present in the input, read the latter.
794 24 : CALL section_vals_list_get(shellvel_section, "_DEFAULT_KEYWORD_", list=shell_list)
795 24 : CALL section_vals_list_get(corevel_section, "_DEFAULT_KEYWORD_", list=core_list)
796 2328 : DO i = 1, nshell
797 2304 : is_ok = cp_sll_val_next(shell_list, val)
798 2304 : CALL val_get(val, r_vals=vel)
799 16128 : shell_part(i)%v = vel
800 2304 : CALL cell_transform_input_cartesian(cell, shell_part(i)%v)
801 2304 : is_ok = cp_sll_val_next(core_list, val)
802 2304 : CALL val_get(val, r_vals=vel)
803 16128 : core_part(i)%v = vel
804 2328 : CALL cell_transform_input_cartesian(cell, core_part(i)%v)
805 : END DO
806 : ELSE
807 24 : IF (.NOT. (shellvel_read .AND. corevel_read)) THEN
808 : ! Otherwise, just copy atom velocties into shell and core velocities.
809 8 : CALL clone_core_shell_vel(part, shell_part, core_part)
810 : END IF
811 : END IF
812 : END IF
813 :
814 : ! compute vcom, ecom and ekin
815 264 : CALL compute_vcom(part, is_fixed, vcom, ecom)
816 264 : ekin = compute_ekin(part) - ecom
817 :
818 264 : IF (simpar%do_thermal_region) THEN
819 12 : CALL get_md_env(md_env, thermal_regions=thermal_regions)
820 12 : IF (ASSOCIATED(thermal_regions)) THEN
821 12 : rescale_regions = thermal_regions%force_rescaling
822 : END IF
823 : ELSE
824 : rescale_regions = .FALSE.
825 : END IF
826 264 : IF (simpar%nfree /= 0 .AND. (force_rescaling .OR. rescale_regions)) THEN
827 24 : IF (simpar%do_thermal_region) THEN
828 0 : CALL rescale_vel_region(part, md_env, simpar)
829 : ELSE
830 24 : CALL rescale_vel(part, simpar, ekin, vcom=vcom)
831 : END IF
832 :
833 : ! After rescaling, the core and shell velocities must also adapt.
834 1894 : DO i = 1, natoms
835 1870 : shell_index = part(i)%shell_index
836 2134 : IF (shell_present .AND. shell_index /= 0) THEN
837 0 : atomic_kind => part(i)%atomic_kind
838 0 : CALL get_atomic_kind(atomic_kind=atomic_kind, mass=mass, shell=shell)
839 0 : fac_masss = shell%mass_shell/mass
840 0 : fac_massc = shell%mass_core/mass
841 0 : vs = shell_part(shell_index)%v
842 0 : vc = core_part(shell_index)%v
843 :
844 0 : shell_part(shell_index)%v(1) = part(i)%v(1) + fac_massc*(vs(1) - vc(1))
845 0 : shell_part(shell_index)%v(2) = part(i)%v(2) + fac_massc*(vs(2) - vc(2))
846 0 : shell_part(shell_index)%v(3) = part(i)%v(3) + fac_massc*(vs(3) - vc(3))
847 0 : core_part(shell_index)%v(1) = part(i)%v(1) + fac_masss*(vc(1) - vs(1))
848 0 : core_part(shell_index)%v(2) = part(i)%v(2) + fac_masss*(vc(2) - vs(2))
849 0 : core_part(shell_index)%v(3) = part(i)%v(3) + fac_masss*(vc(3) - vs(3))
850 : END IF
851 : END DO
852 : END IF
853 1794 : END SUBROUTINE read_input_velocities
854 :
855 : ! **************************************************************************************************
856 : !> \brief Initializing velocities AND positions randomly on all processors, based on vibrational
857 : !> modes of the system, so that the starting coordinates are already very close to
858 : !> canonical ensumble corresponding to temperature of a head bath.
859 : !> \param simpar : MD simulation parameters
860 : !> \param particles : global array of all particles
861 : !> \param md_section : MD input subsection
862 : !> \param vib_section : vibrational analysis input section
863 : !> \param force_env : force environment container
864 : !> \param global_env : global environment container
865 : !> \param shell_present : if core-shell model is used
866 : !> \param shell_particles : global array of all shell particles in shell model
867 : !> \param core_particles : global array of all core particles in shell model
868 : !> \param is_fixed : array of size of total number of atoms, that determines if any
869 : !> cartesian components are fixed
870 : !> \author CJM,MK,Toon Verstraelen <Toon.Verstraelen@gmail.com>, Ole Schuett
871 : ! **************************************************************************************************
872 2 : SUBROUTINE generate_coords_vels_vib(simpar, &
873 : particles, &
874 : md_section, &
875 : vib_section, &
876 : force_env, &
877 : global_env, &
878 : shell_present, &
879 : shell_particles, &
880 : core_particles, &
881 2 : is_fixed)
882 : TYPE(simpar_type), POINTER :: simpar
883 : TYPE(particle_type), DIMENSION(:), POINTER :: particles
884 : TYPE(section_vals_type), POINTER :: md_section, vib_section
885 : TYPE(force_env_type), POINTER :: force_env
886 : TYPE(global_environment_type), POINTER :: global_env
887 : LOGICAL, INTENT(IN) :: shell_present
888 : TYPE(particle_type), DIMENSION(:), POINTER :: shell_particles, core_particles
889 : INTEGER, DIMENSION(:), INTENT(IN) :: is_fixed
890 :
891 : INTEGER :: dof, fixed_dof, iatom, ii, imode, &
892 : my_dof, natoms, shell_index
893 : REAL(KIND=dp) :: Erand, mass, my_phase, ratio, temperature
894 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: eigenvalues, phase, random
895 2 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: dr, eigenvectors
896 : TYPE(atomic_kind_type), POINTER :: atomic_kind
897 : TYPE(mp_para_env_type), POINTER :: para_env
898 2 : TYPE(rng_stream_type), ALLOCATABLE :: random_stream
899 :
900 2 : CALL cite_reference(West2006)
901 2 : natoms = SIZE(particles)
902 2 : temperature = simpar%temp_ext
903 2 : my_dof = 3*natoms
904 6 : ALLOCATE (eigenvalues(my_dof))
905 8 : ALLOCATE (eigenvectors(my_dof, my_dof))
906 4 : ALLOCATE (phase(my_dof))
907 4 : ALLOCATE (random(my_dof))
908 6 : ALLOCATE (dr(3, natoms))
909 2 : CALL force_env_get(force_env=force_env, para_env=para_env)
910 : ! read vibration modes
911 : CALL read_vib_eigs_unformatted(md_section, &
912 : vib_section, &
913 : para_env, &
914 : dof, &
915 : eigenvalues, &
916 2 : eigenvectors)
917 2 : IF (my_dof /= dof) THEN
918 : CALL cp_abort(__LOCATION__, &
919 : "number of degrees of freedom in vibrational analysis data "// &
920 0 : "do not match total number of cartesian degrees of freedom")
921 : END IF
922 : ! read phases
923 2 : CALL section_vals_val_get(md_section, "INITIAL_VIBRATION%PHASE", r_val=my_phase)
924 2 : my_phase = MIN(1.0_dp, my_phase)
925 : ! generate random numbers
926 2 : random_stream = rng_stream_type(name="MD_INIT_VIB", distribution_type=UNIFORM)
927 2 : CALL random_stream%fill(random)
928 2 : IF (my_phase < 0.0_dp) THEN
929 0 : CALL random_stream%fill(phase)
930 : ELSE
931 20 : phase = my_phase
932 : END IF
933 2 : DEALLOCATE (random_stream)
934 :
935 : ! the first three modes are acoustic with zero frequencies,
936 : ! exclude these from considerations
937 2 : my_dof = dof - 3
938 : ! randomly selects energy from distribution about kT, all
939 : ! energies are scaled so that the sum over vibration modes gives
940 : ! exactly my_dof*kT. Note that k = 1.0 in atomic units
941 2 : Erand = 0.0_dp
942 14 : DO imode = 4, dof
943 14 : Erand = Erand - temperature*LOG(1.0_dp - random(imode))
944 : END DO
945 : ! need to take into account of fixed constraints too
946 2 : fixed_dof = 0
947 8 : DO iatom = 1, natoms
948 2 : SELECT CASE (is_fixed(iatom))
949 : CASE (use_perd_x, use_perd_y, use_perd_z)
950 0 : fixed_dof = fixed_dof + 1
951 : CASE (use_perd_xy, use_perd_xz, use_perd_yz)
952 0 : fixed_dof = fixed_dof + 2
953 : CASE (use_perd_xyz)
954 6 : fixed_dof = fixed_dof + 3
955 : END SELECT
956 : END DO
957 2 : my_dof = my_dof - fixed_dof
958 2 : ratio = REAL(my_dof, KIND=dp)*temperature/Erand
959 : ! update velocities AND positions
960 8 : DO iatom = 1, natoms
961 6 : atomic_kind => particles(iatom)%atomic_kind
962 6 : CALL get_atomic_kind(atomic_kind=atomic_kind, mass=mass)
963 8 : SELECT CASE (is_fixed(iatom))
964 : CASE (use_perd_x)
965 0 : DO ii = 2, 3
966 : dr(ii, iatom) = dr_from_vib_data(iatom, ii, mass, temperature, eigenvalues, &
967 0 : eigenvectors, random, phase, dof, ratio)
968 : particles(iatom)%v(ii) = dv_from_vib_data(iatom, ii, mass, temperature, &
969 : eigenvectors, random, phase, dof, &
970 0 : ratio)
971 : END DO
972 : CASE (use_perd_y)
973 0 : DO ii = 1, 3, 2
974 : dr(ii, iatom) = dr_from_vib_data(iatom, ii, mass, temperature, eigenvalues, &
975 0 : eigenvectors, random, phase, dof, ratio)
976 : particles(iatom)%v(ii) = dv_from_vib_data(iatom, ii, mass, temperature, &
977 : eigenvectors, random, phase, dof, &
978 0 : ratio)
979 : END DO
980 : CASE (use_perd_z)
981 0 : DO ii = 1, 2
982 : dr(ii, iatom) = dr_from_vib_data(iatom, ii, mass, temperature, eigenvalues, &
983 0 : eigenvectors, random, phase, dof, ratio)
984 : particles(iatom)%v(ii) = dv_from_vib_data(iatom, ii, mass, temperature, &
985 : eigenvectors, random, phase, dof, &
986 0 : ratio)
987 : END DO
988 : CASE (use_perd_xy)
989 : dr(3, iatom) = dr_from_vib_data(iatom, 3, mass, temperature, eigenvalues, &
990 0 : eigenvectors, random, phase, dof, ratio)
991 : particles(iatom)%v(3) = dv_from_vib_data(iatom, 3, mass, temperature, &
992 : eigenvectors, random, phase, dof, &
993 0 : ratio)
994 : CASE (use_perd_xz)
995 : dr(2, iatom) = dr_from_vib_data(iatom, 2, mass, temperature, eigenvalues, &
996 0 : eigenvectors, random, phase, dof, ratio)
997 : particles(iatom)%v(2) = dv_from_vib_data(iatom, 2, mass, temperature, &
998 : eigenvectors, random, phase, dof, &
999 0 : ratio)
1000 : CASE (use_perd_yz)
1001 : dr(1, iatom) = dr_from_vib_data(iatom, 1, mass, temperature, eigenvalues, &
1002 0 : eigenvectors, random, phase, dof, ratio)
1003 : particles(iatom)%v(1) = dv_from_vib_data(iatom, 1, mass, temperature, &
1004 : eigenvectors, random, phase, dof, &
1005 0 : ratio)
1006 : CASE (use_perd_none)
1007 24 : DO ii = 1, 3
1008 : dr(ii, iatom) = dr_from_vib_data(iatom, ii, mass, temperature, eigenvalues, &
1009 18 : eigenvectors, random, phase, dof, ratio)
1010 : particles(iatom)%v(ii) = dv_from_vib_data(iatom, ii, mass, temperature, &
1011 : eigenvectors, random, phase, dof, &
1012 24 : ratio)
1013 : END DO
1014 : END SELECT
1015 : END DO ! iatom
1016 : ! free memory
1017 2 : DEALLOCATE (eigenvalues)
1018 2 : DEALLOCATE (eigenvectors)
1019 2 : DEALLOCATE (phase)
1020 2 : DEALLOCATE (random)
1021 : ! update particle coordinates
1022 8 : DO iatom = 1, natoms
1023 26 : particles(iatom)%r(:) = particles(iatom)%r(:) + dr(:, iatom)
1024 : END DO
1025 : ! update core-shell model coordinates
1026 2 : IF (shell_present) THEN
1027 : ! particles have moved, and for core-shell model this means
1028 : ! the cores and shells must also move by the same amount. The
1029 : ! shell positions will then be optimised if needed
1030 0 : shell_index = particles(iatom)%shell_index
1031 0 : IF (shell_index /= 0) THEN
1032 : core_particles(shell_index)%r(:) = core_particles(shell_index)%r(:) + &
1033 0 : dr(:, iatom)
1034 : shell_particles(shell_index)%r(:) = shell_particles(shell_index)%r(:) + &
1035 0 : dr(:, iatom)
1036 : END IF
1037 : CALL optimize_shell_core(force_env, &
1038 : particles, &
1039 : shell_particles, &
1040 : core_particles, &
1041 0 : global_env)
1042 : END IF
1043 : ! cleanup
1044 2 : DEALLOCATE (dr)
1045 4 : END SUBROUTINE generate_coords_vels_vib
1046 :
1047 : ! **************************************************************************************************
1048 : !> \brief calculates componbent of initial velocity of an atom from vibreational modes
1049 : !> \param iatom : global atomic index
1050 : !> \param icart : cartesian index (1, 2 or 3)
1051 : !> \param mass : atomic mass
1052 : !> \param temperature : target temperature of canonical ensemble
1053 : !> \param eigenvalues : array containing all cartesian vibrational mode eigenvalues (frequencies)
1054 : !> \param eigenvectors : array containing all corresponding vibrational mode eigenvectors
1055 : !> (displacements)
1056 : !> \param random : array containing uniform distributed random numbers, must be the size
1057 : !> of 3*natoms. Numbers must be between 0 and 1
1058 : !> \param phase : array containing numbers between 0 and 1 that determines for each
1059 : !> vibration mode the ratio of potential energy vs kinetic energy contribution
1060 : !> to total energy
1061 : !> \param dof : total number of degrees of freedom, = 3*natoms
1062 : !> \param scale : scale to make sure the sum of vibrational modes give the correct energy
1063 : !> \return : outputs icart-th cartesian component of initial position of atom iatom
1064 : !> \author Lianheng Tong, lianheng.tong@kcl.ac.uk
1065 : ! **************************************************************************************************
1066 18 : PURE FUNCTION dr_from_vib_data(iatom, &
1067 : icart, &
1068 : mass, &
1069 : temperature, &
1070 36 : eigenvalues, &
1071 18 : eigenvectors, &
1072 18 : random, &
1073 18 : phase, &
1074 : dof, &
1075 : scale) &
1076 : RESULT(res)
1077 : INTEGER, INTENT(IN) :: iatom, icart
1078 : REAL(KIND=dp), INTENT(IN) :: mass, temperature
1079 : REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: eigenvalues
1080 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: eigenvectors
1081 : REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: random, phase
1082 : INTEGER, INTENT(IN) :: dof
1083 : REAL(KIND=dp), INTENT(IN) :: scale
1084 : REAL(KIND=dp) :: res
1085 :
1086 : INTEGER :: imode, ind
1087 :
1088 18 : res = 0.0_dp
1089 : ! assuming the eigenvalues are sorted in ascending order, the
1090 : ! first three modes are acoustic with zero frequencies. These are
1091 : ! excluded from considerations, and should have been reflected in
1092 : ! the calculation of scale outside this function
1093 18 : IF (mass > 0.0_dp) THEN
1094 : ! eigenvector rows assumed to be grouped in atomic blocks
1095 18 : ind = (iatom - 1)*3 + icart
1096 126 : DO imode = 4, dof
1097 : res = res + &
1098 : SQRT(-2.0_dp*scale*temperature*LOG(1 - random(imode))/mass)/ &
1099 : eigenvalues(imode)* &
1100 : eigenvectors(ind, imode)* &
1101 126 : COS(2.0_dp*pi*phase(imode))
1102 : END DO
1103 : END IF
1104 18 : END FUNCTION dr_from_vib_data
1105 :
1106 : ! **************************************************************************************************
1107 : !> \brief calculates componbent of initial velocity of an atom from vibreational modes
1108 : !> \param iatom : global atomic index
1109 : !> \param icart : cartesian index (1, 2 or 3)
1110 : !> \param mass : atomic mass
1111 : !> \param temperature : target temperature of canonical ensemble
1112 : !> \param eigenvectors : array containing all corresponding vibrational mode eigenvectors
1113 : !> (displacements)
1114 : !> \param random : array containing uniform distributed random numbers, must be the size
1115 : !> of 3*natoms. Numbers must be between 0 and 1
1116 : !> \param phase : array containing numbers between 0 and 1 that determines for each
1117 : !> vibration mode the ratio of potential energy vs kinetic energy contribution
1118 : !> to total energy
1119 : !> \param dof : total number of degrees of freedom, = 3*natoms
1120 : !> \param scale : scale to make sure the sum of vibrational modes give the correct energy
1121 : !> \return : outputs icart-th cartesian component of initial velocity of atom iatom
1122 : !> \author Lianheng Tong, lianheng.tong@kcl.ac.uk
1123 : ! **************************************************************************************************
1124 18 : PURE FUNCTION dv_from_vib_data(iatom, &
1125 : icart, &
1126 : mass, &
1127 : temperature, &
1128 36 : eigenvectors, &
1129 18 : random, &
1130 18 : phase, &
1131 : dof, &
1132 : scale) &
1133 : RESULT(res)
1134 : INTEGER, INTENT(IN) :: iatom, icart
1135 : REAL(KIND=dp), INTENT(IN) :: mass, temperature
1136 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: eigenvectors
1137 : REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: random, phase
1138 : INTEGER, INTENT(IN) :: dof
1139 : REAL(KIND=dp), INTENT(IN) :: scale
1140 : REAL(KIND=dp) :: res
1141 :
1142 : INTEGER :: imode, ind
1143 :
1144 18 : res = 0.0_dp
1145 : ! assuming the eigenvalues are sorted in ascending order, the
1146 : ! first three modes are acoustic with zero frequencies. These are
1147 : ! excluded from considerations, and should have been reflected in
1148 : ! the calculation of scale outside this function
1149 18 : IF (mass > 0.0_dp) THEN
1150 : ! eigenvector rows assumed to be grouped in atomic blocks
1151 18 : ind = (iatom - 1)*3 + icart
1152 126 : DO imode = 4, dof
1153 : res = res - &
1154 : SQRT(-2.0_dp*scale*temperature*LOG(1 - random(imode))/mass)* &
1155 : eigenvectors(ind, imode)* &
1156 126 : SIN(2.0_dp*pi*phase(imode))
1157 : END DO
1158 : END IF
1159 18 : END FUNCTION dv_from_vib_data
1160 :
1161 : ! **************************************************************************************************
1162 : !> \brief Initializing velocities deterministically on all processors, if not given in input
1163 : !> \param simpar ...
1164 : !> \param part ...
1165 : !> \param force_env ...
1166 : !> \param globenv ...
1167 : !> \param md_env ...
1168 : !> \param shell_present ...
1169 : !> \param shell_part ...
1170 : !> \param core_part ...
1171 : !> \param is_fixed ...
1172 : !> \param iw ...
1173 : !> \author CJM,MK,Toon Verstraelen <Toon.Verstraelen@gmail.com>, Ole Schuett
1174 : ! **************************************************************************************************
1175 1528 : SUBROUTINE generate_velocities(simpar, part, force_env, globenv, md_env, &
1176 1528 : shell_present, shell_part, core_part, is_fixed, iw)
1177 : TYPE(simpar_type), POINTER :: simpar
1178 : TYPE(particle_type), DIMENSION(:), POINTER :: part
1179 : TYPE(force_env_type), POINTER :: force_env
1180 : TYPE(global_environment_type), POINTER :: globenv
1181 : TYPE(md_environment_type), POINTER :: md_env
1182 : LOGICAL, INTENT(IN) :: shell_present
1183 : TYPE(particle_type), DIMENSION(:), POINTER :: shell_part, core_part
1184 : INTEGER, DIMENSION(:), INTENT(INOUT) :: is_fixed
1185 : INTEGER, INTENT(IN) :: iw
1186 :
1187 : INTEGER :: i, natoms
1188 : REAL(KIND=dp) :: mass
1189 : TYPE(atomic_kind_type), POINTER :: atomic_kind
1190 :
1191 1528 : NULLIFY (atomic_kind)
1192 1528 : natoms = SIZE(part)
1193 :
1194 437432 : DO i = 1, natoms
1195 435904 : atomic_kind => part(i)%atomic_kind
1196 435904 : CALL get_atomic_kind(atomic_kind=atomic_kind, mass=mass)
1197 435904 : part(i)%v(1) = 0.0_dp
1198 435904 : part(i)%v(2) = 0.0_dp
1199 435904 : part(i)%v(3) = 0.0_dp
1200 437432 : IF (mass /= 0.0) THEN
1201 435970 : SELECT CASE (is_fixed(i))
1202 : CASE (use_perd_x)
1203 512 : part(i)%v(2) = globenv%gaussian_rng_stream%next()/SQRT(mass)
1204 512 : part(i)%v(3) = globenv%gaussian_rng_stream%next()/SQRT(mass)
1205 : CASE (use_perd_y)
1206 512 : part(i)%v(1) = globenv%gaussian_rng_stream%next()/SQRT(mass)
1207 512 : part(i)%v(3) = globenv%gaussian_rng_stream%next()/SQRT(mass)
1208 : CASE (use_perd_z)
1209 512 : part(i)%v(1) = globenv%gaussian_rng_stream%next()/SQRT(mass)
1210 512 : part(i)%v(2) = globenv%gaussian_rng_stream%next()/SQRT(mass)
1211 : CASE (use_perd_xy)
1212 512 : part(i)%v(3) = globenv%gaussian_rng_stream%next()/SQRT(mass)
1213 : CASE (use_perd_xz)
1214 0 : part(i)%v(2) = globenv%gaussian_rng_stream%next()/SQRT(mass)
1215 : CASE (use_perd_yz)
1216 0 : part(i)%v(1) = globenv%gaussian_rng_stream%next()/SQRT(mass)
1217 : CASE (use_perd_none)
1218 430292 : part(i)%v(1) = globenv%gaussian_rng_stream%next()/SQRT(mass)
1219 430292 : part(i)%v(2) = globenv%gaussian_rng_stream%next()/SQRT(mass)
1220 865750 : part(i)%v(3) = globenv%gaussian_rng_stream%next()/SQRT(mass)
1221 : END SELECT
1222 : END IF
1223 : END DO
1224 :
1225 1528 : CALL normalize_velocities(simpar, part, force_env, md_env, is_fixed)
1226 1528 : CALL soften_velocities(simpar, part, force_env, md_env, is_fixed, iw)
1227 :
1228 : ! Initialize the core and the shell velocity. Atom velocities are just
1229 : ! copied so that the initial relative core-shell velocity is zero.
1230 1528 : IF (shell_present) THEN
1231 84 : CALL optimize_shell_core(force_env, part, shell_part, core_part, globenv)
1232 : END IF
1233 1528 : END SUBROUTINE generate_velocities
1234 :
1235 : ! **************************************************************************************************
1236 : !> \brief Direct velocities along a low-curvature direction in order to
1237 : !> favors MD trajectories to cross rapidly over small energy barriers
1238 : !> into neighboring basins.
1239 : !> \param simpar ...
1240 : !> \param part ...
1241 : !> \param force_env ...
1242 : !> \param md_env ...
1243 : !> \param is_fixed ...
1244 : !> \param iw ...
1245 : !> \author Ole Schuett
1246 : ! **************************************************************************************************
1247 1528 : SUBROUTINE soften_velocities(simpar, part, force_env, md_env, is_fixed, iw)
1248 : TYPE(simpar_type), POINTER :: simpar
1249 : TYPE(particle_type), DIMENSION(:), POINTER :: part
1250 : TYPE(force_env_type), POINTER :: force_env
1251 : TYPE(md_environment_type), POINTER :: md_env
1252 : INTEGER, DIMENSION(:), INTENT(INOUT) :: is_fixed
1253 : INTEGER, INTENT(IN) :: iw
1254 :
1255 : INTEGER :: i, k
1256 1500 : REAL(KIND=dp), DIMENSION(SIZE(part), 3) :: F, F_t, N, x0
1257 :
1258 1528 : IF (simpar%soften_nsteps <= 0) RETURN !nothing todo
1259 :
1260 308 : IF (ANY(is_fixed /= use_perd_none)) THEN
1261 0 : CPABORT("Velocitiy softening with constraints is not supported.")
1262 : END IF
1263 :
1264 : !backup positions
1265 308 : DO i = 1, SIZE(part)
1266 1148 : x0(i, :) = part(i)%r
1267 : END DO
1268 :
1269 588 : DO k = 1, simpar%soften_nsteps
1270 :
1271 : !use normalized velocities as displace direction
1272 6160 : DO i = 1, SIZE(part)
1273 22960 : N(i, :) = part(i)%v
1274 : END DO
1275 37520 : N = N/SQRT(SUM(N**2))
1276 :
1277 : ! displace system temporarly to calculate forces
1278 6160 : DO i = 1, SIZE(part)
1279 22960 : part(i)%r = part(i)%r + simpar%soften_delta*N(i, :)
1280 : END DO
1281 560 : CALL force_env_calc_energy_force(force_env)
1282 :
1283 : ! calculate velocity update direction F_t
1284 6160 : DO i = 1, SIZE(part)
1285 22960 : F(i, :) = part(i)%f
1286 : END DO
1287 37520 : F_t = F - N*SUM(N*F)
1288 :
1289 : ! restore positions and update velocities
1290 6160 : DO i = 1, SIZE(part)
1291 22400 : part(i)%r = x0(i, :)
1292 22960 : part(i)%v = part(i)%v + simpar%soften_alpha*F_t(i, :)
1293 : END DO
1294 :
1295 588 : CALL normalize_velocities(simpar, part, force_env, md_env, is_fixed)
1296 : END DO
1297 :
1298 28 : IF (iw > 0) THEN
1299 0 : WRITE (iw, "(A,T71, I10)") " Velocities softening Steps: ", simpar%soften_nsteps
1300 0 : WRITE (iw, "(A,T71, E10.3)") " Velocities softening NORM(F_t): ", SQRT(SUM(F_t**2))
1301 : END IF
1302 28 : END SUBROUTINE soften_velocities
1303 :
1304 : ! **************************************************************************************************
1305 : !> \brief Scale velocities according to temperature and remove rigid body motion.
1306 : !> \param simpar ...
1307 : !> \param part ...
1308 : !> \param force_env ...
1309 : !> \param md_env ...
1310 : !> \param is_fixed ...
1311 : !> \author CJM,MK,Toon Verstraelen <Toon.Verstraelen@gmail.com>, Ole Schuett
1312 : ! **************************************************************************************************
1313 2088 : SUBROUTINE normalize_velocities(simpar, part, force_env, md_env, is_fixed)
1314 : TYPE(simpar_type), POINTER :: simpar
1315 : TYPE(particle_type), DIMENSION(:), POINTER :: part
1316 : TYPE(force_env_type), POINTER :: force_env
1317 : TYPE(md_environment_type), POINTER :: md_env
1318 : INTEGER, DIMENSION(:), INTENT(INOUT) :: is_fixed
1319 :
1320 : REAL(KIND=dp) :: ekin
1321 : REAL(KIND=dp), DIMENSION(3) :: rcom, vang, vcom
1322 : TYPE(cell_type), POINTER :: cell
1323 :
1324 2088 : NULLIFY (cell)
1325 :
1326 : ! Subtract the vcom
1327 2088 : CALL compute_vcom(part, is_fixed, vcom)
1328 2088 : CALL subtract_vcom(part, is_fixed, vcom)
1329 : ! If requested and the system is not periodic, subtract the angular velocity
1330 2088 : CALL force_env_get(force_env, cell=cell)
1331 8352 : IF (SUM(cell%perd(1:3)) == 0 .AND. simpar%angvel_zero) THEN
1332 4 : CALL compute_rcom(part, is_fixed, rcom)
1333 4 : CALL compute_vang(part, is_fixed, rcom, vang)
1334 4 : CALL subtract_vang(part, is_fixed, rcom, vang)
1335 : END IF
1336 : ! Rescale the velocities
1337 2088 : IF (simpar%do_thermal_region) THEN
1338 2 : CALL rescale_vel_region(part, md_env, simpar)
1339 : ELSE
1340 2086 : ekin = compute_ekin(part)
1341 2086 : CALL rescale_vel(part, simpar, ekin)
1342 : END IF
1343 2088 : END SUBROUTINE normalize_velocities
1344 :
1345 : ! **************************************************************************************************
1346 : !> \brief Computes Ekin, VCOM and Temp for particles
1347 : !> \param subsys ...
1348 : !> \param md_ener ...
1349 : !> \param vsubtract ...
1350 : !> \par History
1351 : !> Teodoro Laino - University of Zurich - 09.2007 [tlaino]
1352 : ! **************************************************************************************************
1353 42 : SUBROUTINE reset_vcom(subsys, md_ener, vsubtract)
1354 : TYPE(cp_subsys_type), POINTER :: subsys
1355 : TYPE(md_ener_type), POINTER :: md_ener
1356 : REAL(KIND=dp), DIMENSION(3), INTENT(IN) :: vsubtract
1357 :
1358 : CHARACTER(LEN=*), PARAMETER :: routineN = 'reset_vcom'
1359 :
1360 : INTEGER :: atom, handle, iatom, ikind, natom, &
1361 : shell_index
1362 42 : INTEGER, DIMENSION(:), POINTER :: atom_list
1363 : LOGICAL :: is_shell
1364 : REAL(KIND=dp) :: ekin_old, imass_c, imass_s, mass, v2
1365 : REAL(KIND=dp), DIMENSION(3) :: tmp, v
1366 : TYPE(atomic_kind_list_type), POINTER :: atomic_kinds
1367 : TYPE(atomic_kind_type), POINTER :: atomic_kind
1368 : TYPE(particle_list_type), POINTER :: core_particles, particles, &
1369 : shell_particles
1370 : TYPE(shell_kind_type), POINTER :: shell
1371 :
1372 42 : NULLIFY (particles, atomic_kind, atomic_kinds, atom_list, shell)
1373 42 : CALL timeset(routineN, handle)
1374 :
1375 : CALL cp_subsys_get(subsys, &
1376 : atomic_kinds=atomic_kinds, &
1377 : particles=particles, &
1378 : shell_particles=shell_particles, &
1379 42 : core_particles=core_particles)
1380 :
1381 42 : ekin_old = md_ener%ekin
1382 : ! Possibly subtract a quantity from all velocities
1383 126 : DO ikind = 1, atomic_kinds%n_els
1384 84 : atomic_kind => atomic_kinds%els(ikind)
1385 : CALL get_atomic_kind(atomic_kind=atomic_kind, atom_list=atom_list, &
1386 84 : natom=natom, mass=mass, shell_active=is_shell, shell=shell)
1387 126 : IF (is_shell) THEN
1388 336 : tmp = 0.5_dp*vsubtract*mass
1389 84 : imass_s = 1.0_dp/shell%mass_shell
1390 84 : imass_c = 1.0_dp/shell%mass_core
1391 3780 : DO iatom = 1, natom
1392 3696 : atom = atom_list(iatom)
1393 3696 : shell_index = particles%els(atom)%shell_index
1394 14784 : shell_particles%els(shell_index)%v = shell_particles%els(shell_index)%v - tmp*imass_s
1395 14784 : core_particles%els(shell_index)%v = core_particles%els(shell_index)%v - tmp*imass_c
1396 14868 : particles%els(atom)%v = particles%els(atom)%v - vsubtract
1397 : END DO
1398 : ELSE
1399 0 : DO iatom = 1, natom
1400 0 : atom = atom_list(iatom)
1401 0 : particles%els(atom)%v = particles%els(atom)%v - vsubtract
1402 : END DO
1403 : END IF
1404 : END DO
1405 : ! Compute Kinetic Energy and COM Velocity
1406 168 : md_ener%vcom = 0.0_dp
1407 42 : md_ener%total_mass = 0.0_dp
1408 42 : md_ener%ekin = 0.0_dp
1409 126 : DO ikind = 1, atomic_kinds%n_els
1410 84 : atomic_kind => atomic_kinds%els(ikind)
1411 84 : CALL get_atomic_kind(atomic_kind=atomic_kind, atom_list=atom_list, mass=mass, natom=natom)
1412 84 : v2 = 0.0_dp
1413 84 : v = 0.0_dp
1414 3780 : DO iatom = 1, natom
1415 3696 : atom = atom_list(iatom)
1416 14784 : v2 = v2 + SUM(particles%els(atom)%v**2)
1417 3696 : v(1) = v(1) + particles%els(atom)%v(1)
1418 3696 : v(2) = v(2) + particles%els(atom)%v(2)
1419 3780 : v(3) = v(3) + particles%els(atom)%v(3)
1420 : END DO
1421 84 : md_ener%ekin = md_ener%ekin + 0.5_dp*mass*v2
1422 84 : md_ener%vcom(1) = md_ener%vcom(1) + mass*v(1)
1423 84 : md_ener%vcom(2) = md_ener%vcom(2) + mass*v(2)
1424 84 : md_ener%vcom(3) = md_ener%vcom(3) + mass*v(3)
1425 210 : md_ener%total_mass = md_ener%total_mass + REAL(natom, KIND=dp)*mass
1426 : END DO
1427 168 : md_ener%vcom = md_ener%vcom/md_ener%total_mass
1428 42 : md_ener%constant = md_ener%constant - ekin_old + md_ener%ekin
1429 42 : IF (md_ener%nfree /= 0) THEN
1430 42 : md_ener%temp_part = 2.0_dp*md_ener%ekin/REAL(md_ener%nfree, KIND=dp)*kelvin
1431 : END IF
1432 42 : CALL timestop(handle)
1433 :
1434 42 : END SUBROUTINE reset_vcom
1435 :
1436 : ! **************************************************************************************************
1437 : !> \brief Scale velocities to get the correct temperature
1438 : !> \param subsys ...
1439 : !> \param md_ener ...
1440 : !> \param temp_expected ...
1441 : !> \param temp_tol ...
1442 : !> \param iw ...
1443 : !> \par History
1444 : !> Teodoro Laino - University of Zurich - 09.2007 [tlaino]
1445 : ! **************************************************************************************************
1446 12914 : SUBROUTINE scale_velocity(subsys, md_ener, temp_expected, temp_tol, iw)
1447 : TYPE(cp_subsys_type), POINTER :: subsys
1448 : TYPE(md_ener_type), POINTER :: md_ener
1449 : REAL(KIND=dp), INTENT(IN) :: temp_expected, temp_tol
1450 : INTEGER, INTENT(IN) :: iw
1451 :
1452 : REAL(KIND=dp) :: ekin_old, scale, temp_old
1453 :
1454 12914 : IF (ABS(temp_expected - md_ener%temp_part/kelvin) > temp_tol) THEN
1455 2640 : scale = 0.0_dp
1456 2640 : IF (md_ener%temp_part > 0.0_dp) scale = SQRT((temp_expected/md_ener%temp_part)*kelvin)
1457 2640 : ekin_old = md_ener%ekin
1458 2640 : temp_old = md_ener%temp_part
1459 2640 : md_ener%ekin = 0.0_dp
1460 2640 : md_ener%temp_part = 0.0_dp
1461 10560 : md_ener%vcom = 0.0_dp
1462 2640 : md_ener%total_mass = 0.0_dp
1463 :
1464 2640 : CALL scale_velocity_low(subsys, scale, ireg=0, ekin=md_ener%ekin, vcom=md_ener%vcom)
1465 2640 : IF (md_ener%nfree /= 0) THEN
1466 2640 : md_ener%temp_part = 2.0_dp*md_ener%ekin/REAL(md_ener%nfree, KIND=dp)*kelvin
1467 : END IF
1468 2640 : md_ener%constant = md_ener%constant - ekin_old + md_ener%ekin
1469 2640 : IF (iw > 0) THEN
1470 : WRITE (UNIT=iw, FMT='(/,T2,A)') &
1471 1320 : 'MD_VEL| Temperature scaled to requested temperature'
1472 : WRITE (UNIT=iw, FMT='(T2,A,T61,F20.6)') &
1473 1320 : 'MD_VEL| Old temperature [K]', temp_old, &
1474 2640 : 'MD_VEL| New temperature [K]', md_ener%temp_part
1475 : END IF
1476 : END IF
1477 :
1478 12914 : END SUBROUTINE scale_velocity
1479 :
1480 : ! **************************************************************************************************
1481 : !> \brief Scale velocities of set of regions
1482 : !> \param md_env ...
1483 : !> \param subsys ...
1484 : !> \param md_ener ...
1485 : !> \param simpar ...
1486 : !> \param iw ...
1487 : !> \par author MI
1488 : ! **************************************************************************************************
1489 96 : SUBROUTINE scale_velocity_region(md_env, subsys, md_ener, simpar, iw)
1490 :
1491 : TYPE(md_environment_type), POINTER :: md_env
1492 : TYPE(cp_subsys_type), POINTER :: subsys
1493 : TYPE(md_ener_type), POINTER :: md_ener
1494 : TYPE(simpar_type), POINTER :: simpar
1495 : INTEGER, INTENT(IN) :: iw
1496 :
1497 : INTEGER :: ireg, nfree, nfree_done, nregions
1498 : REAL(KIND=dp) :: ekin, ekin_old, ekin_total_new, fscale, &
1499 : vcom(3), vcom_total(3)
1500 96 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: temp_new, temp_old
1501 : TYPE(particle_list_type), POINTER :: particles
1502 : TYPE(particle_type), DIMENSION(:), POINTER :: part
1503 : TYPE(thermal_region_type), POINTER :: t_region
1504 : TYPE(thermal_regions_type), POINTER :: thermal_regions
1505 :
1506 96 : NULLIFY (particles, part, thermal_regions, t_region)
1507 96 : CALL cp_subsys_get(subsys, particles=particles)
1508 96 : part => particles%els
1509 96 : CALL get_md_env(md_env, thermal_regions=thermal_regions)
1510 :
1511 96 : nregions = thermal_regions%nregions
1512 96 : nfree_done = 0
1513 96 : ekin_total_new = 0.0_dp
1514 96 : ekin_old = md_ener%ekin
1515 : vcom_total = 0.0_dp
1516 384 : ALLOCATE (temp_new(0:nregions), temp_old(0:nregions))
1517 96 : temp_new = 0.0_dp
1518 96 : temp_old = 0.0_dp
1519 : !loop regions
1520 256 : DO ireg = 1, nregions
1521 160 : NULLIFY (t_region)
1522 160 : t_region => thermal_regions%thermal_region(ireg)
1523 160 : nfree = 3*t_region%npart
1524 160 : ekin = compute_ekin(part, ireg)
1525 160 : IF (nfree > 0) t_region%temperature = 2.0_dp*ekin/REAL(nfree, KIND=dp)*kelvin
1526 160 : temp_old(ireg) = t_region%temperature
1527 160 : IF (t_region%temp_tol > 0.0_dp .AND. &
1528 : ABS(t_region%temp_expected - t_region%temperature/kelvin) > t_region%temp_tol) THEN
1529 2 : fscale = SQRT((t_region%temp_expected/t_region%temperature)*kelvin)
1530 2 : CALL scale_velocity_low(subsys, fscale, ireg, ekin, vcom)
1531 2 : t_region%temperature = 2.0_dp*ekin/REAL(nfree, KIND=dp)*kelvin
1532 2 : temp_new(ireg) = t_region%temperature
1533 : END IF
1534 160 : nfree_done = nfree_done + nfree
1535 256 : ekin_total_new = ekin_total_new + ekin
1536 : END DO
1537 96 : nfree = simpar%nfree - nfree_done
1538 96 : ekin = compute_ekin(part, ireg=0)
1539 96 : IF (nfree > 0) thermal_regions%temp_reg0 = 2.0_dp*ekin/REAL(nfree, KIND=dp)*kelvin
1540 96 : temp_old(0) = thermal_regions%temp_reg0
1541 96 : IF (simpar%temp_tol > 0.0_dp .AND. nfree > 0) THEN
1542 0 : IF (ABS(simpar%temp_ext - thermal_regions%temp_reg0/kelvin) > simpar%temp_tol) THEN
1543 0 : fscale = SQRT((simpar%temp_ext/thermal_regions%temp_reg0)*kelvin)
1544 0 : CALL scale_velocity_low(subsys, fscale, 0, ekin, vcom)
1545 0 : thermal_regions%temp_reg0 = 2.0_dp*ekin/REAL(nfree, KIND=dp)*kelvin
1546 0 : temp_new(0) = thermal_regions%temp_reg0
1547 : END IF
1548 : END IF
1549 96 : ekin_total_new = ekin_total_new + ekin
1550 :
1551 96 : md_ener%ekin = ekin_total_new
1552 96 : IF (md_ener%nfree /= 0) THEN
1553 96 : md_ener%temp_part = 2.0_dp*md_ener%ekin/REAL(md_ener%nfree, KIND=dp)*kelvin
1554 : END IF
1555 96 : md_ener%constant = md_ener%constant - ekin_old + md_ener%ekin
1556 96 : IF (iw > 0) THEN
1557 176 : DO ireg = 0, nregions
1558 176 : IF (temp_new(ireg) > 0.0_dp) THEN
1559 : WRITE (UNIT=iw, FMT='(/,T2,A,I0,A)') &
1560 1 : 'MD_VEL| Temperature region ', ireg, ' scaled to requested temperature'
1561 : WRITE (UNIT=iw, FMT='(T2,A,T61,F20.6)') &
1562 1 : 'MD_VEL| Old temperature [K]', temp_old(ireg), &
1563 2 : 'MD_VEL| New temperature [K]', temp_new(ireg)
1564 : END IF
1565 : END DO
1566 : END IF
1567 96 : DEALLOCATE (temp_new, temp_old)
1568 :
1569 96 : END SUBROUTINE scale_velocity_region
1570 :
1571 : ! **************************************************************************************************
1572 : !> \brief Scale velocities for a specific region
1573 : !> \param subsys ...
1574 : !> \param fscale ...
1575 : !> \param ireg ...
1576 : !> \param ekin ...
1577 : !> \param vcom ...
1578 : !> \par author MI
1579 : ! **************************************************************************************************
1580 2642 : SUBROUTINE scale_velocity_low(subsys, fscale, ireg, ekin, vcom)
1581 :
1582 : TYPE(cp_subsys_type), POINTER :: subsys
1583 : REAL(KIND=dp), INTENT(IN) :: fscale
1584 : INTEGER, INTENT(IN) :: ireg
1585 : REAL(KIND=dp), INTENT(OUT) :: ekin, vcom(3)
1586 :
1587 : INTEGER :: atom, iatom, ikind, my_ireg, natom, &
1588 : shell_index
1589 2642 : INTEGER, DIMENSION(:), POINTER :: atom_list
1590 : LOGICAL :: is_shell
1591 : REAL(KIND=dp) :: imass, mass, tmass, v2
1592 : REAL(KIND=dp), DIMENSION(3) :: tmp, v, vc, vs
1593 : TYPE(atomic_kind_list_type), POINTER :: atomic_kinds
1594 : TYPE(atomic_kind_type), POINTER :: atomic_kind
1595 : TYPE(particle_list_type), POINTER :: core_particles, particles, &
1596 : shell_particles
1597 : TYPE(shell_kind_type), POINTER :: shell
1598 :
1599 2642 : NULLIFY (atomic_kinds, particles, shell_particles, core_particles, shell, atom_list)
1600 :
1601 2642 : my_ireg = ireg
1602 2642 : ekin = 0.0_dp
1603 2642 : tmass = 0.0_dp
1604 2642 : vcom = 0.0_dp
1605 :
1606 : CALL cp_subsys_get(subsys, atomic_kinds=atomic_kinds, particles=particles, &
1607 2642 : shell_particles=shell_particles, core_particles=core_particles)
1608 :
1609 9082 : DO ikind = 1, atomic_kinds%n_els
1610 6440 : atomic_kind => atomic_kinds%els(ikind)
1611 : CALL get_atomic_kind(atomic_kind=atomic_kind, atom_list=atom_list, mass=mass, &
1612 6440 : natom=natom, shell_active=is_shell, shell=shell)
1613 6440 : IF (is_shell) THEN
1614 124 : imass = 1.0_dp/mass
1615 124 : v2 = 0.0_dp
1616 124 : v = 0.0_dp
1617 5740 : DO iatom = 1, natom
1618 5616 : atom = atom_list(iatom)
1619 : !check region
1620 5616 : IF (particles%els(atom)%t_region_index /= my_ireg) CYCLE
1621 :
1622 21080 : particles%els(atom)%v(:) = fscale*particles%els(atom)%v
1623 5270 : shell_index = particles%els(atom)%shell_index
1624 21080 : vs = shell_particles%els(shell_index)%v
1625 21080 : vc = core_particles%els(shell_index)%v
1626 5270 : tmp(1) = imass*(vs(1) - vc(1))
1627 5270 : tmp(2) = imass*(vs(2) - vc(2))
1628 5270 : tmp(3) = imass*(vs(3) - vc(3))
1629 :
1630 5270 : shell_particles%els(shell_index)%v(1) = particles%els(atom)%v(1) + tmp(1)*shell%mass_core
1631 5270 : shell_particles%els(shell_index)%v(2) = particles%els(atom)%v(2) + tmp(2)*shell%mass_core
1632 5270 : shell_particles%els(shell_index)%v(3) = particles%els(atom)%v(3) + tmp(3)*shell%mass_core
1633 :
1634 5270 : core_particles%els(shell_index)%v(1) = particles%els(atom)%v(1) - tmp(1)*shell%mass_shell
1635 5270 : core_particles%els(shell_index)%v(2) = particles%els(atom)%v(2) - tmp(2)*shell%mass_shell
1636 5270 : core_particles%els(shell_index)%v(3) = particles%els(atom)%v(3) - tmp(3)*shell%mass_shell
1637 :
1638 : ! kinetic energy and velocity of COM
1639 21080 : v2 = v2 + SUM(particles%els(atom)%v**2)
1640 5270 : v(1) = v(1) + particles%els(atom)%v(1)
1641 5270 : v(2) = v(2) + particles%els(atom)%v(2)
1642 5270 : v(3) = v(3) + particles%els(atom)%v(3)
1643 5740 : tmass = tmass + mass
1644 : END DO
1645 : ELSE
1646 6316 : v2 = 0.0_dp
1647 6316 : v = 0.0_dp
1648 22826 : DO iatom = 1, natom
1649 16510 : atom = atom_list(iatom)
1650 : !check region
1651 16510 : IF (particles%els(atom)%t_region_index /= my_ireg) CYCLE
1652 :
1653 66040 : particles%els(atom)%v(:) = fscale*particles%els(atom)%v
1654 : ! kinetic energy and velocity of COM
1655 66040 : v2 = v2 + SUM(particles%els(atom)%v**2)
1656 16510 : v(1) = v(1) + particles%els(atom)%v(1)
1657 16510 : v(2) = v(2) + particles%els(atom)%v(2)
1658 16510 : v(3) = v(3) + particles%els(atom)%v(3)
1659 22826 : tmass = tmass + mass
1660 : END DO
1661 : END IF
1662 6440 : ekin = ekin + 0.5_dp*mass*v2
1663 6440 : vcom(1) = vcom(1) + mass*v(1)
1664 6440 : vcom(2) = vcom(2) + mass*v(2)
1665 15522 : vcom(3) = vcom(3) + mass*v(3)
1666 :
1667 : END DO
1668 10568 : vcom = vcom/tmass
1669 :
1670 2642 : END SUBROUTINE scale_velocity_low
1671 :
1672 : ! **************************************************************************************************
1673 : !> \brief Scale internal motion of CORE-SHELL model to the correct temperature
1674 : !> \param subsys ...
1675 : !> \param md_ener ...
1676 : !> \param temp_expected ...
1677 : !> \param temp_tol ...
1678 : !> \param iw ...
1679 : !> \par History
1680 : !> Teodoro Laino - University of Zurich - 09.2007 [tlaino]
1681 : ! **************************************************************************************************
1682 1060 : SUBROUTINE scale_velocity_internal(subsys, md_ener, temp_expected, temp_tol, iw)
1683 : TYPE(cp_subsys_type), POINTER :: subsys
1684 : TYPE(md_ener_type), POINTER :: md_ener
1685 : REAL(KIND=dp), INTENT(IN) :: temp_expected, temp_tol
1686 : INTEGER, INTENT(IN) :: iw
1687 :
1688 : INTEGER :: atom, iatom, ikind, natom, shell_index
1689 1060 : INTEGER, DIMENSION(:), POINTER :: atom_list
1690 : LOGICAL :: is_shell
1691 : REAL(KIND=dp) :: ekin_shell_old, fac_mass, mass, scale, &
1692 : temp_shell_old, v2
1693 : REAL(KIND=dp), DIMENSION(3) :: tmp, v, vc, vs
1694 : TYPE(atomic_kind_list_type), POINTER :: atomic_kinds
1695 : TYPE(atomic_kind_type), POINTER :: atomic_kind
1696 : TYPE(particle_list_type), POINTER :: core_particles, particles, &
1697 : shell_particles
1698 : TYPE(shell_kind_type), POINTER :: shell
1699 :
1700 1060 : NULLIFY (atom_list, atomic_kinds, atomic_kind, core_particles, particles, shell_particles, shell)
1701 1060 : IF (ABS(temp_expected - md_ener%temp_shell/kelvin) > temp_tol) THEN
1702 80 : scale = 0.0_dp
1703 80 : IF (md_ener%temp_shell > EPSILON(0.0_dp)) scale = SQRT((temp_expected/md_ener%temp_shell)*kelvin)
1704 80 : ekin_shell_old = md_ener%ekin_shell
1705 80 : temp_shell_old = md_ener%temp_shell
1706 80 : md_ener%ekin_shell = 0.0_dp
1707 80 : md_ener%temp_shell = 0.0_dp
1708 :
1709 : CALL cp_subsys_get(subsys, atomic_kinds=atomic_kinds, particles=particles, shell_particles=shell_particles, &
1710 80 : core_particles=core_particles)
1711 :
1712 240 : DO ikind = 1, atomic_kinds%n_els
1713 160 : atomic_kind => atomic_kinds%els(ikind)
1714 : CALL get_atomic_kind(atomic_kind=atomic_kind, atom_list=atom_list, mass=mass, natom=natom, &
1715 160 : shell_active=is_shell, shell=shell)
1716 240 : IF (is_shell) THEN
1717 160 : fac_mass = 1.0_dp/mass
1718 160 : v2 = 0.0_dp
1719 776 : DO iatom = 1, natom
1720 616 : atom = atom_list(iatom)
1721 616 : shell_index = particles%els(atom)%shell_index
1722 2464 : vs = shell_particles%els(shell_index)%v
1723 2464 : vc = core_particles%els(shell_index)%v
1724 2464 : v = particles%els(atom)%v
1725 616 : tmp(1) = fac_mass*(vc(1) - vs(1))
1726 616 : tmp(2) = fac_mass*(vc(2) - vs(2))
1727 616 : tmp(3) = fac_mass*(vc(3) - vs(3))
1728 :
1729 616 : shell_particles%els(shell_index)%v(1) = v(1) - shell%mass_core*scale*tmp(1)
1730 616 : shell_particles%els(shell_index)%v(2) = v(2) - shell%mass_core*scale*tmp(2)
1731 616 : shell_particles%els(shell_index)%v(3) = v(3) - shell%mass_core*scale*tmp(3)
1732 :
1733 616 : core_particles%els(shell_index)%v(1) = v(1) + shell%mass_shell*scale*tmp(1)
1734 616 : core_particles%els(shell_index)%v(2) = v(2) + shell%mass_shell*scale*tmp(2)
1735 616 : core_particles%els(shell_index)%v(3) = v(3) + shell%mass_shell*scale*tmp(3)
1736 :
1737 2464 : vs = shell_particles%els(shell_index)%v
1738 2464 : vc = core_particles%els(shell_index)%v
1739 616 : tmp(1) = vc(1) - vs(1)
1740 616 : tmp(2) = vc(2) - vs(2)
1741 616 : tmp(3) = vc(3) - vs(3)
1742 2624 : v2 = v2 + SUM(tmp**2)
1743 : END DO
1744 160 : md_ener%ekin_shell = md_ener%ekin_shell + 0.5_dp*shell%mass_core*shell%mass_shell*fac_mass*v2
1745 : END IF
1746 : END DO
1747 80 : IF (md_ener%nfree_shell > 0) THEN
1748 80 : md_ener%temp_shell = 2.0_dp*md_ener%ekin_shell/REAL(md_ener%nfree_shell, KIND=dp)*kelvin
1749 : END IF
1750 80 : md_ener%constant = md_ener%constant - ekin_shell_old + md_ener%ekin_shell
1751 80 : IF (iw > 0) THEN
1752 : WRITE (UNIT=iw, FMT='(/,T2,A)') &
1753 40 : 'MD_VEL| Temperature of shell internal motion scaled to requested temperature'
1754 : WRITE (UNIT=iw, FMT='(T2,A,T61,F20.6)') &
1755 40 : 'MD_VEL| Old temperature [K]', temp_shell_old, &
1756 80 : 'MD_VEL| New temperature [K]', md_ener%temp_shell
1757 : END IF
1758 : END IF
1759 :
1760 1060 : END SUBROUTINE scale_velocity_internal
1761 :
1762 : ! **************************************************************************************************
1763 : !> \brief Scale barostat velocities to get the desired temperature
1764 : !> \param md_env ...
1765 : !> \param md_ener ...
1766 : !> \param temp_expected ...
1767 : !> \param temp_tol ...
1768 : !> \param iw ...
1769 : !> \par History
1770 : !> MI 02.2008
1771 : ! **************************************************************************************************
1772 40 : SUBROUTINE scale_velocity_baro(md_env, md_ener, temp_expected, temp_tol, iw)
1773 : TYPE(md_environment_type), POINTER :: md_env
1774 : TYPE(md_ener_type), POINTER :: md_ener
1775 : REAL(KIND=dp), INTENT(IN) :: temp_expected, temp_tol
1776 : INTEGER, INTENT(IN) :: iw
1777 :
1778 : INTEGER :: i, j, nfree
1779 : REAL(KIND=dp) :: ekin_old, scale, temp_old
1780 40 : TYPE(npt_info_type), POINTER :: npt(:, :)
1781 : TYPE(simpar_type), POINTER :: simpar
1782 :
1783 40 : NULLIFY (npt, simpar)
1784 40 : CALL get_md_env(md_env, simpar=simpar, npt=npt)
1785 40 : IF (ABS(temp_expected - md_ener%temp_baro/kelvin) > temp_tol) THEN
1786 2 : scale = 0.0_dp
1787 2 : IF (md_ener%temp_baro > 0.0_dp) scale = SQRT((temp_expected/md_ener%temp_baro)*kelvin)
1788 2 : ekin_old = md_ener%baro_kin
1789 2 : temp_old = md_ener%temp_baro
1790 2 : md_ener%baro_kin = 0.0_dp
1791 2 : md_ener%temp_baro = 0.0_dp
1792 : IF (simpar%ensemble == npt_i_ensemble .OR. simpar%ensemble == npe_i_ensemble &
1793 2 : .OR. simpar%ensemble == npt_ia_ensemble) THEN
1794 0 : npt(1, 1)%v = npt(1, 1)%v*scale
1795 0 : md_ener%baro_kin = 0.5_dp*npt(1, 1)%v**2*npt(1, 1)%mass
1796 : ELSE IF (simpar%ensemble == npt_f_ensemble .OR. simpar%ensemble == npe_f_ensemble) THEN
1797 2 : md_ener%baro_kin = 0.0_dp
1798 8 : DO i = 1, 3
1799 26 : DO j = 1, 3
1800 18 : npt(i, j)%v = npt(i, j)%v*scale
1801 24 : md_ener%baro_kin = md_ener%baro_kin + 0.5_dp*npt(i, j)%v**2*npt(i, j)%mass
1802 : END DO
1803 : END DO
1804 : END IF
1805 2 : nfree = SIZE(npt, 1)*SIZE(npt, 2)
1806 2 : md_ener%temp_baro = 2.0_dp*md_ener%baro_kin/REAL(nfree, dp)*kelvin
1807 2 : IF (iw > 0) THEN
1808 : WRITE (UNIT=iw, FMT='(/,T2,A)') &
1809 1 : 'MD_VEL| Temperature of barostat motion scaled to requested temperature'
1810 : WRITE (UNIT=iw, FMT='(T2,A,T61,F20.6)') &
1811 1 : 'MD_VEL| Old temperature [K]', temp_old, &
1812 2 : 'MD_VEL| New temperature [K]', md_ener%temp_baro
1813 : END IF
1814 : END IF
1815 :
1816 40 : END SUBROUTINE scale_velocity_baro
1817 :
1818 : ! **************************************************************************************************
1819 : !> \brief Perform all temperature manipulations during a QS MD run.
1820 : !> \param simpar ...
1821 : !> \param md_env ...
1822 : !> \param md_ener ...
1823 : !> \param force_env ...
1824 : !> \param logger ...
1825 : !> \par History
1826 : !> Creation (15.09.2003,MK)
1827 : !> adapted to force_env (05.10.2003,fawzi)
1828 : !> Cleaned (09.2007) Teodoro Laino [tlaino] - University of Zurich
1829 : ! **************************************************************************************************
1830 40643 : SUBROUTINE temperature_control(simpar, md_env, md_ener, force_env, logger)
1831 :
1832 : TYPE(simpar_type), POINTER :: simpar
1833 : TYPE(md_environment_type), POINTER :: md_env
1834 : TYPE(md_ener_type), POINTER :: md_ener
1835 : TYPE(force_env_type), POINTER :: force_env
1836 : TYPE(cp_logger_type), POINTER :: logger
1837 :
1838 : CHARACTER(LEN=*), PARAMETER :: routineN = 'temperature_control'
1839 :
1840 : INTEGER :: handle, iw
1841 : TYPE(cp_subsys_type), POINTER :: subsys
1842 : TYPE(mp_para_env_type), POINTER :: para_env
1843 :
1844 40643 : CALL timeset(routineN, handle)
1845 40643 : NULLIFY (subsys, para_env)
1846 40643 : CPASSERT(ASSOCIATED(simpar))
1847 40643 : CPASSERT(ASSOCIATED(md_ener))
1848 40643 : CPASSERT(ASSOCIATED(force_env))
1849 40643 : CALL force_env_get(force_env, subsys=subsys, para_env=para_env)
1850 : iw = cp_print_key_unit_nr(logger, force_env%root_section, "MOTION%MD%PRINT%PROGRAM_RUN_INFO", &
1851 40643 : extension=".mdLog")
1852 :
1853 : ! Control the particle motion
1854 40643 : IF (simpar%do_thermal_region) THEN
1855 96 : CALL scale_velocity_region(md_env, subsys, md_ener, simpar, iw)
1856 : ELSE
1857 40547 : IF (simpar%temp_tol > 0.0_dp) THEN
1858 12870 : CALL scale_velocity(subsys, md_ener, simpar%temp_ext, simpar%temp_tol, iw)
1859 : END IF
1860 : END IF
1861 : ! Control the internal core-shell motion
1862 40643 : IF (simpar%temp_sh_tol > 0.0_dp) THEN
1863 1060 : CALL scale_velocity_internal(subsys, md_ener, simpar%temp_sh_ext, simpar%temp_sh_tol, iw)
1864 : END IF
1865 : ! Control cell motion
1866 43183 : SELECT CASE (simpar%ensemble)
1867 : CASE (nph_uniaxial_damped_ensemble, nph_uniaxial_ensemble, &
1868 : npt_f_ensemble, npt_i_ensemble, npe_f_ensemble, npe_i_ensemble, npt_ia_ensemble)
1869 40643 : IF (simpar%temp_baro_tol > 0.0_dp) THEN
1870 40 : CALL scale_velocity_baro(md_env, md_ener, simpar%temp_baro_ext, simpar%temp_baro_tol, iw)
1871 : END IF
1872 : END SELECT
1873 :
1874 : CALL cp_print_key_finished_output(iw, logger, force_env%root_section, &
1875 40643 : "MOTION%MD%PRINT%PROGRAM_RUN_INFO")
1876 40643 : CALL timestop(handle)
1877 40643 : END SUBROUTINE temperature_control
1878 :
1879 : ! **************************************************************************************************
1880 : !> \brief Set to 0 the velocity of the COM along MD runs, if required.
1881 : !> \param md_ener ...
1882 : !> \param force_env ...
1883 : !> \param md_section ...
1884 : !> \param logger ...
1885 : !> \par History
1886 : !> Creation (29.04.2007,MI)
1887 : !> Cleaned (09.2007) Teodoro Laino [tlaino] - University of Zurich
1888 : ! **************************************************************************************************
1889 81286 : SUBROUTINE comvel_control(md_ener, force_env, md_section, logger)
1890 :
1891 : TYPE(md_ener_type), POINTER :: md_ener
1892 : TYPE(force_env_type), POINTER :: force_env
1893 : TYPE(section_vals_type), POINTER :: md_section
1894 : TYPE(cp_logger_type), POINTER :: logger
1895 :
1896 : CHARACTER(LEN=*), PARAMETER :: routineN = 'comvel_control'
1897 :
1898 : INTEGER :: handle, iw
1899 : LOGICAL :: explicit
1900 : REAL(KIND=dp) :: comvel_tol, temp_old, vel_com
1901 : REAL(KIND=dp), DIMENSION(3) :: vcom_old
1902 : TYPE(cp_subsys_type), POINTER :: subsys
1903 :
1904 40643 : CALL timeset(routineN, handle)
1905 40643 : NULLIFY (subsys)
1906 40643 : CPASSERT(ASSOCIATED(force_env))
1907 40643 : CALL force_env_get(force_env, subsys=subsys)
1908 :
1909 : ! Print COMVEL and COM Position
1910 40643 : iw = cp_print_key_unit_nr(logger, md_section, "PRINT%CENTER_OF_MASS", extension=".mdLog")
1911 40643 : IF (iw > 0) THEN
1912 : WRITE (UNIT=iw, FMT="(/,T2,A)") &
1913 7785 : "MD_VEL| Centre of mass motion (COM)"
1914 : WRITE (UNIT=iw, FMT="(T2,A,T30,3(1X,F16.10))") &
1915 31140 : "MD_VEL| VCOM [a.u.]", md_ener%vcom(1:3)
1916 : END IF
1917 40643 : CALL cp_print_key_finished_output(iw, logger, md_section, "PRINT%CENTER_OF_MASS")
1918 :
1919 : ! If requested rescale COMVEL
1920 40643 : CALL section_vals_val_get(md_section, "COMVEL_TOL", explicit=explicit)
1921 40643 : IF (explicit) THEN
1922 826 : CALL section_vals_val_get(md_section, "COMVEL_TOL", r_val=comvel_tol)
1923 : iw = cp_print_key_unit_nr(logger, md_section, "PRINT%PROGRAM_RUN_INFO", &
1924 826 : extension=".mdLog")
1925 826 : vel_com = SQRT(md_ener%vcom(1)**2 + md_ener%vcom(2)**2 + md_ener%vcom(3)**2)
1926 :
1927 : ! Subtract the velocity of the COM, if requested
1928 826 : IF (vel_com > comvel_tol) THEN
1929 42 : temp_old = md_ener%temp_part/kelvin
1930 168 : vcom_old = md_ener%vcom
1931 42 : CALL reset_vcom(subsys, md_ener, vsubtract=vcom_old)
1932 42 : CALL scale_velocity(subsys, md_ener, temp_old, 0.0_dp, iw)
1933 42 : IF (iw > 0) THEN
1934 : WRITE (UNIT=iw, FMT="(T2,A,T30,3(1X,F16.10))") &
1935 21 : "MD_VEL| Old VCOM [a.u.]", vcom_old(1:3)
1936 : WRITE (UNIT=iw, FMT="(T2,A,T30,3(1X,F16.10))") &
1937 84 : "MD_VEL| New VCOM [a.u.]", md_ener%vcom(1:3)
1938 : END IF
1939 : END IF
1940 : CALL cp_print_key_finished_output(iw, logger, md_section, &
1941 826 : "PRINT%PROGRAM_RUN_INFO")
1942 : END IF
1943 :
1944 40643 : CALL timestop(handle)
1945 40643 : END SUBROUTINE comvel_control
1946 :
1947 : ! **************************************************************************************************
1948 : !> \brief Set to 0 the angular velocity along MD runs, if required.
1949 : !> \param md_ener ...
1950 : !> \param force_env ...
1951 : !> \param md_section ...
1952 : !> \param logger ...
1953 : !> \par History
1954 : !> Creation (10.2009) Teodoro Laino [tlaino]
1955 : ! **************************************************************************************************
1956 40643 : SUBROUTINE angvel_control(md_ener, force_env, md_section, logger)
1957 :
1958 : TYPE(md_ener_type), POINTER :: md_ener
1959 : TYPE(force_env_type), POINTER :: force_env
1960 : TYPE(section_vals_type), POINTER :: md_section
1961 : TYPE(cp_logger_type), POINTER :: logger
1962 :
1963 : CHARACTER(LEN=*), PARAMETER :: routineN = 'angvel_control'
1964 :
1965 : INTEGER :: handle, ifixd, imolecule_kind, iw, natoms
1966 40643 : INTEGER, ALLOCATABLE, DIMENSION(:) :: is_fixed
1967 : LOGICAL :: explicit
1968 : REAL(KIND=dp) :: angvel_tol, rcom(3), temp_old, vang(3), &
1969 : vang_new(3)
1970 : TYPE(cell_type), POINTER :: cell
1971 : TYPE(cp_subsys_type), POINTER :: subsys
1972 40643 : TYPE(fixd_constraint_type), DIMENSION(:), POINTER :: fixd_list
1973 : TYPE(molecule_kind_list_type), POINTER :: molecule_kinds
1974 40643 : TYPE(molecule_kind_type), DIMENSION(:), POINTER :: molecule_kind_set
1975 : TYPE(molecule_kind_type), POINTER :: molecule_kind
1976 : TYPE(particle_list_type), POINTER :: particles
1977 :
1978 40643 : CALL timeset(routineN, handle)
1979 : ! If requested rescale ANGVEL
1980 40643 : CALL section_vals_val_get(md_section, "ANGVEL_TOL", explicit=explicit)
1981 40643 : IF (explicit) THEN
1982 40 : NULLIFY (subsys, cell)
1983 40 : CPASSERT(ASSOCIATED(force_env))
1984 40 : CALL force_env_get(force_env, subsys=subsys, cell=cell)
1985 :
1986 160 : IF (SUM(cell%perd(1:3)) == 0) THEN
1987 40 : CALL section_vals_val_get(md_section, "ANGVEL_TOL", r_val=angvel_tol)
1988 : iw = cp_print_key_unit_nr(logger, md_section, "PRINT%PROGRAM_RUN_INFO", &
1989 40 : extension=".mdLog")
1990 :
1991 : CALL cp_subsys_get(subsys, molecule_kinds=molecule_kinds, &
1992 40 : particles=particles)
1993 :
1994 40 : natoms = SIZE(particles%els)
1995 : ! Build a list of all fixed atoms (if any)
1996 120 : ALLOCATE (is_fixed(natoms))
1997 :
1998 40 : is_fixed = use_perd_none
1999 40 : molecule_kind_set => molecule_kinds%els
2000 600 : DO imolecule_kind = 1, molecule_kinds%n_els
2001 560 : molecule_kind => molecule_kind_set(imolecule_kind)
2002 560 : CALL get_molecule_kind(molecule_kind=molecule_kind, fixd_list=fixd_list)
2003 600 : IF (ASSOCIATED(fixd_list)) THEN
2004 0 : DO ifixd = 1, SIZE(fixd_list)
2005 0 : IF (.NOT. fixd_list(ifixd)%restraint%active) THEN
2006 0 : is_fixed(fixd_list(ifixd)%fixd) = fixd_list(ifixd)%itype
2007 : END IF
2008 : END DO
2009 : END IF
2010 : END DO
2011 :
2012 : ! If requested and the system is not periodic, subtract the angular velocity
2013 40 : CALL compute_rcom(particles%els, is_fixed, rcom)
2014 40 : CALL compute_vang(particles%els, is_fixed, rcom, vang)
2015 : ! SQRT(DOT_PRODUCT(vang,vang))>angvel_tol
2016 160 : IF (DOT_PRODUCT(vang, vang) > (angvel_tol*angvel_tol)) THEN
2017 2 : CALL subtract_vang(particles%els, is_fixed, rcom, vang)
2018 :
2019 : ! Rescale velocities after removal
2020 2 : temp_old = md_ener%temp_part/kelvin
2021 2 : CALL scale_velocity(subsys, md_ener, temp_old, 0.0_dp, iw)
2022 2 : CALL compute_vang(particles%els, is_fixed, rcom, vang_new)
2023 2 : IF (iw > 0) THEN
2024 : WRITE (UNIT=iw, FMT="(T2,A,T30,3(1X,F16.10))") &
2025 1 : 'MD_VEL| Old VANG [a.u.]', vang(1:3)
2026 : WRITE (UNIT=iw, FMT="(T2,A,T30,3(1X,F16.10))") &
2027 1 : 'MD_VEL| New VANG [a.u.]', vang_new(1:3)
2028 : END IF
2029 : END IF
2030 :
2031 40 : DEALLOCATE (is_fixed)
2032 :
2033 : CALL cp_print_key_finished_output(iw, logger, md_section, &
2034 80 : "PRINT%PROGRAM_RUN_INFO")
2035 : END IF
2036 : END IF
2037 :
2038 40643 : CALL timestop(handle)
2039 81286 : END SUBROUTINE angvel_control
2040 :
2041 : ! **************************************************************************************************
2042 : !> \brief Initialize Velocities for MD runs
2043 : !> \param force_env ...
2044 : !> \param simpar ...
2045 : !> \param globenv ...
2046 : !> \param md_env ...
2047 : !> \param md_section ...
2048 : !> \param constraint_section ...
2049 : !> \param write_binary_restart_file ...
2050 : !> \par History
2051 : !> Teodoro Laino - University of Zurich - 09.2007 [tlaino]
2052 : ! **************************************************************************************************
2053 3540 : SUBROUTINE setup_velocities(force_env, simpar, globenv, md_env, md_section, &
2054 : constraint_section, write_binary_restart_file)
2055 :
2056 : TYPE(force_env_type), POINTER :: force_env
2057 : TYPE(simpar_type), POINTER :: simpar
2058 : TYPE(global_environment_type), POINTER :: globenv
2059 : TYPE(md_environment_type), POINTER :: md_env
2060 : TYPE(section_vals_type), POINTER :: md_section, constraint_section
2061 : LOGICAL, INTENT(IN) :: write_binary_restart_file
2062 :
2063 : CHARACTER(LEN=*), PARAMETER :: routineN = 'setup_velocities'
2064 :
2065 : INTEGER :: handle, nconstraint, nconstraint_fixd
2066 : LOGICAL :: apply_cns0, shell_adiabatic, &
2067 : shell_present
2068 : TYPE(atomic_kind_list_type), POINTER :: atomic_kinds
2069 : TYPE(cell_type), POINTER :: cell
2070 : TYPE(cp_subsys_type), POINTER :: subsys
2071 : TYPE(molecule_kind_list_type), POINTER :: molecule_kinds
2072 : TYPE(mp_para_env_type), POINTER :: para_env
2073 : TYPE(particle_list_type), POINTER :: core_particles, particles, &
2074 : shell_particles
2075 1770 : TYPE(particle_type), DIMENSION(:), POINTER :: core_particle_set, particle_set, &
2076 1770 : shell_particle_set
2077 : TYPE(section_vals_type), POINTER :: force_env_section, print_section, &
2078 : subsys_section
2079 :
2080 1770 : CALL timeset(routineN, handle)
2081 :
2082 1770 : NULLIFY (atomic_kinds, cell, para_env, subsys, molecule_kinds, core_particles, particles)
2083 1770 : NULLIFY (shell_particles, core_particle_set, particle_set, shell_particle_set)
2084 1770 : NULLIFY (force_env_section, print_section, subsys_section)
2085 :
2086 1770 : print_section => section_vals_get_subs_vals(md_section, "PRINT")
2087 1770 : apply_cns0 = .FALSE.
2088 1770 : IF (simpar%constraint) THEN
2089 310 : CALL section_vals_val_get(constraint_section, "CONSTRAINT_INIT", l_val=apply_cns0)
2090 : END IF
2091 : ! Always initialize velocities and possibly restart them
2092 : CALL force_env_get(force_env, subsys=subsys, cell=cell, para_env=para_env, &
2093 1770 : force_env_section=force_env_section)
2094 1770 : subsys_section => section_vals_get_subs_vals(force_env_section, "SUBSYS")
2095 :
2096 : CALL cp_subsys_get(subsys, &
2097 : atomic_kinds=atomic_kinds, &
2098 : core_particles=core_particles, &
2099 : molecule_kinds=molecule_kinds, &
2100 : particles=particles, &
2101 1770 : shell_particles=shell_particles)
2102 :
2103 : CALL get_atomic_kind_set(atomic_kind_set=atomic_kinds%els, &
2104 : shell_present=shell_present, &
2105 1770 : shell_adiabatic=shell_adiabatic)
2106 :
2107 1770 : NULLIFY (core_particle_set)
2108 : NULLIFY (particle_set)
2109 1770 : NULLIFY (shell_particle_set)
2110 1770 : particle_set => particles%els
2111 :
2112 1770 : IF (shell_present .AND. shell_adiabatic) THEN
2113 : ! Constraints are not yet implemented for core-shell models generally
2114 : CALL get_molecule_kind_set(molecule_kind_set=molecule_kinds%els, &
2115 : nconstraint=nconstraint, &
2116 132 : nconstraint_fixd=nconstraint_fixd)
2117 132 : IF (nconstraint - nconstraint_fixd /= 0) THEN
2118 0 : CPABORT("Only the fixed atom constraint is implemented for core-shell models")
2119 : END IF
2120 : !MK CPPostcondition(.NOT.simpar%constraint,cp_failure_level,routineP,failure)
2121 132 : CPASSERT(ASSOCIATED(shell_particles))
2122 132 : CPASSERT(ASSOCIATED(core_particles))
2123 132 : shell_particle_set => shell_particles%els
2124 132 : core_particle_set => core_particles%els
2125 : END IF
2126 :
2127 : CALL initialize_velocities(simpar, &
2128 : particle_set, &
2129 : molecule_kinds=molecule_kinds, &
2130 : force_env=force_env, &
2131 : globenv=globenv, &
2132 : md_env=md_env, &
2133 : label="Velocities initialization", &
2134 : print_section=print_section, &
2135 : subsys_section=subsys_section, &
2136 : shell_present=(shell_present .AND. shell_adiabatic), &
2137 : shell_part=shell_particle_set, &
2138 : core_part=core_particle_set, &
2139 : force_rescaling=.FALSE., &
2140 : para_env=para_env, &
2141 3408 : write_binary_restart_file=write_binary_restart_file)
2142 :
2143 : ! Apply constraints if required and rescale velocities..
2144 1770 : IF (simpar%ensemble /= reftraj_ensemble) THEN
2145 1734 : IF (apply_cns0) THEN
2146 24 : CALL force_env_calc_energy_force(force_env, calc_force=.TRUE.)
2147 : CALL force_env_shake(force_env, &
2148 : shake_tol=simpar%shake_tol, &
2149 : log_unit=simpar%info_constraint, &
2150 : lagrange_mult=simpar%lagrange_multipliers, &
2151 : dump_lm=simpar%dump_lm, &
2152 24 : compold=.TRUE.)
2153 : CALL force_env_rattle(force_env, shake_tol=simpar%shake_tol, &
2154 : log_unit=simpar%info_constraint, lagrange_mult=simpar%lagrange_multipliers, &
2155 24 : dump_lm=simpar%dump_lm, reset=.TRUE.)
2156 24 : IF (simpar%do_respa) THEN
2157 : CALL force_env_calc_energy_force(force_env%sub_force_env(1)%force_env, &
2158 0 : calc_force=.TRUE.)
2159 : CALL force_env_shake(force_env%sub_force_env(1)%force_env, &
2160 : shake_tol=simpar%shake_tol, log_unit=simpar%info_constraint, &
2161 0 : lagrange_mult=simpar%lagrange_multipliers, dump_lm=simpar%dump_lm, compold=.TRUE.)
2162 : CALL force_env_rattle(force_env%sub_force_env(1)%force_env, &
2163 : shake_tol=simpar%shake_tol, log_unit=simpar%info_constraint, &
2164 0 : lagrange_mult=simpar%lagrange_multipliers, dump_lm=simpar%dump_lm, reset=.TRUE.)
2165 : END IF
2166 : ! Reinitialize velocities rescaling properly after rattle
2167 24 : subsys_section => section_vals_get_subs_vals(force_env_section, "SUBSYS")
2168 24 : CALL update_subsys(subsys_section, force_env, .FALSE., write_binary_restart_file)
2169 : CALL initialize_velocities(simpar, &
2170 : particle_set, &
2171 : molecule_kinds=molecule_kinds, &
2172 : force_env=force_env, &
2173 : globenv=globenv, &
2174 : md_env=md_env, &
2175 : label="Re-Initializing velocities after applying constraints", &
2176 : print_section=print_section, &
2177 : subsys_section=subsys_section, &
2178 : shell_present=(shell_present .AND. shell_adiabatic), &
2179 : shell_part=shell_particle_set, &
2180 : core_part=core_particle_set, &
2181 : force_rescaling=.TRUE., &
2182 : para_env=para_env, &
2183 48 : write_binary_restart_file=write_binary_restart_file)
2184 : END IF
2185 : END IF
2186 :
2187 : ! Perform setup for a cascade run
2188 1770 : CALL initialize_cascade(simpar, particle_set, molecule_kinds, md_section)
2189 :
2190 1770 : CALL timestop(handle)
2191 :
2192 1770 : END SUBROUTINE setup_velocities
2193 :
2194 : ! **************************************************************************************************
2195 : !> \brief Perform the initialization for a cascade run
2196 : !> \param simpar ...
2197 : !> \param particle_set ...
2198 : !> \param molecule_kinds ...
2199 : !> \param md_section ...
2200 : !> \date 05.02.2012
2201 : !> \author Matthias Krack (MK)
2202 : !> \version 1.0
2203 : ! **************************************************************************************************
2204 1770 : SUBROUTINE initialize_cascade(simpar, particle_set, molecule_kinds, md_section)
2205 :
2206 : TYPE(simpar_type), POINTER :: simpar
2207 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
2208 : TYPE(molecule_kind_list_type), POINTER :: molecule_kinds
2209 : TYPE(section_vals_type), POINTER :: md_section
2210 :
2211 : CHARACTER(LEN=*), PARAMETER :: routineN = 'initialize_cascade'
2212 :
2213 : CHARACTER(len=2*default_string_length) :: line
2214 : INTEGER :: handle, iatom, ifixd, imolecule_kind, &
2215 : iparticle, iw, natom, nparticle
2216 1770 : INTEGER, ALLOCATABLE, DIMENSION(:) :: atom_index, is_fixed
2217 : LOGICAL :: init_cascade, is_ok, no_read_error
2218 : REAL(KIND=dp) :: ecom, ekin, energy, norm, temp, &
2219 : temperature
2220 1770 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: matom, weight
2221 1770 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: vatom
2222 : REAL(KIND=dp), DIMENSION(3) :: vcom
2223 : TYPE(atomic_kind_type), POINTER :: atomic_kind
2224 : TYPE(cp_logger_type), POINTER :: logger
2225 : TYPE(cp_sll_val_type), POINTER :: atom_list
2226 1770 : TYPE(fixd_constraint_type), DIMENSION(:), POINTER :: fixd_list
2227 1770 : TYPE(molecule_kind_type), DIMENSION(:), POINTER :: molecule_kind_set
2228 : TYPE(molecule_kind_type), POINTER :: molecule_kind
2229 : TYPE(section_vals_type), POINTER :: atom_list_section, cascade_section, &
2230 : print_section
2231 : TYPE(val_type), POINTER :: val
2232 :
2233 1770 : CALL timeset(routineN, handle)
2234 :
2235 1770 : NULLIFY (atom_list)
2236 1770 : NULLIFY (atom_list_section)
2237 1770 : NULLIFY (atomic_kind)
2238 1770 : NULLIFY (cascade_section)
2239 1770 : NULLIFY (fixd_list)
2240 1770 : NULLIFY (molecule_kind)
2241 1770 : NULLIFY (molecule_kind_set)
2242 1770 : NULLIFY (logger)
2243 1770 : NULLIFY (val)
2244 :
2245 1770 : logger => cp_get_default_logger()
2246 1770 : print_section => section_vals_get_subs_vals(md_section, "PRINT")
2247 1770 : iw = cp_print_key_unit_nr(logger, print_section, "PROGRAM_RUN_INFO", extension=".log")
2248 :
2249 1770 : cascade_section => section_vals_get_subs_vals(md_section, "CASCADE")
2250 1770 : CALL section_vals_val_get(cascade_section, "_SECTION_PARAMETERS_", l_val=init_cascade)
2251 :
2252 1770 : nparticle = SIZE(particle_set)
2253 :
2254 1770 : IF (init_cascade) THEN
2255 :
2256 2 : CALL section_vals_val_get(cascade_section, "ENERGY", r_val=energy)
2257 2 : IF (energy < 0.0_dp) THEN
2258 0 : CPABORT("Error occurred reading &CASCADE section: Negative energy found")
2259 : END IF
2260 :
2261 2 : IF (iw > 0) THEN
2262 1 : ekin = cp_unit_from_cp2k(energy, "keV")
2263 : WRITE (UNIT=iw, FMT="(/,T2,A,T61,F20.6)") &
2264 1 : "CASCADE| Energy [keV]", ekin
2265 : WRITE (UNIT=iw, FMT="(T2,A)") &
2266 1 : "CASCADE|"
2267 : END IF
2268 :
2269 : ! Read the atomic velocities given in the input file
2270 2 : atom_list_section => section_vals_get_subs_vals(cascade_section, "ATOM_LIST")
2271 2 : CALL section_vals_val_get(atom_list_section, "_DEFAULT_KEYWORD_", n_rep_val=natom)
2272 2 : CALL section_vals_list_get(atom_list_section, "_DEFAULT_KEYWORD_", list=atom_list)
2273 2 : IF (natom <= 0) THEN
2274 0 : CPABORT("Error occurred reading &CASCADE section: No atom list found")
2275 : END IF
2276 :
2277 2 : IF (iw > 0) THEN
2278 : WRITE (UNIT=iw, FMT="(T2,A,T11,A,3(11X,A),9X,A)") &
2279 1 : "CASCADE| ", "Atom index", "v(x)", "v(y)", "v(z)", "weight"
2280 : END IF
2281 :
2282 6 : ALLOCATE (atom_index(natom))
2283 6 : ALLOCATE (matom(natom))
2284 6 : ALLOCATE (vatom(3, natom))
2285 4 : ALLOCATE (weight(natom))
2286 :
2287 8 : DO iatom = 1, natom
2288 6 : is_ok = cp_sll_val_next(atom_list, val)
2289 6 : CALL val_get(val, c_val=line)
2290 : ! Read atomic index, velocity vector, and weight
2291 6 : no_read_error = .FALSE.
2292 6 : READ (UNIT=line, FMT=*, ERR=999) atom_index(iatom), vatom(1:3, iatom), weight(iatom)
2293 : no_read_error = .TRUE.
2294 : 999 IF (.NOT. no_read_error) THEN
2295 0 : CPABORT("Error occurred reading &CASCADE section. Last line read <"//TRIM(line)//">")
2296 : END IF
2297 6 : IF ((atom_index(iatom) <= 0) .OR. ((atom_index(iatom) > nparticle))) THEN
2298 0 : CPABORT("Error occurred reading &CASCADE section: Invalid atom index found")
2299 : END IF
2300 6 : IF (weight(iatom) < 0.0_dp) THEN
2301 0 : CPABORT("Error occurred reading &CASCADE section: Negative weight found")
2302 : END IF
2303 8 : IF (iw > 0) THEN
2304 : WRITE (UNIT=iw, FMT="(T2,A,I10,4(1X,F14.6))") &
2305 3 : "CASCADE| ", atom_index(iatom), vatom(1:3, iatom), weight(iatom)
2306 : END IF
2307 : END DO
2308 :
2309 : ! Normalise velocities and weights
2310 : norm = 0.0_dp
2311 8 : DO iatom = 1, natom
2312 6 : iparticle = atom_index(iatom)
2313 6 : IF (particle_set(iparticle)%shell_index /= 0) THEN
2314 0 : CPWARN("Warning: The primary knock-on atom is a core-shell atom")
2315 : END IF
2316 6 : atomic_kind => particle_set(iparticle)%atomic_kind
2317 6 : CALL get_atomic_kind(atomic_kind=atomic_kind, mass=matom(iatom))
2318 8 : norm = norm + matom(iatom)*weight(iatom)
2319 : END DO
2320 8 : weight(:) = matom(:)*weight(:)*energy/norm
2321 8 : DO iatom = 1, natom
2322 24 : norm = NORM2(vatom(1:3, iatom))
2323 26 : vatom(1:3, iatom) = vatom(1:3, iatom)/norm
2324 : END DO
2325 :
2326 2 : IF (iw > 0) THEN
2327 : WRITE (UNIT=iw, FMT="(T2,A)") &
2328 1 : "CASCADE|", &
2329 1 : "CASCADE| Normalised velocities and additional kinetic energy [keV]", &
2330 2 : "CASCADE|"
2331 : WRITE (UNIT=iw, FMT="(T2,A,T11,A,3(11X,A),9X,A)") &
2332 1 : "CASCADE| ", "Atom index", "v(x)", "v(y)", "v(z)", "E(kin)"
2333 4 : DO iatom = 1, natom
2334 3 : ekin = cp_unit_from_cp2k(weight(iatom), "keV")
2335 : WRITE (UNIT=iw, FMT="(T2,A,I10,4(1X,F14.6))") &
2336 4 : "CASCADE| ", atom_index(iatom), vatom(1:3, iatom), ekin
2337 : END DO
2338 : END IF
2339 :
2340 : ! Apply velocity modifications
2341 8 : DO iatom = 1, natom
2342 6 : iparticle = atom_index(iatom)
2343 : particle_set(iparticle)%v(:) = particle_set(iparticle)%v(:) + &
2344 26 : SQRT(2.0_dp*weight(iatom)/matom(iatom))*vatom(1:3, iatom)
2345 : END DO
2346 :
2347 2 : DEALLOCATE (atom_index)
2348 2 : DEALLOCATE (matom)
2349 2 : DEALLOCATE (vatom)
2350 2 : DEALLOCATE (weight)
2351 :
2352 6 : IF (iw > 0) THEN
2353 : ! Build a list of all fixed atoms (if any)
2354 3 : ALLOCATE (is_fixed(nparticle))
2355 1 : is_fixed = use_perd_none
2356 1 : molecule_kind_set => molecule_kinds%els
2357 2 : DO imolecule_kind = 1, molecule_kinds%n_els
2358 1 : molecule_kind => molecule_kind_set(imolecule_kind)
2359 1 : CALL get_molecule_kind(molecule_kind=molecule_kind, fixd_list=fixd_list)
2360 2 : IF (ASSOCIATED(fixd_list)) THEN
2361 0 : DO ifixd = 1, SIZE(fixd_list)
2362 0 : IF (.NOT. fixd_list(ifixd)%restraint%active) is_fixed(fixd_list(ifixd)%fixd) = fixd_list(ifixd)%itype
2363 : END DO
2364 : END IF
2365 : END DO
2366 : ! Compute vcom, ecom and ekin for printout
2367 1 : CALL compute_vcom(particle_set, is_fixed, vcom, ecom)
2368 1 : ekin = compute_ekin(particle_set) - ecom
2369 1 : IF (simpar%nfree == 0) THEN
2370 0 : CPASSERT(ekin == 0.0_dp)
2371 0 : temp = 0.0_dp
2372 : ELSE
2373 1 : temp = 2.0_dp*ekin/REAL(simpar%nfree, KIND=dp)
2374 : END IF
2375 1 : temperature = cp_unit_from_cp2k(temp, "K")
2376 : WRITE (UNIT=iw, FMT="(T2,A)") &
2377 1 : "CASCADE|"
2378 : WRITE (UNIT=iw, FMT="(T2,A,T61,F20.6)") &
2379 1 : "CASCADE| Temperature after cascade initialization [K]", temperature
2380 : WRITE (UNIT=iw, FMT="(T2,A,T30,3(1X,ES16.8))") &
2381 1 : "CASCADE| COM velocity", vcom(1:3)
2382 : !MK ! compute and log rcom and vang if not periodic
2383 : !MK CALL force_env_get(force_env,cell=cell)
2384 : !MK IF (SUM(cell%perd(1:3)) == 0) THEN
2385 : !MK CALL compute_rcom(particle_set,is_fixed,rcom)
2386 : !MK CALL compute_vang(particle_set,is_fixed,rcom,vang)
2387 : !MK WRITE (iw, '( A, T21, F20.12 , F20.12 , F20.12 )' ) ' COM position:',rcom(1:3)
2388 : !MK WRITE (iw, '( A, T21, F20.12 , F20.12 , F20.12 )' ) ' Angular velocity:',vang(1:3)
2389 : !MK END IF
2390 2 : DEALLOCATE (is_fixed)
2391 : END IF
2392 :
2393 : END IF
2394 :
2395 1770 : CALL cp_print_key_finished_output(iw, logger, print_section, "PROGRAM_RUN_INFO")
2396 :
2397 1770 : CALL timestop(handle)
2398 :
2399 3540 : END SUBROUTINE initialize_cascade
2400 :
2401 : END MODULE md_vel_utils
|