def test_schedule_fixedinterval_to_idf_compact(): """Test the ScheduleFixedInterval to_idf_compact method.""" trans_sched = ScheduleFixedInterval('Custom Transmittance', [x / 8760 for x in range(8760)], schedule_types.fractional) compact_idf = trans_sched.to_idf_compact() assert len(compact_idf.split(',')) > 8760 * 2
def schedule_fixedinterval_random_annual(directory): occ_sched = ScheduleFixedInterval( 'Random Occupancy', [round(random.random(), 4) for i in range(8760)], schedule_types.fractional) dest_file = os.path.join(directory, 'schedule_fixedinterval_random_annual.json') with open(dest_file, 'w') as fp: json.dump(occ_sched.to_dict(True), fp, indent=4)
def schedule_fixedinterval_increasing_fine_timestep(directory): increase_sched = ScheduleFixedInterval( 'Solstice Increasing', [round(x / 143, 4) for x in range(144)], schedule_types.fractional, start_date=Date(6, 21), timestep=6,) dest_file = os.path.join( directory, 'schedule_fixedinterval_increasing_fine_timestep.json') with open(dest_file, 'w') as fp: json.dump(increase_sched.to_dict(True), fp, indent=4)
def schedule_fixedinterval_leap_year(directory): test_vals = [15, 15, 15, 15, 15, 15, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 15, 15, 15, 15] sched = ScheduleFixedInterval( 'Weekly Temperature', test_vals * 7, schedule_types.temperature, start_date=Date(2, 29, True)) dest_file = os.path.join(directory, 'schedule_fixedinterval_leap_year.json') with open(dest_file, 'w') as fp: json.dump(sched.to_dict(True), fp, indent=4)
def test_schedule_fixedinterval_dict_methods(): """Test the ScheduleFixedInterval to/from dict methods.""" trans_sched = ScheduleFixedInterval('Custom Transmittance', [x / 8760 for x in range(8760)], schedule_types.fractional) sch_dict = trans_sched.to_dict() new_schedule = ScheduleFixedInterval.from_dict(sch_dict) assert new_schedule == trans_sched assert sch_dict == new_schedule.to_dict()
def model_energy_fixed_interval(directory): room = Room.from_box('Tiny_House_Office', 5, 10, 3) room.properties.energy.program_type = prog_type_lib.office_program room.properties.energy.add_default_ideal_air() occ_sched = ScheduleFixedInterval( 'Random Occupancy', [round(random.random(), 4) for i in range(8760)], schedule_types.fractional) new_people = room.properties.energy.people.duplicate() new_people.occupancy_schedule = occ_sched room.properties.energy.people = new_people south_face = room[3] south_face.apertures_by_ratio(0.4, 0.01) south_face.apertures[0].overhang(0.5, indoor=False) south_face.apertures[0].overhang(0.5, indoor=True) south_face.move_shades(Vector3D(0, 0, -0.5)) light_shelf_out = ShadeConstruction('Outdoor_Light_Shelf', 0.5, 0.5) light_shelf_in = ShadeConstruction('Indoor_Light_Shelf', 0.7, 0.7) south_face.apertures[0].outdoor_shades[0].properties.energy.construction = light_shelf_out south_face.apertures[0].indoor_shades[0].properties.energy.construction = light_shelf_in north_face = room[1] north_face.overhang(0.25, indoor=False) door_verts = [Point3D(2, 10, 0.1), Point3D(1, 10, 0.1), Point3D(1, 10, 2.5), Point3D(2, 10, 2.5)] door = Door('Front_Door', Face3D(door_verts)) north_face.add_door(door) aperture_verts = [Point3D(4.5, 10, 1), Point3D(2.5, 10, 1), Point3D(2.5, 10, 2.5), Point3D(4.5, 10, 2.5)] aperture = Aperture('Front_Aperture', Face3D(aperture_verts)) north_face.add_aperture(aperture) tree_canopy_geo = Face3D.from_regular_polygon( 6, 2, Plane(Vector3D(0, 0, 1), Point3D(5, -3, 4))) tree_canopy = Shade('Tree_Canopy', tree_canopy_geo) winter = [0.75] * 2190 spring = [0.75 - ((x / 2190) * 0.5) for x in range(2190)] summer = [0.25] * 2190 fall = [0.25 + ((x / 2190) * 0.5) for x in range(2190)] trans_sched = ScheduleFixedInterval( 'Seasonal Tree Transmittance', winter + spring + summer + fall, schedule_types.fractional) tree_canopy.properties.energy.transmittance_schedule = trans_sched model = Model('Tiny_House', [room], orphaned_shades=[tree_canopy]) model.north_angle = 15 dest_file = os.path.join( directory, 'model_energy_fixed_interval.json') with open(dest_file, 'w') as fp: json.dump(model.to_dict(included_prop=['energy']), fp, indent=4)
def test_schedule_fixedinterval_data_collection(): """Test the ScheduleFixedInterval data_collection_at_timestep method.""" trans_sched = ScheduleFixedInterval('Custom Transmittance', [x / 8760 for x in range(8760)], schedule_types.fractional) sch_data = trans_sched.data_collection_at_timestep() assert len(sch_data) == 8760 assert sch_data.values == trans_sched.values assert isinstance(sch_data.header.data_type, fraction.Fraction) assert sch_data.header.unit == 'fraction' assert sch_data.header.analysis_period == AnalysisPeriod() sch_data = trans_sched.data_collection_at_timestep(timestep=2) assert len(sch_data) == 8760 * 2
def test_shcedule_fixedinterval_to_idf_collective_csv(): """Test the to_idf_collective_csv method.""" ec_sched_idf = './tests/idf/ElectrochromicControlSchedules.idf' ec_scheds = ScheduleFixedInterval.extract_all_from_idf_file(ec_sched_idf) collective_string = ScheduleFixedInterval.to_idf_collective_csv( ec_scheds, './tests/csv/', 'All Electrochromic') assert len(collective_string) == 4 assert os.path.isfile('./tests/csv/All_Electrochromic.csv') all_data = csv_to_matrix('./tests/csv/All_Electrochromic.csv') assert len(all_data) == 8761 assert len(all_data[0]) >= 4 os.remove('./tests/csv/All_Electrochromic.csv')
def test_schedule_fixedinterval_init(): """Test the ScheduleFixedInterval initialization and basic properties.""" trans_sched = ScheduleFixedInterval('Custom Transmittance', [x / 8760 for x in range(8760)], schedule_types.fractional) str(trans_sched) # test the string representation assert trans_sched.identifier == 'Custom Transmittance' assert len(trans_sched.values) == 8760 assert trans_sched[0] == 0 assert trans_sched[1] == 1 / 8760 assert isinstance(trans_sched.schedule_type_limit, ScheduleTypeLimit) assert trans_sched.schedule_type_limit == schedule_types.fractional assert trans_sched.timestep == 1 assert not trans_sched.interpolate assert trans_sched.start_date == Date(1, 1) assert trans_sched.end_date_time == DateTime(12, 31, 23) assert not trans_sched.is_leap_year assert trans_sched.placeholder_value == 0 sch_data = trans_sched.data_collection assert len(sch_data) == 8760 assert isinstance(sch_data.header.data_type, fraction.Fraction) assert sch_data.header.unit == 'fraction' assert sch_data.header.analysis_period == AnalysisPeriod()
def dict_abridged_to_schedule(sch_dict, schedule_type_limits, raise_exception=True): """Get a Python object of any Schedule from an abridged dictionary. Args: sch_dict: A dictionary of any Honeybee energy schedules. Note that this should be a non-abridged dictionary to be valid. schedule_type_limits: Dictionary of all schedule type limit objects that might be used in the schedule with the type limit identifiers as the keys. raise_exception: Boolean to note whether an excpetion should be raised if the object is not identified as a schedule. Default: True. Returns: A Python object derived from the input sch_dict. """ try: # get the type key from the dictionary sch_type = sch_dict['type'] except KeyError: raise ValueError('Schedule dictionary lacks required "type" key.') if sch_type == 'ScheduleRulesetAbridged': return ScheduleRuleset.from_dict_abridged(sch_dict, schedule_type_limits) elif sch_type == 'ScheduleFixedIntervalAbridged': return ScheduleFixedInterval.from_dict_abridged(sch_dict, schedule_type_limits) elif raise_exception: raise ValueError('{} is not a recognized energy Schedule type'.format(sch_type))
def test_schedule_fixedinterval_from_idf(): """Test the ScheduleFixedInterval from_idf method.""" idf_str = \ """Schedule:File, Electrochromic Control, !- schedule name On-Off, !- schedule type limits ./tests/csv/Electrochromic_Control.csv, !- file name 1, !- column number 0, !- rows to skip 8760, !- number of hours of data Comma, !- column separator No, !- interpolate to timestep 60; !- minutes per item """ ec_schedule = ScheduleFixedInterval.from_idf(idf_str) assert ec_schedule.identifier == 'Electrochromic Control' assert len(ec_schedule.values) == 8760 assert ec_schedule[0] == 0 assert ec_schedule.schedule_type_limit is None assert ec_schedule.timestep == 1 assert not ec_schedule.interpolate assert ec_schedule.start_date == Date(1, 1) assert ec_schedule.end_date_time == DateTime(12, 31, 23) assert not ec_schedule.is_leap_year assert ec_schedule.placeholder_value == 0
def from_dict(cls, data, host): """Create ContextShadeEnergyProperties from a dictionary. Note that the dictionary must be a non-abridged version for this classmethod to work. Args: data: A dictionary representation of ContextShadeEnergyProperties. host: A ContextShade object that hosts these properties. """ assert data['type'] == 'ContextShadeEnergyProperties', \ 'Expected ContextShadeEnergyProperties. Got {}.'.format(data['type']) new_prop = cls(host) if 'construction' in data and data['construction'] is not None: new_prop.construction = ShadeConstruction.from_dict( data['construction']) if 'transmittance_schedule' in data and \ data['transmittance_schedule'] is not None: sch_dict = data['transmittance_schedule'] if sch_dict['type'] == 'ScheduleRuleset': new_prop.transmittance_schedule = \ ScheduleRuleset.from_dict(data['transmittance_schedule']) elif sch_dict['type'] == 'ScheduleFixedInterval': new_prop.transmittance_schedule = \ ScheduleFixedInterval.from_dict(data['transmittance_schedule']) else: raise ValueError( 'Expected non-abridged Schedule dictionary for ContextShade ' 'transmittance_schedule. Got {}.'.format(sch_dict['type'])) return new_prop
def test_schedule_fixedinterval_equality(): """Test the ScheduleFixedInterval to/from dict methods.""" trans_sched = ScheduleFixedInterval('Custom Transmittance', [x / 8760 for x in range(8760)], schedule_types.fractional) trans_sched_dup = trans_sched.duplicate() occ_sched = ScheduleFixedInterval( 'Random Occupancy', [round(random.random(), 4) for i in range(8760)], schedule_types.fractional) assert trans_sched is trans_sched assert trans_sched is not trans_sched_dup assert trans_sched == trans_sched_dup trans_sched_dup.identifier = 'Transmittance' assert trans_sched != trans_sched_dup assert trans_sched != occ_sched
def test_schedule_fixedinterval_average_schedules_ruleset(): """Test the average_schedules method with a ScheduleRuleset.""" trans_sched_1 = ScheduleFixedInterval('Transmittance 1', [1 for i in range(8760)], schedule_types.fractional) trans_sched_2 = ScheduleRuleset.from_constant_value('Transmittance 2', 0) avg_trans = ScheduleFixedInterval.average_schedules( 'Transmittance Avg', [trans_sched_1, trans_sched_2]) assert avg_trans.name == 'Transmittance Avg' assert avg_trans.schedule_type_limit == schedule_types.fractional assert len(avg_trans.values) == 8760 assert list(avg_trans.values) == [0.5] * 8760 avg_trans = ScheduleFixedInterval.average_schedules( 'Transmittance Avg', [trans_sched_1, trans_sched_2], [0.75, 0.25]) assert len(avg_trans.values) == 8760 assert list(avg_trans.values) == [0.75] * 8760
def validate_schedule(schedule_json): """Validate all properties of a schedule or abridged schedule JSON. \b Args: schedule_json: Full path to a either ScheduleRuleset, ScheduleRulesetAbridged ScheduleFixedInterval, or ScheduleFixedIntervalAbridged JSON file. """ try: # first check the JSON against the OpenAPI specification with open(schedule_json) as json_file: data = json.load(json_file) if data['type'] == 'ScheduleRuleset': click.echo('Validating ScheduleRuleset JSON ...') schema_schedule.ScheduleRuleset.parse_file(schedule_json) click.echo('Pydantic validation passed.') ScheduleRuleset.from_dict(data) click.echo('Python re-serialization passed.') elif data['type'] == 'ScheduleFixedInterval': click.echo('Validating ScheduleFixedInterval JSON ...') schema_schedule.ScheduleFixedInterval.parse_file(schedule_json) click.echo('Pydantic validation passed.') ScheduleFixedInterval.from_dict(data) click.echo('Python re-serialization passed.') elif data['type'] == 'ScheduleRulesetAbridged': click.echo('Validating ScheduleRulesetAbridged JSON ...') schema_schedule.ScheduleRulesetAbridged.parse_file(schedule_json) click.echo('Pydantic validation passed.') else: # assume it's a ScheduleFixedIntervalAbridged schema click.echo('Validating ScheduleFixedIntervalAbridged JSON ...') schema_schedule.ScheduleFixedIntervalAbridged.parse_file( schedule_json) click.echo('Pydantic validation passed.') # if we made it to this point, report that the object is valid click.echo('Congratulations! Your Schedule JSON is valid!') except Exception as e: _logger.exception('Schedule validation failed.\n{}'.format(e)) sys.exit(1) else: sys.exit(0)
def test_schedule_fixedinterval_average_schedules(): """Test the average_schedules method.""" trans_sched_1 = ScheduleFixedInterval('Transmittance 1', [1 for i in range(8760)], schedule_types.fractional) trans_sched_2 = ScheduleFixedInterval('Transmittance 2', [0 for i in range(8760)], schedule_types.fractional) avg_trans = ScheduleFixedInterval.average_schedules( 'Transmittance Avg', [trans_sched_1, trans_sched_2]) assert avg_trans.name == 'Transmittance Avg' assert avg_trans.schedule_type_limit == schedule_types.fractional assert len(avg_trans.values) == 8760 assert list(avg_trans.values) == [0.5] * 8760 avg_trans = ScheduleFixedInterval.average_schedules( 'Transmittance Avg', [trans_sched_1, trans_sched_2], [0.75, 0.25]) assert len(avg_trans.values) == 8760 assert list(avg_trans.values) == [0.75] * 8760 with pytest.raises(AssertionError): avg_trans = ScheduleFixedInterval.average_schedules( 'Transmittance Avg', [trans_sched_1, trans_sched_2], [0.5, 0.25])
def test_schedule_fixedinterval_single_day(): """Test the ScheduleFixedInterval initialization for a single day.""" increase_sched = ScheduleFixedInterval( 'Solstice Increasing', [round(x / 23, 4) for x in range(24)], schedule_types.fractional, start_date=Date(6, 21)) assert increase_sched.identifier == 'Solstice Increasing' assert len(increase_sched.values) == 24 assert increase_sched[0] == 0 assert increase_sched[-1] == 1 assert isinstance(increase_sched.schedule_type_limit, ScheduleTypeLimit) assert increase_sched.schedule_type_limit == schedule_types.fractional assert increase_sched.timestep == 1 assert not increase_sched.interpolate assert increase_sched.start_date == Date(6, 21)
def test_schedule_fixedinterval_single_day_fine_timestep(): """Test the ScheduleFixedInterval initialization for a single day at a fine timestep.""" increase_sched = ScheduleFixedInterval( 'Solstice Increasing', [round(x / 143, 4) for x in range(144)], schedule_types.fractional, start_date=Date(6, 21), timestep=6,) assert increase_sched.name == 'Solstice Increasing' assert len(increase_sched.values) == 144 assert increase_sched[0] == 0 assert increase_sched[-1] == 1 assert isinstance(increase_sched.schedule_type_limit, ScheduleTypeLimit) assert increase_sched.schedule_type_limit == schedule_types.fractional assert increase_sched.timestep == 6 assert not increase_sched.interpolate assert increase_sched.start_date == Date(6, 21) """
def test_schedule_fixedinterval_from_idf_file(): """Test the initialization of ScheduleFixedInterval from file.""" ec_sched_idf = './tests/idf/ElectrochromicControlSchedules.idf' ec_scheds = ScheduleFixedInterval.extract_all_from_idf_file(ec_sched_idf) assert len(ec_scheds) == 4 assert ec_scheds[0].identifier == 'Electrochromic Control 0' assert ec_scheds[1].identifier == 'Electrochromic Control 90' assert ec_scheds[2].identifier == 'Electrochromic Control 180' assert ec_scheds[3].identifier == 'Electrochromic Control 270' assert len(ec_scheds[0].values) == 8760 assert len(ec_scheds[1].values) == 8760 assert len(ec_scheds[2].values) == 8760 assert len(ec_scheds[3].values) == 8760 assert ec_scheds[0].schedule_type_limit is ec_scheds[1].schedule_type_limit == \ schedule_types.on_off
def test_schedule_fixedinterval_values_at_coarser_timestep(): """Test the ScheduleFixedInterval values_at_timestep method with a coarser step.""" trans_sched = ScheduleFixedInterval( 'Custom Transmittance', [x / 17520 for x in range(17520)], schedule_types.fractional, timestep=2) values = trans_sched.values_at_timestep(timestep=1) assert len(values) == 8760 assert values[0] == trans_sched.values[0] trans_sched_2 = ScheduleFixedInterval( 'Custom Transmittance', [x / 96 for x in range(96)], schedule_types.fractional, interpolate=True) values = trans_sched_2.values_at_timestep(timestep=1, end_date=Date(1, 1)) assert len(values) == 24 assert values[0] == trans_sched.values[0]
def test_schedule_fixedinterval_values_at_finer_timestep(): """Test the ScheduleFixedInterval values_at_timestep method with a finer step.""" trans_sched = ScheduleFixedInterval( 'Custom Transmittance', [x / 8760 for x in range(8760)], schedule_types.fractional) values = trans_sched.values_at_timestep(timestep=2) assert len(values) == 8760 * 2 assert values[0] == values[1] == trans_sched.values[0] trans_sched_2 = ScheduleFixedInterval( 'Custom Transmittance', [x / 24 for x in range(24)], schedule_types.fractional, interpolate=True) values = trans_sched_2.values_at_timestep(timestep=4, end_date=Date(1, 1)) assert len(values) == 24 * 4 assert values[0] == trans_sched.values[0] assert values[0] != values[1]
def test_schedule_fixedinterval_values_at_timestep_reversed(): """Test the ScheduleFixedInterval values_at_timestep method with a reversed list.""" trans_sched = ScheduleFixedInterval( 'Custom Transmittance', [x / 8760 for x in range(8760)], schedule_types.fractional, start_date=Date(1, 2)) values = trans_sched.values_at_timestep() assert len(values) == 8760 assert values[24] == 0 assert values[0] == trans_sched.values[-24] trans_sched_4 = ScheduleFixedInterval( 'Custom Transmittance', [x / 168 for x in range(168)], schedule_types.fractional, start_date=Date(12, 31)) values = trans_sched_4.values_at_timestep(end_date=Date(1, 2)) assert len(values) == 48 assert values[0] == 24 / 168 assert values[23] == 47 / 168
def test_schedule_fixedinterval_to_idf(): """Test the methods that go to and from an IDF.""" random_occ = [0.5] * 8760 occ_sched = ScheduleFixedInterval('Random Occupancy', random_occ, schedule_types.fractional) schedule_file = occ_sched.to_idf('./tests/csv/', include_datetimes=False) sch_type = schedule_types.fractional.to_idf() rebuilt_schedule = ScheduleFixedInterval.from_idf(schedule_file, sch_type) assert rebuilt_schedule == occ_sched assert rebuilt_schedule.to_idf('./tests/csv/') == schedule_file schedule_file = occ_sched.to_idf('./tests/csv/', include_datetimes=True) rebuilt_schedule = ScheduleFixedInterval.from_idf(schedule_file, sch_type) assert rebuilt_schedule == occ_sched os.remove('./tests/csv/Random_Occupancy.csv')
try: # import ladybug_rhino dependencies from ladybug_rhino.grasshopper import all_required_inputs except ImportError as e: raise ImportError('\nFailed to import ladybug_rhino:\n\t{}'.format(e)) if all_required_inputs(ghenv.Component): # set the defaults _timestep_ = 1 if _timestep_ is None else _timestep_ start_date = Date(1, 1) if analysis_period_ is None else \ analysis_period_.st_time.date name = clean_and_id_ep_string('FixedIntervalSchedule') if _name_ is None else \ clean_ep_string(_name_) # get the ScheduleTypeLimit object if _type_limit_ is None: _type_limit_ = schedule_type_limit_by_identifier('Fractional') elif isinstance(_type_limit_, str): _type_limit_ = schedule_type_limit_by_identifier(_type_limit_) # create the schedule object schedule = ScheduleFixedInterval(name, _values, _type_limit_, _timestep_, start_date, placeholder_value=0, interpolate=False) if _name_ is not None: schedule.display_name = _name_
def test_schedule_fixedinterval_lockability(): """Test the lockability of ScheduleFixedInterval objects.""" schedule = ScheduleFixedInterval('Custom Transmittance', [x / 8760 for x in range(8760)], schedule_types.fractional) schedule.interpolate = True schedule.lock() with pytest.raises(AttributeError): schedule.interpolate = False with pytest.raises(AttributeError): schedule.values = [1] * 8760 schedule.unlock() schedule.interpolate = False schedule.values = [1] * 8760
from honeybee_energy.lib.scheduletypelimits import schedule_type_limit_by_identifier except ImportError as e: raise ImportError('\nFailed to import honeybee_energy:\n\t{}'.format(e)) try: # import ladybug_rhino dependencies from ladybug_rhino.grasshopper import all_required_inputs except ImportError as e: raise ImportError('\nFailed to import ladybug_rhino:\n\t{}'.format(e)) if all_required_inputs(ghenv.Component): # set the defaults _timestep_ = 1 if _timestep_ is None else _timestep_ start_date = Date(1, 1) if analysis_period_ is None else \ analysis_period_.st_time.date # get the ScheduleTypeLimit object if _type_limit_ is None: _type_limit_ = schedule_type_limit_by_identifier('Fractional') elif isinstance(_type_limit_, str): _type_limit_ = schedule_type_limit_by_identifier(_type_limit_) # create the schedule object schedule = ScheduleFixedInterval(clean_and_id_ep_string(_name), _values, _type_limit_, _timestep_, start_date, placeholder_value=0, interpolate=False) schedule.display_name = _name
def test_schedule_fixedinterval_values_at_timestep(): """Test the ScheduleFixedInterval values_at_timestep method.""" trans_sched = ScheduleFixedInterval('Custom Transmittance', [x / 8760 for x in range(8760)], schedule_types.fractional) values = trans_sched.values_at_timestep() assert len(values) == 8760 assert values == list(trans_sched.values) trans_sched_2 = ScheduleFixedInterval('Custom Transmittance', [x / 24 for x in range(24)], schedule_types.fractional) values = trans_sched_2.values_at_timestep() assert len(values) == 8760 assert values[:24] == [x / 24 for x in range(24)] assert values[24] == 0 trans_sched_3 = ScheduleFixedInterval('Custom Transmittance', [x / 24 for x in range(24)], schedule_types.fractional, start_date=Date(1, 2)) values = trans_sched_3.values_at_timestep() assert len(values) == 8760 assert values[24:48] == [x / 24 for x in range(24)] assert values[0] == 0 assert values[48] == 0 trans_sched_4 = ScheduleFixedInterval('Custom Transmittance', [x / 168 for x in range(168)], schedule_types.fractional) values = trans_sched_4.values_at_timestep(end_date=Date(1, 2)) assert len(values) == 48 assert values[0] == 0 assert values[47] == 47 / 168 values = trans_sched_4.values_at_timestep(start_date=Date(1, 2), end_date=Date(1, 3)) assert len(values) == 48 assert values[0] == 24 / 168 assert values[47] == 71 / 168
def test_to_dict_single_zone_schedule_fixed_interval(): """Test the Model to_dict method with a single zone model and fixed interval schedules.""" room = Room.from_box('Tiny House Zone', 5, 10, 3) room.properties.energy.program_type = office_program room.properties.energy.hvac = IdealAirSystem() occ_sched = ScheduleFixedInterval( 'Random Occupancy', [round(random.random(), 4) for i in range(8760)], schedule_types.fractional) new_people = room.properties.energy.people.duplicate() new_people.occupancy_schedule = occ_sched room.properties.energy.people = new_people south_face = room[3] south_face.apertures_by_ratio(0.4, 0.01) south_face.apertures[0].overhang(0.5, indoor=False) south_face.apertures[0].overhang(0.5, indoor=True) south_face.move_shades(Vector3D(0, 0, -0.5)) light_shelf_out = ShadeConstruction('Outdoor Light Shelf', 0.5, 0.5) light_shelf_in = ShadeConstruction('Indoor Light Shelf', 0.7, 0.7) south_face.apertures[0].outdoor_shades[ 0].properties.energy.construction = light_shelf_out south_face.apertures[0].indoor_shades[ 0].properties.energy.construction = light_shelf_in north_face = room[1] north_face.overhang(0.25, indoor=False) door_verts = [ Point3D(2, 10, 0.1), Point3D(1, 10, 0.1), Point3D(1, 10, 2.5), Point3D(2, 10, 2.5) ] door = Door('Front Door', Face3D(door_verts)) north_face.add_door(door) aperture_verts = [ Point3D(4.5, 10, 1), Point3D(2.5, 10, 1), Point3D(2.5, 10, 2.5), Point3D(4.5, 10, 2.5) ] aperture = Aperture('Front Aperture', Face3D(aperture_verts)) north_face.add_aperture(aperture) tree_canopy_geo = Face3D.from_regular_polygon( 6, 2, Plane(Vector3D(0, 0, 1), Point3D(5, -3, 4))) tree_canopy = Shade('Tree Canopy', tree_canopy_geo) winter = [0.75] * 2190 spring = [0.75 - ((x / 2190) * 0.5) for x in range(2190)] summer = [0.25] * 2190 fall = [0.25 + ((x / 2190) * 0.5) for x in range(2190)] trans_sched = ScheduleFixedInterval('Seasonal Tree Transmittance', winter + spring + summer + fall, schedule_types.fractional) tree_canopy.properties.energy.transmittance_schedule = trans_sched model = Model('Tiny House', [room], orphaned_shades=[tree_canopy]) model.north_angle = 15 model_dict = model.to_dict() assert 'energy' in model_dict['properties'] assert 'schedules' in model_dict['properties']['energy'] assert 'program_types' in model_dict['properties']['energy'] assert len(model_dict['properties']['energy']['program_types']) == 1 assert len(model_dict['properties']['energy']['schedules']) == 9 assert 'people' in model_dict['rooms'][0]['properties']['energy'] assert model_dict['rooms'][0]['properties']['energy']['people']['occupancy_schedule'] \ == 'Random Occupancy' assert model_dict['orphaned_shades'][0]['properties']['energy']['transmittance_schedule'] \ == 'Seasonal Tree Transmittance' assert model_dict['rooms'][0]['properties']['energy']['program_type'] == \ office_program.name """