29 & mmax, electrostatics, ddx_error)
31 type(ddx_params_type),
intent(in) :: params
32 type(ddx_constants_type),
intent(in) :: constants
33 type(ddx_workspace_type),
intent(inout) :: workspace
34 integer,
intent(in) :: mmax
35 real(dp),
intent(in) :: multipoles((mmax + 1)**2, params % nsph)
37 type(ddx_error_type),
intent(inout) :: ddx_error
40 if (ddx_error % flag .ne. 0)
then
41 call update_error(ddx_error, &
42 &
"allocate_electrostatics returned an error, exiting")
47 if (electrostatics % do_phi .and. electrostatics % do_e &
48 & .and. electrostatics % do_g)
then
49 call multipole_electrostatics_2(params, constants, workspace, &
50 & multipoles, 0, electrostatics % phi_cav, &
51 & electrostatics % e_cav, electrostatics % g_cav, ddx_error)
52 else if (electrostatics % do_phi .and. electrostatics % do_e)
then
53 call multipole_electrostatics_1(params, constants, workspace, &
54 & multipoles, 0, electrostatics % phi_cav, &
55 & electrostatics % e_cav, ddx_error)
57 call multipole_electrostatics_0(params, constants, workspace, &
58 & multipoles, 0, electrostatics % phi_cav, ddx_error)
80subroutine multipole_electrostatics_2(params, constants, workspace, multipoles, &
81 & mmax, phi_cav, e_cav, g_cav, ddx_error)
83 type(ddx_params_type),
intent(in) :: params
84 type(ddx_workspace_type),
intent(inout) :: workspace
85 type(ddx_constants_type),
intent(in) :: constants
86 type(ddx_error_type),
intent(inout) :: ddx_error
87 integer,
intent(in) :: mmax
88 real(dp),
intent(in) :: multipoles((mmax + 1)**2, params % nsph)
89 real(dp),
intent(out) :: phi_cav(constants % ncav)
90 real(dp),
intent(out) :: e_cav(3, constants % ncav)
91 real(dp),
intent(out) :: g_cav(3, 3, constants % ncav)
93 if (params % fmm .eq. 0)
then
94 call build_g_dense(multipoles, params % csph, mmax, params % nsph, &
95 & phi_cav, constants % ccav, constants % ncav, e_cav, g_cav, &
97 else if (params % fmm .eq. 1)
then
98 call build_g_fmm(params, constants, workspace, multipoles, &
99 & mmax, phi_cav, e_cav, g_cav, ddx_error)
101end subroutine multipole_electrostatics_2
121subroutine build_g_dense(multipoles, cm, mmax, nm, phi_cav, ccav, ncav, &
122 & e_cav, g_cav, ddx_error)
124 integer,
intent(in) :: mmax, nm, ncav
125 real(dp),
intent(in) :: multipoles((mmax + 1)**2, nm)
126 real(dp),
intent(in) :: cm(3, nm), ccav(3, ncav)
127 real(dp),
intent(out) :: phi_cav(ncav), e_cav(3, ncav), g_cav(3, 3, ncav)
128 type(ddx_error_type),
intent(inout) :: ddx_error
129 real(dp),
allocatable :: tmp_m_grad(:, :, :), vscales(:), &
130 & vscales_rel(:), v4pi2lp1(:), tmp_m_hess(:, :, :, :), tmp(:, :)
131 integer icav, im, info
132 real(dp) :: v, ex, ey, ez, c(3), gxx, gxy, gxz, gyy, gyz, gzz
136 allocate(tmp_m_grad((mmax + 2)**2, 3, nm), vscales((mmax + 3)**2), &
137 & vscales_rel((mmax + 3)**2), v4pi2lp1(mmax + 3), &
138 & tmp_m_hess((mmax + 3)**2, 3, nm, 3), tmp((mmax + 2)**2, 3), &
140 if (info .ne. 0)
then
141 call update_error(ddx_error,
"Allocation failed in build_g_dense!")
144 call ylmscale(mmax + 2, vscales, v4pi2lp1, vscales_rel)
147 call grad_m2m(multipoles, mmax, nm, tmp_m_grad, ddx_error)
148 tmp = tmp_m_grad(:, 1, :)
149 call grad_m2m(tmp, mmax + 1, nm, tmp_m_hess(:, :, :, 1), ddx_error)
150 tmp = tmp_m_grad(:, 2, :)
151 call grad_m2m(tmp, mmax + 1, nm, tmp_m_hess(:, :, :, 2), ddx_error)
152 tmp = tmp_m_grad(:, 3, :)
153 call grad_m2m(tmp, mmax + 1, nm, tmp_m_hess(:, :, :, 3), ddx_error)
154 if (ddx_error % flag .ne. 0)
then
155 call update_error(ddx_error,
"grad_m2m returned an error, exiting")
173 c(:) = ccav(:, icav) - cm(:, im)
174 call fmm_m2p(c, one, mmax, vscales_rel, one, multipoles(:, im), &
177 call fmm_m2p(c, one, mmax + 1, vscales_rel, one, &
178 & tmp_m_grad(:, 1, im), one, ex)
179 call fmm_m2p(c, one, mmax + 1, vscales_rel, one, &
180 & tmp_m_grad(:, 2, im), one, ey)
181 call fmm_m2p(c, one, mmax + 1, vscales_rel, one, &
182 & tmp_m_grad(:, 3, im), one, ez)
184 call fmm_m2p(c, one, mmax + 2, vscales_rel, one, &
185 & tmp_m_hess(:, 1, im, 1), one, gxx)
186 call fmm_m2p(c, one, mmax + 2, vscales_rel, one, &
187 & tmp_m_hess(:, 2, im, 1), one, gxy)
188 call fmm_m2p(c, one, mmax + 2, vscales_rel, one, &
189 & tmp_m_hess(:, 3, im, 1), one, gxz)
191 call fmm_m2p(c, one, mmax + 2, vscales_rel, one, &
192 & tmp_m_hess(:, 2, im, 2), one, gyy)
193 call fmm_m2p(c, one, mmax + 2, vscales_rel, one, &
194 & tmp_m_hess(:, 3, im, 2), one, gyz)
196 call fmm_m2p(c, one, mmax + 2, vscales_rel, one, &
197 & tmp_m_hess(:, 3, im, 3), one, gzz)
203 g_cav(1, 1, icav) = gxx
204 g_cav(1, 2, icav) = gxy
205 g_cav(1, 3, icav) = gxz
206 g_cav(2, 1, icav) = gxy
207 g_cav(2, 2, icav) = gyy
208 g_cav(2, 3, icav) = gyz
209 g_cav(3, 1, icav) = gxz
210 g_cav(3, 2, icav) = gyz
211 g_cav(3, 3, icav) = gzz
214 deallocate(tmp_m_grad, vscales, vscales_rel, v4pi2lp1, tmp_m_hess, &
216 if (info .ne. 0)
then
217 call update_error(ddx_error,
"Deallocation failed in build_e_dense!")
220end subroutine build_g_dense
237subroutine multipole_electrostatics_1(params, constants, workspace, multipoles, &
238 & mmax, phi_cav, e_cav, ddx_error)
240 type(ddx_params_type),
intent(in) :: params
241 type(ddx_workspace_type),
intent(inout) :: workspace
242 type(ddx_constants_type),
intent(in) :: constants
243 type(ddx_error_type),
intent(inout) :: ddx_error
244 integer,
intent(in) :: mmax
245 real(dp),
intent(in) :: multipoles((mmax + 1)**2, params % nsph)
246 real(dp),
intent(out) :: phi_cav(constants % ncav)
247 real(dp),
intent(out) :: e_cav(3, constants % ncav)
248 if (params % fmm .eq. 0)
then
249 call build_e_dense(multipoles, params % csph, mmax, params % nsph, &
250 & phi_cav, constants % ccav, constants % ncav, e_cav, ddx_error)
251 else if (params % fmm .eq. 1)
then
252 call build_e_fmm(params, constants, workspace, multipoles, &
253 & mmax, phi_cav, e_cav, ddx_error)
255end subroutine multipole_electrostatics_1
272subroutine build_e_dense(multipoles, cm, mmax, nm, phi_cav, ccav, ncav, &
275 integer,
intent(in) :: mmax, nm, ncav
276 real(dp),
intent(in) :: cm(3, nm), ccav(3, ncav), &
277 & multipoles((mmax + 1)**2, nm)
278 real(dp),
intent(out) :: phi_cav(ncav), e_cav(3, ncav)
279 type(ddx_error_type),
intent(inout) :: ddx_error
281 real(dp),
allocatable :: tmp_m_grad(:, :, :), vscales(:), &
282 & vscales_rel(:), v4pi2lp1(:)
283 integer icav, im, info
284 real(dp) :: v, ex, ey, ez, c(3)
288 allocate(tmp_m_grad((mmax + 2)**2, 3, nm), vscales((mmax + 2)**2), &
289 & vscales_rel((mmax + 2)**2), v4pi2lp1(mmax + 2), stat=info)
290 if (info .ne. 0)
then
291 call update_error(ddx_error,
"Allocation failed in build_e_dense!")
294 call ylmscale(mmax + 1, vscales, v4pi2lp1, vscales_rel)
297 call grad_m2m(multipoles, mmax, nm, tmp_m_grad, ddx_error)
298 if (ddx_error % flag .ne. 0)
then
299 call update_error(ddx_error,
"grad_m2m returned an error, exiting")
312 c(:) = ccav(:, icav) - cm(:, im)
313 call fmm_m2p(c, one, mmax, vscales_rel, one, multipoles(:, im), &
316 call fmm_m2p(c, one, mmax + 1, vscales_rel, one, &
317 & tmp_m_grad(:, 1, im), one, ex)
318 call fmm_m2p(c, one, mmax + 1, vscales_rel, one, &
319 & tmp_m_grad(:, 2, im), one, ey)
320 call fmm_m2p(c, one, mmax + 1, vscales_rel, one, &
321 & tmp_m_grad(:, 3, im), one, ez)
329 deallocate(tmp_m_grad, vscales, vscales_rel, v4pi2lp1, stat=info)
330 if (info .ne. 0)
then
331 call update_error(ddx_error,
"Deallocation failed in build_e_dense!")
334end subroutine build_e_dense
348subroutine multipole_electrostatics_0(params, constants, workspace, multipoles, &
349 & mmax, phi_cav, ddx_error)
351 type(ddx_params_type),
intent(in) :: params
352 type(ddx_workspace_type),
intent(inout) :: workspace
353 type(ddx_constants_type),
intent(in) :: constants
354 type(ddx_error_type),
intent(inout) :: ddx_error
355 integer,
intent(in) :: mmax
356 real(dp),
intent(in) :: multipoles((mmax + 1)**2, params % nsph)
357 real(dp),
intent(out) :: phi_cav(constants % ncav)
358 if (params % fmm .eq. 0)
then
359 call build_phi_dense(multipoles, params % csph, mmax, params % nsph, &
360 & phi_cav, constants % ccav, constants % ncav, ddx_error)
361 else if (params % fmm .eq. 1)
then
362 call build_phi_fmm(params, constants, workspace, multipoles, mmax, &
365end subroutine multipole_electrostatics_0
381subroutine build_phi_dense(multipoles, cm, mmax, nm, phi_cav, ccav, ncav, &
384 integer,
intent(in) :: mmax, nm, ncav
385 real(dp),
intent(in) :: cm(3, nm), ccav(3, ncav), &
386 & multipoles((mmax + 1)**2, nm)
387 real(dp),
intent(out) :: phi_cav(ncav)
388 type(ddx_error_type),
intent(inout) :: ddx_error
390 integer icav, im, info
392 real(dp),
allocatable :: vscales(:), vscales_rel(:), v4pi2lp1(:)
395 allocate(vscales((mmax + 1)**2), vscales_rel((mmax + 1)**2), &
396 & v4pi2lp1(mmax + 1), stat=info)
397 if (info .ne. 0)
then
398 call update_error(ddx_error,
'Allocation failed in build_phi_dense!')
401 call ylmscale(mmax, vscales, v4pi2lp1, vscales_rel)
406 c(:) = ccav(:, icav) - cm(:, im)
407 call fmm_m2p(c, one, mmax, vscales_rel, one, &
408 & multipoles(:, im), one, v)
413 deallocate(vscales, vscales_rel, v4pi2lp1, stat=info)
414 if (info .ne. 0)
then
415 call update_error(ddx_error,
'Deallocation failed in build_phi_dense!')
419end subroutine build_phi_dense
434subroutine build_e_fmm(params, constants, workspace, multipoles, &
435 & mmax, phi_cav, e_cav, ddx_error)
437 type(ddx_params_type),
intent(in) :: params
438 type(ddx_workspace_type),
intent(inout) :: workspace
439 type(ddx_constants_type),
intent(in) :: constants
440 type(ddx_error_type),
intent(inout) :: ddx_error
441 integer,
intent(in) :: mmax
442 real(dp),
intent(in) :: multipoles((mmax + 1)**2, params % nsph)
443 real(dp),
intent(out) :: phi_cav(constants % ncav), &
444 & e_cav(3, constants % ncav)
446 integer :: info, isph, igrid, inode, jnode, jsph, jnear, icav
447 real(dp) :: ex, ey, ez, c(3)
448 real(dp),
allocatable :: tmp_m_grad(:, :, :), grid_grad(:, :, :)
450 allocate(tmp_m_grad((mmax + 2)**2, 3, params % nsph), &
451 & grid_grad(params % ngrid, 3, params % nsph), stat=info)
452 if (info .ne. 0)
then
453 call update_error(ddx_error,
"Allocation failed in build_e_fmm!")
458 call grad_m2m(multipoles, mmax, params % nsph, tmp_m_grad, ddx_error)
459 if (ddx_error % flag .ne. 0)
then
460 call update_error(ddx_error,
"grad_m2m returned an error, exiting")
465 call load_m(params, constants, workspace, multipoles, mmax)
468 call do_fmm(params, constants, workspace)
471 call tree_m2p(params, constants, params % lmax, one, &
472 & workspace % tmp_sph, one, workspace % tmp_grid)
475 call dgemm(
'T',
'N', params % ngrid, params % nsph, &
476 & constants % nbasis, one, constants % vgrid2, &
477 & constants % vgrid_nbasis, workspace % tmp_sph, &
478 & constants % nbasis, one, workspace % tmp_grid, &
482 do isph = 1, params % nsph
483 do igrid = 1, params % ngrid
484 if(constants % ui(igrid, isph) .eq. zero) cycle
485 inode = constants % snode(isph)
489 do jnear = constants % snear(inode), constants % snear(inode+1) - 1
490 jnode = constants % near(jnear)
491 jsph = constants % order(constants % cluster(1, jnode))
492 c = params % csph(:, isph) + constants % cgrid(:, igrid) &
493 & *params % rsph(isph) - params % csph(:, jsph)
494 call fmm_m2p(c, one, mmax + 1, constants % vscales_rel, &
495 & one, tmp_m_grad(:, 1, jsph), one, ex)
496 call fmm_m2p(c, one, mmax + 1, constants % vscales_rel, &
497 & one, tmp_m_grad(:, 2, jsph), one, ey)
498 call fmm_m2p(c, one, mmax + 1, constants % vscales_rel, &
499 & one, tmp_m_grad(:, 3, jsph), one, ez)
501 grid_grad(igrid, 1, isph) = ex
502 grid_grad(igrid, 2, isph) = ey
503 grid_grad(igrid, 3, isph) = ez
508 if (params % pl .gt. 0)
then
509 call tree_grad_l2l(params, constants, workspace % tmp_node_l, &
510 & workspace % tmp_sph_l_grad, workspace % tmp_sph_l)
511 call dgemm(
'T',
'N', params % ngrid, 3*params % nsph, &
512 & (params % pl)**2, one, constants % vgrid2, &
513 & constants % vgrid_nbasis, workspace % tmp_sph_l_grad, &
514 & (params % pl+1)**2, one, grid_grad, params % ngrid)
519 do isph = 1, params % nsph
520 do igrid = 1, params % ngrid
521 if(constants % ui(igrid, isph) .eq. zero) cycle
523 phi_cav(icav) = workspace % tmp_grid(igrid, isph)
524 e_cav(:, icav) = grid_grad(igrid, :, isph)
528 deallocate(tmp_m_grad, grid_grad, stat=info)
529 if (info .ne. 0)
then
530 call update_error(ddx_error,
"Deallocation failed in build_e_fmm!")
534end subroutine build_e_fmm
551subroutine build_g_fmm(params, constants, workspace, multipoles, &
552 & mmax, phi_cav, e_cav, g_cav, ddx_error)
554 type(ddx_params_type),
intent(in) :: params
555 type(ddx_workspace_type),
intent(inout) :: workspace
556 type(ddx_constants_type),
intent(in) :: constants
557 type(ddx_error_type),
intent(inout) :: ddx_error
558 integer,
intent(in) :: mmax
559 real(dp),
intent(in) :: multipoles((mmax + 1)**2, params % nsph)
560 real(dp),
intent(out) :: phi_cav(constants % ncav), &
561 & e_cav(3, constants % ncav), g_cav(3, 3, constants % ncav)
563 integer :: info, isph, igrid, inode, jnode, jsph, jnear, icav
564 real(dp) :: ex, ey, ez, c(3), gxx, gxy, gxz, gyy, gyz, gzz
565 real(dp),
allocatable :: m_grad(:, :, :), grid_grad(:, :, :), &
566 & m_hess_x(:, :, :), m_hess_y(:, :, :), m_hess_z(:, :, :), &
567 & m_grad_component(:, :), grid_hess_x(:, :, :), &
568 & grid_hess_y(:, :, :), grid_hess_z(:, :, :), grid_hessian2(:, :, :)
570 allocate(m_hess_x((mmax+3)**2, 3, params % nsph), &
571 & m_hess_y((mmax+3)**2, 3, params % nsph), &
572 & m_hess_z((mmax+3)**2, 3, params % nsph), &
573 & m_grad_component((mmax+2)**2, params % nsph), &
574 & m_grad((mmax + 2)**2, 3, params % nsph), &
575 & grid_grad(params % ngrid, 3, params % nsph), &
576 & grid_hess_x(params % ngrid, 3, params % nsph), &
577 & grid_hess_y(params % ngrid, 3, params % nsph), &
578 & grid_hess_z(params % ngrid, 3, params % nsph), &
579 & grid_hessian2(params % ngrid, 3, params % nsph), &
581 if (info .ne. 0)
then
582 call update_error(ddx_error,
"Allocation failed in build_g_fmm!")
587 call grad_m2m(multipoles, mmax, params % nsph, m_grad, ddx_error)
591 m_grad_component = m_grad(:, 1, :)
592 call grad_m2m(m_grad_component, mmax + 1, params % nsph, m_hess_x, ddx_error)
593 m_grad_component = m_grad(:, 2, :)
594 call grad_m2m(m_grad_component, mmax + 1, params % nsph, m_hess_y, ddx_error)
595 m_grad_component = m_grad(:, 3, :)
596 call grad_m2m(m_grad_component, mmax + 1, params % nsph, m_hess_z, ddx_error)
597 if (ddx_error % flag .ne. 0)
then
598 call update_error(ddx_error,
"grad_m2m returned an error, exiting")
604 call load_m(params, constants, workspace, multipoles, mmax)
607 call do_fmm(params, constants, workspace)
610 call tree_m2p(params, constants, params % lmax, one, &
611 & workspace % tmp_sph, one, workspace % tmp_grid)
614 call dgemm(
'T',
'N', params % ngrid, params % nsph, &
615 & constants % nbasis, one, constants % vgrid2, &
616 & constants % vgrid_nbasis, workspace % tmp_sph, &
617 & constants % nbasis, one, workspace % tmp_grid, &
621 do isph = 1, params % nsph
622 do igrid = 1, params % ngrid
623 if(constants % ui(igrid, isph) .eq. zero) cycle
624 inode = constants % snode(isph)
628 do jnear = constants % snear(inode), constants % snear(inode+1) - 1
629 jnode = constants % near(jnear)
630 jsph = constants % order(constants % cluster(1, jnode))
631 c = params % csph(:, isph) + constants % cgrid(:, igrid) &
632 & *params % rsph(isph) - params % csph(:, jsph)
633 call fmm_m2p(c, one, mmax + 1, constants % vscales_rel, &
634 & one, m_grad(:, 1, jsph), one, ex)
635 call fmm_m2p(c, one, mmax + 1, constants % vscales_rel, &
636 & one, m_grad(:, 2, jsph), one, ey)
637 call fmm_m2p(c, one, mmax + 1, constants % vscales_rel, &
638 & one, m_grad(:, 3, jsph), one, ez)
640 grid_grad(igrid, 1, isph) = ex
641 grid_grad(igrid, 2, isph) = ey
642 grid_grad(igrid, 3, isph) = ez
647 do isph = 1, params % nsph
648 do igrid = 1, params % ngrid
649 if(constants % ui(igrid, isph) .eq. zero) cycle
650 inode = constants % snode(isph)
657 do jnear = constants % snear(inode), constants % snear(inode+1) - 1
658 jnode = constants % near(jnear)
659 jsph = constants % order(constants % cluster(1, jnode))
660 c = params % csph(:, isph) + constants % cgrid(:, igrid) &
661 & *params % rsph(isph) - params % csph(:, jsph)
662 call fmm_m2p(c, one, mmax + 2, constants % vscales_rel, &
663 & one, m_hess_x(:, 1, jsph), one, gxx)
664 call fmm_m2p(c, one, mmax + 2, constants % vscales_rel, &
665 & one, m_hess_x(:, 2, jsph), one, gxy)
666 call fmm_m2p(c, one, mmax + 2, constants % vscales_rel, &
667 & one, m_hess_x(:, 3, jsph), one, gxz)
668 call fmm_m2p(c, one, mmax + 2, constants % vscales_rel, &
669 & one, m_hess_y(:, 2, jsph), one, gyy)
670 call fmm_m2p(c, one, mmax + 2, constants % vscales_rel, &
671 & one, m_hess_y(:, 3, jsph), one, gyz)
672 call fmm_m2p(c, one, mmax + 2, constants % vscales_rel, &
673 & one, m_hess_z(:, 3, jsph), one, gzz)
675 grid_hess_x(igrid, 1, isph) = gxx
676 grid_hess_x(igrid, 2, isph) = gxy
677 grid_hess_x(igrid, 3, isph) = gxz
678 grid_hess_y(igrid, 1, isph) = gxy
679 grid_hess_y(igrid, 2, isph) = gyy
680 grid_hess_y(igrid, 3, isph) = gyz
681 grid_hess_z(igrid, 1, isph) = gxz
682 grid_hess_z(igrid, 2, isph) = gyz
683 grid_hess_z(igrid, 3, isph) = gzz
688 if (params % pl .gt. 0)
then
689 call tree_grad_l2l(params, constants, workspace % tmp_node_l, &
690 & workspace % tmp_sph_l_grad, workspace % tmp_sph_l)
691 call dgemm(
'T',
'N', params % ngrid, 3*params % nsph, &
692 & (params % pl)**2, one, constants % vgrid2, &
693 & constants % vgrid_nbasis, workspace % tmp_sph_l_grad, &
694 & (params % pl+1)**2, one, grid_grad, params % ngrid)
695 call tree_grad_l2l(params, constants, workspace % tmp_node_l, &
696 & workspace % tmp_sph_l_grad, workspace % tmp_sph_l)
700 if (params % pl .gt. 1)
then
704 do isph = 1, params % nsph
705 inode = constants % snode(isph)
706 workspace % tmp_node_l(:, inode) = &
707 & workspace % tmp_sph_l_grad(:, 1, isph)
713 call tree_grad_l2l(params, constants, workspace % tmp_node_l, &
714 & workspace % tmp_sph_l_grad2, workspace % tmp_sph_l)
716 call dgemm(
'T',
'N', params % ngrid, 3*params % nsph, &
717 & (params % pl-1)**2, one, constants % vgrid2, &
718 & constants % vgrid_nbasis, workspace % tmp_sph_l_grad2, &
719 & (params % pl+1)**2, zero, grid_hessian2, params % ngrid)
721 grid_hess_x = grid_hess_x + grid_hessian2
724 do isph = 1, params % nsph
725 inode = constants % snode(isph)
726 workspace % tmp_node_l(:, inode) = &
727 & workspace % tmp_sph_l_grad(:, 2, isph)
729 call tree_grad_l2l(params, constants, workspace % tmp_node_l, &
730 & workspace % tmp_sph_l_grad2, workspace % tmp_sph_l)
731 call dgemm(
'T',
'N', params % ngrid, 3*params % nsph, &
732 & (params % pl-1)**2, one, constants % vgrid2, &
733 & constants % vgrid_nbasis, workspace % tmp_sph_l_grad2, &
734 & (params % pl+1)**2, zero, grid_hessian2, params % ngrid)
735 grid_hess_y = grid_hess_y + grid_hessian2
738 do isph = 1, params % nsph
739 inode = constants % snode(isph)
740 workspace % tmp_node_l(:, inode) = &
741 & workspace % tmp_sph_l_grad(:, 3, isph)
743 call tree_grad_l2l(params, constants, workspace % tmp_node_l, &
744 & workspace % tmp_sph_l_grad2, workspace % tmp_sph_l)
745 call dgemm(
'T',
'N', params % ngrid, 3*params % nsph, &
746 & (params % pl-1)**2, one, constants % vgrid2, &
747 & constants % vgrid_nbasis, workspace % tmp_sph_l_grad2, &
748 & (params % pl+1)**2, zero, grid_hessian2, params % ngrid)
749 grid_hess_z = grid_hess_z + grid_hessian2
755 do isph = 1, params % nsph
756 do igrid = 1, params % ngrid
757 if(constants % ui(igrid, isph) .eq. zero) cycle
759 phi_cav(icav) = workspace % tmp_grid(igrid, isph)
760 e_cav(:, icav) = grid_grad(igrid, :, isph)
761 g_cav(1, :, icav) = grid_hess_x(igrid, :, isph)
762 g_cav(2, :, icav) = grid_hess_y(igrid, :, isph)
763 g_cav(3, :, icav) = grid_hess_z(igrid, :, isph)
767 deallocate(m_hess_x, m_hess_y, m_hess_z, m_grad_component, m_grad, &
768 & grid_grad, grid_hess_x, grid_hess_y, grid_hess_z, grid_hessian2, &
770 if (info .ne. 0)
then
771 call update_error(ddx_error,
"Deallocation failed in build_g_fmm!")
775end subroutine build_g_fmm
787subroutine build_phi_fmm(params, constants, workspace, multipoles, mmax, &
790 type(ddx_params_type),
intent(in) :: params
791 type(ddx_workspace_type),
intent(inout) :: workspace
792 type(ddx_constants_type),
intent(in) :: constants
793 integer,
intent(in) :: mmax
794 real(dp),
intent(in) :: multipoles((mmax + 1)**2, params % nsph)
795 real(dp),
intent(out) :: phi_cav(constants % ncav)
797 integer isph, igrid, icav
800 call load_m(params, constants, workspace, multipoles, mmax)
803 call do_fmm(params, constants, workspace)
806 call tree_m2p(params, constants, params % lmax, one, &
807 & workspace % tmp_sph, one, workspace % tmp_grid)
810 call dgemm(
'T',
'N', params % ngrid, params % nsph, &
811 & constants % nbasis, one, constants % vgrid2, &
812 & constants % vgrid_nbasis, workspace % tmp_sph, &
813 & constants % nbasis, one, workspace % tmp_grid, &
818 do isph = 1, params % nsph
819 do igrid = 1, params % ngrid
820 if(constants % ui(igrid, isph) .eq. zero) cycle
822 phi_cav(icav) = workspace % tmp_grid(igrid, isph)
826end subroutine build_phi_fmm
840 type(ddx_params_type),
intent(in) :: params
841 integer,
intent(in) :: mmax
842 real(dp),
intent(in) :: multipoles((mmax+1)**2, params % nsph)
843 real(dp),
intent(out) :: psi((params % lmax+1)**2, params % nsph)
844 integer :: isph, l, m, i
848 do isph = 1, params % nsph
850 v = fourpi/((two*dble(l) + one)*(params % rsph(isph)**(l)))
853 psi(i + m, isph) = v*multipoles(i + m, isph)
868subroutine load_m(params, constants, workspace, multipoles, mmax)
870 type(ddx_params_type),
intent(in) :: params
871 type(ddx_workspace_type),
intent(inout) :: workspace
872 type(ddx_constants_type),
intent(in) :: constants
873 integer,
intent(in) :: mmax
874 real(dp),
intent(in) :: multipoles((mmax + 1)**2, params % nsph)
875 integer :: isph, l, ind, m, inode, tmp_max
877 tmp_max = min(params % pm, mmax)
881 do isph = 1, params % nsph
882 inode = constants % snode(isph)
883 workspace % tmp_sph(:, isph) = zero
884 workspace % tmp_node_m(:, inode) = zero
888 workspace % tmp_sph(ind+m, isph) = &
889 & multipoles(ind+m, isph)/(params%rsph(isph)**(l+1))
890 workspace % tmp_node_m(ind+m, inode) = &
891 & multipoles(ind+m, isph)/(params%rsph(isph)**(l+1))
905subroutine do_fmm(params, constants, workspace)
907 type(ddx_params_type),
intent(in) :: params
908 type(ddx_workspace_type),
intent(inout) :: workspace
909 type(ddx_constants_type),
intent(in) :: constants
912 & workspace % tmp_node_l)
914 call tree_l2p(params, constants, one, workspace % tmp_node_l, zero, &
915 & workspace % tmp_grid, workspace % tmp_sph_l)
928subroutine grad_m2m(multipoles, mmax, nm, tmp_m_grad, ddx_error)
930 integer,
intent(in) :: mmax, nm
931 real(dp),
intent(in) :: multipoles((mmax + 1)**2, nm)
932 real(dp),
intent(out) :: tmp_m_grad((mmax + 2)**2, 3, nm)
933 type(ddx_error_type),
intent(inout) :: ddx_error
935 real(dp),
dimension(3, 3) :: zx_coord_transform, zy_coord_transform
936 real(dp),
allocatable :: tmp(:, :)
937 integer :: info, im, l, indi, indj, m
938 real(dp) :: tmp1, tmp2
940 allocate(tmp((mmax + 2)**2, nm), stat=info)
941 if (info .ne. 0)
then
942 call update_error(ddx_error,
"Allocation failed in grad_m2m!")
946 zx_coord_transform = zero
947 zx_coord_transform(3, 2) = one
948 zx_coord_transform(2, 3) = one
949 zx_coord_transform(1, 1) = one
950 zy_coord_transform = zero
951 zy_coord_transform(1, 2) = one
952 zy_coord_transform(2, 1) = one
953 zy_coord_transform(3, 3) = one
955 tmp_m_grad(1:(mmax + 1)**2, 3, :) = multipoles
957 call fmm_sph_transform(mmax, zx_coord_transform, one, &
958 & multipoles(:, im), zero, tmp_m_grad(1:(mmax + 1)**2, 1, im))
959 call fmm_sph_transform(mmax, zy_coord_transform, one, &
960 & multipoles(:, im), zero, tmp_m_grad(1:(mmax + 1)**2, 2, im))
966 tmp1 = sqrt(dble(2*l+1)) / sqrt(dble(2*l-1))
968 tmp2 = sqrt(dble(l*l-m*m)) * tmp1
969 tmp_m_grad(indi+m, :, :) = tmp2 * tmp_m_grad(indj+m, :, :)
971 tmp_m_grad(indi+l, :, :) = zero
972 tmp_m_grad(indi-l, :, :) = zero
974 tmp_m_grad(1, :, :) = zero
977 tmp_m_grad(:, 3, im) = tmp_m_grad(:, 3, im)
978 tmp(:, im) = tmp_m_grad(:, 1, im)
979 call fmm_sph_transform(mmax+1, zx_coord_transform, one, &
980 & tmp(:, im), zero, tmp_m_grad(:, 1, im))
981 tmp(:, im) = tmp_m_grad(:, 2, im)
982 call fmm_sph_transform(mmax+1, zy_coord_transform, one, &
983 & tmp(:, im), zero, tmp_m_grad(:, 2, im))
986 deallocate(tmp, stat=info)
987 if (info .ne. 0)
then
988 call update_error(ddx_error,
"Deallocation failed in grad_m2m!")
992end subroutine grad_m2m
1003subroutine grad_phi_for_charges(params, constants, workspace, state, &
1004 & charges, forces, ddx_error)
1006 type(ddx_params_type),
intent(in) :: params
1007 type(ddx_workspace_type),
intent(inout) :: workspace
1008 type(ddx_constants_type),
intent(in) :: constants
1010 type(ddx_error_type),
intent(inout) :: ddx_error
1011 real(dp),
intent(in) :: charges(params % nsph)
1012 real(dp),
intent(inout) :: forces(3, params % nsph)
1015 real(dp),
allocatable :: multipoles(:, :)
1017 allocate(multipoles(1, params % nsph), stat=info)
1018 if (info .ne. 0)
then
1019 call update_error(ddx_error,
"Allocation failed in grad_phi_for_charges")
1023 multipoles(1, :) = charges/sqrt4pi
1024 call grad_phi(params, constants, workspace, state, 0, multipoles, forces, &
1026 deallocate(multipoles, stat=info)
1027 if (info .ne. 0)
then
1028 call update_error(ddx_error,
"Deallocation failed in grad_phi_for_charges")
1032end subroutine grad_phi_for_charges
1047subroutine grad_phi(params, constants, workspace, state, mmax, &
1048 & multipoles, forces, ddx_error)
1050 type(ddx_params_type),
intent(in) :: params
1051 type(ddx_workspace_type),
intent(inout) :: workspace
1052 type(ddx_constants_type),
intent(in) :: constants
1054 type(ddx_error_type),
intent(inout) :: ddx_error
1055 integer,
intent(in) :: mmax
1056 real(dp),
intent(in) :: multipoles((mmax + 1)**2, params % nsph)
1057 real(dp),
intent(inout) :: forces(3, params % nsph)
1059 integer :: info, im, lm, ind, l, m
1060 real(dp),
allocatable :: adj_phi(:, :), m_grad(:, :, :)
1065 allocate(adj_phi((mmax + 2)**2, params % nsph), &
1066 & m_grad((mmax + 2)**2, 3, params % nsph), stat=info)
1067 if (info .ne. 0)
then
1068 call update_error(ddx_error,
"Allocation failed in grad_phi!")
1073 call build_adj_phi(params, constants, workspace, state % zeta, &
1074 & mmax + 1, adj_phi, ddx_error)
1075 if (ddx_error % flag .ne. 0)
then
1076 call update_error(ddx_error,
"build_adj_phi returned an error, exiting")
1081 call grad_m2m(multipoles, mmax, params % nsph, m_grad, ddx_error)
1082 if (ddx_error % flag .ne. 0)
then
1083 call update_error(ddx_error,
"grad_m2m returned an error, exiting")
1088 do im = 1, params % nsph
1094 forces(1, im) = forces(1, im) &
1095 & + fac*pt5*m_grad(lm, 1, im)*adj_phi(lm, im)
1096 forces(2, im) = forces(2, im) &
1097 & + fac*pt5*m_grad(lm, 2, im)*adj_phi(lm, im)
1098 forces(3, im) = forces(3, im) &
1099 & + fac*pt5*m_grad(lm, 3, im)*adj_phi(lm, im)
1104 deallocate(adj_phi, m_grad, stat=info)
1105 if (info .ne. 0)
then
1106 call update_error(ddx_error,
"Deallocation failed in grad_phi!")
1110end subroutine grad_phi
1125subroutine build_adj_phi(params, constants, workspace, charges, mmax, &
1126 & adj_phi, ddx_error)
1128 type(ddx_params_type),
intent(in) :: params
1129 type(ddx_workspace_type),
intent(inout) :: workspace
1130 type(ddx_constants_type),
intent(in) :: constants
1131 type(ddx_error_type),
intent(inout) :: ddx_error
1132 integer,
intent(in) :: mmax
1133 real(dp),
intent(in) :: charges(constants % ncav)
1134 real(dp),
intent(out) :: adj_phi((mmax + 1)**2, params % nsph)
1135 if (params % fmm .eq. 0)
then
1136 call build_adj_phi_dense(charges, constants % ccav, constants % ncav, &
1137 & params % csph, mmax, params % nsph, adj_phi, ddx_error)
1138 else if (params % fmm .eq. 1)
then
1139 call build_adj_phi_fmm(params, constants, workspace, charges, mmax, &
1140 & adj_phi, ddx_error)
1142end subroutine build_adj_phi
1157subroutine build_adj_phi_dense(qcav, ccav, ncav, cm, mmax, nm, adj_phi, &
1160 integer,
intent (in) :: ncav, mmax, nm
1161 real(dp),
intent(in) :: qcav(ncav), ccav(3, ncav), cm(3, nm)
1162 real(dp),
intent(out) :: adj_phi((mmax + 1)**2, nm)
1163 type(ddx_error_type),
intent(inout) :: ddx_error
1165 integer :: icav, im, info
1167 real(dp),
allocatable :: vscales(:), vscales_rel(:), v4pi2lp1(:), &
1170 allocate(vscales((mmax + 1)**2), vscales_rel((mmax + 1)**2), &
1171 & v4pi2lp1(mmax + 1), work((mmax + 1)**2 + 3*mmax), stat=info)
1172 if (info .ne. 0)
then
1173 call update_error(ddx_error,
'Allocation failed in build_adj_phi_dense!')
1176 call ylmscale(mmax, vscales, v4pi2lp1, vscales_rel)
1179 adj_phi(:, im) = zero
1181 c(:) = cm(:, im) - ccav(:, icav)
1182 call fmm_m2p_adj_work(c, qcav(icav), one, mmax, vscales_rel, &
1183 & one, adj_phi(:, im), work)
1187 deallocate(vscales, vscales_rel, v4pi2lp1, work, stat=info)
1188 if (info .ne. 0)
then
1189 call update_error(ddx_error,
'Deallocation failed in build_adj_phi_dense!')
1193end subroutine build_adj_phi_dense
1208subroutine build_adj_phi_fmm(params, constants, workspace, charges, mmax, &
1209 & adj_phi, ddx_error)
1211 type(ddx_params_type),
intent(in) :: params
1212 type(ddx_workspace_type),
intent(inout) :: workspace
1213 type(ddx_constants_type),
intent(in) :: constants
1214 type(ddx_error_type),
intent(inout) :: ddx_error
1215 integer,
intent(in) :: mmax
1216 real(dp),
intent(in) :: charges(constants % ncav)
1217 real(dp),
intent(out) :: adj_phi((mmax + 1)**2, params % nsph)
1219 real(dp),
allocatable :: tmp_grid(:, :), sph_m(:, :), work(:)
1220 integer :: info, icav, isph, igrid, inode, indl, l, jnear, &
1221 & jnode, jsph, m, ind
1222 real(dp) :: c(3), fac
1224 allocate(tmp_grid(params % ngrid, params % nsph), &
1225 & sph_m((mmax + 1)**2, params % nsph), &
1226 & work((mmax + 1)**2 + 3*mmax), stat=info)
1227 if (info .ne. 0)
then
1228 call update_error(ddx_error,
"Allocation failed in build_adj_phi_fmm!")
1236 do isph = 1, params % nsph
1237 do igrid = 1, params % ngrid
1238 if (constants % ui(igrid, isph) .eq. zero) cycle
1240 tmp_grid(igrid, isph) = charges(icav)
1247 do isph = 1, params % nsph
1248 inode = constants % snode(isph)
1249 do jnear = constants % snear(inode), constants % snear(inode+1)-1
1250 jnode = constants % near(jnear)
1251 jsph = constants % order(constants % cluster(1, jnode))
1252 do igrid = 1, params % ngrid
1253 c = constants % cgrid(:, igrid)*params % rsph(isph) - &
1254 & params % csph(:, jsph) + params % csph(:, isph)
1255 call fmm_m2p_adj_work(c, tmp_grid(igrid, isph), &
1256 & params % rsph(jsph), mmax, constants % vscales_rel, one, &
1257 & adj_phi(:, jsph), work)
1263 call tree_l2p_adj(params, constants, one, tmp_grid, zero, &
1264 & workspace % tmp_node_l, workspace % tmp_sph_l)
1267 & workspace % tmp_node_m)
1271 if(mmax .lt. params % pm)
then
1272 do isph = 1, params % nsph
1273 inode = constants % snode(isph)
1274 adj_phi(:, isph) = adj_phi(:, isph) &
1275 & + workspace % tmp_node_m(1:(mmax + 1)**2, inode)
1278 indl = (params % pm+1)**2
1279 do isph = 1, params % nsph
1280 inode = constants % snode(isph)
1281 adj_phi(1:indl, isph) = adj_phi(1:indl, isph) &
1282 & + workspace % tmp_node_m(:, inode)
1288 do isph = 1, params % nsph
1291 fac = - (-one/params % rsph(isph))**(l + 1)
1293 adj_phi(ind + m, isph) = fac*adj_phi(ind + m, isph)
1298 deallocate(tmp_grid, work, stat=info)
1299 if (info .ne. 0)
then
1300 call update_error(ddx_error,
"Deallocation failed in build_adj_phi_fmm")
1304end subroutine build_adj_phi_fmm
1317subroutine grad_e_for_charges(params, constants, workspace, state, &
1318 & charges, force, ddx_error)
1320 type(ddx_params_type),
intent(in) :: params
1321 type(ddx_workspace_type),
intent(inout) :: workspace
1322 type(ddx_constants_type),
intent(in) :: constants
1324 type(ddx_error_type),
intent(inout) :: ddx_error
1325 real(dp),
intent(in) :: charges(params % nsph)
1326 real(dp),
intent(inout) :: force(3, params % nsph)
1327 real(dp),
allocatable :: multipoles(:, :)
1330 allocate(multipoles(1, params % nsph), stat=info)
1331 if (info .ne. 0)
then
1332 call update_error(ddx_error,
"Allocation failed in grad_e_for_charges")
1336 multipoles(1, :) = charges/sqrt4pi
1337 call grad_e(params, constants, workspace, state, 0, multipoles, force, &
1339 deallocate(multipoles, stat=info)
1340 if (info .ne. 0)
then
1341 call update_error(ddx_error,
"Deallocation failed in grad_e_for_charges")
1345end subroutine grad_e_for_charges
1360subroutine grad_e(params, constants, workspace, state, mmax, &
1361 & multipoles, force, ddx_error)
1363 type(ddx_params_type),
intent(in) :: params
1364 type(ddx_workspace_type),
intent(inout) :: workspace
1365 type(ddx_constants_type),
intent(in) :: constants
1367 type(ddx_error_type),
intent(inout) :: ddx_error
1368 integer,
intent(in) :: mmax
1369 real(dp),
intent(in) :: multipoles((mmax+1)**2, params % nsph)
1370 real(dp),
intent(inout) :: force(3, params % nsph)
1372 real(dp),
allocatable :: zeta_comp(:), m_grad(:, :, :), &
1373 & m_hess_x(:, :, :), m_hess_y(:, :, :), m_hess_z(:, :, :), &
1374 & m_grad_component(:, :), adj_phi_x(:, :), adj_phi_y(:, :), &
1376 integer :: info, isph, ind, l, m, lm
1379 allocate(zeta_comp(constants % ncav), &
1380 & adj_phi_x((mmax+3)**2, params % nsph), &
1381 & adj_phi_y((mmax+3)**2, params % nsph), &
1382 & adj_phi_z((mmax+3)**2, params % nsph), &
1383 & m_hess_x((mmax+3)**2, 3, params % nsph), &
1384 & m_hess_y((mmax+3)**2, 3, params % nsph), &
1385 & m_hess_z((mmax+3)**2, 3, params % nsph), &
1386 & m_grad((mmax+2)**2, 3, params % nsph), &
1387 & m_grad_component((mmax+2)**2, params % nsph), &
1390 call update_error(ddx_error,
"Allocation failed in grad_e")
1395 call grad_m2m(multipoles, mmax, params % nsph, m_grad, ddx_error)
1399 m_grad_component = m_grad(:, 1, :)
1400 call grad_m2m(m_grad_component, mmax + 1, params % nsph, m_hess_x, ddx_error)
1401 m_grad_component = m_grad(:, 2, :)
1402 call grad_m2m(m_grad_component, mmax + 1, params % nsph, m_hess_y, ddx_error)
1403 m_grad_component = m_grad(:, 3, :)
1404 call grad_m2m(m_grad_component, mmax + 1, params % nsph, m_hess_z, ddx_error)
1405 if (ddx_error % flag .ne. 0)
then
1406 call update_error(ddx_error,
"grad_m2m returned an error, exiting")
1413 zeta_comp = state % zeta_dip(1, :)
1414 call build_adj_phi(params, constants, workspace, zeta_comp, &
1415 & mmax + 2, adj_phi_x, ddx_error)
1416 zeta_comp = state % zeta_dip(2, :)
1417 call build_adj_phi(params, constants, workspace, zeta_comp, &
1418 & mmax + 2, adj_phi_y, ddx_error)
1419 zeta_comp = state % zeta_dip(3, :)
1420 call build_adj_phi(params, constants, workspace, zeta_comp, &
1421 & mmax + 2, adj_phi_z, ddx_error)
1422 if (ddx_error % flag .ne. 0)
then
1423 call update_error(ddx_error,
"build_adj_phi returned an error, exiting")
1430 do isph = 1, params % nsph
1433 fac = -(-one)**(l+1)/2.0d0
1436 force(1, isph) = force(1, isph) &
1437 & + fac*m_hess_x(lm, 1, isph)*adj_phi_x(lm, isph) &
1438 & + fac*m_hess_y(lm, 1, isph)*adj_phi_y(lm, isph) &
1439 & + fac*m_hess_z(lm, 1, isph)*adj_phi_z(lm, isph)
1440 force(2, isph) = force(2, isph) &
1441 & + fac*m_hess_x(lm, 2, isph)*adj_phi_x(lm, isph) &
1442 & + fac*m_hess_y(lm, 2, isph)*adj_phi_y(lm, isph) &
1443 & + fac*m_hess_z(lm, 2, isph)*adj_phi_z(lm, isph)
1444 force(3, isph) = force(3, isph) &
1445 & + fac*m_hess_x(lm, 3, isph)*adj_phi_x(lm, isph) &
1446 & + fac*m_hess_y(lm, 3, isph)*adj_phi_y(lm, isph) &
1447 & + fac*m_hess_z(lm, 3, isph)*adj_phi_z(lm, isph)
1452 deallocate(zeta_comp, adj_phi_x, adj_phi_y, adj_phi_z, m_hess_x, &
1453 & m_hess_y, m_hess_z, m_grad, m_grad_component, stat=info)
1455 call update_error(ddx_error,
"Allocation failed in grad_e")
1459end subroutine grad_e
1476 & multipoles, forces, ddx_error)
1478 type(ddx_params_type),
intent(in) :: params
1479 type(ddx_workspace_type),
intent(inout) :: workspace
1480 type(ddx_constants_type),
intent(in) :: constants
1482 type(ddx_error_type),
intent(inout) :: ddx_error
1483 integer,
intent(in) :: mmax
1484 real(dp),
intent(in) :: multipoles((mmax + 1)**2, params % nsph)
1485 real(dp),
intent(inout) :: forces(3, params % nsph)
1487 call grad_phi(params, constants, workspace, state, mmax, multipoles, &
1488 & forces, ddx_error)
1489 if (ddx_error % flag .ne. 0)
then
1490 call update_error(ddx_error, &
1491 &
"multipole_force_terms: grad_phi returned an error, exiting")
1495 if (params % model .eq. 3)
then
1496 call grad_e(params, constants, workspace, state, mmax, multipoles, &
1497 & forces, ddx_error)
1498 if (ddx_error % flag .ne. 0)
then
1499 call update_error(ddx_error, &
1500 &
"multipole_force_terms: grad_e returned an error, exiting")
subroutine allocate_electrostatics(params, constants, electrostatics, ddx_error)
Given the chosen model, find the required electrostatic properties, and allocate the arrays for them ...
subroutine multipole_electrostatics(params, constants, workspace, multipoles, mmax, electrostatics, ddx_error)
Given a multipolar distribution, compute the required electrostatic properties for the chosen model.
subroutine multipole_force_terms(params, constants, workspace, state, mmax, multipoles, forces, ddx_error)
Given a multipolar distribution in real spherical harmonics and centered on the spheres,...
subroutine multipole_psi(params, multipoles, mmax, psi)
Given a multipolar distribution, assemble the RHS psi. The multipoles must be centered on the ddx sph...
Core routines and parameters of the ddX software.
subroutine tree_grad_l2l(params, constants, node_l, sph_l_grad, work)
TODO.
subroutine tree_l2l_rotation(params, constants, node_l)
Transfer local coefficients over a tree.
subroutine tree_m2m_rotation(params, constants, node_m)
Transfer multipole coefficients over a tree.
subroutine tree_l2p(params, constants, alpha, node_l, beta, grid_v, sph_l)
TODO.
subroutine tree_l2p_adj(params, constants, alpha, grid_v, beta, node_l, sph_l)
TODO.
subroutine tree_m2l_rotation(params, constants, node_m, node_l)
Transfer multipole local coefficients into local over a tree.
subroutine tree_m2p(params, constants, p, alpha, sph_m, beta, grid_v)
TODO.
subroutine tree_m2l_rotation_adj(params, constants, node_l, node_m)
Adjoint transfer multipole local coefficients into local over a tree.
subroutine tree_l2l_rotation_adj(params, constants, node_l)
Adjoint transfer local coefficients over a tree.
subroutine tree_m2m_rotation_adj(params, constants, node_m)
Adjoint transfer multipole coefficients over a tree.
Compile-time constants and definitions.
Core routines and parameters specific to gradients.
Routines to build rhs (phi and psi)
Container for the electrostatic properties. Since different methods require different electrostatic p...
This defined type contains the primal and adjoint RHSs, the solution of the primal and adjoint linear...