Mechanics of Defect Evolution Library
Loading...
Searching...
No Matches
GlobalRigidMotionPenalty.h
Go to the documentation of this file.
1/* This file is part of MoDELib, distributed under the GNU GPL v2. */
2#ifndef model_GlobalRigidMotionPenalty_H_
3#define model_GlobalRigidMotionPenalty_H_
5#include <Eigen/Eigenvalues>
6#include <Quadrature.h>
7#include <GaussLegendre.h>
8#include <BarycentricTraits.h>
9#include <memory>
10#include <Eigen/SparseCore>
11#include <vector>
12#include <cmath>
13#include <algorithm>
14#include <stdexcept>
15
16namespace model
17{
18 // Penalize mean displacement and mean infinitesimal rotation, restricted
19 // to homogeneous rigid modes admitted by the constraints.
20 // Only six global moments are stored; WeakProblem handles F^T F as a low-rank term.
21 template<class Trial>
22 class GlobalRigidMotionPenalty : public BilinearWeakExpression<GlobalRigidMotionPenalty<Trial>>
23 {
24 public:
25 using TrialFunctionType=Trial;
26 using Element=typename Trial::ElementType;
27 using RigidMatrix=Eigen::Matrix<double,3,6>;
28 using GramMatrix=Eigen::Matrix<double,6,6>;
30 static_assert(Trial::dim==3 && Trial::dofPerNode==3);
31 private:
32 const std::shared_ptr<Trial> trial;
33 const double factor;
34 const bool freeAffineJumps;
35 Eigen::Vector3d centroid=Eigen::Vector3d::Zero();
36 double length=0.0;
37 double volume=0.0;
38 Eigen::MatrixXd moments;
39
40 static Eigen::Matrix3d crossMatrix(const Eigen::Vector3d& x)
41 {
42 Eigen::Matrix3d result;
43 result<<0,-x(2),x(1),x(2),0,-x(0),-x(1),x(0),0;
44 return result;
45 }
46 RigidMatrix rigid(const Eigen::Vector3d& x) const
47 {
49 result.leftCols<3>().setIdentity();
50 result.rightCols<3>()=-crossMatrix((x-centroid)/length);
51 return result;
52 }
53 Eigen::Matrix<double,6,Trial::dofPerElement> momentKernel(const Eigen::Vector3d& a,const Element& e) const
54 {
55 const auto bary=BarycentricTraits<3>::x2l(a);
56 Eigen::Matrix<double,6,Trial::dofPerElement> result;
57 result.template topRows<3>()=trial->sfm(e,bary);
58 // sfmGrad stores grad(u) rowwise: u1,x u1,y u1,z u2,x ...
59 // Scale rotation by length to give all six moments displacement units.
60 const auto gradient=trial->sfmGrad(e,bary);
61 result.row(3)=0.5*length*(gradient.row(7)-gradient.row(5));
62 result.row(4)=0.5*length*(gradient.row(2)-gradient.row(6));
63 result.row(5)=0.5*length*(gradient.row(3)-gradient.row(1));
64 return result*e.absJ(bary)/volume;
65 }
66 Eigen::MatrixXd admissibleParameters() const
67 {
68 GramMatrix constraints=GramMatrix::Zero();
69 const auto& pairs=trial->fe().periodicNodePairs();
70 if(!freeAffineJumps)
71 {
72 for(const auto& pair : pairs)
73 {
74 // A rigid rotation omega is periodic iff omega cross p == 0.
75 RigidMatrix jump=RigidMatrix::Zero();
76 jump.rightCols<3>()=-crossMatrix(pair.shift.normalized());
77 constraints+=jump.transpose()*jump/double(pairs.size());
78 }
79 }
80 const auto& conditions=trial->dirichletConditions();
81 for(const auto& entry : conditions)
82 {
83 if(entry.first>=trial->gSize())
84 {
85 throw std::invalid_argument("Invalid rigid-motion Dirichlet DOF.");
86 }
87 const Eigen::Matrix<double,1,6> row=rigid(trial->fe().node(entry.first/3).P0).row(entry.first%3);
88 constraints+=row.transpose()*row/(row.squaredNorm()*double(conditions.size()));
89 }
90 Eigen::SelfAdjointEigenSolver<GramMatrix> eig(constraints);
91 if(eig.info()!=Eigen::Success)
92 {
93 throw std::runtime_error("Rigid-motion constraint decomposition failed.");
94 }
95 const double tolerance=1.e-10*std::max(1.0,eig.eigenvalues().maxCoeff());
96 const Eigen::Index count=(eig.eigenvalues().array()<tolerance).count();
97 return eig.eigenvectors().leftCols(count);
98 }
99 public:
100 GlobalRigidMotionPenalty(std::shared_ptr<Trial> u,double alpha,bool freeAffineJumpsIn=false) : trial(std::move(u)),factor(alpha),freeAffineJumps(freeAffineJumpsIn)
101 {
102 if(!trial || !std::isfinite(factor) || factor<=0.0)
103 {
104 throw std::invalid_argument("Rigid-motion penalty factor must be positive.");
105 }
106 const auto& fe=trial->fe();
107 for(const auto& pair : fe.elements())
108 {
109 volume+=pair.second.simplex.vol0;
110 centroid+=pair.second.simplex.vol0*pair.second.simplex.center();
111 }
112 if(!(volume>0.0))
113 {
114 throw std::runtime_error("Empty rigid-motion penalty domain.");
115 }
116 centroid/=volume;
117 length=(fe.mesh.xMax()-fe.mesh.xMin()).norm();
118 moments=Eigen::MatrixXd::Zero(6,trial->gSize());
119 for(const auto& pair : fe.elements())
120 {
121 const auto& e=pair.second;
122 Eigen::Matrix<double,6,Trial::dofPerElement> local=Eigen::Matrix<double,6,Trial::dofPerElement>::Zero();
123 QuadratureType::integrate(this,local,&GlobalRigidMotionPenalty::momentKernel,e);
124 for(int node=0;node<Trial::nodesPerElement;++node)
125 {
126 moments.middleCols(3*e.node(node).gID,3)+=local.middleCols(3*node,3);
127 }
128 }
129 }
130 const auto& field() const
131 {
132 return trial->field();
133 }
134 // Sparse part only. The global term is provided by lowRankPenaltyRows().
135 std::vector<Eigen::Triplet<double>> globalTriplets() const
136 {
137 return {};
138 }
139 Eigen::MatrixXd lowRankPenaltyRows() const
140 {
141 const Eigen::MatrixXd S=admissibleParameters();
142 if(S.cols()==0)
143 {
144 return Eigen::MatrixXd(0,moments.cols());
145 }
146 // For u=t+omega cross (x-centroid)/length these moments equal
147 // (t,omega). S has orthonormal columns, so no geometric inertia
148 // normalization is needed. Symmetric affine strain has zero curl.
149 return std::sqrt(factor)*S.transpose()*moments;
150 }
151 Eigen::MatrixXd rigidModes() const
152 {
153 const Eigen::MatrixXd S=admissibleParameters();
154 Eigen::MatrixXd result(trial->gSize(),S.cols());
155 for(size_t node=0;node<trial->fe().nodeSize();++node)
156 {
157 result.middleRows(3*node,3)=rigid(trial->fe().node(node).P0)*S;
158 }
159 return result;
160 }
161 };
162}
163#endif
Eigen::Matrix< double, 3, 6 > RigidMatrix
std::vector< Eigen::Triplet< double > > globalTriplets() const
typename Trial::ElementType Element
Quadrature< 3, 4, GaussLegendre > QuadratureType
Eigen::Matrix< double, 6, 6 > GramMatrix
GlobalRigidMotionPenalty(std::shared_ptr< Trial > u, double alpha, bool freeAffineJumpsIn=false)
the tangent vector S
a
Definition int_R.m:14
x
Definition int_R.m:12
size_t InstanceCount< Derived >::count
double SplineSegment< dim, corder >::alpha
static VectorHigherDimD x2l(const VectorDimD &X)
A static class template for generating quadrature abcsissas and weights for arbitrary-order and Quadr...
Definition Quadrature.h:50
REAL u[4]
int e
result