void CCTPlate3d :: giveCharacteristicTensor(FloatMatrix &answer, CharTensor type, GaussPoint *gp, TimeStep *tStep) // returns characteristic tensor of the receiver at given gp and tStep // strain vector = (Kappa_x, Kappa_y, Kappa_xy, Gamma_zx, Gamma_zy) { FloatArray charVect; Material *mat = this->giveMaterial(); StructuralMaterialStatus *ms = static_cast< StructuralMaterialStatus * >( mat->giveStatus(gp) ); answer.resize(3, 3); answer.zero(); if ( ( type == LocalForceTensor ) || ( type == GlobalForceTensor ) ) { //this->computeStressVector(charVect, gp, tStep); charVect = ms->giveStressVector(); answer.at(1, 3) = charVect.at(4); answer.at(3, 1) = charVect.at(4); answer.at(2, 3) = charVect.at(5); answer.at(3, 2) = charVect.at(5); } else if ( ( type == LocalMomentumTensor ) || ( type == GlobalMomentumTensor ) ) { //this->computeStressVector(charVect, gp, tStep); charVect = ms->giveStressVector(); answer.at(1, 1) = charVect.at(1); answer.at(2, 2) = charVect.at(2); answer.at(1, 2) = charVect.at(3); answer.at(2, 1) = charVect.at(3); } else if ( ( type == LocalStrainTensor ) || ( type == GlobalStrainTensor ) ) { //this->computeStrainVector(charVect, gp, tStep); charVect = ms->giveStrainVector(); answer.at(1, 3) = charVect.at(4) / 2.; answer.at(3, 1) = charVect.at(4) / 2.; answer.at(2, 3) = charVect.at(5) / 2.; answer.at(3, 2) = charVect.at(5) / 2.; } else if ( ( type == LocalCurvatureTensor ) || ( type == GlobalCurvatureTensor ) ) { //this->computeStrainVector(charVect, gp, tStep); charVect = ms->giveStrainVector(); answer.at(1, 1) = charVect.at(1); answer.at(2, 2) = charVect.at(2); answer.at(1, 2) = charVect.at(3) / 2.; answer.at(2, 1) = charVect.at(3) / 2.; } else { _error("GiveCharacteristicTensor: unsupported tensor mode"); exit(1); } if ( ( type == GlobalForceTensor ) || ( type == GlobalMomentumTensor ) || ( type == GlobalStrainTensor ) || ( type == GlobalCurvatureTensor ) ) { this->computeGtoLRotationMatrix(); answer.rotatedWith(* GtoLRotationMatrix); } }
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 StructuralMaterialSettable :: giveRealStressVector_3d(FloatArray &answer, GaussPoint *gp, const FloatArray &totalStrain, TimeStep *atTime) { StructuralMaterialStatus *status = static_cast< StructuralMaterialStatus * >( this->giveStatus(gp) ); const FloatArray& stressVector = status->giveStressVector(); status->letTempStrainVectorBe(totalStrain); status->letTempStressVectorBe(stressVector); answer = stressVector; }
int FiberedCrossSection :: giveIPValue(FloatArray &answer, GaussPoint *gp, InternalStateType type, TimeStep *tStep) { Material *mat = this->giveDomain()->giveMaterial( fiberMaterials.at(1) ); ///@todo For now, create material status according to the first fiber material StructuralMaterialStatus *status = static_cast< StructuralMaterialStatus * >( mat->giveStatus(gp) ); if ( type == IST_BeamForceMomentTensor ) { answer = status->giveStressVector(); return 1; } else if ( type == IST_BeamStrainCurvatureTensor ) { answer = status->giveStrainVector(); return 1; } return CrossSection :: giveIPValue(answer, gp, type, tStep); }
void LinQuad3DPlaneStress :: giveCharacteristicTensor(FloatMatrix &answer, CharTensor type, GaussPoint *gp, TimeStep *tStep) // returns characteristic tensor of the receiver at given gp and tStep // strain vector = (Eps_X, Eps_y, Gamma_xy, Kappa_z) { FloatArray charVect; StructuralMaterialStatus *ms = static_cast< StructuralMaterialStatus * >( gp->giveMaterialStatus() ); answer.resize(3, 3); answer.zero(); if ( ( type == LocalForceTensor ) || ( type == GlobalForceTensor ) ) { //this->computeStressVector(charVect, gp, tStep); charVect = ms->giveStressVector(); answer.at(1, 1) = charVect.at(1); answer.at(2, 2) = charVect.at(2); answer.at(1, 2) = charVect.at(3); answer.at(2, 1) = charVect.at(3); } else if ( ( type == LocalMomentTensor ) || ( type == GlobalMomentTensor ) ) { } else if ( ( type == LocalStrainTensor ) || ( type == GlobalStrainTensor ) ) { //this->computeStrainVector(charVect, gp, tStep); charVect = ms->giveStrainVector(); answer.at(1, 1) = charVect.at(1); answer.at(2, 2) = charVect.at(2); answer.at(1, 2) = charVect.at(3) / 2.; answer.at(2, 1) = charVect.at(3) / 2.; } else if ( ( type == LocalCurvatureTensor ) || ( type == GlobalCurvatureTensor ) ) { } else { OOFEM_ERROR("unsupported tensor mode"); exit(1); } if ( ( type == GlobalForceTensor ) || ( type == GlobalMomentTensor ) || ( type == GlobalStrainTensor ) || ( type == GlobalCurvatureTensor ) ) { this->computeGtoLRotationMatrix(); answer.rotatedWith(* GtoLRotationMatrix); } }
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 NLStructuralElement :: giveInternalForcesVector_withIRulesAsSubcells(FloatArray &answer, TimeStep *tStep, int useUpdatedGpRecord) { /* * Returns nodal representation of real internal forces computed from first Piola-Kirchoff stress * if useGpRecord == 1 then stresses stored in the gp are used, otherwise stresses are computed * this must be done if you want internal forces after element->updateYourself() has been called * for the same time step. * The integration procedure uses an integrationRulesArray for numerical integration. * Each integration rule is considered to represent a separate sub-cell/element. Typically this would be used when * integration of the element domain needs special treatment, e.g. when using the XFEM. */ FloatMatrix B; FloatArray vStress, vStrain; IntArray irlocnum; FloatArray *m = & answer, temp; if ( this->giveInterpolation() && this->giveInterpolation()->hasSubPatchFormulation() ) { m = & temp; } // zero answer will resize accordingly when adding first contribution answer.clear(); // loop over individual integration rules for ( auto &iRule: integrationRulesArray ) { for ( GaussPoint *gp: *iRule ) { StructuralMaterialStatus *matStat = static_cast< StructuralMaterialStatus * >( gp->giveMaterialStatus() ); if ( nlGeometry == 0 ) { this->computeBmatrixAt(gp, B); if ( useUpdatedGpRecord == 1 ) { vStress = matStat->giveStressVector(); } else { this->computeStrainVector(vStrain, gp, tStep); this->computeStressVector(vStress, vStrain, gp, tStep); } } else if ( nlGeometry == 1 ) { if ( this->domain->giveEngngModel()->giveFormulation() == AL ) { // Cauchy stress if ( useUpdatedGpRecord == 1 ) { vStress = matStat->giveCVector(); } else { this->computeCauchyStressVector(vStress, gp, tStep); } this->computeBmatrixAt(gp, B); } else { // First Piola-Kirchhoff stress if ( useUpdatedGpRecord == 1 ) { vStress = matStat->givePVector(); } else { this->computeFirstPKStressVector(vStress, gp, tStep); } this->computeBHmatrixAt(gp, B); } } if ( vStress.giveSize() == 0 ) { //@todo is this really necessary? break; } // compute nodal representation of internal forces at nodes as f = B^T*stress dV double dV = this->computeVolumeAround(gp); m->plusProduct(B, vStress, dV); // localize irule contribution into element matrix if ( this->giveIntegrationRuleLocalCodeNumbers(irlocnum, *iRule) ) { answer.assemble(* m, irlocnum); m->clear(); } } } // if inactive: update fields but do not give any contribution to the structure if ( !this->isActivated(tStep) ) { answer.zero(); return; } }
void NLStructuralElement :: giveInternalForcesVector(FloatArray &answer, TimeStep *tStep, int useUpdatedGpRecord) { FloatMatrix B; FloatArray vStress, vStrain, u; // This function can be quite costly to do inside the loops when one has many slave dofs. this->computeVectorOf(VM_Total, tStep, u); // subtract initial displacements, if defined if ( initialDisplacements ) { u.subtract(* initialDisplacements); } // zero answer will resize accordingly when adding first contribution answer.clear(); for ( auto &gp: *this->giveDefaultIntegrationRulePtr() ) { StructuralMaterialStatus *matStat = static_cast< StructuralMaterialStatus * >( gp->giveMaterialStatus() ); // Engineering (small strain) stress if ( nlGeometry == 0 ) { this->computeBmatrixAt(gp, B); if ( useUpdatedGpRecord == 1 ) { vStress = matStat->giveStressVector(); } else { ///@todo Is this really what we should do for inactive elements? if ( !this->isActivated(tStep) ) { vStrain.resize( StructuralMaterial :: giveSizeOfVoigtSymVector( gp->giveMaterialMode() ) ); vStrain.zero(); } vStrain.beProductOf(B, u); this->computeStressVector(vStress, vStrain, gp, tStep); } } else if ( nlGeometry == 1 ) { // First Piola-Kirchhoff stress if ( this->domain->giveEngngModel()->giveFormulation() == AL ) { // Cauchy stress if ( useUpdatedGpRecord == 1 ) { vStress = matStat->giveCVector(); } else { this->computeCauchyStressVector(vStress, gp, tStep); } this->computeBmatrixAt(gp, B); } else { // First Piola-Kirchhoff stress if ( useUpdatedGpRecord == 1 ) { vStress = matStat->givePVector(); } else { this->computeFirstPKStressVector(vStress, gp, tStep); ///@todo This is actaully inefficient since it constructs B and twice and collects the nodal unknowns over and over. } this->computeBHmatrixAt(gp, B); } } if ( vStress.giveSize() == 0 ) { /// @todo is this check really necessary? break; } // Compute nodal internal forces at nodes as f = B^T*Stress dV double dV = this->computeVolumeAround(gp); if ( nlGeometry == 1 ) { // First Piola-Kirchhoff stress if ( vStress.giveSize() == 9 ) { FloatArray stressTemp; StructuralMaterial :: giveReducedVectorForm( stressTemp, vStress, gp->giveMaterialMode() ); answer.plusProduct(B, stressTemp, dV); } else { answer.plusProduct(B, vStress, dV); } } else { if ( vStress.giveSize() == 6 ) { // It may happen that e.g. plane strain is computed // using the default 3D implementation. If so, // the stress needs to be reduced. // (Note that no reduction will take place if // the simulation is actually 3D.) FloatArray stressTemp; StructuralMaterial :: giveReducedSymVectorForm( stressTemp, vStress, gp->giveMaterialMode() ); answer.plusProduct(B, stressTemp, dV); } else { answer.plusProduct(B, vStress, dV); } } } // If inactive: update fields but do not give any contribution to the internal forces if ( !this->isActivated(tStep) ) { answer.zero(); return; } }