DPsim
SP_Ph1_Load.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_Load.h>
10 
11 using namespace CPS;
12 
13 // #### General ####
14 // please note that P,Q values can not be passed inside constructor since P,Q are currently read from the terminal,
15 // and these values are not yet assigned to the terminals when this constructor was called in reader.
16 SP::Ph1::Load::Load(String uid, String name, Logger::Level logLevel)
17  : CompositePowerComp<Complex>(uid, name, false, true, logLevel),
18  mActivePowerPerUnit(mAttributes->create<Real>("P_pu")),
19  mReactivePowerPerUnit(mAttributes->create<Real>("Q_pu")),
20  mActivePower(mAttributes->createDynamic<Real>(
21  "P")), //Made dynamic so it can be imported through InterfaceVillas
22  mReactivePower(mAttributes->createDynamic<Real>(
23  "Q")), //Made dynamic so it can be imported through InterfaceVillas
24  mNomVoltage(mAttributes->create<Real>("V_nom")) {
25 
26  SPDLOG_LOGGER_INFO(mSLog, "Create {} of type {}", **mName, this->type());
27  mSLog->flush();
28  **mIntfVoltage = MatrixComp::Zero(1, 1);
29  **mIntfCurrent = MatrixComp::Zero(1, 1);
30  setTerminalNumber(1);
31 };
32 
33 void SP::Ph1::Load::setParameters(Real activePower, Real reactivePower,
34  Real nominalVoltage) {
35  **mActivePower = activePower;
36  **mReactivePower = reactivePower;
37  **mNomVoltage = nominalVoltage;
38 
39  SPDLOG_LOGGER_INFO(mSLog, "Active Power={} [W] Reactive Power={} [VAr]",
40  **mActivePower, **mReactivePower);
41  mSLog->flush();
42 
43  mParametersSet = true;
44 }
45 
46 // #### Powerflow section ####
47 void SP::Ph1::Load::calculatePerUnitParameters(Real baseApparentPower,
48  Real baseOmega) {
49  SPDLOG_LOGGER_INFO(mSLog, "#### Calculate Per Unit Parameters for {}",
50  **mName);
51  mBaseApparentPower = baseApparentPower;
52  mBaseOmega = baseOmega;
53  SPDLOG_LOGGER_INFO(mSLog, "Base Power={} [VA] Base Omega={} [1/s]",
54  mBaseApparentPower, mBaseOmega);
55 
56  **mActivePowerPerUnit = **mActivePower / mBaseApparentPower;
57  **mReactivePowerPerUnit = **mReactivePower / mBaseApparentPower;
58  SPDLOG_LOGGER_INFO(mSLog, "Active Power={} [pu] Reactive Power={} [pu]",
59  **mActivePowerPerUnit, **mReactivePowerPerUnit);
60  mSLog->flush();
61 }
62 
63 void SP::Ph1::Load::modifyPowerFlowBusType(PowerflowBusType powerflowBusType) {
64  switch (powerflowBusType) {
65  case CPS::PowerflowBusType::PV:
66  throw std::invalid_argument(
67  " Power flow bus type error, load currently cannot be set as PVNode ");
68  break;
69  case CPS::PowerflowBusType::PQ:
70  mPowerflowBusType = powerflowBusType;
71  break;
72  case CPS::PowerflowBusType::VD:
73  throw std::invalid_argument(
74  " Power flow bus type error, load cannot be set as VDNode ");
75  break;
76  case CPS::PowerflowBusType::None:
77  break;
78  default:
79  throw std::invalid_argument(" Invalid power flow bus type ");
80  break;
81  }
82 };
83 
84 void SP::Ph1::Load::updatePQ(Real time) {
85  if (mLoadProfile.weightingFactors.empty()) {
86  **mActivePower = mLoadProfile.pqData.find(time)->second.p;
87  **mReactivePower = mLoadProfile.pqData.find(time)->second.q;
88  } else {
89  Real wf = mLoadProfile.weightingFactors.find(time)->second;
91  Real P_new = this->attributeTyped<Real>("P_nom")->get() * wf;
92  Real Q_new = this->attributeTyped<Real>("Q_nom")->get() * wf;
93  **mActivePower = P_new;
94  **mReactivePower = Q_new;
95  }
96 };
97 
99 
100  if (!mParametersSet) {
101  setParameters(mTerminals[0]->singleActivePower(),
102  mTerminals[0]->singleReactivePower(),
103  std::abs(mTerminals[0]->initialSingleVoltage()));
104  }
105 
106  // instantiate subResistor for active power consumption
107  if (**mActivePower != 0) {
108  mResistance = std::pow(**mNomVoltage, 2) / **mActivePower;
109  mConductance = 1.0 / mResistance;
110  mSubResistor = std::make_shared<SP::Ph1::Resistor>(
111  **mUID + "_res", **mName + "_res", Logger::Level::off);
112  mSubResistor->setParameters(mResistance);
113  mSubResistor->connect({SimNode::GND, mTerminals[0]->node()});
114  mSubResistor->initialize(mFrequencies);
115  mSubResistor->initializeFromNodesAndTerminals(frequency);
116  addMNASubComponent(mSubResistor, MNA_SUBCOMP_TASK_ORDER::NO_TASK,
117  MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, false);
118  }
119 
120  if (**mReactivePower != 0)
121  mReactance = std::pow(**mNomVoltage, 2) / **mReactivePower;
122  else
123  mReactance = 0;
124 
125  // instantiate subInductor or subCapacitor for reactive power consumption
126  if (mReactance > 0) {
127  mInductance = mReactance / (2 * PI * frequency);
128  mSubInductor = std::make_shared<SP::Ph1::Inductor>(
129  **mUID + "_res", **mName + "_ind", Logger::Level::off);
130  mSubInductor->setParameters(mInductance);
131  mSubInductor->connect({SimNode::GND, mTerminals[0]->node()});
132  mSubInductor->initialize(mFrequencies);
133  mSubInductor->initializeFromNodesAndTerminals(frequency);
134  addMNASubComponent(mSubInductor, MNA_SUBCOMP_TASK_ORDER::NO_TASK,
135  MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, false);
136  } else if (mReactance < 0) {
137  mCapacitance = -1 / (2 * PI * frequency) / mReactance;
138  mSubCapacitor = std::make_shared<SP::Ph1::Capacitor>(
139  **mUID + "_res", **mName + "_cap", Logger::Level::off);
140  mSubCapacitor->setParameters(mCapacitance);
141  mSubCapacitor->connect({SimNode::GND, mTerminals[0]->node()});
142  mSubCapacitor->initialize(mFrequencies);
143  mSubCapacitor->initializeFromNodesAndTerminals(frequency);
144  addMNASubComponent(mSubCapacitor, MNA_SUBCOMP_TASK_ORDER::NO_TASK,
145  MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, false);
146  }
147 
148  (**mIntfVoltage)(0, 0) = mTerminals[0]->initialSingleVoltage();
149  (**mIntfCurrent)(0, 0) = std::conj(Complex(attributeTyped<Real>("P")->get(),
150  attributeTyped<Real>("Q")->get()) /
151  (**mIntfVoltage)(0, 0));
152 
153  SPDLOG_LOGGER_INFO(mSLog,
154  "\n--- Initialization from powerflow ---"
155  "\nVoltage across: {:s}"
156  "\nCurrent: {:s}"
157  "\nTerminal 0 voltage: {:s}"
158  "\n--- Initialization from powerflow finished ---",
159  Logger::phasorToString((**mIntfVoltage)(0, 0)),
160  Logger::phasorToString((**mIntfCurrent)(0, 0)),
161  Logger::phasorToString(initialSingleVoltage(0)));
162  SPDLOG_LOGGER_INFO(mSLog,
163  "Updated parameters according to powerflow:\n"
164  "Active Power={} [W] Reactive Power={} [VAr]",
165  attributeTyped<Real>("P")->get(),
166  attributeTyped<Real>("Q")->get());
167  mSLog->flush();
168 }
169 
170 // #### MNA section ####
171 
172 void SP::Ph1::Load::mnaParentAddPostStepDependencies(
173  AttributeBase::List &prevStepDependencies,
174  AttributeBase::List &attributeDependencies,
175  AttributeBase::List &modifiedAttributes,
176  Attribute<Matrix>::Ptr &leftVector) {
177  attributeDependencies.push_back(leftVector);
178  modifiedAttributes.push_back(mIntfCurrent);
179  modifiedAttributes.push_back(mIntfVoltage);
180 };
181 
182 void SP::Ph1::Load::mnaParentPostStep(Real time, Int timeStepCount,
183  Attribute<Matrix>::Ptr &leftVector) {
184  mnaCompUpdateVoltage(**leftVector);
185  mnaCompUpdateCurrent(**leftVector);
186 }
187 
188 void SP::Ph1::Load::mnaCompUpdateVoltage(const Matrix &leftVector) {
189  (**mIntfVoltage)(0, 0) =
190  Math::complexFromVectorElement(leftVector, matrixNodeIndex(0));
191 }
192 
193 void SP::Ph1::Load::mnaCompUpdateCurrent(const Matrix &leftVector) {
194  (**mIntfCurrent)(0, 0) = 0;
195 
196  for (auto &subc : mSubComponents) {
197  (**mIntfCurrent)(0, 0) += subc->intfCurrent()(0, 0);
198  }
199 }
Base class for composite power components.
const Attribute< String >::Ptr mName
Human readable name.
String type()
Get component type (cross-platform)
void mnaCompUpdateVoltage(const Matrix &leftVector) override
Updates internal voltage variable of the component.
void modifyPowerFlowBusType(PowerflowBusType powerflowBusType) override
Modify powerflow bus type.
Definition: SP_Ph1_Load.cpp:63
void initializeFromNodesAndTerminals(Real frequency) override
Initializes component from power flow data.
Definition: SP_Ph1_Load.cpp:98
Load(String uid, String name, Logger::Level logLevel=Logger::Level::off)
Defines UID, name and logging level.
Definition: SP_Ph1_Load.cpp:16
void updatePQ(Real time)
Update PQ for this load for power flow calculation at next time step.
Definition: SP_Ph1_Load.cpp:84
void mnaParentPostStep(Real time, Int timeStepCount, Attribute< Matrix >::Ptr &leftVector) override
MNA post step operations.
void mnaCompUpdateCurrent(const Matrix &leftVector) override
Updates internal current variable of the component.
void calculatePerUnitParameters(Real baseApparentPower, Real baseOmega)
Calculates component's parameters in specified per-unit system.
Definition: SP_Ph1_Load.cpp:47
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.