OPAL (Object Oriented Parallel Accelerator Library)  2.2.0
OPAL
MGPoissonSolver.cpp
Go to the documentation of this file.
1 #ifdef HAVE_SAAMG_SOLVER
2 //#define DBG_STENCIL
3 
5 
7 #include "ArbitraryDomain.h"
8 #include "EllipticDomain.h"
9 #include "BoxCornerDomain.h"
10 //#include "RectangularDomain.h"
11 
12 #include "Track/Track.h"
13 #include "Physics/Physics.h"
15 #include "Attributes/Attributes.h"
18 #include "Utilities/Options.h"
19 
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"
28 
29 #include "Teuchos_CommandLineProcessor.hpp"
30 
31 #include "BelosLinearProblem.hpp"
32 #include "BelosRCGSolMgr.hpp"
33 #include "BelosEpetraAdapter.hpp"
34 #include "BelosBlockCGSolMgr.hpp"
35 
36 #include "ml_MultiLevelPreconditioner.h"
37 #include "ml_MultiLevelOperator.h"
38 #include "ml_epetra_utils.h"
39 
40 #include "Isorropia_Exception.hpp"
41 #include "Isorropia_Epetra.hpp"
42 #include "Isorropia_EpetraRedistributor.hpp"
43 #include "Isorropia_EpetraPartitioner.hpp"
44 
45 #pragma GCC diagnostic pop
46 
47 #include <algorithm>
48 
49 using Teuchos::RCP;
50 using Teuchos::rcp;
51 using Physics::c;
52 
53 MGPoissonSolver::MGPoissonSolver ( PartBunch *beam,
54  Mesh_t *mesh,
55  FieldLayout_t *fl,
56  std::vector<BoundaryGeometry *> geometries,
57  std::string itsolver,
58  std::string interpl,
59  double tol,
60  int maxiters,
61  std::string precmode):
62  geometries_m(geometries),
63  tol_m(tol),
64  maxiters_m(maxiters),
65  Comm(Ippl::getComm()),
66  itsBunch_m(beam),
67  mesh_m(mesh),
68  layout_m(fl) {
69 
70  domain_m = layout_m->getDomain();
71 
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();
75  }
76 
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!");
81 
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;
87 
88  tolerableIterationsCount_m = 2;
89  numIter_m = -1;
90  forcePreconditionerRecomputation_m = false;
91 
92  hasParallelDecompositionChanged_m = true;
93  repartFreq_m = 1000;
94  useRCB_m = false;
95  if(Ippl::Info->getOutputLevel() > 3)
96  verbose_m = true;
97  else
98  verbose_m = false;
99 
100  // Find CURRENT geometry
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());
108  } else {
109  throw OpalException("MGPoissonSolver::MGPoissonSolver",
110  "Geometry not known");
111  }
112  } else {
113  NDIndex<3> localId = layout_m->getLocalNDIndex();
114  if (localId[0].length() != domain_m[0].length() ||
115  localId[1].length() != domain_m[1].length()) {
116  throw OpalException("ArbitraryDomain::compute",
117  "The class ArbitraryDomain only works with parallelization\n"
118  "in z-direction.\n"
119  "Please set PARFFTX=FALSE, PARFFTY=FALSE, PARFFTT=TRUE in \n"
120  "the definition of the field solver in the input file.\n");
121  }
122  bp = new ArbitraryDomain(currentGeometry, orig_nr_m, hr_m, interpl);
123  }
124 
125  Map = 0;
126  A = Teuchos::null;
127  LHS = Teuchos::null;
128  RHS = Teuchos::null;
129  MLPrec = 0;
130  prec_m = Teuchos::null;
131 
132  numBlocks_m = Options::numBlocks;
133  recycleBlocks_m = Options::recycleBlocks;
134  nLHS_m = Options::nLHS;
135  SetupMLList();
136  SetupBelosList();
137  problem_ptr = rcp(new Belos::LinearProblem<ST, MV, OP>);
138  // setup Belos solver
139  if(numBlocks_m == 0 || recycleBlocks_m == 0)
140  solver_ptr = rcp(new Belos::BlockCGSolMgr<double, MV, OP>());
141  else
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);
146 
147  //all timers used here
148  FunctionTimer1_m = IpplTimings::getTimer("BGF-IndexCoordMap");
149  FunctionTimer2_m = IpplTimings::getTimer("computeMap");
150  FunctionTimer3_m = IpplTimings::getTimer("IPPL to RHS");
151  FunctionTimer4_m = IpplTimings::getTimer("ComputeStencil");
152  FunctionTimer5_m = IpplTimings::getTimer("ML");
153  FunctionTimer6_m = IpplTimings::getTimer("Setup");
154  FunctionTimer7_m = IpplTimings::getTimer("CG");
155  FunctionTimer8_m = IpplTimings::getTimer("LHS to IPPL");
156 }
157 
158 void MGPoissonSolver::deletePtr() {
159  delete Map;
160  Map = nullptr;
161  delete MLPrec;
162  MLPrec = nullptr;
163  A = Teuchos::null;
164  LHS = Teuchos::null;
165  RHS = Teuchos::null;
166  prec_m = Teuchos::null;
167 }
168 
169 MGPoissonSolver::~MGPoissonSolver() {
170  deletePtr ();
171  solver_ptr = Teuchos::null;
172  problem_ptr = Teuchos::null;
173 }
174 
175 void MGPoissonSolver::computePotential(Field_t &rho, Vector_t hr, double zshift) {
176  throw OpalException("MGPoissonSolver", "not implemented yet");
177 }
178 
179 void MGPoissonSolver::computeMap(NDIndex<3> localId) {
180  if (itsBunch_m->getLocalTrackStep()%repartFreq_m == 0){
181  deletePtr();
182  if(useRCB_m)
183  redistributeWithRCB(localId);
184  else
185  IPPLToMap3D(localId);
186 
187  extrapolateLHS();
188  }
189 }
190 
191 void MGPoissonSolver::extrapolateLHS() {
192 // Aitken-Neville
193 // Pi0 (x) := yi , i = 0 : n
194 // Pik (x) := (x − xi ) Pi+1,k−1(x) − (x − xi+k ) Pi,k−1(x) /(xi+k − xi )
195 // k = 1, . . . , n, i = 0, . . . , n − k.
196  //we also have to redistribute LHS
197 
198  if (Teuchos::is_null(LHS)){
199  LHS = rcp(new Epetra_Vector(*Map));
200  LHS->PutScalar(1.0);
201  } else {
202  RCP<Epetra_Vector> tmplhs = rcp(new Epetra_Vector(*Map));
203  Epetra_Import importer(*Map, LHS->Map());
204  tmplhs->Import(*LHS, importer, Add);
205  LHS = tmplhs;
206  }
207 
208  //...and all previously saved LHS
209  std::deque< Epetra_Vector >::iterator it = OldLHS.begin();
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);
216  *it = tmplhs;
217  ++it;
218  }
219  }
220 
221  // extrapolate last OldLHS.size LHS to get a new start vector
222  it = OldLHS.begin();
223  if(nLHS_m == 0 || OldLHS.size()==0)
224  LHS->PutScalar(1.0);
225  else if(OldLHS.size() == 1)
226  *LHS = *it;
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) {
233  *(*P)(i) = *it++;
234  }
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);
238  }
239  }
240  *LHS = *(*P)(0);
241  } else
242  throw OpalException("MGPoissonSolver", "Invalid number of old LHS: " + std::to_string(OldLHS.size()));
243 }
244 
245 
246 // given a charge-density field rho and a set of mesh spacings hr,
247 // compute the electric field and put in eg by solving the Poisson's equation
248 // XXX: use matrix stencil in computation directly (no Epetra, define operators
249 // on IPPL GRID)
250 void MGPoissonSolver::computePotential(Field_t &rho, Vector_t hr) {
251 
252  Inform msg("OPAL ", INFORM_ALL_NODES);
253  nr_m[0] = orig_nr_m[0];
254  nr_m[1] = orig_nr_m[1];
255  nr_m[2] = orig_nr_m[2];
256 
257  bp->setGlobalMeanR(itsBunch_m->getGlobalMeanR());
258  bp->setGlobalToLocalQuaternion(itsBunch_m->getGlobalToLocalQuaternion());
259  bp->setNr(nr_m);
260 
261  NDIndex<3> localId = layout_m->getLocalNDIndex();
262 
263  IpplTimings::startTimer(FunctionTimer1_m);
264  // Compute boundary intersections (only do on the first step)
265  if(!itsBunch_m->getLocalTrackStep())
266  bp->compute(hr, localId);
267  IpplTimings::stopTimer(FunctionTimer1_m);
268 
269  // Define the Map
270  INFOMSG(level3 << "* Computing Map..." << endl);
271  IpplTimings::startTimer(FunctionTimer2_m);
272  computeMap(localId);
273  IpplTimings::stopTimer(FunctionTimer2_m);
274  INFOMSG(level3 << "* Done." << endl);
275 
276  // Allocate the RHS with the new Epetra Map
277  if (Teuchos::is_null(RHS))
278  RHS = rcp(new Epetra_Vector(*Map));
279  RHS->PutScalar(0.0);
280 
281  // // get charge densities from IPPL field and store in Epetra vector (RHS)
282  if (verbose_m) {
283  Ippl::Comm->barrier();
284  msg << "* Node:" << Ippl::myNode() << ", Filling RHS..." << endl;
285  Ippl::Comm->barrier();
286  }
287  IpplTimings::startTimer(FunctionTimer3_m);
288  int id = 0;
289  float scaleFactor = itsBunch_m->getdT();
290 
291 
292  if (verbose_m) {
293  msg << "* Node:" << Ippl::myNode() << ", Rho for final element: " << rho[localId[0].last()][localId[1].last()][localId[2].last()].get() << endl;
294 
295  Ippl::Comm->barrier();
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;
299  Ippl::Comm->barrier();
300  }
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;
306  }
307  }
308  }
309 
310  IpplTimings::stopTimer(FunctionTimer3_m);
311  if (verbose_m) {
312  Ippl::Comm->barrier();
313  msg << "* Node:" << Ippl::myNode() << ", Number of Local Inside Points " << id << endl;
314  msg << "* Node:" << Ippl::myNode() << ", Done." << endl;
315  Ippl::Comm->barrier();
316  }
317  // build discretization matrix
318  INFOMSG(level3 << "* Building Discretization Matrix..." << endl);
319  IpplTimings::startTimer(FunctionTimer4_m);
320  if(Teuchos::is_null(A))
321  A = rcp(new Epetra_CrsMatrix(Copy, *Map, 7, true));
322  ComputeStencil(hr, RHS);
323  IpplTimings::stopTimer(FunctionTimer4_m);
324  INFOMSG(level3 << "* Done." << endl);
325 
326 #ifdef DBG_STENCIL
327  EpetraExt::RowMatrixToMatlabFile("DiscrStencil.dat", *A);
328 #endif
329 
330  INFOMSG(level3 << "* Computing Preconditioner..." << endl);
331  IpplTimings::startTimer(FunctionTimer5_m);
332  if(!MLPrec) {
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){
337  }
338  IpplTimings::stopTimer(FunctionTimer5_m);
339  INFOMSG(level3 << "* Done." << endl);
340 
341  // setup preconditioned iterative solver
342  // use old LHS solution as initial guess
343  INFOMSG(level3 << "* Final Setup of Solver..." << endl);
344  IpplTimings::startTimer(FunctionTimer6_m);
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);
355  }
356  }
357  IpplTimings::stopTimer(FunctionTimer6_m);
358  INFOMSG(level3 << "* Done." << endl);
359 
360  double time = MPI_Wtime();
361 
362  INFOMSG(level3 << "* Solving for Space Charge..." << endl);
363  IpplTimings::startTimer(FunctionTimer7_m);
364  solver_ptr->solve();
365  IpplTimings::stopTimer(FunctionTimer7_m);
366  INFOMSG(level3 << "* Done." << endl);
367 
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) {
377  char filename[50];
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"
381  //<< time <<" "<<
382  << minTime << "\t"
383  << maxTime << "\t"
384  << avgTime << "\t"
385  << numBlocks_m << "\t"
386  << recycleBlocks_m << "\t"
387  << nLHS_m << "\t"
388  //<< OldLHS.size() <<"\t"<<
389  << std::endl;
390 
391  timings.close();
392  }
393 
394  }
395  // Store new LHS in OldLHS
396  if(nLHS_m > 1) OldLHS.push_front(*(LHS.get()));
397  if(OldLHS.size() > nLHS_m) OldLHS.pop_back();
398 
399  //now transfer solution back to IPPL grid
400  IpplTimings::startTimer(FunctionTimer8_m);
401  id = 0;
402  rho = 0.0;
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++) {
406  NDIndex<3> l(Index(idx, idx), Index(idy, idy), Index(idz, idz));
407  if (bp->isInside(idx, idy, idz))
408  rho.localElement(l) = LHS->Values()[id++]*scaleFactor;
409  }
410  }
411  }
412  IpplTimings::stopTimer(FunctionTimer8_m);
413 
414  if(itsBunch_m->getLocalTrackStep()+1 == (long long)Track::block->localTimeSteps.front()) {
415  A = Teuchos::null;
416  LHS = Teuchos::null;
417  RHS = Teuchos::null;
418  prec_m = Teuchos::null;
419  }
420 }
421 
422 
423 void MGPoissonSolver::redistributeWithRCB(NDIndex<3> localId) {
424 
425  int numMyGridPoints = 0;
426 
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))
431  numMyGridPoints++;
432  }
433  }
434  }
435 
436  Epetra_BlockMap bmap(-1, numMyGridPoints, 1, 0, Comm);
437  Teuchos::RCP<const Epetra_MultiVector> coords = Teuchos::rcp(new Epetra_MultiVector(bmap, 3, false));
438 
439  double *v;
440  int stride, stride2;
441 
442  coords->ExtractView(&v, &stride);
443  stride2 = 2 * stride;
444 
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)) {
449  v[0] = (double)idx;
450  v[stride] = (double)idy;
451  v[stride2] = (double)idz;
452  v++;
453  }
454  }
455  }
456  }
457 
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");
463 
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);
467 
468  newcoords->ExtractView(&v, &stride);
469  stride2 = 2 * stride;
470  numMyGridPoints = 0;
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]));
474  v++;
475  numMyGridPoints++;
476  }
477 
478  Map = new Epetra_Map(-1, numMyGridPoints, &MyGlobalElements[0], 0, Comm);
479 }
480 
481 void MGPoissonSolver::IPPLToMap3D(NDIndex<3> localId) {
482 
483  int NumMyElements = 0;
484  std::vector<int> MyGlobalElements;
485 
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));
491  NumMyElements++;
492  }
493  }
494  }
495  }
496  Map = new Epetra_Map(-1, NumMyElements, &MyGlobalElements[0], 0, Comm);
497 }
498 
499 void MGPoissonSolver::ComputeStencil(Vector_t hr, Teuchos::RCP<Epetra_Vector> RHS) {
500 
501  A->PutScalar(0.0);
502 
503  int NumMyElements = Map->NumMyElements();
504  int *MyGlobalElements = Map->MyGlobalElements();
505 
506  std::vector<double> Values(6);
507  std::vector<int> Indices(6);
508 
509  for(int i = 0 ; i < NumMyElements ; i++) {
510 
511  int NumEntries = 0;
512 
513  double WV, EV, SV, NV, FV, BV, CV, scaleFactor=1.0;
514  int W, E, S, N, F, B;
515 
516  bp->getBoundaryStencil(MyGlobalElements[i], WV, EV, SV, NV, FV, BV, CV, scaleFactor);
517  RHS->Values()[i] *= scaleFactor;
518 
519  bp->getNeighbours(MyGlobalElements[i], W, E, S, N, F, B);
520  if(E != -1) {
521  Indices[NumEntries] = E;
522  Values[NumEntries++] = EV;
523  }
524  if(W != -1) {
525  Indices[NumEntries] = W;
526  Values[NumEntries++] = WV;
527  }
528  if(S != -1) {
529  Indices[NumEntries] = S;
530  Values[NumEntries++] = SV;
531  }
532  if(N != -1) {
533  Indices[NumEntries] = N;
534  Values[NumEntries++] = NV;
535  }
536  if(F != -1) {
537  Indices[NumEntries] = F;
538  Values[NumEntries++] = FV;
539  }
540  if(B != -1) {
541  Indices[NumEntries] = B;
542  Values[NumEntries++] = BV;
543  }
544 
545  // if matrix has already been filled (FillComplete()) we can only
546  // replace entries
547 
548  if(A->Filled()) {
549  // off-diagonal entries
550  A->ReplaceGlobalValues(MyGlobalElements[i], NumEntries, &Values[0], &Indices[0]);
551  // diagonal entry
552  A->ReplaceGlobalValues(MyGlobalElements[i], 1, &CV, MyGlobalElements + i);
553  } else {
554  // off-diagonal entries
555  A->InsertGlobalValues(MyGlobalElements[i], NumEntries, &Values[0], &Indices[0]);
556  // diagonal entry
557  A->InsertGlobalValues(MyGlobalElements[i], 1, &CV, MyGlobalElements + i);
558  }
559  }
560 
561  A->FillComplete();
562 
563  A->OptimizeStorage();
564 }
565 
566 void MGPoissonSolver::printLoadBalanceStats() {
567 
568  //compute some load balance statistics
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;
574  else
575  imbalance += (NumPart - myNumPart) / NumPart;
576 
577  double max = 0.0, min = 0.0, avg = 0.0;
578  int minn = 0, maxn = 0;
579  MPI_Reduce(&imbalance, &min, 1, MPI_DOUBLE, MPI_MIN, 0, Ippl::getComm());
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());
583  MPI_Reduce(&myNumPart, &maxn, 1, MPI_INT, MPI_MAX, 0, Ippl::getComm());
584 
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;
588 }
589 
590 Inform &MGPoissonSolver::print(Inform &os) const {
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;
594  return os;
595 }
596 
597 #endif /* HAVE_SAAMG_SOLVER */
Definition: TSVMeta.h:24
#define INFORM_ALL_NODES
Definition: Inform.h:38
T::PETE_Expr_t::PETE_Return_t max(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:123
The base class for all OPAL exceptions.
Definition: OpalException.h:28
#define ERRORMSG(msg)
Definition: IpplInfo.h:399
Inform * gmsg
Definition: Main.cpp:21
void barrier(void)
static int myNode()
Definition: IpplInfo.cpp:794
double Add(double a, double b)
int recycleBlocks
RCG: number of recycle blocks.
Definition: Options.cpp:82
T & localElement(const NDIndex< Dim > &) const
Definition: BareField.hpp:1475
Definition: Index.h:236
constexpr double c
The velocity of light in m/s.
Definition: Physics.h:52
int numBlocks
RCG: cycle length.
Definition: Options.cpp:81
static void startTimer(TimerRef t)
Definition: IpplTimings.h:187
static Track * block
The block of track data.
Definition: Track.h:63
#define INFOMSG(msg)
Definition: IpplInfo.h:397
int nLHS
number of old left hand sides used to extrapolate a new start vector
Definition: Options.cpp:83
static MPI_Comm getComm()
Definition: IpplInfo.h:178
FVps< double, 6 > Map
Definition: ThickMapper.cpp:67
static Inform * Info
Definition: IpplInfo.h:87
Particle Bunch.
Definition: PartBunch.h:30
Inform & level3(Inform &inf)
Definition: Inform.cpp:47
std::string::iterator iterator
Definition: MSLang.h:16
static TimerRef getTimer(const char *nm)
Definition: IpplTimings.h:182
static void stopTimer(TimerRef t)
Definition: IpplTimings.h:192
Definition: Inform.h:41
static Communicate * Comm
Definition: IpplInfo.h:93
T::PETE_Expr_t::PETE_Return_t min(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:95
Inform & endl(Inform &inf)
Definition: Inform.cpp:42