void PolygonLine :: giveGlobalCoordinates(FloatArray &oGlobalCoord, const double &iArcPos) const { double L = computeLength(); double xSegStart = 0.0, xSegEnd = 0.0; double xiSegStart = 0.0, xiSegEnd = 0.0; size_t numSeg = mVertices.size() - 1; const double xiTol = 1.0e-9; if ( iArcPos < xiTol ) { oGlobalCoord = mVertices [ 0 ]; return; } for ( size_t i = 0; i < numSeg; i++ ) { xSegEnd += mVertices [ i ].distance(mVertices [ i + 1 ]); xiSegStart = xSegStart / L; xiSegEnd = xSegEnd / L; if ( iArcPos > xiSegStart-xiTol && iArcPos < xiSegEnd+xiTol ) { // Point is within the segment FloatArray p; double elXi = ( iArcPos - xiSegStart ) / ( xiSegEnd - xiSegStart ); p.beScaled( ( 1.0 - elXi ), mVertices [ i ] ); p.add(elXi, mVertices [ i + 1 ]); oGlobalCoord = p; return; } } }
void RankineMatNl :: giveRealStressVector(FloatArray &answer, MatResponseForm form, GaussPoint *gp, const FloatArray &totalStrain, TimeStep *atTime) { RankineMatNlStatus *nlStatus = ( RankineMatNlStatus * ) this->giveStatus(gp); //mj this->initGpForNewStep(gp); double tempDam; FloatArray tempEffStress, totalStress; MaterialMode mode = gp->giveMaterialMode(); //mj performPlasticityReturn(gp, totalStrain, mode); // nonlocal method "computeDamage" performs the plastic return // for all Gauss points when it is called for the first time // in the iteration tempDam = this->computeDamage(gp, atTime); nlStatus->giveTempEffectiveStress(tempEffStress); answer.beScaled( 1.0 - tempDam, tempEffStress); nlStatus->setTempDamage(tempDam); nlStatus->letTempStrainVectorBe(totalStrain); nlStatus->letTempStressVectorBe(answer); #ifdef keep_track_of_dissipated_energy double gf = sig0 * sig0 / E; // only estimated, but OK for this purpose nlStatus->computeWork(gp, mode, gf); #endif }
void PolygonLine :: giveSubPolygon(std :: vector< FloatArray > &oPoints, const double &iXiStart, const double &iXiEnd) const { double L = computeLength(); double xSegStart = 0.0, xSegEnd = 0.0; double xiSegStart = 0.0, xiSegEnd = 0.0; size_t numSeg = mVertices.size() - 1; const double xiTol = 1.0e-9; if ( iXiStart < xiTol ) { // Add first point oPoints.push_back(mVertices [ 0 ]); } for ( size_t i = 0; i < numSeg; i++ ) { xSegEnd += mVertices [ i ].distance(mVertices [ i + 1 ]); xiSegStart = xSegStart / L; xiSegEnd = xSegEnd / L; if ( iXiStart > xiSegStart-xiTol && iXiStart < xiSegEnd+xiTol ) { // Start point is within the segment FloatArray p; double elXi = ( iXiStart - xiSegStart ) / ( xiSegEnd - xiSegStart ); p.beScaled( ( 1.0 - elXi ), mVertices [ i ] ); p.add(elXi, mVertices [ i + 1 ]); oPoints.push_back(p); } if ( iXiEnd > xiSegStart && iXiEnd < xiSegEnd ) { // End point is within the segment FloatArray p; double elXi = ( iXiEnd - xiSegStart ) / ( xiSegEnd - xiSegStart ); p.beScaled( ( 1.0 - elXi ), mVertices [ i ] ); p.add(elXi, mVertices [ i + 1 ]); oPoints.push_back(p); } if ( xiSegEnd > iXiStart && xiSegEnd < iXiEnd + xiTol ) { // End point of the segment is within range oPoints.push_back(mVertices [ i + 1 ]); } xSegStart = xSegEnd; } }
void FEI3dLineLin :: local2global(FloatArray &answer, const FloatArray &lcoords, const FEICellGeometry &cellgeo) { double ksi; FloatArray n(2); ksi = lcoords.at(1); answer.beScaled( ( 1. - ksi ) * 0.5, *cellgeo.giveVertexCoordinates(1) ); answer.add( ( 1. + ksi ) * 0.5, *cellgeo.giveVertexCoordinates(2) ); }
void IsotropicMoistureTransferMaterial :: giveFluxVector(FloatArray &answer, GaussPoint *gp, const FloatArray &grad, const FloatArray &field, TimeStep *tStep) { TransportMaterialStatus *ms = static_cast< TransportMaterialStatus * >( this->giveStatus(gp) ); ///@todo Shouldn't the permeability typically depend on the primary field and/or its gradient? answer.beScaled(-this->givePermeability(gp, tStep), grad); ms->setTempField(field); ms->setTempGradient(grad); ms->setTempFlux(answer); }
void NonlinearMassTransferMaterial :: giveFluxVector(FloatArray &answer, GaussPoint *gp, const FloatArray &grad, const FloatArray &field, TimeStep *tStep) { TransportMaterialStatus *ms = static_cast< TransportMaterialStatus * >( this->giveStatus(gp) ); double gradPNorm = grad.computeNorm(); answer.beScaled( -(1. + C * pow(gradPNorm, alpha)), grad); ms->setTempGradient(grad); ms->setTempField(field); ms->setTempFlux(answer); }
void ConstantEdgeLoad :: computeValueAt(FloatArray &answer, TimeStep *tStep, const FloatArray &coords, ValueModeType mode) { if ( ( mode != VM_Total ) && ( mode != VM_Incremental ) ) { OOFEM_ERROR("mode not supported"); } if ( !isImposed(tStep) ) { answer.zero(); } else { double factor = this->giveTimeFunction()->evaluate(tStep, mode); answer.beScaled(factor, componentArray); } }
void MisesMatNl :: giveRealStressVector(FloatArray &answer, GaussPoint *gp, const FloatArray &totalStrain, TimeStep *tStep) { MisesMatNlStatus *nlStatus = static_cast< MisesMatNlStatus * >( this->giveStatus(gp) ); this->initGpForNewStep(gp); double tempDam; performPlasticityReturn(gp, totalStrain); tempDam = this->computeDamage(gp, tStep); answer.beScaled(1.0 - tempDam, nlStatus->giveTempEffectiveStress()); nlStatus->setTempDamage(tempDam); nlStatus->letTempStrainVectorBe(totalStrain); nlStatus->letTempStressVectorBe(answer); }
void PrescribedGradientBCWeak :: giveTractionElArcPos(size_t iElInd, double &oXiStart, double &oXiEnd) const { FloatArray xS, xE; giveTractionElCoord(iElInd, xS, xE); FloatArray xC; xC.beScaled(0.5, xS); xC.add(0.5, xE); int sideIndex = giveSideIndex(xC); const double nodeDistTol = 1.0e-15; ArcPosSortFunction3< bool >sortFunc(mLC, mUC, nodeDistTol, sideIndex); oXiStart = sortFunc.calcArcPos(xS); oXiEnd = sortFunc.calcArcPos(xE); }
void MisesMatNl :: giveRealStressVector(FloatArray &answer, MatResponseForm form, GaussPoint *gp, const FloatArray &totalStrain, TimeStep *atTime) { MisesMatNlStatus *nlStatus = ( MisesMatNlStatus * ) this->giveStatus(gp); this->initGpForNewStep(gp); double tempDam; FloatArray tempEffStress, totalStress; MaterialMode mode = gp->giveMaterialMode(); performPlasticityReturn(gp, totalStrain, mode); tempDam = this->computeDamage(gp, atTime); nlStatus->giveTempEffectiveStress(tempEffStress); answer.beScaled( 1.0 - tempDam, tempEffStress); nlStatus->setTempDamage(tempDam); nlStatus->letTempStrainVectorBe(totalStrain); nlStatus->letTempStressVectorBe(answer); }
void MisesMatGrad :: giveRealStressVectorGrad(FloatArray &answer1, double &answer2, GaussPoint *gp, const FloatArray &totalStrain, double nonlocalCumulatedStrain, TimeStep *tStep) { MisesMatGradStatus *status = static_cast< MisesMatGradStatus * >( this->giveStatus(gp) ); //this->initGpForNewStep(gp); this->initTempStatus(gp); double tempDamage; MisesMat :: performPlasticityReturn(gp, totalStrain); status->letTempStrainVectorBe(totalStrain); tempDamage = computeDamage(gp, tStep); const FloatArray &tempEffStress = status->giveTempEffectiveStress(); answer1.beScaled(1.0 - tempDamage, tempEffStress); answer2 = status->giveTempCumulativePlasticStrain(); status->setNonlocalCumulatedStrain(nonlocalCumulatedStrain); status->setTempDamage(tempDamage); status->letTempEffectiveStressBe(tempEffStress); status->letTempStressVectorBe(answer1); }
void SimpleInterfaceMaterial :: giveRealStressVector(FloatArray &answer, GaussPoint *gp, //const FloatArray &totalStrain,// @todo temporary -should not be here /JB const FloatArray &strainVector, TimeStep *tStep) // // returns real stress vector in 3d stress space of receiver according to // previous level of stress and current // strain increment, the only way, how to correctly update gp records // { SimpleInterfaceMaterialStatus *status = static_cast< SimpleInterfaceMaterialStatus * >( this->giveStatus(gp) ); //this->initGpForNewStep(gp); this->initTempStatus(gp); FloatArray shearStrain(2), shearStress; //, strainVector; StructuralElement *el = static_cast< StructuralElement * >( gp->giveElement() ); //el->computeStrainVector(strainVector, gp, tStep); FloatArray tempShearStressShift = status->giveTempShearStressShift(); const double normalStrain = strainVector.at(1); double normalStress, maxShearStress, dp; double shift = -this->kn * this->stiffCoeff * normalClearance; MaterialMode mMode = el->giveMaterialMode(); //answer.resize(giveSizeOfReducedStressStrainVector(mMode)); answer.zero(); if ( normalStrain + normalClearance <= 0. ) { normalStress = this->kn * ( normalStrain + normalClearance ) + shift; //in compression and after the clearance gap closed maxShearStress = fabs(normalStress) * this->frictCoeff; } else { normalStress = this->kn * this->stiffCoeff * ( normalStrain + normalClearance ) + shift; maxShearStress = 0.; } switch ( mMode ) { case _1dInterface: answer.resize(1); break; case _2dInterface: answer.resize(2); shearStrain.at(1) = strainVector.at(2); shearStress.beScaled(this->kn, shearStrain); shearStress.subtract(tempShearStressShift); dp = shearStress.dotProduct(shearStress, 1); if ( dp > maxShearStress * maxShearStress ) { shearStress.times( maxShearStress / sqrt(dp) ); } tempShearStressShift.beScaled(this->kn, shearStrain); tempShearStressShift.subtract(shearStress); answer.at(2) = shearStress.at(1); break; case _3dInterface: case _3dMat: //JB answer.resize(3); shearStrain.at(1) = strainVector.at(2); shearStrain.at(2) = strainVector.at(3); shearStress.beScaled(this->kn, shearStrain); shearStress.subtract(tempShearStressShift); dp = shearStress.dotProduct(shearStress, 2); if ( dp > maxShearStress * maxShearStress ) { shearStress.times( maxShearStress / sqrt(dp) ); } tempShearStressShift.beScaled(this->kn, shearStrain); tempShearStressShift.subtract(shearStress); answer.at(2) = shearStress.at(1); answer.at(3) = shearStress.at(2); break; default: OOFEM_ERROR("Unsupported interface mode"); } double lim = 1.e+50; answer.at(1) = min(normalStress, lim); //threshold on maximum answer.at(1) = max(answer.at(1), -lim); //threshold on minimum //answer.at(1) = normalStress > lim ? lim : normalStress < -lim ? -lim : normalStress; // update gp status->setTempShearStressShift(tempShearStressShift); status->letTempStrainVectorBe(strainVector); status->letTempStressVectorBe(answer); }
void PLHoopStressCirc :: propagateInterfaces(Domain &iDomain, EnrichmentDomain &ioEnrDom) { // Fetch crack tip data TipInfo tipInfoStart, tipInfoEnd; ioEnrDom.giveTipInfos(tipInfoStart, tipInfoEnd); std :: vector< TipInfo >tipInfo = {tipInfoStart, tipInfoEnd}; SpatialLocalizer *localizer = iDomain.giveSpatialLocalizer(); for ( size_t tipIndex = 0; tipIndex < tipInfo.size(); tipIndex++ ) { // Construct circle points on an arc from -90 to 90 degrees double angle = -90.0 + mAngleInc; std :: vector< double >angles; while ( angle <= ( 90.0 - mAngleInc ) ) { angles.push_back(angle * M_PI / 180.0); angle += mAngleInc; } const FloatArray &xT = tipInfo [ tipIndex ].mGlobalCoord; const FloatArray &t = tipInfo [ tipIndex ].mTangDir; const FloatArray &n = tipInfo [ tipIndex ].mNormalDir; // It is meaningless to propagate a tip that is not inside any element Element *el = localizer->giveElementContainingPoint(tipInfo [ tipIndex ].mGlobalCoord); if ( el != NULL ) { std :: vector< FloatArray >circPoints; for ( size_t i = 0; i < angles.size(); i++ ) { FloatArray tangent(2); tangent.zero(); tangent.add(cos(angles [ i ]), t); tangent.add(sin(angles [ i ]), n); tangent.normalize(); FloatArray x(xT); x.add(mRadius, tangent); circPoints.push_back(x); } std :: vector< double >sigTTArray, sigRTArray; // Loop over circle points for ( size_t pointIndex = 0; pointIndex < circPoints.size(); pointIndex++ ) { FloatArray stressVec; if ( mUseRadialBasisFunc ) { // Interpolate stress with radial basis functions // Choose a cut-off length l: // take the distance between two nodes in the element containing the // crack tip multiplied by a constant factor. // ( This choice implies that we hope that the element has reasonable // aspect ratio.) const FloatArray &x1 = * ( el->giveDofManager(1)->giveCoordinates() ); const FloatArray &x2 = * ( el->giveDofManager(2)->giveCoordinates() ); const double l = 1.0 * x1.distance(x2); // Use the octree to get all elements that have // at least one Gauss point in a certain region around the tip. const double searchRadius = 3.0 * l; std :: set< int >elIndices; localizer->giveAllElementsWithIpWithinBox(elIndices, circPoints [ pointIndex ], searchRadius); // Loop over the elements and Gauss points obtained. // Evaluate the interpolation. FloatArray sumQiWiVi; double sumWiVi = 0.0; for ( int elIndex: elIndices ) { Element *gpEl = iDomain.giveElement(elIndex); IntegrationRule *iRule = gpEl->giveDefaultIntegrationRulePtr(); for ( GaussPoint *gp_i: *iRule ) { //////////////////////////////////////// // Compute global gp coordinates FloatArray N; FEInterpolation *interp = gpEl->giveInterpolation(); interp->evalN( N, * ( gp_i->giveCoordinates() ), FEIElementGeometryWrapper(gpEl) ); // Compute global coordinates of Gauss point FloatArray globalCoord(2); globalCoord.zero(); for ( int i = 1; i <= gpEl->giveNumberOfDofManagers(); i++ ) { DofManager *dMan = gpEl->giveDofManager(i); globalCoord.at(1) += N.at(i) * dMan->giveCoordinate(1); globalCoord.at(2) += N.at(i) * dMan->giveCoordinate(2); } //////////////////////////////////////// // Compute weight of kernel function FloatArray tipToGP; tipToGP.beDifferenceOf(globalCoord, xT); bool inFrontOfCrack = true; if ( tipToGP.dotProduct(t) < 0.0 ) { inFrontOfCrack = false; } double r = circPoints [ pointIndex ].distance(globalCoord); if ( r < l && inFrontOfCrack ) { double w = ( ( l - r ) / ( pow(2.0 * M_PI, 1.5) * pow(l, 3) ) ) * exp( -0.5 * pow(r, 2) / pow(l, 2) ); // Compute gp volume double V = gpEl->computeVolumeAround(gp_i); // Get stress StructuralMaterialStatus *ms = dynamic_cast< StructuralMaterialStatus * >( gp_i->giveMaterialStatus() ); if ( ms == NULL ) { OOFEM_ERROR("failed to fetch MaterialStatus."); } FloatArray stressVecGP = ms->giveStressVector(); if ( sumQiWiVi.giveSize() != stressVecGP.giveSize() ) { sumQiWiVi.resize( stressVecGP.giveSize() ); sumQiWiVi.zero(); } // Add to numerator sumQiWiVi.add(w * V, stressVecGP); // Add to denominator sumWiVi += w * V; } } } if ( fabs(sumWiVi) > 1.0e-12 ) { stressVec.beScaled(1.0 / sumWiVi, sumQiWiVi); } else { // Take stress from closest Gauss point int region = 1; bool useCZGP = false; GaussPoint &gp = * ( localizer->giveClosestIP(circPoints [ pointIndex ], region, useCZGP) ); // Compute stresses StructuralMaterialStatus *ms = dynamic_cast< StructuralMaterialStatus * >( gp.giveMaterialStatus() ); if ( ms == NULL ) { OOFEM_ERROR("failed to fetch MaterialStatus."); } stressVec = ms->giveStressVector(); } } else { // Take stress from closest Gauss point int region = 1; bool useCZGP = false; GaussPoint &gp = * ( localizer->giveClosestIP(circPoints [ pointIndex ], region, useCZGP) ); // Compute stresses StructuralMaterialStatus *ms = dynamic_cast< StructuralMaterialStatus * >( gp.giveMaterialStatus() ); if ( ms == NULL ) { OOFEM_ERROR("failed to fetch MaterialStatus."); } stressVec = ms->giveStressVector(); } FloatMatrix stress(2, 2); int shearPos = stressVec.giveSize(); stress.at(1, 1) = stressVec.at(1); stress.at(1, 2) = stressVec.at(shearPos); stress.at(2, 1) = stressVec.at(shearPos); stress.at(2, 2) = stressVec.at(2); // Rotation matrix FloatMatrix rot(2, 2); rot.at(1, 1) = cos(angles [ pointIndex ]); rot.at(1, 2) = -sin(angles [ pointIndex ]); rot.at(2, 1) = sin(angles [ pointIndex ]); rot.at(2, 2) = cos(angles [ pointIndex ]); FloatArray tRot, nRot; tRot.beProductOf(rot, t); nRot.beProductOf(rot, n); FloatMatrix rotTot(2, 2); rotTot.setColumn(tRot, 1); rotTot.setColumn(nRot, 2); FloatMatrix tmp, stressRot; tmp.beTProductOf(rotTot, stress); stressRot.beProductOf(tmp, rotTot); const double sigThetaTheta = stressRot.at(2, 2); sigTTArray.push_back(sigThetaTheta); const double sigRTheta = stressRot.at(1, 2); sigRTArray.push_back(sigRTheta); } ////////////////////////////// // Compute propagation angle // Find angles that fulfill sigRT = 0 const double stressTol = 1.0e-9; double maxSigTT = 0.0, maxAngle = 0.0; bool foundZeroLevel = false; for ( size_t segIndex = 0; segIndex < ( circPoints.size() - 1 ); segIndex++ ) { // If the shear stress sigRT changes sign over the segment if ( sigRTArray [ segIndex ] * sigRTArray [ segIndex + 1 ] < stressTol ) { // Compute location of zero level double xi = EnrichmentItem :: calcXiZeroLevel(sigRTArray [ segIndex ], sigRTArray [ segIndex + 1 ]); double theta = 0.5 * ( 1.0 - xi ) * angles [ segIndex ] + 0.5 * ( 1.0 + xi ) * angles [ segIndex + 1 ]; double sigThetaTheta = 0.5 * ( 1.0 - xi ) * sigTTArray [ segIndex ] + 0.5 * ( 1.0 + xi ) * sigTTArray [ segIndex + 1 ]; // printf("Found candidate: theta: %e sigThetaTheta: %e\n", theta, sigThetaTheta); if ( sigThetaTheta > maxSigTT ) { foundZeroLevel = true; maxSigTT = sigThetaTheta; maxAngle = theta; } } } if ( !foundZeroLevel ) { printf("No zero level was found.\n"); } if ( iDomain.giveXfemManager()->giveVtkDebug() ) { XFEMDebugTools :: WriteArrayToMatlab("sigTTvsAngle.m", angles, sigTTArray); XFEMDebugTools :: WriteArrayToMatlab("sigRTvsAngle.m", angles, sigRTArray); XFEMDebugTools :: WriteArrayToGnuplot("sigTTvsAngle.dat", angles, sigTTArray); XFEMDebugTools :: WriteArrayToGnuplot("sigRTvsAngle.dat", angles, sigRTArray); } // Compare with threshold if ( maxSigTT > mHoopStressThreshold && foundZeroLevel ) { // Rotation matrix FloatMatrix rot(2, 2); rot.at(1, 1) = cos(maxAngle); rot.at(1, 2) = -sin(maxAngle); rot.at(2, 1) = sin(maxAngle); rot.at(2, 2) = cos(maxAngle); FloatArray dir; dir.beProductOf(rot, tipInfo [ tipIndex ].mTangDir); // Fill up struct std :: vector< TipPropagation >tipPropagations; TipPropagation tipProp; tipProp.mTipIndex = tipIndex; tipProp.mPropagationDir = dir; tipProp.mPropagationLength = mIncrementLength; tipPropagations.push_back(tipProp); // Propagate ioEnrDom.propagateTips(tipPropagations); } } } }
void PrescribedGradientBCNeumann :: assembleVector(FloatArray &answer, TimeStep *tStep, CharType type, ValueModeType mode, const UnknownNumberingScheme &s, FloatArray *eNorm) { Set *setPointer = this->giveDomain()->giveSet(this->set); const IntArray &boundaries = setPointer->giveBoundaryList(); IntArray loc, sigma_loc; // For the displacements and stress respectively IntArray masterDofIDs, sigmaMasterDofIDs; mpSigmaHom->giveCompleteLocationArray(sigma_loc, s); if ( type == ExternalForcesVector ) { // The external forces have two contributions. On the additional equations for sigma, the load is simply the prescribed gradient. double rve_size = this->domainSize(); FloatArray stressLoad; FloatArray gradVoigt; giveGradientVoigt(gradVoigt); stressLoad.beScaled(-rve_size, gradVoigt); answer.assemble(stressLoad, sigma_loc); } else if ( type == InternalForcesVector ) { FloatMatrix Ke; FloatArray fe_v, fe_s; FloatArray sigmaHom, e_u; // Fetch the current values of the stress; mpSigmaHom->giveCompleteUnknownVector(sigmaHom, mode, tStep); // and the master dof ids for sigmadev used for the internal norms mpSigmaHom->giveCompleteMasterDofIDArray(sigmaMasterDofIDs); // Assemble for ( int pos = 1; pos <= boundaries.giveSize() / 2; ++pos ) { Element *e = this->giveDomain()->giveElement( boundaries.at(pos * 2 - 1) ); int boundary = boundaries.at(pos * 2); // Fetch the element information; e->giveLocationArray(loc, s, & masterDofIDs); // Here, we could use only the nodes actually located on the boundary, but we don't. // Instead, we use all nodes belonging to the element, which is allowed because the // basis functions related to the interior nodes will be zero on the boundary. // Obviously, this is less efficient, so why do we want to do it this way? // Because it is easier when XFEM enrichments are present. /ES e->computeVectorOf(mode, tStep, e_u); this->integrateTangent(Ke, e, boundary); // We just use the tangent, less duplicated code (the addition of sigmaDev is linear). fe_v.beProductOf(Ke, e_u); fe_s.beTProductOf(Ke, sigmaHom); // Note: The terms appear negative in the equations: fe_v.negated(); fe_s.negated(); answer.assemble(fe_s, loc); // Contributions to delta_v equations answer.assemble(fe_v, sigma_loc); // Contribution to delta_s_i equations if ( eNorm != NULL ) { eNorm->assembleSquared(fe_s, masterDofIDs); eNorm->assembleSquared(fe_v, sigmaMasterDofIDs); } } } }
void IntMatBilinearCZ :: giveFirstPKTraction_3d(FloatArray &answer, GaussPoint *gp, const FloatArray &jump, const FloatMatrix &F, TimeStep *tStep) { IntMatBilinearCZStatus *status = static_cast< IntMatBilinearCZStatus * >( this->giveStatus(gp) ); status->mJumpNew = jump; FloatArray jumpInc; jumpInc.beDifferenceOf(status->mJumpNew, status->mJumpOld); FloatArray tractionTrial = status->mTractionOld; tractionTrial.add(mPenaltyStiffness, jumpInc); double TTrNormal = tractionTrial.at(3); double TTrTang = sqrt( pow(tractionTrial.at(1), 2.0) + pow(tractionTrial.at(2), 2.0) ); double phiTr = computeYieldFunction(TTrNormal, TTrTang); const double damageTol = 1.0e-6; if ( status->mDamageOld > ( 1.0 - damageTol ) ) { status->mDamageNew = 1.0; status->mPlastMultIncNew = 0.0; answer.resize(3); answer.zero(); status->mTractionNew = answer; status->letTempJumpBe(jump); status->letTempFirstPKTractionBe(answer); status->letTempTractionBe(answer); return; } answer = tractionTrial; if ( phiTr < 0.0 ) { status->mDamageNew = status->mDamageOld; status->mPlastMultIncNew = 0.0; answer.beScaled( ( 1.0 - status->mDamageNew ), answer ); status->mTractionNew = answer; status->letTempJumpBe(jump); status->letTempFirstPKTractionBe(answer); status->letTempTractionBe(answer); return; } else { // Iterate to find plastic strain increment. int maxIter = 50; int minIter = 1; double absTol = 1.0e-9; // Absolute error tolerance double relTol = 1.0e-9; // Relative error tolerance double eps = 1.0e-12; // Small value for perturbation when computing numerical Jacobian double plastMultInc = 0.0; double initialRes = 0.0; for ( int iter = 0; iter < maxIter; iter++ ) { // Evaluate residual (i.e. yield function) computeTraction(answer, tractionTrial, plastMultInc); double TNormal = answer.at(3); double TTang = sqrt( pow(answer.at(1), 2.0) + pow(answer.at(2), 2.0) ); double phi = computeYieldFunction(TNormal, TTang); // if(iter > 20) { // printf("iter: %d res: %e\n", iter, fabs(phi) ); // } if ( iter == 0 ) { initialRes = fabs(phi); initialRes = max(initialRes, 1.0e-12); } if ( (iter >= minIter && fabs(phi) < absTol) || ( iter >= minIter && ( fabs(phi) / initialRes ) < relTol ) ) { // Add damage evolution double S = mGIc / mSigmaF; status->mPlastMultIncNew = plastMultInc; double damageInc = status->mPlastMultIncNew / S; status->mDamageNew = status->mDamageOld + damageInc; if ( status->mDamageNew > 1.0 ) { status->mDamageNew = 1.0; } if(mSemiExplicit) { // computeTraction(answer, tractionTrial, status->mPlastMultIncOld); answer.beScaled( ( 1.0 - status->mDamageOld ), answer ); } else { answer.beScaled( ( 1.0 - status->mDamageNew ), answer ); } status->mTractionNew = answer; // Jim status->letTempJumpBe(jump); status->letTempFirstPKTractionBe(answer); status->letTempTractionBe(answer); return; } // Numerical Jacobian FloatArray tractionPert(3); computeTraction(tractionPert, tractionTrial, plastMultInc + eps); double TNormalPert = tractionPert.at(3); double TTangPert = sqrt( pow(tractionPert.at(1), 2.0) + pow(tractionPert.at(2), 2.0) ); double phiPert = computeYieldFunction(TNormalPert, TTangPert); double Jac = ( phiPert - phi ) / eps; plastMultInc -= ( 1.0 / Jac ) * phi; } } OOFEM_ERROR("No convergence in."); }