Xyce  6.1
N_ANP_AnalysisBase.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_ANP_AnalysisBase.C,v $
27 // Purpose : Base class analysis functions.
28 // Special Notes :
29 // Creator : Richard Schiek, SNL, Electrical and Microsystem Modeling
30 // Creation Date : 01/24/08
31 //
32 // Revision Information:
33 // ---------------------
34 // Revision Number: $Revision: 1.77.2.1 $
35 // Revision Date : $Date: 2015/04/02 18:20:07 $
36 // Current Owner : $Author: tvrusso $
37 //-----------------------------------------------------------------------------
38 #include <Xyce_config.h>
39 
40 #include <N_ANP_AnalysisBase.h>
41 #include <N_ANP_AnalysisManager.h>
42 #include <N_ANP_SweepParam.h>
43 #include <N_ERH_Message.h>
44 #include <N_LOA_Loader.h>
46 #include <N_NLS_Manager.h>
47 #include <N_PDS_Comm.h>
49 #include <N_TIA_StepErrorControl.h>
50 #include <N_TIA_TIAParams.h>
51 #include <N_UTL_FeatureTest.h>
52 #include <N_UTL_MachDepParams.h>
53 #include <N_UTL_OptionBlock.h>
54 
55 namespace Xyce {
56 namespace Analysis {
57 
59  : successfulStepsTaken_(0),
60  successStepsThisParameter_(0),
61  failedStepsAttempted_(0),
62  jacobiansEvaluated_(0),
63  iterationMatrixFactorizations_(0),
64  linearSolves_(0),
65  failedLinearSolves_(0),
66  linearIters_(0),
67  residualEvaluations_(0),
68  nonlinearConvergenceFailures_(0),
69  linearSolutionTime_(0.0),
70  residualLoadTime_(0.0),
71  jacobianLoadTime_(0.0)
72 {}
73 
74 StatCounts &
76  const StatCounts & stats)
77 {
85  linearIters_ += stats.linearIters_;
91 
92  return *this;
93 }
94 
95 
96 Util::JSON &operator<<(Util::JSON &json, const StatCounts &s)
97 {
98  json << Util::JSON::open
99  << Util::nameValuePair("successfulStepsTaken", s.successfulStepsTaken_) << Util::JSON::sep
100  << Util::nameValuePair("failedStepsAttempted", s.failedStepsAttempted_) << Util::JSON::sep
101  << Util::nameValuePair("jacobiansEvaluated", s.jacobiansEvaluated_) << Util::JSON::sep
102  << Util::nameValuePair("iterationMatrixFactorizations", s.iterationMatrixFactorizations_) << Util::JSON::sep
103  << Util::nameValuePair("linearSolves", s.linearSolves_) << Util::JSON::sep
104  << Util::nameValuePair("failedLinearSolves", s.failedLinearSolves_) << Util::JSON::sep
105  << Util::nameValuePair("linearIters", s.linearIters_) << Util::JSON::sep
106  << Util::nameValuePair("residualEvaluations", s.residualEvaluations_) << Util::JSON::sep
107  << Util::nameValuePair("nonlinearConvergenceFailures", s.nonlinearConvergenceFailures_) << Util::JSON::sep
108  << Util::nameValuePair("residualLoadTime", s.residualLoadTime_) << Util::JSON::sep
109  << Util::nameValuePair("jacobianLoadTime", s.jacobianLoadTime_) << Util::JSON::sep
110  << Util::nameValuePair("linearSolutionTime", s.linearSolutionTime_)
111  << Util::JSON::close;
112 
113  return json;
114 }
115 
116 //-----------------------------------------------------------------------------
117 // Function : AnalysisBase::AnalysisBase
118 // Purpose : Constructor
119 // Special Notes :
120 // Scope : public
121 // Creator : Todd S. Coffey, SNL.
122 // Creation Date : 01/29/08
123 //-----------------------------------------------------------------------------
124 AnalysisBase::AnalysisBase(AnalysisManager &analysis_manager, const char *name )
125  : name_(name),
126  beginningIntegration(true),
127  baseIntegrationMethod_(TimeIntg::NoTimeIntegration::type),
128  stepNumber(0),
129  tranStepNumber(0),
130  NOOP_(false),
131  doubleDCOPFlag_(false),
132  doubleDCOPStep_(0),
133  firstDCOPStep_(0),
134  lastDCOPStep_(1),
135  inputOPFlag_(false),
136  saveStatCountsVector_(),
137  stats_()
138 {}
139 
140 //-----------------------------------------------------------------------------
141 // Function : AnalysisBase::~AnalysisBase()
142 // Purpose : destructor
143 // Special Notes :
144 // Scope :
145 // Creator : Todd S. Coffey, SNL.
146 // Creation Date : 01/29/08
147 //-----------------------------------------------------------------------------
149 {}
150 
151 bool
153 {
154  Stats::StatTop _analysis(name_);
155 
156  return doRun();
157 }
158 
159 bool
161 {
162  Stats::StatTop _analysis(name_);
163 
164  return doInit();
165 }
166 
167 
168 bool
170 {
171  Stats::StatTop _analysis(name_);
172 
173  return doLoopProcess();
174 }
175 
176 bool
178 {
179  return doProcessSuccessfulStep();
180 }
181 
182 bool
184 {
185  return doProcessFailedStep();
186 }
187 
188 bool
190 {
191  return doFinish();
192 }
193 
194 
195 bool
197 {
198  return doHandlePredictor();
199 }
200 
201 
202 //-----------------------------------------------------------------------------
203 // Function : AnalysisBase::resetForStepAnalysis()
204 // Purpose : When doing a .STEP sweep, some data must be reset to its
205 // initial state.
206 // Special Notes :
207 // Scope : public
208 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
209 // Creation Date : 8/26/04
210 //-----------------------------------------------------------------------------
212 {
214  stepNumber = 0;
215  beginningIntegration = true;
216 
217  return true;
218 }
219 
220 
221 
222 //-----------------------------------------------------------------------------
223 // Function : AnalysisBase::resetAll
224 // Purpose :
225 // Special Notes :
226 // Scope : public
227 // Creator : Eric R. Keiter
228 // Creation Date : 12/16/10
229 //-----------------------------------------------------------------------------
231 {
232  stepNumber = 0;
233  tranStepNumber = 0;
234 
235  stats_ = StatCounts();
236 }
237 
238 //-----------------------------------------------------------------------------
239 // Function : AnalysisBase::saveLoopInfo
240 // Purpose :
241 // Special Notes :
242 // Scope : public
243 // Creator : Eric R. Keiter
244 // Creation Date : 12/16/10
245 //-----------------------------------------------------------------------------
247 {
248  if (saveStatCountsVector_.empty()) // push back empty stats as sentinel
249  saveStatCountsVector_.push_back(StatCounts());
250 
251  saveStatCountsVector_.push_back(stats_);
252 
253  return saveStatCountsVector_.size() - 1;
254 }
255 
258  const StatCounts & s0,
259  const StatCounts & s1)
260 {
261  StatCounts s;
262 
269 
270  if (s0.linearIters_ > s1.linearIters_)
272 
278 
279  return s;
280 }
281 
282 //-----------------------------------------------------------------------------
283 // Function : AnalysisBase::printLoopInfo
284 // Purpose : Prints out time loop information.
285 // Special Notes : Prints stats from save point start to save point finish.
286 // Special case 0,0 is entire run to this point
287 // Scope : public
288 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
289 // Creation Date : 6/26/00
290 //-----------------------------------------------------------------------------
291 bool AnalysisBase::printLoopInfo(int t1, int t2)
292 {
293  bool bsuccess = true;
294 
295  if (t1 == 0 && t2 == 0)
296  {
297  t2 = saveLoopInfo();
298  }
299 
300  lout() << "\tNumber Successful Steps Taken:\t\t" << saveStatCountsVector_[t2].successfulStepsTaken_ - saveStatCountsVector_[t1].successfulStepsTaken_ << std::endl
301  << "\tNumber Failed Steps Attempted:\t\t" << saveStatCountsVector_[t2].failedStepsAttempted_ - saveStatCountsVector_[t1].failedStepsAttempted_ << std::endl
302  << "\tNumber Jacobians Evaluated:\t\t" << saveStatCountsVector_[t2].jacobiansEvaluated_ - saveStatCountsVector_[t1].jacobiansEvaluated_ << std::endl
303  << "\tNumber Iteration Matrix Factorizations:\t" << saveStatCountsVector_[t2].iterationMatrixFactorizations_ - saveStatCountsVector_[t1].iterationMatrixFactorizations_ << std::endl
304  << "\tNumber Linear Solves:\t\t\t" << saveStatCountsVector_[t2].linearSolves_ - saveStatCountsVector_[t1].linearSolves_ << std::endl
305  << "\tNumber Failed Linear Solves:\t\t" << saveStatCountsVector_[t2].failedLinearSolves_ - saveStatCountsVector_[t1].failedLinearSolves_ << std::endl;
306 
307  if (saveStatCountsVector_[t2].linearIters_ > saveStatCountsVector_[t1].linearIters_)
308  {
309  lout() << "\tNumber Linear Solver Iterations:\t" << saveStatCountsVector_[t2].linearIters_ - saveStatCountsVector_[t1].linearIters_ << std::endl;
310  }
311  lout() << "\tNumber Residual Evaluations:\t\t" << saveStatCountsVector_[t2].residualEvaluations_ - saveStatCountsVector_[t1].residualEvaluations_ << std::endl
312  << "\tNumber Nonlinear Convergence Failures:\t" << saveStatCountsVector_[t2].nonlinearConvergenceFailures_ - saveStatCountsVector_[t1].nonlinearConvergenceFailures_ << std::endl
313  << "\tTotal Residual Load Time:\t\t" << saveStatCountsVector_[t2].residualLoadTime_ - saveStatCountsVector_[t1].residualLoadTime_ << " seconds" << std::endl
314  << "\tTotal Jacobian Load Time:\t\t" << saveStatCountsVector_[t2].jacobianLoadTime_ - saveStatCountsVector_[t1].jacobianLoadTime_ << " seconds" << std::endl
315  << "\tTotal Linear Solution Time:\t\t" << saveStatCountsVector_[t2].linearSolutionTime_ - saveStatCountsVector_[t1].linearSolutionTime_ << " seconds" << std::endl << std::endl;
316 
317  return bsuccess;
318 }
319 
320 
321 
322 //-----------------------------------------------------------------------------
323 // Function : AnalysisBase::firstDoubleDCOPStep
324 // Purpose : If the current step is the first step of
325 // a "doubleDCOP", then return "true".
326 //
327 // Explanation:
328 //
329 // If there are PDE semiconductor devices as part of this problem,
330 // there may need to be a "double-pass"
331 //
332 // first pass = nonlinear poisson solution
333 // second pass = drift diffusion solution
334 //
335 // Special Notes : Only PDE problems can ever return true.
336 // Scope :
337 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
338 // Creation Date : 11/21/04
339 //-----------------------------------------------------------------------------
341 {
343 }
344 
345 
346 //-----------------------------------------------------------------------------
347 // Function : setupSweepLoop
348 // Purpose : Processes sweep parameters.
349 // Special Notes : Used for DC and STEP analysis classes.
350 // Scope : public
351 // Creator : Eric R. Keiter, SNL.
352 // Creation Date : 08/21/04
353 //-----------------------------------------------------------------------------
354 int setupSweepLoop(Loader::Loader &loader, int debug_level, std::vector<SweepParam>::iterator begin, std::vector<SweepParam>::iterator end)
355 {
356  // loop over the param containers, and check that all the params exist.
357  // (the device package will complain if it can't find the param)
358  for (std::vector<SweepParam>::iterator it = begin; it != end; ++it)
359  {
360  SweepParam &sweep_param = (*it);
361 
362  loader.getParamAndReduce(sweep_param.name);
363  }
364 
365  if (DEBUG_ANALYSIS && debug_level > 0)
366  {
367  Xyce::dout() << std::endl << std::endl
368  << Xyce::subsection_divider << std::endl
369  << "AnalysisManager::setupSweepLoop" << std::endl;
370  }
371 
372  double pinterval = 1.0;
373  double pcount = 0.0, pstart, pstop, pstep;
374 
375  // loop over the param containers:
376  for (std::vector<SweepParam>::iterator it = begin; it != end; ++it)
377  {
378  SweepParam &sweep_param = (*it);
379 
380  if (DEBUG_ANALYSIS && debug_level > 0)
381  {
382  Xyce::dout() << "name = " << sweep_param.name << std::endl;
383  }
384 
385  // set interval:
386  sweep_param.interval = static_cast<int> (pinterval);
387 
388  // This stuff should probably be moved up into the SweepParam class.
389  // obtain next pinterval:
390  if (sweep_param.type=="LIN")
391  {
392  pstart = sweep_param.startVal;
393  pstop = sweep_param.stopVal;
394  pstep = sweep_param.stepVal;
395  // ----------
396  // pcount = floor(((pstop - pstart)/pstep) + 1.0);
397  // The computation of "pcount" above is notoriously prone to roundoff
398  // error, especially if the "floor" function is an in-line function
399  // and is subject to high levels of optimization on x86 processors.
400  // The symptom is that the last step of a DC sweep (or other sweep)
401  // gets lost for very specific combinations of start/stop/step.
402  // The next few lines are an attempt to mitigate this roundoff issue,
403  // which was present in Xyce for years, and was inherited from SPICE3F5,
404  // from which the above expression was taken verbatim.
405 
406  // Compute the number of steps of size pstep between pstart and pstop
407  pcount = floor(((pstop - pstart)/pstep));
408  // Here we're checking that adding one more step doesn't pass pstop
409  // by more than machine precision. If we're within machine precision
410  // of pstop by taking one more step, that must mean we undercounted
411  // due to roundoff in the division --- if we hadn't undercounted, we'd
412  // exceed pstop by (nearly) a full pstep.
413  if ( fabs(pstop-(pstart+(pcount+1.0)*pstep)) < 2.0*Util::MachineDependentParams::MachinePrecision())
414  {
415  pcount += 1.0;
416  }
417 
418  // Pcount is now the exact number of steps of size pstep between pstart
419  // and pstop, with roundoff handled mostly cleanly.
420 
421  // finally, because our actual loop does a loop from zero to maxStep-1,
422  // we have to pad maxStep (as is done in the original pcount expression
423  // above) to get the full range.
424  pcount += 1.0;
425 
426  // done this way, we should no longer miss final steps of DC sweeps.
427  // Fixed 31 Jul 2012. This was bug 695 in Bugzilla, and had plagued
428  // us since Xyce was first ported to Linux with GCC.
429  // ----------
430 
431  sweep_param.maxStep = static_cast<int>(pcount);
432 
433  if (DEBUG_ANALYSIS && debug_level > 0)
434  {
435  Xyce::dout() << "pstart = " << pstart << std::endl;
436  Xyce::dout() << "pstop = " << pstop << std::endl;
437  Xyce::dout() << "pstep = " << pstep << std::endl;
438  Xyce::dout() << "pstop-pstart/pstep = " << ((pstop - pstart)/pstep) << std::endl;
439  Xyce::dout() << "floor ()= " << floor(((pstop - pstart)/pstep)+1.0) << std::endl;
440  Xyce::dout() << "pcount = " << pcount << std::endl;
441  Xyce::dout() << "maxStep = " << sweep_param.maxStep << std::endl;
442  }
443  }
444  else if(sweep_param.type=="DEC")
445  {
446  double numSteps = static_cast<double>(sweep_param.numSteps);
447  // stepMult could also be calculated as pow(10,(1/numSteps))
448  double stepMult = exp(log(10.0)/numSteps);
449  sweep_param.stepMult = stepMult;
450 
451  pstart = sweep_param.startVal;
452  pstop = sweep_param.stopVal;
453  pcount = floor(fabs(log10(pstart) - log10(pstop)) * numSteps + 1);
454  sweep_param.maxStep = static_cast<int>(pcount);
455  }
456  else if(sweep_param.type=="OCT")
457  {
458  double numSteps = static_cast<double>(sweep_param.numSteps);
459  // stepMult could also be calculated as pow(2,1/(numSteps))
460  double stepMult = exp(log(2.0)/numSteps);
461 
462  // changed to remove dependence on "log2" function, which apparently
463  // doesn't exist in the math libraries of FreeBSD or the mingw
464  // cross-compilation suite. Log_2(x)=log_e(x)/log_e(2.0)
465  double ln2=log(2.0);
466 
467  sweep_param.stepMult = stepMult;
468  pstart = sweep_param.startVal;
469  pstop = sweep_param.stopVal;
470  pcount = floor(fabs(log(pstart) - log(pstop))/ln2 * numSteps + 1);
471  sweep_param.maxStep = static_cast<int>(pcount);
472  }
473  else if(sweep_param.type=="LIST")
474  {
475  pcount = sweep_param.valList.size();
476  sweep_param.maxStep = sweep_param.valList.size();
477  }
478  else
479  {
480  Report::UserError0() << " Unsupported STEP type";
481  }
482  pinterval *= pcount;
483 
484  if (DEBUG_ANALYSIS && debug_level > 0)
485  {
486  Xyce::dout() << "parameter = " << sweep_param.name << std::endl;
487  Xyce::dout() << "pcount = " << pcount << std::endl;
488  Xyce::dout() << "pinterval = " << pinterval << std::endl;
489  }
490  }
491 
492  // At this point, pinterval equals the total number of steps
493  // for the step loop.
494  return static_cast<int>(pinterval);
495 }
496 
497 //-----------------------------------------------------------------------------
498 // Function : updateSweepParams
499 // Purpose : Update parameters either for DC or STEP sweeps
500 // Special Notes :
501 // Scope : public
502 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
503 // Creation Date : 8/26/04
504 //-----------------------------------------------------------------------------
505 bool updateSweepParams(Loader::Loader &loader, AnalysisManager &analysis_manager, int step_count, std::vector<SweepParam>::iterator begin, std::vector<SweepParam>::iterator end)
506 {
507  bool resetFlag = false;
508 
509  // set parameter(s)
510  for (std::vector<SweepParam>::iterator it = begin; it != end; ++it)
511  {
512  (*it).updateCurrentVal(step_count);
513  resetFlag = resetFlag || (*it).getSweepResetFlag();
514  loader.setParam ((*it).name, (*it).currentVal);
515  if (DEBUG_ANALYSIS)
516  {
517  Xyce::dout() << "Updating parameter " << (*it).name << " to " << (*it).currentVal << std::endl;
518  }
519  }
520 
521  // Tell the manager if any of our sweeps are being reset in this loop iteration.
522  analysis_manager.setSweepSourceResetFlag(resetFlag);
523 
524  return true;
525 }
526 
527 void gatherStepStatistics(StatCounts &stats, Nonlinear::NonLinearSolver &nonlinear_solver, int newton_convergence_status)
528 {
529  if (newton_convergence_status <= 0) {
531  }
532 
533  stats.jacobiansEvaluated_ += nonlinear_solver.getNumJacobianLoads();
534  stats.linearSolves_ += nonlinear_solver.getNumLinearSolves();
535  stats.failedLinearSolves_ += nonlinear_solver.getNumFailedLinearSolves();
536  stats.linearIters_ += nonlinear_solver.getTotalNumLinearIters();
537  stats.residualEvaluations_ += nonlinear_solver.getNumResidualLoads();
539  stats.linearSolutionTime_ += nonlinear_solver.getTotalLinearSolveTime();
540  stats.residualLoadTime_ += nonlinear_solver.getTotalResidualLoadTime();
541  stats.jacobianLoadTime_ += nonlinear_solver.getTotalJacobianLoadTime();
542 }
543 
544 //-----------------------------------------------------------------------------
545 // Function : setTimeIntegratorOptions
546 // Purpose :
547 // Special Notes : These are from '.options timeint'
548 // Scope : public
549 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
550 // Creation Date : 04/18/02
551 //-----------------------------------------------------------------------------
552 bool
554  const Util::Param & param)
555 {
556  if (param.uTag() == "DOUBLEDCOPSTEP")
557  {
558  doubleDCOPStep_ = param.getImmutableValue<int>();
559  }
560  else if (param.uTag() == "FIRSTDCOPSTEP")
561  {
562  firstDCOPStep_ = param.getImmutableValue<int>();
563  if (firstDCOPStep_ < 0)
564  firstDCOPStep_ = 0;
565  if (firstDCOPStep_ > 1)
566  firstDCOPStep_ = 1;
567  }
568  else if (param.uTag() == "LASTDCOPSTEP")
569  {
570  lastDCOPStep_ = param.getImmutableValue<int>();
571  if (lastDCOPStep_ < 0)
572  lastDCOPStep_ = 0;
573  if (lastDCOPStep_ > 1)
574  lastDCOPStep_ = 1;
575  }
576  else
577  {
578  return false;
579  }
580 
581  return true;
582 }
583 
584 } // namespace Analysis
585 } // namespace Xyce
586 
unsigned int successfulStepsTaken_
Number of consecutive successful time-integration steps.
virtual bool doProcessSuccessfulStep()=0
Pure virtual class to augment a linear system.
unsigned int iterationMatrixFactorizations_
bool updateSweepParams(Loader::Loader &loader, int step_count, std::vector< SweepParam >::iterator begin, std::vector< SweepParam >::iterator end, bool overrideOriginal=false)
int doubleDCOPStep_
current step in the DCOP loop.
unsigned int stepNumber
Time-integration step number counter.
void gatherStepStatistics(StatCounts &stats, Nonlinear::NonLinearSolver &nonlinear_solver, int newton_convergence_status)
Util::JSON & operator<<(Util::JSON &json, const StatCounts &s)
virtual bool doHandlePredictor()=0
virtual int getDoubleDCOPStep() const
unsigned int failedStepsAttempted_
Total number of failed time-integration steps.
StatCounts & operator+=(const StatCounts &stats)
bool setDCOPOption(const Util::Param &param)
std::vector< double > valList
virtual unsigned int getTotalNumLinearIters()
virtual bool setParam(std::string &name, double val, bool overrideOriginal=false)=0
virtual bool doProcessFailedStep()=0
virtual bool printLoopInfo(int start, int finish)
StatCounts operator-(const StatCounts &s0, const StatCounts &s1)
virtual double getParamAndReduce(const std::string &name) const =0
virtual bool doLoopProcess()=0
AnalysisBase(AnalysisManager &analysis_manager, const char *name)
unsigned int nonlinearConvergenceFailures_
std::vector< StatCounts > saveStatCountsVector_
int setupSweepLoop(Loader::Loader &loader, std::vector< SweepParam >::iterator begin, std::vector< SweepParam >::iterator end)