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 3116 : 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 3116 : vcom = 0.0_dp
152 3116 : denom = 0.0_dp
153 746461 : DO i = 1, SIZE(part)
154 743345 : atomic_kind => part(i)%atomic_kind
155 743345 : CALL get_atomic_kind(atomic_kind=atomic_kind, mass=mass)
156 746461 : IF (mass /= 0.0) THEN
157 1479322 : 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 737303 : vcom(1) = vcom(1) + part(i)%v(1)*mass
160 737303 : vcom(2) = vcom(2) + part(i)%v(2)*mass
161 737303 : vcom(3) = vcom(3) + part(i)%v(3)*mass
162 742019 : denom = denom + mass
163 : END SELECT
164 : END IF
165 : END DO
166 12464 : vcom = vcom/denom
167 3116 : IF (PRESENT(ecom)) THEN
168 4364 : ecom = 0.5_dp*denom*SUM(vcom*vcom)
169 : END IF
170 :
171 3116 : 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 3382 : 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 3382 : NULLIFY (atomic_kind)
222 3382 : ekin = 0.0_dp
223 3382 : 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 746267 : DO i = 1, SIZE(part)
233 743153 : atomic_kind => part(i)%atomic_kind
234 743153 : CALL get_atomic_kind(atomic_kind=atomic_kind, mass=mass)
235 2975726 : ekin = ekin + 0.5_dp*mass*SUM(part(i)%v(:)*part(i)%v(:))
236 : END DO
237 : END IF
238 :
239 3382 : 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 2053 : 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 2053 : 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 2047 : ELSEIF (PRESENT(nfree)) THEN
273 0 : my_ireg = 0
274 0 : my_nfree = nfree
275 0 : my_temp = simpar%temp_ext
276 : ELSE
277 2047 : my_ireg = 0
278 2047 : my_nfree = simpar%nfree
279 2047 : my_temp = simpar%temp_ext
280 : END IF
281 2053 : IF (my_nfree /= 0) THEN
282 2041 : 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 2053 : ekin = ekin*factor
290 2053 : factor = SQRT(factor)
291 2053 : 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 444599 : DO i = 1, SIZE(part)
297 1772255 : part(i)%v(:) = factor*part(i)%v(:)
298 : END DO
299 2047 : IF (PRESENT(vcom)) THEN
300 96 : vcom = factor*vcom
301 : END IF
302 : END IF
303 :
304 2053 : 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 2025 : 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 442899 : DO i = 1, SIZE(part)
370 2025 : 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 1747998 : part(i)%v(:) = part(i)%v(:) - vcom(:)
388 : END SELECT
389 : END DO
390 2025 : 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 1791 : 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 1791 : TYPE(fixd_constraint_type), DIMENSION(:), POINTER :: fixd_list
570 1791 : 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 1791 : CALL timeset(routineN, handle)
575 :
576 : ! Initializing parameters
577 1791 : natoms = SIZE(part)
578 1791 : NULLIFY (atomic_kind, fixd_list, logger, molecule_kind)
579 1791 : NULLIFY (molecule_kind_set)
580 :
581 : ! Logging
582 1791 : logger => cp_get_default_logger()
583 1791 : 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 5373 : ALLOCATE (is_fixed(natoms))
587 :
588 1791 : is_fixed = use_perd_none
589 1791 : molecule_kind_set => molecule_kinds%els
590 66581 : DO imolecule_kind = 1, molecule_kinds%n_els
591 64790 : molecule_kind => molecule_kind_set(imolecule_kind)
592 64790 : CALL get_molecule_kind(molecule_kind=molecule_kind, fixd_list=fixd_list)
593 66581 : 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 1791 : 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 1791 : shell_present, shell_part, core_part, force_rescaling, para_env, is_fixed, success)
614 1791 : IF (.NOT. success) THEN
615 3052 : SELECT CASE (simpar%initialization_method)
616 : CASE (md_init_default)
617 : CALL generate_velocities(simpar, part, force_env, globenv, md_env, shell_present, &
618 1525 : 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 1529 : CALL update_subsys(subsys_section, force_env, .FALSE., write_binary_restart_file)
635 : END SELECT
636 : END IF
637 :
638 1791 : 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 1791 : DEALLOCATE (is_fixed)
669 1791 : CALL cp_print_key_finished_output(iw, logger, print_section, "PROGRAM_RUN_INFO")
670 1791 : CALL timestop(handle)
671 :
672 3582 : 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 12537 : SUBROUTINE read_input_velocities(simpar, part, force_env, md_env, subsys_section, &
691 1791 : 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 1791 : 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 1791 : success = .FALSE.
722 1791 : natoms = SIZE(part)
723 : atomvel_read = .FALSE.
724 : corevel_read = .FALSE.
725 : shellvel_read = .FALSE.
726 1791 : NULLIFY (vel, atomic_kind, atom_list, core_list, shell_list)
727 1791 : NULLIFY (atomvel_section, shellvel_section, corevel_section)
728 1791 : NULLIFY (cell, shell, thermal_regions, val)
729 1791 : CALL force_env_get(force_env, cell=cell)
730 :
731 : ! Core-Shell Model
732 1791 : nshell = 0
733 1791 : 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 1791 : atomvel_section => section_vals_get_subs_vals(subsys_section, "VELOCITY")
740 1791 : shellvel_section => section_vals_get_subs_vals(subsys_section, "SHELL_VELOCITY")
741 1791 : corevel_section => section_vals_get_subs_vals(subsys_section, "CORE_VELOCITY")
742 :
743 : ! Read or initialize the particle velocities
744 1791 : CALL section_vals_get(atomvel_section, explicit=atomvel_explicit)
745 1791 : CALL section_vals_get(shellvel_section, explicit=shellvel_explicit)
746 1791 : CALL section_vals_get(corevel_section, explicit=corevel_explicit)
747 1791 : CPASSERT(shellvel_explicit .EQV. corevel_explicit)
748 :
749 : CALL read_binary_velocities("", part, force_env%root_section, para_env, &
750 1791 : subsys_section, atomvel_read, cell)
751 : CALL read_binary_velocities("SHELL", shell_part, force_env%root_section, para_env, &
752 1791 : subsys_section, shellvel_read, cell)
753 : CALL read_binary_velocities("CORE", core_part, force_env%root_section, para_env, &
754 1791 : subsys_section, corevel_read, cell)
755 :
756 1791 : 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 1791 : 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 1525 : SUBROUTINE generate_velocities(simpar, part, force_env, globenv, md_env, &
1176 1525 : 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 1525 : NULLIFY (atomic_kind)
1192 1525 : natoms = SIZE(part)
1193 :
1194 437399 : DO i = 1, natoms
1195 435874 : atomic_kind => part(i)%atomic_kind
1196 435874 : CALL get_atomic_kind(atomic_kind=atomic_kind, mass=mass)
1197 435874 : part(i)%v(1) = 0.0_dp
1198 435874 : part(i)%v(2) = 0.0_dp
1199 435874 : part(i)%v(3) = 0.0_dp
1200 437399 : IF (mass /= 0.0) THEN
1201 435940 : 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 430262 : part(i)%v(1) = globenv%gaussian_rng_stream%next()/SQRT(mass)
1219 430262 : part(i)%v(2) = globenv%gaussian_rng_stream%next()/SQRT(mass)
1220 865690 : part(i)%v(3) = globenv%gaussian_rng_stream%next()/SQRT(mass)
1221 : END SELECT
1222 : END IF
1223 : END DO
1224 :
1225 1525 : CALL normalize_velocities(simpar, part, force_env, md_env, is_fixed)
1226 1525 : 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 1525 : IF (shell_present) THEN
1231 84 : CALL optimize_shell_core(force_env, part, shell_part, core_part, globenv)
1232 : END IF
1233 1525 : 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 1525 : 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 1525 : IF (simpar%soften_nsteps <= 0) RETURN !nothing todo
1259 :
1260 275 : IF (ANY(is_fixed /= use_perd_none)) &
1261 0 : CPABORT("Velocitiy softening with constraints is not supported.")
1262 :
1263 : !backup positions
1264 275 : DO i = 1, SIZE(part)
1265 1025 : x0(i, :) = part(i)%r
1266 : END DO
1267 :
1268 525 : DO k = 1, simpar%soften_nsteps
1269 :
1270 : !use normalized velocities as displace direction
1271 5500 : DO i = 1, SIZE(part)
1272 20500 : N(i, :) = part(i)%v
1273 : END DO
1274 33500 : N = N/SQRT(SUM(N**2))
1275 :
1276 : ! displace system temporarly to calculate forces
1277 5500 : DO i = 1, SIZE(part)
1278 20500 : part(i)%r = part(i)%r + simpar%soften_delta*N(i, :)
1279 : END DO
1280 500 : CALL force_env_calc_energy_force(force_env)
1281 :
1282 : ! calculate velocity update direction F_t
1283 5500 : DO i = 1, SIZE(part)
1284 20500 : F(i, :) = part(i)%f
1285 : END DO
1286 33500 : F_t = F - N*SUM(N*F)
1287 :
1288 : ! restore positions and update velocities
1289 5500 : DO i = 1, SIZE(part)
1290 20000 : part(i)%r = x0(i, :)
1291 20500 : part(i)%v = part(i)%v + simpar%soften_alpha*F_t(i, :)
1292 : END DO
1293 :
1294 525 : CALL normalize_velocities(simpar, part, force_env, md_env, is_fixed)
1295 : END DO
1296 :
1297 25 : IF (iw > 0) THEN
1298 0 : WRITE (iw, "(A,T71, I10)") " Velocities softening Steps: ", simpar%soften_nsteps
1299 0 : WRITE (iw, "(A,T71, E10.3)") " Velocities softening NORM(F_t): ", SQRT(SUM(F_t**2))
1300 : END IF
1301 25 : END SUBROUTINE soften_velocities
1302 :
1303 : ! **************************************************************************************************
1304 : !> \brief Scale velocities according to temperature and remove rigid body motion.
1305 : !> \param simpar ...
1306 : !> \param part ...
1307 : !> \param force_env ...
1308 : !> \param md_env ...
1309 : !> \param is_fixed ...
1310 : !> \author CJM,MK,Toon Verstraelen <Toon.Verstraelen@gmail.com>, Ole Schuett
1311 : ! **************************************************************************************************
1312 2025 : SUBROUTINE normalize_velocities(simpar, part, force_env, md_env, is_fixed)
1313 : TYPE(simpar_type), POINTER :: simpar
1314 : TYPE(particle_type), DIMENSION(:), POINTER :: part
1315 : TYPE(force_env_type), POINTER :: force_env
1316 : TYPE(md_environment_type), POINTER :: md_env
1317 : INTEGER, DIMENSION(:), INTENT(INOUT) :: is_fixed
1318 :
1319 : REAL(KIND=dp) :: ekin
1320 : REAL(KIND=dp), DIMENSION(3) :: rcom, vang, vcom
1321 : TYPE(cell_type), POINTER :: cell
1322 :
1323 2025 : NULLIFY (cell)
1324 :
1325 : ! Subtract the vcom
1326 2025 : CALL compute_vcom(part, is_fixed, vcom)
1327 2025 : CALL subtract_vcom(part, is_fixed, vcom)
1328 : ! If requested and the system is not periodic, subtract the angular velocity
1329 2025 : CALL force_env_get(force_env, cell=cell)
1330 8100 : IF (SUM(cell%perd(1:3)) == 0 .AND. simpar%angvel_zero) THEN
1331 4 : CALL compute_rcom(part, is_fixed, rcom)
1332 4 : CALL compute_vang(part, is_fixed, rcom, vang)
1333 4 : CALL subtract_vang(part, is_fixed, rcom, vang)
1334 : END IF
1335 : ! Rescale the velocities
1336 2025 : IF (simpar%do_thermal_region) THEN
1337 2 : CALL rescale_vel_region(part, md_env, simpar)
1338 : ELSE
1339 2023 : ekin = compute_ekin(part)
1340 2023 : CALL rescale_vel(part, simpar, ekin)
1341 : END IF
1342 2025 : END SUBROUTINE normalize_velocities
1343 :
1344 : ! **************************************************************************************************
1345 : !> \brief Computes Ekin, VCOM and Temp for particles
1346 : !> \param subsys ...
1347 : !> \param md_ener ...
1348 : !> \param vsubtract ...
1349 : !> \par History
1350 : !> Teodoro Laino - University of Zurich - 09.2007 [tlaino]
1351 : ! **************************************************************************************************
1352 42 : SUBROUTINE reset_vcom(subsys, md_ener, vsubtract)
1353 : TYPE(cp_subsys_type), POINTER :: subsys
1354 : TYPE(md_ener_type), POINTER :: md_ener
1355 : REAL(KIND=dp), DIMENSION(3), INTENT(IN) :: vsubtract
1356 :
1357 : CHARACTER(LEN=*), PARAMETER :: routineN = 'reset_vcom'
1358 :
1359 : INTEGER :: atom, handle, iatom, ikind, natom, &
1360 : shell_index
1361 42 : INTEGER, DIMENSION(:), POINTER :: atom_list
1362 : LOGICAL :: is_shell
1363 : REAL(KIND=dp) :: ekin_old, imass_c, imass_s, mass, v2
1364 : REAL(KIND=dp), DIMENSION(3) :: tmp, v
1365 : TYPE(atomic_kind_list_type), POINTER :: atomic_kinds
1366 : TYPE(atomic_kind_type), POINTER :: atomic_kind
1367 : TYPE(particle_list_type), POINTER :: core_particles, particles, &
1368 : shell_particles
1369 : TYPE(shell_kind_type), POINTER :: shell
1370 :
1371 42 : NULLIFY (particles, atomic_kind, atomic_kinds, atom_list, shell)
1372 42 : CALL timeset(routineN, handle)
1373 :
1374 : CALL cp_subsys_get(subsys, &
1375 : atomic_kinds=atomic_kinds, &
1376 : particles=particles, &
1377 : shell_particles=shell_particles, &
1378 42 : core_particles=core_particles)
1379 :
1380 42 : ekin_old = md_ener%ekin
1381 : ! Possibly subtract a quantity from all velocities
1382 126 : DO ikind = 1, atomic_kinds%n_els
1383 84 : atomic_kind => atomic_kinds%els(ikind)
1384 : CALL get_atomic_kind(atomic_kind=atomic_kind, atom_list=atom_list, &
1385 84 : natom=natom, mass=mass, shell_active=is_shell, shell=shell)
1386 126 : IF (is_shell) THEN
1387 336 : tmp = 0.5_dp*vsubtract*mass
1388 84 : imass_s = 1.0_dp/shell%mass_shell
1389 84 : imass_c = 1.0_dp/shell%mass_core
1390 3780 : DO iatom = 1, natom
1391 3696 : atom = atom_list(iatom)
1392 3696 : shell_index = particles%els(atom)%shell_index
1393 14784 : shell_particles%els(shell_index)%v = shell_particles%els(shell_index)%v - tmp*imass_s
1394 14784 : core_particles%els(shell_index)%v = core_particles%els(shell_index)%v - tmp*imass_c
1395 14868 : particles%els(atom)%v = particles%els(atom)%v - vsubtract
1396 : END DO
1397 : ELSE
1398 0 : DO iatom = 1, natom
1399 0 : atom = atom_list(iatom)
1400 0 : particles%els(atom)%v = particles%els(atom)%v - vsubtract
1401 : END DO
1402 : END IF
1403 : END DO
1404 : ! Compute Kinetic Energy and COM Velocity
1405 168 : md_ener%vcom = 0.0_dp
1406 42 : md_ener%total_mass = 0.0_dp
1407 42 : md_ener%ekin = 0.0_dp
1408 126 : DO ikind = 1, atomic_kinds%n_els
1409 84 : atomic_kind => atomic_kinds%els(ikind)
1410 84 : CALL get_atomic_kind(atomic_kind=atomic_kind, atom_list=atom_list, mass=mass, natom=natom)
1411 84 : v2 = 0.0_dp
1412 84 : v = 0.0_dp
1413 3780 : DO iatom = 1, natom
1414 3696 : atom = atom_list(iatom)
1415 14784 : v2 = v2 + SUM(particles%els(atom)%v**2)
1416 3696 : v(1) = v(1) + particles%els(atom)%v(1)
1417 3696 : v(2) = v(2) + particles%els(atom)%v(2)
1418 3780 : v(3) = v(3) + particles%els(atom)%v(3)
1419 : END DO
1420 84 : md_ener%ekin = md_ener%ekin + 0.5_dp*mass*v2
1421 84 : md_ener%vcom(1) = md_ener%vcom(1) + mass*v(1)
1422 84 : md_ener%vcom(2) = md_ener%vcom(2) + mass*v(2)
1423 84 : md_ener%vcom(3) = md_ener%vcom(3) + mass*v(3)
1424 210 : md_ener%total_mass = md_ener%total_mass + REAL(natom, KIND=dp)*mass
1425 : END DO
1426 168 : md_ener%vcom = md_ener%vcom/md_ener%total_mass
1427 42 : md_ener%constant = md_ener%constant - ekin_old + md_ener%ekin
1428 42 : IF (md_ener%nfree /= 0) THEN
1429 42 : md_ener%temp_part = 2.0_dp*md_ener%ekin/REAL(md_ener%nfree, KIND=dp)*kelvin
1430 : END IF
1431 42 : CALL timestop(handle)
1432 :
1433 42 : END SUBROUTINE reset_vcom
1434 :
1435 : ! **************************************************************************************************
1436 : !> \brief Scale velocities to get the correct temperature
1437 : !> \param subsys ...
1438 : !> \param md_ener ...
1439 : !> \param temp_expected ...
1440 : !> \param temp_tol ...
1441 : !> \param iw ...
1442 : !> \par History
1443 : !> Teodoro Laino - University of Zurich - 09.2007 [tlaino]
1444 : ! **************************************************************************************************
1445 12914 : SUBROUTINE scale_velocity(subsys, md_ener, temp_expected, temp_tol, iw)
1446 : TYPE(cp_subsys_type), POINTER :: subsys
1447 : TYPE(md_ener_type), POINTER :: md_ener
1448 : REAL(KIND=dp), INTENT(IN) :: temp_expected, temp_tol
1449 : INTEGER, INTENT(IN) :: iw
1450 :
1451 : REAL(KIND=dp) :: ekin_old, scale, temp_old
1452 :
1453 12914 : IF (ABS(temp_expected - md_ener%temp_part/kelvin) > temp_tol) THEN
1454 2640 : scale = 0.0_dp
1455 2640 : IF (md_ener%temp_part > 0.0_dp) scale = SQRT((temp_expected/md_ener%temp_part)*kelvin)
1456 2640 : ekin_old = md_ener%ekin
1457 2640 : temp_old = md_ener%temp_part
1458 2640 : md_ener%ekin = 0.0_dp
1459 2640 : md_ener%temp_part = 0.0_dp
1460 10560 : md_ener%vcom = 0.0_dp
1461 2640 : md_ener%total_mass = 0.0_dp
1462 :
1463 2640 : CALL scale_velocity_low(subsys, scale, ireg=0, ekin=md_ener%ekin, vcom=md_ener%vcom)
1464 2640 : IF (md_ener%nfree /= 0) THEN
1465 2640 : md_ener%temp_part = 2.0_dp*md_ener%ekin/REAL(md_ener%nfree, KIND=dp)*kelvin
1466 : END IF
1467 2640 : md_ener%constant = md_ener%constant - ekin_old + md_ener%ekin
1468 2640 : IF (iw > 0) THEN
1469 : WRITE (UNIT=iw, FMT='(/,T2,A)') &
1470 1320 : 'MD_VEL| Temperature scaled to requested temperature'
1471 : WRITE (UNIT=iw, FMT='(T2,A,T61,F20.6)') &
1472 1320 : 'MD_VEL| Old temperature [K]', temp_old, &
1473 2640 : 'MD_VEL| New temperature [K]', md_ener%temp_part
1474 : END IF
1475 : END IF
1476 :
1477 12914 : END SUBROUTINE scale_velocity
1478 :
1479 : ! **************************************************************************************************
1480 : !> \brief Scale velocities of set of regions
1481 : !> \param md_env ...
1482 : !> \param subsys ...
1483 : !> \param md_ener ...
1484 : !> \param simpar ...
1485 : !> \param iw ...
1486 : !> \par author MI
1487 : ! **************************************************************************************************
1488 96 : SUBROUTINE scale_velocity_region(md_env, subsys, md_ener, simpar, iw)
1489 :
1490 : TYPE(md_environment_type), POINTER :: md_env
1491 : TYPE(cp_subsys_type), POINTER :: subsys
1492 : TYPE(md_ener_type), POINTER :: md_ener
1493 : TYPE(simpar_type), POINTER :: simpar
1494 : INTEGER, INTENT(IN) :: iw
1495 :
1496 : INTEGER :: ireg, nfree, nfree_done, nregions
1497 : REAL(KIND=dp) :: ekin, ekin_old, ekin_total_new, fscale, &
1498 : vcom(3), vcom_total(3)
1499 96 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: temp_new, temp_old
1500 : TYPE(particle_list_type), POINTER :: particles
1501 : TYPE(particle_type), DIMENSION(:), POINTER :: part
1502 : TYPE(thermal_region_type), POINTER :: t_region
1503 : TYPE(thermal_regions_type), POINTER :: thermal_regions
1504 :
1505 96 : NULLIFY (particles, part, thermal_regions, t_region)
1506 96 : CALL cp_subsys_get(subsys, particles=particles)
1507 96 : part => particles%els
1508 96 : CALL get_md_env(md_env, thermal_regions=thermal_regions)
1509 :
1510 96 : nregions = thermal_regions%nregions
1511 96 : nfree_done = 0
1512 96 : ekin_total_new = 0.0_dp
1513 96 : ekin_old = md_ener%ekin
1514 : vcom_total = 0.0_dp
1515 384 : ALLOCATE (temp_new(0:nregions), temp_old(0:nregions))
1516 96 : temp_new = 0.0_dp
1517 96 : temp_old = 0.0_dp
1518 : !loop regions
1519 256 : DO ireg = 1, nregions
1520 160 : NULLIFY (t_region)
1521 160 : t_region => thermal_regions%thermal_region(ireg)
1522 160 : nfree = 3*t_region%npart
1523 160 : ekin = compute_ekin(part, ireg)
1524 160 : IF (nfree > 0) t_region%temperature = 2.0_dp*ekin/REAL(nfree, KIND=dp)*kelvin
1525 160 : temp_old(ireg) = t_region%temperature
1526 160 : IF (t_region%temp_tol > 0.0_dp .AND. &
1527 : ABS(t_region%temp_expected - t_region%temperature/kelvin) > t_region%temp_tol) THEN
1528 2 : fscale = SQRT((t_region%temp_expected/t_region%temperature)*kelvin)
1529 2 : CALL scale_velocity_low(subsys, fscale, ireg, ekin, vcom)
1530 2 : t_region%temperature = 2.0_dp*ekin/REAL(nfree, KIND=dp)*kelvin
1531 2 : temp_new(ireg) = t_region%temperature
1532 : END IF
1533 160 : nfree_done = nfree_done + nfree
1534 256 : ekin_total_new = ekin_total_new + ekin
1535 : END DO
1536 96 : nfree = simpar%nfree - nfree_done
1537 96 : ekin = compute_ekin(part, ireg=0)
1538 96 : IF (nfree > 0) thermal_regions%temp_reg0 = 2.0_dp*ekin/REAL(nfree, KIND=dp)*kelvin
1539 96 : temp_old(0) = thermal_regions%temp_reg0
1540 96 : IF (simpar%temp_tol > 0.0_dp .AND. nfree > 0) THEN
1541 0 : IF (ABS(simpar%temp_ext - thermal_regions%temp_reg0/kelvin) > simpar%temp_tol) THEN
1542 0 : fscale = SQRT((simpar%temp_ext/thermal_regions%temp_reg0)*kelvin)
1543 0 : CALL scale_velocity_low(subsys, fscale, 0, ekin, vcom)
1544 0 : thermal_regions%temp_reg0 = 2.0_dp*ekin/REAL(nfree, KIND=dp)*kelvin
1545 0 : temp_new(0) = thermal_regions%temp_reg0
1546 : END IF
1547 : END IF
1548 96 : ekin_total_new = ekin_total_new + ekin
1549 :
1550 96 : md_ener%ekin = ekin_total_new
1551 96 : IF (md_ener%nfree /= 0) THEN
1552 96 : md_ener%temp_part = 2.0_dp*md_ener%ekin/REAL(md_ener%nfree, KIND=dp)*kelvin
1553 : END IF
1554 96 : md_ener%constant = md_ener%constant - ekin_old + md_ener%ekin
1555 96 : IF (iw > 0) THEN
1556 176 : DO ireg = 0, nregions
1557 176 : IF (temp_new(ireg) > 0.0_dp) THEN
1558 : WRITE (UNIT=iw, FMT='(/,T2,A,I0,A)') &
1559 1 : 'MD_VEL| Temperature region ', ireg, ' scaled to requested temperature'
1560 : WRITE (UNIT=iw, FMT='(T2,A,T61,F20.6)') &
1561 1 : 'MD_VEL| Old temperature [K]', temp_old(ireg), &
1562 2 : 'MD_VEL| New temperature [K]', temp_new(ireg)
1563 : END IF
1564 : END DO
1565 : END IF
1566 96 : DEALLOCATE (temp_new, temp_old)
1567 :
1568 96 : END SUBROUTINE scale_velocity_region
1569 :
1570 : ! **************************************************************************************************
1571 : !> \brief Scale velocities for a specific region
1572 : !> \param subsys ...
1573 : !> \param fscale ...
1574 : !> \param ireg ...
1575 : !> \param ekin ...
1576 : !> \param vcom ...
1577 : !> \par author MI
1578 : ! **************************************************************************************************
1579 2642 : SUBROUTINE scale_velocity_low(subsys, fscale, ireg, ekin, vcom)
1580 :
1581 : TYPE(cp_subsys_type), POINTER :: subsys
1582 : REAL(KIND=dp), INTENT(IN) :: fscale
1583 : INTEGER, INTENT(IN) :: ireg
1584 : REAL(KIND=dp), INTENT(OUT) :: ekin, vcom(3)
1585 :
1586 : INTEGER :: atom, iatom, ikind, my_ireg, natom, &
1587 : shell_index
1588 2642 : INTEGER, DIMENSION(:), POINTER :: atom_list
1589 : LOGICAL :: is_shell
1590 : REAL(KIND=dp) :: imass, mass, tmass, v2
1591 : REAL(KIND=dp), DIMENSION(3) :: tmp, v, vc, vs
1592 : TYPE(atomic_kind_list_type), POINTER :: atomic_kinds
1593 : TYPE(atomic_kind_type), POINTER :: atomic_kind
1594 : TYPE(particle_list_type), POINTER :: core_particles, particles, &
1595 : shell_particles
1596 : TYPE(shell_kind_type), POINTER :: shell
1597 :
1598 2642 : NULLIFY (atomic_kinds, particles, shell_particles, core_particles, shell, atom_list)
1599 :
1600 2642 : my_ireg = ireg
1601 2642 : ekin = 0.0_dp
1602 2642 : tmass = 0.0_dp
1603 2642 : vcom = 0.0_dp
1604 :
1605 : CALL cp_subsys_get(subsys, atomic_kinds=atomic_kinds, particles=particles, &
1606 2642 : shell_particles=shell_particles, core_particles=core_particles)
1607 :
1608 9082 : DO ikind = 1, atomic_kinds%n_els
1609 6440 : atomic_kind => atomic_kinds%els(ikind)
1610 : CALL get_atomic_kind(atomic_kind=atomic_kind, atom_list=atom_list, mass=mass, &
1611 6440 : natom=natom, shell_active=is_shell, shell=shell)
1612 6440 : IF (is_shell) THEN
1613 124 : imass = 1.0_dp/mass
1614 124 : v2 = 0.0_dp
1615 124 : v = 0.0_dp
1616 5740 : DO iatom = 1, natom
1617 5616 : atom = atom_list(iatom)
1618 : !check region
1619 5616 : IF (particles%els(atom)%t_region_index /= my_ireg) CYCLE
1620 :
1621 21080 : particles%els(atom)%v(:) = fscale*particles%els(atom)%v
1622 5270 : shell_index = particles%els(atom)%shell_index
1623 21080 : vs = shell_particles%els(shell_index)%v
1624 21080 : vc = core_particles%els(shell_index)%v
1625 5270 : tmp(1) = imass*(vs(1) - vc(1))
1626 5270 : tmp(2) = imass*(vs(2) - vc(2))
1627 5270 : tmp(3) = imass*(vs(3) - vc(3))
1628 :
1629 5270 : shell_particles%els(shell_index)%v(1) = particles%els(atom)%v(1) + tmp(1)*shell%mass_core
1630 5270 : shell_particles%els(shell_index)%v(2) = particles%els(atom)%v(2) + tmp(2)*shell%mass_core
1631 5270 : shell_particles%els(shell_index)%v(3) = particles%els(atom)%v(3) + tmp(3)*shell%mass_core
1632 :
1633 5270 : core_particles%els(shell_index)%v(1) = particles%els(atom)%v(1) - tmp(1)*shell%mass_shell
1634 5270 : core_particles%els(shell_index)%v(2) = particles%els(atom)%v(2) - tmp(2)*shell%mass_shell
1635 5270 : core_particles%els(shell_index)%v(3) = particles%els(atom)%v(3) - tmp(3)*shell%mass_shell
1636 :
1637 : ! kinetic energy and velocity of COM
1638 21080 : v2 = v2 + SUM(particles%els(atom)%v**2)
1639 5270 : v(1) = v(1) + particles%els(atom)%v(1)
1640 5270 : v(2) = v(2) + particles%els(atom)%v(2)
1641 5270 : v(3) = v(3) + particles%els(atom)%v(3)
1642 5740 : tmass = tmass + mass
1643 : END DO
1644 : ELSE
1645 6316 : v2 = 0.0_dp
1646 6316 : v = 0.0_dp
1647 22826 : DO iatom = 1, natom
1648 16510 : atom = atom_list(iatom)
1649 : !check region
1650 16510 : IF (particles%els(atom)%t_region_index /= my_ireg) CYCLE
1651 :
1652 66040 : particles%els(atom)%v(:) = fscale*particles%els(atom)%v
1653 : ! kinetic energy and velocity of COM
1654 66040 : v2 = v2 + SUM(particles%els(atom)%v**2)
1655 16510 : v(1) = v(1) + particles%els(atom)%v(1)
1656 16510 : v(2) = v(2) + particles%els(atom)%v(2)
1657 16510 : v(3) = v(3) + particles%els(atom)%v(3)
1658 22826 : tmass = tmass + mass
1659 : END DO
1660 : END IF
1661 6440 : ekin = ekin + 0.5_dp*mass*v2
1662 6440 : vcom(1) = vcom(1) + mass*v(1)
1663 6440 : vcom(2) = vcom(2) + mass*v(2)
1664 15522 : vcom(3) = vcom(3) + mass*v(3)
1665 :
1666 : END DO
1667 10568 : vcom = vcom/tmass
1668 :
1669 2642 : END SUBROUTINE scale_velocity_low
1670 :
1671 : ! **************************************************************************************************
1672 : !> \brief Scale internal motion of CORE-SHELL model to the correct temperature
1673 : !> \param subsys ...
1674 : !> \param md_ener ...
1675 : !> \param temp_expected ...
1676 : !> \param temp_tol ...
1677 : !> \param iw ...
1678 : !> \par History
1679 : !> Teodoro Laino - University of Zurich - 09.2007 [tlaino]
1680 : ! **************************************************************************************************
1681 1060 : SUBROUTINE scale_velocity_internal(subsys, md_ener, temp_expected, temp_tol, iw)
1682 : TYPE(cp_subsys_type), POINTER :: subsys
1683 : TYPE(md_ener_type), POINTER :: md_ener
1684 : REAL(KIND=dp), INTENT(IN) :: temp_expected, temp_tol
1685 : INTEGER, INTENT(IN) :: iw
1686 :
1687 : INTEGER :: atom, iatom, ikind, natom, shell_index
1688 1060 : INTEGER, DIMENSION(:), POINTER :: atom_list
1689 : LOGICAL :: is_shell
1690 : REAL(KIND=dp) :: ekin_shell_old, fac_mass, mass, scale, &
1691 : temp_shell_old, v2
1692 : REAL(KIND=dp), DIMENSION(3) :: tmp, v, vc, vs
1693 : TYPE(atomic_kind_list_type), POINTER :: atomic_kinds
1694 : TYPE(atomic_kind_type), POINTER :: atomic_kind
1695 : TYPE(particle_list_type), POINTER :: core_particles, particles, &
1696 : shell_particles
1697 : TYPE(shell_kind_type), POINTER :: shell
1698 :
1699 1060 : NULLIFY (atom_list, atomic_kinds, atomic_kind, core_particles, particles, shell_particles, shell)
1700 1060 : IF (ABS(temp_expected - md_ener%temp_shell/kelvin) > temp_tol) THEN
1701 80 : scale = 0.0_dp
1702 80 : IF (md_ener%temp_shell > EPSILON(0.0_dp)) scale = SQRT((temp_expected/md_ener%temp_shell)*kelvin)
1703 80 : ekin_shell_old = md_ener%ekin_shell
1704 80 : temp_shell_old = md_ener%temp_shell
1705 80 : md_ener%ekin_shell = 0.0_dp
1706 80 : md_ener%temp_shell = 0.0_dp
1707 :
1708 : CALL cp_subsys_get(subsys, atomic_kinds=atomic_kinds, particles=particles, shell_particles=shell_particles, &
1709 80 : core_particles=core_particles)
1710 :
1711 240 : DO ikind = 1, atomic_kinds%n_els
1712 160 : atomic_kind => atomic_kinds%els(ikind)
1713 : CALL get_atomic_kind(atomic_kind=atomic_kind, atom_list=atom_list, mass=mass, natom=natom, &
1714 160 : shell_active=is_shell, shell=shell)
1715 240 : IF (is_shell) THEN
1716 160 : fac_mass = 1.0_dp/mass
1717 160 : v2 = 0.0_dp
1718 776 : DO iatom = 1, natom
1719 616 : atom = atom_list(iatom)
1720 616 : shell_index = particles%els(atom)%shell_index
1721 2464 : vs = shell_particles%els(shell_index)%v
1722 2464 : vc = core_particles%els(shell_index)%v
1723 2464 : v = particles%els(atom)%v
1724 616 : tmp(1) = fac_mass*(vc(1) - vs(1))
1725 616 : tmp(2) = fac_mass*(vc(2) - vs(2))
1726 616 : tmp(3) = fac_mass*(vc(3) - vs(3))
1727 :
1728 616 : shell_particles%els(shell_index)%v(1) = v(1) - shell%mass_core*scale*tmp(1)
1729 616 : shell_particles%els(shell_index)%v(2) = v(2) - shell%mass_core*scale*tmp(2)
1730 616 : shell_particles%els(shell_index)%v(3) = v(3) - shell%mass_core*scale*tmp(3)
1731 :
1732 616 : core_particles%els(shell_index)%v(1) = v(1) + shell%mass_shell*scale*tmp(1)
1733 616 : core_particles%els(shell_index)%v(2) = v(2) + shell%mass_shell*scale*tmp(2)
1734 616 : core_particles%els(shell_index)%v(3) = v(3) + shell%mass_shell*scale*tmp(3)
1735 :
1736 2464 : vs = shell_particles%els(shell_index)%v
1737 2464 : vc = core_particles%els(shell_index)%v
1738 616 : tmp(1) = vc(1) - vs(1)
1739 616 : tmp(2) = vc(2) - vs(2)
1740 616 : tmp(3) = vc(3) - vs(3)
1741 2624 : v2 = v2 + SUM(tmp**2)
1742 : END DO
1743 160 : md_ener%ekin_shell = md_ener%ekin_shell + 0.5_dp*shell%mass_core*shell%mass_shell*fac_mass*v2
1744 : END IF
1745 : END DO
1746 80 : IF (md_ener%nfree_shell > 0) THEN
1747 80 : md_ener%temp_shell = 2.0_dp*md_ener%ekin_shell/REAL(md_ener%nfree_shell, KIND=dp)*kelvin
1748 : END IF
1749 80 : md_ener%constant = md_ener%constant - ekin_shell_old + md_ener%ekin_shell
1750 80 : IF (iw > 0) THEN
1751 : WRITE (UNIT=iw, FMT='(/,T2,A)') &
1752 40 : 'MD_VEL| Temperature of shell internal motion scaled to requested temperature'
1753 : WRITE (UNIT=iw, FMT='(T2,A,T61,F20.6)') &
1754 40 : 'MD_VEL| Old temperature [K]', temp_shell_old, &
1755 80 : 'MD_VEL| New temperature [K]', md_ener%temp_shell
1756 : END IF
1757 : END IF
1758 :
1759 1060 : END SUBROUTINE scale_velocity_internal
1760 :
1761 : ! **************************************************************************************************
1762 : !> \brief Scale barostat velocities to get the desired temperature
1763 : !> \param md_env ...
1764 : !> \param md_ener ...
1765 : !> \param temp_expected ...
1766 : !> \param temp_tol ...
1767 : !> \param iw ...
1768 : !> \par History
1769 : !> MI 02.2008
1770 : ! **************************************************************************************************
1771 40 : SUBROUTINE scale_velocity_baro(md_env, md_ener, temp_expected, temp_tol, iw)
1772 : TYPE(md_environment_type), POINTER :: md_env
1773 : TYPE(md_ener_type), POINTER :: md_ener
1774 : REAL(KIND=dp), INTENT(IN) :: temp_expected, temp_tol
1775 : INTEGER, INTENT(IN) :: iw
1776 :
1777 : INTEGER :: i, j, nfree
1778 : REAL(KIND=dp) :: ekin_old, scale, temp_old
1779 40 : TYPE(npt_info_type), POINTER :: npt(:, :)
1780 : TYPE(simpar_type), POINTER :: simpar
1781 :
1782 40 : NULLIFY (npt, simpar)
1783 40 : CALL get_md_env(md_env, simpar=simpar, npt=npt)
1784 40 : IF (ABS(temp_expected - md_ener%temp_baro/kelvin) > temp_tol) THEN
1785 2 : scale = 0.0_dp
1786 2 : IF (md_ener%temp_baro > 0.0_dp) scale = SQRT((temp_expected/md_ener%temp_baro)*kelvin)
1787 2 : ekin_old = md_ener%baro_kin
1788 2 : temp_old = md_ener%temp_baro
1789 2 : md_ener%baro_kin = 0.0_dp
1790 2 : md_ener%temp_baro = 0.0_dp
1791 : IF (simpar%ensemble == npt_i_ensemble .OR. simpar%ensemble == npe_i_ensemble &
1792 2 : .OR. simpar%ensemble == npt_ia_ensemble) THEN
1793 0 : npt(1, 1)%v = npt(1, 1)%v*scale
1794 0 : md_ener%baro_kin = 0.5_dp*npt(1, 1)%v**2*npt(1, 1)%mass
1795 : ELSE IF (simpar%ensemble == npt_f_ensemble .OR. simpar%ensemble == npe_f_ensemble) THEN
1796 2 : md_ener%baro_kin = 0.0_dp
1797 8 : DO i = 1, 3
1798 26 : DO j = 1, 3
1799 18 : npt(i, j)%v = npt(i, j)%v*scale
1800 24 : md_ener%baro_kin = md_ener%baro_kin + 0.5_dp*npt(i, j)%v**2*npt(i, j)%mass
1801 : END DO
1802 : END DO
1803 : END IF
1804 2 : nfree = SIZE(npt, 1)*SIZE(npt, 2)
1805 2 : md_ener%temp_baro = 2.0_dp*md_ener%baro_kin/REAL(nfree, dp)*kelvin
1806 2 : IF (iw > 0) THEN
1807 : WRITE (UNIT=iw, FMT='(/,T2,A)') &
1808 1 : 'MD_VEL| Temperature of barostat motion scaled to requested temperature'
1809 : WRITE (UNIT=iw, FMT='(T2,A,T61,F20.6)') &
1810 1 : 'MD_VEL| Old temperature [K]', temp_old, &
1811 2 : 'MD_VEL| New temperature [K]', md_ener%temp_baro
1812 : END IF
1813 : END IF
1814 :
1815 40 : END SUBROUTINE scale_velocity_baro
1816 :
1817 : ! **************************************************************************************************
1818 : !> \brief Perform all temperature manipulations during a QS MD run.
1819 : !> \param simpar ...
1820 : !> \param md_env ...
1821 : !> \param md_ener ...
1822 : !> \param force_env ...
1823 : !> \param logger ...
1824 : !> \par History
1825 : !> Creation (15.09.2003,MK)
1826 : !> adapted to force_env (05.10.2003,fawzi)
1827 : !> Cleaned (09.2007) Teodoro Laino [tlaino] - University of Zurich
1828 : ! **************************************************************************************************
1829 40248 : SUBROUTINE temperature_control(simpar, md_env, md_ener, force_env, logger)
1830 :
1831 : TYPE(simpar_type), POINTER :: simpar
1832 : TYPE(md_environment_type), POINTER :: md_env
1833 : TYPE(md_ener_type), POINTER :: md_ener
1834 : TYPE(force_env_type), POINTER :: force_env
1835 : TYPE(cp_logger_type), POINTER :: logger
1836 :
1837 : CHARACTER(LEN=*), PARAMETER :: routineN = 'temperature_control'
1838 :
1839 : INTEGER :: handle, iw
1840 : TYPE(cp_subsys_type), POINTER :: subsys
1841 : TYPE(mp_para_env_type), POINTER :: para_env
1842 :
1843 40248 : CALL timeset(routineN, handle)
1844 40248 : NULLIFY (subsys, para_env)
1845 40248 : CPASSERT(ASSOCIATED(simpar))
1846 40248 : CPASSERT(ASSOCIATED(md_ener))
1847 40248 : CPASSERT(ASSOCIATED(force_env))
1848 40248 : CALL force_env_get(force_env, subsys=subsys, para_env=para_env)
1849 : iw = cp_print_key_unit_nr(logger, force_env%root_section, "MOTION%MD%PRINT%PROGRAM_RUN_INFO", &
1850 40248 : extension=".mdLog")
1851 :
1852 : ! Control the particle motion
1853 40248 : IF (simpar%do_thermal_region) THEN
1854 96 : CALL scale_velocity_region(md_env, subsys, md_ener, simpar, iw)
1855 : ELSE
1856 40152 : IF (simpar%temp_tol > 0.0_dp) THEN
1857 12870 : CALL scale_velocity(subsys, md_ener, simpar%temp_ext, simpar%temp_tol, iw)
1858 : END IF
1859 : END IF
1860 : ! Control the internal core-shell motion
1861 40248 : IF (simpar%temp_sh_tol > 0.0_dp) THEN
1862 1060 : CALL scale_velocity_internal(subsys, md_ener, simpar%temp_sh_ext, simpar%temp_sh_tol, iw)
1863 : END IF
1864 : ! Control cell motion
1865 42768 : SELECT CASE (simpar%ensemble)
1866 : CASE (nph_uniaxial_damped_ensemble, nph_uniaxial_ensemble, &
1867 : npt_f_ensemble, npt_i_ensemble, npe_f_ensemble, npe_i_ensemble, npt_ia_ensemble)
1868 40248 : IF (simpar%temp_baro_tol > 0.0_dp) THEN
1869 40 : CALL scale_velocity_baro(md_env, md_ener, simpar%temp_baro_ext, simpar%temp_baro_tol, iw)
1870 : END IF
1871 : END SELECT
1872 :
1873 : CALL cp_print_key_finished_output(iw, logger, force_env%root_section, &
1874 40248 : "MOTION%MD%PRINT%PROGRAM_RUN_INFO")
1875 40248 : CALL timestop(handle)
1876 40248 : END SUBROUTINE temperature_control
1877 :
1878 : ! **************************************************************************************************
1879 : !> \brief Set to 0 the velocity of the COM along MD runs, if required.
1880 : !> \param md_ener ...
1881 : !> \param force_env ...
1882 : !> \param md_section ...
1883 : !> \param logger ...
1884 : !> \par History
1885 : !> Creation (29.04.2007,MI)
1886 : !> Cleaned (09.2007) Teodoro Laino [tlaino] - University of Zurich
1887 : ! **************************************************************************************************
1888 80496 : SUBROUTINE comvel_control(md_ener, force_env, md_section, logger)
1889 :
1890 : TYPE(md_ener_type), POINTER :: md_ener
1891 : TYPE(force_env_type), POINTER :: force_env
1892 : TYPE(section_vals_type), POINTER :: md_section
1893 : TYPE(cp_logger_type), POINTER :: logger
1894 :
1895 : CHARACTER(LEN=*), PARAMETER :: routineN = 'comvel_control'
1896 :
1897 : INTEGER :: handle, iw
1898 : LOGICAL :: explicit
1899 : REAL(KIND=dp) :: comvel_tol, temp_old, vel_com
1900 : REAL(KIND=dp), DIMENSION(3) :: vcom_old
1901 : TYPE(cp_subsys_type), POINTER :: subsys
1902 :
1903 40248 : CALL timeset(routineN, handle)
1904 40248 : NULLIFY (subsys)
1905 40248 : CPASSERT(ASSOCIATED(force_env))
1906 40248 : CALL force_env_get(force_env, subsys=subsys)
1907 :
1908 : ! Print COMVEL and COM Position
1909 40248 : iw = cp_print_key_unit_nr(logger, md_section, "PRINT%CENTER_OF_MASS", extension=".mdLog")
1910 40248 : IF (iw > 0) THEN
1911 : WRITE (UNIT=iw, FMT="(/,T2,A)") &
1912 7785 : "MD_VEL| Centre of mass motion (COM)"
1913 : WRITE (UNIT=iw, FMT="(T2,A,T30,3(1X,F16.10))") &
1914 31140 : "MD_VEL| VCOM [a.u.]", md_ener%vcom(1:3)
1915 : END IF
1916 40248 : CALL cp_print_key_finished_output(iw, logger, md_section, "PRINT%CENTER_OF_MASS")
1917 :
1918 : ! If requested rescale COMVEL
1919 40248 : CALL section_vals_val_get(md_section, "COMVEL_TOL", explicit=explicit)
1920 40248 : IF (explicit) THEN
1921 826 : CALL section_vals_val_get(md_section, "COMVEL_TOL", r_val=comvel_tol)
1922 : iw = cp_print_key_unit_nr(logger, md_section, "PRINT%PROGRAM_RUN_INFO", &
1923 826 : extension=".mdLog")
1924 826 : vel_com = SQRT(md_ener%vcom(1)**2 + md_ener%vcom(2)**2 + md_ener%vcom(3)**2)
1925 :
1926 : ! Subtract the velocity of the COM, if requested
1927 826 : IF (vel_com > comvel_tol) THEN
1928 42 : temp_old = md_ener%temp_part/kelvin
1929 168 : vcom_old = md_ener%vcom
1930 42 : CALL reset_vcom(subsys, md_ener, vsubtract=vcom_old)
1931 42 : CALL scale_velocity(subsys, md_ener, temp_old, 0.0_dp, iw)
1932 42 : IF (iw > 0) THEN
1933 : WRITE (UNIT=iw, FMT="(T2,A,T30,3(1X,F16.10))") &
1934 21 : "MD_VEL| Old VCOM [a.u.]", vcom_old(1:3)
1935 : WRITE (UNIT=iw, FMT="(T2,A,T30,3(1X,F16.10))") &
1936 84 : "MD_VEL| New VCOM [a.u.]", md_ener%vcom(1:3)
1937 : END IF
1938 : END IF
1939 : CALL cp_print_key_finished_output(iw, logger, md_section, &
1940 826 : "PRINT%PROGRAM_RUN_INFO")
1941 : END IF
1942 :
1943 40248 : CALL timestop(handle)
1944 40248 : END SUBROUTINE comvel_control
1945 :
1946 : ! **************************************************************************************************
1947 : !> \brief Set to 0 the angular velocity along MD runs, if required.
1948 : !> \param md_ener ...
1949 : !> \param force_env ...
1950 : !> \param md_section ...
1951 : !> \param logger ...
1952 : !> \par History
1953 : !> Creation (10.2009) Teodoro Laino [tlaino]
1954 : ! **************************************************************************************************
1955 40248 : SUBROUTINE angvel_control(md_ener, force_env, md_section, logger)
1956 :
1957 : TYPE(md_ener_type), POINTER :: md_ener
1958 : TYPE(force_env_type), POINTER :: force_env
1959 : TYPE(section_vals_type), POINTER :: md_section
1960 : TYPE(cp_logger_type), POINTER :: logger
1961 :
1962 : CHARACTER(LEN=*), PARAMETER :: routineN = 'angvel_control'
1963 :
1964 : INTEGER :: handle, ifixd, imolecule_kind, iw, natoms
1965 40248 : INTEGER, ALLOCATABLE, DIMENSION(:) :: is_fixed
1966 : LOGICAL :: explicit
1967 : REAL(KIND=dp) :: angvel_tol, rcom(3), temp_old, vang(3), &
1968 : vang_new(3)
1969 : TYPE(cell_type), POINTER :: cell
1970 : TYPE(cp_subsys_type), POINTER :: subsys
1971 40248 : TYPE(fixd_constraint_type), DIMENSION(:), POINTER :: fixd_list
1972 : TYPE(molecule_kind_list_type), POINTER :: molecule_kinds
1973 40248 : TYPE(molecule_kind_type), DIMENSION(:), POINTER :: molecule_kind_set
1974 : TYPE(molecule_kind_type), POINTER :: molecule_kind
1975 : TYPE(particle_list_type), POINTER :: particles
1976 :
1977 40248 : CALL timeset(routineN, handle)
1978 : ! If requested rescale ANGVEL
1979 40248 : CALL section_vals_val_get(md_section, "ANGVEL_TOL", explicit=explicit)
1980 40248 : IF (explicit) THEN
1981 40 : NULLIFY (subsys, cell)
1982 40 : CPASSERT(ASSOCIATED(force_env))
1983 40 : CALL force_env_get(force_env, subsys=subsys, cell=cell)
1984 :
1985 160 : IF (SUM(cell%perd(1:3)) == 0) THEN
1986 40 : CALL section_vals_val_get(md_section, "ANGVEL_TOL", r_val=angvel_tol)
1987 : iw = cp_print_key_unit_nr(logger, md_section, "PRINT%PROGRAM_RUN_INFO", &
1988 40 : extension=".mdLog")
1989 :
1990 : CALL cp_subsys_get(subsys, molecule_kinds=molecule_kinds, &
1991 40 : particles=particles)
1992 :
1993 40 : natoms = SIZE(particles%els)
1994 : ! Build a list of all fixed atoms (if any)
1995 120 : ALLOCATE (is_fixed(natoms))
1996 :
1997 40 : is_fixed = use_perd_none
1998 40 : molecule_kind_set => molecule_kinds%els
1999 600 : DO imolecule_kind = 1, molecule_kinds%n_els
2000 560 : molecule_kind => molecule_kind_set(imolecule_kind)
2001 560 : CALL get_molecule_kind(molecule_kind=molecule_kind, fixd_list=fixd_list)
2002 600 : IF (ASSOCIATED(fixd_list)) THEN
2003 0 : DO ifixd = 1, SIZE(fixd_list)
2004 0 : IF (.NOT. fixd_list(ifixd)%restraint%active) &
2005 0 : is_fixed(fixd_list(ifixd)%fixd) = fixd_list(ifixd)%itype
2006 : END DO
2007 : END IF
2008 : END DO
2009 :
2010 : ! If requested and the system is not periodic, subtract the angular velocity
2011 40 : CALL compute_rcom(particles%els, is_fixed, rcom)
2012 40 : CALL compute_vang(particles%els, is_fixed, rcom, vang)
2013 : ! SQRT(DOT_PRODUCT(vang,vang))>angvel_tol
2014 160 : IF (DOT_PRODUCT(vang, vang) > (angvel_tol*angvel_tol)) THEN
2015 2 : CALL subtract_vang(particles%els, is_fixed, rcom, vang)
2016 :
2017 : ! Rescale velocities after removal
2018 2 : temp_old = md_ener%temp_part/kelvin
2019 2 : CALL scale_velocity(subsys, md_ener, temp_old, 0.0_dp, iw)
2020 2 : CALL compute_vang(particles%els, is_fixed, rcom, vang_new)
2021 2 : IF (iw > 0) THEN
2022 : WRITE (UNIT=iw, FMT="(T2,A,T30,3(1X,F16.10))") &
2023 1 : 'MD_VEL| Old VANG [a.u.]', vang(1:3)
2024 : WRITE (UNIT=iw, FMT="(T2,A,T30,3(1X,F16.10))") &
2025 1 : 'MD_VEL| New VANG [a.u.]', vang_new(1:3)
2026 : END IF
2027 : END IF
2028 :
2029 40 : DEALLOCATE (is_fixed)
2030 :
2031 : CALL cp_print_key_finished_output(iw, logger, md_section, &
2032 80 : "PRINT%PROGRAM_RUN_INFO")
2033 : END IF
2034 : END IF
2035 :
2036 40248 : CALL timestop(handle)
2037 80496 : END SUBROUTINE angvel_control
2038 :
2039 : ! **************************************************************************************************
2040 : !> \brief Initialize Velocities for MD runs
2041 : !> \param force_env ...
2042 : !> \param simpar ...
2043 : !> \param globenv ...
2044 : !> \param md_env ...
2045 : !> \param md_section ...
2046 : !> \param constraint_section ...
2047 : !> \param write_binary_restart_file ...
2048 : !> \par History
2049 : !> Teodoro Laino - University of Zurich - 09.2007 [tlaino]
2050 : ! **************************************************************************************************
2051 3534 : SUBROUTINE setup_velocities(force_env, simpar, globenv, md_env, md_section, &
2052 : constraint_section, write_binary_restart_file)
2053 :
2054 : TYPE(force_env_type), POINTER :: force_env
2055 : TYPE(simpar_type), POINTER :: simpar
2056 : TYPE(global_environment_type), POINTER :: globenv
2057 : TYPE(md_environment_type), POINTER :: md_env
2058 : TYPE(section_vals_type), POINTER :: md_section, constraint_section
2059 : LOGICAL, INTENT(IN) :: write_binary_restart_file
2060 :
2061 : CHARACTER(LEN=*), PARAMETER :: routineN = 'setup_velocities'
2062 :
2063 : INTEGER :: handle, nconstraint, nconstraint_fixd
2064 : LOGICAL :: apply_cns0, shell_adiabatic, &
2065 : shell_present
2066 : TYPE(atomic_kind_list_type), POINTER :: atomic_kinds
2067 : TYPE(cell_type), POINTER :: cell
2068 : TYPE(cp_subsys_type), POINTER :: subsys
2069 : TYPE(molecule_kind_list_type), POINTER :: molecule_kinds
2070 : TYPE(mp_para_env_type), POINTER :: para_env
2071 : TYPE(particle_list_type), POINTER :: core_particles, particles, &
2072 : shell_particles
2073 1767 : TYPE(particle_type), DIMENSION(:), POINTER :: core_particle_set, particle_set, &
2074 1767 : shell_particle_set
2075 : TYPE(section_vals_type), POINTER :: force_env_section, print_section, &
2076 : subsys_section
2077 :
2078 1767 : CALL timeset(routineN, handle)
2079 :
2080 1767 : NULLIFY (atomic_kinds, cell, para_env, subsys, molecule_kinds, core_particles, particles)
2081 1767 : NULLIFY (shell_particles, core_particle_set, particle_set, shell_particle_set)
2082 1767 : NULLIFY (force_env_section, print_section, subsys_section)
2083 :
2084 1767 : print_section => section_vals_get_subs_vals(md_section, "PRINT")
2085 1767 : apply_cns0 = .FALSE.
2086 1767 : IF (simpar%constraint) THEN
2087 310 : CALL section_vals_val_get(constraint_section, "CONSTRAINT_INIT", l_val=apply_cns0)
2088 : END IF
2089 : ! Always initialize velocities and possibly restart them
2090 : CALL force_env_get(force_env, subsys=subsys, cell=cell, para_env=para_env, &
2091 1767 : force_env_section=force_env_section)
2092 1767 : subsys_section => section_vals_get_subs_vals(force_env_section, "SUBSYS")
2093 :
2094 : CALL cp_subsys_get(subsys, &
2095 : atomic_kinds=atomic_kinds, &
2096 : core_particles=core_particles, &
2097 : molecule_kinds=molecule_kinds, &
2098 : particles=particles, &
2099 1767 : shell_particles=shell_particles)
2100 :
2101 : CALL get_atomic_kind_set(atomic_kind_set=atomic_kinds%els, &
2102 : shell_present=shell_present, &
2103 1767 : shell_adiabatic=shell_adiabatic)
2104 :
2105 1767 : NULLIFY (core_particle_set)
2106 : NULLIFY (particle_set)
2107 1767 : NULLIFY (shell_particle_set)
2108 1767 : particle_set => particles%els
2109 :
2110 1767 : IF (shell_present .AND. shell_adiabatic) THEN
2111 : ! Constraints are not yet implemented for core-shell models generally
2112 : CALL get_molecule_kind_set(molecule_kind_set=molecule_kinds%els, &
2113 : nconstraint=nconstraint, &
2114 132 : nconstraint_fixd=nconstraint_fixd)
2115 132 : IF (nconstraint - nconstraint_fixd /= 0) &
2116 0 : CPABORT("Only the fixed atom constraint is implemented for core-shell models")
2117 : !MK CPPostcondition(.NOT.simpar%constraint,cp_failure_level,routineP,failure)
2118 132 : CPASSERT(ASSOCIATED(shell_particles))
2119 132 : CPASSERT(ASSOCIATED(core_particles))
2120 132 : shell_particle_set => shell_particles%els
2121 132 : core_particle_set => core_particles%els
2122 : END IF
2123 :
2124 : CALL initialize_velocities(simpar, &
2125 : particle_set, &
2126 : molecule_kinds=molecule_kinds, &
2127 : force_env=force_env, &
2128 : globenv=globenv, &
2129 : md_env=md_env, &
2130 : label="Velocities initialization", &
2131 : print_section=print_section, &
2132 : subsys_section=subsys_section, &
2133 : shell_present=(shell_present .AND. shell_adiabatic), &
2134 : shell_part=shell_particle_set, &
2135 : core_part=core_particle_set, &
2136 : force_rescaling=.FALSE., &
2137 : para_env=para_env, &
2138 3402 : write_binary_restart_file=write_binary_restart_file)
2139 :
2140 : ! Apply constraints if required and rescale velocities..
2141 1767 : IF (simpar%ensemble /= reftraj_ensemble) THEN
2142 1729 : IF (apply_cns0) THEN
2143 24 : CALL force_env_calc_energy_force(force_env, calc_force=.TRUE.)
2144 : CALL force_env_shake(force_env, &
2145 : shake_tol=simpar%shake_tol, &
2146 : log_unit=simpar%info_constraint, &
2147 : lagrange_mult=simpar%lagrange_multipliers, &
2148 : dump_lm=simpar%dump_lm, &
2149 24 : compold=.TRUE.)
2150 : CALL force_env_rattle(force_env, shake_tol=simpar%shake_tol, &
2151 : log_unit=simpar%info_constraint, lagrange_mult=simpar%lagrange_multipliers, &
2152 24 : dump_lm=simpar%dump_lm, reset=.TRUE.)
2153 24 : IF (simpar%do_respa) THEN
2154 : CALL force_env_calc_energy_force(force_env%sub_force_env(1)%force_env, &
2155 0 : calc_force=.TRUE.)
2156 : CALL force_env_shake(force_env%sub_force_env(1)%force_env, &
2157 : shake_tol=simpar%shake_tol, log_unit=simpar%info_constraint, &
2158 0 : lagrange_mult=simpar%lagrange_multipliers, dump_lm=simpar%dump_lm, compold=.TRUE.)
2159 : CALL force_env_rattle(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, reset=.TRUE.)
2162 : END IF
2163 : ! Reinitialize velocities rescaling properly after rattle
2164 24 : subsys_section => section_vals_get_subs_vals(force_env_section, "SUBSYS")
2165 24 : CALL update_subsys(subsys_section, force_env, .FALSE., write_binary_restart_file)
2166 : CALL initialize_velocities(simpar, &
2167 : particle_set, &
2168 : molecule_kinds=molecule_kinds, &
2169 : force_env=force_env, &
2170 : globenv=globenv, &
2171 : md_env=md_env, &
2172 : label="Re-Initializing velocities after applying constraints", &
2173 : print_section=print_section, &
2174 : subsys_section=subsys_section, &
2175 : shell_present=(shell_present .AND. shell_adiabatic), &
2176 : shell_part=shell_particle_set, &
2177 : core_part=core_particle_set, &
2178 : force_rescaling=.TRUE., &
2179 : para_env=para_env, &
2180 48 : write_binary_restart_file=write_binary_restart_file)
2181 : END IF
2182 : END IF
2183 :
2184 : ! Perform setup for a cascade run
2185 1767 : CALL initialize_cascade(simpar, particle_set, molecule_kinds, md_section)
2186 :
2187 1767 : CALL timestop(handle)
2188 :
2189 1767 : END SUBROUTINE setup_velocities
2190 :
2191 : ! **************************************************************************************************
2192 : !> \brief Perform the initialization for a cascade run
2193 : !> \param simpar ...
2194 : !> \param particle_set ...
2195 : !> \param molecule_kinds ...
2196 : !> \param md_section ...
2197 : !> \date 05.02.2012
2198 : !> \author Matthias Krack (MK)
2199 : !> \version 1.0
2200 : ! **************************************************************************************************
2201 1767 : SUBROUTINE initialize_cascade(simpar, particle_set, molecule_kinds, md_section)
2202 :
2203 : TYPE(simpar_type), POINTER :: simpar
2204 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
2205 : TYPE(molecule_kind_list_type), POINTER :: molecule_kinds
2206 : TYPE(section_vals_type), POINTER :: md_section
2207 :
2208 : CHARACTER(LEN=*), PARAMETER :: routineN = 'initialize_cascade'
2209 :
2210 : CHARACTER(len=2*default_string_length) :: line
2211 : INTEGER :: handle, iatom, ifixd, imolecule_kind, &
2212 : iparticle, iw, natom, nparticle
2213 1767 : INTEGER, ALLOCATABLE, DIMENSION(:) :: atom_index, is_fixed
2214 : LOGICAL :: init_cascade, is_ok, no_read_error
2215 : REAL(KIND=dp) :: ecom, ekin, energy, norm, temp, &
2216 : temperature
2217 1767 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: matom, weight
2218 1767 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: vatom
2219 : REAL(KIND=dp), DIMENSION(3) :: vcom
2220 : TYPE(atomic_kind_type), POINTER :: atomic_kind
2221 : TYPE(cp_logger_type), POINTER :: logger
2222 : TYPE(cp_sll_val_type), POINTER :: atom_list
2223 1767 : TYPE(fixd_constraint_type), DIMENSION(:), POINTER :: fixd_list
2224 1767 : TYPE(molecule_kind_type), DIMENSION(:), POINTER :: molecule_kind_set
2225 : TYPE(molecule_kind_type), POINTER :: molecule_kind
2226 : TYPE(section_vals_type), POINTER :: atom_list_section, cascade_section, &
2227 : print_section
2228 : TYPE(val_type), POINTER :: val
2229 :
2230 1767 : CALL timeset(routineN, handle)
2231 :
2232 1767 : NULLIFY (atom_list)
2233 1767 : NULLIFY (atom_list_section)
2234 1767 : NULLIFY (atomic_kind)
2235 1767 : NULLIFY (cascade_section)
2236 1767 : NULLIFY (fixd_list)
2237 1767 : NULLIFY (molecule_kind)
2238 1767 : NULLIFY (molecule_kind_set)
2239 1767 : NULLIFY (logger)
2240 1767 : NULLIFY (val)
2241 :
2242 1767 : logger => cp_get_default_logger()
2243 1767 : print_section => section_vals_get_subs_vals(md_section, "PRINT")
2244 1767 : iw = cp_print_key_unit_nr(logger, print_section, "PROGRAM_RUN_INFO", extension=".log")
2245 :
2246 1767 : cascade_section => section_vals_get_subs_vals(md_section, "CASCADE")
2247 1767 : CALL section_vals_val_get(cascade_section, "_SECTION_PARAMETERS_", l_val=init_cascade)
2248 :
2249 1767 : nparticle = SIZE(particle_set)
2250 :
2251 1767 : IF (init_cascade) THEN
2252 :
2253 2 : CALL section_vals_val_get(cascade_section, "ENERGY", r_val=energy)
2254 2 : IF (energy < 0.0_dp) &
2255 0 : CPABORT("Error occurred reading &CASCADE section: Negative energy found")
2256 :
2257 2 : IF (iw > 0) THEN
2258 1 : ekin = cp_unit_from_cp2k(energy, "keV")
2259 : WRITE (UNIT=iw, FMT="(/,T2,A,T61,F20.6)") &
2260 1 : "CASCADE| Energy [keV]", ekin
2261 : WRITE (UNIT=iw, FMT="(T2,A)") &
2262 1 : "CASCADE|"
2263 : END IF
2264 :
2265 : ! Read the atomic velocities given in the input file
2266 2 : atom_list_section => section_vals_get_subs_vals(cascade_section, "ATOM_LIST")
2267 2 : CALL section_vals_val_get(atom_list_section, "_DEFAULT_KEYWORD_", n_rep_val=natom)
2268 2 : CALL section_vals_list_get(atom_list_section, "_DEFAULT_KEYWORD_", list=atom_list)
2269 2 : IF (natom <= 0) &
2270 0 : CPABORT("Error occurred reading &CASCADE section: No atom list found")
2271 :
2272 2 : IF (iw > 0) THEN
2273 : WRITE (UNIT=iw, FMT="(T2,A,T11,A,3(11X,A),9X,A)") &
2274 1 : "CASCADE| ", "Atom index", "v(x)", "v(y)", "v(z)", "weight"
2275 : END IF
2276 :
2277 6 : ALLOCATE (atom_index(natom))
2278 6 : ALLOCATE (matom(natom))
2279 6 : ALLOCATE (vatom(3, natom))
2280 4 : ALLOCATE (weight(natom))
2281 :
2282 8 : DO iatom = 1, natom
2283 6 : is_ok = cp_sll_val_next(atom_list, val)
2284 6 : CALL val_get(val, c_val=line)
2285 : ! Read atomic index, velocity vector, and weight
2286 6 : no_read_error = .FALSE.
2287 6 : READ (UNIT=line, FMT=*, ERR=999) atom_index(iatom), vatom(1:3, iatom), weight(iatom)
2288 : no_read_error = .TRUE.
2289 : 999 IF (.NOT. no_read_error) &
2290 0 : CPABORT("Error occurred reading &CASCADE section. Last line read <"//TRIM(line)//">")
2291 6 : IF ((atom_index(iatom) <= 0) .OR. ((atom_index(iatom) > nparticle))) &
2292 0 : CPABORT("Error occurred reading &CASCADE section: Invalid atom index found")
2293 6 : IF (weight(iatom) < 0.0_dp) &
2294 0 : CPABORT("Error occurred reading &CASCADE section: Negative weight found")
2295 8 : IF (iw > 0) THEN
2296 : WRITE (UNIT=iw, FMT="(T2,A,I10,4(1X,F14.6))") &
2297 3 : "CASCADE| ", atom_index(iatom), vatom(1:3, iatom), weight(iatom)
2298 : END IF
2299 : END DO
2300 :
2301 : ! Normalise velocities and weights
2302 : norm = 0.0_dp
2303 8 : DO iatom = 1, natom
2304 6 : iparticle = atom_index(iatom)
2305 6 : IF (particle_set(iparticle)%shell_index /= 0) THEN
2306 0 : CPWARN("Warning: The primary knock-on atom is a core-shell atom")
2307 : END IF
2308 6 : atomic_kind => particle_set(iparticle)%atomic_kind
2309 6 : CALL get_atomic_kind(atomic_kind=atomic_kind, mass=matom(iatom))
2310 8 : norm = norm + matom(iatom)*weight(iatom)
2311 : END DO
2312 8 : weight(:) = matom(:)*weight(:)*energy/norm
2313 8 : DO iatom = 1, natom
2314 24 : norm = SQRT(DOT_PRODUCT(vatom(1:3, iatom), vatom(1:3, iatom)))
2315 26 : vatom(1:3, iatom) = vatom(1:3, iatom)/norm
2316 : END DO
2317 :
2318 2 : IF (iw > 0) THEN
2319 : WRITE (UNIT=iw, FMT="(T2,A)") &
2320 1 : "CASCADE|", &
2321 1 : "CASCADE| Normalised velocities and additional kinetic energy [keV]", &
2322 2 : "CASCADE|"
2323 : WRITE (UNIT=iw, FMT="(T2,A,T11,A,3(11X,A),9X,A)") &
2324 1 : "CASCADE| ", "Atom index", "v(x)", "v(y)", "v(z)", "E(kin)"
2325 4 : DO iatom = 1, natom
2326 3 : ekin = cp_unit_from_cp2k(weight(iatom), "keV")
2327 : WRITE (UNIT=iw, FMT="(T2,A,I10,4(1X,F14.6))") &
2328 4 : "CASCADE| ", atom_index(iatom), vatom(1:3, iatom), ekin
2329 : END DO
2330 : END IF
2331 :
2332 : ! Apply velocity modifications
2333 8 : DO iatom = 1, natom
2334 6 : iparticle = atom_index(iatom)
2335 : particle_set(iparticle)%v(:) = particle_set(iparticle)%v(:) + &
2336 26 : SQRT(2.0_dp*weight(iatom)/matom(iatom))*vatom(1:3, iatom)
2337 : END DO
2338 :
2339 2 : DEALLOCATE (atom_index)
2340 2 : DEALLOCATE (matom)
2341 2 : DEALLOCATE (vatom)
2342 2 : DEALLOCATE (weight)
2343 :
2344 6 : IF (iw > 0) THEN
2345 : ! Build a list of all fixed atoms (if any)
2346 3 : ALLOCATE (is_fixed(nparticle))
2347 1 : is_fixed = use_perd_none
2348 1 : molecule_kind_set => molecule_kinds%els
2349 2 : DO imolecule_kind = 1, molecule_kinds%n_els
2350 1 : molecule_kind => molecule_kind_set(imolecule_kind)
2351 1 : CALL get_molecule_kind(molecule_kind=molecule_kind, fixd_list=fixd_list)
2352 2 : IF (ASSOCIATED(fixd_list)) THEN
2353 0 : DO ifixd = 1, SIZE(fixd_list)
2354 0 : IF (.NOT. fixd_list(ifixd)%restraint%active) is_fixed(fixd_list(ifixd)%fixd) = fixd_list(ifixd)%itype
2355 : END DO
2356 : END IF
2357 : END DO
2358 : ! Compute vcom, ecom and ekin for printout
2359 1 : CALL compute_vcom(particle_set, is_fixed, vcom, ecom)
2360 1 : ekin = compute_ekin(particle_set) - ecom
2361 1 : IF (simpar%nfree == 0) THEN
2362 0 : CPASSERT(ekin == 0.0_dp)
2363 0 : temp = 0.0_dp
2364 : ELSE
2365 1 : temp = 2.0_dp*ekin/REAL(simpar%nfree, KIND=dp)
2366 : END IF
2367 1 : temperature = cp_unit_from_cp2k(temp, "K")
2368 : WRITE (UNIT=iw, FMT="(T2,A)") &
2369 1 : "CASCADE|"
2370 : WRITE (UNIT=iw, FMT="(T2,A,T61,F20.6)") &
2371 1 : "CASCADE| Temperature after cascade initialization [K]", temperature
2372 : WRITE (UNIT=iw, FMT="(T2,A,T30,3(1X,ES16.8))") &
2373 1 : "CASCADE| COM velocity", vcom(1:3)
2374 : !MK ! compute and log rcom and vang if not periodic
2375 : !MK CALL force_env_get(force_env,cell=cell)
2376 : !MK IF (SUM(cell%perd(1:3)) == 0) THEN
2377 : !MK CALL compute_rcom(particle_set,is_fixed,rcom)
2378 : !MK CALL compute_vang(particle_set,is_fixed,rcom,vang)
2379 : !MK WRITE (iw, '( A, T21, F20.12 , F20.12 , F20.12 )' ) ' COM position:',rcom(1:3)
2380 : !MK WRITE (iw, '( A, T21, F20.12 , F20.12 , F20.12 )' ) ' Angular velocity:',vang(1:3)
2381 : !MK END IF
2382 2 : DEALLOCATE (is_fixed)
2383 : END IF
2384 :
2385 : END IF
2386 :
2387 1767 : CALL cp_print_key_finished_output(iw, logger, print_section, "PROGRAM_RUN_INFO")
2388 :
2389 1767 : CALL timestop(handle)
2390 :
2391 3534 : END SUBROUTINE initialize_cascade
2392 :
2393 : END MODULE md_vel_utils
|