Mechanics of Defect Evolution Library
Loading...
Searching...
No Matches
testThermalCrossSlipBranches.cpp
Go to the documentation of this file.
7#include <filesystem>
8#include <fstream>
9#include <iomanip>
10#include <chrono>
11#include <iostream>
12
13namespace model
14{
16 {
17 template<class N> static void queue(N& network,const std::deque<CrossSlipBranch<TypeTraits<N>::dim>>& branches)
18 {
19 network.crossSlipMaker.csNodes=branches;
20 }
21 };
22}
23
24void require(bool value,const char* message)
25{
26 if(!value)
27 {
28 throw std::runtime_error(message);
29 }
30}
31
32int main(int argc,char** argv)
33{
34 try
35 {
36 require(argc==2,"Expected repository root");
37 const std::filesystem::path root(argv[1]);
38 const auto folder=std::filesystem::temp_directory_path()/
39 ("thermal-branches-"+std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()));
40 const auto input=folder/"inputFiles";
41 std::filesystem::create_directories(input);
42 std::filesystem::create_directories(folder/"F");
43 std::filesystem::create_directories(folder/"config");
44 std::filesystem::copy_file(root/"Library/Materials/Zr.txt",input/"Zr.txt");
45 std::filesystem::copy_file(root/"Library/Meshes/bicrystal_48.msh",input/"mesh.msh");
46 {
47 std::ofstream material(input/"Zr.txt",std::ios::app);
48 // Zero barriers and volumes give a known, spatially uniform rate.
49 material<<"\ncsw_SI=1e15;\ncsLb_SI=9.699e-8;\ncsLp_SI=9.699e-8;\ncsb2pE_eV=0;\ncsb2pVeg_SI=0;\ncsb2pVsc_SI=0;\ncsb2pVec_SI=0;\ncsp2bE_eV=0;\ncsp2bVeg_SI=0;\ncsp2bVsc_SI=0;\ncsp2bVec_SI=0;\n";
50 std::ifstream dd(root/"Library/DislocationDynamics/DD.txt");
51 std::string text((std::istreambuf_iterator<char>(dd)),std::istreambuf_iterator<char>());
52 const auto pos=text.find("crossSlipModel=0;");
53 require(pos!=std::string::npos,"Missing cross-slip setting");
54 text.replace(pos,17,"crossSlipModel=2;");
55 std::ofstream(input/"DD.txt")<<text;
56 std::ofstream(input/"DefectiveCrystal.txt")<<"physics=DislocationDynamics;\nuseFEM=0;\nNsteps=0;\nmaxResolveSteps=0;\ndtMax=1;\noutputFrequency=1;\noutputBinary=0;\nstartAtTimeStep=0;\nperiodicImageSize=;\nEwaldLengthFactor=0;\n";
57 }
58 const double box=3671.9477120460206;
59 std::vector<double> referenceLocations;
60 for(const int refinement : {1,2,12,200})
61 {
62 {
63 std::ofstream p(input/"polycrystal.txt");
64 p<<std::setprecision(17)<<"materialFile=Zr.txt;\nmeshFile=mesh.msh;\nabsoluteTemperature=300;\nC2G1="<<(refinement==200? "0 -1 0 1 0 0 0 0 1" : "1 0 0 0 1 0 0 0 1")<<";\nC2G2=1 0 0 0 1 0 0 0 1;\nF="<<box<<" 0 0 0 "<<box<<" 0 0 0 "<<box<<";\nX0=0 0 0;\nperiodicFaceIDs=;\n";
65 }
67 using V=Eigen::Vector3d;
68 model::DefectiveCrystalBase<3> base(folder.string());
70 Network network(container);
71 const auto grain=base.poly.grain(1);
72 const auto slip=grain->slipSystems().begin()->second;
73 const auto plane=base.dislocationDynamics().glidePlaneFactory.getFromKey(model::GlidePlaneKey<3>(V(-0.5*box,0,0),slip->n));
74 const V center=plane->snapToPlane(V(-0.5*box,0,0));
75 const V along=slip->s.cartesian().normalized();
76 const V side=plane->unitNormal.cross(along);
77 const V a=center-0.15*box*along,end=center+0.15*box*along;
78 std::vector<V> polygon;
79 for(int k=0;k<=refinement;++k)
80 {
81 polygon.push_back(a+(end-a)*(double(k)/refinement));
82 }
83 polygon.push_back(end+100.0*side);
84 polygon.push_back(a+100.0*side);
85 model::MicrostructureGenerator generator(base);
86 require(generator.insertJunctionLoop(polygon,base.dislocationDynamics().periodicGlidePlaneFactory.get(plane->key),slip->s.cartesian(),plane->unitNormal,plane->P,1,model::DislocationLoopIO<3>::GLISSILELOOP),"Parent insertion failed");
87 network.initializeConfiguration(generator.config(),std::ofstream(),std::ofstream());
88 const auto parent=network.loops().begin()->second.lock();
89 base.simulationParameters.dt=1.0;
90 auto* thermal=dynamic_cast<model::EscaigCrossSlipModelHEX<model::TypeTraits<Network>::dim>*>(network.crossSlipModel.get());
91 require(thermal,"Missing production HEX thermal model");
92 double totalRate=0.0,totalLength=0.0;
93 for(const auto* link : parent->linkSequence())
94 {
95 if(link->networkLink())
96 {
97 link->networkLink()->createQuadraturePoints(false);
98 for(auto& q : link->networkLink()->quadraturePoints())
99 {
100 q.stress.setZero();
101 }
102 if(thermal->isCrossSlipLink(*link->networkLink()).first)
103 {
104 totalLength+=link->networkLink()->chordLength();
105 for(const auto& [target,rate] : thermal->targetRates(*link->networkLink()))
106 {
107 totalRate+=rate;
108 }
109 }
110 }
111 }
112 require(std::abs(totalLength-0.6*box)<1.e-6,"Thermal eligibility depends on remeshing length");
113 require(totalRate>0.0 && std::abs(totalRate-thermal->csw*totalLength/thermal->csLb)<1.e-8*totalRate,"Integrated branch hazard depends on segmentation");
114 std::deque<model::CrossSlipBranch<model::TypeTraits<Network>::dim>> candidates;
115 parent->crossSlipBranches(candidates,0.0);
116 require(candidates.empty(),"Thermal sampler ignored the supplied timestep");
117 thermal->gen.seed(77);
118 parent->crossSlipBranches(candidates,1.0);
119 require(candidates.size()==2,"Branch discovery depends on segmentation");
120 std::vector<double> locations;
121 for(const auto& candidate : candidates)
122 {
123 require(candidate.thermal && std::abs(candidate.thermal->length-300.0)<1.e-9,"Wrong physical nucleus length");
124 const auto target=grain->slipSystems().at(candidate.second);
125 require(target->n.base()(2)==0,"Wrong thermal target plane family");
126 locations.push_back(candidate.thermal->centerFraction);
127 }
128 std::sort(locations.begin(),locations.end());
129 if(referenceLocations.empty())
130 {
131 referenceLocations=locations;
132 }
133 else
134 {
135 for(size_t k=0;k<locations.size();++k)
136 {
137 require(std::abs(locations[k]-referenceLocations[k])<1.e-9,"Nucleation position depends on segmentation");
138 }
139 }
140 if(refinement==2)
141 {
142 // A point junction divides the screw branch even though its
143 // adjacent segments each still belong to only one loop.
144 std::shared_ptr<Network::LoopNodeType> junction;
145 for(const auto* link : parent->linkSequence())
146 {
147 if((link->source->get_P()-center).norm()<1.e-6)
148 {
149 junction=link->source;
150 }
151 }
152 require(bool(junction),"Missing junction anchor");
153 const auto other=network.loops().create(slip->s.cartesian(),plane);
154 std::vector<std::shared_ptr<Network::LoopNodeType>> nodes;
155 for(const auto& net : std::vector{junction->networkNode,
156 network.networkNodes().create(V(center+30.0*side)),
157 network.networkNodes().create(V(center+30.0*side+30.0*along))})
158 {
159 nodes.push_back(network.loopNodes().create(other,net,net->get_P(),
160 other->periodicGlidePlane->getPatch(V::Zero()),std::make_pair(nullptr,nullptr)));
161 }
162 network.insertLoop(other,nodes);
163 network.updateGeometry();
164 candidates.clear();
165 parent->crossSlipBranches(candidates,1.0);
166 require(candidates.size()==3,"Thermal branch did not stop at a shared junction");
167 for(const auto& candidate : candidates)
168 {
169 for(size_t k=1;k+1<candidate.first.size();++k)
170 {
171 require(candidate.first[k]->networkNode!=junction->networkNode,"Junction remained inside thermal branch");
172 }
173 }
174 continue;
175 }
176 model::CrossSlipTestAccess::queue(network,candidates);
177 candidates.clear();
178 network.crossSlipMaker.execute();
179 require(network.loops().size()==3,"Production thermal seeds were not inserted");
180 for(const auto& entry : network.loops())
181 {
182 const auto loop=entry.second.lock();
183 if(loop!=parent)
184 {
185 double perimeter=0.0;
186 for(const auto* link : loop->linkSequence())
187 {
188 perimeter+=(link->sink->get_P()-link->source->get_P()).norm();
189 }
190 require(std::abs(perimeter-600.0)<1.e-6,"Production seed length depends on segmentation");
191 }
192 }
193 }
194 std::filesystem::remove_all(folder);
195 std::cout<<"PASS: production HEX branch discovery, rates and nucleus geometry invariant under refinement\n";
196 }
197 catch(const std::exception& error)
198 {
199 std::cerr<<error.what()<<'\n';
200 return 1;
201 }
202}
Eigen::Vector3d V
DislocationCrossSlip< dim > crossSlipMaker
void initializeConfiguration(const DefectiveCrystalConfigIO< dim > &configIO, const std::ofstream &f_file, const std::ofstream &F_labels) override
const std::shared_ptr< BaseCrossSlipModel< dim > > crossSlipModel
const LoopContainerType & loops() const
Definition LoopNetwork.h:98
const NetworkNodeContainerType & networkNodes() const
const LoopNodeContainerType & loopNodes() const
void insertLoop(const std::shared_ptr< LoopType > &loop, const std::vector< std::shared_ptr< LoopNodeType > > nodes)
the magnitude of the R vector q
a
Definition int_R.m:14
LatticePlaneKey< dim > GlidePlaneKey
static void queue(N &network, const std::deque< std::shared_ptr< typename N::LoopNodeType > > &nodes, int slip)
static void queue(N &network, const std::deque< CrossSlipBranch< TypeTraits< N >::dim > > &branches)
SharedPtrType create(const Args &...args)
model::DislocationNetwork< 3 > Network
std::string text(Config &config)
void require(bool value, const char *message)
int end[2]
int parent
void argv
void b int argc
vertex p[3]
int k