(git:34ef472)
qmmm_elpot.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 !> 09.2004 created [tlaino]
11 !> \author Teodoro Laino
12 ! **************************************************************************************************
13 MODULE qmmm_elpot
14  USE cell_types, ONLY: cell_type
17  cp_logger_type
18  USE cp_output_handling, ONLY: cp_p_file,&
22  USE input_constants, ONLY: do_qmmm_coulomb,&
26  USE input_section_types, ONLY: section_vals_type
27  USE kinds, ONLY: default_path_length,&
29  dp
30  USE mathconstants, ONLY: rootpi
31  USE memory_utilities, ONLY: reallocate
32  USE qmmm_gaussian_types, ONLY: qmmm_gaussian_p_type,&
33  qmmm_gaussian_type
34  USE qmmm_types_low, ONLY: qmmm_pot_type,&
35  qmmm_pot_p_type
36 #include "./base/base_uses.f90"
37 
38  IMPLICIT NONE
39  PRIVATE
40 
41  LOGICAL, PRIVATE, PARAMETER :: debug_this_module = .true.
42  CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qmmm_elpot'
43  PUBLIC :: qmmm_potential_init
44 
45 CONTAINS
46 
47 ! **************************************************************************************************
48 !> \brief Initialize the QMMM potential stored on vector,
49 !> according the qmmm_coupl_type
50 !> \param qmmm_coupl_type ...
51 !> \param mm_el_pot_radius ...
52 !> \param potentials ...
53 !> \param pgfs ...
54 !> \param mm_cell ...
55 !> \param compatibility ...
56 !> \param print_section ...
57 !> \par History
58 !> 09.2004 created [tlaino]
59 !> \author Teodoro Laino
60 ! **************************************************************************************************
61  SUBROUTINE qmmm_potential_init(qmmm_coupl_type, mm_el_pot_radius, potentials, &
62  pgfs, mm_cell, compatibility, print_section)
63  INTEGER, INTENT(IN) :: qmmm_coupl_type
64  REAL(kind=dp), DIMENSION(:), POINTER :: mm_el_pot_radius
65  TYPE(qmmm_pot_p_type), DIMENSION(:), POINTER :: potentials
66  TYPE(qmmm_gaussian_p_type), DIMENSION(:), POINTER :: pgfs
67  TYPE(cell_type), POINTER :: mm_cell
68  LOGICAL, INTENT(IN) :: compatibility
69  TYPE(section_vals_type), POINTER :: print_section
70 
71  REAL(kind=dp), PARAMETER :: dx = 0.05_dp
72 
73  CHARACTER(LEN=default_path_length) :: myformat
74  CHARACTER(LEN=default_string_length) :: rc_s
75  INTEGER :: i, ig, ig_start, j, k, myind, ndim, np, &
76  output_unit, unit_nr
77  INTEGER, DIMENSION(:), POINTER :: mm_atom_index
78  LOGICAL :: found
79  REAL(kind=dp) :: a, g, rc, rmax, rmin, t, t1, t2, x
80  REAL(kind=dp), DIMENSION(:), POINTER :: radius
81  REAL(kind=dp), DIMENSION(:, :), POINTER :: pot0_2
82  TYPE(cp_logger_type), POINTER :: logger
83  TYPE(qmmm_gaussian_type), POINTER :: pgf
84 
85  logger => cp_get_default_logger()
86  output_unit = cp_logger_get_default_io_unit(logger)
87  rmin = 0.0_dp
88  rmax = sqrt(mm_cell%hmat(1, 1)**2 + &
89  mm_cell%hmat(2, 2)**2 + &
90  mm_cell%hmat(3, 3)**2)
91  np = ceiling(rmax/dx) + 1
92  !
93  ! Preprocessing
94  !
95  IF (SIZE(mm_el_pot_radius) /= 0) THEN
96  ALLOCATE (radius(1))
97  radius(1) = mm_el_pot_radius(1)
98  ELSE
99  ALLOCATE (radius(0))
100  END IF
101  loop_on_all_values: DO i = 2, SIZE(mm_el_pot_radius)
102  found = .false.
103  loop_on_found_values: DO j = 1, SIZE(radius)
104  IF (mm_el_pot_radius(i) .EQ. radius(j)) THEN
105  found = .true.
106  EXIT loop_on_found_values
107  END IF
108  END DO loop_on_found_values
109  IF (.NOT. found) THEN
110  ndim = SIZE(radius)
111  ndim = ndim + 1
112  CALL reallocate(radius, 1, ndim)
113  radius(ndim) = mm_el_pot_radius(i)
114  END IF
115  END DO loop_on_all_values
116  !
117  cpassert(.NOT. ASSOCIATED(potentials))
118  ALLOCATE (potentials(SIZE(radius)))
119 
120  potential_type: DO k = 1, SIZE(radius)
121 
122  rc = radius(k)
123  ALLOCATE (potentials(k)%Pot)
124  SELECT CASE (qmmm_coupl_type)
125  CASE (do_qmmm_coulomb)
126  NULLIFY (pot0_2)
127  CASE (do_qmmm_pcharge)
128  NULLIFY (pot0_2)
130  ALLOCATE (pot0_2(2, np))
131  END SELECT
132 
133  SELECT CASE (qmmm_coupl_type)
135  ! Do Nothing
137  IF (qmmm_coupl_type == do_qmmm_gauss) THEN
138  ! Smooth Coulomb Potential :: Erf(x/rc)/x
139  pot0_2(1, 1) = 2.0_dp/(rootpi*rc)
140  pot0_2(2, 1) = 0.0_dp
141  x = 0.0_dp
142  DO i = 2, np
143  x = x + dx
144  pot0_2(1, i) = erf(x/rc)/x
145  t = 2._dp/(rootpi*x*rc)*exp(-(x/rc)**2)
146  pot0_2(2, i) = (t - pot0_2(1, i)/x)*dx
147  END DO
148  ELSEIF (qmmm_coupl_type == do_qmmm_swave) THEN
149  ! S-wave expansion :: 1/x - exp(-2*x/rc) * ( 1/x - 1/rc )
150  pot0_2(1, 1) = 1.0_dp/rc
151  pot0_2(2, 1) = 0.0_dp
152  x = 0.0_dp
153  DO i = 2, np
154  x = x + dx
155  t = exp(-2.0_dp*x/rc)/rc
156  pot0_2(1, i) = (1.0_dp - t*(rc + x))/x
157  pot0_2(2, i) = ((t*(rc**2 + 2.0_dp*rc*x + 2.0_dp*x**2)/rc - 1.0_dp)/x**2)*dx
158  END DO
159  END IF
160  pgf => pgfs(k)%pgf
161  cpassert(pgf%Elp_Radius == rc)
162  ig_start = 1
163  IF (compatibility .AND. (qmmm_coupl_type == do_qmmm_gauss)) ig_start = 2
164  DO ig = ig_start, pgf%number_of_gaussians
165  a = pgf%Ak(ig)
166  g = pgf%Gk(ig)
167  pot0_2(1, 1) = pot0_2(1, 1) - a
168  x = 0.0_dp
169  DO i = 2, np
170  x = x + dx
171  t = exp(-(x/g)**2)*a
172  t1 = 1/g**2
173  t2 = t1*t
174  pot0_2(1, i) = pot0_2(1, i) - t
175  pot0_2(2, i) = pot0_2(2, i) + 2.0_dp*x*t2*dx
176  END DO
177  END DO
178 
179  ! Print info on the unidimensional MM electrostatic potential
180  IF (btest(cp_print_key_should_output(logger%iter_info, print_section, "MM_POTENTIAL") &
181  , cp_p_file)) THEN
182  WRITE (rc_s, '(F6.3)') rc
183  unit_nr = cp_print_key_unit_nr(logger, print_section, "MM_POTENTIAL", &
184  extension="_rc="//trim(adjustl(rc_s))//".data")
185  IF (unit_nr > 0) THEN
186  WRITE (unit_nr, '(A)') "# MM ELECTROSTATIC POTENTIAL - UNIDIMENSIONAL - ATOMIC UNITS"
187  WRITE (unit_nr, '(A,I5)') "# MM ELECTROSTATIC POTENTIAL - Nr. of Gaussians:", pgf%number_of_gaussians
188  WRITE (unit_nr, '(A,T10,A,T30,A,T300,A)') "#", "Xval", "Gaussians", "LongRange"
189  myformat = "T10,F15.9,T30,"
190  DO ig = 1, pgf%number_of_gaussians
191  myind = index(myformat, " ")
192  WRITE (myformat(myind:), '(A6)') "F12.9,"
193  END DO
194  myind = index(myformat, " ") - 1
195  myformat = myformat(1:myind)//"T300,F15.9"
196  myind = index(myformat, " ") - 1
197  x = 0.0_dp
198  DO i = 1, np
199  WRITE (unit_nr, '('//myformat(1:myind)//')') &
200  x, (exp(-(x/pgf%Gk(ig))**2)*pgf%Ak(ig), ig=1, pgf%number_of_gaussians), pot0_2(1, i)
201  x = x + dx
202  END DO
203  END IF
204  CALL cp_print_key_finished_output(unit_nr, logger, print_section, &
205  "MM_POTENTIAL")
206  END IF
207  CASE DEFAULT
208  DEALLOCATE (potentials(k)%Pot)
209  IF (output_unit > 0) WRITE (output_unit, '(A)') " QMMM Potential - Spline Interpolation - not Initialized!"
210  cycle potential_type
211  END SELECT
212  NULLIFY (mm_atom_index)
213  ALLOCATE (mm_atom_index(1))
214  ! Build mm_atom_index List
215  DO j = 1, SIZE(mm_el_pot_radius)
216  IF (rc .EQ. mm_el_pot_radius(j)) THEN
217  ndim = SIZE(mm_atom_index)
218  mm_atom_index(ndim) = j
219  CALL reallocate(mm_atom_index, 1, ndim + 1)
220  END IF
221  END DO
222  CALL reallocate(mm_atom_index, 1, ndim)
223 
224  NULLIFY (potentials(k)%Pot%pot0_2)
225  CALL qmmm_pot_type_create(potentials(k)%Pot, pot0_2=pot0_2, &
226  rmax=rmax, rmin=rmin, dx=dx, rc=rc, npts=np, &
227  mm_atom_index=mm_atom_index)
228 
229  END DO potential_type
230  DEALLOCATE (radius)
231  END SUBROUTINE qmmm_potential_init
232 
233 ! **************************************************************************************************
234 !> \brief Creates the qmmm_pot_type structure
235 !> \param Pot ...
236 !> \param pot0_2 ...
237 !> \param Rmax ...
238 !> \param Rmin ...
239 !> \param dx ...
240 !> \param npts ...
241 !> \param rc ...
242 !> \param mm_atom_index ...
243 !> \par History
244 !> 09.2004 created [tlaino]
245 !> \author Teodoro Laino
246 ! **************************************************************************************************
247  SUBROUTINE qmmm_pot_type_create(Pot, pot0_2, Rmax, Rmin, dx, npts, rc, &
248  mm_atom_index)
249  TYPE(qmmm_pot_type), POINTER :: pot
250  REAL(kind=dp), DIMENSION(:, :), POINTER :: pot0_2
251  REAL(kind=dp), INTENT(IN) :: rmax, rmin, dx
252  INTEGER, INTENT(IN) :: npts
253  REAL(kind=dp), INTENT(IN) :: rc
254  INTEGER, DIMENSION(:), POINTER :: mm_atom_index
255 
256  pot%pot0_2 => pot0_2
257  pot%mm_atom_index => mm_atom_index
258  pot%Rmax = rmax
259  pot%Rmin = rmin
260  pot%Rc = rc
261  pot%dx = dx
262  pot%npts = npts
263 
264  END SUBROUTINE qmmm_pot_type_create
265 
266 END MODULE qmmm_elpot
Handles all functions related to the CELL.
Definition: cell_types.F:15
various routines to log and control the output. The idea is that decisions about where to log should ...
integer function, public cp_logger_get_default_io_unit(logger)
returns the unit nr for the ionode (-1 on all other processors) skips as well checks if the procs cal...
type(cp_logger_type) function, pointer, public cp_get_default_logger()
returns the default logger
routines to handle the output, The idea is to remove the decision of wheter to output and what to out...
integer function, public cp_print_key_unit_nr(logger, basis_section, print_key_path, extension, middle_name, local, log_filename, ignore_should_output, file_form, file_position, file_action, file_status, do_backup, on_file, is_new_file, mpi_io, fout)
...
subroutine, public cp_print_key_finished_output(unit_nr, logger, basis_section, print_key_path, local, ignore_should_output, on_file, mpi_io)
should be called after you finish working with a unit obtained with cp_print_key_unit_nr,...
integer, parameter, public cp_p_file
integer function, public cp_print_key_should_output(iteration_info, basis_section, print_key_path, used_print_key, first_time)
returns what should be done with the given property if btest(res,cp_p_store) then the property should...
collects all constants needed in input so that they can be used without circular dependencies
integer, parameter, public do_qmmm_pcharge
integer, parameter, public do_qmmm_coulomb
integer, parameter, public do_qmmm_swave
integer, parameter, public do_qmmm_gauss
objects that represent the structure of input sections and the data contained in an input section
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
integer, parameter, public default_path_length
Definition: kinds.F:58
Definition of mathematical constants and functions.
Definition: mathconstants.F:16
real(kind=dp), parameter, public rootpi
Utility routines for the memory handling.
subroutine, public qmmm_potential_init(qmmm_coupl_type, mm_el_pot_radius, potentials, pgfs, mm_cell, compatibility, print_section)
Initialize the QMMM potential stored on vector, according the qmmm_coupl_type.
Definition: qmmm_elpot.F:63
Sets the typo for the gaussian treatment of the qm/mm interaction.