Xyce  6.1
N_DEV_PowerGrid.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_PowerGrid.C,v $
27 //
28 // Purpose : PowerGrid classes: provides a device that calculates the
29 // steady state power flow in a transmission grid. This is
30 // a "monolithic model" for the entire power grid. It is
31 // being replaced by individual device models (branch, bus
32 // shunt, load, sources) that parallelize better.
33 //
34 // Special Notes : Experimental new device for an LDRD.
35 //
36 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
37 //
38 // Creation Date : 9/12/14
39 //
40 // Revision Information:
41 // ---------------------
42 //
43 // Revision Number: $Revision: 1.13 $
44 //
45 // Revision Date : $Date: 2015/04/08 19:18:24 $
46 //
47 // Current Owner : $Author: tvrusso $
48 //----------------------------------------------------------------------------
49 
50 #include <Xyce_config.h>
51 
52 
53 // ---------- Standard Includes ----------
54 
55 // ---------- Xyce Includes ----------
56 #include <N_DEV_PowerGrid.h>
57 #include <N_DEV_Const.h>
58 #include <N_DEV_DeviceOptions.h>
59 #include <N_DEV_DeviceMaster.h>
60 #include <N_DEV_ExternData.h>
61 #include <N_DEV_MatrixLoadData.h>
62 #include <N_DEV_Message.h>
63 #include <N_DEV_SolverState.h>
64 
65 #include <N_LAS_Matrix.h>
66 #include <N_LAS_Vector.h>
67 
68 #include <N_UTL_FeatureTest.h>
69 #include <N_UTL_IndentStreamBuf.h>
70 
71 namespace Xyce {
72 namespace Device {
73 
74 
75 namespace PowerGrid {
76 
77 // enables debug output for just the digital devices
78 //static const int DEBUG_DEVICE = 1;
79 
81 {
83  .setUnit(U_NONE)
84  .setDescription("Number of Buses");
85 
86  p.addPar("AT", std::string("IV"), &PowerGrid::Instance::analysisType_)
87  .setUnit(U_NONE)
88  .setDescription("Analysis Type");
89 
90  p.addPar("BUF", std::string("busFile"), &PowerGrid::Instance::busFileName_)
91  .setUnit(U_NONE)
92  .setDescription("IC File Name");
93 
94  p.addPar("BRF", std::string("branchFile"), &PowerGrid::Instance::branchFileName_)
95  .setUnit(U_NONE)
96  .setDescription("BD File Name");
97 }
98 
100 {}
101 
102 
103 
104 std::vector< std::vector<int> > Instance::jacStamp;
105 
106 // Class Instance
107 //-----------------------------------------------------------------------------
108 // Function : Instance::Instance
109 // Purpose : "instance block" constructor
110 // Special Notes :
111 // Scope : public
112 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
113 // Creation Date : 9/12/14
114 //-----------------------------------------------------------------------------
116  const Configuration & configuration,
117  const InstanceBlock & IB,
118  Model & Miter,
119  const FactoryBlock & factory_block)
120  : DeviceInstance(IB, configuration.getInstanceParameters(), factory_block),
121  model_(Miter),
122  numBus_(1),
123  analysisType_(""),
124  busFileName_(""),
125  branchFileName_("")
126 {
127  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
128  {
129  Xyce::dout() << std::endl << "In device constructor for " << getName() << std::endl;
130  }
131 
132  std::vector<Param>::const_iterator iter = IB.params.begin();
133  std::vector<Param>::const_iterator last = IB.params.end();
134 
135  for ( ; iter != last; ++iter)
136  {
137  const std::string & tmpname = iter->tag();
138  const bool & tmpgiven = iter->given();
139 
140  // copy instance parameter values into private variables
141  if (tmpname == "NB" && tmpgiven == true)
142  {
143  numBus_ = iter->getImmutableValue<int>();
144  }
145  if (tmpname == "AT" && tmpgiven == true)
146  {
147  analysisType_ = iter->stringValue();
148  }
149  if (tmpname == "BUF" && tmpgiven == true)
150  {
151  busFileName_ = iter->stringValue();
152  }
153  if (tmpname == "BRF" && tmpgiven == true)
154  {
155  branchFileName_ = iter->stringValue();
156  }
157  }
158 
159  // read input data
160  loadBusdata();
161  loadBranchData();
162 
163  // do sanity checking on input files and entered values
164  if (numBus_ < 1)
165  {
166  UserError0(*this) << "NB Instance Parameter must be an integer >=1";
167  }
168 
169  if (magICmap_.size() != numBus_)
170  {
171  UserError(*this) << "Incorrect number of Initial Conditions for device "
172  << getName() << std::endl << "Device has NB=" << numBus_
173  << " and " << magICmap_.size() << " initial conditions in file "
174  << busFileName_;
175  return;
176  }
177 
178  // Build the admittance matrix from the branch data
179  buildYMatrixMap();
180 
181  if (DEBUG_DEVICE && isActive(Diag::DEVICE_DUMP_VECTORS))
182  {
183  printYMatrixMap();
184  }
185 
186  numIntVars = 0;
187  numExtVars = 4; // In general, this will be 4*numBus_
188  numStateVars = 0;
189 
190  // temporarily make this into a 2-port device, between inputs 1 and 2
191  // this is just to get the rest of the "Xyce plumbing" working
192 
193  // this code made the device into a 2-port resistor, as an intermediate step
194  // set G to real part of G11, just for initial testing
195  //twodComplexMap::iterator YMatrixMapIter=yMatrixMap_.begin();
196  //std::complex<double> cVal = YMatrixMapIter->second;
197  //G = std::abs(cVal);
198 
199  // this code needs to be generalized
200  g11 = yMatrixMap_[std::make_pair(1,1)].real();
201  b11 = yMatrixMap_[std::make_pair(1,1)].imag();
202  g12 = yMatrixMap_[std::make_pair(1,2)].real();
203  b12 = yMatrixMap_[std::make_pair(1,2)].imag();
204  g21 = yMatrixMap_[std::make_pair(2,1)].real();
205  b21 = yMatrixMap_[std::make_pair(2,1)].imag();
206  g22 = yMatrixMap_[std::make_pair(2,2)].real();
207  b22 = yMatrixMap_[std::make_pair(2,2)].imag();
208 
209  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
210  {
211  Xyce::dout() << getName() << " G's and B's are:"
212  << Util::push << std::endl
213  << "(g11,b11) = (" << g11 << " , " << b11 << ")" << std::endl
214  << "(g12,b12) = (" << g12 << " , " << b12 << ")" << std::endl
215  << "(g21,b21) = (" << g21 << " , " << b21 << ")" << std::endl
216  << "(g22,b22) = (" << g22 << " , " << b22 << ")" << std::endl
217  << std::endl;
218  }
219 
220  if( jacStamp.empty() )
221  {
222  jacStamp.resize(4);
223  jacStamp[0].resize(4);
224  jacStamp[1].resize(4);
225  jacStamp[2].resize(4);
226  jacStamp[3].resize(4);
227 
228  jacStamp[0][0] = 0;
229  jacStamp[0][1] = 1;
230  jacStamp[0][2] = 2;
231  jacStamp[0][3] = 3;
232  jacStamp[1][0] = 0;
233  jacStamp[1][1] = 1;
234  jacStamp[1][2] = 2;
235  jacStamp[1][3] = 3;
236  jacStamp[2][0] = 0;
237  jacStamp[2][1] = 1;
238  jacStamp[2][2] = 2;
239  jacStamp[2][3] = 3;
240  jacStamp[3][0] = 0;
241  jacStamp[3][1] = 1;
242  jacStamp[3][2] = 2;
243  jacStamp[3][3] = 3;
244 
245  }
246 
247  // Set params to constant default values:
248  setDefaultParams ();
249 
250  // Set params according to instance line and constant defaults from metadata:
251  setParams (IB.params);
252 
253  // Set any non-constant parameter defaults:
254 
255 }
256 
257 //-----------------------------------------------------------------------------
258 // Function : Instance::~Instance
259 // Purpose : destructor
260 // Special Notes :
261 // Scope : public
262 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
263 // Creation Date : 9/12/14
264 //-----------------------------------------------------------------------------
266 {
267 }
268 
269 //-----------------------------------------------------------------------------
270 // Function : Instance::registerLIDs
271 // Purpose :
272 // Special Notes :
273 // Scope : public
274 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
275 // Creation Date : 9/12/14
276 //-----------------------------------------------------------------------------
277 void Instance::registerLIDs( const std::vector<int> & intLIDVecRef,
278  const std::vector<int> & extLIDVecRef )
279 {
280  AssertLIDs(intLIDVecRef.size() == numIntVars);
281  AssertLIDs(extLIDVecRef.size() == numExtVars);
282 
283  // copy over the global ID lists.
284  intLIDVec = intLIDVecRef;
285  extLIDVec = extLIDVecRef;
286 
287  // in general, there will be 4 I/0 nodes for each branch
288  // these if-else blocks will be made into separate classes,
289  // once they work
290  if ( analysisType_ == "IV" )
291  {
292  li_VR1 = extLIDVec[0];
293  li_VR2 = extLIDVec[1];
294  li_VI1 = extLIDVec[2];
295  li_VI2 = extLIDVec[3];
296 
297  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
298  {
299  Xyce::dout() << getName() << " LIDs"
300  << Util::push << std::endl
301  << "li_VR1 = " << li_VR1 << std::endl
302  << "li_VI1 = " << li_VI1 << std::endl
303  << "li_VR2 = " << li_VR2 << std::endl
304  << "li_VI2 = " << li_VI2 << std::endl
305  << std::endl;
306  }
307  }
308  else if (analysisType_ == "PQ" )
309  {
310  li_Theta1 = extLIDVec[0];
311  li_Theta2 = extLIDVec[1];
312  li_VM1 = extLIDVec[2];
313  li_VM2 = extLIDVec[3];
314 
315  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
316  {
317  Xyce::dout() << getName() << " LIDs"
318  << Util::push << std::endl
319  << "li_Theta1 = " << li_Theta1 << std::endl
320  << "li_VM1 = " << li_VM1 << std::endl
321  << "li_Theta2 = " << li_Theta2 << std::endl
322  << "li_VM2 = " << li_VM2 << std::endl
323  << std::endl;
324  }
325  }
326  else
327  {
328  UserError0(*this) << "Analysis Type must be IV or PQ in power grid device: " << getName();
329  return;
330  }
331 }
332 
333 //-----------------------------------------------------------------------------
334 // Function : Instance::loadNodeSymbols
335 // Purpose :
336 // Special Notes :
337 // Scope : public
338 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
339 // Creation Date : 05/13/05
340 //-----------------------------------------------------------------------------
341 void Instance::loadNodeSymbols(Util::SymbolTable &symbol_table) const
342 {
343 }
344 
345 //-----------------------------------------------------------------------------
346 // Function : Instance::registerStateLIDs
347 // Purpose : Set up offsets so we can store quantities that need to be
348 // differentiated.
349 // Special Notes :
350 // Scope : public
351 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
352 // Creation Date : 9/12/14
353 //-----------------------------------------------------------------------------
354 void Instance::registerStateLIDs(const std::vector<int> & staLIDVecRef )
355 {
356  AssertLIDs(staLIDVecRef.size() == numStateVars);
357 }
358 
359 //-----------------------------------------------------------------------------
360 // Function : Instance::jacobianStamp
361 // Purpose :
362 // Special Notes :
363 // Scope : public
364 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
365 // Creation Date : 08/20/01
366 //-----------------------------------------------------------------------------
367 const std::vector< std::vector<int> > & Instance::jacobianStamp() const
368 {
369  return jacStamp;
370 }
371 
372 //-----------------------------------------------------------------------------
373 // Function : Instance::registerJacLIDs
374 // Purpose :
375 // Special Notes :
376 // Scope : public
377 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
378 // Creation Date : 08/27/01
379 //-----------------------------------------------------------------------------
380 void Instance::registerJacLIDs( const std::vector< std::vector<int> > & jacLIDVec )
381 {
382  DeviceInstance::registerJacLIDs( jacLIDVec );
383 
384  // These will be split out into separate classes once they both work
385  if (analysisType_ == "IV")
386  {
387  VR1_VR1_Offset = jacLIDVec[0][0];
388  VR1_VR2_Offset = jacLIDVec[0][1];
389  VR1_VI1_Offset = jacLIDVec[0][2];
390  VR1_VI2_Offset = jacLIDVec[0][3];
391 
392  VR2_VR1_Offset = jacLIDVec[1][0];
393  VR2_VR2_Offset = jacLIDVec[1][1];
394  VR2_VI1_Offset = jacLIDVec[1][2];
395  VR2_VI2_Offset = jacLIDVec[1][3];
396 
397  VI1_VR1_Offset = jacLIDVec[2][0];
398  VI1_VR2_Offset = jacLIDVec[2][1];
399  VI1_VI1_Offset = jacLIDVec[2][2];
400  VI1_VI2_Offset = jacLIDVec[2][3];
401 
402  VI2_VR1_Offset = jacLIDVec[3][0];
403  VI2_VR2_Offset = jacLIDVec[3][1];
404  VI2_VI1_Offset = jacLIDVec[3][2];
405  VI2_VI2_Offset = jacLIDVec[3][3];
406  }
407  else if (analysisType_ == "PQ")
408  {
409  Theta1_Theta1_Offset = jacLIDVec[0][0];
410  Theta1_Theta2_Offset = jacLIDVec[0][1];
411  Theta1_VM1_Offset = jacLIDVec[0][2];
412  Theta1_VM2_Offset = jacLIDVec[0][3];
413 
414  Theta2_Theta1_Offset = jacLIDVec[1][0];
415  Theta2_Theta2_Offset = jacLIDVec[1][1];
416  Theta2_VM1_Offset = jacLIDVec[1][2];
417  Theta2_VM2_Offset = jacLIDVec[1][3];
418 
419  VM1_Theta1_Offset = jacLIDVec[2][0];
420  VM1_Theta2_Offset = jacLIDVec[2][1];
421  VM1_VM1_Offset = jacLIDVec[2][2];
422  VM1_VM2_Offset = jacLIDVec[2][3];
423 
424  VM2_Theta1_Offset = jacLIDVec[3][0];
425  VM2_Theta2_Offset = jacLIDVec[3][1];
426  VM2_VM1_Offset = jacLIDVec[3][2];
427  VM2_VM2_Offset = jacLIDVec[3][3];
428  }
429 }
430 
431 //-----------------------------------------------------------------------------
432 // Function : Instance::updateIntermediateVars
433 // Purpose : update intermediate variables for one diode instance
434 // Special Notes :
435 // Scope : public
436 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
437 // Creation Date : 9/12/14
438 //-----------------------------------------------------------------------------
440 {
441  double * solVec = extData.nextSolVectorRawPtr;
442 
443  // These will be split out into separate classes once they work
444  if (analysisType_ == "IV")
445  {
446  IR1 = g11*solVec[li_VR1] + g12*solVec[li_VR2] - b11*solVec[li_VI1] - b12*solVec[li_VI2];
447  IR2 = g21*solVec[li_VR1] + g22*solVec[li_VR2] - b21*solVec[li_VI1] - b22*solVec[li_VI2];
448  II1 = b11*solVec[li_VR1] + b12*solVec[li_VR2] + g11*solVec[li_VI1] + g12*solVec[li_VI2];
449  II2 = b21*solVec[li_VR1] + b22*solVec[li_VR2] + g21*solVec[li_VI1] + g22*solVec[li_VI2];
450  }
451  else if (analysisType_ == "PQ")
452  {
453  double dSin12 = sin(solVec[li_Theta1]-solVec[li_Theta2]);
454  double dSin21 = sin(solVec[li_Theta2]-solVec[li_Theta1]);
455  double dCos12 = cos(solVec[li_Theta1]-solVec[li_Theta2]);
456  double dCos21 = cos(solVec[li_Theta2]-solVec[li_Theta1]);
457 
458  P1 = g11*solVec[li_VM1]*solVec[li_VM1] + solVec[li_VM1]*solVec[li_VM2]*(g12*dCos12 + b12*dSin12);
459  P2 = g22*solVec[li_VM2]*solVec[li_VM2] + solVec[li_VM2]*solVec[li_VM1]*(g21*dCos21 + b21*dSin21);
460  Q1 = -1*b11*solVec[li_VM1]*solVec[li_VM1] + solVec[li_VM1]*solVec[li_VM2]*(g12*dSin12 - b12*dCos12);
461  Q2 = -1*b22*solVec[li_VM2]*solVec[li_VM2] + solVec[li_VM2]*solVec[li_VM1]*(g21*dSin21 - b21*dCos21);
462  }
463  else
464  {
465  UserError0(*this) << "Analysis Type must be IV or PQ in power grid device: " << getName();
466  return false;
467  }
468 
469  return true;
470 }
471 
472 //-----------------------------------------------------------------------------
473 // Function : Instance::updatePrimaryState
474 // Purpose :
475 // Special Notes :
476 // Scope : public
477 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
478 // Creation Date : 9/12/14
479 //-----------------------------------------------------------------------------
481 {
482  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
483  {
484  Xyce::dout() << "Instance::updatePrimaryState" <<std::endl;
485  }
486 
487  return updateIntermediateVars ();
488 }
489 
490 //-----------------------------------------------------------------------------
491 // Function : Instance::loadDAEFVector
492 //
493 // Purpose : Loads the F-vector contributions
494 //
495 // Special Notes :
496 //
497 //
498 // Scope : public
499 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
500 // Creation Date : 9/12/14
501 //-----------------------------------------------------------------------------
503 {
504  double * fVec = extData.daeFVectorRawPtr;
505 
506  // this needs to be vectorized in the general case.
507  // These will be split out into separate classes once they work
508  if (analysisType_ == "IV")
509  {
510  fVec[li_VR1] += IR1;
511  fVec[li_VR2] += IR2;
512  fVec[li_VI1] += II1;
513  fVec[li_VI2] += II2;
514  }
515  else if (analysisType_ == "PQ")
516  {
517  fVec[li_Theta1] += P1;
518  fVec[li_Theta2] += P2;
519  fVec[li_VM1] += Q1;
520  fVec[li_VM2] += Q2;
521  }
522  else
523  {
524  UserError0(*this) << "Analysis Type must be IV or PQ in power grid device: " << getName();
525  return false;
526  }
527 
528  if (getSolverState().dcopFlag)
529  {
530  // no op placeholder
531  }
532  else
533  {
534  // no op placeholder
535  }
536 
537  return true;
538 }
539 
540 //-----------------------------------------------------------------------------
541 // Function : Instance::loadDAEQVector
542 //
543 // Purpose : Loads the Q-vector contributions. This is a no-op for
544 // this model
545 //
546 // Special Notes :
547 //
548 //
549 // Scope : public
550 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
551 // Creation Date : 9/12/14
552 //-----------------------------------------------------------------------------
554 {
555  return true;
556 }
557 
558 //-----------------------------------------------------------------------------
559 // Function : Instance::loadDAEdFdx ()
560 //
561 // Purpose : Loads the F-vector contributions
562 //
563 // Special Notes :
564 //
565 // Scope : public
566 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
567 // Creation Date : 9/12/14
568 //-----------------------------------------------------------------------------
570 {
571  Linear::Matrix & dFdx = *(extData.dFdxMatrixPtr);
572 
573  if (analysisType_ == "IV")
574  {
575  dFdx[li_VR1][VR1_VR1_Offset] += g11;
576  dFdx[li_VR1][VR1_VR2_Offset] += g12;
577  dFdx[li_VR1][VR1_VI1_Offset] -= b11;
578  dFdx[li_VR1][VR1_VI2_Offset] -= b12;
579 
580  dFdx[li_VR2][VR2_VR1_Offset] += g21;
581  dFdx[li_VR2][VR2_VR2_Offset] += g22;
582  dFdx[li_VR2][VR2_VI1_Offset] -= b21;
583  dFdx[li_VR2][VR2_VI2_Offset] -= b22;
584 
585  dFdx[li_VI1][VI1_VR1_Offset] += b11;
586  dFdx[li_VI1][VI1_VR2_Offset] += b12;
587  dFdx[li_VI1][VI1_VI1_Offset] += g11;
588  dFdx[li_VI1][VI1_VI2_Offset] += g12;
589 
590  dFdx[li_VI2][VI2_VR1_Offset] += b21;
591  dFdx[li_VI2][VI2_VR2_Offset] += b22;
592  dFdx[li_VI2][VI2_VI1_Offset] += g21;
593  dFdx[li_VI2][VI2_VI2_Offset] += g22;
594  }
595  else if (analysisType_ == "PQ")
596  {
597  double * solVec = extData.nextSolVectorRawPtr;
598  double dSin12 = sin(solVec[li_Theta1]-solVec[li_Theta2]);
599  double dSin21 = sin(solVec[li_Theta2]-solVec[li_Theta1]);
600  double dCos12 = cos(solVec[li_Theta1]-solVec[li_Theta2]);
601  double dCos21 = cos(solVec[li_Theta2]-solVec[li_Theta1]);
602 
603  // dP / dTheta terms
604  dFdx[li_Theta1][Theta1_Theta1_Offset] -= solVec[li_VM1]*solVec[li_VM2]*(g12*dSin12 - b12*dCos12);
605  dFdx[li_Theta1][Theta1_Theta2_Offset] += solVec[li_VM1]*solVec[li_VM2]*(g12*dSin12 - b12*dCos12);
606  dFdx[li_Theta2][Theta2_Theta1_Offset] += solVec[li_VM1]*solVec[li_VM2]*(g21*dSin21 - b21*dCos21);
607  dFdx[li_Theta2][Theta2_Theta2_Offset] -= solVec[li_VM1]*solVec[li_VM2]*(g21*dSin21 - b21*dCos21);
608 
609  // dP / dV terms
610  dFdx[li_Theta1][Theta1_VM1_Offset] += 2*solVec[li_VM1]*g11 + solVec[li_VM2]*(g12*dCos12 + b12*dSin12);
611  dFdx[li_Theta1][Theta1_VM2_Offset] += solVec[li_VM2]*(g21*dCos21 + b21*dSin21);
612  dFdx[li_Theta2][Theta2_VM1_Offset] += solVec[li_VM1]*(g12*dCos12 + b12*dSin12);
613  dFdx[li_Theta2][Theta2_VM2_Offset] += 2*solVec[li_VM2]*g22 + solVec[li_VM1]*(g21*dCos21 + b21*dSin21);
614 
615  // dQ / dTheta terms
616  dFdx[li_VM1][VM1_Theta1_Offset] -= solVec[li_VM1]*solVec[li_VM2]*(g12*dCos12 + b12*dSin12);
617  dFdx[li_VM1][VM1_Theta2_Offset] += solVec[li_VM1]*solVec[li_VM2]*(g12*dCos12 + b12*dSin12);
618  dFdx[li_VM2][VM2_Theta1_Offset] += solVec[li_VM1]*solVec[li_VM2]*(g21*dCos21 + b21*dSin21);
619  dFdx[li_VM2][VM2_Theta2_Offset] -= solVec[li_VM1]*solVec[li_VM2]*(g21*dCos21 + b21*dSin21);
620 
621  // dQ / dV terms
622  dFdx[li_VM1][VM1_VM1_Offset] += -2*solVec[li_VM1]*b11 + solVec[li_VM2]*(g12*dSin12 - b12*dCos12);
623  dFdx[li_VM1][VM1_VM2_Offset] += solVec[li_VM2]*(g21*dSin21 - b21*dCos21);
624  dFdx[li_VM2][VM2_VM1_Offset] += solVec[li_VM1]*(g21*dSin12 - b21*dCos12);
625  dFdx[li_VM2][VM2_VM2_Offset] += -2*solVec[li_VM2]*b22 + solVec[li_VM1]*(g21*dSin21 - b21*dCos21);
626  }
627  else
628  {
629  UserError0(*this) << "Analysis Type must be IV or PQ in power grid device: " << getName();
630  return false;
631  }
632 
633  if (getSolverState().dcopFlag)
634  {
635  // no op placeholder code;
636  }
637  else
638  {
639  // no op placeholder code;
640  }
641 
642  return true;
643 }
644 
645 //-----------------------------------------------------------------------------
646 // Function : Instance::loadDAEdQdx ()
647 //
648 // Purpose : Loads the Q-vector contributions. This is no-op for this
649 // model.
650 //
651 // Special Notes :
652 //
653 // Scope : public
654 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
655 // Creation Date : 9/12/14
656 //-----------------------------------------------------------------------------
658 {
659  return true;
660 }
661 
662 //-----------------------------------------------------------------------------
663 // Function : Instance::loadBusdata ()
664 //
665 // Purpose : Loads IC and Bus data from a file. This function will likely
666 // go away, once the monolithic PowerGrid model does.
667 // In that case, it may be more convenient to load
668 // the initial conditions for each bus from IC=
669 // statements on the instance lines
670 //
671 // Special Notes :
672 //
673 // Scope : public
674 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
675 // Creation Date : 9/12/14
676 //-----------------------------------------------------------------------------
678 {
679  // If the file name is enclosed in double quotes, strip them.
680  if (busFileName_[0] == '"' && busFileName_[busFileName_.length()-1] =='"')
681  {
682  busFileName_ = busFileName_.substr(1, busFileName_.length()-2);
683  }
684 
685  // make the file exists
686  std::ifstream busDataIn;
687  busDataIn.open(busFileName_.c_str(), std::ios::in);
688  if ( !busDataIn.is_open() )
689  {
690  Report::UserError() << "Could not find file " << busFileName_;
691  return false;
692  }
693 
694  // read in data for initial conditions for voltage magnitude and
695  // phase at each bus
696  int bus;
697  while ( busDataIn >> bus )
698  {
699  if ( magICmap_.count(bus) == 0 )
700  {
701  if (busDataIn >> magICmap_[bus] >> angleICmap_[bus]
703  {
704  if (DEBUG_DEVICE && isActive(Diag::DEVICE_DUMP_VECTORS))
705  {
706  Xyce::dout() << "Read line in file " << busFileName_ << " for bus "
707  << bus << ". (Mag,angle) ICs=(" << magICmap_[bus] << ","
708  << angleICmap_[bus] << "). Shunt (G,B)=("
709  << busShuntConductance_[bus] << ","
710  << busShuntSusceptance_[bus] << ")" << std::endl;
711  }
712  }
713  else
714  {
715  Report::UserError() << "Problem reading file " << busFileName_
716  << std::endl << "File must use space separated values,"
717  << "with 3 items per line.";
718  busDataIn.close();
719  return false;
720  }
721  }
722  else
723  {
724  Report::UserError() << "Problem reading " << busFileName_ << std::endl
725  << "There is a duplicate entry for bus number " << bus;
726  busDataIn.close();
727  return false;
728  }
729  }
730 
731  return true;
732 }
733 
734 //-----------------------------------------------------------------------------
735 // Function : Instance::loadBranchData ()
736 //
737 // Purpose : Loads branch data from a file. This function will likely
738 // go away, once the monolithic PowerGrid model does.
739 // In that case, it may be more convenient to load
740 // the branch data from instance parameters on each
741 // branch's instance line
742 //
743 // Special Notes :
744 //
745 // Scope : public
746 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
747 // Creation Date : 9/12/14
748 //-----------------------------------------------------------------------------
750 {
751  // If the file name is enclosed in double quotes, strip them.
752  if (branchFileName_[0] == '"' && branchFileName_[branchFileName_.length()-1] =='"')
753  {
754  branchFileName_ = branchFileName_.substr(1, branchFileName_.length()-2);
755  }
756 
757  std::ifstream branchDataIn;
758  branchDataIn.open(branchFileName_.c_str(), std::ios::in);
759  if ( !branchDataIn.is_open() )
760  {
761  Report::UserError() << "Could not find file " << branchFileName_;
762  return false;
763  }
764 
765  // read in data for branch data
766  int bus1, bus2;
767  double resistance, reactance, susceptance,turnsRatio;
768  twodKey fromToKey, toFromKey;
769  while ( branchDataIn >> bus1 >> bus2)
770  {
771  if ( (bus1 < 1) || (bus1 > numBus_) || (bus2 < 1) || (bus2 > numBus_) )
772  {
773  Report::UserError() << "Invalid bus number in file " << branchFileName_ << std::endl
774  << "Bus numbers should be between 1 and " << numBus_;
775  return false;
776  }
777 
778  // key1 is to-from data from file. key2 is from-to version.
779  // input data should only have one of them for each possible branch
780  fromToKey = std::make_pair(bus1,bus2);
781  toFromKey = std::make_pair(bus2,bus1);
782 
783  // insert data if neither key is in the map
784  if (( branchResistance_.count(fromToKey) == 0 ) &&
785  ( branchResistance_.count(toFromKey) == 0 ))
786  {
787  if ( branchDataIn >> resistance >> reactance >> susceptance >> turnsRatio )
788  {
789  branchResistance_[fromToKey]=resistance;
790  branchReactance_[fromToKey]=reactance;
791  branchSusceptance_[fromToKey]=susceptance;
792  // IEEE CDF format uses 0 to denote no transformer is present.
793  // This is effectively a turns-ratio of 1.0
794  turnsRatio_[fromToKey]= (turnsRatio > 0) ? turnsRatio : 1.0;
795  //branchResistance_.insert(twodMap::value_type(key1,resistance));
796 
797  if (DEBUG_DEVICE && isActive(Diag::DEVICE_DUMP_VECTORS))
798  {
799  Xyce::dout() << "Read line in file " << branchFileName_ << " for buses "
800  << bus1 << " " << bus2 << ". (R,X,B)=(" << branchResistance_[fromToKey]
801  << "," << branchReactance_[fromToKey] << "," << branchSusceptance_[fromToKey]
802  << "). Turns Ratio=" << turnsRatio_[fromToKey] << std::endl;
803  }
804  }
805  else
806  {
807  Report::UserError() << "Problem reading file " << branchFileName_
808  << std::endl << "File must use space separated values,"
809  << "with 3 items per line.";
810  branchDataIn.close();
811  return false;
812  }
813  }
814  else
815  {
816  Report::UserError() << "Problem reading " << branchFileName_ << std::endl
817  << "There is a duplicate branch data entry for bus numbers "
818  << bus1 << " and " << bus2 << std::endl;
819  branchDataIn.close();
820  return false;
821  }
822  }
823 
824  return true;
825 }
826 
827 //-----------------------------------------------------------------------------
828 // Function : Instance::buildYMatrixMap ()
829 //
830 // Purpose : Builds the Y Matrix from the branch data.
831 //
832 // Special Notes :
833 //
834 // Scope : public
835 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
836 // Creation Date : 9/15/14
837 //-----------------------------------------------------------------------------
839 {
840  // may combine these maps into one data structure
841  twodMap::iterator iterRes=branchResistance_.begin();
842  twodMap::iterator iterReact=branchReactance_.begin();
843  twodMap::iterator iterSuscept=branchSusceptance_.begin();
844  twodKey fromToKey, toFromKey, toToKey, fromFromKey;
845  int toID,fromID;
846  double invTurnsRatio; // makes equations easier to read
847  std::complex<double> zVal,selfVal;
848 
849  if ( (branchReactance_.size() != branchResistance_.size()) ||
850  (branchSusceptance_.size() != branchResistance_.size()) ||
851  (turnsRatio_.size() != branchResistance_.size()) )
852  {
853  Report::UserError() << "Branch Resistance, Reactance and Susceptance Matrices not same size.";
854  return false;
855  }
856 
857  for (iterRes;iterRes!=branchResistance_.end();++iterRes)
858  {
859  fromToKey=iterRes->first;
860  fromID=fromToKey.first;
861  toID=fromToKey.second;
862  if (DEBUG_DEVICE && isActive(Diag::DEVICE_DUMP_VECTORS))
863  {
864  Xyce::dout() << "Processing Y Matrix for branch ID: " << fromID << "-" << toID << std::endl;
865  }
866 
867  toFromKey = std::make_pair(toID,fromID);
868  fromFromKey = std::make_pair(fromID,fromID);;
869  toToKey = std::make_pair(toID,toID);
870  // makes equations easier to read
871  invTurnsRatio = (1./turnsRatio_[fromToKey]);
872 
873  // zVal is the impedance between the FROM and TO buses
874  // (1/zVal)*invTurnsRatio is the Y[i,j] and Y[j,i] term in the Admittance Matrix.
875  //zVal.real(branchResistance_[fromToKey]);
876  //zVal.imag(branchReactance_[fromToKey]);
877  zVal=std::complex<double>(branchResistance_[fromToKey],branchReactance_[fromToKey]);
878  yMatrixMap_[fromToKey] = (-1./zVal) * invTurnsRatio;
879  yMatrixMap_[toFromKey] = (-1./zVal) * invTurnsRatio;
880 
881  // addition to the Yii term is then Yij + half of the branch susceptance defined
882  // in the IEEE CDF Format, since CDF gives the parameters for a PI model of
883  // the branch. Y[j,j] term is unaffected by turns ratio. Y[i,i] term is.
884  selfVal = (1./zVal);
885  //selfVal.imag(selfVal.imag() + 0.5*branchSusceptance_[fromToKey]);
886  selfVal=std::complex<double>(selfVal.real(),selfVal.imag() + 0.5*branchSusceptance_[fromToKey]);
887  yMatrixMap_[fromFromKey] += selfVal*invTurnsRatio*invTurnsRatio;
888  yMatrixMap_[toToKey] += selfVal;
889 
890  if (DEBUG_DEVICE && isActive(Diag::DEVICE_DUMP_VECTORS))
891  {
892  Xyce::dout() << "zVal, selfVal and inverse turns Ratio are: " << zVal << " " << selfVal
893  << " " << invTurnsRatio << std::endl << "Updated Y Matrix values are: " << std::endl
894  << " Index " << fromID << " and " << toID << " = " << yMatrixMap_[fromToKey] << std::endl
895  << " Index " << toID << " and " << fromID << " = " << yMatrixMap_[toFromKey] << std::endl
896  << " Index " << fromID << " and " << fromID << " = " << yMatrixMap_[fromFromKey] << std::endl
897  << " Index " << toID << " and " << toID << " = " << yMatrixMap_[toToKey] << std::endl;
898  }
899  }
900 
901  // now add in bus conductance and susceptance
902  for (fromID=1; fromID <= numBus_; fromID++)
903  {
904  fromFromKey = std::make_pair(fromID,fromID);
905  yMatrixMap_[fromFromKey]=std::complex<double>(yMatrixMap_[fromFromKey].real() + busShuntConductance_[fromID],
906  yMatrixMap_[fromFromKey].imag() + busShuntSusceptance_[fromID]);
907  }
908 
909  return true;
910 }
911 
912 //-----------------------------------------------------------------------------
913 // Function : Instance::printYMatrixMap ()
914 //
915 // Purpose : prints the Y Matrix Map
916 //
917 // Special Notes :
918 //
919 // Scope : public
920 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
921 // Creation Date : 9/16/14
922 //-----------------------------------------------------------------------------
924 {
925  twodComplexMap::iterator iter=yMatrixMap_.begin();
926  twodKey key;
927  int toID, fromID;
928  std::complex<double> cVal;
929 
930  std::cout << "Y Matrix complex values are: " << std::endl;
931  for (iter;iter!=yMatrixMap_.end();++iter)
932  {
933  key=iter->first;
934  toID=key.first;
935  fromID=key.second;
936  cVal= iter->second;
937 
938  Xyce::dout() << " (" << toID << "," << fromID << ") = " << cVal << std::endl;
939  }
940 
941  return true;
942 }
943 
944 //-----------------------------------------------------------------------------
945 // Function : Model::Model
946 // Purpose : "Model block" constructor
947 // Special Notes :
948 // Scope : public
949 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
950 // Creation Date : 9/12/14
951 //-----------------------------------------------------------------------------
952 
953 
954 // These are all just placeholder functions, as there is nothing to the model
955 // class.
956 // Class Model
957 
958 //-----------------------------------------------------------------------------
959 // Function : Model::Model
960 // Purpose : "Model block" constructor
961 // Special Notes :
962 // Scope : public
963 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
964 // Creation Date : 9/12/14
965 //-----------------------------------------------------------------------------
967  const Configuration & configuration,
968  const ModelBlock & MB,
969  const FactoryBlock & factory_block)
970  : DeviceModel(MB, configuration.getModelParameters(), factory_block)
971 {
972 }
973 
974 //-----------------------------------------------------------------------------
975 // Function : Model::~Model
976 // Purpose : destructor
977 // Special Notes :
978 // Scope : public
979 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
980 // Creation Date : 9/12/14
981 //-----------------------------------------------------------------------------
983 {
984  std::vector<Instance*>::iterator iter;
985  std::vector<Instance*>::iterator first = instanceContainer.begin();
986  std::vector<Instance*>::iterator last = instanceContainer.end();
987 
988  for (iter=first; iter!=last; ++iter)
989  {
990  delete (*iter);
991  }
992 }
993 
994 //-----------------------------------------------------------------------------
995 // Function : Model::printOutInstances
996 // Purpose : debugging tool.
997 // Special Notes :
998 // Scope : public
999 // Creator : Pete Sholander, SNL, Electrical and Microsystems Modeling
1000 // Creation Date : 9/12/14
1001 //-----------------------------------------------------------------------------
1002 std::ostream &Model::printOutInstances(std::ostream &os) const
1003 {
1004  std::vector<Instance*>::const_iterator iter;
1005  std::vector<Instance*>::const_iterator first = instanceContainer.begin();
1006  std::vector<Instance*>::const_iterator last = instanceContainer.end();
1007 
1008  int i;
1009  os << std::endl;
1010  os << " name model name Parameters" << std::endl;
1011  for (i=0, iter=first; iter!=last; ++iter, ++i)
1012  {
1013  os << " " << i << ": " << (*iter)->getName() << " ";
1014  os << getName();
1015  os << std::endl;
1016  }
1017 
1018  os << std::endl;
1019 
1020  return os;
1021 }
1022 
1023 //-----------------------------------------------------------------------------
1024 // Function : Model::forEachInstance
1025 // Purpose :
1026 // Special Notes :
1027 // Scope : public
1028 // Creator : David Baur
1029 // Creation Date : 2/4/2014
1030 //-----------------------------------------------------------------------------
1031 /// Apply a device instance "op" to all instances associated with this
1032 /// model
1033 ///
1034 /// @param[in] op Operator to apply to all instances.
1035 ///
1036 ///
1037 void Model::forEachInstance(DeviceInstanceOp &op) const /* override */
1038 {
1039  for (std::vector<Instance *>::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
1040  op(*it);
1041 }
1042 
1043 
1044 Device *Traits::factory(const Configuration &configuration, const FactoryBlock &factory_block)
1045 {
1046 
1047  return new DeviceMaster<Traits>(configuration, factory_block, factory_block.solverState_, factory_block.deviceOptions_);
1048 }
1049 
1051 {
1053  .registerDevice("PowerGrid", 1)
1054  .registerModelType("PowerGrid", 1);
1055 }
1056 
1057 } // namespace PowerGrid
1058 } // namespace Device
1059 } // namespace Xyce
const InstanceName & getName() const
void registerJacLIDs(const std::vector< std::vector< int > > &jacLIDVec)
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
std::map< int, double > busShuntSusceptance_
Pure virtual class to augment a linear system.
std::vector< Instance * > instanceContainer
#define AssertLIDs(cmp)
std::map< int, double > angleICmap_
virtual void registerJacLIDs(const JacobianStamp &jacLIDVec)
Instance(const Configuration &configuration, const InstanceBlock &IB, Model &Riter, const FactoryBlock &factory_block)
void setParams(const std::vector< Param > &params)
const std::string & getName() const
static void loadModelParameters(ParametricData< Model > &model_parameters)
The FactoryBlock contains parameters needed by the device, instance and model creation functions...
void loadNodeSymbols(Util::SymbolTable &symbol_table) const
Populates and returns the store name map.
const std::vector< std::vector< int > > & jacobianStamp() const
static std::vector< std::vector< int > > jacStamp
const DeviceOptions & deviceOptions_
std::map< int, double > magICmap_
static Config< T > & addConfiguration()
Adds the device to the Xyce device configuration.
void registerStateLIDs(const std::vector< int > &staLIDVecRef)
virtual void forEachInstance(DeviceInstanceOp &op) const
Apply a device instance "op" to all instances associated with this model.
Linear::Matrix * dFdxMatrixPtr
The Device class is an interface for device implementations.
Definition: N_DEV_Device.h:101
Class Configuration contains device configuration data.
static Device * factory(const Configuration &configuration, const FactoryBlock &factory_block)
const SolverState & getSolverState() const
void registerLIDs(const std::vector< int > &intLIDVecRef, const std::vector< int > &extLIDVecRef)
virtual std::ostream & printOutInstances(std::ostream &os) const
ModelBlock represents a .MODEL line from the netlist.
Manages parameter binding for class C.
Definition: N_DEV_Pars.h:214
InstanceBlock represent a device instance line from the netlist.
std::vector< Param > params
std::map< int, double > busShuntConductance_
static void loadInstanceParameters(ParametricData< Instance > &instance_parameters)