bool StaggeredSolver :: checkConvergenceDofIdArray(FloatArray &RT, FloatArray &F, FloatArray &rhs, FloatArray &ddX, FloatArray &X, double RRT, const FloatArray &internalForcesEBENorm, int nite, bool &errorOutOfRange, TimeStep *tStep, IntArray &dofIdArray) { double forceErr, dispErr; FloatArray dg_forceErr, dg_dispErr, dg_totalLoadLevel, dg_totalDisp; bool answer; EModelDefaultEquationNumbering dn; ParallelContext *parallel_context = engngModel->giveParallelContext( this->domain->giveNumber() ); /* * The force errors are (if possible) evaluated as relative errors. * If the norm of applied load vector is zero (one may load by temperature, etc) * then the norm of reaction forces is used in relative norm evaluation. * * Note: This is done only when all dofs are included (nccdg = 0). Not implemented if * multiple convergence criteria are used. * */ answer = true; errorOutOfRange = false; // Store the errors associated with the dof groups if ( this->constrainedNRFlag ) { this->forceErrVecOld = this->forceErrVec; // copy the old values this->forceErrVec.resize( internalForcesEBENorm.giveSize() ); forceErrVec.zero(); } if ( internalForcesEBENorm.giveSize() > 1 ) { // Special treatment when just one norm is given; No grouping int nccdg = this->domain->giveMaxDofID(); // Keeps tracks of which dof IDs are actually in use; IntArray idsInUse(nccdg); idsInUse.zero(); // zero error norms per group dg_forceErr.resize(nccdg); dg_forceErr.zero(); dg_dispErr.resize(nccdg); dg_dispErr.zero(); dg_totalLoadLevel.resize(nccdg); dg_totalLoadLevel.zero(); dg_totalDisp.resize(nccdg); dg_totalDisp.zero(); // loop over dof managers for ( auto &dofman : domain->giveDofManagers() ) { if ( !parallel_context->isLocal(dofman.get()) ) { continue; } // loop over individual dofs for ( Dof *dof: *dofman ) { if ( !dof->isPrimaryDof() ) { continue; } int eq = dof->giveEquationNumber(dn); int dofid = dof->giveDofID(); if ( !eq ) { continue; } dg_forceErr.at(dofid) += rhs.at(eq) * rhs.at(eq); dg_dispErr.at(dofid) += ddX.at(eq) * ddX.at(eq); dg_totalLoadLevel.at(dofid) += RT.at(eq) * RT.at(eq); dg_totalDisp.at(dofid) += X.at(eq) * X.at(eq); idsInUse.at(dofid) = 1; } // end loop over DOFs } // end loop over dof managers // loop over elements and their DOFs for ( auto &elem : domain->giveElements() ) { if ( elem->giveParallelMode() != Element_local ) { continue; } // loop over element internal Dofs for ( int idofman = 1; idofman <= elem->giveNumberOfInternalDofManagers(); idofman++ ) { DofManager *dofman = elem->giveInternalDofManager(idofman); // loop over individual dofs for ( Dof *dof: *dofman ) { if ( !dof->isPrimaryDof() ) { continue; } int eq = dof->giveEquationNumber(dn); int dofid = dof->giveDofID(); if ( !eq ) { continue; } dg_forceErr.at(dofid) += rhs.at(eq) * rhs.at(eq); dg_dispErr.at(dofid) += ddX.at(eq) * ddX.at(eq); dg_totalLoadLevel.at(dofid) += RT.at(eq) * RT.at(eq); dg_totalDisp.at(dofid) += X.at(eq) * X.at(eq); idsInUse.at(dofid) = 1; } // end loop over DOFs } // end loop over element internal dofmans } // end loop over elements // loop over boundary conditions and their internal DOFs for ( auto &bc : domain->giveBcs() ) { // loop over element internal Dofs for ( int idofman = 1; idofman <= bc->giveNumberOfInternalDofManagers(); idofman++ ) { DofManager *dofman = bc->giveInternalDofManager(idofman); // loop over individual dofs for ( Dof *dof: *dofman ) { if ( !dof->isPrimaryDof() ) { continue; } int eq = dof->giveEquationNumber(dn); int dofid = dof->giveDofID(); if ( !eq ) { continue; } dg_forceErr.at(dofid) += rhs.at(eq) * rhs.at(eq); dg_dispErr.at(dofid) += ddX.at(eq) * ddX.at(eq); dg_totalLoadLevel.at(dofid) += RT.at(eq) * RT.at(eq); dg_totalDisp.at(dofid) += X.at(eq) * X.at(eq); idsInUse.at(dofid) = 1; } // end loop over DOFs } // end loop over element internal dofmans } // end loop over elements // exchange individual partition contributions (simultaneously for all groups) FloatArray collectiveErr(nccdg); parallel_context->accumulate(dg_forceErr, collectiveErr); dg_forceErr = collectiveErr; parallel_context->accumulate(dg_dispErr, collectiveErr); dg_dispErr = collectiveErr; parallel_context->accumulate(dg_totalLoadLevel, collectiveErr); dg_totalLoadLevel = collectiveErr; parallel_context->accumulate(dg_totalDisp, collectiveErr); dg_totalDisp = collectiveErr; OOFEM_LOG_INFO("StaggeredSolver: %-5d", nite); //bool zeroNorm = false; // loop over dof groups and check convergence individually for ( int dg = 1; dg <= nccdg; dg++ ) { bool zeroFNorm = false, zeroDNorm = false; // Skips the ones which aren't used in this problem (the residual will be zero for these anyway, but it is annoying to print them all) if ( !idsInUse.at(dg) ) { continue; } if ( dofIdArray.giveSize() && !dofIdArray.contains(dg) ) { continue; } OOFEM_LOG_INFO( " %s:", __DofIDItemToString( ( DofIDItem ) dg ).c_str() ); if ( rtolf.at(1) > 0.0 ) { // compute a relative error norm if ( ( dg_totalLoadLevel.at(dg) + internalForcesEBENorm.at(dg) ) > ERROR_NORM_SMALL_NUM ) { forceErr = sqrt( dg_forceErr.at(dg) / ( dg_totalLoadLevel.at(dg) + internalForcesEBENorm.at(dg) ) ); } else { // If both external forces and internal ebe norms are zero, then the residual must be zero. //zeroNorm = true; // Warning about this afterwards. zeroFNorm = true; forceErr = sqrt( dg_forceErr.at(dg) ); } if ( forceErr > rtolf.at(1) * MAX_REL_ERROR_BOUND ) { errorOutOfRange = true; } if ( forceErr > rtolf.at(1) ) { answer = false; } OOFEM_LOG_INFO(zeroFNorm ? " *%.3e" : " %.3e", forceErr); // Store the errors from the current iteration if ( this->constrainedNRFlag ) { forceErrVec.at(dg) = forceErr; } } if ( rtold.at(1) > 0.0 ) { // compute displacement error if ( dg_totalDisp.at(dg) > ERROR_NORM_SMALL_NUM ) { dispErr = sqrt( dg_dispErr.at(dg) / dg_totalDisp.at(dg) ); } else { ///@todo This is almost always the case for displacement error. ERROR_NORM_SMALL_NUM is no good. //zeroNorm = true; // Warning about this afterwards. //zeroDNorm = true; dispErr = sqrt( dg_dispErr.at(dg) ); } if ( dispErr > rtold.at(1) * MAX_REL_ERROR_BOUND ) { errorOutOfRange = true; } if ( dispErr > rtold.at(1) ) { answer = false; } OOFEM_LOG_INFO(zeroDNorm ? " *%.3e" : " %.3e", dispErr); } } OOFEM_LOG_INFO("\n"); //if ( zeroNorm ) OOFEM_WARNING("Had to resort to absolute error measure (marked by *)"); } else { // No dof grouping double dXX, dXdX; if ( engngModel->giveProblemScale() == macroScale ) { OOFEM_LOG_INFO("StaggeredSolver: %-15d", nite); } else { OOFEM_LOG_INFO(" StaggeredSolver: %-15d", nite); } forceErr = parallel_context->localNorm(rhs); forceErr *= forceErr; dXX = parallel_context->localNorm(X); dXX *= dXX; // Note: Solutions are always total global values (natural distribution makes little sense for the solution) dXdX = parallel_context->localNorm(ddX); dXdX *= dXdX; if ( rtolf.at(1) > 0.0 ) { // we compute a relative error norm if ( ( RRT + internalForcesEBENorm.at(1) ) > ERROR_NORM_SMALL_NUM ) { forceErr = sqrt( forceErr / ( RRT + internalForcesEBENorm.at(1) ) ); } else { forceErr = sqrt(forceErr); // absolute norm as last resort } if ( fabs(forceErr) > rtolf.at(1) * MAX_REL_ERROR_BOUND ) { errorOutOfRange = true; } if ( fabs(forceErr) > rtolf.at(1) ) { answer = false; } OOFEM_LOG_INFO(" %-15e", forceErr); if ( this->constrainedNRFlag ) { // store the errors from the current iteration for use in the next forceErrVec.at(1) = forceErr; } } if ( rtold.at(1) > 0.0 ) { // compute displacement error // err is relative displacement change if ( dXX > ERROR_NORM_SMALL_NUM ) { dispErr = sqrt(dXdX / dXX); } else { dispErr = sqrt(dXdX); } if ( fabs(dispErr) > rtold.at(1) * MAX_REL_ERROR_BOUND ) { errorOutOfRange = true; } if ( fabs(dispErr) > rtold.at(1) ) { answer = false; } OOFEM_LOG_INFO(" %-15e", dispErr); } OOFEM_LOG_INFO("\n"); } // end default case (all dofs contributing) return answer; }
void RCSDNLMaterial :: 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 // { FloatMatrix Ds0; double equivStrain; FloatArray princStress, nonlocalStrain, reducedSpaceStressVector; FloatArray reducedNonlocStrainVector, fullNonlocStrainVector, principalStrain; FloatMatrix tempCrackDirs; RCSDNLMaterialStatus *nonlocStatus, *status = static_cast< RCSDNLMaterialStatus * >( this->giveStatus(gp) ); FloatArray nonlocalContribution; FloatArray reducedLocalStrainVector, localStrain; this->initTempStatus(gp); this->buildNonlocalPointTable(gp); this->updateDomainBeforeNonlocAverage(tStep); // compute nonlocal strain increment first std :: list< localIntegrationRecord > *list = this->giveIPIntegrationList(gp); // ! for ( auto &lir: *list ) { nonlocStatus = static_cast< RCSDNLMaterialStatus * >( this->giveStatus(lir.nearGp) ); nonlocalContribution = nonlocStatus->giveLocalStrainVectorForAverage(); nonlocalContribution.times(lir.weight); reducedNonlocStrainVector.add(nonlocalContribution); } reducedNonlocStrainVector.times( 1. / status->giveIntegrationScale() ); this->endIPNonlocalAverage(gp); // ! // subtract stress independent part ////# this->giveStressDependentPartOfStrainVector(nonlocalStrainIncrement, gp, nonlocalTotalStrainIncrement,tStep); // reducedLocalStrainVector = totalStrain; // 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(nonlocalStrain, gp, reducedNonlocStrainVector, tStep, VM_Total); this->giveStressDependentPartOfStrainVector(localStrain, gp, reducedLocalStrainVector, tStep, VM_Total); StructuralMaterial :: giveFullSymVectorForm( fullNonlocStrainVector, nonlocalStrain, gp->giveMaterialMode() ); tempCrackDirs = status->giveTempCrackDirs(); this->computePrincipalValDir(principalStrain, tempCrackDirs, fullNonlocStrainVector, principal_strain); if ( status->giveTempMode() == RCSDEMaterialStatus :: rcMode ) { // rotating crack mode this->giveRealPrincipalStressVector3d(princStress, gp, principalStrain, tempCrackDirs, tStep); ////# // ////# // this -> giveRealPrincipalStressVector3d (princStress, gp, strainIncrement, tStep); ////# princStress.resize (6); ////# status->giveTempCrackDirs (tempCrackDirs); ////# this -> transformStressVectorTo (answer, tempCrackDirs, princStress, 1); ////# crossSection->giveReducedCharacteristicVector(stressIncrement, gp, answer); ////# stressIncrement.subtract (status -> giveStressVector()); ////# status -> letStressIncrementVectorBe (stressIncrement); this->updateCrackStatus(gp, status->giveCrackStrainVector()); ////# this->giveMaterialStiffnessMatrix(Ds0, SecantStiffness, gp, tStep); ////# if (form == ReducedForm) { ////# crossSection->giveReducedCharacteristicVector(reducedAnswer, gp, answer); ////# answer = reducedAnswer; ////# } // check for any currently opening crack int anyOpeningCrack = 0; for ( int i = 1; i <= 3; i++ ) { if ( ( status->giveTempCrackStatus(i) == pscm_SOFTENING ) || ( status->giveTempCrackStatus(i) == pscm_OPEN ) ) { anyOpeningCrack++; } } if ( anyOpeningCrack ) { // test if transition to scalar damage mode take place double minSofteningPrincStress = this->Ft, E, Le, CurrFt, Gf, Gf0, Gf1, e0, ef, ef2, damage; // double minSofteningPrincStress = this->Ft, dCoeff, CurrFt, E, ep, ef, damage; int ipos = 0; for ( int i = 1; i <= 3; i++ ) { if ( ( status->giveTempCrackStatus(i) == pscm_SOFTENING ) || ( status->giveTempCrackStatus(i) == pscm_OPEN ) ) { if ( princStress.at(i) < minSofteningPrincStress ) { minSofteningPrincStress = princStress.at(i); ipos = i; } } } CurrFt = this->computeStrength( gp, status->giveCharLength(ipos) ); ////## // next pasted from rcm2:giveEffectiveMaterialStiffnessMatrix double G, minG, currG, princStressDis, princStrainDis; int ii, jj; minG = G = this->give(pscm_G, gp); ///@todo Double-Check the logic here with the mask: IntArray indx; StructuralMaterial :: giveVoigtSymVectorMask( indx, gp->giveMaterialMode() ); for ( int i = 4; i <= 6; i++ ) { if ( indx.contains(i) ) { if ( i == 4 ) { ii = 2; jj = 3; } else if ( i == 5 ) { ii = 1; jj = 3; } else if ( i == 6 ) { ii = 1; jj = 2; } else { continue; } princStressDis = princStress.at(ii) - princStress.at(jj); princStrainDis = principalStrain.at(ii) - principalStrain.at(jj); if ( fabs(princStrainDis) < rcm_SMALL_STRAIN ) { currG = G; } else { currG = princStressDis / ( 2.0 * princStrainDis ); } //currG = Ds0.at(indi, indi); minG = min(minG, currG); } } ////# if ( ( minSofteningPrincStress <= this->SDTransitionCoeff * CurrFt ) || ( minG <= this->SDTransitionCoeff2 * G ) ) { // printf ("minSofteningPrincStress=%lf, CurrFt=%lf, SDTransitionCoeff=%lf",minSofteningPrincStress, CurrFt, this->SDTransitionCoeff); // printf ("\nminG=%lf, G=%lf, SDTransitionCoeff2=%lf\n",minG, G, this->SDTransitionCoeff2); // sd transition takes place if ( ipos == 0 ) { for ( int i = 1; i <= 3; i++ ) { if ( ( status->giveTempCrackStatus(i) == pscm_SOFTENING ) || ( status->giveTempCrackStatus(i) == pscm_OPEN ) ) { if ( ipos == 0 ) { ipos = i; minSofteningPrincStress = princStress.at(i); } if ( princStress.at(i) < minSofteningPrincStress ) { minSofteningPrincStress = princStress.at(i); ipos = i; } } } } // test for internal consistency error // we should switch to scalar damage, but no softening take place if ( ipos == 0 ) { //RCSDEMaterial :: OOFEM_ERROR("can not switch to sd mode, while no cracking"); OOFEM_ERROR("can not switch to sd mode, while no cracking"); } //if (minSofteningPrincStress <= this->SDTransitionCoeff * CurrFt) printf ("."); //else printf (":"); // Le = status->giveCharLength(ipos); E = linearElasticMaterial->give(Ex, gp); Gf = this->give(pscm_Gf, gp) / Le; ef = this->ef; e0 = principalStrain.at(ipos); Gf0 = -CurrFt * ef * ( exp(-status->giveCrackStrain(ipos) / ef) - 1.0 ); // already disipated + 0.5*sigma0*epsilon0 Gf1 = Gf - Gf0; ef2 = Gf1 / princStress.at(ipos); //this->giveMaterialStiffnessMatrix (Ds0, SecantStiffness, gp, tStep); // compute reached equivalent strain equivStrain = this->computeCurrEquivStrain(gp, nonlocalStrain, E, tStep); damage = this->computeDamageCoeff(equivStrain, e0, ef2); // printf ("Gf=%lf, Gf0=%lf, damage=%lf, e0=%lf, ef2=%lf, es=%lf\n",Gf, Gf0, damage,e0,ef2,equivStrain); status->setTransitionEpsCoeff(e0); status->setEpsF2Coeff(ef2); status->setDs0Matrix(Ds0); status->setTempMaxEquivStrain(equivStrain); status->setTempDamageCoeff(damage); status->setTempMode(RCSDEMaterialStatus :: sdMode); } } } else if ( status->giveTempMode() == RCSDEMaterialStatus :: sdMode ) { // scalar damage mode double E, e0, ef2; // double ep, ef, E, dCoeff; //FloatArray reducedSpaceStressVector; double damage; E = linearElasticMaterial->give(Ex, gp); equivStrain = this->computeCurrEquivStrain(gp, nonlocalStrain, E, tStep); equivStrain = max( equivStrain, status->giveTempMaxEquivStrain() ); ////# reducedSpaceStressVector.beProductOf (*status->giveDs0Matrix(), reducedNonlocStrainVector); ef2 = status->giveEpsF2Coeff(); e0 = status->giveTransitionEpsCoeff(); damage = this->computeDamageCoeff(equivStrain, e0, ef2); // dCoeff = status->giveDamageStiffCoeff (); // ef = status->giveDamageEpsfCoeff(); // ep = status->giveDamageEpspCoeff(); // damage = this->computeDamageCoeff (equivStrain, dCoeff, ep, ef); ////# Ds0 = * status->giveDs0Matrix(); Ds0.times(1.0 - damage); ////# ////# reducedSpaceStressVector.times (1.0 - damage); ////# answer = reducedSpaceStressVector; ////# stressIncrement = reducedSpaceStressVector; ////# stressIncrement.subtract (status -> giveStressVector()); ////# status -> letStressIncrementVectorBe (stressIncrement); status->setTempMaxEquivStrain(equivStrain); status->setTempDamageCoeff(damage); } ////# common part reducedSpaceStressVector.beProductOf(Ds0, localStrain); answer = reducedSpaceStressVector; status->letTempStressVectorBe(reducedSpaceStressVector); status->letTempStrainVectorBe(totalStrain); status->setTempNonlocalStrainVector(reducedNonlocStrainVector); }