25 const std::filesystem::path root(
argv[1]);
26 const auto folder = std::filesystem::temp_directory_path() /
27 (
"node-motion-" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()));
28 const auto input = folder /
"inputFiles";
29 std::filesystem::create_directories(input);
30 std::filesystem::create_directories(folder /
"F");
31 std::filesystem::copy_file(root /
"Library/Materials/W.txt", input /
"W.txt");
32 const auto meshFile = root /
"Library/Meshes/unitCube24.msh";
33 std::filesystem::copy_file(meshFile, input /
"mesh.msh");
35 std::vector<int> seeds;
40 for(
const auto& face : region.second->faces())
42 const auto& pair = face.second->periodicFacePair;
43 if(pair.second && pair.first[
axis] > 0.9 &&
44 pair.first.normalized().cross(Eigen::Vector3d::Unit(
axis)).norm() < 1.e-8)
46 seeds.push_back(face.first);
51 require(seeds.size() == 3,
"Expected three cube periodic directions");
54 std::filesystem::copy_file(root /
"Library/DislocationDynamics/DD.txt", input /
"DD.txt");
55 const double length=200.0/std::sqrt(3.0);
56 for(
int scenario=0; scenario<5; ++scenario)
58 const int activeAxis=(scenario==0 || scenario==3 || scenario==4) ? 0 : 1;
60 std::ofstream
f(input /
"DefectiveCrystal.txt");
61 f <<
"physics=DislocationDynamics;\nuseFEM=0;\nNsteps=0;\nmaxResolveSteps=0;\ndtMax=1;\n"
62 <<
"outputFrequency=1;\noutputBinary=0;\nstartAtTimeStep=0;\nperiodicImageSize=0;\nEwaldLengthFactor=0;\n";
63 std::ofstream
p(input /
"polycrystal.txt");
64 p << std::setprecision(17) <<
"materialFile=W.txt;\nmeshFile=mesh.msh;\nabsoluteTemperature=300;\n"
65 <<
"C2G1=1 0 0 0 1 0 0 0 1;\nF=" << length <<
" 0 0 0 " << length <<
" 0 0 0 " << length
66 <<
";\nX0=0 0 0;\nperiodicFaceIDs=";
69 p << seeds[activeAxis];
76 using V=Eigen::Vector3d;
78 const auto grain=base.poly.grain(1);
79 const auto plane=base.dislocationDynamics().glidePlaneFactory.getFromKey(
model::GlidePlaneKey<3>(V::Zero(),grain->reciprocalLatticeDirection(V::UnitZ())));
80 const V burgers=2.0/std::sqrt(3.0)*V::UnitX();
83 const auto secondPlane=scenario==4 ? base.dislocationDynamics().glidePlaneFactory.getFromKey(
85 const auto second=network.
loops().
create(2.0*burgers,secondPlane);
86 const bool surface=scenario==2 || scenario==3;
87 const V a=length*(scenario==3 ?
V(0.4,0.5,0) : scenario==2 ?
V(0.5,0,0) :
V(0.4,0,0));
88 const V b=length*
V(0.1,0,0);
91 const auto makeNode=[&](
const auto& loop,
const auto& net,
const V& position)
93 return network.
loopNodes().
create(loop,net,position,loop->periodicGlidePlane->getPatch(V::Zero()),
96 network.
insertLoop(
first,std::vector<std::shared_ptr<Network::LoopNodeType>>{
99 network.
insertLoop(second,std::vector<std::shared_ptr<Network::LoopNodeType>>{
100 makeNode(second,nb,
b),makeNode(second,na,
a),
101 makeNode(second,network.
networkNodes().
create(length*(scenario==4 ?
V(0,0,-0.2) :
V(0,-0.2,0))),length*(scenario==4 ?
V(0,0,-0.2) :
V(0,-0.2,0)))});
103 const V requested=length*(scenario==2 ?
V(-0.2,0.1,0) : scenario==3 ?
V(0.1,-0.2,0) :
V(0.3,0,0));
104 na->set_V(requested,
true);
107 const int normal=scenario==2 ? 0 : 1;
108 require(std::abs(na->get_V()[normal])<1.e-8,
"Physical surface velocity was not projected");
112 require(
first->isLoop() && second->isLoop(),
"Motion broke loop closure");
115 require(na->loopNodes().empty(),
"Exited original node was not trimmed");
116 bool sharedExit=
false;
117 for(
const auto* link :
first->linkSequence())
119 const auto node=link->source->networkNode;
120 if(std::abs(node->get_P().x()-0.5*length)<1.e-7 && std::abs(node->get_P().y())<1.e-7)
122 sharedExit=node->loopNodes().size()==2;
125 require(sharedExit,
"Physical exit lost junction sharing");
129 const V expected=length*(scenario==2 ?
V(0.5,0.1,0) : scenario==3 ?
V(0.5,0.5,0) :
V(-0.3,0,0));
130 require((na->get_P()-expected).norm()<1.e-7,
"Incorrect committed position");
131 require(na->loopNodes().size()==2,
"Motion lost original junction identity");
132 require((na->get_V()-(surface ? length*(scenario==2 ?
V(0,0.1,0) :
V(0.1,0,0)) : requested)).norm()<1.e-7,
133 "Motion discarded velocity state");
137 const auto node=entry.second.lock();
138 require(base.mesh.search(node->get_P()).first,
"Committed a network node outside the RVE");
140 for(
const auto* link :
first->linkSequence())
142 require((link->source->get_P()+link->source->periodicPlanePatch()->shift-link->source->networkNode->get_P()).norm()<1.e-7,
143 "Loop and network positions disagree");
144 if(
const auto segment=link->networkLink())
146 if(segment->loopLinks().size()==2)
148 require(std::abs(segment->burgers().norm()-burgers.norm())<1.e-7,
"Motion changed junction Burgers vector");
154 na->set_V(length*
V(0.2,-0.1,0),
true);
155 require((na->get_V()-length*
V(0.2,0,0)).norm()<1.e-7,
"Periodic corner pinned surface sliding");
157 require((na->get_P()-length*
V(-0.3,0.5,0)).norm()<1.e-7,
"Mixed-corner continuation failed");
158 require(na->loopNodes().size()==2,
"Mixed corner split junction ownership");
162 const V oldPosition=na->get_P();
164 na->trySet_P(oldPosition+length*
V(0.05,0,0));
165 require((na->get_P()-oldPosition).norm()<1.e-8,
"Trial motion prematurely committed network position");
168 require((na->get_P()-oldPosition-length*
V(0.05,0,0)).norm()<1.e-7,
"Trial position not committed");
169 require(na->trySet_P(na->get_P()+length*
V(0.05,0,0)),
"Immediate motion failed");
170 require((na->get_P()-oldPosition-length*
V(0.1,0,0)).norm()<1.e-7,
"Standalone trySet_P did not commit");
175 entry.second.lock()->set_V(V::Zero(),
true);
178 require(
first->isLoop() && second->isLoop(),
"Repeated motion broke topology");
180 std::filesystem::remove_all(folder);
181 std::cout <<
"PASS: periodic crossing, physical exit, surface sliding and mixed corner motion\n";
184 catch(
const std::exception& error)
186 std::cerr << error.what() <<
'\n';