Mechanics of Defect Evolution Library
Loading...
Searching...
No Matches
testBicrystalBoundaryRemesh.cpp
Go to the documentation of this file.
4#include <filesystem>
5#include <fstream>
6#include <iomanip>
7#include <chrono>
8#include <iostream>
9#include <map>
10#include <set>
11#include <iterator>
12
13void require(bool condition, const char* message)
14{
15 if(!condition)
16 {
17 throw std::runtime_error(message);
18 }
19}
20
21int main(int argc, char** argv)
22{
23 try
24 {
25 require(argc == 2, "Expected repository root");
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");
33
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;
38 {
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";
45 }
46 // Match the tutorial remeshing length, without depending on its inputs.
47 {
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);
55 output<<contents;
56 }
57 for(int frame : {430,433,500})
58 {
59 model::DefectiveCrystalBase<3> base(folder.string());
61 model::DislocationNetwork<3> network(container);
62 model::DefectiveCrystalConfigIO<3> saved(folder.string());
63 std::ifstream stream(root/"tests/data"/("bicrystalBoundary"+std::to_string(frame)+".txt"));
64 require(bool(stream),"Missing bicrystal boundary regression fixture");
65 saved.readTxtStream(stream);
66 network.initializeConfiguration(saved,std::ofstream(),std::ofstream());
67 // Overlay one real bicrystal loop on the same network nodes to
68 // exercise a shared boundary chain (including nonzero junction Burgers).
69 {
70 std::shared_ptr<model::DislocationNetwork<3>::LoopType> source;
71 size_t mostPhysical=0;
72 for(const auto& entry : network.loops())
73 {
74 const auto candidate=entry.second.lock();
75 size_t physical=0;
76 for(const auto* link : candidate->linkSequence())
77 {
78 physical+=link->source->isPhysicalBoundaryNode();
79 }
80 if(physical>mostPhysical)
81 {
82 mostPhysical=physical;
83 source=candidate;
84 }
85 }
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())
90 {
91 const auto node=link->source;
92 nodes.push_back(network.loopNodes().create(overlay,node->networkNode,node->get_P(),
93 node->periodicPlanePatch(),node->periodicPlaneEdge));
94 }
95 network.insertLoop(overlay,nodes);
96 }
97 network.updateGeometry();
98 using V=Eigen::Vector3d;
99 const auto areas=[&]()
100 {
101 std::map<size_t,V> result;
102 for(const auto& entry : network.loops())
103 {
104 V area=V::Zero();
105 for(const auto* link : entry.second.lock()->linkSequence())
106 {
107 area+=0.5*link->source->get_P().cross(link->sink->get_P());
108 }
109 result.emplace(entry.first,area);
110 }
111 return result;
112 };
113 const auto check=[&](const std::map<size_t,V>& before,double tolerance)
114 {
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)
118 {
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");
121 }
122 for(const auto& entry : network.loopNodes())
123 {
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");
127 }
128 };
129 const auto initial=areas();
130 std::set<size_t> protectedNodes;
131 size_t sharedBefore=0;
132 for(const auto& entry : network.networkNodes())
133 {
134 const auto node=entry.second.lock();
135 bool protect=node->neighbors().size()!=2;
136 bool physical=false;
137 for(const auto* ln : node->loopNodes())
138 {
139 protect|=ln->isPeriodicSubdivision() || ln->periodicPlaneEdge.second!=nullptr;
140 physical|=ln->isPhysicalBoundaryNode();
141 }
142 if(protect)
143 {
144 protectedNodes.insert(entry.first);
145 }
146 sharedBefore+=physical && node->loopNodes().size()>1;
147 }
148 const auto sharedLengths=[&]()
149 {
150 std::map<std::set<size_t>,double> result;
151 for(const auto& entry : network.networkLinks())
152 {
153 const auto segment=entry.second.lock();
154 std::set<size_t> loops;
155 for(const auto* link : segment->loopLinks())
156 {
157 loops.insert(link->loop->sID);
158 }
159 result[loops]+=segment->chordLength();
160 }
161 return result;
162 };
163 const auto stress=[&]()
164 {
165 Eigen::Matrix3d result=Eigen::Matrix3d::Zero();
166 const V point(0.31*length,0.23*length,0.17*length);
167 for(const auto& entry : network.networkLinks())
168 {
169 const auto segment=entry.second.lock();
170 result+=segment->straight.stress(point);
171 }
172 return result;
173 };
174 const auto lengthsBefore=sharedLengths();
175 const auto stressBefore=stress();
176 const auto countBefore=network.networkNodes().size();
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)
183 {
184 require(network.networkNodes().find(id)!=network.networkNodes().end(),"Removed a corner, crossing or branching junction");
185 }
186 size_t sharedAfter=0;
187 for(const auto& entry : network.networkNodes())
188 {
189 const auto node=entry.second.lock();
190 bool physical=false;
191 for(const auto* ln : node->loopNodes())
192 {
193 physical|=ln->isPhysicalBoundaryNode();
194 }
195 sharedAfter+=physical && node->loopNodes().size()>1;
196 }
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)
201 {
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");
204 }
205 network.updateGeometry();
206 require((stress()-stressBefore).norm()<1.e-8*std::max(1.e-12,stressBefore.norm()),
207 "Simplification changed the network stress field");
208 network.updateBoundaryNodes();
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;
213 }
214 std::filesystem::remove_all(folder);
215 return 0;
216 }
217 catch(const std::exception& error)
218 {
219 std::cerr<<error.what()<<'\n';
220 return 1;
221 }
222}
Eigen::Vector3d V
DislocationNetworkRemesh< dim > networkRemesher
void updateBoundaryNodes(const std::function< void()> &checkpoint={})
void initializeConfiguration(const DefectiveCrystalConfigIO< dim > &configIO, const std::ofstream &f_file, const std::ofstream &F_labels) override
const LoopContainerType & loops() const
Definition LoopNetwork.h:98
const NetworkNodeContainerType & networkNodes() const
const LoopNodeContainerType & loopNodes() const
NetworkLinkContainerType & networkLinks()
void insertLoop(const std::shared_ptr< LoopType > &loop, const std::vector< std::shared_ptr< LoopNodeType > > nodes)
function int_R syms a b c u real f
Definition int_R.m:4
SharedPtrType create(const Args &...args)
void require(bool condition, const char *message)
void check(bool ok, const char *message)
void argv
void b int argc
vertex p[3]
REAL area
result