Xyce  6.1
N_DEV_DeviceModel.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_DEV_DeviceModel.C,v $
27 //
28 // Purpose :
29 //
30 // Special Notes :
31 //
32 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
33 //
34 // Creation Date : 04/03/00
35 //
36 // Revision Information:
37 // ---------------------
38 //
39 // Revision Number: $Revision: 1.76 $
40 //
41 // Revision Date : $Date: 2015/06/22 23:57:19 $
42 //
43 // Current Owner : $Author: hkthorn $
44 //-------------------------------------------------------------------------
45 
46 #include <Xyce_config.h>
47 
48 #include <iostream>
49 #include <set>
50 
51 #if defined(HAVE_UNORDERED_MAP)
52 #include <unordered_map>
53 using std::unordered_map;
54 #elif defined(HAVE_TR1_UNORDERED_MAP)
55 #include <tr1/unordered_map>
56 using std::tr1::unordered_map;
57 #else
58 #error neither unordered_map or tr1/unordered_map found
59 #endif
60 
61 #if defined(HAVE_UNORDERED_SET)
62 #include <unordered_set>
63 using std::unordered_set;
64 #elif defined(HAVE_TR1_UNORDERED_SET)
65 #include <tr1/unordered_set>
66 using std::tr1::unordered_set;
67 #else
68 #error neither unordered_set or tr1/unordered_set found
69 #endif
70 
71 #include <N_DEV_Const.h>
72 #include <N_DEV_DeviceModel.h>
73 #include <N_DEV_DeviceBlock.h>
74 #include <N_DEV_DeviceOptions.h>
75 #include <N_DEV_SolverState.h>
76 #include <N_DEV_Param.h>
77 #include <N_DEV_Message.h>
78 #include <N_DEV_Configuration.h>
79 
80 #include <N_ERH_ErrorMgr.h>
81 
82 namespace Xyce {
83 namespace Device {
84 
85 //-----------------------------------------------------------------------------
86 // Function : DeviceModel::DeviceModel
87 // Purpose : model block constructor
88 // Special Notes :
89 // Scope : public
90 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
91 // Creation Date : 3/30/00
92 //-----------------------------------------------------------------------------
94  const ModelBlock & model_block,
95  ParametricData<void> & parametric_data,
96  const FactoryBlock & factory_block)
97  : DeviceEntity(parametric_data, factory_block.solverState_, factory_block.deviceOptions_, model_block.getNetlistLocation().getFilename(), model_block.getNetlistLocation().getLineNumber()),
98  name_(model_block.getName()),
99  type_(model_block.getType()),
100  level_(model_block.getLevel()),
101  temperatureModel(""),
102  doseModel(""),
103  iModel(TEMP),
104  iMethod(QUAD),
105  base_temp(CONSTREFTEMP)
106 {}
107 
108 std::ostream &
109 DeviceModel::printName(std::ostream &os) const
110 {
111  return os << "model " << name_;
112 }
113 
114 //-----------------------------------------------------------------------------
115 // Function : DeviceModel::setModParams
116 // Purpose : Set up parameter fits from model line
117 // Special Notes :
118 //
119 // Scope : public
120 // Creator : Dave Shirley, PSSI
121 // Creation Date : 8/26/05
122 //-----------------------------------------------------------------------------
123 void DeviceModel::setModParams(const std::vector<Param> &params)
124 {
125  std::vector<int> m_start;
126  unordered_set<std::string> pname;
127  std::vector<std::string> ptype_expr;
128 
129  int param_index = 0;
130  m_start.push_back(param_index);
131  for (std::vector<Param>::const_iterator mp = params.begin(); mp != params.end(); ++mp)
132  {
133  ++param_index;
134  if ((*mp).tag() == "INDEPENDENT;PARAM")
135  {
136  m_start.push_back(param_index);
137  pname.clear();
138  }
139  else
140  {
141  std::pair<unordered_set<std::string>::iterator,bool> ret = pname.insert((*mp).tag());
142  if (ret.second==false)
143  {
144  UserError0(*this) << "Duplicate specification of parameter " << (*mp).tag();
145  return;
146  }
147  if (m_start.size() == 1)
148  {
149  // Collect all parameters that are expressions.
150  if ((*mp).getType() == Util::EXPR)
151  {
152  ptype_expr.push_back( (*mp).tag() );
153  }
154  }
155  }
156  }
157 
158  // Make sure list of expression model parameters is unique and sorted.
159  std::sort( ptype_expr.begin(), ptype_expr.end() );
160  ptype_expr.erase(std::unique(ptype_expr.begin(), ptype_expr.end() ), ptype_expr.end() );
161 
162  if (m_start.size() == 1)
163  {
164  setParams(params);
165  }
166  else
167  {
168  m_start.push_back(param_index + 1);
169 
170  // An interpolation method is present, first figure out what it
171  // is and make sure that all models agree on the method.
172  std::string tmod("");
173  std::string dmod("");
174  std::string modName("");
175 
176  for (int i = 0; i < m_start.size()-1; ++i)
177  {
178  for (int j = m_start[i]; j < m_start[i+1]-1; ++j)
179  {
180  if (params[j].tag() == "TEMPMODEL" && params[j].stringValue() != "NONE")
181  {
182  if (i == 0)
183  {
184  tmod = params[j].stringValue();
185  }
186  else
187  {
188  if (tmod != params[j].stringValue())
189  {
190  UserError0(*this) << "Inconsistent or missing TEMPMODEL parameter, " << params[j].stringValue() << " specified here, " << tmod << " specified perviously";
191  return;
192  }
193  }
194  }
195  if (params[j].tag() == "DOSEMODEL" && params[j].stringValue() != "NONE")
196  {
197  if (i == 0)
198  {
199  dmod = params[j].stringValue();
200  }
201  else
202  {
203  if (dmod != params[j].stringValue())
204  {
205  UserError0(*this) << "Inconsistent or missing DOSEMODEL parameter, " << params[j].stringValue() << " specified here, " << dmod << " specified perviously";
206  return;
207  }
208  }
209  }
210  }
211  }
212 
213  if (tmod == "" && dmod == "")
214  {
215  UserError0(*this) << "Duplicate model specification implies parameter interpolation, TEMPMODEL or DOSEMODEL parameters must specified";
216  return;
217  }
218  else if (tmod != "" && dmod != "")
219  {
220  UserError0(*this) << "Only one of TEMPMODEL or DOSEMODEL parameters may be specified";
221  return;
222  }
223  else if (tmod != "")
224  {
225  modName = tmod;
226  iModel = TEMP;
227  }
228  else if (dmod != "")
229  {
230  modName = dmod;
231  iModel = DOSE;
232  }
233 
234  if (modName == "QUADRATIC")
235  {
236  iMethod = QUAD;
237  if (m_start.size() != 4)
238  {
239  UserError0(*this) << "Three model specifications required for QUADRATIC fit";
240  return;
241  }
242  fit.resize(3);
243  }
244  else if (modName == "PWL")
245  {
246  iMethod = PWL;
247  fit.resize(m_start.size() - 1);
248  }
249  else
250  {
251  UserError0(*this) << "Only QUADRATIC or PWL interpolation method is supported";
252  return;
253  }
254 
255  // First find the params that vary between the specified models:
256  unordered_map<std::string,double> basePars;
257  std::vector<double> t;
258  std::string par;
259 
260  for (int i = 0 ;i < m_start.size()-1; ++i)
261  {
262  for (int j = m_start[i]; j < m_start[i+1]-1; ++j)
263  {
264  par = params[j].tag();
265  ParameterMap::const_iterator parIt = getParameterMap().find(par);
266  if (parIt == getParameterMap().end())
267  DevelFatal0(*this).in("DeviceModel::setModParams") << "Parameter " << par << " not found";
268 
269  const Descriptor &nPar = *(*parIt).second;
270  if (params[j].given() && nPar.isType<double>())
271  {
272  if (iModel == TEMP)
273  {
274  if (par == "TNOM")
275  {
276  t.push_back(params[j].getImmutableValue<double>());
277  }
278  }
279  else if (iModel == DOSE)
280  {
281  if (par == "DOSE")
282  {
283  t.push_back(params[j].getImmutableValue<double>());
284  }
285  }
286  if (i == 0)
287  {
288  if (params[j].getType() != Util::EXPR)
289  {
290  basePars[par] = params[j].getImmutableValue<double>();
291  }
292  }
293  else
294  {
295  if (std::binary_search( ptype_expr.begin(), ptype_expr.end(), par))
296  {
297  UserWarning0(*this) << "Non-constant expression for parameter " << par << ", it will not interpolated";
298  }
299  else
300  {
301  if (basePars.find(par) == basePars.end())
302  {
303  UserError0(*this) << "Unknown parameter " << params[j].tag() << " in temperature compensation .MODEL statement";
304  return;
305  }
306  if (basePars[par] != params[j].getImmutableValue<double>() && params[j].given())
307  {
308  if (fitMap.find(par) == fitMap.end())
309  {
310  fitMap[par] = fit[0].size();
311  fitParams.push_back(nPar.getMemberPtr<double>());
312  fit[0].push_back(basePars[par]);
313  }
314  }
315  }
316  }
317  }
318  }
319  }
320 
321  if (t.size() != m_start.size()-1)
322  {
323  UserError0(*this) << (iModel == TEMP ? "TNOM" : "DOSE") << " not specified in all .MODEL statements";
324  return;
325  }
326 
327  for (int i = 1; i < t.size(); ++i)
328  {
329  for (int j = 0; j < i; ++j)
330  {
331  if (t[i] == t[j])
332  {
333  UserError0(*this) << "Identical " << (iModel == TEMP ? "TNOM" : "DOSE") << " values in .MODEL statements";
334  return;
335  }
336  }
337  }
338 
339  // Now, collect the values to use for the fits:
340  int nFit = fitMap.size();
341  //int nSet = t.size();
342  std::vector<std::vector<double> > temp(nFit);
343  std::vector<std::vector<double> > val(nFit);
344  oldParams.resize(nFit);
345 
346  for (int i = 1; i < fit.size(); ++i)
347  {
348  fit[i].resize(nFit);
349  }
350  min_par.resize(nFit);
351  max_par.resize(nFit);
352  parType.resize(nFit);
353  std::map<std::string, int>::iterator fm = fitMap.begin();
354  std::map<std::string, int>::iterator fm_end = fitMap.end();
355 
356  for ( ; fm != fm_end ; ++fm)
357  {
358  par = (*fm).first;
359  ParameterMap::const_iterator parIt = getParameterMap().find(par);
360  if (parIt == getParameterMap().end())
361  throw std::runtime_error(std::string("Parameter ") + par + " not found");
362  {
363  const Descriptor &nPar = *(*parIt).second;
364 
366  {
367  parType[fitMap[par]] = LOG_FIT;
368  }
369  else
370  {
371  parType[fitMap[par]] = LINEAR_FIT;
372  }
373  }
374  }
375 
376  base_temp = t[0];
377  if (iModel == TEMP)
378  {
379  base_temp += CONSTCtoK;
380  }
381 
382  for (int i = 0; i < nFit; ++i)
383  {
384  temp[i].push_back(t[0]);
385  val[i].push_back(fit[0][i]);
386  if (parType[i] == LOG_FIT)
387  {
388  if (val[i][0] <= 0)
389  {
390  UserError0 message(*this);
391  message << "Negative parameter value for log interpolation based parameter ";
392  fm = fitMap.begin();
393  for ( ; fm != fm_end ; ++fm)
394  {
395  if ((*fm).second == i)
396  {
397  par = (*fm).first;
398  break;
399  }
400  }
401  message << par;
402  return;
403  }
404  val[i][0] = log(val[i][0]);
405  }
406  min_par[i] = val[i][0];
407  max_par[i] = val[i][0];
408  }
409 
410  for (int i = 1; i < m_start.size()-1; ++i)
411  {
412  for (int j = m_start[i]; j < m_start[i+1]-1; ++j)
413  {
414  if (params[j].getType() == Util::DBLE && params[j].given())
415  {
416  par = params[j].tag();
417  std::map<std::string, int>::iterator fm1 = fitMap.find(par);
418  if (fm1 != fitMap.end())
419  {
420  int k = fm1->second;
421  temp[k].push_back(t[i]);
422  double p = params[j].getImmutableValue<double>();
423  if (parType[k] == LOG_FIT)
424  {
425  if (p <= 0)
426  {
427  UserError0 message(*this);
428  message << "Negative parameter value for log interpolation based parameter ";
429  fm = fitMap.begin();
430  for ( ; fm != fm_end ; ++fm)
431  {
432  if ((*fm).second == k)
433  {
434  par = (*fm).first;
435  break;
436  }
437  }
438  message << par;
439  return;
440  }
441  p = log(p);
442  }
443  val[k].push_back(p);
444  if (p > max_par[k])
445  max_par[k] = p;
446  if (p < min_par[k])
447  min_par[k] = p;
448  }
449  }
450  }
451  }
452 
453  // Finally, do the actual fits:
454  if (fitMap.size() > 0)
455  {
456  if (iMethod == QUAD)
457  {
458  std::map<std::string, int>::iterator f;
459  for (f=fitMap.begin() ; f!=fitMap.end() ; ++f)
460  {
461  int i = (*f).second;
462  if (temp[i].size() == 2)
463  {
464  fit[0][i] = val[i][0];
465  fit[1][i] = (val[i][1] - val[i][0])/(temp[i][1] - temp[i][0]);
466  fit[2][i] = 0;
467  }
468  else if (temp[i].size() == 3)
469  {
470  fit[0][i] = val[i][0];
471  double x1,x2,y1,y2;
472  x1 = temp[i][1] - temp[i][0];
473  y1 = val[i][1];
474  x2 = temp[i][2] - temp[i][0];
475  y2 = val[i][2];
476  fit[2][i] = (x2*y1-x1*y2-fit[0][i]*(x2-x1))/(x2*x1*x1-x1*x2*x2);
477  fit[1][i] = (y1-fit[2][i]*x1*x1-fit[0][i])/x1;
478  }
479  else
480  {
481  DevelFatal0(*this).in("setModParams") << "Internal error in DeviceModel, illegal number of fit points for parameter " << (*f).first;
482  }
483  if ((*f).first == "TNOM")
484  {
485  fit[0][i] += CONSTCtoK;
486  }
487  }
488  }
489  else if (iMethod == PWL)
490  {
491  int nT = fit.size();
492  std::map<double,int> tOrd;
493  for (int i = 0; i < nT; ++i)
494  {
495  tOrd[t[i]] = 0;
496  }
497  int i = 0;
498  std::map<double,int>::iterator tOrd_i = tOrd.begin();
499  std::map<double,int>::iterator tOrd_end = tOrd.end();
500  for ( ; tOrd_i != tOrd_end; ++tOrd_i)
501  {
502  if (iModel == TEMP)
503  {
504  base.push_back((*tOrd_i).first+CONSTCtoK);
505  }
506  else
507  {
508  base.push_back((*tOrd_i).first);
509  }
510  (*tOrd_i).second = i++;
511  }
512  std::map<std::string, int>::iterator f;
513  std::map<std::string, int>::iterator f_end;
514  std::vector<bool> p(nT,false);
515  f=fitMap.begin();
516  f_end=fitMap.end();
517  for ( ; f!=f_end; ++f)
518  {
519  i = (*f).second;
520  for (int j = 0 ;j < nT; ++j)
521  {
522  p[j] = false;
523  }
524  for (int j = 0; j < temp[i].size() ; ++j)
525  {
526  int ind = tOrd[temp[i][j]];
527  p[ind] = true;
528  fit[ind][i] = val[i][j];
529  }
530  for (int j = 0; j < nT ; ++j)
531  {
532  if (!p[j])
533  {
534  int k_lo = j;
535  int k_hi = j;
536  while (k_lo >= 0 && !p[k_lo])
537  {
538  k_lo--;
539  }
540  while (k_hi <nT && !p[k_hi])
541  {
542  ++k_hi;
543  }
544  if (k_lo == -1)
545  {
546  if (k_hi < nT)
547  {
548  fit[j][i] = fit[k_hi][i];
549  }
550  else
551  {
552  DevelFatal0(*this).in("DeviceModel::setModParams") <<"DeviceModel::setModParams: Internal error forming PWL interpolation";
553  }
554  }
555  else
556  {
557  if (k_hi < nT)
558  {
559  double frac = (base[j]-base[k_lo])/(base[k_hi]-base[k_lo]);
560  fit[j][i] = fit[k_hi][i]*frac+fit[k_lo][i]*(1-frac);
561  }
562  else
563  {
564  fit[j][i] = fit[k_lo][i];
565  }
566  }
567  }
568  if ((*f).first == "TNOM")
569  {
570  fit[j][i] += CONSTCtoK;
571  }
572  }
573  }
574  }
575  }
576 
577  // params.resize(m_start[1]-1);
578  // setParams(params);
579  std::vector<Param> remaining_params(&params[0], &params[m_start[1] - 1]);
580  setParams(remaining_params);
581  }
582 }
583 
584 //-----------------------------------------------------------------------------
585 // Function : DeviceModel::~DeviceModel
586 // Purpose : destructor
587 // Special Notes :
588 // Scope : public
589 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
590 // Creation Date : 3/30/00
591 //-----------------------------------------------------------------------------
593 {
594 }
595 
596 //-----------------------------------------------------------------------------
597 // Function : DeviceModel::saveParams
598 // Purpose : save existing param values before fitting params to temperature
599 // Special Notes :
600 // Scope : public
601 // Creator : Dave Shirley, PSSI
602 // Creation Date : 8/29/05
603 //-----------------------------------------------------------------------------
605 {
606  int nFit = fitMap.size();
607  int i;
608 
609  if (nFit == 0)
610  {
611  return;
612  }
613 
614  for (i=0 ; i<nFit ; ++i)
615  {
616  oldParams[i] = this->*(fitParams[i]);
617  }
618 }
619 
620 //-----------------------------------------------------------------------------
621 // Function : DeviceModel::interpolateTNOM
622 // Purpose : interpolate param values to a specified temperature
623 // Special Notes :
624 // Scope : public
625 // Creator : Dave Shirley, PSSI
626 // Creation Date : 8/29/05
627 //-----------------------------------------------------------------------------
629 {
630  if (iModel != TEMP)
631  {
632  return false;
633  }
634 
635  return interpolate(t);
636 }
637 
638 //-----------------------------------------------------------------------------
639 // Function : DeviceModel::interpolateDOSE
640 // Purpose : interpolate param values to a specified temperature
641 // Special Notes :
642 // Scope : public
643 // Creator : Dave Shirley, PSSI
644 // Creation Date : 11/11/05
645 //-----------------------------------------------------------------------------
647 {
648  if (iModel != DOSE)
649  {
650  return false;
651  }
652 
653  return interpolate(d);
654 }
655 
656 //-----------------------------------------------------------------------------
657 // Function : DeviceModel::interpolated
658 // Purpose : returns true if an interpolation is in effect
659 // Special Notes :
660 // Scope : private
661 // Creator : Dave Shirley, PSSI
662 // Creation Date : 1/31/06
663 //-----------------------------------------------------------------------------
665 {
666  return (fitMap.size() > 0);
667 }
668 
669 //-----------------------------------------------------------------------------
670 // Function : DeviceModel::interpolate
671 // Purpose : interpolate param values to a specified temperature
672 // Special Notes :
673 // Scope : private
674 // Creator : Dave Shirley, PSSI
675 // Creation Date : 11/11/05
676 //-----------------------------------------------------------------------------
678 {
679  int nFit = fitMap.size();
680  int i, j, k_hi, k_lo;
681  double del;
682  double frac, p;
683 
684  if (nFit == 0)
685  {
686  return false;
687  }
688 
689  if (iMethod == QUAD)
690  {
691  del = t - base_temp;
692  // for (i=0 ; i<nFit ; ++i)
693  std::map<std::string,int>::iterator fp;
694  std::map<std::string,int>::iterator fm_begin=fitMap.begin();
695  std::map<std::string,int>::iterator fm_end=fitMap.end();
696  for (fp=fm_begin; fp != fm_end; fp++)
697  {
698  i=fp->second;
699  p = (fit[2][i]*del + fit[1][i])*del + fit[0][i];
700 
701  if (p > max_par[i] && i>0)
702  {
703  this->*(fitParams[i]) = max_par[i];
704  }
705  else if (p < min_par[i] && i>0)
706  {
707  this->*(fitParams[i]) = min_par[i];
708  }
709  else
710  {
711  this->*(fitParams[i]) = p;
712  }
713  }
714  }
715  else if (iMethod == PWL)
716  {
717  del = t;
718  k_hi = 0;
719  for (j=0 ; j<fit.size() ; ++j)
720  {
721  if (base[j] >= del)
722  {
723  break;
724  }
725  k_hi = j+1;
726  }
727  if (k_hi == 0)
728  {
729  frac = 0;
730  }
731  else if (k_hi == fit.size())
732  {
733  k_hi = fit.size()-1;
734  frac = 1;
735  }
736  else
737  {
738  k_lo = k_hi-1;
739  frac = (del-base[k_lo])/(base[k_hi]-base[k_lo]);
740  }
741  if (frac == 1)
742  {
743  for (i=0 ; i<nFit ; ++i)
744  {
745  this->*(fitParams[i]) = fit[k_hi][i];
746  }
747  }
748  else
749  {
750  for (i=0 ; i<nFit ; ++i)
751  this->*(fitParams[i]) = fit[k_hi][i]*frac + fit[k_lo][i]*(1-frac);
752  }
753  }
754  for (i=0 ; i<nFit ; ++i)
755  {
756  if (parType[i] == LOG_FIT)
757  {
758  this->*(fitParams[i]) = exp(this->*(fitParams[i]));
759  }
760  }
761 
762  return true;
763 }
764 
765 //-----------------------------------------------------------------------------
766 // Function : DeviceModel::restoreParams
767 // Purpose : restore previously saved param values
768 // Special Notes :
769 // Scope : public
770 // Creator : Dave Shirley, PSSI
771 // Creation Date : 8/29/05
772 //-----------------------------------------------------------------------------
774 {
775  int nFit = fitMap.size();
776  int i;
777 
778  if (nFit == 0)
779  {
780  return;
781  }
782 
783  for (i=0 ; i<nFit ; ++i)
784  {
785  this->*(fitParams[i]) = oldParams[i];
786  }
787 }
788 
789 } // namespace Device
790 } // namespace Xyce
std::vector< double > oldParams
std::vector< double > max_par
#define CONSTCtoK
Definition: N_DEV_Const.h:52
#define CONSTREFTEMP
Definition: N_DEV_Const.h:56
bool given(const std::string &parameter_name) const
Pure virtual class to augment a linear system.
std::vector< std::vector< double > > fit
const std::string & getName(const C *c)
Returns the name of the specified object.
void setParams(const std::vector< Param > &params)
const ParameterMap & getParameterMap() const
The FactoryBlock contains parameters needed by the device, instance and model creation functions...
std::vector< double > base
Class ParametricData manages the configuration information and the parameter binding map...
Definition: N_DEV_Pars.h:1303
ExprAccess getExpressionAccess() const
Gets the expression access which describes the usage of the paramter.
Definition: N_DEV_Pars.h:659
Parameter uses temperature interpolation based on log of value.
Definition: N_DEV_Pars.h:69
Class Descriptor describes the parameters stored in the ParametricData parameter map.
Definition: N_DEV_Pars.h:546
std::vector< fitType > parType
virtual std::ostream & printName(std::ostream &os) const
const std::string & getType() const
bool isType() const
Tests entry data type.
Definition: N_DEV_Pars.h:597
std::vector< double > min_par
ModelBlock represents a .MODEL line from the netlist.
T ParameterBase::* getMemberPtr() const
Returns the parameter member variable pointer of the enrtry.
Definition: N_DEV_Pars.h:905
std::map< std::string, int > fitMap
std::vector< double DeviceEntity::* > fitParams
void setModParams(const std::vector< Param > &params)