Skip to content

Commit c2fbdef

Browse files
authored
Merge pull request #3911 from architecture-building-systems/some-fix-from-idp-shanghai---void-deck-and-pv-without-demand
Allow running pv plots without running demand
2 parents 57119a6 + ab9746a commit c2fbdef

22 files changed

+244
-199
lines changed

cea/analysis/lca/embodied.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import cea.inputlocator
1616
from cea.constants import SERVICE_LIFE_OF_BUILDINGS, SERVICE_LIFE_OF_TECHNICAL_SYSTEMS, \
1717
CONVERSION_AREA_TO_FLOOR_AREA_RATIO, EMISSIONS_EMBODIED_TECHNICAL_SYSTEMS
18-
from cea.datamanagement.void_deck_migrator import migrate_void_deck_data
18+
from cea.datamanagement.utils import migrate_void_deck_data
1919

2020
__author__ = "Jimeno A. Fonseca"
2121
__copyright__ = "Copyright 2015, Architecture and Building Systems - ETH Zurich"

cea/datamanagement/archetypes_mapper.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ def archetypes_mapper(locator,
100100
supply_mapper(locator, building_typology_df)
101101

102102

103+
103104
def indoor_comfort_mapper(list_uses, locator, occupant_densities, building_typology_df):
104105
comfort_DB = pd.read_csv(locator.get_database_archetypes_use_type())
105106
# define comfort
@@ -400,7 +401,6 @@ def verify_building_standards(building_typology_df, db_standards):
400401
diff = typology_standards.difference(db_standards)
401402
raise ValueError(f'The following standards are not found in the database: {", ".join(diff)}')
402403

403-
404404
def main(config):
405405
"""
406406
Run the properties script with input from the reference case and compare the results. This ensures that changes

cea/datamanagement/format_helper/cea4_migrate.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from cea.datamanagement.format_helper.cea4_verify import cea4_verify, verify_shp, \
2525
COLUMNS_ZONE_4, print_verification_results_4, path_to_input_file_without_db_4, CSV_BUILDING_PROPERTIES_3_CSV
2626
from cea.datamanagement.format_helper.cea4_verify_db import check_directory_contains_csv
27+
from cea.datamanagement.utils import migrate_void_deck_data
2728
from cea.utilities.dbf import dbf_to_dataframe
2829

2930
COLUMNS_ZONE_3 = ['Name', 'floors_bg', 'floors_ag', 'height_bg', 'height_ag']
@@ -550,9 +551,12 @@ def migrate_cea3_to_cea4(scenario, verbose=False):
550551
pass
551552
# print('For Scenario: {scenario}, '.format(scenario=scenario_name), 'zone.shp already follows the CEA-4 format.')
552553
else:
553-
raise ValueError('! zone.shp exists but follows neither the CEA-3 nor CEA-4 format. CEA cannot proceed with the data migration.'
554-
'Check the following column(s) for CEA-3 format: {list_missing_attributes_zone_3}.'.format(list_missing_attributes_zone_3=list_missing_attributes_zone_3),
555-
'Check the following column(s) for CEA-4 format: {list_missing_attributes_zone_4}.'.format(list_missing_attributes_zone_4=list_missing_attributes_zone_4)
554+
if list_missing_attributes_zone_4[0] == 'void_deck' and len(list_missing_attributes_zone_4) == 1:
555+
config = cea.config.Configuration()
556+
locator = cea.inputlocator.InputLocator(config.scenario)
557+
migrate_void_deck_data(locator)
558+
else:
559+
raise ValueError('! zone.shp exists but follows neither the CEA-3 nor CEA-4 format. CEA cannot proceed with the data migration. Check the following column(s) for CEA-3 format: {list_missing_attributes_zone_3}.'.format(list_missing_attributes_zone_3=list_missing_attributes_zone_3), 'Check the following column(s) for CEA-4 format: {list_missing_attributes_zone_4}.'.format(list_missing_attributes_zone_4=list_missing_attributes_zone_4)
556560
)
557561
else:
558562
print("! Ensure zone.shp (CEA-3 format) is present in building-geometry folder.")
@@ -571,9 +575,12 @@ def migrate_cea3_to_cea4(scenario, verbose=False):
571575
pass
572576
# print('For Scenario: {scenario}, '.format(scenario=scenario_name), 'surroundings.shp already follows the CEA-4 format.')
573577
else:
574-
raise ValueError('surroundings.shp exists but follows neither the CEA-3 nor CEA-4 format. CEA cannot proceed with the data migration.'
575-
'Check the following column(s) for CEA-3 format: {list_missing_attributes_surroundings_3}.'.format(list_missing_attributes_surroundings_3=list_missing_attributes_surroundings_3),
576-
'Check the following column(s) for CEA-4 format: {list_missing_attributes_surroundings_4}.'.format(list_missing_attributes_surroundings_4=list_missing_attributes_surroundings_4)
578+
if list_missing_attributes_zone_4[0] == 'void_deck' and len(list_missing_attributes_zone_4) == 1:
579+
config = cea.config.Configuration()
580+
locator = cea.inputlocator.InputLocator(config.scenario)
581+
migrate_void_deck_data(locator)
582+
else:
583+
raise ValueError('surroundings.shp exists but follows neither the CEA-3 nor CEA-4 format. CEA cannot proceed with the data migration. Check the following column(s) for CEA-3 format: {list_missing_attributes_surroundings_3}.'.format(list_missing_attributes_surroundings_3=list_missing_attributes_surroundings_3), 'Check the following column(s) for CEA-4 format: {list_missing_attributes_surroundings_4}.'.format(list_missing_attributes_surroundings_4=list_missing_attributes_surroundings_4)
577584
)
578585
else:
579586
print('! (optional) Run Surroundings Helper to generate surroundings.shp after the data migration.')

cea/datamanagement/void_deck_migrator.py renamed to cea/datamanagement/utils/__init__.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1+
from __future__ import annotations
2+
from typing import TYPE_CHECKING
3+
import warnings
4+
15
import pandas as pd
26
import geopandas as gpd
3-
import cea.inputlocator
4-
import warnings
57

8+
if TYPE_CHECKING:
9+
from cea.inputlocator import InputLocator
610

7-
def migrate_void_deck_data(locator: cea.inputlocator.InputLocator) -> None:
11+
12+
def migrate_void_deck_data(locator: InputLocator) -> None:
813
"""Check if void_deck exists in zone.shp and copy it from envelope.csv if necessary.
914
1015
:param locator: the input locator object.
@@ -23,6 +28,8 @@ def migrate_void_deck_data(locator: cea.inputlocator.InputLocator) -> None:
2328
envelope_df[["name", "void_deck"]], on="name", how="left"
2429
)
2530
zone_gdf["void_deck"] = zone_gdf["void_deck"].fillna(0)
31+
zone_gdf.to_file(locator.get_zone_geometry())
32+
2633
print("Migrated void_deck data from envelope.csv to zone.shp.")
2734
envelope_df.drop(columns=["void_deck"], inplace=True)
2835
envelope_df.to_csv(locator.get_building_architecture(), index=False)
@@ -32,4 +39,11 @@ def migrate_void_deck_data(locator: cea.inputlocator.InputLocator) -> None:
3239
warnings.warn(
3340
"No void_deck data found in envelope.csv, setting to 0 in zone.shp"
3441
)
35-
zone_gdf.to_file(locator.get_zone_geometry(), driver="ESRI Shapefile")
42+
43+
# Validate that floors_ag is larger than void_deck for each building
44+
actual_floors = zone_gdf["floors_ag"] - zone_gdf["void_deck"]
45+
invalid_floors = zone_gdf[actual_floors <= 0]
46+
if len(invalid_floors) > 0:
47+
invalid_buildings = invalid_floors["name"].tolist()
48+
warnings.warn(f"Some buildings have void_deck greater than floors_ag: {invalid_buildings}",
49+
RuntimeWarning)

