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
|