33fs::path
fixture(
const fs::path &root,
int rank,
int reactions,
bool source,
const std::string &name =
"unitCube24.msh")
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");
47 const int species[4] = {-1, 1, 2, 3};
48 for (
int i = 0;
i < 4; ++
i)
50 for (
int j =
i;
j < 4; ++
j)
52 map += std::to_string(species[
i]) +
" " + std::to_string(species[
j]) +
" " +
53 ((reactions == 2 &&
i == 0 &&
j == 1) ?
"1\n" :
"0\n");
56 parameter(material,
"reactionPrefactorMap", map);
59 parameter(material,
"mobileSpeciesCascadeFractions",
"1 1 0 0");
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();
71 for (
const auto &entry : region.second->faces())
73 if (entry.second->periodicFacePair.second)
75 for (
int d = 0; d < rank; ++d)
77 if (entry.second->periodicFacePair.first.normalized().cross(F.col(d).normalized()).norm() <
80 seeds.insert(entry.first);
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)
93 poly << F.row(
i) <<
"\n";
95 poly <<
";\nX0=0 0 0;\nperiodicFaceIDs=";
96 for (
int seed : seeds)
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)
104 poly <<
"C2G" << g <<
"=1 0 0 0 1 0 0 0 1;\n";
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)
113 dc <<
";\nEwaldLengthFactor=0;\n";
117void climb(
const fs::path &root,
int rank)
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");
126 const auto grain = base.poly.grain(1);
127 const Eigen::Vector3d center = Eigen::Vector3d::Zero();
128 const Eigen::Vector3d normal = Eigen::Vector3d::UnitZ();
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}};
139 "Failed to insert climb loop");
141 auto cd = std::make_shared<ClusterDynamics<3>>(container);
142 container.push_back(cd);
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())
150 const auto &node = link->source;
151 nodes.push_back(network.
loopNodes().
create(duplicate, node->networkNode, node->get_P(),
152 node->periodicPlanePatch(), node->periodicPlaneEdge));
156 size_t quadrature = 0;
159 const auto link = entry.second.lock();
160 link->createQuadraturePoints(
true);
161 for (
auto &qp : link->quadraturePoints())
169 require(quadrature > 0,
"Climb regression has no active quadrature points");
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;
177 [&](
size_t n,
size_t a,
size_t b,
double wa,
double wb)
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");
184 require(rank == 0 || relations > 0,
"Periodic climb test has no crossings");
185 size_t tangentialMarkers = 0;
186 size_t localIndex = 0;
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())
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");
209 entry.second.lock()->set_V(velocity.segment<3>(3 *
index++),
true);
211 network.
moveNodes(1.e-4 / velocity.norm());
214 require(entry.second.lock()->loopLinks().size() == 2,
"Climb motion broke shared junction ownership");
216 fs::remove_all(folder);