Mechanics of Defect Evolution Library
Loading...
Searching...
No Matches
ClusterDynamicsFEM.cpp
Go to the documentation of this file.
1/* This file is part of MoDELib, the Mechanics Of Defects Evolution Library.
2 *
3 *
4 * MoDELib is distributed without any warranty under the
5 * GNU General Public License (GPL) v2 <http://www.gnu.org/licenses/>.
6 */
7
8#ifndef model_ClusterDynamicsFEM_cpp_
9#define model_ClusterDynamicsFEM_cpp_
10
11#include <cmath>
12#include <ClusterDynamicsFEM.h>
13#include <Eigen/SVD>
14#include <Fix.h>
15
16namespace model
17{
18
19 template<int dim>
21 /* init */cdp(cdp_in)
22 {
23
24 }
25
26 template<int dim>
28 {
29
30 const size_t grainID(elem.simplex.region->regionID);
31 MatrixType D(MatrixType::Zero());
32 for(size_t k=0;k<mSize;++k)
33 {
34 D.template block<dim,dim>(k*dim,k*dim)=-cdp.D.at(grainID)[k]/cdp.omega;
35 }
36
37 // for(size_t k=0;k<mSize;++k)
38 // {
39 // std::cout
40 // << " species " << k
41 // << " D trace = "
42 // << cdp.D.at(grainID)[k].trace()
43 // << std::endl;
44 // }
45
46 return D;
47 }
48
49 template struct FluxMatrix<3>;
50
51template<int dim>
53/* init */cdp(cdp_in)
54{
55
56}
57
58template<int dim>
60{
61 const size_t grainID(elem.simplex.region->regionID);
62 MatrixType InvDscaling(MatrixType::Zero());
63 for(size_t k=0;k<mSize;++k)
64 {
65 InvDscaling(k,k)=3.0/(cdp.D.at(grainID)[k].trace()/cdp.omega);
66// InvDscaling(k,k)=(cdp.D.at(grainID)[k].trace()/cdp.omega)/3.0;
67// InvDscaling(k,k)=1.0;
68
69 }
70 return InvDscaling;
71}
72
73template struct InvDscaling<3>;
74
75
76 template<int dim>
78 /* init */ ddBase(ddBase_in)
79 /* init */,cdp(cdp_in)
80 /* init */,iDs(std::make_shared<InvDscaling<dim>>(cdp))
81 /* init */,mobileClusters(ddBase.fe->template trial<'m',mSize>())
82 /* init */,mobileGrad(grad(mobileClusters))
83 /* init */,mobileFlux(std::make_shared<FluxMatrix<dim>>(cdp)*mobileGrad)
84 /* init */,immobileClusters(ddBase.fe->template trial<'i',iSize>())
86 /* init */,mobileClustersIncrement(ddBase.fe->template trial<'d',mSize>())
87 /* init */,dV(ddBase.fe->template domain<EntireDomain,dVorder,GaussLegendre>())
88// /* init */,mBWF((test(this->mobileGrad),-ddBase.poly.Omega*this->mobileFlux)*dV)
89 /* init */,mBWF((test(grad(iDs*mobileClusters)),-ddBase.poly.Omega*this->mobileFlux)*dV)
90 /* init */,dmBWF((test(grad(iDs*mobileClustersIncrement)),-ddBase.poly.Omega*(std::make_shared<FluxMatrix<dim>>(this->cdp)*grad(mobileClustersIncrement)))*dV)
91 /* init */,immobileRateTrial(ddBase.fe->template trial<'r',iSize>())
92 /* init */,solverInitialized(false)
93 /* init */,cascadeGlobalProduction(((test(iDs*this->mobileClusters),make_constant(this->cdp.G))*dV)->globalVector())
94 // /* init */,cascadeGlobalProduction(((test(this->mobileClusters),make_constant(this->cdp.G))*dV)->globalVector())
95
96 {
97 mobileClustersIncrement->setConstant(Eigen::Matrix<double,mSize,1>::Zero());
98 mobileClusters->setConstant(cdp.equilibriumMobileConcentration(0.0).matrix().transpose());
99 // immobileClusters->setConstant(Eigen::Matrix<double,iSize,1>::Zero());
100 immobileClusters->setConstant(cdp.initLoopSinks);
101 immobileClusterRate = Eigen::VectorXd::Zero(immobileClusters->gSize());
102 }
103
104 template<int dim>
106 {
107 auto values=mobileClusters->dofVector();
108 std::map<size_t,double> fixed;
109 const auto& offset=mobileClusters->periodicNodalOffset();
110 const auto lift=[&](size_t node,int component)
111 {
112 const size_t root=ddBase.fe->periodicRepresentative(node);
113 return offset.size()? offset(node*mSize+component)-offset(root*mSize+component) : 0.0;
114 };
115 for(const auto& bc : mobileClusters->dirichletConditions())
116 {
117 const size_t node=bc.first/mSize;
118 const int component=bc.first%mSize;
119 const size_t root=ddBase.fe->periodicRepresentative(node)*mSize+component;
120 const double value=bc.second-lift(node,component);
121 const auto inserted=fixed.emplace(root,value);
122 if(!inserted.second && std::abs(inserted.first->second-value)>1.e-8*std::max({1.e-50,std::abs(value),std::abs(inserted.first->second)}))
123 {
124 throw std::runtime_error("ClusterDynamics: incompatible concentrations on periodic sink nodes.");
125 }
126 }
127 for(size_t node=0;node<ddBase.fe->nodeSize();++node)
128 {
129 for(int c=0;c<mSize;++c)
130 {
131 const size_t root=ddBase.fe->periodicRepresentative(node)*mSize+c;
132 values(node*mSize+c)=(fixed.count(root)? fixed.at(root) : mobileClusters->dofVector()(root))+lift(node,c);
133 }
134 }
135 mobileClusters->setFullDofVector(values);
136 }
137
138 template<int dim>
139 Eigen::MatrixXd ClusterDynamicsFEM<dim>::conservedRows(const bool useImmobileClusters) const
140 {
141 if(!sinkNormals.empty())
142 {
143 return Eigen::MatrixXd(0,mobileClusters->gSize());
144 }
145 std::vector<Eigen::Matrix<double,mSize,1>> directions;
146 const auto append=[&](const Eigen::Matrix<double,mSize,mSize>& matrix)
147 {
148 for(int c=0;c<mSize;++c)
149 {
150 if(matrix.col(c).norm()>0.0)
151 {
152 directions.push_back(matrix.col(c).normalized());
153 }
154 }
155 };
156 if(cdp.computeReactions)
157 {
158 append(cdp.R1cd);
159 for(int j=0;j<mSize;++j)
160 {
161 Eigen::Matrix<double,mSize,mSize> matrix;
162 for(int row=0;row<mSize;++row)
163 {
164 for(int k=0;k<mSize;++k)
165 {
166 matrix(row,k)=std::abs(cdp.msVector(row))*cdp.R2[row](j,k)/std::abs(cdp.msVector(j)*cdp.msVector(k));
167 }
168 }
169 append(matrix);
170 }
171 if(useImmobileClusters)
172 {
174 for(const auto& entry : ddBase.fe->elements())
175 {
176 // Include every interpolation node, not only element centers.
177 for(int n=0;n<ElementType::nodesPerElement;++n)
178 {
179 append(sink(entry.second,ElementType::baryStarsAndBars.row(n).template cast<double>().transpose()/ElementType::order));
180 }
181 }
182 }
183 }
184 Eigen::MatrixXd invariants=Eigen::MatrixXd::Identity(mSize,mSize);
185 if(!directions.empty())
186 {
187 Eigen::MatrixXd matrix(mSize,directions.size());
188 for(size_t k=0;k<directions.size();++k)
189 {
190 matrix.col(k)=directions[k];
191 }
192 Eigen::JacobiSVD<Eigen::MatrixXd> svd(matrix,Eigen::ComputeFullU);
193 svd.setThreshold(1.e-10);
194 invariants=svd.matrixU().rightCols(mSize-svd.rank());
195 }
196 const Eigen::VectorXd production=cdp.G;
197 if((invariants.transpose()*production).norm()>1.e-10*production.norm())
198 {
199 throw std::runtime_error("ClusterDynamics: no steady state in the closed periodic domain; production changes a conserved species inventory.");
200 }
201 return invariants.transpose()*meanRows;
202 }
203
204 template<int dim>
205 void ClusterDynamicsFEM<dim>::solveMobileClusters(const bool hasDiscreteLoops)
206 {
207 std::cout<<", mobile solver, "<<std::flush;
208 const Eigen::VectorXd saved=mobileClusters->dofVector();
209 const Eigen::VectorXd savedIncrement=mobileClustersIncrement->dofVector();
210 try
211 {
213 const bool useImmobileClusters(!hasDiscreteLoops && iSize>0);
214 const Eigen::MatrixXd conserved=conservedRows(useImmobileClusters);
215 const Eigen::VectorXd inventory=conserved*mobileClusters->dofVector();
216 if(!cdp.computeReactions)
217 {
218 if(mSolver->factorizationCount()==0)
219 {
220 mSolver->setLinearConstraints(conserved);
221 }
222 mSolver->setLinearConstraintValues(inventory);
223 mSolver->solveWithMasterSlaveConstraints();
224 return;
225 }
226 // Do not solve singular diffusion alone in a closed periodic domain.
227 const auto R1=cdp.R1cd.eval();
228 auto sink=std::make_shared<FirstOrderReaction<MobileTrialType,ImmobileTrialType>>(immobileClusters,cdp,ddBase.poly);
229 auto R2=std::make_shared<SecondOrderReaction<MobileTrialType>>(mobileClusters,cdp);
236 const auto residual=[&]() -> Eigen::VectorXd
237 {
238 Eigen::VectorXd result=cascadeGlobalProduction-diffusionMatrix*mobileClusters->dofVector()+f1->globalVector()+f2->globalVector();
239 if(useImmobileClusters)
240 {
241 result+=fs->globalVector();
242 }
243 return result;
244 };
245 const auto reducedNorm=[&](const Eigen::VectorXd& value)
246 {
247 Eigen::VectorXd reduced=Eigen::VectorXd::Zero(value.size());
248 std::set<size_t> fixed;
249 for(const auto& bc : mobileClusters->dirichletConditions())
250 {
251 fixed.insert(ddBase.fe->periodicRepresentative(bc.first/mSize)*mSize+bc.first%mSize);
252 }
253 for(size_t n=0;n<ddBase.fe->nodeSize();++n)
254 {
255 for(int c=0;c<mSize;++c)
256 {
257 const size_t root=ddBase.fe->periodicRepresentative(n)*mSize+c;
258 if(!fixed.count(root))
259 {
260 reduced(root)+=value(n*mSize+c);
261 }
262 }
263 }
264 return reduced.norm();
265 };
266 rSolver->setLinearConstraints(conserved);
267 double reference=0.0;
268 for(int iteration=0;iteration<60;++iteration)
269 {
270 reactionLoad->value=residual();
271 const double error=reducedNorm(reactionLoad->value);
272 if(iteration==0)
273 {
274 reference=std::max({error,reducedNorm(cascadeGlobalProduction),1.e-50});
275 }
276 if(error<=1.e-8*reference)
277 {
278 return;
279 }
281 const auto append=[&](const auto& form)
282 {
283 const auto entries=form->globalTriplets();
284 reactionMatrix->entries.insert(reactionMatrix->entries.end(),entries.begin(),entries.end());
285 };
286 append(j1);
287 append(j2);
288 if(useImmobileClusters)
289 {
290 append(js);
291 }
292 rSolver->setLinearConstraintValues(inventory-conserved*mobileClusters->dofVector());
293 rSolver->reassembleMatrix();
294 rSolver->solveWithMasterSlaveConstraints();
295 const Eigen::VectorXd old=mobileClusters->dofVector();
296 bool accepted=false;
297 for(int backtrack=0;backtrack<24;++backtrack)
298 {
299 const double step=std::ldexp(1.0,-backtrack);
300 mobileClusters->setFullDofVector(old+step*mobileClustersIncrement->dofVector());
301 Eigen::VectorXd total=mobileClusters->dofVector();
302 if(mobileClusters->periodicNodalOffset().size())
303 {
304 total-=mobileClusters->periodicNodalOffset();
305 }
306 if(total.minCoeff()< -1.e-12*std::max(1.e-50,total.cwiseAbs().maxCoeff()))
307 {
308 continue;
309 }
310 const double trialError=reducedNorm(residual());
311 if(std::isfinite(trialError) && (trialError<error || trialError<=1.e-8*reference))
312 {
313 accepted=true;
314 break;
315 }
316 }
317 if(!accepted)
318 {
319 throw std::runtime_error("ClusterDynamics: reaction iteration failed to reduce the residual.");
320 }
321 }
322 throw std::runtime_error("ClusterDynamics: reaction iteration exceeded 60 steps.");
323 }
324 catch(...)
325 {
326 mobileClusters->setFullDofVector(saved);
327 mobileClustersIncrement->setFullDofVector(savedIncrement);
328 throw;
329 }
330 }
331
332 template<int dim>
334 {
335 if constexpr(iSize>0)
336 {
337 auto rate=std::make_shared<ImmobileSinkRate<MobileTrialType,ImmobileTrialType>>(mobileClusters,immobileClusters,cdp,ddBase.poly);
338 auto rhs=(test(immobileRateTrial),rate)*dV;
339 if(!iSolver)
340 {
342 WeakProblemOptions options;
343 options.useDirectSolver=false;
344 iSolver=weakProblem<Eigen::SparseLU<SparseMatrixType>,Eigen::BiCGSTAB<SparseMatrixType>>(mass,rhs,options);
345 }
346 else
347 {
348 iSolver->setRightHandSide(rhs);
349 }
350 iSolver->solveWithMasterSlaveConstraints();
352 }
353 }
354
355 template<int dim>
357 {
358 immobileClusters->dofVector()+=immobileClusterRate * dt;
359 for(size_t nodeID=0; nodeID<immobileClusters->nodeSize(); nodeID++)
360 {
361 for(int dof=0;dof<iSize/2;dof++)
362 { // Corrected sink strength is to adjust for negative values at the barycenter of the quadratic elements where we have a sharp gradient of sink values between two end nodes
363 // rmin = r_min * omega * N
364 const double cmin = this->cdp.n_min(dof)*this->cdp.omega*immobileClusters->dofVector()(iSize*nodeID+dof);
365 if(immobileClusters->dofVector()(iSize*nodeID+iSize/2+dof)<cmin) // Nc, Na1, Na2, Na3, c, ca1, ca2, ca3
366 { // Loop size cannot be smaller than a minimal value
367 immobileClusters->dofVector()(iSize*nodeID+iSize/2+dof)=cmin;
368 }
369 }
370 }
371 for(size_t node=0;node<ddBase.fe->nodeSize();++node)
372 {
373 const size_t root=ddBase.fe->periodicRepresentative(node);
374 if(root!=node)
375 {
376 immobileClusters->dofVector().template segment<iSize>(iSize*node)=
377 immobileClusters->dofVector().template segment<iSize>(iSize*root);
378 }
379 }
380 }
381
382
383 template<int dim>
384 void ClusterDynamicsFEM<dim>::solve(const bool hasDiscreteLoops)
385 {
386 const Eigen::VectorXd mobile=mobileClusters->dofVector();
387 const Eigen::VectorXd increment=mobileClustersIncrement->dofVector();
388 const Eigen::VectorXd rate=immobileClusterRate;
389 const Eigen::VectorXd rateTrial=immobileRateTrial->dofVector();
390 try
391 {
392 solveMobileClusters(hasDiscreteLoops);
393 if(!hasDiscreteLoops && iSize>0)
394 {
396 }
397 else
398 {
399 immobileClusterRate.setZero();
400 }
401 }
402 catch(...)
403 {
404 mobileClusters->setFullDofVector(mobile);
405 mobileClustersIncrement->setFullDofVector(increment);
407 immobileRateTrial->setFullDofVector(rateTrial);
408 throw;
409 }
410 }
411
412 template<int dim>
414 {
415 for(const auto& entry : sinkNormals)
416 {
417 for(int c=0;c<mSize;++c)
418 {
419 mobileClusters->dirichletConditions()[entry.first*mSize+c]=0.0;
420 mobileClustersIncrement->dirichletConditions()[entry.first*mSize+c]=0.0;
421 }
422 }
423 diffusionTriplets=dmBWF->globalTriplets();
424 diffusionMatrix.resize(mobileClusters->gSize(),mobileClusters->gSize());
425 diffusionMatrix.setFromTriplets(diffusionTriplets.begin(),diffusionTriplets.end());
426 mobileLoad=std::make_shared<Load<MobileTrialType>>(Load<MobileTrialType>{mobileClusters,cascadeGlobalProduction});
427 reactionLoad=std::make_shared<Load<MobileIncrementTrialType>>(Load<MobileIncrementTrialType>{mobileClustersIncrement,Eigen::VectorXd::Zero(mobileClusters->gSize())});
428 reactionMatrix=std::make_shared<MatrixForm<MobileIncrementTrialType>>(MatrixForm<MobileIncrementTrialType>{mobileClustersIncrement,diffusionTriplets});
429 mSolver=weakProblem<Eigen::SparseLU<SparseMatrixType>,Eigen::BiCGSTAB<SparseMatrixType>>(mBWF,mobileLoad);
430 WeakProblemOptions reactionOptions;
431 // Preserve iterative reaction solves on surface/GB-bounded domains.
432 // Closed domains may need an indefinite conservation-constrained solve.
433 reactionOptions.useDirectSolver=sinkNormals.empty();
434 rSolver=weakProblem<Eigen::SparseLU<SparseMatrixType>,Eigen::BiCGSTAB<SparseMatrixType>>(reactionMatrix,reactionLoad,reactionOptions);
435 meanRows=Eigen::MatrixXd::Zero(mSize,mobileClusters->gSize());
436 for(int c=0;c<mSize;++c)
437 {
438 Eigen::Matrix<double,mSize,1> unit=Eigen::Matrix<double,mSize,1>::Zero();
439 unit(c)=1.0;
440 meanRows.row(c)=((test(mobileClusters),make_constant(unit))*dV)->globalVector().transpose()/ddBase.mesh.volume();
441 }
443 }
444
445 template<int dim>
446 void ClusterDynamicsFEM<dim>::initializeConfiguration(const DefectiveCrystalConfigIO<dim>& configIO,const std::ofstream& f_file,const std::ofstream& F_labels)
447 {
448 if(size_t(configIO.cdMatrix().size())==mobileClusters->gSize()+immobileClusters->gSize())
449 {
450 const size_t nNodes(mobileClusters->fe().nodes().size());
451 const Eigen::VectorXd mobile=configIO.cdMatrix().block(0,0,nNodes,mSize).transpose().reshaped(mobileClusters->gSize(),1);
452 const Eigen::VectorXd immobile=configIO.cdMatrix().block(0,mSize,nNodes,iSize).transpose().reshaped(immobileClusters->gSize(),1);
453 for(const auto& pair : ddBase.fe->periodicNodePairs())
454 {
455 const auto a=immobile.template segment<iSize>(iSize*pair.source);
456 const auto b=immobile.template segment<iSize>(iSize*pair.sink);
457 if((a-b).norm()>1.e-8*std::max({1.e-50,a.norm(),b.norm()}))
458 {
459 throw std::runtime_error("ClusterDynamics: restart immobile concentrations violate active periodic pairs.");
460 }
461 }
462 mobileClusters->setFullDofVector(mobile);
463 immobileClusters->setFullDofVector(immobile);
464
465 }
466 else
467 {
468 if(configIO.cdMatrix().size())
469 {
470 throw std::runtime_error("ClusterDynamics: TrialFunctions initializatoin size mismatch");
471 }
472 }
473 }
474
475
476 template<int dim>
477 typename ClusterDynamicsFEM<dim>::VectorDim ClusterDynamicsFEM<dim>::inelasticDisplacementRate(const VectorDim& x, const NodeType* const node, const ElementType* const ele,const SimplexDim* const guess) const
478 {
479 Eigen::Matrix<double,dim*mSize,1> speciesFlux(Eigen::Matrix<double,dim*mSize,1>::Zero());
480 if(node)
481 {
482 speciesFlux=(*eval(this->mobileFlux))(*node);
483 }
484 else
485 {
486 if(ele)
487 {
488 speciesFlux=(*eval(this->mobileFlux))(*ele,ele->simplex.pos2bary(x));
489 }
490 else
491 {
492 speciesFlux=(*eval(this->mobileFlux))(x,guess);
493 }
494 }
495 Eigen::Matrix<double,dim,1> netFlux(Eigen::Matrix<double,dim,1>::Zero());
496 for(int i=0; i<mSize; i++)
497 {
498 const int mSgn(this->cdp.msVector(i)/std::abs(this->cdp.msVector(i)));
499 netFlux += speciesFlux.template block<dim,1>(i*dim,0)*mSgn;
500 }
501 return netFlux;
502 }
503
504
505 template<int dim>
506 std::vector<Eigen::Matrix<double,dim,dim>> ClusterDynamicsFEM<dim>::betaP(const ElementType& ele, const BaryType& bary) const
507 {
508 std::vector<Eigen::Matrix<double,dim,dim>> strainVector;
509 const Eigen::Matrix<double,iSize,1> sinkValue((*eval(immobileClusters))(ele,bary));
510 Eigen::Matrix<double,iSize,1> correctedSinkValue(sinkValue);
511 for(int dof=0;dof<iSize/2;dof++)
512 {
513 const double cmin = cdp.n_min(dof)*cdp.omega*correctedSinkValue(dof);
514 if(correctedSinkValue(iSize/2+dof)<cmin)
515 { // Loop size cannot be smaller than a minimal value
516 correctedSinkValue(iSize/2+dof)=cmin;
517 }
518 }
519 const size_t gID(ele.simplex.region->regionID);
520 const Eigen::Matrix<double,dim,dim> lat(ddBase.poly.grains.at(gID)->latticeBasis);
521 const Eigen::Matrix<double,dim,iSize/2> localBurgers(lat*cdp.immobileSpeciesBurgers);
522 const Eigen::Array<double,1,iSize/2> cr(cdp.clusterRadius(correctedSinkValue.template block<iSize/2,1>(iSize/2,0),correctedSinkValue.template block<iSize/2,1>(0,0)));
523 const Eigen::Matrix<double,1,dim> localx(lat.col(0).normalized());
524 const Eigen::Matrix<double,1,dim> localy((2.0*lat.col(1)-lat.col(0)).normalized());
525 const Eigen::Matrix<double,1,dim> localz(lat.col(2).normalized());
526 for(int k=0; k<iSize/2; k++)
527 { // N A b ^b*^b
528 Eigen::Matrix<double,dim,dim> tempStrain(Eigen::Matrix<double,dim,dim>::Zero());
529 const double Area=M_PI*std::pow(cr(k),2);
530 const Eigen::Matrix<double,dim,dim> highValue(cdp.immobileSpeciesVector(k)*correctedSinkValue(k)*Area*localBurgers.col(k)*localBurgers.col(k).normalized().transpose());
531 const Eigen::Matrix<double,dim,dim> lowValue(cdp.immobileSpeciesVector(k)*correctedSinkValue(k)*cdp.delVPyramid*(localx.transpose()*localx+localy.transpose()*localy+localz.transpose()*localz)/3.0);
532 tempStrain+=cdp.sigmoidalMatrixInterpolation(correctedSinkValue.template block<iSize/2,1>(iSize/2,0),correctedSinkValue.template block<iSize/2,1>(0,0),lowValue,highValue,k).matrix();
533 strainVector.push_back(tempStrain);
534 }
535 return strainVector;
536 }
537
538
539 template<int dim>
540 std::vector<Eigen::Matrix<double,dim,dim>> ClusterDynamicsFEM<dim>::betaV(const ElementType& ele, const BaryType& bary) const
541 {
542 std::vector<Eigen::Matrix<double,dim,dim>> strainVector;
543 const Eigen::Matrix<double,iSize,1> sinkValue((*eval(immobileClusters))(ele,bary));
544 Eigen::Matrix<double,iSize,1> correctedSinkValue(sinkValue);
545 for(int dof=0;dof<iSize/2;dof++)
546 {
547 const double cmin = cdp.n_min(dof)*cdp.omega*correctedSinkValue(dof);
548 if(correctedSinkValue(iSize/2+dof)<cmin)
549 { // Loop size cannot be smaller than a minimal valu
550 correctedSinkValue(iSize/2+dof)=cmin;
551 }
552 }
553 const size_t gID(ele.simplex.region->regionID);
554 const Eigen::Matrix<double,dim,dim> lat(ddBase.poly.grains.at(gID)->latticeBasis);
555 const Eigen::Matrix<double,dim,iSize/2> localBurgers(lat*cdp.immobileSpeciesBurgers);
556 const Eigen::Matrix<double,1,dim> localx(lat.col(0).normalized());
557 const Eigen::Matrix<double,1,dim> localy((2.0*lat.col(1)-lat.col(0)).normalized());
558 const Eigen::Matrix<double,1,dim> localz(lat.col(2).normalized());
559 const Eigen::Array<double,1,iSize/2> cr(cdp.clusterRadius(correctedSinkValue.template block<iSize/2,1>(iSize/2,0),correctedSinkValue.template block<iSize/2,1>(0,0)));
560 for(int k=0; k<iSize/2; k++)
561 { // N A b ^b*^b
562 Eigen::Matrix<double,dim,dim> tempStrain(Eigen::Matrix<double,dim,dim>::Zero());
563 const double Area=M_PI*std::pow(cr(k),2);
564 const Eigen::Matrix<double,dim,dim> highValue(cdp.immobileSpeciesRelRelaxVol(k)*cdp.immobileSpeciesVector(k)*correctedSinkValue(k)*Area*localBurgers.col(k)*localBurgers.col(k).normalized().transpose());
565 const Eigen::Matrix<double,dim,dim> lowValue(cdp.immobileSpeciesRelRelaxVol(k)*cdp.immobileSpeciesVector(k)*correctedSinkValue(k)*cdp.delVPyramid*(localx.transpose()*localx+localy.transpose()*localy+localz.transpose()*localz)/3.0);
566 tempStrain+=cdp.sigmoidalMatrixInterpolation(correctedSinkValue.template block<iSize/2,1>(iSize/2,0),correctedSinkValue.template block<iSize/2,1>(0,0),lowValue,highValue,k).matrix();
567 strainVector.push_back(tempStrain);
568 }
569 // Add up the contribution from the mobile species
570 Eigen::Matrix<double,dim,dim> tempStrain(Eigen::Matrix<double,dim,dim>::Zero());
571 const Eigen::Matrix<double,mSize,1> inFactors((1.0/cdp.msVector.abs()).matrix());
572 const Eigen::Matrix<double,mSize,1> localConcentration(inFactors.asDiagonal()*(*eval(mobileClusters))(ele,bary)); // Local concentration
573 for(int k=0; k<mSize; k++)
574 {
575 tempStrain += 1.0/3.0*cdp.msVector(k)*localConcentration(k)*cdp.msRelRelaxVol(k)*Eigen::Matrix<double,dim,dim>::Identity();
576 }
577 strainVector.push_back(tempStrain);
578 return strainVector;
579 }
580
581
582 /* plastic distortion */
583 template<int dim>
584 typename ClusterDynamicsFEM<dim>::MatrixDim ClusterDynamicsFEM<dim>::averageBetaPKernel(const Eigen::Matrix<double,dim,1>& a1, const ElementType& ele) const
585 {
586 const auto bary(BarycentricTraits<dim>::x2l(a1));
587
588 const std::vector<Eigen::Matrix<double,dim,dim>> bps(betaP(ele,bary));
589 Eigen::Matrix<double,dim,dim> temp(Eigen::Matrix<double,dim,dim>::Zero());
590 for(const Eigen::Matrix<double,dim,dim>& bp : bps)
591 {
592 temp += bp*ele.absJ(bary);
593 }
594 return temp;
595 // return betaP(ele,bary)[0]*ele.absJ(bary);
596 }
597 template<int dim>
599 {
600 Eigen::Matrix<double,dim,dim> temp(Eigen::Matrix<double,dim,dim>::Zero());
601 // dV.integrate(this,temp,&ClusterDynamicsFEM<dim>::averageBetaPKernel); // integrate through the volume
602 for(size_t k=0; k<dV.size(); ++k)
603 {
604 VolumeIntegrationDomainType::QuadratureType::integrate(this,temp,&ClusterDynamicsFEM<dim>::averageBetaPKernel,dV.element(k));
605 }
606 return temp/ddBase.poly.mesh.volume();
607 }
608
609 /* volumetric distortion */
610 template<int dim>
611 typename ClusterDynamicsFEM<dim>::MatrixDim ClusterDynamicsFEM<dim>::averageBetaVKernel(const Eigen::Matrix<double,dim,1>& a1, const ElementType& ele) const
612 {
613 const auto bary(BarycentricTraits<dim>::x2l(a1));
614
615 const std::vector<Eigen::Matrix<double,dim,dim>> bvs(betaV(ele,bary));
616 Eigen::Matrix<double,dim,dim> temp(Eigen::Matrix<double,dim,dim>::Zero());
617 for(const Eigen::Matrix<double,dim,dim>& bv : bvs)
618 {
619 temp += bv*ele.absJ(bary);
620 }
621 return temp;
622 // return betaP(ele,bary)[0]*ele.absJ(bary);
623 }
624 template<int dim>
626 {
627 Eigen::Matrix<double,dim,dim> temp(Eigen::Matrix<double,dim,dim>::Zero());
628 // dV.integrate(this,temp,&ClusterDynamicsFEM<dim>::averageBetaVKernel); // integrate through the volume
629 for(size_t k=0; k<dV.size(); ++k)
630 {
631 VolumeIntegrationDomainType::QuadratureType::integrate(this,temp,&ClusterDynamicsFEM<dim>::averageBetaVKernel,dV.element(k));
632 }
633 return temp/ddBase.poly.mesh.volume();
634 }
635
636
637 template struct ClusterDynamicsFEM<3>;
638
639}
640#endif
641
642
643
644//template<int dim>
645//void ClusterDynamicsFEM<dim>::applyBoundaryConditions()
646//{
647//
648// const auto& nodesInternalExternal(mobileClusters->fe().nodeList(nodeListInternalExternal));
649//
650//#ifdef _OPENMP
651//#pragma omp parallel for
652//#endif
653// for(size_t k=0;k<nodesInternalExternal.size();++k)
654// {
655// const auto& node(nodesInternalExternal[k]);
656// const auto outNormal(node->outNormal()); // used to compute traction
657// const MatrixDim sigma(microstructures.stress(node->P0,node,nullptr,nullptr));
658// const double normalTraction(outNormal.dot(sigma*outNormal));
659// const auto bndConcentration(this->cdp.boundaryMobileConcentration(sigma.trace(),normalTraction));
660//
661// VectorMSize otherConcentration(VectorMSize::Zero());
662// for(const auto& microstructure : this->microstructures)
663// {
664// if(microstructure.get()!=static_cast<const MicrostructureBase<dim>* const>(this))
665// {// not the ClusterDynamics physics
666// otherConcentration += microstructure->mobileConcentration(node->P0,node,nullptr,nullptr);
667// }
668// }
669// for(int k=0;k<mSize;++k)
670// {
671// mobileClusters->dirichletConditions().at(mSize*node->gID+k) = bndConcentration(k) - otherConcentration(k);
672// }
673// }
674//}
static const Eigen::Matrix< int, CombinationWithRepetition< _dim+1, degree >::value, _dim+1 > baryStarsAndBars
static constexpr int nodesPerElement
double absJ(const BaryType &bary) const
const Simplex< dim, dim > & simplex
A const reference to the Simplex that this element refers to.
Eigen::Matrix< double, dim+1, 1 > pos2bary(const Eigen::Matrix< double, dim, 1 > &P) const
Definition Simplex.cpp:374
const std::shared_ptr< MeshRegionType > region
Shared pointer to MeshRegioin containing *this.
Definition Simplex.h:150
c
Definition int_R.m:15
a
Definition int_R.m:14
b
Definition int_R.m:16
x
Definition int_R.m:12
auto clusterBoundarySinks(const FE &fe)
auto weakProblem(std::shared_ptr< BWF > bwf, std::shared_ptr< LWF > lwf, WeakProblemOptions options={})
auto grad(const std::shared_ptr< T > &x)
Definition TrialGrad.h:66
auto eval(const std::shared_ptr< T > &t)
size_t StaticID< Derived >::increment
Definition StaticID.h:103
auto make_constant(const Eigen::Matrix< double, rows, cols > &c)
Definition Constant.h:44
static VectorHigherDimD x2l(const VectorDimD &X)
MicrostructureBase< dim >::NodeType NodeType
std::shared_ptr< MobileGradType > mobileGrad
const std::shared_ptr< InvDscaling< dim > > iDs
void solve(const bool hasDiscreteLoops)
const ClusterDynamicsParameters< dim > & cdp
std::shared_ptr< MobileFluxType > mobileFlux
std::shared_ptr< MobileBilinearWeakFormType > mBWF
VectorDim inelasticDisplacementRate(const VectorDim &, const NodeType *const, const ElementType *const, const SimplexDim *const) const
std::shared_ptr< ImmobileRateTrialType > immobileRateTrial
MatrixDim averageBetaVKernel(const Eigen::Matrix< double, dim, 1 > &a1, const ElementType &ele) const
std::shared_ptr< MobileIncrementTrialType > mobileClustersIncrement
std::vector< Eigen::Matrix< double, dim, dim > > betaV(const ElementType &ele, const BaryType &bary) const
std::shared_ptr< Problem > mSolver
void updateImmobileClusters(const double dt)
static constexpr int mSize
static constexpr int dVorder
std::shared_ptr< ImmobileTrialType > immobileClusters
std::shared_ptr< Load< MobileIncrementTrialType > > reactionLoad
const std::map< size_t, std::vector< VectorDim > > sinkNormals
static constexpr int iSize
std::vector< Eigen::Matrix< double, dim, dim > > betaP(const ElementType &ele, const BaryType &bary) const
MatrixDim averageBetaPKernel(const Eigen::Matrix< double, dim, 1 > &a1, const ElementType &ele) const
MicrostructureBase< dim >::SimplexDim SimplexDim
std::shared_ptr< MobileTrialType > mobileClusters
std::shared_ptr< Load< MobileTrialType > > mobileLoad
std::shared_ptr< MobileIncrementBilinearWeakFormType > dmBWF
VolumeIntegrationDomainType dV
MicrostructureBase< dim >::ElementType ElementType
MicrostructureBase< dim >::MatrixDim MatrixDim
MicrostructureBase< dim >::VectorDim VectorDim
void initializeConfiguration(const DefectiveCrystalConfigIO< dim > &configIO, const std::ofstream &f_file, const std::ofstream &F_labels)
std::shared_ptr< MatrixForm< MobileIncrementTrialType > > reactionMatrix
std::vector< Eigen::Triplet< double > > diffusionTriplets
const Eigen::VectorXd cascadeGlobalProduction
std::shared_ptr< Problem > rSolver
const DefectiveCrystalBase< dim > & ddBase
Eigen::MatrixXd conservedRows(const bool useImmobileClusters) const
void solveMobileClusters(const bool hasDiscreteLoops)
ClusterDynamicsFEM(DefectiveCrystalBase< dim > &ddBase_in, const ClusterDynamicsParameters< dim > &cdp_in)
std::shared_ptr< Problem > iSolver
Eigen::Matrix< double, dim+1, 1 > BaryType
FluxMatrix(const ClusterDynamicsParameters< dim > &cdp_in)
static constexpr int mSize
Eigen::Matrix< double, dim+1, 1 > BaryType
const MatrixType operator()(const ElementType &elem, const BaryType &bary) const
const ClusterDynamicsParameters< dim > & cdp
Eigen::Matrix< double, rows, cols > MatrixType
DefectiveCrystalBase< dim >::ElementType ElementType
Class template defining the GaussLegendre rules for determination of quadrature abscissas and weights...
const MatrixType operator()(const ElementType &elem, const BaryType &bary) const
DefectiveCrystalBase< dim >::ElementType ElementType
const ClusterDynamicsParameters< dim > & cdp
InvDscaling(const ClusterDynamicsParameters< dim > &cdp_in)
Eigen::Matrix< double, dim+1, 1 > BaryType
Eigen::Matrix< double, rows, cols > MatrixType
static constexpr int mSize
Eigen::MatrixXd matrix(const Form &form)
REAL D[16]
int j
int k
int i
vertex temp
b poly
result
REAL bc[4]