openstudio-standards 0.2.8 → 0.2.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (22) hide show
  1. checksums.yaml +4 -4
  2. data/data/geometry/ASHRAEPrimarySchool.osm +36 -2
  3. data/data/geometry/ASHRAESecondarySchool.osm +19 -2
  4. data/data/standards/OpenStudio_Standards_elevators.json +10756 -0
  5. data/lib/openstudio-standards.rb +0 -2
  6. data/lib/openstudio-standards/hvac_sizing/Siz.HVACComponent.rb +36 -0
  7. data/lib/openstudio-standards/hvac_sizing/Siz.Model.rb +3 -0
  8. data/lib/openstudio-standards/prototypes/common/objects/Prototype.Model.elevators.rb +175 -164
  9. data/lib/openstudio-standards/prototypes/common/objects/Prototype.Model.swh.rb +268 -476
  10. data/lib/openstudio-standards/prototypes/common/objects/Prototype.ServiceWaterHeating.rb +625 -116
  11. data/lib/openstudio-standards/prototypes/common/objects/Prototype.hvac_systems.rb +4 -0
  12. data/lib/openstudio-standards/standards/Standards.AirLoopHVAC.rb +2 -19
  13. data/lib/openstudio-standards/standards/Standards.ThermalZone.rb +112 -68
  14. data/lib/openstudio-standards/standards/Standards.WaterHeaterMixed.rb +10 -2
  15. data/lib/openstudio-standards/standards/necb/necb_2011/data/space_types.json +224 -224
  16. data/lib/openstudio-standards/standards/necb/necb_2011/service_water_heating.rb +8 -16
  17. data/lib/openstudio-standards/standards/necb/necb_2015/data/space_types.json +318 -318
  18. data/lib/openstudio-standards/standards/standard.rb +1 -0
  19. data/lib/openstudio-standards/version.rb +1 -1
  20. metadata +4 -4
  21. data/lib/openstudio-standards/prototypes/ashrae_90_1/doe_ref_1980_2004/doe_ref_1980_2004.hvac_systems.rb +0 -15
  22. data/lib/openstudio-standards/prototypes/ashrae_90_1/doe_ref_pre_1980/doe_ref_pre_1980.hvac_systems.rb +0 -15
@@ -28,13 +28,12 @@ class Standard
28
28
  'Main Service Water Loop',
29
29
  water_heater_zone,
30
30
  OpenStudio.convert(prototype_input['main_service_water_temperature'], 'F', 'C').get,
31
- prototype_input['main_service_water_pump_head'],
31
+ prototype_input['main_service_water_pump_head'].to_f,
32
32
  prototype_input['main_service_water_pump_motor_efficiency'],
33
33
  OpenStudio.convert(prototype_input['main_water_heater_capacity'], 'Btu/hr', 'W').get,
34
34
  OpenStudio.convert(prototype_input['main_water_heater_volume'], 'gal', 'm^3').get,
35
35
  swh_fueltype,
36
- OpenStudio.convert(prototype_input['main_service_water_parasitic_fuel_consumption_rate'], 'Btu/hr', 'W').get,
37
- building_type)
36
+ OpenStudio.convert(prototype_input['main_service_water_parasitic_fuel_consumption_rate'], 'Btu/hr', 'W').get)
38
37
  end
39
38
 
40
39
  # Attach the end uses if specified in prototype inputs
@@ -52,8 +51,7 @@ class Standard
52
51
  OpenStudio.convert(prototype_input['main_service_water_peak_flowrate'], 'gal/min', 'm^3/s').get,
53
52
  prototype_input['main_service_water_flowrate_schedule'],
54
53
  OpenStudio.convert(prototype_input['main_water_use_temperature'], 'F', 'C').get,
55
- space_name,
56
- building_type)
54
+ space_name)
57
55
  end
58
56
  elsif building_type == 'LargeOfficeDetailed' && template != 'NECB2011'
59
57
 
@@ -65,8 +63,7 @@ class Standard
65
63
  OpenStudio.convert(prototype_input['main_service_water_peak_flowrate'], 'gal/min', 'm^3/s').get,
66
64
  prototype_input['main_service_water_flowrate_schedule'],
67
65
  OpenStudio.convert(prototype_input['main_water_use_temperature'], 'F', 'C').get,
68
- space_name,
69
- building_type)
66
+ space_name)
70
67
  end
71
68
  elsif building_type == 'RetailStripmall' && template != 'NECB2011'
72
69
 
@@ -87,13 +84,12 @@ class Standard
87
84
  "#{swh_thermal_zone.name} Service Water Loop",
88
85
  swh_thermal_zone,
89
86
  OpenStudio.convert(prototype_input['main_service_water_temperature'], 'F', 'C').get,
90
- prototype_input['main_service_water_pump_head'],
87
+ prototype_input['main_service_water_pump_head'].to_f,
91
88
  prototype_input['main_service_water_pump_motor_efficiency'],
92
89
  OpenStudio.convert(prototype_input['main_water_heater_capacity'], 'Btu/hr', 'W').get,
93
90
  OpenStudio.convert(prototype_input['main_water_heater_volume'], 'gal', 'm^3').get,
94
91
  prototype_input['main_water_heater_fuel'],
95
- OpenStudio.convert(prototype_input['main_service_water_parasitic_fuel_consumption_rate'], 'Btu/hr', 'W').get,
96
- building_type)
92
+ OpenStudio.convert(prototype_input['main_service_water_parasitic_fuel_consumption_rate'], 'Btu/hr', 'W').get)
97
93
 
98
94
  model_add_swh_end_uses(model,
99
95
  'Main',
@@ -101,8 +97,7 @@ class Standard
101
97
  rated_flow_rate_m3_per_s,
102
98
  swh_sch_name,
103
99
  OpenStudio.convert(prototype_input['main_water_use_temperature'], 'F', 'C').get,
104
- swh_space_name,
105
- building_type)
100
+ swh_space_name)
106
101
  end
107
102
 
108
103
  elsif prototype_input['main_service_water_peak_flowrate']
@@ -115,8 +110,7 @@ class Standard
115
110
  OpenStudio.convert(prototype_input['main_service_water_peak_flowrate'], 'gal/min', 'm^3/s').get,
116
111
  prototype_input['main_service_water_flowrate_schedule'],
117
112
  OpenStudio.convert(prototype_input['main_water_use_temperature'], 'F', 'C').get,
118
- nil,
119
- building_type)
113
+ nil)
120
114
 
121
115
  else
122
116
  OpenStudio.logFree(OpenStudio::Debug, 'openstudio.model.Model', 'Adding shw by space_type_map')
@@ -158,11 +152,9 @@ class Standard
158
152
  space.multiplier
159
153
  end
160
154
 
161
- water_fixture = model_add_swh_end_uses_by_space(model, model_get_lookup_name(building_type),
162
- climate_zone,
155
+ water_fixture = model_add_swh_end_uses_by_space(model,
163
156
  main_swh_loop,
164
- space_type_name,
165
- space_name,
157
+ space,
166
158
  space_multiplier)
167
159
  unless water_fixture.nil?
168
160
  water_fixtures << water_fixture
@@ -187,16 +179,14 @@ class Standard
187
179
  prototype_input['booster_water_heater_fuel'],
188
180
  OpenStudio.convert(prototype_input['booster_water_temperature'], 'F', 'C').get,
189
181
  0,
190
- nil,
191
- building_type)
182
+ nil)
192
183
 
