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

[WIP] Proposal for "M" type topologies #50

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
5 changes: 4 additions & 1 deletion src/dgcv/core/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,12 @@ def __init__(
validation_pcs, "model_bess_validation_pcs", "model/BESS"
)

# TODO: (M-topologies) Its necessary to add a Zone1 PCS by DYD file in the producer path
self._validation_pcs = validation_pcs

# Prepare the environment to execute the tool
# TODO: (M-topologies) Repeated PCS must distinguish which is their model using the
# DYD file name
pcs_list = [Pcs(pcs_name, parameters) for pcs_name in self._validation_pcs]
self._pcs_list = sorted(pcs_list, key=attrgetter("_id", "_zone"))

Expand Down Expand Up @@ -166,7 +169,7 @@ def __initialize_working_environment(self) -> None:

def __create_report(self, summary_list: list, report_results: dict) -> None:
"""Create the full report."""
sorted_summary_list = sorted(summary_list, key=attrgetter("id", "zone"))
sorted_summary_list = sorted(summary_list, key=attrgetter("producer_file", "id", "zone"))
dgcv_logging.get_logger("Validation").debug(f"Sorted summary {sorted_summary_list}")
try:
report.create_pdf(
Expand Down
1 change: 1 addition & 0 deletions src/dgcv/curves/importer/curves.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ def __obtain_files_curve(
is_reference: bool = False,
):
# Copy base case and producers file
# TODO: In Zone1 copy the curves file for the current model
success = manage_files.copy_base_curves_files(
curves, working_oc_dir, get_cfg_oc_name(pcs_bm_name, oc_name)
)
Expand Down
16 changes: 16 additions & 0 deletions src/dgcv/dynawo/curves.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ def _obtain_gen_value(self, gen: Gen_params, value_definition: str) -> float:
return 0.0

def __adjust_event_value(self, event_params: dict) -> None:
# TODO: (M-topologies) Adjust Uref value by generator
generator = self.get_producer().generators[0]
event_params["pre_value"] = self._gens[0].U0 + generator.VoltageDrop * self._gens[0].Q0

Expand Down Expand Up @@ -309,6 +310,17 @@ def __complete_model(
self.get_producer().generators,
)

# TODO: (M-topologies) Create a Setpoint model by generator, with their connections
# and parameters.
# tso_file.complete_setpoint(
# working_oc_dir,
# "TSOModel.dyd",
# "TSOModel.par",
# self.get_producer().generators,
# config.get_value(pcs_bm_name, "TSO_model"),
# event_params["connect_to"],
# )

xmfrs = self.get_producer().stepup_xfmrs.copy()
if self.get_producer().auxload_xfmr:
xmfrs.append(self.get_producer().auxload_xfmr)
Expand Down Expand Up @@ -345,6 +357,10 @@ def __get_event_parameters(

connect_event_to = config.get_value(config_section, "connect_event_to")
self.__log(f"\t{connect_event_to=}")
# TODO: (M-topologies) Event values depends of the test type
# * for reference tracking tests the tool needs an event by generator
# (Save in Gen_Params object? Refactor to a new class?)
# * for others tests only one global event is needed.
pre_value = 1.0
if connect_event_to:
if "ActivePowerSetpointPu" == connect_event_to:
Expand Down
1 change: 1 addition & 0 deletions src/dgcv/files/producer_curves.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ def _get_model_templates(
):
xfmrs = _get_xmfrs_models(model_path, "Zone3")
z3_gen_ppms = _get_generator_models(model_path, template, "Zone3")
# TODO: (M-topologies) Copy the zone1 curves files by each zone1 model and modify them
z1_gen_ppms = _get_generator_models(model_path, template, "Zone1")

producer_curves_txt = _get_model_file_template()
Expand Down
3 changes: 3 additions & 0 deletions src/dgcv/files/producer_dyd_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,9 @@ def create_producer_dyd_file(
validation_type = VALIDATION_PPM
if template == "model_BESS":
validation_type = VALIDATION_BESS
# TODO: (M-topologies) First create the DYD file for Zone3
# TODO: (M-topologies) Then create a DYD file for Zone1 by generator in the DYD
# file of Zone3
_create_producer_dyd_file(target / "Zone1", "S", validation_type)
_create_producer_dyd_file(target / "Zone3", topology, validation_type)

Expand Down
2 changes: 2 additions & 0 deletions src/dgcv/files/producer_par_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ def create_producer_par_file(
* 'model_BESS' if it is model validation for Storage Model
"""
if template.startswith("model"):
# TODO: (M-topologies) First create the PAR file for Zone3
# TODO: (M-topologies) Then create a PAR file for Zone1 by DYD file of Zone1
_create_producer_par_file(launcher_dwo, target / "Zone1")
_create_producer_par_file(launcher_dwo, target / "Zone3")
else:
Expand Down
135 changes: 135 additions & 0 deletions src/dgcv/files/tso_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# (c) 2023/24 RTE
# Developed by Grupo AIA
# marinjl@aia.es
# omsg@aia.es
# demiguelm@aia.es
#

from pathlib import Path

from lxml import etree

from dgcv.dynawo.translator import dynawo_translator
from dgcv.model.parameters import Gen_params


def _connect_generator_to_setpoint(
dyd_root: etree.Element, ns: str, tso_model: str, generator: Gen_params, connect_to: str
) -> None:
if tso_model == "RefTracking_1Line_InfBus":
setpoint_id = f"SetPoint_{generator.id}"
_create_model(dyd_root, ns, setpoint_id, "Step", "TSOModel.par", setpoint_id)
connect_event_to = dynawo_translator.get_dynawo_variable(generator.lib, connect_to)
_connect_generator(
dyd_root, ns, generator.id, connect_event_to, setpoint_id, "step_step_value"
)


def _create_model(
dyd_root: etree.Element, ns: str, id: str, lib: str, par_file: str, par_id: str
) -> None:

dyd_root.append(
etree.Element(
f"{{{ns}}}blackBoxModel",
id=f"{id}",
lib=f"{lib}",
parFile=f"{par_file}",
parId=f"{par_id}",
)
)


def _connect_generator(
dyd_root: etree.Element, ns: str, id1: str, var1: str, id2: str, var2: str
) -> None:

dyd_root.append(
etree.Element(
f"{{{ns}}}connect",
id1=f"{id1}",
var1=f"{var1}",
id2=f"{id2}",
var2=f"{var2}",
)
)


def _add_setpoint_parameters(
par_root: etree.Element, ns: str, tso_model: str, generator: Gen_params
) -> None:
if tso_model == "RefTracking_1Line_InfBus":
parset = par_root.append(
etree.Element(
f"{{{ns}}}set",
id=f"SetPoint_{generator.id}",
)
)
parset.append(
etree.Element(
f"{{{ns}}}par",
type="DOUBLE",
name="step_tStep",
value=f"{generator.step_time}",
)
)
parset.append(
etree.Element(
f"{{{ns}}}par",
type="DOUBLE",
name="step_Value0",
value=f"{generator.step_value0}",
)
)
parset.append(
etree.Element(
f"{{{ns}}}par",
type="DOUBLE",
name="step_Height",
value=f"{generator.step_height}",
)
)


def complete_setpoint(
path: Path,
dyd_file: str,
par_file: str,
generators: list,
tso_model: str,
connect_to: str,
) -> None:
"""Replace DYD/PAR TSOModel files placeholders with values.

Parameters
----------
path: Path
Path where the omega files are stored
dyd_file: str
DYD filename
par_file: str
PAR filename
generators: list
Variable where the step is connected
tso_model: str
TSO Model library name
connect_to: str
Connect to variable
"""
dyd_tree = etree.parse(path / dyd_file, etree.XMLParser(remove_blank_text=True))
dyd_root = dyd_tree.getroot()
dyd_ns = etree.QName(dyd_root).namespace

par_tree = etree.parse(path / par_file, etree.XMLParser(remove_blank_text=True))
par_root = par_tree.getroot()
par_ns = etree.QName(dyd_root).namespace

for generator in generators:
_connect_generator_to_setpoint(dyd_root, dyd_ns, tso_model, generator, connect_to)
_add_setpoint_parameters(par_root, par_ns, tso_model, generator)

par_tree.write(path / par_file, pretty_print=True)
dyd_tree.write(path / dyd_file, pretty_print=True)
18 changes: 17 additions & 1 deletion src/dgcv/model/benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,16 @@

Summary = namedtuple(
"Summary",
["id", "zone", "pcs", "benchmark", "operating_condition", "compliance", "report_name"],
[
"producer_file",
"id",
"zone",
"pcs",
"benchmark",
"operating_condition",
"compliance",
"report_name",
],
)


Expand Down Expand Up @@ -585,8 +594,15 @@ def validate(
results = {"compliance": False, "curves": None}

results["summary"] = compliance
if self._parameters.get_producer().is_dynawo_model():
producer_file = self._parameters.get_producer().get_producer_dyd().name
else:
producer_file = self._parameters.get_producer().get_producer_curves_path().name

results["producer"] = producer_file
summary_list.append(
Summary(
producer_file,
int(self._pcs_id),
int(self._pcs_zone),
self._pcs_name,
Expand Down
2 changes: 2 additions & 0 deletions src/dgcv/model/pcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ def __init__(self, pcs_name: str, parameters: Parameters):
self._has_pcs_config = False
self._has_user_config = False

# TODO: (M-topologies) New variable to save the current Zone1 DYD file
# (Its an input parameter)
report_name, bms_by_pcs, pcs_id, pcs_zone = self.__prepare_pcs_config(
parameters.get_producer()
)
Expand Down
43 changes: 43 additions & 0 deletions src/dgcv/model/producer.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,49 @@ def __init__(
self._is_user_curves = self._producer_curves_path is not None
self._has_reference_curves_path = self._reference_curves_path is not None

# TODO: (M-topologies) Check if the Zone3 has only a DYD file
# TODO: (M-topologies) Check the number of DYD files in Zone1 is equal to the number
# of generators in Zone3
# TODO: (M-topologies) Check that each DYD file has a PAR file and an INI file with
# the same name
# TODO: (M-topologies) Need 2 new variables, the number of DYD files in Zone1 and
# the current DYD file
# Expected input example:
# Dynawo
# ├─── Zone3
# │ ├─── Producer.dyd
# │ ├─── Producer.par
# │ └─── Producer.ini
# └─── Zone1
# ├─── Producer_G1.dyd
# ├─── Producer_G1.par
# ├─── Producer_G1.ini
# ├─── Producer_G2.dyd
# ├─── Producer_G2.par
# └─── Producer_G2.ini

# TODO: (M-topologies) Check that we only have one set of curves for each test in
# Zone3 at most
# TODO: (M-topologies) Check that we only have one set of curves for each Zone1 test and
# DYD file at most
# TODO: (M-topologies) By default the tool will search for the curve using a compound name:
# PCS.benchmark.OC.DYDfilename
# TODO: (M-topologies) As a second option, it will search for the compound name:
# PCS.benchmark.OC
# TODO: (M-topologies) This logic is only used if the user does not inform the file name
# specifically.
# Expected input example:
# ReferenceCurves
# ├── CurvesFiles.ini
# ...
# ├── PCS_RTE-I16z1.SetPointStep.Voltage.Producer_G1.csv
# ├── PCS_RTE-I16z1.SetPointStep.Voltage.Producer_G1.dict
# ├── PCS_RTE-I16z1.SetPointStep.Voltage.Producer_G2.csv
# ├── PCS_RTE-I16z1.SetPointStep.Voltage.Producer_G2.dict
# ...
# ├── PCS_RTE-I16z3.PSetPointStep.Dec40.csv
# ├── PCS_RTE-I16z3.PSetPointStep.Dec40.dict
# ...
if verification_type == ELECTRIC_PERFORMANCE:
self.__set_electric_performance_type()
elif verification_type == MODEL_VALIDATION:
Expand Down
11 changes: 8 additions & 3 deletions src/dgcv/report/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ def _pcs_replace(
time_error_map = characteristics_response.create_map(oc_results)
active_power_recovery_map = active_power_recovery.create_map(oc_results)

subst_dict = subst_dict | {"producer": oc_results["producer"]}
subst_dict = subst_dict | {"solver" + operating_condition_: solver_map}
subst_dict = subst_dict | {"rm" + operating_condition_: results_map}
subst_dict = subst_dict | {"cm" + operating_condition_: compliance_map}
Expand All @@ -164,6 +165,7 @@ def _pcs_replace(
* 100
}

# TODO: (M-topologies) Identify the producer files used in each test
oc_report_name = config.get_value(operating_condition, "report_name")
if oc_report_name is not None:
# Process only "Compliant" and "Non-compliant" results;
Expand Down Expand Up @@ -363,13 +365,16 @@ def _summary_log(

header_txt += (
"\n\n"
"Pcs Benchmark Operating Condition Overall Result\n"
"-----------------------------------------------------------------------------\n"
"Producer Pcs Benchmark "
"Operating Condition Overall Result\n"
"----------------------------------------------------------"
"---------------------------------------\n"
)
body_txt = ""
for i in summary_list:
body_txt += (
f"{i.pcs:13}{i.benchmark:25}{i.operating_condition:25}{i.compliance.to_str()}\n"
f"{i.producer_file:20}{i.pcs:13}{i.benchmark:25}"
f"{i.operating_condition:25}{i.compliance.to_str()}\n"
)
body_txt += "\n"
# Show the summary report on the console and save it to file
Expand Down
1 change: 1 addition & 0 deletions src/dgcv/report/tables/summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def create_map(summary_list: list) -> list:
for i in summary_list:
summary_map.append(
[
f"{i.producer_file}".replace("_", "\_").strip(),
f"{i.pcs}".replace("_", "\_").strip(),
f"{i.benchmark}".strip(),
f"{i.operating_condition}".strip(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
%% The document starts here
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Model Validation - Results for PCS RTE-I16 Zone 1}
\section{Model Validation - Results for PCS RTE-I16 Zone 1 ({{producer}})}

\BLOCK{for subReport in subReports}
{{subReport}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
%% The document starts here
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Model Validation - Results for PCS RTE-I16 Zone 1}
\section{Model Validation - Results for PCS RTE-I16 Zone 1 ({{producer}})}

\BLOCK{for subReport in subReports}
{{subReport}}
Expand Down