Source code for honeybee_radiance_postprocess.dynamic

"""Post-processing classes for dynamic schedules."""
import json
import os
import sys
from itertools import islice, cycle

from honeybee.config import folders


[docs]class ApertureGroupSchedule(object): """ApertureGroupSchedule. This class contains the dynamic states schedule of a single ApertureGroup. Args: identifier: Identifier of the ApertureGroup. schedule: A list or tuple of integer values. Properties: * identifier * schedule * is_static """ __slots__ = ('_identifier', '_schedule', '_is_static') def __init__(self, identifier, schedule, is_static=None): """Initialize ApertureGroupSchedule.""" self._identifier = identifier self.schedule = schedule self.is_static = is_static
[docs] @classmethod def from_dict(cls, data): """Initialize a ApertureGroupSchedule from a dictionary. Args: data: A dictionary representation of an ApertureGroupSchedule object. """ identifier = data['identifier'] schedule = data['schedule'] is_static = data['is_static'] if 'is_static' in data else None return cls(identifier, schedule, is_static)
@property def identifier(self): """Return identifier.""" return self._identifier @property def schedule(self): """Return ApertureGroup schedule.""" return self._schedule @schedule.setter def schedule(self, schedule): assert isinstance(schedule, (list, tuple)), \ ('Failed to add schedule. Received input of type: ' '%s. Expected input of type: list or tuple.' % type(schedule)) if isinstance(schedule, tuple): schedule = list(schedule) if len(schedule) < 8760: schedule = list(islice(cycle(schedule), 8760)) elif len(schedule) > 8760: error_message = ( 'The light path %s has %s values in ' 'its states schedule. Maximum allowed number of values ' 'is 8760.' % (self.identifier, len(schedule)) ) raise ValueError(error_message) self._schedule = schedule @property def is_static(self): """Return True if schedule is static.""" return self._is_static @is_static.setter def is_static(self, value): if value is not None: assert isinstance(value, bool) self._is_static = value else: if len(set(self.schedule)) == 1: self._is_static = True else: self._is_static = False
[docs] def to_dict(self): """Return ApertureGroupSchedule as a dictionary.""" base = {} base['identifier'] = self.identifier base['schedule'] = self.schedule base['is_static'] = self.is_static return base
[docs] def ToString(self): """Overwrite .NET ToString.""" return self.__repr__()
def __repr__(self): return '{}: {}'.format(self.__class__.__name__, self.identifier)
[docs]class DynamicSchedule(object): """DynamicSchedule. This class contains a single property (dynamic_schedule). This property is a dictionary where keys are ApertureGroup identifiers and the value for each key is the dynamic schedule for the ApertureGroup. Args: dynamic_schedule: A dictionary of ApertureGroup identifier and schedules. Properties: * dynamic_schedule """ __slots__ = ('_dynamic_schedule',) def __init__(self, dynamic_schedule = None): self.dynamic_schedule = dynamic_schedule
[docs] @classmethod def from_group_schedules(cls, group_schedules): """Initialize a DynamicSchedule from a list of ApertureGroupSchedules. The method will automatically sense if there are duplicated groups in the list and ensure the group schedule only appears once. Args: data: A dictionary representation of a DynamicSchedule objects. """ dyn_sch = cls() dyn_sch_ids = set() for _ap_group in group_schedules: assert isinstance(_ap_group, ApertureGroupSchedule), \ 'Expected Aperture Group Schedule. Got {}'.format(type(_ap_group)) if _ap_group.identifier not in dyn_sch_ids: dyn_sch_ids.add(_ap_group.identifier) dyn_sch.add_aperture_group_schedule(_ap_group) return dyn_sch
[docs] @classmethod def from_dict(cls, data): """Initialize a DynamicSchedule from a dictionary. Args: data: A dictionary representation of a DynamicSchedule objects. """ dynamic_schedule = {} for identifier, group in data.items(): dynamic_schedule[identifier] = ApertureGroupSchedule.from_dict(group) return cls(dynamic_schedule)
[docs] @classmethod def from_json(cls, json_file): """Initialize a DynamicSchedule from a JSON file. Args: json_file: Path to JSON file. """ assert os.path.isfile(json_file), 'Failed to find %s' % json_file if sys.version_info < (3, 0): with open(json_file) as inf: data = json.load(inf) else: with open(json_file, encoding='utf-8') as inf: data = json.load(inf) return cls.from_dict(data)
@property def dynamic_schedule(self): """Return dynamic schedule as a dictionary.""" return self._dynamic_schedule @dynamic_schedule.setter def dynamic_schedule(self, dynamic_schedule): if not dynamic_schedule: dynamic_schedule = {} assert isinstance(dynamic_schedule, dict), \ 'Expected dictionary. Got %s.' % type(dynamic_schedule) self._dynamic_schedule = dynamic_schedule
[docs] def add_aperture_group_schedule(self, aperture_group_schedule): """Add an ApertureGroupSchedule to the DynamicSchedule instance. Args: aperture_group_schedule: An ApertureGroupSchedule object. """ assert isinstance(aperture_group_schedule, ApertureGroupSchedule), \ ('Failed to add ApertureGroupSchedule. Received input of type: ' '%s. Expected input of type: ApertureGroupSchedule.' \ % type(aperture_group_schedule)) identifier = aperture_group_schedule.identifier self.dynamic_schedule[identifier] = aperture_group_schedule
[docs] def filter_by_identifiers(self, identifiers): """Filter the DynamicSchedule by identifiers. This method returns a filtered DynamicSchedule object. Args: identifiers: A list of identifiers. Returns: A filtered DynamicSchedule object. """ filter_dyn_sch = DynamicSchedule() for identifier in identifiers: if identifier in self.dynamic_schedule: filter_dyn_sch.add_aperture_group_schedule( self.dynamic_schedule[identifier] ) else: filter_dyn_sch.add_aperture_group_schedule( ApertureGroupSchedule(identifier, [0]) ) return filter_dyn_sch
[docs] def to_dict(self, simplified=False): """Return DynamicSchedule as a dictionary.""" base = {} for identifier, group in self.dynamic_schedule.items(): if not simplified: base[identifier] = group.to_dict() else: base[identifier] = group.to_dict()['schedule'] return base
[docs] def to_json(self, folder=None, file_name=None, indent=None, simplified=False): """Write a DynamicSchedule to JSON. Args: folder: A text string for the directory where the JSON file will be written. If unspecified, the default simulation folder will be used. This is usually at "C:\\Users\\USERNAME\\simulation." file_name: _description_. Defaults to None. indent: A positive integer to set the indentation used in the resulting JSON file. (Default: None). Returns: json_file: Path to JSON file. """ # create dictionary of the DynamicSchedule dyn_sch_dict = self.to_dict(simplified=simplified) # set up name and folder for the JSON file_name = file_name if file_name else 'dynamic_schedule' if not file_name.endswith('.json'): file_name += '.json' folder = folder if folder is not None else folders.default_simulation_folder json_file = os.path.join(folder, file_name) # write JSON with open(json_file, 'w') as fp: json.dump(dyn_sch_dict, fp, indent=indent) return json_file
[docs] def duplicate(self): """Get a copy of this object.""" return self.__copy__()
[docs] def ToString(self): """Overwrite .NET ToString.""" return self.__repr__()
def __copy__(self): new_dyn_sch = DynamicSchedule(self.dynamic_schedule) return new_dyn_sch def __repr__(self): return '{}'.format(self.__class__.__name__)