cea/demand/building_properties/building_geometry.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from __future__ import annotations
55
from geopandas import GeoDataFrame as Gdf
66

7+
from cea.datamanagement.databases_verification import COLUMNS_ZONE_GEOMETRY
78
from cea.utilities.standardize_coordinates import get_lat_lon_projected_shapefile, get_projected_coordinate_system
89

910
from typing import TYPE_CHECKING
@@ -25,18 +26,19 @@ def __init__(self, locator: InputLocator, building_names: list[str]):
2526
:param locator: an InputLocator for locating the input files
2627
:param building_names: list of buildings to read properties for
2728
"""
28-
prop_geometry: Gdf = Gdf.from_file(locator.get_zone_geometry()).set_index('name').loc[building_names]
29+
prop_geometry = Gdf.from_file(locator.get_zone_geometry())[COLUMNS_ZONE_GEOMETRY + ['geometry']].set_index('name').loc[building_names]
2930

3031
# reproject to projected coordinate system (in meters) to calculate area
3132
lat, lon = get_lat_lon_projected_shapefile(prop_geometry)
3233
target_crs = get_projected_coordinate_system(float(lat), float(lon))
33-
prop_geometry: Gdf = prop_geometry.to_crs(target_crs)
34+
prop_geometry = prop_geometry.to_crs(target_crs)
3435

36+
# TODO: Check usage of footprint and perimeter in other parts of the code
3537
prop_geometry['footprint'] = prop_geometry.area
3638
prop_geometry['perimeter'] = prop_geometry.length
3739
prop_geometry['Blength'], prop_geometry['Bwidth'] = self.calc_bounding_box_geom(prop_geometry)
3840

39-
self._prop_geometry = prop_geometry.drop('geometry', axis=1)
41+
self._prop_geometry = prop_geometry
4042

4143
@staticmethod
4244
def calc_bounding_box_geom(gdf: Gdf) -> tuple[list[float], list[float]]:

cea/demand/building_properties/building_properties.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,7 @@ def check_buildings(self, min_gfa: float = 100):
108108
"""
109109

