Xyce  6.1
N_NLS_NOX_XyceTests.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_XyceTests.C,v $
27 //
28 // Purpose : Status test.
29 //
30 // Special Notes :
31 //
32 // Creator : Roger Pawlowski, SNL 9233
33 //
34 // Creation Date : 04/15/03
35 //
36 // Revision Information:
37 // ---------------------
38 //
39 // Revision Number: $Revision: 1.55.2.1 $
40 //
41 // Revision Date : $Date: 2015/04/02 18:20:17 $
42 //
43 // Current Owner : $Author: tvrusso $
44 //-------------------------------------------------------------------------
45 
46 #include <Xyce_config.h>
47 
48 
49 // ---------- Standard Includes ----------
50 
51 // ---------- Xyce Includes ----------
52 #include "N_NLS_NOX_XyceTests.h"
53 #include "N_NLS_NOX_Vector.h"
54 #include "N_LAS_Vector.h"
56 #include "NOX.H"
57 #include "NOX_Solver_LineSearchBased.H"
58 
59 #include <N_UTL_MachDepParams.h>
60 
61 // ---------- Namespaces ----------
62 
63 namespace Xyce {
64 namespace Nonlinear {
65 namespace N_NLS_NOX {
66 
67 // ---------- Code ----------
68 
70  Parallel::Machine comm,
71  bool isTransient,
72  double normF,
73  double machPrec,
74  Linear::Vector ** currSolVectorPtrPtr,
75  double epsilon_a,
76  double epsilon_r,
77  double tol,
78  int maxIters,
79  double convRate,
80  double relConvRate,
81  double maxConvRate,
82  double stagnationTol,
83  int maxBadSteps,
84  int checkDeviceConvergence,
85  double smallUpdateTol,
87  bool maskingFlag,
88  Linear::Vector * maskVectorPtr)
89  : comm_(comm),
90  status_(NOX::StatusTest::Unconverged),
91  returnTest_(0),
92  isTransient_(isTransient),
93  niters_(-1),
94  maxNormFindex_(-1),
95  maxNormF_(0.0),
96  requestedMaxNormF_(normF),
97  requestedMachPrecTol_(machPrec),
98  oldTimeStepVectorPtrPtr_(currSolVectorPtrPtr),
99  weightsVectorPtr_(0),
100  updateVectorPtr_(0),
101  tmpVectorPtr_(0),
102  epsilon_a_(epsilon_a),
103  epsilon_r_(epsilon_r),
104  tol_(tol),
105  weightedUpdate_(0.0),
106  maxIters_(maxIters),
107  requestedConvRate_(convRate),
108  currentConvRate_(1.0),
109  requestedRelativeConvRate_(relConvRate),
110  currentRelativeConvRate_(1.0),
111  normResidualInit_(1.0),
112  maxConvRate_(maxConvRate),
113  lastIteration_(-1),
114  badStepCount_(0),
115  minConvRate_(1.0),
116  stagnationTol_(stagnationTol),
117  maxBadSteps_(maxBadSteps),
118  xyceReturnCode_(0),
119  smallUpdateTol_(smallUpdateTol),
120  checkDeviceConvergence_(checkDeviceConvergence),
121  loaderPtr_(loader),
122  allDevicesConverged_(false),
123  innerDevicesConverged_(false),
124  maskingFlag_(NLS_MASKED_WRMS_NORMS && maskingFlag ),
125  deviceMaskFlag_( true ),
126  weightMaskVectorPtr_( maskVectorPtr)
127 {
128 
129 }
130 
132 {
133  if( weightsVectorPtr_ != 0 )
134  {
135  delete weightsVectorPtr_;
136  delete updateVectorPtr_;
137  delete tmpVectorPtr_;
138  }
139 }
140 
141 
142 NOX::StatusTest::StatusType
144  const NOX::Solver::Generic& problem,
145  NOX::StatusTest::CheckType checkType)
146 {
147  status_ = NOX::StatusTest::Unconverged;
148  xyceReturnCode_ = 0;
149  niters_ = problem.getNumIterations();
150 
151  returnTest_ = 0;
152 
153  // Get the current and previous solutions
154  const Linear::Vector& x = (dynamic_cast<const Vector&>
155  (problem.getSolutionGroup().getX())).getNativeVectorRef();
156  const Linear::Vector& oldX = (dynamic_cast<const Vector&>
157  (problem.getPreviousSolutionGroup().getX())).getNativeVectorRef();
158 
159  // Test0 - NaN/Inf checker
160  NOX::StatusTest::StatusType check = finiteTest_.checkStatus(problem, checkType);
161  if (check == NOX::StatusTest::Failed)
162  {
163  status_ = check;
164  returnTest_ = 0;
165  xyceReturnCode_ = retCodes_.nanFail; // default: -6
166  return status_;
167  }
168 
169  // This test is for 2-level solves only.
170  // If the inner solve failed, then the whole thing needs to fail.
171  // If 2-level is not being used, this test doesn't do anything.
174  {
175  status_ = NOX::StatusTest::Failed;
176  returnTest_ = 9;
177  xyceReturnCode_ = retCodes_.innerSolveFailed; // default: -5
178  return status_;
179  }
180 
181  // Test 8 - Devices need to satisfy their own convergence criteria
183  {
186  {
187  status_ = NOX::StatusTest::Unconverged;
188  returnTest_ = 8;
189  xyceReturnCode_ = 0;
190  return status_;
191  }
192  }
193 
194  //Test 1 - Make sure the residual isn't too small, hardwired tolerances
195  maxNormF_ = problem.getSolutionGroup().getF()
196  .norm(NOX::Abstract::Vector::MaxNorm);
197 
198  const Linear::Vector& F = (dynamic_cast<const Vector&>
199  (problem.getSolutionGroup().getF())).getNativeVectorRef();
200 
201  std::vector<int> index(1, -1);
202  F.infNormIndex( &index[0] );
203  maxNormFindex_ = index[0];
204 
205  if ((maxNormF_ < requestedMaxNormF_) &&
207  {
208  status_ = NOX::StatusTest::Converged;
209  returnTest_ = 1;
210  xyceReturnCode_ = retCodes_.normTooSmall; // default: 1
211  return status_;
212  }
213 
214  // Test 2 - Normal convergence based on rhs residual (2a) and
215  // update norm (2b).
216 
217  // Copy into local reference
218  Linear::Vector& oldTimeStepX = **oldTimeStepVectorPtrPtr_;
219 
220  // Allocate space if necessary
221  if (weightsVectorPtr_ == 0)
222  {
223  weightsVectorPtr_ = new Linear::Vector(x);
224  // when we create weightsVectorPtr_ from the latest solution, there
225  // is a chance that one of the values will be zero. If this isn't
226  // the DC op step or the first iteration of a time step, then
227  // we'll end up dividing by zero in the wMaxNorm function below.
228  // So to be safe we'll just add epsilon_a_ on the when we create
229  // this vector.
230  for (int i=0; i< x.localLength() ; ++i )
231  {
232  (*weightsVectorPtr_)[i] += epsilon_a_;
233  }
234  updateVectorPtr_ = new Linear::Vector(x);
235  tmpVectorPtr_ = new Linear::Vector(x);
236  }
237 
238  // Local references
239  Linear::Vector& weights = *weightsVectorPtr_;
240  Linear::Vector& update = *updateVectorPtr_;
241  Linear::Vector& tmp = *tmpVectorPtr_;
242 
243  // Compute local portion of weights vector
244  // Weights are recomputed at each nonlinear iteration of a DC Op calc
245  // but only at the beginning of a transient nonlinear solve.
246  if ((!isTransient_) || (niters_ == 0))
247  {
248  int length = x.localLength();
249  for (int i = 0; i < length; ++i )
250  {
251  //update[i] = x[i] - oldX[i];
252  weights[i] =
253  epsilon_r_ * std::max(fabs(x[i]), fabs(oldTimeStepX[i])) + epsilon_a_;
254  if (NLS_MASKED_WRMS_NORMS && maskingFlag_ && deviceMaskFlag_ && ((*weightMaskVectorPtr_)[i] == 0.0) )
255  {
256  weights[i] = Util::MachineDependentParams::MachineBig();
257  }
258  }
259  }
260 
261  if (niters_ < 1)
262  {
263  weightedUpdate_ = 1.0;
264  }
265  else
266  {
267  // Next compute the update
268  update.update(1.0, x, -1.0, oldX, 0.0);
269 
270  // Compute final result
271 #ifdef Xyce_SPICE_NORMS
272  update.wMaxNorm(weights,tmp,&weightedUpdate_);
273 #else
274  update.wRMSNorm(weights,&weightedUpdate_);
275 #endif
276 
277  // RPP: If a line search is being used, we must account for any
278  // damping of the step length. Otherwise delta X could be small due
279  // the line search and not due to being close to a solution.
280  const NOX::Solver::LineSearchBased* test = 0;
281  test = dynamic_cast<const NOX::Solver::LineSearchBased*>(&problem);
282  if (test != 0)
283  {
284  weightedUpdate_ = weightedUpdate_/(test->getStepSize());
285  }
286 
287  // RPP: 11/11/2003 - Fix for Bug 354 - Xyce fails in DC Op calc
288  // but proceeds to transient.
289  // Check to see if WRMS is exactly zero. If so the linear solver
290  // has failed. Return a failure. This should be commented out for
291  // Broyden runs.
292  // RPP: 02/18/2004 - Causing premature failures if deltaX is ~1e-16.
293  // Adding a check to look at norm of dx
294  // RPP: 08/09/2004 - Still goes into transient from failed DC Op on
295  // freebsd platforms for Down_8-bit_03.cir (bug 354). Changed return
296  // code from +4 to -4. This forces TIA to assume failure.
297  if ((weightedUpdate_ == 0.0) && (niters_ > 0))
298  {
299  if (!(problem.getPreviousSolutionGroup().isNewton()))
300  {
301  NOX::Abstract::Group & tmpGrp =
302  (const_cast<NOX::Abstract::Group&>(problem.getPreviousSolutionGroup()));
303  Teuchos::ParameterList tmpParams;
304  tmpGrp.computeNewton (tmpParams);
305  }
306 
307  const Linear::Vector& dx = (dynamic_cast<const Vector&>
308  (problem.getPreviousSolutionGroup().getNewton())).getNativeVectorRef();
309 
310  double tmp = 0.0;
311  dx.lpNorm(2, &tmp );
312  if (tmp == 0.0)
313  {
314  status_ = NOX::StatusTest::Failed;
315  returnTest_ = 4;
316  xyceReturnCode_ = retCodes_.wrmsExactZero; // default: -4
317  return status_;
318  }
319  }
320 
322  {
323  status_ = NOX::StatusTest::Converged;
324  returnTest_ = 2;
326  return status_;
327  }
328  }
329 
330  // Test 3 - Near Convergence - Hit max iterations but residual
331  // and convergence rate indicate we may be near a converged solution.
332  // Therefore, let the time stepper decide whether or not the step is ok.
333  // Transient mode ONLY!
334  // NOTE: Convergence rates are based on the 2-Norm, not max norm!
335  if (niters_ > 0)
336  {
337  // ||F(x_current)|| / ||F(x_previous)||
338  currentConvRate_ = (problem.getSolutionGroup().getNormF()) /
339  (problem.getPreviousSolutionGroup().getNormF());
340 
341  // ||F(x)|| / ||F(x_init)||
342  currentRelativeConvRate_ = (problem.getSolutionGroup().getNormF()) /
344  }
345  else
346  {
347  currentConvRate_ = 1.0;
349  }
350 
351  if (isTransient_)
352  {
353  if (niters_ == 0)
354  {
355  normResidualInit_ = problem.getSolutionGroup().getNormF();
356  }
357 
358  // Test only if we hit the max number of iterations
359  if (niters_ >= maxIters_)
360  {
363  {
364  status_ = NOX::StatusTest::Converged;
365  xyceReturnCode_ = retCodes_.nearConvergence; // default: 3
366 
367  if (xyceReturnCode_ < 0)
368  status_ = NOX::StatusTest::Failed;
369  else
370  status_ = NOX::StatusTest::Converged;
371  }
372  else
373  {
374  status_ = NOX::StatusTest::Failed;
375  xyceReturnCode_ = retCodes_.tooManySteps; // default: -1
376  }
377 
378  returnTest_ = 3;
379  return status_;
380  }
381  } // end test 3
382 
383  // Test 4 - Update is too small
384  if ((niters_ > 0) && (weightedUpdate_ < smallUpdateTol_) && (niters_ < maxIters_))
385  {
386  if (isTransient_) // Let the time integrator determine convergence (+4)
387  {
388  xyceReturnCode_ = retCodes_.smallUpdate; // default: 4
389  status_ = NOX::StatusTest::Failed;
390  }
391  else // Steady state should always return a hard failure -4
392  {
393  xyceReturnCode_ = 0; // neither pass nor fail.
394  status_ = NOX::StatusTest::Unconverged;
395 
396  //xyceReturnCode_ = retCodes_.wrmsExactZero; // default: -4
397  //status_ = NOX::StatusTest::Failed;
398  }
399 
400  returnTest_ = 4;
401 
402  return status_;
403  }
404 
405  // Test 5 - Max nonlinear iterations (if transient, this will be checked
406  // in the NearConvergence test (#3)
407  if ((!isTransient_) && (niters_ >= maxIters_))
408  {
409  status_ = NOX::StatusTest::Failed;
410  returnTest_ = 5;
411  xyceReturnCode_ = retCodes_.tooManySteps; // default: -1
412  return status_;
413  }
414 
415  // Test 6 - update is too big
417  {
418  status_ = NOX::StatusTest::Failed;
419  returnTest_ = 6;
420  xyceReturnCode_ = retCodes_.updateTooBig; // default: -2
421  return status_;
422  }
423 
424  // Test 7 - Stall in the convergence rate. Transient mode ONLY!
425  if (isTransient_)
426  {
427  // First time through we don't do anything but reset the counters
428  if (niters_ == 0)
429  {
430  badStepCount_ = 0;
431  lastIteration_ = 0;
432  //minConvRate = 1.0; // Don't reset this. Xyce solver never does.
433  }
434 
435  // Make sure we have not already counted the last nonlinear iteration.
436  // This protects against multiple calls to checkStatus() in between
437  // nonlinear iterations.
438  bool isCounted = false;
439  if (niters_ == lastIteration_)
440  {
441  isCounted = true;
442  }
443  else
444  {
446  }
447 
448  // Set counter appropriately
449  if (!isCounted)
450  {
451  if (fabs(currentConvRate_ - 1.0) <= stagnationTol_)
452  {
453  if ((badStepCount_ == 0) || (currentConvRate_ < minConvRate_))
454  {
456  }
457  ++badStepCount_ ;
458  }
459  else
460  {
461  badStepCount_ = 0;
462  }
463  }
464 
465  if (badStepCount_ >= maxBadSteps_)
466  {
467  if ((currentRelativeConvRate_ <= 0.9) && (minConvRate_ <= 1.0))
468  {
469  status_ = NOX::StatusTest::Converged;
470  returnTest_ = 7;
471  xyceReturnCode_ = retCodes_.nearConvergence; // default: 3
472  // note - I'm not sure if this is
473  // really a near convergece test - but 3 is the code for it...
474 
475  if (xyceReturnCode_ < 0)
476  status_ = NOX::StatusTest::Failed;
477  else
478  status_ = NOX::StatusTest::Converged;
479  }
480  else
481  {
482  status_ = NOX::StatusTest::Failed;
483  returnTest_ = 7;
484  xyceReturnCode_ = retCodes_.stalled; // default: -3
485  }
486  }
487  }
488 
489  return status_;
490 }
491 
492 std::ostream& XyceTests::print(std::ostream& stream, int indent) const
493 {
494  // precision
495  int p = 5;
496 
497  for (int j = 0; j < indent; ++j )
498  stream << ' ';
499  stream << status_ << "by Test #" << returnTest_ << "\n";
500 
501  indent += 4;
502 
503  //for (int j = 0; j < indent; ++j )
504  // stream << ' ';
505  finiteTest_.print(stream, indent);
506 
508  for (int j = 0; j < indent; ++j )
509  stream << ' ';
510  stream << "8. Devices are Converged: ";
512  stream << "true" << "\n";
513  else
514  stream << "false" << "\n";
515  }
516 
517  for (int j = 0; j < indent; ++j )
518  stream << ' ';
519  stream << "1. Inf-Norm F too small" << "\n";
520 
521  for (int j = 0; j < indent; ++j )
522  stream << ' ';
523  stream << " Machine Precision: " << NOX::Utils::sciformat(maxNormF_, p)
524  << " < " << NOX::Utils::sciformat(requestedMachPrecTol_, p) << "\n";
525 
526  for (int j = 0; j < indent; ++j )
527  stream << ' ';
528  stream << " Requested Tolerance: " << NOX::Utils::sciformat(maxNormF_, p)
529  << " < " << NOX::Utils::sciformat(requestedMaxNormF_, p) << "\n";
530 
531  for (int j = 0; j < indent; ++j )
532  stream << ' ';
533  stream << "2. Normal Convergence" << "\n";
534 
535  for (int j = 0; j < indent; ++j )
536  stream << ' ';
537  stream << " Inf-Norm F: " << NOX::Utils::sciformat(maxNormF_, p)
538  << " < " << NOX::Utils::sciformat(requestedMaxNormF_, p) << "\n";
539 
540  for (int j = 0; j < indent; ++j )
541  stream << ' ';
542  stream << " Weighted Update: " << NOX::Utils::sciformat(weightedUpdate_, p)
543  << " < " << NOX::Utils::sciformat(tol_, p) << "\n";
544 
545  for (int j = 0; j < indent; ++j )
546  stream << ' ';
547  stream << "3. Near Convergence" << "\n";
548 
549  for (int j = 0; j < indent; ++j )
550  stream << ' ';
551  stream << " Max Iters: " << niters_
552  << " < " << maxIters_ << "\n";
553 
554  for (int j = 0; j < indent; ++j )
555  stream << ' ';
556  stream << " Convergence Rate: "
557  << NOX::Utils::sciformat(currentConvRate_, p)
558  << " < " << NOX::Utils::sciformat(requestedConvRate_, p) << "\n";
559 
560  for (int j = 0; j < indent; ++j )
561  stream << ' ';
562  stream << " Relative Convergence Rate: "
563  << NOX::Utils::sciformat(currentRelativeConvRate_, p)
564  << " < " << NOX::Utils::sciformat(requestedRelativeConvRate_, p)
565  << "\n";
566 
567  for (int j = 0; j < indent; ++j )
568  stream << ' ';
569  stream << "4. Small Weighted Update: "
570  << NOX::Utils::sciformat(weightedUpdate_, p)
571  << " < " << NOX::Utils::sciformat(smallUpdateTol_, p) << "\n";
572 
573  if (!isTransient_) {
574 
575  for (int j = 0; j < indent; ++j )
576  stream << ' ';
577  stream << "5. Maximum Iterations: "
578  << niters_
579  << " < " << maxIters_ << "\n";
580 
581  for (int j = 0; j < indent; ++j )
582  stream << ' ';
583  stream << "6. Large Conv Rate: "
584  << NOX::Utils::sciformat(currentConvRate_, p)
585  << " < " << NOX::Utils::sciformat(maxConvRate_, p) << "\n";
586  }
587 
588  for (int j = 0; j < indent; ++j )
589  stream << ' ';
590  stream << "7. Stagnation " << "\n";
591 
592  for (int j = 0; j < indent; ++j )
593  stream << ' ';
594  stream << " Bad Step Count: "
595  << badStepCount_ << " < " << maxBadSteps_ << "\n";
596 
597  for (int j = 0; j < indent; ++j )
598  stream << ' ';
599  stream << " Stagnation Tolerance: "
600  << NOX::Utils::sciformat(fabs(currentConvRate_ - 1.0), p)
601  << " < " << NOX::Utils::sciformat(stagnationTol_, p) << "\n";
602 
603  stream << std::endl;
604  return stream;
605 }
606 
608 {
609  return xyceReturnCode_;
610 }
611 
613 {
614  return maxNormF_;
615 }
616 
618 {
619  return maxNormFindex_;
620 }
621 
622 }}}
Pure virtual class to augment a linear system.
Xyce::Loader::NonlinearEquationLoader * loaderPtr_
NOX::StatusTest::FiniteValue finiteTest_
Xyce::Linear::Vector ** oldTimeStepVectorPtrPtr_
Xyce::Nonlinear::ReturnCodes retCodes_
XyceTests(Parallel::Machine comm, bool isTransient, double normF, double machPrec, Xyce::Linear::Vector **currSolVectorPtrPtr, double epsilon_a, double epsilon_r, double tol, int maxIters, double convRate, double relConvRate, double maxConvRate, double stagnationTol, int maxBadSteps, int checkDeviceConvergence, double smallUpdateTol, Xyce::Loader::NonlinearEquationLoader *loader, bool maskingFlag, Xyce::Linear::Vector *maskVectorPtr)
std::ostream & print(std::ostream &stream, int indent=0) const
NOX::StatusTest::StatusType checkStatus(const NOX::Solver::Generic &problem, NOX::StatusTest::CheckType checkType)
Definition: N_NLS_fwd.h:107