LCOV - code coverage report
Current view: top level - src/Integrator - AllenCahn.H (source / functions) Hit Total Coverage
Test: coverage_merged.info Lines: 60 66 90.9 %
Date: 2025-01-16 18:33:59 Functions: 8 8 100.0 %

          Line data    Source code
       1             : //
       2             : // This is a simple implementation of an Allen-Cahn equation governed by
       3             : // 
       4             : // .. math::
       5             : //
       6             : //    \frac{\partial\alpha}{\partial t} = 
       7             : //               - L \Big(\frac{\lambda}{\epsilon}(2.0\alpha 
       8             : //                        - 6\alpha^2 + 4\alpha^3) + \epsilon\,\kappa\,\Delta \alpha \Big)
       9             : // 
      10             : // where :math:`\alpha(x,t)` is the order parameter.
      11             : //
      12             : 
      13             : #ifndef INTEGRATOR_ALLENCAHN_H // Include guards
      14             : #define INTEGRATOR_ALLENCAHN_H // 
      15             : 
      16             : // Standard library includes
      17             : #include <iostream>
      18             : #include <fstream>
      19             : #include <iomanip>
      20             : 
      21             : // AMReX Includes
      22             : #include "AMReX.H"
      23             : #include "AMReX_ParallelDescriptor.H"
      24             : #include "AMReX_ParmParse.H"
      25             : 
      26             : // Alamo Includes
      27             : #include "IO/ParmParse.H"
      28             : #include "Integrator/Integrator.H"
      29             : #include "BC/Constant.H"
      30             : #include "IC/IC.H"
      31             : #include "IC/Sphere.H"
      32             : #include "IC/Constant.H"
      33             : #include "IC/Expression.H"
      34             : #include "IC/BMP.H"
      35             : #include "IC/PNG.H"
      36             : #include "IC/PSRead.H"
      37             : #include "Numeric/Stencil.H"
      38             : #include "IC/Random.H"
      39             : 
      40             : namespace Integrator
      41             : {
      42             : class AllenCahn : virtual public Integrator
      43             : {
      44             : public:
      45             :     // Empty constructor
      46           2 :     AllenCahn() : Integrator()
      47           2 :     {}
      48             : 
      49             :     // Constructor that triggers parse
      50           2 :     AllenCahn(IO::ParmParse& pp) : AllenCahn()
      51             :     {
      52           2 :         Parse(*this, pp);
      53           2 :     }
      54             : 
      55             :     // The Parse function initializes the AllenCahn object using
      56             :     // a parser, pp. 
      57             :     // Note that this is a static function, which means it does not have
      58             :     // direct access to member variables. Instead, it initializes the variables
      59             :     // inside the argument, "value", and so all references to member items are
      60             :     // prefixed by "value."
      61           2 :     static void Parse(AllenCahn& value, IO::ParmParse& pp)
      62             :     {
      63             :         // Criterion for mesh refinement [0.01]
      64           2 :         pp_query_default("refinement_threshold", value.refinement_threshold, 0.01);
      65             : 
      66             :         // Value for :math:`L` (mobility)
      67           2 :         pp_query_default("ch.L",value.ch.L, 1.0);
      68             :         // Value for :math:`\epsilon` (diffuse boundary width)
      69           2 :         pp_query_default("ch.eps",value.ch.eps, 0.1);
      70             :         // Value for :math:`\kappa` (Interface energy parameter)
      71           2 :         pp_query_default("ch.grad",value.ch.grad, 1.0);
      72             :         // Value for :math:`\lambda` (Chemical potential coefficient)
      73           2 :         pp_query_default("ch.chempot",value.ch.chempot, 1.0);
      74             :         // Force directional growth: 0=no growth, 1=only positive, -1=only negative
      75           2 :         pp_query_validate("ch.direction",value.ch.direction, {0,1,-1});
      76             : 
      77           2 :         std::string type = "sphere";
      78             :         // Initial condition type ([sphere], constant, expression, bmp, random)
      79           2 :         pp_query_validate("alpha.ic.type", type, {"sphere","constant","expression","bmp","png","random","psread"});
      80           2 :         if (type == "sphere")          value.ic = new IC::Sphere(value.geom, pp, "alpha.ic.sphere");
      81           2 :         else if (type == "constant")   value.ic = new IC::Constant(value.geom, pp, "alpha.ic.constant");
      82           2 :         else if (type == "expression") value.ic = new IC::Expression(value.geom, pp, "alpha.ic.expression");
      83           2 :         else if (type == "bmp")        value.ic = new IC::BMP(value.geom, pp, "alpha.ic.bmp");
      84           0 :         else if (type == "png")        value.ic = new IC::PNG(value.geom, pp, "alpha.ic.png");
      85           0 :         else if (type == "random")     value.ic = new IC::Random(value.geom, pp, "alpha.ic.random");
      86           0 :         else if (type == "psread")     value.ic = new IC::PSRead(value.geom, pp, "alpha.ic.psread");
      87           0 :         else  Util::Abort(INFO, "Invalid ic.type ", type);
      88             : 
      89             :         // Use a constant BC object for temperature
      90           2 :         value.bc = new BC::Constant(1);
      91             :         // :ref:`BC::Constant` parameters 
      92           2 :         pp_queryclass("alpha.bc", *static_cast<BC::Constant*>(value.bc));
      93             : 
      94             :         // Register the temperature and old temperature fields.
      95             :         // alpha_mf and alpha_old_mf are defined near the bottom of this Header file.
      96           2 :         value.RegisterNewFab(value.alpha_mf, value.bc, value.number_of_components, value.number_of_ghost_cells, "alpha", true);
      97           2 :         value.RegisterNewFab(value.alpha_old_mf, value.bc, value.number_of_components, value.number_of_ghost_cells, "alpha_old", false);
      98           2 :     }
      99             : 
     100             : protected:
     101             : 
     102             :     // Use the ic object to initialize the order parameter
     103           6 :     void Initialize(int lev)
     104             :     {
     105           6 :         ic->Initialize(lev, alpha_mf);
     106           6 :         ic->Initialize(lev, alpha_old_mf);
     107           6 :     }
     108             : 
     109             :     // Integrate the Allen Cahn equation
     110        7700 :     void Advance(int lev, Set::Scalar /*time*/, Set::Scalar dt)
     111             :     {
     112        7700 :         std::swap(*alpha_mf[lev], *alpha_old_mf[lev]);
     113             : 
     114        7700 :         const Set::Scalar *DX = this->geom[lev].CellSize();
     115             :         // Evolve alpha
     116       15400 :         for (amrex::MFIter mfi(*alpha_mf[lev], true); mfi.isValid(); ++mfi)
     117             :         {
     118        7700 :             const amrex::Box& bx = mfi.tilebox();
     119        7700 :             amrex::Array4<Set::Scalar> const& alpha_new = (*alpha_mf[lev]).array(mfi);
     120        7700 :             amrex::Array4<const Set::Scalar> const& alpha = (*alpha_old_mf[lev]).array(mfi);
     121             : 
     122        7700 :             amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
     123             :             {
     124   218414000 :                 Set::Scalar driving_force = 0.0;
     125             :                 // Chemical potential
     126   436828000 :                 Set::Scalar alpha_2 = alpha(i, j, k) * alpha(i, j, k);
     127   218414000 :                 Set::Scalar alpha_3 = alpha_2 * alpha(i, j, k);
     128   218414000 :                 driving_force += (ch.chempot / ch.eps) * (2.0 * alpha(i, j, k) - 6.0 * alpha_2 + 4.0 * alpha_3);
     129             :                 // Gradient
     130   218414000 :                 Set::Scalar alpha_lap = Numeric::Laplacian(alpha, i, j, k, 0, DX);
     131   218414000 :                 driving_force -= ch.eps * ch.grad * alpha_lap;
     132             : 
     133   218414000 :                 if (ch.direction == 1)
     134           0 :                     driving_force = std::min(0.0, driving_force);
     135   218414000 :                 else if (ch.direction == -1)
     136           0 :                     driving_force = std::max(0.0, driving_force);
     137             : 
     138             :                 // Update
     139   436828000 :                 alpha_new(i, j, k) =
     140   436828000 :                     alpha(i, j, k) - ch.L * dt * driving_force;
     141   218414000 :             });
     142             :         }
     143        7700 :     }
     144             : 
     145             :     // Tag cells for mesh refinement based on temperature gradient
     146        2208 :     void TagCellsForRefinement(int lev, amrex::TagBoxArray& a_tags, Set::Scalar /*time*/, int /*ngrow*/)
     147             :     {
     148             :         // Get cell dimensions as done above.
     149        2208 :         const Set::Scalar* DX = geom[lev].CellSize();
     150             :         // Calculate the diagonal.
     151        2208 :         Set::Scalar dr = sqrt(AMREX_D_TERM(DX[0] * DX[0], +DX[1] * DX[1], +DX[2] * DX[2]));
     152             : 
     153             :         // Iterate over the patches on this level
     154        4416 :         for (amrex::MFIter mfi(*alpha_mf[lev], amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
     155             :         {
     156             :             // Get the box and handles as done above.
     157        2208 :             const amrex::Box& bx = mfi.tilebox();
     158        2208 :             amrex::Array4<char>         const& tags = a_tags.array(mfi);
     159        2208 :             amrex::Array4<Set::Scalar>  const& alpha = (*alpha_mf[lev]).array(mfi);
     160             : 
     161             :             // Iterate over the grid as done above.
     162        2208 :             amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
     163             :             {
     164             :                 // Calculate the temperature gradient.
     165    21927900 :                 Set::Vector grad = Numeric::Gradient(alpha, i, j, k, 0, DX);
     166             : 
     167             :                 // Is the gradient * cell_size too big? If so, then
     168             :                 // mark this cell as needing refinement.
     169    21927900 :                 if (grad.lpNorm<2>() * dr > refinement_threshold)
     170    32841400 :                     tags(i, j, k) = amrex::TagBox::SET;
     171    21927900 :             });
     172             :         }
     173        2208 :     }
     174             : 
     175             : protected:
     176             :     Set::Field<Set::Scalar> alpha_mf;         // Temperature field variable (current timestep)
     177             :     Set::Field<Set::Scalar> alpha_old_mf;     // Temperature field variable (previous timestep)
     178             :     IC::IC* ic;                              // Object used to initialize temperature field
     179             : 
     180             :     struct {
     181             :         Set::Scalar L = NAN;
     182             :         Set::Scalar eps = NAN;
     183             :         Set::Scalar grad = NAN;
     184             :         Set::Scalar chempot = NAN;
     185             :         int direction = 0;
     186             :     } ch;
     187             : 
     188             : private:
     189             :     int number_of_components = 1;            // Number of components
     190             :     int number_of_ghost_cells = 2;           // Number of ghost cells
     191             : 
     192             :     Set::Scalar refinement_threshold = NAN; // Criterion for cell refinement
     193             : 
     194             :     BC::BC<Set::Scalar>* bc;                 // Object used to update temp field boundary ghost cells
     195             : };
     196             : } // namespace Integrator
     197             : #endif

Generated by: LCOV version 1.14