Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
SimStadt
simstadtpy
Commits
03a19d2b
Commit
03a19d2b
authored
Mar 12, 2026
by
Eric Duminil
Browse files
Adding solar results too
parent
b886d1a3
Changes
11
Expand all
Hide whitespace changes
Inline
Side-by-side
src/simstadtpy/__init__.py
View file @
03a19d2b
...
@@ -5,6 +5,7 @@ from simstadtpy.results import (
...
@@ -5,6 +5,7 @@ from simstadtpy.results import (
LoadProfileResults
,
LoadProfileResults
,
PhotovoltaicResults
,
PhotovoltaicResults
,
SimStadtResults
,
SimStadtResults
,
SolarPotentialResults
,
create_simstadt_results
,
create_simstadt_results
,
)
)
from
simstadtpy.runner
import
run_workflow_with_citygml
from
simstadtpy.runner
import
run_workflow_with_citygml
...
@@ -17,6 +18,7 @@ __all__ = [
...
@@ -17,6 +18,7 @@ __all__ = [
"LoadProfileResults"
,
"LoadProfileResults"
,
"PhotovoltaicResults"
,
"PhotovoltaicResults"
,
"GreenWaterResults"
,
"GreenWaterResults"
,
"SolarPotentialResults"
,
"create_simstadt_results"
,
"create_simstadt_results"
,
"run_workflow_with_citygml"
,
"run_workflow_with_citygml"
,
"photovoltaic_simulation"
,
"photovoltaic_simulation"
,
...
...
src/simstadtpy/results.py
View file @
03a19d2b
...
@@ -77,6 +77,7 @@ class Providers(str, Enum):
...
@@ -77,6 +77,7 @@ class Providers(str, Enum):
)
)
GREEN_WATER
=
"de.hftstuttgart.simstadtworkflows.greenwater.GreenWaterWorkflowProvider"
GREEN_WATER
=
"de.hftstuttgart.simstadtworkflows.greenwater.GreenWaterWorkflowProvider"
LOAD_PROFILE
=
"de.hftstuttgart.simstadtworkflows.energy.LoadProfileProvider"
LOAD_PROFILE
=
"de.hftstuttgart.simstadtworkflows.energy.LoadProfileProvider"
SOLAR_POTENTIAL
=
"de.hftstuttgart.simstadtworkflows.energy.SolarPotentialAnalysisWorkflowProvider"
def
detect_decimal
(
csv_path
:
Path
,
line_number
:
int
,
check
:
str
=
""
)
->
str
:
def
detect_decimal
(
csv_path
:
Path
,
line_number
:
int
,
check
:
str
=
""
)
->
str
:
...
@@ -459,6 +460,33 @@ class LoadProfileResults(SimStadtResults):
...
@@ -459,6 +460,33 @@ class LoadProfileResults(SimStadtResults):
]
]
@
dataclass
(
repr
=
False
)
class
SolarPotentialResults
(
SimStadtResults
):
"""Results for SolarPotential workflows.
The output is a .prn weather file with 8760 hourly rows and three columns:
GHI (W/m²), DHI (W/m²), Ta (°C).
"""
supported_providers
:
ClassVar
[
list
[
str
]]
=
[
Providers
.
SOLAR_POTENTIAL
]
csv_identifier
=
"_solar_potential"
# no CSV output; csv_path will raise if called
def
_parse_results
(
self
)
->
pd
.
DataFrame
:
prn_paths
=
self
.
get_all_by_extension
(
".prn"
)
if
len
(
prn_paths
)
!=
1
:
raise
ValueError
(
f
"Expected exactly one .prn file, found
{
len
(
prn_paths
)
}
"
)
return
pd
.
read_csv
(
prn_paths
[
0
],
sep
=
r
"\s+"
,
names
=
[
"GHI"
,
"DHI"
,
"Ta"
],
header
=
None
)
@
property
def
kpis
(
self
)
->
list
[
KPI
]:
df
=
self
.
dataframe
return
[
KPI
(
"Annual GHI"
,
df
[
"GHI"
].
sum
()
/
1000
,
"kWh/m²"
,
precision
=
1
),
KPI
(
"Annual DHI"
,
df
[
"DHI"
].
sum
()
/
1000
,
"kWh/m²"
,
precision
=
1
),
KPI
(
"Mean temperature"
,
float
(
df
[
"Ta"
].
mean
()),
"°C"
,
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)."""
...
...
tests/data/TestRepo/SektorSim.proj/Solar.flow/00_ImportCityGml.step/params.xml
0 → 100755
View file @
03a19d2b
<?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>
tests/data/TestRepo/SektorSim.proj/Solar.flow/01_Preprocessing.step/00_GeometricPreprocessor.step/params.xml
0 → 100755
View file @
03a19d2b
<?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
property=
"name"
>
<string>
Base
</string>
</void>
</object>
</java>
tests/data/TestRepo/SektorSim.proj/Solar.flow/01_Preprocessing.step/params.xml
0 → 100755
View file @
03a19d2b
<?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.WorkflowStep"
method=
"getField"
>
<string>
selectedNextStepPath
</string>
<void
method=
"set"
>
<object
idref=
"Preprocessing0"
/>
<string>
02_WeatherProcessor.step
</string>
</void>
</void>
<void
property=
"name"
>
<string>
Base
</string>
</void>
</object>
</java>
tests/data/TestRepo/SektorSim.proj/Solar.flow/02_WeatherProcessor.step/hourly_GHI_DHI_Ta_inseldb_Stuttgart.prn
0 → 100755
View file @
03a19d2b
This diff is collapsed.
Click to expand it.
tests/data/TestRepo/SektorSim.proj/Solar.flow/02_WeatherProcessor.step/params.xml
0 → 100755
View file @
03a19d2b
<?xml version="1.0" encoding="UTF-8"?>
<java
version=
"17.0.14"
class=
"java.beans.XMLDecoder"
>
<object
class=
"eu.simstadt.workflowsteps.WeatherProcessorStep"
id=
"WeatherProcessorStep0"
>
<void
class=
"de.hftstuttgart.hierarchicworkflow.WorkflowStep"
method=
"getField"
>
<string>
selectedNextStepPath
</string>
<void
method=
"set"
>
<object
idref=
"WeatherProcessorStep0"
/>
<string>
03_IrradianceProcessor.step
</string>
</void>
</void>
<void
property=
"inputFilename"
>
<string>
Stuttgart-hour.csv
</string>
</void>
<void
property=
"name"
>
<string>
Base
</string>
</void>
<void
property=
"weatherDataSource"
>
<object
class=
"java.lang.Enum"
method=
"valueOf"
>
<class>
de.hft.stuttgart.simstadt2.weather.WeatherDataSourceType
</class>
<string>
INSEL_DATABASE
</string>
</object>
</void>
</object>
</java>
tests/data/TestRepo/SektorSim.proj/Solar.flow/03_IrradianceProcessor.step/params.xml
0 → 100755
View file @
03a19d2b
<?xml version="1.0" encoding="UTF-8"?>
<java
version=
"17.0.14"
class=
"java.beans.XMLDecoder"
>
<object
class=
"eu.simstadt.workflowsteps.IrradianceProcessorStep"
id=
"IrradianceProcessorStep0"
>
<void
class=
"de.hftstuttgart.hierarchicworkflow.WorkflowStep"
method=
"getField"
>
<string>
selectedNextStepPath
</string>
<void
method=
"set"
>
<object
idref=
"IrradianceProcessorStep0"
/>
<string>
04_Visualization.step
</string>
</void>
</void>
<void
property=
"name"
>
<string>
Base
</string>
</void>
</object>
</java>
tests/data/TestRepo/SektorSim.proj/Solar.flow/04_Visualization.step/params.xml
0 → 100755
View file @
03a19d2b
<?xml version="1.0" encoding="UTF-8"?>
<java
version=
"21.0.9"
class=
"java.beans.XMLDecoder"
>
<object
class=
"eu.simstadt.workflowsteps.Visualization"
id=
"Visualization0"
>
<void
property=
"name"
>
<string>
Base
</string>
</void>
<void
property=
"view"
>
<object
class=
"java.lang.Enum"
method=
"valueOf"
>
<class>
eu.simstadt.workflowsteps.Visualization$View
</class>
<string>
Top_View
</string>
</object>
</void>
<void
id=
"Boolean0"
method=
"isShowIrradianceOnLOD1"
/>
<void
property=
"withIrradianceGraph"
>
<object
idref=
"Boolean0"
/>
</void>
</object>
</java>
tests/data/TestRepo/SektorSim.proj/Solar.flow/params.xml
0 → 100755
View file @
03a19d2b
<java
version=
"17.0.14"
class=
"java.beans.XMLDecoder"
>
<object
class=
"eu.simstadt.workflows.CityGmlWorkflow"
id=
"CityGmlWorkflow0"
>
<void
class=
"de.hftstuttgart.hierarchicworkflow.WorkflowStep"
method=
"getField"
>
<string>
startStep
</string>
<void
method=
"set"
>
<object
idref=
"CityGmlWorkflow0"
/>
<boolean>
true
</boolean>
</void>
</void>
<void
property=
"name"
>
<string>
ImBuchwald_Solar
</string>
</void>
<void
property=
"shortName"
>
<string>
Solar
</string>
</void>
<void
property=
"workflowProvider"
>
<object
class=
"de.hftstuttgart.simstadtworkflows.energy.SolarPotentialAnalysisWorkflowProvider"
/>
</void>
<void
property=
"cityGmlFileNames"
><void
method=
"add"
><string>
MiniBuchwald.gml
</string></void></void></object>
</java>
\ No newline at end of file
tests/test_results.py
View file @
03a19d2b
...
@@ -12,12 +12,14 @@ from simstadtpy import (
...
@@ -12,12 +12,14 @@ from simstadtpy import (
LoadProfileResults
,
LoadProfileResults
,
PhotovoltaicResults
,
PhotovoltaicResults
,
SimStadtResults
,
SimStadtResults
,
SolarPotentialResults
,
create_simstadt_results
,
create_simstadt_results
,
)
)
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"
LOAD_PROFILE_FLOW
=
TEST_REPOSITORY
/
"SektorSim.proj"
/
"LoadProfile.flow"
SOLAR_FLOW
=
TEST_REPOSITORY
/
"SektorSim.proj"
/
"Solar.flow"
def
kpis_by_name
(
results
:
SimStadtResults
)
->
dict
[
str
,
KPI
]:
def
kpis_by_name
(
results
:
SimStadtResults
)
->
dict
[
str
,
KPI
]:
...
@@ -492,6 +494,75 @@ def test_loadprofile_repr(loadprofile_results):
...
@@ -492,6 +494,75 @@ def test_loadprofile_repr(loadprofile_results):
assert
"Total load"
in
detailed
assert
"Total load"
in
detailed
# ---------------------------------------------------------------------------
# Solar potential
# ---------------------------------------------------------------------------
@
pytest
.
fixture
(
scope
=
"module"
)
def
solar_results
()
->
SimStadtResults
:
output_files
=
[
SOLAR_FLOW
/
"02_WeatherProcessor.step/hourly_GHI_DHI_Ta_inseldb_Stuttgart.prn"
,
SOLAR_FLOW
/
"04_Visualization.step/MiniBuchwald_inseldb_Hay_irradiance_Top_View.png"
,
SOLAR_FLOW
/
"04_Visualization.step/irradiance_inseldb_Hay_Stuttgart.png"
,
]
return
create_simstadt_results
(
"Solar potential for MiniBuchwald"
,
output_files
)
def
test_solar_result_type
(
solar_results
):
assert
isinstance
(
solar_results
,
SolarPotentialResults
)
def
test_solar_output_files_exist
(
solar_results
):
assert
all
(
f
.
exists
()
for
f
in
solar_results
.
output_files
)
def
test_solar_dataframe
(
solar_results
):
df
=
solar_results
.
dataframe
assert
isinstance
(
df
,
pd
.
DataFrame
)
assert
df
.
shape
==
(
8760
,
3
)
assert
list
(
df
.
columns
)
==
[
"GHI"
,
"DHI"
,
"Ta"
]
def
test_solar_kpis
(
solar_results
):
kpis
=
kpis_by_name
(
solar_results
)
assert
kpis
[
"Annual GHI"
].
value
==
pytest
.
approx
(
1143.9
,
abs
=
0.1
)
assert
kpis
[
"Annual GHI"
].
unit
==
"kWh/m²"
assert
kpis
[
"Annual DHI"
].
value
==
pytest
.
approx
(
685.1
,
abs
=
0.1
)
assert
kpis
[
"Mean temperature"
].
value
==
pytest
.
approx
(
9.73
,
abs
=
0.05
)
assert
kpis
[
"Mean temperature"
].
unit
==
"°C"
def
test_solar_no_diagrams
(
solar_results
):
assert
solar_results
.
diagrams
==
{}
def
test_solar_project
(
solar_results
):
assert
solar_results
.
project
==
"SektorSim"
def
test_solar_params
(
solar_results
):
assert
solar_results
.
short_name
==
"Solar"
assert
solar_results
.
name
==
"ImBuchwald_Solar"
assert
solar_results
.
workflow_provider
==
(
"de.hftstuttgart.simstadtworkflows.energy.SolarPotentialAnalysisWorkflowProvider"
)
def
test_solar_serialization
(
solar_results
):
json_str
=
solar_results
.
to_json
()
reconstructed
=
SimStadtResults
.
from_json
(
json_str
)
assert
isinstance
(
reconstructed
,
SolarPotentialResults
)
assert
reconstructed
.
description
==
solar_results
.
description
assert
len
(
reconstructed
.
kpis
)
==
3
pd
.
testing
.
assert_frame_equal
(
reconstructed
.
dataframe
,
solar_results
.
dataframe
)
def
test_solar_repr
(
solar_results
):
detailed
=
repr
(
solar_results
)
assert
"MiniBuchwald.gml"
in
detailed
assert
"Annual GHI"
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"
,
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment