Skip to content

Commit c1cd7ab

Browse files
debogEZoniRemiLeheJustinRayAngusWeiqunZhang
authored
Implicit Field Solve Preconditioner based on Curl-Curl Operator (#5286)
Implemented a preconditioner for the implicit E-field solve using the AMReX curl-curl operator and the MLMG solver. + Introduced a `Preconditioner` base class that defines the action of a preconditioner for the JFNK algorithm. + Implemented the `CurlCurlMLMGPC` that uses the multigrid solution for the curl-curl operator (implemented in `AMReX`) to precondition the E-field JFNK solve. Other changes needed for this: + Partially implemented a mapping between WarpX field boundary types and AMReX's linear operator boundary types. + Added some functionalities to `ImplicitSolver` class that allows preconditioners to access `WarpX` info (like `Geometry`, boundaries, etc). Some premilinary wall times for: ``` Test: inputs_vandb_2d Grid: 160 X 160 dt: 0.125/wpe = 2.22e-18 (dt_CFL = 7.84e-19 s, CFL = 2.83) Time iterations: 20 Solver parameters: newton.max_iterations = 10 newton.relative_tolerance = 1.0e-12 newton.absolute_tolerance = 0.0 gmres.max_iterations = 1000 gmres.relative_tolerance = 1.0e-8 gmres.absolute_tolerance = 0.0 Avg GMRES iterations: ~3 (wPC), ~27 (noPC) ``` with `32^2` particles per cell: ``` Lassen (MPI + CUDA) ------------------- Box GPU Walltime (s) wPC noPC 1 1 2324.7 15004.1 4 1 2306.8 14356.8 4 4 758.9 3647.3 Dane (MPI + OMP) ---------------- Box CPU Threads Walltime (s) wPC noPC 1 1 1 6709.3 43200.0* 1 1 2 3279.1 22296.1 1 1 4 1696.3 11613.2 1 1 8 1085.0 6911.4 1 1 16 724.3 4729.0 4 1 1 5525.9 33288.8 16 1 1 4419.4 28467.8 4 4 1 1324.4 9121.1 16 16 1 524.9 3658.8 * 43200.0 seconds is 12 hours (max job duration on Dane); the simulation was almost done (started the 20th step). ``` with `10^2` particles per cell: ``` Lassen (MPI + CUDA) ------------------- Box GPU Walltime (s) wPC noPC 1 1 365.0 1443.5 4 1 254.1 927.8 4 4 133.1 301.5 Dane (MPI + OMP) ---------------- Box CPU Threads Walltime (s) wPC noPC 1 1 1 440.8 2360.5 1 1 2 241.7 1175.8 1 1 4 129.3 727.0 1 1 8 94.2 407.5 1 1 16 74.3 245.6 4 1 1 393.3 1932.5 16 1 1 337.6 1618.7 4 4 1 92.2 479.1 16 16 1 58.1 192.6 ``` --------- Co-authored-by: Edoardo Zoni <[email protected]> Co-authored-by: Remi Lehe <[email protected]> Co-authored-by: Justin Angus <[email protected]> Co-authored-by: Weiqun Zhang <[email protected]>
1 parent 78cf034 commit c1cd7ab

File tree

13 files changed

+615
-24
lines changed

13 files changed

+615
-24
lines changed

Source/FieldSolver/ImplicitSolvers/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ foreach(D IN LISTS WarpX_DIMS)
22
warpx_set_suffix_dims(SD ${D})
33
target_sources(lib_${SD}
44
PRIVATE
5+
ImplicitSolver.cpp
56
SemiImplicitEM.cpp
67
ThetaImplicitEM.cpp
78
WarpXImplicitOps.cpp

Source/FieldSolver/ImplicitSolvers/ImplicitSolver.H

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright 2024 Justin Angus
1+
/* Copyright 2024 Justin Angus, Debojyoti Ghosh
22
*
33
* This file is part of WarpX.
44
*
@@ -9,9 +9,11 @@
99

1010
#include "FieldSolver/ImplicitSolvers/WarpXSolverVec.H"
1111
#include "NonlinearSolvers/NonlinearSolverLibrary.H"
12+
#include "Utils/WarpXAlgorithmSelection.H"
1213

1314
#include <AMReX_Array.H>
1415
#include <AMReX_REAL.H>
16+
#include <AMReX_LO_BCTYPES.H>
1517

1618
/**
1719
* \brief Base class for implicit time solvers. The base functions are those
@@ -85,6 +87,16 @@ public:
8587
int a_nl_iter,
8688
bool a_from_jacobian ) = 0;
8789

90+
[[nodiscard]] virtual amrex::Real theta () const { return 1.0; }
91+
92+
[[nodiscard]] int numAMRLevels () const { return m_num_amr_levels; }
93+
94+
[[nodiscard]] const amrex::Geometry& GetGeometry (int) const;
95+
[[nodiscard]] const amrex::Array<FieldBoundaryType,AMREX_SPACEDIM>& GetFieldBoundaryLo () const;
96+
[[nodiscard]] const amrex::Array<FieldBoundaryType,AMREX_SPACEDIM>& GetFieldBoundaryHi () const;
97+
[[nodiscard]] amrex::Array<amrex::LinOpBCType,AMREX_SPACEDIM> GetLinOpBCLo () const;
98+
[[nodiscard]] amrex::Array<amrex::LinOpBCType,AMREX_SPACEDIM> GetLinOpBCHi () const;
99+
88100
protected:
89101

90102
/**
@@ -94,6 +106,11 @@ protected:
94106

95107
bool m_is_defined = false;
96108

109+
/**
110+
* \brief Number of AMR levels
111+
*/
112+
int m_num_amr_levels = 1;
113+
97114
/**
98115
* \brief Nonlinear solver type and object
99116
*/
@@ -140,6 +157,11 @@ protected:
140157

141158
}
142159

160+
/**
161+
* \brief Convert from WarpX FieldBoundaryType to amrex::LinOpBCType
162+
*/
163+
[[nodiscard]] amrex::Array<amrex::LinOpBCType,AMREX_SPACEDIM> convertFieldBCToLinOpBC ( const amrex::Array<FieldBoundaryType,AMREX_SPACEDIM>& ) const;
164+
143165
};
144166

