42 const std::filesystem::path root(
argv[1]);
43 const auto folder = std::filesystem::temp_directory_path() /
44 (
"thermal-cross-slip-" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()));
45 const auto input = folder /
"inputFiles";
46 std::filesystem::create_directories(input);
47 std::filesystem::create_directories(folder /
"F");
48 std::filesystem::copy_file(root /
"Library/Materials/W.txt", input /
"W.txt");
50 std::filesystem::copy_file(root /
"Library/Meshes/bicrystal_48.msh", input /
"mesh.msh");
51 std::filesystem::copy_file(root /
"Library/DislocationDynamics/DD.txt", input /
"DD.txt");
53 std::ifstream inputDD(input/
"DD.txt");
54 std::string contents((std::istreambuf_iterator<char>(inputDD)),std::istreambuf_iterator<char>());
55 const auto pos=contents.find(
"crossSlipModel=0;");
56 require(pos!=std::string::npos,
"Missing cross-slip setting");
57 contents.replace(pos,17,
"crossSlipModel=1;");
58 std::ofstream outputDD(input/
"DD.txt");
61 std::filesystem::create_directories(folder /
"config");
63 std::array<int,3> seeds{-1,-1,-1};
66 for(
const auto& face : region.second->faces())
68 const auto& pair=face.second->periodicFacePair;
73 if(pair.first.normalized().cross(Eigen::Vector3d::Unit(
axis)).norm()<1.e-8)
75 seeds[
axis]=face.first;
81 require(seeds[0]>=0 && seeds[1]>=0,
"Missing periodic seeds");
83 const double length=3671.9477120460206;
84 for(
int refinement : {1,2,12})
86 for(
int scenario=0;scenario<6;++scenario)
88 const bool full=scenario==1;
91 std::ofstream
f(input/
"DefectiveCrystal.txt");
92 f<<
"physics=DislocationDynamics;\nuseFEM=0;\nNsteps=0;\nmaxResolveSteps=0;\ndtMax=1;\noutputFrequency=1;\noutputBinary=0;\nstartAtTimeStep=0;\nperiodicImageSize="<<(full ?
"0 0 0" :
"0")<<
";\nEwaldLengthFactor=0;\n";
93 std::ofstream
p(input/
"polycrystal.txt");
94 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=";
97 p<<(full ? -1 : seeds[1]);
104 using V=Eigen::Vector3d;
106 const auto grain=base.poly.grain(1);
107 const auto slip=grain->slipSystems().begin()->second;
109 for(
size_t k=0;
k<grain->slipSystems().size();++
k)
111 const auto candidate=grain->slipSystems().at(
k);
112 if((candidate->s-slip->s).squaredNorm()==0 && candidate->unitNormal.cross(slip->unitNormal).norm()>0.1)
118 require(other>=0,
"No cross-slip system");
119 const auto css=grain->slipSystems().at(other);
120 const V b=slip->s.cartesian();
121 const V center=scenario==4 ? V::Zero().eval() :
V(length*
V(-0.5,
periodic ? 0.49 : 0.0,0));
122 const auto plane=base.dislocationDynamics().glidePlaneFactory.getFromKey(
model::GlidePlaneKey<3>(center,slip->n));
123 const long spacing=std::max(1L,
static_cast<long>(20.0/css->n.planeSpacing()));
124 const long height=std::lround(
double(css->n.closestPlaneIndexOfPoint(center))/spacing)*spacing;
126 V origin=intersection.
P+(center-intersection.
P).dot(intersection.
d)*intersection.
d;
127 V along=intersection.
d;
128 if(scenario==4 && along.x()<0.0)
132 V side=plane->unitNormal.cross(along).normalized();
135 origin=-0.15*length*along;
143 origin+=(0.5*length+2.0-origin.y())/along.y()*along;
145 const V a=origin-0.15*length*along;
146 const V middle=origin;
147 const V end=origin+0.15*length*along;
148 std::vector<V> polygon{
a,middle,
end,
end+100.0*side,
a+100.0*side};
151 polygon[1]-=4.0/side.y()*side;
155 polygon[0]+=0.2*side;
156 polygon[1]+=0.2*side;
157 polygon[2]+=2.0*css->n.planeSpacing()/css->unitNormal.dot(side)*side;
159 if(scenario!=3 && scenario!=5)
162 for(
int k=0;
k<=refinement;++
k)
164 polygon.push_back(
a+(
end-
a)*(
double(
k)/refinement));
166 polygon.push_back(
end+100.0*side);
167 polygon.push_back(
a+100.0*side);
173 const auto parent=network.
loops().begin()->second.lock();
174 std::deque<std::shared_ptr<Network::LoopNodeType>> branch;
175 for(
const auto& point : std::vector<V>{polygon.front(),polygon[polygon.size()-3]})
177 for(
const auto* link :
parent->linkSequence())
179 if((link->source->get_P()-point).norm()<1.e-6 && !link->source->isPeriodicSubdivision())
181 branch.push_back(link->source);
186 require(branch.size()==2,
"Missing branch anchors");
187 if(scenario==3 || scenario==5)
189 for(
const auto* link :
parent->linkSequence())
191 if((link->source->get_P()-polygon[1]).norm()<1.e-6 && !link->source->isPeriodicSubdivision())
193 branch.insert(branch.begin()+1,link->source);
200 const auto endpoint=branch.back()->networkNode;
201 const V normal=scenario==3 ? css->unitNormal : plane->unitNormal;
202 const auto extraPlane=base.dislocationDynamics().glidePlaneFactory.getFromKey(
model::GlidePlaneKey<3>(endpoint->get_P(),grain->reciprocalLatticeDirection(normal)));
204 V u=normal.cross(along).normalized();
205 if(scenario==4 &&
u.x()>0.0)
211 std::vector<std::shared_ptr<Network::LoopNodeType>> ring;
212 for(
const auto& node : std::vector{endpoint,e1,e2})
214 ring.push_back(network.
loopNodes().
create(extra,node,node->get_P(),extra->periodicGlidePlane->getPatch(V::Zero()),std::make_pair(
nullptr,
nullptr)));
218 const auto snapshot=[&]()
220 std::ostringstream
out;
221 out<<std::setprecision(17);
224 const auto node=entry.second.lock();
225 out<<node->sID<<
' '<<node->get_P().transpose()<<
' '<<node->get_V().transpose()<<
'\n';
227 for(
const auto& entry : network.
loops())
229 out<<entry.first<<
'\n';
230 for(
const auto* link : entry.second.lock()->linkSequence())
232 out<<link->source->sID<<
' '<<link->source->networkNode->sID<<
' '<<link->source->get_P().transpose()<<
' '<<link->sink->sID<<
'\n';
237 const auto before=snapshot();
238 const auto endpointID=endpoint->sID;
239 const auto middleNode=branch[1]->networkNode;
240 const V oldMiddle=middleNode->get_P();
245 require(snapshot()==before,
"Rejected alignment changed network");
250 require((middleNode->get_P()-oldMiddle).norm()>0.5*length,
"Alignment did not cross the periodic face");
251 require(network.
networkNodes().
get(middleNode->sID)==middleNode,
"Alignment lost network identity at seam");
255 require(network.
loops().size()==3,
"Cross-slip seed was discarded");
256 require(network.
networkNodes().
get(endpointID)==endpoint && endpoint->loopNodes().size()==2,
"Shared endpoint was detached");
257 std::shared_ptr<Network::LoopType> seed;
258 for(
const auto& entry : network.
loops())
260 const auto loop=entry.second.lock();
261 if(loop!=
parent && loop!=extra)
266 require(seed && seed->loopLinks().size()>=4 && seed->slipSystem(),
"Invalid zero-area seed");
267 double perimeter=0.0;
268 for(
const auto* link : seed->linkSequence())
270 perimeter+=(link->sink->get_P()-link->source->get_P()).norm();
272 require(std::abs(perimeter-600.0)<1.e-6,
"Nucleus length depends on segmentation");
273 require(seed->currentAreaVector().norm()<1.e-6,
"Seed added slipped area before motion");
274 size_t seams=0,cancelled=0;
275 for(
const auto* link : seed->linkSequence())
277 seams+=link->source->isPeriodicSubdivision();
278 if(link->networkLink() && link->networkLink()->loopLinks().size()==2)
280 require(link->networkLink()->hasZeroBurgers(),
"Parent branch Burgers vector not cancelled");
283 require((link->source->get_P()+link->source->periodicPlanePatch()->shift-link->source->networkNode->get_P()).norm()<1.e-6,
"Incorrect periodic mapping");
285 require(cancelled>=2,
"No cancellation on original branch");
286 require((seams>0)==(
periodic && scenario!=4),
"Periodic crossing was not preserved");
287 const auto expected=network.
glideSolver->getNodeVelocities();
291 const auto node=entry.second.lock();
292 const V stored=node->get_V();
293 node->set_V(expected.segment<3>(3*
k),
false);
294 require((stored-node->get_V()).norm()<1.e-7,
"Stale nodal velocity after cross-slip");
301 entry.second.lock()->set_V(V::Zero(),
false);
303 for(
const auto* link : seed->linkSequence())
305 const auto node=link->source->networkNode;
306 if(node->loopNodes().size()==1)
308 node->set_V(css->unitNormal.cross(along).normalized(),
false);
312 require(seed->currentAreaVector().norm()>1.e-6,
"Seed failed to expand under motion");
313 require(endpoint->loopNodes().size()==2,
"Motion lost shared endpoint");
316 std::filesystem::remove_all(folder);
317 std::cout<<
"PASS: thermal nucleus length, periodic mapping, shared endpoint, fresh velocities and atomic rejection\n";
320 catch(
const std::exception& error)
322 std::cerr<<error.what()<<
'\n';