Commit b886d1a3 authored by Eric Duminil's avatar Eric Duminil
Browse files

Reading and testing LoadProfile too

parent 116ddee4
...@@ -2,6 +2,7 @@ from simstadtpy.results import ( ...@@ -2,6 +2,7 @@ from simstadtpy.results import (
GreenWaterResults, GreenWaterResults,
HeatDemandResults, HeatDemandResults,
KPI, KPI,
LoadProfileResults,
PhotovoltaicResults, PhotovoltaicResults,
SimStadtResults, SimStadtResults,
create_simstadt_results, create_simstadt_results,
...@@ -13,6 +14,7 @@ __all__ = [ ...@@ -13,6 +14,7 @@ __all__ = [
"KPI", "KPI",
"SimStadtResults", "SimStadtResults",
"HeatDemandResults", "HeatDemandResults",
"LoadProfileResults",
"PhotovoltaicResults", "PhotovoltaicResults",
"GreenWaterResults", "GreenWaterResults",
"create_simstadt_results", "create_simstadt_results",
......
...@@ -64,6 +64,9 @@ class Providers(str, Enum): ...@@ -64,6 +64,9 @@ class Providers(str, Enum):
HEAT_DEMAND_WITH_REFURBISHMENT = ( HEAT_DEMAND_WITH_REFURBISHMENT = (
"de.hftstuttgart.simstadtworkflows.energy.HeatDemandAnalysisWithRefurbishmentStrategyWorkflowProvider" "de.hftstuttgart.simstadtworkflows.energy.HeatDemandAnalysisWithRefurbishmentStrategyWorkflowProvider"
) )
HEAT_DEMAND_WITH_HISTORIC_REFURBISHMENT = (
"de.hftstuttgart.simstadtworkflows.energy.HeatDemandAnalysisWithHistoricAndFutureRefurbishmentWorkflowProvider"
)
HEAT_DEMAND_WITH_SHADOW = ( HEAT_DEMAND_WITH_SHADOW = (
"de.hftstuttgart.simstadtworkflows.shadow.HeatDemandCalculationWithShadowProcessingProvider" "de.hftstuttgart.simstadtworkflows.shadow.HeatDemandCalculationWithShadowProcessingProvider"
) )
...@@ -73,6 +76,7 @@ class Providers(str, Enum): ...@@ -73,6 +76,7 @@ class Providers(str, Enum):
"de.hftstuttgart.simstadtworkflows.economics.PhotovoltaicPotentialFinancialAnalysisWorkflowProvider" "de.hftstuttgart.simstadtworkflows.economics.PhotovoltaicPotentialFinancialAnalysisWorkflowProvider"
) )
GREEN_WATER = "de.hftstuttgart.simstadtworkflows.greenwater.GreenWaterWorkflowProvider" GREEN_WATER = "de.hftstuttgart.simstadtworkflows.greenwater.GreenWaterWorkflowProvider"
LOAD_PROFILE = "de.hftstuttgart.simstadtworkflows.energy.LoadProfileProvider"
def detect_decimal(csv_path: Path, line_number: int, check: str = "") -> str: def detect_decimal(csv_path: Path, line_number: int, check: str = "") -> str:
...@@ -315,6 +319,7 @@ class HeatDemandResults(SimStadtResults): ...@@ -315,6 +319,7 @@ class HeatDemandResults(SimStadtResults):
Providers.HEAT_DEMAND, Providers.HEAT_DEMAND,
Providers.HEAT_DEMAND_WITH_SHADOW, Providers.HEAT_DEMAND_WITH_SHADOW,
Providers.HEAT_DEMAND_WITH_REFURBISHMENT, Providers.HEAT_DEMAND_WITH_REFURBISHMENT,
Providers.HEAT_DEMAND_WITH_HISTORIC_REFURBISHMENT,
] ]
csv_identifier = "DIN18599" csv_identifier = "DIN18599"
...@@ -424,6 +429,36 @@ class PhotovoltaicResults(SimStadtResults): ...@@ -424,6 +429,36 @@ class PhotovoltaicResults(SimStadtResults):
return self._prepare_kpis(sums, averages) return self._prepare_kpis(sums, averages)
@dataclass(repr=False)
class LoadProfileResults(SimStadtResults):
"""Results for LoadProfile workflows.
The dataframe has one column per building (building GML ID as column name)
and 8760 rows of hourly energy demand [kWh/h].
"""
supported_providers: ClassVar[list[str]] = [Providers.LOAD_PROFILE]
csv_identifier = "_load_profile_Hourly"
def _parse_results(self) -> pd.DataFrame:
csv_decimal = detect_decimal(self.csv_path, 6, "Area")
df = pd.read_csv(self.csv_path, skiprows=range(1, 12), sep=";", decimal=csv_decimal)
# First column is the timestamp; remaining columns are per-building loads
return df.drop(columns=[df.columns[0]])
@property
def kpis(self) -> list[KPI]:
# TODO: Add sum, average. Add timestep too?
# TODO: Add people? Add total heated area?
df = self.dataframe
total = df.sum().sum()
return [
KPI("Number of buildings", df.shape[1], precision=0),
KPI("Total load", total, "kWh/a", precision=1),
KPI("Average load", total / 8760, "kWh/h", precision=1),
]
@dataclass(repr=False) @dataclass(repr=False)
class GreenWaterResults(SimStadtResults): class GreenWaterResults(SimStadtResults):
"""Results for GreenWater workflows (hourly time series with tree species breakdown).""" """Results for GreenWater workflows (hourly time series with tree species breakdown)."""
......
<?xml version="1.0" encoding="UTF-8"?>
<java version="17.0.14" class="java.beans.XMLDecoder">
<object class="eu.simstadt.citygml.steps.ImportCityGml" id="ImportCityGml0">
<void class="de.hftstuttgart.hierarchicworkflow.WorkflowStep" method="getField">
<string>startStep</string>
<void method="set">
<object idref="ImportCityGml0"/>
<boolean>true</boolean>
</void>
</void>
<void class="de.hftstuttgart.hierarchicworkflow.WorkflowStep" method="getField">
<string>selectedNextStepPath</string>
<void method="set">
<object idref="ImportCityGml0"/>
<string>01_Preprocessing.step</string>
</void>
</void>
<void property="name">
<string>Base</string>
</void>
</object>
</java>
<?xml version="1.0" encoding="UTF-8"?>
<java version="17.0.14" class="java.beans.XMLDecoder">
<object class="eu.simstadt.workflowsteps.GeometricPreprocessorStep" id="GeometricPreprocessorStep0">
<void class="de.hftstuttgart.hierarchicworkflow.WorkflowStep" method="getField">
<string>startStep</string>
<void method="set">
<object idref="GeometricPreprocessorStep0"/>
<boolean>true</boolean>
</void>
</void>
<void class="de.hftstuttgart.hierarchicworkflow.WorkflowStep" method="getField">
<string>selectedNextStepPath</string>
<void method="set">
<object idref="GeometricPreprocessorStep0"/>
<string>01_GeometricEstimator.step</string>
</void>
</void>
<void property="name">
<string>Base</string>
</void>
</object>
</java>
<?xml version="1.0" encoding="UTF-8"?>
<java version="17.0.14" class="java.beans.XMLDecoder">
<object class="eu.simstadt.workflowsteps.GeometricEstimatorStep" id="GeometricEstimatorStep0">
<void class="de.hftstuttgart.hierarchicworkflow.WorkflowStep" method="getField">
<string>selectedNextStepPath</string>
<void method="set">
<object idref="GeometricEstimatorStep0"/>
<string>02_PhysicsPreprocessor.step</string>
</void>
</void>
<void property="name">
<string>Base</string>
</void>
</object>
</java>
<?xml version="1.0" encoding="UTF-8"?>
<java version="17.0.14" class="java.beans.XMLDecoder">
<object class="eu.simstadt.workflowsteps.PhysicsPreprocessorStep" id="PhysicsPreprocessorStep0">
<void class="de.hftstuttgart.hierarchicworkflow.WorkflowStep" method="getField">
<string>selectedNextStepPath</string>
<void method="set">
<object idref="PhysicsPreprocessorStep0"/>
<string>03_UsagePreprocessor.step</string>
</void>
</void>
<void property="name">
<string>Base</string>
</void>
</object>
</java>
<?xml version="1.0" encoding="UTF-8"?>
<java version="17.0.14" class="java.beans.XMLDecoder">
<object class="eu.simstadt.workflowsteps.UsagePreprocessorStep">
<void property="name">
<string>Base</string>
</void>
</object>
</java>
<?xml version="1.0" encoding="UTF-8"?>
<java version="17.0.14" class="java.beans.XMLDecoder">
<object class="eu.simstadt.workflowsteps.Preprocessing" id="Preprocessing0">
<void class="de.hftstuttgart.hierarchicworkflow.Workflow" method="getField">
<string>selectedStartStepPath</string>
<void method="set">
<object idref="Preprocessing0"/>
<string>00_GeometricPreprocessor.step</string>
</void>
</void>
<void class="de.hftstuttgart.hierarchicworkflow.WorkflowStep" method="getField">
<string>selectedNextStepPath</string>
<void method="set">
<object idref="Preprocessing0"/>
<string>02_LoadProfileGenerator.step</string>
</void>
</void>
<void property="name">
<string>Base</string>
</void>
</object>
</java>
======================== Summary ========================
Excluded 3 buildings from processing (Reason: Usagezone: garage has no standard load profile)
Excluded 1 buildings from processing (Reason: Could not create usage zones. SimStadtLibraryAccessException: 'Unknown function code: 51009_1610.')
================ Excluded buildings lists ===============
Excluded 3 buildings from processing (Reason: Usagezone: garage has no standard load profile)
# GML ID [-];Zone Number [-];Volume [m3];Footprint area [m2];X [m];Y [m]
DEBW_52210003uuj;0;127.08;37.73;515329.080000;5402144.630000
DEBW_52210004dHR;0;80.85;23.66;515313.045000;5402167.405000
DEBW_52210006Jqm;0;45.27;16.44;515362.825000;5402135.910000
Excluded 1 buildings from processing (Reason: Could not create usage zones. SimStadtLibraryAccessException: 'Unknown function code: 51009_1610.')
# GML ID [-];Zone Number [-];Volume [m3];Footprint area [m2];X [m];Y [m]
DEBW_5221000BwaG;0;25.75;6.88;515326.310000;5402146.910000
<?xml version="1.0" encoding="UTF-8"?>
<java version="17.0.14" class="java.beans.XMLDecoder">
<object class="de.hftstuttgart.simstadtworkflowsteps.energy.LoadProfileGeneratorStep">
<void property="name">
<string>Base</string>
</void>
</object>
</java>
<java version="17.0.14" class="java.beans.XMLDecoder">
<object class="eu.simstadt.workflows.CityGmlWorkflow" id="CityGmlWorkflow0">
<void class="de.hftstuttgart.hierarchicworkflow.Workflow" method="getField">
<string>selectedStartStepPath</string>
<void method="set">
<object idref="CityGmlWorkflow0" />
<string>00_ImportCityGml.step</string>
</void>
</void>
<void class="de.hftstuttgart.hierarchicworkflow.WorkflowStep" method="getField">
<string>startStep</string>
<void method="set">
<object idref="CityGmlWorkflow0" />
<boolean>true</boolean>
</void>
</void>
<void property="cityGmlFileNames">
</void>
<void property="name">
<string>LoadProfile_Template</string>
</void>
<void property="shortName">
<string>LoadProfile</string>
</void>
<void property="workflowProvider">
<object class="de.hftstuttgart.simstadtworkflows.energy.LoadProfileProvider" />
</void>
<void property="cityGmlFileNames"><void method="add"><string>MiniBuchwald.gml</string></void></void></object>
</java>
\ No newline at end of file
...@@ -9,6 +9,7 @@ from simstadtpy import ( ...@@ -9,6 +9,7 @@ from simstadtpy import (
GreenWaterResults, GreenWaterResults,
HeatDemandResults, HeatDemandResults,
KPI, KPI,
LoadProfileResults,
PhotovoltaicResults, PhotovoltaicResults,
SimStadtResults, SimStadtResults,
create_simstadt_results, create_simstadt_results,
...@@ -16,6 +17,7 @@ from simstadtpy import ( ...@@ -16,6 +17,7 @@ from simstadtpy import (
TEST_REPOSITORY = Path(__file__).parent / "data" / "TestRepo" TEST_REPOSITORY = Path(__file__).parent / "data" / "TestRepo"
TEST_PROJECT_PATH = TEST_REPOSITORY / "CGSC.proj" TEST_PROJECT_PATH = TEST_REPOSITORY / "CGSC.proj"
LOAD_PROFILE_FLOW = TEST_REPOSITORY / "SektorSim.proj" / "LoadProfile.flow"
def kpis_by_name(results: SimStadtResults) -> dict[str, KPI]: def kpis_by_name(results: SimStadtResults) -> dict[str, KPI]:
...@@ -35,7 +37,7 @@ def find_output_files(workflow_name: str) -> list[Path]: ...@@ -35,7 +37,7 @@ def find_output_files(workflow_name: str) -> list[Path]:
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def heat_results() -> SimStadtResults: def heating_results() -> SimStadtResults:
output_files = [ output_files = [
TEST_REPOSITORY / "CGSC.proj/101_HeatDemand.flow/02_WeatherProcessor.step/hourly_GHI_DHI_Ta_meteonorm_Wuerzburg.prn", TEST_REPOSITORY / "CGSC.proj/101_HeatDemand.flow/02_WeatherProcessor.step/hourly_GHI_DHI_Ta_meteonorm_Wuerzburg.prn",
TEST_REPOSITORY / "CGSC.proj/101_HeatDemand.flow/04_MonthlyEnergyBalance.step/Grombuehl_mini_Steinheilstrasse_DIN18599_HEATING.csv", TEST_REPOSITORY / "CGSC.proj/101_HeatDemand.flow/04_MonthlyEnergyBalance.step/Grombuehl_mini_Steinheilstrasse_DIN18599_HEATING.csv",
...@@ -44,33 +46,33 @@ def heat_results() -> SimStadtResults: ...@@ -44,33 +46,33 @@ def heat_results() -> SimStadtResults:
return create_simstadt_results("Heat demand simulation for Grombühl", output_files) return create_simstadt_results("Heat demand simulation for Grombühl", output_files)
def test_heat_result_type(heat_results): def test_heating_result_type(heating_results):
assert isinstance(heat_results, HeatDemandResults) assert isinstance(heating_results, HeatDemandResults)
def test_heat_output_files_exist(heat_results): def test_heating_output_files_exist(heating_results):
assert all(f.exists() for f in heat_results.output_files) assert all(f.exists() for f in heating_results.output_files)
def test_heat_csv_content(heat_results): def test_heating_csv_content(heating_results):
assert heat_results.csv_path.exists() assert heating_results.csv_path.exists()
assert b"DIN18599 Monthly Energy Balance" in heat_results.csv_content() assert b"DIN18599 Monthly Energy Balance" in heating_results.csv_content()
def test_heat_log_content(heat_results): def test_heating_log_content(heating_results):
assert len(heat_results.log_content()) > 0 assert len(heating_results.log_content()) > 0
def test_heat_zip_content(heat_results): def test_heating_zip_content(heating_results):
assert heat_results.zip_content()[:4] == b"PK\x03\x04" assert heating_results.zip_content()[:4] == b"PK\x03\x04"
def test_heat_diagrams(heat_results): def test_heating_diagrams(heating_results):
assert len(heat_results.diagrams) == 1 assert len(heating_results.diagrams) == 1
def test_heat_dataframe(heat_results): def test_heating_dataframe(heating_results):
df = heat_results.dataframe df = heating_results.dataframe
assert isinstance(df, pd.DataFrame) assert isinstance(df, pd.DataFrame)
assert len(df) > 0 assert len(df) > 0
assert "GMLId" in df assert "GMLId" in df
...@@ -79,8 +81,8 @@ def test_heat_dataframe(heat_results): ...@@ -79,8 +81,8 @@ def test_heat_dataframe(heat_results):
assert "has_flat_roof" in df assert "has_flat_roof" in df
def test_heat_kpis(heat_results): def test_heating_kpis(heating_results):
kpis = kpis_by_name(heat_results) kpis = kpis_by_name(heating_results)
assert "Heated area" in kpis assert "Heated area" in kpis
assert "Number of buildings" in kpis assert "Number of buildings" in kpis
assert kpis["Heated area"].value == pytest.approx(10557.2, abs=0.1) assert kpis["Heated area"].value == pytest.approx(10557.2, abs=0.1)
...@@ -88,47 +90,47 @@ def test_heat_kpis(heat_results): ...@@ -88,47 +90,47 @@ def test_heat_kpis(heat_results):
assert kpis["Heated area"].unit == "m²" assert kpis["Heated area"].unit == "m²"
assert kpis["Storey number"].value == pytest.approx(4, abs=0.5) assert kpis["Storey number"].value == pytest.approx(4, abs=0.5)
assert kpis["Year of construction"].value == pytest.approx(1963, abs=0.5) assert kpis["Year of construction"].value == pytest.approx(1963, abs=0.5)
assert heat_results.kpi("Number of buildings").value == 24 assert heating_results.kpi("Number of buildings").value == 24
assert heat_results.kpi("Specific Heating Demand").value == pytest.approx(100, abs=5) assert heating_results.kpi("Specific Heating Demand").value == pytest.approx(100, abs=5)
with pytest.raises(ValueError, match="No 'Not here' KPI found"): with pytest.raises(ValueError, match="No 'Not here' KPI found"):
heat_results.kpi("Not here") heating_results.kpi("Not here")
assert len(kpis) == 10 # heating only assert len(kpis) == 10 # heating only
def test_heat_more_info_empty(heat_results): def test_heating_more_info_empty(heating_results):
assert heat_results.more_info == {} assert heating_results.more_info == {}
def test_heat_project(heat_results): def test_heating_project(heating_results):
assert heat_results.project == "CGSC" assert heating_results.project == "CGSC"
def test_heat_repository(heat_results): def test_heating_repository(heating_results):
assert heat_results.repository.absolute() == TEST_REPOSITORY assert heating_results.repository.absolute() == TEST_REPOSITORY
def test_heat_params(heat_results): def test_heating_params(heating_results):
assert heat_results.short_name == "HeatDemand" assert heating_results.short_name == "HeatDemand"
assert heat_results.name == "CGSC_HeatDemand" assert heating_results.name == "CGSC_HeatDemand"
assert heat_results.workflow_provider == ( assert heating_results.workflow_provider == (
"de.hftstuttgart.simstadtworkflows.energy.HeatDemandAnalysisWorkflowProvider" "de.hftstuttgart.simstadtworkflows.energy.HeatDemandAnalysisWorkflowProvider"
) )
def test_heat_serialization(heat_results): def test_heating_serialization(heating_results):
json_str = heat_results.to_json() json_str = heating_results.to_json()
reconstructed = SimStadtResults.from_json(json_str) reconstructed = SimStadtResults.from_json(json_str)
assert isinstance(reconstructed, HeatDemandResults) assert isinstance(reconstructed, HeatDemandResults)
assert reconstructed.description == heat_results.description assert reconstructed.description == heating_results.description
assert len(reconstructed.output_files) == len(heat_results.output_files) assert len(reconstructed.output_files) == len(heating_results.output_files)
assert "Domestic hot water demand" in json_str assert "Domestic hot water demand" in json_str
assert len(reconstructed.kpis) > 0 assert len(reconstructed.kpis) > 0
assert isinstance(reconstructed.csv_path, Path) assert isinstance(reconstructed.csv_path, Path)
pd.testing.assert_frame_equal(reconstructed.dataframe, heat_results.dataframe) pd.testing.assert_frame_equal(reconstructed.dataframe, heating_results.dataframe)
def test_heat_repr(heat_results): def test_heating_repr(heating_results):
detailed = repr(heat_results) detailed = repr(heating_results)
assert "Grombuehl_mini_Steinheilstrasse.gml" in detailed assert "Grombuehl_mini_Steinheilstrasse.gml" in detailed
assert "Footprint area" in detailed assert "Footprint area" in detailed
assert "1963" in detailed assert "1963" in detailed
...@@ -146,11 +148,11 @@ def heat_cool_results() -> SimStadtResults: ...@@ -146,11 +148,11 @@ def heat_cool_results() -> SimStadtResults:
) )
def test_heat_cool_result_type(heat_cool_results): def test_heating_cool_result_type(heat_cool_results):
assert isinstance(heat_cool_results, HeatDemandResults) assert isinstance(heat_cool_results, HeatDemandResults)
def test_heat_cool_kpis(heat_cool_results): def test_heating_cool_kpis(heat_cool_results):
kpis = kpis_by_name(heat_cool_results) kpis = kpis_by_name(heat_cool_results)
assert "Yearly Heating demand" in kpis assert "Yearly Heating demand" in kpis
assert "Specific Heating Demand" in kpis assert "Specific Heating Demand" in kpis
...@@ -160,7 +162,7 @@ def test_heat_cool_kpis(heat_cool_results): ...@@ -160,7 +162,7 @@ def test_heat_cool_kpis(heat_cool_results):
assert len(kpis) == 12 assert len(kpis) == 12
def test_heat_cool_diagrams(heat_cool_results): def test_heating_cool_diagrams(heat_cool_results):
diagrams = heat_cool_results.diagrams diagrams = heat_cool_results.diagrams
assert len(diagrams) > 0 assert len(diagrams) > 0
assert "Monthly demands" in diagrams assert "Monthly demands" in diagrams
...@@ -200,7 +202,7 @@ def test_cooling_kpis(cooling_results): ...@@ -200,7 +202,7 @@ def test_cooling_kpis(cooling_results):
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def gw_results() -> SimStadtResults: def greenwater_results() -> SimStadtResults:
output_files = [ output_files = [
TEST_REPOSITORY / "CGSC.proj/102_GreenWater.flow/02_WeatherProcessor.step/hourly_GHI_DHI_Ta_meteonorm_Wuerzburg.prn", TEST_REPOSITORY / "CGSC.proj/102_GreenWater.flow/02_WeatherProcessor.step/hourly_GHI_DHI_Ta_meteonorm_Wuerzburg.prn",
TEST_REPOSITORY / "CGSC.proj/102_GreenWater.flow/03_GreenWater.step/Grombühl_mini_with_trees_greenwater.csv", TEST_REPOSITORY / "CGSC.proj/102_GreenWater.flow/03_GreenWater.step/Grombühl_mini_with_trees_greenwater.csv",
...@@ -208,28 +210,28 @@ def gw_results() -> SimStadtResults: ...@@ -208,28 +210,28 @@ def gw_results() -> SimStadtResults:
return create_simstadt_results("Green Water simulation for Grombühl", output_files) return create_simstadt_results("Green Water simulation for Grombühl", output_files)
def test_gw_result_type(gw_results): def test_greenwater_result_type(greenwater_results):
assert isinstance(gw_results, GreenWaterResults) assert isinstance(greenwater_results, GreenWaterResults)
def test_gw_output_files_exist(gw_results): def test_greenwater_output_files_exist(greenwater_results):
assert all(f.exists() for f in gw_results.output_files) assert all(f.exists() for f in greenwater_results.output_files)
def test_gw_csv_exists(gw_results): def test_greenwater_csv_exists(greenwater_results):
assert gw_results.csv_path.exists() assert greenwater_results.csv_path.exists()
def test_gw_diagrams(gw_results): def test_greenwater_diagrams(greenwater_results):
diagrams = gw_results.diagrams diagrams = greenwater_results.diagrams
assert len(diagrams) > 0 assert len(diagrams) > 0
assert "Rain and Irrigation" in diagrams assert "Rain and Irrigation" in diagrams
for diagram in diagrams.values(): for diagram in diagrams.values():
assert diagram.exists() assert diagram.exists()
def test_gw_dataframe(gw_results): def test_greenwater_dataframe(greenwater_results):
df = gw_results.dataframe df = greenwater_results.dataframe
assert isinstance(df, pd.DataFrame) assert isinstance(df, pd.DataFrame)
assert len(df) > 0 assert len(df) > 0
assert "Rain [mm]" in df assert "Rain [mm]" in df
...@@ -237,8 +239,8 @@ def test_gw_dataframe(gw_results): ...@@ -237,8 +239,8 @@ def test_gw_dataframe(gw_results):
assert "Average ETc [mm]" in df assert "Average ETc [mm]" in df
def test_gw_kpis(gw_results): def test_greenwater_kpis(greenwater_results):
kpis = kpis_by_name(gw_results) kpis = kpis_by_name(greenwater_results)
assert "Rain" in kpis assert "Rain" in kpis
assert "Irrigation" in kpis assert "Irrigation" in kpis
assert "Evaporative cooling" in kpis assert "Evaporative cooling" in kpis
...@@ -255,12 +257,12 @@ def test_gw_kpis(gw_results): ...@@ -255,12 +257,12 @@ def test_gw_kpis(gw_results):
assert kpis["Projected tree area"].unit == "m²" assert kpis["Projected tree area"].unit == "m²"
def test_gw_attrs(gw_results): def test_greenwater_attrs(greenwater_results):
assert "Tilia cordata" in gw_results.dataframe.attrs["species"] assert "Tilia cordata" in greenwater_results.dataframe.attrs["species"]
def test_gw_more_info(gw_results): def test_greenwater_more_info(greenwater_results):
more_info = gw_results.more_info more_info = greenwater_results.more_info
assert "_Tilia cordata_" in more_info assert "_Tilia cordata_" in more_info
assert "_Robinia pseudoacacia_" in more_info assert "_Robinia pseudoacacia_" in more_info
tilia = kpis_by_name_list(more_info["_Tilia cordata_"]) tilia = kpis_by_name_list(more_info["_Tilia cordata_"])
...@@ -274,28 +276,28 @@ def kpis_by_name_list(kpi_list: list[KPI]) -> dict[str, KPI]: ...@@ -274,28 +276,28 @@ def kpis_by_name_list(kpi_list: list[KPI]) -> dict[str, KPI]:
return {kpi.name: kpi for kpi in kpi_list} return {kpi.name: kpi for kpi in kpi_list}
def test_gw_project(gw_results): def test_greenwater_project(greenwater_results):
assert gw_results.project == "CGSC" assert greenwater_results.project == "CGSC"
def test_gw_repository(gw_results): def test_greenwater_repository(greenwater_results):
assert gw_results.repository.absolute() == TEST_REPOSITORY assert greenwater_results.repository.absolute() == TEST_REPOSITORY
def test_gw_params(gw_results): def test_greenwater_params(greenwater_results):
assert gw_results.short_name == "GreenWater" assert greenwater_results.short_name == "GreenWater"
assert gw_results.name == "CGSC_GreenWater" assert greenwater_results.name == "CGSC_GreenWater"
assert gw_results.workflow_provider == ( assert greenwater_results.workflow_provider == (
"de.hftstuttgart.simstadtworkflows.greenwater.GreenWaterWorkflowProvider" "de.hftstuttgart.simstadtworkflows.greenwater.GreenWaterWorkflowProvider"
) )
def test_gw_serialization(gw_results): def test_greenwater_serialization(greenwater_results):
json_str = gw_results.to_json() json_str = greenwater_results.to_json()
reconstructed = SimStadtResults.from_json(json_str) reconstructed = SimStadtResults.from_json(json_str)
assert isinstance(reconstructed, GreenWaterResults) assert isinstance(reconstructed, GreenWaterResults)
assert reconstructed.description == gw_results.description assert reconstructed.description == greenwater_results.description
assert len(reconstructed.output_files) == len(gw_results.output_files) assert len(reconstructed.output_files) == len(greenwater_results.output_files)
assert "Average irrigation [mm]" in json_str assert "Average irrigation [mm]" in json_str
assert "_df_attrs" in json_str assert "_df_attrs" in json_str
assert len(reconstructed.kpis) > 0 assert len(reconstructed.kpis) > 0
...@@ -303,11 +305,11 @@ def test_gw_serialization(gw_results): ...@@ -303,11 +305,11 @@ def test_gw_serialization(gw_results):
assert "Projected tree area" in [k.name for k in reconstructed.kpis] assert "Projected tree area" in [k.name for k in reconstructed.kpis]
assert isinstance(reconstructed.csv_path, Path) assert isinstance(reconstructed.csv_path, Path)
assert "Tilia cordata" in reconstructed.dataframe.attrs["species"] assert "Tilia cordata" in reconstructed.dataframe.attrs["species"]
pd.testing.assert_frame_equal(reconstructed.dataframe, gw_results.dataframe) pd.testing.assert_frame_equal(reconstructed.dataframe, greenwater_results.dataframe)
def test_gw_repr(gw_results): def test_greenwater_repr(greenwater_results):
detailed = repr(gw_results) detailed = repr(greenwater_results)
assert "Grombühl_mini_with_trees.gml" in detailed assert "Grombühl_mini_with_trees.gml" in detailed
assert "Rain" in detailed assert "Rain" in detailed
assert "458" in detailed assert "458" in detailed
...@@ -417,6 +419,79 @@ def test_greenwater_without_trees(): ...@@ -417,6 +419,79 @@ def test_greenwater_without_trees():
_ = results.kpis _ = results.kpis
# ---------------------------------------------------------------------------
# Load profile
# ---------------------------------------------------------------------------
@pytest.fixture(scope="module")
def loadprofile_results() -> SimStadtResults:
output_files = [
LOAD_PROFILE_FLOW / "02_LoadProfileGenerator.step/MiniBuchwald_load_profile_Hourly.csv",
]
return create_simstadt_results("Load profile for MiniBuchwald", output_files)
def test_loadprofile_result_type(loadprofile_results):
assert isinstance(loadprofile_results, LoadProfileResults)
def test_loadprofile_output_files_exist(loadprofile_results):
assert all(f.exists() for f in loadprofile_results.output_files)
def test_loadprofile_csv_exists(loadprofile_results):
assert loadprofile_results.csv_path.exists()
def test_loadprofile_dataframe(loadprofile_results):
df = loadprofile_results.dataframe
assert isinstance(df, pd.DataFrame)
assert df.shape == (8760, 3)
assert "DEBW_52210006I2R" in df.columns
assert "DEBW_52210005fRo" in df.columns
assert "DEBW_5221000619W" in df.columns
def test_loadprofile_kpis(loadprofile_results):
kpis = kpis_by_name(loadprofile_results)
assert kpis["Number of buildings"].value == 3
assert kpis["Number of buildings"].unit is None
assert kpis["Total load"].value == pytest.approx(17004.0, abs=1.0)
assert kpis["Total load"].unit == "kWh/a"
assert kpis["Average load"].value == pytest.approx(1.9, abs=0.1)
assert kpis["Average load"].unit == "kWh/h"
def test_loadprofile_no_diagrams(loadprofile_results):
assert loadprofile_results.diagrams == {}
def test_loadprofile_project(loadprofile_results):
assert loadprofile_results.project == "SektorSim"
def test_loadprofile_params(loadprofile_results):
assert loadprofile_results.short_name == "LoadProfile"
assert loadprofile_results.name == "LoadProfile_Template"
assert loadprofile_results.workflow_provider == "de.hftstuttgart.simstadtworkflows.energy.LoadProfileProvider"
def test_loadprofile_serialization(loadprofile_results):
json_str = loadprofile_results.to_json()
reconstructed = SimStadtResults.from_json(json_str)
assert isinstance(reconstructed, LoadProfileResults)
assert reconstructed.description == loadprofile_results.description
assert len(reconstructed.output_files) == len(loadprofile_results.output_files)
assert len(reconstructed.kpis) == 3
pd.testing.assert_frame_equal(reconstructed.dataframe, loadprofile_results.dataframe)
def test_loadprofile_repr(loadprofile_results):
detailed = repr(loadprofile_results)
assert "MiniBuchwald.gml" in detailed
assert "Total load" in detailed
def test_broken_simulation(): def test_broken_simulation():
output_files = [ output_files = [
TEST_REPOSITORY / "CGSC.proj/103_PV.flow/02_WeatherProcessor.step/notATable.log", TEST_REPOSITORY / "CGSC.proj/103_PV.flow/02_WeatherProcessor.step/notATable.log",
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment