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
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#if defined(AMREX_USE_PETSC) && (AMREX_SPACEDIM > 1)
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 if (betainv != RT(1.0)) {
289 a_flux[alev][idim]->mult(betainv, 0, ncomp);
290 }
291 }
292 this->addInhomogNeumannFlux(alev, a_flux[alev], *a_sol[alev], true);
293 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
294 this->unapplyMetricTerm(alev, 0, *a_flux[alev][idim]);
295 }
296 }
297}
298
299template <typename MF>
300void
302{
303 bool has_inhomog_neumann = this->hasInhomogNeumannBC();
304 bool has_robin = this->hasRobinBC();
305
306 if (!has_inhomog_neumann && !has_robin) { return; }
307
308 int ncomp = this->getNComp();
309 const int mglev = 0;
310
311 const auto problo = this->m_geom[amrlev][mglev].ProbLoArray();
312 const auto probhi = this->m_geom[amrlev][mglev].ProbHiArray();
313 amrex::ignore_unused(probhi);
314 const RT dxi = static_cast<RT>(this->m_geom[amrlev][mglev].InvCellSize(0));
315 const RT dyi = static_cast<RT>((AMREX_SPACEDIM >= 2) ? this->m_geom[amrlev][mglev].InvCellSize(1) : Real(1.0));
316 const RT dzi = static_cast<RT>((AMREX_SPACEDIM == 3) ? this->m_geom[amrlev][mglev].InvCellSize(2) : Real(1.0));
317 const RT xlo = static_cast<RT>(problo[0]);
318 const RT dx = static_cast<RT>(this->m_geom[amrlev][mglev].CellSize(0));
319 const Box& domain = this->m_geom[amrlev][mglev].Domain();
320
321 const RT beta = getBScalar();
322 Array<MF const*, AMREX_SPACEDIM> const& bcoef = getBCoeffs(amrlev,mglev);
323 FAB foo(Box(IntVect(0),IntVect(1)));
324 bool has_bcoef = (bcoef[0] != nullptr);
325
326 const auto& maskvals = this->m_maskvals[amrlev][mglev];
327 const auto& bcondloc = *(this->m_bcondloc[amrlev][mglev]);
328 const auto& bndry = *(this->m_bndry_sol[amrlev]);
329
330 MFItInfo mfi_info;
331 if (Gpu::notInLaunchRegion()) { mfi_info.SetDynamic(true); }
332
333#ifdef AMREX_USE_OMP
334#pragma omp parallel if (Gpu::notInLaunchRegion())
335#endif
336 for (MFIter mfi(rhs, mfi_info); mfi.isValid(); ++mfi)
337 {
338 const Box& vbx = mfi.validbox();
339 auto const& rhsfab = rhs.array(mfi);
340
341 const auto & bdlv = bcondloc.bndryLocs(mfi);
342 const auto & bdcv = bcondloc.bndryConds(mfi);
343
344 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim)
345 {
346 auto const bfab = (has_bcoef)
347 ? bcoef[idim]->const_array(mfi) : foo.const_array();
348 const Orientation olo(idim,Orientation::low);
349 const Orientation ohi(idim,Orientation::high);
350 const Box blo = amrex::adjCellLo(vbx, idim);
351 const Box bhi = amrex::adjCellHi(vbx, idim);
352 const auto& mlo = maskvals[olo].array(mfi);
353 const auto& mhi = maskvals[ohi].array(mfi);
354 const auto& bvlo = bndry.bndryValues(olo).array(mfi);
355 const auto& bvhi = bndry.bndryValues(ohi).array(mfi);
356 bool outside_domain_lo = !(domain.contains(blo));
357 bool outside_domain_hi = !(domain.contains(bhi));
358 if ((!outside_domain_lo) && (!outside_domain_hi)) { continue; }
359 for (int icomp = 0; icomp < ncomp; ++icomp) {
360 const BoundCond bctlo = bdcv[icomp][olo];
361 const BoundCond bcthi = bdcv[icomp][ohi];
362 const RT bcllo = bdlv[icomp][olo];
363 const RT bclhi = bdlv[icomp][ohi];
364 if (this->m_lobc_orig[icomp][idim] == LinOpBCType::inhomogNeumann && outside_domain_lo)
365 {
366 if (idim == 0) {
367 RT fac = beta*dxi;
368 if (this->m_has_metric_term && !has_bcoef) {
369#if (AMREX_SPACEDIM == 1)
370 fac *= static_cast<RT>(problo[0]*problo[0]);
371#elif (AMREX_SPACEDIM == 2)
372 fac *= static_cast<RT>(problo[0]);
373#endif
374 }
375 AMREX_HOST_DEVICE_FOR_3D(blo, i, j, k,
376 {
377 mllinop_apply_innu_xlo(i,j,k, rhsfab, mlo, bfab,
378 bctlo, bcllo, bvlo,
379 fac, has_bcoef, icomp);
380 });
381 } else if (idim == 1) {
382 RT fac = beta*dyi;
383 if (this->m_has_metric_term && !has_bcoef) {
384 AMREX_HOST_DEVICE_FOR_3D(blo, i, j, k,
385 {
386 mllinop_apply_innu_ylo_m(i,j,k, rhsfab, mlo,
387 bctlo, bcllo, bvlo,
388 fac, xlo, dx, icomp);
389 });
390 }
391 else {
392 AMREX_HOST_DEVICE_FOR_3D(blo, i, j, k,
393 {
394 mllinop_apply_innu_ylo(i,j,k, rhsfab, mlo, bfab,
395 bctlo, bcllo, bvlo,
396 fac, has_bcoef, icomp);
397 });
398 }
399 } else {
400 RT fac = beta*dzi;
401 AMREX_HOST_DEVICE_FOR_3D(blo, i, j, k,
402 {
403 mllinop_apply_innu_zlo(i,j,k, rhsfab, mlo, bfab,
404 bctlo, bcllo, bvlo,
405 fac, has_bcoef, icomp);
406 });
407 }
408 }
409 if (this->m_hibc_orig[icomp][idim] == LinOpBCType::inhomogNeumann && outside_domain_hi)
410 {
411 if (idim == 0) {
412 RT fac = beta*dxi;
413 if (this->m_has_metric_term && !has_bcoef) {
414#if (AMREX_SPACEDIM == 1)
415 fac *= static_cast<RT>(probhi[0]*probhi[0]);
416#elif (AMREX_SPACEDIM == 2)
417 fac *= static_cast<RT>(probhi[0]);
418#endif
419 }
420 AMREX_HOST_DEVICE_FOR_3D(bhi, i, j, k,
421 {
422 mllinop_apply_innu_xhi(i,j,k, rhsfab, mhi, bfab,
423 bcthi, bclhi, bvhi,
424 fac, has_bcoef, icomp);
425 });
426 } else if (idim == 1) {
427 RT fac = beta*dyi;
428 if (this->m_has_metric_term && !has_bcoef) {
429 AMREX_HOST_DEVICE_FOR_3D(bhi, i, j, k,
430 {
431 mllinop_apply_innu_yhi_m(i,j,k, rhsfab, mhi,
432 bcthi, bclhi, bvhi,
433 fac, xlo, dx, icomp);
434 });
435 } else {
436 AMREX_HOST_DEVICE_FOR_3D(bhi, i, j, k,
437 {
438 mllinop_apply_innu_yhi(i,j,k, rhsfab, mhi, bfab,
439 bcthi, bclhi, bvhi,
440 fac, has_bcoef, icomp);
441 });
442 }
443 } else {
444 RT fac = beta*dzi;
445 AMREX_HOST_DEVICE_FOR_3D(bhi, i, j, k,
446 {
447 mllinop_apply_innu_zhi(i,j,k, rhsfab, mhi, bfab,
448 bcthi, bclhi, bvhi,
449 fac, has_bcoef, icomp);
450 });
451 }
452 }
453
454 if (has_robin) {
455 // For Robin BC, see comments in AMReX_MLABecLaplacian.cpp above
456 // function applyRobinBCTermsCoeffs.
457 auto const& rbc = (*this->m_robin_bcval[amrlev])[mfi].const_array(icomp*3);
458 if (this->m_lobc_orig[icomp][idim] == LinOpBCType::Robin && outside_domain_lo)
459 {
460 if (idim == 0) {
461 RT fac = beta*dxi*dxi;
462 AMREX_HOST_DEVICE_FOR_3D(blo, i, j, k,
463 {
464 RT A = rbc(i,j,k,2)
465 / (rbc(i,j,k,1)*dxi + rbc(i,j,k,0)*RT(0.5));
466 rhsfab(i+1,j,k,icomp) += fac*bfab(i+1,j,k,icomp)*A;
467 });
468 } else if (idim == 1) {
469 RT fac = beta*dyi*dyi;
470 AMREX_HOST_DEVICE_FOR_3D(blo, i, j, k,
471 {
472 RT A = rbc(i,j,k,2)
473 / (rbc(i,j,k,1)*dyi + rbc(i,j,k,0)*RT(0.5));
474 rhsfab(i,j+1,k,icomp) += fac*bfab(i,j+1,k,icomp)*A;
475 });
476 } else {
477 RT fac = beta*dzi*dzi;
478 AMREX_HOST_DEVICE_FOR_3D(blo, i, j, k,
479 {
480 RT A = rbc(i,j,k,2)
481 / (rbc(i,j,k,1)*dzi + rbc(i,j,k,0)*RT(0.5));
482 rhsfab(i,j,k+1,icomp) += fac*bfab(i,j,k+1,icomp)*A;
483 });
484 }
485 }
486 if (this->m_hibc_orig[icomp][idim] == LinOpBCType::Robin && outside_domain_hi)
487 {
488 if (idim == 0) {
489 RT fac = beta*dxi*dxi;
490 AMREX_HOST_DEVICE_FOR_3D(bhi, i, j, k,
491 {
492 RT A = rbc(i,j,k,2)
493 / (rbc(i,j,k,1)*dxi + rbc(i,j,k,0)*RT(0.5));
494 rhsfab(i-1,j,k,icomp) += fac*bfab(i,j,k,icomp)*A;
495 });
496 } else if (idim == 1) {
497 RT fac = beta*dyi*dyi;
498 AMREX_HOST_DEVICE_FOR_3D(bhi, i, j, k,
499 {
500 RT A = rbc(i,j,k,2)
501 / (rbc(i,j,k,1)*dyi + rbc(i,j,k,0)*RT(0.5));
502 rhsfab(i,j-1,k,icomp) += fac*bfab(i,j,k,icomp)*A;
503 });
504 } else {
505 RT fac = beta*dzi*dzi;
506 AMREX_HOST_DEVICE_FOR_3D(bhi, i, j, k,
507 {
508 RT A = rbc(i,j,k,2)
509 / (rbc(i,j,k,1)*dzi + rbc(i,j,k,0)*RT(0.5));
510 rhsfab(i,j,k-1,icomp) += fac*bfab(i,j,k,icomp)*A;
511 });
512 }
513 }
514 }
515 }
516 }
517
518 }
519}
520
521template <typename MF>
522void
524 int amrlev, const Array<MF*,AMREX_SPACEDIM>& grad, MF const& sol,
525 bool mult_bcoef) const
526{
527 /*
528 * if (mult_bcoef == true)
529 * grad is -bceof*grad phi
530 * else
531 * grad is grad phi
532 */
533 RT fac = mult_bcoef ? RT(-1.0) : RT(1.0);
534
535 bool has_inhomog_neumann = this->hasInhomogNeumannBC();
536 bool has_robin = this->hasRobinBC();
537
538 if (!has_inhomog_neumann && !has_robin) { return; }
539
540 int ncomp = this->getNComp();
541 const int mglev = 0;
542
543 const auto dxinv = this->m_geom[amrlev][mglev].InvCellSize();
544 const Box domain = this->m_geom[amrlev][mglev].growPeriodicDomain(1);
545
546 Array<MF const*, AMREX_SPACEDIM> bcoef = {AMREX_D_DECL(nullptr,nullptr,nullptr)};
547 if (mult_bcoef) {
548 bcoef = getBCoeffs(amrlev,mglev);
549 }
550
551 const auto& bndry = *this->m_bndry_sol[amrlev];
552
553 MFItInfo mfi_info;
554 if (Gpu::notInLaunchRegion()) { mfi_info.SetDynamic(true); }
555
556#ifdef AMREX_USE_OMP
557#pragma omp parallel if (Gpu::notInLaunchRegion())
558#endif
559 for (MFIter mfi(sol, mfi_info); mfi.isValid(); ++mfi)
560 {
561 Box const& vbx = mfi.validbox();
562 for (OrientationIter orit; orit.isValid(); ++orit) {
563 const Orientation ori = orit();
564 const int idim = ori.coordDir();
565 const Box& ccb = amrex::adjCell(vbx, ori);
566 const Dim3 os = IntVect::TheDimensionVector(idim).dim3();
567 const RT dxi = static_cast<RT>(dxinv[idim]);
568 if (! domain.contains(ccb)) {
569 for (int icomp = 0; icomp < ncomp; ++icomp) {
570 auto const& phi = sol.const_array(mfi,icomp);
571 auto const& bv = bndry.bndryValues(ori).multiFab().const_array(mfi,icomp);
572 auto const& bc = bcoef[idim] ? bcoef[idim]->const_array(mfi,icomp)
574 auto const& f = grad[idim]->array(mfi,icomp);
575 if (ori.isLow()) {
576 if (this->m_lobc_orig[icomp][idim] ==
577 LinOpBCType::inhomogNeumann) {
578 AMREX_HOST_DEVICE_FOR_3D(ccb, i, j, k,
579 {
580 int ii = i+os.x;
581 int jj = j+os.y;
582 int kk = k+os.z;
583 RT b = bc ? bc(ii,jj,kk) : RT(1.0);
584 f(ii,jj,kk) = fac*b*bv(i,j,k);
585 });
586 } else if (this->m_lobc_orig[icomp][idim] ==
587 LinOpBCType::Robin) {
588 auto const& rbc = (*this->m_robin_bcval[amrlev])[mfi].const_array(icomp*3);
589 AMREX_HOST_DEVICE_FOR_3D(ccb, i, j, k,
590 {
591 int ii = i+os.x;
592 int jj = j+os.y;
593 int kk = k+os.z;
594 RT tmp = RT(1.0) /
595 (rbc(i,j,k,1)*dxi + rbc(i,j,k,0)*RT(0.5));
596 RT RA = rbc(i,j,k,2) * tmp;
597 RT RB = (rbc(i,j,k,1)*dxi - rbc(i,j,k,0)*RT(0.5)) * tmp;
598 RT b = bc ? bc(ii,jj,kk) : RT(1.0);
599 f(ii,jj,kk) = fac*b*dxi*((RT(1.0)-RB)*phi(ii,jj,kk)-RA);
600 });
601 }
602 } else {
603 if (this->m_hibc_orig[icomp][idim] ==
604 LinOpBCType::inhomogNeumann) {
605 AMREX_HOST_DEVICE_FOR_3D(ccb, i, j, k,
606 {
607 RT b = bc ? bc(i,j,k) : RT(1.0);
608 f(i,j,k) = fac*b*bv(i,j,k);
609 });
610 } else if (this->m_hibc_orig[icomp][idim] ==
611 LinOpBCType::Robin) {
612 auto const& rbc = (*this->m_robin_bcval[amrlev])[mfi].const_array(icomp*3);
613 AMREX_HOST_DEVICE_FOR_3D(ccb, i, j, k,
614 {
615 RT tmp = RT(1.0) /
616 (rbc(i,j,k,1)*dxi + rbc(i,j,k,0)*RT(0.5));
617 RT RA = rbc(i,j,k,2) * tmp;
618 RT RB = (rbc(i,j,k,1)*dxi - rbc(i,j,k,0)*RT(0.5)) * tmp;
619 RT b = bc ? bc(i,j,k) : RT(1.0);
620 f(i,j,k) = fac*b*dxi*(RA+(RB-RT(1.0))*
621 phi(i-os.x,j-os.y,k-os.z));
622 });
623 }
624 }
625 }
626 }
627 }
628 }
629}
630
631template <typename MF>
632void
633MLCellABecLapT<MF>::applyOverset (int amrlev, MF& rhs) const
634{
635 if (m_overset_mask[amrlev][0]) {
636 const int ncomp = this->getNComp();
637#ifdef AMREX_USE_GPU
638 if (Gpu::inLaunchRegion() && m_overset_mask[amrlev][0]->isFusingCandidate()) {
639 auto const& osma = m_overset_mask[amrlev][0]->const_arrays();
640 auto const& rhsa = rhs.arrays();
641 ParallelFor(*m_overset_mask[amrlev][0], IntVect(0), ncomp,
642 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
643 {
644 if (osma[box_no](i,j,k) == 0) {
645 rhsa[box_no](i,j,k,n) = RT(0.0);
646 }
647 });
648 if (!Gpu::inNoSyncRegion()) {
650 }
651 } else
652#endif
653 {
654#ifdef AMREX_USE_OMP
655#pragma omp parallel if (Gpu::notInLaunchRegion())
656#endif
657 for (MFIter mfi(*m_overset_mask[amrlev][0],TilingIfNotGPU()); mfi.isValid(); ++mfi)
658 {
659 const Box& bx = mfi.tilebox();
660 auto const& rfab = rhs.array(mfi);
661 auto const& osm = m_overset_mask[amrlev][0]->const_array(mfi);
662 AMREX_HOST_DEVICE_PARALLEL_FOR_4D(bx, ncomp, i, j, k, n,
663 {
664 if (osm(i,j,k) == 0) { rfab(i,j,k,n) = RT(0.0); }
665 });
666 }
667 }
668 }
669}
670
671#if defined(AMREX_USE_HYPRE) && (AMREX_SPACEDIM > 1)
672template <typename MF>
673std::unique_ptr<Hypre>
675{
676 if constexpr (!std::is_same<MF,MultiFab>()) {
677 amrex::Abort("MLCellABecLap Hypre interface only supports MultiFab");
678 } else {
679 const BoxArray& ba = this->m_grids[0].back();
680 const DistributionMapping& dm = this->m_dmap[0].back();
681 const Geometry& geom = this->m_geom[0].back();
682 const auto& factory = *(this->m_factory[0].back());
683 MPI_Comm comm = this->BottomCommunicator();
684
685 const int mglev = this->NMGLevels(0)-1;
686
687 auto om = getOversetMask(0, mglev);
688
689 auto hypre_solver = amrex::makeHypre(ba, dm, geom, comm, hypre_interface, om);
690
691 hypre_solver->setScalars(getAScalar(), getBScalar());
692
693 auto ac = getACoeffs(0, mglev);
694 if (ac)
695 {
696 hypre_solver->setACoeffs(*ac);
697 }
698 else
699 {
700 MultiFab alpha(ba,dm,1,0,MFInfo(),factory);
701 alpha.setVal(0.0);
702 hypre_solver->setACoeffs(alpha);
703 }
704
705 auto bc = getBCoeffs(0, mglev);
706 if (bc[0])
707 {
708 hypre_solver->setBCoeffs(bc);
709 }
710 else
711 {
712 Array<MultiFab,AMREX_SPACEDIM> beta;
713 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim)
714 {
715 beta[idim].define(amrex::convert(ba,IntVect::TheDimensionVector(idim)),
716 dm, 1, 0, MFInfo(), factory);
717 beta[idim].setVal(1.0);
718 }
719 hypre_solver->setBCoeffs(amrex::GetArrOfConstPtrs(beta));
720 }
721 hypre_solver->setIsMatrixSingular(this->isBottomSingular());
722
723 return hypre_solver;
724 }
725 return nullptr;
726}
727#endif
728
729#if defined(AMREX_USE_PETSC) && (AMREX_SPACEDIM > 1)
730template <typename MF>
731std::unique_ptr<PETScABecLap>
732MLCellABecLapT<MF>::makePETSc () const
733{
734 if constexpr (!std::is_same<MF,MultiFab>()) {
735 amrex::Abort("MLCellABecLap PETSc interface only supports MultiFab");
736 } else {
737 const BoxArray& ba = this->m_grids[0].back();
738 const DistributionMapping& dm = this->m_dmap[0].back();
739 const Geometry& geom = this->m_geom[0].back();
740 const auto& factory = *(this->m_factory[0].back());
741 MPI_Comm comm = this->BottomCommunicator();
742
743 auto petsc_solver = makePetsc(ba, dm, geom, comm);
744
745 petsc_solver->setScalars(getAScalar(), getBScalar());
746
747 const int mglev = this->NMGLevels(0)-1;
748 auto ac = getACoeffs(0, mglev);
749 if (ac)
750 {
751 petsc_solver->setACoeffs(*ac);
752 }
753 else
754 {
755 MultiFab alpha(ba,dm,1,0,MFInfo(),factory);
756 alpha.setVal(0.0);
757 petsc_solver->setACoeffs(alpha);
758 }
759
760 auto bc = getBCoeffs(0, mglev);
761 if (bc[0])
762 {
763 petsc_solver->setBCoeffs(bc);
764 }
765 else
766 {
767 Array<MultiFab,AMREX_SPACEDIM> beta;
768 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim)
769 {
770 beta[idim].define(amrex::convert(ba,IntVect::TheDimensionVector(idim)),
771 dm, 1, 0, MFInfo(), factory);
772 beta[idim].setVal(1.0);
773 }
774 petsc_solver->setBCoeffs(amrex::GetArrOfConstPtrs(beta));
775 }
776 return petsc_solver;
777 }
778 return nullptr;
779}
780#endif
781
782extern template class MLCellABecLapT<MultiFab>;
783
785
786}
787
788#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
Returns true if argument is contained within BoxND.
Definition AMReX_Box.H:207
__host__ __device__ bool coarsenable(const IntVectND< dim > &refrat, const IntVectND< dim > &min_width) const noexcept
Definition AMReX_Box.H:748
__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:711
const FAB & get(const MFIter &mfi) const noexcept
Return a constant reference to the FAB associated with mfi.
Definition AMReX_FabArray.H:510
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:696
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
void addInhomogNeumannFlux(int amrlev, const Array< MF *, 3 > &grad, MF const &sol, bool mult_bcoef) const final
Definition AMReX_MLCellABecLap.H:523
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 getFluxes(const Vector< Array< MF *, 3 > > &a_flux, const Vector< MF * > &a_sol, Location a_loc) const final
Definition AMReX_MLCellABecLap.H:276
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: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:633
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:301
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
__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: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:28
Long size() const noexcept
Definition AMReX_Vector.H:53
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:260
bool inLaunchRegion() noexcept
Definition AMReX_GpuControl.H:92
bool notInLaunchRegion() noexcept
Definition AMReX_GpuControl.H:93
bool inNoSyncRegion() noexcept
Definition AMReX_GpuControl.H:152
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
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:1630
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
Returns a BoxND with different type.
Definition AMReX_Box.H:1453
std::array< T const *, 3 > GetArrOfConstPtrs(const std::array< T, 3 > &a) noexcept
Definition AMReX_Array.H:1010
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
__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
Returns the cell centered BoxND of length len adjacent to b on the low end along the coordinate direc...
Definition AMReX_Box.H:1609
__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
__host__ __device__ 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:1322
BoxND< 3 > Box
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:1652
bool isMFIterSafe(const FabArrayBase &x, const FabArrayBase &y)
Definition AMReX_MFIter.H:219
__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
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:54
__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
__host__ __device__ BoxND< dim > refine(const BoxND< dim > &b, int ref_ratio) noexcept
Definition AMReX_Box.H:1360
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