Mechanics of Defect Evolution Library
Loading...
Searching...
No Matches
testContractionSafety.cpp
Go to the documentation of this file.
5#include <filesystem>
6#include <fstream>
7#include <iomanip>
8#include <chrono>
9#include <iostream>
10#include <set>
11#include <sstream>
12
13void require(bool condition, const char* message)
14{
15 if(!condition)
16 {
17 throw std::runtime_error(message);
18 }
19}
20
21int main(int argc, char** argv)
22{
23 try
24 {
25 require(argc == 2, "Expected repository root");
26 const std::filesystem::path root(argv[1]);
27 const auto folder = std::filesystem::temp_directory_path() /
28 ("contraction-safety-" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()));
29 const auto input = folder / "inputFiles";
30 std::filesystem::create_directories(input);
31 std::filesystem::create_directories(folder / "F");
32 std::filesystem::copy_file(root / "Library/Materials/W.txt", input / "W.txt");
33 const auto meshFile = root / "Library/Meshes/unitCube24.msh";
34 std::filesystem::copy_file(meshFile, input / "mesh.msh");
35 model::SimplicialMesh<3> mesh(meshFile.string(), Eigen::Matrix3d::Identity(), Eigen::Vector3d::Zero(), {-1});
36 std::vector<int> seeds;
37 for(int axis = 0; axis < 3; ++axis)
38 {
39 for(const auto& region : mesh.regions())
40 {
41 for(const auto& face : region.second->faces())
42 {
43 const auto& pair = face.second->periodicFacePair;
44 if(pair.second && pair.first[axis] > 0.9 &&
45 pair.first.normalized().cross(Eigen::Vector3d::Unit(axis)).norm() < 1.e-8)
46 {
47 seeds.push_back(face.first);
48 }
49 }
50 }
51 }
52 require(seeds.size() == 3, "Expected three cube periodic directions");
53 model::StaticID<model::Polyhedron<3,3-1>>::force_count(0);
54
55 std::filesystem::copy_file(root / "Library/DislocationDynamics/DD.txt", input / "DD.txt");
56 const double length=200.0/std::sqrt(3.0);
57 for(int scenario=0;scenario<6;++scenario)
58 {
59 {
60 std::ifstream original(root/"Library/DislocationDynamics/DD.txt");
61 std::string dd((std::istreambuf_iterator<char>(original)),std::istreambuf_iterator<char>());
62 const auto begin=dd.find("nodalVelocityConstraints=");
63 require(begin!=std::string::npos,"Missing velocity constraints input");
64 const auto end=dd.find(';',begin);
65 dd.replace(begin,end-begin,scenario<2 ? "nodalVelocityConstraints=1 0 0" : "nodalVelocityConstraints=");
66 std::ofstream(input/"DD.txt")<<dd;
67 }
68 {
69 std::ofstream f(input/"DefectiveCrystal.txt");
70 f<<"physics=DislocationDynamics;\nuseFEM=0;\nNsteps=0;\nmaxResolveSteps=0;\ndtMax=1;\noutputFrequency=1;\noutputBinary=0;\nstartAtTimeStep=0;\nperiodicImageSize=0;\nEwaldLengthFactor=0;\n";
71 std::ofstream p(input/"polycrystal.txt");
72 p<<std::setprecision(17)<<"materialFile=W.txt;\nmeshFile=mesh.msh;\nabsoluteTemperature=300;\nC2G1=1 0 0 0 1 0 0 0 1;\nF="<<length<<" 0 0 0 "<<length<<" 0 0 0 "<<length<<";\nX0=0 0 0;\nperiodicFaceIDs="<<seeds[0]<<";\n";
73 }
74 model::DefectiveCrystalBase<3> base(folder.string());
75 require(base.periodicLatticeBasis.cols()==1,"Incorrect active periodic rank");
78 using V=Eigen::Vector3d;
79 Network network(container);
80 const auto grain=base.poly.grain(1);
81 const auto plane=base.dislocationDynamics().glidePlaneFactory.getFromKey(model::GlidePlaneKey<3>(V::Zero(),grain->reciprocalLatticeDirection(V::UnitZ())));
82 const V burgers=2.0/std::sqrt(3.0)*V::UnitX();
83
84 if(scenario>=4)
85 {
86 const bool bent=scenario==5;
87 const V pa=length*V(0.2,0,0);
88 const V pb=length*V(0.2,0.1,0);
89 const V pc=length*V(0.7,0,0);
90 const V bend=length*V(0.5,0.2,0);
91 const auto a=network.networkNodes().create(pa);
92 const auto b=network.networkNodes().create(pb);
93 const auto c=network.networkNodes().create(length*V(-0.3,0,0));
94 const auto loop=network.loops().create(burgers,plane);
95 const auto partner=network.loops().create(burgers,plane);
96 const auto make=[&](const auto& owner,const auto& net,const V& position)
97 {
98 return network.loopNodes().create(owner,net,position,owner->periodicGlidePlane->getPatch(V::Zero()),
99 std::make_pair(std::shared_ptr<model::PeriodicPlaneEdge<3>>(),std::shared_ptr<model::PeriodicPlaneEdge<3>>()));
100 };
101 {
102 std::vector<std::shared_ptr<Network::LoopNodeType>> ring{make(loop,a,pa)};
103 if(bent)
104 {
105 ring.push_back(make(loop,network.networkNodes().create(bend),bend));
106 }
107 ring.push_back(make(loop,c,pc));
108 ring.push_back(make(loop,b,pb));
109 network.insertLoop(loop,ring);
110 const V pd=length*V(0.2,-0.2,0);
111 network.insertLoop(partner,std::vector<std::shared_ptr<Network::LoopNodeType>>{
112 make(partner,c,pc),make(partner,a,pa),make(partner,network.networkNodes().create(pd),pd)});
113 }
114 network.updateBoundaryNodes();
115 network.updateGeometry();
116 const V partnerArea=partner->currentAreaVector();
117 // Simulate an old saved configuration: seam nodes have geometry
118 // but no stored distinction between bends and subdivisions.
119 for(const auto& entry : network.loopNodes())
120 {
121 entry.second.lock()->periodicContourVertex=false;
122 }
123 require(network.contract(a,b),"Periodic contour contraction was rejected");
124 require((partner->currentAreaVector()-partnerArea).norm()<1.e-8,
125 "Contraction changed the shared partner's slipped area");
126 require(!a->loopNodes().empty() && !c->loopNodes().empty(),
127 "Collapsed contour destroyed shared network endpoints");
128 if(bent)
129 {
130 require(loop->isLoop(),"Genuine periodic bend was deleted");
131 require(std::abs(loop->currentAreaVector().norm()-0.05*length*length)<1.e-8,
132 "Contraction lost slipped area at the periodic bend");
133 size_t retainedBends=0;
134 for(const auto* link : loop->linkSequence())
135 {
136 if((link->source->get_P()-bend).norm()<1.e-8)
137 {
138 require(!link->source->isPeriodicSubdivision(),"Genuine bend is still a subdivision");
139 ++retainedBends;
140 }
141 }
142 require(retainedBends>0,"Missing periodic contour vertex");
143 // Without provenance, two bulk anchors are still not a
144 // deletion certificate: retain the bent geometric contour.
145 for(const auto* link : loop->linkSequence())
146 {
147 link->source->periodicContourVertex=false;
148 }
149 network.updateBoundaryNodes();
150 require(std::abs(loop->currentAreaVector().norm()-0.05*length*length)<1.e-8,
151 "Repeated reconciliation lost the periodic bend");
152 }
153 else
154 {
155 require(loop->linkSequence().empty(),"Retraced contour was not removed");
156 for(const auto* link : partner->linkSequence())
157 {
158 if(const auto segment=link->networkLink())
159 {
160 require(std::abs(segment->burgers().norm()-burgers.norm())<1.e-10,
161 "Deleting a retraced loop corrupted the partner's Burgers contribution");
162 }
163 }
164 }
165 for(const auto& entry : network.loopNodes())
166 {
167 const auto n=entry.second.lock();
168 require((n->get_P()+n->periodicPlanePatch()->shift-n->networkNode->get_P()).norm()<1.e-8,
169 "Contour contraction broke periodic mapping");
170 }
171 continue;
172 }
173
174 const auto snapshot=[&]()
175 {
176 std::ostringstream out;
177 out<<std::hexfloat;
178 for(const auto& entry : network.networkNodes())
179 {
180 const auto n=entry.second.lock();
181 out<<n.get()<<' '<<n->sID<<' '<<n->get_P().transpose()<<' '<<n->get_V().transpose()<<'\n';
182 }
183 for(const auto& entry : network.loopNodes())
184 {
185 const auto n=entry.second.lock();
186 out<<n.get()<<' '<<n->sID<<' '<<n->get_P().transpose()<<' '<<n->networkNode.get()<<' '
187 <<n->loop()<<' '<<n->periodicPlanePatch().get()<<' '<<n->periodicPlaneEdge.first.get()<<' '
188 <<n->prev.first<<' '<<n->next.first<<'\n';
189 }
190 for(const auto& entry : network.networkLinks())
191 {
192 const auto link=entry.second.lock();
193 out<<link.get()<<' '<<link->source->sID<<' '<<link->sink->sID<<' '<<link->burgers().transpose()<<'\n';
194 }
195 for(const auto* n : network.danglingBoundaryLoopNodes)
196 {
197 out<<n<<'\n';
198 }
199 return out.str();
200 };
201 const V origin=V::Zero();
202 const auto a=network.networkNodes().create(origin);
203 const auto b=network.networkNodes().create(scenario==2 ? V(1.e-5,0,0) : scenario<2 ? V(1,0,0) : origin);
204 const auto makeNode=[&](const auto& loop,const auto& node)
205 {
206 return network.loopNodes().create(loop,node,node->get_P(),loop->periodicGlidePlane->getPatch(V::Zero()),
207 std::make_pair(std::shared_ptr<model::PeriodicPlaneEdge<3>>(),std::shared_ptr<model::PeriodicPlaneEdge<3>>()));
208 };
209 if(scenario==3)
210 {
211 const auto loop=network.loops().create(burgers,plane);
212 std::vector<std::shared_ptr<Network::LoopNodeType>> ring;
213 const std::vector<V> corners{V(10,0,0),V(10,10,0),V(0,10,0),V(-10,10,0),
214 V(-10,0,0),V(-10,-10,0),V(0,-10,0),V(10,-10,0)};
215 for(size_t k=0;k<4;++k)
216 {
217 ring.push_back(makeNode(loop,k%2==0 ? a : b));
218 ring.push_back(makeNode(loop,network.networkNodes().create(corners[2*k])));
219 ring.push_back(makeNode(loop,network.networkNodes().create(corners[2*k+1])));
220 }
221 network.insertLoop(loop,ring);
222 }
223 else
224 {
225 for(int k=0;k<2;++k)
226 {
227 const auto loop=network.loops().create(burgers,plane);
228 network.insertLoop(loop,std::vector<std::shared_ptr<Network::LoopNodeType>>{
229 makeNode(loop,k==0 ? a : b),
230 makeNode(loop,network.networkNodes().create(V(10,10+10*k,0))),
231 makeNode(loop,network.networkNodes().create(V(-10,10+10*k,0)))});
232 }
233 }
234 network.updateGeometry();
235 if(scenario<2)
236 {
237 const auto before=snapshot();
238 require(!network.contract(scenario==0 ? a : b,scenario==0 ? b : a),"Projected target incorrectly accepted");
239 require(snapshot()==before,"Rejected contraction mutated network state or junction identity");
240 require(!network.contract(a,a) && snapshot()==before,"Self-contraction changed network");
241 }
242 else
243 {
244 const V probe(3,4,20);
245 const auto stressBefore=network.stress(probe,nullptr,nullptr,nullptr);
246 require(network.contract(a,b),"Valid contraction failed");
247 require(b->loopNodes().empty(),"Removed endpoint still owns loop representations");
248 for(const auto& entry : network.loopNodes())
249 {
250 const auto n=entry.second.lock();
251 require((n->get_P()+n->periodicPlanePatch()->shift-n->networkNode->get_P()).norm()<1.e-10,
252 "Successful contraction did not reach exact mapped target");
253 }
254 network.updateGeometry();
255 if(scenario==3)
256 {
257 // Two A/B cuts create two additional loops. The remaining
258 // contour can still visit the surviving network node twice.
259 require(network.loops().size()==3,"Repeated visits produced incorrect loop splits");
260 require(a->loopNodes().size()==4,"Repeated-visit contraction lost junction sharing");
261 const auto stressAfter=network.stress(probe,nullptr,nullptr,nullptr);
262 require((stressAfter-stressBefore).norm()<1.e-10,"Coincident contraction changed stress/Burgers content");
263 }
264 for(const auto& entry : network.loops())
265 {
266 require(entry.second.lock()->isLoop(),"Contraction broke loop closure");
267 }
268 }
269 }
270 std::filesystem::remove_all(folder);
271 std::cout<<"PASS: contraction target verification, unchanged rejection, repeated visits\n";
272 return 0;
273 }
274 catch(const std::exception& error)
275 {
276 std::cerr<<error.what()<<'\n';
277 return 1;
278 }
279}
Eigen::Vector3d V
void updateBoundaryNodes(const std::function< void()> &checkpoint={})
bool contract(std::shared_ptr< NetworkNodeType > nA, std::shared_ptr< NetworkNodeType > nB)
MatrixDim stress(const VectorDim &, const NodeType *const, const ElementType *const ele, const SimplexDim *const guess) const override
std::set< const LoopNodeType * > danglingBoundaryLoopNodes
const LoopContainerType & loops() const
Definition LoopNetwork.h:98
const NetworkNodeContainerType & networkNodes() const
const LoopNodeContainerType & loopNodes() const
NetworkLinkContainerType & networkLinks()
void insertLoop(const std::shared_ptr< LoopType > &loop, const std::vector< std::shared_ptr< LoopNodeType > > nodes)
A class template that implements a counter of the number of instances of Derived type that are create...
Definition StaticID.h:29
c
Definition int_R.m:15
function int_R syms a b c u real f
Definition int_R.m:4
a
Definition int_R.m:14
b
Definition int_R.m:16
LatticePlaneKey< dim > GlidePlaneKey
int regions
Definition triangle.cpp:696
SharedPtrType create(const Args &...args)
void require(bool condition, const char *message)
model::DislocationNetwork< 3 > Network
int end[2]
void out
void argv
REAL pc
int corners
int axis
void b int argc
vertex p[3]
int k
REAL pb
REAL detsum vertex pa
REAL pd