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 Implementation of the GAL21 potential
10 : !>
11 : !> \author Clabaut Paul
12 : ! **************************************************************************************************
13 : MODULE manybody_gal21
14 :
15 : USE atomic_kind_types, ONLY: get_atomic_kind
16 : USE cell_types, ONLY: cell_type,&
17 : pbc
18 : USE cp_log_handling, ONLY: cp_get_default_logger,&
19 : cp_logger_type,&
20 : cp_to_string
21 : USE cp_output_handling, ONLY: cp_print_key_finished_output,&
22 : cp_print_key_unit_nr
23 : USE fist_neighbor_list_types, ONLY: fist_neighbor_type,&
24 : neighbor_kind_pairs_type
25 : USE fist_nonbond_env_types, ONLY: pos_type
26 : USE input_section_types, ONLY: section_vals_type
27 : USE kinds, ONLY: dp
28 : USE message_passing, ONLY: mp_para_env_type
29 : USE pair_potential_types, ONLY: gal21_pot_type,&
30 : gal21_type,&
31 : pair_potential_pp_type,&
32 : pair_potential_single_type
33 : USE particle_types, ONLY: particle_type
34 : USE util, ONLY: sort
35 : #include "./base/base_uses.f90"
36 :
37 : IMPLICIT NONE
38 :
39 : PRIVATE
40 : PUBLIC :: setup_gal21_arrays, destroy_gal21_arrays, &
41 : gal21_energy, gal21_forces, &
42 : print_nr_ions_gal21
43 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'manybody_gal21'
44 :
45 : CONTAINS
46 :
47 : ! **************************************************************************************************
48 : !> \brief Main part of the energy evaluation of GAL2119
49 : !> \param pot_loc value of total potential energy
50 : !> \param gal21 all parameters of GAL2119
51 : !> \param r_last_update_pbc position of every atoms on previous frame
52 : !> \param iparticle first index of the atom of the evaluated pair
53 : !> \param jparticle second index of the atom of the evaluated pair
54 : !> \param cell dimension of the pbc cell
55 : !> \param particle_set full list of atoms of the system
56 : !> \param mm_section ...
57 : !> \author Clabaut Paul - 2019 - ENS de Lyon
58 : ! **************************************************************************************************
59 5732 : SUBROUTINE gal21_energy(pot_loc, gal21, r_last_update_pbc, iparticle, jparticle, &
60 : cell, particle_set, mm_section)
61 :
62 : REAL(KIND=dp), INTENT(OUT) :: pot_loc
63 : TYPE(gal21_pot_type), POINTER :: gal21
64 : TYPE(pos_type), DIMENSION(:), POINTER :: r_last_update_pbc
65 : INTEGER, INTENT(IN) :: iparticle, jparticle
66 : TYPE(cell_type), POINTER :: cell
67 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
68 : TYPE(section_vals_type), POINTER :: mm_section
69 :
70 : CHARACTER(LEN=2) :: element_symbol
71 : INTEGER :: index_outfile
72 : REAL(KIND=dp) :: anglepart, AO, BO, bxy, bz, cosalpha, &
73 : drji2, eps, nvec(3), rji(3), sinalpha, &
74 : sum_weight, Vang, Vgaussian, VH, VTT, &
75 : weight
76 : TYPE(cp_logger_type), POINTER :: logger
77 :
78 5732 : pot_loc = 0.0_dp
79 : CALL get_atomic_kind(atomic_kind=particle_set(iparticle)%atomic_kind, &
80 5732 : element_symbol=element_symbol) !Read the atom type of i
81 :
82 5732 : IF (element_symbol == "O") THEN !To avoid counting two times each pair
83 :
84 2866 : rji(:) = pbc(r_last_update_pbc(jparticle)%r(:), r_last_update_pbc(iparticle)%r(:), cell) !Vector in pbc from j to i
85 :
86 2866 : IF (.NOT. ALLOCATED(gal21%n_vectors)) THEN !First calling of the forcefield only
87 3 : ALLOCATE (gal21%n_vectors(3, SIZE(particle_set)))
88 3481 : gal21%n_vectors(:, :) = 0.0_dp
89 : END IF
90 :
91 2866 : IF (gal21%express) THEN
92 0 : logger => cp_get_default_logger()
93 : index_outfile = cp_print_key_unit_nr(logger, mm_section, &
94 0 : "PRINT%PROGRAM_RUN_INFO", extension=".mmLog")
95 0 : IF (index_outfile > 0) WRITE (index_outfile, *) "GCN", gal21%gcn(jparticle)
96 : CALL cp_print_key_finished_output(index_outfile, logger, mm_section, &
97 0 : "PRINT%PROGRAM_RUN_INFO")
98 : END IF
99 :
100 : !Build epsilon attraction and the parameters of the gaussian attraction as a function of gcn
101 2866 : eps = gal21%epsilon1*gal21%gcn(jparticle)*gal21%gcn(jparticle) + gal21%epsilon2*gal21%gcn(jparticle) + gal21%epsilon3
102 2866 : bxy = gal21%bxy1 + gal21%bxy2*gal21%gcn(jparticle)
103 2866 : bz = gal21%bz1 + gal21%bz2*gal21%gcn(jparticle)
104 :
105 : !Angular dependance %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
106 2866 : Vang = 0.0_dp
107 :
108 : ! Calculation of the normal vector centered on the Me atom of the pair,
109 : ! only the first time that an interaction with the metal atom of the pair is evaluated
110 : IF (gal21%n_vectors(1, jparticle) == 0.0_dp .AND. &
111 2866 : gal21%n_vectors(2, jparticle) == 0.0_dp .AND. &
112 : gal21%n_vectors(3, jparticle) == 0.0_dp) THEN
113 : gal21%n_vectors(:, jparticle) = normale(gal21, r_last_update_pbc, jparticle, &
114 596 : particle_set, cell)
115 : END IF
116 :
117 : ! Else, retrive it, should not have moved sinc metal is supposed to be frozen
118 11464 : nvec(:) = gal21%n_vectors(:, jparticle)
119 :
120 : !Calculation of the sum of the expontial weights of each Me surrounding the principal one
121 2866 : sum_weight = somme(gal21, r_last_update_pbc, iparticle, particle_set, cell)
122 :
123 : !Exponential damping weight for angular dependance
124 11464 : weight = EXP(-NORM2(rji)/gal21%r1)
125 :
126 : !Calculation of the truncated fourier series of the water-dipole/surface-normal angle
127 : anglepart = 0.0_dp
128 : VH = 0.0_dp
129 : CALL angular(anglepart, VH, gal21, r_last_update_pbc, iparticle, jparticle, cell, particle_set, nvec, &
130 2866 : .TRUE., mm_section)
131 :
132 : !Build the complete angular potential while avoiding division by 0
133 2866 : IF (weight /= 0) THEN
134 2866 : Vang = weight*weight*anglepart/sum_weight
135 2866 : IF (gal21%express) THEN
136 0 : logger => cp_get_default_logger()
137 : index_outfile = cp_print_key_unit_nr(logger, mm_section, &
138 0 : "PRINT%PROGRAM_RUN_INFO", extension=".mmLog")
139 0 : IF (index_outfile > 0) WRITE (index_outfile, *) "Fermi", weight*weight/sum_weight
140 : CALL cp_print_key_finished_output(index_outfile, logger, mm_section, &
141 0 : "PRINT%PROGRAM_RUN_INFO")
142 : END IF
143 : END IF
144 : !END Angular%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
145 :
146 : !Attractive Gaussian %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
147 2866 : Vgaussian = 0.0_dp
148 11464 : drji2 = DOT_PRODUCT(rji, rji)
149 : !Alpha is the angle of the Me-O vector with the normale vector. Used for gaussian attaction
150 :
151 11464 : cosalpha = DOT_PRODUCT(rji, nvec)/SQRT(drji2)
152 2866 : IF (cosalpha < -1.0_dp) cosalpha = -1.0_dp
153 : IF (cosalpha > +1.0_dp) cosalpha = +1.0_dp
154 2866 : sinalpha = SIN(ACOS(cosalpha))
155 :
156 : !Gaussian component of the energy
157 : Vgaussian = -1.0_dp*eps*EXP(-bz*drji2*cosalpha*cosalpha &
158 2866 : - bxy*drji2*sinalpha*sinalpha)
159 : !END Gaussian%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
160 :
161 2866 : AO = gal21%AO1 + gal21%AO2*gal21%gcn(jparticle)
162 2866 : BO = gal21%BO1 + gal21%BO2*gal21%gcn(jparticle)
163 :
164 : !Tang and toennies potential for physisorption
165 : VTT = AO*EXP(-BO*SQRT(drji2)) - (1.0 - EXP(-BO*SQRT(drji2)) &
166 : - BO*SQRT(drji2)*EXP(-BO*SQRT(drji2)) &
167 : - (((BO*SQRT(drji2))**2)/2)*EXP(-BO*SQRT(drji2)) &
168 : - (((BO*SQRT(drji2))**3)/6)*EXP(-BO*SQRT(drji2)) &
169 : - (((BO*SQRT(drji2))**4)/24)*EXP(-BO*SQRT(drji2)) &
170 : - (((BO*SQRT(drji2))**5)/120)*EXP(-BO*SQRT(drji2)) &
171 : - (((BO*SQRT(drji2))**6)/720)*EXP(-BO*SQRT(drji2))) &
172 2866 : *gal21%c/(SQRT(drji2)**6)
173 :
174 : !For fit purpose only
175 2866 : IF (gal21%express) THEN
176 0 : logger => cp_get_default_logger()
177 : index_outfile = cp_print_key_unit_nr(logger, mm_section, &
178 0 : "PRINT%PROGRAM_RUN_INFO", extension=".mmLog")
179 0 : IF (index_outfile > 0) WRITE (index_outfile, *) "Gau", -1.0_dp*EXP(-bz*drji2*cosalpha*cosalpha &
180 0 : - bxy*drji2*sinalpha*sinalpha)
181 0 : IF (weight == 0 .AND. index_outfile > 0) WRITE (index_outfile, *) "Fermi 0"
182 0 : IF (index_outfile > 0) WRITE (index_outfile, *) "expO", EXP(-BO*SQRT(drji2))
183 0 : IF (index_outfile > 0) WRITE (index_outfile, *) "cstpart", -(1.0 - EXP(-BO*SQRT(drji2)) &
184 : - BO*SQRT(drji2)*EXP(-BO*SQRT(drji2)) &
185 : - (((BO*SQRT(drji2))**2)/2)*EXP(-BO*SQRT(drji2)) &
186 : - (((BO*SQRT(drji2))**3)/6)*EXP(-BO*SQRT(drji2)) &
187 : - (((BO*SQRT(drji2))**4)/24)*EXP(-BO*SQRT(drji2)) &
188 : - (((BO*SQRT(drji2))**5)/120)*EXP(-BO*SQRT(drji2)) &
189 : - (((BO*SQRT(drji2))**6)/720)*EXP(-BO*SQRT(drji2))) &
190 0 : *gal21%c/(SQRT(drji2)**6)
191 0 : IF (index_outfile > 0) WRITE (index_outfile, *) "params_lin_eps", gal21%epsilon1, gal21%epsilon2, gal21%epsilon3
192 0 : IF (index_outfile > 0) WRITE (index_outfile, *) "params_lin_A0", AO
193 : CALL cp_print_key_finished_output(index_outfile, logger, mm_section, &
194 0 : "PRINT%PROGRAM_RUN_INFO")
195 : END IF
196 : !Compute the total energy
197 2866 : pot_loc = Vgaussian + Vang + VTT + VH
198 :
199 : END IF
200 :
201 5732 : END SUBROUTINE gal21_energy
202 :
203 : ! **************************************************************************************************
204 : !> \brief The idea is to build a vector normal to the local surface by using the symetry of the
205 : !> surface that make the opposite vectors compensate themself. The vector is therefore in the
206 : !>. direction of the missing atoms of a large coordination sphere
207 : !> \param gal21 ...
208 : !> \param r_last_update_pbc ...
209 : !> \param jparticle ...
210 : !> \param particle_set ...
211 : !> \param cell ...
212 : !> \return ...
213 : !> \retval normale ...
214 : ! **************************************************************************************************
215 149 : FUNCTION normale(gal21, r_last_update_pbc, jparticle, particle_set, cell)
216 : TYPE(gal21_pot_type), POINTER :: gal21
217 : TYPE(pos_type), DIMENSION(:), POINTER :: r_last_update_pbc
218 : INTEGER, INTENT(IN) :: jparticle
219 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
220 : TYPE(cell_type), POINTER :: cell
221 : REAL(KIND=dp) :: normale(3)
222 :
223 : CHARACTER(LEN=2) :: element_symbol_k
224 : INTEGER :: kparticle, natom
225 : REAL(KIND=dp) :: drjk, rjk(3)
226 :
227 149 : natom = SIZE(particle_set)
228 596 : normale(:) = 0.0_dp
229 :
230 129779 : DO kparticle = 1, natom !Loop on every atom of the system
231 129630 : IF (kparticle == jparticle) CYCLE !Avoid the principal Me atom (j) in the counting
232 : CALL get_atomic_kind(atomic_kind=particle_set(kparticle)%atomic_kind, &
233 129481 : element_symbol=element_symbol_k)
234 : !Keep only metals
235 129481 : IF (element_symbol_k /= gal21%met1 .AND. element_symbol_k /= gal21%met2) CYCLE
236 28459 : rjk(:) = pbc(r_last_update_pbc(jparticle)%r(:), r_last_update_pbc(kparticle)%r(:), cell)
237 113836 : drjk = NORM2(rjk)
238 : !Keep only those within square root of the force-field cutoff distance of the metallic atom of the evaluated pair
239 28459 : IF (drjk > gal21%rcutsq) CYCLE
240 : !Build the normal, vector by vector
241 215156 : normale(:) = normale(:) - rjk(:)/(drjk*drjk*drjk*drjk*drjk)
242 : END DO
243 :
244 : ! Normalisation of the vector
245 1043 : normale(:) = normale(:)/NORM2(normale)
246 :
247 : END FUNCTION normale
248 :
249 : ! **************************************************************************************************
250 : !> \brief Scan all the Me atoms that have been counted in the O-Me paires and sum their exp. weights
251 : !> \param gal21 ...
252 : !> \param r_last_update_pbc ...
253 : !> \param iparticle ...
254 : !> \param particle_set ...
255 : !> \param cell ...
256 : !> \return ...
257 : !> \retval somme ...
258 : ! **************************************************************************************************
259 5732 : FUNCTION somme(gal21, r_last_update_pbc, iparticle, particle_set, cell)
260 : TYPE(gal21_pot_type), POINTER :: gal21
261 : TYPE(pos_type), DIMENSION(:), POINTER :: r_last_update_pbc
262 : INTEGER, INTENT(IN) :: iparticle
263 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
264 : TYPE(cell_type), POINTER :: cell
265 : REAL(KIND=dp) :: somme
266 :
267 : CHARACTER(LEN=2) :: element_symbol_k
268 : INTEGER :: kparticle, natom
269 : REAL(KIND=dp) :: rki(3)
270 :
271 5732 : natom = SIZE(particle_set)
272 5732 : somme = 0.0_dp
273 :
274 4992572 : DO kparticle = 1, natom !Loop on every atom of the system
275 : CALL get_atomic_kind(atomic_kind=particle_set(kparticle)%atomic_kind, &
276 4986840 : element_symbol=element_symbol_k)
277 : !Keep only metals
278 4986840 : IF (element_symbol_k /= gal21%met1 .AND. element_symbol_k /= gal21%met2) CYCLE
279 1100544 : rki(:) = pbc(r_last_update_pbc(kparticle)%r(:), r_last_update_pbc(iparticle)%r(:), cell)
280 : !Keep only those within cutoff distance of the oxygen atom of the evaluated pair (the omega ensemble)
281 4402176 : IF (NORM2(rki) > gal21%rcutsq) CYCLE
282 : !Build the sum of the exponential weights
283 4402176 : IF (element_symbol_k == gal21%met1) somme = somme + EXP(-NORM2(rki)/gal21%r1)
284 1106276 : IF (element_symbol_k == gal21%met2) somme = somme + EXP(-NORM2(rki)/gal21%r2)
285 : END DO
286 :
287 5732 : END FUNCTION somme
288 :
289 : ! **************************************************************************************************
290 : !> \brief Compute the angular dependance (on theta) of the forcefield
291 : !> \param anglepart ...
292 : !> \param VH ...
293 : !> \param gal21 ...
294 : !> \param r_last_update_pbc ...
295 : !> \param iparticle ...
296 : !> \param jparticle ...
297 : !> \param cell ...
298 : !> \param particle_set ...
299 : !> \param nvec ...
300 : !> \param energy ...
301 : !> \param mm_section ...
302 : !> \return ...
303 : !> \retval angular ...
304 : ! **************************************************************************************************
305 5732 : SUBROUTINE angular(anglepart, VH, gal21, r_last_update_pbc, iparticle, jparticle, cell, &
306 : particle_set, nvec, energy, mm_section)
307 : REAL(KIND=dp) :: anglepart, VH
308 : TYPE(gal21_pot_type), POINTER :: gal21
309 : TYPE(pos_type), DIMENSION(:), POINTER :: r_last_update_pbc
310 : INTEGER, INTENT(IN) :: iparticle, jparticle
311 : TYPE(cell_type), POINTER :: cell
312 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
313 : REAL(KIND=dp), DIMENSION(3) :: nvec
314 : LOGICAL :: energy
315 : TYPE(section_vals_type), POINTER :: mm_section
316 :
317 : CHARACTER(LEN=2) :: element_symbol
318 : INTEGER :: count_h, iatom, index_h1, index_h2, &
319 : index_outfile, natom
320 : REAL(KIND=dp) :: a1, a2, a3, a4, BH, costheta, &
321 : h_max_dist, rih(3), rih1(3), rih2(3), &
322 : rix(3), rjh1(3), rjh2(3), theta
323 : TYPE(cp_logger_type), POINTER :: logger
324 :
325 5732 : count_h = 0
326 5732 : index_h1 = 0
327 5732 : index_h2 = 0
328 5732 : h_max_dist = 2.1_dp ! 1.1 angstrom
329 5732 : natom = SIZE(particle_set)
330 :
331 4992572 : DO iatom = 1, natom !Loop on every atom of the system
332 : CALL get_atomic_kind(atomic_kind=particle_set(iatom)%atomic_kind, &
333 4986840 : element_symbol=element_symbol)
334 4986840 : IF (element_symbol /= "H") CYCLE !Kepp only hydrogen
335 2590864 : rih(:) = pbc(r_last_update_pbc(iparticle)%r(:), r_last_update_pbc(iatom)%r(:), cell)
336 10363456 : IF (NORM2(rih) >= h_max_dist) CYCLE !Keep only hydrogen that are bounded to the considered O
337 11464 : count_h = count_h + 1
338 17196 : IF (count_h == 1) THEN
339 : index_h1 = iatom
340 5732 : ELSE IF (count_h == 2) THEN
341 5732 : index_h2 = iatom
342 : END IF
343 : END DO
344 :
345 : ! Abort if the oxygen is not part of a water molecule (2 H)
346 5732 : IF (count_h /= 2) THEN
347 : CALL cp_abort(__LOCATION__, &
348 0 : " Error: Found "//cp_to_string(count_h)//" H atoms for O atom "//cp_to_string(iparticle))
349 : END IF
350 :
351 5732 : a1 = gal21%a11 + gal21%a12*gal21%gcn(jparticle) + gal21%a13*gal21%gcn(jparticle)*gal21%gcn(jparticle)
352 5732 : a2 = gal21%a21 + gal21%a22*gal21%gcn(jparticle) + gal21%a23*gal21%gcn(jparticle)*gal21%gcn(jparticle)
353 5732 : a3 = gal21%a31 + gal21%a32*gal21%gcn(jparticle) + gal21%a33*gal21%gcn(jparticle)*gal21%gcn(jparticle)
354 5732 : a4 = gal21%a41 + gal21%a42*gal21%gcn(jparticle) + gal21%a43*gal21%gcn(jparticle)*gal21%gcn(jparticle)
355 :
356 5732 : rih1(:) = pbc(r_last_update_pbc(iparticle)%r(:), r_last_update_pbc(index_h1)%r(:), cell)
357 5732 : rih2(:) = pbc(r_last_update_pbc(iparticle)%r(:), r_last_update_pbc(index_h2)%r(:), cell)
358 22928 : rix(:) = rih1(:) + rih2(:) ! build the dipole vector rix of the H2O molecule
359 40124 : costheta = DOT_PRODUCT(rix, nvec)/NORM2(rix)
360 5732 : IF (costheta < -1.0_dp) costheta = -1.0_dp
361 5732 : IF (costheta > +1.0_dp) costheta = +1.0_dp
362 5732 : theta = ACOS(costheta) ! Theta is the angle between the normal to the surface and the dipole
363 : anglepart = a1*costheta + a2*COS(2.0_dp*theta) + a3*COS(3.0_dp*theta) &
364 5732 : + a4*COS(4.0_dp*theta) ! build the fourier series
365 :
366 5732 : BH = gal21%BH1 + gal21%gcn(jparticle)*gal21%BH2
367 :
368 5732 : rjh1(:) = pbc(r_last_update_pbc(jparticle)%r(:), r_last_update_pbc(index_h1)%r(:), cell)
369 5732 : rjh2(:) = pbc(r_last_update_pbc(jparticle)%r(:), r_last_update_pbc(index_h2)%r(:), cell)
370 40124 : VH = (gal21%AH2*gal21%gcn(jparticle) + gal21%AH1)*(EXP(-BH*NORM2(rjh1)) + EXP(-BH*NORM2(rjh2)))
371 :
372 : ! For fit purpose
373 5732 : IF (gal21%express .AND. energy) THEN
374 0 : logger => cp_get_default_logger()
375 : index_outfile = cp_print_key_unit_nr(logger, mm_section, &
376 0 : "PRINT%PROGRAM_RUN_INFO", extension=".mmLog")
377 :
378 0 : IF (index_outfile > 0) WRITE (index_outfile, *) "Fourier", costheta, COS(2.0_dp*theta), COS(3.0_dp*theta), &
379 0 : COS(4.0_dp*theta) !, theta
380 0 : IF (index_outfile > 0) WRITE (index_outfile, *) "H_rep", EXP(-BH*NORM2(rjh1)) + &
381 0 : EXP(-BH*NORM2(rjh2))
382 :
383 : CALL cp_print_key_finished_output(index_outfile, logger, mm_section, &
384 0 : "PRINT%PROGRAM_RUN_INFO")
385 : END IF
386 :
387 5732 : END SUBROUTINE angular
388 :
389 : ! **************************************************************************************************
390 : !> \brief forces generated by the GAL2119 potential
391 : !> \param gal21 all parameters of GAL2119
392 : !> \param r_last_update_pbc position of every atoms on previous frame
393 : !> \param iparticle first index of the atom of the evaluated pair
394 : !> \param jparticle second index of the atom of the evaluated pair
395 : !> \param f_nonbond all the forces applying on the system
396 : !> \param pv_nonbond ...
397 : !> \param use_virial request of usage of virial (for barostat)
398 : !> \param cell dimension of the pbc cell
399 : !> \param particle_set full list of atoms of the system
400 : !> \author Clabaut Paul - 2019 - ENS de Lyon
401 : ! **************************************************************************************************
402 5732 : SUBROUTINE gal21_forces(gal21, r_last_update_pbc, iparticle, jparticle, f_nonbond, pv_nonbond, &
403 : use_virial, cell, particle_set)
404 : TYPE(gal21_pot_type), POINTER :: gal21
405 : TYPE(pos_type), DIMENSION(:), POINTER :: r_last_update_pbc
406 : INTEGER, INTENT(IN) :: iparticle, jparticle
407 : REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT) :: f_nonbond, pv_nonbond
408 : LOGICAL, INTENT(IN) :: use_virial
409 : TYPE(cell_type), POINTER :: cell
410 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
411 :
412 : CHARACTER(LEN=2) :: element_symbol
413 : REAL(KIND=dp) :: anglepart, AO, BO, bxy, bz, cosalpha, dGauss(3), drji, drjicosalpha(3), &
414 : drjisinalpha(3), dTT(3), dweight(3), eps, nvec(3), prefactor, rji(3), rji_hat(3), &
415 : sinalpha, sum_weight, Vgaussian, VH, weight
416 : TYPE(section_vals_type), POINTER :: mm_section
417 :
418 : CALL get_atomic_kind(atomic_kind=particle_set(iparticle)%atomic_kind, &
419 5732 : element_symbol=element_symbol)
420 :
421 5732 : IF (element_symbol == "O") THEN !To avoid counting two times each pair
422 :
423 2866 : rji(:) = pbc(r_last_update_pbc(jparticle)%r(:), r_last_update_pbc(iparticle)%r(:), cell)
424 11464 : drji = NORM2(rji)
425 11464 : rji_hat(:) = rji(:)/drji ! hat = pure directional component of a given vector
426 :
427 2866 : IF (.NOT. ALLOCATED(gal21%n_vectors)) THEN !First calling of the forcefield only
428 0 : ALLOCATE (gal21%n_vectors(3, SIZE(particle_set)))
429 0 : gal21%n_vectors(:, :) = 0.0_dp
430 : END IF
431 :
432 : !Build epsilon attraction and the a parameters of the Fourier serie as quadratic fucntion of gcn
433 2866 : eps = gal21%epsilon1*gal21%gcn(jparticle)*gal21%gcn(jparticle) + gal21%epsilon2*gal21%gcn(jparticle) + gal21%epsilon3
434 2866 : bxy = gal21%bxy1 + gal21%bxy2*gal21%gcn(jparticle)
435 2866 : bz = gal21%bz1 + gal21%bz2*gal21%gcn(jparticle)
436 :
437 : !Angular dependance %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
438 :
439 : ! Calculation of the normal vector centered on the Me atom of the pair, only the first time that an interaction with
440 : ! the metal atom of the pair is evaluated
441 : IF (gal21%n_vectors(1, jparticle) == 0.0_dp .AND. &
442 2866 : gal21%n_vectors(2, jparticle) == 0.0_dp .AND. &
443 : gal21%n_vectors(3, jparticle) == 0.0_dp) THEN
444 : gal21%n_vectors(:, jparticle) = normale(gal21, r_last_update_pbc, jparticle, &
445 0 : particle_set, cell)
446 : END IF
447 :
448 11464 : nvec(:) = gal21%n_vectors(:, jparticle) !Else, retrive it, should not have moved sinc metal is supposed to be frozen
449 :
450 : !Calculation of the sum of the expontial weights of each Me surrounding the principal one
451 2866 : sum_weight = somme(gal21, r_last_update_pbc, iparticle, particle_set, cell)
452 :
453 : !Exponential damping weight for angular dependance
454 2866 : weight = EXP(-drji/gal21%r1)
455 11464 : dweight(:) = 1.0_dp/gal21%r1*weight*rji_hat(:) !Derivativ of it
456 :
457 : !Calculation of the truncated fourier series of the water-dipole/surface-normal angle
458 2866 : NULLIFY (mm_section)
459 : anglepart = 0.0_dp
460 : VH = 0.0_dp
461 : CALL angular(anglepart, VH, gal21, r_last_update_pbc, iparticle, jparticle, cell, particle_set, nvec, &
462 2866 : .FALSE., mm_section)
463 :
464 : !Build the average of the exponential weight while avoiding division by 0
465 2866 : IF (weight /= 0) THEN
466 : ! Calculate the first component of the derivativ of the angular term
467 : f_nonbond(1:3, iparticle) = f_nonbond(1:3, iparticle) + 2.0_dp*dweight(1:3)*weight* &
468 11464 : anglepart/sum_weight
469 :
470 2866 : IF (use_virial) THEN
471 : pv_nonbond(1, 1:3) = pv_nonbond(1, 1:3) + rji(1)*2.0_dp*dweight(1:3)*weight* &
472 0 : anglepart/sum_weight
473 : pv_nonbond(2, 1:3) = pv_nonbond(2, 1:3) + rji(2)*2.0_dp*dweight(1:3)*weight* &
474 0 : anglepart/sum_weight
475 : pv_nonbond(3, 1:3) = pv_nonbond(3, 1:3) + rji(3)*2.0_dp*dweight(1:3)*weight* &
476 0 : anglepart/sum_weight
477 : END IF
478 :
479 : ! Calculate the second component of the derivativ of the angular term
480 : CALL somme_d(gal21, r_last_update_pbc, iparticle, jparticle, &
481 2866 : f_nonbond, pv_nonbond, use_virial, particle_set, cell, anglepart, sum_weight)
482 :
483 2866 : prefactor = (-1.0_dp)*weight*weight/sum_weight ! Avoiding division by 0
484 :
485 : ! Calculate the third component of the derivativ of the angular term
486 : CALL angular_d(gal21, r_last_update_pbc, iparticle, jparticle, &
487 2866 : f_nonbond, pv_nonbond, use_virial, prefactor, cell, particle_set, nvec)
488 : END IF
489 : !END Angular%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
490 :
491 : !Attractive Gaussian %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
492 : !Alpha is the angle of the Me-O vector with the normale vector. Used for gaussian attaction
493 11464 : cosalpha = DOT_PRODUCT(rji, nvec)/drji
494 2866 : IF (cosalpha < -1.0_dp) cosalpha = -1.0_dp
495 : IF (cosalpha > +1.0_dp) cosalpha = +1.0_dp
496 2866 : sinalpha = SIN(ACOS(cosalpha))
497 :
498 : !Gaussian component of the energy
499 : Vgaussian = -1.0_dp*eps*EXP(-bz*DOT_PRODUCT(rji, rji)*cosalpha*cosalpha &
500 11464 : - bxy*DOT_PRODUCT(rji, rji)*sinalpha*sinalpha)
501 :
502 : ! Calculation of partial derivativ of the gaussian components
503 11464 : drjicosalpha(:) = rji_hat(:)*cosalpha + nvec(:) - cosalpha*rji_hat(:)
504 11464 : drjisinalpha(:) = rji_hat(:)*sinalpha - (cosalpha/sinalpha)*(nvec(:) - cosalpha*rji_hat(:))
505 : dGauss(:) = (-1.0_dp*bz*2*drji*cosalpha*drjicosalpha - &
506 11464 : 1.0_dp*bxy*2*drji*sinalpha*drjisinalpha)*Vgaussian*(-1.0_dp)
507 :
508 : ! Force due to gaussian term
509 11464 : f_nonbond(1:3, iparticle) = f_nonbond(1:3, iparticle) + dGauss(1:3)
510 :
511 2866 : IF (use_virial) THEN
512 0 : pv_nonbond(1, 1:3) = pv_nonbond(1, 1:3) + rji(1)*dGauss(1:3)
513 0 : pv_nonbond(2, 1:3) = pv_nonbond(2, 1:3) + rji(2)*dGauss(1:3)
514 0 : pv_nonbond(3, 1:3) = pv_nonbond(3, 1:3) + rji(3)*dGauss(1:3)
515 : END IF
516 : !END Gaussian%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
517 :
518 2866 : AO = gal21%AO1 + gal21%AO2*gal21%gcn(jparticle)
519 2866 : BO = gal21%BO1 + gal21%BO2*gal21%gcn(jparticle)
520 :
521 : !Derivativ of the Tang and Toennies term
522 : dTT(:) = (-(AO*BO + (BO**7)*gal21%c/720)*EXP(-BO*drji) + 6*(gal21%c/drji**7)* &
523 : (1.0 - EXP(-BO*drji) &
524 : - BO*drji*EXP(-BO*drji) &
525 : - (((BO*drji)**2)/2)*EXP(-BO*drji) &
526 : - (((BO*drji)**3)/6)*EXP(-BO*drji) &
527 : - (((BO*drji)**4)/24)*EXP(-BO*drji) &
528 : - (((BO*drji)**5)/120)*EXP(-BO*drji) &
529 : - (((BO*drji)**6)/720)*EXP(-BO*drji)) &
530 11464 : )*rji_hat(:)
531 :
532 : ! Force of Tang & Toennies
533 11464 : f_nonbond(1:3, iparticle) = f_nonbond(1:3, iparticle) - dTT(1:3)
534 :
535 2866 : IF (use_virial) THEN
536 0 : pv_nonbond(1, 1:3) = pv_nonbond(1, 1:3) - rji(1)*dTT(1:3)
537 0 : pv_nonbond(2, 1:3) = pv_nonbond(2, 1:3) - rji(2)*dTT(1:3)
538 0 : pv_nonbond(3, 1:3) = pv_nonbond(3, 1:3) - rji(3)*dTT(1:3)
539 : END IF
540 :
541 : END IF
542 :
543 5732 : END SUBROUTINE gal21_forces
544 :
545 : ! **************************************************************************************************
546 : !> \brief Derivativ of the second component of angular dependance
547 : !> \param gal21 ...
548 : !> \param r_last_update_pbc ...
549 : !> \param iparticle ...
550 : !> \param jparticle ...
551 : !> \param f_nonbond ...
552 : !> \param pv_nonbond ...
553 : !> \param use_virial ...
554 : !> \param particle_set ...
555 : !> \param cell ...
556 : !> \param anglepart ...
557 : !> \param sum_weight ...
558 : ! **************************************************************************************************
559 2866 : SUBROUTINE somme_d(gal21, r_last_update_pbc, iparticle, jparticle, &
560 2866 : f_nonbond, pv_nonbond, use_virial, particle_set, cell, anglepart, sum_weight)
561 : TYPE(gal21_pot_type), POINTER :: gal21
562 : TYPE(pos_type), DIMENSION(:), POINTER :: r_last_update_pbc
563 : INTEGER, INTENT(IN) :: iparticle, jparticle
564 : REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT) :: f_nonbond, pv_nonbond
565 : LOGICAL, INTENT(IN) :: use_virial
566 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
567 : TYPE(cell_type), POINTER :: cell
568 : REAL(KIND=dp), INTENT(IN) :: anglepart, sum_weight
569 :
570 : CHARACTER(LEN=2) :: element_symbol_k
571 : INTEGER :: kparticle, natom
572 : REAL(KIND=dp) :: drki, dwdr(3), rji(3), rki(3), &
573 : rki_hat(3), weight_rji
574 :
575 2866 : rji(:) = pbc(r_last_update_pbc(jparticle)%r(:), r_last_update_pbc(iparticle)%r(:), cell)
576 11464 : weight_rji = EXP(-NORM2(rji)/gal21%r1)
577 :
578 2866 : natom = SIZE(particle_set)
579 2496286 : DO kparticle = 1, natom !Loop on every atom of the system
580 : CALL get_atomic_kind(atomic_kind=particle_set(kparticle)%atomic_kind, &
581 2493420 : element_symbol=element_symbol_k)
582 : !Keep only metals
583 2493420 : IF (element_symbol_k /= gal21%met1 .AND. element_symbol_k /= gal21%met2) CYCLE
584 550272 : rki(:) = pbc(r_last_update_pbc(kparticle)%r(:), r_last_update_pbc(iparticle)%r(:), cell)
585 : !Keep only those within cutoff distance of the oxygen atom of the evaluated pair (the omega ensemble)
586 2201088 : IF (NORM2(rki) > gal21%rcutsq) CYCLE
587 2201088 : drki = NORM2(rki)
588 2201088 : rki_hat(:) = rki(:)/drki
589 :
590 : !Build the sum of derivativs
591 2201088 : IF (element_symbol_k == gal21%met1) dwdr(:) = (-1.0_dp)*(1.0_dp/gal21%r1)*EXP(-drki/gal21%r1)*rki_hat(:)
592 550272 : IF (element_symbol_k == gal21%met2) dwdr(:) = (-1.0_dp)*(1.0_dp/gal21%r2)*EXP(-drki/gal21%r2)*rki_hat(:)
593 :
594 : f_nonbond(1:3, iparticle) = f_nonbond(1:3, iparticle) + dwdr(1:3)*weight_rji &
595 2201088 : *weight_rji*anglepart/(sum_weight**2)
596 :
597 553138 : IF (use_virial) THEN
598 : pv_nonbond(1, 1:3) = pv_nonbond(1, 1:3) + rki(1)*dwdr(1:3)*weight_rji &
599 0 : *weight_rji*anglepart/(sum_weight**2)
600 : pv_nonbond(2, 1:3) = pv_nonbond(2, 1:3) + rki(2)*dwdr(1:3)*weight_rji &
601 0 : *weight_rji*anglepart/(sum_weight**2)
602 : pv_nonbond(3, 1:3) = pv_nonbond(3, 1:3) + rki(3)*dwdr(1:3)*weight_rji &
603 0 : *weight_rji*anglepart/(sum_weight**2)
604 : END IF
605 :
606 : END DO
607 :
608 2866 : END SUBROUTINE somme_d
609 :
610 : ! **************************************************************************************************
611 : !> \brief Derivativ of the third component of angular term
612 : !> \param gal21 ...
613 : !> \param r_last_update_pbc ...
614 : !> \param iparticle ...
615 : !> \param jparticle ...
616 : !> \param f_nonbond ...
617 : !> \param pv_nonbond ...
618 : !> \param use_virial ...
619 : !> \param prefactor ...
620 : !> \param cell ...
621 : !> \param particle_set ...
622 : !> \param nvec ...
623 : ! **************************************************************************************************
624 2866 : SUBROUTINE angular_d(gal21, r_last_update_pbc, iparticle, jparticle, f_nonbond, &
625 2866 : pv_nonbond, use_virial, prefactor, cell, particle_set, nvec)
626 : TYPE(gal21_pot_type), POINTER :: gal21
627 : TYPE(pos_type), DIMENSION(:), POINTER :: r_last_update_pbc
628 : INTEGER, INTENT(IN) :: iparticle, jparticle
629 : REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT) :: f_nonbond, pv_nonbond
630 : LOGICAL, INTENT(IN) :: use_virial
631 : REAL(KIND=dp), INTENT(IN) :: prefactor
632 : TYPE(cell_type), POINTER :: cell
633 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
634 : REAL(KIND=dp), DIMENSION(3) :: nvec
635 :
636 : CHARACTER(LEN=2) :: element_symbol
637 : INTEGER :: count_h, iatom, index_h1, index_h2, natom
638 : REAL(KIND=dp) :: a1, a2, a3, a4, BH, costheta, &
639 : dsumdtheta, h_max_dist, theta
640 : REAL(KIND=dp), DIMENSION(3) :: dangular, dcostheta, rih, rih1, rih2, &
641 : rix, rix_hat, rjh1, rjh2, rji, rji_hat
642 :
643 2866 : count_h = 0
644 2866 : index_h1 = 0
645 2866 : index_h2 = 0
646 2866 : h_max_dist = 2.1_dp ! 1.1 angstrom
647 2866 : natom = SIZE(particle_set)
648 :
649 2496286 : DO iatom = 1, natom !Loop on every atom of the system
650 : CALL get_atomic_kind(atomic_kind=particle_set(iatom)%atomic_kind, &
651 2493420 : element_symbol=element_symbol)
652 2493420 : IF (element_symbol /= "H") CYCLE !Kepp only hydrogen
653 1295432 : rih(:) = pbc(r_last_update_pbc(iparticle)%r(:), r_last_update_pbc(iatom)%r(:), cell)
654 5181728 : IF (NORM2(rih) >= h_max_dist) CYCLE !Keep only hydrogen that are bounded to the considered O
655 5732 : count_h = count_h + 1
656 8598 : IF (count_h == 1) THEN
657 : index_h1 = iatom
658 2866 : ELSE IF (count_h == 2) THEN
659 2866 : index_h2 = iatom
660 : END IF
661 : END DO
662 :
663 : ! Abort if the oxygen is not part of a water molecule (2 H)
664 2866 : IF (count_h /= 2) THEN
665 : CALL cp_abort(__LOCATION__, &
666 0 : " Error: Found "//cp_to_string(count_h)//" H atoms for O atom "//cp_to_string(iparticle))
667 : END IF
668 :
669 2866 : a1 = gal21%a11 + gal21%a12*gal21%gcn(jparticle) + gal21%a13*gal21%gcn(jparticle)*gal21%gcn(jparticle)
670 2866 : a2 = gal21%a21 + gal21%a22*gal21%gcn(jparticle) + gal21%a23*gal21%gcn(jparticle)*gal21%gcn(jparticle)
671 2866 : a3 = gal21%a31 + gal21%a32*gal21%gcn(jparticle) + gal21%a33*gal21%gcn(jparticle)*gal21%gcn(jparticle)
672 2866 : a4 = gal21%a41 + gal21%a42*gal21%gcn(jparticle) + gal21%a43*gal21%gcn(jparticle)*gal21%gcn(jparticle)
673 :
674 2866 : rji(:) = pbc(r_last_update_pbc(jparticle)%r(:), r_last_update_pbc(iparticle)%r(:), cell)
675 20062 : rji_hat(:) = rji(:)/NORM2(rji) ! hat = pure directional component of a given vector
676 :
677 : !dipole vector rix of the H2O molecule
678 2866 : rih1(:) = pbc(r_last_update_pbc(iparticle)%r(:), r_last_update_pbc(index_h1)%r(:), cell)
679 2866 : rih2(:) = pbc(r_last_update_pbc(iparticle)%r(:), r_last_update_pbc(index_h2)%r(:), cell)
680 11464 : rix(:) = rih1(:) + rih2(:) ! build the dipole vector rix of the H2O molecule
681 20062 : rix_hat(:) = rix(:)/NORM2(rix) ! hat = pure directional component of a given vector
682 20062 : costheta = DOT_PRODUCT(rix, nvec)/NORM2(rix) ! Theta is the angle between the normal to the surface and the dipole
683 2866 : IF (costheta < -1.0_dp) costheta = -1.0_dp
684 : IF (costheta > +1.0_dp) costheta = +1.0_dp
685 2866 : theta = ACOS(costheta) ! Theta is the angle between the normal to the surface and the dipole
686 :
687 : ! Calculation of partial derivativ of the angular components
688 : dsumdtheta = -1.0_dp*a1*SIN(theta) - a2*2.0_dp*SIN(2.0_dp*theta) - &
689 2866 : a3*3.0_dp*SIN(3.0_dp*theta) - a4*4.0_dp*SIN(4.0_dp*theta)
690 20062 : dcostheta(:) = (1.0_dp/NORM2(rix))*(nvec(:) - costheta*rix_hat(:))
691 11464 : dangular(:) = prefactor*dsumdtheta*(-1.0_dp/SIN(theta))*dcostheta(:)
692 :
693 : !Force due to the third component of the derivativ of the angular term
694 11464 : f_nonbond(1:3, iparticle) = f_nonbond(1:3, iparticle) - dangular(1:3)*2.0_dp !(one per H)
695 11464 : f_nonbond(1:3, index_h1) = f_nonbond(1:3, index_h1) + dangular(1:3)
696 11464 : f_nonbond(1:3, index_h2) = f_nonbond(1:3, index_h2) + dangular(1:3)
697 :
698 2866 : IF (use_virial) THEN
699 0 : pv_nonbond(1, 1:3) = pv_nonbond(1, 1:3) + rix(1)*dangular(1:3)
700 0 : pv_nonbond(2, 1:3) = pv_nonbond(2, 1:3) + rix(2)*dangular(1:3)
701 0 : pv_nonbond(3, 1:3) = pv_nonbond(3, 1:3) + rix(3)*dangular(1:3)
702 : END IF
703 :
704 2866 : BH = gal21%BH1 + gal21%gcn(jparticle)*gal21%BH2
705 :
706 2866 : rjh1(:) = pbc(r_last_update_pbc(jparticle)%r(:), r_last_update_pbc(index_h1)%r(:), cell)
707 : f_nonbond(1:3, index_h1) = f_nonbond(1:3, index_h1) + (gal21%AH2*gal21%gcn(jparticle) + gal21%AH1)* &
708 20062 : BH*EXP(-BH*NORM2(rjh1))*rjh1(:)/NORM2(rjh1)
709 :
710 2866 : IF (use_virial) THEN
711 : pv_nonbond(1, 1:3) = pv_nonbond(1, 1:3) + rjh1(1)*((gal21%AH2*gal21%gcn(jparticle) + gal21%AH1)* &
712 : BH*EXP(-BH*NORM2(rjh1))) &
713 0 : *rjh1(:)/NORM2(rjh1)
714 : pv_nonbond(2, 1:3) = pv_nonbond(2, 1:3) + rjh1(2)*((gal21%AH2*gal21%gcn(jparticle) + gal21%AH1)* &
715 : BH*EXP(-BH*NORM2(rjh1))) &
716 0 : *rjh1(:)/NORM2(rjh1)
717 : pv_nonbond(3, 1:3) = pv_nonbond(3, 1:3) + rjh1(3)*((gal21%AH2*gal21%gcn(jparticle) + gal21%AH1)* &
718 : BH*EXP(-BH*NORM2(rjh1))) &
719 0 : *rjh1(:)/NORM2(rjh1)
720 : END IF
721 :
722 2866 : rjh2(:) = pbc(r_last_update_pbc(jparticle)%r(:), r_last_update_pbc(index_h2)%r(:), cell)
723 : f_nonbond(1:3, index_h2) = f_nonbond(1:3, index_h2) + ((gal21%AH2*gal21%gcn(jparticle) + gal21%AH1)* &
724 : BH*EXP(-BH*NORM2(rjh2))) &
725 20062 : *rjh2(:)/NORM2(rjh2)
726 :
727 2866 : IF (use_virial) THEN
728 : pv_nonbond(1, 1:3) = pv_nonbond(1, 1:3) + rjh2(1)*((gal21%AH2*gal21%gcn(jparticle) + gal21%AH1)* &
729 : BH*EXP(-BH*NORM2(rjh2))) &
730 0 : *rjh2(:)/NORM2(rjh2)
731 : pv_nonbond(2, 1:3) = pv_nonbond(2, 1:3) + rjh2(2)*((gal21%AH2*gal21%gcn(jparticle) + gal21%AH1)* &
732 : BH*EXP(-BH*NORM2(rjh2))) &
733 0 : *rjh2(:)/NORM2(rjh2)
734 : pv_nonbond(3, 1:3) = pv_nonbond(3, 1:3) + rjh2(3)*((gal21%AH2*gal21%gcn(jparticle) + gal21%AH1)* &
735 : BH*EXP(-BH*NORM2(rjh2))) &
736 0 : *rjh2(:)/NORM2(rjh2)
737 : END IF
738 :
739 2866 : END SUBROUTINE angular_d
740 :
741 : ! **************************************************************************************************
742 : !> \brief ...
743 : !> \param nonbonded ...
744 : !> \param potparm ...
745 : !> \param glob_loc_list ...
746 : !> \param glob_cell_v ...
747 : !> \param glob_loc_list_a ...
748 : !> \param cell ...
749 : !> \par History
750 : ! **************************************************************************************************
751 2 : SUBROUTINE setup_gal21_arrays(nonbonded, potparm, glob_loc_list, glob_cell_v, &
752 : glob_loc_list_a, cell)
753 : TYPE(fist_neighbor_type), POINTER :: nonbonded
754 : TYPE(pair_potential_pp_type), POINTER :: potparm
755 : INTEGER, DIMENSION(:, :), POINTER :: glob_loc_list
756 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: glob_cell_v
757 : INTEGER, DIMENSION(:), POINTER :: glob_loc_list_a
758 : TYPE(cell_type), POINTER :: cell
759 :
760 : CHARACTER(LEN=*), PARAMETER :: routineN = 'setup_gal21_arrays'
761 :
762 : INTEGER :: handle, i, iend, igrp, ikind, ilist, &
763 : ipair, istart, jkind, nkinds, npairs, &
764 : npairs_tot
765 2 : INTEGER, DIMENSION(:), POINTER :: work_list, work_list2
766 2 : INTEGER, DIMENSION(:, :), POINTER :: list
767 : REAL(KIND=dp), DIMENSION(3) :: cell_v, cvi
768 2 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: rwork_list
769 : TYPE(neighbor_kind_pairs_type), POINTER :: neighbor_kind_pair
770 : TYPE(pair_potential_single_type), POINTER :: pot
771 :
772 0 : CPASSERT(.NOT. ASSOCIATED(glob_loc_list))
773 2 : CPASSERT(.NOT. ASSOCIATED(glob_loc_list_a))
774 2 : CPASSERT(.NOT. ASSOCIATED(glob_cell_v))
775 2 : CALL timeset(routineN, handle)
776 2 : npairs_tot = 0
777 2 : nkinds = SIZE(potparm%pot, 1)
778 56 : DO ilist = 1, nonbonded%nlists
779 54 : neighbor_kind_pair => nonbonded%neighbor_kind_pairs(ilist)
780 54 : npairs = neighbor_kind_pair%npairs
781 54 : IF (npairs == 0) CYCLE
782 336 : Kind_Group_Loop1: DO igrp = 1, neighbor_kind_pair%ngrp_kind
783 316 : istart = neighbor_kind_pair%grp_kind_start(igrp)
784 316 : iend = neighbor_kind_pair%grp_kind_end(igrp)
785 316 : ikind = neighbor_kind_pair%ij_kind(1, igrp)
786 316 : jkind = neighbor_kind_pair%ij_kind(2, igrp)
787 316 : pot => potparm%pot(ikind, jkind)%pot
788 316 : npairs = iend - istart + 1
789 316 : IF (pot%no_mb) CYCLE Kind_Group_Loop1
790 90 : DO i = 1, SIZE(pot%type)
791 334 : IF (pot%type(i) == gal21_type) npairs_tot = npairs_tot + npairs
792 : END DO
793 : END DO Kind_Group_Loop1
794 : END DO
795 6 : ALLOCATE (work_list(npairs_tot))
796 4 : ALLOCATE (work_list2(npairs_tot))
797 6 : ALLOCATE (glob_loc_list(2, npairs_tot))
798 6 : ALLOCATE (glob_cell_v(3, npairs_tot))
799 : ! Fill arrays with data
800 2 : npairs_tot = 0
801 56 : DO ilist = 1, nonbonded%nlists
802 54 : neighbor_kind_pair => nonbonded%neighbor_kind_pairs(ilist)
803 54 : npairs = neighbor_kind_pair%npairs
804 54 : IF (npairs == 0) CYCLE
805 336 : Kind_Group_Loop2: DO igrp = 1, neighbor_kind_pair%ngrp_kind
806 316 : istart = neighbor_kind_pair%grp_kind_start(igrp)
807 316 : iend = neighbor_kind_pair%grp_kind_end(igrp)
808 316 : ikind = neighbor_kind_pair%ij_kind(1, igrp)
809 316 : jkind = neighbor_kind_pair%ij_kind(2, igrp)
810 316 : list => neighbor_kind_pair%list
811 1264 : cvi = neighbor_kind_pair%cell_vector
812 316 : pot => potparm%pot(ikind, jkind)%pot
813 316 : npairs = iend - istart + 1
814 316 : IF (pot%no_mb) CYCLE Kind_Group_Loop2
815 234 : cell_v = MATMUL(cell%hmat, cvi)
816 90 : DO i = 1, SIZE(pot%type)
817 : ! gal21
818 334 : IF (pot%type(i) == gal21_type) THEN
819 17618 : DO ipair = 1, npairs
820 105600 : glob_loc_list(:, npairs_tot + ipair) = list(:, istart - 1 + ipair)
821 70418 : glob_cell_v(1:3, npairs_tot + ipair) = cell_v(1:3)
822 : END DO
823 18 : npairs_tot = npairs_tot + npairs
824 : END IF
825 : END DO
826 : END DO Kind_Group_Loop2
827 : END DO
828 : ! Order the arrays w.r.t. the first index of glob_loc_list
829 2 : CALL sort(glob_loc_list(1, :), npairs_tot, work_list)
830 17602 : DO ipair = 1, npairs_tot
831 17602 : work_list2(ipair) = glob_loc_list(2, work_list(ipair))
832 : END DO
833 35204 : glob_loc_list(2, :) = work_list2
834 2 : DEALLOCATE (work_list2)
835 6 : ALLOCATE (rwork_list(3, npairs_tot))
836 17602 : DO ipair = 1, npairs_tot
837 140802 : rwork_list(:, ipair) = glob_cell_v(:, work_list(ipair))
838 : END DO
839 140804 : glob_cell_v = rwork_list
840 2 : DEALLOCATE (rwork_list)
841 2 : DEALLOCATE (work_list)
842 6 : ALLOCATE (glob_loc_list_a(npairs_tot))
843 35204 : glob_loc_list_a = glob_loc_list(1, :)
844 2 : CALL timestop(handle)
845 4 : END SUBROUTINE setup_gal21_arrays
846 :
847 : ! **************************************************************************************************
848 : !> \brief ...
849 : !> \param glob_loc_list ...
850 : !> \param glob_cell_v ...
851 : !> \param glob_loc_list_a ...
852 : ! **************************************************************************************************
853 1 : SUBROUTINE destroy_gal21_arrays(glob_loc_list, glob_cell_v, glob_loc_list_a)
854 : INTEGER, DIMENSION(:, :), POINTER :: glob_loc_list
855 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: glob_cell_v
856 : INTEGER, DIMENSION(:), POINTER :: glob_loc_list_a
857 :
858 1 : IF (ASSOCIATED(glob_loc_list)) THEN
859 1 : DEALLOCATE (glob_loc_list)
860 : END IF
861 1 : IF (ASSOCIATED(glob_loc_list_a)) THEN
862 1 : DEALLOCATE (glob_loc_list_a)
863 : END IF
864 1 : IF (ASSOCIATED(glob_cell_v)) THEN
865 1 : DEALLOCATE (glob_cell_v)
866 : END IF
867 :
868 1 : END SUBROUTINE destroy_gal21_arrays
869 :
870 : ! **************************************************************************************************
871 : !> \brief prints the number of OH- ions or H3O+ ions near surface
872 : !> \param nr_ions number of ions
873 : !> \param mm_section ...
874 : !> \param para_env ...
875 : !> \param print_oh flag indicating if number OH- is printed
876 : !> \param print_h3o flag indicating if number H3O+ is printed
877 : !> \param print_o flag indicating if number O^(2-) is printed
878 : ! **************************************************************************************************
879 0 : SUBROUTINE print_nr_ions_gal21(nr_ions, mm_section, para_env, print_oh, &
880 : print_h3o, print_o)
881 : INTEGER, INTENT(INOUT) :: nr_ions
882 : TYPE(section_vals_type), POINTER :: mm_section
883 : TYPE(mp_para_env_type), OPTIONAL, POINTER :: para_env
884 : LOGICAL, INTENT(IN) :: print_oh, print_h3o, print_o
885 :
886 : INTEGER :: iw
887 : TYPE(cp_logger_type), POINTER :: logger
888 :
889 0 : NULLIFY (logger)
890 :
891 0 : CALL para_env%sum(nr_ions)
892 0 : logger => cp_get_default_logger()
893 :
894 : iw = cp_print_key_unit_nr(logger, mm_section, "PRINT%PROGRAM_RUN_INFO", &
895 0 : extension=".mmLog")
896 :
897 0 : IF (iw > 0 .AND. nr_ions > 0 .AND. print_oh) THEN
898 0 : WRITE (iw, '(/,A,T71,I10,/)') " gal21: number of OH- ions at surface", nr_ions
899 : END IF
900 0 : IF (iw > 0 .AND. nr_ions > 0 .AND. print_h3o) THEN
901 0 : WRITE (iw, '(/,A,T71,I10,/)') " gal21: number of H3O+ ions at surface", nr_ions
902 : END IF
903 0 : IF (iw > 0 .AND. nr_ions > 0 .AND. print_o) THEN
904 0 : WRITE (iw, '(/,A,T71,I10,/)') " gal21: number of O^2- ions at surface", nr_ions
905 : END IF
906 :
907 0 : CALL cp_print_key_finished_output(iw, logger, mm_section, "PRINT%PROGRAM_RUN_INFO")
908 :
909 0 : END SUBROUTINE print_nr_ions_gal21
910 :
911 : END MODULE manybody_gal21
|