145167
#endif
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#include "ImplicitSolver.H"
2+
#include "WarpX.H"
3+
4+
using namespace amrex;
5+
6+
const Geometry& ImplicitSolver::GetGeometry (const int a_lvl) const
7+
{
8+
AMREX_ASSERT((a_lvl >= 0) && (a_lvl < m_num_amr_levels));
9+
return m_WarpX->Geom(a_lvl);
10+
}
11+
12+
const Array<FieldBoundaryType,AMREX_SPACEDIM>& ImplicitSolver::GetFieldBoundaryLo () const
13+
{
14+
return m_WarpX->GetFieldBoundaryLo();
15+
}
16+
17+
const Array<FieldBoundaryType,AMREX_SPACEDIM>& ImplicitSolver::GetFieldBoundaryHi () const
18+
{
19+
return m_WarpX->GetFieldBoundaryHi();
20+
}
21+
22+
Array<LinOpBCType,AMREX_SPACEDIM> ImplicitSolver::GetLinOpBCLo () const
23+
{
24+
return convertFieldBCToLinOpBC(m_WarpX->GetFieldBoundaryLo());
25+
}
26+
27+
Array<LinOpBCType,AMREX_SPACEDIM> ImplicitSolver::GetLinOpBCHi () const
28+
{
29+
return convertFieldBCToLinOpBC(m_WarpX->GetFieldBoundaryHi());
30+
}
31+
32+
Array<LinOpBCType,AMREX_SPACEDIM> ImplicitSolver::convertFieldBCToLinOpBC (const Array<FieldBoundaryType,AMREX_SPACEDIM>& a_fbc) const
33+
{
34+
Array<LinOpBCType, AMREX_SPACEDIM> lbc;
35+
for (auto& bc : lbc) { bc = LinOpBCType::interior; }
36+
for (int i = 0; i < AMREX_SPACEDIM; i++) {
37+
if (a_fbc[i] == FieldBoundaryType::PML) {
38+
WARPX_ABORT_WITH_MESSAGE("LinOpBCType not set for this FieldBoundaryType");
39+
} else if (a_fbc[i] == FieldBoundaryType::Periodic) {
40+
lbc[i] = LinOpBCType::Periodic;
41+
} else if (a_fbc[i] == FieldBoundaryType::PEC) {
42+
WARPX_ABORT_WITH_MESSAGE("LinOpBCType not set for this FieldBoundaryType");
43+
} else if (a_fbc[i] == FieldBoundaryType::PMC) {
44+
WARPX_ABORT_WITH_MESSAGE("LinOpBCType not set for this FieldBoundaryType");
45+
} else if (a_fbc[i] == FieldBoundaryType::Damped) {
46+
WARPX_ABORT_WITH_MESSAGE("LinOpBCType not set for this FieldBoundaryType");
47+
} else if (a_fbc[i] == FieldBoundaryType::Absorbing_SilverMueller) {
48+
WARPX_ABORT_WITH_MESSAGE("LinOpBCType not set for this FieldBoundaryType");
49+
} else if (a_fbc[i] == FieldBoundaryType::Neumann) {
50+
lbc[i] = LinOpBCType::Neumann;
51+
} else if (a_fbc[i] == FieldBoundaryType::None) {
52+
WARPX_ABORT_WITH_MESSAGE("LinOpBCType not set for this FieldBoundaryType");
53+
} else if (a_fbc[i] == FieldBoundaryType::Open) {
54+
WARPX_ABORT_WITH_MESSAGE("LinOpBCType not set for this FieldBoundaryType");
55+
} else {
56+
WARPX_ABORT_WITH_MESSAGE("Invalid value for FieldBoundaryType");
57+
}
58+
}
59+
return lbc;
60+
}

