fix: added radiation

This commit is contained in:
Saeed Ranjbar 2024-08-01 10:11:54 -04:00
parent 73a7a12a97
commit 36ebbdc165
9 changed files with 22994 additions and 14 deletions

View File

@ -135,6 +135,8 @@ class Geojson:
building_aliases = []
if 'id' in feature:
building_name = feature['id']
elif 'id' in feature['properties']:
building_name = feature['properties']['id']
else:
building_name = uuid.uuid4()
if self._aliases_field is not None:

File diff suppressed because it is too large Load Diff

37
main.py
View File

@ -7,9 +7,11 @@ from hub.imports.usage_factory import UsageFactory
from hub.imports.weather_factory import WeatherFactory
import hub.helpers.constants as cte
from hub.imports.energy_systems_factory import EnergySystemsFactory
from hub.exports.exports_factory import ExportsFactory
import pandas as pd
# Specify the GeoJSON file path
input_files_path = (Path(__file__).parent / 'input_files')
geojson_file_path = input_files_path / 'test.geojson'
geojson_file_path = input_files_path / 'Lachine_New_Developments.geojson'
output_path = (Path(__file__).parent / 'out_files').resolve()
output_path.mkdir(parents=True, exist_ok=True)
# Create city object from GeoJSON file
@ -23,6 +25,7 @@ city = GeometryFactory('geojson',
ConstructionFactory('nrcan', city).enrich()
UsageFactory('nrcan', city).enrich()
WeatherFactory('epw', city).enrich()
ExportsFactory('obj', city, output_path).export()
energy_plus_workflow(city)
for building in city.buildings:
print(building.heating_demand[cte.YEAR][0] / 3.6e6)
@ -42,16 +45,22 @@ for building in city.buildings:
if cte.HEATING in energy_system.demand_types:
for generation_unit in generation_units:
generation_unit.heat_efficiency = 0.96
# for building in city.buildings:
# building.function = cte.COMMERCIAL
#
# ConstructionFactory('nrcan', city).enrich()
# UsageFactory('nrcan', city).enrich()
# energy_plus_workflow(city)
# for building in city.buildings:
# print(building.heating_demand[cte.YEAR][0] / 3.6e6)
# print(building.name)
# total_floor_area = 0
# for thermal_zone in building.thermal_zones_from_internal_zones:
# total_floor_area += thermal_zone.total_floor_area
# print(building.heating_demand[cte.YEAR][0] / (3.6e6 * total_floor_area))
for building in city.buildings:
building.function = cte.COMMERCIAL
ConstructionFactory('nrcan', city).enrich()
UsageFactory('nrcan', city).enrich()
energy_plus_workflow(city)
for building in city.buildings:
print(building.heating_demand[cte.YEAR][0] / 3.6e6)
print(building.name)
total_floor_area = 0
for thermal_zone in building.thermal_zones_from_internal_zones:
total_floor_area += thermal_zone.total_floor_area
print(building.heating_demand[cte.YEAR][0] / (3.6e6 * total_floor_area))
building_names = []
for building in city.buildings:
building_names.append(building.name)
df = pd.DataFrame(columns=building_names)
df.to_csv('selected_buildings.csv')

113
scripts/radiation_tilted.py Normal file
View File

@ -0,0 +1,113 @@
import pandas as pd
import math
import hub.helpers.constants as cte
from hub.helpers.monthly_values import MonthlyValues
class RadiationTilted:
def __init__(self, building, solar_angles, tilt_angle, ghi, solar_constant=1366.1, maximum_clearness_index=1,
min_cos_zenith=0.065, maximum_zenith_angle=87):
self.building = building
self.ghi = ghi
self.tilt_angle = tilt_angle
self.zeniths = solar_angles['zenith'].tolist()[:-1]
self.incidents = solar_angles['incident angle'].tolist()[:-1]
self.date_time = solar_angles['DateTime'].tolist()[:-1]
self.ast = solar_angles['AST'].tolist()[:-1]
self.solar_azimuth = solar_angles['solar azimuth'].tolist()[:-1]
self.solar_altitude = solar_angles['solar altitude'].tolist()[:-1]
data = {'DateTime': self.date_time, 'AST': self.ast, 'solar altitude': self.solar_altitude, 'zenith': self.zeniths,
'solar azimuth': self.solar_azimuth, 'incident angle': self.incidents, 'ghi': self.ghi}
self.df = pd.DataFrame(data)
self.df['DateTime'] = pd.to_datetime(self.df['DateTime'])
self.df['AST'] = pd.to_datetime(self.df['AST'])
self.df.set_index('DateTime', inplace=True)
self.solar_constant = solar_constant
self.maximum_clearness_index = maximum_clearness_index
self.min_cos_zenith = min_cos_zenith
self.maximum_zenith_angle = maximum_zenith_angle
self.i_on = []
self.i_oh = []
self.k_t = []
self.fraction_diffuse = []
self.diffuse_horizontal = []
self.beam_horizontal = []
self.dni = []
self.beam_tilted = []
self.diffuse_tilted = []
self.total_radiation_tilted = []
self.calculate()
def dni_extra(self):
for i in range(len(self.df)):
self.i_on.append(self.solar_constant * (1 + 0.033 * math.cos(math.radians(360 * self.df.index.dayofyear[i] / 365))))
self.df['extraterrestrial normal radiation (Wh/m2)'] = self.i_on
def clearness_index(self):
for i in range(len(self.df)):
self.i_oh.append(self.i_on[i] * max(math.cos(math.radians(self.zeniths[i])), self.min_cos_zenith))
self.k_t.append(self.ghi[i] / self.i_oh[i])
self.k_t[i] = max(0, self.k_t[i])
self.k_t[i] = min(self.maximum_clearness_index, self.k_t[i])
self.df['extraterrestrial radiation on horizontal (Wh/m2)'] = self.i_oh
self.df['clearness index'] = self.k_t
def diffuse_fraction(self):
for i in range(len(self.df)):
if self.k_t[i] <= 0.22:
self.fraction_diffuse.append(1 - 0.09 * self.k_t[i])
elif self.k_t[i] <= 0.8:
self.fraction_diffuse.append(0.9511 - 0.1604 * self.k_t[i] + 4.388 * self.k_t[i] ** 2 -
16.638 * self.k_t[i] ** 3 + 12.336 * self.k_t[i] ** 4)
else:
self.fraction_diffuse.append(0.165)
if self.zeniths[i] > self.maximum_zenith_angle:
self.fraction_diffuse[i] = 1
self.df['diffuse fraction'] = self.fraction_diffuse
def radiation_components_horizontal(self):
for i in range(len(self.df)):
self.diffuse_horizontal.append(self.ghi[i] * self.fraction_diffuse[i])
self.beam_horizontal.append(self.ghi[i] - self.diffuse_horizontal[i])
self.dni.append((self.ghi[i] - self.diffuse_horizontal[i]) / math.cos(math.radians(self.zeniths[i])))
if self.zeniths[i] > self.maximum_zenith_angle or self.dni[i] < 0:
self.dni[i] = 0
self.df['diffuse horizontal (Wh/m2)'] = self.diffuse_horizontal
self.df['dni (Wh/m2)'] = self.dni
self.df['beam horizontal (Wh/m2)'] = self.beam_horizontal
def radiation_components_tilted(self):
for i in range(len(self.df)):
self.beam_tilted.append(self.dni[i] * math.cos(math.radians(self.incidents[i])))
self.beam_tilted[i] = max(self.beam_tilted[i], 0)
self.diffuse_tilted.append(self.diffuse_horizontal[i] * ((1 + math.cos(math.radians(self.tilt_angle))) / 2))
self.total_radiation_tilted.append(self.beam_tilted[i] + self.diffuse_tilted[i])
self.df['beam tilted (Wh/m2)'] = self.beam_tilted
self.df['diffuse tilted (Wh/m2)'] = self.diffuse_tilted
self.df['total radiation tilted (Wh/m2)'] = self.total_radiation_tilted
def calculate(self) -> pd.DataFrame:
self.dni_extra()
self.clearness_index()
self.diffuse_fraction()
self.radiation_components_horizontal()
self.radiation_components_tilted()
return self.df
def enrich(self):
tilted_radiation = self.total_radiation_tilted
self.building.roofs[0].global_irradiance_tilted[cte.HOUR] = [x * cte.WATTS_HOUR_TO_JULES for x in
tilted_radiation]
self.building.roofs[0].global_irradiance_tilted[cte.HOUR] = [x * cte.WATTS_HOUR_TO_JULES for x in
tilted_radiation]
self.building.roofs[0].global_irradiance_tilted[cte.MONTH] = (
MonthlyValues.get_total_month(self.building.roofs[0].global_irradiance_tilted[cte.HOUR]))
self.building.roofs[0].global_irradiance_tilted[cte.YEAR] = \
[sum(self.building.roofs[0].global_irradiance_tilted[cte.MONTH])]

146
scripts/solar_angles.py Normal file
View File

@ -0,0 +1,146 @@
import math
import pandas as pd
from datetime import datetime
from pathlib import Path
class CitySolarAngles:
def __init__(self, file_name, location_latitude, location_longitude, tilt_angle, surface_azimuth_angle,
standard_meridian=-75):
self.file_name = file_name
self.location_latitude = location_latitude
self.location_longitude = location_longitude
self.location_latitude_rad = math.radians(location_latitude)
self.surface_azimuth_angle = surface_azimuth_angle
self.surface_azimuth_rad = math.radians(surface_azimuth_angle)
self.tilt_angle = tilt_angle
self.tilt_angle_rad = math.radians(tilt_angle)
self.standard_meridian = standard_meridian
self.longitude_correction = (location_longitude - standard_meridian) * 4
self.timezone = 'Etc/GMT+5'
self.eot = []
self.ast = []
self.hour_angles = []
self.declinations = []
self.solar_altitudes = []
self.solar_azimuths = []
self.zeniths = []
self.incidents = []
self.beam_tilted = []
self.factor = []
self.times = pd.date_range(start='2023-01-01', end='2024-01-01', freq='H', tz=self.timezone)
self.df = pd.DataFrame(index=self.times)
self.day_of_year = self.df.index.dayofyear
def solar_time(self, datetime_val, day_of_year):
b = (day_of_year - 81) * 2 * math.pi / 364
eot = 9.87 * math.sin(2 * b) - 7.53 * math.cos(b) - 1.5 * math.sin(b)
self.eot.append(eot)
# Calculate Local Solar Time (LST)
lst_hour = datetime_val.hour
lst_minute = datetime_val.minute
lst_second = datetime_val.second
lst = lst_hour + lst_minute / 60 + lst_second / 3600
# Calculate Apparent Solar Time (AST) in decimal hours
ast_decimal = lst + eot / 60 + self.longitude_correction / 60
ast_hours = int(ast_decimal)
ast_minutes = round((ast_decimal - ast_hours) * 60)
# Ensure ast_minutes is within valid range
if ast_minutes == 60:
ast_hours += 1
ast_minutes = 0
elif ast_minutes < 0:
ast_minutes = 0
ast_time = datetime(year=datetime_val.year, month=datetime_val.month, day=datetime_val.day,
hour=ast_hours, minute=ast_minutes)
self.ast.append(ast_time)
return ast_time
def declination_angle(self, day_of_year):
declination = 23.45 * math.sin(math.radians(360 / 365 * (284 + day_of_year)))
declination_radian = math.radians(declination)
self.declinations.append(declination)
return declination_radian
def hour_angle(self, ast_time):
hour_angle = ((ast_time.hour * 60 + ast_time.minute) - 720) / 4
hour_angle_radian = math.radians(hour_angle)
self.hour_angles.append(hour_angle)
return hour_angle_radian
def solar_altitude(self, declination_radian, hour_angle_radian):
solar_altitude_radians = math.asin(math.cos(self.location_latitude_rad) * math.cos(declination_radian) *
math.cos(hour_angle_radian) + math.sin(self.location_latitude_rad) *
math.sin(declination_radian))
solar_altitude = math.degrees(solar_altitude_radians)
self.solar_altitudes.append(solar_altitude)
return solar_altitude_radians
def zenith(self, solar_altitude_radians):
solar_altitude = math.degrees(solar_altitude_radians)
zenith_degree = 90 - solar_altitude
zenith_radian = math.radians(zenith_degree)
self.zeniths.append(zenith_degree)
return zenith_radian
def solar_azimuth_analytical(self, hourangle, declination, zenith):
numer = (math.cos(zenith) * math.sin(self.location_latitude_rad) - math.sin(declination))
denom = (math.sin(zenith) * math.cos(self.location_latitude_rad))
if math.isclose(denom, 0.0, abs_tol=1e-8):
cos_azi = 1.0
else:
cos_azi = numer / denom
cos_azi = max(-1.0, min(1.0, cos_azi))
sign_ha = math.copysign(1, hourangle)
solar_azimuth_radians = sign_ha * math.acos(cos_azi) + math.pi
solar_azimuth_degrees = math.degrees(solar_azimuth_radians)
self.solar_azimuths.append(solar_azimuth_degrees)
return solar_azimuth_radians
def incident_angle(self, solar_altitude_radians, solar_azimuth_radians):
incident_radian = math.acos(math.cos(solar_altitude_radians) *
math.cos(abs(solar_azimuth_radians - self.surface_azimuth_rad)) *
math.sin(self.tilt_angle_rad) + math.sin(solar_altitude_radians) *
math.cos(self.tilt_angle_rad))
incident_angle_degrees = math.degrees(incident_radian)
self.incidents.append(incident_angle_degrees)
return incident_radian
@property
def calculate(self) -> pd.DataFrame:
for i in range(len(self.times)):
datetime_val = self.times[i]
day_of_year = self.day_of_year[i]
declination_radians = self.declination_angle(day_of_year)
ast_time = self.solar_time(datetime_val, day_of_year)
hour_angle_radians = self.hour_angle(ast_time)
solar_altitude_radians = self.solar_altitude(declination_radians, hour_angle_radians)
zenith_radians = self.zenith(solar_altitude_radians)
solar_azimuth_radians = self.solar_azimuth_analytical(hour_angle_radians, declination_radians, zenith_radians)
incident_angle_radian = self.incident_angle(solar_altitude_radians, solar_azimuth_radians)
self.df['DateTime'] = self.times
self.df['AST'] = self.ast
self.df['hour angle'] = self.hour_angles
self.df['eot'] = self.eot
self.df['declination angle'] = self.declinations
self.df['solar altitude'] = self.solar_altitudes
self.df['zenith'] = self.zeniths
self.df['solar azimuth'] = self.solar_azimuths
self.df['incident angle'] = self.incidents
return self.df

1
selected_buildings.csv Normal file
View File

@ -0,0 +1 @@
,1673,1646,1647,1648,1649,1650,1651,1652,1653,1654,1655,1656,1657,1658,1659,1660,1661,1662,1663,1664,1665,1666,1667,1668,1669,1676,1677,1678,1679,1680,1681,1687,1674,1688,1675,1689,1690,1691
1 1673 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1676 1677 1678 1679 1680 1681 1687 1674 1688 1675 1689 1690 1691

59
solar_radiation.py Normal file
View File

@ -0,0 +1,59 @@
from pathlib import Path
import subprocess
from scripts.ep_workflow import energy_plus_workflow
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
import hub.helpers.constants as cte
from hub.exports.exports_factory import ExportsFactory
from hub.imports.results_factory import ResultFactory
import pandas as pd
from scripts.solar_angles import CitySolarAngles
from scripts.radiation_tilted import RadiationTilted
# Specify the GeoJSON file path
input_files_path = (Path(__file__).parent / 'input_files')
geojson_file_path = input_files_path / 'Lachine_New_Developments.geojson'
output_path = (Path(__file__).parent / 'out_files').resolve()
output_path.mkdir(parents=True, exist_ok=True)
sra_output_path = output_path / 'sra_outputs'
sra_output_path.mkdir(parents=True, exist_ok=True)
# Create city object from GeoJSON file
city = GeometryFactory('geojson',
path=geojson_file_path,
height_field='maximum_roof_height',
year_of_construction_field='year_built',
function_field='building_type',
function_to_hub=Dictionaries().montreal_function_to_hub_function).city
# Enrich city data
WeatherFactory('epw', city).enrich()
ExportsFactory('sra', city, sra_output_path).export()
sra_path = (sra_output_path / f'{city.name}_sra.xml').resolve()
subprocess.run(['sra', str(sra_path)])
ResultFactory('sra', city, sra_output_path).enrich()
solar_angles = CitySolarAngles(city.name,
city.latitude,
city.longitude,
tilt_angle=45,
surface_azimuth_angle=180).calculate
for building in city.buildings:
ghi = [x / cte.WATTS_HOUR_TO_JULES for x in building.roofs[0].global_irradiance[cte.HOUR]]
RadiationTilted(building,
solar_angles,
tilt_angle=45,
ghi=ghi).enrich()
building_names = []
for building in city.buildings:
building_names.append(building.name)
df = pd.DataFrame(columns=building_names)
df1 = pd.DataFrame(columns=building_names)
print('test')
for building in city.buildings:
# if building.name in selected_buildings_list:
df[f'{building.name}'] = building.roofs[0].global_irradiance[cte.HOUR]
df1[f'{building.name}'] = building.roofs[0].global_irradiance_tilted[cte.HOUR]
df.to_csv('solar_radiation_horizontal_selected_buildings.csv')
df1.to_csv('solar_radiation_tilted_selected_buildings.csv')

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff