Block-Structured AMR Software Framework
Loading...
Searching...
No Matches
AMReX_MLCellABecLap.H
Go to the documentation of this file.
1#ifndef AMREX_ML_CELL_ABECLAP_H_
2#define AMREX_ML_CELL_ABECLAP_H_
3#include <AMReX_Config.H>
4
5#include <AMReX_MLCellLinOp.H>
6#include <AMReX_MLCellABecLap_K.H>
7
8namespace amrex {
9
18template <typename MF>
20class MLCellABecLapT // NOLINT(cppcoreguidelines-virtual-class-destructor)
21 : public MLCellLinOpT<MF>
22{
23public:
24
25 using FAB = typename MF::fab_type;
26 using RT = typename MF::value_type;
27
29
30 MLCellABecLapT () = default;
31 ~MLCellABecLapT () override = default;
32
37
47 void define (const Vector<Geometry>& a_geom,
48 const Vector<BoxArray>& a_grids,
49 const Vector<DistributionMapping>& a_dmap,
50 const LPInfo& a_info = LPInfo(),
51 const Vector<FabFactory<FAB> const*>& a_factory = {});
52
63 void define (const Vector<Geometry>& a_geom,
64 const Vector<BoxArray>& a_grids,
65 const Vector<DistributionMapping>& a_dmap,
66 const Vector<iMultiFab const*>& a_overset_mask,
67 const LPInfo& a_info = LPInfo(),
68 const Vector<FabFactory<FAB> const*>& a_factory = {});
69
71 [[nodiscard]] iMultiFab const* getOversetMask (int amrlev, int mglev) const {
72 return m_overset_mask[amrlev][mglev].get();
73 }
74
75 [[nodiscard]] bool needsUpdate () const override {
77 }
79 void update () override;
80
82 void prepareForSolve () override;
83
88 void setDirichletNodesToZero (int amrlev, int mglev, MF& mf) const override;
89
97 void getFluxes (const Vector<Array<MF*,AMREX_SPACEDIM> >& a_flux,
98 const Vector<MF*>& a_sol,
99 Location a_loc) const final;
104 void getFluxes (const Vector<MF*>& a_flux,
105 const Vector<MF*>& a_sol) const final {
106 amrex::ignore_unused(a_flux, a_sol);
107 amrex::Abort("MLCellABecLap::getFluxes: How did we get here?");
108 }
109
111 virtual RT getAScalar () const = 0;
113 virtual RT getBScalar () const = 0;
115 virtual MF const* getACoeffs (int amrlev, int mglev) const = 0;
117 virtual Array<MF const*,AMREX_SPACEDIM> getBCoeffs (int amrlev, int mglev) const = 0;
118
120 void applyInhomogNeumannTerm (int amrlev, MF& rhs) const final;
121
124 int amrlev, const Array<MF*,AMREX_SPACEDIM>& grad,
125 MF const& sol, bool mult_bcoef) const final;
126
128 void applyOverset (int amrlev, MF& rhs) const override;
129
130#if defined(AMREX_USE_HYPRE) && (AMREX_SPACEDIM > 1)
132 [[nodiscard]] std::unique_ptr<Hypre> makeHypre (Hypre::Interface hypre_interface) const override;
133#endif
134
135#if defined(AMREX_USE_PETSC) && (AMREX_SPACEDIM > 1)
137 [[nodiscard]] std::unique_ptr<PETScABecLap> makePETSc () const override;
138#endif
139
140protected:
142
144
145 [[nodiscard]] bool supportInhomogNeumannBC () const noexcept override { return true; }
146};
147
148template <typename MF>
149void
151 const Vector<BoxArray>& a_grids,
152 const Vector<DistributionMapping>& a_dmap,
153 const LPInfo& a_info,
154 const Vector<FabFactory<FAB> const*>& a_factory)
155{
156 MLCellLinOpT<MF>::define(a_geom, a_grids, a_dmap, a_info, a_factory);
157
158 this->m_overset_mask.resize(this->m_num_amr_levels);
159 for (int amrlev = 0; amrlev < this->m_num_amr_levels; ++amrlev) {
160 this->m_overset_mask[amrlev].resize(this->m_num_mg_levels[amrlev]);
161 }
162}
163
164template <typename MF>
165void
167 const Vector<BoxArray>& a_grids,
168 const Vector<DistributionMapping>& a_dmap,
169 const Vector<iMultiFab const*>& a_overset_mask,
170 const LPInfo& a_info,
171 const Vector<FabFactory<FAB> const*>& a_factory)
172{
173 BL_PROFILE("MLCellABecLap::define(overset)");
174
175 AMREX_ALWAYS_ASSERT(!this->hasHiddenDimension());
176
177 this->m_lpinfo_arg = a_info;
178
179 auto namrlevs = static_cast<int>(a_geom.size());
180 this->m_overset_mask.resize(namrlevs);
181 for (int amrlev = 0; amrlev < namrlevs; ++amrlev)
182 {
183 this->m_overset_mask[amrlev].push_back(std::make_unique<iMultiFab>(a_grids[amrlev],
184 a_dmap[amrlev], 1, 1));
185 iMultiFab::Copy(*(this->m_overset_mask[amrlev][0]), *a_overset_mask[amrlev], 0, 0, 1, 0);
186 if (amrlev > 1) {
187 AMREX_ALWAYS_ASSERT(amrex::refine(a_geom[amrlev-1].Domain(),2)
188 == a_geom[amrlev].Domain());
189 }
190 }
191
192 int amrlev = 0;
193 Box dom = a_geom[0].Domain();
194 for (int mglev = 1; mglev <= a_info.max_coarsening_level; ++mglev)
195 {
196 AMREX_ALWAYS_ASSERT(this->mg_coarsen_ratio == 2);
197 iMultiFab const& fine = *(this->m_overset_mask[amrlev][mglev-1]);
198 if (dom.coarsenable(2) && fine.boxArray().coarsenable(2)) {
199 dom.coarsen(2);
200 auto crse = std::make_unique<iMultiFab>(amrex::coarsen(fine.boxArray(),2),
201 fine.DistributionMap(), 1, 1);
202 ReduceOps<ReduceOpSum> reduce_op;
203 ReduceData<int> reduce_data(reduce_op);
204 using ReduceTuple = typename decltype(reduce_data)::Type;
205#ifdef AMREX_USE_OMP
206#pragma omp parallel if (Gpu::notInLaunchRegion())
207#endif
208 for (MFIter mfi(*crse, TilingIfNotGPU()); mfi.isValid(); ++mfi)
209 {
210 const Box& bx = mfi.tilebox();
211 Array4<int const> const& fmsk = fine.const_array(mfi);
212 Array4<int> const& cmsk = crse->array(mfi);
213 reduce_op.eval(bx, reduce_data,
214 [=] AMREX_GPU_HOST_DEVICE (Box const& b) -> ReduceTuple
215 {
216 return { coarsen_overset_mask(b, cmsk, fmsk) };
217 });
218 }
219 ReduceTuple hv = reduce_data.value(reduce_op);
220 if (amrex::get<0>(hv) == 0) {
221 this->m_overset_mask[amrlev].push_back(std::move(crse));
222 } else {
223 break;
224 }
225 } else {
226 break;
227 }
228 }
229 int max_overset_mask_coarsening_level = this->m_overset_mask[amrlev].size()-1;
230 ParallelAllReduce::Min(max_overset_mask_coarsening_level, ParallelContext::CommunicatorSub());
231 this->m_overset_mask[amrlev].resize(max_overset_mask_coarsening_level+1);
232
233 LPInfo linfo = a_info;
234 linfo.max_coarsening_level = std::min(a_info.max_coarsening_level,
235 max_overset_mask_coarsening_level);
236 // The overset masks above are coarsened isotropically by 2, so the MG
237 // levels must be too, or the masks and the grids end up in different
238 // index spaces.
239 linfo.do_semicoarsening = false;
240
241 MLCellLinOpT<MF>::define(a_geom, a_grids, a_dmap, linfo, a_factory);
242
243 amrlev = 0;
244 for (int mglev = 1; mglev < this->m_num_mg_levels[amrlev]; ++mglev) {
245 MF foo(this->m_grids[amrlev][mglev], this->m_dmap[amrlev][mglev], 1, 0, MFInfo().SetAlloc(false));
246 if (! amrex::isMFIterSafe(*(this->m_overset_mask[amrlev][mglev]), foo)) {
247 auto osm = std::make_unique<iMultiFab>(this->m_grids[amrlev][mglev],
248 this->m_dmap[amrlev][mglev], 1, 1);
249 osm->ParallelCopy(*(this->m_overset_mask[amrlev][mglev]));
250 std::swap(osm, this->m_overset_mask[amrlev][mglev]);
251 }
252 }
253
254 for (amrlev = 1; amrlev < this->m_num_amr_levels; ++amrlev) {
255 for (int mglev = 1; mglev < this->m_num_mg_levels[amrlev]; ++mglev) { // for ref_ratio 4
256 this->m_overset_mask[amrlev].push_back(std::make_unique<iMultiFab>(this->m_grids[amrlev][mglev],
257 this->m_dmap[amrlev][mglev],
258 1, 1));
259
260#ifdef AMREX_USE_GPU
261 if (Gpu::inLaunchRegion() && this->m_overset_mask[amrlev][mglev]->isFusingCandidate()) {
262 auto const& crsema = this->m_overset_mask[amrlev][mglev]->arrays();
263 auto const& finema = this->m_overset_mask[amrlev][mglev-1]->const_arrays();
264 ParallelFor(*(this->m_overset_mask[amrlev][mglev]),
265 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k) noexcept
266 {
267 coarsen_overset_mask(i,j,k, crsema[box_no], finema[box_no]);
268 });
269 if (!Gpu::inNoSyncRegion()) {
271 }
272 } else
273#endif
274 {
275#ifdef AMREX_USE_OMP
276#pragma omp parallel if (Gpu::notInLaunchRegion())
277#endif
278 for (MFIter mfi(*(this->m_overset_mask[amrlev][mglev]), TilingIfNotGPU()); mfi.isValid(); ++mfi)
279 {
280 const Box& bx = mfi.tilebox();
281 Array4<int> const& cmsk = this->m_overset_mask[amrlev][mglev]->array(mfi);
282 Array4<int const> const fmsk = this->m_overset_mask[amrlev][mglev-1]->const_array(mfi);
284 {
285 coarsen_overset_mask(i,j,k, cmsk, fmsk);
286 });
287 }
288 }
289 }
290 }
291
292 for (amrlev = 0; amrlev < this->m_num_amr_levels; ++amrlev) {
293 for (int mglev = 0; mglev < this->m_num_mg_levels[amrlev]; ++mglev) {
294 this->m_overset_mask[amrlev][mglev]->setBndry(1);
295 this->m_overset_mask[amrlev][mglev]->FillBoundary(this->m_geom[amrlev][mglev].periodicity());
296 }
297 }
298}
299
300template <typename MF>
301void
306
307template <typename MF>
308void
313
314template <typename MF>
315void
316MLCellABecLapT<MF>::setDirichletNodesToZero (int amrlev, int mglev, MF& mf) const
317{
318 auto const* omask = this->getOversetMask(amrlev, mglev);
319 if (omask) {
320 const int ncomp = this->getNComp();
321 auto const& mskma = omask->const_arrays();
322 auto const& ma = mf.arrays();
323 ParallelFor(mf, IntVect(0), ncomp,
324 [=] AMREX_GPU_DEVICE (int bno, int i, int j, int k, int n)
325 {
326 if (mskma[bno](i,j,k) == 0) { ma[bno](i,j,k,n) = RT(0.0); }
327 });
328 if (!Gpu::inNoSyncRegion()) {
330 }
331 }
332}
333
334template <typename MF>
335void
337 const Vector<MF*>& a_sol,
338 Location a_loc) const
339{
340 BL_PROFILE("MLMG::getFluxes()");
341
342 const int ncomp = this->getNComp();
343 const RT betainv = RT(1.0) / getBScalar();
344 const int nlevs = this->NAMRLevels();
345 // Without b coefficients, the metric factor is in the flux kernels, not in
346 // b, so it must be removed before the boundary faces are set using b = 1.
347 const bool has_bcoef = (getBCoeffs(0,0)[0] != nullptr);
348 for (int alev = 0; alev < nlevs; ++alev) {
349 this->compFlux(alev, a_flux[alev], *a_sol[alev], a_loc);
350 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
351 if (betainv != RT(1.0)) {
352 a_flux[alev][idim]->mult(betainv, 0, ncomp);
353 }
354 if (!has_bcoef) {
355 this->unapplyMetricTerm(alev, 0, *a_flux[alev][idim]);
356 }
357 }
358 this->addInhomogNeumannFlux(alev, a_flux[alev], *a_sol[alev], true);
359 if (has_bcoef) {
360 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
361 this->unapplyMetricTerm(alev, 0, *a_flux[alev][idim]);
362 }
363 }
364 }
365}
366
367template <typename MF>
368void
370{
371 bool has_inhomog_neumann = this->hasInhomogNeumannBC();
372 bool has_robin = this->hasRobinBC();
373
374 // A preconditioner must be linear, so it gets no inhomogeneous terms.
375 if (this->m_precond_mode) { return; }
376 if (!has_inhomog_neumann && !has_robin) { return; }
377
378 int ncomp = this->getNComp();
379 const int mglev = 0;
380
381 const auto problo = this->m_geom[amrlev][mglev].ProbLoArray();
382 const auto probhi = this->m_geom[amrlev][mglev].ProbHiArray();
383 amrex::ignore_unused(probhi);
384 const RT dxi = static_cast<RT>(this->m_geom[amrlev][mglev].InvCellSize(0));
385 const RT dyi = static_cast<RT>((AMREX_SPACEDIM >= 2) ? this->m_geom[amrlev][mglev].InvCellSize(1) : Real(1.0));
386 const RT dzi = static_cast<RT>((AMREX_SPACEDIM == 3) ? this->m_geom[amrlev][mglev].InvCellSize(2) : Real(1.0));
387 const RT xlo = static_cast<RT>(problo[0]);
388 const RT dx = static_cast<RT>(this->m_geom[amrlev][mglev].CellSize(0));
389 const Box& domain = this->m_geom[amrlev][mglev].Domain();
390
391 const RT beta = getBScalar();
392 Array<MF const*, AMREX_SPACEDIM> const& bcoef = getBCoeffs(amrlev,mglev);
393 FAB foo(Box(IntVect(0),IntVect(1)));
394 bool has_bcoef = (bcoef[0] != nullptr);
395
396 const auto& maskvals = this->m_maskvals[amrlev][mglev];
397 const auto& bcondloc = *(this->m_bcondloc[amrlev][mglev]);
398 const auto& bndry = *(this->m_bndry_sol[amrlev]);
399
400 MFItInfo mfi_info;
401 if (Gpu::notInLaunchRegion()) { mfi_info.SetDynamic(true); }
402
403#ifdef AMREX_USE_OMP
404#pragma omp parallel if (Gpu::notInLaunchRegion())
405#endif
406 for (MFIter mfi(rhs, mfi_info); mfi.isValid(); ++mfi)
407 {
408 const Box& vbx = mfi.validbox();
409 auto const& rhsfab = rhs.array(mfi);
410
411 const auto & bdlv = bcondloc.bndryLocs(mfi);
412 const auto & bdcv = bcondloc.bndryConds(mfi);
413
414 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim)
415 {
416 auto const bfab = (has_bcoef)
417 ? bcoef[idim]->const_array(mfi) : foo.const_array();
418 const Orientation olo(idim,Orientation::low);
419 const Orientation ohi(idim,Orientation::high);
420 const Box blo = amrex::adjCellLo(vbx, idim);
421 const Box bhi = amrex::adjCellHi(vbx, idim);
422 const auto& mlo = maskvals[olo].array(mfi);
423 const auto& mhi = maskvals[ohi].array(mfi);
424 const auto& bvlo = bndry.bndryValues(olo).array(mfi);
425 const auto& bvhi = bndry.bndryValues(ohi).array(mfi);
426 bool outside_domain_lo = !(domain.contains(blo));
427 bool outside_domain_hi = !(domain.contains(bhi));
428 if ((!outside_domain_lo) && (!outside_domain_hi)) { continue; }
429 for (int icomp = 0; icomp < ncomp; ++icomp) {
430 const BoundCond bctlo = bdcv[icomp][olo];
431 const BoundCond bcthi = bdcv[icomp][ohi];
432 const RT bcllo = bdlv[icomp][olo];
433 const RT bclhi = bdlv[icomp][ohi];
434 if (this->m_lobc_orig[icomp][idim] == LinOpBCType::inhomogNeumann && outside_domain_lo)
435 {
436 if (idim == 0) {
437 RT fac = beta*dxi;
438 if (this->m_has_metric_term && !has_bcoef) {
439#if (AMREX_SPACEDIM == 1)
440 fac *= static_cast<RT>(problo[0]*problo[0]);
441#elif (AMREX_SPACEDIM == 2)
442 fac *= static_cast<RT>(problo[0]);
443#endif
444 }
445 AMREX_HOST_DEVICE_FOR_3D(blo, i, j, k,
446 {
447 mllinop_apply_innu_xlo(i,j,k, rhsfab, mlo, bfab,
448 bctlo, bcllo, bvlo,
449 fac, has_bcoef, icomp);
450 });
451 } else if (idim == 1) {
452 RT fac = beta*dyi;
453 if (this->m_has_metric_term && !has_bcoef) {
454 AMREX_HOST_DEVICE_FOR_3D(blo, i, j, k,
455 {
456 mllinop_apply_innu_ylo_m(i,j,k, rhsfab, mlo,
457 bctlo, bcllo, bvlo,
458 fac, xlo, dx, icomp);
459 });
460 }
461 else {
462 AMREX_HOST_DEVICE_FOR_3D(blo, i, j, k,
463 {
464 mllinop_apply_innu_ylo(i,j,k, rhsfab, mlo, bfab,
465 bctlo, bcllo, bvlo,
466 fac, has_bcoef, icomp);
467 });
468 }
469 } else {
470 RT fac = beta*dzi;
471 AMREX_HOST_DEVICE_FOR_3D(blo, i, j, k,
472 {
473 mllinop_apply_innu_zlo(i,j,k, rhsfab, mlo, bfab,
474 bctlo, bcllo, bvlo,
475 fac, has_bcoef, icomp);
476 });
477 }
478 }
479 if (this->m_hibc_orig[icomp][idim] == LinOpBCType::inhomogNeumann && outside_domain_hi)
480 {
481 if (idim == 0) {
482 RT fac = beta*dxi;
483 if (this->m_has_metric_term && !has_bcoef) {
484#if (AMREX_SPACEDIM == 1)
485 fac *= static_cast<RT>(probhi[0]*probhi[0]);
486#elif (AMREX_SPACEDIM == 2)
487 fac *= static_cast<RT>(probhi[0]);
488#endif
489 }
490 AMREX_HOST_DEVICE_FOR_3D(bhi, i, j, k,
491 {
492 mllinop_apply_innu_xhi(i,j,k, rhsfab, mhi, bfab,
493 bcthi, bclhi, bvhi,
494 fac, has_bcoef, icomp);
495 });
496 } else if (idim == 1) {
497 RT fac = beta*dyi;
498 if (this->m_has_metric_term && !has_bcoef) {
499 AMREX_HOST_DEVICE_FOR_3D(bhi, i, j, k,
500 {
501 mllinop_apply_innu_yhi_m(i,j,k, rhsfab, mhi,
502 bcthi, bclhi, bvhi,
503 fac, xlo, dx, icomp);
504 });
505 } else {
506 AMREX_HOST_DEVICE_FOR_3D(bhi, i, j, k,
507 {
508 mllinop_apply_innu_yhi(i,j,k, rhsfab, mhi, bfab,
509 bcthi, bclhi, bvhi,
510 fac, has_bcoef, icomp);
511 });
512 }
513 } else {
514 RT fac = beta*dzi;
515 AMREX_HOST_DEVICE_FOR_3D(bhi, i, j, k,
516 {
517 mllinop_apply_innu_zhi(i,j,k, rhsfab, mhi, bfab,
518 bcthi, bclhi, bvhi,
519 fac, has_bcoef, icomp);
520 });
521 }
522 }
523
524 if (has_robin) {
525 // For Robin BC, see comments in AMReX_MLABecLaplacian.cpp above
526 // function applyRobinBCTermsCoeffs.
527 auto const& rbc = (*this->m_robin_bcval[amrlev])[mfi].const_array(icomp*3);
528 if (this->m_lobc_orig[icomp][idim] == LinOpBCType::Robin && outside_domain_lo)
529 {
530 if (idim == 0) {
531 RT fac = beta*dxi*dxi;
532 AMREX_HOST_DEVICE_FOR_3D(blo, i, j, k,
533 {
534 RT A = rbc(i,j,k,2)
535 / (rbc(i,j,k,1)*dxi + rbc(i,j,k,0)*RT(0.5));
536 rhsfab(i+1,j,k,icomp) += fac*bfab(i+1,j,k,icomp)*A;
537 });
538 } else if (idim == 1) {
539 RT fac = beta*dyi*dyi;
540 AMREX_HOST_DEVICE_FOR_3D(blo, i, j, k,
541 {
542 RT A = rbc(i,j,k,2)
543 / (rbc(i,j,k,1)*dyi + rbc(i,j,k,0)*RT(0.5));
544 rhsfab(i,j+1,k,icomp) += fac*bfab(i,j+1,k,icomp)*A;
545 });
546 } else {
547 RT fac = beta*dzi*dzi;
548 AMREX_HOST_DEVICE_FOR_3D(blo, i, j, k,
549 {
550 RT A = rbc(i,j,k,2)
551 / (rbc(i,j,k,1)*dzi + rbc(i,j,k,0)*RT(0.5));
552 rhsfab(i,j,k+1,icomp) += fac*bfab(i,j,k+1,icomp)*A;
553 });
554 }
555 }
556 if (this->m_hibc_orig[icomp][idim] == LinOpBCType::Robin && outside_domain_hi)
557 {
558 if (idim == 0) {
559 RT fac = beta*dxi*dxi;
560 AMREX_HOST_DEVICE_FOR_3D(bhi, i, j, k,
561 {
562 RT A = rbc(i,j,k,2)
563 / (rbc(i,j,k,1)*dxi + rbc(i,j,k,0)*RT(0.5));
564 rhsfab(i-1,j,k,icomp) += fac*bfab(i,j,k,icomp)*A;
565 });
566 } else if (idim == 1) {
567 RT fac = beta*dyi*dyi;
568 AMREX_HOST_DEVICE_FOR_3D(bhi, i, j, k,
569 {
570 RT A = rbc(i,j,k,2)
571 / (rbc(i,j,k,1)*dyi + rbc(i,j,k,0)*RT(0.5));
572 rhsfab(i,j-1,k,icomp) += fac*bfab(i,j,k,icomp)*A;
573 });
574 } else {
575 RT fac = beta*dzi*dzi;
576 AMREX_HOST_DEVICE_FOR_3D(bhi, i, j, k,
577 {
578 RT A = rbc(i,j,k,2)
579 / (rbc(i,j,k,1)*dzi + rbc(i,j,k,0)*RT(0.5));
580 rhsfab(i,j,k-1,icomp) += fac*bfab(i,j,k,icomp)*A;
581 });
582 }
583 }
584 }
585 }
586 }
587
588 }
589}
590
591template <typename MF>
592void
594 int amrlev, const Array<MF*,AMREX_SPACEDIM>& grad, MF const& sol,
595 bool mult_bcoef) const
596{
597 /*
598 * if (mult_bcoef == true)
599 * grad is -bceof*grad phi
600 * else
601 * grad is grad phi
602 */
603 RT fac = mult_bcoef ? RT(-1.0) : RT(1.0);
604
605 bool has_inhomog_neumann = this->hasInhomogNeumannBC();
606 bool has_robin = this->hasRobinBC();
607
608 if (!has_inhomog_neumann && !has_robin) { return; }
609
610 int ncomp = this->getNComp();
611 const int mglev = 0;
612
613 const auto dxinv = this->m_geom[amrlev][mglev].InvCellSize();
614 const Box domain = this->m_geom[amrlev][mglev].growPeriodicDomain(1);
615
616 Array<MF const*, AMREX_SPACEDIM> bcoef = {AMREX_D_DECL(nullptr,nullptr,nullptr)};
617 if (mult_bcoef) {
618 bcoef = getBCoeffs(amrlev,mglev);
619 }
620
621 const auto& bndry = *this->m_bndry_sol[amrlev];
622
623 MFItInfo mfi_info;
624 if (Gpu::notInLaunchRegion()) { mfi_info.SetDynamic(true); }
625
626#ifdef AMREX_USE_OMP
627#pragma omp parallel if (Gpu::notInLaunchRegion())
628#endif
629 for (MFIter mfi(sol, mfi_info); mfi.isValid(); ++mfi)
630 {
631 Box const& vbx = mfi.validbox();
632 for (OrientationIter orit; orit.isValid(); ++orit) {
633 const Orientation ori = orit();
634 const int idim = ori.coordDir();
635 const Box& ccb = amrex::adjCell(vbx, ori);
636 const Dim3 os = IntVect::TheDimensionVector(idim).dim3();
637 const RT dxi = static_cast<RT>(dxinv[idim]);
638 if (! domain.contains(ccb)) {
639 for (int icomp = 0; icomp < ncomp; ++icomp) {
640 auto const& phi = sol.const_array(mfi,icomp);
641 auto const& bv = bndry.bndryValues(ori).multiFab().const_array(mfi,icomp);
642 auto const& bc = bcoef[idim] ? bcoef[idim]->const_array(mfi,icomp)
644 auto const& f = grad[idim]->array(mfi,icomp);
645 if (ori.isLow()) {
646 if (this->m_lobc_orig[icomp][idim] ==
648 AMREX_HOST_DEVICE_FOR_3D(ccb, i, j, k,
649 {
650 int ii = i+os.x;
651 int jj = j+os.y;
652 int kk = k+os.z;
653 RT b = bc ? bc(ii,jj,kk) : RT(1.0);
654 f(ii,jj,kk) = fac*b*bv(i,j,k);
655 });
656 } else if (this->m_lobc_orig[icomp][idim] ==
658 auto const& rbc = (*this->m_robin_bcval[amrlev])[mfi].const_array(icomp*3);
659 AMREX_HOST_DEVICE_FOR_3D(ccb, i, j, k,
660 {
661 int ii = i+os.x;
662 int jj = j+os.y;
663 int kk = k+os.z;
664 RT tmp = RT(1.0) /
665 (rbc(i,j,k,1)*dxi + rbc(i,j,k,0)*RT(0.5));
666 RT RA = rbc(i,j,k,2) * tmp;
667 RT RB = (rbc(i,j,k,1)*dxi - rbc(i,j,k,0)*RT(0.5)) * tmp;
668 RT b = bc ? bc(ii,jj,kk) : RT(1.0);
669 f(ii,jj,kk) = fac*b*dxi*((RT(1.0)-RB)*phi(ii,jj,kk)-RA);
670 });
671 }
672 } else {
673 if (this->m_hibc_orig[icomp][idim] ==
675 AMREX_HOST_DEVICE_FOR_3D(ccb, i, j, k,
676 {
677 RT b = bc ? bc(i,j,k) : RT(1.0);
678 f(i,j,k) = fac*b*bv(i,j,k);
679 });
680 } else if (this->m_hibc_orig[icomp][idim] ==
682 auto const& rbc = (*this->m_robin_bcval[amrlev])[mfi].const_array(icomp*3);
683 AMREX_HOST_DEVICE_FOR_3D(ccb, i, j, k,
684 {
685 RT tmp = RT(1.0) /
686 (rbc(i,j,k,1)*dxi + rbc(i,j,k,0)*RT(0.5));
687 RT RA = rbc(i,j,k,2) * tmp;
688 RT RB = (rbc(i,j,k,1)*dxi - rbc(i,j,k,0)*RT(0.5)) * tmp;
689 RT b = bc ? bc(i,j,k) : RT(1.0);
690 f(i,j,k) = fac*b*dxi*(RA+(RB-RT(1.0))*
691 phi(i-os.x,j-os.y,k-os.z));
692 });
693 }
694 }
695 }
696 }
697 }
698 }
699}
700
701template <typename MF>
702void
703MLCellABecLapT<MF>::applyOverset (int amrlev, MF& rhs) const
704{
705 if (m_overset_mask[amrlev][0]) {
706 const int ncomp = this->getNComp();
707#ifdef AMREX_USE_GPU
708 if (Gpu::inLaunchRegion() && m_overset_mask[amrlev][0]->isFusingCandidate()) {
709 auto const& osma = m_overset_mask[amrlev][0]->const_arrays();
710 auto const& rhsa = rhs.arrays();
711 ParallelFor(*m_overset_mask[amrlev][0], IntVect(0), ncomp,
712 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
713 {
714 if (osma[box_no](i,j,k) == 0) {
715 rhsa[box_no](i,j,k,n) = RT(0.0);
716 }
717 });
718 if (!Gpu::inNoSyncRegion()) {
720 }
721 } else
722#endif
723 {
724#ifdef AMREX_USE_OMP
725#pragma omp parallel if (Gpu::notInLaunchRegion())
726#endif
727 for (MFIter mfi(*m_overset_mask[amrlev][0],TilingIfNotGPU()); mfi.isValid(); ++mfi)
728 {
729 const Box& bx = mfi.tilebox();
730 auto const& rfab = rhs.array(mfi);
731 auto const& osm = m_overset_mask[amrlev][0]->const_array(mfi);
732 AMREX_HOST_DEVICE_PARALLEL_FOR_4D(bx, ncomp, i, j, k, n,
733 {
734 if (osm(i,j,k) == 0) { rfab(i,j,k,n) = RT(0.0); }
735 });
736 }
737 }
738 }
739}
740
741#if defined(AMREX_USE_HYPRE) && (AMREX_SPACEDIM > 1)
742template <typename MF>
743std::unique_ptr<Hypre>
745{
746 if constexpr (!std::is_same<MF,MultiFab>()) {
747 amrex::Abort("MLCellABecLap Hypre interface only supports MultiFab");
748 } else {
749 const BoxArray& ba = this->m_grids[0].back();
750 const DistributionMapping& dm = this->m_dmap[0].back();
751 const Geometry& geom = this->m_geom[0].back();
752 const auto& factory = *(this->m_factory[0].back());
753 MPI_Comm comm = this->BottomCommunicator();
754
755 const int mglev = this->NMGLevels(0)-1;
756
757 auto om = getOversetMask(0, mglev);
758
759 auto hypre_solver = amrex::makeHypre(ba, dm, geom, comm, hypre_interface, om);
760
761 hypre_solver->setScalars(getAScalar(), getBScalar());
762
763 auto ac = getACoeffs(0, mglev);
764 if (ac)
765 {
766 hypre_solver->setACoeffs(*ac);
767 }
768 else
769 {
770 MultiFab alpha(ba,dm,1,0,MFInfo().SetArena(The_Async_Arena()),factory);
771 alpha.setVal(0.0);
772 hypre_solver->setACoeffs(alpha);
773 }
774
775 auto bc = getBCoeffs(0, mglev);
776 if (bc[0])
777 {
778 hypre_solver->setBCoeffs(bc);
779 }
780 else
781 {
782 Array<MultiFab,AMREX_SPACEDIM> beta;
783 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim)
784 {
785 beta[idim].define(amrex::convert(ba,IntVect::TheDimensionVector(idim)),
786 dm, 1, 0, MFInfo().SetArena(The_Async_Arena()), factory);
787 beta[idim].setVal(1.0);
788 }
789 hypre_solver->setBCoeffs(amrex::GetArrOfConstPtrs(beta));
790 }
791 hypre_solver->setIsMatrixSingular(this->isBottomSingular());
792
793 return hypre_solver;
794 }
795 return nullptr;
796}
797#endif
798
799#if defined(AMREX_USE_PETSC) && (AMREX_SPACEDIM > 1)
800template <typename MF>
801std::unique_ptr<PETScABecLap>
802MLCellABecLapT<MF>::makePETSc () const
803{
804 if constexpr (!std::is_same<MF,MultiFab>()) {
805 amrex::Abort("MLCellABecLap PETSc interface only supports MultiFab");
806 } else {
807 const BoxArray& ba = this->m_grids[0].back();
808 const DistributionMapping& dm = this->m_dmap[0].back();
809 const Geometry& geom = this->m_geom[0].back();
810 const auto& factory = *(this->m_factory[0].back());
811 MPI_Comm comm = this->BottomCommunicator();
812
813 auto petsc_solver = makePetsc(ba, dm, geom, comm);
814
815 petsc_solver->setScalars(getAScalar(), getBScalar());
816
817 const int mglev = this->NMGLevels(0)-1;
818 auto ac = getACoeffs(0, mglev);
819 if (ac)
820 {
821 petsc_solver->setACoeffs(*ac);
822 }
823 else
824 {
825 MultiFab alpha(ba,dm,1,0,MFInfo().SetArena(The_Async_Arena()),factory);
826 alpha.setVal(0.0);
827 petsc_solver->setACoeffs(alpha);
828 }
829
830 auto bc = getBCoeffs(0, mglev);
831 if (bc[0])
832 {
833 petsc_solver->setBCoeffs(bc);
834 }
835 else
836 {
837 Array<MultiFab,AMREX_SPACEDIM> beta;
838 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim)
839 {
840 beta[idim].define(amrex::convert(ba,IntVect::TheDimensionVector(idim)),
841 dm, 1, 0, MFInfo().SetArena(The_Async_Arena()), factory);
842 beta[idim].setVal(1.0);
843 }
844 petsc_solver->setBCoeffs(amrex::GetArrOfConstPtrs(beta));
845 }
846 return petsc_solver;
847 }
848 return nullptr;
849}
850#endif
851
852extern template class MLCellABecLapT<MultiFab>;
853
856
857}
858
859#endif
#define BL_PROFILE(a)
Definition AMReX_BLProfiler.H:562
#define AMREX_ALWAYS_ASSERT(EX)
Definition AMReX_BLassert.H:50
#define AMREX_HOST_DEVICE_PARALLEL_FOR_3D(...)
Definition AMReX_GpuLaunchMacrosC.nolint.H:110
#define AMREX_HOST_DEVICE_FOR_3D(...)
Definition AMReX_GpuLaunchMacrosC.nolint.H:106
#define AMREX_HOST_DEVICE_PARALLEL_FOR_4D(...)
Definition AMReX_GpuLaunchMacrosC.nolint.H:111
#define AMREX_GPU_DEVICE
Definition AMReX_GpuQualifiers.H:18
#define AMREX_GPU_HOST_DEVICE
Definition AMReX_GpuQualifiers.H:20
Array4< Real > fine
Definition AMReX_InterpFaceRegister.cpp:90
Array4< Real const > crse
Definition AMReX_InterpFaceRegister.cpp:92
GpuArray< Real, 3 > beta
Definition AMReX_MLEBNodeFDLaplacian.cpp:1099
#define AMREX_D_DECL(a, b, c)
Definition AMReX_SPACE.H:171
Maintain an identifier for boundary condition types.
Definition AMReX_BoundCond.H:25
__host__ __device__ bool contains(const IntVectND< dim > &p) const noexcept
Return true if argument is contained within BoxND.
Definition AMReX_Box.H:233
__host__ __device__ bool coarsenable(const IntVectND< dim > &refrat, const IntVectND< dim > &min_width) const noexcept
Return whether this Box is coarsenable.
Definition AMReX_Box.H:802
__host__ __device__ BoxND & coarsen(int ref_ratio) noexcept
Coarsen BoxND by given (positive) refinement ratio. NOTE: if type(dir) = CELL centered: lo <- lo/rati...
Definition AMReX_Box.H:754
const FAB & get(const MFIter &mfi) const noexcept
Return a constant reference to the FAB associated with mfi.
Definition AMReX_FabArray.H:558
Abstract factory interface for creating, aliasing, and destroying FAB objects.
Definition AMReX_FabFactory.H:73
Interface
HYPRE interface modes supported.
Definition AMReX_Hypre.H:37
__host__ static __device__ constexpr IntVectND< dim > TheDimensionVector(int d) noexcept
This static member function returns a reference to a constant IntVectND object, all of whose dim argu...
Definition AMReX_IntVect.H:790
Iterator for looping ever tiles and boxes of amrex::FabArray based containers.
Definition AMReX_MFIter.H:88
bool isValid() const noexcept
Is the iterator valid i.e. is it associated with a FAB?
Definition AMReX_MFIter.H:176
Cell-centered operator that exposes ABec Laplacian helpers to derived classes.
Definition AMReX_MLCellABecLap.H:22
void addInhomogNeumannFlux(int amrlev, const Array< MF *, 3 > &grad, MF const &sol, bool mult_bcoef) const final
Add inhomogeneous Neumann/Robin flux contributions into grad from sol (include b when mult_bcoef is t...
Definition AMReX_MLCellABecLap.H:593
MLCellABecLapT(const MLCellABecLapT< MF > &)=delete
void getFluxes(const Vector< MF * > &a_flux, const Vector< MF * > &a_sol) const final
Guard overload that aborts if called (cell-centered flux extraction requires per-direction face array...
Definition AMReX_MLCellABecLap.H:104
LPInfo m_lpinfo_arg
Definition AMReX_MLCellABecLap.H:143
virtual MF const * getACoeffs(int amrlev, int mglev) const =0
Cell-centered a coefficient MultiFab for AMR level amrlev and MG level mglev.
void getFluxes(const Vector< Array< MF *, 3 > > &a_flux, const Vector< MF * > &a_sol, Location a_loc) const final
Fill per-face fluxes using the supplied solution hierarchy.
Definition AMReX_MLCellABecLap.H:336
MLCellABecLapT< MF > & operator=(const MLCellABecLapT< MF > &)=delete
MLCellABecLapT(MLCellABecLapT< MF > &&)=delete
virtual Array< MF const *, 3 > getBCoeffs(int amrlev, int mglev) const =0
Face-centered b coefficients for AMR level amrlev and MG level mglev.
typename MF::value_type RT
Definition AMReX_MLCellABecLap.H:26
void setDirichletNodesToZero(int amrlev, int mglev, MF &mf) const override
Zero out Dirichlet nodes on (amrlev,mglev) so that GMRES can treat them as known.
Definition AMReX_MLCellABecLap.H:316
void applyOverset(int amrlev, MF &rhs) const override
Zero RHS entries in rhs that are covered by overset masks on level amrlev.
Definition AMReX_MLCellABecLap.H:703
virtual RT getBScalar() const =0
Scalar applied to b on the current operator.
iMultiFab const * getOversetMask(int amrlev, int mglev) const
Overset mask for (amrlev,mglev); returns nullptr when not defined.
Definition AMReX_MLCellABecLap.H:71
bool needsUpdate() const override
Does it need update if it's reused?
Definition AMReX_MLCellABecLap.H:75
typename MLLinOpT< MF >::Location Location
Definition AMReX_MLCellABecLap.H:28
typename MF::fab_type FAB
Definition AMReX_MLCellABecLap.H:25
Vector< Vector< std::unique_ptr< iMultiFab > > > m_overset_mask
Definition AMReX_MLCellABecLap.H:141
void define(const Vector< Geometry > &a_geom, const Vector< BoxArray > &a_grids, const Vector< DistributionMapping > &a_dmap, const LPInfo &a_info=LPInfo(), const Vector< FabFactory< FAB > const * > &a_factory={})
Describe the AMR hierarchy when overset masks are not required.
Definition AMReX_MLCellABecLap.H:150
bool supportInhomogNeumannBC() const noexcept override
Definition AMReX_MLCellABecLap.H:145
void prepareForSolve() override
Standard hook called before MLMG iterates (fixes BC data, etc.).
Definition AMReX_MLCellABecLap.H:309
~MLCellABecLapT() override=default
virtual RT getAScalar() const =0
Scalar applied to a on the current operator.
void applyInhomogNeumannTerm(int amrlev, MF &rhs) const final
Apply stored Neumann data to the RHS rhs on AMR level amrlev.
Definition AMReX_MLCellABecLap.H:369
void update() override
Average coefficients/metrics when marked dirty.
Definition AMReX_MLCellABecLap.H:302
Definition AMReX_MLCellLinOp.H:31
void update() override
Update for reuse.
Definition AMReX_MLCellLinOp.H:945
void prepareForSolve() override
Prepare multilevel metadata before MLMG iterates (coefficients, BC caches, etc.).
Definition AMReX_MLCellLinOp.H:1956
void define(const Vector< Geometry > &a_geom, const Vector< BoxArray > &a_grids, const Vector< DistributionMapping > &a_dmap, const LPInfo &a_info=LPInfo(), const Vector< FabFactory< FAB > const * > &a_factory={})
Bind the operator to an AMR hierarchy.
Definition AMReX_MLCellLinOp.H:648
bool needsUpdate() const override
Does it need update if it's reused?
Definition AMReX_MLCellLinOp.H:93
An Iterator over the Orientation of Faces of a Box.
Definition AMReX_Orientation.H:135
__host__ __device__ bool isValid() const noexcept
Is the iterator valid?
Definition AMReX_Orientation.H:156
Encapsulation of the Orientation of the Faces of a Box.
Definition AMReX_Orientation.H:29
__host__ __device__ bool isLow() const noexcept
Returns true if Orientation is low.
Definition AMReX_Orientation.H:89
__host__ __device__ int coordDir() const noexcept
Returns the coordinate direction.
Definition AMReX_Orientation.H:83
@ low
Definition AMReX_Orientation.H:34
@ high
Definition AMReX_Orientation.H:34
Definition AMReX_Reduce.H:438
Type value()
Definition AMReX_Reduce.H:473
Definition AMReX_Reduce.H:597
void eval(MF const &mf, IntVect const &nghost, D &reduce_data, F &&f)
Definition AMReX_Reduce.H:734
This class is a thin wrapper around std::vector. Unlike vector, Vector::operator[] provides bound che...
Definition AMReX_Vector.H:29
Long size() const noexcept
Definition AMReX_Vector.H:54
A Collection of IArrayBoxes.
Definition AMReX_iMultiFab.H:34
static void Copy(iMultiFab &dst, const iMultiFab &src, int srccomp, int dstcomp, int numcomp, int nghost)
Copy from src to dst including nghost ghost cells. The two iMultiFabs MUST have the same underlying B...
Definition AMReX_iMultiFab.cpp:51
amrex_real Real
Floating Point Type for Fields.
Definition AMReX_REAL.H:80
__host__ __device__ BoxND< dim > adjCellHi(const BoxND< dim > &b, int dir, int len=1) noexcept
Return the BoxND of length len adjacent to b on the high end along coordinate direction dir.
Definition AMReX_Box.H:1848
__host__ __device__ BoxND< dim > convert(const BoxND< dim > &b, const IntVectND< dim > &typ) noexcept
Return a copy of b converted to the nodal flags typ.
Definition AMReX_Box.H:1630
__host__ __device__ BoxND< dim > adjCellLo(const BoxND< dim > &b, int dir, int len=1) noexcept
Return the BoxND of length len adjacent to b on the low end along coordinate direction dir.
Definition AMReX_Box.H:1817
__host__ __device__ BoxND< dim > coarsen(const BoxND< dim > &b, int ref_ratio) noexcept
Return a copy of b coarsened by the isotropic ratio ref_ratio.
Definition AMReX_Box.H:1469
__host__ __device__ BoxND< dim > adjCell(const BoxND< dim > &b, Orientation face, int len=1) noexcept
Similar to adjCellLo and adjCellHi except that it operates on the given face of BoxND b.
Definition AMReX_Box.H:1880
__host__ __device__ BoxND< dim > refine(const BoxND< dim > &b, int ref_ratio) noexcept
Return a copy of b refined by the isotropic ratio ref_ratio.
Definition AMReX_Box.H:1510
std::array< T, N > Array
Definition AMReX_Array.H:31
Arena * The_Async_Arena()
Definition AMReX_Arena.cpp:825
void Min(KeyValuePair< K, V > &vi, MPI_Comm comm)
Definition AMReX_ParallelReduce.H:161
void streamSynchronize() noexcept
Definition AMReX_GpuDevice.H:310
bool inLaunchRegion() noexcept
Definition AMReX_GpuControl.H:88
bool notInLaunchRegion() noexcept
Definition AMReX_GpuControl.H:89
bool inNoSyncRegion() noexcept
Definition AMReX_GpuControl.H:148
MPI_Comm CommunicatorSub() noexcept
sub-communicator for current frame
Definition AMReX_ParallelContext.H:70
int MPI_Comm
Definition AMReX_ccse-mpi.H:51
Definition AMReX_Amr.cpp:50
__host__ __device__ void ignore_unused(const Ts &...)
No-op helper that marks variables as intentionally unused.
Definition AMReX.H:259
std::array< T const *, 3 > GetArrOfConstPtrs(const std::array< T, 3 > &a) noexcept
Create an array of const-qualified pointers from an array of objects.
Definition AMReX_Array.H:1079
void ParallelFor(TypeList< CTOs... > ctos, std::array< int, sizeof...(CTOs)> const &runtime_options, T N, F &&f)
Definition AMReX_CTOParallelForImpl.H:202
BoxND< 3 > Box
Box is an alias for amrex::BoxND instantiated with AMREX_SPACEDIM.
Definition AMReX_BaseFwd.H:35
bool isMFIterSafe(const FabArrayBase &x, const FabArrayBase &y)
Definition AMReX_MFIter.H:256
IntVectND< 3 > IntVect
IntVect is an alias for amrex::IntVectND instantiated with AMREX_SPACEDIM.
Definition AMReX_BaseFwd.H:38
std::unique_ptr< Hypre > makeHypre(const BoxArray &grids, const DistributionMapping &dmap, const Geometry &geom, MPI_Comm comm_, Hypre::Interface interface, const iMultiFab *overset_mask)
Factory that instantiates the requested HYPRE interface.
Definition AMReX_Hypre.cpp:12
bool TilingIfNotGPU() noexcept
Definition AMReX_MFIter.H:12
std::unique_ptr< PETScABecLap > makePetsc(const BoxArray &grids, const DistributionMapping &dmap, const Geometry &geom, MPI_Comm comm_)
Factory helper that instantiates a PETSc ABec Laplacian on one level.
Definition AMReX_PETSc.cpp:58
void Abort(const std::string &msg)
Print a fatal-error message to stderr and abort execution.
Definition AMReX.cpp:242
A multidimensional array accessor.
Definition AMReX_Array4.H:289
A simple struct holding 3 int values for a 3D index.
Definition AMReX_Dim3.H:24
int x
Definition AMReX_Dim3.H:24
int z
Definition AMReX_Dim3.H:24
int y
Definition AMReX_Dim3.H:24
Configuration knobs for multilevel linear operators (grid agglomeration, metrics, etc....
Definition AMReX_MLLinOp.H:51
bool do_semicoarsening
Definition AMReX_MLLinOp.H:54
int max_coarsening_level
Definition AMReX_MLLinOp.H:60
Location
Definition AMReX_MLLinOp.H:119
FabArray memory allocation information.
Definition AMReX_FabArray.H:73
Definition AMReX_MFIter.H:20
MFItInfo & SetDynamic(bool f) noexcept
Definition AMReX_MFIter.H:43