Xyce  6.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
N_DEV_Resistor.C
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // Copyright Notice
3 //
4 // Copyright 2002 Sandia Corporation. Under the terms
5 // of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S.
6 // Government retains certain rights in this software.
7 //
8 // Xyce(TM) Parallel Electrical Simulator
9 // Copyright (C) 2002-2014 Sandia Corporation
10 //
11 // This program is free software: you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation, either version 3 of the License, or
14 // (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 // ----------------------------------------------------------------------------
24 
25 //----------------------------------------------------------------------------
26 // Filename : $RCSfile: N_DEV_Resistor.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.229.2.3 $
40 //
41 // Revision Date : $Date: 2014/03/06 23:33:43 $
42 //
43 // Current Owner : $Author: tvrusso $
44 //----------------------------------------------------------------------------
45 #include <Xyce_config.h>
46 
47 #include <N_DEV_Resistor.h>
48 
49 #include <N_DEV_DeviceOptions.h>
50 #include <N_DEV_ExternData.h>
51 #include <N_DEV_Message.h>
52 
53 #include <N_LAS_Matrix.h>
54 
55 namespace Xyce {
56 namespace Device {
57 namespace Resistor {
58 
59 
60 ///
61 /// Common Jacobian Stamp for all Resistor devices.
62 /// Because all resistors have identical Jacobian stamps, this data is
63 /// declared static and is shared by all resistor instances.
64 ///
65 std::vector<std::vector<int> > Instance::jacStamp;
66 
67 //-----------------------------------------------------------------------------
68 // Function : Xyce::Device::Resistor::Instance::initializeJacobianStamp
69 // Purpose :
70 // Special Notes : Initialization of jacobian stamp moved from constructor
71 // in revision 1.227 of N_DEV_Resistor.C by David Baur.
72 // The code itself code was written by R. Hoekstra, 9/27/2002
73 // Scope : private
74 // Creator : David Baur
75 // Creation Date : 2/11/2014
76 //-----------------------------------------------------------------------------
77 ///
78 /// @brief Common Jacobian stamp initializer for all Resistor devices.
79 ///
80 /// The Jacobian stamp is a sparse-matrix representation of the pattern
81 /// of non-zero elements that a device will put into the Jacobian matrix.
82 ///
83 /// The Jacobian stamp is used by the Topology package to determine indices
84 /// into the full Jacobian matrix for elements that correspond to this
85 /// device.
86 ///
87 /// There is one row of the Jacobian stamp for each equation associated with
88 /// a device. The number of elements in a row are the number of non-zero
89 /// elements in that row of the device's contribution to the Jacobian.
90 /// The values of the elements are numbers local to the device that
91 /// represent the column in which the non-zero element appears.
92 ///
93 /// For the resistor, there are two external nodes (the positive and negative
94 /// terminals of the device). The positive node is referred to as the 0th
95 /// node of the device, and the negative node the 1st node.
96 /// Considering positive current flow from the positive node to the negative
97 /// node, current out of the positive node is \f$(V_+-V_-)*G\f$, and current
98 /// out of the negative node is \f$-(V_+-V_-)*G\f$. Thus, the Jacobian
99 /// matrix contribution for the resistor is:
100 /// \f[
101 /// \left[\begin{array}{cc}
102 /// G& -G\\
103 /// -G& G
104 /// \end{array}
105 /// \right] \f]
106 ///
107 /// This is a dense Jacobian with two rows. The first row is the row
108 /// for the positive node's KCL, the second row is the row for the
109 /// negative node KCL. Each row has two non-zero elements. The
110 /// columns correspond to the nodes of the device: the first column is
111 /// the positive node, the second the negative node. The element of
112 /// the jacobian is the dependence of the equation associated with the
113 /// row on the variable associated with the column.
114 ///
115 /// The Jacobian stamp therefore has two rows, and each row has two elements.
116 /// In this trivial device (because the matrix is small and fully dense),
117 /// the stamp values are 0 ("positive node") for the first nonzero in
118 /// each row, and 1 ("negative node") for the second nonzero.
119 ///
121 {
122  if (jacStamp.empty())
123  {
124  jacStamp.resize(2);
125  jacStamp[0].resize(2);
126  jacStamp[1].resize(2);
127  jacStamp[0][0] = 0;
128  jacStamp[0][1] = 1;
129  jacStamp[1][0] = 0;
130  jacStamp[1][1] = 1;
131  }
132 }
133 
134 //-----------------------------------------------------------------------------
135 // Function : Xyce::Device::Resistor::Traits::loadInstanceParameters
136 // Purpose :
137 // Special Notes : The addPar calls here were refactored and moved here
138 // from the instance constructor. Those addPars had been
139 // in place from 2/4/2005.
140 // Scope : private
141 // Creator : David Baur
142 // Creation Date : 1/27/2014
143 //-----------------------------------------------------------------------------
144 ///
145 /// Loads the parameter definition into the instance parameter map.
146 ///
147 /// @param p instance parameter map
148 ///
149 /// Each parameter supported by the resistor device instance is
150 /// defined via the addPar call. The minimum information required is
151 /// the name of the parameter, the default value, and a member pointer
152 /// to a variable in the instance class to which the value will be
153 /// assigned.
154 ///
155 /// Additional information such as documentation for the parameter, units
156 /// (used only in output of tables for documentation), whether a special
157 /// boolean should be set if the parameter is given, etc. may be specified
158 /// using the various set* calls of the Xyce::Device::Descriptor class.
159 ///
160 /// It is important to note that since parameters defined by addPar are
161 /// defined as metadata separate from any instance, it is not possible to
162 /// establish interrelationships between parameter defaults here. Parameter
163 /// defaults specified in addPar are always constants. If a device requires
164 /// that parameter defaults depend on values of other parameters, this has to
165 /// be done in the instance constructor. Examples of such parameters in this
166 /// device arethe "DTEMP" and "W" parameters, which are set to special defaults
167 /// at device instantiation time. Defaults for those parameters in the addPar
168 /// calls (and hence in the LaTeX tables in the reference guide produced from
169 /// this data) are misleading.
170 ///
172 {
173  p.addPar("R", 1000.0, &Resistor::Instance::R)
174  .setExpressionAccess(ParameterType::TIME_DEP)
175  .setUnit(U_OHM)
176  .setDescription("Resistance");
177  p.addPar("L", 0.0, &Resistor::Instance::length)
178  .setUnit(U_METER)
179  .setDescription("Length");
180  p.addPar("W", 0.0, &Resistor::Instance::width)
181  .setUnit(U_METER)
182  .setDescription("Width");
183  p.addPar("TEMP", 0.0, &Resistor::Instance::temp)
184  .setExpressionAccess(ParameterType::TIME_DEP)
185  .setUnit(U_DEGC)
186  .setDescription("Device temperature");
187 
188  p.addPar("TC1", 0.0, &Resistor::Instance::tempCoeff1)
189  .setGivenMember(&Resistor::Instance::tempCoeff1Given)
190  .setUnit(U_DEGCM1)
191  .setDescription("Linear Temperature Coefficient");
192  p.addPar("TC2", 0.0, &Resistor::Instance::tempCoeff2)
193  .setGivenMember(&Resistor::Instance::tempCoeff2Given)
194  .setUnit(U_DEGCM2)
195  .setDescription("Quadratic Temperature Coefficient");
196  p.makeVector("TC", 2); // Allow TC to be entered as a vector (TC=1,2)
197 
198  p.addPar("DTEMP", 0.0, &Resistor::Instance::dtemp)
199  .setGivenMember(&Resistor::Instance::dtempGiven)
200  .setUnit(U_DEGC)
201  .setDescription("Device Temperature -- For compatibility only. Parameter is NOT used");
202 }
203 
204 //-----------------------------------------------------------------------------
205 // Function : Xyce::Device::Resistor::Traits::loadModelParameters
206 // Purpose :
207 // Special Notes : The addPar calls here were refactored and moved here
208 // from the model constructor. Those addPars had been
209 // in place from 2/4/2005.
210 // Scope : private
211 // Creator : David Baur
212 // Creation Date : 1/27/2014
213 //-----------------------------------------------------------------------------
214 ///
215 /// Loads the parameter definition into the model parameter map.
216 ///
217 /// @param p model parameter map
218 ///
219 /// @see Xyce::Device::Resistor::Traits::loadInstanceParameters
220 ///
221 /// Resistors may optionally be given a model name to enable a semiconductor
222 /// resistor model with a sheet resistance. The resistance of an instance
223 /// is then determined by the length and width given on the instance line.
224 /// This loadModelParameters method defines the parameters that may be
225 /// specified on model cards associated with semiconductor resistors.
226 ///
228 {
229  // Create parameter definitions for parameter member variables
230  p.addPar("TC1", 0.0, &Resistor::Model::tempCoeff1)
231  .setUnit(U_DEGCM1)
232  .setDescription("Linear Temperature Coefficient");
233  p.addPar("TC2", 0.0, &Resistor::Model::tempCoeff2)
234  .setUnit(U_DEGCM2)
235  .setDescription("Quadratic Temperature Coefficient");
236  p.addPar("RSH", 0.0, &Resistor::Model::sheetRes)
237  .setUnit(U_OHM)
238  .setDescription("Sheet Resistance");
239  p.addPar("DEFW", 1.e-5, &Resistor::Model::defWidth)
240  .setUnit(U_METER)
241  .setDescription("Default Instance Width");
242  p.addPar("NARROW",0.0, &Resistor::Model::narrow)
243  .setUnit(U_METER)
244  .setDescription("Narrowing due to side etching");
245  p.addPar("TNOM", 0.0, &Resistor::Model::tnom)
246  .setUnit(U_DEGC)
247  .setDescription("Parameter Measurement Temperature");
248 }
249 
250 //-----------------------------------------------------------------------------
251 // Function : Xyce::Device::Resistor::Instance::Instance
252 // Purpose : Instance constructor
253 // Special Notes :
254 // Scope : public
255 // Creator : Eric Keiter
256 // Creation Date : 3/16/2000
257 //-----------------------------------------------------------------------------
258 ///
259 /// Construct a resistor instance.
260 ///
261 /// @param[in] configuration Device configuration and traits.
262 /// @param[in] instance_block Instance information from parser.
263 /// @param[in] model Resistor Model to which we should add this instance.
264 /// @param[in] factory_block Device options defined in netlist.
265 ///
266 /// @note The parameter member variable values from the initializers
267 /// are immediately replaced with the values from the parameter
268 /// definitions by the setDefaultParams() function.
269 
271  const Configuration & configuration,
272  const InstanceBlock & instance_block,
273  Model & model,
274  const FactoryBlock & factory_block)
275  : DeviceInstance(instance_block, configuration.getInstanceParameters(), factory_block),
276  model_(model),
277  R(0.0),
278  length(0.0),
279  width(0.0),
280  temp(factory_block.deviceOptions_.temp.getImmutableValue<double>()),
281  tempCoeff1(0.0),
282  tempCoeff2(0.0),
283  dtemp(0.0),
284  tempCoeff1Given(false),
285  tempCoeff2Given(false),
286  dtempGiven(false),
287  G(0.0),
288  i0(0.0),
289  li_Pos(-1),
290  li_Neg(-1),
291  li_store_dev_i(0),
292  APosEquPosNodeOffset(-1),
293  APosEquNegNodeOffset(-1),
294  ANegEquPosNodeOffset(-1),
295  ANegEquNegNodeOffset(-1)
297  ,
298  f_PosEquPosNodePtr(0),
299  f_PosEquNegNodePtr(0),
300  f_NegEquPosNodePtr(0),
301  f_NegEquNegNodePtr(0)
302 #endif
303 {
304  // Initialize DeviceInstance values
305  numIntVars = 0; // Initialize number if internal nodes in DeviceInstance
306  numExtVars = 2; // Initialize number if external nodes in DeviceInstance
307  numStateVars = 0; // Initialize number if state variables in DeviceInstance
308  setNumStoreVars(0); // Initialize number if store variables in DeviceInstance
309  numLeadCurrentStoreVars = 1; // Initialize number if lead current variables
310  //in DeviceInstance
311 
313 
314  // Set params to constant default values from parameter definition
316 
317  // Set params according to instance line and constant defaults from metadata
318  setParams(instance_block.params);
319 
320  // Set any non-constant parameter defaults:
321  if (!given("TEMP"))
322  temp = factory_block.deviceOptions_.temp.getImmutableValue<double>();
323  if (!given("W"))
325 
326  // Get temperature values from model is not given in instance
327  if (!tempCoeff1Given)
329  if (!tempCoeff2Given)
331 
332  // Calculate any parameters specified as expressions
334 
335  // calculate dependent (ie computed) params and check for errors
336  if (!given("R"))
337  {
338  if (model_.given("RSH") && given("L") && (model_.sheetRes != 0) &&
339  (length != 0))
340  {
342  / (width - model_.narrow);
343  }
344  else
345  {
346  R = 1000.0;
347  UserWarning0(*this) << "Resistance is set to 0, setting to the default, " << R << " ohms";
348  }
349  }
350 
351  // Process the parameters to complete initialization
352  processParams();
353 }
354 
355 //-----------------------------------------------------------------------------
356 // Function : Xyce::Device::Resistor::Instance::processParams
357 // Purpose :
358 // Special Notes :
359 // Scope : public
360 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
361 // Creation Date : 6/3/02
362 //-----------------------------------------------------------------------------
363 /// Process parameters.
364 ///
365 /// @return true on success
366 ///
367 /// In general, the processParams method is intended as a place for complex
368 /// manipulation of parameters that must happen if temperature or other
369 /// external changes happen. In the resistor device it does nothing other
370 /// than call updateTemperature.
371 ///
372 /// @author Eric Keiter, SNL, Parallel Computational Sciences
373 /// @date 6/03/02
375 {
376  // now set the temperature related stuff.
377  return updateTemperature(temp);
378 }
379 
380 //-----------------------------------------------------------------------------
381 // Function : Xyce::Device::Resistor::Instance::registerLIDs
382 // Purpose :
383 // Special Notes :
384 // Scope : public
385 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
386 // Creation Date : 6/12/02
387 //-----------------------------------------------------------------------------
388 ///
389 /// Register local IDs
390 ///
391 /// Register the local internal and external node IDs.
392 ///
393 /// @param intLIDVecRef internal local IDs from topology package
394 /// @param extLIDVecRef external local IDs from topology package
395 ///
396 /// Instantiation (calling the device constructor) of the device
397 /// sets up variables numIntVars and numExtVars, the numbers of internal and
398 /// external variables associated with the device. This information is then
399 /// used by the Topology package to assign locations in the solution vector
400 /// (and all other vectors of the same shape) for those variables.
401 /// The "Local IDs" (LIDs) of these locations are provided by Topology
402 /// so the device can know where to load its data.
403 ///
404 /// This method saves the LIDs from Topology and associates each one with
405 /// a particular local name for the internal or external variable. They
406 /// are then used when we load the F and Q vectors.
407 ///
408 /// The resistor device has no internal variables, so this method makes no use
409 /// of the intLIDVecRef array.
410 ///
411 /// @author Robert Hoekstra, SNL, Parallel Computational Sciences
412 /// @date 6/12/02
414  const std::vector<int> & intLIDVecRef,
415  const std::vector<int> & extLIDVecRef)
416 {
417  AssertLIDs(intLIDVecRef.size() == numIntVars);
418  AssertLIDs(extLIDVecRef.size() == numExtVars);
419 
420  // Copy the local ID lists.
421  intLIDVec = intLIDVecRef; // Set the internal local IDs in DeviceInstance
422  extLIDVec = extLIDVecRef; // Set the external local IDs in DeviceInstance
423 
424  li_Pos = extLIDVec[0];
425  li_Neg = extLIDVec[1];
426 
427  if (DEBUG_DEVICE && getDeviceOptions().debugLevel > 0)
428  {
429  dout() << getName() << " LIDs"
430  //<< Util::push << std::endl
431  << std::endl
432  << "li_Pos_ = " << li_Pos << std::endl
433  << "li_Neg_ = " << li_Neg << std::endl
434  //<< Util::pop << std::endl;
435  << std::endl;
436  }
437 }
438 
439 //-----------------------------------------------------------------------------
440 // Function : Xyce::Device::Resistor::Instance::registerStateLIDs
441 // Purpose :
442 // Special Notes :
443 // Scope : public
444 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
445 // Creation Date : 6/12/02
446 //-----------------------------------------------------------------------------
447 ///
448 /// Register the local state IDs
449 ///
450 /// @note The resistor does not have any state vars, so this function
451 /// does nothing.
452 ///
453 /// @param staLIDVecRef State variable local IDs
454 ///
455 /// In general, devices may declare at construction that they require storage
456 /// locations in the "state vector." Topology assigns locations in the
457 /// state vector and returns "Local IDs" (LIDs) for devices to use for their
458 /// state vector entries. If a device uses state vector entries, it
459 /// uses the registerStateLIDs method to save the local IDs for later use.
460 ///
461 /// @author Robert Hoekstra, SNL, Parallel Computational Sciences
462 /// @date 06/12/02
463 
464 void Instance::registerStateLIDs(const std::vector<int> & staLIDVecRef)
465 {
466  AssertLIDs(staLIDVecRef.size() == numStateVars);
467 }
468 
469 //-----------------------------------------------------------------------------
470 // Function : Xyce::Device::Resistor::Instance::registerStoreLIDs
471 // Purpose :
472 // Special Notes :
473 // Scope : public
474 // Creator : Richard Schiek, Electrical Systems Modeling
475 // Creation Date : 12/18/2012
476 //-----------------------------------------------------------------------------
477 /// Register the local store IDs
478 ///
479 /// In addition to state vector, Xyce maintains a separate datastructure
480 /// called a "store" vector. As with other such vectors, the device
481 /// declares at construction time how many store vector entries it needs,
482 /// and later Topology assigns locations for devices, returning LIDs.
483 ///
484 /// These LIDs are stored in this method for later use.
485 ///
486 /// The Resistor device uses exactly one "store vector" element, where
487 /// it keeps the "lead current" that may be used on .PRINT lines as
488 /// "I(R1)" for the current through resistor R1.
489 ///
490 /// @param stoLIDVecRef Store variable local IDs
491 ///
492 /// @author Richard Schiek, Electrical Systems Modeling
493 /// @date 12/18/2012
494 
495 void Instance::registerStoreLIDs(const std::vector<int> & stoLIDVecRef)
496 {
497  AssertLIDs(stoLIDVecRef.size() == getNumStoreVars());
498 
499  if (loadLeadCurrent)
500  {
501  li_store_dev_i = stoLIDVecRef[0];
502  }
503 }
504 
505 //-----------------------------------------------------------------------------
506 // Function : Xyce::Device::Resistor::Instance::getStoreNameMap
507 // Purpose :
508 // Special Notes :
509 // Scope : public
510 // Creator : Richard Schiek, Electrical Systems Modeling
511 // Creation Date : 12/18/2012
512 //-----------------------------------------------------------------------------
513 /// Populates and returns the store name map.
514 ///
515 /// If the DeviceInstance::storeNameMap is empty, populate it.
516 ///
517 /// @return reference to the DeviceInstance::storeNameMap
518 ///
519 /// For the purpose of lead currents, store vector elements must be given
520 /// names that can be used to locate lead currents at print time.
521 /// When a netlist attempts to print, say, "I(R1)" the output code looks for
522 /// an entry in the store vector named R1:DEV_I.
523 ///
524 /// This method does the assignment of names to store vector elements.
525 ///
526 /// @author Richard Schiek, Electrical Systems Modeling
527 /// @date 12/18/2012
528 
529 std::map<int,std::string> & Instance::getStoreNameMap()
530 {
531  // set up the internal name map, if it hasn't been already.
532  if (loadLeadCurrent && storeNameMap.empty ())
533  {
534  // change subcircuitname:devicetype_deviceName to
535  // devicetype:subcircuitName:deviceName
536  std::string modName(getName());
537  spiceInternalName(modName);
538  std::string tmpstr;
539  tmpstr = modName+":DEV_I";
540  storeNameMap[ li_store_dev_i ] = tmpstr;
541  }
542 
543  return storeNameMap;
544 }
545 
546 //-----------------------------------------------------------------------------
547 // Function : Xyce::Device::Resistor::Instance::registerJacLIDs
548 // Purpose :
549 // Special Notes :
550 // Scope : public
551 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
552 // Creation Date : 08/27/01
553 //-----------------------------------------------------------------------------
554 ///
555 /// Register the Jacobian local IDs
556 ///
557 /// @param jacLIDVec Jacobian local Ids
558 ///
559 /// @see Xyce::Device::Resistor::Instance::initializeJacobianStamp
560 ///
561 /// Having established local IDs for the solution variables, Topology must
562 /// also assign local IDs for the elements of the Jacobian matrix.
563 ///
564 /// For each non-zero element that was identified in the jacobianStamp,
565 /// Topology will assign a Jacobian LID. The jacLIDVec will have the
566 /// same structure as the JacStamp, but the values in the jacLIDVec will
567 /// be offsets into the row of the sparse Jacobian matrix corresponding
568 /// to the non-zero identified in the stamp.
569 ///
570 /// These offsets are stored in this method for use later when we load
571 /// the Jacobian.
572 ///
573 /// @author Robert Hoekstra, SNL, Parallel Computational Sciences
574 /// @date 08/27/01
575 
576 void Instance::registerJacLIDs(const std::vector< std::vector<int> > & jacLIDVec)
577 {
578  // Let DeviceInstance do its work.
580 
581  // Store offsets of the components of the Jacobian of this instance
582  APosEquPosNodeOffset = jacLIDVec[0][0];
583  APosEquNegNodeOffset = jacLIDVec[0][1];
584  ANegEquPosNodeOffset = jacLIDVec[1][0];
585  ANegEquNegNodeOffset = jacLIDVec[1][1];
586 }
587 
588 //-----------------------------------------------------------------------------
589 // Function : Xyce::Device::Resistor::Instance::setupPointers
590 // Purpose :
591 // Special Notes :
592 // Scope : public
593 // Creator : Eric Keiter, SNL
594 // Creation Date : 11/30/08
595 //-----------------------------------------------------------------------------
596 ///
597 /// Setup direct access pointer to solution matrix and vectors.
598 ///
599 /// @see Xyce::Device::Resistor::Instance::registerJacLIDs
600 ///
601 /// As an alternative to the row offsets defined in registerJacLIDs, it
602 /// is also possible to obtain direct pointers of the Jacobian elements.
603 ///
604 /// This method uses the offsets obtained in registerJacLIDs to retrieve
605 /// the pointers.
606 ///
607 /// In the resistor device the pointers to the matrix are only saved
608 /// (and are only used for matrix access) if
609 /// Xyce_NONPOINTER_MATRIX_LOAD is NOT defined at compile time. For
610 /// some devices the use of pointers instead of array indexing can be
611 /// a performance enhancement.
612 ///
613 /// Use of pointers in this device is disabled by defining
614 /// Xyce_NONPOINTER_MATRIX_LOAD at compile time. When disabled, array
615 /// indexing with the offsets from registerJacLIDs is used in
616 /// the matrix load methods.
617 ///
618 /// @author Eric Keiter, SNL
619 /// @date 11/30/08
620 
622 {
623 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
624  N_LAS_Matrix & dFdx = *(extData.dFdxMatrixPtr);
629 #endif
630 }
631 
632 //-----------------------------------------------------------------------------
633 // Function : Xyce::Device::Resistor::Instance::updateIntermediateVars
634 // Purpose :
635 // Special Notes :
636 // Scope : public
637 // Creator : Eric Keiter, SNL
638 // Creation Date : 3/05/2004
639 //-----------------------------------------------------------------------------
640 ///
641 /// Update the intermediate variables
642 ///
643 /// @return true on success
644 ///
645 /// The bulk of any device's computation is handled in the instance class'
646 /// updateIntermediateVars method. For the resistor, this is
647 /// merely the computation of the current through the resistor given the
648 /// voltage difference between its terminals.
649 ///
650 /// Intermediate variables computed here are used in the methods that
651 /// load data into the F, Q, dFdX and dQdX data structures.
652 ///
653 /// @note This method is called by the updatePrimaryState
654 /// method. Since the Resistor class reimplements the "Master"
655 /// "loadState" function that loads the contributions from all
656 /// resistor devices in a single loop, THIS FUNCTION IS NOT ACTUALLY
657 /// USED!
658 ///
659 /// @see Xyce::Device::Resistor::Instance::loadDAEFVector Xyce::Device::Resistor::Instance::loadDAEQVector Xyce::Device::Resistor::Instance::loadDAEdFdx Xyce::Device::Resistor::Instance::loadDAEdQdx Xyce::Device::Resistor::Instance::updatePrimaryState
660 /// @author Eric R. Keiter, Dept. 9233.
661 /// @date 3/05/04
662 ///
664 {
665  double * solVec = extData.nextSolVectorRawPtr;
666  double v_pos = solVec[li_Pos];
667  double v_neg = solVec[li_Neg];
668  i0 = (v_pos-v_neg)*G;
669  return true;
670 }
671 
672 //-----------------------------------------------------------------------------
673 // Function : Xyce::Device::Resistor::Instance::updatePrimaryState
674 // Purpose :
675 // Special Notes :
676 // Scope : public
677 // Creator : Eric Keiter, SNL
678 // Creation Date : 1/29/01
679 //-----------------------------------------------------------------------------
680 ///
681 /// Update the state variables.
682 ///
683 /// @return true on success
684 ///
685 /// This function is the function that is called from the device manager
686 /// each time a load of vectors and Jacobian is required. Its first
687 /// job is to call updateIntermediateVars.
688 ///
689 /// After calling updateIntermediateVars, the updatePrimaryState method
690 /// may load state vector elements as needed.
691 ///
692 /// The resistor device has no state vector elements, so all this method does
693 /// in the resistor instance class is call updateIntermediateVars.
694 ///
695 /// There is no longer a "secondary" state. The "primary" in
696 /// this method's name is purely historical.
697 ///
698 /// @note This method is called by the default implementation of the
699 /// loadState master function. Since the Resistor class reimplements
700 /// the "Master" "loadState" function that loads the contributions
701 /// from all resistor devices in a single loop, THIS FUNCTION IS NOT
702 /// ACTUALLY USED, NOR is the updateIntermediateVars method it calls!
703 /// The updatePrimaryState method is only called when a device class
704 /// does not re-implement the master class. This can be a source of
705 /// confusion when attempting to modify the Resistor device, or any
706 /// other device That reimplements the Master classes.
707 ///
708 /// @see Xyce::Device::Resistor::Master::updateState
709 ///
710 /// @author Eric Keiter, SNL, Parallel Computational Sciences
711 /// @date 01/29/01
712 ///
714 {
715  return updateIntermediateVars();
716 }
717 
718 //-----------------------------------------------------------------------------
719 // Function : Xyce::Device::Resistor::Instance::loadDAEFVector
720 // Purpose :
721 // Special Notes :
722 // Scope : public
723 // Creator : Eric Keiter, SNL
724 // Creation Date : 1/24/03
725 //-----------------------------------------------------------------------------
726 ///
727 /// Load the DAE F vector.
728 ///
729 /// @return true on success
730 ///
731 /// The Xyce DAE formulation solves the differential-algebraic
732 /// equations \f$F(x)+dQ(x)/dt=0\f$ These are vector equations
733 /// resulting from the modified nodal analysis of the circuit.
734 ///
735 /// This method loads the F-vector contributions for a single resistor
736 /// instance.
737 ///
738 /// In this method, the offsets defined in registerLIDs are used to
739 /// store the device's F contributions into the F vector.
740 ///
741 /// The Q vector is used for devices that store charge or magnetic
742 /// energy, and since the resistor does none of that, the F vector
743 /// contributions are the whole of the resistor's contribution to the
744 /// full set of DAEs.
745 ///
746 /// @note This method is called by the default implementation of the
747 /// loadDAEVectors master function. Since the Resistor class
748 /// reimplements the "Master" "loadDAEVectors" function that loads the
749 /// contributions from all resistor devices in a single loop, THIS
750 /// FUNCTION IS NOT ACTUALLY USED. The loadDAEFVector method is only
751 /// called when a device class does not re-implement the master class.
752 /// This can be a source of confusion when attempting to modify the Resistor
753 /// device, or any other device that reimplements the Master classes.
754 ///
755 /// @see Xyce::Device::Resistor::Master::loadDAEVectors
756 ///
757 /// @author Eric Keiter, SNL, Parallel Computational Sciences
758 /// @date 01/24/03
759 ///
761 {
762  double * fVec = extData.daeFVectorRawPtr;
763  fVec[li_Pos] += i0;
764  fVec[li_Neg] += -i0;
765 
766  if( loadLeadCurrent )
767  {
768  double * stoVec = extData.nextStoVectorRawPtr;
769  stoVec[li_store_dev_i] = i0;
770  }
771 
772  return true;
773 }
774 
775 //-----------------------------------------------------------------------------
776 // Function : Xyce::Device::Resistor::Instance::loadDAEdFdx
777 // Purpose : Loads the F-vector contributions for a single
778 // resistor instance.
779 // Special Notes :
780 // Scope : public
781 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
782 // Creation Date : 03/05/04
783 //-----------------------------------------------------------------------------
784 ///
785 /// Load the DAE the derivative of the F vector with respect to the
786 /// solution vector x, dFdx
787 ///
788 /// Loads the contributions for a single resistor instance to the
789 /// dFdx matrix (the F contribution to the Jacobian).
790 ///
791 /// This method uses the Jacobian LIDs (row offsets) that were stored by
792 /// registerJacLIDs.
793 ///
794 /// @see Xyce::Device::Resistor::Instance::registerJacLIDs
795 ///
796 /// @note This method is called by the default implementation of the
797 /// loadDAEMatrices master function. Since the Resistor class
798 /// reimplements the "Master" "loadDAEMatrices" function that loads the
799 /// contributions from all resistor devices in a single loop, THIS
800 /// FUNCTION IS NOT ACTUALLY USED. The loadDAEdFdx method is only
801 /// called when a device class does not re-implement the master class.
802 /// This can be a source of confusion when attempting to modify the Resistor
803 /// device, or any other device that reimplements the Master classes.
804 ///
805 /// @see Xyce::Device::Resistor::Master::loadDAEMatrices
806 ///
807 /// @return true on success
808 ///
809 /// @author Eric Keiter, SNL, Parallel Computational Sciences
810 /// @date 03/05/04
812 {
813  N_LAS_Matrix & dFdx = *(extData.dFdxMatrixPtr);
814  dFdx[li_Pos][APosEquPosNodeOffset] += G;
815  dFdx[li_Pos][APosEquNegNodeOffset] -= G;
816  dFdx[li_Neg][ANegEquPosNodeOffset] -= G;
817  dFdx[li_Neg][ANegEquNegNodeOffset] += G;
818  return true;
819 }
820 
821 //-----------------------------------------------------------------------------
822 // Function : Xyce::Device::Resistor::Instance::updateTemperature
823 // Purpose :
824 // Special Notes :
825 // Scope : public
826 // Creator : Tom Russo, Component Information and Models
827 // Creation Date : 02/27/01
828 //-----------------------------------------------------------------------------
829 ///
830 /// Update the parameters that depend on the temperature of the device
831 ///
832 /// @param temp_tmp temperature
833 ///
834 /// Xyce has a number of mechanisms that allow temperature to be changed
835 /// after a device has been instantiated. These include .STEP loops over
836 /// temperature. When temperature is changed, any device that has parameters
837 /// that depend on temperature must be updated. That updating happens here.
838 ///
839 /// The Resistor device supports temperature-dependent resistance through its
840 /// TC1 (linear dependence) and TC2 (quadratic dependence) parameters.
841 /// If these parameters are specified, the resistance must be updated.
842 ///
843 /// @return true on success
844 ///
845 /// @author Tom Russo, Component Information and Models
846 /// @date 02/27/01
847 bool Instance::updateTemperature(const double & temp_tmp)
848 {
849  bool bsuccess = true;
850  double difference, factor;
851 
852  if (temp_tmp != -999.0)
853  temp = temp_tmp;
854  difference = temp - model_.tnom;
855  factor = 1.0 + tempCoeff1*difference + tempCoeff2*difference*difference;
856 
857  if (R*factor != 0.0)
858  G = 1.0/(R * factor);
859  else
860  G = 0.0;
861 
862  return bsuccess;
863 }
864 
865 //-----------------------------------------------------------------------------
866 // Function : Xyce::Device::Resistor::Model::processParams
867 // Purpose :
868 // Special Notes :
869 // Scope : public
870 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
871 // Creation Date : 6/03/02
872 //-----------------------------------------------------------------------------
873 ///
874 /// Process model parameters
875 ///
876 /// @return true on success
877 ///
878 /// @author Eric Keiter, SNL, Parallel Computational Sciences
879 /// @date 6/03/02
881 {
882  return true;
883 }
884 
885 //----------------------------------------------------------------------------
886 // Function : Xyce::Device::Resistor::Model::processInstanceParams
887 // Purpose :
888 // Special Notes :
889 // Scope : public
890 // Creator : Dave Shirely, PSSI
891 // Creation Date : 03/23/06
892 //----------------------------------------------------------------------------
893 ///
894 /// Process the instance parameters of instance owned by this model
895 ///
896 /// This method simply loops over all instances associated with this
897 /// model and calls their processParams method.
898 ///
899 /// @return true
900 ///
901 /// @author Dave Shirely, PSSI
902 /// @date 03/23/06
903 
905 {
906  for (InstanceVector::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
907  {
908  (*it)->processParams();
909  }
910 
911  return true;
912 }
913 //-----------------------------------------------------------------------------
914 // Function : Xyce::Device::Resistor::Model::N_DEV_ResistorModel
915 // Purpose : model block constructor
916 // Special Notes :
917 // Scope : public
918 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
919 // Creation Date : 5/16/00
920 //-----------------------------------------------------------------------------
921 ///
922 /// Construct a resistor model from a "model block" that was created
923 /// by the netlist parser.
924 ///
925 /// @param configuration
926 /// @param model_block
927 /// @param factory_block
928 ///
929 /// @author Eric Keiter, SNL, Parallel Computational Sciences
930 /// @date 5/16/00
932  const Configuration & configuration,
933  const ModelBlock & model_block,
934  const FactoryBlock & factory_block)
935  : DeviceModel(model_block, configuration.getModelParameters(), factory_block),
936  tempCoeff1(0.0),
937  tempCoeff2(0.0),
938  sheetRes(0.0),
939  defWidth(10e-6),
940  narrow(0.0),
941  tnom(getDeviceOptions().tnom)
942 {
943  // Set params to constant default values.
945 
946  // Set params according to .model line and constant defaults from metadata.
947  setModParams(model_block.params);
948 
949  // Set any non-constant parameter defaults.
950  if (!given("TNOM"))
952 
953  // Calculate any parameters specified as expressions.
955 
956  // calculate dependent (ie computed) params and check for errors.
957  processParams();
958 }
959 
960 //-----------------------------------------------------------------------------
961 // Function : Xyce::Device::Resistor::Model::~N_DEV_ResistorModel
962 // Purpose : destructor
963 // Special Notes :
964 // Scope : public
965 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
966 // Creation Date : 3/16/00
967 //-----------------------------------------------------------------------------
968 ///
969 /// Destroy this model.
970 ///
971 /// Also destroys all instances that use this model.
972 ///
973 /// @author Eric Keiter, SNL, Parallel Computational Sciences
974 /// @date 3/16/00
976 {
977  // Destory all owned instances
978  for (InstanceVector::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
979  {
980  delete (*it);
981  }
982 }
983 
984 //-----------------------------------------------------------------------------
985 // Function : N_DEV_ResistorModel::printOutInstances
986 // Purpose : debugging tool.
987 // Special Notes :
988 // Scope : public
989 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
990 // Creation Date : 4/03/00
991 //-----------------------------------------------------------------------------
992 ///
993 /// Print instances associated with this model.
994 ///
995 /// Used only for debugging
996 ///
997 /// @param os output stream
998 ///
999 /// @return reference to output stream
1000 ///
1001 /// @author Eric Keiter, SNL, Parallel Computational Sciences
1002 /// @date 4/03/00
1003 ///
1004 std::ostream &Model::printOutInstances(std::ostream &os) const
1005 {
1006  os << std::endl;
1007  os << "Number of Resistor Instances: " << instanceContainer.size() << std::endl;
1008  os << " name model name Parameters" << std::endl;
1009 
1010  int i = 0;
1011  for (InstanceVector::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
1012  {
1013  os << " " << i << ": " << (*it)->getName() << "\t";
1014  os << getName();
1015  os << "\t\tR(Tnom) = " << (*it)->R;
1016  os << "\tG(T) = " << (*it)->G;
1017  os << std::endl;
1018  ++i;
1019  }
1020 
1021  os << std::endl;
1022 
1023  return os;
1024 }
1025 
1026 //-----------------------------------------------------------------------------
1027 // Function : Model::forEachInstance
1028 // Purpose :
1029 // Special Notes :
1030 // Scope : public
1031 // Creator : David Baur
1032 // Creation Date : 2/4/2014
1033 //-----------------------------------------------------------------------------
1034 /// Apply a device instance "op" to all instances associated with this
1035 /// model
1036 ///
1037 /// @param[in] op Operator to apply to all instances.
1038 ///
1039 ///
1040 void Model::forEachInstance(DeviceInstanceOp &op) const /* override */
1041 {
1042  for (std::vector<Instance *>::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
1043  op(*it);
1044 }
1045 
1046 //-----------------------------------------------------------------------------
1047 // Function : Xyce::Device::Resistor::Master::updateState
1048 // Purpose :
1049 // Special Notes :
1050 // Scope : public
1051 // Creator : Eric Keiter, SNL
1052 // Creation Date : 11/26/08
1053 //-----------------------------------------------------------------------------
1054 ///
1055 /// Update state for all resistor instances, regardless of model.
1056 ///
1057 /// @param solVec solution vector
1058 /// @param staVec state vector
1059 /// @param stoVec store vector
1060 ///
1061 /// @return true on success
1062 ///
1063 /// @note Because the resistor device re-implements the base-class
1064 /// Master::updateState, the Instance::updatePrimaryState method is never
1065 /// called, nor is the Instance::updateIntermediateVars method. This method
1066 /// replaces those, and does the same work but inside a loop over all
1067 /// resistor instances.
1068 ///
1069 /// @see Xyce::Device::Resistor::Instance::updatePrimaryState
1070 /// @author Eric Keiter, SNL
1071 /// @date 11/26/08
1072 
1073 bool Master::updateState(double * solVec, double * staVec, double * stoVec)
1074 {
1075  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
1076  {
1077  Instance & ri = *(*it);
1078 
1079  double v_pos = solVec[ri.li_Pos];
1080  double v_neg = solVec[ri.li_Neg];
1081 
1082  // Load RHS vector element for the positive circuit node KCL equ.
1083  ri.i0 = (v_pos-v_neg)*ri.G;
1084  }
1085 
1086  return true;
1087 }
1088 
1089 //-----------------------------------------------------------------------------
1090 // Function : Xyce::Device::Resistor::Master::loadDAEVectors
1091 // Purpose :
1092 // Special Notes :
1093 // Scope : public
1094 // Creator : Eric Keiter, SNL
1095 // Creation Date : 11/26/08
1096 //-----------------------------------------------------------------------------
1097 ///
1098 /// Load DAE vectors of all resistor instances, regardless of model
1099 ///
1100 /// @param solVec solution vector
1101 /// @param fVec f vector
1102 /// @param qVec q vector
1103 /// @param storeLeadF store lead current f vector
1104 /// @param storeLeadQ store lead current q vector
1105 ///
1106 /// @return true on success
1107 ///
1108 /// @note Because the resistor device re-implements the base-class
1109 /// Master::loadDAEVectors, the Instance::loadDAEFVector method is
1110 /// never called. This method replaces those, and does the same work
1111 /// but inside a loop over all resistor instances.
1112 ///
1113 /// @see Xyce::Device::Resistor::Instance::loadDAEFVector
1114 ///
1115 /// @author Eric Keiter, SNL
1116 /// @date 11/26/08
1117 
1118 bool Master::loadDAEVectors (double * solVec, double * fVec, double *qVec, double * storeLeadF, double * storeLeadQ)
1119 {
1120  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
1121  {
1122  Instance & ri = *(*it);
1123  fVec[ri.li_Pos] += ri.i0;
1124  fVec[ri.li_Neg] += -ri.i0;
1125  if( ri.loadLeadCurrent )
1126  {
1127  storeLeadF[ri.li_store_dev_i] = ri.i0;
1128  }
1129  }
1130  return true;
1131 }
1132 
1133 //-----------------------------------------------------------------------------
1134 // Function : Xyce::Device::Resistor::Master::loadDAEMatrices
1135 // Purpose :
1136 // Special Notes :
1137 // Scope : public
1138 // Creator : Eric Keiter, SNL
1139 // Creation Date : 11/26/08
1140 //-----------------------------------------------------------------------------
1141 ///
1142 /// Load DAE matrices for all resistor instances, regardless of model
1143 ///
1144 /// @param dFdx matrix of derivatives of F vector with respect to solution
1145 /// @param dQdx matrix of derivatives of Q vector with respect to solution
1146 ///
1147 /// @return true on success
1148 ///
1149 /// @note Because the resistor device re-implements the base-class
1150 /// Master::loadDAEMatrices, the Instance::loadDAEdFdx method is
1151 /// never called. This method replaces those, and does the same work
1152 /// but inside a loop over all resistor instances.
1153 ///
1154 /// @see Xyce::Device::Resistor::Instance::loadDAEdFdx
1155 ///
1156 /// @author Eric Keiter, SNL
1157 /// @date 11/26/08
1158 
1159 bool Master::loadDAEMatrices(N_LAS_Matrix & dFdx, N_LAS_Matrix & dQdx)
1160 {
1161  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
1162  {
1163  Instance & ri = *(*it);
1164 
1165 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
1166  *(ri.f_PosEquPosNodePtr) += ri.G;
1167  *(ri.f_PosEquNegNodePtr) -= ri.G;
1168  *(ri.f_NegEquPosNodePtr) -= ri.G;
1169  *(ri.f_NegEquNegNodePtr) += ri.G;
1170 #else
1171  dFdx[ri.li_Pos][ri.APosEquPosNodeOffset] += ri.G;
1172  dFdx[ri.li_Pos][ri.APosEquNegNodeOffset] -= ri.G;
1173  dFdx[ri.li_Neg][ri.ANegEquPosNodeOffset] -= ri.G;
1174  dFdx[ri.li_Neg][ri.ANegEquNegNodeOffset] += ri.G;
1175 #endif
1176  }
1177 
1178  return true;
1179 }
1180 
1181 //-----------------------------------------------------------------------------
1182 // Function : Xyce::Device::Resistor::Traits::factory
1183 // Purpose :
1184 // Special Notes :
1185 // Scope : public
1186 // Creator : David Baur
1187 // Creation Date :
1188 //-----------------------------------------------------------------------------
1189 ///
1190 /// Create a new instance of the Resistor device.
1191 ///
1192 /// @param configuration
1193 /// @param factory_block
1194 ///
1195 Device *
1196 Traits::factory(const Configuration &configuration, const FactoryBlock &factory_block)
1197 {
1198  return new Master(configuration, factory_block, factory_block.solverState_, factory_block.deviceOptions_);
1199 }
1200 
1201 //-----------------------------------------------------------------------------
1202 // Function : Xyce::Device::Resistor::registerDevice
1203 // Purpose :
1204 // Special Notes :
1205 // Scope : public
1206 // Creator : David Baur
1207 // Creation Date :
1208 //-----------------------------------------------------------------------------
1209 ///
1210 /// Define how to use the device in a netlist.
1211 ///
1212 /// This method is called from the Xyce::Device::registerOpenDevices
1213 /// function, which in turn is called by the device manager.
1214 ///
1215 /// The device is declared here to be an "R" device, which may optionally
1216 /// take a model card of type "R". This device will correspond to model
1217 /// level 1 of resistor models.
1218 void
1220 {
1222  .registerDevice("r", 1)
1223  .registerModelType("r", 1);
1224 }
1225 
1226 } // namespace Resistor
1227 } // namespace Device
1228 } // namespace Xyce