void NOX::MeritFunction::SumOfSquares:: computeGradient(const NOX::Abstract::Group& grp, NOX::Abstract::Vector& result) const { if ( !(grp.isF()) ) { utils->err() << "ERROR: NOX::MeritFunction::SumOfSquares::computeGradient() - " << "F has not been computed yet!. Please call " << "computeF() on the group passed into this function." << std::endl; throw "NOX Error"; } if ( !(grp.isJacobian()) ) { utils->err() << "ERROR: NOX::MeritFunction::SumOfSquares::computeGradient() - " << "Jacobian has not been computed yet!. Please call " << "computeJacobian() on the group passed into this function." << std::endl; throw "NOX Error"; } NOX::Abstract::Group::ReturnType status = grp.applyJacobianTranspose(grp.getF(), result); if (status != NOX::Abstract::Group::Ok) { utils->err() << "ERROR: NOX::MeritFunction::SumOfSquares::compute" << "Gradient - applyJacobianTranspose failed!" << std::endl; throw "NOX Error"; } return; }
void NOX::MeritFunction::SumOfSquares:: computeQuadraticMinimizer(const NOX::Abstract::Group& grp, NOX::Abstract::Vector& result) const { // Clone a temporary vector if (Teuchos::is_null(tmpVecPtr)) tmpVecPtr = grp.getF().clone(NOX::ShapeCopy); // Make sure the function and Jacobian have been evaluated if ( !(grp.isF()) ) { utils->err() << "ERROR: NOX::MeritFunction::SumOfSquares::" << "computeQuadraticMinimizer() - " << "F has not been computed yet!. Please call " << "computeF() on the group passed into this function." << std::endl; throw "NOX Error"; } if ( !(grp.isJacobian()) ) { utils->err() << "ERROR: NOX::MeritFunction::SumOfSquares::" << "computeQuadraticMinimizer() - " << "Jacobian has not been computed yet!. Please call " << "computeJacobian() on the group passed into this function." << std::endl; throw "NOX Error"; } // Compute the steepest descent direction = J^T F this->computeGradient(grp, result); // Compute = J (J^T F) NOX::Abstract::Group::ReturnType status = grp.applyJacobian(result, *tmpVecPtr); if (status != NOX::Abstract::Group::Ok) { utils->err() << "ERROR: NOX::MeritFunction::SumOfSquares::" << "computeQuadraticMinimizer() - grp->applyJacobian() has failed!" << std::endl; throw "NOX Error"; } result.scale( -1.0 * result.innerProduct(result) / tmpVecPtr->innerProduct(*tmpVecPtr) ); }
double NOX::MeritFunction::SumOfSquares:: computeSlope(const NOX::Abstract::Vector& dir, const NOX::Abstract::Group& grp) const { if (Teuchos::is_null(tmpVecPtr)) tmpVecPtr = grp.getF().clone(); // If the Jacobian is not computed, approximate it with // directional derivatives. dir^T J^T F = F^T Jd if (!(grp.isJacobian())) return this->computeSlopeWithoutJacobian(dir, grp); // If the Jacobian is computed but doesn't support a gradient, // employ a different form for the inner product, eg // return <v, F> = F' * J * dir = <J'F, dir> = <g, dir> else if(!(grp.isGradient())) return this->computeSlopeWithoutJacobianTranspose(dir, grp); this->computeGradient(grp, *(tmpVecPtr.get())); return dir.innerProduct(*(tmpVecPtr.get())); }
// ************************************************************************** // *** computeForcingTerm // ************************************************************************** double NOX::Direction::Utils::InexactNewton:: computeForcingTerm(const NOX::Abstract::Group& soln, const NOX::Abstract::Group& oldsoln, int niter, const NOX::Solver::Generic& solver, double eta_last) { const std::string indent = " "; if (forcingTermMethod == Constant) { if (printing->isPrintType(NOX::Utils::Details)) { printing->out() << indent << "CALCULATING FORCING TERM" << std::endl; printing->out() << indent << "Method: Constant" << std::endl; printing->out() << indent << "Forcing Term: " << eta_k << std::endl; } if (setTolerance) paramsPtr->sublist(directionMethod).sublist("Linear Solver"). set("Tolerance", eta_k); return eta_k; } // Get linear solver current tolerance. // NOTE: These values are changing at each nonlinear iteration and // must either be updated from the parameter list each time a compute // is called or supplied during the function call! double eta_km1 = 0.0; if (eta_last < 0.0) eta_km1 = paramsPtr->sublist(directionMethod). sublist("Linear Solver").get("Tolerance", 0.0); else eta_km1 = eta_last; // Tolerance may have been adjusted in a line search algorithm so we // have to account for this. const NOX::Solver::LineSearchBased* solverPtr = 0; solverPtr = dynamic_cast<const NOX::Solver::LineSearchBased*>(&solver); if (solverPtr != 0) { eta_km1 = 1.0 - solverPtr->getStepSize() * (1.0 - eta_km1); } if (printing->isPrintType(NOX::Utils::Details)) { printing->out() << indent << "CALCULATING FORCING TERM" << std::endl; printing->out() << indent << "Method: " << method << std::endl; } if (forcingTermMethod == Type1) { if (niter == 0) { eta_k = eta_initial; } else { // Return norm of predicted F // do NOT use the following lines!! This does NOT account for // line search step length taken. // const double normpredf = 0.0; // oldsoln.getNormLastLinearSolveResidual(normpredf); // Create a new vector to be the predicted RHS if (Teuchos::is_null(predRhs)) { predRhs = oldsoln.getF().clone(ShapeCopy); } if (Teuchos::is_null(stepDir)) { stepDir = oldsoln.getF().clone(ShapeCopy); } // stepDir = X - oldX (i.e., the step times the direction) stepDir->update(1.0, soln.getX(), -1.0, oldsoln.getX(), 0); // Compute predRhs = Jacobian * step * dir if (!(oldsoln.isJacobian())) { if (printing->isPrintType(NOX::Utils::Details)) { printing->out() << "WARNING: NOX::InexactNewtonUtils::resetForcingTerm() - " << "Jacobian is out of date! Recomputing Jacobian." << std::endl; } const_cast<NOX::Abstract::Group&>(oldsoln).computeJacobian(); } oldsoln.applyJacobian(*stepDir, *predRhs); // Compute predRhs = RHSVector + predRhs (this is the predicted RHS) predRhs->update(1.0, oldsoln.getF(), 1.0); // Compute the norms double normpredf = predRhs->norm(); double normf = soln.getNormF(); double normoldf = oldsoln.getNormF(); if (printing->isPrintType(NOX::Utils::Details)) { printing->out() << indent << "Forcing Term Norm: Using L-2 Norm." << std::endl; } // Compute forcing term eta_k = fabs(normf - normpredf) / normoldf; // Some output if (printing->isPrintType(NOX::Utils::Details)) { printing->out() << indent << "Residual Norm k-1 = " << normoldf << "\n"; printing->out() << indent << "Residual Norm Linear Model k = " << normpredf << "\n"; printing->out() << indent << "Residual Norm k = " << normf << "\n"; printing->out() << indent << "Calculated eta_k (pre-bounds) = " << eta_k << std::endl; } // Impose safeguard and constraints ... const double tmp = (1.0 + sqrt(5.0)) / 2.0; const double eta_km1_alpha = pow(eta_km1, tmp); if (eta_km1_alpha > 0.1) eta_k = NOX_MAX(eta_k, eta_km1_alpha); eta_k = NOX_MAX(eta_k, eta_min); eta_k = NOX_MIN(eta_max, eta_k); } } else if (forcingTermMethod == Type2) { if (niter == 0) { eta_k = eta_initial; } else { double normf = soln.getNormF(); double normoldf = oldsoln.getNormF(); if (printing->isPrintType(NOX::Utils::Details)) { printing->out() << indent << "Forcing Term Norm: Using L-2 Norm." << std::endl; } const double residual_ratio = normf / normoldf; eta_k = gamma * pow(residual_ratio, alpha); // Some output if (printing->isPrintType(NOX::Utils::Details)) { printing->out() << indent << "Residual Norm k-1 = " << normoldf << "\n"; printing->out() << indent << "Residual Norm k = " << normf << "\n"; printing->out() << indent << "Calculated eta_k (pre-bounds) = " << eta_k << std::endl; } // Impose safeguard and constraints ... const double eta_k_alpha = gamma * pow(eta_km1, alpha); if (eta_k_alpha > 0.1) eta_k = NOX_MAX(eta_k, eta_k_alpha); eta_k = NOX_MAX(eta_k, eta_min); eta_k = NOX_MIN(eta_max, eta_k); } } // Set the new linear solver tolerance if (setTolerance) paramsPtr->sublist(directionMethod).sublist("Linear Solver"). set("Tolerance", eta_k); if (printing->isPrintType(NOX::Utils::Details)) printing->out() << indent << "Forcing Term: " << eta_k << std::endl; return eta_k; }