43 const std::filesystem::path root(
argv[1]);
44 const auto folder = std::filesystem::temp_directory_path() /
45 (
"remesh-safety-" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()));
46 const auto input = folder /
"inputFiles";
47 std::filesystem::create_directories(input);
48 std::filesystem::create_directories(folder /
"F");
49 std::filesystem::copy_file(root /
"Library/Materials/W.txt", input /
"W.txt");
51 std::filesystem::copy_file(root /
"Library/Meshes/bicrystal_48.msh", input /
"mesh.msh");
52 std::filesystem::copy_file(root /
"Library/DislocationDynamics/DD.txt", input /
"DD.txt");
53 std::filesystem::create_directories(folder /
"config");
55 std::array<int,3> seeds{-1,-1,-1};
58 for(
const auto& face : region.second->faces())
60 const auto& pair=face.second->periodicFacePair;
65 if(pair.first.normalized().cross(Eigen::Vector3d::Unit(
axis)).norm()<1.e-8)
67 seeds[
axis]=face.first;
73 require(seeds[0]>=0 && seeds[1]>=0,
"Missing periodic seeds");
75 const double length=3671.9477120460206;
79 std::ifstream source(input/
"DD.txt");
80 std::string
text((std::istreambuf_iterator<char>(source)),std::istreambuf_iterator<char>());
81 const auto begin=
text.find(
"absoluteAreaThreshold=");
82 require(begin!=std::string::npos,
"Missing area threshold");
83 text.replace(begin,
text.find(
';',begin)-begin,
"absoluteAreaThreshold=1");
84 std::ofstream(input/
"DD.txt")<<
text;
86 for(
int scenario=0;scenario<4;++scenario)
89 std::ofstream
f(input/
"DefectiveCrystal.txt");
90 f<<
"physics=DislocationDynamics;\nuseFEM=0;\nNsteps=0;\nmaxResolveSteps=0;\ndtMax=1;\noutputFrequency=1;\noutputBinary=0;\nstartAtTimeStep=0;\nperiodicImageSize=0;\nEwaldLengthFactor=0;\n";
91 std::ofstream
p(input/
"polycrystal.txt");
92 p<<std::setprecision(17)<<
"materialFile=W.txt;\nmeshFile=mesh.msh;\nabsoluteTemperature=300;\nC2G1=1 0 0 0 1 0 0 0 1;\nC2G2=0.8 0 0.6 0 1 0 -0.6 0 0.8;\nF="<<length<<
" 0 0 0 "<<length<<
" 0 0 0 "<<length<<
";\nX0=0 0 0;\nperiodicFaceIDs="<<seeds[1]<<
";\n";
97 using V=Eigen::Vector3d;
99 const auto grain=base.poly.grain(1);
100 const auto plane=base.dislocationDynamics().glidePlaneFactory.getFromKey(
model::GlidePlaneKey<3>(V::Zero(),grain->reciprocalLatticeDirection(V::UnitZ())));
101 const V burgers=2.0/std::sqrt(3.0)*V::UnitX();
102 const V origin=scenario==0 ? V::Zero() :
V(-0.5*length,0,0);
103 const auto node=[&](
const V& offset)
107 const auto insert=[&](
const auto& nodes)
109 const auto loop=network.
loops().
create(burgers,plane);
110 const auto patch=loop->periodicGlidePlane->getPatch(V::Zero());
111 std::vector<std::shared_ptr<Network::LoopNodeType>> ring;
112 for(
const auto& n : nodes)
114 std::shared_ptr<model::PeriodicPlaneEdge<3>> edge;
115 for(
const auto& candidate : patch->edges())
117 if(candidate->meshIntersection->contains(n->get_P()))
131 const auto a=node(V::Zero());
132 const auto b=node(V::Zero());
133 const auto first=insert(std::vector{
a,
b,node(
V(-10,10,0)),node(
V(-10,-10,0))});
134 const auto second=insert(std::vector{
a,
b,node(
V(-20,10,0)),node(
V(-20,-10,0))});
136 require(
a->isGrainBoundaryNode() && !
a->isBoundaryNode(),
"Expected internal GB node");
137 const V probe(100,100,100);
138 const Eigen::Matrix3d stress=network.
stress(probe,
nullptr,
nullptr,
nullptr);
140 require(
b->loopNodes().empty(),
"Coincident GB nodes did not contract");
141 require(
a->loopNodes().size()==2 &&
first->isLoop() && second->isLoop(),
"GB contraction lost sharing");
143 require((network.
stress(probe,
nullptr,
nullptr,
nullptr)-stress).norm()<1.e-10,
"GB contraction changed stress");
147 const auto a=node(V::Zero());
148 const auto b=node(
V(20,0,0));
149 const auto c=node(
V(0,20,0));
150 auto loop=insert(std::vector{
a,
b,
c});
151 require(loop->slippedArea()==0 && loop->currentAreaVector().norm()>100,
"Expected stale initial area");
153 require(loop->isLoop(),
"Positive-area loop deleted using stale zero area");
155 const V oldNormal=loop->rightHandedUnitNormal();
156 c->trySet_P(origin+
V(0,-20,0));
157 require(loop->rightHandedUnitNormal().dot(oldNormal)>0.99,
"Motion overwrote normal history");
158 require(loop->currentAreaVector().dot(oldNormal)<0,
"Expected current contour to flip");
160 require(loop->loopLinks().empty(),
"Freshly inverted loop was not removed");
161 require((loop->rightHandedUnitNormal()-oldNormal).norm()==0,
"Remeshing overwrote orientation history");
164 const auto shrinking=insert(std::vector{node(
V(40,0,0)),node(
V(60,0,0)),node(
V(40,20,0))});
166 auto apex=shrinking->linkSequence().back()->source->networkNode;
167 for(
const auto* ll : shrinking->linkSequence())
169 if(ll->source->get_P().y()>10)
171 apex=ll->source->networkNode;
174 apex->trySet_P(origin+
V(40,0.01,0));
175 require(shrinking->slippedArea()>100 && shrinking->currentAreaVector().norm()<1,
"Expected stale large area");
177 require(shrinking->loopLinks().empty(),
"Fresh small-area loop was not removed");
181 const auto a=node(V::Zero());
182 const auto b=node(V::Zero());
183 const auto loop=insert(std::vector{
a,
b,node(
V(20,20,0)),node(
V(-20,20,0))});
185 const std::pair<size_t,size_t>
key(
a->sID,
b->sID);
187 b->trySet_P(origin+
V(10,0,0));
191 "Rejected stale contraction changed topology");
192 require((
b->get_P()-origin-
V(10,0,0)).norm()<1.e-10,
"Rejected contraction moved a node");
196 const auto a=node(
V(-10,0,0));
197 const auto n=node(V::Zero());
198 const auto b=node(
V(10,0,0));
199 const auto first=insert(std::vector{
a,n,
b,node(
V(0,10,0))});
200 const auto second=insert(std::vector{
b,n,node(
V(-10,-10,0)),node(
V(10,-10,0)),n,
a,node(
V(0,20,0))});
202 const auto before=network.
loopLinks().size();
203 for(
const auto* ll :
first->linkSequence())
205 if(ll->source->networkNode==n)
207 require(!ll->source->isRemovable(25,100,0.001).first,
"Distinct twin occurrences incorrectly removable");
210 require(network.
loopLinks().size()==before,
"Removal predicate changed topology");
212 require(n->loopNodes().size()==3 &&
first->isLoop() && second->isLoop(),
"Repeated visits lost junction sharing");
214 for(
const auto& entry : network.
loopNodes())
216 const auto ln=entry.second.lock();
217 require((ln->get_P()+ln->periodicPlanePatch()->shift-ln->networkNode->get_P()).norm()<1.e-7,
218 "Remeshing broke periodic mapping");
221 std::filesystem::remove_all(folder);
222 std::cout<<
"PASS: internal GB contraction, fresh loop geometry, stale candidates, repeated loop visits\n";
225 catch(
const std::exception& error)
227 std::cerr<<error.what()<<
'\n';