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;
}
Exemplo n.º 2
0
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);
}