void Crack :: computeCrackIntersectionPoints(Crack &iCrack, std::vector<FloatArray> &oIntersectionPoints, std::vector<double> &oArcPositions) { const double tol = 1.0e-12; // Enrichment domain of the current crack const EnrichmentDomain_BG *ed1 = dynamic_cast<const EnrichmentDomain_BG*>( giveEnrichmentDomain() ); PolygonLine *polygonLine1 = NULL; if(ed1 != NULL) { polygonLine1 = dynamic_cast<PolygonLine*>( ed1->bg ); } // Enrichment domain of the crack given as input const EnrichmentDomain_BG *ed2 = dynamic_cast<const EnrichmentDomain_BG*>( iCrack.giveEnrichmentDomain() ); PolygonLine *polygonLine2 = NULL; if(ed2 != NULL) { polygonLine2 = dynamic_cast<PolygonLine*>( ed2->bg ); } if( polygonLine1 != NULL && polygonLine2 != NULL ) { polygonLine2->computeIntersectionPoints(*polygonLine1, oIntersectionPoints); for(FloatArray pos:oIntersectionPoints) { double tangDist, arcPos; polygonLine1->computeTangentialSignDist(tangDist, pos, arcPos); if(arcPos < -tol || arcPos > (1.0+tol)) { printf("arcPos: %e\n", arcPos); OOFEM_ERROR("arcPos is outside the allowed range [0,1].") } oArcPositions.push_back(arcPos); }
bool XfemStructuralElementInterface :: XfemElementInterface_updateIntegrationRule() { const double tol2 = 1.0e-18; bool partitionSucceeded = false; if ( mpCZMat != NULL ) { mpCZIntegrationRules.clear(); mCZEnrItemIndices.clear(); mCZTouchingEnrItemIndices.clear(); } XfemManager *xMan = this->element->giveDomain()->giveXfemManager(); if ( xMan->isElementEnriched(element) ) { if ( mpCZMat == NULL && mCZMaterialNum > 0 ) { initializeCZMaterial(); } MaterialMode matMode = element->giveMaterialMode(); bool firstIntersection = true; std :: vector< std :: vector< FloatArray > >pointPartitions; mSubTri.clear(); std :: vector< int >enrichingEIs; int elPlaceInArray = xMan->giveDomain()->giveElementPlaceInArray( element->giveGlobalNumber() ); xMan->giveElementEnrichmentItemIndices(enrichingEIs, elPlaceInArray); for ( size_t p = 0; p < enrichingEIs.size(); p++ ) { // Index of current ei int eiIndex = enrichingEIs [ p ]; // Indices of other ei interaction with this ei through intersection enrichment fronts. std :: vector< int >touchingEiIndices; giveIntersectionsTouchingCrack(touchingEiIndices, enrichingEIs, eiIndex, * xMan); if ( firstIntersection ) { // Get the points describing each subdivision of the element double startXi, endXi; bool intersection = false; this->XfemElementInterface_prepareNodesForDelaunay(pointPartitions, startXi, endXi, eiIndex, intersection); if ( intersection ) { firstIntersection = false; // Use XfemElementInterface_partitionElement to subdivide the element for ( int i = 0; i < int ( pointPartitions.size() ); i++ ) { // Triangulate the subdivisions this->XfemElementInterface_partitionElement(mSubTri, pointPartitions [ i ]); } if ( mpCZMat != NULL ) { Crack *crack = dynamic_cast< Crack * >( xMan->giveEnrichmentItem(eiIndex) ); if ( crack == NULL ) { OOFEM_ERROR("Cohesive zones are only available for cracks.") } // We have xi_s and xi_e. Fetch sub polygon. std :: vector< FloatArray >crackPolygon; crack->giveSubPolygon(crackPolygon, startXi, endXi); /////////////////////////////////// // Add cohesive zone Gauss points size_t numSeg = crackPolygon.size() - 1; for ( size_t segIndex = 0; segIndex < numSeg; segIndex++ ) { int czRuleNum = 1; mpCZIntegrationRules.emplace_back( new GaussIntegrationRule(czRuleNum, element) ); // Add index of current ei mCZEnrItemIndices.push_back(eiIndex); // Add indices of other ei, that cause interaction through // intersection enrichment fronts mCZTouchingEnrItemIndices.push_back(touchingEiIndices); // Compute crack normal FloatArray crackTang; crackTang.beDifferenceOf(crackPolygon [ segIndex + 1 ], crackPolygon [ segIndex ]); if ( crackTang.computeSquaredNorm() > tol2 ) { crackTang.normalize(); } FloatArray crackNormal = { -crackTang.at(2), crackTang.at(1) }; mpCZIntegrationRules [ segIndex ]->SetUpPointsOn2DEmbeddedLine(mCSNumGaussPoints, matMode, crackPolygon [ segIndex ], crackPolygon [ segIndex + 1 ]); for ( GaussPoint *gp: *mpCZIntegrationRules [ segIndex ] ) { double gw = gp->giveWeight(); double segLength = crackPolygon [ segIndex ].distance(crackPolygon [ segIndex + 1 ]); gw *= 0.5 * segLength; gp->setWeight(gw); // Fetch material status and set normal StructuralInterfaceMaterialStatus *ms = dynamic_cast< StructuralInterfaceMaterialStatus * >( mpCZMat->giveStatus(gp) ); if ( ms == NULL ) { OOFEM_ERROR("Failed to fetch material status."); } ms->letNormalBe(crackNormal); // Give Gauss point reference to the enrichment item // to simplify post processing. crack->AppendCohesiveZoneGaussPoint(gp); } } } partitionSucceeded = true; } } // if(firstIntersection) else { // Loop over triangles std :: vector< Triangle >allTriCopy; for ( size_t triIndex = 0; triIndex < mSubTri.size(); triIndex++ ) { // Call alternative version of XfemElementInterface_prepareNodesForDelaunay std :: vector< std :: vector< FloatArray > >pointPartitionsTri; double startXi, endXi; bool intersection = false; XfemElementInterface_prepareNodesForDelaunay(pointPartitionsTri, startXi, endXi, mSubTri [ triIndex ], eiIndex, intersection); if ( intersection ) { // Use XfemElementInterface_partitionElement to subdivide triangle j for ( int i = 0; i < int ( pointPartitionsTri.size() ); i++ ) { this->XfemElementInterface_partitionElement(allTriCopy, pointPartitionsTri [ i ]); } // Add cohesive zone Gauss points if ( mpCZMat != NULL ) { Crack *crack = dynamic_cast< Crack * >( xMan->giveEnrichmentItem(eiIndex) ); if ( crack == NULL ) { OOFEM_ERROR("Cohesive zones are only available for cracks.") } // We have xi_s and xi_e. Fetch sub polygon. std :: vector< FloatArray >crackPolygon; crack->giveSubPolygon(crackPolygon, startXi, endXi); int numSeg = crackPolygon.size() - 1; for ( int segIndex = 0; segIndex < numSeg; segIndex++ ) { int czRuleNum = 1; mpCZIntegrationRules.emplace_back( new GaussIntegrationRule(czRuleNum, element) ); size_t newRuleInd = mpCZIntegrationRules.size() - 1; mCZEnrItemIndices.push_back(eiIndex); mCZTouchingEnrItemIndices.push_back(touchingEiIndices); // Compute crack normal FloatArray crackTang; crackTang.beDifferenceOf(crackPolygon [ segIndex + 1 ], crackPolygon [ segIndex ]); if ( crackTang.computeSquaredNorm() > tol2 ) { crackTang.normalize(); } FloatArray crackNormal = { -crackTang.at(2), crackTang.at(1) }; mpCZIntegrationRules [ newRuleInd ]->SetUpPointsOn2DEmbeddedLine(mCSNumGaussPoints, matMode, crackPolygon [ segIndex ], crackPolygon [ segIndex + 1 ]); for ( GaussPoint *gp: *mpCZIntegrationRules [ newRuleInd ] ) { double gw = gp->giveWeight(); double segLength = crackPolygon [ segIndex ].distance(crackPolygon [ segIndex + 1 ]); gw *= 0.5 * segLength; gp->setWeight(gw); // Fetch material status and set normal StructuralInterfaceMaterialStatus *ms = dynamic_cast< StructuralInterfaceMaterialStatus * >( mpCZMat->giveStatus(gp) ); if ( ms == NULL ) { OOFEM_ERROR("Failed to fetch material status."); } ms->letNormalBe(crackNormal); // Give Gauss point reference to the enrichment item // to simplify post processing. crack->AppendCohesiveZoneGaussPoint(gp); } } } } else { allTriCopy.push_back(mSubTri [ triIndex ]); } }
void GnuplotExportModule::outputXFEM(Crack &iCrack, TimeStep *tStep) { const std::vector<GaussPoint*> &czGaussPoints = iCrack.giveCohesiveZoneGaussPoints(); std::vector<double> arcLengthPositions, normalJumps, tangJumps, normalTractions; const BasicGeometry *bg = iCrack.giveGeometry(); for( GaussPoint *gp: czGaussPoints ) { StructuralInterfaceMaterialStatus *matStat = dynamic_cast<StructuralInterfaceMaterialStatus*> ( gp->giveMaterialStatus() ); if(matStat != NULL) { // Compute arc length position of the Gauss point const FloatArray &coord = (gp->giveGlobalCoordinates()); double tangDist = 0.0, arcPos = 0.0; bg->computeTangentialSignDist(tangDist, coord, arcPos); arcLengthPositions.push_back(arcPos); // Compute displacement jump in normal and tangential direction // Local numbering: (tang_z, tang, normal) const FloatArray &jumpLoc = matStat->giveJump(); double normalJump = jumpLoc.at(3); normalJumps.push_back(normalJump); tangJumps.push_back( jumpLoc.at(2) ); const FloatArray &trac = matStat->giveFirstPKTraction(); normalTractions.push_back(trac.at(3)); } } Domain *domain = emodel->giveDomain(1); XfemManager *xMan = domain->giveXfemManager(); if ( xMan != NULL ) { double time = 0.0; TimeStep *ts = emodel->giveCurrentStep(); if ( ts != NULL ) { time = ts->giveTargetTime(); } int eiIndex = iCrack.giveNumber(); std :: stringstream strNormalJump; strNormalJump << "NormalJumpGnuplotEI" << eiIndex << "Time" << time << ".dat"; std :: string nameNormalJump = strNormalJump.str(); XFEMDebugTools::WriteArrayToGnuplot(nameNormalJump, arcLengthPositions, normalJumps); std :: stringstream strTangJump; strTangJump << "TangJumpGnuplotEI" << eiIndex << "Time" << time << ".dat"; std :: string nameTangJump = strTangJump.str(); XFEMDebugTools::WriteArrayToGnuplot(nameTangJump, arcLengthPositions, tangJumps); std :: stringstream strNormalTrac; strNormalTrac << "NormalTracGnuplotEI" << eiIndex << "Time" << time << ".dat"; std :: string nameNormalTrac = strNormalTrac.str(); XFEMDebugTools::WriteArrayToGnuplot(nameNormalTrac, arcLengthPositions, normalTractions); std::vector<FloatArray> matForcesStart, matForcesEnd; std::vector<double> radii; // Material forces for(double matForceRadius : mMatForceRadii) { radii.push_back(matForceRadius); EnrichmentFront *efStart = iCrack.giveEnrichmentFrontStart(); const TipInfo &tipInfoStart = efStart->giveTipInfo(); FloatArray matForceStart; mpMatForceEvaluator->computeMaterialForce(matForceStart, *domain, tipInfoStart, tStep, matForceRadius); if(matForceStart.giveSize() > 0) { matForcesStart.push_back(matForceStart); } else { matForcesStart.push_back({0.0,0.0}); } EnrichmentFront *efEnd = iCrack.giveEnrichmentFrontEnd(); const TipInfo &tipInfoEnd = efEnd->giveTipInfo(); FloatArray matForceEnd; mpMatForceEvaluator->computeMaterialForce(matForceEnd, *domain, tipInfoEnd, tStep, matForceRadius); if(matForceEnd.giveSize() > 0) { matForcesEnd.push_back(matForceEnd); } else { matForcesEnd.push_back({0.0,0.0}); } } std::vector< std::vector<FloatArray> > matForcesStartArray, matForcesEndArray; matForcesStartArray.push_back(matForcesStart); matForcesEndArray.push_back(matForcesEnd); std :: stringstream strRadii; strRadii << "MatForceRadiiGnuplotTime" << time << "Crack" << iCrack.giveNumber() << ".dat"; XFEMDebugTools::WriteArrayToGnuplot(strRadii.str(), radii, radii); std :: stringstream strMatForcesStart; strMatForcesStart << "MatForcesStartGnuplotTime" << time << "Crack" << iCrack.giveNumber() << ".dat"; WritePointsToGnuplot(strMatForcesStart.str(), matForcesStartArray); std :: stringstream strMatForcesEnd; strMatForcesEnd << "MatForcesEndGnuplotTime" << time << "Crack" << iCrack.giveNumber() << ".dat"; WritePointsToGnuplot(strMatForcesEnd.str(), matForcesEndArray); double crackLength = iCrack.computeLength(); // printf("crackLength: %e\n", crackLength ); mCrackLengthHist[eiIndex].push_back(crackLength); std :: stringstream strCrackLength; strCrackLength << "CrackLengthGnuplotEI" << eiIndex << "Time" << time << ".dat"; XFEMDebugTools::WriteArrayToGnuplot(strCrackLength.str(), mTimeHist, mCrackLengthHist[eiIndex]); } }
void XfemStructureManager :: splitCracks() { // Loop over cracks for ( int i = 1; i <= giveNumberOfEnrichmentItems(); i++ ) { Crack *crack_i = dynamic_cast< Crack * >( this->giveEnrichmentItem(i) ); if ( crack_i ) { // Check if crack i intersects with any of the cracks [1,i-1]: for ( int j = 1; j < i; j++ ) { // TODO: To improve performance, we may wish to use // a tree structure here. bool splittedCrack = false; Crack *crack_j = dynamic_cast< Crack * >( this->giveEnrichmentItem(j) ); if ( crack_j ) { // If so, find the arc length positions of the intersections on crack i ... std :: vector< FloatArray >intersectionPoints; std :: vector< double >arcPositions_i, arcPositions_j; crack_i->computeCrackIntersectionPoints(* crack_j, intersectionPoints, arcPositions_i); crack_j->computeArcPoints(intersectionPoints, arcPositions_j); const double arcLengthTol = 1.0e-6; for ( int k = 0; k < int( arcPositions_i.size() ); k++ ) { if ( arcPositions_i [ k ] < arcLengthTol || arcPositions_i [ k ] > ( 1.0 - arcLengthTol ) || arcPositions_j [ k ] < arcLengthTol || arcPositions_j [ k ] > ( 1.0 - arcLengthTol ) ) { arcPositions_i.erase(arcPositions_i.begin() + k); arcPositions_j.erase(arcPositions_j.begin() + k); k--; } } if ( arcPositions_i.size() > 0 ) { arcPositions_i.insert(arcPositions_i.begin(), 0.0); arcPositions_i.push_back(1.0); arcPositions_j.insert(arcPositions_j.begin(), 0.0); arcPositions_j.push_back(1.0); for ( int k = 1; k < int( arcPositions_i.size() ); k++ ) { // Only include segments of finite length if ( fabs(arcPositions_i [ k ] - arcPositions_i [ k - 1 ]) > arcLengthTol ) { //printf("arcPositions.size(): %lu\n", arcPositions.size() ); DynamicDataReader dataReader; crack_i->appendInputRecords(dataReader); // ... split crack i at the intersection and add intersection enrichment // fronts at the newly detected intersections. int n1 = this->giveNumberOfEnrichmentItems() + 1; // EnrichmentItem *newEI_1 = new Crack(n1, this, this->giveDomain() ); Crack *newCrack = new Crack( n1, this, this->giveDomain() ); std :: unique_ptr< EnrichmentItem >newEI_1(newCrack); InputRecord *ir = dataReader.giveInputRecord(DataReader :: IR_enrichItemRec, i); newEI_1->initializeFrom(ir); newEI_1->instanciateYourself(& dataReader); PolygonLine *new_pl = dynamic_cast< PolygonLine * >( newCrack->giveGeometry() ); // EDCrack *ed = dynamic_cast<EDCrack*>( newEI_1->giveEnrichmentDomain() ); if ( new_pl == NULL ) { OOFEM_ERROR("Failed to cast PolygonLine *new_pl.") } if ( new_pl != NULL ) { //printf("arcPositions_i[k-1]: %e arcPositions_i[k]: %e\n", arcPositions_i[k-1], arcPositions_i[k] ); new_pl->cropPolygon(arcPositions_i [ k - 1 ], arcPositions_i [ k ]); PolygonLine *polygonLine_j = dynamic_cast< PolygonLine * >( crack_j->giveGeometry() ); if ( polygonLine_j == NULL ) { OOFEM_ERROR("Failed to cast PolygonLine *polygonLine_j.") } PolygonLine *polygonLine_i = dynamic_cast< PolygonLine * >( crack_i->giveGeometry() ); if ( polygonLine_i == NULL ) { OOFEM_ERROR("Failed to cast PolygonLine *polygonLine_i.") } // Take enrichment front tangent direction // as the normal direction of crack_j // EnrichmentDomain_BG *ed_crack_j = dynamic_cast<EnrichmentDomain_BG*>( crack_j->giveEnrichmentDomain() ); // if(ed_crack_j == NULL) { // OOFEM_ERROR("Failed to cast EnrichmentDomain_BG *ed_crack_j.") // } // // PolygonLine *polygonLine_j = dynamic_cast<PolygonLine*>( ed_crack_j->bg ); // if(polygonLine_j == NULL) { // OOFEM_ERROR("Failed to cast PolygonLine *polygonLine_j.") // } // // EnrichmentDomain_BG *ed_crack_i = dynamic_cast<EnrichmentDomain_BG*>( crack_i->giveEnrichmentDomain() ); // if(ed_crack_i == NULL) { // OOFEM_ERROR("Failed to cast EnrichmentDomain_BG *ed_crack_i.") // } // // PolygonLine *polygonLine_i = dynamic_cast<PolygonLine*>( ed_crack_i->bg ); // if(polygonLine_i == NULL) { // OOFEM_ERROR("Failed to cast PolygonLine *polygonLine_i.") // } // Change enrichment fronts if ( k - 1 > 0 ) { FloatArray frontTangent1; polygonLine_j->giveNormal(frontTangent1, arcPositions_j [ k - 1 ]); FloatArray crackTangent1; polygonLine_i->giveTangent(crackTangent1, arcPositions_i [ k - 1 ]); crackTangent1.times(-1.0); EnrFrontIntersection *ef = new EnrFrontIntersection(); if ( frontTangent1.dotProduct(crackTangent1) < 0.0 ) { frontTangent1.times(-1.0); } ef->setTangent(frontTangent1); newEI_1->setEnrichmentFrontStart(ef); } if ( k < int( arcPositions_i.size() ) - 1 ) { FloatArray frontTangent1; polygonLine_j->giveNormal(frontTangent1, arcPositions_j [ k ]); FloatArray crackTangent1; polygonLine_i->giveTangent(crackTangent1, arcPositions_i [ k ]); EnrFrontIntersection *ef = new EnrFrontIntersection(); if ( frontTangent1.dotProduct(crackTangent1) < 0.0 ) { frontTangent1.times(-1.0); } ef->setTangent(frontTangent1); newEI_1->setEnrichmentFrontEnd(ef); } } //this->enrichmentItemList[i-1] = std :: move(ei); this->enrichmentItemList.push_back(NULL); newEI_1->updateGeometry(); this->enrichmentItemList [ enrichmentItemList.size() - 1 ] = std :: move(newEI_1); splittedCrack = true; } } } } if ( splittedCrack ) { enrichmentItemList.erase(enrichmentItemList.begin() + i - 1); numberOfEnrichmentItems = giveNumberOfEnrichmentItems(); i--; break; } }