openstudio-standards 0.1.4 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/data/standards/OpenStudio_Standards.xlsx +0 -0
- data/data/standards/OpenStudio_Standards_boilers.json +62 -4
- data/data/standards/OpenStudio_Standards_chillers.json +778 -68
- data/data/standards/OpenStudio_Standards_construction_sets.json +52 -93
- data/data/standards/OpenStudio_Standards_curve_biquadratics.json +36 -36
- data/data/standards/OpenStudio_Standards_curve_quadratics.json +3 -3
- data/data/standards/OpenStudio_Standards_heat_pumps.json +840 -0
- data/data/standards/OpenStudio_Standards_heat_pumps_heating.json +352 -0
- data/data/standards/OpenStudio_Standards_heat_rejection.json +48 -0
- data/data/standards/OpenStudio_Standards_motors.json +270 -0
- data/data/standards/OpenStudio_Standards_space_types.json +10390 -2824
- data/data/standards/OpenStudio_Standards_unitary_acs.json +794 -18
- data/data/weather/USA_CO_Boulder-Broomfield-Jefferson.County.AP.724699_TMY3.ddy +538 -0
- data/data/weather/USA_CO_Boulder-Broomfield-Jefferson.County.AP.724699_TMY3.epw +8768 -0
- data/data/weather/USA_CO_Boulder-Broomfield-Jefferson.County.AP.724699_TMY3.stat +493 -0
- data/data/weather/USA_CO_Denver.Intl.AP.725650_TMY3.ddy +536 -0
- data/data/weather/USA_CO_Denver.Intl.AP.725650_TMY3.epw +8768 -0
- data/data/weather/USA_CO_Denver.Intl.AP.725650_TMY3.stat +554 -0
- data/data/weather/USA_CO_Fort.Collins.AWOS.724769_TMY3.ddy +536 -0
- data/data/weather/USA_CO_Fort.Collins.AWOS.724769_TMY3.epw +8768 -0
- data/data/weather/USA_CO_Fort.Collins.AWOS.724769_TMY3.stat +554 -0
- data/data/weather/envelope_info.csv +6 -0
- data/lib/openstudio-standards.rb +10 -11
- data/lib/openstudio-standards/btap/compliance.rb +251 -969
- data/lib/openstudio-standards/btap/envelope.rb +1 -1
- data/lib/openstudio-standards/btap/fileio.rb +37 -5
- data/lib/openstudio-standards/btap/geometry.rb +27 -17
- data/lib/openstudio-standards/btap/hvac.rb +80 -27
- data/lib/openstudio-standards/hvac_sizing/{HVACSizing.CoilHeatingDXMultiSpeed.rb → Siz.CoilHeatingDXMultiSpeed.rb} +0 -0
- data/lib/openstudio-standards/hvac_sizing/Siz.ControllerOutdoorAir.rb +30 -4
- data/lib/openstudio-standards/hvac_sizing/Siz.CoolingTowerTwoSpeed.rb +61 -5
- data/lib/openstudio-standards/hvac_sizing/Siz.CoolingTowerVariableSpeed.rb +37 -7
- data/lib/openstudio-standards/hvac_sizing/Siz.DistrictCooling.rb +27 -0
- data/lib/openstudio-standards/hvac_sizing/Siz.DistrictHeating.rb +27 -0
- data/lib/openstudio-standards/hvac_sizing/Siz.HeaderedPumpsConstantSpeed.rb +55 -0
- data/lib/openstudio-standards/hvac_sizing/Siz.HeaderedPumpsVariableSpeed.rb +55 -0
- data/lib/openstudio-standards/hvac_sizing/Siz.HeatingCoolingFuels.rb +51 -9
- data/lib/openstudio-standards/hvac_sizing/Siz.Model.rb +99 -17
- data/lib/openstudio-standards/hvac_sizing/Siz.PumpConstantSpeed.rb +1 -1
- data/lib/openstudio-standards/hvac_sizing/Siz.ThermalZone.rb +29 -6
- data/lib/openstudio-standards/hvac_sizing/Siz.WaterHeaterMixed.rb +16 -0
- data/lib/openstudio-standards/prototypes/Prototype.AirTerminalSingleDuctVAVReheat.rb +43 -48
- data/lib/openstudio-standards/prototypes/Prototype.ControllerWaterCoil.rb +5 -9
- data/lib/openstudio-standards/prototypes/Prototype.Fan.rb +68 -0
- data/lib/openstudio-standards/prototypes/Prototype.FanConstantVolume.rb +39 -43
- data/lib/openstudio-standards/prototypes/Prototype.FanOnOff.rb +49 -51
- data/lib/openstudio-standards/prototypes/Prototype.FanVariableVolume.rb +55 -61
- data/lib/openstudio-standards/prototypes/Prototype.FanZoneExhaust.rb +8 -10
- data/lib/openstudio-standards/prototypes/Prototype.HeatExchangerAirToAirSensibleAndLatent.rb +15 -20
- data/lib/openstudio-standards/prototypes/Prototype.Model.hvac.rb +330 -322
- data/lib/openstudio-standards/prototypes/Prototype.Model.rb +501 -446
- data/lib/openstudio-standards/prototypes/Prototype.Model.swh.rb +221 -230
- data/lib/openstudio-standards/prototypes/Prototype.add_objects.rb +0 -2
- data/lib/openstudio-standards/prototypes/Prototype.full_service_restaurant.rb +130 -137
- data/lib/openstudio-standards/prototypes/Prototype.high_rise_apartment.rb +374 -291
- data/lib/openstudio-standards/prototypes/Prototype.hospital.rb +146 -193
- data/lib/openstudio-standards/prototypes/Prototype.hvac_systems.rb +1315 -1113
- data/lib/openstudio-standards/prototypes/Prototype.large_hotel.rb +65 -88
- data/lib/openstudio-standards/prototypes/Prototype.large_office.rb +101 -156
- data/lib/openstudio-standards/prototypes/Prototype.medium_office.rb +46 -96
- data/lib/openstudio-standards/prototypes/Prototype.mid_rise_apartment.rb +113 -123
- data/lib/openstudio-standards/prototypes/Prototype.outpatient.rb +356 -345
- data/lib/openstudio-standards/prototypes/Prototype.primary_school.rb +48 -103
- data/lib/openstudio-standards/prototypes/Prototype.quick_service_restaurant.rb +115 -123
- data/lib/openstudio-standards/prototypes/Prototype.retail_standalone.rb +30 -39
- data/lib/openstudio-standards/prototypes/Prototype.retail_stripmall.rb +32 -45
- data/lib/openstudio-standards/prototypes/Prototype.secondary_school.rb +98 -258
- data/lib/openstudio-standards/prototypes/Prototype.small_hotel.rb +429 -474
- data/lib/openstudio-standards/prototypes/Prototype.small_office.rb +28 -36
- data/lib/openstudio-standards/prototypes/Prototype.strip_model.rb +7 -7
- data/lib/openstudio-standards/prototypes/Prototype.utilities.rb +172 -146
- data/lib/openstudio-standards/prototypes/Prototype.warehouse.rb +46 -53
- data/lib/openstudio-standards/standards/Standards.AirLoopHVAC.rb +885 -707
- data/lib/openstudio-standards/standards/Standards.AirTerminalSingleDuctParallelPIUReheat.rb +48 -57
- data/lib/openstudio-standards/standards/Standards.AirTerminalSingleDuctVAVReheat.rb +24 -31
- data/lib/openstudio-standards/standards/Standards.BoilerHotWater.rb +80 -93
- data/lib/openstudio-standards/standards/Standards.BuildingStory.rb +69 -0
- data/lib/openstudio-standards/standards/Standards.ChillerElectricEIR.rb +60 -72
- data/lib/openstudio-standards/standards/Standards.CoilCoolingDXMultiSpeed.rb +104 -108
- data/lib/openstudio-standards/standards/Standards.CoilCoolingDXSingleSpeed.rb +190 -198
- data/lib/openstudio-standards/standards/Standards.CoilCoolingDXTwoSpeed.rb +134 -146
- data/lib/openstudio-standards/standards/Standards.CoilHeatingDXMultiSpeed.rb +56 -60
- data/lib/openstudio-standards/standards/Standards.CoilHeatingDXSingleSpeed.rb +151 -161
- data/lib/openstudio-standards/standards/Standards.CoilHeatingGasMultiStage.rb +30 -34
- data/lib/openstudio-standards/standards/Standards.Construction.rb +116 -132
- data/lib/openstudio-standards/standards/Standards.CoolingTower.rb +138 -0
- data/lib/openstudio-standards/standards/Standards.CoolingTowerSingleSpeed.rb +11 -0
- data/lib/openstudio-standards/standards/Standards.CoolingTowerTwoSpeed.rb +11 -0
- data/lib/openstudio-standards/standards/Standards.CoolingTowerVariableSpeed.rb +16 -0
- data/lib/openstudio-standards/standards/Standards.Fan.rb +190 -236
- data/lib/openstudio-standards/standards/Standards.FanConstantVolume.rb +0 -2
- data/lib/openstudio-standards/standards/Standards.FanOnOff.rb +0 -2
- data/lib/openstudio-standards/standards/Standards.FanVariableVolume.rb +168 -14
- data/lib/openstudio-standards/standards/Standards.FanZoneExhaust.rb +0 -2
- data/lib/openstudio-standards/standards/Standards.HeaderedPumpsConstantSpeed.rb +33 -0
- data/lib/openstudio-standards/standards/Standards.HeaderedPumpsVariableSpeed.rb +83 -0
- data/lib/openstudio-standards/standards/Standards.HeatExchangerSensLat.rb +22 -0
- data/lib/openstudio-standards/standards/Standards.Model.rb +2385 -1622
- data/lib/openstudio-standards/standards/Standards.PlanarSurface.rb +83 -35
- data/lib/openstudio-standards/standards/Standards.PlantLoop.rb +805 -395
- data/lib/openstudio-standards/standards/Standards.Pump.rb +139 -119
- data/lib/openstudio-standards/standards/Standards.PumpConstantSpeed.rb +0 -2
- data/lib/openstudio-standards/standards/Standards.PumpVariableSpeed.rb +16 -15
- data/lib/openstudio-standards/standards/Standards.ScheduleCompact.rb +35 -0
- data/lib/openstudio-standards/standards/Standards.ScheduleConstant.rb +7 -13
- data/lib/openstudio-standards/standards/Standards.ScheduleRuleset.rb +144 -59
- data/lib/openstudio-standards/standards/Standards.Space.rb +1509 -1326
- data/lib/openstudio-standards/standards/Standards.SpaceType.rb +254 -262
- data/lib/openstudio-standards/standards/Standards.SubSurface.rb +105 -105
- data/lib/openstudio-standards/standards/Standards.Surface.rb +27 -31
- data/lib/openstudio-standards/standards/Standards.ThermalZone.rb +882 -157
- data/lib/openstudio-standards/standards/Standards.WaterHeaterMixed.rb +179 -69
- data/lib/openstudio-standards/standards/Standards.ZoneHVACComponent.rb +75 -0
- data/lib/openstudio-standards/utilities/logging.rb +31 -38
- data/lib/openstudio-standards/utilities/simulation.rb +118 -82
- data/lib/openstudio-standards/version.rb +1 -1
- data/lib/openstudio-standards/weather/Weather.Model.rb +382 -390
- data/lib/openstudio-standards/weather/Weather.stat_file.rb +159 -78
- metadata +59 -6
@@ -1,8 +1,8 @@
|
|
1
1
|
|
2
2
|
# open the class to add methods to size all HVAC equipment
|
3
3
|
class OpenStudio::Model::Model
|
4
|
-
|
5
4
|
# Load the helper libraries for
|
5
|
+
require_relative 'Prototype.Fan'
|
6
6
|
require_relative 'Prototype.FanConstantVolume'
|
7
7
|
require_relative 'Prototype.FanVariableVolume'
|
8
8
|
require_relative 'Prototype.FanOnOff'
|
@@ -17,189 +17,157 @@ class OpenStudio::Model::Model
|
|
17
17
|
# the current model with this model.
|
18
18
|
#
|
19
19
|
# @param building_type [String] the building type
|
20
|
-
# @param
|
20
|
+
# @param template [String] the template
|
21
21
|
# @param climate_zone [String] the climate zone
|
22
22
|
# @param debug [Boolean] If true, will report out more detailed debugging output
|
23
23
|
# @return [Bool] returns true if successful, false if not
|
24
24
|
# @example Create a Small Office, 90.1-2010, in ASHRAE Climate Zone 5A (Chicago)
|
25
25
|
# model.create_prototype_building('SmallOffice', '90.1-2010', 'ASHRAE 169-2006-5A')
|
26
26
|
|
27
|
-
def create_prototype_building(building_type,
|
28
|
-
|
27
|
+
def create_prototype_building(building_type, template, climate_zone, epw_file, sizing_run_dir = Dir.pwd, debug = false)
|
29
28
|
# There are no reference models for HighriseApartment at vintages Pre-1980 and 1980-2004, nor for NECB 2011. This is a quick check.
|
30
|
-
if building_type ==
|
31
|
-
if
|
32
|
-
OpenStudio
|
29
|
+
if building_type == 'HighriseApartment'
|
30
|
+
if template == 'DOE Ref Pre-1980' || template == 'DOE Ref 1980-2004'
|
31
|
+
OpenStudio.logFree(OpenStudio::Error, 'Not available', "DOE Reference models for #{building_type} at template #{template} are not available, the measure is disabled for this specific type.")
|
33
32
|
return false
|
34
|
-
elsif
|
35
|
-
OpenStudio
|
33
|
+
elsif template == 'NECB 2011'
|
34
|
+
OpenStudio.logFree(OpenStudio::Error, 'Not available', "Reference model for #{building_type} at template #{template} is not available, the measure is disabled for this specific type.")
|
36
35
|
return false
|
37
36
|
end
|
38
37
|
end
|
39
38
|
|
40
|
-
lookup_building_type =
|
39
|
+
lookup_building_type = get_lookup_name(building_type)
|
41
40
|
|
42
41
|
# Retrieve the Prototype Inputs from JSON
|
43
42
|
search_criteria = {
|
44
|
-
'template' =>
|
43
|
+
'template' => template,
|
45
44
|
'building_type' => building_type
|
46
45
|
}
|
47
46
|
|
48
|
-
prototype_input =
|
49
|
-
|
47
|
+
prototype_input = find_object($os_standards['prototype_inputs'], search_criteria, nil)
|
50
48
|
|
51
49
|
if prototype_input.nil?
|
52
|
-
OpenStudio
|
50
|
+
OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Model', "Could not find prototype inputs for #{search_criteria}, cannot create model.")
|
53
51
|
return false
|
54
52
|
end
|
55
53
|
|
56
|
-
|
57
|
-
case building_vintage
|
54
|
+
case template
|
58
55
|
when 'NECB 2011'
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
space_type_map =
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
#Getting System Fuel type types from BTAP::Environment.
|
77
|
-
BTAP::Environment::get_canadian_system_defaults_by_weatherfile_name(epw_file)
|
78
|
-
boiler_fueltype, baseboard_type, mau_type, mau_heating_coil_type, mua_cooling_type, chiller_type, heating_coil_types_sys3, heating_coil_types_sys4,heating_coil_types_sys6, fan_type = BTAP::Environment::get_canadian_system_defaults_by_weatherfile_name(epw_file)
|
79
|
-
BTAP::Compliance::NECB2011::necb_autozone_and_autosystem(self, runner=nil, use_ideal_air_loads = false, boiler_fueltype, mau_type, mau_heating_coil_type, baseboard_type, chiller_type, mua_cooling_type, heating_coil_types_sys3, heating_coil_types_sys4, heating_coil_types_sys6, fan_type )
|
80
|
-
|
81
|
-
self.set_sizing_parameters(building_type, building_vintage)
|
82
|
-
self.yearDescription.get.setDayofWeekforStartDay('Sunday')
|
83
|
-
self.add_swh(building_type, building_vintage, climate_zone, prototype_input) # note exhaust fan schedule for * common spaces.
|
84
|
-
# TO DO: routine custom_swh_tweaks sets loss coefficient to ambient for water heater, differs for each archetype
|
85
|
-
# NECB 2011 follows ASHRAE 90.1 for now, does this need to change?
|
86
|
-
self.custom_swh_tweaks(building_type, building_vintage, climate_zone, prototype_input)
|
87
|
-
# self.add_exterior_lights(building_type, building_vintage, climate_zone, prototype_input)
|
88
|
-
# self.add_occupancy_sensors(building_type, building_vintage, climate_zone)
|
89
|
-
|
90
|
-
#
|
91
|
-
|
56
|
+
load_building_type_methods(building_type, template, climate_zone)
|
57
|
+
load_geometry(building_type, template, climate_zone)
|
58
|
+
getBuilding.setName("#{template}-#{building_type}-#{climate_zone}-#{epw_file} created: #{Time.new}")
|
59
|
+
space_type_map = define_space_type_map(building_type, template, climate_zone)
|
60
|
+
assign_space_type_stubs('Space Function', template, space_type_map) # TO DO: add support for defining NECB 2011 archetype by building type (versus space function)
|
61
|
+
add_loads(template, climate_zone)
|
62
|
+
apply_infiltration_standard(template)
|
63
|
+
modify_infiltration_coefficients(building_type, template, climate_zone) # does not apply to NECB 2011 but left here for consistency
|
64
|
+
modify_surface_convection_algorithm(template)
|
65
|
+
add_constructions(lookup_building_type, template, climate_zone)
|
66
|
+
create_thermal_zones(building_type, template, climate_zone)
|
67
|
+
add_design_days_and_weather_file(building_type, template, climate_zone, epw_file)
|
68
|
+
return false if runSizingRun("#{sizing_run_dir}/SizingRun0") == false
|
69
|
+
add_hvac(building_type, template, climate_zone, prototype_input, epw_file)
|
70
|
+
add_swh(building_type, template, climate_zone, prototype_input)
|
71
|
+
apply_sizing_parameters(building_type, template)
|
72
|
+
yearDescription.get.setDayofWeekforStartDay('Sunday')
|
92
73
|
else
|
93
74
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
space_type_map =
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
75
|
+
load_building_type_methods(building_type, template, climate_zone)
|
76
|
+
load_geometry(building_type, template, climate_zone)
|
77
|
+
getBuilding.setName("#{template}-#{building_type}-#{climate_zone} created: #{Time.new}")
|
78
|
+
space_type_map = define_space_type_map(building_type, template, climate_zone)
|
79
|
+
assign_space_type_stubs(lookup_building_type, template, space_type_map)
|
80
|
+
add_loads(template, climate_zone)
|
81
|
+
apply_infiltration_standard(template)
|
82
|
+
modify_infiltration_coefficients(building_type, template, climate_zone)
|
83
|
+
modify_surface_convection_algorithm(template)
|
84
|
+
add_constructions(lookup_building_type, template, climate_zone)
|
85
|
+
create_thermal_zones(building_type, template, climate_zone)
|
86
|
+
add_hvac(building_type, template, climate_zone, prototype_input, epw_file)
|
87
|
+
custom_hvac_tweaks(building_type, template, climate_zone, prototype_input)
|
88
|
+
add_swh(building_type, template, climate_zone, prototype_input)
|
89
|
+
custom_swh_tweaks(building_type, template, climate_zone, prototype_input)
|
90
|
+
add_exterior_lights(building_type, template, climate_zone, prototype_input)
|
91
|
+
add_occupancy_sensors(building_type, template, climate_zone)
|
92
|
+
add_design_days_and_weather_file(building_type, template, climate_zone, epw_file)
|
93
|
+
apply_sizing_parameters(building_type, template)
|
94
|
+
yearDescription.get.setDayofWeekforStartDay('Sunday')
|
114
95
|
|
115
96
|
end
|
116
97
|
# set climate zone and building type
|
117
|
-
|
98
|
+
getBuilding.setStandardsBuildingType(building_type)
|
118
99
|
if climate_zone.include? 'ASHRAE 169-2006-'
|
119
|
-
|
100
|
+
getClimateZones.setClimateZone('ASHRAE', climate_zone.gsub('ASHRAE 169-2006-', ''))
|
120
101
|
end
|
121
102
|
|
122
103
|
# Perform a sizing run
|
123
|
-
if
|
104
|
+
if runSizingRun("#{sizing_run_dir}/SizingRun1") == false
|
124
105
|
return false
|
125
106
|
end
|
126
107
|
|
127
|
-
|
128
|
-
#
|
129
|
-
#
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
self.getAirLoopHVACs.sort.each do |air_loop|
|
134
|
-
|
135
|
-
if air_loop.is_multizone_vav_system
|
136
|
-
self.apply_multizone_vav_outdoor_air_sizing(building_vintage)
|
137
|
-
if self.runSizingRun("#{sizing_run_dir}/SizingRun2") == false
|
138
|
-
return false
|
139
|
-
end
|
140
|
-
break
|
141
|
-
end
|
142
|
-
end
|
108
|
+
# If there are any multizone systems, reset damper positions
|
109
|
+
# to achieve a 60% ventilation effectiveness minimum for the system
|
110
|
+
# following the ventilation rate procedure from 62.1
|
111
|
+
apply_multizone_vav_outdoor_air_sizing(template)
|
143
112
|
|
144
113
|
# Apply the prototype HVAC assumptions
|
145
114
|
# which include sizing the fan pressure rises based
|
146
115
|
# on the flow rate of the system.
|
147
|
-
|
116
|
+
apply_prototype_hvac_assumptions(building_type, template, climate_zone)
|
148
117
|
|
149
118
|
# for 90.1-2010 Outpatient, AHU2 set minimum outdoor air flow rate as 0
|
150
119
|
# AHU1 doesn't have economizer
|
151
|
-
if building_type ==
|
152
|
-
|
120
|
+
if building_type == 'Outpatient'
|
121
|
+
modify_oa_controller(template)
|
153
122
|
# For operating room 1&2 in 2010 and 2013, VAV minimum air flow is set by schedule
|
154
|
-
|
123
|
+
reset_or_room_vav_minimum_damper(prototype_input, template)
|
155
124
|
end
|
156
125
|
|
157
|
-
if building_type ==
|
158
|
-
|
126
|
+
if building_type == 'Hospital'
|
127
|
+
modify_hospital_oa_controller(template)
|
159
128
|
end
|
160
129
|
|
161
130
|
# Apply the HVAC efficiency standard
|
162
|
-
|
131
|
+
apply_hvac_efficiency_standard(template, climate_zone)
|
163
132
|
|
164
133
|
# Add daylighting controls per standard
|
165
134
|
# only four zones in large hotel have daylighting controls
|
166
135
|
# todo: YXC to merge to the main function
|
167
|
-
if building_type ==
|
168
|
-
|
169
|
-
elsif building_type ==
|
170
|
-
|
136
|
+
if building_type == 'LargeHotel'
|
137
|
+
large_hotel_add_daylighting_controls(template)
|
138
|
+
elsif building_type == 'Hospital'
|
139
|
+
hospital_add_daylighting_controls(template)
|
171
140
|
else
|
172
|
-
|
141
|
+
add_daylighting_controls(template)
|
173
142
|
end
|
174
143
|
|
175
|
-
if building_type ==
|
176
|
-
|
144
|
+
if building_type == 'QuickServiceRestaurant' || building_type == 'FullServiceRestaurant' || building_type == 'Outpatient'
|
145
|
+
update_exhaust_fan_efficiency(template)
|
177
146
|
end
|
178
147
|
|
179
|
-
if building_type ==
|
180
|
-
|
148
|
+
if building_type == 'HighriseApartment'
|
149
|
+
update_fan_efficiency
|
181
150
|
end
|
182
151
|
|
183
152
|
# Add output variables for debugging
|
184
153
|
# AHU1 doesn't have economizer
|
185
|
-
if building_type ==
|
154
|
+
if building_type == 'Outpatient'
|
186
155
|
# remove the controller:mechanical ventilation for AHU1 OA
|
187
|
-
|
156
|
+
modify_oa_controller(template)
|
188
157
|
# For operating room 1&2 in 2010 and 2013, VAV minimum air flow is set by schedule
|
189
|
-
|
158
|
+
reset_or_room_vav_minimum_damper(prototype_input, template)
|
190
159
|
end
|
191
160
|
|
192
161
|
# Add output variables for debugging
|
193
162
|
if debug
|
194
|
-
|
163
|
+
request_timeseries_outputs
|
195
164
|
end
|
196
165
|
|
197
166
|
# Finished
|
198
167
|
model_status = 'final'
|
199
|
-
|
168
|
+
save(OpenStudio::Path.new("#{sizing_run_dir}/#{model_status}.osm"), true)
|
200
169
|
|
201
170
|
return true
|
202
|
-
|
203
171
|
end
|
204
172
|
|
205
173
|
# Get the name of the building type used in lookups
|
@@ -209,7 +177,6 @@ class OpenStudio::Model::Model
|
|
209
177
|
# @return [String] returns the lookup name as a string
|
210
178
|
# @todo Unify the lookup names and eliminate this method
|
211
179
|
def get_lookup_name(building_type)
|
212
|
-
|
213
180
|
lookup_name = building_type
|
214
181
|
|
215
182
|
case building_type
|
@@ -228,18 +195,15 @@ class OpenStudio::Model::Model
|
|
228
195
|
end
|
229
196
|
|
230
197
|
return lookup_name
|
231
|
-
|
232
198
|
end
|
233
199
|
|
234
|
-
|
235
200
|
# Loads the library of methods specific to this building type
|
236
201
|
#
|
237
202
|
# @param building_type [String] the building type
|
238
|
-
# @param
|
203
|
+
# @param template [String] the template
|
239
204
|
# @param climate_zone [String] the climate zone
|
240
205
|
# @return [Bool] returns true if successful, false if not
|
241
|
-
def load_building_type_methods(building_type,
|
242
|
-
|
206
|
+
def load_building_type_methods(building_type, template, climate_zone)
|
243
207
|
building_methods = nil
|
244
208
|
|
245
209
|
case building_type
|
@@ -276,64 +240,61 @@ class OpenStudio::Model::Model
|
|
276
240
|
when 'HighriseApartment'
|
277
241
|
building_methods = 'Prototype.high_rise_apartment'
|
278
242
|
else
|
279
|
-
OpenStudio
|
243
|
+
OpenStudio.logFree(OpenStudio::Error, 'openstudio.model.Model', "Building Type = #{building_type} not recognized")
|
280
244
|
return false
|
281
245
|
end
|
282
246
|
|
283
|
-
|
284
|
-
require "#{lib_dir}/lib/openstudio-standards/prototypes/#{building_methods}"
|
247
|
+
require_relative "#{building_methods}"
|
285
248
|
|
286
249
|
return true
|
287
|
-
|
288
250
|
end
|
289
251
|
|
290
252
|
# Loads a geometry-only .osm as a starting point.
|
291
253
|
#
|
292
254
|
# @param building_type [String] the building type
|
293
|
-
# @param
|
255
|
+
# @param template [String] the template
|
294
256
|
# @param climate_zone [String] the climate zone
|
295
257
|
# @return [Bool] returns true if successful, false if not
|
296
|
-
def load_geometry(building_type,
|
297
|
-
|
298
|
-
OpenStudio::logFree(OpenStudio::Info, 'openstudio.model.Model', 'Started adding geometry')
|
258
|
+
def load_geometry(building_type, template, climate_zone)
|
259
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', 'Started adding geometry')
|
299
260
|
|
300
261
|
# Determine which geometry file to use
|
301
262
|
# based on building_type and template
|
302
|
-
# NECB 2011 geometry is not explicitly defined; for NECB 2011
|
263
|
+
# NECB 2011 geometry is not explicitly defined; for NECB 2011 template, latest ASHRAE 90.1 geometry file is assigned (implicitly)
|
303
264
|
|
304
265
|
case building_type
|
305
266
|
when 'SecondarySchool'
|
306
|
-
if
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
267
|
+
geometry_file = if template == 'DOE Ref Pre-1980' || template == 'DOE Ref 1980-2004'
|
268
|
+
'Geometry.secondary_school_pre_1980_to_2004.osm'
|
269
|
+
else
|
270
|
+
'Geometry.secondary_school.osm'
|
271
|
+
end
|
311
272
|
when 'PrimarySchool'
|
312
|
-
if
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
273
|
+
geometry_file = if template == 'DOE Ref Pre-1980' || template == 'DOE Ref 1980-2004'
|
274
|
+
'Geometry.primary_school_pre_1980_to_2004.osm'
|
275
|
+
else
|
276
|
+
'Geometry.primary_school.osm'
|
277
|
+
end
|
317
278
|
when 'SmallOffice'
|
318
|
-
if
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
279
|
+
geometry_file = if template == 'DOE Ref Pre-1980'
|
280
|
+
'Geometry.small_office_pre_1980.osm'
|
281
|
+
else
|
282
|
+
'Geometry.small_office.osm'
|
283
|
+
end
|
323
284
|
alt_search_name = 'Office'
|
324
285
|
when 'MediumOffice'
|
325
286
|
geometry_file = 'Geometry.medium_office.osm'
|
326
287
|
alt_search_name = 'Office'
|
327
288
|
when 'LargeOffice'
|
328
289
|
alt_search_name = 'Office'
|
329
|
-
case
|
330
|
-
when 'DOE Ref Pre-1980','DOE Ref 1980-2004','DOE Ref 2004'
|
290
|
+
case template
|
291
|
+
when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004', 'DOE Ref 2004'
|
331
292
|
geometry_file = 'Geometry.large_office_reference.osm'
|
332
293
|
else
|
333
294
|
geometry_file = 'Geometry.large_office_2010.osm'
|
334
295
|
end
|
335
296
|
when 'SmallHotel'
|
336
|
-
case
|
297
|
+
case template
|
337
298
|
when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004'
|
338
299
|
geometry_file = 'Geometry.small_hotel_doe.osm'
|
339
300
|
when '90.1-2004'
|
@@ -342,14 +303,14 @@ class OpenStudio::Model::Model
|
|
342
303
|
geometry_file = 'Geometry.small_hotel_pnnl2007.osm'
|
343
304
|
when '90.1-2010'
|
344
305
|
geometry_file = 'Geometry.small_hotel_pnnl2010.osm'
|
345
|
-
else #'90.1-2013'
|
306
|
+
else # '90.1-2013'
|
346
307
|
geometry_file = 'Geometry.small_hotel_pnnl2013.osm'
|
347
308
|
end
|
348
309
|
when 'LargeHotel'
|
349
|
-
case
|
350
|
-
when 'DOE Ref Pre-1980','DOE Ref 1980-2004','DOE Ref 2004'
|
310
|
+
case template
|
311
|
+
when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004', 'DOE Ref 2004'
|
351
312
|
geometry_file = 'Geometry.large_hotel.doe.osm'
|
352
|
-
when '90.1-2007','90.1-2004'
|
313
|
+
when '90.1-2007', '90.1-2004'
|
353
314
|
geometry_file = 'Geometry.large_hotel.2004_2007.osm'
|
354
315
|
when '90.1-2010'
|
355
316
|
geometry_file = 'Geometry.large_hotel.2010.osm'
|
@@ -357,19 +318,19 @@ class OpenStudio::Model::Model
|
|
357
318
|
geometry_file = 'Geometry.large_hotel.2013.osm'
|
358
319
|
end
|
359
320
|
when 'Warehouse'
|
360
|
-
case
|
361
|
-
when 'DOE Ref Pre-1980','DOE Ref 1980-2004','DOE Ref 2004'
|
321
|
+
case template
|
322
|
+
when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004', 'DOE Ref 2004'
|
362
323
|
geometry_file = 'Geometry.warehouse_pre_1980_to_2004.osm'
|
363
324
|
else
|
364
325
|
geometry_file = 'Geometry.warehouse.osm'
|
365
326
|
end
|
366
327
|
when 'RetailStandalone'
|
367
|
-
case
|
368
|
-
when 'DOE Ref Pre-1980','DOE Ref 1980-2004','DOE Ref 2004'
|
328
|
+
case template
|
329
|
+
when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004', 'DOE Ref 2004'
|
369
330
|
geometry_file = 'Geometry.retail_standalone.pre1980_post1980.osm'
|
370
|
-
when '90.1-2004','90.1-2007'
|
331
|
+
when '90.1-2004', '90.1-2007'
|
371
332
|
geometry_file = 'Geometry.retail_standalone.2004_2007.osm'
|
372
|
-
else #'90.1-2010', '90.1-2013'
|
333
|
+
else # '90.1-2010', '90.1-2013'
|
373
334
|
geometry_file = 'Geometry.retail_standalone.2010_2013.osm'
|
374
335
|
end
|
375
336
|
alt_search_name = 'Retail'
|
@@ -377,68 +338,85 @@ class OpenStudio::Model::Model
|
|
377
338
|
geometry_file = 'Geometry.retail_stripmall.osm'
|
378
339
|
alt_search_name = 'StripMall'
|
379
340
|
when 'QuickServiceRestaurant'
|
380
|
-
case
|
341
|
+
geometry_file = case template
|
381
342
|
when 'DOE Ref Pre-1980'
|
382
|
-
|
383
|
-
else #'DOE Ref 1980-2004','90.1-2010','90.1-2007','90.1-2004','90.1-2013'
|
384
|
-
|
385
|
-
|
343
|
+
'Geometry.quick_service_restaurant_pre1980.osm'
|
344
|
+
else # 'DOE Ref 1980-2004','90.1-2010','90.1-2007','90.1-2004','90.1-2013'
|
345
|
+
'Geometry.quick_service_restaurant_allothers.osm'
|
346
|
+
end
|
386
347
|
when 'FullServiceRestaurant'
|
387
|
-
case
|
348
|
+
geometry_file = case template
|
388
349
|
when 'DOE Ref Pre-1980'
|
389
|
-
|
350
|
+
'Geometry.full_service_restaurant_pre1980.osm'
|
390
351
|
else # 'DOE Ref 1980-2004','90.1-2010','90.1-2007','90.1-2004','90.1-2013'
|
391
|
-
|
392
|
-
|
352
|
+
'Geometry.full_service_restaurant_allothers.osm'
|
353
|
+
end
|
393
354
|
when 'Hospital'
|
394
355
|
geometry_file = 'Geometry.hospital.osm'
|
395
356
|
when 'Outpatient'
|
396
357
|
geometry_file = 'Geometry.outpatient.osm'
|
397
358
|
when 'MidriseApartment'
|
398
359
|
geometry_file = 'Geometry.mid_rise_apartment.osm'
|
399
|
-
when 'Office'
|
360
|
+
when 'Office' # For NECB 2011 prototypes (old)
|
400
361
|
geometry_file = 'Geometry.large_office_2010.osm'
|
401
362
|
alt_search_name = 'Office'
|
402
363
|
when 'HighriseApartment'
|
403
364
|
geometry_file = 'Geometry.high_rise_apartment.osm'
|
404
365
|
else
|
405
|
-
OpenStudio
|
366
|
+
OpenStudio.logFree(OpenStudio::Error, 'openstudio.model.Model', "Building Type = #{building_type} not recognized")
|
406
367
|
return false
|
407
368
|
end
|
408
369
|
|
409
370
|
# Load the geometry .osm
|
410
|
-
|
411
|
-
|
412
|
-
self.replace_model("#{geom_dir}/#{geometry_file}")
|
371
|
+
geom_dir = "../../../data/geometry"
|
372
|
+
replace_model("#{geom_dir}/#{geometry_file}")
|
413
373
|
|
414
|
-
OpenStudio
|
374
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', 'Finished adding geometry')
|
415
375
|
|
416
376
|
return true
|
417
|
-
|
418
377
|
end
|
419
378
|
|
420
379
|
# Replaces all objects in the current model
|
421
380
|
# with the objects in the .osm. Typically used to
|
422
381
|
# load a model as a starting point.
|
423
382
|
#
|
424
|
-
# @param
|
383
|
+
# @param rel_path_to_osm [String] the path to an .osm file, relative to this file
|
425
384
|
# @return [Bool] returns true if successful, false if not
|
426
|
-
def replace_model(
|
427
|
-
|
385
|
+
def replace_model(rel_path_to_osm)
|
428
386
|
# Take the existing model and remove all the objects
|
429
387
|
# (this is cheesy), but need to keep the same memory block
|
430
388
|
handles = OpenStudio::UUIDVector.new
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
389
|
+
objects.each { |o| handles << o.handle }
|
390
|
+
removeObjects(handles)
|
391
|
+
|
392
|
+
model = nil
|
393
|
+
if File.dirname(__FILE__)[0] == ':'
|
394
|
+
# running from embedded location
|
395
|
+
|
396
|
+
# Load geometry from the saved geometry.osm
|
397
|
+
geom_model_string = load_resource_relative(rel_path_to_osm)
|
398
|
+
|
399
|
+
# version translate from string
|
400
|
+
version_translator = OpenStudio::OSVersion::VersionTranslator.new
|
401
|
+
model = version_translator.loadModelFromString(geom_model_string)
|
402
|
+
else
|
403
|
+
abs_path = File.join(File.dirname(__FILE__), rel_path_to_osm)
|
404
|
+
|
405
|
+
# version translate from string
|
406
|
+
version_translator = OpenStudio::OSVersion::VersionTranslator.new
|
407
|
+
model = version_translator.loadModel(abs_path)
|
408
|
+
end
|
409
|
+
|
410
|
+
if model.empty?
|
411
|
+
OpenStudio.logFree(OpenStudio::Error, 'openstudio.model.Model', "Version translation failed for #{rel_path_to_osm}")
|
412
|
+
return false
|
413
|
+
end
|
414
|
+
model = model.get
|
436
415
|
|
437
416
|
# Add the objects from the geometry model to the working model
|
438
|
-
|
439
|
-
|
417
|
+
addObjects(model.toIdfFile.objects)
|
418
|
+
|
440
419
|
return true
|
441
|
-
|
442
420
|
end
|
443
421
|
|
444
422
|
# Reads in a mapping between names of space types and
|
@@ -454,44 +432,50 @@ class OpenStudio::Model::Model
|
|
454
432
|
# The hash for each building is defined inside the Prototype.building_name
|
455
433
|
# e.g. (Prototype.secondary_school.rb) file.
|
456
434
|
# @return [Bool] returns true if successful, false if not
|
457
|
-
def assign_space_type_stubs(building_type,
|
458
|
-
|
435
|
+
def assign_space_type_stubs(building_type, template, space_type_map)
|
459
436
|
space_type_map.each do |space_type_name, space_names|
|
460
437
|
# Create a new space type
|
461
438
|
stub_space_type = OpenStudio::Model::SpaceType.new(self)
|
462
439
|
stub_space_type.setStandardsBuildingType(building_type)
|
463
440
|
stub_space_type.setStandardsSpaceType(space_type_name)
|
464
441
|
stub_space_type.setName("#{building_type} #{space_type_name}")
|
465
|
-
stub_space_type.
|
442
|
+
stub_space_type.apply_rendering_color(template)
|
466
443
|
|
467
444
|
space_names.each do |space_name|
|
468
|
-
|
469
|
-
space = self.getSpaceByName(space_name)
|
470
|
-
|
445
|
+
space = getSpaceByName(space_name)
|
471
446
|
next if space.empty?
|
472
447
|
space = space.get
|
473
448
|
space.setSpaceType(stub_space_type)
|
474
|
-
|
475
|
-
OpenStudio::logFree(OpenStudio::Info, 'openstudio.model.Model', "Setting #{space.name} to #{building_type}.#{space_type_name}")
|
449
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', "Setting #{space.name} to #{building_type}.#{space_type_name}")
|
476
450
|
end
|
477
451
|
end
|
478
|
-
|
479
452
|
return true
|
480
453
|
end
|
481
454
|
|
482
|
-
def
|
455
|
+
def add_full_space_type_libs(template)
|
456
|
+
space_type_properties_list = find_objects($os_standards['space_types'], 'template' => 'NECB 2011')
|
457
|
+
space_type_properties_list.each do |space_type_property|
|
458
|
+
stub_space_type = OpenStudio::Model::SpaceType.new(self)
|
459
|
+
stub_space_type.setStandardsBuildingType(space_type_property['building_type'])
|
460
|
+
stub_space_type.setStandardsSpaceType(space_type_property['space_type'])
|
461
|
+
stub_space_type.setName("#{template}-#{space_type_property['building_type']}-#{space_type_property['space_type']}")
|
462
|
+
stub_space_type.apply_rendering_color(template)
|
463
|
+
end
|
464
|
+
add_loads(template)
|
465
|
+
end
|
466
|
+
|
467
|
+
def assign_building_story(building_type, template, climate_zone, building_story_map)
|
483
468
|
building_story_map.each do |building_story_name, space_names|
|
484
469
|
stub_building_story = OpenStudio::Model::BuildingStory.new(self)
|
485
470
|
stub_building_story.setName(building_story_name)
|
486
471
|
|
487
472
|
space_names.each do |space_name|
|
488
|
-
space =
|
473
|
+
space = getSpaceByName(space_name)
|
489
474
|
next if space.empty?
|
490
475
|
space = space.get
|
491
476
|
space.setBuildingStory(stub_building_story)
|
492
477
|
end
|
493
478
|
end
|
494
|
-
|
495
479
|
return true
|
496
480
|
end
|
497
481
|
|
@@ -502,34 +486,29 @@ class OpenStudio::Model::Model
|
|
502
486
|
# Some loads are governed by the standard, others are typical values
|
503
487
|
# pulled from sources such as the DOE Reference and DOE Prototype Buildings.
|
504
488
|
#
|
505
|
-
# @param
|
489
|
+
# @param template [String] the template to draw data from
|
506
490
|
# @param climate_zone [String] the name of the climate zone the building is in
|
507
491
|
# @return [Bool] returns true if successful, false if not
|
508
492
|
|
509
|
-
def add_loads(
|
510
|
-
|
511
|
-
OpenStudio::logFree(OpenStudio::Info, 'openstudio.model.Model', 'Started applying space types (loads)')
|
493
|
+
def add_loads(template, climate_zone = nil)
|
494
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', 'Started applying space types (loads)')
|
512
495
|
|
513
496
|
# Loop through all the space types currently in the model,
|
514
497
|
# which are placeholders, and give them appropriate loads and schedules
|
515
|
-
|
516
|
-
|
498
|
+
getSpaceTypes.sort.each do |space_type|
|
517
499
|
# Rendering color
|
518
|
-
space_type.
|
500
|
+
space_type.apply_rendering_color(template)
|
519
501
|
|
520
502
|
# Loads
|
521
|
-
space_type.
|
503
|
+
space_type.apply_internal_loads(template, true, true, true, true, true, true)
|
522
504
|
|
523
505
|
# Schedules
|
524
|
-
space_type.
|
525
|
-
|
526
|
-
|
506
|
+
space_type.apply_internal_load_schedules(template, true, true, true, true, true, true, true)
|
527
507
|
end
|
528
508
|
|
529
|
-
OpenStudio
|
509
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', 'Finished applying space types (loads)')
|
530
510
|
|
531
511
|
return true
|
532
|
-
|
533
512
|
end
|
534
513
|
|
535
514
|
# Adds code-minimum constructions based on the building type
|
@@ -539,19 +518,18 @@ class OpenStudio::Model::Model
|
|
539
518
|
# to this space type, overriding the whole-building construction set.
|
540
519
|
#
|
541
520
|
# @param building_type [String] the type of building
|
542
|
-
# @param
|
521
|
+
# @param template [String] the template to draw data from
|
543
522
|
# @param climate_zone [String] the name of the climate zone the building is in
|
544
523
|
# @return [Bool] returns true if successful, false if not
|
545
|
-
def add_constructions(building_type,
|
546
|
-
|
547
|
-
|
548
|
-
is_residential = "No" #default is nonresidential for building level
|
524
|
+
def add_constructions(building_type, template, climate_zone)
|
525
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', 'Started applying constructions')
|
526
|
+
is_residential = 'No' # default is nonresidential for building level
|
549
527
|
|
550
528
|
# Assign construction to adiabatic construction
|
551
529
|
# Assign a material to all internal mass objects
|
552
530
|
cp02_carpet_pad = OpenStudio::Model::MasslessOpaqueMaterial.new(self)
|
553
531
|
cp02_carpet_pad.setName('CP02 CARPET PAD')
|
554
|
-
cp02_carpet_pad.setRoughness(
|
532
|
+
cp02_carpet_pad.setRoughness('VeryRough')
|
555
533
|
cp02_carpet_pad.setThermalResistance(0.21648)
|
556
534
|
cp02_carpet_pad.setThermalAbsorptance(0.9)
|
557
535
|
cp02_carpet_pad.setSolarAbsorptance(0.7)
|
@@ -567,7 +545,7 @@ class OpenStudio::Model::Model
|
|
567
545
|
|
568
546
|
nonres_floor_insulation = OpenStudio::Model::MasslessOpaqueMaterial.new(self)
|
569
547
|
nonres_floor_insulation.setName('Nonres_Floor_Insulation')
|
570
|
-
nonres_floor_insulation.setRoughness(
|
548
|
+
nonres_floor_insulation.setRoughness('MediumSmooth')
|
571
549
|
nonres_floor_insulation.setThermalResistance(2.88291975297193)
|
572
550
|
nonres_floor_insulation.setThermalAbsorptance(0.9)
|
573
551
|
nonres_floor_insulation.setSolarAbsorptance(0.7)
|
@@ -599,7 +577,7 @@ class OpenStudio::Model::Model
|
|
599
577
|
wall_layers << g01_13mm_gypsum_board
|
600
578
|
wall_adiabatic_construction.setLayers(wall_layers)
|
601
579
|
|
602
|
-
m10_200mm_concrete_block_basement_wall= OpenStudio::Model::StandardOpaqueMaterial.new(self)
|
580
|
+
m10_200mm_concrete_block_basement_wall = OpenStudio::Model::StandardOpaqueMaterial.new(self)
|
603
581
|
m10_200mm_concrete_block_basement_wall.setName('M10 200mm concrete block basement wall')
|
604
582
|
m10_200mm_concrete_block_basement_wall.setRoughness('MediumRough')
|
605
583
|
m10_200mm_concrete_block_basement_wall.setThickness(0.2032)
|
@@ -620,44 +598,43 @@ class OpenStudio::Model::Model
|
|
620
598
|
basement_floor_layers << cp02_carpet_pad
|
621
599
|
basement_floor_construction.setLayers(basement_floor_layers)
|
622
600
|
|
623
|
-
|
624
|
-
if surface.outsideBoundaryCondition.to_s ==
|
625
|
-
if surface.surfaceType.to_s ==
|
601
|
+
getSurfaces.each do |surface|
|
602
|
+
if surface.outsideBoundaryCondition.to_s == 'Adiabatic'
|
603
|
+
if surface.surfaceType.to_s == 'Wall'
|
626
604
|
surface.setConstruction(wall_adiabatic_construction)
|
627
605
|
else
|
628
606
|
surface.setConstruction(floor_adiabatic_construction)
|
629
607
|
end
|
630
|
-
elsif
|
608
|
+
elsif surface.outsideBoundaryCondition.to_s == 'OtherSideCoefficients'
|
631
609
|
# Ground
|
632
|
-
if surface.surfaceType.to_s ==
|
633
|
-
surface.setOutsideBoundaryCondition(
|
610
|
+
if surface.surfaceType.to_s == 'Wall'
|
611
|
+
surface.setOutsideBoundaryCondition('Ground')
|
634
612
|
surface.setConstruction(basement_wall_construction)
|
635
613
|
else
|
636
|
-
surface.setOutsideBoundaryCondition(
|
614
|
+
surface.setOutsideBoundaryCondition('Ground')
|
637
615
|
surface.setConstruction(basement_floor_construction)
|
638
616
|
end
|
639
617
|
end
|
640
618
|
end
|
641
619
|
|
642
620
|
# Make the default construction set for the building
|
643
|
-
bldg_def_const_set =
|
621
|
+
bldg_def_const_set = add_construction_set(template, climate_zone, building_type, nil, is_residential)
|
644
622
|
|
645
623
|
if bldg_def_const_set.is_initialized
|
646
|
-
|
624
|
+
getBuilding.setDefaultConstructionSet(bldg_def_const_set.get)
|
647
625
|
else
|
648
|
-
OpenStudio
|
626
|
+
OpenStudio.logFree(OpenStudio::Error, 'openstudio.model.Model', 'Could not create default construction set for the building.')
|
649
627
|
return false
|
650
628
|
end
|
651
629
|
|
652
630
|
# Make a construction set for each space type, if one is specified
|
653
|
-
|
654
|
-
|
631
|
+
getSpaceTypes.each do |space_type|
|
655
632
|
# Get the standards building type
|
656
633
|
stds_building_type = nil
|
657
634
|
if space_type.standardsBuildingType.is_initialized
|
658
635
|
stds_building_type = space_type.standardsBuildingType.get
|
659
636
|
else
|
660
|
-
OpenStudio
|
637
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', "Space type called '#{space_type.name}' has no standards building type.")
|
661
638
|
end
|
662
639
|
|
663
640
|
# Get the standards space type
|
@@ -665,7 +642,7 @@ class OpenStudio::Model::Model
|
|
665
642
|
if space_type.standardsSpaceType.is_initialized
|
666
643
|
stds_spc_type = space_type.standardsSpaceType.get
|
667
644
|
else
|
668
|
-
OpenStudio
|
645
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', "Space type called '#{space_type.name}' has no standards space type.")
|
669
646
|
end
|
670
647
|
|
671
648
|
# If the standards space type is Attic,
|
@@ -676,40 +653,39 @@ class OpenStudio::Model::Model
|
|
676
653
|
|
677
654
|
# Attempt to make a construction set for this space type
|
678
655
|
# and assign it if it can be created.
|
679
|
-
spc_type_const_set =
|
656
|
+
spc_type_const_set = add_construction_set(template, climate_zone, stds_building_type, stds_spc_type, is_residential)
|
680
657
|
if spc_type_const_set.is_initialized
|
681
658
|
space_type.setDefaultConstructionSet(spc_type_const_set.get)
|
682
659
|
end
|
683
|
-
|
684
660
|
end
|
685
661
|
|
686
662
|
# Add construction from story level, especially for the case when there are residential and nonresidential construction in the same building
|
687
663
|
if building_type == 'SmallHotel'
|
688
|
-
|
664
|
+
getBuildingStorys.each do |story|
|
689
665
|
next if story.name.get == 'AtticStory'
|
690
666
|
puts "story = #{story.name}"
|
691
|
-
is_residential =
|
667
|
+
is_residential = 'No' # default for building story level
|
692
668
|
exterior_spaces_area = 0
|
693
669
|
story_exterior_residential_area = 0
|
694
670
|
|
695
671
|
# calculate the propotion of residential area in exterior spaces, see if this story is residential or not
|
696
|
-
story
|
697
|
-
next if space.exteriorWallArea
|
672
|
+
story.spaces.each do |space|
|
673
|
+
next if space.exteriorWallArea.zero?
|
698
674
|
space_type = space.spaceType.get
|
699
675
|
if space_type.standardsSpaceType.is_initialized
|
700
676
|
space_type_name = space_type.standardsSpaceType.get
|
701
677
|
end
|
702
|
-
data =
|
678
|
+
data = find_object($os_standards['space_types'], 'template' => template, 'building_type' => building_type, 'space_type' => space_type_name)
|
703
679
|
exterior_spaces_area += space.floorArea
|
704
|
-
story_exterior_residential_area += space.floorArea if data['is_residential'] ==
|
680
|
+
story_exterior_residential_area += space.floorArea if data['is_residential'] == 'Yes' # "Yes" is residential, "No" or nil is nonresidential
|
705
681
|
end
|
706
|
-
is_residential =
|
707
|
-
next if is_residential ==
|
682
|
+
is_residential = 'Yes' if story_exterior_residential_area / exterior_spaces_area >= 0.5
|
683
|
+
next if is_residential == 'No'
|
708
684
|
|
709
685
|
# if the story is identified as residential, assign residential construction set to the spaces on this story.
|
710
|
-
building_story_const_set =
|
686
|
+
building_story_const_set = add_construction_set(template, climate_zone, building_type, nil, is_residential)
|
711
687
|
if building_story_const_set.is_initialized
|
712
|
-
story
|
688
|
+
story.spaces.each do |space|
|
713
689
|
space.setDefaultConstructionSet(building_story_const_set.get)
|
714
690
|
end
|
715
691
|
end
|
@@ -723,7 +699,6 @@ class OpenStudio::Model::Model
|
|
723
699
|
# window_construction = sub_surface.fixedWindowConstruction.get
|
724
700
|
# sub_surface.setSkylightConstruction(window_construction)
|
725
701
|
|
726
|
-
|
727
702
|
# Assign a material to all internal mass objects
|
728
703
|
material = OpenStudio::Model::StandardOpaqueMaterial.new(self)
|
729
704
|
material.setName('Std Wood 6inch')
|
@@ -742,7 +717,7 @@ class OpenStudio::Model::Model
|
|
742
717
|
construction.setLayers(layers)
|
743
718
|
|
744
719
|
# Assign the internal mass construction to existing internal mass objects
|
745
|
-
|
720
|
+
getSpaces.each do |space|
|
746
721
|
internal_masses = space.internalMass
|
747
722
|
internal_masses.each do |internal_mass|
|
748
723
|
internal_mass.internalMassDefinition.setConstruction(construction)
|
@@ -752,21 +727,20 @@ class OpenStudio::Model::Model
|
|
752
727
|
# get all the space types that are conditioned
|
753
728
|
|
754
729
|
# not required for NECB 2011
|
755
|
-
unless
|
756
|
-
conditioned_space_names = find_conditioned_space_names(building_type,
|
730
|
+
unless template == 'NECB 2011'
|
731
|
+
conditioned_space_names = find_conditioned_space_names(building_type, template, climate_zone)
|
757
732
|
end
|
758
733
|
|
759
|
-
|
760
734
|
# add internal mass
|
761
735
|
# not required for NECB 2011
|
762
|
-
unless (
|
763
|
-
|
764
|
-
|
736
|
+
unless (template == 'NECB 2011') ||
|
737
|
+
((building_type == 'SmallHotel') &&
|
738
|
+
(template == '90.1-2004' || template == '90.1-2007' || template == '90.1-2010' || template == '90.1-2013'))
|
765
739
|
internal_mass_def = OpenStudio::Model::InternalMassDefinition.new(self)
|
766
740
|
internal_mass_def.setSurfaceAreaperSpaceFloorArea(2.0)
|
767
741
|
internal_mass_def.setConstruction(construction)
|
768
742
|
conditioned_space_names.each do |conditioned_space_name|
|
769
|
-
space =
|
743
|
+
space = getSpaceByName(conditioned_space_name)
|
770
744
|
if space.is_initialized
|
771
745
|
space = space.get
|
772
746
|
internal_mass = OpenStudio::Model::InternalMass.new(internal_mass_def)
|
@@ -776,10 +750,9 @@ class OpenStudio::Model::Model
|
|
776
750
|
end
|
777
751
|
end
|
778
752
|
|
779
|
-
OpenStudio
|
753
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', 'Finished applying constructions')
|
780
754
|
|
781
755
|
return true
|
782
|
-
|
783
756
|
end
|
784
757
|
|
785
758
|
# Get the list of all conditioned spaces, as defined for each building in the
|
@@ -788,8 +761,8 @@ class OpenStudio::Model::Model
|
|
788
761
|
#
|
789
762
|
# @param (see #add_constructions)
|
790
763
|
# @return [Array<String>] returns an array of space names as strings
|
791
|
-
def find_conditioned_space_names(building_type,
|
792
|
-
system_to_space_map = define_hvac_system_map(building_type,
|
764
|
+
def find_conditioned_space_names(building_type, template, climate_zone)
|
765
|
+
system_to_space_map = define_hvac_system_map(building_type, template, climate_zone)
|
793
766
|
conditioned_space_names = OpenStudio::StringVector.new
|
794
767
|
system_to_space_map.each do |system|
|
795
768
|
system['space_names'].each do |space_name|
|
@@ -805,23 +778,25 @@ class OpenStudio::Model::Model
|
|
805
778
|
#
|
806
779
|
# @param (see #add_constructions)
|
807
780
|
# @return [Bool] returns true if successful, false if not
|
808
|
-
def create_thermal_zones(building_type,
|
781
|
+
def create_thermal_zones(building_type, template, climate_zone)
|
782
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', 'Started creating thermal zones')
|
809
783
|
|
810
|
-
|
784
|
+
# Remove any Thermal zones assigned
|
785
|
+
getThermalZones.each(&:remove)
|
811
786
|
|
812
787
|
# This map define the multipliers for spaces with multipliers not equals to 1
|
813
788
|
case building_type
|
814
|
-
when 'LargeHotel', 'MidriseApartment','LargeOffice','Hospital'
|
815
|
-
space_multiplier_map =
|
789
|
+
when 'LargeHotel', 'MidriseApartment', 'LargeOffice', 'Hospital'
|
790
|
+
space_multiplier_map = define_space_multiplier
|
816
791
|
else
|
817
|
-
space_multiplier_map ={}
|
792
|
+
space_multiplier_map = {}
|
818
793
|
end
|
819
794
|
|
820
795
|
# Create a thermal zone for each space in the self
|
821
|
-
|
796
|
+
getSpaces.each do |space|
|
822
797
|
zone = OpenStudio::Model::ThermalZone.new(self)
|
823
798
|
zone.setName("#{space.name} ZN")
|
824
|
-
|
799
|
+
unless space_multiplier_map[space.name.to_s].nil?
|
825
800
|
zone.setMultiplier(space_multiplier_map[space.name.to_s])
|
826
801
|
end
|
827
802
|
space.setThermalZone(zone)
|
@@ -832,19 +807,19 @@ class OpenStudio::Model::Model
|
|
832
807
|
# Add a thermostat
|
833
808
|
space_type_name = space.spaceType.get.name.get
|
834
809
|
thermostat_name = space_type_name + ' Thermostat'
|
835
|
-
thermostat =
|
810
|
+
thermostat = getThermostatSetpointDualSetpointByName(thermostat_name)
|
836
811
|
if thermostat.empty?
|
837
|
-
OpenStudio
|
812
|
+
OpenStudio.logFree(OpenStudio::Error, 'openstudio.model.Model', "Thermostat #{thermostat_name} not found for space name: #{space.name}")
|
838
813
|
else
|
839
|
-
|
840
|
-
zone.setThermostatSetpointDualSetpoint(
|
814
|
+
thermostat_clone = thermostat.get.clone(self).to_ThermostatSetpointDualSetpoint.get
|
815
|
+
zone.setThermostatSetpointDualSetpoint(thermostat_clone)
|
816
|
+
# Set Ideal loads to thermal zone for sizing.
|
817
|
+
ideal_loads = OpenStudio::Model::ZoneHVACIdealLoadsAirSystem.new(self)
|
818
|
+
ideal_loads.addToThermalZone(zone)
|
841
819
|
end
|
842
820
|
end
|
843
821
|
|
844
|
-
OpenStudio
|
845
|
-
|
846
|
-
return true
|
847
|
-
|
822
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', 'Finished creating thermal zones')
|
848
823
|
end
|
849
824
|
|
850
825
|
# Adds occupancy sensors to certain space types per
|
@@ -853,23 +828,22 @@ class OpenStudio::Model::Model
|
|
853
828
|
# @param (see #add_constructions)
|
854
829
|
# @return [Bool] returns true if successful, false if not
|
855
830
|
# @todo genericize and move this method to Standards.Space
|
856
|
-
def add_occupancy_sensors(building_type,
|
857
|
-
|
831
|
+
def add_occupancy_sensors(building_type, template, climate_zone)
|
858
832
|
# Only add occupancy sensors for 90.1-2010
|
859
|
-
case
|
833
|
+
case template
|
860
834
|
when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004', '90.1-2004', '90.1-2007'
|
861
835
|
return true
|
862
836
|
end
|
863
837
|
|
864
|
-
OpenStudio
|
838
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', 'Started Adding Occupancy Sensors')
|
865
839
|
|
866
840
|
space_type_reduction_map = {
|
867
|
-
'SecondarySchool' => {'Classroom' => 0.32, 'Restroom' => 0.34, 'Office' => 0.22},
|
868
|
-
'PrimarySchool' => {'Classroom' => 0.32, 'Restroom' => 0.34, 'Office' => 0.22}
|
841
|
+
'SecondarySchool' => { 'Classroom' => 0.32, 'Restroom' => 0.34, 'Office' => 0.22 },
|
842
|
+
'PrimarySchool' => { 'Classroom' => 0.32, 'Restroom' => 0.34, 'Office' => 0.22 }
|
869
843
|
}
|
870
844
|
|
871
845
|
# Loop through all the space types and reduce lighting operation schedule fractions as-specified
|
872
|
-
|
846
|
+
getSpaceTypes.each do |space_type|
|
873
847
|
# Skip space types with no standards building type
|
874
848
|
next if space_type.standardsBuildingType.empty?
|
875
849
|
stds_bldg_type = space_type.standardsBuildingType.get
|
@@ -879,8 +853,8 @@ class OpenStudio::Model::Model
|
|
879
853
|
stds_spc_type = space_type.standardsSpaceType.get
|
880
854
|
|
881
855
|
# Skip building types and space types that aren't listed in the hash
|
882
|
-
next unless space_type_reduction_map.
|
883
|
-
next unless space_type_reduction_map[stds_bldg_type].
|
856
|
+
next unless space_type_reduction_map.key?(stds_bldg_type)
|
857
|
+
next unless space_type_reduction_map[stds_bldg_type].key?(stds_spc_type)
|
884
858
|
|
885
859
|
# Get the reduction fraction multiplier
|
886
860
|
red_multiplier = 1 - space_type_reduction_map[stds_bldg_type][stds_spc_type]
|
@@ -912,33 +886,6 @@ class OpenStudio::Model::Model
|
|
912
886
|
new_lights_sch.setName("#{lights_sch_name} OccSensor Reduction")
|
913
887
|
reduced_lights_schs[lights_sch_name] = new_lights_sch
|
914
888
|
|
915
|
-
# Method to multiply the values in a day schedule by a specified value
|
916
|
-
# but only when the existing value is higher than a specified lower limit.
|
917
|
-
# This limit prevents occupancy sensors from affecting unoccupied hours.
|
918
|
-
def multiply_schedule(day_sch, multiplier, limit)
|
919
|
-
# Record the original times and values
|
920
|
-
times = day_sch.times
|
921
|
-
values = day_sch.values
|
922
|
-
|
923
|
-
# Remove the original times and values
|
924
|
-
day_sch.clearValues
|
925
|
-
|
926
|
-
# Create new values by using the multiplier on the original values
|
927
|
-
new_values = []
|
928
|
-
for i in 0..(values.length - 1)
|
929
|
-
if values[i] > limit
|
930
|
-
new_values << values[i] * multiplier
|
931
|
-
else
|
932
|
-
new_values << values[i]
|
933
|
-
end
|
934
|
-
end
|
935
|
-
|
936
|
-
# Add the revised time/value pairs to the schedule
|
937
|
-
for i in 0..(new_values.length - 1)
|
938
|
-
day_sch.addValue(times[i], new_values[i])
|
939
|
-
end
|
940
|
-
end #end reduce schedule
|
941
|
-
|
942
889
|
# Reduce default day schedule
|
943
890
|
multiply_schedule(new_lights_sch.defaultDaySchedule, red_multiplier, 0.25)
|
944
891
|
|
@@ -946,8 +893,7 @@ class OpenStudio::Model::Model
|
|
946
893
|
new_lights_sch.scheduleRules.each do |sch_rule|
|
947
894
|
multiply_schedule(sch_rule.daySchedule, red_multiplier, 0.25)
|
948
895
|
end
|
949
|
-
|
950
|
-
end #end of lights_sch_names.uniq.each do
|
896
|
+
end # end of lights_sch_names.uniq.each do
|
951
897
|
|
952
898
|
# Loop through all lights instances, replacing old lights
|
953
899
|
# schedules with the reduced schedules.
|
@@ -957,17 +903,15 @@ class OpenStudio::Model::Model
|
|
957
903
|
old_lights_sch_name = light.schedule.get.name.to_s
|
958
904
|
if reduced_lights_schs[old_lights_sch_name]
|
959
905
|
light.setSchedule(reduced_lights_schs[old_lights_sch_name])
|
960
|
-
OpenStudio
|
906
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', "Occupancy sensor reduction added to '#{light.name}'")
|
961
907
|
end
|
962
908
|
end
|
963
|
-
|
964
909
|
end
|
965
910
|
|
966
|
-
OpenStudio
|
911
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', 'Finished Adding Occupancy Sensors')
|
967
912
|
|
968
913
|
return true
|
969
|
-
|
970
|
-
end #add occupancy sensors
|
914
|
+
end # add occupancy sensors
|
971
915
|
|
972
916
|
# Adds exterior lights to the building, as specified
|
973
917
|
# in OpenStudio_Standards_prototype_inputs
|
@@ -977,11 +921,11 @@ class OpenStudio::Model::Model
|
|
977
921
|
# @todo translate w/linear foot of facade, door, parking, etc
|
978
922
|
# into lookup table and implement that way instead of hard-coding as
|
979
923
|
# inputs in the spreadsheet.
|
980
|
-
def add_exterior_lights(building_type,
|
981
|
-
# TODO Standards - translate w/linear foot of facade, door, parking, etc
|
924
|
+
def add_exterior_lights(building_type, template, climate_zone, prototype_input)
|
925
|
+
# TODO: Standards - translate w/linear foot of facade, door, parking, etc
|
982
926
|
# into lookup table and implement that way instead of hard-coding as
|
983
927
|
# inputs in the spreadsheet.
|
984
|
-
OpenStudio
|
928
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', 'Started adding exterior lights')
|
985
929
|
|
986
930
|
# Occupancy Sensing Exterior Lights
|
987
931
|
# which reduce to 70% power when no one is around.
|
@@ -992,7 +936,7 @@ class OpenStudio::Model::Model
|
|
992
936
|
occ_sens_ext_lts_def = OpenStudio::Model::ExteriorLightsDefinition.new(self)
|
993
937
|
occ_sens_ext_lts_def.setName("#{occ_sens_ext_lts_name} Def")
|
994
938
|
occ_sens_ext_lts_def.setDesignLevel(occ_sens_ext_lts_power)
|
995
|
-
occ_sens_ext_lts_sch =
|
939
|
+
occ_sens_ext_lts_sch = add_schedule(occ_sens_ext_lts_sch_name)
|
996
940
|
occ_sens_ext_lts = OpenStudio::Model::ExteriorLights.new(occ_sens_ext_lts_def, occ_sens_ext_lts_sch)
|
997
941
|
occ_sens_ext_lts.setName("#{occ_sens_ext_lts_name} Def")
|
998
942
|
occ_sens_ext_lts.setControlOption('AstronomicalClock')
|
@@ -1007,7 +951,7 @@ class OpenStudio::Model::Model
|
|
1007
951
|
nondimming_ext_lts_def = OpenStudio::Model::ExteriorLightsDefinition.new(self)
|
1008
952
|
nondimming_ext_lts_def.setName("#{nondimming_ext_lts_name} Def")
|
1009
953
|
nondimming_ext_lts_def.setDesignLevel(nondimming_ext_lts_power)
|
1010
|
-
nondimming_ext_lts_sch =
|
954
|
+
nondimming_ext_lts_sch = add_schedule(nondimming_ext_lts_sch_name)
|
1011
955
|
nondimming_ext_lts = OpenStudio::Model::ExteriorLights.new(nondimming_ext_lts_def, nondimming_ext_lts_sch)
|
1012
956
|
nondimming_ext_lts.setName("#{nondimming_ext_lts_name} Def")
|
1013
957
|
nondimming_ext_lts.setControlOption('AstronomicalClock')
|
@@ -1023,9 +967,9 @@ class OpenStudio::Model::Model
|
|
1023
967
|
fuel_ext_def = OpenStudio::Model::ExteriorLightsDefinition.new(self)
|
1024
968
|
fuel_ext_def.setName("#{fuel_ext_name} Def")
|
1025
969
|
fuel_ext_def.setDesignLevel(fuel_ext_power)
|
1026
|
-
fuel_ext_sch =
|
970
|
+
fuel_ext_sch = add_schedule(fuel_ext_sch_name)
|
1027
971
|
fuel_ext_lts = OpenStudio::Model::ExteriorLights.new(fuel_ext_def, fuel_ext_sch)
|
1028
|
-
fuel_ext_lts.setName(
|
972
|
+
fuel_ext_lts.setName(fuel_ext_name.to_s)
|
1029
973
|
fuel_ext_lts.setControlOption('ScheduleNameOnly')
|
1030
974
|
end
|
1031
975
|
|
@@ -1036,16 +980,16 @@ class OpenStudio::Model::Model
|
|
1036
980
|
fuel_ext_def = OpenStudio::Model::ExteriorLightsDefinition.new(self)
|
1037
981
|
fuel_ext_def.setName("#{fuel_ext_name} Def")
|
1038
982
|
fuel_ext_def.setDesignLevel(fuel_ext_power)
|
1039
|
-
fuel_ext_sch =
|
983
|
+
fuel_ext_sch = add_schedule(fuel_ext_sch_name)
|
1040
984
|
fuel_ext_lts = OpenStudio::Model::ExteriorLights.new(fuel_ext_def, fuel_ext_sch)
|
1041
|
-
fuel_ext_lts.setName(
|
985
|
+
fuel_ext_lts.setName(fuel_ext_name.to_s)
|
1042
986
|
fuel_ext_lts.setControlOption('ScheduleNameOnly')
|
1043
987
|
end
|
1044
988
|
|
1045
|
-
OpenStudio
|
989
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', 'Finished adding exterior lights')
|
1046
990
|
|
1047
991
|
return true
|
1048
|
-
end #add exterior lights
|
992
|
+
end # add exterior lights
|
1049
993
|
|
1050
994
|
# Changes the infiltration coefficients for the prototype vintages.
|
1051
995
|
#
|
@@ -1053,41 +997,41 @@ class OpenStudio::Model::Model
|
|
1053
997
|
# @return [Bool] returns true if successful, false if not
|
1054
998
|
# @todo Consistency - make prototype and reference vintages consistent
|
1055
999
|
# @todo Add 90.1-2013?
|
1056
|
-
def modify_infiltration_coefficients(building_type,
|
1000
|
+
def modify_infiltration_coefficients(building_type, template, climate_zone)
|
1057
1001
|
# Select the terrain type, which
|
1058
1002
|
# impacts wind speed, and in turn infiltration
|
1059
1003
|
terrain = 'City'
|
1060
|
-
case
|
1004
|
+
case template
|
1061
1005
|
when '90.1-2004', '90.1-2007', '90.1-2010', '90.1-2013'
|
1062
1006
|
case building_type
|
1063
1007
|
when 'Warehouse'
|
1064
|
-
|
1008
|
+
terrain = 'Urban'
|
1065
1009
|
when 'SmallHotel'
|
1066
|
-
|
1010
|
+
terrain = 'Suburbs'
|
1067
1011
|
end
|
1068
1012
|
end
|
1069
1013
|
# Set the terrain type
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1090
|
-
|
1014
|
+
getSite.setTerrain(terrain)
|
1015
|
+
|
1016
|
+
# modify the infiltration coefficients for 90.1-2004, 90.1-2007, 90.1-2010, 90.1-2013
|
1017
|
+
return true unless template == '90.1-2004' || template == '90.1-2007' || template == '90.1-2010' || template == '90.1-2013' || template == 'NECB 2011'
|
1018
|
+
|
1019
|
+
# The pre-1980 and 1980-2004 buildings have this:
|
1020
|
+
# 1.0000, !- Constant Term Coefficient
|
1021
|
+
# 0.0000, !- Temperature Term Coefficient
|
1022
|
+
# 0.0000, !- Velocity Term Coefficient
|
1023
|
+
# 0.0000; !- Velocity Squared Term Coefficient
|
1024
|
+
# The 90.1-2010 buildings have this:
|
1025
|
+
# 0.0000, !- Constant Term Coefficient
|
1026
|
+
# 0.0000, !- Temperature Term Coefficient
|
1027
|
+
# 0.224, !- Velocity Term Coefficient
|
1028
|
+
# 0.0000; !- Velocity Squared Term Coefficient
|
1029
|
+
getSpaceInfiltrationDesignFlowRates.each do |infiltration|
|
1030
|
+
infiltration.setConstantTermCoefficient(0.0)
|
1031
|
+
infiltration.setTemperatureTermCoefficient(0.0)
|
1032
|
+
infiltration.setVelocityTermCoefficient(0.224)
|
1033
|
+
infiltration.setVelocitySquaredTermCoefficient(0.0)
|
1034
|
+
end
|
1091
1035
|
end
|
1092
1036
|
|
1093
1037
|
# Sets the inside and outside convection algorithms for different vintages
|
@@ -1095,12 +1039,11 @@ class OpenStudio::Model::Model
|
|
1095
1039
|
# @param (see #add_constructions)
|
1096
1040
|
# @return [Bool] returns true if successful, false if not
|
1097
1041
|
# @todo Consistency - make prototype and reference vintages consistent
|
1098
|
-
def modify_surface_convection_algorithm(
|
1099
|
-
|
1100
|
-
|
1101
|
-
outside = self.getOutsideSurfaceConvectionAlgorithm
|
1042
|
+
def modify_surface_convection_algorithm(template)
|
1043
|
+
inside = getInsideSurfaceConvectionAlgorithm
|
1044
|
+
outside = getOutsideSurfaceConvectionAlgorithm
|
1102
1045
|
|
1103
|
-
case
|
1046
|
+
case template
|
1104
1047
|
when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004'
|
1105
1048
|
inside.setAlgorithm('TARP')
|
1106
1049
|
outside.setAlgorithm('DOE-2')
|
@@ -1108,22 +1051,19 @@ class OpenStudio::Model::Model
|
|
1108
1051
|
inside.setAlgorithm('TARP')
|
1109
1052
|
outside.setAlgorithm('TARP')
|
1110
1053
|
end
|
1111
|
-
|
1112
1054
|
end
|
1113
1055
|
|
1114
|
-
|
1115
1056
|
# Changes the infiltration coefficients for the prototype vintages.
|
1116
1057
|
#
|
1117
1058
|
# @param (see #add_constructions)
|
1118
1059
|
# @return [Bool] returns true if successful, false if not
|
1119
1060
|
# @todo Consistency - make sizing factors consistent
|
1120
1061
|
# between building types, climate zones, and vintages?
|
1121
|
-
def
|
1122
|
-
|
1062
|
+
def apply_sizing_parameters(building_type, template)
|
1123
1063
|
# Default unless otherwise specified
|
1124
1064
|
clg = 1.2
|
1125
1065
|
htg = 1.2
|
1126
|
-
case
|
1066
|
+
case template
|
1127
1067
|
when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004'
|
1128
1068
|
case building_type
|
1129
1069
|
when 'PrimarySchool', 'SecondarySchool', 'Outpatient'
|
@@ -1144,50 +1084,55 @@ class OpenStudio::Model::Model
|
|
1144
1084
|
htg = 1.3
|
1145
1085
|
end
|
1146
1086
|
|
1147
|
-
sizing_params =
|
1087
|
+
sizing_params = getSizingParameters
|
1148
1088
|
sizing_params.setHeatingSizingFactor(htg)
|
1149
1089
|
sizing_params.setCoolingSizingFactor(clg)
|
1150
1090
|
|
1151
|
-
OpenStudio
|
1152
|
-
|
1091
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.prototype.Model', "Set sizing factors to #{htg} for heating and #{clg} for cooling.")
|
1153
1092
|
end
|
1154
1093
|
|
1155
|
-
def
|
1156
|
-
|
1157
|
-
OpenStudio::logFree(OpenStudio::Info, 'openstudio.model.Model', 'Started applying prototype HVAC assumptions.')
|
1094
|
+
def apply_prototype_hvac_assumptions(building_type, template, climate_zone)
|
1095
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', 'Started applying prototype HVAC assumptions.')
|
1158
1096
|
|
1159
1097
|
##### Apply equipment efficiencies
|
1160
1098
|
|
1161
1099
|
# Fans
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1100
|
+
# Pressure Rise
|
1101
|
+
getFanConstantVolumes.sort.each { |obj| obj.apply_prototype_fan_pressure_rise(building_type, template, climate_zone) }
|
1102
|
+
getFanVariableVolumes.sort.each { |obj| obj.apply_prototype_fan_pressure_rise(building_type, template, climate_zone) }
|
1103
|
+
getFanOnOffs.sort.each { |obj| obj.apply_prototype_fan_pressure_rise(building_type, template, climate_zone) }
|
1104
|
+
getFanZoneExhausts.sort.each(&:apply_prototype_fan_pressure_rise)
|
1105
|
+
|
1106
|
+
# Motor Efficiency
|
1107
|
+
getFanConstantVolumes.sort.each { |obj| obj.apply_prototype_fan_efficiency(template) }
|
1108
|
+
getFanVariableVolumes.sort.each { |obj| obj.apply_prototype_fan_efficiency(template) }
|
1109
|
+
getFanOnOffs.sort.each { |obj| obj.apply_prototype_fan_efficiency(template) }
|
1110
|
+
getFanZoneExhausts.sort.each { |obj| obj.apply_prototype_fan_efficiency(template) }
|
1166
1111
|
|
1167
1112
|
##### Add Economizers
|
1168
1113
|
|
1169
|
-
if
|
1114
|
+
if template != 'NECB 2011'
|
1170
1115
|
# Create an economizer maximum OA fraction of 70%
|
1171
1116
|
# to reflect damper leakage per PNNL
|
1172
1117
|
econ_max_70_pct_oa_sch = OpenStudio::Model::ScheduleRuleset.new(self)
|
1173
|
-
econ_max_70_pct_oa_sch.setName(
|
1174
|
-
econ_max_70_pct_oa_sch.defaultDaySchedule.setName(
|
1175
|
-
econ_max_70_pct_oa_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0,24,0,0), 0.7)
|
1118
|
+
econ_max_70_pct_oa_sch.setName('Economizer Max OA Fraction 70 pct')
|
1119
|
+
econ_max_70_pct_oa_sch.defaultDaySchedule.setName('Economizer Max OA Fraction 70 pct Default')
|
1120
|
+
econ_max_70_pct_oa_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), 0.7)
|
1176
1121
|
else
|
1177
1122
|
# NECB 2011 prescribes ability to provide 100% OA (5.2.2.7-5.2.2.9)
|
1178
1123
|
econ_max_100_pct_oa_sch = OpenStudio::Model::ScheduleRuleset.new(self)
|
1179
|
-
econ_max_100_pct_oa_sch.setName(
|
1180
|
-
econ_max_100_pct_oa_sch.defaultDaySchedule.setName(
|
1181
|
-
econ_max_100_pct_oa_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0,24,0,0), 1.0)
|
1124
|
+
econ_max_100_pct_oa_sch.setName('Economizer Max OA Fraction 100 pct')
|
1125
|
+
econ_max_100_pct_oa_sch.defaultDaySchedule.setName('Economizer Max OA Fraction 100 pct Default')
|
1126
|
+
econ_max_100_pct_oa_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), 1.0)
|
1182
1127
|
end
|
1183
1128
|
|
1184
1129
|
# Check each airloop
|
1185
|
-
|
1186
|
-
if air_loop.
|
1130
|
+
getAirLoopHVACs.each do |air_loop|
|
1131
|
+
if air_loop.economizer_required?(template, climate_zone) == true
|
1187
1132
|
# If an economizer is required, determine the economizer type
|
1188
1133
|
# in the prototype buildings, which depends on climate zone.
|
1189
1134
|
economizer_type = nil
|
1190
|
-
case
|
1135
|
+
case template
|
1191
1136
|
when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004', '90.1-2004', '90.1-2007'
|
1192
1137
|
economizer_type = 'DifferentialDryBulb'
|
1193
1138
|
when '90.1-2010', '90.1-2013'
|
@@ -1213,37 +1158,33 @@ class OpenStudio::Model::Model
|
|
1213
1158
|
if oa_sys.is_initialized
|
1214
1159
|
oa_sys = oa_sys.get
|
1215
1160
|
else
|
1216
|
-
OpenStudio
|
1161
|
+
OpenStudio.logFree(OpenStudio::Error, 'openstudio.prototype.Model', "#{air_loop.name} is required to have an economizer, but it has no OA system.")
|
1217
1162
|
next
|
1218
1163
|
end
|
1219
1164
|
oa_control = oa_sys.getControllerOutdoorAir
|
1220
1165
|
oa_control.setEconomizerControlType(economizer_type)
|
1221
|
-
if
|
1222
|
-
#oa_control.setMaximumFractionofOutdoorAirSchedule(econ_max_70_pct_oa_sch)
|
1223
|
-
else
|
1224
|
-
#oa_control.setMaximumFractionofOutdoorAirSchedule(econ_max_100_pct_oa_sch)
|
1166
|
+
if template != 'NECB 2011'
|
1167
|
+
# oa_control.setMaximumFractionofOutdoorAirSchedule(econ_max_70_pct_oa_sch)
|
1225
1168
|
end
|
1226
1169
|
|
1227
1170
|
# Check that the economizer type set by the prototypes
|
1228
1171
|
# is not prohibited by code. If it is, change to no economizer.
|
1229
|
-
unless air_loop.
|
1230
|
-
OpenStudio
|
1172
|
+
unless air_loop.economizer_type_allowable?(template, climate_zone)
|
1173
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.prototype.Model', "#{air_loop.name} is required to have an economizer, but the type chosen, #{economizer_type} is prohibited by code for #{template}, climate zone #{climate_zone}. Economizer type will be switched to No Economizer.")
|
1231
1174
|
oa_control.setEconomizerControlType('NoEconomizer')
|
1232
1175
|
end
|
1233
1176
|
|
1234
1177
|
end
|
1235
1178
|
end
|
1236
1179
|
|
1237
|
-
# TODO What is the logic behind hard-sizing
|
1180
|
+
# TODO: What is the logic behind hard-sizing
|
1238
1181
|
# hot water coil convergence tolerances?
|
1239
|
-
|
1240
|
-
|
1241
|
-
OpenStudio::logFree(OpenStudio::Info, 'openstudio.model.Model', 'Finished applying prototype HVAC assumptions.')
|
1182
|
+
getControllerWaterCoils.sort.each(&:set_convergence_limits)
|
1242
1183
|
|
1184
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', 'Finished applying prototype HVAC assumptions.')
|
1243
1185
|
end
|
1244
1186
|
|
1245
1187
|
def add_debugging_variables(type)
|
1246
|
-
|
1247
1188
|
# 'detailed'
|
1248
1189
|
# 'timestep'
|
1249
1190
|
# 'hourly'
|
@@ -1253,44 +1194,41 @@ class OpenStudio::Model::Model
|
|
1253
1194
|
vars = []
|
1254
1195
|
case type
|
1255
1196
|
when 'service_water_heating'
|
1256
|
-
var_names << ['Water Heater Water Volume Flow Rate','timestep']
|
1257
|
-
var_names << ['Water Use Equipment Hot Water Volume Flow Rate','timestep']
|
1258
|
-
var_names << ['Water Use Equipment Cold Water Volume Flow Rate','timestep']
|
1259
|
-
var_names << ['Water Use Equipment Hot Water Temperature','timestep']
|
1260
|
-
var_names << ['Water Use Equipment Cold Water Temperature','timestep']
|
1261
|
-
var_names << ['Water Use Equipment Mains Water Volume','timestep']
|
1262
|
-
var_names << ['Water Use Equipment Target Water Temperature','timestep']
|
1263
|
-
var_names << ['Water Use Equipment Mixed Water Temperature','timestep']
|
1264
|
-
var_names << ['Water Heater Tank Temperature','timestep']
|
1265
|
-
var_names << ['Water Heater Use Side Mass Flow Rate','timestep']
|
1266
|
-
var_names << ['Water Heater Heating Rate','timestep']
|
1267
|
-
var_names << ['Water Heater Water Volume Flow Rate','timestep']
|
1268
|
-
var_names << ['Water Heater Water Volume','timestep']
|
1197
|
+
var_names << ['Water Heater Water Volume Flow Rate', 'timestep']
|
1198
|
+
var_names << ['Water Use Equipment Hot Water Volume Flow Rate', 'timestep']
|
1199
|
+
var_names << ['Water Use Equipment Cold Water Volume Flow Rate', 'timestep']
|
1200
|
+
var_names << ['Water Use Equipment Hot Water Temperature', 'timestep']
|
1201
|
+
var_names << ['Water Use Equipment Cold Water Temperature', 'timestep']
|
1202
|
+
var_names << ['Water Use Equipment Mains Water Volume', 'timestep']
|
1203
|
+
var_names << ['Water Use Equipment Target Water Temperature', 'timestep']
|
1204
|
+
var_names << ['Water Use Equipment Mixed Water Temperature', 'timestep']
|
1205
|
+
var_names << ['Water Heater Tank Temperature', 'timestep']
|
1206
|
+
var_names << ['Water Heater Use Side Mass Flow Rate', 'timestep']
|
1207
|
+
var_names << ['Water Heater Heating Rate', 'timestep']
|
1208
|
+
var_names << ['Water Heater Water Volume Flow Rate', 'timestep']
|
1209
|
+
var_names << ['Water Heater Water Volume', 'timestep']
|
1269
1210
|
end
|
1270
1211
|
|
1271
1212
|
var_names.each do |var_name, reporting_frequency|
|
1272
|
-
|
1273
|
-
|
1213
|
+
output_var = OpenStudio::Model::OutputVariable.new(var_name, self)
|
1214
|
+
output_var.setReportingFrequency(reporting_frequency)
|
1274
1215
|
end
|
1275
|
-
|
1276
|
-
|
1277
1216
|
end
|
1278
1217
|
|
1279
1218
|
def run(run_dir = "#{Dir.pwd}/Run")
|
1280
|
-
|
1281
1219
|
# If the run directory is not specified
|
1282
1220
|
# run in the current working directory
|
1283
1221
|
|
1284
1222
|
# Make the directory if it doesn't exist
|
1285
|
-
|
1223
|
+
unless Dir.exist?(run_dir)
|
1286
1224
|
Dir.mkdir(run_dir)
|
1287
1225
|
end
|
1288
1226
|
|
1289
|
-
OpenStudio
|
1227
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', "Started simulation in '#{run_dir}'")
|
1290
1228
|
|
1291
1229
|
# Change the simulation to only run the weather file
|
1292
1230
|
# and not run the sizing day simulations
|
1293
|
-
sim_control =
|
1231
|
+
sim_control = getSimulationControl
|
1294
1232
|
sim_control.setRunSimulationforSizingPeriods(false)
|
1295
1233
|
sim_control.setRunSimulationforWeatherFileRunPeriods(true)
|
1296
1234
|
|
@@ -1301,34 +1239,34 @@ class OpenStudio::Model::Model
|
|
1301
1239
|
idf = forward_translator.translateModel(self)
|
1302
1240
|
idf_path = OpenStudio::Path.new("#{run_dir}/#{idf_name}")
|
1303
1241
|
osm_path = OpenStudio::Path.new("#{run_dir}/#{osm_name}")
|
1304
|
-
idf.save(idf_path,true)
|
1305
|
-
|
1242
|
+
idf.save(idf_path, true)
|
1243
|
+
save(osm_path, true)
|
1306
1244
|
|
1307
1245
|
# Set up the sizing simulation
|
1308
1246
|
# Find the weather file
|
1309
1247
|
epw_path = nil
|
1310
|
-
if
|
1311
|
-
epw_path =
|
1248
|
+
if weatherFile.is_initialized
|
1249
|
+
epw_path = weatherFile.get.path
|
1312
1250
|
if epw_path.is_initialized
|
1313
1251
|
if File.exist?(epw_path.get.to_s)
|
1314
1252
|
epw_path = epw_path.get
|
1315
1253
|
else
|
1316
1254
|
# If this is an always-run Measure, need to check a different path
|
1317
|
-
alt_weath_path = File.expand_path(File.join(File.dirname(__FILE__),
|
1255
|
+
alt_weath_path = File.expand_path(File.join(File.dirname(__FILE__), '../../../resources'))
|
1318
1256
|
alt_epw_path = File.expand_path(File.join(alt_weath_path, epw_path.get.to_s))
|
1319
1257
|
if File.exist?(alt_epw_path)
|
1320
1258
|
epw_path = OpenStudio::Path.new(alt_epw_path)
|
1321
1259
|
else
|
1322
|
-
OpenStudio
|
1260
|
+
OpenStudio.logFree(OpenStudio::Error, 'openstudio.prototype.Model', "Model has been assigned a weather file, but the file is not in the specified location of '#{epw_path.get}'.")
|
1323
1261
|
return false
|
1324
1262
|
end
|
1325
1263
|
end
|
1326
1264
|
else
|
1327
|
-
OpenStudio
|
1265
|
+
OpenStudio.logFree(OpenStudio::Error, 'openstudio.prototype.Model', 'Model has a weather file assigned, but the weather file path has been deleted.')
|
1328
1266
|
return false
|
1329
1267
|
end
|
1330
1268
|
else
|
1331
|
-
OpenStudio
|
1269
|
+
OpenStudio.logFree(OpenStudio::Error, 'openstudio.prototype.Model', 'Model has not been assigned a weather file.3')
|
1332
1270
|
return false
|
1333
1271
|
end
|
1334
1272
|
|
@@ -1346,38 +1284,38 @@ class OpenStudio::Model::Model
|
|
1346
1284
|
|
1347
1285
|
sql_path = nil
|
1348
1286
|
if use_runmanager == true
|
1349
|
-
OpenStudio
|
1287
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.prototype.Model', 'Running sizing run with RunManager.')
|
1350
1288
|
|
1351
1289
|
# Find EnergyPlus
|
1352
1290
|
ep_dir = OpenStudio.getEnergyPlusDirectory
|
1353
1291
|
ep_path = OpenStudio.getEnergyPlusExecutable
|
1354
1292
|
ep_tool = OpenStudio::Runmanager::ToolInfo.new(ep_path)
|
1355
|
-
idd_path = OpenStudio::Path.new(ep_dir.to_s +
|
1293
|
+
idd_path = OpenStudio::Path.new(ep_dir.to_s + '/Energy+.idd')
|
1356
1294
|
output_path = OpenStudio::Path.new("#{run_dir}/")
|
1357
1295
|
|
1358
1296
|
# Make a run manager and queue up the sizing run
|
1359
1297
|
run_manager_db_path = OpenStudio::Path.new("#{run_dir}/run.db")
|
1360
1298
|
run_manager = OpenStudio::Runmanager::RunManager.new(run_manager_db_path, true, false, false, false)
|
1361
|
-
job = OpenStudio::Runmanager::JobFactory
|
1362
|
-
|
1363
|
-
|
1364
|
-
|
1365
|
-
|
1299
|
+
job = OpenStudio::Runmanager::JobFactory.createEnergyPlusJob(ep_tool,
|
1300
|
+
idd_path,
|
1301
|
+
idf_path,
|
1302
|
+
epw_path,
|
1303
|
+
output_path)
|
1366
1304
|
|
1367
1305
|
run_manager.enqueue(job, true)
|
1368
1306
|
|
1369
1307
|
# Start the sizing run and wait for it to finish.
|
1370
1308
|
while run_manager.workPending
|
1371
1309
|
sleep 1
|
1372
|
-
OpenStudio::Application
|
1310
|
+
OpenStudio::Application.instance.processEvents
|
1373
1311
|
end
|
1374
1312
|
|
1375
1313
|
sql_path = OpenStudio::Path.new("#{run_dir}/Energyplus/eplusout.sql")
|
1376
1314
|
|
1377
|
-
OpenStudio
|
1315
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.prototype.Model', "Finished sizing run in #{(Time.new - start_time).round}sec.")
|
1378
1316
|
|
1379
1317
|
else # Use the openstudio-workflow gem
|
1380
|
-
OpenStudio
|
1318
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.prototype.Model', 'Running sizing run with openstudio-workflow gem.')
|
1381
1319
|
|
1382
1320
|
# Copy the weather file to this directory
|
1383
1321
|
FileUtils.copy(epw_path.to_s, run_dir)
|
@@ -1387,7 +1325,7 @@ class OpenStudio::Model::Model
|
|
1387
1325
|
final_state = sim.run
|
1388
1326
|
|
1389
1327
|
if final_state == :finished
|
1390
|
-
OpenStudio
|
1328
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.prototype.Model', "Finished sizing run in #{(Time.new - start_time).round}sec.")
|
1391
1329
|
end
|
1392
1330
|
|
1393
1331
|
sql_path = OpenStudio::Path.new("#{run_dir}/run/eplusout.sql")
|
@@ -1396,18 +1334,18 @@ class OpenStudio::Model::Model
|
|
1396
1334
|
|
1397
1335
|
# Load the sql file created by the sizing run
|
1398
1336
|
sql_path = OpenStudio::Path.new("#{run_dir}/Energyplus/eplusout.sql")
|
1399
|
-
if OpenStudio
|
1337
|
+
if OpenStudio.exists(sql_path)
|
1400
1338
|
sql = OpenStudio::SqlFile.new(sql_path)
|
1401
1339
|
# Check to make sure the sql file is readable,
|
1402
1340
|
# which won't be true if EnergyPlus crashed during simulation.
|
1403
|
-
|
1404
|
-
OpenStudio
|
1341
|
+
unless sql.connectionOpen
|
1342
|
+
OpenStudio.logFree(OpenStudio::Error, 'openstudio.model.Model', "The run failed. Look at the eplusout.err file in #{File.dirname(sql_path.to_s)} to see the cause.")
|
1405
1343
|
return false
|
1406
1344
|
end
|
1407
1345
|
# Attach the sql file from the run to the sizing model
|
1408
|
-
|
1346
|
+
setSqlFile(sql)
|
1409
1347
|
else
|
1410
|
-
OpenStudio
|
1348
|
+
OpenStudio.logFree(OpenStudio::Error, 'openstudio.model.Model', "Results for the sizing run couldn't be found here: #{sql_path}.")
|
1411
1349
|
return false
|
1412
1350
|
end
|
1413
1351
|
|
@@ -1416,24 +1354,22 @@ class OpenStudio::Model::Model
|
|
1416
1354
|
FROM Errors
|
1417
1355
|
WHERE ErrorType='1'"
|
1418
1356
|
|
1419
|
-
errs =
|
1357
|
+
errs = sqlFile.get.execAndReturnVectorOfString(error_query)
|
1420
1358
|
if errs.is_initialized
|
1421
1359
|
errs = errs.get
|
1422
|
-
|
1360
|
+
unless errs.empty?
|
1423
1361
|
errs = errs.get
|
1424
|
-
OpenStudio
|
1362
|
+
OpenStudio.logFree(OpenStudio::Error, 'openstudio.model.Model', "The run failed with the following severe errors: #{errs.join('\n')}.")
|
1425
1363
|
return false
|
1426
1364
|
end
|
1427
1365
|
end
|
1428
1366
|
|
1429
|
-
OpenStudio
|
1367
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', "Finished simulation in '#{run_dir}'")
|
1430
1368
|
|
1431
1369
|
return true
|
1432
|
-
|
1433
1370
|
end
|
1434
1371
|
|
1435
1372
|
def request_timeseries_outputs
|
1436
|
-
|
1437
1373
|
# "detailed"
|
1438
1374
|
# "timestep"
|
1439
1375
|
# "hourly"
|
@@ -1478,14 +1414,14 @@ class OpenStudio::Model::Model
|
|
1478
1414
|
# vars << ['Air System Mixed Air Mass Flow Rate','timestep']
|
1479
1415
|
|
1480
1416
|
# vars << ['Heating Coil Gas Rate','timestep']
|
1481
|
-
vars << ['Boiler Part Load Ratio','timestep']
|
1482
|
-
vars << ['Boiler Gas Rate','timestep']
|
1417
|
+
vars << ['Boiler Part Load Ratio', 'timestep']
|
1418
|
+
vars << ['Boiler Gas Rate', 'timestep']
|
1483
1419
|
# vars << ['Boiler Gas Rate','timestep']
|
1484
1420
|
# vars << ['Fan Electric Power','timestep']
|
1485
1421
|
|
1486
|
-
vars << ['Pump Electric Power','timestep']
|
1487
|
-
vars << ['Pump Outlet Temperature','timestep']
|
1488
|
-
vars << ['Pump Mass Flow Rate','timestep']
|
1422
|
+
vars << ['Pump Electric Power', 'timestep']
|
1423
|
+
vars << ['Pump Outlet Temperature', 'timestep']
|
1424
|
+
vars << ['Pump Mass Flow Rate', 'timestep']
|
1489
1425
|
|
1490
1426
|
# vars << ['Zone Air Terminal VAV Damper Position','timestep']
|
1491
1427
|
# vars << ['Zone Air Terminal Minimum Air Flow Fraction','timestep']
|
@@ -1495,10 +1431,129 @@ class OpenStudio::Model::Model
|
|
1495
1431
|
# vars << ['Schedule Value','hourly']
|
1496
1432
|
|
1497
1433
|
vars.each do |var, freq|
|
1498
|
-
|
1499
|
-
|
1434
|
+
output_var = OpenStudio::Model::OutputVariable.new(var, self)
|
1435
|
+
output_var.setReportingFrequency(freq)
|
1500
1436
|
end
|
1437
|
+
end
|
1501
1438
|
|
1439
|
+
def clear_and_set_example_constructions
|
1440
|
+
# Define Materials
|
1441
|
+
name = 'opaque material'
|
1442
|
+
thickness = 0.012700
|
1443
|
+
conductivity = 0.160000
|
1444
|
+
opaque_mat = BTAP::Resources::Envelope::Materials::Opaque.create_opaque_material(self, name, thickness, conductivity)
|
1445
|
+
|
1446
|
+
name = 'insulation material'
|
1447
|
+
thickness = 0.050000
|
1448
|
+
conductivity = 0.043000
|
1449
|
+
insulation_mat = BTAP::Resources::Envelope::Materials::Opaque.create_opaque_material(self, name, thickness, conductivity)
|
1450
|
+
|
1451
|
+
name = 'simple glazing test'
|
1452
|
+
shgc = 0.250000
|
1453
|
+
ufactor = 3.236460
|
1454
|
+
thickness = 0.003000
|
1455
|
+
visible_transmittance = 0.160000
|
1456
|
+
simple_glazing_mat = BTAP::Resources::Envelope::Materials::Fenestration.create_simple_glazing(self, name, shgc, ufactor, thickness, visible_transmittance)
|
1457
|
+
|
1458
|
+
name = 'Standard Glazing Test'
|
1459
|
+
thickness = 0.003
|
1460
|
+
conductivity = 0.9
|
1461
|
+
solar_trans_normal = 0.84
|
1462
|
+
front_solar_ref_normal = 0.075
|
1463
|
+
back_solar_ref_normal = 0.075
|
1464
|
+
vlt = 0.9
|
1465
|
+
front_vis_ref_normal = 0.081
|
1466
|
+
back_vis_ref_normal = 0.081
|
1467
|
+
ir_trans_normal = 0.0
|
1468
|
+
front_ir_emis = 0.84
|
1469
|
+
back_ir_emis = 0.84
|
1470
|
+
optical_data_type = 'SpectralAverage'
|
1471
|
+
dirt_correction_factor = 1.0
|
1472
|
+
is_solar_diffusing = false
|
1473
|
+
|
1474
|
+
standard_glazing_mat = BTAP::Resources::Envelope::Materials::Fenestration.create_standard_glazing(self,
|
1475
|
+
name,
|
1476
|
+
thickness,
|
1477
|
+
conductivity,
|
1478
|
+
solar_trans_normal,
|
1479
|
+
front_solar_ref_normal,
|
1480
|
+
back_solar_ref_normal, vlt,
|
1481
|
+
front_vis_ref_normal,
|
1482
|
+
back_vis_ref_normal,
|
1483
|
+
ir_trans_normal,
|
1484
|
+
front_ir_emis,
|
1485
|
+
back_ir_emis,
|
1486
|
+
optical_data_type,
|
1487
|
+
dirt_correction_factor,
|
1488
|
+
is_solar_diffusing)
|
1489
|
+
|
1490
|
+
# Define Constructions
|
1491
|
+
# # Surfaces
|
1492
|
+
ext_wall = BTAP::Resources::Envelope::Constructions.create_construction(self, 'OpaqueConstructionExtWall', [opaque_mat, insulation_mat], insulation_mat)
|
1493
|
+
ext_roof = BTAP::Resources::Envelope::Constructions.create_construction(self, 'OpaqueConstructionExtRoof', [opaque_mat, insulation_mat], insulation_mat)
|
1494
|
+
ext_floor = BTAP::Resources::Envelope::Constructions.create_construction(self, 'OpaqueConstructionExtFloor', [opaque_mat, insulation_mat], insulation_mat)
|
1495
|
+
grnd_wall = BTAP::Resources::Envelope::Constructions.create_construction(self, 'OpaqueConstructionGrndWall', [opaque_mat, insulation_mat], insulation_mat)
|
1496
|
+
grnd_roof = BTAP::Resources::Envelope::Constructions.create_construction(self, 'OpaqueConstructionGrndRoof', [opaque_mat, insulation_mat], insulation_mat)
|
1497
|
+
grnd_floor = BTAP::Resources::Envelope::Constructions.create_construction(self, 'OpaqueConstructionGrndFloor', [opaque_mat, insulation_mat], insulation_mat)
|
1498
|
+
int_wall = BTAP::Resources::Envelope::Constructions.create_construction(self, 'OpaqueConstructionIntWall', [opaque_mat, insulation_mat], insulation_mat)
|
1499
|
+
int_roof = BTAP::Resources::Envelope::Constructions.create_construction(self, 'OpaqueConstructionIntRoof', [opaque_mat, insulation_mat], insulation_mat)
|
1500
|
+
int_floor = BTAP::Resources::Envelope::Constructions.create_construction(self, 'OpaqueConstructionIntFloor', [opaque_mat, insulation_mat], insulation_mat)
|
1501
|
+
# # Subsurfaces
|
1502
|
+
fixed_window = BTAP::Resources::Envelope::Constructions.create_construction(self, 'FenestrationConstructionFixed', [simple_glazing_mat])
|
1503
|
+
operable_window = BTAP::Resources::Envelope::Constructions.create_construction(self, 'FenestrationConstructionOperable', [simple_glazing_mat])
|
1504
|
+
glass_door = BTAP::Resources::Envelope::Constructions.create_construction(self, 'FenestrationConstructionDoor', [standard_glazing_mat])
|
1505
|
+
door = BTAP::Resources::Envelope::Constructions.create_construction(self, 'OpaqueConstructionDoor', [opaque_mat, insulation_mat], insulation_mat)
|
1506
|
+
overhead_door = BTAP::Resources::Envelope::Constructions.create_construction(self, 'OpaqueConstructionOverheadDoor', [opaque_mat, insulation_mat], insulation_mat)
|
1507
|
+
skylt = BTAP::Resources::Envelope::Constructions.create_construction(self, 'FenestrationConstructionSkylight', [standard_glazing_mat])
|
1508
|
+
daylt_dome = BTAP::Resources::Envelope::Constructions.create_construction(self, 'FenestrationConstructionDomeConstruction', [standard_glazing_mat])
|
1509
|
+
daylt_diffuser = BTAP::Resources::Envelope::Constructions.create_construction(self, 'FenestrationConstructionDiffuserConstruction', [standard_glazing_mat])
|
1510
|
+
|
1511
|
+
# Define Construction Sets
|
1512
|
+
# # Surface
|
1513
|
+
exterior_construction_set = BTAP::Resources::Envelope::ConstructionSets.create_default_surface_constructions(self, 'ExteriorSet', ext_wall, ext_roof, ext_floor)
|
1514
|
+
interior_construction_set = BTAP::Resources::Envelope::ConstructionSets.create_default_surface_constructions(self, 'InteriorSet', int_wall, int_roof, int_floor)
|
1515
|
+
ground_construction_set = BTAP::Resources::Envelope::ConstructionSets.create_default_surface_constructions(self, 'GroundSet', grnd_wall, grnd_roof, grnd_floor)
|
1516
|
+
|
1517
|
+
# # Subsurface
|
1518
|
+
subsurface_exterior_construction_set = BTAP::Resources::Envelope::ConstructionSets.create_subsurface_construction_set(self, fixed_window, operable_window, door, glass_door, overhead_door, skylt, daylt_dome, daylt_diffuser)
|
1519
|
+
subsurface_interior_construction_set = BTAP::Resources::Envelope::ConstructionSets.create_subsurface_construction_set(self, fixed_window, operable_window, door, glass_door, overhead_door, skylt, daylt_dome, daylt_diffuser)
|
1520
|
+
|
1521
|
+
# Define default construction sets.
|
1522
|
+
name = 'Construction Set 1'
|
1523
|
+
default_construction_set = BTAP::Resources::Envelope::ConstructionSets.create_default_construction_set(self, name, exterior_construction_set, interior_construction_set, ground_construction_set, subsurface_exterior_construction_set, subsurface_interior_construction_set)
|
1524
|
+
|
1525
|
+
# Assign default to the model.
|
1526
|
+
getBuilding.setDefaultConstructionSet(default_construction_set)
|
1527
|
+
|
1528
|
+
return default_construction_set
|
1502
1529
|
end
|
1503
1530
|
|
1531
|
+
private
|
1532
|
+
|
1533
|
+
# Method to multiply the values in a day schedule by a specified value
|
1534
|
+
# but only when the existing value is higher than a specified lower limit.
|
1535
|
+
# This limit prevents occupancy sensors from affecting unoccupied hours.
|
1536
|
+
def multiply_schedule(day_sch, multiplier, limit)
|
1537
|
+
# Record the original times and values
|
1538
|
+
times = day_sch.times
|
1539
|
+
values = day_sch.values
|
1540
|
+
|
1541
|
+
# Remove the original times and values
|
1542
|
+
day_sch.clearValues
|
1543
|
+
|
1544
|
+
# Create new values by using the multiplier on the original values
|
1545
|
+
new_values = []
|
1546
|
+
values.each do |value|
|
1547
|
+
new_values << if value > limit
|
1548
|
+
value * multiplier
|
1549
|
+
else
|
1550
|
+
value
|
1551
|
+
end
|
1552
|
+
end
|
1553
|
+
|
1554
|
+
# Add the revised time/value pairs to the schedule
|
1555
|
+
new_values.each_with_index do |new_value, i|
|
1556
|
+
day_sch.addValue(times[i], new_value)
|
1557
|
+
end
|
1558
|
+
end # end reduce schedule
|
1504
1559
|
end
|