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

Generated by: LCOV version 1.15