DPsim
SP_Ph1_PiLine.cpp
1 /* Copyright 2017-2021 Institute for Automation of Complex Power Systems,
2  * EONERC, RWTH Aachen University
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
7  *********************************************************************************/
8 
9 #include <dpsim-models/SP/SP_Ph1_PiLine.h>
10 
11 using namespace CPS;
12 
13 SP::Ph1::PiLine::PiLine(String uid, String name, Logger::Level logLevel)
14  : Base::Ph1::PiLine(mAttributes),
15  CompositePowerComp<Complex>(uid, name, false, true, logLevel),
16  mBaseVoltage(mAttributes->create<Real>("base_Voltage")),
17  mCurrent(mAttributes->create<MatrixComp>("current_vector")),
18  mActivePowerBranch(mAttributes->create<Matrix>("p_branch_vector")),
19  mReactivePowerBranch(mAttributes->create<Matrix>("q_branch_vector")),
20  mActivePowerInjection(mAttributes->create<Real>("p_inj")),
21  mReactivePowerInjection(mAttributes->create<Real>("q_inj")) {
22 
23  SPDLOG_LOGGER_INFO(mSLog, "Create {} {}", this->type(), name);
24  mSLog->flush();
25 
26  setVirtualNodeNumber(1);
27  setTerminalNumber(2);
28  **mIntfVoltage = MatrixComp::Zero(1, 1);
29  **mIntfCurrent = MatrixComp::Zero(1, 1);
30  **mCurrent = MatrixComp::Zero(2, 1);
31  **mActivePowerBranch = Matrix::Zero(2, 1);
32  **mReactivePowerBranch = Matrix::Zero(2, 1);
33 }
34 
35 void SP::Ph1::PiLine::setParameters(Real resistance, Real inductance,
36  Real capacitance, Real conductance) {
37 
38  **mSeriesRes = resistance;
39  **mSeriesInd = inductance;
40  SPDLOG_LOGGER_INFO(mSLog, "Resistance={} [Ohm] Inductance={} [H]",
41  **mSeriesRes, **mSeriesInd);
42 
43  if (capacitance > 0) {
44  **mParallelCap = capacitance;
45  } else {
46  **mParallelCap = 1e-12;
47  SPDLOG_LOGGER_WARN(
48  mSLog, "Zero value for Capacitance, setting default value of C={} [F]",
49  **mParallelCap);
50  }
51  if (conductance > 0) {
52  **mParallelCond = conductance;
53  } else {
54  if (mBehaviour == Behaviour::Initialization)
55  **mParallelCond =
56  (conductance >= 0)
57  ? conductance
58  : 1e-6; // init mode for initFromPowerFlow of mna system components
59  else
60  **mParallelCond = (conductance > 0) ? conductance : 1e-6;
61  SPDLOG_LOGGER_WARN(
62  mSLog, "Zero value for Conductance, setting default value of G={} [S]",
63  **mParallelCond);
64  }
65  SPDLOG_LOGGER_INFO(mSLog, "Capacitance={} [F] Conductance={} [S]",
66  **mParallelCap, **mParallelCond);
67  mSLog->flush();
68  mParametersSet = true;
69 }
70 
73  auto copy = PiLine::make(name, mLogLevel);
74  copy->setParameters(**mSeriesRes, **mSeriesInd, **mParallelCap,
75  **mParallelCond);
76  return copy;
77 }
78 
79 // #### Powerflow section ####
80 void SP::Ph1::PiLine::setBaseVoltage(Real baseVoltage) {
81  **mBaseVoltage = baseVoltage;
82 }
83 
84 void SP::Ph1::PiLine::calculatePerUnitParameters(Real baseApparentPower,
85  Real baseOmega) {
86  SPDLOG_LOGGER_INFO(mSLog, "#### Calculate Per Unit Parameters for {}",
87  **mName);
88  mBaseApparentPower = baseApparentPower;
89  mBaseOmega = baseOmega;
90  SPDLOG_LOGGER_INFO(mSLog, "Base Power={} [VA] Base Omega={} [1/s]",
91  baseApparentPower, baseOmega);
92 
93  mBaseImpedance = (**mBaseVoltage * **mBaseVoltage) / mBaseApparentPower;
94  mBaseAdmittance = 1.0 / mBaseImpedance;
95  mBaseInductance = mBaseImpedance / mBaseOmega;
96  mBaseCapacitance = 1.0 / mBaseOmega / mBaseImpedance;
97  mBaseCurrent = baseApparentPower /
98  (**mBaseVoltage *
99  sqrt(3)); // I_base=(S_threephase/3)/(V_line_to_line/sqrt(3))
100  SPDLOG_LOGGER_INFO(mSLog, "Base Voltage={} [V] Base Impedance={} [Ohm]",
101  **mBaseVoltage, mBaseImpedance);
102 
103  mSeriesResPerUnit = **mSeriesRes / mBaseImpedance;
104  mSeriesIndPerUnit = **mSeriesInd / mBaseInductance;
105  mParallelCapPerUnit = **mParallelCap / mBaseCapacitance;
106  mParallelCondPerUnit = **mParallelCond / mBaseAdmittance;
107 
108  SPDLOG_LOGGER_INFO(mSLog, "Resistance={} [pu] Reactance={} [pu]",
109  mSeriesResPerUnit, 1. * mSeriesIndPerUnit);
110  SPDLOG_LOGGER_INFO(mSLog, "Susceptance={} [pu] Conductance={} [pu]",
111  1. * mParallelCapPerUnit, mParallelCondPerUnit);
112  mSLog->flush();
113 }
114 
115 void SP::Ph1::PiLine::pfApplyAdmittanceMatrixStamp(SparseMatrixCompRow &Y) {
116  int bus1 = this->matrixNodeIndex(0);
117  int bus2 = this->matrixNodeIndex(1);
118 
119  //create the element admittance matrix
120  Complex y =
121  Complex(1, 0) / Complex(mSeriesResPerUnit, 1. * mSeriesIndPerUnit);
122  Complex ys =
123  Complex(mParallelCondPerUnit, 1. * mParallelCapPerUnit) / Complex(2, 0);
124 
125  //Fill the internal matrix
126  mY_element = MatrixComp(2, 2);
127  mY_element(0, 0) = y + ys;
128  mY_element(0, 1) = -y;
129  mY_element(1, 0) = -y;
130  mY_element(1, 1) = y + ys;
131 
132  //check for inf or nan
133  for (int i = 0; i < 2; i++)
134  for (int j = 0; j < 2; j++)
135  if (std::isinf(mY_element.coeff(i, j).real()) ||
136  std::isinf(mY_element.coeff(i, j).imag())) {
137  std::cout << mY_element << std::endl;
138  std::stringstream ss;
139  ss << "Line>>" << this->name()
140  << ": infinite or nan values in the element Y at: " << i << "," << j;
141  throw std::invalid_argument(ss.str());
142  std::cout << "Line>>" << this->name()
143  << ": infinite or nan values in the element Y at: " << i
144  << "," << j << std::endl;
145  }
146 
147  //set the circuit matrix values
148  Y.coeffRef(bus1, bus1) += mY_element.coeff(0, 0);
149  Y.coeffRef(bus1, bus2) += mY_element.coeff(0, 1);
150  Y.coeffRef(bus2, bus2) += mY_element.coeff(1, 1);
151  Y.coeffRef(bus2, bus1) += mY_element.coeff(1, 0);
152 
153  SPDLOG_LOGGER_INFO(mSLog, "#### PF Y matrix stamping #### ");
154  SPDLOG_LOGGER_INFO(mSLog, "{}", mY_element);
155  mSLog->flush();
156 }
157 
158 void SP::Ph1::PiLine::updateBranchFlow(VectorComp &current,
159  VectorComp &powerflow) {
160  **mCurrent = current * mBaseCurrent;
161  **mActivePowerBranch = powerflow.real() * mBaseApparentPower;
162  **mReactivePowerBranch = powerflow.imag() * mBaseApparentPower;
163 }
164 
165 void SP::Ph1::PiLine::storeNodalInjection(Complex powerInjection) {
166  **mActivePowerInjection = std::real(powerInjection) * mBaseApparentPower;
167  **mReactivePowerInjection = std::imag(powerInjection) * mBaseApparentPower;
168 }
169 
170 MatrixComp SP::Ph1::PiLine::Y_element() { return mY_element; }
171 
173 
174  // By default there is always a small conductance to ground to
175  // avoid problems with floating nodes.
176  **mParallelCond = (**mParallelCond >= 0) ? **mParallelCond : 1e-6;
177 
178  // Static calculation
179  Real omega = 2. * PI * frequency;
180  Complex impedance = {**mSeriesRes, omega * **mSeriesInd};
181  (**mIntfVoltage)(0, 0) = initialSingleVoltage(1) - initialSingleVoltage(0);
182  (**mIntfCurrent)(0, 0) = (**mIntfVoltage)(0, 0) / impedance;
183 
184  // Initialization of virtual node
185  mVirtualNodes[0]->setInitialVoltage(initialSingleVoltage(0) +
186  (**mIntfCurrent)(0, 0) * **mSeriesRes);
187 
188  // Create series sub components
189  mSubSeriesResistor =
190  std::make_shared<SP::Ph1::Resistor>(**mName + "_res", mLogLevel);
191  mSubSeriesResistor->setParameters(**mSeriesRes);
192  mSubSeriesResistor->connect({mTerminals[0]->node(), mVirtualNodes[0]});
193  mSubSeriesResistor->initialize(mFrequencies);
194  mSubSeriesResistor->initializeFromNodesAndTerminals(frequency);
195  addMNASubComponent(mSubSeriesResistor, MNA_SUBCOMP_TASK_ORDER::NO_TASK,
196  MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, false);
197 
198  mSubSeriesInductor =
199  std::make_shared<SP::Ph1::Inductor>(**mName + "_ind", mLogLevel);
200  mSubSeriesInductor->setParameters(**mSeriesInd);
201  mSubSeriesInductor->connect({mVirtualNodes[0], mTerminals[1]->node()});
202  mSubSeriesInductor->initialize(mFrequencies);
203  mSubSeriesInductor->initializeFromNodesAndTerminals(frequency);
204  addMNASubComponent(mSubSeriesInductor, MNA_SUBCOMP_TASK_ORDER::NO_TASK,
205  MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, true);
206 
207  // Create parallel sub components
208  if (**mParallelCond >= 0) {
209  mSubParallelResistor0 =
210  std::make_shared<SP::Ph1::Resistor>(**mName + "_con0", mLogLevel);
211  mSubParallelResistor0->setParameters(2. / **mParallelCond);
212  mSubParallelResistor0->connect(
213  SimNode::List{SimNode::GND, mTerminals[0]->node()});
214  mSubParallelResistor0->initialize(mFrequencies);
215  mSubParallelResistor0->initializeFromNodesAndTerminals(frequency);
216  addMNASubComponent(mSubParallelResistor0, MNA_SUBCOMP_TASK_ORDER::NO_TASK,
217  MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, false);
218 
219  mSubParallelResistor1 =
220  std::make_shared<SP::Ph1::Resistor>(**mName + "_con1", mLogLevel);
221  mSubParallelResistor1->setParameters(2. / **mParallelCond);
222  mSubParallelResistor1->connect(
223  SimNode::List{SimNode::GND, mTerminals[1]->node()});
224  mSubParallelResistor1->initialize(mFrequencies);
225  mSubParallelResistor1->initializeFromNodesAndTerminals(frequency);
226  addMNASubComponent(mSubParallelResistor1, MNA_SUBCOMP_TASK_ORDER::NO_TASK,
227  MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, false);
228  }
229 
230  if (**mParallelCap >= 0) {
231  mSubParallelCapacitor0 =
232  std::make_shared<SP::Ph1::Capacitor>(**mName + "_cap0", mLogLevel);
233  mSubParallelCapacitor0->setParameters(**mParallelCap / 2.);
234  mSubParallelCapacitor0->connect(
235  SimNode::List{SimNode::GND, mTerminals[0]->node()});
236  mSubParallelCapacitor0->initialize(mFrequencies);
237  mSubParallelCapacitor0->initializeFromNodesAndTerminals(frequency);
238  addMNASubComponent(mSubParallelCapacitor0, MNA_SUBCOMP_TASK_ORDER::NO_TASK,
239  MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, true);
240 
241  mSubParallelCapacitor1 =
242  std::make_shared<SP::Ph1::Capacitor>(**mName + "_cap1", mLogLevel);
243  mSubParallelCapacitor1->setParameters(**mParallelCap / 2.);
244  mSubParallelCapacitor1->connect(
245  SimNode::List{SimNode::GND, mTerminals[1]->node()});
246  mSubParallelCapacitor1->initialize(mFrequencies);
247  mSubParallelCapacitor1->initializeFromNodesAndTerminals(frequency);
248  addMNASubComponent(mSubParallelCapacitor1, MNA_SUBCOMP_TASK_ORDER::NO_TASK,
249  MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, true);
250  }
251 
252  SPDLOG_LOGGER_INFO(
253  mSLog,
254  "\n--- Initialization from powerflow ---"
255  "\nVoltage across: {:s}"
256  "\nCurrent: {:s}"
257  "\nTerminal 0 voltage: {:s}"
258  "\nTerminal 1 voltage: {:s}"
259  "\nVirtual Node 1 voltage: {:s}"
260  "\n--- Initialization from powerflow finished ---",
261  Logger::phasorToString((**mIntfVoltage)(0, 0)),
262  Logger::phasorToString((**mIntfCurrent)(0, 0)),
263  Logger::phasorToString(initialSingleVoltage(0)),
264  Logger::phasorToString(initialSingleVoltage(1)),
265  Logger::phasorToString(mVirtualNodes[0]->initialSingleVoltage()));
266 }
267 
269  AttributeBase::List &prevStepDependencies,
270  AttributeBase::List &attributeDependencies,
271  AttributeBase::List &modifiedAttributes,
272  Attribute<Matrix>::Ptr &leftVector) {
273  attributeDependencies.push_back(leftVector);
274  modifiedAttributes.push_back(mIntfVoltage);
275  modifiedAttributes.push_back(mIntfCurrent);
276 }
277 
278 void SP::Ph1::PiLine::mnaParentPostStep(Real time, Int timeStepCount,
279  Attribute<Matrix>::Ptr &leftVector) {
280  this->mnaUpdateVoltage(**leftVector);
281  this->mnaUpdateCurrent(**leftVector);
282 }
283 
284 void SP::Ph1::PiLine::mnaCompUpdateVoltage(const Matrix &leftVector) {
285  (**mIntfVoltage)(0, 0) = 0;
286  if (terminalNotGrounded(1))
287  (**mIntfVoltage)(0, 0) =
288  Math::complexFromVectorElement(leftVector, matrixNodeIndex(1));
289  if (terminalNotGrounded(0))
290  (**mIntfVoltage)(0, 0) =
291  (**mIntfVoltage)(0, 0) -
292  Math::complexFromVectorElement(leftVector, matrixNodeIndex(0));
293 }
294 
295 void SP::Ph1::PiLine::mnaCompUpdateCurrent(const Matrix &leftVector) {
296  (**mIntfCurrent)(0, 0) = mSubSeriesInductor->intfCurrent()(0, 0);
297 }
298 
299 MNAInterface::List SP::Ph1::PiLine::mnaTearGroundComponents() {
300  MNAInterface::List gndComponents;
301 
302  gndComponents.push_back(mSubParallelResistor0);
303  gndComponents.push_back(mSubParallelResistor1);
304 
305  if (**mParallelCap >= 0) {
306  gndComponents.push_back(mSubParallelCapacitor0);
307  gndComponents.push_back(mSubParallelCapacitor1);
308  }
309 
310  return gndComponents;
311 }
312 
313 void SP::Ph1::PiLine::mnaTearInitialize(Real omega, Real timeStep) {
314  mSubSeriesResistor->mnaTearSetIdx(mTearIdx);
315  mSubSeriesResistor->mnaTearInitialize(omega, timeStep);
316  mSubSeriesInductor->mnaTearSetIdx(mTearIdx);
317  mSubSeriesInductor->mnaTearInitialize(omega, timeStep);
318 }
319 
320 void SP::Ph1::PiLine::mnaTearApplyMatrixStamp(SparseMatrixRow &tearMatrix) {
321  mSubSeriesResistor->mnaTearApplyMatrixStamp(tearMatrix);
322  mSubSeriesInductor->mnaTearApplyMatrixStamp(tearMatrix);
323 }
324 
325 void SP::Ph1::PiLine::mnaTearApplyVoltageStamp(Matrix &voltageVector) {
326  mSubSeriesInductor->mnaTearApplyVoltageStamp(voltageVector);
327 }
328 
329 void SP::Ph1::PiLine::mnaTearPostStep(Complex voltage, Complex current) {
330  mSubSeriesInductor->mnaTearPostStep(voltage - current * **mSeriesRes,
331  current);
332 }
Base class for composite power components.
String type()
Get component type (cross-platform)
PI-line static phasor model.
Definition: SP_Ph1_PiLine.h:30
void setBaseVoltage(Real baseVoltage)
Set base voltage.
void calculatePerUnitParameters(Real baseApparentPower, Real baseOmega)
Calculates component's parameters in specified per-unit system.
const Attribute< Matrix >::Ptr mActivePowerBranch
branch active powerflow [W], coef(0) has data from node 0, coef(1) from node 1.
Definition: SP_Ph1_PiLine.h:40
const Attribute< MatrixComp >::Ptr mCurrent
branch Current flow [A], coef(0) has data from node 0, coef(1) from node 1.
Definition: SP_Ph1_PiLine.h:37
const Attribute< Matrix >::Ptr mReactivePowerBranch
branch reactive powerflow [Var], coef(0) has data from node 0, coef(1) from node 1.
Definition: SP_Ph1_PiLine.h:43
void mnaParentAddPostStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes, Attribute< Matrix >::Ptr &leftVector) override
add MNA post-step dependencies
void updateBranchFlow(VectorComp &current, VectorComp &powerflow)
updates branch current and power flow, input pu value, update with real value
void mnaParentPostStep(Real time, Int timeStepCount, Attribute< Matrix >::Ptr &leftVector) override
MNA post-step operations.
MatrixComp Y_element()
get admittance matrix
void pfApplyAdmittanceMatrixStamp(SparseMatrixCompRow &Y) override
Stamps admittance matrix.
void mnaCompUpdateCurrent(const Matrix &leftVector) override
Updates internal current variable of the component.
PiLine(String uid, String name, Logger::Level logLevel=Logger::Level::off)
Defines UID, name and logging level.
SimPowerComp< Complex >::Ptr clone(String copySuffix) override
DEPRECATED: Delete method.
void initializeFromNodesAndTerminals(Real frequency) override
Initializes component from power flow data.
void mnaCompUpdateVoltage(const Matrix &leftVector) override
Updates internal voltage variable of the component.
void storeNodalInjection(Complex powerInjection)
stores nodal injection power in this line object
Base class for all components that are transmitting power.
Definition: SimPowerComp.h:17
const Attribute< MatrixVar< Complex > >::Ptr mIntfCurrent
Current through component.
Definition: SimPowerComp.h:47
const Attribute< MatrixVar< Complex > >::Ptr mIntfVoltage
Voltage between terminals.
Definition: SimPowerComp.h:45
Logger::Log mSLog
Component logger.