51 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: xkp
52 INTEGER,
DIMENSION(3),
INTENT(IN) :: nkp_grid
53 INTEGER,
DIMENSION(:, :),
INTENT(OUT),
OPTIONAL :: grid_index
54 REAL(kind=
dp),
DIMENSION(3),
INTENT(OUT),
OPTIONAL :: k_offset
56 REAL(kind=
dp),
PARAMETER :: map_tolerance = 2.0e-10_dp
58 INTEGER :: d, ik, m, nkp
59 INTEGER,
DIMENSION(3) :: index
60 LOGICAL,
ALLOCATABLE,
DIMENSION(:, :, :) :: occupied
61 REAL(kind=
dp) :: offset(3), scaled
64 IF (
SIZE(xkp, 1) < 3 .OR. any(nkp_grid <= 0))
RETURN
66 IF (product(nkp_grid) /= nkp)
RETURN
67 IF (
PRESENT(grid_index))
THEN
68 IF (
SIZE(grid_index, 1) < 3 .OR.
SIZE(grid_index, 2) < nkp)
RETURN
72 scaled =
modulo(real(nkp_grid(d), kind=
dp)*xkp(d, 1), 1.0_dp)
73 IF (abs(scaled) < map_tolerance .OR. abs(scaled - 1.0_dp) < map_tolerance) scaled = 0.0_dp
74 offset(d) = scaled/real(nkp_grid(d), kind=
dp)
77 ALLOCATE (occupied(nkp_grid(1), nkp_grid(2), nkp_grid(3)), source=.false.)
80 scaled = real(nkp_grid(d), kind=
dp)*(xkp(d, ik) - offset(d))
82 IF (abs(scaled - real(m, kind=
dp)) > map_tolerance)
THEN
86 index(d) =
modulo(m, nkp_grid(d)) + 1
88 IF (occupied(index(1), index(2), index(3)))
THEN
92 occupied(index(1), index(2), index(3)) = .true.
93 IF (
PRESENT(grid_index)) grid_index(1:3, ik) = index
95 regular = all(occupied)
98 IF (regular .AND.
PRESENT(k_offset)) k_offset = offset
115 used_fft, deriv_direction, hmat, selected_kpoints)
117 REAL(kind=
dp),
DIMENSION(:, :, :),
INTENT(IN) :: values_rs
118 INTEGER,
DIMENSION(:, :),
INTENT(IN) :: index_to_cell
119 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: xkp
120 INTEGER,
DIMENSION(3),
INTENT(IN) :: nkp_grid
121 COMPLEX(KIND=dp),
DIMENSION(:, :, :),
INTENT(OUT) :: values_k
122 LOGICAL,
INTENT(OUT),
OPTIONAL :: used_fft
123 INTEGER,
INTENT(IN),
OPTIONAL :: deriv_direction
124 REAL(kind=
dp),
DIMENSION(3, 3),
INTENT(IN), &
126 INTEGER,
DIMENSION(:),
INTENT(IN),
OPTIONAL :: selected_kpoints
128 COMPLEX(KIND=dp),
ALLOCATABLE,
DIMENSION(:) :: cell_factor
129 COMPLEX(KIND=dp),
CONTIGUOUS,
DIMENSION(:, :, :), &
130 POINTER :: fft_in, fft_out
131 INTEGER :: attempt, d, handle, i, icell, ik, &
132 ik_out, j, nout, radix_length, stat
133 INTEGER,
ALLOCATABLE,
DIMENSION(:, :) :: cell_index, grid_index
134 INTEGER,
DIMENSION(3) :: n, nfft
135 LOGICAL :: compatible, regular
137 REAL(kind=
dp),
DIMENSION(3) :: cell_vector, k_offset
139 CALL timeset(
"cell_to_k_grid_fft", handle)
141 IF (
SIZE(index_to_cell, 1) < 3 .OR. &
142 SIZE(index_to_cell, 2) /=
SIZE(values_rs, 3))
THEN
143 cpabort(
"Inconsistent real-space image-cell mapping in lattice FFT")
146 IF (
PRESENT(selected_kpoints))
THEN
147 nout =
SIZE(selected_kpoints)
148 IF (any(selected_kpoints < 1) .OR. any(selected_kpoints >
SIZE(xkp, 2)))
THEN
149 cpabort(
"Selected lattice-FFT k-point index is out of range")
152 IF (
SIZE(values_k, 1) /=
SIZE(values_rs, 1) .OR. &
153 SIZE(values_k, 2) /=
SIZE(values_rs, 2) .OR. &
154 SIZE(values_k, 3) /= nout)
THEN
155 cpabort(
"Inconsistent input and output matrix batches in lattice FFT")
157 IF (
PRESENT(deriv_direction))
THEN
158 IF (.NOT.
PRESENT(hmat)) cpabort(
"Lattice-FFT derivative requested without a cell matrix")
159 IF (deriv_direction < 1 .OR. deriv_direction > 3)
THEN
160 cpabort(
"Lattice-FFT derivative direction must be 1, 2, or 3")
164 ALLOCATE (grid_index(3,
SIZE(xkp, 2)))
177 IF (nfft(d) >= 3)
THEN
179 IF (radix_length == nfft(d))
THEN
184 nfft(d) = nfft(d) + n(d)
186 IF (.NOT. compatible) regular = .false.
189 IF (.NOT. regular)
THEN
190 CALL direct_cell_to_k(values_rs, index_to_cell, xkp, values_k, deriv_direction, hmat, &
192 IF (
PRESENT(used_fft)) used_fft = .false.
193 DEALLOCATE (grid_index)
194 CALL timestop(handle)
198 NULLIFY (fft_in, fft_out)
199 CALL fft_alloc(fft_in, nfft)
200 CALL fft_alloc(fft_out, nfft)
201 ALLOCATE (cell_index(3,
SIZE(values_rs, 3)), cell_factor(
SIZE(values_rs, 3)))
202 DO icell = 1,
SIZE(values_rs, 3)
204 cell_index(d, icell) =
modulo(index_to_cell(d, icell), n(d))*(nfft(d)/n(d)) + 1
206 arg = sum(k_offset*real(index_to_cell(1:3, icell), kind=
dp))
208 IF (
PRESENT(deriv_direction))
THEN
209 cell_vector = matmul(hmat, real(index_to_cell(1:3, icell), kind=
dp))
210 cell_factor(icell) = cell_factor(icell)*
gaussi*cell_vector(deriv_direction)
215 DO j = 1,
SIZE(values_rs, 2)
216 DO i = 1,
SIZE(values_rs, 1)
218 DO icell = 1,
SIZE(values_rs, 3)
219 fft_in(cell_index(1, icell), cell_index(2, icell), cell_index(3, icell)) = &
220 fft_in(cell_index(1, icell), cell_index(2, icell), cell_index(3, icell)) + &
221 cell_factor(icell)*values_rs(i, j, icell)
223 CALL fft3d(
bwfft, nfft, fft_in, fft_out, status=stat)
227 IF (
PRESENT(selected_kpoints)) ik = selected_kpoints(ik_out)
228 values_k(i, j, ik_out) = &
229 fft_out(grid_index(1, ik), grid_index(2, ik), grid_index(3, ik))
236 CALL direct_cell_to_k(values_rs, index_to_cell, xkp, values_k, deriv_direction, hmat, &
240 IF (
PRESENT(used_fft)) used_fft = regular
242 CALL fft_dealloc(fft_in)
243 CALL fft_dealloc(fft_out)
244 DEALLOCATE (cell_factor, cell_index, grid_index)
245 CALL timestop(handle)
260 COMPLEX(KIND=dp),
DIMENSION(:, :, :),
INTENT(IN) :: values_k
261 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: xkp
262 INTEGER,
DIMENSION(3),
INTENT(IN) :: nkp_grid
263 INTEGER,
DIMENSION(:, :),
INTENT(IN) :: index_to_cell
264 COMPLEX(KIND=dp),
DIMENSION(:, :, :),
INTENT(OUT) :: values_rs
265 LOGICAL,
INTENT(OUT),
OPTIONAL :: used_fft
267 COMPLEX(KIND=dp) :: phase
268 COMPLEX(KIND=dp),
CONTIGUOUS,
DIMENSION(:, :, :), &
269 POINTER :: fft_in, fft_out
270 INTEGER :: attempt, d, handle, i, icell, ik, j, &
272 INTEGER,
ALLOCATABLE,
DIMENSION(:, :) :: cell_index, grid_index
273 INTEGER,
DIMENSION(3) :: n, nfft
274 LOGICAL :: compatible, regular
275 REAL(kind=
dp) :: arg, normalization
276 REAL(kind=
dp),
DIMENSION(3) :: k_offset
278 CALL timeset(
"k_grid_to_cell_fft", handle)
280 IF (
SIZE(xkp, 1) < 3 .OR.
SIZE(index_to_cell, 1) < 3 .OR. &
281 SIZE(values_k, 3) /=
SIZE(xkp, 2))
THEN
282 cpabort(
"Inconsistent reciprocal-grid mapping in inverse lattice FFT")
284 IF (
SIZE(values_rs, 1) /=
SIZE(values_k, 1) .OR. &
285 SIZE(values_rs, 2) /=
SIZE(values_k, 2) .OR. &
286 SIZE(values_rs, 3) /=
SIZE(index_to_cell, 2))
THEN
287 cpabort(
"Inconsistent input and output matrix batches in inverse lattice FFT")
290 ALLOCATE (grid_index(3,
SIZE(xkp, 2)))
298 IF (nfft(d) >= 3)
THEN
300 IF (radix_length == nfft(d))
THEN
305 nfft(d) = nfft(d) + n(d)
307 IF (.NOT. compatible) regular = .false.
310 IF (.NOT. regular)
THEN
311 CALL direct_k_to_cell(values_k, xkp, index_to_cell, values_rs)
312 IF (
PRESENT(used_fft)) used_fft = .false.
313 DEALLOCATE (grid_index)
314 CALL timestop(handle)
318 CALL fft_alloc(fft_in, nfft)
319 CALL fft_alloc(fft_out, nfft)
320 ALLOCATE (cell_index(3,
SIZE(index_to_cell, 2)))
321 DO icell = 1,
SIZE(index_to_cell, 2)
323 cell_index(d, icell) =
modulo(index_to_cell(d, icell), n(d))*(nfft(d)/n(d)) + 1
326 normalization = real(product(nfft), kind=
dp)/real(product(n), kind=
dp)
329 DO j = 1,
SIZE(values_k, 2)
330 DO i = 1,
SIZE(values_k, 1)
332 DO ik = 1,
SIZE(values_k, 3)
333 fft_in(grid_index(1, ik), grid_index(2, ik), grid_index(3, ik)) = values_k(i, j, ik)
335 CALL fft3d(
fwfft, nfft, fft_in, fft_out, status=stat)
337 DO icell = 1,
SIZE(index_to_cell, 2)
338 arg = sum(k_offset*real(index_to_cell(1:3, icell), kind=
dp))
340 values_rs(i, j, icell) = normalization*phase* &
341 fft_out(cell_index(1, icell), cell_index(2, icell), cell_index(3, icell))
348 CALL direct_k_to_cell(values_k, xkp, index_to_cell, values_rs)
351 IF (
PRESENT(used_fft)) used_fft = regular
353 CALL fft_dealloc(fft_in)
354 CALL fft_dealloc(fft_out)
355 DEALLOCATE (cell_index, grid_index)
356 CALL timestop(handle)
subroutine, public cell_to_k_grid_fft(values_rs, index_to_cell, xkp, nkp_grid, values_k, used_fft, deriv_direction, hmat, selected_kpoints)
Transform a batch of real matrices from image cells to every supplied k point.