LCOV - code coverage report
Current view: top level - src/Integrator - TopOp.H (source / functions) Hit Total Coverage
Test: coverage_merged.info Lines: 98 103 95.1 %
Date: 2024-11-18 05:28:54 Functions: 10 10 100.0 %

          Line data    Source code
       1             : #ifndef INTEGRATOR_TOPOP_H
       2             : #define INTEGRATOR_TOPOP_H
       3             : #include <iostream>
       4             : #include <fstream>
       5             : #include <iomanip>
       6             : #include <numeric>
       7             : 
       8             : #include "AMReX.H"
       9             : #include "AMReX_ParallelDescriptor.H"
      10             : #include "AMReX_ParmParse.H"
      11             : 
      12             : #include "IO/ParmParse.H"
      13             : #include "Integrator/Base/Mechanics.H"
      14             : 
      15             : 
      16             : #include "IC/IC.H"
      17             : #include "BC/BC.H"
      18             : #include "BC/Operator/Elastic/Constant.H"
      19             : #include "BC/Operator/Elastic/TensionTest.H"
      20             : #include "BC/Operator/Elastic/Expression.H"
      21             : 
      22             : #include "IC/Ellipse.H"
      23             : #include "IC/Voronoi.H"
      24             : #include "IC/Constant.H"
      25             : #include "IC/BMP.H"
      26             : #include "BC/Constant.H"
      27             : #include "Numeric/Stencil.H"
      28             : 
      29             : #include "Model/Solid/Solid.H"
      30             : #include "Solver/Nonlocal/Linear.H"
      31             : #include "Solver/Nonlocal/Newton.H"
      32             : 
      33             : #include "Operator/Operator.H"
      34             : 
      35             : 
      36             : namespace Integrator
      37             : {
      38             : template<class MODEL>
      39             : class TopOp: virtual public Base::Mechanics<MODEL>
      40             : {
      41             : public:
      42             : 
      43             :     TopOp(): Base::Mechanics<MODEL>() {}
      44           1 :     TopOp(IO::ParmParse& pp): Base::Mechanics<MODEL>()
      45             :     {
      46           1 :         Parse(*this, pp);
      47           1 :     }
      48             : 
      49             :     // The mechanics integrator manages the solution of an elastic 
      50             :     // solve using the MLMG solver. 
      51           1 :     static void Parse(TopOp& value, IO::ParmParse& pp)
      52             :     {
      53           1 :         Base::Mechanics<MODEL>::Parse(value, pp);
      54             : 
      55           1 :         pp_queryclass("model", value.model);
      56             :         // Read in IC for psi
      57           1 :         if (pp.contains("psi.ic.type"))
      58             :         {
      59           1 :             std::string type;
      60           1 :             pp_query_validate("psi.ic.type", type, {"ellipse", "constant"}); // Read IC type for the eta field
      61           1 :             if (type == "ellipse") value.ic_psi = new IC::Ellipse(value.geom, pp, "psi.ic.ellipse");
      62           1 :             else if (type == "constant") value.ic_psi = new IC::Constant(value.geom, pp, "psi.ic.constant");
      63           0 :             else Util::Abort(INFO, "Invalid value for psi.ic.type: ", type);
      64             : 
      65           1 :             value.bc_psi = new BC::Constant(1, pp, "psi.bc");
      66           1 :             value.RegisterNewFab(value.psi_mf, value.bc_psi, 1, 2, "psi", true);
      67           1 :             value.RegisterNewFab(value.psi_old_mf, value.bc_psi, 1, 2, "psiold", false);
      68           1 :             value.psi_on = true;
      69             :         }
      70           1 :         pp_query_default("eta_ref_threshold", value.m_eta_ref_threshold, 0.01); // Refinement threshold based on eta
      71           1 :         pp_query_default("alpha", value.alpha, 1.0); // :math:`\alpha` parameter
      72           1 :         pp_query_default("beta", value.beta, 1.0); // :math:`\beta` parameter
      73           1 :         pp_query_default("gamma", value.gamma, 1.0); // :math:`\gamma` parameter
      74           1 :         pp_queryclass("L", value.L); // Mobility
      75           1 :         if (pp.contains("volume0frac"))
      76             :         {
      77           0 :             if (pp.contains("volume0")) Util::Abort(INFO, "Cannot specify volume0frac and volume0");
      78             :             Set::Scalar volumefrac;
      79           0 :             pp_query_default("volume0frac", volumefrac, 0.5); // Prescribed volume fraction
      80           0 :             value.volume0 = volumefrac *
      81           0 :                 AMREX_D_TERM((value.geom[0].ProbHi()[0] - value.geom[0].ProbLo()[0]),
      82             :                     *(value.geom[0].ProbHi()[1] - value.geom[0].ProbLo()[1]),
      83             :                     *(value.geom[0].ProbHi()[2] - value.geom[0].ProbLo()[2]));
      84             :         }
      85             :         else
      86           1 :             pp_query_default("volume0", value.volume0, 0.5); // Prescribed total vlume
      87             : 
      88           1 :         pp_queryclass("lambda", value.lambda); // Lagrange multiplier (can be interplated)
      89             : 
      90             : 
      91           1 :         value.RegisterIntegratedVariable(&value.volume, "volume");
      92           1 :         value.RegisterIntegratedVariable(&value.w_chem_potential, "chem_potential");
      93           1 :         value.RegisterIntegratedVariable(&value.w_bndry, "bndry");
      94           1 :         value.RegisterIntegratedVariable(&value.w_elastic, "elastic");
      95           1 :     }
      96             : 
      97           1 :     void Initialize(int lev) override
      98             :     {
      99           1 :         Base::Mechanics<MODEL>::Initialize(lev);
     100           1 :         if (psi_on) ic_psi->Initialize(lev, psi_mf);
     101           1 :         if (psi_on) ic_psi->Initialize(lev, psi_old_mf);
     102           1 :     }
     103             : 
     104           2 :     virtual void UpdateModel(int a_step, Set::Scalar /*a_time*/) override
     105             :     {
     106           2 :         if (m_type == Base::Mechanics<MODEL>::Type::Disable) return;
     107             : 
     108           2 :         if (a_step > 0) return;
     109             : 
     110           2 :         for (int lev = 0; lev <= finest_level; ++lev)
     111             :         {
     112           1 :             model_mf[lev]->setVal(model);
     113           1 :             Util::RealFillBoundary(*model_mf[lev], geom[lev]);
     114           1 :             Util::RealFillBoundary(*psi_mf[lev], geom[lev]);
     115           1 :             Util::RealFillBoundary(*psi_old_mf[lev], geom[lev]);
     116             :         }
     117             : 
     118             :     }
     119             : 
     120             : 
     121           6 :     void Advance(int lev, Set::Scalar time, Set::Scalar dt) override
     122             :     {
     123             :         BL_PROFILE("TopOp::Advance");
     124           6 :         Base::Mechanics<MODEL>::Advance(lev, time, dt);
     125           6 :         std::swap(psi_old_mf[lev], psi_mf[lev]);
     126           6 :         const Set::Scalar* DX = geom[lev].CellSize();
     127           6 :         amrex::Box domain = geom[lev].Domain();
     128             : 
     129           6 :         Set::Scalar Lnow = L(time);
     130           6 :         Set::Scalar lambdaT = lambda(time);
     131             : 
     132          60 :         for (amrex::MFIter mfi(*psi_mf[lev], amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
     133             :         {
     134          54 :             amrex::Box bx = mfi.tilebox();
     135          54 :             bx.grow(1);
     136          54 :             bx = bx & domain;
     137          54 :             amrex::Array4<const Set::Matrix> const& sig = (*stress_mf[lev]).array(mfi);
     138          54 :             amrex::Array4<const Set::Matrix> const& eps = (*strain_mf[lev]).array(mfi);
     139          54 :             amrex::Array4<const Set::Scalar> const& psi = (*psi_old_mf[lev]).array(mfi);
     140          54 :             amrex::Array4<Set::Scalar> const& psinew = (*psi_mf[lev]).array(mfi);
     141             : 
     142       12966 :             amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
     143             :             {
     144       12912 :                 Set::Scalar driving_force = 0.0;
     145             : 
     146       51648 :                 driving_force += alpha * 2.0 * psi(i, j, k) * (2.0 * psi(i, j, k) * psi(i, j, k) - 3.0 * psi(i, j, k) + 1.0);
     147       12912 :                 driving_force += -beta * Numeric::Laplacian(psi, i, j, k, 0, DX);
     148             : 
     149       12912 :                 Set::Matrix sig_avg = Numeric::Interpolate::NodeToCellAverage(sig, i, j, k, 0);
     150       12912 :                 Set::Matrix eps_avg = Numeric::Interpolate::NodeToCellAverage(eps, i, j, k, 0);
     151             : 
     152       12912 :                 driving_force += -gamma * 0.5 * (sig_avg.transpose() * eps_avg).trace() * psi(i, j, k);
     153             : 
     154       12912 :                 driving_force += lambdaT * (volume - volume0);
     155             : 
     156       25824 :                 psinew(i, j, k) = psi(i, j, k) - Lnow * dt * driving_force;
     157       25824 :                 if (psinew(i, j, k) < 0.0) psinew(i, j, k) = 0.0;
     158       28590 :                 if (psinew(i, j, k) > 1.0) psinew(i, j, k) = 1.0;
     159             :             });
     160             :         }
     161           6 :     }
     162             : 
     163           2 :     void Integrate(int amrlev, Set::Scalar time, int step,
     164             :         const amrex::MFIter& mfi, const amrex::Box& box) override
     165             :     {
     166             :         BL_PROFILE("TopOp::Integrate");
     167           2 :         Base::Mechanics<MODEL>::Integrate(amrlev, time, step, mfi, box);
     168             : 
     169           2 :         const amrex::Real* DX = geom[amrlev].CellSize();
     170           2 :         Set::Scalar dv = AMREX_D_TERM(DX[0], *DX[1], *DX[2]);
     171             : 
     172           2 :         amrex::Array4<amrex::Real> const& psi = (*psi_mf[amrlev]).array(mfi);
     173           2 :         amrex::Array4<const Set::Matrix> const& sig = (*stress_mf[amrlev]).array(mfi);
     174           2 :         amrex::Array4<const Set::Matrix> const& eps = (*strain_mf[amrlev]).array(mfi);
     175           2 :         amrex::ParallelFor(box, [=] AMREX_GPU_DEVICE(int i, int j, int k)
     176             :         {
     177        4096 :             volume += psi(i, j, k, 0) * dv;
     178       16384 :             w_chem_potential += alpha * psi(i, j, k, 0) * psi(i, j, k, 0) * (1. - psi(i, j, k, 0) * psi(i, j, k, 0)) * dv;
     179        8192 :             w_bndry += beta * 0.5 * Numeric::Gradient(psi, i, j, k, 0, DX).squaredNorm() * dv;
     180             : 
     181        4096 :             Set::Matrix sig_avg = Numeric::Interpolate::NodeToCellAverage(sig, i, j, k, 0);
     182        4096 :             Set::Matrix eps_avg = Numeric::Interpolate::NodeToCellAverage(eps, i, j, k, 0);
     183        8192 :             w_elastic += gamma * 0.5 * (sig_avg.transpose() * eps_avg).trace() * psi(i, j, k) * dv;
     184             :         });
     185           2 :     }
     186             : 
     187             : 
     188           4 :     void TagCellsForRefinement(int lev, amrex::TagBoxArray& a_tags, Set::Scalar a_time, int a_ngrow) override
     189             :     {
     190           4 :         if (m_type == Base::Mechanics<MODEL>::Type::Disable) return;
     191           4 :         Base::Mechanics<MODEL>::TagCellsForRefinement(lev, a_tags, a_time, a_ngrow);
     192             : 
     193           4 :         Set::Vector DX(geom[lev].CellSize());
     194           4 :         Set::Scalar DXnorm = DX.lpNorm<2>();
     195          17 :         for (amrex::MFIter mfi(*model_mf[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi)
     196             :         {
     197          13 :             amrex::Box bx = mfi.tilebox();
     198          13 :             amrex::Array4<char> const& tags = a_tags.array(mfi);
     199          13 :             if (psi_on)
     200             :             {
     201          13 :                 amrex::Array4<Set::Scalar> const& psi = psi_mf[lev]->array(mfi);
     202        8218 :                 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
     203             :                 {
     204        8205 :                     auto sten = Numeric::GetStencil(i, j, k, bx);
     205             :                     {
     206        8205 :                         Set::Vector gradpsi = Numeric::Gradient(psi, i, j, k, 0, DX.data(), sten);
     207        8205 :                         if (gradpsi.lpNorm<2>() * DXnorm > m_eta_ref_threshold)
     208        1254 :                             tags(i, j, k) = amrex::TagBox::SET;
     209             :                     }
     210             :                 });
     211             :             }
     212             :         }
     213             :     }
     214             : 
     215             : 
     216             : protected:
     217             :     MODEL model;
     218             :     IC::IC* ic_psi = nullptr;
     219             :     BC::BC<Set::Scalar>* bc_psi = nullptr;
     220             :     Set::Scalar m_eta_ref_threshold = NAN;
     221             :     Set::Field<Set::Scalar> psi_old_mf;
     222             : 
     223             : 
     224             :     using Base::Mechanics<MODEL>::m_type;
     225             :     using Base::Mechanics<MODEL>::finest_level;
     226             :     using Base::Mechanics<MODEL>::geom;
     227             :     using Base::Mechanics<MODEL>::model_mf;
     228             :     using Base::Mechanics<MODEL>::psi_mf;
     229             :     using Base::Mechanics<MODEL>::psi_on;
     230             :     using Base::Mechanics<MODEL>::stress_mf;
     231             :     using Base::Mechanics<MODEL>::strain_mf;
     232             : 
     233             : 
     234             :     Set::Scalar alpha = NAN;
     235             :     Set::Scalar beta = NAN;
     236             :     Set::Scalar gamma = NAN;
     237             :     //Set::Scalar L = 1.0;
     238             :     Numeric::Interpolator::Linear<Set::Scalar> L;
     239             :     Set::Scalar volume0 = NAN;
     240             :     //Set::Scalar lambda = 1.0;
     241             :     Numeric::Interpolator::Linear<Set::Scalar> lambda;
     242             : 
     243             :     Set::Scalar volume = NAN;
     244             :     Set::Scalar w_chem_potential = NAN;
     245             :     Set::Scalar w_bndry = NAN;
     246             :     Set::Scalar w_elastic = NAN;
     247             : };
     248             : 
     249             : 
     250             : 
     251             : 
     252             : 
     253             : 
     254             : 
     255             : 
     256             : 
     257             : 
     258             : } // namespace Integrator
     259             : #endif

Generated by: LCOV version 1.14