193
184
  # Attach the end uses
194
185
  model_add_booster_swh_end_uses(model,
195
186
  swh_booster_loop,
196
187
  OpenStudio.convert(prototype_input['booster_service_water_peak_flowrate'], 'gal/min', 'm^3/s').get,
197
188
  prototype_input['booster_service_water_flowrate_schedule'],
198
- OpenStudio.convert(prototype_input['booster_water_use_temperature'], 'F', 'C').get,
199
- building_type)
189
+ OpenStudio.convert(prototype_input['booster_water_use_temperature'], 'F', 'C').get)
200
190
 
201
191
  end
202
192
 
@@ -208,13 +198,12 @@ class Standard
208
198
  'Laundry Service Water Loop',
209
199
  nil,
210
200
  OpenStudio.convert(prototype_input['laundry_service_water_temperature'], 'F', 'C').get,
211
- prototype_input['laundry_service_water_pump_head'],
201
+ prototype_input['laundry_service_water_pump_head'].to_f,
212
202
  prototype_input['laundry_service_water_pump_motor_efficiency'],
213
203
  OpenStudio.convert(prototype_input['laundry_water_heater_capacity'], 'Btu/hr', 'W').get,
214
204
  OpenStudio.convert(prototype_input['laundry_water_heater_volume'], 'gal', 'm^3').get,
215
205
  prototype_input['laundry_water_heater_fuel'],
216
- OpenStudio.convert(prototype_input['laundry_service_water_parasitic_fuel_consumption_rate'], 'Btu/hr', 'W').get,
217
- building_type)
206
+ OpenStudio.convert(prototype_input['laundry_service_water_parasitic_fuel_consumption_rate'], 'Btu/hr', 'W').get)
218
207
 
219
208
  # Attach the end uses if specified in prototype inputs
220
209
  model_add_swh_end_uses(model,
@@ -223,8 +212,7 @@ class Standard
223
212
  OpenStudio.convert(prototype_input['laundry_service_water_peak_flowrate'], 'gal/min', 'm^3/s').get,
224
213
  prototype_input['laundry_service_water_flowrate_schedule'],
225
214
  OpenStudio.convert(prototype_input['laundry_water_use_temperature'], 'F', 'C').get,
226
- nil,
227
- building_type)
215
+ nil)
228
216
 
229
217
  end
230
218
 
@@ -233,17 +221,18 @@ class Standard
233
221
  return true
234
222
  end
235
223
 
236
- # add swh
237
-
238
224
  # add typical swh demand and supply to model
239
225
  #
240
- # @param trust_effective_num_spaces [Bool]
241
- # @param fuel [String] (gas, electric, nil) nil is smart
242
- # @param pipe_insul_in [Double]
243
- # @param circulating [String] (circulating, noncirculating, nil) nil is smart
226
+ # @param water_heater_fuel [String] water heater fuel. Valid choices are NaturalGas, Electricity, and HeatPump.
227
+ # If not supplied, a smart default will be determined based on building type.
228
+ # @param pipe_insul_in [Double] thickness of the pipe insulation, in inches.
229
+ # @param circulating [String] whether the (circulating, noncirculating, nil) nil is smart
244
230
  # @return [Array] hot water loops
245
231
  # @todo - add in losses from tank and pipe insulation, etc.
246
- def model_add_typical_swh(model, trust_effective_num_spaces = false, fuel = nil, pipe_insul_in = nil, circulating = nil)
232
+ def model_add_typical_swh(model,
233
+ water_heater_fuel: nil,
234
+ pipe_insul_in: nil,
235
+ circulating: nil)
247
236
  # array of hot water loops
248
237
  swh_systems = []
249
238
 
@@ -253,30 +242,30 @@ class Standard
253
242
  # create space type hash (need num_units for MidriseApartment and RetailStripmall)
254
243
  space_type_hash = model_create_space_type_hash(model, trust_effective_num_spaces = false)
255
244
 
256
- # add temperate schedules to hash so they can be shared across water use equipment
257
- water_use_def_schedules = {} # key is temp C value is schedule
258
-
259
245
  # loop through space types adding demand side of swh
260
246
  model.getSpaceTypes.sort.each do |space_type|
261
247
  next unless space_type.standardsBuildingType.is_initialized
262
- next unless space_type.standardsSpaceType.is_initialized
263
248
  next unless space_type_hash.key?(space_type) # this is used for space types without any floor area
264
249
  stds_bldg_type = space_type.standardsBuildingType.get
265
- stds_space_type = space_type.standardsSpaceType.get
266
250
 
267
251
  # lookup space_type_properties
268
252
  space_type_properties = space_type_get_standards_data(space_type)
269
- gal_hr_per_area = space_type_properties['service_water_heating_peak_flow_per_area']
270
- gal_hr_peak_flow_rate = space_type_properties['service_water_heating_peak_flow_rate']
253
+ peak_flow_rate_gal_per_hr_per_ft2 = space_type_properties['service_water_heating_peak_flow_per_area'].to_f
254
+ peak_flow_rate_gal_per_hr = space_type_properties['service_water_heating_peak_flow_rate'].to_f
255
+ swh_system_type = space_type_properties['service_water_heating_system_type']
271
256
  flow_rate_fraction_schedule = model_add_schedule(model, space_type_properties['service_water_heating_schedule'])
272
- service_water_temperature_si = space_type_properties['service_water_heating_target_temperature']
257
+ service_water_temperature_f = space_type_properties['service_water_heating_target_temperature'].to_f
258
+ service_water_temperature_c = OpenStudio.convert(service_water_temperature_f, 'F', 'C').get
259
+ booster_water_temperature_f = space_type_properties['booster_water_heating_target_temperature'].to_f
260
+ booster_water_temperature_c = OpenStudio.convert(booster_water_temperature_f, 'F', 'C').get
261
+ booster_water_heater_fraction = space_type_properties['booster_water_heater_fraction'].to_f
273
262
  service_water_fraction_sensible = space_type_properties['service_water_heating_fraction_sensible']
274
263
  service_water_fraction_latent = space_type_properties['service_water_heating_fraction_latent']
275
- floor_area_si = space_type_hash[space_type][:floor_area]
276
- floor_area_ip = OpenStudio.convert(floor_area_si, 'm^2', 'ft^2').get
264
+ floor_area_m2 = space_type_hash[space_type][:floor_area]
265
+ floor_area_ft2 = OpenStudio.convert(floor_area_m2, 'm^2', 'ft^2').get
277
266
 
278
267
  # next if no service water heating demand
279
- next unless gal_hr_per_area.to_f > 0.0 || gal_hr_peak_flow_rate.to_f > 0.0
268
+ next unless peak_flow_rate_gal_per_hr_per_ft2 > 0.0 || peak_flow_rate_gal_per_hr > 0.0
280
269
 
281
270
  # If there is no SWH schedule specified, assume
282
271
  # that there should be no SWH consumption for this space type.
@@ -285,398 +274,233 @@ class Standard
285
274
  flow_rate_fraction_schedule = model.alwaysOffDiscreteSchedule
