LCOV - code coverage report
Current view: top level - src/Solver/Nonlocal - Newton.H (source / functions) Hit Total Coverage
Test: coverage_merged.info Lines: 145 268 54.1 %
Date: 2024-11-18 05:28:54 Functions: 71 225 31.6 %

          Line data    Source code
       1             : #ifndef SOLVER_NONLOCAL_NEWTON
       2             : #define SOLVER_NONLOCAL_NEWTON
       3             : 
       4             : #include "Set/Set.H"
       5             : #include "Operator/Elastic.H"
       6             : #include "Solver/Nonlocal/Linear.H"
       7             : #include "IO/ParmParse.H"
       8             : #include "Numeric/Stencil.H"
       9             : 
      10             : namespace Solver
      11             : {
      12             : namespace Nonlocal
      13             : {
      14             : template <typename T>
      15             : class Newton: public Linear
      16             : {
      17             : public:
      18          25 :     Newton() {};
      19             : 
      20           0 :     Newton(Operator::Elastic<T::sym>& a_op)
      21           0 :     {
      22           0 :         this->Define(a_op);
      23           0 :     };
      24             : 
      25          25 :     ~Newton()
      26             :     {
      27          25 :         if (m_defined) Clear();
      28          25 :     }
      29             : 
      30         426 :     void Define(Operator::Elastic<T::sym>& a_op)
      31             :     {
      32         426 :         Linear::Define(a_op);
      33         426 :         m_elastic = dynamic_cast<Operator::Elastic<T::sym> *>(linop);
      34             :         //m_bc = &m_elastic->GetBC();
      35         426 :     }
      36         426 :     void Clear()
      37             :     {
      38         426 :         Linear::Clear();
      39         426 :         m_elastic = nullptr;
      40             :         //m_bc = nullptr;
      41         426 :     }
      42             : 
      43             : 
      44             :     void setNRIters(int a_nriters) { m_nriters = a_nriters; }
      45             : 
      46          14 :     void setPsi(Set::Field<Set::Scalar>& a_psi)
      47             :     {
      48          14 :         m_psi = &a_psi;
      49          14 :     }
      50             : 
      51             : private:
      52           0 :     void prepareForSolve(const Set::Field<Set::Scalar>& a_u_mf,
      53             :         const Set::Field<Set::Scalar>& a_b_mf,
      54             :         Set::Field<Set::Scalar>& a_rhs_mf,
      55             :         Set::Field<Set::Matrix>& a_dw_mf,
      56             :         Set::Field<Set::Matrix4<AMREX_SPACEDIM, T::sym>>& a_ddw_mf,
      57             :         Set::Field<T>& a_model_mf)
      58             :     {
      59           0 :         for (int lev = 0; lev <= a_b_mf.finest_level; ++lev)
      60             :         {
      61           0 :             amrex::Box domain(linop->Geom(lev).Domain());
      62           0 :             domain.convert(amrex::IntVect::TheNodeVector());
      63           0 :             const Set::Scalar* dx = linop->Geom(lev).CellSize();
      64           0 :             Set::Vector DX(linop->Geom(lev).CellSize());
      65           0 :             for (MFIter mfi(*a_model_mf[lev], false); mfi.isValid(); ++mfi)
      66             :             {
      67           0 :                 amrex::Box bx = mfi.grownnodaltilebox();
      68           0 :                 bx = bx & domain;
      69             : 
      70           0 :                 amrex::Array4<const T>           const& model = a_model_mf[lev]->array(mfi);
      71           0 :                 amrex::Array4<const Set::Scalar> const& u = a_u_mf[lev]->array(mfi);
      72           0 :                 amrex::Array4<Set::Matrix>       const& dw = a_dw_mf[lev]->array(mfi);
      73           0 :                 amrex::Array4<Set::Matrix4<AMREX_SPACEDIM, T::sym>>  const& ddw = a_ddw_mf[lev]->array(mfi);
      74             : 
      75             :                 // Set model internal dw and ddw.
      76           0 :                 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
      77           0 :                     auto sten = Numeric::GetStencil(i, j, k, bx);
      78             : 
      79           0 :                     Set::Matrix gradu = Numeric::Gradient(u, i, j, k, dx, sten);
      80             : 
      81           0 :                     if (model(i, j, k).kinvar == Model::Solid::KinematicVariable::gradu)
      82             :                     {
      83           0 :                         dw(i, j, k) = model(i, j, k).DW(gradu);
      84           0 :                         ddw(i, j, k) = model(i, j, k).DDW(gradu);
      85             :                     }
      86           0 :                     else if (model(i, j, k).kinvar == Model::Solid::KinematicVariable::epsilon)
      87             :                     {
      88           0 :                         Set::Matrix eps = 0.5 * (gradu + gradu.transpose());
      89           0 :                         dw(i, j, k) = model(i, j, k).DW(eps);
      90           0 :                         ddw(i, j, k) = model(i, j, k).DDW(eps);
      91             :                     }
      92           0 :                     else if (model(i, j, k).kinvar == Model::Solid::KinematicVariable::F)
      93             :                     {
      94           0 :                         Set::Matrix F = gradu + Set::Matrix::Identity();
      95           0 :                         dw(i, j, k) = model(i, j, k).DW(F);
      96           0 :                         ddw(i, j, k) = model(i, j, k).DDW(F);
      97             :                     }
      98             :                 });
      99             :             }
     100             : 
     101           0 :             Util::RealFillBoundary(*a_dw_mf[lev], m_elastic->Geom(lev));
     102           0 :             Util::RealFillBoundary(*a_ddw_mf[lev], m_elastic->Geom(lev));
     103             :         }
     104             : 
     105           0 :         m_elastic->SetModel(a_ddw_mf);
     106             : 
     107           0 :         for (int lev = 0; lev <= a_b_mf.finest_level; ++lev)
     108             :         {
     109           0 :             amrex::Box domain(linop->Geom(lev).Domain());
     110           0 :             domain.convert(amrex::IntVect::TheNodeVector());
     111           0 :             const Set::Scalar* dx = linop->Geom(lev).CellSize();
     112           0 :             const amrex::Dim3 lo = amrex::lbound(domain), hi = amrex::ubound(domain);
     113           0 :             for (MFIter mfi(*a_model_mf[lev], false); mfi.isValid(); ++mfi)
     114             :             {
     115           0 :                 amrex::Box bx = mfi.nodaltilebox();
     116           0 :                 bx = bx & domain;
     117           0 :                 amrex::Array4<const Set::Scalar>  const& u = a_u_mf[lev]->array(mfi);
     118           0 :                 amrex::Array4<const Set::Scalar>  const& b = a_b_mf[lev]->array(mfi);
     119           0 :                 amrex::Array4<const Set::Matrix>  const& dw = a_dw_mf[lev]->array(mfi);
     120           0 :                 amrex::Array4<Set::Scalar>        const& rhs = a_rhs_mf[lev]->array(mfi);
     121           0 :                 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
     122             :                 {
     123           0 :                     auto sten = Numeric::GetStencil(i, j, k, bx);
     124             :                     // Do this if on the domain boundary
     125           0 :                     if (AMREX_D_TERM(i == lo.x || i == hi.x, || j == lo.y || j == hi.y, || k == lo.z || k == hi.z))
     126             :                     {
     127           0 :                         Set::Matrix gradu = Numeric::Gradient(u, i, j, k, dx, sten);
     128           0 :                         Set::Vector U(AMREX_D_DECL(u(i, j, k, 0), u(i, j, k, 1), u(i, j, k, 2)));
     129           0 :                         Set::Vector ret = m_elastic->GetBC()(U, gradu, dw(i, j, k), i, j, k, bx);
     130           0 :                         for (int d = 0; d < AMREX_SPACEDIM; d++) rhs(i, j, k, d) = b(i, j, k, d) - ret(d);
     131             :                     }
     132             :                     else
     133             :                     {
     134           0 :                         Set::Vector divdw = Numeric::Divergence(dw, i, j, k, dx);
     135           0 :                         for (int p = 0; p < AMREX_SPACEDIM; p++) rhs(i, j, k, p) = b(i, j, k, p) - divdw(p);
     136             :                     }
     137             :                 });
     138             :             }
     139           0 :             Util::RealFillBoundary(*a_ddw_mf[lev], m_elastic->Geom(lev));
     140           0 :             Util::RealFillBoundary(*a_rhs_mf[lev], m_elastic->Geom(lev));
     141             :         }
     142           0 :     }
     143             : 
     144        1326 :     void prepareForSolve(const Set::Field<Set::Vector>& a_u_mf,
     145             :         const Set::Field<Set::Vector>& a_b_mf,
     146             :         Set::Field<Set::Scalar>& a_rhs_mf,
     147             :         Set::Field<Set::Matrix>& a_dw_mf,
     148             :         Set::Field<Set::Matrix4<AMREX_SPACEDIM, T::sym>>& a_ddw_mf,
     149             :         Set::Field<T>& a_model_mf)
     150             :     {
     151        2698 :         for (int lev = 0; lev <= a_b_mf.finest_level; ++lev)
     152             :         {
     153        1372 :             amrex::Box domain(linop->Geom(lev).Domain());
     154        1372 :             domain.convert(amrex::IntVect::TheNodeVector());
     155        1372 :             const Set::Scalar* dx = linop->Geom(lev).CellSize();
     156        1372 :             Set::Vector DX(linop->Geom(lev).CellSize());
     157        2877 :             for (MFIter mfi(*a_model_mf[lev], false); mfi.isValid(); ++mfi)
     158             :             {
     159        1505 :                 amrex::Box bx = mfi.grownnodaltilebox();
     160        1505 :                 bx = bx & domain;
     161             : 
     162        1505 :                 amrex::Array4<const T>           const& model = a_model_mf[lev]->array(mfi);
     163        1505 :                 amrex::Array4<const Set::Vector> const& u = a_u_mf[lev]->array(mfi);
     164        1505 :                 amrex::Array4<Set::Matrix>       const& dw = a_dw_mf[lev]->array(mfi);
     165        1505 :                 amrex::Array4<Set::Matrix4<AMREX_SPACEDIM, T::sym>>  const& ddw = a_ddw_mf[lev]->array(mfi);
     166             : 
     167             :                 // Set model internal dw and ddw.
     168      617906 :                 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
     169             :                 {
     170      209757 :                     auto sten = Numeric::GetStencil(i, j, k, bx);
     171             : 
     172      209757 :                     Set::Matrix gradu = Numeric::Gradient(u, i, j, k, dx, sten);
     173      209757 :                     Set::Matrix kinvar;
     174      419514 :                     if (model(i, j, k).kinvar == Model::Solid::KinematicVariable::gradu)
     175      138723 :                         kinvar = gradu; // gradu
     176      142068 :                     else if (model(i, j, k).kinvar == Model::Solid::KinematicVariable::epsilon)
     177           0 :                         kinvar = 0.5 * (gradu + gradu.transpose()); // epsilon
     178      142068 :                     else if (model(i, j, k).kinvar == Model::Solid::KinematicVariable::F)
     179       71034 :                         kinvar = gradu + Set::Matrix::Identity(); // F
     180             : 
     181      629271 :                     dw(i, j, k) = model(i, j, k).DW(kinvar);
     182      629271 :                     ddw(i, j, k) = model(i, j, k).DDW(kinvar);
     183             : 
     184             :                 });
     185             :             }
     186             : 
     187        1372 :             Util::RealFillBoundary(*a_dw_mf[lev], m_elastic->Geom(lev));
     188        1372 :             Util::RealFillBoundary(*a_ddw_mf[lev], m_elastic->Geom(lev));
     189             :         }
     190             : 
     191        1326 :         m_elastic->SetModel(a_ddw_mf);
     192        1326 :         if (m_psi)
     193          58 :             for (int i = 0; i <= a_b_mf.finest_level; i++)
     194          44 :                 m_elastic->SetPsi(i, *(*m_psi)[i]);
     195             : 
     196             : 
     197        2698 :         for (int lev = 0; lev <= a_b_mf.finest_level; ++lev)
     198             :         {
     199        1372 :             amrex::Box domain(linop->Geom(lev).Domain());
     200        1372 :             domain.convert(amrex::IntVect::TheNodeVector());
     201        1372 :             const Set::Scalar* dx = linop->Geom(lev).CellSize();
     202        1372 :             const amrex::Dim3 lo = amrex::lbound(domain), hi = amrex::ubound(domain);
     203        2877 :             for (MFIter mfi(*a_model_mf[lev], false); mfi.isValid(); ++mfi)
     204             :             {
     205        1505 :                 amrex::Box bx = mfi.grownnodaltilebox() & domain;
     206        1505 :                 amrex::Array4<const Set::Vector>  const& u = a_u_mf[lev]->array(mfi);
     207        1505 :                 amrex::Array4<const Set::Vector>  const& b = a_b_mf[lev]->array(mfi);
     208        1505 :                 amrex::Array4<const Set::Matrix>  const& dw = a_dw_mf[lev]->array(mfi);
     209        1505 :                 amrex::Array4<Set::Scalar>        const& rhs = a_rhs_mf[lev]->array(mfi);
     210             : 
     211             :                 // This is for if psi is not being used and has not been set
     212        1505 :                 if (m_psi == nullptr)
     213             :                 {
     214      122666 :                     amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
     215             :                     {
     216      121275 :                         auto sten = Numeric::GetStencil(i, j, k, bx);
     217             :                         // Do this if on the domain boundary
     218      121275 :                         if (AMREX_D_TERM(i == lo.x || i == hi.x, || j == lo.y || j == hi.y, || k == lo.z || k == hi.z))
     219             :                         {
     220       46805 :                             Set::Matrix gradu = Numeric::Gradient(u, i, j, k, dx, sten);
     221      140415 :                             Set::Vector ret = m_elastic->GetBC()(u(i, j, k), gradu, dw(i, j, k), i, j, k, bx);
     222      292825 :                             for (int d = 0; d < AMREX_SPACEDIM; d++) rhs(i, j, k, d) = b(i, j, k)(d) - ret(d);
     223             :                         }
     224             :                         else
     225             :                         {
     226       74470 :                             Set::Vector divdw = Numeric::Divergence(dw, i, j, k, dx, sten);
     227      388550 :                             for (int d = 0; d < AMREX_SPACEDIM; d++) rhs(i, j, k, d) = b(i, j, k)(d) - divdw(d);
     228             :                         }
     229             :                     });
     230             :                 }
     231             :                 // This is EXACTLY THE SAME AS THE ABOVE, excpet that we are now accounting
     232             :                 // for psi terms. The reason we do this is because there's no good way (yet) to 
     233             :                 // initialize patches if psi = nullptr
     234             :                 else
     235             :                 {
     236         114 :                     const amrex::Dim3 boxlo = amrex::lbound(bx), boxhi = amrex::ubound(bx);
     237         114 :                     amrex::Array4<const Set::Scalar>  const& psi = (*m_psi)[lev]->array(mfi);
     238       88596 :                     amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
     239             :                     {
     240       88482 :                         auto sten = Numeric::GetStencil(i, j, k, bx);
     241             :                         // Do this if on the domain boundary
     242       88482 :                         if (AMREX_D_TERM(i == lo.x || i == hi.x, || j == lo.y || j == hi.y, || k == lo.z || k == hi.z))
     243             :                         {
     244        2560 :                             Set::Matrix gradu = Numeric::Gradient(u, i, j, k, dx, sten);
     245        2560 :                             Set::Scalar psiavg = 1.0;
     246        2560 :                             if (AMREX_D_TERM(i > boxlo.x && i<boxhi.x, && j>boxlo.y && j<boxhi.y, && k>boxlo.z && k < boxhi.z))
     247             :                             {
     248           0 :                                 psiavg = Numeric::Interpolate::CellToNodeAverage(psi, i, j, k, 0);
     249             :                             }
     250        7680 :                             Set::Vector ret = m_elastic->GetBC()(u(i, j, k), gradu, dw(i, j, k) * psiavg, i, j, k, bx);
     251       12800 :                             for (int d = 0; d < AMREX_SPACEDIM; d++) rhs(i, j, k, d) = b(i, j, k)(d) - ret(d);
     252             :                         }
     253             :                         else
     254             :                         {
     255       85922 :                             Set::Vector divdw = Numeric::Divergence(dw, i, j, k, dx, sten);
     256       85922 :                             if (AMREX_D_TERM(i > boxlo.x && i<boxhi.x, && j>boxlo.y && j<boxhi.y, && k>boxlo.z && k < boxhi.z))
     257             :                             {
     258      153860 :                                 divdw *= Numeric::Interpolate::CellToNodeAverage(psi, i, j, k, 0);
     259       76930 :                                 Set::Vector gradpsi = Numeric::CellGradientOnNode(psi, i, j, k, 0, dx);
     260      153860 :                                 divdw += dw(i, j, k) * gradpsi;
     261             :                             }
     262      429610 :                             for (int d = 0; d < AMREX_SPACEDIM; d++) rhs(i, j, k, d) = b(i, j, k)(d) - divdw(d);
     263             :                         }
     264             :                     });
     265             :                 }
     266             :             }
     267             : 
     268        1372 :             Util::RealFillBoundary(*a_ddw_mf[lev], m_elastic->Geom(lev));
     269        1372 :             Util::RealFillBoundary(*a_rhs_mf[lev], m_elastic->Geom(lev));
     270             :         }
     271        1326 :     }
     272             : 
     273             : 
     274             : public:
     275         426 :     Set::Scalar solve(const Set::Field<Set::Vector>& a_u_mf,
     276             :         const Set::Field<Set::Vector>& a_b_mf,
     277             :         Set::Field<T>& a_model_mf,
     278             :         Real a_tol_rel, Real a_tol_abs, const char* checkpoint_file = nullptr)
     279             :     {
     280         852 :         Set::Field<Set::Scalar> dsol_mf, rhs_mf;
     281         852 :         Set::Field<Set::Matrix> dw_mf;
     282         852 :         Set::Field<Set::Matrix4<AMREX_SPACEDIM, T::sym>> ddw_mf;
     283             : 
     284         426 :         dsol_mf.resize(a_u_mf.finest_level + 1); dsol_mf.finest_level = a_u_mf.finest_level;
     285         426 :         dw_mf.resize(a_u_mf.finest_level + 1); dw_mf.finest_level = a_u_mf.finest_level;
     286         426 :         ddw_mf.resize(a_u_mf.finest_level + 1); ddw_mf.finest_level = a_u_mf.finest_level;
     287         426 :         rhs_mf.resize(a_u_mf.finest_level + 1); rhs_mf.finest_level = a_u_mf.finest_level;
     288         898 :         for (int lev = 0; lev <= a_u_mf.finest_level; lev++)
     289             :         {
     290         944 :             dsol_mf.Define(lev, a_u_mf[lev]->boxArray(),
     291         472 :                 a_u_mf[lev]->DistributionMap(),
     292             :                 a_u_mf.NComp(),
     293         472 :                 a_u_mf[lev]->nGrow());
     294         944 :             dw_mf.Define(lev, a_b_mf[lev]->boxArray(),
     295         472 :                 a_b_mf[lev]->DistributionMap(),
     296             :                 1,
     297         472 :                 a_b_mf[lev]->nGrow());
     298         944 :             ddw_mf.Define(lev, a_b_mf[lev]->boxArray(),
     299         472 :                 a_b_mf[lev]->DistributionMap(),
     300             :                 1,
     301         472 :                 a_b_mf[lev]->nGrow());
     302         944 :             rhs_mf.Define(lev, a_b_mf[lev]->boxArray(),
     303         472 :                 a_b_mf[lev]->DistributionMap(),
     304             :                 a_b_mf.NComp(),
     305         472 :                 a_b_mf[lev]->nGrow());
     306             : 
     307         472 :             dsol_mf[lev]->setVal(0.0);
     308         472 :             dw_mf[lev]->setVal(Set::Matrix::Zero());
     309         472 :             ddw_mf[lev]->setVal(Set::Matrix4<AMREX_SPACEDIM, T::sym>::Zero());
     310             : 
     311         472 :             a_b_mf.Copy(lev, *rhs_mf[lev], 0, 2);
     312             :             //amrex::MultiFab::Copy(*rhs_mf[lev], *a_b_mf[lev], 0, 0, AMREX_SPACEDIM, 2);
     313             :         }
     314             : 
     315        1750 :         for (int nriter = 0; nriter < m_nriters; nriter++)
     316             :         {
     317        1326 :             if (verbose > 0 && nriter < m_nriters) Util::Message(INFO, "Newton Iteration ", nriter + 1, " of ", m_nriters);
     318             : 
     319        1326 :             prepareForSolve(a_u_mf, a_b_mf, rhs_mf, dw_mf, ddw_mf, a_model_mf);
     320             : 
     321             : 
     322        1326 :             if (nriter == m_nriters) break;
     323             : 
     324        1326 :             Solver::Nonlocal::Linear::solve(dsol_mf, rhs_mf, a_tol_rel, a_tol_abs, checkpoint_file);
     325             : 
     326        1326 :             Set::Scalar cornorm = 0, solnorm = 0;
     327        2698 :             for (int lev = 0; lev < dsol_mf.size(); ++lev)
     328             :             {
     329        4416 :                 for (int comp = 0; comp < AMREX_SPACEDIM; comp++)
     330             :                 {
     331        3044 :                     Set::Scalar tmpcornorm = dsol_mf[lev]->norm0(comp, 0);
     332        3044 :                     if (tmpcornorm > cornorm) cornorm = tmpcornorm;
     333             : 
     334             :                     //Set::Scalar tmpsolnorm = a_u_mf[lev]->norm0(comp,0);
     335             :                     //if (tmpsolnorm > solnorm) solnorm = tmpsolnorm;
     336             :                 }
     337             : 
     338             :             }
     339             :             Set::Scalar relnorm;
     340        1326 :             if (solnorm == 0) relnorm = cornorm;
     341           0 :             else relnorm = cornorm / solnorm;
     342        1326 :             if (verbose > 0) Util::Message(INFO, "NR iteration ", nriter + 1, ", relative norm(ddisp) = ", relnorm);
     343             : 
     344        2698 :             for (int lev = 0; lev < dsol_mf.size(); ++lev)
     345        1372 :                 a_u_mf.AddFrom(lev, *dsol_mf[lev], 0, 2);
     346             :             //amrex::MultiFab::Add(*a_u_mf[lev], *dsol_mf[lev], 0, 0, AMREX_SPACEDIM, 2);
     347             : 
     348        1326 :             if (relnorm < m_nrtolerance)
     349           2 :                 return relnorm;
     350             : 
     351             :         }
     352             : 
     353         424 :         return 0.0;
     354             :     }
     355             : 
     356           0 :     Set::Scalar solve(const Set::Field<Set::Scalar>& a_u_mf,
     357             :         const Set::Field<Set::Scalar>& a_b_mf,
     358             :         Set::Field<T>& a_model_mf,
     359             :         Real a_tol_rel, Real a_tol_abs, const char* checkpoint_file = nullptr)
     360             :     {
     361           0 :         Set::Field<Set::Scalar> dsol_mf, rhs_mf;
     362           0 :         Set::Field<Set::Matrix> dw_mf;
     363           0 :         Set::Field<Set::Matrix4<AMREX_SPACEDIM, T::sym>> ddw_mf;
     364             : 
     365           0 :         dsol_mf.resize(a_u_mf.finest_level + 1); dsol_mf.finest_level = a_u_mf.finest_level;
     366           0 :         dw_mf.resize(a_u_mf.finest_level + 1); dw_mf.finest_level = a_u_mf.finest_level;
     367           0 :         ddw_mf.resize(a_u_mf.finest_level + 1); ddw_mf.finest_level = a_u_mf.finest_level;
     368           0 :         rhs_mf.resize(a_u_mf.finest_level + 1); rhs_mf.finest_level = a_u_mf.finest_level;
     369           0 :         for (int lev = 0; lev <= a_u_mf.finest_level; lev++)
     370             :         {
     371           0 :             dsol_mf.Define(lev, a_u_mf[lev]->boxArray(),
     372           0 :                 a_u_mf[lev]->DistributionMap(),
     373           0 :                 a_u_mf[lev]->nComp(),
     374           0 :                 a_u_mf[lev]->nGrow());
     375           0 :             dw_mf.Define(lev, a_b_mf[lev]->boxArray(),
     376           0 :                 a_b_mf[lev]->DistributionMap(),
     377             :                 1,
     378           0 :                 a_b_mf[lev]->nGrow());
     379           0 :             ddw_mf.Define(lev, a_b_mf[lev]->boxArray(),
     380           0 :                 a_b_mf[lev]->DistributionMap(),
     381             :                 1,
     382           0 :                 a_b_mf[lev]->nGrow());
     383           0 :             rhs_mf.Define(lev, a_b_mf[lev]->boxArray(),
     384           0 :                 a_b_mf[lev]->DistributionMap(),
     385           0 :                 a_b_mf[lev]->nComp(),
     386           0 :                 a_b_mf[lev]->nGrow());
     387             : 
     388           0 :             dsol_mf[lev]->setVal(0.0);
     389           0 :             dw_mf[lev]->setVal(Set::Matrix::Zero());
     390           0 :             ddw_mf[lev]->setVal(Set::Matrix4<AMREX_SPACEDIM, T::sym>::Zero());
     391             : 
     392           0 :             amrex::MultiFab::Copy(*rhs_mf[lev], *a_b_mf[lev], 0, 0, AMREX_SPACEDIM, 2);
     393             :         }
     394             : 
     395           0 :         for (int nriter = 0; nriter < m_nriters; nriter++)
     396             :         {
     397           0 :             if (verbose > 0 && nriter < m_nriters) Util::Message(INFO, "Newton Iteration ", nriter + 1, " of ", m_nriters);
     398             : 
     399           0 :             prepareForSolve(a_u_mf, a_b_mf, rhs_mf, dw_mf, ddw_mf, a_model_mf);
     400             : 
     401             : 
     402           0 :             if (nriter == m_nriters) break;
     403             : 
     404           0 :             Solver::Nonlocal::Linear::solve(dsol_mf, rhs_mf, a_tol_rel, a_tol_abs, checkpoint_file);
     405             :             //Solver::Nonlocal::Linear::solve(GetVecOfPtrs(dsol_mf), GetVecOfConstPtrs(rhs_mf), a_tol_rel, a_tol_abs,checkpoint_file);
     406             : 
     407           0 :             Set::Scalar cornorm = 0, solnorm = 0;
     408           0 :             for (int lev = 0; lev < dsol_mf.size(); ++lev)
     409             :             {
     410           0 :                 for (int comp = 0; comp < AMREX_SPACEDIM; comp++)
     411             :                 {
     412           0 :                     Set::Scalar tmpcornorm = dsol_mf[lev]->norm0(comp, 0);
     413           0 :                     if (tmpcornorm > cornorm) cornorm = tmpcornorm;
     414             : 
     415           0 :                     Set::Scalar tmpsolnorm = a_u_mf[lev]->norm0(comp, 0);
     416           0 :                     if (tmpsolnorm > solnorm) solnorm = tmpsolnorm;
     417             :                 }
     418             : 
     419             :             }
     420             :             Set::Scalar relnorm;
     421           0 :             if (solnorm == 0) relnorm = cornorm;
     422           0 :             else relnorm = cornorm / solnorm;
     423           0 :             if (verbose > 0) Util::Message(INFO, "NR iteration ", nriter + 1, ", relative norm(ddisp) = ", relnorm);
     424             : 
     425           0 :             for (int lev = 0; lev < dsol_mf.size(); ++lev)
     426           0 :                 amrex::MultiFab::Add(*a_u_mf[lev], *dsol_mf[lev], 0, 0, AMREX_SPACEDIM, 2);
     427             : 
     428           0 :             if (relnorm < m_nrtolerance)
     429           0 :                 return relnorm;
     430             : 
     431             :         }
     432             : 
     433           0 :         return 0.0;
     434             :     }
     435             :     Set::Scalar solve(const Set::Field<Set::Scalar>& a_u_mf,
     436             :         const Set::Field<Set::Scalar>& a_b_mf,
     437             :         Set::Field<T>& a_model_mf)
     438             :     {
     439             :         return solve(a_u_mf, a_b_mf, a_model_mf, tol_rel, tol_abs);
     440             :     }
     441             : 
     442           0 :     void compResidual(Set::Field<Set::Scalar>& a_res_mf,
     443             :         Set::Field<Set::Scalar>& a_u_mf,
     444             :         Set::Field<Set::Scalar>& a_b_mf,
     445             :         Set::Field<T>& a_model_mf)
     446             :     {
     447           0 :         Set::Field<Set::Matrix> dw_mf;
     448           0 :         Set::Field<Set::Matrix4<AMREX_SPACEDIM, T::sym>> ddw_mf;
     449           0 :         dw_mf.resize(a_u_mf.size());
     450           0 :         ddw_mf.resize(a_u_mf.size());
     451           0 :         for (int lev = 0; lev < a_u_mf.size(); lev++)
     452             :         {
     453           0 :             dw_mf.Define(lev, a_b_mf[lev]->boxArray(),
     454           0 :                 a_b_mf[lev]->DistributionMap(),
     455           0 :                 1, a_b_mf[lev]->nGrow());
     456           0 :             ddw_mf.Define(lev, a_b_mf[lev]->boxArray(),
     457           0 :                 a_b_mf[lev]->DistributionMap(),
     458           0 :                 1, a_b_mf[lev]->nGrow());
     459           0 :             dw_mf[lev]->setVal(Set::Matrix::Zero());
     460             :         }
     461             : 
     462           0 :         prepareForSolve(a_u_mf, a_b_mf, a_res_mf, dw_mf, ddw_mf, a_model_mf);
     463           0 :     }
     464             : 
     465             :     void compResidual(Set::Field<Set::Vector>& a_res_mf,
     466             :         Set::Field<Set::Vector>& a_u_mf,
     467             :         Set::Field<Set::Vector>& a_b_mf,
     468             :         Set::Field<T>& a_model_mf)
     469             :     {
     470             :         Set::Field<Set::Matrix> dw_mf;
     471             :         Set::Field<Set::Matrix4<AMREX_SPACEDIM, T::sym>> ddw_mf;
     472             :         Set::Field<Set::Scalar> res_mf(a_res_mf.size());
     473             :         dw_mf.resize(a_u_mf.size());
     474             :         ddw_mf.resize(a_u_mf.size());
     475             :         res_mf.resize(a_u_mf.size());
     476             :         for (int lev = 0; lev < a_u_mf.size(); lev++)
     477             :         {
     478             :             dw_mf.Define(lev, a_b_mf[lev]->boxArray(),
     479             :                 a_b_mf[lev]->DistributionMap(),
     480             :                 1, a_b_mf[lev]->nGrow());
     481             :             ddw_mf.Define(lev, a_b_mf[lev]->boxArray(),
     482             :                 a_b_mf[lev]->DistributionMap(),
     483             :                 1, a_b_mf[lev]->nGrow());
     484             :             res_mf.Define(lev, a_b_mf[lev]->boxArray(),
     485             :                 a_b_mf[lev]->DistributionMap(),
     486             :                 AMREX_SPACEDIM, a_b_mf[lev]->nGrow());
     487             :             dw_mf[lev]->setVal(Set::Matrix::Zero());
     488             :         }
     489             : 
     490             :         prepareForSolve(a_u_mf, a_b_mf, res_mf, dw_mf, ddw_mf, a_model_mf);
     491             : 
     492             :         for (int lev = 0; lev < a_res_mf.size(); ++lev)
     493             :         {
     494             :             Util::RealFillBoundary(*res_mf[lev], m_elastic->Geom(lev));
     495             :             a_res_mf.CopyFrom(lev, *res_mf[lev], 0, 2);
     496             :         }
     497             :     }
     498             : 
     499           4 :     void compLinearSolverResidual(Set::Field<Set::Vector>& a_res_mf,
     500             :         Set::Field<Set::Vector>& a_u_mf,
     501             :         Set::Field<Set::Vector>& a_b_mf)
     502             :     {
     503           8 :         Util::Assert(INFO, TEST(a_res_mf.finest_level == a_u_mf.finest_level));
     504           8 :         Util::Assert(INFO, TEST(a_u_mf.finest_level == a_b_mf.finest_level));
     505           8 :         Set::Field<Set::Scalar> res_mf(a_res_mf.finest_level + 1), sol_mf(a_u_mf.finest_level + 1), rhs_mf(a_b_mf.finest_level + 1);
     506          18 :         for (int lev = 0; lev <= a_u_mf.finest_level; lev++)
     507             :         {
     508          14 :             res_mf.Define(lev, a_b_mf[lev]->boxArray(), a_b_mf[lev]->DistributionMap(), AMREX_SPACEDIM, a_b_mf[lev]->nGrow());
     509          14 :             sol_mf.Define(lev, a_b_mf[lev]->boxArray(), a_b_mf[lev]->DistributionMap(), AMREX_SPACEDIM, a_b_mf[lev]->nGrow());
     510          14 :             rhs_mf.Define(lev, a_b_mf[lev]->boxArray(), a_b_mf[lev]->DistributionMap(), AMREX_SPACEDIM, a_b_mf[lev]->nGrow());
     511             : 
     512          14 :             a_u_mf.Copy(lev, *sol_mf[lev], 0, 2);
     513          14 :             a_b_mf.Copy(lev, *rhs_mf[lev], 0, 2);
     514             :         }
     515             : 
     516           4 :         mlmg->compResidual(amrex::GetVecOfPtrs(res_mf), amrex::GetVecOfPtrs(sol_mf), amrex::GetVecOfConstPtrs(rhs_mf));
     517             : 
     518          18 :         for (int lev = 0; lev <= a_res_mf.finest_level; ++lev)
     519             :         {
     520          14 :             a_res_mf.CopyFrom(lev, *res_mf[lev], 0, 2);
     521             :         }
     522           4 :     }
     523             : 
     524             : 
     525             :     void W(Set::Field<Set::Scalar>& a_w_mf,
     526             :         Set::Field<Set::Scalar>& a_u_mf,
     527             :         Set::Field<T>& a_model_mf)
     528             :     {
     529             :         for (int lev = 0; lev < a_u_mf.size(); lev++)
     530             :         {
     531             :             BL_PROFILE("Solver::Nonlocal::Newton::DW()");
     532             : 
     533             :             const amrex::Real* DX = linop->Geom(lev).CellSize();
     534             :             amrex::Box domain(linop->Geom(lev).Domain());
     535             :             domain.convert(amrex::IntVect::TheNodeVector());
     536             : 
     537             :             for (MFIter mfi(*a_u_mf[lev], amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
     538             :             {
     539             :                 const Box& bx = mfi.tilebox();
     540             :                 amrex::Array4<T> const& C = a_model_mf[lev]->array(mfi);
     541             :                 amrex::Array4<amrex::Real> const& w = a_w_mf[lev]->array(mfi);
     542             :                 amrex::Array4<const amrex::Real> const& u = a_u_mf[lev]->array(mfi);
     543             :                 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
     544             :                 {
     545             :                     Set::Matrix gradu;
     546             : 
     547             :                     auto sten = Numeric::GetStencil(i, j, k, bx);
     548             : 
     549             :                     // Fill gradu
     550             :                     for (int p = 0; p < AMREX_SPACEDIM; p++)
     551             :                     {
     552             :                         AMREX_D_TERM(gradu(p, 0) = (Numeric::Stencil<Set::Scalar, 1, 0, 0>::D(u, i, j, k, p, DX, sten));,
     553             :                             gradu(p, 1) = (Numeric::Stencil<Set::Scalar, 0, 1, 0>::D(u, i, j, k, p, DX, sten));,
     554             :                             gradu(p, 2) = (Numeric::Stencil<Set::Scalar, 0, 0, 1>::D(u, i, j, k, p, DX, sten)););
     555             :                     }
     556             : 
     557             :                     if (C(i, j, k).kinvar == Model::Solid::KinematicVariable::gradu)
     558             :                         w(i, j, k) = C(i, j, k).W(gradu);
     559             :                     else if (C(i, j, k).kinvar == Model::Solid::KinematicVariable::epsilon)
     560             :                         w(i, j, k) = C(i, j, k).W(0.5 * (gradu + gradu.transpose()));
     561             :                     else if (C(i, j, k).kinvar == Model::Solid::KinematicVariable::F)
     562             :                         w(i, j, k) = C(i, j, k).W(gradu + Set::Matrix::Identity());
     563             :                 });
     564             :             }
     565             :         }
     566             :     }
     567             : 
     568             :     void DW(Set::Field<Set::Scalar>& a_dw_mf,
     569             :         Set::Field<Set::Scalar>& a_u_mf,
     570             :         Set::Field<T>& a_model_mf)
     571             :     {
     572             :         for (int lev = 0; lev < a_u_mf.size(); lev++)
     573             :         {
     574             :             BL_PROFILE("Solver::Nonlocal::Newton::DW()");
     575             : 
     576             :             const amrex::Real* DX = linop->Geom(lev).CellSize();
     577             :             amrex::Box domain(linop->Geom(lev).Domain());
     578             :             domain.convert(amrex::IntVect::TheNodeVector());
     579             : 
     580             :             for (MFIter mfi(*a_u_mf[lev], amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
     581             :             {
     582             :                 const Box& bx = mfi.tilebox();
     583             :                 amrex::Array4<T> const& C = a_model_mf[lev]->array(mfi);
     584             :                 amrex::Array4<amrex::Real> const& dw = a_dw_mf[lev]->array(mfi);
     585             :                 amrex::Array4<const amrex::Real> const& u = a_u_mf[lev]->array(mfi);
     586             :                 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
     587             :                 {
     588             :                     Set::Matrix gradu;
     589             : 
     590             :                     auto sten = Numeric::GetStencil(i, j, k, bx);
     591             : 
     592             :                     // Fill gradu
     593             :                     for (int p = 0; p < AMREX_SPACEDIM; p++)
     594             :                     {
     595             :                         AMREX_D_TERM(gradu(p, 0) = (Numeric::Stencil<Set::Scalar, 1, 0, 0>::D(u, i, j, k, p, DX, sten));,
     596             :                             gradu(p, 1) = (Numeric::Stencil<Set::Scalar, 0, 1, 0>::D(u, i, j, k, p, DX, sten));,
     597             :                             gradu(p, 2) = (Numeric::Stencil<Set::Scalar, 0, 0, 1>::D(u, i, j, k, p, DX, sten)););
     598             :                     }
     599             : 
     600             :                     Set::Matrix sig = Set::Matrix::Zero();
     601             : 
     602             :                     if (C(i, j, k).kinvar == Model::Solid::KinematicVariable::gradu)
     603             :                         sig = C(i, j, k).DW(gradu);
     604             :                     else if (C(i, j, k).kinvar == Model::Solid::KinematicVariable::epsilon)
     605             :                         sig = C(i, j, k).DW(0.5 * (gradu + gradu.transpose()));
     606             :                     else if (C(i, j, k).kinvar == Model::Solid::KinematicVariable::F)
     607             :                         sig = C(i, j, k).DW(gradu + Set::Matrix::Identity());
     608             : 
     609             :                     // = C(i,j,k)(gradu,m_homogeneous);
     610             : 
     611             :                     AMREX_D_PICK(dw(i, j, k, 0) = sig(0, 0);
     612             :                     ,
     613             :                         dw(i, j, k, 0) = sig(0, 0); dw(i, j, k, 1) = sig(0, 1);
     614             :                     dw(i, j, k, 2) = sig(1, 0); dw(i, j, k, 3) = sig(1, 1);
     615             :                     ,
     616             :                         dw(i, j, k, 0) = sig(0, 0); dw(i, j, k, 1) = sig(0, 1); dw(i, j, k, 2) = sig(0, 2);
     617             :                     dw(i, j, k, 3) = sig(1, 0); dw(i, j, k, 4) = sig(1, 1); dw(i, j, k, 5) = sig(1, 2);
     618             :                     dw(i, j, k, 6) = sig(2, 0); dw(i, j, k, 7) = sig(2, 1); dw(i, j, k, 8) = sig(2, 2););
     619             : 
     620             :                 });
     621             :             }
     622             :         }
     623             :     }
     624             : 
     625             : 
     626             : public:
     627             :     int m_nriters = 1;
     628             :     Set::Scalar m_nrtolerance = 0.0;
     629             :     Operator::Elastic<T::sym>* m_elastic;
     630             :     //BC::Operator::Elastic::Elastic *m_bc;
     631             : 
     632             :     Set::Field<Set::Scalar>* m_psi = nullptr;
     633             : 
     634             : public:
     635             :     // These paramters control a standard Newton-Raphson solve.
     636             :     // 
     637             :     // **Note**: 
     638             :     // This class inherits all of the linear solve paramters
     639             :     // from its parent class, :ref:`Solver::Nonlocal::Linear`
     640          19 :     static void Parse(Newton<T>& value, amrex::ParmParse& pp)
     641             :     {
     642          19 :         Linear::Parse(value, pp);
     643             : 
     644             :         // Number of newton-raphson iterations.
     645          19 :         pp_query("nriters", value.m_nriters);
     646             : 
     647             :         // Tolerance to use for newton-raphson convergence
     648          19 :         pp_query("nrtolerance", value.m_nrtolerance); 
     649          19 :     }
     650             : 
     651             : };
     652             : } // namespace Nonlocal
     653             : } // namespace Solver
     654             : 
     655             : 
     656             : #endif

Generated by: LCOV version 1.14