Xyce  6.1
N_DEV_PowerGridBranch.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_PowerGridBranch.C,v $
27 //
28 // Purpose : PowerGrid classes: provides a device that calculates the
29 // steady state power flow in a transmission grid branch
30 //
31 // Special Notes : Experimental new device for an LDRD.
32 //
33 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
34 //
35 // Creation Date : 9/12/14
36 //
37 // Revision Information:
38 // ---------------------
39 //
40 // Revision Number: $Revision: 1.17 $
41 //
42 // Revision Date : $Date: 2015/10/21 17:14:21 $
43 //
44 // Current Owner : $Author: peshola $
45 //----------------------------------------------------------------------------
46 
47 #include <Xyce_config.h>
48 
49 
50 // ---------- Standard Includes ----------
51 
52 // ---------- Xyce Includes ----------
53 #include <N_DEV_PowerGridBranch.h>
54 #include <N_DEV_Const.h>
55 #include <N_DEV_DeviceOptions.h>
56 #include <N_DEV_DeviceMaster.h>
57 #include <N_DEV_ExternData.h>
58 #include <N_DEV_MatrixLoadData.h>
59 #include <N_DEV_Message.h>
60 #include <N_DEV_SolverState.h>
61 
62 #include <N_LAS_Matrix.h>
63 #include <N_LAS_Vector.h>
64 
65 #include <N_UTL_ExtendedString.h>
66 #include <N_UTL_FeatureTest.h>
67 #include <N_UTL_IndentStreamBuf.h>
68 
69 namespace Xyce {
70 namespace Device {
71 namespace PowerGridBranch {
72 
73 // enables debug output for just this device
74 //static const int DEBUG_DEVICE = 1;
75 
77 {
78  p.addPar("AT", std::string("PQP"), &PowerGridBranch::Instance::analysisTypeStr_)
79  .setUnit(U_NONE)
80  .setDescription("Analysis Type");
81 
83  .setExpressionAccess(ParameterType::TIME_DEP)
84  .setUnit(U_PERUNIT)
85  .setDescription("Branch Resistance");
86 
88  .setExpressionAccess(ParameterType::TIME_DEP)
89  .setUnit(U_PERUNIT)
90  .setDescription("Branch Reactance");
91 
93  .setExpressionAccess(ParameterType::TIME_DEP)
94  .setUnit(U_PERUNIT)
95  .setDescription("Branch Shunt Susceptance");
96 
97  // turnsRatio_ was moved into the transformer model
98  //p.addPar("TR", 1.0, &PowerGridBranch::Instance::turnsRatio_)
99  // .setExpressionAccess(ParameterType::TIME_DEP)
100  // .setUnit(U_NONE)
101  // .setDescription("Transformer Turns Ratio");
102 
103  // the bus shunts were implemented in the PowerGridBusShunt device.
104  // that is the preferred way to include bus shunts in a netlist.
105  // The approach of adding them to a branch model was the initial implementation.
106  //p.addPar("B1SC", 1.0, &PowerGridBranch::Instance::bus1ShuntConductance_)
107  // .setExpressionAccess(ParameterType::TIME_DEP)
108  // .setUnit(U_OHM)
109  // .setDescription("Bus1 Shunt Conductance");
110 
111  //p.addPar("B2SC", 1.0, &PowerGridBranch::Instance::bus2ShuntConductance_)
112  // .setExpressionAccess(ParameterType::TIME_DEP)
113  // .setUnit(U_OHM)
114  // .setDescription("Bus2 Shunt Conductance");
115 
116  //p.addPar("B1SS", 1.0, &PowerGridBranch::Instance::bus1ShuntSusceptance_)
117  // .setExpressionAccess(ParameterType::TIME_DEP)
118  // .setUnit(U_OHM)
119  // .setDescription("Bus1 Shunt Susceptance");
120 
121  //p.addPar("B2SS", 1.0, &PowerGridBranch::Instance::bus1ShuntSusceptance_)
122  // .setExpressionAccess(ParameterType::TIME_DEP)
123  // .setUnit(U_OHM)
124  // .setDescription("Bus2 Shunt Susceptance");
125 }
126 
128 {}
129 
130 
131 
132 std::vector< std::vector<int> > Instance::jacStamp;
133 
134 // Class Instance
135 //-----------------------------------------------------------------------------
136 // Function : Instance::Instance
137 // Purpose : "instance block" constructor
138 // Special Notes :
139 // Scope : public
140 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
141 // Creation Date : 10/16/14
142 //-----------------------------------------------------------------------------
144  const Configuration & configuration,
145  const InstanceBlock & IB,
146  Model & Miter,
147  const FactoryBlock & factory_block)
148  : DeviceInstance(IB, configuration.getInstanceParameters(), factory_block),
149  model_(Miter),
150  analysisTypeStr_("PQP"),
151  analysisType_(PQP),
152  branchResistance_(1.0),
153  branchReactance_(1.0),
154  branchSusceptance_(1.0)
155  // these parameters were moved into the transformer and bus shunt models
156  //turnsRatio_(1.0),
157  //bus1ShuntConductance_(0.0),
158  //bus2ShuntConductance_(0.0),
159  //bus1ShuntSusceptance_(0.0),
160  //bus2ShuntSusceptance_(0.0)
161 {
162  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
163  {
164  Xyce::dout() << std::endl << "In device constructor for " << getName() << std::endl;
165  }
166 
167  std::vector<Param>::const_iterator iter = IB.params.begin();
168  std::vector<Param>::const_iterator last = IB.params.end();
169 
170  for ( ; iter != last; ++iter)
171  {
172  const std::string & tmpname = iter->tag();
173  const bool & tmpgiven = iter->given();
174 
175  // copy instance parameter values into private variables
176  if (tmpname == "AT" && tmpgiven == true)
177  {
178  ExtendedString atStr(iter->stringValue());
179  atStr.toUpper();
180  if ( atStr == "IV" )
181  {
182  analysisType_ = IV;
183  analysisTypeStr_ = "IV";
184  }
185  else if ( atStr == "PQR" )
186  {
187  analysisType_ = PQR;
188  analysisTypeStr_ = "PQR";
189  }
190  else if ( atStr == "PQP" )
191  {
192  analysisType_ = PQP;
193  analysisTypeStr_ = "PQP";
194  }
195  else
196  {
197  UserError0(*this) << "Analysis Type must be IV, PQR or PQP in power grid device: " << getName();
198  }
199  }
200  if (tmpname == "R" && tmpgiven == true)
201  {
202  branchResistance_ = iter->getImmutableValue<double>();
203  }
204  if (tmpname == "X" && tmpgiven == true)
205  {
206  branchReactance_ = iter->getImmutableValue<double>();
207  }
208  if (tmpname == "B" && tmpgiven == true)
209  {
210  branchSusceptance_ = iter->getImmutableValue<double>();
211  }
212  // TR parameter was moved into the transformer model
213  //if (tmpname == "TR" && tmpgiven == true)
214  //{
215  // turnsRatio_ = iter->getImmutableValue<double>();
216  //}
217  // bus shunt parameters were moved into the bus shunt device
218  //if (tmpname == "B1SC" && tmpgiven == true)
219  //{
220  // bus1ShuntConductance_ = iter->getImmutableValue<double>();
221  //}
222  //if (tmpname == "B2SC" && tmpgiven == true)
223  //{
224  // bus2ShuntConductance_ = iter->getImmutableValue<double>();
225  //}
226  //if (tmpname == "B1SS" && tmpgiven == true)
227  //{
228  // bus1ShuntSusceptance_ = iter->getImmutableValue<double>();
229  //}
230  //if (tmpname == "B2SS" && tmpgiven == true)
231  //{
232  // bus2ShuntSusceptance_ = iter->getImmutableValue<double>();
233  //}
234  }
235 
236  numIntVars = 0;
237  numExtVars = 4;
238  numStateVars = 0;
239 
240  // Calculate the Y parameters from the branch data
241  //calculateYParameters();
242  std::complex<double> zVal, selfVal;
243 
244  // makes equations easier to read
245  //double invTurnsRatio = (1./turnsRatio_);
246  zVal=std::complex<double>(branchResistance_,branchReactance_);
247 
248  // off-diagonal elements are identical but specify both of them because it makes
249  // the rest of the code (in the F and dF/dX functions) more readable
250  //y12 = (-1./zVal) * invTurnsRatio;
251  //y21 = (-1./zVal) * invTurnsRatio;
252  y12 = (-1./zVal);
253  y21 = (-1./zVal);
254 
255  // diagonal elements
256  selfVal = (1./zVal);
257  selfVal = std::complex<double>(selfVal.real(),selfVal.imag() + 0.5*branchSusceptance_);
258  //y11 = selfVal*invTurnsRatio*invTurnsRatio;
259  y11 = selfVal;
260  y22 = selfVal;
261 
262  // parameters moved to bus shunt model
263  //y11 = std::complex<double>(y11.real() + bus1ShuntConductance_, y11.imag() + bus1ShuntSusceptance_);
264  //y22 = std::complex<double>(y22.real() + bus2ShuntConductance_, y22.imag() + bus2ShuntSusceptance_);
265 
266  // get the real and imaginary parts. It makes the rest of the code (in the F and dF/dX
267  // functions) more readable
268  g11 = y11.real();
269  b11 = y11.imag();
270  g12 = y12.real();
271  b12 = y12.imag();
272  g21 = y21.real();
273  b21 = y21.imag();
274  g22 = y22.real();
275  b22 = y22.imag();
276 
277  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
278  {
279  Xyce::dout() << getName() << " G's and B's are:"
280  << Util::push << std::endl
281  << "(g11,b11) = (" << g11 << " , " << b11 << ")" << std::endl
282  << "(g12,b12) = (" << g12 << " , " << b12 << ")" << std::endl
283  << "(g21,b21) = (" << g21 << " , " << b21 << ")" << std::endl
284  << "(g22,b22) = (" << g22 << " , " << b22 << ")" << std::endl
285  << std::endl;
286  }
287 
288  if( jacStamp.empty() )
289  {
290  jacStamp.resize(4);
291  jacStamp[0].resize(4);
292  jacStamp[1].resize(4);
293  jacStamp[2].resize(4);
294  jacStamp[3].resize(4);
295 
296  jacStamp[0][0] = 0;
297  jacStamp[0][1] = 1;
298  jacStamp[0][2] = 2;
299  jacStamp[0][3] = 3;
300  jacStamp[1][0] = 0;
301  jacStamp[1][1] = 1;
302  jacStamp[1][2] = 2;
303  jacStamp[1][3] = 3;
304  jacStamp[2][0] = 0;
305  jacStamp[2][1] = 1;
306  jacStamp[2][2] = 2;
307  jacStamp[2][3] = 3;
308  jacStamp[3][0] = 0;
309  jacStamp[3][1] = 1;
310  jacStamp[3][2] = 2;
311  jacStamp[3][3] = 3;
312  }
313 
314  // Set params to constant default values:
315  setDefaultParams ();
316 
317  // Set params according to instance line and constant defaults from metadata:
318  setParams (IB.params);
319 
320  // Set any non-constant parameter defaults:
321 
322 }
323 
324 //-----------------------------------------------------------------------------
325 // Function : Instance::~Instance
326 // Purpose : destructor
327 // Special Notes :
328 // Scope : public
329 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
330 // Creation Date : 9/12/14
331 //-----------------------------------------------------------------------------
333 {
334 }
335 
336 //-----------------------------------------------------------------------------
337 // Function : Instance::registerLIDs
338 // Purpose :
339 // Special Notes :
340 // Scope : public
341 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
342 // Creation Date : 9/12/14
343 //-----------------------------------------------------------------------------
344 void Instance::registerLIDs( const std::vector<int> & intLIDVecRef,
345  const std::vector<int> & extLIDVecRef )
346 {
347  AssertLIDs(intLIDVecRef.size() == numIntVars);
348  AssertLIDs(extLIDVecRef.size() == numExtVars);
349 
350  // copy over the global ID lists.
351  intLIDVec = intLIDVecRef;
352  extLIDVec = extLIDVecRef;
353 
354  // in general, there will be 4 I/0 nodes for each branch.
355  // These if-else blocks may be made into separate classes,
356  // in the final version of this model.
357  if ( analysisType_ == IV || analysisType_ == PQR)
358  {
359  li_VR1 = extLIDVec[0];
360  li_VR2 = extLIDVec[1];
361  li_VI1 = extLIDVec[2];
362  li_VI2 = extLIDVec[3];
363 
364  if (DEBUG_DEVICE && isActive(Diag::DEVICE_LIDS))
365  {
366  Xyce::dout() << getName() << " LIDs"
367  << Util::push << std::endl
368  << "li_VR1 = " << li_VR1 << std::endl
369  << "li_VI1 = " << li_VI1 << std::endl
370  << "li_VR2 = " << li_VR2 << std::endl
371  << "li_VI2 = " << li_VI2 << std::endl
372  << std::endl;
373  }
374  }
375  else if (analysisType_ == PQP )
376  {
377  li_Theta1 = extLIDVec[0];
378  li_Theta2 = extLIDVec[1];
379  li_VM1 = extLIDVec[2];
380  li_VM2 = extLIDVec[3];
381 
382  if (DEBUG_DEVICE && isActive(Diag::DEVICE_LIDS))
383  {
384  Xyce::dout() << getName() << " LIDs"
385  << Util::push << std::endl
386  << "li_Theta1 = " << li_Theta1 << std::endl
387  << "li_VM1 = " << li_VM1 << std::endl
388  << "li_Theta2 = " << li_Theta2 << std::endl
389  << "li_VM2 = " << li_VM2 << std::endl
390  << std::endl;
391  }
392  }
393  else
394  {
395  UserError0(*this) << "Analysis Type must be IV, PQR or PQP in power grid device: " << getName();
396  return;
397  }
398 }
399 
400 //-----------------------------------------------------------------------------
401 // Function : Instance::loadNodeSymbols
402 // Purpose :
403 // Special Notes :
404 // Scope : public
405 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
406 // Creation Date : 05/13/05
407 //-----------------------------------------------------------------------------
408 void Instance::loadNodeSymbols(Util::SymbolTable &symbol_table) const
409 {}
410 
411 //-----------------------------------------------------------------------------
412 // Function : Instance::registerStateLIDs
413 // Purpose : Set up offsets so we can store quantities that need to be
414 // differentiated.
415 // Special Notes :
416 // Scope : public
417 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
418 // Creation Date : 9/12/14
419 //-----------------------------------------------------------------------------
420 void Instance::registerStateLIDs(const std::vector<int> & staLIDVecRef )
421 {
422  AssertLIDs(staLIDVecRef.size() == numStateVars);
423 }
424 
425 //-----------------------------------------------------------------------------
426 // Function : Instance::jacobianStamp
427 // Purpose :
428 // Special Notes :
429 // Scope : public
430 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
431 // Creation Date : 08/20/01
432 //-----------------------------------------------------------------------------
433 const std::vector< std::vector<int> > & Instance::jacobianStamp() const
434 {
435  return jacStamp;
436 }
437 
438 //-----------------------------------------------------------------------------
439 // Function : Instance::registerJacLIDs
440 // Purpose :
441 // Special Notes :
442 // Scope : public
443 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
444 // Creation Date : 09/12/14
445 //-----------------------------------------------------------------------------
446 void Instance::registerJacLIDs( const std::vector< std::vector<int> > & jacLIDVec )
447 {
448  DeviceInstance::registerJacLIDs( jacLIDVec );
449 
450  // These if-else blocks may be made into separate classes,
451  // in the final version of this model
452  if (analysisType_ == IV || analysisType_ == PQR)
453  {
454  VR1_VR1_Offset = jacLIDVec[0][0];
455  VR1_VR2_Offset = jacLIDVec[0][1];
456  VR1_VI1_Offset = jacLIDVec[0][2];
457  VR1_VI2_Offset = jacLIDVec[0][3];
458 
459  VR2_VR1_Offset = jacLIDVec[1][0];
460  VR2_VR2_Offset = jacLIDVec[1][1];
461  VR2_VI1_Offset = jacLIDVec[1][2];
462  VR2_VI2_Offset = jacLIDVec[1][3];
463 
464  VI1_VR1_Offset = jacLIDVec[2][0];
465  VI1_VR2_Offset = jacLIDVec[2][1];
466  VI1_VI1_Offset = jacLIDVec[2][2];
467  VI1_VI2_Offset = jacLIDVec[2][3];
468 
469  VI2_VR1_Offset = jacLIDVec[3][0];
470  VI2_VR2_Offset = jacLIDVec[3][1];
471  VI2_VI1_Offset = jacLIDVec[3][2];
472  VI2_VI2_Offset = jacLIDVec[3][3];
473 
474  if (DEBUG_DEVICE && (isActive(Diag::DEVICE_JACSTAMP) || isActive(Diag::DEVICE_LIDS)))
475  {
476  Xyce::dout() << getName() << ": In registerJacLIDs, the offsets are:" << std::endl
477  << "VR1 offsets are (" << VR1_VR1_Offset << " , " << VR1_VR2_Offset << " , "
478  << VR1_VI1_Offset << " , " << VR1_VI2_Offset << ")" << std::endl
479  << "VR2 offsets are (" << VR2_VR1_Offset << " , " << VR2_VR2_Offset << " , "
480  << VR2_VI1_Offset << " , " << VR2_VI2_Offset << ")" << std::endl
481  << "VI1 offsets are (" << VI1_VR1_Offset << " , " << VI1_VR2_Offset << " , "
482  << VI1_VI1_Offset << " , " << VI1_VI2_Offset << ")" << std::endl
483  << "VI2 offsets are (" << VI2_VR1_Offset << " , " << VI2_VR2_Offset << " , "
484  << VI2_VI1_Offset << " , " << VI2_VI2_Offset << ")" << std::endl << std::endl;
485  }
486  }
487  else if (analysisType_ == PQP)
488  {
489  Theta1_Theta1_Offset = jacLIDVec[0][0];
490  Theta1_Theta2_Offset = jacLIDVec[0][1];
491  Theta1_VM1_Offset = jacLIDVec[0][2];
492  Theta1_VM2_Offset = jacLIDVec[0][3];
493 
494  Theta2_Theta1_Offset = jacLIDVec[1][0];
495  Theta2_Theta2_Offset = jacLIDVec[1][1];
496  Theta2_VM1_Offset = jacLIDVec[1][2];
497  Theta2_VM2_Offset = jacLIDVec[1][3];
498 
499  VM1_Theta1_Offset = jacLIDVec[2][0];
500  VM1_Theta2_Offset = jacLIDVec[2][1];
501  VM1_VM1_Offset = jacLIDVec[2][2];
502  VM1_VM2_Offset = jacLIDVec[2][3];
503 
504  VM2_Theta1_Offset = jacLIDVec[3][0];
505  VM2_Theta2_Offset = jacLIDVec[3][1];
506  VM2_VM1_Offset = jacLIDVec[3][2];
507  VM2_VM2_Offset = jacLIDVec[3][3];
508 
509  if (DEBUG_DEVICE && (isActive(Diag::DEVICE_JACSTAMP) || isActive(Diag::DEVICE_LIDS)))
510  {
511  Xyce::dout() << getName() << ": In registerJacLIDs, the offsets are:" << std::endl
512  << "Theta1 offsets are (" << Theta1_Theta1_Offset << " , " << Theta1_Theta2_Offset << " , "
513  << Theta1_VM1_Offset << " , " << Theta1_VM2_Offset << ")" << std::endl
514  << "Theta2 offsets are (" << Theta2_Theta1_Offset << " , " << Theta2_Theta2_Offset << " , "
515  << Theta2_VM1_Offset << " , " << Theta2_VM2_Offset << ")" << std::endl
516  << "VM1 offsets are (" << VM1_Theta1_Offset << " , " << VM1_Theta2_Offset << " , "
517  << VM1_VM1_Offset << " , " << VM1_VM2_Offset << ")" << std::endl
518  << "VM2 offsets are (" << VM2_Theta1_Offset << " , " << VM2_Theta2_Offset << " , "
519  << VM2_VM1_Offset << " , " << VM2_VM2_Offset << ")" << std::endl<< std::endl;
520  }
521  }
522 }
523 
524 //-----------------------------------------------------------------------------
525 // Function : Instance::updateIntermediateVars
526 // Purpose : update intermediate variables for one diode instance
527 // Special Notes :
528 // Scope : public
529 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
530 // Creation Date : 9/12/14
531 //-----------------------------------------------------------------------------
533 {
534  double * solVec = extData.nextSolVectorRawPtr;
535 
536  // These if-else blocks may be split out into separate classes in the final version
537  // of this model
538  if (analysisType_ == IV)
539  {
540  IR1 = g11*solVec[li_VR1] + g12*solVec[li_VR2] - b11*solVec[li_VI1] - b12*solVec[li_VI2];
541  IR2 = g21*solVec[li_VR1] + g22*solVec[li_VR2] - b21*solVec[li_VI1] - b22*solVec[li_VI2];
542  II1 = b11*solVec[li_VR1] + b12*solVec[li_VR2] + g11*solVec[li_VI1] + g12*solVec[li_VI2];
543  II2 = b21*solVec[li_VR1] + b22*solVec[li_VR2] + g21*solVec[li_VI1] + g22*solVec[li_VI2];
544  }
545  else if (analysisType_ == PQR)
546  {
547  P1 = g11*(solVec[li_VR1]*solVec[li_VR1] + solVec[li_VI1]*solVec[li_VI1]) +
548  solVec[li_VR1]*(g12*solVec[li_VR2] - b12*solVec[li_VI2]) +
549  solVec[li_VI1]*(b12*solVec[li_VR2] + g12*solVec[li_VI2]);
550 
551  P2 = g22*(solVec[li_VR2]*solVec[li_VR2] + solVec[li_VI2]*solVec[li_VI2]) +
552  solVec[li_VR2]*(g21*solVec[li_VR1] - b21*solVec[li_VI1]) +
553  solVec[li_VI2]*(b21*solVec[li_VR1] + g21*solVec[li_VI1]);
554 
555  Q1 = -1.0*b11*(solVec[li_VR1]*solVec[li_VR1] + solVec[li_VI1]*solVec[li_VI1]) +
556  solVec[li_VI1]*(g12*solVec[li_VR2] - b12*solVec[li_VI2]) -
557  solVec[li_VR1]*(b12*solVec[li_VR2] + g12*solVec[li_VI2]);
558 
559  Q2 = -1.0*b22*(solVec[li_VR2]*solVec[li_VR2] + solVec[li_VI2]*solVec[li_VI2]) +
560  solVec[li_VI2]*(g21*solVec[li_VR1] - b21*solVec[li_VI1]) -
561  solVec[li_VR2]*(b21*solVec[li_VR1] + g21*solVec[li_VI1]);
562  }
563  else if (analysisType_ == PQP)
564  {
565  double dSin12 = sin(solVec[li_Theta1]-solVec[li_Theta2]);
566  double dSin21 = sin(solVec[li_Theta2]-solVec[li_Theta1]);
567  double dCos12 = cos(solVec[li_Theta1]-solVec[li_Theta2]);
568  double dCos21 = cos(solVec[li_Theta2]-solVec[li_Theta1]);
569 
570  P1 = g11*solVec[li_VM1]*solVec[li_VM1] + solVec[li_VM1]*solVec[li_VM2]*(g12*dCos12 + b12*dSin12);
571  P2 = g22*solVec[li_VM2]*solVec[li_VM2] + solVec[li_VM2]*solVec[li_VM1]*(g21*dCos21 + b21*dSin21);
572  Q1 = -1*b11*solVec[li_VM1]*solVec[li_VM1] + solVec[li_VM1]*solVec[li_VM2]*(g12*dSin12 - b12*dCos12);
573  Q2 = -1*b22*solVec[li_VM2]*solVec[li_VM2] + solVec[li_VM2]*solVec[li_VM1]*(g21*dSin21 - b21*dCos21);
574  }
575  else
576  {
577  UserError0(*this) << "Analysis Type must be IV, PQR or PQP in power grid device: " << getName();
578  return false;
579  }
580 
581  return true;
582 }
583 
584 //-----------------------------------------------------------------------------
585 // Function : Instance::updatePrimaryState
586 // Purpose :
587 // Special Notes :
588 // Scope : public
589 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
590 // Creation Date : 9/12/14
591 //-----------------------------------------------------------------------------
593 {
594  return updateIntermediateVars ();
595 }
596 
597 //-----------------------------------------------------------------------------
598 // Function : Instance::loadDAEFVector
599 //
600 // Purpose : Loads the F-vector contributions
601 //
602 // Special Notes :
603 //
604 //
605 // Scope : public
606 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
607 // Creation Date : 9/12/14
608 //-----------------------------------------------------------------------------
610 {
611  double * fVec = extData.daeFVectorRawPtr;
612 
613  // These if-else blocks may be split out into separate classes in the final version
614  // of this mode.
615  if (analysisType_ == IV)
616  {
617  fVec[li_VR1] += IR1;
618  fVec[li_VR2] += IR2;
619  fVec[li_VI1] += II1;
620  fVec[li_VI2] += II2;
621  }
622  else if (analysisType_ == PQR)
623  {
624  fVec[li_VR1] += P1;
625  fVec[li_VR2] += P2;
626  fVec[li_VI1] += Q1;
627  fVec[li_VI2] += Q2;
628  }
629  else if (analysisType_ == PQP)
630  {
631  fVec[li_Theta1] += P1;
632  fVec[li_Theta2] += P2;
633  fVec[li_VM1] += Q1;
634  fVec[li_VM2] += Q2;
635 
636  if (DEBUG_DEVICE && isActive(Diag::DEVICE_LOAD_VECTOR))
637  {
638  Xyce::dout() << getName() << ": F Vector Load info is: (P1,P2,Q1,Q2) load is: (" << P1 << " , "
639  << P2 << " , " << Q1 << " , " << Q2 << ")" << std::endl << std::endl;
640  }
641  }
642  else
643  {
644  UserError0(*this) << "Analysis Type must be IV, PQR or PQP in power grid device: " << getName();
645  return false;
646  }
647 
648  if (getSolverState().dcopFlag)
649  {
650  // no op placeholder
651  }
652  else
653  {
654  // no op placeholder
655  }
656 
657  return true;
658 }
659 
660 //-----------------------------------------------------------------------------
661 // Function : Instance::loadDAEQVector
662 //
663 // Purpose : Loads the Q-vector contributions. This is a no-op for
664 // this model
665 //
666 // Special Notes :
667 //
668 //
669 // Scope : public
670 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
671 // Creation Date : 9/12/14
672 //-----------------------------------------------------------------------------
674 {
675  return true;
676 }
677 
678 //-----------------------------------------------------------------------------
679 // Function : Instance::loadDAEdFdx ()
680 //
681 // Purpose : Loads the F-vector contributions
682 //
683 // Special Notes :
684 //
685 // Scope : public
686 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
687 // Creation Date : 9/12/14
688 //-----------------------------------------------------------------------------
690 {
691  Linear::Matrix & dFdx = *(extData.dFdxMatrixPtr);
692 
693  // These if-else blocks may be split out into separate classes in the final version
694  // of this model
695  if (analysisType_ == IV)
696  {
697  dFdx[li_VR1][VR1_VR1_Offset] += g11;
698  dFdx[li_VR1][VR1_VR2_Offset] += g12;
699  dFdx[li_VR1][VR1_VI1_Offset] -= b11;
700  dFdx[li_VR1][VR1_VI2_Offset] -= b12;
701 
702  dFdx[li_VR2][VR2_VR1_Offset] += g21;
703  dFdx[li_VR2][VR2_VR2_Offset] += g22;
704  dFdx[li_VR2][VR2_VI1_Offset] -= b21;
705  dFdx[li_VR2][VR2_VI2_Offset] -= b22;
706 
707  dFdx[li_VI1][VI1_VR1_Offset] += b11;
708  dFdx[li_VI1][VI1_VR2_Offset] += b12;
709  dFdx[li_VI1][VI1_VI1_Offset] += g11;
710  dFdx[li_VI1][VI1_VI2_Offset] += g12;
711 
712  dFdx[li_VI2][VI2_VR1_Offset] += b21;
713  dFdx[li_VI2][VI2_VR2_Offset] += b22;
714  dFdx[li_VI2][VI2_VI1_Offset] += g21;
715  dFdx[li_VI2][VI2_VI2_Offset] += g22;
716  }
717  else if (analysisType_ == PQR)
718  {
719  double * solVec = extData.nextSolVectorRawPtr;
720 
721  dFdx[li_VR1][VR1_VR1_Offset] += 2*g11*solVec[li_VR1] + g12*solVec[li_VR2] - b12*solVec[li_VI2];
722  dFdx[li_VR1][VR1_VR2_Offset] += g12*solVec[li_VR1] + b12*solVec[li_VI1];
723  dFdx[li_VR1][VR1_VI1_Offset] += 2*g11*solVec[li_VI1] + b12*solVec[li_VR2] + g12*solVec[li_VI2];
724  dFdx[li_VR1][VR1_VI2_Offset] += g12*solVec[li_VI1] - b12*solVec[li_VR1];
725 
726  dFdx[li_VR2][VR2_VR1_Offset] += g21*solVec[li_VR2] + b21*solVec[li_VI2];
727  dFdx[li_VR2][VR2_VR2_Offset] += 2*g22*solVec[li_VR2] + g21*solVec[li_VR1] - b21*solVec[li_VI1];
728  dFdx[li_VR2][VR2_VI1_Offset] += g21*solVec[li_VI2] - b21*solVec[li_VR2];
729  dFdx[li_VR2][VR2_VI2_Offset] += 2*g22*solVec[li_VI2] + b21*solVec[li_VR1] + g21*solVec[li_VI1];
730 
731  dFdx[li_VI1][VI1_VR1_Offset] += -2*b11*solVec[li_VR1] - b12*solVec[li_VR2] - g12*solVec[li_VI2];
732  dFdx[li_VI1][VI1_VR2_Offset] += g12*solVec[li_VI1] - b12*solVec[li_VR1];
733  dFdx[li_VI1][VI1_VI1_Offset] += -2*b11*solVec[li_VI1] + g12*solVec[li_VR2] - b12*solVec[li_VI2];
734  dFdx[li_VI1][VI1_VI2_Offset] -= g12*solVec[li_VR1] + b12*solVec[li_VI1];
735 
736  dFdx[li_VI2][VI2_VR1_Offset] += g21*solVec[li_VI2] - b21*solVec[li_VR2];
737  dFdx[li_VI2][VI2_VR2_Offset] += -2*b22*solVec[li_VR2] - b21*solVec[li_VR1] - g12*solVec[li_VI1];
738  dFdx[li_VI2][VI2_VI1_Offset] -= g21*solVec[li_VR2] + b21*solVec[li_VI2];
739  dFdx[li_VI2][VI2_VI2_Offset] += -2*b22*solVec[li_VI2] + g21*solVec[li_VR1] - b21*solVec[li_VI1];
740  }
741  else if (analysisType_ == PQP)
742  {
743  double * solVec = extData.nextSolVectorRawPtr;
744  double dSin12 = sin(solVec[li_Theta1]-solVec[li_Theta2]);
745  double dSin21 = sin(solVec[li_Theta2]-solVec[li_Theta1]);
746  double dCos12 = cos(solVec[li_Theta1]-solVec[li_Theta2]);
747  double dCos21 = cos(solVec[li_Theta2]-solVec[li_Theta1]);
748 
749  if (DEBUG_DEVICE && isActive(Diag::DEVICE_LOAD_VECTOR))
750  {
751  Xyce::dout() << getName() << ": dFdx info is: " << std::endl
752  << "(dSin12,dSin21,dCos12,dCos21 = (" << dSin12 << " , " << dSin21
753  << " , " << dCos12 << " , " << dCos21 << ")" << std::endl
754  << "(solVec[li_Theta1],solVec[li_Theta2]) = (" << solVec[li_Theta1]
755  << " , " << solVec[li_Theta2] << ")" << std::endl
756  << "(solVec[li_VM1],solVec[li_VM2]) = (" << solVec[li_VM1]
757  << " , " << solVec[li_VM2] << ")" << std::endl;
758  }
759 
760  // dP / dTheta terms
761  dFdx[li_Theta1][Theta1_Theta1_Offset] -= solVec[li_VM1]*solVec[li_VM2]*(g12*dSin12 - b12*dCos12);
762  dFdx[li_Theta1][Theta1_Theta2_Offset] += solVec[li_VM1]*solVec[li_VM2]*(g12*dSin12 - b12*dCos12);
763  dFdx[li_Theta2][Theta2_Theta1_Offset] += solVec[li_VM1]*solVec[li_VM2]*(g21*dSin21 - b21*dCos21);
764  dFdx[li_Theta2][Theta2_Theta2_Offset] -= solVec[li_VM1]*solVec[li_VM2]*(g21*dSin21 - b21*dCos21);
765 
766  // dP / dV terms
767  dFdx[li_Theta1][Theta1_VM1_Offset] += 2*solVec[li_VM1]*g11 + solVec[li_VM2]*(g12*dCos12 + b12*dSin12);
768  dFdx[li_Theta1][Theta1_VM2_Offset] += solVec[li_VM1]*(g12*dCos12 + b12*dSin12);
769  dFdx[li_Theta2][Theta2_VM1_Offset] += solVec[li_VM2]*(g21*dCos21 + b21*dSin21);
770  dFdx[li_Theta2][Theta2_VM2_Offset] += 2*solVec[li_VM2]*g22 + solVec[li_VM1]*(g21*dCos21 + b21*dSin21);
771 
772  // dQ / dTheta terms
773  dFdx[li_VM1][VM1_Theta1_Offset] += solVec[li_VM1]*solVec[li_VM2]*(g12*dCos12 + b12*dSin12);
774  dFdx[li_VM1][VM1_Theta2_Offset] -= solVec[li_VM1]*solVec[li_VM2]*(g12*dCos12 + b12*dSin12);
775  dFdx[li_VM2][VM2_Theta1_Offset] -= solVec[li_VM1]*solVec[li_VM2]*(g21*dCos21 + b21*dSin21);
776  dFdx[li_VM2][VM2_Theta2_Offset] += solVec[li_VM1]*solVec[li_VM2]*(g21*dCos21 + b21*dSin21);
777 
778  // dQ / dV terms
779  dFdx[li_VM1][VM1_VM1_Offset] += -2*solVec[li_VM1]*b11 + solVec[li_VM2]*(g12*dSin12 - b12*dCos12);
780  dFdx[li_VM1][VM1_VM2_Offset] += solVec[li_VM1]*(g12*dSin12 - b12*dCos12);
781  dFdx[li_VM2][VM2_VM1_Offset] += solVec[li_VM2]*(g21*dSin21 - b21*dCos21);
782  dFdx[li_VM2][VM2_VM2_Offset] += -2*solVec[li_VM2]*b22 + solVec[li_VM1]*(g21*dSin21 - b21*dCos21);
783  }
784  else
785  {
786  UserError0(*this) << "Analysis Type must be IV, PQR or PQP in power grid device: " << getName();
787  return false;
788  }
789 
790  if (getSolverState().dcopFlag)
791  {
792  // no op placeholder code;
793  }
794  else
795  {
796  // no op placeholder code;
797  }
798 
799  return true;
800 }
801 
802 //-----------------------------------------------------------------------------
803 // Function : Instance::loadDAEdQdx ()
804 //
805 // Purpose : Loads the Q-vector contributions. This is no-op for this
806 // model.
807 //
808 // Special Notes :
809 //
810 // Scope : public
811 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
812 // Creation Date : 9/12/14
813 //-----------------------------------------------------------------------------
815 {
816  return true;
817 }
818 
819 //-----------------------------------------------------------------------------
820 // Function : Model::Model
821 // Purpose : "Model block" constructor
822 // Special Notes :
823 // Scope : public
824 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
825 // Creation Date : 9/12/14
826 //-----------------------------------------------------------------------------
827 
828 
829 // These are all just placeholder functions, as there is nothing to the model
830 // class.
831 // Class Model
832 
833 //-----------------------------------------------------------------------------
834 // Function : Model::Model
835 // Purpose : "Model block" constructor
836 // Special Notes :
837 // Scope : public
838 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
839 // Creation Date : 9/12/14
840 //-----------------------------------------------------------------------------
842  const Configuration & configuration,
843  const ModelBlock & MB,
844  const FactoryBlock & factory_block)
845  : DeviceModel(MB, configuration.getModelParameters(), factory_block)
846 {
847 }
848 
849 //-----------------------------------------------------------------------------
850 // Function : Model::~Model
851 // Purpose : destructor
852 // Special Notes :
853 // Scope : public
854 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
855 // Creation Date : 9/12/14
856 //-----------------------------------------------------------------------------
858 {
859  std::vector<Instance*>::iterator iter;
860  std::vector<Instance*>::iterator first = instanceContainer.begin();
861  std::vector<Instance*>::iterator last = instanceContainer.end();
862 
863  for (iter=first; iter!=last; ++iter)
864  {
865  delete (*iter);
866  }
867 }
868 
869 //-----------------------------------------------------------------------------
870 // Function : Model::printOutInstances
871 // Purpose : debugging tool.
872 // Special Notes :
873 // Scope : public
874 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
875 // Creation Date : 9/12/14
876 //-----------------------------------------------------------------------------
877 std::ostream &Model::printOutInstances(std::ostream &os) const
878 {
879  std::vector<Instance*>::const_iterator iter;
880  std::vector<Instance*>::const_iterator first = instanceContainer.begin();
881  std::vector<Instance*>::const_iterator last = instanceContainer.end();
882 
883  int i;
884  os << std::endl;
885  os << " name model name Parameters" << std::endl;
886  for (i=0, iter=first; iter!=last; ++iter, ++i)
887  {
888  os << " " << i << ": " << (*iter)->getName() << " ";
889  os << getName();
890  os << std::endl;
891  }
892 
893  os << std::endl;
894 
895  return os;
896 }
897 
898 //-----------------------------------------------------------------------------
899 // Function : Model::forEachInstance
900 // Purpose :
901 // Special Notes :
902 // Scope : public
903 // Creator : David Baur
904 // Creation Date : 2/4/2014
905 //-----------------------------------------------------------------------------
906 /// Apply a device instance "op" to all instances associated with this
907 /// model
908 ///
909 /// @param[in] op Operator to apply to all instances.
910 ///
911 ///
912 void Model::forEachInstance(DeviceInstanceOp &op) const /* override */
913 {
914  for (std::vector<Instance *>::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
915  op(*it);
916 }
917 
918 
919 Device *Traits::factory(const Configuration &configuration, const FactoryBlock &factory_block)
920 {
921 
922  return new DeviceMaster<Traits>(configuration, factory_block, factory_block.solverState_, factory_block.deviceOptions_);
923 }
924 
926 {
928  .registerDevice("PowerGridBranch", 1)
929  .registerDevice("PGBR", 1)
930  .registerModelType("PowerGridBranch", 1);
931 }
932 
933 } // namespace PowerGridBranch
934 } // namespace Device
935 } // namespace Xyce
const InstanceName & getName() const
static std::vector< std::vector< int > > jacStamp
const SolverState & solverState_
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
Pure virtual class to augment a linear system.
Parameter may be specified as time dependent expression from netlist.
Definition: N_DEV_Pars.h:67
void registerJacLIDs(const std::vector< std::vector< int > > &jacLIDVec)
static void loadModelParameters(ParametricData< Model > &model_parameters)
#define AssertLIDs(cmp)
std::vector< Instance * > instanceContainer
virtual void registerJacLIDs(const JacobianStamp &jacLIDVec)
static Device * factory(const Configuration &configuration, const FactoryBlock &factory_block)
const std::vector< std::vector< int > > & jacobianStamp() const
virtual void forEachInstance(DeviceInstanceOp &op) const
Apply a device instance "op" to all instances associated with this model.
void setParams(const std::vector< Param > &params)
const std::string & getName() const
void registerLIDs(const std::vector< int > &intLIDVecRef, const std::vector< int > &extLIDVecRef)
The FactoryBlock contains parameters needed by the device, instance and model creation functions...
const DeviceOptions & deviceOptions_
static Config< T > & addConfiguration()
Adds the device to the Xyce device configuration.
Linear::Matrix * dFdxMatrixPtr
The Device class is an interface for device implementations.
Definition: N_DEV_Device.h:101
Class Configuration contains device configuration data.
Instance(const Configuration &configuration, const InstanceBlock &IB, Model &Riter, const FactoryBlock &factory_block)
void registerStateLIDs(const std::vector< int > &staLIDVecRef)
const SolverState & getSolverState() const
ModelBlock represents a .MODEL line from the netlist.
Manages parameter binding for class C.
Definition: N_DEV_Pars.h:214
void loadNodeSymbols(Util::SymbolTable &symbol_table) const
Populates and returns the store name map.
InstanceBlock represent a device instance line from the netlist.
virtual std::ostream & printOutInstances(std::ostream &os) const
std::vector< Param > params
static void loadInstanceParameters(ParametricData< Instance > &instance_parameters)