diff --git a/Docs/sphinx_documentation/source/EB.rst b/Docs/sphinx_documentation/source/EB.rst index 0233abde0a5..446e7305e50 100644 --- a/Docs/sphinx_documentation/source/EB.rst +++ b/Docs/sphinx_documentation/source/EB.rst @@ -4,7 +4,6 @@ .. role:: fortran(code) :language: fortran - .. _sec:EB:ebinit: Initializing the Geometric Database @@ -387,6 +386,174 @@ testing cell types and getting neighbor information. For example end do end do +Small Cell Problem and Redistribution +===================================== + +First, we review finite volume discretizations with embedded boundaries as used by +AMReX-based applications. Then we illustrate the small cell problem. + +Finite Volume Discretizations +----------------------------- + +Consider a system of PDEs to advance a conserved quantity :math:`U` with fluxes +:math:`F`: + +.. math:: \frac{\partial U}{\partial t} + \nabla \cdot F = 0. + :label: eqn::hypsys + +A conservative, finite volume discretization starts with the divergence theorm + +.. math:: \int_V \nabla \cdot F dV = \int_{\partial V} F \cdot n dA. + +In an embedded boundary cell, the "conservative divergence" is discretized (as +:math:`D^c(F)`) as follows + +.. math:: + :label: eqn::ebdiv + + D^c(F) = \frac{1}{\kappa h} \left( \sum^D_{d = 1} + (F_{d, \mathrm{hi}} \, \alpha_{d, \mathrm{hi}} - F_{d, \mathrm{lo}}\, \alpha_{d, \mathrm{lo}}) + + F^{EB} \alpha^{EB} \right). + +Geometry is discretely represented by volumes (:math:`V = \kappa h^d`) and +apertures (:math:`A= \alpha h^{d-1}`), where :math:`h` is the (uniform) mesh +spacing at that AMR level, :math:`\kappa` is the volume fraction and +:math:`\alpha` are the area fractions. Without multivalued cells the volume +fractions, area fractions and cell and face centroids (see +:numref:`fig::volume`) are the only geometric information needed to compute +second-order fluxes centered at the face centroids, and to infer the +connectivity of the cells. Cells are connected if adjacent on the Cartesian +mesh, and only via coordinate-aligned faces on the mesh. If an aperture, +:math:`\alpha = 0`, between two cells, they are not directly connected to each +other. + +.. raw:: latex + + \begin{center} + +.. |a| image:: ./EB/areas_and_volumes.png + :width: 100% + +.. |b| image:: ./EB/eb_fluxes.png + :width: 100% + +.. _fig::volume: + +.. table:: Illustration of embedded boundary cutting a two-dimensional cell. + :align: center + + +-----------------------------------------------------+------------------------------------------------------+ + | |a| | |b| | + +-----------------------------------------------------+------------------------------------------------------+ + | | A typical two-dimensional uniform cell that is | | Fluxes in a cut cell. | + | | cut by the embedded boundary. The grey area | | | + | | represents the region excluded from the | | | + | | calculation. The portion of the cell faces | | | + | | faces (labelled with A) through which fluxes | | | + | | flow are the "uncovered" regions of the full | | | + | | cell faces. The volume (labelled V) is the | | | + | | uncovered region of the interior. | | | + +-----------------------------------------------------+------------------------------------------------------+ + +.. raw:: latex + + \end{center} + + +Small Cells And Stability +------------------------- + +In the context of time-explicit advance methods for, say hyperbolic +conservation laws, a naive discretization in time of :eq:`eqn::hypsys` using +:eq:`eqn::ebdiv`, + +.. math:: U^{n+1} = U^{n} - \delta t D^c(F) + +would have a time step constraint :math:`\delta t \sim h \kappa^{1/D}/V_m`, +which goes to zero as the size of the smallest volume fraction :math:`\kappa` in +the calculation. Since EB volume fractions can be arbitrarily small, this presents an +unacceptable constraint. This is the so-called "small cell problem," and AMReX-based +applications address it with redistribution methods. + +Flux Redistribution +----------------------------- + +Consider a conservative update in the form: + +.. math:: (\rho \phi)_t + \nabla \cdot ( \rho \phi u) = RHS + +For each valid cell in the domain, compute the conservative divergence, :math:`(\nabla \cdot F)^c` , +of the convective fluxes, :math:`F` + +.. math:: (\nabla \cdot {F})^c_i = \dfrac{1}{\mathcal{V}_i} \sum_{f=1}^{N_f} ({F}_f\cdot{n}_f) A_f + +Here :math:`N_f` is the number of faces of cell :math:`i`, :math:`\vec{n}_f` and :math:`A_f` +are the unit normal and area of the :math:`f` -th face respectively, +and :math:`\mathcal{V}_i` is the volume of cell :math:`i` given by + +.. math:: \mathcal{V}_i = (\Delta x \Delta y \Delta z)\cdot \mathcal{K}_i + +where :math:`\mathcal{K}_i` is the volume fraction of cell :math:`i` . + +Now, a conservative update can be written as + +.. math:: \frac{ \rho^{n+1} \phi^{n+1} - \rho^{n} \phi^{n} }{\Delta t} = - \nabla \cdot{F}^c + +For each cell cut by the EB geometry, compute the non-conservative update, :math:`\nabla \cdot {F}^{nc}` , + +.. math:: \nabla\cdot{F}^{nc}_i = \dfrac{\sum\limits_{j\in N(i) } \mathcal{K}_j\nabla \cdot {F}^c_j} {\sum\limits_{j\in N(i) } {\mathcal{K}}_j} + +where :math:`N(i)` is the index set of cell :math:`i` and its neighbors. + +For each cell cut by the EB geometry, compute the convective update :math:`\nabla \cdot{F}^{EB}` follows: + +.. math:: \nabla \cdot{F}^{EB}_i = \mathcal{K}_i\nabla \cdot{F}^{c}_i +(1-\mathcal{K}_i) \nabla \cdot \mathcal{F}^{nc}_i + +For each cell cut by the EB geometry, redistribute its mass loss, :math:`\delta M_i` , to its neighbors: + +.. math:: \nabla \cdot {F}^{EB}_j := \nabla \cdot {F}^{EB}_j + w_{ij}\delta M_i\, \qquad \forall j\in N(i)\setminus i + +where the mass loss in cell :math:`i` , :math:`\delta M_i` , is given by + +.. math:: \delta M_i = \mathcal{K}_i(1- \mathcal{K}_i)[ \nabla \cdot {F}^c_i- \nabla \cdot {F}^{nc}_i] + +and the weights, :math:`w_{ij}` , are + +.. math:: w_{ij} = \dfrac{1}{\sum\limits_{j\in N(i)\setminus i} \mathcal{K}_j} + +Note that :math:`\nabla \cdot{F}_i^{EB}` gives an update for :math:`\rho \phi` ; i.e., + +.. math:: \frac{(\rho \phi_i)^{n+1} - (\rho \phi_i)^{n} }{\Delta t} = - \nabla \cdot{F}^{EB}_i + +Typically, the redistribution neighborhood for each cell is one that can be +reached via a monotonic path in each coordinate direction of unit length (see, +e.g., :numref:`fig::redistribution`) + +.. raw:: latex + + \begin{center} + +.. _fig::redistribution: + +.. figure:: ./EB/redist.png + :width: 50.0% + + : Redistribution illustration. Excess update distributed to neighbor cells. + +.. raw:: latex + + \end{center} + + +State Redistribution +----------------------------- + +For state redistribution we implement the weighted state +redistribution algorithm as described in Guiliani et al (2021), +which is available on `arxiv `_ . +This is an extension of the original state redistribution algorithm +of Berger and Guiliani (2020). + Linear Solvers ============== diff --git a/Docs/sphinx_documentation/source/EB/areas_and_volumes.fig b/Docs/sphinx_documentation/source/EB/areas_and_volumes.fig new file mode 100644 index 00000000000..9bad4537b26 --- /dev/null +++ b/Docs/sphinx_documentation/source/EB/areas_and_volumes.fig @@ -0,0 +1,69 @@ +#FIG 3.2 Produced by xfig version 3.2.5c +Landscape +Center +Metric +A4 +100.00 +Single +-2 +1200 2 +2 2 0 7 0 7 14 -1 -1 0.000 0 0 -1 0 0 5 + 1800 1800 5400 1800 5400 5400 1800 5400 1800 1800 +2 1 0 7 0 7 14 -1 15 0.000 0 0 -1 0 0 4 + 1800 2925 4275 5400 1800 5400 1800 2925 +2 1 0 3 0 7 14 -1 -1 0.000 0 0 -1 0 0 2 + 4230 5580 4230 6570 +2 1 0 3 0 7 14 -1 -1 0.000 0 0 -1 0 0 2 + 5400 5625 5400 6525 +2 1 0 3 0 7 14 -1 -1 0.000 0 0 -1 0 0 2 + 5625 1800 7650 1800 +2 1 0 3 0 7 14 -1 -1 0.000 0 0 -1 0 0 2 + 5625 5400 7650 5400 +2 1 0 3 0 7 14 -1 -1 0.000 0 0 -1 0 0 2 + 1575 1800 225 1800 +2 1 0 3 0 7 14 -1 -1 0.000 0 0 -1 0 0 2 + 1575 2925 225 2925 +2 1 0 3 0 7 14 -1 -1 0.000 0 0 -1 0 0 2 + 1800 1575 1800 450 +2 1 0 3 0 7 14 -1 -1 0.000 0 0 -1 0 0 2 + 5400 1575 5400 225 +2 1 0 3 0 7 14 -1 -1 0.000 0 0 -1 0 0 2 + 1852 2845 2430 2340 +2 1 0 3 0 7 14 -1 -1 0.000 0 0 -1 0 0 2 + 4372 5275 4950 4770 +2 1 0 3 0 7 14 -1 -1 0.000 0 0 -1 1 0 2 + 1 1 5.00 135.00 165.00 + 3060 3510 2160 2610 +2 1 0 3 0 7 14 -1 -1 0.000 0 0 -1 1 0 2 + 1 1 5.00 135.00 165.00 + 3690 4140 4590 5040 +2 1 0 3 0 7 14 -1 -1 0.000 0 0 -1 1 0 2 + 1 1 5.00 135.00 165.00 + 3420 6120 4230 6120 +2 1 0 3 0 7 14 -1 -1 0.000 0 0 -1 1 0 2 + 1 1 5.00 135.00 165.00 + 6300 6120 5400 6120 +2 1 0 3 0 7 14 -1 -1 0.000 0 0 -1 1 0 2 + 1 1 5.00 135.00 165.00 + 6300 3420 6300 1890 +2 1 0 3 0 7 14 -1 -1 0.000 0 0 -1 1 0 2 + 1 1 5.00 135.00 165.00 + 6300 4140 6300 5400 +2 1 0 3 0 7 14 -1 -1 0.000 0 0 -1 1 0 2 + 1 1 5.00 135.00 165.00 + 810 990 810 1890 +2 1 0 3 0 7 14 -1 -1 0.000 0 0 -1 1 0 2 + 1 1 5.00 135.00 165.00 + 810 3690 810 2970 +2 1 0 3 0 7 14 -1 -1 0.000 0 0 -1 1 0 2 + 1 1 5.00 135.00 165.00 + 3060 1170 1800 1170 +2 1 0 3 0 7 14 -1 -1 0.000 0 0 -1 1 0 2 + 1 1 5.00 135.00 165.00 + 4050 1170 5400 1170 +4 0 0 14 -1 18 18 0.0000 4 270 375 4500 6210 Ay\001 +4 0 0 14 -1 18 18 0.0000 4 210 375 6120 3780 Ax\001 +4 0 0 14 -1 18 18 0.0000 4 270 375 3330 1260 Ay\001 +4 0 0 14 -1 18 18 0.0000 4 210 375 720 2340 Ax\001 +4 0 0 14 -1 18 18 0.0000 4 210 555 3150 3780 Aeb\001 +4 0 0 14 -1 18 18 0.0000 4 210 195 3780 2790 V\001 diff --git a/Docs/sphinx_documentation/source/EB/areas_and_volumes.png b/Docs/sphinx_documentation/source/EB/areas_and_volumes.png new file mode 100644 index 00000000000..1794b4dcf26 Binary files /dev/null and b/Docs/sphinx_documentation/source/EB/areas_and_volumes.png differ diff --git a/Docs/sphinx_documentation/source/EB/eb_fluxes.fig b/Docs/sphinx_documentation/source/EB/eb_fluxes.fig new file mode 100644 index 00000000000..8274e120a68 --- /dev/null +++ b/Docs/sphinx_documentation/source/EB/eb_fluxes.fig @@ -0,0 +1,38 @@ +#FIG 3.2 Produced by xfig version 3.2.5c +Landscape +Center +Metric +A4 +100.00 +Single +-2 +1200 2 +2 2 0 7 0 7 14 -1 -1 0.000 0 0 -1 0 0 5 + 1800 1800 5400 1800 5400 5400 1800 5400 1800 1800 +2 1 0 7 0 7 14 -1 15 0.000 0 0 -1 0 0 4 + 1800 2925 4275 5400 1800 5400 1800 2925 +2 1 0 4 0 7 14 -1 -1 0.000 0 0 -1 1 0 2 + 1 1 5.00 135.00 165.00 + 2925 4275 4050 3150 +2 1 0 4 0 7 14 -1 -1 0.000 0 0 -1 1 0 2 + 1 1 5.00 135.00 165.00 + 720 2475 2745 2475 +2 1 0 4 0 7 14 -1 -1 0.000 0 0 -1 1 0 2 + 1 1 5.00 135.00 165.00 + 4725 6435 4725 4410 +2 1 0 4 0 7 14 -1 -1 0.000 0 0 -1 1 0 2 + 1 1 5.00 135.00 165.00 + 4725 3600 6525 3600 +2 1 0 4 0 7 14 -1 -1 0.000 0 0 -1 1 0 2 + 1 1 5.00 135.00 165.00 + 3600 2475 3600 450 +4 0 0 14 -1 18 28 0.0000 4 345 285 4050 900 F\001 +4 0 0 14 -1 18 28 0.0000 4 345 285 4050 3150 F\001 +4 0 0 14 -1 18 18 0.0000 4 210 405 4320 3240 EB\001 +4 0 0 14 -1 18 18 0.0000 4 270 930 4320 990 Y, high\001 +4 0 0 14 -1 18 28 0.0000 4 345 285 -270 2475 F\001 +4 0 0 14 -1 18 18 0.0000 4 255 735 45 2520 X,low\001 +4 0 0 14 -1 18 28 0.0000 4 345 285 4455 6885 F\001 +4 0 0 14 -1 18 18 0.0000 4 255 825 4725 6975 Y, low\001 +4 0 0 14 -1 18 18 0.0000 4 270 840 6930 3915 X,high\001 +4 0 0 14 -1 18 28 0.0000 4 345 285 6660 3825 F\001 diff --git a/Docs/sphinx_documentation/source/EB/eb_fluxes.png b/Docs/sphinx_documentation/source/EB/eb_fluxes.png new file mode 100644 index 00000000000..1af57732bed Binary files /dev/null and b/Docs/sphinx_documentation/source/EB/eb_fluxes.png differ diff --git a/Docs/sphinx_documentation/source/EB/redist.fig b/Docs/sphinx_documentation/source/EB/redist.fig new file mode 100644 index 00000000000..7751cd12f07 --- /dev/null +++ b/Docs/sphinx_documentation/source/EB/redist.fig @@ -0,0 +1,41 @@ +#FIG 3.2 Produced by xfig version 3.2.5c +Landscape +Center +Metric +A4 +100.00 +Single +-2 +1200 2 +2 1 0 5 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 1800 1755 1800 9900 +2 1 0 5 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 3600 1755 3600 9900 +2 1 0 5 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 5400 1755 5400 9900 +2 1 0 5 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 7200 1755 7200 9900 +2 1 0 5 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 0 1755 0 9900 +2 1 0 5 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 8100 6300 0 6300 +2 1 0 5 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 8325 4500 0 4500 +2 1 0 5 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 8550 2700 0 2700 +2 1 0 5 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 7875 9900 0 9900 +2 1 0 7 0 7 56 -1 12 0.000 0 0 -1 0 0 11 + 0 2925 0 9900 7650 9900 7200 9000 6300 8100 5400 7650 + 3600 7200 2475 6300 1800 5175 1350 4500 0 2925 +2 1 0 5 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 8100 8100 0 8100 +2 1 0 3 0 7 56 -1 -1 0.000 0 0 -1 1 0 2 + 0 0 3.00 180.00 360.00 + 3150 6750 2700 5400 +2 1 0 3 0 7 56 -1 -1 0.000 0 0 -1 1 0 2 + 0 0 3.00 180.00 360.00 + 3150 6750 4500 5175 +2 1 0 3 0 7 56 -1 -1 0.000 0 0 -1 1 0 2 + 0 0 3.00 180.00 360.00 + 3150 6750 4725 6750 diff --git a/Docs/sphinx_documentation/source/EB/redist.png b/Docs/sphinx_documentation/source/EB/redist.png new file mode 100644 index 00000000000..88d0f9a7711 Binary files /dev/null and b/Docs/sphinx_documentation/source/EB/redist.png differ diff --git a/Docs/sphinx_documentation/source/LinearSolvers.rst b/Docs/sphinx_documentation/source/LinearSolvers.rst index ec585f1925e..63694474e99 100644 --- a/Docs/sphinx_documentation/source/LinearSolvers.rst +++ b/Docs/sphinx_documentation/source/LinearSolvers.rst @@ -509,7 +509,7 @@ passed to the constructor of a linear operator to disable the coarsening completely. In that case the bottom solver is solving the residual correction form of the original problem. To build Hypre, follow the next steps: -.. highlight:: c++ +.. highlight:: console :: @@ -577,7 +577,7 @@ The user is referred to the AMReX can also use `PETSc `_ as a bottom solver for cell-centered problems. To build PETSc, follow the next steps: -.. highlight:: c++ +.. highlight:: console :: diff --git a/Src/Base/AMReX_FArrayBox.H b/Src/Base/AMReX_FArrayBox.H index 37c16af40dd..45e49ebab93 100644 --- a/Src/Base/AMReX_FArrayBox.H +++ b/Src/Base/AMReX_FArrayBox.H @@ -3,13 +3,9 @@ #define BL_FARRAYBOX_H #include -#include #include #include -#include -#include #include -#include namespace amrex { diff --git a/Src/Base/AMReX_Slopes_K.H b/Src/Base/AMReX_Slopes_K.H new file mode 100644 index 00000000000..325a9b05629 --- /dev/null +++ b/Src/Base/AMReX_Slopes_K.H @@ -0,0 +1,427 @@ +#ifndef AMREX_SLOPES_K_H_ +#define AMREX_SLOPES_K_H_ +#include + +#include + +namespace amrex { + +AMREX_GPU_DEVICE AMREX_FORCE_INLINE +Real amrex_calc_xslope (int i, int j, int k, int n, int order, + amrex::Array4 const& q) noexcept +{ + if (order == 2) + { + Real dl = 2.0_rt*(q(i ,j,k,n) - q(i-1,j,k,n)); + Real dr = 2.0_rt*(q(i+1,j,k,n) - q(i ,j,k,n)); + Real dc = 0.5_rt*(q(i+1,j,k,n) - q(i-1,j,k,n)); + Real slope = amrex::min(std::abs(dl),std::abs(dc),std::abs(dr)); + slope = (dr*dl > 0.0_rt) ? slope : 0.0_rt; + return (dc > 0.0_rt) ? slope : -slope; + + } else if (order == 4) { + + Real dlft, drgt, dcen, dfm, dfp, dlim, dsgn, dtemp; + Real qm, qp, qi; + qi = q(i,j,k,n); + qm = q(i-1,j,k,n); + qp = q(i+1,j,k,n); + + dlft = qm - q(i-2,j,k,n); + drgt = qi - qm; + dcen = 0.5_rt*(dlft+drgt); + dsgn = std::copysign(1.e0_rt, dcen); + dlim = (dlft*drgt >= 0.0_rt) ? 2.0_rt*amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + dfm = dsgn*amrex::min(dlim, std::abs(dcen)); + + dlft = qp - qi; + drgt = q(i+2,j,k,n) - qp; + dcen = 0.5_rt*(dlft+drgt); + dsgn = std::copysign(1.e0_rt, dcen); + dlim = (dlft*drgt >= 0.0_rt) ? 2.0_rt*amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + dfp = dsgn*amrex::min(dlim, std::abs(dcen)); + + dlft = qi - qm; + drgt = qp - qi; + dcen = 0.5_rt*(dlft+drgt); + dsgn = std::copysign(1.e0_rt, dcen); + dlim = (dlft*drgt >= 0.0_rt) ? 2.0_rt*amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + + dtemp = 4.0_rt/3.0_rt*dcen - 1.0_rt/6.0_rt*(dfp + dfm); + + return dsgn*amrex::min(dlim, std::abs(dtemp)); + + } else { + return 0._rt; + } +} + +AMREX_GPU_DEVICE AMREX_FORCE_INLINE +Real amrex_calc_xslope_extdir (int i, int j, int k, int n, int order, + amrex::Array4 const& q, + bool edlo, bool edhi, int domlo, int domhi) noexcept +{ + if (order == 2) + { + Real dl = 2.0_rt*(q(i ,j,k,n) - q(i-1,j,k,n)); + Real dr = 2.0_rt*(q(i+1,j,k,n) - q(i ,j,k,n)); + Real dc = 0.5_rt*(q(i+1,j,k,n) - q(i-1,j,k,n)); + + if (edlo && i == domlo) { + dc = (q(i+1,j,k,n)+3.0_rt*q(i,j,k,n)-4.0_rt*q(i-1,j,k,n))/3.0_rt; + } else if (edhi && i == domhi) { + dc = (4.0_rt*q(i+1,j,k,n)-3.0_rt*q(i,j,k,n)-q(i-1,j,k,n))/3.0_rt; + } + + Real slope = amrex::min(std::abs(dl),std::abs(dc),std::abs(dr)); + slope = (dr*dl > 0.0_rt) ? slope : 0.0_rt; + return (dc > 0.0_rt) ? slope : -slope; + + } else if (order == 4) { + + Real dlft, drgt, dcen, dfm, dfp, dlim, dsgn, dtemp, dlimsh, dsgnsh; + Real qm, qp, qi; + qi = q(i,j,k,n); + qm = q(i-1,j,k,n); + qp = q(i+1,j,k,n); + + dlft = qm - q(i-2,j,k,n); + drgt = qi - qm; + dcen = 0.5_rt*(dlft+drgt); + dsgn = std::copysign(1.e0_rt, dcen); + dlim = (dlft*drgt >= 0.0_rt) ? 2.0_rt*amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + dfm = dsgn*amrex::min(dlim, std::abs(dcen)); + + dlft = qp - qi; + drgt = q(i+2,j,k,n) - qp; + dcen = 0.5_rt*(dlft+drgt); + dsgn = std::copysign(1.e0_rt, dcen); + dlim = (dlft*drgt >= 0.0_rt) ? 2.0_rt*amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + dfp = dsgn*amrex::min(dlim, std::abs(dcen)); + + dlft = qi - qm; + drgt = qp - qi; + dcen = 0.5_rt*(dlft+drgt); + dsgn = std::copysign(1.e0_rt, dcen); + dlim = (dlft*drgt >= 0.0_rt) ? 2.0_rt*amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + + dtemp = 4.0_rt/3.0_rt*dcen - 1.0_rt/6.0_rt*(dfp + dfm); + + if (edlo && i == domlo) { + dtemp = -16._rt/15._rt*q(i-1,j,k,n) + .5_rt*q(i,j,k,n) + 2._rt/3._rt*q(i+1,j,k,n) - 0.1_rt*q(i+2,j,k,n); + dlft = 2._rt*(q(i ,j,k,n)-q(i-1,j,k,n)); + drgt = 2._rt*(q(i+1,j,k,n)-q(i ,j,k,n)); + dlim = (dlft*drgt >= 0.0_rt) ? amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + dsgn = std::copysign(1.e0_rt, dtemp); + } else if (edlo && i == domlo+1) { + dfm = -16._rt/15._rt*q(domlo-1,j,k,n) + .5_rt*q(domlo,j,k,n) + 2._rt/3._rt*q(domlo+1,j,k,n) - 0.1_rt*q(domlo+2,j,k,n); + dlft = 2._rt*(q(domlo ,j,k,n)-q(domlo-1,j,k,n)); + drgt = 2._rt*(q(domlo+1,j,k,n)-q(domlo ,j,k,n)); + dlimsh = (dlft*drgt >= 0.0_rt) ? amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + dsgnsh = std::copysign(1.e0_rt, dfm); + dfm = dsgnsh*amrex::min(dlimsh, std::abs(dfm)); + dtemp = 4.0_rt/3.0_rt*dcen - 1.0_rt/6.0_rt*(dfp + dfm); + } + + if (edhi && i == domhi) { + dtemp = 16._rt/15._rt*q(i+1,j,k,n) - .5_rt*q(i,j,k,n) - 2._rt/3._rt*q(i-1,j,k,n) + 0.1_rt*q(i-2,j,k,n); + dlft = 2._rt*(q(i ,j,k,n)-q(i-1,j,k,n)); + drgt = 2._rt*(q(i+1,j,k,n)-q(i ,j,k,n)); + dlim = (dlft*drgt >= 0.0_rt) ? amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + dsgn = std::copysign(1.e0_rt, dtemp); + } else if (edhi && i == domhi-1) { + dfp = 16._rt/15._rt*q(domhi+1,j,k,n) - .5_rt*q(domhi,j,k,n) - 2._rt/3._rt*q(domhi-1,j,k,n) + 0.1_rt*q(domhi-2,j,k,n); + dlft = 2._rt*(q(domhi ,j,k,n)-q(domhi-1,j,k,n)); + drgt = 2._rt*(q(domhi+1,j,k,n)-q(domhi ,j,k,n)); + dlimsh = (dlft*drgt >= 0.0_rt) ? amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + dsgnsh = std::copysign(1.e0_rt, dfp); + dfp = dsgnsh*amrex::min(dlimsh, std::abs(dfp)); + dtemp = 4.0_rt/3.0_rt*dcen - 1.0_rt/6.0_rt*(dfp + dfm); + } + + return dsgn*amrex::min(dlim, std::abs(dtemp)); + + } else { + return 0._rt; + } + +} + +AMREX_GPU_DEVICE AMREX_FORCE_INLINE +Real amrex_calc_yslope (int i, int j, int k, int n, int order, + amrex::Array4 const& q) noexcept +{ + if (order == 2) + { + Real dl = 2.0_rt*(q(i,j ,k,n) - q(i,j-1,k,n)); + Real dr = 2.0_rt*(q(i,j+1,k,n) - q(i,j ,k,n)); + Real dc = 0.5_rt*(q(i,j+1,k,n) - q(i,j-1,k,n)); + Real slope = amrex::min(std::abs(dl),std::abs(dc),std::abs(dr)); + slope = (dr*dl > 0.0_rt) ? slope : 0.0_rt; + return (dc > 0.0_rt) ? slope : -slope; + + } else if (order == 4) { + + Real dlft, drgt, dcen, dfm, dfp, dlim, dsgn, dtemp; + Real qm, qp, qj; + qj = q(i,j,k,n); + qm = q(i,j-1,k,n); + qp = q(i,j+1,k,n); + + dlft = qm - q(i,j-2,k,n); + drgt = qj - qm; + dcen = 0.5_rt*(dlft+drgt); + dsgn = std::copysign(1.e0_rt, dcen); + dlim = (dlft*drgt >= 0.0_rt) ? 2.0_rt*amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + dfm = dsgn*amrex::min(dlim, std::abs(dcen)); + + dlft = qp - qj; + drgt = q(i,j+2,k,n) - qp; + dcen = 0.5_rt*(dlft+drgt); + dsgn = std::copysign(1.e0_rt, dcen); + dlim = (dlft*drgt >= 0.0_rt) ? 2.0_rt*amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + dfp = dsgn*amrex::min(dlim, std::abs(dcen)); + + dlft = qj - qm; + drgt = qp - qj; + dcen = 0.5_rt*(dlft+drgt); + dsgn = std::copysign(1.e0_rt, dcen); + dlim = (dlft*drgt >= 0.0_rt) ? 2.0_rt*amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + + dtemp = 4.0_rt/3.0_rt*dcen - 1.0_rt/6.0_rt*(dfp + dfm); + return dsgn*amrex::min(dlim, std::abs(dtemp)); + + } else { + return 0._rt; + } +} + +AMREX_GPU_DEVICE AMREX_FORCE_INLINE +Real amrex_calc_yslope_extdir (int i, int j, int k, int n, int order, + amrex::Array4 const& q, + bool edlo, bool edhi, int domlo, int domhi) noexcept +{ + if (order == 2) + { + Real dl = 2.0_rt*(q(i,j ,k,n) - q(i,j-1,k,n)); + Real dr = 2.0_rt*(q(i,j+1,k,n) - q(i,j ,k,n)); + Real dc = 0.5_rt*(q(i,j+1,k,n) - q(i,j-1,k,n)); + if (edlo && j == domlo) { + dc = (q(i,j+1,k,n)+3.0_rt*q(i,j,k,n)-4.0_rt*q(i,j-1,k,n))/3.0_rt; + } else if (edhi && j == domhi) { + dc = (4.0_rt*q(i,j+1,k,n)-3.0_rt*q(i,j,k,n)-q(i,j-1,k,n))/3.0_rt; + } + Real slope = amrex::min(std::abs(dl),std::abs(dc),std::abs(dr)); + slope = (dr*dl > 0.0_rt) ? slope : 0.0_rt; + return (dc > 0.0_rt) ? slope : -slope; + + } else if (order == 4) { + + Real dlft, drgt, dcen, dfm, dfp, dlim, dsgn, dtemp, dlimsh,dsgnsh; + Real qm, qp, qj; + qj = q(i,j,k,n); + qm = q(i,j-1,k,n); + qp = q(i,j+1,k,n); + + dlft = qm - q(i,j-2,k,n); + drgt = qj - qm; + dcen = 0.5_rt*(dlft+drgt); + dsgn = std::copysign(1.e0_rt, dcen); + dlim = (dlft*drgt >= 0.0_rt) ? 2.0_rt*amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + dfm = dsgn*amrex::min(dlim, std::abs(dcen)); + + dlft = qp - qj; + drgt = q(i,j+2,k,n) - qp; + dcen = 0.5_rt*(dlft+drgt); + dsgn = std::copysign(1.e0_rt, dcen); + dlim = (dlft*drgt >= 0.0_rt) ? 2.0_rt*amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + dfp = dsgn*amrex::min(dlim, std::abs(dcen)); + + dlft = qj - qm; + drgt = qp - qj; + dcen = 0.5_rt*(dlft+drgt); + dsgn = std::copysign(1.e0_rt, dcen); + dlim = (dlft*drgt >= 0.0_rt) ? 2.0_rt*amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + + dtemp = 4.0_rt/3.0_rt*dcen - 1.0_rt/6.0_rt*(dfp + dfm); + + if (edlo && j == domlo) { + dtemp = -16._rt/15._rt*q(i,j-1,k,n) + .5_rt*q(i,j,k,n) + 2._rt/3._rt*q(i,j+1,k,n) - 0.1_rt*q(i,j+2,k,n); + dlft = 2._rt*(q(i ,j,k,n)-q(i,j-1,k,n)); + drgt = 2._rt*(q(i,j+1,k,n)-q(i ,j,k,n)); + dlim = (dlft*drgt >= 0.0_rt) ? amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + dsgn = std::copysign(1.e0_rt, dtemp); + } else if (edlo && j == domlo+1) { + dfm = -16._rt/15._rt*q(i,domlo-1,k,n) + .5_rt*q(i,domlo,k,n) + 2._rt/3._rt*q(i,domlo+1,k,n) - 0.1_rt*q(i,domlo+2,k,n); + dlft = 2._rt*(q(i ,domlo,k,n)-q(i,domlo-1,k,n)); + drgt = 2._rt*(q(i,domlo+1,k,n)-q(i ,domlo,k,n)); + dlimsh = (dlft*drgt >= 0.0_rt) ? amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + dsgnsh = std::copysign(1.e0_rt, dfm); + dfm = dsgnsh*amrex::min(dlimsh, std::abs(dfm)); + dtemp = 4.0_rt/3.0_rt*dcen - 1.0_rt/6.0_rt*(dfp + dfm); + } + + if (edhi && j == domhi) { + dtemp = 16._rt/15._rt*q(i,j+1,k,n) - .5_rt*q(i,j,k,n) - 2._rt/3._rt*q(i,j-1,k,n) + 0.1_rt*q(i,j-2,k,n); + dlft = 2._rt*(q(i ,j,k,n)-q(i,j-1,k,n)); + drgt = 2._rt*(q(i,j+1,k,n)-q(i ,j,k,n)); + dlim = (dlft*drgt >= 0.0_rt) ? amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + dsgn = std::copysign(1.e0_rt, dtemp); + } else if (edhi && j == domhi-1) { + dfp = 16._rt/15._rt*q(i,domhi+1,k,n) - .5_rt*q(i,domhi,k,n) - 2._rt/3._rt*q(i,domhi-1,k,n) + 0.1_rt*q(i,domhi-2,k,n); + dlft = 2._rt*(q(i ,domhi,k,n)-q(i,domhi-1,k,n)); + drgt = 2._rt*(q(i,domhi+1,k,n)-q(i ,domhi,k,n)); + dlimsh = (dlft*drgt >= 0.0_rt) ? amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + dsgnsh = std::copysign(1.e0_rt, dfp); + dfp = dsgnsh*amrex::min(dlimsh, std::abs(dfp)); + dtemp = 4.0_rt/3.0_rt*dcen - 1.0_rt/6.0_rt*(dfp + dfm); + } + + return dsgn*amrex::min(dlim, std::abs(dtemp)); + + } else { + return 0._rt; + } +} + +#if (AMREX_SPACEDIM == 3) +AMREX_GPU_DEVICE AMREX_FORCE_INLINE +Real amrex_calc_zslope (int i, int j, int k, int n, int order, + amrex::Array4 const& q) noexcept +{ + if (order == 2) + { + Real dl = 2.0_rt*(q(i,j,k ,n) - q(i,j,k-1,n)); + Real dr = 2.0_rt*(q(i,j,k+1,n) - q(i,j,k ,n)); + Real dc = 0.5_rt*(q(i,j,k+1,n) - q(i,j,k-1,n)); + Real slope = amrex::min(std::abs(dl),std::abs(dc),std::abs(dr)); + slope = (dr*dl > 0.0_rt) ? slope : 0.0_rt; + return (dc > 0.0_rt) ? slope : -slope; + + } else if (order == 4) { + + Real dlft, drgt, dcen, dfm, dfp, dlim, dsgn, dtemp; + Real qm, qp, qk; + qk = q(i,j,k,n); + qm = q(i,j,k-1,n); + qp = q(i,j,k+1,n); + + dlft = qm - q(i,j,k-2,n); + drgt = qk - qm; + dcen = 0.5_rt*(dlft+drgt); + dsgn = std::copysign(1.e0_rt, dcen); + dlim = (dlft*drgt >= 0.0_rt) ? 2.0_rt*amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + dfm = dsgn*amrex::min(dlim, std::abs(dcen)); + + dlft = qp - qk; + drgt = q(i,j,k+2,n) - qp; + dcen = 0.5_rt*(dlft+drgt); + dsgn = std::copysign(1.e0_rt, dcen); + dlim = (dlft*drgt >= 0.0_rt) ? 2.0_rt*amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + dfp = dsgn*amrex::min(dlim, std::abs(dcen)); + + dlft = qk - qm; + drgt = qp - qk; + dcen = 0.5_rt*(dlft+drgt); + dsgn = std::copysign(1.e0_rt, dcen); + dlim = (dlft*drgt >= 0.0_rt) ? 2.0_rt*amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + + dtemp = 4.0_rt/3.0_rt*dcen - 1.0_rt/6.0_rt*(dfp + dfm); + return dsgn*amrex::min(dlim, std::abs(dtemp)); + + } else { + return 0._rt; + } +} + +AMREX_GPU_DEVICE AMREX_FORCE_INLINE +Real amrex_calc_zslope_extdir (int i, int j, int k, int n, int order, + amrex::Array4 const& q, + bool edlo, bool edhi, int domlo, int domhi) noexcept +{ + if (order == 2) + { + + Real dl = 2.0_rt*(q(i,j,k ,n) - q(i,j,k-1,n)); + Real dr = 2.0_rt*(q(i,j,k+1,n) - q(i,j,k ,n)); + Real dc = 0.5_rt*(q(i,j,k+1,n) - q(i,j,k-1,n)); + if (edlo && k == domlo) { + dc = (q(i,j,k+1,n)+3.0_rt*q(i,j,k,n)-4.0_rt*q(i,j,k-1,n))/3.0_rt; + } else if (edhi && k == domhi) { + dc = (4.0_rt*q(i,j,k+1,n)-3.0_rt*q(i,j,k,n)-q(i,j,k-1,n))/3.0_rt; + } + Real slope = amrex::min(std::abs(dl),std::abs(dc),std::abs(dr)); + slope = (dr*dl > 0.0_rt) ? slope : 0.0_rt; + return (dc > 0.0_rt) ? slope : -slope; + + } else if (order == 4) { + + Real dlft, drgt, dcen, dfm, dfp, dlim, dsgn, dtemp, dlimsh, dsgnsh; + Real qm, qp, qk; + qk = q(i,j,k,n); + qm = q(i,j,k-1,n); + qp = q(i,j,k+1,n); + + dlft = qm - q(i,j,k-2,n); + drgt = qk - qm; + dcen = 0.5_rt*(dlft+drgt); + dsgn = std::copysign(1.e0_rt, dcen); + dlim = (dlft*drgt >= 0.0_rt) ? 2.0_rt*amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + dfm = dsgn*amrex::min(dlim, std::abs(dcen)); + + dlft = qp - qk; + drgt = q(i,j,k+2,n) - qp; + dcen = 0.5_rt*(dlft+drgt); + dsgn = std::copysign(1.e0_rt, dcen); + dlim = (dlft*drgt >= 0.0_rt) ? 2.0_rt*amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + dfp = dsgn*amrex::min(dlim, std::abs(dcen)); + + dlft = qk - qm; + drgt = qp - qk; + dcen = 0.5_rt*(dlft+drgt); + dsgn = std::copysign(1.e0_rt, dcen); + dlim = (dlft*drgt >= 0.0_rt) ? 2.0_rt*amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + + dtemp = 4.0_rt/3.0_rt*dcen - 1.0_rt/6.0_rt*(dfp + dfm); + + if (edlo && k == domlo) { + dtemp = -16._rt/15._rt*q(i,j,k-1,n) + .5_rt*q(i,j,k,n) + 2._rt/3._rt*q(i,j,k+1,n) - 0.1_rt*q(i,j,k+2,n); + dlft = 2._rt*(q(i ,j,k,n)-q(i,j,k-1,n)); + drgt = 2._rt*(q(i,j,k+1,n)-q(i ,j,k,n)); + dlim = (dlft*drgt >= 0.0_rt) ? amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + dsgn = std::copysign(1.e0_rt, dtemp); + } else if (edlo && k == domlo+1) { + dfm = -16._rt/15._rt*q(i,j,domlo-1,n) + .5_rt*q(i,j,domlo,n) + 2._rt/3._rt*q(i,j,domlo+1,n) - 0.1_rt*q(i,j,domlo+2,n); + dlft = 2._rt*(q(i ,j,domlo,n)-q(i,j,domlo-1,n)); + drgt = 2._rt*(q(i,j,domlo+1,n)-q(i ,j,domlo,n)); + dlimsh = (dlft*drgt >= 0.0_rt) ? amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + dsgnsh = std::copysign(1.e0_rt, dfm); + dfm = dsgnsh*amrex::min(dlimsh, std::abs(dfm)); + dtemp = 4.0_rt/3.0_rt*dcen - 1.0_rt/6.0_rt*(dfp + dfm); + } + + if (edhi && k == domhi) { + dtemp = 16._rt/15._rt*q(i,j,k+1,n) - .5_rt*q(i,j,k,n) - 2._rt/3._rt*q(i,j,k-1,n) + 0.1_rt*q(i,j,k-2,n); + dlft = 2._rt*(q(i ,j,k,n)-q(i,j,k-1,n)); + drgt = 2._rt*(q(i,j,k+1,n)-q(i ,j,k,n)); + dlim = (dlft*drgt >= 0.0_rt) ? amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + dsgn = std::copysign(1.e0_rt, dtemp); + } else if (edhi && k == domhi-1) { + dfp = 16._rt/15._rt*q(i,j,domhi+1,n) - .5_rt*q(i,j,domhi,n) - 2._rt/3._rt*q(i,j,domhi-1,n) + 0.1_rt*q(i,j,domhi-2,n); + dlft = 2._rt*(q(i ,j,domhi,n)-q(i,j,domhi-1,n)); + drgt = 2._rt*(q(i,j,domhi+1,n)-q(i ,j,domhi,n)); + dlimsh = (dlft*drgt >= 0.0_rt) ? amrex::min(std::abs(dlft), std::abs(drgt)) : 0.0_rt; + dsgnsh = std::copysign(1.e0_rt, dfp); + dfp = dsgnsh*amrex::min(dlimsh, std::abs(dfp)); + dtemp = 4.0_rt/3.0_rt*dcen - 1.0_rt/6.0_rt*(dfp + dfm); + } + return dsgn*amrex::min(dlim, std::abs(dtemp)); + + } else { + return 0._rt; + } +} +#endif + +} +#endif diff --git a/Src/Base/CMakeLists.txt b/Src/Base/CMakeLists.txt index 42952dbc853..cb1a3cd9c95 100644 --- a/Src/Base/CMakeLists.txt +++ b/Src/Base/CMakeLists.txt @@ -267,6 +267,8 @@ foreach(D IN LISTS AMReX_SPACEDIM) Parser/amrex_iparser.tab.cpp Parser/amrex_iparser.tab.nolint.H Parser/amrex_iparser.tab.h + # AMReX Hydro ----------------------------------------------------- + AMReX_Slopes_K.H # Forward declaration ----------------------------------------------------- AMReX_BaseFwd.H ) diff --git a/Src/Base/Make.package b/Src/Base/Make.package index f266cc8a306..f75beb73cb3 100644 --- a/Src/Base/Make.package +++ b/Src/Base/Make.package @@ -212,6 +212,11 @@ C$(AMREX_BASE)_headers += AMReX_RKIntegrator.H C$(AMREX_BASE)_headers += AMReX_TimeIntegrator.H C$(AMREX_BASE)_headers += AMReX_RungeKutta.H +# +# Slopes +# +C$(AMREX_BASE)_headers += AMReX_Slopes_K.H + # # Fortran interface routines. # diff --git a/Src/Boundary/AMReX_YAFluxRegister.H b/Src/Boundary/AMReX_YAFluxRegister.H index 1b2210ec25d..619b7100983 100644 --- a/Src/Boundary/AMReX_YAFluxRegister.H +++ b/Src/Boundary/AMReX_YAFluxRegister.H @@ -50,11 +50,22 @@ public: const std::array& flux, const Real* dx, Real dt, RunOn runon) noexcept; + void CrseAdd (const MFIter& mfi, + const std::array& flux, + const Real* dx, Real dt, int srccomp, int destcomp, + int numcomp, RunOn runon) noexcept; + void FineAdd (const MFIter& mfi, const std::array& flux, const Real* dx, Real dt, RunOn runon) noexcept; + void FineAdd (const MFIter& mfi, + const std::array& a_flux, + const Real* dx, Real dt, int srccomp, int destcomp, + int numcomp, RunOn runon) noexcept; + void Reflux (MF& state, int dc = 0); + void Reflux (MF& state, int srccomp, int destcomp, int numcomp); bool CrseHasWork (const MFIter& mfi) const noexcept { return m_crse_fab_flag[mfi.LocalIndex()] != crse_cell; @@ -73,6 +84,13 @@ public: crse_cell = 0, crse_fine_boundary_cell, fine_cell }; + //! For curvilinear cooordinates only. In that case, the flux passed to + //! YAFluxRegister is assumed to have been multiplied by area. Note that + //! YAFluxRegister does NOT make a copy of the volume data. So the + //! coarse volume MF must be alive during the life time of + //! YAFluxRegister. + void setCrseVolume (MF const* cvol) { m_cvol = cvol; } + protected: MF m_crse_data; @@ -90,6 +108,8 @@ protected: IntVect m_ratio; int m_fine_level; int m_ncomp; + + MF const* m_cvol = nullptr; }; template @@ -326,42 +346,84 @@ YAFluxRegisterT::CrseAdd (const MFIter& mfi, const Real* dx, Real dt, RunOn runon) noexcept { BL_ASSERT(m_crse_data.nComp() == flux[0]->nComp()); + int srccomp = 0; + int destcomp = 0; + int numcomp = m_crse_data.nComp(); + CrseAdd(mfi, flux, dx, dt, srccomp, destcomp, numcomp, runon); +} + +template +void +YAFluxRegisterT::CrseAdd (const MFIter& mfi, + const std::array& flux, + const Real* dx, Real dt, int srccomp, int destcomp, + int numcomp, RunOn runon) noexcept +{ + BL_ASSERT(m_crse_data.nComp() >= destcomp+numcomp && + flux[0]->nComp() >= srccomp+numcomp); + + // + // We assume that the fluxes have been passed in starting at component srccomp + // "destcomp" refers to the indexing in the arrays internal to the EBFluxRegister + // if (m_crse_fab_flag[mfi.LocalIndex()] == crse_cell) { return; // this coarse fab is not close to fine fabs. } const Box& bx = mfi.tilebox(); - const int nc = m_crse_data.nComp(); - AMREX_D_TERM(const T dtdx = static_cast(dt/dx[0]);, - const T dtdy = static_cast(dt/dx[1]);, - const T dtdz = static_cast(dt/dx[2]);); + AMREX_D_TERM(auto dtdx = static_cast(dt/dx[0]);, + auto dtdy = static_cast(dt/dx[1]);, + auto dtdz = static_cast(dt/dx[2]);); AMREX_D_TERM(FAB const* fx = flux[0];, FAB const* fy = flux[1];, FAB const* fz = flux[2];); - auto fab = m_crse_data.array(mfi); + if (m_cvol) { + AMREX_D_TERM(dtdx = T(dt);, dtdy = T(dt);, dtdz = T(dt);); + } + + auto dest_arr = m_crse_data.array(mfi,destcomp); auto const flag = m_crse_flag.const_array(mfi); - AMREX_D_TERM(Array4 fxarr = fx->const_array();, - Array4 fyarr = fy->const_array();, - Array4 fzarr = fz->const_array();); + AMREX_D_TERM(Array4 fxarr = fx->const_array(srccomp);, + Array4 fyarr = fy->const_array(srccomp);, + Array4 fzarr = fz->const_array(srccomp);); AMREX_LAUNCH_HOST_DEVICE_LAMBDA_FLAG ( runon, bx, tbx, { - yafluxreg_crseadd(tbx, fab, flag, AMREX_D_DECL(fxarr,fyarr,fzarr), - AMREX_D_DECL(dtdx,dtdy,dtdz),nc); + yafluxreg_crseadd(tbx, dest_arr, flag, AMREX_D_DECL(fxarr,fyarr,fzarr), + AMREX_D_DECL(dtdx,dtdy,dtdz),numcomp); }); } template void YAFluxRegisterT::FineAdd (const MFIter& mfi, - const std::array& a_flux, + const std::array& flux, const Real* dx, Real dt, RunOn runon) noexcept { - BL_ASSERT(m_cfpatch.nComp() == a_flux[0]->nComp()); + BL_ASSERT(m_crse_data.nComp() == flux[0]->nComp()); + int srccomp = 0; + int destcomp = 0; + int numcomp = m_crse_data.nComp(); + FineAdd(mfi, flux, dx, dt, srccomp, destcomp, numcomp, runon); +} + +template +void +YAFluxRegisterT::FineAdd (const MFIter& mfi, + const std::array& a_flux, + const Real* dx, Real dt, int srccomp, int destcomp, + int numcomp, RunOn runon) noexcept +{ + BL_ASSERT(m_cfpatch.nComp() >= destcomp+numcomp && + a_flux[0]->nComp() >= srccomp+numcomp); + // + // We assume that the fluxes have been passed in starting at component srccomp + // "destcomp" refers to the indexing in the arrays internal to the EBFluxRegister + // const int li = mfi.LocalIndex(); Vector& cfp_fabs = m_cfp_fab[li]; if (cfp_fabs.empty()) return; @@ -369,7 +431,6 @@ YAFluxRegisterT::FineAdd (const MFIter& mfi, const Box& tbx = mfi.tilebox(); const Box& bx = amrex::coarsen(tbx, m_ratio); const Box& fbx = amrex::refine(bx, m_ratio); - const int nc = m_cfpatch.nComp(); const T ratio = static_cast(AMREX_D_TERM(m_ratio[0],*m_ratio[1],*m_ratio[2])); std::array dtdx{{AMREX_D_DECL(static_cast(dt/(dx[0]*ratio)), @@ -377,6 +438,13 @@ YAFluxRegisterT::FineAdd (const MFIter& mfi, static_cast(dt/(dx[2]*ratio)))}}; const Dim3 rr = m_ratio.dim3(); + if (m_cvol) { + for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) { + dtdx[idim] = T(dt); + } + } + + int fluxcomp = srccomp; std::array flux{{AMREX_D_DECL(a_flux[0],a_flux[1],a_flux[2])}}; bool use_gpu = (runon == RunOn::Gpu) && Gpu::inLaunchRegion(); amrex::ignore_unused(use_gpu); @@ -385,10 +453,11 @@ YAFluxRegisterT::FineAdd (const MFIter& mfi, AMREX_ASSERT(!use_gpu); for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) { const Box& b = amrex::surroundingNodes(fbx,idim); - ftmp[idim].resize(b,nc); + ftmp[idim].resize(b,numcomp); ftmp[idim].template setVal(T(0.0)); - ftmp[idim].template copy(*a_flux[idim]); + ftmp[idim].template copy(*a_flux[idim], srccomp, 0, numcomp); flux[idim] = &ftmp[idim]; + fluxcomp = 0; } } @@ -406,13 +475,13 @@ YAFluxRegisterT::FineAdd (const MFIter& mfi, const int side = 0; if (lobx_is.ok()) { - auto d = cfp->array(); + auto d = cfp->array(destcomp); auto dtdxs = dtdx[idim]; int dirside = idim*2+side; - Array4 farr = f->const_array(); + Array4 farr = f->const_array(fluxcomp); AMREX_LAUNCH_HOST_DEVICE_LAMBDA_FLAG(runon, lobx_is, tmpbox, { - yafluxreg_fineadd(tmpbox, d, farr, dtdxs, nc, dirside, rr); + yafluxreg_fineadd(tmpbox, d, farr, dtdxs, numcomp, dirside, rr); }); } } @@ -421,13 +490,13 @@ YAFluxRegisterT::FineAdd (const MFIter& mfi, const int side = 1; if (hibx_is.ok()) { - auto d = cfp->array(); + auto d = cfp->array(destcomp); auto dtdxs = dtdx[idim]; int dirside = idim*2+side; - Array4 farr = f->const_array(); + Array4 farr = f->const_array(fluxcomp); AMREX_LAUNCH_HOST_DEVICE_LAMBDA_FLAG(runon, hibx_is, tmpbox, { - yafluxreg_fineadd(tmpbox, d, farr, dtdxs, nc, dirside, rr); + yafluxreg_fineadd(tmpbox, d, farr, dtdxs, numcomp, dirside, rr); }); } } @@ -439,9 +508,22 @@ template void YAFluxRegisterT::Reflux (MF& state, int dc) { + int srccomp = 0; + int destcomp = dc; + int numcomp = m_ncomp; + Reflux(state, srccomp, destcomp, numcomp); +} + +template +void +YAFluxRegisterT::Reflux (MF& state, int srccomp, int destcomp, int numcomp) +{ + // + // Here "srccomp" refers to the indexing in the arrays internal to the EBFluxRegister + // "destcomp" refers to the indexing in the external arrays being filled by refluxing + // if (!m_cfp_mask.empty()) { - const int ncomp = m_ncomp; #ifdef AMREX_USE_OMP #pragma omp parallel if (Gpu::notInLaunchRegion()) #endif @@ -449,18 +531,29 @@ YAFluxRegisterT::Reflux (MF& state, int dc) { const Box& bx = m_cfpatch[mfi].box(); auto const maskfab = m_cfp_mask.array(mfi); - auto cfptfab = m_cfpatch.array(mfi); - AMREX_HOST_DEVICE_PARALLEL_FOR_4D ( bx, ncomp, i, j, k, n, + auto cfptfab = m_cfpatch.array(mfi,srccomp); + AMREX_HOST_DEVICE_PARALLEL_FOR_4D ( bx, numcomp, i, j, k, n, { cfptfab(i,j,k,n) *= maskfab(i,j,k); }); } } - m_crse_data.ParallelCopy(m_cfpatch, m_crse_geom.periodicity(), FabArrayBase::ADD); + m_crse_data.ParallelCopy(m_cfpatch, srccomp, srccomp, numcomp, m_crse_geom.periodicity(), FabArrayBase::ADD); - BL_ASSERT(state.nComp() >= dc + m_ncomp); - amrex::Add(state, m_crse_data, 0, dc, m_ncomp, 0); + BL_ASSERT(state.nComp() >= destcomp + numcomp); + if (m_cvol) { + auto const& dst = state.arrays(); + auto const& src = m_crse_data.const_arrays(); + auto const& vol = m_cvol->const_arrays(); + amrex::ParallelFor(state, IntVect(0), numcomp, + [=] AMREX_GPU_DEVICE (int bno, int i, int j, int k, int n) + { + dst[bno](i,j,k,destcomp+n) += src[bno](i,j,k,srccomp+n) / vol[bno](i,j,k); + }); + } else { + amrex::Add(state, m_crse_data, srccomp, destcomp, numcomp, 0); + } } template diff --git a/Src/EB/AMReX_EBCellFlag.H b/Src/EB/AMReX_EBCellFlag.H index 0a15cba704b..6ad187da9aa 100644 --- a/Src/EB/AMReX_EBCellFlag.H +++ b/Src/EB/AMReX_EBCellFlag.H @@ -57,7 +57,7 @@ public: void setMultiValued (int n) noexcept { flag &= zero_lower_mask; flag |= multi_valued_bits; - BL_ASSERT(n >= 2 && n <= 7); + AMREX_ASSERT(n >= 2 && n <= 7); flag |= static_cast(n) << pos_numvofs; } diff --git a/Src/EB/AMReX_EBFArrayBox.cpp b/Src/EB/AMReX_EBFArrayBox.cpp index 781112ed2c1..5718b3f5377 100644 --- a/Src/EB/AMReX_EBFArrayBox.cpp +++ b/Src/EB/AMReX_EBFArrayBox.cpp @@ -21,7 +21,7 @@ EBFArrayBox::EBFArrayBox (const EBCellFlagFab& ebflag, const Box& bx, int ncomps m_factory(factory), m_box_index(box_index) { - BL_ASSERT(ebflag.box().contains(amrex::enclosedCells(bx))); + AMREX_ASSERT(ebflag.box().contains(amrex::enclosedCells(bx))); const Box& ccbx = amrex::enclosedCells(bx); m_type = ebflag.getType(ccbx); } @@ -174,7 +174,7 @@ const EBCellFlagFab& getEBCellFlagFab (const FArrayBox& fab) { const auto* ebfab = static_cast(&fab); - BL_ASSERT(ebfab); + AMREX_ASSERT(ebfab); return ebfab->getEBCellFlagFab(); } diff --git a/Src/EB/AMReX_EBFluxRegister.H b/Src/EB/AMReX_EBFluxRegister.H index c53f0a894a6..33ec811dcf6 100644 --- a/Src/EB/AMReX_EBFluxRegister.H +++ b/Src/EB/AMReX_EBFluxRegister.H @@ -78,6 +78,12 @@ public: const FArrayBox& volfrac, const std::array& areafrac, RunOn runon); + void CrseAdd (const MFIter& mfi, + const std::array& flux, + const Real* dx, Real dt, + const FArrayBox& volfrac, + const std::array& areafrac, + int srccomp, int destcomp, int numcomp, RunOn runon); using YAFluxRegister::FineAdd; void FineAdd (const MFIter& mfi, @@ -87,9 +93,29 @@ public: const std::array& areafrac, const FArrayBox& dm, RunOn runon); + void FineAdd (const MFIter& mfi, + const std::array& flux, + const Real* dx, Real dt, + const FArrayBox& volfrac, + const std::array& areafrac, + const FArrayBox& dm, + int srccomp, int destcomp, int numcomp, RunOn runon); + //! This version does not do re-redistribution. + void FineAdd (const MFIter& mfi, + const std::array& flux, + const Real* dx, Real dt, + const FArrayBox& volfrac, + const std::array& areafrac, + int srccomp, int destcomp, int numcomp, RunOn runon); void Reflux (MultiFab& crse_state, const amrex::MultiFab& crse_vfrac, MultiFab& fine_state, const amrex::MultiFab& fine_vfrac); + void Reflux (MultiFab& crse_state, const amrex::MultiFab& crse_vfrac, + MultiFab& fine_state, const amrex::MultiFab& fine_vfrac, + int srccomp, int destcomp, int numcomp); + //! This version does not do re-redistribution. + void Reflux (MultiFab& crse_state, const amrex::MultiFab& crse_vfrac, + int srccomp, int destcomp, int numcomp); FArrayBox* getCrseData (const MFIter& mfi) { return &(m_crse_data[mfi]); diff --git a/Src/EB/AMReX_EBFluxRegister.cpp b/Src/EB/AMReX_EBFluxRegister.cpp index c17e5629034..ed2c42f758c 100644 --- a/Src/EB/AMReX_EBFluxRegister.cpp +++ b/Src/EB/AMReX_EBFluxRegister.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #ifdef AMREX_USE_OMP #include @@ -79,13 +80,34 @@ EBFluxRegister::CrseAdd (const MFIter& mfi, const std::array& areafrac, RunOn runon) { - BL_ASSERT(m_crse_data.nComp() == flux[0]->nComp()); + AMREX_ASSERT(m_crse_data.nComp() == flux[0]->nComp()); + int srccomp = 0; + int destcomp = 0; + int numcomp = m_crse_data.nComp(); + CrseAdd(mfi, flux, dx, dt, volfrac, areafrac, srccomp, destcomp, numcomp, runon); +} + +void +EBFluxRegister::CrseAdd (const MFIter& mfi, + const std::array& flux, + const Real* dx, Real dt, + const FArrayBox& volfrac, + const std::array& areafrac, + int srccomp, int destcomp, int numcomp, RunOn runon) +{ + // + // We assume that the fluxes have been passed in starting at component srccomp. + // "destcomp" refers to the indexing in the arrays internal to the EBFluxRegister + // + + AMREX_ASSERT( flux[0]->nComp() >= srccomp+numcomp && + m_crse_data.nComp() >= destcomp+numcomp); if (m_crse_fab_flag[mfi.LocalIndex()] == crse_cell) { return; // this coarse fab is not close to fine fabs. } - Array4 const& fab = m_crse_data.array(mfi); + Array4 const& dest_arr = m_crse_data.array(mfi,destcomp); const Box& bx = mfi.tilebox(); Array4 const& amrflag = m_crse_flag.array(mfi); @@ -93,9 +115,9 @@ EBFluxRegister::CrseAdd (const MFIter& mfi, AMREX_D_TERM(Real dtdx = dt/dx[0];, Real dtdy = dt/dx[1];, Real dtdz = dt/dx[2];); - AMREX_D_TERM(Array4 const& fx = flux[0]->const_array();, - Array4 const& fy = flux[1]->const_array();, - Array4 const& fz = flux[2]->const_array();); + AMREX_D_TERM(Array4 const& fx = flux[0]->const_array(srccomp);, + Array4 const& fy = flux[1]->const_array(srccomp);, + Array4 const& fz = flux[2]->const_array(srccomp);); AMREX_D_TERM(Array4 const& apx = areafrac[0]->const_array();, Array4 const& apy = areafrac[1]->const_array();, Array4 const& apz = areafrac[2]->const_array();); @@ -103,36 +125,56 @@ EBFluxRegister::CrseAdd (const MFIter& mfi, AMREX_HOST_DEVICE_FOR_3D_FLAG(runon, bx, i, j, k, { - eb_flux_reg_crseadd_va(i,j,k,fab,amrflag,AMREX_D_DECL(fx,fy,fz), + eb_flux_reg_crseadd_va(i,j,k,dest_arr,amrflag,AMREX_D_DECL(fx,fy,fz), vfrac,AMREX_D_DECL(apx,apy,apz), - AMREX_D_DECL(dtdx,dtdy,dtdz)); + AMREX_D_DECL(dtdx,dtdy,dtdz), + numcomp); }); } - void EBFluxRegister::FineAdd (const MFIter& mfi, - const std::array& a_flux, + const std::array& flux, const Real* dx, Real dt, const FArrayBox& volfrac, const std::array& areafrac, const FArrayBox& dm, RunOn runon) { - BL_ASSERT(m_cfpatch.nComp() == a_flux[0]->nComp()); + AMREX_ASSERT(m_cfpatch.nComp() == flux[0]->nComp()); + int srccomp = 0; + int destcomp = 0; + int numcomp = m_crse_data.nComp(); + FineAdd(mfi, flux, dx, dt, volfrac, areafrac, dm, srccomp, destcomp, numcomp, runon); +} + +void +EBFluxRegister::FineAdd (const MFIter& mfi, + const std::array& flux, + const Real* dx, Real dt, + const FArrayBox& volfrac, + const std::array& areafrac, + const FArrayBox& dm, + int srccomp, int destcomp, int numcomp, RunOn runon) +{ + // + // We assume that the fluxes and dm have been passed in starting at component srccomp. + // "destcomp" refers to the indexing in the arrays internal to the EBFluxRegister + // + AMREX_ASSERT( srccomp + numcomp <= flux[0]->nComp() && + destcomp + numcomp <= m_ncomp); const int li = mfi.LocalIndex(); Vector& cfp_fabs = m_cfp_fab[li]; if (cfp_fabs.empty()) return; - const int nc = m_cfpatch.nComp(); const Box& tbx = mfi.tilebox(); BL_ASSERT(tbx.cellCentered()); const Box& cbx = amrex::coarsen(tbx, m_ratio); - AMREX_D_TERM(Array4 const& fx = a_flux[0]->const_array();, - Array4 const& fy = a_flux[1]->const_array();, - Array4 const& fz = a_flux[2]->const_array();); + AMREX_D_TERM(Array4 const& fx = flux[0]->const_array(srccomp);, + Array4 const& fy = flux[1]->const_array(srccomp);, + Array4 const& fz = flux[2]->const_array(srccomp);); Array4 const& vfrac = volfrac.const_array(); AMREX_D_TERM(Array4 const& apx = areafrac[0]->const_array();, @@ -148,12 +190,12 @@ EBFluxRegister::FineAdd (const MFIter& mfi, const Box& hibx = amrex::adjCellHi(cbx, idim); for (FArrayBox* cfp : cfp_fabs) { - Array4 const& cfa = cfp->array(); + Array4 const& cfa = cfp->array(destcomp); const Box& lobx_is = lobx & cfp->box(); if (lobx_is.ok()) { if (idim == 0) { - AMREX_HOST_DEVICE_FOR_4D_FLAG(runon,lobx_is,nc,i,j,k,n, + AMREX_HOST_DEVICE_FOR_4D_FLAG(runon,lobx_is,numcomp,i,j,k,n, { eb_flux_reg_fineadd_va_xlo(i,j,k,n, cfa, fx, vfrac, apx, fac, ratio); }); @@ -161,7 +203,7 @@ EBFluxRegister::FineAdd (const MFIter& mfi, #if (AMREX_SPACEDIM >= 2) else if (idim == 1) { - AMREX_HOST_DEVICE_FOR_4D_FLAG(runon,lobx_is,nc,i,j,k,n, + AMREX_HOST_DEVICE_FOR_4D_FLAG(runon,lobx_is,numcomp,i,j,k,n, { eb_flux_reg_fineadd_va_ylo(i,j,k,n, cfa, fy, vfrac, apy, fac, ratio); }); @@ -169,7 +211,7 @@ EBFluxRegister::FineAdd (const MFIter& mfi, #if (AMREX_SPACEDIM == 3) else { - AMREX_HOST_DEVICE_FOR_4D_FLAG(runon,lobx_is,nc,i,j,k,n, + AMREX_HOST_DEVICE_FOR_4D_FLAG(runon,lobx_is,numcomp,i,j,k,n, { eb_flux_reg_fineadd_va_zlo(i,j,k,n, cfa, fz, vfrac, apz, fac, ratio); }); @@ -181,7 +223,7 @@ EBFluxRegister::FineAdd (const MFIter& mfi, if (hibx_is.ok()) { if (idim == 0) { - AMREX_HOST_DEVICE_FOR_4D_FLAG(runon,hibx_is,nc,i,j,k,n, + AMREX_HOST_DEVICE_FOR_4D_FLAG(runon,hibx_is,numcomp,i,j,k,n, { eb_flux_reg_fineadd_va_xhi(i,j,k,n, cfa, fx, vfrac, apx, fac, ratio); }); @@ -189,7 +231,7 @@ EBFluxRegister::FineAdd (const MFIter& mfi, #if (AMREX_SPACEDIM >= 2) else if (idim == 1) { - AMREX_HOST_DEVICE_FOR_4D_FLAG(runon,hibx_is,nc,i,j,k,n, + AMREX_HOST_DEVICE_FOR_4D_FLAG(runon,hibx_is,numcomp,i,j,k,n, { eb_flux_reg_fineadd_va_yhi(i,j,k,n, cfa, fy, vfrac, apy, fac, ratio); }); @@ -197,7 +239,7 @@ EBFluxRegister::FineAdd (const MFIter& mfi, #if (AMREX_SPACEDIM == 3) else { - AMREX_HOST_DEVICE_FOR_4D_FLAG(runon,hibx_is,nc,i,j,k,n, + AMREX_HOST_DEVICE_FOR_4D_FLAG(runon,hibx_is,numcomp,i,j,k,n, { eb_flux_reg_fineadd_va_zhi(i,j,k,n, cfa, fz, vfrac, apz, fac, ratio); }); @@ -208,29 +250,63 @@ EBFluxRegister::FineAdd (const MFIter& mfi, } } - Real threshold = amrex_eb_get_reredistribution_threshold()*static_cast(AMREX_D_TERM(ratio.x,*ratio.y,*ratio.z)); - const Box& tbxg1 = amrex::grow(tbx,1); - const Box& cbxg1 = amrex::grow(cbx,1); - Array4 const& dma = dm.const_array(); - for (FArrayBox* cfp : cfp_fabs) - { - const Box& wbx = cbxg1 & cfp->box(); - if (wbx.ok()) + if (dm.isAllocated()) { + AMREX_ASSERT(srccomp + numcomp <= dm.nComp()); + Real threshold = amrex_eb_get_reredistribution_threshold() + *static_cast(AMREX_D_TERM(ratio.x,*ratio.y,*ratio.z)); + const Box& tbxg1 = amrex::grow(tbx,1); + const Box& cbxg1 = amrex::grow(cbx,1); + Array4 const& dma = dm.const_array(srccomp); + for (FArrayBox* cfp : cfp_fabs) { - Array4 const& cfa = cfp->array(); - AMREX_HOST_DEVICE_FOR_4D_FLAG(runon, wbx, nc, i, j, k, n, + const Box& wbx = cbxg1 & cfp->box(); + if (wbx.ok()) { - eb_flux_reg_fineadd_dm(i,j,k,n,tbxg1, cfa, dma, vfrac, ratio, threshold); - }); + Array4 const& cfa = cfp->array(destcomp); + AMREX_HOST_DEVICE_FOR_4D_FLAG(runon, wbx, numcomp, i, j, k, n, + { + eb_flux_reg_fineadd_dm(i,j,k,n,tbxg1,cfa,dma, vfrac, ratio, threshold); + }); + } } } } +void +EBFluxRegister::FineAdd (const MFIter& mfi, + const std::array& flux, + const Real* dx, Real dt, + const FArrayBox& volfrac, + const std::array& areafrac, + int srccomp, int destcomp, int numcomp, RunOn runon) +{ + FArrayBox dm; + FineAdd(mfi, flux, dx, dt, volfrac, areafrac, dm, + srccomp, destcomp, numcomp, runon); +} + +void +EBFluxRegister::Reflux (MultiFab& crse_state, const amrex::MultiFab& crse_vfrac, + MultiFab& fine_state, const amrex::MultiFab& fine_vfrac) +{ + int srccomp = 0; + int destcomp = 0; + int numcomp = m_ncomp; + Reflux(crse_state, crse_vfrac, fine_state, fine_vfrac, srccomp, destcomp, numcomp); +} void EBFluxRegister::Reflux (MultiFab& crse_state, const amrex::MultiFab& crse_vfrac, - MultiFab& fine_state, const amrex::MultiFab& /*fine_vfrac*/) + MultiFab& fine_state, const amrex::MultiFab& /*fine_vfrac*/, + int srccomp, int destcomp, int numcomp) { + // + // Here "srccomp" refers to the indexing in the arrays internal to the EBFluxRegister + // "destcomp" refers to the indexing in the external arrays being filled by refluxing + // + AMREX_ASSERT( srccomp+numcomp <= m_ncomp && + destcomp+numcomp <= crse_state.nComp()); + if (!m_cfp_mask.empty()) { #ifdef AMREX_USE_OMP @@ -241,22 +317,22 @@ EBFluxRegister::Reflux (MultiFab& crse_state, const amrex::MultiFab& crse_vfrac, Array4 const& cfa = m_cfpatch.array(mfi); Array4 const& m = m_cfp_mask.const_array(mfi); const Box& bx = mfi.fabbox(); - AMREX_HOST_DEVICE_PARALLEL_FOR_4D(bx,m_ncomp,i,j,k,n, + AMREX_HOST_DEVICE_PARALLEL_FOR_4D(bx,numcomp,i,j,k,n, { - cfa(i,j,k,n) *= m(i,j,k); + cfa(i,j,k,srccomp+n) *= m(i,j,k); }); } } - m_crse_data.ParallelCopy(m_cfpatch, m_crse_geom.periodicity(), FabArrayBase::ADD); + m_crse_data.ParallelCopy(m_cfpatch, srccomp, srccomp, numcomp, m_crse_geom.periodicity(), FabArrayBase::ADD); { MultiFab grown_crse_data(m_crse_data.boxArray(), m_crse_data.DistributionMap(), - m_ncomp, 1, MFInfo(), FArrayBoxFactory()); - MultiFab::Copy(grown_crse_data, m_crse_data, 0, 0, m_ncomp, 0); + numcomp, 1, MFInfo(), FArrayBoxFactory()); + MultiFab::Copy(grown_crse_data, m_crse_data, srccomp, 0, numcomp, 0); grown_crse_data.FillBoundary(m_crse_geom.periodicity()); - m_crse_data.setVal(0.0); + m_crse_data.setVal(0.0, srccomp, numcomp); auto const& factory = dynamic_cast(crse_state.Factory()); auto const& flags = factory.getMultiEBCellFlagFab(); @@ -276,12 +352,12 @@ EBFluxRegister::Reflux (MultiFab& crse_state, const amrex::MultiFab& crse_vfrac, const auto& ebflag = flags[mfi]; if (ebflag.getType(bx) != FabType::covered) { const Box& bxg1 = amrex::grow(bx,1) & gdomain; - Array4 const& dfab = m_crse_data.array(mfi); + Array4 const& dfab = m_crse_data.array(mfi,srccomp); Array4 const& sfab = grown_crse_data.const_array(mfi); if (ebflag.getType(bxg1) == FabType::regular) { // no re-reflux or re-re-redistribution - AMREX_HOST_DEVICE_PARALLEL_FOR_4D(bx, m_ncomp, i, j, k, n, + AMREX_HOST_DEVICE_PARALLEL_FOR_4D(bx, numcomp, i, j, k, n, { dfab(i,j,k,n) += sfab(i,j,k,n); }); @@ -291,9 +367,9 @@ EBFluxRegister::Reflux (MultiFab& crse_state, const amrex::MultiFab& crse_vfrac, Array4 const& amrflag = m_crse_flag.const_array(mfi); Array4 const& ebflagarr = ebflag.const_array(); Array4 const& cvol = crse_vfrac.const_array(mfi); - AMREX_HOST_DEVICE_FOR_4D(bxg1, m_ncomp, i, j, k, n, + AMREX_HOST_DEVICE_FOR_4D(bxg1, numcomp, i, j, k, n, { - eb_rereflux_from_crse(i,j,k,n,bx,dfab,sfab,amrflag,ebflagarr,cvol); + eb_rereflux_from_crse(i,j,k,n,bx,dfab,sfab,amrflag,ebflagarr,cvol); }); } } @@ -301,41 +377,52 @@ EBFluxRegister::Reflux (MultiFab& crse_state, const amrex::MultiFab& crse_vfrac, } } - MultiFab::Add(crse_state, m_crse_data, 0, 0, m_ncomp, 0); + MultiFab::Add(crse_state, m_crse_data, srccomp, destcomp, numcomp, 0); - // The fine-covered cells of m_crse_data contain the data that should go to the fine level - BoxArray ba = fine_state.boxArray(); - ba.coarsen(m_ratio); - MultiFab cf(ba, fine_state.DistributionMap(), m_ncomp, 0, MFInfo(), FArrayBoxFactory()); - cf.ParallelCopy(m_crse_data); + if (! fine_state.empty()) { + AMREX_ASSERT(destcomp+numcomp <= fine_state.nComp()); + // The fine-covered cells of m_crse_data contain the data that + // should go to the fine level + BoxArray ba = fine_state.boxArray(); + ba.coarsen(m_ratio); + MultiFab cf(ba, fine_state.DistributionMap(), numcomp, 0, MFInfo(), FArrayBoxFactory()); + cf.ParallelCopy(m_crse_data,srccomp,0,numcomp); - auto const& factory = dynamic_cast(fine_state.Factory()); - auto const& flags = factory.getMultiEBCellFlagFab(); + auto const& factory = dynamic_cast(fine_state.Factory()); + auto const& flags = factory.getMultiEBCellFlagFab(); - Dim3 ratio = m_ratio.dim3(); + Dim3 ratio = m_ratio.dim3(); #ifdef AMREX_USE_OMP #pragma omp parallel if (Gpu::notInLaunchRegion()) #endif - for (MFIter mfi(cf,TilingIfNotGPU()); mfi.isValid(); ++mfi) - { - const Box& cbx = mfi.tilebox(); - const Box& fbx = amrex::refine(cbx, m_ratio); + for (MFIter mfi(cf,TilingIfNotGPU()); mfi.isValid(); ++mfi) { + const Box& cbx = mfi.tilebox(); + const Box& fbx = amrex::refine(cbx, m_ratio); - const auto& ebflag = flags[mfi]; + const auto& ebflag = flags[mfi]; - if (ebflag.getType(fbx) != FabType::covered) - { - Array4 const& d = fine_state.array(mfi); - Array4 const& s = cf.const_array(mfi); - Array4 const& m = m_cfp_inside_mask.const_array(mfi); - AMREX_HOST_DEVICE_FOR_4D(fbx,m_ncomp,i,j,k,n, + if (ebflag.getType(fbx) != FabType::covered) { - eb_rereflux_to_fine(i,j,k,n,d,s,m,ratio); - }); + Array4 const& d = fine_state.array(mfi,destcomp); + Array4 const& s = cf.const_array(mfi,0); + Array4< int const> const& m = m_cfp_inside_mask.const_array(mfi); + AMREX_HOST_DEVICE_FOR_4D(fbx,numcomp,i,j,k,n, + { + eb_rereflux_to_fine(i,j,k,n,d,s,m,ratio); + }); + } } } } +void +EBFluxRegister::Reflux (MultiFab& crse_state, const amrex::MultiFab& crse_vfrac, + int srccomp, int destcomp, int numcomp) +{ + MultiFab fine_state, fine_vfrac; + Reflux(crse_state, crse_vfrac, fine_state, fine_vfrac, + srccomp, destcomp, numcomp); +} } diff --git a/Src/EB/AMReX_EBFluxRegister_2D_C.H b/Src/EB/AMReX_EBFluxRegister_2D_C.H index 8f82487c5a1..067411f0198 100644 --- a/Src/EB/AMReX_EBFluxRegister_2D_C.H +++ b/Src/EB/AMReX_EBFluxRegister_2D_C.H @@ -9,12 +9,11 @@ void eb_flux_reg_crseadd_va(int i, int j, int k, Array4 const& d, Array4 const& flag, Array4 const& fx, Array4 const& fy, Array4 const& vfrac, Array4 const& ax, Array4 const& ay, - Real dtdx, Real dtdy) + Real dtdx, Real dtdy, int ncomp) { if (flag(i,j,k) == amrex_yafluxreg_crse_fine_boundary_cell && vfrac(i,j,k) > Real(1.e-14)) { - int ncomp = d.nComp(); Real volinv = Real(1.0)/vfrac(i,j,k); if (flag(i-1,j,k) == amrex_yafluxreg_fine_cell) { diff --git a/Src/EB/AMReX_EBFluxRegister_3D_C.H b/Src/EB/AMReX_EBFluxRegister_3D_C.H index 2c3f9feeec4..3410c7180db 100644 --- a/Src/EB/AMReX_EBFluxRegister_3D_C.H +++ b/Src/EB/AMReX_EBFluxRegister_3D_C.H @@ -10,12 +10,11 @@ void eb_flux_reg_crseadd_va(int i, int j, int k, Array4 const& d, Array4 const& fy, Array4 const& fz, Array4 const& vfrac, Array4 const& ax, Array4 const& ay, Array4 const& az, - Real dtdx, Real dtdy, Real dtdz) + Real dtdx, Real dtdy, Real dtdz, int ncomp) { if (flag(i,j,k) == amrex_yafluxreg_crse_fine_boundary_cell && vfrac(i,j,k) > Real(1.e-14)) { - int ncomp = d.nComp(); Real volinv = Real(1.0)/vfrac(i,j,k); if (flag(i-1,j,k) == amrex_yafluxreg_fine_cell) { diff --git a/Src/EB/AMReX_EBInterpolater.cpp b/Src/EB/AMReX_EBInterpolater.cpp index cc020637aca..67504383953 100644 --- a/Src/EB/AMReX_EBInterpolater.cpp +++ b/Src/EB/AMReX_EBInterpolater.cpp @@ -31,7 +31,7 @@ EBCellConservativeLinear::interp (const FArrayBox& crse, if (crse.getType() == FabType::regular) { - BL_ASSERT(amrex::getEBCellFlagFab(fine).getType(target_fine_region) == FabType::regular); + AMREX_ASSERT(amrex::getEBCellFlagFab(fine).getType(target_fine_region) == FabType::regular); } else { diff --git a/Src/EB/AMReX_EBMultiFabUtil.cpp b/Src/EB/AMReX_EBMultiFabUtil.cpp index 57d36a536b6..a5202c7d805 100644 --- a/Src/EB/AMReX_EBMultiFabUtil.cpp +++ b/Src/EB/AMReX_EBMultiFabUtil.cpp @@ -410,8 +410,8 @@ EB_average_down (const MultiFab& S_fine, MultiFab& S_crse, int scomp, int ncomp, const auto& factory = dynamic_cast(S_fine.Factory()); const auto& vfrac_fine = factory.getVolFrac(); - BL_ASSERT(S_crse.nComp() == S_fine.nComp()); - BL_ASSERT(S_crse.is_cell_centered() && S_fine.is_cell_centered()); + AMREX_ASSERT(S_crse.nComp() == S_fine.nComp()); + AMREX_ASSERT(S_crse.is_cell_centered() && S_fine.is_cell_centered()); BoxArray crse_S_fine_BA = S_fine.boxArray(); crse_S_fine_BA.coarsen(ratio); diff --git a/Src/EB/AMReX_EB_FluxRedistribute.cpp b/Src/EB/AMReX_EB_FluxRedistribute.cpp new file mode 100644 index 00000000000..42d4d0b5c20 --- /dev/null +++ b/Src/EB/AMReX_EB_FluxRedistribute.cpp @@ -0,0 +1,323 @@ +#include +#include +#include +#include +#include +#include +#include + +namespace amrex { + +void +amrex_flux_redistribute ( + const Box& bx, + Array4 const& dqdt, + Array4 const& divc, + Array4 const& wt, + Array4 const& vfrac, + Array4 const& flag, + int as_crse, + Array4 const& rr_drho_crse, + Array4 const& rr_flag_crse, + int as_fine, + Array4 const& dm_as_fine, + Array4 const& levmsk, + const Geometry& geom, + bool use_wts_in_divnc, + int level_mask_not_covered, + int icomp, int ncomp, Real dt) +{ + // if (as_crse == 0 && as_fine == 0) { + // amrex::Print() << "In amrex_flux_redistribution on neither side" << std::endl; + // } else if (as_crse == 0 && as_fine == 1) { + // amrex::Print() << "In amrex_flux_redistribution on fine side" << std::endl; + // } else if (as_crse == 1 && as_fine == 0) { + // amrex::Print() << "In amrex_flux_redistribution on coarse side" << std::endl; + // } else if (as_crse == 1 && as_fine == 1) { + // amrex::Print() << "In amrex_flux_redistribution on both sides" << std::endl; + // } + // + // Check that grid is uniform + // + const Real* dx = geom.CellSize(); + +#if (AMREX_SPACEDIM == 2) + if (! amrex::almostEqual(dx[0], dx[1])) + amrex::Abort("apply_eb_redistribution(): grid spacing must be uniform"); +#elif (AMREX_SPACEDIM == 3) + if( ! amrex::almostEqual(dx[0],dx[1]) || + ! amrex::almostEqual(dx[0],dx[2]) || + ! amrex::almostEqual(dx[1],dx[2]) ) + amrex::Abort("apply_eb_redistribution(): grid spacing must be uniform"); +#endif + + const Box dbox = geom.growPeriodicDomain(2); + const Box& grown1_bx = amrex::grow(bx,1); + const Box& grown2_bx = amrex::grow(bx,2); + + Real reredistribution_threshold = amrex_eb_get_reredistribution_threshold(); + + int bx_ilo = bx.smallEnd()[0]; + int bx_ihi = bx.bigEnd()[0]; + int bx_jlo = bx.smallEnd()[1]; + int bx_jhi = bx.bigEnd()[1]; +#if (AMREX_SPACEDIM == 3) + int bx_klo = bx.smallEnd()[2]; + int bx_khi = bx.bigEnd()[2]; +#endif + + // + // Working arrays + // + FArrayBox delm_fab(grown1_bx,ncomp); + FArrayBox optmp_fab(grown2_bx,ncomp); + FArrayBox mask_fab(grown2_bx); + + Array4 const& optmp = optmp_fab.array(); + Array4 const& mask = mask_fab.array(); + Array4 const& delm = delm_fab.array(); + + // + // Array "mask" is used to sever the link to ghost cells when the BCs + // are not periodic + // It is set to 1 when a cell can be used in computations, 0 otherwise + // + AMREX_FOR_3D(grown2_bx, i, j, k, + { + mask(i,j,k) = (dbox.contains(IntVect(AMREX_D_DECL(i,j,k)))) ? 1.0 : 0.0; + }); + + //LOOK AT THIS + // + // Init to zero tmp array + // + AMREX_FOR_4D(grown2_bx, ncomp, i, j, k, n, + { + optmp(i,j,k,n) = 0; + }); + + // + // Step 2: compute delta M (mass gain or loss) on (lo-1,lo+1) + //Gives an optoion to use weights to compute divnc or not + + if (use_wts_in_divnc) { + amrex::ParallelFor(grown1_bx, ncomp, + [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept + { + if (flag(i,j,k).isSingleValued()) + { + Real vtot(0.); + Real divnc(0.); +#if (AMREX_SPACEDIM == 2) + int kk(0); +#else + for (int kk = -1; kk <= 1; kk++) +#endif + for (int jj = -1; jj <= 1; jj++) + for (int ii = -1; ii <= 1; ii++) + if ( (ii != 0 || jj != 0 || kk != 0) && flag(i,j,k).isConnected(ii,jj,kk) && + dbox.contains(IntVect(AMREX_D_DECL(i+ii,j+jj,k+kk)))) + { + Real wted_frac = vfrac(i+ii,j+jj,k+kk) * wt(i+ii,j+jj,k+kk) * mask(i+ii,j+jj,k+kk); + vtot += wted_frac; + divnc += wted_frac * divc(i+ii,j+jj,k+kk,n); + } + divnc /= vtot; + + // We need to multiply by mask to make sure optmp is zero for cells + // outside the domain for non-cyclic BCs + optmp(i,j,k,n) = (1 - vfrac(i,j,k)) * (divnc - divc(i,j,k,n)) * mask(i,j,k); + delm(i,j,k,n) = -( vfrac(i,j,k)) * optmp(i,j,k,n); + + } else { + delm(i,j,k,n) = 0.; + } + }); + } else { + amrex::ParallelFor(grown1_bx, ncomp, + [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept + { + if (flag(i,j,k).isSingleValued()) + { + Real vtot(0.); + Real divnc(0.); +#if (AMREX_SPACEDIM == 2) + int kk(0); +#else + for (int kk = -1; kk <= 1; kk++) +#endif + for (int jj = -1; jj <= 1; jj++) + for (int ii = -1; ii <= 1; ii++) + if ( (ii != 0 || jj != 0 || kk != 0) && flag(i,j,k).isConnected(ii,jj,kk) && + dbox.contains(IntVect(AMREX_D_DECL(i+ii,j+jj,k+kk)))) + { + Real unwted_frac = vfrac(i+ii,j+jj,k+kk) * mask(i+ii,j+jj,k+kk); + vtot += unwted_frac; + divnc += unwted_frac*divc(i+ii,j+jj,k+kk,n); + } + divnc /= vtot; + + // We need to multiply by mask to make sure optmp is zero for cells + // outside the domain for non-cyclic BCs + optmp(i,j,k,n) = (1 - vfrac(i,j,k)) * (divnc - divc(i,j,k,n)) * mask(i,j,k); + delm(i,j,k,n) = -( vfrac(i,j,k)) * optmp(i,j,k,n); + } else { + delm(i,j,k,n) = 0.; + } + }); + } + + // + // Step 3: redistribute excess/loss of mass + // + + amrex::ParallelFor(grown1_bx, ncomp, + [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept + { + bool valid_dst_cell; + if (flag(i,j,k).isSingleValued()) + { + Real wtot = Real(0.); +#if (AMREX_SPACEDIM == 2) + int kk(0); +#else + for (int kk = -1; kk <= 1; kk++) +#endif + for (int jj = -1; jj <= 1; jj++) + for (int ii = -1; ii <= 1; ii++) + if ( (ii != 0 || jj != 0 || kk != 0) && flag(i,j,k).isConnected(ii,jj,kk) ) + { + wtot += vfrac(i+ii,j+jj,k+kk)*wt(i+ii,j+jj,k+kk)* mask(i+ii,j+jj,k+kk); + } +#ifdef AMREX_USE_FLOAT + wtot = Real(1.0)/(wtot + Real(1.e-30)); +#else + wtot = Real(1.0)/(wtot + Real(1.e-80)); +#endif + + bool as_crse_crse_cell = false; + bool as_crse_covered_cell = false; + + if (as_crse) + { + bool inside = +#if (AMREX_SPACEDIM == 2) + ( (i >= bx_ilo) && (i <= bx_ihi) && (j >= bx_jlo) && (j <= bx_jhi) ); +#else + ( (i >= bx_ilo) && (i <= bx_ihi) && (j >= bx_jlo) && (j <= bx_jhi) && (k >= bx_klo) && (k <= bx_khi) ); +#endif + as_crse_crse_cell = inside && (rr_flag_crse(i,j,k) == amrex_yafluxreg_crse_fine_boundary_cell); + as_crse_covered_cell = (rr_flag_crse(i,j,k) == amrex_yafluxreg_fine_cell); + } + + bool as_fine_valid_cell = false; // valid cells near box boundary + bool as_fine_ghost_cell = false; // ghost cells just outside valid region + + if (as_fine) + { + bool inside = +#if (AMREX_SPACEDIM == 2) + ( (i >= bx_ilo) && (i <= bx_ihi) && (j >= bx_jlo) && (j <= bx_jhi) ); +#else + ( (i >= bx_ilo) && (i <= bx_ihi) && (j >= bx_jlo) && (j <= bx_jhi) && (k >= bx_klo) && (k <= bx_khi) ); +#endif + if (inside) as_fine_valid_cell = true; + as_fine_ghost_cell = (levmsk(i,j,k) == level_mask_not_covered); // not covered by other grids + } + +#if (AMREX_SPACEDIM == 2) + kk = 0; +#else + for (int kk = -1; kk <= 1; kk++) +#endif + for (int jj = -1; jj <= 1; jj++) + for (int ii = -1; ii <= 1; ii++) + if ( (ii != 0 || jj != 0 || kk != 0) && flag(i,j,k).isConnected(ii,jj,kk) ) + { + int iii = i + ii; + int jjj = j + jj; + int kkk = k + kk; + + Real drho = delm(i,j,k,n)*wtot*wt(iii,jjj,kkk)* mask(iii,jjj,kkk) ; + Gpu::Atomic::Add(&optmp(iii,jjj,kkk,n), drho); + + valid_dst_cell = ( (iii >= bx_ilo) && (iii <= bx_ihi) && + (jjj >= bx_jlo) && (jjj <= bx_jhi) ); +#if (AMREX_SPACEDIM == 3) + valid_dst_cell &= ( (kkk >= bx_klo) && (kkk <= bx_khi) ); +#endif + + if (as_crse_crse_cell) + { + if ( (rr_flag_crse(iii,jjj,kkk) == amrex_yafluxreg_fine_cell) && + (vfrac(i,j,k) > reredistribution_threshold) ) + { + Gpu::Atomic::Add(&rr_drho_crse(i,j,k,n), + dt*drho*(vfrac(iii,jjj,kkk)/vfrac(i,j,k))); + } + } + + if (as_crse_covered_cell && valid_dst_cell) + { + if ( (rr_flag_crse(iii,jjj,kkk) == amrex_yafluxreg_crse_fine_boundary_cell) && + (vfrac(iii,jjj,kkk) > reredistribution_threshold) ) + { + // recipient is a crse/fine boundary cell + Gpu::Atomic::Add(&rr_drho_crse(iii,jjj,kkk,n), -dt*drho); + } + } + + if (as_fine_valid_cell && !valid_dst_cell) + { + Gpu::Atomic::Add(&dm_as_fine(iii,jjj,kkk,n), dt*drho*vfrac(iii,jjj,kkk)); + } + + if (as_fine_ghost_cell && valid_dst_cell) + { + Gpu::Atomic::Add(&dm_as_fine(i,j,k,n), -dt*drho*vfrac(iii,jjj,kkk)); + } + + } // isConnected + } // isSingleValued + }); + + amrex::ParallelFor(bx, ncomp, + [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept + { + if (!flag(i,j,k).isCovered()) + dqdt(i,j,k,icomp+n) = divc(i,j,k,n) + optmp(i,j,k,n); + }); + + + Gpu::streamSynchronize(); // because of FArrayBoxes defined in this function +} // end amrex_flux_redistribute + +// +// Do small cell redistribution on one FAB with the Array4's already passed in +// +void +apply_flux_redistribution ( const Box& bx, + Array4 const& div, + Array4 const& divc, + Array4 const& wt, + int icomp, int ncomp, + Array4 const& flag_arr, + Array4 const& vfrac, + const Geometry & geom, + bool use_wts_in_divnc) +{ + int as_crse = 0; + int as_fine = 0; + Real dummy_dt = 0.0; + Array4 dummy_drho_crse = Array4(); + Array4 dummy_dm_as_fine = Array4(); + Array4 dummy_levmsk = Array4(); + Array4 dummy_flag_crse = Array4(); + int dummy_not_covered = 0; + amrex_flux_redistribute (bx, div, divc, wt, vfrac, flag_arr, + as_crse, dummy_drho_crse , dummy_flag_crse, + as_fine, dummy_dm_as_fine, dummy_levmsk, + geom, use_wts_in_divnc, dummy_not_covered, + icomp, ncomp, dummy_dt); +} +} // end namespace diff --git a/Src/EB/AMReX_EB_Redistribution.H b/Src/EB/AMReX_EB_Redistribution.H new file mode 100644 index 00000000000..a43c55aa605 --- /dev/null +++ b/Src/EB/AMReX_EB_Redistribution.H @@ -0,0 +1,170 @@ +#ifndef AMREX_EB_REDIST_H_ +#define AMREX_EB_REDIST_H_ +#include + +#include +#include +#include +#include +#include + +namespace amrex { + +#ifdef AMREX_USE_FLOAT + static constexpr amrex::Real eb_covered_val = amrex::Real(1.e20); +#else + static constexpr amrex::Real eb_covered_val = amrex::Real(1.e40); +#endif + + void single_level_redistribute (amrex::MultiFab& div_tmp_in, amrex::MultiFab& div_out, + int div_comp, int ncomp, const amrex::Geometry& geom); + + void single_level_weighted_redistribute (amrex::MultiFab& div_tmp_in, amrex::MultiFab& div_out, + const amrex::MultiFab& weights, + int div_comp, int ncomp, const amrex::Geometry& geom, + bool use_wts_in_divnc); + + // Flux redistribution scheme for case where C/F interface does *not* cross EB + void apply_flux_redistribution ( const amrex::Box& bx, + amrex::Array4 const& div, + amrex::Array4 const& divc, + amrex::Array4 const& wt, + int icomp, int ncomp, + amrex::Array4 const& flag_arr, + amrex::Array4 const& vfrac, + const amrex::Geometry & geom, + bool use_wts_in_divnc); + + // Flux redistribution scheme for case where C/F interface crosses EB + void amrex_flux_redistribute (const amrex::Box& bx, + amrex::Array4 const& dqdt, + amrex::Array4 const& divc, + amrex::Array4 const& wt, + amrex::Array4 const& vfrac, + amrex::Array4 const& flag, + int as_crse, + amrex::Array4 const& rr_drho_crse, + amrex::Array4 const& rr_flag_crse, + int as_fine, + amrex::Array4 const& dm_as_fine, + amrex::Array4 const& levmsk, + const amrex::Geometry & geom, + bool use_wts_in_divnc, + int level_mask_not_covered, + int icomp, int ncomp, amrex::Real dt); + + // Interface to redistribution schemes that only calls single-level routines + void ApplyRedistribution ( amrex::Box const& bx, int ncomp, + amrex::Array4 const& dUdt_out, + amrex::Array4 const& dUdt_in, + amrex::Array4 const& U_in, + amrex::Array4 const& scratch, + amrex::Array4 const& flag, + AMREX_D_DECL(amrex::Array4 const& apx, + amrex::Array4 const& apy, + amrex::Array4 const& apz), + amrex::Array4 const& vfrac, + AMREX_D_DECL(amrex::Array4 const& fcx, + amrex::Array4 const& fcy, + amrex::Array4 const& fcz), + amrex::Array4 const& ccc, + amrex::BCRec const* d_bcrec_ptr, + amrex::Geometry const& lev_geom, + amrex::Real dt, std::string const& redistribution_type, + bool use_wts_in_divnc = false, + int srd_max_order = 2, + amrex::Real target_volfrac = 0.5_rt, + amrex::Array4 const& update_scale={}); + + // Interface to redistribution schemes that calls multi-level routines + void ApplyMLRedistribution ( + amrex::Box const& bx, int ncomp, + amrex::Array4 const& dUdt_out, + amrex::Array4 const& dUdt_in, + amrex::Array4 const& U_in, + amrex::Array4 const& wt, + amrex::Array4 const& flag, + AMREX_D_DECL(amrex::Array4 const& apx, + amrex::Array4 const& apy, + amrex::Array4 const& apz), + amrex::Array4 const& vfrac, + AMREX_D_DECL(amrex::Array4 const& fcx, + amrex::Array4 const& fcy, + amrex::Array4 const& fcz), + amrex::Array4 const& ccc, + amrex::BCRec const* d_bcrec_ptr, + amrex::Geometry const& lev_geom, amrex::Real dt, + std::string const& redistribution_type, + int as_crse, + amrex::Array4 const& rr_drho_crse, + amrex::Array4 const& rr_flag_crse, + int as_fine, + amrex::Array4 const& dm_as_fine, + amrex::Array4 const& levmsk, + int level_mask_not_covered, + bool use_wts_in_divnc = false, + int icomp = 0, + int srd_max_order = 2, + amrex::Real target_volfrac = 0.5_rt, + amrex::Array4 const& update_scale={}); + + void ApplyInitialRedistribution ( + amrex::Box const& bx, int ncomp, + amrex::Array4 const& U_out, + amrex::Array4 const& U_in, + amrex::Array4 const& flag, + AMREX_D_DECL(amrex::Array4 const& apx, + amrex::Array4 const& apy, + amrex::Array4 const& apz), + amrex::Array4 const& vfrac, + AMREX_D_DECL(amrex::Array4 const& fcx, + amrex::Array4 const& fcy, + amrex::Array4 const& fcz), + amrex::Array4 const& ccc, + amrex::BCRec const* d_bcrec_ptr, + amrex::Geometry const& geom, std::string const& redistribution_type, + int srd_max_order = 2, + amrex::Real target_volfrac = 0.5_rt); + + void StateRedistribute ( amrex::Box const& bx, int ncomp, + amrex::Array4 const& U_out, + amrex::Array4 const& U_in, + amrex::Array4 const& flag, + amrex::Array4 const& vfrac, + AMREX_D_DECL(amrex::Array4 const& fcx, + amrex::Array4 const& fcy, + amrex::Array4 const& fcz), + amrex::Array4 const& ccent, + amrex::BCRec const* d_bcrec_ptr, + amrex::Array4 const& itracker, + amrex::Array4 const& nrs, + amrex::Array4 const& alpha, + amrex::Array4 const& nbhd_vol, + amrex::Array4 const& cent_hat, + amrex::Geometry const& geom, + int max_order = 2); + + void MakeITracker ( amrex::Box const& bx, + AMREX_D_DECL(amrex::Array4 const& apx, + amrex::Array4 const& apy, + amrex::Array4 const& apz), + amrex::Array4 const& vfrac, + amrex::Array4 const& itracker, + amrex::Geometry const& geom, + amrex::Real target_volfrac); + + void MakeStateRedistUtils ( amrex::Box const& bx, + amrex::Array4 const& flag, + amrex::Array4 const& vfrac, + amrex::Array4 const& ccent, + amrex::Array4< int const> const& itracker, + amrex::Array4 const& nrs, + amrex::Array4 const& alpha, + amrex::Array4 const& nbhd_vol, + amrex::Array4 const& cent_hat, + amrex::Geometry const& geom, + amrex::Real target_volfrac); + +} + +#endif diff --git a/Src/EB/AMReX_EB_Redistribution.cpp b/Src/EB/AMReX_EB_Redistribution.cpp new file mode 100644 index 00000000000..28fd8b70776 --- /dev/null +++ b/Src/EB/AMReX_EB_Redistribution.cpp @@ -0,0 +1,111 @@ +#include +#include +#include +#include +#include +#include +#include + +namespace amrex { + +#if (AMREX_SPACEDIM > 1) + // + // Do small cell redistribution on one FAB + // + void apply_eb_redistribution ( const Box& bx, + MultiFab& div_mf, + MultiFab& divc_mf, + const MultiFab& weights, + MFIter* mfi, + int icomp, + int ncomp, + const EBCellFlagFab& flags_fab, + const MultiFab* volfrac, + Box& /*domain*/, + const Geometry & geom, + bool use_wts_in_divnc) + { + // + // Check that grid is uniform + // + const Real* dx = geom.CellSize(); + +#if (AMREX_SPACEDIM == 2) + if (! amrex::almostEqual(dx[0], dx[1])) + amrex::Abort("apply_eb_redistribution(): grid spacing must be uniform"); +#elif (AMREX_SPACEDIM == 3) + if( ! amrex::almostEqual(dx[0],dx[1]) || + ! amrex::almostEqual(dx[1],dx[2]) ) + amrex::Abort("apply_eb_redistribution(): grid spacing must be uniform"); +#endif + + // + // Get array4 from arguments + // + Array4 const& div = div_mf.array(*mfi); + Array4 const& divc = divc_mf.array(*mfi); + auto const& wt = weights.array(*mfi); + auto const& flags = flags_fab.array(); + auto const& vfrac = volfrac->array(*mfi); + + apply_flux_redistribution ( bx, div, divc, wt, icomp, ncomp, flags, vfrac, geom, use_wts_in_divnc); + } + + // + // Do small cell redistribution on a MultiFab -- with a weighting function + // + void single_level_weighted_redistribute (MultiFab& div_tmp_in, MultiFab& div_out, const MultiFab& weights, + int div_comp, int ncomp, const Geometry& geom, bool use_wts_in_divnc) + { + Box domain(geom.Domain()); + + int nghost = 2; + AMREX_ASSERT(div_tmp_in.nGrow() >= nghost); + + EB_set_covered(div_tmp_in, 0, ncomp, div_tmp_in.nGrow(), eb_covered_val); + + div_tmp_in.FillBoundary(geom.periodicity()); + + // Here we take care of both the regular and covered cases ... all we do below is the cut cell cases + MultiFab::Copy(div_out, div_tmp_in, 0, div_comp, ncomp, 0); + + // Get EB geometric info + const auto& ebfactory = dynamic_cast(div_out.Factory()); + const MultiFab* volfrac = &(ebfactory. getVolFrac()); + + for (MFIter mfi(div_out,TilingIfNotGPU()); mfi.isValid(); ++mfi) + { + // Tilebox + const Box& bx = mfi.tilebox (); + + // this is to check efficiently if this tile contains any eb stuff + const auto& div_fab = static_cast(div_out[mfi]); + const EBCellFlagFab& flags = div_fab.getEBCellFlagFab(); + + if ( !(flags.getType(amrex::grow(bx, 0)) == FabType::covered) && + !(flags.getType(amrex::grow(bx,nghost)) == FabType::regular) ) + { + // Compute div(tau) with EB algorithm + apply_eb_redistribution(bx, div_out, div_tmp_in, weights, &mfi, + div_comp, ncomp, flags, volfrac, domain, geom, use_wts_in_divnc); + + } + } + } + + // + // Do small cell redistribution on a MultiFab -- without a weighting function + // + void single_level_redistribute (MultiFab& div_tmp_in, MultiFab& div_out, + int div_comp, int ncomp, const Geometry& geom) + { + // We create a weighting array to use inside the redistribution array + MultiFab weights(div_out.boxArray(), div_out.DistributionMap(), 1, div_tmp_in.nGrow()); + weights.setVal(1.0); + + bool use_wts_in_divnc = false; + single_level_weighted_redistribute (div_tmp_in, div_out, weights, div_comp, ncomp, geom, use_wts_in_divnc); + } +#endif + +} // end namespace diff --git a/Src/EB/AMReX_EB_RedistributionApply.cpp b/Src/EB/AMReX_EB_RedistributionApply.cpp new file mode 100644 index 00000000000..d7c26a69378 --- /dev/null +++ b/Src/EB/AMReX_EB_RedistributionApply.cpp @@ -0,0 +1,325 @@ +/** + * \file AMReX_EB_RedistributionApply.cpp + * @{ + * + */ + +#include +#include + +namespace amrex { + +void ApplyRedistribution ( Box const& bx, int ncomp, + Array4 const& dUdt_out, + Array4 const& dUdt_in, + Array4 const& U_in, + Array4 const& scratch, + Array4 const& flag, + AMREX_D_DECL(Array4 const& apx, + Array4 const& apy, + Array4 const& apz), + Array4 const& vfrac, + AMREX_D_DECL(Array4 const& fcx, + Array4 const& fcy, + Array4 const& fcz), + Array4 const& ccc, + amrex::BCRec const* d_bcrec_ptr, + Geometry const& lev_geom, Real dt, + std::string const& redistribution_type, + bool use_wts_in_divnc, + int srd_max_order, + amrex::Real target_volfrac, + Array4 const& srd_update_scale) +{ + // redistribution_type = "NoRedist"; // no redistribution + // redistribution_type = "FluxRedist" // flux_redistribute + // redistribution_type = "StateRedist"; // (weighted) state redistribute + + // amrex::Print() <<" Redistribution::Apply " << redistribution_type << std::endl; + + amrex::ParallelFor(bx,ncomp, + [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept + { + dUdt_out(i,j,k,n) = 0.; + }); + + if (redistribution_type == "FluxRedist") + { + int icomp = 0; + apply_flux_redistribution (bx, dUdt_out, dUdt_in, scratch, icomp, ncomp, flag, vfrac, lev_geom, + use_wts_in_divnc); + + } else if (redistribution_type == "StateRedist") { + + Box const& bxg1 = grow(bx,1); + Box const& bxg2 = grow(bx,2); + Box const& bxg3 = grow(bx,3); + Box const& bxg4 = grow(bx,4); + +#if (AMREX_SPACEDIM == 2) + // We assume that in 2D a cell will only need at most 3 neighbors to merge with, and we + // use the first component of this for the number of neighbors + IArrayBox itracker(bxg4,4,The_Async_Arena()); + // How many nbhds is a cell in +#else + // We assume that in 3D a cell will only need at most 7 neighbors to merge with, and we + // use the first component of this for the number of neighbors + IArrayBox itracker(bxg4,8,The_Async_Arena()); +#endif + FArrayBox nrs_fab(bxg3,1,The_Async_Arena()); + FArrayBox alpha_fab(bxg3,2,The_Async_Arena()); + + // Total volume of all cells in my nbhd + FArrayBox nbhd_vol_fab(bxg2,1,The_Async_Arena()); + + // Centroid of my nbhd + FArrayBox cent_hat_fab(bxg3,AMREX_SPACEDIM,The_Async_Arena()); + + Array4 itr = itracker.array(); + Array4 itr_const = itracker.const_array(); + + Array4 nrs = nrs_fab.array(); + Array4 nrs_const = nrs_fab.const_array(); + + Array4 alpha = alpha_fab.array(); + Array4 alpha_const = alpha_fab.const_array(); + + Array4 nbhd_vol = nbhd_vol_fab.array(); + Array4 nbhd_vol_const = nbhd_vol_fab.const_array(); + + Array4 cent_hat = cent_hat_fab.array(); + Array4 cent_hat_const = cent_hat_fab.const_array(); + + Box domain_per_grown = lev_geom.Domain(); + AMREX_D_TERM(if (lev_geom.isPeriodic(0)) domain_per_grown.grow(0,1);, + if (lev_geom.isPeriodic(1)) domain_per_grown.grow(1,1);, + if (lev_geom.isPeriodic(2)) domain_per_grown.grow(2,1);); + + // At any external Dirichlet domain boundaries we need to set dUdt_in to 0 + // in the cells just outside the domain because those values will be used + // in the slope computation in state redistribution. We assume here that + // the ext_dir values of U_in itself have already been set. + if (!domain_per_grown.contains(bxg1)) + amrex::ParallelFor(bxg1,ncomp, + [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept + { + if (!domain_per_grown.contains(IntVect(AMREX_D_DECL(i,j,k)))) + dUdt_in(i,j,k,n) = 0.; + }); + + amrex::ParallelFor(Box(scratch), ncomp, + [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept + { + const Real scale = (srd_update_scale) ? srd_update_scale(i,j,k) : Real(1.0); + scratch(i,j,k,n) = U_in(i,j,k,n) + dt * dUdt_in(i,j,k,n) / scale; + } + ); + + MakeITracker(bx, AMREX_D_DECL(apx, apy, apz), vfrac, itr, lev_geom, target_volfrac); + + MakeStateRedistUtils(bx, flag, vfrac, ccc, itr, nrs, alpha, nbhd_vol, cent_hat, + lev_geom, target_volfrac); + + StateRedistribute(bx, ncomp, dUdt_out, scratch, flag, vfrac, + AMREX_D_DECL(fcx, fcy, fcz), ccc, d_bcrec_ptr, + itr_const, nrs_const, alpha_const, nbhd_vol_const, + cent_hat_const, lev_geom, srd_max_order); + + amrex::ParallelFor(bx, ncomp, + [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept + { + // Only update the values which actually changed -- this makes + // the results insensitive to tiling -- otherwise cells that aren't + // changed but are in a tile on which StateRedistribute gets called + // will have precision-level changes due to adding/subtracting U_in + // and multiplying/dividing by dt. Here we test on whether (i,j,k) + // has at least one neighbor and/or whether (i,j,k) is in the + // neighborhood of another cell -- if either of those is true the + // value may have changed + + if (itr(i,j,k,0) > 0 || nrs(i,j,k) > 1.) + { + const Real scale = (srd_update_scale) ? srd_update_scale(i,j,k) : Real(1.0); + + dUdt_out(i,j,k,n) = scale * (dUdt_out(i,j,k,n) - U_in(i,j,k,n)) / dt; + + } + else + { + dUdt_out(i,j,k,n) = dUdt_in(i,j,k,n); + } + } + ); + + } else if (redistribution_type == "NoRedist") { + amrex::ParallelFor(bx, ncomp, + [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept + { + dUdt_out(i,j,k,n) = dUdt_in(i,j,k,n); + } + ); + + } else { + amrex::Error("Not a legit redist_type"); + } +} + +void +ApplyMLRedistribution ( Box const& bx, int ncomp, + Array4 const& dUdt_out, + Array4 const& dUdt_in, + Array4 const& U_in, + Array4 const& wt, + Array4 const& flag, + AMREX_D_DECL(Array4 const& apx, + Array4 const& apy, + Array4 const& apz), + Array4 const& vfrac, + AMREX_D_DECL(Array4 const& fcx, + Array4 const& fcy, + Array4 const& fcz), + Array4 const& ccc, + amrex::BCRec const* d_bcrec_ptr, + Geometry const& lev_geom, Real dt, + std::string const& redistribution_type, + int as_crse, + Array4 const& rr_drho_crse, + Array4 const& rr_flag_crse, + int as_fine, + Array4 const& dm_as_fine, + Array4 const& levmsk, + int level_mask_not_covered, + bool use_wts_in_divnc, + int icomp, + int srd_max_order, + amrex::Real target_volfrac, + Array4 const& srd_update_scale) +{ + // redistribution_type = "NoRedist"; // no redistribution + // redistribution_type = "FluxRedist" // flux_redistribute + // redistribution_type = "StateRedist"; // (weighted) state redistribute + + // amrex::Print() <<" Redistribution::ApplyML " << redistribution_type << std::endl; + + amrex::ParallelFor(bx,ncomp, + [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept + { + dUdt_out(i,j,k,n) = 0.; + }); + + if (redistribution_type == "FluxRedist") + { + // This is the re-redistribution version of FluxRedistribution + amrex_flux_redistribute (bx, dUdt_out, dUdt_in, wt, vfrac, flag, + as_crse, rr_drho_crse, rr_flag_crse, + as_fine, dm_as_fine, levmsk, lev_geom, + use_wts_in_divnc, level_mask_not_covered, icomp, ncomp, dt); + + } else if (redistribution_type == "StateRedist") { + + // Currently we don't have the re-redistribution version of StateRedistribution + // This is a work in progress so for now we use only the non-re-re version + ApplyRedistribution (bx, ncomp, dUdt_out, dUdt_in, U_in, wt, flag, + AMREX_D_DECL(apx, apy, apz), vfrac, + AMREX_D_DECL(fcx, fcy, fcz), ccc, + d_bcrec_ptr, lev_geom, dt, + redistribution_type, + use_wts_in_divnc, + srd_max_order, + target_volfrac, + srd_update_scale); + + } else if (redistribution_type == "NoRedist") { + amrex::ParallelFor(bx, ncomp, + [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept + { + dUdt_out(i,j,k,n) = dUdt_in(i,j,k,n); + } + ); + + } else { + amrex::Error("Not a legit redist_type in ApplyML"); + } +} + +void +ApplyInitialRedistribution ( Box const& bx, int ncomp, + Array4 const& U_out, + Array4 const& U_in, + Array4 const& flag, + AMREX_D_DECL(amrex::Array4 const& apx, + amrex::Array4 const& apy, + amrex::Array4 const& apz), + amrex::Array4 const& vfrac, + AMREX_D_DECL(amrex::Array4 const& fcx, + amrex::Array4 const& fcy, + amrex::Array4 const& fcz), + amrex::Array4 const& ccc, + amrex::BCRec const* d_bcrec_ptr, + Geometry const& lev_geom, + std::string const& redistribution_type, + int srd_max_order, + amrex::Real target_volfrac) +{ + if (redistribution_type != "StateRedist") { + std::string msg = "ApplyInitialRedistribution: Shouldn't be here with redist type "+redistribution_type; + amrex::Error(msg); + } + + // amrex::Print() <<" Redistribution::ApplyInitial " << redistribution_type << std::endl; + + Box const& bxg2 = grow(bx,2); + Box const& bxg3 = grow(bx,3); + Box const& bxg4 = grow(bx,4); + +#if (AMREX_SPACEDIM == 2) + // We assume that in 2D a cell will only need at most 3 neighbors to merge with, and we + // use the first component of this for the number of neighbors + IArrayBox itracker(bxg4,4,The_Async_Arena()); +#else + // We assume that in 3D a cell will only need at most 7 neighbors to merge with, and we + // use the first component of this for the number of neighbors + IArrayBox itracker(bxg4,8,The_Async_Arena()); +#endif + FArrayBox nrs_fab(bxg3,1,The_Async_Arena()); + FArrayBox alpha_fab(bxg3,2,The_Async_Arena()); + + // Total volume of all cells in my nbhd + FArrayBox nbhd_vol_fab(bxg2,1,The_Async_Arena()); + + // Centroid of my nbhd + FArrayBox cent_hat_fab(bxg3,AMREX_SPACEDIM,The_Async_Arena()); + + Array4 itr = itracker.array(); + Array4 itr_const = itracker.const_array(); + + Array4 nrs = nrs_fab.array(); + Array4 nrs_const = nrs_fab.const_array(); + + Array4 alpha = alpha_fab.array(); + Array4 alpha_const = alpha_fab.const_array(); + + Array4 nbhd_vol = nbhd_vol_fab.array(); + Array4 nbhd_vol_const = nbhd_vol_fab.const_array(); + + Array4 cent_hat = cent_hat_fab.array(); + Array4 cent_hat_const = cent_hat_fab.const_array(); + + amrex::ParallelFor(bx,ncomp, + [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept + { + U_out(i,j,k,n) = 0.; + }); + + MakeITracker(bx, AMREX_D_DECL(apx, apy, apz), vfrac, itr, lev_geom, target_volfrac); + + MakeStateRedistUtils(bx, flag, vfrac, ccc, itr, nrs, alpha, nbhd_vol, cent_hat, + lev_geom, target_volfrac); + + StateRedistribute(bx, ncomp, U_out, U_in, flag, vfrac, + AMREX_D_DECL(fcx, fcy, fcz), ccc, d_bcrec_ptr, + itr_const, nrs_const, alpha_const, nbhd_vol_const, + cent_hat_const, lev_geom, srd_max_order); +} + +} diff --git a/Src/EB/AMReX_EB_Slopes_2D_K.H b/Src/EB/AMReX_EB_Slopes_2D_K.H new file mode 100644 index 00000000000..7bc346c04a7 --- /dev/null +++ b/Src/EB/AMReX_EB_Slopes_2D_K.H @@ -0,0 +1,886 @@ +#ifndef AMREX_HYDRO_EB_SLOPES_2D_K_H_ +#define AMREX_HYDRO_EB_SLOPES_2D_K_H_ + +#include +#include + +#include +#include + +namespace { + +// amrex_calc_slopes_eb calculates the slope in each coordinate direction using a +// least squares linear fit to the 8 nearest neighbors, with the function +// going through the centroid of cell(i,j,k). This does not assume that the cell centroids, +// where the data is assume to live, are the same as cell centers. Note that this routine +// is called either by amrex_calc_slopes_eb or amrex_calc_slopes_extdir_eb; in the former +// A is defined with the cell centroids; in the latter, the A values corresponding to values +// defined on faces use the face centroid location. +// +AMREX_GPU_DEVICE AMREX_FORCE_INLINE +amrex::GpuArray +amrex_calc_slopes_eb_given_A (int i, int j, int /*k*/, int n, + amrex::Real A[9][AMREX_SPACEDIM], + amrex::Array4 const& state, + amrex::Array4 const& flag) noexcept +{ + constexpr int dim_a = 9; + amrex::Real du[dim_a]; + + int ll=0; + for(int jj(-1); jj<=1; jj++){ + for(int ii(-1); ii<=1; ii++){ + if( flag(i,j,0).isConnected(ii,jj,0) && + ! (ii==0 && jj==0)) { + du[ll] = state(i+ii,j+jj,0,n) - state(i,j,0,n); + } else { + du[ll] = amrex::Real(0.0); + } + ll++; + } + } + + amrex::Real AtA[AMREX_SPACEDIM][AMREX_SPACEDIM]; + amrex::Real Atb[AMREX_SPACEDIM]; + + for(int jj(0); jj +amrex_calc_slopes_eb_given_A_grown (int i, int j, int /*k*/, int n, int nx, int ny, + amrex::Real A[25][AMREX_SPACEDIM], + amrex::Array4 const& state, + amrex::Array4 const& flag) noexcept +{ + AMREX_ASSERT(nx == 1 || nx == 2); + AMREX_ASSERT(ny == 1 || ny == 2); + + constexpr int dim_a = 25; + + amrex::Real AtA[AMREX_SPACEDIM][AMREX_SPACEDIM]; + amrex::Real Atb[AMREX_SPACEDIM]; + + for(int jj(0); jj const& state, + amrex::Array4 const& vfrac, + int max_order) noexcept +{ + // + // Here we over-write -- if possible -- with a stencil not using the EB stencil + // + AMREX_ALWAYS_ASSERT( max_order == 0 || max_order == 2 || max_order == 4); + + // We have enough cells in the x-direction to do 4th order slopes + // centered on (i,j,k) with all values at cell centers + if (max_order == 4 && + vfrac(i,j,k) == 1. && vfrac(i-1,j,k) == 1. && vfrac(i-2,j,k) == 1. && + vfrac(i+1,j,k) == 1. && vfrac(i+2,j,k) == 1.) + { + int order = 4; + xslope = amrex_calc_xslope(i,j,k,n,order,state); + } + // We have enough cells in the x-direction to do 2nd order slopes + // centered on (i,j,k) with all values at cell centers + else if (max_order > 0 && vfrac(i,j,k) == 1. && vfrac(i-1,j,k) == 1. && vfrac(i+1,j,k) == 1.) + { + int order = 2; + xslope = amrex_calc_xslope(i,j,k,n,order,state); + } else if (max_order == 0) { + xslope = 0.; + } + + // We have enough cells in the y-direction to do 4th order slopes + // centered on (i,j,k) with all values at cell centers + if (max_order == 4 && + vfrac(i,j,k) == 1. && vfrac(i,j-1,k) == 1. && vfrac(i,j-2,k) == 1. && + vfrac(i,j+1,k) == 1. && vfrac(i,j+2,k) == 1.) + { + int order = 4; + yslope = amrex_calc_yslope(i,j,k,n,order,state); + } + // We have enough cells in the y-direction to do 2nd order slopes + // centered on (i,j,k) with all values at cell centers + else if (max_order > 0 && vfrac(i,j,k) == 1. && vfrac(i,j-1,k) == 1. && vfrac(i,j+1,k) == 1.) + { + int order = 2; + yslope = amrex_calc_yslope(i,j,k,n,order,state); + } else if (max_order == 0) { + yslope = 0.; + } +} + +// amrex_calc_slopes_eb calculates the slope in each coordinate direction using a +// 1) standard limited slope if all three cells in the stencil are regular cells +// OR +// 2) least squares linear fit to the at-most 8 nearest neighbors, with the function +// going through the centroid of cell(i,j,k). This does not assume that the cell centroids, +// where the data is assume to live, are the same as cell centers. Note that calc_slopes_eb +// defines the matrix A and passes this A to amrex_calc_slopes_eb_given_A. +// +// This routine assumes that there are no relevant hoextrap/extdir domain boundary conditions for this cell -- +// it does not test for them so this should not be called if such boundaries might be present +// +AMREX_GPU_DEVICE AMREX_FORCE_INLINE +amrex::GpuArray +amrex_calc_slopes_eb (int i, int j, int k, int n, + amrex::Array4 const& state, + amrex::Array4 const& ccent, + amrex::Array4 const& vfrac, + amrex::Array4 const& flag, + int max_order) noexcept +{ + constexpr int dim_a = 9; + amrex::Real A[dim_a][AMREX_SPACEDIM]; + + int lc=0; + int kk = 0; + { + for(int jj(-1); jj<=1; jj++){ + for(int ii(-1); ii<=1; ii++){ + + if( flag(i,j,k).isConnected(ii,jj,kk) && + ! (ii==0 && jj==0 && kk==0)) { + + // Not multiplying by dx to be consistent with how the + // slope is stored. Also not including the global shift + // wrt plo or i,j,k. We only need relative distance. + + A[lc][0] = amrex::Real(ii) + ccent(i+ii,j+jj,k+kk,0) - ccent(i,j,k,0); + A[lc][1] = amrex::Real(jj) + ccent(i+ii,j+jj,k+kk,1) - ccent(i,j,k,1); + + } else { + + A[lc][0] = amrex::Real(0.0); + A[lc][1] = amrex::Real(0.0); + } + lc++; + } + } + } + + const auto& eb_slopes = amrex_calc_slopes_eb_given_A (i,j,k,n,A,state,flag); + + amrex::Real xslope = eb_slopes[0]; + amrex::Real yslope = eb_slopes[1]; + + // This will over-write the values of xslope and yslope if appropriate + amrex_overwrite_with_regular_slopes(i,j,k,n,xslope,yslope,state,vfrac,max_order); + + return {xslope,yslope}; +} + +// amrex_calc_slopes_eb_grown calculates the slope in each coordinate direction using a +// 1) standard limited slope if all three cells in the stencil are regular cells +// OR +// 2) least squares linear fit to the at-most 24 nearest neighbors, with the function +// going through the centroid of cell(i,j,k). This does not assume that the cell centroids, +// where the data is assume to live, are the same as cell centers. Note that calc_slopes_eb_grown +// defines the matrix A and passes this A to amrex_calc_slopes_eb_given_A_grown. +// +// This routine assumes that there are no relevant hoextrap/extdir domain boundary conditions for this cell -- +// it does not test for them so this should not be called if such boundaries might be present +// +AMREX_GPU_DEVICE AMREX_FORCE_INLINE +amrex::GpuArray +amrex_calc_slopes_eb_grown (int i, int j, int k, int n, int nx, int ny, + amrex::Array4 const& state, + amrex::Array4 const& ccent, + amrex::Array4 const& vfrac, + amrex::Array4 const& flag, + int max_order) noexcept +{ + AMREX_ASSERT(nx == 1 || nx == 2); + AMREX_ASSERT(ny == 1 || ny == 2); + + constexpr int dim_a = 25; + amrex::Real A[dim_a][AMREX_SPACEDIM]; + + int kk = 0; + { + // Make sure to zero all the entries in A (since the loop below may not cover all 25) + int lc=0; + for(int jj(-2); jj<=2; jj++){ + for(int ii(-2); ii<=2; ii++){ + A[lc][0] = amrex::Real(0.0); + A[lc][1] = amrex::Real(0.0); + lc++; + } + } + + lc=0; + for(int jj(-ny); jj<=ny; jj++){ + for(int ii(-nx); ii<=nx; ii++){ + + if(!flag(i+ii,j+jj,k+kk).isCovered() && !(ii==0 && jj==0 && kk==0)) + { + A[lc][0] = amrex::Real(ii) + ccent(i+ii,j+jj,k+kk,0) - ccent(i,j,k,0); + A[lc][1] = amrex::Real(jj) + ccent(i+ii,j+jj,k+kk,1) - ccent(i,j,k,1); + } + lc++; + } + } + } + + const auto& eb_slopes = amrex_calc_slopes_eb_given_A_grown (i,j,k,n,nx,ny,A,state,flag); + + amrex::Real xslope = eb_slopes[0]; + amrex::Real yslope = eb_slopes[1]; + + // This will over-write the values of xslope and yslope if appropriate + amrex_overwrite_with_regular_slopes(i,j,k,n,xslope,yslope,state,vfrac,max_order); + + return {xslope,yslope}; +} + +// +// amrex_overwrite_with_regular_slopes_extdir calculates the slope in each coordinate direction +// with a standard non-EB slope calculation (that depends on max_order) +// +AMREX_GPU_DEVICE AMREX_FORCE_INLINE +void +amrex_overwrite_with_regular_slopes_extdir(int i, int j, int k, int n, + amrex::Real& xslope, amrex::Real& yslope, + amrex::Array4 const& state, + amrex::Array4 const& vfrac, + bool edlo_x, bool edlo_y, bool edhi_x, bool edhi_y, + int domlo_x, int domlo_y, int domhi_x, int domhi_y, + int max_order) noexcept +{ + // + // Correct only those cells which are affected by extdir but not by EB: + // 2) If all the cells are regular we use the "regular slope" in the extdir direction + // + + // We have enough cells in the x-direction to do 4th order slopes + // centered on (i,j,k) with all values at cell centers + if (max_order == 4 && + vfrac(i,j,k) == 1. && vfrac(i-1,j,k) == 1. && vfrac(i-2,j,k) == 1. && + vfrac(i+1,j,k) == 1. && vfrac(i+2,j,k) == 1.) + { + int order = 4; + xslope = amrex_calc_xslope_extdir(i,j,k,n,order,state,edlo_x,edhi_x,domlo_x,domhi_x); + } + // We have enough cells in the x-direction to do 2nd order slopes + // centered on (i,j,k) with all values at cell centers + else if (max_order > 0 && vfrac(i,j,k) == 1. && vfrac(i-1,j,k) == 1. && vfrac(i+1,j,k) == 1.) + { + int order = 2; + xslope = amrex_calc_xslope_extdir(i,j,k,n,order,state,edlo_x,edhi_x,domlo_x,domhi_x); + } else if (max_order == 0) { + xslope = 0.; + } + + // We have enough cells in the y-direction to do 4th order slopes + // centered on (i,j,k) with all values at cell centers + if (max_order == 4 && + vfrac(i,j,k) == 1. && vfrac(i,j-1,k) == 1. && vfrac(i,j-2,k) == 1. && + vfrac(i,j+1,k) == 1. && vfrac(i,j+2,k) == 1.) + { + int order = 4; + yslope = amrex_calc_yslope_extdir(i,j,k,n,order,state,edlo_y,edhi_y,domlo_y,domhi_y); + } + // We have enough cells in the y-direction to do 2nd order slopes + // centered on (i,j,k) with all values at cell centers + else if (max_order > 0 && vfrac(i,j,k) == 1. && vfrac(i,j-1,k) == 1. && vfrac(i,j+1,k) == 1.) + { + int order = 2; + yslope = amrex_calc_yslope_extdir(i,j,k,n,order,state,edlo_y,edhi_y,domlo_y,domhi_y); + } else if (max_order == 0) { + yslope = 0.; + } +} + +// amrex_calc_slopes_extdir_eb calculates the slope in each coordinate direction using a +// 1) standard limited slope if all three cells in the stencil are regular cells +// (this stencil sees the extdir/hoextrap boundary condition if there is one) +// OR +// 2) least squares linear fit to the at-most 8 nearest neighbors, with the function +// going through the centroid of cell(i,j,k). This does not assume that the cell centroids, +// where the data is assume to live, are the same as cell centers. +// +AMREX_GPU_DEVICE AMREX_FORCE_INLINE +amrex::GpuArray +amrex_calc_slopes_extdir_eb (int i, int j, int k, int n, + amrex::Array4 const& state, + amrex::Array4 const& ccent, + amrex::Array4 const& vfrac, + amrex::Array4 const& fcx, + amrex::Array4 const& fcy, + amrex::Array4 const& flag, + bool edlo_x, bool edlo_y, bool edhi_x, bool edhi_y, + int domlo_x, int domlo_y, int domhi_x, int domhi_y, + int max_order) noexcept +{ + constexpr int dim_a = 9; + + auto xslope = amrex::Real(0.0); + auto yslope = amrex::Real(0.0); + + // First get EB-aware slope that doesn't know about extdir + bool needs_bdry_stencil = (edlo_x && i <= domlo_x) || (edhi_x && i >= domhi_x) || + (edlo_y && j <= domlo_y) || (edhi_y && j >= domhi_y); + + // + // This call does not have any knowledge of extdir / hoextrap boundary conditions + // + if (!needs_bdry_stencil) + { + // This returns slopes calculated with the regular 1-d approach if all cells in the stencil + // are regular. If not, it uses the EB-aware least squares approach to fit a linear profile + // using the neighboring un-covered cells. + const auto& slopes = amrex_calc_slopes_eb (i,j,k,n,state,ccent,vfrac,flag,max_order); + return slopes; + + } else { + + amrex::Real A[dim_a][AMREX_SPACEDIM]; + + int lc=0; + int kk = 0; + { + for(int jj(-1); jj<=1; jj++) + for(int ii(-1); ii<=1; ii++) + { + if( flag(i,j,k).isConnected(ii,jj,kk) && + ! (ii==0 && jj==0 && kk==0)) + { + bool ilo_test = ( edlo_x && (i == domlo_x) && ii == -1); + bool ihi_test = ( edhi_x && (i == domhi_x) && ii == 1); + + bool jlo_test = ( edlo_y && (j == domlo_y) && jj == -1); + bool jhi_test = ( edhi_y && (j == domhi_y) && jj == 1); + + bool klo_test = false; + bool khi_test = false; + + // These are the default values if no physical boundary + A[lc][0] = amrex::Real(ii) + ccent(i+ii,j+jj,k+kk,0); + A[lc][1] = amrex::Real(jj) + ccent(i+ii,j+jj,k+kk,1); + // Do corrections for entire x-face + if (ilo_test) + { + if (!jlo_test && !jhi_test && !klo_test && !khi_test) + { + A[lc][1] = amrex::Real(jj) + fcx(i ,j+jj,k+kk,0); + } + A[lc][0] = amrex::Real(-0.5) ; + } else if (ihi_test) { + + if (!jlo_test && !jhi_test && !klo_test && !khi_test) + { + A[lc][1] = amrex::Real(jj) + fcx(i+ii,j+jj,k+kk,0); + } + A[lc][0] = amrex::Real(0.5) ; + } + + // Do corrections for entire y-face + if (jlo_test) + { + if (!ilo_test && !ihi_test && !klo_test && !khi_test) + { + A[lc][0] = amrex::Real(ii) + fcy(i+ii,j ,k+kk,0); + } + A[lc][1] = amrex::Real(-0.5) ; + + } else if (jhi_test) { + + if (!ilo_test && !ihi_test && !klo_test && !khi_test) + { + A[lc][0] = amrex::Real(ii) + fcy(i+ii,j+jj,k+kk,0); + } + A[lc][1] = amrex::Real(0.5) ; + } + + A[lc][0] -= ccent(i,j,k,0); + A[lc][1] -= ccent(i,j,k,1); + + } else { + A[lc][0] = amrex::Real(0.0); + A[lc][1] = amrex::Real(0.0); + } + lc++; + } // i,j + } // k + + const auto& slopes = amrex_calc_slopes_eb_given_A (i,j,k,n,A,state,flag); + xslope = slopes[0]; + yslope = slopes[1]; + + // This will over-write the values of xslope and yslope if appropriate + amrex_overwrite_with_regular_slopes_extdir(i,j,k,n,xslope,yslope,state,vfrac, + edlo_x,edlo_y,edhi_x,edhi_y, + domlo_x,domlo_y,domhi_x,domhi_y,max_order); + + } // end of needs_bndry_stencil + + // Zero out slopes outside of an extdir (or hoextrap) boundary + // TODO: is this the right thing to do at a HOEXTRAP boundary?? + if ( (edlo_x && i < domlo_x) || (edhi_x && i > domhi_x) || + (edlo_y && j < domlo_y) || (edhi_y && j > domhi_y) ) + { + xslope = 0.; + yslope = 0.; + } + return {xslope,yslope}; +} + +// amrex_calc_slopes_extdir_eb_grown calculates the slope in each coordinate direction using a +// 1) standard limited slope if all three cells in the stencil are regular cells +// (this stencil sees the extdir/hoextrap boundary condition if there is one) +// OR +// 2) least squares linear fit to the at-most 24 nearest neighbors, with the function +// going through the centroid of cell(i,j,k). This does not assume that the cell centroids, +// where the data is assume to live, are the same as cell centers. +// +AMREX_GPU_DEVICE AMREX_FORCE_INLINE +amrex::GpuArray +amrex_calc_slopes_extdir_eb_grown (int i, int j, int k, int n, int nx, int ny, + amrex::Array4 const& state, + amrex::Array4 const& ccent, + amrex::Array4 const& vfrac, + amrex::Array4 const& fcx, + amrex::Array4 const& fcy, + amrex::Array4 const& flag, + bool edlo_x, bool edlo_y, bool edhi_x, bool edhi_y, + int domlo_x, int domlo_y, int domhi_x, int domhi_y, + int max_order) noexcept +{ + constexpr int dim_a = 25; + + auto xslope = amrex::Real(0.0); + auto yslope = amrex::Real(0.0); + + // First get EB-aware slope that doesn't know about extdir + bool needs_bdry_stencil = (edlo_x && i <= domlo_x) || (edhi_x && i >= domhi_x) || + (edlo_y && j <= domlo_y) || (edhi_y && j >= domhi_y); + + // + // This call does not have any knowledge of extdir / hoextrap boundary conditions + // + if (!needs_bdry_stencil) + { + // This returns slopes calculated with the regular 1-d approach if all cells in the stencil + // are regular. If not, it uses the EB-aware least squares approach to fit a linear profile + // using the neighboring un-covered cells. + const auto& slopes = amrex_calc_slopes_eb_grown (i,j,k,n,nx,ny,state,ccent,vfrac,flag,max_order); + return slopes; + + } else { + + amrex::Real A[dim_a][AMREX_SPACEDIM]; + + int lc=0; + int kk = 0; + { + for(int jj(-ny); jj<=ny; jj++) + for(int ii(-nx); ii<=nx; ii++) + { + if ( !flag(i+ii,j+jj,k).isCovered() && !(ii==0 && jj==0 && kk==0) ) + { + bool ilo_test = ( edlo_x && (i == domlo_x) && ii == -1); + bool ihi_test = ( edhi_x && (i == domhi_x) && ii == 1); + + bool jlo_test = ( edlo_y && (j == domlo_y) && jj == -1); + bool jhi_test = ( edhi_y && (j == domhi_y) && jj == 1); + + bool klo_test = false; + bool khi_test = false; + + // These are the default values if no physical boundary + A[lc][0] = amrex::Real(ii) + ccent(i+ii,j+jj,k+kk,0); + A[lc][1] = amrex::Real(jj) + ccent(i+ii,j+jj,k+kk,1); + // Do corrections for entire x-face + if (ilo_test) + { + if (!jlo_test && !jhi_test && !klo_test && !khi_test) + { + A[lc][1] = amrex::Real(jj) + fcx(i ,j+jj,k+kk,0); + } + A[lc][0] = amrex::Real(-0.5) ; + } else if (ihi_test) { + + if (!jlo_test && !jhi_test && !klo_test && !khi_test) + { + A[lc][1] = amrex::Real(jj) + fcx(i+ii,j+jj,k+kk,0); + } + A[lc][0] = amrex::Real(0.5) ; + } + + // Do corrections for entire y-face + if (jlo_test) + { + if (!ilo_test && !ihi_test && !klo_test && !khi_test) + { + A[lc][0] = amrex::Real(ii) + fcy(i+ii,j ,k+kk,0); + } + A[lc][1] = amrex::Real(-0.5) ; + + } else if (jhi_test) { + + if (!ilo_test && !ihi_test && !klo_test && !khi_test) + { + A[lc][0] = amrex::Real(ii) + fcy(i+ii,j+jj,k+kk,0); + } + A[lc][1] = amrex::Real(0.5) ; + } + + A[lc][0] -= ccent(i,j,k,0); + A[lc][1] -= ccent(i,j,k,1); + + } else { + A[lc][0] = amrex::Real(0.0); + A[lc][1] = amrex::Real(0.0); + } + lc++; + } // i,j + } // k + + const auto& slopes = amrex_calc_slopes_eb_given_A_grown (i,j,k,n,nx,ny,A,state,flag); + xslope = slopes[0]; + yslope = slopes[1]; + + // This will over-write the values of xslope and yslope if appropriate + amrex_overwrite_with_regular_slopes_extdir(i,j,k,n,xslope,yslope,state,vfrac, + edlo_x,edlo_y,edhi_x,edhi_y, + domlo_x,domlo_y,domhi_x,domhi_y,max_order); + + } // end of needs_bndry_stencil + + // Zero out slopes outside of an extdir (or hoextrap) boundary + // TODO: is this the right thing to do at a HOEXTRAP boundary?? + if ( (edlo_x && i < domlo_x) || (edhi_x && i > domhi_x) || + (edlo_y && j < domlo_y) || (edhi_y && j > domhi_y) ) + { + xslope = 0.; + yslope = 0.; + } + return {xslope,yslope}; +} + +AMREX_GPU_DEVICE AMREX_FORCE_INLINE +amrex::Real +amrex_calc_alpha_stencil(amrex::Real q_hat, amrex::Real q_max, + amrex::Real q_min, amrex::Real state, amrex::Real alpha) noexcept +{ + using namespace amrex::literals; + + auto alpha_temp = 0.0_rt; + auto small = 1.0e-13_rt; + + if ((q_hat-state) > small) { + alpha_temp = amrex::min(1.0_rt,(q_max-state)/(q_hat-state)); + } else if ((q_hat-state) < -small) { + alpha_temp = amrex::min(1.0_rt,(q_min-state)/(q_hat-state)); + } else { + alpha_temp = 1.0_rt; + } + return amrex::min(alpha, alpha_temp); +} + +AMREX_GPU_DEVICE AMREX_FORCE_INLINE +amrex::GpuArray +amrex_calc_alpha_limiter(int i, int j, int k, int n, + amrex::Array4 const& state, + amrex::Array4 const& flag, + const amrex::GpuArray& slopes, + amrex::Array4 const& fcx, + amrex::Array4 const& fcy, + amrex::Array4 const& ccent) noexcept +{ + amrex::Real alpha = 2.0; + + int cuts_x = 0; + int cuts_y = 0; + + // Compute how many cut or regular faces do we have in 3x3 block + int kk = 0; + for(int jj(-1); jj<=1; jj++){ + for(int ii(-1); ii<=1; ii++){ + if( flag(i,j,k).isConnected(ii,jj,kk) && !(ii==0 && jj==0)) + { + if ((ii==-1 || ii==1) && jj==0) cuts_x++; + if ((jj==-1 || jj==1) && ii==0) cuts_y++; + } + } + } + + amrex::Real xc = ccent(i,j,k,0); // centroid of cell (i,j,k) + amrex::Real yc = ccent(i,j,k,1); + + //Reconstruct values at the face centroids and compute the limiter + if(flag(i,j,k).isConnected(0,1,0)) { + amrex::Real xf = fcy(i,j+1,k,0); // local (x,z) of centroid of y-face we are extrapolating to + + amrex::Real delta_x = xf - xc; + amrex::Real delta_y = amrex::Real(0.5) - yc; + + amrex::Real q_hat = state(i,j,k,n) + delta_x * slopes[0] + delta_y * slopes[1]; + + amrex::Real q_min = state(i,j,k,n); + amrex::Real q_max = state(i,j,k,n); + + // Compute max and min values in a 3x2 stencil + for(int jj(0); jj<=1; jj++){ + for(int ii(-1); ii<=1; ii++){ + if ( flag(i,j,k).isConnected(ii,jj,kk) && !(ii==0 && jj==0) ) { + if (state(i+ii,j+jj,k+kk,n) > q_max) q_max = state(i+ii,j+jj,k+kk,n); + if (state(i+ii,j+jj,k+kk,n) < q_min) q_min = state(i+ii,j+jj,k+kk,n); + } + } + } + + alpha = amrex_calc_alpha_stencil(q_hat, q_max, q_min, state(i,j,k,n), alpha); + } + if (flag(i,j,k).isConnected(0,-1,0)){ + amrex::Real xf = fcy(i,j,k,0); // local (x,z) of centroid of y-face we are extrapolating to + + amrex::Real delta_x = xf - xc; + amrex::Real delta_y = amrex::Real(0.5) + yc; + + amrex::Real q_hat = state(i,j,k,n) + delta_x * slopes[0] - delta_y * slopes[1]; + + amrex::Real q_min = state(i,j,k,n); + amrex::Real q_max = state(i,j,k,n); + + // Compute max and min values in a 3x2 stencil + for(int jj(-1); jj<=0; jj++){ + for(int ii(-1); ii<=1; ii++){ + if ( flag(i,j,k).isConnected(ii,jj,kk) && !(ii==0 && jj==0) ) { + if (state(i+ii,j+jj,k+kk,n) > q_max) q_max = state(i+ii,j+jj,k+kk,n); + if (state(i+ii,j+jj,k+kk,n) < q_min) q_min = state(i+ii,j+jj,k+kk,n); + } + } + } + + alpha = amrex_calc_alpha_stencil(q_hat, q_max, q_min, state(i,j,k,n), alpha); + } + if(flag(i,j,k).isConnected(1,0,0)) { + amrex::Real yf = fcx(i+1,j,k,0); // local (y,z) of centroid of x-face we are extrapolating to + + amrex::Real delta_x = amrex::Real(0.5) - xc; + amrex::Real delta_y = yf - yc; + + amrex::Real q_hat = state(i,j,k,n) + delta_x * slopes[0] + delta_y * slopes[1]; + + amrex::Real q_min = state(i,j,k,n); + amrex::Real q_max = state(i,j,k,n); + + for(int jj(-1); jj<=1; jj++){ + for(int ii(0); ii<=1; ii++){ + if ( flag(i,j,k).isConnected(ii,jj,kk) && !(ii==0 && jj==0) ) { + if (state(i+ii,j+jj,k+kk,n) > q_max) q_max = state(i+ii,j+jj,k+kk,n); + if (state(i+ii,j+jj,k+kk,n) < q_min) q_min = state(i+ii,j+jj,k+kk,n); + } + } + } + + alpha = amrex_calc_alpha_stencil(q_hat, q_max, q_min, state(i,j,k,n), alpha); + } + if(flag(i,j,k).isConnected(-1,0,0)) { + amrex::Real yf = fcx(i,j,k,0); // local (y,z) of centroid of x-face we are extrapolating to + + amrex::Real delta_x = amrex::Real(0.5) + xc; + amrex::Real delta_y = yf - yc; + + amrex::Real q_hat = state(i,j,k,n) - delta_x * slopes[0] + delta_y * slopes[1]; + + amrex::Real q_min = state(i,j,k,n); + amrex::Real q_max = state(i,j,k,n); + + for(int jj(-1); jj<=1; jj++){ + for(int ii(-1); ii<=0; ii++){ + if( flag(i,j,k).isConnected(ii,jj,kk) && !(ii==0 && jj==0)) { + if (state(i+ii,j+jj,k+kk,n) > q_max) q_max = state(i+ii,j+jj,k+kk,n); + if (state(i+ii,j+jj,k+kk,n) < q_min) q_min = state(i+ii,j+jj,k+kk,n); + } + } + } + alpha = amrex_calc_alpha_stencil(q_hat, q_max, q_min, state(i,j,k,n), alpha); + } + + amrex::Real xalpha = alpha; + amrex::Real yalpha = alpha; + + //Zeroing out the slopes in the direction where a covered face exists. + if (cuts_x<2) xalpha = 0; + if (cuts_y<2) yalpha = 0; + + return {xalpha,yalpha}; +} + +//amrex_lim_slopes_eb computes the slopes calling amrex_calc_slopes_eb, and then each slope component +//is multiplied by a limiter based on the work of Barth-Jespersen. +AMREX_GPU_DEVICE AMREX_FORCE_INLINE +amrex::GpuArray +amrex_lim_slopes_eb (int i, int j, int k, int n, + amrex::Array4 const& state, + amrex::Array4 const& ccent, + amrex::Array4 const& vfrac, + amrex::Array4 const& fcx, + amrex::Array4 const& fcy, + amrex::Array4 const& flag, + int max_order) noexcept +{ + + amrex::GpuArray slopes; + amrex::GpuArray alpha_lim; + + slopes = amrex_calc_slopes_eb(i,j,k,n,state,ccent,vfrac,flag,max_order); + + alpha_lim = amrex_calc_alpha_limiter(i,j,k,n,state,flag,slopes,fcx,fcy,ccent); + + // Setting limiter to 1 for stencils that just consists of non-EB cells because + // amrex_calc_slopes_eb routine will call the slope routine for non-EB stencils that has already a limiter + if ( max_order > 0 && vfrac(i,j,k) == 1. && vfrac(i-1,j,k) == 1. && vfrac(i+1,j,k) == 1.) + alpha_lim[0] = 1.0; + + if ( max_order > 0 && vfrac(i,j,k) == 1. && vfrac(i,j-1,k) == 1. && vfrac(i,j+1,k) == 1.) + alpha_lim[1] = 1.0; + + return {alpha_lim[0]*slopes[0],alpha_lim[1]*slopes[1]}; +} + +//amrex_lim_slopes_extdir_eb computes the slopes calling amrex_calc_slopes_extdir_eb, and then each slope component +//is multiplied by a limiter based on the work of Barth-Jespersen. +AMREX_GPU_DEVICE AMREX_FORCE_INLINE +amrex::GpuArray +amrex_lim_slopes_extdir_eb (int i, int j, int k, int n, + amrex::Array4 const& state, + amrex::Array4 const& ccent, + amrex::Array4 const& vfrac, + amrex::Array4 const& fcx, + amrex::Array4 const& fcy, + amrex::Array4 const& flag, + bool edlo_x, bool edlo_y, bool edhi_x, bool edhi_y, + int domlo_x, int domlo_y, int domhi_x, int domhi_y, + int max_order) noexcept +{ + + amrex::GpuArray slopes; + amrex::GpuArray alpha_lim; + + slopes = amrex_calc_slopes_extdir_eb(i,j,k,n,state,ccent,vfrac,fcx,fcy,flag, + edlo_x,edlo_y,edhi_x,edhi_y, + domlo_x,domlo_y,domhi_x,domhi_y,max_order); + alpha_lim = amrex_calc_alpha_limiter(i,j,k,n,state,flag,slopes,fcx,fcy,ccent); + + // Setting limiter to 1 for stencils that just consists of non-EB cells because + // amrex_calc_slopes_extdir_eb routine will call the slope routine for non-EB stencils that has already a limiter + if ( max_order > 0 && vfrac(i,j,k) == 1. && vfrac(i-1,j,k) == 1. && vfrac(i+1,j,k) == 1.) + alpha_lim[0] = 1.0; + + if ( max_order > 0 && vfrac(i,j,k) == 1. && vfrac(i,j-1,k) == 1. && vfrac(i,j+1,k) == 1.) + alpha_lim[1] = 1.0; + + return {alpha_lim[0]*slopes[0],alpha_lim[1]*slopes[1]}; +} + +} +#endif diff --git a/Src/EB/AMReX_EB_Slopes_3D_K.H b/Src/EB/AMReX_EB_Slopes_3D_K.H new file mode 100644 index 00000000000..a7e91c7b905 --- /dev/null +++ b/Src/EB/AMReX_EB_Slopes_3D_K.H @@ -0,0 +1,1125 @@ +#ifndef AMREX_HYDRO_EB_SLOPES_3D_K_H_ +#define AMREX_HYDRO_EB_SLOPES_3D_K_H_ + +#include +#include + +#include +#include + +namespace { + +// amrex_calc_slopes_eb calculates the slope in each coordinate direction using a +// least squares linear fit to the 26 nearest neighbors, with the function +// going through the centroid of cell(i,j,k). This does not assume that the cell centroids, +// where the data is assume to live, are the same as cell centers. Note that this routine +// is called either by amrex_calc_slopes_eb or amrex_calc_slopes_extdir_eb; in the former +// A is defined with the cell centroids; in the latter, the A values corresponding to values +// defined on faces use the face centroid location. +AMREX_GPU_DEVICE AMREX_FORCE_INLINE +amrex::GpuArray +amrex_calc_slopes_eb_given_A (int i, int j, int k, int n, + amrex::Real A[27][AMREX_SPACEDIM], + amrex::Array4 const& state, + amrex::Array4 const& flag) noexcept +{ + constexpr int dim_a = 27; + amrex::Real du[dim_a]; + + int ll=0; + for(int kk(-1); kk<=1; kk++) + { + for(int jj(-1); jj<=1; jj++){ + for(int ii(-1); ii<=1; ii++){ + + if (flag(i,j,k).isConnected(ii,jj,kk) && !(ii==0 && jj==0 && kk==0)) + { + du[ll] = state(i+ii,j+jj,k+kk,n) - state(i,j,k,n); + } else { + du[ll] = amrex::Real(0.0); + } + ll++; + } + } + } + + amrex::Real AtA[AMREX_SPACEDIM][AMREX_SPACEDIM]; + amrex::Real Atb[AMREX_SPACEDIM]; + + for(int jj(0); jj +amrex_calc_slopes_eb_given_A_grown (int i, int j, int k, int n, int nx, int ny, int nz, + amrex::Real A[125][AMREX_SPACEDIM], + amrex::Array4 const& state, + amrex::Array4 const& flag) noexcept +{ + AMREX_ASSERT(nx == 1 || nx == 2); + AMREX_ASSERT(ny == 1 || ny == 2); + AMREX_ASSERT(nz == 1 || nz == 2); + + amrex::Real AtA[AMREX_SPACEDIM][AMREX_SPACEDIM]; + amrex::Real Atb[AMREX_SPACEDIM]; + + for(int jj(0); jj= -nx && ii <= nx && jj >= -ny && jj <= ny && + kk >= -nz && kk <= nz) { + du = state(i+ii,j+jj,k+kk,n) - state(i,j,k,n); + } + + Atb[0] += A[lc][0]*du; + Atb[1] += A[lc][1]*du; + Atb[2] += A[lc][2]*du; + } + } + } + + // Fill in symmetric + AtA[1][0] = AtA[0][1]; + AtA[2][0] = AtA[0][2]; + AtA[2][1] = AtA[1][2]; + + amrex::Real detAtA = + AtA[0][0]*(AtA[1][1]*AtA[2][2] - AtA[1][2]*AtA[2][1]) - + AtA[0][1]*(AtA[1][0]*AtA[2][2] - AtA[1][2]*AtA[2][0]) + + AtA[0][2]*(AtA[1][0]*AtA[2][1] - AtA[1][1]*AtA[2][0]); + + amrex::Real detAtA_x = + Atb[0] *(AtA[1][1]*AtA[2][2] - AtA[1][2]*AtA[1][2]) - + AtA[0][1]*(Atb[1] * AtA[2][2] - AtA[1][2]*Atb[2] ) + + AtA[0][2]*(Atb[1] * AtA[2][1] - AtA[1][1]*Atb[2] ); + + // Slope at centroid of (i,j,k) + amrex::Real xs = detAtA_x / detAtA; + + amrex::Real detAtA_y = + AtA[0][0]*(Atb[1] * AtA[2][2] - AtA[1][2]*Atb[2] ) - + Atb[0] * (AtA[1][0]*AtA[2][2] - AtA[1][2]*AtA[2][0]) + + AtA[0][2]*(AtA[1][0]*Atb[2] - Atb[1] *AtA[2][0]); + + // Slope at centroid of (i,j,k) + amrex::Real ys = detAtA_y / detAtA; + + amrex::Real detAtA_z = + AtA[0][0]*(AtA[1][1]*Atb[2] - Atb[1] *AtA[1][2]) - + AtA[0][1]*(AtA[1][0]*Atb[2] - Atb[1] *AtA[2][0]) + + Atb[0] *(AtA[1][0]*AtA[2][1] - AtA[1][1]*AtA[2][0]); + + // Slope at centroid of (i,j,k) + amrex::Real zs = detAtA_z / detAtA; + + return {xs,ys,zs}; +} + +// +// amrex_overwrite_with_regular_slopes calculates the slope in each coordinate direction +// with a standard non-EB slope calculation (that depends on max_order) +// +AMREX_GPU_DEVICE AMREX_FORCE_INLINE +void +amrex_overwrite_with_regular_slopes(int i, int j, int k, int n, + amrex::Real& xslope, amrex::Real& yslope, + amrex::Real& zslope, + amrex::Array4 const& state, + amrex::Array4 const& vfrac, + int max_order) noexcept +{ + // + // Here we over-write -- if possible -- with a stencil not using the EB stencil + // + AMREX_ALWAYS_ASSERT( max_order == 0 || max_order == 2 || max_order == 4); + + // We have enough cells in the x-direction to do 4th order slopes + // centered on (i,j,k) with all values at cell centers + if (max_order == 4 && + vfrac(i,j,k) == 1. && vfrac(i-1,j,k) == 1. && vfrac(i-2,j,k) == 1. && + vfrac(i+1,j,k) == 1. && vfrac(i+2,j,k) == 1.) + { + int order = 4; + xslope = amrex_calc_xslope(i,j,k,n,order,state); + } + // We have enough cells in the x-direction to do 2nd order slopes + // centered on (i,j,k) with all values at cell centers + else if (max_order > 0 && vfrac(i,j,k) == 1. && vfrac(i-1,j,k) == 1. && vfrac(i+1,j,k) == 1.) + { + int order = 2; + xslope = amrex_calc_xslope(i,j,k,n,order,state); + } else if (max_order == 0) { + xslope = 0.; + } + + // We have enough cells in the y-direction to do 4th order slopes + // centered on (i,j,k) with all values at cell centers + if (max_order == 4 && + vfrac(i,j,k) == 1. && vfrac(i,j-1,k) == 1. && vfrac(i,j-2,k) == 1. && + vfrac(i,j+1,k) == 1. && vfrac(i,j+2,k) == 1.) + { + int order = 4; + yslope = amrex_calc_yslope(i,j,k,n,order,state); + } + // We have enough cells in the y-direction to do 2nd order slopes + // centered on (i,j,k) with all values at cell centers + else if (max_order > 0 && vfrac(i,j,k) == 1. && vfrac(i,j-1,k) == 1. && vfrac(i,j+1,k) == 1.) + { + int order = 2; + yslope = amrex_calc_yslope(i,j,k,n,order,state); + } else if (max_order == 0) { + yslope = 0.; + } + +#if (AMREX_SPACEDIM == 3) + // We have enough cells in the z-direction to do 4th order slopes + // centered on (i,j,k) with all values at cell centers + if (max_order == 4 && + vfrac(i,j,k) == 1. && vfrac(i,j,k-1) == 1. && vfrac(i,j,k-2) == 1. && + vfrac(i,j,k+1) == 1. && vfrac(i,j,k+2) == 1.) + { + int order = 4; + zslope = amrex_calc_zslope(i,j,k,n,order,state); + } + // We have enough cells in the z-direction to do 2nd order slopes + // centered on (i,j,k) with all values at cell centers + else if (max_order > 0 && vfrac(i,j,k) == 1. && vfrac(i,j,k-1) == 1. && vfrac(i,j,k+1) == 1.) + { + int order = 2; + zslope = amrex_calc_zslope(i,j,k,n,order,state); + } else if (max_order == 0) { + zslope = 0.; + } +#endif +} + +// amrex_calc_slopes_eb calculates the slope in each coordinate direction using a +// 1) standard limited slope if all three cells in the stencil are regular cells +// OR +// 2) least squares linear fit to the at-most 26 nearest neighbors, with the function +// going through the centroid of cell(i,j,k). This does not assume that the cell centroids, +// where the data is assume to live, are the same as cell centers. Note that calc_slopes_eb +// defines the matrix A and passes this A to amrex_calc_slopes_eb_given_A. +// +// This routine assumes that there are no relevant hoextrap/extdir domain boundary conditions for this cell -- +// it does not test for them so this should not be called if such boundaries might be present +AMREX_GPU_DEVICE AMREX_FORCE_INLINE +amrex::GpuArray +amrex_calc_slopes_eb (int i, int j, int k, int n, + amrex::Array4 const& state, + amrex::Array4 const& ccent, + amrex::Array4 const& vfrac, + amrex::Array4 const& flag, + int max_order) noexcept +{ + constexpr int dim_a = 27; + amrex::Real A[dim_a][AMREX_SPACEDIM]; + + int lc=0; + for(int kk(-1); kk<=1; kk++) + for(int jj(-1); jj<=1; jj++) + for(int ii(-1); ii<=1; ii++) + { + + if (flag(i,j,k).isConnected(ii,jj,kk) && !(ii==0 && jj==0 && kk==0)) + { + A[lc][0] = amrex::Real(ii) + ccent(i+ii,j+jj,k+kk,0) - ccent(i,j,k,0); + A[lc][1] = amrex::Real(jj) + ccent(i+ii,j+jj,k+kk,1) - ccent(i,j,k,1); + A[lc][2] = amrex::Real(kk) + ccent(i+ii,j+jj,k+kk,2) - ccent(i,j,k,2); + } else { + A[lc][0] = amrex::Real(0.0); + A[lc][1] = amrex::Real(0.0); + A[lc][2] = amrex::Real(0.0); + } + lc++; + } // ii + // + // These slopes use the EB stencil without testing whether it is actually needed + // + const auto& slopes = amrex_calc_slopes_eb_given_A (i,j,k,n,A,state,flag); + amrex::Real xslope = slopes[0]; + amrex::Real yslope = slopes[1]; + amrex::Real zslope = slopes[2]; + + // This will over-write the values of xslope, yslope and/or zslope if appropriate + amrex_overwrite_with_regular_slopes(i,j,k,n,xslope,yslope,zslope,state,vfrac,max_order); + + return {xslope,yslope,zslope}; +} + +// amrex_calc_slopes_eb_grown calculates the slope in each coordinate direction using a +// 1) standard limited slope if all three cells in the stencil are regular cells +// OR +// 2) least squares linear fit to the at-most 124 nearest neighbors, with the function +// going through the centroid of cell(i,j,k). This does not assume that the cell centroids, +// where the data is assume to live, are the same as cell centers. Note that calc_slopes_eb +// defines the matrix A and passes this A to amrex_calc_slopes_eb_given_A. +// +// This routine assumes that there are no relevant hoextrap/extdir domain boundary conditions for this cell -- +// it does not test for them so this should not be called if such boundaries might be present +AMREX_GPU_DEVICE AMREX_FORCE_INLINE +amrex::GpuArray +amrex_calc_slopes_eb_grown (int i, int j, int k, int n, int nx, int ny, int nz, + amrex::Array4 const& state, + amrex::Array4 const& ccent, + amrex::Array4 const& vfrac, + amrex::Array4 const& flag, + int max_order) noexcept +{ + AMREX_ASSERT(nx == 1 || nx == 2); + AMREX_ASSERT(ny == 1 || ny == 2); + AMREX_ASSERT(nz == 1 || nz == 2); + + constexpr int dim_a = 125; + amrex::Real A[dim_a][AMREX_SPACEDIM]; + + // Make sure to zero all the entries in A (since the loop below may not cover all 125) + int lc=0; + for(int kk(-2); kk<=2; kk++) + for(int jj(-2); jj<=2; jj++) + for(int ii(-2); ii<=2; ii++) + { + A[lc][0] = amrex::Real(0.0); + A[lc][1] = amrex::Real(0.0); + A[lc][2] = amrex::Real(0.0); + lc++; + } + + lc=0; + for(int kk(-nz); kk<=nz; kk++) + for(int jj(-ny); jj<=ny; jj++) + for(int ii(-nx); ii<=nx; ii++) + { + if (!flag(i+ii,j+jj,k+kk).isCovered() && !(ii==0 && jj==0 && kk==0)) + { + A[lc][0] = amrex::Real(ii) + ccent(i+ii,j+jj,k+kk,0) - ccent(i,j,k,0); + A[lc][1] = amrex::Real(jj) + ccent(i+ii,j+jj,k+kk,1) - ccent(i,j,k,1); + A[lc][2] = amrex::Real(kk) + ccent(i+ii,j+jj,k+kk,2) - ccent(i,j,k,2); + } + lc++; + } // ii + // + // These slopes use the EB stencil without testing whether it is actually needed + // + const auto& slopes = amrex_calc_slopes_eb_given_A_grown (i,j,k,n,nx,ny,nz,A,state,flag); + amrex::Real xslope = slopes[0]; + amrex::Real yslope = slopes[1]; + amrex::Real zslope = slopes[2]; + + // This will over-write the values of xslope, yslope and/or zslope if appropriate + amrex_overwrite_with_regular_slopes(i,j,k,n,xslope,yslope,zslope,state,vfrac,max_order); + + return {xslope,yslope,zslope}; +} + +// +// amrex_overwrite_with_regular_slopes_extdir calculates the slope in each coordinate direction +// with a standard non-EB slope calculation (that depends on max_order) +// +AMREX_GPU_DEVICE AMREX_FORCE_INLINE +void +amrex_overwrite_with_regular_slopes_extdir(int i, int j, int k, int n, + amrex::Real& xslope, amrex::Real& yslope, + amrex::Real& zslope, + amrex::Array4 const& state, + amrex::Array4 const& vfrac, + bool edlo_x, bool edlo_y, bool edlo_z, + bool edhi_x, bool edhi_y, bool edhi_z, + int domlo_x, int domlo_y, int domlo_z, + int domhi_x, int domhi_y, int domhi_z, + int max_order) noexcept +{ + // + // Correct only those cells which are affected by extdir but not by EB: + // + + // We have enough cells in the x-direction to do 4th order slopes + // centered on (i,j,k) with all values at cell centers + if (max_order == 4 && + vfrac(i,j,k) == 1. && vfrac(i-1,j,k) == 1. && vfrac(i-2,j,k) == 1. && + vfrac(i+1,j,k) == 1. && vfrac(i+2,j,k) == 1.) + { + int order = 4; + xslope = amrex_calc_xslope_extdir(i,j,k,n,order,state,edlo_x,edhi_x,domlo_x,domhi_x); + } + // We have enough cells in the x-direction to do 2nd order slopes + // centered on (i,j,k) with all values at cell centers + else if (max_order > 0 && vfrac(i,j,k) == 1. && vfrac(i-1,j,k) == 1. && vfrac(i+1,j,k) == 1.) + { + int order = 2; + xslope = amrex_calc_xslope_extdir(i,j,k,n,order,state,edlo_x,edhi_x,domlo_x,domhi_x); + } else if (max_order == 0) { + xslope = 0.; + } + + // We have enough cells in the y-direction to do 4th order slopes + // centered on (i,j,k) with all values at cell centers + if (max_order == 4 && + vfrac(i,j,k) == 1. && vfrac(i,j-1,k) == 1. && vfrac(i,j-2,k) == 1. && + vfrac(i,j+1,k) == 1. && vfrac(i,j+2,k) == 1.) + { + int order = 4; + yslope = amrex_calc_yslope_extdir(i,j,k,n,order,state,edlo_y,edhi_y,domlo_y,domhi_y); + } + // We have enough cells in the y-direction to do 2nd order slopes + // centered on (i,j,k) with all values at cell centers + else if (max_order > 0 && vfrac(i,j,k) == 1. && vfrac(i,j-1,k) == 1. && vfrac(i,j+1,k) == 1.) + { + int order = 2; + yslope = amrex_calc_yslope_extdir(i,j,k,n,order,state,edlo_y,edhi_y,domlo_y,domhi_y); + } else if (max_order == 0) { + yslope = 0.; + } + + // We have enough cells in the z-direction to do 4th order slopes + // centered on (i,j,k) with all values at cell centers + if (max_order == 4 && + vfrac(i,j,k) == 1. && vfrac(i,j,k-1) == 1. && vfrac(i,j,k-2) == 1. && + vfrac(i,j,k+1) == 1. && vfrac(i,j,k+2) == 1.) + { + int order = 4; + zslope = amrex_calc_zslope_extdir(i,j,k,n,order,state,edlo_z,edhi_z,domlo_z,domhi_z); + } + // We have enough cells in the z-direction to do 2nd order slopes + // centered on (i,j,k) with all values at cell centers + else if (max_order > 0 && vfrac(i,j,k) == 1. && vfrac(i,j,k-1) == 1. && vfrac(i,j,k+1) == 1.) + { + int order = 2; + zslope = amrex_calc_zslope_extdir(i,j,k,n,order,state,edlo_z,edhi_z,domlo_z,domhi_z); + } else if (max_order == 0) { + zslope = 0.; + } +} + +// amrex_calc_slopes_extdir_eb calculates the slope in each coordinate direction using a +// 1) standard limited slope if all three cells in the stencil are regular cells +// (this stencil sees the extdir/hoextrap boundary condition if there is one) +// OR +// 2) least squares linear fit to the at-most 26 nearest neighbors, with the function +// going through the centroid of cell(i,j,k). This does not assume that the cell centroids, +// where the data is assume to live, are the same as cell centers. +// +// All the slopes are returned in one call. +// + +AMREX_GPU_DEVICE AMREX_FORCE_INLINE +amrex::GpuArray +amrex_calc_slopes_extdir_eb (int i, int j, int k, int n, + amrex::Array4 const& state, + amrex::Array4 const& ccent, + amrex::Array4 const& vfrac, + amrex::Array4 const& fcx, + amrex::Array4 const& fcy, + amrex::Array4 const& fcz, + amrex::Array4 const& flag, + bool edlo_x, bool edlo_y, bool edlo_z, + bool edhi_x, bool edhi_y, bool edhi_z, + int domlo_x, int domlo_y, int domlo_z, + int domhi_x, int domhi_y, int domhi_z, + int max_order) noexcept +{ + constexpr int dim_a = 27; + + auto xslope = amrex::Real(0.0); + auto yslope = amrex::Real(0.0); + auto zslope = amrex::Real(0.0); + + // First get EB-aware slope that doesn't know about extdir + bool needs_bdry_stencil = (edlo_x && i <= domlo_x) || (edhi_x && i >= domhi_x) || + (edlo_y && j <= domlo_y) || (edhi_y && j >= domhi_y) || + (edlo_z && k <= domlo_z) || (edhi_z && k >= domhi_z) ; + + // + // This call does not have any knowledge of extdir / hoextrap boundary conditions + // + if (!needs_bdry_stencil) + { + // This returns slopes calculated with the regular 1-d approach if all cells in the stencil + // are regular. If not, it uses the EB-aware least squares approach to fit a linear profile + // using the neighboring un-covered cells. + const auto& slopes = amrex_calc_slopes_eb (i,j,k,n,state,ccent,vfrac,flag,max_order); + return slopes; + + } else { + + amrex::Real A[dim_a][AMREX_SPACEDIM]; + + int lc=0; + for(int kk(-1); kk<=1; kk++) + { + for(int jj(-1); jj<=1; jj++) + for(int ii(-1); ii<=1; ii++) + { + if (flag(i,j,k).isConnected(ii,jj,kk) && !(ii==0 && jj==0 && kk==0)) + { + bool ilo_test = ( edlo_x && (i == domlo_x) && ii == -1); + bool ihi_test = ( edhi_x && (i == domhi_x) && ii == 1); + + bool jlo_test = ( edlo_y && (j == domlo_y) && jj == -1); + bool jhi_test = ( edhi_y && (j == domhi_y) && jj == 1); + + bool klo_test = ( edlo_z && (k == domlo_z) && kk == -1); + bool khi_test = ( edhi_z && (k == domhi_z) && kk == 1); + + // These are the default values if no physical boundary + A[lc][0] = amrex::Real(ii) + ccent(i+ii,j+jj,k+kk,0); + A[lc][1] = amrex::Real(jj) + ccent(i+ii,j+jj,k+kk,1); + A[lc][2] = amrex::Real(kk) + ccent(i+ii,j+jj,k+kk,2); + // Do corrections for entire x-face + if (ilo_test) + { + if (!jlo_test && !jhi_test && !klo_test && !khi_test) + { + A[lc][1] = amrex::Real(jj) + fcx(i ,j+jj,k+kk,0); + A[lc][2] = amrex::Real(kk) + fcx(i ,j+jj,k+kk,1); + } + A[lc][0] = -amrex::Real(0.5); + } else if (ihi_test) { + + if (!jlo_test && !jhi_test && !klo_test && !khi_test) + { + A[lc][1] = amrex::Real(jj) + fcx(i+ii,j+jj,k+kk,0); + A[lc][2] = amrex::Real(kk) + fcx(i+ii,j+jj,k+kk,1); + } + A[lc][0] = amrex::Real(0.5); + } + + // Do corrections for entire y-face + if (jlo_test) + { + if (!ilo_test && !ihi_test && !klo_test && !khi_test) + { + A[lc][0] = amrex::Real(ii) + fcy(i+ii,j ,k+kk,0); + A[lc][2] = amrex::Real(kk) + fcy(i+ii,j ,k+kk,1); + } + A[lc][1] = -amrex::Real(0.5); + + } else if (jhi_test) { + + if (!ilo_test && !ihi_test && !klo_test && !khi_test) + { + A[lc][0] = amrex::Real(ii) + fcy(i+ii,j+jj,k+kk,0); + A[lc][2] = amrex::Real(kk) + fcy(i+ii,j+jj,k+kk,1); + } + A[lc][1] = amrex::Real(0.5); + } + + // Do corrections for entire z-face + if (klo_test) + { + if (!ilo_test && !ihi_test && !jlo_test && !jhi_test) + { + A[lc][0] = amrex::Real(ii) + fcz(i+ii,j+jj,k ,0); + A[lc][1] = amrex::Real(jj) + fcz(i+ii,j+jj,k ,1); + } + A[lc][2] = -amrex::Real(0.5); + + } else if (khi_test) { + if (!ilo_test && !ihi_test && !jlo_test && !jhi_test) + { + A[lc][0] = amrex::Real(ii) + fcz(i+ii,j+jj,k+kk,0); + A[lc][1] = amrex::Real(jj) + fcz(i+ii,j+jj,k+kk,1); + } + A[lc][2] = amrex::Real(0.5); + } + + A[lc][0] -= ccent(i,j,k,0); + A[lc][1] -= ccent(i,j,k,1); + A[lc][2] -= ccent(i,j,k,2); + + } else { + + A[lc][0] = amrex::Real(0.0); + A[lc][1] = amrex::Real(0.0); + A[lc][2] = amrex::Real(0.0); + } + lc++; + } // i,j + } // k + + const auto& slopes = amrex_calc_slopes_eb_given_A (i,j,k,n,A,state,flag); + xslope = slopes[0]; + yslope = slopes[1]; + zslope = slopes[2]; + + // This will over-write the values of xslope and yslope if appropriate + amrex_overwrite_with_regular_slopes_extdir(i,j,k,n,xslope,yslope,zslope,state,vfrac, + edlo_x,edlo_y,edlo_z,edhi_x,edhi_y,edhi_z, + domlo_x,domlo_y,domlo_z,domhi_x,domhi_y,domhi_z, + max_order); + + } // end of needs_bndry_stencil + + // Zero out slopes outside of an extdir (or hoextrap) boundary + // TODO: is this the right thing to do at a HOEXTRAP boundary?? + if ( (edlo_x && i < domlo_x) || (edhi_x && i > domhi_x) || + (edlo_y && j < domlo_y) || (edhi_y && j > domhi_y) || + (edlo_z && k < domlo_z) || (edhi_z && k > domhi_z) ) + { + xslope = 0.; yslope = 0.; zslope = 0.; + } + + return {xslope,yslope,zslope}; +} + +// amrex_calc_slopes_extdir_eb_grown calculates the slope in each coordinate direction using a +// 1) standard limited slope if all three cells in the stencil are regular cells +// (this stencil sees the extdir/hoextrap boundary condition if there is one) +// OR +// 2) least squares linear fit to the at-most 124 nearest neighbors, with the function +// going through the centroid of cell(i,j,k). This does not assume that the cell centroids, +// where the data is assume to live, are the same as cell centers. +// +AMREX_GPU_DEVICE AMREX_FORCE_INLINE +amrex::GpuArray +amrex_calc_slopes_extdir_eb_grown (int i, int j, int k, int n, + int nx, int ny, int nz, + amrex::Array4 const& state, + amrex::Array4 const& ccent, + amrex::Array4 const& vfrac, + amrex::Array4 const& fcx, + amrex::Array4 const& fcy, + amrex::Array4 const& fcz, + amrex::Array4 const& flag, + bool edlo_x, bool edlo_y, bool edlo_z, + bool edhi_x, bool edhi_y, bool edhi_z, + int domlo_x, int domlo_y, int domlo_z, + int domhi_x, int domhi_y, int domhi_z, + int max_order) noexcept +{ + constexpr int dim_a = 125; + + auto xslope = amrex::Real(0.0); + auto yslope = amrex::Real(0.0); + auto zslope = amrex::Real(0.0); + + // First get EB-aware slope that doesn't know about extdir + bool needs_bdry_stencil = (edlo_x && i <= domlo_x) || (edhi_x && i >= domhi_x) || + (edlo_y && j <= domlo_y) || (edhi_y && j >= domhi_y) || + (edlo_z && k <= domlo_z) || (edhi_z && k >= domhi_z) ; + + // + // This call does not have any knowledge of extdir / hoextrap boundary conditions + // + if (!needs_bdry_stencil) + { + // This returns slopes calculated with the regular 1-d approach if all cells in the stencil + // are regular. If not, it uses the EB-aware least squares approach to fit a linear profile + // using the neighboring un-covered cells. + const auto& slopes = amrex_calc_slopes_eb_grown (i,j,k,n,nx,ny,nz,state,ccent,vfrac,flag,max_order); + return slopes; + + } else { + + amrex::Real A[dim_a][AMREX_SPACEDIM]; + + int lc=0; + for(int kk(-nz); kk<=nz; kk++) + { + for(int jj(-ny); jj<=ny; jj++) + for(int ii(-nx); ii<=nx; ii++) + { + if (!flag(i+ii,j+jj,k+kk).isCovered() && !(ii==0 && jj==0 && kk==0)) + { + bool ilo_test = ( edlo_x && (i == domlo_x) && ii == -1); + bool ihi_test = ( edhi_x && (i == domhi_x) && ii == 1); + + bool jlo_test = ( edlo_y && (j == domlo_y) && jj == -1); + bool jhi_test = ( edhi_y && (j == domhi_y) && jj == 1); + + bool klo_test = ( edlo_z && (k == domlo_z) && kk == -1); + bool khi_test = ( edhi_z && (k == domhi_z) && kk == 1); + + // These are the default values if no physical boundary + A[lc][0] = amrex::Real(ii) + ccent(i+ii,j+jj,k+kk,0); + A[lc][1] = amrex::Real(jj) + ccent(i+ii,j+jj,k+kk,1); + A[lc][2] = amrex::Real(kk) + ccent(i+ii,j+jj,k+kk,2); + // Do corrections for entire x-face + if (ilo_test) + { + if (!jlo_test && !jhi_test && !klo_test && !khi_test) + { + A[lc][1] = amrex::Real(jj) + fcx(i ,j+jj,k+kk,0); + A[lc][2] = amrex::Real(kk) + fcx(i ,j+jj,k+kk,1); + } + A[lc][0] = -amrex::Real(0.5); + } else if (ihi_test) { + + if (!jlo_test && !jhi_test && !klo_test && !khi_test) + { + A[lc][1] = amrex::Real(jj) + fcx(i+ii,j+jj,k+kk,0); + A[lc][2] = amrex::Real(kk) + fcx(i+ii,j+jj,k+kk,1); + } + A[lc][0] = amrex::Real(0.5); + } + + // Do corrections for entire y-face + if (jlo_test) + { + if (!ilo_test && !ihi_test && !klo_test && !khi_test) + { + A[lc][0] = amrex::Real(ii) + fcy(i+ii,j ,k+kk,0); + A[lc][2] = amrex::Real(kk) + fcy(i+ii,j ,k+kk,1); + } + A[lc][1] = -amrex::Real(0.5); + + } else if (jhi_test) { + + if (!ilo_test && !ihi_test && !klo_test && !khi_test) + { + A[lc][0] = amrex::Real(ii) + fcy(i+ii,j+jj,k+kk,0); + A[lc][2] = amrex::Real(kk) + fcy(i+ii,j+jj,k+kk,1); + } + A[lc][1] = amrex::Real(0.5); + } + + // Do corrections for entire z-face + if (klo_test) + { + if (!ilo_test && !ihi_test && !jlo_test && !jhi_test) + { + A[lc][0] = amrex::Real(ii) + fcz(i+ii,j+jj,k ,0); + A[lc][1] = amrex::Real(jj) + fcz(i+ii,j+jj,k ,1); + } + A[lc][2] = -amrex::Real(0.5); + + } else if (khi_test) { + if (!ilo_test && !ihi_test && !jlo_test && !jhi_test) + { + A[lc][0] = amrex::Real(ii) + fcz(i+ii,j+jj,k+kk,0); + A[lc][1] = amrex::Real(jj) + fcz(i+ii,j+jj,k+kk,1); + } + A[lc][2] = amrex::Real(0.5); + } + + A[lc][0] -= ccent(i,j,k,0); + A[lc][1] -= ccent(i,j,k,1); + A[lc][2] -= ccent(i,j,k,2); + + } else { + A[lc][0] = amrex::Real(0.0); + A[lc][1] = amrex::Real(0.0); + A[lc][2] = amrex::Real(0.0); + } + lc++; + } // i,j + } // k + + const auto& slopes = amrex_calc_slopes_eb_given_A_grown (i,j,k,n,nx,ny,nz,A,state,flag); + xslope = slopes[0]; + yslope = slopes[1]; + zslope = slopes[2]; + + // This will over-write the values of xslope and yslope if appropriate + amrex_overwrite_with_regular_slopes_extdir(i,j,k,n,xslope,yslope,zslope,state,vfrac, + edlo_x,edlo_y,edlo_z,edhi_x,edhi_y,edhi_z, + domlo_x,domlo_y,domlo_z,domhi_x,domhi_y,domhi_z, + max_order); + + } // end of needs_bndry_stencil + + // Zero out slopes outside of an extdir (or hoextrap) boundary + // TODO: is this the right thing to do at a HOEXTRAP boundary?? + if ( (edlo_x && i < domlo_x) || (edhi_x && i > domhi_x) || + (edlo_y && j < domlo_y) || (edhi_y && j > domhi_y) || + (edlo_z && k < domlo_z) || (edhi_z && k > domhi_z) ) + { + xslope = 0.; yslope = 0.; zslope = 0.; + } + + return {xslope,yslope,zslope}; +} + +AMREX_GPU_DEVICE AMREX_FORCE_INLINE +amrex::Real +amrex_calc_alpha_stencil(amrex::Real q_hat, amrex::Real q_max, + amrex::Real q_min, amrex::Real state, amrex::Real alpha) noexcept +{ + using namespace amrex::literals; + + auto alpha_temp = amrex::Real(0.0); + auto small = amrex::Real(1.0e-13); + + if ((q_hat-state) > small) { + alpha_temp = amrex::min(1.0_rt,(q_max-state)/(q_hat-state)); + } else if ((q_hat-state) < -small) { + alpha_temp = amrex::min(1.0_rt,(q_min-state)/(q_hat-state)); + } else { + alpha_temp = 1.0_rt; + } + return amrex::min(alpha, alpha_temp); +} + +AMREX_GPU_DEVICE AMREX_FORCE_INLINE +amrex::GpuArray +amrex_calc_alpha_limiter(int i, int j, int k, int n, + amrex::Array4 const& state, + amrex::Array4 const& flag, + const amrex::GpuArray& slopes, + amrex::Array4 const& fcx, + amrex::Array4 const& fcy, + amrex::Array4 const& fcz, + amrex::Array4 const& ccent) noexcept +{ + auto alpha = amrex::Real(2.0); + + int cuts_x = 0; int cuts_y = 0; int cuts_z = 0; + + // Compute how many cut or regular faces do we have in 3x3 block + for(int kk(-1); kk<=1; kk++) + { + for(int jj(-1); jj<=1; jj++){ + for(int ii(-1); ii<=1; ii++){ + if (flag(i,j,k).isConnected(ii,jj,kk) && !(ii==0 && jj==0 && kk==0)) + { + if ((ii==-1 || ii==1) && jj==0 && kk==0) cuts_x++; + if ((jj==-1 || jj==1) && ii==0 && kk==0) cuts_y++; + if ((kk==-1 || kk==1) && ii==0 && jj==0) cuts_z++; + } + } + } + } + + amrex::Real xc = ccent(i,j,k,0); // centroid of cell (i,j,k) + amrex::Real yc = ccent(i,j,k,1); + amrex::Real zc = ccent(i,j,k,2); + + + //Reconstruct values at the face centroids and compute the limiter + if (flag(i,j,k).isConnected(0,1,0)) { + amrex::Real xf = fcy(i,j+1,k,0); // local (x,z) of centroid of y-face we are extrapolating to + amrex::Real zf = fcy(i,j+1,k,1); // local (x,z) of centroid of y-face we are extrapolating to + + amrex::Real delta_x = xf - xc; + amrex::Real delta_y = amrex::Real(0.5) - yc; + amrex::Real delta_z = zf - zc; + + amrex::Real q_hat = state(i,j,k,n) + delta_x * slopes[0] + + delta_y * slopes[1] + + delta_z * slopes[2]; + + // Compute max and min values in a 3x2x3 stencil + amrex::Real q_min = state(i,j,k,n); + amrex::Real q_max = state(i,j,k,n); + for(int kk(-1); kk<=1; kk++) { + for(int jj(0); jj<=1; jj++){ + for(int ii(-1); ii<=1; ii++){ + if (flag(i,j,k).isConnected(ii,jj,kk) && !(ii==0 && jj==0 && kk==0)) { + if (state(i+ii,j+jj,k+kk,n) > q_max) q_max = state(i+ii,j+jj,k+kk,n); + if (state(i+ii,j+jj,k+kk,n) < q_min) q_min = state(i+ii,j+jj,k+kk,n); + } + } + } + } + + alpha = amrex_calc_alpha_stencil(q_hat, q_max, q_min, state(i,j,k,n), alpha); + } + if (flag(i,j,k).isConnected(0,-1,0)){ + amrex::Real xf = fcy(i,j,k,0); // local (x,z) of centroid of y-face we are extrapolating to + amrex::Real zf = fcy(i,j,k,1); // local (x,z) of centroid of y-face we are extrapolating to + + amrex::Real delta_x = xf - xc; + amrex::Real delta_y = amrex::Real(0.5) + yc; + amrex::Real delta_z = zf - zc; + + amrex::Real q_hat = state(i,j,k,n) + delta_x * slopes[0] + - delta_y * slopes[1] + + delta_z * slopes[2]; + + // Compute max and min values in a 3x2x3 stencil + amrex::Real q_min = state(i,j,k,n); + amrex::Real q_max = state(i,j,k,n); + for(int kk(-1); kk<=1; kk++) { + for(int jj(-1); jj<=0; jj++){ + for(int ii(-1); ii<=1; ii++){ + if (flag(i,j,k).isConnected(ii,jj,kk) && !(ii==0 && jj==0 && kk==0)) { + if (state(i+ii,j+jj,k+kk,n) > q_max) q_max = state(i+ii,j+jj,k+kk,n); + if (state(i+ii,j+jj,k+kk,n) < q_min) q_min = state(i+ii,j+jj,k+kk,n); + } + } + } + } + + alpha = amrex_calc_alpha_stencil(q_hat, q_max, q_min, state(i,j,k,n), alpha); + } + if (flag(i,j,k).isConnected(1,0,0)) { + amrex::Real yf = fcx(i+1,j,k,0); // local (y,z) of centroid of x-face we are extrapolating to + amrex::Real zf = fcx(i+1,j,k,1); // local (y,z) of centroid of x-face we are extrapolating to + + amrex::Real delta_x = amrex::Real(0.5) - xc; + amrex::Real delta_y = yf - yc; + amrex::Real delta_z = zf - zc; + + amrex::Real q_hat = state(i,j,k,n) + delta_x * slopes[0] + + delta_y * slopes[1] + + delta_z * slopes[2]; + + // Compute max and min values in a 2x3x3 stencil + amrex::Real q_min = state(i,j,k,n); + amrex::Real q_max = state(i,j,k,n); + for(int kk(-1); kk<=1; kk++) { + for(int jj(-1); jj<=1; jj++){ + for(int ii(0); ii<=1; ii++){ + if (flag(i,j,k).isConnected(ii,jj,kk) && !(ii==0 && jj==0 && kk==0)) { + if (state(i+ii,j+jj,k+kk,n) > q_max) q_max = state(i+ii,j+jj,k+kk,n); + if (state(i+ii,j+jj,k+kk,n) < q_min) q_min = state(i+ii,j+jj,k+kk,n); + } + } + } + } + + alpha = amrex_calc_alpha_stencil(q_hat, q_max, q_min, state(i,j,k,n), alpha); + } + if (flag(i,j,k).isConnected(-1,0,0)) { + amrex::Real yf = fcx(i,j,k,0); // local (y,z) of centroid of x-face we are extrapolating to + amrex::Real zf = fcx(i,j,k,1); // local (y,z) of centroid of x-face we are extrapolating to + + amrex::Real delta_x = amrex::Real(0.5) + xc; + amrex::Real delta_y = yf - yc; + amrex::Real delta_z = zf - zc; + + amrex::Real q_hat = state(i,j,k,n) - delta_x * slopes[0] + + delta_y * slopes[1] + + delta_z * slopes[2]; + + // Compute max and min values in a 3x2x3 stencil + amrex::Real q_min = state(i,j,k,n); + amrex::Real q_max = state(i,j,k,n); + for(int kk(-1); kk<=1; kk++) { + for(int jj(-1); jj<=1; jj++){ + for(int ii(-1); ii<=0; ii++){ + if (flag(i,j,k).isConnected(ii,jj,kk) && !(ii==0 && jj==0 && kk==0)) { + if (state(i+ii,j+jj,k+kk,n) > q_max) q_max = state(i+ii,j+jj,k+kk,n); + if (state(i+ii,j+jj,k+kk,n) < q_min) q_min = state(i+ii,j+jj,k+kk,n); + } + } + } + } + alpha = amrex_calc_alpha_stencil(q_hat, q_max, q_min, state(i,j,k,n), alpha); + } + if (flag(i,j,k).isConnected(0,0,1)) { + amrex::Real xf = fcz(i,j,k+1,0); // local (x,y) of centroid of z-face we are extrapolating to + amrex::Real yf = fcz(i,j,k+1,1); // local (x,y) of centroid of z-face we are extrapolating to + + amrex::Real delta_x = xf - xc; + amrex::Real delta_y = yf - yc; + amrex::Real delta_z = amrex::Real(0.5) - zc; + + amrex::Real q_hat = state(i,j,k,n) + delta_x * slopes[0] + + delta_y * slopes[1] + + delta_z * slopes[2]; + + // Compute max and min values in a 3x3x2 stencil + amrex::Real q_min = state(i,j,k,n); + amrex::Real q_max = state(i,j,k,n); + for(int kk(0); kk<=1; kk++) { + for(int jj(-1); jj<=1; jj++){ + for(int ii(-1); ii<=1; ii++){ + if (flag(i,j,k).isConnected(ii,jj,kk) && !(ii==0 && jj==0 && kk==0)) { + if (state(i+ii,j+jj,k+kk,n) > q_max) q_max = state(i+ii,j+jj,k+kk,n); + if (state(i+ii,j+jj,k+kk,n) < q_min) q_min = state(i+ii,j+jj,k+kk,n); + } + } + } + } + alpha = amrex_calc_alpha_stencil(q_hat, q_max, q_min, state(i,j,k,n), alpha); + } + if (flag(i,j,k).isConnected(0,0,-1)) { + amrex::Real xf = fcz(i,j,k,0); // local (x,y) of centroid of z-face we are extrapolating to + amrex::Real yf = fcz(i,j,k,1); // local (x,y) of centroid of z-face we are extrapolating to + + amrex::Real delta_x = xf - xc; + amrex::Real delta_y = yf - yc; + amrex::Real delta_z = amrex::Real(0.5) + zc; + + amrex::Real q_hat = state(i,j,k,n) + delta_x * slopes[0] + + delta_y * slopes[1] + - delta_z * slopes[2]; + + // Compute max and min values in a 3x2x3 stencil + amrex::Real q_min = state(i,j,k,n); + amrex::Real q_max = state(i,j,k,n); + for(int kk(-1); kk<=0; kk++) { + for(int jj(-1); jj<=1; jj++){ + for(int ii(-1); ii<=1; ii++){ + if (flag(i,j,k).isConnected(ii,jj,kk) && !(ii==0 && jj==0 && kk==0)) { + if (state(i+ii,j+jj,k+kk,n) > q_max) q_max = state(i+ii,j+jj,k+kk,n); + if (state(i+ii,j+jj,k+kk,n) < q_min) q_min = state(i+ii,j+jj,k+kk,n); + } + } + } + } + alpha = amrex_calc_alpha_stencil(q_hat, q_max, q_min, state(i,j,k,n), alpha); + } + + amrex::Real xalpha = alpha; + amrex::Real yalpha = alpha; + amrex::Real zalpha = alpha; + + //Zeroing out the slopes in the direction where a covered face exists. + if (cuts_x<2) xalpha = 0; + if (cuts_y<2) yalpha = 0; + if (cuts_z<2) zalpha = 0; + + return {xalpha,yalpha,zalpha}; +} + +//amrex_lim_slopes_eb computes the slopes calling amrex_calc_slopes_eb, and then each slope component +//is multiplied by a limiter based on the work of Barth-Jespersen. +AMREX_GPU_DEVICE AMREX_FORCE_INLINE +amrex::GpuArray +amrex_lim_slopes_eb (int i, int j, int k, int n, + amrex::Array4 const& state, + amrex::Array4 const& ccent, + amrex::Array4 const& vfrac, + amrex::Array4 const& fcx, + amrex::Array4 const& fcy, + amrex::Array4 const& fcz, + amrex::Array4 const& flag, + int max_order) noexcept +{ + + amrex::GpuArray slopes; + amrex::GpuArray alpha_lim; + + slopes = amrex_calc_slopes_eb(i,j,k,n,state,ccent,vfrac,flag,max_order); + + alpha_lim = amrex_calc_alpha_limiter(i,j,k,n,state,flag,slopes,fcx,fcy,fcz,ccent); + + // Setting limiter to 1 for stencils that just consists of non-EB cells because + // amrex_calc_slopes_eb routine will call the slope routine for non-EB stencils that has already a limiter + if ( max_order > 0 && vfrac(i,j,k) == 1. && vfrac(i-1,j,k) == 1. && vfrac(i+1,j,k) == 1.) + alpha_lim[0] = 1.0; + + if ( max_order > 0 && vfrac(i,j,k) == 1. && vfrac(i,j-1,k) == 1. && vfrac(i,j+1,k) == 1.) + alpha_lim[1] = 1.0; + + if ( max_order > 0 && vfrac(i,j,k) == 1. && vfrac(i,j,k-1) == 1. && vfrac(i,j,k+1) == 1.) + alpha_lim[2] = 1.0; + + return {alpha_lim[0]*slopes[0],alpha_lim[1]*slopes[1],alpha_lim[2]*slopes[2]}; +} + +//amrex_lim_slopes_extdir_eb computes the slopes calling amrex_calc_slopes_extdir_eb, and then each slope component +//is multiplied by a limiter based on the work of Barth-Jespersen. +AMREX_GPU_DEVICE AMREX_FORCE_INLINE +amrex::GpuArray +amrex_lim_slopes_extdir_eb (int i, int j, int k, int n, + amrex::Array4 const& state, + amrex::Array4 const& ccent, + amrex::Array4 const& vfrac, + amrex::Array4 const& fcx, + amrex::Array4 const& fcy, + amrex::Array4 const& fcz, + amrex::Array4 const& flag, + bool edlo_x, bool edlo_y, bool edlo_z, + bool edhi_x, bool edhi_y, bool edhi_z, + int domlo_x, int domlo_y, int domlo_z, + int domhi_x, int domhi_y, int domhi_z, + int max_order) noexcept +{ + + amrex::GpuArray slopes; + amrex::GpuArray alpha_lim; + + slopes = amrex_calc_slopes_extdir_eb(i,j,k,n,state,ccent,vfrac,fcx,fcy,fcz,flag, + edlo_x,edlo_y,edlo_z,edhi_x,edhi_y,edhi_z, + domlo_x,domlo_y,domlo_z,domhi_x,domhi_y,domhi_z,max_order); + alpha_lim = amrex_calc_alpha_limiter(i,j,k,n,state,flag,slopes,fcx,fcy,fcz,ccent); + + // Setting limiter to 1 for stencils that just consists of non-EB cells because + // amrex_calc_slopes_extdir_eb routine will call the slope routine for non-EB stencils that has already a limiter + if ( max_order > 0 && vfrac(i,j,k) == 1. && vfrac(i-1,j,k) == 1. && vfrac(i+1,j,k) == 1.) + alpha_lim[0] = 1.0; + + if ( max_order > 0 && vfrac(i,j,k) == 1. && vfrac(i,j-1,k) == 1. && vfrac(i,j+1,k) == 1.) + alpha_lim[1] = 1.0; + + if ( max_order > 0 && vfrac(i,j,k) == 1. && vfrac(i,j,k-1) == 1. && vfrac(i,j,k+1) == 1.) + alpha_lim[2] = 1.0; + + return {alpha_lim[0]*slopes[0],alpha_lim[1]*slopes[1],alpha_lim[2]*slopes[2]}; +} + +} +#endif diff --git a/Src/EB/AMReX_EB_Slopes_K.H b/Src/EB/AMReX_EB_Slopes_K.H new file mode 100644 index 00000000000..5e68c499c62 --- /dev/null +++ b/Src/EB/AMReX_EB_Slopes_K.H @@ -0,0 +1,10 @@ +#ifndef AMREX_EB_SLOPES_K_H_ +#define AMREX_EB_SLOPES_K_H_ + +#if (AMREX_SPACEDIM == 2) +#include +#elif (AMREX_SPACEDIM == 3) +#include +#endif + +#endif diff --git a/Src/EB/AMReX_EB_StateRedistItracker.cpp b/Src/EB/AMReX_EB_StateRedistItracker.cpp new file mode 100644 index 00000000000..50c2360161b --- /dev/null +++ b/Src/EB/AMReX_EB_StateRedistItracker.cpp @@ -0,0 +1,711 @@ +/** + * \file StateRedistItracer.cpp + * @{ + * + */ + +#include + +namespace amrex { + +#if (AMREX_SPACEDIM == 2) + +void +MakeITracker ( Box const& bx, + Array4 const& apx, + Array4 const& apy, + Array4 const& vfrac, + Array4 const& itracker, + Geometry const& lev_geom, + Real target_volfrac) +{ +#if 0 + int debug_verbose = 0; +#endif + + const Real small_norm_diff = 1.e-8; + + const Box domain = lev_geom.Domain(); + + // Note that itracker has 4 components and all are initialized to zero + // We will add to the first component every time this cell is included in a merged neighborhood, + // either by merging or being merged + // We identify the cells in the remaining three components with the following ordering + // + // ^ 6 7 8 + // | 4 5 + // j 1 2 3 + // i ---> + + Array imap{0,-1,0,1,-1,1,-1,0,1}; + Array jmap{0,-1,-1,-1,0,0,1,1,1}; + + const auto& is_periodic_x = lev_geom.isPeriodic(0); + const auto& is_periodic_y = lev_geom.isPeriodic(1); + +// if (debug_verbose > 0) +// amrex::Print() << " IN MAKE_ITRACKER DOING BOX " << bx << std::endl; + + amrex::ParallelFor(Box(itracker), + [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept + { + itracker(i,j,k,0) = 0; + }); + + Box domain_per_grown = domain; + if (is_periodic_x) domain_per_grown.grow(0,4); + if (is_periodic_y) domain_per_grown.grow(1,4); + + Box const& bxg4 = amrex::grow(bx,4); + Box bx_per_g4= domain_per_grown & bxg4; + + amrex::ParallelFor(bx_per_g4, + [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept + { + if (vfrac(i,j,k) > 0.0 && vfrac(i,j,k) < target_volfrac) + { + Real apnorm, apnorm_inv; + const Real dapx = apx(i+1,j ,k ) - apx(i,j,k); + const Real dapy = apy(i ,j+1,k ) - apy(i,j,k); + apnorm = std::sqrt(dapx*dapx+dapy*dapy); + apnorm_inv = 1.0/apnorm; + Real nx = dapx * apnorm_inv; + Real ny = dapy * apnorm_inv; + + bool nx_eq_ny = ( (std::abs(nx-ny) < small_norm_diff) || + (std::abs(nx+ny) < small_norm_diff) ) ? true : false; + + // As a first pass, choose just based on the normal + if (std::abs(nx) > std::abs(ny)) + { + if (nx > 0) + itracker(i,j,k,1) = 5; + else + itracker(i,j,k,1) = 4; + + } else { + if (ny > 0) + itracker(i,j,k,1) = 7; + else + itracker(i,j,k,1) = 2; + } + + bool xdir_mns_ok = (is_periodic_x || (i > domain.smallEnd(0))); + bool xdir_pls_ok = (is_periodic_x || (i < domain.bigEnd(0) )); + bool ydir_mns_ok = (is_periodic_y || (j > domain.smallEnd(1))); + bool ydir_pls_ok = (is_periodic_y || (j < domain.bigEnd(1) )); + + // Override above logic if trying to reach outside a domain boundary (and non-periodic) + if ( (!xdir_mns_ok && (itracker(i,j,k,1) == 4)) || + (!xdir_pls_ok && (itracker(i,j,k,1) == 5)) ) + { + itracker(i,j,k,1) = (ny > 0) ? 7 : 2; + } + if ( (!ydir_mns_ok && (itracker(i,j,k,1) == 2)) || + (!ydir_pls_ok && (itracker(i,j,k,1) == 7)) ) + { + itracker(i,j,k,1) = (nx > 0) ? 5 : 4; + } + + // (i,j) merges with at least one cell now + itracker(i,j,k,0) += 1; + + // (i+ioff,j+joff) is in the nbhd of (i,j) + int ioff = imap[itracker(i,j,k,1)]; + int joff = jmap[itracker(i,j,k,1)]; + + // Sanity check + if (vfrac(i+ioff,j+joff,k) == 0.) + amrex::Abort(" Trying to merge with covered cell"); + + Real sum_vol = vfrac(i,j,k) + vfrac(i+ioff,j+joff,k); + +#if 0 + if (debug_verbose > 0) + amrex::Print() << "Cell " << IntVect(i,j) << " with volfrac " << vfrac(i,j,k) << + " trying to merge with " << IntVect(i+ioff,j+joff) << + " with volfrac " << vfrac(i+ioff,j+joff,k) << + " to get new sum_vol " << sum_vol << std::endl; +#endif + + // If the merged cell isn't large enough, we try to merge in the other direction + if (sum_vol < target_volfrac || nx_eq_ny) + { + // Original offset was in y-direction, so we will add to the x-direction + // Note that if we can't because it would go outside the domain, we don't + if (ioff == 0) { + if (nx >= 0 && xdir_pls_ok) + { + itracker(i,j,k,2) = 5; + itracker(i,j,k,0) += 1; + } + else if (nx <= 0 && xdir_mns_ok) + { + itracker(i,j,k,2) = 4; + itracker(i,j,k,0) += 1; + } + + // Original offset was in x-direction, so we will add to the y-direction + // Note that if we can't because it would go outside the domain, we don't + } else { + if (ny >= 0 && ydir_pls_ok) + { + itracker(i,j,k,2) = 7; + itracker(i,j,k,0) += 1; + } + else if (ny <= 0 && ydir_mns_ok) + { + itracker(i,j,k,2) = 2; + itracker(i,j,k,0) += 1; + } + } + + if (itracker(i,j,k,0) > 1) + { + // (i+ioff2,j+joff2) is in the nbhd of (i,j) + int ioff2 = imap[itracker(i,j,k,2)]; + int joff2 = jmap[itracker(i,j,k,2)]; + + sum_vol += vfrac(i+ioff2,j+joff2,k); +#if 0 + if (debug_verbose > 0) + amrex::Print() << "Cell " << IntVect(i,j) << " with volfrac " << vfrac(i,j,k) << + " trying to ALSO merge with " << IntVect(i+ioff2,j+joff2) << + " with volfrac " << vfrac(i+ioff2,j+joff2,k) << + " to get new sum_vol " << sum_vol << std::endl; +#endif + } + } + + // Now we merge in the corner direction if we have already claimed two + if (itracker(i,j,k,0) == 2) + { + // We already have two offsets, and we know they are in different directions + ioff = imap[itracker(i,j,k,1)] + imap[itracker(i,j,k,2)]; + joff = jmap[itracker(i,j,k,1)] + jmap[itracker(i,j,k,2)]; + + if (ioff > 0 && joff > 0) + itracker(i,j,k,3) = 8; + else if (ioff < 0 && joff > 0) + itracker(i,j,k,3) = 6; + else if (ioff > 0 && joff < 0) + itracker(i,j,k,3) = 3; + else + itracker(i,j,k,3) = 1; + + // (i,j) merges with at least three cells now + itracker(i,j,k,0) += 1; + + sum_vol += vfrac(i+ioff,j+joff,k); +#if 0 + if (debug_verbose > 0) + amrex::Print() << "Cell " << IntVect(i,j) << " with volfrac " << vfrac(i,j,k) << + " trying to ALSO merge with " << IntVect(i+ioff,j+joff) << + " with volfrac " << vfrac(i+ioff,j+joff,k) << + " to get new sum_vol " << sum_vol << std::endl; +#endif + } + if (sum_vol < target_volfrac) + { +#if 0 + amrex::Print() << "Couldnt merge with enough cells to raise volume at " << + IntVect(i,j) << " so stuck with sum_vol " << sum_vol << std::endl; +#endif + amrex::Abort("Couldnt merge with enough cells to raise volume greater than target_volfrac"); + } + } + }); +} + +#elif (AMREX_SPACEDIM == 3) + +void +MakeITracker ( Box const& bx, + Array4 const& apx, + Array4 const& apy, + Array4 const& apz, + Array4 const& vfrac, + Array4 const& itracker, + Geometry const& lev_geom, + Real target_volfrac) +{ +#if 0 + bool debug_print = false; +#endif + + const Real small_norm_diff = Real(1.e-8); + + const Box domain = lev_geom.Domain(); + + // Note that itracker has 8 components and all are initialized to zero + // We will add to the first component every time this cell is included in a merged neighborhood, + // either by merging or being merged + // We identify the cells in the remaining three components with the following ordering + // + // at k-1 | at k | at k+1 + // + // ^ 15 16 17 | 6 7 8 | 24 25 26 + // | 12 13 14 | 4 5 | 21 22 23 + // j 9 10 11 | 1 2 3 | 18 19 20 + // i ---> + // + // Note the first component of each of these arrays should never be used + Array imap{0,-1, 0, 1,-1, 1,-1, 0, 1,-1, 0, 1,-1, 0, 1,-1, 0, 1,-1, 0, 1,-1, 0, 1,-1, 0, 1}; + Array jmap{0,-1,-1,-1, 0, 0, 1, 1, 1,-1,-1,-1, 0, 0, 0, 1, 1, 1,-1,-1,-1, 0, 0, 0, 1, 1, 1}; + Array kmap{0, 0, 0, 0, 0, 0, 0, 0, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + + const auto& is_periodic_x = lev_geom.isPeriodic(0); + const auto& is_periodic_y = lev_geom.isPeriodic(1); + const auto& is_periodic_z = lev_geom.isPeriodic(2); + +#if 0 + if (debug_print) + amrex::Print() << " IN MERGE_REDISTRIBUTE DOING BOX " << bx << std::endl; +#endif + + amrex::ParallelFor(Box(itracker), + [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept + { + itracker(i,j,k,0) = 0; + }); + + Box domain_per_grown = domain; + if (is_periodic_x) domain_per_grown.grow(0,4); + if (is_periodic_y) domain_per_grown.grow(1,4); +#if (AMREX_SPACEDIM == 3) + if (is_periodic_z) domain_per_grown.grow(2,4); +#endif + + Box const& bxg4 = amrex::grow(bx,4); + Box bx_per_g4= domain_per_grown & bxg4; + + amrex::ParallelFor(bx_per_g4, + [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept + { + if (vfrac(i,j,k) > 0.0 && vfrac(i,j,k) < target_volfrac) + { + Real apnorm, apnorm_inv; + const Real dapx = apx(i+1,j ,k ) - apx(i,j,k); + const Real dapy = apy(i ,j+1,k ) - apy(i,j,k); + const Real dapz = apz(i ,j ,k+1) - apz(i,j,k); + apnorm = std::sqrt(dapx*dapx+dapy*dapy+dapz*dapz); + apnorm_inv = Real(1.0)/apnorm; + Real nx = dapx * apnorm_inv; + Real ny = dapy * apnorm_inv; + Real nz = dapz * apnorm_inv; + + bool nx_eq_ny = ( (std::abs(nx-ny) < small_norm_diff) || + (std::abs(nx+ny) < small_norm_diff) ) ? true : false; + bool nx_eq_nz = ( (std::abs(nx-nz) < small_norm_diff) || + (std::abs(nx+nz) < small_norm_diff) ) ? true : false; + bool ny_eq_nz = ( (std::abs(ny-nz) < small_norm_diff) || + (std::abs(ny+nz) < small_norm_diff) ) ? true : false; + + bool xdir_mns_ok = (is_periodic_x || (i > domain.smallEnd(0))); + bool xdir_pls_ok = (is_periodic_x || (i < domain.bigEnd(0) )); + bool ydir_mns_ok = (is_periodic_y || (j > domain.smallEnd(1))); + bool ydir_pls_ok = (is_periodic_y || (j < domain.bigEnd(1) )); + bool zdir_mns_ok = (is_periodic_z || (k > domain.smallEnd(2))); + bool zdir_pls_ok = (is_periodic_z || (k < domain.bigEnd(2) )); + + // x-component of normal is greatest + if ( (std::abs(nx) > std::abs(ny)) && + (std::abs(nx) > std::abs(nz)) ) + { + if (nx > 0) + itracker(i,j,k,1) = 5; + else + itracker(i,j,k,1) = 4; + + // y-component of normal is greatest + } else if ( (std::abs(ny) >= std::abs(nx)) && + (std::abs(ny) > std::abs(nz)) ) + { + if (ny > 0) + itracker(i,j,k,1) = 7; + else + + itracker(i,j,k,1) = 2; + // z-component of normal is greatest + } else { + if (nz > 0) + itracker(i,j,k,1) = 22; + else + itracker(i,j,k,1) = 13; + } + + // Override above logic if trying to reach outside a domain boundary (and non-periodic) + if ( (!xdir_mns_ok && (itracker(i,j,k,1) == 4)) || + (!xdir_pls_ok && (itracker(i,j,k,1) == 5)) ) + { + if ( (std::abs(ny) > std::abs(nz)) ) + itracker(i,j,k,1) = (ny > 0) ? 7 : 2; + else + itracker(i,j,k,1) = (nz > 0) ? 22 : 13; + } + + if ( (!ydir_mns_ok && (itracker(i,j,k,1) == 2)) || + (!ydir_pls_ok && (itracker(i,j,k,1) == 7)) ) + { + if ( (std::abs(nx) > std::abs(nz)) ) + itracker(i,j,k,1) = (nx > 0) ? 5 : 4; + else + itracker(i,j,k,1) = (nz > 0) ? 22 : 13; + } + + if ( (!zdir_mns_ok && (itracker(i,j,k,1) == 13)) || + (!zdir_pls_ok && (itracker(i,j,k,1) == 22)) ) + { + if ( (std::abs(nx) > std::abs(ny)) ) + itracker(i,j,k,1) = (nx > 0) ? 5 : 4; + else + itracker(i,j,k,1) = (ny > 0) ? 7 : 2; + } + + // (i,j,k) merges with at least one cell now + itracker(i,j,k,0) += 1; + + // (i+ioff,j+joff,k+koff) is now the first cell in the nbhd of (i,j,k) + int ioff = imap[itracker(i,j,k,1)]; + int joff = jmap[itracker(i,j,k,1)]; + int koff = kmap[itracker(i,j,k,1)]; + + // Sanity check + if (vfrac(i+ioff,j+joff,k+koff) == 0.) + { + // amrex::Print() << "Cell " << IntVect(i,j,k) << " is trying to merge with cell " << IntVect(i+ioff,j+joff,k+koff) << std::endl; + amrex::Abort(" Trying to merge with covered cell"); + } + + Real sum_vol = vfrac(i,j,k) + vfrac(i+ioff,j+joff,k+koff); + +#if 0 + if (debug_print) + amrex::Print() << "Cell " << IntVect(i,j,k) << " with volfrac " << vfrac(i,j,k) << + " trying to merge with " << IntVect(i+ioff,j+joff,k+koff) << + " with volfrac " << vfrac(i+ioff,j+joff,k+koff) << + " to get new sum_vol " << sum_vol << std::endl; +#endif + + bool just_broke_symmetry = ( ( (joff == 0 && koff == 0) && (nx_eq_ny || nx_eq_nz) ) || + ( (ioff == 0 && koff == 0) && (nx_eq_ny || ny_eq_nz) ) || + ( (ioff == 0 && joff == 0) && (nx_eq_nz || ny_eq_nz) ) ); + + // If the merged cell isn't large enough, or if we broke symmetry by the current merge, + // we merge in one of the other directions. Note that the direction of the next merge + // is first set by a symmetry break, but if that isn't happening, we choose the next largest normal + + if ( (sum_vol < target_volfrac) || just_broke_symmetry ) + { + // Original offset was in x-direction + if (joff == 0 && koff == 0) + { + if (nx_eq_ny) { + itracker(i,j,k,2) = (ny > 0) ? 7 : 2; + } else if (nx_eq_nz) { + itracker(i,j,k,2) = (nz > 0) ? 22 : 13; + } else if ( (std::abs(ny) > std::abs(nz)) ) { + itracker(i,j,k,2) = (ny > 0) ? 7 : 2; + } else { + itracker(i,j,k,2) = (nz > 0) ? 22 : 13; + } + + // Original offset was in y-direction + } else if (ioff == 0 && koff == 0) + { + if (nx_eq_ny) { + itracker(i,j,k,2) = (nx > 0) ? 5 : 4; + } else if (ny_eq_nz) { + itracker(i,j,k,2) = (nz > 0) ? 22 : 13; + } else if ( (std::abs(nx) > std::abs(nz)) ) { + itracker(i,j,k,2) = (nx > 0) ? 5 : 4; + } else { + itracker(i,j,k,2) = (nz > 0) ? 22 : 13; + } + + // Original offset was in z-direction + } else if (ioff == 0 && joff == 0) + { + if (nx_eq_nz) { + itracker(i,j,k,2) = (nx > 0) ? 5 : 4; + } else if (ny_eq_nz) { + itracker(i,j,k,2) = (ny > 0) ? 7 : 2; + } else if ( (std::abs(nx) > std::abs(ny)) ) { + itracker(i,j,k,2) = (nx > 0) ? 5 : 4; + } else { + itracker(i,j,k,2) = (ny > 0) ? 7 : 2; + } + } + + // (i,j,k) merges with at least two cells now + itracker(i,j,k,0) += 1; + + // (i+ioff2,j+joff2,k+koff2) is in the nbhd of (i,j,k) + int ioff2 = imap[itracker(i,j,k,2)]; + int joff2 = jmap[itracker(i,j,k,2)]; + int koff2 = kmap[itracker(i,j,k,2)]; + + sum_vol += vfrac(i+ioff2,j+joff2,k+koff2); +#if 0 + if (debug_print) + amrex::Print() << "Cell " << IntVect(i,j,k) << " with volfrac " << vfrac(i,j,k) << + " trying to ALSO merge with " << IntVect(i+ioff2,j+joff2,k+koff2) << + " with volfrac " << vfrac(i+ioff2,j+joff2,k+koff2) << + " to get new sum_vol " << sum_vol << std::endl; +#endif + } + + // If the merged cell has merged in two directions, we now merge in the corner direction within the current plane + if (itracker(i,j,k,0) >= 2) + { + // We already have two offsets, and we know they are in different directions + ioff = imap[itracker(i,j,k,1)] + imap[itracker(i,j,k,2)]; + joff = jmap[itracker(i,j,k,1)] + jmap[itracker(i,j,k,2)]; + koff = kmap[itracker(i,j,k,1)] + kmap[itracker(i,j,k,2)]; + + // Both nbors are in the koff=0 plane + if (koff == 0) + { + if (ioff > 0 && joff > 0) + itracker(i,j,k,3) = 8; + else if (ioff < 0 && joff > 0) + itracker(i,j,k,3) = 6; + else if (ioff > 0 && joff < 0) + itracker(i,j,k,3) = 3; + else + itracker(i,j,k,3) = 1; + + // Both nbors are in the joff=0 plane + } else if (joff == 0) { + if (ioff > 0 && koff > 0) + itracker(i,j,k,3) = 23; + else if (ioff < 0 && koff > 0) + itracker(i,j,k,3) = 21; + else if (ioff > 0 && koff < 0) + itracker(i,j,k,3) = 14; + else + itracker(i,j,k,3) = 12; + + // Both nbors are in the ioff=0 plane + } else { + if (joff > 0 && koff > 0) + itracker(i,j,k,3) = 25; + else if (joff < 0 && koff > 0) + itracker(i,j,k,3) = 19; + else if (joff > 0 && koff < 0) + itracker(i,j,k,3) = 16; + else + itracker(i,j,k,3) = 10; + } + + // (i,j,k) merges with at least three cells now + itracker(i,j,k,0) += 1; + + sum_vol += vfrac(i+ioff,j+joff,k+koff); + +#if 0 + int ioff3 = imap[itracker(i,j,k,3)]; + int joff3 = jmap[itracker(i,j,k,3)]; + int koff3 = kmap[itracker(i,j,k,3)]; + if (debug_print) + amrex::Print() << "Cell " << IntVect(i,j,k) << " with volfrac " << vfrac(i,j,k) << + " trying to ALSO merge with " << IntVect(i+ioff3,j+joff3,k+koff3) << + " with volfrac " << vfrac(i+ioff3,j+joff3,k+koff3) << std::endl; +#endif + + // All nbors are currently in one of three planes + just_broke_symmetry = ( ( (koff == 0) && (nx_eq_nz || ny_eq_nz) ) || + ( (joff == 0) && (nx_eq_ny || ny_eq_nz) ) || + ( (ioff == 0) && (nx_eq_ny || nx_eq_nz) ) ); + + // If with a nbhd of four cells we have still not reached vfrac > target_volfrac, we add another four + // cells to the nbhd to make a 2x2x2 block. We use the direction of the remaining + // normal to know whether to go lo or hi in the new direction. + if (sum_vol < target_volfrac || just_broke_symmetry) + { +#if 0 + if (debug_print) + if (just_broke_symmetry) + amrex::Print() << "Expanding neighborhood of " << IntVect(i,j,k) << + " from 4 to 8 since we just broke symmetry with the last merge " << std::endl; + else + amrex::Print() << "Expanding neighborhood of " << IntVect(i,j,k) << + " from 4 to 8 since sum_vol with 4 was only " << sum_vol << " " << std::endl; +#endif + // All nbors are currently in the koff=0 plane + if (koff == 0) + { + if (nz > 0) + { + itracker(i,j,k,4) = 22; + + if (ioff > 0) + itracker(i,j,k,5) = 23; + else + itracker(i,j,k,5) = 21; + if (joff > 0) + itracker(i,j,k,6) = 25; + else + itracker(i,j,k,6) = 19; + + if (ioff > 0 && joff > 0) { + itracker(i,j,k,7) = 26; + } else if (ioff < 0 && joff > 0) { + itracker(i,j,k,7) = 24; + } else if (ioff > 0 && joff < 0) { + itracker(i,j,k,7) = 20; + } else { + itracker(i,j,k,7) = 18; + } + } else { // nz <= 0 + + itracker(i,j,k,4) = 13; + + if (ioff > 0) + itracker(i,j,k,5) = 14; + else + itracker(i,j,k,5) = 12; + if (joff > 0) + itracker(i,j,k,6) = 16; + else + itracker(i,j,k,6) = 10; + + if (ioff > 0 && joff > 0) { + itracker(i,j,k,7) = 17; + } else if (ioff < 0 && joff > 0) { + itracker(i,j,k,7) = 15; + } else if (ioff > 0 && joff < 0) { + itracker(i,j,k,7) = 11; + } else { + itracker(i,j,k,7) = 9; + } + } + } else if (joff == 0) { + if (ny > 0) + { + itracker(i,j,k,4) = 7; + + if (ioff > 0) + itracker(i,j,k,5) = 8; + else + itracker(i,j,k,5) = 6; + if (koff > 0) + itracker(i,j,k,6) = 25; + else + itracker(i,j,k,6) = 16; + + if (ioff > 0 && koff > 0) { + itracker(i,j,k,7) = 26; + } else if (ioff < 0 && koff > 0) { + itracker(i,j,k,7) = 24; + } else if (ioff > 0 && koff < 0) { + itracker(i,j,k,7) = 17; + } else { + itracker(i,j,k,7) = 15; + } + + } else { // ny <= 0 + + itracker(i,j,k,4) = 2; + + if (ioff > 0) + itracker(i,j,k,5) = 3; + else + itracker(i,j,k,5) = 1; + if (koff > 0) + itracker(i,j,k,6) = 19; + else + itracker(i,j,k,6) = 10; + + if (ioff > 0 && koff > 0) { + itracker(i,j,k,7) = 20; + } else if (ioff < 0 && koff > 0) { + itracker(i,j,k,7) = 18; + } else if (ioff > 0 && koff < 0) { + itracker(i,j,k,7) = 11; + } else { + itracker(i,j,k,7) = 9; + } + } + } else if (ioff == 0) { + + if (nx > 0) + { + itracker(i,j,k,4) = 5; + + if (joff > 0) + itracker(i,j,k,5) = 8; + else + itracker(i,j,k,5) = 3; + if (koff > 0) + itracker(i,j,k,6) = 23; + else + itracker(i,j,k,6) = 14; + + if (joff > 0 && koff > 0) { + itracker(i,j,k,7) = 26; + } else if (joff < 0 && koff > 0) { + itracker(i,j,k,7) = 20; + } else if (joff > 0 && koff < 0) { + itracker(i,j,k,7) = 17; + } else { + itracker(i,j,k,7) = 11; + } + } else { // nx <= 0 + + itracker(i,j,k,4) = 4; + + if (joff > 0) + itracker(i,j,k,5) = 6; + else + itracker(i,j,k,5) = 1; + if (koff > 0) + itracker(i,j,k,6) = 21; + else + itracker(i,j,k,6) = 12; + + if (joff > 0 && koff > 0) { + itracker(i,j,k,7) = 24; + } else if (joff < 0 && koff > 0) { + itracker(i,j,k,7) = 18; + } else if (joff > 0 && koff < 0) { + itracker(i,j,k,7) = 15; + } else { + itracker(i,j,k,7) = 9; + } + } + } + + for(int n(4); n<8; n++){ + int ioffn = imap[itracker(i,j,k,n)]; + int joffn = jmap[itracker(i,j,k,n)]; + int koffn = kmap[itracker(i,j,k,n)]; + sum_vol += vfrac(i+ioffn,j+joffn,k+koffn); +#if 0 + if (debug_print) + amrex::Print() << "Cell " << IntVect(i,j,k) << " with volfrac " << vfrac(i,j,k) << + " trying to ALSO merge with " << IntVect(i+ioffn,j+joffn,k+koffn) << + " with volfrac " << vfrac(i+ioffn,j+joffn,k+koffn) << + " to get new sum_vol " << sum_vol << std::endl; +#endif + } + + // (i,j,k) has a 2x2x2 neighborhood now + itracker(i,j,k,0) += 4; + } + } + if (sum_vol < target_volfrac) + { +#if 0 + amrex::Print() << "Couldnt merge with enough cells to raise volume at " << + IntVect(i,j,k) << " so stuck with sum_vol " << sum_vol << std::endl; +#endif + amrex::Abort("Couldnt merge with enough cells to raise volume greater than target_volfrac"); + } + } + }); +} + +#endif + +} diff --git a/Src/EB/AMReX_EB_StateRedistSlopeLimiter_K.H b/Src/EB/AMReX_EB_StateRedistSlopeLimiter_K.H new file mode 100644 index 00000000000..7ce6c5cdd0a --- /dev/null +++ b/Src/EB/AMReX_EB_StateRedistSlopeLimiter_K.H @@ -0,0 +1,93 @@ +#ifndef AMREX_EB_STATE_REDIST_SLOPE_LIMITER_K_H_ +#define AMREX_EB_STATE_REDIST_SLOPE_LIMITER_K_H_ + +namespace amrex { + +AMREX_GPU_DEVICE AMREX_FORCE_INLINE +amrex::Real +amrex_calc_alpha_stencil(Real q_hat, Real q_max, Real q_min, Real state) noexcept +{ +#ifdef AMREX_USE_FLOAT + constexpr Real epsilon = amrex::Real(1.e-6); +#else + constexpr Real epsilon = 1.e-12; +#endif + + const Real small = epsilon*amrex::max(amrex::Math::abs(q_max),amrex::Math::abs(q_min)); + Real alpha; + + if ((q_hat-state) > small) { + alpha = amrex::min(1.0_rt,(q_max-state)/(q_hat-state)); + } else if ((q_hat-state) < -small) { + alpha = amrex::min(1.0_rt,(q_min-state)/(q_hat-state)); + } else { + alpha = 1.0_rt; + } + return alpha; +} + +AMREX_GPU_DEVICE AMREX_FORCE_INLINE +amrex::GpuArray +amrex_calc_centroid_limiter(int i, int j, int k, int n, + amrex::Array4 const& state, + amrex::Array4 const& flag, + const amrex::GpuArray& slopes, + amrex::Array4 const& ccent) noexcept +{ +#ifdef AMREX_USE_FLOAT + constexpr Real epsilon = amrex::Real(1.e-6); +#else + constexpr Real epsilon = 1.e-12; +#endif + + AMREX_D_TERM(amrex::Real xalpha = 1.0;, + amrex::Real yalpha = 1.0;, + amrex::Real zalpha = 1.0;); + + // Compute the limiters needed to keep the predicted q_hat between the max and min +#if (AMREX_SPACEDIM == 2) + int kk = 0; +#elif (AMREX_SPACEDIM == 3) + for(int kk(-1); kk<=1; kk++) +#endif + { + for(int jj(-1); jj<=1; jj++){ + for(int ii(-1); ii<=1; ii++){ + Real alpha = amrex::max(xalpha,yalpha); +#if (AMREX_SPACEDIM == 3) + alpha = amrex::max(alpha,zalpha); +#endif + if (flag(i,j,k).isConnected(ii,jj,kk) && alpha > 0.0) + { + AMREX_D_TERM(Real delta_x = ccent(i+ii,j+jj,k+kk,0) - ccent(i,j,k,0) + static_cast(ii);, + Real delta_y = ccent(i+ii,j+jj,k+kk,1) - ccent(i,j,k,1) + static_cast(jj);, + Real delta_z = ccent(i+ii,j+jj,k+kk,2) - ccent(i,j,k,2) + static_cast(kk);); + + Real q_hat = state(i,j,k,n) + AMREX_D_TERM( delta_x * slopes[0], + + delta_y * slopes[1], + + delta_z * slopes[2]); + + Real q_max = amrex::max(state(i+ii,j+jj,k+kk,n),state(i,j,k,n)); + Real q_min = amrex::min(state(i+ii,j+jj,k+kk,n),state(i,j,k,n)); + + if ( q_hat-q_max > amrex::Math::abs(epsilon*q_max) || q_hat-q_min < -1.0*amrex::Math::abs(epsilon*q_min) ) + { + Real new_lim = amrex_calc_alpha_stencil(q_hat, q_max, q_min, state(i,j,k,n)); + + if (amrex::Math::abs(delta_x) > epsilon) xalpha = amrex::min(xalpha,new_lim); + if (amrex::Math::abs(delta_y) > epsilon) yalpha = amrex::min(yalpha,new_lim); +#if (AMREX_SPACEDIM == 3) + if (amrex::Math::abs(delta_z) > epsilon) zalpha = amrex::min(zalpha,new_lim); +#endif + } + } + } + } + } + + return {AMREX_D_DECL(xalpha,yalpha,zalpha)}; +} + +} + +#endif diff --git a/Src/EB/AMReX_EB_StateRedistUtils.cpp b/Src/EB/AMReX_EB_StateRedistUtils.cpp new file mode 100644 index 00000000000..80539761516 --- /dev/null +++ b/Src/EB/AMReX_EB_StateRedistUtils.cpp @@ -0,0 +1,206 @@ +/** + * \file AMReX_StateRedistUtils.cpp + */ + +#include + +namespace amrex { + +void +MakeStateRedistUtils ( Box const& bx, + Array4 const& flag, + Array4 const& vfrac, + Array4 const& ccent, + Array4 const& itracker, + Array4 const& nrs, + Array4 const& alpha, + Array4 const& nbhd_vol, + Array4 const& cent_hat, + Geometry const& lev_geom, + Real target_vol) +{ + // Note that itracker has {4 in 2D, 8 in 3D} components and all are initialized to zero + // We will add to the first component every time this cell is included in a merged neighborhood, + // either by merging or being merged + // + // In 2D, we identify the cells in the remaining three components with the following ordering + // + // ^ 6 7 8 + // | 4 5 + // j 1 2 3 + // i ---> + // + // In 3D, We identify the cells in the remaining three components with the following ordering + // + // at k-1 | at k | at k+1 + // + // ^ 15 16 17 | 6 7 8 | 24 25 26 + // | 12 13 14 | 4 5 | 21 22 23 + // j 9 10 11 | 1 2 3 | 18 19 20 + // i ---> + // + // Note the first component of each of these arrays should never be used + // +#if (AMREX_SPACEDIM == 2) + Array imap{0,-1, 0, 1,-1, 1,-1, 0, 1}; + Array jmap{0,-1,-1,-1, 0, 0, 1, 1, 1}; + Array kmap{0, 0, 0, 0, 0, 0, 0, 0, 0}; +#else + Array imap{0,-1, 0, 1,-1, 1,-1, 0, 1,-1, 0, 1,-1, 0, 1,-1, 0, 1,-1, 0, 1,-1, 0, 1,-1, 0, 1}; + Array jmap{0,-1,-1,-1, 0, 0, 1, 1, 1,-1,-1,-1, 0, 0, 0, 1, 1, 1,-1,-1,-1, 0, 0, 0, 1, 1, 1}; + Array kmap{0, 0, 0, 0, 0, 0, 0, 0, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; +#endif + + AMREX_D_TERM(const auto& is_periodic_x = lev_geom.isPeriodic(0);, + const auto& is_periodic_y = lev_geom.isPeriodic(1);, + const auto& is_periodic_z = lev_geom.isPeriodic(2);); + + Box const& bxg2 = amrex::grow(bx,2); + Box const& bxg3 = amrex::grow(bx,3); + Box const& bxg4 = amrex::grow(bx,4); + + const Box domain = lev_geom.Domain(); + + Box domain_per_grown = domain; + if (is_periodic_x) domain_per_grown.grow(0,2); + if (is_periodic_y) domain_per_grown.grow(1,2); +#if (AMREX_SPACEDIM == 3) + if (is_periodic_z) domain_per_grown.grow(2,2); +#endif + + amrex::ParallelFor(bxg3, + [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept + { + // Everyone is in their own neighborhood at least + nrs(i,j,k) = 1.; + alpha(i,j,k,0) = 1.; + alpha(i,j,k,1) = 1.; + }); + + // nrs captures how many neighborhoods (r,s) is in + amrex::ParallelFor(bxg4, + [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept + { + // This loops over the neighbors of (i,j,k), and doesn't include (i,j,k) itself + for (int i_nbor = 1; i_nbor <= itracker(i,j,k,0); i_nbor++) + { + int r = i+imap[itracker(i,j,k,i_nbor)]; + int s = j+jmap[itracker(i,j,k,i_nbor)]; + int t = k+kmap[itracker(i,j,k,i_nbor)]; + if ( domain_per_grown.contains(IntVect(AMREX_D_DECL(r,s,t))) && + bxg3.contains(IntVect(AMREX_D_DECL(r,s,t))) ) + { + amrex::Gpu::Atomic::Add(&nrs(r,s,t),1.0_rt); + } + } + }); + + amrex::ParallelFor(bxg2, + [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept + { + if (!flag(i,j,k).isCovered()) + { + // Start with the vfrac of (i,j,k) + nbhd_vol(i,j,k) = vfrac(i,j,k) / nrs(i,j,k); + Real vol_of_nbors = 0.; + + // This loops over the neighbors of (i,j,k), and doesn't include (i,j,k) itself + for (int i_nbor = 1; i_nbor <= itracker(i,j,k,0); i_nbor++) + { + int r = i+imap[itracker(i,j,k,i_nbor)]; + int s = j+jmap[itracker(i,j,k,i_nbor)]; + int t = k+kmap[itracker(i,j,k,i_nbor)]; + amrex::Gpu::Atomic::Add(&nbhd_vol(i,j,k),vfrac(r,s,t) / nrs(r,s,t)); + vol_of_nbors += vfrac(r,s,t); + } + + if (itracker(i,j,k,0) > 0) + alpha(i,j,k,1) = (target_vol - vfrac(i,j,k)) / vol_of_nbors; + + } else { + nbhd_vol(i,j,k) = 0.; + alpha(i,j,k,0) = 0.; + alpha(i,j,k,1) = 0.; + } + }); + + // Define how much each cell keeps + amrex::ParallelFor(bxg2, + [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept + { + if (!flag(i,j,k).isCovered()) + { + // This loops over the neighbors of (i,j,k), and doesn't include (i,j,k) itself + for (int i_nbor = 1; i_nbor <= itracker(i,j,k,0); i_nbor++) + { + int r = i+imap[itracker(i,j,k,i_nbor)]; + int s = j+jmap[itracker(i,j,k,i_nbor)]; + int t = k+kmap[itracker(i,j,k,i_nbor)]; + amrex::Gpu::Atomic::Add(&alpha(r,s,t,0),-(alpha(i,j,k,1)/nrs(r,s,t))); + } + } + }); + + // Redefine nbhd_vol + amrex::ParallelFor(bxg2, + [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept + { + if (!flag(i,j,k).isCovered()) + { + nbhd_vol(i,j,k) = alpha(i,j,k,0) * vfrac(i,j,k); + + // This loops over the neighbors of (i,j,k), and doesn't include (i,j,k) itself + for (int i_nbor = 1; i_nbor <= itracker(i,j,k,0); i_nbor++) + { + int r = i+imap[itracker(i,j,k,i_nbor)]; + int s = j+jmap[itracker(i,j,k,i_nbor)]; + int t = k+kmap[itracker(i,j,k,i_nbor)]; + amrex::Gpu::Atomic::Add(&nbhd_vol(i,j,k),alpha(i,j,k,1) * vfrac(r,s,t) / nrs(r,s,t)); + } + } + }); + + // Define xhat,yhat,zhat (from Berger and Guliani) + amrex::ParallelFor(bxg3, + [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept + { + if (vfrac(i,j,k) > 0.0) + { + AMREX_D_TERM(cent_hat(i,j,k,0) = ccent(i,j,k,0);, + cent_hat(i,j,k,1) = ccent(i,j,k,1);, + cent_hat(i,j,k,2) = ccent(i,j,k,2);); + + if ( itracker(i,j,k,0) > 0 && + domain_per_grown.contains(IntVect(AMREX_D_DECL(i,j,k))) && + bxg2.contains(IntVect(AMREX_D_DECL(i,j,k))) ) { + + AMREX_D_TERM(cent_hat(i,j,k,0) = ccent(i,j,k,0) * alpha(i,j,k,0) *vfrac(i,j,k);, + cent_hat(i,j,k,1) = ccent(i,j,k,1) * alpha(i,j,k,0) *vfrac(i,j,k);, + cent_hat(i,j,k,2) = ccent(i,j,k,2) * alpha(i,j,k,0) *vfrac(i,j,k);); + + // This loops over the neighbors of (i,j,k), and doesn't include (i,j,k) itself + for (int i_nbor = 1; i_nbor <= itracker(i,j,k,0); i_nbor++) + { + int ii = imap[itracker(i,j,k,i_nbor)]; int r = i+ii; + int jj = jmap[itracker(i,j,k,i_nbor)]; int s = j+jj; + int kk = kmap[itracker(i,j,k,i_nbor)]; int t = k+kk; + + AMREX_D_TERM(cent_hat(i,j,k,0) += (ccent(r,s,t,0) + ii) * alpha(i,j,k,1) * vfrac(r,s,t) / nrs(r,s,t);, + cent_hat(i,j,k,1) += (ccent(r,s,t,1) + jj) * alpha(i,j,k,1) * vfrac(r,s,t) / nrs(r,s,t);, + cent_hat(i,j,k,2) += (ccent(r,s,t,2) + kk) * alpha(i,j,k,1) * vfrac(r,s,t) / nrs(r,s,t);); + } + + AMREX_D_TERM(cent_hat(i,j,k,0) /= nbhd_vol(i,j,k);, + cent_hat(i,j,k,1) /= nbhd_vol(i,j,k);, + cent_hat(i,j,k,2) /= nbhd_vol(i,j,k);); + } + } else { + + AMREX_D_TERM(cent_hat(i,j,k,0) = eb_covered_val;, + cent_hat(i,j,k,1) = eb_covered_val;, + cent_hat(i,j,k,2) = eb_covered_val;); + } + }); +} + +} diff --git a/Src/EB/AMReX_EB_StateRedistribute.cpp b/Src/EB/AMReX_EB_StateRedistribute.cpp new file mode 100644 index 00000000000..af6c255bf63 --- /dev/null +++ b/Src/EB/AMReX_EB_StateRedistribute.cpp @@ -0,0 +1,312 @@ +/** + * \file AMReX_StateRedistribute.cpp + */ + +#include +#include +#include + +namespace amrex { + +void +StateRedistribute ( Box const& bx, int ncomp, + Array4 const& U_out, + Array4 const& U_in, + Array4 const& flag, + Array4 const& vfrac, + AMREX_D_DECL(Array4 const& fcx, + Array4 const& fcy, + Array4 const& fcz), + Array4 const& ccent, + amrex::BCRec const* d_bcrec_ptr, + Array4< int const> const& itracker, + Array4 const& nrs, + Array4 const& alpha, + Array4 const& nbhd_vol, + Array4 const& cent_hat, + Geometry const& lev_geom, + int max_order) +{ + // Note that itracker has {4 in 2D, 8 in 3D} components and all are initialized to zero + // We will add to the first component every time this cell is included in a merged neighborhood, + // either by merging or being merged + // + // In 2D, we identify the cells in the remaining three components with the following ordering + // + // ^ 6 7 8 + // | 4 5 + // j 1 2 3 + // i ---> + // + // In 3D, We identify the cells in the remaining three components with the following ordering + // + // at k-1 | at k | at k+1 + // + // ^ 15 16 17 | 6 7 8 | 24 25 26 + // | 12 13 14 | 4 5 | 21 22 23 + // j 9 10 11 | 1 2 3 | 18 19 20 + // i ---> + // + // Note the first component of each of these arrays should never be used + // +#if (AMREX_SPACEDIM == 2) + amrex::GpuArray imap{0,-1, 0, 1,-1, 1,-1, 0, 1}; + amrex::GpuArray jmap{0,-1,-1,-1, 0, 0, 1, 1, 1}; + amrex::GpuArray kmap{0, 0, 0, 0, 0, 0, 0, 0, 0}; +#else + amrex::GpuArray imap{0,-1, 0, 1,-1, 1,-1, 0, 1,-1, 0, 1,-1, 0, 1,-1, 0, 1,-1, 0, 1,-1, 0, 1,-1, 0, 1}; + amrex::GpuArray jmap{0,-1,-1,-1, 0, 0, 1, 1, 1,-1,-1,-1, 0, 0, 0, 1, 1, 1,-1,-1,-1, 0, 0, 0, 1, 1, 1}; + amrex::GpuArray kmap{0, 0, 0, 0, 0, 0, 0, 0, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; +#endif + + const Box domain = lev_geom.Domain(); + const int domain_ilo = domain.smallEnd(0); + const int domain_ihi = domain.bigEnd(0); + const int domain_jlo = domain.smallEnd(1); + const int domain_jhi = domain.bigEnd(1); +#if (AMREX_SPACEDIM == 3) + const int domain_klo = domain.smallEnd(2); + const int domain_khi = domain.bigEnd(2); +#endif + + AMREX_D_TERM(const auto& is_periodic_x = lev_geom.isPeriodic(0);, + const auto& is_periodic_y = lev_geom.isPeriodic(1);, + const auto& is_periodic_z = lev_geom.isPeriodic(2);); + + Box const& bxg1 = amrex::grow(bx,1); + Box const& bxg2 = amrex::grow(bx,2); + Box const& bxg3 = amrex::grow(bx,3); + + Box domain_per_grown = domain; + if (is_periodic_x) domain_per_grown.grow(0,2); + if (is_periodic_y) domain_per_grown.grow(1,2); +#if (AMREX_SPACEDIM == 3) + if (is_periodic_z) domain_per_grown.grow(2,2); +#endif + + // Solution at the centroid of my nbhd + FArrayBox soln_hat_fab (bxg3,ncomp,The_Async_Arena()); + Array4 soln_hat = soln_hat_fab.array(); + + // Define Qhat (from Berger and Guliani) + // Here we initialize soln_hat to equal U_in on all cells in bxg3 so that + // in the event we need to use soln_hat 3 cells out from the bx limits + // in a modified slope computation, we have a value of soln_hat to use. + // But we only modify soln_hat inside bxg2 + amrex::ParallelFor(bxg3, + [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept + { + for (int n = 0; n < ncomp; n++) + soln_hat(i,j,k,n) = U_in(i,j,k,n); + + if (vfrac(i,j,k) > 0.0 && bxg2.contains(IntVect(AMREX_D_DECL(i,j,k))) + && domain_per_grown.contains(IntVect(AMREX_D_DECL(i,j,k)))) { + + // Start with U_in(i,j,k) itself + for (int n = 0; n < ncomp; n++) + soln_hat(i,j,k,n) = U_in(i,j,k,n) * alpha(i,j,k,0) * vfrac(i,j,k); + + // This loops over the neighbors of (i,j,k), and doesn't include (i,j,k) itself + for (int i_nbor = 1; i_nbor <= itracker(i,j,k,0); i_nbor++) + { + int r = i+imap[itracker(i,j,k,i_nbor)]; + int s = j+jmap[itracker(i,j,k,i_nbor)]; + int t = k+kmap[itracker(i,j,k,i_nbor)]; + + if (domain_per_grown.contains(IntVect(AMREX_D_DECL(r,s,t)))) + { + for (int n = 0; n < ncomp; n++) + soln_hat(i,j,k,n) += U_in(r,s,t,n) * alpha(i,j,k,1) * vfrac(r,s,t) / nrs(r,s,t); + } + } + for (int n = 0; n < ncomp; n++) + soln_hat(i,j,k,n) /= nbhd_vol(i,j,k); + } + }); + + amrex::ParallelFor(bxg1, + [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept + { + if (vfrac(i,j,k) > 0.0) + { + int num_nbors = itracker(i,j,k,0); + + if (itracker(i,j,k,0) == 0) + { + if (bx.contains(IntVect(AMREX_D_DECL(i,j,k)))) + { + for (int n = 0; n < ncomp; n++) + amrex::Gpu::Atomic::Add(&U_out(i,j,k,n),alpha(i,j,k,0)*nrs(i,j,k)*soln_hat(i,j,k,n)); + } + + } else { + + for (int n = 0; n < ncomp; n++) + { + bool extdir_ilo = (d_bcrec_ptr[n].lo(0) == amrex::BCType::ext_dir || + d_bcrec_ptr[n].lo(0) == amrex::BCType::hoextrap); + bool extdir_ihi = (d_bcrec_ptr[n].hi(0) == amrex::BCType::ext_dir || + d_bcrec_ptr[n].hi(0) == amrex::BCType::hoextrap); + bool extdir_jlo = (d_bcrec_ptr[n].lo(1) == amrex::BCType::ext_dir || + d_bcrec_ptr[n].lo(1) == amrex::BCType::hoextrap); + bool extdir_jhi = (d_bcrec_ptr[n].hi(1) == amrex::BCType::ext_dir || + d_bcrec_ptr[n].hi(1) == amrex::BCType::hoextrap); +#if (AMREX_SPACEDIM == 3) + bool extdir_klo = (d_bcrec_ptr[n].lo(2) == amrex::BCType::ext_dir || + d_bcrec_ptr[n].lo(2) == amrex::BCType::hoextrap); + bool extdir_khi = (d_bcrec_ptr[n].hi(2) == amrex::BCType::ext_dir || + d_bcrec_ptr[n].hi(2) == amrex::BCType::hoextrap); +#endif + // Initialize so that the slope stencil goes from -1:1 in each diretion + int nx = 1; int ny = 1; int nz = 1; + + // Do we have enough extent in each coordinate direction to use the 3x3x3 stencil + // or do we need to enlarge it? + AMREX_D_TERM(Real x_max = -Real(1.e30); Real x_min = Real(1.e30);, + Real y_max = -Real(1.e30); Real y_min = Real(1.e30);, + Real z_max = -Real(1.e30); Real z_min = Real(1.e30);); + + Real slope_stencil_min_width = 0.5; +#if (AMREX_SPACEDIM == 2) + int kk = 0; +#elif (AMREX_SPACEDIM == 3) + for(int kk(-1); kk<=1; kk++) +#endif + { + for(int jj(-1); jj<=1; jj++) + for(int ii(-1); ii<=1; ii++) + if (flag(i,j,k).isConnected(ii,jj,kk)) + { + int r = i+ii; int s = j+jj; int t = k+kk; + + x_max = amrex::max(x_max, cent_hat(r,s,t,0)+static_cast(ii)); + x_min = amrex::min(x_min, cent_hat(r,s,t,0)+static_cast(ii)); + y_max = amrex::max(y_max, cent_hat(r,s,t,1)+static_cast(jj)); + y_min = amrex::min(y_min, cent_hat(r,s,t,1)+static_cast(jj)); +#if (AMREX_SPACEDIM == 3) + z_max = amrex::max(z_max, cent_hat(r,s,t,2)+static_cast(kk)); + z_min = amrex::min(z_min, cent_hat(r,s,t,2)+static_cast(kk)); +#endif + } + } + // If we need to grow the stencil, we let it be -nx:nx in the x-direction, + // for example. Note that nx,ny,nz are either 1 or 2 + if ( (x_max-x_min) < slope_stencil_min_width ) nx = 2; + if ( (y_max-y_min) < slope_stencil_min_width ) ny = 2; +#if (AMREX_SPACEDIM == 3) + if ( (z_max-z_min) < slope_stencil_min_width ) nz = 2; +#endif + + amrex::GpuArray slopes_eb; + if (nx*ny*nz == 1) { + // Compute slope using 3x3x3 stencil + slopes_eb = amrex_calc_slopes_extdir_eb( + i,j,k,n,soln_hat,cent_hat,vfrac, + AMREX_D_DECL(fcx,fcy,fcz),flag, + AMREX_D_DECL(extdir_ilo, extdir_jlo, extdir_klo), + AMREX_D_DECL(extdir_ihi, extdir_jhi, extdir_khi), + AMREX_D_DECL(domain_ilo, domain_jlo, domain_klo), + AMREX_D_DECL(domain_ihi, domain_jhi, domain_khi), + max_order); + + } else { + // Compute slope using grown stencil (no larger than 5x5x5) + slopes_eb = amrex_calc_slopes_extdir_eb_grown( + i,j,k,n,AMREX_D_DECL(nx,ny,nz), + soln_hat,cent_hat,vfrac, + AMREX_D_DECL(fcx,fcy,fcz),flag, + AMREX_D_DECL(extdir_ilo, extdir_jlo, extdir_klo), + AMREX_D_DECL(extdir_ihi, extdir_jhi, extdir_khi), + AMREX_D_DECL(domain_ilo, domain_jlo, domain_klo), + AMREX_D_DECL(domain_ihi, domain_jhi, domain_khi), + max_order); + } + + // We do the limiting separately because this limiter limits the slope based on the values + // extrapolated to the cell centroid (cent_hat) locations - unlike the limiter in amrex + // which bases the limiting on values extrapolated to the face centroids. + amrex::GpuArray lim_slope = + amrex_calc_centroid_limiter(i,j,k,n,soln_hat,flag,slopes_eb,cent_hat); + + AMREX_D_TERM(lim_slope[0] *= slopes_eb[0];, + lim_slope[1] *= slopes_eb[1];, + lim_slope[2] *= slopes_eb[2];); + + // Add to the cell itself + if (bx.contains(IntVect(AMREX_D_DECL(i,j,k)))) + { + Real update = soln_hat(i,j,k,n); + AMREX_D_TERM(update += lim_slope[0] * (ccent(i,j,k,0)-cent_hat(i,j,k,0));, + update += lim_slope[1] * (ccent(i,j,k,1)-cent_hat(i,j,k,1));, + update += lim_slope[2] * (ccent(i,j,k,2)-cent_hat(i,j,k,2));); + amrex::Gpu::Atomic::Add(&U_out(i,j,k,n),alpha(i,j,k,0)*nrs(i,j,k)*update); + } // if bx contains + + // This loops over the neighbors of (i,j,k), and doesn't include (i,j,k) itself + for (int i_nbor = 1; i_nbor <= num_nbors; i_nbor++) + { + int r = i+imap[itracker(i,j,k,i_nbor)]; + int s = j+jmap[itracker(i,j,k,i_nbor)]; + int t = k+kmap[itracker(i,j,k,i_nbor)]; + + if (bx.contains(IntVect(AMREX_D_DECL(r,s,t)))) + { + Real update = soln_hat(i,j,k,n); + AMREX_D_TERM(update += lim_slope[0] * (ccent(r,s,t,0)-cent_hat(i,j,k,0) + static_cast(r-i));, + update += lim_slope[1] * (ccent(r,s,t,1)-cent_hat(i,j,k,1) + static_cast(s-j));, + update += lim_slope[2] * (ccent(r,s,t,2)-cent_hat(i,j,k,2) + static_cast(t-k));); + amrex::Gpu::Atomic::Add(&U_out(r,s,t,n),alpha(i,j,k,1)*update); + } // if bx contains + } // i_nbor + } // n + } // num_nbors + } // vfrac + }); + + amrex::ParallelFor(bx,ncomp, + [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept + { + if (!flag(i,j,k).isCovered()) + { + // This seems to help with a compiler issue ... + auto denom = Real(1.) / (nrs(i,j,k) + Real(1.e-30)); + U_out(i,j,k,n) *= denom; + } + else + { + U_out(i,j,k,n) = Real(1.e30); + } + }); + +#if 0 + // + // This tests whether the redistribution procedure was conservative -- + // only use if bx is the whole domain + // + { + for (int n = 0; n < ncomp; n++) + { + Real sum1(0); + Real sum2(0); +#if (AMREX_SPACEDIM == 2) + int k = 0; +#else + for (int k = bx.smallEnd(2); k <= domain.bigEnd(2); k++) +#endif + for (int j = bx.smallEnd(1); j <= domain.bigEnd(1); j++) + for (int i = bx.smallEnd(0); i <= domain.bigEnd(0); i++) + { + sum1 += vfrac(i,j,k)*U_in(i,j,k,n); + sum2 += vfrac(i,j,k)*U_out(i,j,k,n); + } + if (std::abs(sum1-sum2) > 1.e-8 * sum1 && std::abs(sum1-sum2) > 1.e-8) + { + printf("SUMS DO NOT MATCH IN STATE REDIST : %f %f ",sum1,sum2); + amrex::Abort(); + } + } + } +#endif +} + +} diff --git a/Src/EB/AMReX_EB_utils.H b/Src/EB/AMReX_EB_utils.H index 9bb07b562a3..10c5246c9e6 100644 --- a/Src/EB/AMReX_EB_utils.H +++ b/Src/EB/AMReX_EB_utils.H @@ -8,40 +8,6 @@ #include namespace amrex { - -#if (AMREX_SPACEDIM > 1) - - void single_level_redistribute (MultiFab& div_tmp_in, MultiFab& div_out, - int div_comp, int ncomp, const Geometry& geom); - - void single_level_weighted_redistribute (MultiFab& div_tmp_in, MultiFab& div_out, const MultiFab& weights, - int div_comp, int ncomp, const Geometry& geom); - - void apply_flux_redistribution ( const Box& bx, - Array4 const& div, - Array4 const& divc, - Array4 const& wt, - int icomp, - int ncomp, - Array4 const& flags, - Array4 const& vfrac, - const Geometry & geom); - -#if (__cplusplus >= 201402L) - [[deprecated]] -#endif - inline void single_level_redistribute (int lev, MultiFab& div_tmp_in, MultiFab& div_out, - int div_comp, int ncomp, const Vector& geom) - { single_level_redistribute(div_tmp_in, div_out, div_comp, ncomp, geom[lev]); } - -#if (__cplusplus >= 201402L) - [[deprecated]] -#endif - inline void single_level_weighted_redistribute (int lev, MultiFab& div_tmp_in, MultiFab& div_out, const MultiFab& weights, - int div_comp, int ncomp, const Vector& geom) - { single_level_weighted_redistribute(div_tmp_in, div_out, weights, div_comp, ncomp, geom[lev]); } -#endif - /** * \brief Fill MultiFab with implicit function. * diff --git a/Src/EB/AMReX_EB_utils.cpp b/Src/EB/AMReX_EB_utils.cpp index b0094542d22..ff8c16f5d76 100644 --- a/Src/EB/AMReX_EB_utils.cpp +++ b/Src/EB/AMReX_EB_utils.cpp @@ -8,277 +8,6 @@ namespace amrex { -#if (AMREX_SPACEDIM > 1) - // - // Do small cell redistribution on one FAB - // - void apply_eb_redistribution ( const Box& bx, - MultiFab& div_mf, - MultiFab& divc_mf, - const MultiFab& weights, - MFIter* mfi, - int icomp, - int ncomp, - const EBCellFlagFab& flags_fab, - const MultiFab* volfrac, - Box& /*domain*/, - const Geometry & geom) - { - // - // Check that grid is uniform - // - const Real* dx = geom.CellSize(); - -#if (AMREX_SPACEDIM == 2) - if (! amrex::almostEqual(dx[0], dx[1])) - amrex::Abort("apply_eb_redistribution(): grid spacing must be uniform"); -#elif (AMREX_SPACEDIM == 3) - if( ! amrex::almostEqual(dx[0],dx[1]) || - ! amrex::almostEqual(dx[1],dx[2]) ) - amrex::Abort("apply_eb_redistribution(): grid spacing must be uniform"); -#endif - - // - // Get array4 from arguments - // - Array4 const& div = div_mf.array(*mfi); - Array4 const& divc = divc_mf.array(*mfi); - auto const& wt = weights.array(*mfi); - auto const& flags = flags_fab.array(); - auto const& vfrac = volfrac->array(*mfi); - - apply_flux_redistribution ( bx, div, divc, wt, icomp, ncomp, flags, vfrac, geom); - } - - // - // Do small cell redistribution on one FAB with the Array4's already passed in - // - void apply_flux_redistribution ( const Box& bx, - Array4 const& div, - Array4 const& divc, - Array4 const& wt, - int icomp, - int ncomp, - Array4 const& flags, - Array4 const& vfrac, - const Geometry & geom) - { - // - // Check that grid is uniform - // - const Real* dx = geom.CellSize(); - -#if (AMREX_SPACEDIM == 2) - if (! amrex::almostEqual(dx[0], dx[1])) { - amrex::Abort("apply_eb_redistribution(): grid spacing must be uniform"); - } -#elif (AMREX_SPACEDIM == 3) - if( ! amrex::almostEqual(dx[0],dx[1]) || - ! amrex::almostEqual(dx[1],dx[2]) ) { - amrex::Abort("apply_eb_redistribution(): grid spacing must be uniform"); - } -#endif - - const Box dbox = geom.growPeriodicDomain(2); - - // - // Get array from arguments - // - // Array4 const& div = div_mf.array(*mfi); - // Array4 const& divc = divc_mf.array(*mfi); - // auto const& wt = weights.array(*mfi); - // auto const& flags = flags_fab.array(); - // auto const& vfrac = volfrac->array(*mfi); - - const Box& grown1_bx = amrex::grow(bx,1); - const Box& grown2_bx = amrex::grow(bx,2); - - // - // Working arrays - // - FArrayBox delm_fab(grown1_bx,ncomp); - FArrayBox optmp_fab(grown2_bx,ncomp); - FArrayBox mask_fab(grown2_bx); - - Array4 const& optmp = optmp_fab.array(); - Array4 const& mask = mask_fab.array(); - Array4 const& delm = delm_fab.array(); - - // - // Array "mask" is used to sever the link to ghost cells when the BCs - // are not periodic - // It is set to 1 when a cell can be used in computations, 0 otherwise - // - AMREX_FOR_3D(grown2_bx, i, j, k, - { - mask(i,j,k) = (dbox.contains(IntVect(AMREX_D_DECL(i,j,k)))) ? 1.0 : 0.0; - }); - - // - // Init to zero tmp array - // - AMREX_FOR_4D(grown2_bx, ncomp, i, j, k, n, - { - optmp(i,j,k,n) = 0; - }); - - // - // Step 2: compute delta M (mass gain or loss) on (lo-1,lo+1) - // - AMREX_FOR_4D(grown1_bx, ncomp, i, j, k, n, - { - if(flags(i,j,k).isSingleValued()) - { - Real divnc(0.0); - Real vtot(0.0); - Real wted_frac(0.0); - int ks = (AMREX_SPACEDIM == 3) ? -1 : 0; - int ke = (AMREX_SPACEDIM == 3) ? 1 : 0; - - for (int kk(ks); kk <= ke; ++kk) { - for (int jj(-1); jj <= 1; ++jj) { - for (int ii(-1); ii <= 1; ++ii) { - if( (ii != 0 || jj != 0 || kk != 0) && - flags(i,j,k).isConnected(ii,jj,kk) && - dbox.contains(IntVect(AMREX_D_DECL(i+ii,j+jj,k+kk)))) - { - wted_frac = vfrac(i+ii,j+jj,k+kk) * wt(i+ii,j+jj,k+kk) * mask(i+ii,j+jj,k+kk); - vtot += wted_frac; - divnc += wted_frac * divc(i+ii,j+jj,k+kk,n); - } - } - } - } - divnc /= (vtot + 1.e-80); - - // We need to multiply by mask to make sure optmp is zero for cells - // outside the domain for non-cyclic BCs - optmp(i,j,k,n) = (1 - vfrac(i,j,k)) * (divnc - divc(i,j,k,n)) * mask(i,j,k); - delm(i,j,k,n) = -( vfrac(i,j,k)) * optmp(i,j,k,n); - - } - else - { - delm(i,j,k,n) = 0; - } - }); - - - // - // Step 3: redistribute excess/loss of mass - // - AMREX_FOR_4D(grown1_bx, ncomp, i, j, k, n, - { - if(flags(i,j,k).isSingleValued()) - { - Real wtot(0.0); - int ks = (AMREX_SPACEDIM == 3) ? -1 : 0; - int ke = (AMREX_SPACEDIM == 3) ? 1 : 0; - - for (int kk(ks); kk <= ke; ++kk) { - for (int jj(-1); jj <= 1; ++jj) { - for (int ii(-1); ii <= 1; ++ii) { - - if( (ii != 0 || jj != 0 || kk != 0) && - (flags(i,j,k).isConnected(ii,jj,kk)) ) - { - wtot += wt(i+ii,j+jj,k+kk) * vfrac(i+ii,j+jj,k+kk) * mask(i+ii,j+jj,k+kk); - } - - }}} - - wtot = 1.0/(wtot + 1.e-80); - - for (int kk(ks); kk <= ke; ++kk) { - for (int jj(-1); jj <= 1; ++jj) { - for (int ii(-1); ii <= 1; ++ii) { - - if( (ii != 0 || jj != 0 || kk != 0) && - (flags(i,j,k).isConnected(ii,jj,kk)) && - bx.contains(IntVect(AMREX_D_DECL(i+ii,j+jj,k+kk))) ) - { - Gpu::Atomic::AddNoRet(&optmp(i+ii,j+jj,k+kk,n), - delm(i,j,k,n) * wtot * mask(i+ii,j+jj,k+kk) * wt(i+ii,j+jj,k+kk)); - } - }}} - - } - }); - - // - // Resume the correct sign, AKA return the negative - // - AMREX_FOR_4D(bx, ncomp, i, j, k, n, - { - div(i,j,k,icomp+n) = divc(i,j,k,n) + optmp(i,j,k,n); - }); - - Gpu::streamSynchronize(); - } - - // - // Do small cell redistribution on a MultiFab -- with a weighting function - // - void single_level_weighted_redistribute (MultiFab& div_tmp_in, MultiFab& div_out, const MultiFab& weights, - int div_comp, int ncomp, const Geometry& geom) - { - Box domain(geom.Domain()); - -#ifdef AMREX_USE_FLOAT - Real covered_val = Real(1.e20); -#else - Real covered_val = 1.e40; -#endif - - int nghost = 2; - AMREX_ASSERT(div_tmp_in.nGrow() >= nghost); - - EB_set_covered(div_tmp_in, 0, ncomp, div_tmp_in.nGrow(), covered_val); - - div_tmp_in.FillBoundary(geom.periodicity()); - - // Here we take care of both the regular and covered cases ... all we do below is the cut cell cases - MultiFab::Copy(div_out, div_tmp_in, 0, div_comp, ncomp, 0); - - // Get EB geometric info - const auto& ebfactory = dynamic_cast(div_out.Factory()); - const MultiFab* volfrac = &(ebfactory. getVolFrac()); - - for (MFIter mfi(div_out,TilingIfNotGPU()); mfi.isValid(); ++mfi) - { - // Tilebox - const Box& bx = mfi.tilebox (); - - // this is to check efficiently if this tile contains any eb stuff - const auto& div_fab = static_cast(div_out[mfi]); - const EBCellFlagFab& flags = div_fab.getEBCellFlagFab(); - - if ( !(flags.getType(amrex::grow(bx, 0)) == FabType::covered) && - !(flags.getType(amrex::grow(bx,nghost)) == FabType::regular) ) - { - // Compute div(tau) with EB algorithm - apply_eb_redistribution(bx, div_out, div_tmp_in, weights, &mfi, - div_comp, ncomp, flags, volfrac, domain, - geom); - - } - } - } - - // - // Do small cell redistribution on a MultiFab -- without a weighting function - // - void single_level_redistribute (MultiFab& div_tmp_in, MultiFab& div_out, - int div_comp, int ncomp, const Geometry& geom) - { - // We create a weighting array to use inside the redistribution array - MultiFab weights(div_out.boxArray(), div_out.DistributionMap(), 1, div_tmp_in.nGrow()); - weights.setVal(1.0); - - single_level_weighted_redistribute (div_tmp_in, div_out, weights, div_comp, ncomp, geom); - } -#endif - void FillSignedDistance (MultiFab& mf, bool fluid_has_positive_sign) { const auto *factory = dynamic_cast(&(mf.Factory())); diff --git a/Src/EB/CMakeLists.txt b/Src/EB/CMakeLists.txt index 9523786fa19..6f17526fcd6 100644 --- a/Src/EB/CMakeLists.txt +++ b/Src/EB/CMakeLists.txt @@ -37,6 +37,16 @@ foreach(D IN LISTS AMReX_SPACEDIM) AMReX_EBAmrUtil.cpp AMReX_EB_utils.H AMReX_EB_utils.cpp + AMReX_EB_FluxRedistribute.cpp + AMReX_EB_Redistribution.cpp + AMReX_EB_RedistributionApply.cpp + AMReX_EB_StateRedistItracker.cpp + AMReX_EB_StateRedistUtils.cpp + AMReX_EB_StateRedistribute.cpp + AMReX_EB_Redistribution.H + AMReX_EB_StateRedistSlopeLimiter_K.H + AMReX_EB_Slopes_${D}D_K.H + AMReX_EB_Slopes_K.H AMReX_algoim.H AMReX_algoim_K.H AMReX_algoim.cpp diff --git a/Src/EB/Make.package b/Src/EB/Make.package index 296332d2a52..13f9d2c5ae3 100644 --- a/Src/EB/Make.package +++ b/Src/EB/Make.package @@ -39,6 +39,17 @@ CEXE_sources += AMReX_EB_utils.cpp CEXE_headers += AMReX_algoim.H AMReX_algoim_K.H CEXE_sources += AMReX_algoim.cpp +CEXE_headers += AMReX_EB_Redistribution.H +CEXE_sources += AMReX_EB_Redistribution.cpp +CEXE_sources += AMReX_EB_RedistributionApply.cpp +CEXE_sources += AMReX_EB_FluxRedistribute.cpp +CEXE_sources += AMReX_EB_StateRedistribute.cpp +CEXE_sources += AMReX_EB_StateRedistUtils.cpp +CEXE_sources += AMReX_EB_StateRedistItracker.cpp +CEXE_headers += AMReX_EB_StateRedistSlopeLimiter_K.H +CEXE_headers += AMReX_EB_Slopes_$(DIM)D_K.H +CEXE_headers += AMReX_EB_Slopes_K.H + CEXE_headers += AMReX_EB2_IF_AllRegular.H CEXE_headers += AMReX_EB2_IF_Box.H CEXE_headers += AMReX_EB2_IF_Cylinder.H diff --git a/Tests/EB_CNS/Source/CNS.H b/Tests/EB_CNS/Source/CNS.H index c862039c899..7c578052f34 100644 --- a/Tests/EB_CNS/Source/CNS.H +++ b/Tests/EB_CNS/Source/CNS.H @@ -22,84 +22,86 @@ public: const amrex::BoxArray& bl, const amrex::DistributionMapping& dm, amrex::Real time); - virtual ~CNS (); + ~CNS () override; CNS (const CNS& rhs) = delete; + CNS (CNS&& rhs) = delete; CNS& operator= (const CNS& rhs) = delete; + CNS& operator= (CNS&& rhs) = delete; // Restart from a checkpoint file. - virtual void restart (amrex::Amr& papa, - std::istream& is, - bool bReadSpecial = false) override; + void restart (amrex::Amr& papa, + std::istream& is, + bool bReadSpecial = false) override; // Write checkpoint - virtual void checkPoint(const std::string& dir, - std::ostream& os, - amrex::VisMF::How how = amrex::VisMF::NFiles, - bool dump_old = true) override; + void checkPoint(const std::string& dir, + std::ostream& os, + amrex::VisMF::How how = amrex::VisMF::NFiles, + bool dump_old = true) override; - virtual std::string thePlotFileType () const override { + std::string thePlotFileType () const override { return {"HyperCLaw-V1.1"}; } // Write a plotfile to specified directory. - virtual void writePlotFile (const std::string& dir, - std::ostream& os, - amrex::VisMF::How how) override; + void writePlotFile (const std::string& dir, + std::ostream& os, + amrex::VisMF::How how) override; // Initialize data on this level from another CNS (during regrid). - virtual void init (amrex::AmrLevel& old) override; + void init (amrex::AmrLevel& old) override; // Initialize data on this level after regridding if old level did not previously exist - virtual void init () override; + void init () override; // Initialize grid data at problem start-up. - virtual void initData () override; + void initData () override; // Advance grids at this level in time. - virtual amrex::Real advance (amrex::Real time, - amrex::Real dt, - int iteration, - int ncycle) override; - - virtual void computeInitialDt (int finest_level, - int sub_cycle, - amrex::Vector& n_cycle, - const amrex::Vector& ref_ratio, - amrex::Vector& dt_level, - amrex::Real stop_time) override; - - virtual void computeNewDt (int finest_level, - int sub_cycle, - amrex::Vector& n_cycle, - const amrex::Vector& ref_ratio, - amrex::Vector& dt_min, - amrex::Vector& dt_level, - amrex::Real stop_time, - int post_regrid_flag) override; - - virtual void post_regrid (int lbase, int new_finest) override; + amrex::Real advance (amrex::Real time, + amrex::Real dt, + int iteration, + int ncycle) override; + + void computeInitialDt (int finest_level, + int sub_cycle, + amrex::Vector& n_cycle, + const amrex::Vector& ref_ratio, + amrex::Vector& dt_level, + amrex::Real stop_time) override; + + void computeNewDt (int finest_level, + int sub_cycle, + amrex::Vector& n_cycle, + const amrex::Vector& ref_ratio, + amrex::Vector& dt_min, + amrex::Vector& dt_level, + amrex::Real stop_time, + int post_regrid_flag) override; + + void post_regrid (int lbase, int new_finest) override; // Do work after timestep(). - virtual void post_timestep (int iteration) override; + void post_timestep (int iteration) override; // After a full time step - virtual void postCoarseTimeStep (amrex::Real time) override; + void postCoarseTimeStep (amrex::Real time) override; // Do work after init(). - virtual void post_init (amrex::Real stop_time) override; + void post_init (amrex::Real stop_time) override; - virtual void post_restart () override; + void post_restart () override; // Error estimation for regridding. - virtual void errorEst (amrex::TagBoxArray& tb, - int clearval, - int tagval, - amrex::Real time, - int n_error_buf = 0, - int ngrow = 0) override; + void errorEst (amrex::TagBoxArray& tags, + int clearval, + int tagval, + amrex::Real time, + int n_error_buf = 0, + int ngrow = 0) override; - virtual int WorkEstType () override { return Cost_Type; } + int WorkEstType () override { return Cost_Type; } // Define data descriptors. static void variableSetUp (); @@ -180,51 +182,33 @@ public: amrex::Real estTimeStep (); - void computeTemp (amrex::MultiFab& State, int ng); + static void computeTemp (amrex::MultiFab& State, int ng); void compute_dSdt_box (const amrex::Box& bx, - amrex::Array4& Sfab, - amrex::Array4& dSdtfab, + amrex::Array4& sfab, + amrex::Array4& dsdtfab, const std::array& flux); void compute_dSdt_box_eb (const amrex::Box& bx, - amrex::Array4 const& Sfab, - amrex::Array4 const& dSdtfab, + Array4 const& s_arr, + Array4 const& dsdt_arr, std::array const& flux, - amrex::Array4 const& flag, - amrex::Array4 const& vfrac, - AMREX_D_DECL( - amrex::Array4 const& apx, - amrex::Array4 const& apy, - amrex::Array4 const& apz), - AMREX_D_DECL( - amrex::Array4 const& fcx, - amrex::Array4 const& fcy, - amrex::Array4 const& fcz), - amrex::Array4 const& bcent, + Array4 const& flag, + Array4 const& vfrac, + AMREX_D_DECL(Array4 const& apx, + Array4 const& apy, + Array4 const& apz), + AMREX_D_DECL(Array4 const& fcx, + Array4 const& fcy, + Array4 const& fcz), + Array4 const& bcent, int as_crse, - amrex::Array4 const& drho_as_crse, - amrex::Array4 const& rrflag_as_crse, + Array4 const& drho_as_crse, + Array4 const& rrflag_as_crse, int as_fine, - amrex::Array4 const& dm_as_fine, - amrex::Array4 const& lev_mask, - amrex::Real dt); - - void cns_flux_redistribute (const amrex::Box& bx, - amrex::Array4 const& dqdt, - amrex::Array4 const& divc, - amrex::Array4 const& optmp, - amrex::Array4 const& del_m, - amrex::Array4 const& redistwgt, - amrex::Array4 const& vfrac, - amrex::Array4 const& flag, - int as_crse, - amrex::Array4 const& drho_as_crse, - amrex::Array4 const& rrflag_as_crse, - int as_fine, - amrex::Array4 const& dm_as_fine, - amrex::Array4 const& lev_mask, - amrex::Real dt); + Array4 const& dm_as_fine, + Array4 const& lev_mask, + Real dt); static Parm* h_parm; static Parm* d_parm; @@ -233,9 +217,9 @@ public: }; void cns_bcfill (amrex::Box const& bx, amrex::FArrayBox& data, - const int dcomp, const int numcomp, - amrex::Geometry const& geom, const amrex::Real time, - const amrex::Vector& bcr, const int bcomp, - const int scomp); + int dcomp, int numcomp, + amrex::Geometry const& geom, amrex::Real time, + const amrex::Vector& bcr, int bcomp, + int scomp); #endif diff --git a/Tests/EB_CNS/Source/CNS.cpp b/Tests/EB_CNS/Source/CNS.cpp index ab289e557f8..5bb3c4e2532 100644 --- a/Tests/EB_CNS/Source/CNS.cpp +++ b/Tests/EB_CNS/Source/CNS.cpp @@ -36,8 +36,7 @@ Real CNS::gravity = 0.0; int CNS::eb_weights_type = 0; // [0,1,2,3] 0: weights are all 1 int CNS::do_reredistribution = 1; -CNS::CNS () -{} +CNS::CNS () = default; CNS::CNS (Amr& papa, int lev, @@ -57,8 +56,7 @@ CNS::CNS (Amr& papa, buildMetrics(); } -CNS::~CNS () -{} +CNS::~CNS () = default; void CNS::init (AmrLevel& old) @@ -280,7 +278,7 @@ CNS::printTotal () const Lazy::QueueReduction( [=] () mutable { #endif ParallelDescriptor::ReduceRealSum(tot.data(), 5, ParallelDescriptor::IOProcessorNumber()); - amrex::Print().SetPrecision(17) << "\n[CNS] Total mass is " << tot[0] << "\n" + amrex::Print().SetPrecision(15) << "\n[CNS] Total mass is " << tot[0] << "\n" << " Total x-momentum is " << tot[1] << "\n" << " Total y-momentum is " << tot[2] << "\n" #if (AMREX_SPACEDIM == 3) @@ -322,10 +320,10 @@ CNS::errorEst (TagBoxArray& tags, int, int, Real /*time*/, int, int) if (!refine_boxes.empty()) { - const int n_refine_boxes = refine_boxes.size(); + const auto n_refine_boxes = int(refine_boxes.size()); const auto problo = geom.ProbLoArray(); const auto dx = geom.CellSizeArray(); - auto boxes = dp_refine_boxes; + auto const* boxes = dp_refine_boxes; auto const& tagma = tags.arrays(); ParallelFor(tags, @@ -502,15 +500,13 @@ CNS::buildMetrics () areafrac = ebfactory.getAreaFrac(); facecent = ebfactory.getFaceCent(); - Parm const* l_parm = d_parm; - level_mask.clear(); level_mask.define(grids,dmap,1,3); level_mask.BuildMask(geom.Domain(), geom.periodicity(), - l_parm->level_mask_covered, - l_parm->level_mask_notcovered, - l_parm->level_mask_physbnd, - l_parm->level_mask_interior); + Parm::level_mask_covered, + Parm::level_mask_notcovered, + Parm::level_mask_physbnd, + Parm::level_mask_interior); } Real diff --git a/Tests/EB_CNS/Source/CNSBld.cpp b/Tests/EB_CNS/Source/CNSBld.cpp index d95682bf0a9..48505346613 100644 --- a/Tests/EB_CNS/Source/CNSBld.cpp +++ b/Tests/EB_CNS/Source/CNSBld.cpp @@ -8,15 +8,15 @@ class CNSBld : public LevelBld { - virtual void variableSetUp () override; - virtual void variableCleanUp () override; - virtual AmrLevel *operator() () override; - virtual AmrLevel *operator() (Amr& papa, - int lev, - const Geometry& level_geom, - const BoxArray& ba, - const DistributionMapping& dm, - Real time) override; + void variableSetUp () override; + void variableCleanUp () override; + AmrLevel *operator() () override; + AmrLevel *operator() (Amr& papa, + int lev, + const Geometry& level_geom, + const BoxArray& ba, + const DistributionMapping& dm, + Real time) override; }; CNSBld CNS_bld; diff --git a/Tests/EB_CNS/Source/CNS_advance_box_eb.cpp b/Tests/EB_CNS/Source/CNS_advance_box_eb.cpp index 88bef96c0e0..b4f243739ab 100644 --- a/Tests/EB_CNS/Source/CNS_advance_box_eb.cpp +++ b/Tests/EB_CNS/Source/CNS_advance_box_eb.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #if (AMREX_SPACEDIM == 2) @@ -18,8 +19,8 @@ using namespace amrex; void CNS::compute_dSdt_box_eb (const Box& bx, - Array4 const& sfab, - Array4 const& dsdtfab, + Array4 const& s_arr, + Array4 const& dsdt_arr, std::array const& flux, Array4 const& flag, Array4 const& vfrac, @@ -51,16 +52,12 @@ CNS::compute_dSdt_box_eb (const Box& bx, const auto dxinv = geom.InvCellSizeArray(); // Quantities for redistribution - FArrayBox divc,optmp,redistwgt,delta_m; + FArrayBox divc,redistwgt; divc.resize(bxg2,NEQNS); - optmp.resize(bxg2,NEQNS); - delta_m.resize(bxg1,NEQNS); redistwgt.resize(bxg2,1); // Set to zero just in case divc.setVal(0.0); - optmp.setVal(0.0); - delta_m.setVal(0.0); redistwgt.setVal(0.0); // Primitive variables @@ -86,9 +83,9 @@ CNS::compute_dSdt_box_eb (const Box& bx, Parm const* lparm = d_parm; - AMREX_D_TERM(auto const& fxfab = flux_tmp[0].array();, - auto const& fyfab = flux_tmp[1].array();, - auto const& fzfab = flux_tmp[2].array();); + AMREX_D_TERM(auto const& fx_arr = flux_tmp[0].array();, + auto const& fy_arr = flux_tmp[1].array();, + auto const& fz_arr = flux_tmp[2].array();); auto const& q = qtmp.array(); @@ -110,7 +107,7 @@ CNS::compute_dSdt_box_eb (const Box& bx, amrex::ParallelFor(bxg5, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept { - cns_ctoprim(i, j, k, sfab, q, *lparm); + cns_ctoprim(i, j, k, s_arr, q, *lparm); }); if (do_visc == 1) @@ -149,8 +146,8 @@ CNS::compute_dSdt_box_eb (const Box& bx, amrex::ParallelFor(xflxbx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept { - cns_riemann_x(i, j, k, fxfab, slope, q, *lparm); - for (int n = NEQNS; n < NCONS; ++n) fxfab(i,j,k,n) = Real(0.0); + cns_riemann_x(i, j, k, fx_arr, slope, q, *lparm); + for (int n = NEQNS; n < NCONS; ++n) fx_arr(i,j,k,n) = Real(0.0); }); @@ -160,7 +157,7 @@ CNS::compute_dSdt_box_eb (const Box& bx, amrex::ParallelFor(xflxbx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept { - cns_diff_eb_x(i, j, k, q, coefs, flag, dxinv, weights, fxfab); + cns_diff_eb_x(i, j, k, q, coefs, flag, dxinv, weights, fx_arr); }); } @@ -178,8 +175,8 @@ CNS::compute_dSdt_box_eb (const Box& bx, amrex::ParallelFor(yflxbx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept { - cns_riemann_y(i, j, k, fyfab, slope, q, *lparm); - for (int n = NEQNS; n < NCONS; ++n) fyfab(i,j,k,n) = Real(0.0); + cns_riemann_y(i, j, k, fy_arr, slope, q, *lparm); + for (int n = NEQNS; n < NCONS; ++n) fy_arr(i,j,k,n) = Real(0.0); }); if(do_visc == 1) @@ -188,7 +185,7 @@ CNS::compute_dSdt_box_eb (const Box& bx, amrex::ParallelFor(yflxbx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept { - cns_diff_eb_y(i, j, k, q, coefs, flag, dxinv, weights, fyfab); + cns_diff_eb_y(i, j, k, q, coefs, flag, dxinv, weights, fy_arr); }); } @@ -206,8 +203,8 @@ CNS::compute_dSdt_box_eb (const Box& bx, amrex::ParallelFor(zflxbx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept { - cns_riemann_z(i, j, k, fzfab, slope, q, *lparm); - for (int n = NEQNS; n < NCONS; ++n) fzfab(i,j,k,n) = Real(0.0); + cns_riemann_z(i, j, k, fz_arr, slope, q, *lparm); + for (int n = NEQNS; n < NCONS; ++n) fz_arr(i,j,k,n) = Real(0.0); }); if(do_visc == 1) @@ -216,7 +213,7 @@ CNS::compute_dSdt_box_eb (const Box& bx, amrex::ParallelFor(zflxbx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept { - cns_diff_eb_z(i, j, k, q, coefs, flag, dxinv, weights, fzfab); + cns_diff_eb_z(i, j, k, q, coefs, flag, dxinv, weights, fz_arr); }); } #endif @@ -236,7 +233,7 @@ CNS::compute_dSdt_box_eb (const Box& bx, auto const& bhi = bx.bigEnd(); // Because we are going to redistribute, we put the divergence into divc - // rather than directly into dsdtfab + // rather than directly into dsdt_arr auto const& divc_arr = divc.array(); bool l_do_visc = do_visc; @@ -258,12 +255,16 @@ CNS::compute_dSdt_box_eb (const Box& bx, AMREX_D_DECL(fcx, fcy, fcz), dxinv, *lparm, l_eb_weights_type, l_do_visc); }); - auto const& optmp_arr = optmp.array(); - auto const& del_m_arr = delta_m.array(); - // Now do redistribution - cns_flux_redistribute(bx,dsdtfab,divc_arr,optmp_arr,del_m_arr,redistwgt_arr,vfrac,flag, - as_crse, drho_as_crse, rrflag_as_crse, as_fine, dm_as_fine, lev_mask, dt); + int icomp = 0; + int ncomp = NEQNS; + int level_mask_not_covered = Parm::level_mask_notcovered; + bool use_wts_in_divnc = false; + amrex_flux_redistribute(bx, dsdt_arr, divc_arr, redistwgt_arr, vfrac, flag, + as_crse, drho_as_crse, rrflag_as_crse, + as_fine, dm_as_fine, lev_mask, geom, use_wts_in_divnc, + level_mask_not_covered, icomp, ncomp, dt); + // apply_flux_redistribution(bx, dsdt_arr, divc_arr, redistwgt_arr, icomp, ncomp, flag, vfrac, geom); if (gravity != Real(0.0)) { @@ -278,8 +279,8 @@ CNS::compute_dSdt_box_eb (const Box& bx, amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept { - dsdtfab(i,j,k,imz ) += g * sfab(i,j,k,irho); - dsdtfab(i,j,k,irhoE) += g * sfab(i,j,k,imz); + dsdt_arr(i,j,k,imz ) += g * s_arr(i,j,k,irho); + dsdt_arr(i,j,k,irhoE) += g * s_arr(i,j,k,imz); }); } diff --git a/Tests/EB_CNS/Source/CNS_bcfill.cpp b/Tests/EB_CNS/Source/CNS_bcfill.cpp index 1c787e29a96..bb6b97c0e13 100644 --- a/Tests/EB_CNS/Source/CNS_bcfill.cpp +++ b/Tests/EB_CNS/Source/CNS_bcfill.cpp @@ -24,10 +24,10 @@ struct CnsFillExtDir // scomp : component index for dcomp as in the descriptor set up in CNS::variableSetUp. void cns_bcfill (Box const& bx, FArrayBox& data, - const int dcomp, const int numcomp, - Geometry const& geom, const Real time, - const Vector& bcr, const int bcomp, - const int scomp) + int dcomp, int numcomp, + Geometry const& geom, Real time, + const Vector& bcr, int bcomp, + int scomp) { GpuBndryFuncFab gpu_bndry_func(CnsFillExtDir{}); gpu_bndry_func(bx,data,dcomp,numcomp,geom,time,bcr,bcomp,scomp); diff --git a/Tests/EB_CNS/Source/CNS_derive.H b/Tests/EB_CNS/Source/CNS_derive.H index e44267c62f0..63a33bf9906 100644 --- a/Tests/EB_CNS/Source/CNS_derive.H +++ b/Tests/EB_CNS/Source/CNS_derive.H @@ -4,12 +4,12 @@ #include #include -void cns_derpres (const amrex::Box& bx, amrex::FArrayBox& derfab, int dcomp, int ncomp, - const amrex::FArrayBox& datafab, const amrex::Geometry& geomdata, +void cns_derpres (const amrex::Box& bx, amrex::FArrayBox& pfab, int dcomp, int ncomp, + const amrex::FArrayBox& rhoefab, const amrex::Geometry& geomdata, amrex::Real time, const int* bcrec, int level); -void cns_dervel (const amrex::Box& bx, amrex::FArrayBox& derfab, int dcomp, int ncomp, - const amrex::FArrayBox& datafab, const amrex::Geometry& geomdata, +void cns_dervel (const amrex::Box& bx, amrex::FArrayBox& velfab, int dcomp, int ncomp, + const amrex::FArrayBox& datfab, const amrex::Geometry& geomdata, amrex::Real time, const int* bcrec, int level); #endif diff --git a/Tests/EB_CNS/Source/CNS_init_eb2.cpp b/Tests/EB_CNS/Source/CNS_init_eb2.cpp index d29e7f00647..c64663a8bbe 100644 --- a/Tests/EB_CNS/Source/CNS_init_eb2.cpp +++ b/Tests/EB_CNS/Source/CNS_init_eb2.cpp @@ -10,8 +10,8 @@ using namespace amrex; void -initialize_EB2 (const Geometry& geom, const int /*required_coarsening_level*/, - const int max_coarsening_level) +initialize_EB2 (const Geometry& geom, int /*required_coarsening_level*/, + int max_coarsening_level) { BL_PROFILE("initializeEB2"); diff --git a/Tests/EB_CNS/Source/CNS_parm.cpp b/Tests/EB_CNS/Source/CNS_parm.cpp index 3b3e4a27426..d8c7f22eb9a 100644 --- a/Tests/EB_CNS/Source/CNS_parm.cpp +++ b/Tests/EB_CNS/Source/CNS_parm.cpp @@ -3,7 +3,7 @@ void Parm::Initialize () { - constexpr amrex::Real Ru = amrex::Real(8.31451e7); + constexpr auto Ru = amrex::Real(8.31451e7); cv = Ru / (eos_mu * (eos_gamma-amrex::Real(1.0))); cp = eos_gamma * Ru / (eos_mu * (eos_gamma-amrex::Real(1.0))); } diff --git a/Tests/EB_CNS/Source/Make.package b/Tests/EB_CNS/Source/Make.package index 622abd0e01d..351c95e4a2a 100644 --- a/Tests/EB_CNS/Source/Make.package +++ b/Tests/EB_CNS/Source/Make.package @@ -11,7 +11,6 @@ CEXE_sources += CNS_advance_box.cpp CEXE_sources += CNS_advance_box_eb.cpp CEXE_sources += CNS_bcfill.cpp CEXE_sources += CNS_derive.cpp -CEXE_sources += CNS_flux_redistribute.cpp CEXE_sources += CNS.cpp CEXE_sources += CNSBld.cpp CEXE_sources += CNS_io.cpp diff --git a/Tests/EB_CNS/Source/hydro/CNS_flux_redistribute.cpp b/Tests/EB_CNS/Source/hydro/CNS_flux_redistribute.cpp deleted file mode 100644 index 3f5c2ea6362..00000000000 --- a/Tests/EB_CNS/Source/hydro/CNS_flux_redistribute.cpp +++ /dev/null @@ -1,185 +0,0 @@ -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -using namespace amrex; - -void -CNS::cns_flux_redistribute (const Box& bx, - Array4 const& dqdt, - Array4 const& divc, - Array4 const& optmp, - Array4 const& delm, - Array4 const& redistwgt, - Array4 const& vfrac, - Array4 const& flag, - int as_crse, - Array4 const& rr_drho_crse, - Array4 const& rr_flag_crse, - int as_fine, - Array4 const& dm_as_fine, - Array4 const& levmsk, - Real dt) -{ - const Box& bxg1 = amrex::grow(bx,1); - - Parm* l_parm = d_parm; - - Real reredistribution_threshold = amrex_eb_get_reredistribution_threshold(); - - int bx_ilo = bx.smallEnd()[0]; - int bx_ihi = bx.bigEnd()[0]; - int bx_jlo = bx.smallEnd()[1]; - int bx_jhi = bx.bigEnd()[1]; -#if (AMREX_SPACEDIM == 3) - int bx_klo = bx.smallEnd()[2]; - int bx_khi = bx.bigEnd()[2]; -#endif - - amrex::ParallelFor(bxg1, NEQNS, - [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept - { - if (flag(i,j,k).isSingleValued()) - { - Real vtot(0.); - Real divnc(0.); -#if (AMREX_SPACEDIM == 2) - int kk(0); -#else - for (int kk = -1; kk <= 1; kk++) -#endif - for (int jj = -1; jj <= 1; jj++) - for (int ii = -1; ii <= 1; ii++) - if ( (ii != 0 || jj != 0 || kk != 0) && flag(i,j,k).isConnected(ii,jj,kk) ) - { - vtot += vfrac(i+ii,j+jj,k+kk); - divnc += vfrac(i+ii,j+jj,k+kk)*divc(i+ii,j+jj,k+kk,n); - } - divnc /= vtot; - optmp(i,j,k,n) = (1.0-vfrac(i,j,k))*(divnc-divc(i,j,k,n)); - delm(i,j,k,n) = -vfrac(i,j,k)*optmp(i,j,k,n); - } else { - delm(i,j,k,n) = 0.; - } - }); - - amrex::ParallelFor(bxg1, NEQNS, - [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept - { - bool valid_dst_cell; - if (flag(i,j,k).isSingleValued()) - { - Real wtot = 0.; -#if (AMREX_SPACEDIM == 2) - int kk(0); -#else - for (int kk = -1; kk <= 1; kk++) -#endif - for (int jj = -1; jj <= 1; jj++) - for (int ii = -1; ii <= 1; ii++) - if ( (ii != 0 || jj != 0 || kk != 0) && flag(i,j,k).isConnected(ii,jj,kk) ) - { - wtot += vfrac(i+ii,j+jj,k+kk)*redistwgt(i+ii,j+jj,k+kk); - } - wtot = 1.0 / wtot; - - bool as_crse_crse_cell = false; - bool as_crse_covered_cell = false; - - if (as_crse) - { - bool inside = -#if (AMREX_SPACEDIM == 2) - ( (i >= bx_ilo) && (i <= bx_ihi) && (j >= bx_jlo) && (j <= bx_jhi) ); -#else - ( (i >= bx_ilo) && (i <= bx_ihi) && (j >= bx_jlo) && (j <= bx_jhi) && (k >= bx_klo) && (k <= bx_khi) ); -#endif - as_crse_crse_cell = inside && (rr_flag_crse(i,j,k) == amrex_yafluxreg_crse_fine_boundary_cell); - as_crse_covered_cell = (rr_flag_crse(i,j,k) == amrex_yafluxreg_fine_cell); - } - - bool as_fine_valid_cell = false; // valid cells near box boundary - bool as_fine_ghost_cell = false; // ghost cells just outside valid region - - if (as_fine) - { - bool inside = -#if (AMREX_SPACEDIM == 2) - ( (i >= bx_ilo) && (i <= bx_ihi) && (j >= bx_jlo) && (j <= bx_jhi) ); -#else - ( (i >= bx_ilo) && (i <= bx_ihi) && (j >= bx_jlo) && (j <= bx_jhi) && (k >= bx_klo) && (k <= bx_khi) ); -#endif - if (inside) as_fine_valid_cell = true; - as_fine_ghost_cell = (levmsk(i,j,k) == l_parm->level_mask_notcovered); // not covered by other grids - } - -#if (AMREX_SPACEDIM == 2) - kk = 0; -#else - for (int kk = -1; kk <= 1; kk++) -#endif - for (int jj = -1; jj <= 1; jj++) - for (int ii = -1; ii <= 1; ii++) - if ( (ii != 0 || jj != 0 || kk != 0) && flag(i,j,k).isConnected(ii,jj,kk) ) - { - int iii = i + ii; - int jjj = j + jj; - int kkk = k + kk; - - Real drho = delm(i,j,k,n)*wtot*redistwgt(iii,jjj,kkk); - Gpu::Atomic::Add(&optmp(iii,jjj,kkk,n), drho); - - valid_dst_cell = ( (iii >= bx_ilo) && (iii <= bx_ihi) && - (jjj >= bx_jlo) && (jjj <= bx_jhi) ); -#if (AMREX_SPACEDIM == 3) - valid_dst_cell &= ( (kkk >= bx_klo) && (kkk <= bx_khi) ); -#endif - - if (as_crse_crse_cell) - { - if ( (rr_flag_crse(iii,jjj,kkk) == amrex_yafluxreg_fine_cell) && - (vfrac(i,j,k) > reredistribution_threshold) ) - { - Gpu::Atomic::Add(&rr_drho_crse(i,j,k,n), - dt*drho*(vfrac(iii,jjj,kkk)/vfrac(i,j,k))); - } - } - - if (as_crse_covered_cell && valid_dst_cell) - { - if ( (rr_flag_crse(iii,jjj,kkk) == amrex_yafluxreg_crse_fine_boundary_cell) && - (vfrac(iii,jjj,kkk) > reredistribution_threshold) ) - { - // recipient is a crse/fine boundary cell - Gpu::Atomic::Add(&rr_drho_crse(iii,jjj,kkk,n), -dt*drho); - } - } - - if (as_fine_valid_cell && !valid_dst_cell) - { - Gpu::Atomic::Add(&dm_as_fine(iii,jjj,kkk,n), dt*drho*vfrac(iii,jjj,kkk)); - } - - if (as_fine_ghost_cell && valid_dst_cell) - { - Gpu::Atomic::Add(&dm_as_fine(i,j,k,n), -dt*drho*vfrac(iii,jjj,kkk)); - } - - } // isConnected - } // isSingleValued - }); - - amrex::ParallelFor(bx, NEQNS, - [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept - { - if (!flag(i,j,k).isCovered()) - dqdt(i,j,k,n) = divc(i,j,k,n) + optmp(i,j,k,n); - }); -} diff --git a/Tests/EB_CNS/Source/main.cpp b/Tests/EB_CNS/Source/main.cpp index aa851c47956..42b0e917996 100644 --- a/Tests/EB_CNS/Source/main.cpp +++ b/Tests/EB_CNS/Source/main.cpp @@ -10,7 +10,7 @@ using namespace amrex; amrex::LevelBld* getLevelBld (); -void initialize_EB2 (const Geometry& geom, const int required_level, const int max_level); +void initialize_EB2 (const Geometry& geom, int required_level, int max_level); int main (int argc, char* argv[]) {