// TODO: FIX OOFEG implementation void TrPlaneStress2dXFEM :: drawRawGeometry(oofegGraphicContext &context) { if ( !context.testElementGraphicActivity(this) ) { return; } XfemManager *xf = this->giveDomain()->giveXfemManager(); if ( !xf->isElementEnriched(this) ) { TrPlaneStress2d :: drawRawGeometry(context); } else { if ( numberOfIntegrationRules > 1 ) { int i; // PatchIntegrationRule *iRule; for ( i = 0; i < numberOfIntegrationRules; i++ ) { // TODO: Implement visualization. /* iRule = dynamic_cast< PatchIntegrationRule * >( integrationRulesArray [ i ] ); if ( iRule ) { iRule->givePatch()->draw(context); } */ } } else { TrPlaneStress2d :: drawRawGeometry(context); } } }
// TODO: FIX OOFEG implementation void TrPlaneStress2dXFEM :: drawRawGeometry(oofegGraphicContext &gc, TimeStep *tStep) { if ( !gc.testElementGraphicActivity(this) ) { return; } XfemManager *xf = this->giveDomain()->giveXfemManager(); if ( !xf->isElementEnriched(this) ) { TrPlaneStress2d :: drawRawGeometry(gc, tStep); } else { if ( integrationRulesArray.size() > 1 ) { #if 0 for ( auto &ir: integrationRulesArray ) { // TODO: Implement visualization. PatchIntegrationRule *iRule = dynamic_cast< PatchIntegrationRule * >( ir ); if ( iRule ) { iRule->givePatch()->draw(gc); } } #endif } else { TrPlaneStress2d :: drawRawGeometry(gc, tStep); } } }
void TrPlaneStress2dXFEM :: computeGaussPoints() { XfemManager *xMan = this->giveDomain()->giveXfemManager(); for(int i = 1; i <= xMan->giveNumberOfEnrichmentItems(); i++) { std::vector<FloatArray> intersecPoints; EnrichmentItem *ei = xMan->giveEnrichmentItem(i); std::vector< int > intersecEdgeInd; ei->computeIntersectionPoints(intersecPoints, intersecEdgeInd, this); int numIntersecPoints = intersecPoints.size(); if ( numIntersecPoints > 0 ) { this->XfemElementInterface_updateIntegrationRule(); } else { TrPlaneStress2d ::computeGaussPoints(); } } // this->XfemElementInterface_updateIntegrationRule(); }
Element_Geometry_Type TrPlaneStress2dXFEM :: giveGeometryType() const { if ( this->giveDomain()->hasXfemManager() ) { XfemManager *xMan = this->giveDomain()->giveXfemManager(); if ( xMan->isElementEnriched(this) ) { return EGT_Composite; } else { return EGT_Composite; } } else { return EGT_triangle_1; } }
void TrPlaneStress2dXFEM :: computeGaussPoints() { if ( giveDomain()->hasXfemManager() ) { XfemManager *xMan = giveDomain()->giveXfemManager(); if ( xMan->isElementEnriched(this) ) { if ( !this->XfemElementInterface_updateIntegrationRule() ) { TrPlaneStress2d :: computeGaussPoints(); } } else { TrPlaneStress2d :: computeGaussPoints(); } } else { TrPlaneStress2d :: computeGaussPoints(); } }
void TrPlaneStress2dXFEM :: drawScalar(oofegGraphicContext &context) { if ( !context.testElementGraphicActivity(this) ) { return; } XfemManager *xf = this->giveDomain()->giveXfemManager(); if ( !xf->isElementEnriched(this) ) { TrPlaneStress2d :: drawScalar(context); } else { if ( context.giveIntVarMode() == ISM_local ) { int indx; double val; FloatArray s(3), v; indx = context.giveIntVarIndx(); TimeStep *tStep = this->giveDomain()->giveEngngModel()->giveCurrentStep(); PatchIntegrationRule *iRule; for ( int i = 0; i < numberOfIntegrationRules; i++ ) { iRule = dynamic_cast< PatchIntegrationRule * >( integrationRulesArray [ i ] ); #if 0 val = iRule->giveMaterial(); #else val = 0.0; for ( int j = 0; j < iRule->giveNumberOfIntegrationPoints(); j++ ) { GaussPoint *gp = iRule->getIntegrationPoint(0); giveIPValue(v, gp, context.giveIntVarType(), tStep); val += v.at(indx); } val /= iRule->giveNumberOfIntegrationPoints(); #endif s.at(1) = s.at(2) = s.at(3) = val; // TODO: Implement visualization. // iRule->givePatch()->drawWD(context, s); } } else { TrPlaneStress2d :: drawScalar(context); } } }
void PrescribedGradientBCWeak :: computeIntForceGPContrib(FloatArray &oContrib_disp, IntArray &oDisp_loc_array, FloatArray &oContrib_trac, IntArray &oTrac_loc_array,TracSegArray &iEl, GaussPoint &iGP, int iDim, TimeStep *tStep, const FloatArray &iBndCoord, const double &iScaleFac, ValueModeType mode, CharType type, const UnknownNumberingScheme &s) { SpatialLocalizer *localizer = domain->giveSpatialLocalizer(); FloatMatrix contrib; assembleTangentGPContributionNew(contrib, iEl, iGP, iScaleFac, iBndCoord); // Compute vector of traction unknowns FloatArray tracUnknowns; iEl.mFirstNode->giveUnknownVector(tracUnknowns, giveTracDofIDs(), mode, tStep); iEl.giveTractionLocationArray(oTrac_loc_array, type, s); FloatArray dispElLocCoord, closestPoint; Element *dispEl = localizer->giveElementClosestToPoint(dispElLocCoord, closestPoint, iBndCoord ); // Compute vector of displacement unknowns FloatArray dispUnknowns; int numDMan = dispEl->giveNumberOfDofManagers(); for(int i = 1; i <= numDMan; i++) { FloatArray nodeUnknowns; DofManager *dMan = dispEl->giveDofManager(i); IntArray dispIDs = giveRegularDispDofIDs(); if(domain->hasXfemManager()) { XfemManager *xMan = domain->giveXfemManager(); dispIDs.followedBy(xMan->giveEnrichedDofIDs(*dMan)); } dMan->giveUnknownVector(nodeUnknowns, dispIDs,mode, tStep); dispUnknowns.append(nodeUnknowns); } dispEl->giveLocationArray(oDisp_loc_array, s); oContrib_disp.beTProductOf(contrib, tracUnknowns); oContrib_disp.negated(); oContrib_trac.beProductOf(contrib, dispUnknowns); oContrib_trac.negated(); }
void TrPlaneStress2dXFEM :: drawScalar(oofegGraphicContext &gc, TimeStep *tStep) { if ( !gc.testElementGraphicActivity(this) ) { return; } XfemManager *xf = this->giveDomain()->giveXfemManager(); if ( !xf->isElementEnriched(this) ) { TrPlaneStress2d :: drawScalar(gc, tStep); } else { if ( gc.giveIntVarMode() == ISM_local ) { int indx; double val; FloatArray s(3), v; indx = gc.giveIntVarIndx(); for ( auto &ir: integrationRulesArray ) { PatchIntegrationRule *iRule = dynamic_cast< PatchIntegrationRule * >(ir); #if 0 val = iRule->giveMaterial(); #else val = 0.0; for ( GaussPoint *gp: *iRule ) { giveIPValue(v, gp, gc.giveIntVarType(), tStep); val += v.at(indx); } val /= iRule->giveNumberOfIntegrationPoints(); #endif s.at(1) = s.at(2) = s.at(3) = val; // TODO: Implement visualization. // iRule->givePatch()->drawWD(gc, s); } } else { TrPlaneStress2d :: drawScalar(gc, tStep); } } }
void TrPlaneStress2dXFEM :: giveDofManDofIDMask(int inode, IntArray &answer) const { // Continuous part TrPlaneStress2d :: giveDofManDofIDMask(inode, answer); // Discontinuous part if( this->giveDomain()->hasXfemManager() ) { DofManager *dMan = giveDofManager(inode); XfemManager *xMan = giveDomain()->giveXfemManager(); const std::vector<int> &nodeEiIndices = xMan->giveNodeEnrichmentItemIndices( dMan->giveGlobalNumber() ); for ( size_t i = 0; i < nodeEiIndices.size(); i++ ) { EnrichmentItem *ei = xMan->giveEnrichmentItem(nodeEiIndices[i]); if ( ei->isDofManEnriched(* dMan) ) { IntArray eiDofIdArray; ei->computeEnrichedDofManDofIdArray(eiDofIdArray, *dMan); answer.followedBy(eiDofIdArray); } } } }
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::doOutput(TimeStep *tStep, bool forcedOutput) { if (!(testTimeStepOutput(tStep) || forcedOutput)) { return; } // Export the sum of reaction forces for each Dirichlet BC if(mExportReactionForces) { outputReactionForces(tStep); } Domain *domain = emodel->giveDomain(1); // Export output from boundary conditions if(mExportBoundaryConditions) { int numBC = domain->giveNumberOfBoundaryConditions(); for(int i = 1; i <= numBC; i++) { PrescribedGradient *presGradBC = dynamic_cast<PrescribedGradient*>( domain->giveBc(i) ); if(presGradBC != NULL) { outputBoundaryCondition(*presGradBC, tStep); } PrescribedGradientBCNeumann *presGradBCNeumann = dynamic_cast<PrescribedGradientBCNeumann*>( domain->giveBc(i) ); if(presGradBCNeumann != NULL) { outputBoundaryCondition(*presGradBCNeumann, tStep); } PrescribedGradientBCWeak *presGradBCWeak = dynamic_cast<PrescribedGradientBCWeak*>( domain->giveBc(i) ); if(presGradBCWeak != NULL) { outputBoundaryCondition(*presGradBCWeak, tStep); } } } mTimeHist.push_back( tStep->giveTargetTime() ); if(mExportXFEM) { if(domain->hasXfemManager()) { XfemManager *xMan = domain->giveXfemManager(); int numEI = xMan->giveNumberOfEnrichmentItems(); std::vector< std::vector<FloatArray> > points; for(int i = 1; i <= numEI; i++) { EnrichmentItem *ei = xMan->giveEnrichmentItem(i); ei->callGnuplotExportModule(*this, tStep); GeometryBasedEI *geoEI = dynamic_cast<GeometryBasedEI*>(ei); if(geoEI != NULL) { std::vector<FloatArray> eiPoints; geoEI->giveSubPolygon(eiPoints, 0.0, 1.0); points.push_back(eiPoints); } } outputXFEMGeometry(points); } } if(mExportMesh) { outputMesh(*domain); } if(mMonitorNodeIndex != -1) { DofManager *dMan = domain->giveDofManager(mMonitorNodeIndex); outputNodeDisp(*dMan, tStep); } }
std::vector<std::unique_ptr<EnrichmentItem>> NCPrincipalStress::nucleateEnrichmentItems() { SpatialLocalizer *octree = this->mpDomain->giveSpatialLocalizer(); XfemManager *xMan = mpDomain->giveXfemManager(); std::vector<std::unique_ptr<EnrichmentItem>> eiList; // Center coordinates of newly inserted cracks std::vector<FloatArray> center_coord_inserted_cracks; // Loop over all elements and all bulk GP. for(auto &el : mpDomain->giveElements() ) { int numIR = el->giveNumberOfIntegrationRules(); int csNum = el->giveCrossSection()->giveNumber(); if(csNum == mCrossSectionInd || true) { for(int irInd = 0; irInd < numIR; irInd++) { IntegrationRule *ir = el->giveIntegrationRule(irInd); int numGP = ir->giveNumberOfIntegrationPoints(); for(int gpInd = 0; gpInd < numGP; gpInd++) { GaussPoint *gp = ir->getIntegrationPoint(gpInd); // int csNum = gp->giveCrossSection()->giveNumber(); // printf("csNum: %d\n", csNum); StructuralMaterialStatus *ms = dynamic_cast<StructuralMaterialStatus*>(gp->giveMaterialStatus()); if(ms != NULL) { const FloatArray &stress = ms->giveTempStressVector(); FloatArray principalVals; FloatMatrix principalDirs; StructuralMaterial::computePrincipalValDir(principalVals, principalDirs, stress, principal_stress); if(principalVals[0] > mStressThreshold) { // printf("\nFound GP with stress above threshold.\n"); // printf("principalVals: "); principalVals.printYourself(); FloatArray crackNormal; crackNormal.beColumnOf(principalDirs, 1); // printf("crackNormal: "); crackNormal.printYourself(); FloatArray crackTangent = {-crackNormal(1), crackNormal(0)}; crackTangent.normalize(); // printf("crackTangent: "); crackTangent.printYourself(); // Create geometry FloatArray pc = {gp->giveGlobalCoordinates()(0), gp->giveGlobalCoordinates()(1)}; // printf("Global coord: "); pc.printYourself(); FloatArray ps = pc; ps.add(-0.5*mInitialCrackLength, crackTangent); FloatArray pe = pc; pe.add(0.5*mInitialCrackLength, crackTangent); if(mCutOneEl) { // If desired, ensure that the crack cuts exactly one element. Line line(ps, pe); std::vector<FloatArray> intersecPoints; // line.computeIntersectionPoints(el.get(), intersecPoints); for ( int i = 1; i <= el->giveNumberOfDofManagers(); i++ ) { // int n1 = i; // int n2 = 0; // if ( i < el->giveNumberOfDofManagers() ) { // n2 = i + 1; // } else { // n2 = 1; // } // const FloatArray &p1 = *(el->giveDofManager(n1)->giveCoordinates()); // const FloatArray &p2 = *(el->giveDofManager(n2)->giveCoordinates()); } // printf("intersecPoints.size(): %lu\n", intersecPoints.size()); if(intersecPoints.size() == 2) { ps = std::move(intersecPoints[0]); pe = std::move(intersecPoints[1]); } else { OOFEM_ERROR("intersecPoints.size() != 2") } } FloatArray points = {ps(0), ps(1), pc(0), pc(1), pe(0), pe(1)}; // double diffX = 0.5*(ps(0) + pe(0)) - pc(0); // printf("diffX: %e\n", diffX); // double diffY = 0.5*(ps(1) + pe(1)) - pc(1); // printf("diffY: %e\n", diffY); // TODO: Check if nucleation is allowed, by checking for already existing cracks close to the GP. // Idea: Nucleation is not allowed if we are within an enriched element. In this way, branching is not // completely prohibited, but we avoid initiating multiple similar cracks. bool insertionAllowed = true; Element *el_s = octree->giveElementContainingPoint(ps); if(el_s) { if( xMan->isElementEnriched(el_s) ) { insertionAllowed = false; } } Element *el_c = octree->giveElementContainingPoint(pc); if(el_c) { if( xMan->isElementEnriched(el_c) ) { insertionAllowed = false; } } Element *el_e = octree->giveElementContainingPoint(pe); if(el_e) { if( xMan->isElementEnriched(el_e) ) { insertionAllowed = false; } } for(const auto &x: center_coord_inserted_cracks) { if( x.distance(pc) < 2.0*mInitialCrackLength) { insertionAllowed = false; break; printf("Preventing insertion.\n"); } } if(insertionAllowed) { int n = xMan->giveNumberOfEnrichmentItems() + 1; std::unique_ptr<Crack> crack = std::make_unique<Crack>(n, xMan, mpDomain); // Geometry std::unique_ptr<BasicGeometry> geom = std::make_unique<PolygonLine>(); geom->insertVertexBack(ps); geom->insertVertexBack(pc); geom->insertVertexBack(pe); crack->setGeometry(std::move(geom)); // Enrichment function EnrichmentFunction *ef = new HeavisideFunction(1, mpDomain); crack->setEnrichmentFunction(ef); // Enrichment fronts // EnrichmentFront *efStart = new EnrFrontLinearBranchFuncOneEl(); EnrichmentFront *efStart = new EnrFrontCohesiveBranchFuncOneEl(); crack->setEnrichmentFrontStart(efStart); // EnrichmentFront *efEnd = new EnrFrontLinearBranchFuncOneEl(); EnrichmentFront *efEnd = new EnrFrontCohesiveBranchFuncOneEl(); crack->setEnrichmentFrontEnd(efEnd); /////////////////////////////////////// // Propagation law // Options // double radius = 0.5*mInitialCrackLength, angleInc = 10.0, incrementLength = 0.5*mInitialCrackLength, hoopStressThreshold = 0.0; // bool useRadialBasisFunc = true; // PLHoopStressCirc *pl = new PLHoopStressCirc(); // pl->setRadius(radius); // pl->setAngleInc(angleInc); // pl->setIncrementLength(incrementLength); // pl->setHoopStressThreshold(hoopStressThreshold); // pl->setUseRadialBasisFunc(useRadialBasisFunc); // PLDoNothing *pl = new PLDoNothing(); PLMaterialForce *pl = new PLMaterialForce(); pl->setRadius(mMatForceRadius); pl->setIncrementLength(mIncrementLength); // pl->setIncrementLength(0.25); // pl->setCrackPropThreshold(0.25); pl->setCrackPropThreshold(mCrackPropThreshold); crack->setPropagationLaw(pl); crack->updateDofIdPool(); center_coord_inserted_cracks.push_back(pc); eiList.push_back( std::unique_ptr<EnrichmentItem>(std::move(crack)) ); // printf("Nucleating a crack in NCPrincipalStress::nucleateEnrichmentItems.\n"); // printf("el->giveGlobalNumber(): %d\n", el->giveGlobalNumber() ); // We only introduce one crack per element in a single time step. break; } } } } } } // If correct csNum }
int PatchIntegrationRule :: SetUpPointsOnTriangle(int nPoints, MaterialMode mode) { int pointsPassed = 0; // TODO: set properly firstLocalStrainIndx = 1; lastLocalStrainIndx = 3; //////////////////////////////////////////// // Allocate Gauss point array // It may happen that the patch contains triangles with // zero area. This does no harm, since their weights in // the quadrature will be zero. However, they invoke additional // computational cost and therefore we want to avoid them. // Thus, count the number of triangles with finite area // and keep only those triangles. double totArea = 0.0; for ( size_t i = 0; i < mTriangles.size(); i++ ) { totArea += mTriangles [ i ].getArea(); } std :: vector< int >triToKeep; const double triTol = ( 1.0e-6 ) * totArea; for ( size_t i = 0; i < mTriangles.size(); i++ ) { if ( mTriangles [ i ].getArea() > triTol ) { triToKeep.push_back(i); } } int nPointsTot = nPoints * triToKeep.size(); FloatArray coords_xi1, coords_xi2, weights; this->giveTriCoordsAndWeights(nPoints, coords_xi1, coords_xi2, weights); this->gaussPoints.resize( nPointsTot ); //////////////////////////////////////////// std :: vector< FloatArray >newGPCoord; double parentArea = this->elem->computeArea(); // Loop over triangles for ( int tri: triToKeep ) { // TODO: Probably unnecessary to allocate here std::vector< FloatArray > coords( mTriangles [ tri ].giveNrVertices() ); // this we should put into the function before for ( int k = 1; k <= mTriangles [ tri ].giveNrVertices(); k++ ) { coords[ k - 1 ] = mTriangles [ tri ].giveVertex( k ); } // Can not be used because it writes to the start of the array instead of appending. // int nPointsTri = GaussIntegrationRule :: SetUpPointsOnTriangle(nPoints, mode); for ( int j = 0; j < nPoints; j++ ) { FloatArray global; GaussPoint * &gp = this->gaussPoints [ pointsPassed ]; FloatArray *coord = new FloatArray(2); coord->at(1) = coords_xi1.at(j + 1); coord->at(2) = coords_xi2.at(j + 1); gp = new GaussPoint(this, pointsPassed + 1, coord, weights.at(j + 1), mode); mTriInterp.local2global( global, * gp->giveNaturalCoordinates(), FEIVertexListGeometryWrapper(coords) ); newGPCoord.push_back(global); FloatArray local; this->elem->computeLocalCoordinates(local, global); gp->setGlobalCoordinates(global); gp->setNaturalCoordinates(local); gp->setSubPatchCoordinates(local); double refElArea = this->elem->giveParentElSize(); gp->setWeight(2.0 * refElArea * gp->giveWeight() * mTriangles [ tri ].getArea() / parentArea); // update integration weight pointsPassed++; } } XfemManager *xMan = elem->giveDomain()->giveXfemManager(); if ( xMan != NULL ) { if ( xMan->giveVtkDebug() ) { double time = 0.0; Element *el = this->elem; if ( el != NULL ) { Domain *dom = el->giveDomain(); if ( dom != NULL ) { EngngModel *em = dom->giveEngngModel(); if ( em != NULL ) { TimeStep *ts = em->giveCurrentStep(); if ( ts != NULL ) { time = ts->giveTargetTime(); } } } } int elIndex = this->elem->giveGlobalNumber(); std :: stringstream str; str << "GaussPointsTime" << time << "El" << elIndex << ".vtk"; std :: string name = str.str(); XFEMDebugTools :: WritePointsToVTK(name, newGPCoord); } } return this->giveNumberOfIntegrationPoints(); }
int PatchIntegrationRule :: SetUpPointsOnWedge(int nPointsTri, int nPointsDepth, MaterialMode mode) { //int pointsPassed = 0; // TODO: set properly firstLocalStrainIndx = 1; lastLocalStrainIndx = 3; double totArea = 0.0; for ( size_t i = 0; i < mTriangles.size(); i++ ) { totArea += mTriangles [ i ].getArea(); } std :: vector< int >triToKeep; const double triTol = ( 1.0e-6 ) * totArea; for ( size_t i = 0; i < mTriangles.size(); i++ ) { if ( mTriangles [ i ].getArea() > triTol ) { triToKeep.push_back(i); } } int nPointsTot = nPointsTri * nPointsDepth * triToKeep.size(); FloatArray coords_xi1, coords_xi2, coords_xi3, weightsTri, weightsDepth; this->giveTriCoordsAndWeights(nPointsTri, coords_xi1, coords_xi2, weightsTri); this->giveLineCoordsAndWeights(nPointsDepth, coords_xi3, weightsDepth); this->gaussPoints.resize(nPointsTot); std :: vector< FloatArray >newGPCoord; double parentArea = this->elem->computeArea(); int count = 0; // Loop over triangles for ( int i = 0; i < int( triToKeep.size() ); i++ ) { Triangle triangle = mTriangles [ triToKeep [ i ] ]; // global coords of the the triangle verticies std::vector< FloatArray > gCoords( triangle.giveNrVertices() ); for ( int j = 0; j < triangle.giveNrVertices(); j++ ) { gCoords[j] = (triangle.giveVertex(j + 1)); } for ( int k = 1; k <= nPointsTri; k++ ) { for ( int m = 1; m <= nPointsDepth; m++ ) { // local coords in the parent triangle FloatArray *lCoords = new FloatArray(3); lCoords->at(1) = coords_xi1.at(k); lCoords->at(2) = coords_xi2.at(k); lCoords->at(3) = coords_xi3.at(m); double refElArea = 0.5; double oldWeight = weightsTri.at(k) * weightsDepth.at(m); double newWeight = 2.0 * refElArea * oldWeight * triangle.getArea() / parentArea; GaussPoint *gp = new GaussPoint(this, count + 1, lCoords, newWeight, mode); this->gaussPoints[count] = gp; count++; // Compute global gp coordinate in the element from local gp coord in the sub triangle FloatArray global; mTriInterp.local2global( global, * gp->giveNaturalCoordinates(), FEIVertexListGeometryWrapper(gCoords) ); // Compute local gp coordinate in the element from global gp coord in the element FloatArray local; this->elem->computeLocalCoordinates(local, global); local.at(3) = coords_xi3.at(m); // manually set third coordinate // compute global coords again, since interpolator dosn't give the z-coord this->elem->computeGlobalCoordinates(global, local); gp->setGlobalCoordinates(global); gp->setNaturalCoordinates(local); gp->setSubPatchCoordinates(local); // Store new global gp coord for vtk output newGPCoord.push_back(global); } } //for ( int k = 0; k < mTriangles [ triToKeep [ i ] ].giveNrVertices(); k++ ) { // delete gCoords [ k ]; //} //delete [] gCoords; } XfemManager *xMan = elem->giveDomain()->giveXfemManager(); if ( xMan != NULL ) { if ( xMan->giveVtkDebug() ) { double time = 0.0; Element *el = this->elem; if ( el != NULL ) { Domain *dom = el->giveDomain(); if ( dom != NULL ) { EngngModel *em = dom->giveEngngModel(); if ( em != NULL ) { TimeStep *ts = em->giveCurrentStep(); if ( ts != NULL ) { time = ts->giveTargetTime(); } } } } int elIndex = this->elem->giveGlobalNumber(); std :: stringstream str; str << "GaussPointsTime" << time << "El" << elIndex << ".vtk"; std :: string name = str.str(); XFEMDebugTools :: WritePointsToVTK(name, newGPCoord); } } return this->giveNumberOfIntegrationPoints(); }
void XFEMStatic :: terminate(TimeStep *tStep) { this->doStepOutput(tStep); this->printReactionForces(tStep, 1); // update load vectors before storing context fflush( this->giveOutputStream() ); this->updateLoadVectors(tStep); this->saveStepContext(tStep); // Propagate fronts for ( auto &domain: domainList ) { XfemManager *xMan = domain->giveXfemManager(); xMan->propagateFronts(); } // Update element subdivisions if necessary // (e.g. if a crack has moved and cut a new element) for ( int domInd = 1; domInd <= this->giveNumberOfDomains(); domInd++ ) { Domain *domain = this->giveDomain(domInd); // create a new set containing all elements Set elemSet(0, domain); elemSet.addAllElements(); if ( domain->giveXfemManager()->hasPropagatingFronts() || mForceRemap ) { // If domain cloning is performed, there is no need to // set values from the dof map. mSetValsFromDofMap = false; // Take copy of the domain to allow mapping of state variables // to the new Gauss points. Domain *dNew = domain->Clone(); bool deallocateOld = false; setDomain(1, dNew, deallocateOld); forceEquationNumbering(); // Map primary variables LSPrimaryVariableMapper primMapper; FloatArray u; primMapper.mapPrimaryVariables(u, * domain, * dNew, VM_Total, * tStep); if ( totalDisplacement.giveSize() == u.giveSize() ) { FloatArray diff; diff.beDifferenceOf(totalDisplacement, u); printf( "diff norm: %e\n", diff.computeNorm() ); } totalDisplacement = u; primMapper.mapPrimaryVariables(incrementOfDisplacement, * domain, * dNew, VM_Incremental, * tStep); int numEl = dNew->giveNumberOfElements(); for ( int i = 1; i <= numEl; i++ ) { //////////////////////////////////////////////////////// // Map state variables for regular Gauss points StructuralElement *el = dynamic_cast< StructuralElement * >( dNew->giveElement(i) ); el->createMaterialStatus(); el->mapStateVariables(* domain, * tStep); //////////////////////////////////////////////////////// // Map state variables for cohesive zone if applicable XfemStructuralElementInterface *xFemEl = dynamic_cast< XfemStructuralElementInterface * >(el); if ( xFemEl != NULL ) { if ( xFemEl->mpCZMat != NULL ) { size_t numCzRules = xFemEl->mpCZIntegrationRules.size(); for ( size_t czIndex = 0; czIndex < numCzRules; czIndex++ ) { if ( xFemEl->mpCZIntegrationRules [ czIndex ] != NULL ) { for ( GaussPoint *gp: *xFemEl->mpCZIntegrationRules [ czIndex ] ) { MaterialStatus *ms = xFemEl->mpCZMat->giveStatus(gp); if ( ms == NULL ) { OOFEM_ERROR("Failed to fetch material status."); } MaterialStatusMapperInterface *interface = dynamic_cast< MaterialStatusMapperInterface * > ( xFemEl->mpCZMat->giveStatus(gp) ); if ( interface == NULL ) { OOFEM_ERROR("Failed to fetch MaterialStatusMapperInterface."); } MaterialStatus *matStat = dynamic_cast< MaterialStatus * >( xFemEl->mpCZMat->giveStatus(gp) ); StructuralInterfaceMaterialStatus *siMatStat = dynamic_cast< StructuralInterfaceMaterialStatus * >(matStat); if ( siMatStat == NULL ) { OOFEM_ERROR("Failed to cast to StructuralInterfaceMaterialStatus."); } interface->MSMI_map_cz(* gp, * domain, elemSet, * tStep, * siMatStat); } } } } } } delete domain; domain = this->giveDomain(1); // Set domain pointer to various components ... this->nMethod->setDomain(domain); int numExpModules = this->exportModuleManager->giveNumberOfModules(); for ( int i = 1; i <= numExpModules; i++ ) { // ... by diving deep into the hierarchies ... :-/ VTKXMLExportModule *vtkxmlMod = dynamic_cast< VTKXMLExportModule * >( this->exportModuleManager->giveModule(i) ); if ( vtkxmlMod != NULL ) { vtkxmlMod->giveSmoother()->setDomain(domain); vtkxmlMod->givePrimVarSmoother()->setDomain(domain); } } this->setUpdateStructureFlag(true); } // if( domain->giveXfemManager()->hasPropagatingFronts() ) //#endif } // Fracture/failure mechanics evaluation for ( auto &domain: domainList ) { if ( domain->hasFractureManager() ) { // Will most likely fail if numDom > 1 FractureManager *fracMan = domain->giveFractureManager(); fracMan->evaluateYourself(tStep); fracMan->updateXFEM(tStep); // Update XFEM structure based on the fracture manager this->setUpdateStructureFlag( fracMan->giveUpdateFlag() ); // if the internal structure need to be updated } } }
void TrPlaneStress2dXFEM :: giveCompositeExportData(std::vector< VTKPiece > &vtkPieces, IntArray &primaryVarsToExport, IntArray &internalVarsToExport, IntArray cellVarsToExport, TimeStep *tStep) { vtkPieces.resize(1); const int numCells = mSubTri.size(); if(numCells == 0) { // Enriched but uncut element // Visualize as a quad vtkPieces[0].setNumberOfCells(1); int numTotalNodes = 3; vtkPieces[0].setNumberOfNodes(numTotalNodes); // Node coordinates std :: vector< FloatArray >nodeCoords; for(int i = 1; i <= 3; i++) { FloatArray &x = *(giveDofManager(i)->giveCoordinates()); nodeCoords.push_back(x); vtkPieces[0].setNodeCoords(i, x); } // Connectivity IntArray nodes1 = {1, 2, 3}; vtkPieces[0].setConnectivity(1, nodes1); // Offset int offset = 3; vtkPieces[0].setOffset(1, offset); // Cell types vtkPieces[0].setCellType(1, 5); // Linear triangle // Export nodal variables from primary fields vtkPieces[0].setNumberOfPrimaryVarsToExport(primaryVarsToExport.giveSize(), numTotalNodes); for ( int fieldNum = 1; fieldNum <= primaryVarsToExport.giveSize(); fieldNum++ ) { UnknownType type = ( UnknownType ) primaryVarsToExport.at(fieldNum); for ( int nodeInd = 1; nodeInd <= numTotalNodes; nodeInd++ ) { if ( type == DisplacementVector ) { // compute displacement FloatArray u = {0.0, 0.0, 0.0}; // Fetch global coordinates (in undeformed configuration) const FloatArray &x = nodeCoords[nodeInd-1]; // Compute local coordinates FloatArray locCoord; computeLocalCoordinates(locCoord, x); // Compute displacement in point FloatMatrix NMatrix; computeNmatrixAt(locCoord, NMatrix); FloatArray solVec; computeVectorOf(VM_Total, tStep, solVec); FloatArray uTemp; uTemp.beProductOf(NMatrix, solVec); if(uTemp.giveSize() == 3) { u = uTemp; } else { u = {uTemp[0], uTemp[1], 0.0}; } vtkPieces[0].setPrimaryVarInNode(fieldNum, nodeInd, u); } else { printf("fieldNum: %d\n", fieldNum); // TODO: Implement // ZZNodalRecoveryMI_recoverValues(values, layer, ( InternalStateType ) 1, tStep); // does not work well - fix // for ( int j = 1; j <= numCellNodes; j++ ) { // vtkPiece.setPrimaryVarInNode(fieldNum, nodeNum, values [ j - 1 ]); // nodeNum += 1; // } } } } // Export nodal variables from internal fields vtkPieces[0].setNumberOfInternalVarsToExport(0, numTotalNodes); // Export cell variables vtkPieces[0].setNumberOfCellVarsToExport(cellVarsToExport.giveSize(), 1); for ( int i = 1; i <= cellVarsToExport.giveSize(); i++ ) { InternalStateType type = ( InternalStateType ) cellVarsToExport.at(i); FloatArray average; std :: unique_ptr< IntegrationRule > &iRule = integrationRulesArray [ 0 ]; VTKXMLExportModule :: computeIPAverage(average, iRule.get(), this, type, tStep); FloatArray averageV9(9); averageV9.at(1) = average.at(1); averageV9.at(5) = average.at(2); averageV9.at(9) = average.at(3); averageV9.at(6) = averageV9.at(8) = average.at(4); averageV9.at(3) = averageV9.at(7) = average.at(5); averageV9.at(2) = averageV9.at(4) = average.at(6); vtkPieces[0].setCellVar( i, 1, averageV9 ); } // Export of XFEM related quantities if ( domain->hasXfemManager() ) { XfemManager *xMan = domain->giveXfemManager(); int nEnrIt = xMan->giveNumberOfEnrichmentItems(); vtkPieces[0].setNumberOfInternalXFEMVarsToExport(xMan->vtkExportFields.giveSize(), nEnrIt, numTotalNodes); const int nDofMan = giveNumberOfDofManagers(); for ( int field = 1; field <= xMan->vtkExportFields.giveSize(); field++ ) { XFEMStateType xfemstype = ( XFEMStateType ) xMan->vtkExportFields [ field - 1 ]; for ( int enrItIndex = 1; enrItIndex <= nEnrIt; enrItIndex++ ) { EnrichmentItem *ei = xMan->giveEnrichmentItem(enrItIndex); for ( int nodeInd = 1; nodeInd <= numTotalNodes; nodeInd++ ) { const FloatArray &x = nodeCoords[nodeInd-1]; FloatArray locCoord; computeLocalCoordinates(locCoord, x); FloatArray N; FEInterpolation *interp = giveInterpolation(); interp->evalN( N, locCoord, FEIElementGeometryWrapper(this) ); if ( xfemstype == XFEMST_LevelSetPhi ) { double levelSet = 0.0, levelSetInNode = 0.0; for(int elNodeInd = 1; elNodeInd <= nDofMan; elNodeInd++) { DofManager *dMan = giveDofManager(elNodeInd); ei->evalLevelSetNormalInNode(levelSetInNode, dMan->giveGlobalNumber(), *(dMan->giveCoordinates()) ); levelSet += N.at(elNodeInd)*levelSetInNode; } FloatArray valueArray = {levelSet}; vtkPieces[0].setInternalXFEMVarInNode(field, enrItIndex, nodeInd, valueArray); } else if ( xfemstype == XFEMST_LevelSetGamma ) { double levelSet = 0.0, levelSetInNode = 0.0; for(int elNodeInd = 1; elNodeInd <= nDofMan; elNodeInd++) { DofManager *dMan = giveDofManager(elNodeInd); ei->evalLevelSetTangInNode(levelSetInNode, dMan->giveGlobalNumber(), *(dMan->giveCoordinates()) ); levelSet += N.at(elNodeInd)*levelSetInNode; } FloatArray valueArray = {levelSet}; vtkPieces[0].setInternalXFEMVarInNode(field, enrItIndex, nodeInd, valueArray); } else if ( xfemstype == XFEMST_NodeEnrMarker ) { double nodeEnrMarker = 0.0, nodeEnrMarkerInNode = 0.0; for(int elNodeInd = 1; elNodeInd <= nDofMan; elNodeInd++) { DofManager *dMan = giveDofManager(elNodeInd); ei->evalNodeEnrMarkerInNode(nodeEnrMarkerInNode, dMan->giveGlobalNumber() ); nodeEnrMarker += N.at(elNodeInd)*nodeEnrMarkerInNode; } FloatArray valueArray = {nodeEnrMarker}; vtkPieces[0].setInternalXFEMVarInNode(field, enrItIndex, nodeInd, valueArray); } } } } } } else { // Enriched and cut element XfemStructuralElementInterface::giveSubtriangulationCompositeExportData(vtkPieces, primaryVarsToExport, internalVarsToExport, cellVarsToExport, tStep); } }