286
275
  end
287
276
 
288
- if (stds_bldg_type == 'MidriseApartment' && stds_space_type.include?('Apartment')) || stds_bldg_type == 'StripMall'
289
- num_units = space_type_hash[space_type][:num_units].round
290
- OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', "Adding dedicated water heating fpr #{num_units} #{space_type.name} units, each with max flow rate of #{gal_hr_peak_flow_rate} gal/hr per.")
291
-
292
- # add water use equipment definition
293
- water_use_equip_def = OpenStudio::Model::WaterUseEquipmentDefinition.new(model)
294
- water_use_equip_def.setName("#{space_type.name} SWH def")
295
- peak_flow_rate_si = OpenStudio.convert(gal_hr_peak_flow_rate, 'gal/hr', 'm^3/s').get
296
- water_use_equip_def.setPeakFlowRate(peak_flow_rate_si)
297
- target_temp = service_water_temperature_si # in spreadsheet in si, no conversion needed unless that changes
298
- name = "#{target_temp} C"
299
- if water_use_def_schedules.key?(name)
300
- target_temperature_sch = water_use_def_schedules[name]
301
- else
302
- target_temperature_sch = model_add_constant_schedule_ruleset(model, target_temp, name)
303
- water_use_def_schedules[name] = target_temperature_sch
304
- end
305
- water_use_equip_def.setTargetTemperatureSchedule(target_temperature_sch)
306
- name = "#{service_water_fraction_sensible} Fraction"
307
- if water_use_def_schedules.key?(name)
308
- service_water_fraction_sensible_sch = water_use_def_schedules[name]
309
- else
310
- service_water_fraction_sensible_sch = model_add_constant_schedule_ruleset(model, service_water_fraction_sensible, name)
311
- water_use_def_schedules[name] = service_water_fraction_sensible_sch
312
- end
313
- water_use_equip_def.setSensibleFractionSchedule(service_water_fraction_sensible_sch)
314
- name = "#{service_water_fraction_latent} Fraction"
315
- if water_use_def_schedules.key?(name)
316
- service_water_fraction_latent_sch = water_use_def_schedules[name]
317
- else
318
- service_water_fraction_latent_sch = model_add_constant_schedule_ruleset(model, service_water_fraction_sensible, name)
319
- water_use_def_schedules[name] = service_water_fraction_latent_sch
320
- end
321
- water_use_equip_def.setLatentFractionSchedule(service_water_fraction_latent_sch)
322
-
323
- # add water use equipment, connection, and loop for each unit
324
- num_units.times do |i|
325
- # add water use equipment
326
- water_use_equip = OpenStudio::Model::WaterUseEquipment.new(water_use_equip_def)
327
- water_use_equip.setFlowRateFractionSchedule(flow_rate_fraction_schedule)
328
- water_use_equip.setName("#{space_type.name} SWH #{i + 1}")
329
-
330
- # add water use connection
331
- water_use_connection = OpenStudio::Model::WaterUseConnections.new(model)
332
- water_use_connection.addWaterUseEquipment(water_use_equip)
333
- water_use_connection.setName("#{space_type.name} WUC #{i + 1}")
334
-
335
- # gather inputs for add_swh_loop
336
- # default fuel, capacity, and volume from Table A.1. Water Heating Equipment Enhancements to ASHRAE Standard 90.1 Prototype Building Models
337
- # temperature, pump head, motor efficiency, and parasitic load from Prototype Inputs
338
- system_name = "#{space_type.name} Service Water Loop #{i + 1}"
339
- water_heater_thermal_zone = nil
340
- service_water_temperature = service_water_temperature_si
341
- service_water_pump_head = 0.01
342
- service_water_pump_motor_efficiency = 1.0
343
- water_heater_fuel = if fuel.nil?
344
- 'Electric'
345
- else
346
- fuel
347
- end
348
- if stds_bldg_type == 'MidriseApartment'
349
- water_heater_capacity = OpenStudio.convert(15.0, 'kBtu/hr', 'W').get
350
- water_heater_volume = OpenStudio.convert(50.0, 'gal', 'm^3').get
351
- parasitic_fuel_consumption_rate = 0.0 # Prototype inputs has 87.75W but prototype IDF's use 0
352
- else # StripMall
353
- water_heater_capacity = OpenStudio.convert(12.0, 'kBtu/hr', 'W').get
354
- water_heater_volume = OpenStudio.convert(40.0, 'gal', 'm^3').get
355
- parasitic_fuel_consumption_rate = 173.0
356
- end
357
-
358
- # make loop for each unit and add on water use equipment
359
- unit_hot_water_loop = model_add_swh_loop(model,
360
- system_name,
361
- water_heater_thermal_zone,
362
- service_water_temperature,
363
- service_water_pump_head,
364
- service_water_pump_motor_efficiency,
365
- water_heater_capacity,
366
- water_heater_volume,
367
- water_heater_fuel,
368
- parasitic_fuel_consumption_rate,
369
- stds_bldg_type)
370
-
371
- # Connect the water use connection to the SWH loop
372
- unit_hot_water_loop.addDemandBranchForComponent(water_use_connection)
373
-
374
- # apply efficiency to hot water heater
375
- unit_hot_water_loop.supplyComponents.sort.each do |component|
376
- next if component.to_WaterHeaterMixed.empty?
377
- component = component.to_WaterHeaterMixed.get
378
- water_heater_mixed_apply_efficiency(component)
379
- end
380
-
381
- # add to list of systems
382
- swh_systems << unit_hot_water_loop
383
- end
384
-
385
- elsif stds_space_type.include?('Kitchen') || stds_space_type.include?('Laundry')
386
- gal_hr_peak_flow_rate = gal_hr_per_area * floor_area_ip
387
- OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', "Adding dedicated water heating for #{space_type.name} space type with max flow rate of #{gal_hr_peak_flow_rate.round} gal/hr.")
388
-
389
- # add water use equipment definition
390
- water_use_equip_def = OpenStudio::Model::WaterUseEquipmentDefinition.new(model)
391
- water_use_equip_def.setName("#{space_type.name} SWH def")
392
- peak_flow_rate_si = OpenStudio.convert(gal_hr_peak_flow_rate, 'gal/hr', 'm^3/s').get
393
- water_use_equip_def.setPeakFlowRate(peak_flow_rate_si)
394
- target_temp = service_water_temperature_si # in spreadsheet in si, no conversion needed unless that changes
395
- name = "#{target_temp} C"
396
- if water_use_def_schedules.key?(name)
397
- target_temperature_sch = water_use_def_schedules[name]
398
- else
399
- target_temperature_sch = model_add_constant_schedule_ruleset(model, target_temp, name)
400
- water_use_def_schedules[name] = target_temperature_sch
401
- end
402
- water_use_equip_def.setTargetTemperatureSchedule(target_temperature_sch)
403
- name = "#{service_water_fraction_sensible} Fraction"
404
- if water_use_def_schedules.key?(name)
405
- service_water_fraction_sensible_sch = water_use_def_schedules[name]
406
- else
407
- service_water_fraction_sensible_sch = model_add_constant_schedule_ruleset(model, service_water_fraction_sensible, name)
408
- water_use_def_schedules[name] = service_water_fraction_sensible_sch
409
- end
410
- water_use_equip_def.setSensibleFractionSchedule(service_water_fraction_sensible_sch)
411
- name = "#{service_water_fraction_latent} Fraction"
412
- if water_use_def_schedules.key?(name)
413
- service_water_fraction_latent_sch = water_use_def_schedules[name]
414
- else
415
- service_water_fraction_latent_sch = model_add_constant_schedule_ruleset(model, service_water_fraction_sensible, name)
416
- water_use_def_schedules[name] = service_water_fraction_latent_sch
417
- end
418
- water_use_equip_def.setLatentFractionSchedule(service_water_fraction_latent_sch)
419
-
420
- # add water use equipment
421
- water_use_equip = OpenStudio::Model::WaterUseEquipment.new(water_use_equip_def)
422
- water_use_equip.setFlowRateFractionSchedule(flow_rate_fraction_schedule)
423
- water_use_equip.setName("#{space_type.name} SWH")
424
-
425
- # add water use connection
426
- water_use_connection = OpenStudio::Model::WaterUseConnections.new(model)
427
- water_use_connection.addWaterUseEquipment(water_use_equip)
428
- water_use_connection.setName("#{space_type.name} WUC")
429
-
430
- # gather inputs for add_swh_loop
431
- system_name = "#{space_type.name} Service Water Loop"
432
- water_heater_thermal_zone = nil
433
- water_heater_temp_si = 60.0 # C
434
- service_water_pump_head = 0.01
435
- service_water_pump_motor_efficiency = 1.0
436
- water_heater_fuel = if fuel.nil?
437
- 'Gas'
438
- else
439
- fuel
440
- end
441
-
442
- # find_water_heater_capacity_volume_and_parasitic
443
- water_use_equipment_array = [water_use_equip]
444
- water_heater_sizing = model_find_water_heater_capacity_volume_and_parasitic(model, water_use_equipment_array)
445
- water_heater_capacity = water_heater_sizing[:water_heater_capacity]
446
- water_heater_volume = water_heater_sizing[:water_heater_volume]
447
- parasitic_fuel_consumption_rate = water_heater_sizing[:parasitic_fuel_consumption_rate]
448
-
449
- # make loop for each unit and add on water use equipment
450
- dedicated_hot_water_loop = model_add_swh_loop(model,
451
- system_name,
452
- water_heater_thermal_zone,
453
- water_heater_temp_si,
454
- service_water_pump_head,
455
- service_water_pump_motor_efficiency,
456
- water_heater_capacity,
457
- water_heater_volume,
458
- water_heater_fuel,
459
- parasitic_fuel_consumption_rate,
460
- stds_bldg_type)
461
-
462
- # Connect the water use connection to the SWH loop
463
- dedicated_hot_water_loop.addDemandBranchForComponent(water_use_connection)
464
-
465
- # find water heater
466
- dedicated_hot_water_loop.supplyComponents.sort.each do |component|
467
- next if component.to_WaterHeaterMixed.empty?
468
- water_heater = component.to_WaterHeaterMixed.get
469
-
470
- # apply efficiency to hot water heater
471
- water_heater_mixed_apply_efficiency(water_heater)
472
- end
473
-
474
- # add to list of systems
475
- swh_systems << dedicated_hot_water_loop
476
-
477
- # add booster to all kitchens except for QuickServiceRestaurant (QuickServiceRestaurant assumed to use chemicals instead of hotter water)
478
- # boosters are all 6 gal elec but heating capacity varies from 3 to 19 (kBtu/hr) for prototype buildings
479
- if stds_space_type.include?('Kitchen') && stds_bldg_type != 'QuickServiceRestaurant'
480
-
481
- # find_water_heater_capacity_volume_and_parasitic
482
- water_use_equipment_array = [water_use_equip]
483
- inlet_temp_ip = OpenStudio.convert(service_water_temperature_si, 'C', 'F').get # pre-booster temp
484
- outlet_temp_ip = inlet_temp_ip + 40.0
485
- peak_flow_fraction = 0.6 # assume 60% of peak for dish washing
486
- water_heater_sizing = model_find_water_heater_capacity_volume_and_parasitic(model, water_use_equipment_array, pipe_hash = {}, 1.0, 1.0, inlet_temp_ip, outlet_temp_ip, peak_flow_fraction)
487
- water_heater_capacity = water_heater_sizing[:water_heater_capacity]
488
-
489
- # gather additional inputs for add_swh_booster
490
- water_heater_volume = OpenStudio.convert(6, 'gal', 'm^3').get
491
- water_heater_fuel = 'Electric'
492
- booster_water_temperature = 82.22 # C
493
- parasitic_fuel_consumption_rate = 0.0
494
- booster_water_heater_thermal_zone = nil
495
-
496
- # add_swh_booster
497
- booster_service_water_loop = model_add_swh_booster(model,
498
- dedicated_hot_water_loop,
499
- water_heater_capacity,
500
- water_heater_volume,
501
- water_heater_fuel,
502
- booster_water_temperature,
503
- parasitic_fuel_consumption_rate,
504
- booster_water_heater_thermal_zone,
505
- stds_bldg_type)
506
-
507
- # find water heater
508
- booster_service_water_loop.supplyComponents.sort.each do |component|
509
- next if component.to_WaterHeaterMixed.empty?
510
- water_heater = component.to_WaterHeaterMixed.get
511
-
512
- # apply efficiency to hot water heater
513
- water_heater_mixed_apply_efficiency(water_heater)
514
- end
515
-
516
- # rename booster loop
517
- booster_service_water_loop.setName("#{space_type.name} Booster Service Water Loop")
518
- OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', "Adding Electric Booster water heater for #{space_type.name} on a loop named #{booster_service_water_loop.name}.")
519
-
520
- end
521
-
522
- else # store water use equip by building type in hash so can add general building type hot water loop
277
+ # Determine flow rate
278
+ case swh_system_type
279
+ when 'One Per Unit'
280
+ water_heater_fuel = 'Electricity' if water_heater_fuel.nil?
281
+ num_units = space_type_hash[space_type][:num_units].round # First try number of units
282
+ num_units = space_type_hash[space_type][:effective_num_spaces].round if num_units.zero? # Fall back on number of spaces
283
+ peak_flow_rate_gal_per_hr = num_units * peak_flow_rate_gal_per_hr
284
+ peak_flow_rate_m3_per_s = num_units * OpenStudio.convert(peak_flow_rate_gal_per_hr, 'gal/hr', 'm^3/s').get
285
+ use_name = "#{space_type.name} #{num_units} units"
286
+ else
287
+ # TODO: - add building type or sice specific logic or just assume Gas? (SmallOffice and Warehouse are only non unit prototypes with Electric heating)
288
+ water_heater_fuel = 'NaturalGas' if water_heater_fuel.nil?
289
+ num_units = 1
290
+ peak_flow_rate_gal_per_hr = peak_flow_rate_gal_per_hr_per_ft2 * floor_area_ft2
291
+ peak_flow_rate_m3_per_s = OpenStudio.convert(peak_flow_rate_gal_per_hr, 'gal/hr', 'm^3/s').get
292
+ use_name = "#{space_type.name}"
293
+ end
523
294
 
