26 using Element=
typename Trial::ElementType;
30 static_assert(Trial::dim==3 && Trial::dofPerNode==3);
32 const std::shared_ptr<Trial> trial;
34 const bool freeAffineJumps;
35 Eigen::Vector3d centroid=Eigen::Vector3d::Zero();
38 Eigen::MatrixXd moments;
40 static Eigen::Matrix3d crossMatrix(
const Eigen::Vector3d&
x)
49 result.leftCols<3>().setIdentity();
50 result.rightCols<3>()=-crossMatrix((
x-centroid)/length);
53 Eigen::Matrix<double,6,Trial::dofPerElement> momentKernel(
const Eigen::Vector3d&
a,
const Element&
e)
const
56 Eigen::Matrix<double,6,Trial::dofPerElement>
result;
57 result.template topRows<3>()=trial->sfm(
e,bary);
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;
66 Eigen::MatrixXd admissibleParameters()
const
69 const auto& pairs=trial->fe().periodicNodePairs();
72 for(
const auto& pair : pairs)
76 jump.rightCols<3>()=-crossMatrix(pair.shift.normalized());
77 constraints+=jump.transpose()*jump/double(pairs.size());
80 const auto& conditions=trial->dirichletConditions();
81 for(
const auto& entry : conditions)
83 if(entry.first>=trial->gSize())
85 throw std::invalid_argument(
"Invalid rigid-motion Dirichlet DOF.");
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()));
90 Eigen::SelfAdjointEigenSolver<GramMatrix> eig(constraints);
91 if(eig.info()!=Eigen::Success)
93 throw std::runtime_error(
"Rigid-motion constraint decomposition failed.");
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);
102 if(!trial || !std::isfinite(factor) || factor<=0.0)
104 throw std::invalid_argument(
"Rigid-motion penalty factor must be positive.");
106 const auto& fe=trial->fe();
107 for(
const auto& pair : fe.elements())
109 volume+=pair.second.simplex.vol0;
110 centroid+=pair.second.simplex.vol0*pair.second.simplex.center();
114 throw std::runtime_error(
"Empty rigid-motion penalty domain.");
117 length=(fe.mesh.xMax()-fe.mesh.xMin()).norm();
118 moments=Eigen::MatrixXd::Zero(6,trial->gSize());
119 for(
const auto& pair : fe.elements())
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)
126 moments.middleCols(3*e.node(node).gID,3)+=local.middleCols(3*node,3);
132 return trial->field();
141 const Eigen::MatrixXd
S=admissibleParameters();
144 return Eigen::MatrixXd(0,moments.cols());
149 return std::sqrt(factor)*
S.transpose()*moments;
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)
157 result.middleRows(3*node,3)=rigid(trial->fe().node(node).P0)*
S;