8#ifndef model_ClusterDynamicsFEM_cpp_
9#define model_ClusterDynamicsFEM_cpp_
34 D.template block<dim,dim>(
k*dim,
k*dim)=-
cdp.D.at(grainID)[
k]/
cdp.omega;
98 mobileClusters->setConstant(
cdp.equilibriumMobileConcentration(0.0).matrix().transpose());
108 std::map<size_t,double> fixed;
110 const auto lift=[&](
size_t node,
int component)
112 const size_t root=
ddBase.fe->periodicRepresentative(node);
113 return offset.size()? offset(node*
mSize+component)-offset(root*
mSize+component) : 0.0;
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)}))
124 throw std::runtime_error(
"ClusterDynamics: incompatible concentrations on periodic sink nodes.");
127 for(
size_t node=0;node<
ddBase.fe->nodeSize();++node)
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);
145 std::vector<Eigen::Matrix<double,mSize,1>> directions;
146 const auto append=[&](
const Eigen::Matrix<double,mSize,mSize>&
matrix)
152 directions.push_back(
matrix.col(
c).normalized());
156 if(
cdp.computeReactions)
161 Eigen::Matrix<double,mSize,mSize>
matrix;
162 for(
int row=0;row<
mSize;++row)
171 if(useImmobileClusters)
174 for(
const auto& entry :
ddBase.fe->elements())
184 Eigen::MatrixXd invariants=Eigen::MatrixXd::Identity(
mSize,
mSize);
185 if(!directions.empty())
188 for(
size_t k=0;
k<directions.size();++
k)
192 Eigen::JacobiSVD<Eigen::MatrixXd> svd(
matrix,Eigen::ComputeFullU);
193 svd.setThreshold(1.e-10);
194 invariants=svd.matrixU().rightCols(
mSize-svd.rank());
196 const Eigen::VectorXd production=
cdp.G;
197 if((invariants.transpose()*production).norm()>1.e-10*production.norm())
199 throw std::runtime_error(
"ClusterDynamics: no steady state in the closed periodic domain; production changes a conserved species inventory.");
201 return invariants.transpose()*
meanRows;
207 std::cout<<
", mobile solver, "<<std::flush;
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)
218 if(
mSolver->factorizationCount()==0)
220 mSolver->setLinearConstraints(conserved);
222 mSolver->setLinearConstraintValues(inventory);
223 mSolver->solveWithMasterSlaveConstraints();
227 const auto R1=
cdp.R1cd.eval();
229 auto R2=std::make_shared<SecondOrderReaction<MobileTrialType>>(
mobileClusters,
cdp);
236 const auto residual=[&]() -> Eigen::VectorXd
239 if(useImmobileClusters)
241 result+=fs->globalVector();
245 const auto reducedNorm=[&](
const Eigen::VectorXd& value)
247 Eigen::VectorXd reduced=Eigen::VectorXd::Zero(value.size());
248 std::set<size_t> fixed;
253 for(
size_t n=0;n<
ddBase.fe->nodeSize();++n)
257 const size_t root=
ddBase.fe->periodicRepresentative(n)*
mSize+
c;
258 if(!fixed.count(root))
260 reduced(root)+=value(n*
mSize+
c);
264 return reduced.norm();
266 rSolver->setLinearConstraints(conserved);
267 double reference=0.0;
268 for(
int iteration=0;iteration<60;++iteration)
276 if(error<=1.e-8*reference)
281 const auto append=[&](
const auto& form)
283 const auto entries=form->globalTriplets();
288 if(useImmobileClusters)
294 rSolver->solveWithMasterSlaveConstraints();
297 for(
int backtrack=0;backtrack<24;++backtrack)
299 const double step=std::ldexp(1.0,-backtrack);
306 if(total.minCoeff()< -1.e-12*std::max(1.e-50,total.cwiseAbs().maxCoeff()))
310 const double trialError=reducedNorm(residual());
311 if(std::isfinite(trialError) && (trialError<error || trialError<=1.e-8*reference))
319 throw std::runtime_error(
"ClusterDynamics: reaction iteration failed to reduce the residual.");
322 throw std::runtime_error(
"ClusterDynamics: reaction iteration exceeded 60 steps.");
335 if constexpr(
iSize>0)
348 iSolver->setRightHandSide(rhs);
350 iSolver->solveWithMasterSlaveConstraints();
361 for(
int dof=0;dof<
iSize/2;dof++)
371 for(
size_t node=0;node<
ddBase.fe->nodeSize();++node)
373 const size_t root=
ddBase.fe->periodicRepresentative(node);
393 if(!hasDiscreteLoops &&
iSize>0)
438 Eigen::Matrix<double,mSize,1> unit=Eigen::Matrix<double,mSize,1>::Zero();
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())
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()}))
459 throw std::runtime_error(
"ClusterDynamics: restart immobile concentrations violate active periodic pairs.");
468 if(configIO.cdMatrix().size())
470 throw std::runtime_error(
"ClusterDynamics: TrialFunctions initializatoin size mismatch");
479 Eigen::Matrix<double,dim*mSize,1> speciesFlux(Eigen::Matrix<double,dim*mSize,1>::Zero());
495 Eigen::Matrix<double,dim,1> netFlux(Eigen::Matrix<double,dim,1>::Zero());
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;
508 std::vector<Eigen::Matrix<double,dim,dim>> strainVector;
510 Eigen::Matrix<double,iSize,1> correctedSinkValue(sinkValue);
511 for(
int dof=0;dof<
iSize/2;dof++)
513 const double cmin =
cdp.n_min(dof)*
cdp.omega*correctedSinkValue(dof);
514 if(correctedSinkValue(
iSize/2+dof)<cmin)
516 correctedSinkValue(
iSize/2+dof)=cmin;
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());
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);
542 std::vector<Eigen::Matrix<double,dim,dim>> strainVector;
544 Eigen::Matrix<double,iSize,1> correctedSinkValue(sinkValue);
545 for(
int dof=0;dof<
iSize/2;dof++)
547 const double cmin =
cdp.n_min(dof)*
cdp.omega*correctedSinkValue(dof);
548 if(correctedSinkValue(
iSize/2+dof)<cmin)
550 correctedSinkValue(
iSize/2+dof)=cmin;
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)));
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);
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));
575 tempStrain += 1.0/3.0*
cdp.msVector(
k)*localConcentration(
k)*
cdp.msRelRelaxVol(
k)*Eigen::Matrix<double,dim,dim>::Identity();
577 strainVector.push_back(tempStrain);
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)
600 Eigen::Matrix<double,dim,dim>
temp(Eigen::Matrix<double,dim,dim>::Zero());
602 for(
size_t k=0;
k<
dV.size(); ++
k)
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)
627 Eigen::Matrix<double,dim,dim>
temp(Eigen::Matrix<double,dim,dim>::Zero());
629 for(
size_t k=0;
k<
dV.size(); ++
k)
static constexpr int order
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
const std::shared_ptr< MeshRegionType > region
Shared pointer to MeshRegioin containing *this.
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)
auto eval(const std::shared_ptr< T > &t)
size_t StaticID< Derived >::increment
auto make_constant(const Eigen::Matrix< double, rows, cols > &c)
static VectorHigherDimD x2l(const VectorDimD &X)
void enforceMobileConstraints()
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
SparseMatrixType diffusionMatrix
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 averageBetaP() const
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
Eigen::VectorXd immobileClusterRate
std::vector< Eigen::Triplet< double > > diffusionTriplets
const Eigen::VectorXd cascadeGlobalProduction
std::shared_ptr< Problem > rSolver
MatrixDim averageBetaV() const
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
void solveImmobileClusters()
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)