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.174 $
40 //
41 // Revision Date : $Date: 2014/05/19 15:49:14 $
42 //
43 // Current Owner : $Author: dgbaur $
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  {
382  }
383 
384  return intNameMap;
385 }
386 
387 
388 
389 //-----------------------------------------------------------------------------
390 // Function : Instance::registerStateLIDs
391 // Purpose :
392 // Special Notes :
393 // Scope : public
394 // Creator : Robert Hoekstra, SNL, Computational Sciences
395 // Creation Date : 6/21/02
396 //-----------------------------------------------------------------------------
397 void Instance::registerStateLIDs( const std::vector<int> & staLIDVecRef)
398 {
399  AssertLIDs(staLIDVecRef.size() == numStateVars);
400 }
401 
402 //-----------------------------------------------------------------------------
403 // Function : N_DEV_TRAInstance::registerStoreLIDs
404 // Purpose : One store var for device current.
405 // Special Notes :
406 // Scope : public
407 // Creator : Richard Schiek, Electrical Systems Modeling
408 // Creation Date : 04/05/2013
409 //-----------------------------------------------------------------------------
410 void N_DEV_TRAInstance::registerStoreLIDs(const std::vector<int> & stoLIDVecRef )
411 {
412  AssertLIDs(stoLIDVecRef.size() == getNumStoreVars());
413 
414  if( loadLeadCurrent )
415  {
416  li_store_dev_i1 = stoLIDVecRef[0];
417  li_store_dev_i2 = stoLIDVecRef[1];
418  }
419 }
420 
421 //-----------------------------------------------------------------------------
422 // Function : N_DEV_TRAInstance::getStoreNameMap
423 // Purpose :
424 // Special Notes :
425 // Scope : public
426 // Creator : Richard Schiek, Electrical Systems Modeling
427 // Creation Date : 04/05/2013
428 //-----------------------------------------------------------------------------
429 std::map<int,std::string> & N_DEV_TRAInstance::getStoreNameMap ()
430 {
431  // set up the internal name map, if it hasn't been already.
432  if( loadLeadCurrent && storeNameMap.empty ())
433  {
434  storeNameMap[ li_store_dev_i1 ] = spiceStoreName(getName(), "DEV_I1");
435  storeNameMap[ li_store_dev_i2 ] = spiceStoreName(getName(), "DEV_I2");
436  }
437 
438  return storeNameMap;
439 }
440 
441 
442 //-----------------------------------------------------------------------------
443 // Function : N_DEV_TRAInstance::jacobianStamp
444 // Purpose :
445 // Special Notes :
446 // Scope : public
447 // Creator : Robert Hoekstra, SNL, Computational Sciences
448 // Creation Date : 9/2/02
449 //-----------------------------------------------------------------------------
450 const std::vector< std::vector<int> > & Instance::jacobianStamp() const
451 {
452  return jacStamp;
453 }
454 
455 //-----------------------------------------------------------------------------
456 // Function : Instance::registerJacLIDs
457 // Purpose :
458 // Special Notes :
459 // Scope : public
460 // Creator : Robert Hoekstra, SNL, Computational Sciences
461 // Creation Date : 9/2/02
462 //-----------------------------------------------------------------------------
463 void Instance::registerJacLIDs( const std::vector< std::vector<int> > & jacLIDVec )
464 {
465  DeviceInstance::registerJacLIDs( jacLIDVec );
466  APos1EquPos1NodeOffset = jacLIDVec[0][0];
467  APos1EquInt1NodeOffset = jacLIDVec[0][1];
468 
469  ANeg1EquIbr1NodeOffset = jacLIDVec[1][0];
470 
471  APos2EquPos2NodeOffset = jacLIDVec[2][0];
472  APos2EquInt2NodeOffset = jacLIDVec[2][1];
473 
474  ANeg2EquIbr2NodeOffset = jacLIDVec[3][0];
475 
476  AInt1EquPos1NodeOffset = jacLIDVec[4][0];
477  AInt1EquInt1NodeOffset = jacLIDVec[4][1];
478  AInt1EquIbr1NodeOffset = jacLIDVec[4][2];
479 
480  AIbr1EquNeg1NodeOffset = jacLIDVec[5][0];
481  AIbr1EquPos2NodeOffset = jacLIDVec[5][1];
482  AIbr1EquNeg2NodeOffset = jacLIDVec[5][2];
483  AIbr1EquInt1NodeOffset = jacLIDVec[5][3];
484  AIbr1EquIbr2NodeOffset = jacLIDVec[5][4];
485 
486  AInt2EquPos2NodeOffset = jacLIDVec[6][0];
487  AInt2EquInt2NodeOffset = jacLIDVec[6][1];
488  AInt2EquIbr2NodeOffset = jacLIDVec[6][2];
489 
490  AIbr2EquPos1NodeOffset = jacLIDVec[7][0];
491  AIbr2EquNeg1NodeOffset = jacLIDVec[7][1];
492  AIbr2EquNeg2NodeOffset = jacLIDVec[7][2];
493  AIbr2EquIbr1NodeOffset = jacLIDVec[7][3];
494  AIbr2EquInt2NodeOffset = jacLIDVec[7][4];
495 
496 }
497 
498 //-----------------------------------------------------------------------------
499 // Function : Instance::loadDAEFVector
500 //
501 // Purpose : Loads the F-vector contributions for a single
502 // TRA instance.
503 //
504 // Special Notes :
505 //
506 // Scope : public
507 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
508 // Creation Date : 02/19/05
509 //-----------------------------------------------------------------------------
511 {
512  bool bsuccess = true;
513 
514  double coef_pos1;
515  double coef_neg1;
516  double coef_int1;
517  double coef_ibr1;
518  double coef_pos2;
519  double coef_neg2;
520  double coef_int2;
521  double coef_ibr2;
522 
523  double * fVec = extData.daeFVectorRawPtr;
524 
525 #ifdef Xyce_DEBUG_DEVICE
526  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
527  {
528  Xyce::dout() << subsection_divider << std::endl;
529  Xyce::dout() << " Instance::loadDAEFVector" << std::endl;
530  Xyce::dout() << " name = " << getName() <<std::endl;
531  }
532 #endif
533 
534  // Most of the work has already been done by uIVB.
535  coef_pos1 = (Vpos1-Vint1)*G0;
536  coef_neg1 = -Ibr1;
537  coef_int1 = -(Vpos1-Vint1)*G0+Ibr1;
538  coef_ibr1 = ((Vint1-Vneg1)-v1);
539  coef_pos2 = (Vpos2-Vint2)*G0;
540  coef_neg2 = -Ibr2;
541  coef_int2 = -(Vpos2-Vint2)*G0+Ibr2;
542  coef_ibr2 = ((Vint2-Vneg2)-v2);
543 
544 
545  fVec[li_Pos1] += coef_pos1;
546  fVec[li_Neg1] += coef_neg1;
547  fVec[li_Int1] += coef_int1;
548  fVec[li_Ibr1] += coef_ibr1;
549  fVec[li_Pos2] += coef_pos2;
550  fVec[li_Neg2] += coef_neg2;
551  fVec[li_Int2] += coef_int2;
552  fVec[li_Ibr2] += coef_ibr2;
553 
554  if( loadLeadCurrent )
555  {
556  double * stoVec = extData.nextStoVectorRawPtr;
557  stoVec[li_store_dev_i1] = Ibr1;
558  stoVec[li_store_dev_i2] = -Ibr2;
559  }
560 
561  return bsuccess;
562 }
563 
564 //-----------------------------------------------------------------------------
565 // Function : Instance::loadDAEdFdx ()
566 //
567 // Purpose : Loads the F-vector contributions for a single device instance.
568 //
569 // Special Notes : The F-vector is an algebraic constaint.
570 //
571 // The special notes below are those that were taken from
572 // the old loadAnalyticJacobian header. The matrix
573 // it describes is the full jacobian matrix:
574 //----------------------------------------------------------------------
575 // Special Notes : This is based on there being two two-node ports
576 // and a model of the following sort:
577 //
578 // Pos1 o-----+ +------o Pos2
579 // | |
580 // \ \
581 // / /
582 // \Z0 \ Z0
583 // / /
584 // | |
585 // oInt1 o Int2
586 // | |
587 // ++++++ ++++++
588 // | V1 | | V2 |
589 // ------ ------
590 // | |
591 // Neg1 o-----+ +------o Neg2
592 //
593 // There are also two branch currents, Ibr1 and Ibr2 for left and right
594 // sides as well.
595 //
596 // The matrix for this ends up being:
597 // V_Pos1 V_Neg1 V_Int1 Ibr1 V_Pos2 V_Neg2 V_Int2 V_Ibr2
598 // ------------------------------------------------------------
599 // KCL Pos1 a b
600 // KCL Neg1 c
601 // KCL Int1 d e f
602 // KCL Ibr1 g h i j k
603 // KCL Pos2 l m
604 // KCL Neg2 n
605 // KCL Int2 o p q
606 // KCL Ibr2 r s t u v
607 //
608 // When doing time integration, i,j,k,r,s and t are zero, those dependences
609 // are time-delayed, i.e. the equations for the output depend on time-delayed
610 // of the input. For DC calculations, i,j,k,r,s and t are non-zero.
611 //
612 // The right hand sides are:
613 // Pos1: (V_int1-V_Pos1)*G0 Pos2: (V_Int2-V_Pos2)*G0
614 // Neg1: -Ibr1 Neg2: -Ibr2
615 // Int1: (V_Pos1-V_Int1)*G0+Ibr1 Int2: (V_Pos2-V_Int2)*G0+Ibr2
616 // Ibr1: (V_Int1-V_Neg1)-V1 Ibr2: (V_Int2-V_Neg2)-V2
617 //
618 // For transient operation, v1 and v2 depend on values of voltage and
619 // current at delayed time at the opposite port:
620 // V1 = DeltaV2(t-td)+Z0*Ibr2(t-td)
621 // V2 = DeltaV1(t-td)+Z0*Ibr1(t-td)
622 //
623 // For DC operation V1=VPos2-Vneg2+Ibr2*Z0, V2 = Vpos1-Vneg1+Ibr1*Z0
624 //--------------------------------------------------------------------
625 //
626 // Scope : public
627 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
628 // Creation Date : 02/19/05
629 //-----------------------------------------------------------------------------
631 {
632  N_LAS_Matrix & dFdx = *(extData.dFdxMatrixPtr);
633 
634 #ifdef Xyce_DEBUG_DEVICE
636  {
637  Xyce::dout() << subsection_divider << std::endl;
638  Xyce::dout() << " name = " << getName() << std::endl;
639  }
640 #endif
641 
642 
644 
646 
647 
649 
651 
652  dFdx[li_Int1][AInt1EquIbr1NodeOffset] += 1.0;
653 
654 
655  dFdx[li_Neg1][ANeg1EquIbr1NodeOffset] -= 1.0;
656 
657 
658  dFdx[li_Ibr1][AIbr1EquInt1NodeOffset] += 1.0;
659 
660  dFdx[li_Ibr1][AIbr1EquNeg1NodeOffset] -= 1.0;
661  if( DCMODE )
662  {
663 
664  dFdx[li_Ibr1][AIbr1EquPos2NodeOffset] -= 1.0;
665 
666  dFdx[li_Ibr1][AIbr1EquNeg2NodeOffset] += 1.0;
667 
669  }
670 
671 
673 
675 
676 
678 
680 
681  dFdx[li_Int2][AInt2EquIbr2NodeOffset] += 1.0;
682 
683 
684  dFdx[li_Neg2][ANeg2EquIbr2NodeOffset] -= 1.0;
685 
686 
687  dFdx[li_Ibr2][AIbr2EquInt2NodeOffset] += 1.0;
688 
689  dFdx[li_Ibr2][AIbr2EquNeg2NodeOffset] -= 1.0;
690  if( DCMODE )
691  {
692 
693  dFdx[li_Ibr2][AIbr2EquPos1NodeOffset] -= 1.0;
694 
695  dFdx[li_Ibr2][AIbr2EquNeg1NodeOffset] += 1.0;
696 
698  }
699 
700 
701 #ifdef Xyce_DEBUG_DEVICE
702  if (getDeviceOptions().debugLevel > 1 && getSolverState().debugTimeFlag)
703  Xyce::dout() << subsection_divider << std::endl;
704 #endif
705 
706  return true;
707 }
708 
709 //-----------------------------------------------------------------------------
710 // Function : Instance::updatePrimaryState
711 // Purpose : update primary state for one TRA instance
712 // Special Notes :
713 // Scope : public
714 // Creator : Tom Russo, SNL, Component Information and Models
715 // Creation Date : 1/10/01
716 //-----------------------------------------------------------------------------
718 {
719 #ifdef Xyce_DEBUG_DEVICE
720  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
721  {
722  Xyce::dout() << std::endl << subsection_divider << std::endl;
723  Xyce::dout() << "In TRA::updatePrimaryState\n";
724  Xyce::dout() << " last_t is " << last_t << std::endl;
725  Xyce::dout() << " v1 is " << v1 << std::endl;
726  Xyce::dout() << " v2 is " << v2 << std::endl;
727  }
728 #endif
729 
730  return updateIntermediateVars ();
731 }
732 
733 //-----------------------------------------------------------------------------
734 // Function : Instance::updateIntermediateVars
735 // Purpose : update intermediate variables for one TRA instance
736 // Special Notes :
737 // Scope : public
738 // Creator : Tom Russo, Component Information and Models
739 // Creation Date : 1/10/01
740 //-----------------------------------------------------------------------------
742 {
743  double * solVec = extData.nextSolVectorRawPtr; // the current guess
744 
745 #ifdef Xyce_DEBUG_DEVICE
746  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
747  {
748  Xyce::dout() << std::endl << subsection_divider << std::endl;
749  Xyce::dout() << " In ::updateIntermediateVars\n\n";
750  }
751 #endif
752 
753  Vpos1 = Vpos2 = Vneg1 = Vneg2 = Vint1 = Vint2 = 0.0;
754 
755  Vpos1 = solVec[li_Pos1];
756  Vneg1 = solVec[li_Neg1];
757  Vint1 = solVec[li_Int1];
758  Ibr1 = solVec[li_Ibr1];
759  Vpos2 = solVec[li_Pos2];
760  Vneg2 = solVec[li_Neg2];
761  Vint2 = solVec[li_Int2];
762  Ibr2 = solVec[li_Ibr2];
763 
764 #ifdef Xyce_DEBUG_DEVICE
765  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
766  {
767  Xyce::dout() << " Vpos1 = " << Vpos1 << std::endl;
768  Xyce::dout() << " Vneg1 = " << Vneg1 << std::endl;
769  Xyce::dout() << " Vint1 = " << Vint1 << std::endl;
770  Xyce::dout() << " Ibr1 = " << Ibr1 << std::endl;
771  Xyce::dout() << " Vpos2 = " << Vpos2 << std::endl;
772  Xyce::dout() << " Vneg2 = " << Vneg2 << std::endl;
773  Xyce::dout() << " Vint2 = " << Vint2 << std::endl;
774  Xyce::dout() << " Ibr2 = " << Ibr2 << std::endl;
775  }
776 #endif
777 
778  // Test if we're doing DC or Transient
779  if ((getSolverState().dcopFlag))
780  {
781  // DC operation
782  DCMODE=true;
783  v1 = (Vpos2-Vneg2)+Z0*Ibr2;
784  v2 = (Vpos1-Vneg1)+Z0*Ibr1;
785 #ifdef Xyce_DEBUG_DEVICE
787  Xyce::dout() << "DC Mode, V1 = " << v1 << ", V2 = " << v2 << std::endl;
788 #endif
789  }
790  else
791  {
792  double currentTime = getSolverState().currTime;
793  DCMODE=false;
794 #ifdef Xyce_DEBUG_DEVICE
795  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
796  {
797  Xyce::dout() << "Not DC, newtonIter = " << getSolverState().newtonIter;
798  Xyce::dout() << " Time is " << currentTime << std::endl;
799  Xyce::dout() << " newtonIterOld = " << newtonIterOld << " timeOld is " << timeOld << std::endl;
800  }
801 #endif
802  // Transient operation
803  // Now determine if we're on the first newton step of an iteration
804  if (getSolverState().newtonIter == 0 && (currentTime != timeOld))
805  {
806  timeOld = currentTime;
807  // we are, so need to manipulate history and calculate v1,v2.
808  // If we're the first time step, we need to initialize it
809  if (getSolverState().initTranFlag)
810  {
811  last_t = currentTime;
812  v1 = (Vpos2-Vneg2)+Z0*Ibr2;
813  v2 = (Vpos1-Vneg1)+Z0*Ibr1;
814 
815  history.clear();
816  history.push_back(History(-2*td,v1,v2));
817  history.push_back(History(-td,v1,v2));
818  history.push_back(History(0,v1,v2));
819 #ifdef Xyce_DEBUG_DEVICE
820  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
821  {
822  Xyce::dout() << "Transient, first time, T = ";
823  Xyce::dout() << currentTime;
824  Xyce::dout() << ", V1 = " << v1;
825  Xyce::dout() << ", V2 = " << v2 << std::endl;
826  }
827 #endif
828  }
829  else
830  {
831  double delayedTime = currentTime-td;
832 
833  // now get the values of v1 and v2 from the delayed-time
834  // information
835  InterpV1V2FromHistory(delayedTime, &v1, &v2);
836 #ifdef Xyce_DEBUG_DEVICE
837  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
838  {
839  Xyce::dout() << " Done with interpolation to delayedTime=";
840  Xyce::dout() << delayedTime;
841  Xyce::dout() << ", have v1="<<v1 << " and v2=" << v2 << std::endl;
842  Xyce::dout() << " INTERP " << delayedTime << " " << v1 << " " << v2 << std::endl;
843  Xyce::dout() << " Set last_t to " << currentTime << std::endl;
844  }
845 #endif
846  // now save the current time so we can have it next time
847  // we get to this block (i.e. on the next time step)
848  last_t = currentTime;
849  }
850  }
851  else
852  {
853  // we're on the second iteration or later of the second time
854  // step or later. Re-use the values of v1 and v2 from the
855  // first iteration of this time step. We don't care what time
856  // it is
857 #ifdef Xyce_DEBUG_DEVICE
858  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
859  {
860  Xyce::dout() << "second or later iteration, t is " << currentTime;
861  Xyce::dout() << " have last_t = " << last_t << " v1="<<v1 << " and v2=" << v2 << std::endl;
862  }
863 #endif
864  }
865  }
866  return true;
867 }
868 
869 //-----------------------------------------------------------------------------
870 // Function : Instance::pruneHistory
871 // Purpose : sift through the transmission line state history and
872 // delete records that are so old they'll never be used again
873 // Special Notes :
874 // Scope : private
875 // Creator : Tom Russo, SNL, Component Information and Models
876 // Creation Date : 6/15/2001
877 //-----------------------------------------------------------------------------
878 
879 void Instance::pruneHistory(double t1)
880 {
881 
882  // The input t is the oldest time for which we'll ever interpolate again.
883  // That means we only need two times in the history that are older than t1,
884  // so this routine drops everything off the head but the most recent 2 that
885  // are older than t.
886 
887  std::vector<History>::iterator first = history.begin();
888  std::vector<History>::iterator it1;
889  std::vector<History>::iterator last = history.end();
890  int i;
891 
892  last--; // point to last stored item, not end of the list!
893 #ifdef Xyce_DEBUG_DEVICE
894  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
895  {
896  Xyce::dout() << Xyce::section_divider << std::endl;
897  Xyce::dout() << "Pruning for time t1="<<t1 << std::endl;
898  Xyce::dout() << " Oldest in list is t="<<first->t<<" v1 = "<<first->v1 <<
899  " v2="<<first->v2 << std::endl;
900  Xyce::dout() << " latest in list is t="<<last->t<<" v1 = "<<last->v1
901  << " v2="<<last->v2 << std::endl;
902  }
903 #endif
904  // First find the first element for which the stored time is greater than t
905  for (it1 = first, i = 0; it1->t < t1 && it1 != last; ++it1, ++i)
906  {
907 #ifdef Xyce_DEBUG_DEVICE
908  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
909  {
910  Xyce::dout() << "i = " << i << " t = " << it1->t;
911  Xyce::dout() << " v1 = " << it1->v1;
912  Xyce::dout() << " v2 = " << it1->v2 << std::endl;
913  }
914 #endif
915  }
916 
917 #ifdef Xyce_DEBUG_DEVICE
918  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
919  {
920  Xyce::dout() << " i ="<<i << std::endl;
921  }
922 #endif
923 
924  // Now it1 points to the first element with t>t1
925  if (i > 2)
926  {
927 #ifdef Xyce_DEBUG_DEVICE
928  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
929  {
930  Xyce::dout() << "Need to prune. Keeping " << it1->t << std::endl;
931  }
932 #endif
933  // if i>2 we have too many old ones.
934  // back up 2
935  it1--;
936 #ifdef Xyce_DEBUG_DEVICE
937  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
938  {
939  Xyce::dout() << " Keeping " << it1->t << std::endl;
940  }
941 #endif
942 
943  it1--;
944 #ifdef Xyce_DEBUG_DEVICE
945  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
946  {
947  Xyce::dout() << " Keeping " << it1->t << std::endl;
948  }
949 #endif
950  // delete everything from the first to it1, not counting it1
951  history.erase(first,it1);
952  }
953  // otherwise we don't need to do anything.
954 #ifdef Xyce_DEBUG_DEVICE
955  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
956  {
957  Xyce::dout() << Xyce::section_divider << std::endl;
958  }
959 #endif
960 }
961 
962 
963 //-----------------------------------------------------------------------------
964 // Function : Instance::InterpV1V2FromHistory
965 // Purpose : Use 3-point lagrange interpolation to determine
966 // v1(t) and v2(t) at a specified time in the past
967 // Special Notes :
968 // Scope : private
969 // Creator : Tom Russo, SNL, Component Information and Models
970 // Creation Date : 6/15/2001
971 //-----------------------------------------------------------------------------
972 void Instance::InterpV1V2FromHistory(double t, double * v1p,
973  double *v2p)
974 {
975  std::vector<History>::iterator first = history.begin();
976  std::vector<History>::iterator it1;
977  std::vector<History>::iterator last = history.end();
978  double t1,t2,t3;
979  double dt1,dt2,dt3;
980  double v11,v21,v12,v22,v13,v23;
981  double dt12,dt13,dt23;
982  double f1,f2,f3; // interpolating functions
983 
984  if (history.size() <= 0)
985  {
986  std::string msg;
987  msg="Instance::InterpV1V2FromHistory called but history list is"
988  " empty. Might be due to trying to restart this netlist.\n"
989  "Restarts of netlists with transmission lines does not work yet.\n";
990  N_ERH_ErrorMgr::report( N_ERH_ErrorMgr::DEV_FATAL, msg);
991  }
992 
993  last--; // point to the last stored item, not the tail of the list!
994  // sanity clause (you canna foola me, I know they're ain'ta no sanity
995  // clause!)
996  // if (t < first->t || t > last->t)
997  if (t - first->t < -N_UTL_MachineDependentParams::MachinePrecision()
998  || t - last->t > N_UTL_MachineDependentParams::MachinePrecision() )
999  {
1000  UserError(*this) << "Cannot interpolate to a time (" << t << ") prior to oldest("
1001  << first->t << ") or after newest(" << last->t << ") in history";
1002  return;
1003  }
1004 
1005 #ifdef Xyce_DEBUG_DEVICE
1006  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
1007  {
1008  Xyce::dout() << " interpolating for t = " << t << std::endl;
1009  }
1010 #endif
1011 
1012  // If we are within roundoff of the endpoints of the history, just use
1013  // the endpoints, otherwise interpolate to get it.
1014  if ( fabs(t-first->t)<N_UTL_MachineDependentParams::MachinePrecision())
1015  {
1016  *v1p = first->v1;
1017  *v2p = first->v2;
1018  }
1019  else if ( fabs(t-last->t)<N_UTL_MachineDependentParams::MachinePrecision())
1020  {
1021  *v1p = last->v1;
1022  *v2p = last->v2;
1023  }
1024  else
1025  {
1026 
1027  LessThan<History,double> lessFunct;
1028  it1 = lower_bound(history.begin(),history.end(),t,lessFunct);
1029 
1030  // Now it1 points to the first element with time > t
1031  t3 = it1->t;
1032  v13 = it1->v1;
1033  v23 = it1->v2;
1034  it1--;
1035  t2 = it1->t;
1036  v12 = it1->v1;
1037  v22 = it1->v2;
1038  it1--;
1039  t1 = it1->t;
1040  v11 = it1->v1;
1041  v21 = it1->v2;
1042 
1043 #ifdef Xyce_DEBUG_DEVICE
1045  {
1046  Xyce::dout() << "Using time t3="<<t3<<" v1(t3)="<<v13<<" v2(t3)="<<v23 << std::endl;
1047  Xyce::dout() << "Using time t2="<<t2<<" v1(t2)="<<v12<<" v2(t2)="<<v22 << std::endl;
1048  Xyce::dout() << "Using time t1="<<t1<<" v1(t1)="<<v11<<" v2(t1)="<<v21 << std::endl;
1049  }
1050 #endif
1051 
1052  // now we have three values of each function to be interpolated, and three
1053  // times. t3 is after the desired time, t1 and t2 are before (t2 might be
1054  // equal to the desired time)
1055  // Set up the differences for lagrange interpolation:
1056  dt12 = t1-t2;
1057  dt13 = t1-t3;
1058  dt23 = t2-t3;
1059  dt1 = t-t1;
1060  dt2 = t-t2;
1061  dt3 = t-t3;
1062  // now we set up the lagrange interpolating functions
1063  // e.g. f1 = (t-t2)*(t-t3)/((t1-t2)*(t1-t3))
1064  // so that fi is 1 at ti and 0 at the other times.
1065  f1 = dt2*dt3;
1066  f2 = dt1*dt3;
1067  f3 = dt1*dt2;
1068  if (dt12 != 0)
1069  {
1070  f1 /= dt12;
1071  f2 /= -dt12;
1072  }
1073  else
1074  {
1075  f1 = f2 = 0.0;
1076  }
1077  if (dt13 != 0)
1078  {
1079  f1 /= dt13;
1080  f3 /= -dt13;
1081  }
1082  else
1083  {
1084  f1 = f2 = 0.0;
1085  }
1086  if (dt23 != 0)
1087  {
1088  f2 /= dt23;
1089  f3 /= -dt23;
1090  }
1091  else
1092  {
1093  f2 = f3 = 0.0;
1094  }
1095  // that's it, we have the interpolation functions evaluated at the time t,
1096  // and the values of v1 and v2 at the points, perform the interpolation
1097  *v1p = f1*v11+f2*v12+f3*v13;
1098  *v2p = f1*v21+f2*v22+f3*v23;
1099  }
1100 
1101 }
1102 
1103 //-----------------------------------------------------------------------------
1104 // Function : Instance::getInstanceBreakPoints
1105 // Purpose : This function adds break points to a vector of breakpoints.
1106 //
1107 // It does not bother to check them in any way, or put them
1108 // in order. It only adds them in.
1109 //
1110 // Special Notes : The guts of this has been moved to acceptStep, which
1111 // actually computes the breakpoints if needed. We only add
1112 // them to the list here if necessary.
1113 //
1114 // Scope : public
1115 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1116 // Creation Date : 06/08/01
1117 //-----------------------------------------------------------------------------
1118 bool Instance::getInstanceBreakPoints ( std::vector<N_UTL_BreakPoint> & breakPointTimes )
1119 {
1120  bool bsuccess = true;
1121 
1122  double currentTime = getSolverState().currTime;
1123  int timeStep = getSolverState().timeStepNumber;
1124 
1125  // We're called once prior to any newton iterations, not even the
1126  // DC Op point. Never do anything if first_BP_call_done is false.
1127 
1128  if (timeStep != 0 && first_BP_call_done)
1129  {
1130  if (newBreakPoint)
1131  {
1132  breakPointTimes.push_back(newBreakPointTime);
1133  newBreakPoint = false;
1134  }
1135  }
1136  else
1137  {
1138 #ifdef Xyce_DEBUG_DEVICE
1139  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
1140  {
1141  Xyce::dout() << " In Instance::getBreakPoints "<<std::endl;
1142  Xyce::dout() << " First time step, I don't get to set breakpoints. Time is ";
1143  Xyce::dout() << currentTime << std::endl;
1144  }
1145 #endif
1146  }
1147 
1148  first_BP_call_done=true;
1149  return bsuccess;
1150 }
1151 
1152 //-----------------------------------------------------------------------------
1153 // Function : Instance::acceptStep
1154 // Purpose : This function saves the values of v1 and v2 along with
1155 // the current time. It is to be called ONLY at the point
1156 // when the time integrator has determined we've got a
1157 // converged, acceptable solution and is accepting it,
1158 // but before it's updated its times and rotated vectors.
1159 //
1160 // Special Notes : In SPICE this same stuff was done in the "TRAaccept" function.
1161 //
1162 // Scope : public
1163 // Creator : Tom Russo, SNL
1164 // Creation Date : 01/23/07
1165 //-----------------------------------------------------------------------------
1167 {
1168  if (!getSolverState().dcopFlag)
1169  {
1170  double currentTime = getSolverState().currTime;
1171 
1172  double d11, d21, d12, d22;
1173  N_LAS_Vector *theSolVectorPtr = extData.nextSolVectorPtr;// the accepted
1174  // values from this
1175  // step
1176 
1177  std::vector<History>::iterator last = history.end();
1178 
1179  last--; // point to last item, not past last item.
1180 
1181  // We're called once prior to any newton iterations, not even the
1182  // DC Op point. Never do anything if first_BP_call_done is false.
1183  double oVp1,oVp2,oVn1,oVn2,oI1,oI2;
1184  double ov1,ov2;
1185  double tmp_v1,tmp_v2, tmp_t;
1186 
1187 #ifdef Xyce_DEBUG_DEVICE
1188  double oVi1,oVi2;
1189  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
1190  {
1191  Xyce::dout() << " In Instance::acceptStep "<<std::endl;
1192  Xyce::dout() << "I want breakpoints. Time is " << currentTime << std::endl;
1193  Xyce::dout() << " timeOld is " << timeOld << std::endl;
1194  }
1195 #endif
1196 
1197  // we're the end of a time step, the solution has been accepted.
1198  // clean up the history by deleting records of times so far
1199  // back that they'll never be used for interpolation again
1200  // never try to prune history for anything but times that have
1201  // been accepted already.
1202  // TVR: The goal of this was to prune the early history so we don't
1203  // get unbounded growth of the history vector, with the intent of making
1204  // the interpolation method faster. Turns out that deleting these vector
1205  // elements is very expensive, much more expensive than using "lower_bound"
1206  // to find a value in the long list. So I'm commenting this out.
1207  // double delayedTime;
1208  // if (timeOld != -1)
1209  // {
1210  // delayedTime = timeOld-td;
1211  // pruneHistory(delayedTime);
1212  // }
1213 
1214  oVp1 = (*theSolVectorPtr)[li_Pos1];
1215  oVn1 = (*theSolVectorPtr)[li_Neg1];
1216  oI1 = (*theSolVectorPtr)[li_Ibr1];
1217  oVp2 = (*theSolVectorPtr)[li_Pos2];
1218  oVn2 = (*theSolVectorPtr)[li_Neg2];
1219  oI2 = (*theSolVectorPtr)[li_Ibr2];
1220 
1221  // Having the old values means we can calculate what v1 and v2
1222  // were for that time.
1223  ov1=(oVp2-oVn2)+Z0*oI2;
1224  ov2=(oVp1-oVn1)+Z0*oI1;
1225 
1226 #ifdef Xyce_DEBUG_DEVICE
1227  oVi1 = (*theSolVectorPtr)[li_Int1];
1228  oVi2 = (*theSolVectorPtr)[li_Int2];
1229 
1231  {
1232  Xyce::dout() << " ----- New time step -----" << std::endl;
1233  Xyce::dout() << " Last solution : " << std::endl;
1234  Xyce::dout() << " vpos1 = " << oVp1 << std::endl;
1235  Xyce::dout() << " vneg1 = " << oVn1 << std::endl;
1236  Xyce::dout() << " vint1 = " << oVi1 << std::endl;
1237  Xyce::dout() << " ibr1 = " << oI1 << std::endl;
1238  Xyce::dout() << " vpos2 = " << oVp2 << std::endl;
1239  Xyce::dout() << " vneg2 = " << oVn2 << std::endl;
1240  Xyce::dout() << " vint2 = " << oVi2 << std::endl;
1241  Xyce::dout() << " ibr2 = " << oI2 << std::endl;
1242  Xyce::dout() << "in set breakpoints, saving for time=" << currentTime << ", V1 = " << ov1 << ", V2 = " << ov2 << std::endl;
1243  Xyce::dout() << " V1V2DBG " << currentTime << " " << ov1 << " " << ov2 << std::endl;
1244  }
1245 #endif
1246 
1247  history.push_back(History(currentTime,ov1,ov2));
1248 
1249  last = history.end();
1250  last--; // point to last item, not past last item.
1251  // Now calculate derivatives based on history
1252  tmp_v1 = last->v1; tmp_v2 = last->v2; tmp_t = last->t;
1253  last--;
1254 #ifdef Xyce_DEBUG_DEVICE
1255  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
1256  {
1257  Xyce::dout() << "tmp_t=" << tmp_t << " last->t =" << last->t << std::endl;
1258  Xyce::dout() << "tmp_v1=" << tmp_v1 << " last->v1=" << last->v1 << std::endl;
1259  Xyce::dout() << "tmp_v2=" << tmp_v2 << " last->v2=" << last->v2 << std::endl;
1260  }
1261 #endif
1262  d11 = (tmp_v1-last->v1)/(tmp_t-last->t);
1263  d12 = (tmp_v2-last->v2)/(tmp_t-last->t);
1264  tmp_v1 = last->v1; tmp_v2 = last->v2; tmp_t = last->t;
1265  last--;
1266 #ifdef Xyce_DEBUG_DEVICE
1268  {
1269  Xyce::dout() << "tmp_t=" << tmp_t << " last->t =" << last->t << std::endl;
1270  Xyce::dout() << "tmp_v1=" << tmp_v1 << " last->v1=" << last->v1 << std::endl;
1271  Xyce::dout() << "tmp_v2=" << tmp_v2 << " last->v2=" << last->v2 << std::endl;
1272  }
1273 #endif
1274  d21 = (tmp_v1-last->v1)/(tmp_t-last->t);
1275  d22 = (tmp_v2-last->v2)/(tmp_t-last->t);
1276 #ifdef Xyce_DEBUG_DEVICE
1278  {
1279  Xyce::dout() << "Derivs are " << d11 << " " << d21 << std::endl;
1280  Xyce::dout() << " and " << d12 << " " <<d22 << std::endl;
1281  Xyce::dout() << " fabs(d11-d21) = " << fabs(d11-d21) << std::endl;
1282  Xyce::dout() << " fabs(d12-d22) = " << fabs(d12-d22) << std::endl;
1283  Xyce::dout() << "D1D2DBG " << currentTime << " " << d11 << " " << d12 << std::endl;
1284  }
1285 #endif
1286 
1287  if ((fabs(d11-d21) >= .99*Xycemax(fabs(d11),fabs(d21))+1) ||
1288  (fabs(d12-d22) >= .99*Xycemax(fabs(d12),fabs(d22))+1))
1289  {
1290 #ifdef Xyce_DEBUG_DEVICE
1291  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
1292  {
1293  Xyce::dout() << "Derivative is changing enough, I want to set a break point ";
1294  Xyce::dout() << td << " ahead of discontinuity, which is ";
1295  Xyce::dout() << tmp_t+td<<std::endl;
1296  }
1297 #endif
1298  newBreakPointTime = (tmp_t+td);
1299  newBreakPoint = true;
1300  }
1301  }
1302 }
1303 
1304 //-----------------------------------------------------------------------------
1305 // Function : Instance::getInternalState
1306 // Purpose : Generates an DeviceState object and populates
1307 // it with the contents of the history vector for use by
1308 // restarts
1309 //
1310 // Special Notes :
1311 //
1312 // Scope : public
1313 // Creator : Tom Russo, SNL, Component Information and Models
1314 // Creation Date : 09/03/04
1315 //-----------------------------------------------------------------------------
1316 
1318 {
1319  int hsize,i,j;
1320  // allocate object to return
1321  DeviceState * myState = new DeviceState;
1322 
1323 
1324  myState->ID=getName().getEncodedName();
1325  // We'll pack our history data into the single vector of doubles
1326  myState->data.resize(history.size()*3);
1327  hsize=history.size();
1328  for (i=0;i<hsize;++i)
1329  {
1330  j=i*3;
1331  myState->data[j]=history[i].t;
1332  myState->data[j+1]=history[i].v1;
1333  myState->data[j+2]=history[i].v2;
1334  }
1335 
1336 #ifdef Xyce_DEBUG_DEVICE
1337  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
1338  {
1339  Xyce::dout() << Xyce::section_divider
1340  << std::endl;
1341  Xyce::dout() << " In Instance::getInternalState " << std::endl;
1342  Xyce::dout() << " name=" << getName() << std::endl;
1343  Xyce::dout() << " history size = " << hsize << std::endl;
1344  Xyce::dout() << " history data: " << std::endl;
1345  for (i = 0 ; i < hsize ; ++i)
1346  {
1347  Xyce::dout() << " (" << history[i].t << ", " << history[i].v1 << ", "
1348  << history[i].v2 << ")"<< std::endl;
1349  }
1350 
1351  Xyce::dout() << " DeviceState ID = " << myState->ID << std::endl;
1352  Xyce::dout() << " DeviceState data size " << myState->data.size() << std::endl;
1353  Xyce::dout() << " Device State data: " << std::endl;
1354  for (i = 0 ; i < myState->data.size() ; ++i)
1355  {
1356  Xyce::dout() << " " << myState->data[i] << std::endl;
1357  }
1358  Xyce::dout() << Xyce::section_divider
1359  << std::endl;
1360  }
1361 #endif
1362 
1363  return myState;
1364 }
1365 
1366 //-----------------------------------------------------------------------------
1367 // Function : Instance::setInternalState
1368 // Purpose : Reload history data from restart
1369 //
1370 // Special Notes :
1371 //
1372 // Scope : public
1373 // Creator : Tom Russo, SNL, Component Information and Models
1374 // Creation Date : 09/03/04
1375 //-----------------------------------------------------------------------------
1377 {
1378  int dsize=state.data.size();
1379  int hsize,i,j;
1380  if (getName().getEncodedName() != state.ID)
1381  {
1382  DevelFatal(*this).in("TRA::Instance::setInternal") << "ID(" << state.ID << ") from restart does not match my name (" << getName() << ")";
1383  return false;
1384  }
1385 
1386  if (dsize%3 != 0)
1387  {
1388  UserError(*this) << "Data size from restart (" << dsize << ") not a multiple of 3";
1389  return false;
1390  }
1391 
1392  hsize=dsize/3;
1393  history.clear();
1394  history.resize(hsize);
1395  for ( i=0; i<hsize; ++i)
1396  {
1397  j=i*3;
1398  history[i].t=state.data[j];
1399  history[i].v1=state.data[j+1];
1400  history[i].v2=state.data[j+2];
1401  }
1402 
1403 #ifdef Xyce_DEBUG_DEVICE
1404  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
1405  {
1406  Xyce::dout() << Xyce::section_divider
1407  << std::endl;
1408  Xyce::dout() << " In Instance::setInternalState " << std::endl;
1409  Xyce::dout() << " name=" << getName() << std::endl;
1410  Xyce::dout() << " history size = " << hsize << std::endl;
1411  Xyce::dout() << " history data: " << std::endl;
1412  for (i = 0 ; i < hsize ; ++i)
1413  {
1414  Xyce::dout() << " (" << history[i].t << ", " << history[i].v1 << ", "
1415  << history[i].v2 << ")"<< std::endl;
1416  }
1417 
1418  Xyce::dout() << " DeviceState ID = " << state.ID << std::endl;
1419  Xyce::dout() << " DeviceState data size " << state.data.size() << std::endl;
1420  Xyce::dout() << " Device State data: " << std::endl;
1421  for (i = 0 ; i < state.data.size() ; ++i)
1422  {
1423  Xyce::dout() << " " << state.data[i] << std::endl;
1424  }
1425  Xyce::dout() << Xyce::section_divider
1426  << std::endl;
1427  }
1428 #endif
1429  return true;
1430 }
1431 
1432 // Class Model
1433 
1434 //-----------------------------------------------------------------------------
1435 // Function : Model::processParams
1436 // Purpose :
1437 // Special Notes :
1438 // Scope : public
1439 // Creator : Tom Russo, SNL, Component Information and Models
1440 // Creation Date : 9/25/02
1441 //-----------------------------------------------------------------------------
1443 {
1444  // there are no model parameters to process.
1445  return true;
1446 }
1447 
1448 //----------------------------------------------------------------------------
1449 // Function : Model::processInstanceParams
1450 // Purpose :
1451 // Special Notes :
1452 // Scope : public
1453 // Creator : Dave Shirely, PSSI
1454 // Creation Date : 03/23/06
1455 //----------------------------------------------------------------------------
1457 {
1458 
1459  std::vector<Instance*>::iterator iter;
1460  std::vector<Instance*>::iterator first = instanceContainer.begin();
1461  std::vector<Instance*>::iterator last = instanceContainer.end();
1462 
1463  for (iter=first; iter!=last; ++iter)
1464  {
1465  (*iter)->processParams();
1466  }
1467 
1468  return true;
1469 }
1470 
1471 //-----------------------------------------------------------------------------
1472 // Function : Model::Model
1473 // Purpose : model block constructor
1474 // Special Notes :
1475 // Scope : public
1476 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1477 // Creation Date : 5/16/00
1478 //-----------------------------------------------------------------------------
1480  const Configuration & configuration,
1481  const ModelBlock & MB,
1482  const FactoryBlock & factory_block)
1483  : DeviceModel(MB, configuration.getModelParameters(), factory_block)
1484 {
1485 }
1486 
1487 
1488 //-----------------------------------------------------------------------------
1489 // Function : Model::~Model
1490 // Purpose : destructor
1491 // Special Notes :
1492 // Scope : public
1493 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1494 // Creation Date : 3/16/00
1495 //-----------------------------------------------------------------------------
1497 {
1498  std::vector<Instance*>::iterator iter;
1499  std::vector<Instance*>::iterator first = instanceContainer.begin();
1500  std::vector<Instance*>::iterator last = instanceContainer.end();
1501 
1502  for (iter=first; iter!=last; ++iter)
1503  {
1504  delete (*iter);
1505  }
1506 }
1507 
1508 //-----------------------------------------------------------------------------
1509 // Function : Model::printOutInstances
1510 // Purpose : debugging tool.
1511 // Special Notes :
1512 // Scope : public
1513 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1514 // Creation Date : 4/03/00
1515 //-----------------------------------------------------------------------------
1516 std::ostream &Model::printOutInstances(std::ostream &os) const
1517 {
1518  std::vector<Instance*>::const_iterator iter;
1519  std::vector<Instance*>::const_iterator first = instanceContainer.begin();
1520  std::vector<Instance*>::const_iterator last = instanceContainer.end();
1521 
1522  int i;
1523  os << std::endl;
1524  os << " name model name Parameters" << std::endl;
1525  for (i=0, iter=first; iter!=last; ++iter, ++i)
1526  {
1527  os << " " << i << ": " << (*iter)->getName() << " ";
1528  os << getName();
1529 
1530  os << std::endl;
1531  os << "Z0 = " << (*iter)->Z0 << std::endl;
1532  os << "G0 = " << (*iter)->G0 << std::endl;
1533  os << "TD = " << (*iter)->td << std::endl;
1534  os << "FREQ = " << (*iter)->freq << std::endl;
1535  os << "NL = " << (*iter)->NL << std::endl;
1536 
1537  os << std::endl;
1538  }
1539  os << std::endl;
1540 
1541  return os;
1542 }
1543 
1544 //-----------------------------------------------------------------------------
1545 // Function : Model::forEachInstance
1546 // Purpose :
1547 // Special Notes :
1548 // Scope : public
1549 // Creator : David Baur
1550 // Creation Date : 2/4/2014
1551 //-----------------------------------------------------------------------------
1552 /// Apply a device instance "op" to all instances associated with this
1553 /// model
1554 ///
1555 /// @param[in] op Operator to apply to all instances.
1556 ///
1557 ///
1558 void Model::forEachInstance(DeviceInstanceOp &op) const /* override */
1559 {
1560  for (std::vector<Instance *>::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
1561  op(*it);
1562 }
1563 
1564 
1565 //-----------------------------------------------------------------------------
1566 // Function : Instance::getMaxTimeStepSize
1567 // Purpose :
1568 // Special Notes :
1569 // Scope : public
1570 // Creator : Tom Russo, SNL, Component Information and Models
1571 // Creation Date : 8/01/01
1572 //-----------------------------------------------------------------------------
1574 {
1575  return td;
1576 }
1577 
1578 // Additional Declarations
1579 
1580 // History member (trivial) functions
1581 
1582 //-----------------------------------------------------------------------------
1583 // Function : History::History
1584 // Purpose : default constructor
1585 // Special Notes :
1586 // Scope : public
1587 // Creator : Tom Russo, SNL, Component Information and Models
1588 // Creation Date : 06/14/01
1589 //-----------------------------------------------------------------------------
1591  : t(0),v1(0),v2(0)
1592 {
1593 }
1594 
1595 //-----------------------------------------------------------------------------
1596 // Function : History::History
1597 // Purpose : destructor
1598 // Special Notes :
1599 // Scope : public
1600 // Creator : Tom Russo, SNL, Component Information and Models
1601 // Creation Date : 06/14/01
1602 //-----------------------------------------------------------------------------
1604 {
1605 }
1606 //-----------------------------------------------------------------------------
1607 // Function : History::History
1608 // Purpose : copy constructor
1609 // Special Notes :
1610 // Scope : public
1611 // Creator : Tom Russo, SNL, Component Information and Models
1612 // Creation Date : 06/14/01
1613 //-----------------------------------------------------------------------------
1615  : t(right.t),v1(right.v1),v2(right.v2)
1616 {
1617 }
1618 
1619 //-----------------------------------------------------------------------------
1620 // Function : History::History
1621 // Purpose : copy constructor
1622 // Special Notes :
1623 // Scope : public
1624 // Creator : Tom Russo, SNL, Component Information and Models
1625 // Creation Date : 06/14/01
1626 //-----------------------------------------------------------------------------
1627 History::History(double a, double b, double c)
1628  : t(a),v1(b),v2(c)
1629 {
1630 }
1631 
1632 Device *Traits::factory(const Configuration &configuration, const FactoryBlock &factory_block)
1633 {
1634 
1635  return new DeviceMaster<Traits>(configuration, factory_block, factory_block.solverState_, factory_block.deviceOptions_);
1636 }
1637 
1639 {
1641  .registerDevice("t", 1);
1642 }
1643 
1644 } // namespace TRA
1645 } // namespace Device
1646 } // namespace Xyce