27 const std::filesystem::path root(
argv[1]);
28 const auto folder = std::filesystem::temp_directory_path() /
29 (
"partial-remesh-" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()));
30 const auto input = folder /
"inputFiles";
31 std::filesystem::create_directories(input);
32 std::filesystem::create_directories(folder /
"F");
33 std::filesystem::copy_file(root /
"Library/Materials/W.txt", input /
"W.txt");
35 std::filesystem::copy_file(root /
"Library/Meshes/bicrystal_48.msh", input /
"mesh.msh");
36 std::filesystem::copy_file(root /
"Library/DislocationDynamics/DD.txt", input /
"DD.txt");
37 std::filesystem::create_directories(folder /
"config");
39 std::array<int,3> seeds{-1,-1,-1};
42 for(
const auto& face : region.second->faces())
44 const auto& pair=face.second->periodicFacePair;
49 if(pair.first.normalized().cross(Eigen::Vector3d::Unit(
axis)).norm()<1.e-8)
51 seeds[
axis]=face.first;
57 require(seeds[0]>=0 && seeds[1]>=0,
"Missing periodic seeds");
59 const double length=3671.9477120460206;
60 for(
int scenario=0;scenario<3;++scenario)
62 const bool full=scenario==1;
65 std::ofstream
f(input/
"DefectiveCrystal.txt");
66 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";
67 std::ofstream
p(input/
"polycrystal.txt");
68 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=";
71 p<<(full ? -1 : seeds[1]);
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();
83 const auto insert=[&](
const auto& nodes)
85 const auto loop=network.
loops().
create(burgers,plane);
86 std::vector<std::shared_ptr<Network::LoopNodeType>> ring;
87 for(
const auto& node : nodes)
89 ring.push_back(network.
loopNodes().
create(loop,node,node->get_P(),loop->periodicGlidePlane->getPatch(V::Zero()),
101 const auto first=insert(std::vector{
a,
b,
c});
102 const auto second=insert(std::vector{
a,
b,d});
105 b->trySet_P(length*
V(-0.5,0.7,0));
111 std::vector<std::shared_ptr<Network::LoopNodeType>> arc;
112 for(
const auto* ll :
first->linkSequence())
114 if(ll->source->networkNode==
a)
116 auto node=ll->source;
118 while(node->networkNode!=
b)
122 require(arc.size()<20,
"Cannot find shared periodic arc");
127 require(arc.size()>2,
"Missing periodic subdivisions");
128 const V probe=length*
V(0.3,0.2,0.1);
129 const Eigen::Matrix3d stressBefore=network.
stress(probe,
nullptr,
nullptr,
nullptr);
131 auto collapsed=network.
loops().
create(burgers,plane);
132 const auto collapsedID=collapsed->sID;
133 std::vector<std::shared_ptr<Network::LoopNodeType>> ring;
134 const auto append=[&](
const auto& node)
136 ring.push_back(network.
loopNodes().
create(collapsed,node->networkNode,node->get_P(),node->periodicPlanePatch(),node->periodicPlaneEdge));
138 for(
const auto& node : arc)
142 for(
size_t i=arc.size()-2;
i>0;--
i)
149 require(collapsed->slippedArea()<FLT_EPSILON,
"Fixture is not collapsed");
152 require(!network.
loops().
get(collapsedID),
"Collapsed periodic loop was retained");
154 require(
first->isLoop() && second->isLoop(),
"Cleanup broke surviving loops");
157 require((network.
stress(probe,
nullptr,
nullptr,
nullptr)-stressBefore).norm()<1.e-9*std::max(1.e-12,stressBefore.norm()),
158 "Cleanup changed shared junction stress");
159 for(
size_t i=1;
i<arc.size();++
i)
161 if(arc[
i]->periodicPlanePatch()==arc[
i-1]->periodicPlanePatch())
163 const auto link=network.
networkLinks().
get(std::minmax(arc[
i]->networkNode->sID,arc[
i-1]->networkNode->sID));
164 require(link && link->loopLinks().size()==2 && std::abs(link->burgers().norm()-2*burgers.norm())<1.e-8,
165 "Cleanup changed junction sharing or Burgers sum");
171 for(
const double x : {0.0,-1.0})
174 const auto patch=seed->periodicGlidePlane->getPatch(V::Zero());
175 std::vector<std::shared_ptr<Network::LoopNodeType>> ring;
176 for(
const double y : {-0.2,0.0,0.2})
178 const V pos=length*
V(
x,
y,0);
179 std::shared_ptr<model::PeriodicPlaneEdge<3>> edge;
180 for(
const auto& candidate : patch->edges())
182 if(candidate->meshIntersection->contains(pos))
188 require(
bool(edge),
"Missing physical edge");
191 require(ring.back()->isPhysicalBoundaryNode(),
"Expected physical GB/surface anchor");
196 require(seed->slippedArea()<FLT_EPSILON,
"Expected zero-area physical seed");
198 require(seed->isLoop() && seed->loopLinks().size()==3,
"Cleanup removed physical boundary anchors");
200 for(
const auto& entry : network.
loopNodes())
202 const auto node=entry.second.lock();
203 require((node->get_P()+node->periodicPlanePatch()->shift-node->networkNode->get_P()).norm()<1.e-7,
204 "Remeshing broke periodic mapping");
207 std::filesystem::remove_all(folder);
208 std::cout<<
"PASS: partial/full periodic cleanup, junction sharing, physical/GB anchors\n";
211 catch(
const std::exception& error)
213 std::cerr<<error.what()<<
'\n';