Mechanics of Defect Evolution Library
Loading...
Searching...
No Matches
testPrismaticLoopAtomic.cpp
Go to the documentation of this file.
5#include <filesystem>
6#include <fstream>
7#include <iomanip>
8#include <chrono>
9#include <iostream>
10#include <set>
11#include <sstream>
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 || argc == 3, "Expected repository root");
26 const std::filesystem::path root(argv[1]);
27 const auto folder = std::filesystem::temp_directory_path() /
28 ("prismatic-atomic-" + 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 model::DefectiveCrystalBase<3> base(folder.string());
47 using V=Eigen::Vector3d;
48 model::MicrostructureGenerator generator(base);
49 const auto snapshot=[&]()
50 {
51 std::ostringstream out;
52 out<<std::setprecision(17);
53 for(const auto& x : generator.config().nodes())
54 {
55 out<<x<<'\n';
56 }
57 for(const auto& x : generator.config().loops())
58 {
59 out<<x<<'\n';
60 }
61 for(const auto& x : generator.config().loopNodes())
62 {
63 out<<x<<'\n';
64 }
65 for(const auto& x : generator.config().loopLinks())
66 {
67 out<<x<<'\n';
68 }
69 for(const auto& x : generator.uniqueNetworkNodeMap)
70 {
71 out<<x.first.transpose()<<' '<<x.second<<'\n';
72 }
73 return out.str();
74 };
75 const auto insert=[&](const V& center,const double steps)
76 {
78 spec.slipSystemIDs={0};
79 spec.loopRadii={1.e-7};
80 spec.glideSteps={steps};
81 spec.loopCenters.resize(1,3);
82 spec.loopCenters.row(0)=center;
83 generator.addPrismaticLoopIndividual(spec);
84 };
85 const auto reject=[&](const V& center,const double steps)
86 {
87 const auto before=snapshot();
88 bool rejected=false;
89 try
90 {
91 insert(center,steps);
92 }
93 catch(const std::runtime_error&)
94 {
95 rejected=true;
96 }
97 require(rejected,"Prism crossing into another grain was accepted");
98 require(snapshot()==before,"Failed prism changed loops, nodes, links or the node map");
99 };
100 // A failed first attempt must leave every output container empty.
101 reject(V(-0.02*length,0,0),50);
102 require(generator.config().loops().empty() && generator.config().nodes().empty() &&
103 generator.config().loopNodes().empty() && generator.config().loopLinks().empty() &&
104 generator.uniqueNetworkNodeMap.empty(),"Failed first prism left residual topology");
105 insert(V(-0.5*length,0,0),50);
106 require(generator.config().loops().size()==7,"Contained prism is incomplete");
107 // Reject both the internal GB and the cross-grain periodic back face.
108 reject(V(-0.02*length,0,0),50);
109 reject(V(-0.98*length,0,0),50);
110 // The base fits, but the translated cap and sides cross a GB.
111 reject(V(-0.5*length,0,0),10000);
112 reject(V(-0.5*length,0,0),-10000);
113 const size_t oldLoops=generator.config().loops().size();
114 // Cross two same-grain periodic directions at a box corner.
115 insert(V(-0.5*length,0.49*length,0.49*length),50);
116 require(generator.config().loops().size()==oldLoops+7,"Same-grain periodic prism is incomplete");
117 size_t shifted=0;
118 std::map<std::pair<size_t,size_t>,V> burgers;
119 std::set<std::pair<size_t,size_t>> baseEdges;
120 for(const auto& node : generator.config().loopNodes())
121 {
122 shifted+=node.periodicShift.norm()>1.e-8;
123 }
124 require(shifted>0,"Periodic acceptance test never crossed a seam");
125 for(const auto& link : generator.config().loopLinks())
126 {
127 if(link.hasNetworkLink)
128 {
129 const auto& source=generator.config().loopNodes().at(link.sourceID);
130 const auto& sink=generator.config().loopNodes().at(link.sinkID);
131 const auto& loop=generator.config().loops().at(link.loopID);
132 const auto key=std::make_pair(std::min(source.networkNodeID,sink.networkNodeID),
133 std::max(source.networkNodeID,sink.networkNodeID));
134 auto entry=burgers.emplace(key,V::Zero()).first;
135 entry->second+=(source.networkNodeID<sink.networkNodeID? 1.0 : -1.0)*loop.B;
137 {
138 baseEdges.insert(key);
139 }
140 }
141 }
142 require(!baseEdges.empty(),"No sessile base edges tested");
143 for(const auto& key : baseEdges)
144 {
145 require(burgers.at(key).norm()<1.e-10,"Prism base edge lacks Burgers cancellation");
146 }
147 reject(V(-0.02*length,0,0),50);
148 std::filesystem::remove_all(folder);
149 std::cout<<"PASS: atomic prism rejection, same-grain periodic crossings and base cancellation\n";
150 return 0;
151 }
152 catch(const std::exception& error)
153 {
154 std::cerr<<error.what()<<'\n';
155 return 1;
156 }
157}
Eigen::Vector3d V
function int_R syms a b c u real f
Definition int_R.m:4
x
Definition int_R.m:12
void require(bool condition, const char *message)
void out
void argv
void b int argc
vertex p[3]
newbad key