NOX_TSF_Group.C
Go to the documentation of this file.
00001 // $Id$ 
00002 // $Source$ 
00003 
00004 //@HEADER
00005 // ************************************************************************
00006 // 
00007 //            NOX: An Object-Oriented Nonlinear Solver Package
00008 //                 Copyright (2002) Sandia Corporation
00009 // 
00010 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00011 // license for use of this work by or on behalf of the U.S. Government.
00012 // 
00013 // This library is free software; you can redistribute it and/or modify
00014 // it under the terms of the GNU Lesser General Public License as
00015 // published by the Free Software Foundation; either version 2.1 of the
00016 // License, or (at your option) any later version.
00017 //  
00018 // This library is distributed in the hope that it will be useful, but
00019 // WITHOUT ANY WARRANTY; without even the implied warranty of
00020 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00021 // Lesser General Public License for more details.
00022 //                                                                                 
00023 // You should have received a copy of the GNU Lesser General Public
00024 // License along with this library; if not, write to the Free Software
00025 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00026 // USA                                                                                
00027 // Questions? Contact Tammy Kolda (tgkolda@sandia.gov) or Roger Pawlowski
00028 // (rppawlo@sandia.gov), Sandia National Laboratories.
00029 // 
00030 // ************************************************************************
00031 //@HEADER
00032 
00033 #include "NOX_Common.H"
00034 #include "NOX_TSF_Group.H"  // class definition
00035 #include "Teuchos_MPIComm.hpp"
00036 #include "SundanceOut.hpp"
00037 
00038 
00039 using namespace Sundance;
00040 
00041 NOX::TSF::Group::Group(const TSFExtended::Vector<double>& initcond, 
00042   const TSFExtended::NonlinearOperator<double>& nonlinOp,
00043   const TSFExtended::LinearSolver<double>& linsolver) 
00044   :
00045   precision(3),  // 3 digits of accuracy is default
00046   xVector(initcond, precision, DeepCopy),
00047   fVector(xVector, precision, ShapeCopy),
00048   newtonVector(xVector, precision, ShapeCopy),
00049   gradientVector(xVector, precision, ShapeCopy),
00050   solver(linsolver),
00051   jacobian(),
00052   nonlinearOp(nonlinOp),
00053   normF(0.0)
00054 {  
00055   nonlinearOp.setEvalPt(xVector.getTSFVector());
00056   resetIsValid();
00057 }
00058 
00059 NOX::TSF::Group::Group(const TSFExtended::NonlinearOperator<double>& nonlinOp,
00060   const TSFExtended::LinearSolver<double>& linsolver) 
00061   :
00062   precision(3), // 3 digits of accuracy is default
00063   xVector(nonlinOp.getInitialGuess(), precision, DeepCopy),
00064   fVector(xVector, precision, ShapeCopy),
00065   newtonVector(xVector, precision, ShapeCopy),
00066   gradientVector(xVector, precision, ShapeCopy),
00067   solver(linsolver),
00068   jacobian(),
00069   nonlinearOp(nonlinOp),
00070   normF(0.0)
00071 {  
00072   nonlinearOp.setEvalPt(xVector.getTSFVector());
00073   resetIsValid();
00074 }
00075 
00076 NOX::TSF::Group::Group(const TSFExtended::Vector<double>& initcond, 
00077   const TSFExtended::NonlinearOperator<double>& nonlinOp,
00078   const TSFExtended::LinearSolver<double>& linsolver,
00079   int numdigits) 
00080   :
00081   precision(numdigits),
00082   xVector(initcond, precision, DeepCopy),
00083   fVector(xVector, precision, ShapeCopy),
00084   newtonVector(xVector, precision, ShapeCopy),
00085   gradientVector(xVector, precision, ShapeCopy),
00086   solver(linsolver),
00087   jacobian(),
00088   nonlinearOp(nonlinOp),
00089   normF(0.0)
00090 {  
00091   nonlinearOp.setEvalPt(xVector.getTSFVector());
00092   resetIsValid();
00093 }
00094 
00095 NOX::TSF::Group::Group(const TSFExtended::NonlinearOperator<double>& nonlinOp,
00096   const TSFExtended::LinearSolver<double>& linsolver,
00097   int numdigits) 
00098   :
00099   precision(numdigits),
00100   xVector(nonlinOp.getInitialGuess(), precision, DeepCopy),
00101   fVector(xVector, precision, ShapeCopy),
00102   newtonVector(xVector, precision, ShapeCopy),
00103   gradientVector(xVector, precision, ShapeCopy),
00104   solver(linsolver),
00105   jacobian(),
00106   nonlinearOp(nonlinOp),
00107   normF(0.0)
00108 {  
00109   nonlinearOp.setEvalPt(xVector.getTSFVector());
00110   resetIsValid();
00111 }
00112 
00113 
00114 NOX::TSF::Group::Group(const NOX::TSF::Group& source, NOX::CopyType type) :
00115   precision(source.precision),
00116   xVector(source.xVector, precision, type), 
00117   fVector(source.fVector, precision, type),  
00118   newtonVector(source.newtonVector, precision, type),
00119   gradientVector(source.gradientVector, precision, type),
00120   solver(source.solver),
00121   jacobian(source.jacobian),
00122   nonlinearOp(source.nonlinearOp),
00123   isValidF(false),
00124   isValidJacobian(false),
00125   isValidGradient(false),
00126   isValidNewton(false),
00127   normF(0.0)
00128 {
00129   switch (type) 
00130   {
00131     
00132     case NOX::DeepCopy:
00133     
00134       isValidF = source.isValidF;
00135       isValidGradient = source.isValidGradient;
00136       isValidNewton = source.isValidNewton;
00137       isValidJacobian = source.isValidJacobian;
00138       normF = source.normF;
00139       break;
00140 
00141     case NOX::ShapeCopy:
00142       resetIsValid();
00143       normF = 0.0;
00144       break;
00145 
00146     default:
00147       Out::os() << "NOX:TSF::Group - invalid CopyType for copy constructor." << std::endl;
00148       throw "NOX TSF Error";
00149   }
00150 
00151 }
00152 
00153 NOX::TSF::Group::~Group() 
00154 {
00155 }
00156 
00157 void NOX::TSF::Group::resetIsValid() //private
00158 {
00159   isValidF = false;
00160   isValidJacobian = false;
00161   isValidGradient = false;
00162   isValidNewton = false;
00163 }
00164 
00165 #ifdef TRILINOS_6
00166 NOX::Abstract::Group* NOX::TSF::Group::clone(NOX::CopyType type) const 
00167 {
00168   return new NOX::TSF::Group(*this, type);
00169 }
00170 #else
00171 RCP<NOX::Abstract::Group> NOX::TSF::Group::clone(NOX::CopyType type) const 
00172 {
00173   return rcp(new NOX::TSF::Group(*this, type));
00174 }
00175 #endif
00176 
00177 NOX::Abstract::Group& NOX::TSF::Group::operator=(const NOX::Abstract::Group& source)
00178 {
00179   return operator=(dynamic_cast<const NOX::TSF::Group&> (source));
00180 }
00181 
00182 NOX::Abstract::Group& NOX::TSF::Group::operator=(const NOX::TSF::Group& source)
00183 {
00184   if (this != &source) 
00185   {
00186 
00187     // Deep Copy of the xVector
00188     xVector = source.xVector;
00189     nonlinearOp = source.nonlinearOp;
00190     solver = source.solver;
00191     jacobian = source.jacobian;
00192     precision = source.precision;
00193 
00194     // Update the isValidVectors
00195     isValidF = source.isValidF;
00196     isValidGradient = source.isValidGradient;
00197     isValidNewton = source.isValidNewton;
00198     isValidJacobian = source.isValidJacobian;
00199     
00200     // Only copy vectors that are valid
00201     if (isValidF) 
00202     {
00203       fVector = source.fVector;
00204       normF = source.normF;
00205     }
00206 
00207     if (isValidGradient)
00208       gradientVector = source.gradientVector;
00209     
00210     if (isValidNewton)
00211       newtonVector = source.newtonVector;
00212     
00213     if (isValidJacobian)
00214       jacobian = source.jacobian;
00215   }
00216   return *this;
00217 }
00218 
00219 void NOX::TSF::Group::setX(const NOX::Abstract::Vector& y) 
00220 {
00221   setX(dynamic_cast<const NOX::TSF::Vector&> (y));
00222 }
00223 
00224 void NOX::TSF::Group::setX(const NOX::TSF::Vector& y) 
00225 {
00226   resetIsValid();
00227   nonlinearOp.setEvalPt(y.getTSFVector());
00228   xVector = y;
00229 }
00230 
00231 void NOX::TSF::Group::computeX(const NOX::Abstract::Group& grp, 
00232   const NOX::Abstract::Vector& d, 
00233   double step) 
00234 {
00235   // Cast to appropriate type, then call the "native" computeX
00236   const Group& tsfgrp = dynamic_cast<const NOX::TSF::Group&> (grp);
00237   const Vector& tsfd = dynamic_cast<const NOX::TSF::Vector&> (d);
00238   computeX(tsfgrp, tsfd, step); 
00239 }
00240 
00241 void NOX::TSF::Group::computeX(const Group& grp, const Vector& d, double step) 
00242 {
00243   resetIsValid();
00244   xVector.update(1.0, grp.xVector, step, d);
00245 }
00246 
00247 NOX::Abstract::Group::ReturnType NOX::TSF::Group::computeF() 
00248 {
00249  
00250   if (verb() > 2)
00251   {
00252     Out::os() << "calling computeF()" << std::endl;
00253   }
00254 
00255   if (isValidF)
00256   {
00257     if (verb() > 2)
00258     {
00259       Out::os() << "reusing F" << std::endl;
00260     }
00261     return NOX::Abstract::Group::Ok;
00262   }
00263   else
00264   {
00265     if (verb() > 2)
00266     {
00267       Out::os() << "computing new F" << std::endl;
00268     }
00269     nonlinearOp.setEvalPt(xVector.getTSFVector());
00270     fVector = nonlinearOp.getFunctionValue();
00271     isValidF = true;
00272     normF = fVector.norm();
00273   }
00274 
00275   return (isValidF) ? (NOX::Abstract::Group::Ok) : (NOX::Abstract::Group::Failed);
00276 }
00277 
00278 NOX::Abstract::Group::ReturnType NOX::TSF::Group::computeJacobian() 
00279 {
00280 
00281   if (verb() > 2)
00282   {
00283     Out::os() << "calling computeJ()" << std::endl;
00284   }
00285 
00286   // Skip if the Jacobian is already valid
00287   if (isValidJacobian)
00288   {
00289     return NOX::Abstract::Group::Ok;
00290   }
00291   else
00292   {
00293     nonlinearOp.setEvalPt(xVector.getTSFVector());
00294     jacobian = nonlinearOp.getJacobian();
00295 
00296     isValidJacobian = true;
00297   }
00298   return (isValidJacobian) ? (NOX::Abstract::Group::Ok) : (NOX::Abstract::Group::Failed);
00299 }
00300 
00301 NOX::Abstract::Group::ReturnType NOX::TSF::Group::computeGradient() 
00302 {
00303   if (verb() > 2)
00304   {
00305     Out::os() << "calling computeGrad()" << std::endl;
00306   }
00307   if (isValidGradient)
00308   {
00309     return NOX::Abstract::Group::Ok;
00310   }
00311   else
00312   {
00313     if (!isF()) 
00314     {
00315       Out::os() << "ERROR: NOX::TSF::Group::computeGrad() - F is out of date wrt X!" << std::endl;
00316       return NOX::Abstract::Group::BadDependency;
00317     }
00318 
00319     if (!isJacobian()) 
00320     {
00321       Out::os() << "ERROR: NOX::TSF::Group::computeGrad() - Jacobian is out of date wrt X!" << std::endl;
00322       return NOX::Abstract::Group::BadDependency;
00323     }
00324   
00325     // Compute Gradient = J' * F
00326 
00327     NOX::Abstract::Group::ReturnType status 
00328       = applyJacobianTranspose(fVector,gradientVector);
00329     isValidGradient = (status == NOX::Abstract::Group::Ok);
00330 
00331     // Return result
00332     return status;
00333   }
00334 }
00335 
00336 NOX::Abstract::Group::ReturnType 
00337 NOX::TSF::Group::computeNewton(Teuchos::ParameterList& p) 
00338 {
00339   if (isNewton())
00340   {
00341     return NOX::Abstract::Group::Ok;
00342   }
00343   else
00344   {
00345     if (!isF()) 
00346     {
00347       Out::os() << "ERROR: NOX::Example::Group::computeNewton() - invalid F" 
00348            << std::endl;
00349       throw "NOX Error";
00350     }
00351 
00352     if (!isJacobian()) 
00353     {
00354       Out::os() << "ERROR: NOX::Example::Group::computeNewton() - invalid Jacobian" << std::endl;
00355       throw "NOX Error";
00356     }
00357 
00358 /*
00359     if (p.isParameter("Tolerance"))
00360     {
00361       double tol = p.get("Tolerance", tol);
00362       solver.updateTolerance(tol);
00363     }
00364 */
00365 
00366     NOX::Abstract::Group::ReturnType status 
00367       = applyJacobianInverse(p, fVector, newtonVector);
00368     isValidNewton = (status == NOX::Abstract::Group::Ok);
00369 
00370     
00371     // Scale soln by -1
00372     newtonVector.scale(-1.0);
00373 
00374     if (verb() > 0)
00375     {
00376       Out::os() << "newton step" << std::endl;
00377       newtonVector.getTSFVector().print(Out::os());
00378     }
00379       
00380     // Return solution
00381     return status;
00382   }
00383 }
00384 
00385 
00386 NOX::Abstract::Group::ReturnType 
00387 NOX::TSF::Group::applyJacobian(const Abstract::Vector& input, 
00388   NOX::Abstract::Vector& result) const
00389 {
00390   const NOX::TSF::Vector& tsfinput = dynamic_cast<const NOX::TSF::Vector&> (input);
00391   NOX::TSF::Vector& tsfresult = dynamic_cast<NOX::TSF::Vector&> (result);
00392   return applyJacobian(tsfinput, tsfresult);
00393 }
00394 
00395 NOX::Abstract::Group::ReturnType 
00396 NOX::TSF::Group::applyJacobian(const NOX::TSF::Vector& input, 
00397   NOX::TSF::Vector& result) const
00398 {
00399   // Check validity of the Jacobian
00400   if (!isJacobian()) 
00401   {
00402     return NOX::Abstract::Group::BadDependency;
00403   }
00404   else
00405   {
00406     // Compute result = J * input
00407     jacobian.apply(input.getTSFVector(),result.getTSFVector());
00408     return NOX::Abstract::Group::Ok;
00409   }
00410 }
00411 
00412 NOX::Abstract::Group::ReturnType 
00413 NOX::TSF::Group::applyJacobianTranspose(const NOX::Abstract::Vector& input, 
00414   NOX::Abstract::Vector& result) const
00415 {
00416   const NOX::TSF::Vector& tsfinput = dynamic_cast<const NOX::TSF::Vector&> (input);
00417   NOX::TSF::Vector& tsfresult = dynamic_cast<NOX::TSF::Vector&> (result);
00418   return applyJacobianTranspose(tsfinput, tsfresult);
00419 }
00420 
00421 NOX::Abstract::Group::ReturnType 
00422 NOX::TSF::Group::applyJacobianTranspose(const NOX::TSF::Vector& input, NOX::TSF::Vector& result) const
00423 {
00424   // Check validity of the Jacobian
00425   if (!isJacobian()) 
00426   {
00427     return NOX::Abstract::Group::BadDependency;
00428   }
00429   else
00430   {
00431     // Compute result = J^T * input
00432     jacobian.applyTranspose(input.getTSFVector(), result.getTSFVector());
00433       
00434     return NOX::Abstract::Group::Ok;
00435   }
00436 }
00437 
00438 NOX::Abstract::Group::ReturnType 
00439 NOX::TSF::Group::applyJacobianInverse(Teuchos::ParameterList& p, 
00440   const Abstract::Vector& input, 
00441   NOX::Abstract::Vector& result) const 
00442 {
00443   const NOX::TSF::Vector& tsfinput = dynamic_cast<const NOX::TSF::Vector&> (input);
00444   NOX::TSF::Vector& tsfresult = dynamic_cast<NOX::TSF::Vector&> (result); 
00445   return applyJacobianInverse(p, tsfinput, tsfresult);
00446 }
00447 
00448 NOX::Abstract::Group::ReturnType 
00449 NOX::TSF::Group::applyJacobianInverse(Teuchos::ParameterList& p, 
00450   const NOX::TSF::Vector& input, 
00451   NOX::TSF::Vector& result) const 
00452 {
00453 
00454   if (!isJacobian()) 
00455   {
00456     Out::os() << "ERROR: NOX::TSF::Group::applyJacobianInverse() - invalid Jacobian" << std::endl;
00457     throw "NOX Error";
00458 
00459   }
00460 /*
00461   if (p.isParameter("Tolerance"))
00462   {
00463     double tol = p.get("Tolerance", tol);
00464     solver.updateTolerance(tol);
00465   }
00466 */
00467   if (verb() > 4)
00468   {
00469     Out::os() << "---------------- applying J^-1 ------------------" << std::endl;
00470     Out::os() << "J=" << std::endl;
00471     jacobian.print(Out::os());
00472     Out::os() << "F=" << std::endl;
00473     input.getTSFVector().print(Out::os());
00474   }
00475 
00476   TSFExtended::SolverState<double> status 
00477     = solver.solve(jacobian, input.getTSFVector(),
00478       result.getTSFVector());
00479   
00480   if (status.finalState() != TSFExtended::SolveConverged)
00481   {
00482     return NOX::Abstract::Group::Failed;
00483   }
00484   else
00485   {
00486     if (verb() > 2)
00487     {
00488       Out::os() << "soln=" << std::endl;
00489       result.getTSFVector().print(Out::os());
00490     }
00491     return NOX::Abstract::Group::Ok;
00492   }
00493 
00494 }
00495 
00496 bool NOX::TSF::Group::isF() const 
00497 {   
00498   return isValidF;
00499 }
00500 
00501 bool NOX::TSF::Group::isJacobian() const 
00502 {  
00503   return isValidJacobian;
00504 }
00505 
00506 bool NOX::TSF::Group::isGradient() const 
00507 {   
00508   return isValidGradient;
00509 }
00510 
00511 bool NOX::TSF::Group::isNewton() const 
00512 {   
00513   return isValidNewton;
00514 }
00515 
00516 const NOX::Abstract::Vector& NOX::TSF::Group::getX() const 
00517 {
00518   return xVector;
00519 }
00520 
00521 const NOX::Abstract::Vector& NOX::TSF::Group::getF() const 
00522 {  
00523   if (verb() > 2)
00524   {
00525     Out::os() << "calling getF()" << std::endl;
00526   }
00527   TEST_FOR_EXCEPTION(!isF(), runtime_error, 
00528     "calling getF() with invalid function value");
00529   return fVector;
00530 }
00531 
00532 double NOX::TSF::Group::getNormF() const
00533 {
00534   if (verb() > 2)
00535   {
00536     Out::os() << "normF = " << normF << std::endl;
00537   }
00538   TEST_FOR_EXCEPTION(!isF(), runtime_error, 
00539     "calling normF() with invalid function value");
00540   return normF;
00541 }
00542 
00543 const NOX::Abstract::Vector& NOX::TSF::Group::getGradient() const 
00544 { 
00545   return gradientVector;
00546 }
00547 
00548 const NOX::Abstract::Vector& NOX::TSF::Group::getNewton() const 
00549 {
00550   return newtonVector;
00551 }
00552 
00553 void NOX::TSF::Group::print() const
00554 {
00555   cout << "x = " << xVector << "\n";
00556 
00557   if (isValidF) {
00558     cout << "F(x) = " << fVector << "\n";
00559     cout << "|| F(x) || = " << normF << "\n";
00560   }
00561   else
00562     cout << "F(x) has not been computed" << "\n";
00563   
00564   cout << std::endl;
00565 }
00566 
00567 
00568 

Site Contact