Source code for ladybug.wea

# coding=utf-8
"""Wea weather file."""
from .epw import EPW
from .stat import Stat
from .location import Location
from .dt import DateTime
from .header import Header
from .datacollection import DataCollection
from .datatype import DataPoint
from .analysisperiod import AnalysisPeriod
from .sunpath import Sunpath
from .euclid import Vector3

import math
try:
    from itertools import izip as zip
except ImportError:
    # python 3
    xrange = range


[docs]class Wea(object): """An annual WEA object containing solar radiation. Attributes: location: Ladybug location object. direct_normal_radiation: An annual DataCollection of direct normal radiation values. diffuse_horizontal_radiation: An annual DataCollection of diffuse horizontal radiation values for every hourly timestep of the year. timestep: An optional integer to set the number of time steps per hour. Default is 1 for one value per hour. is_leap_year: A boolean to indicate if values are representing a leap year. Default is False. """ def __init__(self, location, direct_normal_radiation, diffuse_horizontal_radiation, timestep=1, is_leap_year=False): """Create a wea object.""" timestep = timestep or 1 self._timestep = timestep self._is_leap_year = is_leap_year assert isinstance(timestep, int), 'timestep must be an' \ ' integer. Got {}'.format(type(timestep)) self.location = location self.direct_normal_radiation = direct_normal_radiation self.diffuse_horizontal_radiation = diffuse_horizontal_radiation
[docs] @classmethod def from_values(cls, location, direct_normal_radiation, diffuse_horizontal_radiation, timestep=1, is_leap_year=False): """Create wea from a list of radiation values. This method converts input lists to DataCollection. """ dnr, dhr = cls._get_empty_data_collections(location, timestep, is_leap_year) dts = cls._get_datetimes(timestep, is_leap_year) for dir_norm, diff_horiz, dt in zip(direct_normal_radiation, diffuse_horizontal_radiation, dts): dnr.append(DataPoint(dir_norm, dt, 'SI', 'Direct Normal Radiation')) dhr.append(DataPoint(diff_horiz, dt, 'SI', 'Diffuse Horizontal Radiation')) return cls(location, direct_normal_radiation, diffuse_horizontal_radiation, timestep, is_leap_year)
[docs] @classmethod def from_json(cls, data): """ Create Wea from json file { "location": {} , // ladybug location schema "direct_normal_radiation": [], // List of hourly direct normal radiation data points "diffuse_horizontal_radiation": [], // List of hourly diffuse horizontal radiation data points "timestep": float //timestep between measurements, default is 1 } """ required_keys = ('location', 'direct_normal_radiation', 'diffuse_horizontal_radiation') optional_keys = ('timestep', 'is_leap_year') for key in required_keys: assert key in data, 'Required key "{}" is missing!'.format(key) for key in optional_keys: if key not in data: data[key] = None location = Location.from_json(data['location']) direct_normal_radiation = \ DataCollection.from_json(data['direct_normal_radiation']) diffuse_horizontal_radiation = \ DataCollection.from_json(data['diffuse_horizontal_radiation']) timestep = data['timestep'] is_leap_year = data['is_leap_year'] return cls(location, direct_normal_radiation, diffuse_horizontal_radiation, timestep, is_leap_year)
[docs] @classmethod def from_epw_file(cls, epwfile, timestep=1): """Create a wea object using the solar radiation values in an epw file. Args: epwfile: Full path to epw weather file. timestep: An optional integer to set the number of time steps per hour. Default is 1 for one value per hour. Note that this input will only do a linear interpolation over the data in the EPW file. While such linear interpolations are suitable for most thermal simulations, where thermal lag "smooths over" the effect of momentary increases in solar energy, it is not recommended for daylight simulations, where momentary increases in solar energy can mean the difference between glare and visual comfort. """ epw = EPW(epwfile) direct_normal = epw.direct_normal_radiation diffuse_horizontal = epw.diffuse_horizontal_radiation if timestep is not 1: print ("Note: timesteps greater than 1 on epw-generated Wea's \n" + "are suitable for thermal models but are not recommended \n" + "for daylight models.") direct_normal = direct_normal.interpolate_data(timestep, True) diffuse_horizontal = diffuse_horizontal.interpolate_data(timestep, True) else: # add half an hour to datetime to put sun in the middle of the hour for dnr in direct_normal: dnr.datetime = dnr.datetime.add_minute(30) for dhr in diffuse_horizontal: dhr.datetime = dhr.datetime.add_minute(30) # epw file is always for 8760 hours is_leap_year = False return cls(epw.location, direct_normal, diffuse_horizontal, timestep, is_leap_year)
[docs] @classmethod def from_stat_file(cls, statfile, timestep=1, is_leap_year=False): """Create an ASHRAE Revised Clear Sky wea object from the monthly sky optical depths in a .stat file. Args: statfile: Full path to the .stat file. timestep: An optional integer to set the number of time steps per hour. Default is 1 for one value per hour. is_leap_year: A boolean to indicate if values are representing a leap year. Default is False. """ stat = Stat(statfile) # check to be sure the stat file does not have missing tau values def check_missing(opt_data, data_name): for i, x in enumerate(opt_data): if x is None: raise ValueError( 'Missing optical depth data for {} at month {}'.format( data_name, i) ) check_missing(stat.monthly_tau_beam, 'monthly_tau_beam') check_missing(stat.monthly_tau_diffuse, 'monthly_tau_diffuse') return cls.from_ashrae_revised_clear_sky(stat.location, stat.monthly_tau_beam, stat.monthly_tau_diffuse, timestep, is_leap_year)
[docs] @classmethod def from_ashrae_revised_clear_sky(cls, location, monthly_tau_beam, monthly_tau_diffuse, timestep=1, is_leap_year=False): """Create a wea object representing an ASHRAE Revised Clear Sky ("Tau Model") ASHRAE Revised Clear Skies are intended to determine peak solar load and sizing parmeters for HVAC systems. The revised clear sky is currently the default recommended sky model used to autosize HVAC systems in EnergyPlus. For more information on the ASHRAE Revised Clear Sky model, see the EnergyPlus Engineering Reference: https://bigladdersoftware.com/epx/docs/8-9/engineering-reference/climate-calculations.html Args: location: Ladybug location object. monthly_tau_beam: A list of 12 float values indicating the beam optical depth of the sky at each month of the year. monthly_tau_diffuse: A list of 12 float values indicating the diffuse optical depth of the sky at each month of the year. timestep: An optional integer to set the number of time steps per hour. Default is 1 for one value per hour. is_leap_year: A boolean to indicate if values are representing a leap year. Default is False. """ # create sunpath and get altitude at every timestep of the year sp = Sunpath.from_location(location) sp.is_leap_year = is_leap_year altitudes = [] months = [] dates = cls._get_datetimes(timestep, is_leap_year) for t_date in dates: sun = sp.calculate_sun_from_date_time(t_date) months.append(sun.datetime.month - 1) altitudes.append(sun.altitude) # calculate hourly air mass between top of the atmosphere and earth air_masses = [] for alt in altitudes: air_mass = 0 if alt > 0: air_mass = 1 / (math.sin(math.radians(alt)) + (0.50572 * math.pow((6.07995 + alt), -1.6364))) air_masses.append(air_mass) # calculate monthly air mass exponents. beam_epxs = [] diffuse_exps = [] for count, tb in enumerate(monthly_tau_beam): td = monthly_tau_diffuse[count] ab = 1.219 - (0.043 * tb) - (0.151 * td) - (0.204 * tb * td) ad = 0.202 + (0.852 * tb) - (0.007 * td) - (0.357 * tb * td) beam_epxs.append(ab) diffuse_exps.append(ad) # compute the clear sky radiation values direct_norm_rad, diffuse_horiz_rad = \ cls._get_empty_data_collections(location, timestep, is_leap_year) for i, air_mass in enumerate(air_masses): alt = altitudes[i] if alt > 0: m = months[i] e_beam = (1415 * math.exp(-monthly_tau_beam[m] * math.pow( air_mass, beam_epxs[m]))) / timestep e_diff = (1415 * math.exp(-monthly_tau_diffuse[m] * math.pow( air_mass, diffuse_exps[m]))) / timestep direct_norm_rad.append( DataPoint(e_beam, dates[i], 'SI', 'Direct Normal Radiation')) diffuse_horiz_rad.append( DataPoint(e_diff, dates[i], 'SI', 'Diffuse Horizontal Radiation')) else: direct_norm_rad.append( DataPoint(0, dates[i], 'SI', 'Direct Normal Radiation')) diffuse_horiz_rad.append( DataPoint(0, dates[i], 'SI', 'Diffuse Horizontal Radiation')) return cls(location, direct_norm_rad, diffuse_horiz_rad, timestep, is_leap_year)
[docs] @classmethod def from_ashrae_clear_sky(cls, location, sky_clearness=1, timestep=1, is_leap_year=False): """Create a wea object representing an original ASHRAE Clear Sky. The original ASHRAE Clear Sky is intended to determine peak solar load and sizing parmeters for HVAC systems. It is not the sky model currently recommended by ASHRAE since it usually overestimates the amount of solar radiation in comparison to the newer ASHRAE Revised Clear Sky ("Tau Model"). However, the original model here is still useful for cases where monthly optical depth values are not known. For more information on the ASHRAE Clear Sky model, see the EnergyPlus Engineering Reference: https://bigladdersoftware.com/epx/docs/8-9/engineering-reference/climate-calculations.html Args: location: Ladybug location object. sky_clearness: A factor that will be multiplied by the output of the model. This is to help account for locations where clear, dry skies predominate (e.g., at high elevations) or, conversely, where hazy and humid conditions are frequent. See Threlkeld and Jordan (1958) for recommended values. Typical values range from 0.95 to 1.05 and are usually never more than 1.2. Default is set to 1.0. timestep: An optional integer to set the number of time steps per hour. Default is 1 for one value per hour. is_leap_year: A boolean to indicate if values are representing a leap year. Default is False. """ # parameters that approximate clear conditions across the planet # apparent solar irradiation at air mass m = 0 monthly_a = [1202, 1187, 1164, 1130, 1106, 1092, 1093, 1107, 1136, 1166, 1190, 1204] # atmospheric extinction coefficient monthly_b = [0.141, 0.142, 0.149, 0.164, 0.177, 0.185, 0.186, 0.182, 0.165, 0.152, 0.144, 0.141] # create sunpath and get altitude at every timestep of the year sp = Sunpath.from_location(location) sp.is_leap_year = is_leap_year altitudes = [] months = [] dates = cls._get_datetimes(timestep, is_leap_year) for t_date in dates: sun = sp.calculate_sun_from_date_time(t_date) months.append(sun.datetime.month - 1) altitudes.append(sun.altitude) # compute hourly direct normal and diffuse horizontal radiation direct_norm_rad, diffuse_horiz_rad = \ cls._get_empty_data_collections(location, timestep, is_leap_year) for i, alt in enumerate(altitudes): if alt > 0: try: dir_norm = monthly_a[months[i]] / (math.exp( monthly_b[months[i]] / (math.sin(math.radians(alt))))) diff_horiz = 0.17 * dir_norm * math.sin(math.radians(alt)) dir_norm = (dir_norm * sky_clearness) / timestep diff_horiz = (diff_horiz * sky_clearness) / timestep direct_norm_rad.append(DataPoint( dir_norm, dates[i], 'SI', 'Direct Normal Radiation')) diffuse_horiz_rad.append(DataPoint( diff_horiz, dates[i], 'SI', 'Diffuse Horizontal Radiation')) except OverflowError: # very small altitude values direct_norm_rad.append( DataPoint(0, dates[i], 'SI', 'Direct Normal Radiation')) diffuse_horiz_rad.append( DataPoint(0, dates[i], 'SI', 'Diffuse Horizontal Radiation')) else: direct_norm_rad.append( DataPoint(0, dates[i], 'SI', 'Direct Normal Radiation')) diffuse_horiz_rad.append( DataPoint(0, dates[i], 'SI', 'Diffuse Horizontal Radiation')) return cls(location, direct_norm_rad, diffuse_horiz_rad, timestep, is_leap_year)
# TODO: Split golbal into direct and diffuse using Perez method. # Right now, I use an old inaccurate method.
[docs] @classmethod def from_zhang_huang_solar_model(cls, location, cloud_cover, relative_humidity, dry_bulb_temperature, wind_speed, timestep=1, is_leap_year=False): """Create a wea object from climate data using the Zhang-Huang model. The Zhang-Huang solar model was developed to estimate solar radiation for weather stations that lack such values, which are typically colleted with a pyranometer. Using total cloud cover, dry-bulb temperature, relative humidity, and wind speed as inputs the Zhang-Huang estimates global horizontal radiation by means of a regression model across these variables. For more information on the Zhang-Huang model, see the EnergyPlus Engineering Reference: https://bigladdersoftware.com/epx/docs/8-7/engineering-reference/climate-calculations.html#zhang-huang-solar-model Args: location: Ladybug location object. cloud_cover: A list of annual float values between 0 and 1 that represent the fraction of the sky dome covered in clouds (0 = clear; 1 = completely overcast) cloud_cover: A list of annual float values between 0 and 1 that represent the fraction of the sky dome covered in clouds (0 = clear; 1 = completely overcast) relative_humidity: A list of annual float values between 0 and 100 that represent the relative humidity in percent. dry_bulb_temperature: A list of annual float values that represent the dry bulb temperature in degrees Celcius. wind_speed: A list of annual float values that represent the wind speed in meters per second. timestep: An optional integer to set the number of time steps per hour. Default is 1 for one value per hour. is_leap_year: A boolean to indicate if values are representing a leap year. Default is False. """ # check input data assert len(cloud_cover) == len(relative_humidity) == \ len(dry_bulb_temperature) == len(wind_speed), \ 'lengths of input climate data must match.' assert len(cloud_cover) / timestep == cls.day_count(is_leap_year), \ 'input climate data must be annual.' assert isinstance(timestep, int), 'timestep must be an' \ ' integer. Got {}'.format(type(timestep)) # solar model regression constants c0, c1, c2, c3, c4, c5, d_coeff, k_coeff = 0.5598, 0.4982, \ -0.6762, 0.02842, -0.00317, 0.014, -17.853, 0.843 # extraterrestrial solar constant (W/m2) irr0 = 1355 # initiate sunpath based on location sp = Sunpath.from_location(location) sp.is_leap_year = is_leap_year # calculate zhang-huang radiation direct_norm_rad, diffuse_horiz_rad = \ cls._get_empty_data_collections(location, timestep, is_leap_year) for count, t_date in enumerate(cls._get_datetimes(timestep, is_leap_year)): # start assuming night time glob_ir = 0 dir_ir = 0 diff_ir = 0 # calculate sun altitude sun = sp.calculate_sun_from_date_time(t_date) alt = sun.altitude if alt > 0: # get sin of the altitude sin_alt = math.sin(math.radians(alt)) # get the values at each timestep cc, rh, n_temp, n3_temp, w_spd = cloud_cover[count] / 10.0, \ relative_humidity[count], dry_bulb_temperature[count], \ dry_bulb_temperature[count - (3 * timestep)], wind_speed[count] # calculate zhang-huang global radiation glob_ir = ((irr0 * sin_alt * (c0 + (c1 * cc) + (c2 * cc**2) + (c3 * (n_temp - n3_temp)) + (c4 * rh) + (c5 * w_spd))) + d_coeff) / k_coeff if glob_ir < 0: glob_ir = 0 else: # calculate direct and diffuse solar k_t = glob_ir / (irr0 * sin_alt) k_tc = 0.4268 + (0.1934 * sin_alt) if k_t >= k_tc: k_ds = k_t - ((1.107 + (0.03569 * sin_alt) + (1.681 * sin_alt**2)) * (1 - k_t)**2) else: k_ds = (3.996 - (3.862 * sin_alt) + (1.540 * sin_alt**2)) * k_t**3 diff_ir = (irr0 * sin_alt * (k_t - k_ds)) / (1 - k_ds) dir_horiz_ir = (irr0 * sin_alt * k_ds * (1 - k_t)) / (1 - k_ds) dir_ir = dir_horiz_ir / math.sin(math.radians(alt)) direct_norm_rad.append(DataPoint( dir_ir, t_date, 'SI', 'Direct Normal Radiation')) diffuse_horiz_rad.append(DataPoint( diff_ir, t_date, 'SI', 'Diffuse Horizontal Radiation')) return cls(location, direct_norm_rad, diffuse_horiz_rad, timestep, is_leap_year)
@property def isWea(self): """Return True.""" return True @property def hoys(self): """Hours of the year in wea file.""" return tuple(data.datetime.hoy for data in self.direct_normal_radiation) @property def datetimes(self): """Datetimes in wea file.""" return tuple(data.datetime for data in self.direct_normal_radiation) @property def timestep(self): """Return the timestep.""" return self._timestep @property def direct_normal_radiation(self): """Get or set the direct normal radiation.""" return self._direct_normal_radiation @direct_normal_radiation.setter def direct_normal_radiation(self, data): assert len(data) / self.timestep == self.day_count(self.is_leap_year), \ 'direct_normal_radiation data must be annual.' assert isinstance(data, DataCollection), \ 'direct_normal_radiation data must be a data collection.' self._direct_normal_radiation = data self._is_global_computed = False @property def diffuse_horizontal_radiation(self): """Get or set the diffuse horizontal radiation.""" return self._diffuse_horizontal_radiation @diffuse_horizontal_radiation.setter def diffuse_horizontal_radiation(self, data): assert len(data) / self.timestep == self.day_count(self.is_leap_year), \ 'diffuse_horizontal_radiation data must be annual.' assert isinstance(data, DataCollection), \ 'diffuse_horizontal_radiation data must be a data collection.' self._diffuse_horizontal_radiation = data self._is_global_computed = False @property def global_horizontal_radiation(self): """Returns the global horizontal radiation at each timestep.""" analysis_period = AnalysisPeriod(timestep=self.timestep, is_leap_year=self.is_leap_year) header_ghr = Header(location=self.location, analysis_period=analysis_period, data_type='Global Horizontal Radiation', unit='Wh/m2') global_horizontal_rad = DataCollection(header=header_ghr) is_leap_year = self.is_leap_year sp = Sunpath.from_location(self.location) sp.is_leap_year = is_leap_year for dnr, dhr in zip(self.direct_normal_radiation, self.diffuse_horizontal_radiation): sun = sp.calculate_sun_from_date_time(dnr.datetime) glob_h = dhr + dnr * math.sin(math.radians(sun.altitude)) global_horizontal_rad.append( DataPoint(glob_h, dnr.datetime, 'SI', 'Global Horizontal Radiation')) return global_horizontal_rad @property def direct_horizontal_radiation(self): """Returns the direct radiation on a horizontal surface at each timestep. Note that this is different from the direct_normal_radiation needed to construct a Wea, which is NORMAL and not HORIZONTAL.""" analysis_period = AnalysisPeriod(timestep=self.timestep, is_leap_year=self.is_leap_year) header_dhr = Header(location=self.location, analysis_period=analysis_period, data_type='Direct Horizontal Radiation', unit='Wh/m2') direct_horizontal_rad = DataCollection(header=header_dhr) is_leap_year = self.is_leap_year sp = Sunpath.from_location(self.location) sp.is_leap_year = is_leap_year for dnr in self.direct_normal_radiation: sun = sp.calculate_sun_from_date_time(dnr.datetime) dir_h = dnr * math.sin(math.radians(sun.altitude)) direct_horizontal_rad.append( DataPoint(dir_h, dnr.datetime, 'SI', 'Direct Horizontal Radiation')) return direct_horizontal_rad @property def is_leap_year(self): """Return the timestep.""" return self._is_leap_year
[docs] @staticmethod def day_count(is_leap_year): """Number of days in this Wea file. Keep in mind that wea file is an annual file but this value will be different for a leap year """ return 8760 + 24 if is_leap_year else 8760
@staticmethod def _get_datetimes(timestep, is_leap_year): """List of datetimes based on timestep. This method should only be used for classmethods. For datetimes use datetiems or hoys methods. """ day_count = 8760 + 24 if is_leap_year else 8760 adjust_time = 30 if timestep == 1 else 0 return tuple( DateTime.from_moy(60.0 * count / timestep + adjust_time, is_leap_year) for count in xrange(day_count * timestep) ) @staticmethod def _get_empty_data_collections(location, timestep, is_leap_year): """Return two empty data collection. Direct Normal Radiation, Diffuse Horizontal Radiation """ analysis_period = AnalysisPeriod(timestep=timestep, is_leap_year=is_leap_year) header_dnr = Header(location=location, analysis_period=analysis_period, data_type='Direct Normal Radiation', unit='Wh/m2') direct_norm_rad = DataCollection(header=header_dnr) header_dhr = Header(location=location, analysis_period=analysis_period, data_type='Diffuse Horizontal Radiation', unit='Wh/m2') diffuse_horiz_rad = DataCollection(header=header_dhr) return direct_norm_rad, diffuse_horiz_rad
[docs] def get_radiation_values(self, month, day, hour): """Get direct and diffuse radiation values for a point in time.""" dt = DateTime(month, day, hour, leap_year=self.is_leap_year) count = int(dt.hoy * self.timestep) return self.direct_normal_radiation[count], \ self.diffuse_horizontal_radiation[count]
[docs] def get_radiation_values_for_hoy(self, hoy): """Get direct and diffuse radiation values for an hoy.""" count = int(hoy * self.timestep) return self.direct_normal_radiation[count], \ self.diffuse_horizontal_radiation[count]
[docs] def directional_radiation(self, altitude=90, azimuth=180, ground_reflectance=0.2, isotrophic=True): """Returns the radiation components facing a given altitude and azimuth. This method computes unobstructed solar flux facing a given altitude and azimuth. The default is set to return the golbal horizontal radiation, assuming an altitude facing straight up (90 degrees). Args: altitude: A number between -90 and 90 that represents the altitude at which radiation is being evaluated in degrees. azimuth: A number between 0 and 360 that represents the azimuth at wich radiation is being evaluated in degrees. ground_reflectance: A number between 0 and 1 that represents the reflectance of the ground. Default is set to 0.2. isotrophic: A boolean value that sets whether an istotrophic sky is used (as opposed to an anisotrophic sky). An isotrophic sky assummes an even distribution of diffuse radiation across the sky while an anisotrophic sky places more diffuse radiation near the solar disc. Default is set to True for isotrophic Returns: total_radiation: A list of total solar radiation at each timestep. direct_radiation: A list of direct solar radiation at each timestep. diffuse_radiation: A list of diffuse sky solar radiation at each timestep. reflected_radiation: A list of ground reflected solar radiation at each timestep. """ # function to convert polar coordinates to xyz. def pol2cart(phi, theta): mult = math.cos(theta) x = math.sin(phi) * mult y = math.cos(phi) * mult z = math.sin(theta) return Vector3(x, y, z) # convert the altitude and azimuth to a normal vector normal = pol2cart(math.radians(azimuth), math.radians(altitude)) # create sunpath and get altitude at every timestep of the year direct_radiation = [] diffuse_radiation = [] reflected_radiation = [] total_radiation = [] sp = Sunpath.from_location(self.location) sp.is_leap_year = self.is_leap_year for dnr, dhr in zip(self.direct_normal_radiation, self.diffuse_horizontal_radiation): dt = dnr.datetime sun = sp.calculate_sun_from_date_time(dt) sun_vec = pol2cart(math.radians(sun.azimuth), math.radians(sun.altitude)) vec_angle = sun_vec.angle(normal) # direct radiation on surface srf_dir = 0 if sun.altitude > 0 and vec_angle < math.pi / 2: srf_dir = dnr * math.cos(vec_angle) # diffuse radiation on surface if isotrophic is True: srf_dif = dhr * ((math.sin(math.radians(altitude)) / 2) + 0.5) else: y = max(0.45, 0.55 + (0.437 * math.cos(vec_angle)) + 0.313 * math.cos(vec_angle) * 0.313 * math.cos(vec_angle)) srf_dif = self.dhr * (y * ( math.sin(math.radians(abs(90 - altitude)))) + math.cos(math.radians(abs(90 - altitude)))) # reflected radiation on surface. e_glob = dhr + dnr * math.cos(math.radians(90 - sun.altitude)) srf_ref = e_glob * ground_reflectance * (0.5 - (math.sin( math.radians(altitude)) / 2)) # add it all together direct_radiation.append( DataPoint(srf_dir, dt, 'SI', 'Radiation')) diffuse_radiation.append( DataPoint(srf_dif, dt, 'SI', 'Radiation')) reflected_radiation.append( DataPoint(srf_ref, dt, 'SI', 'Radiation')) total_radiation.append( DataPoint(srf_dir + srf_dif + srf_ref, dt, 'SI', 'Radiation')) return total_radiation, direct_radiation, \ diffuse_radiation, reflected_radiation
@property def header(self): """Wea header.""" return "place %s\n" % self.location.city + \ "latitude %.2f\n" % self.location.latitude + \ "longitude %.2f\n" % -self.location.longitude + \ "time_zone %d\n" % (-self.location.time_zone * 15) + \ "site_elevation %.1f\n" % self.location.elevation + \ "weather_data_file_units 1\n"
[docs] def to_json(self): """Write Wea to json file { "location": {} , // ladybug location schema "direct_normal_radiation": (), // Tuple of hourly direct normal radiation "diffuse_horizontal_radiation": (), // Tuple of hourly diffuse horizontal radiation "timestep": float //timestep between measurements, default is 1 } """ return { 'location': self.location.to_json(), 'direct_normal_radiation': self.direct_normal_radiation.to_json(), 'diffuse_horizontal_radiation': self.diffuse_horizontal_radiation.to_json(), 'timestep': self.timestep, 'is_leap_year': self.is_leap_year }
[docs] def write(self, file_path, hoys=None, write_hours=False): """Write the wea file. WEA carries radiation values from epw and is what gendaymtx uses to generate the sky. """ # generate hoys in wea file based on timestep full_wea = False if not hoys: hoys = self.hoys full_wea = True with open(file_path, "wb") as wea_file: # write header wea_file.write(self.header) if full_wea: # there is no input user for hoys, write it for all the hours # write values for dir_rad, dif_rad in zip(self.direct_normal_radiation, self.diffuse_horizontal_radiation): dt = dir_rad.datetime line = "%d %d %.3f %d %d\n" \ % (dt.month, dt.day, dt.float_hour, dir_rad, dif_rad) wea_file.write(line) else: # output wea based on user request for hoy in hoys: try: dir_rad, dif_rad = self.get_radiation_values_for_hoy(hoy) except IndexError: print('Warn: Wea data for {} is not available!'.format(dt)) continue dt = dir_rad.datetime line = "%d %d %.3f %d %d\n" \ % (dt.month, dt.day, dt.float_hour, dir_rad, dif_rad) wea_file.write(line) if write_hours: with open(file_path[:-4] + '.hrs', 'wb') as outf: outf.write(','.join(str(h) for h in hoys) + '\n') return file_path
[docs] def ToString(self): """Overwrite .NET ToString.""" return self.__repr__()
def __repr__(self): """epw file representation.""" return "WEA [%s]" % self.location.city