Source code for honeybee_plus.radiance.recipe.daylightcoeff.gridbased

"""Radiance Daylight Coefficient Grid-Based Analysis Recipe."""
from ..recipeutil import write_extra_files
from ..recipedcutil import write_rad_files_daylight_coeff, get_commands_sky
from ..recipedcutil import get_commands_scene_daylight_coeff
from ..recipedcutil import get_commands_w_groups_daylight_coeff
from .._gridbasedbase import GenericGridBased
from ..parameters import get_radiance_parameters_grid_based
from ...sky.skymatrix import SkyMatrix
from ....futil import write_to_file
from ...analysisgrid import AnalysisGrid
from ...parameters.rfluxmtx import RfluxmtxParameters
from ....hbsurface import HBSurface

import os


[docs]class DaylightCoeffGridBased(GenericGridBased): """Grid based daylight coefficient analysis recipe. Attributes: sky_mtx: A radiance SkyMatrix or SkyVector. For an SkyMatrix the analysis will be ran for the analysis period. analysis_grids: A list of Honeybee analysis grids. Daylight metrics will be calculated for each analysisGrid separately. simulation_type: 0: Illuminance(lux), 1: Radiation (kWh), 2: Luminance (Candela) (Default: 0) radiance_parameters: Radiance parameters for this analysis. Parameters should be an instance of RfluxmtxParameters. hb_objects: An optional list of Honeybee surfaces or zones (Default: None). sub_folder: Analysis subfolder for this recipe. (Default: "daylightcoeff"). Usage: # initiate analysis_recipe analysis_recipe = DaylightCoeffGridBased( sky_mtx, analysis_grids, rad_parameters ) # add honeybee object analysis_recipe.hb_objects = HBObjs # write analysis files to local drive commandsFile = analysis_recipe.write(_folder_, _name_) # run the analysis analysis_recipe.run(commandsFile) # get the results print(analysis_recipe.results()) """ def __init__(self, sky_mtx, analysis_grids, simulation_type=0, radiance_parameters=None, reuse_daylight_mtx=True, hb_objects=None, sub_folder="gridbased_daylightcoeff"): """Create an annual recipe.""" GenericGridBased.__init__( self, analysis_grids, hb_objects, sub_folder ) self.sky_matrix = sky_mtx self.radiance_parameters = radiance_parameters self.simulation_type = simulation_type """Simulation type: 0: Illuminance(lux), 1: Radiation (kWh), 2: Luminance (Candela) (Default: 2) """ self.reuse_daylight_mtx = reuse_daylight_mtx
[docs] @classmethod def from_json(cls, rec_json): """Create daylight coefficient recipe from JSON file { "id": "daylight_coeff", "type": "gridbased", "sky_mtx": {}, // sky matrix json file "analysis_grids": [], // list of analysis grids "surfaces": [], // list of honeybee surfaces "simulation_type": int // value between 0-2 "rad_parameters": {} // radiance gridbased parameters json file } """ sky_mtx = SkyMatrix.from_json(rec_json["sky_mtx"]) analysis_grids = \ tuple(AnalysisGrid.from_json(ag) for ag in rec_json["analysis_grids"]) hb_objects = tuple(HBSurface.from_json(srf) for srf in rec_json["surfaces"]) rad_parameters = RfluxmtxParameters.from_json(rec_json["rad_parameters"]) simulation_type = rec_json["simulation_type"] return cls(sky_mtx=sky_mtx, analysis_grids=analysis_grids, radiance_parameters=rad_parameters, hb_objects=hb_objects, simulation_type=simulation_type)
[docs] @classmethod def from_weather_file_points_and_vectors( cls, epw_file, point_groups, vector_groups=None, sky_density=1, simulation_type=0, radiance_parameters=None, reuse_daylight_mtx=True, hb_objects=None, sub_folder="gridbased_daylightcoeff"): """Create grid based daylight coefficient from weather file, points and vectors. Args: epw_file: An EnergyPlus weather file. point_groups: A list of (x, y, z) test points or lists of (x, y, z) test points. Each list of test points will be converted to a TestPointGroup. If testPts is a single flattened list only one TestPointGroup will be created. vector_groups: An optional list of (x, y, z) vectors. Each vector represents direction of corresponding point in testPts. If the vector is not provided (0, 0, 1) will be assigned. sky_density: A positive intger for sky density. 1: Tregenza Sky, 2: Reinhart Sky, etc. (Default: 1) hb_objects: An optional list of Honeybee surfaces or zones (Default: None). sub_folder: Analysis subfolder for this recipe. (Default: "sunlighthours") """ assert epw_file.lower().endswith('.epw'), \ ValueError('{} is not a an EnergyPlus weather file.'.format(epw_file)) sky_mtx = SkyMatrix.from_epw_file(epw_file, sky_density) analysis_grids = cls.analysis_grids_from_points_and_vectors(point_groups, vector_groups) return cls(sky_mtx, analysis_grids, simulation_type, radiance_parameters, reuse_daylight_mtx, hb_objects, sub_folder)
[docs] @classmethod def from_points_file(cls, epw_file, points_file, sky_density=1, simulation_type=0, radiance_parameters=None, reuse_daylight_mtx=True, hb_objects=None, sub_folder="gridbased_daylightcoeff"): """Create grid based daylight coefficient recipe from points file.""" try: with open(points_file, "rb") as inf: point_groups = tuple(line.split()[:3] for line in inf.readline()) vector_groups = tuple(line.split()[3:] for line in inf.readline()) except Exception: raise ValueError("Couldn't import points from {}".format(points_file)) return cls.from_weather_file_points_and_vectors( epw_file, point_groups, vector_groups, sky_density, simulation_type, radiance_parameters, reuse_daylight_mtx, hb_objects, sub_folder)
@property def simulation_type(self): """Get/set simulation Type. 0: Illuminance(lux), 1: Radiation (kWh), 2: Luminance (Candela) (Default: 0) """ return self._simType @simulation_type.setter def simulation_type(self, value): try: value = int(value) except TypeError: value = 0 assert 0 <= value <= 2, \ "Simulation type should be between 0-2. Current value: {}".format(value) # If this is a radiation analysis make sure the sky is climate-based if value == 1: assert self.sky_matrix.is_climate_based, \ "The sky for radition analysis should be climate-based." self._simType = value self.sky_matrix.sky_type = value if self._simType < 2: self.radiance_parameters.irradiance_calc = True else: self.radiance_parameters.irradiance_calc = None if hasattr(self, 'view_mtx_parameters'): if self._simType < 2: self.view_mtx_parameters.irradiance_calc = True else: self.view_mtx_parameters.irradiance_calc = None if hasattr(self, 'daylight_mtx_parameters'): if self._simType < 2: self.daylight_mtx_parameters.irradiance_calc = True else: self.daylight_mtx_parameters.irradiance_calc = None @property def sky_matrix(self): """Get and set sky definition.""" return self._sky_matrix @sky_matrix.setter def sky_matrix(self, new_sky): assert hasattr(new_sky, 'isRadianceSky'), \ '%s is not a valid Honeybee sky.' % type(new_sky) assert not new_sky.is_point_in_time, \ TypeError('Sky for daylight coefficient recipe must be a sky matrix.') self._sky_matrix = new_sky.duplicate() @property def radiance_parameters(self): """Radiance parameters for annual analysis.""" return self._radiance_parameters @radiance_parameters.setter def radiance_parameters(self, par): if not par: # set RfluxmtxParameters as default radiance parameter for annual analysis par = get_radiance_parameters_grid_based(0, 1).dmtx assert hasattr(par, 'isRfluxmtxParameters'), \ TypeError('Expected RfluxmtxParameters not {}'.format(type(par))) self._radiance_parameters = par @property def sky_density(self): """Radiance sky type e.g. r1, r2, r4.""" return "r{}".format(self.sky_matrix.sky_density) @property def total_runs_count(self): """Number of total runs for all window groups and states.""" return sum(wg.state_count for wg in self.window_groups) + 1 # 1 for base case
[docs] def preproc_commands(self): """Add echo in front of comments in batch file comments.""" cmd = [c for c in self._commands if c] cmd = ['echo ' + c if c[:2] == '::' else c for c in cmd] return ['@echo off'] + cmd
def _add_commands(self, skycommands, commands): """Check if the commands should be added to self._commands.""" if self.reuse_daylight_mtx: if not skycommands: for f in self._result_files: if not os.path.isfile(f): self._commands.extend(commands) break else: # there are changes in the sky. # matrices multiplication needs to be recalculated. self._commands.extend(commands) else: # there are changes in the sky. # matrices multiplication needs to be recalculated. self._commands.extend(commands)
[docs] def to_json(self): """Create daylight coefficient JSON file { "id": "daylight_coeff", "type": "gridbased", "sky_mtx": {}, // sky matrix json file "analysis_grids": [], // list of analysis grids "surfaces": [], // list of honeybee surfaces "simulation_type": int // value between 0-2 "rad_parameters": {} // radiance gridbased parameters json file } """ return { "id": "daylight_coeff", "type": "gridbased", "sky_mtx": self.sky_matrix.to_json(), "analysis_grids": [ag.to_json() for ag in self.analysis_grids], "surfaces": [srf.to_json() for srf in self.hb_objects], "simulation_type": self.simulation_type, "rad_parameters": self.radiance_parameters.to_json() }
[docs] def write(self, target_folder, project_name='untitled', header=True, transpose=False): """Write analysis files to target folder. Args: target_folder: Path to parent folder. Files will be created under target_folder/gridbased. use self.sub_folder to change subfolder name. project_name: Name of this project as a string. header: A boolean to include the header lines in commands.bat. header includes PATH and cd toFolder Returns: Full path to command.bat """ # 0.prepare target folder # create main folder target_folder/project_name self._commands = [] self._result_files = [] project_folder = \ super(GenericGridBased, self).write_content( target_folder, project_name, False, subfolders=['tmp', 'result/matrix'] ) # write geometry and material files opqfiles, glzfiles, wgsfiles = write_rad_files_daylight_coeff( project_folder + '/scene', project_name, self.opaque_rad_file, self.glazing_rad_file, self.window_groups_rad_files ) # additional radiance files added to the recipe as scene extrafiles = write_extra_files(self.scene, project_folder + '/scene', True) # 0.write points points_file = self.write_analysis_grids(project_folder, project_name) # 2.write batch file if header: self._commands.append(self.header(project_folder)) # # 2.1.Create sky matrix. # # 2.2. Create sun matrix skycommands, skyfiles = get_commands_sky(project_folder, self.sky_matrix, reuse=True) self._commands.extend(skycommands) # for each window group - calculate total, direct and direct-analemma results # calculate the contribution of glazing if any with all window groups blacked inputfiles = opqfiles, glzfiles, wgsfiles, extrafiles commands, results = get_commands_scene_daylight_coeff( project_name, self.sky_matrix.sky_density, project_folder, skyfiles, inputfiles, points_file, self.total_point_count, self.radiance_parameters, self.reuse_daylight_mtx, self.total_runs_count, transpose=transpose) self._result_files.extend( os.path.join(project_folder, str(result)) for result in results ) self._add_commands(skycommands, commands) if self.window_groups: # calculate the contribution for all window groups commands, results = get_commands_w_groups_daylight_coeff( project_name, self.sky_matrix.sky_density, project_folder, self.window_groups, skyfiles, inputfiles, points_file, self.total_point_count, self.radiance_parameters, self.reuse_daylight_mtx, self.total_runs_count, transpose=transpose) self._add_commands(skycommands, commands) self._result_files.extend( os.path.join(project_folder, str(result)) for result in results ) # # 2.5 write batch file batch_file = os.path.join(project_folder, 'commands.bat') # add echo to commands and write them to file write_to_file(batch_file, '\n'.join(self.preproc_commands())) return batch_file
[docs] def results(self): """Return results for this analysis.""" assert self._isCalculated, \ "You haven't run the Recipe yet. Use self.run " + \ "to run the analysis before loading the results." print('Unloading the current values from the analysis grids.') for ag in self.analysis_grids: ag.unload() # results are merged as a single file for rf in self._result_files: fn = os.path.split(rf)[-1][:-4].split("..") source = fn[-2] state = fn[-1] folder, name = os.path.split(rf) df = os.path.join(folder, 'sun..%s' % name) if self.simulation_type == 1: # for grid-based radiation divide values by 179 # and also divide by timestep to adjust the values for each timestep # to convert radiation rate to cumulative radiation in that hour. mode = 179.0 * self.sky_matrix.wea.timestep else: mode = 0 start_line = 0 for count, analysisGrid in enumerate(self.analysis_grids): if count: start_line += len(self.analysis_grids[count - 1]) if not os.path.exists(df): print('\nloading the results for {} AnalysisGrid form {}::{}\n{}\n' .format(analysisGrid.name, source, state, rf)) # total value only analysisGrid.set_values_from_file( rf, self.sky_matrix.hoys, source, state, start_line=start_line, header=True, check_point_count=False, mode=mode ) else: # total and direct values print( '\nloading total and direct results for {} AnalysisGrid' ' from {}::{}\n{}\n{}\n'.format( analysisGrid.name, source, state, rf, df)) analysisGrid.set_coupled_values_from_file( rf, df, self.sky_matrix.hoys, source, state, start_line=start_line, header=True, check_point_count=False, mode=mode ) return self.analysis_grids