openstudio-standards 0.8.5 → 0.8.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/data/standards/test_performance_expected_dd_results.csv +90 -90
- data/lib/openstudio-standards/btap/activity.rb +858 -61
- data/lib/openstudio-standards/btap/attributes.rb +297 -103
- data/lib/openstudio-standards/btap/bridging.rb +1335 -593
- data/lib/openstudio-standards/btap/btap.rb +60 -181
- data/lib/openstudio-standards/btap/carbon/btap_carbon.rb +199 -142
- data/lib/openstudio-standards/btap/common/constructions.json +1275 -0
- data/lib/openstudio-standards/btap/common/costs.csv +1969 -0
- data/lib/openstudio-standards/btap/common/costs_local_factors.csv +2315 -0
- data/lib/openstudio-standards/btap/common/materials_glazing.csv +61 -0
- data/lib/openstudio-standards/btap/{common_resources → common}/materials_hvac.csv +1685 -1685
- data/lib/openstudio-standards/btap/{common_resources → common}/materials_lighting.csv +266 -266
- data/lib/openstudio-standards/btap/common/materials_opaque.csv +214 -0
- data/lib/openstudio-standards/btap/common/necb_building_types.csv +35 -0
- data/lib/openstudio-standards/btap/common/necb_space_types.csv +110 -0
- data/lib/openstudio-standards/btap/common/thermal_bridging.csv +73 -0
- data/lib/openstudio-standards/btap/costing/btap_costing.rb +346 -429
- data/lib/openstudio-standards/btap/costing/database.rb +104 -0
- data/lib/openstudio-standards/btap/costing/daylighting_sensor_control_costing.rb +356 -344
- data/lib/openstudio-standards/btap/costing/dcv_costing.rb +282 -296
- data/lib/openstudio-standards/btap/costing/envelope_costing.rb +179 -192
- data/lib/openstudio-standards/btap/costing/heating_cooling_costing.rb +2477 -2316
- data/lib/openstudio-standards/btap/costing/led_lighting_costing.rb +127 -142
- data/lib/openstudio-standards/btap/costing/lighting_costing.rb +216 -198
- data/lib/openstudio-standards/btap/costing/nv_costing.rb +522 -523
- data/lib/openstudio-standards/btap/costing/pv_ground_costing.rb +649 -649
- data/lib/openstudio-standards/btap/costing/shw_costing.rb +626 -625
- data/lib/openstudio-standards/btap/costing/thermal_bridging_costing.rb +72 -0
- data/lib/openstudio-standards/btap/costing/ventilation_costing.rb +2363 -2361
- data/lib/openstudio-standards/btap/deprecated.rb +1033 -0
- data/lib/openstudio-standards/btap/envelope.rb +313 -572
- data/lib/openstudio-standards/btap/fileio.rb +152 -1070
- data/lib/openstudio-standards/btap/geometry.rb +486 -766
- data/lib/openstudio-standards/btap/linear_regression.rb +130 -0
- data/lib/openstudio-standards/btap/paths.rb +46 -0
- data/lib/openstudio-standards/btap/qaqc/analysis.rb +163 -0
- data/lib/openstudio-standards/btap/qaqc/data.rb +2293 -0
- data/lib/openstudio-standards/btap/qaqc/datapoint.rb +641 -0
- data/lib/openstudio-standards/btap/schedules.rb +11 -611
- data/lib/openstudio-standards/btap/structure.rb +574 -189
- data/lib/openstudio-standards/constructions/materials/information.rb +1 -1
- data/lib/openstudio-standards/create_typical/create_typical.rb +1 -1
- data/lib/openstudio-standards/exterior_lighting/create.rb +135 -85
- data/lib/openstudio-standards/exterior_lighting/data/typical_exterior_lighting.json +20 -0
- data/lib/openstudio-standards/exterior_lighting/information.rb +23 -2
- data/lib/openstudio-standards/geometry/create.rb +7 -3
- data/lib/openstudio-standards/prototypes/ashrae_90_1/ashrae_90_1_2016/ashrae_90_1_2016.Model.rb +3 -2
- data/lib/openstudio-standards/prototypes/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.Model.rb +3 -2
- data/lib/openstudio-standards/prototypes/common/data/thermostat_schedule_lookup.json +84 -84
- data/lib/openstudio-standards/prototypes/common/objects/Prototype.hvac_systems.rb +4 -4
- data/lib/openstudio-standards/refrigeration/create_walkin.rb +45 -5
- data/lib/openstudio-standards/refrigeration/data/refrigerated_walkins.csv +75 -75
- data/lib/openstudio-standards/schedules/parametric.rb +6 -0
- data/lib/openstudio-standards/service_water_heating/create_typical.rb +10 -3
- data/lib/openstudio-standards/service_water_heating/create_water_heating_loop.rb +30 -14
- data/lib/openstudio-standards/service_water_heating/information.rb +4 -1
- data/lib/openstudio-standards/sql_file/unmet_hours.rb +2 -1
- data/lib/openstudio-standards/standards/Standards.CoilCoolingDXSingleSpeed.rb +3 -1
- data/lib/openstudio-standards/standards/Standards.CoilHeatingDXSingleSpeed.rb +3 -1
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/data/ashrae_90_1_2004.boilers.json +12 -0
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/data/ashrae_90_1_2004.construction_properties.json +18432 -3072
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/data/ashrae_90_1_2007.boilers.json +26 -0
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/data/ashrae_90_1_2007.construction_properties.json +8532 -1422
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/data/ashrae_90_1_2010.boilers.json +26 -0
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/data/ashrae_90_1_2010.construction_properties.json +8532 -1422
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.boilers.json +16 -0
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.computer_room_acs.json +30 -30
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.construction_properties.json +7560 -1260
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/ashrae_90_1_2016.PumpVariableSpeed.rb +1 -2
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/data/ashrae_90_1_2016.boilers.json +16 -0
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/data/ashrae_90_1_2016.construction_properties.json +7560 -1260
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.AirLoopHVAC.rb +3 -3
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.PumpVariableSpeed.rb +1 -2
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/data/ashrae_90_1_2019.boilers.json +22 -0
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/data/ashrae_90_1_2019.construction_properties.json +7236 -1206
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/data/ashrae_90_1_2019.furnaces.json +223 -19
- data/lib/openstudio-standards/standards/ashrae_90_1/data/ashrae_90_1.schedules.json +37 -1
- data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.boilers.json +3 -0
- data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.construction_properties.json +6900 -1150
- data/lib/openstudio-standards/standards/cbes/data/cbes.schedules.json +1 -1
- data/lib/openstudio-standards/standards/deer/data/deer.schedules.json +1 -1
- data/lib/openstudio-standards/standards/necb/BTAP1980TO2010/data/surface_thermal_transmittance.json +76 -40
- data/lib/openstudio-standards/standards/necb/BTAPPRE1980/data/surface_thermal_transmittance.json +76 -40
- data/lib/openstudio-standards/standards/necb/ECMS/hvac_systems.rb +6 -4
- data/lib/openstudio-standards/standards/necb/NECB2011/NECB2011_QAQC.json +2988 -0
- data/lib/openstudio-standards/standards/necb/NECB2011/autozone.rb +25 -3
- data/lib/openstudio-standards/standards/necb/NECB2011/building_envelope.rb +672 -534
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/Hospital.osm +1791 -1792
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/LEEPMultiTower.osm +7 -1
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/LEEPTownHouse.osm +7 -1
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/LargeHotel.osm +5 -6
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/LargeOffice.osm +8 -9
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/NorthernEducation.osm +10 -4
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/NorthernHealthCare.osm +14 -15
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/Outpatient.osm +7 -1
- data/lib/openstudio-standards/standards/necb/NECB2011/data/surface_thermal_transmittance.json +76 -40
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_systems.rb +14 -6
- data/lib/openstudio-standards/standards/necb/NECB2011/necb_2011.rb +542 -130
- data/lib/openstudio-standards/standards/necb/NECB2011/qaqc/necb_qaqc.rb +30 -63
- data/lib/openstudio-standards/standards/necb/NECB2011/service_water_heating.rb +7 -2
- data/lib/openstudio-standards/standards/necb/NECB2015/data/surface_thermal_transmittance.json +90 -0
- data/lib/openstudio-standards/standards/necb/NECB2015/necb_2015.rb +8 -6
- data/lib/openstudio-standards/standards/necb/NECB2017/data/surface_thermal_transmittance.json +76 -40
- data/lib/openstudio-standards/standards/necb/NECB2017/necb_2017.rb +2 -1
- data/lib/openstudio-standards/standards/necb/NECB2020/building_envelope.rb +0 -117
- data/lib/openstudio-standards/standards/necb/NECB2020/data/surface_thermal_transmittance.json +76 -45
- data/lib/openstudio-standards/standards/necb/NECB2020/necb_2020.rb +218 -0
- data/lib/openstudio-standards/standards/necb/common/construction_defaults.osm +12 -7
- data/lib/openstudio-standards/standards/standard.rb +1 -1
- data/lib/openstudio-standards/version.rb +1 -1
- data/lib/openstudio-standards.rb +9 -4
- metadata +59 -66
- data/data/inventory/thermal_bridging.csv +0 -90
- data/data/standards/OpenStudio_Standards-ashrae_90_1-ALL-comstock(space_types).xlsx +0 -0
- data/data/standards/openstudio_standards_duplicates_log.csv +0 -7962
- data/lib/openstudio-standards/btap/NECB_building_types.csv +0 -35
- data/lib/openstudio-standards/btap/NECB_space_types.csv +0 -109
- data/lib/openstudio-standards/btap/WeatherData1.json +0 -2110
- data/lib/openstudio-standards/btap/WeatherData1.xlsx +0 -0
- data/lib/openstudio-standards/btap/btap_result.rb +0 -1144
- data/lib/openstudio-standards/btap/btap_test_helper.rb +0 -86
- data/lib/openstudio-standards/btap/common_paths.rb +0 -81
- data/lib/openstudio-standards/btap/common_resources/ConstructionProperties.csv +0 -52
- data/lib/openstudio-standards/btap/common_resources/Constructions.csv +0 -37
- data/lib/openstudio-standards/btap/common_resources/construction_sets.csv +0 -1270
- data/lib/openstudio-standards/btap/common_resources/constructions_glazing.csv +0 -121
- data/lib/openstudio-standards/btap/common_resources/constructions_opaque.csv +0 -2256
- data/lib/openstudio-standards/btap/common_resources/costs.csv +0 -1897
- data/lib/openstudio-standards/btap/common_resources/costs_local_factors.csv +0 -2315
- data/lib/openstudio-standards/btap/common_resources/materials_glazing.csv +0 -35
- data/lib/openstudio-standards/btap/common_resources/materials_opaque.csv +0 -164
- data/lib/openstudio-standards/btap/costing/btap_measure_helper.rb +0 -359
- data/lib/openstudio-standards/btap/costing/btap_workflow.rb +0 -117
- data/lib/openstudio-standards/btap/costing/copy_test_results_files_to_expected_results.rb +0 -11
- data/lib/openstudio-standards/btap/costing/cost_building_from_file.rb +0 -136
- data/lib/openstudio-standards/btap/costing/costing_database_wrapper.rb +0 -173
- data/lib/openstudio-standards/btap/costing/dummy.epw +0 -8768
- data/lib/openstudio-standards/btap/costing/dummy.osm +0 -5320
- data/lib/openstudio-standards/btap/costing/neb_end_use_prices.csv +0 -42
- data/lib/openstudio-standards/btap/costing/necb_2011_spacetype_info.csv +0 -225
- data/lib/openstudio-standards/btap/costing/necb_reference_runs.csv +0 -28705
- data/lib/openstudio-standards/btap/costing/parallel_tests.rb +0 -92
- data/lib/openstudio-standards/btap/costing/test_list.txt +0 -15
- data/lib/openstudio-standards/btap/costing/test_run_all_test_locally.rb +0 -27
- data/lib/openstudio-standards/btap/costing/test_run_costing_tests.rb +0 -80
- data/lib/openstudio-standards/btap/necb_2011_spacetype_info.csv +0 -225
- data/lib/openstudio-standards/btap/utilities/Add_template_field_to_json.rb +0 -22
- data/lib/openstudio-standards/btap/utilities/convert_surfaces_to_adiabatic_necb_8426.rb +0 -204
- data/lib/openstudio-standards/btap/utilities/generate_space_types.rb +0 -8
- data/lib/openstudio-standards/btap/utilities/necb_to_epw_map.rb +0 -50
- data/lib/openstudio-standards/btap/utilities/os_sim_extract.rb +0 -48
- data/lib/openstudio-standards/btap/utilities/rename_surfaces.rb +0 -24
- data/lib/openstudio-standards/btap/utilities/round_surf_coords.rb +0 -32
- data/lib/openstudio-standards/btap/utilities/sched_create.rb +0 -145
- data/lib/openstudio-standards/btap/utilities/set_mult_to_adiabatic.rb +0 -53
- data/lib/openstudio-standards/btap/utilities/space_type.rb +0 -78
- data/lib/openstudio-standards/btap/utilities/weatherData1_xlsx_to_json.rb +0 -56
- data/lib/openstudio-standards/btap/vintagizer.rb +0 -161
- data/lib/openstudio-standards/btap/visualization.rb +0 -72
- data/lib/openstudio-standards/standards/necb/NECB2011/data/necb_2011_spacetype_info.csv +0 -225
- data/lib/openstudio-standards/standards/necb/common/btap_analysis.rb +0 -79
- data/lib/openstudio-standards/standards/necb/common/btap_data.rb +0 -2656
- data/lib/openstudio-standards/standards/necb/common/btap_datapoint.rb +0 -653
- data/lib/openstudio-standards/standards/necb/common/necb_reference_runs.csv +0 -28705
- data/lib/openstudio-standards/standards/necb/common/utility_pricing_2025-02-20.csv +0 -92
- /data/lib/openstudio-standards/btap/{common_resources → common}/carbon_frame.csv +0 -0
- /data/lib/openstudio-standards/btap/{common_resources → common}/carbon_glazing.csv +0 -0
- /data/lib/openstudio-standards/btap/{common_resources → common}/carbon_opaque.csv +0 -0
- /data/lib/openstudio-standards/btap/{common_resources → common}/hvac_vent_ahu.csv +0 -0
- /data/lib/openstudio-standards/btap/{common_resources → common}/lighting.csv +0 -0
- /data/lib/openstudio-standards/btap/{common_resources → common}/lighting_sets.csv +0 -0
- /data/lib/openstudio-standards/btap/{common_resources → common}/locations.csv +0 -0
- /data/lib/openstudio-standards/btap/{costing → common}/mech_sizing.json +0 -0
|
@@ -0,0 +1,1033 @@
|
|
|
1
|
+
# BTAP Deprecated
|
|
2
|
+
#
|
|
3
|
+
# 2026-07-09
|
|
4
|
+
# This file will house methods that aren't used inside OpenStudio Standards.
|
|
5
|
+
# NRCan task 486 involves cleaning up unused code, however since OpenStudio
|
|
6
|
+
# Standards is a library, other people could be using these methods despite them
|
|
7
|
+
# not being used inside this repository. For now, they are marked as deprecated
|
|
8
|
+
# unless someone expresses otherwise. If there are no concerns these methods
|
|
9
|
+
# will soon be removed for the purpose of making developer operations simpler.
|
|
10
|
+
|
|
11
|
+
module BTAP
|
|
12
|
+
module Deprecated
|
|
13
|
+
def self.msg(klass, method_name)
|
|
14
|
+
warn("[BTAP::Deprecated] #{klass}##{method_name} is considered for " \
|
|
15
|
+
"deletion for the future as of July 2026. If you are still using" \
|
|
16
|
+
"this method, please contact" \
|
|
17
|
+
"nicholas.pneumaticos@nrcan-rncan.gc.ca.")
|
|
18
|
+
end
|
|
19
|
+
end # module Deprecated
|
|
20
|
+
|
|
21
|
+
module Geometry
|
|
22
|
+
def self.enumerate_spaces_model(model, prepend_name = false)
|
|
23
|
+
#enumerate stories.
|
|
24
|
+
BTAP::Geometry::BuildingStoreys::auto_assign_spaces_to_stories(model)
|
|
25
|
+
#Enumerate spaces
|
|
26
|
+
model.getBuildingStorys.sort.each do |story|
|
|
27
|
+
spaces = Array.new
|
|
28
|
+
spaces.concat(story.spaces)
|
|
29
|
+
spaces.sort! do |a, b|
|
|
30
|
+
(a.xOrigin <=> b.xOrigin).nonzero? ||
|
|
31
|
+
(a.yOrigin <=> b.yOrigin)
|
|
32
|
+
end
|
|
33
|
+
counter = 1
|
|
34
|
+
spaces.sort.each do |space|
|
|
35
|
+
#puts "old space name : #{space.name}"
|
|
36
|
+
if prepend_name == true
|
|
37
|
+
space.setName("#{story.name}-#{counter.to_s}:#{space.name}")
|
|
38
|
+
else
|
|
39
|
+
space.setName("#{story.name}-#{counter.to_s}")
|
|
40
|
+
end
|
|
41
|
+
counter = counter + 1
|
|
42
|
+
p #uts "new space name : #{space.name}"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# this was a copy of the sketchup plugin method.
|
|
48
|
+
def self.rename_zones_based_on_spaces(model)
|
|
49
|
+
|
|
50
|
+
# loop through thermal zones
|
|
51
|
+
model.getThermalZones.sort.each do |thermal_zone| # this is going through all, not just selection
|
|
52
|
+
#puts "old zone name : #{thermal_zone.name}"
|
|
53
|
+
# reset the array of spaces to be empty
|
|
54
|
+
spaces_in_thermal_zone = []
|
|
55
|
+
# reset length of array of spaces
|
|
56
|
+
number_of_spaces = 0
|
|
57
|
+
|
|
58
|
+
# get list of spaces in thermal zone
|
|
59
|
+
spaces = thermal_zone.spaces
|
|
60
|
+
spaces.sort.each do |space|
|
|
61
|
+
|
|
62
|
+
# make an array instead of the puts statement
|
|
63
|
+
spaces_in_thermal_zone.push space.name.to_s
|
|
64
|
+
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# store length of array
|
|
68
|
+
number_of_spaces = spaces_in_thermal_zone.size
|
|
69
|
+
|
|
70
|
+
# sort the array
|
|
71
|
+
spaces_in_thermal_zone = spaces_in_thermal_zone.sort
|
|
72
|
+
|
|
73
|
+
# setup a suffix if the thermal zone contains more than one space
|
|
74
|
+
if number_of_spaces > 1
|
|
75
|
+
multi = " - Plus"
|
|
76
|
+
else
|
|
77
|
+
multi = ""
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# rename thermal zone based on first space with prefix added e.g. ThermalZone 203
|
|
81
|
+
if number_of_spaces > 0
|
|
82
|
+
new_name = "ZN:" + spaces_in_thermal_zone[0] + multi
|
|
83
|
+
thermal_zone.setName(new_name)
|
|
84
|
+
else
|
|
85
|
+
puts "#{thermal_zone.name.to_s} did not have any spaces, and will not be renamed."
|
|
86
|
+
end
|
|
87
|
+
#puts "new zone name : #{thermal_zone.name}"
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
#This method will rename the zone equipment to have the zone name as a prefix for a model.
|
|
92
|
+
#It will also rename the hot water coils for:
|
|
93
|
+
# AirTerminalSingleDuctVAVReheat
|
|
94
|
+
# ZoneHVACBaseboardConvectiveWater
|
|
95
|
+
# ZoneHVACUnitHeater
|
|
96
|
+
|
|
97
|
+
def self.prefix_equipment_with_zone_name(model)
|
|
98
|
+
#puts "Renaming zone equipment."
|
|
99
|
+
# get all thermal zones
|
|
100
|
+
thermal_zones = model.getThermalZones
|
|
101
|
+
|
|
102
|
+
# loop through thermal zones
|
|
103
|
+
thermal_zones.each do |thermal_zone| # this is going through all, not just selection
|
|
104
|
+
|
|
105
|
+
thermal_zone.equipment.each do |equip|
|
|
106
|
+
|
|
107
|
+
#For the hydronic conditions below only, it will rename the zonal coils as well.
|
|
108
|
+
if not equip.to_AirTerminalSingleDuctVAVReheat.empty?
|
|
109
|
+
|
|
110
|
+
equip.setName("#{thermal_zone.name}:AirTerminalSingleDuctVAVReheat")
|
|
111
|
+
reheat_coil = equip.to_AirTerminalSingleDuctVAVReheat.get.reheatCoil
|
|
112
|
+
reheat_coil.setName("#{thermal_zone.name}:ReheatCoil")
|
|
113
|
+
#puts reheat_coil.name
|
|
114
|
+
elsif not equip.to_ZoneHVACBaseboardConvectiveWater.empty?
|
|
115
|
+
equip.setName("#{thermal_zone.name}:ZoneHVACBaseboardConvectiveWater")
|
|
116
|
+
heatingCoil = equip.to_ZoneHVACBaseboardConvectiveWater.get.heatingCoil
|
|
117
|
+
heatingCoil.setName("#{thermal_zone.name}:Baseboard HW Htg Coil")
|
|
118
|
+
#puts heatingCoil.name
|
|
119
|
+
elsif not equip.to_ZoneHVACUnitHeater.empty?
|
|
120
|
+
equip.setName("#{thermal_zone.name}:ZoneHVACUnitHeater")
|
|
121
|
+
heatingCoil = equip.to_ZoneHVACUnitHeater.get.heatingCoil
|
|
122
|
+
heatingCoil.setName("#{thermal_zone.name}:Unit Heater Htg Coil")
|
|
123
|
+
#puts heatingCoil.name
|
|
124
|
+
#Add more cases if you wish!!!!!
|
|
125
|
+
else #if the equipment does not follow the above cases, rename
|
|
126
|
+
# it generically and not touch the underlying coils, etc.
|
|
127
|
+
equip.setName("#{thermal_zone.name}:#{equip.name}")
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
module BuildingStoreys
|
|
135
|
+
#This method will delete any exisiting stories and then try to assign stories based on
|
|
136
|
+
# the z-axis origin of the space.
|
|
137
|
+
def self.auto_assign_spaces_to_stories(model)
|
|
138
|
+
#delete existing stories.
|
|
139
|
+
model.getBuildingStorys.sort.each {|buildingstory| buildingstory.remove}
|
|
140
|
+
#create hash of building storeys, index is the Z-axis origin of the space.
|
|
141
|
+
building_story_hash = Hash.new()
|
|
142
|
+
model.getSpaces.sort.each do |space|
|
|
143
|
+
if building_story_hash[space.zOrigin].nil?
|
|
144
|
+
building_story_hash[space.zOrigin] = OpenStudio::Model::BuildingStory.new(model)
|
|
145
|
+
building_story_hash[space.zOrigin].setName(building_story_hash.length.to_s)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
space.setBuildingStory(building_story_hash[space.zOrigin])
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# override run to implement the functionality of your script
|
|
154
|
+
# model is an OpenStudio::Model::Model, runner is a OpenStudio::Ruleset::UserScriptRunner
|
|
155
|
+
def self.auto_assign_stories(model)
|
|
156
|
+
|
|
157
|
+
# get all spaces
|
|
158
|
+
spaces = model.getSpaces
|
|
159
|
+
|
|
160
|
+
#puts("Assigning Stories to Spaces")
|
|
161
|
+
|
|
162
|
+
# make has of spaces and minz values
|
|
163
|
+
sorted_spaces = Hash.new
|
|
164
|
+
spaces.sort.each do |space|
|
|
165
|
+
# loop through space surfaces to find min z value
|
|
166
|
+
z_points = []
|
|
167
|
+
space.surfaces.each do |surface|
|
|
168
|
+
surface.vertices.each do |vertex|
|
|
169
|
+
z_points << vertex.z
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
minz = z_points.min + space.zOrigin
|
|
173
|
+
sorted_spaces[space] = minz
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# pre-sort spaces
|
|
177
|
+
sorted_spaces = sorted_spaces.sort {|a, b| a[1] <=> b[1]}
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
# this should take the sorted list and make and assign stories
|
|
181
|
+
sorted_spaces.sort.each do |space|
|
|
182
|
+
space_obj = space[0]
|
|
183
|
+
space_minz = space[1]
|
|
184
|
+
if space_obj.buildingStory.empty?
|
|
185
|
+
story = OpenstudioStandards::Geometry.model_get_building_story_for_nominal_height(model, space_minz)
|
|
186
|
+
if story.nil?
|
|
187
|
+
story = OpenStudio::Model::BuildingStory.new(model)
|
|
188
|
+
story.setNominalZCoordinate(space_minz)
|
|
189
|
+
story.setName("Building Story #{space_minz.round(1)}m")
|
|
190
|
+
end
|
|
191
|
+
space_obj.setBuildingStory(story)
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
end # module BuildingStoreys
|
|
196
|
+
|
|
197
|
+
#This module contains helper functions that deal with Space objects.
|
|
198
|
+
module Spaces
|
|
199
|
+
|
|
200
|
+
# This method will return the horizontal placement type. (N,S,W,E,C) In the
|
|
201
|
+
# case of a corner, it will take whatever surface area it faces is the
|
|
202
|
+
# largest. It will also return the top, bottom or middle conditions.
|
|
203
|
+
def self.get_space_placement(space)
|
|
204
|
+
horizontal_placement = nil
|
|
205
|
+
vertical_placement = nil
|
|
206
|
+
json_data = nil
|
|
207
|
+
|
|
208
|
+
#get all exterior surfaces.
|
|
209
|
+
surfaces = BTAP::Geometry::Surfaces::filter_by_boundary_condition(space.surfaces,
|
|
210
|
+
["Outdoors",
|
|
211
|
+
"Ground",
|
|
212
|
+
"GroundFCfactorMethod",
|
|
213
|
+
"GroundSlabPreprocessorAverage",
|
|
214
|
+
"GroundSlabPreprocessorCore",
|
|
215
|
+
"GroundSlabPreprocessorPerimeter",
|
|
216
|
+
"GroundBasementPreprocessorAverageWall",
|
|
217
|
+
"GroundBasementPreprocessorAverageFloor",
|
|
218
|
+
"GroundBasementPreprocessorUpperWall",
|
|
219
|
+
"GroundBasementPreprocessorLowerWall"])
|
|
220
|
+
|
|
221
|
+
#exterior Surfaces
|
|
222
|
+
ext_wall_surfaces = BTAP::Geometry::Surfaces::filter_by_surface_types(surfaces, ["Wall"])
|
|
223
|
+
ext_bottom_surface = BTAP::Geometry::Surfaces::filter_by_surface_types(surfaces, ["Floor"])
|
|
224
|
+
ext_top_surface = BTAP::Geometry::Surfaces::filter_by_surface_types(surfaces, ["RoofCeiling"])
|
|
225
|
+
|
|
226
|
+
#Interior Surfaces..if needed....
|
|
227
|
+
internal_surfaces = BTAP::Geometry::Surfaces::filter_by_boundary_condition(space.surfaces, ["Surface"])
|
|
228
|
+
int_wall_surfaces = BTAP::Geometry::Surfaces::filter_by_surface_types(internal_surfaces, ["Wall"])
|
|
229
|
+
int_bottom_surface = BTAP::Geometry::Surfaces::filter_by_surface_types(internal_surfaces, ["Floor"])
|
|
230
|
+
int_top_surface = BTAP::Geometry::Surfaces::filter_by_surface_types(internal_surfaces, ["RoofCeiling"])
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
vertical_placement = "NA"
|
|
234
|
+
#determine if space is a top or bottom, both or middle space.
|
|
235
|
+
if ext_bottom_surface.size > 0 and ext_top_surface.size > 0 and int_bottom_surface.size == 0 and int_top_surface.size == 0
|
|
236
|
+
vertical_placement = "single_story_space"
|
|
237
|
+
elsif int_bottom_surface.size > 0 and ext_top_surface.size > 0 and int_bottom_surface.size > 0
|
|
238
|
+
vertical_placement = "top"
|
|
239
|
+
elsif ext_bottom_surface.size > 0 and ext_top_surface.size == 0
|
|
240
|
+
vertical_placement = "bottom"
|
|
241
|
+
elsif ext_bottom_surface.size == 0 and ext_top_surface.size == 0
|
|
242
|
+
vertical_placement = "middle"
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
#determine if what cardinal direction has the majority of external
|
|
247
|
+
#surface area of the space.
|
|
248
|
+
#set this to 'core' by default and change it if it is found to be a space exposed to a cardinal direction.
|
|
249
|
+
horizontal_placement = nil
|
|
250
|
+
#set up summing hashes for each direction.
|
|
251
|
+
json_data = Hash.new
|
|
252
|
+
walls_area_array = Hash.new
|
|
253
|
+
subsurface_area_array = Hash.new
|
|
254
|
+
boundary_conditions = {}
|
|
255
|
+
boundary_conditions[:outdoors] = ["Outdoors"]
|
|
256
|
+
boundary_conditions[:ground] = [
|
|
257
|
+
"Ground",
|
|
258
|
+
"GroundFCfactorMethod",
|
|
259
|
+
"GroundSlabPreprocessorAverage",
|
|
260
|
+
"GroundSlabPreprocessorCore",
|
|
261
|
+
"GroundSlabPreprocessorPerimeter",
|
|
262
|
+
"GroundBasementPreprocessorAverageWall",
|
|
263
|
+
"GroundBasementPreprocessorAverageFloor",
|
|
264
|
+
"GroundBasementPreprocessorUpperWall",
|
|
265
|
+
"GroundBasementPreprocessorLowerWall"]
|
|
266
|
+
#go through all directions.. need to do north twice since that goes around zero degree mark.
|
|
267
|
+
orientations = [
|
|
268
|
+
{:surface_type => 'Wall', :direction => 'north', :azimuth_from => 0.00, :azimuth_to => 45.0, :tilt_from => 0.0, :tilt_to => 180.0},
|
|
269
|
+
{:surface_type => 'Wall', :direction => 'north', :azimuth_from => 315.001, :azimuth_to => 360.0, :tilt_from => 0.0, :tilt_to => 180.0},
|
|
270
|
+
{:surface_type => 'Wall', :direction => 'east', :azimuth_from => 45.001, :azimuth_to => 135.0, :tilt_from => 0.0, :tilt_to => 180.0},
|
|
271
|
+
{:surface_type => 'Wall', :direction => 'south', :azimuth_from => 135.001, :azimuth_to => 225.0, :tilt_from => 0.0, :tilt_to => 180.0},
|
|
272
|
+
{:surface_type => 'Wall', :direction => 'west', :azimuth_from => 225.001, :azimuth_to => 315.0, :tilt_from => 0.0, :tilt_to => 180.0},
|
|
273
|
+
{:surface_type => 'RoofCeiling', :direction => 'top', :azimuth_from => 0.0, :azimuth_to => 360.0, :tilt_from => 0.0, :tilt_to => 180.0},
|
|
274
|
+
{:surface_type => 'Floor', :direction => 'bottom', :azimuth_from => 0.0, :azimuth_to => 360.0, :tilt_from => 0.0, :tilt_to => 180.0}
|
|
275
|
+
]
|
|
276
|
+
[:outdoors, :ground].each do |bc|
|
|
277
|
+
orientations.each do |orientation|
|
|
278
|
+
walls_area_array[orientation[:direction]] = 0.0
|
|
279
|
+
subsurface_area_array[orientation[:direction]] = 0.0
|
|
280
|
+
json_data[orientation[:direction]] = {} if json_data[orientation[:direction]].nil?
|
|
281
|
+
json_data[orientation[:direction]][bc] = {:surface_area => 0.0,
|
|
282
|
+
:glazed_subsurface_area => 0.0,
|
|
283
|
+
:opaque_subsurface_area => 0.0}
|
|
284
|
+
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
[:outdoors, :ground].each do |bc|
|
|
289
|
+
orientations.each do |orientation|
|
|
290
|
+
# puts "bc= #{bc}"
|
|
291
|
+
# puts boundary_conditions[bc.to_sym]
|
|
292
|
+
# puts boundary_conditions
|
|
293
|
+
surfaces = BTAP::Geometry::Surfaces::filter_by_boundary_condition(space.surfaces, boundary_conditions[bc])
|
|
294
|
+
selected_surfaces = BTAP::Geometry::Surfaces::filter_by_surface_types(surfaces, [orientation[:surface_type]])
|
|
295
|
+
BTAP::Geometry::Surfaces::filter_by_azimuth_and_tilt(selected_surfaces, orientation[:azimuth_from], orientation[:azimuth_to], orientation[:tilt_from], orientation[:tilt_to]).each do |surface|
|
|
296
|
+
#sum wall area and subsurface area by direction. This is the old way so excluding top and bottom surfaces.
|
|
297
|
+
walls_area_array[orientation[:direction]] += surface.grossArea unless ['RoofCeiling', 'Floor'].include?(orientation[:surface_type])
|
|
298
|
+
subsurface_area_array[orientation[:direction]] += surface.subSurfaces.map {|subsurface| subsurface.grossArea}.inject(0) {|sum, x| sum + x}
|
|
299
|
+
json_data[orientation[:direction]][bc][:surface_area] += surface.grossArea
|
|
300
|
+
glazings = BTAP::Geometry::Surfaces::filter_subsurfaces_by_types(surface.subSurfaces, ["FixedWindow", "OperableWindow", "GlassDoor", "Skylight", "TubularDaylightDiffuser", "TubularDaylightDome"])
|
|
301
|
+
doors = BTAP::Geometry::Surfaces::filter_subsurfaces_by_types(surface.subSurfaces, ["Door", "OverheadDoor"])
|
|
302
|
+
json_data[orientation[:direction]][bc][:glazed_subsurface_area] += glazings.map {|subsurface| subsurface.grossArea}.inject(0) {|sum, x| sum + x}
|
|
303
|
+
json_data[orientation[:direction]][bc][:opaque_subsurface_area] += doors.map {|subsurface| subsurface.grossArea}.inject(0) {|sum, x| sum + x}
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
puts JSON.pretty_generate(json_data)
|
|
308
|
+
|
|
309
|
+
puts walls_area_array
|
|
310
|
+
#find if no direction
|
|
311
|
+
sum= 0.0
|
|
312
|
+
['north','east','south','west'].each do |direction|
|
|
313
|
+
[:outdoors,:ground].each do |bc|
|
|
314
|
+
sum += json_data[direction][bc][:surface_area]
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
if sum == 0.0
|
|
318
|
+
horizontal_placement = "core"
|
|
319
|
+
else
|
|
320
|
+
#find our which cardinal direction has the most exterior surface and declare it that orientation.
|
|
321
|
+
horizontal_placement = walls_area_array.max_by {|k, v| v}[0] #include ext and ground.
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
#save JSON data
|
|
325
|
+
json_data = ({:horizontal_placement => horizontal_placement,
|
|
326
|
+
:vertical_placement => vertical_placement,
|
|
327
|
+
}).merge(json_data)
|
|
328
|
+
puts JSON.pretty_generate(json_data)
|
|
329
|
+
|
|
330
|
+
return json_data
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
def self.is_perimeter_space?(model, space)
|
|
334
|
+
exterior_surfaces = BTAP::Geometry::Surfaces::filter_by_boundary_condition(
|
|
335
|
+
space.surfaces,
|
|
336
|
+
["Outdoors",
|
|
337
|
+
"Ground",
|
|
338
|
+
"GroundFCfactorMethod",
|
|
339
|
+
"GroundSlabPreprocessorAverage",
|
|
340
|
+
"GroundSlabPreprocessorCore",
|
|
341
|
+
"GroundSlabPreprocessorPerimeter",
|
|
342
|
+
"GroundBasementPreprocessorAverageWall",
|
|
343
|
+
"GroundBasementPreprocessorAverageFloor",
|
|
344
|
+
"GroundBasementPreprocessorUpperWall",
|
|
345
|
+
"GroundBasementPreprocessorLowerWall"])
|
|
346
|
+
|
|
347
|
+
return BTAP::Geometry::Surfaces::filter_by_surface_types(exterior_surfaces, ["Wall"]).size > 0
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
def self.show(model, space)
|
|
351
|
+
if drawing_interface = BTAP::Common::validate_array(model, space, "Space").first.drawing_interface
|
|
352
|
+
if entity = drawing_interface.entity
|
|
353
|
+
entity.visible = true
|
|
354
|
+
end
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
def self.hide(model, space)
|
|
359
|
+
if drawing_interface = BTAP::Common::validate_array(model, space, "Space").first.drawing_interface
|
|
360
|
+
if entity = drawing_interface.entity
|
|
361
|
+
entity.visible = false
|
|
362
|
+
end
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
# This method will filter an array of spaces that have an external wall
|
|
367
|
+
# passed floors. Note: if you wish to avoid to create an array of spaces,
|
|
368
|
+
# simply put the space variable in [] brackets
|
|
369
|
+
# Ex: get_all_surfaces_from_spaces( [space1,space2] )
|
|
370
|
+
# @param spaces_array an array of type [OpenStudio::Model::Space]
|
|
371
|
+
# @return an array of spaces.
|
|
372
|
+
def self.filter_perimeter_spaces(model, spaces_array)
|
|
373
|
+
spaces_array = BTAP::Common::validate_array(model, spaces_array, "Space")
|
|
374
|
+
array = Array.new()
|
|
375
|
+
spaces_array.each do |space|
|
|
376
|
+
if space.is_a_perimeter_space?()
|
|
377
|
+
array.push(space)
|
|
378
|
+
end
|
|
379
|
+
end
|
|
380
|
+
return array
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
# This method will filter an array of spaces that have no external wall
|
|
384
|
+
# passed floors. Note: if you wish to avoid to create an array of spaces,
|
|
385
|
+
# simply put the space variable in [] brackets
|
|
386
|
+
# Ex: get_all_surfaces_from_spaces( [space1,space2] )
|
|
387
|
+
# @param spaces_array an array of type [OpenStudio::Model::Space]
|
|
388
|
+
# @return an array of spaces.
|
|
389
|
+
def self.filter_core_spaces(model, spaces_array)
|
|
390
|
+
spaces_array = BTAP::Common::validate_array(model, spaces_array, "Space")
|
|
391
|
+
array = Array.new()
|
|
392
|
+
spaces_array.each do |space|
|
|
393
|
+
unless space.is_a_perimeter_space?()
|
|
394
|
+
array.push(space)
|
|
395
|
+
end
|
|
396
|
+
end
|
|
397
|
+
return array
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
def self.filter_spaces_by_space_types(model, spaces_array, spacetype_array)
|
|
401
|
+
spaces_array = BTAP::Common::validate_array(model, spaces_array, "Space")
|
|
402
|
+
spacetype_array = BTAP::Common::validate_array(model, spacetype_array, "SpaceType")
|
|
403
|
+
#validate space array
|
|
404
|
+
returnarray = Array.new()
|
|
405
|
+
spaces_array.each do |space|
|
|
406
|
+
returnarray << spacetype_array.include?(space.spaceType())
|
|
407
|
+
end
|
|
408
|
+
return returnarray
|
|
409
|
+
end
|
|
410
|
+
end # module Spaces
|
|
411
|
+
|
|
412
|
+
module Zones
|
|
413
|
+
|
|
414
|
+
# This method will filter an array of zones that have an external wall
|
|
415
|
+
# passed floors. Note: if you wish to avoid to create an array of spaces,
|
|
416
|
+
# simply put the space variable in [] brackets
|
|
417
|
+
# Ex: get_all_surfaces_from_spaces( [space1,space2] )
|
|
418
|
+
# @param thermal_zones [Array<OpenStudio::Model::ThermalZone>] an array of zones
|
|
419
|
+
# @return [Array<OpenStudio::Model::ThermalZone] an array of thermal zones.
|
|
420
|
+
def self.filter_perimeter_zones(thermal_zones)
|
|
421
|
+
array = Array.new()
|
|
422
|
+
thermal_zones.each do |zone|
|
|
423
|
+
zone.space.each do |space|
|
|
424
|
+
if space.is_a_perimeter_space?()
|
|
425
|
+
array.push(zone)
|
|
426
|
+
next
|
|
427
|
+
end
|
|
428
|
+
end
|
|
429
|
+
end
|
|
430
|
+
return array
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
# This method will filter an array of zones that have no external wall
|
|
434
|
+
# passed floors. Note: if you wish to avoid to create an array of spaces,
|
|
435
|
+
# simply put the space variable in [] brackets
|
|
436
|
+
# Ex: ( [space1,space2] )
|
|
437
|
+
# @param thermal_zones [Array<OpenStudio::Model::ThermalZone] an array of zones
|
|
438
|
+
# @return [Array<OpenStudio::Model::ThermalZone] an array of zones
|
|
439
|
+
def self.filter_core_zones(thermal_zones)
|
|
440
|
+
array = Array.new()
|
|
441
|
+
thermal_zones.getThermalZones.sort.each do |zone|
|
|
442
|
+
zone.space.each do |space|
|
|
443
|
+
if not space.is_a_perimeter_space?()
|
|
444
|
+
array.push(zone)
|
|
445
|
+
next
|
|
446
|
+
end
|
|
447
|
+
end
|
|
448
|
+
end
|
|
449
|
+
return array
|
|
450
|
+
end
|
|
451
|
+
end # module Zones
|
|
452
|
+
|
|
453
|
+
module Surfaces
|
|
454
|
+
def self.create_surface(model, name, os_point3d_array, boundary_condition = "", construction = "")
|
|
455
|
+
os_surface = OpenStudio::Model::Surface.new(os_point3d_array, model)
|
|
456
|
+
os_surface.setName(name)
|
|
457
|
+
if OpenStudio::Model::Surface::validOutsideBoundaryConditionValues.include?(boundary_condition)
|
|
458
|
+
self.set_surfaces_boundary_condition([os_surface], boundary_condition)
|
|
459
|
+
else
|
|
460
|
+
puts "boundary condition not set for #{name}"
|
|
461
|
+
end
|
|
462
|
+
os_surface.setConstruction(construction)
|
|
463
|
+
return os_surface
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
# This method will rotate a surface
|
|
467
|
+
# @param planar_surfaces [Array<OpenStudio::Model::Surface>] an array of surfaces
|
|
468
|
+
# @param azimuth_degrees [Float] rotation value
|
|
469
|
+
# @param tilt_degrees [Float] rotation value
|
|
470
|
+
# @param translation_vector [OpenStudio::Vector3d] a vector along which to move all surfaces
|
|
471
|
+
# @return [OpenStudio::Model::Model] the model object.
|
|
472
|
+
def self.rotate_tilt_translate_surfaces(planar_surfaces, azimuth_degrees, tilt_degrees = 0.0, translation_vector = OpenStudio::Vector3d.new(0.0, 0.0, 0.0))
|
|
473
|
+
# Identity matrix for setting space origins
|
|
474
|
+
azimuth_matrix = OpenStudio::Transformation::rotation(OpenStudio::Vector3d.new(0, 0, 1), azimuth_degrees * Math::PI / 180)
|
|
475
|
+
tilt_matrix = OpenStudio::Transformation::rotation(OpenStudio::Vector3d.new(0, 0, 1), tilt_degrees * Math::PI / 180)
|
|
476
|
+
translation_matrix = OpenStudio::createTranslation(translation_vector)
|
|
477
|
+
planar_surfaces.each do |surface|
|
|
478
|
+
surface.changeTransformation(azimuth_matrix)
|
|
479
|
+
surface.changeTransformation(tilt_matrix)
|
|
480
|
+
surface.changeTransformation(translation_matrix)
|
|
481
|
+
end
|
|
482
|
+
return planar_surfaces
|
|
483
|
+
end
|
|
484
|
+
|
|
485
|
+
def self.set_fenestration_to_wall_ratio(surfaces, ratio, offset = 0, height_offset_from_floor = true, floor = "all")
|
|
486
|
+
surfaces.each do |surface|
|
|
487
|
+
result = surface.setWindowToWallRatio(ratio, offset, height_offset_from_floor)
|
|
488
|
+
raise("Unable to set FWR for surface " +
|
|
489
|
+
surface.name.get.to_s +
|
|
490
|
+
" . Possible reasons are if the surface is not a wall, if the surface
|
|
491
|
+
is not rectangular in face coordinates, if requested ratio is too large
|
|
492
|
+
(window area ~= surface area) or too small (min dimension of window < 1 foot),
|
|
493
|
+
or if the window clips any remaining sub surfaces. Otherwise, removes all
|
|
494
|
+
existing windows and adds new window to meet requested ratio.") unless result
|
|
495
|
+
end
|
|
496
|
+
return surfaces
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
def self.filter_by_non_defaulted_surfaces(surfaces)
|
|
500
|
+
non_defaulted_surfaces = Array.new()
|
|
501
|
+
surfaces.each {|surface| non_defaulted_surfaces << surface unless surface.isConstructionDefaulted}
|
|
502
|
+
return non_defaulted_surfaces
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
def self.filter_by_interzonal_surface(surfaces)
|
|
506
|
+
return_array = Array.new()
|
|
507
|
+
surfaces.each do |surface|
|
|
508
|
+
unless surface.adjacentSurface().empty?
|
|
509
|
+
return_array.push(surface)
|
|
510
|
+
end
|
|
511
|
+
return return_array
|
|
512
|
+
end
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
# Azimuth start from Y axis, Tilts starts from Z-axis
|
|
516
|
+
def self.filter_by_azimuth_and_tilt(surfaces, azimuth_from, azimuth_to, tilt_from, tilt_to, tolerance = 1.0)
|
|
517
|
+
return_surfaces = []
|
|
518
|
+
surfaces.each do |surface|
|
|
519
|
+
unless OpenStudio::Model::PlanarSurface::findPlanarSurfaces([surface], OpenStudio::OptionalDouble.new(azimuth_from), OpenStudio::OptionalDouble.new(azimuth_to), OpenStudio::OptionalDouble.new(tilt_from), OpenStudio::OptionalDouble.new(tilt_to), tolerance).empty?
|
|
520
|
+
return_surfaces << surface
|
|
521
|
+
end
|
|
522
|
+
end
|
|
523
|
+
return return_surfaces
|
|
524
|
+
end
|
|
525
|
+
|
|
526
|
+
def self.show(surfaces)
|
|
527
|
+
surfaces.each do |surface|
|
|
528
|
+
if drawing_interface = surface.drawing_interface
|
|
529
|
+
if entity = drawing_interface.entity
|
|
530
|
+
entity.visible = false
|
|
531
|
+
end
|
|
532
|
+
end
|
|
533
|
+
end
|
|
534
|
+
end
|
|
535
|
+
|
|
536
|
+
def self.hide(surfaces)
|
|
537
|
+
surfaces.each do |surface|
|
|
538
|
+
if drawing_interface = surface.drawing_interface
|
|
539
|
+
if entity = drawing_interface.entity
|
|
540
|
+
entity.visible = false
|
|
541
|
+
end
|
|
542
|
+
end
|
|
543
|
+
end
|
|
544
|
+
end
|
|
545
|
+
end # module Surfaces
|
|
546
|
+
end # module Geometry
|
|
547
|
+
|
|
548
|
+
module Schedules
|
|
549
|
+
module Fraction
|
|
550
|
+
def self.always_off(model)
|
|
551
|
+
fraction_always_off_name = "FRACTION_ALWAYS_OFF"
|
|
552
|
+
schedule = model.getScheduleRulesetByName(fraction_always_off_name)
|
|
553
|
+
if schedule.empty?
|
|
554
|
+
#create Schedule
|
|
555
|
+
return BTAP::Resources::Schedules::create_annual_constant_ruleset_schedule(
|
|
556
|
+
fraction_always_off_name,
|
|
557
|
+
"FRACTION",
|
|
558
|
+
0.0)
|
|
559
|
+
else
|
|
560
|
+
return schedule.get
|
|
561
|
+
end
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
def self.always_on(model)
|
|
565
|
+
fraction_always_on_name = "FRACTION_ALWAYS_ON"
|
|
566
|
+
schedule = model.getScheduleRulesetByName(fraction_always_on_name)
|
|
567
|
+
if schedule.empty?
|
|
568
|
+
#create Schedule
|
|
569
|
+
return BTAP::Resources::Schedules::create_annual_constant_ruleset_schedule(
|
|
570
|
+
model,
|
|
571
|
+
fraction_always_on_name,
|
|
572
|
+
"FRACTION",
|
|
573
|
+
1.0)
|
|
574
|
+
else
|
|
575
|
+
return schedule.get
|
|
576
|
+
end
|
|
577
|
+
end
|
|
578
|
+
end # module Fraction
|
|
579
|
+
|
|
580
|
+
module ON_OFF
|
|
581
|
+
def self.always_on(model)
|
|
582
|
+
on_off_always_on = "ON_OFF_ALWAYS_ON"
|
|
583
|
+
schedule = model.getScheduleRulesetByName(on_off_always_on)
|
|
584
|
+
if schedule.empty?
|
|
585
|
+
#create Schedule
|
|
586
|
+
return BTAP::Resources::Schedules::create_annual_constant_ruleset_schedule(
|
|
587
|
+
model,
|
|
588
|
+
on_off_always_on,
|
|
589
|
+
"ON_OFF",
|
|
590
|
+
1)
|
|
591
|
+
else
|
|
592
|
+
return schedule.get
|
|
593
|
+
end
|
|
594
|
+
end
|
|
595
|
+
end # module ON_OFF
|
|
596
|
+
|
|
597
|
+
module Temperature
|
|
598
|
+
def self.no_heating(model)
|
|
599
|
+
no_heating = "NO_HEATING_SETPOINT"
|
|
600
|
+
schedule = model.getScheduleRulesetByName(no_heating)
|
|
601
|
+
if schedule.empty?
|
|
602
|
+
#create Schedule
|
|
603
|
+
return BTAP::Resources::Schedules::create_annual_constant_ruleset_schedule(
|
|
604
|
+
model,
|
|
605
|
+
no_heating,
|
|
606
|
+
"TEMPERATURE",
|
|
607
|
+
-200.0)
|
|
608
|
+
else
|
|
609
|
+
return schedule.get
|
|
610
|
+
end
|
|
611
|
+
end
|
|
612
|
+
|
|
613
|
+
def self.no_cooling(model)
|
|
614
|
+
no_cooling = "NO_COOLING_SETPOINT"
|
|
615
|
+
schedule = model.getScheduleRulesetByName(no_cooling)
|
|
616
|
+
if schedule.empty?
|
|
617
|
+
#create Schedule
|
|
618
|
+
return BTAP::Resources::Schedules::create_annual_constant_ruleset_schedule(
|
|
619
|
+
model,
|
|
620
|
+
no_cooling,
|
|
621
|
+
"TEMPERATURE",
|
|
622
|
+
200.0)
|
|
623
|
+
else
|
|
624
|
+
return schedule.get
|
|
625
|
+
end
|
|
626
|
+
end
|
|
627
|
+
|
|
628
|
+
def self.no_heating_cooling_dual_setpoint_schedule(model)
|
|
629
|
+
dual_setpoint_name = "FREE_FLOATING_DUAL_SETPOINT_THERMOSTAT"
|
|
630
|
+
schedule = model.getScheduleRulesetByName(dual_setpoint_name)
|
|
631
|
+
if schedule.empty?
|
|
632
|
+
#create Schedule
|
|
633
|
+
return BTAP::Resources::Schedules::create_annual_thermostat_setpoint_dual_setpoint( model, dual_setpoint_name, self.heating_setpoint_off, self.cooling_setpoint_off)
|
|
634
|
+
else
|
|
635
|
+
return schedule.getThermostatSetpointDualSetpointByName()
|
|
636
|
+
end
|
|
637
|
+
end
|
|
638
|
+
end # module Temperature
|
|
639
|
+
|
|
640
|
+
def self.remove_all_schedules(model)
|
|
641
|
+
model.getScheduleBases.sort.each { |item| item.remove }
|
|
642
|
+
end
|
|
643
|
+
|
|
644
|
+
def self.create_zonal_occupancy_schedule_on_off(model, thermal_zone)
|
|
645
|
+
model.getFanZoneExhausts.sort.each {|zfe| puts "Fan Ex:#{zfe}"}
|
|
646
|
+
|
|
647
|
+
# Create new timeseries object to keep track of on/off states. Default to 30min intervals.
|
|
648
|
+
timeseries = OpenStudio::TimeSeries.new
|
|
649
|
+
thermal_zone.spaces.sort.each do |space|
|
|
650
|
+
#Iterate through the people object in the space.
|
|
651
|
+
space.spaceType.get.people.each do |people|
|
|
652
|
+
if people.numberofPeopleSchedule.is_initialized() and people.numberofPeopleSchedule.get.to_ScheduleRuleset.is_initialized
|
|
653
|
+
#Get the occupancy schedule.
|
|
654
|
+
occ_schedule = people.numberofPeopleSchedule.get
|
|
655
|
+
#Convert schedule to timeseries and sum up timeseries objects for this space / zone.
|
|
656
|
+
occ_time_series = create_timeseries_from_schedule_ruleset(model,occ_schedule)
|
|
657
|
+
timeseries = timeseries + occ_time_series
|
|
658
|
+
end
|
|
659
|
+
end
|
|
660
|
+
end
|
|
661
|
+
# Return the timeseries converted to
|
|
662
|
+
return create_schedule_variable_interval_from_time_series(model,timeseries)
|
|
663
|
+
end
|
|
664
|
+
|
|
665
|
+
# This method will only work with a single occupancy definition.
|
|
666
|
+
def self.set_exhaust_fans_availability_to_building_default_occ_schedule(model)
|
|
667
|
+
# get occupancy schedule if possible.
|
|
668
|
+
if model.building.get.defaultScheduleSet.is_initialized and
|
|
669
|
+
model.building.get.defaultScheduleSet.get.numberofPeopleSchedule.is_initialized and
|
|
670
|
+
model.building.get.defaultScheduleSet.get.numberofPeopleSchedule.get.to_ScheduleRuleset.is_initialized
|
|
671
|
+
occ_schedule = model.building.get.defaultScheduleSet.get.numberofPeopleSchedule.get
|
|
672
|
+
#get building default occupancy schedule.
|
|
673
|
+
model.getFanZoneExhausts.sort.each do |zfe|
|
|
674
|
+
zfe.setAvailabilitySchedule(occ_schedule)
|
|
675
|
+
zfe.setBalancedExhaustFractionSchedule(occ_schedule)
|
|
676
|
+
end
|
|
677
|
+
else
|
|
678
|
+
raise ("Default occupancy schedule has not been set in model! Unsure what to set exhaust fans to. Exiting.")
|
|
679
|
+
end
|
|
680
|
+
return model.getFanZoneExhausts
|
|
681
|
+
end
|
|
682
|
+
|
|
683
|
+
def self.modify_schedule(model, schedule_ruleset, a_coef = 0.0 ,b_coef = 0.0 ,c_coef= 0.0 ,time_shift = nil,time_sign = nil)
|
|
684
|
+
new_schedule = schedule_ruleset.clone( model ).to_ScheduleRuleset.get
|
|
685
|
+
self.modify_schedule!(model, new_schedule, a_coef,b_coef,c_coef ,time_shift,time_sign)
|
|
686
|
+
end
|
|
687
|
+
|
|
688
|
+
def self.modify_schedule!(model, schedule_ruleset, a_coef = 0.0 ,b_coef = 0.0 ,c_coef= 0.0 ,time_shift = nil,time_sign = nil)
|
|
689
|
+
schedule_ruleset.scheduleRules.each do |week_rule|
|
|
690
|
+
day_rule = week_rule.daySchedule()
|
|
691
|
+
times = day_rule.times()
|
|
692
|
+
times.each do |time|
|
|
693
|
+
old_value = day_rule.getValue(time)
|
|
694
|
+
day_rule.removeValue(time)
|
|
695
|
+
new_value = "error"
|
|
696
|
+
new_time = "error"
|
|
697
|
+
#set the new value according to Ax2+Bx+C.
|
|
698
|
+
new_value = a_coef * old_value ** 2.0 + b_coef * old_value + c_coef
|
|
699
|
+
unless time_shift.nil? or time_sign.nil?
|
|
700
|
+
command = "new_time = time #{time_sign} #{BTAP::Common::get_time_from_string(time_shift)}"
|
|
701
|
+
eval(command)
|
|
702
|
+
#make sure time is not past 24 hours.
|
|
703
|
+
new_time = new_time - BTAP::Common::get_time_from_string("24:00") if new_time > BTAP::Common::get_time_from_string("24:00")
|
|
704
|
+
end
|
|
705
|
+
day_rule.addValue(time, new_value)
|
|
706
|
+
end
|
|
707
|
+
end
|
|
708
|
+
end
|
|
709
|
+
|
|
710
|
+
def self.create_availability_schedule_based_on_another_schedule(model, occupancy_schedule, threshold = 0.05)
|
|
711
|
+
#create new On-Off schedule ruleset.
|
|
712
|
+
availability_ruleset = OpenStudio::Model::ScheduleRuleset.new(model)
|
|
713
|
+
availability_ruleset.setName("availabilty_based_on_occupancy")
|
|
714
|
+
#iterate though all rules.
|
|
715
|
+
occupancy_schedule.scheduleRules.each do |occ_rule|
|
|
716
|
+
#Create new hourly rule to populate availability schedule hourly data.
|
|
717
|
+
hourly_data = OpenStudio::Model::ScheduleDay.new(model)
|
|
718
|
+
#set schedule type to availabilty.
|
|
719
|
+
hourly_data.setScheduleTypeLimits(BTAP::Resources::Schedules::StandardScheduleTypeLimits::get_on_off(model))
|
|
720
|
+
#iterate though hour / value pairs for 24 hour period.
|
|
721
|
+
occ_rule.daySchedule().times().each do |time|
|
|
722
|
+
#check if time value is greater or equal to the threshold. If true set hour value to 1, else 0.
|
|
723
|
+
occ_rule.daySchedule().getValue(time) >= threshold ? hourly_data.addValue(time, 1.0) : hourly_data.addValue(time, 0.0)
|
|
724
|
+
end
|
|
725
|
+
#create new rule with hourly data and add to availablity ruleset.
|
|
726
|
+
avail_rule = OpenStudio::Model::ScheduleRule.new(availability_ruleset,hourly_data)
|
|
727
|
+
#Set same start and end date.
|
|
728
|
+
avail_rule.setStartDate(occ_rule.getStartDate)
|
|
729
|
+
avail_rule.setEndDate(occ_rule.getEndDate)
|
|
730
|
+
end #loop occ_rule
|
|
731
|
+
#Make sure to set the default schedule to be the same as well.
|
|
732
|
+
avail_default_day = availability_ruleset.defaultDaySchedule()
|
|
733
|
+
avail_default_day.clearValues()
|
|
734
|
+
#iterate though hour / value pairs for 24 hour period.
|
|
735
|
+
occupancy_schedule.defaultDaySchedule().times().each do |time|
|
|
736
|
+
#check if time value is greater or equal to the threshold. If true set hour value to 1, else 0.
|
|
737
|
+
occupancy_schedule.defaultDaySchedule().getValue(time) >= threshold ? avail_default_day.addValue(time, 1.0) : avail_default_day.addValue(time, 0.0)
|
|
738
|
+
end
|
|
739
|
+
return availability_ruleset
|
|
740
|
+
end
|
|
741
|
+
|
|
742
|
+
|
|
743
|
+
def self.create_setback_schedule_based_on_another_schedule(
|
|
744
|
+
model,
|
|
745
|
+
occupancy_schedule,
|
|
746
|
+
threshold = 0.05,
|
|
747
|
+
heat_setpoint = 22.0,
|
|
748
|
+
heat_setback = 17.0,
|
|
749
|
+
cool_setpoint = 24.0,
|
|
750
|
+
cool_setback =99.0)
|
|
751
|
+
#create new On-Off schedule ruleset.
|
|
752
|
+
heating_ruleset = OpenStudio::Model::ScheduleRuleset.new(model)
|
|
753
|
+
heating_ruleset.setName("heat_thermostat_based_on_occupancy")
|
|
754
|
+
cooling_ruleset = OpenStudio::Model::ScheduleRuleset.new(model)
|
|
755
|
+
cooling_ruleset.setName("cool_thermostat_based_on_occupancy")
|
|
756
|
+
#iterate though all rules.
|
|
757
|
+
occupancy_schedule.to_ScheduleRuleset.get.scheduleRules.each do |occ_rule|
|
|
758
|
+
#Create new hourly rule to populate heat/cold schedule hourly data.
|
|
759
|
+
heating_hourly_data = OpenStudio::Model::ScheduleDay.new(model)
|
|
760
|
+
cooling_hourly_data = OpenStudio::Model::ScheduleDay.new(model)
|
|
761
|
+
#set schedule type to availabilty.
|
|
762
|
+
heating_hourly_data.setScheduleTypeLimits(BTAP::Resources::Schedules::StandardScheduleTypeLimits::get_temperature(model))
|
|
763
|
+
cooling_hourly_data.setScheduleTypeLimits(BTAP::Resources::Schedules::StandardScheduleTypeLimits::get_temperature(model))
|
|
764
|
+
#iterate though hour / value pairs for 24 hour period.
|
|
765
|
+
occ_rule.daySchedule().times().each do |time|
|
|
766
|
+
#check if time value is greater or equal to the threshold. If true set hour value to 1, else 0.
|
|
767
|
+
occ_rule.daySchedule().getValue(time) >= threshold ? heating_hourly_data.addValue(time, heat_setpoint) : heating_hourly_data.addValue(time,heat_setback)
|
|
768
|
+
occ_rule.daySchedule().getValue(time) >= threshold ? cooling_hourly_data.addValue(time, cool_setpoint) : cooling_hourly_data.addValue(time,cool_setback)
|
|
769
|
+
end
|
|
770
|
+
#create new rule with hourly data and add to availablity ruleset.
|
|
771
|
+
heating_avail_rule = OpenStudio::Model::ScheduleRule.new(heating_ruleset,heating_hourly_data)
|
|
772
|
+
cooling_avail_rule = OpenStudio::Model::ScheduleRule.new(cooling_ruleset,cooling_hourly_data)
|
|
773
|
+
#Set same start and end date.
|
|
774
|
+
heating_avail_rule.setStartDate(occ_rule.startDate.get)
|
|
775
|
+
heating_avail_rule.setEndDate(occ_rule.endDate.get)
|
|
776
|
+
cooling_avail_rule.setStartDate(occ_rule.startDate.get)
|
|
777
|
+
cooling_avail_rule.setEndDate(occ_rule.endDate.get)
|
|
778
|
+
#set days enforced.
|
|
779
|
+
heating_avail_rule.setApplySunday(occ_rule.applySunday)
|
|
780
|
+
heating_avail_rule.setApplyMonday(occ_rule.applyMonday)
|
|
781
|
+
heating_avail_rule.setApplyTuesday(occ_rule.applyTuesday)
|
|
782
|
+
heating_avail_rule.setApplyWednesday(occ_rule.applyWednesday)
|
|
783
|
+
heating_avail_rule.setApplyThursday(occ_rule.applyThursday)
|
|
784
|
+
heating_avail_rule.setApplyFriday(occ_rule.applyFriday)
|
|
785
|
+
heating_avail_rule.setApplySaturday(occ_rule.applySaturday)
|
|
786
|
+
|
|
787
|
+
cooling_avail_rule.setApplySunday(occ_rule.applySunday)
|
|
788
|
+
cooling_avail_rule.setApplyMonday(occ_rule.applyMonday)
|
|
789
|
+
cooling_avail_rule.setApplyTuesday(occ_rule.applyTuesday)
|
|
790
|
+
cooling_avail_rule.setApplyWednesday(occ_rule.applyWednesday)
|
|
791
|
+
cooling_avail_rule.setApplyThursday(occ_rule.applyThursday)
|
|
792
|
+
cooling_avail_rule.setApplyFriday(occ_rule.applyFriday)
|
|
793
|
+
cooling_avail_rule.setApplySaturday(occ_rule.applySaturday)
|
|
794
|
+
|
|
795
|
+
|
|
796
|
+
end #loop occ_rule
|
|
797
|
+
#Make sure to set the default schedule to be the same as well.
|
|
798
|
+
heating_default_day = heating_ruleset.defaultDaySchedule()
|
|
799
|
+
heating_default_day.clearValues()
|
|
800
|
+
cooling_default_day = cooling_ruleset.defaultDaySchedule()
|
|
801
|
+
cooling_default_day.clearValues()
|
|
802
|
+
|
|
803
|
+
#iterate though hour / value pairs for 24 hour period.
|
|
804
|
+
occupancy_schedule.to_ScheduleRuleset.get.defaultDaySchedule().times().each do |time|
|
|
805
|
+
#check if time value is greater or equal to the threshold. If true set hour value to 1, else 0.
|
|
806
|
+
occupancy_schedule.to_ScheduleRuleset.get.defaultDaySchedule().getValue(time) >= threshold ? heating_default_day.addValue(time, heat_setpoint) : heating_default_day.addValue(time, heat_setback)
|
|
807
|
+
occupancy_schedule.to_ScheduleRuleset.get.defaultDaySchedule().getValue(time) >= threshold ? cooling_default_day.addValue(time, cool_setpoint) : cooling_default_day.addValue(time, cool_setback)
|
|
808
|
+
end
|
|
809
|
+
return heating_ruleset,cooling_ruleset
|
|
810
|
+
end
|
|
811
|
+
|
|
812
|
+
#Sets all values in a schedule less than min_value to min_value.
|
|
813
|
+
def self.apply_schedule_minimum(min_value,schedule)
|
|
814
|
+
schedule_ruleset = schedule.to_ScheduleRuleset.get unless schedule.to_ScheduleRuleset.empty?
|
|
815
|
+
schedule_ruleset.scheduleRules.each do |week_rule|
|
|
816
|
+
day_rule = week_rule.daySchedule()
|
|
817
|
+
times = day_rule.times()
|
|
818
|
+
times.each do |time|
|
|
819
|
+
old_value = day_rule.getValue(time).to_f
|
|
820
|
+
day_rule.removeValue(time)
|
|
821
|
+
new_value = old_value
|
|
822
|
+
new_value = min_value if old_value < min_value
|
|
823
|
+
day_rule.addValue(time, new_value)
|
|
824
|
+
end
|
|
825
|
+
end
|
|
826
|
+
end
|
|
827
|
+
|
|
828
|
+
#Sets all values in a schedule greater than max_value to max_value.
|
|
829
|
+
def self.apply_schedule_maximum(max_value,schedule)
|
|
830
|
+
schedule_ruleset = schedule.to_ScheduleRuleset.get unless schedule.to_ScheduleRuleset.empty?
|
|
831
|
+
schedule_ruleset.scheduleRules.each do |week_rule|
|
|
832
|
+
day_rule = week_rule.daySchedule()
|
|
833
|
+
times = day_rule.times()
|
|
834
|
+
times.each do |time|
|
|
835
|
+
old_value = day_rule.getValue(time).to_f
|
|
836
|
+
day_rule.removeValue(time)
|
|
837
|
+
new_value = old_value
|
|
838
|
+
new_value = max_value if old_value > max_value
|
|
839
|
+
day_rule.addValue(time, new_value)
|
|
840
|
+
end
|
|
841
|
+
end
|
|
842
|
+
end
|
|
843
|
+
|
|
844
|
+
def self.create_annual_ruleset_schedule_detailed(model,name,type,schedule_struct )
|
|
845
|
+
#create new ruleset
|
|
846
|
+
ruleset = OpenStudio::Model::ScheduleRuleset.new(model)
|
|
847
|
+
ruleset.setName(name)
|
|
848
|
+
default_day = ruleset.defaultDaySchedule
|
|
849
|
+
|
|
850
|
+
#set types limits
|
|
851
|
+
scheduletype = ""
|
|
852
|
+
case type.downcase
|
|
853
|
+
when "FRACTION".downcase
|
|
854
|
+
scheduletype = BTAP::Resources::Schedules::StandardScheduleTypeLimits::get_fraction(model)
|
|
855
|
+
when "ON_OFF".downcase
|
|
856
|
+
scheduletype = BTAP::Resources::Schedules::StandardScheduleTypeLimits::get_on_off(model)
|
|
857
|
+
when "TEMPERATURE".downcase
|
|
858
|
+
scheduletype = BTAP::Resources::Schedules::StandardScheduleTypeLimits::get_temperature(model)
|
|
859
|
+
# this will set the default day for temperatures to 23.5C
|
|
860
|
+
default_day.clearValues()
|
|
861
|
+
raise "unable to set ScheduleDay type limits" unless default_day.setScheduleTypeLimits(scheduletype)
|
|
862
|
+
default_day.addValue(BTAP::Common::get_time_from_string( "24:00"), 23.5 )
|
|
863
|
+
when "ACTIVITY".downcase
|
|
864
|
+
scheduletype = BTAP::Resources::Schedules::StandardScheduleTypeLimits::get_activity(model)
|
|
865
|
+
# this will set the default day for temperatures to 23.5C
|
|
866
|
+
default_day.clearValues()
|
|
867
|
+
raise "unable to set ScheduleDay type limits" unless default_day.setScheduleTypeLimits(scheduletype)
|
|
868
|
+
default_day.addValue(BTAP::Common::get_time_from_string( "24:00"), 120.0 )
|
|
869
|
+
else
|
|
870
|
+
#if schedule type could not be found raise an exception.
|
|
871
|
+
raise "could not find schedule limits type :" + type
|
|
872
|
+
end
|
|
873
|
+
|
|
874
|
+
#loop through each schedule ruleset.
|
|
875
|
+
schedule_struct.each do |run_period_profile|
|
|
876
|
+
start_end_dates = run_period_profile[0]
|
|
877
|
+
days_of_the_week = run_period_profile[1]
|
|
878
|
+
hourly_schedule = run_period_profile[2]
|
|
879
|
+
day_rule = OpenStudio::Model::ScheduleDay.new(model)
|
|
880
|
+
day_rule.setName( name )
|
|
881
|
+
if not day_rule.setScheduleTypeLimits(scheduletype)
|
|
882
|
+
raise "unable to set ScheduleDay type limits"
|
|
883
|
+
end
|
|
884
|
+
|
|
885
|
+
hourly_schedule.each do |hour|
|
|
886
|
+
day_rule.addValue(BTAP::Common::get_time_from_string( hour[0]), hour[1] )
|
|
887
|
+
end
|
|
888
|
+
|
|
889
|
+
#create weekday rule
|
|
890
|
+
week_rule = OpenStudio::Model::ScheduleRule.new(ruleset,day_rule)
|
|
891
|
+
#Set Default to false
|
|
892
|
+
week_rule.setApplySunday(false)
|
|
893
|
+
week_rule.setApplyMonday(false)
|
|
894
|
+
week_rule.setApplyTuesday(false)
|
|
895
|
+
week_rule.setApplyWednesday(false)
|
|
896
|
+
week_rule.setApplyThursday(false)
|
|
897
|
+
week_rule.setApplyFriday(false)
|
|
898
|
+
week_rule.setApplySaturday(false)
|
|
899
|
+
# Now set actual days it is applied.
|
|
900
|
+
week_rule.setApplySunday(true) if days_of_the_week.include?("Su") or days_of_the_week.include?("Wke") or days_of_the_week.include?("All")
|
|
901
|
+
week_rule.setApplyMonday(true) if days_of_the_week.include?("M") or days_of_the_week.include?("Wkd") or days_of_the_week.include?("All")
|
|
902
|
+
week_rule.setApplyTuesday(true) if days_of_the_week.include?("T") or days_of_the_week.include?("Wkd") or days_of_the_week.include?("All")
|
|
903
|
+
week_rule.setApplyWednesday(true) if days_of_the_week.include?("W") or days_of_the_week.include?("Wkd") or days_of_the_week.include?("All")
|
|
904
|
+
week_rule.setApplyThursday(true) if days_of_the_week.include?("Th") or days_of_the_week.include?("Wkd") or days_of_the_week.include?("All")
|
|
905
|
+
week_rule.setApplyFriday(true) if days_of_the_week.include?("F") or days_of_the_week.include?("Wkd") or days_of_the_week.include?("All")
|
|
906
|
+
week_rule.setApplySaturday(true) if days_of_the_week.include?("S") or days_of_the_week.include?("Wke") or days_of_the_week.include?("All")
|
|
907
|
+
|
|
908
|
+
#Set Period Rule
|
|
909
|
+
week_rule.setStartDate( BTAP::Common::get_date_from_string(start_end_dates[0] ) )
|
|
910
|
+
week_rule.setEndDate( BTAP::Common::get_date_from_string(start_end_dates[1] ) )
|
|
911
|
+
end
|
|
912
|
+
return ruleset
|
|
913
|
+
end
|
|
914
|
+
|
|
915
|
+
def self.create_annual_fraction_ruleset_schedule(model,name,hourArrayValues)
|
|
916
|
+
self.create_annual_ruleset_schedule(model,name,"FRACTION",hourArrayValues)
|
|
917
|
+
end
|
|
918
|
+
|
|
919
|
+
def self.create_annual_on_off_ruleset_schedule(model,name,hourArrayValues)
|
|
920
|
+
self.create_annual_ruleset_schedule(model,name,"ON_OFF",hourArrayValues)
|
|
921
|
+
end
|
|
922
|
+
|
|
923
|
+
def self.create_annual_temperature_ruleset_schedule(model,name,hourArrayValues)
|
|
924
|
+
self.create_annual_ruleset_schedule(model,name,"TEMPERATURE",hourArrayValues)
|
|
925
|
+
end
|
|
926
|
+
end # module Schedules
|
|
927
|
+
|
|
928
|
+
module Resources
|
|
929
|
+
module Envelope
|
|
930
|
+
module Constructions
|
|
931
|
+
|
|
932
|
+
# This checks if the construction layer can be modified to set thermal resistance of the whole construction to
|
|
933
|
+
# be less than the required resistance
|
|
934
|
+
# @author Chris Kirney <chris.kirney@canada.ca>
|
|
935
|
+
# @param mat_resistance <Fixnum>
|
|
936
|
+
# @param total_conductance <Fixnum>
|
|
937
|
+
# @param req_conductance <Fixnum>
|
|
938
|
+
# @return [<Fixnum>] layer resistance needed to meet construction material resistance, -999 if this is not enough
|
|
939
|
+
def self.should_modify_layer(mat_resistance:, total_conductance:, req_conductance:)
|
|
940
|
+
# Determine if the amount of resistance you can modify in this layer is greater than the amount of resistance
|
|
941
|
+
# you have to change.
|
|
942
|
+
if mat_resistance > ((1.0 / total_conductance) - (1.0 / req_conductance))
|
|
943
|
+
# If yes, determine what the resistance for this layer should be to meet the required resistance of the
|
|
944
|
+
# entire assembly. Then return the new resistance value.
|
|
945
|
+
target_res = mat_resistance - ((1.0 / total_conductance) - (1.0 / req_conductance))
|
|
946
|
+
return target_res
|
|
947
|
+
else
|
|
948
|
+
# If no, then return an unambiguous no.
|
|
949
|
+
return -999
|
|
950
|
+
end
|
|
951
|
+
end
|
|
952
|
+
end # module Constructions
|
|
953
|
+
|
|
954
|
+
module ConstructionSets
|
|
955
|
+
|
|
956
|
+
#This method set the default construction set from an OSM library file and the construction set name.
|
|
957
|
+
#params construction_library_file [String] Path to osm file that contains the contruction set to be used.
|
|
958
|
+
#params construction_set_name [String] Name of the construction set to be used.
|
|
959
|
+
def self.set_construction_set_by_file(model, construction_library_file, construction_set_name, runner = nil)
|
|
960
|
+
BTAP::runner_register("Info", "set_construction_set_by_file(#{construction_library_file}, #{construction_set_name})")
|
|
961
|
+
#check if file exists
|
|
962
|
+
unless File.exist?(construction_library_file) == true
|
|
963
|
+
BTAP::runner_register("Error", "Could not find #{construction_library_file}", runner)
|
|
964
|
+
return false
|
|
965
|
+
end
|
|
966
|
+
construction_set = BTAP::Resources::Envelope::ConstructionSets::get_construction_set_from_library(construction_library_file, construction_set_name)
|
|
967
|
+
#check if construction set name exists and can apply to the model.
|
|
968
|
+
unless model.building.get.setDefaultConstructionSet(construction_set.clone(model).to_DefaultConstructionSet.get)
|
|
969
|
+
BTAP::runner_register("Error", "Could not use default construction set #{construction_set_name} from #{construction_library_file} ", runner)
|
|
970
|
+
return false
|
|
971
|
+
end
|
|
972
|
+
#sets all surfaces to use default constructions except adiabatic, where it does a hard assignment of the interior wall construction type.
|
|
973
|
+
model.getPlanarSurfaces.sort.each { |item| item.resetConstruction }
|
|
974
|
+
#if the default construction set is defined..try to assign the interior wall to the adiabatic surfaces
|
|
975
|
+
BTAP::Resources::Envelope::assign_interior_surface_construction_to_adiabatic_surfaces(model, runner)
|
|
976
|
+
BTAP::runner_register("Info", "set_construction_set_by_file(#{construction_library_file}, #{construction_set_name}) Completed Sucessfully.")
|
|
977
|
+
return true
|
|
978
|
+
end
|
|
979
|
+
|
|
980
|
+
#This method gets construction set object from external library
|
|
981
|
+
#@author phylroy.lopez@nrcan.gc.ca
|
|
982
|
+
#@param construction_library_file [String]
|
|
983
|
+
#@param construction_set_name [String]
|
|
984
|
+
#@return [Boolean] optional_construction_set
|
|
985
|
+
def self.get_construction_set_from_library(construction_library_file, construction_set_name)
|
|
986
|
+
#Load Contruction osm library.
|
|
987
|
+
if File.exist?(construction_library_file)
|
|
988
|
+
construction_lib = BTAP::FileIO::load_osm(construction_library_file)
|
|
989
|
+
#Get construction set..
|
|
990
|
+
optional_construction_set = construction_lib.getDefaultConstructionSetByName(construction_set_name)
|
|
991
|
+
if optional_construction_set.empty?
|
|
992
|
+
raise("#{construction_set_name} does not exist in #{construction_library_file} library ")
|
|
993
|
+
else
|
|
994
|
+
return optional_construction_set.get
|
|
995
|
+
end
|
|
996
|
+
else
|
|
997
|
+
raise("Error : Construction Lib #{construction_library_file} does not exist!")
|
|
998
|
+
end
|
|
999
|
+
return false
|
|
1000
|
+
end
|
|
1001
|
+
end # module ConstructionSets
|
|
1002
|
+
end # module Envelope
|
|
1003
|
+
end # module Resources
|
|
1004
|
+
|
|
1005
|
+
# Deprecate all the methods in the BTAP module according to the proc below.
|
|
1006
|
+
# Note for this to work properly this file should be the first BTAP-related
|
|
1007
|
+
# file required by `btap.rb` so that only the methods in this file are
|
|
1008
|
+
# deprecated.
|
|
1009
|
+
@deprecate_methods = proc do |target_klass, display_klass, methods_list|
|
|
1010
|
+
methods_list.each do |method_name|
|
|
1011
|
+
old_method = target_klass.instance_method(method_name)
|
|
1012
|
+
target_klass.class_eval do
|
|
1013
|
+
define_method(method_name) do |*args, &block|
|
|
1014
|
+
Deprecated.msg(display_klass, method_name)
|
|
1015
|
+
old_method.bind_call(self, *args, &block)
|
|
1016
|
+
end
|
|
1017
|
+
end
|
|
1018
|
+
end
|
|
1019
|
+
end
|
|
1020
|
+
|
|
1021
|
+
def self.deprecate_all_nested(namespace)
|
|
1022
|
+
namespace.constants(false).select { |c| c != :Deprecated }.each do |name|
|
|
1023
|
+
next unless namespace.const_defined?(name, false)
|
|
1024
|
+
const = namespace.const_get(name)
|
|
1025
|
+
next unless const.is_a?(Module)
|
|
1026
|
+
@deprecate_methods.call(const, const, const.instance_methods(false))
|
|
1027
|
+
@deprecate_methods.call(const.singleton_class, const, const.methods(false))
|
|
1028
|
+
deprecate_all_nested(const)
|
|
1029
|
+
end
|
|
1030
|
+
end
|
|
1031
|
+
|
|
1032
|
+
deprecate_all_nested(self)
|
|
1033
|
+
end
|