Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#216 Implement shunt regulation model #224

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 26 additions & 6 deletions sources/Algo/include/Algo.h
Original file line number Diff line number Diff line change
Expand Up @@ -905,23 +905,42 @@ class DynModelAlgorithm : public NodeAlgorithm {
const inputs::DynamicDataBaseManager& manager_; ///< dynamic database config manager
};

/// @brief Shunts definition for a voltage level
struct VLShuntsDefinition {
/// @brief Hash for shunts definition
struct ShuntHash {
/**
* @brief Retrieve the hash value
*
* @param shunt the shunt to hash
* @return the hash value
*/
size_t operator()(const inputs::Shunt& shunt) const noexcept;
};
using ShuntsSet = std::unordered_set<inputs::Shunt, ShuntHash>; ///< Alias for set of shunts

ShuntsSet shunts; ///< Set of shunts for current voltage level
bool dynamicModelAssociated = false; ///< determines if the current voltage level is associated with a dynamic model
};

/**
* @brief Shunt counter definition
* @brief Shunt definitions
*/
struct ShuntCounterDefinitions {
std::unordered_map<inputs::VoltageLevel::VoltageLevelId, unsigned int> nbShunts; ///< Number of shunts by voltage level
struct ShuntDefinitions {
std::unordered_map<inputs::VoltageLevel::VoltageLevelId, VLShuntsDefinition> shunts; ///< Shunt definitions by voltage level
};

/**
* @brief Counter of shunts by voltage levels
*/
class ShuntCounterAlgorithm : public NodeAlgorithm {
class ShuntDefinitionAlgorithm : public NodeAlgorithm {
public:
/**
* @brief Constructor
* @param shuntCounterDefs the counter definitions to update
* @param manager dynamic data base manager
*/
explicit ShuntCounterAlgorithm(ShuntCounterDefinitions& shuntCounterDefs);
ShuntDefinitionAlgorithm(ShuntDefinitions& shuntCounterDefs, const inputs::DynamicDataBaseManager& manager);

/**
* @brief Performs the algorithm
Expand All @@ -933,7 +952,8 @@ class ShuntCounterAlgorithm : public NodeAlgorithm {
void operator()(const NodePtr& node);

private:
ShuntCounterDefinitions& shuntCounterDefs_; ///< the counter definitions to update
ShuntDefinitions& shuntDefs_; ///< the counter definitions to update
std::unordered_set<inputs::VoltageLevel::VoltageLevelId> voltageLevelsWithAssociation_; ///< dynamic data base manager
};

/**
Expand Down
17 changes: 14 additions & 3 deletions sources/Algo/src/Algo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -705,12 +705,23 @@ DynModelAlgorithm::MacroConnectHash::operator()(const MacroConnect& connect) con

/////////////////////////////////////////////////////////////////////////////////

ShuntCounterAlgorithm::ShuntCounterAlgorithm(ShuntCounterDefinitions& defs) : shuntCounterDefs_(defs) {}
ShuntDefinitionAlgorithm::ShuntDefinitionAlgorithm(ShuntDefinitions& defs, const inputs::DynamicDataBaseManager& manager) : shuntDefs_(defs) {
const auto& multiAssociations = manager.assemblingDocument().multipleAssociations();
std::transform(multiAssociations.begin(), multiAssociations.end(), std::inserter(voltageLevelsWithAssociation_, voltageLevelsWithAssociation_.begin()),
[](const inputs::AssemblingXmlDocument::MultipleAssociation& association) { return association.shunt.voltageLevel; });
}

void
ShuntCounterAlgorithm::operator()(const NodePtr& node) {
ShuntDefinitionAlgorithm::operator()(const NodePtr& node) {
auto vl = node->voltageLevel.lock();
shuntCounterDefs_.nbShunts[vl->id] += node->shunts.size();
auto& map = shuntDefs_.shunts[vl->id];
std::copy(node->shunts.begin(), node->shunts.end(), std::inserter(map.shunts, map.shunts.end()));
map.dynamicModelAssociated |= (voltageLevelsWithAssociation_.count(vl->id) > 0);
}

size_t
VLShuntsDefinition::ShuntHash::operator()(const inputs::Shunt& shunt) const noexcept {
return std::hash<inputs::Shunt::ShuntId>{}(shunt.id);
}

//////////////////////////////////////////////////////////////////////////////////
Expand Down
24 changes: 16 additions & 8 deletions sources/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ Context::Context(const ContextDef& def, const inputs::Configuration& config) :

networkManager_.onNode(algo::MainConnexComponentAlgorithm(mainConnexNodes_));
networkManager_.onNode(algo::DynModelAlgorithm(dynamicModels_, dynamicDataBaseManager_));
networkManager_.onNode(algo::ShuntCounterAlgorithm(counters_));
networkManager_.onNode(algo::ShuntDefinitionAlgorithm(shuntDefinitions_, dynamicDataBaseManager_));
networkManager_.onNode(algo::LinesByIdAlgorithm(linesById_));
}

Expand Down Expand Up @@ -175,7 +175,7 @@ Context::exportOutputs() {
file::path dydOutput(config_.outputDir());
dydOutput.append(basename_ + ".dyd");
outputs::Dyd dydWriter(outputs::Dyd::DydDefinition(basename_, dydOutput.generic_string(), generators_, loads_, slackNode_, hvdcLineDefinitions_,
busesWithDynamicModel_, dynamicDataBaseManager_, dynamicModels_, svarcsDefinitions_));
busesWithDynamicModel_, dynamicDataBaseManager_, dynamicModels_, svarcsDefinitions_, shuntDefinitions_));
dydWriter.write();

// Par
Expand All @@ -191,14 +191,15 @@ Context::exportOutputs() {
file::path parOutput(config_.outputDir());
parOutput.append(basename_ + ".par");
outputs::Par parWriter(outputs::Par::ParDefinition(basename_, config_.outputDir(), parOutput, generators_, hvdcLineDefinitions_,
config_.getActivePowerCompensation(), busesWithDynamicModel_, dynamicDataBaseManager_, counters_,
config_.getActivePowerCompensation(), busesWithDynamicModel_, dynamicDataBaseManager_, shuntDefinitions_,
dynamicModels_, linesById_, svarcsDefinitions_));
parWriter.write();

// Diagram
file::path diagramDirectory(config_.outputDir());
diagramDirectory.append(basename_ + outputs::constants::diagramDirectorySuffix);
outputs::Diagram diagramWriter(outputs::Diagram::DiagramDefinition(basename_, diagramDirectory.generic_string(), generators_, hvdcLineDefinitions_));
outputs::Diagram diagramWriter(
outputs::Diagram::DiagramDefinition(basename_, diagramDirectory.generic_string(), generators_, hvdcLineDefinitions_, shuntDefinitions_));
diagramWriter.write();

if (def_.simulationKind == SimulationKind::SECURITY_ANALYSIS) {
Expand Down Expand Up @@ -227,15 +228,21 @@ Context::exportOutputJob() {

void
Context::exportOutputsContingencies() {
auto map = outputs::constants::computeFilteredShuntsByIds(shuntDefinitions_);
outputs::constants::ShuntsRefSet shuntsWithSections;
for (const auto& pair : map) {
shuntsWithSections.insert(pair.second.begin(), pair.second.end());
}

if (validContingencies_) {
for (const auto& contingency : validContingencies_->get()) {
exportOutputsContingency(contingency);
exportOutputsContingency(contingency, shuntsWithSections);
}
}
}

void
Context::exportOutputsContingency(const inputs::Contingency& contingency) {
Context::exportOutputsContingency(const inputs::Contingency& contingency, const outputs::constants::ShuntsRefSet& shuntsWithSections) {
// Prepare a DYD, PAR and JOBS for every contingency
// The DYD and PAR contain the definition of the events of the contingency

Expand All @@ -245,13 +252,14 @@ Context::exportOutputsContingency(const inputs::Contingency& contingency) {
// Specific DYD for contingency
file::path dydEvent(config_.outputDir());
dydEvent.append(basenameEvent + ".dyd");
outputs::DydEvent dydEventWriter(outputs::DydEvent::DydEventDefinition(basenameEvent, dydEvent.generic_string(), contingency));
outputs::DydEvent dydEventWriter(outputs::DydEvent::DydEventDefinition(basenameEvent, dydEvent.generic_string(), contingency, shuntsWithSections));
dydEventWriter.write();

// Specific PAR for contingency
file::path parEvent(config_.outputDir());
parEvent.append(basenameEvent + ".par");
outputs::ParEvent parEventWriter(outputs::ParEvent::ParEventDefinition(basenameEvent, parEvent.generic_string(), contingency, config_.getTimeOfEvent()));
outputs::ParEvent parEventWriter(
outputs::ParEvent::ParEventDefinition(basenameEvent, parEvent.generic_string(), contingency, shuntsWithSections, config_.getTimeOfEvent()));
parEventWriter.write();

#if _DEBUG_
Expand Down
13 changes: 9 additions & 4 deletions sources/Context.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include "Algo.h"
#include "Configuration.h"
#include "Constants.h"
#include "ContingenciesManager.h"
#include "DynamicDataBaseManager.h"
#include "NetworkManager.h"
Expand Down Expand Up @@ -148,9 +149,13 @@ class Context {
/// @brief Prepare the output files required to simulate the valid contingencies
void exportOutputsContingencies();

/// @brief Prepare the output files required to simulate a given contingency
/// @param contingency the contingency
void exportOutputsContingency(const inputs::Contingency& contingency);
/**
* @brief Prepare the output files required to simulate a given contingency
*
* @param contingency the contingency
* @param shuntsWithSections set of shunts with sections
*/
void exportOutputsContingency(const inputs::Contingency& contingency, const outputs::constants::ShuntsRefSet& shuntsWithSections);

private:
ContextDef def_; ///< context definition
Expand All @@ -170,7 +175,7 @@ class Context {
algo::HVDCLineDefinitions hvdcLineDefinitions_; ///< hvdc definitions
algo::GeneratorDefinitionAlgorithm::BusGenMap busesWithDynamicModel_; ///< map of bus ids to a generator that regulates them
algo::DynamicModelDefinitions dynamicModels_; ///< model definitions
algo::ShuntCounterDefinitions counters_; ///< shunt counters definitions
algo::ShuntDefinitions shuntDefinitions_; ///< shunt definitions
algo::LinesByIdDefinitions linesById_; ///< Lines by ids definition
algo::StaticVarCompensatorDefinitions svarcsDefinitions_; ///< Static var compensators definitions to use
boost::optional<algo::ValidContingencies> validContingencies_; ///< contingencies accepted for simulation in a Security Analyasis
Expand Down
35 changes: 32 additions & 3 deletions sources/Inputs/include/Node.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,15 +141,44 @@ class Tfo {
/// @brief Topological shunt
struct Shunt {
using ShuntId = std::string; ///< alias for shunt id
using BusId = std::string; ///< Alias for bus id connected to the shunt

/**
* @brief Constructor
* @brief Construct a new Shunt
*
* @param id the shunt id
* @param busId the connected bus id
* @param targetV the target voltage of the shunt
* @param voltageRegulationOn whether voltage regulation is enabled for the shunt
* @param bs the vector of the susceptance values for the shunt
* @param sectionNumber initial section index
*/
explicit Shunt(const ShuntId& id) : id(id) {}
Shunt(const ShuntId& id, const BusId& busId, double targetV, bool voltageRegulationOn, const std::vector<double>& bs, unsigned int sectionNumber) :
id(id),
busId(busId),
targetV(targetV),
voltageRegulationOn(voltageRegulationOn),
bSections(bs),
sectionNumber(sectionNumber) {}

const ShuntId id; ///< Shunt id
/**
* @brief Equality operator
*
* comparing the ids
*
* @param other the shunt to compare to
* @return @b true if the shunts are equal, @b false if not
*/
bool operator==(const Shunt& other) const {
return id == other.id;
}

const ShuntId id; ///< Shunt id
const BusId busId; ///< the connected bus of the shunt
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this the bus of connection or the regulated one? the comment here is not aligned on the one of line 144 above

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to dynawo documentation, it is the connection bus (comment l144 corrected)

const double targetV; ///< the target V of the shunt
const bool voltageRegulationOn; ///< whether voltage regulation is enabled for the shunt
const std::vector<double> bSections; ///< the vector of the susceptance values for the shunt
const unsigned int sectionNumber; ///< initial section index in sections
};

/// @brief Topological dangling line
Expand Down
8 changes: 7 additions & 1 deletion sources/Inputs/src/NetworkManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,14 @@ NetworkManager::buildTree() {
const auto& shunts = networkVL->getShuntCompensators();
std::unordered_map<Node::NodeId, std::vector<Shunt>> shuntsMap;
for (const auto& shunt : shunts) {
std::size_t nbSections = shunt->getMaximumSection() + 1; // We add the first section at 0
std::vector<double> bs(nbSections);
unsigned int i = 0;
std::generate(bs.begin(), bs.end(), [&shunt, &i]() { return shunt->getB(i++); });
// We take into account even disconnected shunts as dynamic models may aim to connect them
(shuntsMap[shunt->getBusInterface()->getID()]).push_back(std::move(Shunt(shunt->getID())));
(shuntsMap[shunt->getBusInterface()->getID()])
.push_back(std::move(
Shunt(shunt->getID(), shunt->getBusInterface()->getID(), shunt->getTargetV(), shunt->isVoltageRegulationOn(), bs, shunt->getCurrentSection())));
}

auto vl = std::make_shared<VoltageLevel>(networkVL->getID());
Expand Down
55 changes: 55 additions & 0 deletions sources/Outputs/include/Constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,50 @@
#pragma once

#include "Algo.h"
#include "Node.h"

#include <functional>
#include <limits>
#include <string>
#include <unordered_map>
#include <vector>

namespace dfl {
namespace outputs {
/// @brief Namespace for constant variables common to all writers
namespace constants {

/// @brief Alias for map of references to shunts by connected bus id
using RefShuntsByIdMap = std::unordered_map<inputs::Shunt::BusId, std::vector<std::reference_wrapper<const inputs::Shunt>>>;

/// @brief Alias for reference on const shunt
using ConstShuntRef = std::reference_wrapper<const inputs::Shunt>;
/// @brief Hash for shunts references
struct ShuntRefHash {
/**
* @brief Retrieve the hash value
*
* @param shunt the shunt to hash
* @return the hash value
*/
size_t operator()(const ConstShuntRef& shunt) const noexcept;
};
/// @brief Operator equal definition for shunt references
struct ShuntRefEqual {
/**
* @brief Determine if two references to a shunt are the same
*
* They are equal if the embedded shunts are equal
*
* @param lhs left comparee
* @param rhs right comparee
* @return true if both referenced shunts are equal, false if not
*/
bool operator()(const ConstShuntRef& lhs, const ConstShuntRef& rhs) const;
};
/// @brief Alias for set of references to shunt
using ShuntsRefSet = std::unordered_set<ConstShuntRef, ShuntRefHash, ShuntRefEqual>; ///< Alias for set of reference to shunts

/**
* @brief Return a hash number from a string as input
* @param str The string that will serve as input for the hash function
Expand Down Expand Up @@ -59,6 +94,25 @@ computeQmax(double powerFactor, double pMax) {
*/
std::string diagramFilename(const std::string& id);

/**
* @brief Retrieve the shunt regulation id
*
* @param busId the connected bus id of the shunt
* @return the computed shunt regulation id
*/
static inline std::string
computeShuntRegulationId(const std::string& busId) {
return "ShuntRegulation_" + busId;
}

/**
* @brief Compute the list of shunts, sorting by connected bus id
*
* @param shuntDefinitions the shund definitions to use
* @return the sorted list of shunts
*/
RefShuntsByIdMap computeFilteredShuntsByIds(const algo::ShuntDefinitions& shuntDefinitions);

const std::string networkModelName{"NETWORK"}; ///< Name of the model corresponding to network
const std::string loadParId{"GenericRestorativeLoad"}; ///< PAR id common to all loads
const std::string diagramDirectorySuffix{"_Diagram"}; ///< Suffix for the diagram directory
Expand All @@ -71,6 +125,7 @@ const std::string propSignalNGeneratorFixedPParId{"propSignalNGeneratorFixedP"};
const std::string remoteVControlParId{"remoteVControl"}; ///< PAR id for using remote voltage control
const std::string remoteSignalNGeneratorFixedP{"remoteSignalNFixedP"}; ///< PAR id for using remote signal N with fixed P
const std::string xmlEncoding{"UTF-8"}; ///< Default encoding for XML outputs files
const std::string diagramTableBPu{"tableBPu"}; ///< Name of the table in susceptance sections diagram files

constexpr double powerValueMax = std::numeric_limits<double>::max(); ///< Maximum value for powers, meaning infinite

Expand Down
Loading