diff --git a/hub/catalog_factories/cost/montreal_complete_cost_catalog.py b/hub/catalog_factories/cost/montreal_complete_cost_catalog.py
index c66668ca..b41aec5d 100644
--- a/hub/catalog_factories/cost/montreal_complete_cost_catalog.py
+++ b/hub/catalog_factories/cost/montreal_complete_cost_catalog.py
@@ -146,16 +146,31 @@ class MontrealNewCatalog(Catalog):
fuel_variable_units = item['variable']['@cost_unit']
fuel_fixed_monthly = None
fuel_fixed_peak = None
- if fuel_type == 'electricity':
+ density = None
+ density_unit = None
+ lower_heating_value = None
+ lower_heating_value_unit = None
+ if fuel_type == 'Electricity':
fuel_fixed_monthly = float(item['fixed_monthly']['#text'])
fuel_fixed_peak = float(item['fixed_power']['#text']) / 1000
- elif fuel_type == 'gas':
- fuel_fixed_monthly = float(item['fixed_monthly']['#text'])
+ else:
+ if item['fixed_monthly']:
+ fuel_fixed_monthly = float(item['fixed_monthly']['#text'])
+ if item['density']:
+ density = float(item['density']['#text'])
+ density_unit = item['density']['@density_unit']
+ if item['lower_heating_value']:
+ lower_heating_value = float(item['lower_heating_value']['#text'])
+ lower_heating_value_unit = item['lower_heating_value']['@lhv_unit']
fuel = Fuel(fuel_type,
fixed_monthly=fuel_fixed_monthly,
fixed_power=fuel_fixed_peak,
variable=fuel_variable,
- variable_units=fuel_variable_units)
+ variable_units=fuel_variable_units,
+ density=density,
+ density_unit=density_unit,
+ lower_heating_value=lower_heating_value,
+ lower_heating_value_unit=lower_heating_value_unit)
fuels.append(fuel)
heating_equipment_maintenance = float(entry['maintenance']['heating_equipment']['#text']) / 1000
cooling_equipment_maintenance = float(entry['maintenance']['cooling_equipment']['#text']) / 1000
diff --git a/hub/catalog_factories/data_models/cost/fuel.py b/hub/catalog_factories/data_models/cost/fuel.py
index f785cc59..5eb4866c 100644
--- a/hub/catalog_factories/data_models/cost/fuel.py
+++ b/hub/catalog_factories/data_models/cost/fuel.py
@@ -16,13 +16,21 @@ class Fuel:
fixed_monthly=None,
fixed_power=None,
variable=None,
- variable_units=None):
+ variable_units=None,
+ density=None,
+ density_unit=None,
+ lower_heating_value=None,
+ lower_heating_value_unit=None):
self._fuel_type = fuel_type
self._fixed_monthly = fixed_monthly
self._fixed_power = fixed_power
self._variable = variable
self._variable_units = variable_units
+ self._density = density
+ self._density_unit = density_unit
+ self._lower_heating_value = lower_heating_value
+ self._lower_heating_value_unit = lower_heating_value_unit
@property
def type(self):
@@ -58,13 +66,33 @@ class Fuel:
"""
return self._variable, self._variable_units
+ @property
+ def density(self) -> Union[tuple[None, None], tuple[float, str]]:
+ """
+ Get fuel density in given units
+ :return: None, None or float, str
+ """
+ return self._density, self._density_unit
+
+ @property
+ def lower_heating_value(self) -> Union[tuple[None, None], tuple[float, str]]:
+ """
+ Get lower heating value in given units
+ :return: None, None or float, str
+ """
+ return self._lower_heating_value, self._lower_heating_value_unit
+
def to_dictionary(self):
"""Class content to dictionary"""
content = {'Fuel': {'fuel type': self.type,
'fixed operational costs [currency/month]': self.fixed_monthly,
'fixed operational costs depending on the peak power consumed [currency/month W]': self.fixed_power,
'variable operational costs': self.variable[0],
- 'units': self.variable[1]
+ 'units': self.variable[1],
+ 'density': self.density[0],
+ 'density unit': self.density[1],
+ 'lower heating value': self.lower_heating_value[0],
+ 'lower heating value unit': self.lower_heating_value[1]
}
}
diff --git a/hub/catalog_factories/data_models/energy_systems/__pycache__/generation_system.cpython-39.pyc b/hub/catalog_factories/data_models/energy_systems/__pycache__/generation_system.cpython-39.pyc
index f24740fd..81666400 100644
Binary files a/hub/catalog_factories/data_models/energy_systems/__pycache__/generation_system.cpython-39.pyc and b/hub/catalog_factories/data_models/energy_systems/__pycache__/generation_system.cpython-39.pyc differ
diff --git a/hub/catalog_factories/data_models/energy_systems/__pycache__/non_pv_generation_system.cpython-39.pyc b/hub/catalog_factories/data_models/energy_systems/__pycache__/non_pv_generation_system.cpython-39.pyc
index 23f64ef9..d66f0daa 100644
Binary files a/hub/catalog_factories/data_models/energy_systems/__pycache__/non_pv_generation_system.cpython-39.pyc and b/hub/catalog_factories/data_models/energy_systems/__pycache__/non_pv_generation_system.cpython-39.pyc differ
diff --git a/hub/catalog_factories/data_models/energy_systems/__pycache__/pv_generation_system.cpython-39.pyc b/hub/catalog_factories/data_models/energy_systems/__pycache__/pv_generation_system.cpython-39.pyc
index 7fc22430..489baa34 100644
Binary files a/hub/catalog_factories/data_models/energy_systems/__pycache__/pv_generation_system.cpython-39.pyc and b/hub/catalog_factories/data_models/energy_systems/__pycache__/pv_generation_system.cpython-39.pyc differ
diff --git a/hub/catalog_factories/data_models/energy_systems/__pycache__/thermal_storage_system.cpython-39.pyc b/hub/catalog_factories/data_models/energy_systems/__pycache__/thermal_storage_system.cpython-39.pyc
index 8ee8d1d8..31ec81fc 100644
Binary files a/hub/catalog_factories/data_models/energy_systems/__pycache__/thermal_storage_system.cpython-39.pyc and b/hub/catalog_factories/data_models/energy_systems/__pycache__/thermal_storage_system.cpython-39.pyc differ
diff --git a/hub/catalog_factories/data_models/energy_systems/generation_system.py b/hub/catalog_factories/data_models/energy_systems/generation_system.py
index cb4b1e9d..f0692f9d 100644
--- a/hub/catalog_factories/data_models/energy_systems/generation_system.py
+++ b/hub/catalog_factories/data_models/energy_systems/generation_system.py
@@ -20,7 +20,7 @@ class GenerationSystem(ABC):
"""
def __init__(self, system_id, name, model_name=None, manufacturer=None, fuel_type=None,
- distribution_systems=None, energy_storage_systems=None):
+ distribution_systems=None, energy_storage_systems=None, number_of_units=None):
self._system_id = system_id
self._name = name
self._model_name = model_name
@@ -28,6 +28,7 @@ class GenerationSystem(ABC):
self._fuel_type = fuel_type
self._distribution_systems = distribution_systems
self._energy_storage_systems = energy_storage_systems
+ self._number_of_units = number_of_units
@property
def id(self):
@@ -93,6 +94,14 @@ class GenerationSystem(ABC):
"""
return self._energy_storage_systems
+ @property
+ def number_of_units(self):
+ """
+ Get the number of a specific generation unit
+ :return: int
+ """
+ return self._number_of_units
+
def to_dictionary(self):
"""Class content to dictionary"""
raise NotImplementedError
diff --git a/hub/catalog_factories/data_models/energy_systems/non_pv_generation_system.py b/hub/catalog_factories/data_models/energy_systems/non_pv_generation_system.py
index 5b203d01..10481e71 100644
--- a/hub/catalog_factories/data_models/energy_systems/non_pv_generation_system.py
+++ b/hub/catalog_factories/data_models/energy_systems/non_pv_generation_system.py
@@ -25,9 +25,11 @@ class NonPvGenerationSystem(GenerationSystem):
maximum_cooling_supply_temperature=None, minimum_cooling_supply_temperature=None, heat_output_curve=None,
heat_fuel_consumption_curve=None, heat_efficiency_curve=None, cooling_output_curve=None,
cooling_fuel_consumption_curve=None, cooling_efficiency_curve=None,
- distribution_systems=None, energy_storage_systems=None, dual_supply_capability=False):
+ distribution_systems=None, energy_storage_systems=None, domestic_hot_water=False,
+ heat_supply_temperature=None, cooling_supply_temperature=None, number_of_units=None, reversible=None,
+ simultaneous_heat_cold=None):
super().__init__(system_id=system_id, name=name, model_name=model_name, manufacturer=manufacturer, fuel_type=fuel_type,
- distribution_systems=distribution_systems, energy_storage_systems=energy_storage_systems)
+ distribution_systems=distribution_systems, energy_storage_systems=energy_storage_systems, number_of_units=number_of_units)
self._system_type = system_type
self._nominal_heat_output = nominal_heat_output
self._maximum_heat_output = maximum_heat_output
@@ -53,7 +55,11 @@ class NonPvGenerationSystem(GenerationSystem):
self._cooling_output_curve = cooling_output_curve
self._cooling_fuel_consumption_curve = cooling_fuel_consumption_curve
self._cooling_efficiency_curve = cooling_efficiency_curve
- self._dual_supply_capability = dual_supply_capability
+ self._domestic_hot_water = domestic_hot_water
+ self._heat_supply_temperature = heat_supply_temperature
+ self._cooling_supply_temperature = cooling_supply_temperature
+ self._reversible = reversible
+ self._simultaneous_heat_cold = simultaneous_heat_cold
@property
def system_type(self):
@@ -256,12 +262,44 @@ class NonPvGenerationSystem(GenerationSystem):
return self._cooling_efficiency_curve
@property
- def dual_supply_capability(self):
+ def domestic_hot_water(self):
"""
- Get dual supply capability
+ Get the ability to produce domestic hot water
:return: bool
"""
- return self._dual_supply_capability
+ return self._domestic_hot_water
+
+ @property
+ def heat_supply_temperature(self):
+ """
+ Get heat supply temperature
+ :return: list
+ """
+ return self._heat_supply_temperature
+
+ @property
+ def cooling_supply_temperature(self):
+ """
+ Get heat supply temperature
+ :return: list
+ """
+ return self._cooling_supply_temperature
+
+ @property
+ def reversibility(self):
+ """
+ Get the ability to produce heating and cooling
+ :return: bool
+ """
+ return self._reversible
+
+ @property
+ def simultaneous_heat_cold(self):
+ """
+ Get the ability to produce heating and cooling at the same time
+ :return: bool
+ """
+ return self._simultaneous_heat_cold
def to_dictionary(self):
"""Class content to dictionary"""
@@ -304,7 +342,12 @@ class NonPvGenerationSystem(GenerationSystem):
'cooling efficiency curve': self.cooling_efficiency_curve,
'distribution systems connected': _distribution_systems,
'storage systems connected': _energy_storage_systems,
- 'dual supply capability': self.dual_supply_capability
+ 'domestic hot water production capability': self.domestic_hot_water,
+ 'heat supply temperature': self.heat_supply_temperature,
+ 'cooling supply temperature': self.cooling_supply_temperature,
+ 'number of units': self.number_of_units,
+ 'reversible cycle': self.reversibility,
+ 'simultaneous heat and cooling production': self.simultaneous_heat_cold
}
}
return content
diff --git a/hub/catalog_factories/data_models/energy_systems/pv_generation_system.py b/hub/catalog_factories/data_models/energy_systems/pv_generation_system.py
index 87228afa..319070c0 100644
--- a/hub/catalog_factories/data_models/energy_systems/pv_generation_system.py
+++ b/hub/catalog_factories/data_models/energy_systems/pv_generation_system.py
@@ -18,10 +18,10 @@ class PvGenerationSystem(GenerationSystem):
nominal_electricity_output=None, nominal_ambient_temperature=None, nominal_cell_temperature=None,
nominal_radiation=None, standard_test_condition_cell_temperature=None,
standard_test_condition_maximum_power=None, cell_temperature_coefficient=None, width=None, height=None,
- distribution_systems=None, energy_storage_systems=None):
+ distribution_systems=None, energy_storage_systems=None, number_of_units=None):
super().__init__(system_id=system_id, name=name, model_name=model_name,
manufacturer=manufacturer, fuel_type='renewable', distribution_systems=distribution_systems,
- energy_storage_systems=energy_storage_systems)
+ energy_storage_systems=energy_storage_systems, number_of_units=number_of_units)
self._system_type = system_type
self._electricity_efficiency = electricity_efficiency
self._nominal_electricity_output = nominal_electricity_output
@@ -147,7 +147,8 @@ class PvGenerationSystem(GenerationSystem):
'width': self.width,
'height': self.height,
'distribution systems connected': _distribution_systems,
- 'storage systems connected': _energy_storage_systems
+ 'storage systems connected': _energy_storage_systems,
+ 'number of units': self.number_of_units
}
}
return content
diff --git a/hub/catalog_factories/data_models/energy_systems/thermal_storage_system.py b/hub/catalog_factories/data_models/energy_systems/thermal_storage_system.py
index d3cdf255..ca773e09 100644
--- a/hub/catalog_factories/data_models/energy_systems/thermal_storage_system.py
+++ b/hub/catalog_factories/data_models/energy_systems/thermal_storage_system.py
@@ -17,7 +17,7 @@ class ThermalStorageSystem(EnergyStorageSystem):
def __init__(self, storage_id, type_energy_stored=None, model_name=None, manufacturer=None, storage_type=None,
nominal_capacity=None, losses_ratio=None, volume=None, height=None, layers=None,
- maximum_operating_temperature=None, storage_medium=None):
+ maximum_operating_temperature=None, storage_medium=None, heating_coil_capacity=None):
super().__init__(storage_id, model_name, manufacturer, nominal_capacity, losses_ratio)
self._type_energy_stored = type_energy_stored
@@ -27,6 +27,7 @@ class ThermalStorageSystem(EnergyStorageSystem):
self._layers = layers
self._maximum_operating_temperature = maximum_operating_temperature
self._storage_medium = storage_medium
+ self._heating_coil_capacity = heating_coil_capacity
@property
def type_energy_stored(self):
@@ -84,6 +85,14 @@ class ThermalStorageSystem(EnergyStorageSystem):
"""
return self._storage_medium
+ @property
+ def heating_coil_capacity(self):
+ """
+ Get heating coil capacity in Watts
+ :return: [material
+ """
+ return self._heating_coil_capacity
+
def to_dictionary(self):
"""Class content to dictionary"""
_layers = None
@@ -110,7 +119,8 @@ class ThermalStorageSystem(EnergyStorageSystem):
'height [m]': self.height,
'layers': _layers,
'maximum operating temperature [Celsius]': self.maximum_operating_temperature,
- 'storage_medium': self.storage_medium.to_dictionary()
+ 'storage_medium': self.storage_medium.to_dictionary(),
+ 'heating coil capacity [W]': self.heating_coil_capacity
}
}
return content
diff --git a/hub/catalog_factories/energy_systems/__pycache__/montreal_custom_catalog.cpython-39.pyc b/hub/catalog_factories/energy_systems/__pycache__/montreal_custom_catalog.cpython-39.pyc
index e6e57547..18eeb41c 100644
Binary files a/hub/catalog_factories/energy_systems/__pycache__/montreal_custom_catalog.cpython-39.pyc and b/hub/catalog_factories/energy_systems/__pycache__/montreal_custom_catalog.cpython-39.pyc differ
diff --git a/hub/catalog_factories/energy_systems/__pycache__/montreal_future_system_catalogue.cpython-39.pyc b/hub/catalog_factories/energy_systems/__pycache__/montreal_future_system_catalogue.cpython-39.pyc
index 4987531e..0ab98f97 100644
Binary files a/hub/catalog_factories/energy_systems/__pycache__/montreal_future_system_catalogue.cpython-39.pyc and b/hub/catalog_factories/energy_systems/__pycache__/montreal_future_system_catalogue.cpython-39.pyc differ
diff --git a/hub/catalog_factories/energy_systems/montreal_custom_catalog.py b/hub/catalog_factories/energy_systems/montreal_custom_catalog.py
index d731f781..d3e37e36 100644
--- a/hub/catalog_factories/energy_systems/montreal_custom_catalog.py
+++ b/hub/catalog_factories/energy_systems/montreal_custom_catalog.py
@@ -87,7 +87,7 @@ class MontrealCustomCatalog(Catalog):
cooling_efficiency=cooling_efficiency,
electricity_efficiency=electricity_efficiency,
energy_storage_systems=storage_systems,
- dual_supply_capability=False
+ domestic_hot_water=False
)
_equipments.append(generation_system)
diff --git a/hub/catalog_factories/energy_systems/montreal_future_system_catalogue.py b/hub/catalog_factories/energy_systems/montreal_future_system_catalogue.py
index d2eb35c3..f234ace4 100644
--- a/hub/catalog_factories/energy_systems/montreal_future_system_catalogue.py
+++ b/hub/catalog_factories/energy_systems/montreal_future_system_catalogue.py
@@ -121,12 +121,30 @@ class MontrealFutureSystemCatalogue(Catalog):
parameters = non_pv['cooling_efficiency_curve']['parameters']
coefficients = list(non_pv['cooling_efficiency_curve']['coefficients'].values())
cooling_efficiency_curve = PerformanceCurves(curve_type, dependant_variable, parameters, coefficients)
- dual_supply_capability = None
- if non_pv['dual_supply_capability'] is not None:
- if non_pv['dual_supply_capability'] == 'True':
- dual_supply_capability = True
+ dhw = None
+ if non_pv['domestic_hot_water'] is not None:
+ if non_pv['domestic_hot_water'] == 'True':
+ dhw = True
else:
- dual_supply_capability = False
+ dhw = False
+
+ reversible = None
+ if non_pv['reversible'] is not None:
+ if non_pv['reversible'] == 'True':
+ reversible = True
+ else:
+ reversible = False
+
+ dual_supply = None
+ if non_pv['simultaneous_heat_cold'] is not None:
+ if non_pv['simultaneous_heat_cold'] == 'True':
+ dual_supply = True
+ else:
+ dual_supply = False
+
+ heat_supply_temperature = None
+ cooling_supply_temperature = None
+ number_of_units = non_pv['number_of_units']
non_pv_component = NonPvGenerationSystem(system_id=system_id,
name=name,
@@ -160,7 +178,12 @@ class MontrealFutureSystemCatalogue(Catalog):
cooling_efficiency_curve=cooling_efficiency_curve,
distribution_systems=distribution_systems,
energy_storage_systems=energy_storage_systems,
- dual_supply_capability=dual_supply_capability)
+ domestic_hot_water=dhw,
+ heat_supply_temperature=heat_supply_temperature,
+ cooling_supply_temperature=cooling_supply_temperature,
+ number_of_units=number_of_units,
+ reversible=reversible,
+ simultaneous_heat_cold=dual_supply)
generation_components.append(non_pv_component)
pv_generation_components = self._archetypes['EnergySystemCatalog']['energy_generation_components'][
'pv_generation_component']
@@ -187,7 +210,7 @@ class MontrealFutureSystemCatalogue(Catalog):
storage_component = pv['energy_storage_systems']['storage_id']
storage_systems = self._search_storage_equipment(self._load_storage_components(), storage_component)
energy_storage_systems = storage_systems
-
+ number_of_units = pv['number_of_units']
pv_component = PvGenerationSystem(system_id=system_id,
name=name,
system_type=system_type,
@@ -205,7 +228,8 @@ class MontrealFutureSystemCatalogue(Catalog):
width=width,
height=height,
distribution_systems=distribution_systems,
- energy_storage_systems=energy_storage_systems)
+ energy_storage_systems=energy_storage_systems,
+ number_of_units=number_of_units)
generation_components.append(pv_component)
return generation_components
@@ -284,6 +308,7 @@ class MontrealFutureSystemCatalogue(Catalog):
layers = [insulation_layer, tank_layer]
nominal_capacity = tes['nominal_capacity']
losses_ratio = tes['losses_ratio']
+ heating_coil_capacity = None
storage_component = ThermalStorageSystem(storage_id=storage_id,
model_name=model_name,
type_energy_stored=type_energy_stored,
@@ -295,7 +320,8 @@ class MontrealFutureSystemCatalogue(Catalog):
height=height,
layers=layers,
maximum_operating_temperature=maximum_operating_temperature,
- storage_medium=medium)
+ storage_medium=medium,
+ heating_coil_capacity=heating_coil_capacity)
storage_components.append(storage_component)
for template in template_storages:
@@ -303,7 +329,7 @@ class MontrealFutureSystemCatalogue(Catalog):
storage_type = template['storage_type']
type_energy_stored = template['type_energy_stored']
maximum_operating_temperature = template['maximum_operating_temperature']
- height = template['physical_characteristics']['height']
+ height = float(template['physical_characteristics']['height'])
materials = self._load_materials()
insulation_material_id = template['insulation']['material_id']
insulation_material = self._search_material(materials, insulation_material_id)
@@ -322,6 +348,7 @@ class MontrealFutureSystemCatalogue(Catalog):
nominal_capacity = template['nominal_capacity']
losses_ratio = template['losses_ratio']
volume = template['physical_characteristics']['volume']
+ heating_coil_capacity = None
storage_component = ThermalStorageSystem(storage_id=storage_id,
model_name=model_name,
type_energy_stored=type_energy_stored,
@@ -333,7 +360,8 @@ class MontrealFutureSystemCatalogue(Catalog):
height=height,
layers=layers,
maximum_operating_temperature=maximum_operating_temperature,
- storage_medium=medium)
+ storage_medium=medium,
+ heating_coil_capacity=heating_coil_capacity)
storage_components.append(storage_component)
return storage_components
diff --git a/hub/city_model_structure/building.py b/hub/city_model_structure/building.py
index c01e5bf2..95f0f167 100644
--- a/hub/city_model_structure/building.py
+++ b/hub/city_model_structure/building.py
@@ -91,6 +91,9 @@ class Building(CityObject):
else:
logging.error('Building %s [%s] has an unexpected surface type %s.', self.name, self.aliases, surface.type)
self._heating_consumption_disaggregated = {}
+ self._domestic_hot_water_peak_load = None
+ self._fuel_consumption_breakdown = {}
+ self._domestic_how_water_consumption_disaggregated = {}
@property
def shell(self) -> Polyhedron:
@@ -470,6 +473,22 @@ class Building(CityObject):
results[cte.YEAR] = [max(monthly_values)]
return results
+ @property
+ def domestic_hot_water_peak_load(self) -> Union[None, dict]:
+ """
+ Get cooling peak load in W
+ :return: dict{[float]}
+ """
+ results = {}
+ monthly_values = None
+ if cte.HOUR in self.domestic_hot_water_heat_demand:
+ monthly_values = PeakLoads().peak_loads_from_hourly(self.domestic_hot_water_heat_demand[cte.HOUR])
+ if monthly_values is None:
+ return None
+ results[cte.MONTH] = [x for x in monthly_values]
+ results[cte.YEAR] = [max(monthly_values)]
+ return results
+
@property
def eave_height(self):
"""
@@ -841,6 +860,21 @@ class Building(CityObject):
"""
self._heating_consumption_disaggregated = value
+ @property
+ def domestic_how_water_consumption_disaggregated(self) -> dict:
+ """
+ Get energy consumed for heating from different fuels in J
+ return: dict
+ """
+ return self._domestic_how_water_consumption_disaggregated
+
+ @domestic_how_water_consumption_disaggregated.setter
+ def domestic_how_water_consumption_disaggregated(self, value):
+ """
+ Get energy consumed for heating from different fuels in J
+ return: dict
+ """
+ self._domestic_how_water_consumption_disaggregated = value
@property
def lower_corner(self):
@@ -855,3 +889,47 @@ class Building(CityObject):
Get building upper corner.
"""
return [self._max_x, self._max_y, self._max_z]
+
+ @property
+ def fuel_consumption_breakdown(self) -> dict:
+ """
+ Get energy consumption of different sectors
+ return: dict
+ """
+ fuel_breakdown = {cte.ELECTRICITY: {cte.LIGHTING: self.lighting_electrical_demand[cte.YEAR][0],
+ cte.APPLIANCES: self.appliances_electrical_demand[cte.YEAR][0]}}
+ energy_systems = self.energy_systems
+ for energy_system in energy_systems:
+ demand_types = energy_system.demand_types
+ generation_systems = energy_system.generation_systems
+ for demand_type in demand_types:
+ if demand_type == cte.COOLING:
+ fuel_breakdown[cte.ELECTRICITY][cte.COOLING] = self.cooling_consumption[cte.YEAR][0] / 3600
+ elif demand_type == cte.HEATING:
+ heating_fuels = [generation_system.fuel_type for generation_system in generation_systems]
+ if len(heating_fuels) > 1:
+ for fuel in heating_fuels:
+ if fuel == cte.ELECTRICITY:
+ fuel_breakdown[cte.ELECTRICITY][cte.HEATING] = self._heating_consumption_disaggregated[cte.ELECTRICITY][cte.YEAR][0]
+ elif fuel not in fuel_breakdown.keys():
+ fuel_breakdown[fuel] = {cte.HEATING: self._heating_consumption_disaggregated[fuel][cte.YEAR][0]}
+ else:
+ fuel_breakdown[fuel][cte.HEATING] = self._heating_consumption_disaggregated[fuel][cte.YEAR][0]
+ else:
+ fuel = heating_fuels[0]
+ if fuel == cte.ELECTRICITY:
+ fuel_breakdown[cte.ELECTRICITY][cte.HEATING] = self.heating_consumption[cte.YEAR][0]
+ elif fuel not in fuel_breakdown.keys():
+ fuel_breakdown[fuel] = {cte.HEATING: self.heating_consumption[cte.YEAR][0]}
+ else:
+ fuel_breakdown[fuel][cte.HEATING] = self.heating_consumption[cte.YEAR][0]
+ elif demand_type == cte.DOMESTIC_HOT_WATER:
+ for generation_system in generation_systems:
+ if generation_system.fuel_type == cte.ELECTRICITY:
+ fuel_breakdown[cte.ELECTRICITY][cte.DOMESTIC_HOT_WATER] = self.domestic_hot_water_consumption[cte.YEAR][0]
+ elif generation_system.fuel_type not in fuel_breakdown.keys():
+ fuel_breakdown[generation_system.fuel_type] = {cte.DOMESTIC_HOT_WATER: self.domestic_hot_water_consumption[cte.YEAR][0]}
+ else:
+ fuel_breakdown[generation_system.fuel_type][cte.DOMESTIC_HOT_WATER] = self.domestic_hot_water_consumption[cte.YEAR][0]
+ self._fuel_consumption_breakdown = fuel_breakdown
+ return self._fuel_consumption_breakdown
diff --git a/hub/city_model_structure/energy_systems/__pycache__/generation_system.cpython-39.pyc b/hub/city_model_structure/energy_systems/__pycache__/generation_system.cpython-39.pyc
index eccddbab..4d2de077 100644
Binary files a/hub/city_model_structure/energy_systems/__pycache__/generation_system.cpython-39.pyc and b/hub/city_model_structure/energy_systems/__pycache__/generation_system.cpython-39.pyc differ
diff --git a/hub/city_model_structure/energy_systems/__pycache__/non_pv_generation_system.cpython-39.pyc b/hub/city_model_structure/energy_systems/__pycache__/non_pv_generation_system.cpython-39.pyc
index b51798c1..0c6b8d45 100644
Binary files a/hub/city_model_structure/energy_systems/__pycache__/non_pv_generation_system.cpython-39.pyc and b/hub/city_model_structure/energy_systems/__pycache__/non_pv_generation_system.cpython-39.pyc differ
diff --git a/hub/city_model_structure/energy_systems/__pycache__/thermal_storage_system.cpython-39.pyc b/hub/city_model_structure/energy_systems/__pycache__/thermal_storage_system.cpython-39.pyc
index c27735b2..cb1c3543 100644
Binary files a/hub/city_model_structure/energy_systems/__pycache__/thermal_storage_system.cpython-39.pyc and b/hub/city_model_structure/energy_systems/__pycache__/thermal_storage_system.cpython-39.pyc differ
diff --git a/hub/city_model_structure/energy_systems/generation_system.py b/hub/city_model_structure/energy_systems/generation_system.py
index 394c2f09..4d06eb14 100644
--- a/hub/city_model_structure/energy_systems/generation_system.py
+++ b/hub/city_model_structure/energy_systems/generation_system.py
@@ -12,6 +12,8 @@ from typing import Union, List
from hub.city_model_structure.energy_systems.distribution_system import DistributionSystem
from hub.city_model_structure.energy_systems.energy_storage_system import EnergyStorageSystem
+from hub.city_model_structure.energy_systems.thermal_storage_system import ThermalStorageSystem
+from hub.city_model_structure.energy_systems.electrical_storage_system import ElectricalStorageSystem
class GenerationSystem(ABC):
@@ -26,6 +28,7 @@ class GenerationSystem(ABC):
self._fuel_type = None
self._distribution_systems = None
self._energy_storage_systems = None
+ self._number_of_units = None
@property
def system_type(self):
@@ -124,7 +127,7 @@ class GenerationSystem(ABC):
self._distribution_systems = value
@property
- def energy_storage_systems(self) -> Union[None, List[EnergyStorageSystem]]:
+ def energy_storage_systems(self) -> Union[None, List[ThermalStorageSystem], List[ElectricalStorageSystem]]:
"""
Get energy storage systems connected to this generation system
:return: [EnergyStorageSystem]
@@ -138,3 +141,19 @@ class GenerationSystem(ABC):
:param value: [EnergyStorageSystem]
"""
self._energy_storage_systems = value
+
+ @property
+ def number_of_units(self):
+ """
+ Get number of a specific generation unit
+ :return: int
+ """
+ return self._number_of_units
+
+ @number_of_units.setter
+ def number_of_units(self, value):
+ """
+ Set number of a specific generation unit
+ :return: int
+ """
+ self._number_of_units = value
diff --git a/hub/city_model_structure/energy_systems/non_pv_generation_system.py b/hub/city_model_structure/energy_systems/non_pv_generation_system.py
index fea1d7b2..e5df16cd 100644
--- a/hub/city_model_structure/energy_systems/non_pv_generation_system.py
+++ b/hub/city_model_structure/energy_systems/non_pv_generation_system.py
@@ -42,7 +42,11 @@ class NonPvGenerationSystem(GenerationSystem):
self._cooling_output_curve = None
self._cooling_fuel_consumption_curve = None
self._cooling_efficiency_curve = None
- self._dual_supply_capability = None
+ self._domestic_hot_water = None
+ self._heat_supply_temperature = None
+ self._cooling_supply_temperature = None
+ self._reversible = None
+ self._simultaneous_heat_cold = None
@property
def nominal_heat_output(self):
@@ -429,21 +433,90 @@ class NonPvGenerationSystem(GenerationSystem):
self._cooling_efficiency_curve = value
@property
- def dual_supply_capability(self):
+ def domestic_hot_water(self):
"""
- Get the capability of the generation component for simultaneous heat and cold production
+ Get the capability of generating domestic hot water
:return: bool
"""
- return self._dual_supply_capability
+ return self._domestic_hot_water
- @dual_supply_capability.setter
- def dual_supply_capability(self, value):
+ @domestic_hot_water.setter
+ def domestic_hot_water(self, value):
"""
- Set the capability of the generation component for simultaneous heat and cold production
+ Set the capability of generating domestic hot water
:return: bool
"""
- self._dual_supply_capability = value
+ self._domestic_hot_water = value
+ @property
+ def heat_supply_temperature(self):
+ """
+ Get the hourly heat supply temperature
+ :return: list
+ """
+ return self._heat_supply_temperature
+
+ @heat_supply_temperature.setter
+ def heat_supply_temperature(self, value):
+ """
+ set the hourly heat supply temperature
+ :param value:
+ :return: list
+ """
+ self._heat_supply_temperature = value
+
+ @property
+ def cooling_supply_temperature(self):
+ """
+ Get the hourly cooling supply temperature
+ :return: list
+ """
+ return self._heat_supply_temperature
+
+ @cooling_supply_temperature.setter
+ def cooling_supply_temperature(self, value):
+ """
+ set the hourly cooling supply temperature
+ :param value:
+ :return: list
+ """
+ self._cooling_supply_temperature = value
+
+ @property
+ def reversibility(self):
+ """
+ Get the capability of generating both heating and cooling
+
+ :return: bool
+ """
+ return self._reversible
+
+ @reversibility.setter
+ def reversibility(self, value):
+ """
+ Set the capability of generating domestic hot water
+
+ :return: bool
+ """
+ self._reversible = value
+
+ @property
+ def simultaneous_heat_cold(self):
+ """
+ Get the capability of generating both heating and cooling at the same time
+
+ :return: bool
+ """
+ return self._simultaneous_heat_cold
+
+ @simultaneous_heat_cold.setter
+ def simultaneous_heat_cold(self, value):
+ """
+ Set the capability of generating domestic hot water at the same time
+
+ :return: bool
+ """
+ self._simultaneous_heat_cold = value
diff --git a/hub/city_model_structure/energy_systems/thermal_storage_system.py b/hub/city_model_structure/energy_systems/thermal_storage_system.py
index 0f7f6a12..30e1579e 100644
--- a/hub/city_model_structure/energy_systems/thermal_storage_system.py
+++ b/hub/city_model_structure/energy_systems/thermal_storage_system.py
@@ -22,6 +22,7 @@ class ThermalStorageSystem(EnergyStorageSystem):
self._height = None
self._layers = None
self._maximum_operating_temperature = None
+ self._heating_coil_capacity = None
@property
def volume(self):
@@ -86,3 +87,19 @@ class ThermalStorageSystem(EnergyStorageSystem):
:param value: float
"""
self._maximum_operating_temperature = value
+
+ @property
+ def heating_coil_capacity(self):
+ """
+ Get heating coil capacity in Watts
+ :return: float
+ """
+ return self._maximum_operating_temperature
+
+ @heating_coil_capacity.setter
+ def heating_coil_capacity(self, value):
+ """
+ Set heating coil capacity in Watts
+ :param value: float
+ """
+ self._heating_coil_capacity = value
diff --git a/hub/data/costs/montreal_costs_completed.xml b/hub/data/costs/montreal_costs_completed.xml
index 64be368c..5ce1fde9 100644
--- a/hub/data/costs/montreal_costs_completed.xml
+++ b/hub/data/costs/montreal_costs_completed.xml
@@ -38,38 +38,33 @@
25
- 47.62
- 47.62
+ 550
+ 550
15
- 47.62
- 47.62
+ 700
+ 700
15
- 47.62
- 47.62
+ 850
+ 850
15
- 47.62
- 47.62
+ 480
+ 480
15
-
- 47.62
- 47.62
- 15
-
- 47.62
- 47.62
+ 350
+ 350
15
- 47.62
- 47.62
+ 300
+ 300
15
@@ -90,26 +85,26 @@
- 47.62
- 47.62
+ 50
+ 50
15
- 47.62
- 47.62
+ 80
+ 80
15
- 47.62
- 47.62
+ 850
+ 850
15
- 47.62
- 47.62
+ 50
+ 50
15
@@ -128,20 +123,30 @@
-
- 12.27
- 0
- 0.075
+
+ 12.27
+ 0
+ 0.075
+
+
-
+
17.71
0.0640
+ 0.777
+ 47.1
-
+
+
1.2
+ 0.846
+ 42.6
-
- 0.04
+
+
+ 0.04
+
+ 18
@@ -201,78 +206,73 @@
25
- 47.62
- 47.62
+ 550
+ 550
15
- 47.62
- 47.62
+ 700
+ 700
15
- 47.62
- 47.62
+ 850
+ 850
15
- 47.62
- 47.62
+ 480
+ 480
15
-
- 47.62
- 47.62
- 15
-
- 47.62
- 47.62
+ 350
+ 350
15
- 47.62
- 47.62
+ 300
+ 300
15
-
+
622.86
622.86
15
-
+
- 0
+ 0
0
15
-
+
47.62
47.62
15
-
+
- 47.62
- 47.62
+ 50
+ 50
15
- 47.62
- 47.62
+ 80
+ 80
15
- 47.62
- 47.62
+ 850
+ 850
15
- 47.62
- 47.62
+ 50
+ 50
15
@@ -291,20 +291,28 @@
-
+
12.27
0
0.075
-
+
17.71
0.0640
+ 0.777
+ 47.1
-
+
+
1.2
+ 0.846
+ 42.6
-
- 0.04
+
+
+ 0.04
+
+ 18
diff --git a/hub/data/energy_systems/montreal_future_systems.xml b/hub/data/energy_systems/montreal_future_systems.xml
index 769f87bd..4437fe62 100644
--- a/hub/data/energy_systems/montreal_future_systems.xml
+++ b/hub/data/energy_systems/montreal_future_systems.xml
@@ -5,11 +5,11 @@
1
Water
-
-
-
-
-
+
+
+
+
+
981.0
4180.0
0.6
@@ -26,7 +26,7 @@
4.7
23.5
0.95
- True
+ False
natural gas
@@ -50,7 +50,11 @@
-
+ True
+
+
+
+ False
2
@@ -62,7 +66,7 @@
6.15
30.8
0.95
- True
+ False
natural gas
@@ -86,7 +90,11 @@
-
+ True
+
+
+
+ False
3
@@ -98,7 +106,7 @@
8.8
44
0.95
- True
+ False
natural gas
@@ -122,7 +130,11 @@
-
+ True
+
+
+
+ False
4
@@ -134,7 +146,7 @@
12.3
61.5
0.95
- True
+ False
natural gas
@@ -158,7 +170,11 @@
-
+ True
+
+
+
+ False
5
@@ -170,7 +186,7 @@
4.0
35.2
0.95
- True
+ False
natural gas
@@ -194,7 +210,11 @@
-
+ True
+
+
+
+ False
6
@@ -206,7 +226,7 @@
4.0
35.2
0.95
- False
+ False
natural gas
@@ -230,7 +250,11 @@
-
+ True
+
+
+
+ False
7
@@ -242,7 +266,7 @@
2.5
25.0
0.96
-
+ False
natural gas
@@ -266,7 +290,11 @@
-
+ True
+
+
+
+ False
8
@@ -278,7 +306,7 @@
3.2
32.0
0.96
-
+ False
natural gas
@@ -302,7 +330,11 @@
-
+ True
+
+
+
+ False
9
@@ -314,7 +346,7 @@
4.5
45.0
0.95
- True
+ False
natural gas
@@ -338,7 +370,11 @@
-
+ True
+
+
+
+ False
10
@@ -350,7 +386,7 @@
3.5
35.0
0.95
- True
+ False
natural gas
@@ -374,7 +410,11 @@
-
+ True
+
+
+
+ False
11
@@ -386,7 +426,7 @@
5.3
53.0
0.95
- True
+ False
natural gas
@@ -410,7 +450,11 @@
-
+ True
+
+
+
+ False
12
@@ -430,6 +474,7 @@
1.048
+
13
@@ -441,10 +486,10 @@
0
51.7
3.32
-
+ True
Electricity
Air
- water
+ Water
@@ -471,7 +516,11 @@
- False
+ False
+
+
+
+ False
14
@@ -483,10 +532,10 @@
0
279.3
3.07
-
+ True
Electricity
Air
- water
+ Water
@@ -513,7 +562,11 @@
- False
+ False
+
+
+
+ False
15
@@ -525,10 +578,10 @@
0
557
3.46
-
+ True
Electricity
Air
- water
+ Water
@@ -555,7 +608,11 @@
- False
+ False
+
+
+
+ False
16
@@ -567,7 +624,7 @@
0.90
-
+ False
natural gas
@@ -593,7 +650,11 @@
6
-
+ True
+
+
+
+ False
17
@@ -605,7 +666,7 @@
0.95
-
+ False
electricity
@@ -631,11 +692,15 @@
6
-
+ False
+
+
+
+ False
18
- template Air-to-Water heat pump
+ template Air-to-Water heat pump with storage
heat pump
@@ -643,10 +708,10 @@
3
-
+ True
electricity
Air
- water
+ Water
@@ -669,11 +734,15 @@
6
- True
+ True
+
+
+
+ True
19
- template Groundwater-to-Water heat pump
+ template Groundwater-to-Water heat pump with storage
heat pump
@@ -681,10 +750,10 @@
3.5
-
+ True
electricity
Ground
- water
+ Water
@@ -707,11 +776,15 @@
6
- True
+ True
+
+
+
+ True
20
- template Water-to-Water heat pump
+ template Water-to-Water heat pump with storage
heat pump
@@ -719,10 +792,10 @@
3.5
-
+ True
electricity
Water
- water
+ Water
@@ -745,7 +818,11 @@
6
- True
+ True
+
+
+
+ False
21
@@ -757,7 +834,7 @@
0.90
-
+ False
natural gas
@@ -781,7 +858,11 @@
-
+ True
+
+
+
+ False
22
@@ -793,7 +874,7 @@
0.95
-
+ False
electricity
@@ -817,7 +898,11 @@
-
+ True
+
+
+
+ False
23
@@ -829,10 +914,10 @@
3
-
+ True
electricity
Air
- water
+ Water
@@ -853,7 +938,11 @@
- True
+ True
+
+
+
+ True
24
@@ -865,10 +954,10 @@
3.5
-
+ True
electricity
Ground
- water
+ Water
@@ -889,7 +978,11 @@
- True
+ True
+
+
+
+ True
25
@@ -901,10 +994,10 @@
3.5
-
+ True
electricity
Water
- water
+ Water
@@ -925,7 +1018,11 @@
- True
+ True
+
+
+
+ True
26
@@ -945,7 +1042,51 @@
1.0
+
+ False
+
+ 27
+ template domestic hot water heat pump
+ heat pump
+
+
+
+
+
+ 3.5
+
+ electricity
+ Water
+ Water
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 7
+
+ True
+
+
+
+ False
+
@@ -970,8 +1111,9 @@
1
sensible
-
-
+
+
+
2
@@ -995,8 +1137,9 @@
1
sensible
-
-
+
+
+
3
@@ -1020,8 +1163,9 @@
1
sensible
-
-
+
+
+
4
@@ -1044,8 +1188,9 @@
1
sensible
-
-
+
+
+
5
@@ -1069,15 +1214,16 @@
1
sensible
-
-
+
+
+
6
template Hot Water Storage Tank
thermal
- HF 200
-
+
+
95.0
1
@@ -1088,47 +1234,74 @@
0
1.5
Steel
-
+
1
sensible
-
-
+
+
+
+
+
+ 7
+ template Hot Water Storage Tank with Heating Coil
+ thermal
+
+
+ 95.0
+
+ 1
+ 90.0
+
+
+ 2
+ 0
+ 1.5
+ Steel
+
+
+
+ 1
+
+ sensible
+
+
+
1
Polyurethane
-
-
-
-
-
-
-
+
+
+
+
+
+
+
0.028
2
Steel
-
-
-
-
-
-
-
+
+
+
+
+
+
+
18
-
+
-
+
@@ -1226,7 +1399,45 @@
26
+
+ 8
+ 4 pipe system with air source heat pump storage and gas boiler
+ schemas/ASHP+TES+GasBoiler.jpg
+
+ heating
+ cooling
+
+
+ 21
+ 18
+
+
+
+ 9
+ 4 pipe system with air source heat pump storage and electric boiler
+ schemas/ASHP+TES+GasBoiler.jpg
+
+ heating
+ cooling
+
+
+ 22
+ 18
+
+
+
+ 10
+ Domestic Hot Water Heat Pump with Coiled Storage
+ schemas/ASHP+TES+GasBoiler.jpg
+
+ domestic_hot_water
+
+
+ 27
+
+
+
PV+ASHP+GasBoiler+TES
@@ -1306,6 +1517,14 @@
6
+
+ PV+4Pipe+DHW
+
+ 7
+ 8
+ 10
+
+
diff --git a/hub/helpers/constants.py b/hub/helpers/constants.py
index 23fab290..a48718bd 100644
--- a/hub/helpers/constants.py
+++ b/hub/helpers/constants.py
@@ -292,6 +292,7 @@ WOOD = 'Wood'
GAS = 'Gas'
DIESEL = 'Diesel'
COAL = 'Coal'
+BIOMASS = 'Biomass'
AIR = 'Air'
WATER = 'Water'
GEOTHERMAL = 'Geothermal'
diff --git a/hub/imports/energy_systems/__pycache__/montreal_custom_energy_system_parameters.cpython-39.pyc b/hub/imports/energy_systems/__pycache__/montreal_custom_energy_system_parameters.cpython-39.pyc
index 6c52da3b..4e8f384a 100644
Binary files a/hub/imports/energy_systems/__pycache__/montreal_custom_energy_system_parameters.cpython-39.pyc and b/hub/imports/energy_systems/__pycache__/montreal_custom_energy_system_parameters.cpython-39.pyc differ
diff --git a/hub/imports/energy_systems/__pycache__/montreal_future_energy_systems_parameters.cpython-39.pyc b/hub/imports/energy_systems/__pycache__/montreal_future_energy_systems_parameters.cpython-39.pyc
index 30d50078..24cbd513 100644
Binary files a/hub/imports/energy_systems/__pycache__/montreal_future_energy_systems_parameters.cpython-39.pyc and b/hub/imports/energy_systems/__pycache__/montreal_future_energy_systems_parameters.cpython-39.pyc differ
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 348df9fe..00f84d3b 100644
--- a/hub/imports/energy_systems/montreal_custom_energy_system_parameters.py
+++ b/hub/imports/energy_systems/montreal_custom_energy_system_parameters.py
@@ -113,7 +113,7 @@ class MontrealCustomEnergySystemParameters:
else:
_generic_storage_system = ThermalStorageSystem()
_generic_storage_system.type_energy_stored = 'thermal'
- _generation_system.energy_storage_systems = [_generic_storage_system]
+ _generation_system.energy_storage_systems = _generic_storage_system
_generation_systems.append(_generation_system)
return _generation_systems
diff --git a/hub/imports/energy_systems/montreal_future_energy_systems_parameters.py b/hub/imports/energy_systems/montreal_future_energy_systems_parameters.py
index 542608a0..8612f845 100644
--- a/hub/imports/energy_systems/montreal_future_energy_systems_parameters.py
+++ b/hub/imports/energy_systems/montreal_future_energy_systems_parameters.py
@@ -140,12 +140,13 @@ class MontrealFutureEnergySystemParameters:
_generation_system.cooling_output_curve = archetype_generation_system.cooling_output_curve
_generation_system.cooling_fuel_consumption_curve = archetype_generation_system.cooling_fuel_consumption_curve
_generation_system.cooling_efficiency_curve = archetype_generation_system.cooling_efficiency_curve
- _generation_system.dual_supply_capability = archetype_generation_system.dual_supply_capability
+ _generation_system.domestic_hot_water = archetype_generation_system.domestic_hot_water
_generation_system.nominal_electricity_output = archetype_generation_system.nominal_electricity_output
_generation_system.source_medium = archetype_generation_system.source_medium
_generation_system.heat_efficiency = archetype_generation_system.heat_efficiency
_generation_system.cooling_efficiency = archetype_generation_system.cooling_efficiency
_generation_system.electricity_efficiency = archetype_generation_system.electricity_efficiency
+ _generation_system.reversibility = archetype_generation_system.reversibility
_generic_storage_system = None
if archetype_generation_system.energy_storage_systems is not None:
_storage_systems = []
@@ -155,11 +156,18 @@ class MontrealFutureEnergySystemParameters:
_generic_storage_system.type_energy_stored = 'electrical'
else:
_generic_storage_system = ThermalStorageSystem()
- _generic_storage_system.type_energy_stored = 'thermal'
+ _generic_storage_system.type_energy_stored = storage_system.type_energy_stored
+ _generic_storage_system.height = storage_system.height
+ _generic_storage_system.layers = storage_system.layers
+ _generic_storage_system.storage_medium = storage_system.storage_medium
_storage_systems.append(_generic_storage_system)
- _generation_system.energy_storage_systems = [_storage_systems]
- if archetype_generation_system.dual_supply_capability:
- _generation_system.dual_supply_capability = True
+ _generation_system.energy_storage_systems = _storage_systems
+ if archetype_generation_system.domestic_hot_water:
+ _generation_system.domestic_hot_water = True
+ if archetype_generation_system.reversibility:
+ _generation_system.reversibility = True
+ if archetype_generation_system.simultaneous_heat_cold:
+ _generation_system.simultaneous_heat_cold = True
_generation_systems.append(_generation_system)
return _generation_systems
diff --git a/main.py b/main.py
index e9c69db6..f89d37c9 100644
--- a/main.py
+++ b/main.py
@@ -12,6 +12,11 @@ from hub.exports.exports_factory import ExportsFactory
from scripts.energy_system_analysis_report import EnergySystemAnalysisReport
from scripts import random_assignation
from hub.imports.energy_systems_factory import EnergySystemsFactory
+from scripts.energy_system_sizing import SystemSizing
+from scripts.system_simulation import SystemSimulation
+from scripts.costs.cost import Cost
+from costs.constants import CURRENT_STATUS, SKIN_RETROFIT, SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV, SYSTEM_RETROFIT_AND_PV
+from scripts.energy_system_retrofit_results import system_results, new_system_results
# Specify the GeoJSON file path
geojson_file = process_geojson(x=-73.5681295982132, y=45.49218262677643, diff=0.0001)
@@ -33,8 +38,21 @@ ExportsFactory('sra', city, output_path).export()
sra_path = (output_path / f'{city.name}_sra.xml').resolve()
subprocess.run(['sra', str(sra_path)])
ResultFactory('sra', city, output_path).enrich()
-# Run EnergyPlus workflow
energy_plus_workflow(city)
random_assignation.call_random(city.buildings, random_assignation.residential_systems_percentage)
EnergySystemsFactory('montreal_custom', city).enrich()
-EnergySystemAnalysisReport(city, output_path).create_report()
+SystemSizing(city.buildings).montreal_custom()
+current_system = system_results(city.buildings)
+new_system = system_results(city.buildings)
+EnergySystemAnalysisReport(city, output_path).create_report(current_system, new_system)
+
+for building in city.buildings:
+ costs = Cost(building, retrofit_scenario=SYSTEM_RETROFIT_AND_PV).life_cycle
+ Cost(building, retrofit_scenario=SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV).life_cycle.to_csv(output_path / f'{building.name}_lcc.csv')
+ costs.loc['global_capital_costs', f'Scenario {SYSTEM_RETROFIT_AND_PV}'].to_csv(output_path / f'{building.name}_global_capital.csv')
+ costs.loc['global_operational_costs', f'Scenario {SYSTEM_RETROFIT_AND_PV}'].to_csv(
+ output_path / f'{building.name}_global_operational.csv')
+
+
+
+
diff --git a/scripts/costs/capital_costs.py b/scripts/costs/capital_costs.py
index 654218af..49f7efd0 100644
--- a/scripts/costs/capital_costs.py
+++ b/scripts/costs/capital_costs.py
@@ -11,15 +11,16 @@ import pandas as pd
import numpy_financial as npf
from hub.city_model_structure.building import Building
import hub.helpers.constants as cte
-from costs.configuration import Configuration
-from costs.constants import SKIN_RETROFIT, SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV, SYSTEM_RETROFIT_AND_PV
-from costs.cost_base import CostBase
+from scripts.costs.configuration import Configuration
+from scripts.costs.constants import SKIN_RETROFIT, SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV, SYSTEM_RETROFIT_AND_PV
+from scripts.costs.cost_base import CostBase
class CapitalCosts(CostBase):
"""
Capital costs class
"""
+
def __init__(self, building: Building, configuration: Configuration):
super().__init__(building, configuration)
self._yearly_capital_costs = pd.DataFrame(
@@ -28,25 +29,28 @@ class CapitalCosts(CostBase):
'B2010_opaque_walls',
'B2020_transparent',
'B3010_opaque_roof',
- 'B10_superstructure',
- 'D301010_photovoltaic_system',
- 'D3020_heat_generating_systems',
- 'D3030_cooling_generation_systems',
+ 'B1010_superstructure',
+ 'D2010_photovoltaic_system',
+ 'D3020_heat_and_cooling_generating_systems',
'D3040_distribution_systems',
- 'D3080_other_hvac_ahu',
+ 'D3050_other_hvac_ahu',
+ 'D3060_storage_systems',
+ 'D40_dhw',
'D5020_lighting_and_branch_wiring'
],
dtype='float'
)
self._yearly_capital_costs.loc[0, 'B2010_opaque_walls'] = 0
- self._yearly_capital_costs.loc[0]['B2020_transparent'] = 0
+ self._yearly_capital_costs.loc[0, 'B2020_transparent'] = 0
self._yearly_capital_costs.loc[0, 'B3010_opaque_roof'] = 0
- self._yearly_capital_costs.loc[0]['B10_superstructure'] = 0
- self._yearly_capital_costs.loc[0, 'D3020_heat_generating_systems'] = 0
- self._yearly_capital_costs.loc[0, 'D3030_cooling_generation_systems'] = 0
+ self._yearly_capital_costs.loc[0, 'B1010_superstructure'] = 0
+ self._yearly_capital_costs.loc[0, 'D2010_photovoltaic_system'] = 0
+ self._yearly_capital_costs.loc[0, 'D3020_heat_and_cooling_generating_systems'] = 0
self._yearly_capital_costs.loc[0, 'D3040_distribution_systems'] = 0
self._yearly_capital_costs.loc[0, 'D3080_other_hvac_ahu'] = 0
- self._yearly_capital_costs.loc[0, 'D5020_lighting_and_branch_wiring'] = 0
+ self._yearly_capital_costs.loc[0, 'D3060_storage_systems'] = 0
+ self._yearly_capital_costs.loc[0, 'D40_dhw'] = 0
+ # self._yearly_capital_costs.loc[0, 'D5020_lighting_and_branch_wiring'] = 0
self._yearly_capital_incomes = pd.DataFrame(
index=self._rng,
@@ -60,26 +64,32 @@ class CapitalCosts(CostBase):
self._yearly_capital_incomes.loc[0, 'Subsidies construction'] = 0
self._yearly_capital_incomes.loc[0, 'Subsidies HVAC'] = 0
self._yearly_capital_incomes.loc[0, 'Subsidies PV'] = 0
+ self._yearly_capital_costs.fillna(0, inplace=True)
+ self._own_capital = 1 - self._configuration.percentage_credit
+ self._surface_pv = 0
+ for roof in self._building.roofs:
+ self._surface_pv += roof.solid_polygon.area * roof.solar_collectors_area_reduction_factor
def calculate(self) -> tuple[pd.DataFrame, pd.DataFrame]:
+ if self._configuration.retrofit_scenario in (SKIN_RETROFIT, SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV):
+ self.skin_capital_cost()
+ if self._configuration.retrofit_scenario in (SYSTEM_RETROFIT_AND_PV, SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV):
+ self.energy_system_capital_cost()
+
+ self.skin_yearly_capital_costs()
+ self.yearly_energy_system_costs()
+ self.yearly_incomes()
+ return self._yearly_capital_costs, self._yearly_capital_incomes
+
+ def skin_capital_cost(self):
"""
- Calculate capital cost
- :return: pd.DataFrame, pd.DataFrame
+ calculating skin costs
+ :return:
"""
surface_opaque = 0
surface_transparent = 0
surface_roof = 0
surface_ground = 0
- capital_cost_pv = 0
- capital_cost_opaque = 0
- capital_cost_ground = 0
- capital_cost_transparent = 0
- capital_cost_roof = 0
- capital_cost_heating_equipment = 0
- capital_cost_cooling_equipment = 0
- capital_cost_distribution_equipment = 0
- capital_cost_other_hvac_ahu = 0
- capital_cost_lighting = 0
for thermal_zone in self._building.thermal_zones_from_internal_zones:
for thermal_boundary in thermal_zone.thermal_boundaries:
@@ -91,144 +101,222 @@ class CapitalCosts(CostBase):
surface_opaque += thermal_boundary.opaque_area * (1 - thermal_boundary.window_ratio)
surface_transparent += thermal_boundary.opaque_area * thermal_boundary.window_ratio
- peak_heating = self._building.heating_peak_load[cte.YEAR][0] / 1000
- peak_cooling = self._building.cooling_peak_load[cte.YEAR][0] / 1000
-
- surface_pv = 0
- for roof in self._building.roofs:
- surface_pv += roof.solid_polygon.area * roof.solar_collectors_area_reduction_factor
-
- self._yearly_capital_costs.fillna(0, inplace=True)
- own_capital = 1 - self._configuration.percentage_credit
- if self._configuration.retrofit_scenario in (SKIN_RETROFIT, SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV):
- chapter = self._capital_costs_chapter.chapter('B_shell')
- capital_cost_opaque = surface_opaque * chapter.item('B2010_opaque_walls').refurbishment[0]
- capital_cost_transparent = surface_transparent * chapter.item('B2020_transparent').refurbishment[0]
- capital_cost_roof = surface_roof * chapter.item('B3010_opaque_roof').refurbishment[0]
- capital_cost_ground = surface_ground * chapter.item('B10_superstructure').refurbishment[0]
- self._yearly_capital_costs.loc[0, 'B2010_opaque_walls'] = capital_cost_opaque * own_capital
- self._yearly_capital_costs.loc[0]['B2020_transparent'] = capital_cost_transparent * own_capital
- self._yearly_capital_costs.loc[0, 'B3010_opaque_roof'] = capital_cost_roof * own_capital
- self._yearly_capital_costs.loc[0]['B10_superstructure'] = capital_cost_ground * own_capital
-
- if self._configuration.retrofit_scenario in (SYSTEM_RETROFIT_AND_PV, SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV):
- chapter = self._capital_costs_chapter.chapter('D_services')
- capital_cost_pv = surface_pv * chapter.item('D301010_photovoltaic_system').initial_investment[0]
- capital_cost_heating_equipment = peak_heating * chapter.item('D3020_heat_generating_systems').initial_investment[0]
- capital_cost_cooling_equipment = peak_cooling * chapter.item('D3030_cooling_generation_systems').initial_investment[0]
- capital_cost_distribution_equipment = peak_cooling * chapter.item('D3040_distribution_systems').initial_investment[0]
- capital_cost_other_hvac_ahu = peak_cooling * chapter.item('D3080_other_hvac_ahu').initial_investment[0]
- capital_cost_lighting = self._total_floor_area * chapter.item('D5020_lighting_and_branch_wiring').initial_investment[0]
- self._yearly_capital_costs.loc[0]['D301010_photovoltaic_system'] = capital_cost_pv
- self._yearly_capital_costs.loc[0, 'D3020_heat_generating_systems'] = capital_cost_heating_equipment * own_capital
- self._yearly_capital_costs.loc[0, 'D3030_cooling_generation_systems'] = capital_cost_cooling_equipment * own_capital
- self._yearly_capital_costs.loc[0, 'D3040_distribution_systems'] = capital_cost_distribution_equipment * own_capital
- self._yearly_capital_costs.loc[0, 'D3080_other_hvac_ahu'] = capital_cost_other_hvac_ahu * own_capital
- self._yearly_capital_costs.loc[0, 'D5020_lighting_and_branch_wiring'] = capital_cost_lighting * own_capital
+ chapter = self._capital_costs_chapter.chapter('B_shell')
+ capital_cost_opaque = surface_opaque * chapter.item('B2010_opaque_walls').refurbishment[0]
+ capital_cost_transparent = surface_transparent * chapter.item('B2020_transparent').refurbishment[0]
+ capital_cost_roof = surface_roof * chapter.item('B3010_opaque_roof').refurbishment[0]
+ capital_cost_ground = surface_ground * chapter.item('B1010_superstructure').refurbishment[0]
+ self._yearly_capital_costs.loc[0, 'B2010_opaque_walls'] = capital_cost_opaque * self._own_capital
+ self._yearly_capital_costs.loc[0, 'B2020_transparent'] = capital_cost_transparent * self._own_capital
+ self._yearly_capital_costs.loc[0, 'B3010_opaque_roof'] = capital_cost_roof * self._own_capital
+ self._yearly_capital_costs.loc[0, 'B1010_superstructure'] = capital_cost_ground * self._own_capital
+ capital_cost_skin = capital_cost_opaque + capital_cost_ground + capital_cost_transparent + capital_cost_roof
+ return capital_cost_opaque, capital_cost_transparent, capital_cost_roof, capital_cost_ground, capital_cost_skin
+ def skin_yearly_capital_costs(self):
+ skin_capital_cost = self.skin_capital_cost()
for year in range(1, self._configuration.number_of_years):
- chapter = self._capital_costs_chapter.chapter('D_services')
- costs_increase = math.pow(1 + self._configuration.consumer_price_index, year)
self._yearly_capital_costs.loc[year, 'B2010_opaque_walls'] = (
-npf.pmt(
self._configuration.interest_rate,
self._configuration.credit_years,
- capital_cost_opaque * self._configuration.percentage_credit
+ skin_capital_cost[0] * self._configuration.percentage_credit
)
)
self._yearly_capital_costs.loc[year, 'B2020_transparent'] = (
-npf.pmt(
self._configuration.interest_rate,
self._configuration.credit_years,
- capital_cost_transparent * self._configuration.percentage_credit
+ skin_capital_cost[1] * self._configuration.percentage_credit
)
)
self._yearly_capital_costs.loc[year, 'B3010_opaque_roof'] = (
-npf.pmt(
self._configuration.interest_rate,
self._configuration.credit_years,
- capital_cost_roof * self._configuration.percentage_credit
+ skin_capital_cost[2] * self._configuration.percentage_credit
)
)
- self._yearly_capital_costs.loc[year, 'B10_superstructure'] = (
+ self._yearly_capital_costs.loc[year, 'B1010_superstructure'] = (
-npf.pmt(
self._configuration.interest_rate,
self._configuration.credit_years,
- capital_cost_ground * self._configuration.percentage_credit
+ skin_capital_cost[3] * self._configuration.percentage_credit
)
)
- self._yearly_capital_costs.loc[year, 'D3020_heat_generating_systems'] = (
+
+ def energy_system_capital_cost(self):
+ chapter = self._capital_costs_chapter.chapter('D_services')
+ energy_system_components = self.system_components()
+ system_components = energy_system_components[0]
+ component_categories = energy_system_components[1]
+ component_sizes = energy_system_components[-1]
+ capital_cost_heating_and_cooling_equipment = 0
+ capital_cost_domestic_hot_water_equipment = 0
+ capital_cost_energy_storage_equipment = 0
+ capital_cost_distribution_equipment = 0
+ capital_cost_lighting = 0
+ capital_cost_pv = self._surface_pv * chapter.item('D2010_photovoltaic_system').initial_investment[0]
+ # capital_cost_lighting = self._total_floor_area * \
+ # chapter.item('D5020_lighting_and_branch_wiring').initial_investment[0]
+ for (i, component) in enumerate(system_components):
+ if component_categories[i] == 'generation':
+ capital_cost_heating_and_cooling_equipment += chapter.item(component).initial_investment[0] * component_sizes[i]
+ elif component_categories[i] == 'dhw':
+ capital_cost_domestic_hot_water_equipment += chapter.item(component).initial_investment[0] * \
+ component_sizes[i]
+ elif component_categories[i] == 'distribution':
+ capital_cost_distribution_equipment += chapter.item(component).initial_investment[0] * \
+ component_sizes[i]
+ else:
+ capital_cost_energy_storage_equipment += chapter.item(component).initial_investment[0] * component_sizes[i]
+
+ self._yearly_capital_costs.loc[0, 'D2010_photovoltaic_system'] = capital_cost_pv
+ self._yearly_capital_costs.loc[0, 'D3020_heat_and_cooling_generating_systems'] = (
+ capital_cost_heating_and_cooling_equipment * self._own_capital)
+ self._yearly_capital_costs.loc[0, 'D3040_distribution_systems'] = (
+ capital_cost_distribution_equipment * self._own_capital)
+ self._yearly_capital_costs.loc[0, 'D3060_storage_systems'] = (
+ capital_cost_energy_storage_equipment * self._own_capital)
+ self._yearly_capital_costs.loc[0, 'D40_dhw'] = (
+ capital_cost_domestic_hot_water_equipment * self._own_capital)
+ # self._yearly_capital_costs.loc[0, 'D5020_lighting_and_branch_wiring'] = capital_cost_lighting * self._own_capital
+ capital_cost_hvac = capital_cost_heating_and_cooling_equipment + capital_cost_distribution_equipment + capital_cost_energy_storage_equipment + capital_cost_domestic_hot_water_equipment
+ return (capital_cost_pv, capital_cost_heating_and_cooling_equipment, capital_cost_distribution_equipment,
+ capital_cost_energy_storage_equipment, capital_cost_domestic_hot_water_equipment, capital_cost_lighting, capital_cost_hvac)
+
+ def yearly_energy_system_costs(self):
+ chapter = self._capital_costs_chapter.chapter('D_services')
+ system_investment_costs = self.energy_system_capital_cost()
+ system_components = self.system_components()[0]
+ component_categories = self.system_components()[1]
+ component_sizes = self.system_components()[2]
+ for year in range(1, self._configuration.number_of_years):
+ costs_increase = math.pow(1 + self._configuration.consumer_price_index, year)
+ self._yearly_capital_costs.loc[year, 'D2010_photovoltaic_system'] = (
-npf.pmt(
self._configuration.interest_rate,
self._configuration.credit_years,
- capital_cost_heating_equipment * self._configuration.percentage_credit
+ system_investment_costs[0] * self._configuration.percentage_credit
)
)
- self._yearly_capital_costs.loc[year, 'D3030_cooling_generation_systems'] = (
+ self._yearly_capital_costs.loc[year, 'D3020_heat_and_cooling_generating_systems'] = (
-npf.pmt(
self._configuration.interest_rate,
self._configuration.credit_years,
- capital_cost_cooling_equipment * self._configuration.percentage_credit
+ system_investment_costs[1] * self._configuration.percentage_credit
)
)
self._yearly_capital_costs.loc[year, 'D3040_distribution_systems'] = (
-npf.pmt(
self._configuration.interest_rate,
self._configuration.credit_years,
- capital_cost_distribution_equipment * self._configuration.percentage_credit
+ system_investment_costs[2] * self._configuration.percentage_credit
)
)
- self._yearly_capital_costs.loc[year, 'D3080_other_hvac_ahu'] = (
+ self._yearly_capital_costs.loc[year, 'D3060_storage_systems'] = (
-npf.pmt(
self._configuration.interest_rate,
self._configuration.credit_years,
- capital_cost_other_hvac_ahu * self._configuration.percentage_credit
+ system_investment_costs[3] * self._configuration.percentage_credit
)
)
- self._yearly_capital_costs.loc[year, 'D5020_lighting_and_branch_wiring'] = (
+ self._yearly_capital_costs.loc[year, 'D40_dhw'] = (
-npf.pmt(
self._configuration.interest_rate,
self._configuration.credit_years,
- capital_cost_lighting * self._configuration.percentage_credit
+ system_investment_costs[4] * self._configuration.percentage_credit
)
)
-
- if (year % chapter.item('D3020_heat_generating_systems').lifetime) == 0:
- reposition_cost_heating_equipment = (
- peak_heating * chapter.item('D3020_heat_generating_systems').reposition[0] * costs_increase
- )
- self._yearly_capital_costs.loc[year, 'D3020_heat_generating_systems'] += reposition_cost_heating_equipment
-
- if (year % chapter.item('D3030_cooling_generation_systems').lifetime) == 0:
- reposition_cost_cooling_equipment = (
- peak_cooling * chapter.item('D3030_cooling_generation_systems').reposition[0] * costs_increase
- )
- self._yearly_capital_costs.loc[year, 'D3030_cooling_generation_systems'] += reposition_cost_cooling_equipment
-
- if (year % chapter.item('D3080_other_hvac_ahu').lifetime) == 0:
- reposition_cost_hvac_ahu = (
- peak_cooling * chapter.item('D3080_other_hvac_ahu').reposition[0] * costs_increase
- )
- self._yearly_capital_costs.loc[year, 'D3080_other_hvac_ahu'] = reposition_cost_hvac_ahu
-
- if (year % chapter.item('D5020_lighting_and_branch_wiring').lifetime) == 0:
- reposition_cost_lighting = (
- self._total_floor_area * chapter.item('D5020_lighting_and_branch_wiring').reposition[0] * costs_increase
- )
- self._yearly_capital_costs.loc[year, 'D5020_lighting_and_branch_wiring'] += reposition_cost_lighting
-
+ # self._yearly_capital_costs.loc[year, 'D5020_lighting_and_branch_wiring'] = (
+ # -npf.pmt(
+ # self._configuration.interest_rate,
+ # self._configuration.credit_years,
+ # system_investment_costs[5] * self._configuration.percentage_credit
+ # )
+ # )
+ # if (year % chapter.item('D5020_lighting_and_branch_wiring').lifetime) == 0:
+ # reposition_cost_lighting = (
+ # self._total_floor_area * chapter.item('D5020_lighting_and_branch_wiring').reposition[0] * costs_increase
+ # )
+ # self._yearly_capital_costs.loc[year, 'D5020_lighting_and_branch_wiring'] += reposition_cost_lighting
if self._configuration.retrofit_scenario in (SYSTEM_RETROFIT_AND_PV, SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV):
- if (year % chapter.item('D301010_photovoltaic_system').lifetime) == 0:
- self._yearly_capital_costs.loc[year]['D301010_photovoltaic_system'] += (
- surface_pv * chapter.item('D301010_photovoltaic_system').reposition[0] * costs_increase
+ if (year % chapter.item('D2010_photovoltaic_system').lifetime) == 0:
+ self._yearly_capital_costs.loc[year, 'D2010_photovoltaic_system'] += (
+ self._surface_pv * chapter.item('D2010_photovoltaic_system').reposition[0] * costs_increase
)
- capital_cost_skin = capital_cost_opaque + capital_cost_ground + capital_cost_transparent + capital_cost_roof
- capital_cost_hvac = (
- capital_cost_heating_equipment +
- capital_cost_cooling_equipment +
- capital_cost_distribution_equipment +
- capital_cost_other_hvac_ahu + capital_cost_lighting
- )
+ for (i, component) in enumerate(system_components):
+ if (year % chapter.item(component).lifetime) == 0 and year != (self._configuration.number_of_years - 1):
+ if component_categories[i] == 'generation':
+ reposition_cost_heating_and_cooling_equipment = chapter.item(component).reposition[0] * component_sizes[i] * costs_increase
+ self._yearly_capital_costs.loc[year, 'D3020_heat_and_cooling_generating_systems'] += reposition_cost_heating_and_cooling_equipment
+ elif component_categories[i] == 'dhw':
+ reposition_cost_domestic_hot_water_equipment = chapter.item(component).reposition[0] * component_sizes[i] * costs_increase
+ self._yearly_capital_costs.loc[year, 'D40_dhw'] += reposition_cost_domestic_hot_water_equipment
+ elif component_categories[i] == 'distribution':
+ reposition_cost_distribution_equipment = chapter.item(component).reposition[0] * component_sizes[i] * costs_increase
+ self._yearly_capital_costs.loc[year, 'D3040_distribution_systems'] += reposition_cost_distribution_equipment
+ else:
+ reposition_cost_energy_storage_equipment = chapter.item(component).initial_investment[0] * component_sizes[i] * costs_increase
+ self._yearly_capital_costs.loc[year, 'D3060_storage_systems'] += reposition_cost_energy_storage_equipment
+
+ def system_components(self):
+ system_components = []
+ component_categories = []
+ sizes = []
+ energy_systems = self._building.energy_systems
+ for energy_system in energy_systems:
+ demand_types = energy_system.demand_types
+ generation_systems = energy_system.generation_systems
+ distribution_systems = energy_system.distribution_systems
+ for generation_system in generation_systems:
+ if generation_system.system_type != cte.PHOTOVOLTAIC:
+ heating_capacity = generation_system.nominal_heat_output or 0
+ cooling_capacity = generation_system.nominal_cooling_output or 0
+ installed_capacity = max(heating_capacity, cooling_capacity)
+ if cte.DOMESTIC_HOT_WATER in demand_types and cte.HEATING not in demand_types:
+ component_categories.append('dhw')
+ sizes.append(installed_capacity)
+ if generation_system.system_type == cte.HEAT_PUMP:
+ system_components.append(self.heat_pump_type(generation_system, domestic_how_water=True))
+ elif generation_system.system_type == cte.BOILER and generation_system.fuel_type == cte.ELECTRICITY:
+ system_components.append(self.boiler_type(generation_system))
+ else:
+ system_components.append('D302010_template_heat')
+ elif cte.HEATING or cte.COOLING in demand_types:
+ component_categories.append('generation')
+ sizes.append(installed_capacity)
+ if generation_system.system_type == cte.HEAT_PUMP:
+ item_type = self.heat_pump_type(generation_system)
+ system_components.append(item_type)
+ elif generation_system.system_type == cte.BOILER:
+ item_type = self.boiler_type(generation_system)
+ system_components.append(item_type)
+ else:
+ if cte.COOLING in demand_types and cte.HEATING not in demand_types:
+ system_components.append('D302090_template_cooling')
+ else:
+ system_components.append('D302010_template_heat')
+
+ if generation_system.energy_storage_systems is not None:
+ energy_storage_systems = generation_system.energy_storage_systems
+ for storage_system in energy_storage_systems:
+ if storage_system.type_energy_stored == 'thermal':
+ component_categories.append('thermal storage')
+ sizes.append(storage_system.volume or 0)
+ system_components.append('D306010_storage_tank')
+ if distribution_systems is not None:
+ for distribution_system in distribution_systems:
+ component_categories.append('distribution')
+ sizes.append(self._building.cooling_peak_load[cte.YEAR][0] / 3.6e6)
+ system_components.append('D3040_distribution_systems')
+ return system_components, component_categories, sizes
+
+ def yearly_incomes(self):
+ capital_cost_skin = self.skin_capital_cost()[-1]
+ system_investment_cost = self.energy_system_capital_cost()
+ capital_cost_hvac = system_investment_cost[-1]
+ capital_cost_pv = system_investment_cost[0]
self._yearly_capital_incomes.loc[0, 'Subsidies construction'] = (
capital_cost_skin * self._archetype.income.construction_subsidy/100
@@ -236,4 +324,41 @@ class CapitalCosts(CostBase):
self._yearly_capital_incomes.loc[0, 'Subsidies HVAC'] = capital_cost_hvac * self._archetype.income.hvac_subsidy/100
self._yearly_capital_incomes.loc[0, 'Subsidies PV'] = capital_cost_pv * self._archetype.income.photovoltaic_subsidy/100
self._yearly_capital_incomes.fillna(0, inplace=True)
- return self._yearly_capital_costs, self._yearly_capital_incomes
+
+ @staticmethod
+ def heat_pump_type(generation_system, domestic_how_water=False):
+ source_medium = generation_system.source_medium
+ supply_medium = generation_system.supply_medium
+ if domestic_how_water:
+ heat_pump_item = 'D4010_hot_water_heat_pump'
+ else:
+ if source_medium == cte.AIR and supply_medium == cte.WATER:
+ heat_pump_item = 'D302020_air_to_water_heat_pump'
+ elif source_medium == cte.AIR and supply_medium == cte.AIR:
+ heat_pump_item = 'D302050_air_to_air_heat_pump'
+ elif source_medium == cte.GROUND and supply_medium == cte.WATER:
+ heat_pump_item = 'D302030_ground_to_water_heat_pump'
+ elif source_medium == cte.GROUND and supply_medium == cte.AIR:
+ heat_pump_item = 'D302100_ground_to_air_heat_pump'
+ elif source_medium == cte.WATER and supply_medium == cte.WATER:
+ heat_pump_item = 'D302040_water_to_water_heat_pump'
+ elif source_medium == cte.WATER and supply_medium == cte.AIR:
+ heat_pump_item = 'D302110_water_to_air_heat_pump'
+ else:
+ heat_pump_item = 'D302010_template_heat'
+ return heat_pump_item
+
+ @staticmethod
+ def boiler_type(generation_system):
+ fuel = generation_system.fuel_type
+ if fuel == cte.ELECTRICITY:
+ boiler_item = 'D302080_electrical_boiler'
+ elif fuel == cte.GAS:
+ boiler_item = 'D302070_natural_gas_boiler'
+ else:
+ boiler_item = 'D302010_template_heat'
+ return boiler_item
+
+
+
+
diff --git a/scripts/costs/cost.py b/scripts/costs/cost.py
index 7204b508..b040f063 100644
--- a/scripts/costs/cost.py
+++ b/scripts/costs/cost.py
@@ -11,10 +11,14 @@ import pandas as pd
import numpy_financial as npf
from hub.city_model_structure.building import Building
from hub.helpers.dictionaries import Dictionaries
-
-from costs.configuration import Configuration
-from costs import CapitalCosts, EndOfLifeCosts, TotalMaintenanceCosts, TotalOperationalCosts, TotalOperationalIncomes
-from costs.constants import CURRENT_STATUS
+from scripts.costs.configuration import Configuration
+from scripts.costs.capital_costs import CapitalCosts
+from scripts.costs.end_of_life_costs import EndOfLifeCosts
+from scripts.costs.total_maintenance_costs import TotalMaintenanceCosts
+from scripts.costs.total_operational_costs import TotalOperationalCosts
+from scripts.costs.total_operational_incomes import TotalOperationalIncomes
+from scripts.costs.constants import CURRENT_STATUS, SKIN_RETROFIT, SYSTEM_RETROFIT_AND_PV, SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV
+import hub.helpers.constants as cte
class Cost:
@@ -31,25 +35,23 @@ class Cost:
consumer_price_index=0.04,
electricity_peak_index=0.05,
electricity_price_index=0.05,
- gas_price_index=0.05,
+ fuel_price_index=0.05,
discount_rate=0.03,
retrofitting_year_construction=2020,
- factories_handler='montreal_custom',
+ factories_handler='montreal_new',
retrofit_scenario=CURRENT_STATUS,
dictionary=None):
if dictionary is None:
dictionary = Dictionaries().hub_function_to_montreal_custom_costs_function
self._building = building
- fuel_type = 0
- if "gas" in building.energy_systems_archetype_name:
- fuel_type = 1
+ fuel_type = self._building.fuel_consumption_breakdown.keys()
self._configuration = Configuration(number_of_years,
percentage_credit,
interest_rate, credit_years,
consumer_price_index,
electricity_peak_index,
electricity_price_index,
- gas_price_index,
+ fuel_price_index,
discount_rate,
retrofitting_year_construction,
factories_handler,
@@ -79,28 +81,37 @@ class Cost:
global_operational_costs = TotalOperationalCosts(self._building, self._configuration).calculate()
global_maintenance_costs = TotalMaintenanceCosts(self._building, self._configuration).calculate()
global_operational_incomes = TotalOperationalIncomes(self._building, self._configuration).calculate()
+
df_capital_costs_skin = (
global_capital_costs['B2010_opaque_walls'] +
global_capital_costs['B2020_transparent'] +
global_capital_costs['B3010_opaque_roof'] +
- global_capital_costs['B10_superstructure']
+ global_capital_costs['B1010_superstructure']
)
df_capital_costs_systems = (
- global_capital_costs['D3020_heat_generating_systems'] +
- global_capital_costs['D3030_cooling_generation_systems'] +
- global_capital_costs['D3080_other_hvac_ahu'] +
+ global_capital_costs['D3020_heat_and_cooling_generating_systems'] +
+ global_capital_costs['D3040_distribution_systems'] +
+ global_capital_costs['D3050_other_hvac_ahu'] +
+ global_capital_costs['D3060_storage_systems'] +
+ global_capital_costs['D40_dhw'] +
global_capital_costs['D5020_lighting_and_branch_wiring'] +
- global_capital_costs['D301010_photovoltaic_system']
+ global_capital_costs['D2010_photovoltaic_system']
)
df_end_of_life_costs = global_end_of_life_costs['End_of_life_costs']
- df_operational_costs = (
- global_operational_costs['Fixed_costs_electricity_peak'] +
- global_operational_costs['Fixed_costs_electricity_monthly'] +
- global_operational_costs['Variable_costs_electricity'] +
- global_operational_costs['Fixed_costs_gas'] +
- global_operational_costs['Variable_costs_gas']
- )
+ operational_costs_list = [
+ global_operational_costs['Fixed Costs Electricity Peak'],
+ global_operational_costs['Fixed Costs Electricity Monthly'],
+ global_operational_costs['Variable Costs Electricity']
+ ]
+ additional_costs = [
+ global_operational_costs[f'Fixed Costs {fuel}'] for fuel in
+ self._building.fuel_consumption_breakdown.keys() if fuel != cte.ELECTRICITY
+ ] + [
+ global_operational_costs[f'Variable Costs {fuel}'] for fuel in
+ self._building.fuel_consumption_breakdown.keys() if fuel != cte.ELECTRICITY
+ ]
+ df_operational_costs = sum(operational_costs_list + additional_costs)
df_maintenance_costs = (
global_maintenance_costs['Heating_maintenance'] +
global_maintenance_costs['Cooling_maintenance'] +
@@ -116,7 +127,7 @@ class Cost:
life_cycle_costs_capital_skin = self._npv_from_list(df_capital_costs_skin.values.tolist())
life_cycle_costs_capital_systems = self._npv_from_list(df_capital_costs_systems.values.tolist())
life_cycle_costs_end_of_life_costs = self._npv_from_list(df_end_of_life_costs.values.tolist())
- life_cycle_operational_costs = self._npv_from_list(df_operational_costs.values.tolist())
+ life_cycle_operational_costs = self._npv_from_list([df_operational_costs])
life_cycle_maintenance_costs = self._npv_from_list(df_maintenance_costs.values.tolist())
life_cycle_operational_incomes = self._npv_from_list(df_operational_incomes.values.tolist())
life_cycle_capital_incomes = self._npv_from_list(df_capital_incomes.values.tolist())
diff --git a/scripts/costs/end_of_life_costs.py b/scripts/costs/end_of_life_costs.py
index f7d0d63f..8dacfecc 100644
--- a/scripts/costs/end_of_life_costs.py
+++ b/scripts/costs/end_of_life_costs.py
@@ -9,8 +9,8 @@ import math
import pandas as pd
from hub.city_model_structure.building import Building
-from costs.configuration import Configuration
-from costs.cost_base import CostBase
+from scripts.costs.configuration import Configuration
+from scripts.costs.cost_base import CostBase
class EndOfLifeCosts(CostBase):
diff --git a/scripts/costs/total_maintenance_costs.py b/scripts/costs/total_maintenance_costs.py
index 081df443..13cdc3a0 100644
--- a/scripts/costs/total_maintenance_costs.py
+++ b/scripts/costs/total_maintenance_costs.py
@@ -43,8 +43,8 @@ class TotalMaintenanceCosts(CostBase):
roof_area += roof.solid_polygon.area
surface_pv = roof_area * 0.5
- peak_heating = building.heating_peak_load[cte.YEAR][0]
- peak_cooling = building.cooling_peak_load[cte.YEAR][0]
+ peak_heating = building.heating_peak_load[cte.YEAR][0] / 3.6e6
+ peak_cooling = building.cooling_peak_load[cte.YEAR][0] / 3.6e6
maintenance_heating_0 = peak_heating * archetype.operational_cost.maintenance_heating
maintenance_cooling_0 = peak_cooling * archetype.operational_cost.maintenance_cooling
diff --git a/scripts/costs/total_operational_costs.py b/scripts/costs/total_operational_costs.py
index e38ac5f5..338baab1 100644
--- a/scripts/costs/total_operational_costs.py
+++ b/scripts/costs/total_operational_costs.py
@@ -1,8 +1,7 @@
"""
Total operational costs module
SPDX - License - Identifier: LGPL - 3.0 - or -later
-Copyright © 2023 Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
-Code contributor Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+Copyright © 2024 Project Coder Saeed Ranjbar saeed.ranjbar@mail.concordia.ca
Code contributor Oriol Gavalda Torrellas oriol.gavalda@concordia.ca
"""
import math
@@ -11,27 +10,22 @@ import pandas as pd
from hub.city_model_structure.building import Building
import hub.helpers.constants as cte
-from costs.configuration import Configuration
-from costs.cost_base import CostBase
-from costs.peak_load import PeakLoad
+from scripts.costs.configuration import Configuration
+from scripts.costs.cost_base import CostBase
+from scripts.costs.peak_load import PeakLoad
class TotalOperationalCosts(CostBase):
"""
- End of life costs class
+ Total Operational costs class
"""
def __init__(self, building: Building, configuration: Configuration):
super().__init__(building, configuration)
+ columns_list = self.columns()
self._yearly_operational_costs = pd.DataFrame(
index=self._rng,
- columns=[
- 'Fixed_costs_electricity_peak',
- 'Fixed_costs_electricity_monthly',
- 'Variable_costs_electricity',
- 'Fixed_costs_gas',
- 'Variable_costs_gas'
- ],
+ columns=columns_list,
dtype='float'
)
@@ -41,67 +35,70 @@ class TotalOperationalCosts(CostBase):
:return: pd.DataFrame
"""
building = self._building
+ fuel_consumption_breakdown = building.fuel_consumption_breakdown
archetype = self._archetype
total_floor_area = self._total_floor_area
- factor_residential = total_floor_area / 80
- # todo: split the heating between fuels
- fixed_gas_cost_year_0 = 0
- variable_gas_cost_year_0 = 0
- electricity_heating = 0
- domestic_hot_water_electricity = 0
- # todo: each fuel has different units that have to be processed
- if self._configuration.fuel_type == 1:
- fixed_gas_cost_year_0 = archetype.operational_cost.fuels[1].fixed_monthly * 12 * factor_residential
- variable_gas_cost_year_0 = (
- (building.heating_consumption[cte.YEAR][0] + building.domestic_hot_water_consumption[cte.YEAR][0])
- / (1000 * cte.WATTS_HOUR_TO_JULES) * archetype.operational_cost.fuels[1].variable[0]
- )
- if self._configuration.fuel_type == 0:
- electricity_heating = building.heating_consumption[cte.YEAR][0] / 1000
- domestic_hot_water_electricity = building.domestic_hot_water_consumption[cte.YEAR][0] / 1000
-
- electricity_cooling = building.cooling_consumption[cte.YEAR][0] / 1000
- electricity_lighting = building.lighting_electrical_demand[cte.YEAR][0] / 1000
- electricity_plug_loads = building.appliances_electrical_demand[cte.YEAR][0] / 1000
- electricity_distribution = 0
- total_electricity_consumption = (
- electricity_heating + electricity_cooling + electricity_lighting + domestic_hot_water_electricity +
- electricity_plug_loads + electricity_distribution
- )
-
- # todo: change when peak electricity demand is coded. Careful with factor residential
- peak_electricity_load = PeakLoad(building).electricity_peak_load
+ if archetype.function == 'residential':
+ factor = total_floor_area / 80
+ else:
+ factor = 1
+ total_electricity_consumption = sum(self._building.fuel_consumption_breakdown[cte.ELECTRICITY].values())
+ peak_electricity_load = PeakLoad(self._building).electricity_peak_load
peak_load_value = peak_electricity_load.max(axis=1)
peak_electricity_demand = peak_load_value[1] / 1000 # self._peak_electricity_demand adapted to kW
- variable_electricity_cost_year_0 = (
- total_electricity_consumption / cte.WATTS_HOUR_TO_JULES * archetype.operational_cost.fuels[0].variable[0]
- )
- peak_electricity_cost_year_0 = peak_electricity_demand * archetype.operational_cost.fuels[0].fixed_power * 12
- monthly_electricity_cost_year_0 = archetype.operational_cost.fuels[0].fixed_monthly * 12 * factor_residential
-
- for year in range(1, self._configuration.number_of_years + 1):
- price_increase_electricity = math.pow(1 + self._configuration.electricity_price_index, year)
- price_increase_peak_electricity = math.pow(1 + self._configuration.electricity_peak_index, year)
- price_increase_gas = math.pow(1 + self._configuration.gas_price_index, year)
- self._yearly_operational_costs.at[year, 'Fixed_costs_electricity_peak'] = (
- peak_electricity_cost_year_0 * price_increase_peak_electricity
- )
- self._yearly_operational_costs.at[year, 'Fixed_costs_electricity_monthly'] = (
- monthly_electricity_cost_year_0 * price_increase_peak_electricity
- )
- if not isinstance(variable_electricity_cost_year_0, pd.DataFrame):
- variable_costs_electricity = variable_electricity_cost_year_0 * price_increase_electricity
- else:
- variable_costs_electricity = float(variable_electricity_cost_year_0.iloc[0] * price_increase_electricity)
- self._yearly_operational_costs.at[year, 'Variable_costs_electricity'] = (
- variable_costs_electricity
- )
- self._yearly_operational_costs.at[year, 'Fixed_costs_gas'] = fixed_gas_cost_year_0 * price_increase_gas
- self._yearly_operational_costs.at[year, 'Variable_costs_gas'] = (
- variable_gas_cost_year_0 * price_increase_peak_electricity
- )
- self._yearly_operational_costs.at[year, 'Variable_costs_gas'] = (
- variable_gas_cost_year_0 * price_increase_peak_electricity
- )
+ fuels = archetype.operational_cost.fuels
+ for fuel in fuels:
+ if fuel.type in fuel_consumption_breakdown.keys():
+ if fuel.type == cte.ELECTRICITY:
+ variable_electricity_cost_year_0 = (
+ total_electricity_consumption / cte.WATTS_HOUR_TO_JULES * fuel.variable[0]
+ )
+ peak_electricity_cost_year_0 = peak_electricity_demand * fuel.fixed_power * 12
+ monthly_electricity_cost_year_0 = fuel.fixed_monthly * 12 * factor
+ for year in range(1, self._configuration.number_of_years + 1):
+ price_increase_electricity = math.pow(1 + self._configuration.electricity_price_index, year)
+ price_increase_peak_electricity = math.pow(1 + self._configuration.electricity_peak_index, year)
+ self._yearly_operational_costs.at[year, 'Fixed Costs Electricity Peak'] = (
+ peak_electricity_cost_year_0 * price_increase_peak_electricity
+ )
+ self._yearly_operational_costs.at[year, 'Fixed Costs Electricity Monthly'] = (
+ monthly_electricity_cost_year_0 * price_increase_peak_electricity
+ )
+ if not isinstance(variable_electricity_cost_year_0, pd.DataFrame):
+ variable_costs_electricity = variable_electricity_cost_year_0 * price_increase_electricity
+ else:
+ variable_costs_electricity = float(variable_electricity_cost_year_0.iloc[0] * price_increase_electricity)
+ self._yearly_operational_costs.at[year, 'Variable Costs Electricity'] = (
+ variable_costs_electricity
+ )
+ else:
+ fuel_fixed_cost = fuel.fixed_monthly * 12 * factor
+ if fuel.type == cte.BIOMASS:
+ conversion_factor = 1
+ else:
+ conversion_factor = fuel.density[0]
+ variable_cost_fuel = (
+ (sum(fuel_consumption_breakdown[fuel.type].values())/(1e6*fuel.lower_heating_value[0] * conversion_factor)) * fuel.variable[0])
+ for year in range(1, self._configuration.number_of_years + 1):
+ price_increase_gas = math.pow(1 + self._configuration.gas_price_index, year)
+ self._yearly_operational_costs.at[year, f'Fixed Costs {fuel.type}'] = fuel_fixed_cost * price_increase_gas
+ self._yearly_operational_costs.at[year, f'Variable Costs {fuel.type}'] = (
+ variable_cost_fuel * price_increase_gas)
self._yearly_operational_costs.fillna(0, inplace=True)
+
return self._yearly_operational_costs
+
+ def columns(self):
+ columns_list = []
+ fuels = [key for key in self._building.fuel_consumption_breakdown.keys()]
+ for fuel in fuels:
+ if fuel == cte.ELECTRICITY:
+ columns_list.append('Fixed Costs Electricity Peak')
+ columns_list.append('Fixed Costs Electricity Monthly')
+ columns_list.append('Variable Costs Electricity')
+ else:
+ columns_list.append(f'Fixed Costs {fuel}')
+ columns_list.append(f'Variable Costs {fuel}')
+
+ return columns_list
+
diff --git a/scripts/energy_system_analysis_report.py b/scripts/energy_system_analysis_report.py
index 09b88482..9f44a288 100644
--- a/scripts/energy_system_analysis_report.py
+++ b/scripts/energy_system_analysis_report.py
@@ -6,7 +6,6 @@ import matplotlib.colors as mcolors
from matplotlib import cm
from scripts.report_creation import LatexReport
-
class EnergySystemAnalysisReport:
def __init__(self, city, output_path):
self.city = city
@@ -196,50 +195,48 @@ class EnergySystemAnalysisReport:
self.report.add_table(table_data, caption=f'{building.name} Information', first_column_width=1.5)
- def building_existing_system_info(self, building):
- existing_archetype = building.energy_systems_archetype_name
- fuels = []
- system_schematic = "-"
- heating_system = "-"
- cooling_system = "-"
- dhw = "-"
- electricity = "Grid"
- hvac_ec = format((building.heating_consumption[cte.YEAR][0] + building.cooling_consumption[cte.YEAR][0]) / 3.6e9,
- '.2f')
- dhw_ec = format(building.domestic_hot_water_consumption[cte.YEAR][0] / 1e6, '.2f')
- on_site_generation = "-"
- yearly_operational_cost = "-"
- life_cycle_cost = "-"
- for energy_system in building.energy_systems:
- if cte.HEATING and cte.DOMESTIC_HOT_WATER in energy_system.demand_types:
- heating_system = energy_system.name
- dhw = energy_system.name
- elif cte.DOMESTIC_HOT_WATER in energy_system.demand_types:
- dhw = energy_system.name
- elif cte.HEATING in energy_system.demand_types:
- heating_system = energy_system.name
- elif cte.COOLING in energy_system.demand_types:
- cooling_system = energy_system.name
- for generation_system in energy_system.generation_systems:
- fuels.append(generation_system.fuel_type)
- if generation_system.system_type == cte.PHOTOVOLTAIC:
- electricity = "Grid-tied PV"
+ def building_system_retrofit_results(self, building_name, current_system, new_system):
+ current_system_archetype = current_system[f'{building_name}']['Energy System Archetype']
+ current_system_heating = current_system[f'{building_name}']['Heating System']
+ current_system_cooling = current_system[f'{building_name}']['Cooling System']
+ current_system_dhw = current_system[f'{building_name}']['DHW System']
+ current_system_pv = current_system[f'{building_name}']['Photovoltaic System Capacity']
+ current_system_heating_fuel = current_system[f'{building_name}']['Heating Fuel']
+ current_system_hvac_consumption = current_system[f'{building_name}']['Yearly HVAC Energy Consumption (MWh)']
+ current_system_dhw_consumption = current_system[f'{building_name}']['DHW Energy Consumption (MWH)']
+ current_pv_production = current_system[f'{building_name}']['PV Yearly Production (kWh)']
+ current_capital_cost = current_system[f'{building_name}']['Energy System Capital Cost (CAD)']
+ current_operational = current_system[f'{building_name}']['Energy System Average Yearly Operational Cost (CAD)']
+ current_lcc = current_system[f'{building_name}']['Energy System Life Cycle Cost (CAD)']
+ new_system_archetype = new_system[f'{building_name}']['Energy System Archetype']
+ new_system_heating = new_system[f'{building_name}']['Heating System']
+ new_system_cooling = new_system[f'{building_name}']['Cooling System']
+ new_system_dhw = new_system[f'{building_name}']['DHW System']
+ new_system_pv = new_system[f'{building_name}']['Photovoltaic System Capacity']
+ new_system_heating_fuel = new_system[f'{building_name}']['Heating Fuel']
+ new_system_hvac_consumption = new_system[f'{building_name}']['Yearly HVAC Energy Consumption (MWh)']
+ new_system_dhw_consumption = new_system[f'{building_name}']['DHW Energy Consumption (MWH)']
+ new_pv_production = new_system[f'{building_name}']['PV Yearly Production (kWh)']
+ new_capital_cost = new_system[f'{building_name}']['Energy System Capital Cost (CAD)']
+ new_operational = new_system[f'{building_name}']['Energy System Average Yearly Operational Cost (CAD)']
+ new_lcc = new_system[f'{building_name}']['Energy System Life Cycle Cost (CAD)']
energy_system_table_data = [
["Detail", "Existing System", "Proposed System"],
- ["Energy System Archetype", existing_archetype, "-"],
- ["System Schematic", system_schematic, system_schematic],
- ["Heating System", heating_system, "-"],
- ["Cooling System", cooling_system, "-"],
- ["DHW System", dhw, "-"],
- ["Electricity", electricity, "-"],
- ["Fuel(s)", str(fuels), "-"],
- ["HVAC Energy Consumption (MWh)", hvac_ec, "-"],
- ["DHW Energy Consumption (MWH)", dhw_ec, "-"],
- ["Yearly Operational Cost (CAD)", yearly_operational_cost, "-"],
- ["Life Cycle Cost (CAD)", life_cycle_cost, "-"]
+ ["Energy System Archetype", current_system_archetype, new_system_archetype],
+ ["Heating System", current_system_heating, new_system_heating],
+ ["Cooling System", current_system_cooling, new_system_cooling],
+ ["DHW System", current_system_dhw, new_system_dhw],
+ ["Photovoltaic System Capacity", current_system_pv, new_system_pv],
+ ["Heating Fuel", current_system_heating_fuel, new_system_heating_fuel],
+ ["Yearly HVAC Energy Consumption (MWh)", current_system_hvac_consumption, new_system_hvac_consumption],
+ ["DHW Energy Consumption (MWH)", current_system_dhw_consumption, new_system_dhw_consumption],
+ ["PV Yearly Production (kWh)", current_pv_production, new_pv_production],
+ ["Energy System Capital Cost (CAD)", current_capital_cost, new_capital_cost],
+ ["Energy System Average Yearly Operational Cost (CAD)", current_operational, new_operational],
+ ["Energy System Life Cycle Cost (CAD)", current_lcc, new_lcc]
]
- self.report.add_table(energy_system_table_data, caption=f'Building {building.name} Energy System Characteristics')
+ self.report.add_table(energy_system_table_data, caption=f'Building {building_name} Energy System Characteristics')
def building_fuel_consumption_breakdown(self, building):
save_directory = self.output_path
@@ -255,19 +252,23 @@ class EnergySystemAnalysisReport:
# Iterate through energy systems of the building
for energy_system in building.energy_systems:
for demand_type in energy_system.demand_types:
- for generation_system in energy_system.generation_systems:
- consumption = 0
- if demand_type == cte.HEATING:
- consumption = building.heating_consumption[cte.YEAR][0] / 3.6e9
- elif demand_type == cte.DOMESTIC_HOT_WATER:
- consumption = building.domestic_hot_water_consumption[cte.YEAR][0] / 1e6
- elif demand_type == cte.COOLING:
- consumption = building.cooling_consumption[cte.YEAR][0] / 3.6e9
-
- if generation_system.fuel_type == cte.ELECTRICITY:
- fuel_breakdown[demand_type]["Electricity"] += consumption
- else:
- fuel_breakdown[demand_type]["Gas"] += consumption
+ if demand_type == cte.HEATING:
+ consumption = building.heating_consumption[cte.YEAR][0] / 3.6e9
+ for generation_system in energy_system.generation_systems:
+ if generation_system.fuel_type == cte.ELECTRICITY:
+ fuel_breakdown[demand_type]["Electricity"] += consumption
+ else:
+ fuel_breakdown[demand_type]["Gas"] += consumption
+ elif demand_type == cte.DOMESTIC_HOT_WATER:
+ consumption = building.domestic_hot_water_consumption[cte.YEAR][0] / 1e6
+ for generation_system in energy_system.generation_systems:
+ if generation_system.fuel_type == cte.ELECTRICITY:
+ fuel_breakdown[demand_type]["Electricity"] += consumption
+ else:
+ fuel_breakdown[demand_type]["Gas"] += consumption
+ elif demand_type == cte.COOLING:
+ consumption = building.cooling_consumption[cte.YEAR][0] / 3.6e9
+ fuel_breakdown[demand_type]["Electricity"] += consumption
electricity_labels = ['Appliance', 'Lighting']
electricity_sizes = [fuel_breakdown['Appliance'], fuel_breakdown['Lighting']]
@@ -317,7 +318,7 @@ class EnergySystemAnalysisReport:
plt.savefig(save_directory / f'{building.name}_energy_consumption_breakdown.png', dpi=300)
plt.close()
- def create_report(self):
+ def create_report(self, current_system, new_system):
os.chdir(self.output_path)
self.report.add_section('Current Status')
self.building_energy_info()
@@ -329,7 +330,7 @@ class EnergySystemAnalysisReport:
self.load_duration_curves()
for building in self.city.buildings:
self.individual_building_info(building)
- self.building_existing_system_info(building)
+ self.building_system_retrofit_results(building_name=building.name, current_system=current_system, new_system=new_system)
self.building_fuel_consumption_breakdown(building)
self.report.add_image(f'{building.name}_energy_consumption_breakdown.png',
caption=f'Building {building.name} Consumption by source and sector breakdown')
diff --git a/scripts/energy_system_retrofit_results.py b/scripts/energy_system_retrofit_results.py
new file mode 100644
index 00000000..f3f1cd4a
--- /dev/null
+++ b/scripts/energy_system_retrofit_results.py
@@ -0,0 +1,59 @@
+import hub.helpers.constants as cte
+
+
+def system_results(buildings):
+ system_performance_summary = {}
+ fields = ["Energy System Archetype", "Heating System", "Cooling System", "DHW System",
+ "Photovoltaic System Capacity", "Heating Fuel", "Yearly HVAC Energy Consumption (MWh)",
+ "DHW Energy Consumption (MWH)", "PV Yearly Production (kWh)",
+ "Energy System Capital Cost (CAD)", "Energy System Average Yearly Operational Cost (CAD)",
+ "Energy System Life Cycle Cost (CAD)"]
+ for building in buildings:
+ system_performance_summary[f'{building.name}'] = {}
+ for field in fields:
+ system_performance_summary[f'{building.name}'][field] = '-'
+
+ for building in buildings:
+ fuels = []
+ system_performance_summary[f'{building.name}']['Energy System Archetype'] = building.energy_systems_archetype_name
+ energy_systems = building.energy_systems
+ for energy_system in energy_systems:
+ demand_types = energy_system.demand_types
+ if cte.HEATING and cte.DOMESTIC_HOT_WATER in demand_types:
+ system_performance_summary[f'{building.name}']['Heating System'] = energy_system.name
+ system_performance_summary[f'{building.name}']['DHW System'] = energy_system.name
+ for generation_system in energy_system.generation_systems:
+ fuels.append(generation_system.fuel_type)
+ elif cte.DOMESTIC_HOT_WATER in energy_system.demand_types:
+ system_performance_summary[f'{building.name}']['DHW System'] = energy_system.name
+ elif cte.HEATING in energy_system.demand_types:
+ system_performance_summary[f'{building.name}']['Heating System'] = energy_system.name
+ for generation_system in energy_system.generation_systems:
+ fuels.append(generation_system.fuel_type)
+ elif cte.COOLING in energy_system.demand_types:
+ system_performance_summary[f'{building.name}']['Cooling System'] = energy_system.name
+ for generation_system in energy_system.generation_systems:
+ if generation_system.system_type == cte.PHOTOVOLTAIC:
+ system_performance_summary[f'{building.name}'][
+ 'Photovoltaic System Capacity'] = generation_system.nominal_electricity_output or str(0)
+ heating_fuels = ", ".join(fuels)
+ system_performance_summary[f'{building.name}']['Heating Fuel'] = heating_fuels
+ system_performance_summary[f'{building.name}']['Yearly HVAC Energy Consumption (MWh)'] = format(
+ (building.heating_consumption[cte.YEAR][0] + building.cooling_consumption[cte.YEAR][0]) / 3.6e9, '.2f')
+ system_performance_summary[f'{building.name}']['DHW Energy Consumption (MWH)'] = format(
+ building.domestic_hot_water_consumption[cte.YEAR][0] / 1e6, '.2f')
+ return system_performance_summary
+
+
+def new_system_results(buildings):
+ new_system_performance_summary = {}
+ fields = ["Energy System Archetype", "Heating System", "Cooling System", "DHW System",
+ "Photovoltaic System Capacity", "Heating Fuel", "Yearly HVAC Energy Consumption (MWh)",
+ "DHW Energy Consumption (MWH)", "PV Yearly Production (kWh)",
+ "Energy System Capital Cost (CAD)", "Energy System Average Yearly Operational Cost (CAD)",
+ "Energy System Life Cycle Cost (CAD)"]
+ for building in buildings:
+ new_system_performance_summary[f'{building.name}'] = {}
+ for field in fields:
+ new_system_performance_summary[f'{building.name}'][field] = '-'
+ return new_system_performance_summary
diff --git a/scripts/energy_system_sizing.py b/scripts/energy_system_sizing.py
index 42b53886..7f49d6af 100644
--- a/scripts/energy_system_sizing.py
+++ b/scripts/energy_system_sizing.py
@@ -17,18 +17,21 @@ class SystemSizing:
def hvac_sizing(self):
for building in self.buildings:
- peak_heating_demand = building.heating_peak_load[cte.YEAR][0]
- peak_cooling_demand = building.cooling_peak_load[cte.YEAR][0]
+ peak_heating_demand = building.heating_peak_load[cte.YEAR][0] / 3600
+ peak_cooling_demand = building.cooling_peak_load[cte.YEAR][0] / 3600
if peak_heating_demand > peak_cooling_demand:
sizing_demand = peak_heating_demand
for system in building.energy_systems:
if 'Heating' in system.demand_types:
for generation in system.generation_systems:
if generation.system_type == 'Heat Pump':
+ if generation.source_medium == cte.AIR:
+ generation.source_temperature = building.external_temperature
generation.nominal_heat_output = 0.6 * sizing_demand / 1000
- for storage in generation.energy_storage_systems:
- if storage.type_energy_stored == 'thermal':
- storage.volume = (sizing_demand * 1000) / (cte.WATER_HEAT_CAPACITY*cte.WATER_DENSITY)
+ if generation.energy_storage_systems is not None:
+ for storage in generation.energy_storage_systems:
+ if storage.type_energy_stored == 'thermal':
+ storage.volume = (sizing_demand * 1000) / (cte.WATER_HEAT_CAPACITY*cte.WATER_DENSITY)
elif generation.system_type == 'Boiler':
generation.nominal_heat_output = 0.4 * sizing_demand / 1000
@@ -40,6 +43,27 @@ class SystemSizing:
if generation.system_type == 'Heat Pump':
generation.nominal_heat_output = sizing_demand / 1000
+ def montreal_custom(self):
+ for building in self.buildings:
+ energy_systems = building.energy_systems
+ for energy_system in energy_systems:
+ demand_types = energy_system.demand_types
+ generation_systems = energy_system.generation_systems
+ if cte.HEATING in demand_types:
+ if len(generation_systems) == 1:
+ for generation in generation_systems:
+ generation.nominal_heat_output = building.heating_peak_load[cte.YEAR][0] / 3.6e6
+ else:
+ for generation in generation_systems:
+ generation.nominal_heat_output = building.heating_peak_load[cte.YEAR][0] / (len(generation_systems) * 3.6e6)
+ elif cte.COOLING in demand_types:
+ if len(generation_systems) == 1:
+ for generation in generation_systems:
+ generation.nominal_cooling_output = building.cooling_peak_load[cte.YEAR][0] / 3.6e6
+ else:
+ for generation in generation_systems:
+ generation.nominal_heat_output = building.cooling_peak_load[cte.YEAR][0] / (len(generation_systems) * 3.6e6)
+
diff --git a/scripts/energy_system_sizing_and_simulation_factory.py b/scripts/energy_system_sizing_and_simulation_factory.py
new file mode 100644
index 00000000..adef8151
--- /dev/null
+++ b/scripts/energy_system_sizing_and_simulation_factory.py
@@ -0,0 +1,33 @@
+"""
+EnergySystemSizingSimulationFactory retrieve the energy system archetype sizing and simulation module
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2022 Concordia CERC group
+Project Coder Saeed Ranjbar saeed.ranjbar@mail.concordia.ca
+"""
+
+from scripts.system_simulation_models.archetype13 import Archetype13
+
+
+class EnergySystemsSimulationFactory:
+ """
+ EnergySystemsFactory class
+ """
+
+ def __init__(self, handler, building):
+ self._handler = '_' + handler.lower()
+ self._building = building
+
+ def _archetype13(self):
+ """
+ Enrich the city by using the sizing and simulation model developed for archetype13 of montreal_future_systems
+ """
+ Archetype13(self._building).enrich_buildings()
+ self._building.level_of_detail.energy_systems = 2
+ self._building.level_of_detail.energy_systems = 2
+
+ def enrich(self):
+ """
+ Enrich the city given to the class using the class given handler
+ :return: None
+ """
+ getattr(self, self._handler, lambda: None)()
diff --git a/scripts/random_assignation.py b/scripts/random_assignation.py
index 4c2b558a..d607c259 100644
--- a/scripts/random_assignation.py
+++ b/scripts/random_assignation.py
@@ -15,8 +15,8 @@ from hub.city_model_structure.building import Building
energy_systems_format = 'montreal_custom'
# parameters:
-residential_systems_percentage = {'system 1 gas': 44,
- 'system 1 electricity': 6,
+residential_systems_percentage = {'system 1 gas': 100,
+ 'system 1 electricity': 0,
'system 2 gas': 0,
'system 2 electricity': 0,
'system 3 and 4 gas': 0,
@@ -25,10 +25,11 @@ residential_systems_percentage = {'system 1 gas': 44,
'system 5 electricity': 0,
'system 6 gas': 0,
'system 6 electricity': 0,
- 'system 8 gas': 44,
- 'system 8 electricity': 6}
+ 'system 8 gas': 0,
+ 'system 8 electricity': 0}
residential_new_systems_percentage = {'PV+ASHP+GasBoiler+TES': 100,
+ 'PV+4Pipe+DHW': 0,
'PV+ASHP+ElectricBoiler+TES': 0,
'PV+GSHP+GasBoiler+TES': 0,
'PV+GSHP+ElectricBoiler+TES': 0,
diff --git a/scripts/system_simulation.py b/scripts/system_simulation.py
index 8fbe9148..24759f26 100644
--- a/scripts/system_simulation.py
+++ b/scripts/system_simulation.py
@@ -9,10 +9,10 @@ from hub.helpers.monthly_values import MonthlyValues
class SystemSimulation:
- def __init__(self, building):
+ def __init__(self, building, out_path):
self.building = building
self.energy_systems = building.energy_systems
- self.heating_demand = building.heating_demand[cte.HOUR]
+ self.heating_demand = [0] + building.heating_demand[cte.HOUR]
self.cooling_demand = building.cooling_demand
self.dhw_demand = building.domestic_hot_water_heat_demand
self.T_out = building.external_temperature[cte.HOUR]
@@ -20,9 +20,10 @@ class SystemSimulation:
self.maximum_cooling_demand = building.cooling_peak_load[cte.YEAR][0]
self.name = building.name
self.energy_system_archetype = building.energy_systems_archetype_name
+ self.out_path = out_path
def archetype1(self):
- out_path = (Path(__file__).parent / 'out_files')
+ out_path = self.out_path
T, T_sup, T_ret, m_ch, m_dis, q_hp, q_aux = [0] * len(self.heating_demand), [0] * len(
self.heating_demand), [0] * len(self.heating_demand), [0] * len(self.heating_demand), [0] * len(
self.heating_demand), [0] * len(self.heating_demand), [0] * len(self.heating_demand)
@@ -36,7 +37,7 @@ class SystemSimulation:
if cte.ELECTRICITY not in energy_system.demand_types:
generation_systems = energy_system.generation_systems
for generation_system in generation_systems:
- if generation_system.system_type == cte.HEAT_PUMP:
+ if generation_system.system_type == cte.HEAT_PUMP and cte.HEATING in energy_system.demand_types:
hp_cap = generation_system.nominal_heat_output
hp_efficiency = float(generation_system.heat_efficiency)
for storage in generation_system.energy_storage_systems:
@@ -79,15 +80,15 @@ class SystemSimulation:
factor = 8
else:
factor = 4
- m_dis[i + 1] = self.maximum_heating_demand / (cte.WATER_HEAT_CAPACITY * factor)
+ m_dis[i + 1] = self.maximum_heating_demand / (cte.WATER_HEAT_CAPACITY * factor * 3600)
t_return = T[i + 1] - self.heating_demand[i + 1] / (m_dis[i + 1] * cte.WATER_HEAT_CAPACITY)
if m_dis[i + 1] == 0 or (m_dis[i + 1] > 0 and t_return < 25):
T_ret[i + 1] = max(25, T[i + 1])
else:
- T_ret[i + 1] = T[i + 1] - self.heating_demand[i + 1] / (m_dis[i + 1] * cte.WATER_HEAT_CAPACITY)
+ T_ret[i + 1] = T[i + 1] - self.heating_demand[i + 1] / (m_dis[i + 1] * cte.WATER_HEAT_CAPACITY * 3600)
tes_output = m_dis[i + 1] * cte.WATER_HEAT_CAPACITY * (T[i + 1] - T_ret[i + 1])
- if tes_output < self.heating_demand[i + 1]:
- q_aux[i + 1] = self.heating_demand[i + 1] - tes_output
+ if tes_output < (self.heating_demand[i + 1] / 3600):
+ q_aux[i + 1] = (self.heating_demand[i + 1] / 3600) - tes_output
aux_fuel[i + 1] = (q_aux[i + 1] * dt) / 50e6
boiler_consumption[i + 1] = q_aux[i + 1] / boiler_efficiency
heating_consumption[i + 1] = boiler_consumption[i + 1] + hp_electricity[i + 1]
@@ -99,11 +100,11 @@ class SystemSimulation:
output_file.writerow(['T', 'T_sup', 'T_ret', 'm_ch', 'm_dis', 'q_hp', 'hp_electricity', 'aux_fuel', 'q_aux', 'heating_demand'])
# Write data
output_file.writerows(data)
- return heating_consumption, hp_electricity, boiler_consumption
+ return heating_consumption, hp_electricity, boiler_consumption, T_sup
def enrich(self):
- if self.energy_system_archetype == 'PV+ASHP+GasBoiler+TES':
- building_new_heating_consumption, building_heating_electricity_consumption, building_heating_gas_consumption = (
+ if self.energy_system_archetype == 'PV+ASHP+GasBoiler+TES' or 'PV+4Pipe+DHW':
+ building_new_heating_consumption, building_heating_electricity_consumption, building_heating_gas_consumption, supply_temperature = (
self.archetype1())
self.building.heating_consumption[cte.HOUR] = building_new_heating_consumption
self.building.heating_consumption[cte.MONTH] = MonthlyValues.get_total_month(self.building.heating_consumption[cte.HOUR])
@@ -112,6 +113,8 @@ class SystemSimulation:
for energy_system in self.building.energy_systems:
if cte.HEATING in energy_system.demand_types:
for generation_system in energy_system.generation_systems:
+ if generation_system.system_type == cte.HEAT_PUMP:
+ generation_system.heat_supply_temperature = supply_temperature
disaggregated_consumption[generation_system.fuel_type] = {}
if generation_system.fuel_type == cte.ELECTRICITY:
disaggregated_consumption[generation_system.fuel_type][
diff --git a/scripts/system_simulation_models/archetype13.py b/scripts/system_simulation_models/archetype13.py
new file mode 100644
index 00000000..03057cdc
--- /dev/null
+++ b/scripts/system_simulation_models/archetype13.py
@@ -0,0 +1,100 @@
+import math
+
+import hub.helpers.constants as cte
+
+
+class Archetype13:
+ def __init__(self, building, output_path):
+ self._pv_system = building.energy_systems[0]
+ self._hvac_system = building.energy_systems[1]
+ self._dhw_system = building.energy_systems[-1]
+ self._heating_peak_load = building.heating_peak_load[cte.YEAR][0]
+ self._cooling_peak_load = building.cooling_peak_load[cte.YEAR][0]
+ self._domestic_hot_water_peak_load = building.domestic_hot_water_peak_load[cte.YEAR][0]
+ self._hourly_heating_demand = [0] + [demand / 3600 for demand in building.heating_demand[cte.HOUR]]
+ self._hourly_cooling_demand = [demand / 3600 for demand in building.cooling_demand[cte.HOUR]]
+ self._hourly_dhw_demand = building.domestic_hot_water_heat_demand[cte.HOUR]
+ self._output_path = output_path
+ self._t_out = building.external_temperature
+
+ def hvac_sizing(self):
+ storage_factor = 3
+ heat_pump = self._hvac_system.generation_systems[0]
+ boiler = self._hvac_system.generation_systems[1]
+ thermal_storage = heat_pump.energy_storage_systems[0]
+ heat_pump.nominal_heat_output = round(0.5 * self._heating_peak_load / 3600)
+ heat_pump.nominal_cooling_output = round(self._cooling_peak_load / 3600)
+ boiler.nominal_heat_output = round(0.5 * self._heating_peak_load / 3600)
+ thermal_storage.volume = round(
+ (self._heating_peak_load * storage_factor) / (cte.WATER_HEAT_CAPACITY * cte.WATER_DENSITY * 30))
+ return heat_pump, boiler, thermal_storage
+
+ def hvac_simulation(self):
+ hp, boiler, tes = self.hvac_sizing()
+ if hp.source_medium == cte.AIR:
+ hp.source_temperature = self._t_out[cte.HOUR]
+ # Heating System Simulation
+ variable_names = ["t_sup", "t_tank", "t_ret", "m_ch", "m_dis", "q_hp", "q_boiler", "hp_cop",
+ "hp_electricity", "boiler_gas", "boiler_consumption", "heating_consumption"]
+ num_hours = len(self._hourly_heating_demand)
+ variables = {name: [0] * num_hours for name in variable_names}
+ (t_sup, t_tank, t_ret, m_ch, m_dis, q_hp, q_boiler, hp_cop,
+ hp_electricity, boiler_gas, boiler_consumption, heating_consumption) = [variables[name] for name in variable_names]
+ t_tank[0] = 30
+ dt = 3600
+ hp_heating_cap = hp.nominal_heat_output
+ hp_efficiency = float(hp.heat_efficiency)
+ boiler_efficiency = float(boiler.heat_efficiency)
+ v, h = float(tes.volume), float(tes.height)
+ r_tot = sum(float(layer.thickness) / float(layer.material.conductivity) for layer in
+ tes.layers)
+ u_tot = 1 / r_tot
+ d = math.sqrt((4 * v) / (math.pi * h))
+ a_side = math.pi * d * h
+ a_top = math.pi * d ** 2 / 4
+ ua = u_tot * (2 * a_top + a_side)
+ for i in range(len(self._hourly_heating_demand) - 1):
+ t_tank[i + 1] = (t_tank[i] +
+ ((m_ch[i] * (t_sup[i] - t_tank[i])) +
+ (ua * (self._t_out[i] - t_tank[i] + 5)) / cte.WATER_HEAT_CAPACITY -
+ m_dis[i] * (t_tank[i] - t_ret[i])) * (dt / (cte.WATER_DENSITY * v)))
+ if t_tank[i + 1] < 40:
+ q_hp[i + 1] = hp_heating_cap
+ m_ch[i + 1] = q_hp[i + 1] / (cte.WATER_HEAT_CAPACITY * 7)
+ t_sup[i + 1] = (q_hp[i + 1] / (m_ch[i + 1] * cte.WATER_HEAT_CAPACITY)) + t_tank[i + 1]
+ elif 45 <= t_tank[i + 1] < 55 and q_hp[i] == 0:
+ q_hp[i + 1] = 0
+ m_ch[i + 1] = 0
+ t_sup[i + 1] = t_tank[i + 1]
+ elif 45 <= t_tank[i + 1] < 55 and q_hp[i] > 0:
+ q_hp[i + 1] = hp_heating_cap
+ m_ch[i + 1] = q_hp[i + 1] / (cte.WATER_HEAT_CAPACITY * 3)
+ t_sup[i + 1] = (q_hp[i + 1] / (m_ch[i + 1] * cte.WATER_HEAT_CAPACITY)) + t_tank[i + 1]
+ else:
+ q_hp[i + 1], m_ch[i + 1], t_sup[i + 1] = 0, 0, t_tank[i + 1]
+
+ hp_electricity[i + 1] = q_hp[i + 1] / hp_efficiency
+ if self._hourly_heating_demand[i + 1] == 0:
+ m_dis[i + 1], t_return, t_ret[i + 1] = 0, t_tank[i + 1], t_tank[i + 1]
+ else:
+ if self._hourly_heating_demand[i + 1] > 0.5 * self._heating_peak_load:
+ factor = 8
+ else:
+ factor = 4
+ m_dis[i + 1] = self._heating_peak_load / (cte.WATER_HEAT_CAPACITY * factor * 3600)
+ t_return = t_tank[i + 1] - self._hourly_heating_demand[i + 1] / (m_dis[i + 1] * cte.WATER_HEAT_CAPACITY)
+ if m_dis[i + 1] == 0 or (m_dis[i + 1] > 0 and t_return < 25):
+ t_ret[i + 1] = max(25, t_tank[i + 1])
+ else:
+ t_ret[i + 1] = t_tank[i + 1] - self._hourly_heating_demand[i + 1] / (m_dis[i + 1] * cte.WATER_HEAT_CAPACITY * 3600)
+ tes_output = m_dis[i + 1] * cte.WATER_HEAT_CAPACITY * (t_tank[i + 1] - t_ret[i + 1])
+ if tes_output < (self._hourly_heating_demand[i + 1] / 3600):
+ q_boiler[i + 1] = (self._hourly_heating_demand[i + 1] / 3600) - tes_output
+ boiler_gas[i + 1] = (q_boiler[i + 1] * dt) / 50e6
+ boiler_consumption[i + 1] = q_boiler[i + 1] / boiler_efficiency
+ heating_consumption[i + 1] = boiler_consumption[i + 1] + hp_electricity[i + 1]
+ data = list(zip(t_tank, t_sup, t_ret, m_ch, m_dis, q_hp, hp_electricity, boiler_gas, q_boiler,
+ self._hourly_heating_demand))
+
+ def enrich_buildings(self):
+ self.hvac_sizing()
diff --git a/tests/__pycache__/test_systems_catalog.cpython-39.pyc b/tests/__pycache__/test_systems_catalog.cpython-39.pyc
index 26324a1a..923b2ef7 100644
Binary files a/tests/__pycache__/test_systems_catalog.cpython-39.pyc and b/tests/__pycache__/test_systems_catalog.cpython-39.pyc differ
diff --git a/tests/__pycache__/test_systems_factory.cpython-39.pyc b/tests/__pycache__/test_systems_factory.cpython-39.pyc
index f6c71e1a..1458d3dc 100644
Binary files a/tests/__pycache__/test_systems_factory.cpython-39.pyc and b/tests/__pycache__/test_systems_factory.cpython-39.pyc differ
diff --git a/tests/test_systems_catalog.py b/tests/test_systems_catalog.py
index d41e5c07..839107c2 100644
--- a/tests/test_systems_catalog.py
+++ b/tests/test_systems_catalog.py
@@ -39,11 +39,11 @@ class TestSystemsCatalog(TestCase):
catalog_categories = catalog.names()
archetypes = catalog.names('archetypes')
- self.assertEqual(12, len(archetypes['archetypes']))
+ self.assertEqual(13, len(archetypes['archetypes']))
systems = catalog.names('systems')
- self.assertEqual(7, len(systems['systems']))
+ self.assertEqual(10, len(systems['systems']))
generation_equipments = catalog.names('generation_equipments')
- self.assertEqual(26, len(generation_equipments['generation_equipments']))
+ self.assertEqual(27, len(generation_equipments['generation_equipments']))
with self.assertRaises(ValueError):
catalog.names('unknown')
diff --git a/tests/test_systems_factory.py b/tests/test_systems_factory.py
index c4c086e3..442e5be5 100644
--- a/tests/test_systems_factory.py
+++ b/tests/test_systems_factory.py
@@ -114,7 +114,7 @@ class TestSystemsFactory(TestCase):
ResultFactory('insel_monthly_energy_balance', self._city, self._output_path).enrich()
for building in self._city.buildings:
- building.energy_systems_archetype_name = 'PV+ASHP+GasBoiler+TES'
+ building.energy_systems_archetype_name = 'PV+4Pipe+DHW'
EnergySystemsFactory('montreal_future', self._city).enrich()
# Need to assign energy systems to buildings:
for building in self._city.buildings: