36 require(
argc<3 || std::string(
argv[2])!=
"--require-assertions",
"Assertions are disabled in this test build");
38 std::cout<<
"Assertions enabled in periodic glissile-junction regression\n";
40 const std::filesystem::path root(
argv[1]);
41 const auto folder=std::filesystem::temp_directory_path()/
42 (
"periodic-glissile-"+std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()));
43 const auto input=folder/
"inputFiles";
44 std::filesystem::create_directories(input);
45 std::filesystem::create_directories(folder/
"F");
46 std::filesystem::create_directories(folder/
"config");
47 std::filesystem::copy_file(root/
"Library/Materials/W.txt",input/
"W.txt");
48 std::filesystem::copy_file(root/
"Library/DislocationDynamics/DD.txt",input/
"DD.txt");
49 std::filesystem::copy_file(root/
"Library/Meshes/unitCube24.msh",input/
"mesh.msh");
51 using V=Eigen::Vector3d;
53 std::array<int,3> seeds{-1,-1,-1};
56 for(
const auto& face : region.second->faces())
58 const auto& pair=face.second->periodicFacePair;
63 if(pair.first[
axis]>0.9 && pair.first.normalized().cross(V::Unit(
axis)).norm()<1.e-8)
65 seeds[
axis]=face.first;
71 require(seeds[0]>=0 && seeds[1]>=0,
"Missing periodic face seeds");
73 const double length=200.0/std::sqrt(3.0);
74 for(
int scenario=0;scenario<4;++scenario)
76 const bool corner=scenario==1 || scenario==2;
77 const bool twoEnds=scenario!=1;
78 const int rank=
corner? 3 : (scenario==3? 2 : 1);
80 std::ofstream
f(input/
"DefectiveCrystal.txt");
81 f<<
"physics=DislocationDynamics;\nuseFEM=0;\nNsteps=0;\nmaxResolveSteps=0;\ndtMax=1;\noutputFrequency=1;\noutputBinary=0;\nstartAtTimeStep=0;\nperiodicImageSize=";
82 for(
int k=0;
k<rank;++
k)
86 f<<
";\nEwaldLengthFactor=0;\n";
87 std::ofstream
p(input/
"polycrystal.txt");
88 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=";
89 for(
int k=0;
k<rank;++
k)
98 const auto grain=base.poly.grain(1);
99 const V direction=
corner?
V(1,1,1) : (scenario==3?
V(1,1,0) :
V(1,0,0));
100 const V parentNormal=
corner?
V(1,-1,0).normalized().eval() : V::UnitZ().eval();
101 const V side=parentNormal.cross(direction).normalized();
102 const auto planeAt=[&](
const V& point)
104 return base.dislocationDynamics().glidePlaneFactory.getFromKey(
model::GlidePlaneKey<3>(point,grain->reciprocalLatticeDirection(parentNormal)));
106 const auto plane=planeAt(V::Zero());
108 for(
const auto& [
id,slip] : grain->slipSystems())
110 if(std::abs(slip->unitNormal.dot(direction))<1.e-8 &&
111 std::abs(slip->s.cartesian().dot(parentNormal))>1.e-8)
113 burgers=slip->s.cartesian();
117 require(burgers.norm()>0.0,
"No glissile Burgers vector for test direction");
118 const auto insert=[&](
const V&
b,
const auto& gp,
const auto& netNodes)
121 std::vector<std::shared_ptr<Network::LoopNodeType>> nodes;
122 for(
const auto& node : netNodes)
125 loop->periodicGlidePlane->getPatch(V::Zero()),std::make_pair(
nullptr,
nullptr)));
134 const auto first=insert(2.0*burgers,plane,std::vector{
a,
b,
c});
135 const auto second=insert(-burgers,plane,std::vector{
a,
b,d});
141 a->trySet_P(-0.9*length*direction);
143 b->trySet_P(0.9*length*direction);
147 const double threshold=twoEnds? 0.8*length*direction.norm() : 0.0;
148 std::shared_ptr<Network::NetworkLinkType> selected;
149 std::vector<std::shared_ptr<Network::NetworkLinkType>> shared;
152 const auto link=entry.second.lock();
153 if(link->loopLinks().size()==2)
155 shared.push_back(link);
156 if(link->chordLength()>threshold && !selected)
162 require(selected && shared.size()>=2,
"Missing shared periodic continuation");
165 for(
const auto* occurrence : selected->loopLinks())
167 require(occurrence->source->isPeriodicSubdivision() && occurrence->sink->isPeriodicSubdivision(),
168 "Test did not isolate a segment with two periodic endpoints");
173 auto endpoint=selected->source;
174 if(!(*selected->loopLinks().begin())->source->isPeriodicSubdivision())
176 endpoint=selected->sink;
178 const auto unrelated=network.
loops().
create(burgers,plane);
179 std::map<size_t,std::shared_ptr<Network::NetworkNodeType>> copies;
180 std::vector<std::shared_ptr<Network::LoopNodeType>> unrelatedNodes;
181 for(
const auto* link :
first->linkSequence())
183 const auto& node=link->source;
184 auto& copy=copies[node->networkNode->sID];
187 copy=node->networkNode==endpoint? endpoint : network.
networkNodes().
clone(node->networkNode->sID);
189 unrelatedNodes.push_back(network.
loopNodes().
create(unrelated,copy,node->get_P(),
190 node->periodicPlanePatch(),node->periodicPlaneEdge));
193 unrelatedNodes.clear();
196 const V unrelatedArea=unrelated->currentAreaVector();
197 const auto memberships=endpoint->loopNodes();
198 const Eigen::Matrix3d stressBefore=network.
stress(
V(7,11,19),
nullptr,
nullptr,
nullptr);
201 require(network.
loops().size()==4,
"Expected exactly one glissile seed for the whole continuation");
202 for(
auto* occurrence : memberships)
204 require(endpoint->loopNodes().count(occurrence)==1,
"Shared periodic endpoint was detached");
206 require(endpoint->loopNodes().size()>memberships.size(),
"Seed did not share the periodic endpoint");
207 require((unrelated->currentAreaVector()-unrelatedArea).norm()<1.e-8,
"Unrelated loop at periodic endpoint changed");
208 require((network.
stress(
V(7,11,19),
nullptr,
nullptr,
nullptr)-stressBefore).norm()<1.e-9*std::max(1.e-12,stressBefore.norm()),
209 "Zero-area junction seed changed the stress field");
210 for(
const auto& link : shared)
212 require(link->loopLinks().size()==3 && link->hasZeroBurgers(),
"Seed lost junction sharing or Burgers cancellation");
214 std::shared_ptr<Network::LoopType> seed;
215 for(
const auto& entry : network.
loops())
217 const auto loop=entry.second.lock();
218 if(loop!=
first && loop!=second && loop!=unrelated)
223 require(seed && seed->isLoop() && seed->currentAreaVector().norm()<1.e-8,
"Invalid glissile seed");
225 for(
const auto* link : seed->linkSequence())
227 const auto node=link->source;
228 corners+=bool(node->periodicPlaneEdge.second);
229 require((node->get_P()+node->periodicPlanePatch()->shift-node->networkNode->get_P()).norm()<1.e-7,
"Incorrect seed patch translation");
230 for(
const auto& edge : {node->periodicPlaneEdge.first,node->periodicPlaneEdge.second})
234 require(edge->patch==node->periodicPlanePatch().get() && edge->meshIntersection->contains(node->networkNode->get_P()),
235 "Invalid corner edge metadata");
244 entry.second.lock()->set_V(V::Zero(),
false);
246 for(
const auto* link : seed->linkSequence())
248 const auto node=link->source;
249 if(!node->isPeriodicSubdivision() && node->networkNode->loopNodes().size()==1)
251 node->networkNode->set_V(seed->glidePlane->unitNormal.cross(direction).normalized(),
false);
254 double sharedLengthBefore=0.0;
255 for(
const auto& link : shared)
257 sharedLengthBefore+=link->chordLength();
262 require(seed->currentAreaVector().norm()>1.e-8,
"Glissile seed did not expand");
263 double sharedLengthAfter=0.0;
266 const auto segment=entry.second.lock();
267 bool hasFirst=
false,hasSecond=
false,hasSeed=
false;
268 for(
const auto* occurrence : segment->loopLinks())
270 hasFirst=hasFirst || occurrence->loop==
first;
271 hasSecond=hasSecond || occurrence->loop==second;
272 hasSeed=hasSeed || occurrence->loop==seed;
274 if(hasFirst && hasSecond && hasSeed)
276 require(segment->hasZeroBurgers(),
"Motion lost Burgers cancellation on shared continuation");
277 sharedLengthAfter+=segment->chordLength();
280 require(std::abs(sharedLengthAfter-sharedLengthBefore)<1.e-7,
"Motion lost sharing along the periodic continuation");
281 for(
const auto& entry : network.
loopNodes())
283 const auto node=entry.second.lock();
284 require((node->get_P()+node->periodicPlanePatch()->shift-node->networkNode->get_P()).norm()<1.e-7,
285 "Motion lost periodic mapping");
287 require((unrelated->currentAreaVector()-unrelatedArea).norm()<1.e-7,
"Seed motion altered unrelated loop");
288 require(
first->isLoop() && second->isLoop() && unrelated->isLoop() && seed->isLoop(),
"Motion broke loop closure");
289 std::cout<<
"PASS periodic glissile scenario "<<scenario<<
'\n';
291 std::filesystem::remove_all(folder);
293 catch(
const std::exception& error)
295 std::cerr<<error.what()<<
'\n';