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