LCOV - code coverage report
Current view: top level - src/motion - pint_normalmode.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:7641cd9) Lines: 96.3 % 107 103
Test Date: 2026-05-25 07:16:39 Functions: 100.0 % 7 7

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief  Data type and methods dealing with PI calcs in normal mode coords
      10              : !> \author fawzi
      11              : !> \par    History
      12              : !>         2006-02 created
      13              : !>         2006-11 modified so it might actually work [hforbert]
      14              : !>         2009-04-07 moved from pint_types module to a separate file [lwalewski]
      15              : !>         2015-10 added alternative normal mode transformation needed by RPMD
      16              : !>                 [Felix Uhl
      17              : ! **************************************************************************************************
      18              : MODULE pint_normalmode
      19              :    USE input_constants,                 ONLY: propagator_bcmd,&
      20              :                                               propagator_cmd,&
      21              :                                               propagator_pimd,&
      22              :                                               propagator_rpmd
      23              :    USE input_section_types,             ONLY: section_vals_type,&
      24              :                                               section_vals_val_get
      25              :    USE kinds,                           ONLY: dp
      26              :    USE mathconstants,                   ONLY: pi,&
      27              :                                               twopi
      28              :    USE pint_types,                      ONLY: normalmode_env_type
      29              : #include "../base/base_uses.f90"
      30              : 
      31              :    IMPLICIT NONE
      32              :    PRIVATE
      33              : 
      34              :    LOGICAL, PRIVATE, PARAMETER :: debug_this_module = .TRUE.
      35              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'pint_normalmode'
      36              : 
      37              :    PUBLIC :: normalmode_env_create
      38              :    PUBLIC :: normalmode_release
      39              :    PUBLIC :: normalmode_init_masses
      40              :    PUBLIC :: normalmode_x2u
      41              :    PUBLIC :: normalmode_u2x
      42              :    PUBLIC :: normalmode_f2uf
      43              :    PUBLIC :: normalmode_calc_uf_h
      44              : 
      45              : CONTAINS
      46              : 
      47              : ! ***************************************************************************
      48              : !> \brief creates the data needed for a normal mode transformation
      49              : !> \param normalmode_env ...
      50              : !> \param normalmode_section ...
      51              : !> \param p ...
      52              : !> \param kT ...
      53              : !> \param propagator ...
      54              : !> \author Harald Forbert
      55              : ! **************************************************************************************************
      56           58 :    SUBROUTINE normalmode_env_create(normalmode_env, normalmode_section, p, kT, propagator)
      57              :       TYPE(normalmode_env_type), INTENT(OUT)             :: normalmode_env
      58              :       TYPE(section_vals_type), POINTER                   :: normalmode_section
      59              :       INTEGER, INTENT(in)                                :: p
      60              :       REAL(kind=dp), INTENT(in)                          :: kT
      61              :       INTEGER, INTENT(in)                                :: propagator
      62              : 
      63              :       INTEGER                                            :: i, j, k, li
      64              :       LOGICAL                                            :: explicit_gamma, explicit_modefactor
      65              :       REAL(kind=dp)                                      :: gamma_parameter, invsqrtp, pip, sqrt2p, &
      66              :                                                             twopip
      67              : 
      68          232 :       ALLOCATE (normalmode_env%x2u(p, p))
      69          174 :       ALLOCATE (normalmode_env%u2x(p, p))
      70          174 :       ALLOCATE (normalmode_env%lambda(p))
      71              : 
      72           58 :       normalmode_env%p = p
      73              : 
      74              :       CALL section_vals_val_get(normalmode_section, "Q_CENTROID", &
      75           58 :                                 r_val=normalmode_env%Q_centroid)
      76              :       CALL section_vals_val_get(normalmode_section, "Q_BEAD", &
      77           58 :                                 r_val=normalmode_env%Q_bead)
      78              :       CALL section_vals_val_get(normalmode_section, "MODEFACTOR", &
      79              :                                 explicit=explicit_modefactor, &
      80           58 :                                 r_val=normalmode_env%modefactor)
      81              :       CALL section_vals_val_get(normalmode_section, "GAMMA", &
      82              :                                 r_val=gamma_parameter, &
      83           58 :                                 explicit=explicit_gamma)
      84              : 
      85           58 :       IF (explicit_modefactor .AND. explicit_gamma) THEN
      86            0 :          CPABORT("Both GAMMA and MODEFACTOR have been declared. Please use only one.")
      87              :       END IF
      88           58 :       IF (explicit_gamma) THEN
      89            4 :          normalmode_env%modefactor = 1.0_dp/gamma_parameter**2
      90              :       END IF
      91              : 
      92           58 :       IF (propagator == propagator_cmd) THEN
      93            4 :          IF (.NOT. explicit_gamma) THEN
      94            0 :             CPABORT("GAMMA needs to be specified with CMD PROPAGATOR")
      95              :          END IF
      96            4 :          IF (gamma_parameter <= 1.0_dp) THEN
      97            0 :             CPWARN("GAMMA should be larger than 1.0 for CMD PROPAGATOR")
      98              :          END IF
      99              :       END IF
     100              : 
     101           58 :       IF (normalmode_env%Q_centroid < 0.0_dp) THEN
     102           58 :          normalmode_env%Q_centroid = -normalmode_env%Q_centroid/(kT*p)
     103              :       END IF
     104           58 :       IF (normalmode_env%Q_bead < 0.0_dp) THEN
     105           58 :          normalmode_env%Q_bead = -normalmode_env%Q_bead/(kT*p)
     106              :       END IF
     107              : 
     108              :       !Use different normal mode transformations depending on the propagator
     109           58 :       IF (propagator == propagator_pimd .OR. propagator == propagator_cmd .OR. &
     110              :           propagator == propagator_bcmd) THEN
     111              : 
     112           40 :          IF (propagator == propagator_pimd .OR. propagator == propagator_bcmd) THEN
     113           36 :             normalmode_env%harm = p*kT*kT/normalmode_env%modefactor
     114            4 :          ELSE IF (propagator == propagator_cmd) THEN
     115            4 :             normalmode_env%harm = p*kT*kT*gamma_parameter*gamma_parameter
     116            4 :             normalmode_env%modefactor = 1.0_dp/(gamma_parameter*gamma_parameter)
     117              :          END IF
     118              : 
     119              :          ! set up the transformation matrices
     120          224 :          DO i = 1, p
     121          184 :             normalmode_env%lambda(i) = 2.0_dp*(1.0_dp - COS(pi*(i/2)*2.0_dp/p))
     122         1248 :             DO j = 1, p
     123         1024 :                k = ((i/2)*(j - 1))/p
     124         1024 :                k = (i/2)*(j - 1) - k*p
     125         1024 :                li = 2*(i - 2*(i/2))*p - p
     126         1208 :                normalmode_env%u2x(j, i) = SQRT(2.0_dp/p)*SIN(twopi*(k + 0.125_dp*li)/p)
     127              :             END DO
     128              :          END DO
     129           40 :          normalmode_env%lambda(1) = 1.0_dp/(p*normalmode_env%modefactor)
     130          224 :          DO i = 1, p
     131         1248 :             DO j = 1, p
     132              :                normalmode_env%x2u(i, j) = SQRT(normalmode_env%lambda(i)* &
     133              :                                                normalmode_env%modefactor)* &
     134         1208 :                                           normalmode_env%u2x(j, i)
     135              :             END DO
     136              :          END DO
     137          224 :          DO i = 1, p
     138         1248 :             DO j = 1, p
     139              :                normalmode_env%u2x(i, j) = normalmode_env%u2x(i, j)/ &
     140              :                                           SQRT(normalmode_env%lambda(j)* &
     141         1208 :                                                normalmode_env%modefactor)
     142              :             END DO
     143              :          END DO
     144          224 :          normalmode_env%lambda(:) = normalmode_env%harm
     145              : 
     146           18 :       ELSE IF (propagator == propagator_rpmd) THEN
     147           18 :          normalmode_env%harm = kT/normalmode_env%modefactor
     148           18 :          sqrt2p = SQRT(2.0_dp/REAL(p, dp))
     149           18 :          twopip = twopi/REAL(p, dp)
     150           18 :          pip = pi/REAL(p, dp)
     151           18 :          invsqrtp = 1.0_dp/SQRT(REAL(p, dp))
     152         3226 :          normalmode_env%x2u(:, :) = 0.0_dp
     153          186 :          normalmode_env%x2u(1, :) = invsqrtp
     154          186 :          DO j = 1, p
     155         1688 :             DO i = 2, p/2 + 1
     156         1688 :                normalmode_env%x2u(i, j) = sqrt2p*COS(twopip*(i - 1)*(j - 1))
     157              :             END DO
     158         1538 :             DO i = p/2 + 2, p
     159         1520 :                normalmode_env%x2u(i, j) = sqrt2p*SIN(twopip*(i - 1)*(j - 1))
     160              :             END DO
     161              :          END DO
     162           18 :          IF (MOD(p, 2) == 0) THEN
     163           18 :             DO i = 1, p - 1, 2
     164           84 :                normalmode_env%x2u(p/2 + 1, i) = invsqrtp
     165           84 :                normalmode_env%x2u(p/2 + 1, i + 1) = -1.0_dp*invsqrtp
     166              :             END DO
     167              :          END IF
     168              : 
     169         6434 :          normalmode_env%u2x = TRANSPOSE(normalmode_env%x2u)
     170              : 
     171              :          ! Setting up propagator frequencies for rpmd
     172           18 :          normalmode_env%lambda(1) = 0.0_dp
     173          168 :          DO i = 2, p
     174          150 :             normalmode_env%lambda(i) = 2.0_dp*normalmode_env%harm*SIN((i - 1)*pip)
     175          168 :             normalmode_env%lambda(i) = normalmode_env%lambda(i)*normalmode_env%lambda(i)
     176              :          END DO
     177           18 :          normalmode_env%harm = kT*kT
     178              :       ELSE
     179            0 :          CPABORT("UNKNOWN PROPAGATOR FOR PINT SELECTED")
     180              :       END IF
     181              : 
     182           58 :    END SUBROUTINE normalmode_env_create
     183              : 
     184              : ! ***************************************************************************
     185              : !> \brief releases the normalmode environment
     186              : !> \param normalmode_env the normalmode_env to release
     187              : !> \author Harald Forbert
     188              : ! **************************************************************************************************
     189           58 :    PURE SUBROUTINE normalmode_release(normalmode_env)
     190              : 
     191              :       TYPE(normalmode_env_type), INTENT(INOUT)           :: normalmode_env
     192              : 
     193           58 :       DEALLOCATE (normalmode_env%x2u)
     194           58 :       DEALLOCATE (normalmode_env%u2x)
     195           58 :       DEALLOCATE (normalmode_env%lambda)
     196              : 
     197           58 :    END SUBROUTINE normalmode_release
     198              : 
     199              : ! ***************************************************************************
     200              : !> \brief initializes the masses and fictitious masses compatible with the
     201              : !>      normal mode information
     202              : !> \param normalmode_env the definition of the normal mode transformation
     203              : !> \param mass *input* the masses of the particles
     204              : !> \param mass_beads masses of the beads
     205              : !> \param mass_fict the fictitious masses
     206              : !> \param Q masses of the nose thermostats
     207              : !> \author Harald Forbert
     208              : ! **************************************************************************************************
     209           58 :    PURE SUBROUTINE normalmode_init_masses(normalmode_env, mass, mass_beads, mass_fict, &
     210           58 :                                           Q)
     211              : 
     212              :       TYPE(normalmode_env_type), INTENT(IN)              :: normalmode_env
     213              :       REAL(kind=dp), DIMENSION(:), INTENT(in)            :: mass
     214              :       REAL(kind=dp), DIMENSION(:, :), INTENT(out), &
     215              :          OPTIONAL                                        :: mass_beads, mass_fict
     216              :       REAL(kind=dp), DIMENSION(:), INTENT(out), OPTIONAL :: Q
     217              : 
     218              :       INTEGER                                            :: iat, ib
     219              : 
     220           58 :       IF (PRESENT(Q)) THEN
     221          410 :          Q = normalmode_env%Q_bead
     222           58 :          Q(1) = normalmode_env%Q_centroid
     223              :       END IF
     224           58 :       IF (PRESENT(mass_beads) .OR. PRESENT(mass_fict)) THEN
     225           58 :          IF (PRESENT(mass_beads)) THEN
     226        64984 :             DO iat = 1, SIZE(mass)
     227        64926 :                mass_beads(1, iat) = 0.0_dp
     228       297706 :                DO ib = 2, normalmode_env%p
     229       297648 :                   mass_beads(ib, iat) = mass(iat)
     230              :                END DO
     231              :             END DO
     232              :          END IF
     233           58 :          IF (PRESENT(mass_fict)) THEN
     234        64984 :             DO iat = 1, SIZE(mass)
     235       362632 :                DO ib = 1, normalmode_env%p
     236       362574 :                   mass_fict(ib, iat) = mass(iat)
     237              :                END DO
     238              :             END DO
     239              :          END IF
     240              :       END IF
     241              : 
     242           58 :    END SUBROUTINE normalmode_init_masses
     243              : 
     244              : ! ***************************************************************************
     245              : !> \brief Transforms from the x into the u variables using a normal mode
     246              : !>      transformation for the positions
     247              : !> \param normalmode_env the environment for the normal mode transformation
     248              : !> \param ux will contain the u variable
     249              : !> \param x the positions to transform
     250              : !> \author Harald Forbert
     251              : ! **************************************************************************************************
     252           97 :    SUBROUTINE normalmode_x2u(normalmode_env, ux, x)
     253              :       TYPE(normalmode_env_type), INTENT(INOUT)           :: normalmode_env
     254              :       REAL(kind=dp), DIMENSION(:, :), INTENT(out)        :: ux
     255              :       REAL(kind=dp), DIMENSION(:, :), INTENT(in)         :: x
     256              : 
     257              :       CALL DGEMM('N', 'N', normalmode_env%p, SIZE(x, 2), normalmode_env%p, 1.0_dp, &
     258              :                  normalmode_env%x2u(1, 1), SIZE(normalmode_env%x2u, 1), x(1, 1), SIZE(x, 1), &
     259           97 :                  0.0_dp, ux, SIZE(ux, 1))
     260           97 :    END SUBROUTINE normalmode_x2u
     261              : 
     262              : ! ***************************************************************************
     263              : !> \brief transform from the u variable to the x (back normal mode
     264              : !>      transformation for the positions)
     265              : !> \param normalmode_env the environment for the normal mode transformation
     266              : !> \param ux the u variable (positions to be backtransformed)
     267              : !> \param x will contain the positions
     268              : !> \author Harald Forbert
     269              : ! **************************************************************************************************
     270         3247 :    SUBROUTINE normalmode_u2x(normalmode_env, ux, x)
     271              :       TYPE(normalmode_env_type), INTENT(INOUT)           :: normalmode_env
     272              :       REAL(kind=dp), DIMENSION(:, :), INTENT(in)         :: ux
     273              :       REAL(kind=dp), DIMENSION(:, :), INTENT(out)        :: x
     274              : 
     275              :       CALL DGEMM('N', 'N', normalmode_env%p, SIZE(ux, 2), normalmode_env%p, 1.0_dp, &
     276              :                  normalmode_env%u2x(1, 1), SIZE(normalmode_env%u2x, 1), ux(1, 1), SIZE(ux, 1), &
     277         3247 :                  0.0_dp, x, SIZE(x, 1))
     278         3247 :    END SUBROUTINE normalmode_u2x
     279              : 
     280              : ! ***************************************************************************
     281              : !> \brief normalmode transformation for the forces
     282              : !> \param normalmode_env the environment for the normal mode transformation
     283              : !> \param uf will contain the forces for the transformed variables afterwards
     284              : !> \param f the forces to transform
     285              : !> \author Harald Forbert
     286              : ! **************************************************************************************************
     287          712 :    SUBROUTINE normalmode_f2uf(normalmode_env, uf, f)
     288              :       TYPE(normalmode_env_type), INTENT(INOUT)           :: normalmode_env
     289              :       REAL(kind=dp), DIMENSION(:, :), INTENT(out)        :: uf
     290              :       REAL(kind=dp), DIMENSION(:, :), INTENT(in)         :: f
     291              : 
     292              :       CALL DGEMM('T', 'N', normalmode_env%p, SIZE(f, 2), normalmode_env%p, 1.0_dp, &
     293              :                  normalmode_env%u2x(1, 1), SIZE(normalmode_env%u2x, 1), f(1, 1), SIZE(f, 1), &
     294          712 :                  0.0_dp, uf, SIZE(uf, 1))
     295          712 :    END SUBROUTINE normalmode_f2uf
     296              : 
     297              : ! ***************************************************************************
     298              : !> \brief calculates the harmonic force in the normal mode basis
     299              : !> \param normalmode_env the normal mode environment
     300              : !> \param mass_beads the masses of the beads
     301              : !> \param ux the positions of the beads in the staging basis
     302              : !> \param uf_h the harmonic forces (not accelerations)
     303              : !> \param e_h ...
     304              : !> \author Harald Forbert
     305              : ! **************************************************************************************************
     306         1446 :    PURE SUBROUTINE normalmode_calc_uf_h(normalmode_env, mass_beads, ux, uf_h, e_h)
     307              :       TYPE(normalmode_env_type), INTENT(IN)              :: normalmode_env
     308              :       REAL(kind=dp), DIMENSION(:, :), POINTER            :: mass_beads, ux, uf_h
     309              :       REAL(KIND=dp), INTENT(OUT)                         :: e_h
     310              : 
     311              :       INTEGER                                            :: ibead, idim
     312              :       REAL(kind=dp)                                      :: f
     313              : 
     314         1446 :       e_h = 0.0_dp
     315       448782 :       DO idim = 1, SIZE(mass_beads, 2)
     316              : 
     317              :          ! starting at 2 since the centroid is at 1 and it's mass_beads
     318              :          ! SHOULD be zero anyways:
     319              : 
     320       447336 :          uf_h(1, idim) = 0.0_dp
     321      2124294 :          DO ibead = 2, normalmode_env%p
     322      1675512 :             f = -mass_beads(ibead, idim)*normalmode_env%lambda(ibead)*ux(ibead, idim)
     323      1675512 :             uf_h(ibead, idim) = f
     324              :             ! - to cancel the - in the force f.
     325      2122848 :             e_h = e_h - 0.5_dp*ux(ibead, idim)*f
     326              :          END DO
     327              : 
     328              :       END DO
     329         1446 :    END SUBROUTINE normalmode_calc_uf_h
     330              : 
     331              : END MODULE pint_normalmode
        

Generated by: LCOV version 2.0-1