Mechanics of Defect Evolution Library
Loading...
Searching...
No Matches
testPartialPeriodicRemesh.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
22int main(int argc, char** argv)
23{
24 try
25 {
26 require(argc == 2, "Expected repository root");
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");
34
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");
38 model::SimplicialMesh<3> mesh((input/"mesh.msh").string(),Eigen::Matrix3d::Identity(),Eigen::Vector3d::Zero(),{-1});
39 std::array<int,3> seeds{-1,-1,-1};
40 for(const auto& region : mesh.regions())
41 {
42 for(const auto& face : region.second->faces())
43 {
44 const auto& pair=face.second->periodicFacePair;
45 if(pair.second)
46 {
47 for(int axis=0;axis<3;++axis)
48 {
49 if(pair.first.normalized().cross(Eigen::Vector3d::Unit(axis)).norm()<1.e-8)
50 {
51 seeds[axis]=face.first;
52 }
53 }
54 }
55 }
56 }
57 require(seeds[0]>=0 && seeds[1]>=0,"Missing periodic seeds");
58 model::StaticID<model::Polyhedron<3,3-1>>::force_count(0);
59 const double length=3671.9477120460206;
60 for(int scenario=0;scenario<3;++scenario)
61 {
62 const bool full=scenario==1;
63 const bool periodic=scenario<2;
64 {
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=";
69 if(periodic)
70 {
71 p<<(full ? -1 : seeds[1]);
72 }
73 p<<";\n";
74 }
75 model::DefectiveCrystalBase<3> base(folder.string());
78 using V=Eigen::Vector3d;
79 Network network(container);
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)
84 {
85 const auto loop=network.loops().create(burgers,plane);
86 std::vector<std::shared_ptr<Network::LoopNodeType>> ring;
87 for(const auto& node : nodes)
88 {
89 ring.push_back(network.loopNodes().create(loop,node,node->get_P(),loop->periodicGlidePlane->getPatch(V::Zero()),
90 std::make_pair(std::shared_ptr<model::PeriodicPlaneEdge<3>>(),std::shared_ptr<model::PeriodicPlaneEdge<3>>())));
91 }
92 network.insertLoop(loop,ring);
93 return loop;
94 };
95 if(periodic)
96 {
97 const auto a=network.networkNodes().create(length*V(-0.5,0,0));
98 const auto b=network.networkNodes().create(length*V(-0.5,0.4,0));
99 const auto c=network.networkNodes().create(length*V(-0.7,0.1,0));
100 const auto d=network.networkNodes().create(length*V(-0.3,0.1,0));
101 const auto first=insert(std::vector{a,b,c});
102 const auto second=insert(std::vector{a,b,d});
103 network.updateBoundaryNodes();
104 network.trialNodeMotion=true;
105 b->trySet_P(length*V(-0.5,0.7,0));
106 network.updateBoundaryNodes();
107 network.trialNodeMotion=false;
108 network.updateGeometry();
109 // Copy the shared arc out and back: two physical anchors plus
110 // same-grain periodic subdivisions, with exactly zero area.
111 std::vector<std::shared_ptr<Network::LoopNodeType>> arc;
112 for(const auto* ll : first->linkSequence())
113 {
114 if(ll->source->networkNode==a)
115 {
116 auto node=ll->source;
117 arc.push_back(node);
118 while(node->networkNode!=b)
119 {
120 node=network.loopNodes().get(node->next.first->sID);
121 arc.push_back(node);
122 require(arc.size()<20,"Cannot find shared periodic arc");
123 }
124 break;
125 }
126 }
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);
130 const auto nodeCount=network.networkNodes().size();
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)
135 {
136 ring.push_back(network.loopNodes().create(collapsed,node->networkNode,node->get_P(),node->periodicPlanePatch(),node->periodicPlaneEdge));
137 };
138 for(const auto& node : arc)
139 {
140 append(node);
141 }
142 for(size_t i=arc.size()-2;i>0;--i)
143 {
144 append(arc[i]);
145 }
146 network.insertLoop(collapsed,ring);
147 ring.clear();
148 network.updateGeometry();
149 require(collapsed->slippedArea()<FLT_EPSILON,"Fixture is not collapsed");
150 collapsed.reset();
151 network.networkRemesher.remove0AreaLoopAcrossBnd();
152 require(!network.loops().get(collapsedID),"Collapsed periodic loop was retained");
153 require(network.networkNodes().size()==nodeCount,"Cleanup lost shared network nodes");
154 require(first->isLoop() && second->isLoop(),"Cleanup broke surviving loops");
155 network.updateBoundaryNodes();
156 network.updateGeometry();
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)
160 {
161 if(arc[i]->periodicPlanePatch()==arc[i-1]->periodicPlanePatch())
162 {
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");
166 }
167 }
168 }
169 // Physical faces are real anchors even for a zero-area seed loop.
170 // x=0 is an internal GB; x=-1 is a periodic GB only in the full case.
171 for(const double x : {0.0,-1.0})
172 {
173 auto seed=network.loops().create(burgers,plane);
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})
177 {
178 const V pos=length*V(x,y,0);
179 std::shared_ptr<model::PeriodicPlaneEdge<3>> edge;
180 for(const auto& candidate : patch->edges())
181 {
182 if(candidate->meshIntersection->contains(pos))
183 {
184 edge=candidate;
185 break;
186 }
187 }
188 require(bool(edge),"Missing physical edge");
189 const auto node=network.networkNodes().create(pos);
190 ring.push_back(network.loopNodes().create(seed,node,pos,patch,std::make_pair(edge,std::shared_ptr<model::PeriodicPlaneEdge<3>>())));
191 require(ring.back()->isPhysicalBoundaryNode(),"Expected physical GB/surface anchor");
192 }
193 network.insertLoop(seed,ring);
194 ring.clear();
195 network.updateGeometry();
196 require(seed->slippedArea()<FLT_EPSILON,"Expected zero-area physical seed");
197 network.networkRemesher.remove0AreaLoopAcrossBnd();
198 require(seed->isLoop() && seed->loopLinks().size()==3,"Cleanup removed physical boundary anchors");
199 }
200 for(const auto& entry : network.loopNodes())
201 {
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");
205 }
206 }
207 std::filesystem::remove_all(folder);
208 std::cout<<"PASS: partial/full periodic cleanup, junction sharing, physical/GB anchors\n";
209 return 0;
210 }
211 catch(const std::exception& error)
212 {
213 std::cerr<<error.what()<<'\n';
214 return 1;
215 }
216}
Eigen::Vector3d V
DislocationNetworkRemesh< dim > networkRemesher
void updateBoundaryNodes(const std::function< void()> &checkpoint={})
MatrixDim stress(const VectorDim &, const NodeType *const, const ElementType *const ele, const SimplexDim *const guess) const 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)
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
x
Definition int_R.m:12
LatticePlaneKey< dim > GlidePlaneKey
int regions
Definition triangle.cpp:696
SharedPtrType create(const Args &...args)
SharedPtrType get(const KeyType &key) const
void periodic(const Trial &field, double relative=1.e-10)
model::DislocationNetwork< 3 > Network
void require(bool condition, const char *message)
void argv
int axis
void b int argc
vertex p[3]
int i
vertex first