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; } }