Xyce  6.1
N_NLS_NOX_PseudoTransientSolver.C
Go to the documentation of this file.
1 //-------------------------------------------------------------------------
2 // Copyright Notice
3 //
4 // Copyright 2002 Sandia Corporation. Under the terms
5 // of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S.
6 // Government retains certain rights in this software.
7 //
8 // Xyce(TM) Parallel Electrical Simulator
9 // Copyright (C) 2002-2015 Sandia Corporation
10 //
11 // This program is free software: you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation, either version 3 of the License, or
14 // (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 //-------------------------------------------------------------------------
24 
25 //-------------------------------------------------------------------------
26 // Filename : $RCSfile: N_NLS_NOX_PseudoTransientSolver.C,v $
27 //
28 // Purpose :
29 //
30 // Special Notes :
31 //
32 // Creator :
33 //
34 // Creation Date :
35 //
36 // Revision Information:
37 // ---------------------
38 //
39 // Revision Number: $Revision: 1.22.2.1 $
40 //
41 // Revision Date : $Date: 2015/04/02 18:20:17 $
42 //
43 // Current Owner : $Author: tvrusso $
44 //-------------------------------------------------------------------------
45 
46 /* DEBUG: missing standard header */
47 
48 
49 #include <Xyce_config.h>
50 
51 
52 #include "N_NLS_NOX_PseudoTransientSolver.h" // class definition
54 #include "NOX_Abstract_Vector.H"
55 #include "NOX_Abstract_Group.H"
56 #include "NOX_Common.H"
57 #include "NOX_GlobalData.H"
58 #include "Teuchos_ParameterList.hpp"
59 #include "NOX_Utils.H"
60 #include "NOX_StatusTest_FiniteValue.H"
61 #include "N_NLS_LOCA_Group.h"
62 #include "N_ERH_ErrorMgr.h"
63 
64 #include "NOX_Direction_Factory.H"
65 #include "NOX_LineSearch_Factory.H"
66 #include "NOX_Solver_SolverUtils.H"
67 
68 namespace Xyce {
69 namespace Nonlinear {
70 namespace N_NLS_NOX {
71 
73 PseudoTransientBased(const Teuchos::RCP<AugmentLinSys>& als,
74  const Teuchos::RCP<NOX::Abstract::Group>& xGrp,
75  const Teuchos::RCP<NOX::StatusTest::Generic>& t,
76  const Teuchos::RCP<Teuchos::ParameterList>& p,
77  double initialStepSize,
78  double minStepSize,
79  double maxStepSize) :
80  globalData(Teuchos::rcp(new NOX::GlobalData(p))),
81  augmentLSStrategy(als),
82  solnPtr(xGrp), // pointer to xGrp
83  oldSolnPtr(xGrp->clone(NOX::DeepCopy)), // create via clone
84  oldSoln(*oldSolnPtr), // reference to just-created pointer
85  dirPtr(xGrp->getX().clone(NOX::ShapeCopy)), // create via clone
86  dir(*dirPtr), // reference to just-created pointer
87  testPtr(t), // pointer to t
88  paramsPtr(p), // pointer to p
89  utils(*(globalData->getUtils())), // intialize the utils
90  lineSearch(NOX::LineSearch::buildLineSearch(globalData, paramsPtr->sublist("Line Search"))), // initialize the line search
91  direction(NOX::Direction::buildDirection(globalData, paramsPtr->sublist("Direction"))), // initialize the direction
92  prePostOperator(globalData->getUtils(), paramsPtr->sublist("Solver Options")),
93  initialStepSize_(initialStepSize),
94  minStepSize_(minStepSize),
95  maxStepSize_(maxStepSize),
96  stepSize_(initialStepSize),
97  previousStepSize_(0.0),
98  group_(0),
99  previousGroup_(0),
100  scaleFactor_(1.0)
101 {
102  init();
103 }
104 
105 // Protected
107 {
108  // Initialize
109  step_ = 0.0;
110  nIter = 0;
111  status = NOX::StatusTest::Unconverged;
112 
113  // Print out parameters
114  if (utils.isPrintType(NOX::Utils::Parameters))
115  {
116  utils.out() << "\n" << NOX::Utils::fill(72) << "\n";
117  utils.out() << "\n-- Parameters Passed to Nonlinear Solver --\n\n";
118  paramsPtr->print(utils.out(),5);
119  }
120 
121  checkType = NOX::Solver::parseStatusTestCheckType(paramsPtr->sublist("Solver Options"));
122 }
123 
125 reset(const NOX::Abstract::Vector& initial_guess)
126 {
127  solnPtr->setX(initial_guess);
128  init();
129 }
130 
132 reset(const NOX::Abstract::Vector& initial_guess,
133  const Teuchos::RCP<NOX::StatusTest::Generic>& t)
134 {
135  solnPtr->setX(initial_guess);
136  testPtr = t;
137  init();
138 }
139 
141 {
142 }
143 
144 
145 NOX::StatusTest::StatusType PseudoTransientBased::getStatus()
146 {
147  return status;
148 }
149 
150 NOX::StatusTest::StatusType PseudoTransientBased::step()
151 {
152  prePostOperator.runPreIterate(*this);
153 
154  // First time thru, do some initializations
155  if (this->getNumIterations() == 0) {
156 
157  // Compute F of initital guess
158  NOX::Abstract::Group::ReturnType rtype = solnPtr->computeF();
159  if (rtype != NOX::Abstract::Group::Ok) {
160  dout() << "NOX::Solver::PseudoTransientBased::step - Unable to compute F" << std::endl;
161  throw "NOX Error";
162  }
163 
164  // Test the initial guess
165  status = testPtr->checkStatus(*this, checkType);
166  if ((status == NOX::StatusTest::Converged) &&
167  (utils.isPrintType(NOX::Utils::Warning))) {
168  utils.out() << "Warning: NOX::Solver::PseudoTransientBased::step() - The solution passed "
169  << "into the solver (either through constructor or reset method) "
170  << "is already converged! The solver will not "
171  << "attempt to solve this system since status is flagged as "
172  << "converged." << std::endl;
173  }
174 
175  // Print out status tests
176  if (utils.isPrintType(NOX::Utils::Parameters)) {
177  utils.out() << "\n-- Status Tests Passed to Nonlinear Solver --\n\n";
178  testPtr->print(utils.out(), 5);
179  utils.out() <<"\n" << NOX::Utils::fill(72) << "\n";
180  }
181 
182  if (status != NOX::StatusTest::Unconverged) {
183  prePostOperator.runPostIterate(*this);
184  return status;
185  }
186  }
187 
188  // Compute a new stp length
189  if (this->getNumIterations() == 0) {
191  }
192  else {
194  double f_n = this->getSolutionGroup().getNormF();
195  double f_nm1 = this->getPreviousSolutionGroup().getNormF();
196 
197  stepSize_ = scaleFactor_ * previousStepSize_ * f_nm1 / f_n;
198 
199  //dout() << "f_nm1/f_n = " << f_nm1 / f_n << std::endl;
200 
201  if (stepSize_ < minStepSize_)
203 
204  if (stepSize_ > maxStepSize_)
206 
207  }
208 
209  // Set Steplength with group
210  augmentLSStrategy->setProgressVariable(stepSize_);
211 
212  // First check status
213  if (status != NOX::StatusTest::Unconverged) {
214  prePostOperator.runPostIterate(*this);
215  return status;
216  }
217 
218  // Copy pointers into temporary references
219  NOX::Abstract::Group& soln = *solnPtr;
220  NOX::StatusTest::Generic& test = *testPtr;
221 
222  // Compute the direction for the update vector at the current solution.
223  bool ok;
224  ok = direction->compute(dir, soln, *this);
225  if (!ok)
226  {
227  dout() << "PseudoTransientBased::iterate - unable to calculate direction" << std::endl;
228  status = NOX::StatusTest::Failed;
229  prePostOperator.runPostIterate(*this);
230  return status;
231  }
232 
233  // Update iteration count.
234  nIter ++;
235 
236  // Copy current soln to the old soln.
237  oldSoln = soln;
238 
239  // Do line search and compute new soln.
240  ok = lineSearch->compute(soln, step_, dir, *this);
241  if (!ok)
242  {
243  if (nIter == 0)
244  {
245  dout() << "PseudoTransientBased::iterate - line search failed" << std::endl;
246  status = NOX::StatusTest::Failed;
247  prePostOperator.runPostIterate(*this);
248  return status;
249  }
250  else if (utils.isPrintType(NOX::Utils::Warning))
251  utils.out() << "PseudoTransientBased::iterate - using recovery step for line search" << std::endl;
252  }
253 
254  // Compute F for new current solution.
255  NOX::Abstract::Group::ReturnType rtype = soln.computeF();
256  if (rtype != NOX::Abstract::Group::Ok)
257  {
258  utils.out() << "PseudoTransientBased::iterate - unable to compute F" << std::endl;
259  status = NOX::StatusTest::Failed;
260  prePostOperator.runPostIterate(*this);
261  return status;
262  }
263 
264  NOX::StatusTest::FiniteValue fv;
265  NOX::StatusTest::StatusType fvStatus = fv.checkStatus(*this, checkType);
266  if (fvStatus == NOX::StatusTest::Failed) {
267  scaleFactor_ *= 0.5;
269  prePostOperator.runPostIterate(*this);
270  group_->setX(group_->getX());
271  if (stepSize_ > minStepSize_)
272  return (NOX::StatusTest::Unconverged);
273  else
274  return (NOX::StatusTest::Failed);
275  }
276  else
277  scaleFactor_ = 1.0;
278 
279  // Evaluate the current status.
280  status = test.checkStatus(*this, checkType);
281 
282  prePostOperator.runPostIterate(*this);
283 
284  // Return status.
285  return status;
286 }
287 
288 NOX::StatusTest::StatusType PseudoTransientBased::solve()
289 {
290  prePostOperator.runPreSolve(*this);
291 
292 
293  group_ = 0;
294  NOX::Abstract::Group* tmpGroup =
295  const_cast<NOX::Abstract::Group*>(&(this->getSolutionGroup()));
296  group_ = dynamic_cast<N_NLS_LOCA::Group*>(tmpGroup);
297 
298 
299  previousGroup_ = 0;
300  NOX::Abstract::Group* tmpPreviousGroup =
301  const_cast<NOX::Abstract::Group*>(&(this->getPreviousSolutionGroup()));
302  previousGroup_ = dynamic_cast<N_NLS_LOCA::Group*>(tmpPreviousGroup);
303 
304  if ((group_ == 0) || (previousGroup_ == 0)) {
305  std::string message = "PrePostOperator\n Failed to dynamic_cast the old and new groups to N_NLS_LOCA::Groups! ";
306  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL, message);
307  }
308 
309  // Enable xyce group pseudotransient
312 
313  printUpdate();
314 
315  // Iterate until converged or failed
316  while (status == NOX::StatusTest::Unconverged)
317  {
318  status = step();
319  printUpdate();
320  }
321 
324 
325  Teuchos::ParameterList& outputParams = paramsPtr->sublist("Output");
326  outputParams.set("Nonlinear Iterations", nIter);
327  outputParams.set("2-Norm of Residual", solnPtr->getNormF());
328 
329  prePostOperator.runPostSolve(*this);
330 
331  return status;
332 }
333 
334 const NOX::Abstract::Group&
336 {
337  return *solnPtr;
338 }
339 
340 const NOX::Abstract::Group&
342 {
343  return oldSoln;
344 }
345 
347 {
348  return nIter;
349 }
350 
351 const Teuchos::ParameterList&
353 {
354  return *paramsPtr;
355 }
356 
357 // protected
359 {
360  double normSoln = 0;
361  double normStep = 0;
362 
363  // Print the status test parameters at each iteration if requested
364  if ((status == NOX::StatusTest::Unconverged) &&
365  (utils.isPrintType(NOX::Utils::OuterIterationStatusTest)))
366  {
367  utils.out() << NOX::Utils::fill(72) << "\n";
368  utils.out() << "-- Status Test Results --\n";
369  testPtr->print(utils.out());
370  utils.out() << NOX::Utils::fill(72) << "\n";
371  }
372 
373  // All processes participate in the computation of these norms...
374  if (utils.isPrintType(NOX::Utils::OuterIteration))
375  {
376  normSoln = solnPtr->getNormF();
377  normStep = (nIter > 0) ? dir.norm() : 0;
378  }
379 
380  // ...But only the print process actually prints the result.
381  if (utils.isPrintType(NOX::Utils::OuterIteration))
382  {
383  utils.out() << "\n" << NOX::Utils::fill(72) << "\n";
384  utils.out() << "-- Nonlinear Solver Step " << nIter << " -- \n";
385  utils.out() << "f = " << utils.sciformat(normSoln);
386  utils.out() << " step = " << utils.sciformat(step_);
387  utils.out() << " dx = " << utils.sciformat(normStep);
388  if (status == NOX::StatusTest::Converged)
389  utils.out() << " (Converged!)";
390  if (status == NOX::StatusTest::Failed)
391  utils.out() << " (Failed!)";
392  utils.out() << "\n" << NOX::Utils::fill(72) << "\n" << std::endl;
393  }
394 
395  // Print the final parameter values of the status test
396  if ((status != NOX::StatusTest::Unconverged) &&
397  (utils.isPrintType(NOX::Utils::OuterIteration)))
398  {
399  utils.out() << NOX::Utils::fill(72) << "\n";
400  utils.out() << "-- Final Status Test Results --\n";
401  testPtr->print(utils.out());
402  utils.out() << NOX::Utils::fill(72) << "\n";
403  }
404 }
405 
407 {
408  return step_;
409 }
410 
412 {
413  return stepSize_;
414 }
415 
416 }}}
NOX::StatusTest::StatusType status
Status of nonlinear solver.
void setX(const Vector &input)
Teuchos::RCP< NOX::StatusTest::Generic > testPtr
Stopping test.
const NOX::Abstract::Vector & getX() const
Pure virtual class to augment a linear system.
NOX::Solver::PrePostOperator prePostOperator
Pointer to a user defined NOX::Abstract::PrePostOperator object.
NOX::Abstract::Vector & dir
Current search direction.reference.
Teuchos::RCP< NOX::Abstract::Group > solnPtr
Current solution.
virtual double getStepSize() const
Return the line search step size from the current iteration.
virtual const NOX::Abstract::Group & getPreviousSolutionGroup() const
Teuchos::RCP< AugmentLinSys > augmentLSStrategy
RCP to the strategy for augmenting the linear system.
Teuchos::RCP< NOX::LineSearch::Generic > lineSearch
Linesearch.
virtual void reset(const NOX::Abstract::Vector &initial_guess)
virtual const Teuchos::ParameterList & getList() const
NOX::Abstract::Group & oldSoln
Previous solution reference.
virtual void init()
Print out initialization information and calcuation the RHS.
Teuchos::RCP< Teuchos::ParameterList > paramsPtr
Input parameters.
NOX::StatusTest::CheckType checkType
Type of check to use for status tests.
PseudoTransientBased(const Teuchos::RCP< AugmentLinSys > &als, const Teuchos::RCP< NOX::Abstract::Group > &grp, const Teuchos::RCP< NOX::StatusTest::Generic > &tests, const Teuchos::RCP< Teuchos::ParameterList > &params, double initialStepSize, double minStepSize, double maxStepSize)
Constructor.
virtual void printUpdate()
Prints the current iteration information.
void setAugmentLinearSystem(bool enable, const Teuchos::RCP< N_NLS_NOX::AugmentLinSys > &ls)
virtual const NOX::Abstract::Group & getSolutionGroup() const
Definition: N_NLS_fwd.h:107
Teuchos::RCP< NOX::Direction::Generic > direction
Search Direction.
virtual double getPseudoTransientStepSize() const
Return the pseudo transient step size.