Mechanics of Defect Evolution Library
Loading...
Searching...
No Matches
testPeriodicVelocityConstraints.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 <map>
12#include <iterator>
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 ("bicrystal-shared-constraints-" + 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 const double length=3671.9477120460206;
39 {
40 std::ofstream f(input / "DefectiveCrystal.txt");
41 f << "physics=DislocationDynamics;\nuseFEM=0;\nNsteps=0;\nmaxResolveSteps=0;\ndtMax=1;\noutputFrequency=1;\noutputBinary=0;\nstartAtTimeStep=0;\nperiodicImageSize=0 0 0;\nEwaldLengthFactor=0;\n";
42 std::ofstream p(input / "polycrystal.txt");
43 p << std::setprecision(17) << "materialFile=W.txt;\nmeshFile=mesh.msh;\nabsoluteTemperature=300;\nC2G1=1 0 0 0 1 0 0 0 1;\n"
44 << "C2G2=0.8 0 0.6 0 1 0 -0.6 0 0.8;\nF=" << length << " 0 0 0 " << length << " 0 0 0 " << length
45 << ";\nX0=0 0 0;\nperiodicFaceIDs=-1;\n";
46 }
47 model::DefectiveCrystalBase<3> base(folder.string());
49 model::DislocationNetwork<3> network(container);
50 model::DefectiveCrystalConfigIO<3> saved(folder.string());
51 std::ifstream stream(root/"tests/data/bicrystalSharedConstraints1915.txt");
52 require(bool(stream),"Missing bicrystal junction regression fixture");
53 saved.readTxtStream(stream);
54 network.initializeConfiguration(saved,std::ofstream(),std::ofstream());
55 using Triplets=std::vector<Eigen::Triplet<double>>;
56 Triplets triplets;
57 const size_t freeCount=model::periodicVelocityConstraints<3>(network,triplets);
58 Eigen::SparseMatrix<double> sparse(3*network.networkNodes().size(),3*freeCount);
59 sparse.setFromTriplets(triplets.begin(),triplets.end());
60 const Eigen::MatrixXd Z(sparse);
61 require((Z*Eigen::VectorXd::Ones(Z.cols())-Eigen::VectorXd::Ones(Z.rows())).norm()<1.e-8,
62 "Periodic constraints lost uniform translation or doubled a velocity");
63 size_t shared=0;
64 for(const auto& entry : network.networkNodes())
65 {
66 const auto node=entry.second.lock();
67 if(node->sID>=975875 && node->sID<=975878)
68 {
69 ++shared;
70 require(node->loopNodes().size()==2,"Missing shared crossing memberships");
71 for(const auto* ln : node->loopNodes())
72 {
73 require(ln->isPeriodicSubdivision(),"Fixture no longer exercises periodic interpolation");
74 const auto a=ln->periodicPrev();
75 const auto b=ln->periodicNext();
76 const double da=(ln->get_P()-a->get_P()).norm();
77 const double db=(ln->get_P()-b->get_P()).norm();
78 const auto residual=(Z.middleRows(3*node->networkID(),3)
79 -db/(da+db)*Z.middleRows(3*a->networkNode->networkID(),3)
80 -da/(da+db)*Z.middleRows(3*b->networkNode->networkID(),3)).eval();
81 require(residual.norm()<1.e-8,"Shared crossing does not satisfy both loop interpolants");
82 }
83 }
84 }
85 require(shared==4,"Missing frame 1915 shared crossings");
86 // Independent endpoints 1 and 2 must become compatible through a
87 // shared crossing. Repeated/reversed relations must not add rank.
88 for(bool reverse : {false,true})
89 {
91 for(size_t endpoint : {reverse ? 2UL : 1UL,reverse ? 1UL : 2UL})
92 {
93 constraints.interpolate(3,0,endpoint,0.4,0.6);
94 constraints.interpolate(4,endpoint,0,0.2,0.8);
95 constraints.interpolate(3,endpoint,0,0.6,0.4);
96 }
97 Triplets t;
98 const auto count=constraints.append<1>(t);
99 require(count==2,"Duplicate periodic relations changed the number of free velocities");
100 Eigen::SparseMatrix<double> transform(5,count);
101 transform.setFromTriplets(t.begin(),t.end());
102 const Eigen::MatrixXd M(transform);
103 require((M.row(1)-M.row(2)).norm()<1.e-12,"Competing endpoint velocities are incompatible");
104 require((M.row(3)-0.4*M.row(0)-0.6*M.row(1)).norm()<1.e-12,"Incorrect crossing interpolation");
105 require((M.row(4)-0.8*M.row(0)-0.2*M.row(2)).norm()<1.e-12,"Incorrect second crossing interpolation");
106 require((M*Eigen::Vector2d::Ones()-Eigen::VectorXd::Ones(5)).norm()<1.e-12,"Constant velocity changed");
107 }
108 {
109 // v0=s0 ex, v1=s1 ey, v2=s2 (ex+ey)/sqrt(2),
110 // with v2=(v0+v1)/2. Scalar interpolation alone is incorrect here.
112 directions.constrain({{2,1/std::sqrt(2.0)},{0,-0.5}});
113 directions.constrain({{2,1/std::sqrt(2.0)},{1,-0.5}});
114 Triplets entries;
115 const auto count=directions.append<1>(entries);
116 model::VelocityMatrix map(3,count);
117 map.setFromTriplets(entries.begin(),entries.end());
118 const Eigen::Vector3d diagonal(1,2,3), force(1,2,4), mode(1,1,1/std::sqrt(2.0));
119 const Eigen::Vector3d expected=mode*(mode.dot(force)/mode.dot(diagonal.cwiseProduct(mode)));
120 const auto actual=model::solveConstrainedVelocityDiagonal(diagonal,force,map);
121 require((actual-expected).norm()<1.e-12,"Direction-aware climb differs from independent reduced balance");
122 require(model::solveConstrainedVelocityDiagonal(diagonal,Eigen::Vector3d::Zero(),map).isZero(0.0),
123 "Undriven constrained climb is not stationary");
124 }
125 {
127 constraints.interpolate(1,0,2,0.5,0.5);
128 Triplets entries;
129 const auto count=constraints.append<1>(entries);
130 model::VelocityMatrix map(3,count);
131 map.setFromTriplets(entries.begin(),entries.end());
132 const auto actual=model::solveConstrainedVelocityDiagonal(Eigen::Vector3d(1,0,1),Eigen::Vector3d(0,1,0),map);
133 require((actual-Eigen::Vector3d::Constant(0.5)).norm()<1.e-12,
134 "Force on a dependent zero-mass crossing was lost during reduction");
135 }
136 std::filesystem::remove_all(folder);
137 std::cout<<"PASS: frame 1915 shared periodic constraints, compatibility and uniform translation\n";
138 return 0;
139 }
140 catch(const std::exception& error)
141 {
142 std::cerr<<error.what()<<'\n';
143 return 1;
144 }
145}
Eigen::Matrix3d M
void initializeConfiguration(const DefectiveCrystalConfigIO< dim > &configIO, const std::ofstream &f_file, const std::ofstream &F_labels) override
const NetworkNodeContainerType & networkNodes() const
size_t append(Triplets &triplets) const
void interpolate(size_t node, size_t a, size_t b, double wa, double wb)
void constrain(Row row, bool preserveTranslation=false, size_t preferredNode=std::numeric_limits< size_t >::max())
final point of the source segment t
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
Eigen::VectorXd solveConstrainedVelocityDiagonal(const Eigen::VectorXd &diagonal, const Eigen::VectorXd &force, const VelocityMatrix &Z)
Eigen::SparseMatrix< double > VelocityMatrix
size_t periodicVelocityConstraints(const Network &network, Triplets &triplets)
std::deque< Eigen::Triplet< double > > Triplets
void require(bool condition, const char *message)
void argv
void b int argc
vertex p[3]