diff --git a/city_model_structure/attributes/occupancy.py b/city_model_structure/attributes/occupancy.py
index 6560e302..57ccaa3e 100644
--- a/city_model_structure/attributes/occupancy.py
+++ b/city_model_structure/attributes/occupancy.py
@@ -2,33 +2,35 @@
Building module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Sanam Dabirian sanam.dabirian@mail.concordia.ca
+Contributors Pilar Monsalvete pilar_monsalvete@yahoo.es
"""
+import calendar as cal
+
class Occupancy:
"""
Occupancy class
"""
- def __init__(self, internal_heat_gain, heat_dissipation, occupant_rate, occupant_type, occupant_zone,
- number_of_occupants, arrival_time=None, departure_time=None, break_time=None, day_of_week=None,
- pd_of_meetings_duration=None, occupant_schedule=None):
+ def __init__(self):
"""
Constructor
"""
- self._internal_heat_gain = internal_heat_gain
- self._heat_dissipation = heat_dissipation
- self._occupant_rate = occupant_rate
- self._occupant_type = occupant_type
- self._occupant_zone = occupant_zone
- self._occupant_schedule = occupant_schedule
- self._number_of_occupants = number_of_occupants
- self._arrival_time = arrival_time
- self._departure_time = departure_time
- self._break_time = break_time
- self._day_of_week = day_of_week
- self._pd_of_meetings_duration = pd_of_meetings_duration
+ self._internal_heat_gain = None
+ self._heat_dissipation = None
+ self._occupant_rate = None
+ self._occupant_type = None
+ self._occupant_zone = None
+ self._occupant_schedule = None
+ self._number_of_occupants = None
+ self._arrival_time = None
+ self._departure_time = None
+ self._break_time = None
+ self._day_of_week = None
+ self._pd_of_meetings_duration = None
+ self._complete_year_schedule = None
@property
def internal_heat_gain(self):
@@ -125,3 +127,23 @@ class Occupancy:
:return: probability distribution of the meeting duration
"""
return self._pd_of_meetings_duration
+
+ def get_complete_year_schedule(self, schedules):
+ if self._complete_year_schedule is None:
+ self._complete_year_schedule = []
+ for i in range(1, 13):
+ month_range = cal.monthrange(2015, i)
+ for day in range(1, month_range[1]+1):
+ if cal.weekday(2015, i, day) < 5:
+ for j in range(0, 24):
+ week_schedule = schedules['WD'][j]
+ self._complete_year_schedule.append(week_schedule)
+ elif cal.weekday(2015, i, day) == 5:
+ for j in range(0, 24):
+ week_schedule = schedules['Sat'][j]
+ self._complete_year_schedule.append(week_schedule)
+ else:
+ for j in range(0, 24):
+ week_schedule = schedules['Sun'][j]
+ self._complete_year_schedule.append(week_schedule)
+ return self._complete_year_schedule
diff --git a/city_model_structure/attributes/usage_zone.py b/city_model_structure/attributes/usage_zone.py
index e82f9be0..6bcb07e2 100644
--- a/city_model_structure/attributes/usage_zone.py
+++ b/city_model_structure/attributes/usage_zone.py
@@ -2,6 +2,7 @@
UsageZone module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
+Contributors Pilar Monsalvete pilar_monsalvete@yahoo.es
"""
from typing import List
@@ -21,10 +22,11 @@ class UsageZone:
self._cooling_setpoint = None
self._hours_day = None
self._days_year = None
- # todo: this must come from library, talk to Rabeeh
+ # todo: mechanical_air_change must come from library, talk to Rabeeh
self._mechanical_air_change = ConfigurationHelper().min_air_change
self._occupancy = None
self._schedules = None
+ self._heating_schedule = None
@property
def internal_gains(self) -> List[InternalGains]:
@@ -193,3 +195,19 @@ class UsageZone:
:param value: Sunday schedules
"""
self._schedules = value
+
+ @property
+ def heating_schedule(self):
+ """
+ Get heating schedule
+ :return: dict{DtaFrame(int)}
+ """
+ return self._heating_schedule
+
+ @heating_schedule.setter
+ def heating_schedule(self, values):
+ """
+ Get heating schedule
+ :param values: dict{DtaFrame(int)}
+ """
+ self._heating_schedule = values
diff --git a/city_model_structure/monthly_to_hourly_demand.py b/city_model_structure/monthly_to_hourly_demand.py
index 13160b50..b52da7a1 100644
--- a/city_model_structure/monthly_to_hourly_demand.py
+++ b/city_model_structure/monthly_to_hourly_demand.py
@@ -5,16 +5,18 @@ Copyright © 2020 Project Author Pilar Monsalvete pilar_monsalvete@yahoo.es
"""
import pandas as pd
import helpers.constants as cte
-
+from city_model_structure.attributes.occupancy import Occupancy
+import calendar as cal
class MonthlyToHourlyDemand:
"""
MonthlyToHourlyDemand class
"""
- def __init__(self, building):
+ def __init__(self, building, conditioning_seasons):
self._hourly_heating = pd.DataFrame()
self._hourly_cooling = pd.DataFrame()
self._building = building
+ self._conditioning_seasons = conditioning_seasons
@property
def hourly_heating(self):
@@ -23,38 +25,45 @@ class MonthlyToHourlyDemand:
:return: [hourly_heating]
"""
# todo: this method and the insel model have to be reviewed for more than one thermal zone
- external_temp = self._building.hourly_external_temperature
+ external_temp = self._building.external_temperature['hour']
# todo: review index depending on how the schedules are defined, either 8760 or 24 hours
- period = 'day'
for usage_zone in self._building.usage_zones:
- temp_set = usage_zone.heating_setpoint
- temp_back = usage_zone.heating_setback
- occupancy = usage_zone.occupancy.occupant_schedule(period)
- # todo: heating_schedule is still missing
- heating_schedule = usage_zone.heating_schedule_month
+ temp_set = float(usage_zone.heating_setpoint)
+ temp_back = float(usage_zone.heating_setback)
+ occupancy = Occupancy().get_complete_year_schedule(usage_zone.schedules['Occupancy'])
+ heating_schedule = self._conditioning_seasons['heating']
- self._hourly_heating = pd.DataFrame(columns=['monthly to hourly'])
+ hourly_heating = []
i = 0
- for month in range(0, 12):
+ temp_grad_day = []
+ for month in range(1, 13):
temp_grad_month = 0
- for day in cte.days_of_month[month]:
+ month_range = cal.monthrange(2015, month)
+ for day in range(1, month_range[1]+1):
external_temp_med = 0
for hour in range(0, 24):
- external_temp_med += external_temp[i]/24
+ external_temp_med += external_temp['inseldb'][i]/24
for hour in range(0, 24):
- if external_temp_med < temp_set[i] & heating_schedule[month] == 1:
- if occupancy[hour] == 1:
- temp_grad_day = temp_set[i] - external_temp[i]
+ if external_temp_med < temp_set and heating_schedule[month-1] == 1:
+ if occupancy[hour] > 0:
+ temp_grad_day.append(temp_set - external_temp['inseldb'][i])
else:
- temp_grad_day = temp_back[i] - external_temp[i]
+ temp_grad_day.append(temp_back - external_temp['inseldb'][i])
else:
- temp_grad_day = 0
+ temp_grad_day.append(0)
- temp_grad_month += temp_grad_day
- self._hourly_heating.append(self._building.monthly_heating(month)*temp_grad_day/temp_grad_month)
+ temp_grad_month += temp_grad_day[i]
i += 1
+ for day in range(1, month_range[1] + 1):
+ for hour in range(0, 24):
+ j = (day - 1) * 24 + hour
+ monthly_demand = self._building.heating['month']['INSEL'][month-1]
+ hourly_demand = float(monthly_demand)*float(temp_grad_day[j])/float(temp_grad_month)
+ hourly_heating.append(hourly_demand)
+
+ self._hourly_heating = pd.DataFrame(data=hourly_heating, columns=['monthly to hourly'])
return self._hourly_heating
@property
diff --git a/data/physics/us_archetypes.xml b/data/physics/us_archetypes.xml
index c928bf16..cd378aeb 100644
--- a/data/physics/us_archetypes.xml
+++ b/data/physics/us_archetypes.xml
@@ -805,4 +805,28 @@
0.10
0
+
+
+
+ 0.15
+ 4
+
+
+ 0
+
+
+
+ 0
+
+
+
+ 3.05
+ 3
+ 90
+ 0.15
+ 0.15
+ 0.50
+ 0
+
+
diff --git a/factories/occupancy_factory.py b/factories/occupancy_factory.py
index 77726e4b..bfa0cb3c 100644
--- a/factories/occupancy_factory.py
+++ b/factories/occupancy_factory.py
@@ -12,7 +12,7 @@ class OccupancyFactory:
"""
PhysicsFactor class
"""
- def __init__(self, handler, city, base_path=Path(Path(__file__).parent.parent.parent / 'data/occupancy')):
+ def __init__(self, handler, city, base_path=Path(Path(__file__).parent.parent / 'data/occupancy')):
self._handler = '_' + handler.lower().replace(' ', '_')
self._city = city
self._base_path = base_path
diff --git a/factories/occupancy_feeders/demo_occupancy_parameters.py b/factories/occupancy_feeders/demo_occupancy_parameters.py
index c1e83f09..0cd3b602 100644
--- a/factories/occupancy_feeders/demo_occupancy_parameters.py
+++ b/factories/occupancy_feeders/demo_occupancy_parameters.py
@@ -2,6 +2,7 @@
PhysicsFactory retrieve the specific physics module for the given region
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
+contributors Pilar Monsalvete pilar_monsalvete@yahoo.es
"""
import pandas as pd
from factories.occupancy_feeders.helpers.occupancy_helper import OccupancyHelper
@@ -12,19 +13,27 @@ class DemoOccupancyParameters:
def __init__(self, city, base_path):
self._city = city
self._demo_schedules_path = base_path / 'demo_schedules.xlsx'
+ print('schedules: ', self._demo_schedules_path)
xls = pd.ExcelFile(self._demo_schedules_path)
# todo: review for more than one usage_zones per building
for building in city.buildings:
schedules = dict()
occupancy = pd.read_excel(xls, sheet_name=OccupancyHelper.pluto_occupancy_function(building.function),
skiprows=[0, 1, 2, 3], nrows=39, usecols="A:AA")
+ # todo: should we safe the data type? How?
for index in range(0, 13):
- row = occupancy.iloc[3 * index]
- data = row[1:]
- name = row[0]
- for i in range(1, 3):
+ data = pd.DataFrame()
+ columns_names = []
+ name = ''
+ data_type = ''
+ for i in range(0, 3):
row = occupancy.iloc[3*index + i]
- data1 = row[1:]
- data = pd.concat([data, data1], axis=1)
+ if i == 0:
+ name = row[0]
+ data_type = row[1]
+ columns_names.append(row[2])
+ data1 = row[3:]
+ data = pd.concat([data, data1], axis=1)
+ data.columns = columns_names
schedules[name] = data
building.usage_zones[0].schedules = schedules
diff --git a/factories/physics_feeders/us_base_physics_parameters.py b/factories/physics_feeders/us_base_physics_parameters.py
index 4bc94987..c3fb461a 100644
--- a/factories/physics_feeders/us_base_physics_parameters.py
+++ b/factories/physics_feeders/us_base_physics_parameters.py
@@ -40,7 +40,7 @@ class UsBasePhysicsParameters:
# ToDo: remove this in the future
# ToDo: Raise WrongArchetype if not all the surface types are defined for the given city_object
if archetype is None:
- print('Building ', building.name, 'has unknown archetype')
+ print('Building ', building.name, 'has unknown archetype for building type: ', building_type)
print('type: ', building_type, UsToLibraryTypes.yoc_to_standard(building.year_of_construction),
self._climate_zone)
continue
diff --git a/factories/physics_feeders/us_new_york_city_physics_parameters.py b/factories/physics_feeders/us_new_york_city_physics_parameters.py
index 4640bbbc..1f845780 100644
--- a/factories/physics_feeders/us_new_york_city_physics_parameters.py
+++ b/factories/physics_feeders/us_new_york_city_physics_parameters.py
@@ -3,7 +3,7 @@ UsNewYorkCityPhysicsParameters import the construction and material information
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
-from factories.physics_feeders.helpers.us_pluto_to_function import UsPlutoToFunction as Pf
+from factories.physics_feeders.helpers.us_pluto_to_function import UsPlutoToFunction as pf
from factories.physics_feeders.us_base_physics_parameters import UsBasePhysicsParameters
@@ -14,4 +14,4 @@ class UsNewYorkCityPhysicsParameters(UsBasePhysicsParameters):
def __init__(self, city, base_path):
self._city = city
climate_zone = 'ASHRAE_2004:4A'
- super().__init__(climate_zone, self._city.buildings, Pf.function, base_path)
+ super().__init__(climate_zone, self._city.buildings, pf.function, base_path)
diff --git a/factories/usage_feeders/us_new_york_city_usage_parameters.py b/factories/usage_feeders/us_new_york_city_usage_parameters.py
index 60e16783..536d23a4 100644
--- a/factories/usage_feeders/us_new_york_city_usage_parameters.py
+++ b/factories/usage_feeders/us_new_york_city_usage_parameters.py
@@ -3,7 +3,7 @@ UsNewYorkCityUsageParameters model the usage properties for a NYC building
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
-from factories.usage_feeders.helpers.us_pluto_to_usage import UsPlutoToUsage as Pu
+from factories.usage_feeders.helpers.us_pluto_to_usage import UsPlutoToUsage as pu
from factories.usage_feeders.us_base_usage_parameters import UsBaseUsageParameters
@@ -13,4 +13,4 @@ class UsNewYorkCityUsageParameters(UsBaseUsageParameters):
"""
def __init__(self, city):
self._city = city
- super().__init__(self._city, Pu.usage)
+ super().__init__(self._city, pu.usage)
diff --git a/requirements.txt b/requirements.txt
index 44eb9e62..1ec3cd7b 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -54,4 +54,5 @@ requests~=2.24.0
esoreader~=1.2.3
geomeppy~=0.11.8
pyglet~=1.5.8
-networkx~=2.5
\ No newline at end of file
+networkx~=2.5
+xlrd~=1.2.0
diff --git a/tests/test_occupancy_factory.py b/tests/test_occupancy_factory.py
index 9a58aa6a..66939e3d 100644
--- a/tests/test_occupancy_factory.py
+++ b/tests/test_occupancy_factory.py
@@ -9,6 +9,7 @@ from unittest import TestCase
from factories.geometry_factory import GeometryFactory
from factories.usage_factory import UsageFactory
from factories.occupancy_factory import OccupancyFactory
+from city_model_structure.attributes.occupancy import Occupancy
class TestOccupancyFactory(TestCase):
@@ -46,3 +47,4 @@ class TestOccupancyFactory(TestCase):
for building in city.buildings:
for usage_zone in building.usage_zones:
self.assertTrue(usage_zone.schedules)
+ print(len(Occupancy().get_complete_year_schedule(usage_zone.schedules['Occupancy'])))