(git:bb35279)
Loading...
Searching...
No Matches
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-2025 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! **************************************************************************************************
15 USE cell_types, ONLY: cell_type,&
16 pbc
26 USE kinds, ONLY: default_string_length,&
27 dp
28 USE mathconstants, ONLY: twopi,&
29 z_one,&
30 z_zero
33 USE physcon, ONLY: debye
34#include "./base/base_uses.f90"
35
36 IMPLICIT NONE
37
38 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'fist_efield_methods'
39
40 PRIVATE
41
43
44! **************************************************************************************************
45
46CONTAINS
47
48! **************************************************************************************************
49!> \brief ...
50!> \param qenergy ...
51!> \param qforce ...
52!> \param qpv ...
53!> \param atomic_kind_set ...
54!> \param particle_set ...
55!> \param cell ...
56!> \param efield ...
57!> \param use_virial ...
58!> \param iunit ...
59!> \param charges ...
60! **************************************************************************************************
61 SUBROUTINE fist_efield_energy_force(qenergy, qforce, qpv, atomic_kind_set, particle_set, cell, &
62 efield, use_virial, iunit, charges)
63 REAL(kind=dp), INTENT(OUT) :: qenergy
64 REAL(kind=dp), DIMENSION(:, :), INTENT(OUT) :: qforce
65 REAL(kind=dp), DIMENSION(3, 3), INTENT(OUT) :: qpv
66 TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set
67 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
68 TYPE(cell_type), POINTER :: cell
69 TYPE(fist_efield_type), POINTER :: efield
70 LOGICAL, INTENT(IN), OPTIONAL :: use_virial
71 INTEGER, INTENT(IN), OPTIONAL :: iunit
72 REAL(kind=dp), DIMENSION(:), OPTIONAL, POINTER :: charges
73
74 COMPLEX(KIND=dp) :: zeta
75 COMPLEX(KIND=dp), DIMENSION(3) :: ggamma
76 INTEGER :: i, ii, iparticle_kind, iw, j
77 INTEGER, DIMENSION(:), POINTER :: atom_list
78 LOGICAL :: use_charges, virial
79 REAL(kind=dp) :: q, theta
80 REAL(kind=dp), DIMENSION(3) :: ci, dfilter, di, dipole, fieldpol, fq, &
81 gvec, ria, tmp
82 TYPE(atomic_kind_type), POINTER :: atomic_kind
83
84 qenergy = 0.0_dp
85 qforce = 0.0_dp
86 qpv = 0.0_dp
87
88 use_charges = .false.
89 IF (PRESENT(charges)) THEN
90 IF (ASSOCIATED(charges)) use_charges = .true.
91 END IF
92
93 IF (PRESENT(iunit)) THEN
94 iw = iunit
95 ELSE
96 iw = -1
97 END IF
98
99 IF (PRESENT(use_virial)) THEN
100 virial = use_virial
101 ELSE
102 virial = .false.
103 END IF
104
105 fieldpol = efield%polarisation
106 fieldpol = fieldpol/sqrt(dot_product(fieldpol, fieldpol))
107 fieldpol = -fieldpol*efield%strength
108
109 dfilter = efield%dfilter
110
111 dipole = 0.0_dp
112 ggamma = z_one
113 DO iparticle_kind = 1, SIZE(atomic_kind_set)
114 atomic_kind => atomic_kind_set(iparticle_kind)
115 CALL get_atomic_kind(atomic_kind=atomic_kind, qeff=q, atom_list=atom_list)
116 ! TODO parallelization over atoms (local_particles)
117 DO i = 1, SIZE(atom_list)
118 ii = atom_list(i)
119 ria = particle_set(ii)%r(:)
120 ria = pbc(ria, cell)
121 IF (use_charges) q = charges(ii)
122 DO j = 1, 3
123 gvec = twopi*cell%h_inv(j, :)
124 theta = sum(ria(:)*gvec(:))
125 zeta = cmplx(cos(theta), sin(theta), kind=dp)**(-q)
126 ggamma(j) = ggamma(j)*zeta
127 END DO
128 qforce(1:3, ii) = q
129 END DO
130 END DO
131
132 IF (all(real(ggamma, kind=dp) /= 0.0_dp)) THEN
133 tmp = aimag(ggamma)/real(ggamma, kind=dp)
134 ci = atan(tmp)
135 dipole = matmul(cell%hmat, ci)/twopi
136 END IF
137
138 IF (efield%displacement) THEN
139 ! E = (omega/8Pi)(D - 4Pi*P)^2
140 di = dipole/cell%deth
141 DO i = 1, 3
142 theta = fieldpol(i) - 2._dp*twopi*di(i)
143 qenergy = qenergy + dfilter(i)*theta**2
144 fq(i) = -dfilter(i)*theta
145 END DO
146 qenergy = 0.25_dp*cell%deth/twopi*qenergy
147 DO i = 1, SIZE(qforce, 2)
148 qforce(1:3, i) = fq(1:3)*qforce(1:3, i)
149 END DO
150 ELSE
151 ! E = -omega*E*P
152 qenergy = sum(fieldpol*dipole)
153 DO i = 1, SIZE(qforce, 2)
154 qforce(1:3, i) = fieldpol(1:3)*qforce(1:3, i)
155 END DO
156 END IF
157
158 IF (virial) THEN
159 DO iparticle_kind = 1, SIZE(atomic_kind_set)
160 atomic_kind => atomic_kind_set(iparticle_kind)
161 CALL get_atomic_kind(atomic_kind=atomic_kind, atom_list=atom_list)
162 DO i = 1, SIZE(atom_list)
163 ii = atom_list(i)
164 ria = particle_set(ii)%r(:)
165 ria = pbc(ria, cell)
166 DO j = 1, 3
167 qpv(j, 1:3) = qpv(j, 1:3) + qforce(j, ii)*ria(1:3)
168 END DO
169 END DO
170 END DO
171 ! Stress tensor for constant D needs further investigation
172 IF (efield%displacement) THEN
173 cpabort("Stress Tensor for constant D simulation is not working")
174 END IF
175 END IF
176
177 END SUBROUTINE fist_efield_energy_force
178! **************************************************************************************************
179!> \brief Evaluates the Dipole of a classical charge distribution(point-like)
180!> possibly using the berry phase formalism
181!> \param fist_env ...
182!> \param print_section ...
183!> \param atomic_kind_set ...
184!> \param particle_set ...
185!> \param cell ...
186!> \param unit_nr ...
187!> \param charges ...
188!> \par History
189!> [01.2006] created
190!> [12.2007] tlaino - University of Zurich - debug and extended
191!> \author Teodoro Laino
192! **************************************************************************************************
193 SUBROUTINE fist_dipole(fist_env, print_section, atomic_kind_set, particle_set, &
194 cell, unit_nr, charges)
195 TYPE(fist_environment_type), POINTER :: fist_env
196 TYPE(section_vals_type), POINTER :: print_section
197 TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set
198 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
199 TYPE(cell_type), POINTER :: cell
200 INTEGER, INTENT(IN) :: unit_nr
201 REAL(kind=dp), DIMENSION(:), OPTIONAL, POINTER :: charges
202
203 CHARACTER(LEN=default_string_length) :: description, dipole_type
204 COMPLEX(KIND=dp) :: dzeta, dzphase(3), zeta, zphase(3)
205 COMPLEX(KIND=dp), DIMENSION(3) :: dggamma, ggamma
206 INTEGER :: i, iparticle_kind, j, reference
207 INTEGER, DIMENSION(:), POINTER :: atom_list
208 LOGICAL :: do_berry, use_charges
209 REAL(kind=dp) :: charge_tot, ci(3), dci(3), dipole(3), dipole_deriv(3), drcc(3), dria(3), &
210 dtheta, gvec(3), q, rcc(3), ria(3), theta, tmp(3), via(3)
211 REAL(kind=dp), DIMENSION(:), POINTER :: ref_point
212 TYPE(atomic_kind_type), POINTER :: atomic_kind
213 TYPE(cp_result_type), POINTER :: results
214
215 NULLIFY (atomic_kind)
216 ! Reference point
217 reference = section_get_ival(print_section, keyword_name="DIPOLE%REFERENCE")
218 NULLIFY (ref_point)
219 description = '[DIPOLE]'
220 CALL section_vals_val_get(print_section, "DIPOLE%REF_POINT", r_vals=ref_point)
221 CALL section_vals_val_get(print_section, "DIPOLE%PERIODIC", l_val=do_berry)
222 use_charges = .false.
223 IF (PRESENT(charges)) THEN
224 IF (ASSOCIATED(charges)) use_charges = .true.
225 END IF
226
227 CALL get_reference_point(rcc, drcc, fist_env=fist_env, reference=reference, ref_point=ref_point)
228
229 ! Dipole deriv will be the derivative of the Dipole(dM/dt=\sum e_j v_j)
230 dipole_deriv = 0.0_dp
231 dipole = 0.0_dp
232 IF (do_berry) THEN
233 dipole_type = "periodic (Berry phase)"
234 rcc = pbc(rcc, cell)
235 charge_tot = 0._dp
236 IF (use_charges) THEN
237 charge_tot = sum(charges)
238 ELSE
239 DO i = 1, SIZE(particle_set)
240 atomic_kind => particle_set(i)%atomic_kind
241 CALL get_atomic_kind(atomic_kind=atomic_kind, qeff=q)
242 charge_tot = charge_tot + q
243 END DO
244 END IF
245 ria = twopi*matmul(cell%h_inv, rcc)
246 zphase = cmplx(cos(ria), sin(ria), dp)**charge_tot
247
248 dria = twopi*matmul(cell%h_inv, drcc)
249 dzphase = charge_tot*cmplx(-sin(ria), cos(ria), dp)**(charge_tot - 1.0_dp)*dria
250
251 ggamma = z_one
252 dggamma = z_zero
253 DO iparticle_kind = 1, SIZE(atomic_kind_set)
254 atomic_kind => atomic_kind_set(iparticle_kind)
255 CALL get_atomic_kind(atomic_kind=atomic_kind, qeff=q, atom_list=atom_list)
256
257 DO i = 1, SIZE(atom_list)
258 ria = particle_set(atom_list(i))%r(:)
259 ria = pbc(ria, cell)
260 via = particle_set(atom_list(i))%v(:)
261 IF (use_charges) q = charges(atom_list(i))
262 DO j = 1, 3
263 gvec = twopi*cell%h_inv(j, :)
264 theta = sum(ria(:)*gvec(:))
265 dtheta = sum(via(:)*gvec(:))
266 zeta = cmplx(cos(theta), sin(theta), kind=dp)**(-q)
267 dzeta = -q*cmplx(-sin(theta), cos(theta), kind=dp)**(-q - 1.0_dp)*dtheta
268 dggamma(j) = dggamma(j)*zeta + ggamma(j)*dzeta
269 ggamma(j) = ggamma(j)*zeta
270 END DO
271 END DO
272 END DO
273 dggamma = dggamma*zphase + ggamma*dzphase
274 ggamma = ggamma*zphase
275 IF (all(real(ggamma, kind=dp) /= 0.0_dp)) THEN
276 tmp = aimag(ggamma)/real(ggamma, kind=dp)
277 ci = atan(tmp)
278 dci = (1.0_dp/(1.0_dp + tmp**2))* &
279 (aimag(dggamma)*real(ggamma, kind=dp) - aimag(ggamma)*real(dggamma, kind=dp))/(real(ggamma, kind=dp))**2
280
281 dipole = matmul(cell%hmat, ci)/twopi
282 dipole_deriv = matmul(cell%hmat, dci)/twopi
283 END IF
284 CALL fist_env_get(fist_env=fist_env, results=results)
285 CALL cp_results_erase(results, description)
286 CALL put_results(results, description, dipole)
287 ELSE
288 dipole_type = "non-periodic"
289 DO i = 1, SIZE(particle_set)
290 atomic_kind => particle_set(i)%atomic_kind
291 ria = particle_set(i)%r(:) ! no pbc(particle_set(i)%r(:),cell) so that the total dipole
292 ! is the sum of the molecular dipoles
293 CALL get_atomic_kind(atomic_kind=atomic_kind, qeff=q)
294 IF (use_charges) q = charges(i)
295 dipole = dipole - q*(ria - rcc)
296 dipole_deriv(:) = dipole_deriv(:) - q*(particle_set(i)%v(:) - drcc)
297 END DO
298 CALL fist_env_get(fist_env=fist_env, results=results)
299 CALL cp_results_erase(results, description)
300 CALL put_results(results, description, dipole)
301 END IF
302 IF (unit_nr > 0) THEN
303 WRITE (unit_nr, '(/,T2,A,T31,A50)') &
304 'MM_DIPOLE| Dipole type', adjustr(trim(dipole_type))
305 WRITE (unit_nr, '(T2,A,T30,3(1X,F16.8))') &
306 'MM_DIPOLE| Moment [a.u.]', dipole(1:3)
307 WRITE (unit_nr, '(T2,A,T30,3(1X,F16.8))') &
308 'MM_DIPOLE| Moment [Debye]', dipole(1:3)*debye
309 WRITE (unit_nr, '(T2,A,T30,3(1X,F16.8))') &
310 'MM_DIPOLE| Derivative [a.u.]', dipole_deriv(1:3)
311 END IF
312
313 END SUBROUTINE fist_dipole
314
315END MODULE fist_efield_methods
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.
complex(kind=dp), parameter, public z_one
real(kind=dp), parameter, public twopi
complex(kind=dp), parameter, public z_zero
Calculates the moment integrals <a|r^m|b>
subroutine, public get_reference_point(rpoint, drpoint, qs_env, fist_env, reference, ref_point, ifirst, ilast)
...
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
Provides all information about an atomic kind.
Type defining parameters related to the simulation cell.
Definition cell_types.F:55
contains arbitrary information which need to be stored