99 */
1010#include " PoissonSolve.H"
1111
12+ #include " initialization/Algorithms.H"
13+
1214#include < ablastr/constant.H>
1315#include < ablastr/fields/PoissonSolver.H>
1416
1517#include < AMReX_BLProfiler.H>
1618#include < AMReX_Math.H>
19+ #include < AMReX_MultiFabUtil.H>
1720#include < AMReX_ParmParse.H>
1821#include < AMReX_REAL.H> // for ParticleReal
1922
@@ -34,6 +37,8 @@ namespace impactx::particles::spacecharge
3437 using namespace amrex ::literals;
3538 using amrex::Math::powi;
3639
40+ auto space_charge = get_space_charge_algo ();
41+
3742 // set space charge field to zero
3843 // loop over refinement levels
3944 int const finest_level = phi.size () - 1u ;
@@ -77,12 +82,38 @@ namespace impactx::particles::spacecharge
7782 amrex::Vector<amrex::MultiFab*> sorted_rho;
7883 amrex::Vector<amrex::MultiFab*> sorted_phi;
7984
85+ auto geom_3d = pc.GetParGDB ()->Geom ();
86+
87+ amrex::Vector<std::pair<amrex::MultiFab, amrex::MultiFab>> rho_2d; // pair: local & unique boxes
88+ amrex::Vector<amrex::MultiFab> phi_2d;
8089 for (int lev = 0 ; lev <= finest_level; ++lev) {
81- sorted_rho.emplace_back (&rho[lev]);
82- sorted_phi.emplace_back (&phi[lev]);
90+ if (space_charge == SpaceChargeAlgo::True_2D) {
91+ // flattened rho
92+ auto const & ma = rho[lev].const_arrays ();
93+ amrex::Box domain_lev = lev == 0 ? geom_3d[lev].Domain () : phi[lev].boxArray ().minimalBox ();
94+ rho_2d.emplace_back (amrex::ReduceToPlaneMF2<amrex::ReduceOpSum>
95+ (2 , domain_lev, rho[lev], [=] AMREX_GPU_DEVICE (int b, int i, int j, int k)
96+ {
97+ return ma[b](i,j,k);
98+ })
99+ );
100+
101+ // 2D phi
102+ auto & r2d = rho_2d.back ().second ;
103+ auto nGrow = phi[lev].nGrowVect ();
104+ nGrow[2 ] = 0 ;
105+ phi_2d.emplace_back (r2d.boxArray (), r2d.DistributionMap (), r2d.nComp (), nGrow);
106+
107+ sorted_rho.emplace_back (&rho_2d.back ().second );
108+ sorted_phi.emplace_back (&phi_2d.back ());
109+ }
110+ else if (space_charge == SpaceChargeAlgo::True_3D) {
111+ sorted_rho.emplace_back (&rho[lev]);
112+ sorted_phi.emplace_back (&phi[lev]);
113+ }
83114 }
84115
85- const bool is_igf_2d = false ;
116+ const bool is_igf_2d = space_charge == SpaceChargeAlgo::True_2D ;
86117 const bool do_single_precision_comms = false ;
87118 const bool eb_enabled = false ;
88119 ablastr::fields::computePhi (
@@ -120,6 +151,24 @@ namespace impactx::particles::spacecharge
120151 for (int lev=0 ; lev<=finest_level; lev++)
121152 {
122153 amrex::MultiFab & phi_at_level = phi.at (lev);
154+
155+ if (space_charge == SpaceChargeAlgo::True_2D) {
156+ rho_2d[lev].first .ParallelCopy (phi_2d[lev]);
157+
158+ for (amrex::MFIter mfi (phi_at_level); mfi.isValid (); ++mfi) {
159+ auto const & src = rho_2d[lev].first [mfi].const_array ();
160+ auto const & dst = phi_at_level[mfi].array ();
161+
162+ // spread out the same x-y values over all z (s)
163+ // TODO: later on we can keep phi flat 2D, but need to update the gather for that to not use
164+ // a stencil in z
165+ auto bx = mfi.validbox ();
166+ amrex::ParallelFor (bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept {
167+ dst (i,j,k) = src (i,j,0 );
168+ });
169+ }
170+ }
171+
123172 phi_at_level.FillBoundary (pc.GetParGDB ()->Geom ()[lev].periodicity ());
124173 }
125174 }
0 commit comments