LCOV - code coverage report
Current view: top level - src/motion - md_vel_utils.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:4dc10b3) Lines: 840 932 90.1 %
Date: 2024-11-21 06:45:46 Functions: 28 28 100.0 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2024 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_type, use_perd_none, use_perd_x, use_perd_xy, use_perd_xyz, use_perd_xz, use_perd_y, &
      26             :         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         105 :    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         105 :       rcom(:) = 0.0_dp
     114         105 :       denom = 0.0_dp
     115        1242 :       DO i = 1, SIZE(part)
     116        1137 :          atomic_kind => part(i)%atomic_kind
     117        1137 :          CALL get_atomic_kind(atomic_kind=atomic_kind, mass=mass)
     118        1242 :          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        1137 :             rcom(1) = rcom(1) + part(i)%r(1)*mass
     121        1137 :             rcom(2) = rcom(2) + part(i)%r(2)*mass
     122        1137 :             rcom(3) = rcom(3) + part(i)%r(3)*mass
     123        1137 :             denom = denom + mass
     124             :          END SELECT
     125             :       END DO
     126         420 :       rcom = rcom/denom
     127             : 
     128         105 :    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        3590 :    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        3590 :       vcom = 0.0_dp
     152        3590 :       denom = 0.0_dp
     153      744304 :       DO i = 1, SIZE(part)
     154      740714 :          atomic_kind => part(i)%atomic_kind
     155      740714 :          CALL get_atomic_kind(atomic_kind=atomic_kind, mass=mass)
     156      744304 :          IF (mass .NE. 0.0) THEN
     157     1474060 :             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      734672 :                vcom(1) = vcom(1) + part(i)%v(1)*mass
     160      734672 :                vcom(2) = vcom(2) + part(i)%v(2)*mass
     161      734672 :                vcom(3) = vcom(3) + part(i)%v(3)*mass
     162      739388 :                denom = denom + mass
     163             :             END SELECT
     164             :          END IF
     165             :       END DO
     166       14360 :       vcom = vcom/denom
     167        3590 :       IF (PRESENT(ecom)) THEN
     168        4360 :          ecom = 0.5_dp*denom*SUM(vcom*vcom)
     169             :       END IF
     170             : 
     171        3590 :    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        3856 :    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        3856 :       NULLIFY (atomic_kind)
     222        3856 :       ekin = 0.0_dp
     223        3856 :       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      744110 :          DO i = 1, SIZE(part)
     233      740522 :             atomic_kind => part(i)%atomic_kind
     234      740522 :             CALL get_atomic_kind(atomic_kind=atomic_kind, mass=mass)
     235     2965676 :             ekin = ekin + 0.5_dp*mass*SUM(part(i)%v(:)*part(i)%v(:))
     236             :          END DO
     237             :       END IF
     238             : 
     239        3856 :    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        2528 :    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        2528 :       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        2522 :       ELSEIF (PRESENT(nfree)) THEN
     273           0 :          my_ireg = 0
     274           0 :          my_nfree = nfree
     275           0 :          my_temp = simpar%temp_ext
     276             :       ELSE
     277        2522 :          my_ireg = 0
     278        2522 :          my_nfree = simpar%nfree
     279        2522 :          my_temp = simpar%temp_ext
     280             :       END IF
     281        2528 :       IF (my_nfree /= 0) THEN
     282        2516 :          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        2528 :       ekin = ekin*factor
     290        2528 :       factor = SQRT(factor)
     291        2528 :       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      444278 :          DO i = 1, SIZE(part)
     297     1769546 :             part(i)%v(:) = factor*part(i)%v(:)
     298             :          END DO
     299        2522 :          IF (PRESENT(vcom)) THEN
     300          96 :             vcom = factor*vcom
     301             :          END IF
     302             :       END IF
     303             : 
     304        2528 :    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        2500 :    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      442578 :       DO i = 1, SIZE(part)
     370        2500 :          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     1744814 :             part(i)%v(:) = part(i)%v(:) - vcom(:)
     388             :          END SELECT
     389             :       END DO
     390        2500 :    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         107 :    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         107 :       NULLIFY (atomic_kind)
     416         107 :       mang(:) = 0.0_dp
     417         107 :       iner(:, :) = 0.0_dp
     418        1272 :       DO i = 1, SIZE(part)
     419             :          ! compute angular momentum and inertia tensor
     420         107 :          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        4660 :             r(:) = part(i)%r(:) - rcom(:)
     423        1165 :             atomic_kind => part(i)%atomic_kind
     424        1165 :             CALL get_atomic_kind(atomic_kind=atomic_kind, mass=mass)
     425        1165 :             mang(1) = mang(1) + mass*(r(2)*part(i)%v(3) - r(3)*part(i)%v(2))
     426        1165 :             mang(2) = mang(2) + mass*(r(3)*part(i)%v(1) - r(1)*part(i)%v(3))
     427        1165 :             mang(3) = mang(3) + mass*(r(1)*part(i)%v(2) - r(2)*part(i)%v(1))
     428             : 
     429        1165 :             iner(1, 1) = iner(1, 1) + mass*(r(2)*r(2) + r(3)*r(3))
     430        1165 :             iner(2, 2) = iner(2, 2) + mass*(r(3)*r(3) + r(1)*r(1))
     431        1165 :             iner(3, 3) = iner(3, 3) + mass*(r(1)*r(1) + r(2)*r(2))
     432             : 
     433        1165 :             iner(1, 2) = iner(1, 2) - mass*r(1)*r(2)
     434        1165 :             iner(2, 3) = iner(2, 3) - mass*r(2)*r(3)
     435        2330 :             iner(3, 1) = iner(3, 1) - mass*r(3)*r(1)
     436             :          END SELECT
     437             :       END DO
     438         107 :       iner(2, 1) = iner(1, 2)
     439         107 :       iner(3, 2) = iner(2, 3)
     440         107 :       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         107 :       CALL diamat_all(iner, evals)
     446             : 
     447         107 :       vang(:) = 0.0_dp
     448         428 :       DO i = 1, 3
     449         428 :          IF (evals(i) > 0.0_dp) THEN
     450        1240 :             proj = SUM(iner(:, i)*mang)/evals(i)
     451         310 :             vang(1) = vang(1) + proj*iner(1, i)
     452         310 :             vang(2) = vang(2) + proj*iner(2, i)
     453         310 :             vang(3) = vang(3) + proj*iner(3, i)
     454             :          END IF
     455             :       END DO
     456             : 
     457         107 :    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        1808 :    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        1808 :       TYPE(fixd_constraint_type), DIMENSION(:), POINTER  :: fixd_list
     570        1808 :       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        1808 :       CALL timeset(routineN, handle)
     575             : 
     576             :       ! Initializing parameters
     577        1808 :       natoms = SIZE(part)
     578        1808 :       NULLIFY (atomic_kind, fixd_list, logger, molecule_kind)
     579        1808 :       NULLIFY (molecule_kind_set)
     580             : 
     581             :       ! Logging
     582        1808 :       logger => cp_get_default_logger()
     583        1808 :       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        5424 :       ALLOCATE (is_fixed(natoms))
     587             : 
     588      489438 :       is_fixed = use_perd_none
     589        1808 :       molecule_kind_set => molecule_kinds%els
     590       61864 :       DO imolecule_kind = 1, molecule_kinds%n_els
     591       60056 :          molecule_kind => molecule_kind_set(imolecule_kind)
     592       60056 :          CALL get_molecule_kind(molecule_kind=molecule_kind, fixd_list=fixd_list)
     593       61864 :          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        1808 :       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        1808 :                                  shell_present, shell_part, core_part, force_rescaling, para_env, is_fixed, success)
     614        1808 :       IF (.NOT. success) THEN
     615        3082 :          SELECT CASE (simpar%initialization_method)
     616             :          CASE (md_init_default)
     617             :             CALL generate_velocities(simpar, part, force_env, globenv, md_env, shell_present, &
     618        1540 :                                      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        1544 :             CALL update_subsys(subsys_section, force_env, .FALSE., write_binary_restart_file)
     635             :          END SELECT
     636             :       END IF
     637             : 
     638        1808 :       IF (iw > 0) THEN
     639             :          WRITE (iw, '(/,T2,A)') &
     640         823 :             'MD_VEL| '//TRIM(ADJUSTL(label))
     641             :          ! Recompute vcom, ecom and ekin for IO
     642         823 :          CALL compute_vcom(part, is_fixed, vcom, ecom)
     643         823 :          ekin = compute_ekin(part) - ecom
     644         823 :          IF (simpar%nfree == 0) THEN
     645           6 :             CPASSERT(ekin == 0.0_dp)
     646           6 :             temp = 0.0_dp
     647             :          ELSE
     648         817 :             temp = 2.0_dp*ekin/REAL(simpar%nfree, KIND=dp)
     649             :          END IF
     650         823 :          tmp_r1 = cp_unit_from_cp2k(temp, "K")
     651             :          WRITE (iw, '(T2,A,T61,F20.6)') &
     652         823 :             'MD_VEL| Initial temperature [K]', tmp_r1
     653             :          WRITE (iw, '(T2,A,T30,3(1X,F16.10))') &
     654         823 :             'MD_VEL| COM velocity', vcom(1:3)
     655             : 
     656             :          ! compute and log rcom and vang if not periodic
     657         823 :          CALL force_env_get(force_env, cell=cell)
     658        3292 :          IF (SUM(cell%perd(1:3)) == 0) THEN
     659          61 :             CALL compute_rcom(part, is_fixed, rcom)
     660          61 :             CALL compute_vang(part, is_fixed, rcom, vang)
     661             :             WRITE (iw, '(T2,A,T30,3(1X,F16.10))') &
     662          61 :                'MD_VEL| COM position', rcom(1:3)
     663             :             WRITE (iw, '(T2,A,T30,3(1X,F16.10))') &
     664          61 :                'MD_VEL| Angular velocity', vang(1:3)
     665             :          END IF
     666             :       END IF
     667             : 
     668        1808 :       DEALLOCATE (is_fixed)
     669        1808 :       CALL cp_print_key_finished_output(iw, logger, print_section, "PROGRAM_RUN_INFO")
     670        1808 :       CALL timestop(handle)
     671             : 
     672        3616 :    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       12656 :    SUBROUTINE read_input_velocities(simpar, part, force_env, md_env, subsys_section, &
     691        1808 :                                     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        1808 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: vel
     710             :       TYPE(atomic_kind_type), POINTER                    :: atomic_kind
     711             :       TYPE(cp_sll_val_type), POINTER                     :: atom_list, core_list, shell_list
     712             :       TYPE(section_vals_type), POINTER                   :: atomvel_section, corevel_section, &
     713             :                                                             shellvel_section
     714             :       TYPE(shell_kind_type), POINTER                     :: shell
     715             :       TYPE(thermal_regions_type), POINTER                :: thermal_regions
     716             :       TYPE(val_type), POINTER                            :: val
     717             : 
     718             : ! Initializing parameters
     719             : 
     720        1808 :       success = .FALSE.
     721        1808 :       natoms = SIZE(part)
     722        1808 :       atomvel_read = .FALSE.
     723        1808 :       corevel_read = .FALSE.
     724        1808 :       shellvel_read = .FALSE.
     725        1808 :       NULLIFY (vel, atomic_kind, atom_list, core_list, shell_list)
     726        1808 :       NULLIFY (atomvel_section, shellvel_section, corevel_section)
     727        1808 :       NULLIFY (shell, thermal_regions, val)
     728             : 
     729             :       ! Core-Shell Model
     730        1808 :       nshell = 0
     731        1808 :       IF (shell_present) THEN
     732         132 :          CPASSERT(ASSOCIATED(core_part))
     733         132 :          CPASSERT(ASSOCIATED(shell_part))
     734         132 :          nshell = SIZE(shell_part)
     735             :       END IF
     736             : 
     737        1808 :       atomvel_section => section_vals_get_subs_vals(subsys_section, "VELOCITY")
     738        1808 :       shellvel_section => section_vals_get_subs_vals(subsys_section, "SHELL_VELOCITY")
     739        1808 :       corevel_section => section_vals_get_subs_vals(subsys_section, "CORE_VELOCITY")
     740             : 
     741             :       ! Read or initialize the particle velocities
     742        1808 :       CALL section_vals_get(atomvel_section, explicit=atomvel_explicit)
     743        1808 :       CALL section_vals_get(shellvel_section, explicit=shellvel_explicit)
     744        1808 :       CALL section_vals_get(corevel_section, explicit=corevel_explicit)
     745        1808 :       CPASSERT(shellvel_explicit .EQV. corevel_explicit)
     746             : 
     747             :       CALL read_binary_velocities("", part, force_env%root_section, para_env, &
     748        1808 :                                   subsys_section, atomvel_read)
     749             :       CALL read_binary_velocities("SHELL", shell_part, force_env%root_section, para_env, &
     750        1808 :                                   subsys_section, shellvel_read)
     751             :       CALL read_binary_velocities("CORE", core_part, force_env%root_section, para_env, &
     752        1808 :                                   subsys_section, corevel_read)
     753             : 
     754        1808 :       IF (.NOT. (atomvel_explicit .OR. atomvel_read)) RETURN
     755         266 :       success = .TRUE.
     756             : 
     757         266 :       IF (.NOT. atomvel_read) THEN
     758             :          ! Read the atom velocities if explicitly given in the input file
     759         220 :          CALL section_vals_list_get(atomvel_section, "_DEFAULT_KEYWORD_", list=atom_list)
     760       52950 :          DO i = 1, natoms
     761       52730 :             is_ok = cp_sll_val_next(atom_list, val)
     762       52730 :             CALL val_get(val, r_vals=vel)
     763      369330 :             part(i)%v = vel
     764             :          END DO
     765             :       END IF
     766       57412 :       DO i = 1, natoms
     767         266 :          SELECT CASE (is_fixed(i))
     768             :          CASE (use_perd_x)
     769           0 :             part(i)%v(1) = 0.0_dp
     770             :          CASE (use_perd_y)
     771           0 :             part(i)%v(2) = 0.0_dp
     772             :          CASE (use_perd_z)
     773           0 :             part(i)%v(3) = 0.0_dp
     774             :          CASE (use_perd_xy)
     775           0 :             part(i)%v(1) = 0.0_dp
     776           0 :             part(i)%v(2) = 0.0_dp
     777             :          CASE (use_perd_xz)
     778           0 :             part(i)%v(1) = 0.0_dp
     779           0 :             part(i)%v(3) = 0.0_dp
     780             :          CASE (use_perd_yz)
     781           0 :             part(i)%v(2) = 0.0_dp
     782           0 :             part(i)%v(3) = 0.0_dp
     783             :          CASE (use_perd_xyz)
     784       57224 :             part(i)%v = 0.0_dp
     785             :          END SELECT
     786             :       END DO
     787         266 :       IF (shell_present) THEN
     788          48 :          IF (shellvel_explicit) THEN
     789             :             ! If the atoms positions are given (?) and core and shell velocities are
     790             :             ! present in the input, read the latter.
     791          24 :             CALL section_vals_list_get(shellvel_section, "_DEFAULT_KEYWORD_", list=shell_list)
     792          24 :             CALL section_vals_list_get(corevel_section, "_DEFAULT_KEYWORD_", list=core_list)
     793        2328 :             DO i = 1, nshell
     794        2304 :                is_ok = cp_sll_val_next(shell_list, val)
     795        2304 :                CALL val_get(val, r_vals=vel)
     796       16128 :                shell_part(i)%v = vel
     797        2304 :                is_ok = cp_sll_val_next(core_list, val)
     798        2304 :                CALL val_get(val, r_vals=vel)
     799       16152 :                core_part(i)%v = vel
     800             :             END DO
     801             :          ELSE
     802          24 :             IF (.NOT. (shellvel_read .AND. corevel_read)) THEN
     803             :                ! Otherwise, just copy atom velocties into shell and core velocities.
     804           8 :                CALL clone_core_shell_vel(part, shell_part, core_part)
     805             :             END IF
     806             :          END IF
     807             :       END IF
     808             : 
     809             :       ! compute vcom, ecom and ekin
     810         266 :       CALL compute_vcom(part, is_fixed, vcom, ecom)
     811         266 :       ekin = compute_ekin(part) - ecom
     812             : 
     813         266 :       IF (simpar%do_thermal_region) THEN
     814          12 :          CALL get_md_env(md_env, thermal_regions=thermal_regions)
     815          12 :          IF (ASSOCIATED(thermal_regions)) THEN
     816          12 :             rescale_regions = thermal_regions%force_rescaling
     817             :          END IF
     818             :       ELSE
     819             :          rescale_regions = .FALSE.
     820             :       END IF
     821         266 :       IF (simpar%nfree /= 0 .AND. (force_rescaling .OR. rescale_regions)) THEN
     822          24 :          IF (simpar%do_thermal_region) THEN
     823           0 :             CALL rescale_vel_region(part, md_env, simpar)
     824             :          ELSE
     825          24 :             CALL rescale_vel(part, simpar, ekin, vcom=vcom)
     826             :          END IF
     827             : 
     828             :          ! After rescaling, the core and shell velocities must also adapt.
     829        1894 :          DO i = 1, natoms
     830        1870 :             shell_index = part(i)%shell_index
     831        2136 :             IF (shell_present .AND. shell_index /= 0) THEN
     832           0 :                atomic_kind => part(i)%atomic_kind
     833           0 :                CALL get_atomic_kind(atomic_kind=atomic_kind, mass=mass, shell=shell)
     834           0 :                fac_masss = shell%mass_shell/mass
     835           0 :                fac_massc = shell%mass_core/mass
     836           0 :                vs = shell_part(shell_index)%v
     837           0 :                vc = core_part(shell_index)%v
     838             : 
     839           0 :                shell_part(shell_index)%v(1) = part(i)%v(1) + fac_massc*(vs(1) - vc(1))
     840           0 :                shell_part(shell_index)%v(2) = part(i)%v(2) + fac_massc*(vs(2) - vc(2))
     841           0 :                shell_part(shell_index)%v(3) = part(i)%v(3) + fac_massc*(vs(3) - vc(3))
     842           0 :                core_part(shell_index)%v(1) = part(i)%v(1) + fac_masss*(vc(1) - vs(1))
     843           0 :                core_part(shell_index)%v(2) = part(i)%v(2) + fac_masss*(vc(2) - vs(2))
     844           0 :                core_part(shell_index)%v(3) = part(i)%v(3) + fac_masss*(vc(3) - vs(3))
     845             :             END IF
     846             :          END DO
     847             :       END IF
     848        1808 :    END SUBROUTINE read_input_velocities
     849             : 
     850             : ! **************************************************************************************************
     851             : !> \brief Initializing velocities AND positions randomly on all processors, based on vibrational
     852             : !>        modes of the system, so that the starting coordinates are already very close to
     853             : !>        canonical ensumble corresponding to temperature of a head bath.
     854             : !> \param simpar          : MD simulation parameters
     855             : !> \param particles       : global array of all particles
     856             : !> \param md_section      : MD input subsection
     857             : !> \param vib_section     : vibrational analysis input section
     858             : !> \param force_env       : force environment container
     859             : !> \param global_env      : global environment container
     860             : !> \param shell_present   : if core-shell model is used
     861             : !> \param shell_particles : global array of all shell particles in shell model
     862             : !> \param core_particles  : global array of all core particles in shell model
     863             : !> \param is_fixed        : array of size of total number of atoms, that determines if any
     864             : !>                          cartesian components are fixed
     865             : !> \author CJM,MK,Toon Verstraelen <Toon.Verstraelen@gmail.com>, Ole Schuett
     866             : ! **************************************************************************************************
     867           2 :    SUBROUTINE generate_coords_vels_vib(simpar, &
     868             :                                        particles, &
     869             :                                        md_section, &
     870             :                                        vib_section, &
     871             :                                        force_env, &
     872             :                                        global_env, &
     873             :                                        shell_present, &
     874             :                                        shell_particles, &
     875             :                                        core_particles, &
     876           2 :                                        is_fixed)
     877             :       TYPE(simpar_type), POINTER                         :: simpar
     878             :       TYPE(particle_type), DIMENSION(:), POINTER         :: particles
     879             :       TYPE(section_vals_type), POINTER                   :: md_section, vib_section
     880             :       TYPE(force_env_type), POINTER                      :: force_env
     881             :       TYPE(global_environment_type), POINTER             :: global_env
     882             :       LOGICAL, INTENT(IN)                                :: shell_present
     883             :       TYPE(particle_type), DIMENSION(:), POINTER         :: shell_particles, core_particles
     884             :       INTEGER, DIMENSION(:), INTENT(IN)                  :: is_fixed
     885             : 
     886             :       INTEGER                                            :: dof, fixed_dof, iatom, ii, imode, &
     887             :                                                             my_dof, natoms, shell_index
     888             :       REAL(KIND=dp)                                      :: Erand, mass, my_phase, ratio, temperature
     889             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: eigenvalues, phase, random
     890           2 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: dr, eigenvectors
     891             :       TYPE(atomic_kind_type), POINTER                    :: atomic_kind
     892             :       TYPE(mp_para_env_type), POINTER                    :: para_env
     893           2 :       TYPE(rng_stream_type), ALLOCATABLE                 :: random_stream
     894             : 
     895           2 :       CALL cite_reference(West2006)
     896           2 :       natoms = SIZE(particles)
     897           2 :       temperature = simpar%temp_ext
     898           2 :       my_dof = 3*natoms
     899           6 :       ALLOCATE (eigenvalues(my_dof))
     900           8 :       ALLOCATE (eigenvectors(my_dof, my_dof))
     901           4 :       ALLOCATE (phase(my_dof))
     902           4 :       ALLOCATE (random(my_dof))
     903           6 :       ALLOCATE (dr(3, natoms))
     904           2 :       CALL force_env_get(force_env=force_env, para_env=para_env)
     905             :       ! read vibration modes
     906             :       CALL read_vib_eigs_unformatted(md_section, &
     907             :                                      vib_section, &
     908             :                                      para_env, &
     909             :                                      dof, &
     910             :                                      eigenvalues, &
     911           2 :                                      eigenvectors)
     912           2 :       IF (my_dof .NE. dof) THEN
     913             :          CALL cp_abort(__LOCATION__, &
     914             :                        "number of degrees of freedom in vibrational analysis data "// &
     915           0 :                        "do not match total number of cartesian degrees of freedom")
     916             :       END IF
     917             :       ! read phases
     918           2 :       CALL section_vals_val_get(md_section, "INITIAL_VIBRATION%PHASE", r_val=my_phase)
     919           2 :       my_phase = MIN(1.0_dp, my_phase)
     920             :       ! generate random numbers
     921           2 :       random_stream = rng_stream_type(name="MD_INIT_VIB", distribution_type=UNIFORM)
     922           2 :       CALL random_stream%fill(random)
     923           2 :       IF (my_phase .LT. 0.0_dp) THEN
     924           0 :          CALL random_stream%fill(phase)
     925             :       ELSE
     926          20 :          phase = my_phase
     927             :       END IF
     928           2 :       DEALLOCATE (random_stream)
     929             : 
     930             :       ! the first three modes are acoustic with zero frequencies,
     931             :       ! exclude these from considerations
     932           2 :       my_dof = dof - 3
     933             :       ! randomly selects energy from distribution about kT, all
     934             :       ! energies are scaled so that the sum over vibration modes gives
     935             :       ! exactly my_dof*kT. Note that k = 1.0 in atomic units
     936           2 :       Erand = 0.0_dp
     937          14 :       DO imode = 4, dof
     938          14 :          Erand = Erand - temperature*LOG(1.0_dp - random(imode))
     939             :       END DO
     940             :       ! need to take into account of fixed constraints too
     941           2 :       fixed_dof = 0
     942           8 :       DO iatom = 1, natoms
     943           2 :          SELECT CASE (is_fixed(iatom))
     944             :          CASE (use_perd_x, use_perd_y, use_perd_z)
     945           0 :             fixed_dof = fixed_dof + 1
     946             :          CASE (use_perd_xy, use_perd_xz, use_perd_yz)
     947           0 :             fixed_dof = fixed_dof + 2
     948             :          CASE (use_perd_xyz)
     949           6 :             fixed_dof = fixed_dof + 3
     950             :          END SELECT
     951             :       END DO
     952           2 :       my_dof = my_dof - fixed_dof
     953           2 :       ratio = REAL(my_dof, KIND=dp)*temperature/Erand
     954             :       ! update  velocities AND positions
     955           8 :       DO iatom = 1, natoms
     956           6 :          atomic_kind => particles(iatom)%atomic_kind
     957           6 :          CALL get_atomic_kind(atomic_kind=atomic_kind, mass=mass)
     958           8 :          SELECT CASE (is_fixed(iatom))
     959             :          CASE (use_perd_x)
     960           0 :             DO ii = 2, 3
     961             :                dr(ii, iatom) = dr_from_vib_data(iatom, ii, mass, temperature, eigenvalues, &
     962           0 :                                                 eigenvectors, random, phase, dof, ratio)
     963             :                particles(iatom)%v(ii) = dv_from_vib_data(iatom, ii, mass, temperature, &
     964             :                                                          eigenvectors, random, phase, dof, &
     965           0 :                                                          ratio)
     966             :             END DO
     967             :          CASE (use_perd_y)
     968           0 :             DO ii = 1, 3, 2
     969             :                dr(ii, iatom) = dr_from_vib_data(iatom, ii, mass, temperature, eigenvalues, &
     970           0 :                                                 eigenvectors, random, phase, dof, ratio)
     971             :                particles(iatom)%v(ii) = dv_from_vib_data(iatom, ii, mass, temperature, &
     972             :                                                          eigenvectors, random, phase, dof, &
     973           0 :                                                          ratio)
     974             :             END DO
     975             :          CASE (use_perd_z)
     976           0 :             DO ii = 1, 2
     977             :                dr(ii, iatom) = dr_from_vib_data(iatom, ii, mass, temperature, eigenvalues, &
     978           0 :                                                 eigenvectors, random, phase, dof, ratio)
     979             :                particles(iatom)%v(ii) = dv_from_vib_data(iatom, ii, mass, temperature, &
     980             :                                                          eigenvectors, random, phase, dof, &
     981           0 :                                                          ratio)
     982             :             END DO
     983             :          CASE (use_perd_xy)
     984             :             dr(3, iatom) = dr_from_vib_data(iatom, 3, mass, temperature, eigenvalues, &
     985           0 :                                             eigenvectors, random, phase, dof, ratio)
     986             :             particles(iatom)%v(3) = dv_from_vib_data(iatom, 3, mass, temperature, &
     987             :                                                      eigenvectors, random, phase, dof, &
     988           0 :                                                      ratio)
     989             :          CASE (use_perd_xz)
     990             :             dr(2, iatom) = dr_from_vib_data(iatom, 2, mass, temperature, eigenvalues, &
     991           0 :                                             eigenvectors, random, phase, dof, ratio)
     992             :             particles(iatom)%v(2) = dv_from_vib_data(iatom, 2, mass, temperature, &
     993             :                                                      eigenvectors, random, phase, dof, &
     994           0 :                                                      ratio)
     995             :          CASE (use_perd_yz)
     996             :             dr(1, iatom) = dr_from_vib_data(iatom, 1, mass, temperature, eigenvalues, &
     997           0 :                                             eigenvectors, random, phase, dof, ratio)
     998             :             particles(iatom)%v(1) = dv_from_vib_data(iatom, 1, mass, temperature, &
     999             :                                                      eigenvectors, random, phase, dof, &
    1000           0 :                                                      ratio)
    1001             :          CASE (use_perd_none)
    1002          24 :             DO ii = 1, 3
    1003             :                dr(ii, iatom) = dr_from_vib_data(iatom, ii, mass, temperature, eigenvalues, &
    1004          18 :                                                 eigenvectors, random, phase, dof, ratio)
    1005             :                particles(iatom)%v(ii) = dv_from_vib_data(iatom, ii, mass, temperature, &
    1006             :                                                          eigenvectors, random, phase, dof, &
    1007          24 :                                                          ratio)
    1008             :             END DO
    1009             :          END SELECT
    1010             :       END DO ! iatom
    1011             :       ! free memory
    1012           2 :       DEALLOCATE (eigenvalues)
    1013           2 :       DEALLOCATE (eigenvectors)
    1014           2 :       DEALLOCATE (phase)
    1015           2 :       DEALLOCATE (random)
    1016             :       ! update particle coordinates
    1017           8 :       DO iatom = 1, natoms
    1018          26 :          particles(iatom)%r(:) = particles(iatom)%r(:) + dr(:, iatom)
    1019             :       END DO
    1020             :       ! update core-shell model coordinates
    1021           2 :       IF (shell_present) THEN
    1022             :          ! particles have moved, and for core-shell model this means
    1023             :          ! the cores and shells must also move by the same amount. The
    1024             :          ! shell positions will then be optimised if needed
    1025           0 :          shell_index = particles(iatom)%shell_index
    1026           0 :          IF (shell_index .NE. 0) THEN
    1027             :             core_particles(shell_index)%r(:) = core_particles(shell_index)%r(:) + &
    1028           0 :                                                dr(:, iatom)
    1029             :             shell_particles(shell_index)%r(:) = shell_particles(shell_index)%r(:) + &
    1030           0 :                                                 dr(:, iatom)
    1031             :          END IF
    1032             :          CALL optimize_shell_core(force_env, &
    1033             :                                   particles, &
    1034             :                                   shell_particles, &
    1035             :                                   core_particles, &
    1036           0 :                                   global_env)
    1037             :       END IF
    1038             :       ! cleanup
    1039           2 :       DEALLOCATE (dr)
    1040           4 :    END SUBROUTINE generate_coords_vels_vib
    1041             : 
    1042             : ! **************************************************************************************************
    1043             : !> \brief calculates componbent of initial velocity of an atom from vibreational modes
    1044             : !> \param iatom        : global atomic index
    1045             : !> \param icart        : cartesian index (1, 2 or 3)
    1046             : !> \param mass         : atomic mass
    1047             : !> \param temperature  : target temperature of canonical ensemble
    1048             : !> \param eigenvalues  : array containing all cartesian vibrational mode eigenvalues (frequencies)
    1049             : !> \param eigenvectors : array containing all corresponding vibrational mode eigenvectors
    1050             : !>                       (displacements)
    1051             : !> \param random       : array containing uniform distributed random numbers, must be the size
    1052             : !>                       of 3*natoms. Numbers must be between 0 and 1
    1053             : !> \param phase        : array containing numbers between 0 and 1 that determines for each
    1054             : !>                       vibration mode the ratio of potential energy vs kinetic energy contribution
    1055             : !>                       to total energy
    1056             : !> \param dof          : total number of degrees of freedom, = 3*natoms
    1057             : !> \param scale        : scale to make sure the sum of vibrational modes give the correct energy
    1058             : !> \return : outputs icart-th cartesian component of initial position of atom iatom
    1059             : !> \author Lianheng Tong, lianheng.tong@kcl.ac.uk
    1060             : ! **************************************************************************************************
    1061          18 :    PURE FUNCTION dr_from_vib_data(iatom, &
    1062             :                                   icart, &
    1063             :                                   mass, &
    1064             :                                   temperature, &
    1065          36 :                                   eigenvalues, &
    1066          18 :                                   eigenvectors, &
    1067          18 :                                   random, &
    1068          18 :                                   phase, &
    1069             :                                   dof, &
    1070             :                                   scale) &
    1071             :       RESULT(res)
    1072             :       INTEGER, INTENT(IN)                                :: iatom, icart
    1073             :       REAL(KIND=dp), INTENT(IN)                          :: mass, temperature
    1074             :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: eigenvalues
    1075             :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: eigenvectors
    1076             :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: random, phase
    1077             :       INTEGER, INTENT(IN)                                :: dof
    1078             :       REAL(KIND=dp), INTENT(IN)                          :: scale
    1079             :       REAL(KIND=dp)                                      :: res
    1080             : 
    1081             :       INTEGER                                            :: imode, ind
    1082             : 
    1083          18 :       res = 0.0_dp
    1084             :       ! assuming the eigenvalues are sorted in ascending order, the
    1085             :       ! first three modes are acoustic with zero frequencies. These are
    1086             :       ! excluded from considerations, and should have been reflected in
    1087             :       ! the calculation of scale outside this function
    1088          18 :       IF (mass .GT. 0.0_dp) THEN
    1089             :          ! eigenvector rows assumed to be grouped in atomic blocks
    1090          18 :          ind = (iatom - 1)*3 + icart
    1091         126 :          DO imode = 4, dof
    1092             :             res = res + &
    1093             :                   SQRT(-2.0_dp*scale*temperature*LOG(1 - random(imode))/mass)/ &
    1094             :                   eigenvalues(imode)* &
    1095             :                   eigenvectors(ind, imode)* &
    1096         126 :                   COS(2.0_dp*pi*phase(imode))
    1097             :          END DO
    1098             :       END IF
    1099          18 :    END FUNCTION dr_from_vib_data
    1100             : 
    1101             : ! **************************************************************************************************
    1102             : !> \brief calculates componbent of initial velocity of an atom from vibreational modes
    1103             : !> \param iatom        : global atomic index
    1104             : !> \param icart        : cartesian index (1, 2 or 3)
    1105             : !> \param mass         : atomic mass
    1106             : !> \param temperature  : target temperature of canonical ensemble
    1107             : !> \param eigenvectors : array containing all corresponding vibrational mode eigenvectors
    1108             : !>                       (displacements)
    1109             : !> \param random       : array containing uniform distributed random numbers, must be the size
    1110             : !>                       of 3*natoms. Numbers must be between 0 and 1
    1111             : !> \param phase        : array containing numbers between 0 and 1 that determines for each
    1112             : !>                       vibration mode the ratio of potential energy vs kinetic energy contribution
    1113             : !>                       to total energy
    1114             : !> \param dof          : total number of degrees of freedom, = 3*natoms
    1115             : !> \param scale        : scale to make sure the sum of vibrational modes give the correct energy
    1116             : !> \return : outputs icart-th cartesian component of initial velocity of atom iatom
    1117             : !> \author Lianheng Tong, lianheng.tong@kcl.ac.uk
    1118             : ! **************************************************************************************************
    1119          18 :    PURE FUNCTION dv_from_vib_data(iatom, &
    1120             :                                   icart, &
    1121             :                                   mass, &
    1122             :                                   temperature, &
    1123          36 :                                   eigenvectors, &
    1124          18 :                                   random, &
    1125          18 :                                   phase, &
    1126             :                                   dof, &
    1127             :                                   scale) &
    1128             :       RESULT(res)
    1129             :       INTEGER, INTENT(IN)                                :: iatom, icart
    1130             :       REAL(KIND=dp), INTENT(IN)                          :: mass, temperature
    1131             :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: eigenvectors
    1132             :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: random, phase
    1133             :       INTEGER, INTENT(IN)                                :: dof
    1134             :       REAL(KIND=dp), INTENT(IN)                          :: scale
    1135             :       REAL(KIND=dp)                                      :: res
    1136             : 
    1137             :       INTEGER                                            :: imode, ind
    1138             : 
    1139          18 :       res = 0.0_dp
    1140             :       ! assuming the eigenvalues are sorted in ascending order, the
    1141             :       ! first three modes are acoustic with zero frequencies. These are
    1142             :       ! excluded from considerations, and should have been reflected in
    1143             :       ! the calculation of scale outside this function
    1144          18 :       IF (mass .GT. 0.0_dp) THEN
    1145             :          ! eigenvector rows assumed to be grouped in atomic blocks
    1146          18 :          ind = (iatom - 1)*3 + icart
    1147         126 :          DO imode = 4, dof
    1148             :             res = res - &
    1149             :                   SQRT(-2.0_dp*scale*temperature*LOG(1 - random(imode))/mass)* &
    1150             :                   eigenvectors(ind, imode)* &
    1151         126 :                   SIN(2.0_dp*pi*phase(imode))
    1152             :          END DO
    1153             :       END IF
    1154          18 :    END FUNCTION dv_from_vib_data
    1155             : 
    1156             : ! **************************************************************************************************
    1157             : !> \brief Initializing velocities deterministically on all processors, if not given in input
    1158             : !> \param simpar ...
    1159             : !> \param part ...
    1160             : !> \param force_env ...
    1161             : !> \param globenv ...
    1162             : !> \param md_env ...
    1163             : !> \param shell_present ...
    1164             : !> \param shell_part ...
    1165             : !> \param core_part ...
    1166             : !> \param is_fixed ...
    1167             : !> \param iw ...
    1168             : !> \author CJM,MK,Toon Verstraelen <Toon.Verstraelen@gmail.com>, Ole Schuett
    1169             : ! **************************************************************************************************
    1170        1540 :    SUBROUTINE generate_velocities(simpar, part, force_env, globenv, md_env, &
    1171        1540 :                                   shell_present, shell_part, core_part, is_fixed, iw)
    1172             :       TYPE(simpar_type), POINTER                         :: simpar
    1173             :       TYPE(particle_type), DIMENSION(:), POINTER         :: part
    1174             :       TYPE(force_env_type), POINTER                      :: force_env
    1175             :       TYPE(global_environment_type), POINTER             :: globenv
    1176             :       TYPE(md_environment_type), POINTER                 :: md_env
    1177             :       LOGICAL, INTENT(IN)                                :: shell_present
    1178             :       TYPE(particle_type), DIMENSION(:), POINTER         :: shell_part, core_part
    1179             :       INTEGER, DIMENSION(:), INTENT(INOUT)               :: is_fixed
    1180             :       INTEGER, INTENT(IN)                                :: iw
    1181             : 
    1182             :       INTEGER                                            :: i, natoms
    1183             :       REAL(KIND=dp)                                      :: mass
    1184             :       TYPE(atomic_kind_type), POINTER                    :: atomic_kind
    1185             : 
    1186        1540 :       NULLIFY (atomic_kind)
    1187        1540 :       natoms = SIZE(part)
    1188             : 
    1189      432018 :       DO i = 1, natoms
    1190      430478 :          atomic_kind => part(i)%atomic_kind
    1191      430478 :          CALL get_atomic_kind(atomic_kind=atomic_kind, mass=mass)
    1192      430478 :          part(i)%v(1) = 0.0_dp
    1193      430478 :          part(i)%v(2) = 0.0_dp
    1194      430478 :          part(i)%v(3) = 0.0_dp
    1195      432018 :          IF (mass .NE. 0.0) THEN
    1196      430544 :             SELECT CASE (is_fixed(i))
    1197             :             CASE (use_perd_x)
    1198         512 :                part(i)%v(2) = globenv%gaussian_rng_stream%next()/SQRT(mass)
    1199         512 :                part(i)%v(3) = globenv%gaussian_rng_stream%next()/SQRT(mass)
    1200             :             CASE (use_perd_y)
    1201         512 :                part(i)%v(1) = globenv%gaussian_rng_stream%next()/SQRT(mass)
    1202         512 :                part(i)%v(3) = globenv%gaussian_rng_stream%next()/SQRT(mass)
    1203             :             CASE (use_perd_z)
    1204         512 :                part(i)%v(1) = globenv%gaussian_rng_stream%next()/SQRT(mass)
    1205         512 :                part(i)%v(2) = globenv%gaussian_rng_stream%next()/SQRT(mass)
    1206             :             CASE (use_perd_xy)
    1207         512 :                part(i)%v(3) = globenv%gaussian_rng_stream%next()/SQRT(mass)
    1208             :             CASE (use_perd_xz)
    1209           0 :                part(i)%v(2) = globenv%gaussian_rng_stream%next()/SQRT(mass)
    1210             :             CASE (use_perd_yz)
    1211           0 :                part(i)%v(1) = globenv%gaussian_rng_stream%next()/SQRT(mass)
    1212             :             CASE (use_perd_none)
    1213      424866 :                part(i)%v(1) = globenv%gaussian_rng_stream%next()/SQRT(mass)
    1214      424866 :                part(i)%v(2) = globenv%gaussian_rng_stream%next()/SQRT(mass)
    1215      854898 :                part(i)%v(3) = globenv%gaussian_rng_stream%next()/SQRT(mass)
    1216             :             END SELECT
    1217             :          END IF
    1218             :       END DO
    1219             : 
    1220        1540 :       CALL normalize_velocities(simpar, part, force_env, md_env, is_fixed)
    1221        1540 :       CALL soften_velocities(simpar, part, force_env, md_env, is_fixed, iw)
    1222             : 
    1223             :       ! Initialize the core and the shell velocity. Atom velocities are just
    1224             :       ! copied so that the initial relative core-shell velocity is zero.
    1225        1540 :       IF (shell_present) THEN
    1226          84 :          CALL optimize_shell_core(force_env, part, shell_part, core_part, globenv)
    1227             :       END IF
    1228        1540 :    END SUBROUTINE generate_velocities
    1229             : 
    1230             : ! **************************************************************************************************
    1231             : !> \brief Direct velocities along a low-curvature direction in order to
    1232             : !>        favors MD trajectories to cross rapidly over small energy barriers
    1233             : !>        into neighboring basins.
    1234             : !> \param simpar ...
    1235             : !> \param part ...
    1236             : !> \param force_env ...
    1237             : !> \param md_env ...
    1238             : !> \param is_fixed ...
    1239             : !> \param iw ...
    1240             : !> \author Ole Schuett
    1241             : ! **************************************************************************************************
    1242        1540 :    SUBROUTINE soften_velocities(simpar, part, force_env, md_env, is_fixed, iw)
    1243             :       TYPE(simpar_type), POINTER                         :: simpar
    1244             :       TYPE(particle_type), DIMENSION(:), POINTER         :: part
    1245             :       TYPE(force_env_type), POINTER                      :: force_env
    1246             :       TYPE(md_environment_type), POINTER                 :: md_env
    1247             :       INTEGER, DIMENSION(:), INTENT(INOUT)               :: is_fixed
    1248             :       INTEGER, INTENT(IN)                                :: iw
    1249             : 
    1250             :       INTEGER                                            :: i, k
    1251        1492 :       REAL(KIND=dp), DIMENSION(SIZE(part), 3)            :: F, F_t, N, x0
    1252             : 
    1253        1540 :       IF (simpar%soften_nsteps <= 0) RETURN !nothing todo
    1254             : 
    1255         528 :       IF (ANY(is_fixed /= use_perd_none)) &
    1256           0 :          CPABORT("Velocitiy softening with constraints is not supported.")
    1257             : 
    1258             :       !backup positions
    1259         528 :       DO i = 1, SIZE(part)
    1260        1968 :          x0(i, :) = part(i)%r
    1261             :       END DO
    1262             : 
    1263        1008 :       DO k = 1, simpar%soften_nsteps
    1264             : 
    1265             :          !use normalized velocities as displace direction
    1266       10560 :          DO i = 1, SIZE(part)
    1267       39360 :             N(i, :) = part(i)%v
    1268             :          END DO
    1269       64320 :          N = N/SQRT(SUM(N**2))
    1270             : 
    1271             :          ! displace system temporarly to calculate forces
    1272       10560 :          DO i = 1, SIZE(part)
    1273       39360 :             part(i)%r = part(i)%r + simpar%soften_delta*N(i, :)
    1274             :          END DO
    1275         960 :          CALL force_env_calc_energy_force(force_env)
    1276             : 
    1277             :          ! calculate velocity update direction F_t
    1278       10560 :          DO i = 1, SIZE(part)
    1279       39360 :             F(i, :) = part(i)%f
    1280             :          END DO
    1281       64320 :          F_t = F - N*SUM(N*F)
    1282             : 
    1283             :          ! restore positions and update velocities
    1284       10560 :          DO i = 1, SIZE(part)
    1285       38400 :             part(i)%r = x0(i, :)
    1286       39360 :             part(i)%v = part(i)%v + simpar%soften_alpha*F_t(i, :)
    1287             :          END DO
    1288             : 
    1289        1008 :          CALL normalize_velocities(simpar, part, force_env, md_env, is_fixed)
    1290             :       END DO
    1291             : 
    1292          48 :       IF (iw > 0) THEN
    1293           0 :          WRITE (iw, "(A,T71, I10)") " Velocities softening Steps: ", simpar%soften_nsteps
    1294           0 :          WRITE (iw, "(A,T71, E10.3)") " Velocities softening NORM(F_t): ", SQRT(SUM(F_t**2))
    1295             :       END IF
    1296          48 :    END SUBROUTINE soften_velocities
    1297             : 
    1298             : ! **************************************************************************************************
    1299             : !> \brief Scale velocities according to temperature and remove rigid body motion.
    1300             : !> \param simpar ...
    1301             : !> \param part ...
    1302             : !> \param force_env ...
    1303             : !> \param md_env ...
    1304             : !> \param is_fixed ...
    1305             : !> \author CJM,MK,Toon Verstraelen <Toon.Verstraelen@gmail.com>, Ole Schuett
    1306             : ! **************************************************************************************************
    1307        2500 :    SUBROUTINE normalize_velocities(simpar, part, force_env, md_env, is_fixed)
    1308             :       TYPE(simpar_type), POINTER                         :: simpar
    1309             :       TYPE(particle_type), DIMENSION(:), POINTER         :: part
    1310             :       TYPE(force_env_type), POINTER                      :: force_env
    1311             :       TYPE(md_environment_type), POINTER                 :: md_env
    1312             :       INTEGER, DIMENSION(:), INTENT(INOUT)               :: is_fixed
    1313             : 
    1314             :       REAL(KIND=dp)                                      :: ekin
    1315             :       REAL(KIND=dp), DIMENSION(3)                        :: rcom, vang, vcom
    1316             :       TYPE(cell_type), POINTER                           :: cell
    1317             : 
    1318        2500 :       NULLIFY (cell)
    1319             : 
    1320             :       ! Subtract the vcom
    1321        2500 :       CALL compute_vcom(part, is_fixed, vcom)
    1322        2500 :       CALL subtract_vcom(part, is_fixed, vcom)
    1323             :       ! If requested and the system is not periodic, subtract the angular velocity
    1324        2500 :       CALL force_env_get(force_env, cell=cell)
    1325       10000 :       IF (SUM(cell%perd(1:3)) == 0 .AND. simpar%angvel_zero) THEN
    1326           4 :          CALL compute_rcom(part, is_fixed, rcom)
    1327           4 :          CALL compute_vang(part, is_fixed, rcom, vang)
    1328           4 :          CALL subtract_vang(part, is_fixed, rcom, vang)
    1329             :       END IF
    1330             :       ! Rescale the velocities
    1331        2500 :       IF (simpar%do_thermal_region) THEN
    1332           2 :          CALL rescale_vel_region(part, md_env, simpar)
    1333             :       ELSE
    1334        2498 :          ekin = compute_ekin(part)
    1335        2498 :          CALL rescale_vel(part, simpar, ekin)
    1336             :       END IF
    1337        2500 :    END SUBROUTINE normalize_velocities
    1338             : 
    1339             : ! **************************************************************************************************
    1340             : !> \brief Computes Ekin, VCOM and Temp for particles
    1341             : !> \param subsys ...
    1342             : !> \param md_ener ...
    1343             : !> \param vsubtract ...
    1344             : !> \par History
    1345             : !>     Teodoro Laino - University of Zurich - 09.2007 [tlaino]
    1346             : ! **************************************************************************************************
    1347          42 :    SUBROUTINE reset_vcom(subsys, md_ener, vsubtract)
    1348             :       TYPE(cp_subsys_type), POINTER                      :: subsys
    1349             :       TYPE(md_ener_type), POINTER                        :: md_ener
    1350             :       REAL(KIND=dp), DIMENSION(3), INTENT(IN)            :: vsubtract
    1351             : 
    1352             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'reset_vcom'
    1353             : 
    1354             :       INTEGER                                            :: atom, handle, iatom, ikind, natom, &
    1355             :                                                             shell_index
    1356          42 :       INTEGER, DIMENSION(:), POINTER                     :: atom_list
    1357             :       LOGICAL                                            :: is_shell
    1358             :       REAL(KIND=dp)                                      :: ekin_old, imass_c, imass_s, mass, v2
    1359             :       REAL(KIND=dp), DIMENSION(3)                        :: tmp, v
    1360             :       TYPE(atomic_kind_list_type), POINTER               :: atomic_kinds
    1361             :       TYPE(atomic_kind_type), POINTER                    :: atomic_kind
    1362             :       TYPE(particle_list_type), POINTER                  :: core_particles, particles, &
    1363             :                                                             shell_particles
    1364             :       TYPE(shell_kind_type), POINTER                     :: shell
    1365             : 
    1366          42 :       NULLIFY (particles, atomic_kind, atomic_kinds, atom_list, shell)
    1367          42 :       CALL timeset(routineN, handle)
    1368             : 
    1369             :       CALL cp_subsys_get(subsys, &
    1370             :                          atomic_kinds=atomic_kinds, &
    1371             :                          particles=particles, &
    1372             :                          shell_particles=shell_particles, &
    1373          42 :                          core_particles=core_particles)
    1374             : 
    1375          42 :       ekin_old = md_ener%ekin
    1376             :       ! Possibly subtract a quantity from all velocities
    1377         126 :       DO ikind = 1, atomic_kinds%n_els
    1378          84 :          atomic_kind => atomic_kinds%els(ikind)
    1379             :          CALL get_atomic_kind(atomic_kind=atomic_kind, atom_list=atom_list, &
    1380          84 :                               natom=natom, mass=mass, shell_active=is_shell, shell=shell)
    1381         126 :          IF (is_shell) THEN
    1382         336 :             tmp = 0.5_dp*vsubtract*mass
    1383          84 :             imass_s = 1.0_dp/shell%mass_shell
    1384          84 :             imass_c = 1.0_dp/shell%mass_core
    1385        3780 :             DO iatom = 1, natom
    1386        3696 :                atom = atom_list(iatom)
    1387        3696 :                shell_index = particles%els(atom)%shell_index
    1388       14784 :                shell_particles%els(shell_index)%v = shell_particles%els(shell_index)%v - tmp*imass_s
    1389       14784 :                core_particles%els(shell_index)%v = core_particles%els(shell_index)%v - tmp*imass_c
    1390       14868 :                particles%els(atom)%v = particles%els(atom)%v - vsubtract
    1391             :             END DO
    1392             :          ELSE
    1393           0 :             DO iatom = 1, natom
    1394           0 :                atom = atom_list(iatom)
    1395           0 :                particles%els(atom)%v = particles%els(atom)%v - vsubtract
    1396             :             END DO
    1397             :          END IF
    1398             :       END DO
    1399             :       ! Compute Kinetic Energy and COM Velocity
    1400         168 :       md_ener%vcom = 0.0_dp
    1401          42 :       md_ener%total_mass = 0.0_dp
    1402          42 :       md_ener%ekin = 0.0_dp
    1403         126 :       DO ikind = 1, atomic_kinds%n_els
    1404          84 :          atomic_kind => atomic_kinds%els(ikind)
    1405          84 :          CALL get_atomic_kind(atomic_kind=atomic_kind, atom_list=atom_list, mass=mass, natom=natom)
    1406          84 :          v2 = 0.0_dp
    1407          84 :          v = 0.0_dp
    1408        3780 :          DO iatom = 1, natom
    1409        3696 :             atom = atom_list(iatom)
    1410       14784 :             v2 = v2 + SUM(particles%els(atom)%v**2)
    1411        3696 :             v(1) = v(1) + particles%els(atom)%v(1)
    1412        3696 :             v(2) = v(2) + particles%els(atom)%v(2)
    1413        3780 :             v(3) = v(3) + particles%els(atom)%v(3)
    1414             :          END DO
    1415          84 :          md_ener%ekin = md_ener%ekin + 0.5_dp*mass*v2
    1416          84 :          md_ener%vcom(1) = md_ener%vcom(1) + mass*v(1)
    1417          84 :          md_ener%vcom(2) = md_ener%vcom(2) + mass*v(2)
    1418          84 :          md_ener%vcom(3) = md_ener%vcom(3) + mass*v(3)
    1419         210 :          md_ener%total_mass = md_ener%total_mass + REAL(natom, KIND=dp)*mass
    1420             :       END DO
    1421         168 :       md_ener%vcom = md_ener%vcom/md_ener%total_mass
    1422          42 :       md_ener%constant = md_ener%constant - ekin_old + md_ener%ekin
    1423          42 :       IF (md_ener%nfree /= 0) THEN
    1424          42 :          md_ener%temp_part = 2.0_dp*md_ener%ekin/REAL(md_ener%nfree, KIND=dp)*kelvin
    1425             :       END IF
    1426          42 :       CALL timestop(handle)
    1427             : 
    1428          42 :    END SUBROUTINE reset_vcom
    1429             : 
    1430             : ! **************************************************************************************************
    1431             : !> \brief Scale velocities to get the correct temperature
    1432             : !> \param subsys ...
    1433             : !> \param md_ener ...
    1434             : !> \param temp_expected ...
    1435             : !> \param temp_tol ...
    1436             : !> \param iw ...
    1437             : !> \par History
    1438             : !>     Teodoro Laino - University of Zurich - 09.2007 [tlaino]
    1439             : ! **************************************************************************************************
    1440       12814 :    SUBROUTINE scale_velocity(subsys, md_ener, temp_expected, temp_tol, iw)
    1441             :       TYPE(cp_subsys_type), POINTER                      :: subsys
    1442             :       TYPE(md_ener_type), POINTER                        :: md_ener
    1443             :       REAL(KIND=dp), INTENT(IN)                          :: temp_expected, temp_tol
    1444             :       INTEGER, INTENT(IN)                                :: iw
    1445             : 
    1446             :       REAL(KIND=dp)                                      :: ekin_old, scale, temp_old
    1447             : 
    1448       12814 :       IF (ABS(temp_expected - md_ener%temp_part/kelvin) > temp_tol) THEN
    1449        2562 :          scale = 0.0_dp
    1450        2562 :          IF (md_ener%temp_part > 0.0_dp) scale = SQRT((temp_expected/md_ener%temp_part)*kelvin)
    1451        2562 :          ekin_old = md_ener%ekin
    1452        2562 :          temp_old = md_ener%temp_part
    1453        2562 :          md_ener%ekin = 0.0_dp
    1454        2562 :          md_ener%temp_part = 0.0_dp
    1455       10248 :          md_ener%vcom = 0.0_dp
    1456        2562 :          md_ener%total_mass = 0.0_dp
    1457             : 
    1458        2562 :          CALL scale_velocity_low(subsys, scale, ireg=0, ekin=md_ener%ekin, vcom=md_ener%vcom)
    1459        2562 :          IF (md_ener%nfree /= 0) THEN
    1460        2562 :             md_ener%temp_part = 2.0_dp*md_ener%ekin/REAL(md_ener%nfree, KIND=dp)*kelvin
    1461             :          END IF
    1462        2562 :          md_ener%constant = md_ener%constant - ekin_old + md_ener%ekin
    1463        2562 :          IF (iw > 0) THEN
    1464             :             WRITE (UNIT=iw, FMT='(/,T2,A)') &
    1465        1281 :                'MD_VEL| Temperature scaled to requested temperature'
    1466             :             WRITE (UNIT=iw, FMT='(T2,A,T61,F20.6)') &
    1467        1281 :                'MD_VEL| Old temperature [K]', temp_old, &
    1468        2562 :                'MD_VEL| New temperature [K]', md_ener%temp_part
    1469             :          END IF
    1470             :       END IF
    1471             : 
    1472       12814 :    END SUBROUTINE scale_velocity
    1473             : 
    1474             : ! **************************************************************************************************
    1475             : !> \brief Scale velocities of set of regions
    1476             : !> \param md_env ...
    1477             : !> \param subsys ...
    1478             : !> \param md_ener ...
    1479             : !> \param simpar ...
    1480             : !> \param iw ...
    1481             : !> \par author MI
    1482             : ! **************************************************************************************************
    1483          96 :    SUBROUTINE scale_velocity_region(md_env, subsys, md_ener, simpar, iw)
    1484             : 
    1485             :       TYPE(md_environment_type), POINTER                 :: md_env
    1486             :       TYPE(cp_subsys_type), POINTER                      :: subsys
    1487             :       TYPE(md_ener_type), POINTER                        :: md_ener
    1488             :       TYPE(simpar_type), POINTER                         :: simpar
    1489             :       INTEGER, INTENT(IN)                                :: iw
    1490             : 
    1491             :       INTEGER                                            :: ireg, nfree, nfree_done, nregions
    1492             :       REAL(KIND=dp)                                      :: ekin, ekin_old, ekin_total_new, fscale, &
    1493             :                                                             vcom(3), vcom_total(3)
    1494          96 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: temp_new, temp_old
    1495             :       TYPE(particle_list_type), POINTER                  :: particles
    1496             :       TYPE(particle_type), DIMENSION(:), POINTER         :: part
    1497             :       TYPE(thermal_region_type), POINTER                 :: t_region
    1498             :       TYPE(thermal_regions_type), POINTER                :: thermal_regions
    1499             : 
    1500          96 :       NULLIFY (particles, part, thermal_regions, t_region)
    1501          96 :       CALL cp_subsys_get(subsys, particles=particles)
    1502          96 :       part => particles%els
    1503          96 :       CALL get_md_env(md_env, thermal_regions=thermal_regions)
    1504             : 
    1505          96 :       nregions = thermal_regions%nregions
    1506          96 :       nfree_done = 0
    1507          96 :       ekin_total_new = 0.0_dp
    1508          96 :       ekin_old = md_ener%ekin
    1509             :       vcom_total = 0.0_dp
    1510         384 :       ALLOCATE (temp_new(0:nregions), temp_old(0:nregions))
    1511         352 :       temp_new = 0.0_dp
    1512         352 :       temp_old = 0.0_dp
    1513             :       !loop regions
    1514         256 :       DO ireg = 1, nregions
    1515         160 :          NULLIFY (t_region)
    1516         160 :          t_region => thermal_regions%thermal_region(ireg)
    1517         160 :          nfree = 3*t_region%npart
    1518         160 :          ekin = compute_ekin(part, ireg)
    1519         160 :          IF (nfree > 0) t_region%temperature = 2.0_dp*ekin/REAL(nfree, KIND=dp)*kelvin
    1520         160 :          temp_old(ireg) = t_region%temperature
    1521         160 :          IF (t_region%temp_tol > 0.0_dp .AND. &
    1522             :              ABS(t_region%temp_expected - t_region%temperature/kelvin) > t_region%temp_tol) THEN
    1523           2 :             fscale = SQRT((t_region%temp_expected/t_region%temperature)*kelvin)
    1524           2 :             CALL scale_velocity_low(subsys, fscale, ireg, ekin, vcom)
    1525           2 :             t_region%temperature = 2.0_dp*ekin/REAL(nfree, KIND=dp)*kelvin
    1526           2 :             temp_new(ireg) = t_region%temperature
    1527             :          END IF
    1528         160 :          nfree_done = nfree_done + nfree
    1529         256 :          ekin_total_new = ekin_total_new + ekin
    1530             :       END DO
    1531          96 :       nfree = simpar%nfree - nfree_done
    1532          96 :       ekin = compute_ekin(part, ireg=0)
    1533          96 :       IF (nfree > 0) thermal_regions%temp_reg0 = 2.0_dp*ekin/REAL(nfree, KIND=dp)*kelvin
    1534          96 :       temp_old(0) = thermal_regions%temp_reg0
    1535          96 :       IF (simpar%temp_tol > 0.0_dp .AND. nfree > 0) THEN
    1536           0 :          IF (ABS(simpar%temp_ext - thermal_regions%temp_reg0/kelvin) > simpar%temp_tol) THEN
    1537           0 :             fscale = SQRT((simpar%temp_ext/thermal_regions%temp_reg0)*kelvin)
    1538           0 :             CALL scale_velocity_low(subsys, fscale, 0, ekin, vcom)
    1539           0 :             thermal_regions%temp_reg0 = 2.0_dp*ekin/REAL(nfree, KIND=dp)*kelvin
    1540           0 :             temp_new(0) = thermal_regions%temp_reg0
    1541             :          END IF
    1542             :       END IF
    1543          96 :       ekin_total_new = ekin_total_new + ekin
    1544             : 
    1545          96 :       md_ener%ekin = ekin_total_new
    1546          96 :       IF (md_ener%nfree /= 0) THEN
    1547          96 :          md_ener%temp_part = 2.0_dp*md_ener%ekin/REAL(md_ener%nfree, KIND=dp)*kelvin
    1548             :       END IF
    1549          96 :       md_ener%constant = md_ener%constant - ekin_old + md_ener%ekin
    1550          96 :       IF (iw > 0) THEN
    1551         176 :          DO ireg = 0, nregions
    1552         176 :             IF (temp_new(ireg) > 0.0_dp) THEN
    1553             :                WRITE (UNIT=iw, FMT='(/,T2,A,I0,A)') &
    1554           1 :                   'MD_VEL| Temperature region ', ireg, ' scaled to requested temperature'
    1555             :                WRITE (UNIT=iw, FMT='(T2,A,T61,F20.6)') &
    1556           1 :                   'MD_VEL| Old temperature [K]', temp_old(ireg), &
    1557           2 :                   'MD_VEL| New temperature [K]', temp_new(ireg)
    1558             :             END IF
    1559             :          END DO
    1560             :       END IF
    1561          96 :       DEALLOCATE (temp_new, temp_old)
    1562             : 
    1563          96 :    END SUBROUTINE scale_velocity_region
    1564             : 
    1565             : ! **************************************************************************************************
    1566             : !> \brief Scale velocities  for a specific region
    1567             : !> \param subsys ...
    1568             : !> \param fscale ...
    1569             : !> \param ireg ...
    1570             : !> \param ekin ...
    1571             : !> \param vcom ...
    1572             : !> \par author MI
    1573             : ! **************************************************************************************************
    1574        2564 :    SUBROUTINE scale_velocity_low(subsys, fscale, ireg, ekin, vcom)
    1575             : 
    1576             :       TYPE(cp_subsys_type), POINTER                      :: subsys
    1577             :       REAL(KIND=dp), INTENT(IN)                          :: fscale
    1578             :       INTEGER, INTENT(IN)                                :: ireg
    1579             :       REAL(KIND=dp), INTENT(OUT)                         :: ekin, vcom(3)
    1580             : 
    1581             :       INTEGER                                            :: atom, iatom, ikind, my_ireg, natom, &
    1582             :                                                             shell_index
    1583        2564 :       INTEGER, DIMENSION(:), POINTER                     :: atom_list
    1584             :       LOGICAL                                            :: is_shell
    1585             :       REAL(KIND=dp)                                      :: imass, mass, tmass, v2
    1586             :       REAL(KIND=dp), DIMENSION(3)                        :: tmp, v, vc, vs
    1587             :       TYPE(atomic_kind_list_type), POINTER               :: atomic_kinds
    1588             :       TYPE(atomic_kind_type), POINTER                    :: atomic_kind
    1589             :       TYPE(particle_list_type), POINTER                  :: core_particles, particles, &
    1590             :                                                             shell_particles
    1591             :       TYPE(shell_kind_type), POINTER                     :: shell
    1592             : 
    1593        2564 :       NULLIFY (atomic_kinds, particles, shell_particles, core_particles, shell, atom_list)
    1594             : 
    1595        2564 :       my_ireg = ireg
    1596        2564 :       ekin = 0.0_dp
    1597        2564 :       tmass = 0.0_dp
    1598        2564 :       vcom = 0.0_dp
    1599             : 
    1600             :       CALL cp_subsys_get(subsys, atomic_kinds=atomic_kinds, particles=particles, &
    1601        2564 :                          shell_particles=shell_particles, core_particles=core_particles)
    1602             : 
    1603        8848 :       DO ikind = 1, atomic_kinds%n_els
    1604        6284 :          atomic_kind => atomic_kinds%els(ikind)
    1605             :          CALL get_atomic_kind(atomic_kind=atomic_kind, atom_list=atom_list, mass=mass, &
    1606        6284 :                               natom=natom, shell_active=is_shell, shell=shell)
    1607        6284 :          IF (is_shell) THEN
    1608         124 :             imass = 1.0_dp/mass
    1609         124 :             v2 = 0.0_dp
    1610         124 :             v = 0.0_dp
    1611        5740 :             DO iatom = 1, natom
    1612        5616 :                atom = atom_list(iatom)
    1613             :                !check region
    1614        5616 :                IF (particles%els(atom)%t_region_index /= my_ireg) CYCLE
    1615             : 
    1616       21080 :                particles%els(atom)%v(:) = fscale*particles%els(atom)%v
    1617        5270 :                shell_index = particles%els(atom)%shell_index
    1618       21080 :                vs = shell_particles%els(shell_index)%v
    1619       21080 :                vc = core_particles%els(shell_index)%v
    1620        5270 :                tmp(1) = imass*(vs(1) - vc(1))
    1621        5270 :                tmp(2) = imass*(vs(2) - vc(2))
    1622        5270 :                tmp(3) = imass*(vs(3) - vc(3))
    1623             : 
    1624        5270 :                shell_particles%els(shell_index)%v(1) = particles%els(atom)%v(1) + tmp(1)*shell%mass_core
    1625        5270 :                shell_particles%els(shell_index)%v(2) = particles%els(atom)%v(2) + tmp(2)*shell%mass_core
    1626        5270 :                shell_particles%els(shell_index)%v(3) = particles%els(atom)%v(3) + tmp(3)*shell%mass_core
    1627             : 
    1628        5270 :                core_particles%els(shell_index)%v(1) = particles%els(atom)%v(1) - tmp(1)*shell%mass_shell
    1629        5270 :                core_particles%els(shell_index)%v(2) = particles%els(atom)%v(2) - tmp(2)*shell%mass_shell
    1630        5270 :                core_particles%els(shell_index)%v(3) = particles%els(atom)%v(3) - tmp(3)*shell%mass_shell
    1631             : 
    1632             :                ! kinetic energy and velocity of COM
    1633       21080 :                v2 = v2 + SUM(particles%els(atom)%v**2)
    1634        5270 :                v(1) = v(1) + particles%els(atom)%v(1)
    1635        5270 :                v(2) = v(2) + particles%els(atom)%v(2)
    1636        5270 :                v(3) = v(3) + particles%els(atom)%v(3)
    1637        5740 :                tmass = tmass + mass
    1638             :             END DO
    1639             :          ELSE
    1640        6160 :             v2 = 0.0_dp
    1641        6160 :             v = 0.0_dp
    1642       22382 :             DO iatom = 1, natom
    1643       16222 :                atom = atom_list(iatom)
    1644             :                !check region
    1645       16222 :                IF (particles%els(atom)%t_region_index /= my_ireg) CYCLE
    1646             : 
    1647       64888 :                particles%els(atom)%v(:) = fscale*particles%els(atom)%v
    1648             :                ! kinetic energy and velocity of COM
    1649       64888 :                v2 = v2 + SUM(particles%els(atom)%v**2)
    1650       16222 :                v(1) = v(1) + particles%els(atom)%v(1)
    1651       16222 :                v(2) = v(2) + particles%els(atom)%v(2)
    1652       16222 :                v(3) = v(3) + particles%els(atom)%v(3)
    1653       22382 :                tmass = tmass + mass
    1654             :             END DO
    1655             :          END IF
    1656        6284 :          ekin = ekin + 0.5_dp*mass*v2
    1657        6284 :          vcom(1) = vcom(1) + mass*v(1)
    1658        6284 :          vcom(2) = vcom(2) + mass*v(2)
    1659       15132 :          vcom(3) = vcom(3) + mass*v(3)
    1660             : 
    1661             :       END DO
    1662       10256 :       vcom = vcom/tmass
    1663             : 
    1664        2564 :    END SUBROUTINE scale_velocity_low
    1665             : 
    1666             : ! **************************************************************************************************
    1667             : !> \brief Scale internal motion of CORE-SHELL model to the correct temperature
    1668             : !> \param subsys ...
    1669             : !> \param md_ener ...
    1670             : !> \param temp_expected ...
    1671             : !> \param temp_tol ...
    1672             : !> \param iw ...
    1673             : !> \par History
    1674             : !>     Teodoro Laino - University of Zurich - 09.2007 [tlaino]
    1675             : ! **************************************************************************************************
    1676        1060 :    SUBROUTINE scale_velocity_internal(subsys, md_ener, temp_expected, temp_tol, iw)
    1677             :       TYPE(cp_subsys_type), POINTER                      :: subsys
    1678             :       TYPE(md_ener_type), POINTER                        :: md_ener
    1679             :       REAL(KIND=dp), INTENT(IN)                          :: temp_expected, temp_tol
    1680             :       INTEGER, INTENT(IN)                                :: iw
    1681             : 
    1682             :       INTEGER                                            :: atom, iatom, ikind, natom, shell_index
    1683        1060 :       INTEGER, DIMENSION(:), POINTER                     :: atom_list
    1684             :       LOGICAL                                            :: is_shell
    1685             :       REAL(KIND=dp)                                      :: ekin_shell_old, fac_mass, mass, scale, &
    1686             :                                                             temp_shell_old, v2
    1687             :       REAL(KIND=dp), DIMENSION(3)                        :: tmp, v, vc, vs
    1688             :       TYPE(atomic_kind_list_type), POINTER               :: atomic_kinds
    1689             :       TYPE(atomic_kind_type), POINTER                    :: atomic_kind
    1690             :       TYPE(particle_list_type), POINTER                  :: core_particles, particles, &
    1691             :                                                             shell_particles
    1692             :       TYPE(shell_kind_type), POINTER                     :: shell
    1693             : 
    1694        1060 :       NULLIFY (atom_list, atomic_kinds, atomic_kind, core_particles, particles, shell_particles, shell)
    1695        1060 :       IF (ABS(temp_expected - md_ener%temp_shell/kelvin) > temp_tol) THEN
    1696          80 :          scale = 0.0_dp
    1697          80 :          IF (md_ener%temp_shell > EPSILON(0.0_dp)) scale = SQRT((temp_expected/md_ener%temp_shell)*kelvin)
    1698          80 :          ekin_shell_old = md_ener%ekin_shell
    1699          80 :          temp_shell_old = md_ener%temp_shell
    1700          80 :          md_ener%ekin_shell = 0.0_dp
    1701          80 :          md_ener%temp_shell = 0.0_dp
    1702             : 
    1703             :          CALL cp_subsys_get(subsys, atomic_kinds=atomic_kinds, particles=particles, shell_particles=shell_particles, &
    1704          80 :                             core_particles=core_particles)
    1705             : 
    1706         240 :          DO ikind = 1, atomic_kinds%n_els
    1707         160 :             atomic_kind => atomic_kinds%els(ikind)
    1708             :             CALL get_atomic_kind(atomic_kind=atomic_kind, atom_list=atom_list, mass=mass, natom=natom, &
    1709         160 :                                  shell_active=is_shell, shell=shell)
    1710         240 :             IF (is_shell) THEN
    1711         160 :                fac_mass = 1.0_dp/mass
    1712         160 :                v2 = 0.0_dp
    1713         776 :                DO iatom = 1, natom
    1714         616 :                   atom = atom_list(iatom)
    1715         616 :                   shell_index = particles%els(atom)%shell_index
    1716        2464 :                   vs = shell_particles%els(shell_index)%v
    1717        2464 :                   vc = core_particles%els(shell_index)%v
    1718        2464 :                   v = particles%els(atom)%v
    1719         616 :                   tmp(1) = fac_mass*(vc(1) - vs(1))
    1720         616 :                   tmp(2) = fac_mass*(vc(2) - vs(2))
    1721         616 :                   tmp(3) = fac_mass*(vc(3) - vs(3))
    1722             : 
    1723         616 :                   shell_particles%els(shell_index)%v(1) = v(1) - shell%mass_core*scale*tmp(1)
    1724         616 :                   shell_particles%els(shell_index)%v(2) = v(2) - shell%mass_core*scale*tmp(2)
    1725         616 :                   shell_particles%els(shell_index)%v(3) = v(3) - shell%mass_core*scale*tmp(3)
    1726             : 
    1727         616 :                   core_particles%els(shell_index)%v(1) = v(1) + shell%mass_shell*scale*tmp(1)
    1728         616 :                   core_particles%els(shell_index)%v(2) = v(2) + shell%mass_shell*scale*tmp(2)
    1729         616 :                   core_particles%els(shell_index)%v(3) = v(3) + shell%mass_shell*scale*tmp(3)
    1730             : 
    1731        2464 :                   vs = shell_particles%els(shell_index)%v
    1732        2464 :                   vc = core_particles%els(shell_index)%v
    1733         616 :                   tmp(1) = vc(1) - vs(1)
    1734         616 :                   tmp(2) = vc(2) - vs(2)
    1735         616 :                   tmp(3) = vc(3) - vs(3)
    1736        2624 :                   v2 = v2 + SUM(tmp**2)
    1737             :                END DO
    1738         160 :                md_ener%ekin_shell = md_ener%ekin_shell + 0.5_dp*shell%mass_core*shell%mass_shell*fac_mass*v2
    1739             :             END IF
    1740             :          END DO
    1741          80 :          IF (md_ener%nfree_shell > 0) THEN
    1742          80 :             md_ener%temp_shell = 2.0_dp*md_ener%ekin_shell/REAL(md_ener%nfree_shell, KIND=dp)*kelvin
    1743             :          END IF
    1744          80 :          md_ener%constant = md_ener%constant - ekin_shell_old + md_ener%ekin_shell
    1745          80 :          IF (iw > 0) THEN
    1746             :             WRITE (UNIT=iw, FMT='(/,T2,A)') &
    1747          40 :                'MD_VEL| Temperature of shell internal motion scaled to requested temperature'
    1748             :             WRITE (UNIT=iw, FMT='(T2,A,T61,F20.6)') &
    1749          40 :                'MD_VEL| Old temperature [K]', temp_shell_old, &
    1750          80 :                'MD_VEL| New temperature [K]', md_ener%temp_shell
    1751             :          END IF
    1752             :       END IF
    1753             : 
    1754        1060 :    END SUBROUTINE scale_velocity_internal
    1755             : 
    1756             : ! **************************************************************************************************
    1757             : !> \brief Scale barostat velocities to get the desired temperature
    1758             : !> \param md_env ...
    1759             : !> \param md_ener ...
    1760             : !> \param temp_expected ...
    1761             : !> \param temp_tol ...
    1762             : !> \param iw ...
    1763             : !> \par History
    1764             : !>     MI 02.2008
    1765             : ! **************************************************************************************************
    1766          40 :    SUBROUTINE scale_velocity_baro(md_env, md_ener, temp_expected, temp_tol, iw)
    1767             :       TYPE(md_environment_type), POINTER                 :: md_env
    1768             :       TYPE(md_ener_type), POINTER                        :: md_ener
    1769             :       REAL(KIND=dp), INTENT(IN)                          :: temp_expected, temp_tol
    1770             :       INTEGER, INTENT(IN)                                :: iw
    1771             : 
    1772             :       INTEGER                                            :: i, j, nfree
    1773             :       REAL(KIND=dp)                                      :: ekin_old, scale, temp_old
    1774          40 :       TYPE(npt_info_type), POINTER                       :: npt(:, :)
    1775             :       TYPE(simpar_type), POINTER                         :: simpar
    1776             : 
    1777          40 :       NULLIFY (npt, simpar)
    1778          40 :       CALL get_md_env(md_env, simpar=simpar, npt=npt)
    1779          40 :       IF (ABS(temp_expected - md_ener%temp_baro/kelvin) > temp_tol) THEN
    1780           2 :          scale = 0.0_dp
    1781           2 :          IF (md_ener%temp_baro > 0.0_dp) scale = SQRT((temp_expected/md_ener%temp_baro)*kelvin)
    1782           2 :          ekin_old = md_ener%baro_kin
    1783           2 :          temp_old = md_ener%temp_baro
    1784           2 :          md_ener%baro_kin = 0.0_dp
    1785           2 :          md_ener%temp_baro = 0.0_dp
    1786             :          IF (simpar%ensemble == npt_i_ensemble .OR. simpar%ensemble == npe_i_ensemble &
    1787           2 :              .OR. simpar%ensemble == npt_ia_ensemble) THEN
    1788           0 :             npt(1, 1)%v = npt(1, 1)%v*scale
    1789           0 :             md_ener%baro_kin = 0.5_dp*npt(1, 1)%v**2*npt(1, 1)%mass
    1790             :          ELSE IF (simpar%ensemble == npt_f_ensemble .OR. simpar%ensemble == npe_f_ensemble) THEN
    1791           2 :             md_ener%baro_kin = 0.0_dp
    1792           8 :             DO i = 1, 3
    1793          26 :                DO j = 1, 3
    1794          18 :                   npt(i, j)%v = npt(i, j)%v*scale
    1795          24 :                   md_ener%baro_kin = md_ener%baro_kin + 0.5_dp*npt(i, j)%v**2*npt(i, j)%mass
    1796             :                END DO
    1797             :             END DO
    1798             :          END IF
    1799           2 :          nfree = SIZE(npt, 1)*SIZE(npt, 2)
    1800           2 :          md_ener%temp_baro = 2.0_dp*md_ener%baro_kin/REAL(nfree, dp)*kelvin
    1801           2 :          IF (iw > 0) THEN
    1802             :             WRITE (UNIT=iw, FMT='(/,T2,A)') &
    1803           1 :                'MD_VEL| Temperature of barostat motion scaled to requested temperature'
    1804             :             WRITE (UNIT=iw, FMT='(T2,A,T61,F20.6)') &
    1805           1 :                'MD_VEL| Old temperature [K]', temp_old, &
    1806           2 :                'MD_VEL| New temperature [K]', md_ener%temp_baro
    1807             :          END IF
    1808             :       END IF
    1809             : 
    1810          40 :    END SUBROUTINE scale_velocity_baro
    1811             : 
    1812             : ! **************************************************************************************************
    1813             : !> \brief Perform all temperature manipulations during a QS MD run.
    1814             : !> \param simpar ...
    1815             : !> \param md_env ...
    1816             : !> \param md_ener ...
    1817             : !> \param force_env ...
    1818             : !> \param logger ...
    1819             : !> \par History
    1820             : !>     Creation (15.09.2003,MK)
    1821             : !>     adapted to force_env (05.10.2003,fawzi)
    1822             : !>     Cleaned (09.2007) Teodoro Laino [tlaino] - University of Zurich
    1823             : ! **************************************************************************************************
    1824       41253 :    SUBROUTINE temperature_control(simpar, md_env, md_ener, force_env, logger)
    1825             : 
    1826             :       TYPE(simpar_type), POINTER                         :: simpar
    1827             :       TYPE(md_environment_type), POINTER                 :: md_env
    1828             :       TYPE(md_ener_type), POINTER                        :: md_ener
    1829             :       TYPE(force_env_type), POINTER                      :: force_env
    1830             :       TYPE(cp_logger_type), POINTER                      :: logger
    1831             : 
    1832             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'temperature_control'
    1833             : 
    1834             :       INTEGER                                            :: handle, iw
    1835             :       TYPE(cp_subsys_type), POINTER                      :: subsys
    1836             :       TYPE(mp_para_env_type), POINTER                    :: para_env
    1837             : 
    1838       41253 :       CALL timeset(routineN, handle)
    1839       41253 :       NULLIFY (subsys, para_env)
    1840       41253 :       CPASSERT(ASSOCIATED(simpar))
    1841       41253 :       CPASSERT(ASSOCIATED(md_ener))
    1842       41253 :       CPASSERT(ASSOCIATED(force_env))
    1843       41253 :       CALL force_env_get(force_env, subsys=subsys, para_env=para_env)
    1844             :       iw = cp_print_key_unit_nr(logger, force_env%root_section, "MOTION%MD%PRINT%PROGRAM_RUN_INFO", &
    1845       41253 :                                 extension=".mdLog")
    1846             : 
    1847             :       ! Control the particle motion
    1848       41253 :       IF (simpar%do_thermal_region) THEN
    1849          96 :          CALL scale_velocity_region(md_env, subsys, md_ener, simpar, iw)
    1850             :       ELSE
    1851       41157 :          IF (simpar%temp_tol > 0.0_dp) THEN
    1852       12770 :             CALL scale_velocity(subsys, md_ener, simpar%temp_ext, simpar%temp_tol, iw)
    1853             :          END IF
    1854             :       END IF
    1855             :       ! Control the internal core-shell motion
    1856       41253 :       IF (simpar%temp_sh_tol > 0.0_dp) THEN
    1857        1060 :          CALL scale_velocity_internal(subsys, md_ener, simpar%temp_sh_ext, simpar%temp_sh_tol, iw)
    1858             :       END IF
    1859             :       ! Control cell motion
    1860       43773 :       SELECT CASE (simpar%ensemble)
    1861             :       CASE (nph_uniaxial_damped_ensemble, nph_uniaxial_ensemble, &
    1862             :             npt_f_ensemble, npt_i_ensemble, npe_f_ensemble, npe_i_ensemble, npt_ia_ensemble)
    1863       41253 :          IF (simpar%temp_baro_tol > 0.0_dp) THEN
    1864          40 :             CALL scale_velocity_baro(md_env, md_ener, simpar%temp_baro_ext, simpar%temp_baro_tol, iw)
    1865             :          END IF
    1866             :       END SELECT
    1867             : 
    1868             :       CALL cp_print_key_finished_output(iw, logger, force_env%root_section, &
    1869       41253 :                                         "MOTION%MD%PRINT%PROGRAM_RUN_INFO")
    1870       41253 :       CALL timestop(handle)
    1871       41253 :    END SUBROUTINE temperature_control
    1872             : 
    1873             : ! **************************************************************************************************
    1874             : !> \brief Set to 0 the velocity of the COM along MD runs, if required.
    1875             : !> \param md_ener ...
    1876             : !> \param force_env ...
    1877             : !> \param md_section ...
    1878             : !> \param logger ...
    1879             : !> \par History
    1880             : !>      Creation (29.04.2007,MI)
    1881             : !>      Cleaned (09.2007) Teodoro Laino [tlaino] - University of Zurich
    1882             : ! **************************************************************************************************
    1883       82506 :    SUBROUTINE comvel_control(md_ener, force_env, md_section, logger)
    1884             : 
    1885             :       TYPE(md_ener_type), POINTER                        :: md_ener
    1886             :       TYPE(force_env_type), POINTER                      :: force_env
    1887             :       TYPE(section_vals_type), POINTER                   :: md_section
    1888             :       TYPE(cp_logger_type), POINTER                      :: logger
    1889             : 
    1890             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'comvel_control'
    1891             : 
    1892             :       INTEGER                                            :: handle, iw
    1893             :       LOGICAL                                            :: explicit
    1894             :       REAL(KIND=dp)                                      :: comvel_tol, temp_old, vel_com
    1895             :       REAL(KIND=dp), DIMENSION(3)                        :: vcom_old
    1896             :       TYPE(cp_subsys_type), POINTER                      :: subsys
    1897             : 
    1898       41253 :       CALL timeset(routineN, handle)
    1899       41253 :       NULLIFY (subsys)
    1900       41253 :       CPASSERT(ASSOCIATED(force_env))
    1901       41253 :       CALL force_env_get(force_env, subsys=subsys)
    1902             : 
    1903             :       ! Print COMVEL and COM Position
    1904       41253 :       iw = cp_print_key_unit_nr(logger, md_section, "PRINT%CENTER_OF_MASS", extension=".mdLog")
    1905       41253 :       IF (iw > 0) THEN
    1906             :          WRITE (UNIT=iw, FMT="(/,T2,A)") &
    1907        7747 :             "MD_VEL| Centre of mass motion (COM)"
    1908             :          WRITE (UNIT=iw, FMT="(T2,A,T30,3(1X,F16.10))") &
    1909        7747 :             "MD_VEL| VCOM [a.u.]", md_ener%vcom(1:3)
    1910             :       END IF
    1911       41253 :       CALL cp_print_key_finished_output(iw, logger, md_section, "PRINT%CENTER_OF_MASS")
    1912             : 
    1913             :       ! If requested rescale COMVEL
    1914       41253 :       CALL section_vals_val_get(md_section, "COMVEL_TOL", explicit=explicit)
    1915       41253 :       IF (explicit) THEN
    1916         826 :          CALL section_vals_val_get(md_section, "COMVEL_TOL", r_val=comvel_tol)
    1917             :          iw = cp_print_key_unit_nr(logger, md_section, "PRINT%PROGRAM_RUN_INFO", &
    1918         826 :                                    extension=".mdLog")
    1919         826 :          vel_com = SQRT(md_ener%vcom(1)**2 + md_ener%vcom(2)**2 + md_ener%vcom(3)**2)
    1920             : 
    1921             :          ! Subtract the velocity of the COM, if requested
    1922         826 :          IF (vel_com > comvel_tol) THEN
    1923          42 :             temp_old = md_ener%temp_part/kelvin
    1924         168 :             vcom_old = md_ener%vcom
    1925          42 :             CALL reset_vcom(subsys, md_ener, vsubtract=vcom_old)
    1926          42 :             CALL scale_velocity(subsys, md_ener, temp_old, 0.0_dp, iw)
    1927          42 :             IF (iw > 0) THEN
    1928             :                WRITE (UNIT=iw, FMT="(T2,A,T30,3(1X,F16.10))") &
    1929          21 :                   "MD_VEL| Old VCOM [a.u.]", vcom_old(1:3)
    1930             :                WRITE (UNIT=iw, FMT="(T2,A,T30,3(1X,F16.10))") &
    1931          21 :                   "MD_VEL| New VCOM [a.u.]", md_ener%vcom(1:3)
    1932             :             END IF
    1933             :          END IF
    1934             :          CALL cp_print_key_finished_output(iw, logger, md_section, &
    1935         826 :                                            "PRINT%PROGRAM_RUN_INFO")
    1936             :       END IF
    1937             : 
    1938       41253 :       CALL timestop(handle)
    1939       41253 :    END SUBROUTINE comvel_control
    1940             : 
    1941             : ! **************************************************************************************************
    1942             : !> \brief Set to 0 the angular velocity along MD runs, if required.
    1943             : !> \param md_ener ...
    1944             : !> \param force_env ...
    1945             : !> \param md_section ...
    1946             : !> \param logger ...
    1947             : !> \par History
    1948             : !>      Creation (10.2009) Teodoro Laino [tlaino]
    1949             : ! **************************************************************************************************
    1950       41253 :    SUBROUTINE angvel_control(md_ener, force_env, md_section, logger)
    1951             : 
    1952             :       TYPE(md_ener_type), POINTER                        :: md_ener
    1953             :       TYPE(force_env_type), POINTER                      :: force_env
    1954             :       TYPE(section_vals_type), POINTER                   :: md_section
    1955             :       TYPE(cp_logger_type), POINTER                      :: logger
    1956             : 
    1957             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'angvel_control'
    1958             : 
    1959             :       INTEGER                                            :: handle, ifixd, imolecule_kind, iw, natoms
    1960       41253 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: is_fixed
    1961             :       LOGICAL                                            :: explicit
    1962             :       REAL(KIND=dp)                                      :: angvel_tol, rcom(3), temp_old, vang(3), &
    1963             :                                                             vang_new(3)
    1964             :       TYPE(cell_type), POINTER                           :: cell
    1965             :       TYPE(cp_subsys_type), POINTER                      :: subsys
    1966       41253 :       TYPE(fixd_constraint_type), DIMENSION(:), POINTER  :: fixd_list
    1967             :       TYPE(molecule_kind_list_type), POINTER             :: molecule_kinds
    1968       41253 :       TYPE(molecule_kind_type), DIMENSION(:), POINTER    :: molecule_kind_set
    1969             :       TYPE(molecule_kind_type), POINTER                  :: molecule_kind
    1970             :       TYPE(particle_list_type), POINTER                  :: particles
    1971             : 
    1972       41253 :       CALL timeset(routineN, handle)
    1973             :       ! If requested rescale ANGVEL
    1974       41253 :       CALL section_vals_val_get(md_section, "ANGVEL_TOL", explicit=explicit)
    1975       41253 :       IF (explicit) THEN
    1976          40 :          NULLIFY (subsys, cell)
    1977          40 :          CPASSERT(ASSOCIATED(force_env))
    1978          40 :          CALL force_env_get(force_env, subsys=subsys, cell=cell)
    1979             : 
    1980         160 :          IF (SUM(cell%perd(1:3)) == 0) THEN
    1981          40 :             CALL section_vals_val_get(md_section, "ANGVEL_TOL", r_val=angvel_tol)
    1982             :             iw = cp_print_key_unit_nr(logger, md_section, "PRINT%PROGRAM_RUN_INFO", &
    1983          40 :                                       extension=".mdLog")
    1984             : 
    1985             :             CALL cp_subsys_get(subsys, molecule_kinds=molecule_kinds, &
    1986          40 :                                particles=particles)
    1987             : 
    1988          40 :             natoms = SIZE(particles%els)
    1989             :             ! Build a list of all fixed atoms (if any)
    1990         120 :             ALLOCATE (is_fixed(natoms))
    1991             : 
    1992         600 :             is_fixed = use_perd_none
    1993          40 :             molecule_kind_set => molecule_kinds%els
    1994         600 :             DO imolecule_kind = 1, molecule_kinds%n_els
    1995         560 :                molecule_kind => molecule_kind_set(imolecule_kind)
    1996         560 :                CALL get_molecule_kind(molecule_kind=molecule_kind, fixd_list=fixd_list)
    1997         600 :                IF (ASSOCIATED(fixd_list)) THEN
    1998           0 :                   DO ifixd = 1, SIZE(fixd_list)
    1999           0 :                      IF (.NOT. fixd_list(ifixd)%restraint%active) &
    2000           0 :                         is_fixed(fixd_list(ifixd)%fixd) = fixd_list(ifixd)%itype
    2001             :                   END DO
    2002             :                END IF
    2003             :             END DO
    2004             : 
    2005             :             ! If requested and the system is not periodic, subtract the angular velocity
    2006          40 :             CALL compute_rcom(particles%els, is_fixed, rcom)
    2007          40 :             CALL compute_vang(particles%els, is_fixed, rcom, vang)
    2008             :             ! SQRT(DOT_PRODUCT(vang,vang))>angvel_tol
    2009         160 :             IF (DOT_PRODUCT(vang, vang) > (angvel_tol*angvel_tol)) THEN
    2010           2 :                CALL subtract_vang(particles%els, is_fixed, rcom, vang)
    2011             : 
    2012             :                ! Rescale velocities after removal
    2013           2 :                temp_old = md_ener%temp_part/kelvin
    2014           2 :                CALL scale_velocity(subsys, md_ener, temp_old, 0.0_dp, iw)
    2015           2 :                CALL compute_vang(particles%els, is_fixed, rcom, vang_new)
    2016           2 :                IF (iw > 0) THEN
    2017             :                   WRITE (UNIT=iw, FMT="(T2,A,T30,3(1X,F16.10))") &
    2018           1 :                      'MD_VEL| Old VANG [a.u.]', vang(1:3)
    2019             :                   WRITE (UNIT=iw, FMT="(T2,A,T30,3(1X,F16.10))") &
    2020           1 :                      'MD_VEL| New VANG [a.u.]', vang_new(1:3)
    2021             :                END IF
    2022             :             END IF
    2023             : 
    2024          40 :             DEALLOCATE (is_fixed)
    2025             : 
    2026             :             CALL cp_print_key_finished_output(iw, logger, md_section, &
    2027          80 :                                               "PRINT%PROGRAM_RUN_INFO")
    2028             :          END IF
    2029             :       END IF
    2030             : 
    2031       41253 :       CALL timestop(handle)
    2032       82506 :    END SUBROUTINE angvel_control
    2033             : 
    2034             : ! **************************************************************************************************
    2035             : !> \brief Initialize Velocities for MD runs
    2036             : !> \param force_env ...
    2037             : !> \param simpar ...
    2038             : !> \param globenv ...
    2039             : !> \param md_env ...
    2040             : !> \param md_section ...
    2041             : !> \param constraint_section ...
    2042             : !> \param write_binary_restart_file ...
    2043             : !> \par History
    2044             : !>     Teodoro Laino - University of Zurich - 09.2007 [tlaino]
    2045             : ! **************************************************************************************************
    2046        3568 :    SUBROUTINE setup_velocities(force_env, simpar, globenv, md_env, md_section, &
    2047             :                                constraint_section, write_binary_restart_file)
    2048             : 
    2049             :       TYPE(force_env_type), POINTER                      :: force_env
    2050             :       TYPE(simpar_type), POINTER                         :: simpar
    2051             :       TYPE(global_environment_type), POINTER             :: globenv
    2052             :       TYPE(md_environment_type), POINTER                 :: md_env
    2053             :       TYPE(section_vals_type), POINTER                   :: md_section, constraint_section
    2054             :       LOGICAL, INTENT(IN)                                :: write_binary_restart_file
    2055             : 
    2056             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'setup_velocities'
    2057             : 
    2058             :       INTEGER                                            :: handle, nconstraint, nconstraint_fixd
    2059             :       LOGICAL                                            :: apply_cns0, shell_adiabatic, &
    2060             :                                                             shell_present
    2061             :       TYPE(atomic_kind_list_type), POINTER               :: atomic_kinds
    2062             :       TYPE(cell_type), POINTER                           :: cell
    2063             :       TYPE(cp_subsys_type), POINTER                      :: subsys
    2064             :       TYPE(molecule_kind_list_type), POINTER             :: molecule_kinds
    2065             :       TYPE(mp_para_env_type), POINTER                    :: para_env
    2066             :       TYPE(particle_list_type), POINTER                  :: core_particles, particles, &
    2067             :                                                             shell_particles
    2068        1784 :       TYPE(particle_type), DIMENSION(:), POINTER         :: core_particle_set, particle_set, &
    2069        1784 :                                                             shell_particle_set
    2070             :       TYPE(section_vals_type), POINTER                   :: force_env_section, print_section, &
    2071             :                                                             subsys_section
    2072             : 
    2073        1784 :       CALL timeset(routineN, handle)
    2074             : 
    2075        1784 :       NULLIFY (atomic_kinds, cell, para_env, subsys, molecule_kinds, core_particles, particles)
    2076        1784 :       NULLIFY (shell_particles, core_particle_set, particle_set, shell_particle_set)
    2077        1784 :       NULLIFY (force_env_section, print_section, subsys_section)
    2078             : 
    2079        1784 :       print_section => section_vals_get_subs_vals(md_section, "PRINT")
    2080        1784 :       apply_cns0 = .FALSE.
    2081        1784 :       IF (simpar%constraint) THEN
    2082         310 :          CALL section_vals_val_get(constraint_section, "CONSTRAINT_INIT", l_val=apply_cns0)
    2083             :       END IF
    2084             :       ! Always initialize velocities and possibly restart them
    2085             :       CALL force_env_get(force_env, subsys=subsys, cell=cell, para_env=para_env, &
    2086        1784 :                          force_env_section=force_env_section)
    2087        1784 :       subsys_section => section_vals_get_subs_vals(force_env_section, "SUBSYS")
    2088             : 
    2089             :       CALL cp_subsys_get(subsys, &
    2090             :                          atomic_kinds=atomic_kinds, &
    2091             :                          core_particles=core_particles, &
    2092             :                          molecule_kinds=molecule_kinds, &
    2093             :                          particles=particles, &
    2094        1784 :                          shell_particles=shell_particles)
    2095             : 
    2096             :       CALL get_atomic_kind_set(atomic_kind_set=atomic_kinds%els, &
    2097             :                                shell_present=shell_present, &
    2098        1784 :                                shell_adiabatic=shell_adiabatic)
    2099             : 
    2100        1784 :       NULLIFY (core_particle_set)
    2101             :       NULLIFY (particle_set)
    2102        1784 :       NULLIFY (shell_particle_set)
    2103        1784 :       particle_set => particles%els
    2104             : 
    2105        1784 :       IF (shell_present .AND. shell_adiabatic) THEN
    2106             :          ! Constraints are not yet implemented for core-shell models generally
    2107             :          CALL get_molecule_kind_set(molecule_kind_set=molecule_kinds%els, &
    2108             :                                     nconstraint=nconstraint, &
    2109         132 :                                     nconstraint_fixd=nconstraint_fixd)
    2110         132 :          IF (nconstraint - nconstraint_fixd /= 0) &
    2111           0 :             CPABORT("Only the fixed atom constraint is implemented for core-shell models")
    2112             : !MK    CPPostcondition(.NOT.simpar%constraint,cp_failure_level,routineP,failure)
    2113         132 :          CPASSERT(ASSOCIATED(shell_particles))
    2114         132 :          CPASSERT(ASSOCIATED(core_particles))
    2115         132 :          shell_particle_set => shell_particles%els
    2116         132 :          core_particle_set => core_particles%els
    2117             :       END IF
    2118             : 
    2119             :       CALL initialize_velocities(simpar, &
    2120             :                                  particle_set, &
    2121             :                                  molecule_kinds=molecule_kinds, &
    2122             :                                  force_env=force_env, &
    2123             :                                  globenv=globenv, &
    2124             :                                  md_env=md_env, &
    2125             :                                  label="Velocities initialization", &
    2126             :                                  print_section=print_section, &
    2127             :                                  subsys_section=subsys_section, &
    2128             :                                  shell_present=(shell_present .AND. shell_adiabatic), &
    2129             :                                  shell_part=shell_particle_set, &
    2130             :                                  core_part=core_particle_set, &
    2131             :                                  force_rescaling=.FALSE., &
    2132             :                                  para_env=para_env, &
    2133        3436 :                                  write_binary_restart_file=write_binary_restart_file)
    2134             : 
    2135             :       ! Apply constraints if required and rescale velocities..
    2136        1784 :       IF (simpar%ensemble /= reftraj_ensemble) THEN
    2137        1746 :          IF (apply_cns0) THEN
    2138          24 :             CALL force_env_calc_energy_force(force_env, calc_force=.TRUE.)
    2139             :             CALL force_env_shake(force_env, &
    2140             :                                  shake_tol=simpar%shake_tol, &
    2141             :                                  log_unit=simpar%info_constraint, &
    2142             :                                  lagrange_mult=simpar%lagrange_multipliers, &
    2143             :                                  dump_lm=simpar%dump_lm, &
    2144          24 :                                  compold=.TRUE.)
    2145             :             CALL force_env_rattle(force_env, shake_tol=simpar%shake_tol, &
    2146             :                                   log_unit=simpar%info_constraint, lagrange_mult=simpar%lagrange_multipliers, &
    2147          24 :                                   dump_lm=simpar%dump_lm, reset=.TRUE.)
    2148          24 :             IF (simpar%do_respa) THEN
    2149             :                CALL force_env_calc_energy_force(force_env%sub_force_env(1)%force_env, &
    2150           0 :                                                 calc_force=.TRUE.)
    2151             :                CALL force_env_shake(force_env%sub_force_env(1)%force_env, &
    2152             :                                     shake_tol=simpar%shake_tol, log_unit=simpar%info_constraint, &
    2153           0 :                                     lagrange_mult=simpar%lagrange_multipliers, dump_lm=simpar%dump_lm, compold=.TRUE.)
    2154             :                CALL force_env_rattle(force_env%sub_force_env(1)%force_env, &
    2155             :                                      shake_tol=simpar%shake_tol, log_unit=simpar%info_constraint, &
    2156           0 :                                      lagrange_mult=simpar%lagrange_multipliers, dump_lm=simpar%dump_lm, reset=.TRUE.)
    2157             :             END IF
    2158             :             ! Reinitialize velocities rescaling properly after rattle
    2159          24 :             subsys_section => section_vals_get_subs_vals(force_env_section, "SUBSYS")
    2160          24 :             CALL update_subsys(subsys_section, force_env, .FALSE., write_binary_restart_file)
    2161             :             CALL initialize_velocities(simpar, &
    2162             :                                        particle_set, &
    2163             :                                        molecule_kinds=molecule_kinds, &
    2164             :                                        force_env=force_env, &
    2165             :                                        globenv=globenv, &
    2166             :                                        md_env=md_env, &
    2167             :                                        label="Re-Initializing velocities after applying constraints", &
    2168             :                                        print_section=print_section, &
    2169             :                                        subsys_section=subsys_section, &
    2170             :                                        shell_present=(shell_present .AND. shell_adiabatic), &
    2171             :                                        shell_part=shell_particle_set, &
    2172             :                                        core_part=core_particle_set, &
    2173             :                                        force_rescaling=.TRUE., &
    2174             :                                        para_env=para_env, &
    2175          48 :                                        write_binary_restart_file=write_binary_restart_file)
    2176             :          END IF
    2177             :       END IF
    2178             : 
    2179             :       ! Perform setup for a cascade run
    2180        1784 :       CALL initialize_cascade(simpar, particle_set, molecule_kinds, md_section)
    2181             : 
    2182        1784 :       CALL timestop(handle)
    2183             : 
    2184        1784 :    END SUBROUTINE setup_velocities
    2185             : 
    2186             : ! **************************************************************************************************
    2187             : !> \brief   Perform the initialization for a cascade run
    2188             : !> \param simpar ...
    2189             : !> \param particle_set ...
    2190             : !> \param molecule_kinds ...
    2191             : !> \param md_section ...
    2192             : !> \date    05.02.2012
    2193             : !> \author  Matthias Krack (MK)
    2194             : !> \version 1.0
    2195             : ! **************************************************************************************************
    2196        1784 :    SUBROUTINE initialize_cascade(simpar, particle_set, molecule_kinds, md_section)
    2197             : 
    2198             :       TYPE(simpar_type), POINTER                         :: simpar
    2199             :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    2200             :       TYPE(molecule_kind_list_type), POINTER             :: molecule_kinds
    2201             :       TYPE(section_vals_type), POINTER                   :: md_section
    2202             : 
    2203             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'initialize_cascade'
    2204             : 
    2205             :       CHARACTER(len=2*default_string_length)             :: line
    2206             :       INTEGER                                            :: handle, iatom, ifixd, imolecule_kind, &
    2207             :                                                             iparticle, iw, natom, nparticle
    2208        1784 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: atom_index, is_fixed
    2209             :       LOGICAL                                            :: init_cascade, is_ok, no_read_error
    2210             :       REAL(KIND=dp)                                      :: ecom, ekin, energy, norm, temp, &
    2211             :                                                             temperature
    2212        1784 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: matom, weight
    2213        1784 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: vatom
    2214             :       REAL(KIND=dp), DIMENSION(3)                        :: vcom
    2215             :       TYPE(atomic_kind_type), POINTER                    :: atomic_kind
    2216             :       TYPE(cp_logger_type), POINTER                      :: logger
    2217             :       TYPE(cp_sll_val_type), POINTER                     :: atom_list
    2218        1784 :       TYPE(fixd_constraint_type), DIMENSION(:), POINTER  :: fixd_list
    2219        1784 :       TYPE(molecule_kind_type), DIMENSION(:), POINTER    :: molecule_kind_set
    2220             :       TYPE(molecule_kind_type), POINTER                  :: molecule_kind
    2221             :       TYPE(section_vals_type), POINTER                   :: atom_list_section, cascade_section, &
    2222             :                                                             print_section
    2223             :       TYPE(val_type), POINTER                            :: val
    2224             : 
    2225        1784 :       CALL timeset(routineN, handle)
    2226             : 
    2227        1784 :       NULLIFY (atom_list)
    2228        1784 :       NULLIFY (atom_list_section)
    2229        1784 :       NULLIFY (atomic_kind)
    2230        1784 :       NULLIFY (cascade_section)
    2231        1784 :       NULLIFY (fixd_list)
    2232        1784 :       NULLIFY (molecule_kind)
    2233        1784 :       NULLIFY (molecule_kind_set)
    2234        1784 :       NULLIFY (logger)
    2235        1784 :       NULLIFY (val)
    2236             : 
    2237        1784 :       logger => cp_get_default_logger()
    2238        1784 :       print_section => section_vals_get_subs_vals(md_section, "PRINT")
    2239        1784 :       iw = cp_print_key_unit_nr(logger, print_section, "PROGRAM_RUN_INFO", extension=".log")
    2240             : 
    2241        1784 :       cascade_section => section_vals_get_subs_vals(md_section, "CASCADE")
    2242        1784 :       CALL section_vals_val_get(cascade_section, "_SECTION_PARAMETERS_", l_val=init_cascade)
    2243             : 
    2244        1784 :       nparticle = SIZE(particle_set)
    2245             : 
    2246        1784 :       IF (init_cascade) THEN
    2247             : 
    2248           2 :          CALL section_vals_val_get(cascade_section, "ENERGY", r_val=energy)
    2249           2 :          IF (energy < 0.0_dp) &
    2250           0 :             CPABORT("Error occurred reading &CASCADE section: Negative energy found")
    2251             : 
    2252           2 :          IF (iw > 0) THEN
    2253           1 :             ekin = cp_unit_from_cp2k(energy, "keV")
    2254             :             WRITE (UNIT=iw, FMT="(/,T2,A,T61,F20.6)") &
    2255           1 :                "CASCADE| Energy [keV]", ekin
    2256             :             WRITE (UNIT=iw, FMT="(T2,A)") &
    2257           1 :                "CASCADE|"
    2258             :          END IF
    2259             : 
    2260             :          ! Read the atomic velocities given in the input file
    2261           2 :          atom_list_section => section_vals_get_subs_vals(cascade_section, "ATOM_LIST")
    2262           2 :          CALL section_vals_val_get(atom_list_section, "_DEFAULT_KEYWORD_", n_rep_val=natom)
    2263           2 :          CALL section_vals_list_get(atom_list_section, "_DEFAULT_KEYWORD_", list=atom_list)
    2264           2 :          IF (natom <= 0) &
    2265           0 :             CPABORT("Error occurred reading &CASCADE section: No atom list found")
    2266             : 
    2267           2 :          IF (iw > 0) THEN
    2268             :             WRITE (UNIT=iw, FMT="(T2,A,T11,A,3(11X,A),9X,A)") &
    2269           1 :                "CASCADE| ", "Atom index", "v(x)", "v(y)", "v(z)", "weight"
    2270             :          END IF
    2271             : 
    2272           6 :          ALLOCATE (atom_index(natom))
    2273           6 :          ALLOCATE (matom(natom))
    2274           6 :          ALLOCATE (vatom(3, natom))
    2275           4 :          ALLOCATE (weight(natom))
    2276             : 
    2277           8 :          DO iatom = 1, natom
    2278           6 :             is_ok = cp_sll_val_next(atom_list, val)
    2279           6 :             CALL val_get(val, c_val=line)
    2280             :             ! Read atomic index, velocity vector, and weight
    2281           6 :             no_read_error = .FALSE.
    2282           6 :             READ (UNIT=line, FMT=*, ERR=999) atom_index(iatom), vatom(1:3, iatom), weight(iatom)
    2283             :             no_read_error = .TRUE.
    2284             : 999         IF (.NOT. no_read_error) &
    2285           0 :                CPABORT("Error occurred reading &CASCADE section. Last line read <"//TRIM(line)//">")
    2286           6 :             IF ((atom_index(iatom) <= 0) .OR. ((atom_index(iatom) > nparticle))) &
    2287           0 :                CPABORT("Error occurred reading &CASCADE section: Invalid atom index found")
    2288           6 :             IF (weight(iatom) < 0.0_dp) &
    2289           0 :                CPABORT("Error occurred reading &CASCADE section: Negative weight found")
    2290           8 :             IF (iw > 0) THEN
    2291             :                WRITE (UNIT=iw, FMT="(T2,A,I10,4(1X,F14.6))") &
    2292           3 :                   "CASCADE| ", atom_index(iatom), vatom(1:3, iatom), weight(iatom)
    2293             :             END IF
    2294             :          END DO
    2295             : 
    2296             :          ! Normalise velocities and weights
    2297             :          norm = 0.0_dp
    2298           8 :          DO iatom = 1, natom
    2299           6 :             iparticle = atom_index(iatom)
    2300           6 :             IF (particle_set(iparticle)%shell_index /= 0) THEN
    2301           0 :                CPWARN("Warning: The primary knock-on atom is a core-shell atom")
    2302             :             END IF
    2303           6 :             atomic_kind => particle_set(iparticle)%atomic_kind
    2304           6 :             CALL get_atomic_kind(atomic_kind=atomic_kind, mass=matom(iatom))
    2305           8 :             norm = norm + matom(iatom)*weight(iatom)
    2306             :          END DO
    2307           8 :          weight(:) = matom(:)*weight(:)*energy/norm
    2308           8 :          DO iatom = 1, natom
    2309          24 :             norm = SQRT(DOT_PRODUCT(vatom(1:3, iatom), vatom(1:3, iatom)))
    2310          26 :             vatom(1:3, iatom) = vatom(1:3, iatom)/norm
    2311             :          END DO
    2312             : 
    2313           2 :          IF (iw > 0) THEN
    2314             :             WRITE (UNIT=iw, FMT="(T2,A)") &
    2315           1 :                "CASCADE|", &
    2316           1 :                "CASCADE| Normalised velocities and additional kinetic energy [keV]", &
    2317           2 :                "CASCADE|"
    2318             :             WRITE (UNIT=iw, FMT="(T2,A,T11,A,3(11X,A),9X,A)") &
    2319           1 :                "CASCADE| ", "Atom index", "v(x)", "v(y)", "v(z)", "E(kin)"
    2320           4 :             DO iatom = 1, natom
    2321           3 :                ekin = cp_unit_from_cp2k(weight(iatom), "keV")
    2322             :                WRITE (UNIT=iw, FMT="(T2,A,I10,4(1X,F14.6))") &
    2323           4 :                   "CASCADE| ", atom_index(iatom), vatom(1:3, iatom), ekin
    2324             :             END DO
    2325             :          END IF
    2326             : 
    2327             :          ! Apply velocity modifications
    2328           8 :          DO iatom = 1, natom
    2329           6 :             iparticle = atom_index(iatom)
    2330             :             particle_set(iparticle)%v(:) = particle_set(iparticle)%v(:) + &
    2331          26 :                                            SQRT(2.0_dp*weight(iatom)/matom(iatom))*vatom(1:3, iatom)
    2332             :          END DO
    2333             : 
    2334           2 :          DEALLOCATE (atom_index)
    2335           2 :          DEALLOCATE (matom)
    2336           2 :          DEALLOCATE (vatom)
    2337           2 :          DEALLOCATE (weight)
    2338             : 
    2339           6 :          IF (iw > 0) THEN
    2340             :             ! Build a list of all fixed atoms (if any)
    2341           3 :             ALLOCATE (is_fixed(nparticle))
    2342          97 :             is_fixed = use_perd_none
    2343           1 :             molecule_kind_set => molecule_kinds%els
    2344           2 :             DO imolecule_kind = 1, molecule_kinds%n_els
    2345           1 :                molecule_kind => molecule_kind_set(imolecule_kind)
    2346           1 :                CALL get_molecule_kind(molecule_kind=molecule_kind, fixd_list=fixd_list)
    2347           2 :                IF (ASSOCIATED(fixd_list)) THEN
    2348           0 :                   DO ifixd = 1, SIZE(fixd_list)
    2349           0 :                      IF (.NOT. fixd_list(ifixd)%restraint%active) is_fixed(fixd_list(ifixd)%fixd) = fixd_list(ifixd)%itype
    2350             :                   END DO
    2351             :                END IF
    2352             :             END DO
    2353             :             ! Compute vcom, ecom and ekin for printout
    2354           1 :             CALL compute_vcom(particle_set, is_fixed, vcom, ecom)
    2355           1 :             ekin = compute_ekin(particle_set) - ecom
    2356           1 :             IF (simpar%nfree == 0) THEN
    2357           0 :                CPASSERT(ekin == 0.0_dp)
    2358           0 :                temp = 0.0_dp
    2359             :             ELSE
    2360           1 :                temp = 2.0_dp*ekin/REAL(simpar%nfree, KIND=dp)
    2361             :             END IF
    2362           1 :             temperature = cp_unit_from_cp2k(temp, "K")
    2363             :             WRITE (UNIT=iw, FMT="(T2,A)") &
    2364           1 :                "CASCADE|"
    2365             :             WRITE (UNIT=iw, FMT="(T2,A,T61,F20.6)") &
    2366           1 :                "CASCADE| Temperature after cascade initialization [K]", temperature
    2367             :             WRITE (UNIT=iw, FMT="(T2,A,T30,3(1X,ES16.8))") &
    2368           1 :                "CASCADE| COM velocity", vcom(1:3)
    2369             : !MK          ! compute and log rcom and vang if not periodic
    2370             : !MK          CALL force_env_get(force_env,cell=cell)
    2371             : !MK          IF (SUM(cell%perd(1:3)) == 0) THEN
    2372             : !MK             CALL compute_rcom(particle_set,is_fixed,rcom)
    2373             : !MK             CALL compute_vang(particle_set,is_fixed,rcom,vang)
    2374             : !MK             WRITE (iw, '( A, T21, F20.12 , F20.12 , F20.12 )' ) ' COM position:',rcom(1:3)
    2375             : !MK             WRITE (iw, '( A, T21, F20.12 , F20.12 , F20.12 )' ) ' Angular velocity:',vang(1:3)
    2376             : !MK          END IF
    2377           2 :             DEALLOCATE (is_fixed)
    2378             :          END IF
    2379             : 
    2380             :       END IF
    2381             : 
    2382        1784 :       CALL cp_print_key_finished_output(iw, logger, print_section, "PROGRAM_RUN_INFO")
    2383             : 
    2384        1784 :       CALL timestop(handle)
    2385             : 
    2386        3568 :    END SUBROUTINE initialize_cascade
    2387             : 
    2388             : END MODULE md_vel_utils

Generated by: LCOV version 1.15