(git:34ef472)
fist_efield_methods.F
Go to the documentation of this file.
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 ! **************************************************************************************************
13  USE atomic_kind_types, ONLY: atomic_kind_type,&
15  USE cell_types, ONLY: cell_type,&
16  pbc
18  put_results
19  USE cp_result_types, ONLY: cp_result_type
22  fist_environment_type
24  section_vals_type,&
26  USE kinds, ONLY: default_string_length,&
27  dp
28  USE mathconstants, ONLY: twopi
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 
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  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  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  qenergy = 0.0_dp
83  qforce = 0.0_dp
84  qpv = 0.0_dp
85 
86  use_charges = .false.
87  IF (PRESENT(charges)) THEN
88  IF (ASSOCIATED(charges)) use_charges = .true.
89  END IF
90 
91  IF (PRESENT(iunit)) THEN
92  iw = iunit
93  ELSE
94  iw = -1
95  END IF
96 
97  IF (PRESENT(use_virial)) THEN
98  virial = use_virial
99  ELSE
100  virial = .false.
101  END IF
102 
103  fieldpol = efield%polarisation
104  fieldpol = fieldpol/sqrt(dot_product(fieldpol, fieldpol))
105  fieldpol = -fieldpol*efield%strength
106 
107  dfilter = efield%dfilter
108 
109  dipole = 0.0_dp
110  ggamma = cmplx(1.0_dp, 0.0_dp, kind=dp)
111  DO iparticle_kind = 1, SIZE(atomic_kind_set)
112  atomic_kind => atomic_kind_set(iparticle_kind)
113  CALL get_atomic_kind(atomic_kind=atomic_kind, qeff=q, atom_list=atom_list)
114  ! TODO parallelization over atoms (local_particles)
115  DO i = 1, SIZE(atom_list)
116  ii = atom_list(i)
117  ria = particle_set(ii)%r(:)
118  ria = pbc(ria, cell)
119  IF (use_charges) q = charges(ii)
120  DO j = 1, 3
121  gvec = twopi*cell%h_inv(j, :)
122  theta = sum(ria(:)*gvec(:))
123  zeta = cmplx(cos(theta), sin(theta), kind=dp)**(-q)
124  ggamma(j) = ggamma(j)*zeta
125  END DO
126  qforce(1:3, ii) = q
127  END DO
128  END DO
129 
130  IF (all(real(ggamma, kind=dp) /= 0.0_dp)) THEN
131  tmp = aimag(ggamma)/real(ggamma, kind=dp)
132  ci = atan(tmp)
133  dipole = matmul(cell%hmat, ci)/twopi
134  END IF
135 
136  IF (efield%displacement) THEN
137  ! E = (omega/8Pi)(D - 4Pi*P)^2
138  di = dipole/cell%deth
139  DO i = 1, 3
140  theta = fieldpol(i) - 2._dp*twopi*di(i)
141  qenergy = qenergy + dfilter(i)*theta**2
142  fq(i) = -dfilter(i)*theta
143  END DO
144  qenergy = 0.25_dp*cell%deth/twopi*qenergy
145  DO i = 1, SIZE(qforce, 2)
146  qforce(1:3, i) = fq(1:3)*qforce(1:3, i)
147  END DO
148  ELSE
149  ! E = -omega*E*P
150  qenergy = sum(fieldpol*dipole)
151  DO i = 1, SIZE(qforce, 2)
152  qforce(1:3, i) = fieldpol(1:3)*qforce(1:3, i)
153  END DO
154  END IF
155 
156  IF (virial) THEN
157  DO iparticle_kind = 1, SIZE(atomic_kind_set)
158  atomic_kind => atomic_kind_set(iparticle_kind)
159  CALL get_atomic_kind(atomic_kind=atomic_kind, atom_list=atom_list)
160  DO i = 1, SIZE(atom_list)
161  ii = atom_list(i)
162  ria = particle_set(ii)%r(:)
163  ria = pbc(ria, cell)
164  DO j = 1, 3
165  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  IF (efield%displacement) THEN
171  cpabort("Stress Tensor for constant D simulation is not working")
172  END IF
173  END IF
174 
175  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  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  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  REAL(kind=dp), DIMENSION(:), POINTER :: ref_point
210  TYPE(atomic_kind_type), POINTER :: atomic_kind
211  TYPE(cp_result_type), POINTER :: results
212 
213  NULLIFY (atomic_kind)
214  ! Reference point
215  reference = section_get_ival(print_section, keyword_name="DIPOLE%REFERENCE")
216  NULLIFY (ref_point)
217  description = '[DIPOLE]'
218  CALL section_vals_val_get(print_section, "DIPOLE%REF_POINT", r_vals=ref_point)
219  CALL section_vals_val_get(print_section, "DIPOLE%PERIODIC", l_val=do_berry)
220  use_charges = .false.
221  IF (PRESENT(charges)) THEN
222  IF (ASSOCIATED(charges)) use_charges = .true.
223  END IF
224 
225  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  dipole_deriv = 0.0_dp
229  dipole = 0.0_dp
230  IF (do_berry) THEN
231  dipole_type = "periodic (Berry phase)"
232  rcc = pbc(rcc, cell)
233  charge_tot = 0._dp
234  IF (use_charges) THEN
235  charge_tot = sum(charges)
236  ELSE
237  DO i = 1, SIZE(particle_set)
238  atomic_kind => particle_set(i)%atomic_kind
239  CALL get_atomic_kind(atomic_kind=atomic_kind, qeff=q)
240  charge_tot = charge_tot + q
241  END DO
242  END IF
243  ria = twopi*matmul(cell%h_inv, rcc)
244  zphase = cmplx(cos(ria), sin(ria), dp)**charge_tot
245 
246  dria = twopi*matmul(cell%h_inv, drcc)
247  dzphase = charge_tot*cmplx(-sin(ria), cos(ria), dp)**(charge_tot - 1.0_dp)*dria
248 
249  ggamma = cmplx(1.0_dp, 0.0_dp, kind=dp)
250  dggamma = cmplx(0.0_dp, 0.0_dp, kind=dp)
251  DO iparticle_kind = 1, SIZE(atomic_kind_set)
252  atomic_kind => atomic_kind_set(iparticle_kind)
253  CALL get_atomic_kind(atomic_kind=atomic_kind, qeff=q, atom_list=atom_list)
254 
255  DO i = 1, SIZE(atom_list)
256  ria = particle_set(atom_list(i))%r(:)
257  ria = pbc(ria, cell)
258  via = particle_set(atom_list(i))%v(:)
259  IF (use_charges) q = charges(atom_list(i))
260  DO j = 1, 3
261  gvec = twopi*cell%h_inv(j, :)
262  theta = sum(ria(:)*gvec(:))
263  dtheta = sum(via(:)*gvec(:))
264  zeta = cmplx(cos(theta), sin(theta), kind=dp)**(-q)
265  dzeta = -q*cmplx(-sin(theta), cos(theta), kind=dp)**(-q - 1.0_dp)*dtheta
266  dggamma(j) = dggamma(j)*zeta + ggamma(j)*dzeta
267  ggamma(j) = ggamma(j)*zeta
268  END DO
269  END DO
270  END DO
271  dggamma = dggamma*zphase + ggamma*dzphase
272  ggamma = ggamma*zphase
273  IF (all(real(ggamma, kind=dp) /= 0.0_dp)) THEN
274  tmp = aimag(ggamma)/real(ggamma, kind=dp)
275  ci = atan(tmp)
276  dci = (1.0_dp/(1.0_dp + tmp**2))* &
277  (aimag(dggamma)*real(ggamma, kind=dp) - aimag(ggamma)*real(dggamma, kind=dp))/(real(ggamma, kind=dp))**2
278 
279  dipole = matmul(cell%hmat, ci)/twopi
280  dipole_deriv = matmul(cell%hmat, dci)/twopi
281  END IF
282  CALL fist_env_get(fist_env=fist_env, results=results)
283  CALL cp_results_erase(results, description)
284  CALL put_results(results, description, dipole)
285  ELSE
286  dipole_type = "non-periodic"
287  DO i = 1, SIZE(particle_set)
288  atomic_kind => particle_set(i)%atomic_kind
289  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  CALL get_atomic_kind(atomic_kind=atomic_kind, qeff=q)
292  IF (use_charges) q = charges(i)
293  dipole = dipole - q*(ria - rcc)
294  dipole_deriv(:) = dipole_deriv(:) - q*(particle_set(i)%v(:) - drcc)
295  END DO
296  CALL fist_env_get(fist_env=fist_env, results=results)
297  CALL cp_results_erase(results, description)
298  CALL put_results(results, description, dipole)
299  END IF
300  IF (unit_nr > 0) THEN
301  WRITE (unit_nr, '(/,T2,A,T31,A50)') &
302  'MM_DIPOLE| Dipole type', adjustr(trim(dipole_type))
303  WRITE (unit_nr, '(T2,A,T30,3(1X,F16.8))') &
304  'MM_DIPOLE| Moment [a.u.]', dipole(1:3)
305  WRITE (unit_nr, '(T2,A,T30,3(1X,F16.8))') &
306  'MM_DIPOLE| Moment [Debye]', dipole(1:3)*debye
307  WRITE (unit_nr, '(T2,A,T30,3(1X,F16.8))') &
308  'MM_DIPOLE| Derivative [a.u.]', dipole_deriv(1:3)
309  END IF
310 
311  END SUBROUTINE fist_dipole
312 
313 END MODULE fist_efield_methods
subroutine pbc(r, r_pbc, s, s_pbc, a, b, c, alpha, beta, gamma, debug, info, pbc0, h, hinv)
...
Definition: dumpdcd.F:1203
Define the atomic kind types and their sub types.
subroutine, public get_atomic_kind(atomic_kind, fist_potential, element_symbol, name, mass, kind_number, natom, atom_list, rcov, rvdw, z, qeff, apol, cpol, mm_radius, shell, shell_active, damping)
Get attributes of an atomic kind.
Handles all functions related to the CELL.
Definition: cell_types.F:15
set of type/routines to handle the storage of results in force_envs
subroutine, public cp_results_erase(results, description, nval)
erase a part of result_list
set of type/routines to handle the storage of results in force_envs
subroutine, public fist_efield_energy_force(qenergy, qforce, qpv, atomic_kind_set, particle_set, cell, efield, use_virial, iunit, charges)
...
subroutine, public fist_dipole(fist_env, print_section, atomic_kind_set, particle_set, cell, unit_nr, charges)
Evaluates the Dipole of a classical charge distribution(point-like) possibly using the berry phase fo...
subroutine, public fist_env_get(fist_env, atomic_kind_set, particle_set, ewald_pw, local_particles, local_molecules, molecule_kind_set, molecule_set, cell, cell_ref, ewald_env, fist_nonbond_env, thermo, para_env, subsys, qmmm, qmmm_env, input, shell_model, shell_model_ad, shell_particle_set, core_particle_set, multipoles, results, exclusions, efield)
Purpose: Get the FIST environment.
objects that represent the structure of input sections and the data contained in an input section
integer function, public section_get_ival(section_vals, keyword_name)
...
subroutine, public section_vals_val_get(section_vals, keyword_name, i_rep_section, i_rep_val, n_rep_val, val, l_val, i_val, r_val, c_val, l_vals, i_vals, r_vals, c_vals, explicit)
returns the requested value
Defines the basic variable types.
Definition: kinds.F:23
integer, parameter, public dp
Definition: kinds.F:34
integer, parameter, public default_string_length
Definition: kinds.F:57
Definition of mathematical constants and functions.
Definition: mathconstants.F:16
real(kind=dp), parameter, public twopi
Calculates the moment integrals <a|r^m|b>
Definition: moments_utils.F:15
subroutine, public get_reference_point(rpoint, drpoint, qs_env, fist_env, reference, ref_point, ifirst, ilast)
...
Definition: moments_utils.F:61
Define the data structure for the particle information.
Definition of physical constants:
Definition: physcon.F:68
real(kind=dp), parameter, public debye
Definition: physcon.F:201