99 int shearInd = 3, numRows = 3;
113 interp->
evaldNdx(dNdx, iNaturalGpCoord, geomWrapper);
114 interp->
evalN(
N, iNaturalGpCoord, geomWrapper);
123 for (
int i = 1; i <= nDofMan; i++ ) {
126 globalCoord.
at(1) +=
N.at(i) * nodeCoord [ 0 ];
127 globalCoord.
at(2) +=
N.at(i) * nodeCoord [ 1 ];
132 std :: vector< FloatMatrix >Bc(nDofMan);
133 for (
int i = 1; i <= nDofMan; i++ ) {
136 BNode.
at(1, 1) = dNdx.
at(i, 1);
137 BNode.
at(2, 2) = dNdx.
at(i, 2);
138 BNode.
at(shearInd, 1) = dNdx.
at(i, 2);
141 BNode.
at(shearInd + 1, 2) = dNdx.
at(i, 1);
143 BNode.
at(shearInd, 2) = dNdx.
at(i, 1);
149 double enrDofsScaleFactor = 1.0;
156 std :: vector< FloatMatrix >Bd(nDofMan);
158 int counter = nDofMan * dim;
162 for (
int j = 1; j <= nDofMan; j++ ) {
171 if ( numEnrNode > 0 ) {
173 BdNode.
resize(numRows, numEnrNode * dim);
178 int nodeEnrCounter = 0;
181 for (
size_t i = 0; i < nodeEiIndices.size(); i++ ) {
188 std :: vector< FloatArray >efgpD;
191 std :: vector< double >efGP;
200 std :: vector< double >efNode;
205 int numEnr = efGP.size();
206 for (
int k = 0; k < numEnr; k++ ) {
211 for (
int p = 1; p <= dim; p++ ) {
212 grad_ef_N.
at(p) = dNdx.
at(j, p) * ( efGP [ k ] - efNode [ k ] ) +
N.at(j) * efgpD [ k ].at(p);
215 BdNode.
at(1, nodeEnrCounter + 1) = grad_ef_N.
at(1);
216 BdNode.
at(2, nodeEnrCounter + 2) = grad_ef_N.
at(2);
217 BdNode.
at(shearInd, nodeEnrCounter + 1) = grad_ef_N.
at(2);
220 BdNode.
at(shearInd + 1, nodeEnrCounter + 2) = grad_ef_N.
at(1);
222 BdNode.
at(shearInd, nodeEnrCounter + 2) = grad_ef_N.
at(1);
235 oAnswer.
resize(numRows, counter);
238 for (
int i = 0; i < nDofMan; i++ ) {
241 if ( Bd [ i ].isNotEmpty() ) {
242 Bd[i].times(enrDofsScaleFactor);
245 column += Bd [ i ].giveNumberOfColumns();
263void XfemElementInterface :: XfemElementInterface_createEnrNmatrixAt(
FloatMatrix &oAnswer,
const FloatArray &iLocCoord,
Element &iEl,
const std :: vector< int > &iLocNodeInd,
bool iSetDiscontContribToZero)
278 for (
int i = 1; i <= nDofMan; i++ ) {
289 [[maybe_unused]]
int counter = iLocNodeInd.size() * dim;
291 std :: vector< std :: vector< double > >Nd( iLocNodeInd.size() );
292 for (
int j = 1; j <= int( iLocNodeInd.size() ); j++ ) {
294 Node *node =
dynamic_cast< Node *
>( dMan );
298 std :: vector< double > &NdNode = Nd [ j - 1 ];
299 NdNode.assign(numEnrNode, 0.0);
304 size_t nodeCounter = 0;
306 int placeInArray =
element->giveDomain()->giveDofManPlaceInArray(globalNodeInd);
308 for (
size_t i = 0; i < nodeEiIndices.size(); i++ ) {
316 std :: vector< double >efGP;
317 ei->
evaluateEnrFuncAt(efGP, globalCoord, iLocCoord, globalNodeInd, iEl, Nc, elNodes);
322 std :: vector< double >efNode;
329 int numEnr = efGP.size();
330 for (
int k = 0; k < numEnr; k++ ) {
331 if ( iSetDiscontContribToZero ) {
332 NdNode [ nodeCounter ] = 0.0;
334 NdNode [ nodeCounter ] = ( efGP [ k ] - efNode [ k ] ) * Nc.
at(j);
343 int numN = iLocNodeInd.size();
345 for (
int j = 1; j <= int( iLocNodeInd.size() ); j++ ) {
346 numN += Nd [ j - 1 ].size();
354 for (
int i = 1; i <= int( iLocNodeInd.size() ); i++ ) {
355 NTot.
at(
column) = Nc.
at(iLocNodeInd [ i - 1 ]);
358 const std :: vector< double > &NdNode = Nd [ i - 1 ];
359 for (
size_t j = 1; j <= NdNode.size(); j++ ) {
360 NTot.
at(
column) = NdNode [ j - 1 ]*enrDofsScaleFactor;
392bool XfemElementInterface :: XfemElementInterface_updateIntegrationRule()
394 bool partitionSucceeded =
false;
398 MaterialMode matMode =
element->giveMaterialMode();
400 bool firstIntersection =
true;
402 std :: vector< std :: vector< FloatArray > >pointPartitions;
403 std :: vector< Triangle >allTri;
405 std :: vector< int >enrichingEIs;
410 for (
size_t p = 0; p < enrichingEIs.size(); p++ ) {
411 int eiIndex = enrichingEIs [ p ];
413 if ( firstIntersection ) {
415 double startXi, endXi;
416 bool intersection =
false;
419 if ( intersection ) {
420 firstIntersection =
false;
423 for (
int i = 0; i < int ( pointPartitions.size() ); i++ ) {
428 partitionSucceeded =
true;
433 std :: vector< Triangle >allTriCopy;
434 for (
size_t triIndex = 0; triIndex < allTri.size(); triIndex++ ) {
436 std :: vector< std :: vector< FloatArray > >pointPartitionsTri;
437 double startXi, endXi;
438 bool intersection =
false;
441 if ( intersection ) {
443 for (
int i = 0; i < int ( pointPartitionsTri.size() ); i++ ) {
447 allTriCopy.push_back(allTri [ triIndex ]);
463 std :: stringstream str3;
464 int elIndex = this->
element->giveGlobalNumber();
465 str3 <<
"TriEl" << elIndex <<
".vtk";
466 std :: string name3 = str3.str();
468 if ( allTri.size() > 0 ) {
469 XFEMDebugTools :: WriteTrianglesToVTK(name3, allTri);
475 if ( partitionSucceeded ) {
476 std :: vector< std :: unique_ptr< IntegrationRule > >intRule;
478 intRule [ 0 ]->SetUpPointsOnTriangle(xMan->
giveNumGpPerTri(), matMode);
479 element->setIntegrationRules( std :: move(intRule) );
483 return partitionSucceeded;
486void XfemElementInterface :: XfemElementInterface_prepareNodesForDelaunay(std :: vector< std :: vector< FloatArray > > &oPointPartitions,
double &oCrackStartXi,
double &oCrackEndXi,
int iEnrItemIndex,
bool &oIntersection)
488 int dim =
element->giveDofManager(1)->giveCoordinates().giveSize();
492 std :: vector< const FloatArray * >nodeCoord;
493 for (
int i = 1; i <= this->
element->giveNumberOfDofManagers(); i++ ) {
494 nodeCoord.push_back( &
element->giveDofManager(i)->giveCoordinates() );
495 elCenter.
add(
element->giveDofManager(i)->giveCoordinates() );
497 elCenter.
times( 1.0 /
double(
element->giveNumberOfDofManagers() ) );
502 if ( ei ==
nullptr ) {
503 oIntersection =
false;
507 std :: vector< FloatArray >intersecPoints;
508 std :: vector< int >intersecEdgeInd;
510 std :: vector< double >minDistArcPos;
513 for (
size_t i = 0; i < intersecPoints.size(); i++ ) {
514 intersecPoints [ i ].resizeWithValues(dim);
518 if ( intersecPoints.size() == 2 ) {
522 oPointPartitions.resize(2);
528 oCrackStartXi = std :: min(minDistArcPos [ 0 ], minDistArcPos [ 1 ]);
529 oCrackEndXi = std :: max(minDistArcPos [ 0 ], minDistArcPos [ 1 ]);
531 oIntersection =
true;
533 }
else if ( intersecPoints.size() == 1 ) {
534 std :: vector< FloatArray >edgeCoords;
539 bool foundTip =
false;
540 double tipArcPos = -1.0;
546 int nEdges = this->
element->giveInterpolation()->giveNumberOfEdges(
element->giveGeometryType());
548 oPointPartitions.clear();
552 for (
int i = 1; i <= nEdges; i++ ) {
553 const auto &bNodes = this->
element->giveInterpolation()->boundaryGiveNodes(i,
element->giveGeometryType());
555 if ( bNodes.giveSize() == 2 ) {
557 int nsLoc = bNodes.at(1);
558 int neLoc = bNodes.at( bNodes.giveSize() );
560 const auto &coordS =
element->giveDofManager(nsLoc)->giveCoordinates();
561 const auto &coordE =
element->giveDofManager(neLoc)->giveCoordinates();
563 if ( i == intersecEdgeInd [ 0 ] ) {
564 oPointPartitions.push_back( std :: vector< FloatArray >() );
565 oPointPartitions [ triPassed ].push_back(tipCoord);
566 oPointPartitions [ triPassed ].push_back(intersecPoints [ 0 ]);
567 oPointPartitions [ triPassed ].push_back(coordE);
570 oPointPartitions.push_back( std :: vector< FloatArray >() );
571 oPointPartitions [ triPassed ].push_back(tipCoord);
572 oPointPartitions [ triPassed ].push_back(coordS);
573 oPointPartitions [ triPassed ].push_back(intersecPoints [ 0 ]);
576 oPointPartitions.push_back( std :: vector< FloatArray >() );
577 oPointPartitions [ triPassed ].push_back(tipCoord);
578 oPointPartitions [ triPassed ].push_back(coordS);
579 oPointPartitions [ triPassed ].push_back(coordE);
582 }
else if( bNodes.giveSize() == 3 ) {
585 const auto &coordS =
element->giveDofManager(bNodes[0])->giveCoordinates();
588 const auto &coordC =
element->giveDofManager(bNodes[2])->giveCoordinates();
591 const auto &coordE =
element->giveDofManager(bNodes[1])->giveCoordinates();
594 if ( i == intersecEdgeInd [ 0 ] ) {
601 if( dist_S_2 < dist_C_2 ) {
602 oPointPartitions.push_back( std :: vector< FloatArray >() );
603 oPointPartitions [ triPassed ].push_back(intersecPoints [ 0 ]);
604 oPointPartitions [ triPassed ].push_back(tipCoord);
605 oPointPartitions [ triPassed ].push_back(coordS);
608 oPointPartitions.push_back( std :: vector< FloatArray >() );
609 oPointPartitions [ triPassed ].push_back(coordC);
610 oPointPartitions [ triPassed ].push_back(tipCoord);
611 oPointPartitions [ triPassed ].push_back(intersecPoints [ 0 ]);
614 oPointPartitions.push_back( std :: vector< FloatArray >() );
615 oPointPartitions [ triPassed ].push_back(coordE);
616 oPointPartitions [ triPassed ].push_back(tipCoord);
617 oPointPartitions [ triPassed ].push_back(coordC);
622 oPointPartitions.push_back( std :: vector< FloatArray >() );
623 oPointPartitions [ triPassed ].push_back(coordC);
624 oPointPartitions [ triPassed ].push_back(tipCoord);
625 oPointPartitions [ triPassed ].push_back(coordS);
629 oPointPartitions.push_back( std :: vector< FloatArray >() );
630 oPointPartitions [ triPassed ].push_back(intersecPoints [ 0 ]);
631 oPointPartitions [ triPassed ].push_back(tipCoord);
632 oPointPartitions [ triPassed ].push_back(coordC);
635 oPointPartitions.push_back( std :: vector< FloatArray >() );
636 oPointPartitions [ triPassed ].push_back(coordE);
637 oPointPartitions [ triPassed ].push_back(tipCoord);
638 oPointPartitions [ triPassed ].push_back(coordC);
645 oPointPartitions.push_back( std :: vector< FloatArray >() );
646 oPointPartitions [ triPassed ].push_back(tipCoord);
647 oPointPartitions [ triPassed ].push_back(coordS);
648 oPointPartitions [ triPassed ].push_back(coordC);
651 oPointPartitions.push_back( std :: vector< FloatArray >() );
652 oPointPartitions [ triPassed ].push_back(tipCoord);
653 oPointPartitions [ triPassed ].push_back(coordC);
654 oPointPartitions [ triPassed ].push_back(coordE);
660 printf(
"bNodes.giveSize(): %d\n", bNodes.giveSize() );
667 oCrackStartXi = std :: min(minDistArcPos [ 0 ], tipArcPos);
668 oCrackEndXi = std :: max(minDistArcPos [ 0 ], tipArcPos);
673 oPointPartitions.resize(1);
675 for (
int i = 1; i <= this->
element->giveNumberOfDofManagers(); i++ ) {
676 const auto &nodeCoord =
element->giveDofManager(i)->giveCoordinates();
677 oPointPartitions [ 0 ].push_back(nodeCoord);
682 oPointPartitions [ 0 ].push_back(intersecPoints [ 0 ]);
691 oCrackStartXi = minDistArcPos [ 0 ];
692 oCrackEndXi = tipArcPos;
695 oIntersection =
true;
704 oIntersection =
false;
707void XfemElementInterface :: XfemElementInterface_prepareNodesForDelaunay(std :: vector< std :: vector< FloatArray > > &oPointPartitions,
double &oCrackStartXi,
double &oCrackEndXi,
const Triangle &iTri,
int iEnrItemIndex,
bool &oIntersection)
709 int dim =
element->giveDofManager(1)->giveCoordinates().giveSize();
713 std :: vector< const FloatArray * >nodeCoord;
714 for (
int i = 1; i <= 3; i++ ) {
718 elCenter.
times(1.0 / 3.0);
724 if ( ei ==
nullptr ) {
725 oIntersection =
false;
729 std :: vector< FloatArray >intersecPoints;
730 std :: vector< int >intersecEdgeInd;
732 std :: vector< double >minDistArcPos;
734 for (
size_t i = 0; i < intersecPoints.size(); i++ ) {
735 intersecPoints [ i ].resizeWithValues(dim);
738 if ( intersecPoints.size() == 2 ) {
743 oPointPartitions.resize(2);
749 oCrackStartXi = std :: min(minDistArcPos [ 0 ], minDistArcPos [ 1 ]);
750 oCrackEndXi = std :: max(minDistArcPos [ 0 ], minDistArcPos [ 1 ]);
752 oIntersection =
true;
754 }
else if ( intersecPoints.size() == 1 ) {
756 std :: vector< FloatArray >edgeCoords, nodeCoords;
759 int dim =
element->giveDofManager(1)->giveCoordinates().giveSize();
762 bool foundTip =
false;
763 double tipArcPos = -1.0;
771 oPointPartitions.resize( ( nEdges + 1 ) );
775 for (
int i = 1; i <= nEdges; i++ ) {
784 if ( i == intersecEdgeInd [ 0 ] ) {
785 oPointPartitions [ triPassed ].push_back(tipCoord);
786 oPointPartitions [ triPassed ].push_back(intersecPoints [ 0 ]);
787 oPointPartitions [ triPassed ].push_back(coordE);
790 oPointPartitions [ triPassed ].push_back(tipCoord);
791 oPointPartitions [ triPassed ].push_back(coordS);
792 oPointPartitions [ triPassed ].push_back(intersecPoints [ 0 ]);
795 oPointPartitions [ triPassed ].push_back(tipCoord);
796 oPointPartitions [ triPassed ].push_back(coordS);
797 oPointPartitions [ triPassed ].push_back(coordE);
804 oCrackStartXi = std :: min(minDistArcPos [ 0 ], tipArcPos);
805 oCrackEndXi = std :: max(minDistArcPos [ 0 ], tipArcPos);
808 oPointPartitions.resize(1);
810 for (
int i = 1; i <= 3; i++ ) {
812 oPointPartitions [ 0 ].push_back(nodeCoord);
817 oCrackStartXi = minDistArcPos [ 0 ];
818 oCrackEndXi = tipArcPos;
821 oIntersection =
true;
825 oIntersection =
false;
828void XfemElementInterface :: putPointsInCorrectPartition(std :: vector< std :: vector< FloatArray > > &oPointPartitions,
829 const std :: vector< FloatArray > &iIntersecPoints,
830 const std :: vector< const FloatArray * > &iNodeCoord)
const
832 for (
size_t i = 0; i < iIntersecPoints.size(); i++ ) {
833 oPointPartitions [ 0 ].push_back(iIntersecPoints [ i ]);
834 oPointPartitions [ 1 ].push_back(iIntersecPoints [ i ]);
838 const double &x1 = iIntersecPoints [ 0 ].at(1);
839 const double &x2 = iIntersecPoints [ 1 ].at(1);
840 const double &y1 = iIntersecPoints [ 0 ].at(2);
841 const double &y2 = iIntersecPoints [ 1 ].at(2);
843 for (
size_t i = 1; i <= iNodeCoord.size(); i++ ) {
844 const double &x = iNodeCoord [ i - 1 ]->at(1);
845 const double &y = iNodeCoord [ i - 1 ]->at(2);
846 double det = ( x1 - x ) * ( y2 - y ) - ( x2 - x ) * ( y1 - y );
849 oPointPartitions [ 0 ].push_back(* iNodeCoord [ i - 1 ]);
851 oPointPartitions [ 1 ].push_back(* iNodeCoord [ i - 1 ]);
856void XfemElementInterface :: partitionEdgeSegment(
int iBndIndex, std :: vector< Line > &oSegments, std :: vector< FloatArray > &oIntersectionPoints,
const double &iTangDistPadding)
858 const double levelSetTol2 = 1.0e-12;
865 if ( interp2d ==
nullptr ) {
866 OOFEM_ERROR(
"In XfemElementInterface :: partitionEdgeSegment: failed to cast to FEInterpolation2d.\n")
871 const auto &xS =
element->giveDofManager( edgeNodes.at(1) )->giveCoordinates();
872 const auto &xE =
element->giveDofManager( edgeNodes.at(2) )->giveCoordinates();
878 oSegments.push_back(seg1);
883 for (
int eiIndex = 1; eiIndex <= numEI; eiIndex++ ) {
886 std :: vector< Line >newSegments;
889 size_t numSeg = oSegments.size();
890 for (
size_t segInd = 0; segInd < numSeg; segInd++ ) {
893 const auto &seg_xS = oSegments [ segInd ].giveVertex(1);
894 const auto &seg_xE = oSegments [ segInd ].giveVertex(2);
899 bool evaluationSucceeded =
true;
900 if ( !
element->computeLocalCoordinates(xiS, seg_xS) ) {
906 if ( !
element->computeLocalCoordinates(xiE, seg_xE) ) {
916 double phiS = 0.0, phiE = 0.0;
917 double gammaS = 0.0, gammaE = 0.0;
920 for (
int i = 1; i <= Ns.
giveSize(); i++ ) {
921 const auto &nodePos =
element->giveNode(i)->giveCoordinates();
922 double phiNode = 0.0;
924 evaluationSucceeded =
false;
927 double gammaNode = 0.0;
929 evaluationSucceeded =
false;
932 phiS += Ns.
at(i) * phiNode;
933 gammaS += Ns.
at(i) * gammaNode;
935 phiE += Ne.
at(i) * phiNode;
936 gammaE += Ne.
at(i) * gammaNode;
940 if ( phiS * phiE < levelSetTol2 && evaluationSucceeded ) {
941 double xi = EnrichmentItem :: calcXiZeroLevel(phiS, phiE);
942 double gamma = 0.5 * ( 1.0 - xi ) * gammaS + 0.5 * ( 1.0 + xi ) * gammaE;
945 if ( gamma > -iTangDistPadding ) {
949 int nDim = std :: min( seg_xS.giveSize(), seg_xE.giveSize() );
953 for (
int i = 1; i <= nDim; i++ ) {
954 ( p.
at(i) ) = 0.5 * ( 1.0 - xi ) * ( ( seg_xS.at(i) ) ) + 0.5 * ( 1.0 + xi ) * ( ( seg_xE.at(i) ) );
957 Line segA(seg_xS, p);
958 newSegments.push_back(segA);
959 Line segB(p, seg_xE);
960 newSegments.push_back(segB);
963 oIntersectionPoints.push_back(p);
965 newSegments.push_back(oSegments [ segInd ]);
969 newSegments.push_back(oSegments [ segInd ]);
973 oSegments = newSegments;
1012void XfemElementInterface :: computeNCohesive(
FloatMatrix &oN,
GaussPoint &iGP,
int iEnrItemIndex,
const std :: vector< int > &iTouchingEnrItemIndices)
1018 element->computeLocalCoordinates(localCoord, globalCoord);
1022 const int nDofMan =
element->giveNumberOfDofManagers();
1029 [[maybe_unused]]
int counter = nDofMan * dim;
1031 std :: vector< std :: vector< double > >Nd(nDofMan);
1033 for (
int j = 1; j <= nDofMan; j++ ) {
1038 std :: vector< double > &NdNode = Nd [ j - 1 ];
1039 NdNode.assign(numEnrNode, 0.0);
1047 for (
size_t i = 0; i < nodeEiIndices.size(); i++ ) {
1052 if ( geoEI !=
nullptr ) {
1056 std :: vector< double >efJumps;
1057 bool gpLivesOnCurrentCrack = ( nodeEiIndices [ i ] == iEnrItemIndex );
1059 bool gpLivesOnInteractingCrack =
false;
1060 for (
int touchingEIIndex : iTouchingEnrItemIndices ) {
1061 if ( nodeEiIndices [ i ] == touchingEIIndex ) {
1062 gpLivesOnInteractingCrack =
true;
1066 if ( nodeEiIndices [ i ] == iEnrItemIndex || gpLivesOnInteractingCrack ) {
1070 for (
int k = 0; k < numEnr; k++ ) {
1071 if ( nodeEiIndices [ i ] == iEnrItemIndex || gpLivesOnInteractingCrack ) {
1072 NdNode [ ndNodeInd ] = efJumps [ k ] * Nc.
at(j);
1074 NdNode [ ndNodeInd ] = 0.0;
1087 for (
int j = 1; j <= nDofMan; j++ ) {
1088 numN += Nd [ j - 1 ].size();
1096 for (
int i = 1; i <= nDofMan; i++ ) {
1100 const std :: vector< double > &NdNode = Nd [ i - 1 ];
1101 for (
size_t j = 1; j <= NdNode.size(); j++ ) {
1102 NTot.
at(
column) = NdNode [ j - 1 ]*enrDofsScaleFactor;