NM_Status NRSolver :: solve(SparseMtrx &k, FloatArray &R, FloatArray *R0, FloatArray &X, FloatArray &dX, FloatArray &F, const FloatArray &internalForcesEBENorm, double &l, referenceLoadInputModeType rlm, int &nite, TimeStep *tStep) // // this function solve the problem of the unbalanced equilibrium // using NR scheme // // { // residual, iteration increment of solution, total external force FloatArray rhs, ddX, RT; double RRT; FloatArray norm; norm = internalForcesEBENorm; int neq = X.giveSize(); bool converged, errorOutOfRangeFlag; ParallelContext *parallel_context = engngModel->giveParallelContext( this->domain->giveNumber() ); if ( engngModel->giveProblemScale() == macroScale ) { OOFEM_LOG_INFO("NRSolver: 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"); } l = 1.0; NM_Status status = NM_None; this->giveLinearSolver(); // compute total load R = R+R0 RT = R; if ( R0 ) { RT.add(* R0); } RRT = parallel_context->localNorm(RT); RRT *= RRT; ddX.resize(neq); ddX.zero(); // Fetch the matrix before evaluating internal forces. // This is intentional, since its a simple way to drastically increase convergence for nonlinear problems. // (This old tangent is just used) // This improves convergence for many nonlinear problems, but not all. It may actually // cause divergence for some nonlinear problems. Therefore a flag is used to determine if // the stiffness should be evaluated before the residual (default yes). /ES engngModel->updateComponent(tStep, NonLinearLhs, domain); if ( this->prescribedDofsFlag ) { if ( !prescribedEqsInitFlag ) { this->initPrescribedEqs(); } applyConstraintsToStiffness(k); } nite = 0; do { // Compute the residual engngModel->updateComponent(tStep, InternalRhs, domain); rhs.beDifferenceOf(RT, F); if ( this->prescribedDofsFlag ) { this->applyConstraintsToLoadIncrement(nite, k, rhs, rlm, tStep); } // convergence check converged = this->checkConvergence(RT, F, rhs, ddX, X, RRT, internalForcesEBENorm, nite, errorOutOfRangeFlag); if ( errorOutOfRangeFlag ) { status = NM_NoSuccess; OOFEM_WARNING("Divergence reached after %d iterations", nite); break; } else if ( converged && ( nite >= minIterations ) ) { break; } else if ( nite >= nsmax ) { OOFEM_LOG_DEBUG("Maximum number of iterations reached\n"); break; } if ( nite > 0 || !mCalcStiffBeforeRes ) { if ( ( NR_Mode == nrsolverFullNRM ) || ( ( NR_Mode == nrsolverAccelNRM ) && ( nite % MANRMSteps == 0 ) ) ) { engngModel->updateComponent(tStep, NonLinearLhs, domain); applyConstraintsToStiffness(k); } } if ( ( nite == 0 ) && ( deltaL < 1.0 ) ) { // deltaL < 1 means no increment applied, only equilibrate current state rhs.zero(); R.zero(); ddX = rhs; } else { linSolver->solve(k, rhs, ddX); } // // update solution // if ( this->lsFlag && ( nite > 0 ) ) { // Why not nite == 0 ? // line search LineSearchNM :: LS_status LSstatus; double eta; this->giveLineSearchSolver()->solve(X, ddX, F, R, R0, prescribedEqs, 1.0, eta, LSstatus, tStep); } else if ( this->constrainedNRFlag && ( nite > this->constrainedNRminiter ) ) { ///@todo This doesn't check units, it is nonsense and must be corrected / Mikael if ( this->forceErrVec.computeSquaredNorm() > this->forceErrVecOld.computeSquaredNorm() ) { OOFEM_LOG_INFO("Constraining increment to be %e times full increment...\n", this->constrainedNRalpha); ddX.times(this->constrainedNRalpha); } //this->giveConstrainedNRSolver()->solve(X, & ddX, this->forceErrVec, this->forceErrVecOld, status, tStep); } X.add(ddX); dX.add(ddX); tStep->incrementStateCounter(); // update solution state counter tStep->incrementSubStepNumber(); nite++; // iteration increment engngModel->giveExportModuleManager()->doOutput(tStep, true); } while ( true ); // end of iteration status |= NM_Success; solved = 1; // Modify Load vector to include "quasi reaction" if ( R0 ) { for ( int i = 1; i <= numberOfPrescribedDofs; i++ ) { R.at( prescribedEqs.at(i) ) = F.at( prescribedEqs.at(i) ) - R0->at( prescribedEqs.at(i) ) - R.at( prescribedEqs.at(i) ); } } else { for ( int i = 1; i <= numberOfPrescribedDofs; i++ ) { R.at( prescribedEqs.at(i) ) = F.at( prescribedEqs.at(i) ) - R.at( prescribedEqs.at(i) ); } } this->lastReactions.resize(numberOfPrescribedDofs); #ifdef VERBOSE if ( numberOfPrescribedDofs ) { // print quasi reactions if direct displacement control used OOFEM_LOG_INFO("\n"); OOFEM_LOG_INFO("NRSolver: Quasi reaction table \n"); OOFEM_LOG_INFO("NRSolver: Node Dof Displacement Force\n"); double reaction; for ( int i = 1; i <= numberOfPrescribedDofs; i++ ) { reaction = R.at( prescribedEqs.at(i) ); if ( R0 ) { reaction += R0->at( prescribedEqs.at(i) ); } lastReactions.at(i) = reaction; OOFEM_LOG_INFO("NRSolver: %-15d %-15d %-+15.5e %-+15.5e\n", prescribedDofs.at(2 * i - 1), prescribedDofs.at(2 * i), X.at( prescribedEqs.at(i) ), reaction); } OOFEM_LOG_INFO("\n"); } #endif return status; }
NM_Status StaggeredSolver :: solve(SparseMtrx &k, FloatArray &R, FloatArray *R0, FloatArray &Xtotal, FloatArray &dXtotal, FloatArray &F, const FloatArray &internalForcesEBENorm, double &l, referenceLoadInputModeType rlm, int &nite, TimeStep *tStep) { // residual, iteration increment of solution, total external force FloatArray RHS, rhs, ddXtotal, RT; double RRTtotal; int neq = Xtotal.giveSize(); NM_Status status; bool converged, errorOutOfRangeFlag; ParallelContext *parallel_context = engngModel->giveParallelContext( this->domain->giveNumber() ); if ( engngModel->giveProblemScale() == macroScale ) { OOFEM_LOG_INFO("StaggeredSolver: 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"); } l = 1.0; status = NM_None; this->giveLinearSolver(); // compute total load R = R+R0 RT = R; if ( R0 ) { RT.add(* R0); } RRTtotal = parallel_context->localNorm(RT); RRTtotal *= RRTtotal; ddXtotal.resize(neq); ddXtotal.zero(); // Fetch the matrix before evaluating internal forces. // This is intentional, since its a simple way to drastically increase convergence for nonlinear problems. // (This old tangent is just used) // This improves convergence for many nonlinear problems, but not all. It may actually // cause divergence for some nonlinear problems. Therefore a flag is used to determine if // the stiffness should be evaluated before the residual (default yes). /ES //------------------------------------------------- // Compute external forces int numDofIdGroups = this->UnknownNumberingSchemeList.size(); FloatArray RRT(numDofIdGroups); for ( int dG = 0; dG < numDofIdGroups; dG++ ) { this->fExtList[dG].beSubArrayOf( RT, locArrayList[dG] ); RRT(dG) = this->fExtList[dG].computeSquaredNorm(); } int nStaggeredIter = 0; do { // Staggered iterations for ( int dG = 0; dG < (int)this->UnknownNumberingSchemeList.size(); dG++ ) { printf("\nSolving for dof group %d \n", dG+1); engngModel->updateComponent(tStep, NonLinearLhs, domain); this->stiffnessMatrixList[dG] = k.giveSubMatrix( locArrayList[dG], locArrayList[dG]); if ( this->prescribedDofsFlag ) { if ( !prescribedEqsInitFlag ) { this->initPrescribedEqs(); } applyConstraintsToStiffness(k); } nite = 0; do { // Compute the residual engngModel->updateComponent(tStep, InternalRhs, domain); RHS.beDifferenceOf(RT, F); this->fIntList[dG].beSubArrayOf( F, locArrayList[dG] ); rhs.beDifferenceOf(this->fExtList[dG], this->fIntList[dG]); RHS.zero(); RHS.assemble(rhs, locArrayList[dG]); if ( this->prescribedDofsFlag ) { this->applyConstraintsToLoadIncrement(nite, k, rhs, rlm, tStep); } // convergence check IntArray &idArray = UnknownNumberingSchemeList[dG].dofIdArray; converged = this->checkConvergenceDofIdArray(RT, F, RHS, ddXtotal, Xtotal, RRTtotal, internalForcesEBENorm, nite, errorOutOfRangeFlag, tStep, idArray); if ( errorOutOfRangeFlag ) { status = NM_NoSuccess; OOFEM_WARNING("Divergence reached after %d iterations", nite); break; } else if ( converged && ( nite >= minIterations ) ) { break; } else if ( nite >= nsmax ) { OOFEM_LOG_DEBUG("Maximum number of iterations reached\n"); break; } if ( nite > 0 || !mCalcStiffBeforeRes ) { if ( ( NR_Mode == nrsolverFullNRM ) || ( ( NR_Mode == nrsolverAccelNRM ) && ( nite % MANRMSteps == 0 ) ) ) { engngModel->updateComponent(tStep, NonLinearLhs, domain); this->stiffnessMatrixList[dG] = k.giveSubMatrix( locArrayList[dG], locArrayList[dG]); applyConstraintsToStiffness(*this->stiffnessMatrixList[dG]); } } if ( ( nite == 0 ) && ( deltaL < 1.0 ) ) { // deltaL < 1 means no increment applied, only equilibrate current state rhs.zero(); R.zero(); ddX[dG] = rhs; } else { status = linSolver->solve(*this->stiffnessMatrixList[dG], rhs, ddX[dG]); } // // update solution // if ( this->lsFlag && ( nite > 0 ) ) { // Why not nite == 0 ? // line search LineSearchNM :: LS_status LSstatus; double eta; this->giveLineSearchSolver()->solve( X[dG], ddX[dG], fIntList[dG], fExtList[dG], R0, prescribedEqs, 1.0, eta, LSstatus, tStep); } else if ( this->constrainedNRFlag && ( nite > this->constrainedNRminiter ) ) { if ( this->forceErrVec.computeSquaredNorm() > this->forceErrVecOld.computeSquaredNorm() ) { printf("Constraining increment to be %e times full increment...\n", this->constrainedNRalpha); ddX[dG].times(this->constrainedNRalpha); } } X[dG].add(ddX[dG]); dX[dG].add(ddX[dG]); // Update total solution (containing all dofs) Xtotal.assemble(ddX[dG], locArrayList[dG]); dXtotal.assemble(ddX[dG], locArrayList[dG]); ddXtotal.zero(); ddXtotal.assemble(ddX[dG], locArrayList[dG]); tStep->incrementStateCounter(); // update solution state counter tStep->incrementSubStepNumber(); nite++; // iteration increment engngModel->giveExportModuleManager()->doOutput(tStep, true); } while ( true ); // end of iteration } printf("\nStaggered iteration (all dof id's) \n"); // Check convergence of total system RHS.beDifferenceOf(RT, F); converged = this->checkConvergence(RT, F, RHS, ddXtotal, Xtotal, RRTtotal, internalForcesEBENorm, nStaggeredIter, errorOutOfRangeFlag); if ( converged && ( nStaggeredIter >= minIterations ) ) { break; } nStaggeredIter++; } while ( true ); // end of iteration status |= NM_Success; solved = 1; // Modify Load vector to include "quasi reaction" if ( R0 ) { for ( int i = 1; i <= numberOfPrescribedDofs; i++ ) { R.at( prescribedEqs.at(i) ) = F.at( prescribedEqs.at(i) ) - R0->at( prescribedEqs.at(i) ) - R.at( prescribedEqs.at(i) ); } } else { for ( int i = 1; i <= numberOfPrescribedDofs; i++ ) { R.at( prescribedEqs.at(i) ) = F.at( prescribedEqs.at(i) ) - R.at( prescribedEqs.at(i) ); } } this->lastReactions.resize(numberOfPrescribedDofs); #ifdef VERBOSE if ( numberOfPrescribedDofs ) { // print quasi reactions if direct displacement control used OOFEM_LOG_INFO("\n"); OOFEM_LOG_INFO("StaggeredSolver: Quasi reaction table \n"); OOFEM_LOG_INFO("StaggeredSolver: Node Dof Displacement Force\n"); double reaction; for ( int i = 1; i <= numberOfPrescribedDofs; i++ ) { reaction = R->at( prescribedEqs.at(i) ); if ( R0 ) { reaction += R0->at( prescribedEqs.at(i) ); } lastReactions.at(i) = reaction; OOFEM_LOG_INFO("StaggeredSolver: %-15d %-15d %-+15.5e %-+15.5e\n", prescribedDofs.at(2 * i - 1), prescribedDofs.at(2 * i), X.at( prescribedEqs.at(i) ), reaction); } OOFEM_LOG_INFO("\n"); } #endif return status; }
NM_Status NRSolver :: solve(SparseMtrx *k, FloatArray *R, FloatArray *R0, FloatArray *X, FloatArray *dX, FloatArray *F, const FloatArray &internalForcesEBENorm, double &l, referenceLoadInputModeType rlm, int &nite, TimeStep *tNow) // // this function solve the problem of the unbalanced equilibrium // using NR scheme // // { // residual, iteration increment of solution, total external force FloatArray rhs, ddX, RT; double RRT; int neq = X->giveSize(); NM_Status status; bool converged, errorOutOfRangeFlag; #ifdef __PARALLEL_MODE #ifdef __PETSC_MODULE PetscContext *parallel_context = engngModel->givePetscContext(this->domain->giveNumber()); #endif #endif if ( engngModel->giveProblemScale() == macroScale ) { OOFEM_LOG_INFO("NRSolver: 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"); } l = 1.0; status = NM_None; this->giveLinearSolver(); // compute total load R = R+R0 RT = * R; if ( R0 ) { RT.add(*R0); } #ifdef __PARALLEL_MODE RRT = parallel_context->norm(RT); RRT *= RRT; #else RRT = RT.computeSquaredNorm(); #endif ddX.resize(neq); ddX.zero(); // Fetch the matrix before evaluating internal forces. // This is intentional, since its a simple way to drastically increase convergence for nonlinear problems. // (This old tangent is just used) engngModel->updateComponent(tNow, NonLinearLhs, domain); if ( this->prescribedDofsFlag ) { if ( !prescribedEqsInitFlag ) { this->initPrescribedEqs(); } applyConstraintsToStiffness(k); } nite = 0; do { // Compute the residual engngModel->updateComponent(tNow, InternalRhs, domain); rhs.beDifferenceOf(RT, *F); if ( this->prescribedDofsFlag ) { this->applyConstraintsToLoadIncrement(nite, k, rhs, rlm, tNow); } // convergence check converged = this->checkConvergence(RT, * F, rhs, ddX, * X, RRT, internalForcesEBENorm, nite, errorOutOfRangeFlag, tNow); if ( errorOutOfRangeFlag ) { status = NM_NoSuccess; OOFEM_WARNING2("NRSolver: Divergence reached after %d iterations", nite); break; } else if ( converged && ( nite >= minIterations ) ) { break; } else if ( nite >= nsmax ) { OOFEM_LOG_DEBUG("Maximum number of iterations reached\n"); break; } if ( nite > 0 ) { if ( ( NR_Mode == nrsolverFullNRM ) || ( ( NR_Mode == nrsolverAccelNRM ) && ( nite % MANRMSteps == 0 ) ) ) { engngModel->updateComponent(tNow, NonLinearLhs, domain); applyConstraintsToStiffness(k); } } if ( ( nite == 0 ) && ( deltaL < 1.0 ) ) { // deltaL < 1 means no increment applied, only equilibrate current state rhs.zero(); R->zero(); ddX = rhs; } else { linSolver->solve(k, & rhs, & ddX); } // // update solution // if ( this->lsFlag && ( nite > 0 ) ) { // Why not nite == 0 ? // line search LineSearchNM :: LS_status status; double eta; this->giveLineSearchSolver()->solve(X, & ddX, F, R, R0, prescribedEqs, 1.0, eta, status, tNow); } X->add(ddX); dX->add(ddX); tNow->incrementStateCounter(); // update solution state counter nite++; // iteration increment } while ( true ); // end of iteration status |= NM_Success; solved = 1; // Modify Load vector to include "quasi reaction" if ( R0 ) { for ( int i = 1; i <= numberOfPrescribedDofs; i++ ) { R->at( prescribedEqs.at(i) ) = F->at( prescribedEqs.at(i) ) - R0->at( prescribedEqs.at(i) ) - R->at( prescribedEqs.at(i) ); } } else { for ( int i = 1; i <= numberOfPrescribedDofs; i++ ) { R->at( prescribedEqs.at(i) ) = F->at( prescribedEqs.at(i) ) - R->at( prescribedEqs.at(i) ); } } this->lastReactions.resize(numberOfPrescribedDofs); #ifdef VERBOSE if (numberOfPrescribedDofs) { // print quasi reactions if direct displacement control used OOFEM_LOG_INFO("\n"); OOFEM_LOG_INFO("NRSolver: Quasi reaction table \n"); OOFEM_LOG_INFO("NRSolver: Node Dof Displacement Force\n"); double reaction; for ( int i = 1; i <= numberOfPrescribedDofs; i++ ) { reaction = R->at( prescribedEqs.at(i) ); if ( R0 ) { reaction += R0->at( prescribedEqs.at(i) ); } lastReactions.at(i) = reaction; OOFEM_LOG_INFO("NRSolver: %-15d %-15d %-+15.5e %-+15.5e\n", prescribedDofs.at(2 * i - 1), prescribedDofs.at(2 * i), X->at( prescribedEqs.at(i) ), reaction); } OOFEM_LOG_INFO("\n"); } #endif return status; }