2 #include <eigen3/Eigen/Eigenvalues>
6 #include <AMReX_SPACE.H>
19 #include "Numeric/Stencil.H"
29 template<
class model_type>
32 BL_PROFILE(
"PhaseFieldMicrostructure::Advance");
42 for (amrex::MFIter mfi(*eta_mf[lev], amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
44 amrex::Box bx = mfi.tilebox();
52 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k)
54 for (
int m = 0; m < number_of_grains; m++)
56 driving_force(i, j, k, m) = 0.0;
57 if (pf.threshold.on) driving_force_threshold(i, j, k, m) = 0.0;
72 if (!anisotropy.on || time < anisotropy.tstart)
74 kappa = pf.l_gb * 0.75 * pf.sigma0;
75 mu = 0.75 * (1.0 / 0.23) * pf.sigma0 / pf.l_gb;
76 if (pf.threshold.boundary) driving_force_threshold(i, j, k, m) += -kappa * laplacian;
77 else driving_force(i, j, k, m) += -kappa * laplacian;
82 auto anisotropic_df = boundary->DrivingForce(Deta, DDeta, DDDDEta);
83 if (pf.threshold.boundary) driving_force_threshold(i, j, k, m) += pf.l_gb * 0.75 * std::get<0>(anisotropic_df);
84 else driving_force(i, j, k, m) += pf.l_gb * 0.75 * std::get<0>(anisotropic_df);
86 if (pf.threshold.boundary) driving_force_threshold(i, j, k, m) += anisotropy.beta * std::get<1>(anisotropic_df);
87 else driving_force(i, j, k, m) += anisotropy.beta * std::get<1>(anisotropic_df);
89 mu = 0.75 * (1.0 / 0.23) * boundary->W(Deta) / pf.l_gb;
97 for (
int n = 0; n < number_of_grains; n++)
101 sum_of_squares += eta(i, j, k, n) * eta(i, j, k, n);
103 if (pf.threshold.chempot)
104 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);
106 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);
111 if (lagrange.on && m == 0 && time > lagrange.tstart)
113 if (pf.threshold.lagrange)
114 driving_force_threshold(i, j, k, m) += lagrange.lambda * (volume - lagrange.vol0);
116 driving_force(i, j, k, m) += lagrange.lambda * (volume - lagrange.vol0);
122 if (sdf.on && time > sdf.tstart)
124 if (pf.threshold.sdf)
125 driving_force_threshold(i, j, k, m) += sdf.val[m](time);
127 driving_force(i, j, k, m) += sdf.val[m](time);
137 amrex::Array4<const Set::Matrix>
const& sigma = (*this->stress_mf[lev]).array(mfi);
139 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k)
141 for (
int m = 0; m < number_of_grains; m++)
145 for (
int n = 0; n < number_of_grains; n++)
147 F0avg += eta(i, j, k, n) * mechanics.model[n].F0;
155 for (
int n = 0; n < number_of_grains; n++)
157 if (n == m)
continue;
158 Set::Scalar normsq = eta(i, j, k, m) * eta(i, j, k, m) + eta(i, j, k, n) * eta(i, j, k, n);
159 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))
163 Set::Scalar tmpdf = (dF0deta.transpose() * sig).trace();
165 if (pf.threshold.mechanics)
166 driving_force_threshold(i, j, k, m) -= pf.elastic_mult * tmpdf;
168 driving_force(i, j, k, m) -= pf.elastic_mult * tmpdf;
179 if (!anisotropic_kinetics.on || time < anisotropic_kinetics.tstart)
181 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k)
183 for (
int m = 0; m < number_of_grains; m++)
187 if (driving_force_threshold(i, j, k, m) > pf.threshold.value)
189 if (pf.threshold.type == ThresholdType::Continuous)
190 eta(i, j, k, m) -= pf.L * dt * (driving_force_threshold(i, j, k, m) - pf.threshold.value);
191 else if (pf.threshold.type == ThresholdType::Chop)
192 eta(i, j, k, m) -= pf.L * dt * (driving_force_threshold(i, j, k, m));
194 else if (driving_force_threshold(i, j, k, m) < -pf.threshold.value)
196 if (pf.threshold.type == ThresholdType::Continuous)
197 eta(i, j, k, m) -= pf.L * dt * (driving_force_threshold(i, j, k, m) + pf.threshold.value);
198 else if (pf.threshold.type == ThresholdType::Chop)
199 eta(i, j, k, m) -= pf.L * dt * (driving_force_threshold(i, j, k, m));
203 eta(i, j, k, m) -= pf.L * dt * driving_force(i, j, k, m);
214 if (anisotropic_kinetics.on && time >= anisotropic_kinetics.tstart)
216 for (amrex::MFIter mfi(*eta_mf[lev], amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
218 amrex::Box bx = mfi.tilebox();
219 amrex::Array4<const Set::Scalar>
const& eta = (*eta_mf[lev]).array(mfi);
220 amrex::Array4<Set::Scalar>
const& L = (*anisotropic_kinetics.L_mf[lev]).array(mfi);
221 amrex::Array4<Set::Scalar>
const& threshold = (*anisotropic_kinetics.threshold_mf[lev]).array(mfi);
223 for (
int m = 0; m < number_of_grains; m++)
225 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k)
229 L(i, j, k, m) = (4. / 3.) * anisotropic_kinetics.mobility(theta) / pf.l_gb;
230 threshold(i, j, k, m) = anisotropic_kinetics.threshold(theta);
235 for (amrex::MFIter mfi(*eta_mf[lev], amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
237 amrex::Box bx = mfi.tilebox();
244 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k)
246 for (
int m = 0; m < number_of_grains; m++)
250 if (driving_force_threshold(i, j, k, m) > threshold(i,j,k,m))
252 if (pf.threshold.type == ThresholdType::Continuous)
253 eta(i, j, k, m) -= L(i,j,k,m) * dt * (driving_force_threshold(i, j, k, m) - threshold(i,j,k,m));
254 else if (pf.threshold.type == ThresholdType::Chop)
255 eta(i, j, k, m) -= L(i,j,k,m) * dt * (driving_force_threshold(i, j, k, m));
257 else if (driving_force_threshold(i, j, k, m) < -pf.threshold.value)
259 if (pf.threshold.type == ThresholdType::Continuous)
260 eta(i, j, k, m) -= L(i,j,k,m) * dt * (driving_force_threshold(i, j, k, m) + threshold(i,j,k,m));
261 else if (pf.threshold.type == ThresholdType::Chop)
262 eta(i, j, k, m) -= L(i,j,k,m) * dt * (driving_force_threshold(i, j, k, m));
266 eta(i, j, k, m) -= L(i,j,k,m) * dt * driving_force(i, j, k, m);
273 template<
class model_type>
276 BL_PROFILE(
"PhaseFieldMicrostructure::Initialize");
278 ic->Initialize(lev, eta_mf);
281 template<
class model_type>
284 BL_PROFILE(
"PhaseFieldMicrostructure::TagCellsForRefinement");
286 const amrex::Real* DX = this->geom[lev].CellSize();
290 for (amrex::MFIter mfi(*eta_mf[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi)
292 const amrex::Box& bx = mfi.tilebox();
293 amrex::Array4<const amrex::Real>
const& etanew = (*eta_mf[lev]).array(mfi);
294 amrex::Array4<char>
const& tags = a_tags.array(mfi);
296 for (
int n = 0; n < number_of_grains; n++)
297 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) {
300 if (dxnorm * grad.lpNorm<2>() > ref_threshold)
301 tags(i, j, k) = amrex::TagBox::SET;
306 template<
class model_type>
312 template<
class model_type>
315 BL_PROFILE(
"PhaseFieldMicrostructure::UpdateModel");
316 if (a_step % this->m_interval)
return;
318 for (
int lev = 0; lev <= this->finest_level; ++lev)
320 amrex::Box domain = this->geom[lev].Domain();
321 domain.convert(amrex::IntVect::TheNodeVector());
323 eta_mf[lev]->FillBoundary();
325 for (MFIter mfi(*this->model_mf[lev],
false); mfi.isValid(); ++mfi)
327 amrex::Box bx = mfi.grownnodaltilebox() & domain;
329 amrex::Array4<model_type>
const& model = this->model_mf[lev]->array(mfi);
330 amrex::Array4<const Set::Scalar>
const& eta = eta_mf[lev]->array(mfi);
332 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k)
334 std::vector<Set::Scalar> etas(number_of_grains);
335 for (
int n = 0; n < number_of_grains; n++)
337 model(i, j, k) = model_type::Combine(mechanics.model, etas, 1);
346 template<
class model_type>
349 BL_PROFILE(
"PhaseFieldMicrostructure::TimeStepBegin");
352 if (anisotropy.on && time >= anisotropy.tstart)
354 this->SetTimestep(anisotropy.timestep);
355 if (anisotropy.elastic_int > 0)
356 if (iter % anisotropy.elastic_int)
return;
360 template<
class model_type>
362 const amrex::MFIter& mfi,
const amrex::Box& box)
364 BL_PROFILE(
"PhaseFieldMicrostructure::Integrate");
368 const amrex::Real* DX = this->geom[amrlev].CellSize();
369 Set::Scalar dv = AMREX_D_TERM(DX[0], *DX[1], *DX[2]);
371 amrex::Array4<amrex::Real>
const& eta = (*eta_mf[amrlev]).array(mfi);
372 amrex::ParallelFor(box, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) {
373 #if AMREX_SPACEDIM == 2
377 volume += eta(i, j, k, 0) * dv;
389 if (!anisotropy.on || time < anisotropy.tstart)
391 gbenergy += pf.sigma0 * da;
393 realgbenergy += 0.5 * k * normgrad * normgrad * dv;
398 #if AMREX_SPACEDIM == 2
401 gbenergy += sigma * da;
404 realgbenergy += 0.5 * k * normgrad * normgrad * dv;
409 regenergy += 0.5 * anisotropy.beta * k2 * k2;
410 #elif AMREX_SPACEDIM == 3
411 gbenergy += gbmodel.
W(normal) * da;