47 use,
intrinsic :: iso_fortran_env
71 logical :: enabled = .false.
73 integer :: divisor = 0
75 integer :: interp_min = 0
76 integer :: interp_max = 0
81 real(real64),
allocatable :: co(:, :)
88 type(double_grid_t),
intent(out) :: this
89 type(namespace_t),
intent(in) :: namespace
90 integer,
intent(in) :: dim
93 real(real64),
allocatable :: points(:)
111 call parse_variable(namespace,
'DoubleGrid', .false., this%enabled)
113 this%enabled = .false.
116 if (.not. this%enabled)
then
133 if (mod(this%order, 2) == 0 .or. this%order < 3)
then
146 if (mod(this%divisor, 2) == 0 .or. this%divisor < 3)
then
150 this%nn = (this%divisor - 1)/2
151 this%interp_min = -this%order/2
152 this%interp_max = this%order/2 + 1
158 safe_allocate(this%co(this%interp_min:this%interp_max, 1:this%nn))
159 safe_allocate(points(1:this%order + 1))
161 do ll = this%interp_min, this%interp_max
162 points(ll - this%interp_min + 1) = real(this%divisor*ll - aa, real64)
166 safe_deallocate_a(points)
177 safe_deallocate_a(this%co)
178 this%enabled = .false.
190 class(
mesh_t),
intent(in) :: mesh
192 integer :: i1, i2, i3
195 if (.not. this%enabled)
return
200 margin = max(margin, norm2(mesh%coord_system%to_cartesian(mesh%spacing(1:3)*[i1, i2, i3])))
204 margin = this%interp_max*margin
220 type(submesh_t),
intent(in) :: sm
221 integer,
intent(in) :: nf
222 type(spline_t),
intent(in) :: spl(:)
223 integer,
intent(in) :: ll(:)
224 integer,
intent(in) :: mm(:)
225 real(real64),
intent(in) :: rcut(:)
226 real(real64),
intent(out) :: feff(:, :)
227 integer,
optional,
intent(in) :: cart_dir(:)
231 real(real64),
allocatable :: rcut_eff(:)
232 integer,
allocatable :: cdir(:)
242 assert(
size(feff, 1) >= sm%np)
243 assert(
size(spl) >= nf .and.
size(ll) >= nf .and.
size(mm) >= nf .and.
size(rcut) >= nf)
246 safe_allocate(rcut_eff(1:nf))
248 rcut_eff(jf) = min(rcut(jf), spline_range_max(spl(jf)))
251 safe_allocate(cdir(1:nf))
253 if (
present(cart_dir)) cdir(1:nf) = cart_dir(1:nf)
255 if (.not. this%enabled)
then
259 if (sm%r(ip) <= rcut_eff(jf))
then
260 feff(ip, jf) = spline_eval(spl(jf), sm%r(ip))
261 if (ll(jf) >= 0)
then
262 call ylmr_real(sm%rel_x(1:3, ip), ll(jf), mm(jf), ylm)
263 feff(ip, jf) = feff(ip, jf)*ylm
265 if (cdir(jf) > 0) feff(ip, jf) = feff(ip, jf)*sm%rel_x(cdir(jf), ip)
267 feff(ip, jf) = m_zero
278 safe_deallocate_a(rcut_eff)
279 safe_deallocate_a(cdir)
298 type(submesh_t),
intent(in) :: sm
299 integer,
intent(in) :: nf
300 type(spline_t),
intent(in) :: spl(:)
301 integer,
intent(in) :: ll(:)
302 integer,
intent(in) :: mm(:)
303 real(real64),
intent(in) :: rcut(:)
304 integer,
intent(in) :: cdir(:)
305 real(real64),
intent(out) :: feff(:, :)
307 integer :: ip, jf, idir, io, io1, io2, io3, il1
308 integer :: ia1, ia2, ia3, noff, ngrp, igrp, nthr, ithr
309 integer :: kmin(1:3), kmax(1:3), key(1:3)
310 integer,
allocatable :: isub(:, :, :), offs(:, :), gfirst(:)
311 real(real64) :: hh(1:3), chi(1:3), rmax, anchor_reach, rel_ref(1:3)
312 real(real64),
allocatable :: xstep(:, :), xoff(:, :), wgt(:, :), fbuf(:, :, :)
313 integer,
allocatable :: tgt(:, :), ntgt(:)
315 type(c_ptr),
allocatable :: acc(:)
317 call profiling_in(
"DOUBLE_GRID")
320 assert(.not. sm%mesh%use_curvilinear)
321 assert(sm%mesh%box%dim == 3)
323 hh(1:3) = sm%mesh%spacing(1:3)
324 rel_ref(1:3) = sm%rel_x(1:3, 1)
325 rmax = maxval(rcut(1:nf))
334 chi = sm%mesh%coord_system%from_cartesian(sm%rel_x(1:3, ip) - rel_ref(1:3))
336 assert(all(abs(chi/hh - key) < 1e-6_real64))
337 kmin = min(kmin, key)
338 kmax = max(kmax, key)
341 safe_allocate(isub(kmin(1):kmax(1), kmin(2):kmax(2), kmin(3):kmax(3)))
344 chi = sm%mesh%coord_system%from_cartesian(sm%rel_x(1:3, ip) - rel_ref(1:3))
346 assert(isub(key(1), key(2), key(3)) == 0)
347 isub(key(1), key(2), key(3)) = ip
351 safe_allocate(xstep(1:3, 1:3))
355 xstep(1:3, idir) = sm%mesh%coord_system%to_cartesian(chi)
358 noff = this%divisor**3
359 safe_allocate(offs(1:3, 1:noff))
360 safe_allocate(xoff(1:3, 1:noff))
362 do io3 = -this%nn, this%nn
363 do io2 = -this%nn, this%nn
364 do io1 = -this%nn, this%nn
366 offs(1:3, io) = [io1, io2, io3]
367 xoff(1:3, io) = (xstep(1:3, 1)*io1 + xstep(1:3, 2)*io2 + xstep(1:3, 3)*io3)/this%divisor
374 anchor_reach = rmax + 1e-12_real64
376 anchor_reach = max(anchor_reach, rmax + norm2(xoff(1:3, io)) + 1e-12_real64)
382 safe_allocate(tgt(1:this%order + 1, -this%nn:this%nn))
383 safe_allocate(wgt(1:this%order + 1, -this%nn:this%nn))
384 safe_allocate(ntgt(-this%nn:this%nn))
385 do io1 = -this%nn, this%nn
391 ntgt(io1) = this%order + 1
392 do il1 = this%interp_min, this%interp_max
393 tgt(il1 - this%interp_min + 1, io1) = il1*sign(1, io1)
394 wgt(il1 - this%interp_min + 1, io1) = this%co(il1, abs(io1))
401 safe_allocate(gfirst(1:nf + 1))
405 if (spline_same(spl(jf), spl(jf - 1)) .and. abs(rcut(jf) - rcut(jf - 1)) < m_epsilon) cycle
409 gfirst(ngrp + 1) = nf + 1
416 if (ngrp >= nthr)
then
418 feff(1:sm%np, 1:nf) = m_zero
421 call spline_accel_init(acc1)
422 do ia3 = kmin(3) - this%interp_max, kmax(3) + this%interp_max
423 do ia2 = kmin(2) - this%interp_max, kmax(2) + this%interp_max
424 do ia1 = kmin(1) - this%interp_max, kmax(1) + this%interp_max
429 call spline_accel_end(acc1)
435 safe_allocate(fbuf(1:sm%np, 1:nf, 0:nthr - 1))
439 fbuf(1:sm%np, 1:nf, ithr) = m_zero
440 safe_allocate(acc(1:ngrp))
442 call spline_accel_init(acc(igrp))
445 do ia3 = kmin(3) - this%interp_max, kmax(3) + this%interp_max
446 do ia2 = kmin(2) - this%interp_max, kmax(2) + this%interp_max
447 do ia1 = kmin(1) - this%interp_max, kmax(1) + this%interp_max
448 call scatter_anchor(ia1, ia2, ia3, 1, ngrp, acc, fbuf(:, :, ithr))
454 call spline_accel_end(acc(igrp))
456 safe_deallocate_a(acc)
459 feff(1:sm%np, 1:nf) = fbuf(1:sm%np, 1:nf, 0)
460 do ithr = 1, nthr - 1
461 feff(1:sm%np, 1:nf) = feff(1:sm%np, 1:nf) + fbuf(1:sm%np, 1:nf, ithr)
463 safe_deallocate_a(fbuf)
467 feff(1:sm%np, 1:nf) = feff(1:sm%np, 1:nf)/real(noff, real64)
469 safe_deallocate_a(isub)
470 safe_deallocate_a(offs)
471 safe_deallocate_a(xoff)
472 safe_deallocate_a(xstep)
473 safe_deallocate_a(tgt)
474 safe_deallocate_a(wgt)
475 safe_deallocate_a(ntgt)
476 safe_deallocate_a(gfirst)
479 call profiling_out(
"DOUBLE_GRID")
486 integer,
intent(in) :: ia1, ia2, ia3, ig1, ig2
487 type(c_ptr),
intent(in) :: accg(:)
488 real(real64),
intent(inout) :: fout(:, :)
490 integer :: io, ig, jf, il1, il2, il3, it1, it2, it3
491 real(real64) :: xanchor(1:3), xfine(1:3), rr, rad, ylm, val, ww3, ww23
493 xanchor(1:3) = rel_ref(1:3) + xstep(1:3, 1)*ia1 + xstep(1:3, 2)*ia2 + xstep(1:3, 3)*ia3
494 if (norm2(xanchor) > anchor_reach)
return
497 xfine(1:3) = xanchor(1:3) + xoff(1:3, io)
502 if (rr > rcut(gfirst(ig))) cycle
503 rad = spline_eval_accel(spl(gfirst(ig)), rr, accg(ig - ig1 + 1))
505 do jf = gfirst(ig), gfirst(ig + 1) - 1
507 if (ll(jf) >= 0)
then
508 call ylmr_real(xfine, ll(jf), mm(jf), ylm)
511 if (cdir(jf) > 0) val = val*xfine(cdir(jf))
512 if (abs(val) <= m_epsilon) cycle
515 do il3 = 1, ntgt(offs(3, io))
516 it3 = ia3 + tgt(il3, offs(3, io))
517 if (it3 < kmin(3) .or. it3 > kmax(3)) cycle
518 ww3 = wgt(il3, offs(3, io))*val
519 do il2 = 1, ntgt(offs(2, io))
520 it2 = ia2 + tgt(il2, offs(2, io))
521 if (it2 < kmin(2) .or. it2 > kmax(2)) cycle
522 ww23 = wgt(il2, offs(2, io))*ww3
523 do il1 = 1, ntgt(offs(1, io))
524 it1 = ia1 + tgt(il1, offs(1, io))
525 if (it1 < kmin(1) .or. it1 > kmax(1)) cycle
526 if (isub(it1, it2, it3) > 0)
then
527 fout(isub(it1, it2, it3), jf) = fout(isub(it1, it2, it3), jf) &
528 + wgt(il1, offs(1, io))*ww23
subroutine scatter_anchor(ia1, ia2, ia3, ig1, ig2, accg, fout)
Scatter the fine points around the anchor site (ia1, ia2, ia3) of the function groups ig1:ig2 (accele...
The Ono-Hirose double-grid technique [T. Ono and K. Hirose, Phys. Rev. Lett. 82, 5016 (1999); Phys....
subroutine, public double_grid_transform(this, sm, nf, spl, ll, mm, rcut, feff, cart_dir)
Evaluate a batch of localized functions f_jf(x) = spl_jf(r) * Y_{ll,mm}(x) (or a purely radial spl_jf...
real(real64) function, public double_grid_margin(this, mesh)
Submesh radius enlargement needed to contain the effective support of a transformed function: the ten...
subroutine, public double_grid_end(this)
subroutine, public double_grid_init(this, namespace, dim)
subroutine double_grid_transform_kernel(this, sm, nf, spl, ll, mm, rcut, cdir, feff)
The transpose-interpolation scatter. All arithmetic is done with integer grid keys relative to the fi...
real(real64), parameter, public m_zero
This module is intended to contain "only mathematical" functions and procedures.
subroutine, public interpolation_coefficients(nn, xa, xx, cc)
This module defines the meshes, which are used in Octopus.
subroutine, public messages_input_error(namespace, var, details, row, column)
subroutine, public messages_experimental(name, namespace)
/* To use the profiling module, call profiling_in and profiling_out with the label of the region as a...
Describes mesh distribution to nodes.