Source code for honeybee.radiance.sky.sunmatrix

from ._skyBase import RadianceSky
from .gendaylit import gendaylit

from ladybug.dt import DateTime
from ladybug.sunpath import Sunpath
from ladybug.wea import Wea

import os


[docs]class SunMatrix(RadianceSky): """Radiance direct sun matrix. This class generates a sky matrix similar to gendaymtx -5 with the difference that unlike gendaymtx that uses the approximate position of the sun it uses the exact sun position for each timestep. Args: wea: An instance of ladybug Wea. north: An angle in degrees between 0-360 to indicate north direction (Default: 0). hoys: The list of hours for generating the sky matrix (Default: 0..8759) output_type: Specify 0 for visible radiation, 1 for total solar radiation. suffix: An optional suffix for sky name. The suffix will be added at the end of the standard name. Use this input to customize the new and avoid sky being overwritten by other skymatrix components. Attributes: solar_values: A list of radiance values for each sun_up_hour. These values can be visible or total solar radiation based on output_type input. sun_up_hours: List of sun up hours as hours of the year. Values will be between 0..8759. Usage: from honeybee.radiance.sky.sunmatrix import SunMatrix epwfile = r"./USA_CA_San.Francisco.Intl.AP.724940_TMY3.epw" sunmtx = sun_matrix.from_epw_file(epwfile, north=20) analemma, sunlist, sunmtxfile = sunmtx.execute('c:/ladybug') """ # TODO(mostapha) this is how the init should be: # def __init__(self, sun_vectors, solar_values=None, sun_up_hours=None, hoys=None, # suffix=None): def __init__(self, wea, north=0, hoys=None, output_type=0, suffix=None): """Create sun matrix.""" RadianceSky.__init__(self) self.wea = wea self.north = north self.hoys = hoys or range(8760) self._solar_values = [] # collection of indices for sun up hours from hoys self._sun_up_hours_indices = [] self.output_type = output_type or 0 # set default to 0 for visible radiation self.suffix = suffix or ''
[docs] @classmethod def from_epw_file(cls, epw_file, north=0, hoys=None, output_type=0, suffix=None): """Create sun matrix from an epw file.""" return cls(Wea.from_epw_file(epw_file), north, hoys, output_type, suffix)
@property def isSunMatrix(self): """Return True.""" return True @property def is_climate_based(self): """Return True if the sky is generated from values from weather file.""" return True @property def wea(self): """An instance of ladybug Wea.""" return self._wea @wea.setter def wea(self, w): assert hasattr(w, 'isWea'), \ TypeError('wea must be a WEA object not a {}'.format(type(w))) self._wea = w @property def north(self): """An angle in degrees between 0-360 to indicate north direction (Default: 0).""" return self._north @north.setter def north(self, n): north = n or 0 self._north = north @property def name(self): """Sky default name.""" return "sunmtx_{}_{}_{}_{}_{}{}".format( self.output_type_human_readable, self.wea.location.station_id, self.wea.location.latitude, self.wea.location.longitude, self.north, '_{}'.format(self.suffix) if self.suffix else '' ) @property def output_type(self): """Specify 0 for visible radiation, 1 for solar radiation and 2 for luminance.""" return self._output_type @output_type.setter def output_type(self, t): """Specify 0 for visible radiation, 1 for solar radiation and 2 for luminance.""" self._output_type = t % 3 self._calculate_solar_values() @property def output_type_human_readable(self): """Human readable output type.""" values = ('vis', 'sol', 'lum') return values[self.output_type] @property def analemmafile(self): """Analemma file.""" return self.name + '.ann' @property def sunlistfile(self): """Sun list file.""" return self.name + '.sun' @property def sunmtxfile(self): """Sun matrix file.""" return self.name + '.mtx' @property def solar_values(self): """List of radiance values for each sun_up_hour. These values can be visible or total solar radiation based on output_type input. """ return self._solar_values @property def sun_up_hours(self): """List of sun up hours as hours of the year. Values will be between 0..8759. """ return [self.hoys[i] for i in self._sun_up_hours_indices] @property def output_header(self): """Sun matrix file header output.""" # Start creating header for the sun matrix. latitude, longitude = self.wea.location.latitude, -self.wea.location.longitude file_header = '#?RADIANCE\n' \ 'Sun matrix created by Honeybee\n' \ 'LATLONG= %s %s\n' \ 'NROWS=%s\n' \ 'NCOLS=%s\n' \ 'NCOMP=3\n' \ 'FORMAT=ascii\n\n' % ( latitude, -longitude, len(self._sun_up_hours_indices), len(self.hoys) ) return file_header
[docs] def hours_match(self, hours_file): """Check if hours in the hours file matches the hours of wea.""" if not os.path.isfile(hours_file): return False with open(hours_file, 'r') as hrf: line = hrf.read() found = line == ','.join(str(h) for h in self.hoys) + '\n' if found: print('Reusing sun_matrix: {}.'.format(self.sunmtxfile)) return found
def _calculate_solar_values(self): """Calculate solar values for requested hours of the year. This method is called everytime that output type is set. """ wea = self.wea hoys_set = set(wea.hoys) output_type = self.output_type month_date_time = (DateTime.from_hoy(idx) for idx in self.hoys) sp = Sunpath.from_location(wea.location, self.north) # use gendaylit to calculate radiation values for each hour. print('Calculating solar values...') for timecount, dt in enumerate(month_date_time): if dt.hoy not in hoys_set: print('Warn: Wea data for {} is not available!'.format(dt)) continue month, day, hour = dt.month, dt.day, dt.float_hour dnr, dhr = wea.get_radiation_values(month, day, hour) sun = sp.calculate_sun(month, day, hour) if sun.altitude < 0: continue if dnr == 0: solarradiance = 0 else: solarradiance = \ int(gendaylit(sun.altitude, month, day, hour, dnr, dhr, output_type)) self._solar_values.append(solarradiance) # keep the number of hour relative to hoys in this sun matrix self._sun_up_hours_indices.append(timecount)
[docs] def execute(self, working_dir, reuse=True): """Generate sun matrix. Args: working_dir: Folder to execute and write the output. reuse: Reuse the matrix if already existed in the folder. Returns: Full path to analemma, sunlist and sun_matrix. """ mfp = os.path.join(working_dir, self.sunmtxfile) # annual sun matrix hrf = os.path.join(working_dir, self.name + '.hrs') # list of hours if reuse and self.hours_match(hrf) and os.path.isfile(mfp): return mfp with open(hrf, 'wb') as outf: outf.write(','.join(str(h) for h in self.hoys) + '\n') sun_count = len(self._sun_up_hours_indices) assert sun_count > 0, ValueError('There is 0 sun up hours!') print('# Number of sun up hours: %d' % sun_count) print('Writing sun matrix to {}'.format(mfp)) # Write the matrix to file. with open(mfp, 'w') as sunmtx: sunmtx.write(self.output_header) for idx, sun_value in enumerate(self.solar_values): sun_rad_list = ['0 0 0'] * len(self.hoys) sun_rad_list[self._sun_up_hours_indices[idx]] = \ '{0} {0} {0}'.format(sun_value) sunmtx.write('\n'.join(sun_rad_list) + '\n\n') sunmtx.write('\n') return mfp
[docs] def duplicate(self): """Duplicate this class.""" return SunMatrix(self.wea, self.north, self.hoys, self.output_type, self.suffix)
[docs] def to_rad_string(self, working_dir, write_hours=False): """Get the radiance command line as a string.""" raise AttributeError( 'sun_matrix does not have a single line command. Try execute method.' )
[docs] def ToString(self): """Overwrite .NET ToString method.""" return self.__repr__()
def __repr__(self): """Sky representation.""" return self.name