Block-Structured AMR Software Framework
 
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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>
7
8namespace amrex {
9
10template <typename MF>
11class MLCellABecLapT // NOLINT(cppcoreguidelines-virtual-class-destructor)
12 : public MLCellLinOpT<MF>
13{
14public:
15
16 using FAB = typename MF::fab_type;
17 using RT = typename MF::value_type;
18
20
21 MLCellABecLapT () = default;
22 ~MLCellABecLapT () override = default;
23
28
29 void define (const Vector<Geometry>& a_geom,
30 const Vector<BoxArray>& a_grids,
31 const Vector<DistributionMapping>& a_dmap,
32 const LPInfo& a_info = LPInfo(),
33 const Vector<FabFactory<FAB> const*>& a_factory = {});
34
35 void define (const Vector<Geometry>& a_geom,
36 const Vector<BoxArray>& a_grids,
37 const Vector<DistributionMapping>& a_dmap,
38 const Vector<iMultiFab const*>& a_overset_mask,
39 const LPInfo& a_info = LPInfo(),
40 const Vector<FabFactory<FAB> const*>& a_factory = {});
41
42 [[nodiscard]] iMultiFab const* getOversetMask (int amrlev, int mglev) const {
43 return m_overset_mask[amrlev][mglev].get();
44 }
45
46 [[nodiscard]] bool needsUpdate () const override {
48 }
49 void update () override;
50
51 void prepareForSolve () override;
52
53 void setDirichletNodesToZero (int amrlev, int mglev, MF& mf) const override;
54
55 void getFluxes (const Vector<Array<MF*,AMREX_SPACEDIM> >& a_flux,
56 const Vector<MF*>& a_sol,
57 Location a_loc) const final;
58 void getFluxes (const Vector<MF*>& /*a_flux*/,
59 const Vector<MF*>& /*a_sol*/) const final {
60 amrex::Abort("MLCellABecLap::getFluxes: How did we get here?");
61 }
62
63 virtual RT getAScalar () const = 0;
64 virtual RT getBScalar () const = 0;
65 virtual MF const* getACoeffs (int amrlev, int mglev) const = 0;
66 virtual Array<MF const*,AMREX_SPACEDIM> getBCoeffs (int amrlev, int mglev) const = 0;
67
68 void applyInhomogNeumannTerm (int amrlev, MF& rhs) const final;
69
71 int amrlev, const Array<MF*,AMREX_SPACEDIM>& grad,
72 MF const& sol, bool mult_bcoef) const final;
73
74 void applyOverset (int amrlev, MF& rhs) const override;
75
76#if defined(AMREX_USE_HYPRE) && (AMREX_SPACEDIM > 1)
77 [[nodiscard]] std::unique_ptr<Hypre> makeHypre (Hypre::Interface hypre_interface) const override;
78#endif
79
80#ifdef AMREX_USE_PETSC
81 [[nodiscard]] std::unique_ptr<PETScABecLap> makePETSc () const override;
82#endif
83
84protected:
86
88
89 [[nodiscard]] bool supportInhomogNeumannBC () const noexcept override { return true; }
90};
91
92template <typename MF>
93void
95 const Vector<BoxArray>& a_grids,
96 const Vector<DistributionMapping>& a_dmap,
97 const LPInfo& a_info,
98 const Vector<FabFactory<FAB> const*>& a_factory)
99{
100 MLCellLinOpT<MF>::define(a_geom, a_grids, a_dmap, a_info, a_factory);
101
102 this->m_overset_mask.resize(this->m_num_amr_levels);
103 for (int amrlev = 0; amrlev < this->m_num_amr_levels; ++amrlev) {
104 this->m_overset_mask[amrlev].resize(this->m_num_mg_levels[amrlev]);
105 }
106}
107
108template <typename MF>
109void
111 const Vector<BoxArray>& a_grids,
112 const Vector<DistributionMapping>& a_dmap,
113 const Vector<iMultiFab const*>& a_overset_mask,
114 const LPInfo& a_info,
115 const Vector<FabFactory<FAB> const*>& a_factory)
116{
117 BL_PROFILE("MLCellABecLap::define(overset)");
118
119 AMREX_ALWAYS_ASSERT(!this->hasHiddenDimension());
120
121 this->m_lpinfo_arg = a_info;
122
123 auto namrlevs = static_cast<int>(a_geom.size());
124 this->m_overset_mask.resize(namrlevs);
125 for (int amrlev = 0; amrlev < namrlevs; ++amrlev)
126 {
127 this->m_overset_mask[amrlev].push_back(std::make_unique<iMultiFab>(a_grids[amrlev],
128 a_dmap[amrlev], 1, 1));
129 iMultiFab::Copy(*(this->m_overset_mask[amrlev][0]), *a_overset_mask[amrlev], 0, 0, 1, 0);
130 if (amrlev > 1) {
131 AMREX_ALWAYS_ASSERT(amrex::refine(a_geom[amrlev-1].Domain(),2)
132 == a_geom[amrlev].Domain());
133 }
134 }
135
136 int amrlev = 0;
137 Box dom = a_geom[0].Domain();
138 for (int mglev = 1; mglev <= a_info.max_coarsening_level; ++mglev)
139 {
140 AMREX_ALWAYS_ASSERT(this->mg_coarsen_ratio == 2);
141 iMultiFab const& fine = *(this->m_overset_mask[amrlev][mglev-1]);
142 if (dom.coarsenable(2) && fine.boxArray().coarsenable(2)) {
143 dom.coarsen(2);
144 auto crse = std::make_unique<iMultiFab>(amrex::coarsen(fine.boxArray(),2),
145 fine.DistributionMap(), 1, 1);
146 ReduceOps<ReduceOpSum> reduce_op;
147 ReduceData<int> reduce_data(reduce_op);
148 using ReduceTuple = typename decltype(reduce_data)::Type;
149#ifdef AMREX_USE_OMP
150#pragma omp parallel if (Gpu::notInLaunchRegion())
151#endif
152 for (MFIter mfi(*crse, TilingIfNotGPU()); mfi.isValid(); ++mfi)
153 {
154 const Box& bx = mfi.tilebox();
155 Array4<int const> const& fmsk = fine.const_array(mfi);
156 Array4<int> const& cmsk = crse->array(mfi);
157 reduce_op.eval(bx, reduce_data,
158 [=] AMREX_GPU_HOST_DEVICE (Box const& b) -> ReduceTuple
159 {
160 return { coarsen_overset_mask(b, cmsk, fmsk) };
161 });
162 }
163 ReduceTuple hv = reduce_data.value(reduce_op);
164 if (amrex::get<0>(hv) == 0) {
165 this->m_overset_mask[amrlev].push_back(std::move(crse));
166 } else {
167 break;
168 }
169 } else {
170 break;
171 }
172 }
173 int max_overset_mask_coarsening_level = this->m_overset_mask[amrlev].size()-1;
174 ParallelAllReduce::Min(max_overset_mask_coarsening_level, ParallelContext::CommunicatorSub());
175 this->m_overset_mask[amrlev].resize(max_overset_mask_coarsening_level+1);
176
177 LPInfo linfo = a_info;
178 linfo.max_coarsening_level = std::min(a_info.max_coarsening_level,
179 max_overset_mask_coarsening_level);
180
181 MLCellLinOpT<MF>::define(a_geom, a_grids, a_dmap, linfo, a_factory);
182
183 amrlev = 0;
184 for (int mglev = 1; mglev < this->m_num_mg_levels[amrlev]; ++mglev) {
185 MF foo(this->m_grids[amrlev][mglev], this->m_dmap[amrlev][mglev], 1, 0, MFInfo().SetAlloc(false));
186 if (! amrex::isMFIterSafe(*(this->m_overset_mask[amrlev][mglev]), foo)) {
187 auto osm = std::make_unique<iMultiFab>(this->m_grids[amrlev][mglev],
188 this->m_dmap[amrlev][mglev], 1, 1);
189 osm->ParallelCopy(*(this->m_overset_mask[amrlev][mglev]));
190 std::swap(osm, this->m_overset_mask[amrlev][mglev]);
191 }
192 }
193
194 for (amrlev = 1; amrlev < this->m_num_amr_levels; ++amrlev) {
195 for (int mglev = 1; mglev < this->m_num_mg_levels[amrlev]; ++mglev) { // for ref_ratio 4
196 this->m_overset_mask[amrlev].push_back(std::make_unique<iMultiFab>(this->m_grids[amrlev][mglev],
197 this->m_dmap[amrlev][mglev],
198 1, 1));
199
200#ifdef AMREX_USE_GPU
201 if (Gpu::inLaunchRegion() && this->m_overset_mask[amrlev][mglev]->isFusingCandidate()) {
202 auto const& crsema = this->m_overset_mask[amrlev][mglev]->arrays();
203 auto const& finema = this->m_overset_mask[amrlev][mglev-1]->const_arrays();
204 ParallelFor(*(this->m_overset_mask[amrlev][mglev]),
205 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k) noexcept
206 {
207 coarsen_overset_mask(i,j,k, crsema[box_no], finema[box_no]);
208 });
209 if (!Gpu::inNoSyncRegion()) {
211 }
212 } else
213#endif
214 {
215#ifdef AMREX_USE_OMP
216#pragma omp parallel if (Gpu::notInLaunchRegion())
217#endif
218 for (MFIter mfi(*(this->m_overset_mask[amrlev][mglev]), TilingIfNotGPU()); mfi.isValid(); ++mfi)
219 {
220 const Box& bx = mfi.tilebox();
221 Array4<int> const& cmsk = this->m_overset_mask[amrlev][mglev]->array(mfi);
222 Array4<int const> const fmsk = this->m_overset_mask[amrlev][mglev-1]->const_array(mfi);
224 {
225 coarsen_overset_mask(i,j,k, cmsk, fmsk);
226 });
227 }
228 }
229 }
230 }
231
232 for (amrlev = 0; amrlev < this->m_num_amr_levels; ++amrlev) {
233 for (int mglev = 0; mglev < this->m_num_mg_levels[amrlev]; ++mglev) {
234 this->m_overset_mask[amrlev][mglev]->setBndry(1);
235 this->m_overset_mask[amrlev][mglev]->FillBoundary(this->m_geom[amrlev][mglev].periodicity());
236 }
237 }
238}
239
240template <typename MF>
241void
246
247template <typename MF>
248void
253
254template <typename MF>
255void
256MLCellABecLapT<MF>::setDirichletNodesToZero (int amrlev, int mglev, MF& mf) const
257{
258 auto const* omask = this->getOversetMask(amrlev, mglev);
259 if (omask) {
260 const int ncomp = this->getNComp();
261 auto const& mskma = omask->const_arrays();
262 auto const& ma = mf.arrays();
263 ParallelFor(mf, IntVect(0), ncomp,
264 [=] AMREX_GPU_DEVICE (int bno, int i, int j, int k, int n)
265 {
266 if (mskma[bno](i,j,k) == 0) { ma[bno](i,j,k,n) = RT(0.0); }
267 });
268 if (!Gpu::inNoSyncRegion()) {
270 }
271 }
272}
273
274template <typename MF>
275void
277 const Vector<MF*>& a_sol,
278 Location a_loc) const
279{
280 BL_PROFILE("MLMG::getFluxes()");
281
282 const int ncomp = this->getNComp();
283 const RT betainv = RT(1.0) / getBScalar();
284 const int nlevs = this->NAMRLevels();
285 for (int alev = 0; alev < nlevs; ++alev) {
286 this->compFlux(alev, a_flux[alev], *a_sol[alev], a_loc);
287 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
288 this->unapplyMetricTerm(alev, 0, *a_flux[alev][idim]);
289 if (betainv != RT(1.0)) {
290 a_flux[alev][idim]->mult(betainv, 0, ncomp);
291 }
292 }
293 this->addInhomogNeumannFlux(alev, a_flux[alev], *a_sol[alev], true);
294 }
295}
296
297template <typename MF>
298void
300{
301 bool has_inhomog_neumann = this->hasInhomogNeumannBC();
302 bool has_robin = this->hasRobinBC();
303
304 if (!has_inhomog_neumann && !has_robin) { return; }
305
306 int ncomp = this->getNComp();
307 const int mglev = 0;
308
309 const auto problo = this->m_geom[amrlev][mglev].ProbLoArray();
310 const auto probhi = this->m_geom[amrlev][mglev].ProbHiArray();
311 amrex::ignore_unused(probhi);
312 const RT dxi = static_cast<RT>(this->m_geom[amrlev][mglev].InvCellSize(0));
313 const RT dyi = static_cast<RT>((AMREX_SPACEDIM >= 2) ? this->m_geom[amrlev][mglev].InvCellSize(1) : Real(1.0));
314 const RT dzi = static_cast<RT>((AMREX_SPACEDIM == 3) ? this->m_geom[amrlev][mglev].InvCellSize(2) : Real(1.0));
315 const RT xlo = static_cast<RT>(problo[0]);
316 const RT dx = static_cast<RT>(this->m_geom[amrlev][mglev].CellSize(0));
317 const Box& domain = this->m_geom[amrlev][mglev].Domain();
318
319 const RT beta = getBScalar();
320 Array<MF const*, AMREX_SPACEDIM> const& bcoef = getBCoeffs(amrlev,mglev);
321 FAB foo(Box(IntVect(0),IntVect(1)));
322 bool has_bcoef = (bcoef[0] != nullptr);
323
324 const auto& maskvals = this->m_maskvals[amrlev][mglev];
325 const auto& bcondloc = *(this->m_bcondloc[amrlev][mglev]);
326 const auto& bndry = *(this->m_bndry_sol[amrlev]);
327
328 MFItInfo mfi_info;
329 if (Gpu::notInLaunchRegion()) { mfi_info.SetDynamic(true); }
330
331#ifdef AMREX_USE_OMP
332#pragma omp parallel if (Gpu::notInLaunchRegion())
333#endif
334 for (MFIter mfi(rhs, mfi_info); mfi.isValid(); ++mfi)
335 {
336 const Box& vbx = mfi.validbox();
337 auto const& rhsfab = rhs.array(mfi);
338
339 const auto & bdlv = bcondloc.bndryLocs(mfi);
340 const auto & bdcv = bcondloc.bndryConds(mfi);
341
342 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim)
343 {
344 auto const bfab = (has_bcoef)
345 ? bcoef[idim]->const_array(mfi) : foo.const_array();
346 const Orientation olo(idim,Orientation::low);
347 const Orientation ohi(idim,Orientation::high);
348 const Box blo = amrex::adjCellLo(vbx, idim);
349 const Box bhi = amrex::adjCellHi(vbx, idim);
350 const auto& mlo = maskvals[olo].array(mfi);
351 const auto& mhi = maskvals[ohi].array(mfi);
352 const auto& bvlo = bndry.bndryValues(olo).array(mfi);
353 const auto& bvhi = bndry.bndryValues(ohi).array(mfi);
354 bool outside_domain_lo = !(domain.contains(blo));
355 bool outside_domain_hi = !(domain.contains(bhi));
356 if ((!outside_domain_lo) && (!outside_domain_hi)) { continue; }
357 for (int icomp = 0; icomp < ncomp; ++icomp) {
358 const BoundCond bctlo = bdcv[icomp][olo];
359 const BoundCond bcthi = bdcv[icomp][ohi];
360 const RT bcllo = bdlv[icomp][olo];
361 const RT bclhi = bdlv[icomp][ohi];
362 if (this->m_lobc_orig[icomp][idim] == LinOpBCType::inhomogNeumann && outside_domain_lo)
363 {
364 if (idim == 0) {
365 RT fac = beta*dxi;
366 if (this->m_has_metric_term && !has_bcoef) {
367#if (AMREX_SPACEDIM == 1)
368 fac *= static_cast<RT>(problo[0]*problo[0]);
369#elif (AMREX_SPACEDIM == 2)
370 fac *= static_cast<RT>(problo[0]);
371#endif
372 }
373 AMREX_HOST_DEVICE_FOR_3D(blo, i, j, k,
374 {
375 mllinop_apply_innu_xlo(i,j,k, rhsfab, mlo, bfab,
376 bctlo, bcllo, bvlo,
377 fac, has_bcoef, icomp);
378 });
379 } else if (idim == 1) {
380 RT fac = beta*dyi;
381 if (this->m_has_metric_term && !has_bcoef) {
382 AMREX_HOST_DEVICE_FOR_3D(blo, i, j, k,
383 {
384 mllinop_apply_innu_ylo_m(i,j,k, rhsfab, mlo,
385 bctlo, bcllo, bvlo,
386 fac, xlo, dx, icomp);
387 });
388 }
389 else {
390 AMREX_HOST_DEVICE_FOR_3D(blo, i, j, k,
391 {
392 mllinop_apply_innu_ylo(i,j,k, rhsfab, mlo, bfab,
393 bctlo, bcllo, bvlo,
394 fac, has_bcoef, icomp);
395 });
396 }
397 } else {
398 RT fac = beta*dzi;
399 AMREX_HOST_DEVICE_FOR_3D(blo, i, j, k,
400 {
401 mllinop_apply_innu_zlo(i,j,k, rhsfab, mlo, bfab,
402 bctlo, bcllo, bvlo,
403 fac, has_bcoef, icomp);
404 });
405 }
406 }
407 if (this->m_hibc_orig[icomp][idim] == LinOpBCType::inhomogNeumann && outside_domain_hi)
408 {
409 if (idim == 0) {
410 RT fac = beta*dxi;
411 if (this->m_has_metric_term && !has_bcoef) {
412#if (AMREX_SPACEDIM == 1)
413 fac *= static_cast<RT>(probhi[0]*probhi[0]);
414#elif (AMREX_SPACEDIM == 2)
415 fac *= static_cast<RT>(probhi[0]);
416#endif
417 }
418 AMREX_HOST_DEVICE_FOR_3D(bhi, i, j, k,
419 {
420 mllinop_apply_innu_xhi(i,j,k, rhsfab, mhi, bfab,
421 bcthi, bclhi, bvhi,
422 fac, has_bcoef, icomp);
423 });
424 } else if (idim == 1) {
425 RT fac = beta*dyi;
426 if (this->m_has_metric_term && !has_bcoef) {
427 AMREX_HOST_DEVICE_FOR_3D(bhi, i, j, k,
428 {
429 mllinop_apply_innu_yhi_m(i,j,k, rhsfab, mhi,
430 bcthi, bclhi, bvhi,
431 fac, xlo, dx, icomp);
432 });
433 } else {
434 AMREX_HOST_DEVICE_FOR_3D(bhi, i, j, k,
435 {
436 mllinop_apply_innu_yhi(i,j,k, rhsfab, mhi, bfab,
437 bcthi, bclhi, bvhi,
438 fac, has_bcoef, icomp);
439 });
440 }
441 } else {
442 RT fac = beta*dzi;
443 AMREX_HOST_DEVICE_FOR_3D(bhi, i, j, k,
444 {
445 mllinop_apply_innu_zhi(i,j,k, rhsfab, mhi, bfab,
446 bcthi, bclhi, bvhi,
447 fac, has_bcoef, icomp);
448 });
449 }
450 }
451
452 if (has_robin) {
453 // For Robin BC, see comments in AMReX_MLABecLaplacian.cpp above
454 // function applyRobinBCTermsCoeffs.
455 auto const& rbc = (*this->m_robin_bcval[amrlev])[mfi].const_array(icomp*3);
456 if (this->m_lobc_orig[icomp][idim] == LinOpBCType::Robin && outside_domain_lo)
457 {
458 if (idim == 0) {
459 RT fac = beta*dxi*dxi;
460 AMREX_HOST_DEVICE_FOR_3D(blo, i, j, k,
461 {
462 RT A = rbc(i,j,k,2)
463 / (rbc(i,j,k,1)*dxi + rbc(i,j,k,0)*RT(0.5));
464 rhsfab(i+1,j,k,icomp) += fac*bfab(i+1,j,k,icomp)*A;
465 });
466 } else if (idim == 1) {
467 RT fac = beta*dyi*dyi;
468 AMREX_HOST_DEVICE_FOR_3D(blo, i, j, k,
469 {
470 RT A = rbc(i,j,k,2)
471 / (rbc(i,j,k,1)*dyi + rbc(i,j,k,0)*RT(0.5));
472 rhsfab(i,j+1,k,icomp) += fac*bfab(i,j+1,k,icomp)*A;
473 });
474 } else {
475 RT fac = beta*dzi*dzi;
476 AMREX_HOST_DEVICE_FOR_3D(blo, i, j, k,
477 {
478 RT A = rbc(i,j,k,2)
479 / (rbc(i,j,k,1)*dzi + rbc(i,j,k,0)*RT(0.5));
480 rhsfab(i,j,k+1,icomp) += fac*bfab(i,j,k+1,icomp)*A;
481 });
482 }
483 }
484 if (this->m_hibc_orig[icomp][idim] == LinOpBCType::Robin && outside_domain_hi)
485 {
486 if (idim == 0) {
487 RT fac = beta*dxi*dxi;
488 AMREX_HOST_DEVICE_FOR_3D(bhi, i, j, k,
489 {
490 RT A = rbc(i,j,k,2)
491 / (rbc(i,j,k,1)*dxi + rbc(i,j,k,0)*RT(0.5));
492 rhsfab(i-1,j,k,icomp) += fac*bfab(i,j,k,icomp)*A;
493 });
494 } else if (idim == 1) {
495 RT fac = beta*dyi*dyi;
496 AMREX_HOST_DEVICE_FOR_3D(bhi, i, j, k,
497 {
498 RT A = rbc(i,j,k,2)
499 / (rbc(i,j,k,1)*dyi + rbc(i,j,k,0)*RT(0.5));
500 rhsfab(i,j-1,k,icomp) += fac*bfab(i,j,k,icomp)*A;
501 });
502 } else {
503 RT fac = beta*dzi*dzi;
504 AMREX_HOST_DEVICE_FOR_3D(bhi, i, j, k,
505 {
506 RT A = rbc(i,j,k,2)
507 / (rbc(i,j,k,1)*dzi + rbc(i,j,k,0)*RT(0.5));
508 rhsfab(i,j,k-1,icomp) += fac*bfab(i,j,k,icomp)*A;
509 });
510 }
511 }
512 }
513 }
514 }
515
516 }
517}
518
519template <typename MF>
520void
522 int amrlev, const Array<MF*,AMREX_SPACEDIM>& grad, MF const& sol,
523 bool mult_bcoef) const
524{
525 /*
526 * if (mult_bcoef == true)
527 * grad is -bceof*grad phi
528 * else
529 * grad is grad phi
530 */
531 RT fac = mult_bcoef ? RT(-1.0) : RT(1.0);
532
533 bool has_inhomog_neumann = this->hasInhomogNeumannBC();
534 bool has_robin = this->hasRobinBC();
535
536 if (!has_inhomog_neumann && !has_robin) { return; }
537
538 int ncomp = this->getNComp();
539 const int mglev = 0;
540
541 const auto dxinv = this->m_geom[amrlev][mglev].InvCellSize();
542 const Box domain = this->m_geom[amrlev][mglev].growPeriodicDomain(1);
543
544 Array<MF const*, AMREX_SPACEDIM> bcoef = {AMREX_D_DECL(nullptr,nullptr,nullptr)};
545 if (mult_bcoef) {
546 bcoef = getBCoeffs(amrlev,mglev);
547 }
548
549 const auto& bndry = *this->m_bndry_sol[amrlev];
550
551 MFItInfo mfi_info;
552 if (Gpu::notInLaunchRegion()) { mfi_info.SetDynamic(true); }
553
554#ifdef AMREX_USE_OMP
555#pragma omp parallel if (Gpu::notInLaunchRegion())
556#endif
557 for (MFIter mfi(sol, mfi_info); mfi.isValid(); ++mfi)
558 {
559 Box const& vbx = mfi.validbox();
560 for (OrientationIter orit; orit.isValid(); ++orit) {
561 const Orientation ori = orit();
562 const int idim = ori.coordDir();
563 const Box& ccb = amrex::adjCell(vbx, ori);
564 const Dim3 os = IntVect::TheDimensionVector(idim).dim3();
565 const RT dxi = static_cast<RT>(dxinv[idim]);
566 if (! domain.contains(ccb)) {
567 for (int icomp = 0; icomp < ncomp; ++icomp) {
568 auto const& phi = sol.const_array(mfi,icomp);
569 auto const& bv = bndry.bndryValues(ori).multiFab().const_array(mfi,icomp);
570 auto const& bc = bcoef[idim] ? bcoef[idim]->const_array(mfi,icomp)
572 auto const& f = grad[idim]->array(mfi,icomp);
573 if (ori.isLow()) {
574 if (this->m_lobc_orig[icomp][idim] ==
575 LinOpBCType::inhomogNeumann) {
576 AMREX_HOST_DEVICE_FOR_3D(ccb, i, j, k,
577 {
578 int ii = i+os.x;
579 int jj = j+os.y;
580 int kk = k+os.z;
581 RT b = bc ? bc(ii,jj,kk) : RT(1.0);
582 f(ii,jj,kk) = fac*b*bv(i,j,k);
583 });
584 } else if (this->m_lobc_orig[icomp][idim] ==
585 LinOpBCType::Robin) {
586 auto const& rbc = (*this->m_robin_bcval[amrlev])[mfi].const_array(icomp*3);
587 AMREX_HOST_DEVICE_FOR_3D(ccb, i, j, k,
588 {
589 int ii = i+os.x;
590 int jj = j+os.y;
591 int kk = k+os.z;
592 RT tmp = RT(1.0) /
593 (rbc(i,j,k,1)*dxi + rbc(i,j,k,0)*RT(0.5));
594 RT RA = rbc(i,j,k,2) * tmp;
595 RT RB = (rbc(i,j,k,1)*dxi - rbc(i,j,k,0)*RT(0.5)) * tmp;
596 RT b = bc ? bc(ii,jj,kk) : RT(1.0);
597 f(ii,jj,kk) = fac*b*dxi*((RT(1.0)-RB)*phi(ii,jj,kk)-RA);
598 });
599 }
600 } else {
601 if (this->m_hibc_orig[icomp][idim] ==
602 LinOpBCType::inhomogNeumann) {
603 AMREX_HOST_DEVICE_FOR_3D(ccb, i, j, k,
604 {
605 RT b = bc ? bc(i,j,k) : RT(1.0);
606 f(i,j,k) = fac*b*bv(i,j,k);
607 });
608 } else if (this->m_hibc_orig[icomp][idim] ==
609 LinOpBCType::Robin) {
610 auto const& rbc = (*this->m_robin_bcval[amrlev])[mfi].const_array(icomp*3);
611 AMREX_HOST_DEVICE_FOR_3D(ccb, i, j, k,
612 {
613 RT tmp = RT(1.0) /
614 (rbc(i,j,k,1)*dxi + rbc(i,j,k,0)*RT(0.5));
615 RT RA = rbc(i,j,k,2) * tmp;
616 RT RB = (rbc(i,j,k,1)*dxi - rbc(i,j,k,0)*RT(0.5)) * tmp;
617 RT b = bc ? bc(i,j,k) : RT(1.0);
618 f(i,j,k) = fac*b*dxi*(RA+(RB-RT(1.0))*
619 phi(i-os.x,j-os.y,k-os.z));
620 });
621 }
622 }
623 }
624 }
625 }
626 }
627}
628
629template <typename MF>
630void
631MLCellABecLapT<MF>::applyOverset (int amrlev, MF& rhs) const
632{
633 if (m_overset_mask[amrlev][0]) {
634 const int ncomp = this->getNComp();
635#ifdef AMREX_USE_GPU
636 if (Gpu::inLaunchRegion() && m_overset_mask[amrlev][0]->isFusingCandidate()) {
637 auto const& osma = m_overset_mask[amrlev][0]->const_arrays();
638 auto const& rhsa = rhs.arrays();
639 ParallelFor(*m_overset_mask[amrlev][0], IntVect(0), ncomp,
640 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
641 {
642 if (osma[box_no](i,j,k) == 0) {
643 rhsa[box_no](i,j,k,n) = RT(0.0);
644 }
645 });
646 if (!Gpu::inNoSyncRegion()) {
648 }
649 } else
650#endif
651 {
652#ifdef AMREX_USE_OMP
653#pragma omp parallel if (Gpu::notInLaunchRegion())
654#endif
655 for (MFIter mfi(*m_overset_mask[amrlev][0],TilingIfNotGPU()); mfi.isValid(); ++mfi)
656 {
657 const Box& bx = mfi.tilebox();
658 auto const& rfab = rhs.array(mfi);
659 auto const& osm = m_overset_mask[amrlev][0]->const_array(mfi);
660 AMREX_HOST_DEVICE_PARALLEL_FOR_4D(bx, ncomp, i, j, k, n,
661 {
662 if (osm(i,j,k) == 0) { rfab(i,j,k,n) = RT(0.0); }
663 });
664 }
665 }
666 }
667}
668
669#if defined(AMREX_USE_HYPRE) && (AMREX_SPACEDIM > 1)
670template <typename MF>
671std::unique_ptr<Hypre>
673{
674 if constexpr (!std::is_same<MF,MultiFab>()) {
675 amrex::Abort("MLCellABecLap Hypre interface only supports MultiFab");
676 } else {
677 const BoxArray& ba = this->m_grids[0].back();
678 const DistributionMapping& dm = this->m_dmap[0].back();
679 const Geometry& geom = this->m_geom[0].back();
680 const auto& factory = *(this->m_factory[0].back());
681 MPI_Comm comm = this->BottomCommunicator();
682
683 const int mglev = this->NMGLevels(0)-1;
684
685 auto om = getOversetMask(0, mglev);
686
687 auto hypre_solver = amrex::makeHypre(ba, dm, geom, comm, hypre_interface, om);
688
689 hypre_solver->setScalars(getAScalar(), getBScalar());
690
691 auto ac = getACoeffs(0, mglev);
692 if (ac)
693 {
694 hypre_solver->setACoeffs(*ac);
695 }
696 else
697 {
698 MultiFab alpha(ba,dm,1,0,MFInfo(),factory);
699 alpha.setVal(0.0);
700 hypre_solver->setACoeffs(alpha);
701 }
702
703 auto bc = getBCoeffs(0, mglev);
704 if (bc[0])
705 {
706 hypre_solver->setBCoeffs(bc);
707 }
708 else
709 {
710 Array<MultiFab,AMREX_SPACEDIM> beta;
711 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim)
712 {
713 beta[idim].define(amrex::convert(ba,IntVect::TheDimensionVector(idim)),
714 dm, 1, 0, MFInfo(), factory);
715 beta[idim].setVal(1.0);
716 }
717 hypre_solver->setBCoeffs(amrex::GetArrOfConstPtrs(beta));
718 }
719 hypre_solver->setIsMatrixSingular(this->isBottomSingular());
720
721 return hypre_solver;
722 }
723 return nullptr;
724}
725#endif
726
727#ifdef AMREX_USE_PETSC
728template <typename MF>
729std::unique_ptr<PETScABecLap>
730MLCellABecLapT<MF>::makePETSc () const
731{
732 if constexpr (!std::is_same<MF,MultiFab>()) {
733 amrex::Abort("MLCellABecLap PETSc interface only supports MultiFab");
734 } else {
735 const BoxArray& ba = this->m_grids[0].back();
736 const DistributionMapping& dm = this->m_dmap[0].back();
737 const Geometry& geom = this->m_geom[0].back();
738 const auto& factory = *(this->m_factory[0].back());
739 MPI_Comm comm = this->BottomCommunicator();
740
741 auto petsc_solver = makePetsc(ba, dm, geom, comm);
742
743 petsc_solver->setScalars(getAScalar(), getBScalar());
744
745 const int mglev = this->NMGLevels(0)-1;
746 auto ac = getACoeffs(0, mglev);
747 if (ac)
748 {
749 petsc_solver->setACoeffs(*ac);
750 }
751 else
752 {
753 MultiFab alpha(ba,dm,1,0,MFInfo(),factory);
754 alpha.setVal(0.0);
755 petsc_solver->setACoeffs(alpha);
756 }
757
758 auto bc = getBCoeffs(0, mglev);
759 if (bc[0])
760 {
761 petsc_solver->setBCoeffs(bc);
762 }
763 else
764 {
765 Array<MultiFab,AMREX_SPACEDIM> beta;
766 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim)
767 {
768 beta[idim].define(amrex::convert(ba,IntVect::TheDimensionVector(idim)),
769 dm, 1, 0, MFInfo(), factory);
770 beta[idim].setVal(1.0);
771 }
772 petsc_solver->setBCoeffs(amrex::GetArrOfConstPtrs(beta));
773 }
774 return petsc_solver;
775 }
776 return nullptr;
777}
778#endif
779
780extern template class MLCellABecLapT<MultiFab>;
781
783
784}
785
786#endif
#define BL_PROFILE(a)
Definition AMReX_BLProfiler.H:551
#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
int MPI_Comm
Definition AMReX_ccse-mpi.H:47
Maintain an identifier for boundary condition types.
Definition AMReX_BoundCond.H:20
AMREX_GPU_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:708
AMREX_GPU_HOST_DEVICE bool coarsenable(const IntVectND< dim > &refrat, const IntVectND< dim > &min_width) const noexcept
Definition AMReX_Box.H:745
AMREX_GPU_HOST_DEVICE bool contains(const IntVectND< dim > &p) const noexcept
Returns true if argument is contained within BoxND.
Definition AMReX_Box.H:204
const FAB & get(const MFIter &mfi) const noexcept
Return a constant reference to the FAB associated with mfi.
Definition AMReX_FabArray.H:509
Definition AMReX_FabFactory.H:50
Interface
Definition AMReX_Hypre.H:21
AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE 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:689
Definition AMReX_MFIter.H:57
bool isValid() const noexcept
Is the iterator valid i.e. is it associated with a FAB?
Definition AMReX_MFIter.H:141
Definition AMReX_MLCellABecLap.H:13
MLCellABecLapT(const MLCellABecLapT< MF > &)=delete
LPInfo m_lpinfo_arg
Definition AMReX_MLCellABecLap.H:87
virtual MF const * getACoeffs(int amrlev, int mglev) const =0
void addInhomogNeumannFlux(int amrlev, const Array< MF *, AMREX_SPACEDIM > &grad, MF const &sol, bool mult_bcoef) const final
Definition AMReX_MLCellABecLap.H:521
void getFluxes(const Vector< Array< MF *, AMREX_SPACEDIM > > &a_flux, const Vector< MF * > &a_sol, Location a_loc) const final
Definition AMReX_MLCellABecLap.H:276
MLCellABecLapT< MF > & operator=(const MLCellABecLapT< MF > &)=delete
virtual Array< MF const *, AMREX_SPACEDIM > getBCoeffs(int amrlev, int mglev) const =0
MLCellABecLapT(MLCellABecLapT< MF > &&)=delete
typename MF::value_type RT
Definition AMReX_MLCellABecLap.H:17
void setDirichletNodesToZero(int amrlev, int mglev, MF &mf) const override
Definition AMReX_MLCellABecLap.H:256
void applyOverset(int amrlev, MF &rhs) const override
for overset solver only
Definition AMReX_MLCellABecLap.H:631
virtual RT getBScalar() const =0
iMultiFab const * getOversetMask(int amrlev, int mglev) const
Definition AMReX_MLCellABecLap.H:42
bool needsUpdate() const override
Does it need update if it's reused?
Definition AMReX_MLCellABecLap.H:46
typename MLLinOpT< MF >::Location Location
Definition AMReX_MLCellABecLap.H:19
typename MF::fab_type FAB
Definition AMReX_MLCellABecLap.H:16
Vector< Vector< std::unique_ptr< iMultiFab > > > m_overset_mask
Definition AMReX_MLCellABecLap.H:85
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={})
Definition AMReX_MLCellABecLap.H:94
bool supportInhomogNeumannBC() const noexcept override
Definition AMReX_MLCellABecLap.H:89
void prepareForSolve() override
Definition AMReX_MLCellABecLap.H:249
~MLCellABecLapT() override=default
void getFluxes(const Vector< MF * > &, const Vector< MF * > &) const final
Definition AMReX_MLCellABecLap.H:58
virtual RT getAScalar() const =0
void applyInhomogNeumannTerm(int amrlev, MF &rhs) const final
Extra terms introduced when we treat inhomogeneous Nuemann BC as homogeneous.
Definition AMReX_MLCellABecLap.H:299
void update() override
Update for reuse.
Definition AMReX_MLCellABecLap.H:242
Definition AMReX_MLCellLinOp.H:21
void update() override
Update for reuse.
Definition AMReX_MLCellLinOp.H:653
void prepareForSolve() override
Definition AMReX_MLCellLinOp.H:1617
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={})
Definition AMReX_MLCellLinOp.H:362
bool needsUpdate() const override
Does it need update if it's reused?
Definition AMReX_MLCellLinOp.H:53
An Iterator over the Orientation of Faces of a Box.
Definition AMReX_Orientation.H:135
AMREX_GPU_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
AMREX_GPU_HOST_DEVICE int coordDir() const noexcept
Returns the coordinate direction.
Definition AMReX_Orientation.H:83
AMREX_GPU_HOST_DEVICE bool isLow() const noexcept
Returns true if Orientation is low.
Definition AMReX_Orientation.H:89
@ low
Definition AMReX_Orientation.H:34
@ high
Definition AMReX_Orientation.H:34
Definition AMReX_Reduce.H:249
Type value()
Definition AMReX_Reduce.H:281
Definition AMReX_Reduce.H:364
std::enable_if_t< IsFabArray< MF >::value > eval(MF const &mf, IntVect const &nghost, D &reduce_data, F &&f)
Definition AMReX_Reduce.H:433
This class is a thin wrapper around std::vector. Unlike vector, Vector::operator[] provides bound che...
Definition AMReX_Vector.H:27
Long size() const noexcept
Definition AMReX_Vector.H:50
Definition AMReX_iMultiFab.H:32
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
void streamSynchronize() noexcept
Definition AMReX_GpuDevice.H:237
bool inLaunchRegion() noexcept
Definition AMReX_GpuControl.H:86
bool notInLaunchRegion() noexcept
Definition AMReX_GpuControl.H:87
bool inNoSyncRegion() noexcept
Definition AMReX_GpuControl.H:146
void Min(KeyValuePair< K, V > &vi, MPI_Comm comm)
Definition AMReX_ParallelReduce.H:152
MPI_Comm CommunicatorSub() noexcept
sub-communicator for current frame
Definition AMReX_ParallelContext.H:70
Definition AMReX_Amr.cpp:49
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE int coarsen_overset_mask(Box const &bx, Array4< int > const &cmsk, Array4< int const > const &fmsk) noexcept
Definition AMReX_MLCellABecLap_1D_K.H:8
std::enable_if_t< std::is_integral_v< T > > ParallelFor(TypeList< CTOs... > ctos, std::array< int, sizeof...(CTOs)> const &runtime_options, T N, F &&f)
Definition AMReX_CTOParallelForImpl.H:191
BoxND< AMREX_SPACEDIM > Box
Definition AMReX_BaseFwd.H:27
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void mllinop_apply_innu_zlo(int i, int j, int k, Array4< T > const &rhs, Array4< int const > const &mask, Array4< T const > const &bcoef, BoundCond bct, T, Array4< T const > const &bcval, T fac, bool has_bcoef, int icomp) noexcept
Definition AMReX_MLLinOp_K.H:1026
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void mllinop_apply_innu_xhi(int i, int j, int k, Array4< T > const &rhs, Array4< int const > const &mask, Array4< T const > const &bcoef, BoundCond bct, T, Array4< T const > const &bcval, T fac, bool has_bcoef, int icomp) noexcept
Definition AMReX_MLLinOp_K.H:948
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE BoxND< dim > convert(const BoxND< dim > &b, const IntVectND< dim > &typ) noexcept
Returns a BoxND with different type.
Definition AMReX_Box.H:1435
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void mllinop_apply_innu_ylo(int i, int j, int k, Array4< T > const &rhs, Array4< int const > const &mask, Array4< T const > const &bcoef, BoundCond bct, T, Array4< T const > const &bcval, T fac, bool has_bcoef, int icomp) noexcept
Definition AMReX_MLLinOp_K.H:964
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void mllinop_apply_innu_zhi(int i, int j, int k, Array4< T > const &rhs, Array4< int const > const &mask, Array4< T const > const &bcoef, BoundCond bct, T, Array4< T const > const &bcval, T fac, bool has_bcoef, int icomp) noexcept
Definition AMReX_MLLinOp_K.H:1042
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE BoxND< dim > adjCellLo(const BoxND< dim > &b, int dir, int len=1) noexcept
Returns the cell centered BoxND of length len adjacent to b on the low end along the coordinate direc...
Definition AMReX_Box.H:1591
bool isMFIterSafe(const FabArrayBase &x, const FabArrayBase &y)
Definition AMReX_MFIter.H:219
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void mllinop_apply_innu_xlo(int i, int j, int k, Array4< T > const &rhs, Array4< int const > const &mask, Array4< T const > const &bcoef, BoundCond bct, T, Array4< T const > const &bcval, T fac, bool has_bcoef, int icomp) noexcept
Definition AMReX_MLLinOp_K.H:932
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void mllinop_apply_innu_ylo_m(int i, int j, int k, Array4< T > const &rhs, Array4< int const > const &mask, BoundCond bct, T, Array4< T const > const &bcval, T fac, T xlo, T dx, int icomp) noexcept
Definition AMReX_MLLinOp_K.H:980
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE BoxND< dim > coarsen(const BoxND< dim > &b, int ref_ratio) noexcept
Coarsen BoxND by given (positive) refinement ratio. NOTE: if type(dir) = CELL centered: lo <- lo/rati...
Definition AMReX_Box.H:1304
IntVectND< AMREX_SPACEDIM > IntVect
Definition AMReX_BaseFwd.H:30
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE BoxND< dim > adjCell(const BoxND< dim > &b, Orientation face, int len=1) noexcept
Similar to adjCellLo and adjCellHi; operates on given face.
Definition AMReX_Box.H:1634
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void mllinop_apply_innu_yhi(int i, int j, int k, Array4< T > const &rhs, Array4< int const > const &mask, Array4< T const > const &bcoef, BoundCond bct, T, Array4< T const > const &bcval, T fac, bool has_bcoef, int icomp) noexcept
Definition AMReX_MLLinOp_K.H:995
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void ignore_unused(const Ts &...)
This shuts up the compiler about unused variables.
Definition AMReX.H:127
bool TilingIfNotGPU() noexcept
Definition AMReX_MFIter.H:12
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void mllinop_apply_innu_yhi_m(int i, int j, int k, Array4< T > const &rhs, Array4< int const > const &mask, BoundCond bct, T, Array4< T const > const &bcval, T fac, T xlo, T dx, int icomp) noexcept
Definition AMReX_MLLinOp_K.H:1011
std::unique_ptr< PETScABecLap > makePetsc(const BoxArray &grids, const DistributionMapping &dmap, const Geometry &geom, MPI_Comm comm_)
Definition AMReX_PETSc.cpp:54
std::array< T const *, AMREX_SPACEDIM > GetArrOfConstPtrs(const std::array< T, AMREX_SPACEDIM > &a) noexcept
Definition AMReX_Array.H:994
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE BoxND< dim > refine(const BoxND< dim > &b, int ref_ratio) noexcept
Definition AMReX_Box.H:1342
void Abort(const std::string &msg)
Print out message to cerr and exit via abort().
Definition AMReX.cpp:230
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE BoxND< dim > adjCellHi(const BoxND< dim > &b, int dir, int len=1) noexcept
Similar to adjCellLo but builds an adjacent BoxND on the high end.
Definition AMReX_Box.H:1612
std::unique_ptr< Hypre > makeHypre(const BoxArray &grids, const DistributionMapping &dmap, const Geometry &geom, MPI_Comm comm_, Hypre::Interface interface, const iMultiFab *overset_mask)
Definition AMReX_Hypre.cpp:12
std::array< T, N > Array
Definition AMReX_Array.H:24
Definition AMReX_Array4.H:61
Definition AMReX_Dim3.H:12
int x
Definition AMReX_Dim3.H:12
int z
Definition AMReX_Dim3.H:12
int y
Definition AMReX_Dim3.H:12
Definition AMReX_MLLinOp.H:35
int max_coarsening_level
Definition AMReX_MLLinOp.H:44
Location
Definition AMReX_MLLinOp.H:87
FabArray memory allocation information.
Definition AMReX_FabArray.H:66
Definition AMReX_MFIter.H:20
MFItInfo & SetDynamic(bool f) noexcept
Definition AMReX_MFIter.H:34