Xyce  6.1
N_NLS_DampedNewton.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_DampedNewton.C,v $
27 //
28 // Purpose : Body file for the implemenation of the Newton trust-region
29 // related methods.
30 //
31 // Special Notes :
32 //
33 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
34 //
35 // Creation Date : 05/28/00
36 //
37 // Revision Information:
38 // ---------------------
39 //
40 // Revision Number: $Revision: 1.242.2.1 $
41 //
42 // Revision Date : $Date: 2015/04/02 18:20:17 $
43 //
44 // Current Owner : $Author: tvrusso $
45 //-------------------------------------------------------------------------
46 
47 #include <Xyce_config.h>
48 
49 // ---------- Standard Includes ----------
50 #include <vector>
51 
52 // ---------- Xyce Includes ----------
53 #include <N_ANP_AnalysisManager.h>
54 #include <N_ERH_ErrorMgr.h>
55 #include <N_IO_CmdParse.h>
56 #include <N_LAS_Builder.h>
57 #include <N_LAS_Matrix.h>
58 #include <N_LAS_Problem.h>
59 #include <N_LAS_Solver.h>
60 #include <N_LAS_System.h>
61 #include <N_LAS_Vector.h>
63 #include <N_NLS_ConstraintBT.h>
64 #include <N_NLS_DampedNewton.h>
65 #include <N_NLS_NonLinearSolver.h>
66 #include <N_NLS_ParamMgr.h>
67 #include <N_NLS_TwoLevelNewton.h>
68 #include <N_PDS_Comm.h>
69 #include <N_UTL_FeatureTest.h>
70 #include <N_UTL_OptionBlock.h>
71 #include <N_UTL_Param.h>
72 
73 // ---------- Static Initializations ----------
74 
75 namespace Xyce {
76 namespace Nonlinear {
77 
78 //-----------------------------------------------------------------------------
79 // Function : DampedNewton::DampedNewton
80 // Purpose : constructor
81 // Special Notes :
82 // Scope : public
83 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
84 // Creation Date : 5/01/00
85 //-----------------------------------------------------------------------------
87  const IO::CmdParse & cp)
88  : NonLinearSolver (cp),
89  nlParams(DC_OP,cp),
90  iNumCalls_(0),
91  loadJacobianFlag_(true),
92  nlConstraintPtr_(0),
93  searchDirectionPtr_(0),
94  tmpVectorPtr_(0),
95  delta_(pow(Util::MachineDependentParams::MachineEpsilon(), 0.67)),
96  // set the measures:
97  normRHS_(0.0),
98  maxNormRHS_(0.0),
99  maxNormRHSindex_(-1),
100  normRHS_init_(0.0),
101  normSoln_(0.0),
102  normDX_(0.0),
103  wtNormDX_(0.0),
104  stepLength_(1.0),
105  constraintFactor_(1.0),
106  nlStep_(0),
107  newtonStep_(0),
108  modNewtonStep_(0),
109  descentStep_(0),
110  searchStep_(0),
111  firstTime(true),
112  initialDeltaXTol(0.0),
113  etaOld(0.1),
114  nlResNormOld(0.0),
115  tmpConvRate(0.0),
116  count(0)
117 {
120 
122 }
123 
124 //-----------------------------------------------------------------------------
125 // Function : DampedNewton::~DampedNewton
126 // Purpose : destructor
127 // Special Notes :
128 // Scope : public
129 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
130 // Creation Date : 5/01/00
131 //-----------------------------------------------------------------------------
133 {
134  delete tmpVectorPtr_;
135  delete nlConstraintPtr_;
136  delete searchDirectionPtr_;
138  delete jdxVLVectorPtr_;
139  delete fdxVLVectorPtr_;
140  delete qdxVLVectorPtr_;
141 }
142 
143 //-----------------------------------------------------------------------------
144 // Function : DampedNewton::setOptions
145 // Purpose : Sets the nonlinear solver options.
146 // Special Notes :
147 // Scope : public
148 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
149 // Creation Date : 9/29/00
150 //-----------------------------------------------------------------------------
151 bool DampedNewton::setOptions(const Util::OptionBlock & OB)
152 {
153  bool bsuccess = nlParams.setOptions(OB);
154 
157 
158  return bsuccess;
159 }
160 
161 //-----------------------------------------------------------------------------
162 // Function : DampedNewton::setTranOptions
163 // Purpose : Sets the nonlinear solver options.
164 // Special Notes :
165 // Scope : public
166 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
167 // Creation Date : 9/05/01
168 //-----------------------------------------------------------------------------
169 bool DampedNewton::setTranOptions(const Util::OptionBlock & OB)
170 {
171  NLParams nlTranParams(TRANSIENT, commandLine_);
172  bool bsuccess = nlTranParams.setOptions(OB);
173 
175  return bsuccess;
176 }
177 
178 //-----------------------------------------------------------------------------
179 // Function : DampedNewton::setHBOptions
180 // Purpose : Sets the nonlinear solver options.
181 // Special Notes :
182 // Scope : public
183 // Creator : Ting Mei, SNL
184 // Creation Date : 02/03/2009
185 //-----------------------------------------------------------------------------
186 bool DampedNewton::setHBOptions(const Util::OptionBlock & OB)
187 {
188  NLParams nlHBParams(HB_MODE, commandLine_);
189  bool bsuccess = nlHBParams.setOptions(OB);
190 
192  return bsuccess;
193 }
194 
195 //-----------------------------------------------------------------------------
196 // Function : DampedNewton::initializeAll
197 // Purpose : Called after all register and set functions.
198 // Once the various registrations have taken place,
199 // this function sets the remaining pointers.
200 // Special Notes :
201 // Scope : public
202 // Creator : Tamara G. Kolda, SNL, Compuational Sciences and
203 // Creation Date : 1/31/02
204 //-----------------------------------------------------------------------------
206 {
207  bool bsuccess = NonLinearSolver::initializeAll();
208 
209  tmpVectorPtr_ = lasSysPtr_->builder().createVector();
210 
211  // make sure the current nlParams is correct.
213 
214  // create and initialize constraint backtracking vectors:
216 
217  searchDirectionPtr_ = lasSysPtr_->builder().createVector();
218 
219  if (DEBUG_VOLTLIM)
220  {
221  // get the dx vector (due to voltage limiting)
222  dxVoltlimVectorPtr_ = lasSysPtr_->getDxVoltlimVector();
223 
224  // this vector is for debug purposes:
225  jdxVLVectorPtr_ = lasSysPtr_->builder().createVector();
226  fdxVLVectorPtr_ = lasSysPtr_->builder().createVector();
227  qdxVLVectorPtr_ = lasSysPtr_->builder().createVector();
228 
229  // get the test matrices
230  jacTestMatrixPtr_ = lasSysPtr_->getJacTestMatrix(); // old-DAE
231  dFdxTestMatrixPtr_ = lasSysPtr_->getdFdxTestMatrix(); // new-DAE
232  dQdxTestMatrixPtr_ = lasSysPtr_->getdQdxTestMatrix(); // new-DAE
233  }
234 
235  bsuccess = bsuccess && (jacobianMatrixPtr_ != 0);
236 
237  return bsuccess;
238 }
239 
240 //-----------------------------------------------------------------------------
241 // Function : DampedNewton::printHeader_
242 // Purpose : Print out header for step information.
243 // Special Notes :
244 // Scope : private
245 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
246 // Creation Date : 5/03/00
247 //-----------------------------------------------------------------------------
248 void DampedNewton::printHeader_(std::ostream &os)
249 {
250  os << std::endl
251  << " Iter Step Wt DX Inf-Norm 2-Norm (rel)\n"
252  << " -------------------------------------------------------------------\n";
253 }
254 
255 //-----------------------------------------------------------------------------
256 // Function : DampedNewton::printFooter_
257 // Purpose :
258 // Special Notes :
259 // Scope : private
260 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
261 // Creation Date : 5/03/11
262 //-----------------------------------------------------------------------------
263 void DampedNewton::printFooter_(std::ostream &os)
264 {
265  os << Xyce::section_divider << std::endl;
266 }
267 
268 //-----------------------------------------------------------------------------
269 // Function : DampedNewton::printStepInfo_
270 // Purpose : Print out Newton step information
271 // Special Notes :
272 // Scope : public
273 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
274 // Creation Date : 5/03/00
275 //-----------------------------------------------------------------------------
276 void DampedNewton::printStepInfo_(std::ostream &os, int step)
277 {
278  os << "Niter: " << std::fixed << step
279  << " " << std::setprecision(4) << std::scientific << stepLength_
280  << " " << std::setprecision(4) << std::scientific << wtNormDX_
281  << " " << std::setprecision(4) << std::scientific << maxNormRHS_
282  << " " << std::setprecision(4) << std::scientific << normRHS_rel_
283  << std::endl;
284 }
285 
286 //-----------------------------------------------------------------------------
287 // Function : DampedNewton::updateWeights_
288 // Purpose : Updates the error weight vector using the previous solution
289 // values as "typical" and the absolute and relative
290 // tolerances.
291 // Special Notes :
292 // Scope : private
293 // Creator : Scott A. Hutchinson, SNL, Computational Sciences
294 // Creation Date : 01/17/01
295 //-----------------------------------------------------------------------------
297 {
298  // ***** Weighting Vector for Solution *****
299 
300  // On the first call to the nonlinear solver,
301  // weigh based on the minimums.
302  double tmp = 0.0;
303  (*nextSolVectorPtrPtr_)->maxValue(&tmp);
304  double solnNorm = fabs(tmp);
305 
306  if ((iNumCalls_ == 0) && (solnNorm <= Util::MachineDependentParams::DoubleMin()))
307  {
309  }
310  else
311  {
312  double newSoln, oldSoln;
313 
314  int length = (*nextSolVectorPtrPtr_)->localLength();
315  for (int i = 0; i < length; ++i)
316  {
317  newSoln = (*(*nextSolVectorPtrPtr_))[i];
318  oldSoln = (*(*currSolVectorPtrPtr_))[i];
319 
320  (*(solWtVectorPtr_))[i] =
321  nlParams.getRelTol() * std::max(fabs(oldSoln), fabs(newSoln)) +
323  }
324  }
325 }
326 
327 //-----------------------------------------------------------------------------
328 // Function : DampedNewton::solve
329 // Purpose : solve implements a damped Newton method nonlinear equations
330 // solver.
331 // Special Notes : The implementation is based upon the original damped Newton
332 // method implemented in Xyce(TM) by Eric Keiter.
333 //
334 // Selected variables and methods:
335 //
336 // nextSolVector the approximate solution to the nonlinear equation
337 // The rhsVector and jacobianMatrix load nextSolVector.
338 //
339 // equateTmpVectors_ tmpSolVector := nextSolVector
340 // updateTmpSol_ tmpSolVector := nextVector + searchDirection*stepLength_
341 //
342 // switchTmpVectors swap &tmpSolVector and &nextSolVector, makes it possible
343 // for the nonlinear solver to preserve the entire
344 // circuit state associated with nextSolVector.
345 //
346 // Scope : public
347 // Creator : Scott A. Hutchinson, SNL, Computational Sciences
348 // Creation Date : 01/09/01
349 //-----------------------------------------------------------------------------
351 {
352  static const char *trace = "DampedNewton::solve: ";
353 
354  if (DEBUG_NONLINEAR)
355  {
356  setDebugFlags(getAnalysisManager().getStepNumber() + 1, getAnalysisManager().getTime());
357 
358  if (debugTimeFlag_ && nlParams.getDebugLevel() > 0 )
359  Xyce::dout() << retCodes_;
360  }
361 
363 
364  // Change the nlparams so that they are appropriate for the current
365  // time integration mode, if neccessary.
367 
368  // Get the current analysis mode
370 
371  if (mode1 == TRANSIENT)
372  {
373  // Set the tolerance
374  lasSolverPtr_->setTolerance(1.0e-09);
375  }
376 
377 #ifndef Xyce_SPICE_NORMS
378  if (firstTime)
379  {
380  // First time through we want to tighten up the convergence tolerance a la
381  // Petzold, et al. The DeltaXTol parameter is used by converge_().
384  firstTime = false;
385  }
386 #endif
387 
388  // Output the nonlinear solver information header:
389  if (VERBOSE_NONLINEAR)
390  printHeader_(Xyce::lout());
391 
392  // Print warning about using the gradient-only strategy
393  if (VERBOSE_NONLINEAR && nlParams.getNLStrategy() == GRADIENT)
394  Xyce::Report::UserWarning0() << "Use of the gradient strategy (1) is discouraged";
395 
396  // For the initial RHS load, the step number needs to be zero. The Xyce
397  // device package needs to know this - either in the event that it might want
398  // to set initial conditions.
400 
401  // Recall that prior to this solver being called, the new solution has been
402  // predicted and resides in nextSolVectorPtr.
403  rhs_();
404 
405  if (VERBOSE_NONLINEAR)
406  {
407  // Set some values and dummy values so that we can call printStepInfo_().
408 
409  // Relative RHS norm (normRHS_rel_). On the first evaluation this is one
410  // since normRHS_init = normRHS.
411  normRHS_rel_ = 1.0;
412 
413  // Weighted norm of the change (wtNormDX_) is set to zero initially.
414  wtNormDX_ = 0.0;
415 
416  // Max RHS norm (maxNormRHS_).
417  rhsVectorPtr_->infNorm(&maxNormRHS_);
418  std::vector<int> index(1, -1);
419  rhsVectorPtr_->infNormIndex( &index[0] );
420  maxNormRHSindex_ = index[0];
421 
422  // Print out the starting point information.
423  printStepInfo_(Xyce::lout(), nlStep_);
424  }
425 
426  // Check to ensure that we haven't been passed a converged solution already
427  // (i.e., normRHS < absTol)
428 
429  if (normRHS_ < Util::MachineDependentParams::MachineEpsilon())
430  {
431  return true;
432  }
433 
434  // Used to calculate resConvRate which is used by converged_(). This changes
435  // each nonlinear iteration to be the norm of the RHS from the previous
436  // iteration.
437  double normRHS_old = normRHS_;
438 
439  // Used to calculate normRHS_rel_, which is output by printStepInfo_().
441 
442  // Set the flag that controls the loading and solution of the Jacobian
443  // matrix.
444  if (nlParams.getLinearOpt())
446  else
447  loadJacobianFlag_ = true;
448 
449  // Update the error weighting vector for use with the weighted norms.
450  if (mode1 == TRANSIENT)
451  updateWeights_();
452 
453  // Nonlinear loop. Loop continues until convergedStatus is nonzero. A
454  // positive value indicates that the method has converged. A negative value
455  // that the method has failed. This is updated using the subroutine
456  // converged_() at the end of each nonlinear solver iteration.
457  int convergedStatus = 0;
458  while (convergedStatus == 0)
459  {
460  // Increment step counters. This needs to be updated *before* the rhs_
461  // call, which is inside of computeStepLength_.
462  nlStep_++;
463 
464  // Calculate the Jacobian for the current iterate.
465  if (loadJacobianFlag_)
466  jacobian_();
467 
468  if (DEBUG_NONLINEAR)
469  debugOutput1( *(lasSysPtr_->getJacobianMatrix()), *(lasSysPtr_->getRHSVector()));
470 
471  // Calculate a direction.
472  // Note: It is illegal to modify tmpVector between direction_ and
473  // computeStepLength_
474  direction_();
475 
476  // Perform update constraining...
479 
480  setX0_();
481 
482  // Calculate a step length (damping or backtracking for Newton, line search
483  // for others...) and take that step and recalulate the RHS.
485 
486  if (DEBUG_NONLINEAR)
488 
489  // Test for convergence based on the weighted norms of the RHS and DX.
490  // Also update convergence rate and counters.
491 
492  // Update the error weighting vector for use with the weighted norms.
493  if (mode1 != TRANSIENT)
494  updateWeights_();
495 
496  // Scale the search direction so that we can calculate some norms on it and
497  // use them in the convergence tests and output.
499 
500  // Weighted norm of the change (wtNormDX_) is used in converged_() and
501  // output by printStepInfo_().
502 
503 #ifdef Xyce_SPICE_NORMS
504  // TGKOLDA: Why is tmpVectorPtr_ used here and where was it set??
506  *tmpVectorPtr_,
507  &wtNormDX_);
508 #else
510 #endif
511 
512  // Relative RHS norm (normRHS_rel_) is output by printStepInfo_().
514 
515  // Max RHS norm (maxNormRHS_) is used in converged_() and output by
516  // printStepInfo_().
517  rhsVectorPtr_->infNorm(&maxNormRHS_);
518 
519  // Residual convergence rate (resConvRate) used by converged_(),
520  // also printed out below.
521  resConvRate_ = normRHS_ / normRHS_old;
522 
523  // Reset old norm for next nonlinear iteration.
524  normRHS_old = normRHS_;
525 
526  if (VERBOSE_NONLINEAR)
527  printStepInfo_(Xyce::lout(), nlStep_);
528 
529  // Increment diagnostic step counters. These need to be updated after
530  // direction_, in which the current direction (NEWTON_DIR,
531  // MOD_NEWTON_DIR or GRADIENT_DIR) is set.
533  newtonStep_++;
534  else if (nlParams.getDirection() == MOD_NEWTON_DIR)
535  modNewtonStep_++;
536  else if (nlParams.getDirection() == GRADIENT_DIR)
537  descentStep_++;
538 
539  // Evaluate the need for a fresh Jacobian and/or preconditioner...
541  evalModNewton_();
542 
543  // Check our iteration status. Returns positive if done, negative if error,
544  // zero otherwise.
545  convergedStatus = converged_();
546 
547  // If the norm is an NaN, then exit.
548  if (maxNormRHS_ != 0.0 &&
549  !(maxNormRHS_ < 0.0) &&
550  !(maxNormRHS_ > 0.0))
551  {
552  convergedStatus = retCodes_.nanFail; // default = -6
553  //break;
554  }
555 
556  } // while (convergedStatus == 0)
557 
558 #ifndef Xyce_SPICE_NORMS
559  // Reset the tolerance which is used in converged_().
561 #endif
562 
563  // Reset the linear solver tolerance.
564  lasSolverPtr_->setDefaultOption( "AZ_tol" );
565 
566  // Increment the number of calls to the nonlinear solver.
567  iNumCalls_++;
568 
569  if (VERBOSE_NONLINEAR)
570  printFooter_(Xyce::lout());
571 
572  // A positive value of convergedStatus indicates a successful nonlinear
573  // solutions. Otherwise, there was an error.
574  return convergedStatus;
575 }
576 
577 //-----------------------------------------------------------------------------
578 // Function : DampedNewton::takeFirstSolveStep
579 //
580 // Purpose : This is the same as the function "solve", except that
581 // it only does the various initializations at the top
582 // of the "::solve" function, and only takes the first
583 // NL step.
584 //
585 // Special Notes :
586 // Scope : public
587 // Creator : Eric R. Keiter, SNL, Computational Sciences
588 // Creation Date : 01/09/01
589 //-----------------------------------------------------------------------------
590 int
592  NonLinearSolver * nlsTmpPtr)
593 {
594  static const char *trace = "DampedNewton::takeFirstSolveStep: ";
595 
596  if (DEBUG_NONLINEAR)
597  setDebugFlags(getAnalysisManager().getStepNumber() + 1, getAnalysisManager().getTime());
598 
599  // resolve the counters issue later. It may be neccessary to save the
600  // counters for later. Or not.
602 
603  // Change the nlparams so that they are appropriate for the current
604  // time integration mode, if neccessary.
606 
608  lasSolverPtr_->setTolerance(1.0e-09);
609 
610  // Output the nonlinear solver information header:
611  if (VERBOSE_NONLINEAR)
612  printHeader_(Xyce::lout());
613 
614  // Print warning about using the gradient-only strategy
615  if (VERBOSE_NONLINEAR && nlParams.getNLStrategy() == GRADIENT)
616  Xyce::Report::UserWarning0() << "Use of the gradient strategy (1) is discouraged";
617 
618  // For the initial RHS load, the step number needs to be zero. The Xyce
619  // device package needs to know this - either in the event that it might want
620  // to set initial conditions.
622 
623  // Recall that prior to this solver being called, the new solution has been
624  // predicted and resides in nextSolVectorPtr.
625  rhs_();
626 
627  if (VERBOSE_NONLINEAR)
628  {
629  // Set some values and dummy values so that we can call printStepInfo_().
630 
631  // Relative RHS norm (normRHS_rel_). On the first evaluation this is one
632  // since normRHS_init = normRHS.
633  normRHS_rel_ = 1.0;
634 
635  // Weighted norm of the change (wtNormDX_) is set to zero initially.
636  wtNormDX_ = 0.0;
637 
638  // Max RHS norm (maxNormRHS_).
639  rhsVectorPtr_->infNorm(&maxNormRHS_);
640 
641  // Print out the starting point information.
642  printStepInfo_(Xyce::lout(), nlStep_);
643  }
644 
645  // Check to ensure that we haven't been passed a converged solution already
646  // (i.e., normRHS < absTol)
647  if (normRHS_ < Util::MachineDependentParams::MachineEpsilon()) return 1;
648 
649  // Used to calculate resConvRate which is used by converged_(). This changes
650  // each nonlinear iteration to be the norm of the RHS from the previous
651  // iteration.
652  double normRHS_old = normRHS_;
653 
654  // Used to calculate normRHS_rel_, which is output by printStepInfo_().
656 
657  // Set the flag that controls the loading and solution of the Jacobian
658  // matrix.
659  if (nlParams.getLinearOpt())
661  else
662  loadJacobianFlag_ = true;
663 
664  // The variable convergedStatus: positive value indicates that
665  // the method has converged. A negative value
666  // that the method has failed. This is updated using the subroutine
667  // converged_() at the end of each nonlinear solver iteration.
668  int convergedStatus = 0;
669 
670  // Increment step counters. This needs to be updated *before* the rhs_
671  // call, which is inside of computeStepLength_.
672  nlStep_++;
673 
674  // Calculate the Jacobian for the current iterate.
676 
677  if (DEBUG_NONLINEAR)
678  debugOutput1( *(lasSysPtr_->getJacobianMatrix()), *(lasSysPtr_->getRHSVector()));
679 
680  // Calculate a direction.
681  // Note: It is illegal to modify tmpVector between direction_ and
682  // computeStepLength_
683  direction_();
684 
685  // Perform update constraining...
688 
689  setX0_();
690 
691  // Calculate a step length (damping or backtracking for Newton, line search
692  // for others...) and take that step and recalulate the RHS.
694 
695  if (DEBUG_NONLINEAR)
697 
698  // Test for convergence based on the weighted norms of the RHS and DX.
699  // Also update convergence rate and counters. 1. Update the error
700  // weighting vector for use with the weighted norms.
701  updateWeights_();
702 
703  // Scale the search direction so that we can calculate some norms on it and
704  // use them in the convergence tests and output.
706 
707  // Weighted norm of the change (wtNormDX_) is used in converged_() and
708  // output by printStepInfo_().
709 
710 #ifdef Xyce_SPICE_NORMS
711  // TGKOLDA: Why is tmpVectorPtr_ used here and where was it set??
713  *tmpVectorPtr_,
714  &wtNormDX_);
715 #else
717 #endif
718 
719  // Relative RHS norm (normRHS_rel_) is output by printStepInfo_().
721 
722  // Max RHS norm (maxNormRHS_) is used in converged_() and output by
723  // printStepInfo_().
724  rhsVectorPtr_->infNorm(&maxNormRHS_);
725 
726  // Residual convergence rate (resConvRate) used by converged_(),
727  // also printed out below.
728  resConvRate_ = normRHS_ / normRHS_old;
729 
730  // Reset old norm for next nonlinear iteration.
731  normRHS_old = normRHS_;
732 
733  if (VERBOSE_NONLINEAR)
734  printStepInfo_(Xyce::lout(), nlStep_);
735 
736  // Increment diagnostic step counters. These need to be updated after
737  // direction_, in which the current direction (NEWTON_DIR,
738  // MOD_NEWTON_DIR or GRADIENT_DIR) is set.
740  newtonStep_++;
741  else if (nlParams.getDirection() == MOD_NEWTON_DIR)
742  modNewtonStep_++;
743  else if (nlParams.getDirection() == GRADIENT_DIR)
744  descentStep_++;
745 
746  // Evaluate the need for a fresh Jacobian and/or preconditioner...
748  evalModNewton_();
749 
750  // Check our iteration status. Returns positive if done, negative if error,
751  // zero otherwise.
752  convergedStatus = converged_();
753 
754 #ifndef Xyce_SPICE_NORMS
755 #if 0
756  // Reset the tolerance which is used in converged_().
758 #endif
759 #endif
760 
761  // Reset the linear solver tolerance.
762  lasSolverPtr_->setDefaultOption( "AZ_tol" );
763 
764  // Increment the number of calls to the nonlinear solver.
765  iNumCalls_++;
766 
767  // A positive value of convergedStatus indicates a successful nonlinear
768  // solutions. Otherwise, there was an error.
769  return convergedStatus;
770 }
771 
772 //-----------------------------------------------------------------------------
773 // Function : DampedNewton::takeOneSolveStep
774 //
775 // Purpose : Just like "::initializeSolve" is essentially the top
776 // of the "::solve" function, this function is similar
777 // to the bottom of the "::solve" function. This
778 // function also only takes a single NL step.
779 //
780 // The main differences between this function and solve are:
781 // 1) There is no while loop. - this is only a single
782 // step.
783 //
784 // 2) Most tasks performed prior to the while loop are not
785 // performed here, as they are initialization tasks.
786 // These include:
787 
788 // - step counters, such as "nlStep_" and "newtonStep_"
789 // are not reset to zero.
790 //
791 // - The function "resetCountersAndTimers" is not called.
792 // This may be fixed up later.
793 //
794 // - The resetting of the deltaXtol, which is performed
795 // on the "first call" to ::solve, is not done.
796 // I'll have to sort this out later as well.
797 //
798 // - the loadJacobianFlag is not updated - assumed to
799 // have not changed.
800 //
801 // Special Notes :
802 // Scope : public
803 // Creator : Eric R. Keiter, SNL, Computational Sciences
804 // Creation Date : 01/09/01
805 //-----------------------------------------------------------------------------
807 {
808  static const char *trace = "DampedNewton::takeOneSolveStep";
809 
810  if (DEBUG_NONLINEAR)
811  setDebugFlags(getAnalysisManager().getStepNumber() + 1, getAnalysisManager().getTime());
812 
813  // Change the nlparams so that they are appropriate for the current
814  // time integration mode, if neccessary.
816 
818  lasSolverPtr_->setTolerance(1.0e-09);
819 
820  // Recall that prior to this solver step being called, a new solution has been
821  // predicted and resides in nextSolVectorPtr.
822  rhs_();
823 
824  // Used to calculate resConvRate which is used by converged_(). This changes
825  // each nonlinear iteration to be the norm of the RHS from the previous
826  // iteration.
827  double normRHS_old = normRHS_;
828 
829  // Nonlinear loop. Loop continues until convergedStatus is nonzero. A
830  // positive value indicates that the method has converged. A negative value
831  // that the method has failed. This is updated using the subroutine
832  // converged_() at the end of each nonlinear solver iteration.
833  int convergedStatus = 0;
834 
835  // Increment step counters. This needs to be updated *before* the rhs_
836  // call, which is inside of computeStepLength_.
837  nlStep_++;
838 
839  // Calculate the Jacobian for the current iterate.
840  if (loadJacobianFlag_)
841  jacobian_();
842 
843  if (DEBUG_NONLINEAR)
844  debugOutput1( *(lasSysPtr_->getJacobianMatrix()), *(lasSysPtr_->getRHSVector()));
845 
846  // Calculate a direction.
847  // Note: It is illegal to modify tmpVector between direction_ and
848  // computeStepLength_
849  direction_();
850 
851  // Perform update constraining...
854 
855  setX0_();
856 
857  // Calculate a step length (damping or backtracking for Newton, line search
858  // for others...) and take that step and recalulate the RHS.
860 
861  if (DEBUG_NONLINEAR)
863 
864  // Test for convergence based on the weighted norms of the RHS and DX.
865  // Also update convergence rate and counters. 1. Update the error
866  // weighting vector for use with the weighted norms.
867  updateWeights_();
868 
869  // Scale the search direction so that we can calculate some norms on it and
870  // use them in the convergence tests and output.
872 
873  // Weighted norm of the change (wtNormDX_) is used in converged_() and
874  // output by printStepInfo_().
875 
876 #ifdef Xyce_SPICE_NORMS
877  // TGKOLDA: Why is tmpVectorPtr_ used here and where was it set??
879  *tmpVectorPtr_,
880  &wtNormDX_);
881 #else
883 #endif
884 
885  // Relative RHS norm (normRHS_rel_) is output by printStepInfo_().
887 
888  // Max RHS norm (maxNormRHS_) is used in converged_() and output by
889  // printStepInfo_().
890  rhsVectorPtr_->infNorm(&maxNormRHS_);
891 
892  // Residual convergence rate (resConvRate) used by converged_(),
893  // also printed out below.
894  resConvRate_ = normRHS_ / normRHS_old;
895 
896  // Reset old norm for next nonlinear iteration.
897  normRHS_old = normRHS_;
898 
899  if (VERBOSE_NONLINEAR)
900  printStepInfo_(Xyce::lout(), nlStep_);
901 
902  // Increment diagnostic step counters. These need to be updated after
903  // direction_, in which the current direction (NEWTON_DIR,
904  // MOD_NEWTON_DIR or GRADIENT_DIR) is set.
906  newtonStep_++;
907  else if (nlParams.getDirection() == MOD_NEWTON_DIR)
908  modNewtonStep_++;
909  else if (nlParams.getDirection() == GRADIENT_DIR)
910  descentStep_++;
911 
912  // Evaluate the need for a fresh Jacobian and/or preconditioner...
914  evalModNewton_();
915 
916  // Check our iteration status. Returns positive if done, negative if error,
917  // zero otherwise.
918  convergedStatus = converged_();
919 
920  if (DEBUG_NONLINEAR && convergedStatus > 0)
921  {
922  // ERK Note: this one needs the nl solve step incremented by 1!
923 // nlStep_++;
924  debugOutput1(*lasSysPtr_->getJacobianMatrix(), *lasSysPtr_->getRHSVector());
925 // nlStep_--; // restore original value.
926  }
927 
928  // Reset the linear solver tolerance.
929  lasSolverPtr_->setDefaultOption( "AZ_tol" );
930 
931  // Increment the number of calls to the nonlinear solver.
932  iNumCalls_++;
933 
934  // A positive value of convergedStatus indicates a successful nonlinear
935  // solutions. Otherwise, there was an error.
936  return convergedStatus;
937 }
938 
939 //-----------------------------------------------------------------------------
940 // Function : DampedNewton::updateX_()
941 //
942 // Purpose : Update the value of nextSolVectorPtr_ using
943 // steplength and the searchDirectionPtr_. On input, it is
944 // assumed that tmpSolVectorPtr_ contains the intial guess for
945 // the nonlinear iteration, i.e., setX0_ was called earlier.
946 //
947 // Special Notes : Also modifies errorEstVectorPtr_. Only this and
948 // updateX_() should modify the solution directly.
949 //
950 // ERK: This is new version of this function, hopefully less
951 // confusing. The roles of "tmp" and "next" have been
952 // reversed, which removes the need for some of the switch
953 // functions.
954 //
955 // Scope : private
956 // Creator : Tamara G. Kolda, SNL, Compuational Sciences and
957 // Mathematics Research Department
958 //
959 // Eric Keiter, SNL, Parallel Computational Sciences (9233)
960 //
961 // Creation Date : 01/24/02
962 //-----------------------------------------------------------------------------
964 {
965  (*nextSolVectorPtrPtr_)->daxpy(**tmpSolVectorPtrPtr_,
966  stepLength_,
968 }
969 
970 //-----------------------------------------------------------------------------
971 // Function : DampedNewton::rhs_()
972 // Purpose : Updates the RHS based on nextSolVectorPtrPtr_ and
973 // calculates normRHS_ based on nlParams.getNormLevel().
974 // Special Notes : The rhsVectorPtr_ is really the NEGATIVE of F(x).
975 // Scope : private
976 // Creator : Tamara G. Kolda, SNL, Compuational Sciences and
977 // Mathematics Research Department
978 // Creation Date : 06/19/01
979 //-----------------------------------------------------------------------------
981 {
982  bool status = NonLinearSolver::rhs_();
983 
984  if (DEBUG_NONLINEAR)
986 
988 
989  return status;
990 }
991 
992 //-----------------------------------------------------------------------------
993 // Function : DampedNewton::newtonDirection_
994 // Purpose : Computes the Newton Direction inexactly using
995 // jacobianMatrixPtr_ and the rhsVectorPtr_.
996 // On output, NewtonVectorPtr_ contains the Newton
997 // Direction.
998 // Special Notes : This is *not* meant to override newton_ in
999 // NonLinearSolver.
1000 // Scope : private
1001 // Creator : Tamara G. Kolda, SNL, Compuational Sciences and
1002 // Mathematics Research Department
1003 // Creation Date : 06/19/01
1004 //-----------------------------------------------------------------------------
1006 {
1007  // Set the solver tolerance based on the residual norm.
1009 
1010  return NonLinearSolver::newton_();
1011 }
1012 
1013 //-----------------------------------------------------------------------------
1014 // Function : DampedNewton::direction_
1015 // Purpose : The function calculates the direction vector used in
1016 // the nonlinear solver (e.g., Newton direction).
1017 // Special Notes : If the search direction is a Newton direction, then a linear
1018 // system is solved inexactly. To ensure that the approximate
1019 // solution is a descent direction, the projection of the
1020 // solution along the gradient is computed to working
1021 // precision. On output, searchDirectionPtr_ points to the
1022 // search direction vector. The vector allocated to store the
1023 // NewtonVector is always used to store the
1024 // SearchDirectionVector, regardless of the actual algorithm
1025 // used to determine the search direction.
1026 // Scope : private
1027 // Creator : Scott A. Hutchinson, SNL, Computational Sciences Department
1028 // Creation Date : 02/21/01
1029 //-----------------------------------------------------------------------------
1031 {
1032  static const char *trace = "DampedNewton::direction_: ";
1033 
1034  // --- Set the Direction Type ---
1035  switch (nlParams.getNLStrategy())
1036  {
1037  case NEWTON:
1039  break;
1040 
1041  case MOD_NEWTON:
1043  break;
1044 
1045  case NEWTON_GRADIENT:
1046  {
1047  const double minRedFac = 0.999;
1048  if ((nlStep_ > 15) || (resConvRate_ > minRedFac))
1050  else
1052 
1053  break;
1054  }
1055  case MOD_NEWTON_GRADIENT:
1056  {
1057  const double minRedFac = 0.999;
1058  if ((nlStep_ > 15) || (resConvRate_ > minRedFac))
1059  {
1061  }
1062  else
1063  {
1065  }
1066  break;
1067  }
1068  case GRADIENT:
1070  break;
1071 
1072  default:
1074  break;
1075 
1076  } // end switch on nlParams.getNLStrategy()
1077 
1078  // --- Calculate SearchDirection ---
1079  switch (nlParams.getDirection())
1080  {
1081  case NEWTON_DIR:
1082 
1083  // Compute the Newton direction
1084  newton_();
1085 
1086  // Copy the Newton direction into the search direction
1088 
1089  break;
1090 
1091  case MOD_NEWTON_DIR:
1092 
1093  // Compute the modified-Newton direction
1094  newton_();
1095 
1096  // Copy the modified-Newton direction into the search direction
1098 
1099  break;
1100 
1101  case GRADIENT_DIR:
1102 
1103  // Compute the gradient
1104  gradient_();
1105 
1106  // Copy Gradient into Search Direction, then Reverse and scale
1107  // search direction. (Can this be done in one operation??)
1109  searchDirectionPtr_->scale(-1.0 / normRHS_);
1110 
1111  break;
1112 
1113  default:
1114 
1115  if (DEBUG_NONLINEAR)
1116  Xyce::Report::DevelFatal0().in("DampedNewton::direction_") << "Invalid search direction: " << static_cast<int>(nlParams.getDirection());
1117 
1118  break;
1119 
1120  } // end switch on nlParams.getDirection()
1121 
1122 } // end direction_
1123 
1124 //-----------------------------------------------------------------------------
1125 // Function : DampedNewton::computeStepLength_
1126 // Purpose : This function calculates the step length for a given search
1127 // direction. If the search direction is Newton, it may use one
1128 // of a variety of backtracking methods including on suggested
1129 // by
1130 // Special Notes : !!!!!NOTE: In this method, we use the term FULLSTEP to mean
1131 // the maximum allowed Newton step (0..1). fullStep = 1.
1132 // corresponds to a Newton step, but when computeStepLength_
1133 // is coupled with a constraint back tracking, 0<fullStep<=1.
1134 // Scope : private
1135 // Creator : Scott A. Hutchinson, SNL, Computational Sciences Department
1136 // Creation Date : 02/21/01
1137 //-----------------------------------------------------------------------------
1139 
1140 {
1141  static const char *trace = "DampedNewton::computeStepLength_";
1142 
1143  searchStep_ = 0; // number of search steps
1144 
1145  // Choose step length approach based on the current solution method.
1146  switch (nlParams.getSearchMethod())
1147  {
1148  case DIVIDE:
1149 
1150  return divide_();
1151  break;
1152 
1153  case BACKTRACK:
1154 
1155  return backtrack_();
1156  break;
1157 
1158  case SIMPLE_BACKTRACK:
1159 
1160  return simpleBacktrack_();
1161  break;
1162 
1163  case BANK_ROSE:
1164 
1165  return bankRose_();
1166  break;
1167 
1168  case DESCENT:
1169 
1170  return descent_();
1171  break;
1172 
1173  default:
1174 
1175  return fullNewton_();
1176  break;
1177  }
1178 
1179  // If the code gets to this point in the function there has been an
1180  // error...
1181  return false;
1182 }
1183 
1184 //-----------------------------------------------------------------------------
1185 // Function : DampedNewton::divide_()
1186 // Purpose : Eric's "Divide and Conquer" method. Subsequently halves
1187 // the steplength until there is improvement in the RHS or
1188 // the steplength becomes smaller than Util::MachineDependentParams::MachineEpsilon().
1189 // Special Notes : Does not verify that the search direction is a descent
1190 // direction.
1191 // Scope : private
1192 // Creator : Tamara G. Kolda, SNL, Compuational Sciences and
1193 // Mathematics Research Department
1194 // Creation Date : 06/29/01
1195 //-----------------------------------------------------------------------------
1197 {
1198  static const char *trace = "DampedNewton::divide__";
1199 
1200  // Want to get reduction in the norm, so we first copy the norm from
1201  // the previous iterate
1202  const double oldNormRHS = normRHS_;
1203 
1204  // The upper bound on the backtracking (damping) is determined by
1205  // the applied constraints.
1206  const double fullStep = constraintFactor_;
1207 
1208  // Starting value
1209  stepLength_ = fullStep;
1210 
1211  // Update the solution.
1212  updateX_();
1213 
1214  // Evaluate the new residual and take its norm:
1215  rhs_();
1216 if (DEBUG_NONLINEAR && debugTimeFlag_ && isActive(Diag::NONLINEAR_PARAMETERS) )
1217  {
1218  Xyce::dout() << "\n\tSearch Step: " << searchStep_ << ", Step Size: " << stepLength_ << std::endl
1219  << "\toldNormRHS: " << oldNormRHS << ", normRHS: " << normRHS_ << std::endl;
1220  }
1221 
1222  // Linesearch...
1223  bool searchDone = (normRHS_ < oldNormRHS);
1224  while (!searchDone)
1225  {
1226  // Cut the step length
1227  stepLength_ *= 0.5;
1228 
1229  // If the step length gets too small, try full step and finish.
1230  if (stepLength_ < Util::MachineDependentParams::MachineEpsilon())
1231  {
1232  if (DEBUG_NONLINEAR && debugTimeFlag_ && isActive(Diag::NONLINEAR_PARAMETERS) )
1233  {
1234  Xyce::Report::UserWarning0() << "\tStep size too small: " << stepLength_ << "\n\tTaking a full step.\n";
1235  }
1236 
1237  stepLength_ = fullStep;
1238  searchDone = true;
1239  }
1240 
1241  updateX_();
1242 
1243  // Evaluate the new RHS vector and take norm:
1244  rhs_();
1245 
1246  searchStep_++;
1247 
1248  // Check to see if we're done:
1249  searchDone = ((normRHS_ < oldNormRHS) || (searchDone) ||
1251 
1252  if (DEBUG_NONLINEAR && debugTimeFlag_ && isActive(Diag::NONLINEAR_PARAMETERS) )
1253  {
1254  Xyce::dout() << "\n\tSearch Step: " << searchStep_ << ", Step Size: " << stepLength_ << std::endl
1255  << "\toldNormRHS: " << oldNormRHS << ", normRHS: " << normRHS_ << std::endl;
1256  }
1257  }
1258 
1259  return (normRHS_ < oldNormRHS);
1260 }
1261 
1262 //-----------------------------------------------------------------------------
1263 // Function : DampedNewton::backtrack_
1264 // Purpose : Does a backtracking line search along the current search
1265 // direction in the hopes of satisfying the Wolfe conditions
1266 // for f(x) = 0.5 F(x)'F(x) = normrhs^2.
1267 // Special Notes :
1268 // Scope : private
1269 // Creator : Tamara G. Kolda, SNL, Compuational Sciences and
1270 // Mathematics Research Department
1271 // Creation Date : 07/02/01
1272 //-----------------------------------------------------------------------------
1274 {
1275  bool issuffdec;
1276 
1277  // Local references
1278  Linear::Vector& g(*gradVectorPtr_); // Gradient
1279  Linear::Vector& s(*searchDirectionPtr_); // Search Direction
1280 
1281  // Compute the gradient, i.e., fill in g
1282  gradient_();
1283 
1284  // Evaluate <s,g>
1285  double sdotg = s.dotProduct(g);
1286 
1287  double& normrhs(normRHS_); // Norm of RHS
1288  const double f = 0.5 * normrhs * normrhs; // f(x) = 0.5 F(x)'F(X)
1289 
1290  // If s is a descent direction, then do the line search
1291  if (sdotg < 0)
1292  {
1293  issuffdec = simpleBt_(sdotg, f);
1294  }
1295 
1296  // If s is not a descent direction or we cannot find descent along s, switch
1297  // to the gradient. We must recompute the maximum allowable step with the new
1298  // search direction.
1299  if (((sdotg >= 0) || (!issuffdec)) &&
1301  {
1302  Xyce::lout() << "Switching to Cauchy!" << std::endl;
1303  s = g;
1304  s.scale(-1.0 / normrhs);
1305  sdotg = s.dotProduct(g);
1306  double& maxstep(constraintFactor_);
1307  maxstep = constrain_();
1308  issuffdec = simpleBt_(sdotg, f);
1309  }
1310 
1311  if (!issuffdec)
1312  {
1313  double& step(stepLength_);
1314  step = 0.0;
1315  updateX_();
1316  rhs_();
1317 
1318  Xyce::lout() << "Linesearch failed!" << std::endl;
1319  }
1320 
1321  return issuffdec;
1322 }
1323 
1324 //-----------------------------------------------------------------------------
1325 // Function : DampedNewton::simpleBt_
1326 // Purpose : Does a backtracking line search along the current sear
1327 // Special Notes :
1328 // Scope : private
1329 // Creator : Tamara G. Kolda, SNL, Compuational Sciences and
1330 // Mathematics Research Department
1331 // Creation Date : 07/02/01
1332 //-----------------------------------------------------------------------------
1333 bool DampedNewton::simpleBt_(double gsinit, double finit)
1334 {
1335  // Local references
1336  double& normrhs(normRHS_); // Norm of RHS
1337  double& step(stepLength_); // Step length
1338  double& maxstep(constraintFactor_); // Maximum step length
1339  unsigned int& nstep(searchStep_); // Number of backtracking steps
1340 
1341  // Local values
1342  double f = 0.5 * normrhs * normrhs; // Function value
1343  const double alpha = 1.0e-6; // Suff dec cond parameter
1344 
1345  Xyce::dout().setf(std::ios::scientific);
1346  Xyce::dout().precision(10);
1347 
1348  Xyce::dout() << "\nIteration: " << 0
1349  << " Step: " << 0
1350  << " F(X): " << finit
1351  << " gsinit: " << gsinit
1352  << " alpha * gsinit: " << alpha * gsinit
1353  << std::endl;
1354 
1355  // Initialize search
1356  const int nstepmax = 20; // Max number of backtracking steps
1357  const double minstep = Util::MachineDependentParams::MachineEpsilon(); // Min step length
1358  nstep = 0;
1359 
1360  // Loop until we obtain sufficient decrease or violate some condition.
1361  bool issuffdec = false;
1362  while (!issuffdec)
1363  {
1364  // Stop if we've taken too many steps
1365  if (nstep >= nstepmax)
1366  break;
1367 
1368  // If this is the first iteration, set the step to maxstep.
1369  // Otherwise, reduce the step by a factor of one-half.
1370  if (nstep == 0)
1371  step = maxstep;
1372  else
1373  step *= 0.5;
1374 
1375  // Stop if the step has gotten too small
1376  if (step < minstep)
1377  break;
1378 
1379  // Compute the new X based on the currect step
1380  updateX_();
1381 
1382  // Evaluate the RHS for the new X
1383  rhs_();
1384 
1385  // Compute the new function value
1386  f = 0.5 * normrhs * normrhs;
1387 
1388  // Check the sufficient decrease condition
1389  issuffdec = (f <= (finit + (alpha * step * gsinit)));
1390 
1391  // Increment the step counter
1392  nstep ++;
1393 
1394  Xyce::dout() << "Iteration: " << nstep
1395  << " Step: " << step
1396  << " F(X): " << f
1397  << " Test: " << (finit + (alpha * step * gsinit))
1398  << std::endl;
1399  }
1400 
1401  Xyce::dout().unsetf(std::ios::scientific);
1402 
1403  return issuffdec;
1404 }
1405 
1406 //-----------------------------------------------------------------------------
1407 // Function : DampedNewton::backtrack_()
1408 // Purpose : Backtracking method based on Dennis & Shnabel.
1409 // Special Notes :
1410 // Scope : private
1411 // Creator : Scott A. Hutchinson, SNL, Computational Sciences Department
1412 // Creation Date : 07/28/01
1413 //-----------------------------------------------------------------------------
1415 {
1416  static const char *trace = "DampedNewton::computeStepLength_";
1417 
1418  // Want to get reduction in the norm, so we first copy the norm from
1419  // the previous iterate
1420  const double oldNormRHS = normRHS_;
1421 
1422  // The upper bound on the backtracking (damping) is determined by
1423  // the applied constraints.
1424  const double fullStep = constraintFactor_;
1425 
1426  // Starting value
1427  stepLength_ = fullStep;
1428 
1429  // Update the solution.
1430  updateX_();
1431 
1432  // Evaluate the new residual and take its norm:
1433  rhs_();
1434 
1435  // Linesearch...
1436  double rho, delta, theta, lambda;
1437  const double t = 1.0e-04, thetaMin = 0.1, thetaMax = 0.5;
1438  const double minStep = pow(Util::MachineDependentParams::MachineEpsilon(), 0.33);
1439 
1440  // If we're using the inexact-Newton forcing, we use the forcing value
1441  // (linear-solver convergence tolerance) to set the initial "lambda".
1442  if (nlParams.getForcingFlag())
1443  lambda = 1.0 - nlParams.getForcingTerm();
1444  else
1445  lambda = 1.0;
1446 
1447  rho = normRHS_ / oldNormRHS;
1448 
1449  while ((rho > 1.0 - t * lambda) &&
1451  {
1452  delta = rho * rho - 1.0 + 2.0 * lambda;
1453  if (delta <= 0.0)
1454  theta = thetaMax;
1455  else
1456  {
1457  theta = lambda / delta;
1458 
1459  if (theta > thetaMax)
1460  theta = thetaMax;
1461  else if (theta < thetaMin)
1462  theta = thetaMin;
1463  }
1464 
1465  lambda *= theta;
1466  stepLength_ *= theta;
1467 
1468  // Jump out if the step-size gets too small...
1469  if (stepLength_ < minStep)
1470  {
1471  stepLength_ = minStep;
1473  }
1474 
1475  // Update solution & evaluate the new RHS vector and take norm:
1476  updateX_();
1477  rhs_();
1478 
1479  rho = normRHS_ / oldNormRHS;
1480  searchStep_++;
1481 
1482  if (DEBUG_NONLINEAR && debugTimeFlag_ && isActive(Diag::NONLINEAR_PARAMETERS) )
1483  {
1484  Xyce::dout() << "\n\tSearch Step: " << searchStep_ << ", Step Size: " << stepLength_ << std::endl
1485  << "\toldNormRHS: " << oldNormRHS << ", normRHS: " << normRHS_ << std::endl;
1486  }
1487  }
1488 
1489  return (rho <= 1.0 - t * lambda);
1490 
1491 }
1492 
1493 //-----------------------------------------------------------------------------
1494 // Function : DampedNewton::fullNewton_()
1495 // Purpose :
1496 // Special Notes :
1497 // Scope : private
1498 // Creator : Tamara G. Kolda, SNL, Compuational Sciences and
1499 // Mathematics Research Department
1500 // Creation Date : 06/29/01
1501 //-----------------------------------------------------------------------------
1503 {
1504  // ***** Full Newton method *****
1505  stepLength_ = 1.0;
1506 
1507  updateX_();
1508 
1509  // Evaluate the new residual and take its norm:
1510  rhs_();
1511 
1512  return true;
1513 }
1514 
1515 //-----------------------------------------------------------------------------
1516 // Function : DampedNewton::spiceNewton_()
1517 //
1518 // Purpose : Mimics spice. Assumes you've loaded things so
1519 // that the system you are solving is:
1520 //
1521 // J x_{i+1} = -f + J x_i
1522 //
1523 // Special Notes : This is ONLY used for debugging!
1524 //
1525 // At the moment, this will not get the norm right.
1526 //
1527 // Scope : private
1528 // Creator : Eric R. Keite, SNL, Compuational Sciences
1529 // Creation Date : 12/16/04
1530 //-----------------------------------------------------------------------------
1532 {
1533  // ***** Spice Newton method *****
1534  stepLength_ = 1.0;
1535 
1536  // Create the real dx. Normally, the search vector contains dx, but not
1537  // in the spice-style iteration. The search vector is actually the new x,
1538  // so dx = search-nextSol.
1540  -1.0,
1542 
1543  // copy "dx" into x. "dx" is really the new solution.
1544  // - should really use the "=" operator for this.
1545  (*nextSolVectorPtrPtr_)->putScalar(0.0);
1546  (*nextSolVectorPtrPtr_)->addVec(1.0, *searchDirectionPtr_);
1547 
1548  // now copy the tmp vector back into searchDirection, to set up the real dx.
1549  (searchDirectionPtr_)->putScalar(0.0);
1550  (searchDirectionPtr_)->addVec(1.0, *tmpVectorPtr_);
1551 
1552  // Evaluate the new residual and take its norm:
1553  rhs_();
1554 
1555  return true;
1556 }
1557 
1558 //-----------------------------------------------------------------------------
1559 // Function : DampedNewton::evalModNewton_
1560 // Purpose : This method evaluates the modified Newton status to
1561 // determine if a fresh Jacobian and associated preconditioner
1562 // are required. If we take a step that dramatically degrades
1563 // the NLS convergence, we ensure that we're going to use a
1564 // "fresh" Jacobian and preconditioner for some number of steps
1565 // to get us back to a region of good convergence.
1566 // Special Notes :
1567 // Scope : private
1568 // Creator : Scott A. Hutchinson, SNL, Computational Sciences Department
1569 // Creation Date : 08/17/01
1570 //-----------------------------------------------------------------------------
1572 
1573 {
1574  static const char * trace = "DampedNewton::evalModNewton_";
1575 
1576  const double minConvFactor = 0.01;
1577 
1578  const double etaMax = 1.0;
1579  const double etaMin = 1.0e-12;
1580  const double etaInit = 1.0e-01;
1581  double eta;
1582  double nlResNorm = normRHS_;
1583 
1584  if (modNewtonStep_ <= 2)
1585  {
1586  eta = etaInit;
1587  nlResNormOld = nlResNorm;
1588  }
1589  else
1590  {
1591  eta = resConvRate_;
1592  }
1593 
1594  if (DEBUG_NONLINEAR && debugTimeFlag_ && isActive(Diag::NONLINEAR_PARAMETERS) )
1595  {
1596  Util::Param linRes( "RESIDUAL", 0.0 );
1597  lasSolverPtr_->getInfo( linRes );
1598  Xyce::dout() << "\tnlResNorm: " << nlResNorm << " linRes: " << linRes.getImmutableValue<double>()
1599  << "nlResNormOld: " << nlResNormOld << "calculated eta: " << eta << std::endl;
1600  }
1601 
1602  etaOld = eta;
1603  nlResNormOld = nlResNorm;
1604 
1605  if (DEBUG_NONLINEAR && debugTimeFlag_ && isActive(Diag::NONLINEAR_PARAMETERS) )
1606  Xyce::dout() << "\t\teta:\t" << eta << "\n" << std::endl;
1607 
1608  loadJacobianFlag_ = true;
1609 
1610  if (eta < minConvFactor)
1611  {
1612  loadJacobianFlag_ = false;
1613  }
1614 
1615  if (VERBOSE_NONLINEAR) {
1616  if (loadJacobianFlag_)
1617  Xyce::lout() << " ***** Calculating new Jacobian and preconditioner\n" << std::endl;
1618  else
1619  Xyce::lout() << " ***** Using old Jacobian and preconditioner\n" << std::endl;
1620  }
1621 }
1622 
1623 //-----------------------------------------------------------------------------
1624 // Function : DampedNewton::converged_
1625 // Purpose : This method checks for convergence of the Newton solver.
1626 // Much of this is currently based on the methods in both
1627 // P.N. Brown, A.C. Hindmarsh and L.R. Petzold, "Consistent
1628 // initial condition calculations for differential-algebraic
1629 // systems", SIAM J. Sci. Comput., Vol. 19, No. 5,
1630 // pp. 1495-1512, Sep. 1998 and J.E. Dennis, Jr. and
1631 // R.B. Schnabel, "Numerical Methods for Unconstrained
1632 // Optimization and Nonlinear Equations", Prentice-Hall, 1983.
1633 //
1634 // Special Notes : Returns 0 if not converged, positive if converged, negative
1635 // if not converged but some other error.
1636 //
1637 // Eric Keiter, 9233, 03/27/03: I modified the code so that
1638 // it would use values in the ReturnCodes class as
1639 // the integer values for success/failure, rather than
1640 // hardwired numbers. The defaults of this class are the
1641 // same numbers as the old hardwired ones.
1642 //
1643 // The reason for doing this is to allow the user, or
1644 // calling code to set which circumstances should be
1645 // considered adequate convergence. If
1646 // running a two-level continuation loop, within the transient mode,
1647 // there needed to be a way to easily disable the
1648 // "nearConverged" senario.
1649 //
1650 // Scope : private
1651 // Creator : Scott A. Hutchinson, SNL, Computational Sciences Department
1652 // Creation Date : 01/13/01
1653 //-----------------------------------------------------------------------------
1655 
1656 {
1657  static const char *trace = "DampedNewton::converged_";
1658 
1659  const double rhsTol = Util::MachineDependentParams::MachineEpsilon();
1660  const double convRateMax = 0.5 * Util::MachineDependentParams::DoubleMax();
1661  const double minResReduct = 9.0e-1;
1662  const double stagnationTol = 1.0e-3;
1663 
1665 
1666  // This parameter "takes-out" any damping induced in the size of the norm by
1667  // a line-search or other globalization method.
1668  double updateSize = wtNormDX_ / stepLength_;
1669 
1670  // Devices need to satisfy their own convergence criteria
1672  bool allDevicesConverged_ = loaderPtr_->allDevicesConverged(pdsMgrPtr_->getPDSComm()->comm());
1673  if (!allDevicesConverged_ &&
1675  {
1676  return 0;
1677  }
1678  }
1679 
1680  // This test is for 2-level solves ONLY.
1681  bool innerDevicesConverged_ = loaderPtr_->innerDevicesConverged(pdsMgrPtr_->getPDSComm()->comm());
1682  if (!innerDevicesConverged_ )
1683  {
1684  return 0;
1685  }
1686 
1687  // Make sure the residual isn't too small (i.e., there's nothing more to do)
1688  if (maxNormRHS_ <= rhsTol && maxNormRHS_ <= nlParams.getRHSTol())
1689  return retCodes_.normTooSmall; // 1;
1690 
1691  // Check for "normal" convergence
1692  if (maxNormRHS_ <= nlParams.getRHSTol() &&
1693  updateSize <= nlParams.getDeltaXTol())
1694  return retCodes_.normalConvergence; // 2;
1695 
1696  // Transient "Near Converged"...
1697  if (nlStep_ > nlParams.getMaxNewtonStep() &&
1698  mode1 == TRANSIENT)
1699  {
1700  // Check for "near" convergence and let the time integrator handle the
1701  // error analysis and decide on whether or not to accept its step
1702  if ((normRHS_rel_ <= minResReduct) && (resConvRate_ <= 1.0))
1703  return retCodes_.nearConvergence; // 3;
1704  }
1705 
1706  // Check to see if update is really small
1707  if (updateSize <= nlParams.getSmallUpdateTol ())
1708  return retCodes_.smallUpdate; // 4;
1709 
1710  // Next check the number of steps
1712  return retCodes_.tooManySteps; // -1;
1713 
1714  // Make sure that we haven't had too big an update
1715  else if (resConvRate_ > convRateMax)
1716  return retCodes_.updateTooBig; // -2;
1717 
1718  // Check for a stall in the convergence rate - if it is near one for five
1719  // consecutive steps, we've stalled so jump out.
1720  if (mode1 == TRANSIENT && fabs(resConvRate_ - 1.0) <= stagnationTol)
1721  {
1722  if (count == 0 || resConvRate_ < tmpConvRate)
1724 
1725  count++;
1726  if (DEBUG_NONLINEAR && debugTimeFlag_ && isActive(Diag::NONLINEAR_PARAMETERS) )
1727  Xyce::dout() << "\tcount:\t" << count << std::endl
1728  << "\tresConvRate_:\t" << resConvRate_ << "\n" << std::endl;
1729  }
1730  else
1731  count = 0;
1732 
1733  if (mode1 == TRANSIENT && count == 5)
1734  {
1735  count = 0;
1736  if ((normRHS_rel_ < minResReduct) && (tmpConvRate <= 1.0))
1737  {
1738  if (DEBUG_NONLINEAR && debugTimeFlag_ && isActive(Diag::NONLINEAR_PARAMETERS) )
1739  Xyce::dout() << "\ttmpConvRate: " << tmpConvRate << std::endl
1740  << "\tnormRHS_rel_:\t" << normRHS_rel_ << std::endl
1741  << "\tReturning 3\n" << std::endl;
1742 
1743  return retCodes_.nearConvergence; // 3;
1744  }
1745  else
1746  {
1747  if (DEBUG_NONLINEAR && debugTimeFlag_ && isActive(Diag::NONLINEAR_PARAMETERS) )
1748  Xyce::dout() << "\ttmpConvRate: " << tmpConvRate << std::endl
1749  << "\tnormRHS_rel_:\t" << normRHS_rel_ << std::endl
1750  << "\tReturning -3\n" << std::endl;
1751 
1752  return retCodes_.stalled; // -3;
1753  }
1754  }
1755 
1756  return 0;
1757 
1758 }
1759 
1760 //-----------------------------------------------------------------------------
1761 // Function : DampedNewton::constrain_
1762 // Purpose : This method performs constraint backtracking by determining
1763 // a damping factor:
1764 //
1765 // theta = min{1, theta-, theta+, theta_u}
1766 //
1767 // where theta-, theta+ and theta_u are determined according
1768 // the constraint algorithm of J.N. Shadid (SNL internal
1769 // communication).
1770 // Special Notes : See the notes in ConstraintBT.C for how these are
1771 // calculated.
1772 // Scope : private
1773 // Creator : Scott A. Hutchinson, SNL, Computational Sciences Department
1774 // Creation Date : 02/08/01
1775 //-----------------------------------------------------------------------------
1777 {
1778  double minValue;
1779 
1780  // First, update all the thetas...
1783 
1786 
1789 
1790  // Now, determine the minimum value
1791  minValue = std::min(1.0, nlConstraintPtr_->getThetaBoundNeg());
1792  minValue = std::min(minValue, nlConstraintPtr_->getThetaBoundPos());
1793  minValue = std::min(minValue, nlConstraintPtr_->getThetaChange());
1794 
1795  if (DEBUG_NONLINEAR)
1796  Xyce::dout() << "DampedNewton::constrain_: minValue: " << minValue << std::endl;
1797 
1798  if (VERBOSE_NONLINEAR && minValue < 1.0)
1799  Xyce::lout() << " ***** Constraining:\t" << minValue << std::endl;
1800 
1801  return minValue;
1802 }
1803 
1804 //-----------------------------------------------------------------------------
1805 // Function : DampedNewton::setForcing_
1806 // Purpose : This method calculates the forcing term (i.e., linear
1807 // residual tolerance) for iterative solvers based on the
1808 // method of Walker and Pernice (RefXXX)
1809 // Special Notes :
1810 // Scope : private
1811 // Creator : Scott A. Hutchinson, SNL, Computational Sciences Department
1812 // Creation Date : 05/03/01
1813 //-----------------------------------------------------------------------------
1814 void DampedNewton::setForcing_(const double nlResNorm)
1815 {
1816  const double etaExp = 0.5 * (1.0 + sqrt(5.0));
1817  const double etaMax = 0.1;
1818  const double etaMin = 1.0e-12;
1819  const double etaInit = 1.0e-01;
1820  double eta;
1821  double etaSafe;
1822 
1823  if (newtonStep_ == 0 && modNewtonStep_ == 0)
1824  {
1825  eta = etaInit;
1826  nlResNormOld = nlResNorm;
1827  }
1828 
1829  else if (nlResNormOld > Util::MachineDependentParams::DoubleMin())
1830  {
1831  Util::Param linRes( "RESIDUAL", 0.0 );
1832  lasSolverPtr_->getInfo( linRes );
1833  eta = fabs(nlResNorm - linRes.getImmutableValue<double>()) / nlResNormOld;
1834  eta *= eta;
1835 
1836  // First safeguard...
1837  etaSafe = pow(etaOld, etaExp);
1838  if (etaSafe > 0.1)
1839  eta = std::max(eta, etaSafe);
1840 
1841  // Second safeguard...
1842  eta = std::min(etaMax, eta);
1843 
1844  // Not too small...
1845  eta = std::max(etaMin, eta);
1846 
1847  if (DEBUG_NONLINEAR)
1848  Xyce::dout() << "\tnlResNorm: " << nlResNorm
1849  << " linRes: " << linRes.getImmutableValue<double>()
1850  << " nlResNormOld: " << nlResNormOld
1851  << " calculated eta: " << fabs(nlResNorm - linRes.getImmutableValue<double>())/nlResNormOld << std::endl;
1852  }
1853 
1854  else
1855  eta = etaMax;
1856 
1857  etaOld = eta;
1858  nlResNormOld = nlResNorm;
1859 
1860  if (VERBOSE_NONLINEAR)
1861  Xyce::lout() << "\t\teta:\t" << eta << "\n" << std::endl;
1862 
1863  // Set the tolerance
1864  lasSolverPtr_->setTolerance(eta);
1865 
1866  // Set the parameter
1867  nlParams.setForcingTerm(eta);
1868 
1869 }
1870 
1871 //-----------------------------------------------------------------------------
1872 // Function : DampedNewton::bankRose_(nlInfo)
1873 // Purpose : Method of R.E. Bank and D.J. Rose in their paper "Global
1874 // Approximate Newton Methods", 1981, Numerische Mathematik,
1875 // Springer-Verlag. Modifications to their original method
1876 // have been made so that this implementation looks more like
1877 // that implemented in CAzM - W.M. Coughran, Jr., E. Grosse and
1878 // D.J. Rose, "CAzM: A Circuit Analyzer with Macromodeling",
1879 // IEEE Trans. on Electron Devices, Vol. ED-30, No. 9,
1880 // Sep. 1983.
1881 // Special Notes :
1882 // Scope : private
1883 // Creator : Tamara G. Kolda, SNL, Compuational Sciences and
1884 // Mathematics Research Department
1885 // Creation Date : 06/29/01
1886 //-----------------------------------------------------------------------------
1888 {
1889  Xyce::lout() << "THIS IS BROKEN. DO NOT USE THIS METHOD" << std::endl;
1890  return false;
1891 }
1892 
1893 //-----------------------------------------------------------------------------
1894 // Function : DampedNewton::descent_(nlInfo)
1895 // Purpose :
1896 // Special Notes :
1897 // Scope : private
1898 // Creator : Tamara G. Kolda, SNL, Compuational Sciences and
1899 // Mathematics Research Department
1900 // Creation Date : 06/29/01
1901 //-----------------------------------------------------------------------------
1903 {
1904  Xyce::lout() << "THIS IS BROKEN. DO NOT USE THIS METHOD" << std::endl;
1905  return false;
1906 }
1907 
1908 //-----------------------------------------------------------------------------
1909 // Dummy function since homotopy doesn't work with old solver
1910 //-----------------------------------------------------------------------------
1912 {
1913  return true;
1914 }
1915 
1916 //-----------------------------------------------------------------------------
1917 // Dummy function since homotopy doesn't work with old solver
1918 //-----------------------------------------------------------------------------
1920 {
1921  return 0;
1922 }
1923 
1924 //-----------------------------------------------------------------------------
1925 // Dummy function since homotopy doesn't work with old solver
1926 //-----------------------------------------------------------------------------
1928 {
1929  return 0;
1930 }
1931 
1932 } // namespace Nonlinear
1933 } // namespace Xyce
void debugOutput3(Linear::Vector &dxVector, Linear::Vector &xVector)
bool simpleBt_(double gsinit, double finit)
Pure virtual class to augment a linear system.
double getSmallUpdateTol() const
void setForcingTerm(double value)
bool getCurrentParams(NLParams &nlp)
unsigned getMaxNewtonStep() const
void printStepInfo_(std::ostream &os, int step)
AnalysisMode getAnalysisMode() const
double resConvRate_
Convergence Rate.
bool addParameterSet(AnalysisMode mode, NLParams &nlp)
bool setHBOptions(const Util::OptionBlock &OB)
Direction getDirection() const
void updateThetaBoundNeg(const Linear::Vector *oldSoln, const Linear::Vector *solnUpdate)
const Analysis::AnalysisManager & getAnalysisManager() const
LineSearchMethod getSearchMethod() const
void setDebugFlags(int output_step_number, double time)
double getForcingTerm() const
void setDeltaXTol(double Tolerance)
void debugOutput1(Linear::Matrix &jacobian, Linear::Vector &rhs)
void updateThetaChange(const Linear::Vector *oldSoln, const Linear::Vector *solnUpdate)
void setDirection(Direction value)
void printHeader_(std::ostream &os)
Linear::Vector * searchDirectionPtr_
Pointer to direction vector.
int takeFirstSolveStep(NonLinearSolver *nlsTmpPtr=NULL)
bool setTranOptions(const Util::OptionBlock &OB)
DampedNewton(const IO::CmdParse &cp)
double getDeltaXTol() const
int solve(NonLinearSolver *nlsTmpPtr=NULL)
NLStrategy getNLStrategy() const
bool setOptions(const Util::OptionBlock &OB)
ConstraintBT * nlConstraintPtr_
Constraint object pointer.
bool setOptions(const Util::OptionBlock &OB)
bool getEnforceDeviceConvFlag() const
Loader::NonlinearEquationLoader * loaderPtr_
void updateThetaBoundPos(const Linear::Vector *oldSoln, const Linear::Vector *solnUpdate)
bool initializeAll(Linear::System *lasSysPtr, const NLParams &nlParams)
unsigned getMaxSearchStep() const
void printFooter_(std::ostream &os)