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