openstudio-standards 0.2.0.rc1 → 0.2.0.rc2
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/export_OpenStudio_libraries.rb +392 -376
- data/data/standards/manage_OpenStudio_Standards.rb +0 -1
- data/lib/openstudio-standards/btap/fileio.rb +0 -1
- data/lib/openstudio-standards/prototypes/common/buildings/Prototype.Hospital.rb +2 -2
- data/lib/openstudio-standards/prototypes/common/buildings/Prototype.LargeHotel.rb +2 -2
- data/lib/openstudio-standards/prototypes/common/buildings/Prototype.PrimarySchool.rb +2 -2
- data/lib/openstudio-standards/prototypes/common/buildings/Prototype.SecondarySchool.rb +2 -2
- data/lib/openstudio-standards/refs/references.rb +13 -0
- data/lib/openstudio-standards/standards/Standards.Construction.rb +6 -6
- data/lib/openstudio-standards/standards/Standards.Model.rb +1 -1
- data/lib/openstudio-standards/standards/Standards.Pump.rb +18 -7
- data/lib/openstudio-standards/standards/Standards.ScheduleRuleset.rb +2 -2
- data/lib/openstudio-standards/standards/Standards.ThermalZone.rb +7 -7
- data/lib/openstudio-standards/standards/icc_iecc/icc_iecc.rb +9 -0
- data/lib/openstudio-standards/standards/icc_iecc/icc_iecc_2015/icc_iecc_2015.rb +16 -0
- data/lib/openstudio-standards/standards/necb/necb_2011/necb_2011.rb +0 -1
- data/lib/openstudio-standards/standards/necb/necb_2015/necb_2015.rb +0 -1
- data/lib/openstudio-standards/standards/oeesc/oeesc.rb +9 -0
- data/lib/openstudio-standards/standards/oeesc/oeesc_2014/oeesc_2014.rb +16 -0
- data/lib/openstudio-standards/version.rb +1 -1
- data/lib/openstudio-standards.rb +6 -0
- metadata +8 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7971c760a2256abb5458a28ad4e0d31a9364acca
|
4
|
+
data.tar.gz: b4ed3ac1b33749ad8511de8b22dac45052074476
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7156d8390581e7633b5ec60a0fb1d44f8bb1eb78876eaf5b4ab26adcddededd0fe2b5e6a3e411d1721cce3532e5cb1c7d108f54ccfe00148555fb42b97502055
|
7
|
+
data.tar.gz: 8a8c9b87d8796999ffcee7319ec59f109513f5a7ed2057ac1b5853936263781a78797febee97909888af385c51a3db17d92a2b7402843299d9e63cf78b238f5d
|
@@ -10,14 +10,15 @@ require 'openstudio'
|
|
10
10
|
require_relative '../../lib/openstudio-standards'
|
11
11
|
|
12
12
|
def export_openstudio_libraries
|
13
|
+
start_time = Time.now
|
13
14
|
|
14
15
|
### Define what to include in the libraries ###
|
15
|
-
include_construction_sets = true # Construction Sets, Constructions, and Materials
|
16
|
-
include_space_types = true # Space Types, Internal Loads, and associated Schedule Sets and Schedules
|
17
16
|
include_boilers = true # BoilerHotWater
|
18
17
|
include_chillers = true # ChillerElectricEIR
|
19
18
|
include_unitary_acs = true # CoilCoolingDXSingleSpeed
|
20
|
-
include_heat_pumps =
|
19
|
+
include_heat_pumps = false # CoilCoolingDXSingleSpeed, CoilHeatingDXSingleSpeed, AirLoopHVACUnitaryHeatPump
|
20
|
+
include_space_types = true # Space Types, Internal Loads, and associated Schedule Sets and Schedules
|
21
|
+
include_construction_sets = true # Construction Sets, Constructions, and Materials
|
21
22
|
|
22
23
|
# Make an initial Standard to access the library data
|
23
24
|
std = Standard.build('90.1-2013')
|
@@ -27,412 +28,427 @@ def export_openstudio_libraries
|
|
27
28
|
templates_to_climate_zones = JSON.parse(temp)
|
28
29
|
|
29
30
|
# Make a library model for each template
|
30
|
-
template_to_lib_models = {}
|
31
31
|
std.standards_data["templates"].each do |template|
|
32
|
-
|
33
|
-
|
34
|
-
|
32
|
+
|
33
|
+
# Wrap each library creation in a begin/rescue because
|
34
|
+
# the entire process can take a long time and
|
35
|
+
# we don't want to lose all templates if one fails
|
35
36
|
begin
|
36
|
-
data['standard_applier'] = Standard.build(template_name)
|
37
|
-
template_to_lib_models[template_name] = data
|
38
|
-
rescue Exception => e
|
39
|
-
puts "'#{template_name}' is not defined in OpenStudio-Standards yet"
|
40
|
-
end
|
41
|
-
end
|
42
37
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
# Add a construction set for each valid climate zone
|
53
|
-
templates_to_climate_zones[props['template']].each do |climate_zone|
|
54
|
-
construction_set = std_applier.model_add_construction_set(model,
|
55
|
-
climate_zone,
|
56
|
-
props['building_type'],
|
57
|
-
props['space_type'],
|
58
|
-
props['is_residential'])
|
38
|
+
# Make a Standard for this template
|
39
|
+
template_name = template['name']
|
40
|
+
puts "*** Making #{template_name} ***"
|
41
|
+
template_start_time = Time.now
|
42
|
+
puts "* Started #{template_name} at: #{template_start_time}"
|
43
|
+
begin
|
44
|
+
std_applier = Standard.build(template_name)
|
45
|
+
rescue Exception => e
|
46
|
+
puts "'#{template_name}' is not defined in OpenStudio-Standards yet"
|
59
47
|
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
# Space Types
|
64
|
-
if include_space_types
|
65
|
-
std.standards_data['space_types'].each do |props|
|
66
|
-
lib = template_to_lib_models[props['template']]
|
67
|
-
next if lib.nil? # Skip unsupported templates
|
68
|
-
model = lib['model']
|
69
|
-
std_applier = lib['standard_applier']
|
70
48
|
|
71
|
-
#
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
49
|
+
# Reset the openstudio-standards log
|
50
|
+
reset_log
|
51
|
+
|
52
|
+
next unless template_name == '90.1-2004'
|
53
|
+
|
54
|
+
# Make an empty model
|
55
|
+
model = OpenStudio::Model::Model.new
|
56
|
+
|
57
|
+
# Boilers
|
58
|
+
if include_boilers
|
59
|
+
puts "* Boilers *"
|
60
|
+
std.standards_data['boilers'].each do |props|
|
61
|
+
next unless props['template'] == template_name
|
62
|
+
|
63
|
+
# Make a new boiler
|
64
|
+
boiler = OpenStudio::Model::BoilerHotWater.new(model)
|
65
|
+
# Fuel Type
|
66
|
+
case props['fuel_type']
|
67
|
+
when 'Gas'
|
68
|
+
boiler.setFuelType('NaturalGas')
|
69
|
+
when 'Electric'
|
70
|
+
boiler.setFuelType('Electricity')
|
71
|
+
when 'Oil'
|
72
|
+
boiler.setFuelType('FuelOil#2')
|
73
|
+
end
|
74
|
+
# Set capacity to middle of range
|
75
|
+
min_cap_btu_per_hr = props['minimum_capacity'].to_f
|
76
|
+
max_cap_btu_per_hr = props['maximum_capacity'].to_f
|
77
|
+
mid_cap_btu_per_hr = (min_cap_btu_per_hr + max_cap_btu_per_hr) / 2
|
78
|
+
mid_cap_w = OpenStudio.convert(mid_cap_btu_per_hr, 'Btu/hr', 'W').get
|
79
|
+
boiler.setNominalCapacity(mid_cap_w)
|
80
|
+
|
81
|
+
# Apply the standard
|
82
|
+
std_applier.boiler_hot_water_apply_efficiency_and_curves(boiler)
|
83
|
+
|
84
|
+
# Reset the capacity
|
85
|
+
boiler.autosizeNominalCapacity
|
86
|
+
|
87
|
+
# Modify the name of the boiler to reflect the capacity range
|
88
|
+
min_cap_kbtu_per_hr = OpenStudio.convert(min_cap_btu_per_hr, 'Btu/hr', 'kBtu/hr').get.round
|
89
|
+
max_cap_kbtu_per_hr = OpenStudio.convert(max_cap_btu_per_hr, 'Btu/hr', 'kBtu/hr').get.round
|
90
|
+
|
91
|
+
old_name = boiler.name.get.to_s
|
92
|
+
m = old_name.match(/(\d+)kBtu\/hr/)
|
93
|
+
if m
|
94
|
+
# Put the fuel type into the name
|
95
|
+
old_type = 'Boiler Hot Water 1'
|
96
|
+
new_type = "#{props['fuel_type']} Boiler"
|
97
|
+
new_name = old_name.gsub(old_type, new_type)
|
98
|
+
# Swap out the capacity number for a range
|
99
|
+
old_cap = m[1]
|
100
|
+
if max_cap_kbtu_per_hr == 10_000_000 # Value representing infinity
|
101
|
+
new_cap = "> #{min_cap_kbtu_per_hr}"
|
102
|
+
else
|
103
|
+
new_cap = "#{min_cap_kbtu_per_hr}-#{max_cap_kbtu_per_hr}"
|
104
|
+
end
|
105
|
+
new_name = new_name.gsub(old_cap, new_cap)
|
106
|
+
boiler.setName(new_name)
|
107
|
+
puts "#{props['template']}: #{boiler.name.get.to_s}"
|
108
|
+
end
|
76
109
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
# Loads
|
81
|
-
std_applier.space_type_apply_internal_loads(space_type, true, true, true, true, true, true)
|
110
|
+
end
|
111
|
+
end
|
82
112
|
|
83
|
-
#
|
84
|
-
|
113
|
+
# Chillers
|
114
|
+
if include_chillers
|
115
|
+
puts "* Chillers *"
|
116
|
+
std.standards_data['chillers'].each do |props|
|
117
|
+
next unless props['template'] == template_name
|
118
|
+
|
119
|
+
# Skip absorption chillers
|
120
|
+
next unless props['absorption_type'].nil?
|
121
|
+
|
122
|
+
# Skip interim chiller efficiency requirements
|
123
|
+
next unless props['end_date'] == "2999-09-09T00:00:00+00:00"
|
124
|
+
|
125
|
+
# Make a new chiller
|
126
|
+
chiller = OpenStudio::Model::ChillerElectricEIR.new(model)
|
127
|
+
# Set capacity to middle of range
|
128
|
+
min_cap_tons = props['minimum_capacity'].to_f
|
129
|
+
max_cap_tons = props['maximum_capacity'].to_f
|
130
|
+
mid_cap_tons = (min_cap_tons + max_cap_tons) / 2
|
131
|
+
mid_cap_w = OpenStudio.convert(mid_cap_tons, 'ton', 'W').get
|
132
|
+
chiller.setReferenceCapacity(mid_cap_w)
|
133
|
+
|
134
|
+
# Add the chiller properties to the name, because this is what
|
135
|
+
# the standards currently work off of.
|
136
|
+
if props['cooling_type'] == 'AirCooled'
|
137
|
+
new_name = "#{props['cooling_type']} Chiller #{props['condenser_type']}"
|
138
|
+
elsif props['cooling_type'] == 'WaterCooled'
|
139
|
+
new_name = "#{props['cooling_type']} #{props['compressor_type']} Chiller"
|
140
|
+
else
|
141
|
+
new_name = chiller.name.get
|
142
|
+
end
|
143
|
+
chiller.setName(new_name)
|
144
|
+
|
145
|
+
# Apply the standard
|
146
|
+
std_applier.chiller_electric_eir_apply_efficiency_and_curves(chiller, nil)
|
147
|
+
|
148
|
+
# Reset the capacity
|
149
|
+
chiller.autosizeReferenceCapacity
|
150
|
+
|
151
|
+
# Modify the name of the chiller to reflect the capacity range
|
152
|
+
old_name = chiller.name.get.to_s
|
153
|
+
m = old_name.match(/(\d+)tons/)
|
154
|
+
if m
|
155
|
+
# Put the fuel type into the name
|
156
|
+
old_type = 'Chiller Electric EIR 1'
|
157
|
+
new_type = 'Chiller'
|
158
|
+
new_name = old_name.gsub(old_type, new_type)
|
159
|
+
# Swap out the capacity number for a range
|
160
|
+
old_cap = m[1]
|
161
|
+
if max_cap_tons == 10_000 # Value representing infinity
|
162
|
+
new_cap = "> #{min_cap_tons.round}"
|
163
|
+
else
|
164
|
+
new_cap = "#{min_cap_tons.round}-#{max_cap_tons.round}"
|
165
|
+
end
|
166
|
+
new_name = new_name.gsub(old_cap, new_cap)
|
167
|
+
chiller.setName(new_name)
|
168
|
+
puts "#{props['template']}: #{chiller.name.get.to_s}"
|
169
|
+
end
|
85
170
|
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
# Boilers
|
90
|
-
if include_boilers
|
91
|
-
std.standards_data['boilers'].each do |props|
|
92
|
-
lib = template_to_lib_models[props['template']]
|
93
|
-
next if lib.nil? # Skip unsupported templates
|
94
|
-
# Skip NECB 2011 for now
|
95
|
-
next if props['template'] == 'NECB 2011'
|
96
|
-
model = lib['model']
|
97
|
-
std_applier = lib['standard_applier']
|
98
|
-
|
99
|
-
# Make a new boiler
|
100
|
-
boiler = OpenStudio::Model::BoilerHotWater.new(model)
|
101
|
-
# Fuel Type
|
102
|
-
case props['fuel_type']
|
103
|
-
when 'Gas'
|
104
|
-
boiler.setFuelType('NaturalGas')
|
105
|
-
when 'Electric'
|
106
|
-
boiler.setFuelType('Electricity')
|
107
|
-
when 'Oil'
|
108
|
-
boiler.setFuelType('FuelOil#2')
|
109
|
-
end
|
110
|
-
# Set capacity to middle of range
|
111
|
-
min_cap_btu_per_hr = props['minimum_capacity'].to_f
|
112
|
-
max_cap_btu_per_hr = props['maximum_capacity'].to_f
|
113
|
-
mid_cap_btu_per_hr = (min_cap_btu_per_hr + max_cap_btu_per_hr) / 2
|
114
|
-
mid_cap_w = OpenStudio.convert(mid_cap_btu_per_hr, 'Btu/hr', 'W').get
|
115
|
-
boiler.setNominalCapacity(mid_cap_w)
|
116
|
-
|
117
|
-
# Apply the standard
|
118
|
-
std_applier.boiler_hot_water_apply_efficiency_and_curves(boiler)
|
119
|
-
|
120
|
-
# Reset the capacity
|
121
|
-
boiler.autosizeNominalCapacity
|
122
|
-
|
123
|
-
# Modify the name of the boiler to reflect the capacity range
|
124
|
-
min_cap_kbtu_per_hr = OpenStudio.convert(min_cap_btu_per_hr, 'Btu/hr', 'kBtu/hr').get.round
|
125
|
-
max_cap_kbtu_per_hr = OpenStudio.convert(max_cap_btu_per_hr, 'Btu/hr', 'kBtu/hr').get.round
|
126
|
-
|
127
|
-
old_name = boiler.name.get.to_s
|
128
|
-
m = old_name.match(/(\d+)kBtu\/hr/)
|
129
|
-
if m
|
130
|
-
# Put the fuel type into the name
|
131
|
-
old_type = 'Boiler Hot Water 1'
|
132
|
-
new_type = "#{props['fuel_type']} Boiler"
|
133
|
-
new_name = old_name.gsub(old_type, new_type)
|
134
|
-
# Swap out the capacity number for a range
|
135
|
-
old_cap = m[1]
|
136
|
-
if max_cap_kbtu_per_hr == 10_000_000 # Value representing infinity
|
137
|
-
new_cap = "> #{min_cap_kbtu_per_hr}"
|
138
|
-
else
|
139
|
-
new_cap = "#{min_cap_kbtu_per_hr}-#{max_cap_kbtu_per_hr}"
|
140
171
|
end
|
141
|
-
new_name = new_name.gsub(old_cap, new_cap)
|
142
|
-
boiler.setName(new_name)
|
143
|
-
puts "#{props['template']}: #{boiler.name.get.to_s}"
|
144
172
|
end
|
145
173
|
|
146
|
-
|
147
|
-
|
174
|
+
# Unitary AC
|
175
|
+
if include_unitary_acs
|
176
|
+
puts "* Unitary ACs *"
|
177
|
+
std.standards_data['unitary_acs'].each do |props|
|
178
|
+
next unless props['template'] == template_name
|
179
|
+
|
180
|
+
# Skip interim efficiency requirements
|
181
|
+
next unless props['end_date'] == "2999-09-09T00:00:00+00:00"
|
182
|
+
|
183
|
+
# Make a new DX coil
|
184
|
+
dx_coil = OpenStudio::Model::CoilCoolingDXSingleSpeed.new(model)
|
185
|
+
# Set capacity to middle of range
|
186
|
+
min_cap_btu_per_hr = props['minimum_capacity'].to_f
|
187
|
+
max_cap_btu_per_hr = props['maximum_capacity'].to_f
|
188
|
+
mid_cap_btu_per_hr = (min_cap_btu_per_hr + max_cap_btu_per_hr) / 2
|
189
|
+
mid_cap_w = OpenStudio.convert(mid_cap_btu_per_hr, 'Btu/hr', 'W').get
|
190
|
+
dx_coil.setRatedTotalCoolingCapacity(mid_cap_w)
|
191
|
+
|
192
|
+
# Add the subcategory to the name so that it
|
193
|
+
# can be used by the efficiency lookup
|
194
|
+
dx_coil.setName("#{dx_coil.name} #{props['subcategory']}")
|
195
|
+
|
196
|
+
# If it is a PTAC coil, add to PTAC
|
197
|
+
if props['subcategory'] == 'PTAC'
|
198
|
+
htg_coil = nil
|
199
|
+
if props['heating_type'] == 'Electric Resistance or None'
|
200
|
+
htg_coil = OpenStudio::Model::CoilHeatingElectric.new(model)
|
201
|
+
htg_coil.setName('PTAC Electric Backup Htg Coil')
|
202
|
+
else
|
203
|
+
htg_coil = OpenStudio::Model::CoilHeatingGas.new(model)
|
204
|
+
htg_coil.setName('PTAC Gas Backup Htg Coil')
|
205
|
+
end
|
206
|
+
fan = OpenStudio::Model::FanOnOff.new(model, model.alwaysOnDiscreteSchedule)
|
207
|
+
fan.setName("PTAC Supply Fan")
|
208
|
+
ptac = OpenStudio::Model::ZoneHVACPackagedTerminalAirConditioner.new(model,
|
209
|
+
model.alwaysOnDiscreteSchedule,
|
210
|
+
fan,
|
211
|
+
htg_coil,
|
212
|
+
dx_coil)
|
213
|
+
end
|
214
|
+
|
215
|
+
# Apply the standard
|
216
|
+
std_applier.coil_cooling_dx_single_speed_apply_efficiency_and_curves(dx_coil, {})
|
217
|
+
|
218
|
+
# Reset the capacity
|
219
|
+
dx_coil.autosizeRatedTotalCoolingCapacity
|
220
|
+
|
221
|
+
# Modify the name of the boiler to reflect the capacity range
|
222
|
+
min_cap_kbtu_per_hr = OpenStudio.convert(min_cap_btu_per_hr, 'Btu/hr', 'kBtu/hr').get.round
|
223
|
+
max_cap_kbtu_per_hr = OpenStudio.convert(max_cap_btu_per_hr, 'Btu/hr', 'kBtu/hr').get.round
|
224
|
+
|
225
|
+
# Modify the name of the dx_coil to reflect the capacity range
|
226
|
+
old_name = dx_coil.name.get.to_s
|
227
|
+
m = old_name.match(/(\d+)kBtu\/hr/)
|
228
|
+
if m
|
229
|
+
# Put the fuel type into the name
|
230
|
+
old_type = "Coil Cooling DX Single Speed 1 #{props['subcategory']}"
|
231
|
+
new_type = "#{props['cooling_type']} #{props['heating_type']} #{props['subcategory']} DX"
|
232
|
+
new_name = old_name.gsub(old_type, new_type)
|
233
|
+
# Swap out the capacity number for a range
|
234
|
+
old_cap = m[1]
|
235
|
+
if max_cap_kbtu_per_hr == 10_000 # Value representing infinity
|
236
|
+
new_cap = "> #{min_cap_kbtu_per_hr}"
|
237
|
+
else
|
238
|
+
new_cap = "#{min_cap_kbtu_per_hr}-#{max_cap_kbtu_per_hr}"
|
239
|
+
end
|
240
|
+
new_name = new_name.gsub(old_cap, new_cap)
|
241
|
+
dx_coil.setName(new_name)
|
242
|
+
puts "#{props['template']}: #{dx_coil.name.get.to_s}"
|
243
|
+
|
244
|
+
# Rename PTAC too
|
245
|
+
if props['subcategory'] == 'PTAC'
|
246
|
+
ptac.setName("PTAC #{new_name}")
|
247
|
+
end
|
248
|
+
|
249
|
+
end
|
148
250
|
|
149
|
-
# Chillers
|
150
|
-
if include_chillers
|
151
|
-
std.standards_data['chillers'].each do |props|
|
152
|
-
lib = template_to_lib_models[props['template']]
|
153
|
-
next if lib.nil? # Skip unsupported templates
|
154
|
-
# Skip NECB 2011 for now
|
155
|
-
next if props['template'] == 'NECB 2011'
|
156
|
-
model = lib['model']
|
157
|
-
std_applier = lib['standard_applier']
|
158
|
-
|
159
|
-
# Skip absorption chillers
|
160
|
-
next unless props['absorption_type'].nil?
|
161
|
-
|
162
|
-
# Skip interim chiller efficiency requirements
|
163
|
-
next unless props['end_date'] == "2999-09-09T00:00:00+00:00"
|
164
|
-
|
165
|
-
# Make a new chiller
|
166
|
-
chiller = OpenStudio::Model::ChillerElectricEIR.new(model)
|
167
|
-
# Set capacity to middle of range
|
168
|
-
min_cap_tons = props['minimum_capacity'].to_f
|
169
|
-
max_cap_tons = props['maximum_capacity'].to_f
|
170
|
-
mid_cap_tons = (min_cap_tons + max_cap_tons) / 2
|
171
|
-
mid_cap_w = OpenStudio.convert(mid_cap_tons, 'ton', 'W').get
|
172
|
-
chiller.setReferenceCapacity(mid_cap_w)
|
173
|
-
|
174
|
-
# Add the chiller properties to the name, because this is what
|
175
|
-
# the standards currently work off of.
|
176
|
-
if props['cooling_type'] == 'AirCooled'
|
177
|
-
new_name = "#{props['cooling_type']} Chiller #{props['condenser_type']}"
|
178
|
-
elsif props['cooling_type'] == 'WaterCooled'
|
179
|
-
new_name = "#{props['cooling_type']} #{props['compressor_type']} Chiller"
|
180
|
-
else
|
181
|
-
new_name = chiller.name.get
|
182
|
-
end
|
183
|
-
chiller.setName(new_name)
|
184
|
-
|
185
|
-
# Apply the standard
|
186
|
-
std_applier.chiller_electric_eir_apply_efficiency_and_curves(chiller, nil)
|
187
|
-
|
188
|
-
# Reset the capacity
|
189
|
-
chiller.autosizeReferenceCapacity
|
190
|
-
|
191
|
-
# Modify the name of the chiller to reflect the capacity range
|
192
|
-
old_name = chiller.name.get.to_s
|
193
|
-
m = old_name.match(/(\d+)tons/)
|
194
|
-
if m
|
195
|
-
# Put the fuel type into the name
|
196
|
-
old_type = 'Chiller Electric EIR 1'
|
197
|
-
new_type = 'Chiller'
|
198
|
-
new_name = old_name.gsub(old_type, new_type)
|
199
|
-
# Swap out the capacity number for a range
|
200
|
-
old_cap = m[1]
|
201
|
-
if max_cap_tons == 10_000 # Value representing infinity
|
202
|
-
new_cap = "> #{min_cap_tons.round}"
|
203
|
-
else
|
204
|
-
new_cap = "#{min_cap_tons.round}-#{max_cap_tons.round}"
|
205
251
|
end
|
206
|
-
new_name = new_name.gsub(old_cap, new_cap)
|
207
|
-
chiller.setName(new_name)
|
208
|
-
puts "#{props['template']}: #{chiller.name.get.to_s}"
|
209
252
|
end
|
210
253
|
|
211
|
-
|
212
|
-
|
254
|
+
# Heat Pumps
|
255
|
+
if include_heat_pumps
|
256
|
+
puts "* Heat Pumps *"
|
257
|
+
std.standards_data['heat_pumps'].each do |props|
|
258
|
+
next unless props['template'] == template_name
|
259
|
+
|
260
|
+
# Skip interim efficiency requirements
|
261
|
+
next unless props['end_date'] == "2999-09-09T00:00:00+00:00"
|
262
|
+
|
263
|
+
# Make a new DX cooling coil
|
264
|
+
clg_coil = OpenStudio::Model::CoilCoolingDXSingleSpeed.new(model)
|
265
|
+
# Set capacity to middle of range
|
266
|
+
min_clg_cap_btu_per_hr = props['minimum_capacity'].to_f
|
267
|
+
max_clg_cap_btu_per_hr = props['maximum_capacity'].to_f
|
268
|
+
mid_clg_cap_btu_per_hr = (min_clg_cap_btu_per_hr + max_clg_cap_btu_per_hr) / 2
|
269
|
+
mid_clg_cap_w = OpenStudio.convert(mid_clg_cap_btu_per_hr, 'Btu/hr', 'W').get
|
270
|
+
clg_coil.setRatedTotalCoolingCapacity(mid_clg_cap_w)
|
271
|
+
|
272
|
+
# Make a new DX heating coil sized at 90% of the capacity
|
273
|
+
# of the cooling coil.
|
274
|
+
htg_coil = OpenStudio::Model::CoilHeatingDXSingleSpeed.new(model)
|
275
|
+
mid_htg_cap_w = mid_clg_cap_w * 0.9
|
276
|
+
htg_coil.setRatedTotalHeatingCapacity(mid_htg_cap_w)
|
277
|
+
|
278
|
+
# If it is a PTHP Coil, add to PTHP
|
279
|
+
# If not, add to unitary HP
|
280
|
+
if props['subcategory'] == 'PTHP'
|
281
|
+
if props['heating_type'] == 'Electric Resistance or None'
|
282
|
+
backup_htg_coil = OpenStudio::Model::CoilHeatingElectric.new(model)
|
283
|
+
backup_htg_coil.setName('PTHP Electric Backup Htg Coil')
|
284
|
+
else
|
285
|
+
backup_htg_coil = OpenStudio::Model::CoilHeatingGas.new(model)
|
286
|
+
backup_htg_coil.setName('PTHP Electric Backup Htg Coil')
|
287
|
+
end
|
288
|
+
fan = OpenStudio::Model::FanOnOff.new(model, model.alwaysOnDiscreteSchedule)
|
289
|
+
fan.setName("PTHP Supply Fan")
|
290
|
+
pthp = OpenStudio::Model::ZoneHVACPackagedTerminalHeatPump.new(model,
|
291
|
+
model.alwaysOnDiscreteSchedule,
|
292
|
+
fan,
|
293
|
+
htg_coil,
|
294
|
+
clg_coil,
|
295
|
+
backup_htg_coil)
|
296
|
+
else
|
297
|
+
if props['heating_type'] == 'Electric Resistance or None'
|
298
|
+
backup_htg_coil = OpenStudio::Model::CoilHeatingElectric.new(model)
|
299
|
+
backup_htg_coil.setName('Unitary Heat Pump Electric Backup Htg Coil')
|
300
|
+
else
|
301
|
+
backup_htg_coil = OpenStudio::Model::CoilHeatingGas.new(model)
|
302
|
+
backup_htg_coil.setName('Unitary Heat Pump Electric Backup Htg Coil')
|
303
|
+
end
|
304
|
+
fan = OpenStudio::Model::FanOnOff.new(model, model.alwaysOnDiscreteSchedule)
|
305
|
+
fan.setName("Unitary Heat Pump Supply Fan")
|
306
|
+
unitary_system = OpenStudio::Model::AirLoopHVACUnitaryHeatPumpAirToAir.new(model,
|
307
|
+
model.alwaysOnDiscreteSchedule,
|
308
|
+
fan,
|
309
|
+
htg_coil,
|
310
|
+
clg_coil,
|
311
|
+
backup_htg_coil)
|
312
|
+
unitary_system.setName("Unitary Heat Pump")
|
313
|
+
unitary_system.setMaximumOutdoorDryBulbTemperatureforSupplementalHeaterOperation(OpenStudio.convert(40, 'F', 'C').get)
|
314
|
+
end
|
315
|
+
|
316
|
+
# Apply the standard
|
317
|
+
std_applier.coil_cooling_dx_single_speed_apply_efficiency_and_curves(clg_coil, {})
|
318
|
+
std_applier.coil_heating_dx_single_speed_apply_efficiency_and_curves(htg_coil, {})
|
319
|
+
|
320
|
+
# Reset the capacity
|
321
|
+
clg_coil.autosizeRatedTotalCoolingCapacity
|
322
|
+
htg_coil.autosizeRatedTotalHeatingCapacity
|
323
|
+
|
324
|
+
# Modify the name of the boiler to reflect the capacity range
|
325
|
+
min_clg_cap_kbtu_per_hr = OpenStudio.convert(min_clg_cap_btu_per_hr, 'Btu/hr', 'kBtu/hr').get.round
|
326
|
+
max_clg_cap_kbtu_per_hr = OpenStudio.convert(max_clg_cap_btu_per_hr, 'Btu/hr', 'kBtu/hr').get.round
|
327
|
+
|
328
|
+
# Modify the name of the dx_coil to reflect the capacity range
|
329
|
+
old_name = clg_coil.name.get.to_s
|
330
|
+
m = old_name.match(/(\d+)kBtu\/hr/)
|
331
|
+
if m
|
332
|
+
# Put the fuel type into the name
|
333
|
+
old_type = 'Coil Cooling DX Single Speed 1'
|
334
|
+
new_type = "#{props['cooling_type']} #{props['heating_type']} #{props['subcategory']} DX"
|
335
|
+
new_name = old_name.gsub(old_type, new_type)
|
336
|
+
# Swap out the capacity number for a range
|
337
|
+
old_cap = m[1]
|
338
|
+
if max_clg_cap_kbtu_per_hr == 10_000 # Value representing infinity
|
339
|
+
new_cap = "> #{min_clg_cap_kbtu_per_hr}"
|
340
|
+
else
|
341
|
+
new_cap = "#{min_clg_cap_kbtu_per_hr}-#{max_clg_cap_kbtu_per_hr}"
|
342
|
+
end
|
343
|
+
new_name = new_name.gsub(old_cap, new_cap)
|
344
|
+
clg_coil.setName(new_name)
|
345
|
+
puts "#{props['template']}: #{clg_coil.name.get.to_s}"
|
346
|
+
|
347
|
+
# Rename PTHP or unitary same as the cooling coil
|
348
|
+
if pthp
|
349
|
+
pthp.setName("PTHP #{new_name}")
|
350
|
+
else
|
351
|
+
unitary_system.setName("Unitary Heat Pump #{new_name}")
|
352
|
+
end
|
353
|
+
|
354
|
+
# Rename the heating coil
|
355
|
+
old_type = 'Coil Heating DX Single Speed 1'
|
356
|
+
new_type = "#{props['cooling_type']} #{props['heating_type']} #{props['subcategory']} DX"
|
357
|
+
new_name = old_name.gsub(old_type, new_type)
|
358
|
+
# Swap out the capacity number for a blank
|
359
|
+
old_cap = m[1]
|
360
|
+
new_name = new_name.gsub(old_cap, '')
|
361
|
+
htg_coil.setName(new_name)
|
362
|
+
|
363
|
+
end
|
213
364
|
|
214
|
-
# Unitary AC
|
215
|
-
if include_unitary_acs
|
216
|
-
std.standards_data['unitary_acs'].each do |props|
|
217
|
-
lib = template_to_lib_models[props['template']]
|
218
|
-
next if lib.nil? # Skip unsupported templates
|
219
|
-
# Skip NECB 2011 for now
|
220
|
-
next if props['template'] == 'NECB 2011'
|
221
|
-
model = lib['model']
|
222
|
-
std_applier = lib['standard_applier']
|
223
|
-
|
224
|
-
# Skip interim efficiency requirements
|
225
|
-
next unless props['end_date'] == "2999-09-09T00:00:00+00:00"
|
226
|
-
|
227
|
-
# Make a new DX coil
|
228
|
-
dx_coil = OpenStudio::Model::CoilCoolingDXSingleSpeed.new(model)
|
229
|
-
# Set capacity to middle of range
|
230
|
-
min_cap_btu_per_hr = props['minimum_capacity'].to_f
|
231
|
-
max_cap_btu_per_hr = props['maximum_capacity'].to_f
|
232
|
-
mid_cap_btu_per_hr = (min_cap_btu_per_hr + max_cap_btu_per_hr) / 2
|
233
|
-
mid_cap_w = OpenStudio.convert(mid_cap_btu_per_hr, 'Btu/hr', 'W').get
|
234
|
-
dx_coil.setRatedTotalCoolingCapacity(mid_cap_w)
|
235
|
-
|
236
|
-
# Add the subcategory to the name so that it
|
237
|
-
# can be used by the efficiency lookup
|
238
|
-
dx_coil.setName("#{dx_coil.name} #{props['subcategory']}")
|
239
|
-
|
240
|
-
# If it is a PTAC coil, add to PTAC
|
241
|
-
if props['subcategory'] == 'PTAC'
|
242
|
-
htg_coil = nil
|
243
|
-
if props['heating_type'] == 'Electric Resistance or None'
|
244
|
-
htg_coil = OpenStudio::Model::CoilHeatingElectric.new(model)
|
245
|
-
htg_coil.setName('PTAC Electric Backup Htg Coil')
|
246
|
-
else
|
247
|
-
htg_coil = OpenStudio::Model::CoilHeatingGas.new(model)
|
248
|
-
htg_coil.setName('PTAC Gas Backup Htg Coil')
|
249
365
|
end
|
250
|
-
fan = OpenStudio::Model::FanOnOff.new(model, model.alwaysOnDiscreteSchedule)
|
251
|
-
fan.setName("PTAC Supply Fan")
|
252
|
-
ptac = OpenStudio::Model::ZoneHVACPackagedTerminalAirConditioner.new(model,
|
253
|
-
model.alwaysOnDiscreteSchedule,
|
254
|
-
fan,
|
255
|
-
htg_coil,
|
256
|
-
dx_coil)
|
257
366
|
end
|
258
367
|
|
259
|
-
#
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
# Modify the name of the boiler to reflect the capacity range
|
266
|
-
min_cap_kbtu_per_hr = OpenStudio.convert(min_cap_btu_per_hr, 'Btu/hr', 'kBtu/hr').get.round
|
267
|
-
max_cap_kbtu_per_hr = OpenStudio.convert(max_cap_btu_per_hr, 'Btu/hr', 'kBtu/hr').get.round
|
268
|
-
|
269
|
-
# Modify the name of the dx_coil to reflect the capacity range
|
270
|
-
old_name = dx_coil.name.get.to_s
|
271
|
-
m = old_name.match(/(\d+)kBtu\/hr/)
|
272
|
-
if m
|
273
|
-
# Put the fuel type into the name
|
274
|
-
old_type = "Coil Cooling DX Single Speed 1 #{props['subcategory']}"
|
275
|
-
new_type = "#{props['cooling_type']} #{props['heating_type']} #{props['subcategory']} DX"
|
276
|
-
new_name = old_name.gsub(old_type, new_type)
|
277
|
-
# Swap out the capacity number for a range
|
278
|
-
old_cap = m[1]
|
279
|
-
if max_cap_kbtu_per_hr == 10_000 # Value representing infinity
|
280
|
-
new_cap = "> #{min_cap_kbtu_per_hr}"
|
281
|
-
else
|
282
|
-
new_cap = "#{min_cap_kbtu_per_hr}-#{max_cap_kbtu_per_hr}"
|
283
|
-
end
|
284
|
-
new_name = new_name.gsub(old_cap, new_cap)
|
285
|
-
dx_coil.setName(new_name)
|
286
|
-
puts "#{props['template']}: #{dx_coil.name.get.to_s}"
|
368
|
+
# Space Types
|
369
|
+
if include_space_types
|
370
|
+
puts "* Space Types *"
|
371
|
+
std.standards_data['space_types'].each do |props|
|
372
|
+
next unless props['template'] == template_name
|
287
373
|
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
374
|
+
# Create a new space type
|
375
|
+
space_type = OpenStudio::Model::SpaceType.new(model)
|
376
|
+
space_type.setStandardsBuildingType(props['building_type'])
|
377
|
+
space_type.setStandardsSpaceType(props['space_type'])
|
378
|
+
space_type.setName("#{props['building_type']} #{props['space_type']}")
|
292
379
|
|
293
|
-
|
380
|
+
# Rendering color
|
381
|
+
std_applier.space_type_apply_rendering_color(space_type)
|
294
382
|
|
295
|
-
|
296
|
-
|
383
|
+
# Loads
|
384
|
+
std_applier.space_type_apply_internal_loads(space_type, true, true, true, true, true, true)
|
385
|
+
|
386
|
+
# Schedules
|
387
|
+
std_applier.space_type_apply_internal_load_schedules(space_type, true, true, true, true, true, true, true)
|
297
388
|
|
298
|
-
# Heat Pumps
|
299
|
-
if include_heat_pumps
|
300
|
-
std.standards_data['heat_pumps'].each do |props|
|
301
|
-
lib = template_to_lib_models[props['template']]
|
302
|
-
next if lib.nil? # Skip unsupported templates
|
303
|
-
# Skip NECB 2011 for now
|
304
|
-
next if props['template'] == 'NECB 2011'
|
305
|
-
model = lib['model']
|
306
|
-
std_applier = lib['standard_applier']
|
307
|
-
|
308
|
-
# Skip interim efficiency requirements
|
309
|
-
next unless props['end_date'] == "2999-09-09T00:00:00+00:00"
|
310
|
-
|
311
|
-
# Make a new DX cooling coil
|
312
|
-
clg_coil = OpenStudio::Model::CoilCoolingDXSingleSpeed.new(model)
|
313
|
-
# Set capacity to middle of range
|
314
|
-
min_clg_cap_btu_per_hr = props['minimum_capacity'].to_f
|
315
|
-
max_clg_cap_btu_per_hr = props['maximum_capacity'].to_f
|
316
|
-
mid_clg_cap_btu_per_hr = (min_clg_cap_btu_per_hr + max_clg_cap_btu_per_hr) / 2
|
317
|
-
mid_clg_cap_w = OpenStudio.convert(mid_clg_cap_btu_per_hr, 'Btu/hr', 'W').get
|
318
|
-
clg_coil.setRatedTotalCoolingCapacity(mid_clg_cap_w)
|
319
|
-
|
320
|
-
# Make a new DX heating coil sized at 90% of the capacity
|
321
|
-
# of the cooling coil.
|
322
|
-
htg_coil = OpenStudio::Model::CoilHeatingDXSingleSpeed.new(model)
|
323
|
-
mid_htg_cap_w = mid_clg_cap_w * 0.9
|
324
|
-
htg_coil.setRatedTotalHeatingCapacity(mid_htg_cap_w)
|
325
|
-
|
326
|
-
# If it is a PTHP Coil, add to PTHP
|
327
|
-
# If not, add to unitary HP
|
328
|
-
if props['subcategory'] == 'PTHP'
|
329
|
-
if props['heating_type'] == 'Electric Resistance or None'
|
330
|
-
backup_htg_coil = OpenStudio::Model::CoilHeatingElectric.new(model)
|
331
|
-
backup_htg_coil.setName('PTHP Electric Backup Htg Coil')
|
332
|
-
else
|
333
|
-
backup_htg_coil = OpenStudio::Model::CoilHeatingGas.new(model)
|
334
|
-
backup_htg_coil.setName('PTHP Electric Backup Htg Coil')
|
335
|
-
end
|
336
|
-
fan = OpenStudio::Model::FanOnOff.new(model, model.alwaysOnDiscreteSchedule)
|
337
|
-
fan.setName("PTHP Supply Fan")
|
338
|
-
pthp = OpenStudio::Model::ZoneHVACPackagedTerminalHeatPump.new(model,
|
339
|
-
model.alwaysOnDiscreteSchedule,
|
340
|
-
fan,
|
341
|
-
htg_coil,
|
342
|
-
clg_coil,
|
343
|
-
backup_htg_coil)
|
344
|
-
else
|
345
|
-
if props['heating_type'] == 'Electric Resistance or None'
|
346
|
-
backup_htg_coil = OpenStudio::Model::CoilHeatingElectric.new(model)
|
347
|
-
backup_htg_coil.setName('Unitary Heat Pump Electric Backup Htg Coil')
|
348
|
-
else
|
349
|
-
backup_htg_coil = OpenStudio::Model::CoilHeatingGas.new(model)
|
350
|
-
backup_htg_coil.setName('Unitary Heat Pump Electric Backup Htg Coil')
|
351
389
|
end
|
352
|
-
fan = OpenStudio::Model::FanOnOff.new(model, model.alwaysOnDiscreteSchedule)
|
353
|
-
fan.setName("Unitary Heat Pump Supply Fan")
|
354
|
-
unitary_system = OpenStudio::Model::AirLoopHVACUnitaryHeatPumpAirToAir.new(model,
|
355
|
-
model.alwaysOnDiscreteSchedule,
|
356
|
-
fan,
|
357
|
-
htg_coil,
|
358
|
-
clg_coil,
|
359
|
-
backup_htg_coil)
|
360
|
-
unitary_system.setName("Unitary Heat Pump")
|
361
|
-
unitary_system.setMaximumOutdoorDryBulbTemperatureforSupplementalHeaterOperation(OpenStudio.convert(40, 'F', 'C').get)
|
362
390
|
end
|
363
391
|
|
364
|
-
#
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
m = old_name.match(/(\d+)kBtu\/hr/)
|
379
|
-
if m
|
380
|
-
# Put the fuel type into the name
|
381
|
-
old_type = 'Coil Cooling DX Single Speed 1'
|
382
|
-
new_type = "#{props['cooling_type']} #{props['heating_type']} #{props['subcategory']} DX"
|
383
|
-
new_name = old_name.gsub(old_type, new_type)
|
384
|
-
# Swap out the capacity number for a range
|
385
|
-
old_cap = m[1]
|
386
|
-
if max_clg_cap_kbtu_per_hr == 10_000 # Value representing infinity
|
387
|
-
new_cap = "> #{min_clg_cap_kbtu_per_hr}"
|
388
|
-
else
|
389
|
-
new_cap = "#{min_clg_cap_kbtu_per_hr}-#{max_clg_cap_kbtu_per_hr}"
|
390
|
-
end
|
391
|
-
new_name = new_name.gsub(old_cap, new_cap)
|
392
|
-
clg_coil.setName(new_name)
|
393
|
-
puts "#{props['template']}: #{clg_coil.name.get.to_s}"
|
394
|
-
|
395
|
-
# Rename PTHP or unitary same as the cooling coil
|
396
|
-
if pthp
|
397
|
-
pthp.setName("PTHP #{new_name}")
|
398
|
-
else
|
399
|
-
unitary_system.setName("Unitary Heat Pump #{new_name}")
|
392
|
+
# Construction Sets, Constructions, and Materials
|
393
|
+
# TODO fix code to remove duplicate constructions and materials
|
394
|
+
if include_construction_sets
|
395
|
+
puts "* Construction Sets *"
|
396
|
+
std.standards_data['construction_sets'].each do |props|
|
397
|
+
next unless props['template'] == template_name
|
398
|
+
# Add a construction set for each valid climate zone
|
399
|
+
templates_to_climate_zones[props['template']].each do |climate_zone|
|
400
|
+
construction_set = std_applier.model_add_construction_set(model,
|
401
|
+
climate_zone,
|
402
|
+
props['building_type'],
|
403
|
+
props['space_type'],
|
404
|
+
props['is_residential'])
|
405
|
+
end
|
400
406
|
end
|
407
|
+
end
|
401
408
|
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
htg_coil.setName(new_name)
|
410
|
-
|
409
|
+
# Delete all the unused curves
|
410
|
+
puts '* Cleaning up the unused curves *'
|
411
|
+
model.getCurves.sort.each do |curve|
|
412
|
+
if curve.directUseCount == 0
|
413
|
+
puts " #{curve.name} is unused; successfully removed? #{model.removeObject(curve.handle)}."
|
414
|
+
# curve.remove # For some reason curve.remove doesn't work properly
|
415
|
+
end
|
411
416
|
end
|
412
417
|
|
418
|
+
# Save the library
|
419
|
+
osm_lib_dir = "#{__dir__}/../../pkg/libraries"
|
420
|
+
Dir.mkdir(osm_lib_dir) unless Dir.exists?(osm_lib_dir)
|
421
|
+
library_path = "#{osm_lib_dir}/#{template_name.gsub(/\W/,'_')}.osm"
|
422
|
+
puts "* Saving library #{library_path}"
|
423
|
+
model.save(OpenStudio::Path.new(library_path), true)
|
424
|
+
|
425
|
+
# Save the log messages for debugging library creation
|
426
|
+
log_path = "#{osm_lib_dir}/#{template_name.gsub(/\W/,'_')}.log"
|
427
|
+
puts "* Saving log #{log_path}"
|
428
|
+
log_messages_to_file(log_path, debug=false)
|
429
|
+
|
430
|
+
# Show the timing
|
431
|
+
template_end_time = Time.now
|
432
|
+
template_time_min = ((template_end_time - template_start_time)/60.0).round(1)
|
433
|
+
puts "* Finished #{template_name} at: #{template_end_time}, time elapsed = #{template_time_min} min."
|
434
|
+
|
435
|
+
rescue Exception => exc
|
436
|
+
puts "ERROR creating '#{template_name}', skipping to next template."
|
437
|
+
puts "#{exc}"
|
438
|
+
puts "Backtrace:\n\t#{e.caller.join("\n\t")}"
|
439
|
+
puts "Backtrace:\n\t#{e.backtrace.join("\n\t")}"
|
440
|
+
|
441
|
+
# Save the log messages for debugging library creation even on failure
|
442
|
+
log_path = "#{osm_lib_dir}/#{template_name.gsub(/\W/,'_')}.log"
|
443
|
+
puts "* Saving log #{log_path}"
|
444
|
+
log_messages_to_file(log_path, debug=false)
|
413
445
|
end
|
414
|
-
end
|
415
446
|
|
416
|
-
# Delete all the unused curves
|
417
|
-
puts 'Cleaning up the unused curves'
|
418
|
-
template_to_lib_models.each do |template, data|
|
419
|
-
puts ''
|
420
|
-
puts "***#{template}***"
|
421
|
-
data['model'].getCurves.sort.each do |curve|
|
422
|
-
if curve.directUseCount == 0
|
423
|
-
puts " #{curve.name} is unused; successfully removed? #{data['model'].removeObject(curve.handle)}."
|
424
|
-
# curve.remove # For some reason curve.remove doesn't work properly
|
425
|
-
end
|
426
|
-
end
|
427
447
|
end
|
428
448
|
|
429
|
-
#
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
library_path = "#{osm_lib_dir}/#{template.gsub(/\W/,'_')}.osm"
|
434
|
-
puts "Saving library #{library_path}"
|
435
|
-
data['model'].save(OpenStudio::Path.new(library_path), true)
|
436
|
-
end
|
449
|
+
# Show the timing
|
450
|
+
end_time = Time.now
|
451
|
+
total_time_min = ((end_time - start_time)/60.0).round(1)
|
452
|
+
puts "*** Finished all templates at: #{end_time}, time elapsed = #{total_time_min} min."
|
437
453
|
|
438
454
|
end
|
@@ -71,8 +71,8 @@ module Hospital
|
|
71
71
|
elec_equip_def1.setDesignLevel(915)
|
72
72
|
elec_equip_def2.setDesignLevel(855)
|
73
73
|
else
|
74
|
-
elec_equip_def1.setDesignLevel(
|
75
|
-
elec_equip_def2.setDesignLevel(
|
74
|
+
elec_equip_def1.setDesignLevel(915)
|
75
|
+
elec_equip_def2.setDesignLevel(855)
|
76
76
|
end
|
77
77
|
# Create the electric equipment instance and hook it up to the space type
|
78
78
|
elec_equip1 = OpenStudio::Model::ElectricEquipment.new(elec_equip_def1)
|
@@ -106,8 +106,8 @@ module LargeHotel
|
|
106
106
|
elec_equip_def1.setDesignLevel(457.7)
|
107
107
|
elec_equip_def2.setDesignLevel(285)
|
108
108
|
else
|
109
|
-
elec_equip_def1.setDesignLevel(
|
110
|
-
elec_equip_def2.setDesignLevel(
|
109
|
+
elec_equip_def1.setDesignLevel(457.7)
|
110
|
+
elec_equip_def2.setDesignLevel(285)
|
111
111
|
end
|
112
112
|
# Create the electric equipment instance and hook it up to the space type
|
113
113
|
elec_equip1 = OpenStudio::Model::ElectricEquipment.new(elec_equip_def1)
|
@@ -33,8 +33,8 @@ module PrimarySchool
|
|
33
33
|
elec_equip_def1.setDesignLevel(915)
|
34
34
|
elec_equip_def2.setDesignLevel(570)
|
35
35
|
else
|
36
|
-
elec_equip_def1.setDesignLevel(
|
37
|
-
elec_equip_def2.setDesignLevel(
|
36
|
+
elec_equip_def1.setDesignLevel(1032)
|
37
|
+
elec_equip_def2.setDesignLevel(852)
|
38
38
|
end
|
39
39
|
# Create the electric equipment instance and hook it up to the space type
|
40
40
|
elec_equip1 = OpenStudio::Model::ElectricEquipment.new(elec_equip_def1)
|
@@ -49,8 +49,8 @@ module SecondarySchool
|
|
49
49
|
elec_equip_def1.setDesignLevel(915)
|
50
50
|
elec_equip_def2.setDesignLevel(570)
|
51
51
|
else
|
52
|
-
elec_equip_def1.setDesignLevel(
|
53
|
-
elec_equip_def2.setDesignLevel(
|
52
|
+
elec_equip_def1.setDesignLevel(1032)
|
53
|
+
elec_equip_def2.setDesignLevel(852)
|
54
54
|
end
|
55
55
|
# Create the electric equipment instance and hook it up to the space type
|
56
56
|
elec_equip1 = OpenStudio::Model::ElectricEquipment.new(elec_equip_def1)
|
@@ -78,4 +78,17 @@ module References
|
|
78
78
|
# @see http://deeresources.com/index.php/deer-versions
|
79
79
|
class DEERMASControl; end
|
80
80
|
|
81
|
+
# OEESC 2014
|
82
|
+
# The Oregon Energy Efficiency Specialty Code is the building energy code for the
|
83
|
+
# state of Oregon. It is very similar to ASHRAE 90.1-2013, but has been tailored
|
84
|
+
# to meet the needs of Oregon.
|
85
|
+
# @see http://www.oregon.gov/bcd/codes-stand/Pages/energy-efficiency.aspx
|
86
|
+
class OEESC2014; end
|
87
|
+
|
88
|
+
# ICC IECC 2015
|
89
|
+
# The International Code Council's International Energy Conservation Code is widely
|
90
|
+
# used across the United States.
|
91
|
+
# @see https://codes.iccsafe.org/public/document/toc/545/
|
92
|
+
class ICCIECC2015; end
|
93
|
+
|
81
94
|
end
|
@@ -265,7 +265,7 @@ class Standard
|
|
265
265
|
# Only applies to fenestration constructions.
|
266
266
|
# @return [Double] the SHGC as a decimal.
|
267
267
|
def construction_calculated_solar_heat_gain_coefficient(construction)
|
268
|
-
construction_name = name.get.to_s
|
268
|
+
construction_name = construction.name.get.to_s
|
269
269
|
|
270
270
|
shgc = nil
|
271
271
|
|
@@ -286,7 +286,7 @@ class Standard
|
|
286
286
|
if row_id.is_initialized
|
287
287
|
row_id = row_id.get
|
288
288
|
else
|
289
|
-
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.model.
|
289
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.model.Construction', "SHGC row ID not found for construction: #{construction_name}.")
|
290
290
|
row_id = 9999
|
291
291
|
end
|
292
292
|
|
@@ -315,7 +315,7 @@ class Standard
|
|
315
315
|
# Only applies to fenestration constructions.
|
316
316
|
# @return [Double] the visible transmittance as a decimal.
|
317
317
|
def construction_calculated_visible_transmittance(construction)
|
318
|
-
construction_name = name.get.to_s
|
318
|
+
construction_name = construction.name.get.to_s
|
319
319
|
|
320
320
|
vt = nil
|
321
321
|
|
@@ -365,7 +365,7 @@ class Standard
|
|
365
365
|
# Only applies to fenestration constructions.
|
366
366
|
# @return [Double] the U-Factor in W/m^2*K.
|
367
367
|
def construction_calculated_u_factor(construction)
|
368
|
-
construction_name = name.get.to_s
|
368
|
+
construction_name = construction.name.get.to_s
|
369
369
|
|
370
370
|
u_factor_w_per_m2_k = nil
|
371
371
|
|
@@ -386,7 +386,7 @@ class Standard
|
|
386
386
|
if row_id.is_initialized
|
387
387
|
row_id = row_id.get
|
388
388
|
else
|
389
|
-
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.model.
|
389
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.model.Construction', "U-Factor row ID not found for construction: #{construction_name}.")
|
390
390
|
row_id = 9999
|
391
391
|
end
|
392
392
|
|
@@ -405,7 +405,7 @@ class Standard
|
|
405
405
|
end
|
406
406
|
|
407
407
|
else
|
408
|
-
OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.
|
408
|
+
OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Construction', 'Model has no sql file containing results, cannot lookup data.')
|
409
409
|
end
|
410
410
|
|
411
411
|
return u_factor_w_per_m2_k
|
@@ -278,13 +278,24 @@ module Pump
|
|
278
278
|
end
|
279
279
|
|
280
280
|
rated_m3_per_s = 0
|
281
|
-
if pump.
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
281
|
+
if pump.to_PumpVariableSpeed.is_initialized || pump.to_PumpConstantSpeed.is_initialized
|
282
|
+
if pump.ratedFlowRate.is_initialized
|
283
|
+
rated_m3_per_s = pump.ratedFlowRate.get
|
284
|
+
elsif pump.autosizedRatedFlowRate.is_initialized
|
285
|
+
rated_m3_per_s = pump.autosizedRatedFlowRate.get
|
286
|
+
else
|
287
|
+
OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Pump', "For #{pump.name}, could not find rated pump Flow Rate, cannot determine w per gpm correctly.")
|
288
|
+
return 0.0
|
289
|
+
end
|
290
|
+
elsif pump.to_HeaderedPumpsVariableSpeed.is_initialized || pump.to_HeaderedPumpsConstantSpeed.is_initialized
|
291
|
+
if pump.totalRatedFlowRate.is_initialized
|
292
|
+
rated_m3_per_s = pump.totalRatedFlowRate.get
|
293
|
+
elsif pump.autosizedTotalRatedFlowRate.is_initialized
|
294
|
+
rated_m3_per_s = pump.autosizedTotalRatedFlowRate.get
|
295
|
+
else
|
296
|
+
OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Pump', "For #{pump.name}, could not find rated pump Flow Rate, cannot determine w per gpm correctly.")
|
297
|
+
return 0.0
|
298
|
+
end
|
288
299
|
end
|
289
300
|
|
290
301
|
rated_w_per_m3s = rated_power_w / rated_m3_per_s
|
@@ -79,7 +79,7 @@ class Standard
|
|
79
79
|
|
80
80
|
previous_time_decimal = 0
|
81
81
|
times.each_with_index do |time, i|
|
82
|
-
time_decimal = (time.days * 24) + time.hours + (time.minutes / 60) + (time.seconds / 3600)
|
82
|
+
time_decimal = (time.days * 24.0) + time.hours + (time.minutes / 60.0) + (time.seconds / 3600.0)
|
83
83
|
duration_of_value = time_decimal - previous_time_decimal
|
84
84
|
# OpenStudio::logFree(OpenStudio::Debug, "openstudio.standards.ScheduleRuleset", " Value of #{values[i]} for #{duration_of_value} hours")
|
85
85
|
daily_flh += values[i] * duration_of_value
|
@@ -219,7 +219,7 @@ class Standard
|
|
219
219
|
|
220
220
|
previous_time_decimal = 0
|
221
221
|
times.each_with_index do |time, i|
|
222
|
-
time_decimal = (time.days * 24) + time.hours + (time.minutes / 60) + (time.seconds / 3600)
|
222
|
+
time_decimal = (time.days * 24.0) + time.hours + (time.minutes / 60.0) + (time.seconds / 3600.0)
|
223
223
|
duration_of_value = time_decimal - previous_time_decimal
|
224
224
|
# OpenStudio::logFree(OpenStudio::Debug, "openstudio.standards.ScheduleRuleset", " Value of #{values[i]} for #{duration_of_value} hours")
|
225
225
|
daily_hrs += values[i] * duration_of_value
|
@@ -396,7 +396,7 @@ class Standard
|
|
396
396
|
# Electricity, NaturalGas, PropaneGas, FuelOil#1, FuelOil#2,
|
397
397
|
# Coal, Diesel, Gasoline, DistrictHeating,
|
398
398
|
# and SolarEnergy.
|
399
|
-
htg_fuels = heating_fuels
|
399
|
+
htg_fuels = thermal_zone.heating_fuels
|
400
400
|
|
401
401
|
if htg_fuels.include?('NaturalGas') ||
|
402
402
|
htg_fuels.include?('PropaneGas') ||
|
@@ -498,7 +498,7 @@ class Standard
|
|
498
498
|
# Electricity, NaturalGas, PropaneGas, FuelOil#1, FuelOil#2,
|
499
499
|
# Coal, Diesel, Gasoline, DistrictHeating,
|
500
500
|
# and SolarEnergy.
|
501
|
-
htg_fuels = heating_fuels
|
501
|
+
htg_fuels = thermal_zone.heating_fuels
|
502
502
|
|
503
503
|
# Includes fossil
|
504
504
|
fossil = false
|
@@ -576,7 +576,7 @@ class Standard
|
|
576
576
|
has_ptac = false
|
577
577
|
has_pthp = false
|
578
578
|
has_unitheater = false
|
579
|
-
equipment.each do |equip|
|
579
|
+
thermal_zone.equipment.each do |equip|
|
580
580
|
# Skip HVAC components
|
581
581
|
next unless equip.to_HVACComponent.is_initialized
|
582
582
|
equip = equip.to_HVACComponent.get
|
@@ -601,8 +601,8 @@ class Standard
|
|
601
601
|
end
|
602
602
|
|
603
603
|
# Get the zone heating and cooling fuels
|
604
|
-
htg_fuels = heating_fuels
|
605
|
-
clg_fuels = cooling_fuels
|
604
|
+
htg_fuels = thermal_zone.heating_fuels
|
605
|
+
clg_fuels = thermal_zone.cooling_fuels
|
606
606
|
is_fossil = thermal_zone_fossil_hybrid_or_purchased_heat?(thermal_zone)
|
607
607
|
|
608
608
|
# Infer the HVAC type
|
@@ -615,7 +615,7 @@ class Standard
|
|
615
615
|
# Air Loop
|
616
616
|
if has_air_loop
|
617
617
|
# Gas_Furnace (as air loop)
|
618
|
-
sys_type = if
|
618
|
+
sys_type = if clg_fuels.size.zero?
|
619
619
|
'Gas_Furnace'
|
620
620
|
# PSZ_AC
|
621
621
|
else
|
@@ -637,7 +637,7 @@ class Standard
|
|
637
637
|
# Air Loop
|
638
638
|
if has_air_loop
|
639
639
|
# Electric_Furnace (as air loop)
|
640
|
-
sys_type = if
|
640
|
+
sys_type = if clg_fuels.size.zero?
|
641
641
|
'Electric_Furnace'
|
642
642
|
# PSZ_HP
|
643
643
|
else
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# This class will hold methods that apply ICC IECC 2015
|
2
|
+
# to a given model.
|
3
|
+
# @todo ICC IECC 2015 is incomplete and will default to the logic
|
4
|
+
# in the default Standard class methods
|
5
|
+
# @ref [References::ICCIECC2015]
|
6
|
+
class ICCIECC2015 < ICCIECC
|
7
|
+
@@template = 'ICC IECC 2015' # rubocop:disable Style/ClassVars
|
8
|
+
register_standard @@template
|
9
|
+
attr_reader :template
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
super()
|
13
|
+
@template = @@template
|
14
|
+
load_standards_database
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# This class will hold methods that apply OEESC 2014
|
2
|
+
# to a given model.
|
3
|
+
# @todo OEESC 2014 is incomplete and will default to the logic
|
4
|
+
# in the default Standard class methods
|
5
|
+
# @ref [References::OEESC2014]
|
6
|
+
class OEESC2014 < OEESC
|
7
|
+
@@template = 'OEESC 2014' # rubocop:disable Style/ClassVars
|
8
|
+
register_standard @@template
|
9
|
+
attr_reader :template
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
super()
|
13
|
+
@template = @@template
|
14
|
+
load_standards_database
|
15
|
+
end
|
16
|
+
end
|
data/lib/openstudio-standards.rb
CHANGED
@@ -85,6 +85,12 @@ module OpenstudioStandards
|
|
85
85
|
require_relative "#{stds}/deer/deer_2015/deer_2015"
|
86
86
|
require_relative "#{stds}/deer/deer_2017/deer_2017"
|
87
87
|
|
88
|
+
require_relative "#{stds}/oeesc/oeesc"
|
89
|
+
require_relative "#{stds}/oeesc/oeesc_2014/oeesc_2014"
|
90
|
+
|
91
|
+
require_relative "#{stds}/icc_iecc/icc_iecc"
|
92
|
+
require_relative "#{stds}/icc_iecc/icc_iecc_2015/icc_iecc_2015"
|
93
|
+
|
88
94
|
# Files with modules
|
89
95
|
require_relative "#{stds}/Standards.Fan"
|
90
96
|
require_relative "#{stds}/Standards.CoilDX"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: openstudio-standards
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.0.
|
4
|
+
version: 0.2.0.rc2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Parker
|
@@ -21,7 +21,7 @@ authors:
|
|
21
21
|
autorequire:
|
22
22
|
bindir: bin
|
23
23
|
cert_chain: []
|
24
|
-
date: 2018-
|
24
|
+
date: 2018-03-16 00:00:00.000000000 Z
|
25
25
|
dependencies:
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: minitest-reporters
|
@@ -141,14 +141,14 @@ dependencies:
|
|
141
141
|
requirements:
|
142
142
|
- - "~>"
|
143
143
|
- !ruby/object:Gem::Version
|
144
|
-
version: '0.
|
144
|
+
version: '0.53'
|
145
145
|
type: :development
|
146
146
|
prerelease: false
|
147
147
|
version_requirements: !ruby/object:Gem::Requirement
|
148
148
|
requirements:
|
149
149
|
- - "~>"
|
150
150
|
- !ruby/object:Gem::Version
|
151
|
-
version: '0.
|
151
|
+
version: '0.53'
|
152
152
|
- !ruby/object:Gem::Dependency
|
153
153
|
name: rubocop-checkstyle_formatter
|
154
154
|
requirement: !ruby/object:Gem::Requirement
|
@@ -1560,6 +1560,8 @@ files:
|
|
1560
1560
|
- lib/openstudio-standards/standards/deer/deer_2015/deer_2015.rb
|
1561
1561
|
- lib/openstudio-standards/standards/deer/deer_2017/deer_2017.rb
|
1562
1562
|
- lib/openstudio-standards/standards/deer/deer_pre_1975/deer_pre_1975.rb
|
1563
|
+
- lib/openstudio-standards/standards/icc_iecc/icc_iecc.rb
|
1564
|
+
- lib/openstudio-standards/standards/icc_iecc/icc_iecc_2015/icc_iecc_2015.rb
|
1563
1565
|
- lib/openstudio-standards/standards/necb/necb_2011/beps_compliance_path.rb
|
1564
1566
|
- lib/openstudio-standards/standards/necb/necb_2011/building_envelope.rb
|
1565
1567
|
- lib/openstudio-standards/standards/necb/necb_2011/data/boilers.json
|
@@ -1592,6 +1594,8 @@ files:
|
|
1592
1594
|
- lib/openstudio-standards/standards/necb/necb_2011/necb_2011.rb
|
1593
1595
|
- lib/openstudio-standards/standards/necb/necb_2011/service_water_heating.rb
|
1594
1596
|
- lib/openstudio-standards/standards/necb/necb_2015/necb_2015.rb
|
1597
|
+
- lib/openstudio-standards/standards/oeesc/oeesc.rb
|
1598
|
+
- lib/openstudio-standards/standards/oeesc/oeesc_2014/oeesc_2014.rb
|
1595
1599
|
- lib/openstudio-standards/standards/standard.rb
|
1596
1600
|
- lib/openstudio-standards/utilities/convert_costing_constructions.rb
|
1597
1601
|
- lib/openstudio-standards/utilities/define_thermal_zone_and_mulitpliers.rb
|