524
- gal_hr_peak_flow_rate = gal_hr_per_area * floor_area_ip
525
- OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', "Adding water heating for #{space_type.name} space type with max flow rate of #{gal_hr_peak_flow_rate.round} gal/hr on a shared loop.")
295
+ # Split flow rate between main and booster uses if specified
296
+ booster_water_use_equip = nil
297
+ if booster_water_heater_fraction > 0.0
298
+ booster_peak_flow_rate_m3_per_s = peak_flow_rate_m3_per_s * booster_water_heater_fraction
299
+ peak_flow_rate_m3_per_s -= booster_peak_flow_rate_m3_per_s
300
+
301
+ # Add booster water heater equipment and connections
302
+ booster_water_use_equip = model_add_swh_end_uses(model,
303
+ "Booster #{use_name}",
304
+ loop=nil,
305
+ booster_peak_flow_rate_m3_per_s,
306
+ flow_rate_fraction_schedule.name.get,
307
+ booster_water_temperature_c,
308
+ space_name=nil,
309
+ frac_sensible: service_water_fraction_sensible,
310
+ frac_latent: service_water_fraction_latent)
311
+ end
526
312
 
527
- # add water use equipment definition
528
- water_use_equip_def = OpenStudio::Model::WaterUseEquipmentDefinition.new(model)
529
- water_use_equip_def.setName("#{space_type.name} SWH def")
530
- peak_flow_rate_si = OpenStudio.convert(gal_hr_peak_flow_rate, 'gal/hr', 'm^3/s').get
531
- water_use_equip_def.setPeakFlowRate(peak_flow_rate_si)
532
- target_temp = service_water_temperature_si # in spreadsheet in si, no conversion needed unless that changes
533
- name = "#{target_temp} C"
534
- if water_use_def_schedules.key?(name)
535
- target_temperature_sch = water_use_def_schedules[name]
536
- else
537
- target_temperature_sch = model_add_constant_schedule_ruleset(model, target_temp, name)
538
- water_use_def_schedules[name] = target_temperature_sch
539
- end
540
- water_use_equip_def.setTargetTemperatureSchedule(target_temperature_sch)
541
- name = "#{service_water_fraction_sensible} Fraction"
542
- if water_use_def_schedules.key?(name)
543
- service_water_fraction_sensible_sch = water_use_def_schedules[name]
544
- else
545
- service_water_fraction_sensible_sch = model_add_constant_schedule_ruleset(model, service_water_fraction_sensible, name)
546
- water_use_def_schedules[name] = service_water_fraction_sensible_sch
547
- end
548
- water_use_equip_def.setSensibleFractionSchedule(service_water_fraction_sensible_sch)
549
- name = "#{service_water_fraction_latent} Fraction"
550
- if water_use_def_schedules.key?(name)
551
- service_water_fraction_latent_sch = water_use_def_schedules[name]
552
- else
553
- service_water_fraction_latent_sch = model_add_constant_schedule_ruleset(model, service_water_fraction_sensible, name)
554
- water_use_def_schedules[name] = service_water_fraction_latent_sch
555
- end
556
- water_use_equip_def.setLatentFractionSchedule(service_water_fraction_latent_sch)
313
+ # Add water use equipment and connections
314
+ water_use_equip = model_add_swh_end_uses(model,
315
+ use_name,
316
+ swh_loop=nil,
317
+ peak_flow_rate_m3_per_s,
318
+ flow_rate_fraction_schedule.name.get,
319
+ service_water_temperature_c,
320
+ space_name=nil,
321
+ frac_sensible: service_water_fraction_sensible,
322
+ frac_latent: service_water_fraction_latent)
323
+
324
+ # Water heater sizing
325
+ case swh_system_type
326
+ when 'One Per Unit'
327
+ water_heater_capacity_w = num_units * OpenStudio.convert(20.0, 'kBtu/hr', 'W').get
328
+ water_heater_volume_m3 = num_units * OpenStudio.convert(50.0, 'gal', 'm^3').get
329
+ num_water_heaters = num_units
330
+ else
331
+ water_use_equips = [water_use_equip]
332
+ water_use_equips << booster_water_use_equip unless booster_water_use_equip.nil? # Include booster in sizing since flows will be preheated by main water heater
333
+ water_heater_sizing = model_find_water_heater_capacity_volume_and_parasitic(model, water_use_equips)
334
+ water_heater_capacity_w = water_heater_sizing[:water_heater_capacity]
335
+ water_heater_volume_m3 = water_heater_sizing[:water_heater_volume]
336
+ num_water_heaters = 1
337
+ end
557
338
 
