200 std::array<amrex::Real, 3>
const beta,
201 amrex::Real relative_tolerance,
202 amrex::Real absolute_tolerance,
209 bool is_solver_igf_on_lev0,
210 [[maybe_unused]]
bool const is_igf_2d,
211 bool eb_enabled =
false,
212 bool do_single_precision_comms =
false,
214 [[maybe_unused]] T_PostPhiCalculationFunctor post_phi_calculation = std::nullopt,
215 [[maybe_unused]] T_BoundaryHandler
const boundary_handler = std::nullopt,
216 [[maybe_unused]] std::optional<amrex::Real const> current_time = std::nullopt,
220 using namespace amrex::literals;
224 auto const finest_level =
static_cast<int>(rho.
size() - 1);
226 if (!rel_ref_ratio.has_value()) {
228 "rel_ref_ratio must be set if mesh-refinement is used");
232#if !defined(AMREX_USE_EB)
234 "Embedded boundary solve requested but not compiled in");
237#if !defined(ABLASTR_USE_FFT)
239 "Must compile with FFT support to use the IGF solver!");
242#if !defined(WARPX_DIM_3D)
244 "The FFT Poisson solver is currently only implemented for 3D!");
249#if defined(WARPX_DIM_1D_Z)
251#elif defined(WARPX_DIM_XZ) || defined(WARPX_DIM_RZ)
252 {{ beta[0], beta[2] }};
253#elif defined(WARPX_DIM_RCYLINDER) || defined(WARPX_DIM_RSPHERE)
256 {{ beta[0], beta[1], beta[2] }};
260 std::all_of(beta_solver.begin(), beta_solver.end(),
261 [](
const auto b){return (b<1.0_rt);}),
262 "Components of beta_solver must be < 1.");
270 for (
int lev=0; lev<=finest_level; lev++) {
272 {
AMREX_D_DECL(geom[lev].CellSize(0)/std::sqrt(1._rt-beta_solver[0]*beta_solver[0]),
273 geom[lev].CellSize(1)/std::sqrt(1._rt-beta_solver[1]*beta_solver[1]),
274 geom[lev].CellSize(2)/std::sqrt(1._rt-beta_solver[2]*beta_solver[2]))};
276#if (defined(ABLASTR_USE_FFT) && defined(WARPX_DIM_3D))
278 if(is_solver_igf_on_lev0 && lev==0){
279 if ( max_norm_b == 0 ) {
292 constexpr bool is_rz =
true;
294 constexpr bool is_rz =
false;
297 if (!eb_enabled && !is_rz) {
299 int max_semicoarsening_level = 0;
300 int semicoarsening_direction = -1;
301 const auto min_dir =
static_cast<int>(std::distance(dx_scaled.begin(),
302 std::min_element(dx_scaled.begin(), dx_scaled.end())));
303 const auto max_dir =
static_cast<int>(std::distance(dx_scaled.begin(),
304 std::max_element(dx_scaled.begin(), dx_scaled.end())));
305 if (dx_scaled[max_dir] > dx_scaled[min_dir]) {
306 semicoarsening_direction = max_dir;
307 max_semicoarsening_level =
static_cast<int>(std::log2(dx_scaled[max_dir] / dx_scaled[min_dir]));
309 if (max_semicoarsening_level > 0) {
316 std::unique_ptr<amrex::MLNodeLinOp> linop;
317 if (eb_enabled || is_rz) {
321 auto linop_nodelap = std::make_unique<amrex::MLEBNodeFDLaplacian>();
323#if defined(AMREX_USE_EB)
324 if constexpr(std::is_same_v<void, T_FArrayBoxFactory>) {
325 throw std::runtime_error(
"EB requested by eb_farray_box_factory not provided!");
327 linop_nodelap->define(
339 linop_nodelap->define(
350#if defined(WARPX_DIM_RZ)
351 linop_nodelap->setRZ(
true);
352 linop_nodelap->setSigma({0._rt, 1._rt-beta_solver[1]*beta_solver[1]});
355 1._rt-beta_solver[0]*beta_solver[0],
356 1._rt-beta_solver[1]*beta_solver[1],
357 1._rt-beta_solver[2]*beta_solver[2])});
359#if defined(AMREX_USE_EB)
361 if constexpr (!std::is_same_v<T_BoundaryHandler, std::nullopt_t>) {
364 if (boundary_handler.phi_EB_only_t) {
365 linop_nodelap->setEBDirichlet(boundary_handler.potential_eb_t(current_time.value()));
367 linop_nodelap->setEBDirichlet(boundary_handler.getPhiEB(current_time.value()));
372 "EB Poisson solver enabled but no 'boundary_handler' passed!");
376 linop = std::move(linop_nodelap);
380 auto linop_tenslap = std::make_unique<amrex::MLNodeTensorLaplacian>(
386 linop_tenslap->setBeta(beta_solver);
387 linop = std::move(linop_tenslap);
391 if constexpr (std::is_same_v<T_BoundaryHandler, std::nullopt_t>) {
393 amrex::LinOpBCType::Dirichlet,
394 amrex::LinOpBCType::Dirichlet,
395 amrex::LinOpBCType::Dirichlet
398 linop->setDomainBC(lobc, hibc);
400 linop->setDomainBC(boundary_handler.lobc, boundary_handler.hibc);
407 mlmg.
setConvergenceNormType((max_norm_b > 0) ? amrex::MLMGNormType::bnorm : amrex::MLMGNormType::greater);
417 mlmg.
solve( {phi[lev]}, {rho[lev]},
418 relative_tolerance, absolute_tolerance );
421 const int ncomp = linop->getNComp();
428 if (lev < finest_level) {
432 do_single_precision_comms,
439 if constexpr (!std::is_same_v<T_PostPhiCalculationFunctor, std::nullopt_t>) {
440 if (post_phi_calculation.has_value()) {
441 post_phi_calculation.value()(mlmg, lev);
#define ABLASTR_ALWAYS_ASSERT_WITH_MESSAGE(EX, MSG)
Definition TextMsg.H:75
void computePhi(ablastr::fields::MultiLevelScalarField const &rho, ablastr::fields::MultiLevelScalarField const &phi, std::array< amrex::Real, 3 > const beta, 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 const is_igf_2d, 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 PoissonSolver.H:197
void ParallelCopy(amrex::MultiFab &dst, const amrex::MultiFab &src, int src_comp, int dst_comp, int num_comp, const amrex::IntVect &src_nghost, const amrex::IntVect &dst_nghost, bool do_single_precision_comms, const amrex::Periodicity &period, amrex::FabArrayBase::CpOp op)
Definition Communication.cpp:28