Xyce  6.1
N_DEV_Capacitor.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_Capacitor.C,v $
27 //
28 // Purpose :
29 //
30 // Special Notes :
31 //
32 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
33 //
34 // Creation Date : 02/28/00
35 //
36 // Revision Information:
37 // ---------------------
38 //
39 // Revision Number: $Revision: 1.282 $
40 //
41 // Revision Date : $Date: 2015/09/09 19:26:08 $
42 //
43 // Current Owner : $Author: tvrusso $
44 //-------------------------------------------------------------------------
45 
46 #include <Xyce_config.h>
47 
48 #include <N_DEV_Capacitor.h>
49 #include <N_DEV_Const.h>
50 #include <N_DEV_DeviceOptions.h>
51 #include <N_DEV_ExternData.h>
52 #include <N_DEV_MatrixLoadData.h>
53 #include <N_DEV_Message.h>
54 #include <N_DEV_SolverState.h>
55 #include <N_LAS_Matrix.h>
56 #include <N_LAS_Vector.h>
57 #include <N_UTL_Expression.h>
58 #include <N_UTL_FeatureTest.h>
59 #include <N_UTL_LogStream.h>
60 #include <N_UTL_Math.h>
61 
62 namespace Xyce {
63 namespace Device {
64 namespace Capacitor {
65 
66 //-----------------------------------------------------------------------------
67 // Function : Xyce::Device::Capacitor::Traits::loadInstanceParameters
68 // Purpose :
69 // Special Notes : The addPar calls here were refactored and moved here
70 // from the instance constructor. Those addPars had been
71 // in place from 2/4/2005.
72 // Scope : private
73 // Creator : David Baur
74 // Creation Date : 1/27/2014
75 //-----------------------------------------------------------------------------
76 ///
77 /// Loads the parameter definition into the instance parameter map.
78 ///
79 /// @param p instance parameter map
80 ///
81 /// @see Xyce::Device::Resistor::Traits::loadInstanceParameters
82 ///
84 {
85  p.addPar("C", 1.e-6, &Capacitor::Instance::C)
86  .setExpressionAccess(ParameterType::SOLN_DEP)
87  .setUnit(U_FARAD)
88  .setDescription("Capacitance")
89  .setAnalyticSensitivityAvailable(true)
90  .setSensitivityFunctor(&capSens);
91  p.addPar("IC", 0.0, &Capacitor::Instance::IC)
92  .setGivenMember(&Capacitor::Instance::ICGiven)
93  .setUnit(STANDARD);
95  .setUnit(U_METER)
96  .setDescription("Semiconductor capacitor width");
97  p.addPar("W", 1.e-6, &Capacitor::Instance::width)
98  .setUnit(U_METER)
99  .setDescription("Semiconductor capacitor length");
100  p.addPar("AGE", 0.0, &Capacitor::Instance::age)
101  .setUnit(U_HOUR)
102  .setDescription("Age of capacitor");
103  p.addPar("D", 0.0233, &Capacitor::Instance::ageCoef)
104  .setDescription("Age degradation coefficient");
105  p.addPar("TEMP", 0.0, &Capacitor::Instance::temp)
106  .setExpressionAccess(ParameterType::TIME_DEP)
107  .setUnit(STANDARD)
108  .setDescription("Device temperature");
109 
111  .setGivenMember(&Capacitor::Instance::tempCoeff1Given)
112  .setUnit(U_DEGCM1)
113  .setDescription("Linear Temperature Coefficient");
115  .setGivenMember(&Capacitor::Instance::tempCoeff2Given)
116  .setUnit(U_DEGCM2)
117  .setDescription("Quadratic Temperature Coefficient");
118  p.makeVector("TC", 2);
119 }
120 
121 //-----------------------------------------------------------------------------
122 // Function : Xyce::Device::Capacitor::Traits::loadModelParameters
123 // Purpose :
124 // Special Notes : The addPar calls here were refactored and moved here
125 // from the model constructor. Those addPars had been
126 // in place from 2/4/2005.
127 // Scope : private
128 // Creator : David Baur
129 // Creation Date : 1/27/2014
130 //-----------------------------------------------------------------------------
131 ///
132 /// Loads the parameter definition into the model parameter map.
133 ///
134 /// @param p model parameter map
135 ///
136 /// @see Xyce::Device::Resistor::Traits::loadInstanceParameters
137 ///
139 {
141  .setUnit(U_NONE)
142  .setDescription("Capacitance multiplier");
143  p.addPar("CJ", 0.0, &Capacitor::Model::cj)
144  .setUnit(U_FARADMM2)
145  .setDescription("Junction bottom capacitance");
146  p.addPar("CJSW", 0.0, &Capacitor::Model::cjsw)
147  .setUnit(U_FARADMM1)
148  .setDescription("Junction sidewall capacitance");
149  p.addPar("DEFW", 1.e-6, &Capacitor::Model::defWidth)
150  .setUnit(U_METER)
151  .setDescription("Default device width");
152  p.addPar("NARROW", 0.0, &Capacitor::Model::narrow)
153  .setUnit(U_METER)
154  .setDescription("Narrowing due to side etching");
155  p.addPar("TC1", 0.0, &Capacitor::Model::tempCoeff1)
156  .setUnit(STANDARD);
157  p.addPar("TC2", 0.0, &Capacitor::Model::tempCoeff2)
158  .setUnit(STANDARD);
159  p.addPar("TNOM", 0.0, &Capacitor::Model::tnom)
160  .setGivenMember(&Capacitor::Model::tnomGiven)
161  .setUnit(STANDARD);
162 }
163 
164 // Class Instance
165 //-----------------------------------------------------------------------------
166 // Function : Instance::processParams
167 // Purpose :
168 // Special Notes :
169 // Scope : public
170 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
171 // Creation Date : 6/03/02
172 //-----------------------------------------------------------------------------
173 /// Process parameters.
174 ///
175 /// @return true on success
176 ///
177 /// In general, the processParams method is intended as a place for complex
178 /// manipulation of parameters that must happen if temperature or other
179 /// external changes happen.
180 ///
181 /// The Capacitor device supports an "AGE" parameter and a degradation
182 /// rate parameter that together determine how to modify the
183 /// capacitance given on the instance line. Further, Xyce supports a
184 /// "semiconductor capacitor" model which allows the user to specify
185 /// the capacitance through a combination of model parameters (junction
186 /// capacitance and junction sidewall capacitance) and instance parameters
187 /// (length and width).
188 ///
189 /// Both of these methods of capacitance value determination need to
190 /// be done after the normal processing of netlist parameters. That
191 /// processing is done here.
192 ///
193 /// @author Eric Keiter, SNL, Parallel Computational Sciences
194 /// @date 6/03/02
196 {
197  // Set any non-constant parameter defaults:
198 
199  if (!given("W"))
201  if (!given("TEMP"))
202  temp = getDeviceOptions().temp.getImmutableValue<double>();
203 
204  if (!tempCoeff1Given)
206  if (!tempCoeff2Given)
208 
209 
210 
211  baseCap = C;
212  if (!given("C") && given("AGE"))
213  {
214  UserError0(*this) << "Age defined, but no base capacitance given. Can't use age-aware with semiconductor capacitor options";
215  }
216 
217  // the age aware capacitor simply modifies the base capacitance.
218  if (given("AGE") && age >= 1)
219  {
220  baseCap = baseCap*(1-ageCoef*log10(age));
221  }
222 
223  if (!given("C") && !given("L"))
224  {
225  UserError0(*this) << "Could find neither C parameter or L in instance.";
226  }
227 
228  // Now we know we have either cap or length specified.
229  if (!given("C"))
230  {
231  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
232  {
233  dout() << "Semiconductor capacitor " << getName()
234  //<< Util::push << std::endl
235  << std::endl
236  << "cj = " << model_.cj << std::endl
237  << "cjsw = " << model_.cjsw << std::endl
238  << "width = " << width << std::endl
239  << "length = " << length << std::endl
240  << "narrow = " << model_.narrow <<
241  //Util::pop << std::endl;
242  std::endl;
243  }
244 
245  baseCap = C =
248  }
249 
250  // If there are any time dependent parameters, set their values for
251  // the current time.
252 
254 
255  return true;
256 }
257 
258 //-----------------------------------------------------------------------------
259 // Function : Instance::updateTemperature
260 // Purpose :
261 // Special Notes :
262 // Scope : public
263 // Creator : Tom Russo, Component Information and Models
264 // Creation Date : 02/27/01
265 //-----------------------------------------------------------------------------
266 ///
267 /// Update the parameters that depend on the temperature of the device
268 ///
269 /// @param temp_tmp temperature
270 ///
271 /// Xyce has a number of mechanisms that allow temperature to be changed
272 /// after a device has been instantiated. These include .STEP loops over
273 /// temperature. When temperature is changed, any device that has parameters
274 /// that depend on temperature must be updated. That updating happens here.
275 ///
276 /// The capacitor device supports temperature-dependent resistance through its
277 /// TC1 (linear dependence) and TC2 (quadratic dependence) parameters.
278 /// If these parameters are specified, the capacitance must be updated.
279 ///
280 bool Instance::updateTemperature ( const double & temp_tmp)
281 {
282  bool bsuccess = true;
283  double difference, factor;
284 
285  difference = temp - model_.tnom;
286  factor = model_.capacitanceMultiplier*(1.0 + tempCoeff1*difference +
287  tempCoeff2*difference*difference);
288  C = baseCap*factor;
289 
290  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
291  {
292  dout() << "Capacitor " << getName() << " updateTemperature()"
293  //<< Util::push << std::endl
294  << std::endl
295  << "C = " << C << std::endl
296  << "temp = " << temp << std::endl
297  << "temp_tmp = " << temp_tmp << std::endl
298  << "tnom = " << model_.tnom << std::endl
299  << "difference = " << difference << std::endl
300  << "tempCoeff1 = " << tempCoeff1 << std::endl
301  << "tempCoeff2 = " << tempCoeff2 << std::endl
302  << "baseCap = " << baseCap << std::endl
303  //<< "factor = " << factor << Util::pop << std::endl;
304  << "factor = " << factor << std::endl;
305  }
306 
307  return bsuccess;
308 }
309 
310 //-----------------------------------------------------------------------------
311 // Function : Instance::Instance
312 // Purpose : instance block constructor
313 // Special Notes :
314 // Scope : public
315 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
316 // Creation Date : 3/16/00
317 //-----------------------------------------------------------------------------
318 ///
319 /// Construct a Capacitor model from a "model block" that was created
320 /// by the netlist parser.
321 ///
322 /// @param configuration
323 /// @param model_block
324 /// @param factory_block
325 ///
326 /// @author Eric Keiter, SNL, Parallel Computational Sciences
327 /// @date 3/16/00
329  const Configuration & configuration,
330  const InstanceBlock & instance_block,
331  Model & model,
332  const FactoryBlock & factory_block)
333  : DeviceInstance(instance_block, configuration.getInstanceParameters(), factory_block),
334  model_(model),
335  expNumVars(0),
336  expPtr(0),
337  baseCap(0.0),
338  temp(getDeviceOptions().temp.getImmutableValue<double>()),
339  tempGiven(0),
340  tempCoeff1(0.0),
341  tempCoeff2(0.0),
342  tempCoeff1Given(false),
343  tempCoeff2Given(false),
344  li_Pos(-1),
345  li_Neg(-1),
346  li_QState(-1),
347  li_vcapState(-1),
348  li_capState(-1),
349  li_store_dev_i(-1),
350  li_branch_data(0),
351  APosEquPosNodeOffset(-1),
352  ANegEquPosNodeOffset(-1),
353  APosEquNegNodeOffset(-1),
354  ANegEquNegNodeOffset(-1),
355  APosEquBraNodeOffset(-1),
356  ANegEquBraNodeOffset(-1),
357  ABraEquBraNodeOffset(-1),
358  ABraEquPosNodeOffset(-1),
359  ABraEquNegNodeOffset(-1),
360 
362  qPosEquPosNodePtr(0),
363  qNegEquPosNodePtr(0),
364  qPosEquNegNodePtr(0),
365  qNegEquNegNodePtr(0),
366  fPosEquBraNodePtr(0),
367  fNegEquBraNodePtr(0),
368  fBraEquBraNodePtr(0),
369  fBraEquPosNodePtr(0),
370  fBraEquNegNodePtr(0),
371 #endif
372 
373  ICGiven(false),
374  solVarDepC(false),
375  IC(0)
376 
377 {
378  numIntVars = 0;
379  numExtVars = 2;
380  numStateVars = 1;
381  setNumStoreVars(0);
382  numLeadCurrentStoreVars = 1; // lead current DEV_I
383  setNumBranchDataVars(0); // by default don't allocate space in branch vectors
384  numBranchDataVarsIfAllocated = 1; // this is the space to allocate if lead current or power is needed.
385 
386  devConMap[0] = 1;
387  devConMap[1] = 2;
388 
389  /// Unlike the resistor, the capacitor's jacobian stamp is set up directly
390  /// in the constructor, and is not static. This is because the capacitor
391  /// supports some options that the resistor does not:
392  ///
393  /// - The capacitor instance line may be given an IC=value that
394  /// will be used as the initial voltage drop across the
395  /// capacitance at the operating point.
396  ///
397  /// - The capacitance on the instance line may be an expression
398  /// that is permitted to be a function of other solution variables (such
399  /// as voltages elsewhere in the circuit).
400  ///
401  /// Both of these require that the Jacobian stamp for the device be modified.
402  /// Use of a static Jacobian stamp would prevent this flexibility, because
403  /// the static stamp would be used by all capacitor devices, even those
404  /// that do not make use of the options.
405  ///
406  /// Since the setting of the Jacobian stamp in this otherwise simple device
407  /// is so complex, we will document how it is set here.
408  ///
409  /// In its simplest form, the charge \f$q_0\f$ on the capacitor is
410  /// \f$C(V_+-V_-)\f$. Thus, the current out of the positive node is
411  /// \f$d(q_0)/dt\f$, and the current "out" of the negative node is
412  /// \f$-d(q0)/dt\f$. In the Xyce formulation, we load \f$q_0\f$ into
413  /// the Q vector for the positive node, and \f$-q_0\f$ into the Q
414  /// vector for the negative node; the time integator will later
415  /// differentiate this to obtain the currents. Thus, the contribution
416  /// to the Jacobian from the capacitor (with constant capacitance and
417  /// no initial condition) will require loading the dQdx matrix with the
418  /// derivatives of \f$q_0\f$ with respect to the voltage nodes:
419  /// \f[
420  /// \left[\begin{array}{rr}
421  /// C & -C \\
422  /// -C & C
423  /// \end{array} \right] \f]
424  ///
425  /// The jacobian stamp in this case is the same as the one defined by
426  /// the resistor: it has two rows, one for the positive node equation
427  /// and one for negative node equation, and two columns, one for the
428  /// positive node and one for the negative. Column 0's value in each
429  /// row is 0 to reflect that the first nonzero value of the jacobian
430  /// row is the one corresponding to the positive node, and column 1's value
431  /// is 1 to reflect that the second nonzero corresponds to the dependence on
432  /// the negative node.
433  ///
434  /// If an initial condition is present, however, the circuit at DC is
435  /// the same as if there were only a voltage source across the
436  /// positive and negative nodes, and in transient it is the same as
437  /// the capacitor without the voltage source present. Thus, at DC the
438  /// current out of the positive node would be equal to the voltage
439  /// source branch current, and the current out of the negative node
440  /// would be the negative of that. Since these quantities are not
441  /// differentiated they would be placed in the F vector, no the Q
442  /// vector. An extra equation, called the "branch equation"
443  /// stipulates that the voltage drop between the positive and negative
444  /// node be equal to the initial condition, so this element of
445  /// the F vector would be loaded with \f$(V_+-V_-)-V_{ic}\f$.
446  /// Therefore in DC the dFdx matrix would be loaded with:
447  /// \f[
448  /// \left[ \begin{array}{rrr}
449  /// 0 & 0 & 1 \\
450  /// 0 & 0 & -1 \\
451  /// 1 & -1 & 0
452  /// \end{array}\right] \f]
453  /// The the first two rows are for the positive and negative node
454  /// equations, and the third row is for the branch equation. The
455  /// third column is for the branch current variable. At DC nothing
456  /// would be loaded into either the Q vector or its derivative.
457  ///
458  /// In transient, the loads into the Q vector are the same as
459  /// without the initial condition. Xyce requires that a single jacobian
460  /// stamp be used for both the dFdx and dQdx matrices, and does not allow
461  /// this matrix to vary between DC and transient. Thus the dQdx matrix would
462  /// be loaded with:
463  /// \f[
464  /// \left[ \begin{array}{rrr}
465  /// C & -C & 0 \\
466  /// -C & C & 0 \\
467  /// 0 & 0 & 0
468  /// \end{array}\right] \f]
469  /// The dFdx matrix must be loaded with a single value to turn off the
470  /// branch equation and prevent a singular Jacobian:
471  /// \f[
472  /// \left[ \begin{array}{rrr}
473  /// 0 & 0 & 0 \\
474  /// 0 & 0 & 0 \\
475  /// 0 & 0 & 1
476  /// \end{array}\right] \f]
477  /// The net result of this modification is that now, irrespective of whether
478  /// we are at DC or in transient, every element of the 3x3 matrix is potentially
479  /// nonzero in one or the other of dFdx or dQdx, and therefore our jacobian
480  /// stamp is also a dense 3x3 matrix, with each column's value equal to that
481  /// column's number.
482  ///
483  /// Finally, if the capacitance is solution-variable dependent, each of the
484  /// rows for positive and negative nodes must be augmented with an additional
485  /// column for each variable that the capacitance depends on. These rows
486  /// are similarly dense, and each value of the jacobian stamp for each column
487  /// is equal to its column number.
488  if( jacStamp.empty() )
489  {
490  jacStamp_IC.resize(3);
491  jacStamp_IC[0].resize(3);
492  jacStamp_IC[1].resize(3);
493  jacStamp_IC[2].resize(3);
494  jacStamp_IC[0][0] = 0;
495  jacStamp_IC[0][1] = 1;
496  jacStamp_IC[0][2] = 2;
497  jacStamp_IC[1][0] = 0;
498  jacStamp_IC[1][1] = 1;
499  jacStamp_IC[1][2] = 2;
500  jacStamp_IC[2][0] = 0;
501  jacStamp_IC[2][1] = 1;
502  jacStamp_IC[2][2] = 2;
503 
504  jacStamp.resize(2);
505  jacStamp[0].resize(2);
506  jacStamp[1].resize(2);
507  jacStamp[0][0] = 0;
508  jacStamp[0][1] = 1;
509  jacStamp[1][0] = 0;
510  jacStamp[1][1] = 1;
511  }
512 
513 
514  // Set params to constant default values:
515  setDefaultParams ();
516 
517  // Set params according to instance line and constant defaults from metadata:
518  setParams (instance_block.params);
519 
520 
521  // Handle case where capacitance is solution-variable dependent:
522  if (getDependentParams().size()>0)
523  {
524  std::vector<Depend>::const_iterator d;
525  std::vector<Depend>::const_iterator begin=getDependentParams().begin();
526  std::vector<Depend>::const_iterator end=getDependentParams().end();
527 
528  for (d=begin; d!=end; ++d)
529  {
530  if (d->name != "C")
531  {
532  UserError0(*this) << "Solution-variable-dependent parameter other than C detected";
533  }
534  else
535  {
536  expNumVars = d->n_vars;
537  expPtr = d->expr;
538 
539  if (expNumVars > 0 || expPtr->isTimeDependent())
540  {
541  solVarDepC = true;
542  // To do the proper integration of the charge, we need to save the
543  // voltage drop, the old capacitance and
544  // the derivatives of Q and C from the last step.
545  numStateVars += 2+2*expNumVars;
546 
547  if (expPtr->getNumDdt() != 0)
548  {
549  UserError0(*this) << "Solution-variable-dependent expression contains time derivatives";
550  }
551 
552  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
553  {
554  dout() << "Capacitor " << getName()
555  << ": Found solution-dependent parameter C depending on " << expNumVars << " variables" << std::endl;
556  if (expPtr->isTimeDependent())
557  {
558  dout() << " " << "Expression is time-dependent." << std::endl;
559  }
560  else
561  {
562  dout() << " " << "Expression is not time-dependent." << std::endl;
563  }
564  dout() << " " << "Expression depends on " << expPtr->num_vars() << " quantity, of which " << expPtr->num_vars()-expNumVars << " are not solution vars. " << std::endl;
565 
566  }
567 
568  // We now need to extend the pos and neg rows of the jacstamps
569  // to account for the additional dependencies:
570 
571  jacStamp[0].resize(2+expNumVars);
572  jacStamp[1].resize(2+expNumVars);
573  jacStamp_IC[0].resize(3+expNumVars);
574  jacStamp_IC[1].resize(3+expNumVars);
575  for (int i=0; i<expNumVars; ++i)
576  {
577  jacStamp[0][2+i]=2+i;
578  jacStamp[1][2+i]=2+i;
579 
580  jacStamp_IC[0][3+i]=3+i;
581  jacStamp_IC[1][3+i]=3+i;
582  }
583 
584  // finally, allocate space to hold the derivatives of C w.r.t.
585  // the variables it depends on:
586  expVarDerivs.resize(expNumVars);
587  // and LIDs for state vector
588  li_dQdXState.resize(expNumVars);
589  li_dCdXState.resize(expNumVars);
590 
591  }
592  }
593  }
594  }
595 
596  // Calculate any parameters specified as expressions:
597 
599 
600  // calculate dependent (ie computed) params:
601 
602  processParams ();
603 
604  // we're gonna have to fake a voltage source at the operating point
605  if (ICGiven ) numIntVars = 1;
606 }
607 
608 //-----------------------------------------------------------------------------
609 // Function : Instance::~Instance
610 // Purpose : destructor
611 // Special Notes :
612 // Scope : public
613 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
614 // Creation Date : 3/16/00
615 //-----------------------------------------------------------------------------
617 {
618 }
619 
620 // Additional Declarations
621 
622 //-----------------------------------------------------------------------------
623 // Function : Instance::registerLIDs
624 // Purpose :
625 // Special Notes :
626 // Scope : public
627 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
628 // Creation Date : 6/20/02
629 //-----------------------------------------------------------------------------
630 ///
631 /// Register local IDs
632 ///
633 /// Register the local internal and external node IDs.
634 ///
635 /// @param intLIDVecRef internal local IDs from topology package
636 /// @param extLIDVecRef external local IDs from topology package
637 ///
638 /// Instantiation (calling the device constructor) of the device
639 /// sets up variables numIntVars and numExtVars, the numbers of internal and
640 /// external variables associated with the device. This information is then
641 /// used by the Topology package to assign locations in the solution vector
642 /// (and all other vectors of the same shape) for those variables.
643 /// The "Local IDs" (LIDs) of these locations are provided by Topology
644 /// so the device can know where to load its data.
645 ///
646 /// This method saves the LIDs from Topology and associates each one with
647 /// a particular local name for the internal or external variable. They
648 /// are then used when we load the F and Q vectors.
649 ///
650 /// The Capacitor device has no internal variables, so this method makes no use
651 /// of the intLIDVecRef array.
652 ///
653 /// @author Robert Hoekstra, SNL, Parallel Computational Sciences
654 /// @date 6/20/02
655 void Instance::registerLIDs( const std::vector<int> & intLIDVecRef,
656  const std::vector<int> & extLIDVecRef)
657 
658 {
659  AssertLIDs(intLIDVecRef.size() == numIntVars);
660  AssertLIDs(extLIDVecRef.size() == numExtVars);
661 
662  // Copy over the local ID lists:
663  intLIDVec = intLIDVecRef;
664  extLIDVec = extLIDVecRef;
665 
666  // Now use these lists to obtain the indices into the linear algebra
667  // entities. This assumes an order. For the matrix indices, first do the
668  // rows.
669 
670  li_Pos = extLIDVec[0];
671  li_Neg = extLIDVec[1];
672 
673  // For fake voltage source at operating point
674  if (ICGiven)
675  {
676  li_Bra = intLIDVec[0];
677  }
678 
679  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
680  {
681  dout() << "Capacitor " << getName() << " Instance::registerLIDs"
682  // << Util::push << std::endl
683  << std::endl
684  << "li_Pos_ = " << li_Pos << std::endl
685  << "li_Neg_ = " << li_Neg << std::endl;
686 
687  if (ICGiven)
688  dout() << "li_Bra = "<< li_Bra<< std::endl;
689 
690  //dout() << Util::pop << std::endl;
691  dout() << std::endl;
692  }
693 }
694 
695 //-----------------------------------------------------------------------------
696 // Function : Instance::registerStateLIDs
697 // Purpose :
698 // Special Notes :
699 // Scope : public
700 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
701 // Creation Date : 6/20/02
702 //-----------------------------------------------------------------------------
703 ///
704 /// Register the local state IDs
705 ///
706 /// @param staLIDVecRef State variable local IDs
707 ///
708 /// In general, devices may declare at construction that they require storage
709 /// locations in the "state vector." Topology assigns locations in the
710 /// state vector and returns "Local IDs" (LIDs) for devices to use for their
711 /// state vector entries. If a device uses state vector entries, it
712 /// uses the registerStateLIDs method to save the local IDs for later use.
713 ///
714 /// The capacitor has at least one state variable (the charge) and as many
715 /// as three (the charge plus state variables used to support the "voltage
716 /// dependent capacitance" feature) plus the number of variables on whihc
717 /// the capacitance depends.
718 ///
719 /// @note The storage of the charge as a state variable when the capacitance
720 /// is a constant is a holdover from older implementations, and in the future
721 /// may be saved only as part of the voltage-dependent capacitance feature.
722 ///
723 /// @author Robert Hoekstra, SNL, Parallel Computational Sciences
724 /// @date 06/20/02
725 void Instance::registerStateLIDs( const std::vector<int> & staLIDVecRef)
726 {
727  AssertLIDs(staLIDVecRef.size() == numStateVars);
728 
729  int i=0;
730 
731  // Copy over the global ID lists:
732  staLIDVec = staLIDVecRef;
733 
734  li_QState = staLIDVec[i++];
735 
736  // If the capacitance is voltage dependent, we have additional state vars
737  if (solVarDepC)
738  {
739  li_vcapState = staLIDVec[i++];
740  li_capState = staLIDVec[i++];
741 
742  for (int j = 0; j<expNumVars; ++j)
743  {
744  li_dQdXState[j] = staLIDVec[i++];
745  }
746 
747  for (int j = 0; j<expNumVars; ++j)
748  {
749  li_dCdXState[j] = staLIDVec[i++];
750  }
751  }
752 
753 }
754 
755 
756 //-----------------------------------------------------------------------------
757 // Function : Instance::registerStoreLIDs
758 // Purpose : One store var for device current.
759 // Special Notes :
760 // Scope : public
761 // Creator : Richard Schiek, Electrical Systems Modeling
762 // Creation Date : 01/23/2013
763 //-----------------------------------------------------------------------------
764 /// Register the local store IDs
765 ///
766 /// In addition to state vector, Xyce maintains a separate datastructure
767 /// called a "store" vector. As with other such vectors, the device
768 /// declares at construction time how many store vector entries it needs,
769 /// and later Topology assigns locations for devices, returning LIDs.
770 ///
771 /// These LIDs are stored in this method for later use.
772 ///
773 /// The Capacitor device uses exactly one "store vector" element, where
774 /// it keeps the "lead current" that may be used on .PRINT lines as
775 /// "I(C1)" for the current through resistor R1.
776 ///
777 /// @param stoLIDVecRef Store variable local IDs
778 ///
779 /// @author Richard Schiek, Electrical Systems Modeling
780 /// @date 1/23/2013
781 void Instance::registerStoreLIDs(const std::vector<int> & stoLIDVecRef )
782 {
783  AssertLIDs(stoLIDVecRef.size() == getNumStoreVars());
784 
785  if( loadLeadCurrent )
786  {
787  li_store_dev_i = stoLIDVecRef[0];
788  }
789 }
790 
791 //-----------------------------------------------------------------------------
792 // Function : Xyce::Device::Capacitor::Instance::registerBranchDataLIDs
793 // Purpose :
794 // Special Notes :
795 // Scope : public
796 // Creator : Richard Schiek, Electrical Systems Modeling
797 // Creation Date : 12/18/2012
798 //-----------------------------------------------------------------------------
799 /// Register the local store IDs
800 ///
801 /// In addition to state vector, Xyce maintains a separate datastructure
802 /// called a "branch data" vector. As with other such vectors, the device
803 /// declares at construction time how many branch vector entries it needs,
804 /// and later Topology assigns locations for devices, returning LIDs.
805 ///
806 /// These LIDs are stored in this method for later use.
807 ///
808 /// The Resistor device uses exactly one "branch data vector" element, where
809 /// it keeps the "lead current" that may be used on .PRINT lines as
810 /// "I(C1)" for the current through C1. and a junction voltage.
811 ///
812 /// @param stoLIDVecRef Store variable local IDs
813 ///
814 /// @author Richard Schiek, Electrical Systems Modeling
815 /// @date 12/18/2012
816 
817 void Instance::registerBranchDataLIDs(const std::vector<int> & branchLIDVecRef)
818 {
819  AssertLIDs(branchLIDVecRef.size() == getNumBranchDataVars());
820 
821  if (loadLeadCurrent)
822  {
823  li_branch_data= branchLIDVecRef[0];
824  }
825 }
826 
827 
828 
829 //-----------------------------------------------------------------------------
830 // Function : Instance::loadNodeSymbols
831 // Purpose :
832 // Special Notes :
833 // Scope : public
834 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
835 // Creation Date : 05/13/05
836 //-----------------------------------------------------------------------------
837 void Instance::loadNodeSymbols(Util::SymbolTable &symbol_table) const
838 {
839  if (ICGiven)
840  addInternalNode(symbol_table, li_Bra, getName(), "branch");
841 
842  if (loadLeadCurrent)
843  {
844  //addStoreNode(symbol_table, li_store_dev_i, getName(), "DEV_I");
845  addBranchDataNode( symbol_table, li_branch_data, getName(), "BRANCH_D");
846  }
847 }
848 
849 //-----------------------------------------------------------------------------
850 // Function : Instance::jacobianStamp
851 // Purpose :
852 // Special Notes :
853 // Scope : public
854 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
855 // Creation Date : 08/27/02
856 //-----------------------------------------------------------------------------
857 ///
858 /// Return Jacobian stamp that informs topology of the layout of the
859 /// resistor jacobian.
860 ///
861 /// @return const reference to a std::vector of std::vector of
862 /// integers describing Jacobian stamp shape
863 //
864 /// The Jacobian stamp describes the shape of the Jacobian to the
865 /// Topology subsystem. The Topology subsystem, in turn, returns
866 /// the offsets into the matrix and solution vectors where this
867 /// instance data is located.
868 ///
869 /// The Jacobian stamp of the capacitor depends on whether an initial
870 /// condition is given or not.
871 ///
872 /// @author Robert Hoekstra
873 /// @date 8/20/2001
874 const std::vector< std::vector<int> > & Instance::jacobianStamp() const
875 {
876  if (ICGiven)
877  return jacStamp_IC;
878  else
879  return jacStamp;
880 }
881 
882 //-----------------------------------------------------------------------------
883 // Function : Instance::registerJacLIDs
884 // Purpose :
885 // Special Notes :
886 // Scope : public
887 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
888 // Creation Date : 08/27/02
889 //-----------------------------------------------------------------------------
890 ///
891 /// Register the Jacobian local IDs
892 ///
893 /// @param jacLIDVec Jacobian local Ids
894 ///
895 /// @see Xyce::Device::Capacitor::Instance::Capacitor
896 ///
897 /// Having established local IDs for the solution variables, Topology must
898 /// also assign local IDs for the elements of the Jacobian matrix.
899 ///
900 /// For each non-zero element that was identified in the jacobianStamp,
901 /// Topology will assign a Jacobian LID. The jacLIDVec will have the
902 /// same structure as the JacStamp, but the values in the jacLIDVec will
903 /// be offsets into the row of the sparse Jacobian matrix corresponding
904 /// to the non-zero identified in the stamp.
905 ///
906 /// These offsets are stored in this method for use later when we load
907 /// the Jacobian.
908 ///
909 /// @note Because the capacitor's Jacobian stamp depends on whether an
910 /// initial condition was given or not, this method is slightly more
911 /// complex than the corresponding method in the Resistor. The method
912 /// is further complicated by the possibilty that the capacitance may
913 /// be given as an expression depending on solution variables; in this case,
914 /// the capacitor jacstamp has extra columns for the device's dependence on
915 /// those other variables.
916 ///
917 /// @see Xyce::Device::Resistor::Instance::registerJacLIDs
918 ///
919 /// @author Robert Hoekstra, SNL, Parallel Computational Sciences
920 /// @date 08/27/02
921 void Instance::registerJacLIDs( const std::vector< std::vector<int> > & jacLIDVec )
922 {
923  DeviceInstance::registerJacLIDs( jacLIDVec );
924 
925  APosEquPosNodeOffset = jacLIDVec[0][0];
926  APosEquNegNodeOffset = jacLIDVec[0][1];
927  ANegEquPosNodeOffset = jacLIDVec[1][0];
928  ANegEquNegNodeOffset = jacLIDVec[1][1];
929 
930  if (ICGiven)
931  {
932  APosEquBraNodeOffset = jacLIDVec[0][2];
933  ANegEquBraNodeOffset = jacLIDVec[1][2];
934  ABraEquPosNodeOffset = jacLIDVec[2][0];
935  ABraEquNegNodeOffset = jacLIDVec[2][1];
936  ABraEquBraNodeOffset = jacLIDVec[2][2];
937  }
938  // set offsets if we have a solution-variable dependent C
939  if (solVarDepC)
940  {
941  int depVarsBaseIndex = 2;
942  if (ICGiven)
943  {
944  depVarsBaseIndex=3;
945  }
946 
949 
950  for ( int i=0; i<expNumVars; ++i)
951  {
952  APosEquDepVarOffsets[i] = jacLIDVec[0][depVarsBaseIndex+i];
953  ANegEquDepVarOffsets[i] = jacLIDVec[1][depVarsBaseIndex+i];
954  }
955  }
956 
957  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
958  {
959  dout() << "Capacitor " << getName() << " Instance::registerJacLIDs"
960  //<< Util::push << std::endl
961  << std::endl
962  << "APosEquPosNodeOffset: " << APosEquPosNodeOffset << std::endl
963  << "APosEquNegNodeOffset: " << APosEquNegNodeOffset << std::endl
964  << "ANegEquPosNodeOffset: " << ANegEquPosNodeOffset << std::endl
965  << "ANegEquNegNodeOffset: " << ANegEquNegNodeOffset << std::endl
966  << "APosEquBraNodeOffset: " << APosEquBraNodeOffset << std::endl
967  << "ANegEquBraNodeOffset: " << ANegEquBraNodeOffset << std::endl
968  << "ABraEquPosNodeOffset: " << ABraEquPosNodeOffset << std::endl
969  << "ABraEquNegNodeOffset: " << ABraEquNegNodeOffset << std::endl
970  << "ABraEquBraNodeOffset: " << ABraEquBraNodeOffset << std::endl;
971  if (solVarDepC)
972  {
973  for ( int i=0; i<expNumVars; ++i)
974  {
975  dout() << "APosEquDepVarOffsets["<<i<<"]: " << APosEquDepVarOffsets[i] << std::endl
976  << "ANegEquDepVarOffsets["<<i<<"]: " << ANegEquDepVarOffsets[i] << std::endl;
977  }
978  }
979  //dout() << Util::pop << std::endl;
980  dout() << std::endl;
981  }
982 }
983 
984 //-----------------------------------------------------------------------------
985 // Function : Instance::setupPointers
986 // Purpose :
987 // Special Notes :
988 // Scope : public
989 // Creator : Eric Keiter, SNL
990 // Creation Date : 11/30/08
991 //-----------------------------------------------------------------------------
992 ///
993 /// Setup direct access pointer to solution matrix and vectors.
994 ///
995 /// @see Xyce::Device::Capacitor::Instance::registerJacLIDs
996 ///
997 /// As an alternative to the row offsets defined in registerJacLIDs, it
998 /// is also possible to obtain direct pointers of the Jacobian elements.
999 ///
1000 /// This method uses the offsets obtained in registerJacLIDs to retrieve
1001 /// the pointers.
1002 ///
1003 /// In the resistor device the pointers to the matrix are only saved
1004 /// (and are only used for matrix access) if
1005 /// Xyce_NONPOINTER_MATRIX_LOAD is NOT defined at compile time. For
1006 /// some devices the use of pointers instead of array indexing can be
1007 /// a performance enhancement.
1008 ///
1009 /// Use of pointers in this device is disabled by defining
1010 /// Xyce_NONPOINTER_MATRIX_LOAD at compile time. When disabled, array
1011 /// indexing with the offsets from registerJacLIDs is used in
1012 /// the matrix load methods.
1013 ///
1014 /// @author Eric Keiter, SNL
1015 /// @date 11/30/08
1017 {
1018 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
1019  Linear::Matrix & dFdx = *(extData.dFdxMatrixPtr);
1020  Linear::Matrix & dQdx = *(extData.dQdxMatrixPtr);
1021 
1026 
1027  if (solVarDepC)
1028  {
1031 
1032  for (int i=0; i<expNumVars; ++i)
1033  {
1036  }
1037  }
1038 
1039  // there are no contributions to the dFdx matrix from dependent C's, so
1040  // we don't bother with those pointers.
1041 
1042  if (ICGiven)
1043  {
1049  }
1050 #endif
1051 }
1052 
1053 //-----------------------------------------------------------------------------
1054 // Function : Instance::updatePrimaryState
1055 // Purpose :
1056 // Special Notes :
1057 // Scope : public
1058 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1059 // Creation Date : 01/29/01
1060 //-----------------------------------------------------------------------------
1061 ///
1062 /// Update the state variables.
1063 ///
1064 /// @return true on success
1065 ///
1066 /// The capacitor's state variables are used to store the charge on
1067 /// the capacitor. In the case of a constant capacitance the charge
1068 /// is \f$q_0=CV\f$, but the computation is much more complex if the
1069 /// capacitance is variable.
1070 ///
1071 /// @note This method is called by the default implementation of the
1072 /// loadState master function. While the Capacitor class reimplements
1073 /// the "Master" "loadState" function that loads the contributions
1074 /// from all capacitor devices in a single loop, because this method
1075 /// is so complicated for the case of solution-dependent capacitances,
1076 /// the overloaded method falls back on this function in that case.
1077 ///
1078 /// @note Even though this method IS called in some cases, note that it does
1079 /// NOT call updateIntermediateVars as other device updatePrimaryState methods
1080 /// do. The capacitor device doesn't actually *HAVE* an updateIntermediateVars
1081 /// method, and all the hard work is done either in the Master class
1082 /// updateState function directly for the simple, constant-capacitance
1083 /// case, or here, for the solution-variable-dependent-capacitance case.
1084 ///
1085 /// @see Xyce::Device::Capacitor::Master::updateState
1086 ///
1087 /// @author Eric Keiter, SNL, Parallel Computational Sciences
1088 /// @date 01/29/01
1089 ///
1091 {
1092  double * solVec = extData.nextSolVectorRawPtr;
1093  double * staVec = extData.nextStaVectorRawPtr;
1094  double v_pos = solVec[li_Pos];
1095  double v_neg = solVec[li_Neg];
1096 
1097  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1098  {
1099  dout() << " ----------------------------------" << std::endl;
1100  dout() << "Instance::updatePrimaryState:" << std::endl;
1101  }
1102 
1103  vcap = v_pos-v_neg;
1104 
1105  if( getSolverState().dcopFlag && ICGiven ) vcap = IC;
1106 
1107  if (!solVarDepC)
1108  {
1109  // Obtain the "current" value for the charge stored in the capacitor.
1110  q0 = C*vcap;
1111  staVec[li_QState] = q0;
1112  }
1113  else
1114  {
1115  // The capacitance depends on solution variables, the work load just
1116  // went up.
1117 
1118  // here, we're just calling evaluate
1119  // to get the derivatives of C, and discarding the actual value
1120  // of C (which has already been stored)
1121  double junk;
1122  expPtr->evaluate(junk,expVarDerivs);
1123 
1124 
1125  // At DC, the charge really still is V*C.
1126  if (getSolverState().dcopFlag)
1127  {
1128  q0 = vcap*C;
1129  // dQ/dX is just dC/dX*vcap
1130  for (int i=0;i<expNumVars; ++i)
1131  {
1132  expVarDerivs[i] *= vcap;
1133  }
1134  }
1135  else
1136  {
1137  ///
1138  /// For solution-variable dependent cap in transient, we can't
1139  /// use the expression \f$q_0=CV\f$ because the capacitance is
1140  /// actually dQ/dV, not Q/V. We must integrate CdV to get the
1141  /// charge. We approximate this by incrementally adding
1142  /// C'*deltaV as V changes. C' is the average capacitance
1143  /// between this and the previous step. Using the average
1144  /// assures charge conservation, at least when C is a function
1145  /// of vcap alone.
1146  ///
1147  double * oldstaVector = extData.currStaVectorRawPtr;
1148  double oldC;
1149  double oldVcap;
1150  q0=oldstaVector[li_QState];
1151  oldC=oldstaVector[li_capState];
1152  oldVcap=oldstaVector[li_vcapState];
1153 
1154  q0 += 0.5*(oldC+C)*(vcap-oldVcap);
1155 
1156  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1157  {
1158  dout() << " Derivatives of C w.r.t variables: " << std::endl;
1159  for (int i=0;i<expNumVars;++i)
1160  {
1161  dout() << " expVarDerivs[ "<< i << " ] = " << expVarDerivs[i] << std::endl;
1162  }
1163  }
1164  ///
1165  /// When C is not a function of vcap alone, we have additional derivative
1166  /// terms that must also be integrated for proper computation of
1167  /// all dQdx entries.
1168  ///
1169  // If expressions contain the "ddt" (time differentiation)
1170  // function, everything becomes harder. So for now, we're going
1171  // to disallow use of ddt in C, so we don't have to deal with
1172  // that added complexity. This restriction is enforced in the
1173  // constructor, where we throw a fatal error if the user gives
1174  // us a ddt-dependent C. This code is NOT sufficient if ddt is allowed
1175  // in capacitance expressions.
1176  //
1177  // Now we have some trickiness because we are integrating CdV to get Q.
1178  // In order to get dQ/dX we have two cases:
1179  // X is one of our capacitor's voltage nodes: dQ/dX = C or -C depending
1180  // on whether X is the pos or negative node
1181  // X is NOT one of our nodes: dQ/dX = integral( dC/dX *dV)
1182 
1183  // For now, because we don't have an easy way to tell which of our
1184  // expression nodes is which, we'll just calculate all the dC/dX and dQ/dX
1185  // the same way. When it comes time to assemble the jacobian, we'll use
1186  // the node/equation offsets to know when to skip adding in this component.
1187 
1188  // The logic here is similar to the computation of the charge itself.
1189  // We'll use "expVarDerivs" to hold the final dQ/dX values.
1190 
1191 
1192  // Need to save the dC/dX value for next step.
1193  for (int i=0;i<expNumVars; ++i)
1194  {
1195  staVec[li_dCdXState[i]] = expVarDerivs[i];
1196  }
1197 
1198  // we have to integrate
1199 
1200  // dQ/dx = olddQdX + .5*(olddCdX+newdCdX)*(vcap-oldvcap)
1201 
1202  for (int i=0; i< expNumVars; ++i)
1203  {
1204  expVarDerivs[i] = oldstaVector[li_dQdXState[i]]
1205  + 0.5*(oldstaVector[li_dCdXState[i]]+expVarDerivs[i])*
1206  (vcap-oldstaVector[li_vcapState]);
1207 
1208  }
1209  }
1210  // Regardless of whether it's dcop or not, expVarDerivs now contains
1211  // dQ/dX for all the X's. It's WRONG if X is one of our voltage nodes,
1212  // so we have to be careful not to use it in that case. This logic
1213  // is handled down in loadDAEdQdx
1214  // Save to state:
1215  for (int i=0;i<expNumVars; ++i)
1216  {
1217  staVec[li_dQdXState[i]] = expVarDerivs[i];
1218  }
1219 
1220 
1221 
1222  staVec[li_QState] = q0;
1223  staVec[li_vcapState]=vcap;
1224  staVec[li_capState]=C;
1225  }
1226  return true;
1227 }
1228 
1229 
1230 //-----------------------------------------------------------------------------
1231 // Function : Instance::loadDAEQVector
1232 //
1233 // Purpose : Loads the Q-vector contributions for a single
1234 // capacitor instance.
1235 //
1236 // Special Notes : The "Q" vector is part of a standard DAE formalism in
1237 // which the system of equations is represented as:
1238 //
1239 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
1240 //
1241 // Scope : public
1242 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1243 // Creation Date : 01/24/03
1244 //-----------------------------------------------------------------------------
1245 ///
1246 /// Load the DAE Q vector.
1247 ///
1248 /// @return true on success
1249 ///
1250 /// The Xyce DAE formulation solves the differential-algebraic
1251 /// equations \f$F(x)+dQ(x)/dt=0\f$ These are vector equations
1252 /// resulting from the modified nodal analysis of the circuit.
1253 ///
1254 /// This method loads the Q-vector contributions for a single capacitor
1255 /// instance.
1256 ///
1257 /// In this method, the offsets defined in registerLIDs are used to
1258 /// store the device's Q contributions into the Q vector.
1259 ///
1260 /// The Q vector is used for devices that store charge or magnetic
1261 /// energy. The capacitor is such a device
1262 ///
1263 /// @note This method is called by the default implementation of the
1264 /// loadDAEVectors master function. Since the capacitor class
1265 /// reimplements the "Master" "loadDAEVectors" function that loads the
1266 /// contributions from all capacitor devices in a single loop, THIS
1267 /// FUNCTION IS NOT ACTUALLY USED. The loadDAEQVector method is only
1268 /// called when a device class does not re-implement the master class.
1269 /// This can be a source of confusion when attempting to modify the Capacitor
1270 /// device, or any other device that reimplements the Master classes.
1271 ///
1272 /// @see Xyce::Device::Capacitor::Master::loadDAEVectors
1273 ///
1274 /// @author Eric Keiter, SNL, Parallel Computational Sciences
1275 /// @date 01/24/03
1277 {
1278  double * qVec = extData.daeQVectorRawPtr;
1279  qVec[li_Pos] += q0;
1280  qVec[li_Neg] += -q0;
1281  if( loadLeadCurrent )
1282  {
1283  double * storeLeadQ = extData.storeLeadCurrQCompRawPtr;
1284  storeLeadQ[li_store_dev_i] = q0;
1285 
1286  double * leadQ = extData.nextLeadCurrQCompRawPtr;
1287  leadQ[li_branch_data] = q0;
1288  }
1289 
1290 
1291  return true;
1292 }
1293 
1294 //-----------------------------------------------------------------------------
1295 // Function : Instance::loadDAEFVector
1296 //
1297 // Purpose : Loads the F-vector contributions for a single
1298 // capacitor instance.
1299 //
1300 // Special Notes : See the special notes for loadDAEFVector.
1301 //
1302 // For the capacitor this doesn't do anything, except in
1303 // the case of IC= being specified. In that case, then
1304 // some extra stuff is contributed that doesn't have time
1305 // derivatives.
1306 //
1307 // Scope : public
1308 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1309 // Creation Date : 01/24/03
1310 //-----------------------------------------------------------------------------
1311 ///
1312 /// Load the DAE F vector.
1313 ///
1314 /// @return true on success
1315 ///
1316 /// The Xyce DAE formulation solves the differential-algebraic
1317 /// equations \f$F(x)+dQ(x)/dt=0\f$ These are vector equations
1318 /// resulting from the modified nodal analysis of the circuit.
1319 ///
1320 /// This method loads the F-vector contributions for a single capacitor
1321 /// instance.
1322 ///
1323 /// In this method, the offsets defined in registerLIDs are used to
1324 /// store the device's F contributions into the F vector.
1325 ///
1326 /// The only time a capacitor adds anything to the F vector is in the
1327 /// DC phase of a computation if and only if an initial condition is given
1328 /// on the capacitor instance line.
1329 ///
1330 /// @note This method is called by the default implementation of the
1331 /// loadDAEVectors master function. Since the Capacitor class
1332 /// reimplements the "Master" "loadDAEVectors" function that loads the
1333 /// contributions from all capacitor devices in a single loop, THIS
1334 /// FUNCTION IS NOT ACTUALLY USED. The loadDAEFVector method is only
1335 /// called when a device class does not re-implement the master class.
1336 /// This can be a source of confusion when attempting to modify the Capacitor
1337 /// device, or any other device that reimplements the Master classes.
1338 ///
1339 /// @see Xyce::Device::Capacitor::Master::loadDAEVectors
1340 ///
1341 /// @author Eric Keiter, SNL, Parallel Computational Sciences
1342 /// @date 01/24/03
1344 {
1345  bool bsuccess = true;
1346  double Vpos = 0.0;
1347  double Vneg = 0.0;
1348  double v_tmp = 0.0;
1349  double * fVec = extData.daeFVectorRawPtr;
1350  if( loadLeadCurrent )
1351  {
1352  double * stoVec = extData.nextStoVectorRawPtr;
1353  stoVec[li_store_dev_i] = 0;
1354 
1355  double * leadF = extData.nextLeadCurrFCompRawPtr;
1356  leadF[li_branch_data] = 0;
1357 
1358  double * junctionV = extData.nextJunctionVCompRawPtr;
1359  double * solVec = extData.nextSolVectorRawPtr;
1360  junctionV[li_branch_data] = solVec[li_Pos] - solVec[li_Neg];
1361  }
1362 
1363 
1364  if (ICGiven && getSolverState().dcopFlag)
1365  {
1366  // If we're doing the operating point and we have an initial condition,
1367  // get the current from the branch equation
1368  Vpos = (*extData.nextSolVectorPtr)[li_Pos];
1369  Vneg = (*extData.nextSolVectorPtr)[li_Neg];
1370 
1371  // load current into the F vector
1372  fVec[li_Pos] += (*extData.nextSolVectorPtr)[li_Bra];
1373  fVec[li_Neg] += -(*extData.nextSolVectorPtr)[li_Bra];
1374 
1375  if( loadLeadCurrent )
1376  {
1377  double * stoVec = extData.nextStoVectorRawPtr;
1379  }
1380  }
1381 
1382  // Initial condition stuff.
1383  v_tmp=0;
1384  if (ICGiven && getSolverState().dcopFlag)
1385  {
1386  v_tmp= (Vpos-Vneg-IC);
1387  }
1388 
1389  // Do this whenever there's a Branch equation, but only if there is one.
1390  // We'll be using 0 if we're not the OP.
1391  if (ICGiven)
1392  {
1393  fVec[li_Bra] += v_tmp;
1394  }
1395 
1396  return bsuccess;
1397 }
1398 
1399 //-----------------------------------------------------------------------------
1400 // Function : Instance::loadDAEdQdx
1401 //
1402 // Purpose : Loads the dQdx-matrix contributions for a single
1403 // capacitor instance.
1404 //
1405 // Special Notes : The "Q" vector is part of a standard DAE formalism in
1406 // which the system of equations is represented as:
1407 //
1408 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
1409 //
1410 // Scope : public
1411 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1412 // Creation Date : 03/05/04
1413 //-----------------------------------------------------------------------------
1414 ///
1415 /// Load the DAE the derivative of the Q vector with respect to the
1416 /// solution vector x, dFdx
1417 ///
1418 /// Loads the contributions for a single resistor instance to the
1419 /// dFdx matrix (the Q contribution to the Jacobian).
1420 ///
1421 /// This method uses the Jacobian LIDs (row offsets) that were stored by
1422 /// registerJacLIDs.
1423 ///
1424 /// @see Xyce::Device::Capacitor::Instance::registerJacLIDs
1425 ///
1426 /// @note This method is called by the default implementation of the
1427 /// loadDAEMatrices master function. Since the Capacitor class
1428 /// reimplements the "Master" "loadDAEMatrices" function that loads the
1429 /// contributions from all capacitor devices in a single loop, THIS
1430 /// FUNCTION IS NOT ACTUALLY USED. The loadDAEdFdx method is only
1431 /// called when a device class does not re-implement the master class.
1432 /// This can be a source of confusion when attempting to modify the capacitor
1433 /// device, or any other device that reimplements the Master classes.
1434 ///
1435 /// @see Xyce::Device::Capacitor::Master::loadDAEMatrices
1436 ///
1437 /// @return true on success
1438 ///
1439 /// @author Eric Keiter, SNL, Parallel Computational Sciences
1440 /// @date 03/05/04
1442 {
1443  if (!(ICGiven&& getSolverState().dcopFlag))
1444  {
1445  Linear::Matrix & dQdx = *(extData.dQdxMatrixPtr);
1446  dQdx[li_Pos][APosEquPosNodeOffset] += C;
1447  dQdx[li_Pos][APosEquNegNodeOffset] -= C;
1448  dQdx[li_Neg][ANegEquPosNodeOffset] -= C;
1449  dQdx[li_Neg][ANegEquNegNodeOffset] += C;
1450 
1451 
1452  // Remember the comments in updatePrimaryState: expVarDerivs
1453  // contains dQ/dX, but they are only correct when X is not one of
1454  // our nodal voltages. If X *IS* one of our nodal voltages, dQ/dX
1455  // is either C or -C and is already handled above. We need only
1456  // do the stuff below for the dependencies on voltages that are
1457  // NOT our nodal voltages.
1458  if (solVarDepC)
1459  {
1460  for (int i=0; i< expNumVars; ++i)
1461  {
1464  {
1465  dQdx[li_Pos][APosEquDepVarOffsets[i]] += expVarDerivs[i];
1466  }
1469  {
1470  dQdx[li_Neg][ANegEquDepVarOffsets[i]] -= expVarDerivs[i];
1471  }
1472  }
1473  }
1474 
1475  }
1476  return true;
1477 }
1478 
1479 //-----------------------------------------------------------------------------
1480 // Function : Instance::loadDAEdFdx ()
1481 //
1482 // Purpose : Loads the F-vector contributions for a single
1483 // capacitor instance.
1484 //
1485 // Special Notes : See the special notes for loadDAEFVector.
1486 //
1487 // For the capacitor this doesn't do anything, unless IC=
1488 // has been specified for an initial condition. Then,
1489 // there are extra equations that do not contain time
1490 // derivatives.
1491 //
1492 // Scope : public
1493 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1494 // Creation Date : 03/05/04
1495 //-----------------------------------------------------------------------------
1496 ///
1497 /// Load the DAE the derivative of the F vector with respect to the
1498 /// solution vector x, dFdx
1499 ///
1500 /// Loads the contributions for a single capacitor instance to the
1501 /// dFdx matrix (the F contribution to the Jacobian).
1502 ///
1503 /// This method uses the Jacobian LIDs (row offsets) that were stored by
1504 /// registerJacLIDs.
1505 ///
1506 /// @see Xyce::Device::Capacitor::Instance::registerJacLIDs
1507 ///
1508 /// The capacitor only loads the dFdx matrix when an initial condition is
1509 /// given on the instance line for the device.
1510 ///
1511 /// @note This method is called by the default implementation of the
1512 /// loadDAEMatrices master function. Since the Capacitor class
1513 /// reimplements the "Master" "loadDAEMatrices" function that loads the
1514 /// contributions from all capacitor devices in a single loop, THIS
1515 /// FUNCTION IS NOT ACTUALLY USED. The loadDAEdFdx method is only
1516 /// called when a device class does not re-implement the master class.
1517 /// This can be a source of confusion when attempting to modify the Capacitor
1518 /// device, or any other device that reimplements the Master classes.
1519 ///
1520 /// @see Xyce::Device::Capacitor::Master::loadDAEMatrices
1521 ///
1522 /// @return true on success
1523 ///
1524 /// @author Eric Keiter, SNL, Parallel Computational Sciences
1525 /// @date 03/05/04
1527 {
1528  Linear::Matrix & dFdx = *(extData.dFdxMatrixPtr);
1529 
1530  if (ICGiven && getSolverState().dcopFlag)
1531  {
1532  // Special Jacobian if we're doing operating point when IC given
1533  dFdx[li_Pos][APosEquBraNodeOffset] += 1.0;
1534  dFdx[li_Neg][ANegEquBraNodeOffset] += -1.0;
1535  dFdx[li_Bra][ABraEquPosNodeOffset] += 1.0;
1536  dFdx[li_Bra][ABraEquNegNodeOffset] += -1.0;
1537  }
1538  else
1539  {
1540  if (ICGiven)
1541  dFdx[li_Bra][ABraEquBraNodeOffset] += 1.0;
1542  }
1543 
1544  return true;
1545 }
1546 
1547 //-----------------------------------------------------------------------------
1548 // Function : Instance::setIC
1549 // Purpose :
1550 // Special Notes :
1551 // Scope : public
1552 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
1553 // Creation Date : 01/10/02
1554 //-----------------------------------------------------------------------------
1556 {
1557  double Vic;
1558  double Vpos, Vneg;
1559  double * nextStaVector = extData.nextStaVectorRawPtr;
1560  double * currStaVector = extData.currStaVectorRawPtr;
1561 
1562  double * nextSolVector = extData.nextSolVectorRawPtr;
1563  double * currSolVector = extData.currSolVectorRawPtr;
1564 
1565  if (ICGiven)
1566  {
1567  Vic = IC;
1568  q0 = C*Vic;
1569 
1570  currStaVector[li_QState] = q0;
1571  nextStaVector[li_QState] = q0;
1572 
1573  Vneg = currSolVector[li_Neg];
1574  Vpos = Vneg + Vic;
1575 
1576  currSolVector[li_Pos] = Vpos;
1577  nextSolVector[li_Pos] = Vpos;
1578  currSolVector[li_Neg] = -Vpos;
1579  nextSolVector[li_Neg] = -Vpos;
1580  }
1581 
1582  return true;
1583 }
1584 
1585 //-----------------------------------------------------------------------------
1586 // Function : Instance::varTypes
1587 // Purpose :
1588 // Special Notes :
1589 // Scope : public
1590 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
1591 // Creation Date : 02/17/04
1592 //-----------------------------------------------------------------------------
1593 void Instance::varTypes( std::vector<char> & varTypeVec )
1594 {
1595  if (ICGiven)
1596  {
1597  varTypeVec.resize(1);
1598  varTypeVec[0] = 'I';
1599  }
1600 }
1601 
1602 // Class Model
1603 
1604 //-----------------------------------------------------------------------------
1605 // Function : Model::processParams
1606 // Purpose :
1607 // Special Notes :
1608 // Scope : public
1609 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1610 // Creation Date : 6/03/02
1611 //-----------------------------------------------------------------------------
1612 ///
1613 /// Process model parameters
1614 ///
1615 /// @return true on success
1616 ///
1617 /// @author Eric Keiter, SNL, Parallel Computational Sciences
1618 /// @date 6/03/02
1620 {
1621 
1622  if (!tnomGiven)
1624 
1625  // If there are any time dependent parameters, set their values for
1626  // the current time.
1627 
1628  return true;
1629 }
1630 
1631 //----------------------------------------------------------------------------
1632 // Function : Model::processInstanceParams
1633 // Purpose :
1634 // Special Notes :
1635 // Scope : public
1636 // Creator : Dave Shirely, PSSI
1637 // Creation Date : 03/23/06
1638 //----------------------------------------------------------------------------
1639 ///
1640 /// Process the instance parameters of instance owned by this model
1641 ///
1642 /// This method simply loops over all instances associated with this
1643 /// model and calls their processParams method.
1644 ///
1645 /// @return true
1646 ///
1647 /// @author Dave Shirely, PSSI
1648 /// @date 03/23/06
1650 {
1651 
1652  std::vector<Instance*>::iterator iter;
1653  std::vector<Instance*>::iterator first = instanceContainer.begin();
1654  std::vector<Instance*>::iterator last = instanceContainer.end();
1655 
1656  for (iter=first; iter!=last; ++iter)
1657  {
1658  (*iter)->processParams();
1659  }
1660 
1661  return true;
1662 }
1663 
1664 //-----------------------------------------------------------------------------
1665 // Function : Model::Model
1666 // Purpose : model block constructor
1667 // Special Notes :
1668 // Scope : public
1669 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1670 // Creation Date : 5/17/00
1671 //-----------------------------------------------------------------------------
1672 ///
1673 /// Construct a capacitor model from a "model block" that was created
1674 /// by the netlist parser.
1675 ///
1676 /// @param configuration
1677 /// @param model_block
1678 /// @param factory_block
1679 ///
1680 /// @author Eric Keiter, SNL, Parallel Computational Sciences
1681 /// @date 5/17/00
1683  const Configuration & configuration,
1684  const ModelBlock & model_block,
1685  const FactoryBlock & factory_block)
1686  : DeviceModel(model_block, configuration.getModelParameters(), factory_block),
1687  capacitanceMultiplier(1.0),
1688  cj(0.0),
1689  cjsw(0.0),
1690  defWidth(10e-6),
1691  narrow(0),
1692  tempCoeff1(0.0),
1693  tempCoeff2(0.0),
1694  tnom(getDeviceOptions().tnom),
1695  tnomGiven(0)
1696 {
1697 
1698  // Set params to constant default values :
1699  setDefaultParams ();
1700 
1701  // Set params according to .model line and constant defaults from metadata:
1702  setModParams(model_block.params);
1703 
1704  // Set any non-constant parameter defaults:
1705  if (!given("TNOM"))
1707 
1708  // Calculate any parameters specified as expressions:
1709 
1711 
1712  // calculate dependent (ie computed) params and check for errors:
1713 
1714  processParams ();
1715 }
1716 
1717 //-----------------------------------------------------------------------------
1718 // Function : Model::Model
1719 // Purpose : destructor
1720 // Special Notes :
1721 // Scope : public
1722 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1723 // Creation Date : 3/16/00
1724 //-----------------------------------------------------------------------------
1725 
1727 {
1728  std::vector<Instance*>::iterator iter;
1729  std::vector<Instance*>::iterator first = instanceContainer.begin();
1730  std::vector<Instance*>::iterator last = instanceContainer.end();
1731 
1732  for (iter=first; iter!=last; ++iter)
1733  {
1734  delete (*iter);
1735  }
1736 
1737 }
1738 
1739 //-----------------------------------------------------------------------------
1740 // Function : Model::printOutInstances
1741 // Purpose : debugging tool.
1742 // Special Notes :
1743 // Scope : public
1744 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1745 // Creation Date : 4/03/00
1746 //-----------------------------------------------------------------------------
1747 
1748 std::ostream &Model::printOutInstances(std::ostream &os) const
1749 {
1750  std::vector<Instance*>::const_iterator iter;
1751  std::vector<Instance*>::const_iterator first = instanceContainer.begin();
1752  std::vector<Instance*>::const_iterator last = instanceContainer.end();
1753 
1754  int i,isize;
1755 
1756  isize = instanceContainer.size();
1757  os << std::endl;
1758  os << "Number of capacitor instances: " << isize << std::endl;
1759  os << " name\t\tmodelName\tParameters" << std::endl;
1760 
1761  for (i = 0, iter = first; iter != last; ++iter, ++i)
1762  {
1763  os << " " << i << ": " << (*iter)->getName() << "\t";
1764  os << getName();
1765  os << "\t\tC = " << (*iter)->C;
1766  os << "\tIC = " << (*iter)->IC;
1767  os << std::endl;
1768  }
1769 
1770  os << std::endl;
1771 
1772  return os;
1773 }
1774 
1775 //-----------------------------------------------------------------------------
1776 // Function : Model::forEachInstance
1777 // Purpose :
1778 // Special Notes :
1779 // Scope : public
1780 // Creator : David Baur
1781 // Creation Date : 2/4/2014
1782 //-----------------------------------------------------------------------------
1783 /// Apply a device instance "op" to all instances associated with this
1784 /// model
1785 ///
1786 /// @param[in] op Operator to apply to all instances.
1787 ///
1788 ///
1789 void Model::forEachInstance(DeviceInstanceOp &op) const /* override */
1790 {
1791  for (std::vector<Instance *>::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
1792  op(*it);
1793 }
1794 
1795 
1796 // Capacitor Master functions:
1797 
1798 //-----------------------------------------------------------------------------
1799 // Function : Master::updateState
1800 // Purpose :
1801 // Special Notes :
1802 // Scope : public
1803 // Creator : Eric Keiter, SNL
1804 // Creation Date : 11/26/08
1805 //-----------------------------------------------------------------------------
1806 ///
1807 /// Update state for all capacitor instances, regardless of model.
1808 ///
1809 /// @param solVec solution vector
1810 /// @param staVec state vector
1811 /// @param stoVec store vector
1812 ///
1813 /// @return true on success
1814 ///
1815 /// @note Because the capacitor device re-implements the base-class
1816 /// Master::updateState, the Instance::updatePrimaryState method is never
1817 /// called, nor is the Instance::updateIntermediateVars method. This method
1818 /// replaces those, and does the same work but inside a loop over all
1819 /// capacitor instances.
1820 ///
1821 /// Because the computation of state variables is so complex in the
1822 /// event that the capacitance is given by an expression that depends
1823 /// on solution variables, this method falls back on calling the
1824 /// instance's updatePrimaryState method instead of reimplementing the
1825 /// computation here.
1826 ///
1827 /// @see Xyce::Device::Capacitor::Instance::updatePrimaryState
1828 /// @author Eric Keiter, SNL
1829 /// @date 11/26/08
1830 bool Master::updateState (double * solVec, double * staVec, double * stoVec)
1831 {
1832  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
1833  {
1834  Instance & ci = *(*it);
1835 
1836  double v_pos = solVec[ci.li_Pos];
1837  double v_neg = solVec[ci.li_Neg];
1838  ci.vcap = v_pos-v_neg;
1839 
1840  if( getSolverState().dcopFlag && ci.ICGiven )
1841  {
1842  ci.vcap = ci.IC;
1843  }
1844 
1845  if (!ci.solVarDepC)
1846  {
1847  // Obtain the "current" value for the charge stored in the capacitor.
1848  ci.q0 = ci.C * ci.vcap;
1849  staVec[ci.li_QState] = ci.q0;
1850  }
1851  else
1852  {
1853  // fall back on old pre-turbo scheme
1854  bool tmpBool=true;
1855  tmpBool = ci.updatePrimaryState ();
1856  }
1857  }
1858 
1859  return true;
1860 }
1861 
1862 //-----------------------------------------------------------------------------
1863 // Function : Master::loadDAEVectors
1864 // Purpose :
1865 // Special Notes :
1866 // Scope : public
1867 // Creator : Eric Keiter, SNL
1868 // Creation Date : 11/26/08
1869 //-----------------------------------------------------------------------------
1870 ///
1871 /// Load DAE vectors of all capacitor instances, regardless of model
1872 ///
1873 /// @param solVec solution vector
1874 /// @param fVec f vector
1875 /// @param qVec q vector
1876 /// @param storeLeadF store lead current f vector
1877 /// @param storeLeadQ store lead current q vector
1878 ///
1879 /// @return true on success
1880 ///
1881 /// @note Because the capacitor device re-implements the base-class
1882 /// Master::loadDAEVectors, the Instance::loadDAEFVector method is
1883 /// never called. This method replaces those, and does the same work
1884 /// but inside a loop over all capacitor instances.
1885 ///
1886 /// @see Xyce::Device::Capacitor::Instance::loadDAEFVector
1887 ///
1888 /// @author Eric Keiter, SNL
1889 /// @date 11/26/08
1890 bool Master::loadDAEVectors (double * solVec, double * fVec, double *qVec, double * bVec, double * storeLeadF, double * storeLeadQ, double * leadF, double * leadQ, double * junctionV)
1891 {
1892 
1893  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1894  {
1895  dout() << " ----------------------------------" << std::endl;
1896  dout() << " Master::loadDAEVectors: " << std::endl;
1897  }
1898 
1899  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
1900  {
1901  Instance & ci = *(*it);
1902  if (ci.ICGiven)
1903  {
1904  double Vpos (0.0), Vneg (0.0), v_tmp (0.0);
1905 
1906  // Initial condition
1907  if (getSolverState().dcopFlag)
1908  {
1909  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1910  {
1911  dout() << " loading dcop F vector for cap " << ci.getName() << ":" << std::endl;
1912  }
1913  // If doing the DCOP and have IC=, get current from branch equation
1914  // ci.i0 = solVec[ci.li_Bra]; moved to CapacitorMaster::updateState() where stovec is passed in.
1915  Vpos = solVec[ci.li_Pos];
1916  Vneg = solVec[ci.li_Neg];
1917  fVec [ci.li_Pos] += solVec[ci.li_Bra];
1918  fVec [ci.li_Neg] += -solVec[ci.li_Bra];
1919 
1920  if( ci.loadLeadCurrent )
1921  {
1922  storeLeadF[ci.li_store_dev_i] = solVec[ci.li_Bra];
1923  }
1924 
1925  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1926  {
1927  dout() << " f[ " << ci.li_Pos << " ] += " << solVec[ci.li_Bra]<< std::endl;
1928  dout() << " f[ " << ci.li_Neg << " ] += " << -solVec[ci.li_Bra] << std::endl;
1929  }
1930 
1931  v_tmp= (Vpos-Vneg-ci.IC);
1932  }
1933 
1934  // Do this only if there's a Branch equation
1935  fVec[ci.li_Bra] += v_tmp;
1936 
1937  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1938  {
1939  dout() << " f[ " << ci.li_Bra << " ] += " << v_tmp << std::endl;
1940  }
1941  }
1942 
1943  qVec[ci.li_Pos] += ci.q0;
1944  qVec[ci.li_Neg] += -ci.q0;
1945 
1946  if( ci.loadLeadCurrent )
1947  {
1948  storeLeadQ[ci.li_store_dev_i] = ci.q0;
1949  storeLeadF[ci.li_store_dev_i] = 0;
1950  leadF[ci.li_branch_data] = 0;
1951  leadQ[ci.li_branch_data] = ci.q0;
1952  junctionV[ci.li_branch_data] = solVec[ci.li_Pos] - solVec[ci.li_Neg];
1953 
1954  }
1955 
1956  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1957  {
1958  dout() << " loading Q vector for cap " << ci.getName() << ":" << std::endl;
1959  dout() << " q[ " << ci.li_Pos << " ] += " << ci.q0 << std::endl;
1960  dout() << " q[ " << ci.li_Neg << " ] += " << -ci.q0 << std::endl;
1961 
1962  }
1963 
1964  }
1965  return true;
1966 }
1967 
1968 //-----------------------------------------------------------------------------
1969 // Function : Master::loadDAEMatrices
1970 // Purpose :
1971 // Special Notes :
1972 // Scope : public
1973 // Creator : Eric Keiter, SNL
1974 // Creation Date : 11/26/08
1975 //-----------------------------------------------------------------------------
1976 ///
1977 /// Load DAE matrices for all capacitor instances, regardless of model
1978 ///
1979 /// @param dFdx matrix of derivatives of F vector with respect to solution
1980 /// @param dQdx matrix of derivatives of Q vector with respect to solution
1981 ///
1982 /// @return true on success
1983 ///
1984 /// @note Because the capacitor device re-implements the base-class
1985 /// Master::loadDAEMatrices, the Instance::loadDAEdFdx method is
1986 /// never called. This method replaces those, and does the same work
1987 /// but inside a loop over all capacitor instances.
1988 ///
1989 /// @see Xyce::Device::Capacitor::Instance::loadDAEdFdx
1990 ///
1991 /// @author Eric Keiter, SNL
1992 /// @date 11/26/08
1993 bool Master::loadDAEMatrices (Linear::Matrix & dFdx, Linear::Matrix & dQdx)
1994 {
1995 
1996  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1997  {
1998  dout() << " ----------------------------------" << std::endl;
1999  dout() << " Master::loadDAEMatrices: " << std::endl;
2000  }
2001 
2002  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
2003  {
2004  Instance & ci = *(*it);
2005 
2006  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
2007  {
2008  dout() << " loads for capacitor " << ci.getName() << std::endl;
2009  }
2010 
2011  if (ci.ICGiven && getSolverState().dcopFlag)
2012  {
2013  // Special Jacobian if we're doing operating point when IC given
2014 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
2015  *(ci.fPosEquBraNodePtr) += 1.0;
2016  *(ci.fNegEquBraNodePtr) += -1.0;
2017  *(ci.fBraEquPosNodePtr) += 1.0;
2018  *(ci.fBraEquNegNodePtr) += -1.0;
2019 #else
2020  dFdx[ci.li_Pos][ci.APosEquBraNodeOffset] += 1.0;
2021  dFdx[ci.li_Neg][ci.ANegEquBraNodeOffset] += -1.0;
2022  dFdx[ci.li_Bra][ci.ABraEquPosNodeOffset] += 1.0;
2023  dFdx[ci.li_Bra][ci.ABraEquNegNodeOffset] += -1.0;
2024 #endif
2025  }
2026  else
2027  {
2028  if (ci.ICGiven)
2029  {
2030 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
2031  *(ci.fBraEquBraNodePtr) += 1.0;
2032 #else
2033  dFdx[ci.li_Bra][ci.ABraEquBraNodeOffset] += 1.0;
2034 #endif
2035  }
2036  }
2037 
2038  if (!(ci.ICGiven&& getSolverState().dcopFlag))
2039  {
2040 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
2041  *(ci.qPosEquPosNodePtr) += ci.C;
2042  *(ci.qPosEquNegNodePtr) -= ci.C;
2043  *(ci.qNegEquPosNodePtr) -= ci.C;
2044  *(ci.qNegEquNegNodePtr) += ci.C;
2045 
2046  if (ci.solVarDepC)
2047  {
2048  for (int i=0; i< ci.expNumVars; ++i)
2049  {
2050  // Similar to logic in loadDAEdQdX:
2051  if ((ci.qPosEquDepVarsPtrs[i] != ci.qPosEquPosNodePtr)
2052  && (ci.qPosEquDepVarsPtrs[i] != ci.qPosEquNegNodePtr))
2053  {
2054  *(ci.qPosEquDepVarsPtrs[i]) += ci.expVarDerivs[i];
2055  }
2056 
2057  if ((ci.qNegEquDepVarsPtrs[i] != ci.qNegEquPosNodePtr)
2058  && (ci.qNegEquDepVarsPtrs[i] != ci.qNegEquNegNodePtr))
2059  {
2060  *(ci.qNegEquDepVarsPtrs[i]) -= ci.expVarDerivs[i];
2061  }
2062  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
2063  {
2064  if ((ci.qPosEquDepVarsPtrs[i] != ci.qPosEquPosNodePtr)
2065  && (ci.qPosEquDepVarsPtrs[i] != ci.qPosEquNegNodePtr))
2066  {
2067  dout() << " q[pos][ " << ci.APosEquDepVarOffsets[i] << " ] += "
2068  << ci.expVarDerivs[i] << std::endl;
2069  }
2070  if ((ci.qNegEquDepVarsPtrs[i] != ci.qNegEquPosNodePtr)
2071  && (ci.qNegEquDepVarsPtrs[i] != ci.qNegEquNegNodePtr))
2072  {
2073  dout() << " q[neg][ " << ci.ANegEquDepVarOffsets[i] << " ] += "
2074  << ci.expVarDerivs[i] << std::endl;
2075  }
2076  }
2077 
2078  }
2079  }
2080 #else
2081  dQdx[ci.li_Pos][ci.APosEquPosNodeOffset] += ci.C;
2082  dQdx[ci.li_Pos][ci.APosEquNegNodeOffset] -= ci.C;
2083  dQdx[ci.li_Neg][ci.ANegEquPosNodeOffset] -= ci.C;
2084  dQdx[ci.li_Neg][ci.ANegEquNegNodeOffset] += ci.C;
2085 
2086  if (ci.solVarDepC)
2087  {
2088  for (int i=0; i< ci.expNumVars; ++i)
2089  {
2090  if ( (ci.APosEquDepVarOffsets[i] != ci.APosEquPosNodeOffset)
2091  && (ci.APosEquDepVarOffsets[i] != ci.APosEquNegNodeOffset))
2092  {
2093  dQdx[ci.li_Pos][ci.APosEquDepVarOffsets[i]] +=
2094  ci.expVarDerivs[i];
2095  }
2096  if ( (ci.ANegEquDepVarOffsets[i] != ci.ANegEquPosNodeOffset)
2097  && (ci.ANegEquDepVarOffsets[i] != ci.ANegEquNegNodeOffset))
2098  {
2099  dQdx[ci.li_Neg][ci.ANegEquDepVarOffsets[i]] -=
2100  ci.expVarDerivs[i];
2101  }
2102 
2103  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
2104  {
2105  if ( (ci.APosEquDepVarOffsets[i] != ci.APosEquPosNodeOffset)
2106  && (ci.APosEquDepVarOffsets[i] != ci.APosEquNegNodeOffset))
2107  {
2108  dout() << " q[pos][ " << ci.APosEquDepVarOffsets[i] << " ] += "
2109  << expVarDerivs[i] << std::endl;
2110  }
2111  if ( (ci.ANegEquDepVarOffsets[i] != ci.ANegEquPosNodeOffset)
2112  && (ci.ANegEquDepVarOffsets[i] != ci.ANegEquNegNodeOffset))
2113  {
2114  dout() << " q[neg][ " << ci.ANegEquDepVarOffsets[i] << " ] += "
2115  << ci.expVarDerivs[i] << std::endl;
2116  }
2117  }
2118  }
2119  }
2120 
2121 #endif
2122  }
2123  }
2124 
2125  return true;
2126 }
2127 
2128 //-----------------------------------------------------------------------------
2129 // Function : Xyce::Device::Capacitor::Traits::factory
2130 // Purpose :
2131 // Special Notes :
2132 // Scope : public
2133 // Creator : David Baur
2134 // Creation Date :
2135 //-----------------------------------------------------------------------------
2136 ///
2137 /// Create a new instance of the Capacitor device.
2138 ///
2139 /// @param configuration
2140 /// @param factory_block
2141 ///
2142 Device *
2143 Traits::factory(const Configuration &configuration, const FactoryBlock &factory_block)
2144 {
2145  return new Master(configuration, factory_block, factory_block.solverState_, factory_block.deviceOptions_);
2146 }
2147 
2148 //-----------------------------------------------------------------------------
2149 // Function : Xyce::Device::Capacitor::registerDevice
2150 // Purpose :
2151 // Special Notes :
2152 // Scope : public
2153 // Creator : David Baur
2154 // Creation Date :
2155 //-----------------------------------------------------------------------------
2156 ///
2157 /// Define how to use the device in a netlist.
2158 ///
2159 /// This method is called from the Xyce::Device::registerOpenDevices
2160 /// function, which in turn is called by the device manager.
2161 ///
2162 /// The device is declared here to be an "R" device, which may optionally
2163 /// take a model card of type "R". This device will correspond to model
2164 /// level 1 of capacitor models.
2166 {
2168  .registerDevice("c", 1)
2169  .registerModelType("c", 1)
2170  .registerModelType("cap", 1);
2171 }
2172 
2173 //-----------------------------------------------------------------------------
2174 // Function : capSensitivity::operator
2175 // Purpose : produces df/dp and dq/dp, where p=C.
2176 // Special Notes :
2177 // Scope : public
2178 // Creator : Eric Keiter, SNL
2179 // Creation Date : 7/31/2014
2180 //-----------------------------------------------------------------------------
2182  const ParameterBase &entity,
2183  const std::string & name,
2184  std::vector<double> & dfdp,
2185  std::vector<double> & dqdp,
2186  std::vector<double> & dbdp,
2187  std::vector<int> & Findices,
2188  std::vector<int> & Qindices,
2189  std::vector<int> & Bindices
2190  ) const
2191 {
2192  const ParameterBase * e1 = &entity;
2193  const Instance * in = dynamic_cast<const Instance *> (e1);
2194 
2195  double * solVec = in->extData.nextSolVectorRawPtr;
2196  double v_pos = solVec[in->li_Pos];
2197  double v_neg = solVec[in->li_Neg];
2198  double vcap = v_pos-v_neg;
2199 
2200  double dqdpLoc = vcap;
2201 
2202  dqdp.resize(2);
2203  dqdp[0] = +dqdpLoc;
2204  dqdp[1] = -dqdpLoc;
2205 
2206  Qindices.resize(2);
2207  Qindices[0] = in->li_Pos;
2208  Qindices[1] = in->li_Neg;
2209 }
2210 
2211 } // namespace Capacitor
2212 } // namespace Device
2213 } // namespace Xyce
const InstanceName & getName() const
bool loadDAEdQdx()
Load the DAE the derivative of the Q vector with respect to the solution vector x, dFdx.
virtual bool updateState(double *solVec, double *staVec, double *stoVec)
Update state for all capacitor instances, regardless of model.
const DeviceOptions & deviceOptions_
Descriptor & addPar(const char *parName, T default_value, T U::*varPtr)
Adds the parameter description to the parameter map.
Definition: N_DEV_Pars.h:1429
bool processParams()
Process model parameters.
Linear::Vector * nextSolVectorPtr
bool given(const std::string &parameter_name) const
Pure virtual class to augment a linear system.
Parameter may be specified as time dependent expression from netlist.
Definition: N_DEV_Pars.h:67
bool loadDAEQVector()
Load the DAE Q vector.
void addInternalNode(Util::SymbolTable &symbol_table, int index, const InstanceName &instance_name, const std::string &lead_name)
std::vector< Instance * > instanceContainer
bool processInstanceParams()
Process the instance parameters of instance owned by this model.
double baseCap
the baseline capacitance before aging
void setNumStoreVars(int num_store_vars)
void registerDevice()
Define how to use the device in a netlist.
void addBranchDataNode(Util::SymbolTable &symbol_table, int index, const InstanceName &instance_name, const std::string &lead_name)
Capacitor Master class.
void makeVector(const std::string &cname, int len)
Allows the parameter to be specified as a vector.
Definition: N_DEV_Pars.h:1597
InstanceVector::const_iterator getInstanceEnd() const
Returns an iterator to the ending of the vector of all instances created for this device...
Base class for all parameters.
Definition: N_DEV_Pars.h:169
const std::vector< Depend > & getDependentParams()
#define AssertLIDs(cmp)
virtual bool loadDAEVectors(double *solVec, double *fVec, double *qVec, double *bVec, double *storeLeadF, double *storeLeadQ, double *leadF, double *leadQ, double *junctionV)
Load DAE vectors of all capacitor instances, regardless of model.
virtual void registerJacLIDs(const JacobianStamp &jacLIDVec)
Instance(const Configuration &configuration, const InstanceBlock &instance_block, Model &model, const FactoryBlock &factory_block)
Construct a Capacitor model from a "model block" that was created by the netlist parser.
void registerStoreLIDs(const std::vector< int > &stoLIDVecRef)
Register the local store IDs.
bool updatePrimaryState()
Update the state variables.
double tnom
nominal temperature for device params.
std::vector< int > ANegEquDepVarOffsets
InstanceVector::const_iterator getInstanceBegin() const
Returns an iterator to the beginning of the vector of all instances created for this device...
std::vector< Param > params
Parameters from the line.
Capacitor Model class.
void setParams(const std::vector< Param > &params)
const std::string & getName() const
static Device * factory(const Configuration &configuration, const FactoryBlock &factory_block)
Create a new instance of the Capacitor device.
The FactoryBlock contains parameters needed by the device, instance and model creation functions...
void registerStateLIDs(const std::vector< int > &staLIDVecRef)
Register the local state IDs.
virtual void operator()(const ParameterBase &entity, const std::string &name, std::vector< double > &dfdp, std::vector< double > &dqdp, std::vector< double > &dbdp, std::vector< int > &Findices, std::vector< int > &Qindices, std::vector< int > &Bindices) const
const DeviceOptions & getDeviceOptions() const
static void loadInstanceParameters(ParametricData< Instance > &instance_parameters)
Loads the parameter definition into the instance parameter map.
bool loadDAEdFdx()
Load the DAE the derivative of the F vector with respect to the solution vector x, dFdx.
static void loadModelParameters(ParametricData< Model > &model_parameters)
Loads the parameter definition into the model parameter map.
void loadNodeSymbols(Util::SymbolTable &symbol_table) const
Populates and returns the store name map.
static capSensitivity capSens
static Config< T > & addConfiguration()
Adds the device to the Xyce device configuration.
Linear::Matrix * dFdxMatrixPtr
The Device class is an interface for device implementations.
Definition: N_DEV_Device.h:101
virtual void forEachInstance(DeviceInstanceOp &op) const
Apply a device instance "op" to all instances associated with this model.
const SolverState & solverState_
double q0
charge in the capacitor
int li_Bra
for the "voltage source" when IC is specified
Class Configuration contains device configuration data.
std::vector< int > APosEquDepVarOffsets
bool processParams()
Process parameters.
std::vector< double > expVarDerivs
void registerJacLIDs(const std::vector< std::vector< int > > &jacLIDVec)
Register the Jacobian local IDs.
std::vector< double * > qPosEquDepVarsPtrs
const std::vector< std::vector< int > > & jacobianStamp() const
Return Jacobian stamp that informs topology of the layout of the resistor jacobian.
const SolverState & getSolverState() const
bool updateTemperature(const double &temp_tmp)
Update the parameters that depend on the temperature of the device.
void setNumBranchDataVars(int num_branch_data_vars)
virtual std::ostream & printOutInstances(std::ostream &os) const
#define Xyce_NONPOINTER_MATRIX_LOAD
Definition: N_DEV_Bsrc.C:97
std::vector< std::vector< int > > jacStamp_IC
std::vector< std::vector< int > > jacStamp
std::vector< double * > qNegEquDepVarsPtrs
void setupPointers()
Setup direct access pointer to solution matrix and vectors.
ModelBlock represents a .MODEL line from the netlist.
Parameter may be specified as a solution dependent expression from netlist.
Definition: N_DEV_Pars.h:68
Manages parameter binding for class C.
Definition: N_DEV_Pars.h:214
InstanceBlock represent a device instance line from the netlist.
bool loadDAEFVector()
Load the DAE F vector.
double ageCoef
degradation coeficient.
Util::Param temp
operating temperature of ckt.
std::vector< Param > params
void registerBranchDataLIDs(const std::vector< int > &branchLIDVecRef)
Register the local store IDs.
Linear::Matrix * dQdxMatrixPtr
int li_branch_data
Index for lead current and junction voltage (for power calculations)
void registerLIDs(const std::vector< int > &intLIDVecRef, const std::vector< int > &extLIDVecRef)
Register local IDs.
const SolverState & getSolverState() const
Returns the solver state given during device construction.
void setModParams(const std::vector< Param > &params)
virtual bool loadDAEMatrices(Linear::Matrix &dFdx, Linear::Matrix &dQdx)
Load DAE matrices for all capacitor instances, regardless of model.
void varTypes(std::vector< char > &varTypeVec)