558
- # add water use equipment
559
- water_use_equip = OpenStudio::Model::WaterUseEquipment.new(water_use_equip_def)
560
- water_use_equip.setFlowRateFractionSchedule(flow_rate_fraction_schedule)
561
- water_use_equip.setName("#{space_type.name} SWH")
339
+ # Add either a dedicated SWH loop or save to add to shared SWH loop
340
+ case swh_system_type
341
+ when 'Shared'
562
342
 
343
+ # Store water use equip by building type to add to shared building hot water loop
563
344
  if water_use_equipment_hash.key?(stds_bldg_type)
564
345
  water_use_equipment_hash[stds_bldg_type] << water_use_equip
565
346
  else
566
347
  water_use_equipment_hash[stds_bldg_type] = [water_use_equip]
567
348
  end
568
349
 
350
+ when 'One Per Unit', 'Dedicated'
351
+ pipe_insul_in = 0.0 if pipe_insul_in.nil?
352
+
353
+ # Add service water loop with water heater
354
+ swh_loop = model_add_swh_loop(model,
355
+ system_name="#{space_type.name} Service Water Loop",
356
+ water_heater_thermal_zone=nil,
357
+ service_water_temperature_c,
358
+ service_water_pump_head=0.01,
359
+ service_water_pump_motor_efficiency=1.0,
360
+ water_heater_capacity_w,
361
+ water_heater_volume_m3,
362
+ water_heater_fuel,
363
+ parasitic_fuel_consumption_rate_w=0,
364
+ add_pipe_losses=true,
365
+ floor_area_served=OpenStudio.convert(950, 'ft^2', 'm^2').get,
366
+ number_of_stories=1,
367
+ pipe_insulation_thickness=OpenStudio.convert(pipe_insul_in, 'in', 'm').get,
368
+ num_water_heaters)
369
+ OpenStudio.logFree(OpenStudio::Warn, 'openstudio.Model.Model', "In model_add_typical, num_water_heaters = #{num_water_heaters}")
370
+ # Add loop to list
371
+ swh_systems << swh_loop
372
+
373
+ # Attach water use equipment to the loop
374
+ swh_connection = water_use_equip.waterUseConnections
375
+ swh_loop.addDemandBranchForComponent(swh_connection.get) if swh_connection.is_initialized
376
+
377
+ # If a booster fraction is specified, some percentage of the water
378
+ # is assumed to be heated beyond the normal temperature by a separate
379
+ # booster water heater. This booster water heater is fed by the
380
+ # main water heater, so the booster is responsible for a smaller delta-T.
381
+ if booster_water_heater_fraction > 0
382
+ # find_water_heater_capacity_volume_and_parasitic
383
+ booster_water_heater_sizing = model_find_water_heater_capacity_volume_and_parasitic(model,
384
+ [booster_water_use_equip],
385
+ htg_eff: 1.0,
386
+ inlet_temp_f: service_water_temperature_f,
387
+ target_temp_f: booster_water_temperature_f)
388
+
389
+ # Add service water booster loop with water heater
390
+ # Note that booster water heaters are always assumed to be electric resistance
391
+ swh_booster_loop = model_add_swh_booster(model,
392
+ swh_loop,
393
+ booster_water_heater_sizing[:water_heater_capacity],
394
+ water_heater_volume_m3=OpenStudio.convert(6, 'gal', 'm^3').get,
395
+ water_heater_fuel='Electricity',
396
+ booster_water_temperature_c,
397
+ parasitic_fuel_consumption_rate_w=0.0,
398
+ booster_water_heater_thermal_zone=nil)
399
+
400
+ # Rename the service water booster loop
401
+ swh_booster_loop.setName("#{space_type.name} Service Water Booster Loop")
402
+
403
+ # Attach booster water use equipment to the booster loop
404
+ booster_swh_connection = booster_water_use_equip.waterUseConnections
405
+ swh_booster_loop.addDemandBranchForComponent(booster_swh_connection.get) if booster_swh_connection.is_initialized
406
+ end
407
+
408
+ else
409
+ OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', "'#{swh_system_type}' is not a valid Service Water Heating System Type, cannot add SWH to #{space_type.name}. Valid choices are One Per Unit, Dedicated, and Shared.")
569
410
  end
