NOX_Playa_Group.cpp
Go to the documentation of this file.
00001 /* @HEADER@ */
00002 // ************************************************************************
00003 // 
00004 //                 Playa: Programmable Linear Algebra
00005 //                 Copyright 2012 Sandia Corporation
00006 // 
00007 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
00008 // the U.S. Government retains certain rights in this software.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are
00012 // met:
00013 //
00014 // 1. Redistributions of source code must retain the above copyright
00015 // notice, this list of conditions and the following disclaimer.
00016 //
00017 // 2. Redistributions in binary form must reproduce the above copyright
00018 // notice, this list of conditions and the following disclaimer in the
00019 // documentation and/or other materials provided with the distribution.
00020 //
00021 // 3. Neither the name of the Corporation nor the names of the
00022 // contributors may be used to endorse or promote products derived from
00023 // this software without specific prior written permission.
00024 //
00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036 //
00037 // Questions? Contact Kevin Long (kevin.long@ttu.edu)
00038 // 
00039 
00040 /* @HEADER@ */
00041 
00042 
00043 // $Id$ 
00044 // $Source$ 
00045 
00046 
00047 //   
00048 
00049 
00050 #include "NOX_Common.H"
00051 #include "NOX_Playa_Group.hpp"  // class definition
00052 #include "PlayaMPIComm.hpp"
00053 #include "PlayaOut.hpp"
00054 #include "PlayaTabs.hpp"
00055 
00056 using Playa::Out;
00057 using Playa::Tabs;
00058 using Teuchos::RCP;
00059 
00060 using std::ostream;
00061 using std::cout;
00062 using std::runtime_error;
00063 
00064 
00065 
00066 NOX::NOXPlaya::Group::Group(const Playa::Vector<double>& initcond, 
00067   const Playa::NonlinearOperator<double>& nonlinOp,
00068   const Playa::LinearSolver<double>& linsolver) 
00069   :
00070   precision(3),  // 3 digits of accuracy is default
00071   xVector(rcp(new NOX::NOXPlaya::Vector(initcond, precision, DeepCopy))),
00072   fVector(rcp(new NOX::NOXPlaya::Vector(initcond, precision, ShapeCopy))),
00073   newtonVector(rcp(new NOX::NOXPlaya::Vector(initcond, precision, ShapeCopy))),
00074   gradientVector(rcp(new NOX::NOXPlaya::Vector(initcond, precision, ShapeCopy))),
00075   solver(linsolver),
00076   jacobian(),
00077   nonlinearOp(nonlinOp),
00078   normF(0.0)
00079 {  
00080   nonlinearOp.setEvalPt(xVector->getPlayaVector());
00081   resetIsValid();
00082 }
00083 
00084 NOX::NOXPlaya::Group::Group(const Playa::NonlinearOperator<double>& nonlinOp,
00085   const Playa::LinearSolver<double>& linsolver) 
00086   :
00087   precision(3), // 3 digits of accuracy is default
00088   xVector(rcp(new NOX::NOXPlaya::Vector(nonlinOp.getInitialGuess(), precision, DeepCopy))),
00089   fVector(rcp(new NOX::NOXPlaya::Vector(nonlinOp.getInitialGuess(), precision, ShapeCopy))),
00090   newtonVector(rcp(new NOX::NOXPlaya::Vector(nonlinOp.getInitialGuess(), precision, ShapeCopy))),
00091   gradientVector(rcp(new NOX::NOXPlaya::Vector(nonlinOp.getInitialGuess(), precision, ShapeCopy))),
00092   solver(linsolver),
00093   jacobian(),
00094   nonlinearOp(nonlinOp),
00095   normF(0.0)
00096 {  
00097   nonlinearOp.setEvalPt(xVector->getPlayaVector());
00098   resetIsValid();
00099 }
00100 
00101 NOX::NOXPlaya::Group::Group(const Playa::Vector<double>& initcond, 
00102   const Playa::NonlinearOperator<double>& nonlinOp,
00103   const Playa::LinearSolver<double>& linsolver,
00104   int numdigits) 
00105   :
00106   precision(numdigits),
00107   xVector(rcp(new NOX::NOXPlaya::Vector(initcond, precision, DeepCopy))),
00108   fVector(rcp(new NOX::NOXPlaya::Vector(initcond, precision, ShapeCopy))),
00109   newtonVector(rcp(new NOX::NOXPlaya::Vector(initcond, precision, ShapeCopy))),
00110   gradientVector(rcp(new NOX::NOXPlaya::Vector(initcond, precision, ShapeCopy))),
00111   solver(linsolver),
00112   jacobian(),
00113   nonlinearOp(nonlinOp),
00114   normF(0.0)
00115 {  
00116   nonlinearOp.setEvalPt(xVector->getPlayaVector());
00117   resetIsValid();
00118 }
00119 
00120 NOX::NOXPlaya::Group::Group(const Playa::NonlinearOperator<double>& nonlinOp,
00121   const Playa::LinearSolver<double>& linsolver,
00122   int numdigits) 
00123   :
00124   precision(numdigits),
00125   xVector(rcp(new NOX::NOXPlaya::Vector(nonlinOp.getInitialGuess(), precision, DeepCopy))),
00126   fVector(rcp(new NOX::NOXPlaya::Vector(nonlinOp.getInitialGuess(), precision, ShapeCopy))),
00127   newtonVector(rcp(new NOX::NOXPlaya::Vector(nonlinOp.getInitialGuess(), precision, ShapeCopy))),
00128   gradientVector(rcp(new NOX::NOXPlaya::Vector(nonlinOp.getInitialGuess(), precision, ShapeCopy))),
00129   solver(linsolver),
00130   jacobian(),
00131   nonlinearOp(nonlinOp),
00132   normF(0.0)
00133 {  
00134   nonlinearOp.setEvalPt(xVector->getPlayaVector());
00135   resetIsValid();
00136 }
00137 
00138 
00139 NOX::NOXPlaya::Group::Group(const NOX::NOXPlaya::Group& source, NOX::CopyType type) :
00140   precision(source.precision),
00141   xVector(rcp(new NOX::NOXPlaya::Vector(*(source.xVector), precision, type))), 
00142   fVector(rcp(new NOX::NOXPlaya::Vector(*(source.fVector), precision, type))),  
00143   newtonVector(rcp(new NOX::NOXPlaya::Vector(*(source.newtonVector), precision, type))),
00144   gradientVector(rcp(new NOX::NOXPlaya::Vector(*(source.gradientVector), precision, type))),
00145   solver(source.solver),
00146   jacobian(source.jacobian),
00147   nonlinearOp(source.nonlinearOp),
00148   isValidF(false),
00149   isValidJacobian(false),
00150   isValidGradient(false),
00151   isValidNewton(false),
00152   normF(0.0)
00153 {
00154   switch (type) 
00155   {
00156     
00157     case NOX::DeepCopy:
00158     
00159       isValidF = source.isValidF;
00160       isValidGradient = source.isValidGradient;
00161       isValidNewton = source.isValidNewton;
00162       isValidJacobian = source.isValidJacobian;
00163       normF = source.normF;
00164       break;
00165 
00166     case NOX::ShapeCopy:
00167       resetIsValid();
00168       normF = 0.0;
00169       break;
00170 
00171     default:
00172       Out::os() << "NOX:Playa::Group - invalid CopyType for copy constructor." << std::endl;
00173       throw "NOX Playa Error";
00174   }
00175 
00176 }
00177 
00178 NOX::NOXPlaya::Group::~Group() 
00179 {
00180 }
00181 
00182 void NOX::NOXPlaya::Group::resetIsValid() //private
00183 {
00184   isValidF = false;
00185   isValidJacobian = false;
00186   isValidGradient = false;
00187   isValidNewton = false;
00188 }
00189 
00190 
00191 RCP<NOX::Abstract::Group> NOX::NOXPlaya::Group::clone(NOX::CopyType type) const 
00192 {
00193   return rcp(new NOX::NOXPlaya::Group(*this, type));
00194 }
00195 
00196 NOX::Abstract::Group& NOX::NOXPlaya::Group::operator=(const NOX::Abstract::Group& source)
00197 {
00198   return operator=(dynamic_cast<const NOX::NOXPlaya::Group&> (source));
00199 }
00200 
00201 NOX::Abstract::Group& NOX::NOXPlaya::Group::operator=(const NOX::NOXPlaya::Group& source)
00202 {
00203   if (this != &source) 
00204   {
00205 
00206     // Deep Copy of the xVector
00207     *xVector = *(source.xVector);
00208     nonlinearOp = source.nonlinearOp;
00209     solver = source.solver;
00210     jacobian = source.jacobian;
00211     precision = source.precision;
00212 
00213     // Update the isValidVectors
00214     isValidF = source.isValidF;
00215     isValidGradient = source.isValidGradient;
00216     isValidNewton = source.isValidNewton;
00217     isValidJacobian = source.isValidJacobian;
00218     
00219     // Only copy vectors that are valid
00220     if (isValidF) 
00221     {
00222       *fVector = *(source.fVector);
00223       normF = source.normF;
00224     }
00225 
00226     if (isValidGradient)
00227       *gradientVector = *(source.gradientVector);
00228     
00229     if (isValidNewton)
00230       *newtonVector = *(source.newtonVector);
00231     
00232     if (isValidJacobian)
00233       jacobian = source.jacobian;
00234   }
00235   return *this;
00236 }
00237 
00238 void NOX::NOXPlaya::Group::setX(const NOX::Abstract::Vector& y) 
00239 {
00240   setX(dynamic_cast<const NOX::NOXPlaya::Vector&> (y));
00241 }
00242 
00243 void NOX::NOXPlaya::Group::setX(const NOX::NOXPlaya::Vector& y) 
00244 {
00245   resetIsValid();
00246   nonlinearOp.setEvalPt(y.getPlayaVector());
00247   *xVector = y;
00248 }
00249 
00250 void NOX::NOXPlaya::Group::computeX(const NOX::Abstract::Group& grp, 
00251   const NOX::Abstract::Vector& d, 
00252   double step) 
00253 {
00254   // Cast to appropriate type, then call the "native" computeX
00255   const Group& tsfgrp = dynamic_cast<const NOX::NOXPlaya::Group&> (grp);
00256   const Vector& tsfd = dynamic_cast<const NOX::NOXPlaya::Vector&> (d);
00257   computeX(tsfgrp, tsfd, step); 
00258 }
00259 
00260 void NOX::NOXPlaya::Group::computeX(const Group& grp, const Vector& d, double step) 
00261 {
00262   Tabs tab;
00263   resetIsValid();
00264   xVector->update(1.0, *(grp.xVector), step, d);
00265 }
00266 
00267 NOX::Abstract::Group::ReturnType NOX::NOXPlaya::Group::computeF() 
00268 {
00269  
00270   if (nonlinearOp.verb() > 2)
00271   {
00272     Out::os() << "calling computeF()" << std::endl;
00273   }
00274 
00275   if (isValidF)
00276   {
00277     if (nonlinearOp.verb() > 2)
00278     {
00279       Out::os() << "reusing F" << std::endl;
00280     }
00281     return NOX::Abstract::Group::Ok;
00282   }
00283   else
00284   {
00285     if (nonlinearOp.verb() > 2)
00286     {
00287       Out::os() << "computing new F" << std::endl;
00288     }
00289     nonlinearOp.setEvalPt(xVector->getPlayaVector());
00290     *fVector = nonlinearOp.getFunctionValue();
00291     isValidF = true;
00292     normF = fVector->norm();
00293   }
00294 
00295   return (isValidF) ? (NOX::Abstract::Group::Ok) : (NOX::Abstract::Group::Failed);
00296 }
00297 
00298 NOX::Abstract::Group::ReturnType NOX::NOXPlaya::Group::computeJacobian() 
00299 {
00300 
00301   if (nonlinearOp.verb() > 2)
00302   {
00303     Out::os() << "calling computeJ()" << std::endl;
00304   }
00305 
00306   // Skip if the Jacobian is already valid
00307   if (isValidJacobian)
00308   {
00309     return NOX::Abstract::Group::Ok;
00310   }
00311   else
00312   {
00313     nonlinearOp.setEvalPt(xVector->getPlayaVector());
00314     jacobian = nonlinearOp.getJacobian();
00315 
00316     isValidJacobian = true;
00317   }
00318   return (isValidJacobian) ? (NOX::Abstract::Group::Ok) : (NOX::Abstract::Group::Failed);
00319 }
00320 
00321 NOX::Abstract::Group::ReturnType NOX::NOXPlaya::Group::computeGradient() 
00322 {
00323   if (nonlinearOp.verb() > 2)
00324   {
00325     Out::os() << "calling computeGrad()" << std::endl;
00326   }
00327   if (isValidGradient)
00328   {
00329     return NOX::Abstract::Group::Ok;
00330   }
00331   else
00332   {
00333     if (!isF()) 
00334     {
00335       Out::os() << "ERROR: NOX::NOXPlaya::Group::computeGrad() - F is out of date wrt X!" << std::endl;
00336       return NOX::Abstract::Group::BadDependency;
00337     }
00338 
00339     if (!isJacobian()) 
00340     {
00341       Out::os() << "ERROR: NOX::NOXPlaya::Group::computeGrad() - Jacobian is out of date wrt X!" << std::endl;
00342       return NOX::Abstract::Group::BadDependency;
00343     }
00344   
00345     // Compute Gradient = J' * F
00346 
00347     NOX::Abstract::Group::ReturnType status 
00348       = applyJacobianTranspose(*fVector,*gradientVector);
00349     isValidGradient = (status == NOX::Abstract::Group::Ok);
00350 
00351     // Return result
00352     return status;
00353   }
00354 }
00355 
00356 NOX::Abstract::Group::ReturnType 
00357 NOX::NOXPlaya::Group::computeNewton(Teuchos::ParameterList& p) 
00358 {
00359   if (isNewton())
00360   {
00361     return NOX::Abstract::Group::Ok;
00362   }
00363   else
00364   {
00365     if (!isF()) 
00366     {
00367       Out::os() << "ERROR: NOX::Example::Group::computeNewton() - invalid F" 
00368                 << std::endl;
00369       throw "NOX Error";
00370     }
00371 
00372     if (!isJacobian()) 
00373     {
00374       Out::os() << "ERROR: NOX::Example::Group::computeNewton() - invalid Jacobian" << std::endl;
00375       throw "NOX Error";
00376     }
00377 
00378 /*
00379   if (p.isParameter("Tolerance"))
00380   {
00381   double tol = p.get("Tolerance", tol);
00382   solver.updateTolerance(tol);
00383   }
00384 */
00385 
00386     NOX::Abstract::Group::ReturnType status 
00387       = applyJacobianInverse(p, *fVector, *newtonVector);
00388     isValidNewton = (status == NOX::Abstract::Group::Ok);
00389 
00390     
00391     // Scale soln by -1
00392     newtonVector->scale(-1.0);
00393 
00394     if (nonlinearOp.verb() > 0)
00395     {
00396       Out::os() << "newton step" << std::endl;
00397       newtonVector->getPlayaVector().print(Out::os());
00398     }
00399       
00400     // Return solution
00401     return status;
00402   }
00403 }
00404 
00405 
00406 NOX::Abstract::Group::ReturnType 
00407 NOX::NOXPlaya::Group::applyJacobian(const Abstract::Vector& input, 
00408   NOX::Abstract::Vector& result) const
00409 {
00410   const NOX::NOXPlaya::Vector& tsfinput = dynamic_cast<const NOX::NOXPlaya::Vector&> (input);
00411   NOX::NOXPlaya::Vector& tsfresult = dynamic_cast<NOX::NOXPlaya::Vector&> (result);
00412   return applyJacobian(tsfinput, tsfresult);
00413 }
00414 
00415 NOX::Abstract::Group::ReturnType 
00416 NOX::NOXPlaya::Group::applyJacobian(const NOX::NOXPlaya::Vector& input, 
00417   NOX::NOXPlaya::Vector& result) const
00418 {
00419   // Check validity of the Jacobian
00420   if (!isJacobian()) 
00421   {
00422     return NOX::Abstract::Group::BadDependency;
00423   }
00424   else
00425   {
00426     // Compute result = J * input
00427     jacobian.apply(input.getPlayaVector(),result.getPlayaVector());
00428     return NOX::Abstract::Group::Ok;
00429   }
00430 }
00431 
00432 NOX::Abstract::Group::ReturnType 
00433 NOX::NOXPlaya::Group::applyJacobianTranspose(const NOX::Abstract::Vector& input, 
00434   NOX::Abstract::Vector& result) const
00435 {
00436   const NOX::NOXPlaya::Vector& tsfinput = dynamic_cast<const NOX::NOXPlaya::Vector&> (input);
00437   NOX::NOXPlaya::Vector& tsfresult = dynamic_cast<NOX::NOXPlaya::Vector&> (result);
00438   return applyJacobianTranspose(tsfinput, tsfresult);
00439 }
00440 
00441 NOX::Abstract::Group::ReturnType 
00442 NOX::NOXPlaya::Group::applyJacobianTranspose(const NOX::NOXPlaya::Vector& input, NOX::NOXPlaya::Vector& result) const
00443 {
00444   // Check validity of the Jacobian
00445   if (!isJacobian()) 
00446   {
00447     return NOX::Abstract::Group::BadDependency;
00448   }
00449   else
00450   {
00451     // Compute result = J^T * input
00452     jacobian.applyTranspose(input.getPlayaVector(), result.getPlayaVector());
00453       
00454     return NOX::Abstract::Group::Ok;
00455   }
00456 }
00457 
00458 NOX::Abstract::Group::ReturnType 
00459 NOX::NOXPlaya::Group::applyJacobianInverse(Teuchos::ParameterList& p, 
00460   const Abstract::Vector& input, 
00461   NOX::Abstract::Vector& result) const 
00462 {
00463   const NOX::NOXPlaya::Vector& tsfinput = dynamic_cast<const NOX::NOXPlaya::Vector&> (input);
00464   NOX::NOXPlaya::Vector& tsfresult = dynamic_cast<NOX::NOXPlaya::Vector&> (result); 
00465   return applyJacobianInverse(p, tsfinput, tsfresult);
00466 }
00467 
00468 NOX::Abstract::Group::ReturnType 
00469 NOX::NOXPlaya::Group::applyJacobianInverse(Teuchos::ParameterList& p, 
00470   const NOX::NOXPlaya::Vector& input, 
00471   NOX::NOXPlaya::Vector& result) const 
00472 {
00473 
00474   if (!isJacobian()) 
00475   {
00476     Out::os() << "ERROR: NOX::NOXPlaya::Group::applyJacobianInverse() - invalid Jacobian" << std::endl;
00477     throw "NOX Error";
00478 
00479   }
00480 /*
00481   if (p.isParameter("Tolerance"))
00482   {
00483   double tol = p.get("Tolerance", tol);
00484   solver.updateTolerance(tol);
00485   }
00486 */
00487   if (nonlinearOp.verb() > 4)
00488   {
00489     Out::os() << "---------------- applying J^-1 ------------------" << std::endl;
00490     Out::os() << "J=" << std::endl;
00491     jacobian.print(Out::os());
00492     Out::os() << "F=" << std::endl;
00493     input.getPlayaVector().print(Out::os());
00494   }
00495 
00496   Playa::SolverState<double> status 
00497     = solver.solve(jacobian, input.getPlayaVector(),
00498       result.getPlayaVector());
00499   
00500   if (status.finalState() != Playa::SolveConverged)
00501   {
00502     return NOX::Abstract::Group::Failed;
00503   }
00504   else
00505   {
00506     if (nonlinearOp.verb() > 2)
00507     {
00508       Out::os() << "soln=" << std::endl;
00509       result.getPlayaVector().print(Out::os());
00510     }
00511     return NOX::Abstract::Group::Ok;
00512   }
00513 
00514 }
00515 
00516 bool NOX::NOXPlaya::Group::isF() const 
00517 {   
00518   return isValidF;
00519 }
00520 
00521 bool NOX::NOXPlaya::Group::isJacobian() const 
00522 {  
00523   return isValidJacobian;
00524 }
00525 
00526 bool NOX::NOXPlaya::Group::isGradient() const 
00527 {   
00528   return isValidGradient;
00529 }
00530 
00531 bool NOX::NOXPlaya::Group::isNewton() const 
00532 {   
00533   return isValidNewton;
00534 }
00535 
00536 const NOX::Abstract::Vector& NOX::NOXPlaya::Group::getX() const 
00537 {
00538   return *xVector;
00539 }
00540 
00541 const NOX::Abstract::Vector& NOX::NOXPlaya::Group::getF() const 
00542 {  
00543   if (nonlinearOp.verb() > 2)
00544   {
00545     Out::os() << "calling getF()" << std::endl;
00546   }
00547   TEUCHOS_TEST_FOR_EXCEPTION(!isF(), runtime_error, 
00548     "calling getF() with invalid function value");
00549   return *fVector;
00550 }
00551 
00552 double NOX::NOXPlaya::Group::getNormF() const
00553 {
00554   if (nonlinearOp.verb() > 2)
00555   {
00556     Out::os() << "normF = " << normF << std::endl;
00557   }
00558   TEUCHOS_TEST_FOR_EXCEPTION(!isF(), runtime_error, 
00559     "calling normF() with invalid function value");
00560   return normF;
00561 }
00562 
00563 const NOX::Abstract::Vector& NOX::NOXPlaya::Group::getGradient() const 
00564 { 
00565   return *gradientVector;
00566 }
00567 
00568 const NOX::Abstract::Vector& NOX::NOXPlaya::Group::getNewton() const 
00569 {
00570   return *newtonVector;
00571 }
00572 
00573 void NOX::NOXPlaya::Group::print() const
00574 {
00575   cout << "x = " << *xVector << "\n";
00576 
00577   if (isValidF) {
00578     cout << "F(x) = " << *fVector << "\n";
00579     cout << "|| F(x) || = " << normF << "\n";
00580   }
00581   else
00582     cout << "F(x) has not been computed" << "\n";
00583   
00584   cout << std::endl;
00585 }
00586 
00587 
00588 

Site Contact