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");
36 std::vector<int> seeds;
41 for(
const auto& face : region.second->faces())
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)
47 seeds.push_back(face.first);
52 require(seeds.size() == 3,
"Expected three cube periodic directions");
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)
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;
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";
75 require(base.periodicLatticeBasis.cols()==1,
"Incorrect active periodic rank");
78 using V=Eigen::Vector3d;
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();
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);
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)
98 return network.
loopNodes().
create(owner,net,position,owner->periodicGlidePlane->getPatch(V::Zero()),
102 std::vector<std::shared_ptr<Network::LoopNodeType>> ring{make(loop,
a,
pa)};
107 ring.push_back(make(loop,
c,
pc));
108 ring.push_back(make(loop,
b,
pb));
110 const V pd=length*
V(0.2,-0.2,0);
111 network.
insertLoop(partner,std::vector<std::shared_ptr<Network::LoopNodeType>>{
116 const V partnerArea=partner->currentAreaVector();
119 for(
const auto& entry : network.
loopNodes())
121 entry.second.lock()->periodicContourVertex=
false;
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");
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())
136 if((link->source->get_P()-bend).norm()<1.e-8)
138 require(!link->source->isPeriodicSubdivision(),
"Genuine bend is still a subdivision");
142 require(retainedBends>0,
"Missing periodic contour vertex");
145 for(
const auto* link : loop->linkSequence())
147 link->source->periodicContourVertex=
false;
150 require(std::abs(loop->currentAreaVector().norm()-0.05*length*length)<1.e-8,
151 "Repeated reconciliation lost the periodic bend");
155 require(loop->linkSequence().empty(),
"Retraced contour was not removed");
156 for(
const auto* link : partner->linkSequence())
158 if(
const auto segment=link->networkLink())
160 require(std::abs(segment->burgers().norm()-burgers.norm())<1.e-10,
161 "Deleting a retraced loop corrupted the partner's Burgers contribution");
165 for(
const auto& entry : network.
loopNodes())
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");
174 const auto snapshot=[&]()
176 std::ostringstream
out;
180 const auto n=entry.second.lock();
181 out<<n.get()<<
' '<<n->sID<<
' '<<n->get_P().transpose()<<
' '<<n->get_V().transpose()<<
'\n';
183 for(
const auto& entry : network.
loopNodes())
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';
192 const auto link=entry.second.lock();
193 out<<link.get()<<
' '<<link->source->sID<<
' '<<link->sink->sID<<
' '<<link->burgers().transpose()<<
'\n';
201 const V origin=V::Zero();
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)
206 return network.
loopNodes().
create(loop,node,node->get_P(),loop->periodicGlidePlane->getPatch(V::Zero()),
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)
217 ring.push_back(makeNode(loop,
k%2==0 ?
a :
b));
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),
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");
244 const V probe(3,4,20);
245 const auto stressBefore=network.
stress(probe,
nullptr,
nullptr,
nullptr);
247 require(
b->loopNodes().empty(),
"Removed endpoint still owns loop representations");
248 for(
const auto& entry : network.
loopNodes())
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");
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");
264 for(
const auto& entry : network.
loops())
266 require(entry.second.lock()->isLoop(),
"Contraction broke loop closure");
270 std::filesystem::remove_all(folder);
271 std::cout<<
"PASS: contraction target verification, unchanged rejection, repeated visits\n";
274 catch(
const std::exception& error)
276 std::cerr<<error.what()<<
'\n';