26 const std::filesystem::path root(
argv[1]);
27 const auto folder = std::filesystem::temp_directory_path() /
28 (
"bicrystal-boundary-remesh-" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()));
29 const auto input = folder /
"inputFiles";
30 std::filesystem::create_directories(input);
31 std::filesystem::create_directories(folder /
"F");
32 std::filesystem::copy_file(root /
"Library/Materials/W.txt", input /
"W.txt");
34 std::filesystem::copy_file(root /
"Library/Meshes/bicrystal_48.msh", input /
"mesh.msh");
35 std::filesystem::copy_file(root /
"Library/DislocationDynamics/DD.txt", input /
"DD.txt");
36 std::filesystem::create_directories(folder /
"config");
37 const double length=3671.9477120460206;
39 std::ofstream
f(input /
"DefectiveCrystal.txt");
40 f <<
"physics=DislocationDynamics;\nuseFEM=0;\nNsteps=0;\nmaxResolveSteps=0;\ndtMax=1;\noutputFrequency=1;\noutputBinary=0;\nstartAtTimeStep=0;\nperiodicImageSize=0 0 0;\nEwaldLengthFactor=0;\n";
41 std::ofstream
p(input /
"polycrystal.txt");
42 p << std::setprecision(17) <<
"materialFile=W.txt;\nmeshFile=mesh.msh;\nabsoluteTemperature=300;\nC2G1=1 0 0 0 1 0 0 0 1;\n"
43 <<
"C2G2=0.8 0 0.6 0 1 0 -0.6 0 0.8;\nF=" << length <<
" 0 0 0 " << length <<
" 0 0 0 " << length
44 <<
";\nX0=0 0 0;\nperiodicFaceIDs=-1;\n";
48 const auto dd=input/
"DD.txt";
49 std::ifstream source(dd);
50 std::string contents((std::istreambuf_iterator<char>(source)),std::istreambuf_iterator<char>());
51 const auto location=contents.find(
"Lmax=100;");
52 require(location!=std::string::npos,
"Expected library remeshing default");
53 contents.replace(location,std::string(
"Lmax=100;").size(),
"Lmax=150;");
54 std::ofstream output(dd);
57 for(
int frame : {430,433,500})
63 std::ifstream stream(root/
"tests/data"/(
"bicrystalBoundary"+std::to_string(frame)+
".txt"));
64 require(
bool(stream),
"Missing bicrystal boundary regression fixture");
70 std::shared_ptr<model::DislocationNetwork<3>::LoopType> source;
71 size_t mostPhysical=0;
72 for(
const auto& entry : network.
loops())
74 const auto candidate=entry.second.lock();
76 for(
const auto* link : candidate->linkSequence())
78 physical+=link->source->isPhysicalBoundaryNode();
80 if(physical>mostPhysical)
82 mostPhysical=physical;
86 require(
bool(source),
"Missing physical-boundary loop");
87 const auto overlay=network.
loops().
create(source->burgers(),source->glidePlane);
88 std::vector<std::shared_ptr<model::DislocationNetwork<3>::LoopNodeType>> nodes;
89 for(
const auto* link : source->linkSequence())
91 const auto node=link->source;
92 nodes.push_back(network.
loopNodes().
create(overlay,node->networkNode,node->get_P(),
93 node->periodicPlanePatch(),node->periodicPlaneEdge));
98 using V=Eigen::Vector3d;
99 const auto areas=[&]()
101 std::map<size_t,V>
result;
102 for(
const auto& entry : network.
loops())
105 for(
const auto* link : entry.second.lock()->linkSequence())
107 area+=0.5*link->source->get_P().cross(link->sink->get_P());
113 const auto check=[&](
const std::map<size_t,V>& before,
double tolerance)
115 const auto after=areas();
116 require(after.size()==8 && after.size()==before.size(),
"Boundary update split or lost a loop");
117 for(
const auto& entry : before)
119 require((after.at(entry.first)-entry.second).norm()<tolerance*std::max(1.0,entry.second.norm()),
120 "Boundary walk jumped to another contour branch");
122 for(
const auto& entry : network.
loopNodes())
124 const auto node=entry.second.lock();
125 require((node->get_P()+node->periodicPlanePatch()->shift-node->networkNode->get_P()).norm()<1.e-7,
126 "Loop/network periodic mapping is inconsistent");
129 const auto initial=areas();
130 std::set<size_t> protectedNodes;
131 size_t sharedBefore=0;
134 const auto node=entry.second.lock();
135 bool protect=node->neighbors().size()!=2;
137 for(
const auto* ln : node->loopNodes())
139 protect|=ln->isPeriodicSubdivision() || ln->periodicPlaneEdge.second!=
nullptr;
140 physical|=ln->isPhysicalBoundaryNode();
144 protectedNodes.insert(entry.first);
146 sharedBefore+=physical && node->loopNodes().size()>1;
148 const auto sharedLengths=[&]()
150 std::map<std::set<size_t>,
double>
result;
153 const auto segment=entry.second.lock();
154 std::set<size_t> loops;
155 for(
const auto* link : segment->loopLinks())
157 loops.insert(link->loop->sID);
159 result[loops]+=segment->chordLength();
163 const auto stress=[&]()
165 Eigen::Matrix3d
result=Eigen::Matrix3d::Zero();
166 const V point(0.31*length,0.23*length,0.17*length);
169 const auto segment=entry.second.lock();
170 result+=segment->straight.stress(point);
174 const auto lengthsBefore=sharedLengths();
175 const auto stressBefore=stress();
177 const auto removed=network.
networkRemesher.simplifyPhysicalBoundaryChains();
178 require(removed>0,
"No redundant boundary nodes removed");
179 require(network.
networkNodes().size()+removed==countBefore,
"Network nodes leaked after removal");
180 require(network.
networkRemesher.simplifyPhysicalBoundaryChains()==0,
"Simplification did not reach a fixed point");
181 check(initial,1.e-10);
182 for(
const auto id : protectedNodes)
186 size_t sharedAfter=0;
189 const auto node=entry.second.lock();
191 for(
const auto* ln : node->loopNodes())
193 physical|=ln->isPhysicalBoundaryNode();
195 sharedAfter+=physical && node->loopNodes().size()>1;
197 require(sharedAfter<sharedBefore,
"Did not simplify any shared physical-boundary chains");
198 const auto lengthsAfter=sharedLengths();
199 require(lengthsBefore.size()==lengthsAfter.size(),
"Changed participating loop sets");
200 for(
const auto& entry : lengthsBefore)
202 require(std::abs(lengthsAfter.at(entry.first)-entry.second)<1.e-8*std::max(1.0,entry.second),
203 "Changed junction sharing or segment lengths");
206 require((stress()-stressBefore).norm()<1.e-8*std::max(1.e-12,stressBefore.norm()),
207 "Simplification changed the network stress field");
209 check(initial,1.e-10);
210 require(network.
networkRemesher.simplifyPhysicalBoundaryChains()==0,
"Boundary update recreated redundant nodes");
211 std::cout<<
"Frame "<<frame<<
": removed "<<removed<<
" network nodes, shared physical nodes "
212 <<sharedBefore<<
" -> "<<sharedAfter<<std::endl;
214 std::filesystem::remove_all(folder);
217 catch(
const std::exception& error)
219 std::cerr<<error.what()<<
'\n';