570
411
  end
571
412
 
572
413
  # get building floor area and effective number of stories
573
- bldg_floor_area = model.getBuilding.floorArea
414
+ bldg_floor_area_m2 = model.getBuilding.floorArea
574
415
  bldg_effective_num_stories_hash = model_effective_num_stories(model)
575
416
  bldg_effective_num_stories = bldg_effective_num_stories_hash[:below_grade] + bldg_effective_num_stories_hash[:above_grade]
576
417
 
577
418
  # add non-dedicated system(s) here. Separate systems for water use equipment from different building types
578
419
  water_use_equipment_hash.sort.each do |stds_bldg_type, water_use_equipment_array|
579
- # gather inputs for add_swh_loop
580
- system_name = "#{stds_bldg_type} Shared Service Water Loop"
581
- water_heater_thermal_zone = nil
582
- water_heater_temp_si = 60.0
420
+ # TODO: find the water use equipment with the highest temperature
421
+ water_heater_temp_f = 140.0
422
+ water_heater_temp_c = OpenStudio.convert(water_heater_temp_f, 'F', 'C').get
583
423
 
584
424
  # find pump values
585
425
  # Table A.2 in PrototypeModelEnhancements_2014_0.pdf shows 10ft on everything except SecondarySchool which has 11.4ft
586
- # todo - if SmallOffice then shouldn't have circulating pump
587
- if ['Office', 'PrimarySchool', 'Outpatient', 'Hospital', 'SmallHotel', 'LargeHotel', 'FullServiceRestaurant', 'HighriseApartment'].include?(stds_bldg_type)
588
- service_water_pump_head = OpenStudio.convert(10.0, 'ftH_{2}O', 'Pa').get
589
- service_water_pump_motor_efficiency = 0.3
590
- if circulating.nil? then
591
- irculating = true
592
- end
593
- if pipe_insul_in.nil? then
594
- pipe_insul_in = 0.5
595
- end
596
- elsif ['SecondarySchool'].include?(stds_bldg_type)
597
- service_water_pump_head = OpenStudio.convert(11.4, 'ftH_{2}O', 'Pa').get
426
+ # TODO: Remove hard-coded building-type-based lookups for circulating vs. non-circulating SWH systems
427
+ circulating_bldg_types = [
428
+ # DOE building types
429
+ 'Office',
430
+ 'PrimarySchool',
431
+ 'Outpatient',
432
+ 'Hospital',
433
+ 'SmallHotel',
434
+ 'LargeHotel',
435
+ 'FullServiceRestaurant',
436
+ 'HighriseApartment',
437
+ # DEER building types
438
+ 'Asm', # 'Assembly'
439
+ 'ECC', # 'Education - Community College'
440
+ 'EPr', # 'Education - Primary School'
441
+ 'ERC', # 'Education - Relocatable Classroom'
442
+ 'ESe', # 'Education - Secondary School'
443
+ 'EUn', # 'Education - University'
444
+ 'Gro', # 'Grocery'
445
+ 'Hsp', # 'Health/Medical - Hospital'
446
+ 'Htl', # 'Lodging - Hotel'
447
+ 'MBT', # 'Manufacturing Biotech'
448
+ 'MFm', # 'Residential Multi-family'
449
+ 'Mtl', # 'Lodging - Motel'
450
+ 'Nrs', # 'Health/Medical - Nursing Home'
451
+ 'OfL', # 'Office - Large'
452
+ # 'RFF', # 'Restaurant - Fast-Food'
453
+ 'RSD' # 'Restaurant - Sit-Down'
454
+ ]
455
+ if circulating_bldg_types.include?(stds_bldg_type)
456
+ service_water_pump_head_pa = OpenStudio.convert(10.0, 'ftH_{2}O', 'Pa').get
598
457
  service_water_pump_motor_efficiency = 0.3
599
- if circulating.nil? then
600
- irculating = true
601
- end
602
- if pipe_insul_in.nil? then
603
- pipe_insul_in = 0.5
604
- end
458
+ circulating = true if circulating.nil?
459
+ pipe_insul_in = 0.5 if pipe_insul_in.nil?
605
460
  else # values for non-circulating pump
606
- service_water_pump_head = 0.01
461
+ service_water_pump_head_pa = 0.01
607
462
  service_water_pump_motor_efficiency = 1.0
608
- if circulating.nil? then
609
- irculating = false
610
- end
611
- if pipe_insul_in.nil? then
612
- pipe_insul_in = 0.0
613
- end
614
- end
615
-
616
- # TODO: - add building type or sice specific logic or just assume Gas? (SmallOffice and Warehouse are only non unit prototypes with Electric heating)
617
- water_heater_fuel = if fuel.nil?
618
- 'Gas'
619
- else
620
- fuel
621
- end
622
-
623
- bldg_type_floor_area = 0.0
624
- space_type_hash.sort.each do |space_type, hash|
625
- next if hash[:stds_bldg_type] != stds_bldg_type
626
- bldg_type_floor_area += hash[:floor_area]
627
- end
628
-
629
- # inputs for find_water_heater_capacity_volume_and_parasitic
630
- pipe_hash = {}
631
- pipe_hash[:floor_area] = bldg_type_floor_area
632
- pipe_hash[:effective_num_stories] = bldg_effective_num_stories * (bldg_type_floor_area / bldg_floor_area)
633
- pipe_hash[:circulating] = circulating
634
- pipe_hash[:insulation_thickness] = pipe_insul_in
635
-
636
- # find_water_heater_capacity_volume_and_parasitic
637
- water_heater_sizing = model_find_water_heater_capacity_volume_and_parasitic(model, water_use_equipment_array, pipe_hash)
638
- water_heater_capacity = water_heater_sizing[:water_heater_capacity]
639
- water_heater_volume = water_heater_sizing[:water_heater_volume]
640
- parasitic_fuel_consumption_rate = water_heater_sizing[:parasitic_fuel_consumption_rate]
641
- if parasitic_fuel_consumption_rate > 0
642
- OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', "Adding parasitic loss for #{stds_bldg_type} loop of #{parasitic_fuel_consumption_rate.round} Btu/hr.")
463
+ circulating = false if circulating.nil?
464
+ pipe_insul_in = 0.0 if pipe_insul_in.nil?
643
465
  end
