diff --git a/Docs/source/usage/parameters.rst b/Docs/source/usage/parameters.rst index c1df197075b..b272aa27d23 100644 --- a/Docs/source/usage/parameters.rst +++ b/Docs/source/usage/parameters.rst @@ -241,6 +241,8 @@ Overall simulation parameters non-zero value is specified by the user via ``warpx.self_fields_absolute_tolerance``). + * ``gmres``: Poisson's equation is solved using an MLMG-preconditioned GMRES solver. + * ``fft``: Poisson's equation is solved using an Integrated Green Function method (which requires FFT calculations). See these references for more details :cite:t:`param-QiangPhysRevSTAB2006`, :cite:t:`param-QiangPhysRevSTAB2006err`. It only works in 3D and it requires the compilation flag ``-DWarpX_FFT=ON``. diff --git a/Source/FieldSolver/ElectrostaticSolvers/PoissonBoundaryHandler.cpp b/Source/FieldSolver/ElectrostaticSolvers/PoissonBoundaryHandler.cpp index efcdac3404c..4f50f043848 100644 --- a/Source/FieldSolver/ElectrostaticSolvers/PoissonBoundaryHandler.cpp +++ b/Source/FieldSolver/ElectrostaticSolvers/PoissonBoundaryHandler.cpp @@ -81,7 +81,7 @@ void PoissonBoundaryHandler::DefinePhiBCs (const amrex::Geometry& geom) amrex::ignore_unused(geom); #endif for (int idim=dim_start; idim #endif +#include +#include "WarpX.H" #include #include @@ -414,8 +416,14 @@ computePhi ( } // Solve Poisson equation at lev - mlmg.solve( {phi[lev]}, {rho[lev]}, - relative_tolerance, absolute_tolerance ); + if (WarpX::poisson_solver_id == PoissonSolverAlgo::Multigrid) { + mlmg.solve( {phi[lev]}, {rho[lev]}, + relative_tolerance, absolute_tolerance ); + } else { + amrex::GMRESMLMG gmsolve(mlmg); + gmsolve.solve( *phi[lev], *rho[lev], relative_tolerance, absolute_tolerance ); + linop->postSolve({phi[lev]}); + } const amrex::IntVect& refratio = rel_ref_ratio.value()[lev]; const int ncomp = linop->getNComp(); @@ -435,12 +443,47 @@ computePhi ( ng); } - // Run additional operations, such as calculation of the E field for embedded boundaries - if constexpr (!std::is_same_v) { - if (post_phi_calculation.has_value()) { - post_phi_calculation.value()(mlmg, lev); + if (WarpX::poisson_solver_id == PoissonSolverAlgo::Multigrid) { + // Run additional operations, such as calculation of the E field for embedded boundaries + if constexpr (!std::is_same_v) { + if (post_phi_calculation.has_value()) { + post_phi_calculation.value()(mlmg, lev); + } } } + + if (WarpX::poisson_solver_id == PoissonSolverAlgo::GMRES && eb_enabled) { + + // create an alieas to the WarpX Efield + auto & warpx = WarpX::GetInstance(); + + amrex::Vector< amrex::Array > e_field; + e_field.push_back( +#if defined(WARPX_DIM_1D_Z) + amrex::Array{ + warpx.m_fields.get(warpx::fields::FieldType::Efield_fp, Direction{2}, lev) + } +#elif defined(WARPX_DIM_XZ) || defined(WARPX_DIM_RZ) + amrex::Array{ + warpx.m_fields.get(warpx::fields::FieldType::Efield_fp, Direction{0}, lev), + warpx.m_fields.get(warpx::fields::FieldType::Efield_fp, Direction{2}, lev) + } +#elif defined(WARPX_DIM_3D) + amrex::Array{ + warpx.m_fields.get(warpx::fields::FieldType::Efield_fp, Direction{0}, lev), + warpx.m_fields.get(warpx::fields::FieldType::Efield_fp, Direction{1}, lev), + warpx.m_fields.get(warpx::fields::FieldType::Efield_fp, Direction{2}, lev) + } +#endif + ); + + // compute E = grad(phi) + linop->compGrad(lev, e_field[lev], *phi[lev], amrex::MLLinOp::Location::CellCenter); + for(int dir=0; dirmult(-1.); + } + } + rho[lev]->mult(-ablastr::constant::SI::epsilon_0); // Multiply rho by epsilon again } // loop over lev(els)