LCOV - code coverage report
Current view: top level - src/Operator - Elastic.cpp (source / functions) Hit Total Coverage
Test: coverage_merged.info Lines: 255 448 56.9 %
Date: 2024-11-18 05:28:54 Functions: 65 144 45.1 %

          Line data    Source code
       1             : // TODO: Remove these 
       2             : 
       3             : #include "Elastic.H"
       4             : #include "Set/Set.H"
       5             : 
       6             : #include "Numeric/Stencil.H"
       7             : namespace Operator
       8             : {
       9             : template<int SYM>
      10         426 : Elastic<SYM>::Elastic(const Vector<Geometry>& a_geom,
      11             :     const Vector<BoxArray>& a_grids,
      12             :     const Vector<DistributionMapping>& a_dmap,
      13         426 :     const LPInfo& a_info)
      14             : {
      15             :     BL_PROFILE("Operator::Elastic::Elastic()");
      16             : 
      17         426 :     define(a_geom, a_grids, a_dmap, a_info);
      18         426 : }
      19             : 
      20             : template<int SYM>
      21         426 : Elastic<SYM>::~Elastic()
      22         426 : {}
      23             : 
      24             : template<int SYM>
      25             : void
      26         426 : Elastic<SYM>::define(const Vector<Geometry>& a_geom,
      27             :     const Vector<BoxArray>& a_grids,
      28             :     const Vector<DistributionMapping>& a_dmap,
      29             :     const LPInfo& a_info,
      30             :     const Vector<FabFactory<FArrayBox> const*>& a_factory)
      31             : {
      32             :     BL_PROFILE("Operator::Elastic::define()");
      33             : 
      34         426 :     Operator::define(a_geom, a_grids, a_dmap, a_info, a_factory);
      35             : 
      36         426 :     int model_nghost = 2;
      37             : 
      38         426 :     m_ddw_mf.resize(m_num_amr_levels);
      39         426 :     m_psi_mf.resize(m_num_amr_levels);
      40         898 :     for (int amrlev = 0; amrlev < m_num_amr_levels; ++amrlev)
      41             :     {
      42         472 :         m_ddw_mf[amrlev].resize(m_num_mg_levels[amrlev]);
      43         472 :         m_psi_mf[amrlev].resize(m_num_mg_levels[amrlev]);
      44        1435 :         for (int mglev = 0; mglev < m_num_mg_levels[amrlev]; ++mglev)
      45             :         {
      46        1926 :             m_ddw_mf[amrlev][mglev].reset(new MultiTab(amrex::convert(m_grids[amrlev][mglev],
      47         963 :                 amrex::IntVect::TheNodeVector()),
      48             :                 m_dmap[amrlev][mglev], 1, model_nghost));
      49         963 :             m_psi_mf[amrlev][mglev].reset(new MultiFab(m_grids[amrlev][mglev],
      50             :                 m_dmap[amrlev][mglev], 1, model_nghost));
      51             : 
      52         963 :             if (!m_psi_set) m_psi_mf[amrlev][mglev]->setVal(1.0);
      53             :         }
      54             :     }
      55         426 : }
      56             : 
      57             : template <int SYM>
      58             : void
      59           0 : Elastic<SYM>::SetModel(MATRIX4& a_model)
      60             : {
      61           0 :     for (int amrlev = 0; amrlev < m_num_amr_levels; amrlev++)
      62             :     {
      63           0 :         amrex::Box domain(m_geom[amrlev][0].Domain());
      64           0 :         domain.convert(amrex::IntVect::TheNodeVector());
      65             : 
      66           0 :         int nghost = m_ddw_mf[amrlev][0]->nGrow();
      67             : 
      68           0 :         for (MFIter mfi(*m_ddw_mf[amrlev][0], amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
      69             :         {
      70           0 :             Box bx = mfi.tilebox();
      71           0 :             bx.grow(nghost);   // Expand to cover first layer of ghost nodes
      72           0 :             bx = bx & domain;  // Take intersection of box and the problem domain
      73             : 
      74           0 :             amrex::Array4<MATRIX4> const& ddw = (*(m_ddw_mf[amrlev][0])).array(mfi);
      75             : 
      76           0 :             amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
      77           0 :                 ddw(i, j, k) = a_model;
      78             : 
      79             : #ifdef AMREX_DEBUG
      80             :                 if (ddw(i, j, k).contains_nan()) Util::Abort(INFO, "model is nan at (", i, ",", j, ",", k, "), amrlev=", amrlev);
      81             : #endif
      82             :             });
      83             :         }
      84             :     }
      85           0 :     m_model_set = true;
      86           0 : }
      87             : 
      88             : template <int SYM>
      89             : void
      90        1372 : Elastic<SYM>::SetModel(int amrlev, const amrex::FabArray<amrex::BaseFab<MATRIX4> >& a_model)
      91             : {
      92             :     BL_PROFILE("Operator::Elastic::SetModel()");
      93             : 
      94        1372 :     amrex::Box domain(m_geom[amrlev][0].Domain());
      95        1372 :     domain.convert(amrex::IntVect::TheNodeVector());
      96             : 
      97        1372 :     if (a_model.boxArray() != m_ddw_mf[amrlev][0]->boxArray()) Util::Abort(INFO, "Inconsistent box arrays\n", "a_model.boxArray()=\n", a_model.boxArray(), "\n but the current box array is \n", m_ddw_mf[amrlev][0]->boxArray());
      98        1372 :     if (a_model.DistributionMap() != m_ddw_mf[amrlev][0]->DistributionMap()) Util::Abort(INFO, "Inconsistent distribution maps");
      99        1372 :     if (a_model.nComp() != m_ddw_mf[amrlev][0]->nComp()) Util::Abort(INFO, "Inconsistent # of components - should be ", m_ddw_mf[amrlev][0]->nComp());
     100        1372 :     if (a_model.nGrow() != m_ddw_mf[amrlev][0]->nGrow()) Util::Abort(INFO, "Inconsistent # of ghost nodes, should be ", m_ddw_mf[amrlev][0]->nGrow());
     101             : 
     102             : 
     103        1372 :     int nghost = m_ddw_mf[amrlev][0]->nGrow();
     104             : 
     105        2877 :     for (MFIter mfi(a_model, amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
     106             :     {
     107        1505 :         Box bx = mfi.tilebox();
     108        1505 :         bx.grow(nghost);   // Expand to cover first layer of ghost nodes
     109        1505 :         bx = bx & domain;  // Take intersection of box and the problem domain
     110             : 
     111        1505 :         amrex::Array4<MATRIX4> const& C = (*(m_ddw_mf[amrlev][0])).array(mfi);
     112        1505 :         amrex::Array4<const MATRIX4> const& a_C = a_model.array(mfi);
     113             : 
     114      421019 :         amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
     115      427977 :             C(i, j, k) = a_C(i, j, k);
     116             :         });
     117             :     }
     118             :     //FillBoundaryCoeff(*model[amrlev][0], m_geom[amrlev][0]);
     119             : 
     120             : 
     121        1372 :     m_model_set = true;
     122        1372 : }
     123             : 
     124             : template <int SYM>
     125             : void
     126          44 : Elastic<SYM>::SetPsi(int amrlev, const amrex::MultiFab& a_psi_mf)
     127             : {
     128             :     BL_PROFILE("Operator::Elastic::SetPsi()");
     129          44 :     amrex::Box domain(m_geom[amrlev][0].Domain());
     130             : 
     131         158 :     for (MFIter mfi(a_psi_mf, amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
     132             :     {
     133         114 :         Box bx = mfi.growntilebox() & domain;
     134             : 
     135         114 :         amrex::Array4<Set::Scalar> const& m_psi = (*(m_psi_mf[amrlev][0])).array(mfi);
     136         114 :         amrex::Array4<const Set::Scalar> const& a_psi = a_psi_mf.array(mfi);
     137             : 
     138      165298 :         amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
     139      165184 :             m_psi(i, j, k) = a_psi(i, j, k);
     140             :         });
     141             :     }
     142          44 :     m_psi_set = true;
     143          44 : }
     144             : 
     145             : template<int SYM>
     146             : void
     147      385843 : Elastic<SYM>::Fapply(int amrlev, int mglev, MultiFab& a_f, const MultiFab& a_u) const
     148             : {
     149             :     BL_PROFILE("Operator::Elastic::Fapply()");
     150             : 
     151      385843 :     amrex::Box domain(m_geom[amrlev][mglev].Domain());
     152      385843 :     domain.convert(amrex::IntVect::TheNodeVector());
     153             : 
     154      385843 :     const Real* DX = m_geom[amrlev][mglev].CellSize();
     155             : 
     156      785917 :     for (MFIter mfi(a_f, amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
     157             :     {
     158      400074 :         Box bx = mfi.validbox().grow(1) & domain;
     159      400074 :         amrex::Box tilebox = mfi.grownnodaltilebox() & bx;
     160             : 
     161      400074 :         amrex::Array4<MATRIX4> const& DDW = (*(m_ddw_mf[amrlev][mglev])).array(mfi);
     162      400074 :         amrex::Array4<const amrex::Real> const& U = a_u.array(mfi);
     163      400074 :         amrex::Array4<amrex::Real> const& F = a_f.array(mfi);
     164      400074 :         amrex::Array4<Set::Scalar> const& psi = m_psi_mf[amrlev][mglev]->array(mfi);
     165             : 
     166      400074 :         const Dim3 lo = amrex::lbound(domain), hi = amrex::ubound(domain);
     167             : 
     168   418289374 :         amrex::ParallelFor(tilebox, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
     169             : 
     170    25183800 :             Set::Vector f = Set::Vector::Zero();
     171             : 
     172    25183800 :             Set::Vector u;
     173    86646100 :             for (int p = 0; p < AMREX_SPACEDIM; p++) u(p) = U(i, j, k, p);
     174             : 
     175             : 
     176    25183800 :             bool AMREX_D_DECL(xmin = (i == lo.x), ymin = (j == lo.y), zmin = (k == lo.z)),
     177    25183800 :                 AMREX_D_DECL(xmax = (i == hi.x), ymax = (j == hi.y), zmax = (k == hi.z));
     178             : 
     179             :             // Determine if a special stencil will be necessary for first derivatives
     180             :             std::array<Numeric::StencilType, AMREX_SPACEDIM>
     181    25183800 :                 sten = Numeric::GetStencil(i, j, k, domain);
     182             : 
     183             :             // The displacement gradient tensor
     184    25183800 :             Set::Matrix gradu; // gradu(i,j) = u_{i,j)
     185             : 
     186             :             // Fill gradu
     187    86646100 :             for (int p = 0; p < AMREX_SPACEDIM; p++)
     188             :             {
     189   217670000 :                 AMREX_D_TERM(gradu(p, 0) = (Numeric::Stencil<Set::Scalar, 1, 0, 0>::D(U, i, j, k, p, DX, sten));,
     190             :                     gradu(p, 1) = (Numeric::Stencil<Set::Scalar, 0, 1, 0>::D(U, i, j, k, p, DX, sten));,
     191             :                     gradu(p, 2) = (Numeric::Stencil<Set::Scalar, 0, 0, 1>::D(U, i, j, k, p, DX, sten)););
     192             :             }
     193             : 
     194    25183800 :             Set::Scalar psi_avg = 1.0;
     195    29722200 :             if (m_psi_set) psi_avg = (1.0 - m_psi_small) * Numeric::Interpolate::CellToNodeAverage(psi, i, j, k, 0) + m_psi_small;
     196             : 
     197             :             // Stress tensor computed using the model fab
     198    75551500 :             Set::Matrix sig = (DDW(i, j, k) * gradu) * psi_avg;
     199             : 
     200             :             // Boundary conditions
     201             :             /// \todo Important: we need a way to handle corners and edges.
     202    25183800 :             amrex::IntVect m(AMREX_D_DECL(i, j, k));
     203    25183800 :             if (AMREX_D_TERM(xmax || xmin, || ymax || ymin, || zmax || zmin))
     204             :             {
     205    11713790 :                 f = (*m_bc)(u, gradu, sig, i, j, k, domain);
     206             :             }
     207             :             else
     208             :             {
     209             : 
     210             : 
     211             :                 // The gradient of the displacement gradient tensor
     212             :                 // TODO - replace with this call. But not for this PR
     213             :                 //Set::Matrix3 gradgradu = Numeric::Hessian(U,i,j,k,DX,sten); // gradgradu[k](l,j) = u_{k,lj}
     214    13470100 :                 Set::Matrix3 gradgradu; // gradgradu[k](l,j) = u_{k,lj}
     215             : 
     216             :                 // Fill gradu and gradgradu
     217    42108300 :                 for (int p = 0; p < AMREX_SPACEDIM; p++)
     218             :                 {
     219             :                     // Diagonal terms:
     220   124741500 :                     AMREX_D_TERM(gradgradu(p, 0, 0) = (Numeric::Stencil<Set::Scalar, 2, 0, 0>::D(U, i, j, k, p, DX));,
     221             :                         gradgradu(p, 1, 1) = (Numeric::Stencil<Set::Scalar, 0, 2, 0>::D(U, i, j, k, p, DX));,
     222             :                         gradgradu(p, 2, 2) = (Numeric::Stencil<Set::Scalar, 0, 0, 2>::D(U, i, j, k, p, DX)););
     223             : 
     224             :                     // Off-diagonal terms:
     225   183945900 :                     AMREX_D_TERM(,// 2D
     226             :                         gradgradu(p, 0, 1) = (Numeric::Stencil<Set::Scalar, 1, 1, 0>::D(U, i, j, k, p, DX));
     227             :                     gradgradu(p, 1, 0) = gradgradu(p, 0, 1);
     228             :                     ,// 3D
     229             :                         gradgradu(p, 0, 2) = (Numeric::Stencil<Set::Scalar, 1, 0, 1>::D(U, i, j, k, p, DX));
     230             :                     gradgradu(p, 1, 2) = (Numeric::Stencil<Set::Scalar, 0, 1, 1>::D(U, i, j, k, p, DX));
     231             :                     gradgradu(p, 2, 0) = gradgradu(p, 0, 2);
     232             :                     gradgradu(p, 2, 1) = gradgradu(p, 1, 2););
     233             :                 }
     234             : 
     235             :                 //
     236             :                 // Operator
     237             :                 //
     238             :                 // The return value is
     239             :                 //    f = C(grad grad u) + grad(C)*grad(u)
     240             :                 // In index notation
     241             :                 //    f_i = C_{ijkl,j} u_{k,l}  +  C_{ijkl}u_{k,lj}
     242             :                 //
     243             : 
     244    40410200 :                 f = (DDW(i, j, k) * gradgradu) * psi_avg;
     245             : 
     246    13470100 :                 if (!m_uniform)
     247             :                 {
     248             :                     MATRIX4
     249    42010100 :                         AMREX_D_DECL(Cgrad1 = (Numeric::Stencil<MATRIX4, 1, 0, 0>::D(DDW, i, j, k, 0, DX, sten)),
     250             :                             Cgrad2 = (Numeric::Stencil<MATRIX4, 0, 1, 0>::D(DDW, i, j, k, 0, DX, sten)),
     251             :                             Cgrad3 = (Numeric::Stencil<MATRIX4, 0, 0, 1>::D(DDW, i, j, k, 0, DX, sten)));
     252    28736400 :                     f += (AMREX_D_TERM((Cgrad1 * gradu).col(0),
     253             :                         +(Cgrad2 * gradu).col(1),
     254             :                         +(Cgrad3 * gradu).col(2))) * (psi_avg);
     255             :                 }
     256    13470100 :                 if (m_psi_set)
     257             :                 {
     258     4281250 :                     Set::Vector gradpsi = Numeric::CellGradientOnNode(psi, i, j, k, 0, DX);
     259     4281250 :                     gradpsi *= (1.0 - m_psi_small);
     260    12843800 :                     f += (DDW(i, j, k) * gradu) * gradpsi;
     261             :                 }
     262             :             }
     263    86646100 :             AMREX_D_TERM(F(i, j, k, 0) = f[0];, F(i, j, k, 1) = f[1];, F(i, j, k, 2) = f[2];);
     264             :         });
     265             :     }
     266      385843 : }
     267             : 
     268             : 
     269             : 
     270             : template<int SYM>
     271             : void
     272         963 : Elastic<SYM>::Diagonal(int amrlev, int mglev, MultiFab& a_diag)
     273             : {
     274             :     BL_PROFILE("Operator::Elastic::Diagonal()");
     275             : 
     276         963 :     amrex::Box domain(m_geom[amrlev][mglev].Domain());
     277         963 :     domain.convert(amrex::IntVect::TheNodeVector());
     278         963 :     const Real* DX = m_geom[amrlev][mglev].CellSize();
     279             : 
     280        2059 :     for (MFIter mfi(a_diag, amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
     281             :     {
     282        1096 :         Box bx = mfi.validbox().grow(1) & domain;
     283        1096 :         amrex::Box tilebox = mfi.grownnodaltilebox() & bx;
     284             : 
     285        1096 :         amrex::Array4<MATRIX4> const& DDW = (*(m_ddw_mf[amrlev][mglev])).array(mfi);
     286        1096 :         amrex::Array4<Set::Scalar> const& diag = a_diag.array(mfi);
     287        1096 :         amrex::Array4<Set::Scalar> const& psi = m_psi_mf[amrlev][mglev]->array(mfi);
     288             : 
     289        1096 :         const Dim3 lo = amrex::lbound(domain), hi = amrex::ubound(domain);
     290             : 
     291      187432 :         amrex::ParallelFor(tilebox, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
     292             : 
     293      186336 :             Set::Vector f = Set::Vector::Zero();
     294             : 
     295      186336 :             bool    AMREX_D_DECL(xmin = (i == lo.x), ymin = (j == lo.y), zmin = (k == lo.z)),
     296      186336 :                 AMREX_D_DECL(xmax = (i == hi.x), ymax = (j == hi.y), zmax = (k == hi.z));
     297             : 
     298      186336 :             Set::Scalar psi_avg = 1.0;
     299      268052 :             if (m_psi_set) psi_avg = (1.0 - m_psi_small) * Numeric::Interpolate::CellToNodeAverage(psi, i, j, k, 0) + m_psi_small;
     300             : 
     301      186336 :             Set::Matrix gradu; // gradu(i,j) = u_{i,j)
     302      186336 :             Set::Matrix3 gradgradu; // gradgradu[k](l,j) = u_{k,lj}
     303             : 
     304      604608 :             for (int p = 0; p < AMREX_SPACEDIM; p++)
     305             :             {
     306             : 
     307      418272 :                 diag(i, j, k, p) = 0.0;
     308     1391616 :                 for (int q = 0; q < AMREX_SPACEDIM; q++)
     309             :                 {
     310      973344 :                     AMREX_D_TERM(
     311             :                         gradu(q, 0) = ((!xmax ? 0.0 : (p == q ? 1.0 : 0.0)) - (!xmin ? 0.0 : (p == q ? 1.0 : 0.0))) / ((xmin || xmax ? 1.0 : 2.0) * DX[0]);,
     312             :                         gradu(q, 1) = ((!ymax ? 0.0 : (p == q ? 1.0 : 0.0)) - (!ymin ? 0.0 : (p == q ? 1.0 : 0.0))) / ((ymin || ymax ? 1.0 : 2.0) * DX[1]);,
     313             :                         gradu(q, 2) = ((!zmax ? 0.0 : (p == q ? 1.0 : 0.0)) - (!zmin ? 0.0 : (p == q ? 1.0 : 0.0))) / ((zmin || zmax ? 1.0 : 2.0) * DX[2]););
     314             : 
     315     6918720 :                     AMREX_D_TERM(
     316             :                         gradgradu(q, 0, 0) = (p == q ? -2.0 : 0.0) / DX[0] / DX[0];
     317             :                     ,// 2D
     318             :                         gradgradu(q, 0, 1) = 0.0;
     319             :                     gradgradu(q, 1, 0) = 0.0;
     320             :                     gradgradu(q, 1, 1) = (p == q ? -2.0 : 0.0) / DX[1] / DX[1];
     321             :                     ,// 3D
     322             :                         gradgradu(q, 0, 2) = 0.0;
     323             :                     gradgradu(q, 1, 2) = 0.0;
     324             :                     gradgradu(q, 2, 0) = 0.0;
     325             :                     gradgradu(q, 2, 1) = 0.0;
     326             :                     gradgradu(q, 2, 2) = (p == q ? -2.0 : 0.0) / DX[2] / DX[2]);
     327             :                 }
     328             : 
     329             : 
     330      418272 :                 amrex::IntVect m(AMREX_D_DECL(i, j, k));
     331      418272 :                 if (AMREX_D_TERM(xmax || xmin, || ymax || ymin, || zmax || zmin))
     332             :                 {
     333      379392 :                     Set::Matrix sig = DDW(i, j, k) * gradu * psi_avg;
     334      126464 :                     Set::Vector u = Set::Vector::Zero();
     335      126464 :                     u(p) = 1.0;
     336      126464 :                     f = (*m_bc)(u, gradu, sig, i, j, k, domain);
     337      252928 :                     diag(i, j, k, p) = f(p);
     338             :                 }
     339             :                 else
     340             :                 {
     341      875424 :                     Set::Vector f = (DDW(i, j, k) * gradgradu) * psi_avg;
     342      583616 :                     diag(i, j, k, p) += f(p);
     343             :                 }
     344             : 
     345             : #ifdef AMREX_DEBUG
     346             :                 if (std::isnan(diag(i, j, k, p))) Util::Abort(INFO, "diagonal is nan at (", i, ",", j, ",", k, "), amrlev=", amrlev, ", mglev=", mglev);
     347             :                 if (std::isinf(diag(i, j, k, p))) Util::Abort(INFO, "diagonal is inf at (", i, ",", j, ",", k, "), amrlev=", amrlev, ", mglev=", mglev);
     348             :                 if (diag(i, j, k, p) == 0) Util::Abort(INFO, "diagonal is zero at (", i, ",", j, ",", k, "), amrlev=", amrlev, ", mglev=", mglev);
     349             : #endif
     350             : 
     351             :             }
     352             :         });
     353             :     }
     354         963 : }
     355             : 
     356             : 
     357             : template<int SYM>
     358             : void
     359           0 : Elastic<SYM>::Error0x(int amrlev, int mglev, MultiFab& R0x, const MultiFab& x) const
     360             : {
     361             :     BL_PROFILE("Operator::Elastic::Error0x()");
     362           0 :     Util::Message(INFO);
     363             : 
     364           0 :     int ncomp = x.nComp();//getNComp();
     365           0 :     int nghost = x.nGrow();
     366             : 
     367           0 :     if (!m_diagonal_computed)
     368           0 :         Util::Abort(INFO, "Operator::Diagonal() must be called before using normalize");
     369             : 
     370           0 :     amrex::MultiFab D0x(x.boxArray(), x.DistributionMap(), ncomp, nghost);
     371           0 :     amrex::MultiFab AD0x(x.boxArray(), x.DistributionMap(), ncomp, nghost);
     372             : 
     373           0 :     amrex::MultiFab::Copy(D0x, x, 0, 0, ncomp, nghost); // D0x = x
     374           0 :     amrex::MultiFab::Divide(D0x, *m_diag[amrlev][mglev], 0, 0, ncomp, 0); // D0x = x/diag
     375           0 :     amrex::MultiFab::Copy(AD0x, D0x, 0, 0, ncomp, nghost); // AD0x = D0x
     376             : 
     377           0 :     Fapply(amrlev, mglev, AD0x, D0x);    // AD0x = A * D0 * x
     378             : 
     379           0 :     amrex::MultiFab::Copy(R0x, x, 0, 0, ncomp, nghost); // R0x = x
     380           0 :     amrex::MultiFab::Subtract(R0x, AD0x, 0, 0, ncomp, nghost); // R0x = x - AD0x
     381           0 : }
     382             : 
     383             : 
     384             : template<int SYM>
     385             : void
     386           0 : Elastic<SYM>::FFlux(int /*amrlev*/, const MFIter& /*mfi*/,
     387             :     const std::array<FArrayBox*, AMREX_SPACEDIM>& sigmafab,
     388             :     const FArrayBox& /*ufab*/, const int /*face_only*/) const
     389             : {
     390             :     BL_PROFILE("Operator::Elastic::FFlux()");
     391           0 :     Util::Message(INFO);
     392           0 :     amrex::BaseFab<amrex::Real> AMREX_D_DECL(&fxfab = *sigmafab[0],
     393             :         &fyfab = *sigmafab[1],
     394             :         &fzfab = *sigmafab[2]);
     395           0 :     AMREX_D_TERM(fxfab.setVal(0.0);,
     396             :         fyfab.setVal(0.0);,
     397             :         fzfab.setVal(0.0););
     398             : 
     399           0 : }
     400             : 
     401             : template<int SYM>
     402             : void
     403           0 : Elastic<SYM>::Strain(int amrlev,
     404             :     amrex::MultiFab& a_eps,
     405             :     const amrex::MultiFab& a_u,
     406             :     bool voigt) const
     407             : {
     408             :     BL_PROFILE("Operator::Elastic::Strain()");
     409             : 
     410           0 :     const amrex::Real* DX = m_geom[amrlev][0].CellSize();
     411           0 :     amrex::Box domain(m_geom[amrlev][0].Domain());
     412           0 :     domain.convert(amrex::IntVect::TheNodeVector());
     413             : 
     414             : 
     415           0 :     for (MFIter mfi(a_u, amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
     416             :     {
     417           0 :         const Box& bx = mfi.tilebox();
     418           0 :         amrex::Array4<amrex::Real> const& epsilon = a_eps.array(mfi);
     419           0 :         amrex::Array4<const amrex::Real> const& u = a_u.array(mfi);
     420           0 :         amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
     421             :         {
     422           0 :             Set::Matrix gradu;
     423             : 
     424             :             std::array<Numeric::StencilType, AMREX_SPACEDIM> sten
     425           0 :                 = Numeric::GetStencil(i, j, k, domain);
     426             : 
     427             :             // Fill gradu
     428           0 :             for (int p = 0; p < AMREX_SPACEDIM; p++)
     429             :             {
     430           0 :                 AMREX_D_TERM(gradu(p, 0) = (Numeric::Stencil<Set::Scalar, 1, 0, 0>::D(u, i, j, k, p, DX, sten));,
     431             :                     gradu(p, 1) = (Numeric::Stencil<Set::Scalar, 0, 1, 0>::D(u, i, j, k, p, DX, sten));,
     432             :                     gradu(p, 2) = (Numeric::Stencil<Set::Scalar, 0, 0, 1>::D(u, i, j, k, p, DX, sten)););
     433             :             }
     434             : 
     435           0 :             Set::Matrix eps = 0.5 * (gradu + gradu.transpose());
     436             : 
     437           0 :             if (voigt)
     438             :             {
     439           0 :                 AMREX_D_PICK(epsilon(i, j, k, 0) = eps(0, 0);
     440             :                 ,
     441             :                     epsilon(i, j, k, 0) = eps(0, 0); epsilon(i, j, k, 1) = eps(1, 1); epsilon(i, j, k, 2) = eps(0, 1);
     442             :                 ,
     443             :                     epsilon(i, j, k, 0) = eps(0, 0); epsilon(i, j, k, 1) = eps(1, 1); epsilon(i, j, k, 2) = eps(2, 2);
     444             :                 epsilon(i, j, k, 3) = eps(1, 2); epsilon(i, j, k, 4) = eps(2, 0); epsilon(i, j, k, 5) = eps(0, 1););
     445             :             }
     446             :             else
     447             :             {
     448           0 :                 AMREX_D_PICK(epsilon(i, j, k, 0) = eps(0, 0);
     449             :                 ,
     450             :                     epsilon(i, j, k, 0) = eps(0, 0); epsilon(i, j, k, 1) = eps(0, 1);
     451             :                 epsilon(i, j, k, 2) = eps(1, 0); epsilon(i, j, k, 3) = eps(1, 1);
     452             :                 ,
     453             :                     epsilon(i, j, k, 0) = eps(0, 0); epsilon(i, j, k, 1) = eps(0, 1); epsilon(i, j, k, 2) = eps(0, 2);
     454             :                 epsilon(i, j, k, 3) = eps(1, 0); epsilon(i, j, k, 4) = eps(1, 1); epsilon(i, j, k, 5) = eps(1, 2);
     455             :                 epsilon(i, j, k, 6) = eps(2, 0); epsilon(i, j, k, 7) = eps(2, 1); epsilon(i, j, k, 8) = eps(2, 2););
     456             :             }
     457             :         });
     458             :     }
     459           0 : }
     460             : 
     461             : 
     462             : template<int SYM>
     463             : void
     464           0 : Elastic<SYM>::Stress(int amrlev,
     465             :     amrex::MultiFab& a_sigma,
     466             :     const amrex::MultiFab& a_u,
     467             :     bool voigt, bool a_homogeneous)
     468             : {
     469             :     BL_PROFILE("Operator::Elastic::Stress()");
     470           0 :     SetHomogeneous(a_homogeneous);
     471             : 
     472           0 :     const amrex::Real* DX = m_geom[amrlev][0].CellSize();
     473           0 :     amrex::Box domain(m_geom[amrlev][0].Domain());
     474           0 :     domain.convert(amrex::IntVect::TheNodeVector());
     475             : 
     476           0 :     for (MFIter mfi(a_u, amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
     477             :     {
     478           0 :         const Box& bx = mfi.tilebox();
     479           0 :         amrex::Array4<Set::Matrix4<AMREX_SPACEDIM, SYM>> const& DDW = (*(m_ddw_mf[amrlev][0])).array(mfi);
     480           0 :         amrex::Array4<amrex::Real> const& sigma = a_sigma.array(mfi);
     481           0 :         amrex::Array4<Set::Scalar> const& psi = m_psi_mf[amrlev][0]->array(mfi);
     482           0 :         amrex::Array4<const amrex::Real> const& u = a_u.array(mfi);
     483           0 :         amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
     484             :         {
     485           0 :             Set::Matrix gradu;
     486             : 
     487             :             std::array<Numeric::StencilType, AMREX_SPACEDIM> sten
     488           0 :                 = Numeric::GetStencil(i, j, k, domain);
     489             : 
     490             :             // Fill gradu
     491           0 :             for (int p = 0; p < AMREX_SPACEDIM; p++)
     492             :             {
     493           0 :                 AMREX_D_TERM(gradu(p, 0) = (Numeric::Stencil<Set::Scalar, 1, 0, 0>::D(u, i, j, k, p, DX, sten));,
     494             :                     gradu(p, 1) = (Numeric::Stencil<Set::Scalar, 0, 1, 0>::D(u, i, j, k, p, DX, sten));,
     495             :                     gradu(p, 2) = (Numeric::Stencil<Set::Scalar, 0, 0, 1>::D(u, i, j, k, p, DX, sten)););
     496             :             }
     497             : 
     498           0 :             Set::Scalar psi_avg = 1.0;
     499           0 :             if (m_psi_set) psi_avg = (1.0 - m_psi_small) * Numeric::Interpolate::CellToNodeAverage(psi, i, j, k, 0) + m_psi_small;
     500           0 :             Set::Matrix sig = (DDW(i, j, k) * gradu) * psi_avg;
     501             : 
     502           0 :             if (voigt)
     503             :             {
     504           0 :                 AMREX_D_PICK(sigma(i, j, k, 0) = sig(0, 0);
     505             :                 ,
     506             :                     sigma(i, j, k, 0) = sig(0, 0); sigma(i, j, k, 1) = sig(1, 1); sigma(i, j, k, 2) = sig(0, 1);
     507             :                 ,
     508             :                     sigma(i, j, k, 0) = sig(0, 0); sigma(i, j, k, 1) = sig(1, 1); sigma(i, j, k, 2) = sig(2, 2);
     509             :                 sigma(i, j, k, 3) = sig(1, 2); sigma(i, j, k, 4) = sig(2, 0); sigma(i, j, k, 5) = sig(0, 1););
     510             :             }
     511             :             else
     512             :             {
     513           0 :                 AMREX_D_PICK(sigma(i, j, k, 0) = sig(0, 0);
     514             :                 ,
     515             :                     sigma(i, j, k, 0) = sig(0, 0); sigma(i, j, k, 1) = sig(0, 1);
     516             :                 sigma(i, j, k, 2) = sig(1, 0); sigma(i, j, k, 3) = sig(1, 1);
     517             :                 ,
     518             :                     sigma(i, j, k, 0) = sig(0, 0); sigma(i, j, k, 1) = sig(0, 1); sigma(i, j, k, 2) = sig(0, 2);
     519             :                 sigma(i, j, k, 3) = sig(1, 0); sigma(i, j, k, 4) = sig(1, 1); sigma(i, j, k, 5) = sig(1, 2);
     520             :                 sigma(i, j, k, 6) = sig(2, 0); sigma(i, j, k, 7) = sig(2, 1); sigma(i, j, k, 8) = sig(2, 2););
     521             :             }
     522             :         });
     523             :     }
     524           0 : }
     525             : 
     526             : 
     527             : template<int SYM>
     528             : void
     529           0 : Elastic<SYM>::Energy(int amrlev,
     530             :     amrex::MultiFab& a_energy,
     531             :     const amrex::MultiFab& a_u, bool a_homogeneous)
     532             : {
     533             :     BL_PROFILE("Operator::Elastic::Energy()");
     534           0 :     SetHomogeneous(a_homogeneous);
     535             : 
     536           0 :     amrex::Box domain(m_geom[amrlev][0].Domain());
     537           0 :     domain.convert(amrex::IntVect::TheNodeVector());
     538             : 
     539           0 :     const amrex::Real* DX = m_geom[amrlev][0].CellSize();
     540             : 
     541           0 :     for (MFIter mfi(a_u, amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
     542             :     {
     543           0 :         const Box& bx = mfi.tilebox();
     544           0 :         amrex::Array4<Set::Matrix4<AMREX_SPACEDIM, SYM>> const& DDW = (*(m_ddw_mf[amrlev][0])).array(mfi);
     545           0 :         amrex::Array4<amrex::Real> const& energy = a_energy.array(mfi);
     546           0 :         amrex::Array4<const amrex::Real> const& u = a_u.array(mfi);
     547           0 :         amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
     548             :         {
     549           0 :             Set::Matrix gradu;
     550             : 
     551             :             std::array<Numeric::StencilType, AMREX_SPACEDIM> sten
     552           0 :                 = Numeric::GetStencil(i, j, k, domain);
     553             : 
     554             :             // Fill gradu
     555           0 :             for (int p = 0; p < AMREX_SPACEDIM; p++)
     556             :             {
     557           0 :                 AMREX_D_TERM(gradu(p, 0) = (Numeric::Stencil<Set::Scalar, 1, 0, 0>::D(u, i, j, k, p, DX, sten));,
     558             :                     gradu(p, 1) = (Numeric::Stencil<Set::Scalar, 0, 1, 0>::D(u, i, j, k, p, DX, sten));,
     559             :                     gradu(p, 2) = (Numeric::Stencil<Set::Scalar, 0, 0, 1>::D(u, i, j, k, p, DX, sten)););
     560             :             }
     561             : 
     562           0 :             Set::Matrix eps = .5 * (gradu + gradu.transpose());
     563           0 :             Set::Matrix sig = DDW(i, j, k) * gradu;
     564             : 
     565             :             // energy(i,j,k) = (gradu.transpose() * sig).trace();
     566             : 
     567             :             //Util::Abort(INFO,"Fix this"); //
     568             :             //energy(i,j,k) = C(i,j,k).W(gradu);
     569           0 :             for (int m = 0; m < AMREX_SPACEDIM; m++)
     570             :             {
     571           0 :                 for (int n = 0; n < AMREX_SPACEDIM; n++)
     572             :                 {
     573           0 :                     energy(i, j, k) += .5 * sig(m, n) * eps(m, n);
     574             :                 }
     575             :             }
     576             :         });
     577             :     }
     578           0 : }
     579             : 
     580             : template<int SYM>
     581             : void
     582         426 : Elastic<SYM>::averageDownCoeffs()
     583             : {
     584             :     BL_PROFILE("Elastic::averageDownCoeffs()");
     585             : 
     586         426 :     if (m_average_down_coeffs)
     587           0 :         for (int amrlev = m_num_amr_levels - 1; amrlev > 0; --amrlev)
     588           0 :             averageDownCoeffsDifferentAmrLevels(amrlev);
     589             : 
     590         426 :     averageDownCoeffsSameAmrLevel(0);
     591         898 :     for (int amrlev = 0; amrlev < m_num_amr_levels; ++amrlev)
     592             :     {
     593        1435 :         for (int mglev = 0; mglev < m_num_mg_levels[amrlev]; ++mglev)
     594             :         {
     595         963 :             if (m_ddw_mf[amrlev][mglev]) {
     596         963 :                 FillBoundaryCoeff(*m_ddw_mf[amrlev][mglev], m_geom[amrlev][mglev]);
     597         963 :                 FillBoundaryCoeff(*m_psi_mf[amrlev][mglev], m_geom[amrlev][mglev]);
     598             :             }
     599             :         }
     600             :     }
     601         426 : }
     602             : 
     603             : template<int SYM>
     604             : void
     605           0 : Elastic<SYM>::averageDownCoeffsDifferentAmrLevels(int fine_amrlev)
     606             : {
     607             :     BL_PROFILE("Operator::Elastic::averageDownCoeffsDifferentAmrLevels()");
     608           0 :     Util::Assert(INFO, TEST(fine_amrlev > 0));
     609             : 
     610           0 :     const int crse_amrlev = fine_amrlev - 1;
     611           0 :     const int ncomp = 1;
     612             : 
     613           0 :     MultiTab& crse_ddw = *m_ddw_mf[crse_amrlev][0];
     614           0 :     MultiTab& fine_ddw = *m_ddw_mf[fine_amrlev][0];
     615             : 
     616           0 :     amrex::Box cdomain(m_geom[crse_amrlev][0].Domain());
     617           0 :     cdomain.convert(amrex::IntVect::TheNodeVector());
     618             : 
     619           0 :     const Geometry& cgeom = m_geom[crse_amrlev][0];
     620             : 
     621           0 :     const BoxArray& fba = fine_ddw.boxArray();
     622           0 :     const DistributionMapping& fdm = fine_ddw.DistributionMap();
     623             : 
     624           0 :     MultiTab fine_ddw_for_coarse(amrex::coarsen(fba, 2), fdm, ncomp, 2);
     625           0 :     fine_ddw_for_coarse.ParallelCopy(crse_ddw, 0, 0, ncomp, 0, 0, cgeom.periodicity());
     626             : 
     627           0 :     const int coarse_fine_node = 1;
     628           0 :     const int fine_fine_node = 2;
     629             : 
     630           0 :     amrex::iMultiFab nodemask(amrex::coarsen(fba, 2), fdm, 1, 2);
     631           0 :     nodemask.ParallelCopy(*m_nd_fine_mask[crse_amrlev], 0, 0, 1, 0, 0, cgeom.periodicity());
     632             : 
     633           0 :     amrex::iMultiFab cellmask(amrex::convert(amrex::coarsen(fba, 2), amrex::IntVect::TheCellVector()), fdm, 1, 2);
     634           0 :     cellmask.ParallelCopy(*m_cc_fine_mask[crse_amrlev], 0, 0, 1, 1, 1, cgeom.periodicity());
     635             : 
     636           0 :     for (MFIter mfi(fine_ddw_for_coarse, false); mfi.isValid(); ++mfi)
     637             :     {
     638           0 :         const Box& bx = mfi.validbox();
     639             : 
     640           0 :         amrex::Array4<const int> const& nmask = nodemask.array(mfi);
     641             :         //amrex::Array4<const int> const& cmask = cellmask.array(mfi);
     642             : 
     643           0 :         amrex::Array4<MATRIX4> const& cdata = fine_ddw_for_coarse.array(mfi);
     644           0 :         amrex::Array4<const MATRIX4> const& fdata = fine_ddw.array(mfi);
     645             : 
     646           0 :         const Dim3 lo = amrex::lbound(cdomain), hi = amrex::ubound(cdomain);
     647             : 
     648           0 :         for (int n = 0; n < fine_ddw.nComp(); n++)
     649             :         {
     650             :             // I,J,K == coarse coordinates
     651             :             // i,j,k == fine coordinates
     652           0 :             amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int I, int J, int K) {
     653           0 :                 int i = I * 2, j = J * 2, k = K * 2;
     654             : 
     655           0 :                 if (nmask(I, J, K) == fine_fine_node || nmask(I, J, K) == coarse_fine_node)
     656             :                 {
     657           0 :                     if ((I == lo.x || I == hi.x) &&
     658           0 :                         (J == lo.y || J == hi.y) &&
     659           0 :                         (K == lo.z || K == hi.z)) // Corner
     660           0 :                         cdata(I, J, K, n) = fdata(i, j, k, n);
     661           0 :                     else if ((J == lo.y || J == hi.y) &&
     662           0 :                         (K == lo.z || K == hi.z)) // X edge
     663           0 :                         cdata(I, J, K, n) = fdata(i - 1, j, k, n) * 0.25 + fdata(i, j, k, n) * 0.5 + fdata(i + 1, j, k, n) * 0.25;
     664           0 :                     else if ((K == lo.z || K == hi.z) &&
     665           0 :                         (I == lo.x || I == hi.x)) // Y edge
     666           0 :                         cdata(I, J, K, n) = fdata(i, j - 1, k, n) * 0.25 + fdata(i, j, k, n) * 0.5 + fdata(i, j + 1, k, n) * 0.25;
     667           0 :                     else if ((I == lo.x || I == hi.x) &&
     668           0 :                         (J == lo.y || J == hi.y)) // Z edge
     669           0 :                         cdata(I, J, K, n) = fdata(i, j, k - 1, n) * 0.25 + fdata(i, j, k, n) * 0.5 + fdata(i, j, k + 1, n) * 0.25;
     670           0 :                     else if (I == lo.x || I == hi.x) // X face
     671           0 :                         cdata(I, J, K, n) =
     672           0 :                         (fdata(i, j - 1, k - 1, n) + fdata(i, j, k - 1, n) * 2.0 + fdata(i, j + 1, k - 1, n)
     673           0 :                             + fdata(i, j - 1, k, n) * 2.0 + fdata(i, j, k, n) * 4.0 + fdata(i, j + 1, k, n) * 2.0
     674           0 :                             + fdata(i, j - 1, k + 1, n) + fdata(i, j, k + 1, n) * 2.0 + fdata(i, j + 1, k + 1, n)) / 16.0;
     675           0 :                     else if (J == lo.y || J == hi.y) // Y face
     676           0 :                         cdata(I, J, K, n) =
     677           0 :                         (fdata(i - 1, j, k - 1, n) + fdata(i - 1, j, k, n) * 2.0 + fdata(i - 1, j, k + 1, n)
     678           0 :                             + fdata(i, j, k - 1, n) * 2.0 + fdata(i, j, k, n) * 4.0 + fdata(i, j, k + 1, n) * 2.0
     679           0 :                             + fdata(i + 1, j, k - 1, n) + fdata(i + 1, j, k, n) * 2.0 + fdata(i + 1, j, k + 1, n)) / 16.0;
     680           0 :                     else if (K == lo.z || K == hi.z) // Z face
     681           0 :                         cdata(I, J, K, n) =
     682           0 :                         (fdata(i - 1, j - 1, k, n) + fdata(i, j - 1, k, n) * 2.0 + fdata(i + 1, j - 1, k, n)
     683           0 :                             + fdata(i - 1, j, k, n) * 2.0 + fdata(i, j, k, n) * 4.0 + fdata(i + 1, j, k, n) * 2.0
     684           0 :                             + fdata(i - 1, j + 1, k, n) + fdata(i, j + 1, k, n) * 2.0 + fdata(i + 1, j + 1, k, n)) / 16.0;
     685             :                     else // Interior
     686           0 :                         cdata(I, J, K, n) =
     687           0 :                         (fdata(i - 1, j - 1, k - 1, n) + fdata(i - 1, j - 1, k + 1, n) + fdata(i - 1, j + 1, k - 1, n) + fdata(i - 1, j + 1, k + 1, n) +
     688           0 :                             fdata(i + 1, j - 1, k - 1, n) + fdata(i + 1, j - 1, k + 1, n) + fdata(i + 1, j + 1, k - 1, n) + fdata(i + 1, j + 1, k + 1, n)) / 64.0
     689           0 :                         +
     690           0 :                         (fdata(i, j - 1, k - 1, n) + fdata(i, j - 1, k + 1, n) + fdata(i, j + 1, k - 1, n) + fdata(i, j + 1, k + 1, n) +
     691           0 :                             fdata(i - 1, j, k - 1, n) + fdata(i + 1, j, k - 1, n) + fdata(i - 1, j, k + 1, n) + fdata(i + 1, j, k + 1, n) +
     692           0 :                             fdata(i - 1, j - 1, k, n) + fdata(i - 1, j + 1, k, n) + fdata(i + 1, j - 1, k, n) + fdata(i + 1, j + 1, k, n)) / 32.0
     693           0 :                         +
     694           0 :                         (fdata(i - 1, j, k, n) + fdata(i, j - 1, k, n) + fdata(i, j, k - 1, n) +
     695           0 :                             fdata(i + 1, j, k, n) + fdata(i, j + 1, k, n) + fdata(i, j, k + 1, n)) / 16.0
     696           0 :                         +
     697           0 :                         fdata(i, j, k, n) / 8.0;
     698             : 
     699             : #ifdef AMREX_DEBUG
     700             :                     if (cdata(i, j, k).contains_nan()) Util::Abort(INFO, "restricted model is nan at (", i, ",", j, ",", k, "), fine_amrlev=", fine_amrlev);
     701             : #endif
     702             :                 }
     703             : 
     704             :             });
     705             :         }
     706             :     }
     707             : 
     708             :     // Copy the fine residual restricted onto the coarse grid
     709             :     // into the final residual.
     710           0 :     crse_ddw.ParallelCopy(fine_ddw_for_coarse, 0, 0, ncomp, 0, 0, cgeom.periodicity());
     711           0 :     const int mglev = 0;
     712           0 :     Util::RealFillBoundary(crse_ddw, m_geom[crse_amrlev][mglev]);
     713           0 :     return;
     714             : }
     715             : 
     716             : 
     717             : 
     718             : template<int SYM>
     719             : void
     720         426 : Elastic<SYM>::averageDownCoeffsSameAmrLevel(int amrlev)
     721             : {
     722             :     BL_PROFILE("Elastic::averageDownCoeffsSameAmrLevel()");
     723             : 
     724         917 :     for (int mglev = 1; mglev < m_num_mg_levels[amrlev]; ++mglev)
     725             :     {
     726         491 :         amrex::Box cdomain(m_geom[amrlev][mglev].Domain());
     727         491 :         cdomain.convert(amrex::IntVect::TheNodeVector());
     728         491 :         amrex::Box fdomain(m_geom[amrlev][mglev - 1].Domain());
     729         491 :         fdomain.convert(amrex::IntVect::TheNodeVector());
     730             : 
     731         491 :         MultiTab& crse = *m_ddw_mf[amrlev][mglev];
     732         491 :         MultiTab& fine = *m_ddw_mf[amrlev][mglev - 1];
     733             : 
     734         491 :         amrex::BoxArray crseba = crse.boxArray();
     735         491 :         amrex::BoxArray fineba = fine.boxArray();
     736             : 
     737         491 :         BoxArray newba = crseba;
     738         491 :         newba.refine(2);
     739         491 :         MultiTab fine_on_crseba;
     740         491 :         fine_on_crseba.define(newba, crse.DistributionMap(), 1, 4);
     741         491 :         fine_on_crseba.ParallelCopy(fine, 0, 0, 1, 2, 4, m_geom[amrlev][mglev].periodicity());
     742             : 
     743         982 :         for (MFIter mfi(crse, amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
     744             :         {
     745         491 :             Box bx = mfi.tilebox();
     746         491 :             bx = bx & cdomain;
     747             : 
     748         491 :             amrex::Array4<const Set::Matrix4<AMREX_SPACEDIM, SYM>> const& fdata = fine_on_crseba.array(mfi);
     749         491 :             amrex::Array4<Set::Matrix4<AMREX_SPACEDIM, SYM>> const& cdata = crse.array(mfi);
     750             : 
     751         491 :             const Dim3 lo = amrex::lbound(cdomain), hi = amrex::ubound(cdomain);
     752             : 
     753             :             // I,J,K == coarse coordinates
     754             :             // i,j,k == fine coordinates
     755       31849 :             amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int I, int J, int K) {
     756       16487 :                 int i = 2 * I, j = 2 * J, k = 2 * K;
     757             : 
     758       16487 :                 if ((I == lo.x || I == hi.x) &&
     759        7326 :                     (J == lo.y || J == hi.y) &&
     760        4364 :                     (K == lo.z || K == hi.z)) // Corner
     761        9492 :                     cdata(I, J, K) = fdata(i, j, k);
     762       13323 :                 else if ((J == lo.y || J == hi.y) &&
     763        4282 :                     (K == lo.z || K == hi.z)) // X edge
     764       23520 :                     cdata(I, J, K) = fdata(i - 1, j, k) * 0.25 + fdata(i, j, k) * 0.5 + fdata(i + 1, j, k) * 0.25;
     765       10841 :                 else if ((K == lo.z || K == hi.z) &&
     766        8141 :                     (I == lo.x || I == hi.x)) // Y edge
     767       22320 :                     cdata(I, J, K) = fdata(i, j - 1, k) * 0.25 + fdata(i, j, k) * 0.5 + fdata(i, j + 1, k) * 0.25;
     768        8479 :                 else if ((I == lo.x || I == hi.x) &&
     769        1800 :                     (J == lo.y || J == hi.y)) // Z edge
     770       12000 :                     cdata(I, J, K) = fdata(i, j, k - 1) * 0.25 + fdata(i, j, k) * 0.5 + fdata(i, j, k + 1) * 0.25;
     771        7279 :                 else if (I == lo.x || I == hi.x) // X face
     772         600 :                     cdata(I, J, K) =
     773        3000 :                     (fdata(i, j - 1, k - 1) + fdata(i, j, k - 1) * 2.0 + fdata(i, j + 1, k - 1)
     774        4200 :                         + fdata(i, j - 1, k) * 2.0 + fdata(i, j, k) * 4.0 + fdata(i, j + 1, k) * 2.0
     775        7200 :                         + fdata(i, j - 1, k + 1) + fdata(i, j, k + 1) * 2.0 + fdata(i, j + 1, k + 1)) / 16.0;
     776        6679 :                 else if (J == lo.y || J == hi.y) // Y face
     777         600 :                     cdata(I, J, K) =
     778        3000 :                     (fdata(i - 1, j, k - 1) + fdata(i - 1, j, k) * 2.0 + fdata(i - 1, j, k + 1)
     779        4200 :                         + fdata(i, j, k - 1) * 2.0 + fdata(i, j, k) * 4.0 + fdata(i, j, k + 1) * 2.0
     780        7200 :                         + fdata(i + 1, j, k - 1) + fdata(i + 1, j, k) * 2.0 + fdata(i + 1, j, k + 1)) / 16.0;
     781        6079 :                 else if (K == lo.z || K == hi.z) // Z face
     782       17139 :                     cdata(I, J, K) =
     783       27645 :                     (fdata(i - 1, j - 1, k) + fdata(i, j - 1, k) * 2.0 + fdata(i + 1, j - 1, k)
     784       40999 :                         + fdata(i - 1, j, k) * 2.0 + fdata(i, j, k) * 4.0 + fdata(i + 1, j, k) * 2.0
     785       44748 :                         + fdata(i - 1, j + 1, k) + fdata(i, j + 1, k) * 2.0 + fdata(i + 1, j + 1, k)) / 16.0;
     786             :                 else // Interior
     787         300 :                     cdata(I, J, K) =
     788        2200 :                     (fdata(i - 1, j - 1, k - 1) + fdata(i - 1, j - 1, k + 1) + fdata(i - 1, j + 1, k - 1) + fdata(i - 1, j + 1, k + 1) +
     789        1800 :                         fdata(i + 1, j - 1, k - 1) + fdata(i + 1, j - 1, k + 1) + fdata(i + 1, j + 1, k - 1) + fdata(i + 1, j + 1, k + 1)) / 64.0
     790         200 :                     +
     791        2200 :                     (fdata(i, j - 1, k - 1) + fdata(i, j - 1, k + 1) + fdata(i, j + 1, k - 1) + fdata(i, j + 1, k + 1) +
     792        2000 :                         fdata(i - 1, j, k - 1) + fdata(i + 1, j, k - 1) + fdata(i - 1, j, k + 1) + fdata(i + 1, j, k + 1) +
     793        1800 :                         fdata(i - 1, j - 1, k) + fdata(i - 1, j + 1, k) + fdata(i + 1, j - 1, k) + fdata(i + 1, j + 1, k)) / 32.0
     794         200 :                     +
     795        1700 :                     (fdata(i - 1, j, k) + fdata(i, j - 1, k) + fdata(i, j, k - 1) +
     796        1300 :                         fdata(i + 1, j, k) + fdata(i, j + 1, k) + fdata(i, j, k + 1)) / 16.0
     797        3000 :                     +
     798        1000 :                     fdata(i, j, k) / 8.0;
     799             : 
     800             : #ifdef AMREX_DEBUG
     801             :                 if (cdata(I, J, K).contains_nan()) Util::Abort(INFO, "restricted model is nan at crse coordinates (I=", I, ",J=", J, ",K=", k, "), amrlev=", amrlev, " interpolating from mglev", mglev - 1, " to ", mglev);
     802             : #endif
     803             :             });
     804             :         }
     805         491 :         FillBoundaryCoeff(crse, m_geom[amrlev][mglev]);
     806             : 
     807             : 
     808         491 :         if (!m_psi_set) continue;
     809             : 
     810          46 :         amrex::Box cdomain_cell(m_geom[amrlev][mglev].Domain());
     811          46 :         amrex::Box fdomain_cell(m_geom[amrlev][mglev - 1].Domain());
     812          46 :         MultiFab& crse_psi = *m_psi_mf[amrlev][mglev];
     813          46 :         MultiFab& fine_psi = *m_psi_mf[amrlev][mglev - 1];
     814          92 :         MultiFab fine_psi_on_crseba;
     815          92 :         fine_psi_on_crseba.define(newba.convert(amrex::IntVect::TheCellVector()), crse_psi.DistributionMap(), 1, 1);
     816          46 :         fine_psi_on_crseba.ParallelCopy(fine_psi, 0, 0, 1, 1, 1, m_geom[amrlev][mglev].periodicity());
     817             : 
     818          92 :         for (MFIter mfi(crse_psi, amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
     819             :         {
     820          46 :             Box bx = mfi.tilebox();
     821          46 :             bx = bx & cdomain_cell;
     822             : 
     823          46 :             amrex::Array4<const Set::Scalar> const& fdata = fine_psi_on_crseba.array(mfi);
     824          46 :             amrex::Array4<Set::Scalar> const& cdata = crse_psi.array(mfi);
     825             : 
     826          46 :             const Dim3 lo = amrex::lbound(cdomain), hi = amrex::ubound(cdomain);
     827             : 
     828             :             // I,J,K == coarse coordinates
     829             :             // i,j,k == fine coordinates
     830        5806 :             amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int I, int J, int K) {
     831        2880 :                 int i = 2 * I, j = 2 * J, k = 2 * K;
     832             : 
     833        2880 :                 if ((I == lo.x || I == hi.x) &&
     834         260 :                     (J == lo.y || J == hi.y) &&
     835          46 :                     (K == lo.z || K == hi.z)) // Corner
     836         138 :                     cdata(I, J, K) = fdata(i, j, k);
     837        2834 :                 else if ((J == lo.y || J == hi.y) &&
     838         274 :                     (K == lo.z || K == hi.z)) // X edge
     839        1370 :                     cdata(I, J, K) = fdata(i - 1, j, k) * 0.25 + fdata(i, j, k) * 0.5 + fdata(i + 1, j, k) * 0.25;
     840        2560 :                 else if ((K == lo.z || K == hi.z) &&
     841        2560 :                     (I == lo.x || I == hi.x)) // Y edge
     842        1070 :                     cdata(I, J, K) = fdata(i, j - 1, k) * 0.25 + fdata(i, j, k) * 0.5 + fdata(i, j + 1, k) * 0.25;
     843        2346 :                 else if ((I == lo.x || I == hi.x) &&
     844           0 :                     (J == lo.y || J == hi.y)) // Z edge
     845           0 :                     cdata(I, J, K) = fdata(i, j, k - 1) * 0.25 + fdata(i, j, k) * 0.5 + fdata(i, j, k + 1) * 0.25;
     846        2346 :                 else if (I == lo.x || I == hi.x) // X face
     847           0 :                     cdata(I, J, K) =
     848           0 :                     (fdata(i, j - 1, k - 1) + fdata(i, j, k - 1) * 2.0 + fdata(i, j + 1, k - 1)
     849           0 :                         + fdata(i, j - 1, k) * 2.0 + fdata(i, j, k) * 4.0 + fdata(i, j + 1, k) * 2.0
     850           0 :                         + fdata(i, j - 1, k + 1) + fdata(i, j, k + 1) * 2.0 + fdata(i, j + 1, k + 1)) / 16.0;
     851        2346 :                 else if (J == lo.y || J == hi.y) // Y face
     852           0 :                     cdata(I, J, K) =
     853           0 :                     (fdata(i - 1, j, k - 1) + fdata(i - 1, j, k) * 2.0 + fdata(i - 1, j, k + 1)
     854           0 :                         + fdata(i, j, k - 1) * 2.0 + fdata(i, j, k) * 4.0 + fdata(i, j, k + 1) * 2.0
     855           0 :                         + fdata(i + 1, j, k - 1) + fdata(i + 1, j, k) * 2.0 + fdata(i + 1, j, k + 1)) / 16.0;
     856        2346 :                 else if (K == lo.z || K == hi.z) // Z face
     857        2346 :                     cdata(I, J, K) =
     858        7038 :                     (fdata(i - 1, j - 1, k) + fdata(i, j - 1, k) * 2.0 + fdata(i + 1, j - 1, k)
     859        7038 :                         + fdata(i - 1, j, k) * 2.0 + fdata(i, j, k) * 4.0 + fdata(i + 1, j, k) * 2.0
     860        9384 :                         + fdata(i - 1, j + 1, k) + fdata(i, j + 1, k) * 2.0 + fdata(i + 1, j + 1, k)) / 16.0;
     861             :                 else // Interior
     862           0 :                     cdata(I, J, K) =
     863           0 :                     (fdata(i - 1, j - 1, k - 1) + fdata(i - 1, j - 1, k + 1) + fdata(i - 1, j + 1, k - 1) + fdata(i - 1, j + 1, k + 1) +
     864           0 :                         fdata(i + 1, j - 1, k - 1) + fdata(i + 1, j - 1, k + 1) + fdata(i + 1, j + 1, k - 1) + fdata(i + 1, j + 1, k + 1)) / 64.0
     865           0 :                     +
     866           0 :                     (fdata(i, j - 1, k - 1) + fdata(i, j - 1, k + 1) + fdata(i, j + 1, k - 1) + fdata(i, j + 1, k + 1) +
     867           0 :                         fdata(i - 1, j, k - 1) + fdata(i + 1, j, k - 1) + fdata(i - 1, j, k + 1) + fdata(i + 1, j, k + 1) +
     868           0 :                         fdata(i - 1, j - 1, k) + fdata(i - 1, j + 1, k) + fdata(i + 1, j - 1, k) + fdata(i + 1, j + 1, k)) / 32.0
     869           0 :                     +
     870           0 :                     (fdata(i - 1, j, k) + fdata(i, j - 1, k) + fdata(i, j, k - 1) +
     871           0 :                         fdata(i + 1, j, k) + fdata(i, j + 1, k) + fdata(i, j, k + 1)) / 16.0
     872           0 :                     +
     873           0 :                     fdata(i, j, k) / 8.0;
     874             :             });
     875             :         }
     876          46 :         FillBoundaryCoeff(crse_psi, m_geom[amrlev][mglev]);
     877             : 
     878             :     }
     879         426 : }
     880             : 
     881             : template<int SYM>
     882             : void
     883        1454 : Elastic<SYM>::FillBoundaryCoeff(MultiTab& sigma, const Geometry& geom)
     884             : {
     885             :     BL_PROFILE("Elastic::FillBoundaryCoeff()");
     886        4362 :     for (int i = 0; i < 2; i++)
     887             :     {
     888        2908 :         MultiTab& mf = sigma;
     889        2908 :         mf.FillBoundary(geom.periodicity());
     890        2908 :         const int ncomp = mf.nComp();
     891        2908 :         const int ng1 = 1;
     892        2908 :         const int ng2 = 2;
     893        5816 :         MultiTab tmpmf(mf.boxArray(), mf.DistributionMap(), ncomp, ng1);
     894        2908 :         tmpmf.ParallelCopy(mf, 0, 0, ncomp, ng2, ng1, geom.periodicity());
     895        2908 :         mf.ParallelCopy(tmpmf, 0, 0, ncomp, ng1, ng2, geom.periodicity());
     896             :     }
     897        1454 : }
     898             : 
     899             : template<int SYM>
     900             : void
     901        1009 : Elastic<SYM>::FillBoundaryCoeff(MultiFab& psi, const Geometry& geom)
     902             : {
     903             :     BL_PROFILE("Elastic::FillBoundaryCoeff()");
     904        3027 :     for (int i = 0; i < 2; i++)
     905             :     {
     906        2018 :         MultiFab& mf = psi;
     907        2018 :         mf.FillBoundary(geom.periodicity());
     908        2018 :         const int ncomp = mf.nComp();
     909        2018 :         const int ng1 = 1;
     910        2018 :         const int ng2 = 2;
     911        4036 :         MultiFab tmpmf(mf.boxArray(), mf.DistributionMap(), ncomp, ng1);
     912        2018 :         tmpmf.ParallelCopy(mf, 0, 0, ncomp, ng2, ng1, geom.periodicity());
     913        2018 :         mf.ParallelCopy(tmpmf, 0, 0, ncomp, ng1, ng2, geom.periodicity());
     914             :     }
     915        1009 : }
     916             : 
     917             : template class Elastic<Set::Sym::Major>;
     918             : template class Elastic<Set::Sym::Isotropic>;
     919             : template class Elastic<Set::Sym::MajorMinor>;
     920             : template class Elastic<Set::Sym::Diagonal>;
     921             : 
     922             : }

Generated by: LCOV version 1.14