98 const size_t initialNetworkNodeCount(NetworkNodeType::get_count());
102 std::deque<std::shared_ptr<LoopType>> tempLoops;
104 for(
const auto& loop : evl.
loops())
106 const bool faulted(
ddBase.poly.grain(loop.grainID)->rationalLatticeDirection(loop.B).rat.asDouble()!=1.0?
true :
false);
107 VerboseDislocationNetwork(1,
"Creating DislocationLoop "<<loop.sID<<
" ("<<loopNumber<<
" of "<<evl.
loops().size()<<
"), type="<<loop.loopType<<
", faulted="<<faulted<<
", |b|="<<loop.B.norm()<<std::endl;);
110 const size_t loopIDtoUse(loop.sID+initialLoopCount);
111 LoopType::set_count(loopIDtoUse);
114 tempLoops.push_back(this->
loops().
create(loop.B,
ddBase.dislocationDynamics().glidePlaneFactory.getFromKey(loopPlaneKey)));
115 assert(this->
loops().
get(loopIDtoUse)->sID == loopIDtoUse);
120 std::deque<std::shared_ptr<NetworkNodeType>> tempNetNodes;
121 size_t netNodeNumber=1;
122 for(
const auto& node : evl.
nodes())
124 VerboseDislocationNetwork(1,
"Creating DislocationNode "<<node.sID<<
" ("<<netNodeNumber<<
" of "<<evl.
nodes().size()<<
")"<<std::endl;);
125 const size_t nodeIDtoUse(node.sID+initialNetworkNodeCount);
126 NetworkNodeType::set_count(nodeIDtoUse);
127 tempNetNodes.push_back(this->
networkNodes().
create(node.P,node.V,node.climbVelocityScalar,node.velocityReduction));
133 std::deque<std::shared_ptr<LoopNodeType>> tempLoopNodes;
134 size_t loopNodeNumber=1;
137 VerboseDislocationNetwork(1,
"Creating DislocationLoopNode "<<node.sID<<
" ("<<loopNodeNumber<<
" of "<<evl.
loopNodes().size()<<
")"<<std::endl;);
138 const size_t nodeIDtoUse(node.sID+initialLoopNodeCount);
140 const auto loop(this->
loops().
get(node.loopID+initialLoopCount));
141 const auto netNode(this->
networkNodes().
get(node.networkNodeID+initialNetworkNodeCount));
142 const auto periodicPatch(loop->periodicGlidePlane? loop->periodicGlidePlane->patches().getFromKey(node.periodicShift) :
nullptr);
143 std::pair<std::shared_ptr<PeriodicPlaneEdge<dim>>,std::shared_ptr<PeriodicPlaneEdge<dim>>> periodicPatchEdge;
144 if(periodicPatch && node.edgeIDs.first>=0)
146 const VectorDim position=node.P+node.periodicShift;
147 const auto&
edges=periodicPatch->edges();
150 const double tolerance=FLT_EPSILON+(position-netNode->get_P()).norm();
151 const auto matches=[&](
int index)
155 if(matches(node.edgeIDs.first) && (node.edgeIDs.second<0 || (node.edgeIDs.second!=node.edgeIDs.first && matches(node.edgeIDs.second))))
157 periodicPatchEdge.first=
edges[node.edgeIDs.first];
158 if(node.edgeIDs.second>=0)
160 periodicPatchEdge.second=
edges[node.edgeIDs.second];
169 std::vector<std::shared_ptr<PeriodicPlaneEdge<dim>>> candidates;
170 for(
const auto& edge :
edges)
172 if(edge->meshIntersection->distanceTo(position)<=tolerance)
174 candidates.push_back(edge);
177 const size_t expected=node.edgeIDs.second>=0 ? 2 : 1;
178 if(candidates.size()!=expected)
180 throw std::runtime_error(
"Cannot recover saved boundary incidences for loop node "+std::to_string(node.sID));
182 periodicPatchEdge.first=candidates.front();
185 periodicPatchEdge.second=candidates.back();
189 tempLoopNodes.push_back(this->
loopNodes().
create(loop,netNode,node.P,periodicPatch,periodicPatchEdge));
190 assert(this->
loopNodes().
get(nodeIDtoUse)->sID==nodeIDtoUse);
195 std::map<size_t,std::map<size_t,size_t>> loopMap;
196 for(
const auto& looplink : evl.
loopLinks())
198 loopMap[looplink.loopID].emplace(looplink.sourceID,looplink.sinkID);
200 assert(loopMap.size()==evl.
loops().size());
202 for(
const auto& loop : evl.
loops())
205 const auto loopFound=loopMap.find(loop.sID);
206 assert(loopFound!=loopMap.end());
207 std::vector<std::shared_ptr<LoopNodeType>>
loopNodes;
208 loopNodes.push_back(this->loopNodes().
get(loopFound->second.begin()->first+initialLoopNodeCount));
209 for(
size_t k=0;
k<loopFound->second.size();++
k)
211 const auto nodeFound=loopFound->second.find(
loopNodes.back()->sID);
214 loopNodes.push_back(this->loopNodes().
get(nodeFound->second+initialLoopNodeCount));
218 assert(nodeFound->second+initialLoopNodeCount==
loopNodes[0]->sID);
1213 using NodePtr=std::shared_ptr<LoopNodeType>;
1214 using NetPtr=std::shared_ptr<NetworkNodeType>;
1217 const double tolerance=1.e-8*(
ddBase.mesh.xMax()-
ddBase.mesh.xMin()).norm();
1220 NodePtr source,sink;
1223 std::set<const NetworkLinkType*> links;
1224 std::vector<NodePtr> subdivisions;
1229 std::shared_ptr<LoopType> loop;
1230 std::vector<NodePtr> oldNodes,anchors,newNodes;
1231 std::vector<size_t> arcs;
1232 std::vector<Record> contour;
1234 std::vector<Plan> plans;
1235 std::vector<Arc> arcs;
1236 std::set<NodePtr> promoted;
1239 for(
const auto& entry : this->
loops())
1241 const auto loop=entry.second.lock();
1242 if(!loop->periodicGlidePlane)
1248 std::vector<size_t> anchorPositions;
1249 for(
const auto* link : loop->linkSequence())
1251 plan.oldNodes.push_back(link->source);
1254 if(!link->source->isPeriodicSubdivision())
1256 anchorPositions.push_back(plan.oldNodes.size()-1);
1257 plan.anchors.push_back(link->source);
1260 if(plan.anchors.size()<3)
1267 plans.push_back(std::move(plan));
1272 plan.anchors.clear();
1273 anchorPositions.clear();
1274 for(
size_t i=0;
i<plan.oldNodes.size();++
i)
1276 if(plan.anchors.empty() ||
1277 (plan.oldNodes[
i]->get_P()-plan.anchors.back()->get_P()).norm()>tolerance)
1279 promoted.insert(plan.oldNodes[
i]);
1280 plan.anchors.push_back(plan.oldNodes[
i]);
1281 anchorPositions.push_back(
i);
1284 if(plan.anchors.size()>1 &&
1285 (plan.anchors.front()->get_P()-plan.anchors.back()->get_P()).norm()<=tolerance)
1287 plan.anchors.pop_back();
1288 anchorPositions.pop_back();
1290 if(plan.anchors.size()<3)
1292 throw std::runtime_error(
"Cannot establish a retraced periodic contour.");
1295 for(
size_t i=0;
i<plan.anchors.size(); ++
i)
1298 arc.source=plan.anchors[
i];
1299 arc.sink=plan.anchors[(
i+1)%plan.anchors.size()];
1300 arc.chord=arc.sink->get_P()-arc.source->get_P();
1301 arc.reversed=arc.source->networkNode->sID>arc.sink->networkNode->sID;
1302 if(arc.source->networkNode==arc.sink->networkNode)
1306 if(std::abs(arc.chord[
axis])>tolerance)
1308 arc.reversed=arc.chord[
axis]<0;
1315 arc.chord=-arc.chord;
1317 size_t pos=anchorPositions[
i];
1318 const size_t end=anchorPositions[(
i+1)%anchorPositions.size()];
1321 if(
const auto link=plan.oldNodes[pos]->next.second->networkLink())
1323 arc.links.insert(link.get());
1325 pos=(pos+1)%plan.oldNodes.size();
1328 arc.subdivisions.push_back(plan.oldNodes[pos]);
1332 arc.group=arcs.size();
1333 plan.arcs.push_back(arcs.size());
1334 arcs.push_back(std::move(arc));
1336 std::vector<std::pair<VectorLowerDim,const LoopNodeType* const>> polygon;
1337 for(
const auto& node : plan.anchors)
1339 polygon.emplace_back(loop->periodicGlidePlane->referencePlane->localPosition(node->get_P()),node.get());
1341 plan.contour=loop->periodicGlidePlane->polygonPatchIntersection(polygon,
false);
1342 plans.push_back(std::move(plan));
1346 const auto root=[&](
size_t i)
1348 while(arcs[
i].group!=
i)
1354 std::map<std::pair<size_t,size_t>,std::vector<size_t>> endpointArcs;
1355 for(
size_t i=0;
i<arcs.size(); ++
i)
1357 const auto key=std::minmax(arcs[
i].source->networkNode->sID,arcs[
i].sink->networkNode->sID);
1358 auto& peers=endpointArcs[
key];
1359 for(
size_t j : peers)
1361 if((arcs[
i].chord-arcs[
j].chord).norm()<=tolerance)
1363 for(
const auto* link : arcs[
i].links)
1365 if(arcs[
j].links.count(link))
1367 arcs[root(
i)].group=root(
j);
1380 std::map<size_t,std::vector<Crossing>> crossings;
1381 for(
size_t i=0;
i<arcs.size(); ++
i)
1383 const auto& arc=arcs[
i];
1384 const VectorDim d=arc.sink->get_P()-arc.source->get_P();
1385 for(
const auto& node : arc.subdivisions)
1389 double t=d.dot(node->get_P()-arc.source->get_P())/d.squaredNorm();
1390 crossings[root(
i)].push_back({arc.reversed ? 1-
t :
t,node->networkNode});
1396 std::map<size_t,VectorDim> committedPositions;
1397 for(
const auto& plan : plans)
1399 for(
const auto& record : plan.contour)
1401 if(
const auto index=std::get<6>(record).originalVertex)
1403 const auto node=plan.anchors.at(*index)->networkNode;
1404 const VectorDim mapped=plan.loop->periodicGlidePlane->referencePlane->globalPosition(std::get<0>(record))+std::get<1>(record);
1405 if(!committedPositions.count(node->sID) || (mapped-node->get_P()).norm()<=tolerance)
1407 committedPositions[node->sID]=mapped;
1412 std::map<size_t,std::vector<NetPtr>> remappedOriginals;
1413 std::map<std::pair<size_t,size_t>,std::vector<NetPtr>> sharedBoundaryCorners;
1414 std::map<std::pair<std::vector<size_t>,
size_t>,std::vector<NetPtr>> enclosedCorners;
1415 for(
auto& plan : plans)
1419 std::vector<size_t> enclosureOwners;
1420 const bool enclosed=std::any_of(plan.contour.begin(),plan.contour.end(),[](
const Record& record)
1422 return std::get<6>(record).enclosureLayer.has_value();
1426 for(
size_t arc : plan.arcs)
1428 enclosureOwners.push_back(root(arc));
1433 auto best=enclosureOwners;
1434 for(
bool reverse : {
false,
true})
1436 auto candidate=enclosureOwners;
1439 std::reverse(candidate.begin(),candidate.end());
1441 for(
size_t start=0;start<candidate.size();++start)
1443 best=std::min(best,candidate);
1444 std::rotate(candidate.begin(),candidate.begin()+1,candidate.end());
1447 enclosureOwners=std::move(best);
1449 std::set<const LoopNodeType*> reused;
1450 for(
const auto& record : plan.contour)
1452 const auto&
info=std::get<6>(record);
1453 const auto patch=plan.loop->periodicGlidePlane->getPatch(std::get<1>(record));
1454 const VectorDim position=plan.loop->periodicGlidePlane->referencePlane->globalPosition(std::get<0>(record));
1455 const VectorDim mapped=position+patch->shift;
1456 std::pair<std::shared_ptr<Edge>,std::shared_ptr<Edge>>
edges;
1457 if(std::get<2>(record).
first>=0)
1459 edges.first=patch->edges().at(std::get<2>(record).
first);
1460 if(std::get<2>(record).second>=0)
1462 edges.second=patch->edges().at(std::get<2>(record).second);
1467 if(
info.originalVertex)
1469 const auto old=plan.anchors.at(*
info.originalVertex);
1470 networkNode=old->networkNode;
1471 if((committedPositions.at(networkNode->sID)-mapped).norm()>tolerance)
1473 auto& alternatives=remappedOriginals[networkNode->sID];
1474 networkNode.reset();
1475 for(
const auto& other : alternatives)
1477 if((other->get_P()-mapped).norm()<=tolerance)
1485 networkNode=this->
networkNodes().create(mapped,old->networkNode->get_V(),old->networkNode->climbVelocityScalar,old->networkNode->velocityReduction());
1486 alternatives.push_back(networkNode);
1491 edges={
nullptr,
nullptr};
1492 for(
const auto& edge : patch->edges())
1494 if((edge->meshIntersection->snap(mapped)-mapped).norm()<=tolerance)
1506 const auto& previous=old->periodicPlaneEdge;
1507 if(old->networkNode==networkNode && old->periodicPlanePatch()==patch &&
1508 ((previous.first==
edges.first && previous.second==
edges.second) ||
1509 (previous.first==
edges.second && previous.second==
edges.first)))
1514 else if(
info.polygonLocation)
1516 const auto& location=*
info.polygonLocation;
1517 const size_t arcID=plan.arcs.at(location.segment.sourceIndex);
1518 const double t=arcs[arcID].reversed ? 1-location.parameter : location.parameter;
1519 auto& candidates=crossings[root(arcID)];
1520 for(
const auto& candidate : candidates)
1522 if(std::abs(candidate.parameter-
t)<=1.e-8 && (candidate.node->get_P()-mapped).norm()<=tolerance)
1524 networkNode=candidate.node;
1531 candidates.push_back({
t,networkNode});
1533 for(
const auto& old : arcs[arcID].subdivisions)
1535 if(old->networkNode==networkNode && old->periodicPlanePatch()==patch &&
1538 const auto& oldEdges=old->periodicPlaneEdge;
1539 if((oldEdges.first==
edges.first && oldEdges.second==
edges.second) ||
1540 (oldEdges.first==
edges.second && oldEdges.second==
edges.first))
1548 if(!networkNode &&
info.enclosureLayer)
1550 auto& candidates=enclosedCorners[{enclosureOwners,*
info.enclosureLayer}];
1551 for(
const auto& candidate : candidates)
1553 if((candidate->get_P()-mapped).norm()<=tolerance)
1555 networkNode=candidate;
1562 candidates.push_back(networkNode);
1568 if(!networkNode &&
info.onPhysicalBoundary && !plan.arcs.empty())
1570 const size_t index=&record-plan.contour.data();
1571 std::optional<size_t> before,after;
1572 for(
size_t step=1;step<plan.contour.size();++step)
1576 const auto& metadata=std::get<6>(plan.contour[(
index+plan.contour.size()-step)%plan.contour.size()]);
1577 if(metadata.polygonLocation)
1579 before=root(plan.arcs.at(metadata.polygonLocation->segment.sourceIndex));
1584 const auto& metadata=std::get<6>(plan.contour[(
index+step)%plan.contour.size()]);
1585 if(metadata.polygonLocation)
1587 after=root(plan.arcs.at(metadata.polygonLocation->segment.sourceIndex));
1597 auto& candidates=sharedBoundaryCorners[std::minmax(*before,*after)];
1598 for(
const auto& candidate : candidates)
1600 if((candidate->get_P()-mapped).norm()<=tolerance)
1602 networkNode=candidate;
1609 candidates.push_back(networkNode);
1617 if(!chosen || reused.count(chosen.get()))
1619 chosen=this->
loopNodes().create(plan.loop,networkNode,position,patch,
edges);
1621 if(
info.originalVertex && (chosen->periodicPlaneEdge.first || plan.anchors.at(*
info.originalVertex)->periodicContourVertex || promoted.count(plan.anchors.at(*
info.originalVertex))))
1623 promoted.insert(chosen);
1625 reused.insert(chosen.get());
1626 plan.newNodes.push_back(chosen);
1628 if(!plan.newNodes.empty() && plan.newNodes.size()<3)
1630 throw std::runtime_error(
"Boundary update produced a degenerate retained contour.");
1634 using LinkMap=
typename std::remove_reference_t<
decltype(this->
loopLinks())>;
1635 using Key=
typename LoopLinkType::KeyType;
1636 std::vector<Key> obsolete,created;
1637 std::vector<std::tuple<NodePtr,NodePtr,std::shared_ptr<LoopType>>> additions;
1638 std::vector<typename LinkMap::node_type> removed;
1639 struct PositionState
1642 typename NetworkNodeType::SplineNodeType spline;
1645 std::vector<PositionState> savedPositions;
1646 for(
const auto& entry : committedPositions)
1649 savedPositions.push_back({node,
static_cast<const typename NetworkNodeType::SplineNodeType&
>(*node),node->p_Simplex});
1651 for(
const auto& plan : plans)
1653 std::set<Key> desired,replacements;
1654 for(
size_t i=0;
i<plan.newNodes.size();++
i)
1656 const auto a=plan.newNodes[
i];
1657 const auto b=plan.newNodes[(
i+1)%plan.newNodes.size()];
1658 const auto key=LoopLinkType::loopLinkKey(plan.loop,
a,
b);
1659 if(!desired.insert(
key).second)
1661 throw std::runtime_error(
"Boundary contour repeats a loop-link identity.");
1664 if(found==this->
loopLinks().
end() || found->second.source!=
a)
1666 additions.emplace_back(
a,
b,plan.loop);
1667 replacements.insert(
key);
1670 for(
size_t i=0;
i<plan.oldNodes.size();++
i)
1672 const auto a=plan.oldNodes[
i];
1673 const auto b=plan.oldNodes[(
i+1)%plan.oldNodes.size()];
1674 const auto key=LoopLinkType::loopLinkKey(plan.loop,
a,
b);
1675 if(!desired.count(
key) || replacements.count(
key))
1677 obsolete.push_back(
key);
1683 std::shared_ptr<NetworkLinkType> link;
1686 std::shared_ptr<SlipSystem> slip;
1688 std::map<const NetworkLinkType*,SegmentState> segmentStates;
1689 const auto saveSegment=[&](
const std::shared_ptr<NetworkLinkType>& link)
1693 segmentStates.try_emplace(link.get(),SegmentState{link,link->Burgers,link->BurgersNorm,link->_slipSystem});
1696 for(
const auto&
key : obsolete)
1700 for(
const auto& item : additions)
1704 removed.reserve(obsolete.size());
1705 created.reserve(additions.size());
1708 for(
const auto& entry : committedPositions)
1710 this->
networkNodes().get(entry.first)->set_P(entry.second);
1716 for(
const auto&
key : obsolete)
1719 handle.mapped().detachTopology();
1720 removed.push_back(std::move(handle));
1726 for(
const auto& item : additions)
1728 const auto& [
a,
b,loop]=item;
1730 created.push_back(LoopLinkType::loopLinkKey(loop,
a,
b));
1739 for(
const auto&
key : created)
1743 for(
auto& handle : removed)
1745 handle.mapped().attachTopology();
1746 this->
loopLinks().insert(std::move(handle));
1748 for(
const auto& entry : savedPositions)
1750 static_cast<typename NetworkNodeType::SplineNodeType&
>(*entry.node)=entry.spline;
1751 entry.node->p_Simplex=entry.simplex;
1753 for(
const auto& entry : savedPositions)
1755 entry.node->updateGeometry();
1757 for(
const auto& entry : segmentStates)
1759 const auto& state=entry.second;
1760 state.link->Burgers=state.burgers;
1761 state.link->BurgersNorm=state.norm;
1762 state.link->_slipSystem=state.slip;
1763 state.link->straight.updateGeometry();
1767 for(
const auto& node : promoted)
1769 node->periodicContourVertex=
true;