110110
# FIXME: This is not a very good indicator of potential issue which causes overheating problems in some cases.
111-
footprint = self.geometry._prop_geometry.footprint
112-
floors = self.geometry._prop_geometry.floors_ag
113-
114-
GFA_m2 = footprint * floors
111+
GFA_m2 = self.rc_model._prop_rc_model['GFA_m2']
115112
small_buildings = GFA_m2[GFA_m2 < min_gfa]
116113

117114
if len(small_buildings) > 0:

cea/demand/building_properties/building_properties_row.py

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,13 @@ class EnvelopeProperties:
234234
A_op: Annotated[float, "Opaque area above ground [m2]"]
235235
win_wall: Annotated[float, "Window to wall ratio [-]"]
236236

237+
# Area fields added from BuildingRCModel
238+
Aroof: Annotated[float, "Roof area [m2]"]
239+
Aunderside: Annotated[float, "Underside area [m2]"]
240+
Awall_ag: Annotated[float, "Above ground wall area [m2]"]
241+
Awin_ag: Annotated[float, "Above ground window area [m2]"]
242+
Aop_bg: Annotated[float, "Area of opaque surfaces below ground [m2]"]
243+
237244
# FIXME: These fields does not neccessarily describe the building envelope
238245
Es: Annotated[float, "Heated/cooled share [-]"]
239246
occupied_bg: Annotated[float, "Basement occupation factor [-]"]
@@ -263,18 +270,14 @@ def from_dict(cls, solar: dict):
263270
@dataclass(frozen=True)
264271
class RCModelProperties:
265272
# --- Area properties ---
273+
footprint: Annotated[float, "Building footprint area [m2]"]
266274
Atot: Annotated[float, "Area of all surfaces facing the building zone [m2]"]
275+
Am: Annotated[float, "Effective mass area [m2]"]
276+
# TODO: Determine if these fields belong here (calculated using calc_useful_areas)
267277
Af: Annotated[float, "Conditioned floor area (areas that are heated or cooled) [m2]"]
268278
GFA_m2: Annotated[float, "Gross floor area [m2]"]
269-
footprint: Annotated[float, "Building footprint area [m2]"]
270-
Aroof: Annotated[float, "Roof area [m2]"]
271-
Aunderside: Annotated[float, "Underside area [m2]"]
272-
Awall_ag: Annotated[float, "Above ground wall area [m2]"]
273-
Awin_ag: Annotated[float, "Above ground window area [m2]"]
274-
Am: Annotated[float, "Effective mass area [m2]"]
275279
Aef: Annotated[float, "Electrified area (share of gross floor area that is electrified) [m2]"]
276280
Aocc: Annotated[float, "Occupied floor area [m2]"]
277-
Aop_bg: Annotated[float, "Area of opaque surfaces below ground [m2]"]
278281
Hs_ag: Annotated[float, "Share of above-ground gross floor area that is conditioned [m2/m2]"]
279282

280283
# --- Thermal properties ---
@@ -289,13 +292,6 @@ class RCModelProperties:
289292
Htr_op: Annotated[float, "Thermal transmission coefficient for opaque surfaces in RC-model [W/K]"]
290293
Htr_w: Annotated[float, "Thermal transmission coefficient for windows in RC-model [W/K]"]
291294

292-
# FIXME: Decide if these fields should be in envelope or rc_model
293-
# --- U-values (Duplicated Envelope properties) ---
294-
U_wall: Annotated[float, "U-value of wall [W/m2K]"]
295-
U_roof: Annotated[float, "U-value of roof [W/m2K]"]
296-
U_win: Annotated[float, "U-value of windows [W/m2K]"]
297-
U_base: Annotated[float, "U-value of floor [W/m2K]"]
298-
299295
@classmethod
300296
def from_dict(cls, rc_model: dict):
301297
field_names = cls.__annotations__.keys()

0 commit comments

Comments
 (0)