Block-Structured AMR Software Framework
Loading...
Searching...
No Matches
AMReX_MLABecLaplacian.H
Go to the documentation of this file.
1#ifndef AMREX_ML_ABECLAPLACIAN_H_
2#define AMREX_ML_ABECLAPLACIAN_H_
3#include <AMReX_Config.H>
4
6#include <AMReX_MLABecLap_K.H>
7
8namespace amrex {
9
19template <typename MF>
21 : public MLCellABecLapT<MF>
22{
23public:
24
25 using FAB = typename MF::fab_type;
26 using RT = typename MF::value_type;
27
30
32 MLABecLaplacianT () = default;
35 const Vector<BoxArray>& a_grids,
36 const Vector<DistributionMapping>& a_dmap,
37 const LPInfo& a_info = LPInfo(),
38 const Vector<FabFactory<FAB> const*>& a_factory = {},
39 int a_ncomp = 1);
40
43 const Vector<BoxArray>& a_grids,
44 const Vector<DistributionMapping>& a_dmap,
45 const Vector<iMultiFab const*>& a_overset_mask, // 1: unknown, 0: known
46 const LPInfo& a_info = LPInfo(),
47 const Vector<FabFactory<FAB> const*>& a_factory = {},
48 int a_ncomp = 1);
49
50 ~MLABecLaplacianT () override;
51
56
67 void define (const Vector<Geometry>& a_geom,
68 const Vector<BoxArray>& a_grids,
69 const Vector<DistributionMapping>& a_dmap,
70 const LPInfo& a_info = LPInfo(),
71 const Vector<FabFactory<FAB> const*>& a_factory = {},
72 int a_ncomp = 1);
73
85 void define (const Vector<Geometry>& a_geom,
86 const Vector<BoxArray>& a_grids,
87 const Vector<DistributionMapping>& a_dmap,
88 const Vector<iMultiFab const*>& a_overset_mask,
89 const LPInfo& a_info = LPInfo(),
90 const Vector<FabFactory<FAB> const*>& a_factory = {},
91 int a_ncomp = 1);
92
98 template <typename T1, typename T2>
99 requires (std::is_convertible_v<T1, typename MF::value_type> && std::is_convertible_v<T2, typename MF::value_type>)
100 void setScalars (T1 a, T2 b) noexcept;
101
111 template <FabArrayType AMF>
112 requires (std::is_convertible_v<typename AMF::value_type, typename MF::value_type>)
113 void setACoeffs (int amrlev, const AMF& alpha);
114
124 template <typename T>
125 requires (std::is_convertible_v<T, typename MF::value_type>)
126 void setACoeffs (int amrlev, T alpha);
127
137 template <FabArrayType AMF>
138 requires (std::is_convertible_v<typename AMF::value_type, typename MF::value_type>)
139 void setBCoeffs (int amrlev, const Array<AMF const*,AMREX_SPACEDIM>& beta);
140
150 template <typename T>
151 requires (std::is_convertible_v<T, typename MF::value_type>)
152 void setBCoeffs (int amrlev, T beta);
153
163 template <typename T>
164 requires (std::is_convertible_v<T, typename MF::value_type>)
165 void setBCoeffs (int amrlev, Vector<T> const& beta);
166
167 [[nodiscard]] int getNComp () const override { return m_ncomp; }
168
170 [[nodiscard]] bool needsUpdate () const override {
171 return (m_needs_update || MLCellABecLapT<MF>::needsUpdate());
172 }
174 void update () override;
175
177 void prepareForSolve () override;
179 [[nodiscard]] bool isSingular (int amrlev) const override { return m_is_singular[amrlev]; }
181 [[nodiscard]] bool isBottomSingular () const override { return m_is_singular[0]; }
186 void Fapply (int amrlev, int mglev, MF& out, const MF& in) const override;
192 void Fsmooth (int amrlev, int mglev, MF& sol, const MF& rhs, int redblack) const override;
198 void FFlux (int amrlev, const MFIter& mfi,
199 const Array<FAB*,AMREX_SPACEDIM>& flux,
200 const FAB& sol, Location /* loc */,
201 int face_only=0) const override;
202
204 void normalize (int amrlev, int mglev, MF& mf) const override;
205
207 [[nodiscard]] RT getAScalar () const final { return m_a_scalar; }
209 [[nodiscard]] RT getBScalar () const final { return m_b_scalar; }
211 [[nodiscard]] MF const* getACoeffs (int amrlev, int mglev) const final
212 { return &(m_a_coeffs[amrlev][mglev]); }
214 [[nodiscard]] Array<MF const*,AMREX_SPACEDIM> getBCoeffs (int amrlev, int mglev) const final
215 { return amrex::GetArrOfConstPtrs(m_b_coeffs[amrlev][mglev]); }
216
218 [[nodiscard]] std::unique_ptr<MLLinOpT<MF>> makeNLinOp (int /*grid_size*/) const final;
219
221 [[nodiscard]] bool supportNSolve () const override;
222
224 void copyNSolveSolution (MF& dst, MF const& src) const final;
225
227 void averageDownCoeffsSameAmrLevel (int amrlev, Vector<MF>& a,
230 void averageDownCoeffs ();
232 void averageDownCoeffsToCoarseAmrLevel (int flev);
233
236
239
252 static void FFlux (Box const& box, Real const* dxinv, RT bscalar,
254 Array<FAB*,AMREX_SPACEDIM> const& flux,
255 FAB const& sol, int face_only, int ncomp);
256
257 RT m_a_scalar = std::numeric_limits<RT>::quiet_NaN();
258 RT m_b_scalar = std::numeric_limits<RT>::quiet_NaN();
261
262 bool m_scalars_set = false;
263 bool m_acoef_set = false;
264
265protected:
266
268
269 [[nodiscard]] bool supportRobinBC () const noexcept override { return true; }
270
271private:
272
273 bool m_needs_update = true;
274
275 int m_ncomp = 1;
276
277 void define_ab_coeffs ();
278
279 void update_singular_flags ();
280};
281
282template <typename MF>
284 const Vector<BoxArray>& a_grids,
285 const Vector<DistributionMapping>& a_dmap,
286 const LPInfo& a_info,
287 const Vector<FabFactory<FAB> const*>& a_factory,
288 int a_ncomp)
289{
290 define(a_geom, a_grids, a_dmap, a_info, a_factory, a_ncomp);
291}
292
293template <typename MF>
295 const Vector<BoxArray>& a_grids,
296 const Vector<DistributionMapping>& a_dmap,
297 const Vector<iMultiFab const*>& a_overset_mask,
298 const LPInfo& a_info,
299 const Vector<FabFactory<FAB> const*>& a_factory,
300 int a_ncomp)
301{
302 define(a_geom, a_grids, a_dmap, a_overset_mask, a_info, a_factory, a_ncomp);
303}
304
305template <typename MF> MLABecLaplacianT<MF>::~MLABecLaplacianT () = default;
306
307template <typename MF>
308void
310 const Vector<BoxArray>& a_grids,
311 const Vector<DistributionMapping>& a_dmap,
312 const LPInfo& a_info,
313 const Vector<FabFactory<FAB> const*>& a_factory,
314 int a_ncomp)
315{
316 BL_PROFILE("MLABecLaplacian::define()");
317 this->m_ncomp = a_ncomp;
318 MLCellABecLapT<MF>::define(a_geom, a_grids, a_dmap, a_info, a_factory);
319 define_ab_coeffs();
320}
321
322template <typename MF>
323void
325 const Vector<BoxArray>& a_grids,
326 const Vector<DistributionMapping>& a_dmap,
327 const Vector<iMultiFab const*>& a_overset_mask,
328 const LPInfo& a_info,
329 const Vector<FabFactory<FAB> const*>& a_factory,
330 int a_ncomp)
331{
332 BL_PROFILE("MLABecLaplacian::define(overset)");
333 this->m_ncomp = a_ncomp;
334 MLCellABecLapT<MF>::define(a_geom, a_grids, a_dmap, a_overset_mask, a_info, a_factory);
335 define_ab_coeffs();
336}
337
338template <typename MF>
339void
341{
342 m_a_coeffs.resize(this->m_num_amr_levels);
343 m_b_coeffs.resize(this->m_num_amr_levels);
344 for (int amrlev = 0; amrlev < this->m_num_amr_levels; ++amrlev)
345 {
346 m_a_coeffs[amrlev].resize(this->m_num_mg_levels[amrlev]);
347 m_b_coeffs[amrlev].resize(this->m_num_mg_levels[amrlev]);
348 for (int mglev = 0; mglev < this->m_num_mg_levels[amrlev]; ++mglev)
349 {
350 m_a_coeffs[amrlev][mglev].define
351 (this->m_grids[amrlev][mglev], this->m_dmap[amrlev][mglev],
352 1, 0, MFInfo(), *(this->m_factory[amrlev][mglev]));
353 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim)
354 {
355 const BoxArray& ba = amrex::convert(this->m_grids[amrlev][mglev],
357 m_b_coeffs[amrlev][mglev][idim].define
358 (ba, this->m_dmap[amrlev][mglev], m_ncomp, 0, MFInfo(),
359 *(this->m_factory[amrlev][mglev]));
360 }
361 }
362 }
363}
364
365template <typename MF>
366template <typename T1, typename T2>
367requires (std::is_convertible_v<T1, typename MF::value_type> && std::is_convertible_v<T2, typename MF::value_type>)
368void
370{
371 m_a_scalar = RT(a);
372 m_b_scalar = RT(b);
373 if (m_a_scalar == RT(0.0)) {
374 for (int amrlev = 0; amrlev < this->m_num_amr_levels; ++amrlev) {
375 m_a_coeffs[amrlev][0].setVal(RT(0.0));
376 }
377 m_acoef_set = true;
378 }
379 m_scalars_set = true;
380}
381
382template <typename MF>
383template <FabArrayType AMF>
384requires (std::is_convertible_v<typename AMF::value_type, typename MF::value_type>)
385void
386MLABecLaplacianT<MF>::setACoeffs (int amrlev, const AMF& alpha)
387{
388 AMREX_ASSERT_WITH_MESSAGE(alpha.nComp() == 1,
389 "MLABecLaplacian::setACoeffs: alpha is supposed to be single component.");
390 m_a_coeffs[amrlev][0].LocalCopy(alpha, 0, 0, 1, IntVect(0));
391 m_needs_update = true;
392 m_acoef_set = true;
393}
394
395template <typename MF>
396template <typename T>
397requires (std::is_convertible_v<T, typename MF::value_type>)
398void
400{
401 m_a_coeffs[amrlev][0].setVal(RT(alpha));
402 m_needs_update = true;
403 m_acoef_set = true;
404}
405
406
407template <typename MF>
408template <FabArrayType AMF>
409requires (std::is_convertible_v<typename AMF::value_type, typename MF::value_type>)
410void
413{
414 const int ncomp = this->getNComp();
415 AMREX_ASSERT(beta[0]->nComp() == 1 || beta[0]->nComp() == ncomp);
416 if (beta[0]->nComp() == ncomp) {
417 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
418 for (int icomp = 0; icomp < ncomp; ++icomp) {
419 m_b_coeffs[amrlev][0][idim].LocalCopy(*beta[idim], icomp, icomp, 1, IntVect(0));
420 }
421 }
422 } else {
423 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
424 for (int icomp = 0; icomp < ncomp; ++icomp) {
425 m_b_coeffs[amrlev][0][idim].LocalCopy(*beta[idim], 0, icomp, 1, IntVect(0));
426 }
427 }
428 }
429 m_needs_update = true;
430}
431
432template <typename MF>
433template <typename T>
434requires (std::is_convertible_v<T, typename MF::value_type>)
435void
437{
438 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
439 m_b_coeffs[amrlev][0][idim].setVal(RT(beta));
440 }
441 m_needs_update = true;
442}
443
444template <typename MF>
445template <typename T>
446requires (std::is_convertible_v<T, typename MF::value_type>)
447void
449{
450 const int ncomp = this->getNComp();
451 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
452 for (int icomp = 0; icomp < ncomp; ++icomp) {
453 m_b_coeffs[amrlev][0][idim].setVal(RT(beta[icomp]), icomp, 1, 0);
454 }
455 }
456 m_needs_update = true;
457}
458
459template <typename MF>
460void
462{
465 }
466
467#if (AMREX_SPACEDIM != 3)
468 applyMetricTermsCoeffs();
469#endif
470
471 applyRobinBCTermsCoeffs();
472
473 averageDownCoeffs();
474
475 update_singular_flags();
476
477 m_needs_update = false;
478}
479
480template <typename MF>
481void
483{
484 BL_PROFILE("MLABecLaplacian::prepareForSolve()");
485
487
488#if (AMREX_SPACEDIM != 3)
489 applyMetricTermsCoeffs();
490#endif
491
492 applyRobinBCTermsCoeffs();
493
494 averageDownCoeffs();
495
496 update_singular_flags();
497
498 m_needs_update = false;
499}
500
501template <typename MF>
502void
504{
505#if (AMREX_SPACEDIM != 3)
506 for (int alev = 0; alev < this->m_num_amr_levels; ++alev)
507 {
508 const int mglev = 0;
509 this->applyMetricTerm(alev, mglev, m_a_coeffs[alev][mglev]);
510 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim)
511 {
512 this->applyMetricTerm(alev, mglev, m_b_coeffs[alev][mglev][idim]);
513 }
514 }
515#endif
516}
517
518//
519// Suppose we are solving `alpha u - del (beta grad u) = rhs` (Scalar
520// coefficients can be easily added back in the end) and there is Robin BC
521// `a u + b du/dn = f` at the upper end of the x-direction. The 1D
522// discretization at the last cell i is
523//
524// alpha u_i + (beta_{i-1/2} (du/dx)_{i-1/2} - beta_{i+1/2} (du/dx)_{i+1/2}) / h = rhs_i
525//
526// where h is the cell size. At `i+1/2` (i.e., the boundary), we have
527//
528// a (u_i + u_{i+1})/2 + b (u_{i+1}-u_i)/h = f,
529//
530// according to the Robin BC. This gives
531//
532// u_{i+1} = A + B u_i,
533//
534// where `A = f/(b/h + a/2)` and `B = (b/h - a/2) / (b/h + a/2). We then
535// use `u_i` and `u_{i+1}` to compute `(du/dx)_{i+1/2}`. The discretization
536// at cell i then becomes
537//
538// \tilde{alpha}_i u_i + (beta_{i-1/2} (du/dx)_{i-1/2} - 0) / h = \tilde{rhs}_i
539//
540// This is equivalent to having homogeneous Neumann BC with modified alpha and rhs.
541//
542// \tilde{alpha}_i = alpha_i + (1-B) beta_{i+1/2} / h^2
543// \tilde{rhs}_i = rhs_i + A beta_{i+1/2} / h^2
544//
546namespace detail {
547template <typename LP>
548void applyRobinBCTermsCoeffs (LP& linop)
549{
550 using RT = typename LP::RT;
551
552 const int ncomp = linop.getNComp();
553 bool reset_alpha = false;
554 if (linop.m_a_scalar == RT(0.0)) {
555 linop.m_a_scalar = RT(1.0);
556 reset_alpha = true;
557 }
558 const RT bovera = linop.m_b_scalar/linop.m_a_scalar;
559
560 if (!reset_alpha) {
561 AMREX_ALWAYS_ASSERT_WITH_MESSAGE(linop.m_scalars_set && linop.m_acoef_set,
562 "To reuse solver With Robin BC, one must re-call setScalars (and setACoeffs if the scalar is not zero)");
563 }
564
565 linop.m_scalars_set = false;
566 linop.m_acoef_set = false;
567
568 for (int amrlev = 0; amrlev < linop.NAMRLevels(); ++amrlev) {
569 const int mglev = 0;
570 const Box& domain = linop.Geom(amrlev,mglev).Domain();
571 const RT dxi = static_cast<RT>(linop.Geom(amrlev,mglev).InvCellSize(0));
572 const RT dyi = static_cast<RT>((AMREX_SPACEDIM >= 2) ? linop.Geom(amrlev,mglev).InvCellSize(1) : Real(1.0));
573 const RT dzi = static_cast<RT>((AMREX_SPACEDIM == 3) ? linop.Geom(amrlev,mglev).InvCellSize(2) : Real(1.0));
574
575 if (reset_alpha) {
576 linop.m_a_coeffs[amrlev][mglev].setVal(RT(0.0));
577 }
578
579 MFItInfo mfi_info;
580 if (Gpu::notInLaunchRegion()) { mfi_info.SetDynamic(true); }
581
582#ifdef AMREX_USE_OMP
583#pragma omp parallel if (Gpu::notInLaunchRegion())
584#endif
585 for (MFIter mfi(linop.m_a_coeffs[amrlev][mglev], mfi_info); mfi.isValid(); ++mfi)
586 {
587 const Box& vbx = mfi.validbox();
588 auto const& afab = linop.m_a_coeffs[amrlev][mglev].array(mfi);
589 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
590 auto const& bfab = linop.m_b_coeffs[amrlev][mglev][idim].const_array(mfi);
591 const Box& blo = amrex::adjCellLo(vbx,idim);
592 const Box& bhi = amrex::adjCellHi(vbx,idim);
593 bool outside_domain_lo = !(domain.contains(blo));
594 bool outside_domain_hi = !(domain.contains(bhi));
595 if ((!outside_domain_lo) && (!outside_domain_hi)) { continue; }
596 for (int icomp = 0; icomp < ncomp; ++icomp) {
597 auto const& rbc = (*(linop.m_robin_bcval[amrlev]))[mfi].const_array(icomp*3);
598 if (linop.m_lobc_orig[icomp][idim] == LinOpBCType::Robin && outside_domain_lo)
599 {
600 if (idim == 0) {
601 RT fac = bovera*dxi*dxi;
602 AMREX_HOST_DEVICE_FOR_3D(blo, i, j, k,
603 {
604 RT B = (rbc(i,j,k,1)*dxi - rbc(i,j,k,0)*RT(0.5))
605 / (rbc(i,j,k,1)*dxi + rbc(i,j,k,0)*RT(0.5));
606 afab(i+1,j,k,icomp) += fac*bfab(i+1,j,k,icomp)*(RT(1.0)-B);
607 });
608 } else if (idim == 1) {
609 RT fac = bovera*dyi*dyi;
610 AMREX_HOST_DEVICE_FOR_3D(blo, i, j, k,
611 {
612 RT B = (rbc(i,j,k,1)*dyi - rbc(i,j,k,0)*RT(0.5))
613 / (rbc(i,j,k,1)*dyi + rbc(i,j,k,0)*RT(0.5));
614 afab(i,j+1,k,icomp) += fac*bfab(i,j+1,k,icomp)*(RT(1.0)-B);
615 });
616 } else {
617 RT fac = bovera*dzi*dzi;
618 AMREX_HOST_DEVICE_FOR_3D(blo, i, j, k,
619 {
620 RT B = (rbc(i,j,k,1)*dzi - rbc(i,j,k,0)*RT(0.5))
621 / (rbc(i,j,k,1)*dzi + rbc(i,j,k,0)*RT(0.5));
622 afab(i,j,k+1,icomp) += fac*bfab(i,j,k+1,icomp)*(RT(1.0)-B);
623 });
624 }
625 }
626 if (linop.m_hibc_orig[icomp][idim] == LinOpBCType::Robin && outside_domain_hi)
627 {
628 if (idim == 0) {
629 RT fac = bovera*dxi*dxi;
630 AMREX_HOST_DEVICE_FOR_3D(bhi, i, j, k,
631 {
632 RT B = (rbc(i,j,k,1)*dxi - rbc(i,j,k,0)*RT(0.5))
633 / (rbc(i,j,k,1)*dxi + rbc(i,j,k,0)*RT(0.5));
634 afab(i-1,j,k,icomp) += fac*bfab(i,j,k,icomp)*(RT(1.0)-B);
635 });
636 } else if (idim == 1) {
637 RT fac = bovera*dyi*dyi;
638 AMREX_HOST_DEVICE_FOR_3D(bhi, i, j, k,
639 {
640 RT B = (rbc(i,j,k,1)*dyi - rbc(i,j,k,0)*RT(0.5))
641 / (rbc(i,j,k,1)*dyi + rbc(i,j,k,0)*RT(0.5));
642 afab(i,j-1,k,icomp) += fac*bfab(i,j,k,icomp)*(RT(1.0)-B);
643 });
644 } else {
645 RT fac = bovera*dzi*dzi;
646 AMREX_HOST_DEVICE_FOR_3D(bhi, i, j, k,
647 {
648 RT B = (rbc(i,j,k,1)*dzi - rbc(i,j,k,0)*RT(0.5))
649 / (rbc(i,j,k,1)*dzi + rbc(i,j,k,0)*RT(0.5));
650 afab(i,j,k-1,icomp) += fac*bfab(i,j,k,icomp)*(RT(1.0)-B);
651 });
652 }
653 }
654 }
655 }
656 }
657 }
658}
659} // namespace detail
661
662template <typename MF>
663void
665{
666 if (this->hasRobinBC()) {
667 detail::applyRobinBCTermsCoeffs(*this);
668 }
669}
670
671template <typename MF>
672void
674{
675 BL_PROFILE("MLABecLaplacian::averageDownCoeffs()");
676
677 for (int amrlev = this->m_num_amr_levels-1; amrlev > 0; --amrlev)
678 {
679 auto& fine_a_coeffs = m_a_coeffs[amrlev];
680 auto& fine_b_coeffs = m_b_coeffs[amrlev];
681
682 averageDownCoeffsSameAmrLevel(amrlev, fine_a_coeffs, fine_b_coeffs);
683 averageDownCoeffsToCoarseAmrLevel(amrlev);
684 }
685
686 averageDownCoeffsSameAmrLevel(0, m_a_coeffs[0], m_b_coeffs[0]);
687}
688
689template <typename MF>
690void
693{
694 int nmglevs = a.size();
695 for (int mglev = 1; mglev < nmglevs; ++mglev)
696 {
697 IntVect ratio = (amrlev > 0) ? IntVect(this->mg_coarsen_ratio) : this->mg_coarsen_ratio_vec[mglev-1];
698
699 if (m_a_scalar == 0.0)
700 {
701 a[mglev].setVal(RT(0.0));
702 }
703 else
704 {
705 amrex::average_down(a[mglev-1], a[mglev], 0, 1, ratio);
706 }
707
708 Vector<const MF*> fine {AMREX_D_DECL(&(b[mglev-1][0]),
709 &(b[mglev-1][1]),
710 &(b[mglev-1][2]))};
711 Vector<MF*> crse {AMREX_D_DECL(&(b[mglev][0]),
712 &(b[mglev][1]),
713 &(b[mglev][2]))};
714
716 }
717
718 for (int mglev = 1; mglev < nmglevs; ++mglev)
719 {
720 if (this->m_overset_mask[amrlev][mglev]) {
721 const RT fac = static_cast<RT>(1 << mglev); // 2**mglev
722 const RT osfac = RT(2.0)*fac/(fac+RT(1.0));
723 const int ncomp = this->getNComp();
724#ifdef AMREX_USE_OMP
725#pragma omp parallel if (Gpu::notInLaunchRegion())
726#endif
727 for (MFIter mfi(a[mglev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
728 {
729 AMREX_D_TERM(Box const& xbx = mfi.nodaltilebox(0);,
730 Box const& ybx = mfi.nodaltilebox(1);,
731 Box const& zbx = mfi.nodaltilebox(2));
732 AMREX_D_TERM(auto const& bx = b[mglev][0].array(mfi);,
733 auto const& by = b[mglev][1].array(mfi);,
734 auto const& bz = b[mglev][2].array(mfi));
735 auto const& osm = this->m_overset_mask[amrlev][mglev]->const_array(mfi);
736#if defined(AMREX_USE_CUDA) && defined(_WIN32)
738 (xbx, t_xbx,
739 {
740 overset_rescale_bcoef_x(t_xbx, bx, osm, ncomp, osfac);
741 });
742#if (AMREX_SPACEDIM >= 2)
744 (ybx, t_ybx,
745 {
746 overset_rescale_bcoef_y(t_ybx, by, osm, ncomp, osfac);
747 });
748#endif
749#if (AMREX_SPACEDIM == 3)
751 (zbx, t_zbx,
752 {
753 overset_rescale_bcoef_z(t_zbx, bz, osm, ncomp, osfac);
754 });
755#endif
756#else
758 (xbx, t_xbx,
759 {
760 overset_rescale_bcoef_x(t_xbx, bx, osm, ncomp, osfac);
761 },
762 ybx, t_ybx,
763 {
764 overset_rescale_bcoef_y(t_ybx, by, osm, ncomp, osfac);
765 },
766 zbx, t_zbx,
767 {
768 overset_rescale_bcoef_z(t_zbx, bz, osm, ncomp, osfac);
769 });
770#endif
771 }
772 }
773 }
774}
775
776template <typename MF>
777void
779{
780 auto& fine_a_coeffs = m_a_coeffs[flev ].back();
781 auto& fine_b_coeffs = m_b_coeffs[flev ].back();
782 auto& crse_a_coeffs = m_a_coeffs[flev-1].front();
783 auto& crse_b_coeffs = m_b_coeffs[flev-1].front();
784
785 if (m_a_scalar != 0.0) {
786 // We coarsen from the back of flev to the front of flev-1.
787 // So we use mg_coarsen_ratio.
788 amrex::average_down(fine_a_coeffs, crse_a_coeffs, 0, 1, this->mg_coarsen_ratio);
789 }
790
792 amrex::GetArrOfPtrs(crse_b_coeffs),
793 IntVect(this->mg_coarsen_ratio),
794 this->m_geom[flev-1][0]);
795}
796
797template <typename MF>
798void
800{
801 m_is_singular.clear();
802 m_is_singular.resize(this->m_num_amr_levels, false);
803 auto itlo = std::ranges::find(this->m_lobc[0], BCType::Dirichlet);
804 auto ithi = std::ranges::find(this->m_hibc[0], BCType::Dirichlet);
805 if (itlo == this->m_lobc[0].end() && ithi == this->m_hibc[0].end())
806 { // No Dirichlet
807 for (int alev = 0; alev < this->m_num_amr_levels; ++alev)
808 {
809 // For now this assumes that overset regions are treated as Dirichlet bc's
810 if (this->m_domain_covered[alev] && !this->m_overset_mask[alev][0])
811 {
812 if (m_a_scalar == Real(0.0))
813 {
814 m_is_singular[alev] = true;
815 }
816 else
817 {
818 RT asum = m_a_coeffs[alev].back().sum(0,IntVect(0));
819 RT amax = m_a_coeffs[alev].back().norminf(0,1,IntVect(0));
820 m_is_singular[alev] = (std::abs(asum) <= amax * RT(1.e-12));
821 }
822 }
823 }
824 }
825
826 if (!m_is_singular[0] && this->m_needs_coarse_data_for_bc &&
827 this->m_coarse_fine_bc_type == LinOpBCType::Neumann)
828 {
829 AMREX_ASSERT(this->m_overset_mask[0][0] == nullptr);
830
831 bool lev0_a_is_zero = false;
832 if (m_a_scalar == Real(0.0)) {
833 lev0_a_is_zero = true;
834 } else {
835 RT asum = m_a_coeffs[0].back().sum(0,IntVect(0));
836 RT amax = m_a_coeffs[0].back().norminf(0,1,IntVect(0));
837 bool a_is_almost_zero = std::abs(asum) <= amax * RT(1.e-12);
838 if (a_is_almost_zero) { lev0_a_is_zero = true; }
839 }
840
841 if (lev0_a_is_zero) {
842 auto bbox = this->m_grids[0][0].minimalBox();
843 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
844 if (this->m_lobc[0][idim] == LinOpBCType::Dirichlet) {
845 bbox.growLo(idim,1);
846 }
847 if (this->m_hibc[0][idim] == LinOpBCType::Dirichlet) {
848 bbox.growHi(idim,1);
849 }
850 }
851 if (this->m_geom[0][0].Domain().contains(bbox)) {
852 m_is_singular[0] = true;
853 }
854 }
855 }
856}
857
858template <typename MF>
859void
860MLABecLaplacianT<MF>::Fapply (int amrlev, int mglev, MF& out, const MF& in) const
861{
862 BL_PROFILE("MLABecLaplacian::Fapply()");
863
864 const MF& acoef = m_a_coeffs[amrlev][mglev];
865 AMREX_D_TERM(const MF& bxcoef = m_b_coeffs[amrlev][mglev][0];,
866 const MF& bycoef = m_b_coeffs[amrlev][mglev][1];,
867 const MF& bzcoef = m_b_coeffs[amrlev][mglev][2];);
868
870 {AMREX_D_DECL(static_cast<RT>(this->m_geom[amrlev][mglev].InvCellSize(0)),
871 static_cast<RT>(this->m_geom[amrlev][mglev].InvCellSize(1)),
872 static_cast<RT>(this->m_geom[amrlev][mglev].InvCellSize(2)))};
873
874 const RT ascalar = m_a_scalar;
875 const RT bscalar = m_b_scalar;
876
877 const int ncomp = this->getNComp();
878
879#ifdef AMREX_USE_GPU
880 if (Gpu::inLaunchRegion()) {
881 const auto& xma = in.const_arrays();
882 const auto& yma = out.arrays();
883 const auto& ama = acoef.arrays();
884 AMREX_D_TERM(const auto& bxma = bxcoef.const_arrays();,
885 const auto& byma = bycoef.const_arrays();,
886 const auto& bzma = bzcoef.const_arrays(););
887 if (this->m_overset_mask[amrlev][mglev]) {
888 const auto& osmma = this->m_overset_mask[amrlev][mglev]->const_arrays();
889 ParallelFor(out, IntVect(0), ncomp,
890 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
891 {
892 mlabeclap_adotx_os(i,j,k,n, yma[box_no], xma[box_no], ama[box_no],
893 AMREX_D_DECL(bxma[box_no],byma[box_no],bzma[box_no]),
894 osmma[box_no], dxinv, ascalar, bscalar);
895 });
896 } else {
897 ParallelFor(out, IntVect(0), ncomp,
898 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
899 {
900 mlabeclap_adotx(i,j,k,n, yma[box_no], xma[box_no], ama[box_no],
901 AMREX_D_DECL(bxma[box_no],byma[box_no],bzma[box_no]),
902 dxinv, ascalar, bscalar);
903 });
904 }
905 if (!Gpu::inNoSyncRegion()) {
907 }
908 } else
909#endif
910 {
911#ifdef AMREX_USE_OMP
912#pragma omp parallel if (Gpu::notInLaunchRegion())
913#endif
914 for (MFIter mfi(out, TilingIfNotGPU()); mfi.isValid(); ++mfi)
915 {
916 const Box& bx = mfi.tilebox();
917 const auto& xfab = in.array(mfi);
918 const auto& yfab = out.array(mfi);
919 const auto& afab = acoef.array(mfi);
920 AMREX_D_TERM(const auto& bxfab = bxcoef.array(mfi);,
921 const auto& byfab = bycoef.array(mfi);,
922 const auto& bzfab = bzcoef.array(mfi););
923 if (this->m_overset_mask[amrlev][mglev]) {
924 const auto& osm = this->m_overset_mask[amrlev][mglev]->const_array(mfi);
925 AMREX_HOST_DEVICE_PARALLEL_FOR_4D(bx, ncomp, i, j, k, n,
926 {
927 mlabeclap_adotx_os(i,j,k,n, yfab, xfab, afab, AMREX_D_DECL(bxfab,byfab,bzfab),
928 osm, dxinv, ascalar, bscalar);
929 });
930 } else {
931 AMREX_HOST_DEVICE_PARALLEL_FOR_4D(bx, ncomp, i, j, k, n,
932 {
933 mlabeclap_adotx(i,j,k,n, yfab, xfab, afab, AMREX_D_DECL(bxfab,byfab,bzfab),
934 dxinv, ascalar, bscalar);
935 });
936 }
937 }
938 }
939}
940
941template <typename MF>
942void
943MLABecLaplacianT<MF>::Fsmooth (int amrlev, int mglev, MF& sol, const MF& rhs, int redblack) const
944{
945 BL_PROFILE("MLABecLaplacian::Fsmooth()");
946
947 bool regular_coarsening = true;
948 if (amrlev == 0 && mglev > 0) {
949 regular_coarsening = this->mg_coarsen_ratio_vec[mglev-1] == this->mg_coarsen_ratio;
950 }
951
952 MF Ax;
953 if (! this->m_use_gauss_seidel && regular_coarsening) { // jacobi
954 Ax.define(sol.boxArray(), sol.DistributionMap(), sol.nComp(), 0);
955 Fapply(amrlev, mglev, Ax, sol);
956 }
957
958 const MF& acoef = m_a_coeffs[amrlev][mglev];
959 AMREX_ALWAYS_ASSERT(acoef.nGrowVect() == 0);
960 AMREX_D_TERM(const MF& bxcoef = m_b_coeffs[amrlev][mglev][0];,
961 const MF& bycoef = m_b_coeffs[amrlev][mglev][1];,
962 const MF& bzcoef = m_b_coeffs[amrlev][mglev][2];);
963 const auto& undrrelxr = this->m_undrrelxr[amrlev][mglev];
964 const auto& maskvals = this->m_maskvals [amrlev][mglev];
965
966 OrientationIter oitr;
967
968 const auto& f0 = undrrelxr[oitr()]; ++oitr;
969 const auto& f1 = undrrelxr[oitr()]; ++oitr;
970#if (AMREX_SPACEDIM > 1)
971 const auto& f2 = undrrelxr[oitr()]; ++oitr;
972 const auto& f3 = undrrelxr[oitr()]; ++oitr;
973#if (AMREX_SPACEDIM > 2)
974 const auto& f4 = undrrelxr[oitr()]; ++oitr;
975 const auto& f5 = undrrelxr[oitr()]; ++oitr;
976#endif
977#endif
978
979 const MultiMask& mm0 = maskvals[0];
980 const MultiMask& mm1 = maskvals[1];
981#if (AMREX_SPACEDIM > 1)
982 const MultiMask& mm2 = maskvals[2];
983 const MultiMask& mm3 = maskvals[3];
984#if (AMREX_SPACEDIM > 2)
985 const MultiMask& mm4 = maskvals[4];
986 const MultiMask& mm5 = maskvals[5];
987#endif
988#endif
989
990 const int nc = this->getNComp();
991 const Real* h = this->m_geom[amrlev][mglev].CellSize();
992 AMREX_D_TERM(const RT dhx = m_b_scalar/static_cast<RT>(h[0]*h[0]);,
993 const RT dhy = m_b_scalar/static_cast<RT>(h[1]*h[1]);,
994 const RT dhz = m_b_scalar/static_cast<RT>(h[2]*h[2]));
995 const RT alpha = m_a_scalar;
996
997#ifdef AMREX_USE_GPU
999 && (this->m_overset_mask[amrlev][mglev] || regular_coarsening))
1000 {
1001 const auto& m0ma = mm0.const_arrays();
1002 const auto& m1ma = mm1.const_arrays();
1003#if (AMREX_SPACEDIM > 1)
1004 const auto& m2ma = mm2.const_arrays();
1005 const auto& m3ma = mm3.const_arrays();
1006#if (AMREX_SPACEDIM > 2)
1007 const auto& m4ma = mm4.const_arrays();
1008 const auto& m5ma = mm5.const_arrays();
1009#endif
1010#endif
1011
1012 const auto& solnma = sol.arrays();
1013 const auto& rhsma = rhs.const_arrays();
1014 const auto& ama = acoef.const_arrays();
1015
1016 AMREX_D_TERM(const auto& bxma = bxcoef.const_arrays();,
1017 const auto& byma = bycoef.const_arrays();,
1018 const auto& bzma = bzcoef.const_arrays(););
1019
1020 const auto& f0ma = f0.const_arrays();
1021 const auto& f1ma = f1.const_arrays();
1022#if (AMREX_SPACEDIM > 1)
1023 const auto& f2ma = f2.const_arrays();
1024 const auto& f3ma = f3.const_arrays();
1025#if (AMREX_SPACEDIM > 2)
1026 const auto& f4ma = f4.const_arrays();
1027 const auto& f5ma = f5.const_arrays();
1028#endif
1029#endif
1030
1031 if (this->m_overset_mask[amrlev][mglev]) {
1032 const auto& osmma = this->m_overset_mask[amrlev][mglev]->const_arrays();
1033 if (this->m_use_gauss_seidel) {
1034 ParallelFor(sol, IntVect(0), nc,
1035 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
1036 {
1037 Box vbx(ama[box_no]);
1038 abec_gsrb_os(i,j,k,n, solnma[box_no], rhsma[box_no], alpha, ama[box_no],
1039 AMREX_D_DECL(dhx, dhy, dhz),
1040 AMREX_D_DECL(bxma[box_no],byma[box_no],bzma[box_no]),
1041 AMREX_D_DECL(m0ma[box_no],m2ma[box_no],m4ma[box_no]),
1042 AMREX_D_DECL(m1ma[box_no],m3ma[box_no],m5ma[box_no]),
1043 AMREX_D_DECL(f0ma[box_no],f2ma[box_no],f4ma[box_no]),
1044 AMREX_D_DECL(f1ma[box_no],f3ma[box_no],f5ma[box_no]),
1045 osmma[box_no], vbx, redblack);
1046 });
1047 } else {
1048 const auto& axma = Ax.const_arrays();
1049 ParallelFor(sol, IntVect(0), nc,
1050 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
1051 {
1052 Box vbx(ama[box_no]);
1053 abec_jacobi_os(i,j,k,n, solnma[box_no], rhsma[box_no], axma[box_no],
1054 alpha, ama[box_no],
1055 AMREX_D_DECL(dhx, dhy, dhz),
1056 AMREX_D_DECL(bxma[box_no],byma[box_no],bzma[box_no]),
1057 AMREX_D_DECL(m0ma[box_no],m2ma[box_no],m4ma[box_no]),
1058 AMREX_D_DECL(m1ma[box_no],m3ma[box_no],m5ma[box_no]),
1059 AMREX_D_DECL(f0ma[box_no],f2ma[box_no],f4ma[box_no]),
1060 AMREX_D_DECL(f1ma[box_no],f3ma[box_no],f5ma[box_no]),
1061 osmma[box_no], vbx);
1062 });
1063 }
1064 } else if (regular_coarsening) {
1065 if (this->m_use_gauss_seidel) {
1066 ParallelFor(sol, IntVect(0), nc,
1067 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
1068 {
1069 Box vbx(ama[box_no]);
1070 abec_gsrb(i,j,k,n, solnma[box_no], rhsma[box_no], alpha, ama[box_no],
1071 AMREX_D_DECL(dhx, dhy, dhz),
1072 AMREX_D_DECL(bxma[box_no],byma[box_no],bzma[box_no]),
1073 AMREX_D_DECL(m0ma[box_no],m2ma[box_no],m4ma[box_no]),
1074 AMREX_D_DECL(m1ma[box_no],m3ma[box_no],m5ma[box_no]),
1075 AMREX_D_DECL(f0ma[box_no],f2ma[box_no],f4ma[box_no]),
1076 AMREX_D_DECL(f1ma[box_no],f3ma[box_no],f5ma[box_no]),
1077 vbx, redblack);
1078 });
1079 } else {
1080 const auto& axma = Ax.const_arrays();
1081 ParallelFor(sol, IntVect(0), nc,
1082 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
1083 {
1084 Box vbx(ama[box_no]);
1085 abec_jacobi(i,j,k,n, solnma[box_no], rhsma[box_no], axma[box_no],
1086 alpha, ama[box_no],
1087 AMREX_D_DECL(dhx, dhy, dhz),
1088 AMREX_D_DECL(bxma[box_no],byma[box_no],bzma[box_no]),
1089 AMREX_D_DECL(m0ma[box_no],m2ma[box_no],m4ma[box_no]),
1090 AMREX_D_DECL(m1ma[box_no],m3ma[box_no],m5ma[box_no]),
1091 AMREX_D_DECL(f0ma[box_no],f2ma[box_no],f4ma[box_no]),
1092 AMREX_D_DECL(f1ma[box_no],f3ma[box_no],f5ma[box_no]),
1093 vbx);
1094 });
1095 }
1096 }
1097 if (Ax.local_size() > 0 || !Gpu::inNoSyncRegion()) {
1099 }
1100 } else
1101#endif
1102 {
1103 MFItInfo mfi_info;
1104 mfi_info.EnableTiling().SetDynamic(true);
1105
1106#ifdef AMREX_USE_OMP
1107#pragma omp parallel if (Gpu::notInLaunchRegion())
1108#endif
1109 for (MFIter mfi(sol,mfi_info); mfi.isValid(); ++mfi)
1110 {
1111 const auto& m0 = mm0.array(mfi);
1112 const auto& m1 = mm1.array(mfi);
1113#if (AMREX_SPACEDIM > 1)
1114 const auto& m2 = mm2.array(mfi);
1115 const auto& m3 = mm3.array(mfi);
1116#if (AMREX_SPACEDIM > 2)
1117 const auto& m4 = mm4.array(mfi);
1118 const auto& m5 = mm5.array(mfi);
1119#endif
1120#endif
1121
1122 const Box& tbx = mfi.tilebox();
1123 const Box& vbx = mfi.validbox();
1124 const auto& solnfab = sol.array(mfi);
1125 const auto& rhsfab = rhs.const_array(mfi);
1126 const auto& afab = acoef.const_array(mfi);
1127
1128 AMREX_D_TERM(const auto& bxfab = bxcoef.const_array(mfi);,
1129 const auto& byfab = bycoef.const_array(mfi);,
1130 const auto& bzfab = bzcoef.const_array(mfi););
1131
1132 const auto& f0fab = f0.const_array(mfi);
1133 const auto& f1fab = f1.const_array(mfi);
1134#if (AMREX_SPACEDIM > 1)
1135 const auto& f2fab = f2.const_array(mfi);
1136 const auto& f3fab = f3.const_array(mfi);
1137#if (AMREX_SPACEDIM > 2)
1138 const auto& f4fab = f4.const_array(mfi);
1139 const auto& f5fab = f5.const_array(mfi);
1140#endif
1141#endif
1142
1143 if (this->m_overset_mask[amrlev][mglev]) {
1144 const auto& osm = this->m_overset_mask[amrlev][mglev]->const_array(mfi);
1145 if (this->m_use_gauss_seidel) {
1146 AMREX_LOOP_4D(tbx, nc, i, j, k, n,
1147 {
1148 abec_gsrb_os(i,j,k,n, solnfab, rhsfab, alpha, afab,
1149 AMREX_D_DECL(dhx, dhy, dhz),
1150 AMREX_D_DECL(bxfab, byfab, bzfab),
1151 AMREX_D_DECL(m0,m2,m4),
1152 AMREX_D_DECL(m1,m3,m5),
1153 AMREX_D_DECL(f0fab,f2fab,f4fab),
1154 AMREX_D_DECL(f1fab,f3fab,f5fab),
1155 osm, vbx, redblack);
1156 });
1157 } else {
1158 const auto& axfab = Ax.const_array(mfi);
1159 AMREX_LOOP_4D(tbx, nc, i, j, k, n,
1160 {
1161 abec_jacobi_os(i,j,k,n, solnfab, rhsfab, axfab,
1162 alpha, afab,
1163 AMREX_D_DECL(dhx, dhy, dhz),
1164 AMREX_D_DECL(bxfab, byfab, bzfab),
1165 AMREX_D_DECL(m0,m2,m4),
1166 AMREX_D_DECL(m1,m3,m5),
1167 AMREX_D_DECL(f0fab,f2fab,f4fab),
1168 AMREX_D_DECL(f1fab,f3fab,f5fab),
1169 osm, vbx);
1170 });
1171 }
1172 } else if (regular_coarsening) {
1173 if (this->m_use_gauss_seidel) {
1174 AMREX_LOOP_4D(tbx, nc, i, j, k, n,
1175 {
1176 abec_gsrb(i,j,k,n, solnfab, rhsfab, alpha, afab,
1177 AMREX_D_DECL(dhx, dhy, dhz),
1178 AMREX_D_DECL(bxfab, byfab, bzfab),
1179 AMREX_D_DECL(m0,m2,m4),
1180 AMREX_D_DECL(m1,m3,m5),
1181 AMREX_D_DECL(f0fab,f2fab,f4fab),
1182 AMREX_D_DECL(f1fab,f3fab,f5fab),
1183 vbx, redblack);
1184 });
1185 } else {
1186 const auto& axfab = Ax.const_array(mfi);
1187 AMREX_LOOP_4D(tbx, nc, i, j, k, n,
1188 {
1189 abec_jacobi(i,j,k,n, solnfab, rhsfab, axfab,
1190 alpha, afab,
1191 AMREX_D_DECL(dhx, dhy, dhz),
1192 AMREX_D_DECL(bxfab, byfab, bzfab),
1193 AMREX_D_DECL(m0,m2,m4),
1194 AMREX_D_DECL(m1,m3,m5),
1195 AMREX_D_DECL(f0fab,f2fab,f4fab),
1196 AMREX_D_DECL(f1fab,f3fab,f5fab),
1197 vbx);
1198 });
1199 }
1200 } else {
1201 // line solve does not with with GPU
1202 abec_gsrb_with_line_solve(tbx, solnfab, rhsfab, alpha, afab,
1203 AMREX_D_DECL(dhx, dhy, dhz),
1204 AMREX_D_DECL(bxfab, byfab, bzfab),
1205 AMREX_D_DECL(m0,m2,m4),
1206 AMREX_D_DECL(m1,m3,m5),
1207 AMREX_D_DECL(f0fab,f2fab,f4fab),
1208 AMREX_D_DECL(f1fab,f3fab,f5fab),
1209 vbx, redblack, nc);
1210 }
1211 }
1212 }
1213}
1214
1215template <typename MF>
1216void
1217MLABecLaplacianT<MF>::FFlux (int amrlev, const MFIter& mfi,
1218 const Array<FAB*,AMREX_SPACEDIM>& flux,
1219 const FAB& sol, Location, int face_only) const
1220{
1221 BL_PROFILE("MLABecLaplacian::FFlux()");
1222
1223 const int mglev = 0;
1224 const Box& box = mfi.tilebox();
1225 const Real* dxinv = this->m_geom[amrlev][mglev].InvCellSize();
1226 const int ncomp = this->getNComp();
1227 FFlux(box, dxinv, m_b_scalar,
1228 Array<FAB const*,AMREX_SPACEDIM>{{AMREX_D_DECL(&(m_b_coeffs[amrlev][mglev][0][mfi]),
1229 &(m_b_coeffs[amrlev][mglev][1][mfi]),
1230 &(m_b_coeffs[amrlev][mglev][2][mfi]))}},
1231 flux, sol, face_only, ncomp);
1232}
1233
1234template <typename MF>
1235void
1236MLABecLaplacianT<MF>::FFlux (Box const& box, Real const* dxinv, RT bscalar,
1238 Array<FAB*,AMREX_SPACEDIM> const& flux,
1239 FAB const& sol, int face_only, int ncomp)
1240{
1241 AMREX_D_TERM(const auto bx = bcoef[0]->const_array();,
1242 const auto by = bcoef[1]->const_array();,
1243 const auto bz = bcoef[2]->const_array(););
1244 AMREX_D_TERM(const auto& fxarr = flux[0]->array();,
1245 const auto& fyarr = flux[1]->array();,
1246 const auto& fzarr = flux[2]->array(););
1247 const auto& solarr = sol.array();
1248
1249 if (face_only)
1250 {
1251 RT fac = bscalar*static_cast<RT>(dxinv[0]);
1252 Box blo = amrex::bdryLo(box, 0);
1253 int blen = box.length(0);
1255 {
1256 mlabeclap_flux_xface(tbox, fxarr, solarr, bx, fac, blen, ncomp);
1257 });
1258#if (AMREX_SPACEDIM >= 2)
1259 fac = bscalar*static_cast<RT>(dxinv[1]);
1260 blo = amrex::bdryLo(box, 1);
1261 blen = box.length(1);
1263 {
1264 mlabeclap_flux_yface(tbox, fyarr, solarr, by, fac, blen, ncomp);
1265 });
1266#endif
1267#if (AMREX_SPACEDIM == 3)
1268 fac = bscalar*static_cast<RT>(dxinv[2]);
1269 blo = amrex::bdryLo(box, 2);
1270 blen = box.length(2);
1272 {
1273 mlabeclap_flux_zface(tbox, fzarr, solarr, bz, fac, blen, ncomp);
1274 });
1275#endif
1276 }
1277 else
1278 {
1279 RT fac = bscalar*static_cast<RT>(dxinv[0]);
1280 Box bflux = amrex::surroundingNodes(box, 0);
1282 {
1283 mlabeclap_flux_x(tbox, fxarr, solarr, bx, fac, ncomp);
1284 });
1285#if (AMREX_SPACEDIM >= 2)
1286 fac = bscalar*static_cast<RT>(dxinv[1]);
1287 bflux = amrex::surroundingNodes(box, 1);
1289 {
1290 mlabeclap_flux_y(tbox, fyarr, solarr, by, fac, ncomp);
1291 });
1292#endif
1293#if (AMREX_SPACEDIM == 3)
1294 fac = bscalar*static_cast<RT>(dxinv[2]);
1295 bflux = amrex::surroundingNodes(box, 2);
1297 {
1298 mlabeclap_flux_z(tbox, fzarr, solarr, bz, fac, ncomp);
1299 });
1300#endif
1301 }
1302}
1303
1304template <typename MF>
1305void
1306MLABecLaplacianT<MF>::normalize (int amrlev, int mglev, MF& mf) const
1307{
1308 BL_PROFILE("MLABecLaplacian::normalize()");
1309
1310 const auto& acoef = m_a_coeffs[amrlev][mglev];
1311 AMREX_D_TERM(const auto& bxcoef = m_b_coeffs[amrlev][mglev][0];,
1312 const auto& bycoef = m_b_coeffs[amrlev][mglev][1];,
1313 const auto& bzcoef = m_b_coeffs[amrlev][mglev][2];);
1314
1315 const GpuArray<RT,AMREX_SPACEDIM> dxinv
1316 {AMREX_D_DECL(static_cast<RT>(this->m_geom[amrlev][mglev].InvCellSize(0)),
1317 static_cast<RT>(this->m_geom[amrlev][mglev].InvCellSize(1)),
1318 static_cast<RT>(this->m_geom[amrlev][mglev].InvCellSize(2)))};
1319
1320 const RT ascalar = m_a_scalar;
1321 const RT bscalar = m_b_scalar;
1322
1323 const int ncomp = getNComp();
1324
1325#ifdef AMREX_USE_GPU
1326 if (Gpu::inLaunchRegion()) {
1327 const auto& ma = mf.arrays();
1328 const auto& ama = acoef.const_arrays();
1329 AMREX_D_TERM(const auto& bxma = bxcoef.const_arrays();,
1330 const auto& byma = bycoef.const_arrays();,
1331 const auto& bzma = bzcoef.const_arrays(););
1332 ParallelFor(mf, IntVect(0), ncomp,
1333 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
1334 {
1335 mlabeclap_normalize(i,j,k,n, ma[box_no], ama[box_no],
1336 AMREX_D_DECL(bxma[box_no],byma[box_no],bzma[box_no]),
1337 dxinv, ascalar, bscalar);
1338 });
1339 if (!Gpu::inNoSyncRegion()) {
1341 }
1342 } else
1343#endif
1344 {
1345#ifdef AMREX_USE_OMP
1346#pragma omp parallel if (Gpu::notInLaunchRegion())
1347#endif
1348 for (MFIter mfi(mf, TilingIfNotGPU()); mfi.isValid(); ++mfi)
1349 {
1350 const Box& bx = mfi.tilebox();
1351 const auto& fab = mf.array(mfi);
1352 const auto& afab = acoef.array(mfi);
1353 AMREX_D_TERM(const auto& bxfab = bxcoef.array(mfi);,
1354 const auto& byfab = bycoef.array(mfi);,
1355 const auto& bzfab = bzcoef.array(mfi););
1356
1357 AMREX_HOST_DEVICE_PARALLEL_FOR_4D(bx, ncomp, i, j, k, n,
1358 {
1359 mlabeclap_normalize(i,j,k,n, fab, afab, AMREX_D_DECL(bxfab,byfab,bzfab),
1360 dxinv, ascalar, bscalar);
1361 });
1362 }
1363 }
1364}
1365
1366template <typename MF>
1367bool
1369{
1370 bool support = false;
1371 if (this->m_overset_mask[0][0]) {
1372 if (this->m_geom[0].back().Domain().coarsenable(MLLinOp::mg_coarsen_ratio,
1373 this->mg_domain_min_width)
1374 && this->m_grids[0].back().coarsenable(MLLinOp::mg_coarsen_ratio, MLLinOp::mg_box_min_width))
1375 {
1376 support = true;
1377 }
1378 }
1379 return support;
1380}
1381
1382template <typename MF>
1383std::unique_ptr<MLLinOpT<MF>>
1384MLABecLaplacianT<MF>::makeNLinOp (int /*grid_size*/) const
1385{
1386 if (this->m_overset_mask[0][0] == nullptr) { return nullptr; }
1387
1388 const Geometry& geom = this->m_geom[0].back();
1389 const BoxArray& ba = this->m_grids[0].back();
1390 const DistributionMapping& dm = this->m_dmap[0].back();
1391
1392 std::unique_ptr<MLLinOpT<MF>> r
1393 {new MLABecLaplacianT<MF>({geom}, {ba}, {dm}, this->m_lpinfo_arg)};
1394
1395 auto nop = dynamic_cast<MLABecLaplacianT<MF>*>(r.get());
1396 if (!nop) {
1397 return nullptr;
1398 }
1399
1400 nop->m_parent = this;
1401
1402 nop->setMaxOrder(this->maxorder);
1403 nop->setVerbose(this->verbose);
1404
1405 nop->setDomainBC(this->m_lobc, this->m_hibc);
1406
1407 if (this->needsCoarseDataForBC())
1408 {
1409 const Real* dx0 = this->m_geom[0][0].CellSize();
1410 RealVect fac(this->m_coarse_data_crse_ratio);
1411 fac *= Real(0.5);
1412 RealVect cbloc {AMREX_D_DECL(dx0[0]*fac[0], dx0[1]*fac[1], dx0[2]*fac[2])};
1413 nop->setCoarseFineBCLocation(cbloc);
1414 }
1415
1416 nop->setScalars(m_a_scalar, m_b_scalar);
1417
1418 MF const& alpha_bottom = m_a_coeffs[0].back();
1419 iMultiFab const& osm_bottom = *(this->m_overset_mask[0].back());
1420 const int ncomp = alpha_bottom.nComp();
1421 MF alpha(ba, dm, ncomp, 0);
1422
1423 RT a_max = alpha_bottom.norminf(0, ncomp, IntVect(0), true, true);
1424 const int ncomp_b = m_b_coeffs[0].back()[0].nComp();
1425 AMREX_D_TERM(RT bx_max = m_b_coeffs[0].back()[0].norminf(0,ncomp_b,IntVect(0),true,true);,
1426 RT by_max = m_b_coeffs[0].back()[1].norminf(0,ncomp_b,IntVect(0),true,true);,
1427 RT bz_max = m_b_coeffs[0].back()[2].norminf(0,ncomp_b,IntVect(0),true,true));
1428 const GpuArray<RT,AMREX_SPACEDIM> dxinv
1429 {AMREX_D_DECL(static_cast<RT>(geom.InvCellSize(0)),
1430 static_cast<RT>(geom.InvCellSize(1)),
1431 static_cast<RT>(geom.InvCellSize(2)))};
1432 RT huge_alpha = RT(1.e30) *
1433 amrex::max(a_max*std::abs(m_a_scalar),
1434 AMREX_D_DECL(std::abs(m_b_scalar)*bx_max*dxinv[0]*dxinv[0],
1435 std::abs(m_b_scalar)*by_max*dxinv[1]*dxinv[1],
1436 std::abs(m_b_scalar)*bz_max*dxinv[2]*dxinv[2]));
1438
1439#ifdef AMREX_USE_GPU
1440 if (Gpu::inLaunchRegion() && alpha.isFusingCandidate()) {
1441 auto const& ama = alpha.arrays();
1442 auto const& abotma = alpha_bottom.const_arrays();
1443 auto const& mma = osm_bottom.const_arrays();
1444 ParallelFor(alpha, IntVect(0), ncomp,
1445 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
1446 {
1447 if (mma[box_no](i,j,k)) {
1448 ama[box_no](i,j,k,n) = abotma[box_no](i,j,k,n);
1449 } else {
1450 ama[box_no](i,j,k,n) = huge_alpha;
1451 }
1452 });
1453 if (alpha.local_size() > 0 || !Gpu::inNoSyncRegion()) {
1455 }
1456 } else
1457#endif
1458 {
1459#ifdef AMREX_USE_OMP
1460#pragma omp parallel if (Gpu::notInLaunchRegion())
1461#endif
1462 for (MFIter mfi(alpha,TilingIfNotGPU()); mfi.isValid(); ++mfi) {
1463 Box const& bx = mfi.tilebox();
1464 auto const& a = alpha.array(mfi);
1465 auto const& abot = alpha_bottom.const_array(mfi);
1466 auto const& m = osm_bottom.const_array(mfi);
1467 AMREX_HOST_DEVICE_PARALLEL_FOR_4D(bx, ncomp, i, j, k, n,
1468 {
1469 if (m(i,j,k)) {
1470 a(i,j,k,n) = abot(i,j,k,n);
1471 } else {
1472 a(i,j,k,n) = huge_alpha;
1473 }
1474 });
1475 }
1476 }
1477
1478 nop->setACoeffs(0, alpha);
1479 nop->setBCoeffs(0, GetArrOfConstPtrs(m_b_coeffs[0].back()));
1480
1481 return r;
1482}
1483
1484template <typename MF>
1485void
1486MLABecLaplacianT<MF>::copyNSolveSolution (MF& dst, MF const& src) const
1487{
1488 if (this->m_overset_mask[0].back() == nullptr) { return; }
1489
1490 const int ncomp = dst.nComp();
1491
1492#ifdef AMREX_USE_GPU
1493 if (Gpu::inLaunchRegion() && dst.isFusingCandidate()) {
1494 auto const& dstma = dst.arrays();
1495 auto const& srcma = src.const_arrays();
1496 auto const& mma = this->m_overset_mask[0].back()->const_arrays();
1497 ParallelFor(dst, IntVect(0), ncomp,
1498 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
1499 {
1500 if (mma[box_no](i,j,k)) {
1501 dstma[box_no](i,j,k,n) = srcma[box_no](i,j,k,n);
1502 } else {
1503 dstma[box_no](i,j,k,n) = RT(0.0);
1504 }
1505 });
1506 if (!Gpu::inNoSyncRegion()) {
1508 }
1509 } else
1510#endif
1511 {
1512#ifdef AMREX_USE_OMP
1513#pragma omp parallel if (Gpu::notInLaunchRegion())
1514#endif
1515 for (MFIter mfi(dst,TilingIfNotGPU()); mfi.isValid(); ++mfi) {
1516 Box const& bx = mfi.tilebox();
1517 auto const& dfab = dst.array(mfi);
1518 auto const& sfab = src.const_array(mfi);
1519 auto const& m = this->m_overset_mask[0].back()->const_array(mfi);
1520 AMREX_HOST_DEVICE_PARALLEL_FOR_4D(bx, ncomp, i, j, k, n,
1521 {
1522 if (m(i,j,k)) {
1523 dfab(i,j,k,n) = sfab(i,j,k,n);
1524 } else {
1525 dfab(i,j,k,n) = RT(0.0);
1526 }
1527 });
1528 }
1529 }
1530}
1531
1532extern template class MLABecLaplacianT<MultiFab>;
1533
1536
1537}
1538
1539#endif
#define BL_PROFILE(a)
Definition AMReX_BLProfiler.H:551
#define AMREX_ALWAYS_ASSERT_WITH_MESSAGE(EX, MSG)
Definition AMReX_BLassert.H:49
#define AMREX_ASSERT_WITH_MESSAGE(EX, MSG)
Definition AMReX_BLassert.H:37
#define AMREX_ASSERT(EX)
Definition AMReX_BLassert.H:38
#define AMREX_ALWAYS_ASSERT(EX)
Definition AMReX_BLassert.H:50
#define AMREX_GPU_LAUNCH_HOST_DEVICE_LAMBDA_RANGE(TN, TI, block)
Definition AMReX_GpuLaunchMacrosC.nolint.H:4
#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_LAUNCH_HOST_DEVICE_LAMBDA_DIM(...)
Definition AMReX_GpuLaunch.nolint.H:37
#define AMREX_GPU_DEVICE
Definition AMReX_GpuQualifiers.H:18
Array4< Real > fine
Definition AMReX_InterpFaceRegister.cpp:90
Array4< Real const > crse
Definition AMReX_InterpFaceRegister.cpp:92
#define AMREX_LOOP_4D(bx, ncomp, i, j, k, n, block)
Definition AMReX_Loop.nolint.H:16
#define AMREX_D_TERM(a, b, c)
Definition AMReX_SPACE.H:172
#define AMREX_D_DECL(a, b, c)
Definition AMReX_SPACE.H:171
Reference-counted collection of Boxes.
Definition AMReX_BoxArray.H:676
__host__ __device__ IntVectND< dim > length() const noexcept
Return the length of the BoxND.
Definition AMReX_Box.H:167
const Real * InvCellSize() const noexcept
Returns the inverse cellsize for each coordinate direction.
Definition AMReX_CoordSys.H:91
Calculates the distribution of FABs to MPI processes.
Definition AMReX_DistributionMapping.H:51
int nComp() const noexcept
Return number of variables (aka components) associated with each point.
Definition AMReX_FabArrayBase.H:83
MultiArray4< typename FabArray< FAB >::value_type const > const_arrays() const noexcept
Definition AMReX_FabArray.H:647
Array4< typename FabArray< FAB >::value_type const > const_array(const MFIter &mfi) const noexcept
Definition AMReX_FabArray.H:585
Definition AMReX_FabFactory.H:50
Rectangular problem domain geometry.
Definition AMReX_Geometry.H:75
__host__ static __device__ constexpr IntVectND< dim > TheDimensionVector(int d) noexcept
This static member function returns a reference to a constant IntVectND object, all of whose dim argu...
Definition AMReX_IntVect.H:790
Iterator for looping ever tiles and boxes of amrex::FabArray based containers.
Definition AMReX_MFIter.H:88
Box tilebox() const noexcept
Return the tile Box at the current index.
Definition AMReX_MFIter.cpp:389
bool isValid() const noexcept
Is the iterator valid i.e. is it associated with a FAB?
Definition AMReX_MFIter.H:172
Definition AMReX_MLABecLaplacian.H:22
RT getBScalar() const final
Scalar beta applied to the b-coefficient term.
Definition AMReX_MLABecLaplacian.H:209
int getNComp() const override
Return number of components.
Definition AMReX_MLABecLaplacian.H:167
void FFlux(int amrlev, const MFIter &mfi, const Array< FAB *, 3 > &flux, const FAB &sol, Location, int face_only=0) const override
Compute fluxes on AMR level amrlev for the tilebox described by mfi using sol, writing to flux and ho...
Definition AMReX_MLABecLaplacian.H:1217
void setACoeffs(int amrlev, const AMF &alpha)
Definition AMReX_MLABecLaplacian.H:386
bool isSingular(int amrlev) const override
Query whether AMR level amrlev is singular (null space present).
Definition AMReX_MLABecLaplacian.H:179
void applyRobinBCTermsCoeffs()
Modify coefficients to honor Robin BC terms introduced at level boundaries.
Definition AMReX_MLABecLaplacian.H:664
Vector< Vector< Array< MF, 3 > > > m_b_coeffs
Definition AMReX_MLABecLaplacian.H:260
typename MF::fab_type FAB
Definition AMReX_MLABecLaplacian.H:25
void setBCoeffs(int amrlev, const Array< AMF const *, 3 > &beta)
Definition AMReX_MLABecLaplacian.H:411
MLABecLaplacianT< MF > & operator=(const MLABecLaplacianT< MF > &)=delete
bool supportRobinBC() const noexcept override
Definition AMReX_MLABecLaplacian.H:269
RT m_b_scalar
Definition AMReX_MLABecLaplacian.H:258
typename MF::value_type RT
Definition AMReX_MLABecLaplacian.H:26
~MLABecLaplacianT() override
void prepareForSolve() override
Finalize singular flags and metric/Robin adjustments prior to calling MLMG.
Definition AMReX_MLABecLaplacian.H:482
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={}, int a_ncomp=1)
Define coefficients/layouts for a standard cell-centered solve.
Definition AMReX_MLABecLaplacian.H:309
RT m_a_scalar
Definition AMReX_MLABecLaplacian.H:257
void averageDownCoeffsToCoarseAmrLevel(int flev)
Average coefficients from fine AMR level flev to coarse AMR level flev-1.
Definition AMReX_MLABecLaplacian.H:778
void averageDownCoeffsSameAmrLevel(int amrlev, Vector< MF > &a, Vector< Array< MF, 3 > > &b)
Average coefficients down within AMR level amrlev (fine-to-coarse multigrid) updating a and b.
Definition AMReX_MLABecLaplacian.H:691
bool m_scalars_set
Definition AMReX_MLABecLaplacian.H:262
Vector< int > m_is_singular
Definition AMReX_MLABecLaplacian.H:267
void averageDownCoeffs()
Average a and b coefficients down across all AMR and MG levels.
Definition AMReX_MLABecLaplacian.H:673
RT getAScalar() const final
Scalar alpha applied to the a-coefficient term.
Definition AMReX_MLABecLaplacian.H:207
void normalize(int amrlev, int mglev, MF &mf) const override
Divide mf by the diagonal of the operator (used by CG-family bottom solvers).
Definition AMReX_MLABecLaplacian.H:1306
void Fsmooth(int amrlev, int mglev, MF &sol, const MF &rhs, int redblack) const override
Perform one smoothing pass on (amrlev,mglev) updating sol against rhs. redblack selects the red (0) o...
Definition AMReX_MLABecLaplacian.H:943
std::unique_ptr< MLLinOpT< MF > > makeNLinOp(int) const final
Build the NSolve counterpart of this operator.
Definition AMReX_MLABecLaplacian.H:1384
bool m_acoef_set
Definition AMReX_MLABecLaplacian.H:263
Array< MF const *, 3 > getBCoeffs(int amrlev, int mglev) const final
Access the stored b coefficients on AMR level amrlev and MG level mglev.
Definition AMReX_MLABecLaplacian.H:214
MLABecLaplacianT(MLABecLaplacianT< MF > &&)=delete
Vector< Vector< MF > > m_a_coeffs
Definition AMReX_MLABecLaplacian.H:259
void setScalars(T1 a, T2 b) noexcept
Definition AMReX_MLABecLaplacian.H:369
bool isBottomSingular() const override
Convenience helper for the coarsest level singularity flag.
Definition AMReX_MLABecLaplacian.H:181
void applyMetricTermsCoeffs()
Apply metric factors to the stored coefficients when solving in mapped space.
Definition AMReX_MLABecLaplacian.H:503
void copyNSolveSolution(MF &dst, MF const &src) const final
Copy an NSolve solution from src to dst.
Definition AMReX_MLABecLaplacian.H:1486
bool supportNSolve() const override
Whether this operator supports NSolve.
Definition AMReX_MLABecLaplacian.H:1368
MLABecLaplacianT()=default
Construct an empty operator; call define() before solving.
typename MLLinOpT< MF >::Location Location
Definition AMReX_MLABecLaplacian.H:29
MF const * getACoeffs(int amrlev, int mglev) const final
Access the stored a coefficient on AMR level amrlev and MG level mglev.
Definition AMReX_MLABecLaplacian.H:211
void update() override
Average coefficients and enforce boundary-provided adjustments when needed.
Definition AMReX_MLABecLaplacian.H:461
bool needsUpdate() const override
True if coefficients need to be averaged down before the next apply().
Definition AMReX_MLABecLaplacian.H:170
void Fapply(int amrlev, int mglev, MF &out, const MF &in) const override
Apply the operator on (amrlev,mglev), storing L(in) in out.
Definition AMReX_MLABecLaplacian.H:860
MLABecLaplacianT(const MLABecLaplacianT< MF > &)=delete
Cell-centered operator that exposes ABec Laplacian helpers to derived classes.
Definition AMReX_MLCellABecLap.H:22
void define(const Vector< Geometry > &a_geom, const Vector< BoxArray > &a_grids, const Vector< DistributionMapping > &a_dmap, const LPInfo &a_info=LPInfo(), const Vector< FabFactory< FAB > const * > &a_factory={})
Describe the AMR hierarchy when overset masks are not required.
Definition AMReX_MLCellABecLap.H:150
void prepareForSolve() override
Standard hook called before MLMG iterates (fixes BC data, etc.).
Definition AMReX_MLCellABecLap.H:305
void update() override
Average coefficients/metrics when marked dirty.
Definition AMReX_MLCellABecLap.H:298
static constexpr int mg_coarsen_ratio
Definition AMReX_MLLinOp.H:857
static constexpr int mg_box_min_width
Definition AMReX_MLLinOp.H:858
const MLLinOpT< MF > * m_parent
Definition AMReX_MLLinOp.H:873
Definition AMReX_MultiMask.H:23
MultiArray4< int const > const_arrays() const noexcept
Return const multi-array views (alias of arrays()).
Definition AMReX_MultiMask.H:86
Array4< int const > array(const MFIter &mfi) const noexcept
Return an Array4 view (const) for iterator mfi.
Definition AMReX_MultiMask.H:69
An Iterator over the Orientation of Faces of a Box.
Definition AMReX_Orientation.H:135
This class is a thin wrapper around std::vector. Unlike vector, Vector::operator[] provides bound che...
Definition AMReX_Vector.H:29
Long size() const noexcept
Definition AMReX_Vector.H:54
A Collection of IArrayBoxes.
Definition AMReX_iMultiFab.H:34
amrex_real Real
Floating Point Type for Fields.
Definition AMReX_REAL.H:79
__host__ __device__ BoxND< dim > adjCellHi(const BoxND< dim > &b, int dir, int len=1) noexcept
Return the BoxND of length len adjacent to b on the high end along coordinate direction dir.
Definition AMReX_Box.H:1848
__host__ __device__ BoxND< dim > convert(const BoxND< dim > &b, const IntVectND< dim > &typ) noexcept
Return a copy of b converted to the nodal flags typ.
Definition AMReX_Box.H:1630
__host__ __device__ BoxND< dim > adjCellLo(const BoxND< dim > &b, int dir, int len=1) noexcept
Return the BoxND of length len adjacent to b on the low end along coordinate direction dir.
Definition AMReX_Box.H:1817
__host__ __device__ BoxND< dim > surroundingNodes(const BoxND< dim > &b, int dir) noexcept
Return a BoxND with NODE based coordinates in direction dir that encloses BoxND b.
Definition AMReX_Box.H:1582
__host__ __device__ BoxND< dim > bdryLo(const BoxND< dim > &b, int dir, int len=1) noexcept
Return the BoxND of length len on the low boundary of b along coordinate direction dir.
Definition AMReX_Box.H:1715
std::array< T, N > Array
Definition AMReX_Array.H:31
void Max(KeyValuePair< K, V > &vi, MPI_Comm comm)
Definition AMReX_ParallelReduce.H:133
__host__ __device__ constexpr const T & max(const T &a, const T &b) noexcept
Definition AMReX_Algorithm.H:53
void streamSynchronize() noexcept
Definition AMReX_GpuDevice.H:310
bool inLaunchRegion() noexcept
Definition AMReX_GpuControl.H:88
bool notInLaunchRegion() noexcept
Definition AMReX_GpuControl.H:89
bool inNoSyncRegion() noexcept
Definition AMReX_GpuControl.H:148
MPI_Comm CommunicatorSub() noexcept
sub-communicator for current frame
Definition AMReX_ParallelContext.H:70
Definition AMReX_Amr.cpp:50
int nComp(FabArrayBase const &fa)
Definition AMReX_FabArrayBase.cpp:2852
std::array< T const *, 3 > GetArrOfConstPtrs(const std::array< T, 3 > &a) noexcept
Create an array of const-qualified pointers from an array of objects.
Definition AMReX_Array.H:1079
void average_down(const MultiFab &S_fine, MultiFab &S_crse, const Geometry &fgeom, const Geometry &cgeom, int scomp, int ncomp, int rr)
Definition AMReX_MultiFabUtil.cpp:359
void ParallelFor(TypeList< CTOs... > ctos, std::array< int, sizeof...(CTOs)> const &runtime_options, T N, F &&f)
Definition AMReX_CTOParallelForImpl.H:202
BoxND< 3 > Box
Box is an alias for amrex::BoxND instantiated with AMREX_SPACEDIM.
Definition AMReX_BaseFwd.H:35
void average_down_faces(const Vector< const MF * > &fine, const Vector< MF * > &crse, const IntVect &ratio, int ngcrse=0)
Average fine face-based FabArray onto crse face-based FabArray.
Definition AMReX_MultiFabUtil.H:1056
std::array< T *, 3 > GetArrOfPtrs(std::array< T, 3 > &a) noexcept
Create an array of pointers from an array of objects.
Definition AMReX_Array.H:1033
LinOpBCType
Definition AMReX_LO_BCTYPES.H:27
IntVectND< 3 > IntVect
IntVect is an alias for amrex::IntVectND instantiated with AMREX_SPACEDIM.
Definition AMReX_BaseFwd.H:38
bool TilingIfNotGPU() noexcept
Definition AMReX_MFIter.H:12
MF::value_type norminf(MF const &mf, int scomp, int ncomp, IntVect const &nghost, bool local=false)
Definition AMReX_FabArrayUtility.H:1961
__host__ __device__ Dim3 end(BoxND< dim > const &box) noexcept
Return the iterator end coordinate of box as Dim3.
Definition AMReX_Box.H:2257
Fixed-size array that can be used on GPU.
Definition AMReX_Array.H:52
Configuration knobs for multilevel linear operators (grid agglomeration, metrics, etc....
Definition AMReX_MLLinOp.H:51
Location
Definition AMReX_MLLinOp.H:119
FabArray memory allocation information.
Definition AMReX_FabArray.H:68
Definition AMReX_MFIter.H:20
MFItInfo & SetDynamic(bool f) noexcept
Definition AMReX_MFIter.H:43
MFItInfo & EnableTiling(const IntVect &ts=FabArrayBase::mfiter_tile_size) noexcept
Definition AMReX_MFIter.H:31