(git:ccc2433)
pw_grid_info.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 !> \brief This module returns additional info on PW grids
10 !> \par History
11 !> JGH (09-06-2007) : Created from pw_grids
12 !> \author JGH
13 ! **************************************************************************************************
15 
16  USE fft_tools, ONLY: fft_radix_next,&
19  USE kinds, ONLY: dp
20  USE mathconstants, ONLY: twopi
21  USE pw_grid_types, ONLY: pw_grid_type
22 #include "../base/base_uses.f90"
23 
24  IMPLICIT NONE
25 
26  PRIVATE
28 
29  CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'pw_grid_info'
30 
31 CONTAINS
32 
33 ! **************************************************************************************************
34 !> \brief ...
35 !> \param hmat ...
36 !> \param cutoff ...
37 !> \param spherical ...
38 !> \param odd ...
39 !> \param fft_usage ...
40 !> \param ncommensurate ...
41 !> \param icommensurate ...
42 !> \param ref_grid ...
43 !> \param n_orig ...
44 !> \return ...
45 ! **************************************************************************************************
46  FUNCTION pw_grid_init_setup(hmat, cutoff, spherical, odd, fft_usage, ncommensurate, &
47  icommensurate, ref_grid, n_orig) RESULT(n)
48 
49  REAL(kind=dp), DIMENSION(3, 3), INTENT(IN) :: hmat
50  REAL(kind=dp), INTENT(IN) :: cutoff
51  LOGICAL, INTENT(IN) :: spherical, odd, fft_usage
52  INTEGER, INTENT(IN) :: ncommensurate, icommensurate
53  TYPE(pw_grid_type), INTENT(IN), OPTIONAL :: ref_grid
54  INTEGER, INTENT(IN), OPTIONAL :: n_orig(3)
55  INTEGER, DIMENSION(3) :: n
56 
57  INTEGER :: my_icommensurate
58 
59  IF (ncommensurate > 0) THEN
60  my_icommensurate = icommensurate
61  cpassert(icommensurate > 0)
62  cpassert(icommensurate <= ncommensurate)
63  ELSE
64  my_icommensurate = 0
65  END IF
66 
67  IF (my_icommensurate > 1) THEN
68  cpassert(PRESENT(ref_grid))
69  n = ref_grid%npts/2**(my_icommensurate - 1)
70  cpassert(all(ref_grid%npts == n*2**(my_icommensurate - 1)))
71  cpassert(all(pw_grid_n_for_fft(n) == n))
72  ELSE
73  n = pw_grid_find_n(hmat, cutoff=cutoff, fft_usage=fft_usage, ncommensurate=ncommensurate, &
74  spherical=spherical, odd=odd, n_orig=n_orig)
75  END IF
76 
77  END FUNCTION pw_grid_init_setup
78 
79 ! **************************************************************************************************
80 !> \brief returns the n needed for the grid with all the given constraints
81 !> \param hmat ...
82 !> \param cutoff ...
83 !> \param fft_usage ...
84 !> \param spherical ...
85 !> \param odd ...
86 !> \param ncommensurate ...
87 !> \param n_orig ...
88 !> \return ...
89 !> \author fawzi
90 ! **************************************************************************************************
91  FUNCTION pw_grid_find_n(hmat, cutoff, fft_usage, spherical, odd, ncommensurate, &
92  n_orig) RESULT(n)
93 
94  REAL(kind=dp), DIMENSION(3, 3), INTENT(IN) :: hmat
95  REAL(kind=dp), INTENT(IN) :: cutoff
96  LOGICAL, INTENT(IN) :: fft_usage, spherical, odd
97  INTEGER, INTENT(IN) :: ncommensurate
98  INTEGER, INTENT(IN), OPTIONAL :: n_orig(3)
99  INTEGER, DIMENSION(3) :: n
100 
101  INTEGER :: idir, my_icommensurate, &
102  my_ncommensurate, nsubgrid, &
103  nsubgrid_new, ntest(3), t_icommensurate
104  LOGICAL :: ftest, subgrid_is_ok
105 
106 ! ncommensurate is the number of commensurate grids
107 ! in order to have non-commensurate grids ncommensurate must be 0
108 ! icommensurte is the level number of communensurate grids
109 ! this implies that the number of grid points in each direction
110 ! is k*2**(ncommensurate-icommensurate)
111 
112  my_ncommensurate = ncommensurate
113  IF (my_ncommensurate > 0) THEN
114  my_icommensurate = 1
115  ELSE
116  my_icommensurate = 0
117  END IF
118  cpassert(my_icommensurate <= my_ncommensurate)
119  cpassert(my_icommensurate > 0 .OR. my_ncommensurate <= 0)
120  cpassert(my_ncommensurate >= 0)
121 
122  IF (PRESENT(n_orig)) THEN
123  n = n_orig
124  ELSE
125  cpassert(cutoff > 0.0_dp)
126  n = pw_grid_n_from_cutoff(hmat, cutoff)
127  END IF
128 
129  IF (fft_usage) THEN
130  n = pw_grid_n_for_fft(n, odd=odd)
131 
132  IF (.NOT. spherical) THEN
133  ntest = n
134 
135  IF (my_ncommensurate > 0) THEN
136  DO idir = 1, 3
137  DO
138  ! find valid radix >= ntest
139  CALL fft_radix_operations(ntest(idir), n(idir), fft_radix_next)
140  ! check every subgrid of n
141  subgrid_is_ok = .true.
142  DO t_icommensurate = 1, my_ncommensurate - 1
143  nsubgrid = n(idir)/2**(my_ncommensurate - t_icommensurate)
144  CALL fft_radix_operations(nsubgrid, nsubgrid_new, fft_radix_next)
145  subgrid_is_ok = (nsubgrid == nsubgrid_new) .AND. &
146  (modulo(n(idir), 2**(my_ncommensurate - t_icommensurate)) == 0)
147  IF (.NOT. subgrid_is_ok) EXIT
148  END DO
149  IF (subgrid_is_ok) THEN
150  EXIT
151  ELSE
152  ! subgrid wasn't OK, increment ntest and try again
153  ntest(idir) = n(idir) + 1
154  END IF
155  END DO
156  END DO
157  END IF
158  END IF
159  ELSE
160  ! without a cutoff and HALFSPACE we have to be sure that there is
161  ! a negative counterpart to every g vector (-> odd number of grid points)
162  IF (odd) n = n + mod(n + 1, 2)
163 
164  END IF
165 
166  ! final check if all went fine ...
167  IF (my_ncommensurate > 0) THEN
168  DO my_icommensurate = 1, my_ncommensurate
169  ftest = any(modulo(n, 2**(my_ncommensurate - my_icommensurate)) .NE. 0)
170  cpassert(.NOT. ftest)
171  END DO
172  END IF
173 
174  END FUNCTION pw_grid_find_n
175 
176 ! **************************************************************************************************
177 !> \brief returns the closest number of points >= n, on which you can perform
178 !> ffts
179 !> \param n the minimum number of points you want
180 !> \param odd if the number has to be odd
181 !> \return ...
182 !> \author fawzi
183 !> \note
184 !> result<=n
185 ! **************************************************************************************************
186  FUNCTION pw_grid_n_for_fft(n, odd) RESULT(nout)
187  INTEGER, DIMENSION(3), INTENT(in) :: n
188  LOGICAL, INTENT(in), OPTIONAL :: odd
189  INTEGER, DIMENSION(3) :: nout
190 
191  LOGICAL :: my_odd
192 
193  my_odd = .false.
194  IF (PRESENT(odd)) my_odd = odd
195  cpassert(all(n >= 0))
196  IF (my_odd) THEN
197  CALL fft_radix_operations(n(1), nout(1), fft_radix_next_odd)
198  CALL fft_radix_operations(n(2), nout(2), fft_radix_next_odd)
199  CALL fft_radix_operations(n(3), nout(3), fft_radix_next_odd)
200  ELSE
201  CALL fft_radix_operations(n(1), nout(1), fft_radix_next)
202  CALL fft_radix_operations(n(2), nout(2), fft_radix_next)
203  CALL fft_radix_operations(n(3), nout(3), fft_radix_next)
204  END IF
205 
206  END FUNCTION pw_grid_n_for_fft
207 
208 ! **************************************************************************************************
209 !> \brief Find the number of points that give at least the requested cutoff
210 !> \param hmat ...
211 !> \param cutoff ...
212 !> \return ...
213 !> \par History
214 !> JGH (21-12-2000) : Simplify parameter list, bounds will be global
215 !> JGH ( 8-01-2001) : Add check to FFT allowd grids (this now depends
216 !> on the FFT library.
217 !> Should the pw_grid_type have a reference to the FFT
218 !> library ?
219 !> JGH (28-02-2001) : Only do conditional check for FFT
220 !> JGH (21-05-2002) : Optimise code, remove orthorhombic special case
221 !> \author apsi
222 !> Christopher Mundy
223 ! **************************************************************************************************
224  FUNCTION pw_grid_n_from_cutoff(hmat, cutoff) RESULT(n)
225 
226  REAL(kind=dp), DIMENSION(3, 3), INTENT(IN) :: hmat
227  REAL(kind=dp), INTENT(IN) :: cutoff
228  INTEGER, DIMENSION(3) :: n
229 
230  INTEGER :: i
231  REAL(kind=dp) :: alat(3)
232 
233  DO i = 1, 3
234  alat(i) = sum(hmat(:, i)**2)
235  END DO
236  cpassert(all(alat /= 0._dp))
237  n = 2*floor(sqrt(2.0_dp*cutoff*alat)/twopi) + 1
238 
239  END FUNCTION pw_grid_n_from_cutoff
240 
241 ! **************************************************************************************************
242 !> \brief returns the bounds that distribute n points evenly around 0
243 !> \param npts the number of points in each direction
244 !> \return ...
245 !> \author fawzi
246 ! **************************************************************************************************
247  FUNCTION pw_grid_bounds_from_n(npts) RESULT(bounds)
248  INTEGER, DIMENSION(3), INTENT(in) :: npts
249  INTEGER, DIMENSION(2, 3) :: bounds
250 
251  bounds(1, :) = -npts/2
252  bounds(2, :) = bounds(1, :) + npts - 1
253 
254  END FUNCTION pw_grid_bounds_from_n
255 
256 ! **************************************************************************************************
257 !> \brief Given a grid and a box, calculate the corresponding cutoff
258 !> *** This routine calculates the cutoff in MOMENTUM UNITS! ***
259 !> \param npts ...
260 !> \param h_inv ...
261 !> \return ...
262 !> \par History
263 !> JGH (20-12-2000) : Deleted some strange comments
264 !> \author apsi
265 !> Christopher Mundy
266 !> \note
267 !> This routine is local. It works independent from the distribution
268 !> of PW on processors.
269 !> npts is the grid size for the full box.
270 ! **************************************************************************************************
271  FUNCTION pw_find_cutoff(npts, h_inv) RESULT(cutoff)
272 
273  INTEGER, DIMENSION(:), INTENT(IN) :: npts
274  REAL(kind=dp), DIMENSION(3, 3), INTENT(IN) :: h_inv
275  REAL(kind=dp) :: cutoff
276 
277  REAL(kind=dp) :: gcut, gdum(3), length
278 
279 ! compute 2*pi*h_inv^t*g where g = (nmax[1],0,0)
280 
281  gdum(:) = twopi*h_inv(1, :)*real((npts(1) - 1)/2, kind=dp)
282  length = sqrt(gdum(1)**2 + gdum(2)**2 + gdum(3)**2)
283  gcut = length
284 
285  ! compute 2*pi*h_inv^t*g where g = (0,nmax[2],0)
286  gdum(:) = twopi*h_inv(2, :)*real((npts(2) - 1)/2, kind=dp)
287  length = sqrt(gdum(1)**2 + gdum(2)**2 + gdum(3)**2)
288  gcut = min(gcut, length)
289 
290  ! compute 2*pi*h_inv^t*g where g = (0,0,nmax[3])
291  gdum(:) = twopi*h_inv(3, :)*real((npts(3) - 1)/2, kind=dp)
292  length = sqrt(gdum(1)**2 + gdum(2)**2 + gdum(3)**2)
293  gcut = min(gcut, length)
294 
295  cutoff = gcut - 1.e-8_dp
296 
297  END FUNCTION pw_find_cutoff
298 
299 END MODULE pw_grid_info
300 
static GRID_HOST_DEVICE int modulo(int a, int m)
Equivalent of Fortran's MODULO, which always return a positive number. https://gcc....
Definition: grid_common.h:117
subroutine, public fft_radix_operations(radix_in, radix_out, operation)
Determine the allowed lengths of FFT's '''.
Definition: fft_tools.F:239
integer, parameter, public fft_radix_next_odd
Definition: fft_tools.F:148
integer, parameter, public fft_radix_next
Definition: fft_tools.F:146
Defines the basic variable types.
Definition: kinds.F:23
integer, parameter, public dp
Definition: kinds.F:34
Definition of mathematical constants and functions.
Definition: mathconstants.F:16
real(kind=dp), parameter, public twopi
This module returns additional info on PW grids.
Definition: pw_grid_info.F:14
real(kind=dp) function, public pw_find_cutoff(npts, h_inv)
Given a grid and a box, calculate the corresponding cutoff *** This routine calculates the cutoff in ...
Definition: pw_grid_info.F:272
integer function, dimension(2, 3), public pw_grid_bounds_from_n(npts)
returns the bounds that distribute n points evenly around 0
Definition: pw_grid_info.F:248
integer function, dimension(3), public pw_grid_init_setup(hmat, cutoff, spherical, odd, fft_usage, ncommensurate, icommensurate, ref_grid, n_orig)
...
Definition: pw_grid_info.F:48
integer function, dimension(3), public pw_grid_n_for_fft(n, odd)
returns the closest number of points >= n, on which you can perform ffts
Definition: pw_grid_info.F:187