Skip to content
Open
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
3 changes: 1 addition & 2 deletions documentation/functionalDoc/functionalDoc.tex
Original file line number Diff line number Diff line change
Expand Up @@ -682,8 +682,7 @@ \section{Solver}
The Maximum time step value is by default 10s. This value can be modified in the configuration file (see section \ref{Dynaflow_Launcher_Configuration_Configuration_File}).
Notice that the maximum step value should be reduced only when the simulation is including
Special Protection Scheme automatons with a timescale smaller than 10 seconds: this would allow one to properly
take into account the SPS behaviour, avoiding any artificial synchronization effect. When modifying the
solver maximum time step, its value must be included in $ 1.0 < TimeStep \leq 10.0 $ seconds.
take into account the SPS behaviour, avoiding any artificial synchronization effect.

The full configuration (with default values) used is the following:

Expand Down
6 changes: 3 additions & 3 deletions sources/Algo/include/DynModelDefinitionAlgorithm.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,11 @@ struct DynamicModelDefinition {
*
* @param macroid the macro connector id to use
* @param type type of the element to connect
* @param id the element id to connect
* @param connectedId the element id to connect
* @param indexId used to index the macroConnections
*/
MacroConnection(const MacroId &macroid, const ElementType &type, const ElementId &id, const std::string &indexId)
: id(macroid), elementType(type), connectedElementId(id), indexId(indexId) {}
MacroConnection(const MacroId &macroid, const ElementType &type, const ElementId &connectedId, const std::string &indexId)
: id(macroid), elementType(type), connectedElementId(connectedId), indexId(indexId) {}

/**
* @brief Equality operator
Expand Down
12 changes: 12 additions & 0 deletions sources/Algo/include/GeneratorDefinitionAlgorithm.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,18 @@ class GeneratorDefinitionAlgorithm {
*/
bool isDiagramRectangular(const inputs::Generator &generator) const;

/**
* @brief selection of the most common generator models
*
* @param generator reference to input generator
* @param withTfo whether the transformer should be modeled within the model used or not
* @param infiniteReactiveLimits whether the selected generator should model reactive limits
* @param isInSVC whether the target generator belongs to a secondary voltage control area
* @param isRPCL2 whether the target generator uses reactive power control loop 2
* @return the selected generator model
*/
ModelType selectDiagramGenerators(const inputs::Generator &generator, bool withTfo, bool infiniteReactiveLimits, bool isInSVC, bool isRPCL2) const;

Generators &generators_; ///< the generators list to update
const inputs::NetworkManager::BusMapRegulating &busesToNumberOfRegulationMap_; ///< mapping of busId and the number of generators that regulates them
std::unordered_map<std::string, bool> generatorsInSVC; ///< If a generator id is in this map then it belongs to a secondary voltage control area,
Expand Down
114 changes: 68 additions & 46 deletions sources/Algo/src/GeneratorDefinitionAlgorithm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,60 +94,22 @@ void GeneratorDefinitionAlgorithm::operator()(const NodePtr &node, std::shared_p
const bool isRPCL2 = isInSVC && svcIt->second;
model = ModelType::SIGNALN_INFINITE;
algoRes->isAtLeastOneGeneratorRegulating = true;
constexpr bool withTfo = true;

if (generator.regulatedBusId == generator.connectedBusId && (generator.VNom > tfoVoltageLevel_ || DYN::doubleEquals(generator.VNom, tfoVoltageLevel_))) {
if ((isInSVC || generator.regulatedBusId == generator.connectedBusId) &&
(generator.VNom > tfoVoltageLevel_ || DYN::doubleEquals(generator.VNom, tfoVoltageLevel_))) {
// Generator is assumed to have no transformer in the static model description
// and regulatedBus equals to connectedBus
if (useInfiniteReactivelimits_) {
if (isInSVC) {
if (isRPCL2) {
model = ModelType::SIGNALN_TFO_RPCL2_INFINITE;
} else {
model = ModelType::SIGNALN_TFO_RPCL_INFINITE;
}
} else {
model = ModelType::SIGNALN_TFO_INFINITE;
}
} else {
if (isInSVC) {
if (isRPCL2) {
model = isDiagramRectangular(generator) ? ModelType::SIGNALN_TFO_RPCL2_RECTANGULAR : ModelType::DIAGRAM_PQ_TFO_RPCL2_SIGNALN;
} else {
model = isDiagramRectangular(generator) ? ModelType::SIGNALN_TFO_RPCL_RECTANGULAR : ModelType::DIAGRAM_PQ_TFO_RPCL_SIGNALN;
}
} else {
model = isDiagramRectangular(generator) ? ModelType::SIGNALN_TFO_RECTANGULAR : ModelType::DIAGRAM_PQ_TFO_SIGNALN;
}
}
model = selectDiagramGenerators(generator, withTfo, useInfiniteReactivelimits_, isInSVC, isRPCL2);
} else {
// Generator is assumed to have its transformer in the static model description
// or regulatedBus different from connectedBus
switch (nbOfRegulatingGenerators) {
case dfl::inputs::NetworkManager::NbOfRegulating::ONE:
// Only one generator regulates this node
if (generator.regulatedBusId == generator.connectedBusId) {
if (isInSVC || generator.regulatedBusId == generator.connectedBusId) {
// local regulation
if (useInfiniteReactivelimits_) {
if (isInSVC) {
if (isRPCL2) {
model = ModelType::SIGNALN_RPCL2_INFINITE;
} else {
model = ModelType::SIGNALN_RPCL_INFINITE;
}
} else {
model = ModelType::SIGNALN_INFINITE;
}
} else {
if (isInSVC) {
if (isRPCL2) {
model = isDiagramRectangular(generator) ? ModelType::SIGNALN_RPCL2_RECTANGULAR : ModelType::DIAGRAM_PQ_RPCL2_SIGNALN;
} else {
model = isDiagramRectangular(generator) ? ModelType::SIGNALN_RPCL_RECTANGULAR : ModelType::DIAGRAM_PQ_RPCL_SIGNALN;
}
} else {
model = isDiagramRectangular(generator) ? ModelType::SIGNALN_RECTANGULAR : ModelType::DIAGRAM_PQ_SIGNALN;
}
}
model = selectDiagramGenerators(generator, !withTfo, useInfiniteReactivelimits_, isInSVC, isRPCL2);
} else {
// remote regulation
if (useInfiniteReactivelimits_) {
Expand All @@ -160,9 +122,20 @@ void GeneratorDefinitionAlgorithm::operator()(const NodePtr &node, std::shared_p
case dfl::inputs::NetworkManager::NbOfRegulating::MULTIPLES:
// Several generators regulate this node
if (useInfiniteReactivelimits_) {
model = ModelType::PROP_SIGNALN_INFINITE;
if (isInSVC) {
model = selectDiagramGenerators(generator, !withTfo, useInfiniteReactivelimits_, isInSVC, isRPCL2);
} else {
model = ModelType::PROP_SIGNALN_INFINITE;
}
} else {
model = isDiagramRectangular(generator) ? ModelType::PROP_SIGNALN_RECTANGULAR : ModelType::PROP_DIAGRAM_PQ_SIGNALN;
dfl::inputs::NetworkManager::BusMapRegulating::const_iterator it2 = busesToNumberOfRegulationMap_.find(generator.connectedBusId);
dfl::inputs::NetworkManager::NbOfRegulating nbOfRegulatingGeneratorsLocal =
(it2 != busesToNumberOfRegulationMap_.end()) ? it2->second : dfl::inputs::NetworkManager::NbOfRegulating::ONE;
if (isInSVC && nbOfRegulatingGeneratorsLocal == dfl::inputs::NetworkManager::NbOfRegulating::ONE) {
model = selectDiagramGenerators(generator, !withTfo, useInfiniteReactivelimits_, isInSVC, isRPCL2);
} else {
model = isDiagramRectangular(generator) ? ModelType::PROP_SIGNALN_RECTANGULAR : ModelType::PROP_DIAGRAM_PQ_SIGNALN;
}
}
break;
default: // impossible by definition of the enum
Expand All @@ -175,6 +148,55 @@ void GeneratorDefinitionAlgorithm::operator()(const NodePtr &node, std::shared_p
}
}

GeneratorDefinitionAlgorithm::ModelType GeneratorDefinitionAlgorithm::selectDiagramGenerators(const inputs::Generator &generator, bool withTfo,
bool infiniteReactiveLimits, bool isInSVC, bool isRPCL2) const {
if (infiniteReactiveLimits) {
if (withTfo) {
if (isInSVC) {
if (isRPCL2) {
return ModelType::SIGNALN_TFO_RPCL2_INFINITE;
} else {
return ModelType::SIGNALN_TFO_RPCL_INFINITE;
}
} else {
return ModelType::SIGNALN_TFO_INFINITE;
}
} else {
if (isInSVC) {
if (isRPCL2) {
return ModelType::SIGNALN_RPCL2_INFINITE;
} else {
return ModelType::SIGNALN_RPCL_INFINITE;
}
} else {
return ModelType::SIGNALN_INFINITE;
}
}
} else {
if (withTfo) {
if (isInSVC) {
if (isRPCL2) {
return isDiagramRectangular(generator) ? ModelType::SIGNALN_TFO_RPCL2_RECTANGULAR : ModelType::DIAGRAM_PQ_TFO_RPCL2_SIGNALN;
} else {
return isDiagramRectangular(generator) ? ModelType::SIGNALN_TFO_RPCL_RECTANGULAR : ModelType::DIAGRAM_PQ_TFO_RPCL_SIGNALN;
}
} else {
return isDiagramRectangular(generator) ? ModelType::SIGNALN_TFO_RECTANGULAR : ModelType::DIAGRAM_PQ_TFO_SIGNALN;
}
} else {
if (isInSVC) {
if (isRPCL2) {
return isDiagramRectangular(generator) ? ModelType::SIGNALN_RPCL2_RECTANGULAR : ModelType::DIAGRAM_PQ_RPCL2_SIGNALN;
} else {
return isDiagramRectangular(generator) ? ModelType::SIGNALN_RPCL_RECTANGULAR : ModelType::DIAGRAM_PQ_RPCL_SIGNALN;
}
} else {
return isDiagramRectangular(generator) ? ModelType::SIGNALN_RECTANGULAR : ModelType::DIAGRAM_PQ_SIGNALN;
}
}
}
}

bool GeneratorDefinitionAlgorithm::isDiagramValid(const inputs::Generator &generator) {
if (useInfiniteReactivelimits_) {
return true;
Expand Down
2 changes: 2 additions & 0 deletions sources/Inputs/src/NetworkManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ void NetworkManager::buildTree() {
if (generator->isVoltageRegulationOn()) {
// We don't use dynamic models for generators with voltage regulation disabled
updateMapRegulatingBuses(mapBusIdToNumberOfRegulation_, nodes_[regulatedBusId]);
if (nodeid != regulatedBusId)
updateMapRegulatingBuses(mapBusIdToNumberOfRegulation_, nodes_[nodeid]);
}
nodes_[nodeid]->generators.emplace_back(generator->getID(), generator->isVoltageRegulationOn(), generator->getReactiveCurvesPoints(),
generator->getQMin(), generator->getQMax(), pmin, pmax, -generator->getQ(), targetP,
Expand Down
1 change: 0 additions & 1 deletion sources/Outputs/src/ParDynModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@ std::shared_ptr<parameters::ParametersSet> ParDynModel::writeSVCParameterSet(con
assert(genInitialParamToValues.find("Qr_" + std::to_string(it->second)) != genInitialParamToValues.end());
new_set->addParameter(helper::buildParameter("Qr_" + std::to_string(idx), genInitialParamToValues["Qr_" + std::to_string(it->second)]));
}
// new_set->addParameter(helper::buildParameter("Participate0_" + std::to_string(idx), true));
std::string side = "1";
if (hvdcDefinition.converterStationOnSide2())
side = "2";
Expand Down
82 changes: 82 additions & 0 deletions tests/algo/TestGeneratorsAlgo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ class TestAlgoServiceManagerInterface : public DYN::ServiceManagerInterface {
} // namespace test

static void generatorsEquals(const dfl::algo::GeneratorDefinition &lhs, const dfl::algo::GeneratorDefinition &rhs) {
std::cout << "Comparing " << lhs.id << std::endl;
ASSERT_EQ(lhs.id, rhs.id);
ASSERT_EQ(lhs.model, rhs.model);
ASSERT_EQ(lhs.points.size(), rhs.points.size());
Expand Down Expand Up @@ -609,6 +610,87 @@ TEST(Generators, generatorRemoteRegulationWithTfo) {
ASSERT_EQ(expected_gens_finite[index].targetP, generators[index].targetP);
}
}

TEST(Generators, generatorRemoteRegulationWithTfoAndSVC) {
auto vl = std::make_shared<dfl::inputs::VoltageLevel>("VL");
auto vl2 = std::make_shared<dfl::inputs::VoltageLevel>("VL2");
auto testServiceManager = boost::make_shared<test::TestAlgoServiceManagerInterface>();
std::vector<std::shared_ptr<dfl::inputs::Node>> nodes{
dfl::inputs::Node::build("0", vl, 0.0, {}, false, testServiceManager), dfl::inputs::Node::build("1", vl, 1.0, {}, false, testServiceManager),
dfl::inputs::Node::build("2", vl, 2.0, {}, false, testServiceManager), dfl::inputs::Node::build("3", vl, 3.0, {}, false, testServiceManager),
dfl::inputs::Node::build("4", vl2, 5.0, {}, false, testServiceManager), dfl::inputs::Node::build("5", vl2, 5.0, {}, false, testServiceManager),
dfl::inputs::Node::build("6", vl2, 0.0, {}, false, testServiceManager),
};

std::vector<dfl::inputs::Generator::ReactiveCurvePoint> points(
{dfl::inputs::Generator::ReactiveCurvePoint(12., 44., 440.), dfl::inputs::Generator::ReactiveCurvePoint(65., 44., 440.)});
std::vector<dfl::inputs::Generator::ReactiveCurvePoint> points0;
points0.push_back(dfl::inputs::Generator::ReactiveCurvePoint(2, -10, -10));
points0.push_back(dfl::inputs::Generator::ReactiveCurvePoint(1, 1, 17));

const std::string bus1 = "BUS_1";
const std::string bus2 = "BUS_2";
const std::string bus3 = "BUS_3";
const std::string bus4 = "BUS_4";
dfl::algo::GeneratorDefinitionAlgorithm::Generators expected_gens_infinite = {
dfl::algo::GeneratorDefinition("00", dfl::algo::GeneratorDefinition::ModelType::SIGNALN_RPCL_INFINITE, "0", points0, 0, 0, 0, 0, 0, 0,
bus1), // multiple generators on the same node
dfl::algo::GeneratorDefinition("01", dfl::algo::GeneratorDefinition::ModelType::SIGNALN_RPCL_INFINITE, "0", points, -1, 1, -1, 1, 0, 0,
bus1), // multiple generators on the same node
dfl::algo::GeneratorDefinition("02", dfl::algo::GeneratorDefinition::ModelType::SIGNALN_RPCL_INFINITE, "2", points, -2, 2, -2, 2, 0, 0, bus2),
dfl::algo::GeneratorDefinition("03", dfl::algo::GeneratorDefinition::ModelType::NETWORK, "3", points, 0, 0, 0, 0, 0, 0, bus4),
dfl::algo::GeneratorDefinition("05", dfl::algo::GeneratorDefinition::ModelType::PROP_SIGNALN_INFINITE, "4", points, -5, 5, -5, 5, 0, 0, bus3)};

dfl::algo::GeneratorDefinitionAlgorithm::Generators expected_gens_finite = {
dfl::algo::GeneratorDefinition("00", dfl::algo::GeneratorDefinition::ModelType::DIAGRAM_PQ_RPCL_SIGNALN, "0", points0, 0, 0, 0, 0, 0, 0,
bus1), // multiple generators on the same node
dfl::algo::GeneratorDefinition("01", dfl::algo::GeneratorDefinition::ModelType::SIGNALN_RPCL_RECTANGULAR, "0", points, -1, 1, -1, 1, 0, 0,
bus1), // multiple generators on the same node
dfl::algo::GeneratorDefinition("02", dfl::algo::GeneratorDefinition::ModelType::SIGNALN_RPCL_RECTANGULAR, "2", points, -2, 2, -2, 2, 0, 0, bus2),
dfl::algo::GeneratorDefinition("03", dfl::algo::GeneratorDefinition::ModelType::NETWORK, "3", points, 0, 0, 0, 0, 0, 0, bus4),
dfl::algo::GeneratorDefinition("05", dfl::algo::GeneratorDefinition::ModelType::PROP_SIGNALN_RECTANGULAR, "4", points, -5, 5, -5, 5, 0, 0, bus3)};

nodes[0]->generators.emplace_back("00", true, points0, 0, 0, 0, 0, 0, 0, 0, bus4, bus1);
nodes[0]->generators.emplace_back("01", true, points, -1, 1, -1, 1, 0, 0, 0, bus4, bus3);

nodes[2]->generators.emplace_back("02", true, points, -2, 2, -2, 2, 0, 0, 0, bus2, bus2);
nodes[3]->generators.emplace_back("03", false, points, 0, 0, 0, 0, 0, 0, 0, bus4, bus4);
nodes[4]->generators.emplace_back("05", true, points, -5, 5, -5, 5, 0, 0, 15, bus4, bus3);
dfl::algo::GeneratorDefinitionAlgorithm::Generators generators;
dfl::inputs::NetworkManager::BusMapRegulating busMap = {{bus1, dfl::inputs::NetworkManager::NbOfRegulating::ONE},
{bus2, dfl::inputs::NetworkManager::NbOfRegulating::ONE},
{bus3, dfl::inputs::NetworkManager::NbOfRegulating::ONE},
{bus4, dfl::inputs::NetworkManager::NbOfRegulating::MULTIPLES}};
std::vector<boost::filesystem::path> emptyPathList;
dfl::inputs::DynamicDataBaseManager manager(emptyPathList, std::vector<boost::filesystem::path>(1, "res/assembling_test_generator.xml"));
dfl::algo::GeneratorDefinitionAlgorithm algo_infinite(generators, busMap, manager, true, 10.);
std::shared_ptr<dfl::algo::AlgorithmsResults> algoRes(new dfl::algo::AlgorithmsResults());
for (const auto &node : nodes) {
algo_infinite(node, algoRes);
}

ASSERT_EQ(5, generators.size());
ASSERT_TRUE(algoRes->isAtLeastOneGeneratorRegulating);
for (size_t index = 0; index < generators.size(); ++index) {
generatorsEquals(expected_gens_infinite[index], generators[index]);
ASSERT_EQ(expected_gens_infinite[index].targetP, generators[index].targetP);
}

generators.clear();
dfl::algo::GeneratorDefinitionAlgorithm algo_finite(generators, busMap, manager, false, 10.);

for (const auto &node : nodes) {
algo_finite(node, algoRes);
}

ASSERT_EQ(5, generators.size());
ASSERT_TRUE(algoRes->isAtLeastOneGeneratorRegulating);
for (size_t index = 0; index < generators.size(); ++index) {
generatorsEquals(expected_gens_finite[index], generators[index]);
ASSERT_EQ(expected_gens_finite[index].targetP, generators[index].targetP);
}
}

TEST(Generators, generatorWithTfo) {
auto vl = std::make_shared<dfl::inputs::VoltageLevel>("VL");
auto vl2 = std::make_shared<dfl::inputs::VoltageLevel>("VL2");
Expand Down
Loading