LCOV - code coverage report
Current view: top level - src/motion/thermostat - al_system_dynamics.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:71c3ab0) Lines: 77.8 % 90 70
Test Date: 2026-07-25 06:35:44 Functions: 75.0 % 4 3

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \author Noam Bernstein [noamb] 02.2012
      10              : ! **************************************************************************************************
      11              : MODULE al_system_dynamics
      12              : 
      13              :    USE al_system_types,                 ONLY: al_system_type
      14              :    USE atomic_kind_types,               ONLY: atomic_kind_type,&
      15              :                                               get_atomic_kind
      16              :    USE constraint_fxd,                  ONLY: fix_atom_control
      17              :    USE distribution_1d_types,           ONLY: distribution_1d_type
      18              :    USE extended_system_types,           ONLY: map_info_type
      19              :    USE force_env_types,                 ONLY: force_env_type
      20              :    USE kinds,                           ONLY: dp
      21              :    USE message_passing,                 ONLY: mp_comm_type
      22              :    USE molecule_kind_types,             ONLY: molecule_kind_type
      23              :    USE molecule_types,                  ONLY: get_molecule,&
      24              :                                               molecule_type
      25              :    USE particle_types,                  ONLY: particle_type
      26              :    USE thermostat_utils,                ONLY: ke_region_particles,&
      27              :                                               vel_rescale_particles
      28              : #include "../../base/base_uses.f90"
      29              : 
      30              :    IMPLICIT NONE
      31              : 
      32              :    PRIVATE
      33              :    LOGICAL, PARAMETER :: debug_this_module = .FALSE.
      34              :    PUBLIC :: al_particles
      35              : 
      36              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'al_system_dynamics'
      37              : 
      38              : CONTAINS
      39              : 
      40              : ! **************************************************************************************************
      41              : !> \brief ...
      42              : !> \param al ...
      43              : !> \param force_env ...
      44              : !> \param molecule_kind_set ...
      45              : !> \param molecule_set ...
      46              : !> \param particle_set ...
      47              : !> \param local_molecules ...
      48              : !> \param local_particles ...
      49              : !> \param group ...
      50              : !> \param vel ...
      51              : !> \author Noam Bernstein [noamb] 02.2012
      52              : ! **************************************************************************************************
      53           32 :    SUBROUTINE al_particles(al, force_env, molecule_kind_set, molecule_set, &
      54           16 :                            particle_set, local_molecules, local_particles, group, vel)
      55              : 
      56              :       TYPE(al_system_type), POINTER                      :: al
      57              :       TYPE(force_env_type), POINTER                      :: force_env
      58              :       TYPE(molecule_kind_type), POINTER                  :: molecule_kind_set(:)
      59              :       TYPE(molecule_type), POINTER                       :: molecule_set(:)
      60              :       TYPE(particle_type), POINTER                       :: particle_set(:)
      61              :       TYPE(distribution_1d_type), POINTER                :: local_molecules, local_particles
      62              :       TYPE(mp_comm_type), INTENT(IN)                     :: group
      63              :       REAL(KIND=dp), INTENT(INOUT), OPTIONAL             :: vel(:, :)
      64              : 
      65              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'al_particles'
      66              : 
      67              :       INTEGER                                            :: handle
      68              :       LOGICAL                                            :: my_shell_adiabatic
      69              :       TYPE(map_info_type), POINTER                       :: map_info
      70              : 
      71           16 :       CALL timeset(routineN, handle)
      72           16 :       my_shell_adiabatic = .FALSE.
      73           16 :       map_info => al%map_info
      74              : 
      75              :       IF (debug_this_module) THEN
      76              :          CALL dump_vel(molecule_kind_set, molecule_set, local_molecules, particle_set, vel, "INIT")
      77              :       END IF
      78              : 
      79           16 :       IF (al%tau_nh <= 0.0_dp) THEN
      80              :          CALL al_OU_step(0.5_dp, al, force_env, map_info, molecule_kind_set, molecule_set, &
      81            0 :                          particle_set, local_molecules, local_particles, vel)
      82              :          IF (debug_this_module) THEN
      83              :             CALL dump_vel(molecule_kind_set, molecule_set, local_molecules, particle_set, vel, "post OU")
      84              :          END IF
      85              :       ELSE
      86              :          ! quarter step of Langevin using Ornstein-Uhlenbeck
      87              :          CALL al_OU_step(0.25_dp, al, force_env, map_info, molecule_kind_set, molecule_set, &
      88           24 :                          particle_set, local_molecules, local_particles, vel)
      89              :          IF (debug_this_module) THEN
      90              :             CALL dump_vel(molecule_kind_set, molecule_set, local_molecules, particle_set, vel, "post 1st OU")
      91              :          END IF
      92              : 
      93              :          ! Compute the kinetic energy for the region to thermostat for the (T dependent chi step)
      94              :          CALL ke_region_particles(map_info, particle_set, molecule_kind_set, &
      95           24 :                                   local_molecules, molecule_set, group, vel=vel)
      96              :          ! quarter step of chi, and set vel drag factors for a half step
      97           16 :          CALL al_NH_quarter_step(al, map_info, set_half_step_vel_factors=.TRUE.)
      98              : 
      99              :          ! Now scale the particle velocities for a NH half step
     100              :          CALL vel_rescale_particles(map_info, molecule_kind_set, molecule_set, particle_set, &
     101           24 :                                     local_molecules, my_shell_adiabatic, vel=vel)
     102              :          ! Recompute the kinetic energy for the region to thermostat (for the T dependent chi step)
     103              :          CALL ke_region_particles(map_info, particle_set, molecule_kind_set, &
     104           24 :                                   local_molecules, molecule_set, group, vel=vel)
     105              :          IF (debug_this_module) THEN
     106              :             CALL dump_vel(molecule_kind_set, molecule_set, local_molecules, particle_set, vel, "post rescale_vel")
     107              :          END IF
     108              : 
     109              :          ! quarter step of chi
     110           16 :          CALL al_NH_quarter_step(al, map_info, set_half_step_vel_factors=.FALSE.)
     111              : 
     112              :          ! quarter step of Langevin using Ornstein-Uhlenbeck
     113              :          CALL al_OU_step(0.25_dp, al, force_env, map_info, molecule_kind_set, molecule_set, &
     114           24 :                          particle_set, local_molecules, local_particles, vel)
     115              :          IF (debug_this_module) THEN
     116              :             CALL dump_vel(molecule_kind_set, molecule_set, local_molecules, particle_set, vel, "post 2nd OU")
     117              :          END IF
     118              :       END IF
     119              : 
     120              :       ! Recompute the final kinetic energy for the region to thermostat
     121              :       CALL ke_region_particles(map_info, particle_set, molecule_kind_set, &
     122           24 :                                local_molecules, molecule_set, group, vel=vel)
     123              : 
     124           16 :       CALL timestop(handle)
     125           16 :    END SUBROUTINE al_particles
     126              : 
     127              : ! **************************************************************************************************
     128              : !> \brief ...
     129              : !> \param molecule_kind_set ...
     130              : !> \param molecule_set ...
     131              : !> \param local_molecules ...
     132              : !> \param particle_set ...
     133              : !> \param vel ...
     134              : !> \param label ...
     135              : ! **************************************************************************************************
     136            0 :    SUBROUTINE dump_vel(molecule_kind_set, molecule_set, local_molecules, particle_set, vel, label)
     137              :       TYPE(molecule_kind_type), POINTER                  :: molecule_kind_set(:)
     138              :       TYPE(molecule_type), POINTER                       :: molecule_set(:)
     139              :       TYPE(distribution_1d_type), POINTER                :: local_molecules
     140              :       TYPE(particle_type), POINTER                       :: particle_set(:)
     141              :       REAL(dp), OPTIONAL                                 :: vel(:, :)
     142              :       CHARACTER(len=*)                                   :: label
     143              : 
     144              :       INTEGER                                            :: first_atom, ikind, imol, imol_local, &
     145              :                                                             ipart, last_atom, nmol_local
     146              :       TYPE(molecule_type), POINTER                       :: molecule
     147              : 
     148            0 :       DO ikind = 1, SIZE(molecule_kind_set)
     149            0 :          nmol_local = local_molecules%n_el(ikind)
     150            0 :          DO imol_local = 1, nmol_local
     151            0 :             imol = local_molecules%list(ikind)%array(imol_local)
     152            0 :             molecule => molecule_set(imol)
     153            0 :             CALL get_molecule(molecule, first_atom=first_atom, last_atom=last_atom)
     154            0 :             DO ipart = first_atom, last_atom
     155            0 :                IF (PRESENT(vel)) THEN
     156            0 :                   WRITE (unit=*, fmt='("VEL ",A20," IPART ",I6," V ",3F20.10)') TRIM(label), ipart, vel(:, ipart)
     157              :                ELSE
     158            0 :                   WRITE (unit=*, fmt='("PARTICLE_SET%VEL ",A20," IPART ",I6," V ",3F20.10)') TRIM(label), &
     159            0 :                      ipart, particle_set(ipart)%v(:)
     160              :                END IF
     161              :             END DO
     162              :          END DO
     163              :       END DO
     164            0 :    END SUBROUTINE dump_vel
     165              : 
     166              : ! **************************************************************************************************
     167              : !> \brief ...
     168              : !> \param step ...
     169              : !> \param al ...
     170              : !> \param force_env ...
     171              : !> \param map_info ...
     172              : !> \param molecule_kind_set ...
     173              : !> \param molecule_set ...
     174              : !> \param particle_set ...
     175              : !> \param local_molecules ...
     176              : !> \param local_particles ...
     177              : !> \param vel ...
     178              : ! **************************************************************************************************
     179           32 :    SUBROUTINE al_OU_step(step, al, force_env, map_info, molecule_kind_set, molecule_set, &
     180           32 :                          particle_set, local_molecules, local_particles, vel)
     181              :       REAL(dp), INTENT(in)                               :: step
     182              :       TYPE(al_system_type), POINTER                      :: al
     183              :       TYPE(force_env_type), POINTER                      :: force_env
     184              :       TYPE(map_info_type), POINTER                       :: map_info
     185              :       TYPE(molecule_kind_type), POINTER                  :: molecule_kind_set(:)
     186              :       TYPE(molecule_type), POINTER                       :: molecule_set(:)
     187              :       TYPE(particle_type), POINTER                       :: particle_set(:)
     188              :       TYPE(distribution_1d_type), POINTER                :: local_molecules, local_particles
     189              :       REAL(KIND=dp), INTENT(INOUT), OPTIONAL             :: vel(:, :)
     190              : 
     191              :       INTEGER :: first_atom, i, ii, ikind, imap, imol, imol_local, ipart, iparticle_kind, &
     192              :          iparticle_local, jj, last_atom, nmol_local, nparticle, nparticle_kind, nparticle_local
     193              :       LOGICAL                                            :: check, present_vel
     194              :       REAL(KIND=dp)                                      :: mass
     195           32 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: w
     196              :       TYPE(atomic_kind_type), POINTER                    :: atomic_kind
     197              :       TYPE(molecule_type), POINTER                       :: molecule
     198              : 
     199           32 :       present_vel = PRESENT(vel)
     200              : 
     201              :       ![NB] not a big deal, but could this be done once at init time?
     202       396776 :       DO i = 1, al%loc_num_al
     203       396744 :          imap = map_info%map_index(i)
     204              :          ! drag on velocities
     205       396776 :          IF (al%tau_langevin > 0.0_dp) THEN
     206       396744 :             map_info%v_scale(imap) = EXP(-step*al%dt/al%tau_langevin)
     207       396744 :             map_info%s_kin(imap) = SQRT((al%nvt(i)%nkt/al%nvt(i)%degrees_of_freedom)*(1.0_dp - map_info%v_scale(imap)**2))
     208              :          ELSE
     209            0 :             map_info%v_scale(imap) = 1.0_dp
     210            0 :             map_info%s_kin(imap) = 0.0_dp
     211              :          END IF
     212              :          ! magnitude of random force, not including 1/sqrt(mass) part
     213              :       END DO
     214              : 
     215           32 :       nparticle = SIZE(particle_set)
     216           32 :       nparticle_kind = SIZE(local_particles%n_el)
     217           96 :       ALLOCATE (w(3, nparticle))
     218           32 :       w(:, :) = 0.0_dp
     219           32 :       check = (nparticle_kind <= SIZE(local_particles%n_el) .AND. nparticle_kind <= SIZE(local_particles%list))
     220            0 :       CPASSERT(check)
     221           32 :       check = ASSOCIATED(local_particles%local_particle_set)
     222           32 :       CPASSERT(check)
     223         5152 :       DO iparticle_kind = 1, nparticle_kind
     224         5120 :          nparticle_local = local_particles%n_el(iparticle_kind)
     225         5120 :          check = (nparticle_local <= SIZE(local_particles%list(iparticle_kind)%array))
     226         5120 :          CPASSERT(check)
     227       137400 :          DO iparticle_local = 1, nparticle_local
     228       132248 :             ipart = local_particles%list(iparticle_kind)%array(iparticle_local)
     229       132248 :             w(1, ipart) = local_particles%local_particle_set(iparticle_kind)%rng(iparticle_local)%stream%next(variance=1.0_dp)
     230       132248 :             w(2, ipart) = local_particles%local_particle_set(iparticle_kind)%rng(iparticle_local)%stream%next(variance=1.0_dp)
     231       137368 :             w(3, ipart) = local_particles%local_particle_set(iparticle_kind)%rng(iparticle_local)%stream%next(variance=1.0_dp)
     232              :          END DO
     233              :       END DO
     234              : 
     235           32 :       CALL fix_atom_control(force_env, w)
     236              : 
     237           32 :       ii = 0
     238        61320 :       DO ikind = 1, SIZE(molecule_kind_set)
     239        61288 :          nmol_local = local_molecules%n_el(ikind)
     240       101200 :          DO imol_local = 1, nmol_local
     241        39880 :             imol = local_molecules%list(ikind)%array(imol_local)
     242        39880 :             molecule => molecule_set(imol)
     243        39880 :             CALL get_molecule(molecule, first_atom=first_atom, last_atom=last_atom)
     244       233416 :             DO ipart = first_atom, last_atom
     245       132248 :                ii = ii + 1
     246       132248 :                atomic_kind => particle_set(ipart)%atomic_kind
     247       132248 :                CALL get_atomic_kind(atomic_kind=atomic_kind, mass=mass)
     248       172128 :                IF (present_vel) THEN
     249       264496 :                   DO jj = 1, 3
     250              :                      vel(jj, ipart) = vel(jj, ipart)*map_info%p_scale(jj, ii)%point + &
     251       264496 :                                       map_info%p_kin(jj, ii)%point/SQRT(mass)*w(jj, ipart)
     252              :                   END DO
     253              :                ELSE
     254       264496 :                   DO jj = 1, 3
     255              :                      particle_set(ipart)%v(jj) = particle_set(ipart)%v(jj)*map_info%p_scale(jj, ii)%point + &
     256       264496 :                                                  map_info%p_kin(jj, ii)%point/SQRT(mass)*w(jj, ipart)
     257              :                   END DO
     258              :                END IF
     259              :             END DO
     260              :          END DO
     261              :       END DO
     262              : 
     263           32 :       DEALLOCATE (w)
     264              : 
     265           32 :    END SUBROUTINE al_OU_step
     266              : 
     267              : ! **************************************************************************************************
     268              : !> \brief ...
     269              : !> \param al ...
     270              : !> \param map_info ...
     271              : !> \param set_half_step_vel_factors ...
     272              : !> \author Noam Bernstein [noamb] 02.2012
     273              : ! **************************************************************************************************
     274           32 :    SUBROUTINE al_NH_quarter_step(al, map_info, set_half_step_vel_factors)
     275              :       TYPE(al_system_type), POINTER                      :: al
     276              :       TYPE(map_info_type), POINTER                       :: map_info
     277              :       LOGICAL, INTENT(in)                                :: set_half_step_vel_factors
     278              : 
     279              :       INTEGER                                            :: i, imap
     280              :       REAL(KIND=dp)                                      :: decay, delta_K
     281              : 
     282              : ![NB] how to deal with dt_fact?
     283              : 
     284       396776 :       DO i = 1, al%loc_num_al
     285       396776 :          IF (al%nvt(i)%mass > 0.0_dp) THEN
     286       396744 :             imap = map_info%map_index(i)
     287       396744 :             delta_K = 0.5_dp*(map_info%s_kin(imap) - al%nvt(i)%nkt)
     288       396744 :             al%nvt(i)%chi = al%nvt(i)%chi + 0.5_dp*al%dt*delta_K/al%nvt(i)%mass
     289       396744 :             IF (set_half_step_vel_factors) THEN
     290       198372 :                decay = EXP(-0.5_dp*al%dt*al%nvt(i)%chi)
     291       198372 :                map_info%v_scale(imap) = decay
     292              :             END IF
     293              :          ELSE
     294            0 :             al%nvt(i)%chi = 0.0_dp
     295            0 :             IF (set_half_step_vel_factors) THEN
     296            0 :                map_info%v_scale(imap) = 1.0_dp
     297              :             END IF
     298              :          END IF
     299              :       END DO
     300              : 
     301           32 :    END SUBROUTINE al_NH_quarter_step
     302              : 
     303              : END MODULE al_system_dynamics
        

Generated by: LCOV version 2.0-1