Mechanics of Defect Evolution Library
Loading...
Searching...
No Matches
testRemeshSafety.cpp
Go to the documentation of this file.
6#include <filesystem>
7#include <fstream>
8#include <iomanip>
9#include <chrono>
10#include <iostream>
11#include <set>
12#include <array>
13
14void require(bool condition, const char* message)
15{
16 if(!condition)
17 {
18 throw std::runtime_error(message);
19 }
20}
21
22namespace model
23{
25 {
27 static bool eligible(Network& network,const std::pair<size_t,size_t>& key)
28 {
29 return network.networkRemesher.zeroChordCandidate(network.networkLinks().get(key));
30 }
31 static size_t contract(Network& network,const std::pair<size_t,size_t>& key)
32 {
33 return network.networkRemesher.contractZeroChordCandidates({key});
34 }
35 };
36}
37
38int main(int argc, char** argv)
39{
40 try
41 {
42 require(argc == 2, "Expected repository root");
43 const std::filesystem::path root(argv[1]);
44 const auto folder = std::filesystem::temp_directory_path() /
45 ("remesh-safety-" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()));
46 const auto input = folder / "inputFiles";
47 std::filesystem::create_directories(input);
48 std::filesystem::create_directories(folder / "F");
49 std::filesystem::copy_file(root / "Library/Materials/W.txt", input / "W.txt");
50
51 std::filesystem::copy_file(root / "Library/Meshes/bicrystal_48.msh", input / "mesh.msh");
52 std::filesystem::copy_file(root / "Library/DislocationDynamics/DD.txt", input / "DD.txt");
53 std::filesystem::create_directories(folder / "config");
54 model::SimplicialMesh<3> mesh((input/"mesh.msh").string(),Eigen::Matrix3d::Identity(),Eigen::Vector3d::Zero(),{-1});
55 std::array<int,3> seeds{-1,-1,-1};
56 for(const auto& region : mesh.regions())
57 {
58 for(const auto& face : region.second->faces())
59 {
60 const auto& pair=face.second->periodicFacePair;
61 if(pair.second)
62 {
63 for(int axis=0;axis<3;++axis)
64 {
65 if(pair.first.normalized().cross(Eigen::Vector3d::Unit(axis)).norm()<1.e-8)
66 {
67 seeds[axis]=face.first;
68 }
69 }
70 }
71 }
72 }
73 require(seeds[0]>=0 && seeds[1]>=0,"Missing periodic seeds");
74 model::StaticID<model::Polyhedron<3,3-1>>::force_count(0);
75 const double length=3671.9477120460206;
76 // A positive threshold distinguishes fresh area from a newly created
77 // loop's initially zero cached area.
78 {
79 std::ifstream source(input/"DD.txt");
80 std::string text((std::istreambuf_iterator<char>(source)),std::istreambuf_iterator<char>());
81 const auto begin=text.find("absoluteAreaThreshold=");
82 require(begin!=std::string::npos,"Missing area threshold");
83 text.replace(begin,text.find(';',begin)-begin,"absoluteAreaThreshold=1");
84 std::ofstream(input/"DD.txt")<<text;
85 }
86 for(int scenario=0;scenario<4;++scenario)
87 {
88 {
89 std::ofstream f(input/"DefectiveCrystal.txt");
90 f<<"physics=DislocationDynamics;\nuseFEM=0;\nNsteps=0;\nmaxResolveSteps=0;\ndtMax=1;\noutputFrequency=1;\noutputBinary=0;\nstartAtTimeStep=0;\nperiodicImageSize=0;\nEwaldLengthFactor=0;\n";
91 std::ofstream p(input/"polycrystal.txt");
92 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="<<seeds[1]<<";\n";
93 }
94 model::DefectiveCrystalBase<3> base(folder.string());
97 using V=Eigen::Vector3d;
98 Network network(container);
99 const auto grain=base.poly.grain(1);
100 const auto plane=base.dislocationDynamics().glidePlaneFactory.getFromKey(model::GlidePlaneKey<3>(V::Zero(),grain->reciprocalLatticeDirection(V::UnitZ())));
101 const V burgers=2.0/std::sqrt(3.0)*V::UnitX();
102 const V origin=scenario==0 ? V::Zero() : V(-0.5*length,0,0);
103 const auto node=[&](const V& offset)
104 {
105 return network.networkNodes().create(origin+offset);
106 };
107 const auto insert=[&](const auto& nodes)
108 {
109 const auto loop=network.loops().create(burgers,plane);
110 const auto patch=loop->periodicGlidePlane->getPatch(V::Zero());
111 std::vector<std::shared_ptr<Network::LoopNodeType>> ring;
112 for(const auto& n : nodes)
113 {
114 std::shared_ptr<model::PeriodicPlaneEdge<3>> edge;
115 for(const auto& candidate : patch->edges())
116 {
117 if(candidate->meshIntersection->contains(n->get_P()))
118 {
119 edge=candidate;
120 break;
121 }
122 }
123 ring.push_back(network.loopNodes().create(loop,n,n->get_P(),patch,
124 std::make_pair(edge,std::shared_ptr<model::PeriodicPlaneEdge<3>>())));
125 }
126 network.insertLoop(loop,ring);
127 return loop;
128 };
129 if(scenario==0)
130 {
131 const auto a=node(V::Zero());
132 const auto b=node(V::Zero());
133 const auto first=insert(std::vector{a,b,node(V(-10,10,0)),node(V(-10,-10,0))});
134 const auto second=insert(std::vector{a,b,node(V(-20,10,0)),node(V(-20,-10,0))});
135 network.updateGeometry();
136 require(a->isGrainBoundaryNode() && !a->isBoundaryNode(),"Expected internal GB node");
137 const V probe(100,100,100);
138 const Eigen::Matrix3d stress=network.stress(probe,nullptr,nullptr,nullptr);
139 network.networkRemesher.contract0chordSegments();
140 require(b->loopNodes().empty(),"Coincident GB nodes did not contract");
141 require(a->loopNodes().size()==2 && first->isLoop() && second->isLoop(),"GB contraction lost sharing");
142 network.updateGeometry();
143 require((network.stress(probe,nullptr,nullptr,nullptr)-stress).norm()<1.e-10,"GB contraction changed stress");
144 }
145 else if(scenario==1)
146 {
147 const auto a=node(V::Zero());
148 const auto b=node(V(20,0,0));
149 const auto c=node(V(0,20,0));
150 auto loop=insert(std::vector{a,b,c});
151 require(loop->slippedArea()==0 && loop->currentAreaVector().norm()>100,"Expected stale initial area");
152 network.networkRemesher.removeCollapsedLoops();
153 require(loop->isLoop(),"Positive-area loop deleted using stale zero area");
154 network.updateGeometry();
155 const V oldNormal=loop->rightHandedUnitNormal();
156 c->trySet_P(origin+V(0,-20,0));
157 require(loop->rightHandedUnitNormal().dot(oldNormal)>0.99,"Motion overwrote normal history");
158 require(loop->currentAreaVector().dot(oldNormal)<0,"Expected current contour to flip");
159 network.networkRemesher.removeCollapsedLoops();
160 require(loop->loopLinks().empty(),"Freshly inverted loop was not removed");
161 require((loop->rightHandedUnitNormal()-oldNormal).norm()==0,"Remeshing overwrote orientation history");
162
163 loop.reset();
164 const auto shrinking=insert(std::vector{node(V(40,0,0)),node(V(60,0,0)),node(V(40,20,0))});
165 network.updateGeometry();
166 auto apex=shrinking->linkSequence().back()->source->networkNode;
167 for(const auto* ll : shrinking->linkSequence())
168 {
169 if(ll->source->get_P().y()>10)
170 {
171 apex=ll->source->networkNode;
172 }
173 }
174 apex->trySet_P(origin+V(40,0.01,0));
175 require(shrinking->slippedArea()>100 && shrinking->currentAreaVector().norm()<1,"Expected stale large area");
176 network.networkRemesher.removeCollapsedLoops();
177 require(shrinking->loopLinks().empty(),"Fresh small-area loop was not removed");
178 }
179 else if(scenario==2)
180 {
181 const auto a=node(V::Zero());
182 const auto b=node(V::Zero());
183 const auto loop=insert(std::vector{a,b,node(V(20,20,0)),node(V(-20,20,0))});
184 network.updateGeometry();
185 const std::pair<size_t,size_t> key(a->sID,b->sID);
186 require(model::RemeshTestAccess::eligible(network,key),"Expected initial zero-chord candidate");
187 b->trySet_P(origin+V(10,0,0));
188 const auto count=network.networkNodes().size();
189 require(model::RemeshTestAccess::contract(network,key)==0,"Stale contraction candidate was accepted");
190 require(network.networkNodes().size()==count && b->loopNodes().size()==1 && loop->isLoop(),
191 "Rejected stale contraction changed topology");
192 require((b->get_P()-origin-V(10,0,0)).norm()<1.e-10,"Rejected contraction moved a node");
193 }
194 else
195 {
196 const auto a=node(V(-10,0,0));
197 const auto n=node(V::Zero());
198 const auto b=node(V(10,0,0));
199 const auto first=insert(std::vector{a,n,b,node(V(0,10,0))});
200 const auto second=insert(std::vector{b,n,node(V(-10,-10,0)),node(V(10,-10,0)),n,a,node(V(0,20,0))});
201 network.updateGeometry();
202 const auto before=network.loopLinks().size();
203 for(const auto* ll : first->linkSequence())
204 {
205 if(ll->source->networkNode==n)
206 {
207 require(!ll->source->isRemovable(25,100,0.001).first,"Distinct twin occurrences incorrectly removable");
208 }
209 }
210 require(network.loopLinks().size()==before,"Removal predicate changed topology");
211 network.networkRemesher.remeshByRemoval();
212 require(n->loopNodes().size()==3 && first->isLoop() && second->isLoop(),"Repeated visits lost junction sharing");
213 }
214 for(const auto& entry : network.loopNodes())
215 {
216 const auto ln=entry.second.lock();
217 require((ln->get_P()+ln->periodicPlanePatch()->shift-ln->networkNode->get_P()).norm()<1.e-7,
218 "Remeshing broke periodic mapping");
219 }
220 }
221 std::filesystem::remove_all(folder);
222 std::cout<<"PASS: internal GB contraction, fresh loop geometry, stale candidates, repeated loop visits\n";
223 return 0;
224 }
225 catch(const std::exception& error)
226 {
227 std::cerr<<error.what()<<'\n';
228 return 1;
229 }
230}
Eigen::Vector3d V
DislocationNetworkRemesh< dim > networkRemesher
MatrixDim stress(const VectorDim &, const NodeType *const, const ElementType *const ele, const SimplexDim *const guess) const override
LoopLinkContainerType & loopLinks()
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)
A class template that implements a counter of the number of instances of Derived type that are create...
Definition StaticID.h:29
c
Definition int_R.m:15
function int_R syms a b c u real f
Definition int_R.m:4
a
Definition int_R.m:14
b
Definition int_R.m:16
LatticePlaneKey< dim > GlidePlaneKey
int regions
Definition triangle.cpp:696
static size_t contract(Network &network, const std::pair< size_t, size_t > &key)
static bool eligible(Network &network, const std::pair< size_t, size_t > &key)
DislocationNetwork< 3 > Network
SharedPtrType create(const Args &...args)
SharedPtrType get(const KeyType &key) const
model::DislocationNetwork< 3 > Network
std::string text(Config &config)
void require(bool condition, const char *message)
void argv
int axis
void b int argc
vertex p[3]
newbad key
vertex first
apex(top, farvertex)