LCOV - code coverage report
Current view: top level - src/Integrator - PhaseFieldMicrostructure.cpp (source / functions) Coverage Total Hit
Test: coverage_merged.info Lines: 69.1 % 243 168
Test Date: 2025-02-27 04:17:48 Functions: 45.8 % 48 22

            Line data    Source code
       1              : 
       2              : #include <eigen3/Eigen/Eigenvalues>
       3              : 
       4              : #include <cmath>
       5              : 
       6              : #include <AMReX_SPACE.H>
       7              : 
       8              : #include "PhaseFieldMicrostructure.H"
       9              : #include "Integrator/Base/Mechanics.H"
      10              : #include "BC/Constant.H"
      11              : #include "Set/Set.H"
      12              : #include "Util/Util.H"
      13              : #include "IC/Random.H"
      14              : #include "IC/Trig.H"
      15              : #include "IC/Sphere.H"
      16              : #include "IC/Expression.H"
      17              : #include "Model/Interface/GB/SH.H"
      18              : #include "Numeric/Stencil.H"
      19              : #include "Solver/Nonlocal/Linear.H"
      20              : #include "Solver/Nonlocal/Newton.H"
      21              : #include "IC/Trig.H"
      22              : 
      23              : #include "Model/Solid/Affine/Cubic.H"
      24              : #include "Model/Solid/Affine/Hexagonal.H"
      25              : #include "Model/Solid/Finite/PseudoAffine/Cubic.H"
      26              : #include "Model/Defect/Disconnection.H"
      27              : 
      28              : #include "Util/MPI.H"
      29              : 
      30              : namespace Integrator
      31              : {
      32              : template<class model_type>
      33         4804 : void PhaseFieldMicrostructure<model_type>::Advance(int lev, Set::Scalar time, Set::Scalar dt)
      34              : {
      35              :     BL_PROFILE("PhaseFieldMicrostructure::Advance");
      36         4804 :     Base::Mechanics<model_type>::Advance(lev, time, dt);
      37         4804 :     const Set::Scalar* DX = this->geom[lev].CellSize();
      38              : 
      39         4804 :     std::swap(eta_old_mf[lev], eta_mf[lev]);
      40              :     
      41              : 
      42         4804 :     Set::Scalar df_max = std::numeric_limits<Set::Scalar>::min();
      43              : 
      44         4804 :     Model::Interface::GB::SH gbmodel(0.0, 0.0, anisotropy.sigma0, anisotropy.sigma1);
      45              : 
      46       354995 :     for (amrex::MFIter mfi(*eta_mf[lev], amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
      47              :     {
      48       350194 :         amrex::Box bx = mfi.tilebox();
      49       350194 :         Set::Patch<Set::Scalar> etanew = eta_mf.Patch(lev,mfi);
      50       350194 :         Set::Patch<const Set::Scalar> eta    = eta_old_mf.Patch(lev,mfi);
      51              : 
      52       350194 :         Set::Scalar *df_max_handle = &df_max;
      53              : 
      54       350194 :         Set::Patch<const Set::Matrix> sigma = stress_mf.Patch(lev,mfi); 
      55       350194 :         Set::Patch<const Set::Vector> disp  = this->disp_mf.Patch(lev,mfi);
      56              : 
      57     22798557 :         amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
      58              :         {
      59     22448366 :             Set::Matrix sig = Set::Matrix::Zero();
      60     23443031 :             if (pf.elastic_df) sig = Numeric::Interpolate::NodeToCellAverage(sigma, i, j, k, 0);
      61              : 
      62     71355589 :             for (int m = 0; m < number_of_grains; m++)
      63              :             {
      64              :                 //if (shearcouple.on) etaold(i,j,k,m) = eta(i,j,k,m);
      65              : 
      66     48907226 :                 Set::Scalar driving_force = 0.0;
      67     48907226 :                 Set::Scalar driving_force_threshold = NAN;
      68     48907226 :                 if (pf.threshold.on) driving_force_threshold = 0.0;
      69     48907226 :                 Set::Scalar kappa = NAN, mu = NAN;
      70              : 
      71              :                 //
      72              :                 // BOUNDARY TERM and SECOND ORDER REGULARIZATION
      73              :                 //
      74              : 
      75     48907226 :                 Set::Vector Deta = Numeric::Gradient(eta, i, j, k, m, DX);
      76     48907226 :                 Set::Scalar normgrad = Deta.lpNorm<2>();
      77     48907226 :                 if (normgrad < 1E-4)
      78     12748641 :                     continue; // This ought to speed things up.
      79              : 
      80     36158585 :                 Set::Matrix DDeta = Numeric::Hessian(eta, i, j, k, m, DX);
      81     36158584 :                 Set::Scalar laplacian = DDeta.trace();
      82              : 
      83     36158584 :                 if (!anisotropy.on || time < anisotropy.tstart)
      84              :                 {
      85     12131663 :                     kappa = pf.l_gb * 0.75 * pf.sigma0;
      86     12131663 :                     mu = 0.75 * (1.0 / 0.23) * pf.sigma0 / pf.l_gb;
      87     12131663 :                     if (pf.threshold.boundary)  driving_force_threshold += -kappa * laplacian;
      88     11221313 :                     else                        driving_force += -kappa * laplacian;
      89              :                 }
      90              :                 else
      91              :                 {
      92     24026921 :                     Set::Matrix4<AMREX_SPACEDIM, Set::Sym::Full> DDDDEta = Numeric::DoubleHessian<AMREX_SPACEDIM>(eta, i, j, k, m, DX);
      93     24026921 :                     auto anisotropic_df = boundary->DrivingForce(Deta, DDeta, DDDDEta);
      94     24026919 :                     if (pf.threshold.boundary) driving_force_threshold += pf.l_gb * 0.75 * std::get<0>(anisotropic_df);
      95     24026919 :                     else                       driving_force += pf.l_gb * 0.75 * std::get<0>(anisotropic_df);
      96     24026919 :                     if (std::isnan(std::get<0>(anisotropic_df))) Util::Abort(INFO);
      97     24026919 :                     if (pf.threshold.boundary) driving_force_threshold += anisotropy.beta * std::get<1>(anisotropic_df);
      98     24026919 :                     else                       driving_force += anisotropy.beta * std::get<1>(anisotropic_df);
      99     24026919 :                     if (std::isnan(std::get<1>(anisotropic_df))) Util::Abort(INFO);
     100     24026919 :                     mu = 0.75 * (1.0 / 0.23) * boundary->W(Deta) / pf.l_gb;
     101              :                 }
     102              : 
     103              :                 //
     104              :                 // CHEMICAL POTENTIAL
     105              :                 //
     106              : 
     107     36158582 :                 Set::Scalar sum_of_squares = 0.;
     108    115151722 :                 for (int n = 0; n < number_of_grains; n++)
     109              :                 {
     110     78993140 :                     if (m == n)
     111     36158582 :                         continue;
     112    128503674 :                     sum_of_squares += eta(i, j, k, n) * eta(i, j, k, n);
     113              :                 }
     114     36158582 :                 if (pf.threshold.chempot)
     115            0 :                     driving_force_threshold += mu * (eta(i, j, k, m) * eta(i, j, k, m) - 1.0 + 2.0 * pf.gamma * sum_of_squares) * eta(i, j, k, m);
     116              :                 else
     117    144634328 :                     driving_force += mu * (eta(i, j, k, m) * eta(i, j, k, m) - 1.0 + 2.0 * pf.gamma * sum_of_squares) * eta(i, j, k, m);
     118              : 
     119              : 
     120              :                 //
     121              :                 // LAGRANGE MULTIPLIER
     122              :                 //
     123     36158582 :                 if (lagrange.on && m == 0 && time > lagrange.tstart)
     124              :                 {
     125      6035177 :                     if (pf.threshold.lagrange)
     126            0 :                         driving_force_threshold += lagrange.lambda * (volume - lagrange.vol0);
     127              :                     else
     128      6035177 :                         driving_force += lagrange.lambda * (volume - lagrange.vol0);
     129              :                 }
     130              : 
     131              :                 //
     132              :                 // SYNTHETIC DRIVING FORCE
     133              :                 //
     134     36158582 :                 if (sdf.on && time > sdf.tstart)
     135              :                 {
     136            0 :                     if (pf.threshold.sdf)
     137            0 :                         driving_force_threshold += sdf.val[m](time);
     138              :                     else
     139            0 :                         driving_force += sdf.val[m](time);
     140              :                 }
     141              : 
     142              :               
     143              :                 //
     144              :                 // ELASTIC DRIVING FORCE
     145              :                 //
     146     36158582 :                 if (pf.elastic_df)
     147              :                 {
     148       910350 :                     Set::Scalar elastic_df_m = 0.0;
     149              :                     
     150       910350 :                     if (shearcouple.on)
     151              :                     {
     152            0 :                         for (int n = 0; n < number_of_grains; n++)
     153              :                         {
     154            0 :                             if (n==m) continue;
     155            0 :                             Set::Scalar etam = eta(i,j,k,m);
     156            0 :                             Set::Scalar etan = eta(i,j,k,n);
     157              : 
     158            0 :                             Set::Scalar sumsq = (etam*etam + etan*etan);
     159            0 :                             sumsq = sumsq * sumsq;
     160              : 
     161              :                             //Set::Scalar dgm = 2.0*etan*etan*etam / sumsq;
     162            0 :                             Set::Scalar dgn = 2.0*etan*etam*etam / sumsq;
     163              : 
     164              : 
     165            0 :                             Set::Matrix Fgbn = shearcouple.Fgb[n*number_of_grains + m];
     166              : 
     167              :                             if (model_type::kinvar == Model::Solid::KinematicVariable::F)
     168              :                             {
     169            0 :                                 Set::Matrix F =
     170              :                                     Set::Matrix::Identity() +
     171            0 :                                     Numeric::NodeGradientOnCell(disp,i,j,k,DX);
     172            0 :                                 Fgbn = F*Fgbn;
     173              :                             }
     174              : 
     175            0 :                             elastic_df_m += (sig.transpose() * Fgbn).trace() * dgn;
     176              :                         }
     177              :                     }
     178              :                     else
     179              :                     {
     180       910350 :                         Set::Matrix F0avg = Set::Matrix::Zero();
     181              : 
     182      2731050 :                         for (int n = 0; n < number_of_grains; n++)
     183      3641400 :                             F0avg += eta(i, j, k, n) * mechanics.model[n].F0;
     184              : 
     185       910350 :                         Set::Matrix dF0deta = Set::Matrix::Zero();
     186              : 
     187      2731050 :                         for (int n = 0; n < number_of_grains; n++)
     188              :                         {
     189      1820700 :                             if (n == m) continue;
     190      3641400 :                             Set::Scalar normsq = eta(i, j, k, m) * eta(i, j, k, m) + eta(i, j, k, n) * eta(i, j, k, n);
     191      3641400 :                             dF0deta += (2.0 * eta(i, j, k, m) * eta(i, j, k, n) * eta(i, j, k, n) *
     192       910350 :                                         (mechanics.model[m].F0 - mechanics.model[n].F0))
     193              :                                 / normsq / normsq;
     194              :                         }
     195              : 
     196       910350 :                         elastic_df_m += (dF0deta.transpose() * sig).trace();
     197              :                     }
     198              : 
     199              : 
     200       910350 :                     if (pf.threshold.mechanics)
     201       910350 :                         driving_force_threshold -= pf.elastic_mult * elastic_df_m;
     202              :                     else
     203            0 :                         driving_force -= pf.elastic_mult * elastic_df_m;
     204              :                 }
     205              : 
     206              :                 //
     207              :                 // Update eta
     208              :                 //
     209              :                 // Final mobility and threshold values:
     210     36158582 :                 Set::Scalar L = NAN, threshold = NAN;
     211              :                 // (if we are NOT using anisotropic kinetics)
     212     36158582 :                 if (!anisotropic_kinetics.on || time < anisotropic_kinetics.tstart)
     213              :                 {
     214     36158582 :                     L = pf.L;
     215     36158582 :                     threshold = pf.threshold.value;
     216              :                 }
     217              :                 // (if we ARE using anisotropic kinetics)
     218              :                 else
     219              :                 {
     220            0 :                     Set::Scalar theta = atan2(Deta(1), Deta(0));
     221            0 :                     L = (4. / 3.) * anisotropic_kinetics.mobility(theta) / pf.l_gb;
     222            0 :                     threshold = anisotropic_kinetics.threshold(theta);
     223              :                 }
     224              : 
     225     36158582 :                 Set::Scalar totaldf = 0.0;
     226     36158582 :                 if (pf.threshold.on)
     227              :                 {
     228       910350 :                     if (driving_force_threshold > threshold)
     229              :                     {
     230       374798 :                         if (pf.threshold.type == ThresholdType::Continuous)
     231            0 :                             totaldf -= L * (driving_force_threshold - threshold);
     232       374798 :                         else if (pf.threshold.type == ThresholdType::Chop)
     233       374798 :                             totaldf -= L * (driving_force_threshold);
     234              :                     }
     235       535552 :                     else if (driving_force_threshold < -threshold)
     236              :                     {
     237       376698 :                         if (pf.threshold.type == ThresholdType::Continuous)
     238            0 :                             totaldf -= L * (driving_force_threshold + threshold);
     239       376698 :                         else if (pf.threshold.type == ThresholdType::Chop)
     240       376698 :                             totaldf -= L  * (driving_force_threshold);
     241              :                     }
     242              :                 }
     243     36158582 :                 totaldf -= L * driving_force;
     244              : 
     245              :                 // Final Eta Update
     246     72317164 :                 etanew(i, j, k, m) = eta(i,j,k,m) +  dt * totaldf;
     247     36158582 :                 *df_max_handle = std::max(df_max, std::fabs(totaldf));
     248              :             }
     249              :         });
     250              :     }
     251              : 
     252         4801 :     if (shearcouple.on && time >= mechanics.tstart) UpdateEigenstrain(lev);
     253              :     //this->DynamicTimestep_SyncDrivingForce(lev,df_max);
     254         4801 : }
     255              : 
     256              : template <class model_type>
     257            0 : void PhaseFieldMicrostructure<model_type>::UpdateEigenstrain(int lev)
     258              : {
     259            0 :     if (this->m_type == Mechanics<model_type>::Disable) return;
     260            0 :     eta_mf[lev]->FillBoundary();
     261            0 :     eta_old_mf[lev]->FillBoundary();
     262              : 
     263            0 :     amrex::Box domain = this->geom[lev].Domain();
     264            0 :     domain.convert(amrex::IntVect::TheNodeVector());
     265              : 
     266            0 :     for (amrex::MFIter mfi(*this->model_mf[lev], false); mfi.isValid(); ++mfi)
     267              :     {
     268            0 :         amrex::Box bx = mfi.grownnodaltilebox() & domain;
     269            0 :         Set::Patch<const Set::Scalar> etaold = eta_old_mf.Patch(lev,mfi);
     270            0 :         Set::Patch<const Set::Scalar> etanew = eta_mf.Patch(lev,mfi);
     271            0 :         Set::Patch<model_type>        model  = model_mf.Patch(lev,mfi);
     272            0 :         amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
     273              :         {
     274            0 :             for (int m = 0; m < number_of_grains; m++)
     275            0 :                 for (int n = 0; n < number_of_grains; n++)
     276              :                 {
     277            0 :                     if (m==n) continue;
     278            0 :                     Set::Scalar emnew = Numeric::Interpolate::CellToNodeAverage(etanew, i, j, k, m);//, sten);
     279            0 :                     Set::Scalar emold = Numeric::Interpolate::CellToNodeAverage(etaold, i, j, k, m);//, sten);
     280            0 :                     Set::Scalar ennew = Numeric::Interpolate::CellToNodeAverage(etanew, i, j, k, n);//, sten);
     281            0 :                     Set::Scalar enold = Numeric::Interpolate::CellToNodeAverage(etaold, i, j, k, n);//, sten);
     282            0 :                     Set::Scalar gmnew = (emnew * emnew) / (emnew * emnew + ennew * ennew);
     283            0 :                     Set::Scalar gmold = (emold * emold) / (emold * emold + enold * enold);
     284            0 :                     model(i, j, k).F0 -= 0.5 * (gmnew - gmold) * shearcouple.Fgb[m*number_of_grains + n]; 
     285              :                 }
     286              :         });
     287              :     }
     288              :     
     289            0 :     Util::RealFillBoundary(*this->model_mf[lev],this->geom[lev]);
     290              : }
     291              : 
     292              : template<class model_type>
     293           64 : void PhaseFieldMicrostructure<model_type>::Initialize(int lev)
     294              : {
     295              :     BL_PROFILE("PhaseFieldMicrostructure::Initialize");
     296           64 :     Base::Mechanics<model_type>::Initialize(lev);
     297           64 :     ic->Initialize(lev, eta_mf);
     298           64 :     ic->Initialize(lev, eta_old_mf);
     299           63 : }
     300              : 
     301              : template<class model_type>
     302          369 : void PhaseFieldMicrostructure<model_type>::TagCellsForRefinement(int lev, amrex::TagBoxArray& a_tags, Set::Scalar time, int ngrow)
     303              : {
     304              :     BL_PROFILE("PhaseFieldMicrostructure::TagCellsForRefinement");
     305          369 :     Base::Mechanics<model_type>::TagCellsForRefinement(lev, a_tags, time, ngrow);
     306          369 :     const amrex::Real* DX = this->geom[lev].CellSize();
     307          369 :     const Set::Vector dx(DX);
     308          369 :     const Set::Scalar dxnorm = dx.lpNorm<2>();
     309              : 
     310        21785 :     for (amrex::MFIter mfi(*eta_mf[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi)
     311              :     {
     312        21416 :         const amrex::Box& bx = mfi.tilebox();
     313        21416 :         amrex::Array4<const amrex::Real> const& etanew = (*eta_mf[lev]).array(mfi);
     314        21416 :         amrex::Array4<char> const& tags = a_tags.array(mfi);
     315              : 
     316        95896 :         for (int n = 0; n < number_of_grains; n++)
     317      5206480 :             amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
     318      5132000 :             Set::Vector grad = Numeric::Gradient(etanew, i, j, k, n, DX);
     319              : 
     320      5132000 :             if (dxnorm * grad.lpNorm<2>() > ref_threshold)
     321       735750 :                 tags(i, j, k) = amrex::TagBox::SET;
     322              :         });
     323              :     }
     324          369 : }
     325              : 
     326              : template<class model_type>
     327          657 : void PhaseFieldMicrostructure<model_type>::TimeStepComplete(Set::Scalar /*time*/, int /*iter*/) 
     328              : {
     329          657 :     this->DynamicTimestep_Update();
     330          657 : }
     331              : 
     332              : template<class model_type>
     333           10 : void PhaseFieldMicrostructure<model_type>::UpdateModel(int a_step, Set::Scalar /*a_time*/)
     334              : {
     335              :     BL_PROFILE("PhaseFieldMicrostructure::UpdateModel");
     336           10 :     if (a_step % this->m_interval) return;
     337              : 
     338           14 :     for (int lev = 0; lev <= this->finest_level; ++lev)
     339              :     {
     340           11 :         amrex::Box domain = this->geom[lev].Domain();
     341           11 :         domain.convert(amrex::IntVect::TheNodeVector());
     342              : 
     343           11 :         eta_mf[lev]->FillBoundary();
     344              : 
     345         2035 :         for (MFIter mfi(*this->model_mf[lev], false); mfi.isValid(); ++mfi)
     346              :         {
     347         2024 :             amrex::Box bx = mfi.grownnodaltilebox() & domain;
     348              : 
     349         2024 :             amrex::Array4<model_type> const& model = this->model_mf[lev]->array(mfi);
     350         2024 :             amrex::Array4<const Set::Scalar> const& eta = eta_mf[lev]->array(mfi);
     351              : 
     352       669864 :             amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
     353              :             {
     354       333920 :                 std::vector<Set::Scalar> etas(number_of_grains);
     355      3360576 :                 for (int n = 0; n < number_of_grains; n++)
     356      6053312 :                     etas[n] = Numeric::Interpolate::CellToNodeAverage(eta, i, j, k, n);
     357       333920 :                 model_type mix = model_type::Combine(mechanics.model, etas, mechanics.model_mix_order);
     358       333920 :                 if (a_step == 0 || !shearcouple.on) // Do a complete model initialization
     359       667840 :                     model(i,j,k) = mix ;
     360              :                 else // Otherwise, we will set the modulus only and leave the eigenstrain alone
     361              :                 {
     362            0 :                     Set::Matrix F0 = model(i,j,k).F0;
     363            0 :                     model(i,j,k) = mix;
     364            0 :                     model(i,j,k).F0 = F0;
     365              :                 }
     366       333920 :             });
     367              :         }
     368              : 
     369           11 :         if (mechanics.model_neumann_boundary)
     370              :         {
     371            0 :             Util::AssertException(INFO,TEST(AMREX_SPACEDIM==2),"neumann boundary works in 2d only");
     372            0 :             for (MFIter mfi(*this->model_mf[lev], false); mfi.isValid(); ++mfi)
     373              :             {
     374            0 :                 amrex::Box bx = mfi.grownnodaltilebox() & domain;
     375            0 :                 amrex::Array4<model_type> const& model = this->model_mf[lev]->array(mfi);
     376            0 :                 const Dim3 lo = amrex::lbound(domain), hi = amrex::ubound(domain);
     377              : 
     378            0 :                 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
     379              :                 {
     380            0 :                     if      (i==lo.x && j==lo.y)
     381            0 :                         model(i,j,k) = 0.5*(model(i+1,j,k)+model(i,j+1,k));
     382            0 :                     else if (i==lo.x && j==hi.y)
     383            0 :                         model(i,j,k) = 0.5*(model(i+1,j,k)+model(i,j-1,k));
     384            0 :                     else if (i==hi.x && j==lo.y)
     385            0 :                         model(i,j,k) = 0.5*(model(i-1,j,k)+model(i,j+1,k));
     386            0 :                     else if (i==hi.x && j==hi.y)
     387            0 :                         model(i,j,k) = 0.5*(model(i-1,j,k)+model(i,j-1,k));
     388              : 
     389            0 :                     else if (i==lo.x)
     390            0 :                         model(i,j,k) = model(i+1,j,k);
     391            0 :                     else if (i==hi.x)
     392            0 :                         model(i,j,k) = model(i-1,j,k);
     393            0 :                     else if (j==lo.y)
     394            0 :                         model(i,j,k) = model(i,j+1,k);
     395            0 :                     else if (j==hi.y)
     396            0 :                         model(i,j,k) = model(i,j-1,k);
     397              :                 });
     398              :             }
     399              :         }
     400              : 
     401           11 :         Util::RealFillBoundary(*this->model_mf[lev], this->geom[lev]);
     402              :     }
     403              : 
     404              : }
     405              : 
     406              : template<class model_type>
     407          662 : void PhaseFieldMicrostructure<model_type>::TimeStepBegin(Set::Scalar time, int iter)
     408              : {
     409              :     BL_PROFILE("PhaseFieldMicrostructure::TimeStepBegin");
     410          662 :     for (int lev = 0; lev < totaldf_mf.size(); lev++) totaldf_mf[lev]->setVal(0.0);
     411              : 
     412              :     // Insertion of disconnections
     413          662 :     if (disconnection.on)
     414              :     {
     415            0 :         disconnection.model.Nucleate(eta_mf,this->Geom(),this->timestep,time, iter);
     416            0 :         UpdateEigenstrain();
     417              :     }
     418              :     
     419          662 :     Base::Mechanics<model_type>::TimeStepBegin(time, iter);
     420              : 
     421          660 :     if (anisotropy.on && time >= anisotropy.tstart)
     422              :     {
     423         3136 :         Util::AssertException(  INFO,TEST(this->dynamictimestep.on == false),
     424              :                                 "Cannot use anisotropy with dynamic timestep yet");
     425          448 :         this->SetTimestep(anisotropy.timestep);
     426          448 :         if (anisotropy.elastic_int > 0)
     427            0 :             if (iter % anisotropy.elastic_int) return;
     428              :     }
     429              : }
     430              : 
     431              : template<class model_type>
     432       130262 : void PhaseFieldMicrostructure<model_type>::Integrate(int amrlev, Set::Scalar time, int step,
     433              :     const amrex::MFIter& mfi, const amrex::Box& box)
     434              : {
     435              :     BL_PROFILE("PhaseFieldMicrostructure::Integrate");
     436       130262 :     Base::Mechanics<model_type>::Integrate(amrlev, time, step, mfi, box);
     437              : 
     438       130262 :     Model::Interface::GB::SH gbmodel(0.0, 0.0, anisotropy.sigma0, anisotropy.sigma1);
     439       130262 :     const amrex::Real* DX = this->geom[amrlev].CellSize();
     440       130262 :     Set::Scalar dv = AMREX_D_TERM(DX[0], *DX[1], *DX[2]);
     441              : 
     442       130262 :     amrex::Array4<amrex::Real> const& eta = (*eta_mf[amrlev]).array(mfi);
     443      7175270 :     amrex::ParallelFor(box, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
     444              : #if AMREX_SPACEDIM == 2
     445      7045008 :         auto sten = Numeric::GetStencil(i, j, k, box);
     446              : #endif
     447              : 
     448      7045008 :         volume += eta(i, j, k, 0) * dv;
     449              : 
     450      7045008 :         Set::Vector grad = Numeric::Gradient(eta, i, j, k, 0, DX);
     451      7045008 :         Set::Scalar normgrad = grad.lpNorm<2>();
     452              : 
     453      7045008 :         if (normgrad > 1E-8)
     454              :         {
     455      4845570 :             Set::Vector normal = grad / normgrad;
     456              : 
     457      4845570 :             Set::Scalar da = normgrad * dv;
     458      4845570 :             area += da;
     459              : 
     460      4845570 :             if (!anisotropy.on || time < anisotropy.tstart)
     461              :             {
     462      1282786 :                 gbenergy += pf.sigma0 * da;
     463      1282786 :                 Set::Scalar k = 0.75 * pf.sigma0 * pf.l_gb;
     464      1282786 :                 realgbenergy += 0.5 * k * normgrad * normgrad * dv;
     465      1282786 :                 regenergy = 0.0;
     466      1282786 :             }
     467              :             else
     468              :             {
     469              : #if AMREX_SPACEDIM == 2
     470      3562784 :                 Set::Scalar theta = atan2(grad(1), grad(0));
     471      3562784 :                 Set::Scalar sigma = boundary->W(theta);
     472      3562784 :                 gbenergy += sigma * da;
     473              : 
     474      3562784 :                 Set::Scalar k = 0.75 * sigma * pf.l_gb;
     475      3562784 :                 realgbenergy += 0.5 * k * normgrad * normgrad * dv;
     476              : 
     477      3562784 :                 Set::Matrix DDeta = Numeric::Hessian(eta, i, j, k, 0, DX, sten);
     478      3562784 :                 Set::Vector tangent(normal[1], -normal[0]);
     479      3562784 :                 Set::Scalar k2 = (DDeta * tangent).dot(tangent);
     480      3562784 :                 regenergy += 0.5 * anisotropy.beta * k2 * k2;
     481              : #elif AMREX_SPACEDIM == 3
     482            0 :                 gbenergy += gbmodel.W(normal) * da;
     483              : #endif
     484              :             }
     485              :         }
     486              :     });
     487       130262 : }
     488              : 
     489              : template class PhaseFieldMicrostructure<Model::Solid::Affine::Cubic>;
     490              : template class PhaseFieldMicrostructure<Model::Solid::Affine::Hexagonal>;
     491              : template class PhaseFieldMicrostructure<Model::Solid::Finite::PseudoAffine::Cubic>;
     492              : 
     493              : 
     494              : } // namespace Integrator
        

Generated by: LCOV version 2.0-1