From c861dc6bc32591abbbf30d76160d6e37d3da1607 Mon Sep 17 00:00:00 2001 From: guille Date: Wed, 25 Aug 2021 11:05:22 -0400 Subject: [PATCH] Partial implementation for idf schedule import (doe_idf) --- .idea/libs_EPlus.iml | 14 - .idea/modules.xml | 4 +- imports/schedules/doe_idf.py | 249 +++++++++--------- .../test_schedules_factory.py | 8 + 4 files changed, 129 insertions(+), 146 deletions(-) delete mode 100644 .idea/libs_EPlus.iml diff --git a/.idea/libs_EPlus.iml b/.idea/libs_EPlus.iml deleted file mode 100644 index 8e5446ac..00000000 --- a/.idea/libs_EPlus.iml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml index 112936b1..4f0963f9 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -2,7 +2,7 @@ - + - \ No newline at end of file + diff --git a/imports/schedules/doe_idf.py b/imports/schedules/doe_idf.py index 03c65825..c9203dbd 100644 --- a/imports/schedules/doe_idf.py +++ b/imports/schedules/doe_idf.py @@ -3,146 +3,135 @@ MyClass module SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2020 Project """ - - import pandas as pd import parseidf class DoeIdf: - """ - This is a import factory to add Idf schedules into the data model - """ - idf_schedule_to_commet_schedule = {'BLDG_LIGHT_SCH': 'Lights', - 'BLDG_OCC_SCH_wo_SB': 'Occupancy', - 'BLDG_EQUIP_SCH': 'Equipment', - 'ACTIVITY_SCH': 'Activity', - 'INFIL_QUARTER_ON_SCH': 'Infiltration'} + """ + This is a import factory to add Idf schedules into the data model + """ + idf_schedule_to_commet_schedule = {'BLDG_LIGHT_SCH': 'Lights', + 'BLDG_OCC_SCH_wo_SB': 'Occupancy', + 'BLDG_EQUIP_SCH': 'Equipment', + 'ACTIVITY_SCH': 'Activity', + 'INFIL_QUARTER_ON_SCH': 'Infiltration'} - _SCHEDULE_COMPACT_TYPE = 'SCHEDULE:COMPACT' - _SCHEDULE_TYPE_NAME = 1 + _SCHEDULE_COMPACT_TYPE = 'SCHEDULE:COMPACT' + _SCHEDULE_TYPE_NAME = 1 - def __init__(self, city, base_path): - self._city = city - self._idf_schedules_path = base_path / 'ASHRAE901_OfficeSmall_STD2019_Buffalo.idf' - with open(self._idf_schedules_path, 'r') as f: - idf = parseidf.parse(f.read()) - self._load_schedule(idf, 'small_office') + def __init__(self, city, base_path): + self._hours = [] + panda_hours = pd.timedelta_range(0, periods=24, freq='H') + for i, hour in enumerate(panda_hours): + self._hours.append(str(hour).replace('0 days ', '').replace(':00:00', ':00')) + self._city = city + self._idf_schedules_path = base_path / 'ASHRAE901_OfficeSmall_STD2019_Buffalo.idf' + with open(self._idf_schedules_path, 'r') as f: + idf = parseidf.parse(f.read()) + self._load_schedule(idf, 'small_office') - def _load_schedule(self, idf, building_usage): - holiday = [] - winter_design_day = [] - summer_design_day = [] - custom_day_1 = [] - custom_day_2 = [] - weekday = [] - weekend = [] - day_types = [] - schedules_day = {'None':[]} - compact_keywords = ['Weekdays', 'Weekends', 'Alldays', 'AllOtherDays', 'Sunday', 'Monday', 'Tuesday', - 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Holiday', 'Winterdesignday', - 'Summerdesignday', 'Customday1', 'Customday2'] - j = 0 - for compact_schedule in idf[self._SCHEDULE_COMPACT_TYPE]: - j = j +1 - if self._SCHEDULE_TYPE_NAME in self.idf_schedule_to_commet_schedule: - schedule_type = self.idf_schedule_to_commet_schedule[compact_schedule[self._SCHEDULE_TYPE_NAME]] + def _load_schedule(self, idf, building_usage): + schedules_day = {} + for compact_schedule in idf[self._SCHEDULE_COMPACT_TYPE]: + if compact_schedule[self._SCHEDULE_TYPE_NAME] in self.idf_schedule_to_commet_schedule: + schedule_type = self.idf_schedule_to_commet_schedule[compact_schedule[self._SCHEDULE_TYPE_NAME]] + else: + continue + days_index = [] + days_schedules = [] + for position, elements in enumerate(compact_schedule): + element_title = elements.title().replace('For: ', '') + if elements.title() != element_title: + days_index.append(position) + # store a cleaned version of the compact schedule + days_schedules.append(element_title) + days_index.append(len(days_schedules)) + + for i, day_index in enumerate(days_index): + if day_index == len(days_schedules): + break + schedules_day[f'{days_schedules[day_index]}'] = [] + hour_index = 0 + for hours_values in range(day_index + 1, days_index[i + 1] - 1, 2): + # Create 24h sequence + for index, hour in enumerate(self._hours[hour_index:]): + hour_formatted = days_schedules[hours_values].replace("Until: ", "") + if len(hour_formatted) == 4: + hour_formatted = f'0{hour_formatted}' + if hour == hour_formatted: + hour_index += index + break else: - schedule_type = 'Unknown' - # todo: check this piece of code logic - days_index = [] - for position, elements in enumerate(compact_schedule): - element_title = elements.title().replace('For: ', '') - if elements.title() != element_title: - days_index.append(position) - day_types.append(element_title) - days_index.append(len(day_types)) - print(day_types) - print(days_index) - ''' - for count, word_day_type in enumerate(day_type): - if word_day_type in compact_keywords: - index.append(count) - index.append(len(day_type)) - ''' + entry = (hour, days_schedules[hours_values + 1]) + schedules_day[f'{days_schedules[day_index]}'].append(entry) - for i, day_index in enumerate(days_index): - if day_index == len(day_types): - break - schedules_day[f'{day_types[day_index]}'] = [] - print(f'{day_types[day_index]}') - for hours_values in range(day_index+1, days_index[i + 1]-1, 2): + print(schedules_day[f'{days_schedules[day_index]}']) + ''' + for i in range(len(index) - 1): + number_of_day_schedule = list(day_types[index[i] + 1:index[i + 1]]) + hourly_values = list(range(24)) + start_hour = 0 + for num in range(int(len(number_of_day_schedule) / 2)): + until_time = list(map(int, (number_of_day_schedule[2*num].split('Until: ')[-1]).split(":")[0:])) + end_hour = int(until_time[0] + until_time[1] / 60) + value = float(number_of_day_schedule[2 * num + 1]) + for hour in range(start_hour, end_hour): + hourly_values[hour] = value + start_hour = end_hour + print(f'{compact_schedule}') + print(f'{building_usage} {schedule_type} {hourly_values}') + if day_type[index[i]] == 'Weekdays': + weekday.append(hourly_values) + elif day_type[index[i]] == 'Weekends': + weekend.append(hourly_values) + elif day_type[index[i]] == 'Holiday': + holiday.append(hourly_values) + elif day_type[index[i]] == 'Winterdesignday': + winter_design_day.append(hourly_values) + elif day_type[index[i]] == 'Summerdesignday': + summer_design_day.append(hourly_values) + elif day_type[index[i]] == 'Customday1': + custom_day_1.append(hourly_values) + elif day_type[index[i]] == 'Customday2': + custom_day_2.append(hourly_values) + else: + raise ValueError('Unknown schedule day type') - print(f'{day_types[hours_values]}# {day_types[hours_values+1]} ') - - if j == 2: - return - - ''' - for i in range(len(index) - 1): - number_of_day_schedule = list(day_types[index[i] + 1:index[i + 1]]) - hourly_values = list(range(24)) - start_hour = 0 - for num in range(int(len(number_of_day_schedule) / 2)): - until_time = list(map(int, (number_of_day_schedule[2*num].split('Until: ')[-1]).split(":")[0:])) - end_hour = int(until_time[0] + until_time[1] / 60) - value = float(number_of_day_schedule[2 * num + 1]) - for hour in range(start_hour, end_hour): - hourly_values[hour] = value - start_hour = end_hour - print(f'{compact_schedule}') - print(f'{building_usage} {schedule_type} {hourly_values}') - if day_type[index[i]] == 'Weekdays': - weekday.append(hourly_values) - elif day_type[index[i]] == 'Weekends': - weekend.append(hourly_values) - elif day_type[index[i]] == 'Holiday': - holiday.append(hourly_values) - elif day_type[index[i]] == 'Winterdesignday': - winter_design_day.append(hourly_values) - elif day_type[index[i]] == 'Summerdesignday': - summer_design_day.append(hourly_values) - elif day_type[index[i]] == 'Customday1': - custom_day_1.append(hourly_values) - elif day_type[index[i]] == 'Customday2': - custom_day_2.append(hourly_values) - else: - raise ValueError('Unknown schedule day type') + idf_schedules = pd.DataFrame( + {'week_day': schedules_day['Weekdays'], + 'Weekends': schedules_day['Weekends'], + 'Holiday': schedules_day['Holiday'], + 'Winterdesignday': schedules_day['Winterdesignday'], + 'Summerdesignday': schedules_day['Summerdesignday'], + 'Customday1': schedules_day['Customday1'], + 'Customday2': schedules_day['Customday2'] + }) + print(idf_schedules) ''' - idf_schedules = pd.DataFrame( - {'week_day': weekday, - 'Weekends': weekend, - 'Holiday': holiday, - 'Winterdesignday': winter_design_day, - 'Summerdesignday': summer_design_day, - 'Customday1': custom_day_1, - 'Customday2': custom_day_2, - }) - print(idf_schedules) + ''' + for building in city.buildings: + schedules = dict() + for usage_zone in building.usage_zones: + usage_schedules = idf_schedules - ''' - for building in city.buildings: - schedules = dict() - for usage_zone in building.usage_zones: - usage_schedules = idf_schedules - - # todo: should we save the data type? How? - number_of_schedule_types = 5 - schedules_per_schedule_type = 6 - idf_day_types = dict({'week_day': 0, 'Weekends': 1, 'Holiday': 2, 'Winterdesignday': 3, 'Summerdesignday': - 4, 'Customday1': 5, 'Customday2': 6}) - for schedule_types in range(0, number_of_schedule_types): - data = pd.DataFrame() - columns_names = [] - name = '' - for schedule_day in range(0, len(idf_schedules)): - row_cells = usage_schedules.iloc[schedules_per_schedule_type*schedule_types + schedule_day] - if schedule_day == idf_day_types['week_day']: - name = row_cells[0] - columns_names.append(row_cells[2]) - data1 = row_cells[schedules_per_schedule_type:] - data = pd.concat([data, data1], axis=1) - data.columns = columns_names - schedules[name] = data - usage_zone.schedules = schedules - ''' + # todo: should we save the data type? How? + number_of_schedule_types = 5 + schedules_per_schedule_type = 6 + idf_day_types = dict({'week_day': 0, 'Weekends': 1, 'Holiday': 2, 'Winterdesignday': 3, 'Summerdesignday': + 4, 'Customday1': 5, 'Customday2': 6}) + for schedule_types in range(0, number_of_schedule_types): + data = pd.DataFrame() + columns_names = [] + name = '' + for schedule_day in range(0, len(idf_schedules)): + row_cells = usage_schedules.iloc[schedules_per_schedule_type*schedule_types + schedule_day] + if schedule_day == idf_day_types['week_day']: + name = row_cells[0] + columns_names.append(row_cells[2]) + data1 = row_cells[schedules_per_schedule_type:] + data = pd.concat([data, data1], axis=1) + data.columns = columns_names + schedules[name] = data + usage_zone.schedules = schedules + ''' diff --git a/non_functional_tests/test_schedules_factory.py b/non_functional_tests/test_schedules_factory.py index f04dbd89..9cc622e3 100644 --- a/non_functional_tests/test_schedules_factory.py +++ b/non_functional_tests/test_schedules_factory.py @@ -8,6 +8,7 @@ from unittest import TestCase from imports.geometry_factory import GeometryFactory from imports.usage_factory import UsageFactory +from imports.construction_factory import ConstructionFactory from imports.schedules_factory import SchedulesFactory from imports.geometry.helpers.geometry_helper import GeometryHelper @@ -28,6 +29,7 @@ class TestSchedulesFactory(TestCase): def _get_citygml(self, file): file_path = (self._example_path / file).resolve() self._city = GeometryFactory('citygml', file_path).city + ConstructionFactory('nrel', self._city).enrich() self.assertIsNotNone(self._city, 'city is none') for building in self._city.buildings: building.function = GeometryHelper.hft_to_function[building.function] @@ -43,3 +45,9 @@ class TestSchedulesFactory(TestCase): self.assertIsNot(len(building.usage_zones), 0, 'no building usage_zones defined') for usage_zone in building.usage_zones: self.assertTrue(usage_zone.schedules) + + def test_deo_idf_archetypes(self): + file = (self._example_path / 'C40_Final.gml').resolve() + city = self._get_citygml(file) + occupancy_handler = 'doe_idf' + SchedulesFactory(occupancy_handler, city).enrich()