Mechanics of Defect Evolution Library
Loading...
Searching...
No Matches
DislocationNodeContraction.cpp
Go to the documentation of this file.
1/* This file is part of MoDELib, the Mechanics Of Defects Evolution Library.
2 *
3 *
4 * MoDELib is distributed without any warranty under the
5 * GNU General Public License (GPL) v2 <http://www.gnu.org/licenses/>.
6 */
7
8#ifndef model_DislocationNodeContraction_cpp_
9#define model_DislocationNodeContraction_cpp_
10
11#include <memory>
12#include <tuple>
13#include <Eigen/Dense>
14#include <TypeTraits.h>
15#include <GlidePlane.h>
16//#include <BoundingMeshSegments.h>
17#include <Grain.h>
18#include <FiniteLineSegment.h>
19#include <PlanesIntersection.h>
20#include <DislocationNetwork.h>
22#include <OneSidedMotion.h>
24
25#ifndef NDEBUG
26#define VerboseNodeContraction(N,x) if(verboseNodeContraction>=N){std::cout<<x;}
27#else
28#define VerboseNodeContraction(N,x)
29#endif
30
31namespace model
32{
33
34 template <int dim>
36 /* init */ DN(DN_in)
37 /* init */,verboseNodeContraction(TextFileParser(DN.ddBase.simulationParameters.traitsIO.inputFilesFolder+"/DD.txt").readScalar<int>("verboseNodeContraction",true))
38 {
39
40 }
41
42 template <int dim>
43 std::vector<std::set<std::shared_ptr<typename DislocationNodeContraction<dim>::NetworkNodeType>>> DislocationNodeContraction<dim>::contractBoundary(std::shared_ptr<NetworkNodeType> nA,
44 std::shared_ptr<NetworkNodeType> nB)
45 {
46 using NodeSet=std::set<std::shared_ptr<NetworkNodeType>>;
47 std::vector<NodeSet> groups;
48 const auto collect=[&](const auto& chainA,const auto& chainB)
49 {
50 for(const auto* a : chainA)
51 {
52 for(const auto* b : chainB)
53 {
54 // Only coincident subdivisions of the same periodic branch
55 // may be shared. Physical faces terminate these chains.
56 if(a->isPeriodicSubdivision() && b->isPeriodicSubdivision() &&
57 a->networkNode!=b->networkNode &&
58 a->networkNode->meshFaces()==b->networkNode->meshFaces() &&
59 (a->networkNode->get_P()-b->networkNode->get_P()).norm()<FLT_EPSILON)
60 {
61 NodeSet merged{a->networkNode,b->networkNode};
62 for(auto it=groups.begin();it!=groups.end();)
63 {
64 bool overlaps=false;
65 for(const auto& node : *it)
66 {
67 if(merged.count(node))
68 {
69 overlaps=true;
70 break;
71 }
72 }
73 if(overlaps)
74 {
75 merged.insert(it->begin(),it->end());
76 it=groups.erase(it);
77 }
78 else
79 {
80 ++it;
81 }
82 }
83 groups.push_back(std::move(merged));
84 }
85 }
86 }
87 };
88 for(const auto* a : nA->loopNodes())
89 {
90 if(a->periodicPlaneEdge.first)
91 {
92 continue;
93 }
94 for(const auto* b : nB->loopNodes())
95 {
96 if(b->periodicPlaneEdge.first)
97 {
98 continue;
99 }
100 const auto ap=a->periodicPrev();
101 const auto an=a->periodicNext();
102 const auto bp=b->periodicPrev();
103 const auto bn=b->periodicNext();
104 if(ap && bp && ap->networkNode==bp->networkNode)
105 {
106 collect(a->boundaryPrev(),b->boundaryPrev());
107 }
108 if(an && bn && an->networkNode==bn->networkNode)
109 {
110 collect(a->boundaryNext(),b->boundaryNext());
111 }
112 if(ap && bn && ap->networkNode==bn->networkNode)
113 {
114 collect(a->boundaryPrev(),b->boundaryNext());
115 }
116 if(an && bp && an->networkNode==bp->networkNode)
117 {
118 collect(a->boundaryNext(),b->boundaryPrev());
119 }
120 }
121 }
122 return groups;
123 }
124
125 template <int dim>
126 bool DislocationNodeContraction<dim>::canReach(const std::shared_ptr<NetworkNodeType>& node,const VectorDim& target) const
127 {
128 if(!target.allFinite() || !node->isMovableTo(target))
129 {
130 return false;
131 }
132 const VectorDim requested=target-node->get_P();
133 typename NetworkNodeType::VectorOfNormalsType normals;
134 for(const auto* plane : node->glidePlanes())
135 {
136 normals.push_back(plane->unitNormal);
137 }
138 for(int row=0;row<DN.nodalVelocityConstraints.rows();++row)
139 {
140 normals.push_back(DN.nodalVelocityConstraints.row(row));
141 }
142 const VectorDim actual=oneSidedMotion<dim>(requested,normals,node->physicalBoundaryNormals());
143 if((actual-requested).norm()>FLT_EPSILON)
144 {
145 return false;
146 }
147 for(const auto* ln : node->loopNodes())
148 {
149 if(ln->periodicPlaneEdge.first && requested.norm()>FLT_EPSILON)
150 {
151 return false;
152 }
153 // Keep each representation in its current convex host-grain patch.
154 // Contraction must not silently trim away one of its endpoints.
155 if(!DN.ddBase.mesh.searchRegion(ln->loop()->grain.grainID,target).first)
156 {
157 return false;
158 }
159 }
160 return true;
161 }
162
163 template <int dim>
164 bool DislocationNodeContraction<dim>::commitContraction(std::shared_ptr<NetworkNodeType> a,
165 std::shared_ptr<NetworkNodeType> b,const VectorDim& target,const bool reconcileBoundary)
166 {
167 if(!a || !b || a==b || a->loopNodes().empty() || b->loopNodes().empty() ||
168 !b->isContractableTo(a) || !canReach(a,target) || !canReach(b,target))
169 {
170 return false;
171 }
172 // All ordinary rejection paths are above this point. Commit the exact
173 // common point without running boundary reconciliation between moves.
175 using NodePtr=std::shared_ptr<LoopNodeType>;
176 struct Subdivision
177 {
178 NodePtr node,source,sink;
179 double parameter;
180 };
181 std::vector<Subdivision> subdivisions;
182 std::set<size_t> visitedLoops;
183 const double tolerance=1.e-8*(DN.ddBase.mesh.xMax()-DN.ddBase.mesh.xMin()).norm();
184 for(const auto& endpoint : {a,b})
185 {
186 for(const auto* occurrence : endpoint->loopNodes())
187 {
188 const auto loop=occurrence->loop();
189 if(!visitedLoops.insert(loop->sID).second)
190 {
191 continue;
192 }
193 std::vector<NodePtr> nodes;
194 for(const auto* link : loop->linkSequence())
195 {
196 nodes.push_back(link->source);
197 }
198 retainPeriodicContourBends(nodes,tolerance);
199 std::vector<size_t> anchors;
200 for(size_t i=0;i<nodes.size();++i)
201 {
202 if(!nodes[i]->isPeriodicSubdivision())
203 {
204 anchors.push_back(i);
205 }
206 }
207 for(size_t k=0;k<anchors.size();++k)
208 {
209 const size_t begin=anchors[k];
210 const size_t end=anchors[(k+1)%anchors.size()];
211 const VectorDim chord=nodes[end]->get_P()-nodes[begin]->get_P();
212 std::vector<Subdivision> edgeSubdivisions;
213 bool straight=true;
214 double previous=0;
215 const double length=chord.norm();
216 for(size_t i=(begin+1)%nodes.size();i!=end;i=(i+1)%nodes.size())
217 {
218 const VectorDim offset=nodes[i]->get_P()-nodes[begin]->get_P();
219 const double parameter=chord.squaredNorm()>0 ? offset.dot(chord)/chord.squaredNorm() : 0;
220 if((offset-parameter*chord).norm()>tolerance ||
221 (parameter-previous)*length < -tolerance || (parameter-1)*length>tolerance)
222 {
223 straight=false;
224 }
225 previous=parameter;
226 edgeSubdivisions.push_back({nodes[i],nodes[begin],nodes[end],parameter});
227 }
228 if(straight)
229 {
230 subdivisions.insert(subdivisions.end(),edgeSubdivisions.begin(),edgeSubdivisions.end());
231 }
232 else
233 {
234 // Local near-collinearity is not enough for a long
235 // chain: retain it if the complete path is not straight.
236 for(const auto& subdivision : edgeSubdivisions)
237 {
238 subdivision.node->periodicContourVertex=true;
239 }
240 }
241 }
242 }
243 }
244 for(const auto& node : {a,b})
245 {
246 for(auto* ln : node->loopNodes())
247 {
248 const VectorDim shift=ln->periodicPlanePatch() ? ln->periodicPlanePatch()->shift : VectorDim::Zero();
249 static_cast<typename LoopNodeType::SplineNodeType&>(*ln).set_P(target-shift);
250 }
251 node->set_P(target);
252 }
253 // Transport only proven straight-edge subdivisions using their old
254 // segment ancestry, before cutLoop changes the contour connectivity.
255 // These are trial loop coordinates; boundary reconciliation recreates
256 // the actual seam intersections and commits their network positions.
257 for(const auto& subdivision : subdivisions)
258 {
259 const VectorDim position=(1-subdivision.parameter)*subdivision.source->get_P()+
260 subdivision.parameter*subdivision.sink->get_P();
261 static_cast<typename LoopNodeType::SplineNodeType&>(*subdivision.node).set_P(position);
262 }
263 subdivisions.clear();
264 const auto groups=contractBoundary(a,b);
265 if(!DN.contractNetworkNodes(a,b))
266 {
267 throw std::logic_error("Validated node contraction unexpectedly rejected.");
268 }
269 for(const auto& group : groups)
270 {
271 const auto survivor=*std::min_element(group.begin(),group.end(),[](const auto& x,const auto& y)
272 {
273 return x->sID<y->sID;
274 });
275 for(const auto& node : group)
276 {
277 if(node!=survivor && !node->loopNodes().empty() && !survivor->loopNodes().empty())
278 {
279 DN.contractNetworkNodes(survivor,node);
280 }
281 }
282 }
283 if(reconcileBoundary)
284 {
285 DN.updateBoundaryNodes();
286 }
287 return true;
288 }
289
290 template <int dim>
291 bool DislocationNodeContraction<dim>::contractSecondAndVirtual(std::shared_ptr<NetworkNodeType> nA,
292 std::shared_ptr<NetworkNodeType> nB,const bool reconcileBoundary)
293 {
294 return commitContraction(nA,nB,nA->get_P(),reconcileBoundary);
295 }
296
297 template <int dim>
298 bool DislocationNodeContraction<dim>::contractYoungest(std::shared_ptr<NetworkNodeType> nA,
299 std::shared_ptr<NetworkNodeType> nB,const bool reconcileBoundary)
300 {
301 return nA->sID<nB->sID? contractSecondAndVirtual(nA,nB,reconcileBoundary) : contractSecondAndVirtual(nB,nA,reconcileBoundary);
302
303 }
304
305 template <int dim>
306 bool DislocationNodeContraction<dim>::contractToPosition(std::shared_ptr<NetworkNodeType> nA,
307 std::shared_ptr<NetworkNodeType> nB,
308 const VectorDim& X,
309 const double& maxRange,const bool reconcileBoundary)
310 {
311
312 if((nA->get_P()-X).norm()+(nB->get_P()-X).norm()>=maxRange)
313 {
314 return false;
315 }
316 return nA->sID<nB->sID ? commitContraction(nA,nB,X,reconcileBoundary) : commitContraction(nB,nA,X,reconcileBoundary);
317 }
318
319
320 template <int dim>
321 bool DislocationNodeContraction<dim>::contract(std::shared_ptr<NetworkNodeType> nA,
322 std::shared_ptr<NetworkNodeType> nB,const bool reconcileBoundary)
323 {
324 if(!nA || !nB || nA==nB || nA->loopNodes().empty() || nB->loopNodes().empty())
325 {
326 return false;
327 }
328 VerboseNodeContraction(1, "DislocationNodeContraction::contract " << nA->sID << " " << nB->sID << std::endl;);
329 if ( !nA->isBoundaryNode()
330 && !nA->isGrainBoundaryNode()
331 && !nB->isBoundaryNode()
332 && !nB->isGrainBoundaryNode()
333 ) //Added for avoiding node contraction with boundary node
334 {
335
336 const bool nAisMovable = canReach(nA,nB->get_P());
337 const bool nBisMovable = canReach(nB,nA->get_P());
338
339 if (nAisMovable && nBisMovable)
340 {
341 VerboseNodeContraction(1, "DislocationNodeContraction case 1a" << std::endl;);
342 return contractYoungest(nA, nB,reconcileBoundary);
343 }
344 else if (nAisMovable && !nBisMovable)
345 {
346 VerboseNodeContraction(1, "DislocationNodeContraction case 1b" << std::endl;);
347 return contractSecondAndVirtual(nB, nA,reconcileBoundary);
348 }
349 else if (!nAisMovable && nBisMovable)
350 {
351 VerboseNodeContraction(1, "DislocationNodeContraction case 1c" << std::endl;);
352 return contractSecondAndVirtual(nA, nB,reconcileBoundary);
353 }
354 else
355 {// nA and nB cannot be moved to each other. The calculation of a third point is necessary
356 VerboseNodeContraction(1, "DislocationNodeContraction case 1d" << std::endl;);
357 const auto planesA(nA->glidePlanes());
358 const auto planesB(nB->glidePlanes());
359 Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> N(Eigen::Matrix<double,dim,Eigen::Dynamic>::Zero(dim,planesA.size()+planesB.size()));
360 Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> P(Eigen::Matrix<double,dim,Eigen::Dynamic>::Zero(dim,planesA.size()+planesB.size()));
361
362 int k=0;
363 for(const auto& plane : planesA)
364 {
365 N.col(k)=plane->unitNormal;
366 P.col(k)=plane->P;
367 ++k;
368 }
369 for(const auto& plane : planesB)
370 {
371 N.col(k)=plane->unitNormal;
372 P.col(k)=plane->P;
373 ++k;
374 }
375
376 PlanesIntersection<dim> pInt(N,P,FLT_EPSILON);
377 const std::pair<bool,VectorDim> snapped(pInt.snap(0.5*(nA->get_P()+nB->get_P())));
378 if(snapped.first)
379 {
380 const double maxRange = 4.0 * (nA->get_P() - nB->get_P()).norm();
381 return contractToPosition(nA,nB,snapped.second,maxRange,reconcileBoundary);
382 }
383 else
384 {
385 return false;
386 }
387 }
388 }
389 else
390 {
391 if ((nA->get_P() - nB->get_P()).norm() <= FLT_EPSILON)
392 {
393 VerboseNodeContraction(1, "DislocationNodeContraction case 2a" << std::endl;);
394 return contractYoungest(nA, nB,reconcileBoundary);
395 }
396 else
397 {
398 VerboseNodeContraction(1, "DislocationNodeContraction case 2b" << std::endl;);
399 return false;
400 }
401 }
402 }
403
404template class DislocationNodeContraction<3>;
405}
406#endif
407
TraitsType::LoopNodeType LoopNodeType
DislocationNodeContraction(DislocationNetwork< dim > &DN_in)
bool contract(std::shared_ptr< NetworkNodeType > nA, std::shared_ptr< NetworkNodeType > nB, const bool reconcileBoundary=true)
a
Definition int_R.m:14
b
Definition int_R.m:16
x
Definition int_R.m:12
void retainPeriodicContourBends(const Nodes &nodes, const double tolerance)
Eigen::Matrix< double, dim, 1 > oneSidedMotion(const Eigen::Matrix< double, dim, 1 > &requested, const std::vector< Eigen::Matrix< double, dim, 1 > > &equalities, const std::vector< Eigen::Matrix< double, dim, 1 > > &outward)
std::pair< bool, VectorDim > snap(const VectorDim &x) const
void parameter(std::string &text, const std::string &key, const std::string &value)
int end[2]
int k
int i