LCOV - code coverage report
Current view: top level - src/Model/Defect - Disconnection.H (source / functions) Coverage Total Hit
Test: coverage_merged.info Lines: 2.4 % 83 2
Test Date: 2025-02-27 04:17:48 Functions: 33.3 % 6 2

            Line data    Source code
       1              : //
       2              : // This simulates the creation of "disconnection pairs" at a GB
       3              : // by perturbing the order parameter :math:`\eta` with a gaussian.
       4              : //
       5              : // Disconnections can be nucleated randomly, or they can be added
       6              : // in a controlled way through the "fixed" option.
       7              : //
       8              : // See the following reference for further details
       9              : // 
      10              : // .. bibliography::
      11              : //    :list: none
      12              : //    :filter: False
      13              : // 
      14              : //    gokuli2021multiphase
      15              : // 
      16              : //
      17              : 
      18              : #ifndef MODEL_DEFECT_DISCONNECTION
      19              : #define MODEL_DEFECT_DISCONNECTION
      20              : 
      21              : #include <random>
      22              : 
      23              : #include "AMReX_SPACE.H"
      24              : #include "IO/ParmParse.H"
      25              : #include "Set/Base.H"
      26              : #include "Util/MPI.H"
      27              : 
      28              : namespace Model
      29              : {
      30              : namespace Defect
      31              : {
      32              : class Disconnection
      33              : {
      34              : public:
      35              : 
      36            9 :     Disconnection(){};
      37            3 :     ~Disconnection() {};
      38              : 
      39              :     static void
      40            0 :     Parse(Disconnection &value, IO::ParmParse &pp)
      41              :     {
      42            0 :         Util::Assert(INFO,TEST(AMREX_SPACEDIM==2),"2D only");
      43              :         // time to start applying disconnections
      44            0 :         pp_query_default ("tstart", value.tstart,0.0); 
      45              :         // nucleation energy
      46            0 :         pp_query_default ("nucleation_energy", value.nucleation_energy,0.0); 
      47              :         // characteristic time
      48            0 :         pp_query_default("tau_vol", value.tau_vol, 1.0);
      49              :         // temperature
      50            0 :         pp_query_default("temp", value.temp, 0.0);
      51              :         // characteristic size
      52            0 :         pp_query_default("box_size", value.box_size, 0.0);
      53              :         // interval between generation events
      54            0 :         pp_query_required("interval", value.interval);
      55              :         // regularization epsilon
      56            0 :         pp_query_default ("epsilon",value.epsilon,1E-20); 
      57              : 
      58              :         // whether to manually specify disconnection nucleation points
      59            0 :         pp.query("disconnection.fixed.on",value.fixed.on); 
      60            0 :         if (value.fixed.on)
      61              :         {
      62              :             // array of x locations
      63            0 :             pp.queryarr("fixed.sitex",value.fixed.sitex); 
      64              :             // array of y locations
      65            0 :             pp.queryarr("fixed.sitey",value.fixed.sitey); 
      66              :             // array of order parameter number
      67            0 :             pp.queryarr("fixed.phases",value.fixed.phases); 
      68              :             // time to appear
      69            0 :             pp.queryarr("fixed.time",value.fixed.time); 
      70            0 :             Util::Assert(INFO,TEST(value.fixed.sitex.size() == value.fixed.sitey.size()));
      71            0 :             Util::Assert(INFO,TEST(value.fixed.sitex.size() == value.fixed.phases.size()));
      72            0 :             Util::Assert(INFO,TEST(value.fixed.sitex.size() == value.fixed.time.size()));
      73            0 :             value.fixed.done.resize(value.fixed.sitex.size(),false);
      74              :         }
      75              :         else
      76              :         {
      77            0 :             value.unif_dist = std::uniform_real_distribution<double>(0.0,1.0);
      78            0 :             value.int_dist = std::uniform_int_distribution<int>(0,1);
      79            0 :             value.rand_num_gen.seed(amrex::ParallelDescriptor::MyProc());
      80              :         }
      81              : 
      82              :         // verbosity
      83            0 :         pp_query_default("verbose",value.verbose,false); 
      84            0 :     }
      85              : 
      86              : 
      87              :     /// This operates on an entire field, and manages all of the MPI
      88              :     /// communication necessary for consistent nucleation.
      89              :     void
      90            0 :     Nucleate(   Set::Field<Set::Scalar> &eta_mf,
      91              :                 std::vector<amrex::Geometry> &geom,
      92              :                 Set::Scalar timestep,
      93              :                 Set::Scalar time,
      94              :                 int iter
      95              :         )
      96              :     {
      97            0 :         Util::Assert(INFO,TEST(eta_mf[0]->nComp() == 2), "This only works for 2 component phase fields");
      98              : 
      99            0 :         if (time < tstart) // wait until it's time to go
     100            0 :             return;
     101            0 :         if (iter % interval) // skip every [interval] timesteps
     102            0 :             return;
     103              : 
     104            0 :         sitex.clear();
     105            0 :         sitey.clear();
     106            0 :         phases.clear();
     107              : 
     108            0 :         int max_lev = eta_mf.finest_level;
     109              : 
     110            0 :         const Set::Scalar *DX = geom[max_lev].CellSize();
     111            0 :         Set::Scalar exponent = DX[0] * DX[0] * (timestep * interval) / tau_vol;
     112              : 
     113              :         // Determine the nucleation sites in the finest grid only
     114            0 :         for (amrex::MFIter mfi(*eta_mf[max_lev], amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
     115              :         {
     116            0 :             const amrex::Box &bx = mfi.tilebox();
     117            0 :             amrex::Array4<amrex::Real> const &eta = (*eta_mf[max_lev]).array(mfi);
     118            0 :             amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
     119              :             {
     120            0 :                 Set::Scalar E0 = 2.0*nucleation_energy;
     121            0 :                 E0 /= epsilon + 256.0*eta(i,j,k,0)*eta(i,j,k,0)*eta(i,j,k,0)*eta(i,j,k,0)*eta(i,j,k,1)*eta(i,j,k,1)*eta(i,j,k,1)*eta(i,j,k,1);
     122            0 :                 Set::Scalar p = std::exp(-E0/(K_b*temp));
     123            0 :                 Set::Scalar P = 1.0 - std::pow(1.0 - p,exponent);
     124            0 :                 if (eta(i,j,k,0) < 0 || eta(i,j,k,0) > 1.0 || eta(i,j,k,1) < 0 || eta(i,j,k,1) > 1.0) P = 0.0;
     125            0 :                 Set::Scalar q = 0.0;
     126            0 :                 q = unif_dist(rand_num_gen);
     127            0 :                 if (q < P)
     128              :                 {
     129            0 :                     sitex.push_back(geom[max_lev].ProbLo()[0] + ((amrex::Real)(i)) * DX[0]);
     130            0 :                     sitey.push_back(geom[max_lev].ProbLo()[1] + ((amrex::Real)(j)) * DX[1]);
     131            0 :                     int phase = int_dist(rand_num_gen);
     132            0 :                     phases.push_back(phase);
     133            0 :                 } });
     134            0 :         }
     135              : 
     136              :         // Sync up all the nucleation sites among processors
     137            0 :         Util::MPI::Allgather(sitex);
     138            0 :         Util::MPI::Allgather(sitey);
     139            0 :         Util::MPI::Allgather(phases);
     140              : 
     141            0 :         if (verbose)
     142              :         {
     143            0 :             Util::Message(INFO, "Nucleating ", phases.size(), " disconnections");
     144              :         }
     145              : 
     146            0 :         if (sitex.size() > 0)
     147              :         {
     148              :             // Now that we all know the nucleation locations, perform the nucleation
     149            0 :             for (int lev = 0; lev <= max_lev; lev++)
     150              :             {
     151            0 :                 amrex::Box domain = geom[lev].Domain();
     152            0 :                 domain.convert(amrex::IntVect::TheNodeVector());
     153            0 :                 const amrex::Real *DX = geom[lev].CellSize();
     154            0 :                 for (amrex::MFIter mfi(*eta_mf[lev], amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
     155              :                 {
     156            0 :                     const amrex::Box bx = mfi.grownnodaltilebox() & domain;
     157            0 :                     amrex::Array4<Set::Scalar> const &eta = (*eta_mf[lev]).array(mfi);
     158            0 :                     amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
     159              :                     {
     160            0 :                         Set::Vector x;
     161            0 :                         AMREX_D_TERM(
     162              :                             x(0) = geom[lev].ProbLo()[0] + ((amrex::Real)(i)) * DX[0];,
     163              :                             x(1) = geom[lev].ProbLo()[1] + ((amrex::Real)(j)) * DX[1];,
     164              :                             x(2) = geom[lev].ProbLo()[2] + ((amrex::Real)(k)) * DX[2];);
     165            0 :                         for (unsigned int m = 0; m < phases.size(); m++)
     166              :                         {
     167            0 :                             amrex::Real r_squared = 0;
     168            0 :                             Set::Vector nucleation_site(AMREX_D_DECL(sitex[m], sitey[m], 0.0));
     169            0 :                             for (int n = 0; n < AMREX_SPACEDIM; n++)
     170              :                             {
     171            0 :                                 amrex::Real dist = nucleation_site(n) - x(n);
     172            0 :                                 r_squared += dist * dist;
     173              :                             }
     174            0 :                             amrex::Real bump = exp(-r_squared / box_size);
     175            0 :                             eta(i, j, k, phases[m]) = bump * (1 - eta(i, j, k, phases[m])) + eta(i, j, k, phases[m]);
     176            0 :                             eta(i, j, k, 1 - phases[m]) = (1. - bump) * eta(i, j, k, 1 - phases[m]);
     177              :                         }
     178            0 :                     });
     179            0 :                 }
     180              :             }
     181              :         }
     182              :     }
     183              :     
     184              : 
     185              : 
     186              : private:
     187              : 
     188              :     bool verbose = false;
     189              : 
     190              :     Set::Scalar tstart = NAN;
     191              :     Set::Scalar nucleation_energy = NAN;
     192              :     Set::Scalar tau_vol = NAN;
     193              :     Set::Scalar temp = NAN;
     194              :     Set::Scalar box_size = NAN;
     195              :     Set::Scalar epsilon = NAN;
     196              : 
     197              :     int interval = -1;
     198              : 
     199              :     std::uniform_real_distribution<double> unif_dist;  /// random number distribution for spatial location
     200              :     std::uniform_int_distribution<int> int_dist;       /// random number generator for phase
     201              :     std::default_random_engine rand_num_gen;           /// generator object
     202              : 
     203              :     struct {
     204              :         int on = 0;
     205              :         std::vector<Set::Scalar> sitex;
     206              :         std::vector<Set::Scalar> sitey;
     207              :         std::vector<int> phases;
     208              :         std::vector<Set::Scalar> time;
     209              :         std::vector<bool> done;
     210              :     } fixed;
     211              : 
     212              : 
     213              :     std::vector<Set::Scalar> sitex; /// list of nucleation site x coordinates
     214              :     std::vector<Set::Scalar> sitey; /// list of nucleation stie y coordinates
     215              :     std::vector<int> phases;        /// list of nucleation site phases (up or down)
     216              : 
     217              :     const Set::Scalar K_b = 8.617333262145e-5; // eV/K
     218              : };
     219              : }
     220              : }
     221              : 
     222              : #endif
        

Generated by: LCOV version 2.0-1