OPAL (Object Oriented Parallel Accelerator Library)  2.2.0
OPAL
FMGPoissonSolver.cpp
Go to the documentation of this file.
1 #include "FMGPoissonSolver.h"
2 
4 
5 #include <AMReX_ParmParse.H>
6 #include <AMReX_Interpolater.H>
7 
8 #include <cassert>
9 
11  : AmrPoissonSolver<AmrBoxLib>(itsAmrObject_p),
12  reltol_m(1.0e-15),
13  abstol_m(1.0e-9)
14 {
15  // Dirichlet boundary conditions are default
16  for (int d = 0; d < AMREX_SPACEDIM; ++d) {
17  bc_m[2 * d] = MGT_BC_DIR;
18  bc_m[2 * d + 1] = MGT_BC_DIR;
19  }
20 
21  this->initParameters_m();
22 }
23 
27  unsigned short baseLevel,
28  unsigned short finestLevel,
29  bool prevAsGuess)
30 {
31  const GeomContainer_t& geom = itsAmrObject_mp->Geom();
32 
33  if (AmrGeometry_t::isAllPeriodic()) {
34  for (int d = 0; d < AMREX_SPACEDIM; ++d) {
35  bc_m[2 * d] = MGT_BC_PER;
36  bc_m[2 * d + 1] = MGT_BC_PER;
37  }
38  } else if ( AmrGeometry_t::isAnyPeriodic() ) {
39  for (int d = 0; d < AMREX_SPACEDIM; ++d) {
40  if ( AmrGeometry_t::isPeriodic(d) ) {
41  bc_m[2 * d] = MGT_BC_PER;
42  bc_m[2 * d + 1] = MGT_BC_PER;
43  }
44  }
45  }
46 
47  amrex::Vector< AmrScalarFieldContainer_t > grad_phi_edge(rho.size());
48 
49  amrex::Vector< AmrField_t > tmp(rho.size());
50 
51  assert(baseLevel <= finestLevel);
52  assert(finestLevel < (int)rho.size());
53 
54  for (int lev = baseLevel; lev <= finestLevel ; ++lev) {
55  const AmrProcMap_t& dmap = rho[lev]->DistributionMap();
56  grad_phi_edge[lev].resize(AMREX_SPACEDIM);
57  tmp[lev].define(rho[lev]->boxArray(), dmap, AMREX_SPACEDIM, 1);
58 
59  for (int n = 0; n < AMREX_SPACEDIM; ++n) {
60  AmrGrid_t ba = rho[lev]->boxArray();
61  grad_phi_edge[lev][n].reset(new AmrField_t(ba.surroundingNodes(n), dmap, 1, 1));
62  grad_phi_edge[lev][n]->setVal(0.0, 1);
63  }
64  }
65 
66  for (int i = 0; i <= finestLevel; ++i) {
67  phi[i]->setVal(0.0, 1);
68  tmp[i].setVal(0.0, 1);
69  }
70 
71  double residNorm = this->solveWithF90_m(amrex::GetVecOfPtrs(rho),
72  amrex::GetVecOfPtrs(phi),
73  amrex::GetVecOfVecOfPtrs(grad_phi_edge),
74  geom,
75  baseLevel,
76  finestLevel);
77 
78  if ( residNorm > abstol_m ) {
79  std::stringstream ss;
80  ss << "Residual norm: " << std::setprecision(16) << residNorm
81  << " > " << abstol_m << " (absolute tolerance)";
82  throw OpalException("FMGPoissonSolver::solve()",
83  "Multigrid solver did not converge. " + ss.str());
84  }
85 
86  for (int lev = baseLevel; lev <= finestLevel; ++lev) {
87  amrex::average_face_to_cellcenter(tmp[lev],
88  amrex::GetVecOfConstPtrs(grad_phi_edge[lev]),
89  geom[lev]);
90 
91  for (int j = 0; j < AMREX_SPACEDIM; ++j) {
92  efield[lev][j]->setVal(0.0, 1);
93  amr::AmrField_t::Copy(*(efield[lev][j].get()),
94  tmp[lev], j, 0, 1, 1);
95  efield[lev][j]->FillBoundary(0, 1, geom[lev].periodicity());
96  // we need also minus sign due to \vec{E} = - \nabla\phi
97  efield[lev][j]->mult(-1.0, 0, 1);
98  }
99  }
100 }
101 
102 
103 double FMGPoissonSolver::getXRangeMin(unsigned short level) {
104  return itsAmrObject_mp->Geom(level).ProbLo(0);
105 }
106 
107 
108 double FMGPoissonSolver::getXRangeMax(unsigned short level) {
109  return itsAmrObject_mp->Geom(level).ProbHi(0);
110 }
111 
112 
113 double FMGPoissonSolver::getYRangeMin(unsigned short level) {
114  return itsAmrObject_mp->Geom(level).ProbLo(1);
115 }
116 
117 
118 double FMGPoissonSolver::getYRangeMax(unsigned short level) {
119  return itsAmrObject_mp->Geom(level).ProbHi(1);
120 }
121 
122 
123 double FMGPoissonSolver::getZRangeMin(unsigned short level) {
124  return itsAmrObject_mp->Geom(level).ProbLo(2);
125 }
126 
127 
128 double FMGPoissonSolver::getZRangeMax(unsigned short level) {
129  return itsAmrObject_mp->Geom(level).ProbHi(2);
130 }
131 
132 
134  os << "* ************* F M G P o i s s o n S o l v e r ************************************ " << endl
135  << "* relative tolerance " << reltol_m << '\n'
136  << "* absolute tolerance " << abstol_m << '\n' << endl
137  << "* ******************************************************************** " << endl;
138  return os;
139 }
140 
141 
143  /* The information about the parameters is copied from the
144  * BoxLib documentation chapter 5 on linear solvers and from
145  * the code itself.
146  *
147  * Some paramters that have to be given to the solver using
148  * AMReX_ParmParse.
149  * "doc" tells how the variable is called in
150  * - amrex/Src/LinearSolvers/F_MG/cc_mg_cpp.f90
151  * - amrex/Src/LinearSolvers/F_MG/mg_tower.f90 (conains defaults)
152  * - amrex/Src/LinearSolvers/C_to_F_MG/AMReX_MGT_Solver.cpp
153  *
154  */
155 
156  amrex::ParmParse pp_mg("mg");
157 
158  // maximum number of multigrid cycles (doc: max_iter)
159  pp_mg.add("maxiter", 200);
160 
161  // maximum number of iterations for the bottom solver (doc: bottom_max_iter)
162  pp_mg.add("maxiter_b", 200);
163 
164  // number of smoothings at each level on the way DOWN the V-cycle (doc: nu1)
165  pp_mg.add("nu_1", 2);
166 
167  // number of smoothings at each level on the way UP the V-cycle (doc: nu2)
168  pp_mg.add("nu_2", 2);
169 
170  // number of smoothing before and after the bottom solver (doc: nub)
171  pp_mg.add("nu_b", 0);
172 
173  // number of smoothing ... ?
174  pp_mg.add("nu_f", 8);
175 
176  // verbosity of the multigrid solver. Higher numbers give more verbosity (doc: verbose)
177  pp_mg.add("v" , 0);
178 
179 
180  // see amrex/Src/LinearSolvers/C_to_F_MG/AMReX_MGT_Solver.cpp
181  pp_mg.add("usecg", 1);
182 
183  // bottom_solver_eps, see amrex/Src/LinearSolvers/C_to_F_MG/AMReX_MGT_Solver.cpp
184  pp_mg.add("rtol_b", 0.0001);
185 
186  // see amrex/Src/LinearSolvers/C_to_F_MG/AMReX_MGT_Solver.cpp
187  pp_mg.add("cg_solver", 1);
188 
189  // maximum number of levels (max_nlevel)
190  pp_mg.add("numLevelsMAX", 1024);
191 
192  /* MG_SMOOTHER_GS_RB = 1 (red-black Gauss-Seidel)
193  * MG_SMOOTHER_JACOBI = 2 (Jacobi)
194  * MG_SMOOTHER_MINION_CROSS = 5
195  * MG_SMOOTHER_MINION_FULL = 6
196  * MG_SMOOTHER_EFF_RB = 7
197  */
198  pp_mg.add("smoother", 1);
199 
200  /* The type of multigrid to do
201  *
202  * MG_FCycle = 1 (F, full multigrid)
203  * MG_WCycle = 2 (W-cycles)
204  * MG_VCycle = 3 (V-cycles)
205  * MG_FVCycle = 4 (F + V cycles)
206  */
207  pp_mg.add("cycle_type", 1);
208 
209  /* the type of bottom solver to use
210  *
211  * BiCG: biconjugate gradient stabilized (bottom_solver = 1)
212  * CG: conjugate gradient method (bottom_solver = 2)
213  * CABiCG: (bottom_solver = 3)
214  * special: bottom_solver = 4
215  *
216  * The special bottom solver extends the range of the multigrid coarsening
217  * by aggregating coarse grids on the original mesh together and further coarsening.
218  *
219  * if use_cg == 1 && cg_solver == 0 --> CG
220  * if use_cg == 1 && cg_solver == 1 --> BiCG
221  * if use_cg == 1 && cg_solver == 2 --> CABiCG
222  * if use_cg == 0 --> CABiCG
223  */
224  pp_mg.add("bottom_solver", 1);
225 
226  // verbosity of the bottom solver. Higher numbers give more verbosity (doc: cg_verbose)
227  amrex::ParmParse pp_cg("cg");
228  pp_cg.add("v", 0);
229 
230 
231  /* Additional parameters that can't be set by ParmParse:
232  *
233  * - max_bottom_nlevel = 3 (additional coarsening if you use bottom_solver == 4)
234  * - min_width = 2 (minimum size of grid at coarsest multigrid level)
235  * - max_L0_growth = -1
236  */
237  amrex::MGT_Solver::def_min_width = 2;
238  amrex::MGT_Solver::def_max_L0_growth = -1.0;
239 }
240 
241 
243  const AmrFieldContainer_pt& phi,
244  const amrex::Vector< AmrFieldContainer_pt > & grad_phi_edge,
245  const GeomContainer_t& geom,
246  int baseLevel,
247  int finestLevel)
248 {
249  int nlevs = finestLevel - baseLevel + 1;
250 
251  GeomContainer_t geom_p(nlevs);
252  AmrFieldContainer_pt rho_p(nlevs);
253  AmrFieldContainer_pt phi_p(nlevs);
254 
255  for (int ilev = 0; ilev < nlevs; ++ilev) {
256  geom_p[ilev] = geom[ilev + baseLevel];
257  rho_p[ilev] = rho[ilev + baseLevel];
258  phi_p[ilev] = phi[ilev + baseLevel];
259  }
260 
261  //FIXME Refinement ratio
262  amrex::IntVect crse_ratio = (baseLevel == 0) ?
263  amrex::IntVect::TheZeroVector() : itsAmrObject_mp->refRatio(0);
264 
265  amrex::FMultiGrid fmg(geom_p, baseLevel, crse_ratio);
266 
267  if (baseLevel == 0)
268  fmg.set_bc(bc_m, *phi_p[baseLevel]);
269  else
270  fmg.set_bc(bc_m, *phi_p[baseLevel-1], *phi_p[baseLevel]);
271 
272  /* (alpha * a - beta * (del dot b grad)) phi = rho
273  * (b = 1)
274  *
275  * The function call set_const_gravity_coeffs() sets alpha = 0.0
276  * and beta = -1 (in MGT_Solver::set_const_gravity_coeffs)
277  *
278  * --> (del dot grad) phi = rho
279  */
280  fmg.set_const_gravity_coeffs();
281 
282  // order of approximation at Dirichlet boundaries
283  fmg.set_maxorder(3);
284 
285  int always_use_bnorm = 0;
286  int need_grad_phi = 1;
287 
288  double residNorm = fmg.solve(phi_p, rho_p, reltol_m, abstol_m, always_use_bnorm, need_grad_phi);
289 
290  for (int ilev = 0; ilev < nlevs; ++ilev) {
291  int amr_level = ilev + baseLevel;
292  fmg.get_fluxes(grad_phi_edge[amr_level], ilev);
293  }
294 
295  return residNorm;
296 }
297 
298 
299 /*
300 void FMGPoissonSolver::interpolate_m(AmrScalarFieldContainer_t& phi,
301  const GeomContainer_t& geom,
302  double l0norm,
303  int finestLevel)
304 {
305  amrex::PhysBCFunct cphysbc, fphysbc;
306  int lo_bc[] = {INT_DIR, INT_DIR, INT_DIR}; // periodic boundaries
307  int hi_bc[] = {INT_DIR, INT_DIR, INT_DIR};
308  amrex::Vector<amrex::BCRec> bcs(1, amrex::BCRec(lo_bc, hi_bc));
309  amrex::PCInterp mapper;
310 
311  std::unique_ptr<AmrField_t> tmp;
312 
313  for (int lev = 1; lev <= finestLevel; ++lev) {
314  const AmrGrid_t& ba = phi[lev]->boxArray();
315  const AmrProcMap_t& dm = phi[lev]->DistributionMap();
316  tmp.reset(new AmrField_t(ba, dm, 1, 0));
317  tmp->setVal(0.0);
318 
319  amrex::InterpFromCoarseLevel(*tmp, 0.0, *phi[lev-1],
320  0, 0, 1, geom[lev-1], geom[lev],
321  cphysbc, fphysbc,
322  itsAmrObject_mp->refRatio(lev-1),
323  &mapper, bcs);
324  phi[lev]->plus(*tmp, 0, 1, 0);
325  phi[lev-1]->mult(l0norm, 0, 1);
326  }
327 
328  phi[finestLevel]->mult(l0norm, 0, 1);
329 }
330 */
int bc_m[2 *AMREX_SPACEDIM]
Boundary conditions.
AmrBoxLib::AmrVectorFieldContainer_t AmrVectorFieldContainer_t
double abstol_m
Absolute tolerance for solver.
amrex::Vector< AmrBoxLib::AmrField_t * > AmrFieldContainer_pt
constexpr double e
The value of .
Definition: Physics.h:40
double getXRangeMax(unsigned short level=0)
AmrBoxLib::AmrGeomContainer_t GeomContainer_t
The base class for all OPAL exceptions.
Definition: OpalException.h:28
Inform & print(Inform &os) const
AmrBoxLib::AmrScalarFieldContainer_t AmrScalarFieldContainer_t
double solveWithF90_m(const AmrFieldContainer_pt &rho, const AmrFieldContainer_pt &phi, const amrex::Vector< AmrFieldContainer_pt > &grad_phi_edge, const GeomContainer_t &geom, int baseLevel, int finestLevel)
double getYRangeMax(unsigned short level=0)
FMGPoissonSolver(AmrBoxLib *itsAmrObject_p)
AmrBoxLib::AmrGrid_t AmrGrid_t
double reltol_m
Relative tolearance for solver.
double getZRangeMin(unsigned short level=0)
AmrBoxLib::AmrProcMap_t AmrProcMap_t
double getYRangeMin(unsigned short level=0)
double getXRangeMin(unsigned short level=0)
double getZRangeMax(unsigned short level=0)
void solve(AmrScalarFieldContainer_t &rho, AmrScalarFieldContainer_t &phi, AmrVectorFieldContainer_t &efield, unsigned short baseLevel, unsigned short finestLevel, bool prevAsGuess=true)
Definition: Inform.h:41
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
amr::AmrField_t AmrField_t
Definition: PBunchDefs.h:59