Mechanics of Defect Evolution Library
Loading...
Searching...
No Matches
FEMLoadController.h
Go to the documentation of this file.
1/* This file is part of MoDELib, distributed under the GNU GPL v2. */
2#ifndef model_FEMLoadController_H_
3#define model_FEMLoadController_H_
5#include <Quadrature.h>
6#include <BarycentricTraits.h>
7#include <Eigen/QR>
8#include <Eigen/SparseCore>
9#include <cmath>
10#include <stdexcept>
11#include <memory>
12#include <vector>
13namespace model
14{
15 // Mixed loading acts on volume-average engineering strain. Its variational
16 // force supplies uniform traction on physical faces and work on free periodic jumps.
17 template<class Trial>
18 class FEMLoadController : public BilinearWeakExpression<FEMLoadController<Trial>>
19 {
20 std::shared_ptr<Trial> trial;
21 Eigen::Matrix<double,6,1> alpha,D,strain0,strainRate,stress0,stressRate;
22 std::vector<int> fixed;
23 Eigen::MatrixXd meanStrain,periodicDirections;
24 double volume=0.0;
25 double length=1.0;
26 public:
27 using TrialFunctionType=Trial;
28 using Vector6=Eigen::Matrix<double,6,1>;
29 // Values such as 1e20 conventionally denote strain control. Enforce
30 // these exactly rather than placing enormous coefficients in the matrix.
31 static constexpr double rigidDeviceThreshold=1.e15;
32 struct Load
33 {
34 std::shared_ptr<Trial> trial;
35 Eigen::VectorXd force;
36 const auto& field() const
37 {
38 return trial->field();
39 }
40 Eigen::VectorXd globalVector() const
41 {
42 return force;
43 }
44 };
45 template<class Settings>
46 FEMLoadController(std::shared_ptr<Trial> u,const Settings& settings):
47 trial(std::move(u)),alpha(settings.alpha),D(Vector6::Zero()),
48 strain0(settings.g0),strainRate(settings.g0Dot),stress0(settings.f0),stressRate(settings.f0Dot)
49 {
50 if(!alpha.allFinite() || (alpha.array()<0.0).any() || !strain0.allFinite() ||
51 !strainRate.allFinite() || !stress0.allFinite() || !stressRate.allFinite())
52 {
53 throw std::invalid_argument("Invalid FEM loading inputs; stiffnessRatio must be finite and nonnegative.");
54 }
55 const auto& fe=trial->fe();
56 volume=fe.mesh.volume();
57 length=(fe.mesh.xMax()-fe.mesh.xMin()).norm();
58 meanStrain=Eigen::MatrixXd::Zero(6,trial->gSize());
60 for(const auto& entry : fe.elements())
61 {
62 const auto& e=entry.second;
63 for(size_t k=0;k<Q::quadratureOrder;++k)
64 {
65 const auto bary=BarycentricTraits<3>::x2l(Q::abscissa(k));
66 const auto local=(trial->sfmDef(e,bary)*(e.absJ(bary)*Q::weight(k)/volume)).eval();
67 for(int n=0;n<Trial::nodesPerElement;++n)
68 {
69 meanStrain.middleCols(3*e.node(n).gID,3)+=local.middleCols(3*n,3);
70 }
71 }
72 }
73 for(int i=0;i<6;++i)
74 {
76 {
77 fixed.push_back(i);
78 }
79 else
80 {
81 D(i)=alpha(i)*settings.A(i,i);
82 }
83 }
84 const auto& basis=fe.mesh.periodicBasis();
85 periodicDirections=Eigen::MatrixXd::Zero(3,basis.cols());
86 if(basis.cols()>0)
87 {
88 periodicDirections=basis.householderQr().householderQ()*Eigen::MatrixXd::Identity(3,basis.cols());
89 }
90 }
91 const auto& field() const
92 {
93 return trial->field();
94 }
95 std::vector<Eigen::Triplet<double>> globalTriplets() const
96 {
97 return {};
98 }
99 Eigen::MatrixXd lowRankPenaltyRows() const
100 {
101 return (volume*D.array()).sqrt().matrix().asDiagonal()*meanStrain;
102 }
103 Eigen::MatrixXd constraintRows() const
104 {
105 Eigen::MatrixXd rows(fixed.size(),trial->gSize());
106 for(size_t i=0;i<fixed.size();++i)
107 {
108 rows.row(i)=std::sqrt(volume)*meanStrain.row(fixed[i]);
109 }
110 return rows;
111 }
112 Eigen::VectorXd constraintValues(double time,const Vector6& strainOffset) const
113 {
114 const Vector6 target=strain0+time*strainRate-strainOffset;
115 Eigen::VectorXd values(fixed.size());
116 for(size_t i=0;i<fixed.size();++i)
117 {
118 values(i)=std::sqrt(volume)*target(fixed[i]);
119 }
120 return values;
121 }
122 std::shared_ptr<Load> rightHandSide(const Eigen::VectorXd& source,double time,const Vector6& strainOffset) const
123 {
124 const Vector6 force=stress0+time*stressRate+D.asDiagonal()*(strain0+time*strainRate-strainOffset);
125 return std::make_shared<Load>(Load{trial,source+volume*meanStrain.transpose()*force});
126 }
127 Eigen::MatrixXd affineModes() const
128 {
129 Eigen::MatrixXd modes=Eigen::MatrixXd::Zero(trial->gSize(),3*periodicDirections.cols());
130 for(size_t node=0;node<trial->fe().nodeSize();++node)
131 {
132 const Eigen::VectorXd shift=periodicDirections.transpose()*trial->fe().periodicShift(node)/length;
133 for(Eigen::Index j=0;j<shift.size();++j)
134 {
135 modes.block<3,3>(3*node,3*j)=shift(j)*Eigen::Matrix3d::Identity();
136 }
137 }
138 return modes;
139 }
140 Eigen::Matrix3d gradient(const Eigen::VectorXd& coefficients) const
141 {
142 Eigen::Matrix3d result=Eigen::Matrix3d::Zero();
143 for(Eigen::Index j=0;j<periodicDirections.cols();++j)
144 {
145 result+=coefficients.segment<3>(3*j)*periodicDirections.col(j).transpose()/length;
146 }
147 return result;
148 }
150 {
151 return meanStrain*trial->dofVector();
152 }
153 };
154}
155#endif
FEMLoadController(std::shared_ptr< Trial > u, const Settings &settings)
Eigen::MatrixXd affineModes() const
const auto & field() const
typename ElasticDeformationFEM< dim >::TrialFunctionType TrialFunctionType
Eigen::VectorXd constraintValues(double time, const Vector6 &strainOffset) const
std::vector< Eigen::Triplet< double > > globalTriplets() const
Eigen::Matrix3d gradient(const Eigen::VectorXd &coefficients) const
Eigen::MatrixXd lowRankPenaltyRows() const
Eigen::MatrixXd constraintRows() const
std::shared_ptr< Load > rightHandSide(const Eigen::VectorXd &source, double time, const Vector6 &strainOffset) const
double SplineSegment< dim, corder >::alpha
Eigen::VectorXd globalVector() const
std::shared_ptr< Trial > trial
A static class template for generating quadrature abcsissas and weights for arbitrary-order and Quadr...
Definition Quadrature.h:50
Q
REAL D[16]
int j
REAL u[4]
int i
result