2 #include <eigen3/Eigen/Eigenvalues>
6 #include <AMReX_SPACE.H>
18 #include "Numeric/Stencil.H"
28 template<
class model_type>
31 BL_PROFILE(
"PhaseFieldMicrostructure::Advance");
41 for (amrex::MFIter mfi(*eta_mf[lev], amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
43 amrex::Box bx = mfi.tilebox();
51 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k)
53 for (
int m = 0; m < number_of_grains; m++)
55 driving_force(i, j, k, m) = 0.0;
56 if (pf.threshold.on) driving_force_threshold(i, j, k, m) = 0.0;
71 if (!anisotropy.on || time < anisotropy.tstart)
73 kappa = pf.l_gb * 0.75 * pf.sigma0;
74 mu = 0.75 * (1.0 / 0.23) * pf.sigma0 / pf.l_gb;
75 if (pf.threshold.boundary) driving_force_threshold(i, j, k, m) += -kappa * laplacian;
76 else driving_force(i, j, k, m) += -kappa * laplacian;
81 auto anisotropic_df = boundary->DrivingForce(Deta, DDeta, DDDDEta);
82 if (pf.threshold.boundary) driving_force_threshold(i, j, k, m) += pf.l_gb * 0.75 * std::get<0>(anisotropic_df);
83 else driving_force(i, j, k, m) += pf.l_gb * 0.75 * std::get<0>(anisotropic_df);
85 if (pf.threshold.boundary) driving_force_threshold(i, j, k, m) += anisotropy.beta * std::get<1>(anisotropic_df);
86 else driving_force(i, j, k, m) += anisotropy.beta * std::get<1>(anisotropic_df);
88 mu = 0.75 * (1.0 / 0.23) * boundary->W(Deta) / pf.l_gb;
96 for (
int n = 0; n < number_of_grains; n++)
100 sum_of_squares += eta(i, j, k, n) * eta(i, j, k, n);
102 if (pf.threshold.chempot)
103 driving_force_threshold(i, j, k, m) += 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);
105 driving_force(i, j, k, m) += 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);
110 if (lagrange.on && m == 0 && time > lagrange.tstart)
112 if (pf.threshold.lagrange)
113 driving_force_threshold(i, j, k, m) += lagrange.lambda * (volume - lagrange.vol0);
115 driving_force(i, j, k, m) += lagrange.lambda * (volume - lagrange.vol0);
121 if (sdf.on && time > sdf.tstart)
123 if (pf.threshold.sdf)
124 driving_force_threshold(i, j, k, m) += sdf.val[m](time);
126 driving_force(i, j, k, m) += sdf.val[m](time);
136 amrex::Array4<const Set::Matrix>
const& sigma = (*this->stress_mf[lev]).array(mfi);
138 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k)
140 for (
int m = 0; m < number_of_grains; m++)
144 for (
int n = 0; n < number_of_grains; n++)
146 F0avg += eta(i, j, k, n) * mechanics.model[n].F0;
154 for (
int n = 0; n < number_of_grains; n++)
156 if (n == m)
continue;
157 Set::Scalar normsq = eta(i, j, k, m) * eta(i, j, k, m) + eta(i, j, k, n) * eta(i, j, k, n);
158 dF0deta += (2.0 * eta(i, j, k, m) * eta(i, j, k, n) * eta(i, j, k, n) * (mechanics.model[m].F0 - mechanics.model[n].F0))
162 Set::Scalar tmpdf = (dF0deta.transpose() * sig).trace();
164 if (pf.threshold.mechanics)
165 driving_force_threshold(i, j, k, m) -= pf.elastic_mult * tmpdf;
167 driving_force(i, j, k, m) -= pf.elastic_mult * tmpdf;
178 if (!anisotropic_kinetics.on || time < anisotropic_kinetics.tstart)
180 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k)
182 for (
int m = 0; m < number_of_grains; m++)
186 if (driving_force_threshold(i, j, k, m) > pf.threshold.value)
188 if (pf.threshold.type == ThresholdType::Continuous)
189 eta(i, j, k, m) -= pf.L * dt * (driving_force_threshold(i, j, k, m) - pf.threshold.value);
190 else if (pf.threshold.type == ThresholdType::Chop)
191 eta(i, j, k, m) -= pf.L * dt * (driving_force_threshold(i, j, k, m));
193 else if (driving_force_threshold(i, j, k, m) < -pf.threshold.value)
195 if (pf.threshold.type == ThresholdType::Continuous)
196 eta(i, j, k, m) -= pf.L * dt * (driving_force_threshold(i, j, k, m) + pf.threshold.value);
197 else if (pf.threshold.type == ThresholdType::Chop)
198 eta(i, j, k, m) -= pf.L * dt * (driving_force_threshold(i, j, k, m));
202 eta(i, j, k, m) -= pf.L * dt * driving_force(i, j, k, m);
213 if (anisotropic_kinetics.on && time >= anisotropic_kinetics.tstart)
215 for (amrex::MFIter mfi(*eta_mf[lev], amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
217 amrex::Box bx = mfi.tilebox();
218 amrex::Array4<const Set::Scalar>
const& eta = (*eta_mf[lev]).array(mfi);
219 amrex::Array4<Set::Scalar>
const& L = (*anisotropic_kinetics.L_mf[lev]).array(mfi);
220 amrex::Array4<Set::Scalar>
const& threshold = (*anisotropic_kinetics.threshold_mf[lev]).array(mfi);
222 for (
int m = 0; m < number_of_grains; m++)
224 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k)
228 L(i, j, k, m) = (4. / 3.) * anisotropic_kinetics.mobility(theta) / pf.l_gb;
229 threshold(i, j, k, m) = anisotropic_kinetics.threshold(theta);
234 for (amrex::MFIter mfi(*eta_mf[lev], amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
236 amrex::Box bx = mfi.tilebox();
243 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k)
245 for (
int m = 0; m < number_of_grains; m++)
249 if (driving_force_threshold(i, j, k, m) > threshold(i,j,k,m))
251 if (pf.threshold.type == ThresholdType::Continuous)
252 eta(i, j, k, m) -= L(i,j,k,m) * dt * (driving_force_threshold(i, j, k, m) - threshold(i,j,k,m));
253 else if (pf.threshold.type == ThresholdType::Chop)
254 eta(i, j, k, m) -= L(i,j,k,m) * dt * (driving_force_threshold(i, j, k, m));
256 else if (driving_force_threshold(i, j, k, m) < -pf.threshold.value)
258 if (pf.threshold.type == ThresholdType::Continuous)
259 eta(i, j, k, m) -= L(i,j,k,m) * dt * (driving_force_threshold(i, j, k, m) + threshold(i,j,k,m));
260 else if (pf.threshold.type == ThresholdType::Chop)
261 eta(i, j, k, m) -= L(i,j,k,m) * dt * (driving_force_threshold(i, j, k, m));
265 eta(i, j, k, m) -= L(i,j,k,m) * dt * driving_force(i, j, k, m);
272 template<
class model_type>
275 BL_PROFILE(
"PhaseFieldMicrostructure::Initialize");
277 ic->Initialize(lev, eta_mf);
280 template<
class model_type>
283 BL_PROFILE(
"PhaseFieldMicrostructure::TagCellsForRefinement");
285 const amrex::Real* DX = this->geom[lev].CellSize();
289 for (amrex::MFIter mfi(*eta_mf[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi)
291 const amrex::Box& bx = mfi.tilebox();
292 amrex::Array4<const amrex::Real>
const& etanew = (*eta_mf[lev]).array(mfi);
293 amrex::Array4<char>
const& tags = a_tags.array(mfi);
295 for (
int n = 0; n < number_of_grains; n++)
296 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) {
299 if (dxnorm * grad.lpNorm<2>() > ref_threshold)
300 tags(i, j, k) = amrex::TagBox::SET;
305 template<
class model_type>
311 template<
class model_type>
314 BL_PROFILE(
"PhaseFieldMicrostructure::UpdateModel");
315 if (a_step % this->m_interval)
return;
317 for (
int lev = 0; lev <= this->finest_level; ++lev)
319 amrex::Box domain = this->geom[lev].Domain();
320 domain.convert(amrex::IntVect::TheNodeVector());
322 eta_mf[lev]->FillBoundary();
324 for (MFIter mfi(*this->model_mf[lev],
false); mfi.isValid(); ++mfi)
326 amrex::Box bx = mfi.grownnodaltilebox() & domain;
328 amrex::Array4<model_type>
const& model = this->model_mf[lev]->array(mfi);
329 amrex::Array4<const Set::Scalar>
const& eta = eta_mf[lev]->array(mfi);
331 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k)
333 std::vector<Set::Scalar> etas(number_of_grains);
334 for (
int n = 0; n < number_of_grains; n++)
336 model(i, j, k) = model_type::Combine(mechanics.model, etas, 1);
345 template<
class model_type>
348 BL_PROFILE(
"PhaseFieldMicrostructure::TimeStepBegin");
351 if (anisotropy.on && time >= anisotropy.tstart)
353 this->SetTimestep(anisotropy.timestep);
354 if (anisotropy.elastic_int > 0)
355 if (iter % anisotropy.elastic_int)
return;
359 template<
class model_type>
361 const amrex::MFIter& mfi,
const amrex::Box& box)
363 BL_PROFILE(
"PhaseFieldMicrostructure::Integrate");
367 const amrex::Real* DX = this->geom[amrlev].CellSize();
368 Set::Scalar dv = AMREX_D_TERM(DX[0], *DX[1], *DX[2]);
370 amrex::Array4<amrex::Real>
const& eta = (*eta_mf[amrlev]).array(mfi);
371 amrex::ParallelFor(box, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) {
372 #if AMREX_SPACEDIM == 2
376 volume += eta(i, j, k, 0) * dv;
388 if (!anisotropy.on || time < anisotropy.tstart)
390 gbenergy += pf.sigma0 * da;
392 realgbenergy += 0.5 * k * normgrad * normgrad * dv;
397 #if AMREX_SPACEDIM == 2
400 gbenergy += sigma * da;
403 realgbenergy += 0.5 * k * normgrad * normgrad * dv;
408 regenergy += 0.5 * anisotropy.beta * k2 * k2;
409 #elif AMREX_SPACEDIM == 3
410 gbenergy += gbmodel.
W(normal) * da;