def to_radiance(self, output_type=1, wea_file=None, output_name=None): """Return Radiance command to generate the sky. Note that you need to write the wea to a file (in.wea) before running this command. Alternatively you can use write method which will write the wea data to a file. Args: output_type: An integer between 0 to 1 for output type. * 0 = output in W/m2/sr visible * 1 = output in W/m2/sr solar (default) wea_file: Path to wea file (default: in.wea). output_name: A name for output files (default: suns). """ output_type = typing.int_in_range(output_type, 0, 1, 'SunMatrix output type') wea_file = wea_file or 'in.wea' output_name = output_name or 'suns' if self.north == 0: command = 'gendaymtx -n -D {0}.mtx -M {0}.mod -O{1} {2}'.format( output_name, output_type, wea_file) else: command = 'gendaymtx -n -D {0}.mtx -M {0}.mod -O{1} -r {3} {2}'.format( output_name, output_type, wea_file, self.north) return command
def __init__(self, identifier, values, schedule_type_limit=None, timestep=1, start_date=Date(1, 1), placeholder_value=0, interpolate=False): """Initialize Schedule FixedInterval.""" self._locked = False # unlocked by default # set all of the properties that impact how many values can be assigned self._timestep = int_in_range(timestep, 1, 60, 'schedule timestep') assert self._timestep in self.VALIDTIMESTEPS, 'ScheduleFixedInterval timestep ' \ '"{}" is invalid. Must be one of the following:\n{}'.format( timestep, self.VALIDTIMESTEPS) start_date = Date(1, 1) if start_date is None else start_date assert isinstance(start_date, Date), 'Expected ladybug Date for ' \ 'ScheduleFixedInterval start_date. Got {}.'.format(type(start_date)) self._start_date = start_date # set the values and all properties that can be re-set self.identifier = identifier self._display_name = None self.values = values self.schedule_type_limit = schedule_type_limit self.placeholder_value = placeholder_value self.interpolate = interpolate
def __init__(self, name, values, schedule_type_limit=None, timestep=1, start_date=Date(1, 1), placeholder_value=0, interpolate=False): """Initialize Schedule FixedInterval. Args: name: Text string for the schedule name. Must be <= 100 characters. Can include spaces but special characters will be stripped out. values: A list of values occuring at a fixed interval over the simulation. Typically, this should be a list of 8760 values for each hour of the year but it can be a shorter list if you don't plan on using it in an annual simulation. In this case, the start_date should probably be different than the default 1 Jan (it should instead be the start date of your simulation). This list can also have a length much greater than 8760 if a timestep greater than 1 is used. schedule_type_limit: A ScheduleTypeLimit object that will be used to validate schedule values against upper/lower limits and assign units to the schedule values. If None, no validation will occur. timestep: An integer for the number of steps per hour that the input values correspond to. For example, if each value represents 30 minutes, the timestep is 2. For 15 minutes, it is 4. Default is 1, meaning each value represents a single hour. Must be one of the following: (1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60). start_date: A ladybug Date object to note when the the input values begin to take effect. Default is 1 Jan for a non-leap year. Note that this default usually should not be changed unless you plan to run a simulation that is much shorter than a year and/or you plan to run the simulation for a leap year. placeholder_value: A value that will be used for all times not covered by the input values. Typically, your simulation should not need to use this value if the input values completely cover the simulation period. However, a default value may still be necessary for EnergyPlus to run. Default: 0. interpolate: Boolean to note whether values in between intervals should be linearly interpolated or whether successive values should take effect immediately upon the beginning time corrsponding to them. Default: False """ self._locked = False # unlocked by default # set all of the properties that impact how many values can be assigned self._timestep = int_in_range(timestep, 1, 60, 'schedule timestep') assert self._timestep in self.VALIDTIMESTEPS, 'ScheduleFixedInterval timestep ' \ '"{}" is invalid. Must be one of the following:\n{}'.format( timestep, self.VALIDTIMESTEPS) assert isinstance(start_date, Date), 'Expected ladybug Date for ' \ 'ScheduleFixedInterval start_date. Got {}.'.format(type(start_date)) self._start_date = start_date # set the values and all properties that can be re-set self.name = name self.values = values self.schedule_type_limit = schedule_type_limit self.placeholder_value = placeholder_value self.interpolate = interpolate
def to_files(self, folder, count, base_name=None, mkdir=False): """Split this sensor grid and write them to several files. Args: folder: Target folder. count: Number of files. base_name: Optional text for a unique base_name for sensor files. (Default: self.display_name) mkdir: A boolean to indicate if the folder should be created in case it doesn't exist already (Default: False). Returns: A list of dicts containing the grid name, path to the grid and full path to the grid. """ count = typing.int_in_range(count, 1, input_name='file count') base_name = base_name or self.display_name if count == 1 or self.count == 0: name = '%s_0000' % base_name full_path = self.to_file(folder, name, mkdir) return [ {'name': name if not name.endswith('.pts') else name.replace('.pts', ''), 'path': name + '.pts' if not name.endswith('.pts') else name, 'full_path': full_path, 'count': self.count} ] # calculate sensor count in each file sc = int(round(self.count / count)) sensors = iter(self._sensors) for fc in range(count - 1): name = '%s_%04d.pts' % (base_name, fc) content = '\n'.join((next(sensors).to_radiance() for _ in range(sc))) futil.write_to_file_by_name(folder, name, content + '\n', mkdir) # write whatever is left to the last file name = '%s_%04d.pts' % (base_name, count - 1) content = '\n'.join((sensor.to_radiance() for sensor in sensors)) futil.write_to_file_by_name(folder, name, content + '\n', mkdir) grids_info = [] for c in range(count): name = '%s_%04d' % (base_name, c) path = '%s.pts' % name full_path = os.path.join(folder, path) grids_info.append({ 'name': name, 'path': path, 'full_path': full_path, 'count': sc }) # adjust the count for the last grid grids_info[-1]['count'] = self.count - sc * (count - 1) return grids_info
def to_radiance(self, output_type=0, wea_file=None, output_name=None, cumulative=False, components=0): """Return Radiance command to generate the sky. Note that you need to write the wea to a file (in.wea) before running this command. Alternatively you can use write method which will write the wea data to a file. Args: output_type: An integer between 0 to 1 for output type. * 0 = output in W/m2/sr visible (default) * 1 = output in W/m2/sr solar wea_file: Path to wea file (default: in.wea). output_name: A name for output files (default: sky_mtx). cumulative: A boolean to generate cumulative sky. This option is only available in Radiance 5.3 and higher versions (default: False). components: An integer between 0-2 to note the distribution of which components should be included. 0 might be used to include both sun and sky contribution. 1 may be used to produce a sun-only matrix, with no sky contributions. Alternatively, 2 may be used to exclude any sun component from the output. If there is a sun in the description, gendaymtx will include its contribution in the four nearest sky patches, distributing energy according to centroid proximity (default: 0). """ output_type = typing.int_in_range(output_type, 0, 1, 'SkyMatrix output type') wea_file = wea_file or 'in.wea' output_name = output_name or 'sky' options = ['-O{}'.format(output_type)] if self.density != 1: options.append('-m %d' % self.density) if self.north != 0: options.append('-r {}'.format(self.north)) if cumulative: options.append('-A') if components == 1: # sun-only options.append('-d') elif components == 2: # sky only options.append('-s') options.append(wea_file) # add all the other options here command = 'gendaymtx {0} > {1}.mtx'.format(' '.join(options), output_name) return command
def test_int_in_range(): """Test the float_in_range method.""" assert isinstance(int_in_range(2.0, 0, 10), int) assert isinstance(int_in_range(2, 0, 10), int) assert isinstance(int_in_range('2', 0, 10), int) with pytest.raises(AssertionError): assert isinstance(int_in_range(2, 0, 1), float) with pytest.raises(TypeError): assert isinstance(int_in_range('two', 0, 10), float) with pytest.raises(TypeError): assert isinstance(int_in_range([2], 0, 10), float) try: int_in_range(2, 0, 1, 'test number') except AssertionError as e: assert 'test number' in str(e)
def to_radiance(self, output_type=0): """Return Radiance description of the sky. Args: output_type: An integer between 0 to 2 for output type. * 0 = output in W/m2/sr visible (default) * 1 = output in W/m2/sr solar * 2 = output in lm/m2/sr luminance """ output = typing.int_in_range(output_type, 0, 2, 'Sky output type') command = '!gendaylit -ang %.6f %.6f -O %d -W %d %d -g %.3f' % ( self.altitude, self.azimuth - 180.0, output, self.direct_normal_irradiance, self._diffuse_horizontal_irradiance, self.ground_reflectance) return '%s\n\n%s\n\n%s\n' % (command, self.sky_hemisphere, self.ground_hemisphere)
def to_radiance(self, density=1): """Radiance definition for SkyDome. Args: density: Sky patch subdivision density. This values is similar to -m option in gendaymtx command. Default is 1 which means 145 sky patches and 1 patch for the ground. One can add to the resolution typically by factors of two (2, 4, 8, ...) which yields a higher resolution sky using the Reinhart patch subdivision For example, setting density to 4 yields a sky with 2305 patches plus one patch for the ground. """ density = typing.int_in_range(density, 1, input_name='Sky subdivision density') return '#@rfluxmtx h=u u=Y\n%s\n\n#@rfluxmtx h=r%d u=Y\n%s\n' % ( self.ground_hemisphere, density, self.sky_hemisphere)
def workers(self, value): self._workers = int_in_range(value, mi=1, input_name='recipe workers')
def density(self, value): typing.int_in_range(value, 1, input_name='SkyMatrix subdivision density') self._density = value
def end_month(self, value): if value == autocalculate: self._end_month = None else: self._end_month = \ int_in_range(value, 1, 12, 'end_month')
def values_at_timestep(self, timestep=1, start_date=None, end_date=None): """Get a list of sequential schedule values over the year at a given timestep. Note that there are two possible ways that these values can be mapped to corresponding times: * The EnergyPlus interpretation that uses "time until" * The Ladybug Tools interpretation that uses "time of beginning" The EnergyPlus interpretation should be used when aligning the schedule with EnergyPlus results while the Ladybug Tools interpretation should be used when aligning the schedule with ladybug DataCollections or other ladybug objects. See the ScheduleDay.values_at_timestep method documentation for a complete description of these two interpretations. Args: timestep: An integer for the number of steps per hour at which to return the resulting values. start_date: An optional ladybug Date object for when to start the list of values. Default: 1 Jan with a leap year equal to self.start_date. end_date: An optional ladybug Date object for when to end the list of values. Default: 31 Dec with a leap year equal to self.start_date. """ # ensure that the input start_date and end_date are valid if start_date is None: start_date = Date(1, 1, self.is_leap_year) else: if start_date.leap_year is not self.is_leap_year: start_date = Date(start_date.month, start_date.day, self.is_leap_year) if end_date is None: end_date = Date(12, 31, self.is_leap_year) else: if end_date.leap_year is not self.is_leap_year: end_date = Date(end_date.month, end_date.day, self.is_leap_year) assert start_date <= end_date, 'ScheduleFixedInterval values_at_timestep()' \ 'start_date must come before end_date. {} comes after {}.'.format( start_date, end_date) # convert the schedule's values to the desired timestep timestep = int_in_range(timestep, 1, 60, 'schedule timestep') assert timestep in self.VALIDTIMESTEPS, 'ScheduleFixedInterval timestep ' \ '"{}" is invalid. Must be one of the following:\n{}'.format( timestep, self.VALIDTIMESTEPS) if timestep == self.timestep: vals_at_step = list(self._values) elif timestep < self.timestep: assert self.timestep % timestep == 0, \ 'Schedule timestep({}) must be evenly divisible by target timestep({})' \ .format(self.timestep, timestep) vals_at_step = [] ind = 0 step_ratio = self.timestep / timestep for i in xrange(int(len(self._values) / step_ratio)): vals_at_step.append(self._values[int(ind)]) ind += step_ratio else: assert timestep % self.timestep == 0, \ 'Target timestep({}) must be evenly divisible by schedule timestep({})' \ .format(timestep, self.timestep) vals_at_step = [] if self.interpolate: data_len = len(self._values) for d in xrange(data_len): for _v in self._xxrange(self[d], self[(d + 1) % data_len], timestep): vals_at_step.append(_v) else: n_step = int(timestep / self.timestep) for val in self._values: for stp in xrange(n_step): vals_at_step.append(val) # build up the full list of values accounting for start and end dates end_dt = self.end_date_time if self.start_date.doy <= end_dt.doy: start_filler = [] end_filler = [] if start_date < self.start_date: num_vals = int( (self.start_date.doy - start_date.doy) * 24 * timestep) start_filler = [ self.placeholder_value for i in xrange(num_vals) ] elif start_date > self.start_date: start_i = int( (start_date.doy - self.start_date.doy) * 24 * timestep) vals_at_step = vals_at_step[start_i:] if ((end_dt.int_hoy + 1) / 24) < end_date.doy: num_vals = int((end_date.doy * 24 * timestep) - 1 - (end_dt.hoy * timestep)) end_filler = [self.placeholder_value for i in xrange(num_vals)] elif ((end_dt.int_hoy + 1) / 24) > end_date.doy: end_diff = int((end_dt.hoy * timestep) - (end_date.doy * 24 * timestep)) end_i = len(vals_at_step) - end_diff - 1 vals_at_step = vals_at_step[:end_i] return start_filler + vals_at_step + end_filler else: n_dpy = 365 if not self.is_leap_year else 366 start_yr_i = int((n_dpy - self.start_date.doy + 1) * 24 * timestep) n_mid = (8760 * timestep) - len(vals_at_step) end_vals = vals_at_step[:start_yr_i] start_vals = vals_at_step[start_yr_i:] mid_vals = [self.placeholder_value for i in xrange(n_mid)] all_vals = start_vals + mid_vals + end_vals start_i = (start_date.doy - 1) * 24 * timestep end_i = end_date.doy * 24 * timestep return all_vals[start_i:end_i]
def multiplier(self, value): self._multiplier = int_in_range(value, 1, input_name='room multiplier')
def sky_density(self, v): density = typing.int_in_range(v, 1, input_name='Sky subdivision density') self._sky_density = density
def maximum_figures(self, value): self._maximum_figures = int_in_range( value, 200, input_name='shadow calculation maximum figures')
def calculation_frequency(self, value): self._calculation_frequency = int_in_range( value, 1, input_name='shadow calculation calculation frequency')
def start_month(self, value): if value == autocalculate: self._start_month = None else: self._start_month = \ int_in_range(value, 1, 12, 'start_month')
def sky_type(self, value): value = typing.int_in_range(value, 0, 5, 'CIE sky type') self._sky_type = value
def workers(self, value): if value is not None: value = int_in_range(value, mi=1, input_name='recipe workers') self._workers = value
def simulation_step(self, value): if value is not None: value = int_in_range(value, 0, len(self._base_collection) - 1, 'simulation_step') self._simulation_step = value