diff --git a/bpeng/thermal/solar_infiltration.py b/bpeng/thermal/solar_infiltration.py new file mode 100644 index 0000000000000000000000000000000000000000..a947e67d96704b0cd87831882f86ba5c6a304e6a --- /dev/null +++ b/bpeng/thermal/solar_infiltration.py @@ -0,0 +1,204 @@ +""" +provide solar heat gains and infiltation levels for a building +""" + +import numpy as np +import pvlib + +# Set dictionnaries for constants + +# (SI, IP) +EFF_LEAK_DICT = { + 'Tight': (0.7, 0.01), + 'Good': (1.4, 0.02), + 'Average': (2.8, 0.04), + 'Leaky': (5.6, 0.08), + 'Very Leaky': (10.4, 0.15) +} + +# Format: +# 'ABC': (one story, two stories, three stories) +# A: shelter class +# BC: unit type +WIND_COEFF_DIC = { + '1SI': (.00319, .00420, .00494), + '1IP': (.0119, .0157, .0184), + '2SI': (.000246, .000325, .000382), + '2IP': (.0092, .0121, .0143), + '3SI': (.000174, .000231, .000271), + '3IP': (.0065, .0086, .0101), + '4SI': (.000104, .000137, .000161), + '4IP': (.0039, .0051, .0060), + '5SI': (.000032, .000042, .000049), + '5IP': (.0012, .0016, .0018) +} + +# unit: (one story, two stories, three stories, four stories, five stories, six stories) +STACK_COEFF_DIC = { + 'SI': (.000145, .000290, .000435, .000580, .000725, .000870), + 'IP': (.03, .059, .089, .118, .148, .178) +} + + +def get_zone_wind_vel(wind_vel_data, + zone_height, + alpha=.22, + met_height=10): + """ + Calculate wind velocity for a zone the thermal model is run for. Units for zone_height should be 'SI' + + Args: + + wind_vel_data (pandas.Series) + Use 'SI' units for wind_vel_data from the weather station. the wind velocity data from the + weather station / meteoriological station in timestamp that it is needed for + + zone_height (float) + the height of the zone to run the thermal model + + alpha (float) + it's a constant for the terrain (default for urban terrain) + + met_height (float) + height at which the wind_vel_data is measured at by weather station (usually 10m) + if inputs in IP units, input met_height in feet + + Returns: + + pandas.Series: wind velocity for a zone on every timestamp needed + """ + + wind_vel_zone = wind_vel_data * np.power(zone_height / met_height, alpha) + return wind_vel_zone + + +# pylint: disable=too-many-locals +def get_infil_rate(wind_vel_zone, + inf_level, + zone_floor, + shelter_class, + zone_exposed_area, + t_zone, + t_amb, + units='SI'): + """ + Calculate infiltration rate for a zone the thermal model is run for + Args: + + wind_vel_zone (pandas.Series) + the velocity of wind in the zone_exposed_area obtained from the get_zone_wind_vel() function + + inf_level (str) + infiltration level of the building + options are: 'Tight', 'Good', 'Average', 'Leaky', 'Very Leaky' + + zone_floor (int) + it is the floor # of the zone you are running the model for + + shelter_class (int) + it defines the type of shelter + options are: + 1; no obstructions or local shielding + 2; typical shelter for an isolated rural house + 3; typical shelter caused by adjacent buildings near the building of study + 4; typical shelter for urban buildings on larger lots where sheltering obstacles + are more than one building away + 5; typical shelter produced by buildings and other structures immediately adjacent-closer + than one house height + e.g.,neighboring houses on same side of street, trees, bushes etc. + + zone_exposed_area (float) + it is the total exposed area for the zone + + t_zone (float) + the indoor temp of the zone + + t_amb (float) + the outdoor temp of the ambient + + Returns: + pandas.Series: infiltration rate for a zone on every timestamp in datetime_list + index of pandas.Series = datetime_list + """ + if units == 'SI': + unit_key = 0 + elif units == 'IP': + unit_key = 1 + eff_leak = EFF_LEAK_DICT.get(inf_level)[unit_key] + shelter_key = str(shelter_class) + str(units) + floor_key = zone_floor - 1 + + if floor_key > 2: + floor_key_wind_coeff = 2 + else: + floor_key_wind_coeff = floor_key + + if floor_key > 5: + floor_key_stack_coeff = 5 + else: + floor_key_stack_coeff = floor_key + + wind_coeff = WIND_COEFF_DIC.get(shelter_key)[floor_key_wind_coeff] + stack_coeff = STACK_COEFF_DIC.get(units)[floor_key_stack_coeff] + infil_rate = eff_leak * zone_exposed_area * np.power( + stack_coeff * + (t_zone - t_amb) + wind_coeff * np.power(wind_vel_zone, 2), .5) + return infil_rate + + +def window_solar_gain(datetime_list, + latitude, + longitude, + surface_azimuth, + local_ghi, + local_dni, + local_dhi, + window_sunlit_fraction, + area, + tilt=90): + """ + Calculate solar radiation heat gain from windows + + Args: + + datetime_list (list): + list of date and times for which to calculate solar radiation heat gain + latitude (float): + location latitude angle [degrees] + longitude (float): + location longitude angle [degrees] + surface_azimuth (float or int): + window azimuth angle from North axis [degrees] + local_ghi (pandas.Series): + global horizontal irrdiation for location for each timestamp in datetime_list + local_dni (pandas.Series): + direct normal irradiation for location for each timestamp in datetime_list + local_dhi (pandas.Series): + diffuse horizontal irradiation for location for each timestamp in datetime_list + window_sunlit_fraction (pandas.Series): + fraction of window in sunlight (EnergyPlus simulation output) for each timestamp in datetime_list + area (float or int): + window area [m^2] + tilt (float or int): + window tilt angle [degrees], default is 90 + + Returns: + + pandas.Series: solar radiation heat gain for window for every timestamp in datetime_list + index of pandas.Series = datetime_list + """ + local_dhi.index = datetime_list + local_dni.index = datetime_list + local_ghi.index = datetime_list + window_sunlit_fraction.index = datetime_list + + location = pvlib.solarposition.get_solarposition(datetime_list, latitude, + longitude) + totrad_surf = pvlib.irradiance.total_irrad( + tilt, surface_azimuth, location['apparent_zenith'], + location['azimuth'], local_dni, local_ghi, local_dhi) + + heatgain = (totrad_surf['poa_direct'] * window_sunlit_fraction + + totrad_surf['poa_diffuse']) * area + + return heatgain diff --git a/requirements.txt b/requirements.txt index 25dc558cf832a713a8fc8258b095611b3d4dea1c..c1bedd9138c3519ba616d359fc30f22c8183d7ae 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ geopy==1.11.0 oplus==4.6.0 +pvlib==0.4.4 requests==2.12.4 xlrd==1.0.0