644
466
 
645
- # make loop for each unit and add on water use equipment
646
- shared_hot_water_loop = model_add_swh_loop(model,
647
- system_name,
648
- water_heater_thermal_zone,
649
- water_heater_temp_si,
650
- service_water_pump_head,
651
- service_water_pump_motor_efficiency,
652
- water_heater_capacity,
653
- water_heater_volume,
654
- water_heater_fuel,
655
- parasitic_fuel_consumption_rate,
656
- stds_bldg_type)
657
-
658
- # find water heater
659
- shared_hot_water_loop.supplyComponents.sort.each do |component|
660
- next if component.to_WaterHeaterMixed.empty?
661
- water_heater = component.to_WaterHeaterMixed.get
662
-
663
- # apply efficiency to hot water heater
664
- water_heater_mixed_apply_efficiency(water_heater)
467
+ bldg_type_floor_area_m2 = 0.0
468
+ space_type_hash.sort.each do |space_type, space_type_props|
469
+ bldg_type_floor_area_m2 += space_type_props[:floor_area] if space_type_props[:stds_bldg_type] == stds_bldg_type
665
470
  end
666
471
 
667
- # loop through water use equipment
472
+ # Calculate the number of stories covered by this building type
473
+ num_stories = bldg_effective_num_stories * (bldg_type_floor_area_m2 / bldg_floor_area_m2)
474
+
475
+ # Water heater sizing
476
+ water_heater_sizing = model_find_water_heater_capacity_volume_and_parasitic(model, water_use_equipment_array)
477
+ water_heater_capacity_w = water_heater_sizing[:water_heater_capacity]
478
+ water_heater_volume_m3 = water_heater_sizing[:water_heater_volume]
479
+
480
+ # Add a shared service water heating loop with water heater
481
+ shared_swh_loop = model_add_swh_loop(model,
482
+ "#{stds_bldg_type} Shared Service Water Loop",
483
+ water_heater_thermal_zone=nil,
484
+ water_heater_temp_c,
485
+ service_water_pump_head_pa,
486
+ service_water_pump_motor_efficiency,
487
+ water_heater_capacity_w,
488
+ water_heater_volume_m3,
489
+ water_heater_fuel,
490
+ parasitic_fuel_consumption_rate_w=0,
491
+ add_pipe_losses=true,
492
+ floor_area_served=bldg_type_floor_area_m2,
493
+ number_of_stories=num_stories,
494
+ pipe_insulation_thickness=OpenStudio.convert(pipe_insul_in, 'in', 'm').get)
495
+
496
+ # Attach all water use equipment to the shared loop
668
497
  water_use_equipment_array.sort.each do |water_use_equip|
669
- # add water use connection
670
- water_use_connection = OpenStudio::Model::WaterUseConnections.new(model)
671
- water_use_connection.addWaterUseEquipment(water_use_equip)
672
- water_use_connection.setName(water_use_equip.name.get.gsub('SWH', 'WUC'))
673
-
674
- # Connect the water use connection to the SWH loop
675
- shared_hot_water_loop.addDemandBranchForComponent(water_use_connection)
498
+ swh_connection = water_use_equip.waterUseConnections
499
+ shared_swh_loop.addDemandBranchForComponent(swh_connection.get) if swh_connection.is_initialized
676
500
  end
677
501
 
678
502
  # add to list of systems
679
- swh_systems << shared_hot_water_loop
503
+ swh_systems << shared_swh_loop
680
504
 
681
505
  OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', "Adding shared water heating loop for #{stds_bldg_type}.")
682
506
  end
@@ -684,21 +508,28 @@ class Standard
684
508
  return swh_systems
685
509
  end
686
510
 
687
- # set capacity, volume, and parasitic
511
+ # Use rules from DOE Prototype Building documentation to determine water heater capacity,
512
+ # volume, pipe dump losses, and pipe thermal losses.
688
513
  #
689
514
  # @param water_use_equipment_array [Array] array of water use equipment objects that will be using this water heater
690
- # @param storage_to_cap_ratio [Double] gal of storage to kBtu/hr of capacitiy
691
- # @param htg_eff [Double] fraction
692
- # @param inlet_temp_ip [Double] cold water temperature F
693
- # @param target_temp_ip [Double] F
515
+ # @param storage_to_cap_ratio_gal_to_kbtu_per_hr [Double] storage volume gal to kBtu/hr of capacity
516
+ # @param htg_eff [Double] water heater thermal efficiency, fraction
517
+ # @param inlet_temp_f [Double] inlet cold water temperature, degrees Fahrenheit
518
+ # @param target_temp_f [Double] target supply water temperatre from the tank, degrees Fahrenheit
694
519
  # @return [Hash] hash with values needed to size water heater made with downstream method
695
- def model_find_water_heater_capacity_volume_and_parasitic(model, water_use_equipment_array, pipe_hash = {}, storage_to_cap_ratio = 1.0, htg_eff = 0.8, inlet_temp_ip = 40.0, target_temp_ip = 140.0, peak_flow_fraction = 1.0)
520
+ def model_find_water_heater_capacity_volume_and_parasitic(model,
521
+ water_use_equipment_array,
522
+ storage_to_cap_ratio_gal_to_kbtu_per_hr: 1.0,
523
+ htg_eff: 0.8,
524
+ inlet_temp_f: 40.0,
525
+ target_temp_f: 140.0,
526
+ peak_flow_fraction: 1.0)
696
527
  # A.1.4 Total Storage Volume and Water Heater Capacity of PrototypeModelEnhancements_2014_0.pdf shows 1 gallon of storage to 1 kBtu/h of capacity
697
528
 
698
529
  water_heater_sizing = {}
699
530
 
700
- # get water use equipment
701
- max_flow_rate_array = [] # gallons per hour
531
+ # Get the maximum flow rates for all pieces of water use equipment
532
+ adjusted_max_flow_rates_gal_per_hr = [] # gallons per hour
702
533
  water_use_equipment_array.sort.each do |water_use_equip|
703
534
  water_use_equip_sch = water_use_equip.flowRateFractionSchedule
704
535
  next if water_use_equip_sch.empty?
@@ -712,78 +543,39 @@ class Standard
712
543
  elsif water_use_equip_sch.to_ScheduleCompact.is_initialized
713
544
  water_use_equip_sch = water_use_equip_sch.to_ScheduleCompact.get
714
545
  max_sch_value = schedule_compact_annual_min_max_value(water_use_equip_sch)['max']
546
+ else
547
+ OpenStudio.logFree(OpenStudio::Warn, 'openstudio.model.Model', "The peak flow rate fraction for #{water_use_equip_sch.name} could not be determined, assuming 1 for water heater sizing purposes.")
548
+ max_sch_value = 1.0
715
549
  end
