Xyce  6.1
N_ANP_SweepParam.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_SweepParam.C,v $
27 // Purpose :
28 // Special Notes :
29 // Creator : Eric Keiter
30 // Creation Date : 9/4/04
31 //
32 // Revision Information:
33 // ---------------------
34 // Revision Number: $Revision: 1.25.2.1 $
35 // Revision Date : $Date: 2015/04/02 18:20:07 $
36 // Current Owner : $Author: tvrusso $
37 //-----------------------------------------------------------------------------
38 
39 #include <Xyce_config.h>
40 
41 #include <iostream>
42 
43 #include <N_ANP_SweepParam.h>
44 #include <N_ANP_AnalysisManager.h>
45 #include <N_ERH_ErrorMgr.h>
46 #include <N_LOA_Loader.h>
47 #include <N_UTL_FeatureTest.h>
48 #include <N_UTL_MachDepParams.h>
49 #include <N_UTL_Math.h>
50 #include <N_UTL_Param.h>
51 
52 
53 namespace Xyce {
54 namespace Analysis {
55 
56 //-----------------------------------------------------------------------------
57 // Function : SweepParam::updateCurrentVal
58 //
59 // Purpose : Updates the values of the parameters used in a sweep.
60 //
61 // Special Notes : This is very similar to the "update" function in the
62 // class Device::SweepData. (which no longer exists).
63 //
64 // Scope : public
65 // Creator : Eric R. Keiter,SNL, Computational Sciences
66 // Creation Date : 10/31/2003
67 //-----------------------------------------------------------------------------
68 bool SweepParam::updateCurrentVal (int stepNumberArg)
69 {
70  outerStepNumber = stepNumberArg/interval;
71  int inum = outerStepNumber/maxStep;
72  int localStepNumber = outerStepNumber - inum*maxStep;
73 
74  // We must keep track of whether we're at the first step of our sweep,
75  // because some device manager features need to know that.
76  // It is important that we only set this when localStepNumber first becoms
77  // zero, not every time localStepNumber *is* zero, because an outer loop
78  // might remain at 0 for quite some time.
79 
80  if (localStepNumber == 0 && localStepNumber != lastLocalStepNumber_)
81  {
82  sweepResetFlag_=true;
83  }
84  else
85  {
86  sweepResetFlag_=false;
87  }
88  lastLocalStepNumber_=localStepNumber;
89 
90  if (type == "LIN")
91  {
92  currentVal = startVal + static_cast<double>(localStepNumber)*stepVal;
93  ++count;
94  }
95  else if (type == "DEC" || type == "OCT")
96  {
97  currentVal = startVal*pow(stepMult, static_cast<double>(localStepNumber) );
98  ++count;
99  }
100  else if (type == "LIST")
101  {
102  int size= valList.size();
103  int index = (localStepNumber < size)?localStepNumber:(size-1);
104  currentVal = valList[index];
105  ++count;
106  }
107  else
108  {
109  Report::DevelFatal0().in("SweepParam::updateCurrentVal") << "Unsupported type specified";
110  }
111 
112  if (DEBUG_TIME)
113  Xyce::dout() << std::endl
114  << Xyce::subsection_divider << std::endl
115  << "updateCurrentVal" << std::endl
116  << " name = " << name << std::endl
117  << " stepNumberArg = " << stepNumberArg<< std::endl
118  << " interval = " << interval << std::endl
119  << " outerStepNumber = " << outerStepNumber << std::endl
120  << " localStepNumber = " << localStepNumber << std::endl
121  << " inum = " << inum << std::endl
122  << " sweepResetFlag = " << sweepResetFlag_ << std::endl
123  << " currentVal = " << currentVal << std::endl
124  << Xyce::subsection_divider << std::endl;
125 
126  return true;
127 }
128 
129 //-----------------------------------------------------------------------------
130 // Function : SweepParam::operator<<
131 // Purpose : "<<" operator
132 // Special Notes :
133 // Scope : public
134 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
135 // Creation Date : 7/02/03
136 //-----------------------------------------------------------------------------
137 std::ostream &
138 operator<<(std::ostream & os, const SweepParam & sp)
139 {
140  os << "\tname = " << sp.name
141  << "\tcurrentVal = " << sp.currentVal
142  << std::endl;
143  return os;
144 }
145 
146 
147 
148 //-----------------------------------------------------------------------------
149 // Function : parseSweepParam
150 // Purpose :
151 // Special Notes :
152 // Scope : public
153 // Creator : David G. Baur Raytheon Sandia National Laboratories 1355
154 // Creation Date : Wed Oct 1 09:19:28 2014
155 //-----------------------------------------------------------------------------
156 SweepParam parseSweepParams(Util::ParamList::const_iterator first, Util::ParamList::const_iterator last)
157 {
158  if (DEBUG_ANALYSIS)
159  {
160  Xyce::dout() << std::endl << section_divider << std::endl
161  << "parseSweepParam" << std::endl;
162 
163  for (Util::ParamList::const_iterator it = first, end = last; it != end; ++it)
164  {
165  Xyce::dout() << (*it).uTag() << "\t";
166  if ((*it).uTag() == "PARAM" || (*it).uTag() == "TYPE")
167  {
168  Xyce::dout() << (*it).stringValue();
169  }
170  else
171  {
172  Xyce::dout() << (*it).getImmutableValue<double>();
173  }
174  Xyce::dout() << std::endl;
175  }
176  }
177 
178  SweepParam sweep_param;
179 
180  Util::ParamList::const_iterator it_param = last;
181  for (Util::ParamList::const_iterator it = first, end = last; it != end; ++it)
182  {
183  if ((*it).uTag() == "TYPE")
184  {
185  sweep_param.type = (*it).stringValue();
186  }
187  else if ((*it).uTag() == "PARAM")
188  {
189  it_param = it;
190  sweep_param.name = (*it).stringValue();
191  }
192  }
193 
194  if (it_param != last)
195  {
196  if (sweep_param.type == "LIN") // default
197  {
198  sweep_param.startVal = (*++it_param).getImmutableValue<double>();
199  sweep_param.stopVal = (*++it_param).getImmutableValue<double>();
200  sweep_param.stepVal = (*++it_param).getImmutableValue<double>();
201  }
202  else if (sweep_param.type == "DEC" || sweep_param.type == "OCT")
203  {
204  sweep_param.startVal = (*++it_param).getImmutableValue<double>();
205  sweep_param.stopVal = (*++it_param).getImmutableValue<double>();
206  sweep_param.numSteps = (*++it_param).getImmutableValue<int>();
207  }
208  else if (sweep_param.type == "LIST")
209  {
210  for (Util::ParamList::const_iterator it = ++it_param, end = last; it != end; ++it)
211  {
212  sweep_param.valList.push_back((*it).getImmutableValue<double>());
213  }
214  }
215  else
216  {
217  Report::DevelFatal().in("parseSweepParam") << "Unsupported DC type";
218  }
219  }
220  return sweep_param;
221 
222 }
223 
224 //-----------------------------------------------------------------------------
225 // Function : setupSweepLoop
226 // Purpose : Processes sweep parameters.
227 // Special Notes : Used for DC and STEP analysis classes.
228 // Scope : public
229 // Creator : Eric R. Keiter, SNL.
230 // Creation Date : 08/21/04
231 //-----------------------------------------------------------------------------
232 int setupSweepLoop(Loader::Loader &loader, std::vector<SweepParam>::iterator begin, std::vector<SweepParam>::iterator end)
233 {
234  // loop over the param containers, and check that all the params exist.
235  // (the device package will complain if it can't find the param)
236  for (std::vector<SweepParam>::iterator it = begin; it != end; ++it)
237  {
238  SweepParam &sweep_param = (*it);
239 
240  loader.getParamAndReduce(sweep_param.name);
241  }
242 
243  double pinterval = 1.0;
244  double pcount = 0.0, pstart, pstop, pstep;
245 
246  // loop over the param containers:
247  for (std::vector<SweepParam>::iterator it = begin; it != end; ++it)
248  {
249  SweepParam &sweep_param = (*it);
250 
251  // set interval:
252  sweep_param.interval = static_cast<int> (pinterval);
253 
254  // This stuff should probably be moved up into the SweepParam class.
255  // obtain next pinterval:
256  if (sweep_param.type=="LIN")
257  {
258  pstart = sweep_param.startVal;
259  pstop = sweep_param.stopVal;
260  pstep = sweep_param.stepVal;
261  // ----------
262  // pcount = floor(((pstop - pstart)/pstep) + 1.0);
263  // The computation of "pcount" above is notoriously prone to roundoff
264  // error, especially if the "floor" function is an in-line function
265  // and is subject to high levels of optimization on x86 processors.
266  // The symptom is that the last step of a DC sweep (or other sweep)
267  // gets lost for very specific combinations of start/stop/step.
268  // The next few lines are an attempt to mitigate this roundoff issue,
269  // which was present in Xyce for years, and was inherited from SPICE3F5,
270  // from which the above expression was taken verbatim.
271 
272  // Compute the number of steps of size pstep between pstart and pstop
273  pcount = floor(((pstop - pstart)/pstep));
274  // Here we're checking that adding one more step doesn't pass pstop
275  // by more than machine precision. If we're within machine precision
276  // of pstop by taking one more step, that must mean we undercounted
277  // due to roundoff in the division --- if we hadn't undercounted, we'd
278  // exceed pstop by (nearly) a full pstep.
279  if ( fabs(pstop-(pstart+(pcount+1.0)*pstep)) < 2.0*Util::MachineDependentParams::MachinePrecision())
280  {
281  pcount += 1.0;
282  }
283 
284  // Pcount is now the exact number of steps of size pstep between pstart
285  // and pstop, with roundoff handled mostly cleanly.
286 
287  // finally, because our actual loop does a loop from zero to maxStep-1,
288  // we have to pad maxStep (as is done in the original pcount expression
289  // above) to get the full range.
290  pcount += 1.0;
291 
292  // done this way, we should no longer miss final steps of DC sweeps.
293  // Fixed 31 Jul 2012. This was bug 695 in Bugzilla, and had plagued
294  // us since Xyce was first ported to Linux with GCC.
295  // ----------
296 
297  sweep_param.maxStep = static_cast<int>(pcount);
298  }
299  else if(sweep_param.type=="DEC")
300  {
301  double numSteps = static_cast<double>(sweep_param.numSteps);
302  // stepMult could also be calculated as pow(10,(1/numSteps))
303  double stepMult = exp(log(10.0)/numSteps);
304  sweep_param.stepMult = stepMult;
305 
306  pstart = sweep_param.startVal;
307  pstop = sweep_param.stopVal;
308  pcount = floor(fabs(log10(pstart) - log10(pstop)) * numSteps + 1);
309  sweep_param.maxStep = static_cast<int>(pcount);
310  }
311  else if(sweep_param.type=="OCT")
312  {
313  double numSteps = static_cast<double>(sweep_param.numSteps);
314  // stepMult could also be calculated as pow(2,1/(numSteps))
315  double stepMult = exp(log(2.0)/numSteps);
316 
317  // changed to remove dependence on "log2" function, which apparently
318  // doesn't exist in the math libraries of FreeBSD or the mingw
319  // cross-compilation suite. Log_2(x)=log_e(x)/log_e(2.0)
320  double ln2=log(2.0);
321 
322  sweep_param.stepMult = stepMult;
323  pstart = sweep_param.startVal;
324  pstop = sweep_param.stopVal;
325  pcount = floor(fabs(log(pstart) - log(pstop))/ln2 * numSteps + 1);
326  sweep_param.maxStep = static_cast<int>(pcount);
327  }
328  else if(sweep_param.type=="LIST")
329  {
330  pcount = sweep_param.valList.size();
331  sweep_param.maxStep = sweep_param.valList.size();
332  }
333  else
334  {
335  Report::UserError0() << " Unsupported STEP type";
336  }
337  pinterval *= pcount;
338  }
339 
340  // At this point, pinterval equals the total number of steps
341  // for the step loop.
342  return static_cast<int>(pinterval);
343 }
344 
345 //-----------------------------------------------------------------------------
346 // Function : updateSweepParams
347 // Purpose : Update parameters either for DC or STEP sweeps
348 // Special Notes :
349 // Scope : public
350 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
351 // Creation Date : 8/26/04
352 //-----------------------------------------------------------------------------
353 bool updateSweepParams(Loader::Loader &loader, int step_count, std::vector<SweepParam>::iterator begin, std::vector<SweepParam>::iterator end, bool overrideOriginal)
354 {
355  bool reset = false;
356 
357  // set parameter(s)
358  for (std::vector<SweepParam>::iterator it = begin; it != end; ++it)
359  {
360  (*it).updateCurrentVal(step_count);
361  reset = reset || (*it).getSweepResetFlag();
362  loader.setParam((*it).name, (*it).currentVal, overrideOriginal);
363  if (DEBUG_ANALYSIS)
364  {
365  Xyce::dout() << "Updating parameter " << (*it).name << " to " << (*it).currentVal << std::endl;
366  }
367  }
368 
369  return reset;
370 }
371 
372 } // namespace Analysis
373 } // namespace Xyce
374 
bool updateCurrentVal(int stepNumber)
Pure virtual class to augment a linear system.
bool updateSweepParams(Loader::Loader &loader, int step_count, std::vector< SweepParam >::iterator begin, std::vector< SweepParam >::iterator end, bool overrideOriginal=false)
Util::JSON & operator<<(Util::JSON &json, const StatCounts &s)
std::vector< double > valList
virtual bool setParam(std::string &name, double val, bool overrideOriginal=false)=0
SweepParam parseSweepParams(Util::ParamList::const_iterator first, Util::ParamList::const_iterator last)
Populate the sweep params from the parameter list.
virtual double getParamAndReduce(const std::string &name) const =0
int setupSweepLoop(Loader::Loader &loader, std::vector< SweepParam >::iterator begin, std::vector< SweepParam >::iterator end)