Xyce  6.1
N_DEV_MutIndLin.C
Go to the documentation of this file.
1  //-----------------------------------------------------------------------------
2 // Copyright Notice
3 //
4 // Copyright 2002 Sandia Corporation. Under the terms
5 // of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S.
6 // Government retains certain rights in this software.
7 //
8 // Xyce(TM) Parallel Electrical Simulator
9 // Copyright (C) 2002-2015 Sandia Corporation
10 //
11 // This program is free software: you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation, either version 3 of the License, or
14 // (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 //-----------------------------------------------------------------------------
24 
25 //-------------------------------------------------------------------------
26 // Filename : $RCSfile: N_DEV_MutIndLin.C,v $
27 //
28 // Purpose :
29 //
30 // Special Notes :
31 //
32 // Creator : Rich Schiek, SNL, Parallel Computational Sciences
33 //
34 // Creation Date : 03/21/2005
35 //
36 // Revision Information:
37 // ---------------------
38 //
39 // Revision Number: $Revision: 1.145 $
40 //
41 // Revision Date : $Date: 2015/04/08 19:18:24 $
42 //
43 // Current Owner : $Author: tvrusso $
44 //-------------------------------------------------------------------------
45 #include <Xyce_config.h>
46 
47 // ---------- Standard Includes ----------
48 #include <N_UTL_Math.h>
49 #include <algorithm>
50 #include <set>
51 
52 // ---------- Xyce Includes ----------
53 #include <N_DEV_DeviceOptions.h>
54 #include <N_DEV_DeviceMaster.h>
55 #include <N_DEV_ExternData.h>
56 #include <N_DEV_MatrixLoadData.h>
57 #include <N_DEV_MutIndLin.h>
58 #include <N_DEV_SolverState.h>
59 #include <N_DEV_Message.h>
60 #include <N_ERH_ErrorMgr.h>
61 
62 #include <N_LAS_Vector.h>
63 #include <N_LAS_Matrix.h>
64 
65 #include <N_UTL_Expression.h>
66 #include <N_UTL_FeatureTest.h>
67 
68 namespace Xyce {
69 namespace Device {
70 
71 
72 //-----------------------------------------------------------------------------
73 // Function : InductorInstanceData::InductorInstanceData
74 // Purpose :
75 // Special Notes :
76 //
77 // Need to have a constructor for this data-only class
78 // or it is treated as in-line by some compilers (gcc 3.3 on the mac)
79 // Trying to inline this could cause problems
80 //
81 // Scope : public
82 // Creator : Rich Schiek
83 // Creation Date :
84 //-----------------------------------------------------------------------------
86  name(""), // name of inductor
87  L(0.0),
88  IC(0.0),
89  ICGiven(false),
90  baseL(0.0),
91  li_Pos(-1),
92  li_Neg(-1),
93  li_Branch(-1),
94  APosEquBraVarOffset(-1),
95  ANegEquBraVarOffset(-1),
96  ABraEquPosNodeOffset(-1),
97  ABraEquNegNodeOffset(-1),
98  ABraEquBraVarOffset(-1),
99  magOffset(-1),
100  vPosOffset(-1),
101  vNegOffset(-1),
103  // Pointers for dFdx entries:
104  f_PosEquBraVarPtr(0),
105  f_NegEquBraVarPtr(0),
106  f_BraEquPosNodePtr(0),
107  f_BraEquNegNodePtr(0),
108  f_BraEquBraVarPtr(0),
109  // offsets only needed in nonlinear application
110  f_magPtr(0),
111  f_vPosPtr(0),
112  f_vNegPtr(0),
113  q_PosEquBraVarPtr(0),
114  q_NegEquBraVarPtr(0),
115  q_BraEquPosNodePtr(0),
116  q_BraEquNegNodePtr(0),
117  q_BraEquBraVarPtr(0),
118  // offsets only needed in nonlinear application
119  q_magPtr(0),
120  q_vPosPtr(0),
121  q_vNegPtr(0)
122 #endif
123 {}
124 
125 namespace MutIndLin {
126 
128 {
129  p.addPar ("COUP_VAL",1.0,&MutIndLin::Instance::mutualCup)
130  .setGivenMember(&MutIndLin::Instance::mutualCupGiven)
131  .setUnit(U_NONE)
132  .setCategory(CAT_NONE)
133  .setDescription("Coupling value");
134 
135  p.addPar ("COUPLEDMutIndLin",std::vector<std::string>(),&MutIndLin::Instance::inductorNames)
136  .setUnit(U_NONE)
137  .setCategory(CAT_NONE)
138  .setDescription("");
139 
140  p.addPar ("COUPLEDINDUCTANCE",std::vector<double>(),&MutIndLin::Instance::inductorInductances)
141  .setUnit(U_NONE)
142  .setCategory(CAT_NONE)
143  .setDescription("");
144 
145  p.addPar ("NODE1",std::vector<std::string>(),&MutIndLin::Instance::inductorsNode1)
146  .setUnit(U_NONE)
147  .setCategory(CAT_NONE)
148  .setDescription("");
149 
150  p.addPar ("NODE2",std::vector<std::string>(),&MutIndLin::Instance::inductorsNode2)
151  .setUnit(U_NONE)
152  .setCategory(CAT_NONE)
153  .setDescription("");
154 
155  p.addPar ("COUPLING",std::vector<double>(),&MutIndLin::Instance::couplingCoefficient)
156  .setExpressionAccess(ParameterType::SOLN_DEP)
157  .setUnit(U_NONE)
158  .setCategory(CAT_NONE)
159  .setDescription("Coupling coefficient");
160 
161  p.addPar ("COUPLEDINDUCTOR",std::vector<std::string>(),&MutIndLin::Instance::couplingInductor)
162  .setUnit(U_NONE)
163  .setCategory(CAT_NONE)
164  .setDescription("");
165 }
166 
168 {
169  p.addPar ("TNOM",27.0,&MutIndLin::Model::tnom)
170  .setUnit(U_DEGC)
171  .setCategory(CAT_MATERIAL)
172  .setDescription("Reference temperature");
173 
174  p.addPar ("TC1",0.0,&MutIndLin::Model::tempCoeff1)
175  .setUnit(U_NONE)
176  .setCategory(CAT_MATERIAL)
177  .setDescription("First order temperature coeff.");
178 
179  p.addPar ("TC2",0.0,&MutIndLin::Model::tempCoeff2)
180  .setUnit(U_NONE)
181  .setCategory(CAT_MATERIAL)
182  .setDescription("Second order temperature coeff.");
183 }
184 
185 //-----------------------------------------------------------------------------
186 // Function : Instance::Instance
187 // Purpose : constructor
188 // Special Notes :
189 // Scope : public
190 // Creator : Rich Schiek, SNL, Parallel Computational Sciences
191 // Creation Date : 03/21/2005
192 //-----------------------------------------------------------------------------
194  const Configuration & configuration,
195  const InstanceBlock & IB,
196  Model & Iiter,
197  const FactoryBlock & factory_block)
198  : DeviceInstance(IB, configuration.getInstanceParameters(), factory_block),
199  model_(Iiter),
200  numInductors(0),
201  mutualCup(0.0),
202  mutualCupGiven(false),
203  scalingRHS(1.0),
204  temp(getDeviceOptions().temp.getImmutableValue<double>()),
205  tempGiven(false)
206 {
207  scalingRHS = 1.0;
208 
209  // set some default values. May be changed by processParams
210  numExtVars = 2;
211  numIntVars = 1;
212  numStateVars = 0;
213 
214  // Set params to constant default values:
215  setDefaultParams ();
216 
217  // Set params according to instance line and constant defaults from metadata:
218  setParams (IB.params);
219 
220  // now load the instance data vector
221  for( int i=0; i<inductorNames.size(); ++i )
222  {
223  InductorInstanceData * inductorData = new InductorInstanceData();
224  inductorData->name = inductorNames[i];
225  inductorData->L = inductorInductances[i];
226  inductorData->baseL = inductorInductances[i];
227  inductorData->ICGiven = false;
228  inductorData->inductorCurrentOffsets.resize( inductorNames.size() );
229  inductorData->f_inductorCurrentPtrs.resize( inductorNames.size() );
230  inductorData->q_inductorCurrentPtrs.resize( inductorNames.size() );
231  inductorData->depVarPairs.clear();
232  instanceData.push_back( inductorData );
233  }
234 
235  numInductors = instanceData.size();
236 
237  // set up the device connectivity map
238  // each simple inductor in this mutual inductor
239  // is maked as a connection (given a common, non-zero
240  // value in devConMap)
241  devConMap.resize(2*numInductors);
242  for(int i=0; i<numInductors; i++)
243  {
244  devConMap[i] = devConMap[i+1] = (i+1);
245  }
246 
247  // now assemble the mutual coupling coefficient matrix
248  // assume no coupling except to self, so just ones on dialgonal.
249  mutualCouplingCoef.resize( numInductors );
250  mutualCouplingCoefDerivs.resize( numInductors );
251  for( int i=0; i<numInductors; ++i )
252  {
253  mutualCouplingCoef[i].resize( numInductors );
254  fill( mutualCouplingCoef[i].begin(), mutualCouplingCoef[i].end(), 0.0);
255  mutualCouplingCoef[i][i] = 1.0;
256 
257  mutualCouplingCoefDerivs[i].resize( numInductors );
258  fill( mutualCouplingCoefDerivs[i].begin(),
259  mutualCouplingCoefDerivs[i].end(), 0.0 );
260  }
261 
262  // take the vector couplingInductor in pairs to figure out
263  // the coupling value between inductors then insert it into
264  // the couplingCoefficient matrix.
265  // must take sequential pairs to avoid missing some when there are an odd number of inductors.
266  // for example L1 L2 L3 has pairs L1-L2, L1-L3, L2-L3
267  // however, depending on how the netlist was created, the couplingInductor list could be
268  // "L1" "L2" "L1" "L3" ... even pairs of numbers
269  // or
270  // "L1" "L2" "L3" "L4" ... potentially even or odd but inductor names do not repeat.
271  //
272  bool foundDuplicateInductorName=false;
273  if (couplingInductor.size() % 2 == 0)
274  {
275  for( int i=0; i<couplingInductor.size(); ++i)
276  {
277  for( int j=i+1; j<couplingInductor.size(); ++j)
278  {
279  if( (couplingInductor[i] == couplingInductor[j] ) )
280  {
281  foundDuplicateInductorName=true;
282  break;
283  }
284  }
285  }
286  }
287 
288  if( foundDuplicateInductorName )
289  {
290  // in this case the list of coupledInductors is a list of pairs as in
291  // "L1" "L2" "L1" "L3" etc. treat is as such.
292 
293  // take the vector couplingInductor in pairs to figure out
294  // the coupling value between inductors then insert it into
295  // the couplingCoefficient matrix.
296  indexPairs.resize(couplingInductor.size()/2);
297  for( int i=0; i<(couplingInductor.size()-1) ; i+=2 )
298  {
299  // from inductor names, derive indices.
300  int indexInductorOne = -1;
301  int indexInductorTwo = -1;
302  for( int j=0; j<inductorNames.size(); ++j)
303  {
304  if( couplingInductor[i] == inductorNames[j] )
305  {
306  indexInductorOne = j;
307  }
308  if( couplingInductor[i+1] == inductorNames[j] )
309  {
310  indexInductorTwo = j;
311  }
312  if( indexInductorOne != -1 && indexInductorTwo != -1 )
313  {
314  // stop searching if we found the answers.
315  break;
316  }
317  }
318  // Save the indices for later
319  indexPairs[i/2].first = indexInductorOne;
320  indexPairs[i/2].second = indexInductorTwo;
321 
322  // with the indices at hand, assign the value.
323  // note that couplingCoefficient can be of length 1 if all coefficients were the
324  // same. Catch that case here.
325  if( (i/2) < couplingCoefficient.size() )
326  {
327  mutualCouplingCoef[ indexInductorOne ][ indexInductorTwo ] =
328  mutualCouplingCoef[ indexInductorTwo ][ indexInductorOne ] = couplingCoefficient[ (i / 2) ];
329  }
330  else
331  {
332  mutualCouplingCoef[ indexInductorOne ][ indexInductorTwo ] =
333  mutualCouplingCoef[ indexInductorTwo ][ indexInductorOne ] = couplingCoefficient[ 0 ];
334  }
335  }
336 
337  }
338  else
339  {
340  // in this case the list of coupledInductors is a unique list as in
341  // "L1" "L2" "L3" etc. treat it as such
342  int numUniquePairs = couplingInductor.size()*(couplingInductor.size()-1)/2;
343  indexPairs.resize(numUniquePairs);
344  int indexPairCounter=0;
345  for( int i=0; i<couplingInductor.size() ; i++ )
346  {
347  for( int j=(i+1); j<couplingInductor.size() ; j++ )
348  {
349  // from inductor names, derive indices.
350  int indexInductorOne = -1;
351  int indexInductorTwo = -1;
352  for( int k=0; k<inductorNames.size(); ++k)
353  {
354  if( couplingInductor[i] == inductorNames[k] )
355  {
356  indexInductorOne = k;
357  }
358  if( couplingInductor[j] == inductorNames[k] )
359  {
360  indexInductorTwo = k;
361  }
362  if( indexInductorOne != -1 && indexInductorTwo != -1 )
363  {
364  // stop searching if we found the answers.
365  break;
366  }
367  }
368  // Save the indices for later
369  indexPairs[indexPairCounter].first = indexInductorOne;
370  indexPairs[indexPairCounter].second = indexInductorTwo;
371  if( indexPairCounter < (numUniquePairs-1) )
372  ++indexPairCounter;
373 
374  // with the indices at hand, assign the value.
375  // note that couplingCoefficient can be of length 1 if all coefficients were the
376  // same. Catch that case here.
377  if( (i/2) < couplingCoefficient.size() )
378  {
379  mutualCouplingCoef[ indexInductorOne ][ indexInductorTwo ] =
380  mutualCouplingCoef[ indexInductorTwo ][ indexInductorOne ] = couplingCoefficient[ (i / 2) ];
381  }
382  else
383  {
384  mutualCouplingCoef[ indexInductorOne ][ indexInductorTwo ] =
385  mutualCouplingCoef[ indexInductorTwo ][ indexInductorOne ] = couplingCoefficient[ 0 ];
386  }
387  }
388  }
389  }
390  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
391  {
392  Xyce::dout() << "mutualCouplingCoef: " << std::endl;
393  for( int i=0; i<numInductors; ++i )
394  {
395  for( int j=0; j<numInductors; ++j )
396  {
397  Xyce::dout() << mutualCouplingCoef[i][j] << " ";
398  }
399  Xyce::dout() << std::endl;
400  }
401  Xyce::dout() << "index pairs = ";
402  for( int i=0; i<indexPairs.size() ; i++ )
403  {
404  Xyce::dout() << "( " << indexPairs[i].first << ", " << indexPairs[i].second << ") ";
405  }
406  Xyce::dout() << std::endl;
407  }
408 
409  inductorCurrents.resize( numInductors );
410  dIdt.resize( numInductors );
411 
412  inductanceVals.resize( numInductors );
413  LOI.resize( numInductors );
414  LO.resize( numInductors );
415  for( int i=0; i<numInductors; ++i)
416  {
417  LO[i].resize( numInductors );
418  }
419 
421 
422  // Calculate any parameters specified as expressions:
424 
425  // calculate dependent (ie computed) params and check for errors:
426  processParams ();
427 
428  // update internal/external/state variable counts
431  numStateVars = 0;
432 
433  numCoupDepVars.resize(couplingCoefficient.size(),0);
434  expPtrs.resize(couplingCoefficient.size(),0); // null pointers
436 
437  // set up the jacobian stamp
438  // for an individual inductor the stamp would be:
439  //
440  // V1 V2 Ib
441  // kcl1 1
442  // kcl2 -1
443  // branch 1 -1 L/dt
444  //
445  // for a collection of these, the internal variable, branch equations,
446  // must be at the end of a given stamp row.
447  //
448  // So for N inductors the samp is:
449  //
450  // V1 V2 V3 V4 ... V2N I1 I2 ... IN
451  // kcl1 1
452  // kcl2 -1
453  // kcl3 1
454  // kcl4 -1
455  // branch1 1 -1 L/dt c ... c
456  // branch2 1 -1 c L/dt ... c
457  //
458  // where "c" is an induced current change.
459 
460  jacStamp.resize( 3 * numInductors );
461  for( int i=0; i< numInductors; ++i )
462  {
463  jacStamp[2*i].resize(1); // Vpos row
464  jacStamp[2*i+1].resize(1); // Vneg row
465  jacStamp[2*numInductors + i].resize(numInductors + 2); // Ibranch row
466 
467  jacStamp[2*i ][0] = 2*numInductors + i; // vpos-ibranch
468  jacStamp[2*i+1][0] = 2*numInductors + i; // vneg-ibranch
469  jacStamp[2*numInductors + i][0] = 2*i; // ibranch-vpos
470  jacStamp[2*numInductors + i][1] = 2*i + 1; // ibranch-vneg
471  for( int j=0; j<numInductors; ++j )
472  {
473  jacStamp[2*numInductors + i][j+2] = 2*numInductors + j;
474  // ibranch-ibranch[j]
475  }
476  }
477 
478  // Now we process our dependent variables.
479  // We need to bump up the jacstamp for all the dependencies on
480  // the coupling vars that are expressions. We also need to keep track of
481  // how many variables each inductor depends on.
482  std::vector<Depend>::const_iterator d;
483  std::vector<Depend>::const_iterator begin=getDependentParams().begin();
484  std::vector<Depend>::const_iterator end=getDependentParams().end();
485 
486  for (d=begin; d != end; ++d)
487  {
488 
489  if (d->name == "COUPLING" && d->vectorIndex != -1)
490  {
491  // sanity check, they should all have the first two conditions,
492  // and the next means we actually have work to do
493  if (d->n_vars >0)
494  {
495  // Keep track of the number of variables this coefficient depends on:
496  numCoupDepVars[d->vectorIndex] = d->n_vars;
497 
498  // Save the pointer to the expresison, we need to be able to evaluate it.
499  expPtrs[d->vectorIndex] = d->expr;
500 
501  // These are the two inductors that this coefficient couples
502  int indexInductorOne = indexPairs[d->vectorIndex].first;
503  int indexInductorTwo = indexPairs[d->vectorIndex].second;
504 
505  // The coupling coefficient introduces terms to both equations
506  int inductorOneBranchSize = jacStamp[2*numInductors+
507  indexInductorOne].size();
508  int inductorTwoBranchSize = jacStamp[2*numInductors+
509  indexInductorTwo].size();
510  jacStamp[2*numInductors+indexInductorOne].resize(inductorOneBranchSize+
511  d->n_vars);
512  jacStamp[2*numInductors+indexInductorTwo].resize(inductorTwoBranchSize+
513  d->n_vars);
514  for (int i=0; i<d->n_vars; i++)
515  {
516  jacStamp[2*numInductors+indexInductorOne][inductorOneBranchSize+i]
517  = d->lo_var+i+3*numInductors;
518  jacStamp[2*numInductors+indexInductorTwo][inductorTwoBranchSize+i]
519  = d->lo_var+i+3*numInductors;
520 
521  // We need to be able to determine which of our dependent var
522  // indices map onto which variable of what coupling coefficient
523  // when we go to do the jacobian loads. We do this so we don't
524  // need to keep all kinds of two-dimensional arrays like
525  // mutualCoupling that are just copies of the one-dimensonal
526  // arrays like couplingCoefficient.
527  instanceData[indexInductorOne]->depVarPairs.push_back(
528  std::pair<int,int>(d->vectorIndex,i));
529  instanceData[indexInductorTwo]->depVarPairs.push_back(
530  std::pair<int,int>(d->vectorIndex,i));
531  }
532  }
533  }
534  else
535  {
536  Report::UserError() <<"Error in mutual inductor constructor for " << getName().getEncodedName()
537  << ": Parameter " << d->name << " value " << d->expr->get_expression() << " fails sanity check.";
538  }
539  }
540 
541 
542  // We're now done processing all the dependent variables, so we know
543  // everything we need to know about expressions and derivative numbers.
544  for (int i=0; i<couplingCoefficient.size(); ++i)
545  {
547  }
548 
549  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
550  {
551  Xyce::dout() << "Instance::Instance-----------------" << std::endl;
552  Xyce::dout() << "numExtVars = " << numExtVars << std::endl
553  << "numIntVars = " << numIntVars << std::endl
554  << "numStateVars = " << numStateVars << std::endl
555  << "numInductors = " << numInductors << std::endl
556  << "jacStamp = " << std::endl;
557  for( int i = 0; i<jacStamp.size(); ++i )
558  {
559  Xyce::dout() << "jacStamp[ " << i << " ] = { ";
560  for( int j=0; j<jacStamp[i].size(); ++j)
561  {
562  Xyce::dout() << jacStamp[i][j];
563  if( j != ( jacStamp[i].size() -1 ) )
564  {
565  Xyce::dout() << ", ";
566  }
567  }
568  Xyce::dout() << " }" << std::endl;
569  }
570  }
571 
572 }
573 
574 //-----------------------------------------------------------------------------
575 // Function : Instance::~Instance
576 // Purpose : destructor
577 // Special Notes :
578 // Scope : public
579 // Creator : Rich Schiek, SNL, Parallel Computational Sciences
580 // Creation Date : 03/21/2005
581 //-----------------------------------------------------------------------------
583 {
584  std::vector< InductorInstanceData* >::iterator currentInductor = instanceData.begin();
585  std::vector< InductorInstanceData* >::iterator endInductor = instanceData.end();
586  for ( ; currentInductor != endInductor ; ++currentInductor)
587  {
588  delete *currentInductor;
589  }
590 }
591 
592 //-----------------------------------------------------------------------------
593 // Function : Instance::registerLIDs
594 // Purpose :
595 // Special Notes :
596 // Scope : public
597 // Creator : Rich Schiek, SNL, Parallel Computational Sciences
598 // Creation Date : 03/21/2005
599 //-----------------------------------------------------------------------------
600 void Instance::registerLIDs(const std::vector<int> & intLIDVecRef,
601  const std::vector<int> & extLIDVecRef)
602 {
603  AssertLIDs(intLIDVecRef.size() == numIntVars);
604  AssertLIDs(extLIDVecRef.size() == numExtVars);
605 
606 // copy over the global ID lists.
607  intLIDVec = intLIDVecRef;
608  extLIDVec = extLIDVecRef;
609 
610  // Now use these lists to obtain the indices into the
611  // linear algebra entities. This assumes an order.
612  // For the matrix indices, first do the rows.
613  // get the current values of the inductances and currentOffsets
614  std::vector< InductorInstanceData* >::iterator currentInductor = instanceData.begin();
615  std::vector< InductorInstanceData* >::iterator endInductor = instanceData.end();
616  int i = 0;
617  int j = 0;
618  while( currentInductor != endInductor )
619  {
620  (*currentInductor)->li_Pos = extLIDVec[ i++ ];
621  (*currentInductor)->li_Neg = extLIDVec[ i++ ];
622  (*currentInductor)->li_Branch = intLIDVec[ j++ ];
623  ++currentInductor;
624  }
625 
626  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
627  {
628  Xyce::dout() << "Instance::registerLIDs----------------------------" << std::endl;
629  currentInductor = instanceData.begin();
630  i=0;
631  while( currentInductor != endInductor )
632  {
633  Xyce::dout() << "Inductor [ " << i++ << " ] "
634  << " li_Pos = " << (*currentInductor)->li_Pos
635  << " li_Neg = " << (*currentInductor)->li_Neg
636  << " li_Branch = " << (*currentInductor)->li_Branch << std::endl;
637  ++currentInductor;
638  }
639  }
640 }
641 
642 //-----------------------------------------------------------------------------
643 // Function : Instance::loadNodeSymbols
644 // Purpose :
645 // Special Notes :
646 // Scope : public
647 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
648 // Creation Date : 05/13/05
649 //-----------------------------------------------------------------------------
650 void Instance::loadNodeSymbols(Util::SymbolTable &symbol_table) const
651 {
652  for (int i = 0; i < instanceData.size(); ++i) {
653  addInternalNode(symbol_table, intLIDVec[i], getName(), instanceData[i]->name + "_branch");
654  std::string branchInductorName = getName().getSubcircuitName() + ":" + instanceData[i]->name;
655  if( getName().getSubcircuitName() == "" )
656  branchInductorName = instanceData[i]->name;
657  InstanceName bInductorIName = InstanceName( branchInductorName );
658  std::string encodedName = spiceInternalName( bInductorIName, "branch");
659  addInternalNode(symbol_table, intLIDVec[i], encodedName);
660  }
661 
662 }
663 
664 //-----------------------------------------------------------------------------
665 // Function : Instance::registerStateLIDs
666 // Purpose :
667 // Special Notes :
668 // Scope : public
669 // Creator : Rich Schiek, SNL, Parallel Computational Sciences
670 // Creation Date : 03/21/2005
671 //-----------------------------------------------------------------------------
672 void Instance::registerStateLIDs( const std::vector<int> & staLIDVecRef )
673 {
674  AssertLIDs(staLIDVecRef.size() == numStateVars);
675 
676  // copy over the global ID lists.
677  staLIDVec = staLIDVecRef;
678 }
679 
680 //-----------------------------------------------------------------------------
681 // Function : BsrcInstance::getDepSolnVars
682 // Purpose :
683 // Special Notes :
684 // Scope : public
685 // Creator : Rob Hoekstra, SNL, Parallel Computational Sciences
686 // Creation Date : 06/06/01
687 //-----------------------------------------------------------------------------
688 const std::vector<std::string> & Instance::getDepSolnVars()
689 {
691 }
692 
693 //-----------------------------------------------------------------------------
694 // Function : Instance::jacobianStamp
695 // Purpose :
696 // Special Notes :
697 // Scope : public
698 // Creator : Rich Schiek, SNL, Parallel Computational Sciences
699 // Creation Date : 03/21/2005
700 //-----------------------------------------------------------------------------
701 const std::vector< std::vector<int> > & Instance::jacobianStamp() const
702 {
703  return jacStamp;
704 }
705 
706 //-----------------------------------------------------------------------------
707 // Function : Instance::registerJacLIDs
708 // Purpose :
709 // Special Notes :
710 // Scope : public
711 // Creator : Rich Schiek, SNL, Parallel Computational Sciences
712 // Creation Date : 03/21/2005
713 //-----------------------------------------------------------------------------
714 void Instance::registerJacLIDs( const std::vector< std::vector<int> > & jacLIDVec )
715 {
716  DeviceInstance::registerJacLIDs( jacLIDVec );
717  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
718  {
719  Xyce::dout() << "Instance::registerJacLIDs ----------------------------" << std::endl;
720  }
721  std::vector< InductorInstanceData* >::iterator currentInductor = instanceData.begin();
722  std::vector< InductorInstanceData* >::iterator endInductor = instanceData.end();
723  int i = 0;
724  while( currentInductor != endInductor )
725  {
726  (*currentInductor)->APosEquBraVarOffset = jacLIDVec[ 2*i ][ 0 ];
727  (*currentInductor)->ANegEquBraVarOffset = jacLIDVec[ 2*i + 1 ][ 0 ];
728  (*currentInductor)->ABraEquPosNodeOffset = jacLIDVec[ 2*numInductors + i ][ 0 ];
729  (*currentInductor)->ABraEquNegNodeOffset = jacLIDVec[ 2*numInductors + i ][ 1 ];
730  for( int j=0; j<numInductors; ++j )
731  {
732  if( i == j )
733  {
734  (*currentInductor)->ABraEquBraVarOffset = jacLIDVec[ 2*numInductors + i ][ j + 2 ];
735  }
736  (*currentInductor)->inductorCurrentOffsets[ j ] = jacLIDVec[ 2*numInductors + i ][ j + 2 ];
737  }
738  // Now do the parts that are for the dependent variables
739  int numdepvars=(*currentInductor)->depVarPairs.size();
740  (*currentInductor)->ABraEquDepVarOffsets.resize(numdepvars);
741  for (int j = 0; j < numdepvars; ++j)
742  {
743  (*currentInductor)->ABraEquDepVarOffsets[j] =
744  jacLIDVec[2*numInductors+i][numInductors+2+j];
745  }
746  ++currentInductor;
747  ++i;
748  }
749 
750  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
751  {
752  Xyce::dout() << "Instance::registerJacLIDs--------------------------" << std::endl;
753  currentInductor = instanceData.begin();
754  i=0;
755  while( currentInductor != endInductor )
756  {
757  Xyce::dout() << "Inductor [ " << i << " ] " << (*currentInductor)->name
758  << " APosEquBraVarOffset = " << (*currentInductor)->APosEquBraVarOffset
759  << " ANegEquBraVarOffset = " << (*currentInductor)->ANegEquBraVarOffset
760  << " ABraEquPosNodeOffset = " << (*currentInductor)->ABraEquPosNodeOffset
761  << " ABraEquNegNodeOffset = " << (*currentInductor)->ABraEquNegNodeOffset
762  << " ABraEquBraVarOffset = " << (*currentInductor)->ABraEquBraVarOffset << std::endl;
763  Xyce::dout() << "\tInductor branch offsets = { ";
764  for( int j=0; j<numInductors ; ++j )
765  {
766  Xyce::dout() << (*currentInductor)->inductorCurrentOffsets[ j ] << ", ";
767  }
768  Xyce::dout() << "} " << std::endl;
769  ++i;
770  ++currentInductor;
771  }
772  }
773 }
774 
775 //-----------------------------------------------------------------------------
776 // Function : Instance::setupPointers
777 // Purpose :
778 // Special Notes :
779 // Scope : public
780 // Creator : Eric Keiter, SNL
781 // Creation Date : 12/12/08
782 //-----------------------------------------------------------------------------
784 {
785 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
786  Linear::Matrix & dFdx = *(extData.dFdxMatrixPtr);
787  Linear::Matrix & dQdx = *(extData.dQdxMatrixPtr);
788 
789  std::vector< InductorInstanceData* >::iterator currentInductor = instanceData.begin();
790  std::vector< InductorInstanceData* >::iterator endInductor = instanceData.end();
791  int i = 0;
792  while( currentInductor != endInductor )
793  {
794  // dFdx pointers:
795  (*currentInductor)->f_PosEquBraVarPtr =
796  &(dFdx[((*currentInductor)->li_Pos)] [((*currentInductor)->APosEquBraVarOffset)] );
797 
798  (*currentInductor)->f_NegEquBraVarPtr =
799  &(dFdx[((*currentInductor)->li_Neg)] [((*currentInductor)->ANegEquBraVarOffset)] );
800 
801  (*currentInductor)->f_BraEquPosNodePtr =
802  &(dFdx[((*currentInductor)->li_Branch)][((*currentInductor)->ABraEquPosNodeOffset)] );
803 
804  (*currentInductor)->f_BraEquNegNodePtr =
805  &(dFdx[((*currentInductor)->li_Branch)][((*currentInductor)->ABraEquNegNodeOffset)] );
806 
807  for( int j=0; j<numInductors; ++j )
808  {
809  if( i == j )
810  {
811  //(*currentInductor)->ABraEquBraVarOffset =
812  // Is this only used for JMat? (ie old DAE)?
813 
814  }
815  (*currentInductor)->f_inductorCurrentPtrs[ j ] =
816  &(dFdx[((*currentInductor)->li_Branch)][(*currentInductor)->inductorCurrentOffsets[j]] );
817  }
818  // Now do the parts that are for the dependent variables
819  int numdepvars=(*currentInductor)->depVarPairs.size();
820  (*currentInductor)->f_BraEquDepVarPtrs.resize(numdepvars);
821 
822  for (int j = 0; j < numdepvars; ++j)
823  {
824  (*currentInductor)->f_BraEquDepVarPtrs[j] =
825  &(dFdx[((*currentInductor)->li_Branch)][(*currentInductor)->ABraEquDepVarOffsets[j]] );
826 
827  }
828 
829  // dQdx pointers:
830  (*currentInductor)->q_PosEquBraVarPtr =
831  &(dQdx[((*currentInductor)->li_Pos)] [((*currentInductor)->APosEquBraVarOffset)] );
832 
833  (*currentInductor)->q_NegEquBraVarPtr =
834  &(dQdx[((*currentInductor)->li_Neg)] [((*currentInductor)->ANegEquBraVarOffset)] );
835 
836  (*currentInductor)->q_BraEquPosNodePtr =
837  &(dQdx[((*currentInductor)->li_Branch)][((*currentInductor)->ABraEquPosNodeOffset)] );
838 
839  (*currentInductor)->q_BraEquNegNodePtr =
840  &(dQdx[((*currentInductor)->li_Branch)][((*currentInductor)->ABraEquNegNodeOffset)] );
841 
842  for( int j=0; j<numInductors; ++j )
843  {
844  if( i == j )
845  {
846  //(*currentInductor)->ABraEquBraVarOffset =
847  // Is this only used for JMat? (ie old DAE)?
848 
849  }
850  (*currentInductor)->q_inductorCurrentPtrs[ j ] =
851  &(dQdx[((*currentInductor)->li_Branch)][(*currentInductor)->inductorCurrentOffsets[j]] );
852  }
853  // Now do the parts that are for the dependent variables
854  numdepvars=(*currentInductor)->depVarPairs.size();
855  (*currentInductor)->q_BraEquDepVarPtrs.resize(numdepvars);
856 
857  for (int j = 0; j < numdepvars; ++j)
858  {
859  (*currentInductor)->q_BraEquDepVarPtrs[j] =
860  &(dQdx[((*currentInductor)->li_Branch)][(*currentInductor)->ABraEquDepVarOffsets[j]] );
861 
862  }
863 
864  ++currentInductor;
865  ++i;
866  }
867 
868 
869 
870 #endif
871 }
872 
873 //-----------------------------------------------------------------------------
874 // Function : Instance::processParams
875 // Purpose :
876 // Special Notes :
877 // Scope : public
878 // Creator : Rich Schiek, SNL, Parallel Computational Sciences
879 // Creation Date : 03/21/2005
880 //-----------------------------------------------------------------------------
882 {
883  int i, j;
884 
885  // take the vector couplingInductor in pairs to figure out
886  // the coupling value between inductors then insert it into
887  // the couplingCoefficient matrix.
888  j = indexPairs.size();
889  for( i=0; i<j ; ++i )
890  {
891  // note that couplingCoefficient can be of length 1 if all coefficients were the
892  // same. Catch that case here.
893  if( i < couplingCoefficient.size() )
894  {
895  mutualCouplingCoef[ indexPairs[i].first ][ indexPairs[i].second ] =
896  mutualCouplingCoef[ indexPairs[i].second ][ indexPairs[i].first ] = couplingCoefficient[i];
897  }
898  else
899  {
900  mutualCouplingCoef[ indexPairs[i].first ][ indexPairs[i].second ] =
901  mutualCouplingCoef[ indexPairs[i].second ][ indexPairs[i].first ] = couplingCoefficient[0];
902  }
903  }
904  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
905  {
906  Xyce::dout() << "processParams: mutualCouplingCoef: " << std::endl;
907  for( int i=0; i<numInductors; ++i )
908  {
909  for( int j=0; j<numInductors; ++j )
910  {
911  Xyce::dout() << mutualCouplingCoef[i][j] << " ";
912  }
913  Xyce::dout() << std::endl;
914  }
915  }
916 
917  // set the temperature related stuff.
919 
920  return true;
921 }
922 
923 //-----------------------------------------------------------------------------
924 // Function : Instance::updateTemperature
925 // Purpose :
926 // Special Notes :
927 // Scope : public
928 // Creator : Rich Schiek, SNL, Parallel Computational Sciences
929 // Creation Date : 03/21/2005
930 //-----------------------------------------------------------------------------
931 bool Instance::updateTemperature ( const double & temp)
932 {
933  bool bsuccess = true;
934 
935  // current temp difference from reference temp.
936  double difference = temp - model_.tnom;
937 
938  std::vector< InductorInstanceData* >::iterator currentData = instanceData.begin();
939  while( currentData != instanceData.end() )
940  {
941  double factor = 1.0 + (model_.tempCoeff1)*difference +
942  (model_.tempCoeff2)*difference*difference;
943  (*currentData)->L = ((*currentData)->baseL)*factor;
944  ++currentData;
945  }
946 
947  // now that the inductances have changed we need to update the matrix.
949 
950  return bsuccess;
951 }
952 
953 //-----------------------------------------------------------------------------
954 // Function : Instance::updateIntermediateVars
955 // Purpose :
956 // Special Notes :
957 // Scope : public
958 // Creator : Rich Schiek, SNL, Parallel Computational Sciences
959 // Creation Date : 03/21/2005
960 //-----------------------------------------------------------------------------
962 {
963  bool bsuccess = true;
964 
965  // This method is never called anymore
966 
967  return bsuccess;
968 }
969 
970 //-----------------------------------------------------------------------------
971 // Function : Instance::updateInductanceMatrix()
972 // Purpose : A matrix of inductances is used often enough that it
973 // calculated and stored as a member variable here
974 // If and inductance ever changes say from updating
975 // the temperature or a parameter udpate, then this
976 // routine must be called again.
977 // Special Notes :
978 // Scope : public
979 // Creator : Rich Schiek, SNL, Parallel Computational Sciences
980 // Creation Date : 03/21/2005
981 //-----------------------------------------------------------------------------
983 {
984  std::vector< InductorInstanceData* >::iterator
985  currentInductor = instanceData.begin();
986  std::vector< InductorInstanceData* >::iterator
987  endInductor = instanceData.end();
988 
989  // collec the inductances
990  int i=0;
991  while( currentInductor != endInductor )
992  {
993  inductanceVals[ i ] = ((*currentInductor)->L);
994  ++i;
995  ++currentInductor;
996  }
997 
998  // compute the inductance matrix
999  for( i=0; i<numInductors; ++i)
1000  {
1001  for( int j=0; j<numInductors; ++j)
1002  {
1003  LO[i][j] = sqrt( inductanceVals[i]*inductanceVals[j] );
1004  }
1005  }
1006 
1007 }
1008 //-----------------------------------------------------------------------------
1009 // Function : Instance::updatePrimaryState
1010 // Purpose :
1011 // Special Notes :
1012 // Scope : public
1013 // Creator : Rich Schiek, SNL, Parallel Computational Sciences
1014 // Creation Date : 03/21/2005
1015 //-----------------------------------------------------------------------------
1017 {
1018  // nothing happens in updateIntermediateVars() anymore
1019  // bsuccess = updateIntermediateVars ();
1020 
1021  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1022  {
1023  Xyce::dout() << "Instance::updatePrimaryState------------------" << std::endl
1024  << "\tname = " << getName() << std::endl;
1025  }
1026 
1027  double * solVec = extData.nextSolVectorRawPtr;
1028 
1029  // Evaluate the derivatives of all (dependent) coupling coefficients w.r.t
1030  // their variables. We need these for both new and old DAE.
1031  int ncoupcoef=couplingCoefficient.size();
1032  for (int i=0; i<ncoupcoef; ++i)
1033  {
1034  if (expPtrs[i])
1035  {
1036  double junk;
1037  expPtrs[i]->evaluate( junk, couplingCoefficientVarDerivs[i]);
1038  }
1039  }
1040 
1041  // get the currents in each inductor
1042  std::vector< InductorInstanceData* >::iterator
1043  currentInductor = instanceData.begin();
1044  std::vector< InductorInstanceData* >::iterator
1045  endInductor = instanceData.end();
1046  int i = 0;
1047  while( currentInductor != endInductor )
1048  {
1049  if( (getSolverState().dcopFlag) && ((*currentInductor)->ICGiven) )
1050  {
1051  inductorCurrents[ i ] = (*currentInductor)->IC;
1052  }
1053  else
1054  {
1055  inductorCurrents[ i ] = solVec[ (*currentInductor)->li_Branch ];
1056  }
1057  ++i;
1058  ++currentInductor;
1059  }
1060 
1061  return true;
1062 }
1063 
1064 //-----------------------------------------------------------------------------
1065 // Function : Instance::loadErrorWeightMask
1066 //
1067 // Purpose : Loads the zero elements of the device mask
1068 //
1069 // Special Notes : elements of the error vector associated with zero
1070 // elements of the mask will not be included in weighted
1071 // norms by the time integrator.
1072 //
1073 // Scope : public
1074 // Creator : Richard Schiek, SNL, Electrical and Microsystems Modeling
1075 // Creation Date : 02/06/07
1076 //-----------------------------------------------------------------------------
1078 {
1079 #ifndef Xyce_NO_MUTINDLIN_MASK
1080  Linear::Vector * maskVectorPtr = extData.deviceErrorWeightMask_;
1081 
1082  std::vector< InductorInstanceData* >::iterator currentInductor = instanceData.begin();
1083  std::vector< InductorInstanceData* >::iterator endInductor = instanceData.end();
1084  while( currentInductor != endInductor )
1085  {
1086  (*maskVectorPtr)[((*currentInductor)->li_Branch)] = 0.0;
1087  ++currentInductor;
1088  }
1089 #endif
1090 }
1091 
1092 //-----------------------------------------------------------------------------
1093 // Function : Instance::loadDAEQVector
1094 //
1095 // Purpose : Loads the Q-vector contributions for a single
1096 // Mutual Inductor instance.
1097 //
1098 // Special Notes : The "Q" vector is part of a standard DAE formalism in
1099 // which the system of equations is represented as:
1100 //
1101 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
1102 //
1103 // Scope : public
1104 // Creator : Rich Schiek, SNL, Parallel Computational Sciences
1105 // Creation Date : 03/21/2005
1106 //-----------------------------------------------------------------------------
1108 {
1109  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1110  {
1111  Xyce::dout() << "Instance::loadDAEQVector---------------------------" << std::endl
1112  << "\tname = " << getName() << std::endl;
1113  }
1114  double * qVec = extData.daeQVectorRawPtr;
1115 
1116  // calculate the following product
1117  // I = column vector of currents
1118  // L = row vector of inductances
1119  // LO = matrix = mutualCup * sqrt( L' * L )
1120  // LOI = column vector = mutualCup * sqrt( L' * L ) * I
1121  // LOI[1] = mutualCup * sqrt(L[1]*L[1])*I[1]) +
1122  // mutualCup * sqrt(L[1]*L[2])*I[2]) + ...
1123  // mutualCup * sqrt(L[1]*L[n])*I[n])
1124 
1125  for( int i = 0; i < numInductors; ++i )
1126  {
1127  LOI[ i ] = 0.0;
1128  for( int j = 0; j < numInductors; ++j )
1129  {
1130  LOI[i] += mutualCouplingCoef[i][j] * LO[i][j] * inductorCurrents[j];
1131  }
1132  }
1133 
1134  // loop over each inductor and load it's Q vector components
1135  std::vector< InductorInstanceData* >::iterator currentInductor = instanceData.begin();
1136  std::vector< InductorInstanceData* >::iterator endInductor = instanceData.end();
1137  int i=0;
1138  while( currentInductor != endInductor )
1139  {
1140  qVec[(*currentInductor)->li_Branch] += LOI[ i ];
1141  ++i;
1142  ++currentInductor;
1143  }
1144 
1145  return true;
1146 }
1147 
1148 //-----------------------------------------------------------------------------
1149 // Function : Instance::loadDAEFVector
1150 //
1151 // Purpose : Loads the F-vector contributions for a single
1152 // Mutual Inductor instance.
1153 //
1154 // Special Notes :
1155 //
1156 // Scope : public
1157 // Creator : Rich Schiek, SNL, Parallel Computational Sciences
1158 // Creation Date : 03/21/2005
1159 //-----------------------------------------------------------------------------
1161 {
1162  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1163  {
1164  Xyce::dout() << "Instance::loadDAEFVector---------------------------" << std::endl
1165  << "\tname = " << getName() << std::endl;
1166  }
1167 
1168  double * fVec = extData.daeFVectorRawPtr;
1169  double * solVec = extData.nextSolVectorRawPtr;
1170 
1171  // loop over each inductor and load it's F vector components
1172  std::vector< InductorInstanceData* >::iterator currentInductor = instanceData.begin();
1173  std::vector< InductorInstanceData* >::iterator endInductor = instanceData.end();
1174  int i = 0;
1175 
1176  while( currentInductor != endInductor )
1177  {
1178  double current = solVec[(*currentInductor)->li_Branch];
1179  double vNodePos = solVec[(*currentInductor)->li_Pos];
1180  double vNodeNeg = solVec[(*currentInductor)->li_Neg];
1181  fVec[((*currentInductor)->li_Pos)] += scalingRHS * current;
1182  fVec[((*currentInductor)->li_Neg)] += -scalingRHS * current;
1183  fVec[((*currentInductor)->li_Branch)] += -(vNodePos - vNodeNeg);
1184 
1185  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1186  {
1187  Xyce::dout() << " Inductor = " << (*currentInductor)->name
1188  << "\tcurrent = " << current
1189  << "\tvNodePos = " << vNodePos
1190  << "\tvNodeNeg = " << vNodeNeg
1191  << std::endl;
1192  }
1193 
1194  ++currentInductor;
1195  ++i;
1196  }
1197 
1198  return true;
1199 }
1200 
1201 //-----------------------------------------------------------------------------
1202 // Function : Instance::loadDAEdQdx
1203 //
1204 // Purpose : Loads the Q-vector contributions for a single
1205 // Mutual Inductor instance.
1206 // Scope : public
1207 // Creator : Rich Schiek, SNL, Parallel Computational Sciences
1208 // Creation Date : 03/21/2005
1209 //-----------------------------------------------------------------------------
1211 {
1212  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1213  {
1214  Xyce::dout() << "Instance::loadDAEdQdx--------------------------" << std::endl
1215  << "\tname = " << getName() << std::endl;
1216  }
1217 
1218  // During the DCOP, the dQdx*pdt matrix is summed into the Jacobian,
1219  // even though the Q*pdt vector is not summed into the residual.
1220  //if (!getSolverState().dcopFlag)
1221  {
1222  Linear::Matrix & dQdx = *(extData.dQdxMatrixPtr);
1223 
1224  // loop over each inductor and load it's Q vector components
1225  std::vector< InductorInstanceData* >::iterator currentInductor = instanceData.begin();
1226  std::vector< InductorInstanceData* >::iterator endInductor = instanceData.end();
1227  int i=0;
1228  while( currentInductor != endInductor )
1229  {
1230  for( int j=0; j<numInductors; ++j )
1231  {
1232  dQdx[((*currentInductor)->li_Branch)]
1233  [(*currentInductor)->inductorCurrentOffsets[j]] += mutualCouplingCoef[i][j] * LO[i][j];
1234  }
1235  // finally do all the dependent variable terms
1236  int numdepterms=(*currentInductor)->depVarPairs.size();
1237  for (int j=0 ; j<numdepterms; ++j)
1238  {
1239  int coefficientNumber=(*currentInductor)->depVarPairs[j].first;
1240  int depVarNumber=(*currentInductor)->depVarPairs[j].second;
1241  int otherInductor;
1242 
1243  // indexPairs[coefficient] gives the two inductors coupled by that
1244  // coefficient. One of them is currentInductor because we saved that
1245  // coefficient number in our depVarPairs, so the other is the one
1246  // we need to know
1247 
1248  if (i==indexPairs[coefficientNumber].first)
1249  otherInductor=indexPairs[coefficientNumber].second;
1250  else
1251  otherInductor=indexPairs[coefficientNumber].first;
1252 
1253  dQdx[((*currentInductor)->li_Branch)][(*currentInductor)->ABraEquDepVarOffsets[j]] +=
1254  couplingCoefficientVarDerivs[coefficientNumber][depVarNumber]
1255  *LO[i][otherInductor]*inductorCurrents[otherInductor];
1256  }
1257 
1258  ++i;
1259  ++currentInductor;
1260  }
1261  }
1262 
1263  return true;
1264 }
1265 
1266 //-----------------------------------------------------------------------------
1267 // Function : Instance::loadDAEdFdx ()
1268 //
1269 // Purpose : Loads the F-vector contributions for a single
1270 // Mutual Inductor instance.
1271 //
1272 // Special Notes :
1273 //
1274 // Scope : public
1275 // Creator : Rich Schiek, SNL, Parallel Computational Sciences
1276 // Creation Date : 03/21/2005
1277 //-----------------------------------------------------------------------------
1279 {
1280  Linear::Matrix & dFdx = *(extData.dFdxMatrixPtr);
1281 
1282  // loop over each inductor and load it's dFdx components
1283  std::vector< InductorInstanceData* >::iterator currentInductor = instanceData.begin();
1284  std::vector< InductorInstanceData* >::iterator endInductor = instanceData.end();
1285  while( currentInductor != endInductor )
1286  {
1287  dFdx[((*currentInductor)->li_Pos)] [((*currentInductor)->APosEquBraVarOffset)] += scalingRHS;
1288  dFdx[((*currentInductor)->li_Neg)] [((*currentInductor)->ANegEquBraVarOffset)] += -scalingRHS;
1289  dFdx[((*currentInductor)->li_Branch)][((*currentInductor)->ABraEquPosNodeOffset)] += -1.0;
1290  dFdx[((*currentInductor)->li_Branch)][((*currentInductor)->ABraEquNegNodeOffset)] += 1.0;
1291 
1292  ++currentInductor;
1293  }
1294 
1295  return true;
1296 }
1297 
1298 //-----------------------------------------------------------------------------
1299 // Function : Instance::setIC
1300 // Purpose :
1301 // Special Notes :
1302 // Scope : public
1303 // Creator : Rich Schiek, SNL, Parallel Computational Sciences
1304 // Creation Date : 03/21/2005
1305 //-----------------------------------------------------------------------------
1307 {
1308  int i_bra_sol;
1309  int i_f_state;
1310 
1311  bool bsuccess = true;
1312  return bsuccess;
1313 }
1314 
1315 //-----------------------------------------------------------------------------
1316 // Function : Instance::varTypes
1317 // Purpose :
1318 // Special Notes :
1319 // Scope : public
1320 // Creator : Rich Schiek, SNL, Parallel Computational Sciences
1321 // Creation Date : 03/21/2005
1322 //-----------------------------------------------------------------------------
1323 void Instance::varTypes( std::vector<char> & varTypeVec )
1324 {
1325  varTypeVec.resize(numInductors);
1326  for(int i=0; i<numInductors; i++)
1327  {
1328  varTypeVec[i] = 'I';
1329  }
1330 }
1331 
1332 //-----------------------------------------------------------------------------
1333 // Function : Model::processParams
1334 // Purpose :
1335 // Special Notes :
1336 // Scope : public
1337 // Creator : Rich Schiek, SNL, Parallel Computational Sciences
1338 // Creation Date : 03/21/2005
1339 //-----------------------------------------------------------------------------
1341 {
1342  return true;
1343 }
1344 
1345 //----------------------------------------------------------------------------
1346 // Function : Model::processInstanceParams
1347 // Purpose :
1348 // Special Notes :
1349 // Scope : public
1350 // Creator : Dave Shirely, PSSI
1351 // Creation Date : 03/23/06
1352 //----------------------------------------------------------------------------
1354 {
1355  std::vector<Instance*>::iterator iter;
1356  std::vector<Instance*>::iterator first = instanceContainer.begin();
1357  std::vector<Instance*>::iterator last = instanceContainer.end();
1358 
1359  for (iter=first; iter!=last; ++iter)
1360  {
1361  (*iter)->processParams();
1362  }
1363 
1364  return true;
1365 }
1366 
1367 //-----------------------------------------------------------------------------
1368 // Function : Model::Model
1369 // Purpose : block constructor
1370 // Special Notes :
1371 // Scope : public
1372 // Creator : Rich Schiek, SNL, Parallel Computational Sciences
1373 // Creation Date : 03/21/2005
1374 //-----------------------------------------------------------------------------
1376  const Configuration & configuration,
1377  const ModelBlock & MB,
1378  const FactoryBlock & factory_block)
1379  : DeviceModel(MB, configuration.getModelParameters(), factory_block),
1380  tempCoeff1(0.0),
1381  tempCoeff2(0.0),
1382  tnom(getDeviceOptions().tnom)
1383 {
1384 
1385  // Set params to constant default values:
1386  setDefaultParams ();
1387 
1388  // Set params according to .model line and constant defaults from metadata:
1389  setModParams (MB.params);
1390 
1391  // Set any non-constant parameter defaults:
1392  if (!given("TNOM"))
1394 
1395  // Calculate any parameters specified as expressions:
1397 
1398  // calculate dependent (ie computed) params and check for errors:
1399  processParams ();
1400 }
1401 
1402 //-----------------------------------------------------------------------------
1403 // Function : Model::~Model
1404 // Purpose : destructor
1405 // Special Notes :
1406 // Scope : public
1407 // Creator : Rich Schiek, SNL, Parallel Computational Sciences
1408 // Creation Date : 03/21/2005
1409 //-----------------------------------------------------------------------------
1411 {
1412  std::vector<Instance*>::iterator iter;
1413  std::vector<Instance*>::iterator first = instanceContainer.begin();
1414  std::vector<Instance*>::iterator last = instanceContainer.end();
1415 
1416  for (iter=first; iter!=last; ++iter)
1417  {
1418  delete (*iter);
1419  }
1420 
1421 }
1422 
1423 // additional Declarations
1424 
1425 //-----------------------------------------------------------------------------
1426 // Function : Model::printOutInstances
1427 // Purpose : debugging tool.
1428 // Special Notes :
1429 // Scope : public
1430 // Creator : Rich Schiek, SNL, Parallel Computational Sciences
1431 // Creation Date : 03/21/2005
1432 //-----------------------------------------------------------------------------
1433 std::ostream &Model::printOutInstances(std::ostream &os) const
1434 {
1435  std::vector<Instance*>::const_iterator iter;
1436  std::vector<Instance*>::const_iterator first = instanceContainer.begin();
1437  std::vector<Instance*>::const_iterator last = instanceContainer.end();
1438 
1439  int i, isize;
1440  isize = instanceContainer.size();
1441 
1442  os << std::endl;
1443  os << "Number of MutIndLin instances: " << isize << std::endl;
1444  os << " name=\t\tmodelName\tParameters" << std::endl;
1445  for (i=0, iter=first; iter!=last; ++iter, ++i)
1446  {
1447  os << " " << i << ": " << (*iter)->getName() << "\t";
1448  os << getName();
1449  os << std::endl;
1450  }
1451 
1452  os << std::endl;
1453 
1454  return os;
1455 }
1456 
1457 //-----------------------------------------------------------------------------
1458 // Function : Model::forEachInstance
1459 // Purpose :
1460 // Special Notes :
1461 // Scope : public
1462 // Creator : David Baur
1463 // Creation Date : 2/4/2014
1464 //-----------------------------------------------------------------------------
1465 /// Apply a device instance "op" to all instances associated with this
1466 /// model
1467 ///
1468 /// @param[in] op Operator to apply to all instances.
1469 ///
1470 ///
1471 void Model::forEachInstance(DeviceInstanceOp &op) const /* override */
1472 {
1473  for (std::vector<Instance *>::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
1474  op(*it);
1475 }
1476 
1477 
1478 // MutIndLin Master functions:
1479 
1480 //-----------------------------------------------------------------------------
1481 // Function : Master::updateState
1482 // Purpose :
1483 // Special Notes :
1484 // Scope : public
1485 // Creator : Eric Keiter, SNL
1486 // Creation Date : 12/12/08
1487 //-----------------------------------------------------------------------------
1488 bool Master::updateState (double * solVec, double * staVec, double * stoVec)
1489 {
1490  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
1491  {
1492  Instance & inst = *(*it);
1493 
1494  // Evaluate the derivatives of all (dependent) coupling coefficients w.r.t
1495  // their variables. We need these for both new and old DAE.
1496  int ncoupcoef=inst.couplingCoefficient.size();
1497  for (int i=0; i<ncoupcoef; ++i)
1498  {
1499  if (inst.expPtrs[i])
1500  {
1501  double junk;
1502  inst.expPtrs[i]->evaluate( junk, inst.couplingCoefficientVarDerivs[i]);
1503  }
1504  }
1505 
1506  // get the currents in each inductor
1507  std::vector< InductorInstanceData* >::iterator
1508  currentInductor = inst.instanceData.begin();
1509  std::vector< InductorInstanceData* >::iterator
1510  endInductor = inst.instanceData.end();
1511  {
1512  int i = 0;
1513  while( currentInductor != endInductor )
1514  {
1515  if( (getSolverState().dcopFlag) && ((*currentInductor)->ICGiven) )
1516  {
1517  inst.inductorCurrents[ i ] = (*currentInductor)->IC;
1518  }
1519  else
1520  {
1521  inst.inductorCurrents[ i ] = solVec[ (*currentInductor)->li_Branch ];
1522  }
1523  ++i;
1524  ++currentInductor;
1525  }
1526  }
1527  }
1528 
1529  return true;
1530 }
1531 
1532 //-----------------------------------------------------------------------------
1533 // Function : Master::loadDAEVectors
1534 // Purpose :
1535 // Special Notes :
1536 // Scope : public
1537 // Creator : Eric Keiter, SNL
1538 // Creation Date : 12/12/08
1539 //-----------------------------------------------------------------------------
1540 bool Master::loadDAEVectors (double * solVec, double * fVec, double *qVec, double * bVec, double * storeLeadF, double * storeLeadQ, double * leadF, double * leadQ, double * junctionV)
1541 {
1542  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
1543  {
1544  Instance & inst = *(*it);
1545 
1546  // F-vector:
1547  // loop over each inductor and load it's F vector components
1548  std::vector< InductorInstanceData* >::iterator currentInductor = inst.instanceData.begin();
1549  std::vector< InductorInstanceData* >::iterator endInductor = inst.instanceData.end();
1550 
1551  while( currentInductor != endInductor )
1552  {
1553  double current = solVec[(*currentInductor)->li_Branch];
1554  double vNodePos = solVec[(*currentInductor)->li_Pos];
1555  double vNodeNeg = solVec[(*currentInductor)->li_Neg];
1556 
1557  fVec[((*currentInductor)->li_Pos)] += inst.scalingRHS * current;
1558  fVec[((*currentInductor)->li_Neg)] += -inst.scalingRHS * current;
1559  fVec[((*currentInductor)->li_Branch)] += -(vNodePos - vNodeNeg);
1560 
1561  ++currentInductor;
1562  }
1563 
1564  // Q-vector:
1565  // calculate the following product
1566  // I = column vector of currents
1567  // L = row vector of inductances
1568  // LO = matrix = mutualCup * sqrt( L' * L )
1569  // LOI = column vector = mutualCup * sqrt( L' * L ) * I
1570  // LOI[1] = mutualCup * sqrt(L[1]*L[1])*I[1]) +
1571  // mutualCup * sqrt(L[1]*L[2])*I[2]) + ...
1572  // mutualCup * sqrt(L[1]*L[n])*I[n])
1573 
1574  for( int i = 0; i < inst.numInductors; ++i )
1575  {
1576  inst.LOI[ i ] = 0.0;
1577  for( int j = 0; j < inst.numInductors; ++j )
1578  {
1579  inst.LOI[i] += inst.mutualCouplingCoef[i][j] * inst.LO[i][j] * inst.inductorCurrents[j];
1580  }
1581  }
1582 
1583  // loop over each inductor and load it's Q vector components
1584  currentInductor = inst.instanceData.begin();
1585  endInductor = inst.instanceData.end();
1586  int li=0;
1587  while( currentInductor != endInductor )
1588  {
1589  qVec[(*currentInductor)->li_Branch] += inst.LOI[ li ];
1590  ++li;
1591  ++currentInductor;
1592  }
1593  }
1594  return true;
1595 }
1596 
1597 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
1598 //-----------------------------------------------------------------------------
1599 // Function : Master::loadDAEMatrices
1600 // Purpose :
1601 // Special Notes :
1602 // Scope : public
1603 // Creator : Eric Keiter, SNL
1604 // Creation Date : 12/12/08
1605 //-----------------------------------------------------------------------------
1606 bool Master::loadDAEMatrices (Linear::Matrix & dFdx, Linear::Matrix & dQdx)
1607 {
1608  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
1609  {
1610  Instance & inst = *(*it);
1611  // loop over each inductor and load it's dFdx components
1612  std::vector< InductorInstanceData* >::iterator currentInductor = inst.instanceData.begin();
1613  std::vector< InductorInstanceData* >::iterator endInductor = inst.instanceData.end();
1614  while( currentInductor != endInductor )
1615  {
1616  *((*currentInductor)->f_PosEquBraVarPtr) += inst.scalingRHS;
1617  *((*currentInductor)->f_NegEquBraVarPtr) += -inst.scalingRHS;
1618  *((*currentInductor)->f_BraEquPosNodePtr) += -1.0;
1619  *((*currentInductor)->f_BraEquNegNodePtr) += 1.0;
1620 
1621  ++currentInductor;
1622  }
1623 
1624  // During the DCOP, the dQdx*pdt matrix is summed into the Jacobian,
1625  // even though the Q*pdt vector is not summed into the residual.
1626  //if (!getSolverState().dcopFlag)
1627  {
1628  // loop over each inductor and load it's Q vector components
1629  currentInductor = inst.instanceData.begin();
1630  endInductor = inst.instanceData.end();
1631  int li=0;
1632  while( currentInductor != endInductor )
1633  {
1634  for( int j=0; j<inst.numInductors; ++j )
1635  {
1636  *((*currentInductor)->q_inductorCurrentPtrs[j]) += inst.mutualCouplingCoef[li][j] * inst.LO[li][j];
1637  }
1638  // finally do all the dependent variable terms
1639  int numdepterms=(*currentInductor)->depVarPairs.size();
1640  for (int j=0 ; j<numdepterms; ++j)
1641  {
1642  int coefficientNumber=(*currentInductor)->depVarPairs[j].first;
1643  int depVarNumber=(*currentInductor)->depVarPairs[j].second;
1644  int otherInductor;
1645 
1646  // indexPairs[coefficient] gives the two inductors coupled by that
1647  // coefficient. One of them is currentInductor because we saved that
1648  // coefficient number in our depVarPairs, so the other is the one
1649  // we need to know
1650 
1651  if (li==inst.indexPairs[coefficientNumber].first)
1652  otherInductor=inst.indexPairs[coefficientNumber].second;
1653  else
1654  otherInductor=inst.indexPairs[coefficientNumber].second;
1655 
1656  *((*currentInductor)->q_BraEquDepVarPtrs[j]) +=
1657  inst.couplingCoefficientVarDerivs[coefficientNumber][depVarNumber]
1658  *inst.LO[li][otherInductor]*inst.inductorCurrents[otherInductor];
1659  }
1660 
1661  ++li;
1662  ++currentInductor;
1663  }
1664  }
1665  }
1666 
1667  return true;
1668 }
1669 
1670 #else
1671 //-----------------------------------------------------------------------------
1672 // Function : Master::loadDAEMatrices
1673 // Purpose :
1674 // Special Notes :
1675 // Scope : public
1676 // Creator : Eric Keiter, SNL
1677 // Creation Date : 12/12/08
1678 //-----------------------------------------------------------------------------
1679 bool Master::loadDAEMatrices (Linear::Matrix & dFdx, Linear::Matrix & dQdx)
1680 {
1681  int sizeInstances = instanceContainer_.size();
1682  for (int i=0; i<sizeInstances; ++i)
1683  {
1684  Instance & inst = *(instanceContainer_.at(i));
1685  // loop over each inductor and load it's dFdx components
1686  std::vector< InductorInstanceData* >::iterator currentInductor = inst.instanceData.begin();
1687  std::vector< InductorInstanceData* >::iterator endInductor = inst.instanceData.end();
1688  while( currentInductor != endInductor )
1689  {
1690  dFdx[((*currentInductor)->li_Pos)] [((*currentInductor)->APosEquBraVarOffset)] += inst.scalingRHS;
1691  dFdx[((*currentInductor)->li_Neg)] [((*currentInductor)->ANegEquBraVarOffset)] += -inst.scalingRHS;
1692  dFdx[((*currentInductor)->li_Branch)][((*currentInductor)->ABraEquPosNodeOffset)] += -1.0;
1693  dFdx[((*currentInductor)->li_Branch)][((*currentInductor)->ABraEquNegNodeOffset)] += 1.0;
1694 
1695  ++currentInductor;
1696  }
1697 
1698  // During the DCOP, the dQdx*pdt matrix is summed into the Jacobian,
1699  // even though the Q*pdt vector is not summed into the residual.
1700  //if (!getSolverState().dcopFlag)
1701  {
1702  // loop over each inductor and load it's Q vector components
1703  currentInductor = inst.instanceData.begin();
1704  endInductor = inst.instanceData.end();
1705  int i=0;
1706  while( currentInductor != endInductor )
1707  {
1708  for( int j=0; j<inst.numInductors; ++j )
1709  {
1710  dQdx[((*currentInductor)->li_Branch)]
1711  [(*currentInductor)->inductorCurrentOffsets[j]] += inst.mutualCouplingCoef[i][j] * inst.LO[i][j];
1712  }
1713  // finally do all the dependent variable terms
1714  int numdepterms=(*currentInductor)->depVarPairs.size();
1715  for (int j=0 ; j<numdepterms; ++j)
1716  {
1717  int coefficientNumber=(*currentInductor)->depVarPairs[j].first;
1718  int depVarNumber=(*currentInductor)->depVarPairs[j].second;
1719  int otherInductor;
1720 
1721  // indexPairs[coefficient] gives the two inductors coupled by that
1722  // coefficient. One of them is currentInductor because we saved that
1723  // coefficient number in our depVarPairs, so the other is the one
1724  // we need to know
1725 
1726  if (i==inst.indexPairs[coefficientNumber].first)
1727  otherInductor=inst.indexPairs[coefficientNumber].second;
1728  else
1729  otherInductor=inst.indexPairs[coefficientNumber].second;
1730 
1731  dQdx[((*currentInductor)->li_Branch)][(*currentInductor)->ABraEquDepVarOffsets[j]] +=
1732  inst.couplingCoefficientVarDerivs[coefficientNumber][depVarNumber]
1733  *inst.LO[i][otherInductor]*inst.inductorCurrents[otherInductor];
1734  }
1735 
1736  ++i;
1737  ++currentInductor;
1738  }
1739  }
1740  }
1741  return true;
1742 }
1743 #endif
1744 
1745 Device *Traits::factory(const Configuration &configuration, const FactoryBlock &factory_block)
1746 {
1747 
1748  return new Master(configuration, factory_block, factory_block.solverState_, factory_block.deviceOptions_);
1749 }
1750 
1752 {
1754  .registerDevice("mil", 1)
1755  .registerModelType("mil", 1);
1756 }
1757 
1758 } // namespace MutIndLin
1759 } // namespace Device
1760 } // namespace Xyce
const InstanceName & getName() const
std::vector< double * > f_inductorCurrentPtrs
std::vector< std::vector< double > > mutualCouplingCoef
const DeviceOptions & deviceOptions_
Descriptor & addPar(const char *parName, T default_value, T U::*varPtr)
Adds the parameter description to the parameter map.
Definition: N_DEV_Pars.h:1429
const std::string & getSubcircuitName() const
Decodes the device name.
bool given(const std::string &parameter_name) const
Pure virtual class to augment a linear system.
Devices and models are each named.
const std::vector< std::string > & getDepSolnVars()
void addInternalNode(Util::SymbolTable &symbol_table, int index, const InstanceName &instance_name, const std::string &lead_name)
const std::string & getEncodedName() const
Return the instance name encoded as: [s:]*xname [s:]*Ytype!name [s:]*Utype!name!count.
std::vector< std::vector< int > > jacStamp
void loadNodeSymbols(Util::SymbolTable &symbol_table) const
Populates and returns the store name map.
InstanceVector::const_iterator getInstanceEnd() const
Returns an iterator to the ending of the vector of all instances created for this device...
const std::vector< Depend > & getDependentParams()
std::vector< std::vector< double > > couplingCoefficientVarDerivs
#define AssertLIDs(cmp)
virtual void forEachInstance(DeviceInstanceOp &op) const
Apply a device instance "op" to all instances associated with this model.
virtual void registerJacLIDs(const JacobianStamp &jacLIDVec)
const std::vector< std::vector< int > > & jacobianStamp() const
std::vector< std::string > inductorsNode1
std::vector< std::string > inductorNames
double tnom
nominal temperature for device params.
InstanceVector::const_iterator getInstanceBegin() const
Returns an iterator to the beginning of the vector of all instances created for this device...
bool updateTemperature(const double &temp_tmp)
Instance(const Configuration &configuration, const InstanceBlock &IB, Model &Iiter, const FactoryBlock &factory_block)
std::vector< Param > params
Parameters from the line.
void setParams(const std::vector< Param > &params)
const std::string & getName() const
virtual bool loadDAEMatrices(Linear::Matrix &dFdx, Linear::Matrix &dQdx)
Populates the device's Jacobian object with these pointers.
The FactoryBlock contains parameters needed by the device, instance and model creation functions...
bool processInstanceParams()
processInstanceParams
void varTypes(std::vector< char > &varTypeVec)
const DeviceOptions & getDeviceOptions() const
std::vector< std::string > couplingInductor
Linear::Vector * deviceErrorWeightMask_
std::vector< std::pair< int, int > > depVarPairs
static Config< T > & addConfiguration()
Adds the device to the Xyce device configuration.
std::vector< double > inductorCurrents
Linear::Matrix * dFdxMatrixPtr
static void loadModelParameters(ParametricData< Model > &model_parameters)
void registerLIDs(const std::vector< int > &intLIDVecRef, const std::vector< int > &extLIDVecRef)
virtual bool loadDAEVectors(double *solVec, double *fVec, double *qVec, double *bVec, double *storeLeadF, double *storeLeadQ, double *leadF, double *leadQ, double *junctionV)
Populates the device's ExternData object with these pointers.
bool processParams()
processParams
The Device class is an interface for device implementations.
Definition: N_DEV_Device.h:101
const SolverState & solverState_
std::vector< double > inductanceVals
Class Configuration contains device configuration data.
#define L
virtual std::ostream & printOutInstances(std::ostream &os) const
const SolverState & getSolverState() const
std::vector< int > inductorCurrentOffsets
std::vector< double > inductorInductances
static Device * factory(const Configuration &configuration, const FactoryBlock &factory_block)
#define Xyce_NONPOINTER_MATRIX_LOAD
Definition: N_DEV_Bsrc.C:97
std::vector< double * > q_inductorCurrentPtrs
std::string spiceInternalName(const InstanceName &instance_name, const std::string &lead)
std::vector< double > couplingCoefficient
void registerJacLIDs(const std::vector< std::vector< int > > &jacLIDVec)
std::vector< std::pair< int, int > > indexPairs
ModelBlock represents a .MODEL line from the netlist.
std::vector< Util::Expression * > expPtrs
Parameter may be specified as a solution dependent expression from netlist.
Definition: N_DEV_Pars.h:68
Manages parameter binding for class C.
Definition: N_DEV_Pars.h:214
InstanceBlock represent a device instance line from the netlist.
std::vector< Instance * > instanceContainer
std::vector< std::vector< double > > LO
std::vector< Param > params
std::vector< std::vector< double > > mutualCouplingCoefDerivs
Linear::Matrix * dQdxMatrixPtr
void registerStateLIDs(const std::vector< int > &staLIDVecRef)
static void loadInstanceParameters(ParametricData< Instance > &instance_parameters)
std::vector< InductorInstanceData * > instanceData
std::vector< std::string > inductorsNode2
virtual bool updateState(double *solVec, double *staVec, double *stoVec)
Updates the devices state information.
virtual const std::vector< std::string > & getDepSolnVars()
const SolverState & getSolverState() const
Returns the solver state given during device construction.
void setModParams(const std::vector< Param > &params)