diff --git a/pv_assessment.py b/pv_assessment.py new file mode 100644 index 00000000..1ae6a554 --- /dev/null +++ b/pv_assessment.py @@ -0,0 +1,80 @@ +import pandas as pd +from pathlib import Path +import subprocess +from hub.imports.geometry_factory import GeometryFactory +from hub.helpers.dictionaries import Dictionaries +from hub.imports.construction_factory import ConstructionFactory +from hub.imports.usage_factory import UsageFactory +from hub.imports.weather_factory import WeatherFactory +from hub.imports.results_factory import ResultFactory +from scripts.solar_angles import CitySolarAngles +from scripts.ep_workflow import energy_plus_workflow +import hub.helpers.constants as cte +from hub.exports.exports_factory import ExportsFactory +from scripts.pv_sizing_and_simulation import PVSizingSimulation +# Specify the GeoJSON file path +input_files_path = (Path(__file__).parent / 'input_files') +input_files_path.mkdir(parents=True, exist_ok=True) +geojson_file_path = input_files_path / 'test.geojson' +output_path = (Path(__file__).parent / 'out_files').resolve() +output_path.mkdir(parents=True, exist_ok=True) +energy_plus_output_path = output_path / 'energy_plus_outputs' +energy_plus_output_path.mkdir(parents=True, exist_ok=True) +simulation_results_path = (Path(__file__).parent / 'out_files' / 'simulation_results').resolve() +simulation_results_path.mkdir(parents=True, exist_ok=True) +sra_output_path = output_path / 'sra_outputs' +sra_output_path.mkdir(parents=True, exist_ok=True) +cost_analysis_output_path = output_path / 'cost_analysis' +cost_analysis_output_path.mkdir(parents=True, exist_ok=True) +# Create city object from GeoJSON file +city = GeometryFactory('geojson', + path=geojson_file_path, + height_field='height', + year_of_construction_field='year_of_construction', + function_field='function', + function_to_hub=Dictionaries().montreal_function_to_hub_function).city +# Enrich city data +ConstructionFactory('nrcan', city).enrich() +UsageFactory('nrcan', city).enrich() +WeatherFactory('epw', city).enrich() +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() +energy_plus_workflow(city, energy_plus_output_path) +solar_angles = CitySolarAngles(city.name, + city.latitude, + city.longitude, + tilt_angle=45, + surface_azimuth_angle=180).calculate +df = pd.DataFrame() +df.index = ['yearly lighting (kWh)', 'yearly appliance (kWh)', 'yearly heating (kWh)', 'yearly cooling (kWh)', + 'yearly dhw (kWh)', 'roof area (m2)', 'used area for pv (m2)', 'number of panels', 'pv production (kWh)'] +for building in city.buildings: + ghi = [x / cte.WATTS_HOUR_TO_JULES for x in building.roofs[0].global_irradiance[cte.HOUR]] + pv_sizing_simulation = PVSizingSimulation(building, + solar_angles, + tilt_angle=45, + module_height=1, + module_width=2, + ghi=ghi) + pv_sizing_simulation.pv_output() + yearly_lighting = building.lighting_electrical_demand[cte.YEAR][0] / 1000 + yearly_appliance = building.appliances_electrical_demand[cte.YEAR][0] / 1000 + yearly_heating = building.heating_demand[cte.YEAR][0] / (3.6e6 * 3) + yearly_cooling = building.cooling_demand[cte.YEAR][0] / (3.6e6 * 4.5) + yearly_dhw = building.domestic_hot_water_heat_demand[cte.YEAR][0] / 1000 + roof_area = building.roofs[0].perimeter_area + used_roof = pv_sizing_simulation.available_space() + number_of_pv_panels = pv_sizing_simulation.total_number_of_panels + yearly_pv = building.onsite_electrical_production[cte.YEAR][0] / 1000 + df[f'{building.name}'] = [yearly_lighting, yearly_appliance, yearly_heating, yearly_cooling, yearly_dhw, roof_area, + used_roof, number_of_pv_panels, yearly_pv] + +df.to_csv(output_path / 'pv.csv') + + + + + + diff --git a/scripts/pv_sizing_and_simulation.py b/scripts/pv_sizing_and_simulation.py new file mode 100644 index 00000000..6ef1a51d --- /dev/null +++ b/scripts/pv_sizing_and_simulation.py @@ -0,0 +1,59 @@ +import math + +from scripts.radiation_tilted import RadiationTilted +import hub.helpers.constants as cte +from hub.helpers.monthly_values import MonthlyValues + + +class PVSizingSimulation(RadiationTilted): + def __init__(self, building, solar_angles, tilt_angle, module_height, module_width, ghi): + super().__init__(building, solar_angles, tilt_angle, ghi) + self.module_height = module_height + self.module_width = module_width + self.total_number_of_panels = 0 + self.enrich() + + def available_space(self): + roof_area = self.building.roofs[0].perimeter_area + maintenance_factor = 0.1 + orientation_factor = 0.2 + if self.building.function == cte.RESIDENTIAL: + mechanical_equipment_factor = 0.2 + else: + mechanical_equipment_factor = 0.3 + available_roof = (maintenance_factor + orientation_factor + mechanical_equipment_factor) * roof_area + return available_roof + + def inter_row_spacing(self): + winter_solstice = self.df[(self.df['AST'].dt.month == 12) & + (self.df['AST'].dt.day == 21) & + (self.df['AST'].dt.hour == 12)] + solar_altitude = winter_solstice['solar altitude'].values[0] + solar_azimuth = winter_solstice['solar azimuth'].values[0] + distance = ((self.module_height * abs(math.cos(math.radians(solar_azimuth)))) / + math.tan(math.radians(solar_altitude))) + distance = float(format(distance, '.1f')) + return distance + + def number_of_panels(self, available_roof, inter_row_distance): + space_dimension = math.sqrt(available_roof) + space_dimension = float(format(space_dimension, '.2f')) + panels_per_row = math.ceil(space_dimension / self.module_width) + number_of_rows = math.ceil(space_dimension / inter_row_distance) + self.total_number_of_panels = panels_per_row * number_of_rows + return panels_per_row, number_of_rows + + def pv_output(self): + radiation = self.total_radiation_tilted + pv_module_area = self.module_width * self.module_height + available_roof = self.available_space() + inter_row_spacing = self.inter_row_spacing() + self.number_of_panels(available_roof, inter_row_spacing) + self.building.roofs[0].installed_solar_collector_area = pv_module_area * self.total_number_of_panels + system_efficiency = 0.2 + pv_hourly_production = [x * system_efficiency * self.total_number_of_panels * pv_module_area * + cte.WATTS_HOUR_TO_JULES for x in radiation] + self.building.onsite_electrical_production[cte.HOUR] = pv_hourly_production + self.building.onsite_electrical_production[cte.MONTH] = ( + MonthlyValues.get_total_month(self.building.onsite_electrical_production[cte.HOUR])) + self.building.onsite_electrical_production[cte.YEAR] = [sum(self.building.onsite_electrical_production[cte.MONTH])] \ No newline at end of file