Xyce  6.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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-2014 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.19 $
40 //
41 // Revision Date : $Date: 2014/02/24 23:49:25 $
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 
69 PseudoTransientBased(const Teuchos::RefCountPtr<N_NLS_NOX::AugmentLinSys>& als,
70  const Teuchos::RefCountPtr<NOX::Abstract::Group>& xGrp,
71  const Teuchos::RefCountPtr<NOX::StatusTest::Generic>& t,
72  const Teuchos::RefCountPtr<Teuchos::ParameterList>& p,
73  double initialStepSize,
74  double minStepSize,
75  double maxStepSize) :
76  globalData(Teuchos::rcp(new NOX::GlobalData(p))),
77  augmentLSStrategy(als),
78  solnPtr(xGrp), // pointer to xGrp
79  oldSolnPtr(xGrp->clone(NOX::DeepCopy)), // create via clone
80  oldSoln(*oldSolnPtr), // reference to just-created pointer
81  dirPtr(xGrp->getX().clone(NOX::ShapeCopy)), // create via clone
82  dir(*dirPtr), // reference to just-created pointer
83  testPtr(t), // pointer to t
84  paramsPtr(p), // pointer to p
85  utils(*(globalData->getUtils())), // intialize the utils
86  lineSearch(NOX::LineSearch::buildLineSearch(globalData, paramsPtr->sublist("Line Search"))), // initialize the line search
87  direction(NOX::Direction::buildDirection(globalData, paramsPtr->sublist("Direction"))), // initialize the direction
88  prePostOperator(globalData->getUtils(), paramsPtr->sublist("Solver Options")),
89  initialStepSize_(initialStepSize),
90  minStepSize_(minStepSize),
91  maxStepSize_(maxStepSize),
92  stepSize_(initialStepSize),
93  previousStepSize_(0.0),
94  group_(0),
95  previousGroup_(0),
96  scaleFactor_(1.0)
97 {
98  init();
99 }
100 
101 // Protected
103 {
104  // Initialize
105  step_ = 0.0;
106  nIter = 0;
107  status = NOX::StatusTest::Unconverged;
108 
109  // Print out parameters
110  if (utils.isPrintType(NOX::Utils::Parameters))
111  {
112  utils.out() << "\n" << NOX::Utils::fill(72) << "\n";
113  utils.out() << "\n-- Parameters Passed to Nonlinear Solver --\n\n";
114  paramsPtr->print(utils.out(),5);
115  }
116 
117  checkType = NOX::Solver::parseStatusTestCheckType(paramsPtr->sublist("Solver Options"));
118 }
119 
121 reset(const NOX::Abstract::Vector& initial_guess)
122 {
123  solnPtr->setX(initial_guess);
124  init();
125 }
126 
128 reset(const NOX::Abstract::Vector& initial_guess,
129  const Teuchos::RCP<NOX::StatusTest::Generic>& t)
130 {
131  solnPtr->setX(initial_guess);
132  testPtr = t;
133  init();
134 }
135 
137 {
138 }
139 
140 
141 NOX::StatusTest::StatusType N_NLS_NOX::PseudoTransientBased::getStatus()
142 {
143  return status;
144 }
145 
146 NOX::StatusTest::StatusType N_NLS_NOX::PseudoTransientBased::step()
147 {
148  prePostOperator.runPreIterate(*this);
149 
150  // First time thru, do some initializations
151  if (this->getNumIterations() == 0) {
152 
153  // Compute F of initital guess
154  NOX::Abstract::Group::ReturnType rtype = solnPtr->computeF();
155  if (rtype != NOX::Abstract::Group::Ok) {
156  Xyce::dout() << "NOX::Solver::PseudoTransientBased::step - Unable to compute F" << std::endl;
157  throw "NOX Error";
158  }
159 
160  // Test the initial guess
161  status = testPtr->checkStatus(*this, checkType);
162  if ((status == NOX::StatusTest::Converged) &&
163  (utils.isPrintType(NOX::Utils::Warning))) {
164  utils.out() << "Warning: NOX::Solver::PseudoTransientBased::step() - The solution passed "
165  << "into the solver (either through constructor or reset method) "
166  << "is already converged! The solver will not "
167  << "attempt to solve this system since status is flagged as "
168  << "converged." << std::endl;
169  }
170 
171  // Print out status tests
172  if (utils.isPrintType(NOX::Utils::Parameters)) {
173  utils.out() << "\n-- Status Tests Passed to Nonlinear Solver --\n\n";
174  testPtr->print(utils.out(), 5);
175  utils.out() <<"\n" << NOX::Utils::fill(72) << "\n";
176  }
177 
178  if (status != NOX::StatusTest::Unconverged) {
179  prePostOperator.runPostIterate(*this);
180  return status;
181  }
182  }
183 
184  // Compute a new stp length
185  if (this->getNumIterations() == 0) {
186  stepSize_ = initialStepSize_;
187  }
188  else {
189  previousStepSize_ = stepSize_;
190  double f_n = this->getSolutionGroup().getNormF();
191  double f_nm1 = this->getPreviousSolutionGroup().getNormF();
192 
193  stepSize_ = scaleFactor_ * previousStepSize_ * f_nm1 / f_n;
194 
195  //Xyce::dout() << "f_nm1/f_n = " << f_nm1 / f_n << std::endl;
196 
197  //if ((stepSize_ > previousStepSize_) && (f_n > 1.0e+10)) {
198  //stepSize_ = previousStepSize_;
199  //}
200 
201  //if (stepSize_ < previousStepSize_ * 0.1 )
202  //stepSize_ = previousStepSize_ * 0.1;
203 
204  //if (stepSize_ > previousStepSize_ * 1.0e4 )
205  //stepSize_ = previousStepSize_ * 10.0;
206 
207  if (stepSize_ < minStepSize_)
208  stepSize_ = minStepSize_;
209 
210  if (stepSize_ > maxStepSize_)
211  stepSize_ = maxStepSize_;
212 
213  }
214 
215  // Set Steplength with group
216 // group_->setPseudoTransientStepSize(stepSize_);
217 // previousGroup_->setPseudoTransientStepSize(stepSize_);
218  augmentLSStrategy->setProgressVariable(stepSize_);
219 
220  // First check status
221  if (status != NOX::StatusTest::Unconverged) {
222  prePostOperator.runPostIterate(*this);
223  return status;
224  }
225 
226  // Copy pointers into temporary references
227  NOX::Abstract::Group& soln = *solnPtr;
228  NOX::StatusTest::Generic& test = *testPtr;
229 
230  // Compute the direction for the update vector at the current solution.
231  bool ok;
232  ok = direction->compute(dir, soln, *this);
233  if (!ok)
234  {
235  Xyce::dout() << "N_NLS_NOX::PseudoTransientBased::iterate - unable to calculate direction" << std::endl;
236  status = NOX::StatusTest::Failed;
237  prePostOperator.runPostIterate(*this);
238  return status;
239  }
240 
241  // Update iteration count.
242  nIter ++;
243 
244  // Copy current soln to the old soln.
245  oldSoln = soln;
246 
247  // Do line search and compute new soln.
248  ok = lineSearch->compute(soln, step_, dir, *this);
249  if (!ok)
250  {
251  if (nIter == 0)
252  {
253  Xyce::dout() << "N_NLS_NOX::PseudoTransientBased::iterate - line search failed" << std::endl;
254  status = NOX::StatusTest::Failed;
255  prePostOperator.runPostIterate(*this);
256  return status;
257  }
258  else if (utils.isPrintType(NOX::Utils::Warning))
259  utils.out() << "N_NLS_NOX::PseudoTransientBased::iterate - using recovery step for line search" << std::endl;
260  }
261 
262  // Compute F for new current solution.
263  NOX::Abstract::Group::ReturnType rtype = soln.computeF();
264  if (rtype != NOX::Abstract::Group::Ok)
265  {
266  utils.out() << "N_NLS_NOX::PseudoTransientBased::iterate - unable to compute F" << std::endl;
267  status = NOX::StatusTest::Failed;
268  prePostOperator.runPostIterate(*this);
269  return status;
270  }
271 
272  NOX::StatusTest::FiniteValue fv;
273  NOX::StatusTest::StatusType fvStatus = fv.checkStatus(*this, checkType);
274  if (fvStatus == NOX::StatusTest::Failed) {
275  scaleFactor_ *= 0.5;
276  *group_ = *previousGroup_;
277  prePostOperator.runPostIterate(*this);
278  group_->setX(group_->getX());
279  if (stepSize_ > minStepSize_)
280  return (NOX::StatusTest::Unconverged);
281  else
282  return (NOX::StatusTest::Failed);
283  }
284  else
285  scaleFactor_ = 1.0;
286 
287  // Evaluate the current status.
288  status = test.checkStatus(*this, checkType);
289 
290  prePostOperator.runPostIterate(*this);
291 
292  // Return status.
293  return status;
294 }
295 
296 NOX::StatusTest::StatusType N_NLS_NOX::PseudoTransientBased::solve()
297 {
298  prePostOperator.runPreSolve(*this);
299 
300 
301  group_ = 0;
302  NOX::Abstract::Group* tmpGroup =
303  const_cast<NOX::Abstract::Group*>(&(this->getSolutionGroup()));
304  group_ = dynamic_cast<N_NLS_LOCA::Group*>(tmpGroup);
305 
306 
307  previousGroup_ = 0;
308  NOX::Abstract::Group* tmpPreviousGroup =
309  const_cast<NOX::Abstract::Group*>(&(this->getPreviousSolutionGroup()));
310  previousGroup_ = dynamic_cast<N_NLS_LOCA::Group*>(tmpPreviousGroup);
311 
312  if ((group_ == 0) || (previousGroup_ == 0)) {
313  std::string message = "N_NLS_NOX::PrePostOperator\n Failed to dynamic_cast the old and new groups to N_NLS_LOCA::Groups! ";
314  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL, message);
315  }
316 
317  // Enable xyce group pseudotransient
318  group_->setAugmentLinearSystem(true, augmentLSStrategy);
319  previousGroup_->setAugmentLinearSystem(true, augmentLSStrategy);
320 
321  printUpdate();
322 
323  // Iterate until converged or failed
324  while (status == NOX::StatusTest::Unconverged)
325  {
326  status = step();
327  printUpdate();
328  }
329 
330  group_->setAugmentLinearSystem(false, augmentLSStrategy);
331  previousGroup_->setAugmentLinearSystem(false, augmentLSStrategy);
332 
333  Teuchos::ParameterList& outputParams = paramsPtr->sublist("Output");
334  outputParams.set("Nonlinear Iterations", nIter);
335  outputParams.set("2-Norm of Residual", solnPtr->getNormF());
336 
337  prePostOperator.runPostSolve(*this);
338 
339  return status;
340 }
341 
342 const NOX::Abstract::Group&
344 {
345  return *solnPtr;
346 }
347 
348 const NOX::Abstract::Group&
350 {
351  return oldSoln;
352 }
353 
355 {
356  return nIter;
357 }
358 
359 const Teuchos::ParameterList&
361 {
362  return *paramsPtr;
363 }
364 
365 // protected
367 {
368  double normSoln = 0;
369  double normStep = 0;
370 
371  // Print the status test parameters at each iteration if requested
372  if ((status == NOX::StatusTest::Unconverged) &&
373  (utils.isPrintType(NOX::Utils::OuterIterationStatusTest)))
374  {
375  utils.out() << NOX::Utils::fill(72) << "\n";
376  utils.out() << "-- Status Test Results --\n";
377  testPtr->print(utils.out());
378  utils.out() << NOX::Utils::fill(72) << "\n";
379  }
380 
381  // All processes participate in the computation of these norms...
382  if (utils.isPrintType(NOX::Utils::OuterIteration))
383  {
384  normSoln = solnPtr->getNormF();
385  normStep = (nIter > 0) ? dir.norm() : 0;
386  }
387 
388  // ...But only the print process actually prints the result.
389  if (utils.isPrintType(NOX::Utils::OuterIteration))
390  {
391  utils.out() << "\n" << NOX::Utils::fill(72) << "\n";
392  utils.out() << "-- Nonlinear Solver Step " << nIter << " -- \n";
393  utils.out() << "f = " << utils.sciformat(normSoln);
394  utils.out() << " step = " << utils.sciformat(step_);
395  utils.out() << " dx = " << utils.sciformat(normStep);
396  if (status == NOX::StatusTest::Converged)
397  utils.out() << " (Converged!)";
398  if (status == NOX::StatusTest::Failed)
399  utils.out() << " (Failed!)";
400  utils.out() << "\n" << NOX::Utils::fill(72) << "\n" << std::endl;
401  }
402 
403  // Print the final parameter values of the status test
404  if ((status != NOX::StatusTest::Unconverged) &&
405  (utils.isPrintType(NOX::Utils::OuterIteration)))
406  {
407  utils.out() << NOX::Utils::fill(72) << "\n";
408  utils.out() << "-- Final Status Test Results --\n";
409  testPtr->print(utils.out());
410  utils.out() << NOX::Utils::fill(72) << "\n";
411  }
412 }
413 
415 {
416  return step_;
417 }
418 
420 {
421  return stepSize_;
422 }
423