void BroydenOperator::runPostIterate( const NOX::Solver::Generic & solver) { // Get and update using the solver object. if( solver.getNumIterations() > 0 ) { // To consistently compute changes to the step and the yield, eg effects of // linesearch or other globalizations, we need to get and subtract the old and // new solution states and corresponding residuals const Abstract::Group & oldSolnGrp = solver.getPreviousSolutionGroup(); const Abstract::Group & solnGrp = solver.getSolutionGroup(); // Set the Step vector *workVec = solnGrp.getX(); workVec->update(-1.0, oldSolnGrp.getX(), 1.0); setStepVector( *workVec ); // Set the Yield vector *workVec = solnGrp.getF(); workVec->update(-1.0, oldSolnGrp.getF(), 1.0); setYieldVector( *workVec ); // Use of these updated vectors occurs when computeJacobian or computePreconditioner // gets called } prePostOperator.runPostIterate( solver ); return; }
NOX::StatusTest::StatusType N_NLS_NOX::Stagnation::checkStatus(const NOX::Solver::Generic& problem) { status = NOX::StatusTest::Unconverged; // First time through we don't do anything but reset the counters int niters = problem.getNumIterations(); if (niters == 0) { numSteps = 0; lastIteration = 0; convRate = 1.0; //minConvRate = 1.0; // Don't reset this. Xyce solver never does. normFInit = problem.getSolutionGroup().getNormF(); return NOX::StatusTest::Unconverged; } // Make sure we have not already counted the last nonlinear iteration. // This protects against multiple calls to checkStatus() in between // nonlinear iterations. bool isCounted = false; if (niters == lastIteration) { isCounted = true; } else lastIteration = niters; // Compute the convergenc rate and set counter appropriately if (!isCounted) { convRate = problem.getSolutionGroup().getNormF() / problem.getPreviousSolutionGroup().getNormF(); if (fabs(convRate - 1.0) <= tolerance) { if ((numSteps == 0) || (convRate < minConvRate)) minConvRate = convRate; ++numSteps ; } else numSteps = 0; } if (numSteps >= maxSteps) { double initConvRate = problem.getSolutionGroup().getNormF()/normFInit; if ((initConvRate <= 0.9) && (minConvRate <= 1.0)) { status = NOX::StatusTest::Converged; } else status = NOX::StatusTest::Failed; } return status; }
bool NOX::Solver::TensorBased::implementGlobalStrategy(NOX::Abstract::Group& newGrp, double& in_stepSize, const NOX::Solver::Generic& s) { bool ok; counter.incrementNumLineSearches(); isNewtonDirection = false; NOX::Abstract::Vector& searchDirection = *tensorVecPtr; if ((counter.getNumLineSearches() == 1) || (lsType == Newton)) { isNewtonDirection = true; searchDirection = *newtonVecPtr; } // Do line search and compute new soln. if ((lsType != Dual) || (isNewtonDirection)) ok = performLinesearch(newGrp, in_stepSize, searchDirection, s); else if (lsType == Dual) { double fTensor = 0.0; double fNew = 0.0; double tensorStep = 1.0; bool isTensorDescent = false; const Abstract::Group& oldGrp = s.getPreviousSolutionGroup(); double fprime = slopeObj.computeSlope(searchDirection, oldGrp); // Backtrack along tensor direction if it is descent direction. if (fprime < 0) { ok = performLinesearch(newGrp, in_stepSize, searchDirection, s); assert(ok); fTensor = 0.5 * newGrp.getNormF() * newGrp.getNormF(); tensorStep = in_stepSize; isTensorDescent = true; } // Backtrack along the Newton direction. ok = performLinesearch(newGrp, in_stepSize, *newtonVecPtr, s); fNew = 0.5 * newGrp.getNormF() * newGrp.getNormF(); // If backtracking on the tensor step produced a better step, then use it. if (isTensorDescent && (fTensor <= fNew)) { newGrp.computeX(oldGrp, *tensorVecPtr, tensorStep); newGrp.computeF(); } } return ok; }
bool NOX::Direction::Newton::compute(NOX::Abstract::Vector& dir, NOX::Abstract::Group& soln, const NOX::Solver::Generic& solver) { NOX::Abstract::Group::ReturnType status; // Compute F at current solution. status = soln.computeF(); if (status != NOX::Abstract::Group::Ok) NOX::Direction::Newton::throwError("compute", "Unable to compute F"); // Reset the linear solver tolerance. if (useAdjustableForcingTerm) { resetForcingTerm(soln, solver.getPreviousSolutionGroup(), solver.getNumIterations(), solver); } else { if (utils->isPrintType(Utils::Details)) { utils->out() << " CALCULATING FORCING TERM" << endl; utils->out() << " Method: Constant" << endl; utils->out() << " Forcing Term: " << eta_k << endl; } } // Compute Jacobian at current solution. status = soln.computeJacobian(); if (status != NOX::Abstract::Group::Ok) NOX::Direction::Newton::throwError("compute", "Unable to compute Jacobian"); // Compute the Newton direction status = soln.computeNewton(paramsPtr->sublist("Newton").sublist("Linear Solver")); // It didn't converge, but maybe we can recover. if ((status != NOX::Abstract::Group::Ok) && (doRescue == false)) { NOX::Direction::Newton::throwError("compute", "Unable to solve Newton system"); } else if ((status != NOX::Abstract::Group::Ok) && (doRescue == true)) { if (utils->isPrintType(NOX::Utils::Warning)) utils->out() << "WARNING: NOX::Direction::Newton::compute() - Linear solve " << "failed to achieve convergence - using the step anyway " << "since \"Rescue Bad Newton Solve\" is true " << endl; } // Set search direction. dir = soln.getNewton(); return true; }
NOX::StatusTest::StatusType LOCA::Bifurcation::PitchforkBord::StatusTest::ParameterUpdateNorm::checkStatus( const NOX::Solver::Generic& problem) { // Get solution groups from solver const NOX::Abstract::Group& soln = problem.getSolutionGroup(); const NOX::Abstract::Group& oldsoln = problem.getPreviousSolutionGroup(); // Cast soln group to pitchfork group const LOCA::Bifurcation::PitchforkBord::ExtendedGroup* pfGroupPtr = dynamic_cast<const LOCA::Bifurcation::PitchforkBord::ExtendedGroup*>(&soln); // Check that group is a pitchfork group, return converged if not if (pfGroupPtr == NULL) { paramUpdateNorm = 0.0; return NOX::StatusTest::Converged; } // Get solution vectors const LOCA::Bifurcation::PitchforkBord::ExtendedVector& x = dynamic_cast<const LOCA::Bifurcation::PitchforkBord::ExtendedVector&>(soln.getX()); const LOCA::Bifurcation::PitchforkBord::ExtendedVector& xold = dynamic_cast<const LOCA::Bifurcation::PitchforkBord::ExtendedVector&>(oldsoln.getX()); // On the first iteration, the old and current solution are the same so // we should return the test as unconverged until there is a valid // old solution (i.e. the number of iterations is greater than zero). int niters = problem.getNumIterations(); if (niters == 0) { paramUpdateNorm = 1.0e+12; status = NOX::StatusTest::Unconverged; return status; } paramUpdateNorm = fabs(x.getBifParam() - xold.getBifParam()) / (rtol*fabs(x.getBifParam()) + atol); if (paramUpdateNorm < tol) status = NOX::StatusTest::Converged; else status = NOX::StatusTest::Unconverged; return status; }
bool NOX::LineSearch::Backtrack:: compute(NOX::Abstract::Group& grp, double& step, const NOX::Abstract::Vector& dir, const NOX::Solver::Generic& s) { const Abstract::Group& oldGrp = s.getPreviousSolutionGroup(); double oldF = meritFunctionPtr->computef(oldGrp); double newF; bool isFailed = false; step = defaultStep; grp.computeX(oldGrp, dir, step); NOX::Abstract::Group::ReturnType rtype; rtype = grp.computeF(); if (rtype != NOX::Abstract::Group::Ok) { utils->err() << "NOX::LineSearch::BackTrack::compute - Unable to compute F" << std::endl; throw "NOX Error"; } newF = meritFunctionPtr->computef(grp); int nIters = 1; if (utils->isPrintType(Utils::InnerIteration)) { utils->out() << "\n" << Utils::fill(72) << "\n" << "-- Backtrack Line Search -- \n"; } NOX::StatusTest::FiniteValue checkNAN; while ( ((newF >= oldF) || (checkNAN.finiteNumberTest(newF) !=0)) && (!isFailed)) { if (utils->isPrintType(Utils::InnerIteration)) { utils->out() << std::setw(3) << nIters << ":"; utils->out() << " step = " << utils->sciformat(step); utils->out() << " old f = " << utils->sciformat(oldF); utils->out() << " new f = " << utils->sciformat(newF); utils->out() << std::endl; } nIters ++; step = step * reductionFactor; if ((step < minStep) || (nIters > maxIters)) { isFailed = true; step = recoveryStep; } grp.computeX(oldGrp, dir, step); rtype = grp.computeF(); if (rtype != NOX::Abstract::Group::Ok) { utils->err() << "NOX::LineSearch::BackTrack::compute - Unable to compute F" << std::endl; throw "NOX Error"; } newF = meritFunctionPtr->computef(grp); } if (utils->isPrintType(Utils::InnerIteration)) { utils->out() << std::setw(3) << nIters << ":"; utils->out() << " step = " << utils->sciformat(step); utils->out() << " old f = " << utils->sciformat(oldF); utils->out() << " new f = " << utils->sciformat(newF); if (isFailed) utils->out() << " (USING RECOVERY STEP!)" << std::endl; else utils->out() << " (STEP ACCEPTED!)" << std::endl; utils->out() << Utils::fill(72) << "\n" << std::endl; } return (!isFailed); }
StatusType NormWRMS:: checkStatus(const NOX::Solver::Generic& problem, NOX::StatusTest::CheckType checkType) { if (checkType == NOX::StatusTest::None) { status = Unevaluated; value = 1.0e+12; return status; } status = Unconverged; const Abstract::Group& soln = problem.getSolutionGroup(); const Abstract::Group& oldsoln = problem.getPreviousSolutionGroup(); const Abstract::Vector& x = soln.getScaledX(); // On the first iteration, the old and current solution are the same so // we should return the test as unconverged until there is a valid // old solution (i.e. the number of iterations is greater than zero). int niters = problem.getNumIterations(); if (niters == 0) { status = Unconverged; value = 1.0e+12; return status; } // **** Begin check for convergence criteria #1 **** // Create the working vectors if this is the first time this // operator is called. if (Teuchos::is_null(u)) u = x.clone(NOX::ShapeCopy); if (Teuchos::is_null(v)) v = x.clone(NOX::ShapeCopy); // Create the weighting vector u = RTOL |x| + ATOL // |x| is evaluated at the old time step v->abs(oldsoln.getScaledX()); if (atolIsScalar) { u->init(1.0); u->update(rtol, *v, atol); } else { u->update(rtol, *v, 1.0, *atolVec, 0.0); } // v = 1/u (elementwise) v->reciprocal(*u); // u = x - oldx (i.e., the update) u->update(1.0, x, -1.0, oldsoln.getScaledX(), 0.0); // u = Cp * u @ v (where @ represents an elementwise multiply) u->scale(*v); // Turn off implicit scaling of norm if the vector supports it Teuchos::RCP<NOX::Abstract::ImplicitWeighting> iw_u; iw_u = Teuchos::rcp_dynamic_cast<NOX::Abstract::ImplicitWeighting>(u,false); bool saved_status = false; if (nonnull(iw_u) && m_disable_implicit_weighting) { saved_status = iw_u->getImplicitWeighting(); iw_u->setImplicitWeighting(false); } // tmp = factor * sqrt (u * u / N) value = u->norm() * factor / sqrt(static_cast<double>(u->length())); // Set the implicit scaling back to original value if (nonnull(iw_u) && m_disable_implicit_weighting) iw_u->setImplicitWeighting(saved_status); StatusType status1 = Unconverged; if (value < tolerance) status1 = Converged; // **** Begin check for convergence criteria #2 **** StatusType status2 = Unconverged; // Determine if the Generic solver is a LineSearchBased solver // If it is not then return a "Converged" status const Solver::Generic* test = 0; test = dynamic_cast<const Solver::LineSearchBased*>(&problem); if (test == 0) { status2 = Converged; } else { printCriteria2Info = true; computedStepSize = (dynamic_cast<const Solver::LineSearchBased*>(&problem))->getStepSize(); if (computedStepSize >= alpha) status2 = Converged; } // **** Begin check for convergence criteria #3 **** // First time through, make sure the output parameter list exists. // Since the list is const, a sublist call to a non-existent sublist // throws an error. Therefore we have to check the existence of each // sublist before we call it. const Teuchos::ParameterList& p = problem.getList(); if (niters == 1) { if (p.isSublist("Direction")) { if (p.sublist("Direction").isSublist("Newton")) { if (p.sublist("Direction").sublist("Newton").isSublist("Linear Solver")) { if (p.sublist("Direction").sublist("Newton").sublist("Linear Solver").isSublist("Output")) { const Teuchos::ParameterList& list = p.sublist("Direction").sublist("Newton").sublist("Linear Solver").sublist("Output"); if (Teuchos::isParameterType<double>(list, "Achieved Tolerance")) { printCriteria3Info = true; } } } } } } StatusType status3 = Converged; if (printCriteria3Info) { achievedTol = const_cast<Teuchos::ParameterList&>(problem.getList()). sublist("Direction").sublist("Newton").sublist("Linear Solver"). sublist("Output").get("Achieved Tolerance", -1.0); status3 = (achievedTol <= beta) ? Converged : Unconverged; } // Determine status of test if ((status1 == Converged) && (status2 == Converged) && (status3 == Converged)) status = Converged; return status; }
NOX::StatusTest::StatusType LOCA::Bifurcation::TPBord::StatusTest::NullVectorNormWRMS::checkStatus( const NOX::Solver::Generic& problem) { // Get solution groups from solver const NOX::Abstract::Group& soln = problem.getSolutionGroup(); const NOX::Abstract::Group& oldsoln = problem.getPreviousSolutionGroup(); // Cast soln group to turning point group const LOCA::Bifurcation::TPBord::ExtendedGroup* tpGroupPtr = dynamic_cast<const LOCA::Bifurcation::TPBord::ExtendedGroup*>(&soln); // Check that group is a turning point group, return converged if not if (tpGroupPtr == NULL) { normWRMS = 0.0; return NOX::StatusTest::Converged; } // Get solution vectors const LOCA::Bifurcation::TPBord::ExtendedVector& x = dynamic_cast<const LOCA::Bifurcation::TPBord::ExtendedVector&>(soln.getX()); const LOCA::Bifurcation::TPBord::ExtendedVector& xold = dynamic_cast<const LOCA::Bifurcation::TPBord::ExtendedVector&>(oldsoln.getX()); // Get null vectors const NOX::Abstract::Vector& y = x.getNullVec(); const NOX::Abstract::Vector& yold = xold.getNullVec(); // temporary vectors NOX::Abstract::Vector *u = y.clone(NOX::ShapeCopy); NOX::Abstract::Vector *v = yold.clone(NOX::ShapeCopy); // On the first iteration, the old and current solution are the same so // we should return the test as unconverged until there is a valid // old solution (i.e. the number of iterations is greater than zero). int niters = problem.getNumIterations(); if (niters == 0) { normWRMS = 1.0e+12; status = NOX::StatusTest::Unconverged; return status; } // Fill vector with 1's u->init(1.0); // Compute |y| v->abs(y); // Overwrite u with rtol*|y| + atol u->update(rtol, *v, atol); // Overwrite v with 1/(rtol*|y| + atol) v->reciprocal(*u); // Overwrite u with y-yold u->update(1.0, y, -1.0, yold, 0.0); // Overwrite u with (y-yold)/(rtol*|y| + atol) u->scale(*v); // Compute sqrt( (y-yold)/(rtol*|y| + atol) ) / sqrt(N) normWRMS = u->norm() / sqrt(static_cast<double>(u->length())); if (normWRMS < tol) status = NOX::StatusTest::Converged; else status = NOX::StatusTest::Unconverged; delete u; delete v; return status; }
bool NOX::Solver::TensorBased::performLinesearch(NOX::Abstract::Group& newSoln, double& in_stepSize, const NOX::Abstract::Vector& lsDir, const NOX::Solver::Generic& s) { if (print.isPrintType(NOX::Utils::InnerIteration)) { utilsPtr->out() << "\n" << NOX::Utils::fill(72) << "\n"; utilsPtr->out() << "-- Tensor Line Search ("; if (lsType == Curvilinear) utilsPtr->out() << "Curvilinear"; else if (lsType == Standard) utilsPtr->out() << "Standard"; else if (lsType == FullStep) utilsPtr->out() << "Full Step"; else if (lsType == Dual) utilsPtr->out() << "Dual"; utilsPtr->out() << ") -- " << std::endl; } // Local variables bool isFailed = false; bool isAcceptable = false; bool isFirstPass = true; std::string message = "(STEP ACCEPTED!)"; // Set counters int lsIterations = 1; // Get Old f const Abstract::Group& oldSoln = s.getPreviousSolutionGroup(); double fOld = 0.5 * oldSoln.getNormF() * oldSoln.getNormF(); // Compute first trial point and its function value in_stepSize = defaultStep; newSoln.computeX(oldSoln, lsDir, in_stepSize); newSoln.computeF(); double fNew = 0.5 * newSoln.getNormF() * newSoln.getNormF(); // Stop here if only using the full step if (lsType == FullStep) { print.printStep(lsIterations, in_stepSize, fOld, fNew, message); return (!isFailed); } // Compute directional derivative double fprime; if ((lsType == Curvilinear) && !(isNewtonDirection)) fprime = slopeObj.computeSlope(*newtonVecPtr, oldSoln); else fprime = slopeObj.computeSlope(lsDir, oldSoln); numJvMults++; // computeSlope() has J*v inside of it // Compute the convergence criteria for the line search double threshold = fOld + alpha*in_stepSize*fprime; isAcceptable = (fNew < threshold); // Update counter and temporarily hold direction if a linesearch is needed if (!isAcceptable) { counter.incrementNumNonTrivialLineSearches(); *tmpVecPtr = lsDir; } // Iterate until the trial point is accepted.... while (!isAcceptable) { // Check for linesearch failure if (lsIterations > maxIters) { isFailed = true; message = "(FAILED - Max Iters)"; break; } print.printStep(lsIterations, in_stepSize, fOld, fNew); // Is the full tensor step a descent direction? If not, switch to Newton if (isFirstPass && (!isNewtonDirection) && (fprime >= 0) && (lsType != Curvilinear) ) { *tmpVecPtr = *newtonVecPtr; fprime = slopeObj.computeSlope(*tmpVecPtr, oldSoln); numJvMults++; if (utilsPtr->isPrintType(NOX::Utils::Details)) utilsPtr->out() << " Switching to Newton step. New fprime = " << utilsPtr->sciformat(fprime, 6) << std::endl; } else { in_stepSize = selectLambda(fNew, fOld, fprime, in_stepSize); } isFirstPass = false; // Check for linesearch failure if (in_stepSize < minStep) { isFailed = true; message = "(FAILED - Min Step)"; break; } // Update the number of linesearch iterations counter.incrementNumIterations(); lsIterations ++; // Compute new trial point and its function value if ((lsType == Curvilinear) && !(isNewtonDirection)) { computeCurvilinearStep(*tmpVecPtr, oldSoln, s, in_stepSize); // Note: oldSoln is needed above to get correct preconditioner newSoln.computeX(oldSoln, *tmpVecPtr, 1.0); } else { newSoln.computeX(oldSoln, *tmpVecPtr, in_stepSize); } newSoln.computeF(); fNew = 0.5 * newSoln.getNormF() * newSoln.getNormF(); // Recompute convergence criteria based on new step threshold = fOld + alpha*in_stepSize*fprime; isAcceptable = (fNew < threshold); } if (isFailed) { counter.incrementNumFailedLineSearches(); if (recoveryStepType == Constant) { in_stepSize = recoveryStep; if (in_stepSize == 0.0) { newSoln = oldSoln; newSoln.computeF(); fNew = fOld; } else { // Update the group using recovery step if ((lsType == Curvilinear) && !(isNewtonDirection)) { computeCurvilinearStep(*tmpVecPtr, oldSoln, s, in_stepSize); // Note: oldSoln is needed above to get correct preconditioner newSoln.computeX(oldSoln, *tmpVecPtr, 1.0); } else { newSoln.computeX(oldSoln, *tmpVecPtr, in_stepSize); } //newSoln.computeX(oldSoln, lsDir, in_stepSize); newSoln.computeF(); fNew = 0.5 * newSoln.getNormF() * newSoln.getNormF(); message = "(USING RECOVERY STEP!)"; } } else message = "(USING LAST STEP!)"; } print.printStep(lsIterations, in_stepSize, fOld, fNew, message); counter.setValues(paramsPtr->sublist("Line Search")); return (!isFailed); }
bool NOX::Solver::TensorBased::computeTensorDirection(NOX::Abstract::Group& soln, const NOX::Solver::Generic& solver) { NOX::Abstract::Group::ReturnType dir_status; Teuchos::ParameterList& linearParams = paramsPtr->sublist("Direction"). sublist(paramsPtr->sublist("Direction"). get("Method","Tensor")). sublist("Linear Solver"); // Compute F at current solution. dir_status = soln.computeF(); if (dir_status != NOX::Abstract::Group::Ok) throwError("computeTensorDirection", "Unable to compute F"); // Compute Jacobian at current solution. dir_status = soln.computeJacobian(); if (dir_status != NOX::Abstract::Group::Ok) throwError("computeTensorDirection", "Unable to compute Jacobian"); // Begin processing for the tensor step, if necessary. double sDotS = 0.0; int tempVal1 = 0; if ((nIter > 0) && (requestedBaseStep == TensorStep)) { // Compute the tensor term s = x_{k-1} - x_k *sVecPtr = soln.getX(); sVecPtr->update(1.0, solver.getPreviousSolutionGroup().getX(), -1.0); double normS = sVecPtr->norm(); sDotS = normS * normS; // Form the tensor term a = (F_{k-1} - F_k - J*s) / (s^T s)^2 soln.applyJacobian(*sVecPtr, *aVecPtr); numJvMults++; aVecPtr->update(1.0, solver.getPreviousSolutionGroup().getF(), -1.0); aVecPtr->update(-1.0, soln.getF(), 1.0); if (sDotS != 0) aVecPtr->scale(1.0 / (sDotS * sDotS)); // Save old Newton step as initial guess to second system *tmpVecPtr = *newtonVecPtr; tmpVecPtr->scale(-1.0); // Rewrite to avoid this? // Compute residual of linear system using initial guess... soln.applyJacobian(*tmpVecPtr, *residualVecPtr); numJvMults++; residualVecPtr->update(1.0, solver.getPreviousSolutionGroup().getF(),-1.0); double residualNorm = residualVecPtr->norm(); #if DEBUG_LEVEL > 0 double tmpVecNorm = tmpVecPtr->norm(); double residualNormRel = residualNorm / solver.getPreviousSolutionGroup().getNormF(); if (utilsPtr->isPrintType(NOX::Utils::Details)) { utilsPtr->out() << " Norm of initial guess: " << utilsPtr->sciformat(tmpVecNorm, 6) << std::endl; utilsPtr->out() << " initg norm of model residual = " << utilsPtr->sciformat(residualNorm, 6) << " (abs) " << utilsPtr->sciformat(residualNormRel, 6) << " (rel)" << std::endl; } #endif // Save some parameters and use them later... double tol = linearParams.get("Tolerance", 1e-4); double relativeResidual = residualNorm / solver.getPreviousSolutionGroup().getNormF(); // Decide whether to use initial guess... bool isInitialGuessGood = false; #ifdef USE_INITIAL_GUESS_LOGIC if (relativeResidual < 1.0) { if (utilsPtr->isPrintType(NOX::Utils::Details)) utilsPtr->out() << " Initial guess is good..." << std::endl; isInitialGuessGood = true; // RPP - Brett please make sure the line below is correct. *tensorVecPtr = *tmpVecPtr; double newTol = tol / relativeResidual; if (newTol > 0.99) newTol = 0.99; // force at least one iteration linearParams.set("Tolerance", newTol); if (utilsPtr->isPrintType(NOX::Utils::Details)) utilsPtr->out() << " Setting tolerance to " << utilsPtr->sciformat(newTol,6) << std::endl; } else #endif // USE_INITIAL_GUESS_LOGIC { //utilsPtr->out() << " Initial guess is BAD... do not use!\n"; isInitialGuessGood = false; *residualVecPtr = solver.getPreviousSolutionGroup().getF(); } // Compute the term inv(J)*Fp.... tmpVecPtr->init(0.0); dir_status = soln.applyJacobianInverse(linearParams, *residualVecPtr, *tmpVecPtr); // If it didn't converge, maybe we can recover. if (dir_status != NOX::Abstract::Group::Ok) { if (doRescue == false) throwError("computeTensorDirection", "Unable to apply Jacobian inverse"); else if ((doRescue == true) && (utilsPtr->isPrintType(NOX::Utils::Warning))) utilsPtr->out() << "WARNING: NOX::Solver::TensorBased::computeTensorDirection() - " << "Linear solve failed to achieve convergence - " << "using the step anyway " << "since \"Rescue Bad Newton Solve\" is true." << std::endl; } // Continue processing #ifdef USE_INITIAL_GUESS_LOGIC if (isInitialGuessGood) { tmpVecPtr->update(1.0, *tensorVecPtr, 1.0); linearParams.set("Tolerance", tol); } #endif // Save iteration count for comparison later if (linearParams.sublist("Output"). isParameter("Number of Linear Iterations")) tempVal1 = linearParams.sublist("Output"). get("Number of Linear Iterations",0); #if DEBUG_LEVEL > 0 // Compute residual of linear system with initial guess... soln.applyJacobian(*tmpVecPtr, *residualVecPtr); numJvMults++; residualVec.update(-1.0, solver.getPreviousSolutionGroup().getF(),1.0); double residualNorm2 = residualVec.norm(); double residualNorm2Rel = residualNorm2 / solver.getPreviousSolutionGroup().getNormF(); if (utilsPtr->isPrintType(NOX::Utils::Details)) utilsPtr->out() << " jifp norm of model residual = " << utilsPtr->sciformat(residualNorm2, 6) << " (abs) " << utilsPtr->sciformat(residualNorm2Rel, 6) << " (rel)" << std::endl; #endif } // Compute the Newton direction dir_status = soln.computeNewton(linearParams); // If it didn't converge, maybe we can recover. if (dir_status != NOX::Abstract::Group::Ok) { if (doRescue == false) throwError("computeTensorDirection", "Unable to apply Jacobian inverse"); else if ((doRescue == true) && (utilsPtr->isPrintType(NOX::Utils::Warning))) utilsPtr->out() << "WARNING: NOX::Solver::TensorBased::computeTensorDirection() - " << "Linear solve failed to achieve convergence - " << "using the step anyway " << "since \"Rescue Bad Newton Solve\" is true." << std::endl; } // Set Newton direction *newtonVecPtr = soln.getNewton(); // Update counter int tempVal2 = 0; if (linearParams.sublist("Output"). isParameter("Number of Linear Iterations")) tempVal2 = linearParams.sublist("Output"). get("Number of Linear Iterations",0); numJ2vMults += (tempVal1 > tempVal2) ? tempVal1 : tempVal2; #ifdef CHECK_RESIDUALS printDirectionInfo("newtonVec", *newtonVecPtr, soln, false); #endif // CHECK_RESIDUALS // Continue processing the tensor step, if necessary if ((nIter > 0) && (requestedBaseStep == TensorStep)) { // Form the term inv(J)*a... (note that a is not multiplied by 2) // The next line does not work in some implementations for some reason //tmpVec.update(1.0, newtonVec, -1.0, sVec, 1.0); tmpVecPtr->update(1.0, *newtonVecPtr, 1.0); tmpVecPtr->update(-1.0, *sVecPtr, 1.0); if (sDotS != 0.0) tmpVecPtr->scale( 1.0 / (sDotS * sDotS)); // Calculate value of beta sTinvJF = -sVecPtr->innerProduct(*newtonVecPtr); sTinvJa = sVecPtr->innerProduct(*tmpVecPtr); double qval = 0; double lambdaBar = 1; beta = calculateBeta(sTinvJa, 1.0, sTinvJF, qval, lambdaBar); double sVecNorm = sVecPtr->norm(); double aVecNorm = aVecPtr->norm(); if (utilsPtr->isPrintType(NOX::Utils::Details)) { utilsPtr->out() << " sTinvJF = " << utilsPtr->sciformat(sTinvJF, 6) << " sTinvJa = " << utilsPtr->sciformat(sTinvJa, 6) << std::endl; utilsPtr->out() << " norm(s) = " << utilsPtr->sciformat(sVecNorm, 6) << " norm(a) = " << utilsPtr->sciformat(aVecNorm, 6) << std::endl; } if (useModifiedMethod) { double alpha2 = lambdaBar; if (utilsPtr->isPrintType(NOX::Utils::Details)) utilsPtr->out() << " Beta = " << utilsPtr->sciformat(beta, 6) << " Alpha2 = " << utilsPtr->sciformat(alpha2, 6) << std::endl; if (alpha2 != 1.0) { if (utilsPtr->isPrintType(NOX::Utils::Details)) utilsPtr->out() << " *** Scaling tensor term a ***" << std::endl; aVecPtr->scale(alpha2); tmpVecPtr->scale(alpha2); sTinvJa *= alpha2; beta /= alpha2; lambdaBar = 1.0; qval = 0; } } // Form the tensor step tensorVecPtr->update(1.0, *newtonVecPtr, -beta*beta, *tmpVecPtr, 0.0); #ifdef CHECK_RESIDUALS printDirectionInfo("tensorVec", *tensorVecPtr, soln, true); #endif // CHECK_RESIDUALS #if DEBUG_LEVEL > 0 double sDotT = tensorVecPtr->innerProduct(sVec); if (utilsPtr->isPrintType(NOX::Utils::Details)) utilsPtr->out() << " Beta = " << utilsPtr->sciformat(beta, 6) << " std = " << utilsPtr->sciformat(sDotT, 6) << " qval = " << utilsPtr->sciformat(qval, 2) << " lambdaBar = " << lambdaBar << std::endl; #endif } else *tensorVecPtr = *newtonVecPtr; return true; }