1 #ifdef HAVE_SAAMG_SOLVER
20 #pragma GCC diagnostic push
21 #pragma GCC diagnostic ignored "-Wunused-local-typedefs"
22 #include "Epetra_Map.h"
23 #include "Epetra_Vector.h"
24 #include "Epetra_CrsMatrix.h"
25 #include "Epetra_Operator.h"
26 #include "EpetraExt_RowMatrixOut.h"
27 #include "Epetra_Import.h"
29 #include "Teuchos_CommandLineProcessor.hpp"
31 #include "BelosLinearProblem.hpp"
32 #include "BelosRCGSolMgr.hpp"
33 #include "BelosEpetraAdapter.hpp"
34 #include "BelosBlockCGSolMgr.hpp"
36 #include "ml_MultiLevelPreconditioner.h"
37 #include "ml_MultiLevelOperator.h"
38 #include "ml_epetra_utils.h"
40 #include "Isorropia_Exception.hpp"
41 #include "Isorropia_Epetra.hpp"
42 #include "Isorropia_EpetraRedistributor.hpp"
43 #include "Isorropia_EpetraPartitioner.hpp"
45 #pragma GCC diagnostic pop
53 MGPoissonSolver::MGPoissonSolver (
PartBunch *beam,
56 std::vector<BoundaryGeometry *> geometries,
61 std::string precmode):
62 geometries_m(geometries),
65 Comm(
Ippl::getComm()),
70 domain_m = layout_m->getDomain();
72 for (
int i = 0; i < 3; i++) {
73 hr_m[i] = mesh_m->get_meshSpacing(i);
74 orig_nr_m[i] = domain_m[i].length();
77 if(itsolver ==
"CG") itsolver_m = AZ_cg;
78 else if(itsolver ==
"BICGSTAB") itsolver_m = AZ_bicgstab;
79 else if(itsolver ==
"GMRES") itsolver_m = AZ_gmres;
80 else throw OpalException(
"MGPoissonSolver",
"No valid iterative solver selected!");
82 precmode_m = STD_PREC;
83 if(precmode ==
"STD") precmode_m = STD_PREC;
84 else if(precmode ==
"HIERARCHY") precmode_m = REUSE_HIERARCHY;
85 else if(precmode ==
"REUSE") precmode_m = REUSE_PREC;
86 else if(precmode ==
"NO") precmode_m = NO;
88 tolerableIterationsCount_m = 2;
90 forcePreconditionerRecomputation_m =
false;
92 hasParallelDecompositionChanged_m =
true;
101 currentGeometry = geometries_m[0];
102 if(currentGeometry->getFilename() ==
"") {
103 if(currentGeometry->getTopology() ==
"ELLIPTIC"){
104 bp =
new EllipticDomain(currentGeometry, orig_nr_m, hr_m, interpl);
105 }
else if (currentGeometry->getTopology() ==
"BOXCORNER") {
106 bp =
new BoxCornerDomain(currentGeometry->getA(), currentGeometry->getB(), currentGeometry->getC(), currentGeometry->getLength(),currentGeometry->getL1(), currentGeometry->getL2(), orig_nr_m, hr_m, interpl);
107 bp->compute(itsBunch_m->get_hr());
110 "Geometry not known");
113 NDIndex<3> localId = layout_m->getLocalNDIndex();
114 if (localId[0].length() != domain_m[0].length() ||
115 localId[1].length() != domain_m[1].length()) {
117 "The class ArbitraryDomain only works with parallelization\n"
119 "Please set PARFFTX=FALSE, PARFFTY=FALSE, PARFFTT=TRUE in \n"
120 "the definition of the field solver in the input file.\n");
122 bp =
new ArbitraryDomain(currentGeometry, orig_nr_m, hr_m, interpl);
130 prec_m = Teuchos::null;
137 problem_ptr = rcp(
new Belos::LinearProblem<ST, MV, OP>);
139 if(numBlocks_m == 0 || recycleBlocks_m == 0)
140 solver_ptr = rcp(
new Belos::BlockCGSolMgr<double, MV, OP>());
142 solver_ptr = rcp(
new Belos::RCGSolMgr<double, MV, OP>());
143 solver_ptr->setParameters(rcp(&belosList,
false));
144 convStatusTest = rcp(
new Belos::StatusTestGenResNorm<ST, MV, OP> (tol));
145 convStatusTest->defineScaleForm(Belos::NormOfRHS, Belos::TwoNorm);
158 void MGPoissonSolver::deletePtr() {
166 prec_m = Teuchos::null;
169 MGPoissonSolver::~MGPoissonSolver() {
171 solver_ptr = Teuchos::null;
172 problem_ptr = Teuchos::null;
175 void MGPoissonSolver::computePotential(
Field_t &rho,
Vector_t hr,
double zshift) {
176 throw OpalException(
"MGPoissonSolver",
"not implemented yet");
179 void MGPoissonSolver::computeMap(
NDIndex<3> localId) {
180 if (itsBunch_m->getLocalTrackStep()%repartFreq_m == 0){
183 redistributeWithRCB(localId);
185 IPPLToMap3D(localId);
191 void MGPoissonSolver::extrapolateLHS() {
198 if (Teuchos::is_null(LHS)){
199 LHS = rcp(
new Epetra_Vector(*
Map));
202 RCP<Epetra_Vector> tmplhs = rcp(
new Epetra_Vector(*
Map));
203 Epetra_Import importer(*
Map, LHS->Map());
204 tmplhs->Import(*LHS, importer,
Add);
210 if(OldLHS.size() > 0) {
211 int n = OldLHS.size();
212 for(
int i = 0; i <
n; ++i) {
213 Epetra_Vector tmplhs = Epetra_Vector(*
Map);
214 Epetra_Import importer(*
Map, it->Map());
215 tmplhs.Import(*it, importer,
Add);
223 if(nLHS_m == 0 || OldLHS.size()==0)
225 else if(OldLHS.size() == 1)
227 else if(OldLHS.size() == 2)
228 LHS->Update(2.0, *it++, -1.0, *it, 0.0);
229 else if(OldLHS.size() > 2) {
230 int n = OldLHS.size();
231 P = rcp(
new Epetra_MultiVector(*
Map, nLHS_m,
false));
232 for(
int i = 0; i <
n; ++i) {
235 for(
int k = 1; k <
n; ++k) {
236 for(
int i = 0; i < n - k; ++i) {
237 (*P)(i)->Update(-(i + 1) / (float)k, *(*P)(i + 1), (i + k + 1) / (float)k);
242 throw OpalException(
"MGPoissonSolver",
"Invalid number of old LHS: " + std::to_string(OldLHS.size()));
253 nr_m[0] = orig_nr_m[0];
254 nr_m[1] = orig_nr_m[1];
255 nr_m[2] = orig_nr_m[2];
257 bp->setGlobalMeanR(itsBunch_m->getGlobalMeanR());
258 bp->setGlobalToLocalQuaternion(itsBunch_m->getGlobalToLocalQuaternion());
261 NDIndex<3> localId = layout_m->getLocalNDIndex();
265 if(!itsBunch_m->getLocalTrackStep())
266 bp->compute(hr, localId);
277 if (Teuchos::is_null(RHS))
278 RHS = rcp(
new Epetra_Vector(*
Map));
289 float scaleFactor = itsBunch_m->getdT();
293 msg <<
"* Node:" <<
Ippl::myNode() <<
", Rho for final element: " << rho[localId[0].last()][localId[1].last()][localId[2].last()].get() <<
endl;
296 msg <<
"* Node:" <<
Ippl::myNode() <<
", Local nx*ny*nz = " << localId[2].last() * localId[0].last() * localId[1].last() <<
endl;
297 msg <<
"* Node:" <<
Ippl::myNode() <<
", Number of reserved local elements in RHS: " << RHS->MyLength() <<
endl;
298 msg <<
"* Node:" <<
Ippl::myNode() <<
", Number of reserved global elements in RHS: " << RHS->GlobalLength() <<
endl;
301 for (
int idz = localId[2].first(); idz <= localId[2].last(); idz++) {
302 for (
int idy = localId[1].first(); idy <= localId[1].last(); idy++) {
303 for (
int idx = localId[0].first(); idx <= localId[0].last(); idx++) {
304 if (bp->isInside(idx, idy, idz))
305 RHS->Values()[
id++] = 4*M_PI*rho[idx][idy][idz].get()/scaleFactor;
313 msg <<
"* Node:" <<
Ippl::myNode() <<
", Number of Local Inside Points " <<
id <<
endl;
318 INFOMSG(
level3 <<
"* Building Discretization Matrix..." << endl);
320 if(Teuchos::is_null(A))
321 A = rcp(
new Epetra_CrsMatrix(Copy, *
Map, 7,
true));
322 ComputeStencil(hr, RHS);
327 EpetraExt::RowMatrixToMatlabFile(
"DiscrStencil.dat", *A);
333 MLPrec =
new ML_Epetra::MultiLevelPreconditioner(*A, MLList_m);
334 }
else if (precmode_m == REUSE_HIERARCHY) {
335 MLPrec->ReComputePreconditioner();
336 }
else if (precmode_m == REUSE_PREC){
345 problem_ptr->setOperator(A);
346 problem_ptr->setLHS(LHS);
347 problem_ptr->setRHS(RHS);
348 if(Teuchos::is_null(prec_m))
349 prec_m = Teuchos::rcp (
new Belos::EpetraPrecOp ( rcp(MLPrec,
false)));
350 problem_ptr->setLeftPrec(prec_m);
351 solver_ptr->setProblem( problem_ptr);
352 if (!problem_ptr->isProblemSet()) {
353 if (problem_ptr->setProblem() ==
false) {
354 ERRORMSG(
"Belos::LinearProblem failed to set up correctly!" << endl);
360 double time = MPI_Wtime();
368 std::ofstream timings;
369 if (
true || verbose_m) {
370 time = MPI_Wtime() - time;
371 double minTime, maxTime, avgTime;
372 Comm.MinAll(&time, &minTime, 1);
373 Comm.MaxAll(&time, &maxTime, 1);
374 Comm.SumAll(&time, &avgTime, 1);
375 avgTime /= Comm.NumProc();
376 if(Comm.MyPID() == 0) {
378 sprintf(filename,
"timing_MX%d_MY%d_MZ%d_nProc%d_recB%d_numB%d_nLHS%d", orig_nr_m[0], orig_nr_m[1], orig_nr_m[2], Comm.NumProc(), recycleBlocks_m, numBlocks_m, nLHS_m);
379 timings.open(filename, std::ios::app);
380 timings << solver_ptr->getNumIters() <<
"\t"
385 << numBlocks_m <<
"\t"
386 << recycleBlocks_m <<
"\t"
396 if(nLHS_m > 1) OldLHS.push_front(*(LHS.get()));
397 if(OldLHS.size() > nLHS_m) OldLHS.pop_back();
403 for (
int idz = localId[2].first(); idz <= localId[2].last(); idz++) {
404 for (
int idy = localId[1].first(); idy <= localId[1].last(); idy++) {
405 for (
int idx = localId[0].first(); idx <= localId[0].last(); idx++) {
407 if (bp->isInside(idx, idy, idz))
414 if(itsBunch_m->getLocalTrackStep()+1 == (
long long)
Track::block->localTimeSteps.front()) {
418 prec_m = Teuchos::null;
423 void MGPoissonSolver::redistributeWithRCB(
NDIndex<3> localId) {
425 int numMyGridPoints = 0;
427 for (
int idz = localId[2].first(); idz <= localId[2].last(); idz++) {
428 for (
int idy = localId[1].first(); idy <= localId[1].last(); idy++) {
429 for (
int idx = localId[0].first(); idx <= localId[0].last(); idx++) {
430 if (bp->isInside(idx, idy, idz))
436 Epetra_BlockMap bmap(-1, numMyGridPoints, 1, 0, Comm);
437 Teuchos::RCP<const Epetra_MultiVector> coords = Teuchos::rcp(
new Epetra_MultiVector(bmap, 3,
false));
442 coords->ExtractView(&v, &stride);
443 stride2 = 2 * stride;
445 for (
int idz = localId[2].first(); idz <= localId[2].last(); idz++) {
446 for (
int idy = localId[1].first(); idy <= localId[1].last(); idy++) {
447 for (
int idx = localId[0].first(); idx <= localId[0].last(); idx++) {
448 if (bp->isInside(idx, idy, idz)) {
450 v[stride] = (double)idy;
451 v[stride2] = (double)idz;
458 Teuchos::ParameterList paramlist;
459 paramlist.set(
"Partitioning Method",
"RCB");
460 Teuchos::ParameterList &sublist = paramlist.sublist(
"ZOLTAN");
461 sublist.set(
"RCB_RECTILINEAR_BLOCKS",
"1");
462 sublist.set(
"DEBUG_LEVEL",
"1");
464 Teuchos::RCP<Isorropia::Epetra::Partitioner> part = Teuchos::rcp(
new Isorropia::Epetra::Partitioner(coords, paramlist));
465 Isorropia::Epetra::Redistributor rd(part);
466 Teuchos::RCP<Epetra_MultiVector> newcoords = rd.redistribute(*coords);
468 newcoords->ExtractView(&v, &stride);
469 stride2 = 2 * stride;
471 std::vector<int> MyGlobalElements;
472 for(
int i = 0; i < newcoords->MyLength(); i++) {
473 MyGlobalElements.push_back(bp->getIdx(v[0], v[stride], v[stride2]));
478 Map =
new Epetra_Map(-1, numMyGridPoints, &MyGlobalElements[0], 0, Comm);
481 void MGPoissonSolver::IPPLToMap3D(
NDIndex<3> localId) {
483 int NumMyElements = 0;
484 std::vector<int> MyGlobalElements;
486 for (
int idz = localId[2].first(); idz <= localId[2].last(); idz++) {
487 for (
int idy = localId[1].first(); idy <= localId[1].last(); idy++) {
488 for (
int idx = localId[0].first(); idx <= localId[0].last(); idx++) {
489 if (bp->isInside(idx, idy, idz)) {
490 MyGlobalElements.push_back(bp->getIdx(idx, idy, idz));
496 Map =
new Epetra_Map(-1, NumMyElements, &MyGlobalElements[0], 0, Comm);
499 void MGPoissonSolver::ComputeStencil(
Vector_t hr, Teuchos::RCP<Epetra_Vector> RHS) {
503 int NumMyElements =
Map->NumMyElements();
504 int *MyGlobalElements =
Map->MyGlobalElements();
506 std::vector<double> Values(6);
507 std::vector<int> Indices(6);
509 for(
int i = 0 ; i < NumMyElements ; i++) {
513 double WV,
EV, SV, NV, FV, BV, CV, scaleFactor=1.0;
514 int W, E, S, N, F, B;
516 bp->getBoundaryStencil(MyGlobalElements[i], WV, EV, SV, NV, FV, BV, CV, scaleFactor);
517 RHS->Values()[i] *= scaleFactor;
519 bp->getNeighbours(MyGlobalElements[i], W, E, S, N, F, B);
521 Indices[NumEntries] = E;
522 Values[NumEntries++] =
EV;
525 Indices[NumEntries] =
W;
526 Values[NumEntries++] = WV;
529 Indices[NumEntries] = S;
530 Values[NumEntries++] = SV;
533 Indices[NumEntries] = N;
534 Values[NumEntries++] = NV;
537 Indices[NumEntries] = F;
538 Values[NumEntries++] = FV;
541 Indices[NumEntries] = B;
542 Values[NumEntries++] = BV;
550 A->ReplaceGlobalValues(MyGlobalElements[i], NumEntries, &Values[0], &Indices[0]);
552 A->ReplaceGlobalValues(MyGlobalElements[i], 1, &CV, MyGlobalElements + i);
555 A->InsertGlobalValues(MyGlobalElements[i], NumEntries, &Values[0], &Indices[0]);
557 A->InsertGlobalValues(MyGlobalElements[i], 1, &CV, MyGlobalElements + i);
563 A->OptimizeStorage();
566 void MGPoissonSolver::printLoadBalanceStats() {
569 size_t myNumPart =
Map->NumMyElements();
570 size_t NumPart =
Map->NumGlobalElements() * 1.0 / Comm.NumProc();
571 double imbalance = 1.0;
572 if(myNumPart >= NumPart)
573 imbalance += (myNumPart - NumPart) / NumPart;
575 imbalance += (NumPart - myNumPart) / NumPart;
577 double max = 0.0,
min = 0.0, avg = 0.0;
578 int minn = 0,
maxn = 0;
580 MPI_Reduce(&imbalance, &max, 1, MPI_DOUBLE, MPI_MAX, 0,
Ippl::getComm());
581 MPI_Reduce(&imbalance, &avg, 1, MPI_DOUBLE, MPI_SUM, 0,
Ippl::getComm());
582 MPI_Reduce(&myNumPart, &minn, 1, MPI_INT, MPI_MIN, 0,
Ippl::getComm());
585 avg /= Comm.NumProc();
586 *
gmsg <<
"LBAL min = " <<
min <<
", max = " << max <<
", avg = " << avg <<
endl;
587 *
gmsg <<
"min nr gridpoints = " << minn <<
", max nr gridpoints = " <<
maxn <<
endl;
591 os <<
"* *************** M G P o i s s o n S o l v e r ************************************ " <<
endl;
592 os <<
"* h " << hr_m <<
'\n';
593 os <<
"* ********************************************************************************** " <<
endl;
T::PETE_Expr_t::PETE_Return_t max(const PETE_Expr< T > &expr, NDIndex< D > &loc)
The base class for all OPAL exceptions.
double Add(double a, double b)
int recycleBlocks
RCG: number of recycle blocks.
T & localElement(const NDIndex< Dim > &) const
constexpr double c
The velocity of light in m/s.
int numBlocks
RCG: cycle length.
static void startTimer(TimerRef t)
static Track * block
The block of track data.
int nLHS
number of old left hand sides used to extrapolate a new start vector
static MPI_Comm getComm()
Inform & level3(Inform &inf)
std::string::iterator iterator
static TimerRef getTimer(const char *nm)
static void stopTimer(TimerRef t)
static Communicate * Comm
T::PETE_Expr_t::PETE_Return_t min(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Inform & endl(Inform &inf)