Xyce  6.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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-2014 Sandia Corporation
10 //
11 // This program is free software: you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation, either version 3 of the License, or
14 // (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 //-----------------------------------------------------------------------------
24 
25 //-----------------------------------------------------------------------------
26 // Filename : $RCSfile: N_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.48.2.1 $
35 // Revision Date : $Date: 2014/08/28 21:00:43 $
36 // Current Owner : $Author: dgbaur $
37 //-----------------------------------------------------------------------------
38 #include <Xyce_config.h>
39 
40 #include <N_ANP_AnalysisBase.h>
41 
42 #include <N_ANP_AnalysisManager.h>
43 #include <N_ANP_SweepParam.h>
44 #include <N_ERH_Message.h>
45 #include <N_TIA_StepErrorControl.h>
46 #include <N_TIA_TIAParams.h>
47 #include <N_UTL_OptionBlock.h>
48 #include <N_LOA_NonlinearEquationLoader.h>
49 
50 namespace Xyce {
51 namespace Analysis {
52 
54  : successfulStepsTaken_(0),
55  successStepsThisParameter_(0),
56  failedStepsAttempted_(0),
57  jacobiansEvaluated_(0),
58  iterationMatrixFactorizations_(0),
59  linearSolves_(0),
60  failedLinearSolves_(0),
61  linearIters_(0),
62  residualEvaluations_(0),
63  nonlinearConvergenceFailures_(0),
64  linearSolutionTime_(0.0),
65  residualLoadTime_(0.0),
66  jacobianLoadTime_(0.0)
67 {}
68 
69 StatCounts &
71  const StatCounts & stats)
72 {
80  linearIters_ += stats.linearIters_;
86 
87  return *this;
88 }
89 
90 
91 Util::JSON &operator<<(Util::JSON &json, const StatCounts &s)
92 {
93  json << Util::JSON::open
94  << Util::nameValuePair("successfulStepsTaken", s.successfulStepsTaken_) << Util::JSON::sep
95  << Util::nameValuePair("failedStepsAttempted", s.failedStepsAttempted_) << Util::JSON::sep
96  << Util::nameValuePair("jacobiansEvaluated", s.jacobiansEvaluated_) << Util::JSON::sep
97  << Util::nameValuePair("iterationMatrixFactorizations", s.iterationMatrixFactorizations_) << Util::JSON::sep
98  << Util::nameValuePair("linearSolves", s.linearSolves_) << Util::JSON::sep
99  << Util::nameValuePair("failedLinearSolves", s.failedLinearSolves_) << Util::JSON::sep
100  << Util::nameValuePair("linearIters", s.linearIters_) << Util::JSON::sep
101  << Util::nameValuePair("residualEvaluations", s.residualEvaluations_) << Util::JSON::sep
102  << Util::nameValuePair("nonlinearConvergenceFailures", s.nonlinearConvergenceFailures_) << Util::JSON::sep
103  << Util::nameValuePair("residualLoadTime", s.residualLoadTime_) << Util::JSON::sep
104  << Util::nameValuePair("jacobianLoadTime", s.jacobianLoadTime_) << Util::JSON::sep
105  << Util::nameValuePair("linearSolutionTime", s.linearSolutionTime_)
106  << Util::JSON::close;
107 
108  return json;
109 }
110 
111 //-----------------------------------------------------------------------------
112 // Function : AnalysisBase::AnalysisBase
113 // Purpose : Constructor
114 // Special Notes :
115 // Scope : public
116 // Creator : Todd S. Coffey, SNL.
117 // Creation Date : 01/29/08
118 //-----------------------------------------------------------------------------
120  : analysisManager_(analysis_manager),
121  linearSystem_(*analysis_manager.getLinearSystem()),
122  loader_(analysis_manager.getLoader()),
123  nonlinearEquationLoader_(*analysis_manager.getNonlinearEquationLoader()),
124  nonlinearSolverManager_(*analysis_manager.getNonlinearSolverManager()),
125  outputManagerAdapter_(analysis_manager.getOutputManagerAdapter()),
126  stepErrorControl_(analysis_manager.getStepErrorControl()),
127  workingIntgMethod_(analysis_manager.getWorkingIntgMethod()),
128  tiaParams_(analysis_manager.getTIAParams()),
129  beginningIntegration(true),
130  integrationMethod_(TIAMethod_NONE),
131  stepNumber(0),
132  tranStepNumber(0),
133  doubleDCOPFlag_(false),
134  doubleDCOPStep_(0),
135  sensFlag_(false),
136  inputOPFlag_(false),
137  saveStatCountsVector_(),
138  stats_()
139 {}
140 
141 //-----------------------------------------------------------------------------
142 // Function : AnalysisBase::~AnalysisBase()
143 // Purpose : destructor
144 // Special Notes :
145 // Scope :
146 // Creator : Todd S. Coffey, SNL.
147 // Creation Date : 01/29/08
148 //-----------------------------------------------------------------------------
150 {}
151 
152 //-----------------------------------------------------------------------------
153 // Function : AnalysisBase::resetForStepAnalysis()
154 // Purpose : When doing a .STEP sweep, some data must be reset to its
155 // initial state.
156 // Special Notes :
157 // Scope : public
158 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
159 // Creation Date : 8/26/04
160 //-----------------------------------------------------------------------------
162 {
164  stepNumber = 0;
165  beginningIntegration = true;
166 
167  return true;
168 }
169 
170 
171 
172 //-----------------------------------------------------------------------------
173 // Function : AnalysisBase::resetAll
174 // Purpose :
175 // Special Notes :
176 // Scope : public
177 // Creator : Eric R. Keiter
178 // Creation Date : 12/16/10
179 //-----------------------------------------------------------------------------
181 {
182  stepNumber = 0;
183  tranStepNumber = 0;
184 
185  stats_ = StatCounts();
186 }
187 
188 //-----------------------------------------------------------------------------
189 // Function : AnalysisBase::saveLoopInfo
190 // Purpose :
191 // Special Notes :
192 // Scope : public
193 // Creator : Eric R. Keiter
194 // Creation Date : 12/16/10
195 //-----------------------------------------------------------------------------
197 {
198  if (saveStatCountsVector_.empty()) // push back empty stats as sentinel
199  saveStatCountsVector_.push_back(StatCounts());
200 
201  saveStatCountsVector_.push_back(stats_);
202 
203  return saveStatCountsVector_.size() - 1;
204 }
205 
208  const StatCounts & s0,
209  const StatCounts & s1)
210 {
211  StatCounts s;
212 
219 
220  if (s0.linearIters_ > s1.linearIters_)
222 
228 
229  return s;
230 }
231 
232 //-----------------------------------------------------------------------------
233 // Function : AnalysisBase::printLoopInfo
234 // Purpose : Prints out time loop information.
235 // Special Notes : Prints stats from save point start to save point finish.
236 // Special case 0,0 is entire run to this point
237 // Scope : public
238 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
239 // Creation Date : 6/26/00
240 //-----------------------------------------------------------------------------
241 bool AnalysisBase::printLoopInfo(int t1, int t2)
242 {
243  bool bsuccess = true;
244 
245  if (t1 == 0 && t2 == 0)
246  {
247  t2 = saveLoopInfo();
248  }
249 
250  lout() << "\tNumber Successful Steps Taken:\t\t" << saveStatCountsVector_[t2].successfulStepsTaken_ - saveStatCountsVector_[t1].successfulStepsTaken_ << std::endl
251  << "\tNumber Failed Steps Attempted:\t\t" << saveStatCountsVector_[t2].failedStepsAttempted_ - saveStatCountsVector_[t1].failedStepsAttempted_ << std::endl
252  << "\tNumber Jacobians Evaluated:\t\t" << saveStatCountsVector_[t2].jacobiansEvaluated_ - saveStatCountsVector_[t1].jacobiansEvaluated_ << std::endl
253  << "\tNumber Iteration Matrix Factorizations:\t" << saveStatCountsVector_[t2].iterationMatrixFactorizations_ - saveStatCountsVector_[t1].iterationMatrixFactorizations_ << std::endl
254  << "\tNumber Linear Solves:\t\t\t" << saveStatCountsVector_[t2].linearSolves_ - saveStatCountsVector_[t1].linearSolves_ << std::endl
255  << "\tNumber Failed Linear Solves:\t\t" << saveStatCountsVector_[t2].failedLinearSolves_ - saveStatCountsVector_[t1].failedLinearSolves_ << std::endl;
256 
257  if (saveStatCountsVector_[t2].linearIters_ > saveStatCountsVector_[t1].linearIters_)
258  {
259  lout() << "\tNumber Linear Solver Iterations:\t" << saveStatCountsVector_[t2].linearIters_ - saveStatCountsVector_[t1].linearIters_ << std::endl;
260  }
261  lout() << "\tNumber Residual Evaluations:\t\t" << saveStatCountsVector_[t2].residualEvaluations_ - saveStatCountsVector_[t1].residualEvaluations_ << std::endl
262  << "\tNumber Nonlinear Convergence Failures:\t" << saveStatCountsVector_[t2].nonlinearConvergenceFailures_ - saveStatCountsVector_[t1].nonlinearConvergenceFailures_ << std::endl
263  << "\tTotal Residual Load Time:\t\t" << saveStatCountsVector_[t2].residualLoadTime_ - saveStatCountsVector_[t1].residualLoadTime_ << " seconds" << std::endl
264  << "\tTotal Jacobian Load Time:\t\t" << saveStatCountsVector_[t2].jacobianLoadTime_ - saveStatCountsVector_[t1].jacobianLoadTime_ << " seconds" << std::endl
265  << "\tTotal Linear Solution Time:\t\t" << saveStatCountsVector_[t2].linearSolutionTime_ - saveStatCountsVector_[t1].linearSolutionTime_ << " seconds" << std::endl << std::endl;
266 
267  return bsuccess;
268 }
269 
270 
272 {
274  {
276  }
277 
287 }
288 
289 
290 //-----------------------------------------------------------------------------
291 // Function : AnalysisBase::firstDoubleDCOPStep_
292 // Purpose : If the current step is the first step of
293 // a "doubleDCOP", then return "true".
294 //
295 // Explanation:
296 //
297 // If there are PDE semiconductor devices as part of this problem,
298 // there may need to be a "double-pass"
299 //
300 // first pass = nonlinear poisson solution
301 // second pass = drift diffusion solution
302 //
303 // Special Notes : Only PDE problems can ever return true.
304 // Scope :
305 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
306 // Creation Date : 11/21/04
307 //-----------------------------------------------------------------------------
309 {
311 }
312 
313 
314 //-----------------------------------------------------------------------------
315 // Function : setupSweepLoop
316 // Purpose : Processes sweep parameters.
317 // Special Notes : Used for DC and STEP analysis classes.
318 // Scope : public
319 // Creator : Eric R. Keiter, SNL.
320 // Creation Date : 08/21/04
321 //-----------------------------------------------------------------------------
322 int setupSweepLoop(N_LOA_Loader &loader, int debug_level, std::vector<SweepParam>::iterator begin, std::vector<SweepParam>::iterator end)
323 {
324  // loop over the param containers, and check that all the params exist.
325  // (the device package will complain if it can't find the param)
326  for (std::vector<SweepParam>::iterator it = begin; it != end; ++it)
327  {
328  SweepParam &sweep_param = (*it);
329 
330  loader.getParamAndReduce(sweep_param.name);
331  }
332 
333 #ifdef Xyce_DEBUG_ANALYSIS
334  if (debug_level > 0)
335  {
336  Xyce::dout() << std::endl << std::endl
337  << Xyce::subsection_divider << std::endl
338  << "AnalysisManager::setupSweepLoop" << std::endl;
339  }
340 #endif
341 
342  double pinterval = 1.0;
343  double pcount = 0.0, pstart, pstop, pstep;
344 
345  // loop over the param containers:
346  for (std::vector<SweepParam>::iterator it = begin; it != end; ++it)
347  {
348  SweepParam &sweep_param = (*it);
349 
350 #ifdef Xyce_DEBUG_ANALYSIS
351  if (debug_level > 0)
352  {
353  Xyce::dout() << "name = " << sweep_param.name << std::endl;
354  }
355 #endif
356  // set interval:
357  sweep_param.interval = static_cast<int> (pinterval);
358 
359  // This stuff should probably be moved up into the SweepParam class.
360 
361  // obtain next pinterval:
362  if (sweep_param.type=="LIN")
363  {
364  pstart = sweep_param.startVal;
365  pstop = sweep_param.stopVal;
366  pstep = sweep_param.stepVal;
367  // ----------
368  // pcount = floor(((pstop - pstart)/pstep) + 1.0);
369  // The computation of "pcount" above is notoriously prone to roundoff
370  // error, especially if the "floor" function is an in-line function
371  // and is subject to high levels of optimization on x86 processors.
372  // The symptom is that the last step of a DC sweep (or other sweep)
373  // gets lost for very specific combinations of start/stop/step.
374  // The next few lines are an attempt to mitigate this roundoff issue,
375  // which was present in Xyce for years, and was inherited from SPICE3F5,
376  // from which the above expression was taken verbatim.
377 
378  // Compute the number of steps of size pstep between pstart and pstop
379  pcount = floor(((pstop - pstart)/pstep));
380  // Here we're checking that adding one more step doesn't pass pstop
381  // by more than machine precision. If we're within machine precision
382  // of pstop by taking one more step, that must mean we undercounted
383  // due to roundoff in the division --- if we hadn't undercounted, we'd
384  // exceed pstop by (nearly) a full pstep.
385  if ( fabs(pstop-(pstart+(pcount+1.0)*pstep)) < 2.0*Util::MachineDependentParams::MachinePrecision())
386  {
387  pcount += 1.0;
388  }
389 
390  // Pcount is now the exact number of steps of size pstep between pstart
391  // and pstop, with roundoff handled mostly cleanly.
392 
393  // finally, because our actual loop does a loop from zero to maxStep-1,
394  // we have to pad maxStep (as is done in the original pcount expression
395  // above) to get the full range.
396  pcount += 1.0;
397 
398  // done this way, we should no longer miss final steps of DC sweeps.
399  // Fixed 31 Jul 2012. This was bug 695 in Bugzilla, and had plagued
400  // us since Xyce was first ported to Linux with GCC.
401  // ----------
402 
403  sweep_param.maxStep = static_cast<int>(pcount);
404 #ifdef Xyce_DEBUG_ANALYSIS
405  if (debug_level > 0)
406  {
407  Xyce::dout() << "pstart = " << pstart << std::endl;
408  Xyce::dout() << "pstop = " << pstop << std::endl;
409  Xyce::dout() << "pstep = " << pstep << std::endl;
410  Xyce::dout() << "pstop-pstart/pstep = " << ((pstop - pstart)/pstep) << std::endl;
411  Xyce::dout() << "floor ()= " << floor(((pstop - pstart)/pstep)+1.0) << std::endl;
412  Xyce::dout() << "pcount = " << pcount << std::endl;
413  Xyce::dout() << "maxStep = " << sweep_param.maxStep << std::endl;
414  }
415 #endif
416  }
417  else if(sweep_param.type=="DEC")
418  {
419  double numSteps = static_cast<double>(sweep_param.numSteps);
420  // stepMult could also be calculated as pow(10,(1/numSteps))
421  double stepMult = exp(log(10.0)/numSteps);
422  sweep_param.stepMult = stepMult;
423 
424  pstart = sweep_param.startVal;
425  pstop = sweep_param.stopVal;
426  pcount = floor(fabs(log10(pstart) - log10(pstop)) * numSteps + 1);
427  sweep_param.maxStep = static_cast<int>(pcount);
428  }
429  else if(sweep_param.type=="OCT")
430  {
431  double numSteps = static_cast<double>(sweep_param.numSteps);
432  // stepMult could also be calculated as pow(2,1/(numSteps))
433  double stepMult = exp(log(2.0)/numSteps);
434 
435  // changed to remove dependence on "log2" function, which apparently
436  // doesn't exist in the math libraries of FreeBSD or the mingw
437  // cross-compilation suite. Log_2(x)=log_e(x)/log_e(2.0)
438  double ln2=log(2.0);
439 
440  sweep_param.stepMult = stepMult;
441  pstart = sweep_param.startVal;
442  pstop = sweep_param.stopVal;
443  pcount = floor(fabs(log(pstart) - log(pstop))/ln2 * numSteps + 1);
444  sweep_param.maxStep = static_cast<int>(pcount);
445  }
446  else if(sweep_param.type=="LIST")
447  {
448  pcount = sweep_param.valList.size();
449  sweep_param.maxStep = sweep_param.valList.size();
450  }
451  else
452  {
453  Report::UserError0() << " Unsupported STEP type";
454  }
455  pinterval *= pcount;
456 
457 #ifdef Xyce_DEBUG_ANALYSIS
458  if (debug_level > 0)
459  {
460  Xyce::dout() << "parameter = " << sweep_param.name << std::endl;
461  Xyce::dout() << "pcount = " << pcount << std::endl;
462  Xyce::dout() << "pinterval = " << pinterval << std::endl;
463  }
464 #endif
465  }
466 
467  // At this point, pinterval equals the total number of steps
468  // for the step loop.
469  return static_cast<int>(pinterval);
470 }
471 
472 //-----------------------------------------------------------------------------
473 // Function : updateSweepParams
474 // Purpose : Update parameters either for DC or STEP sweeps
475 // Special Notes :
476 // Scope : public
477 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
478 // Creation Date : 8/26/04
479 //-----------------------------------------------------------------------------
480 bool updateSweepParams(N_LOA_Loader &loader, AnalysisManager &analysis_manager, int step_count, std::vector<SweepParam>::iterator begin, std::vector<SweepParam>::iterator end)
481 {
482  bool resetFlag = false;
483 
484  // set parameter(s)
485  for (std::vector<SweepParam>::iterator it = begin; it != end; ++it)
486  {
487  (*it).updateCurrentVal(step_count);
488  resetFlag = resetFlag || (*it).getSweepResetFlag();
489  loader.setParam ((*it).name, (*it).currentVal);
490  }
491 
492  // Tell the manager if any of our sweeps are being reset in this loop iteration.
493  analysis_manager.setSweepSourceResetFlag(resetFlag);
494 
495  return true;
496 }
497 
498 } // namespace Analysis
499 } // namespace Xyce
500