OPAL (Object Oriented Parallel Accelerator Library) 2024.2
OPAL
AmrMultiGrid.cpp
Go to the documentation of this file.
1//
2// Class AmrMultiGrid
3// Main class of the AMR Poisson multigrid solver.
4// It implements the multigrid solver described in https://doi.org/10.1016/j.cpc.2019.106912
5//
6// Copyright (c) 2017 - 2020, Matthias Frey, Paul Scherrer Institut, Villigen PSI, Switzerland
7// All rights reserved
8//
9// Implemented as part of the PhD thesis
10// "Precise Simulations of Multibunches in High Intensity Cyclotrons"
11//
12// This file is part of OPAL.
13//
14// OPAL is free software: you can redistribute it and/or modify
15// it under the terms of the GNU General Public License as published by
16// the Free Software Foundation, either version 3 of the License, or
17// (at your option) any later version.
18//
19// You should have received a copy of the GNU General Public License
20// along with OPAL. If not, see <https://www.gnu.org/licenses/>.
21//
22#include "AmrMultiGrid.h"
23
24#include <algorithm>
25#include <filesystem>
26#include <functional>
27#include <map>
28#include <numeric>
29
31#include "OPALconfig.h"
32#include "Physics/Units.h"
34#include "Utilities/Timer.h"
35#include "Utilities/Util.h"
36
37#include <AMReX_ParallelDescriptor.H>
38
39#if AMR_MG_WRITE
40 #include <iomanip>
41#endif
42
44 const std::string& bsolver,
45 const std::string& prec,
46 const bool& rebalance,
47 const std::string& reuse,
48 const std::string& bcx,
49 const std::string& bcy,
50 const std::string& bcz,
51 const std::string& smoother,
52 const std::size_t& nSweeps,
53 const std::string& interp,
54 const std::string& norm)
55 : AmrPoissonSolver<AmrBoxLib>(itsAmrObject_p)
56 , comm_mp( new comm_t( amrex::ParallelDescriptor::Communicator() ) )
57 , nIter_m(0)
58 , bIter_m(0)
59 , maxiter_m(100)
60 , nSweeps_m(nSweeps)
61 , mglevel_m(0)
62 , lbase_m(0)
63 , lfine_m(0)
64 , nlevel_m(1)
65 , nBcPoints_m(0)
66 , snorm_m(norm)
67 , eps_m(1.0e-10)
68 , verbose_m(false)
69 , fname_m(OpalData::getInstance()->getInputBasename() + std::string(".solver"))
70 , flag_m(std::ios::out)
71{
72#if AMR_MG_TIMER
73 this->initTimer_m();
74#endif
75
76 const Boundary bcs[AMREX_SPACEDIM] = {
77 this->convertToEnumBoundary_m(bcx),
78 this->convertToEnumBoundary_m(bcy),
80 };
81
82 this->initPhysicalBoundary_m(&bcs[0]);
83
85
86 norm_m = this->convertToEnumNorm_m(norm);
87
88 const Interpolater interpolater = this->convertToEnumInterpolater_m(interp);
89 this->initInterpolater_m(interpolater);
90
91 // interpolater for crse-fine-interface
93
94 // preconditioner
95 const Preconditioner precond = this->convertToEnumPreconditioner_m(prec);
96 this->initPrec_m(precond, reuse);
97
98 // base level solver
99 const BaseSolver solver = this->convertToEnumBaseSolver_m(bsolver);
100 this->initBaseSolver_m(solver, rebalance, reuse);
101
102 if (std::filesystem::exists(fname_m)) {
103 flag_m = std::ios::app;
104 INFOMSG("Appending solver information to existing file: " << fname_m << endl);
105 } else {
106 INFOMSG("Creating new file for solver information: " << fname_m << endl);
107 }
108}
109
110
114 unsigned short baseLevel,
115 unsigned short finestLevel,
116 bool prevAsGuess)
117{
118 lbase_m = baseLevel;
119 lfine_m = finestLevel;
120 nlevel_m = lfine_m - lbase_m + 1;
121
122 /* we cannot use the previous solution
123 * if we have to regrid (AmrPoissonSolver::hasToRegrid())
124 *
125 * regrid_m is set in AmrBoxlib::regrid()
126 */
127 bool reset = !prevAsGuess;
128
129 if ( this->regrid_m )
130 reset = true;
131
132 this->initLevels_m(rho, itsAmrObject_mp->Geom(), this->regrid_m);
133
134 // build all necessary matrices and vectors
135 this->setup_m(rho, phi, this->regrid_m);
136
137 this->initGuess_m(reset);
138
139 // actual solve
140 scalar_t error = this->iterate_m();
141
142 for (int lev = nlevel_m - 1; lev > -1; --lev) {
143 averageDown_m(lev);
144 }
145
146 // write efield to AMReX
147 this->computeEfield_m(efield);
148
149 // copy solution back
150 for (int lev = 0; lev < nlevel_m; ++lev) {
151 int ilev = lbase_m + lev;
152
153 phi[ilev]->setVal(0.0, phi[ilev]->nGrow());
154
155 this->trilinos2amrex_m(lev, 0, *phi[ilev], mglevel_m[lev]->phi_p);
156 }
157
158 if ( verbose_m )
159 this->writeSDDSData_m(error);
160
161 // we can now reset
162 this->regrid_m = false;
163}
164
165
166void AmrMultiGrid::setNumberOfSweeps(const std::size_t& nSweeps) {
167 nSweeps_m = nSweeps;
168}
169
170
171void AmrMultiGrid::setMaxNumberOfIterations(const std::size_t& maxiter) {
172 if ( maxiter < 1 )
173 throw OpalException("AmrMultiGrid::setMaxNumberOfIterations()",
174 "The max. number of iterations needs to be positive!");
175
176 maxiter_m = maxiter;
177}
178
179
181 return nIter_m;
182}
183
184
188
189
190void AmrMultiGrid::setVerbose(bool verbose) {
191 verbose_m = verbose;
192}
193
194
196 eps_m = eps;
197}
198
199
201{
202 // make sure it's reset
203 nBcPoints_m = 0;
204
205 for (unsigned int i = 0; i < AMREX_SPACEDIM; ++i) {
206 switch ( bc[i] ) {
209 break;
210 case Boundary::OPEN:
212 break;
215 break;
216 default:
217 throw OpalException("AmrMultiGrid::initPhysicalBoundary_m()",
218 "This type of boundary is not supported");
219 }
220 // we use the maximum in order to build matrices
221 go_t tmp = bc_m[i]->getNumberOfPoints();
222 if ( nBcPoints_m < tmp )
223 nBcPoints_m = tmp;
224 }
225}
226
227
228void AmrMultiGrid::initLevels_m(const amrex::Vector<AmrField_u>& rho,
229 const amrex::Vector<AmrGeometry_t>& geom,
230 bool regrid)
231{
232 if ( !regrid )
233 return;
234
235 // although we do a resize afterwards, we do this to be safe
236 for (int lev = nlevel_m; lev < (int)mglevel_m.size(); ++lev) {
237 mglevel_m[lev].reset(nullptr);
238 }
239
240 mglevel_m.resize(nlevel_m);
241
242 amrex::Periodicity period(AmrIntVect_t(D_DECL(0, 0, 0)));
243
244 AmrIntVect_t rr = AmrIntVect_t(D_DECL(2, 2, 2));
245
246 for (int lev = 0; lev < nlevel_m; ++lev) {
247 int ilev = lbase_m + lev;
248
249 // do not initialize base level every time
250 if (mglevel_m[lev] == nullptr || lev > lbase_m) {
252 rho[ilev]->boxArray(),
253 rho[ilev]->DistributionMap(),
254 geom[ilev],
255 rr,
256 bc_m,
257 comm_mp));
258 } else {
259 mglevel_m[lev]->buildLevelMask();
260 }
261
262 mglevel_m[lev]->refmask.reset(
264 mglevel_m[lev]->dmap, 1, 2)
265 );
266 mglevel_m[lev]->refmask->setVal(AmrMultiGridLevel_t::Refined::NO, 2);
267 mglevel_m[lev]->refmask->FillBoundary(period);
268
269 amrex::BoxArray ba = mglevel_m[lev]->grids;
270 ba.coarsen(rr);
271 mglevel_m[lev]->crsemask.reset(
273 mglevel_m[lev]->dmap, 1, 2)
274 );
275 mglevel_m[lev]->crsemask->setVal(AmrMultiGridLevel_t::Refined::NO, 2);
276 }
277
278 for (int lev = 1; lev < nlevel_m; ++lev) {
279 mglevel_m[lev]->crsemask->setVal(AmrMultiGridLevel_t::Refined::YES, 0);
280
281 // used for boundary interpolation --> replaces expensive calls to isBoundary
282 mglevel_m[lev]->crsemask->setDomainBndry(AmrMultiGridLevel_t::Mask::PHYSBNDRY,
283 mglevel_m[lev-1]->geom); //FIXME: geometry of lev - 1
284 // really needed ?
285 mglevel_m[lev]->crsemask->FillBoundary(period);
286 }
287
288 /* to complete initialization we need to fill
289 * the mask of refinement
290 */
291 for (int lev = 0; lev < nlevel_m-1; ++lev) {
292 // get boxarray with refined cells
293 amrex::BoxArray ba = mglevel_m[lev]->grids;
294 ba.refine(rr);
295 ba = amrex::intersect(mglevel_m[lev+1]->grids, ba);
296 ba.coarsen(rr);
297
298 // refined cells
299 amrex::DistributionMapping dmap(ba, comm_mp->getSize());
300 AmrMultiGridLevel_t::mask_t refined(ba, dmap, 1, 0);
301 refined.setVal(AmrMultiGridLevel_t::Refined::YES);
302// refined.setDomainBndry(AmrMultiGridLevel_t::Mask::PHYSBNDRY, mglevel_m[lev]->geom);
303
304 // fill intersection with YES
305 mglevel_m[lev]->refmask->copy(refined, 0, 0, 1, 0, 2);
306
307 /* physical boundary cells will never be refined cells
308 * since they are ghost cells
309 */
310 mglevel_m[lev]->refmask->setDomainBndry(AmrMultiGridLevel_t::Mask::PHYSBNDRY,
311 mglevel_m[lev]->geom);
312
313 mglevel_m[lev]->refmask->FillBoundary(period);
314 }
315}
316
317
319 for (int lev = 0; lev < nlevel_m; ++lev) {
320 mglevel_m[lev]->refmask.reset(nullptr);
321 mglevel_m[lev]->crsemask.reset(nullptr);
322 mglevel_m[lev]->mask.reset(nullptr);
323 }
324}
325
326
328 if ( !reset )
329 return;
330
331 // reset
332 for (int lev = 0; lev < nlevel_m; ++lev)
333 mglevel_m[lev]->phi_p->putScalar(0.0);
334}
335
336
338
339 // initial error
340 std::vector<scalar_t> rhsNorms;
341 std::vector<scalar_t> resNorms;
342
343 this->initResidual_m(rhsNorms, resNorms);
344
345 std::for_each(rhsNorms.begin(), rhsNorms.end(),
346 [this](double& val){ val *= eps_m; });
347
348 nIter_m = 0;
349 bIter_m = 0;
350
351 while ( !isConverged_m(rhsNorms, resNorms) && nIter_m < maxiter_m ) {
352
354
355// /* in contrast to algorithm, we average down now
356// * --> potential is valid also on coarse covered
357// * cells
358// * --> however, it may take 1-2 iterations longer
359// */
360// for (int lev = nlevel_m - 1; lev > -1; --lev) {
361// averageDown_m(lev);
362// }
363
364 // update residual
365 for (int lev = 0; lev < nlevel_m; ++lev) {
366
367 this->residual_m(lev,
368 mglevel_m[lev]->residual_p,
369 mglevel_m[lev]->rho_p,
370 mglevel_m[lev]->phi_p);
371 }
372
373
374 for (lo_t lev = 0; lev < nlevel_m; ++lev)
375 resNorms[lev] = getLevelResidualNorm(lev);
376
377 ++nIter_m;
378
379#if AMR_MG_WRITE
380 this->writeResidualNorm_m();
381#endif
382
383 bIter_m += solver_mp->getNumIters();
384 }
385
386 return std::accumulate(resNorms.begin(),
387 resNorms.end(), 0.0,
388 std::plus<scalar_t>());
389}
390
391
392bool AmrMultiGrid::isConverged_m(std::vector<scalar_t>& rhsNorms,
393 std::vector<scalar_t>& resNorms)
394{
395 return std::equal(resNorms.begin(), resNorms.end(),
396 rhsNorms.begin(),
397 std::less<scalar_t>());
398}
399
400
402 Teuchos::RCP<vector_t>& r,
403 const Teuchos::RCP<vector_t>& b,
404 const Teuchos::RCP<vector_t>& x)
405{
406 /*
407 * r = b - A*x
408 */
409 if ( level < lfine_m ) {
410
411 vector_t fine2crse(mglevel_m[level]->Awf_p->getDomainMap(), true);
412
413 // get boundary for
414 if ( mglevel_m[level]->Bfine_p != Teuchos::null ) {
415 mglevel_m[level]->Bfine_p->apply(*mglevel_m[level+1]->phi_p, fine2crse);
416 }
417
418 // operation: fine2crse += A * x
419 mglevel_m[level]->Awf_p->apply(*x, fine2crse,
420 Teuchos::NO_TRANS,
421 scalar_t(1.0),
422 scalar_t(1.0));
423
424 if ( mglevel_m[level]->Bcrse_p != Teuchos::null ) {
425 // operation: fine2crse += B * phi^(l-1)
426 mglevel_m[level]->Bcrse_p->apply(*mglevel_m[level-1]->phi_p,
427 fine2crse,
428 Teuchos::NO_TRANS,
429 scalar_t(1.0),
430 scalar_t(1.0));
431 }
432
433 Teuchos::RCP<vector_t> uncov_Ax = Teuchos::rcp( new vector_t(mglevel_m[level]->map_p, true) );
434 mglevel_m[level]->UnCovered_p->apply(fine2crse, *uncov_Ax);
435
436 Teuchos::RCP<vector_t> uncov_b = Teuchos::rcp( new vector_t(mglevel_m[level]->map_p, true) );
437
438 mglevel_m[level]->UnCovered_p->apply(*b, *uncov_b);
439
440 // ONLY subtract coarse rho
441// mglevel_m[level]->residual_p->putScalar(0.0);
442
443 r->update(1.0, *uncov_b, -1.0, *uncov_Ax, 0.0);
444
445 } else {
446 /* finest level: Awf_p == Anf_p
447 */
448 Teuchos::RCP<vector_t> Ax = Teuchos::rcp( new vector_t(mglevel_m[level]->map_p, true) );
449 mglevel_m[level]->Anf_p->apply(*x, *Ax);
450
451 if ( mglevel_m[level]->Bcrse_p != Teuchos::null ) {
452 // operationr: Ax += B * phi^(l-1)
453 mglevel_m[level]->Bcrse_p->apply(*mglevel_m[level-1]->phi_p,
454 *Ax,
455 Teuchos::NO_TRANS,
456 scalar_t(1.0),
457 scalar_t(1.0));
458 }
459 r->update(1.0, *b, -1.0, *Ax, 0.0);
460 }
461}
462
463
464void AmrMultiGrid::relax_m(const lo_t& level) {
465
466 if ( level == lfine_m ) {
467
468 if ( level == lbase_m ) {
469 /* Anf_p == Awf_p
470 */
471 Teuchos::RCP<vector_t> Ax = Teuchos::rcp( new vector_t(mglevel_m[level]->map_p, true) );
472 mglevel_m[level]->Anf_p->apply(*mglevel_m[level]->phi_p, *Ax);
473 mglevel_m[level]->residual_p->update(1.0, *mglevel_m[level]->rho_p, -1.0, *Ax, 0.0);
474
475 } else {
476 this->residual_no_fine_m(level,
477 mglevel_m[level]->residual_p,
478 mglevel_m[level]->phi_p,
479 mglevel_m[level-1]->phi_p,
480 mglevel_m[level]->rho_p);
481 }
482 }
483
484 if ( level > 0 ) {
485 // phi^(l, save) = phi^(l)
486 Teuchos::RCP<vector_t> phi_save = Teuchos::rcp( new vector_t(mglevel_m[level]->map_p) );
487 Tpetra::deep_copy(*phi_save, *mglevel_m[level]->phi_p);
488
489 mglevel_m[level-1]->error_p->putScalar(0.0);
490
491 // smoothing
492 this->smooth_m(level,
493 mglevel_m[level]->error_p,
494 mglevel_m[level]->residual_p);
495
496
497 // phi = phi + e
498 mglevel_m[level]->phi_p->update(1.0, *mglevel_m[level]->error_p, 1.0);
499
500 /*
501 * restrict
502 */
503 this->restrict_m(level);
504
505 this->relax_m(level - 1);
506
507 /*
508 * prolongate / interpolate
509 */
510 this->prolongate_m(level);
511
512 // residual update
513 Teuchos::RCP<vector_t> tmp = Teuchos::rcp( new vector_t(mglevel_m[level]->map_p) );
514 this->residual_no_fine_m(level, tmp,
515 mglevel_m[level]->error_p,
516 mglevel_m[level-1]->error_p,
517 mglevel_m[level]->residual_p);
518
519 Tpetra::deep_copy(*mglevel_m[level]->residual_p, *tmp);
520
521 // delta error
522 Teuchos::RCP<vector_t> derror = Teuchos::rcp( new vector_t(mglevel_m[level]->map_p, true) );
523
524 // smoothing
525 this->smooth_m(level, derror, mglevel_m[level]->residual_p);
526
527 // e^(l) += de^(l)
528 mglevel_m[level]->error_p->update(1.0, *derror, 1.0);
529
530 // phi^(l) = phi^(l, save) + e^(l)
531 mglevel_m[level]->phi_p->update(1.0, *phi_save, 1.0, *mglevel_m[level]->error_p, 0.0);
532
533 } else {
534 // e = A^(-1)r
535#if AMR_MG_TIMER
536 IpplTimings::startTimer(bottomTimer_m);
537#endif
538
539 solver_mp->solve(mglevel_m[level]->error_p,
540 mglevel_m[level]->residual_p);
541
542#if AMR_MG_TIMER
543 IpplTimings::stopTimer(bottomTimer_m);
544#endif
545 // phi = phi + e
546 mglevel_m[level]->phi_p->update(1.0, *mglevel_m[level]->error_p, 1.0);
547 }
548}
549
550
552 Teuchos::RCP<vector_t>& result,
553 const Teuchos::RCP<vector_t>& rhs,
554 const Teuchos::RCP<vector_t>& crs_rhs,
555 const Teuchos::RCP<vector_t>& b)
556{
557 vector_t crse2fine(mglevel_m[level]->Anf_p->getDomainMap(), true);
558
559 // get boundary for
560 if ( mglevel_m[level]->Bcrse_p != Teuchos::null ) {
561 mglevel_m[level]->Bcrse_p->apply(*crs_rhs, crse2fine);
562 }
563
564 // operation: crse2fine = 1.0 * crse2fine + 1.0 * A^(l) * rhs
565 mglevel_m[level]->Anf_p->apply(*rhs, crse2fine,
566 Teuchos::NO_TRANS,
567 scalar_t(1.0),
568 scalar_t(1.0));
569
570 result->update(1.0, *b, -1.0, crse2fine, 0.0);
571}
572
573
574#if AMR_MG_WRITE
575void AmrMultiGrid::writeResidualNorm_m() {
576 scalar_t err = 0.0;
577
578 std::ofstream out;
579 if ( comm_mp->getRank() == 0 )
580 out.open("residual.dat", std::ios::app);
581
582 for (int lev = 0; lev < nlevel_m; ++lev) {
583 scalar_t tmp = evalNorm_m(mglevel_m[lev]->residual_p);
584
585 if ( comm_mp->getRank() == 0 )
586 out << std::setw(15) << std::right << tmp;
587 }
588
589 if ( comm_mp->getRank() == 0 )
590 out.close();
591}
592#endif
593
594
596AmrMultiGrid::evalNorm_m(const Teuchos::RCP<const vector_t>& x)
597{
598 scalar_t norm = 0.0;
599
600 switch ( norm_m ) {
601 case Norm::L1:
602 {
603 norm = x->norm1();
604 break;
605 }
606 case Norm::L2:
607 {
608 norm = x->norm2();
609 break;
610 }
611 case Norm::LINF:
612 {
613 norm = x->normInf();
614 break;
615 }
616 default:
617 throw OpalException("AmrMultiGrid::evalNorm_m()",
618 "This type of norm not suppported.");
619 }
620 return norm;
621}
622
623
624void AmrMultiGrid::initResidual_m(std::vector<scalar_t>& rhsNorms,
625 std::vector<scalar_t>& resNorms)
626{
627 rhsNorms.clear();
628 resNorms.clear();
629
630#if AMR_MG_WRITE
631 std::ofstream out;
632
633 if ( comm_mp->getRank() == 0) {
634 out.open("residual.dat", std::ios::out);
635
636 for (int lev = 0; lev < nlevel_m; ++lev)
637 out << std::setw(14) << std::right << "level" << lev;
638 out << std::endl;
639 }
640#endif
641
642 for (int lev = 0; lev < nlevel_m; ++lev) {
643 this->residual_m(lev,
644 mglevel_m[lev]->residual_p,
645 mglevel_m[lev]->rho_p,
646 mglevel_m[lev]->phi_p);
647
648 resNorms.push_back(evalNorm_m(mglevel_m[lev]->residual_p));
649
650#if AMR_MG_WRITE
651 if ( comm_mp->getRank() == 0 )
652 out << std::setw(15) << std::right << resNorms.back();
653#endif
654
655 rhsNorms.push_back(evalNorm_m(mglevel_m[lev]->rho_p));
656 }
657
658#if AMR_MG_WRITE
659 if ( comm_mp->getRank() == 0 )
660 out.close();
661#endif
662}
663
664
666#if AMR_MG_TIMER
667 IpplTimings::startTimer(efieldTimer_m);
668#endif
669 Teuchos::RCP<vector_t> efield_p = Teuchos::null;
670 for (int lev = nlevel_m - 1; lev > -1; --lev) {
671 int ilev = lbase_m + lev;
672
673 efield_p = Teuchos::rcp( new vector_t(mglevel_m[lev]->map_p, false) );
674
675
676 for (int d = 0; d < AMREX_SPACEDIM; ++d) {
677 efield[ilev][d]->setVal(0.0, efield[ilev][d]->nGrow());
678 efield_p->putScalar(0.0);
679 mglevel_m[lev]->G_p[d]->apply(*mglevel_m[lev]->phi_p, *efield_p);
680 this->trilinos2amrex_m(lev, 0, *efield[ilev][d], efield_p);
681 }
682 }
683#if AMR_MG_TIMER
684 IpplTimings::stopTimer(efieldTimer_m);
685#endif
686}
687
688
689void AmrMultiGrid::setup_m(const amrex::Vector<AmrField_u>& rho,
690 const amrex::Vector<AmrField_u>& phi,
691 const bool& matrices)
692{
693#if AMR_MG_TIMER
694 IpplTimings::startTimer(buildTimer_m);
695#endif
696
697 if ( lbase_m == lfine_m )
698 this->buildSingleLevel_m(rho, phi, matrices);
699 else
700 this->buildMultiLevel_m(rho, phi, matrices);
701
702 mglevel_m[lfine_m]->error_p->putScalar(0.0);
703
704 if ( matrices ) {
705 this->clearMasks_m();
706 // set the bottom solve operator
707 if (!solver_mp->hasOperator()) {
708 solver_mp->setOperator(mglevel_m[lbase_m]->Anf_p, mglevel_m[0].get());
709 }
710 }
711
712#if AMR_MG_TIMER
713 IpplTimings::stopTimer(buildTimer_m);
714#endif
715}
716
717
718void AmrMultiGrid::buildSingleLevel_m(const amrex::Vector<AmrField_u>& rho,
719 const amrex::Vector<AmrField_u>& phi,
720 const bool& matrices)
721{
722 this->open_m(lbase_m, matrices);
723
724 const scalar_t* invdx = mglevel_m[lbase_m]->invCellSize();
725
726 const scalar_t invdx2[] = {
727 D_DECL( invdx[0] * invdx[0],
728 invdx[1] * invdx[1],
729 invdx[2] * invdx[2] )
730 };
731
732 if (matrices) {
733 for (amrex::MFIter mfi(*mglevel_m[lbase_m]->mask, true);
734 mfi.isValid(); ++mfi)
735 {
736 const box_t& tbx = mfi.tilebox();
737 const basefab_t& mfab = (*mglevel_m[lbase_m]->mask)[mfi];
738 const farraybox_t& rhofab = (*rho[lbase_m])[mfi];
739 const farraybox_t& pfab = (*phi[lbase_m])[mfi];
740
741 const int* lo = tbx.loVect();
742 const int* hi = tbx.hiVect();
743
744 for (int i = lo[0]; i <= hi[0]; ++i) {
745 for (int j = lo[1]; j <= hi[1]; ++j) {
746#if AMREX_SPACEDIM == 3
747 for (int k = lo[2]; k <= hi[2]; ++k) {
748#endif
749 AmrIntVect_t iv(D_DECL(i, j, k));
750 go_t gidx = mglevel_m[lbase_m]->serialize(iv);
751
752 if (!solver_mp->hasOperator()) {
753 this->buildNoFinePoissonMatrix_m(lbase_m, gidx, iv, mfab, invdx2);
754 this->buildGradientMatrix_m(lbase_m, gidx, iv, mfab, invdx);
755 }
756
757 mglevel_m[lbase_m]->rho_p->replaceGlobalValue(gidx, rhofab(iv, 0));
758 mglevel_m[lbase_m]->phi_p->replaceGlobalValue(gidx, pfab(iv, 0));
759
760#if AMREX_SPACEDIM == 3
761 }
762#endif
763 }
764 }
765 }
766 } else {
768 }
769
770 this->close_m(lbase_m, matrices);
771
772 if (matrices) {
773 mglevel_m[lbase_m]->Awf_p = Teuchos::null;
774 mglevel_m[lbase_m]->UnCovered_p = Teuchos::null;
775 }
776}
777
778
779void AmrMultiGrid::buildMultiLevel_m(const amrex::Vector<AmrField_u>& rho,
780 const amrex::Vector<AmrField_u>& phi,
781 const bool& matrices)
782{
783 // the base level has no smoother --> nlevel_m - 1
784 if ( matrices ) {
785 // although we do a resize afterwards, we do this to be safe
786 for (int lev = nlevel_m-1; lev < (int)smoother_m.size(); ++lev) {
787 smoother_m[lev].reset();
788 }
789 smoother_m.resize(nlevel_m-1);
790 }
791
792 for (int lev = 0; lev < nlevel_m; ++lev) {
793 this->open_m(lev, matrices);
794
795 int ilev = lbase_m + lev;
796
797 // find all coarse cells that are covered by fine cells
798// AmrIntVect_t rr = mglevel_m[lev]->refinement();
799
800 const scalar_t* invdx = mglevel_m[lev]->invCellSize();
801
802 const scalar_t invdx2[] = {
803 D_DECL( invdx[0] * invdx[0],
804 invdx[1] * invdx[1],
805 invdx[2] * invdx[2] )
806 };
807
808 if ( matrices ) {
809 for (amrex::MFIter mfi(*mglevel_m[lev]->mask, true);
810 mfi.isValid(); ++mfi)
811 {
812 const box_t& tbx = mfi.tilebox();
813 const basefab_t& mfab = (*mglevel_m[lev]->mask)[mfi];
814 const basefab_t& rfab = (*mglevel_m[lev]->refmask)[mfi];
815 const basefab_t& cfab = (*mglevel_m[lev]->crsemask)[mfi];
816 const farraybox_t& rhofab = (*rho[ilev])[mfi];
817 const farraybox_t& pfab = (*phi[ilev])[mfi];
818
819 const int* lo = tbx.loVect();
820 const int* hi = tbx.hiVect();
821
822 for (int i = lo[0]; i <= hi[0]; ++i) {
823 int ii = i << 1;
824 for (int j = lo[1]; j <= hi[1]; ++j) {
825 int jj = j << 1;
826#if AMREX_SPACEDIM == 3
827 for (int k = lo[2]; k <= hi[2]; ++k) {
828 int kk = k << 1;
829#endif
830 AmrIntVect_t iv(D_DECL(i, j, k));
831 go_t gidx = mglevel_m[lev]->serialize(iv);
832
833 this->buildRestrictionMatrix_m(lev, gidx, iv,
834 D_DECL(ii, jj, kk), rfab);
835
836 this->buildInterpolationMatrix_m(lev, gidx, iv, cfab);
837
838 this->buildCrseBoundaryMatrix_m(lev, gidx, iv, mfab,
839 cfab, invdx2);
840
841 this->buildFineBoundaryMatrix_m(lev, gidx, iv,
842 mfab, rfab);
843
844 this->buildCompositePoissonMatrix_m(lev, gidx, iv, mfab,
845 rfab, invdx2);
846
847 if (lev > lbase_m || (lev == lbase_m && !solver_mp->hasOperator())) {
848 this->buildNoFinePoissonMatrix_m(lev, gidx, iv, mfab, invdx2);
849 this->buildGradientMatrix_m(lev, gidx, iv, mfab, invdx);
850 }
851
852 mglevel_m[lev]->rho_p->replaceGlobalValue(gidx, rhofab(iv, 0));
853 mglevel_m[lev]->phi_p->replaceGlobalValue(gidx, pfab(iv, 0));
854#if AMREX_SPACEDIM == 3
855 }
856#endif
857 }
858 }
859 }
860 } else {
861 for (lo_t lev = 0; lev < nlevel_m; ++lev) {
862 int ilev = lbase_m + lev;
863 this->buildDensityVector_m(lev, *rho[ilev]);
864 }
865 }
866
867 this->close_m(lev, matrices);
868
869 if ( matrices && lev > lbase_m ) {
870 smoother_m[lev-1].reset( new AmrSmoother(mglevel_m[lev]->Anf_p,
872 }
873 }
874}
875
876
877void AmrMultiGrid::open_m(const lo_t& level,
878 const bool& matrices)
879{
880 if ( matrices ) {
881
882 if ( level > lbase_m ) {
883
884 /*
885 * interpolation matrix
886 */
887
888 int nNeighbours = (nBcPoints_m + 1) * interp_mp->getNumberOfPoints();
889
890 mglevel_m[level]->I_p = Teuchos::rcp( new matrix_t(mglevel_m[level]->map_p,
891 nNeighbours) );
892
893 /*
894 * coarse boundary matrix
895 */
896
897 nNeighbours = 2 * AMREX_SPACEDIM * nBcPoints_m *
898 2 * AMREX_SPACEDIM * interface_mp->getNumberOfPoints();
899
900 mglevel_m[level]->Bcrse_p = Teuchos::rcp(
901 new matrix_t(mglevel_m[level]->map_p, nNeighbours) );
902
903 }
904
905
906 if ( level < lfine_m ) {
907
908 /*
909 * restriction matrix
910 */
911
912 // refinement 2
913 int nNeighbours = AMREX_D_TERM(2, * 2, * 2);
914
915 mglevel_m[level]->R_p = Teuchos::rcp(
916 new matrix_t(mglevel_m[level]->map_p, nNeighbours) );
917
918 /*
919 * fine boundary matrix
920 */
921
922 // refinement 2
923 nNeighbours = 2 * AMREX_SPACEDIM * AMREX_D_TERM(2, * 2, * 2);
924
925 mglevel_m[level]->Bfine_p = Teuchos::rcp(
926 new matrix_t(mglevel_m[level]->map_p, nNeighbours) );
927
928 }
929
930 /*
931 * no-fine Poisson matrix
932 */
933
934 int nPhysBoundary = 2 * AMREX_SPACEDIM * nBcPoints_m;
935
936 // number of internal stencil points
937 int nIntBoundary = AMREX_SPACEDIM * interface_mp->getNumberOfPoints();
938
939 int nEntries = (AMREX_SPACEDIM << 1) + 2 /* plus boundaries */ + nPhysBoundary + nIntBoundary;
940
941 if (level > lbase_m || (level == lbase_m && !solver_mp->hasOperator())) {
942 mglevel_m[level]->Anf_p = Teuchos::rcp(
943 new matrix_t(mglevel_m[level]->map_p, nEntries) );
944 }
945
946 /*
947 * with-fine / composite Poisson matrix
948 */
949 if ( lbase_m != lfine_m ) {
950 nEntries = (AMREX_SPACEDIM << 1) + 5 /* plus boundaries */ + nPhysBoundary + nIntBoundary;
951
952 mglevel_m[level]->Awf_p = Teuchos::rcp(
953 new matrix_t(mglevel_m[level]->map_p, nEntries) );
954
955 /*
956 * uncovered cells matrix
957 */
958 mglevel_m[level]->UnCovered_p = Teuchos::rcp(
959 new matrix_t(mglevel_m[level]->map_p, 1) );
960 }
961
962 /*
963 * gradient matrices
964 */
965 nEntries = 11;
966
967 if (level > lbase_m || (level == lbase_m && !solver_mp->hasOperator())) {
968 for (int d = 0; d < AMREX_SPACEDIM; ++d) {
969 mglevel_m[level]->G_p[d] = Teuchos::rcp(
970 new matrix_t(mglevel_m[level]->map_p, nEntries) );
971 }
972 }
973 }
974
975 mglevel_m[level]->rho_p = Teuchos::rcp(
976 new vector_t(mglevel_m[level]->map_p, false) );
977
978 if ( matrices ) {
979 mglevel_m[level]->phi_p = Teuchos::rcp(
980 new vector_t(mglevel_m[level]->map_p, false) );
981 }
982}
983
984
985void AmrMultiGrid::close_m(const lo_t& level,
986 const bool& matrices)
987{
988 if ( matrices ) {
989 if ( level > lbase_m ) {
990
991 mglevel_m[level]->I_p->fillComplete(mglevel_m[level-1]->map_p, // col map (domain map)
992 mglevel_m[level]->map_p); // row map (range map)
993
994 mglevel_m[level]->Bcrse_p->fillComplete(mglevel_m[level-1]->map_p, // col map
995 mglevel_m[level]->map_p); // row map
996 }
997
998 if ( level < lfine_m ) {
999
1000 mglevel_m[level]->R_p->fillComplete(mglevel_m[level+1]->map_p,
1001 mglevel_m[level]->map_p);
1002
1003 mglevel_m[level]->Bfine_p->fillComplete(mglevel_m[level+1]->map_p,
1004 mglevel_m[level]->map_p);
1005 }
1006
1007 if (level > lbase_m || (level == lbase_m && !solver_mp->hasOperator())) {
1008 mglevel_m[level]->Anf_p->fillComplete();
1009
1010 for (int d = 0; d < AMREX_SPACEDIM; ++d)
1011 mglevel_m[level]->G_p[d]->fillComplete();
1012 }
1013
1014 if ( lbase_m != lfine_m ) {
1015 mglevel_m[level]->Awf_p->fillComplete();
1016
1017 mglevel_m[level]->UnCovered_p->fillComplete();
1018 }
1019 }
1020}
1021
1022
1024 const go_t& gidx,
1025 const AmrIntVect_t& iv,
1026 const basefab_t& mfab,
1027 const scalar_t* invdx2)
1028{
1029 /*
1030 * Laplacian of "no fine"
1031 */
1032
1033 /*
1034 * 1D not supported
1035 * 2D --> 5 elements per row
1036 * 3D --> 7 elements per row
1037 */
1038
1039 umap_t map;
1040 indices_t indices;
1041 coefficients_t values;
1042
1043 /*
1044 * check neighbours in all directions (Laplacian stencil --> cross)
1045 */
1046 for (int d = 0; d < AMREX_SPACEDIM; ++d) {
1047 for (int shift = -1; shift <= 1; shift += 2) {
1048 AmrIntVect_t biv = iv;
1049 biv[d] += shift;
1050
1051 switch ( mfab(biv) )
1052 {
1054 case AmrMultiGridLevel_t::Mask::COVERED: // covered --> interior cell
1055 {
1056 map[mglevel_m[level]->serialize(biv)] += invdx2[d];
1057 break;
1058 }
1060 {
1061 // boundary cell
1062 // only level > 0 have this kind of boundary
1063#ifndef NDEBUG
1064 if ( level == lbase_m )
1065 throw OpalException("AmrMultiGrid::buildNoFinePoissonMatrix_m()",
1066 "Error in mask for level "
1067 + std::to_string(level) + "!");
1068#endif
1069 /* Dirichlet boundary conditions from coarser level.
1070 */
1071 interface_mp->fine(biv, map, invdx2[d], d, -shift,
1072 mglevel_m[level].get());
1073 break;
1074 }
1076 {
1077 // physical boundary cell
1078 mglevel_m[level]->applyBoundary(biv, d, map,
1079 invdx2[d] /*matrix coefficient*/);
1080 break;
1081 }
1082 default:
1083 throw OpalException("AmrMultiGrid::buildNoFinePoissonMatrix_m()",
1084 "Error in mask for level "
1085 + std::to_string(level) + "!");
1086 }
1087 }
1088 }
1089
1090 // check center
1091 map[gidx] += AMREX_D_TERM(- 2.0 * invdx2[0],
1092 - 2.0 * invdx2[1],
1093 - 2.0 * invdx2[2]);
1094
1095 this->map2vector_m(map, indices, values);
1096
1097 if (!indices.empty()) {
1098 mglevel_m[level]->Anf_p->insertGlobalValues(gidx,
1099 indices.size(),
1100 values.data(),
1101 indices.data());
1102 }
1103}
1104
1105
1107 const go_t& gidx,
1108 const AmrIntVect_t& iv,
1109 const basefab_t& mfab,
1110 const basefab_t& rfab,
1111 const scalar_t* invdx2)
1112{
1113 /*
1114 * Laplacian of "with fine"
1115 *
1116 * For the finest level: Awf == Anf
1117 */
1118 if ( rfab(iv) == AmrMultiGridLevel_t::Refined::YES ) //|| lbase_m != lfine_m )
1119 return;
1120 /*
1121 * Only cells that are not refined
1122 */
1123
1124 /*
1125 * 1D not supported by AmrMultiGrid
1126 * 2D --> 5 elements per row
1127 * 3D --> 7 elements per row
1128 */
1129
1130 umap_t map;
1131 indices_t indices;
1132 coefficients_t values;
1133
1134 /*
1135 * Only cells that are not refined
1136 */
1137
1138 /*
1139 * check neighbours in all directions (Laplacian stencil --> cross)
1140 */
1141 for (int d = 0; d < AMREX_SPACEDIM; ++d) {
1142 for (int shift = -1; shift <= 1; shift += 2) {
1143 AmrIntVect_t biv = iv;
1144 biv[d] += shift;
1145
1146 if ( rfab(biv) != AmrMultiGridLevel_t::Refined::YES )
1147 {
1148 /*
1149 * It can't be a refined cell!
1150 */
1151 switch ( mfab(biv) )
1152 {
1154 // covered --> interior cell
1156 {
1157 map[mglevel_m[level]->serialize(biv)] += invdx2[d];
1158 map[gidx] -= invdx2[d]; // add center once
1159 break;
1160 }
1162 {
1163 // boundary cell
1164 // only level > 0 have this kind of boundary
1165#ifndef NDEBUG
1166 if ( level == lbase_m )
1167 throw OpalException("AmrMultiGrid::buildCompositePoissonMatrix_m()",
1168 "Error in mask for level "
1169 + std::to_string(level) + "!");
1170#endif
1171
1172 /* We are on the fine side of the crse-fine interface
1173 * --> normal stencil --> no flux matching required
1174 * --> interpolation of fine ghost cell required
1175 * (used together with Bcrse)
1176 */
1177
1178 /* Dirichlet boundary conditions from coarser level.
1179 */
1180 interface_mp->fine(biv, map, invdx2[d], d, -shift,
1181 mglevel_m[level].get());
1182
1183 // add center once
1184 map[gidx] -= invdx2[d];
1185 break;
1186 }
1188 {
1189 // physical boundary cell
1190 mglevel_m[level]->applyBoundary(biv, d, map,
1191 invdx2[d] /*matrix coefficient*/);
1192
1193 // add center once
1194 map[gidx] -= invdx2[d];
1195 break;
1196 }
1197 default:
1198 throw OpalException("AmrMultiGrid::buildCompositePoissonMatrix_m()",
1199 "Error in mask for level "
1200 + std::to_string(level) + "!");
1201 }
1202 } else {
1203 /*
1204 * If neighbour cell is refined, we are on the coarse
1205 * side of the crse-fine interface --> flux matching
1206 * required --> interpolation of fine ghost cell
1207 * (used together with Bfine)
1208 */
1209
1210
1211 // flux matching, coarse part
1212
1213 /* 2D --> 2 fine cells to compute flux per coarse-fine-interace --> avg = 2
1214 * 3D --> 4 fine cells to compute flux per coarse-fine-interace --> avg = 4
1215 *
1216 * @precondition: refinement of 2
1217 */
1218 // top and bottom for all directions
1219 const scalar_t* invcdx = mglevel_m[level]->invCellSize();
1220 const scalar_t* invfdx = mglevel_m[level+1]->invCellSize();
1221 scalar_t invavg = AMREX_D_PICK(1.0, 0.5, 0.25);
1222 scalar_t value = - invavg * invcdx[d] * invfdx[d];
1223
1224 for (int d1 = 0; d1 < 2; ++d1) {
1225#if AMREX_SPACEDIM == 3
1226 for (int d2 = 0; d2 < 2; ++d2) {
1227#endif
1228
1229 /* in order to get a top iv --> needs to be odd value in "d"
1230 * in order to get a bottom iv --> needs to be even value in "d"
1231 */
1232 AmrIntVect_t fake(D_DECL(0, 0, 0));
1233
1234 fake[(d+1)%AMREX_SPACEDIM] = d1;
1235#if AMREX_SPACEDIM == 3
1236 fake[(d+2)%AMREX_SPACEDIM] = d2;
1237#endif
1238 interface_mp->coarse(iv, map, value, d, shift, rfab,
1239 fake, mglevel_m[level].get());
1240
1241#if AMREX_SPACEDIM == 3
1242 }
1243#endif
1244 }
1245 }
1246 }
1247 }
1248
1249 this->map2vector_m(map, indices, values);
1250
1251 if (!indices.empty()) {
1252 mglevel_m[level]->Awf_p->insertGlobalValues(gidx,
1253 indices.size(),
1254 values.data(),
1255 indices.data());
1256 }
1257
1258 scalar_t vv = 1.0;
1259 mglevel_m[level]->UnCovered_p->insertGlobalValues(gidx,
1260 1,
1261 &vv,
1262 &gidx);
1263}
1264
1265
1267 const go_t& gidx,
1268 const AmrIntVect_t& iv,
1269 D_DECL(const go_t& ii,
1270 const go_t& jj,
1271 const go_t& kk),
1272 const basefab_t& rfab)
1273{
1274 /*
1275 * x^(l) = R * x^(l+1)
1276 */
1277
1278 // finest level does not need to have a restriction matrix
1279 if ( rfab(iv) == AmrMultiGridLevel_t::Refined::NO || level == lfine_m )
1280 return;
1281
1282 /* Difficulty: If a fine cell belongs to another processor than the underlying
1283 * coarse cell, we get an error when filling the matrix since the
1284 * cell (--> global index) does not belong to the same processor.
1285 * Solution: Find all coarse cells that are covered by fine cells, thus,
1286 * the distributionmap is correct.
1287 *
1288 *
1289 */
1290 indices_t indices;
1291 indices.reserve(2 << (AMREX_SPACEDIM - 1));
1292 coefficients_t values;
1293 values.reserve(2 << (AMREX_SPACEDIM -1));
1294
1295 // neighbours
1296 for (int iref = 0; iref < 2; ++iref) {
1297 for (int jref = 0; jref < 2; ++jref) {
1298#if AMREX_SPACEDIM == 3
1299 for (int kref = 0; kref < 2; ++kref) {
1300#endif
1301 AmrIntVect_t riv(D_DECL(ii + iref, jj + jref, kk + kref));
1302
1303 indices.push_back( mglevel_m[level+1]->serialize(riv) );
1304 values.push_back( AMREX_D_PICK(0.5, 0.25, 0.125) );
1305#if AMREX_SPACEDIM == 3
1306 }
1307#endif
1308 }
1309 }
1310
1311 if (!indices.empty()) {
1312 mglevel_m[level]->R_p->insertGlobalValues(gidx,
1313 indices.size(),
1314 values.data(),
1315 indices.data());
1316 }
1317}
1318
1319
1321 const go_t& gidx,
1322 const AmrIntVect_t& iv,
1323 const basefab_t& cfab)
1324{
1325 /* crse: level - 1
1326 * fine (this): level
1327 */
1328
1329 /*
1330 * This does not include ghost cells
1331 * --> no boundaries
1332 *
1333 * x^(l) = I * x^(l-1)
1334 */
1335
1336 if ( level == lbase_m )
1337 return;
1338
1339 umap_t map;
1340 indices_t indices;
1341 coefficients_t values;
1342
1343 /*
1344 * we need boundary + indices from coarser level
1345 */
1346 interp_mp->stencil(iv, cfab, map, 1.0, mglevel_m[level-1].get());
1347
1348 this->map2vector_m(map, indices, values);
1349
1350 if (!indices.empty()) {
1351 mglevel_m[level]->I_p->insertGlobalValues(gidx,
1352 indices.size(),
1353 values.data(),
1354 indices.data());
1355 }
1356}
1357
1358
1360 const go_t& gidx,
1361 const AmrIntVect_t& iv,
1362 const basefab_t& mfab,
1363 const basefab_t& cfab,
1364 const scalar_t* invdx2)
1365{
1366 /*
1367 * fine (this): level
1368 * coarse: level - 1
1369 */
1370
1371 // the base level has only physical boundaries
1372 if ( level == lbase_m )
1373 return;
1374
1375 // iv is a fine cell
1376
1377 umap_t map;
1378 indices_t indices;
1379 coefficients_t values;
1380
1381 // check its neighbours to see if at crse-fine interface
1382 for (int d = 0; d < AMREX_SPACEDIM; ++d) {
1383 for (int shift = -1; shift <= 1; shift += 2) {
1384 // neighbour
1385 AmrIntVect_t niv = iv;
1386 niv[d] += shift;
1387
1388 if ( mfab(niv) == AmrMultiGridLevel_t::Mask::BNDRY )
1389 {
1390 // neighbour does not belong to fine grids
1391 // includes no cells at physical boundary
1392
1393 // coarse cell that is not refined
1394 AmrIntVect_t civ = iv;
1395 civ[d] += shift;
1396 civ.coarsen(mglevel_m[level]->refinement());
1397
1398 // we need boundary + indices from coarser level
1399 // we need normalization by mesh size squared (of fine cell size)
1400 // --> Laplacian for fine cell
1401 // (Dirichlet boundary for coarse --> fine)
1402 interface_mp->coarse(civ, map, invdx2[d], d, shift, cfab,
1403 iv, mglevel_m[level-1].get());
1404 }
1405#ifndef NDEBUG
1406 else if ( mfab(niv) == AmrMultiGridLevel_t::Mask::PHYSBNDRY ) {
1407 throw OpalException("AmrMultiGrid::buildCrseBoundaryMatrix_m()",
1408 "Fine meshes shouldn't be connected "
1409 "to physical (i.e. mesh) boundary!");
1410 }
1411#endif
1412 }
1413 }
1414
1415 this->map2vector_m(map, indices, values);
1416
1417 if (!indices.empty()) {
1418 mglevel_m[level]->Bcrse_p->insertGlobalValues(gidx,
1419 indices.size(),
1420 values.data(),
1421 indices.data());
1422 }
1423}
1424
1425
1427 const go_t& gidx,
1428 const AmrIntVect_t& iv,
1429 const basefab_t& mfab,
1430 const basefab_t& rfab)
1431{
1432 /* fine: level + 1
1433 * coarse (this): level
1434 */
1435
1436 // the finest level does not need data from a finer level
1437 if ( rfab(iv) == AmrMultiGridLevel_t::Refined::YES || level == lfine_m )
1438 return;
1439
1440 const scalar_t* invcdx = mglevel_m[level]->invCellSize();
1441 const scalar_t* invfdx = mglevel_m[level+1]->invCellSize();
1442
1443 // inverse of number of fine cell gradients
1444 scalar_t invavg = AMREX_D_PICK(1, 0.5, 0.25);
1445
1446 umap_t map;
1447 indices_t indices;
1448 coefficients_t values;
1449
1450 auto fill = [&](umap_t& map,
1451 D_DECL(int ii, int jj, int kk),
1452 int* begin, int* end, int d,
1453 const AmrIntVect_t& iv, int shift)
1454 {
1455 for (int iref = ii - begin[0]; iref <= ii + end[0]; ++iref) {
1456 for (int jref = jj - begin[1]; jref <= jj + end[1]; ++jref) {
1457#if AMREX_SPACEDIM == 3
1458 for (int kref = kk - begin[2]; kref <= kk + end[2]; ++kref) {
1459#endif
1460 /* Since all fine cells on the not-refined cell are
1461 * outside of the "domain" --> we need to interpolate
1462 */
1463 AmrIntVect_t riv(D_DECL(iref, jref, kref));
1464
1465 if ( (riv[d] >> 1) /*refinement*/ == iv[d] ) {
1466 /* the fine cell is on the coarse side --> fine
1467 * ghost cell --> we need to interpolate
1468 */
1469 scalar_t value = - invavg * invcdx[d] * invfdx[d];
1470
1471 interface_mp->fine(riv, map, value, d, shift,
1472 mglevel_m[level+1].get());
1473 } else {
1474 scalar_t value = invavg * invcdx[d] * invfdx[d];
1475 map[mglevel_m[level+1]->serialize(riv)] += value;
1476 }
1477#if AMREX_SPACEDIM == 3
1478 }
1479#endif
1480 }
1481 }
1482 };
1483
1484
1485 /*
1486 * iv is a coarse cell that got not refined
1487 *
1488 * --> check all neighbours to see if at crse-fine
1489 * interface
1490 */
1491 for (int d = 0; d < AMREX_SPACEDIM; ++d) {
1492 for (int shift = -1; shift <= 1; shift += 2) {
1493 // neighbour
1494 AmrIntVect_t covered = iv;
1495 covered[d] += shift;
1496
1497 if ( rfab(covered) == AmrMultiGridLevel_t::Refined::YES &&
1498 mfab(covered) != AmrMultiGridLevel_t::PHYSBNDRY )
1499 {
1500 // neighbour is covered by fine cells
1501
1502 /*
1503 * "shift" is the amount to a coarse cell that got refined
1504 * "d" is the direction to shift
1505 *
1506 * --> check all covered neighbour cells
1507 */
1508
1509 /* we need to iterate over correct fine cells. It depends
1510 * on the orientation of the interface
1511 */
1512 int begin[AMREX_SPACEDIM] = { D_DECL( int(d == 0), int(d == 1), int(d == 2) ) };
1513 int end[AMREX_SPACEDIM] = { D_DECL( int(d != 0), int(d != 1), int(d != 2) ) };
1514
1515 /*
1516 * neighbour cell got refined but is not on physical boundary
1517 * --> we are at a crse-fine interface
1518 *
1519 * we need now to find out which fine cells
1520 * are required to satisfy the flux matching
1521 * condition
1522 */
1523
1524 switch ( shift ) {
1525 case -1:
1526 {
1527 // --> interface is on the lower face
1528 int ii = iv[0] << 1; // refinemet in x
1529 int jj = iv[1] << 1; // refinemet in y
1530#if AMREX_SPACEDIM == 3
1531 int kk = iv[2] << 1; // refinemet in z
1532#endif
1533 // iterate over all fine cells at the interface
1534 // start with lower cells --> cover coarse neighbour
1535 // cell
1536 fill(map, D_DECL(ii, jj, kk), &begin[0], &end[0], d, iv, shift);
1537 break;
1538 }
1539 case 1:
1540 default:
1541 {
1542 // --> interface is on the upper face
1543 int ii = covered[0] << 1; // refinemet in x
1544 int jj = covered[1] << 1; // refinemet in y
1545#if AMREX_SPACEDIM == 3
1546 int kk = covered[2] << 1; // refinemet in z
1547#endif
1548 fill(map, D_DECL(ii, jj, kk), &begin[0], &end[0], d, iv, shift);
1549 break;
1550 }
1551 }
1552 }
1553 }
1554 }
1555
1556 this->map2vector_m(map, indices, values);
1557
1558 // iv: not covered coarse cell at crse-fine interface
1559
1560 if (!indices.empty()) {
1561 mglevel_m[level]->Bfine_p->insertGlobalValues(gidx,
1562 indices.size(),
1563 values.data(),
1564 indices.data());
1565 }
1566}
1567
1568
1570 const AmrField_t& rho)
1571{
1572 this->amrex2trilinos_m(level, 0, rho, mglevel_m[level]->rho_p);
1573}
1574
1575
1577 const AmrField_t& phi)
1578{
1579 this->amrex2trilinos_m(level, 0, phi, mglevel_m[level]->phi_p);
1580}
1581
1582
1584 const go_t& gidx,
1585 const AmrIntVect_t& iv,
1586 const basefab_t& mfab,
1587 const scalar_t* invdx)
1588{
1589 umap_t map;
1590 indices_t indices;
1591 coefficients_t values;
1592
1593 auto check = [&](const AmrIntVect_t& iv,
1594 const basefab_t& mfab,
1595 int dir,
1596 scalar_t shift)
1597 {
1598 switch ( mfab(iv) )
1599 {
1601 // interior cells
1603 // covered --> interior cell
1604 map[mglevel_m[level]->serialize(iv)] -= shift * 0.5 * invdx[dir];
1605 break;
1607 {
1608 // interior boundary cells --> only level > 0
1609#ifndef NDEBUG
1610 if ( level == lbase_m )
1611 throw OpalException("AmrMultiGrid::buildGradientMatrix_m()",
1612 "Error in mask for level "
1613 + std::to_string(level) + "!");
1614#endif
1615
1616 scalar_t value = - shift * 0.5 * invdx[dir];
1617
1618 // use 1st order Lagrange --> only cells of this level required
1619 AmrIntVect_t tmp = iv;
1620 // first fine cell on refined coarse cell (closer to interface)
1621 tmp[dir] -= shift;
1622 map[mglevel_m[level]->serialize(tmp)] += 2.0 * value;
1623
1624 // second fine cell on refined coarse cell (further away from interface)
1625 tmp[dir] -= shift;
1626 map[mglevel_m[level]->serialize(tmp)] -= value;
1627 break;
1628 }
1630 {
1631 // physical boundary cells
1632
1633 scalar_t value = - shift * 0.5 * invdx[dir];
1634
1635 mglevel_m[level]->applyBoundary(iv, dir,
1636 map, value);
1637 break;
1638 }
1639 default:
1640 break;
1641 }
1642 };
1643
1644 for (int d = 0; d < AMREX_SPACEDIM; ++d) {
1645 for (int shift = -1; shift <= 1; shift += 2) {
1646 AmrIntVect_t niv = iv;
1647 niv[d] += shift;
1648 check(niv, mfab, d, shift);
1649 }
1650
1651 this->map2vector_m(map, indices, values);
1652
1653 if (!indices.empty()) {
1654 mglevel_m[level]->G_p[d]->insertGlobalValues(gidx,
1655 indices.size(),
1656 values.data(),
1657 indices.data());
1658 }
1659 }
1660}
1661
1662
1664 const lo_t& comp,
1665 const AmrField_t& mf,
1666 Teuchos::RCP<vector_t>& mv)
1667{
1668 if ( mv.is_null() )
1669 mv = Teuchos::rcp( new vector_t(mglevel_m[level]->map_p, false) );
1670
1671 for (amrex::MFIter mfi(mf, true); mfi.isValid(); ++mfi) {
1672 const amrex::Box& tbx = mfi.tilebox();
1673 const amrex::FArrayBox& fab = mf[mfi];
1674
1675 const int* lo = tbx.loVect();
1676 const int* hi = tbx.hiVect();
1677
1678 for (int i = lo[0]; i <= hi[0]; ++i) {
1679 for (int j = lo[1]; j <= hi[1]; ++j) {
1680#if AMREX_SPACEDIM == 3
1681 for (int k = lo[2]; k <= hi[2]; ++k) {
1682#endif
1683 AmrIntVect_t iv(D_DECL(i, j, k));
1684
1685 go_t gidx = mglevel_m[level]->serialize(iv);
1686
1687 mv->replaceGlobalValue(gidx, fab(iv, comp));
1688#if AMREX_SPACEDIM == 3
1689 }
1690#endif
1691 }
1692 }
1693 }
1694}
1695
1696
1698 const lo_t& comp,
1699 AmrField_t& mf,
1700 const Teuchos::RCP<vector_t>& mv)
1701{
1702 Teuchos::ArrayRCP<const amr::scalar_t> data = mv->get1dView();
1703
1704 for (amrex::MFIter mfi(mf, true); mfi.isValid(); ++mfi) {
1705 const amrex::Box& tbx = mfi.tilebox();
1706 amrex::FArrayBox& fab = mf[mfi];
1707
1708 const int* lo = tbx.loVect();
1709 const int* hi = tbx.hiVect();
1710
1711 for (int i = lo[0]; i <= hi[0]; ++i) {
1712 for (int j = lo[1]; j <= hi[1]; ++j) {
1713#if AMREX_SPACEDIM == 3
1714 for (int k = lo[2]; k <= hi[2]; ++k) {
1715#endif
1716 AmrIntVect_t iv(D_DECL(i, j, k));
1717
1718 go_t gidx = mglevel_m[level]->serialize(iv);
1719 lo_t lidx = mglevel_m[level]->map_p->getLocalElement(gidx);
1720
1721 fab(iv, comp) = data[lidx];
1722 }
1723#if AMREX_SPACEDIM == 3
1724 }
1725#endif
1726 }
1727 }
1728}
1729
1730
1731inline
1733 coefficients_t& values)
1734{
1735 indices.clear();
1736 values.clear();
1737
1738 indices.reserve(map.size());
1739 values.reserve(map.size());
1740
1741 std::for_each(map.begin(), map.end(),
1742 [&](const std::pair<const go_t, scalar_t>& entry)
1743 {
1744#ifndef NDEBUG
1745 if ( entry.first < 0 ) {
1746 throw OpalException("AmrMultiGrid::map2vector_m()",
1747 "Negative matrix index!");
1748 }
1749#endif
1750
1751 indices.push_back(entry.first);
1752 values.push_back(entry.second);
1753 }
1754 );
1755
1756 map.clear();
1757}
1758
1759
1761 Teuchos::RCP<vector_t>& e,
1762 Teuchos::RCP<vector_t>& r)
1763{
1764#if AMR_MG_TIMER
1765 IpplTimings::startTimer(smoothTimer_m);
1766#endif
1767
1768 // base level has no smoother --> l - 1
1769 smoother_m[level-1]->smooth(e, r);
1770
1771#if AMR_MG_TIMER
1772 IpplTimings::stopTimer(smoothTimer_m);
1773#endif
1774}
1775
1776
1777void AmrMultiGrid::restrict_m(const lo_t& level) {
1778
1779#if AMR_MG_TIMER
1780 IpplTimings::startTimer(restrictTimer_m);
1781#endif
1782
1783 Teuchos::RCP<vector_t> tmp = Teuchos::rcp( new vector_t(mglevel_m[level]->map_p) );
1784
1785 this->residual_no_fine_m(level, tmp,
1786 mglevel_m[level]->error_p,
1787 mglevel_m[level-1]->error_p,
1788 mglevel_m[level]->residual_p);
1789
1790 mglevel_m[level-1]->residual_p->putScalar(0.0);
1791
1792 // average down: residual^(l-1) = R^(l) * tmp
1793 mglevel_m[level-1]->R_p->apply(*tmp, *mglevel_m[level-1]->residual_p);
1794
1795
1796 // composite matrix, i.e. matrix without covered cells
1797 // r^(l-1) = rho^(l-1) - A * phi^(l-1)
1798
1799 vector_t fine2crse(mglevel_m[level-1]->Awf_p->getDomainMap(), true);
1800
1801 // get boundary for
1802 mglevel_m[level-1]->Bfine_p->apply(*mglevel_m[level]->phi_p, fine2crse);
1803
1804 // operation: fine2coarse += A * phi
1805 mglevel_m[level-1]->Awf_p->apply(*mglevel_m[level-1]->phi_p,
1806 fine2crse, Teuchos::NO_TRANS,
1807 scalar_t(1.0), scalar_t(1.0));
1808
1809 if ( mglevel_m[level-1]->Bcrse_p != Teuchos::null ) {
1810 // operation: fine2coarse += B * phi
1811 mglevel_m[level-1]->Bcrse_p->apply(*mglevel_m[level-2]->phi_p,
1812 fine2crse, Teuchos::NO_TRANS,
1813 scalar_t(1.0), scalar_t(1.0));
1814 }
1815
1816 Teuchos::RCP<vector_t> uncoveredRho = Teuchos::rcp( new vector_t(mglevel_m[level-1]->map_p, true) );
1817
1818 mglevel_m[level-1]->UnCovered_p->apply(*mglevel_m[level-1]->rho_p, *uncoveredRho);
1819
1820
1821 //FIXME tmp2 not needed
1822 Teuchos::RCP<vector_t> tmp2 = Teuchos::rcp( new vector_t(mglevel_m[level-1]->map_p, true) );
1823 mglevel_m[level-1]->UnCovered_p->apply(fine2crse, *tmp2);
1824
1825 // ONLY subtract coarse rho
1826 mglevel_m[level-1]->residual_p->update(1.0, *uncoveredRho, -1.0, *tmp2, 1.0);
1827
1828#if AMR_MG_TIMER
1829 IpplTimings::stopTimer(restrictTimer_m);
1830#endif
1831}
1832
1833
1835#if AMR_MG_TIMER
1836 IpplTimings::startTimer(interpTimer_m);
1837#endif
1838 // interpolate error from l-1 to l
1839 // operation: e^(l) = 1.0 * e^(l) + 1.0 * I^(l) * e^(l-1)
1840 mglevel_m[level]->I_p->apply(*mglevel_m[level-1]->error_p,
1841 *mglevel_m[level]->error_p,
1842 Teuchos::NO_TRANS,
1843 scalar_t(1.0),
1844 scalar_t(1.0));
1845#if AMR_MG_TIMER
1846 IpplTimings::stopTimer(interpTimer_m);
1847#endif
1848}
1849
1850
1852
1853 if (level == lfine_m )
1854 return;
1855#if AMR_MG_TIMER
1856 IpplTimings::startTimer(averageTimer_m);
1857#endif
1858 Teuchos::RCP<vector_t> phicrse = Teuchos::rcp( new vector_t(mglevel_m[level]->map_p, false) );
1859
1860 // operation: phicrse = 0.0 * phicrse + 1.0 * R^(l) * phi^(l+1)
1861 mglevel_m[level]->R_p->apply(*mglevel_m[level+1]->phi_p, *phicrse);
1862
1863 Teuchos::RCP<vector_t> uncov_phi = Teuchos::rcp( new vector_t(mglevel_m[level]->map_p, true) );
1864
1865 mglevel_m[level]->UnCovered_p->apply(*mglevel_m[level]->phi_p, *uncov_phi);
1866
1867 mglevel_m[level]->phi_p->update(1.0, *phicrse, 1.0, *uncov_phi, 0.0);
1868#if AMR_MG_TIMER
1869 IpplTimings::stopTimer(averageTimer_m);
1870#endif
1871}
1872
1873
1875 switch ( interp ) {
1878 break;
1880 throw OpalException("AmrMultiGrid::initInterpolater_m()",
1881 "Not yet implemented.");
1884 break;
1885 default:
1886 throw OpalException("AmrMultiGrid::initInterpolater_m()",
1887 "No such interpolater available.");
1888 }
1889}
1890
1891
1893 switch ( interface ) {
1896 break;
1900 break;
1903 break;
1904 default:
1905 throw OpalException("AmrMultiGrid::initCrseFineInterp_m()",
1906 "No such interpolater for the coarse-fine interface available.");
1907 }
1908}
1909
1910
1912 const bool& rebalance,
1913 const std::string& reuse)
1914{
1915 switch ( solver ) {
1916 // Belos solvers
1918 solver_mp.reset( new BelosSolver_t("BICGSTAB", prec_mp) );
1919 break;
1920 case BaseSolver::MINRES:
1921 solver_mp.reset( new BelosSolver_t("MINRES", prec_mp) );
1922 break;
1923 case BaseSolver::PCPG:
1924 solver_mp.reset( new BelosSolver_t("PCPG", prec_mp) );
1925 break;
1926 case BaseSolver::CG:
1927 solver_mp.reset( new BelosSolver_t("Pseudoblock CG", prec_mp) );
1928 break;
1929 case BaseSolver::GMRES:
1930 solver_mp.reset( new BelosSolver_t("Pseudoblock GMRES", prec_mp) );
1931 break;
1933 solver_mp.reset( new BelosSolver_t("Stochastic CG", prec_mp) );
1934 break;
1936 solver_mp.reset( new BelosSolver_t("RCG", prec_mp) );
1937 break;
1939 solver_mp.reset( new BelosSolver_t("GCRODR", prec_mp) );
1940 break;
1941 // Amesos2 solvers
1942#ifdef HAVE_AMESOS2_KLU2
1943 case BaseSolver::KLU2:
1944 solver_mp.reset( new Amesos2Solver_t("klu2") );
1945 break;
1946#endif
1947#if HAVE_AMESOS2_SUPERLU
1948 case BaseSolver::SUPERLU:
1949 solver_mp.reset( new Amesos2Solver_t("superlu") );
1950 break;
1951#endif
1952#ifdef HAVE_AMESOS2_UMFPACK
1953 case BaseSolver::UMFPACK:
1954 solver_mp.reset( new Amesos2Solver_t("umfpack") );
1955 break;
1956#endif
1957#ifdef HAVE_AMESOS2_PARDISO_MKL
1958 case BaseSolver::PARDISO_MKL:
1959 solver_mp.reset( new Amesos2Solver_t("pardiso_mkl") );
1960 break;
1961#endif
1962#ifdef HAVE_AMESOS2_MUMPS
1963 case BaseSolver::MUMPS:
1964 solver_mp.reset( new Amesos2Solver_t("mumps") );
1965 break;
1966#endif
1967#ifdef HAVE_AMESOS2_LAPACK
1968 case BaseSolver::LAPACK:
1969 solver_mp.reset( new Amesos2Solver_t("lapack") );
1970 break;
1971#endif
1972 case BaseSolver::SA:
1973 {
1974 std::string muelu = MueLuSolver_t::convertToMueLuReuseOption(reuse);
1975 solver_mp.reset( new MueLuSolver_t(rebalance, muelu) );
1976 break;
1977 }
1978 default:
1979 throw OpalException("AmrMultiGrid::initBaseSolver_m()",
1980 "No such bottom solver available.");
1981 }
1982}
1983
1984
1986 const std::string& reuse)
1987{
1988 switch ( prec ) {
1989 case Preconditioner::ILUT:
1990 case Preconditioner::CHEBYSHEV:
1991 case Preconditioner::RILUK:
1992 case Preconditioner::JACOBI:
1993 case Preconditioner::BLOCK_JACOBI:
1994 case Preconditioner::GS:
1995 case Preconditioner::BLOCK_GS:
1996 prec_mp.reset( new Ifpack2Preconditioner_t(prec) );
1997 break;
1998 case Preconditioner::SA:
1999 {
2000 std::string muelu = MueLuPreconditioner_t::convertToMueLuReuseOption(reuse);
2001 prec_mp.reset( new MueLuPreconditioner_t(muelu) );
2002 break;
2003 }
2004 case Preconditioner::NONE:
2005 prec_mp.reset();
2006 break;
2007 default:
2008 throw OpalException("AmrMultiGrid::initPrec_m()",
2009 "No such preconditioner available.");
2010 }
2011}
2012
2013
2016 std::map<std::string, Boundary> map;
2017
2018 map["DIRICHLET"] = Boundary::DIRICHLET;
2019 map["OPEN"] = Boundary::OPEN;
2020 map["PERIODIC"] = Boundary::PERIODIC;
2021
2022 auto boundary = map.find(bc);
2023
2024 if ( boundary == map.end() )
2025 throw OpalException("AmrMultiGrid::convertToEnumBoundary_m()",
2026 "No boundary type '" + bc + "'.");
2027 return boundary->second;
2028}
2029
2032 std::map<std::string, Interpolater> map;
2033
2034 map["TRILINEAR"] = Interpolater::TRILINEAR;
2035 map["LAGRANGE"] = Interpolater::LAGRANGE;
2037
2038 auto interpolater = map.find(interp);
2039
2040 if ( interpolater == map.end() )
2041 throw OpalException("AmrMultiGrid::convertToEnumInterpolater_m()",
2042 "No interpolater '" + interp + "'.");
2043 return interpolater->second;
2044}
2045
2046
2048AmrMultiGrid::convertToEnumBaseSolver_m(const std::string& bsolver) {
2049 std::map<std::string, BaseSolver> map;
2050
2051 map["BICGSTAB"] = BaseSolver::BICGSTAB;
2052 map["MINRES"] = BaseSolver::MINRES;
2053 map["PCPG"] = BaseSolver::PCPG;
2054 map["CG"] = BaseSolver::CG;
2055 map["GMRES"] = BaseSolver::GMRES;
2056 map["STOCHASTIC_CG"] = BaseSolver::STOCHASTIC_CG;
2057 map["RECYCLING_CG"] = BaseSolver::RECYCLING_GMRES;
2058 map["RECYCLING_GMRES"] = BaseSolver::RECYCLING_GMRES;
2059#ifdef HAVE_AMESOS2_KLU2
2060 map["KLU2"] = BaseSolver::KLU2;
2061#endif
2062#ifdef HAVE_AMESOS2_SUPERLU
2063 map["SUPERLU"] = BaseSolver::SUPERLU;
2064#endif
2065#ifdef HAVE_AMESOS2_UMFPACK
2066 map["UMFPACK"] = BaseSolver::UMFPACK;
2067#endif
2068#ifdef HAVE_AMESOS2_PARDISO_MKL
2069 map["PARDISO_MKL"] = BaseSolver::PARDISO_MKL;
2070#endif
2071#ifdef HAVE_AMESOS2_MUMPS
2072 map["MUMPS"] = BaseSolver::MUMPS;
2073#endif
2074#ifdef HAVE_AMESOS2_LAPACK
2075 map["LAPACK"] = BaseSolver::LAPACK;
2076#endif
2077 map["SA"] = BaseSolver::SA;
2078
2079 auto solver = map.find(bsolver);
2080
2081 if ( solver == map.end() )
2082 throw OpalException("AmrMultiGrid::convertToEnumBaseSolver_m()",
2083 "No bottom solver '" + bsolver + "'.");
2084 return solver->second;
2085}
2086
2087
2090 std::map<std::string, Preconditioner> map;
2091
2092 map["NONE"] = Preconditioner::NONE;
2093
2095
2097
2098 auto precond = map.find(prec);
2099
2100 if ( precond == map.end() )
2101 throw OpalException("AmrMultiGrid::convertToEnumPreconditioner_m()",
2102 "No preconditioner '" + prec + "'.");
2103 return precond->second;
2104}
2105
2106
2108AmrMultiGrid::convertToEnumSmoother_m(const std::string& smoother) {
2109 return AmrSmoother::convertToEnumSmoother(smoother);
2110}
2111
2112
2114AmrMultiGrid::convertToEnumNorm_m(const std::string& norm) {
2115 std::map<std::string, Norm> map;
2116
2117 map["L1_NORM"] = Norm::L1;
2118 map["L2_NORM"] = Norm::L2;
2119 map["LINF_NORM"] = Norm::LINF;
2120
2121 auto n = map.find(norm);
2122
2123 if ( n == map.end() )
2124 throw OpalException("AmrMultiGrid::convertToEnumNorm_m()",
2125 "No norm '" + norm + "'.");
2126 return n->second;
2127}
2128
2129
2130void AmrMultiGrid::writeSDDSHeader_m(std::ofstream& outfile) {
2131 OPALTimer::Timer simtimer;
2132
2133 std::string dateStr(simtimer.date());
2134 std::string timeStr(simtimer.time());
2135 std::string indent(" ");
2136
2137 outfile << "SDDS1" << std::endl;
2138 outfile << "&description\n"
2139 << indent << "text=\"Solver statistics '" << OpalData::getInstance()->getInputFn()
2140 << "' " << dateStr << "" << timeStr << "\",\n"
2141 << indent << "contents=\"solver info\"\n"
2142 << "&end\n";
2143 outfile << "&parameter\n"
2144 << indent << "name=processors,\n"
2145 << indent << "type=long,\n"
2146 << indent << "description=\"Number of Cores used\"\n"
2147 << "&end\n";
2148 outfile << "&parameter\n"
2149 << indent << "name=revision,\n"
2150 << indent << "type=string,\n"
2151 << indent << "description=\"git revision of opal\"\n"
2152 << "&end\n";
2153 outfile << "&parameter\n"
2154 << indent << "name=flavor,\n"
2155 << indent << "type=string,\n"
2156 << indent << "description=\"OPAL flavor that wrote file\"\n"
2157 << "&end\n";
2158 outfile << "&column\n"
2159 << indent << "name=t,\n"
2160 << indent << "type=double,\n"
2161 << indent << "units=ns,\n"
2162 << indent << "description=\"1 Time\"\n"
2163 << "&end\n";
2164 outfile << "&column\n"
2165 << indent << "name=mg_iter,\n"
2166 << indent << "type=long,\n"
2167 << indent << "units=1,\n"
2168 << indent << "description=\"2 Number of Multigrid Iterations\"\n"
2169 << "&end\n";
2170 outfile << "&column\n"
2171 << indent << "name=bottom_iter,\n"
2172 << indent << "type=long,\n"
2173 << indent << "units=1,\n"
2174 << indent << "description=\"3 Total Number of Bottom Solver Iterations\"\n"
2175 << "&end\n";
2176 outfile << "&column\n"
2177 << indent << "name=regrid,\n"
2178 << indent << "type=bool,\n"
2179 << indent << "units=1,\n"
2180 << indent << "description=\"4 Regrid Step\"\n"
2181 << "&end\n";
2182 outfile << "&column\n"
2183 << indent << "name=" + snorm_m + ",\n"
2184 << indent << "type=double,\n"
2185 << indent << "units=1,\n"
2186 << indent << "description=\"5 Error\"\n"
2187 << "&end\n"
2188 << "&data\n"
2189 << indent << "mode=ascii,\n"
2190 << indent << "no_row_counts=1\n"
2191 << "&end\n"
2192 << comm_mp->getSize() << '\n'
2193 << OPAL_PROJECT_NAME << " " << OPAL_PROJECT_VERSION << " git rev. #" << Util::getGitRevision() << '\n'
2194 << (OpalData::getInstance()->isInOPALTMode()? "opal-t":
2195 (OpalData::getInstance()->isInOPALCyclMode()? "opal-cycl": "opal-map")) << std::endl;
2196}
2197
2198
2200#if AMR_MG_TIMER
2201 IpplTimings::startTimer(dumpTimer_m);
2202#endif
2203 unsigned int pwi = 10;
2204
2205 std::ofstream outfile;
2206
2207 if ( comm_mp->getRank() == 0 ) {
2208 outfile.open(fname_m.c_str(), flag_m);
2209 outfile.precision(15);
2210 outfile.setf(std::ios::scientific, std::ios::floatfield);
2211
2212 if ( flag_m == std::ios::out ) {
2213 flag_m = std::ios::app;
2214 writeSDDSHeader_m(outfile);
2215 }
2216
2217 outfile << itsAmrObject_mp->getT() * Units::s2ns << std::setw(pwi) << '\t' // 1
2218 << this->nIter_m << std::setw(pwi) << '\t' // 2
2219 << this->bIter_m << std::setw(pwi) << '\t' // 3
2220 << this->regrid_m << std::setw(pwi) << '\t' // 4
2221 << error << '\n'; // 5
2222 }
2223#if AMR_MG_TIMER
2224 IpplTimings::stopTimer(dumpTimer_m);
2225#endif
2226}
2227
2228
2229#if AMR_MG_TIMER
2230void AmrMultiGrid::initTimer_m() {
2231 buildTimer_m = IpplTimings::getTimer("AMR MG matrix setup");
2232 restrictTimer_m = IpplTimings::getTimer("AMR MG restrict");
2233 smoothTimer_m = IpplTimings::getTimer("AMR MG smooth");
2234 interpTimer_m = IpplTimings::getTimer("AMR MG prolongate");
2235 efieldTimer_m = IpplTimings::getTimer("AMR MG e-field");
2236 averageTimer_m = IpplTimings::getTimer("AMR MG average down");
2237 bottomTimer_m = IpplTimings::getTimer("AMR MG bottom-solver");
2238 dumpTimer_m = IpplTimings::getTimer("AMR MG dump");
2239}
2240#endif
2241
2242
2243double AmrMultiGrid::getXRangeMin(unsigned short level) {
2244 return itsAmrObject_mp->Geom(level).ProbLo(0);
2245}
2246
2247
2248double AmrMultiGrid::getXRangeMax(unsigned short level) {
2249 return itsAmrObject_mp->Geom(level).ProbHi(0);
2250}
2251
2252
2253double AmrMultiGrid::getYRangeMin(unsigned short level) {
2254 return itsAmrObject_mp->Geom(level).ProbLo(1);
2255}
2256
2257
2258double AmrMultiGrid::getYRangeMax(unsigned short level) {
2259 return itsAmrObject_mp->Geom(level).ProbHi(1);
2260}
2261
2262
2263double AmrMultiGrid::getZRangeMin(unsigned short level) {
2264 return itsAmrObject_mp->Geom(level).ProbLo(2);
2265}
2266
2267
2268double AmrMultiGrid::getZRangeMax(unsigned short level) {
2269 return itsAmrObject_mp->Geom(level).ProbHi(2);
2270}
2271
2272
2274 os << "* ********************* A M R M u l t i G r i d ********************** " << endl
2275 //FIXME
2276 << "* ******************************************************************** " << endl;
2277 return os;
2278}
amr::AmrScalarFieldContainer_t AmrScalarFieldContainer_t
Definition PBunchDefs.h:35
amr::AmrVectorFieldContainer_t AmrVectorFieldContainer_t
Definition PBunchDefs.h:36
PartBunchBase< T, Dim >::ConstIterator end(PartBunchBase< T, Dim > const &bunch)
PartBunchBase< T, Dim >::ConstIterator begin(PartBunchBase< T, Dim > const &bunch)
#define INFOMSG(msg)
Definition IpplInfo.h:348
Inform & endl(Inform &inf)
Definition Inform.cpp:42
void serialize(Param_t params, std::ostringstream &os)
serializes params to a text stream, replaces boost::serialization
Definition MPIHelper.cpp:46
constexpr double s2ns
Definition Units.h:44
std::string getGitRevision()
Definition Util.cpp:38
The global OPAL structure.
Definition OpalData.h:49
bool isInOPALTMode()
Definition OpalData.cpp:276
bool isInOPALCyclMode()
Definition OpalData.cpp:272
std::string getInputFn()
get opals input filename
Definition OpalData.cpp:670
static OpalData * getInstance()
Definition OpalData.cpp:196
const Vector_t & getMeshScaling() const
double getT() const override
void trilinos2amrex_m(const lo_t &level, const lo_t &comp, AmrField_t &mf, const Teuchos::RCP< vector_t > &mv)
void buildCrseBoundaryMatrix_m(const lo_t &level, const go_t &gidx, const AmrIntVect_t &iv, const basefab_t &mfab, const basefab_t &cfab, const scalar_t *invdx2)
amrex::BaseFab< int > basefab_t
void relax_m(const lo_t &level)
void initGuess_m(bool reset)
void close_m(const lo_t &level, const bool &matrices)
AmrMultiGrid(AmrBoxLib *itsAmrObject_p, const std::string &bsolver, const std::string &prec, const bool &rebalance, const std::string &reuse, const std::string &bcx, const std::string &bcy, const std::string &bcz, const std::string &smoother, const std::size_t &nSweeps, const std::string &interp, const std::string &norm)
double getZRangeMax(unsigned short level=0)
void restrict_m(const lo_t &level)
Boundary
Supported physical boundaries.
Boundary convertToEnumBoundary_m(const std::string &bc)
std::shared_ptr< bsolver_t > solver_mp
bottom solver
BaseSolver convertToEnumBaseSolver_m(const std::string &bsolver)
void setup_m(const amrex::Vector< AmrField_u > &rho, const amrex::Vector< AmrField_u > &phi, const bool &matrices=true)
double getXRangeMin(unsigned short level=0)
void initPhysicalBoundary_m(const Boundary *bc)
AmrMultiGridLevel_t::coefficients_t coefficients_t
Teuchos::RCP< comm_t > comm_mp
communicator
std::string fname_m
SDDS filename.
BaseSolver
Supported bottom solvers.
AmrMultiGridLevel_t::umap_t umap_t
amrex::FArrayBox farraybox_t
std::string snorm_m
norm for convergence criteria
std::size_t nSweeps_m
number of smoothing iterations
void map2vector_m(umap_t &map, indices_t &indices, coefficients_t &values)
void buildFineBoundaryMatrix_m(const lo_t &level, const go_t &gidx, const AmrIntVect_t &iv, const basefab_t &mfab, const basefab_t &rfab)
void writeSDDSHeader_m(std::ofstream &outfile)
std::vector< std::unique_ptr< AmrMultiGridLevel_t > > mglevel_m
container for levels
void amrex2trilinos_m(const lo_t &level, const lo_t &comp, const AmrField_t &mf, Teuchos::RCP< vector_t > &mv)
scalar_t getLevelResidualNorm(lo_t level)
scalar_t evalNorm_m(const Teuchos::RCP< const vector_t > &x)
void buildSingleLevel_m(const amrex::Vector< AmrField_u > &rho, const amrex::Vector< AmrField_u > &phi, const bool &matrices=true)
int lbase_m
base level (currently only 0 supported)
void initPrec_m(const Preconditioner &prec, const std::string &reuse)
void setVerbose(bool verbose)
void initInterpolater_m(const Interpolater &interp)
amr::comm_t comm_t
std::unique_ptr< AmrInterpolater< AmrMultiGridLevel_t > > interp_mp
interpolater without coarse-fine interface
amr::scalar_t scalar_t
scalar_t iterate_m()
void buildGradientMatrix_m(const lo_t &level, const go_t &gidx, const AmrIntVect_t &iv, const basefab_t &mfab, const scalar_t *invdx)
BelosBottomSolver< AmrMultiGridLevel_t > BelosSolver_t
void initCrseFineInterp_m(const Interpolater &interface)
std::shared_ptr< preconditioner_t > prec_mp
preconditioner for bottom solver
amrex::Box box_t
std::unique_ptr< AmrInterpolater< AmrMultiGridLevel_t > > interface_mp
interpolater for coarse-fine interface
Norm convertToEnumNorm_m(const std::string &norm)
Interpolater convertToEnumInterpolater_m(const std::string &interp)
amr::global_ordinal_t go_t
void averageDown_m(const lo_t &level)
amr::matrix_t matrix_t
Smoother convertToEnumSmoother_m(const std::string &smoother)
double getZRangeMin(unsigned short level=0)
amr::vector_t vector_t
Amesos2BottomSolver< AmrMultiGridLevel_t > Amesos2Solver_t
void buildPotentialVector_m(const lo_t &level, const AmrField_t &phi)
void residual_no_fine_m(const lo_t &level, Teuchos::RCP< vector_t > &result, const Teuchos::RCP< vector_t > &rhs, const Teuchos::RCP< vector_t > &crs_rhs, const Teuchos::RCP< vector_t > &b)
scalar_t eps_m
rhs scale for convergence
AmrMultiGridLevel_t::AmrField_t AmrField_t
std::size_t nIter_m
number of iterations till convergence
int lfine_m
fineste level
double getXRangeMax(unsigned short level=0)
Inform & print(Inform &os) const
AmrMultiGridLevel_t::AmrIntVect_t AmrIntVect_t
bool verbose_m
If true, a SDDS file is written.
std::size_t bIter_m
number of iterations of bottom solver
int nlevel_m
number of levelss
amr::local_ordinal_t lo_t
std::ios_base::openmode flag_m
std::ios::out or std::ios::app
void setNumberOfSweeps(const std::size_t &nSweeps)
void initResidual_m(std::vector< scalar_t > &rhsNorms, std::vector< scalar_t > &resNorms)
void buildMultiLevel_m(const amrex::Vector< AmrField_u > &rho, const amrex::Vector< AmrField_u > &phi, const bool &matrices=true)
void open_m(const lo_t &level, const bool &matrices)
void buildDensityVector_m(const lo_t &level, const AmrField_t &rho)
MueLuPreconditioner< AmrMultiGridLevel_t > MueLuPreconditioner_t
AmrMultiGridLevel< matrix_t, vector_t > AmrMultiGridLevel_t
std::size_t getNumIters()
std::size_t maxiter_m
maximum number of iterations allowed
void buildNoFinePoissonMatrix_m(const lo_t &level, const go_t &gidx, const AmrIntVect_t &iv, const basefab_t &mfab, const scalar_t *invdx2)
double getYRangeMin(unsigned short level=0)
void writeSDDSData_m(const scalar_t &error)
int nBcPoints_m
maximum number of stencils points for BC
void setMaxNumberOfIterations(const std::size_t &maxiter)
void initBaseSolver_m(const BaseSolver &solver, const bool &rebalance, const std::string &reuse)
Smoother smootherType_m
type of smoother
Norm
Supported convergence criteria.
void initLevels_m(const amrex::Vector< AmrField_u > &rho, const amrex::Vector< AmrGeometry_t > &geom, bool regrid)
void smooth_m(const lo_t &level, Teuchos::RCP< vector_t > &e, Teuchos::RCP< vector_t > &r)
Ifpack2Preconditioner< AmrMultiGridLevel_t > Ifpack2Preconditioner_t
boundary_t bc_m[AMREX_SPACEDIM]
boundary conditions
void residual_m(const lo_t &level, Teuchos::RCP< vector_t > &r, const Teuchos::RCP< vector_t > &b, const Teuchos::RCP< vector_t > &x)
std::vector< std::shared_ptr< AmrSmoother > > smoother_m
error smoother
void buildInterpolationMatrix_m(const lo_t &level, const go_t &gidx, const AmrIntVect_t &iv, const basefab_t &cfab)
void computeEfield_m(AmrVectorFieldContainer_t &efield)
AmrMultiGridLevel_t::indices_t indices_t
Interpolater
Supported interpolaters for prolongation operation.
void prolongate_m(const lo_t &level)
bool isConverged_m(std::vector< scalar_t > &rhsNorms, std::vector< scalar_t > &resNorms)
Norm norm_m
norm for convergence criteria (l1, l2, linf)
double getYRangeMax(unsigned short level=0)
void setTolerance(const scalar_t &eps)
void solve(AmrScalarFieldContainer_t &rho, AmrScalarFieldContainer_t &phi, AmrVectorFieldContainer_t &efield, unsigned short baseLevel, unsigned short finestLevel, bool prevAsGuess=true)
MueLuBottomSolver< AmrMultiGridLevel_t > MueLuSolver_t
void buildRestrictionMatrix_m(const lo_t &level, const go_t &gidx, const AmrIntVect_t &iv, D_DECL(const go_t &ii, const go_t &jj, const go_t &kk), const basefab_t &rfab)
Preconditioner convertToEnumPreconditioner_m(const std::string &prec)
void buildCompositePoissonMatrix_m(const lo_t &level, const go_t &gidx, const AmrIntVect_t &iv, const basefab_t &mfab, const basefab_t &rfab, const scalar_t *invdx2)
amrex::FabArray< basefab_t > mask_t
Smoother
All supported Ifpack2 smoothers.
Definition AmrSmoother.h:46
static Smoother convertToEnumSmoother(const std::string &smoother)
static void fillMap(map_t &map)
static std::string convertToMueLuReuseOption(const std::string &reuse)
static std::string convertToMueLuReuseOption(const std::string &reuse)
static void fillMap(map_t &map)
bool regrid_m
is set to true by itsAmrObject_mp and reset to false by solver
The base class for all OPAL exceptions.
std::string date() const
Return date.
Definition Timer.cpp:35
std::string time() const
Return time.
Definition Timer.cpp:42
static TimerRef getTimer(const char *nm)
static void stopTimer(TimerRef t)
static void startTimer(TimerRef t)