From 662735c6964fc921f2ee582429c277f174001404 Mon Sep 17 00:00:00 2001 From: Daniel Thom Date: Fri, 1 Jul 2022 12:52:38 -0600 Subject: [PATCH] Add early checking of cost database and catalog --- disco/cli/upgrade_cost_analysis.py | 2 +- .../upgrades/cost_computation.py | 22 +- ...grade_cost_analysis_generic_input_model.py | 275 ++++++++++-------- 3 files changed, 156 insertions(+), 143 deletions(-) diff --git a/disco/cli/upgrade_cost_analysis.py b/disco/cli/upgrade_cost_analysis.py index 973c43f5..5d82618f 100644 --- a/disco/cli/upgrade_cost_analysis.py +++ b/disco/cli/upgrade_cost_analysis.py @@ -23,7 +23,7 @@ from disco.exceptions import DiscoBaseException, get_error_code_from_exception from disco.models.base import OpenDssDeploymentModel from disco.models.upgrade_cost_analysis_generic_input_model import ( - UpgradeCostAnalysisSimulationModel, + UpgradeCostAnalysisSimulationModel ) from disco.models.upgrade_cost_analysis_generic_output_model import ( UpgradeViolationResultModel, diff --git a/disco/extensions/upgrade_simulation/upgrades/cost_computation.py b/disco/extensions/upgrade_simulation/upgrades/cost_computation.py index 2cf1fca4..5e0bd57a 100644 --- a/disco/extensions/upgrade_simulation/upgrades/cost_computation.py +++ b/disco/extensions/upgrade_simulation/upgrades/cost_computation.py @@ -7,7 +7,7 @@ from .common_functions import create_overall_output_file from disco import timer_stats_collector -from disco.models.upgrade_cost_analysis_generic_input_model import UpgradeCostDatabaseModel +from disco.models.upgrade_cost_analysis_generic_input_model import load_cost_database from disco.models.upgrade_cost_analysis_generic_output_model import AllUpgradesTechnicalResultModel, \ AllEquipmentUpgradeCostsResultModel, EquipmentTypeUpgradeCostsResultModel, CapacitorControllerResultType, \ VoltageRegulatorResultType, TotalUpgradeCostsResultModel, AllUpgradesCostResultSummaryModel @@ -46,19 +46,13 @@ def compute_all_costs( line_upgrades_df = pd.DataFrame(m.dict(by_alias=True)["line"]) voltage_upgrades_df = pd.DataFrame(m.dict(by_alias=True)["voltage"]) - # unit cost database files - xfmr_cost_database = pd.read_excel(cost_database_filepath, "transformers") - line_cost_database = pd.read_excel(cost_database_filepath, "lines") - controls_cost_database = pd.read_excel(cost_database_filepath, "control_changes") - voltage_regulators_cost_database = pd.read_excel(cost_database_filepath, "voltage_regulators") - misc_database = pd.read_excel(cost_database_filepath, "misc") - - # perform validation of input cost database using pydantic models - input_cost_model = UpgradeCostDatabaseModel(transformers=xfmr_cost_database.to_dict(orient="records"), - lines=line_cost_database.to_dict(orient="records"), - control_changes=controls_cost_database.to_dict(orient="records"), - voltage_regulators=voltage_regulators_cost_database.to_dict(orient="records"), - misc=misc_database.to_dict(orient="records")) + ( + xfmr_cost_database, + line_cost_database, + controls_cost_database, + voltage_regulators_cost_database, + misc_database, + ) = load_cost_database(cost_database_filepath) output_columns = list(EquipmentTypeUpgradeCostsResultModel.schema(True).get("properties").keys()) # reformat data diff --git a/disco/models/upgrade_cost_analysis_generic_input_model.py b/disco/models/upgrade_cost_analysis_generic_input_model.py index ef1f67a6..272f4493 100644 --- a/disco/models/upgrade_cost_analysis_generic_input_model.py +++ b/disco/models/upgrade_cost_analysis_generic_input_model.py @@ -1,7 +1,8 @@ -import enum from typing import List, Optional, Set, Dict from pydantic import BaseModel, Field, root_validator, validator +import pandas as pd + from PyDSS.controllers import PvControllerModel from disco.models.base import BaseAnalysisModel @@ -31,6 +32,126 @@ def get_default_voltage_upgrade_params(): return _get_default_upgrade_params()["voltage_upgrade_params"] +class OpenDSSLineModel(OpenDSSLineParams): + bus1: str = Field( + title="bus1", + description="bus1", + ) + bus2: str = Field( + title="bus2", + description="bus2", + ) + length: float = Field( + title="length", + description="length", + ) + enabled: Any = Field( + title="enabled", + description="enabled", + ) + + +class LineModel(OpenDSSLineModel, ExtraLineParams): + name: str = Field( + title="name", + description="name. This is not a direct OpenDSS object property.", + ) + + +class LineCatalogModel(OpenDSSLineParams, ExtraLineParams): + """Contains Line information needed for thermal upgrade analysis. Most fields can be directly obtained from the opendss models""" + name: str = Field( + title="name", + description="name. This is not a direct OpenDSS object property.", + ) + + +class LineCodeCatalogModel(CommonLineParameters): + """Contains LineCode information needed for thermal upgrade analysis. Most fields can be directly obtained from the opendss models""" + name: str = Field( + title="name", + description="name", + ) + nphases: int = Field( + title="nphases", + description="nphases", + determine_upgrade_option=True, + ) + Kron: Optional[Any] = Field( + title="Kron", + description="Kron", + default="N", + determine_upgrade_option=True, + ) + neutral: float = Field( + title="neutral", + description="neutral", + determine_upgrade_option=True, + ) + like: Optional[Any] = Field( + title="like", + description="like", + default=None, + ) + baseFreq: float = Field( + title="basefreq", + description="basefreq", + determine_upgrade_option=True, + ) + + +class OpenDSSTransformerModel(CommonTransformerParameters): + bus: str = Field( + title="bus", + description="bus", + ) + buses: Any = Field( + title="buses", + description="buses", + ) + enabled: Any = Field( + title="enabled", + description="enabled", + ) + + +class TransformerModel(OpenDSSTransformerModel, ExtraTransformerParams): + name: str = Field( + title="name", + description="name. This is not a direct OpenDSS object property.", + ) + + +class TransformerCatalogModel(CommonTransformerParameters, ExtraTransformerParams): + """Contains Transformer information needed for thermal upgrade analysis. Most fields can be directly obtained from the opendss models""" + name: str = Field( + title="name", + description="name", + ) +class UpgradeTechnicalCatalogModel(UpgradeParamsBaseModel): + """Contains Upgrades Technical Catalog needed for thermal upgrade analysis""" + line: Optional[List[LineCatalogModel]] = Field( + title="line", + description="line catalog", + default=[] + ) + transformer: Optional[List[TransformerCatalogModel]] = Field( + title="transformer", + description="transformer catalog", + default=[] + ) + linecode: Optional[List[LineCodeCatalogModel]] = Field( + title="linecode", + description="linecode catalog", + default=[] + ) + # TODO not implemented yet. Can be added if lines are defined through linegeometry + # geometry: Optional[List[LineGeometryCatalogModel]] = Field( + # title="linegeometry", + # description="linegeometry catalog", + # default=[] + # ) + class ThermalUpgradeParamsModel(UpgradeParamsBaseModel): """Thermal Upgrade Parameters for all jobs in a simulation""" @@ -98,8 +219,11 @@ def check_voltage_lower_limits(cls, voltage_lower_limit, values): @validator("external_catalog") def check_catalog(cls, external_catalog, values): - if values["read_external_catalog"] and not Path(external_catalog).exists(): - raise ValueError(f"{external_catalog} does not exist") + if values["read_external_catalog"]: + if not Path(external_catalog).exists(): + raise ValueError(f"{external_catalog} does not exist") + # Just verify that it constructs the model. + UpgradeTechnicalCatalogModel(**load_data(external_catalog)) return external_catalog @validator("timepoint_multipliers") @@ -302,6 +426,8 @@ def check_database(cls, calculate_costs, values): if calculate_costs: if not Path(values["upgrade_cost_database"]).exists(): raise ValueError(f"{values['upgrade_cost_database']} does not exist") + # Just verify that it constructs the model. + load_cost_database(values["upgrade_cost_database"]) return calculate_costs @validator("upgrade_order") @@ -524,130 +650,23 @@ class UpgradeCostDatabaseModel(UpgradeParamsBaseModel): ) -class upgrade_cost_types(enum.Enum): - """Possible values for upgrade costs""" - TRANSFORMER = "Transformer" - LINE = "Line" - - -class OpenDSSLineModel(OpenDSSLineParams): - bus1: str = Field( - title="bus1", - description="bus1", - ) - bus2: str = Field( - title="bus2", - description="bus2", - ) - length: float = Field( - title="length", - description="length", - ) - enabled: Any = Field( - title="enabled", - description="enabled", - ) - - -class LineModel(OpenDSSLineModel, ExtraLineParams): - name: str = Field( - title="name", - description="name. This is not a direct OpenDSS object property.", - ) - - -class LineCatalogModel(OpenDSSLineParams, ExtraLineParams): - """Contains Line information needed for thermal upgrade analysis. Most fields can be directly obtained from the opendss models""" - name: str = Field( - title="name", - description="name. This is not a direct OpenDSS object property.", - ) +def load_cost_database(filepath): + xfmr_cost_database = pd.read_excel(filepath, "transformers") + line_cost_database = pd.read_excel(filepath, "lines") + controls_cost_database = pd.read_excel(filepath, "control_changes") + voltage_regulators_cost_database = pd.read_excel(filepath, "voltage_regulators") + misc_database = pd.read_excel(filepath, "misc") - -class LineCodeCatalogModel(CommonLineParameters): - """Contains LineCode information needed for thermal upgrade analysis. Most fields can be directly obtained from the opendss models""" - name: str = Field( - title="name", - description="name", - ) - nphases: int = Field( - title="nphases", - description="nphases", - determine_upgrade_option=True, + # perform validation of input cost database using pydantic models + input_cost_model = UpgradeCostDatabaseModel(transformers=xfmr_cost_database.to_dict(orient="records"), + lines=line_cost_database.to_dict(orient="records"), + control_changes=controls_cost_database.to_dict(orient="records"), + voltage_regulators=voltage_regulators_cost_database.to_dict(orient="records"), + misc=misc_database.to_dict(orient="records")) + return ( + xfmr_cost_database, + line_cost_database, + controls_cost_database, + voltage_regulators_cost_database, + misc_database, ) - Kron: Optional[Any] = Field( - title="Kron", - description="Kron", - default="N", - determine_upgrade_option=True, - ) - neutral: float = Field( - title="neutral", - description="neutral", - determine_upgrade_option=True, - ) - like: Optional[Any] = Field( - title="like", - description="like", - default=None, - ) - baseFreq: float = Field( - title="basefreq", - description="basefreq", - determine_upgrade_option=True, - ) - - -class OpenDSSTransformerModel(CommonTransformerParameters): - bus: str = Field( - title="bus", - description="bus", - ) - buses: Any = Field( - title="buses", - description="buses", - ) - enabled: Any = Field( - title="enabled", - description="enabled", - ) - - -class TransformerModel(OpenDSSTransformerModel, ExtraTransformerParams): - name: str = Field( - title="name", - description="name. This is not a direct OpenDSS object property.", - ) - - -class TransformerCatalogModel(CommonTransformerParameters, ExtraTransformerParams): - """Contains Transformer information needed for thermal upgrade analysis. Most fields can be directly obtained from the opendss models""" - name: str = Field( - title="name", - description="name", - ) - - -class UpgradeTechnicalCatalogModel(UpgradeParamsBaseModel): - """Contains Upgrades Technical Catalog needed for thermal upgrade analysis""" - line: Optional[List[LineCatalogModel]] = Field( - title="line", - description="line catalog", - default=[] - ) - transformer: Optional[List[TransformerCatalogModel]] = Field( - title="transformer", - description="transformer catalog", - default=[] - ) - linecode: Optional[List[LineCodeCatalogModel]] = Field( - title="linecode", - description="linecode catalog", - default=[] - ) - # TODO not implemented yet. Can be added if lines are defined through linegeometry - # geometry: Optional[List[LineGeometryCatalogModel]] = Field( - # title="linegeometry", - # description="linegeometry catalog", - # default=[] - # ) \ No newline at end of file