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