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.14.2.4 $
41 //
42 // Revision Date : $Date: 2015/04/03 16:42:57 $
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 will be made into separate classes,
356  // once they work
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 : Robert Hoekstra, SNL, Parallel Computational Sciences
444 // Creation Date : 08/27/01
445 //-----------------------------------------------------------------------------
446 void Instance::registerJacLIDs( const std::vector< std::vector<int> > & jacLIDVec )
447 {
448  DeviceInstance::registerJacLIDs( jacLIDVec );
449 
450  // These will be split out into separate classes once they both work
451  if (analysisType_ == IV || analysisType_ == PQR)
452  {
453  VR1_VR1_Offset = jacLIDVec[0][0];
454  VR1_VR2_Offset = jacLIDVec[0][1];
455  VR1_VI1_Offset = jacLIDVec[0][2];
456  VR1_VI2_Offset = jacLIDVec[0][3];
457 
458  VR2_VR1_Offset = jacLIDVec[1][0];
459  VR2_VR2_Offset = jacLIDVec[1][1];
460  VR2_VI1_Offset = jacLIDVec[1][2];
461  VR2_VI2_Offset = jacLIDVec[1][3];
462 
463  VI1_VR1_Offset = jacLIDVec[2][0];
464  VI1_VR2_Offset = jacLIDVec[2][1];
465  VI1_VI1_Offset = jacLIDVec[2][2];
466  VI1_VI2_Offset = jacLIDVec[2][3];
467 
468  VI2_VR1_Offset = jacLIDVec[3][0];
469  VI2_VR2_Offset = jacLIDVec[3][1];
470  VI2_VI1_Offset = jacLIDVec[3][2];
471  VI2_VI2_Offset = jacLIDVec[3][3];
472 
473  if (DEBUG_DEVICE && (isActive(Diag::DEVICE_JACSTAMP) || isActive(Diag::DEVICE_LIDS)))
474  {
475  Xyce::dout() << getName() << ": In registerJacLIDs, the offsets are:" << std::endl
476  << "VR1 offsets are (" << VR1_VR1_Offset << " , " << VR1_VR2_Offset << " , "
477  << VR1_VI1_Offset << " , " << VR1_VI2_Offset << ")" << std::endl
478  << "VR2 offsets are (" << VR2_VR1_Offset << " , " << VR2_VR2_Offset << " , "
479  << VR2_VI1_Offset << " , " << VR2_VI2_Offset << ")" << std::endl
480  << "VI1 offsets are (" << VI1_VR1_Offset << " , " << VI1_VR2_Offset << " , "
481  << VI1_VI1_Offset << " , " << VI1_VI2_Offset << ")" << std::endl
482  << "VI2 offsets are (" << VI2_VR1_Offset << " , " << VI2_VR2_Offset << " , "
483  << VI2_VI1_Offset << " , " << VI2_VI2_Offset << ")" << std::endl << std::endl;
484  }
485  }
486  else if (analysisType_ == PQP)
487  {
488  Theta1_Theta1_Offset = jacLIDVec[0][0];
489  Theta1_Theta2_Offset = jacLIDVec[0][1];
490  Theta1_VM1_Offset = jacLIDVec[0][2];
491  Theta1_VM2_Offset = jacLIDVec[0][3];
492 
493  Theta2_Theta1_Offset = jacLIDVec[1][0];
494  Theta2_Theta2_Offset = jacLIDVec[1][1];
495  Theta2_VM1_Offset = jacLIDVec[1][2];
496  Theta2_VM2_Offset = jacLIDVec[1][3];
497 
498  VM1_Theta1_Offset = jacLIDVec[2][0];
499  VM1_Theta2_Offset = jacLIDVec[2][1];
500  VM1_VM1_Offset = jacLIDVec[2][2];
501  VM1_VM2_Offset = jacLIDVec[2][3];
502 
503  VM2_Theta1_Offset = jacLIDVec[3][0];
504  VM2_Theta2_Offset = jacLIDVec[3][1];
505  VM2_VM1_Offset = jacLIDVec[3][2];
506  VM2_VM2_Offset = jacLIDVec[3][3];
507 
508  if (DEBUG_DEVICE && (isActive(Diag::DEVICE_JACSTAMP) || isActive(Diag::DEVICE_LIDS)))
509  {
510  Xyce::dout() << getName() << ": In registerJacLIDs, the offsets are:" << std::endl
511  << "Theta1 offsets are (" << Theta1_Theta1_Offset << " , " << Theta1_Theta2_Offset << " , "
512  << Theta1_VM1_Offset << " , " << Theta1_VM2_Offset << ")" << std::endl
513  << "Theta2 offsets are (" << Theta2_Theta1_Offset << " , " << Theta2_Theta2_Offset << " , "
514  << Theta2_VM1_Offset << " , " << Theta2_VM2_Offset << ")" << std::endl
515  << "VM1 offsets are (" << VM1_Theta1_Offset << " , " << VM1_Theta2_Offset << " , "
516  << VM1_VM1_Offset << " , " << VM1_VM2_Offset << ")" << std::endl
517  << "VM2 offsets are (" << VM2_Theta1_Offset << " , " << VM2_Theta2_Offset << " , "
518  << VM2_VM1_Offset << " , " << VM2_VM2_Offset << ")" << std::endl<< std::endl;
519  }
520  }
521 }
522 
523 //-----------------------------------------------------------------------------
524 // Function : Instance::updateIntermediateVars
525 // Purpose : update intermediate variables for one diode instance
526 // Special Notes :
527 // Scope : public
528 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
529 // Creation Date : 9/12/14
530 //-----------------------------------------------------------------------------
532 {
533  double * solVec = extData.nextSolVectorRawPtr;
534 
535  // These will be split out into separate classes once they work
536  if (analysisType_ == IV)
537  {
538  IR1 = g11*solVec[li_VR1] + g12*solVec[li_VR2] - b11*solVec[li_VI1] - b12*solVec[li_VI2];
539  IR2 = g21*solVec[li_VR1] + g22*solVec[li_VR2] - b21*solVec[li_VI1] - b22*solVec[li_VI2];
540  II1 = b11*solVec[li_VR1] + b12*solVec[li_VR2] + g11*solVec[li_VI1] + g12*solVec[li_VI2];
541  II2 = b21*solVec[li_VR1] + b22*solVec[li_VR2] + g21*solVec[li_VI1] + g22*solVec[li_VI2];
542  }
543  else if (analysisType_ == PQR)
544  {
545  P1 = g11*(solVec[li_VR1]*solVec[li_VR1] + solVec[li_VI1]*solVec[li_VI1]) +
546  solVec[li_VR1]*(g12*solVec[li_VR2] - b12*solVec[li_VI2]) +
547  solVec[li_VI1]*(b12*solVec[li_VR2] + g12*solVec[li_VI2]);
548 
549  P2 = g22*(solVec[li_VR2]*solVec[li_VR2] + solVec[li_VI2]*solVec[li_VI2]) +
550  solVec[li_VR2]*(g21*solVec[li_VR1] - b21*solVec[li_VI1]) +
551  solVec[li_VI2]*(b21*solVec[li_VR1] + g21*solVec[li_VI1]);
552 
553  Q1 = -1.0*b11*(solVec[li_VR1]*solVec[li_VR1] + solVec[li_VI1]*solVec[li_VI1]) +
554  solVec[li_VI1]*(g12*solVec[li_VR2] - b12*solVec[li_VI2]) -
555  solVec[li_VR1]*(b12*solVec[li_VR2] + g12*solVec[li_VI2]);
556 
557  Q2 = -1.0*b22*(solVec[li_VR2]*solVec[li_VR2] + solVec[li_VI2]*solVec[li_VI2]) +
558  solVec[li_VI2]*(g21*solVec[li_VR1] - b21*solVec[li_VI1]) -
559  solVec[li_VR2]*(b21*solVec[li_VR1] + g21*solVec[li_VI1]);
560  }
561  else if (analysisType_ == PQP)
562  {
563  double dSin12 = sin(solVec[li_Theta1]-solVec[li_Theta2]);
564  double dSin21 = sin(solVec[li_Theta2]-solVec[li_Theta1]);
565  double dCos12 = cos(solVec[li_Theta1]-solVec[li_Theta2]);
566  double dCos21 = cos(solVec[li_Theta2]-solVec[li_Theta1]);
567 
568  P1 = g11*solVec[li_VM1]*solVec[li_VM1] + solVec[li_VM1]*solVec[li_VM2]*(g12*dCos12 + b12*dSin12);
569  P2 = g22*solVec[li_VM2]*solVec[li_VM2] + solVec[li_VM2]*solVec[li_VM1]*(g21*dCos21 + b21*dSin21);
570  Q1 = -1*b11*solVec[li_VM1]*solVec[li_VM1] + solVec[li_VM1]*solVec[li_VM2]*(g12*dSin12 - b12*dCos12);
571  Q2 = -1*b22*solVec[li_VM2]*solVec[li_VM2] + solVec[li_VM2]*solVec[li_VM1]*(g21*dSin21 - b21*dCos21);
572  }
573  else
574  {
575  UserError0(*this) << "Analysis Type must be IV, PQR or PQP in power grid device: " << getName();
576  return false;
577  }
578 
579  return true;
580 }
581 
582 //-----------------------------------------------------------------------------
583 // Function : Instance::updatePrimaryState
584 // Purpose :
585 // Special Notes :
586 // Scope : public
587 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
588 // Creation Date : 9/12/14
589 //-----------------------------------------------------------------------------
591 {
592  return updateIntermediateVars ();
593 }
594 
595 //-----------------------------------------------------------------------------
596 // Function : Instance::loadDAEFVector
597 //
598 // Purpose : Loads the F-vector contributions
599 //
600 // Special Notes :
601 //
602 //
603 // Scope : public
604 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
605 // Creation Date : 9/12/14
606 //-----------------------------------------------------------------------------
608 {
609  double * fVec = extData.daeFVectorRawPtr;
610 
611  // this needs to be vectorized in the general case.
612  // These will be split out into separate classes once they work
613  if (analysisType_ == IV)
614  {
615  fVec[li_VR1] += IR1;
616  fVec[li_VR2] += IR2;
617  fVec[li_VI1] += II1;
618  fVec[li_VI2] += II2;
619  }
620  else if (analysisType_ == PQR)
621  {
622  fVec[li_VR1] += P1;
623  fVec[li_VR2] += P2;
624  fVec[li_VI1] += Q1;
625  fVec[li_VI2] += Q2;
626  }
627  else if (analysisType_ == PQP)
628  {
629  fVec[li_Theta1] += P1;
630  fVec[li_Theta2] += P2;
631  fVec[li_VM1] += Q1;
632  fVec[li_VM2] += Q2;
633 
634  if (DEBUG_DEVICE && isActive(Diag::DEVICE_LOAD_VECTOR))
635  {
636  Xyce::dout() << getName() << ": F Vector Load info is: (P1,P2,Q1,Q2) load is: (" << P1 << " , "
637  << P2 << " , " << Q1 << " , " << Q2 << ")" << std::endl << std::endl;
638  }
639  }
640  else
641  {
642  UserError0(*this) << "Analysis Type must be IV, PQR or PQP in power grid device: " << getName();
643  return false;
644  }
645 
646  if (getSolverState().dcopFlag)
647  {
648  // no op placeholder
649  }
650  else
651  {
652  // no op placeholder
653  }
654 
655  return true;
656 }
657 
658 //-----------------------------------------------------------------------------
659 // Function : Instance::loadDAEQVector
660 //
661 // Purpose : Loads the Q-vector contributions. This is a no-op for
662 // this model
663 //
664 // Special Notes :
665 //
666 //
667 // Scope : public
668 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
669 // Creation Date : 9/12/14
670 //-----------------------------------------------------------------------------
672 {
673  return true;
674 }
675 
676 //-----------------------------------------------------------------------------
677 // Function : Instance::loadDAEdFdx ()
678 //
679 // Purpose : Loads the F-vector contributions
680 //
681 // Special Notes :
682 //
683 // Scope : public
684 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
685 // Creation Date : 9/12/14
686 //-----------------------------------------------------------------------------
688 {
689  Linear::Matrix & dFdx = *(extData.dFdxMatrixPtr);
690 
691  if (analysisType_ == IV)
692  {
693  dFdx[li_VR1][VR1_VR1_Offset] += g11;
694  dFdx[li_VR1][VR1_VR2_Offset] += g12;
695  dFdx[li_VR1][VR1_VI1_Offset] -= b11;
696  dFdx[li_VR1][VR1_VI2_Offset] -= b12;
697 
698  dFdx[li_VR2][VR2_VR1_Offset] += g21;
699  dFdx[li_VR2][VR2_VR2_Offset] += g22;
700  dFdx[li_VR2][VR2_VI1_Offset] -= b21;
701  dFdx[li_VR2][VR2_VI2_Offset] -= b22;
702 
703  dFdx[li_VI1][VI1_VR1_Offset] += b11;
704  dFdx[li_VI1][VI1_VR2_Offset] += b12;
705  dFdx[li_VI1][VI1_VI1_Offset] += g11;
706  dFdx[li_VI1][VI1_VI2_Offset] += g12;
707 
708  dFdx[li_VI2][VI2_VR1_Offset] += b21;
709  dFdx[li_VI2][VI2_VR2_Offset] += b22;
710  dFdx[li_VI2][VI2_VI1_Offset] += g21;
711  dFdx[li_VI2][VI2_VI2_Offset] += g22;
712  }
713  else if (analysisType_ == PQR)
714  {
715  double * solVec = extData.nextSolVectorRawPtr;
716 
717  dFdx[li_VR1][VR1_VR1_Offset] += 2*g11*solVec[li_VR1] + g12*solVec[li_VR2] - b12*solVec[li_VI2];
718  dFdx[li_VR1][VR1_VR2_Offset] += g12*solVec[li_VR1] + b12*solVec[li_VI1];
719  dFdx[li_VR1][VR1_VI1_Offset] += 2*g11*solVec[li_VI1] + b12*solVec[li_VR2] + g12*solVec[li_VI2];
720  dFdx[li_VR1][VR1_VI2_Offset] += g12*solVec[li_VI1] - b12*solVec[li_VR1];
721 
722  dFdx[li_VR2][VR2_VR1_Offset] += g21*solVec[li_VR2] + b21*solVec[li_VI2];
723  dFdx[li_VR2][VR2_VR2_Offset] += 2*g22*solVec[li_VR2] + g21*solVec[li_VR1] - b21*solVec[li_VI1];
724  dFdx[li_VR2][VR2_VI1_Offset] += g21*solVec[li_VI2] - b21*solVec[li_VR2];
725  dFdx[li_VR2][VR2_VI2_Offset] += 2*g22*solVec[li_VI2] + b21*solVec[li_VR1] + g21*solVec[li_VI1];
726 
727  dFdx[li_VI1][VI1_VR1_Offset] += -2*b11*solVec[li_VR1] - b12*solVec[li_VR2] - g12*solVec[li_VI2];
728  dFdx[li_VI1][VI1_VR2_Offset] += g12*solVec[li_VI1] - b12*solVec[li_VR1];
729  dFdx[li_VI1][VI1_VI1_Offset] += -2*b11*solVec[li_VI1] + g12*solVec[li_VR2] - b12*solVec[li_VI2];
730  dFdx[li_VI1][VI1_VI2_Offset] -= g12*solVec[li_VR1] + b12*solVec[li_VI1];
731 
732  dFdx[li_VI2][VI2_VR1_Offset] += g21*solVec[li_VI2] - b21*solVec[li_VR2];
733  dFdx[li_VI2][VI2_VR2_Offset] += -2*b22*solVec[li_VR2] - b21*solVec[li_VR1] - g12*solVec[li_VI1];
734  dFdx[li_VI2][VI2_VI1_Offset] -= g21*solVec[li_VR2] + b21*solVec[li_VI2];
735  dFdx[li_VI2][VI2_VI2_Offset] += -2*b22*solVec[li_VI2] + g21*solVec[li_VR1] - b21*solVec[li_VI1];
736  }
737  else if (analysisType_ == PQP)
738  {
739  double * solVec = extData.nextSolVectorRawPtr;
740  double dSin12 = sin(solVec[li_Theta1]-solVec[li_Theta2]);
741  double dSin21 = sin(solVec[li_Theta2]-solVec[li_Theta1]);
742  double dCos12 = cos(solVec[li_Theta1]-solVec[li_Theta2]);
743  double dCos21 = cos(solVec[li_Theta2]-solVec[li_Theta1]);
744 
745  if (DEBUG_DEVICE && isActive(Diag::DEVICE_LOAD_VECTOR))
746  {
747  Xyce::dout() << getName() << ": dFdx info is: " << std::endl
748  << "(dSin12,dSin21,dCos12,dCos21 = (" << dSin12 << " , " << dSin21
749  << " , " << dCos12 << " , " << dCos21 << ")" << std::endl
750  << "(solVec[li_Theta1],solVec[li_Theta2]) = (" << solVec[li_Theta1]
751  << " , " << solVec[li_Theta2] << ")" << std::endl
752  << "(solVec[li_VM1],solVec[li_VM2]) = (" << solVec[li_VM1]
753  << " , " << solVec[li_VM2] << ")" << std::endl;
754  }
755 
756  // dP / dTheta terms
757  dFdx[li_Theta1][Theta1_Theta1_Offset] -= solVec[li_VM1]*solVec[li_VM2]*(g12*dSin12 - b12*dCos12);
758  dFdx[li_Theta1][Theta1_Theta2_Offset] += solVec[li_VM1]*solVec[li_VM2]*(g12*dSin12 - b12*dCos12);
759  dFdx[li_Theta2][Theta2_Theta1_Offset] += solVec[li_VM1]*solVec[li_VM2]*(g21*dSin21 - b21*dCos21);
760  dFdx[li_Theta2][Theta2_Theta2_Offset] -= solVec[li_VM1]*solVec[li_VM2]*(g21*dSin21 - b21*dCos21);
761 
762  // dP / dV terms
763  dFdx[li_Theta1][Theta1_VM1_Offset] += 2*solVec[li_VM1]*g11 + solVec[li_VM2]*(g12*dCos12 + b12*dSin12);
764  dFdx[li_Theta1][Theta1_VM2_Offset] += solVec[li_VM1]*(g12*dCos12 + b12*dSin12);
765  dFdx[li_Theta2][Theta2_VM1_Offset] += solVec[li_VM2]*(g21*dCos21 + b21*dSin21);
766  dFdx[li_Theta2][Theta2_VM2_Offset] += 2*solVec[li_VM2]*g22 + solVec[li_VM1]*(g21*dCos21 + b21*dSin21);
767 
768  // dQ / dTheta terms
769  dFdx[li_VM1][VM1_Theta1_Offset] += solVec[li_VM1]*solVec[li_VM2]*(g12*dCos12 + b12*dSin12);
770  dFdx[li_VM1][VM1_Theta2_Offset] -= solVec[li_VM1]*solVec[li_VM2]*(g12*dCos12 + b12*dSin12);
771  dFdx[li_VM2][VM2_Theta1_Offset] -= solVec[li_VM1]*solVec[li_VM2]*(g21*dCos21 + b21*dSin21);
772  dFdx[li_VM2][VM2_Theta2_Offset] += solVec[li_VM1]*solVec[li_VM2]*(g21*dCos21 + b21*dSin21);
773 
774  // dQ / dV terms
775  dFdx[li_VM1][VM1_VM1_Offset] += -2*solVec[li_VM1]*b11 + solVec[li_VM2]*(g12*dSin12 - b12*dCos12);
776  dFdx[li_VM1][VM1_VM2_Offset] += solVec[li_VM1]*(g12*dSin12 - b12*dCos12);
777  dFdx[li_VM2][VM2_VM1_Offset] += solVec[li_VM2]*(g21*dSin21 - b21*dCos21);
778  dFdx[li_VM2][VM2_VM2_Offset] += -2*solVec[li_VM2]*b22 + solVec[li_VM1]*(g21*dSin21 - b21*dCos21);
779  }
780  else
781  {
782  UserError0(*this) << "Analysis Type must be IV, PQR or PQP in power grid device: " << getName();
783  return false;
784  }
785 
786  if (getSolverState().dcopFlag)
787  {
788  // no op placeholder code;
789  }
790  else
791  {
792  // no op placeholder code;
793  }
794 
795  return true;
796 }
797 
798 //-----------------------------------------------------------------------------
799 // Function : Instance::loadDAEdQdx ()
800 //
801 // Purpose : Loads the Q-vector contributions. This is no-op for this
802 // model.
803 //
804 // Special Notes :
805 //
806 // Scope : public
807 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
808 // Creation Date : 9/12/14
809 //-----------------------------------------------------------------------------
811 {
812  return true;
813 }
814 
815 //-----------------------------------------------------------------------------
816 // Function : Model::Model
817 // Purpose : "Model block" constructor
818 // Special Notes :
819 // Scope : public
820 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
821 // Creation Date : 9/12/14
822 //-----------------------------------------------------------------------------
823 
824 
825 // These are all just placeholder functions, as there is nothing to the model
826 // class.
827 // Class Model
828 
829 //-----------------------------------------------------------------------------
830 // Function : Model::Model
831 // Purpose : "Model block" constructor
832 // Special Notes :
833 // Scope : public
834 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
835 // Creation Date : 9/12/14
836 //-----------------------------------------------------------------------------
838  const Configuration & configuration,
839  const ModelBlock & MB,
840  const FactoryBlock & factory_block)
841  : DeviceModel(MB, configuration.getModelParameters(), factory_block)
842 {
843 }
844 
845 //-----------------------------------------------------------------------------
846 // Function : Model::~Model
847 // Purpose : destructor
848 // Special Notes :
849 // Scope : public
850 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
851 // Creation Date : 9/12/14
852 //-----------------------------------------------------------------------------
854 {
855  std::vector<Instance*>::iterator iter;
856  std::vector<Instance*>::iterator first = instanceContainer.begin();
857  std::vector<Instance*>::iterator last = instanceContainer.end();
858 
859  for (iter=first; iter!=last; ++iter)
860  {
861  delete (*iter);
862  }
863 }
864 
865 //-----------------------------------------------------------------------------
866 // Function : Model::printOutInstances
867 // Purpose : debugging tool.
868 // Special Notes :
869 // Scope : public
870 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
871 // Creation Date : 9/12/14
872 //-----------------------------------------------------------------------------
873 std::ostream &Model::printOutInstances(std::ostream &os) const
874 {
875  std::vector<Instance*>::const_iterator iter;
876  std::vector<Instance*>::const_iterator first = instanceContainer.begin();
877  std::vector<Instance*>::const_iterator last = instanceContainer.end();
878 
879  int i;
880  os << std::endl;
881  os << " name model name Parameters" << std::endl;
882  for (i=0, iter=first; iter!=last; ++iter, ++i)
883  {
884  os << " " << i << ": " << (*iter)->getName() << " ";
885  os << getName();
886  os << std::endl;
887  }
888 
889  os << std::endl;
890 
891  return os;
892 }
893 
894 //-----------------------------------------------------------------------------
895 // Function : Model::forEachInstance
896 // Purpose :
897 // Special Notes :
898 // Scope : public
899 // Creator : David Baur
900 // Creation Date : 2/4/2014
901 //-----------------------------------------------------------------------------
902 /// Apply a device instance "op" to all instances associated with this
903 /// model
904 ///
905 /// @param[in] op Operator to apply to all instances.
906 ///
907 ///
908 void Model::forEachInstance(DeviceInstanceOp &op) const /* override */
909 {
910  for (std::vector<Instance *>::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
911  op(*it);
912 }
913 
914 
915 Device *Traits::factory(const Configuration &configuration, const FactoryBlock &factory_block)
916 {
917 
918  return new DeviceMaster<Traits>(configuration, factory_block, factory_block.solverState_, factory_block.deviceOptions_);
919 }
920 
922 {
924  .registerDevice("PowerGridBranch", 1)
925  .registerDevice("PGBR", 1)
926  .registerModelType("PowerGridBranch", 1);
927 }
928 
929 } // namespace PowerGridBranch
930 } // namespace Device
931 } // 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)