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.235.2.1 $
40 //
41 // Revision Date : $Date: 2014/08/28 16:40:51 $
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}{rr}
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  .setAnalyticSensitivityAvailable(true)
178  .setSensitivityFunctor(&resSens);
179  p.addPar("L", 0.0, &Resistor::Instance::length)
180  .setUnit(U_METER)
181  .setDescription("Length");
182  p.addPar("W", 0.0, &Resistor::Instance::width)
183  .setUnit(U_METER)
184  .setDescription("Width");
185  p.addPar("TEMP", 0.0, &Resistor::Instance::temp)
186  .setExpressionAccess(ParameterType::TIME_DEP)
187  .setUnit(U_DEGC)
188  .setDescription("Device temperature");
189 
190  p.addPar("TC1", 0.0, &Resistor::Instance::tempCoeff1)
191  .setGivenMember(&Resistor::Instance::tempCoeff1Given)
192  .setUnit(U_DEGCM1)
193  .setDescription("Linear Temperature Coefficient");
194  p.addPar("TC2", 0.0, &Resistor::Instance::tempCoeff2)
195  .setGivenMember(&Resistor::Instance::tempCoeff2Given)
196  .setUnit(U_DEGCM2)
197  .setDescription("Quadratic Temperature Coefficient");
198  p.makeVector("TC", 2); // Allow TC to be entered as a vector (TC=1,2)
199 
200  p.addPar("DTEMP", 0.0, &Resistor::Instance::dtemp)
201  .setGivenMember(&Resistor::Instance::dtempGiven)
202  .setUnit(U_DEGC)
203  .setDescription("Device Temperature -- For compatibility only. Parameter is NOT used");
204 }
205 
206 //-----------------------------------------------------------------------------
207 // Function : Xyce::Device::Resistor::Traits::loadModelParameters
208 // Purpose :
209 // Special Notes : The addPar calls here were refactored and moved here
210 // from the model constructor. Those addPars had been
211 // in place from 2/4/2005.
212 // Scope : private
213 // Creator : David Baur
214 // Creation Date : 1/27/2014
215 //-----------------------------------------------------------------------------
216 ///
217 /// Loads the parameter definition into the model parameter map.
218 ///
219 /// @param p model parameter map
220 ///
221 /// @see Xyce::Device::Resistor::Traits::loadInstanceParameters
222 ///
223 /// Resistors may optionally be given a model name to enable a semiconductor
224 /// resistor model with a sheet resistance. The resistance of an instance
225 /// is then determined by the length and width given on the instance line.
226 /// This loadModelParameters method defines the parameters that may be
227 /// specified on model cards associated with semiconductor resistors.
228 ///
230 {
231  // Create parameter definitions for parameter member variables
232  p.addPar("TC1", 0.0, &Resistor::Model::tempCoeff1)
233  .setUnit(U_DEGCM1)
234  .setDescription("Linear Temperature Coefficient");
235  p.addPar("TC2", 0.0, &Resistor::Model::tempCoeff2)
236  .setUnit(U_DEGCM2)
237  .setDescription("Quadratic Temperature Coefficient");
238  p.addPar("RSH", 0.0, &Resistor::Model::sheetRes)
239  .setUnit(U_OHM)
240  .setDescription("Sheet Resistance");
242  .setUnit(U_NONE)
243  .setDescription("Resistance Multiplier");
244  p.addPar("DEFW", 1.e-5, &Resistor::Model::defWidth)
245  .setUnit(U_METER)
246  .setDescription("Default Instance Width");
247  p.addPar("NARROW",0.0, &Resistor::Model::narrow)
248  .setUnit(U_METER)
249  .setDescription("Narrowing due to side etching");
250  p.addPar("TNOM", 0.0, &Resistor::Model::tnom)
251  .setUnit(U_DEGC)
252  .setDescription("Parameter Measurement Temperature");
253 }
254 
255 //-----------------------------------------------------------------------------
256 // Function : Xyce::Device::Resistor::Instance::Instance
257 // Purpose : Instance constructor
258 // Special Notes :
259 // Scope : public
260 // Creator : Eric Keiter
261 // Creation Date : 3/16/2000
262 //-----------------------------------------------------------------------------
263 ///
264 /// Construct a resistor instance.
265 ///
266 /// @param[in] configuration Device configuration and traits.
267 /// @param[in] instance_block Instance information from parser.
268 /// @param[in] model Resistor Model to which we should add this instance.
269 /// @param[in] factory_block Device options defined in netlist.
270 ///
271 /// @note The parameter member variable values from the initializers
272 /// are immediately replaced with the values from the parameter
273 /// definitions by the setDefaultParams() function.
274 
276  const Configuration & configuration,
277  const InstanceBlock & instance_block,
278  Model & model,
279  const FactoryBlock & factory_block)
280  : DeviceInstance(instance_block, configuration.getInstanceParameters(), factory_block),
281  model_(model),
282  R(0.0),
283  length(0.0),
284  width(0.0),
285  temp(factory_block.deviceOptions_.temp.getImmutableValue<double>()),
286  tempCoeff1(0.0),
287  tempCoeff2(0.0),
288  dtemp(0.0),
289  tempCoeff1Given(false),
290  tempCoeff2Given(false),
291  dtempGiven(false),
292  G(0.0),
293  i0(0.0),
294  li_Pos(-1),
295  li_Neg(-1),
296  li_store_dev_i(0),
297  APosEquPosNodeOffset(-1),
298  APosEquNegNodeOffset(-1),
299  ANegEquPosNodeOffset(-1),
300  ANegEquNegNodeOffset(-1)
302  ,
303  f_PosEquPosNodePtr(0),
304  f_PosEquNegNodePtr(0),
305  f_NegEquPosNodePtr(0),
306  f_NegEquNegNodePtr(0)
307  // ,
308 #endif
309  //resSens(*this)
310 {
311  // Initialize DeviceInstance values
312  numIntVars = 0; // Initialize number if internal nodes in DeviceInstance
313  numExtVars = 2; // Initialize number if external nodes in DeviceInstance
314  numStateVars = 0; // Initialize number if state variables in DeviceInstance
315  setNumStoreVars(0); // Initialize number if store variables in DeviceInstance
316  numLeadCurrentStoreVars = 1; // Initialize number if lead current variables
317  //in DeviceInstance
318 
320 
321  // Set params to constant default values from parameter definition
323 
324  // Set params according to instance line and constant defaults from metadata
325  setParams(instance_block.params);
326 
327  // Set any non-constant parameter defaults:
328  if (!given("TEMP"))
329  temp = factory_block.deviceOptions_.temp.getImmutableValue<double>();
330  if (!given("W"))
332 
333  // Get temperature values from model is not given in instance
334  if (!tempCoeff1Given)
336  if (!tempCoeff2Given)
338 
339  // Calculate any parameters specified as expressions
341 
342  // calculate dependent (ie computed) params and check for errors
343  if (!given("R"))
344  {
345  if (model_.given("RSH") && given("L") && (model_.sheetRes != 0) &&
346  (length != 0))
347  {
349  / (width - model_.narrow);
350  }
351  else
352  {
353  R = 1000.0;
354  UserWarning0(*this) << "Resistance is set to 0, setting to the default, " << R << " ohms";
355  }
356  }
357 
358  // Process the parameters to complete initialization
359  processParams();
360 }
361 
362 //-----------------------------------------------------------------------------
363 // Function : Xyce::Device::Resistor::Instance::processParams
364 // Purpose :
365 // Special Notes :
366 // Scope : public
367 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
368 // Creation Date : 6/3/02
369 //-----------------------------------------------------------------------------
370 /// Process parameters.
371 ///
372 /// @return true on success
373 ///
374 /// In general, the processParams method is intended as a place for complex
375 /// manipulation of parameters that must happen if temperature or other
376 /// external changes happen. In the resistor device it does nothing other
377 /// than call updateTemperature.
378 ///
379 /// @author Eric Keiter, SNL, Parallel Computational Sciences
380 /// @date 6/03/02
382 {
383  // now set the temperature related stuff.
384  return updateTemperature(temp);
385 }
386 
387 //-----------------------------------------------------------------------------
388 // Function : Xyce::Device::Resistor::Instance::registerLIDs
389 // Purpose :
390 // Special Notes :
391 // Scope : public
392 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
393 // Creation Date : 6/12/02
394 //-----------------------------------------------------------------------------
395 ///
396 /// Register local IDs
397 ///
398 /// Register the local internal and external node IDs.
399 ///
400 /// @param intLIDVecRef internal local IDs from topology package
401 /// @param extLIDVecRef external local IDs from topology package
402 ///
403 /// Instantiation (calling the device constructor) of the device
404 /// sets up variables numIntVars and numExtVars, the numbers of internal and
405 /// external variables associated with the device. This information is then
406 /// used by the Topology package to assign locations in the solution vector
407 /// (and all other vectors of the same shape) for those variables.
408 /// The "Local IDs" (LIDs) of these locations are provided by Topology
409 /// so the device can know where to load its data.
410 ///
411 /// This method saves the LIDs from Topology and associates each one with
412 /// a particular local name for the internal or external variable. They
413 /// are then used when we load the F and Q vectors.
414 ///
415 /// The resistor device has no internal variables, so this method makes no use
416 /// of the intLIDVecRef array.
417 ///
418 /// @author Robert Hoekstra, SNL, Parallel Computational Sciences
419 /// @date 6/12/02
421  const std::vector<int> & intLIDVecRef,
422  const std::vector<int> & extLIDVecRef)
423 {
424  AssertLIDs(intLIDVecRef.size() == numIntVars);
425  AssertLIDs(extLIDVecRef.size() == numExtVars);
426 
427  // Copy the local ID lists.
428  intLIDVec = intLIDVecRef; // Set the internal local IDs in DeviceInstance
429  extLIDVec = extLIDVecRef; // Set the external local IDs in DeviceInstance
430 
431  li_Pos = extLIDVec[0];
432  li_Neg = extLIDVec[1];
433 
434  if (DEBUG_DEVICE && getDeviceOptions().debugLevel > 0)
435  {
436  dout() << getName() << " LIDs"
437  //<< Util::push << std::endl
438  << std::endl
439  << "li_Pos_ = " << li_Pos << std::endl
440  << "li_Neg_ = " << li_Neg << std::endl
441  //<< Util::pop << std::endl;
442  << std::endl;
443  }
444 }
445 
446 //-----------------------------------------------------------------------------
447 // Function : Xyce::Device::Resistor::Instance::registerStateLIDs
448 // Purpose :
449 // Special Notes :
450 // Scope : public
451 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
452 // Creation Date : 6/12/02
453 //-----------------------------------------------------------------------------
454 ///
455 /// Register the local state IDs
456 ///
457 /// @note The resistor does not have any state vars, so this function
458 /// does nothing.
459 ///
460 /// @param staLIDVecRef State variable local IDs
461 ///
462 /// In general, devices may declare at construction that they require storage
463 /// locations in the "state vector." Topology assigns locations in the
464 /// state vector and returns "Local IDs" (LIDs) for devices to use for their
465 /// state vector entries. If a device uses state vector entries, it
466 /// uses the registerStateLIDs method to save the local IDs for later use.
467 ///
468 /// @author Robert Hoekstra, SNL, Parallel Computational Sciences
469 /// @date 06/12/02
470 
471 void Instance::registerStateLIDs(const std::vector<int> & staLIDVecRef)
472 {
473  AssertLIDs(staLIDVecRef.size() == numStateVars);
474 }
475 
476 //-----------------------------------------------------------------------------
477 // Function : Xyce::Device::Resistor::Instance::registerStoreLIDs
478 // Purpose :
479 // Special Notes :
480 // Scope : public
481 // Creator : Richard Schiek, Electrical Systems Modeling
482 // Creation Date : 12/18/2012
483 //-----------------------------------------------------------------------------
484 /// Register the local store IDs
485 ///
486 /// In addition to state vector, Xyce maintains a separate datastructure
487 /// called a "store" vector. As with other such vectors, the device
488 /// declares at construction time how many store vector entries it needs,
489 /// and later Topology assigns locations for devices, returning LIDs.
490 ///
491 /// These LIDs are stored in this method for later use.
492 ///
493 /// The Resistor device uses exactly one "store vector" element, where
494 /// it keeps the "lead current" that may be used on .PRINT lines as
495 /// "I(R1)" for the current through resistor R1.
496 ///
497 /// @param stoLIDVecRef Store variable local IDs
498 ///
499 /// @author Richard Schiek, Electrical Systems Modeling
500 /// @date 12/18/2012
501 
502 void Instance::registerStoreLIDs(const std::vector<int> & stoLIDVecRef)
503 {
504  AssertLIDs(stoLIDVecRef.size() == getNumStoreVars());
505 
506  if (loadLeadCurrent)
507  {
508  li_store_dev_i = stoLIDVecRef[0];
509  }
510 }
511 
512 //-----------------------------------------------------------------------------
513 // Function : Xyce::Device::Resistor::Instance::getStoreNameMap
514 // Purpose :
515 // Special Notes :
516 // Scope : public
517 // Creator : Richard Schiek, Electrical Systems Modeling
518 // Creation Date : 12/18/2012
519 //-----------------------------------------------------------------------------
520 /// Populates and returns the store name map.
521 ///
522 /// If the DeviceInstance::storeNameMap is empty, populate it.
523 ///
524 /// @return reference to the DeviceInstance::storeNameMap
525 ///
526 /// For the purpose of lead currents, store vector elements must be given
527 /// names that can be used to locate lead currents at print time.
528 /// When a netlist attempts to print, say, "I(R1)" the output code looks for
529 /// an entry in the store vector named R1:DEV_I.
530 ///
531 /// This method does the assignment of names to store vector elements.
532 ///
533 /// @author Richard Schiek, Electrical Systems Modeling
534 /// @date 12/18/2012
535 
536 std::map<int,std::string> & Instance::getStoreNameMap()
537 {
538  // set up the internal name map, if it hasn't been already.
539  if (loadLeadCurrent && storeNameMap.empty ())
540  {
542  }
543 
544  return storeNameMap;
545 }
546 
547 //-----------------------------------------------------------------------------
548 // Function : Xyce::Device::Resistor::Instance::registerJacLIDs
549 // Purpose :
550 // Special Notes :
551 // Scope : public
552 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
553 // Creation Date : 08/27/01
554 //-----------------------------------------------------------------------------
555 ///
556 /// Register the Jacobian local IDs
557 ///
558 /// @param jacLIDVec Jacobian local Ids
559 ///
560 /// @see Xyce::Device::Resistor::Instance::initializeJacobianStamp
561 ///
562 /// Having established local IDs for the solution variables, Topology must
563 /// also assign local IDs for the elements of the Jacobian matrix.
564 ///
565 /// For each non-zero element that was identified in the jacobianStamp,
566 /// Topology will assign a Jacobian LID. The jacLIDVec will have the
567 /// same structure as the JacStamp, but the values in the jacLIDVec will
568 /// be offsets into the row of the sparse Jacobian matrix corresponding
569 /// to the non-zero identified in the stamp.
570 ///
571 /// These offsets are stored in this method for use later when we load
572 /// the Jacobian.
573 ///
574 /// @author Robert Hoekstra, SNL, Parallel Computational Sciences
575 /// @date 08/27/01
576 
577 void Instance::registerJacLIDs(const std::vector< std::vector<int> > & jacLIDVec)
578 {
579  // Let DeviceInstance do its work.
581 
582  // Store offsets of the components of the Jacobian of this instance
583  APosEquPosNodeOffset = jacLIDVec[0][0];
584  APosEquNegNodeOffset = jacLIDVec[0][1];
585  ANegEquPosNodeOffset = jacLIDVec[1][0];
586  ANegEquNegNodeOffset = jacLIDVec[1][1];
587 }
588 
589 //-----------------------------------------------------------------------------
590 // Function : Xyce::Device::Resistor::Instance::setupPointers
591 // Purpose :
592 // Special Notes :
593 // Scope : public
594 // Creator : Eric Keiter, SNL
595 // Creation Date : 11/30/08
596 //-----------------------------------------------------------------------------
597 ///
598 /// Setup direct access pointer to solution matrix and vectors.
599 ///
600 /// @see Xyce::Device::Resistor::Instance::registerJacLIDs
601 ///
602 /// As an alternative to the row offsets defined in registerJacLIDs, it
603 /// is also possible to obtain direct pointers of the Jacobian elements.
604 ///
605 /// This method uses the offsets obtained in registerJacLIDs to retrieve
606 /// the pointers.
607 ///
608 /// In the resistor device the pointers to the matrix are only saved
609 /// (and are only used for matrix access) if
610 /// Xyce_NONPOINTER_MATRIX_LOAD is NOT defined at compile time. For
611 /// some devices the use of pointers instead of array indexing can be
612 /// a performance enhancement.
613 ///
614 /// Use of pointers in this device is disabled by defining
615 /// Xyce_NONPOINTER_MATRIX_LOAD at compile time. When disabled, array
616 /// indexing with the offsets from registerJacLIDs is used in
617 /// the matrix load methods.
618 ///
619 /// @author Eric Keiter, SNL
620 /// @date 11/30/08
621 
623 {
624 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
625  N_LAS_Matrix & dFdx = *(extData.dFdxMatrixPtr);
630 #endif
631 }
632 
633 //-----------------------------------------------------------------------------
634 // Function : Xyce::Device::Resistor::Instance::updateIntermediateVars
635 // Purpose :
636 // Special Notes :
637 // Scope : public
638 // Creator : Eric Keiter, SNL
639 // Creation Date : 3/05/2004
640 //-----------------------------------------------------------------------------
641 ///
642 /// Update the intermediate variables
643 ///
644 /// @return true on success
645 ///
646 /// The bulk of any device's computation is handled in the instance class'
647 /// updateIntermediateVars method. For the resistor, this is
648 /// merely the computation of the current through the resistor given the
649 /// voltage difference between its terminals.
650 ///
651 /// Intermediate variables computed here are used in the methods that
652 /// load data into the F, Q, dFdX and dQdX data structures.
653 ///
654 /// @note This method is called by the updatePrimaryState
655 /// method. Since the Resistor class reimplements the "Master"
656 /// "loadState" function that loads the contributions from all
657 /// resistor devices in a single loop, THIS FUNCTION IS NOT ACTUALLY
658 /// USED!
659 ///
660 /// @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
661 /// @author Eric R. Keiter, Dept. 9233.
662 /// @date 3/05/04
663 ///
665 {
666  double * solVec = extData.nextSolVectorRawPtr;
667  double v_pos = solVec[li_Pos];
668  double v_neg = solVec[li_Neg];
669  i0 = (v_pos-v_neg)*G;
670  return true;
671 }
672 
673 //-----------------------------------------------------------------------------
674 // Function : Xyce::Device::Resistor::Instance::updatePrimaryState
675 // Purpose :
676 // Special Notes :
677 // Scope : public
678 // Creator : Eric Keiter, SNL
679 // Creation Date : 1/29/01
680 //-----------------------------------------------------------------------------
681 ///
682 /// Update the state variables.
683 ///
684 /// @return true on success
685 ///
686 /// This function is the function that is called from the device manager
687 /// each time a load of vectors and Jacobian is required. Its first
688 /// job is to call updateIntermediateVars.
689 ///
690 /// After calling updateIntermediateVars, the updatePrimaryState method
691 /// may load state vector elements as needed.
692 ///
693 /// The resistor device has no state vector elements, so all this method does
694 /// in the resistor instance class is call updateIntermediateVars.
695 ///
696 /// There is no longer a "secondary" state. The "primary" in
697 /// this method's name is purely historical.
698 ///
699 /// @note This method is called by the default implementation of the
700 /// loadState master function. Since the Resistor class reimplements
701 /// the "Master" "loadState" function that loads the contributions
702 /// from all resistor devices in a single loop, THIS FUNCTION IS NOT
703 /// ACTUALLY USED, NOR is the updateIntermediateVars method it calls!
704 /// The updatePrimaryState method is only called when a device class
705 /// does not re-implement the master class. This can be a source of
706 /// confusion when attempting to modify the Resistor device, or any
707 /// other device That reimplements the Master classes.
708 ///
709 /// @see Xyce::Device::Resistor::Master::updateState
710 ///
711 /// @author Eric Keiter, SNL, Parallel Computational Sciences
712 /// @date 01/29/01
713 ///
715 {
716  return updateIntermediateVars();
717 }
718 
719 //-----------------------------------------------------------------------------
720 // Function : Xyce::Device::Resistor::Instance::loadDAEFVector
721 // Purpose :
722 // Special Notes :
723 // Scope : public
724 // Creator : Eric Keiter, SNL
725 // Creation Date : 1/24/03
726 //-----------------------------------------------------------------------------
727 ///
728 /// Load the DAE F vector.
729 ///
730 /// @return true on success
731 ///
732 /// The Xyce DAE formulation solves the differential-algebraic
733 /// equations \f$F(x)+dQ(x)/dt=0\f$ These are vector equations
734 /// resulting from the modified nodal analysis of the circuit.
735 ///
736 /// This method loads the F-vector contributions for a single resistor
737 /// instance.
738 ///
739 /// In this method, the offsets defined in registerLIDs are used to
740 /// store the device's F contributions into the F vector.
741 ///
742 /// The Q vector is used for devices that store charge or magnetic
743 /// energy, and since the resistor does none of that, the F vector
744 /// contributions are the whole of the resistor's contribution to the
745 /// full set of DAEs.
746 ///
747 /// @note This method is called by the default implementation of the
748 /// loadDAEVectors master function. Since the Resistor class
749 /// reimplements the "Master" "loadDAEVectors" function that loads the
750 /// contributions from all resistor devices in a single loop, THIS
751 /// FUNCTION IS NOT ACTUALLY USED. The loadDAEFVector method is only
752 /// called when a device class does not re-implement the master class.
753 /// This can be a source of confusion when attempting to modify the Resistor
754 /// device, or any other device that reimplements the Master classes.
755 ///
756 /// @see Xyce::Device::Resistor::Master::loadDAEVectors
757 ///
758 /// @author Eric Keiter, SNL, Parallel Computational Sciences
759 /// @date 01/24/03
760 ///
762 {
763  double * fVec = extData.daeFVectorRawPtr;
764  fVec[li_Pos] += i0;
765  fVec[li_Neg] += -i0;
766 
767  if( loadLeadCurrent )
768  {
769  double * stoVec = extData.nextStoVectorRawPtr;
770  stoVec[li_store_dev_i] = i0;
771  }
772 
773  return true;
774 }
775 
776 //-----------------------------------------------------------------------------
777 // Function : Xyce::Device::Resistor::Instance::loadDAEdFdx
778 // Purpose : Loads the F-vector contributions for a single
779 // resistor instance.
780 // Special Notes :
781 // Scope : public
782 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
783 // Creation Date : 03/05/04
784 //-----------------------------------------------------------------------------
785 ///
786 /// Load the DAE the derivative of the F vector with respect to the
787 /// solution vector x, dFdx
788 ///
789 /// Loads the contributions for a single resistor instance to the
790 /// dFdx matrix (the F contribution to the Jacobian).
791 ///
792 /// This method uses the Jacobian LIDs (row offsets) that were stored by
793 /// registerJacLIDs.
794 ///
795 /// @see Xyce::Device::Resistor::Instance::registerJacLIDs
796 ///
797 /// @note This method is called by the default implementation of the
798 /// loadDAEMatrices master function. Since the Resistor class
799 /// reimplements the "Master" "loadDAEMatrices" function that loads the
800 /// contributions from all resistor devices in a single loop, THIS
801 /// FUNCTION IS NOT ACTUALLY USED. The loadDAEdFdx method is only
802 /// called when a device class does not re-implement the master class.
803 /// This can be a source of confusion when attempting to modify the Resistor
804 /// device, or any other device that reimplements the Master classes.
805 ///
806 /// @see Xyce::Device::Resistor::Master::loadDAEMatrices
807 ///
808 /// @return true on success
809 ///
810 /// @author Eric Keiter, SNL, Parallel Computational Sciences
811 /// @date 03/05/04
813 {
814  N_LAS_Matrix & dFdx = *(extData.dFdxMatrixPtr);
815  dFdx[li_Pos][APosEquPosNodeOffset] += G;
816  dFdx[li_Pos][APosEquNegNodeOffset] -= G;
817  dFdx[li_Neg][ANegEquPosNodeOffset] -= G;
818  dFdx[li_Neg][ANegEquNegNodeOffset] += G;
819  return true;
820 }
821 
822 //-----------------------------------------------------------------------------
823 // Function : Xyce::Device::Resistor::Instance::updateTemperature
824 // Purpose :
825 // Special Notes :
826 // Scope : public
827 // Creator : Tom Russo, Component Information and Models
828 // Creation Date : 02/27/01
829 //-----------------------------------------------------------------------------
830 ///
831 /// Update the parameters that depend on the temperature of the device
832 ///
833 /// @param temp_tmp temperature
834 ///
835 /// Xyce has a number of mechanisms that allow temperature to be changed
836 /// after a device has been instantiated. These include .STEP loops over
837 /// temperature. When temperature is changed, any device that has parameters
838 /// that depend on temperature must be updated. That updating happens here.
839 ///
840 /// The Resistor device supports temperature-dependent resistance through its
841 /// TC1 (linear dependence) and TC2 (quadratic dependence) parameters.
842 /// If these parameters are specified, the resistance must be updated.
843 ///
844 /// @return true on success
845 ///
846 /// @author Tom Russo, Component Information and Models
847 /// @date 02/27/01
848 bool Instance::updateTemperature(const double & temp_tmp)
849 {
850  bool bsuccess = true;
851  double difference, factor;
852 
853  if (temp_tmp != -999.0)
854  temp = temp_tmp;
855  difference = temp - model_.tnom;
856  factor = model_.resistanceMultiplier*(1.0 + tempCoeff1*difference + tempCoeff2*difference*difference);
857 
858  if (R*factor != 0.0)
859  G = 1.0/(R * factor);
860  else
861  G = 0.0;
862 
863  return bsuccess;
864 }
865 
866 //-----------------------------------------------------------------------------
867 // Function : Xyce::Device::Resistor::Model::processParams
868 // Purpose :
869 // Special Notes :
870 // Scope : public
871 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
872 // Creation Date : 6/03/02
873 //-----------------------------------------------------------------------------
874 ///
875 /// Process model parameters
876 ///
877 /// @return true on success
878 ///
879 /// @author Eric Keiter, SNL, Parallel Computational Sciences
880 /// @date 6/03/02
882 {
883  return true;
884 }
885 
886 //----------------------------------------------------------------------------
887 // Function : Xyce::Device::Resistor::Model::processInstanceParams
888 // Purpose :
889 // Special Notes :
890 // Scope : public
891 // Creator : Dave Shirely, PSSI
892 // Creation Date : 03/23/06
893 //----------------------------------------------------------------------------
894 ///
895 /// Process the instance parameters of instance owned by this model
896 ///
897 /// This method simply loops over all instances associated with this
898 /// model and calls their processParams method.
899 ///
900 /// @return true
901 ///
902 /// @author Dave Shirely, PSSI
903 /// @date 03/23/06
904 
906 {
907  for (InstanceVector::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
908  {
909  (*it)->processParams();
910  }
911 
912  return true;
913 }
914 //-----------------------------------------------------------------------------
915 // Function : Xyce::Device::Resistor::Model::N_DEV_ResistorModel
916 // Purpose : model block constructor
917 // Special Notes :
918 // Scope : public
919 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
920 // Creation Date : 5/16/00
921 //-----------------------------------------------------------------------------
922 ///
923 /// Construct a resistor model from a "model block" that was created
924 /// by the netlist parser.
925 ///
926 /// @param configuration
927 /// @param model_block
928 /// @param factory_block
929 ///
930 /// @author Eric Keiter, SNL, Parallel Computational Sciences
931 /// @date 5/16/00
933  const Configuration & configuration,
934  const ModelBlock & model_block,
935  const FactoryBlock & factory_block)
936  : DeviceModel(model_block, configuration.getModelParameters(), factory_block),
937  tempCoeff1(0.0),
938  tempCoeff2(0.0),
939  sheetRes(0.0),
940  resistanceMultiplier(1.0),
941  defWidth(10e-6),
942  narrow(0.0),
943  tnom(getDeviceOptions().tnom)
944 {
945  // Set params to constant default values.
947 
948  // Set params according to .model line and constant defaults from metadata.
949  setModParams(model_block.params);
950 
951  // Set any non-constant parameter defaults.
952  if (!given("TNOM"))
954 
955  // Calculate any parameters specified as expressions.
957 
958  // calculate dependent (ie computed) params and check for errors.
959  processParams();
960 }
961 
962 //-----------------------------------------------------------------------------
963 // Function : Xyce::Device::Resistor::Model::~N_DEV_ResistorModel
964 // Purpose : destructor
965 // Special Notes :
966 // Scope : public
967 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
968 // Creation Date : 3/16/00
969 //-----------------------------------------------------------------------------
970 ///
971 /// Destroy this model.
972 ///
973 /// Also destroys all instances that use this model.
974 ///
975 /// @author Eric Keiter, SNL, Parallel Computational Sciences
976 /// @date 3/16/00
978 {
979  // Destory all owned instances
980  for (InstanceVector::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
981  {
982  delete (*it);
983  }
984 }
985 
986 //-----------------------------------------------------------------------------
987 // Function : N_DEV_ResistorModel::printOutInstances
988 // Purpose : debugging tool.
989 // Special Notes :
990 // Scope : public
991 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
992 // Creation Date : 4/03/00
993 //-----------------------------------------------------------------------------
994 ///
995 /// Print instances associated with this model.
996 ///
997 /// Used only for debugging
998 ///
999 /// @param os output stream
1000 ///
1001 /// @return reference to output stream
1002 ///
1003 /// @author Eric Keiter, SNL, Parallel Computational Sciences
1004 /// @date 4/03/00
1005 ///
1006 std::ostream &Model::printOutInstances(std::ostream &os) const
1007 {
1008  os << std::endl;
1009  os << "Number of Resistor Instances: " << instanceContainer.size() << std::endl;
1010  os << " name model name Parameters" << std::endl;
1011 
1012  int i = 0;
1013  for (InstanceVector::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
1014  {
1015  os << " " << i << ": " << (*it)->getName() << "\t";
1016  os << getName();
1017  os << "\t\tR(Tnom) = " << (*it)->R;
1018  os << "\tG(T) = " << (*it)->G;
1019  os << std::endl;
1020  ++i;
1021  }
1022 
1023  os << std::endl;
1024 
1025  return os;
1026 }
1027 
1028 //-----------------------------------------------------------------------------
1029 // Function : Model::forEachInstance
1030 // Purpose :
1031 // Special Notes :
1032 // Scope : public
1033 // Creator : David Baur
1034 // Creation Date : 2/4/2014
1035 //-----------------------------------------------------------------------------
1036 /// Apply a device instance "op" to all instances associated with this
1037 /// model
1038 ///
1039 /// @param[in] op Operator to apply to all instances.
1040 ///
1041 ///
1042 void Model::forEachInstance(DeviceInstanceOp &op) const /* override */
1043 {
1044  for (std::vector<Instance *>::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
1045  op(*it);
1046 }
1047 
1048 //-----------------------------------------------------------------------------
1049 // Function : Xyce::Device::Resistor::Master::updateState
1050 // Purpose :
1051 // Special Notes :
1052 // Scope : public
1053 // Creator : Eric Keiter, SNL
1054 // Creation Date : 11/26/08
1055 //-----------------------------------------------------------------------------
1056 ///
1057 /// Update state for all resistor instances, regardless of model.
1058 ///
1059 /// @param solVec solution vector
1060 /// @param staVec state vector
1061 /// @param stoVec store vector
1062 ///
1063 /// @return true on success
1064 ///
1065 /// @note Because the resistor device re-implements the base-class
1066 /// Master::updateState, the Instance::updatePrimaryState method is never
1067 /// called, nor is the Instance::updateIntermediateVars method. This method
1068 /// replaces those, and does the same work but inside a loop over all
1069 /// resistor instances.
1070 ///
1071 /// @see Xyce::Device::Resistor::Instance::updatePrimaryState
1072 /// @author Eric Keiter, SNL
1073 /// @date 11/26/08
1074 
1075 bool Master::updateState(double * solVec, double * staVec, double * stoVec)
1076 {
1077  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
1078  {
1079  Instance & ri = *(*it);
1080 
1081  double v_pos = solVec[ri.li_Pos];
1082  double v_neg = solVec[ri.li_Neg];
1083 
1084  // Load RHS vector element for the positive circuit node KCL equ.
1085  ri.i0 = (v_pos-v_neg)*ri.G;
1086  }
1087 
1088  return true;
1089 }
1090 
1091 //-----------------------------------------------------------------------------
1092 // Function : Xyce::Device::Resistor::Master::loadDAEVectors
1093 // Purpose :
1094 // Special Notes :
1095 // Scope : public
1096 // Creator : Eric Keiter, SNL
1097 // Creation Date : 11/26/08
1098 //-----------------------------------------------------------------------------
1099 ///
1100 /// Load DAE vectors of all resistor instances, regardless of model
1101 ///
1102 /// @param solVec solution vector
1103 /// @param fVec f vector
1104 /// @param qVec q vector
1105 /// @param storeLeadF store lead current f vector
1106 /// @param storeLeadQ store lead current q vector
1107 ///
1108 /// @return true on success
1109 ///
1110 /// @note Because the resistor device re-implements the base-class
1111 /// Master::loadDAEVectors, the Instance::loadDAEFVector method is
1112 /// never called. This method replaces those, and does the same work
1113 /// but inside a loop over all resistor instances.
1114 ///
1115 /// @see Xyce::Device::Resistor::Instance::loadDAEFVector
1116 ///
1117 /// @author Eric Keiter, SNL
1118 /// @date 11/26/08
1119 
1120 bool Master::loadDAEVectors (double * solVec, double * fVec, double *qVec, double * bVec, double * storeLeadF, double * storeLeadQ)
1121 {
1122  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
1123  {
1124  Instance & ri = *(*it);
1125  fVec[ri.li_Pos] += ri.i0;
1126  fVec[ri.li_Neg] += -ri.i0;
1127  if( ri.loadLeadCurrent )
1128  {
1129  storeLeadF[ri.li_store_dev_i] = ri.i0;
1130  }
1131  }
1132  return true;
1133 }
1134 
1135 //-----------------------------------------------------------------------------
1136 // Function : Xyce::Device::Resistor::Master::loadDAEMatrices
1137 // Purpose :
1138 // Special Notes :
1139 // Scope : public
1140 // Creator : Eric Keiter, SNL
1141 // Creation Date : 11/26/08
1142 //-----------------------------------------------------------------------------
1143 ///
1144 /// Load DAE matrices for all resistor instances, regardless of model
1145 ///
1146 /// @param dFdx matrix of derivatives of F vector with respect to solution
1147 /// @param dQdx matrix of derivatives of Q vector with respect to solution
1148 ///
1149 /// @return true on success
1150 ///
1151 /// @note Because the resistor device re-implements the base-class
1152 /// Master::loadDAEMatrices, the Instance::loadDAEdFdx method is
1153 /// never called. This method replaces those, and does the same work
1154 /// but inside a loop over all resistor instances.
1155 ///
1156 /// @see Xyce::Device::Resistor::Instance::loadDAEdFdx
1157 ///
1158 /// @author Eric Keiter, SNL
1159 /// @date 11/26/08
1160 
1161 bool Master::loadDAEMatrices(N_LAS_Matrix & dFdx, N_LAS_Matrix & dQdx)
1162 {
1163  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
1164  {
1165  Instance & ri = *(*it);
1166 
1167 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
1168  *(ri.f_PosEquPosNodePtr) += ri.G;
1169  *(ri.f_PosEquNegNodePtr) -= ri.G;
1170  *(ri.f_NegEquPosNodePtr) -= ri.G;
1171  *(ri.f_NegEquNegNodePtr) += ri.G;
1172 #else
1173  dFdx[ri.li_Pos][ri.APosEquPosNodeOffset] += ri.G;
1174  dFdx[ri.li_Pos][ri.APosEquNegNodeOffset] -= ri.G;
1175  dFdx[ri.li_Neg][ri.ANegEquPosNodeOffset] -= ri.G;
1176  dFdx[ri.li_Neg][ri.ANegEquNegNodeOffset] += ri.G;
1177 #endif
1178  }
1179 
1180  return true;
1181 }
1182 
1183 //-----------------------------------------------------------------------------
1184 // Function : Xyce::Device::Resistor::Traits::factory
1185 // Purpose :
1186 // Special Notes :
1187 // Scope : public
1188 // Creator : David Baur
1189 // Creation Date :
1190 //-----------------------------------------------------------------------------
1191 ///
1192 /// Create a new instance of the Resistor device.
1193 ///
1194 /// @param configuration
1195 /// @param factory_block
1196 ///
1197 Device *
1198 Traits::factory(const Configuration &configuration, const FactoryBlock &factory_block)
1199 {
1200  return new Master(configuration, factory_block, factory_block.solverState_, factory_block.deviceOptions_);
1201 }
1202 
1203 //-----------------------------------------------------------------------------
1204 // Function : Xyce::Device::Resistor::registerDevice
1205 // Purpose :
1206 // Special Notes :
1207 // Scope : public
1208 // Creator : David Baur
1209 // Creation Date :
1210 //-----------------------------------------------------------------------------
1211 ///
1212 /// Define how to use the device in a netlist.
1213 ///
1214 /// This method is called from the Xyce::Device::registerOpenDevices
1215 /// function, which in turn is called by the device manager.
1216 ///
1217 /// The device is declared here to be an "R" device, which may optionally
1218 /// take a model card of type "R". This device will correspond to model
1219 /// level 1 of resistor models.
1220 void
1222 {
1224  .registerDevice("r", 1)
1225  .registerModelType("r", 1)
1226  .registerModelType("res", 1);
1227 }
1228 
1229 //-----------------------------------------------------------------------------
1230 // Function : resistorSensitivity::operator
1231 // Purpose : produces df/dp and dq/dp, where p=R.
1232 // Special Notes :
1233 // Scope : public
1234 // Creator : Eric Keiter, SNL
1235 // Creation Date : 7/18/2014
1236 //-----------------------------------------------------------------------------
1238  const ParameterBase &entity,
1239  const std::string & name,
1240  std::vector<double> & dfdp,
1241  std::vector<double> & dqdp,
1242  std::vector<double> & dbdp,
1243  std::vector<int> & Findices,
1244  std::vector<int> & Qindices,
1245  std::vector<int> & Bindices
1246  ) const
1247 {
1248  const ParameterBase * e1 = &entity;
1249  const Instance * in = dynamic_cast<const Instance *> (e1);
1250 
1251  double * solVec = in->extData.nextSolVectorRawPtr;
1252  double v_pos = solVec[in->li_Pos];
1253  double v_neg = solVec[in->li_Neg];
1254 
1255  double dfdpLoc = -(v_pos-v_neg)*in->G*in->G;
1256 
1257  dfdp.resize(2);
1258  dfdp[0] = +dfdpLoc;
1259  dfdp[1] = -dfdpLoc;
1260 
1261  Findices.resize(2);
1262  Findices[0] = in->li_Pos;
1263  Findices[1] = in->li_Neg;
1264 }
1265 
1266 } // namespace Resistor
1267 } // namespace Device
1268 } // namespace Xyce