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