Source code for honeybee_plus.radiance.sky.sunmatrix

from ._skyBase import RadianceSky
from .gendaylit import gendaylit
from .analemma import AnalemmaReversed

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

import os

try:
    from itertools import izip as zip
except ImportError:
    pass


[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. A SunMatrix is climate-based and is generated based on radiation values from wea or epw file. It is useful to calculate accurate direct sunlight for an annual study and is usually used in combination with Analemma. See usage for a sample use case. 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_plus.radiance.sky.sunmatrix import SunMatrix working_dir = "." epwfile = r"./USA_CA_San.Francisco.Intl.AP.724940_TMY3.epw" sunmtx = sun_matrix.from_epw_file(epwfile, north=20) # write SunMatrix file sunmtx.execute(working_dir) analemma = sun_matrix.analemma(north=20) # write analemma analemma.execute(working_dir) ... """ def __init__(self, location, solar_values, sun_up_hours, hoys): """ Args: location: Location data as a ladybug Location object. Location data will only be used to create the header. solar_values: A list of solar i/rradiance values for every sun up hour. sun_up_hours: A list of hoys for hours that sun is not below the horizon. hoys: The list of total hours to be included in SunMatrix. List of hours can be subhourly and doesn't need to be continuous but it must include all the hours in sun_up_hours. """ RadianceSky.__init__(self) self._location = location self._sun_up_hours = sun_up_hours self._solar_values = solar_values self._hoys = hoys assert len(sun_up_hours) == len(solar_values), \ 'Number of sun_up_hours (%d) is not equal to number of solar_values (%d)' % \ (len(sun_up_hours), len(solar_values)) # ensure all sun up hours are included in hoys indices = [] for h in sun_up_hours: try: indices.append(hoys.index(h)) except ValueError: raise ValueError('Hour {} is not included in hoys.'.format(h)) # create solar valus for all hoys # create place holder total_solar_values = [['0 0 0'] * len(hoys) for sv in sun_up_hours] # replace the solar value for each sun up hour for count, (idx, sun_value) in enumerate(zip(indices, solar_values)): total_solar_values[count][idx] = '{0} {0} {0}'.format(sun_value) self._total_solar_values = total_solar_values
[docs] @classmethod def from_wea(cls, wea, north=0, hoys=None, output_type=0, is_leap_year=False): """Create sun matrix. 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. """ output_type = output_type or 0 # set default to 0 for visible radiation hoys = hoys or wea.hoys if not hoys and wea.timestep == 1: # adjut for half an hour so all the annual metric methods work for now # this is a design issue in Honeybee and should be fixed by removing # defulting values to range(8760) hoys = [hour - 0.5 for hour in wea.hoys] solar_values, sun_up_hours = cls._calculate_solar_values(wea, hoys, output_type, north, is_leap_year) return cls(wea.location, solar_values, sun_up_hours, hoys)
[docs] @classmethod def from_epw_file(cls, epw_file, north=0, hoys=None, output_type=0): """Create sun matrix from an epw file.""" return cls.from_wea(Wea.from_epw_file(epw_file), north, hoys, output_type)
[docs] @classmethod def from_json(cls, inp): """Create a SunMatrix from a dictionary.""" keys = ('location', 'solar_values', 'sun_up_hours', 'hoys') for key in keys: assert key in inp, '%s is missing from input dictionary' % key location = Location.from_json(inp['location']) solar_values = inp['solar_values'] sun_up_hours = inp['sun_up_hours'] hoys = inp['hoys'] return cls(location, solar_values, sun_up_hours, hoys)
@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 sunmtx_file(self): """Sun matrix file.""" return 'sunmtx.smx' @property def location(self): """SunMatrix location.""" return self._location @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.""" return self._sun_up_hours @property def hoys(self): """List of all hours in SunMatrix as hours of the year.""" return self._hoys @property def output_header(self): """Sun matrix file header output.""" # Start creating header for the sun matrix. latitude, longitude = self.location.latitude, self.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), len(self.hoys) ) return file_header
[docs] def analemma(self, north=0, is_leap_year=False): """Get an Analemma based on this SunMatrix. Analemma is a static representation of SunMatrix. You can use Analemma to generate two files which works hand in hand with SunMatrix for annual simulation. 1. *.ann file which includes sun geometries and materials. 2. *.mod file includes list of modifiers that are included in *.ann file. """ return AnalemmaReversed.from_location_sun_up_hours( self.location, self.sun_up_hours, north, is_leap_year)
@staticmethod def _calculate_solar_values(wea, hoys, output_type, north=0, is_leap_year=False): """Calculate solar values for requested hours of the year. This method is called everytime that output type is set. """ month_date_time = (DateTime.from_hoy(idx, is_leap_year) for idx in hoys) sp = Sunpath.from_location(wea.location, north) sp.is_leap_year = is_leap_year solar_values = [] sun_up_hours = [] # use gendaylit to calculate radiation values for each hour. print('Calculating solar values...') for timecount, dt in enumerate(month_date_time): month, day, hour = dt.month, dt.day, dt.float_hour sun = sp.calculate_sun(month, day, hour) if sun.altitude < 0: continue else: dnr, dhr = wea.get_irradiance_value(month, day, hour) if dnr == 0: solarradiance = 0 else: solarradiance = \ int(gendaylit(sun.altitude, month, day, hour, dnr, dhr, output_type)) solar_values.append(solarradiance) # keep the number of hour relative to hoys in this sun matrix sun_up_hours.append(dt.hoy) return solar_values, sun_up_hours
[docs] def execute(self, working_dir): """Generate sun matrix. Args: working_dir: Folder to execute and write the output. Returns: Full path to sun_matrix. """ # annual sun matrix mfp = os.path.normpath(os.path.join(working_dir, self.sunmtx_file)) sun_count = len(self.sun_up_hours) 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 sun_rad_list in self._total_solar_values: sunmtx.write('\n'.join(sun_rad_list) + '\n\n') sunmtx.write('\n') return mfp
[docs] def duplicate(self): """Duplicate this class.""" return SunMatrix(self.location, self.solar_values, self.sun_up_hours, self.hoys)
[docs] def to_rad_string(self, working_dir, write_hours=False): """Get the radiance command line as a string.""" raise AttributeError( 'SunMatrix does not have a single line command. Try execute method.' )
[docs] def to_json(self): return { 'location': self.location, 'solar_values': self.solar_values, 'sun_up_hours': self.sun_up_hours, 'hoys': self.hoys }
[docs] def ToString(self): """Overwrite .NET ToString method.""" return self.__repr__()
def __repr__(self): """Sky representation.""" return 'SunMatrix: #%d' % len(self.sun_up_hours)