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 // Robin BC modifies alpha, which has only one component.
270 [[nodiscard]] bool supportRobinBC () const noexcept override { return getNComp() == 1; }
271
272private:
273
274 bool m_needs_update = true;
275
276 int m_ncomp = 1;
277
278 Vector<int> m_a_metric_applied;
279 Vector<int> m_b_metric_applied;
280
281 void define_ab_coeffs ();
282
283 void update_singular_flags ();
284};
285
286template <typename MF>
288 const Vector<BoxArray>& a_grids,
289 const Vector<DistributionMapping>& a_dmap,
290 const LPInfo& a_info,
291 const Vector<FabFactory<FAB> const*>& a_factory,
292 int a_ncomp)
293{
294 define(a_geom, a_grids, a_dmap, a_info, a_factory, a_ncomp);
295}
296
297template <typename MF>
299 const Vector<BoxArray>& a_grids,
300 const Vector<DistributionMapping>& a_dmap,
301 const Vector<iMultiFab const*>& a_overset_mask,
302 const LPInfo& a_info,
303 const Vector<FabFactory<FAB> const*>& a_factory,
304 int a_ncomp)
305{
306 define(a_geom, a_grids, a_dmap, a_overset_mask, a_info, a_factory, a_ncomp);
307}
308
309template <typename MF> MLABecLaplacianT<MF>::~MLABecLaplacianT () = default;
310
311template <typename MF>
312void
314 const Vector<BoxArray>& a_grids,
315 const Vector<DistributionMapping>& a_dmap,
316 const LPInfo& a_info,
317 const Vector<FabFactory<FAB> const*>& a_factory,
318 int a_ncomp)
319{
320 BL_PROFILE("MLABecLaplacian::define()");
321 this->m_ncomp = a_ncomp;
322 MLCellABecLapT<MF>::define(a_geom, a_grids, a_dmap, a_info, a_factory);
323 define_ab_coeffs();
324}
325
326template <typename MF>
327void
329 const Vector<BoxArray>& a_grids,
330 const Vector<DistributionMapping>& a_dmap,
331 const Vector<iMultiFab const*>& a_overset_mask,
332 const LPInfo& a_info,
333 const Vector<FabFactory<FAB> const*>& a_factory,
334 int a_ncomp)
335{
336 BL_PROFILE("MLABecLaplacian::define(overset)");
337 this->m_ncomp = a_ncomp;
338 MLCellABecLapT<MF>::define(a_geom, a_grids, a_dmap, a_overset_mask, a_info, a_factory);
339 define_ab_coeffs();
340}
341
342template <typename MF>
343void
345{
346 m_a_coeffs.resize(this->m_num_amr_levels);
347 m_b_coeffs.resize(this->m_num_amr_levels);
348 m_a_metric_applied.assign(this->m_num_amr_levels, 0);
349 m_b_metric_applied.assign(this->m_num_amr_levels, 0);
350 for (int amrlev = 0; amrlev < this->m_num_amr_levels; ++amrlev)
351 {
352 m_a_coeffs[amrlev].resize(this->m_num_mg_levels[amrlev]);
353 m_b_coeffs[amrlev].resize(this->m_num_mg_levels[amrlev]);
354 for (int mglev = 0; mglev < this->m_num_mg_levels[amrlev]; ++mglev)
355 {
356 m_a_coeffs[amrlev][mglev].define
357 (this->m_grids[amrlev][mglev], this->m_dmap[amrlev][mglev],
358 1, 0, MFInfo(), *(this->m_factory[amrlev][mglev]));
359 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim)
360 {
361 const BoxArray& ba = amrex::convert(this->m_grids[amrlev][mglev],
363 m_b_coeffs[amrlev][mglev][idim].define
364 (ba, this->m_dmap[amrlev][mglev], m_ncomp, 0, MFInfo(),
365 *(this->m_factory[amrlev][mglev]));
366 }
367 }
368 }
369}
370
371template <typename MF>
372template <typename T1, typename T2>
373requires (std::is_convertible_v<T1, typename MF::value_type> && std::is_convertible_v<T2, typename MF::value_type>)
374void
376{
377 m_a_scalar = RT(a);
378 m_b_scalar = RT(b);
379 if (m_a_scalar == RT(0.0)) {
380 for (int amrlev = 0; amrlev < this->m_num_amr_levels; ++amrlev) {
381 m_a_coeffs[amrlev][0].setVal(RT(0.0));
382 }
383 m_acoef_set = true;
384 }
385 m_needs_update = true;
386 m_scalars_set = true;
387}
388
389template <typename MF>
390template <FabArrayType AMF>
391requires (std::is_convertible_v<typename AMF::value_type, typename MF::value_type>)
392void
393MLABecLaplacianT<MF>::setACoeffs (int amrlev, const AMF& alpha)
394{
395 AMREX_ASSERT_WITH_MESSAGE(alpha.nComp() == 1,
396 "MLABecLaplacian::setACoeffs: alpha is supposed to be single component.");
397 m_a_coeffs[amrlev][0].LocalCopy(alpha, 0, 0, 1, IntVect(0));
398 m_a_metric_applied[amrlev] = 0;
399 m_needs_update = true;
400 m_acoef_set = true;
401}
402
403template <typename MF>
404template <typename T>
405requires (std::is_convertible_v<T, typename MF::value_type>)
406void
408{
409 m_a_coeffs[amrlev][0].setVal(RT(alpha));
410 m_a_metric_applied[amrlev] = 0;
411 m_needs_update = true;
412 m_acoef_set = true;
413}
414
415
416template <typename MF>
417template <FabArrayType AMF>
418requires (std::is_convertible_v<typename AMF::value_type, typename MF::value_type>)
419void
422{
423 const int ncomp = this->getNComp();
424 AMREX_ASSERT(beta[0]->nComp() == 1 || beta[0]->nComp() == ncomp);
425 if (beta[0]->nComp() == ncomp) {
426 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
427 for (int icomp = 0; icomp < ncomp; ++icomp) {
428 m_b_coeffs[amrlev][0][idim].LocalCopy(*beta[idim], icomp, icomp, 1, IntVect(0));
429 }
430 }
431 } else {
432 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
433 for (int icomp = 0; icomp < ncomp; ++icomp) {
434 m_b_coeffs[amrlev][0][idim].LocalCopy(*beta[idim], 0, icomp, 1, IntVect(0));
435 }
436 }
437 }
438 m_b_metric_applied[amrlev] = 0;
439 m_needs_update = true;
440}
441
442template <typename MF>
443template <typename T>
444requires (std::is_convertible_v<T, typename MF::value_type>)
445void
447{
448 [[maybe_unused]] Gpu::SyncAtExitOnly no_sync{};
449 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
450 m_b_coeffs[amrlev][0][idim].setVal(RT(beta));
451 }
452 m_b_metric_applied[amrlev] = 0;
453 m_needs_update = true;
454}
455
456template <typename MF>
457template <typename T>
458requires (std::is_convertible_v<T, typename MF::value_type>)
459void
461{
462 [[maybe_unused]] Gpu::SyncAtExitOnly no_sync{};
463 const int ncomp = this->getNComp();
464 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
465 for (int icomp = 0; icomp < ncomp; ++icomp) {
466 m_b_coeffs[amrlev][0][idim].setVal(RT(beta[icomp]), icomp, 1, 0);
467 }
468 }
469 m_b_metric_applied[amrlev] = 0;
470 m_needs_update = true;
471}
472
473template <typename MF>
474void
476{
479 }
480
481#if (AMREX_SPACEDIM != 3)
482 applyMetricTermsCoeffs();
483#endif
484
485 applyRobinBCTermsCoeffs();
486
487 averageDownCoeffs();
488
489 update_singular_flags();
490
491 m_needs_update = false;
492}
493
494template <typename MF>
495void
497{
498 BL_PROFILE("MLABecLaplacian::prepareForSolve()");
499
501
502#if (AMREX_SPACEDIM != 3)
503 applyMetricTermsCoeffs();
504#endif
505
506 applyRobinBCTermsCoeffs();
507
508 averageDownCoeffs();
509
510 update_singular_flags();
511
512 m_needs_update = false;
513}
514
515template <typename MF>
516void
518{
519#if (AMREX_SPACEDIM != 3)
520 for (int alev = 0; alev < this->m_num_amr_levels; ++alev)
521 {
522 const int mglev = 0;
523 if (!m_a_metric_applied[alev]) {
524 this->applyMetricTerm(alev, mglev, m_a_coeffs[alev][mglev]);
525 m_a_metric_applied[alev] = 1;
526 }
527 if (!m_b_metric_applied[alev]) {
528 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim)
529 {
530 this->applyMetricTerm(alev, mglev, m_b_coeffs[alev][mglev][idim]);
531 }
532 m_b_metric_applied[alev] = 1;
533 }
534 }
535#endif
536}
537
538//
539// Suppose we are solving `alpha u - del (beta grad u) = rhs` (Scalar
540// coefficients can be easily added back in the end) and there is Robin BC
541// `a u + b du/dn = f` at the upper end of the x-direction. The 1D
542// discretization at the last cell i is
543//
544// alpha u_i + (beta_{i-1/2} (du/dx)_{i-1/2} - beta_{i+1/2} (du/dx)_{i+1/2}) / h = rhs_i
545//
546// where h is the cell size. At `i+1/2` (i.e., the boundary), we have
547//
548// a (u_i + u_{i+1})/2 + b (u_{i+1}-u_i)/h = f,
549//
550// according to the Robin BC. This gives
551//
552// u_{i+1} = A + B u_i,
553//
554// where `A = f/(b/h + a/2)` and `B = (b/h - a/2) / (b/h + a/2). We then
555// use `u_i` and `u_{i+1}` to compute `(du/dx)_{i+1/2}`. The discretization
556// at cell i then becomes
557//
558// \tilde{alpha}_i u_i + (beta_{i-1/2} (du/dx)_{i-1/2} - 0) / h = \tilde{rhs}_i
559//
560// This is equivalent to having homogeneous Neumann BC with modified alpha and rhs.
561//
562// \tilde{alpha}_i = alpha_i + (1-B) beta_{i+1/2} / h^2
563// \tilde{rhs}_i = rhs_i + A beta_{i+1/2} / h^2
564//
566namespace detail {
567template <typename LP>
568void applyRobinBCTermsCoeffs (LP& linop)
569{
570 using RT = typename LP::RT;
571
572 const int ncomp = linop.getNComp();
573 bool reset_alpha = false;
574 if (linop.m_a_scalar == RT(0.0)) {
575 linop.m_a_scalar = RT(1.0);
576 reset_alpha = true;
577 }
578 const RT bovera = linop.m_b_scalar/linop.m_a_scalar;
579
580 if (!reset_alpha) {
581 AMREX_ALWAYS_ASSERT_WITH_MESSAGE(linop.m_scalars_set && linop.m_acoef_set,
582 "To reuse solver With Robin BC, one must re-call setScalars (and setACoeffs if the scalar is not zero)");
583 }
584
585 linop.m_scalars_set = false;
586 linop.m_acoef_set = false;
587
588 for (int amrlev = 0; amrlev < linop.NAMRLevels(); ++amrlev) {
589 const int mglev = 0;
590 const Box& domain = linop.Geom(amrlev,mglev).Domain();
591 const RT dxi = static_cast<RT>(linop.Geom(amrlev,mglev).InvCellSize(0));
592 const RT dyi = static_cast<RT>((AMREX_SPACEDIM >= 2) ? linop.Geom(amrlev,mglev).InvCellSize(1) : Real(1.0));
593 const RT dzi = static_cast<RT>((AMREX_SPACEDIM == 3) ? linop.Geom(amrlev,mglev).InvCellSize(2) : Real(1.0));
594
595 if (reset_alpha) {
596 linop.m_a_coeffs[amrlev][mglev].setVal(RT(0.0));
597 }
598
599 MFItInfo mfi_info;
600 if (Gpu::notInLaunchRegion()) { mfi_info.SetDynamic(true); }
601
602#ifdef AMREX_USE_OMP
603#pragma omp parallel if (Gpu::notInLaunchRegion())
604#endif
605 for (MFIter mfi(linop.m_a_coeffs[amrlev][mglev], mfi_info); mfi.isValid(); ++mfi)
606 {
607 const Box& vbx = mfi.validbox();
608 auto const& afab = linop.m_a_coeffs[amrlev][mglev].array(mfi);
609 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
610 auto const& bfab = linop.m_b_coeffs[amrlev][mglev][idim].const_array(mfi);
611 const Box& blo = amrex::adjCellLo(vbx,idim);
612 const Box& bhi = amrex::adjCellHi(vbx,idim);
613 bool outside_domain_lo = !(domain.contains(blo));
614 bool outside_domain_hi = !(domain.contains(bhi));
615 if ((!outside_domain_lo) && (!outside_domain_hi)) { continue; }
616 for (int icomp = 0; icomp < ncomp; ++icomp) {
617 auto const& rbc = (*(linop.m_robin_bcval[amrlev]))[mfi].const_array(icomp*3);
618 if (linop.m_lobc_orig[icomp][idim] == LinOpBCType::Robin && outside_domain_lo)
619 {
620 if (idim == 0) {
621 RT fac = bovera*dxi*dxi;
622 AMREX_HOST_DEVICE_FOR_3D(blo, i, j, k,
623 {
624 RT B = (rbc(i,j,k,1)*dxi - rbc(i,j,k,0)*RT(0.5))
625 / (rbc(i,j,k,1)*dxi + rbc(i,j,k,0)*RT(0.5));
626 afab(i+1,j,k,icomp) += fac*bfab(i+1,j,k,icomp)*(RT(1.0)-B);
627 });
628 } else if (idim == 1) {
629 RT fac = bovera*dyi*dyi;
630 AMREX_HOST_DEVICE_FOR_3D(blo, i, j, k,
631 {
632 RT B = (rbc(i,j,k,1)*dyi - rbc(i,j,k,0)*RT(0.5))
633 / (rbc(i,j,k,1)*dyi + rbc(i,j,k,0)*RT(0.5));
634 afab(i,j+1,k,icomp) += fac*bfab(i,j+1,k,icomp)*(RT(1.0)-B);
635 });
636 } else {
637 RT fac = bovera*dzi*dzi;
638 AMREX_HOST_DEVICE_FOR_3D(blo, i, j, k,
639 {
640 RT B = (rbc(i,j,k,1)*dzi - rbc(i,j,k,0)*RT(0.5))
641 / (rbc(i,j,k,1)*dzi + rbc(i,j,k,0)*RT(0.5));
642 afab(i,j,k+1,icomp) += fac*bfab(i,j,k+1,icomp)*(RT(1.0)-B);
643 });
644 }
645 }
646 if (linop.m_hibc_orig[icomp][idim] == LinOpBCType::Robin && outside_domain_hi)
647 {
648 if (idim == 0) {
649 RT fac = bovera*dxi*dxi;
650 AMREX_HOST_DEVICE_FOR_3D(bhi, i, j, k,
651 {
652 RT B = (rbc(i,j,k,1)*dxi - rbc(i,j,k,0)*RT(0.5))
653 / (rbc(i,j,k,1)*dxi + rbc(i,j,k,0)*RT(0.5));
654 afab(i-1,j,k,icomp) += fac*bfab(i,j,k,icomp)*(RT(1.0)-B);
655 });
656 } else if (idim == 1) {
657 RT fac = bovera*dyi*dyi;
658 AMREX_HOST_DEVICE_FOR_3D(bhi, i, j, k,
659 {
660 RT B = (rbc(i,j,k,1)*dyi - rbc(i,j,k,0)*RT(0.5))
661 / (rbc(i,j,k,1)*dyi + rbc(i,j,k,0)*RT(0.5));
662 afab(i,j-1,k,icomp) += fac*bfab(i,j,k,icomp)*(RT(1.0)-B);
663 });
664 } else {
665 RT fac = bovera*dzi*dzi;
666 AMREX_HOST_DEVICE_FOR_3D(bhi, i, j, k,
667 {
668 RT B = (rbc(i,j,k,1)*dzi - rbc(i,j,k,0)*RT(0.5))
669 / (rbc(i,j,k,1)*dzi + rbc(i,j,k,0)*RT(0.5));
670 afab(i,j,k-1,icomp) += fac*bfab(i,j,k,icomp)*(RT(1.0)-B);
671 });
672 }
673 }
674 }
675 }
676 }
677 }
678}
679} // namespace detail
681
682template <typename MF>
683void
685{
686 if (this->hasRobinBC()) {
687 detail::applyRobinBCTermsCoeffs(*this);
688 }
689}
690
691template <typename MF>
692void
694{
695 BL_PROFILE("MLABecLaplacian::averageDownCoeffs()");
696
697 for (int amrlev = this->m_num_amr_levels-1; amrlev > 0; --amrlev)
698 {
699 auto& fine_a_coeffs = m_a_coeffs[amrlev];
700 auto& fine_b_coeffs = m_b_coeffs[amrlev];
701
702 averageDownCoeffsSameAmrLevel(amrlev, fine_a_coeffs, fine_b_coeffs);
703 averageDownCoeffsToCoarseAmrLevel(amrlev);
704 }
705
706 averageDownCoeffsSameAmrLevel(0, m_a_coeffs[0], m_b_coeffs[0]);
707}
708
709template <typename MF>
710void
713{
714 int nmglevs = a.size();
715 for (int mglev = 1; mglev < nmglevs; ++mglev)
716 {
717 IntVect ratio = (amrlev > 0) ? IntVect(this->mg_coarsen_ratio) : this->mg_coarsen_ratio_vec[mglev-1];
718 if (this->hasHiddenDimension()) { ratio[this->hiddenDirection()] = 1; }
719
720 if (m_a_scalar == 0.0)
721 {
722 a[mglev].setVal(RT(0.0));
723 }
724 else
725 {
726 amrex::average_down(a[mglev-1], a[mglev], 0, 1, ratio);
727 }
728
729 Vector<const MF*> fine {AMREX_D_DECL(&(b[mglev-1][0]),
730 &(b[mglev-1][1]),
731 &(b[mglev-1][2]))};
732 Vector<MF*> crse {AMREX_D_DECL(&(b[mglev][0]),
733 &(b[mglev][1]),
734 &(b[mglev][2]))};
735
737 }
738
739 for (int mglev = 1; mglev < nmglevs; ++mglev)
740 {
741 if (this->m_overset_mask[amrlev][mglev]) {
742 const RT fac = static_cast<RT>(1 << mglev); // 2**mglev
743 const RT osfac = RT(2.0)*fac/(fac+RT(1.0));
744 const int ncomp = this->getNComp();
745#ifdef AMREX_USE_OMP
746#pragma omp parallel if (Gpu::notInLaunchRegion())
747#endif
748 for (MFIter mfi(a[mglev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
749 {
750 AMREX_D_TERM(Box const& xbx = mfi.nodaltilebox(0);,
751 Box const& ybx = mfi.nodaltilebox(1);,
752 Box const& zbx = mfi.nodaltilebox(2));
753 AMREX_D_TERM(auto const& bx = b[mglev][0].array(mfi);,
754 auto const& by = b[mglev][1].array(mfi);,
755 auto const& bz = b[mglev][2].array(mfi));
756 auto const& osm = this->m_overset_mask[amrlev][mglev]->const_array(mfi);
757#if defined(AMREX_USE_CUDA) && defined(_WIN32)
759 (xbx, t_xbx,
760 {
761 overset_rescale_bcoef_x(t_xbx, bx, osm, ncomp, osfac);
762 });
763#if (AMREX_SPACEDIM >= 2)
765 (ybx, t_ybx,
766 {
767 overset_rescale_bcoef_y(t_ybx, by, osm, ncomp, osfac);
768 });
769#endif
770#if (AMREX_SPACEDIM == 3)
772 (zbx, t_zbx,
773 {
774 overset_rescale_bcoef_z(t_zbx, bz, osm, ncomp, osfac);
775 });
776#endif
777#else
779 (xbx, t_xbx,
780 {
781 overset_rescale_bcoef_x(t_xbx, bx, osm, ncomp, osfac);
782 },
783 ybx, t_ybx,
784 {
785 overset_rescale_bcoef_y(t_ybx, by, osm, ncomp, osfac);
786 },
787 zbx, t_zbx,
788 {
789 overset_rescale_bcoef_z(t_zbx, bz, osm, ncomp, osfac);
790 });
791#endif
792 }
793 }
794 }
795}
796
797template <typename MF>
798void
800{
801 auto& fine_a_coeffs = m_a_coeffs[flev ].back();
802 auto& fine_b_coeffs = m_b_coeffs[flev ].back();
803 auto& crse_a_coeffs = m_a_coeffs[flev-1].front();
804 auto& crse_b_coeffs = m_b_coeffs[flev-1].front();
805
806 if (m_a_scalar != 0.0) {
807 // We coarsen from the back of flev to the front of flev-1.
808 // So we use mg_coarsen_ratio.
809 amrex::average_down(fine_a_coeffs, crse_a_coeffs, 0, 1, this->mg_coarsen_ratio);
810 }
811
813 amrex::GetArrOfPtrs(crse_b_coeffs),
814 IntVect(this->mg_coarsen_ratio),
815 this->m_geom[flev-1][0]);
816}
817
818template <typename MF>
819void
821{
822 m_is_singular.clear();
823 m_is_singular.resize(this->m_num_amr_levels, false);
824 auto itlo = std::ranges::find(this->m_lobc[0], BCType::Dirichlet);
825 auto ithi = std::ranges::find(this->m_hibc[0], BCType::Dirichlet);
826 if (itlo == this->m_lobc[0].end() && ithi == this->m_hibc[0].end())
827 { // No Dirichlet
828 for (int alev = 0; alev < this->m_num_amr_levels; ++alev)
829 {
830 // For now this assumes that overset regions are treated as Dirichlet bc's
831 if (this->m_domain_covered[alev] && !this->m_overset_mask[alev][0])
832 {
833 if (m_a_scalar == Real(0.0))
834 {
835 m_is_singular[alev] = true;
836 }
837 else
838 {
839 RT asum = m_a_coeffs[alev].back().sum(0,IntVect(0));
840 RT amax = m_a_coeffs[alev].back().norminf(0,1,IntVect(0));
841 m_is_singular[alev] = (std::abs(asum) <= amax * RT(1.e-12));
842 }
843 }
844 }
845 }
846
847 if (!m_is_singular[0] && this->m_needs_coarse_data_for_bc &&
848 this->m_coarse_fine_bc_type == LinOpBCType::Neumann)
849 {
850 AMREX_ASSERT(this->m_overset_mask[0][0] == nullptr);
851
852 bool lev0_a_is_zero = false;
853 if (m_a_scalar == Real(0.0)) {
854 lev0_a_is_zero = true;
855 } else {
856 RT asum = m_a_coeffs[0].back().sum(0,IntVect(0));
857 RT amax = m_a_coeffs[0].back().norminf(0,1,IntVect(0));
858 bool a_is_almost_zero = std::abs(asum) <= amax * RT(1.e-12);
859 if (a_is_almost_zero) { lev0_a_is_zero = true; }
860 }
861
862 if (lev0_a_is_zero) {
863 auto bbox = this->m_grids[0][0].minimalBox();
864 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
865 if (this->m_lobc[0][idim] == LinOpBCType::Dirichlet) {
866 bbox.growLo(idim,1);
867 }
868 if (this->m_hibc[0][idim] == LinOpBCType::Dirichlet) {
869 bbox.growHi(idim,1);
870 }
871 }
872 if (this->m_geom[0][0].Domain().contains(bbox)) {
873 m_is_singular[0] = true;
874 }
875 }
876 }
877}
878
879template <typename MF>
880void
881MLABecLaplacianT<MF>::Fapply (int amrlev, int mglev, MF& out, const MF& in) const
882{
883 BL_PROFILE("MLABecLaplacian::Fapply()");
884
885 const MF& acoef = m_a_coeffs[amrlev][mglev];
886 AMREX_D_TERM(const MF& bxcoef = m_b_coeffs[amrlev][mglev][0];,
887 const MF& bycoef = m_b_coeffs[amrlev][mglev][1];,
888 const MF& bzcoef = m_b_coeffs[amrlev][mglev][2];);
889
891 {AMREX_D_DECL(static_cast<RT>(this->m_geom[amrlev][mglev].InvCellSize(0)),
892 static_cast<RT>(this->m_geom[amrlev][mglev].InvCellSize(1)),
893 static_cast<RT>(this->m_geom[amrlev][mglev].InvCellSize(2)))};
894
895 const RT ascalar = m_a_scalar;
896 const RT bscalar = m_b_scalar;
897
898 const int ncomp = this->getNComp();
899
900#ifdef AMREX_USE_GPU
901 if (Gpu::inLaunchRegion()) {
902 const auto& xma = in.const_arrays();
903 const auto& yma = out.arrays();
904 const auto& ama = acoef.arrays();
905 AMREX_D_TERM(const auto& bxma = bxcoef.const_arrays();,
906 const auto& byma = bycoef.const_arrays();,
907 const auto& bzma = bzcoef.const_arrays(););
908 if (this->m_overset_mask[amrlev][mglev]) {
909 const auto& osmma = this->m_overset_mask[amrlev][mglev]->const_arrays();
910 ParallelFor(out, IntVect(0), ncomp,
911 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
912 {
913 mlabeclap_adotx_os(i,j,k,n, yma[box_no], xma[box_no], ama[box_no],
914 AMREX_D_DECL(bxma[box_no],byma[box_no],bzma[box_no]),
915 osmma[box_no], dxinv, ascalar, bscalar);
916 });
917 } else {
918 ParallelFor(out, IntVect(0), ncomp,
919 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
920 {
921 mlabeclap_adotx(i,j,k,n, yma[box_no], xma[box_no], ama[box_no],
922 AMREX_D_DECL(bxma[box_no],byma[box_no],bzma[box_no]),
923 dxinv, ascalar, bscalar);
924 });
925 }
926 if (!Gpu::inNoSyncRegion()) {
928 }
929 } else
930#endif
931 {
932#ifdef AMREX_USE_OMP
933#pragma omp parallel if (Gpu::notInLaunchRegion())
934#endif
935 for (MFIter mfi(out, TilingIfNotGPU()); mfi.isValid(); ++mfi)
936 {
937 const Box& bx = mfi.tilebox();
938 const auto& xfab = in.array(mfi);
939 const auto& yfab = out.array(mfi);
940 const auto& afab = acoef.array(mfi);
941 AMREX_D_TERM(const auto& bxfab = bxcoef.array(mfi);,
942 const auto& byfab = bycoef.array(mfi);,
943 const auto& bzfab = bzcoef.array(mfi););
944 if (this->m_overset_mask[amrlev][mglev]) {
945 const auto& osm = this->m_overset_mask[amrlev][mglev]->const_array(mfi);
946 AMREX_HOST_DEVICE_PARALLEL_FOR_4D(bx, ncomp, i, j, k, n,
947 {
948 mlabeclap_adotx_os(i,j,k,n, yfab, xfab, afab, AMREX_D_DECL(bxfab,byfab,bzfab),
949 osm, dxinv, ascalar, bscalar);
950 });
951 } else {
952 AMREX_HOST_DEVICE_PARALLEL_FOR_4D(bx, ncomp, i, j, k, n,
953 {
954 mlabeclap_adotx(i,j,k,n, yfab, xfab, afab, AMREX_D_DECL(bxfab,byfab,bzfab),
955 dxinv, ascalar, bscalar);
956 });
957 }
958 }
959 }
960}
961
962template <typename MF>
963void
964MLABecLaplacianT<MF>::Fsmooth (int amrlev, int mglev, MF& sol, const MF& rhs, int redblack) const
965{
966 BL_PROFILE("MLABecLaplacian::Fsmooth()");
967
968 bool regular_coarsening = true;
969 if (amrlev == 0 && mglev > 0) {
970 regular_coarsening = this->mg_coarsen_ratio_vec[mglev-1] == this->mg_coarsen_ratio;
971 }
972
973 MF Ax;
974 if (! this->m_use_gauss_seidel && regular_coarsening) { // jacobi
975 Ax.define(sol.boxArray(), sol.DistributionMap(), sol.nComp(), 0,
976 MFInfo().SetArena(The_Async_Arena()));
977 Fapply(amrlev, mglev, Ax, sol);
978 }
979
980 const MF& acoef = m_a_coeffs[amrlev][mglev];
981 AMREX_ALWAYS_ASSERT(acoef.nGrowVect() == 0);
982 AMREX_D_TERM(const MF& bxcoef = m_b_coeffs[amrlev][mglev][0];,
983 const MF& bycoef = m_b_coeffs[amrlev][mglev][1];,
984 const MF& bzcoef = m_b_coeffs[amrlev][mglev][2];);
985 const auto& undrrelxr = this->m_undrrelxr[amrlev][mglev];
986 const auto& maskvals = this->m_maskvals [amrlev][mglev];
987
988 OrientationIter oitr;
989
990 const auto& f0 = undrrelxr[oitr()]; ++oitr;
991 const auto& f1 = undrrelxr[oitr()]; ++oitr;
992#if (AMREX_SPACEDIM > 1)
993 const auto& f2 = undrrelxr[oitr()]; ++oitr;
994 const auto& f3 = undrrelxr[oitr()]; ++oitr;
995#if (AMREX_SPACEDIM > 2)
996 const auto& f4 = undrrelxr[oitr()]; ++oitr;
997 const auto& f5 = undrrelxr[oitr()]; ++oitr;
998#endif
999#endif
1000
1001 const MultiMask& mm0 = maskvals[0];
1002 const MultiMask& mm1 = maskvals[1];
1003#if (AMREX_SPACEDIM > 1)
1004 const MultiMask& mm2 = maskvals[2];
1005 const MultiMask& mm3 = maskvals[3];
1006#if (AMREX_SPACEDIM > 2)
1007 const MultiMask& mm4 = maskvals[4];
1008 const MultiMask& mm5 = maskvals[5];
1009#endif
1010#endif
1011
1012 const int nc = this->getNComp();
1013 const Real* h = this->m_geom[amrlev][mglev].CellSize();
1014 AMREX_D_TERM(const RT dhx = m_b_scalar/static_cast<RT>(h[0]*h[0]);,
1015 const RT dhy = m_b_scalar/static_cast<RT>(h[1]*h[1]);,
1016 const RT dhz = m_b_scalar/static_cast<RT>(h[2]*h[2]));
1017 const RT alpha = m_a_scalar;
1018
1019#ifdef AMREX_USE_GPU
1020 // The line solve taken for semi-coarsened levels is host only.
1021 AMREX_ALWAYS_ASSERT_WITH_MESSAGE(regular_coarsening
1022 || this->m_overset_mask[amrlev][mglev]
1024 "MLABecLaplacian::Fsmooth: line solve is not supported on GPU");
1026 && (this->m_overset_mask[amrlev][mglev] || regular_coarsening))
1027 {
1028 const auto& m0ma = mm0.const_arrays();
1029 const auto& m1ma = mm1.const_arrays();
1030#if (AMREX_SPACEDIM > 1)
1031 const auto& m2ma = mm2.const_arrays();
1032 const auto& m3ma = mm3.const_arrays();
1033#if (AMREX_SPACEDIM > 2)
1034 const auto& m4ma = mm4.const_arrays();
1035 const auto& m5ma = mm5.const_arrays();
1036#endif
1037#endif
1038
1039 const auto& solnma = sol.arrays();
1040 const auto& rhsma = rhs.const_arrays();
1041 const auto& ama = acoef.const_arrays();
1042
1043 AMREX_D_TERM(const auto& bxma = bxcoef.const_arrays();,
1044 const auto& byma = bycoef.const_arrays();,
1045 const auto& bzma = bzcoef.const_arrays(););
1046
1047 const auto& f0ma = f0.const_arrays();
1048 const auto& f1ma = f1.const_arrays();
1049#if (AMREX_SPACEDIM > 1)
1050 const auto& f2ma = f2.const_arrays();
1051 const auto& f3ma = f3.const_arrays();
1052#if (AMREX_SPACEDIM > 2)
1053 const auto& f4ma = f4.const_arrays();
1054 const auto& f5ma = f5.const_arrays();
1055#endif
1056#endif
1057
1058 if (this->m_overset_mask[amrlev][mglev]) {
1059 const auto& osmma = this->m_overset_mask[amrlev][mglev]->const_arrays();
1060 if (this->m_use_gauss_seidel) {
1061 ParallelFor(sol, IntVect(0), nc,
1062 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
1063 {
1064 Box vbx(ama[box_no]);
1065 abec_gsrb_os(i,j,k,n, solnma[box_no], rhsma[box_no], alpha, ama[box_no],
1066 AMREX_D_DECL(dhx, dhy, dhz),
1067 AMREX_D_DECL(bxma[box_no],byma[box_no],bzma[box_no]),
1068 AMREX_D_DECL(m0ma[box_no],m2ma[box_no],m4ma[box_no]),
1069 AMREX_D_DECL(m1ma[box_no],m3ma[box_no],m5ma[box_no]),
1070 AMREX_D_DECL(f0ma[box_no],f2ma[box_no],f4ma[box_no]),
1071 AMREX_D_DECL(f1ma[box_no],f3ma[box_no],f5ma[box_no]),
1072 osmma[box_no], vbx, redblack);
1073 });
1074 } else {
1075 const auto& axma = Ax.const_arrays();
1076 ParallelFor(sol, IntVect(0), nc,
1077 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
1078 {
1079 Box vbx(ama[box_no]);
1080 abec_jacobi_os(i,j,k,n, solnma[box_no], rhsma[box_no], axma[box_no],
1081 alpha, ama[box_no],
1082 AMREX_D_DECL(dhx, dhy, dhz),
1083 AMREX_D_DECL(bxma[box_no],byma[box_no],bzma[box_no]),
1084 AMREX_D_DECL(m0ma[box_no],m2ma[box_no],m4ma[box_no]),
1085 AMREX_D_DECL(m1ma[box_no],m3ma[box_no],m5ma[box_no]),
1086 AMREX_D_DECL(f0ma[box_no],f2ma[box_no],f4ma[box_no]),
1087 AMREX_D_DECL(f1ma[box_no],f3ma[box_no],f5ma[box_no]),
1088 osmma[box_no], vbx);
1089 });
1090 }
1091 } else if (regular_coarsening) {
1092 if (this->m_use_gauss_seidel) {
1093 ParallelFor(sol, IntVect(0), nc,
1094 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
1095 {
1096 Box vbx(ama[box_no]);
1097 abec_gsrb(i,j,k,n, solnma[box_no], rhsma[box_no], alpha, ama[box_no],
1098 AMREX_D_DECL(dhx, dhy, dhz),
1099 AMREX_D_DECL(bxma[box_no],byma[box_no],bzma[box_no]),
1100 AMREX_D_DECL(m0ma[box_no],m2ma[box_no],m4ma[box_no]),
1101 AMREX_D_DECL(m1ma[box_no],m3ma[box_no],m5ma[box_no]),
1102 AMREX_D_DECL(f0ma[box_no],f2ma[box_no],f4ma[box_no]),
1103 AMREX_D_DECL(f1ma[box_no],f3ma[box_no],f5ma[box_no]),
1104 vbx, redblack);
1105 });
1106 } else {
1107 const auto& axma = Ax.const_arrays();
1108 ParallelFor(sol, IntVect(0), nc,
1109 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
1110 {
1111 Box vbx(ama[box_no]);
1112 abec_jacobi(i,j,k,n, solnma[box_no], rhsma[box_no], axma[box_no],
1113 alpha, ama[box_no],
1114 AMREX_D_DECL(dhx, dhy, dhz),
1115 AMREX_D_DECL(bxma[box_no],byma[box_no],bzma[box_no]),
1116 AMREX_D_DECL(m0ma[box_no],m2ma[box_no],m4ma[box_no]),
1117 AMREX_D_DECL(m1ma[box_no],m3ma[box_no],m5ma[box_no]),
1118 AMREX_D_DECL(f0ma[box_no],f2ma[box_no],f4ma[box_no]),
1119 AMREX_D_DECL(f1ma[box_no],f3ma[box_no],f5ma[box_no]),
1120 vbx);
1121 });
1122 }
1123 }
1124 if (!Gpu::inNoSyncRegion()) {
1126 }
1127 } else
1128#endif
1129 {
1130 MFItInfo mfi_info;
1131 mfi_info.SetDynamic(true);
1132 // The line solve below needs whole valid boxes, not tiles: a tile
1133 // would truncate the tridiagonal lines and make neighboring threads
1134 // race on the cells at the tile edges.
1135 if (regular_coarsening || this->m_overset_mask[amrlev][mglev]) {
1136 mfi_info.EnableTiling();
1137 }
1138
1139#ifdef AMREX_USE_OMP
1140#pragma omp parallel if (Gpu::notInLaunchRegion())
1141#endif
1142 for (MFIter mfi(sol,mfi_info); mfi.isValid(); ++mfi)
1143 {
1144 const auto& m0 = mm0.array(mfi);
1145 const auto& m1 = mm1.array(mfi);
1146#if (AMREX_SPACEDIM > 1)
1147 const auto& m2 = mm2.array(mfi);
1148 const auto& m3 = mm3.array(mfi);
1149#if (AMREX_SPACEDIM > 2)
1150 const auto& m4 = mm4.array(mfi);
1151 const auto& m5 = mm5.array(mfi);
1152#endif
1153#endif
1154
1155 const Box& tbx = mfi.tilebox();
1156 const Box& vbx = mfi.validbox();
1157 const auto& solnfab = sol.array(mfi);
1158 const auto& rhsfab = rhs.const_array(mfi);
1159 const auto& afab = acoef.const_array(mfi);
1160
1161 AMREX_D_TERM(const auto& bxfab = bxcoef.const_array(mfi);,
1162 const auto& byfab = bycoef.const_array(mfi);,
1163 const auto& bzfab = bzcoef.const_array(mfi););
1164
1165 const auto& f0fab = f0.const_array(mfi);
1166 const auto& f1fab = f1.const_array(mfi);
1167#if (AMREX_SPACEDIM > 1)
1168 const auto& f2fab = f2.const_array(mfi);
1169 const auto& f3fab = f3.const_array(mfi);
1170#if (AMREX_SPACEDIM > 2)
1171 const auto& f4fab = f4.const_array(mfi);
1172 const auto& f5fab = f5.const_array(mfi);
1173#endif
1174#endif
1175
1176 if (this->m_overset_mask[amrlev][mglev]) {
1177 const auto& osm = this->m_overset_mask[amrlev][mglev]->const_array(mfi);
1178 if (this->m_use_gauss_seidel) {
1179 AMREX_LOOP_4D(tbx, nc, i, j, k, n,
1180 {
1181 abec_gsrb_os(i,j,k,n, solnfab, rhsfab, alpha, afab,
1182 AMREX_D_DECL(dhx, dhy, dhz),
1183 AMREX_D_DECL(bxfab, byfab, bzfab),
1184 AMREX_D_DECL(m0,m2,m4),
1185 AMREX_D_DECL(m1,m3,m5),
1186 AMREX_D_DECL(f0fab,f2fab,f4fab),
1187 AMREX_D_DECL(f1fab,f3fab,f5fab),
1188 osm, vbx, redblack);
1189 });
1190 } else {
1191 const auto& axfab = Ax.const_array(mfi);
1192 AMREX_LOOP_4D(tbx, nc, i, j, k, n,
1193 {
1194 abec_jacobi_os(i,j,k,n, solnfab, rhsfab, axfab,
1195 alpha, afab,
1196 AMREX_D_DECL(dhx, dhy, dhz),
1197 AMREX_D_DECL(bxfab, byfab, bzfab),
1198 AMREX_D_DECL(m0,m2,m4),
1199 AMREX_D_DECL(m1,m3,m5),
1200 AMREX_D_DECL(f0fab,f2fab,f4fab),
1201 AMREX_D_DECL(f1fab,f3fab,f5fab),
1202 osm, vbx);
1203 });
1204 }
1205 } else if (regular_coarsening) {
1206 if (this->m_use_gauss_seidel) {
1207 AMREX_LOOP_4D(tbx, nc, i, j, k, n,
1208 {
1209 abec_gsrb(i,j,k,n, solnfab, rhsfab, alpha, afab,
1210 AMREX_D_DECL(dhx, dhy, dhz),
1211 AMREX_D_DECL(bxfab, byfab, bzfab),
1212 AMREX_D_DECL(m0,m2,m4),
1213 AMREX_D_DECL(m1,m3,m5),
1214 AMREX_D_DECL(f0fab,f2fab,f4fab),
1215 AMREX_D_DECL(f1fab,f3fab,f5fab),
1216 vbx, redblack);
1217 });
1218 } else {
1219 const auto& axfab = Ax.const_array(mfi);
1220 AMREX_LOOP_4D(tbx, nc, i, j, k, n,
1221 {
1222 abec_jacobi(i,j,k,n, solnfab, rhsfab, axfab,
1223 alpha, afab,
1224 AMREX_D_DECL(dhx, dhy, dhz),
1225 AMREX_D_DECL(bxfab, byfab, bzfab),
1226 AMREX_D_DECL(m0,m2,m4),
1227 AMREX_D_DECL(m1,m3,m5),
1228 AMREX_D_DECL(f0fab,f2fab,f4fab),
1229 AMREX_D_DECL(f1fab,f3fab,f5fab),
1230 vbx);
1231 });
1232 }
1233 } else {
1234 // Line solve for semi-coarsening. Host only, and tbx == vbx
1235 // because tiling is disabled above for this branch.
1236 abec_gsrb_with_line_solve(tbx, solnfab, rhsfab, alpha, afab,
1237 AMREX_D_DECL(dhx, dhy, dhz),
1238 AMREX_D_DECL(bxfab, byfab, bzfab),
1239 AMREX_D_DECL(m0,m2,m4),
1240 AMREX_D_DECL(m1,m3,m5),
1241 AMREX_D_DECL(f0fab,f2fab,f4fab),
1242 AMREX_D_DECL(f1fab,f3fab,f5fab),
1243 vbx, redblack, nc);
1244 }
1245 }
1246 }
1247}
1248
1249template <typename MF>
1250void
1251MLABecLaplacianT<MF>::FFlux (int amrlev, const MFIter& mfi,
1252 const Array<FAB*,AMREX_SPACEDIM>& flux,
1253 const FAB& sol, Location, int face_only) const
1254{
1255 BL_PROFILE("MLABecLaplacian::FFlux()");
1256
1257 const int mglev = 0;
1258 const Box& box = mfi.tilebox();
1259 const Real* dxinv = this->m_geom[amrlev][mglev].InvCellSize();
1260 const int ncomp = this->getNComp();
1261 FFlux(box, dxinv, m_b_scalar,
1262 Array<FAB const*,AMREX_SPACEDIM>{{AMREX_D_DECL(&(m_b_coeffs[amrlev][mglev][0][mfi]),
1263 &(m_b_coeffs[amrlev][mglev][1][mfi]),
1264 &(m_b_coeffs[amrlev][mglev][2][mfi]))}},
1265 flux, sol, face_only, ncomp);
1266}
1267
1268template <typename MF>
1269void
1270MLABecLaplacianT<MF>::FFlux (Box const& box, Real const* dxinv, RT bscalar,
1272 Array<FAB*,AMREX_SPACEDIM> const& flux,
1273 FAB const& sol, int face_only, int ncomp)
1274{
1275 AMREX_D_TERM(const auto bx = bcoef[0]->const_array();,
1276 const auto by = bcoef[1]->const_array();,
1277 const auto bz = bcoef[2]->const_array(););
1278 AMREX_D_TERM(const auto& fxarr = flux[0]->array();,
1279 const auto& fyarr = flux[1]->array();,
1280 const auto& fzarr = flux[2]->array(););
1281 const auto& solarr = sol.array();
1282
1283 if (face_only)
1284 {
1285 RT fac = bscalar*static_cast<RT>(dxinv[0]);
1286 Box blo = amrex::bdryLo(box, 0);
1287 int blen = box.length(0);
1289 {
1290 mlabeclap_flux_xface(tbox, fxarr, solarr, bx, fac, blen, ncomp);
1291 });
1292#if (AMREX_SPACEDIM >= 2)
1293 fac = bscalar*static_cast<RT>(dxinv[1]);
1294 blo = amrex::bdryLo(box, 1);
1295 blen = box.length(1);
1297 {
1298 mlabeclap_flux_yface(tbox, fyarr, solarr, by, fac, blen, ncomp);
1299 });
1300#endif
1301#if (AMREX_SPACEDIM == 3)
1302 fac = bscalar*static_cast<RT>(dxinv[2]);
1303 blo = amrex::bdryLo(box, 2);
1304 blen = box.length(2);
1306 {
1307 mlabeclap_flux_zface(tbox, fzarr, solarr, bz, fac, blen, ncomp);
1308 });
1309#endif
1310 }
1311 else
1312 {
1313 RT fac = bscalar*static_cast<RT>(dxinv[0]);
1314 Box bflux = amrex::surroundingNodes(box, 0);
1316 {
1317 mlabeclap_flux_x(tbox, fxarr, solarr, bx, fac, ncomp);
1318 });
1319#if (AMREX_SPACEDIM >= 2)
1320 fac = bscalar*static_cast<RT>(dxinv[1]);
1321 bflux = amrex::surroundingNodes(box, 1);
1323 {
1324 mlabeclap_flux_y(tbox, fyarr, solarr, by, fac, ncomp);
1325 });
1326#endif
1327#if (AMREX_SPACEDIM == 3)
1328 fac = bscalar*static_cast<RT>(dxinv[2]);
1329 bflux = amrex::surroundingNodes(box, 2);
1331 {
1332 mlabeclap_flux_z(tbox, fzarr, solarr, bz, fac, ncomp);
1333 });
1334#endif
1335 }
1336}
1337
1338template <typename MF>
1339void
1340MLABecLaplacianT<MF>::normalize (int amrlev, int mglev, MF& mf) const
1341{
1342 BL_PROFILE("MLABecLaplacian::normalize()");
1343
1344 const auto& acoef = m_a_coeffs[amrlev][mglev];
1345 AMREX_D_TERM(const auto& bxcoef = m_b_coeffs[amrlev][mglev][0];,
1346 const auto& bycoef = m_b_coeffs[amrlev][mglev][1];,
1347 const auto& bzcoef = m_b_coeffs[amrlev][mglev][2];);
1348
1349 const GpuArray<RT,AMREX_SPACEDIM> dxinv
1350 {AMREX_D_DECL(static_cast<RT>(this->m_geom[amrlev][mglev].InvCellSize(0)),
1351 static_cast<RT>(this->m_geom[amrlev][mglev].InvCellSize(1)),
1352 static_cast<RT>(this->m_geom[amrlev][mglev].InvCellSize(2)))};
1353
1354 const RT ascalar = m_a_scalar;
1355 const RT bscalar = m_b_scalar;
1356
1357 const int ncomp = getNComp();
1358
1359#ifdef AMREX_USE_GPU
1360 if (Gpu::inLaunchRegion()) {
1361 const auto& ma = mf.arrays();
1362 const auto& ama = acoef.const_arrays();
1363 AMREX_D_TERM(const auto& bxma = bxcoef.const_arrays();,
1364 const auto& byma = bycoef.const_arrays();,
1365 const auto& bzma = bzcoef.const_arrays(););
1366 ParallelFor(mf, IntVect(0), ncomp,
1367 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
1368 {
1369 mlabeclap_normalize(i,j,k,n, ma[box_no], ama[box_no],
1370 AMREX_D_DECL(bxma[box_no],byma[box_no],bzma[box_no]),
1371 dxinv, ascalar, bscalar);
1372 });
1373 if (!Gpu::inNoSyncRegion()) {
1375 }
1376 } else
1377#endif
1378 {
1379#ifdef AMREX_USE_OMP
1380#pragma omp parallel if (Gpu::notInLaunchRegion())
1381#endif
1382 for (MFIter mfi(mf, TilingIfNotGPU()); mfi.isValid(); ++mfi)
1383 {
1384 const Box& bx = mfi.tilebox();
1385 const auto& fab = mf.array(mfi);
1386 const auto& afab = acoef.array(mfi);
1387 AMREX_D_TERM(const auto& bxfab = bxcoef.array(mfi);,
1388 const auto& byfab = bycoef.array(mfi);,
1389 const auto& bzfab = bzcoef.array(mfi););
1390
1391 AMREX_HOST_DEVICE_PARALLEL_FOR_4D(bx, ncomp, i, j, k, n,
1392 {
1393 mlabeclap_normalize(i,j,k,n, fab, afab, AMREX_D_DECL(bxfab,byfab,bzfab),
1394 dxinv, ascalar, bscalar);
1395 });
1396 }
1397 }
1398}
1399
1400template <typename MF>
1401bool
1403{
1404 bool support = false;
1405 if (this->m_overset_mask[0][0]) {
1406 if (this->m_geom[0].back().Domain().coarsenable(MLLinOp::mg_coarsen_ratio,
1407 this->mg_domain_min_width)
1408 && this->m_grids[0].back().coarsenable(MLLinOp::mg_coarsen_ratio, MLLinOp::mg_box_min_width))
1409 {
1410 support = true;
1411 }
1412 }
1413 return support;
1414}
1415
1416template <typename MF>
1417std::unique_ptr<MLLinOpT<MF>>
1418MLABecLaplacianT<MF>::makeNLinOp (int /*grid_size*/) const
1419{
1420 if (this->m_overset_mask[0][0] == nullptr) { return nullptr; }
1421
1422 const Geometry& geom = this->m_geom[0].back();
1423 const BoxArray& ba = this->m_grids[0].back();
1424 const DistributionMapping& dm = this->m_dmap[0].back();
1425
1426 std::unique_ptr<MLLinOpT<MF>> r
1427 {new MLABecLaplacianT<MF>({geom}, {ba}, {dm}, this->m_lpinfo_arg, {}, m_ncomp)};
1428
1429 auto nop = dynamic_cast<MLABecLaplacianT<MF>*>(r.get());
1430 if (!nop) {
1431 return nullptr;
1432 }
1433
1434 nop->m_parent = this;
1435
1436 nop->setMaxOrder(this->maxorder);
1437 nop->setVerbose(this->verbose);
1438
1439 nop->setDomainBC(this->m_lobc, this->m_hibc);
1440
1441 if (this->needsCoarseDataForBC())
1442 {
1443 const Real* dx0 = this->m_geom[0][0].CellSize();
1444 RealVect fac(this->m_coarse_data_crse_ratio);
1445 fac *= Real(0.5);
1446 RealVect cbloc {AMREX_D_DECL(dx0[0]*fac[0], dx0[1]*fac[1], dx0[2]*fac[2])};
1447 nop->setCoarseFineBCLocation(cbloc);
1448 }
1449
1450 // Pinning the masked cells with a huge alpha below requires a nonzero
1451 // a-scalar. The parent's alpha does not contribute if its a-scalar is zero.
1452 const RT ascalar = (m_a_scalar == RT(0.0)) ? RT(1.0) : m_a_scalar;
1453 const RT afac = m_a_scalar / ascalar; // 1 unless m_a_scalar is zero
1454 nop->setScalars(ascalar, m_b_scalar);
1455
1456 MF const& alpha_bottom = m_a_coeffs[0].back();
1457 iMultiFab const& osm_bottom = *(this->m_overset_mask[0].back());
1458 const int ncomp = alpha_bottom.nComp();
1459 MF alpha(ba, dm, ncomp, 0, MFInfo().SetArena(The_Async_Arena()));
1460
1461 RT a_max = alpha_bottom.norminf(0, ncomp, IntVect(0), true, true);
1462 const int ncomp_b = m_b_coeffs[0].back()[0].nComp();
1463 AMREX_D_TERM(RT bx_max = m_b_coeffs[0].back()[0].norminf(0,ncomp_b,IntVect(0),true,true);,
1464 RT by_max = m_b_coeffs[0].back()[1].norminf(0,ncomp_b,IntVect(0),true,true);,
1465 RT bz_max = m_b_coeffs[0].back()[2].norminf(0,ncomp_b,IntVect(0),true,true));
1466 const GpuArray<RT,AMREX_SPACEDIM> dxinv
1467 {AMREX_D_DECL(static_cast<RT>(geom.InvCellSize(0)),
1468 static_cast<RT>(geom.InvCellSize(1)),
1469 static_cast<RT>(geom.InvCellSize(2)))};
1470 RT huge_alpha = RT(1.e30) *
1471 amrex::max(a_max*std::abs(m_a_scalar),
1472 AMREX_D_DECL(std::abs(m_b_scalar)*bx_max*dxinv[0]*dxinv[0],
1473 std::abs(m_b_scalar)*by_max*dxinv[1]*dxinv[1],
1474 std::abs(m_b_scalar)*bz_max*dxinv[2]*dxinv[2]));
1476
1477#ifdef AMREX_USE_GPU
1478 if (Gpu::inLaunchRegion() && alpha.isFusingCandidate()) {
1479 auto const& ama = alpha.arrays();
1480 auto const& abotma = alpha_bottom.const_arrays();
1481 auto const& mma = osm_bottom.const_arrays();
1482 ParallelFor(alpha, IntVect(0), ncomp,
1483 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
1484 {
1485 if (mma[box_no](i,j,k)) {
1486 ama[box_no](i,j,k,n) = afac*abotma[box_no](i,j,k,n);
1487 } else {
1488 ama[box_no](i,j,k,n) = huge_alpha;
1489 }
1490 });
1491 if (!Gpu::inNoSyncRegion()) {
1493 }
1494 } else
1495#endif
1496 {
1497#ifdef AMREX_USE_OMP
1498#pragma omp parallel if (Gpu::notInLaunchRegion())
1499#endif
1500 for (MFIter mfi(alpha,TilingIfNotGPU()); mfi.isValid(); ++mfi) {
1501 Box const& bx = mfi.tilebox();
1502 auto const& a = alpha.array(mfi);
1503 auto const& abot = alpha_bottom.const_array(mfi);
1504 auto const& m = osm_bottom.const_array(mfi);
1505 AMREX_HOST_DEVICE_PARALLEL_FOR_4D(bx, ncomp, i, j, k, n,
1506 {
1507 if (m(i,j,k)) {
1508 a(i,j,k,n) = afac*abot(i,j,k,n);
1509 } else {
1510 a(i,j,k,n) = huge_alpha;
1511 }
1512 });
1513 }
1514 }
1515
1516 nop->setACoeffs(0, alpha);
1517 nop->setBCoeffs(0, GetArrOfConstPtrs(m_b_coeffs[0].back()));
1518
1519 return r;
1520}
1521
1522template <typename MF>
1523void
1524MLABecLaplacianT<MF>::copyNSolveSolution (MF& dst, MF const& src) const
1525{
1526 if (this->m_overset_mask[0].back() == nullptr) { return; }
1527
1528 const int ncomp = dst.nComp();
1529
1530#ifdef AMREX_USE_GPU
1531 if (Gpu::inLaunchRegion() && dst.isFusingCandidate()) {
1532 auto const& dstma = dst.arrays();
1533 auto const& srcma = src.const_arrays();
1534 auto const& mma = this->m_overset_mask[0].back()->const_arrays();
1535 ParallelFor(dst, IntVect(0), ncomp,
1536 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
1537 {
1538 if (mma[box_no](i,j,k)) {
1539 dstma[box_no](i,j,k,n) = srcma[box_no](i,j,k,n);
1540 } else {
1541 dstma[box_no](i,j,k,n) = RT(0.0);
1542 }
1543 });
1544 if (!Gpu::inNoSyncRegion()) {
1546 }
1547 } else
1548#endif
1549 {
1550#ifdef AMREX_USE_OMP
1551#pragma omp parallel if (Gpu::notInLaunchRegion())
1552#endif
1553 for (MFIter mfi(dst,TilingIfNotGPU()); mfi.isValid(); ++mfi) {
1554 Box const& bx = mfi.tilebox();
1555 auto const& dfab = dst.array(mfi);
1556 auto const& sfab = src.const_array(mfi);
1557 auto const& m = this->m_overset_mask[0].back()->const_array(mfi);
1558 AMREX_HOST_DEVICE_PARALLEL_FOR_4D(bx, ncomp, i, j, k, n,
1559 {
1560 if (m(i,j,k)) {
1561 dfab(i,j,k,n) = sfab(i,j,k,n);
1562 } else {
1563 dfab(i,j,k,n) = RT(0.0);
1564 }
1565 });
1566 }
1567 }
1568}
1569
1570extern template class MLABecLaplacianT<MultiFab>;
1571
1574
1575}
1576
1577#endif
#define BL_PROFILE(a)
Definition AMReX_BLProfiler.H:562
#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
GpuArray< Real, 3 > beta
Definition AMReX_MLEBNodeFDLaplacian.cpp:1099
#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:681
__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:88
MultiArray4< typename FabArray< FAB >::value_type const > const_arrays() const noexcept
Read-only convenience wrapper equivalent to arrays() const.
Definition AMReX_FabArray.H:731
Array4< typename FabArray< FAB >::value_type const > const_array(const MFIter &mfi) const noexcept
Synonym for array(const MFIter&) that highlights read-only semantics.
Definition AMReX_FabArray.H:649
Abstract factory interface for creating, aliasing, and destroying FAB objects.
Definition AMReX_FabFactory.H:73
Rectangular problem domain geometry.
Definition AMReX_Geometry.H:85
__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:176
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:1251
void setACoeffs(int amrlev, const AMF &alpha)
Definition AMReX_MLABecLaplacian.H:393
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:684
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:420
MLABecLaplacianT< MF > & operator=(const MLABecLaplacianT< MF > &)=delete
bool supportRobinBC() const noexcept override
Definition AMReX_MLABecLaplacian.H:270
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:496
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:313
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:799
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:711
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:693
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:1340
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:964
std::unique_ptr< MLLinOpT< MF > > makeNLinOp(int) const final
Build the NSolve counterpart of this operator.
Definition AMReX_MLABecLaplacian.H:1418
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:375
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:517
void copyNSolveSolution(MF &dst, MF const &src) const final
Copy an NSolve solution from src to dst.
Definition AMReX_MLABecLaplacian.H:1524
bool supportNSolve() const override
Whether this operator supports NSolve.
Definition AMReX_MLABecLaplacian.H:1402
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:475
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:881
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:309
void update() override
Average coefficients/metrics when marked dirty.
Definition AMReX_MLCellABecLap.H:302
static constexpr int mg_coarsen_ratio
Definition AMReX_MLLinOp.H:878
static constexpr int mg_box_min_width
Definition AMReX_MLLinOp.H:879
const MLLinOpT< MF > * m_parent
Definition AMReX_MLLinOp.H:894
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:80
__host__ __device__ BoxND< dim > adjCellHi(const BoxND< dim > &b, int dir, int len=1) noexcept
Return the BoxND of length len adjacent to b on the high end along coordinate direction dir.
Definition AMReX_Box.H:1848
__host__ __device__ BoxND< dim > convert(const BoxND< dim > &b, const IntVectND< dim > &typ) noexcept
Return a copy of b converted to the nodal flags typ.
Definition AMReX_Box.H:1630
__host__ __device__ BoxND< dim > adjCellLo(const BoxND< dim > &b, int dir, int len=1) noexcept
Return the BoxND of length len adjacent to b on the low end along coordinate direction dir.
Definition AMReX_Box.H:1817
__host__ __device__ BoxND< dim > 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
Arena * The_Async_Arena()
Definition AMReX_Arena.cpp:825
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
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:1059
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
int nComp(FabArrayBase const &fa)
Convenience wrapper that forwards to fa.nComp().
Definition AMReX_FabArrayBase.cpp:2860
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)
Return the infinity norm, with an MPI maximum unless local is true.
Definition AMReX_FabArrayUtility.H:2262
__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
Definition AMReX_GpuDevice.H:574
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:73
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