716
550
 
717
- # get water_use_equip_def to get max flow rate
718
- water_use_equip_def = water_use_equip.waterUseEquipmentDefinition
719
- peak_flow_rate = water_use_equip_def.peakFlowRate
720
-
721
- # calculate adjusted flow rate
722
- adjusted_peak_flow_rate_si = max_sch_value * peak_flow_rate
723
- adjusted_peak_flow_rate_ip = OpenStudio.convert(adjusted_peak_flow_rate_si, 'm^3/s', 'gal/min').get
724
- max_flow_rate_array << adjusted_peak_flow_rate_ip * 60.0 # min per hour
725
- end
551
+ # Get peak flow rate from water use equipment definition
552
+ peak_flow_rate_m3_per_s = water_use_equip.waterUseEquipmentDefinition.peakFlowRate
726
553
 
727
- # warn if max_flow_rate_array size doesn't match equipment size (one or more didn't have ruleset schedule)
728
- if max_flow_rate_array.size != water_use_equipment_array.size
729
- OpenStudio.logFree(OpenStudio::Warn, 'openstudio.model.Model', 'One or more Water Use Equipment Fraction Flow Rate Scheules were not Schedule Rulestes and were excluding from Water Heating Sizing.')
554
+ # Calculate adjusted flow rate based on the peak fraction found in the flow rate fraction schedule
555
+ adjusted_peak_flow_rate_m3_per_s = max_sch_value * peak_flow_rate_m3_per_s
556
+ adjusted_max_flow_rates_gal_per_hr << OpenStudio.convert(adjusted_peak_flow_rate_m3_per_s, 'm^3/s', 'gal/hr').get
730
557
  end
731
558
 
732
- # sum gpm values from water use equipment to use in formula
733
- adjusted_flow_rate_sum = max_flow_rate_array.inject(:+)
559
+ # Sum gph values from water use equipment to use in formula
560
+ total_adjusted_flow_rate_gal_per_hr = adjusted_max_flow_rates_gal_per_hr.inject(:+)
734
561
 
735
- # use formula to calculate volume and capacity based on analysis of combined water use equipment maximum flow rates and schedules
562
+ # Calculate capacity based on analysis of combined water use equipment maximum flow rates and schedules
736
563
  # Max gal/hr * 8.4 lb/gal * 1 Btu/lb F * (120F - 40F)/0.8 = Btu/hr
737
- water_heater_capacity_ip = peak_flow_fraction * adjusted_flow_rate_sum * 8.4 * 1.0 * (target_temp_ip - inlet_temp_ip) / htg_eff
738
- OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', "Capacity of #{water_heater_capacity_ip} Btu/hr = #{peak_flow_fraction} peak fraction * #{adjusted_flow_rate_sum.round} gal/hr * 8.4 lb/gal * 1.0 Btu/lb F * (#{target_temp_ip.round} - #{inlet_temp_ip.round} deltaF / #{htg_eff} htg eff).")
739
- water_heater_capacity_si = OpenStudio.convert(water_heater_capacity_ip, 'Btu/hr', 'W').get
740
- # Assume 1 gal of volume per 1 kBtu/hr of heating capacity
741
- water_heater_volume_ip = OpenStudio.convert(water_heater_capacity_ip, 'Btu/hr', 'kBtu/hr').get
564
+ water_heater_capacity_btu_per_hr = peak_flow_fraction * total_adjusted_flow_rate_gal_per_hr * 8.4 * 1.0 * (target_temp_f - inlet_temp_f) / htg_eff
565
+ OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', "Capacity of #{water_heater_capacity_btu_per_hr.round} Btu/hr = #{peak_flow_fraction} peak fraction * #{total_adjusted_flow_rate_gal_per_hr.round} gal/hr * 8.4 lb/gal * 1.0 Btu/lb F * (#{target_temp_f.round} - #{inlet_temp_f.round} deltaF / #{htg_eff} htg eff).")
566
+ water_heater_capacity_m3_per_s = OpenStudio.convert(water_heater_capacity_btu_per_hr, 'Btu/hr', 'W').get
567
+
568
+ # Calculate volume based on capacity
569
+ # Default assumption is 1 gal of volume per 1 kBtu/hr of heating capacity
570
+ water_heater_capacity_kbtu_per_hr = OpenStudio.convert(water_heater_capacity_btu_per_hr, 'Btu/hr', 'kBtu/hr').get
571
+ water_heater_volume_gal = water_heater_capacity_kbtu_per_hr * storage_to_cap_ratio_gal_to_kbtu_per_hr
742
572
  # increase tank size to 40 galons if calculated value is smaller
743
- if water_heater_volume_ip < 40.0 # gal
744
- water_heater_volume_ip = 40.0
745
- end
746
- water_heater_volume_si = OpenStudio.convert(water_heater_volume_ip, 'gal', 'm^3').get
747
-
748
- # populate return hash
749
- water_heater_sizing[:water_heater_capacity] = water_heater_capacity_si
750
- water_heater_sizing[:water_heater_volume] = water_heater_volume_si
751
-
752
- # get pipe length (formula from A.3.1 PrototypeModelEnhancements_2014_0.pdf)
753
- if !pipe_hash.empty?
754
-
755
- pipe_length = 2.0 * (Math.sqrt(pipe_hash[:floor_area] / pipe_hash[:effective_num_stories]) + (10.0 * (pipe_hash[:effective_num_stories] - 1.0)))
756
- pipe_length_ip = OpenStudio.convert(pipe_length, 'm', 'ft').get
757
-
758
- # calculate pipe dump (from A.4.1)
759
- pipe_dump = pipe_length_ip * 0.689 # Btu/hr
760
-
761
- pipe_loss_per_foot = if pipe_hash[:circulating]
762
- if pipe_hash[:insulation_thickness] >= 1.0
763
- 16.10
764
- elsif pipe_hash[:insulation_thickness] >= 0.5
765
- 17.5
766
- else
767
- 30.8
768
- end
769
- else
770
- if pipe_hash[:insulation_thickness] >= 1.0
771
- 11.27
772
- elsif pipe_hash[:insulation_thickness] >= 0.5
773
- 12.25
774
- else
775
- 28.07
776
- end
777
- end
778
-
779
- # calculate pipe loss (from Table A.3 in section A.4.2)
780
- pipe_loss = pipe_length * pipe_loss_per_foot # Btu/hr
781
-
782
- # calculate parasitic loss
783
- water_heater_sizing[:parasitic_fuel_consumption_rate] = pipe_dump + pipe_loss
784
- else
785
- water_heater_sizing[:parasitic_fuel_consumption_rate] = 0.0
786
- end
573
+ water_heater_volume_gal = 40.0 if water_heater_volume_gal < 40.0 # gal
574
+ water_heater_volume_m3 = OpenStudio.convert(water_heater_volume_gal, 'gal', 'm^3').get
575
+
576
+ # Populate return hash
577
+ water_heater_sizing[:water_heater_capacity] = water_heater_capacity_m3_per_s
578
+ water_heater_sizing[:water_heater_volume] = water_heater_volume_m3
787
579
 
788
580
  return water_heater_sizing
789
581
  end