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