Xyce  6.1
N_DEV_TRA.C
Go to the documentation of this file.
1 //-----------------------------------------------------------------------------
2 // Copyright Notice
3 //
4 // Copyright 2002 Sandia Corporation. Under the terms
5 // of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S.
6 // Government retains certain rights in this software.
7 //
8 // Xyce(TM) Parallel Electrical Simulator
9 // Copyright (C) 2002-2015 Sandia Corporation
10 //
11 // This program is free software: you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation, either version 3 of the License, or
14 // (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 //-----------------------------------------------------------------------------
24 
25 //-------------------------------------------------------------------------
26 // Filename : $RCSfile: N_DEV_TRA.C,v $
27 //
28 // Purpose : Implement lossless transmission line
29 //
30 // Special Notes :
31 //
32 // Creator : Tom Russo, SNL, Component Information and Models
33 //
34 // Creation Date : 06/14/01
35 //
36 // Revision Information:
37 // ---------------------
38 //
39 // Revision Number: $Revision: 1.181.2.1 $
40 //
41 // Revision Date : $Date: 2015/04/02 18:20:11 $
42 //
43 // Current Owner : $Author: tvrusso $
44 //-------------------------------------------------------------------------
45 
46 #include <Xyce_config.h>
47 
48 #include <N_DEV_DeviceBlock.h>
49 #include <N_DEV_DeviceOptions.h>
50 #include <N_DEV_DeviceState.h>
51 #include <N_DEV_DeviceMaster.h>
52 #include <N_DEV_ExternData.h>
53 #include <N_DEV_MatrixLoadData.h>
54 #include <N_DEV_SolverState.h>
55 #include <N_DEV_TRA.h>
56 #include <N_DEV_Message.h>
57 #include <N_ERH_ErrorMgr.h>
58 
59 #include <N_LAS_Matrix.h>
60 #include <N_LAS_Vector.h>
61 
62 #include <N_UTL_BreakPoint.h>
63 #include <N_UTL_FeatureTest.h>
64 #include <N_UTL_Functors.h>
65 #include <N_UTL_MachDepParams.h>
66 
67 namespace Xyce {
68 namespace Device {
69 namespace TRA {
70 
72 {
73  p.addPar("Z0", 0.0, &TRA::Instance::Z0)
74  .setUnit(U_OHM)
75  .setDescription("Characteristic Impedance");
76 
77  p.addPar("ZO", 0.0, &TRA::Instance::ZO)
78  .setUnit(U_OHM)
79  .setDescription("Characteristic Impedance");
80 
81  p.addPar("TD", 0.0, &TRA::Instance::td)
82  .setUnit(U_SECOND)
83  .setDescription("Time delay");
84 
85  p.addPar("F", 0.0, &TRA::Instance::freq)
86  .setUnit(U_HZ)
87  .setDescription("Frequency");
88 
89  p.addPar("NL", 0.0, &TRA::Instance::NL)
90  .setDescription("Length in wavelengths");
91 }
92 
94 {}
95 
96 std::vector< std::vector<int> > Instance::jacStamp;
97 
98 // Class Instance
99 //-----------------------------------------------------------------------------
100 // Function : Instance::Instance
101 // Purpose : "instance block" constructor
102 // Special Notes :
103 // Scope : public
104 // Creator : Tom Russo, SNL, Component Information and Models
105 // Creation Date : 6/15/01
106 //-----------------------------------------------------------------------------
107 
109  const Configuration & configuration,
110  const InstanceBlock & instance_block,
111  Model & model,
112  const FactoryBlock & factory_block)
113  : DeviceInstance(instance_block, configuration.getInstanceParameters(), factory_block),
114  model_(model),
115  Z0(0.0),
116  G0(0.0),
117  td(0.0),
118  freq(0.0),
119  NL(0.25),
120  timeOld(-1.0),
121  li_Pos1(-1),
122  li_Neg1(-1),
123  li_Int1(-1),
124  li_Ibr1(-1),
125  li_Pos2(-1),
126  li_Neg2(-1),
127  li_Int2(-1),
128  li_Ibr2(-1),
129  li_store_dev_i1(-1),
130  li_store_dev_i2(-1),
131  APos1EquPos1NodeOffset(-1),
132  APos1EquInt1NodeOffset(-1),
133  AInt1EquPos1NodeOffset(-1),
134  AInt1EquInt1NodeOffset(-1),
135  AInt1EquIbr1NodeOffset(-1),
136  ANeg1EquIbr1NodeOffset(-1),
137  AIbr1EquInt1NodeOffset(-1),
138  AIbr1EquNeg1NodeOffset(-1),
139  APos2EquPos2NodeOffset(-1),
140  APos2EquInt2NodeOffset(-1),
141  AInt2EquPos2NodeOffset(-1),
142  AInt2EquInt2NodeOffset(-1),
143  AInt2EquIbr2NodeOffset(-1),
144  ANeg2EquIbr2NodeOffset(-1),
145  AIbr2EquInt2NodeOffset(-1),
146  AIbr2EquNeg2NodeOffset(-1),
147  AIbr1EquPos2NodeOffset(-1),
148  AIbr1EquNeg2NodeOffset(-1),
149  AIbr1EquIbr2NodeOffset(-1),
150  AIbr2EquPos1NodeOffset(-1),
151  AIbr2EquNeg1NodeOffset(-1),
152  AIbr2EquIbr1NodeOffset(-1),
153  first_BP_call_done(false),
154  last_t(0.0),
155  v1(0.0),
156  v2(0.0),
157  newBreakPoint(false),
158  newBreakPointTime(0.0)
159 {
160  numIntVars = 4;
161  numExtVars = 4;
162  numStateVars = 0;
163  numLeadCurrentStoreVars = 2; // lead currents i1 and i2
164 
165  devConMap.resize(4);
166  devConMap[0] = 1;
167  devConMap[1] = 1;
168  devConMap[2] = 2;
169  devConMap[3] = 2;
170 
171  if( jacStamp.empty() )
172  {
173  jacStamp.resize(8);
174  jacStamp[0].resize(2);
175  jacStamp[0][0]=0;
176  jacStamp[0][1]=4;
177  jacStamp[1].resize(1);
178  jacStamp[1][0]=5;
179  jacStamp[2].resize(2);
180  jacStamp[2][0]=2;
181  jacStamp[2][1]=6;
182  jacStamp[3].resize(1);
183  jacStamp[3][0]=7;
184  jacStamp[4].resize(3);
185  jacStamp[4][0]=0;
186  jacStamp[4][1]=4;
187  jacStamp[4][2]=5;
188  jacStamp[5].resize(5);
189  jacStamp[5][0]=1;
190  jacStamp[5][1]=2;
191  jacStamp[5][2]=3;
192  jacStamp[5][3]=4;
193  jacStamp[5][4]=7;
194  jacStamp[6].resize(3);
195  jacStamp[6][0]=2;
196  jacStamp[6][1]=6;
197  jacStamp[6][2]=7;
198  jacStamp[7].resize(5);
199  jacStamp[7][0]=0;
200  jacStamp[7][1]=1;
201  jacStamp[7][2]=3;
202  jacStamp[7][3]=5;
203  jacStamp[7][4]=6;
204  }
205 
206  // Set params to constant default values:
207  setDefaultParams ();
208 
209  // Set params according to instance line and constant defaults from metadata:
210  setParams (instance_block.params);
211 
212  // Set any non-constant parameter defaults:
213 
214  // Calculate any parameters specified as expressions:
216 
217  // calculate dependent (ie computed) params and check for errors:
218  if (!given("Z0"))
219  {
220  if (given("ZO"))
221  Z0 = ZO;
222  else
223  {
224  UserError0(*this) << "Z0 not given.";
225  }
226  }
227  if (Z0>0)
228  {
229  G0 = 1.0/Z0;
230  }
231  else
232  {
233  UserError0(*this) << "Invalid (zero or negative) impedance given.";
234  }
235 
236  // Must give either TD or F.
237  if (!given("TD") && !given("F"))
238  {
239  UserError0(*this) << "Neither time delay (TD) nor frequency (F) given.";
240  }
241  if (given("TD") && given("F"))
242  {
243  UserError0(*this) << "Both time delay (TD) and frequency (F) given. Pick one.";
244  }
245 
246  if (!given("TD") && freq > 0)
247  {
248  td = NL/freq;
249  }
250  else if (!given("TD"))
251  {
252  UserError0(*this) << "Zero or negative frequency given.";
253  }
254  if (td == 0)
255  {
256  UserError0(*this) << "Zero time delay.";
257  }
258 
259 
260  processParams();
261 
262  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
263  {
264  Xyce::dout() << " Z0 = " << Z0 << std::endl;
265  Xyce::dout() << " td = " << td << std::endl;
266  Xyce::dout() << " freq = " << freq << std::endl;
267  Xyce::dout() << " NL = " << NL << std::endl;
268  }
269 }
270 
271 //-----------------------------------------------------------------------------
272 // Function : Instance::processParams
273 // Purpose :
274 // Special Notes :
275 // Scope : public
276 // Creator : Tom Russo, SNL, Component Information and Models
277 // Creation Date : 7/02/04
278 //-----------------------------------------------------------------------------
280 {
281  bool bsuccess = true;
282  return bsuccess;
283 }
284 
285 //-----------------------------------------------------------------------------
286 // Function : Instance::~Instance
287 // Purpose : destructor
288 // Special Notes :
289 // Scope : public
290 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
291 // Creation Date : 3/16/00
292 //-----------------------------------------------------------------------------
294 {
295 }
296 
297 // Additional Declarations
298 
299 //-----------------------------------------------------------------------------
300 // Function : Instance::registerLIDs
301 // Purpose : function for registering, and setting up, local ID's.
302 // Special Notes :
303 // Scope : public
304 // Creator : Robert Hoekstra, SNL, Computational Sciences
305 // Creation Date : 6/21/02
306 //-----------------------------------------------------------------------------
307 void Instance::registerLIDs( const std::vector<int> & intLIDVecRef,
308  const std::vector<int> & extLIDVecRef )
309 {
310  AssertLIDs(intLIDVecRef.size() == numIntVars);
311  AssertLIDs(extLIDVecRef.size() == numExtVars);
312 
313  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
314  {
315  Xyce::dout() << std::endl << section_divider << std::endl;
316  Xyce::dout() << "In Instance::registerLIDs\n\n";
317  Xyce::dout() << "name = " << getName() << std::endl;
318  Xyce::dout() << "number of internal variables: " << numIntVars << std::endl;
319  Xyce::dout() << "number of external variables: " << numExtVars << std::endl;
320  }
321 
322  // copy over the global ID lists.
323  intLIDVec = intLIDVecRef;
324  extLIDVec = extLIDVecRef;
325 
326  // Now use these lists to obtain the indices into the linear algebra
327  // entities. This assumes an order.
328 
329  li_Pos1 = extLIDVec[0];
330  li_Neg1 = extLIDVec[1];
331  li_Pos2 = extLIDVec[2];
332  li_Neg2 = extLIDVec[3];
333 
334  // Now do the internal variables
335 
336  li_Int1 = intLIDVec[0];
337  li_Ibr1 = intLIDVec[1];
338  li_Int2 = intLIDVec[2];
339  li_Ibr2 = intLIDVec[3];
340 
341  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
342  {
343  Xyce::dout() << " VARIABLE Indicies " << std::endl;
344  Xyce::dout() << "li_Pos1 = " << li_Pos1 << std::endl;
345  Xyce::dout() << "li_Neg1 = " << li_Neg1 << std::endl;
346  Xyce::dout() << "li_Int1 = " << li_Int1 << std::endl;
347  Xyce::dout() << "li_Ibr1 = " << li_Ibr1 << std::endl;
348  Xyce::dout() << "li_Pos2 = " << li_Pos2 << std::endl;
349  Xyce::dout() << "li_Neg2 = " << li_Neg2 << std::endl;
350  Xyce::dout() << "li_Int2 = " << li_Int2 << std::endl;
351  Xyce::dout() << "li_Ibr2 = " << li_Ibr2 << std::endl;
352 
353  Xyce::dout() << "\nEnd of Instance::register LIDs\n";
354  Xyce::dout() << section_divider << std::endl;
355  }
356 }
357 //-----------------------------------------------------------------------------
358 // Function : Instance::loadNodeSymbols
359 // Purpose :
360 // Special Notes :
361 // Scope : public
362 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
363 // Creation Date : 05/13/05
364 //-----------------------------------------------------------------------------
365 void Instance::loadNodeSymbols(Util::SymbolTable &symbol_table) const
366 {
367  addInternalNode(symbol_table, li_Int1, getName(), "int1");
368  addInternalNode(symbol_table, li_Int2, getName(), "int2");
369  addInternalNode(symbol_table, li_Ibr1, getName(), "i1");
370  addInternalNode(symbol_table, li_Ibr2, getName(), "i2");
371 
372  if (loadLeadCurrent)
373  {
374  addStoreNode(symbol_table, li_store_dev_i1, getName(), "DEV_I1");
375  addStoreNode(symbol_table, li_store_dev_i2, getName(), "DEV_I2");
376  }
377 }
378 
379 //-----------------------------------------------------------------------------
380 // Function : Instance::registerStateLIDs
381 // Purpose :
382 // Special Notes :
383 // Scope : public
384 // Creator : Robert Hoekstra, SNL, Computational Sciences
385 // Creation Date : 6/21/02
386 //-----------------------------------------------------------------------------
387 void Instance::registerStateLIDs( const std::vector<int> & staLIDVecRef)
388 {
389  AssertLIDs(staLIDVecRef.size() == numStateVars);
390 }
391 
392 //-----------------------------------------------------------------------------
393 // Function : Instance::registerStoreLIDs
394 // Purpose : One store var for device current.
395 // Special Notes :
396 // Scope : public
397 // Creator : Richard Schiek, Electrical Systems Modeling
398 // Creation Date : 04/05/2013
399 //-----------------------------------------------------------------------------
400 void Instance::registerStoreLIDs(const std::vector<int> & stoLIDVecRef )
401 {
402  AssertLIDs(stoLIDVecRef.size() == getNumStoreVars());
403 
404  if( loadLeadCurrent )
405  {
406  li_store_dev_i1 = stoLIDVecRef[0];
407  li_store_dev_i2 = stoLIDVecRef[1];
408  }
409 }
410 
411 //-----------------------------------------------------------------------------
412 // Function : Instance::jacobianStamp
413 // Purpose :
414 // Special Notes :
415 // Scope : public
416 // Creator : Robert Hoekstra, SNL, Computational Sciences
417 // Creation Date : 9/2/02
418 //-----------------------------------------------------------------------------
419 const std::vector< std::vector<int> > & Instance::jacobianStamp() const
420 {
421  return jacStamp;
422 }
423 
424 //-----------------------------------------------------------------------------
425 // Function : Instance::registerJacLIDs
426 // Purpose :
427 // Special Notes :
428 // Scope : public
429 // Creator : Robert Hoekstra, SNL, Computational Sciences
430 // Creation Date : 9/2/02
431 //-----------------------------------------------------------------------------
432 void Instance::registerJacLIDs( const std::vector< std::vector<int> > & jacLIDVec )
433 {
434  DeviceInstance::registerJacLIDs( jacLIDVec );
435  APos1EquPos1NodeOffset = jacLIDVec[0][0];
436  APos1EquInt1NodeOffset = jacLIDVec[0][1];
437 
438  ANeg1EquIbr1NodeOffset = jacLIDVec[1][0];
439 
440  APos2EquPos2NodeOffset = jacLIDVec[2][0];
441  APos2EquInt2NodeOffset = jacLIDVec[2][1];
442 
443  ANeg2EquIbr2NodeOffset = jacLIDVec[3][0];
444 
445  AInt1EquPos1NodeOffset = jacLIDVec[4][0];
446  AInt1EquInt1NodeOffset = jacLIDVec[4][1];
447  AInt1EquIbr1NodeOffset = jacLIDVec[4][2];
448 
449  AIbr1EquNeg1NodeOffset = jacLIDVec[5][0];
450  AIbr1EquPos2NodeOffset = jacLIDVec[5][1];
451  AIbr1EquNeg2NodeOffset = jacLIDVec[5][2];
452  AIbr1EquInt1NodeOffset = jacLIDVec[5][3];
453  AIbr1EquIbr2NodeOffset = jacLIDVec[5][4];
454 
455  AInt2EquPos2NodeOffset = jacLIDVec[6][0];
456  AInt2EquInt2NodeOffset = jacLIDVec[6][1];
457  AInt2EquIbr2NodeOffset = jacLIDVec[6][2];
458 
459  AIbr2EquPos1NodeOffset = jacLIDVec[7][0];
460  AIbr2EquNeg1NodeOffset = jacLIDVec[7][1];
461  AIbr2EquNeg2NodeOffset = jacLIDVec[7][2];
462  AIbr2EquIbr1NodeOffset = jacLIDVec[7][3];
463  AIbr2EquInt2NodeOffset = jacLIDVec[7][4];
464 
465 }
466 
467 //-----------------------------------------------------------------------------
468 // Function : Instance::loadDAEFVector
469 //
470 // Purpose : Loads the F-vector contributions for a single
471 // TRA instance.
472 //
473 // Special Notes :
474 //
475 // Scope : public
476 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
477 // Creation Date : 02/19/05
478 //-----------------------------------------------------------------------------
480 {
481  bool bsuccess = true;
482 
483  double coef_pos1;
484  double coef_neg1;
485  double coef_int1;
486  double coef_ibr1;
487  double coef_pos2;
488  double coef_neg2;
489  double coef_int2;
490  double coef_ibr2;
491 
492  double * fVec = extData.daeFVectorRawPtr;
493 
494  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
495  {
496  Xyce::dout() << subsection_divider << std::endl;
497  Xyce::dout() << " Instance::loadDAEFVector" << std::endl;
498  Xyce::dout() << " name = " << getName() <<std::endl;
499  }
500 
501  // Most of the work has already been done by uIVB.
502  coef_pos1 = (Vpos1-Vint1)*G0;
503  coef_neg1 = -Ibr1;
504  coef_int1 = -(Vpos1-Vint1)*G0+Ibr1;
505  coef_ibr1 = ((Vint1-Vneg1)-v1);
506  coef_pos2 = (Vpos2-Vint2)*G0;
507  coef_neg2 = -Ibr2;
508  coef_int2 = -(Vpos2-Vint2)*G0+Ibr2;
509  coef_ibr2 = ((Vint2-Vneg2)-v2);
510 
511 
512  fVec[li_Pos1] += coef_pos1;
513  fVec[li_Neg1] += coef_neg1;
514  fVec[li_Int1] += coef_int1;
515  fVec[li_Ibr1] += coef_ibr1;
516  fVec[li_Pos2] += coef_pos2;
517  fVec[li_Neg2] += coef_neg2;
518  fVec[li_Int2] += coef_int2;
519  fVec[li_Ibr2] += coef_ibr2;
520 
521  if( loadLeadCurrent )
522  {
523  double * stoVec = extData.nextStoVectorRawPtr;
524  stoVec[li_store_dev_i1] = Ibr1;
525  stoVec[li_store_dev_i2] = -Ibr2;
526  }
527 
528  return bsuccess;
529 }
530 
531 //-----------------------------------------------------------------------------
532 // Function : Instance::loadDAEdFdx ()
533 //
534 // Purpose : Loads the F-vector contributions for a single device instance.
535 //
536 // Special Notes : The F-vector is an algebraic constaint.
537 //
538 // The special notes below are those that were taken from
539 // the old loadAnalyticJacobian header. The matrix
540 // it describes is the full jacobian matrix:
541 //----------------------------------------------------------------------
542 // Special Notes : This is based on there being two two-node ports
543 // and a model of the following sort:
544 //
545 // Pos1 o-----+ +------o Pos2
546 // | |
547 // \ \
548 // / /
549 // \Z0 \ Z0
550 // / /
551 // | |
552 // oInt1 o Int2
553 // | |
554 // ++++++ ++++++
555 // | V1 | | V2 |
556 // ------ ------
557 // | |
558 // Neg1 o-----+ +------o Neg2
559 //
560 // There are also two branch currents, Ibr1 and Ibr2 for left and right
561 // sides as well.
562 //
563 // The matrix for this ends up being:
564 // V_Pos1 V_Neg1 V_Int1 Ibr1 V_Pos2 V_Neg2 V_Int2 V_Ibr2
565 // ------------------------------------------------------------
566 // KCL Pos1 a b
567 // KCL Neg1 c
568 // KCL Int1 d e f
569 // KCL Ibr1 g h i j k
570 // KCL Pos2 l m
571 // KCL Neg2 n
572 // KCL Int2 o p q
573 // KCL Ibr2 r s t u v
574 //
575 // When doing time integration, i,j,k,r,s and t are zero, those dependences
576 // are time-delayed, i.e. the equations for the output depend on time-delayed
577 // of the input. For DC calculations, i,j,k,r,s and t are non-zero.
578 //
579 // The right hand sides are:
580 // Pos1: (V_int1-V_Pos1)*G0 Pos2: (V_Int2-V_Pos2)*G0
581 // Neg1: -Ibr1 Neg2: -Ibr2
582 // Int1: (V_Pos1-V_Int1)*G0+Ibr1 Int2: (V_Pos2-V_Int2)*G0+Ibr2
583 // Ibr1: (V_Int1-V_Neg1)-V1 Ibr2: (V_Int2-V_Neg2)-V2
584 //
585 // For transient operation, v1 and v2 depend on values of voltage and
586 // current at delayed time at the opposite port:
587 // V1 = DeltaV2(t-td)+Z0*Ibr2(t-td)
588 // V2 = DeltaV1(t-td)+Z0*Ibr1(t-td)
589 //
590 // For DC operation V1=VPos2-Vneg2+Ibr2*Z0, V2 = Vpos1-Vneg1+Ibr1*Z0
591 //--------------------------------------------------------------------
592 //
593 // Scope : public
594 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
595 // Creation Date : 02/19/05
596 //-----------------------------------------------------------------------------
598 {
599  Linear::Matrix & dFdx = *(extData.dFdxMatrixPtr);
600 
601  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
602  {
603  Xyce::dout() << subsection_divider << std::endl;
604  Xyce::dout() << " name = " << getName() << std::endl;
605  }
606 
607 
609 
611 
612 
614 
616 
617  dFdx[li_Int1][AInt1EquIbr1NodeOffset] += 1.0;
618 
619 
620  dFdx[li_Neg1][ANeg1EquIbr1NodeOffset] -= 1.0;
621 
622 
623  dFdx[li_Ibr1][AIbr1EquInt1NodeOffset] += 1.0;
624 
625  dFdx[li_Ibr1][AIbr1EquNeg1NodeOffset] -= 1.0;
626  if( DCMODE )
627  {
628 
629  dFdx[li_Ibr1][AIbr1EquPos2NodeOffset] -= 1.0;
630 
631  dFdx[li_Ibr1][AIbr1EquNeg2NodeOffset] += 1.0;
632 
634  }
635 
636 
638 
640 
641 
643 
645 
646  dFdx[li_Int2][AInt2EquIbr2NodeOffset] += 1.0;
647 
648 
649  dFdx[li_Neg2][ANeg2EquIbr2NodeOffset] -= 1.0;
650 
651 
652  dFdx[li_Ibr2][AIbr2EquInt2NodeOffset] += 1.0;
653 
654  dFdx[li_Ibr2][AIbr2EquNeg2NodeOffset] -= 1.0;
655  if( DCMODE )
656  {
657 
658  dFdx[li_Ibr2][AIbr2EquPos1NodeOffset] -= 1.0;
659 
660  dFdx[li_Ibr2][AIbr2EquNeg1NodeOffset] += 1.0;
661 
663  }
664 
665 
666  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
667  Xyce::dout() << subsection_divider << std::endl;
668 
669  return true;
670 }
671 
672 //-----------------------------------------------------------------------------
673 // Function : Instance::updatePrimaryState
674 // Purpose : update primary state for one TRA instance
675 // Special Notes :
676 // Scope : public
677 // Creator : Tom Russo, SNL, Component Information and Models
678 // Creation Date : 1/10/01
679 //-----------------------------------------------------------------------------
681 {
682  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
683  {
684  Xyce::dout() << std::endl << subsection_divider << std::endl;
685  Xyce::dout() << "In TRA::updatePrimaryState\n";
686  Xyce::dout() << " last_t is " << last_t << std::endl;
687  Xyce::dout() << " v1 is " << v1 << std::endl;
688  Xyce::dout() << " v2 is " << v2 << std::endl;
689  }
690 
691  return updateIntermediateVars ();
692 }
693 
694 //-----------------------------------------------------------------------------
695 // Function : Instance::updateIntermediateVars
696 // Purpose : update intermediate variables for one TRA instance
697 // Special Notes :
698 // Scope : public
699 // Creator : Tom Russo, Component Information and Models
700 // Creation Date : 1/10/01
701 //-----------------------------------------------------------------------------
703 {
704  double * solVec = extData.nextSolVectorRawPtr; // the current guess
705 
706  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
707  {
708  Xyce::dout() << std::endl << subsection_divider << std::endl;
709  Xyce::dout() << " In ::updateIntermediateVars\n\n";
710  }
711 
712  Vpos1 = Vpos2 = Vneg1 = Vneg2 = Vint1 = Vint2 = 0.0;
713 
714  Vpos1 = solVec[li_Pos1];
715  Vneg1 = solVec[li_Neg1];
716  Vint1 = solVec[li_Int1];
717  Ibr1 = solVec[li_Ibr1];
718  Vpos2 = solVec[li_Pos2];
719  Vneg2 = solVec[li_Neg2];
720  Vint2 = solVec[li_Int2];
721  Ibr2 = solVec[li_Ibr2];
722 
723  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
724  {
725  Xyce::dout() << " Vpos1 = " << Vpos1 << std::endl;
726  Xyce::dout() << " Vneg1 = " << Vneg1 << std::endl;
727  Xyce::dout() << " Vint1 = " << Vint1 << std::endl;
728  Xyce::dout() << " Ibr1 = " << Ibr1 << std::endl;
729  Xyce::dout() << " Vpos2 = " << Vpos2 << std::endl;
730  Xyce::dout() << " Vneg2 = " << Vneg2 << std::endl;
731  Xyce::dout() << " Vint2 = " << Vint2 << std::endl;
732  Xyce::dout() << " Ibr2 = " << Ibr2 << std::endl;
733  }
734 
735  // Test if we're doing DC or Transient
736  if ((getSolverState().dcopFlag))
737  {
738  // DC operation
739  DCMODE=true;
740  v1 = (Vpos2-Vneg2)+Z0*Ibr2;
741  v2 = (Vpos1-Vneg1)+Z0*Ibr1;
742  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
743  Xyce::dout() << "DC Mode, V1 = " << v1 << ", V2 = " << v2 << std::endl;
744  }
745  else
746  {
747  double currentTime = getSolverState().currTime;
748  DCMODE=false;
749  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
750  {
751  Xyce::dout() << "Not DC, newtonIter = " << getSolverState().newtonIter;
752  Xyce::dout() << " Time is " << currentTime << std::endl;
753  }
754  // Transient operation
755  // Now determine if we're on the first newton step of an iteration
756  if (getSolverState().newtonIter == 0 && (currentTime != timeOld))
757  {
758  timeOld = currentTime;
759  // we are, so need to manipulate history and calculate v1,v2.
760  // If we're the first time step, we need to initialize it
761  if (getSolverState().initTranFlag)
762  {
763  last_t = currentTime;
764  v1 = (Vpos2-Vneg2)+Z0*Ibr2;
765  v2 = (Vpos1-Vneg1)+Z0*Ibr1;
766 
767  history.clear();
768  history.push_back(History(-2*td,v1,v2));
769  history.push_back(History(-td,v1,v2));
770  history.push_back(History(0,v1,v2));
771  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
772  {
773  Xyce::dout() << "Transient, first time, T = ";
774  Xyce::dout() << currentTime;
775  Xyce::dout() << ", V1 = " << v1;
776  Xyce::dout() << ", V2 = " << v2 << std::endl;
777  }
778  }
779  else
780  {
781  double delayedTime = currentTime-td;
782 
783  // now get the values of v1 and v2 from the delayed-time
784  // information
785  InterpV1V2FromHistory(delayedTime, &v1, &v2);
786  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
787  {
788  Xyce::dout() << " Done with interpolation to delayedTime=";
789  Xyce::dout() << delayedTime;
790  Xyce::dout() << ", have v1="<<v1 << " and v2=" << v2 << std::endl;
791  Xyce::dout() << " INTERP " << delayedTime << " " << v1 << " " << v2 << std::endl;
792  Xyce::dout() << " Set last_t to " << currentTime << std::endl;
793  }
794  // now save the current time so we can have it next time
795  // we get to this block (i.e. on the next time step)
796  last_t = currentTime;
797  }
798  }
799  else
800  {
801  // we're on the second iteration or later of the second time
802  // step or later. Re-use the values of v1 and v2 from the
803  // first iteration of this time step. We don't care what time
804  // it is
805  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
806  {
807  Xyce::dout() << "second or later iteration, t is " << currentTime;
808  Xyce::dout() << " have last_t = " << last_t << " v1="<<v1 << " and v2=" << v2 << std::endl;
809  }
810  }
811  }
812  return true;
813 }
814 
815 //-----------------------------------------------------------------------------
816 // Function : Instance::pruneHistory
817 // Purpose : sift through the transmission line state history and
818 // delete records that are so old they'll never be used again
819 // Special Notes :
820 // Scope : private
821 // Creator : Tom Russo, SNL, Component Information and Models
822 // Creation Date : 6/15/2001
823 //-----------------------------------------------------------------------------
824 
825 void Instance::pruneHistory(double t1)
826 {
827 
828  // The input t is the oldest time for which we'll ever interpolate again.
829  // That means we only need two times in the history that are older than t1,
830  // so this routine drops everything off the head but the most recent 2 that
831  // are older than t.
832 
833  std::vector<History>::iterator first = history.begin();
834  std::vector<History>::iterator it1;
835  std::vector<History>::iterator last = history.end();
836  int i;
837 
838  last--; // point to last stored item, not end of the list!
839  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
840  {
841  Xyce::dout() << Xyce::section_divider << std::endl;
842  Xyce::dout() << "Pruning for time t1="<<t1 << std::endl;
843  Xyce::dout() << " Oldest in list is t="<<first->t<<" v1 = "<<first->v1 <<
844  " v2="<<first->v2 << std::endl;
845  Xyce::dout() << " latest in list is t="<<last->t<<" v1 = "<<last->v1
846  << " v2="<<last->v2 << std::endl;
847  }
848  // First find the first element for which the stored time is greater than t
849  for (it1 = first, i = 0; it1->t < t1 && it1 != last; ++it1, ++i)
850  {
851  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
852  {
853  Xyce::dout() << "i = " << i << " t = " << it1->t;
854  Xyce::dout() << " v1 = " << it1->v1;
855  Xyce::dout() << " v2 = " << it1->v2 << std::endl;
856  }
857  }
858 
859  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
860  {
861  Xyce::dout() << " i ="<<i << std::endl;
862  }
863 
864  // Now it1 points to the first element with t>t1
865  if (i > 2)
866  {
867  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
868  {
869  Xyce::dout() << "Need to prune. Keeping " << it1->t << std::endl;
870  }
871  // if i>2 we have too many old ones.
872  // back up 2
873  it1--;
874  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
875  {
876  Xyce::dout() << " Keeping " << it1->t << std::endl;
877  }
878 
879  it1--;
880  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
881  {
882  Xyce::dout() << " Keeping " << it1->t << std::endl;
883  }
884  // delete everything from the first to it1, not counting it1
885  history.erase(first,it1);
886  }
887  // otherwise we don't need to do anything.
888  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
889  {
890  Xyce::dout() << Xyce::section_divider << std::endl;
891  }
892 }
893 
894 
895 //-----------------------------------------------------------------------------
896 // Function : Instance::InterpV1V2FromHistory
897 // Purpose : Use 3-point lagrange interpolation to determine
898 // v1(t) and v2(t) at a specified time in the past
899 // Special Notes :
900 // Scope : private
901 // Creator : Tom Russo, SNL, Component Information and Models
902 // Creation Date : 6/15/2001
903 //-----------------------------------------------------------------------------
904 void Instance::InterpV1V2FromHistory(double t, double * v1p,
905  double *v2p)
906 {
907  std::vector<History>::iterator first = history.begin();
908  std::vector<History>::iterator it1;
909  std::vector<History>::iterator last = history.end();
910  double t1,t2,t3;
911  double dt1,dt2,dt3;
912  double v11,v21,v12,v22,v13,v23;
913  double dt12,dt13,dt23;
914  double f1,f2,f3; // interpolating functions
915 
916  if (history.size() <= 0)
917  {
918  std::string msg;
919  msg="Instance::InterpV1V2FromHistory called but history list is"
920  " empty. Might be due to trying to restart this netlist.\n"
921  "Restarts of netlists with transmission lines does not work yet.\n";
922  N_ERH_ErrorMgr::report( N_ERH_ErrorMgr::DEV_FATAL, msg);
923  }
924 
925  last--; // point to the last stored item, not the tail of the list!
926  // sanity clause (you canna foola me, I know they're ain'ta no sanity
927  // clause!)
928  // if (t < first->t || t > last->t)
929  if (t - first->t < -Util::MachineDependentParams::MachinePrecision()
930  || t - last->t > Util::MachineDependentParams::MachinePrecision() )
931  {
932  UserError(*this) << "Cannot interpolate to a time (" << t << ") prior to oldest("
933  << first->t << ") or after newest(" << last->t << ") in history";
934  return;
935  }
936 
937  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
938  {
939  Xyce::dout() << " interpolating for t = " << t << std::endl;
940  }
941 
942  // If we are within roundoff of the endpoints of the history, just use
943  // the endpoints, otherwise interpolate to get it.
944  if ( fabs(t-first->t)<Util::MachineDependentParams::MachinePrecision())
945  {
946  *v1p = first->v1;
947  *v2p = first->v2;
948  }
949  else if ( fabs(t-last->t)<Util::MachineDependentParams::MachinePrecision())
950  {
951  *v1p = last->v1;
952  *v2p = last->v2;
953  }
954  else
955  {
956 
957  LessThan<History,double> lessFunct;
958  it1 = lower_bound(history.begin(),history.end(),t,lessFunct);
959 
960  // Now it1 points to the first element with time > t
961  t3 = it1->t;
962  v13 = it1->v1;
963  v23 = it1->v2;
964  it1--;
965  t2 = it1->t;
966  v12 = it1->v1;
967  v22 = it1->v2;
968  it1--;
969  t1 = it1->t;
970  v11 = it1->v1;
971  v21 = it1->v2;
972 
973  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
974  {
975  Xyce::dout() << "Using time t3="<<t3<<" v1(t3)="<<v13<<" v2(t3)="<<v23 << std::endl;
976  Xyce::dout() << "Using time t2="<<t2<<" v1(t2)="<<v12<<" v2(t2)="<<v22 << std::endl;
977  Xyce::dout() << "Using time t1="<<t1<<" v1(t1)="<<v11<<" v2(t1)="<<v21 << std::endl;
978  }
979 
980  // now we have three values of each function to be interpolated, and three
981  // times. t3 is after the desired time, t1 and t2 are before (t2 might be
982  // equal to the desired time)
983  // Set up the differences for lagrange interpolation:
984  dt12 = t1-t2;
985  dt13 = t1-t3;
986  dt23 = t2-t3;
987  dt1 = t-t1;
988  dt2 = t-t2;
989  dt3 = t-t3;
990  // now we set up the lagrange interpolating functions
991  // e.g. f1 = (t-t2)*(t-t3)/((t1-t2)*(t1-t3))
992  // so that fi is 1 at ti and 0 at the other times.
993  f1 = dt2*dt3;
994  f2 = dt1*dt3;
995  f3 = dt1*dt2;
996  if (dt12 != 0)
997  {
998  f1 /= dt12;
999  f2 /= -dt12;
1000  }
1001  else
1002  {
1003  f1 = f2 = 0.0;
1004  }
1005  if (dt13 != 0)
1006  {
1007  f1 /= dt13;
1008  f3 /= -dt13;
1009  }
1010  else
1011  {
1012  f1 = f2 = 0.0;
1013  }
1014  if (dt23 != 0)
1015  {
1016  f2 /= dt23;
1017  f3 /= -dt23;
1018  }
1019  else
1020  {
1021  f2 = f3 = 0.0;
1022  }
1023  // that's it, we have the interpolation functions evaluated at the time t,
1024  // and the values of v1 and v2 at the points, perform the interpolation
1025  *v1p = f1*v11+f2*v12+f3*v13;
1026  *v2p = f1*v21+f2*v22+f3*v23;
1027  }
1028 
1029 }
1030 
1031 //-----------------------------------------------------------------------------
1032 // Function : Instance::getInstanceBreakPoints
1033 // Purpose : This function adds break points to a vector of breakpoints.
1034 //
1035 // It does not bother to check them in any way, or put them
1036 // in order. It only adds them in.
1037 //
1038 // Special Notes : The guts of this has been moved to acceptStep, which
1039 // actually computes the breakpoints if needed. We only add
1040 // them to the list here if necessary.
1041 //
1042 // Scope : public
1043 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1044 // Creation Date : 06/08/01
1045 //-----------------------------------------------------------------------------
1046 bool Instance::getInstanceBreakPoints ( std::vector<Util::BreakPoint> & breakPointTimes )
1047 {
1048  bool bsuccess = true;
1049 
1050  double currentTime = getSolverState().currTime;
1051  int timeStep = getSolverState().timeStepNumber;
1052 
1053  // We're called once prior to any newton iterations, not even the
1054  // DC Op point. Never do anything if first_BP_call_done is false.
1055 
1056  if (timeStep != 0 && first_BP_call_done)
1057  {
1058  if (newBreakPoint)
1059  {
1060  breakPointTimes.push_back(newBreakPointTime);
1061  newBreakPoint = false;
1062  }
1063  }
1064  else
1065  {
1066  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1067  {
1068  Xyce::dout() << " In Instance::getBreakPoints "<<std::endl;
1069  Xyce::dout() << " First time step, I don't get to set breakpoints. Time is ";
1070  Xyce::dout() << currentTime << std::endl;
1071  }
1072  }
1073 
1074  first_BP_call_done=true;
1075  return bsuccess;
1076 }
1077 
1078 //-----------------------------------------------------------------------------
1079 // Function : Instance::acceptStep
1080 // Purpose : This function saves the values of v1 and v2 along with
1081 // the current time. It is to be called ONLY at the point
1082 // when the time integrator has determined we've got a
1083 // converged, acceptable solution and is accepting it,
1084 // but before it's updated its times and rotated vectors.
1085 //
1086 // Special Notes : In SPICE this same stuff was done in the "TRAaccept" function.
1087 //
1088 // Scope : public
1089 // Creator : Tom Russo, SNL
1090 // Creation Date : 01/23/07
1091 //-----------------------------------------------------------------------------
1093 {
1094  if (!getSolverState().dcopFlag)
1095  {
1096  double currentTime = getSolverState().currTime;
1097 
1098  double d11, d21, d12, d22;
1099  Linear::Vector *theSolVectorPtr = extData.nextSolVectorPtr;// the accepted
1100  // values from this
1101  // step
1102 
1103  std::vector<History>::iterator last = history.end();
1104 
1105  last--; // point to last item, not past last item.
1106 
1107  // We're called once prior to any newton iterations, not even the
1108  // DC Op point. Never do anything if first_BP_call_done is false.
1109  double oVp1,oVp2,oVn1,oVn2,oI1,oI2;
1110  double ov1,ov2;
1111  double tmp_v1,tmp_v2, tmp_t;
1112 
1113  double oVi1,oVi2;
1114  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1115  {
1116  Xyce::dout() << " In Instance::acceptStep "<<std::endl;
1117  Xyce::dout() << "I want breakpoints. Time is " << currentTime << std::endl;
1118  Xyce::dout() << " timeOld is " << timeOld << std::endl;
1119  }
1120 
1121  // we're the end of a time step, the solution has been accepted.
1122  // clean up the history by deleting records of times so far
1123  // back that they'll never be used for interpolation again
1124  // never try to prune history for anything but times that have
1125  // been accepted already.
1126  // TVR: The goal of this was to prune the early history so we don't
1127  // get unbounded growth of the history vector, with the intent of making
1128  // the interpolation method faster. Turns out that deleting these vector
1129  // elements is very expensive, much more expensive than using "lower_bound"
1130  // to find a value in the long list. So I'm commenting this out.
1131  // double delayedTime;
1132  // if (timeOld != -1)
1133  // {
1134  // delayedTime = timeOld-td;
1135  // pruneHistory(delayedTime);
1136  // }
1137 
1138  oVp1 = (*theSolVectorPtr)[li_Pos1];
1139  oVn1 = (*theSolVectorPtr)[li_Neg1];
1140  oI1 = (*theSolVectorPtr)[li_Ibr1];
1141  oVp2 = (*theSolVectorPtr)[li_Pos2];
1142  oVn2 = (*theSolVectorPtr)[li_Neg2];
1143  oI2 = (*theSolVectorPtr)[li_Ibr2];
1144 
1145  // Having the old values means we can calculate what v1 and v2
1146  // were for that time.
1147  ov1=(oVp2-oVn2)+Z0*oI2;
1148  ov2=(oVp1-oVn1)+Z0*oI1;
1149 
1150  if (DEBUG_DEVICE)
1151  {
1152  oVi1 = (*theSolVectorPtr)[li_Int1];
1153  oVi2 = (*theSolVectorPtr)[li_Int2];
1154 
1155  if (isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1156  {
1157  Xyce::dout() << " ----- New time step -----" << std::endl;
1158  Xyce::dout() << " Last solution : " << std::endl;
1159  Xyce::dout() << " vpos1 = " << oVp1 << std::endl;
1160  Xyce::dout() << " vneg1 = " << oVn1 << std::endl;
1161  Xyce::dout() << " vint1 = " << oVi1 << std::endl;
1162  Xyce::dout() << " ibr1 = " << oI1 << std::endl;
1163  Xyce::dout() << " vpos2 = " << oVp2 << std::endl;
1164  Xyce::dout() << " vneg2 = " << oVn2 << std::endl;
1165  Xyce::dout() << " vint2 = " << oVi2 << std::endl;
1166  Xyce::dout() << " ibr2 = " << oI2 << std::endl;
1167  Xyce::dout() << "in set breakpoints, saving for time=" << currentTime << ", V1 = " << ov1 << ", V2 = " << ov2 << std::endl;
1168  Xyce::dout() << " V1V2DBG " << currentTime << " " << ov1 << " " << ov2 << std::endl;
1169  }
1170  }
1171 
1172  history.push_back(History(currentTime,ov1,ov2));
1173 
1174  last = history.end();
1175  last--; // point to last item, not past last item.
1176  // Now calculate derivatives based on history
1177  tmp_v1 = last->v1; tmp_v2 = last->v2; tmp_t = last->t;
1178  last--;
1179  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1180  {
1181  Xyce::dout() << "tmp_t=" << tmp_t << " last->t =" << last->t << std::endl;
1182  Xyce::dout() << "tmp_v1=" << tmp_v1 << " last->v1=" << last->v1 << std::endl;
1183  Xyce::dout() << "tmp_v2=" << tmp_v2 << " last->v2=" << last->v2 << std::endl;
1184  }
1185  d11 = (tmp_v1-last->v1)/(tmp_t-last->t);
1186  d12 = (tmp_v2-last->v2)/(tmp_t-last->t);
1187  tmp_v1 = last->v1; tmp_v2 = last->v2; tmp_t = last->t;
1188  last--;
1189  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1190  {
1191  Xyce::dout() << "tmp_t=" << tmp_t << " last->t =" << last->t << std::endl;
1192  Xyce::dout() << "tmp_v1=" << tmp_v1 << " last->v1=" << last->v1 << std::endl;
1193  Xyce::dout() << "tmp_v2=" << tmp_v2 << " last->v2=" << last->v2 << std::endl;
1194  }
1195  d21 = (tmp_v1-last->v1)/(tmp_t-last->t);
1196  d22 = (tmp_v2-last->v2)/(tmp_t-last->t);
1197  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1198  {
1199  Xyce::dout() << "Derivs are " << d11 << " " << d21 << std::endl;
1200  Xyce::dout() << " and " << d12 << " " <<d22 << std::endl;
1201  Xyce::dout() << " fabs(d11-d21) = " << fabs(d11-d21) << std::endl;
1202  Xyce::dout() << " fabs(d12-d22) = " << fabs(d12-d22) << std::endl;
1203  Xyce::dout() << "D1D2DBG " << currentTime << " " << d11 << " " << d12 << std::endl;
1204  }
1205 
1206  if ((fabs(d11-d21) >= .99*std::max(fabs(d11),fabs(d21))+1) ||
1207  (fabs(d12-d22) >= .99*std::max(fabs(d12),fabs(d22))+1))
1208  {
1209  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1210  {
1211  Xyce::dout() << "Derivative is changing enough, I want to set a break point ";
1212  Xyce::dout() << td << " ahead of discontinuity, which is ";
1213  Xyce::dout() << tmp_t+td<<std::endl;
1214  }
1215  newBreakPointTime = (tmp_t+td);
1216  newBreakPoint = true;
1217  }
1218  }
1219 }
1220 
1221 //-----------------------------------------------------------------------------
1222 // Function : Instance::getInternalState
1223 // Purpose : Generates an DeviceState object and populates
1224 // it with the contents of the history vector for use by
1225 // restarts
1226 //
1227 // Special Notes :
1228 //
1229 // Scope : public
1230 // Creator : Tom Russo, SNL, Component Information and Models
1231 // Creation Date : 09/03/04
1232 //-----------------------------------------------------------------------------
1233 
1235 {
1236  int hsize,i,j;
1237  // allocate object to return
1238  DeviceState * myState = new DeviceState;
1239 
1240 
1241  myState->ID=getName().getEncodedName();
1242  // We'll pack our history data into the single vector of doubles
1243  myState->data.resize(history.size()*3);
1244  hsize=history.size();
1245  for (i=0;i<hsize;++i)
1246  {
1247  j=i*3;
1248  myState->data[j]=history[i].t;
1249  myState->data[j+1]=history[i].v1;
1250  myState->data[j+2]=history[i].v2;
1251  }
1252 
1253  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1254  {
1255  Xyce::dout() << Xyce::section_divider
1256  << std::endl;
1257  Xyce::dout() << " In Instance::getInternalState " << std::endl;
1258  Xyce::dout() << " name=" << getName() << std::endl;
1259  Xyce::dout() << " history size = " << hsize << std::endl;
1260  Xyce::dout() << " history data: " << std::endl;
1261  for (i = 0 ; i < hsize ; ++i)
1262  {
1263  Xyce::dout() << " (" << history[i].t << ", " << history[i].v1 << ", "
1264  << history[i].v2 << ")"<< std::endl;
1265  }
1266 
1267  Xyce::dout() << " DeviceState ID = " << myState->ID << std::endl;
1268  Xyce::dout() << " DeviceState data size " << myState->data.size() << std::endl;
1269  Xyce::dout() << " Device State data: " << std::endl;
1270  for (i = 0 ; i < myState->data.size() ; ++i)
1271  {
1272  Xyce::dout() << " " << myState->data[i] << std::endl;
1273  }
1274  Xyce::dout() << Xyce::section_divider
1275  << std::endl;
1276  }
1277 
1278  return myState;
1279 }
1280 
1281 //-----------------------------------------------------------------------------
1282 // Function : Instance::setInternalState
1283 // Purpose : Reload history data from restart
1284 //
1285 // Special Notes :
1286 //
1287 // Scope : public
1288 // Creator : Tom Russo, SNL, Component Information and Models
1289 // Creation Date : 09/03/04
1290 //-----------------------------------------------------------------------------
1292 {
1293  int dsize=state.data.size();
1294  int hsize,i,j;
1295  if (getName().getEncodedName() != state.ID)
1296  {
1297  DevelFatal(*this).in("TRA::Instance::setInternal") << "ID(" << state.ID << ") from restart does not match my name (" << getName() << ")";
1298  return false;
1299  }
1300 
1301  if (dsize%3 != 0)
1302  {
1303  UserError(*this) << "Data size from restart (" << dsize << ") not a multiple of 3";
1304  return false;
1305  }
1306 
1307  hsize=dsize/3;
1308  history.clear();
1309  history.resize(hsize);
1310  for ( i=0; i<hsize; ++i)
1311  {
1312  j=i*3;
1313  history[i].t=state.data[j];
1314  history[i].v1=state.data[j+1];
1315  history[i].v2=state.data[j+2];
1316  }
1317 
1318  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1319  {
1320  Xyce::dout() << Xyce::section_divider
1321  << std::endl;
1322  Xyce::dout() << " In Instance::setInternalState " << std::endl;
1323  Xyce::dout() << " name=" << getName() << std::endl;
1324  Xyce::dout() << " history size = " << hsize << std::endl;
1325  Xyce::dout() << " history data: " << std::endl;
1326  for (i = 0 ; i < hsize ; ++i)
1327  {
1328  Xyce::dout() << " (" << history[i].t << ", " << history[i].v1 << ", "
1329  << history[i].v2 << ")"<< std::endl;
1330  }
1331 
1332  Xyce::dout() << " DeviceState ID = " << state.ID << std::endl;
1333  Xyce::dout() << " DeviceState data size " << state.data.size() << std::endl;
1334  Xyce::dout() << " Device State data: " << std::endl;
1335  for (i = 0 ; i < state.data.size() ; ++i)
1336  {
1337  Xyce::dout() << " " << state.data[i] << std::endl;
1338  }
1339  Xyce::dout() << Xyce::section_divider
1340  << std::endl;
1341  }
1342  return true;
1343 }
1344 
1345 // Class Model
1346 
1347 //-----------------------------------------------------------------------------
1348 // Function : Model::processParams
1349 // Purpose :
1350 // Special Notes :
1351 // Scope : public
1352 // Creator : Tom Russo, SNL, Component Information and Models
1353 // Creation Date : 9/25/02
1354 //-----------------------------------------------------------------------------
1356 {
1357  // there are no model parameters to process.
1358  return true;
1359 }
1360 
1361 //----------------------------------------------------------------------------
1362 // Function : Model::processInstanceParams
1363 // Purpose :
1364 // Special Notes :
1365 // Scope : public
1366 // Creator : Dave Shirely, PSSI
1367 // Creation Date : 03/23/06
1368 //----------------------------------------------------------------------------
1370 {
1371 
1372  std::vector<Instance*>::iterator iter;
1373  std::vector<Instance*>::iterator first = instanceContainer.begin();
1374  std::vector<Instance*>::iterator last = instanceContainer.end();
1375 
1376  for (iter=first; iter!=last; ++iter)
1377  {
1378  (*iter)->processParams();
1379  }
1380 
1381  return true;
1382 }
1383 
1384 //-----------------------------------------------------------------------------
1385 // Function : Model::Model
1386 // Purpose : model block constructor
1387 // Special Notes :
1388 // Scope : public
1389 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1390 // Creation Date : 5/16/00
1391 //-----------------------------------------------------------------------------
1393  const Configuration & configuration,
1394  const ModelBlock & MB,
1395  const FactoryBlock & factory_block)
1396  : DeviceModel(MB, configuration.getModelParameters(), factory_block)
1397 {
1398 }
1399 
1400 
1401 //-----------------------------------------------------------------------------
1402 // Function : Model::~Model
1403 // Purpose : destructor
1404 // Special Notes :
1405 // Scope : public
1406 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1407 // Creation Date : 3/16/00
1408 //-----------------------------------------------------------------------------
1410 {
1411  std::vector<Instance*>::iterator iter;
1412  std::vector<Instance*>::iterator first = instanceContainer.begin();
1413  std::vector<Instance*>::iterator last = instanceContainer.end();
1414 
1415  for (iter=first; iter!=last; ++iter)
1416  {
1417  delete (*iter);
1418  }
1419 }
1420 
1421 //-----------------------------------------------------------------------------
1422 // Function : Model::printOutInstances
1423 // Purpose : debugging tool.
1424 // Special Notes :
1425 // Scope : public
1426 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1427 // Creation Date : 4/03/00
1428 //-----------------------------------------------------------------------------
1429 std::ostream &Model::printOutInstances(std::ostream &os) const
1430 {
1431  std::vector<Instance*>::const_iterator iter;
1432  std::vector<Instance*>::const_iterator first = instanceContainer.begin();
1433  std::vector<Instance*>::const_iterator last = instanceContainer.end();
1434 
1435  int i;
1436  os << std::endl;
1437  os << " name model name Parameters" << std::endl;
1438  for (i=0, iter=first; iter!=last; ++iter, ++i)
1439  {
1440  os << " " << i << ": " << (*iter)->getName() << " ";
1441  os << getName();
1442 
1443  os << std::endl;
1444  os << "Z0 = " << (*iter)->Z0 << std::endl;
1445  os << "G0 = " << (*iter)->G0 << std::endl;
1446  os << "TD = " << (*iter)->td << std::endl;
1447  os << "FREQ = " << (*iter)->freq << std::endl;
1448  os << "NL = " << (*iter)->NL << std::endl;
1449 
1450  os << std::endl;
1451  }
1452  os << std::endl;
1453 
1454  return os;
1455 }
1456 
1457 //-----------------------------------------------------------------------------
1458 // Function : Model::forEachInstance
1459 // Purpose :
1460 // Special Notes :
1461 // Scope : public
1462 // Creator : David Baur
1463 // Creation Date : 2/4/2014
1464 //-----------------------------------------------------------------------------
1465 /// Apply a device instance "op" to all instances associated with this
1466 /// model
1467 ///
1468 /// @param[in] op Operator to apply to all instances.
1469 ///
1470 ///
1471 void Model::forEachInstance(DeviceInstanceOp &op) const /* override */
1472 {
1473  for (std::vector<Instance *>::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
1474  op(*it);
1475 }
1476 
1477 
1478 //-----------------------------------------------------------------------------
1479 // Function : Instance::getMaxTimeStepSize
1480 // Purpose :
1481 // Special Notes :
1482 // Scope : public
1483 // Creator : Tom Russo, SNL, Component Information and Models
1484 // Creation Date : 8/01/01
1485 //-----------------------------------------------------------------------------
1487 {
1488  return td;
1489 }
1490 
1491 // Additional Declarations
1492 
1493 // History member (trivial) functions
1494 
1495 //-----------------------------------------------------------------------------
1496 // Function : History::History
1497 // Purpose : default constructor
1498 // Special Notes :
1499 // Scope : public
1500 // Creator : Tom Russo, SNL, Component Information and Models
1501 // Creation Date : 06/14/01
1502 //-----------------------------------------------------------------------------
1504  : t(0),v1(0),v2(0)
1505 {
1506 }
1507 
1508 //-----------------------------------------------------------------------------
1509 // Function : History::History
1510 // Purpose : destructor
1511 // Special Notes :
1512 // Scope : public
1513 // Creator : Tom Russo, SNL, Component Information and Models
1514 // Creation Date : 06/14/01
1515 //-----------------------------------------------------------------------------
1517 {
1518 }
1519 //-----------------------------------------------------------------------------
1520 // Function : History::History
1521 // Purpose : copy constructor
1522 // Special Notes :
1523 // Scope : public
1524 // Creator : Tom Russo, SNL, Component Information and Models
1525 // Creation Date : 06/14/01
1526 //-----------------------------------------------------------------------------
1528  : t(right.t),v1(right.v1),v2(right.v2)
1529 {
1530 }
1531 
1532 //-----------------------------------------------------------------------------
1533 // Function : History::History
1534 // Purpose : copy constructor
1535 // Special Notes :
1536 // Scope : public
1537 // Creator : Tom Russo, SNL, Component Information and Models
1538 // Creation Date : 06/14/01
1539 //-----------------------------------------------------------------------------
1540 History::History(double a, double b, double c)
1541  : t(a),v1(b),v2(c)
1542 {
1543 }
1544 
1545 Device *Traits::factory(const Configuration &configuration, const FactoryBlock &factory_block)
1546 {
1547 
1548  return new DeviceMaster<Traits>(configuration, factory_block, factory_block.solverState_, factory_block.deviceOptions_);
1549 }
1550 
1552 {
1554  .registerDevice("t", 1);
1555 }
1556 
1557 } // namespace TRA
1558 } // namespace Device
1559 } // namespace Xyce
const InstanceName & getName() const
void InterpV1V2FromHistory(double t, double *v1p, double *v2p)
Definition: N_DEV_TRA.C:904
const SolverState & solverState_
void registerDevice()
Definition: N_DEV_TRA.C:1551
Descriptor & addPar(const char *parName, T default_value, T U::*varPtr)
Adds the parameter description to the parameter map.
Definition: N_DEV_Pars.h:1429
Linear::Vector * nextSolVectorPtr
virtual void forEachInstance(DeviceInstanceOp &op) const
Apply a device instance "op" to all instances associated with this model.
Definition: N_DEV_TRA.C:1471
bool given(const std::string &parameter_name) const
Pure virtual class to augment a linear system.
void registerJacLIDs(const std::vector< std::vector< int > > &jacLIDVec)
Definition: N_DEV_TRA.C:432
void addInternalNode(Util::SymbolTable &symbol_table, int index, const InstanceName &instance_name, const std::string &lead_name)
const std::string & getEncodedName() const
Return the instance name encoded as: [s:]*xname [s:]*Ytype!name [s:]*Utype!name!count.
DeviceState * getInternalState()
Definition: N_DEV_TRA.C:1234
void pruneHistory(double t)
Definition: N_DEV_TRA.C:825
#define AssertLIDs(cmp)
void loadNodeSymbols(Util::SymbolTable &symbol_table) const
Populates and returns the store name map.
Definition: N_DEV_TRA.C:365
virtual void registerJacLIDs(const JacobianStamp &jacLIDVec)
virtual std::ostream & printOutInstances(std::ostream &os) const
Definition: N_DEV_TRA.C:1429
bool getInstanceBreakPoints(std::vector< Util::BreakPoint > &breakPointTimes)
Definition: N_DEV_TRA.C:1046
void registerLIDs(const std::vector< int > &intLIDVecRef, const std::vector< int > &extLIDVecRef)
Definition: N_DEV_TRA.C:307
void setParams(const std::vector< Param > &params)
const std::string & getName() const
bool processInstanceParams()
processInstanceParams
Definition: N_DEV_TRA.C:1369
The FactoryBlock contains parameters needed by the device, instance and model creation functions...
const std::vector< std::vector< int > > & jacobianStamp() const
Definition: N_DEV_TRA.C:419
bool setInternalState(const DeviceState &state)
Definition: N_DEV_TRA.C:1291
Instance(const Configuration &configuration, const InstanceBlock &instance_block, Model &model, const FactoryBlock &factory_block)
Definition: N_DEV_TRA.C:108
const DeviceOptions & deviceOptions_
std::vector< Instance * > instanceContainer
Definition: N_DEV_TRA.h:360
static Config< T > & addConfiguration()
Adds the device to the Xyce device configuration.
static std::vector< std::vector< int > > jacStamp
Definition: N_DEV_TRA.h:145
Linear::Matrix * dFdxMatrixPtr
The Device class is an interface for device implementations.
Definition: N_DEV_Device.h:101
void registerStoreLIDs(const std::vector< int > &st0LIDVecRef)
Definition: N_DEV_TRA.C:400
void addStoreNode(Util::SymbolTable &symbol_table, int index, const InstanceName &instance_name, const std::string &lead_name)
std::vector< double > data
Class Configuration contains device configuration data.
static void loadInstanceParameters(ParametricData< Instance > &instance_parameters)
Definition: N_DEV_TRA.C:71
static Device * factory(const Configuration &configuration, const FactoryBlock &factory_block)
Definition: N_DEV_TRA.C:1545
const SolverState & getSolverState() const
std::vector< History > history
Definition: N_DEV_TRA.h:288
bool processParams()
processParams
Definition: N_DEV_TRA.C:1355
static void loadModelParameters(ParametricData< Model > &model_parameters)
Definition: N_DEV_TRA.C:93
ModelBlock represents a .MODEL line from the netlist.
Manages parameter binding for class C.
Definition: N_DEV_Pars.h:214
InstanceBlock represent a device instance line from the netlist.
std::vector< Param > params
void registerStateLIDs(const std::vector< int > &staLIDVecRef)
Definition: N_DEV_TRA.C:387