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