LCOV - code coverage report
Current view: top level - src - fist_efield_methods.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:2fce0f8) Lines: 124 136 91.2 %
Date: 2024-12-21 06:28:57 Functions: 2 2 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             : !> \par History
      10             : !> \author JGH
      11             : ! **************************************************************************************************
      12             : MODULE fist_efield_methods
      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_result_methods,               ONLY: cp_results_erase,&
      18             :                                               put_results
      19             :    USE cp_result_types,                 ONLY: cp_result_type
      20             :    USE fist_efield_types,               ONLY: fist_efield_type
      21             :    USE fist_environment_types,          ONLY: fist_env_get,&
      22             :                                               fist_environment_type
      23             :    USE input_section_types,             ONLY: section_get_ival,&
      24             :                                               section_vals_type,&
      25             :                                               section_vals_val_get
      26             :    USE kinds,                           ONLY: default_string_length,&
      27             :                                               dp
      28             :    USE mathconstants,                   ONLY: twopi
      29             :    USE moments_utils,                   ONLY: get_reference_point
      30             :    USE particle_types,                  ONLY: particle_type
      31             :    USE physcon,                         ONLY: debye
      32             : #include "./base/base_uses.f90"
      33             : 
      34             :    IMPLICIT NONE
      35             : 
      36             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'fist_efield_methods'
      37             : 
      38             :    PRIVATE
      39             : 
      40             :    PUBLIC :: fist_dipole, fist_efield_energy_force
      41             : 
      42             : ! **************************************************************************************************
      43             : 
      44             : CONTAINS
      45             : 
      46             : ! **************************************************************************************************
      47             : !> \brief ...
      48             : !> \param qenergy ...
      49             : !> \param qforce ...
      50             : !> \param qpv ...
      51             : !> \param atomic_kind_set ...
      52             : !> \param particle_set ...
      53             : !> \param cell ...
      54             : !> \param efield ...
      55             : !> \param use_virial ...
      56             : !> \param iunit ...
      57             : !> \param charges ...
      58             : ! **************************************************************************************************
      59         116 :    SUBROUTINE fist_efield_energy_force(qenergy, qforce, qpv, atomic_kind_set, particle_set, cell, &
      60             :                                        efield, use_virial, iunit, charges)
      61             :       REAL(KIND=dp), INTENT(OUT)                         :: qenergy
      62             :       REAL(KIND=dp), DIMENSION(:, :), INTENT(OUT)        :: qforce
      63             :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(OUT)        :: qpv
      64             :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
      65             :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
      66             :       TYPE(cell_type), POINTER                           :: cell
      67             :       TYPE(fist_efield_type), POINTER                    :: efield
      68             :       LOGICAL, INTENT(IN), OPTIONAL                      :: use_virial
      69             :       INTEGER, INTENT(IN), OPTIONAL                      :: iunit
      70             :       REAL(KIND=dp), DIMENSION(:), OPTIONAL, POINTER     :: charges
      71             : 
      72             :       COMPLEX(KIND=dp)                                   :: zeta
      73             :       COMPLEX(KIND=dp), DIMENSION(3)                     :: ggamma
      74             :       INTEGER                                            :: i, ii, iparticle_kind, iw, j
      75         116 :       INTEGER, DIMENSION(:), POINTER                     :: atom_list
      76             :       LOGICAL                                            :: use_charges, virial
      77             :       REAL(KIND=dp)                                      :: q, theta
      78             :       REAL(KIND=dp), DIMENSION(3)                        :: ci, dfilter, di, dipole, fieldpol, fq, &
      79             :                                                             gvec, ria, tmp
      80             :       TYPE(atomic_kind_type), POINTER                    :: atomic_kind
      81             : 
      82         116 :       qenergy = 0.0_dp
      83        1508 :       qforce = 0.0_dp
      84         116 :       qpv = 0.0_dp
      85             : 
      86         116 :       use_charges = .FALSE.
      87         116 :       IF (PRESENT(charges)) THEN
      88         116 :          IF (ASSOCIATED(charges)) use_charges = .TRUE.
      89             :       END IF
      90             : 
      91             :       IF (PRESENT(iunit)) THEN
      92         116 :          iw = iunit
      93             :       ELSE
      94         116 :          iw = -1
      95             :       END IF
      96             : 
      97         116 :       IF (PRESENT(use_virial)) THEN
      98         116 :          virial = use_virial
      99             :       ELSE
     100             :          virial = .FALSE.
     101             :       END IF
     102             : 
     103         464 :       fieldpol = efield%polarisation
     104         812 :       fieldpol = fieldpol/SQRT(DOT_PRODUCT(fieldpol, fieldpol))
     105         464 :       fieldpol = -fieldpol*efield%strength
     106             : 
     107         464 :       dfilter = efield%dfilter
     108             : 
     109         116 :       dipole = 0.0_dp
     110         464 :       ggamma = CMPLX(1.0_dp, 0.0_dp, KIND=dp)
     111         348 :       DO iparticle_kind = 1, SIZE(atomic_kind_set)
     112         232 :          atomic_kind => atomic_kind_set(iparticle_kind)
     113         232 :          CALL get_atomic_kind(atomic_kind=atomic_kind, qeff=q, atom_list=atom_list)
     114             :          ! TODO parallelization over atoms (local_particles)
     115         696 :          DO i = 1, SIZE(atom_list)
     116         348 :             ii = atom_list(i)
     117        1392 :             ria = particle_set(ii)%r(:)
     118        1392 :             ria = pbc(ria, cell)
     119         348 :             IF (use_charges) q = charges(ii)
     120        1392 :             DO j = 1, 3
     121        4176 :                gvec = twopi*cell%h_inv(j, :)
     122        4176 :                theta = SUM(ria(:)*gvec(:))
     123        1044 :                zeta = CMPLX(COS(theta), SIN(theta), KIND=dp)**(-q)
     124        1392 :                ggamma(j) = ggamma(j)*zeta
     125             :             END DO
     126        1624 :             qforce(1:3, ii) = q
     127             :          END DO
     128             :       END DO
     129             : 
     130         464 :       IF (ALL(REAL(ggamma, KIND=dp) /= 0.0_dp)) THEN
     131         464 :          tmp = AIMAG(ggamma)/REAL(ggamma, KIND=dp)
     132         464 :          ci = ATAN(tmp)
     133        1856 :          dipole = MATMUL(cell%hmat, ci)/twopi
     134             :       END IF
     135             : 
     136         116 :       IF (efield%displacement) THEN
     137             :          ! E = (omega/8Pi)(D - 4Pi*P)^2
     138         152 :          di = dipole/cell%deth
     139         152 :          DO i = 1, 3
     140         114 :             theta = fieldpol(i) - 2._dp*twopi*di(i)
     141         114 :             qenergy = qenergy + dfilter(i)*theta**2
     142         152 :             fq(i) = -dfilter(i)*theta
     143             :          END DO
     144          38 :          qenergy = 0.25_dp*cell%deth/twopi*qenergy
     145         152 :          DO i = 1, SIZE(qforce, 2)
     146         494 :             qforce(1:3, i) = fq(1:3)*qforce(1:3, i)
     147             :          END DO
     148             :       ELSE
     149             :          ! E = -omega*E*P
     150         312 :          qenergy = SUM(fieldpol*dipole)
     151         312 :          DO i = 1, SIZE(qforce, 2)
     152        1014 :             qforce(1:3, i) = fieldpol(1:3)*qforce(1:3, i)
     153             :          END DO
     154             :       END IF
     155             : 
     156         116 :       IF (virial) THEN
     157           6 :          DO iparticle_kind = 1, SIZE(atomic_kind_set)
     158           4 :             atomic_kind => atomic_kind_set(iparticle_kind)
     159           4 :             CALL get_atomic_kind(atomic_kind=atomic_kind, atom_list=atom_list)
     160          12 :             DO i = 1, SIZE(atom_list)
     161           6 :                ii = atom_list(i)
     162          24 :                ria = particle_set(ii)%r(:)
     163          24 :                ria = pbc(ria, cell)
     164          28 :                DO j = 1, 3
     165          78 :                   qpv(j, 1:3) = qpv(j, 1:3) + qforce(j, ii)*ria(1:3)
     166             :                END DO
     167             :             END DO
     168             :          END DO
     169             :          ! Stress tensor for constant D needs further investigation
     170           2 :          IF (efield%displacement) THEN
     171           0 :             CPABORT("Stress Tensor for constant D simulation is not working")
     172             :          END IF
     173             :       END IF
     174             : 
     175         116 :    END SUBROUTINE fist_efield_energy_force
     176             : ! **************************************************************************************************
     177             : !> \brief Evaluates the Dipole of a classical charge distribution(point-like)
     178             : !>      possibly using the berry phase formalism
     179             : !> \param fist_env ...
     180             : !> \param print_section ...
     181             : !> \param atomic_kind_set ...
     182             : !> \param particle_set ...
     183             : !> \param cell ...
     184             : !> \param unit_nr ...
     185             : !> \param charges ...
     186             : !> \par History
     187             : !>      [01.2006] created
     188             : !>      [12.2007] tlaino - University of Zurich - debug and extended
     189             : !> \author Teodoro Laino
     190             : ! **************************************************************************************************
     191       42204 :    SUBROUTINE fist_dipole(fist_env, print_section, atomic_kind_set, particle_set, &
     192             :                           cell, unit_nr, charges)
     193             :       TYPE(fist_environment_type), POINTER               :: fist_env
     194             :       TYPE(section_vals_type), POINTER                   :: print_section
     195             :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     196             :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     197             :       TYPE(cell_type), POINTER                           :: cell
     198             :       INTEGER, INTENT(IN)                                :: unit_nr
     199             :       REAL(KIND=dp), DIMENSION(:), OPTIONAL, POINTER     :: charges
     200             : 
     201             :       CHARACTER(LEN=default_string_length)               :: description, dipole_type
     202             :       COMPLEX(KIND=dp)                                   :: dzeta, dzphase(3), zeta, zphase(3)
     203             :       COMPLEX(KIND=dp), DIMENSION(3)                     :: dggamma, ggamma
     204             :       INTEGER                                            :: i, iparticle_kind, j, reference
     205       21102 :       INTEGER, DIMENSION(:), POINTER                     :: atom_list
     206             :       LOGICAL                                            :: do_berry, use_charges
     207             :       REAL(KIND=dp) :: charge_tot, ci(3), dci(3), dipole(3), dipole_deriv(3), drcc(3), dria(3), &
     208             :          dtheta, gvec(3), q, rcc(3), ria(3), theta, tmp(3), via(3)
     209       21102 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: ref_point
     210             :       TYPE(atomic_kind_type), POINTER                    :: atomic_kind
     211             :       TYPE(cp_result_type), POINTER                      :: results
     212             : 
     213       21102 :       NULLIFY (atomic_kind)
     214             :       ! Reference point
     215       42204 :       reference = section_get_ival(print_section, keyword_name="DIPOLE%REFERENCE")
     216       21102 :       NULLIFY (ref_point)
     217       21102 :       description = '[DIPOLE]'
     218       21102 :       CALL section_vals_val_get(print_section, "DIPOLE%REF_POINT", r_vals=ref_point)
     219       21102 :       CALL section_vals_val_get(print_section, "DIPOLE%PERIODIC", l_val=do_berry)
     220       21102 :       use_charges = .FALSE.
     221       21102 :       IF (PRESENT(charges)) THEN
     222       21102 :          IF (ASSOCIATED(charges)) use_charges = .TRUE.
     223             :       END IF
     224             : 
     225       21102 :       CALL get_reference_point(rcc, drcc, fist_env=fist_env, reference=reference, ref_point=ref_point)
     226             : 
     227             :       ! Dipole deriv will be the derivative of the Dipole(dM/dt=\sum e_j v_j)
     228       21102 :       dipole_deriv = 0.0_dp
     229       21102 :       dipole = 0.0_dp
     230       21102 :       IF (do_berry) THEN
     231       21102 :          dipole_type = "periodic (Berry phase)"
     232       84408 :          rcc = pbc(rcc, cell)
     233       21102 :          charge_tot = 0._dp
     234       21102 :          IF (use_charges) THEN
     235        2644 :             charge_tot = SUM(charges)
     236             :          ELSE
     237     2233942 :             DO i = 1, SIZE(particle_set)
     238     2213468 :                atomic_kind => particle_set(i)%atomic_kind
     239     2213468 :                CALL get_atomic_kind(atomic_kind=atomic_kind, qeff=q)
     240     2233942 :                charge_tot = charge_tot + q
     241             :             END DO
     242             :          END IF
     243      337632 :          ria = twopi*MATMUL(cell%h_inv, rcc)
     244       84408 :          zphase = CMPLX(COS(ria), SIN(ria), dp)**charge_tot
     245             : 
     246      337632 :          dria = twopi*MATMUL(cell%h_inv, drcc)
     247       84408 :          dzphase = charge_tot*CMPLX(-SIN(ria), COS(ria), dp)**(charge_tot - 1.0_dp)*dria
     248             : 
     249       84408 :          ggamma = CMPLX(1.0_dp, 0.0_dp, KIND=dp)
     250       21102 :          dggamma = CMPLX(0.0_dp, 0.0_dp, KIND=dp)
     251       80610 :          DO iparticle_kind = 1, SIZE(atomic_kind_set)
     252       59508 :             atomic_kind => atomic_kind_set(iparticle_kind)
     253       59508 :             CALL get_atomic_kind(atomic_kind=atomic_kind, qeff=q, atom_list=atom_list)
     254             : 
     255     2296094 :             DO i = 1, SIZE(atom_list)
     256     8861936 :                ria = particle_set(atom_list(i))%r(:)
     257     8861936 :                ria = pbc(ria, cell)
     258     8861936 :                via = particle_set(atom_list(i))%v(:)
     259     2215484 :                IF (use_charges) q = charges(atom_list(i))
     260     8921444 :                DO j = 1, 3
     261    26585808 :                   gvec = twopi*cell%h_inv(j, :)
     262    26585808 :                   theta = SUM(ria(:)*gvec(:))
     263    26585808 :                   dtheta = SUM(via(:)*gvec(:))
     264     6646452 :                   zeta = CMPLX(COS(theta), SIN(theta), KIND=dp)**(-q)
     265     6646452 :                   dzeta = -q*CMPLX(-SIN(theta), COS(theta), KIND=dp)**(-q - 1.0_dp)*dtheta
     266     6646452 :                   dggamma(j) = dggamma(j)*zeta + ggamma(j)*dzeta
     267     8861936 :                   ggamma(j) = ggamma(j)*zeta
     268             :                END DO
     269             :             END DO
     270             :          END DO
     271       84408 :          dggamma = dggamma*zphase + ggamma*dzphase
     272       84408 :          ggamma = ggamma*zphase
     273       84408 :          IF (ALL(REAL(ggamma, KIND=dp) /= 0.0_dp)) THEN
     274       84408 :             tmp = AIMAG(ggamma)/REAL(ggamma, KIND=dp)
     275       84408 :             ci = ATAN(tmp)
     276             :             dci = (1.0_dp/(1.0_dp + tmp**2))* &
     277       84408 :                   (AIMAG(dggamma)*REAL(ggamma, KIND=dp) - AIMAG(ggamma)*REAL(dggamma, KIND=dp))/(REAL(ggamma, KIND=dp))**2
     278             : 
     279      337632 :             dipole = MATMUL(cell%hmat, ci)/twopi
     280      337632 :             dipole_deriv = MATMUL(cell%hmat, dci)/twopi
     281             :          END IF
     282       21102 :          CALL fist_env_get(fist_env=fist_env, results=results)
     283       21102 :          CALL cp_results_erase(results, description)
     284       21102 :          CALL put_results(results, description, dipole)
     285             :       ELSE
     286           0 :          dipole_type = "non-periodic"
     287           0 :          DO i = 1, SIZE(particle_set)
     288           0 :             atomic_kind => particle_set(i)%atomic_kind
     289           0 :             ria = particle_set(i)%r(:) ! no pbc(particle_set(i)%r(:),cell) so that the total dipole
     290             :             ! is the sum of the molecular dipoles
     291           0 :             CALL get_atomic_kind(atomic_kind=atomic_kind, qeff=q)
     292           0 :             IF (use_charges) q = charges(i)
     293           0 :             dipole = dipole - q*(ria - rcc)
     294           0 :             dipole_deriv(:) = dipole_deriv(:) - q*(particle_set(i)%v(:) - drcc)
     295             :          END DO
     296           0 :          CALL fist_env_get(fist_env=fist_env, results=results)
     297           0 :          CALL cp_results_erase(results, description)
     298           0 :          CALL put_results(results, description, dipole)
     299             :       END IF
     300       21102 :       IF (unit_nr > 0) THEN
     301             :          WRITE (unit_nr, '(/,T2,A,T31,A50)') &
     302       10804 :             'MM_DIPOLE| Dipole type', ADJUSTR(TRIM(dipole_type))
     303             :          WRITE (unit_nr, '(T2,A,T30,3(1X,F16.8))') &
     304       10804 :             'MM_DIPOLE| Moment [a.u.]', dipole(1:3)
     305             :          WRITE (unit_nr, '(T2,A,T30,3(1X,F16.8))') &
     306       43216 :             'MM_DIPOLE| Moment [Debye]', dipole(1:3)*debye
     307             :          WRITE (unit_nr, '(T2,A,T30,3(1X,F16.8))') &
     308       10804 :             'MM_DIPOLE| Derivative [a.u.]', dipole_deriv(1:3)
     309             :       END IF
     310             : 
     311       21102 :    END SUBROUTINE fist_dipole
     312             : 
     313             : END MODULE fist_efield_methods

Generated by: LCOV version 1.15