Mechanics of Defect Evolution Library
Loading...
Searching...
No Matches
testPeriodicClimbSolver.cpp
Go to the documentation of this file.
1#include <ClusterDynamics.h>
7#include <filesystem>
8#include <fstream>
9#include <regex>
10#include <chrono>
11#include <iostream>
12#include <iomanip>
13using namespace model;
14namespace fs = std::filesystem;
15void require(bool ok, const std::string &message)
16{
17 if (!ok)
18 {
19 throw std::runtime_error(message);
20 }
21}
22std::string read(const fs::path &path)
23{
24 std::ifstream stream(path);
25 return {std::istreambuf_iterator<char>(stream), std::istreambuf_iterator<char>()};
26}
27void parameter(std::string &text, const std::string &key, const std::string &value)
28{
29 const std::regex pattern("(^|\\n)\\s*" + key + "\\s*=[^;]*;");
30 require(std::regex_search(text, pattern), "Missing parameter " + key);
31 text = std::regex_replace(text, pattern, "$1" + key + "=" + value + ";");
32}
33fs::path fixture(const fs::path &root, int rank, int reactions, bool source, const std::string &name = "unitCube24.msh")
34{
35 const auto folder =
36 fs::temp_directory_path() /
37 ("cluster-periodic-" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()));
38 fs::create_directories(folder / "inputFiles");
39 fs::create_directories(folder / "config");
40 fs::create_directories(folder / "F");
41 fs::copy_file(root / "Library/Meshes" / name, folder / "inputFiles/mesh.msh");
42 auto material = read(root / "Library/Materials/Zr4_Fitted.txt");
43 parameter(material, "computeReactions", reactions ? "1" : "0");
44 parameter(material, "doseRate_dpaPerSec", source ? "1e-7" : "0");
45 parameter(material, "otherSinks_SI", reactions == 1 ? "1e14 1e14 1e14 1e14" : "0 0 0 0");
46 std::string map;
47 const int species[4] = {-1, 1, 2, 3};
48 for (int i = 0; i < 4; ++i)
49 {
50 for (int j = i; j < 4; ++j)
51 {
52 map += std::to_string(species[i]) + " " + std::to_string(species[j]) + " " +
53 ((reactions == 2 && i == 0 && j == 1) ? "1\n" : "0\n");
54 }
55 }
56 parameter(material, "reactionPrefactorMap", map);
57 if (reactions == 2)
58 {
59 parameter(material, "mobileSpeciesCascadeFractions", "1 1 0 0");
60 }
61 std::ofstream(folder / "inputFiles/material.txt") << material;
62 std::ofstream(folder / "inputFiles/ClusterDynamics.txt") << "useClusterDynamicsFEM=1;\n";
63 const Eigen::Matrix3d F =
64 (Eigen::Matrix3d() << 100, 50, 0, 0, 50 * std::sqrt(3.0), 0, 0, 0, 100 * std::sqrt(8.0 / 3.0)).finished();
65 StaticID<Polyhedron<3, 3 - 1>>::force_count(0);
66 std::set<int> seeds;
67 {
68 SimplicialMesh<3> mesh((root / "Library/Meshes" / name).string(), F, Eigen::Vector3d::Zero(), {-1});
69 for (const auto &region : mesh.regions())
70 {
71 for (const auto &entry : region.second->faces())
72 {
73 if (entry.second->periodicFacePair.second)
74 {
75 for (int d = 0; d < rank; ++d)
76 {
77 if (entry.second->periodicFacePair.first.normalized().cross(F.col(d).normalized()).norm() <
78 1.e-8)
79 {
80 seeds.insert(entry.first);
81 }
82 }
83 }
84 }
85 }
86 }
87 StaticID<Polyhedron<3, 3 - 1>>::force_count(0);
88 std::ofstream poly(folder / "inputFiles/polycrystal.txt");
89 poly << std::setprecision(17) << "materialFile=material.txt;\nmeshFile=" << "mesh.msh"
90 << ";\nabsoluteTemperature=600;\nF=";
91 for (int i = 0; i < 3; ++i)
92 {
93 poly << F.row(i) << "\n";
94 }
95 poly << ";\nX0=0 0 0;\nperiodicFaceIDs=";
96 for (int seed : seeds)
97 {
98 poly << seed << " ";
99 }
100 poly << ";\n";
101 const int grains = name == "bicrystal_48.msh" ? 2 : (name.find("polycrystal") != std::string::npos ? 10 : 1);
102 for (int g = 1; g <= grains; ++g)
103 {
104 poly << "C2G" << g << "=1 0 0 0 1 0 0 0 1;\n";
105 }
106 std::ofstream dc(folder / "inputFiles/DefectiveCrystal.txt");
107 dc << "physics=ClusterDynamics;\nuseFEM=1;\nNsteps=1;\nmaxResolveSteps=0;\ndtMax=1;\noutputFrequency=1;"
108 "\noutputBinary=0;\nstartAtTimeStep=0;\nperiodicImageSize=";
109 for (int d = 0; d < rank; ++d)
110 {
111 dc << "0 ";
112 }
113 dc << ";\nEwaldLengthFactor=0;\n";
114 return folder;
115}
116
117void climb(const fs::path &root, int rank)
118{
119 const auto folder = fixture(root, rank, 0, false);
120 auto dc = read(folder / "inputFiles/DefectiveCrystal.txt");
121 parameter(dc, "physics", "ClusterDynamics DislocationDynamics");
122 std::ofstream(folder / "inputFiles/DefectiveCrystal.txt") << dc;
123 fs::copy_file(root / "Library/DislocationDynamics/DD.txt", folder / "inputFiles/DD.txt");
124 DefectiveCrystalBase<3> base(folder.string());
125 MicrostructureGenerator generator(base);
126 const auto grain = base.poly.grain(1);
127 const Eigen::Vector3d center = Eigen::Vector3d::Zero();
128 const Eigen::Vector3d normal = Eigen::Vector3d::UnitZ();
129 const auto key = GlidePlaneKey<3>(center, grain->reciprocalLatticeDirection(normal));
130 const auto plane = base.dislocationDynamics().periodicGlidePlaneFactory.getFromKey(key);
131 const Eigen::Vector3d burgers(0, 0, std::sqrt(8.0 / 3.0));
132 const double halfWidth = rank > 0 ? 25.0 : 20.0;
133 const double centerX = rank > 0 ? 40.0 : 0.0;
134 std::vector<Eigen::Vector3d> polygon{{centerX - halfWidth, -10, 0},
135 {centerX + halfWidth, -10, 0},
136 {centerX + halfWidth, 10, 0},
137 {centerX - halfWidth, 10, 0}};
138 require(generator.insertJunctionLoop(polygon, plane, burgers, normal, center, 1, DislocationLoopIO<3>::SESSILELOOP),
139 "Failed to insert climb loop");
140 MicrostructureContainer<3> container(base);
141 auto cd = std::make_shared<ClusterDynamics<3>>(container);
142 container.push_back(cd);
143 DislocationNetwork<3> network(container);
144 network.initializeConfiguration(generator.config(), std::ofstream(), std::ofstream());
145 const auto original = network.loops().begin()->second.lock();
146 const auto duplicate = network.loops().create(original->burgers(), original->glidePlane);
147 std::vector<std::shared_ptr<DislocationLoopNode<3>>> nodes;
148 for (const auto *link : original->linkSequence())
149 {
150 const auto &node = link->source;
151 nodes.push_back(network.loopNodes().create(duplicate, node->networkNode, node->get_P(),
152 node->periodicPlanePatch(), node->periodicPlaneEdge));
153 }
154 network.insertLoop(duplicate, nodes);
155 network.updateGeometry();
156 size_t quadrature = 0;
157 for (const auto &entry : network.networkLinks())
158 {
159 const auto link = entry.second.lock();
160 link->createQuadraturePoints(true);
161 for (auto &qp : link->quadraturePoints())
162 {
163 qp.cCD.setZero();
164 qp.cDD.setZero();
165 qp.cDD(0) = 1.e-4;
166 ++quadrature;
167 }
168 }
169 require(quadrature > 0, "Climb regression has no active quadrature points");
170 require(bool(network.climbSolver), "Climb solver not enabled");
171 network.climbSolver->computeClimbScalarVelocities(true);
172 const auto velocity = network.climbSolver->getNodeVelocities();
173 require(velocity.allFinite() && velocity.norm() > 0, "Climb drive produced no finite motion");
174 size_t relations = 0;
176 network,
177 [&](size_t n, size_t a, size_t b, double wa, double wb)
178 {
179 ++relations;
180 require((velocity.segment<3>(3 * n) - wa * velocity.segment<3>(3 * a) - wb * velocity.segment<3>(3 * b))
181 .norm() < 1.e-9 * velocity.norm(),
182 "Actual climb solver violates periodic vector interpolation");
183 });
184 require(rank == 0 || relations > 0, "Periodic climb test has no crossings");
185 size_t tangentialMarkers = 0;
186 size_t localIndex = 0;
187 for (const auto &entry : network.networkNodes())
188 {
189 const auto node = entry.second.lock();
190 const auto direction = node->climbDirection();
191 const auto value = velocity.segment<3>(3 * localIndex);
192 const auto &species = network.climbSolver->scalarVelocities()[localIndex];
193 const double normalSpeed = -(species * cd->cdp.msVector / cd->cdp.msVector.abs()).sum();
194 require(std::abs(value.dot(direction) - normalSpeed) < 1.e-9 * velocity.norm(),
195 "Climb source strength differs from normal motion");
196 if ((value - direction * value.dot(direction)).norm() > 1.e-8 * velocity.norm())
197 {
198 ++tangentialMarkers;
199 }
200 ++localIndex;
201 }
202 require(rank == 0 || tangentialMarkers > 0, "Regression does not exercise tangential subdivision motion");
203 network.climbSolver->computeClimbScalarVelocities(false);
204 require((network.climbSolver->getNodeVelocities() - velocity).norm() < 1.e-10 * velocity.norm(),
205 "Cached climb solve changed velocities");
206 size_t index = 0;
207 for (const auto &entry : network.networkNodes())
208 {
209 entry.second.lock()->set_V(velocity.segment<3>(3 * index++), true);
210 }
211 network.moveNodes(1.e-4 / velocity.norm());
212 for (const auto &entry : network.networkLinks())
213 {
214 require(entry.second.lock()->loopLinks().size() == 2, "Climb motion broke shared junction ownership");
215 }
216 fs::remove_all(folder);
217}
218int main(int argc, char **argv)
219{
220 try
221 {
222 require(argc == 2, "Expected repository root");
223 for (int rank : {0, 1, 3})
224 {
225 climb(argv[1], rank);
226 }
227 std::cout << "PASS: coupled CD/climb solver, periodic crossings, motion and junction sharing\n";
228 return 0;
229 }
230 catch (const std::exception &error)
231 {
232 std::cerr << error.what() << '\n';
233 return 1;
234 }
235}
void moveNodes(const double &dt_in)
std::shared_ptr< DislocationClimbSolverBase< dim > > climbSolver
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)
A class template that implements a counter of the number of instances of Derived type that are create...
Definition StaticID.h:29
a
Definition int_R.m:14
b
Definition int_R.m:16
size_t InstanceCount< Derived >::count
void forEachPeriodicVelocityRelation(const Network &network, Callback callback)
LatticePlaneKey< dim > GlidePlaneKey
int regions
Definition triangle.cpp:696
SharedPtrType create(const Args &...args)
std::string text(Config &config)
void require(bool ok, const std::string &message)
std::string read(const fs::path &path)
fs::path fixture(const fs::path &root, int rank, int reactions, bool source, const std::string &name="unitCube24.msh")
void parameter(std::string &text, const std::string &key, const std::string &value)
void climb(const fs::path &root, int rank)
int j
void argv
int index
void b int argc
int i
newbad key
b poly