LCOV - code coverage report
Current view: top level - src - efield_utils.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:561f475) Lines: 98.8 % 83 82
Test Date: 2026-06-21 06:48:54 Functions: 100.0 % 3 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              : !> \brief all routins needed for a nonperiodic  electric field
      10              : ! **************************************************************************************************
      11              : 
      12              : MODULE efield_utils
      13              :    USE atomic_kind_types,               ONLY: atomic_kind_type,&
      14              :                                               get_atomic_kind
      15              :    USE cell_types,                      ONLY: cell_type,&
      16              :                                               pbc
      17              :    USE cp_control_types,                ONLY: dft_control_type,&
      18              :                                               efield_type
      19              :    USE cp_dbcsr_api,                    ONLY: dbcsr_add,&
      20              :                                               dbcsr_copy,&
      21              :                                               dbcsr_p_type,&
      22              :                                               dbcsr_set
      23              :    USE cp_dbcsr_operations,             ONLY: dbcsr_allocate_matrix_set,&
      24              :                                               dbcsr_deallocate_matrix_set
      25              :    USE input_constants,                 ONLY: constant_env,&
      26              :                                               custom_env,&
      27              :                                               gaussian_env,&
      28              :                                               ramp_env
      29              :    USE kinds,                           ONLY: dp
      30              :    USE mathconstants,                   ONLY: pi,&
      31              :                                               twopi
      32              :    USE particle_types,                  ONLY: particle_type
      33              :    USE physcon,                         ONLY: c_light_au
      34              :    USE qs_energy_types,                 ONLY: qs_energy_type
      35              :    USE qs_environment_types,            ONLY: get_qs_env,&
      36              :                                               qs_environment_type
      37              :    USE qs_force_types,                  ONLY: qs_force_type
      38              :    USE qs_kind_types,                   ONLY: get_qs_kind,&
      39              :                                               qs_kind_type
      40              :    USE qs_moments,                      ONLY: build_local_moment_matrix
      41              : #include "./base/base_uses.f90"
      42              : 
      43              :    IMPLICIT NONE
      44              : 
      45              :    PRIVATE
      46              : 
      47              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'efield_utils'
      48              : 
      49              : ! *** Public subroutines ***
      50              : 
      51              :    PUBLIC :: efield_potential_lengh_gauge, &
      52              :              calculate_ecore_efield, &
      53              :              make_field
      54              : 
      55              : CONTAINS
      56              : 
      57              : ! **************************************************************************************************
      58              : !> \brief Replace the original implementation of the electric-electronic
      59              : !>        interaction in the length gauge. This calculation is no longer done in
      60              : !>        the grid but using matrices to match the velocity gauge implementation.
      61              : !>        Note: The energy is stored in energy%core and computed later on.
      62              : !> \param qs_env ...
      63              : !> \author Guillaume Le Breton (02.23)
      64              : ! **************************************************************************************************
      65              : 
      66          214 :    SUBROUTINE efield_potential_lengh_gauge(qs_env)
      67              : 
      68              :       TYPE(qs_environment_type), POINTER                 :: qs_env
      69              : 
      70              :       CHARACTER(len=*), PARAMETER :: routineN = 'efield_potential_lengh_gauge'
      71              : 
      72              :       INTEGER                                            :: handle, i, image
      73              :       REAL(kind=dp)                                      :: field(3)
      74          214 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s, moments
      75          214 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_h
      76              :       TYPE(dft_control_type), POINTER                    :: dft_control
      77              : 
      78          214 :       NULLIFY (dft_control)
      79          214 :       CALL timeset(routineN, handle)
      80              : 
      81              :       CALL get_qs_env(qs_env, &
      82              :                       dft_control=dft_control, &
      83              :                       matrix_h_kp=matrix_h, &
      84          214 :                       matrix_s=matrix_s)
      85              : 
      86          214 :       NULLIFY (moments)
      87          214 :       CALL dbcsr_allocate_matrix_set(moments, 3)
      88          856 :       DO i = 1, 3
      89          642 :          ALLOCATE (moments(i)%matrix)
      90          642 :          CALL dbcsr_copy(moments(i)%matrix, matrix_s(1)%matrix, "Moments")
      91          856 :          CALL dbcsr_set(moments(i)%matrix, 0.0_dp)
      92              :       END DO
      93              : 
      94          214 :       CALL build_local_moment_matrix(qs_env, moments, 1)
      95              : 
      96          214 :       CALL make_field(dft_control, field, qs_env%sim_step, qs_env%sim_time)
      97              : 
      98          856 :       DO i = 1, 3
      99         1498 :          DO image = 1, dft_control%nimages
     100         1284 :             CALL dbcsr_add(matrix_h(1, image)%matrix, moments(i)%matrix, 1.0_dp, field(i))
     101              :          END DO
     102              :       END DO
     103              : 
     104          214 :       CALL dbcsr_deallocate_matrix_set(moments)
     105              : 
     106          214 :       CALL timestop(handle)
     107              : 
     108          214 :    END SUBROUTINE efield_potential_lengh_gauge
     109              : 
     110              : ! **************************************************************************************************
     111              : !> \brief computes the amplitude of the efield within a given envelop
     112              : !> \param dft_control ...
     113              : !> \param field ...
     114              : !> \param sim_step ...
     115              : !> \param sim_time ...
     116              : !> \author Florian Schiffmann (02.09)
     117              : ! **************************************************************************************************
     118              : 
     119         1204 :    SUBROUTINE make_field(dft_control, field, sim_step, sim_time)
     120              :       TYPE(dft_control_type), INTENT(IN)                 :: dft_control
     121              :       REAL(dp), INTENT(OUT)                              :: field(3)
     122              :       INTEGER, INTENT(IN)                                :: sim_step
     123              :       REAL(KIND=dp), INTENT(IN)                          :: sim_time
     124              : 
     125              :       INTEGER                                            :: i, lower, nfield, upper
     126              :       REAL(dp)                                           :: E_0, env, nu, pol(3), strength
     127              :       REAL(KIND=dp)                                      :: dt
     128              :       TYPE(efield_type), POINTER                         :: efield
     129              : 
     130         1204 :       field = 0._dp
     131         1204 :       nfield = SIZE(dft_control%efield_fields)
     132         2408 :       DO i = 1, nfield
     133         1204 :          efield => dft_control%efield_fields(i)%efield
     134         1204 :          nu = 0.0_dp
     135         1204 :          IF (.NOT. efield%envelop_id == custom_env .AND. efield%wavelength > EPSILON(0.0_dp)) THEN
     136         1090 :             nu = c_light_au/(efield%wavelength) !in case of a custom efield we do not need nu
     137              :          END IF
     138         1204 :          E_0 = efield%amplitude
     139              : 
     140         4816 :          IF (DOT_PRODUCT(efield%polarisation, efield%polarisation) == 0) THEN
     141            0 :             pol(:) = 1.0_dp/3.0_dp
     142              :          ELSE
     143         8428 :             pol(:) = efield%polarisation(:)/(SQRT(DOT_PRODUCT(efield%polarisation, efield%polarisation)))
     144              :          END IF
     145              : 
     146         1204 :          SELECT CASE (efield%envelop_id)
     147              :          CASE (constant_env)
     148          212 :             IF (sim_step >= efield%envelop_i_vars(1) .AND. &
     149          118 :                 (sim_step <= efield%envelop_i_vars(2) .OR. efield%envelop_i_vars(2) < 0)) THEN
     150              :                field = field + E_0*COS(sim_time*nu*twopi + &
     151          530 :                                        efield%phase_offset*pi)*pol(:)
     152              :             END IF
     153              :          CASE (ramp_env)
     154          118 :             IF (sim_step >= efield%envelop_i_vars(1) .AND. sim_step <= efield%envelop_i_vars(2)) &
     155           52 :                strength = E_0*(sim_step - efield%envelop_i_vars(1))/(efield%envelop_i_vars(2) - efield%envelop_i_vars(1))
     156          118 :             IF (sim_step >= efield%envelop_i_vars(3) .AND. sim_step <= efield%envelop_i_vars(4)) &
     157           60 :                strength = E_0*(efield%envelop_i_vars(4) - sim_step)/(efield%envelop_i_vars(4) - efield%envelop_i_vars(3))
     158          118 :             IF (sim_step > efield%envelop_i_vars(4) .AND. efield%envelop_i_vars(4) > 0) strength = 0.0_dp
     159          118 :             IF (sim_step <= efield%envelop_i_vars(1)) strength = 0.0_dp
     160              :             field = field + strength*COS(sim_time*nu*twopi + &
     161          472 :                                          efield%phase_offset*pi)*pol(:)
     162              :          CASE (gaussian_env)
     163          760 :             env = EXP(-0.5_dp*((sim_time - efield%envelop_r_vars(1))/efield%envelop_r_vars(2))**2.0_dp)
     164              :             field = field + E_0*env*COS(sim_time*nu*twopi + &
     165         3040 :                                         efield%phase_offset*pi)*pol(:)
     166              :          CASE (custom_env)
     167          114 :             dt = efield%envelop_r_vars(1)
     168          114 :             IF (sim_time < (SIZE(efield%envelop_r_vars) - 2)*dt) THEN
     169              :                !make a linear interpolation between the two next points
     170           62 :                lower = FLOOR(sim_time/dt)
     171           62 :                upper = lower + 1
     172              :                strength = (efield%envelop_r_vars(lower + 2)*(upper*dt - sim_time) &
     173           62 :                            + efield%envelop_r_vars(upper + 2)*(sim_time - lower*dt))/dt
     174              :             ELSE
     175              :                strength = 0.0_dp
     176              :             END IF
     177         1660 :             field = field + strength*pol(:)
     178              :          CASE default
     179              :          END SELECT
     180              :       END DO
     181              : 
     182         1204 :    END SUBROUTINE make_field
     183              : 
     184              : ! **************************************************************************************************
     185              : !> \brief Computes the force and the energy due to a efield on the cores
     186              : !>        Note: In the velocity gauge, the energy term is not added because
     187              : !>        it would lead to an unbalanced energy (center of negative charge not
     188              : !>        involved in the electric energy in this gauge).
     189              : !> \param qs_env ...
     190              : !> \param calculate_forces ...
     191              : !> \author Florian Schiffmann (02.09)
     192              : ! **************************************************************************************************
     193              : 
     194        18797 :    SUBROUTINE calculate_ecore_efield(qs_env, calculate_forces)
     195              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     196              :       LOGICAL, OPTIONAL                                  :: calculate_forces
     197              : 
     198              :       CHARACTER(len=*), PARAMETER :: routineN = 'calculate_ecore_efield'
     199              : 
     200              :       INTEGER                                            :: atom_a, handle, iatom, ikind, natom, &
     201              :                                                             nkind
     202        18797 :       INTEGER, DIMENSION(:), POINTER                     :: list
     203              :       LOGICAL                                            :: my_force
     204              :       REAL(KIND=dp)                                      :: efield_ener, zeff
     205              :       REAL(KIND=dp), DIMENSION(3)                        :: field, r
     206        18797 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     207              :       TYPE(cell_type), POINTER                           :: cell
     208              :       TYPE(dft_control_type), POINTER                    :: dft_control
     209        18797 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     210              :       TYPE(qs_energy_type), POINTER                      :: energy
     211        18797 :       TYPE(qs_force_type), DIMENSION(:), POINTER         :: force
     212        18797 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     213              : 
     214        18797 :       NULLIFY (dft_control)
     215        18797 :       CALL timeset(routineN, handle)
     216        18797 :       CALL get_qs_env(qs_env, dft_control=dft_control)
     217        18797 :       IF (dft_control%apply_efield_field .OR. dft_control%apply_vector_potential) THEN
     218          322 :          my_force = .FALSE.
     219          322 :          IF (PRESENT(calculate_forces)) my_force = calculate_forces
     220              : 
     221              :          CALL get_qs_env(qs_env=qs_env, &
     222              :                          atomic_kind_set=atomic_kind_set, &
     223              :                          qs_kind_set=qs_kind_set, &
     224              :                          energy=energy, &
     225              :                          particle_set=particle_set, &
     226          322 :                          cell=cell)
     227          322 :          efield_ener = 0.0_dp
     228          322 :          nkind = SIZE(atomic_kind_set)
     229          322 :          CALL make_field(dft_control, field, qs_env%sim_step, qs_env%sim_time)
     230              : 
     231          722 :          DO ikind = 1, SIZE(atomic_kind_set)
     232          400 :             CALL get_atomic_kind(atomic_kind_set(ikind), atom_list=list, natom=natom)
     233          400 :             CALL get_qs_kind(qs_kind_set(ikind), zeff=zeff)
     234              : 
     235          400 :             natom = SIZE(list)
     236         1444 :             DO iatom = 1, natom
     237          722 :                IF (dft_control%apply_efield_field) THEN
     238          510 :                   atom_a = list(iatom)
     239          510 :                   r(:) = pbc(particle_set(atom_a)%r(:), cell)
     240         2040 :                   efield_ener = efield_ener - zeff*DOT_PRODUCT(r, field)
     241              :                END IF
     242         1122 :                IF (my_force) THEN
     243          408 :                   CALL get_qs_env(qs_env=qs_env, force=force)
     244         1632 :                   force(ikind)%efield(:, iatom) = force(ikind)%efield(:, iatom) - field*zeff
     245              :                END IF
     246              :             END DO
     247              : 
     248              :          END DO
     249          322 :          IF (dft_control%apply_efield_field) energy%efield_core = efield_ener
     250              :       END IF
     251        18797 :       CALL timestop(handle)
     252        18797 :    END SUBROUTINE calculate_ecore_efield
     253              : END MODULE efield_utils
        

Generated by: LCOV version 2.0-1