Mechanics of Defect Evolution Library
Loading...
Searching...
No Matches
testAffineDirichlet.cpp
Go to the documentation of this file.
1#include <FiniteElement.h>
2#include <WeakProblem.h>
3#include <Eigen/QR>
4#include <filesystem>
5#include <iostream>
6using namespace model;
7void require(bool value,const char* message)
8{
9 if(!value)
10 {
11 throw std::runtime_error(message);
12 }
13}
14template<class Trial>
15struct Load
16{
17 std::shared_ptr<Trial> trial;
18 Eigen::VectorXd values;
19 const auto& field() const
20 {
21 return trial->field();
22 }
23 Eigen::VectorXd globalVector() const
24 {
25 return values;
26 }
27};
28template<int components,int order>
29void exercise(const std::filesystem::path& root,int rank,bool clamp)
30{
31 auto mesh=std::make_shared<SimplicialMesh<3>>((root/"Library/Meshes/bicrystal_48.msh").string(),Eigen::Matrix3d::Identity(),Eigen::Vector3d::Zero(),std::set<int>{-1});
32 std::set<int> seeds;
33 for(const auto& region : mesh->regions())
34 {
35 for(const auto& face : region.second->faces())
36 {
37 const auto& pair=face.second->periodicFacePair;
38 if(pair.second && (pair.first.normalized().cross(Eigen::Vector3d::UnitY()).norm()<1.e-8 ||
39 (rank==2 && pair.first.normalized().cross(Eigen::Vector3d::UnitX()).norm()<1.e-8)))
40 {
41 seeds.insert(face.first);
42 }
43 }
44 }
45 mesh->identifyParallelFaces(seeds);
47 auto fe=std::make_shared<FE>(mesh);
48 auto u=fe->template trial<components>();
49 using Trial=typename decltype(u)::element_type;
50 const auto dV=fe->template domain<EntireDomain,4,GaussLegendre>();
51 auto bwf=(test(u),u)*dV+(test(grad(u)),grad(u))*dV;
52 Eigen::SparseMatrix<double> K(u->gSize(),u->gSize());
53 const auto triplets=bwf->globalTriplets();
54 K.setFromTriplets(triplets.begin(),triplets.end());
55 const auto& B=mesh->periodicBasis();
56 const Eigen::MatrixXd Q=B.householderQr().householderQ()*Eigen::MatrixXd::Identity(3,rank);
57 Eigen::Matrix<double,components,3> H,G;
58 for(int c=0;c<components;++c)
59 {
60 H.row(c)<<0.13*(c+1),-0.17*(c+1),0.03*(c+1);
61 G.row(c)<<0.2*(c+1),0.4*(c+1),0.3*(c+1);
62 if(clamp)
63 {
64 G.row(c)<<0,0,0.3*(c+1);
65 }
66 }
67 u->setPeriodicGradient(H);
68 Eigen::MatrixXd modes=Eigen::MatrixXd::Zero(u->gSize(),components*rank);
69 Eigen::VectorXd expected(u->gSize());
70 for(size_t n=0;n<fe->nodeSize();++n)
71 {
72 const Eigen::VectorXd shift=Q.transpose()*fe->periodicShift(n);
73 for(int j=0;j<rank;++j)
74 {
75 modes.block(n*components,j*components,components,components)=shift(j)*Eigen::Matrix<double,components,components>::Identity();
76 }
77 const Eigen::Vector3d x=fe->node(n).P0-Eigen::Vector3d(0,0,mesh->xMin()(2));
78 expected.segment(n*components,components)=G*x;
79 if(!clamp)
80 {
81 expected.segment(n*components,components).array()+=0.7;
82 }
83 if(clamp && std::abs(fe->node(n).P0(2)-mesh->xMin()(2))<1.e-10)
84 {
85 for(int c=0;c<components;++c)
86 {
87 u->dirichletConditions()[n*components+c]=0.0;
88 }
89 }
90 }
91 const auto pair=fe->periodicNodePairs().front();
92 if(!clamp)
93 {
94 for(int c=0;c<components;++c)
95 {
96 u->dirichletConditions()[pair.sink*components+c]=expected(pair.sink*components+c);
97 }
98 }
99 auto rhs=std::make_shared<Load<Trial>>(Load<Trial>{u,K*expected});
100 auto problem=weakProblem(bwf,rhs);
101 problem->setAffineModes(modes);
102 const auto verify=[&]()
103 {
104 require((u->dofVector()-expected).norm()<1.e-8*std::max(1.0,expected.norm()),"Coupled affine/Dirichlet solution is wrong");
105 Eigen::Matrix<double,components,3> gradient=H;
106 for(int j=0;j<rank;++j)
107 {
108 gradient+=problem->affineCoefficients().segment(j*components,components)*Q.col(j).transpose();
109 }
110 require(((gradient-G)*Q).norm()<1.e-8,"Original affine coefficients were not reconstructed");
111 for(const auto& bc : u->dirichletConditions())
112 {
113 require(std::abs(u->dofVector()(bc.first)-bc.second)<1.e-9,"Prescribed node moved");
114 }
115 };
116 problem->solveWithMasterSlaveConstraints();
117 verify();
118 if(!clamp)
119 {
120 // Move the anchor to its periodic partner: the nodal mapping is unchanged,
121 // but the affine part changes and must invalidate the factorization.
122 u->dirichletConditions().clear();
123 for(int c=0;c<components;++c)
124 {
125 u->dirichletConditions()[pair.source*components+c]=expected(pair.source*components+c);
126 }
127 require(!problem->solveWithMasterSlaveConstraints().reusedFactorization,"Changed affine anchor reused a stale matrix");
128 verify();
129 for(int c=0;c<components;++c)
130 {
131 u->dirichletConditions()[pair.sink*components+c]=expected(pair.sink*components+c);
132 }
133 problem->solveWithMasterSlaveConstraints();
134 verify();
135 }
136 // A prescribed periodic jump is redundant with the clamps or paired pins.
137 // Duplicate it deliberately; consistent redundancy must not cause singularity.
138 Eigen::MatrixXd rows=Eigen::MatrixXd::Zero(2,u->gSize());
139 size_t source=pair.source,sink=pair.sink;
140 if(clamp)
141 {
142 for(const auto& p : fe->periodicNodePairs())
143 {
144 if(u->dirichletConditions().count(p.source*components) && u->dirichletConditions().count(p.sink*components))
145 {
146 source=p.source;
147 sink=p.sink;
148 break;
149 }
150 }
151 }
152 rows(0,source*components)=-1.0;
153 rows(0,sink*components)=1.0;
154 rows.row(1)=2.0*rows.row(0);
155 problem->setLinearConstraints(rows);
156 problem->setLinearConstraintValues(rows*expected);
157 problem->solveWithMasterSlaveConstraints();
158 verify();
159 require(problem->solveWithMasterSlaveConstraints().reusedFactorization,"Unchanged coupled constraints did not reuse factorization");
160 // New RHS and compatible prescribed values change the particular solution,
161 // including fixed affine coefficients, without changing the free subspace.
162 expected*=1.4;
163 rhs->values=K*expected;
164 for(auto& bc : u->dirichletConditions())
165 {
166 bc.second=expected(bc.first);
167 }
168 G*=1.4;
169 problem->setLinearConstraintValues(rows*expected);
170 require(problem->solveWithMasterSlaveConstraints().reusedFactorization,"Compatible value changes refactorized the matrix");
171 verify();
172 const Eigen::VectorXd saved=u->dofVector();
173 const Eigen::VectorXd coefficients=problem->affineCoefficients();
174 auto incompatible=(rows*expected).eval();
175 incompatible(0)+=1.0;
176 incompatible(1)+=2.0;
177 problem->setLinearConstraintValues(incompatible);
178 bool rejected=false;
179 try
180 {
181 problem->solveWithMasterSlaveConstraints();
182 }
183 catch(const std::invalid_argument& e)
184 {
185 rejected=std::string(e.what()).find("Incompatible")!=std::string::npos;
186 }
187 require(rejected,"Conflicting affine loading and clamps were not diagnosed");
188 require((u->dofVector()-saved).norm()==0.0 && (problem->affineCoefficients()-coefficients).norm()==0.0,"Rejected update changed the solution");
189 problem->setLinearConstraintValues(rows*expected);
190 problem->solveWithMasterSlaveConstraints();
191 verify();
192 if(clamp)
193 {
194 // Contradictory jumps along different edges cannot be fitted by one affine mode.
195 u->dirichletConditions().at(sink*components)+=1.0;
196 rejected=false;
197 try
198 {
199 problem->solveWithMasterSlaveConstraints();
200 }
201 catch(const std::invalid_argument& e)
202 {
203 rejected=std::string(e.what()).find("Incompatible")!=std::string::npos;
204 }
205 require(rejected,"Inconsistent prescribed periodic copies were accepted");
206 require((u->dofVector()-saved).norm()<1.e-12,"Incompatible nodal conditions changed field");
207 }
208 // All nodal and affine unknowns may be prescribed; no factorization is needed.
209 u->dirichletConditions().clear();
210 for(size_t i=0;i<size_t(expected.size());++i)
211 {
212 u->dirichletConditions()[i]=expected(i);
213 }
214 problem->solveWithMasterSlaveConstraints();
215 verify();
216}
217int main(int argc,char** argv)
218{
219 try
220 {
221 require(argc==2,"Expected repository root");
222 for(int rank : {1,2})
223 {
224 for(bool clamp : {false,true})
225 {
226 exercise<1,1>(argv[1],rank,clamp);
227 exercise<3,2>(argv[1],rank,clamp);
228 }
229 }
230 std::cout<<"PASS affine modes with pins, clamps, compatibility checks and factorization reuse\n";
231 }
232 catch(const std::exception& e)
233 {
234 std::cerr<<e.what()<<'\n';
235 return 1;
236 }
237}
initial point of the source segment B
c
Definition int_R.m:15
x
Definition int_R.m:12
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)
Eigen::VectorXd values
std::shared_ptr< Trial > trial
Eigen::VectorXd globalVector() const
const auto & field() const
int regions
Definition triangle.cpp:696
void exercise(const std::filesystem::path &root, int rank, bool clamp)
void require(bool value, const char *message)
void verify(Network &network)
Q
int j
void argv
REAL u[4]
void b int argc
vertex p[3]
int i
int e
REAL bc[4]