diff --git a/hub/city_model_structure/building.py b/hub/city_model_structure/building.py index d8fb88b7..527332be 100644 --- a/hub/city_model_structure/building.py +++ b/hub/city_model_structure/building.py @@ -296,7 +296,7 @@ class Building(CityObject): def cold_water_temperature(self) -> {float}: """ Get cold water temperature in degrees Celsius - :return: dict{DataFrame(float)} + :return: dict{[float]} """ return self._cold_water_temperature @@ -304,7 +304,7 @@ class Building(CityObject): def cold_water_temperature(self, value): """ Set cold water temperature in degrees Celsius - :param value: dict{DataFrame(float)} + :param value: dict{[float]} """ self._cold_water_temperature = value @@ -312,7 +312,7 @@ class Building(CityObject): def heating_demand(self) -> dict: """ Get heating demand in Wh - :return: dict{DataFrame(float)} + :return: dict{[float]} """ return self._heating_demand @@ -320,7 +320,7 @@ class Building(CityObject): def heating_demand(self, value): """ Set heating demand in Wh - :param value: dict{DataFrame(float)} + :param value: dict{[float]} """ self._heating_demand = value @@ -328,7 +328,7 @@ class Building(CityObject): def cooling_demand(self) -> dict: """ Get cooling demand in Wh - :return: dict{DataFrame(float)} + :return: dict{[float]} """ return self._cooling_demand @@ -336,7 +336,7 @@ class Building(CityObject): def cooling_demand(self, value): """ Set cooling demand in Wh - :param value: dict{DataFrame(float)} + :param value: dict{[float]} """ self._cooling_demand = value @@ -344,7 +344,7 @@ class Building(CityObject): def lighting_electrical_demand(self) -> dict: """ Get lighting electrical demand in Wh - :return: dict{DataFrame(float)} + :return: dict{[float]} """ return self._lighting_electrical_demand @@ -352,7 +352,7 @@ class Building(CityObject): def lighting_electrical_demand(self, value): """ Set lighting electrical demand in Wh - :param value: dict{DataFrame(float)} + :param value: dict{[float]} """ self._lighting_electrical_demand = value @@ -360,7 +360,7 @@ class Building(CityObject): def appliances_electrical_demand(self) -> dict: """ Get appliances electrical demand in Wh - :return: dict{DataFrame(float)} + :return: dict{[float]} """ return self._appliances_electrical_demand @@ -368,7 +368,7 @@ class Building(CityObject): def appliances_electrical_demand(self, value): """ Set appliances electrical demand in Wh - :param value: dict{DataFrame(float)} + :param value: dict{[float]} """ self._appliances_electrical_demand = value @@ -376,7 +376,7 @@ class Building(CityObject): def domestic_hot_water_heat_demand(self) -> dict: """ Get domestic hot water heat demand in Wh - :return: dict{DataFrame(float)} + :return: dict{[float]} """ return self._domestic_hot_water_heat_demand @@ -384,7 +384,7 @@ class Building(CityObject): def domestic_hot_water_heat_demand(self, value): """ Set domestic hot water heat demand in Wh - :param value: dict{DataFrame(float)} + :param value: dict{[float]} """ self._domestic_hot_water_heat_demand = value @@ -428,12 +428,12 @@ class Building(CityObject): def heating_peak_load(self) -> Union[None, dict]: """ Get heating peak load in W - :return: dict{DataFrame(float)} + :return: dict{[float]} """ results = {} if cte.HOUR in self.heating_demand: monthly_values = PeakLoads().\ - peak_loads_from_hourly(self.heating_demand[cte.HOUR][next(iter(self.heating_demand[cte.HOUR]))]) + peak_loads_from_hourly(self.heating_demand[cte.HOUR]) else: monthly_values = PeakLoads(self).heating_peak_loads_from_methodology if monthly_values is None: @@ -446,11 +446,11 @@ class Building(CityObject): def cooling_peak_load(self) -> Union[None, dict]: """ Get cooling peak load in W - :return: dict{DataFrame(float)} + :return: dict{[float]} """ results = {} if cte.HOUR in self.cooling_demand: - monthly_values = PeakLoads().peak_loads_from_hourly(self.cooling_demand[cte.HOUR][next(iter(self.cooling_demand[cte.HOUR]))]) + monthly_values = PeakLoads().peak_loads_from_hourly(self.cooling_demand[cte.HOUR]) else: monthly_values = PeakLoads(self).cooling_peak_loads_from_methodology if monthly_values is None: @@ -614,7 +614,8 @@ class Building(CityObject): """ if len(self._heating_consumption) == 0: for heating_demand_key in self.heating_demand: - demand = self.heating_demand[heating_demand_key][cte.INSEL_MEB] + demand = self.heating_demand[heating_demand_key] + print('AAAAAAAAAA', heating_demand_key, demand) consumption_type = cte.HEATING final_energy_consumed = self._calculate_consumption(consumption_type, demand) if final_energy_consumed is None: @@ -630,7 +631,7 @@ class Building(CityObject): """ if len(self._cooling_consumption) == 0: for cooling_demand_key in self.cooling_demand: - demand = self.cooling_demand[cooling_demand_key][cte.INSEL_MEB] + demand = self.cooling_demand[cooling_demand_key] consumption_type = cte.COOLING final_energy_consumed = self._calculate_consumption(consumption_type, demand) if final_energy_consumed is None: @@ -646,7 +647,7 @@ class Building(CityObject): """ if len(self._domestic_hot_water_consumption) == 0: for domestic_hot_water_demand_key in self.domestic_hot_water_heat_demand: - demand = self.domestic_hot_water_heat_demand[domestic_hot_water_demand_key][cte.INSEL_MEB] + demand = self.domestic_hot_water_heat_demand[domestic_hot_water_demand_key] consumption_type = cte.DOMESTIC_HOT_WATER final_energy_consumed = self._calculate_consumption(consumption_type, demand) if final_energy_consumed is None: @@ -677,7 +678,7 @@ class Building(CityObject): _total_hours = 0 for key in _working_hours: hours = sum(_working_hours[key]) - _total_hours += hours * cte.DAYS_A_YEAR[key] + _total_hours += hours * cte.WEEK_DAYS_A_YEAR[key] return _total_hours @property @@ -710,8 +711,8 @@ class Building(CityObject): if _peak_load_type == cte.HEATING.lower(): _consumption_fix_flow = distribution_system.distribution_consumption_fix_flow for heating_demand_key in self.heating_demand: - _consumption = [0]*len(self.heating_demand[heating_demand_key][cte.INSEL_MEB]) - _demand = self.heating_demand[heating_demand_key][cte.INSEL_MEB] + _consumption = [0]*len(self.heating_demand[heating_demand_key]) + _demand = self.heating_demand[heating_demand_key] for i, _ in enumerate(_consumption): _consumption[i] += (parasitic_energy_consumption + consumption_variable_flow) * _demand[i] self._distribution_systems_electrical_consumption[heating_demand_key] = _consumption @@ -720,7 +721,7 @@ class Building(CityObject): _consumption_fix_flow = distribution_system.distribution_consumption_fix_flow for demand_key in self.cooling_demand: _consumption = self._distribution_systems_electrical_consumption[demand_key] - _demand = self.cooling_demand[demand_key][cte.INSEL_MEB] + _demand = self.cooling_demand[demand_key] for i, _ in enumerate(_consumption): _consumption[i] += (parasitic_energy_consumption + consumption_variable_flow) * _demand[i] self._distribution_systems_electrical_consumption[demand_key] = _consumption @@ -780,12 +781,12 @@ class Building(CityObject): _efficiency = energy_system.generation_system.generic_generation_system.electricity_efficiency self._onsite_electrical_production = {} for _key in self.roofs[0].global_irradiance.keys(): - _results = [0 for _ in range(0, len(self.roofs[0].global_irradiance[_key][cte.SRA]))] + _results = [0 for _ in range(0, len(self.roofs[0].global_irradiance[_key]))] for surface in self.roofs: if _key in orientation_losses_factor: _results = [x + y * _efficiency * surface.perimeter_area * surface.solar_collectors_area_reduction_factor * z - for x, y, z in zip(_results, surface.global_irradiance[_key][cte.SRA], + for x, y, z in zip(_results, surface.global_irradiance[_key], orientation_losses_factor[_key]['south'])] self._onsite_electrical_production[_key] = _results return self._onsite_electrical_production diff --git a/hub/city_model_structure/building_demand/surface.py b/hub/city_model_structure/building_demand/surface.py index 3b0113aa..1d34b6ba 100644 --- a/hub/city_model_structure/building_demand/surface.py +++ b/hub/city_model_structure/building_demand/surface.py @@ -179,7 +179,7 @@ class Surface: def global_irradiance(self) -> dict: """ Get global irradiance on surface in Wh/m2 - :return: dict{DataFrame(float)} + :return: dict """ return self._global_irradiance @@ -187,7 +187,7 @@ class Surface: def global_irradiance(self, value): """ Set global irradiance on surface in Wh/m2 - :param value: dict{DataFrame(float)} + :param value: dict """ self._global_irradiance = value diff --git a/hub/city_model_structure/city.py b/hub/city_model_structure/city.py index 44d72414..a723b56c 100644 --- a/hub/city_model_structure/city.py +++ b/hub/city_model_structure/city.py @@ -25,7 +25,6 @@ from hub.city_model_structure.building import Building from hub.city_model_structure.buildings_cluster import BuildingsCluster from hub.city_model_structure.city_object import CityObject from hub.city_model_structure.city_objects_cluster import CityObjectsCluster -from hub.city_model_structure.energy_system import EnergySystem from hub.city_model_structure.iot.station import Station from hub.city_model_structure.level_of_detail import LevelOfDetail from hub.city_model_structure.parts_consisting_building import PartsConsistingBuilding @@ -163,9 +162,6 @@ class City: if self.buildings is not None: for building in self.buildings: self._city_objects.append(building) - if self.energy_systems is not None: - for energy_system in self.energy_systems: - self._city_objects.append(energy_system) return self._city_objects @property @@ -409,14 +405,6 @@ class City: """ return self._parts_consisting_buildings - @property - def energy_systems(self) -> Union[List[EnergySystem], None]: - """ - Get energy systems belonging to the city - :return: None or [EnergySystem] - """ - return self._energy_systems - @property def stations(self) -> [Station]: """ @@ -478,12 +466,12 @@ class City: parameter_city_building_total_radiation = 0 for surface in building.surfaces: if surface.global_irradiance: - parameter_city_building_total_radiation += surface.global_irradiance[cte.YEAR].iloc[0, 0] + parameter_city_building_total_radiation += surface.global_irradiance[cte.YEAR][0] merged_city_building_total_radiation = 0 for surface in merged_city.city_object(building.name).surfaces: if surface.global_irradiance: - merged_city_building_total_radiation += surface.global_irradiance[cte.YEAR].iloc[0, 0] + merged_city_building_total_radiation += surface.global_irradiance[cte.YEAR][0] if merged_city_building_total_radiation == 0: merged_city.remove_city_object(merged_city.city_object(building.name)) diff --git a/hub/city_model_structure/city_object.py b/hub/city_model_structure/city_object.py index 2c3a6be0..4782b346 100644 --- a/hub/city_model_structure/city_object.py +++ b/hub/city_model_structure/city_object.py @@ -172,7 +172,7 @@ class CityObject: def external_temperature(self) -> {float}: """ Get external temperature surrounding the city object in Celsius - :return: dict{DataFrame(float)} + :return: dict{dict{[float]}} """ return self._external_temperature @@ -180,11 +180,10 @@ class CityObject: def external_temperature(self, value): """ Set external temperature surrounding the city object in Celsius - :param value: dict{DataFrame(float)} + :param value: dict{dict{[float]}} """ self._external_temperature = value - # todo: this is the new format we will use to get rid of the data frames @property def ground_temperature(self) -> dict: """ @@ -206,7 +205,7 @@ class CityObject: def global_horizontal(self) -> dict: """ Get global horizontal radiation surrounding the city object in W/m2 - :return: dict{DataFrame(float)} + :return: dict{dict{[float]}} """ return self._global_horizontal @@ -214,7 +213,7 @@ class CityObject: def global_horizontal(self, value): """ Set global horizontal radiation surrounding the city object in W/m2 - :param value: dict{DataFrame(float)} + :param value: dict{dict{[float]}} """ self._global_horizontal = value @@ -222,7 +221,7 @@ class CityObject: def diffuse(self) -> dict: """ Get diffuse radiation surrounding the city object in W/m2 - :return: dict{DataFrame(float)} + :return: dict{dict{[float]}} """ return self._diffuse @@ -230,7 +229,7 @@ class CityObject: def diffuse(self, value): """ Set diffuse radiation surrounding the city object in W/m2 - :param value: dict{DataFrame(float)} + :param value: dict{dict{[float]}} """ self._diffuse = value @@ -238,7 +237,7 @@ class CityObject: def beam(self) -> dict: """ Get beam radiation surrounding the city object in W/m2 - :return: dict{DataFrame(float)} + :return: dict{dict{[float]}} """ return self._beam @@ -246,7 +245,7 @@ class CityObject: def beam(self, value): """ Set beam radiation surrounding the city object in W/m2 - :param value: dict{DataFrame(float)} + :param value: dict{dict{[float]}} """ self._beam = value diff --git a/hub/city_model_structure/energy_system.py b/hub/city_model_structure/energy_system.py deleted file mode 100644 index d7cf1a25..00000000 --- a/hub/city_model_structure/energy_system.py +++ /dev/null @@ -1,65 +0,0 @@ -""" -EnergySystem module -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2022 Concordia CERC group -Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca -Code contributors: Peter Yefi peteryefi@gmail.com -""" - -from hub.city_model_structure.city_object import CityObject -from hub.city_model_structure.energy_systems.air_source_hp import AirSourceHP -from hub.city_model_structure.energy_systems.water_to_water_hp import WaterToWaterHP - - -class EnergySystem(CityObject): - """ - EnergySystem(CityObject) class - """ - - def __init__(self, name, surfaces): - super().__init__(name, surfaces) - self._air_source_hp = None - self._water_to_water_hp = None - self._type = 'energy_system' - - @property - def air_source_hp(self) -> AirSourceHP: - """ - Heat pump energy system - :return: - """ - return self._air_source_hp - - @air_source_hp.setter - def air_source_hp(self, value): - """ - Set heat pump for energy system - :param value: AirSourceHP - """ - if self._air_source_hp is None: - self._air_source_hp = value - - @property - def water_to_water_hp(self) -> WaterToWaterHP: - """ - Water to water heat pump energy system - :return: - """ - return self._water_to_water_hp - - @water_to_water_hp.setter - def water_to_water_hp(self, value): - """ - Set water to water heat pump for energy system - :param value: WaterToWaterHP - """ - if self._water_to_water_hp is None: - self._water_to_water_hp = value - - @property - def type(self) -> str: - """ - Type of city object - :return: str - """ - return self._type diff --git a/hub/city_model_structure/energy_systems/air_source_hp.py b/hub/city_model_structure/energy_systems/air_source_hp.py deleted file mode 100644 index 8f730124..00000000 --- a/hub/city_model_structure/energy_systems/air_source_hp.py +++ /dev/null @@ -1,132 +0,0 @@ -""" -air_source_hp module defines an air source heat pump -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2022 Concordia CERC group -Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca -Code contributors: Peter Yefi peteryefi@gmail.com -""" - -from typing import List -from hub.city_model_structure.energy_systems.heat_pump import HeatPump - - -class AirSourceHP(HeatPump): - """ - AirSourceHP class - """ - - def __init__(self): - super().__init__() - self._cooling_capacity = None - self._cooling_comp_power = None - self._cooling_capacity_coff = None # a coefficients for insel - self._heating_capacity = None - self._heating_comp_power = None - self._heating_capacity_coff = None - - @property - def cooling_capacity(self) -> List[float]: - """ - Get cooling capacity in kW - :return: [[float]] - """ - return self._cooling_capacity - - @cooling_capacity.setter - def cooling_capacity(self, value): - """ - Set cooling capacity in kW - :param value: [[float]] - """ - if self._cooling_capacity is None: - self._cooling_capacity = value - - @property - def cooling_comp_power(self) -> List[float]: - """ - Get cooling compressor power input in kW - :return: [[float]] - """ - return self._cooling_comp_power - - @cooling_comp_power.setter - def cooling_comp_power(self, value): - """ - Set the cooling compressor in kW - :param value: [[float]] - :return: - """ - if self._cooling_comp_power is None: - self._cooling_comp_power = value - - @property - def cooling_capacity_coff(self) -> List[float]: - """ - Get cooling capacity coefficients - :return: [float] - """ - return self._cooling_capacity_coff - - @cooling_capacity_coff.setter - def cooling_capacity_coff(self, value): - """ - Set the value for cooling capacity coefficients - :param value: [float] - :return: - """ - if self._cooling_capacity_coff is None: - self._cooling_capacity_coff = value - - @property - def heating_capacity(self) -> List[float]: - """ - Get heating capacity kW - :return: [[float]] - """ - return self._heating_capacity - - @heating_capacity.setter - def heating_capacity(self, value): - """ - Set the heating capacity in kW - :param value: [[float]] - :return: - """ - if self._heating_capacity is None: - self._heating_capacity = value - - @property - def heating_comp_power(self) -> List[float]: - """ - Get heating compressor power kW - :return: [[float]] - """ - return self._heating_comp_power - - @heating_comp_power.setter - def heating_comp_power(self, value): - """ - Set the heating compressor power in kW - :param value: [[float]] - :return: - """ - if self._heating_comp_power is None: - self._heating_comp_power = value - - @property - def heating_capacity_coff(self) -> List[float]: - """ - Get heating capacity coefficients - :return: [float] - """ - return self._heating_capacity_coff - - @heating_capacity_coff.setter - def heating_capacity_coff(self, value): - """ - Set the value for heating capacity coefficients - :param value: [float] - :return: - """ - if self._heating_capacity_coff is None: - self._heating_capacity_coff = value diff --git a/hub/city_model_structure/energy_systems/water_to_water_hp.py b/hub/city_model_structure/energy_systems/water_to_water_hp.py deleted file mode 100644 index e0de7bad..00000000 --- a/hub/city_model_structure/energy_systems/water_to_water_hp.py +++ /dev/null @@ -1,131 +0,0 @@ -""" -water_to_water_hp module defines a water to water heat pump heat pump -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2022 Concordia CERC group -Project Coder Peter Yefi peteryefi@gmail.com -""" - -from typing import List -from hub.city_model_structure.energy_systems.heat_pump import HeatPump - - -class WaterToWaterHP(HeatPump): - """ - WaterToWaterHP class - """ - - def __init__(self): - super().__init__() - self._entering_water_temp = None - self._leaving_water_temp = None - self._total_cooling_capacity = None - self._power_demand = None - self._flow_rate = None - self._power_demand_coff = None # a coefficients - - @property - def entering_water_temp(self) -> List[float]: - """ - Get entering water temperature in degree celsius - :return: [[float]] - """ - return self._entering_water_temp - - @entering_water_temp.setter - def entering_water_temp(self, value): - """ - Set entering water temperature in degree celsius - :param value: [[float]] - """ - if self._entering_water_temp is None: - self._entering_water_temp = value - - @property - def leaving_water_temp(self) -> List[float]: - """ - Get leaving water temperature in degree celsius - :return: [[float]] - """ - return self._leaving_water_temp - - @leaving_water_temp.setter - def leaving_water_temp(self, value): - """ - Set the leaving water temperature in degree celsius - :param value: [[float]] - :return: - """ - if self._leaving_water_temp is None: - self._leaving_water_temp = value - - @property - def total_cooling_capacity(self) -> List[float]: - """ - Get total cooling capacity - :return: [float] - """ - return self._total_cooling_capacity - - @total_cooling_capacity.setter - def total_cooling_capacity(self, value): - """ - Set the value for total cooling capacity - :param value: [float] - :return: - """ - if self._total_cooling_capacity is None: - self._total_cooling_capacity = value - - @property - def power_demand(self) -> List[float]: - """ - Get power demand in kW - :return: [float] - """ - return self._power_demand - - @power_demand.setter - def power_demand(self, value): - """ - Set the value for power demand in kW - :param value: [float] - :return: - """ - if self._power_demand is None: - self._power_demand = value - - @property - def flow_rate(self) -> List[float]: - """ - Get flow rate in kg/s - :return: [[float]] - """ - return self._flow_rate - - @flow_rate.setter - def flow_rate(self, value): - """ - Set flow rate in kW - :param value: [[float]] - :return: - """ - if self._flow_rate is None: - self._flow_rate = value - - @property - def power_demand_coff(self) -> List[float]: - """ - Get power demand coefficients - :return: [float] - """ - return self._power_demand_coff - - @power_demand_coff.setter - def power_demand_coff(self, value): - """ - Set the value for power demand coefficients - :param value: [float] - :return: - """ - if self._power_demand_coff is None: - self._power_demand_coff = value diff --git a/hub/exports/building_energy/idf.py b/hub/exports/building_energy/idf.py index 898beb55..df55aa4e 100644 --- a/hub/exports/building_energy/idf.py +++ b/hub/exports/building_energy/idf.py @@ -533,7 +533,7 @@ class Idf: self._add_schedules(usage, 'Appliance', thermal_zone.appliances.schedules) self._add_schedules(usage, 'DHW_prof', thermal_zone.domestic_hot_water.schedules) _new_schedules = self._create_yearly_values_schedules('cold_temp', - building.cold_water_temperature[cte.HOUR]['epw']) + building.cold_water_temperature[cte.HOUR]) self._add_schedules(building.name, 'cold_temp', _new_schedules) value = thermal_zone.domestic_hot_water.service_temperature _new_schedules = self._create_constant_value_schedules('DHW_temp', value) diff --git a/hub/exports/building_energy/insel/insel_monthly_energy_balance.py b/hub/exports/building_energy/insel/insel_monthly_energy_balance.py index 7055f55a..1866a37e 100644 --- a/hub/exports/building_energy/insel/insel_monthly_energy_balance.py +++ b/hub/exports/building_energy/insel/insel_monthly_energy_balance.py @@ -30,13 +30,11 @@ class InselMonthlyEnergyBalance: """ Insel monthly energy balance class """ - def __init__(self, city, path, custom_insel_block, radiation_calculation_method='sra', weather_format='epw'): + def __init__(self, city, path, custom_insel_block): self._city = city self._path = path self._custom_insel_block = custom_insel_block self._results = None - self._radiation_calculation_method = radiation_calculation_method - self._weather_format = weather_format self._contents = [] self._insel_files_paths = [] self._sanity_check() @@ -48,7 +46,7 @@ class InselMonthlyEnergyBalance: logging.warning('Building %s has missing values. Monthly Energy Balance cannot be processed', building.name) self._contents.append( - self._generate_meb_template(building, output_path, self._radiation_calculation_method, self._weather_format, self._custom_insel_block) + self._generate_meb_template(building, output_path, self._custom_insel_block) ) self._export() @@ -96,7 +94,7 @@ class InselMonthlyEnergyBalance: f'Required minimum level 1') @staticmethod - def _generate_meb_template(building, insel_outputs_path, radiation_calculation_method, weather_format, custom_insel_block): + def _generate_meb_template(building, insel_outputs_path, custom_insel_block): file = "" i_block = 1 parameters = ["1", "12", "1"] @@ -148,7 +146,7 @@ class InselMonthlyEnergyBalance: total_values = sum(schedule.values) total_hours = 0 for day_type in schedule.day_types: - total_hours += cte.DAYS_A_YEAR[day_type] / 365 / 24 + total_hours += cte.WEEK_DAYS_A_YEAR[day_type] / 365 / 24 total_values *= total_hours total_internal_gain += internal_gain * total_values @@ -181,8 +179,8 @@ class InselMonthlyEnergyBalance: ventilation_day += 0 infiltration_day += infiltration_value / 24 for day_type in schedule.day_types: - infiltration += infiltration_day * cte.DAYS_A_YEAR[day_type] / 365 - ventilation += ventilation_day * cte.DAYS_A_YEAR[day_type] / 365 + infiltration += infiltration_day * cte.WEEK_DAYS_A_YEAR[day_type] / 365 + ventilation += ventilation_day * cte.WEEK_DAYS_A_YEAR[day_type] / 365 ventilation_infiltration = ventilation + infiltration parameters.append(f'{ventilation_infiltration} % BP(18) #8 Minimum air change rate zone {i + 1} (ACH)') @@ -230,7 +228,6 @@ class InselMonthlyEnergyBalance: parameters.append(thermal_boundary.parent_surface.short_wave_reflectance) else: parameters.append(0.0) - file = InselMonthlyEnergyBalance._add_block(file, i_block, custom_insel_block, inputs=inputs, parameters=parameters) i_block = 20 @@ -238,9 +235,8 @@ class InselMonthlyEnergyBalance: parameters = ['12 % Monthly ambient temperature (degree Celsius)'] external_temperature = building.external_temperature[cte.MONTH] - for i in range(0, len(external_temperature)): - parameters.append(f'{i + 1} {external_temperature.at[i, weather_format]}') + parameters.append(f'{i + 1} {external_temperature[i]}') file = InselMonthlyEnergyBalance._add_block(file, i_block, 'polyg', inputs=inputs, parameters=parameters) @@ -248,12 +244,11 @@ class InselMonthlyEnergyBalance: inputs = ['1'] parameters = ['12 % Monthly sky temperature'] - sky_temperature = Weather.sky_temperature(external_temperature[[weather_format]].to_numpy().T[0]) + sky_temperature = Weather.sky_temperature(external_temperature) for i, temperature in enumerate(sky_temperature): parameters.append(f'{i + 1} {temperature}') file = InselMonthlyEnergyBalance._add_block(file, i_block, 'polyg', inputs=inputs, parameters=parameters) - for i, surface in enumerate(surfaces): i_block = 101 + i inputs = ['1 % Monthly surface radiation (W/m2)'] @@ -266,7 +261,7 @@ class InselMonthlyEnergyBalance: global_irradiance = surface.global_irradiance[cte.MONTH] for j in range(0, len(global_irradiance)): parameters.append(f'{j + 1} ' - f'{global_irradiance.at[j, radiation_calculation_method] / 24 / _NUMBER_DAYS_PER_MONTH[j]}') + f'{global_irradiance[j] / 24 / _NUMBER_DAYS_PER_MONTH[j]}') else: for j in range(0, 12): parameters.append(f'{j + 1} 0.0') @@ -290,5 +285,4 @@ class InselMonthlyEnergyBalance: f"'{str(insel_outputs_path)}' % File name", "'*' % Fortran format"] file = InselMonthlyEnergyBalance._add_block(file, i_block, 'WRITE', inputs=inputs, parameters=parameters) - return file diff --git a/hub/exports/formats/simplified_radiosity_algorithm.py b/hub/exports/formats/simplified_radiosity_algorithm.py index d5a0a005..538a863b 100644 --- a/hub/exports/formats/simplified_radiosity_algorithm.py +++ b/hub/exports/formats/simplified_radiosity_algorithm.py @@ -66,8 +66,8 @@ class SimplifiedRadiosityAlgorithm: else: i = (total_days + day - 1) * 24 + hour - 1 representative_building = self._city.buildings[0] - content += f'{day} {month} {hour} {representative_building.global_horizontal[cte.HOUR].epw[i]} ' \ - f'{representative_building.beam[cte.HOUR].epw[i]}\n' + content += f'{day} {month} {hour} {representative_building.global_horizontal[cte.HOUR][i]} ' \ + f'{representative_building.beam[cte.HOUR][i]}\n' with open(file, 'w', encoding='utf-8') as file: file.write(content) diff --git a/hub/helpers/constants.py b/hub/helpers/constants.py index 2810c2d7..2c84b587 100644 --- a/hub/helpers/constants.py +++ b/hub/helpers/constants.py @@ -48,23 +48,36 @@ WEEK_DAYS = 'Weekdays' WEEK_ENDS = 'Weekends' ALL_DAYS = 'Alldays' -DAYS_A_MONTH = {'monday': [5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 5], - 'tuesday': [5, 4, 4, 4, 5, 4, 5, 4, 4, 5, 4, 4], - 'wednesday': [5, 4, 4, 4, 5, 4, 4, 5, 4, 5, 4, 4], - 'thursday': [4, 4, 5, 4, 5, 4, 4, 5, 4, 4, 5, 4], - 'friday': [4, 4, 5, 4, 4, 5, 4, 5, 4, 4, 5, 4], - 'saturday': [4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5], - 'sunday': [4, 4, 4, 5, 4, 4, 5, 4, 5, 4, 4, 5], - 'holiday': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]} +WEEK_DAYS_A_MONTH = {'monday': [5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 5], + 'tuesday': [5, 4, 4, 4, 5, 4, 5, 4, 4, 5, 4, 4], + 'wednesday': [5, 4, 4, 4, 5, 4, 4, 5, 4, 5, 4, 4], + 'thursday': [4, 4, 5, 4, 5, 4, 4, 5, 4, 4, 5, 4], + 'friday': [4, 4, 5, 4, 4, 5, 4, 5, 4, 4, 5, 4], + 'saturday': [4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5], + 'sunday': [4, 4, 4, 5, 4, 4, 5, 4, 5, 4, 4, 5], + 'holiday': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]} -DAYS_A_YEAR = {'monday': 51, - 'tuesday': 50, - 'wednesday': 50, - 'thursday': 50, - 'friday': 50, - 'saturday': 52, - 'sunday': 52, - 'holiday': 10} +WEEK_DAYS_A_YEAR = {'monday': 51, + 'tuesday': 50, + 'wednesday': 50, + 'thursday': 50, + 'friday': 50, + 'saturday': 52, + 'sunday': 52, + 'holiday': 10} + +DAYS_A_MONTH = {'January': 31, + 'February': 28, + 'March': 31, + 'April': 30, + 'May': 31, + 'June': 30, + 'July': 31, + 'August': 31, + 'September': 30, + 'October': 31, + 'November': 30, + 'December': 31} # data types ANY_NUMBER = 'any_number' diff --git a/hub/helpers/monthly_values.py b/hub/helpers/monthly_values.py index cfab31bf..9544f4a5 100644 --- a/hub/helpers/monthly_values.py +++ b/hub/helpers/monthly_values.py @@ -3,55 +3,46 @@ Monthly values module SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2020 Project Author Pilar Monsalvete pilar_monsalvete@yahoo.es """ -import calendar as cal -import pandas as pd -import numpy as np + +import hub.helpers.constants as cte class MonthlyValues: """ Monthly values class """ - def __init__(self): - self._month_hour = None - - def get_mean_values(self, values): + @staticmethod + def get_mean_values(values): """ - Calculates the mean values for each month - :return: DataFrame(float) + Calculates the mean values for each month from a list with hourly values + :return: [float] x 12 + :param values: [float] x 8760 """ - out = None + out = [] if values is not None: - if 'month' not in values.columns: - values = pd.concat([self.month_hour, pd.DataFrame(values)], axis=1) - out = values.groupby('month', as_index=False).mean() - del out['month'] + for month in cte.DAYS_A_MONTH: + total = 0 + for j in range(0, cte.DAYS_A_MONTH[month]): + for k in range(0, 24): + hour = k + 24 * j + cte.DAYS_A_MONTH[month] - 31 + total += values[hour] / 24 / cte.DAYS_A_MONTH[month] + out.append(total) return out - def get_total_month(self, values): + @staticmethod + def get_total_month(values): """ Calculates the total value for each month - :return: DataFrame(int) + :return: [float] x 12 + :param values: [float] x 8760 """ - out = None + out = [] if values is not None: - if 'month' not in values.columns: - values = pd.concat([self.month_hour, pd.DataFrame(values)], axis=1) - out = pd.DataFrame(values).groupby('month', as_index=False).sum() - del out['month'] + for month in cte.DAYS_A_MONTH: + total = 0 + for j in range(0, cte.DAYS_A_MONTH[month]): + for k in range(0, 24): + hour = k + 24 * j + cte.DAYS_A_MONTH[month] - 31 + total += values[hour] + out.append(total) return out - - @property - def month_hour(self): - """ - returns a DataFrame that has x values of the month number (January = 1, February = 2...), - being x the number of hours of the corresponding month - :return: DataFrame(int) - """ - array = [] - for i in range(0, 12): - days_of_month = cal.monthrange(2015, i+1)[1] - total_hours = days_of_month * 24 - array = np.concatenate((array, np.full(total_hours, i + 1))) - self._month_hour = pd.DataFrame(array, columns=['month']) - return self._month_hour diff --git a/hub/helpers/peak_calculation/loads_calculation.py b/hub/helpers/peak_calculation/loads_calculation.py index 5a18867b..75baaf31 100644 --- a/hub/helpers/peak_calculation/loads_calculation.py +++ b/hub/helpers/peak_calculation/loads_calculation.py @@ -132,7 +132,7 @@ class LoadsCalculation: internal_load = cooling_load_occupancy_sensible + cooling_load_lighting + cooling_load_equipment_sensible return internal_load - def get_radiation_load(self, irradiance_format, hour): + def get_radiation_load(self, hour): """ Calculates the radiation load :return: int @@ -142,7 +142,7 @@ class LoadsCalculation: for thermal_zone in internal_zone.thermal_zones: for thermal_boundary in thermal_zone.thermal_boundaries: for thermal_opening in thermal_boundary.thermal_openings: - radiation = thermal_boundary.parent_surface.global_irradiance[cte.HOUR][irradiance_format][hour] + radiation = thermal_boundary.parent_surface.global_irradiance[cte.HOUR][hour] cooling_load_radiation += ( thermal_opening.area * (1 - thermal_opening.frame_ratio) * thermal_opening.g_value * radiation ) diff --git a/hub/helpers/peak_loads.py b/hub/helpers/peak_loads.py index e46a8b51..995e2ada 100644 --- a/hub/helpers/peak_loads.py +++ b/hub/helpers/peak_loads.py @@ -54,11 +54,13 @@ class PeakLoads: """ month = 1 peaks = [0 for _ in range(12)] - for i, value in enumerate(hourly_values): + print('hv', hourly_values) + for i in range(0, len(hourly_values)): if _MONTH_STARTING_HOUR[month] <= i: month += 1 - if value > peaks[month-1]: - peaks[month-1] = value + if hourly_values[i] > peaks[month-1]: + peaks[month-1] = hourly_values[i] + print('peak', peaks) return peaks @property @@ -70,7 +72,7 @@ class PeakLoads: if not self._can_be_calculated(): return None monthly_heating_loads = [] - ambient_temperature = self._building.external_temperature[cte.HOUR]['epw'] + ambient_temperature = self._building.external_temperature[cte.HOUR] for month in range(0, 12): ground_temperature = self._building.ground_temperature[cte.MONTH]['2'][month] heating_ambient_temperature = 100 @@ -100,7 +102,7 @@ class PeakLoads: if not self._can_be_calculated(): return None monthly_cooling_loads = [] - ambient_temperature = self._building.external_temperature[cte.HOUR]['epw'] + ambient_temperature = self._building.external_temperature[cte.HOUR] for month in range(0, 12): ground_temperature = self._building.ground_temperature[cte.MONTH]['2'][month] cooling_ambient_temperature = -100 @@ -118,7 +120,7 @@ class PeakLoads: cooling_load_transmitted = loads.get_cooling_transmitted_load(cooling_ambient_temperature, ground_temperature) cooling_load_renovation_sensible = loads.get_cooling_ventilation_load_sensible(cooling_ambient_temperature) cooling_load_internal_gains_sensible = loads.get_internal_load_sensible() - cooling_load_radiation = loads.get_radiation_load('sra', cooling_calculation_hour) + cooling_load_radiation = loads.get_radiation_load(cooling_calculation_hour) cooling_load_sensible = cooling_load_transmitted + cooling_load_renovation_sensible - cooling_load_radiation \ - cooling_load_internal_gains_sensible diff --git a/hub/imports/energy_systems/air_source_hp_parameters.py b/hub/imports/energy_systems/air_source_hp_parameters.py deleted file mode 100644 index 829575d6..00000000 --- a/hub/imports/energy_systems/air_source_hp_parameters.py +++ /dev/null @@ -1,147 +0,0 @@ -""" -AirSourceHeatPumpParameters import the heat pump information -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2022 Concordia CERC group -Project Coder Peter Yefi peteryefi@gmail.comCode -contributor Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca -""" -import io - -import itertools -from typing import List -from typing import Dict -import pandas as pd -import numpy as np -from scipy.optimize import curve_fit -from hub.city_model_structure.energy_systems.air_source_hp import AirSourceHP -from hub.city_model_structure.energy_system import EnergySystem - - -class AirSourceHeatPumpParameters: - """ - AirSourceHeatPumpParameters class - """ - - def __init__(self, city, base_path): - self._city = city - self._base_path = (base_path / 'heat_pumps/air_source.xlsx').resolve() - - def _read_file(self) -> Dict: - """ - reads xlsx file containing the heat pump information - into a dictionary - :return : Dict - """ - with open(self._base_path, 'rb') as xls: - xl_file = pd.read_excel(io.BytesIO(xls.read()), sheet_name=None) - - cooling_data = {} - heating_data = {} - - for sheet, _ in xl_file.items(): - if 'Summary' in sheet: - continue - - # Remove nan rows and columns and extract cooling and heating data - # for each sheet - df = xl_file[sheet].dropna(axis=1, how='all') - cooling_df = df.iloc[4:34, 0:8] - heating_df = df.iloc[4:29, 8:20] - - # extract the data into dictionaries each sheet is a key entry in the - # dictionary - cooling_data[sheet] = {} - heating_data[sheet] = {} - i = 0 - # for each sheet extract data for twout/Ta.RU temperatures. Thus, the twout - # temp is the key for the values of pf,pa,qw data - while i < 25: - cooling_data[sheet][cooling_df.iloc[i][0]] = cooling_df.iloc[i + 1:i + 4, 2:8].values.tolist() - heating_data[sheet][heating_df.iloc[i][0]] = heating_df.iloc[i + 1:i + 4, 2:8].values.tolist() - i = i + 5 - # extract the last cooling data - cooling_data[sheet][cooling_df.iloc[i][0]] = cooling_df.iloc[i + 1:i + 4, 2:8].values.tolist() - return {"cooling": cooling_data, "heating": heating_data} - - def enrich_city(self): - """ - Enriches the city with information from file - """ - heat_pump_data = self._read_file() - for (k_cool, v_cool), (_, v_heat) in zip(heat_pump_data["cooling"].items(), heat_pump_data["heating"].items()): - heat_pump = AirSourceHP() - heat_pump.model = k_cool - h_data = self._extract_heat_pump_data(v_heat) - c_data = self._extract_heat_pump_data(v_cool) - heat_pump.cooling_capacity = c_data[0] - heat_pump.cooling_comp_power = c_data[1] - heat_pump.cooling_capacity_coff = self._compute_coefficients(c_data, "cool") - heat_pump.heating_capacity = h_data[0] - heat_pump.heating_comp_power = h_data[1] - heat_pump.heating_capacity_coff = self._compute_coefficients(h_data) - - energy_system = EnergySystem(f'{heat_pump.model} capacity heat pump', []) - energy_system.air_source_hp = heat_pump - self._city.add_city_object(energy_system) - return self._city - - @staticmethod - def _extract_heat_pump_data(heat_pump_capacity_data: Dict) -> [List, List]: - """ - Fetches a list of metric based data for heat pump for various temperature, - e.g. cooling capacity data for 12 capacity heat pump - for 6,7,8,9,10 and 11 degree Celsius - :param heat_pump_capacity_data: the heat pump capacity data from the - which the metric specific data is fetched: {List} - :return: List - """ - cooling_heating_capacity_data = [] - compressor_power_data = [] - for _, metric_data in heat_pump_capacity_data.items(): - cooling_heating_capacity_data.append(metric_data[0]) - compressor_power_data.append(metric_data[1]) - return [cooling_heating_capacity_data, compressor_power_data] - - def _compute_coefficients(self, heat_pump_data: List, data_type="heat") -> List[float]: - """ - Compute heat output and electrical demand coefficients - from heating and cooling performance data - :param heat_pump_data: a list of heat pump data. e.g. cooling capacity - :param data_type: string to indicate if data is cooling performance data - or heating performance data - :return: Tuple[Dict, Dict] - """ - # Determine the recurrence of temperature values. 6 repetitions for - # cooling performance and 5 repetition for heating performance - temp_multiplier = 5 if data_type == "heat" else 6 - out_temp = [25, 30, 32, 35, 40, 45] * temp_multiplier - - heat_x_values = np.repeat([-5, 0, 7, 10, 15], 6) - cool_x_values = np.repeat([6, 7, 8, 9, 10, 11], 6) - x_values = heat_x_values if data_type == "heat" else cool_x_values - x_values = x_values.tolist() - # convert list of lists to one list - - hp_data = [i / j for i, j in - zip(list(itertools.chain.from_iterable(heat_pump_data[0])), - list(itertools.chain.from_iterable(heat_pump_data[1])))] - - # Compute heat output coefficients - popt, _ = curve_fit(self._objective_function, [x_values, out_temp], hp_data) - return popt.tolist() - - @staticmethod - def _objective_function(xdata: List, a1: float, a2: float, a3: float, a4: float, a5: float, a6: float) -> float: - """ - Objective function for computing coefficients - :param xdata: - :param a1: float - :param a2: float - :param a3: float - :param a4: float - :param a5: float - :param a6: float - :return: - """ - x, y = xdata - return (a1 * x ** 2) + (a2 * x) + (a3 * x * y) + (a4 * y) + (a5 * y ** 2) + a6 diff --git a/hub/imports/energy_systems/helpers/__init__.py b/hub/imports/energy_systems/helpers/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/hub/imports/energy_systems/helpers/energy_systems_helper.py b/hub/imports/energy_systems/helpers/energy_systems_helper.py deleted file mode 100644 index 8cce5273..00000000 --- a/hub/imports/energy_systems/helpers/energy_systems_helper.py +++ /dev/null @@ -1,29 +0,0 @@ -""" -Energy systems helper -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2022 Concordia CERC group -Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca -""" - -from hub.helpers import constants as cte - - -class EnergySystemsHelper: - """ - EnergySystems helper - """ - _montreal_custom_fuel_to_hub_fuel = { - 'gas': cte.GAS, - 'electricity': cte.ELECTRICITY, - 'renewable': cte.RENEWABLE - } - - @staticmethod - def montreal_custom_fuel_to_hub_fuel(fuel): - """ - Get hub fuel from montreal_custom catalog fuel - :param fuel: str - :return: str - """ - return EnergySystemsHelper._montreal_custom_fuel_to_hub_fuel[fuel] - diff --git a/hub/imports/energy_systems/montreal_custom_energy_system_parameters.py b/hub/imports/energy_systems/montreal_custom_energy_system_parameters.py index 42b5bf07..9b3f7a61 100644 --- a/hub/imports/energy_systems/montreal_custom_energy_system_parameters.py +++ b/hub/imports/energy_systems/montreal_custom_energy_system_parameters.py @@ -19,7 +19,6 @@ from hub.city_model_structure.energy_systems.generation_system import Generation from hub.city_model_structure.energy_systems.distribution_system import DistributionSystem from hub.city_model_structure.energy_systems.emission_system import EmissionSystem from hub.helpers.dictionaries import Dictionaries -from hub.imports.energy_systems.helpers.energy_systems_helper import EnergySystemsHelper class MontrealCustomEnergySystemParameters: diff --git a/hub/imports/energy_systems/water_to_water_hp_parameters.py b/hub/imports/energy_systems/water_to_water_hp_parameters.py deleted file mode 100644 index 1a52fcbb..00000000 --- a/hub/imports/energy_systems/water_to_water_hp_parameters.py +++ /dev/null @@ -1,173 +0,0 @@ -""" -WaterToWaterHPParameters import the heat pump information -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2022 Concordia CERC group -Project Coder Peter Yefi peteryefi@gmail.com -""" - -from typing import Dict -from typing import List - -import numpy as np -import pandas as pd -from scipy.optimize import curve_fit - -from hub.city_model_structure.energy_system import EnergySystem -from hub.city_model_structure.energy_systems.water_to_water_hp import WaterToWaterHP - - -class WaterToWaterHPParameters: - """ - WaterToWaterHPParameters class - """ - - def __init__(self, city, base_path): - self._city = city - self._base_path = (base_path / 'heat_pumps/water_to_water.xlsx').resolve() - - def _read_file(self) -> Dict: - # todo: this method is keeping the excel file open and should be either corrected or removed - xl_file = pd.ExcelFile(self._base_path) - heat_pump_dfs = {sheet_name: xl_file.parse(sheet_name) - for sheet_name in xl_file.sheet_names} - - hp_data = {} - flow_rates = { - '156': [2.84, 4.23, 5.68], - '256': [4.73, 7.13, 9.446], - '335': [6.62, 9.97, 12.93], - } - - for sheet, _ in heat_pump_dfs.items(): - - df = heat_pump_dfs[sheet].dropna(axis=1, how='all') - df = df.iloc[3:, 6:35] - - if '156' in sheet: - hp_data[sheet] = self._extract_required_hp_data(df, [0, 10, 25, 40, 55, 67], flow_rates['156']) - elif '256' in sheet: - hp_data[sheet] = self._extract_required_hp_data(df, [0, 9, 24, 39, 54, 66], flow_rates['256']) - elif '335' in sheet: - hp_data[sheet] = self._extract_required_hp_data(df, [0, 11, 26, 41, 56, 69], flow_rates['335']) - - return hp_data - - def _extract_required_hp_data(self, dataframe, ranges, flow_rates): - """ - Extracts 156 Kw water to water heat pump data - :param dataframe: dataframe containing all data - :param ranges: the range of values to extract - :param flow_rates: the flow rates of water through pump - :return: Dict - """ - # extract data rows and columns - data = {'tc': self._extract_hp_data(dataframe, [1, 11, 21], ranges), - 'pd': self._extract_hp_data(dataframe, [2, 12, 22], ranges), - 'lwt': self._extract_hp_data(dataframe, [5, 15, 25], ranges), - 'fr': (self._extract_flow_and_ewt(dataframe, ranges, [1, 11, 21], flow_rates))[0], - 'ewt': (self._extract_flow_and_ewt(dataframe, ranges, [1, 11, 21], flow_rates))[1]} - # range values for extracting data - return data - - @staticmethod - def _extract_hp_data(df, columns, ranges): - """ - Extract variable specific (LWT, PD or TC) data from water to water hp - :param df: the dataframe - :param columns: the columns to extract data from - :param ranges: the range of values to extract - :return: List - """ - data = pd.concat([df.iloc[ranges[0]:ranges[1], columns[0]], df.iloc[ranges[0]:ranges[1], columns[1]]]) - data = pd.concat([df.iloc[ranges[0]:ranges[1], columns[2]], data]) - for i in range(1, 5): - data = pd.concat([df.iloc[ranges[i]:ranges[i + 1], columns[0]], data]) - data = pd.concat([df.iloc[ranges[i]:ranges[i + 1], columns[1]], data]) - data = pd.concat([df.iloc[ranges[i]:ranges[i + 1], columns[2]], data]) - - return data.dropna().values.tolist() - - @staticmethod - def _extract_flow_and_ewt(df, ranges, columns, flow_rates): - """ - Create the flow and ewt data based on the length of the various - columns for the variables being extracted - :param df: the dataframe - :param ranges: the range of values to extract - :param columns: the columns to extract data from - :param flow_rates: flow rate values - :return: - """ - ewt_values = [-1.111111111, 4.444444444, 10, 15.55555556, 21.11111111] - length = [len(df.iloc[ranges[0]:ranges[1], columns[0]].dropna()), - len(df.iloc[ranges[0]:ranges[1], columns[1]].dropna()), - len(df.iloc[ranges[0]:ranges[1], columns[2]].dropna())] - - ewt_data = np.repeat(ewt_values[0], sum(length)) - flow_rates_data = np.repeat(flow_rates, length) - - for i in range(1, 5): - length = [len(df.iloc[ranges[i]:ranges[i + 1], columns[0]].dropna()), - len(df.iloc[ranges[i]:ranges[i + 1], columns[1]].dropna()), - len(df.iloc[ranges[i]:ranges[i + 1], columns[2]].dropna())] - flow_rates_data = np.append(flow_rates_data, np.repeat(flow_rates, length)) - ewt_data = np.append(ewt_data, np.repeat(ewt_values[i], sum(length))) - - return flow_rates_data.tolist(), ewt_data.tolist() - - def enrich_city(self): - """ - Enriches the city with information from file - """ - heap_pump_data = self._read_file() - for model, data in heap_pump_data.items(): - heat_pump = WaterToWaterHP() - heat_pump.model = model.strip() - heat_pump.total_cooling_capacity = data['tc'] - heat_pump.power_demand = data['pd'] - heat_pump.flow_rate = data['fr'] - heat_pump.entering_water_temp = data['ewt'] - heat_pump.leaving_water_temp = data['lwt'] - heat_pump.power_demand_coff = self._compute_coefficients(data) - energy_system = EnergySystem(heat_pump.model, []) - energy_system.water_to_water_hp = heat_pump - self._city.add_city_object(energy_system) - return self._city - - def _compute_coefficients(self, heat_pump_data: Dict) -> List[float]: - """ - Compute heat output and electrical demand coefficients - from heating performance data - :param heat_pump_data: a dictionary of heat pump data. - :return: Tuple[Dict, Dict] - """ - demand = [i / j for i, j in zip(heat_pump_data['tc'], heat_pump_data['pd'])] - - # Compute heat output coefficients - popt, _ = curve_fit( - self._objective_function, [heat_pump_data['ewt'], heat_pump_data['lwt'], heat_pump_data['fr']], demand - ) - return popt.tolist() - - @staticmethod - def _objective_function(xdata: List, a1: float, a2: float, a3: float, a4: float, a5: float, a6: float, - a7: float, a8: float, a9: float, a10: float, a11: float) -> float: - """ - Objective function for computing coefficients - :param xdata: - :param a1: float - :param a2: float - :param a3: float - :param a4: float - :param a5: float - :param a6: float - :param a7: float - :param a8: float - :param a9: float - :param a10: float - :param a11: float - :return: - """ - x, y, t = xdata - return (a1 * x ** 2) + (a2 * x) + (a3 * y ** 2) + (a4 * y) + (a5 * t ** 2) + (a6 * t) + (a7 * x * y) + ( - a8 * x * t) + (a9 * y * t) + (a10 * x * y * t) + a11 diff --git a/hub/imports/energy_systems_factory.py b/hub/imports/energy_systems_factory.py index c337eecd..ca4e7789 100644 --- a/hub/imports/energy_systems_factory.py +++ b/hub/imports/energy_systems_factory.py @@ -8,9 +8,7 @@ Code contributors: Peter Yefi peteryefi@gmail.com from pathlib import Path from hub.helpers.utils import validate_import_export_type -from hub.imports.energy_systems.air_source_hp_parameters import AirSourceHeatPumpParameters from hub.imports.energy_systems.montreal_custom_energy_system_parameters import MontrealCustomEnergySystemParameters -from hub.imports.energy_systems.water_to_water_hp_parameters import WaterToWaterHPParameters class EnergySystemsFactory: @@ -26,24 +24,6 @@ class EnergySystemsFactory: self._city = city self._base_path = base_path - def _air_source_hp(self): - """ - Enrich the city by using xlsx heat pump information - """ - AirSourceHeatPumpParameters(self._city, self._base_path).enrich_city() - self._city.level_of_detail.energy_systems = 0 - for building in self._city.buildings: - building.level_of_detail.energy_systems = 0 - - def _water_to_water_hp(self): - """ - Enrich the city by using water to water heat pump information - """ - WaterToWaterHPParameters(self._city, self._base_path).enrich_city() - self._city.level_of_detail.energy_systems = 0 - for building in self._city.buildings: - building.level_of_detail.energy_systems = 0 - def _montreal_custom(self): """ Enrich the city by using montreal custom energy systems catalog information diff --git a/hub/imports/geometry/gpandas.py b/hub/imports/geometry/gpandas.py deleted file mode 100644 index b13a648c..00000000 --- a/hub/imports/geometry/gpandas.py +++ /dev/null @@ -1,116 +0,0 @@ -""" -gpandas module parses geopandas input table and import the geometry into the city model structure -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2022 Concordia CERC group -Project Coder: Milad Aghamohamadnia --- milad.aghamohamadnia@concordia.ca -""" - -import trimesh -import trimesh.exchange.load -import trimesh.geometry -import trimesh.creation -import trimesh.repair -from shapely.geometry import Point -from shapely.geometry import Polygon as ShapelyPoly -from trimesh import Scene - -from hub.city_model_structure.attributes.polygon import Polygon -from hub.city_model_structure.building import Building -from hub.city_model_structure.building_demand.surface import Surface -from hub.city_model_structure.city import City - -import hub.helpers.constants as cte - - -class GPandas: - """ - GeoPandas class - """ - - def __init__(self, dataframe, srs_name='EPSG:26911'): - """_summary_ - Arguments: - dataframe {Geopandas.Dataframe} -- input geometry data in geopandas table - Keyword Arguments: - srs_name {str} -- coordinate system of coordinate system (default: {'EPSG:26911'}) - """ - - self._srs_name = srs_name - self._city = None - self._scene = dataframe - self._scene = self._scene.to_crs(self._srs_name) - min_x, min_y, max_x, max_y = self._scene.total_bounds - self._lower_corner = [min_x, min_y, 0] - self._upper_corner = [max_x, max_y, 0] - - @property - def scene(self) -> Scene: - """ - Get GeoPandas scene - """ - return self._scene - - @property - def city(self) -> City: - """ - Get city out of a GeoPandas Table - """ - if self._city is None: - self._city = City(self._lower_corner, self._upper_corner, self._srs_name) - lod = 0 - for _, bldg in self._scene.iterrows(): - polygon = bldg.geometry - height = float(bldg['height']) - building_mesh = trimesh.creation.extrude_polygon(polygon, height) - trimesh.repair.fill_holes(building_mesh) - trimesh.repair.fix_winding(building_mesh) - year_of_construction = int(bldg['year_built']) - name = bldg['name'] - lod = 1 - if year_of_construction > 2000: - function = cte.RESIDENTIAL - else: - function = cte.INDUSTRY - surfaces = [] - for _, face in enumerate(building_mesh.faces): - points = [] - for vertex_index in face: - points.append(building_mesh.vertices[vertex_index]) - solid_polygon = Polygon(points) - perimeter_polygon = solid_polygon - surface = Surface(solid_polygon, perimeter_polygon) - surfaces.append(surface) - building = Building(name, surfaces, year_of_construction, function, terrains=None) - self._city.add_city_object(building) - self._city.level_of_detail.geometry = lod - for building in self._city.buildings: - building.level_of_detail.geometry = lod - return self._city - - @staticmethod - def resize_polygon(poly, factor=0.10, expand=False) -> ShapelyPoly: - """ - returns the shapely polygon which is smaller or bigger by passed factor. - Arguments: - poly {shapely.geometry.Polygon} -- an input geometry in shapely polygon format - - Keyword Arguments: - factor {float} -- factor of expansion (default: {0.10}) - expand {bool} -- If expand = True , then it returns bigger polygon, else smaller (default: {False}) - - Returns: - {shapely.geometry.Polygon} -- output geometry in shapely polygon format - """ - xs = list(poly.exterior.coords.xy[0]) - ys = list(poly.exterior.coords.xy[1]) - x_center = 0.5 * min(xs) + 0.5 * max(xs) - y_center = 0.5 * min(ys) + 0.5 * max(ys) - min_corner = Point(min(xs), min(ys)) - center = Point(x_center, y_center) - shrink_distance = center.distance(min_corner) * factor - - if expand: - poly_resized = poly.buffer(shrink_distance) # expand - else: - poly_resized = poly.buffer(-shrink_distance) # shrink - return poly_resized diff --git a/hub/imports/geometry_factory.py b/hub/imports/geometry_factory.py index 06c07180..3e6ca0b3 100644 --- a/hub/imports/geometry_factory.py +++ b/hub/imports/geometry_factory.py @@ -4,13 +4,11 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2022 Concordia CERC group Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca """ -import geopandas from hub.city_model_structure.city import City from hub.helpers.utils import validate_import_export_type from hub.imports.geometry.citygml import CityGml from hub.imports.geometry.geojson import Geojson -from hub.imports.geometry.gpandas import GPandas from hub.imports.geometry.obj import Obj @@ -56,16 +54,6 @@ class GeometryFactory: """ return Obj(self._path).city - @property - def _gpandas(self) -> City: - """ - Enrich the city by using GeoPandas information as data source - :return: City - """ - if self._data_frame is None: - self._data_frame = geopandas.read_file(self._path) - return GPandas(self._data_frame).city - @property def _geojson(self) -> City: """ diff --git a/hub/imports/results/insel_heatpump_energy_demand.py b/hub/imports/results/insel_heatpump_energy_demand.py deleted file mode 100644 index 54556d70..00000000 --- a/hub/imports/results/insel_heatpump_energy_demand.py +++ /dev/null @@ -1,40 +0,0 @@ -""" -Insel Heap pump energy demand and fossil fuel consumption -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2023 Concordia CERC group -Project Coder peter.yefi@gmail.cm -""" - -from pathlib import Path -import pandas as pd - - -class InselHeatPumpEnergyDemand: - """ - Import Energy demand and fossil fuel consumption results - """ - def __init__(self, city, base_path, hp_model): - """ - :param city: the city - :param base_path: the insel simulation output file - :param hp_model: the heatpump model for both air source and water to water - """ - self._city = city - self._hp_model = hp_model - with open(Path(base_path).resolve(), 'r', encoding='utf8') as csv_file: - df = pd.read_csv(csv_file) - self._monthly_electricity_demand = df.iloc[:, 1] - self._monthly_fossil_fuel_consumption = df.iloc[:, 2] - - def enrich(self): - """ - Enrich the city with the heat pump information - """ - for energy_system in self._city.energy_systems: - if energy_system.air_source_hp is not None: - if energy_system.air_source_hp.model == self._hp_model: - energy_system.air_source_hp.hp_monthly_fossil_consumption = self._monthly_fossil_fuel_consumption - - if energy_system.water_to_water_hp is not None: - if energy_system.water_to_water_hp.model == self._hp_model: - energy_system.water_to_water_hp.hp_monthly_electricity_demand = self._monthly_electricity_demand diff --git a/hub/imports/results/insel_monthly_energry_balance.py b/hub/imports/results/insel_monthly_energry_balance.py index 4450991d..6dd647ab 100644 --- a/hub/imports/results/insel_monthly_energry_balance.py +++ b/hub/imports/results/insel_monthly_energry_balance.py @@ -4,9 +4,9 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2022 Concordia CERC group Project Coder Guillermo.GutierrezMorote@concordia.ca """ + from pathlib import Path import csv -import pandas as pd import hub.helpers.constants as cte @@ -34,11 +34,9 @@ class InselMonthlyEnergyBalance: demand[i] = str(aux) else: demand[i] = '0' - heating.append(demand[0]) - cooling.append(demand[1]) - monthly_heating = pd.DataFrame(heating, columns=[cte.INSEL_MEB]).astype(float) - monthly_cooling = pd.DataFrame(cooling, columns=[cte.INSEL_MEB]).astype(float) - return monthly_heating, monthly_cooling + heating.append(float(demand[0])) + cooling.append(float(demand[1])) + return heating, cooling def _dhw_and_electric_demand(self): for building in self._city.buildings: @@ -52,7 +50,7 @@ class InselMonthlyEnergyBalance: else: thermal_zone = building.internal_zones[0].thermal_zones[0] area = thermal_zone.total_floor_area - cold_water = building.cold_water_temperature[cte.MONTH]['epw'] + cold_water = building.cold_water_temperature[cte.MONTH] peak_flow = thermal_zone.domestic_hot_water.peak_flow service_temperature = thermal_zone.domestic_hot_water.service_temperature lighting_density = thermal_zone.lighting.density @@ -68,7 +66,7 @@ class InselMonthlyEnergyBalance: for value in schedule.values: total_day += value for day_type in schedule.day_types: - total_lighting += total_day * cte.DAYS_A_MONTH[day_type][month] * lighting_density + total_lighting += total_day * cte.WEEK_DAYS_A_MONTH[day_type][month] * lighting_density lighting_demand.append(total_lighting * area) for schedule in thermal_zone.appliances.schedules: @@ -76,7 +74,7 @@ class InselMonthlyEnergyBalance: for value in schedule.values: total_day += value for day_type in schedule.day_types: - total_appliances += total_day * cte.DAYS_A_MONTH[day_type][month] * appliances_density + total_appliances += total_day * cte.WEEK_DAYS_A_MONTH[day_type][month] * appliances_density appliances_demand.append(total_appliances * area) for schedule in thermal_zone.domestic_hot_water.schedules: @@ -87,26 +85,15 @@ class InselMonthlyEnergyBalance: demand = ( peak_flow * cte.WATER_DENSITY * cte.WATER_HEAT_CAPACITY * (service_temperature - cold_water[month]) ) - total_dhw_demand += total_day * cte.DAYS_A_MONTH[day_type][month] * demand + total_dhw_demand += total_day * cte.WEEK_DAYS_A_MONTH[day_type][month] * demand domestic_hot_water_demand.append(total_dhw_demand * area) - building.domestic_hot_water_heat_demand[cte.MONTH] = pd.DataFrame(domestic_hot_water_demand, - columns=[cte.INSEL_MEB]) - yearly_domestic_hot_water_demand = [sum(domestic_hot_water_demand)] - building.domestic_hot_water_heat_demand[cte.YEAR] = pd.DataFrame(yearly_domestic_hot_water_demand, - columns=[cte.INSEL_MEB]) - building.lighting_electrical_demand[cte.MONTH] = pd.DataFrame(lighting_demand, columns=[cte.INSEL_MEB]) - yearly_lighting_electrical_demand = [sum(lighting_demand)] - building.lighting_electrical_demand[cte.YEAR] = pd.DataFrame( - yearly_lighting_electrical_demand, - columns=[cte.INSEL_MEB] - ) - building.appliances_electrical_demand[cte.MONTH] = pd.DataFrame(appliances_demand, columns=[cte.INSEL_MEB]) - yearly_appliances_electrical_demand = [sum(appliances_demand)] - building.appliances_electrical_demand[cte.YEAR] = pd.DataFrame( - yearly_appliances_electrical_demand, - columns=[cte.INSEL_MEB] - ) + building.domestic_hot_water_heat_demand[cte.MONTH] = domestic_hot_water_demand + building.domestic_hot_water_heat_demand[cte.YEAR] = [sum(domestic_hot_water_demand)] + building.lighting_electrical_demand[cte.MONTH] = lighting_demand + building.lighting_electrical_demand[cte.YEAR] = [sum(lighting_demand)] + building.appliances_electrical_demand[cte.MONTH] = appliances_demand + building.appliances_electrical_demand[cte.YEAR] = [sum(appliances_demand)] def enrich(self): """ @@ -118,10 +105,6 @@ class InselMonthlyEnergyBalance: insel_output_file_path = Path(self._base_path / file_name).resolve() if insel_output_file_path.is_file(): building.heating_demand[cte.MONTH], building.cooling_demand[cte.MONTH] = self._conditioning_demand(insel_output_file_path) - building.heating_demand[cte.YEAR] = pd.DataFrame( - [building.heating_demand[cte.MONTH][cte.INSEL_MEB].astype(float).sum()], columns=[cte.INSEL_MEB] - ) - building.cooling_demand[cte.YEAR] = pd.DataFrame( - [building.cooling_demand[cte.MONTH][cte.INSEL_MEB].astype(float).sum()], columns=[cte.INSEL_MEB] - ) + building.heating_demand[cte.YEAR] = [sum(building.heating_demand[cte.MONTH])] + building.cooling_demand[cte.YEAR] = [sum(building.cooling_demand[cte.MONTH])] self._dhw_and_electric_demand() diff --git a/hub/imports/results/simplified_radiosity_algorithm.py b/hub/imports/results/simplified_radiosity_algorithm.py index c5c77bf7..3a9c4e3f 100644 --- a/hub/imports/results/simplified_radiosity_algorithm.py +++ b/hub/imports/results/simplified_radiosity_algorithm.py @@ -4,10 +4,10 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2022 Concordia CERC group Project Coder Guillermo.GutierrezMorote@concordia.ca """ -import calendar as cal + import pandas as pd -import numpy as np import hub.helpers.constants as cte +from hub.helpers.monthly_values import MonthlyValues class SimplifiedRadiosityAlgorithm: @@ -19,54 +19,11 @@ class SimplifiedRadiosityAlgorithm: self._city = city self._base_path = base_path self._input_file_path = (self._base_path / f'{self._city.name}_sra_SW.out').resolve() - self._month_hour = self._month_hour_data_frame - self._results = self._read_results() - self._radiation_list = [] - - @property - def _month_hour_data_frame(self): - array = [] - for i in range(0, 12): - days_of_month = cal.monthrange(2015, i+1)[1] - total_hours = days_of_month * 24 - array = np.concatenate((array, np.full(total_hours, i + 1))) - return pd.DataFrame(array, columns=[cte.MONTH]) - - def _get_monthly_values(self, values): - out = None - if values is not None: - if cte.MONTH not in values.columns: - values = pd.concat([self._month_hour, pd.DataFrame(values)], axis=1) - out = values.groupby(cte.MONTH, as_index=False).sum() - del out[cte.MONTH] - return out - - @staticmethod - def _get_yearly_values(values): - return [values.sum()] - - def _read_results(self): try: - return pd.read_csv(self._input_file_path, sep='\s+', header=0) + self._results = pd.read_csv(self._input_file_path, sep='\s+', header=0).to_dict(orient='list') except FileNotFoundError as err: raise FileNotFoundError('No SRA output file found') from err - @property - def _radiation(self) -> []: - if len(self._radiation_list) == 0: - id_building = '' - header_building = [] - for column in self._results.columns.values: - if id_building != column.split(':')[1]: - id_building = column.split(':')[1] - if len(header_building) > 0: - self._radiation_list.append(pd.concat([self._month_hour, self._results[header_building]], axis=1)) - header_building = [column] - else: - header_building.append(column) - self._radiation_list.append(pd.concat([self._month_hour, self._results[header_building]], axis=1)) - return self._radiation_list - def enrich(self): """ saves in building surfaces the correspondent irradiance at different time-scales depending on the mode @@ -74,28 +31,21 @@ class SimplifiedRadiosityAlgorithm: specific building values :return: none """ - for radiation in self._radiation: - city_object_name = radiation.columns.values.tolist()[1].split(':')[1] + _irradiance = {} + for key in self._results: + header_name = key.split(':') + result = self._results[key] + city_object_name = header_name[1] building = self._city.city_object(city_object_name) - for column in radiation.columns.values: - if column == cte.MONTH: - continue - header_id = column - surface_id = header_id.split(':')[2] - surface = building.surface_by_id(surface_id) - new_value = pd.DataFrame(radiation[[header_id]].to_numpy(), columns=[cte.SRA]) - month_new_value = self._get_monthly_values(new_value) - if cte.MONTH not in surface.global_irradiance: - surface.global_irradiance[cte.MONTH] = month_new_value - else: - pd.concat([surface.global_irradiance[cte.MONTH], month_new_value], axis=1) - if cte.HOUR not in surface.global_irradiance: - surface.global_irradiance[cte.HOUR] = new_value - else: - pd.concat([surface.global_irradiance[cte.HOUR], new_value], axis=1) - if cte.YEAR not in surface.global_irradiance: - surface.global_irradiance[cte.YEAR] = pd.DataFrame(SimplifiedRadiosityAlgorithm._get_yearly_values(new_value), - columns=[cte.SRA]) + surface_id = header_name[2] + surface = building.surface_by_id(surface_id) + monthly_result = MonthlyValues.get_total_month(result) + yearly_result = [sum(result)] + _irradiance[cte.YEAR] = yearly_result + _irradiance[cte.MONTH] = monthly_result + _irradiance[cte.HOUR] = result + surface.global_irradiance = _irradiance + self._city.level_of_detail.surface_radiation = 2 for building in self._city.buildings: building.level_of_detail.surface_radiation = 2 diff --git a/hub/imports/results_factory.py b/hub/imports/results_factory.py index 8903a02f..c5f092b1 100644 --- a/hub/imports/results_factory.py +++ b/hub/imports/results_factory.py @@ -8,7 +8,6 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord from pathlib import Path from hub.helpers.utils import validate_import_export_type -from hub.imports.results.insel_heatpump_energy_demand import InselHeatPumpEnergyDemand from hub.imports.results.insel_monthly_energry_balance import InselMonthlyEnergyBalance from hub.imports.results.simplified_radiosity_algorithm import SimplifiedRadiosityAlgorithm @@ -41,13 +40,6 @@ class ResultFactory: """ SimplifiedRadiosityAlgorithm(self._city, self._base_path).enrich() - def _heat_pump(self): - """ - Enrich the city (energy system specifically) with heat pump insel simulation - results - """ - InselHeatPumpEnergyDemand(self._city, self._base_path, self._hp_model).enrich() - def _insel_monthly_energy_balance(self): """ Enrich the city with insel monthly energy balance results diff --git a/hub/imports/usage/comnet_usage_parameters.py b/hub/imports/usage/comnet_usage_parameters.py index 71649e09..69e1902e 100644 --- a/hub/imports/usage/comnet_usage_parameters.py +++ b/hub/imports/usage/comnet_usage_parameters.py @@ -104,7 +104,7 @@ class ComnetUsageParameters: _domestic_hot_water.service_temperature = archetype.domestic_hot_water.service_temperature peak_flow = None if len(cold_water_temperature) > 0: - cold_temperature = cold_water_temperature[cte.YEAR]['epw'] + cold_temperature = cold_water_temperature[cte.YEAR][0] peak_flow = 0 if (archetype.domestic_hot_water.service_temperature - cold_temperature) > 0: peak_flow = archetype.domestic_hot_water.density / cte.WATER_DENSITY / cte.WATER_HEAT_CAPACITY \ diff --git a/hub/imports/usage/eilat_usage_parameters.py b/hub/imports/usage/eilat_usage_parameters.py index 43fd9066..5690c3f1 100644 --- a/hub/imports/usage/eilat_usage_parameters.py +++ b/hub/imports/usage/eilat_usage_parameters.py @@ -104,7 +104,7 @@ class EilatUsageParameters: _domestic_hot_water.service_temperature = archetype.domestic_hot_water.service_temperature peak_flow = None if len(cold_water_temperature) > 0: - cold_temperature = cold_water_temperature[cte.YEAR]['epw'] + cold_temperature = cold_water_temperature[cte.YEAR][0] peak_flow = 0 if (archetype.domestic_hot_water.service_temperature - cold_temperature) > 0: peak_flow = archetype.domestic_hot_water.density / cte.WATER_DENSITY / cte.WATER_HEAT_CAPACITY \ diff --git a/hub/imports/usage/nrcan_usage_parameters.py b/hub/imports/usage/nrcan_usage_parameters.py index afc24181..8106132f 100644 --- a/hub/imports/usage/nrcan_usage_parameters.py +++ b/hub/imports/usage/nrcan_usage_parameters.py @@ -130,7 +130,7 @@ class NrcanUsageParameters: _domestic_hot_water.service_temperature = archetype.domestic_hot_water.service_temperature density = None if len(cold_water_temperature) > 0: - cold_temperature = cold_water_temperature[cte.YEAR]['epw'] + cold_temperature = cold_water_temperature[cte.YEAR][0] density = ( archetype.domestic_hot_water.peak_flow * cte.WATER_DENSITY * cte.WATER_HEAT_CAPACITY * (archetype.domestic_hot_water.service_temperature - cold_temperature) diff --git a/hub/imports/weather/epw_weather_parameters.py b/hub/imports/weather/epw_weather_parameters.py index cbf4d2de..83cc1bcc 100644 --- a/hub/imports/weather/epw_weather_parameters.py +++ b/hub/imports/weather/epw_weather_parameters.py @@ -4,14 +4,15 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2022 Concordia CERC group Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca """ + import logging import sys from pathlib import Path - -import pandas as pd import requests +import pandas as pd import hub.helpers.constants as cte +from hub.helpers.monthly_values import MonthlyValues from hub.city_model_structure.city import City from hub.imports.weather.helpers.weather import Weather as wh @@ -75,6 +76,25 @@ class EpwWeatherParameters: 'snow_depth_cm', 'days_since_last_snowfall', 'albedo', 'liquid_precipitation_depth_mm', 'liquid_precipitation_quality_hr']) + number_invalid_records = self._weather_values[ + self._weather_values.dry_bulb_temperature_c == 99.9].count().dry_bulb_temperature_c + if number_invalid_records > 0: + sys.stderr.write(f'Warning: {self._path} invalid records (value of 99.9) in dry bulb temperature\n') + number_invalid_records = self._weather_values[ + self._weather_values.global_horizontal_radiation_wh_m2 == 9999].count().global_horizontal_radiation_wh_m2 + if number_invalid_records > 0: + sys.stderr.write(f'Warning: {self._path} invalid records (value of 9999) in global horizontal radiation\n') + number_invalid_records = self._weather_values[ + self._weather_values.diffuse_horizontal_radiation_wh_m2 == 9999].count().diffuse_horizontal_radiation_wh_m2 + if number_invalid_records > 0: + sys.stderr.write(f'Warning: {self._path} invalid records (value of 9999) in diffuse horizontal radiation\n') + number_invalid_records = self._weather_values[ + self._weather_values.direct_normal_radiation_wh_m2 == 9999].count().direct_normal_radiation_wh_m2 + if number_invalid_records > 0: + sys.stderr.write(f'Warning: {self._path} invalid records (value of 9999) in direct horizontal radiation\n') + + self._weather_values = self._weather_values.to_dict(orient='list') + except SystemExit: sys.stderr.write(f'Error: wrong formatting of weather file {self._path}\n') sys.exit() @@ -82,72 +102,29 @@ class EpwWeatherParameters: building.ground_temperature[cte.MONTH] = ground_temperature_from_file ground_temperature = {} for ground_temperature_set in building.ground_temperature[cte.MONTH]: - temperature = 0 - for value in building.ground_temperature[cte.MONTH][ground_temperature_set]: - temperature += value / 12 + temperature = sum(building.ground_temperature[cte.MONTH][ground_temperature_set]) / 12 ground_temperature[ground_temperature_set] = [temperature] building.ground_temperature[cte.YEAR] = ground_temperature if cte.HOUR in building.external_temperature: del building.external_temperature[cte.HOUR] - new_value = pd.DataFrame(self._weather_values[['dry_bulb_temperature_c']].to_numpy(), columns=['epw']) - number_invalid_records = new_value[new_value.epw == 99.9].count().epw - if number_invalid_records > 0: - sys.stderr.write(f'Warning: {self._path} invalid records (value of 99.9) in dry bulb temperature\n') - if cte.HOUR not in building.external_temperature: - building.external_temperature[cte.HOUR] = new_value - else: - pd.concat([building.external_temperature[cte.HOUR], new_value], axis=1) +# new_value = pd.DataFrame(self._weather_values[['dry_bulb_temperature_c']].to_numpy(), columns=['epw']) +# number_invalid_records = new_value[new_value.epw == 99.9].count().epw + building.external_temperature[cte.HOUR] = self._weather_values['dry_bulb_temperature_c'] + building.global_horizontal[cte.HOUR] = self._weather_values['global_horizontal_radiation_wh_m2'] + building.diffuse[cte.HOUR] = self._weather_values['diffuse_horizontal_radiation_wh_m2'] + building.beam[cte.HOUR] = self._weather_values['direct_normal_radiation_wh_m2'] + building.cold_water_temperature[cte.HOUR] = wh().cold_water_temperature(building.external_temperature[cte.HOUR]) - new_value = pd.DataFrame(self._weather_values[['global_horizontal_radiation_wh_m2']].to_numpy(), columns=['epw']) - number_invalid_records = new_value[new_value.epw == 9999].count().epw - if number_invalid_records > 0: - sys.stderr.write(f'Warning: {self._path} invalid records (value of 9999) in global horizontal radiation\n') - if cte.HOUR not in building.global_horizontal: - building.global_horizontal[cte.HOUR] = new_value - else: - pd.concat([building.global_horizontal[cte.HOUR], new_value], axis=1) - - new_value = pd.DataFrame(self._weather_values[['diffuse_horizontal_radiation_wh_m2']].to_numpy(), columns=['epw']) - number_invalid_records = new_value[new_value.epw == 9999].count().epw - if number_invalid_records > 0: - sys.stderr.write(f'Warning: {self._path} invalid records (value of 9999) in diffuse horizontal radiation\n') - if cte.HOUR not in building.diffuse: - building.diffuse[cte.HOUR] = new_value - else: - pd.concat([building.diffuse[cte.HOUR], new_value], axis=1) - - new_value = pd.DataFrame(self._weather_values[['direct_normal_radiation_wh_m2']].to_numpy(), columns=['epw']) - number_invalid_records = new_value[new_value.epw == 9999].count().epw - if number_invalid_records > 0: - sys.stderr.write(f'Warning: {self._path} invalid records (value of 9999) in direct horizontal radiation\n') - if cte.HOUR not in building.beam: - building.beam[cte.HOUR] = new_value - else: - pd.concat([building.beam[cte.HOUR], new_value], axis=1) - - new_value = wh().cold_water_temperature(building.external_temperature[cte.HOUR]['epw']) - if cte.HOUR not in building.cold_water_temperature: - building.cold_water_temperature[cte.HOUR] = new_value - else: - pd.concat([building.cold_water_temperature[cte.HOUR], new_value], axis=1) # create the monthly and yearly values out of the hourly for building in self._city.buildings: - if cte.MONTH not in building.external_temperature: - building.external_temperature[cte.MONTH] = \ - wh().get_monthly_mean_values(building.external_temperature[cte.HOUR][['epw']]) - if cte.YEAR not in building.external_temperature: - building.external_temperature[cte.YEAR] = \ - wh(). get_yearly_mean_values(building.external_temperature[cte.HOUR][['epw']]) - if cte.MONTH not in building.cold_water_temperature: - building.cold_water_temperature[cte.MONTH] = wh().get_monthly_mean_values( - building.cold_water_temperature[cte.HOUR][['epw']]) - if cte.YEAR not in building.cold_water_temperature: - building.cold_water_temperature[cte.YEAR] = wh().get_yearly_mean_values( - building.cold_water_temperature[cte.HOUR][['epw']]) + building.external_temperature[cte.MONTH] = MonthlyValues().get_mean_values(building.external_temperature[cte.HOUR]) + building.external_temperature[cte.YEAR] = [sum(building.external_temperature[cte.HOUR]) / 9870] + building.cold_water_temperature[cte.MONTH] = MonthlyValues().get_mean_values(building.cold_water_temperature[cte.HOUR]) + building.cold_water_temperature[cte.YEAR] = [sum(building.cold_water_temperature[cte.HOUR]) / 9870] # If the usage has already being imported, the domestic hot water missing values must be calculated here that # the cold water temperature is finally known - cold_temperature = building.cold_water_temperature[cte.YEAR]['epw'] + cold_temperature = building.cold_water_temperature[cte.YEAR][0] for internal_zone in building.internal_zones: if internal_zone.usages is not None: for usage in internal_zone.usages: diff --git a/hub/imports/weather/helpers/weather.py b/hub/imports/weather/helpers/weather.py index 18364beb..9d894991 100644 --- a/hub/imports/weather/helpers/weather.py +++ b/hub/imports/weather/helpers/weather.py @@ -4,11 +4,9 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2022 Concordia CERC group Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca """ + import logging import math -import calendar as cal -import pandas as pd -import numpy as np import hub.helpers.constants as cte @@ -75,55 +73,7 @@ class Weather: for temperature in ambient_temperature_fahrenheit: radians = (0.986 * (temperature-15-lag) - 90) * math.pi / 180 cold_temperature.append((average_temperature + 6 + ratio * (delta_temperature/2) * math.sin(radians) - 32) * 5/9) - return pd.DataFrame(cold_temperature, columns=['epw']) - - def get_monthly_mean_values(self, values): - """ - Get the monthly mean for the given values - :return: float - """ - out = None - if values is not None: - if 'month' not in values.columns: - values = pd.concat([self.month_hour, pd.DataFrame(values)], axis=1) - out = values.groupby('month', as_index=False).mean() - del out['month'] - return out - - @staticmethod - def get_yearly_mean_values(values): - """ - Get the yearly mean for the given values - :return: float - """ - return values.mean() - - def get_total_month(self, values): - """ - Get the total value the given values - :return: float - """ - out = None - if values is not None: - if 'month' not in values.columns: - values = pd.concat([self.month_hour, pd.DataFrame(values)], axis=1) - out = pd.DataFrame(values).groupby('month', as_index=False).sum() - del out['month'] - return out - - @property - def month_hour(self): - """ - returns a DataFrame that has x values of the month number (January = 1, February = 2...), - being x the number of hours of the corresponding month - :return: DataFrame(int) - """ - array = [] - for i in range(0, 12): - days_of_month = cal.monthrange(2015, i+1)[1] - total_hours = days_of_month * 24 - array = np.concatenate((array, np.full(total_hours, i + 1))) - return pd.DataFrame(array, columns=['month']) + return cold_temperature def epw_file(self, region_code): """ diff --git a/hub/imports/weather_factory.py b/hub/imports/weather_factory.py index d5cbc6c5..bf991095 100644 --- a/hub/imports/weather_factory.py +++ b/hub/imports/weather_factory.py @@ -4,7 +4,6 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2022 Concordia CERC group Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca """ -from pathlib import Path from hub.city_model_structure.city import City from hub.helpers.utils import validate_import_export_type diff --git a/tests/test_city_merge.py b/tests/test_city_merge.py index 110d45cc..f2b4359c 100644 --- a/tests/test_city_merge.py +++ b/tests/test_city_merge.py @@ -4,14 +4,13 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2022 Concordia CERC group Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca """ + import copy import distutils.spawn import subprocess from pathlib import Path from unittest import TestCase -import pandas as pd - from hub.city_model_structure.city import City from hub.imports.geometry_factory import GeometryFactory from hub.imports.results_factory import ResultFactory @@ -72,13 +71,13 @@ class TestCityMerge(TestCase): for building in merged_city.buildings: for surface in building.surfaces: if surface.global_irradiance: - full_city_building_total_radiation += surface.global_irradiance[cte.YEAR].iloc[0, 0] + full_city_building_total_radiation += surface.global_irradiance[cte.YEAR][0] merged_city_building_total_radiation = 0 for building in merged_city.buildings: for surface in building.surfaces: if surface.global_irradiance: - merged_city_building_total_radiation += surface.global_irradiance[cte.YEAR].iloc[0, 0] + merged_city_building_total_radiation += surface.global_irradiance[cte.YEAR][0] self.assertEqual(full_city_building_total_radiation, merged_city_building_total_radiation) merged_city = even_city.merge(full_city) @@ -86,24 +85,24 @@ class TestCityMerge(TestCase): for building in merged_city.buildings: for surface in building.surfaces: if surface.global_irradiance: - merged_city_building_total_radiation += surface.global_irradiance[cte.YEAR].iloc[0, 0] + merged_city_building_total_radiation += surface.global_irradiance[cte.YEAR][0] self.assertEqual(full_city_building_total_radiation, merged_city_building_total_radiation) for building in even_city.buildings: for surface in building.surfaces: - surface.global_irradiance[cte.YEAR] = pd.DataFrame([3], columns=['sra_mockup_value']) + surface.global_irradiance[cte.YEAR] = [3] merged_city = full_city.merge(even_city) first_merged_city_building_total_radiation = 0 for building in merged_city.buildings: for surface in building.surfaces: if surface.global_irradiance: - first_merged_city_building_total_radiation += surface.global_irradiance[cte.YEAR].iloc[0, 0] + first_merged_city_building_total_radiation += surface.global_irradiance[cte.YEAR][0] merged_city = even_city.merge(full_city) second_merged_city_building_total_radiation = 0 for building in merged_city.buildings: for surface in building.surfaces: if surface.global_irradiance: - second_merged_city_building_total_radiation += surface.global_irradiance[cte.YEAR].iloc[0, 0] + second_merged_city_building_total_radiation += surface.global_irradiance[cte.YEAR][0] self.assertEqual(first_merged_city_building_total_radiation, second_merged_city_building_total_radiation) diff --git a/tests/test_custom_insel_block.py b/tests/test_custom_insel_block.py index b8683bd2..aeb715ed 100644 --- a/tests/test_custom_insel_block.py +++ b/tests/test_custom_insel_block.py @@ -37,24 +37,6 @@ class TestExports(TestCase): self.assertIsNotNone(self._city, 'city is none') return self._city - @property - def _read_sra_file(self) -> []: - path = (self._example_path / "one_building_in_kelowna_sra_SW.out").resolve() - _results = pd.read_csv(path, sep='\s+', header=0) - id_building = '' - header_building = [] - _radiation = [] - for column in _results.columns.values: - if id_building != column.split(':')[1]: - id_building = column.split(':')[1] - if len(header_building) > 0: - _radiation.append(pd.concat([MonthlyValues().month_hour, _results[header_building]], axis=1)) - header_building = [column] - else: - header_building.append(column) - _radiation.append(pd.concat([MonthlyValues().month_hour, _results[header_building]], axis=1)) - return _radiation - def _set_irradiance_surfaces(self, city): """ saves in building surfaces the correspondent irradiance at different time-scales depending on the mode @@ -64,19 +46,22 @@ class TestExports(TestCase): :return: none """ city.level_of_detail.surface_radiation = 2 - for radiation in self._read_sra_file: - city_object_name = radiation.columns.values.tolist()[1].split(':')[1] - building = city.city_object(city_object_name) - for column in radiation.columns.values: - if column == cte.MONTH: - continue - header_id = column - surface_id = header_id.split(':')[2] - surface = building.surface_by_id(surface_id) - new_value = pd.DataFrame(radiation[[header_id]].to_numpy(), columns=['sra']) - surface.global_irradiance[cte.HOUR] = new_value - month_new_value = MonthlyValues().get_mean_values(new_value) - surface.global_irradiance[cte.MONTH] = month_new_value + path = (self._example_path / "one_building_in_kelowna_sra_SW.out").resolve() + self._results = pd.read_csv(path, sep='\s+', header=0).to_dict(orient='list') + _irradiance = {} + for key in self._results: + header_name = key.split(':') + result = self._results[key] + city_object_name = header_name[1] + building = self._city.city_object(city_object_name) + surface_id = header_name[2] + surface = building.surface_by_id(surface_id) + monthly_result = MonthlyValues.get_total_month(result) + yearly_result = [sum(result)] + _irradiance[cte.YEAR] = yearly_result + _irradiance[cte.MONTH] = monthly_result + _irradiance[cte.HOUR] = result + surface.global_irradiance = _irradiance def test_insel_monthly_energy_balance_export(self): """ @@ -86,7 +71,7 @@ class TestExports(TestCase): WeatherFactory('epw', city).enrich() for building in city.buildings: building.external_temperature[cte.MONTH] = MonthlyValues().\ - get_mean_values(building.external_temperature[cte.HOUR][['epw']]) + get_mean_values(building.external_temperature[cte.HOUR]) self._set_irradiance_surfaces(city) for building in city.buildings: diff --git a/tests/test_db_factory.py b/tests/test_db_factory.py index 6b5d0622..6f760bbc 100644 --- a/tests/test_db_factory.py +++ b/tests/test_db_factory.py @@ -225,16 +225,16 @@ TestDBFactory yearly_lighting_peak_load = building.lighting_peak_load[cte.YEAR] monthly_appliances_peak_load = building.appliances_peak_load[cte.MONTH] yearly_appliances_peak_load = building.appliances_peak_load[cte.YEAR] - monthly_cooling_demand = building.cooling_demand[cte.MONTH][cte.INSEL_MEB] - yearly_cooling_demand = building.cooling_demand[cte.YEAR][cte.INSEL_MEB] - monthly_heating_demand = building.heating_demand[cte.MONTH][cte.INSEL_MEB] - yearly_heating_demand = building.heating_demand[cte.YEAR][cte.INSEL_MEB] - monthly_lighting_electrical_demand = building.lighting_electrical_demand[cte.MONTH][cte.INSEL_MEB] - yearly_lighting_electrical_demand = building.lighting_electrical_demand[cte.YEAR][cte.INSEL_MEB] - monthly_appliances_electrical_demand = building.appliances_electrical_demand[cte.MONTH][cte.INSEL_MEB] - yearly_appliances_electrical_demand = building.appliances_electrical_demand[cte.YEAR][cte.INSEL_MEB] - monthly_domestic_hot_water_heat_demand = building.domestic_hot_water_heat_demand[cte.MONTH][cte.INSEL_MEB] - yearly_domestic_hot_water_heat_demand = building.domestic_hot_water_heat_demand[cte.YEAR][cte.INSEL_MEB] + monthly_cooling_demand = building.cooling_demand[cte.MONTH] + yearly_cooling_demand = building.cooling_demand[cte.YEAR] + monthly_heating_demand = building.heating_demand[cte.MONTH] + yearly_heating_demand = building.heating_demand[cte.YEAR] + monthly_lighting_electrical_demand = building.lighting_electrical_demand[cte.MONTH] + yearly_lighting_electrical_demand = building.lighting_electrical_demand[cte.YEAR] + monthly_appliances_electrical_demand = building.appliances_electrical_demand[cte.MONTH] + yearly_appliances_electrical_demand = building.appliances_electrical_demand[cte.YEAR] + monthly_domestic_hot_water_heat_demand = building.domestic_hot_water_heat_demand[cte.MONTH] + yearly_domestic_hot_water_heat_demand = building.domestic_hot_water_heat_demand[cte.YEAR] monthly_heating_consumption = building.heating_consumption[cte.MONTH] yearly_heating_consumption = building.heating_consumption[cte.YEAR] monthly_cooling_consumption = building.cooling_consumption[cte.MONTH] diff --git a/tests/test_energy_systems_air_source_hp.py b/tests/test_energy_systems_air_source_hp.py deleted file mode 100644 index be6b230d..00000000 --- a/tests/test_energy_systems_air_source_hp.py +++ /dev/null @@ -1,74 +0,0 @@ -""" -Test EnergySystemsFactory and various heatpump models -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2022 Concordia CERC group -Project Coder Peter Yefi peteryefi@gmail.com -""" -from pathlib import Path - -import pandas as pd -from unittest import TestCase -from hub.imports.geometry_factory import GeometryFactory -from hub.imports.energy_systems_factory import EnergySystemsFactory -from hub.city_model_structure.energy_systems.air_source_hp import AirSourceHP -from hub.exports.energy_systems_factory import EnergySystemsExportFactory -import os - -# User defined parameters -user_input = { - 'StartYear': 2020, - 'EndYear': 2021, - 'MaximumHPEnergyInput': 8000, - 'HoursOfStorageAtMaxDemand': 1, - 'BuildingSuppTemp': 40, - 'TemperatureDifference': 15, - 'FuelLHV': 47100, - 'FuelPrice': 0.12, - 'FuelEF': 1887, - 'FuelDensity': 0.717, - 'HPSupTemp': 60 -} - - -class TestEnergySystemsFactory(TestCase): - """ - TestBuilding TestCase 1 - """ - - def setUp(self) -> None: - """ - Test setup - :return: None - """ - self._example_path = (Path(__file__).parent / 'tests_data').resolve() - self._output_path = (Path(__file__).parent / 'tests_outputs').resolve() - city_file = (self._example_path/"C40_Final.gml").resolve() - self._output_path = (self._output_path/"as_user_output.csv").resolve() - self._city = GeometryFactory('citygml', path=city_file).city - EnergySystemsFactory('air_source_hp', self._city).enrich() - - def test_air_source_heat_pump_import(self): - self.assertIsNotNone(self._city.energy_systems, 'City has energy systems') - self.assertIsInstance(self._city.energy_systems[0].air_source_hp, AirSourceHP) - self.assertEqual(self._city.energy_systems[0].air_source_hp.model, '012') - self.assertEqual(self._city.energy_systems[16].air_source_hp.model, '140') - - def test_air_source_series_heat_pump_export(self): - EnergySystemsExportFactory(city=self._city, handler=user_input, hp_model='012', - output_path=self._output_path).export() - df = pd.read_csv(self._output_path) - self.assertEqual(df.shape, (13, 3)) - self.assertEqual(df.iloc[0, 1], 1867715.88) - - def test_air_source_parallel_heat_pump_export(self): - output = EnergySystemsExportFactory(city=self._city, handler=user_input, hp_model='018', - output_path=None, sim_type=1).export() - self.assertEqual(output["hourly_electricity_demand"][0], 38748.5625) - self.assertIsNotNone(output["daily_fossil_consumption"]) - self.assertEqual(len(output["hourly_electricity_demand"]), 8760) - - def tearDown(self) -> None: - try: - os.remove(self._output_path) - except OSError: - pass diff --git a/tests/test_energy_systems_water_to_water_hp.py b/tests/test_energy_systems_water_to_water_hp.py deleted file mode 100644 index 376480a9..00000000 --- a/tests/test_energy_systems_water_to_water_hp.py +++ /dev/null @@ -1,72 +0,0 @@ -""" -Test EnergySystemsFactory and various heatpump models -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2022 Concordia CERC group -Project Coder Peter Yefi peteryefi@gmail.com -""" -from pathlib import Path -from unittest import TestCase - -import pandas as pd - -from hub.city_model_structure.energy_systems.water_to_water_hp import WaterToWaterHP -from hub.exports.energy_systems_factory import EnergySystemsExportFactory -from hub.imports.energy_systems_factory import EnergySystemsFactory -from hub.imports.geometry_factory import GeometryFactory - - -class TestEnergySystemsFactory(TestCase): - """ - TestEnergySystemsFactory for Water to Water HP - """ - - def setUp(self) -> None: - """ - Test setup - :return: None - """ - self._example_path = (Path(__file__).parent / 'tests_data').resolve() - self._output_path = (Path(__file__).parent / 'tests_outputs').resolve() - city_file = (self._example_path / "C40_Final.gml").resolve() - self._output_path = (self._example_path / "w2w_user_output.csv").resolve() - self._city = GeometryFactory('citygml', path=city_file).city - EnergySystemsFactory('water_to_water_hp', self._city).enrich() - - def test_water_to_water_heat_pump_import(self): - self.assertIsNotNone(self._city.energy_systems, 'City has energy systems') - self.assertIsInstance(self._city.energy_systems[0].water_to_water_hp, WaterToWaterHP) - self.assertEqual(self._city.energy_systems[0].water_to_water_hp.model, 'ClimateMaster 156 kW') - self.assertEqual(self._city.energy_systems[2].water_to_water_hp.model, 'ClimateMaster 335 kW') - - def test_water_to_water_heat_pump_export(self): - # User defined parameters - user_input = { - 'StartYear': 2020, - 'EndYear': 2021, - 'MaximumHPEnergyInput': 8000, - 'HoursOfStorageAtMaxDemand': 1, - 'BuildingSuppTemp': 40, - 'TemperatureDifference': 15, - 'FuelLHV': 47100, - 'FuelPrice': 0.12, - 'FuelEF': 1887, - 'FuelDensity': 0.717, - 'HPSupTemp': 60, - 'b1': 10, - 'b2': 10, - 'b3': 10, - 'b4': 10, - 'b5': 10, - 'b6': 10, - 'b7': 10, - 'b8': 10, - 'b9': 10, - 'b10': 10, - 'b11': 10 - } - - EnergySystemsExportFactory(city=self._city, handler=user_input, hp_model='ClimateMaster 256 kW', - output_path=self._output_path, sim_type=1).export('water') - df = pd.read_csv(self._output_path) - self.assertEqual(df.shape, (13, 3)) - self.assertEqual(df.iloc[0, 1], 1031544.62) diff --git a/tests/test_exports.py b/tests/test_exports.py index 7607c964..18aeb1cd 100644 --- a/tests/test_exports.py +++ b/tests/test_exports.py @@ -5,10 +5,10 @@ Copyright © 2022 Concordia CERC group Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca """ + import logging.handlers from pathlib import Path from unittest import TestCase -import pandas as pd from hub.imports.geometry_factory import GeometryFactory from hub.helpers.dictionaries import Dictionaries from hub.imports.construction_factory import ConstructionFactory @@ -58,10 +58,10 @@ class TestExports(TestCase): self._complete_city.climate_reference_city = 'Summerland' dummy_measures = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] for building in self._complete_city.buildings: - building.heating_demand[cte.MONTH] = pd.DataFrame({'INSEL': dummy_measures}) - building.cooling_demand[cte.MONTH] = pd.DataFrame({'INSEL': dummy_measures}) - building.heating_demand[cte.YEAR] = pd.DataFrame({'INSEL': [0.0]}) - building.cooling_demand[cte.YEAR] = pd.DataFrame({'INSEL': [0.0]}) + building.heating_demand[cte.MONTH] = dummy_measures + building.cooling_demand[cte.MONTH] = dummy_measures + building.heating_demand[cte.YEAR] = [0.0] + building.cooling_demand[cte.YEAR] = [0.0] return self._complete_city def _export(self, export_type, from_pickle=False): diff --git a/tests/test_heat_pump_results.py b/tests/test_heat_pump_results.py deleted file mode 100644 index 567fb66b..00000000 --- a/tests/test_heat_pump_results.py +++ /dev/null @@ -1,76 +0,0 @@ -""" -Test EnergySystemsFactory and various heatpump models -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2023 Concordia CERC group -Project Coder Peter Yefi peteryefi@gmail.com -""" -from pathlib import Path -from unittest import TestCase -from hub.imports.geometry_factory import GeometryFactory -from hub.imports.energy_systems_factory import EnergySystemsFactory -from hub.exports.energy_systems_factory import EnergySystemsExportFactory -from hub.imports.results_factory import ResultFactory -import os -from pandas.core.series import Series - -# User defined parameters -user_input = { - 'StartYear': 2020, - 'EndYear': 2021, - 'MaximumHPEnergyInput': 8000, - 'HoursOfStorageAtMaxDemand': 1, - 'BuildingSuppTemp': 40, - 'TemperatureDifference': 15, - 'FuelLHV': 47100, - 'FuelPrice': 0.12, - 'FuelEF': 1887, - 'FuelDensity': 0.717, - 'HPSupTemp': 60 -} - - -class TestHeatPumpResults(TestCase): - """ - TestHeatPumpResults - """ - - def setUp(self) -> None: - """ - Test setup - :return: None - """ - self._example_path = (Path(__file__).parent / 'tests_data').resolve() - self._output_path = (Path(__file__).parent / 'tests_outputs/as_user_output.csv').resolve() - city_file = (self._example_path / "C40_Final.gml").resolve() - self._city = GeometryFactory('citygml', path=city_file).city - EnergySystemsFactory('air_source_hp', self._city).enrich() - - def test_air_source_series_heat_pump_012_results(self): - EnergySystemsExportFactory(city=self._city, handler=user_input, hp_model='012', - output_path=self._output_path).export() - ResultFactory('heat_pump', self._city, self._output_path, '012').enrich() - - for energy_system in self._city.energy_systems: - self.assertIsNone(energy_system.water_to_water_hp) - if energy_system.air_source_hp.model == '012': - self.assertIsInstance(energy_system.air_source_hp.hp_monthly_fossil_consumption, Series) - self.assertEqual(energy_system.air_source_hp.hp_monthly_fossil_consumption.iloc[5], 1.51325583) - self.assertEqual(energy_system.air_source_hp.hp_monthly_fossil_consumption.iloc[12], 35.853598782915) - - def test_air_source_series_heat_pump_015_results(self): - EnergySystemsExportFactory(city=self._city, handler=user_input, hp_model='140', - output_path=self._output_path).export() - ResultFactory('heat_pump', self._city, self._output_path, '140').enrich() - - for energy_system in self._city.energy_systems: - self.assertIsNone(energy_system.water_to_water_hp) - if energy_system.air_source_hp.model == '140': - self.assertIsInstance(energy_system.air_source_hp.hp_monthly_fossil_consumption, Series) - self.assertEqual(energy_system.air_source_hp.hp_monthly_fossil_consumption.iloc[0], 7.91282225) - self.assertEqual(energy_system.air_source_hp.hp_monthly_fossil_consumption.iloc[2], 0.068873927) - - def tearDown(self) -> None: - try: - os.remove(self._output_path) - except OSError: - pass diff --git a/tests/test_insel_exports.py b/tests/test_insel_exports.py index ef987000..bca43173 100644 --- a/tests/test_insel_exports.py +++ b/tests/test_insel_exports.py @@ -37,24 +37,6 @@ class TestExports(TestCase): self.assertIsNotNone(self._city, 'city is none') return self._city - @property - def _read_sra_file(self) -> []: - path = (self._example_path / "one_building_in_kelowna_sra_SW.out").resolve() - _results = pd.read_csv(path, sep='\s+', header=0) - id_building = '' - header_building = [] - _radiation = [] - for column in _results.columns.values: - if id_building != column.split(':')[1]: - id_building = column.split(':')[1] - if len(header_building) > 0: - _radiation.append(pd.concat([MonthlyValues().month_hour, _results[header_building]], axis=1)) - header_building = [column] - else: - header_building.append(column) - _radiation.append(pd.concat([MonthlyValues().month_hour, _results[header_building]], axis=1)) - return _radiation - def _set_irradiance_surfaces(self, city): """ saves in building surfaces the correspondent irradiance at different time-scales depending on the mode @@ -64,19 +46,22 @@ class TestExports(TestCase): :return: none """ city.level_of_detail.surface_radiation = 2 - for radiation in self._read_sra_file: - city_object_name = radiation.columns.values.tolist()[1].split(':')[1] - building = city.city_object(city_object_name) - for column in radiation.columns.values: - if column == cte.MONTH: - continue - header_id = column - surface_id = header_id.split(':')[2] - surface = building.surface_by_id(surface_id) - new_value = pd.DataFrame(radiation[[header_id]].to_numpy(), columns=['sra']) - surface.global_irradiance[cte.HOUR] = new_value - month_new_value = MonthlyValues().get_mean_values(new_value) - surface.global_irradiance[cte.MONTH] = month_new_value + path = (self._example_path / "one_building_in_kelowna_sra_SW.out").resolve() + self._results = pd.read_csv(path, sep='\s+', header=0).to_dict(orient='list') + _irradiance = {} + for key in self._results: + header_name = key.split(':') + result = self._results[key] + city_object_name = header_name[1] + building = self._city.city_object(city_object_name) + surface_id = header_name[2] + surface = building.surface_by_id(surface_id) + monthly_result = MonthlyValues.get_total_month(result) + yearly_result = [sum(result)] + _irradiance[cte.YEAR] = yearly_result + _irradiance[cte.MONTH] = monthly_result + _irradiance[cte.HOUR] = result + surface.global_irradiance = _irradiance def test_insel_monthly_energy_balance_export(self): """ @@ -86,7 +71,7 @@ class TestExports(TestCase): WeatherFactory('epw', city).enrich() for building in city.buildings: building.external_temperature[cte.MONTH] = MonthlyValues().\ - get_mean_values(building.external_temperature[cte.HOUR][['epw']]) + get_mean_values(building.external_temperature[cte.HOUR]) self._set_irradiance_surfaces(city) for building in city.buildings: diff --git a/tests/test_results_import.py b/tests/test_results_import.py index 090eb2f1..1befac19 100644 --- a/tests/test_results_import.py +++ b/tests/test_results_import.py @@ -4,12 +4,11 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2022 Concordia CERC group Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca """ + import subprocess from pathlib import Path from unittest import TestCase -import pandas as pd - import hub.helpers.constants as cte from hub.exports.energy_building_exports_factory import EnergyBuildingsExportsFactory from hub.exports.exports_factory import ExportsFactory @@ -65,10 +64,10 @@ class TestResultsImport(TestCase): ResultFactory('insel_monthly_energy_balance', self._city, self._output_path).enrich() # Check that all the buildings have heating and cooling values for building in self._city.buildings: - self.assertIsNotNone(building.heating_demand[cte.MONTH][cte.INSEL_MEB]) - self.assertIsNotNone(building.cooling_demand[cte.MONTH][cte.INSEL_MEB]) - self.assertIsNotNone(building.heating_demand[cte.YEAR][cte.INSEL_MEB]) - self.assertIsNotNone(building.cooling_demand[cte.YEAR][cte.INSEL_MEB]) + self.assertIsNotNone(building.heating_demand[cte.MONTH]) + self.assertIsNotNone(building.cooling_demand[cte.MONTH]) + self.assertIsNotNone(building.heating_demand[cte.YEAR]) + self.assertIsNotNone(building.cooling_demand[cte.YEAR]) self.assertIsNotNone(building.lighting_peak_load[cte.MONTH]) self.assertIsNotNone(building.lighting_peak_load[cte.YEAR]) self.assertIsNotNone(building.appliances_peak_load[cte.MONTH]) @@ -89,7 +88,7 @@ class TestResultsImport(TestCase): expected_monthly_list = [0 for _ in range(12)] expected_monthly_list[0] = 1000 for building in self._city.buildings: - building.heating_demand[cte.HOUR] = pd.DataFrame(values, columns=['dummy']) - building.cooling_demand[cte.HOUR] = pd.DataFrame(values, columns=['dummy']) + building.heating_demand[cte.HOUR] = values + building.cooling_demand[cte.HOUR] = values self.assertIsNotNone(building.heating_peak_load) self.assertIsNotNone(building.cooling_peak_load)