Mechanics of Defect Evolution Library
Loading...
Searching...
No Matches
DislocationNetworkRemesh.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_DislocationNetworkRemesh_cpp_
9#define model_DislocationNetworkRemesh_cpp_
10
12
13#include <DislocationNetwork.h>
14
15namespace model
16{
17 /**************************************************************************/
18 template <int dim>
20 /* init */ DN(DN_in)
21 /* init */,Lmax(TextFileParser(DN.ddBase.simulationParameters.traitsIO.inputFilesFolder+"/DD.txt").readScalar<double>("Lmax",true))
22 /* init */,Lmin(TextFileParser(DN.ddBase.simulationParameters.traitsIO.inputFilesFolder+"/DD.txt").readScalar<double>("Lmin",true))
23 /* init */,absoluteAreaThreshold(TextFileParser(DN.ddBase.simulationParameters.traitsIO.inputFilesFolder+"/DD.txt").readScalar<double>("absoluteAreaThreshold",true))
24 /* init */,relativeAreaThreshold(TextFileParser(DN.ddBase.simulationParameters.traitsIO.inputFilesFolder+"/DD.txt").readScalar<double>("relativeAreaThreshold",true))
25 /* init */,remeshFrequency(TextFileParser(DN.ddBase.simulationParameters.traitsIO.inputFilesFolder+"/DD.txt").readScalar<int>("remeshFrequency",true))
26 {
27
28 assert(Lmin<=Lmax);
29 assert(Lmax>3.0*Lmin);
30 assert(Lmin>=0.0);
31 assert(relativeAreaThreshold>=0.0);
32 }
33
34 /**************************************************************************/
35 template <int dim>
36 void DislocationNetworkRemesh<dim>::remesh(const long int &runID)
37 {
41 {
42 if (!(runID % remeshFrequency))
43 {
45 // remeshByContraction();
50// contractBoundaryNodes(); //Added by Yash
51 }
52 }
53 }
54
55template <int dim>
57{
58 std::cout << " Remeshing network: removeCollapsedLoops... " << std::flush;
59// std::cout<<"Removing collapsed via climb... " << std::flush;
60 const auto t0 = std::chrono::system_clock::now();
61 std::deque<size_t> loopIDs;
62 for(const auto& loop : DN.loops())
63 {
64 const auto current=loop.second.lock();
65 const VectorDim area=current->currentAreaVector();
66 const double magnitude=area.norm();
67 // rightHandedUnitNormal still holds the last committed timestep.
68 // Do not call updateGeometry here: it would overwrite that history.
69 const bool flipped=magnitude>FLT_EPSILON &&
70 current->rightHandedUnitNormal().dot(area/magnitude)<-FLT_EPSILON;
71 if(current->isIsolated() && (flipped || magnitude<absoluteAreaThreshold))
72 {
73 loopIDs.push_back(loop.second.lock()->sID);
74 }
75 }
76 for(const auto& loopID : loopIDs)
77 {
78 DN.deleteLoop(loopID);
79 }
80 std::cout<<"("<<loopIDs.size()<<" removed)"<<std::endl;
81 std::cout<<magentaColor<<" ["<<(std::chrono::duration<double>(std::chrono::system_clock::now()-t0)).count()<<" sec]"<<defaultColor<<std::endl;
82 }
83
84 template <int dim>
86 {
88 size_t removed=0;
89 bool changed=true;
90 while(changed)
91 {
92 changed=false;
93 std::vector<size_t> candidates;
94 for(const auto& entry : DN.networkNodes())
95 {
96 candidates.push_back(entry.first);
97 }
98 for(const size_t id : candidates)
99 {
100 const auto node=DN.networkNodes().get(id);
101 if(!node || node->neighbors().size()!=2 || node->loopNodes().empty())
102 {
103 continue;
104 }
105 std::vector<std::shared_ptr<LoopNode>> representations;
106 std::set<size_t> loops;
107 std::pair<size_t,size_t> endpoints;
108 bool removable=true;
109 for(const auto* ln : node->loopNodes())
110 {
111 const auto* prev=ln->prev.first;
112 const auto* next=ln->next.first;
113 const auto& edge=ln->periodicPlaneEdge.first;
114 // Keep corners, seam crossings, and changes in loop incidence.
115 // Every representation must traverse the same physical edge in
116 // one patch and connect the same two network neighbors.
117 if(!prev || !next || !edge || ln->periodicPlaneEdge.second ||
118 !ln->isPhysicalBoundaryNode() || edge->meshIntersection->faces.size()!=1 ||
119 ln->periodicPlanePatch()!=prev->periodicPlanePatch() ||
120 ln->periodicPlanePatch()!=next->periodicPlanePatch() ||
121 (prev->periodicPlaneEdge.first!=edge && prev->periodicPlaneEdge.second!=edge) ||
122 (next->periodicPlaneEdge.first!=edge && next->periodicPlaneEdge.second!=edge) ||
123 ln->loop()->loopLinks().size()<=3 || !loops.insert(ln->loop()->sID).second)
124 {
125 removable=false;
126 break;
127 }
128 const auto pair=std::minmax(prev->networkNode->sID,next->networkNode->sID);
129 const std::pair<size_t,size_t> current(pair.first,pair.second);
130 if(current.first==current.second || current.first==id || current.second==id ||
131 (!representations.empty() && endpoints!=current))
132 {
133 removable=false;
134 break;
135 }
136 const VectorDim chord=next->get_P()-prev->get_P();
137 const double length2=chord.squaredNorm();
138 if(length2<=0.0)
139 {
140 removable=false;
141 break;
142 }
143 const VectorDim offset=ln->get_P()-prev->get_P();
144 const double t=offset.dot(chord)/length2;
145 const double tolerance=1.e-10*std::max(1.0,std::sqrt(length2));
146 if(t<=0.0 || t>=1.0 || (offset-t*chord).norm()>tolerance)
147 {
148 removable=false;
149 break;
150 }
151 endpoints=current;
152 representations.push_back(DN.loopNodes().get(ln->sID));
153 }
154 // Do not merge this chain into an existing, unrelated network edge.
155 if(!removable || DN.networkLinks().get(endpoints))
156 {
157 continue;
158 }
159 // Hold all representations alive until every loop has been reconnected.
160 // The network link factory shares the replacement segment between them.
161 for(const auto& ln : representations)
162 {
163 DN.removeLoopNode(ln);
164 }
165 ++removed;
166 changed=true;
167 }
168 }
169 return removed;
170 }
171
172 /**************************************************************************/
173 template <int dim>
175 {
176 const auto t0 = std::chrono::system_clock::now();
177 std::cout << " Remeshing network: removing... " << std::flush;
179 DN.danglingBoundaryLoopNodes.clear();
180
181 std::vector<std::shared_ptr<typename DislocationNetwork<dim>::LoopNodeType>> tempLoopNodes;
182 for (const auto &loopNode : DN.loopNodes())
183 {
184 tempLoopNodes.push_back(loopNode.second.lock());
185 }
186
187 std::set<std::tuple<size_t,size_t,size_t>> bndLoopNodes; //First is the ID of the loop node, second is the periodicPrev and third is the periodic Next
188 //Definition of bndLoopNode as a set of tuple is very important as remesh may remove the loop nodes hence changing the connectivity of the loopnodes at the boundary
189 //IF that happens the corresponding boundary node should be classified as a dangling loop node
190 //Also believe that this is only required here as nothing else can change the configuration of the loops near the boundary
191 size_t Nremoved = 0;
192 std::set<const typename DislocationNetwork<dim>::LoopNodeType*> removedLoopNodes;
193
194 // std::deque<size_t> toBeRemoved;
195 for (const auto &loopNode : DN.loopNodes())
196 {
197 // std::cout<<"node "<<node.second->sID<<" "<<node.second->isSimpleBoundaryNode()<<" "<<node.second->isSimpleGrainBoundaryNode()<<std::endl;
198// if (!loopNode.second.lock()->networkNode->masterNode && removedLoopNodes.find(loopNode.second.lock().get())==removedLoopNodes.end())
199 if (removedLoopNodes.find(loopNode.second.lock().get())==removedLoopNodes.end())
200 {
201
202 const auto isRemovableLoopNode(loopNode.second.lock()->isRemovable(Lmin, Lmax, relativeAreaThreshold));
203 // std::cout<<" Trying to remove "<<loopNode.second.lock()->tag()<<" => "<<isRemovableLoopNode.first<<std::endl;
204 if (isRemovableLoopNode.first)
205 {
206 //Do this for all the loopNode of the networkNode
207 if (isRemovableLoopNode.second==loopNode.second.lock()->sID)
208 {
209 //Only the current node is needed to be removed
210 if (!loopNode.second.lock()->periodicPlaneEdge.first) //No need to update the boundary nodes for the nodes at the boundary
211 {
212 for (const auto &bndNode : loopNode.second.lock()->boundaryPrev())
213 {
214 // std::cout << " For " << loopNode.second.lock()->tag() << " bndPrev is " << bndNode->tag() << std::endl;
215 bndLoopNodes.emplace(bndNode->sID,bndNode->periodicPrev()->sID,bndNode->periodicNext()->sID);
216 }
217 for (const auto &bndNode : loopNode.second.lock()->boundaryNext())
218 {
219 // std::cout << " For " << loopNode.second.lock()->tag() << " bndNext is " << bndNode->tag() << std::endl;
220 bndLoopNodes.emplace(bndNode->sID,bndNode->periodicPrev()->sID,bndNode->periodicNext()->sID);
221 }
222 }
223
224 // std::cout<<" Starting to remove the loop Node "<<std::endl;
225// std::cout<<"Removing "<<loopNode.second.lock()->tag()<<std::endl;
226 DN.removeLoopNode(loopNode.second.lock()->sID);
227 // std::cout<<" Removed "<<loopNode.second.lock()->tag()<<std::endl;
228
229 removedLoopNodes.insert(loopNode.second.lock().get());
230 Nremoved++;
231 }
232 else
233 {
234 //Both the current and the twinned loopNode are needed to be removed
235
236 //Collect corresponding to the twinned loopNode and current loopNode
237 for (const auto& loopN : loopNode.second.lock()->networkNode->loopNodes())
238 {
239 if (loopN->sID==loopNode.second.lock()->sID || loopN->sID==isRemovableLoopNode.second)
240 {
241 if (!loopN->periodicPlaneEdge.first)
242 {
243 for (const auto &bndNode : loopN->boundaryPrev())
244 {
245 bndLoopNodes.emplace(bndNode->sID,bndNode->periodicPrev()->sID,bndNode->periodicNext()->sID);
246
247 }
248 for (const auto &bndNode : loopN->boundaryNext())
249 {
250 bndLoopNodes.emplace(bndNode->sID,bndNode->periodicPrev()->sID,bndNode->periodicNext()->sID);
251 }
252 }
253// std::cout<<"Removing LoopNode"<<loopN->tag()<<std::endl;
254 DN.removeLoopNode(loopN->sID);
255 removedLoopNodes.insert(loopN);
256 Nremoved++;
257 }
258 }
259 }
260 }
261 }
262 }
263
264 tempLoopNodes.clear(); //Very important to clear the loop node here
265 std::cout << " (" << Nremoved << " LoopNodes removed) " << std::flush;
266 Nremoved=0;
267 for (const auto &nodeID : bndLoopNodes)
268 {
269 auto nodeIter(DN.loopNodes().find(std::get<0>(nodeID)));
270 if (nodeIter != DN.loopNodes().end())
271 {
272 auto bndNode(nodeIter->second.lock());
273
274 const auto pPrev(bndNode->periodicPrev());
275 const auto pNext(bndNode->periodicNext());
276 if (pPrev && pNext)
277 {
278 if (pPrev->sID == std::get<1>(nodeID) && pNext->sID== std::get<2>(nodeID))
279 {
280 //If the periodic Prev and periodic next are the same as the remesh may change this
281 const auto pPrevLocal(bndNode->loop()->periodicGlidePlane->referencePlane->localPosition(pPrev->get_P()));
282 const auto pNextLocal(bndNode->loop()->periodicGlidePlane->referencePlane->localPosition(pNext->get_P()));
283 //
284
285 SegmentSegmentDistance<dim - 1> ssd1(pPrevLocal, pNextLocal, *bndNode->periodicPlaneEdge.first->source, *bndNode->periodicPlaneEdge.first->sink);
286 if (ssd1.dMin < FLT_EPSILON)
287 {
288 // VerboseDislocationLoopNode(3,"dMin= "<<ssd.dMin<<std::endl;);
289 if (bndNode->periodicPlaneEdge.second)
290 {
291 SegmentSegmentDistance<dim - 1> ssd2(pPrevLocal, pNextLocal, *bndNode->periodicPlaneEdge.second->source, *bndNode->periodicPlaneEdge.second->sink);
292 const VectorLowerDim ssd1Pos(0.5 * (ssd1.x0 + ssd1.x1));
293 const VectorLowerDim ssd2Pos(0.5 * (ssd2.x0 + ssd2.x1));
294 assert((ssd1Pos - ssd2Pos).norm() < FLT_EPSILON && "The two positions must match ");
295 }
296 bndNode->set_P(VectorLowerDim(0.5 * (ssd1.x0 + ssd1.x1)));
297 }
298 else
299 {
300 bndNode->set_P(bndNode->loop()->periodicGlidePlane->referencePlane->localPosition(bndNode->get_P()));
301 DN.danglingBoundaryLoopNodes.insert(bndNode.get());
302 }
303 }
304 else
305 {
306 bndNode->set_P(bndNode->loop()->periodicGlidePlane->referencePlane->localPosition(bndNode->get_P()));
307 DN.danglingBoundaryLoopNodes.insert(bndNode.get());
308 }
309
310
311 }
312 else
313 {
314 //Sole boundary node as the survivor..Remove them
315 DN.removeLoopNode(bndNode->sID);
316 Nremoved++;
317 }
318
319
320 }
321 }
322
323 std::cout << " (" << Nremoved << " bndLoopNodes removed). Updating boundary nodes " << std::flush;
324
325 if (DN.danglingBoundaryLoopNodes.size())
326 {
327 DN.updateBoundaryNodes();
328 }
329
330 std::cout << magentaColor << std::setprecision(3) << std::scientific << " [" << (std::chrono::duration<double>(std::chrono::system_clock::now() - t0)).count() << " sec]." << defaultColor << std::endl;
331 }
332
333 /**************************************************************************/
334 template <int dim>
336 {
337 const auto t0 = std::chrono::system_clock::now();
338 std::cout << " Remeshing network: expanding... " << std::flush;
339 std::set<std::pair<size_t, size_t>> toBeExpanded;
340 for (const auto &linkIter : DN.networkLinks())
341 {
342 const auto sharedLink(linkIter.second.lock());
343
344 if (!sharedLink->hasZeroBurgers() && !sharedLink->isSessile() && !sharedLink->isBoundarySegment() && !sharedLink->isGrainBoundarySegment())
345 {
346 const VectorDim chord(sharedLink->chord()); // this is sink->get_P() - source->get_P()
347 const double chordLength(chord.norm());
348
349// if (sharedLink->source->loopNodes().size() > 1 && sharedLink->sink->loopNodes().size() > 1
350// /*&& chord.dot(dv)>vTolexp*chordLength*dv.norm()*/
351// && chordLength > 3.0 * Lmin)
352// { // also expands a straight line to generate glissile segment
353// toBeExpanded.insert(std::make_pair(sharedLink->source->sID, sharedLink->sink->sID));
354// }
355
356 // Expand segments shorter than Lmax
357 if (chordLength > Lmax)
358 {
359 toBeExpanded.insert(std::make_pair(sharedLink->source->sID, sharedLink->sink->sID));
360 }
361 }
362 }
363
364 // Call Network::expand
365 unsigned int Nexpanded(0);
366 const double expand_at(0.5);
367 for (const auto &expIter : toBeExpanded)
368 {
369 // const size_t i(expIter->first);
370 // const size_t j(expIter->second);
371 const auto source(DN.networkNodes().get(expIter.first));
372 const auto sink(DN.networkNodes().get(expIter.second));
373
374 const auto Lij(DN.networkLinks().get(expIter));
375 if (Lij)
376 {
377 VectorDim expandPoint(Lij->get_r(expand_at));
378
379 if ((expandPoint - source->get_P()).squaredNorm() > FLT_EPSILON && (expandPoint - sink->get_P()).squaredNorm() > FLT_EPSILON)
380 {
381
382 const auto newNetNode(DN.networkNodes().create(expandPoint, 0.5 * (source->get_V() + sink->get_V()),0.5 * (source->climbVelocityScalar + sink->climbVelocityScalar) ,0.5 * (source->velocityReduction() + sink->velocityReduction())));
383// std::cout<<"Expanding "<<Lij->tag()<<std::endl;
384
385 DN.expandNetworkLink(Lij, newNetNode);
386 Nexpanded++;
387 }
388 }
389 }
390 std::cout << " (" << Nexpanded << " expanded)" << std::flush;
391 std::cout << magentaColor << std::setprecision(3) << std::scientific << " [" << (std::chrono::duration<double>(std::chrono::system_clock::now() - t0)).count() << " sec]." << defaultColor << std::endl;
392 }
393
394 /**************************************************************************/
395 template <int dim>
396 void DislocationNetworkRemesh<dim>::contractBoundaryNodes() //This function contracts boundary nodes if they are at the same position and share atleast one same neightbors
397 {
398 std::cout << "Contracting BoundaryNodes... " << std::flush;
399 const auto t0 = std::chrono::system_clock::now();
400
401 typedef std::pair<std::shared_ptr<typename DislocationNetwork<dim>::NetworkNodeType>, std::shared_ptr<typename DislocationNetwork<dim>::NetworkNodeType>> NetNodePairType;
402 typedef std::set<NetNodePairType> BndSetType;
403
404 std::map<NetNodePairType, BndSetType> bndNodesContractionMap;
405
406 for (const auto &netNode : DN.networkNodes())
407 {
408 if (netNode.second.lock()->isBoundaryNode())
409 {
410 // std::cout<<"NetNode is "<<netNode.second.lock()->tag()<<std::endl;
411
412 std::set<std::shared_ptr<typename DislocationNetwork<dim>::NetworkNodeType>> internalNodes; // used to be regular ptrs
413 for (const auto &loopNode : netNode.second.lock()->loopNodes())
414 {
415 internalNodes.insert(loopNode->periodicPrev()->networkNode);
416 internalNodes.insert(loopNode->periodicNext()->networkNode);
417 }
418
419 if (internalNodes.size() == 2)
420 {
421
422 // std::cout<<"internal nodes are "<<(*internalNodes.begin())->tag()<<","<<(*internalNodes.rbegin())->tag()<<std::endl;
423
424 const NetNodePairType key((*internalNodes.begin())->sID < (*internalNodes.rbegin())->sID ? std::make_pair(*internalNodes.begin(), *internalNodes.rbegin()) : std::make_pair(*internalNodes.rbegin(), *internalNodes.begin())); // Line that was causing problem
425
426 if (bndNodesContractionMap.find(key) == bndNodesContractionMap.end())
427 { // key not found
428 std::map<std::set<const Polyhedron<dim,dim-1> *>, std::set<typename DislocationNetwork<dim>::NetworkNodeType *>> bndNodeMap;
429
430 for (const auto &loopNode : (*internalNodes.begin())->loopNodes())
431 {
432 if (loopNode->periodicPrev()->networkNode == *internalNodes.rbegin())
433 {
434 for (const auto &bndNode : loopNode->boundaryPrev())
435 {
436 // std::cout<<"adding bndNode "<<bndNode->networkNode->tag()<<std::endl;
437 bndNodeMap[bndNode->networkNode->meshFaces()].insert(bndNode->networkNode.get());
438 }
439 }
440 else if (loopNode->periodicNext()->networkNode == *internalNodes.rbegin())
441 {
442 for (const auto &bndNode : loopNode->boundaryNext())
443 {
444 // std::cout<<"adding bndNode "<<bndNode->networkNode->tag()<<std::endl;
445 bndNodeMap[bndNode->networkNode->meshFaces()].insert(bndNode->networkNode.get());
446 }
447 }
448 }
449
450 for (const auto &pair : bndNodeMap)
451 {
452 // std::cout<<"Nodes of face"<<std::endl;
453 // for(const auto& face : pair.first)
454 // {
455 // std::cout<<face->outNormal().transpose()<<std::endl;
456 // }
457
458 // std::cout<<"nodes size="<<pair.second.size()<<std::endl;
459 if (pair.second.size() > 1)
460 {
461 for (const auto &tempNode : pair.second)
462 {
463 // std::cout<<"node size="<<tempNode->sID<<std::endl;
464 if (tempNode != *pair.second.begin())
465 {
466 if ((tempNode->get_P() - (*pair.second.begin())->get_P()).norm() < FLT_EPSILON)
467 {
468 const NetNodePairType contractPair(tempNode->sID < (*pair.second.begin())->sID ? std::make_pair(tempNode, *pair.second.begin()) : std::make_pair(*pair.second.begin(), tempNode));
469 // std::cout<<"contract pair="<<contractPair.first->sID<<" "<<contractPair.second->sID<<std::endl;
470 bndNodesContractionMap[key].insert(contractPair);
471 }
472 }
473 }
474 }
475 }
476 }
477 }
478 }
479 }
480
481 // std::cout<<"Finished selection"<<std::endl;
482
483 for (const auto &pair : bndNodesContractionMap)
484 {
485 std::cout << "Contracting bnd nodes of intenal nodes " << pair.first.first->tag() << " " << pair.first.second->tag() << std::endl;
486 for (const auto &bndPair : pair.second)
487 {
488 std::cout << "Contracting bnd nodes " << bndPair.first->tag() << " " << bndPair.second->tag() << std::endl;
489 DN.contract(bndPair.first, bndPair.second);
490 }
491 }
492 std::cout << magentaColor << " [" << (std::chrono::duration<double>(std::chrono::system_clock::now() - t0)).count() << " sec]" << defaultColor << std::endl;
493 }
494
495 /**************************************************************************/
496 template <int dim>
497 bool DislocationNetworkRemesh<dim>::zeroChordCandidate(
498 const std::shared_ptr<typename TraitsType::NetworkLinkType>& link) const
499 {
500 if(!link || link->hasZeroBurgers())
501 {
502 return false;
503 }
504 bool physical=false;
505 for(const auto& node : {link->source,link->sink})
506 {
507 for(const auto* ln : node->loopNodes())
508 {
509 // Periodic subdivisions are rebuilt from loop topology, not
510 // independently contracted in RVE coordinates.
511 if(ln->isPeriodicSubdivision())
512 {
513 return false;
514 }
515 physical=physical || ln->isPhysicalBoundaryNode();
516 }
517 }
518 const VectorDim chord=link->sink->get_P()-link->source->get_P();
519 if(chord.norm()<=FLT_EPSILON)
520 {
521 return true;
522 }
523 if(physical)
524 {
525 return false;
526 }
527 const auto sourcePlanes=link->source->glidePlanes();
528 const auto sinkPlanes=link->sink->glidePlanes();
529 return sourcePlanes.size()==dim-1 && sourcePlanes==sinkPlanes &&
530 chord.squaredNorm()+chord.dot(link->sink->get_V()-link->source->get_V())*
531 DN.ddBase.simulationParameters.dt<FLT_EPSILON;
532 }
533
534 template <int dim>
535 size_t DislocationNetworkRemesh<dim>::contractZeroChordCandidates(
536 const std::vector<std::pair<size_t,size_t>>& candidates)
537 {
538 size_t contracted=0;
539 for(const auto& key : candidates)
540 {
541 const auto link=DN.networkLinks().get(key);
542 // Earlier contractions can move endpoints and change confinement.
543 if(zeroChordCandidate(link))
544 {
545 // DN.contract owns the complete boundary reconciliation and
546 // shared-loop update. No per-occurrence boundary motion here.
547 contracted+=DN.contract(link->source,link->sink);
548 }
549 }
550 return contracted;
551 }
552
553 template <int dim>
555 {
556 std::cout<<" Contracting zero-chord segments... "<<std::flush;
557 const auto t0=std::chrono::system_clock::now();
558 std::set<std::pair<double,std::pair<size_t,size_t>>> ordered;
559 for(const auto& entry : DN.networkLinks())
560 {
561 const auto link=entry.second.lock();
562 if(zeroChordCandidate(link))
563 {
564 ordered.emplace((link->sink->get_P()-link->source->get_P()).norm(),link->key);
565 }
566 }
567 std::vector<std::pair<size_t,size_t>> candidates;
568 for(const auto& entry : ordered)
569 {
570 candidates.push_back(entry.second);
571 }
572 const auto contracted=contractZeroChordCandidates(candidates);
573 std::cout<<"("<<contracted<<" contracted)"<<magentaColor<<" ["
574 <<std::chrono::duration<double>(std::chrono::system_clock::now()-t0).count()
575 <<" sec]"<<defaultColor<<std::endl;
576 }
577
578 template <int dim>
580 {
581 std::cout << " Removing zero-area loops across boundary... " << std::flush;
582 const auto t0 = std::chrono::system_clock::now();
583 size_t nRemoved(0);
584
585 std::vector<size_t> loopToBeRemoved;
586 for(const auto& entry : DN.loops())
587 {
588 const auto loop=entry.second.lock();
589 if(loop->glidePlane && loop->currentAreaVector().norm()<FLT_EPSILON)
590 {
591 size_t anchors=0;
592 size_t periodicSubdivisions=0;
593 for(const auto* link : loop->linkSequence())
594 {
595 if(link->source->isPeriodicSubdivision())
596 {
597 ++periodicSubdivisions;
598 }
599 else
600 {
601 // Physical surfaces and grain boundaries are retained
602 // contour vertices, including cross-grain periodic faces.
603 ++anchors;
604 }
605 }
606 if(anchors<3 && periodicSubdivisions>0)
607 {
608 loopToBeRemoved.push_back(loop->sID);
609 }
610 }
611 }
612 // Remove only this loop's memberships. Other loops sharing network
613 // nodes and segments keep their topology and Burgers contributions.
614 for(const auto id : loopToBeRemoved)
615 {
616 DN.deleteLoop(id);
617 ++nRemoved;
618 }
619 std::cout << "(" << nRemoved << " Loops Removed)" << std::flush;
620 std::cout<<magentaColor<<" ["<<(std::chrono::duration<double>(std::chrono::system_clock::now()-t0)).count()<<" sec]"<<defaultColor<<std::endl;
621 }
622
623// /**************************************************************************/
624// template <int dim>
625// double DislocationNetworkRemesh<dim>::minMeshSize(const SimplicialMesh<dim> &mesh)
626// {
627// return std::min(mesh.xMax(0) - mesh.xMin(0), std::min(mesh.xMax(1) - mesh.xMin(1), mesh.xMax(2) - mesh.xMin(2)));
628// }
629
630 template class DislocationNetworkRemesh<3>;
631
632
633} // namespace model
634#endif
635
TraitsType::LoopNodeType LoopNodeType
Class template that handles the nodal remesh of the DislocationNetwork.
DislocationNetworkRemesh(DislocationNetwork< dim > &DN_in)
final point of the source segment t
size_t InstanceCount< Derived >::count
static std::string magentaColor
static std::string defaultColor
REAL t0
newbad key
REAL area
int current