Source/FieldSolver/ImplicitSolvers/Make.package

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
CEXE_sources += ImplicitSolver.cpp
12
CEXE_sources += SemiImplicitEM.cpp
23
CEXE_sources += ThetaImplicitEM.cpp
34
CEXE_sources += WarpXImplicitOps.cpp

Source/FieldSolver/ImplicitSolvers/ThetaImplicitEM.H

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,12 @@
88
#define THETA_IMPLICIT_EM_H_
99

1010
#include "FieldSolver/ImplicitSolvers/WarpXSolverVec.H"
11+
#include "ImplicitSolver.H"
1112

1213
#include <AMReX_Array.H>
1314
#include <AMReX_MultiFab.H>
1415
#include <AMReX_REAL.H>
1516

16-
#include "ImplicitSolver.H"
17-
1817
/** @file
1918
* Theta-implicit electromagnetic time solver class. This is a fully implicit
2019
* algorithm where both the fields and particles are treated implicitly.
@@ -79,7 +78,7 @@ public:
7978
int a_nl_iter,
8079
bool a_from_jacobian ) override;
8180

82-
[[nodiscard]] amrex::Real theta () const { return m_theta; }
81+
[[nodiscard]] amrex::Real theta () const override { return m_theta; }
8382

8483
private:
8584

Source/FieldSolver/ImplicitSolvers/ThetaImplicitEM.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@ void ThetaImplicitEM::Define ( WarpX* const a_WarpX )
1919

2020
// Retain a pointer back to main WarpX class
2121
m_WarpX = a_WarpX;
22+
m_num_amr_levels = 1;
2223

2324
// Define E and Eold vectors
2425
m_E.Define( m_WarpX, "Efield_fp" );
2526
m_Eold.Define( m_E );
2627

2728
// Define B_old MultiFabs
2829
using ablastr::fields::Direction;
29-
const int num_levels = 1;
30-
for (int lev = 0; lev < num_levels; ++lev) {
30+
for (int lev = 0; lev < m_num_amr_levels; ++lev) {
3131
const auto& ba_Bx = m_WarpX->m_fields.get(FieldType::Bfield_fp, Direction{0}, lev)->boxArray();
3232
const auto& ba_By = m_WarpX->m_fields.get(FieldType::Bfield_fp, Direction{1}, lev)->boxArray();
3333
const auto& ba_Bz = m_WarpX->m_fields.get(FieldType::Bfield_fp, Direction{2}, lev)->boxArray();

Source/FieldSolver/ImplicitSolvers/WarpXSolverVec.H

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ public:
7575
void Define ( const WarpXSolverVec& a_solver_vec )
7676
{
7777
assertIsDefined( a_solver_vec );
78+
m_num_amr_levels = a_solver_vec.m_num_amr_levels;
7879
Define( WarpXSolverVec::m_WarpX,
7980
a_solver_vec.getVectorType(),
8081
a_solver_vec.getScalarType() );
@@ -300,7 +301,7 @@ private:
300301
std::string m_scalar_type_name = "none";
301302

302303
static constexpr int m_ncomp = 1;
303-
static constexpr int m_num_amr_levels = 1;
304+
int m_num_amr_levels = 1;
304305

305306
inline static bool m_warpx_ptr_defined = false;
306307
inline static WarpX* m_WarpX = nullptr;

Source/FieldSolver/ImplicitSolvers/WarpXSolverVec.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ void WarpXSolverVec::Define ( WarpX* a_WarpX,
3434
m_warpx_ptr_defined = true;
3535
}
3636

37+
m_num_amr_levels = 1;
38+
3739
m_vector_type_name = a_vector_type_name;
3840
m_scalar_type_name = a_scalar_type_name;
3941

0 commit comments

Comments
 (0)