WarpX
Loading...
Searching...
No Matches
EffectivePotentialPoissonSolver.H
Go to the documentation of this file.
1/* Copyright 2024 The WarpX Community
2 *
3 * This file is part of WarpX.
4 *
5 * Authors: Roelof Groenewald (TAE Technologies)
6 *
7 * License: BSD-3-Clause-LBNL
8 */
9/*
10 * This file was copied and edited from PoissonSolver.H in the same directory.
11 */
12#ifndef ABLASTR_EFFECTIVE_POTENTIAL_POISSON_SOLVER_H
13#define ABLASTR_EFFECTIVE_POTENTIAL_POISSON_SOLVER_H
14
15#include <ablastr/constant.H>
22#include "PoissonSolver.H"
23
24#if defined(WARPX_USE_FFT) && defined(WARPX_DIM_3D)
26#endif
27
28#include <AMReX_Array.H>
29#include <AMReX_Array4.H>
30#include <AMReX_BLassert.H>
31#include <AMReX_Box.H>
32#include <AMReX_BoxArray.H>
33#include <AMReX_Config.H>
35#include <AMReX_FArrayBox.H>
36#include <AMReX_FabArray.H>
37#include <AMReX_Geometry.H>
38#include <AMReX_GpuControl.H>
39#include <AMReX_GpuLaunch.H>
40#include <AMReX_GpuQualifiers.H>
41#include <AMReX_IndexType.H>
42#include <AMReX_IntVect.H>
43#include <AMReX_LO_BCTYPES.H>
44#include <AMReX_MFIter.H>
45#include <AMReX_MFInterp_C.H>
46#include <AMReX_MLMG.H>
47#include <AMReX_MLLinOp.H>
49#include <AMReX_MultiFab.H>
50#include <AMReX_Parser.H>
51#include <AMReX_REAL.H>
52#include <AMReX_SPACE.H>
53#include <AMReX_Vector.H>
55#ifdef AMREX_USE_EB
56# include <AMReX_EBFabFactory.H>
57#endif
58
59#include <array>
60#include <optional>
61
62
63namespace ablastr::fields {
64
97template<
98 typename T_PostPhiCalculationFunctor = std::nullopt_t,
99 typename T_BoundaryHandler = std::nullopt_t,
100 typename T_FArrayBoxFactory = void
101>
102void
106 amrex::MultiFab const & sigma,
107 amrex::Real relative_tolerance,
108 amrex::Real absolute_tolerance,
109 int max_iters,
110 int verbosity,
114 [[maybe_unused]] utils::enums::GridType grid_type,
115 bool is_solver_igf_on_lev0,
116 bool eb_enabled = false,
117 bool do_single_precision_comms = false,
118 std::optional<amrex::Vector<amrex::IntVect> > rel_ref_ratio = std::nullopt,
119 [[maybe_unused]] T_PostPhiCalculationFunctor post_phi_calculation = std::nullopt,
120 [[maybe_unused]] T_BoundaryHandler const boundary_handler = std::nullopt,
121 [[maybe_unused]] std::optional<amrex::Real const> current_time = std::nullopt, // only used for EB
122 [[maybe_unused]] std::optional<amrex::Vector<T_FArrayBoxFactory const *> > eb_farray_box_factory = std::nullopt // only used for EB
123) {
124 using namespace amrex::literals;
125
126 ABLASTR_PROFILE("computeEffectivePotentialPhi");
127
128 if (!rel_ref_ratio.has_value()) {
130 "rel_ref_ratio must be set if mesh-refinement is used");
131 rel_ref_ratio = amrex::Vector<amrex::IntVect>{{amrex::IntVect(AMREX_D_DECL(1, 1, 1))}};
132 }
133
134#if !defined(AMREX_USE_EB)
136 "Embedded boundary solve requested but not compiled in");
137#endif
138 if (eb_enabled && std::is_same_v<void, T_FArrayBoxFactory>) {
139 throw std::runtime_error("EB requested by eb_farray_box_factory not provided!");
140 }
141
142 ABLASTR_ALWAYS_ASSERT_WITH_MESSAGE( !is_solver_igf_on_lev0,
143 "FFT solver cannot be used with effective potential Poisson solve");
144
145#ifdef WARPX_DIM_RZ
146 constexpr bool is_rz = true;
147#else
148 constexpr bool is_rz = false;
149#endif
150
151 auto const finest_level = static_cast<int>(rho.size() - 1);
152
153 // determine if rho is zero everywhere
154 const amrex::Real max_norm_b = getMaxNormRho(
155 amrex::GetVecOfConstPtrs(rho), finest_level, absolute_tolerance);
156
157 const amrex::LPInfo info;
158
159 for (int lev=0; lev<=finest_level; lev++) {
160
161 // Use the Multigrid (MLMG) solver but first scale rho appropriately
162 using namespace ablastr::constant::SI;
163 rho[lev]->mult(-1._rt/ep0);
164
165 std::unique_ptr<amrex::MLNodeLinOp> linop;
166 // In the presence of EB or RZ the EB enabled linear solver is used
167 if (eb_enabled)
168 {
169#if defined(AMREX_USE_EB)
170 auto linop_nodelap = std::make_unique<amrex::MLEBNodeFDLaplacian>();
171 linop_nodelap->define(
175 info,
176 amrex::Vector<amrex::EBFArrayBoxFactory const*>{eb_farray_box_factory.value()[lev]}
177 );
178 if constexpr (!std::is_same_v<T_BoundaryHandler, std::nullopt_t>) {
179 // if the EB potential only depends on time, the potential can be passed
180 // as a float instead of a callable
181 if (boundary_handler.phi_EB_only_t) {
182 linop_nodelap->setEBDirichlet(boundary_handler.potential_eb_t(current_time.value()));
183 } else {
184 linop_nodelap->setEBDirichlet(boundary_handler.getPhiEB(current_time.value()));
185 }
186 }
187 linop_nodelap->setSigma(lev, sigma);
188 linop = std::move(linop_nodelap);
189#endif
190 }
191 else if (is_rz)
192 {
193 auto linop_nodelap = std::make_unique<amrex::MLEBNodeFDLaplacian>();
194 linop_nodelap->define(
198 info
199 );
200 linop_nodelap->setRZ(true);
201 linop_nodelap->setSigma(lev, sigma);
202 linop = std::move(linop_nodelap);
203 }
204 else
205 {
206 auto linop_nodelap = std::make_unique<amrex::MLNodeLaplacian>();
207 linop_nodelap->define(
211 info
212 );
213 linop_nodelap->setSigma(lev, sigma);
214 linop = std::move(linop_nodelap);
215 }
216
217 // Set domain boundary conditions
218 if constexpr (std::is_same_v<T_BoundaryHandler, std::nullopt_t>) {
220 amrex::LinOpBCType::Dirichlet,
221 amrex::LinOpBCType::Dirichlet,
222 amrex::LinOpBCType::Dirichlet
223 )};
225 linop->setDomainBC(lobc, hibc);
226 } else {
227 linop->setDomainBC(boundary_handler.lobc, boundary_handler.hibc);
228 }
229
230 // Solve the Poisson equation
231 amrex::MLMG mlmg(*linop); // actual solver defined here
232 mlmg.setVerbose(verbosity);
233 mlmg.setMaxIter(max_iters);
234 mlmg.setConvergenceNormType((max_norm_b > 0) ? amrex::MLMGNormType::bnorm : amrex::MLMGNormType::greater);
235
236 const int ng = int(grid_type == utils::enums::GridType::Collocated); // ghost cells
237 if (ng) {
238 // In this case, computeE needs to use ghost nodes data. So we
239 // ask MLMG to fill BC for us after it solves the problem.
240 mlmg.setFinalFillBC(true);
241 }
242
243 // Solve Poisson equation at lev
244 mlmg.solve( {phi[lev]}, {rho[lev]},
245 relative_tolerance, absolute_tolerance );
246
247 // needed for solving the levels by levels:
248 // - coarser level is initial guess for finer level
249 // - coarser level provides boundary values for finer level patch
250 // Interpolation from phi[lev] to phi[lev+1]
251 // (This provides both the boundary conditions and initial guess for phi[lev+1])
252 if (lev < finest_level) {
253 const amrex::IntVect& refratio = rel_ref_ratio.value()[lev];
254 const int ncomp = linop->getNComp();
256 phi[lev+1],
257 geom[lev],
258 do_single_precision_comms,
259 refratio,
260 ncomp,
261 ng);
262 }
263
264 // Run additional operations, such as calculation of the E field for embedded boundaries
265 if constexpr (!std::is_same_v<T_PostPhiCalculationFunctor, std::nullopt_t>) {
266 if (post_phi_calculation.has_value()) {
267 post_phi_calculation.value()(mlmg, lev);
268 }
269 }
270 rho[lev]->mult(-ep0); // Multiply rho by epsilon again
271 } // loop over lev(els)
272}
273
274} // namespace ablastr::fields
275
276#endif // ABLASTR_EFFECTIVE_POTENTIAL_POISSON_SOLVER_H
#define AMREX_D_DECL(a, b, c)
#define ABLASTR_PROFILE(fname)
Definition ProfilerWrapper.H:13
#define ABLASTR_ALWAYS_ASSERT_WITH_MESSAGE(EX, MSG)
Definition TextMsg.H:75
void setVerbose(int v) noexcept
void setFinalFillBC(int flag) noexcept
void setConvergenceNormType(MLMGNormType norm) noexcept
RT solve(const Vector< AMF * > &a_sol, const Vector< AMF const * > &a_rhs, RT a_tol_rel, RT a_tol_abs, const char *checkpoint_file=nullptr)
void setMaxIter(int n) noexcept
Long size() const noexcept
Definition constant.H:40
static constexpr auto ep0
vacuum permittivity: dielectric permittivity of vacuum [F/m]
Definition constant.H:46
Definition EffectivePotentialPoissonSolver.H:63
void interpolatePhiBetweenLevels(amrex::MultiFab const *phi_lev, amrex::MultiFab *phi_lev_plus_one, amrex::Geometry const &geom_lev, bool do_single_precision_comms, const amrex::IntVect &refratio, const int ncomp, const int ng)
Definition PoissonSolver.H:107
amrex::Real getMaxNormRho(ablastr::fields::ConstMultiLevelScalarField const &rho, int finest_level, amrex::Real &absolute_tolerance)
Definition PoissonSolver.H:70
amrex::Vector< ScalarField > MultiLevelScalarField
Definition MultiFabRegister.H:200
void computeEffectivePotentialPhi(ablastr::fields::MultiLevelScalarField const &rho, ablastr::fields::MultiLevelScalarField const &phi, amrex::MultiFab const &sigma, amrex::Real relative_tolerance, amrex::Real absolute_tolerance, int max_iters, int verbosity, amrex::Vector< amrex::Geometry > const &geom, amrex::Vector< amrex::DistributionMapping > const &dmap, amrex::Vector< amrex::BoxArray > const &grids, utils::enums::GridType grid_type, bool is_solver_igf_on_lev0, bool eb_enabled=false, bool do_single_precision_comms=false, std::optional< amrex::Vector< amrex::IntVect > > rel_ref_ratio=std::nullopt, T_PostPhiCalculationFunctor post_phi_calculation=std::nullopt, T_BoundaryHandler const boundary_handler=std::nullopt, std::optional< amrex::Real const > current_time=std::nullopt, std::optional< amrex::Vector< T_FArrayBoxFactory const * > > eb_farray_box_factory=std::nullopt)
Definition EffectivePotentialPoissonSolver.H:103
GridType
Definition Enums.H:23
@ Collocated
Definition Enums.H:23
Vector< const T * > GetVecOfConstPtrs(const Vector< T > &a)
MLMGT< MultiFab > MLMG
IntVectND< 3 > IntVect
std::array< T, N > Array