void SimpleVitrificationMaterial :: giveRealStressVector_3d(FloatArray &answer, GaussPoint *gp, const FloatArray &reducedStrain, TimeStep *tStep) { FloatArray strainVector; FloatMatrix d; FloatArray deltaStrain; StructuralMaterialStatus *status = dynamic_cast< StructuralMaterialStatus * >( this->giveStatus(gp) ); this->giveStressDependentPartOfStrainVector(strainVector, gp, reducedStrain, tStep, VM_Total); deltaStrain.beDifferenceOf( strainVector, status->giveStrainVector() ); this->give3dMaterialStiffnessMatrix(d, TangentStiffness, gp, tStep); FloatArray deltaStress; deltaStress.beProductOf(d, deltaStrain); answer = status->giveStressVector(); answer.add(deltaStress); // update gp status->letTempStrainVectorBe(reducedStrain); status->letTempStressVectorBe(answer); }
void TutorialMaterial :: computeSphDevPartOf(const FloatArray &sigV, FloatArray &sigSph, FloatArray &sigDev) { double volumetricPart = ( sigV.at(1) + sigV.at(2) + sigV.at(3) ) / 3.0; sigSph = {volumetricPart, volumetricPart, volumetricPart, 0.0, 0.0, 0.0}; sigDev.beDifferenceOf(sigV, sigSph); }
void FE2FluidMaterial :: giveDeviatoricPressureStiffness(FloatArray &answer, MatResponseMode mode, GaussPoint *gp, TimeStep *tStep) { FE2FluidMaterialStatus *ms = static_cast<FE2FluidMaterialStatus*> (this->giveStatus(gp)); ms->computeTangents(tStep); if ( mode == TangentStiffness ) { answer = ms->giveDeviatoricPressureTangent(); #ifdef DEBUG_TANGENT // Numerical ATS for debugging FloatArray strain(3); strain.zero(); FloatArray sig, sigh; double epspvol, pressure = 0.0; double h = 1.00; // Linear problem, size of this doesn't matter. computeDeviatoricStressVector (sig, epspvol, gp, strain, pressure, tStep); computeDeviatoricStressVector (sigh, epspvol, gp, strain, pressure+h, tStep); FloatArray dsigh; dsigh.beDifferenceOf(sigh,sig); dsigh.times(1/h); printf("Analytical deviatoric pressure tangent = "); answer.printYourself(); printf("Numerical deviatoric pressure tangent = "); dsigh.printYourself(); dsigh.subtract(answer); double norm = dsigh.computeNorm(); if (norm > answer.computeNorm()*DEBUG_ERR && norm > 0.0) { OOFEM_ERROR("Error in deviatoric pressure tangent"); } #endif } else { OOFEM_ERROR("Mode not implemented"); } }
double Line :: computeTangentialDistanceToEnd(FloatArray *point) { FloatArray projection; this->computeProjection(projection); FloatArray tmp; tmp.beDifferenceOf(* point, mVertices [ 1 ]); return tmp.dotProduct(projection) / projection.computeNorm(); }
void PrescribedGradientBCWeak :: giveTractionElNormal(size_t iElInd, FloatArray &oNormal, FloatArray &oTangent) const { FloatArray xS, xE; giveTractionElCoord(iElInd, xS, xE); oTangent.beDifferenceOf(xE, xS); oTangent.normalize(); oNormal = { oTangent [ 1 ], -oTangent [ 0 ] }; }
void Line :: transformIntoPolar(FloatArray *point, FloatArray &answer) { FloatArray xp; FloatMatrix Qt; FloatArray help; this->computeTransformationMatrix(Qt); help.beDifferenceOf(* point, mVertices [ 1 ]); xp.beProductOf(Qt, help); answer.resize(2); answer.at(1) = xp.computeNorm(); answer.at(2) = atan2( xp.at(2), xp.at(1) ); }
void IntElPoint :: computeLocalSlipDir(FloatArray &normal) { normal.resizeWithValues(3); if ( this->referenceNode ) { // normal normal.beDifferenceOf(*domain->giveNode(this->referenceNode)->giveCoordinates(), *this->giveNode(1)->giveCoordinates()); } else { if ( normal.at(1) == 0 && normal.at(2) == 0 && normal.at(3) == 0 ) { OOFEM_ERROR("Normal is not defined (referenceNode=0,normal=(0,0,0))"); } } normal.normalize(); }
void TransportGradientPeriodic :: computeDofTransformation(ActiveDof *dof, FloatArray &masterContribs) { DofManager *master = this->domain->giveDofManager(this->slavemap[dof->giveDofManager()->giveNumber()]); FloatArray *coords = dof->giveDofManager()->giveCoordinates(); FloatArray *masterCoords = master->giveCoordinates(); FloatArray dx; dx.beDifferenceOf(* coords, * masterCoords ); masterContribs.resize(dx.giveSize() + 1); masterContribs.at(1) = 1.; // Master dof is always weight 1.0 for ( int i = 1; i <= dx.giveSize(); ++i ) { masterContribs.at(i+1) = dx.at(i); } }
void PrescribedGradientBCPeriodic :: findSlaveToMasterMap() { FloatArray coord; SpatialLocalizer *sl = this->domain->giveSpatialLocalizer(); //Set *masterSet = this->domain->giveSet(2); const IntArray &nodes = this->domain->giveSet(this->set)->giveNodeList(); // Split into slave set and master set? int nsd = jump.giveSize(); std :: vector< FloatArray > jumps; // Construct all the possible jumps; jumps.reserve((2 << (nsd-1)) - 1); if ( nsd != 3 ) { OOFEM_ERROR("Only 3d implemented yet!"); } jumps.emplace_back(jump); jumps.emplace_back(FloatArray{jump.at(1), jump.at(2), 0.}); jumps.emplace_back(FloatArray{jump.at(1), 0., jump.at(3)}); jumps.emplace_back(FloatArray{0., jump.at(2), jump.at(3)}); jumps.emplace_back(FloatArray{jump.at(1), 0., 0.}); jumps.emplace_back(FloatArray{0., jump.at(2), 0.}); jumps.emplace_back(FloatArray{0., 0., jump.at(3)}); this->slavemap.clear(); for ( int inode : nodes ) { Node *masterNode = NULL; Node *node = this->domain->giveNode(inode); const FloatArray &masterCoord = *node->giveCoordinates(); //printf("node %d\n", node->giveLabel()); masterCoord.printYourself(); // The difficult part, what offset to subtract to find the master side; for ( FloatArray &testJump : jumps ) { coord.beDifferenceOf(masterCoord, testJump); masterNode = sl->giveNodeClosestToPoint(coord, fabs(jump.at(1))*1e-5); if ( masterNode != NULL ) { //printf("Found master (%d) to node %d (distance = %e)\n", masterNode->giveNumber(), node->giveNumber(), // masterNode->giveCoordinates()->distance(coord)); break; } } if ( masterNode != NULL ) { this->slavemap.insert({node->giveNumber(), masterNode->giveNumber()}); } else { OOFEM_ERROR("Couldn't find master node!"); } } }
double FEI3dLineLin :: evaldNdx(FloatMatrix &answer, const FloatArray &lcoords, const FEICellGeometry &cellgeo) { ///@todo Not clear what this function should return. Just dNds would make sense if the caller defines a local coordinate system. FloatArray vec; vec.beDifferenceOf(*cellgeo.giveVertexCoordinates(2), *cellgeo.giveVertexCoordinates(1)); double detJ = vec.computeSquaredNorm() * 0.5; double l2_inv = 0.5 / detJ; answer.resize(2, 3); answer.at(1, 1) = -vec.at(1)*l2_inv; answer.at(2, 1) = vec.at(1)*l2_inv; answer.at(1, 2) = -vec.at(2)*l2_inv; answer.at(2, 2) = vec.at(2)*l2_inv; answer.at(1, 3) = -vec.at(3)*l2_inv; answer.at(2, 3) = vec.at(3)*l2_inv; return detJ; }
void StructuralFE2Material :: give3dMaterialStiffnessMatrix(FloatMatrix &answer, MatResponseMode mode, GaussPoint *gp, TimeStep *tStep) { if ( useNumTangent ) { // Numerical tangent StructuralFE2MaterialStatus *status = static_cast<StructuralFE2MaterialStatus*>( this->giveStatus( gp ) ); double h = 1.0e-9; const FloatArray &epsRed = status->giveTempStrainVector(); FloatArray eps; StructuralMaterial::giveFullSymVectorForm(eps, epsRed, gp->giveMaterialMode() ); int dim = eps.giveSize(); answer.resize(dim, dim); answer.zero(); FloatArray sig, sigPert, epsPert; for(int i = 1; i <= dim; i++) { // Add a small perturbation to the strain epsPert = eps; epsPert.at(i) += h; giveRealStressVector_3d(sigPert, gp, epsPert, tStep); answer.setColumn(sigPert, i); } giveRealStressVector_3d(sig, gp, eps, tStep); for(int i = 1; i <= dim; i++) { for(int j = 1; j <= dim; j++) { answer.at(j,i) -= sig.at(j); answer.at(j,i) /= h; } } } else { StructuralFE2MaterialStatus *ms = static_cast< StructuralFE2MaterialStatus * >( this->giveStatus(gp) ); ms->computeTangent(tStep); const FloatMatrix &ans9 = ms->giveTangent(); StructuralMaterial::giveReducedSymMatrixForm(answer, ans9, _3dMat); // const FloatMatrix &ans9 = ms->giveTangent(); // printf("ans9: "); ans9.printYourself(); // // // Compute the (minor) symmetrized tangent: // answer.resize(6, 6); // for ( int i = 0; i < 6; ++i ) { // for ( int j = 0; j < 6; ++j ) { // answer(i, j) = ans9(i, j); // } // } // for ( int i = 0; i < 6; ++i ) { // for ( int j = 6; j < 9; ++j ) { // answer(i, j-3) += ans9(i, j); // answer(j-3, i) += ans9(j, i); // } // } // for ( int i = 6; i < 9; ++i ) { // for ( int j = 6; j < 9; ++j ) { // answer(j-3, i-3) += ans9(j, i); // } // } // for ( int i = 0; i < 6; ++i ) { // for ( int j = 3; j < 6; ++j ) { // answer(j, i) *= 0.5; // answer(i, j) *= 0.5; // } // } #if 0 // Numerical ATS for debugging FloatMatrix numericalATS(6, 6); FloatArray dsig; // Note! We need a copy of the temp strain, since the pertubations might change it. FloatArray tempStrain = ms->giveTempStrainVector(); FloatArray sig, strain, sigPert; giveRealStressVector_3d(sig, gp, tempStrain, tStep); double hh = 1e-6; for ( int k = 1; k <= 6; ++k ) { strain = tempStrain; strain.at(k) += hh; giveRealStressVector_3d(sigPert, gp, strain, tStep); dsig.beDifferenceOf(sigPert, sig); numericalATS.setColumn(dsig, k); } numericalATS.times(1. / hh); giveRealStressVector_3d(sig, gp, tempStrain, tStep); // Reset //answer.printYourself("Analytical deviatoric tangent"); //numericalATS.printYourself("Numerical deviatoric tangent"); numericalATS.subtract(answer); double norm = numericalATS.computeFrobeniusNorm(); if ( norm > answer.computeFrobeniusNorm() * 1e-3 && norm > 0.0 ) { OOFEM_ERROR("Error in deviatoric tangent"); } #endif } }
void MisesMat :: giveFirstPKStressVector_3d(FloatArray &answer, GaussPoint *gp, const FloatArray &totalDefGradOOFEM, TimeStep *tStep) { MisesMatStatus *status = static_cast< MisesMatStatus * >( this->giveStatus(gp) ); double kappa, dKappa, yieldValue, mi; FloatMatrix F, oldF, invOldF; FloatArray s; F.beMatrixForm(totalDefGradOOFEM); //(method assumes full 3D) kappa = status->giveCumulativePlasticStrain(); oldF.beMatrixForm( status->giveFVector() ); invOldF.beInverseOf(oldF); //relative deformation radient FloatMatrix f; f.beProductOf(F, invOldF); //compute elastic predictor FloatMatrix trialLeftCauchyGreen, help; f.times( 1./cbrt(f.giveDeterminant()) ); help.beProductOf(f, status->giveTempLeftCauchyGreen()); trialLeftCauchyGreen.beProductTOf(help, f); FloatMatrix E; E.beTProductOf(F, F); E.at(1, 1) -= 1.0; E.at(2, 2) -= 1.0; E.at(3, 3) -= 1.0; E.times(0.5); FloatArray e; e.beSymVectorFormOfStrain(E); FloatArray leftCauchyGreen; FloatArray leftCauchyGreenDev; double leftCauchyGreenVol; leftCauchyGreen.beSymVectorFormOfStrain(trialLeftCauchyGreen); leftCauchyGreenVol = computeDeviatoricVolumetricSplit(leftCauchyGreenDev, leftCauchyGreen); FloatArray trialStressDev; applyDeviatoricElasticStiffness(trialStressDev, leftCauchyGreenDev, G / 2.); s = trialStressDev; //check for plastic loading double trialS = computeStressNorm(trialStressDev); double sigmaY = sig0 + H * kappa; //yieldValue = sqrt(3./2.)*trialS-sigmaY; yieldValue = trialS - sqrt(2. / 3.) * sigmaY; //store deviatoric trial stress(reused by algorithmic stiffness) status->letTrialStressDevBe(trialStressDev); //the return-mapping algorithm double J = F.giveDeterminant(); mi = leftCauchyGreenVol * G; if ( yieldValue > 0 ) { //dKappa =sqrt(3./2.)* yieldValue/(H + 3.*mi); //kappa = kappa + dKappa; //trialStressDev.times(1-sqrt(6.)*mi*dKappa/trialS); dKappa = ( yieldValue / ( 2 * mi ) ) / ( 1 + H / ( 3 * mi ) ); FloatArray n = trialStressDev; n.times(2 * mi * dKappa / trialS); ////return map s.beDifferenceOf(trialStressDev, n); kappa += sqrt(2. / 3.) * dKappa; //update of intermediate configuration trialLeftCauchyGreen.beMatrixForm(s); trialLeftCauchyGreen.times(1.0 / G); trialLeftCauchyGreen.at(1, 1) += leftCauchyGreenVol; trialLeftCauchyGreen.at(2, 2) += leftCauchyGreenVol; trialLeftCauchyGreen.at(2, 2) += leftCauchyGreenVol; trialLeftCauchyGreen.times(J * J); } //addition of the elastic mean stress FloatMatrix kirchhoffStress; kirchhoffStress.beMatrixForm(s); kirchhoffStress.at(1, 1) += 1. / 2. * K * ( J * J - 1 ); kirchhoffStress.at(2, 2) += 1. / 2. * K * ( J * J - 1 ); kirchhoffStress.at(3, 3) += 1. / 2. * K * ( J * J - 1 ); FloatMatrix iF, Ep(3, 3), S; FloatArray vF, vS, ep; //transform Kirchhoff stress into Second Piola - Kirchhoff stress iF.beInverseOf(F); help.beProductOf(iF, kirchhoffStress); S.beProductTOf(help, iF); this->computeGLPlasticStrain(F, Ep, trialLeftCauchyGreen, J); ep.beSymVectorFormOfStrain(Ep); vS.beSymVectorForm(S); vF.beVectorForm(F); answer.beVectorForm(kirchhoffStress); status->setTrialStressVol(mi); status->letTempLeftCauchyGreenBe(trialLeftCauchyGreen); status->setTempCumulativePlasticStrain(kappa); status->letTempStressVectorBe(answer); status->letTempStrainVectorBe(e); status->letTempPlasticStrainBe(ep); status->letTempPVectorBe(answer); status->letTempFVectorBe(vF); }
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 FE2FluidMaterial :: giveStiffnessMatrices(FloatMatrix &dsdd, FloatArray &dsdp, FloatArray &dedd, double &dedp, MatResponseMode mode, GaussPoint *gp, TimeStep *tStep) { FE2FluidMaterialStatus *ms = static_cast< FE2FluidMaterialStatus * >( this->giveStatus(gp) ); ms->computeTangents(tStep); if ( mode == TangentStiffness ) { dsdd = ms->giveDeviatoricTangent(); dsdp = ms->giveDeviatoricPressureTangent(); dedd = ms->giveVolumetricDeviatoricTangent(); dedp = ms->giveVolumetricPressureTangent(); #if 0 // Numerical ATS for debugging FloatMatrix numericalATS(6, 6); FloatArray dsig; FloatArray tempStrain(6); tempStrain.zero(); FloatArray sig, strain, sigPert; double epspvol; computeDeviatoricStressVector(sig, epspvol, gp, tempStrain, 0., tStep); double h = 0.001; // Linear problem, size of this doesn't matter. for ( int k = 1; k <= 6; ++k ) { strain = tempStrain; strain.at(k) += h; double tmp = strain.at(1) + strain.at(2) + strain.at(3); strain.at(1) -= tmp/3.0; strain.at(2) -= tmp/3.0; strain.at(3) -= tmp/3.0; strain.printYourself(); computeDeviatoricStressVector(sigPert, epspvol, gp, strain, 0., tStep); sigPert.printYourself(); dsig.beDifferenceOf(sigPert, sig); numericalATS.setColumn(dsig, k); } numericalATS.times(1. / h); printf("Analytical deviatoric tangent = "); dsdd.printYourself(); printf("Numerical deviatoric tangent = "); numericalATS.printYourself(); numericalATS.subtract(dsdd); double norm = numericalATS.computeFrobeniusNorm(); if ( norm > dsdd.computeFrobeniusNorm() * DEBUG_ERR && norm > 0.0 ) { OOFEM_ERROR("Error in deviatoric tangent"); } #endif #if 0 // Numerical ATS for debugging FloatArray strain(3); strain.zero(); FloatArray sig, sigh; double epspvol, pressure = 0.0; double h = 1.00; // Linear problem, size of this doesn't matter. computeDeviatoricStressVector(sig, epspvol, gp, strain, pressure, tStep); computeDeviatoricStressVector(sigh, epspvol, gp, strain, pressure + h, tStep); FloatArray dsigh; dsigh.beDifferenceOf(sigh, sig); dsigh.times(1 / h); printf("Analytical deviatoric pressure tangent = "); dsdp.printYourself(); printf("Numerical deviatoric pressure tangent = "); dsigh.printYourself(); dsigh.subtract(dsdp); double norm = dsigh.computeNorm(); if ( norm > dsdp.computeNorm() * DEBUG_ERR && norm > 0.0 ) { OOFEM_ERROR("Error in deviatoric pressure tangent"); } #endif #if 0 // Numerical ATS for debugging FloatArray tempStrain(3); tempStrain.zero(); FloatArray sig, strain; double epspvol, epspvol11, epspvol22, epspvol12, pressure = 0.0; double h = 1.0; // Linear problem, size of this doesn't matter. computeDeviatoricStressVector(sig, epspvol, gp, tempStrain, pressure, tStep); strain = tempStrain; strain.at(1) += h; computeDeviatoricStressVector(sig, epspvol11, gp, strain, pressure, tStep); strain = tempStrain; strain.at(2) += h; computeDeviatoricStressVector(sig, epspvol22, gp, strain, pressure, tStep); strain = tempStrain; strain.at(3) += h; computeDeviatoricStressVector(sig, epspvol12, gp, strain, pressure, tStep); FloatArray dvol(3); dvol.at(1) = ( epspvol11 - epspvol ) / h; dvol.at(2) = ( epspvol22 - epspvol ) / h; dvol.at(3) = ( epspvol12 - epspvol ) / h; dvol.at(1) += 1.0; dvol.at(2) += 1.0; printf("Analytical volumetric deviatoric tangent = "); dedd.printYourself(); printf("Numerical volumetric deviatoric tangent = "); dvol.printYourself(); dvol.subtract(dedd); double norm = dvol.computeNorm(); if ( norm > dedd.computeNorm() * DEBUG_ERR && norm > 0.0 ) { OOFEM_ERROR("Error in volumetric deviatoric tangent"); } #endif #if 0 // Numerical ATS for debugging FloatArray strain(3); strain.zero(); FloatArray sig; double epspvol, epspvolh, pressure = 0.0; double h = 1.0; // Linear problem, size of this doesn't matter. computeDeviatoricStressVector(sig, epspvol, gp, strain, pressure, tStep); computeDeviatoricStressVector(sig, epspvolh, gp, strain, pressure + h, tStep); double dvol = -( epspvolh - epspvol ) / h; printf("Analytical volumetric pressure tangent = %e\n", dedp); printf("Numerical volumetric pressure tangent = %e\n", dvol); double norm = fabs(dvol - dedp); if ( norm > fabs(dedp) * DEBUG_ERR && norm > 0.0 ) { OOFEM_ERROR("Error in volumetric pressure tangent"); } #endif } else { OOFEM_ERROR("Mode not implemented"); } }
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."); }
NM_Status DynamicRelaxationSolver :: solve(SparseMtrx &k, FloatArray &R, FloatArray *R0, FloatArray *iR, FloatArray &X, FloatArray &dX, FloatArray &F, const FloatArray &internalForcesEBENorm, double &l, referenceLoadInputModeType rlm, int &nite, TimeStep *tStep) { // residual, iteration increment of solution, total external force FloatArray rhs, ddX, RT, X_0, X_n, X_n1, M; double RRT; int neq = X.giveSize(); NM_Status status = NM_None; bool converged, errorOutOfRangeFlag; ParallelContext *parallel_context = engngModel->giveParallelContext( this->domain->giveNumber() ); if ( engngModel->giveProblemScale() == macroScale ) { OOFEM_LOG_INFO("DRSolver: Iteration"); if ( rtolf.at(1) > 0.0 ) { OOFEM_LOG_INFO(" ForceError"); } if ( rtold.at(1) > 0.0 ) { OOFEM_LOG_INFO(" DisplError"); } OOFEM_LOG_INFO("\n----------------------------------------------------------------------------\n"); } // compute total load R = R+R0 l = 1.0; RT = R; if ( R0 ) { RT.add(* R0); } RRT = parallel_context->localNorm(RT); RRT *= RRT; ddX.resize(neq); ddX.zero(); X_0 = X; X_n = X_0; X_n1 = X_0; // Compute the mass "matrix" (lumped, only storing the diagonal) M.resize(neq); M.zero(); engngModel->assembleVector(M, tStep, LumpedMassVectorAssembler(), VM_Total, EModelDefaultEquationNumbering(), domain); double Le = -1.0; for ( auto &elem : domain->giveElements() ) { double size = elem->computeMeanSize(); if ( Le < 0 || Le >= size ) { Le = size; } } for ( nite = 0; ; ++nite ) { // Compute the residual engngModel->updateComponent(tStep, InternalRhs, domain); rhs.beDifferenceOf(RT, F); converged = this->checkConvergence(RT, F, rhs, ddX, X, RRT, internalForcesEBENorm, nite, errorOutOfRangeFlag); if ( errorOutOfRangeFlag ) { status = NM_NoSuccess; dX.zero(); X.zero(); OOFEM_WARNING("Divergence reached after %d iterations", nite); break; } else if ( converged && ( nite >= minIterations ) ) { status |= NM_Success; break; } else if ( nite >= nsmax ) { OOFEM_LOG_DEBUG("Maximum number of iterations reached\n"); break; } double density = 1.; double lambda = 210e9; double mu = 210e9; double c = sqrt((lambda + 2*mu) / density); double dt = 0.25 * Le / c; double alpha = 0.1 / dt; printf("dt = %e\n", dt); for ( int j = 0; j < neq; ++j ) { //M * x'' + C*x' * dt = rhs * dt*dt X[j] = rhs[j] * dt * dt / M[j] - ( -2*X_n1[j] + X_n[j] ) - alpha * (X_n1[j] - X_n[j]) * dt; } X_n = X_n1; X_n1 = X; dX.beDifferenceOf(X, X_0); tStep->incrementStateCounter(); // update solution state counter tStep->incrementSubStepNumber(); } return status; }
void TutorialMaterial :: giveRealStressVector_3d(FloatArray &answer, GaussPoint *gp, const FloatArray &totalStrain, TimeStep *tStep) { FloatArray strain; TutorialMaterialStatus *status = static_cast< TutorialMaterialStatus * >( this->giveStatus(gp) ); // subtract stress thermal expansion this->giveStressDependentPartOfStrainVector_3d(strain, gp, totalStrain, tStep, VM_Total); FloatArray trialElastStrain; trialElastStrain.beDifferenceOf(strain, status->givePlasticStrain()); // Compute trial stress = sig_tr = sig_old + E*delta_eps FloatMatrix elasticStiffness; D.give3dMaterialStiffnessMatrix(elasticStiffness, TangentStiffness, gp, tStep); FloatArray trialStress; trialStress.beProductOf(elasticStiffness, trialElastStrain); FloatArray sphTrialStress, devTrialStress; computeSphDevPartOf(trialStress, sphTrialStress, devTrialStress); double J2 = this->computeSecondStressInvariant(devTrialStress); double effectiveTrialStress = sqrt(3 * J2); #if 1 double temperatureScaling = 1.0; #else double temperature; FloatArray et; static_cast< StructuralElement *>(gp->giveIntegrationRule()->giveElement())->computeResultingIPTemperatureAt(et, tStep, gp, VM_Total); temperature = et.at(1) + 800; double temperatureScaling = temperature <= 400 ? 1.0 : 1.0 - (temperature - 400) * 0.5 / 400; #endif // evaluate the yield surface double k = status->giveK(); double phiTrial = effectiveTrialStress - ( temperatureScaling * this->sig0 + temperatureScaling * H * k ); if ( phiTrial < 0.0 ) { // elastic answer = trialStress; status->letTempPlasticStrainBe(status->givePlasticStrain()); } else { // plastic loading double G = D.giveShearModulus(); double mu = phiTrial / ( 3.0 * G + temperatureScaling * H ); // plastic multiplier answer = devTrialStress * ( 1.0 - 3.0*G*mu/effectiveTrialStress); // radial return answer.add(sphTrialStress); k += mu; FloatArray plasticStrain = status->givePlasticStrain(); FloatArray dPlStrain; applyDeviatoricElasticCompliance(dPlStrain, devTrialStress, 0.5); plasticStrain.add(mu * 3. / (2. * effectiveTrialStress), dPlStrain); status->letTempPlasticStrainBe(plasticStrain); } // Store the temporary values for the given iteration status->letTempStrainVectorBe(totalStrain); status->letTempStressVectorBe(answer); status->letTempKBe(k); status->letTempDevTrialStressBe(devTrialStress); }
void PlasticMaterial :: giveRealStressVector(FloatArray &answer, GaussPoint *gp, const FloatArray &totalStrain, 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 // // completely formulated in Reduced stress-strain space { FloatArray strainSpaceHardeningVariables; FloatArray fullStressVector, *fullStressSpaceHardeningVars, *residualVectorR; FloatArray elasticStrainVectorR; FloatArray strainVectorR, plasticStrainVectorR, *gradientVectorR; FloatArray helpVec, helpVec2; double yieldValue, Gamma, dGamma, helpVal1, helpVal2; int strSize, totSize, nIterations = 0; FloatMatrix elasticModuli, hardeningModuli, consistentModuli; FloatMatrix elasticModuliInverse, hardeningModuliInverse; FloatMatrix helpMtrx, helpMtrx2; PlasticMaterialStatus *status = static_cast< PlasticMaterialStatus * >( this->giveStatus(gp) ); this->initTempStatus(gp); // subtract stress independent part // note: eigenStrains (temperature) is not contained in mechanical strain stored in gp // therefore it is necessary to subtract always the total eigen strain value this->giveStressDependentPartOfStrainVector(strainVectorR, gp, totalStrain, tStep, VM_Total); plasticStrainVectorR = status->givePlasticStrainVector(); strainSpaceHardeningVariables = status->giveStrainSpaceHardeningVars(); // tady konec debugovani - strainSpaceHardeningVariables ve statusu neinicializovany // to musi udelat material. Gamma = 0.; strSize = strainVectorR.giveSize(); // size of reducedStrain Vector totSize = strSize + strainSpaceHardeningVariables.giveSize(); // compute elastic moduli and its inverse this->computeReducedElasticModuli(elasticModuli, gp, tStep); elasticModuliInverse.beInverseOf(elasticModuli); do { elasticStrainVectorR.beDifferenceOf(strainVectorR, plasticStrainVectorR); // stress vector in full form due to computational convenience this->computeTrialStressIncrement(fullStressVector, gp, elasticStrainVectorR, tStep); fullStressSpaceHardeningVars = this->ComputeStressSpaceHardeningVars(gp, & strainSpaceHardeningVariables); yieldValue = this->computeYieldValueAt(gp, & fullStressVector, fullStressSpaceHardeningVars); gradientVectorR = this->ComputeGradientVector(gp, & fullStressVector, fullStressSpaceHardeningVars); residualVectorR = this->ComputeResidualVector(gp, Gamma, & plasticStrainVectorR, & strainSpaceHardeningVariables, gradientVectorR); // check for end of iteration if ( ( yieldValue < YIELD_TOL ) && ( residualVectorR->computeNorm() < RES_TOL ) ) { delete fullStressSpaceHardeningVars; delete gradientVectorR; delete residualVectorR; break; } // compute consistent tangent moduli this->computeHardeningReducedModuli(hardeningModuli, gp, & strainSpaceHardeningVariables, tStep); if ( hardeningModuli.giveNumberOfRows() ) { hardeningModuliInverse.beInverseOf(hardeningModuli); } else { hardeningModuliInverse.clear(); } this->computeConsistentModuli(consistentModuli, gp, elasticModuliInverse, hardeningModuliInverse, Gamma, fullStressVector, * fullStressSpaceHardeningVars); // obtain increment to consistency parameter helpMtrx.initFromVector(* gradientVectorR, 1); helpMtrx2.beProductOf(helpMtrx, consistentModuli); helpVec.beProductOf(helpMtrx2, * gradientVectorR); helpVal1 = helpVec.at(1); helpVec.beProductOf(helpMtrx2, * residualVectorR); helpVal2 = helpVec.at(1); dGamma = ( yieldValue - helpVal2 ) / helpVal1; // obtain incremental plastic strains and internal variables // we overwrite residualVectorR and gradientVectorR vectors // but they are computed once again when iteration continues gradientVectorR->times(dGamma); residualVectorR->add(* gradientVectorR); helpVec.beProductOf(consistentModuli, * residualVectorR); // note elasticModuli and hardeningModuli are yet inverted this->computeDiagModuli(helpMtrx, gp, elasticModuliInverse, hardeningModuliInverse); helpVec2.beProductOf(helpMtrx, helpVec); // Update state variables and consistency parameter for ( int i = 1; i <= strSize; i++ ) { plasticStrainVectorR.at(i) += helpVec2.at(i); } for ( int i = strSize + 1; i <= totSize; i++ ) { strainSpaceHardeningVariables.at(i - strSize) += helpVec2.at(i); } Gamma += dGamma; // increment iteration count nIterations++; // free allocated memory inside loop delete fullStressSpaceHardeningVars; delete gradientVectorR; delete residualVectorR; if ( nIterations > PLASTIC_MATERIAL_MAX_ITERATIONS ) { OOFEM_WARNING("local equlibrium not reached in %d iterations\nElement %d, gp %d, continuing", PLASTIC_MATERIAL_MAX_ITERATIONS, gp->giveElement()->giveNumber(), gp->giveNumber() ); break; } } while ( 1 ); // update temp state variables in gp and associted material status status->letTempStrainVectorBe(totalStrain); StructuralMaterial :: giveReducedSymVectorForm( helpVec, fullStressVector, gp->giveMaterialMode() ); status->letTempStressVectorBe(helpVec); status->letTempPlasticStrainVectorBe(plasticStrainVectorR); status->letTempStrainSpaceHardeningVarsVectorBe(strainSpaceHardeningVariables); // update plastic consistency parameter status->letTempPlasticConsistencyPrameterBe(Gamma); // update state flag int newState, state = status->giveStateFlag(); if ( Gamma > 0. ) { newState = PM_Yielding; // test if plastic loading occur } // no plastic loading - check for unloading else if ( ( state == PM_Yielding ) || ( state == PM_Unloading ) ) { newState = PM_Unloading; } else { newState = PM_Elastic; } status->letTempStateFlagBe(newState); answer = status->giveTempStressVector(); }
void PolygonLine :: computeNormalSignDist(double &oDist, const FloatArray &iPoint) const { const FloatArray &point = {iPoint[0], iPoint[1]}; oDist = std :: numeric_limits< double > :: max(); int numSeg = this->giveNrVertices() - 1; // TODO: This can probably be done in a nicer way. // Ensure that we work in 2d. const int dim = 2; for ( int segId = 1; segId <= numSeg; segId++ ) { // Crack segment const FloatArray &crackP1( this->giveVertex ( segId ) ); const FloatArray &crackP2( this->giveVertex ( segId + 1 ) ); double dist2 = 0.0; if ( segId == 1 ) { // Vector from start P1 to point X FloatArray u = {point.at(1) - crackP1.at(1), point.at(2) - crackP1.at(2)}; // Line tangent vector FloatArray t = {crackP2.at(1) - crackP1.at(1), crackP2.at(2) - crackP1.at(2)}; double l2 = t.computeSquaredNorm(); if ( l2 > 0.0 ) { double l = t.normalize(); double s = dot(u, t); if ( s > l ) { // X is closest to P2 dist2 = point.distance_square(crackP2); } else { double xi = s / l; FloatArray q = ( 1.0 - xi ) * crackP1 + xi * crackP2; dist2 = point.distance_square(q); } } else { // If the points P1 and P2 coincide, // we can compute the distance to any // of these points. dist2 = point.distance_square(crackP1); } } else if ( segId == numSeg ) { // Vector from start P1 to point X FloatArray u = {point.at(1) - crackP1.at(1), point.at(2) - crackP1.at(2)}; // Line tangent vector FloatArray t = {crackP2.at(1) - crackP1.at(1), crackP2.at(2) - crackP1.at(2)}; double l2 = t.computeSquaredNorm(); if ( l2 > 0.0 ) { double l = t.normalize(); double s = dot(u, t); if ( s < 0.0 ) { // X is closest to P1 dist2 = point.distance_square(crackP1); } else { double xi = s / l; FloatArray q = ( 1.0 - xi ) * crackP1 + xi * crackP2; dist2 = point.distance_square(q); } } else { // If the points P1 and P2 coincide, // we can compute the distance to any // of these points. dist2 = point.distance_square(crackP1); } } else { double arcPos = -1.0, dummy; dist2 = point.distance_square(crackP1, crackP2, arcPos, dummy); } if ( dist2 < oDist*oDist ) { FloatArray lineToP; lineToP.beDifferenceOf(point, crackP1, dim); FloatArray t; t.beDifferenceOf(crackP2, crackP1, dim); FloatArray n = {-t.at(2), t.at(1)}; oDist = sgn( lineToP.dotProduct(n) ) * sqrt(dist2); } } }
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 AbaqusUserMaterial :: giveRealStressVector(FloatArray &answer, MatResponseForm form, GaussPoint *gp, const FloatArray &reducedStrain, TimeStep *tStep) { AbaqusUserMaterialStatus *ms = static_cast< AbaqusUserMaterialStatus * >( this->giveStatus(gp) ); /* User-defined material name, left justified. Some internal material models are given names starting with * the “ABQ_” character string. To avoid conflict, you should not use “ABQ_” as the leading string for * CMNAME. */ //char cmname[80]; MaterialMode mMode = gp->giveMaterialMode(); // Sizes of the tensors. int ndi; int nshr; ///@todo Check how to deal with large deformations. ///@todo Check order of entries in the Voigt notation (which order does Abaqus use? convert to that). if ( mMode == _3dMat ) { ndi = 3; nshr = 3; } else if ( mMode == _PlaneStress ) { ndi = 2; nshr = 1; } else if ( mMode == _PlaneStrain ) { ndi = 3; nshr = 1; } /*else if ( mMode == _3dMat_F ) { * ndi = 3; * nshr = 6; * } */ else if ( mMode == _1dMat ) { ndi = 1; nshr = 0; } else { ndi = nshr = 0; OOFEM_ERROR2( "AbaqusUserMaterial :: giveRealStressVector : unsupported material mode (%s)", __MaterialModeToString(mMode) ); } int ntens = ndi + nshr; FloatArray stress(ntens); FloatArray strain = ms->giveStrainVector(); FloatArray strainIncrement; strainIncrement.beDifferenceOf(reducedStrain, strain); FloatArray state = ms->giveStateVector(); FloatMatrix jacobian(ntens, ntens); int numProperties = this->properties.giveSize(); // Temperature and increment double temp = 0.0, dtemp = 0.0; // Times and increment double dtime = tStep->giveTimeIncrement(); ///@todo Check this. I'm just guessing. Maybe intrinsic time instead? double time [ 2 ] = { tStep->giveTargetTime() - dtime, tStep->giveTargetTime() }; double pnewdt = 1.0; ///@todo Right default value? umat routines may change this (although we ignore it) /* Specific elastic strain energy, plastic dissipation, and “creep” dissipation, respectively. These are passed * in as the values at the start of the increment and should be updated to the corresponding specific energy * values at the end of the increment. They have no effect on the solution, except that they are used for * energy output. */ double sse, spd, scd; // Outputs only in a fully coupled thermal-stress analysis: double rpl = 0.0; // Volumetric heat generation per unit time at the end of the increment caused by mechanical working of the material. FloatArray ddsddt(ntens); // Variation of the stress increments with respect to the temperature. FloatArray drplde(ntens); // Variation of RPL with respect to the strain increments. double drpldt = 0.0; // Variation of RPL with respect to the temperature. /* An array containing the coordinates of this point. These are the current coordinates if geometric * nonlinearity is accounted for during the step (see “Procedures: overview,” Section 6.1.1); otherwise, * the array contains the original coordinates of the point */ FloatArray coords; gp->giveElement()->computeGlobalCoordinates( coords, * gp->giveCoordinates() ); ///@todo Large deformations? /* Rotation increment matrix. This matrix represents the increment of rigid body rotation of the basis * system in which the components of stress (STRESS) and strain (STRAN) are stored. It is provided so * that vector- or tensor-valued state variables can be rotated appropriately in this subroutine: stress and * strain components are already rotated by this amount before UMAT is called. This matrix is passed in * as a unit matrix for small-displacement analysis and for large-displacement analysis if the basis system * for the material point rotates with the material (as in a shell element or when a local orientation is used).*/ FloatMatrix drot(3, 3); drot.beUnitMatrix(); /* Characteristic element length, which is a typical length of a line across an element for a first-order * element; it is half of the same typical length for a second-order element. For beams and trusses it is a * characteristic length along the element axis. For membranes and shells it is a characteristic length in * the reference surface. For axisymmetric elements it is a characteristic length in the * plane only. * For cohesive elements it is equal to the constitutive thickness.*/ double celent = 0.0; /// @todo Include the characteristic element length /* Array containing the deformation gradient at the beginning of the increment. See the discussion * regarding the availability of the deformation gradient for various element types. */ FloatMatrix dfgrd0(3, 3); /* Array containing the deformation gradient at the end of the increment. The components of this array * are set to zero if nonlinear geometric effects are not included in the step definition associated with * this increment. See the discussion regarding the availability of the deformation gradient for various * element types. */ FloatMatrix dfgrd1(3, 3); int noel = gp->giveElement()->giveNumber(); // Element number. int npt = 0; // Integration point number. int layer = 0; // Layer number (for composite shells and layered solids).. int kspt = 0.0; // Section point number within the current layer. int kstep = 0; // Step number. int kinc = 0; // Increment number. ///@todo No idea about these parameters double predef; double dpred; OOFEM_LOG_DEBUG("AbaqusUserMaterial :: giveRealStressVector - Calling subroutine"); this->umat(stress.givePointer(), // STRESS state.givePointer(), // STATEV jacobian.givePointer(), // DDSDDE & sse, // SSE & spd, // SPD & scd, // SCD & rpl, // RPL ddsddt.givePointer(), // DDSDDT drplde.givePointer(), // DRPLDE & drpldt, // DRPLDT strain.givePointer(), // STRAN strainIncrement.givePointer(), // DSTRAN time, // TIME & dtime, // DTIME & temp, // TEMP & dtemp, // DTEMP & predef, // PREDEF & dpred, // DPRED this->cmname, // CMNAME & ndi, // NDI & nshr, // NSHR & ntens, // NTENS & numState, // NSTATV properties.givePointer(), // PROPS & numProperties, // NPROPS coords.givePointer(), // COORDS drot.givePointer(), // DROT & pnewdt, // PNEWDT & celent, // CELENT dfgrd0.givePointer(), // DFGRD0 dfgrd1.givePointer(), // DFGRD1 & noel, // NOEL & npt, // NPT & layer, // LAYER & kspt, // KSPT & kstep, // KSTEP & kinc); // KINC ms->letTempStrainVectorBe(reducedStrain); ms->letTempStressVectorBe(stress); ms->letTempStateVectorBe(state); ms->letTempTangentBe(jacobian); answer = stress; OOFEM_LOG_DEBUG("AbaqusUserMaterial :: giveRealStressVector - Calling subroutine was successful"); }
void AbaqusUserMaterial :: giveFirstPKStressVector_3d(FloatArray &answer, GaussPoint *gp, const FloatArray &vF, TimeStep *tStep) { AbaqusUserMaterialStatus *ms = static_cast< AbaqusUserMaterialStatus * >( this->giveStatus(gp) ); /* User-defined material name, left justified. Some internal material models are given names starting with * the “ABQ_” character string. To avoid conflict, you should not use “ABQ_” as the leading string for * CMNAME. */ //char cmname[80]; // Sizes of the tensors. int ndi = 3; int nshr = 3; int ntens = ndi + nshr; FloatArray stress(9); // PK1 FloatArray strainIncrement; // compute Green-Lagrange strain FloatArray strain; FloatArray vS; FloatMatrix F, E; F.beMatrixForm(vF); E.beTProductOf(F, F); E.at(1, 1) -= 1.0; E.at(2, 2) -= 1.0; E.at(3, 3) -= 1.0; E.times(0.5); strain.beSymVectorFormOfStrain(E); strainIncrement.beDifferenceOf(strain, ms->giveStrainVector()); FloatArray state = ms->giveStateVector(); FloatMatrix jacobian(9, 9); // dPdF int numProperties = this->properties.giveSize(); // Temperature and increment double temp = 0.0, dtemp = 0.0; // Times and increment double dtime = tStep->giveTimeIncrement(); ///@todo Check this. I'm just guessing. Maybe intrinsic time instead? double time [ 2 ] = { tStep->giveTargetTime() - dtime, tStep->giveTargetTime() }; double pnewdt = 1.0; ///@todo Right default value? umat routines may change this (although we ignore it) /* Specific elastic strain energy, plastic dissipation, and “creep” dissipation, respectively. These are passed * in as the values at the start of the increment and should be updated to the corresponding specific energy * values at the end of the increment. They have no effect on the solution, except that they are used for * energy output. */ double sse, spd, scd; // Outputs only in a fully coupled thermal-stress analysis: double rpl = 0.0; // Volumetric heat generation per unit time at the end of the increment caused by mechanical working of the material. FloatArray ddsddt(ntens); // Variation of the stress increments with respect to the temperature. FloatArray drplde(ntens); // Variation of RPL with respect to the strain increments. double drpldt = 0.0; // Variation of RPL with respect to the temperature. /* An array containing the coordinates of this point. These are the current coordinates if geometric * nonlinearity is accounted for during the step (see “Procedures: overview,” Section 6.1.1); otherwise, * the array contains the original coordinates of the point */ FloatArray coords; gp->giveElement()->computeGlobalCoordinates( coords, gp->giveNaturalCoordinates() ); ///@todo Large deformations? /* Rotation increment matrix. This matrix represents the increment of rigid body rotation of the basis * system in which the components of stress (STRESS) and strain (STRAN) are stored. It is provided so * that vector- or tensor-valued state variables can be rotated appropriately in this subroutine: stress and * strain components are already rotated by this amount before UMAT is called. This matrix is passed in * as a unit matrix for small-displacement analysis and for large-displacement analysis if the basis system * for the material point rotates with the material (as in a shell element or when a local orientation is used).*/ FloatMatrix drot(3, 3); drot.beUnitMatrix(); /* Characteristic element length, which is a typical length of a line across an element for a first-order * element; it is half of the same typical length for a second-order element. For beams and trusses it is a * characteristic length along the element axis. For membranes and shells it is a characteristic length in * the reference surface. For axisymmetric elements it is a characteristic length in the * plane only. * For cohesive elements it is equal to the constitutive thickness.*/ double celent = 0.0; /// @todo Include the characteristic element length /* Array containing the deformation gradient at the beginning of the increment. See the discussion * regarding the availability of the deformation gradient for various element types. */ FloatMatrix dfgrd0(3, 3); /* Array containing the deformation gradient at the end of the increment. The components of this array * are set to zero if nonlinear geometric effects are not included in the step definition associated with * this increment. See the discussion regarding the availability of the deformation gradient for various * element types. */ FloatMatrix dfgrd1(3, 3); dfgrd0.beMatrixForm( ms->giveFVector() ); dfgrd1.beMatrixForm(vF); int noel = gp->giveElement()->giveNumber(); // Element number. int npt = 0; // Integration point number. // We intentionally ignore the layer number since that is handled by the layered cross-section in OOFEM. int layer = 0; // Layer number (for composite shells and layered solids).. int kspt = 0; // Section point number within the current layer. int kstep = tStep->giveMetaStepNumber(); // Step number. int kinc = 0; // Increment number. ///@todo No idea about these parameters double predef; double dpred; // Change to Abaqus's component order stress.changeComponentOrder(); strain.changeComponentOrder(); strainIncrement.changeComponentOrder(); OOFEM_LOG_DEBUG("AbaqusUserMaterial :: giveRealStressVector - Calling subroutine"); this->umat(stress.givePointer(), // STRESS state.givePointer(), // STATEV jacobian.givePointer(), // DDSDDE & sse, // SSE & spd, // SPD & scd, // SCD & rpl, // RPL ddsddt.givePointer(), // DDSDDT drplde.givePointer(), // DRPLDE & drpldt, // DRPLDT strain.givePointer(), // STRAN strainIncrement.givePointer(), // DSTRAN time, // TIME & dtime, // DTIME & temp, // TEMP & dtemp, // DTEMP & predef, // PREDEF & dpred, // DPRED this->cmname, // CMNAME & ndi, // NDI & nshr, // NSHR & ntens, // NTENS & numState, // NSTATV properties.givePointer(), // PROPS & numProperties, // NPROPS coords.givePointer(), // COORDS drot.givePointer(), // DROT & pnewdt, // PNEWDT & celent, // CELENT dfgrd0.givePointer(), // DFGRD0 dfgrd1.givePointer(), // DFGRD1 & noel, // NOEL & npt, // NPT & layer, // LAYER & kspt, // KSPT & kstep, // KSTEP & kinc); // KINC // Change to OOFEM's component order stress.changeComponentOrder(); strain.changeComponentOrder(); strainIncrement.changeComponentOrder(); jacobian.changeComponentOrder(); if ( mStressInterpretation == 0 ) { FloatMatrix P, cauchyStress; P.beMatrixForm(stress); FloatArray vP; vP.beVectorForm(P); cauchyStress.beProductTOf(P, F); cauchyStress.times( 1.0 / F.giveDeterminant() ); FloatArray vCauchyStress; vCauchyStress.beSymVectorForm(cauchyStress); ms->letTempStrainVectorBe(strain); ms->letTempStressVectorBe(vCauchyStress); ms->letTempStateVectorBe(state); ms->letTempTangentBe(jacobian); ms->letTempPVectorBe(vP); ms->letTempFVectorBe(vF); answer = vP; } else { FloatArray vP; FloatMatrix P, sigma, F_inv; F_inv.beInverseOf(F); sigma.beMatrixForm(stress); P.beProductOf(F, sigma); vP.beVectorForm(P); answer = vP; // Convert from sigma to S FloatMatrix S; S.beProductOf(F_inv, P); vS.beSymVectorForm(S); // @todo Should convert from dsigmadE to dSdE here // L2=detF*matmul( matmul ( inv(op_a_V9(F,F), cm-op_a_V9(ident,Tau)-op_b_V9(Tau,ident) ), inv(op_a_V9(Ft,Ft))) ms->letTempStrainVectorBe(strain); ms->letTempStressVectorBe(vS); ms->letTempStateVectorBe(state); ms->letTempTangentBe(jacobian); ms->letTempPVectorBe(vP); ms->letTempFVectorBe(vF); } OOFEM_LOG_DEBUG("AbaqusUserMaterial :: giveRealStressVector_3d - Calling subroutine was successful"); }
void Line :: computeProjection(FloatArray &answer) { answer.beDifferenceOf(mVertices [ 1 ], mVertices [ 0 ]); }
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 ]); } }
double BasicGeometry :: computeLineDistance(const FloatArray &iP1, const FloatArray &iP2, const FloatArray &iQ1, const FloatArray &iQ2) { FloatArray u; u.beDifferenceOf(iP2, iP1); const double LengthP = u.computeNorm(); FloatArray v; v.beDifferenceOf(iQ2, iQ1); const double LengthQ = v.computeNorm(); // Regularization coefficients (to make it possible to solve when lines are parallel) const double c1 = (1.0e-14)*LengthP*LengthP; const double c2 = (1.0e-14)*LengthQ*LengthQ; const size_t minIter = 2; const size_t maxIter = 5; const double absTol = 1.0e-12; double xi = 0.0, eta = 0.0; FloatArray d; d = iP1; d.add(xi,u); d.add(-1.0, iQ1); d.add(-eta, v); FloatMatrix K(2,2), KInv; FloatArray dXi; bool lockXi = false, lockEta = false; for(size_t iter = 0; iter < maxIter; iter++) { if(xi < 0.0) { xi = 0.0; lockXi = true; } if(xi > 1.0) { xi = 1.0; lockXi = true; } if(eta < 0.0) { eta = 0.0; lockEta = true; } if(eta > 1.0) { eta = 1.0; lockEta = true; } FloatArray R = { d.dotProduct(u) + c1*xi, -d.dotProduct(v) + c2*eta}; if(lockXi) { R[0] = 0.0; } if(lockEta) { R[1] = 0.0; } const double res = R.computeNorm(); // printf("iter: %lu res: %e\n", iter, res); if(res < absTol && iter >= minIter) { // printf("xi: %e eta: %e\n", xi, eta); break; } K(0,0) = -u.dotProduct(u)-c1; K(0,1) = u.dotProduct(v); K(1,0) = u.dotProduct(v); K(1,1) = -v.dotProduct(v)-c2; if(lockXi) { K(0,0) = -1.0; K(0,1) = K(1,0) = 0.0; } if(lockEta) { K(0,1) = K(1,0) = 0.0; K(1,1) = -1.0; } KInv.beInverseOf(K); dXi.beProductOf(KInv, R); xi += dXi[0]; eta += dXi[1]; d = iP1; d.add(xi,u); d.add(-1.0, iQ1); d.add(-eta, v); } if(xi < 0.0) { xi = 0.0; } if(xi > 1.0) { xi = 1.0; } if(eta < 0.0) { eta = 0.0; } if(eta > 1.0) { eta = 1.0; } d = iP1; d.add(xi,u); d.add(-1.0, iQ1); d.add(-eta, v); const double dist = d.computeNorm(); return dist; }