openstudio-standards 0.6.3 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/data/standards/OpenStudio_Standards-ashrae_90_1.xlsx +0 -0
- data/data/standards/manage_OpenStudio_Standards.rb +2 -49
- data/data/standards/openstudio_standards_duplicates_log.csv +1 -7962
- data/data/standards/test_performance_expected_dd_results.csv +2005 -97
- data/lib/openstudio-standards/create_typical/space_type_ratios.rb +47 -57
- data/lib/openstudio-standards/geometry/create.rb +8 -2
- data/lib/openstudio-standards/geometry/create_bar.rb +6 -3
- data/lib/openstudio-standards/geometry/create_shape.rb +1 -1
- data/lib/openstudio-standards/geometry/group.rb +1 -1
- data/lib/openstudio-standards/geometry/information.rb +1 -1
- data/lib/openstudio-standards/geometry/modify.rb +53 -1
- data/lib/openstudio-standards/infiltration/nist_infiltration.rb +1 -1
- data/lib/openstudio-standards/prototypes/ashrae_90_1/ashrae_90_1_2016/ashrae_90_1_2016.Model.rb +11 -11
- data/lib/openstudio-standards/prototypes/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.Model.rb +11 -11
- data/lib/openstudio-standards/prototypes/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.hvac_systems.rb +2 -2
- data/lib/openstudio-standards/prototypes/common/buildings/Prototype.SuperTallBuilding.rb +44 -47
- data/lib/openstudio-standards/prototypes/common/buildings/Prototype.TallBuilding.rb +43 -48
- data/lib/openstudio-standards/prototypes/common/objects/Prototype.CentralAirSourceHeatPump.rb +1 -1
- data/lib/openstudio-standards/prototypes/common/objects/Prototype.hvac_systems.rb +44 -24
- data/lib/openstudio-standards/prototypes/common/objects/Prototype.refrigeration.rb +24 -24
- data/lib/openstudio-standards/schedules/information.rb +1 -1
- data/lib/openstudio-standards/schedules/parametric.rb +1 -1
- data/lib/openstudio-standards/service_water_heating/create_piping_losses.rb +152 -0
- data/lib/openstudio-standards/service_water_heating/create_water_heater.rb +544 -0
- data/lib/openstudio-standards/service_water_heating/create_water_heating_loop.rb +303 -0
- data/lib/openstudio-standards/service_water_heating/create_water_use.rb +95 -0
- data/lib/openstudio-standards/space/space.rb +1 -1
- data/lib/openstudio-standards/standards/Standards.AirLoopHVAC.rb +65 -70
- data/lib/openstudio-standards/standards/Standards.CoilCoolingWaterToAirHeatPumpEquationFit.rb +12 -14
- data/lib/openstudio-standards/standards/Standards.CoilHeatingDXSingleSpeed.rb +16 -5
- data/lib/openstudio-standards/standards/Standards.Model.rb +2 -2
- data/lib/openstudio-standards/standards/Standards.PlanarSurface.rb +10 -2
- data/lib/openstudio-standards/{prototypes/common/objects/Prototype.Model.swh.rb → standards/Standards.ServiceWaterHeating.rb} +209 -139
- data/lib/openstudio-standards/standards/Standards.Surface.rb +1 -1
- data/lib/openstudio-standards/standards/Standards.ZoneHVACComponent.rb +4 -8
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/ashrae_90_1_2004.Model.rb +2 -2
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/data/ashrae_90_1_2004.construction_properties.json +22251 -12963
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/data/ashrae_90_1_2004.construction_sets.json +91 -91
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/data/ashrae_90_1_2007.construction_properties.json +8981 -5228
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/data/ashrae_90_1_2010.construction_properties.json +8935 -5182
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.construction_properties.json +7281 -5391
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.construction_sets.json +91 -91
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/data/ashrae_90_1_2016.construction_properties.json +9005 -15215
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/data/ashrae_90_1_2016.construction_sets.json +136 -136
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.AirLoopHVAC.rb +1 -1
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/data/ashrae_90_1_2019.construction_properties.json +8717 -17168
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/data/ashrae_90_1_2019.construction_sets.json +136 -136
- data/lib/openstudio-standards/standards/ashrae_90_1/data/ashrae_90_1.constructions.json +1941 -651
- data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_1980_2004/data/doe_ref_1980_2004.construction_properties.json +135 -135
- data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_pre_1980/data/doe_ref_pre_1980.construction_properties.json +135 -135
- data/lib/openstudio-standards/standards/ashrae_90_1/nrel_zne_ready_2017/data/nrel_zne_ready_2017.construction_properties.json +36 -36
- data/lib/openstudio-standards/standards/ashrae_90_1/ze_aedg_multifamily/data/ze_aedg_multifamily.construction_properties.json +36 -36
- data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.PlantLoop.rb +377 -99
- data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.SpaceType.rb +2 -2
- data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/ashrae_90_1_prm_2019.Model.rb +3 -3
- data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.construction_properties.json +6889 -4044
- data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.prm_constructions.json +108 -108
- data/lib/openstudio-standards/standards/cbes/cbes_pre_1978/data/cbes_pre_1978.construction_properties.json +16 -16
- data/lib/openstudio-standards/standards/cbes/cbes_t24_1978/data/cbes_t24_1978.construction_properties.json +16 -16
- data/lib/openstudio-standards/standards/cbes/cbes_t24_1992/data/cbes_t24_1992.construction_properties.json +16 -16
- data/lib/openstudio-standards/standards/cbes/cbes_t24_2001/data/cbes_t24_2001.construction_properties.json +16 -16
- data/lib/openstudio-standards/standards/cbes/cbes_t24_2005/data/cbes_t24_2005.construction_properties.json +16 -16
- data/lib/openstudio-standards/standards/cbes/cbes_t24_2008/data/cbes_t24_2008.construction_properties.json +16 -16
- data/lib/openstudio-standards/standards/cbes/data/cbes.constructions.json +142 -142
- data/lib/openstudio-standards/standards/deer/data/deer.constructions.json +5 -1551
- data/lib/openstudio-standards/standards/deer/data/deer.materials.json +40 -0
- data/lib/openstudio-standards/standards/deer/deer_1985/data/deer_1985.motors.json +88 -8
- data/lib/openstudio-standards/standards/deer/deer_1996/data/deer_1996.motors.json +88 -8
- data/lib/openstudio-standards/standards/deer/deer_2003/data/deer_2003.motors.json +88 -8
- data/lib/openstudio-standards/standards/deer/deer_2007/data/deer_2007.motors.json +88 -8
- data/lib/openstudio-standards/standards/deer/deer_2011/data/deer_2011.motors.json +88 -8
- data/lib/openstudio-standards/standards/deer/deer_2014/data/deer_2014.motors.json +88 -8
- data/lib/openstudio-standards/standards/deer/deer_2015/data/deer_2015.motors.json +88 -8
- data/lib/openstudio-standards/standards/deer/deer_2017/data/deer_2017.motors.json +88 -8
- data/lib/openstudio-standards/standards/deer/deer_2020/data/deer_2020.motors.json +88 -8
- data/lib/openstudio-standards/standards/deer/deer_2025/data/deer_2025.motors.json +88 -8
- data/lib/openstudio-standards/standards/deer/deer_2030/data/deer_2030.motors.json +88 -8
- data/lib/openstudio-standards/standards/deer/deer_2035/data/deer_2035.motors.json +88 -8
- data/lib/openstudio-standards/standards/deer/deer_2040/data/deer_2040.motors.json +88 -8
- data/lib/openstudio-standards/standards/deer/deer_2045/data/deer_2045.motors.json +88 -8
- data/lib/openstudio-standards/standards/deer/deer_2050/data/deer_2050.motors.json +88 -8
- data/lib/openstudio-standards/standards/deer/deer_2055/data/deer_2055.motors.json +88 -8
- data/lib/openstudio-standards/standards/deer/deer_2060/data/deer_2060.motors.json +88 -8
- data/lib/openstudio-standards/standards/deer/deer_2065/data/deer_2065.motors.json +88 -8
- data/lib/openstudio-standards/standards/deer/deer_2070/data/deer_2070.motors.json +88 -8
- data/lib/openstudio-standards/standards/deer/deer_2075/data/deer_2075.motors.json +88 -8
- data/lib/openstudio-standards/standards/deer/deer_pre_1975/data/deer_pre_1975.motors.json +88 -8
- data/lib/openstudio-standards/standards/necb/BTAPPRE1980/btap_pre1980.rb +17 -0
- data/lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_systems.rb +2 -1
- data/lib/openstudio-standards/standards/necb/ECMS/ecms.rb +4 -4
- data/lib/openstudio-standards/standards/necb/ECMS/hvac_systems.rb +61 -88
- data/lib/openstudio-standards/standards/necb/NECB2011/autozone.rb +3 -2
- data/lib/openstudio-standards/standards/necb/NECB2011/data/boiler_fuel_type_sets.json +54 -0
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/LEEPMidriseApartment.osm +1 -1
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/LEEPMultiTower.osm +1 -1
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/LEEPPointTower.osm +1 -1
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/LEEPTownHouse.osm +1 -1
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/NorthernEducation.osm +4 -4
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/NorthernHealthCare.osm +4 -4
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_systems.rb +32 -24
- data/lib/openstudio-standards/standards/necb/NECB2011/necb_2011.rb +89 -15
- data/lib/openstudio-standards/standards/necb/NECB2011/qaqc/necb_qaqc.rb +5 -1
- data/lib/openstudio-standards/standards/necb/NECB2011/service_water_heating.rb +22 -65
- data/lib/openstudio-standards/standards/necb/NECB2011/system_fuels.rb +19 -0
- data/lib/openstudio-standards/standards/necb/common/btap_data.rb +56 -2
- data/lib/openstudio-standards/standards/necb/common/btap_datapoint.rb +3 -1
- data/lib/openstudio-standards/standards/necb/common/construction_defaults.osm +2 -2
- data/lib/openstudio-standards/standards/necb/docs/air_system_names_method.md +127 -0
- data/lib/openstudio-standards/thermal_zone/thermal_zone.rb +1 -1
- data/lib/openstudio-standards/utilities/template_measure/resources/BTAPMeasureHelper.rb +1 -1
- data/lib/openstudio-standards/version.rb +1 -1
- data/lib/openstudio-standards/weather/information.rb +61 -5
- data/lib/openstudio-standards/weather/modify.rb +1 -1
- data/lib/openstudio-standards.rb +5 -3
- metadata +12 -63
- data/data/standards/OpenStudio_Standards-deer.xlsx +0 -0
- data/lib/openstudio-standards/prototypes/common/objects/Prototype.ServiceWaterHeating.rb +0 -1100
- data/lib/openstudio-standards/service_water_heating/component.rb +0 -189
@@ -185,16 +185,16 @@ module TallBuilding
|
|
185
185
|
OpenStudio.logFree(OpenStudio::Error, 'openstudio.model.Model', 'No story info in the SWH loop.')
|
186
186
|
return false
|
187
187
|
end
|
188
|
-
main_swh_loop =
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
188
|
+
main_swh_loop = OpenstudioStandards::ServiceWaterHeating.create_service_water_heating_loop(model,
|
189
|
+
system_name: swh_loop_name,
|
190
|
+
service_water_temperature: OpenStudio.convert(prototype_input['main_service_water_temperature'], 'F', 'C').get,
|
191
|
+
service_water_pump_head: prototype_input['main_service_water_pump_head'].to_f,
|
192
|
+
service_water_pump_motor_efficiency: prototype_input['main_service_water_pump_motor_efficiency'],
|
193
|
+
water_heater_capacity: OpenStudio.convert(prototype_input['main_water_heater_capacity'], 'Btu/hr', 'W').get,
|
194
|
+
water_heater_volume: OpenStudio.convert(prototype_input['main_water_heater_volume'], 'gal', 'm^3').get,
|
195
|
+
water_heater_fuel: swh_fueltype,
|
196
|
+
on_cycle_parasitic_fuel_consumption_rate: OpenStudio.convert(prototype_input['main_service_water_parasitic_fuel_consumption_rate'], 'Btu/hr', 'W').get,
|
197
|
+
off_cycle_parasitic_fuel_consumption_rate: OpenStudio.convert(prototype_input['main_service_water_parasitic_fuel_consumption_rate'], 'Btu/hr', 'W').get)
|
198
198
|
|
199
199
|
# Attach the end uses based on floor function type
|
200
200
|
# Office and retail: add to mechanical room only
|
@@ -225,11 +225,9 @@ module TallBuilding
|
|
225
225
|
next if data['service_water_heating_peak_flow_rate'].to_f < 0.00001 && data['service_water_heating_peak_flow_per_area'].to_f < 0.00001
|
226
226
|
|
227
227
|
# Add a service water use for each space
|
228
|
-
space_multiplier = space.multiplier
|
229
228
|
water_fixture = model_add_swh_end_uses_by_space(model,
|
230
229
|
main_swh_loop,
|
231
|
-
space
|
232
|
-
space_multiplier)
|
230
|
+
space)
|
233
231
|
unless water_fixture.nil?
|
234
232
|
water_fixtures << water_fixture
|
235
233
|
end
|
@@ -246,47 +244,44 @@ module TallBuilding
|
|
246
244
|
|
247
245
|
# Add the booster water loop if there is any hotel floor
|
248
246
|
if additional_params[:num_of_floor_hotel].to_i > 0
|
249
|
-
swh_booster_loop =
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
OpenStudio.convert(prototype_input['booster_water_use_temperature'], 'F', 'C').get)
|
264
|
-
|
247
|
+
swh_booster_loop = OpenstudioStandards::ServiceWaterHeating.create_booster_water_heating_loop(model,
|
248
|
+
water_heater_capacity: OpenStudio.convert(prototype_input['booster_water_heater_capacity'], 'Btu/hr', 'W').get,
|
249
|
+
water_heater_volume: OpenStudio.convert(prototype_input['booster_water_heater_volume'], 'gal', 'm^3').get,
|
250
|
+
water_heater_fuel: prototype_input['booster_water_heater_fuel'],
|
251
|
+
service_water_temperature: OpenStudio.convert(prototype_input['booster_water_temperature'], 'F', 'C').get,
|
252
|
+
service_water_loop: hotel_swh_loop)
|
253
|
+
|
254
|
+
# add booster water use
|
255
|
+
OpenstudioStandards::ServiceWaterHeating.create_water_use(model,
|
256
|
+
name: 'Booster',
|
257
|
+
flow_rate: OpenStudio.convert(prototype_input['booster_service_water_peak_flowrate'], 'gal/min', 'm^3/s').get,
|
258
|
+
flow_rate_fraction_schedule: model_add_schedule(model, prototype_input['booster_service_water_flowrate_schedule']),
|
259
|
+
water_use_temperature: OpenStudio.convert(prototype_input['booster_water_use_temperature'], 'F', 'C').get,
|
260
|
+
service_water_loop: swh_booster_loop)
|
265
261
|
end
|
266
262
|
|
267
263
|
# for tall and super tall buildings, there is laundry only if hotel has more than 1 floors
|
268
264
|
# hotel_bot has laundry, if only one floor, doesn't have hotel_bot
|
269
265
|
if additional_params[:num_of_floor_hotel].to_i > 1
|
270
266
|
# Add the laundry service water heating loop
|
271
|
-
laundry_swh_loop =
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
#
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
nil)
|
267
|
+
laundry_swh_loop = OpenstudioStandards::ServiceWaterHeating.create_service_water_heating_loop(model,
|
268
|
+
system_name: 'Laundry Service Water Loop',
|
269
|
+
service_water_temperature: OpenStudio.convert(prototype_input['laundry_service_water_temperature'], 'F', 'C').get,
|
270
|
+
service_water_pump_head: prototype_input['laundry_service_water_pump_head'].to_f,
|
271
|
+
service_water_pump_motor_efficiency: prototype_input['laundry_service_water_pump_motor_efficiency'],
|
272
|
+
water_heater_capacity: OpenStudio.convert(prototype_input['laundry_water_heater_capacity'], 'Btu/hr', 'W').get,
|
273
|
+
water_heater_volume: OpenStudio.convert(prototype_input['laundry_water_heater_volume'], 'gal', 'm^3').get,
|
274
|
+
water_heater_fuel: prototype_input['laundry_water_heater_fuel'],
|
275
|
+
on_cycle_parasitic_fuel_consumption_rate: OpenStudio.convert(prototype_input['laundry_service_water_parasitic_fuel_consumption_rate'], 'Btu/hr', 'W').get,
|
276
|
+
off_cycle_parasitic_fuel_consumption_rate: OpenStudio.convert(prototype_input['laundry_service_water_parasitic_fuel_consumption_rate'], 'Btu/hr', 'W').get)
|
277
|
+
|
278
|
+
# add water use
|
279
|
+
OpenstudioStandards::ServiceWaterHeating.create_water_use(model,
|
280
|
+
name: 'Laundry',
|
281
|
+
flow_rate: OpenStudio.convert(prototype_input['laundry_service_water_peak_flowrate'], 'gal/min', 'm^3/s').get,
|
282
|
+
flow_rate_fraction_schedule: model_add_schedule(model, prototype_input['laundry_service_water_flowrate_schedule']),
|
283
|
+
water_use_temperature: OpenStudio.convert(prototype_input['laundry_water_use_temperature'], 'F', 'C').get,
|
284
|
+
service_water_loop: laundry_swh_loop)
|
290
285
|
end
|
291
286
|
return true
|
292
287
|
end
|
data/lib/openstudio-standards/prototypes/common/objects/Prototype.CentralAirSourceHeatPump.rb
CHANGED
@@ -27,7 +27,7 @@ class Standard
|
|
27
27
|
end
|
28
28
|
|
29
29
|
# change equipment name for EMS validity
|
30
|
-
plant_comp.setName(name
|
30
|
+
plant_comp.setName(ems_friendly_name(name))
|
31
31
|
|
32
32
|
# set plant component properties
|
33
33
|
plant_comp.setPlantLoadingMode('MeetsLoadWithNominalCapacityHiOutLimit')
|
@@ -296,6 +296,10 @@ class Standard
|
|
296
296
|
# Change the chilled water loop to have a two-way common pipes
|
297
297
|
chilled_water_loop.setCommonPipeSimulation('CommonPipe')
|
298
298
|
elsif pri_sec_config == 'heat_exchanger'
|
299
|
+
# Check number of chillers
|
300
|
+
if num_chillers > 3
|
301
|
+
OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.PlantLoop', "EMS Code for multiple chiller pump has not been written for greater than 3 chillers. This has #{num_chillers} chillers")
|
302
|
+
end
|
299
303
|
# NOTE: PRECONDITIONING for `const_pri_var_sec` pump type is only applicable for PRM routine and only applies to System Type 7 and System Type 8
|
300
304
|
# See: model_add_prm_baseline_system under Model object.
|
301
305
|
# In this scenario, we will need to create a primary and secondary configuration:
|
@@ -309,10 +313,15 @@ class Standard
|
|
309
313
|
secondary_chilled_water_loop.setName(secondary_loop_name)
|
310
314
|
chw_sizing_control(model, secondary_chilled_water_loop, dsgn_sup_wtr_temp, dsgn_sup_wtr_temp_delt)
|
311
315
|
chilled_water_loop.additionalProperties.setFeature('is_primary_loop', true)
|
316
|
+
chilled_water_loop.additionalProperties.setFeature('secondary_loop_name', secondary_chilled_water_loop.name.to_s)
|
312
317
|
secondary_chilled_water_loop.additionalProperties.setFeature('is_secondary_loop', true)
|
313
|
-
# primary chilled water
|
318
|
+
# primary chilled water pumps are added when adding chillers
|
314
319
|
# Add Constant pump, in plant loop, the number of chiller adjustment will assign pump to each chiller
|
315
|
-
pri_chw_pump = OpenStudio::Model::PumpConstantSpeed.new(model)
|
320
|
+
# pri_chw_pump = OpenStudio::Model::PumpConstantSpeed.new(model)
|
321
|
+
pri_chw_pump = OpenStudio::Model::PumpVariableSpeed.new(model)
|
322
|
+
pump_variable_speed_set_control_type(pri_chw_pump, control_type = 'Riding Curve')
|
323
|
+
# This pump name is important for function add_ems_for_multiple_chiller_pumps_w_secondary_plant. If you update
|
324
|
+
# it here, you must update the logic there to account for this
|
316
325
|
pri_chw_pump.setName("#{chilled_water_loop.name} Primary Pump")
|
317
326
|
# Will need to adjust the pump power after a sizing run
|
318
327
|
pri_chw_pump.setRatedPumpHead(OpenStudio.convert(15.0, 'ftH_{2}O', 'Pa').get / num_chillers)
|
@@ -375,8 +384,23 @@ class Standard
|
|
375
384
|
dist_clg.autosizeNominalCapacity
|
376
385
|
chilled_water_loop.addSupplyBranchForComponent(dist_clg)
|
377
386
|
else
|
387
|
+
|
388
|
+
# use default efficiency from 90.1-2019
|
389
|
+
# 1.188 kw/ton for a 150 ton AirCooled chiller
|
390
|
+
# 0.66 kw/ton for a 150 ton Water Cooled positive displacement chiller
|
391
|
+
case chiller_cooling_type
|
392
|
+
when 'AirCooled'
|
393
|
+
default_cop = kw_per_ton_to_cop(1.188)
|
394
|
+
when 'WaterCooled'
|
395
|
+
default_cop = kw_per_ton_to_cop(0.66)
|
396
|
+
else
|
397
|
+
default_cop = kw_per_ton_to_cop(0.66)
|
398
|
+
end
|
399
|
+
|
378
400
|
# make the correct type of chiller based these properties
|
379
401
|
chiller_sizing_factor = (1.0 / num_chillers).round(2)
|
402
|
+
|
403
|
+
# Create chillers and set plant operation scheme
|
380
404
|
num_chillers.times do |i|
|
381
405
|
chiller = OpenStudio::Model::ChillerElectricEIR.new(model)
|
382
406
|
chiller.setName("#{template} #{chiller_cooling_type} #{chiller_condenser_type} #{chiller_compressor_type} Chiller #{i}")
|
@@ -391,18 +415,6 @@ class Standard
|
|
391
415
|
chiller.setMinimumUnloadingRatio(0.25)
|
392
416
|
chiller.setChillerFlowMode('ConstantFlow')
|
393
417
|
chiller.setSizingFactor(chiller_sizing_factor)
|
394
|
-
|
395
|
-
# use default efficiency from 90.1-2019
|
396
|
-
# 1.188 kw/ton for a 150 ton AirCooled chiller
|
397
|
-
# 0.66 kw/ton for a 150 ton Water Cooled positive displacement chiller
|
398
|
-
case chiller_cooling_type
|
399
|
-
when 'AirCooled'
|
400
|
-
default_cop = kw_per_ton_to_cop(1.188)
|
401
|
-
when 'WaterCooled'
|
402
|
-
default_cop = kw_per_ton_to_cop(0.66)
|
403
|
-
else
|
404
|
-
default_cop = kw_per_ton_to_cop(0.66)
|
405
|
-
end
|
406
418
|
chiller.setReferenceCOP(default_cop)
|
407
419
|
|
408
420
|
# connect the chiller to the condenser loop if one was supplied
|
@@ -668,11 +680,10 @@ class Standard
|
|
668
680
|
summer_oat_wbs_f << OpenStudio.convert(summer_oat_wb_c, 'C', 'F').get
|
669
681
|
else
|
670
682
|
if dd.wetBulbOrDewPointAtMaximumDryBulb.is_initialized
|
671
|
-
summer_oat_wb_c = dd.wetBulbOrDewPointAtMaximumDryBulb
|
683
|
+
summer_oat_wb_c = dd.wetBulbOrDewPointAtMaximumDryBulb.get
|
672
684
|
summer_oat_wbs_f << OpenStudio.convert(summer_oat_wb_c, 'C', 'F').get
|
673
685
|
end
|
674
686
|
end
|
675
|
-
|
676
687
|
end
|
677
688
|
end
|
678
689
|
end
|
@@ -1020,22 +1031,25 @@ class Standard
|
|
1020
1031
|
loop_stpt_manager.setName("#{ground_hx_loop.name} Supply Outlet Setpoint")
|
1021
1032
|
loop_stpt_manager.addToNode(ground_hx_loop.supplyOutletNode)
|
1022
1033
|
|
1034
|
+
# edit name to be EMS friendly
|
1035
|
+
ground_hx_ems_name = ems_friendly_name(ground_hx.name)
|
1036
|
+
|
1023
1037
|
# sensor to read supply inlet temperature
|
1024
1038
|
inlet_temp_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model,
|
1025
1039
|
'System Node Temperature')
|
1026
|
-
inlet_temp_sensor.setName("#{
|
1040
|
+
inlet_temp_sensor.setName("#{ground_hx_ems_name} Inlet Temp Sensor")
|
1027
1041
|
inlet_temp_sensor.setKeyName(ground_hx_loop.supplyInletNode.handle.to_s)
|
1028
1042
|
|
1029
1043
|
# actuator to set supply outlet temperature
|
1030
1044
|
outlet_temp_actuator = OpenStudio::Model::EnergyManagementSystemActuator.new(hx_temp_sch,
|
1031
1045
|
'Schedule:Constant',
|
1032
1046
|
'Schedule Value')
|
1033
|
-
outlet_temp_actuator.setName("#{
|
1047
|
+
outlet_temp_actuator.setName("#{ground_hx_ems_name} Outlet Temp Actuator")
|
1034
1048
|
|
1035
1049
|
# program to control outlet temperature
|
1036
1050
|
# adjusts delta-t based on calculation of slope and intercept from control temperatures
|
1037
1051
|
program = OpenStudio::Model::EnergyManagementSystemProgram.new(model)
|
1038
|
-
program.setName("#{
|
1052
|
+
program.setName("#{ground_hx_ems_name} Temperature Control")
|
1039
1053
|
program_body = <<-EMS
|
1040
1054
|
SET Tin = #{inlet_temp_sensor.handle}
|
1041
1055
|
SET Tout = #{slope_c_per_c.round(2)} * Tin + #{intercept_c.round(1)}
|
@@ -1045,7 +1059,7 @@ class Standard
|
|
1045
1059
|
|
1046
1060
|
# program calling manager
|
1047
1061
|
pcm = OpenStudio::Model::EnergyManagementSystemProgramCallingManager.new(model)
|
1048
|
-
pcm.setName("#{program.name
|
1062
|
+
pcm.setName("#{program.name} Calling Manager")
|
1049
1063
|
pcm.setCallingPoint('InsideHVACSystemIterationLoop')
|
1050
1064
|
pcm.addProgram(program)
|
1051
1065
|
|
@@ -4451,20 +4465,20 @@ class Standard
|
|
4451
4465
|
# Create a sensor to read the zone load
|
4452
4466
|
zn_load_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model,
|
4453
4467
|
'Zone Predicted Sensible Load to Cooling Setpoint Heat Transfer Rate')
|
4454
|
-
zn_load_sensor.setName("#{zone_name_clean
|
4468
|
+
zn_load_sensor.setName("#{ems_friendly_name(zone_name_clean)} Clg Load Sensor")
|
4455
4469
|
zn_load_sensor.setKeyName(zone.handle.to_s)
|
4456
4470
|
|
4457
4471
|
# Create an actuator to set the airloop availability
|
4458
4472
|
air_loop_avail_actuator = OpenStudio::Model::EnergyManagementSystemActuator.new(air_loop_avail_sch,
|
4459
4473
|
'Schedule:Constant',
|
4460
4474
|
'Schedule Value')
|
4461
|
-
air_loop_avail_actuator.setName("#{air_loop.name
|
4475
|
+
air_loop_avail_actuator.setName("#{ems_friendly_name(air_loop.name)} Availability Actuator")
|
4462
4476
|
|
4463
4477
|
# Create a program to turn on Evap Cooler if
|
4464
4478
|
# there is a cooling load in the target zone.
|
4465
4479
|
# Load < 0.0 is a cooling load.
|
4466
4480
|
avail_program = OpenStudio::Model::EnergyManagementSystemProgram.new(model)
|
4467
|
-
avail_program.setName("#{air_loop.name
|
4481
|
+
avail_program.setName("#{ems_friendly_name(air_loop.name)} Availability Control")
|
4468
4482
|
avail_program_body = <<-EMS
|
4469
4483
|
IF #{zn_load_sensor.handle} < 0.0
|
4470
4484
|
SET #{air_loop_avail_actuator.handle} = 1
|
@@ -4477,10 +4491,16 @@ class Standard
|
|
4477
4491
|
programs << avail_program
|
4478
4492
|
|
4479
4493
|
# Direct Evap Cooler
|
4480
|
-
# @todo better assumptions for
|
4494
|
+
# @todo better assumptions for fan pressure rise
|
4481
4495
|
evap = OpenStudio::Model::EvaporativeCoolerDirectResearchSpecial.new(model, model.alwaysOnDiscreteSchedule)
|
4482
4496
|
evap.setName("#{zone.name} Evap Media")
|
4497
|
+
# assume 90% design effectiveness from https://basc.pnnl.gov/resource-guides/evaporative-cooling-systems#edit-group-description
|
4498
|
+
evap.setCoolerDesignEffectiveness(0.90)
|
4483
4499
|
evap.autosizePrimaryAirDesignFlowRate
|
4500
|
+
evap.autosizeRecirculatingWaterPumpPowerConsumption
|
4501
|
+
# use suggested E+ default values of 90.0 W-s/m^3 for pump sizing factor and 3.0 for blowdown concentration
|
4502
|
+
evap.setWaterPumpPowerSizingFactor(90.0)
|
4503
|
+
evap.setBlowdownConcentrationRatio(3.0)
|
4484
4504
|
evap.addToNode(air_loop.supplyInletNode)
|
4485
4505
|
|
4486
4506
|
# Fan (cycling), must be inside unitary system to cycle on airloop
|
@@ -612,11 +612,11 @@ class Standard
|
|
612
612
|
|
613
613
|
# Add defrost and dripdown schedules
|
614
614
|
defrost_sch = OpenStudio::Model::ScheduleRuleset.new(model)
|
615
|
-
defrost_sch.setName(
|
616
|
-
defrost_sch.defaultDaySchedule.setName("
|
615
|
+
defrost_sch.setName("#{ref_case.name} Defrost")
|
616
|
+
defrost_sch.defaultDaySchedule.setName("#{ref_case.name} Defrost Default")
|
617
617
|
dripdown_sch = OpenStudio::Model::ScheduleRuleset.new(model)
|
618
|
-
dripdown_sch.setName(
|
619
|
-
dripdown_sch.defaultDaySchedule.setName("
|
618
|
+
dripdown_sch.setName("#{ref_case.name} Dripdown")
|
619
|
+
dripdown_sch.defaultDaySchedule.setName("#{ref_case.name} Dripdown Default")
|
620
620
|
|
621
621
|
# Stagger the defrosts for cases by 1 hr
|
622
622
|
interval_defrost = (24 / numb_defrosts_per_day).floor # Hour interval between each defrost period
|
@@ -630,9 +630,9 @@ class Standard
|
|
630
630
|
(1..numb_defrosts_per_day).each do |defrost_of_day|
|
631
631
|
def_start_hr = first_def_start_hr + ((1 - defrost_of_day) * interval_defrost)
|
632
632
|
defrost_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, def_start_hr, 0, 0), 0)
|
633
|
-
defrost_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, def_start_hr, minutes_defrost.to_int, 0),
|
633
|
+
defrost_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, def_start_hr, minutes_defrost.to_int, 0), 1)
|
634
634
|
dripdown_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, def_start_hr, 0, 0), 0) # Dripdown is synced with defrost
|
635
|
-
dripdown_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, def_start_hr, minutes_dripdown.to_int, 0),
|
635
|
+
dripdown_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, def_start_hr, minutes_dripdown.to_int, 0), 1)
|
636
636
|
end
|
637
637
|
defrost_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), 0)
|
638
638
|
dripdown_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), 0)
|
@@ -698,11 +698,11 @@ class Standard
|
|
698
698
|
|
699
699
|
# Add defrost and dripdown schedules
|
700
700
|
defrost_sch_walkin = OpenStudio::Model::ScheduleRuleset.new(model)
|
701
|
-
defrost_sch_walkin.setName(
|
702
|
-
defrost_sch_walkin.defaultDaySchedule.setName("
|
701
|
+
defrost_sch_walkin.setName("#{ref_walkin.name} Defrost")
|
702
|
+
defrost_sch_walkin.defaultDaySchedule.setName("#{ref_walkin.name} Defrost Default")
|
703
703
|
dripdown_sch_walkin = OpenStudio::Model::ScheduleRuleset.new(model)
|
704
|
-
dripdown_sch_walkin.setName(
|
705
|
-
dripdown_sch_walkin.defaultDaySchedule.setName("
|
704
|
+
dripdown_sch_walkin.setName("#{ref_walkin.name} Dripdown")
|
705
|
+
dripdown_sch_walkin.defaultDaySchedule.setName("#{ref_walkin.name} Dripdown Default")
|
706
706
|
|
707
707
|
# Stagger the defrosts for cases by 1 hr
|
708
708
|
interval_defrost = (24 / numb_defrosts_per_day).floor # Hour interval between each defrost period
|
@@ -716,9 +716,9 @@ class Standard
|
|
716
716
|
(1..numb_defrosts_per_day).each do |defrost_of_day|
|
717
717
|
def_start_hr = first_def_start_hr + ((1 - defrost_of_day) * interval_defrost)
|
718
718
|
defrost_sch_walkin.defaultDaySchedule.addValue(OpenStudio::Time.new(0, def_start_hr, 0, 0), 0)
|
719
|
-
defrost_sch_walkin.defaultDaySchedule.addValue(OpenStudio::Time.new(0, def_start_hr, minutes_defrost.to_int, 0),
|
719
|
+
defrost_sch_walkin.defaultDaySchedule.addValue(OpenStudio::Time.new(0, def_start_hr, minutes_defrost.to_int, 0), 1)
|
720
720
|
dripdown_sch_walkin.defaultDaySchedule.addValue(OpenStudio::Time.new(0, def_start_hr, 0, 0), 0) # Dripdown is synced with defrost
|
721
|
-
dripdown_sch_walkin.defaultDaySchedule.addValue(OpenStudio::Time.new(0, def_start_hr, minutes_dripdown.to_int, 0),
|
721
|
+
dripdown_sch_walkin.defaultDaySchedule.addValue(OpenStudio::Time.new(0, def_start_hr, minutes_dripdown.to_int, 0), 1)
|
722
722
|
end
|
723
723
|
defrost_sch_walkin.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), 0)
|
724
724
|
dripdown_sch_walkin.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), 0)
|
@@ -899,22 +899,22 @@ class Standard
|
|
899
899
|
########################################
|
900
900
|
# Defrost schedule
|
901
901
|
defrost_sch = OpenStudio::Model::ScheduleRuleset.new(model)
|
902
|
-
defrost_sch.setName(
|
903
|
-
defrost_sch.defaultDaySchedule.setName(
|
902
|
+
defrost_sch.setName("#{ref_case.name} Defrost")
|
903
|
+
defrost_sch.defaultDaySchedule.setName("#{ref_case.name} Defrost Default")
|
904
904
|
defrost_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, i, 0, 0), 0)
|
905
|
-
defrost_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, i, 59, 0),
|
905
|
+
defrost_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, i, 59, 0), 1)
|
906
906
|
defrost_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), 0)
|
907
907
|
# Dripdown schedule
|
908
908
|
dripdown_sch = OpenStudio::Model::ScheduleRuleset.new(model)
|
909
|
-
dripdown_sch.setName(
|
910
|
-
dripdown_sch.defaultDaySchedule.setName(
|
909
|
+
dripdown_sch.setName("#{ref_case.name} Defrost")
|
910
|
+
dripdown_sch.defaultDaySchedule.setName("#{ref_case.name} Defrost Default")
|
911
911
|
dripdown_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, i, 0, 0), 0)
|
912
|
-
dripdown_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, i, 59, 0),
|
912
|
+
dripdown_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, i, 59, 0), 1)
|
913
913
|
dripdown_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), 0)
|
914
914
|
# Case Credit Schedule
|
915
915
|
case_credit_sch = OpenStudio::Model::ScheduleRuleset.new(model)
|
916
|
-
case_credit_sch.setName(
|
917
|
-
case_credit_sch.defaultDaySchedule.setName(
|
916
|
+
case_credit_sch.setName("#{ref_case.name} Case Credit")
|
917
|
+
case_credit_sch.defaultDaySchedule.setName("#{ref_case.name} Case Credit Default")
|
918
918
|
case_credit_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 7, 0, 0), 0.2)
|
919
919
|
case_credit_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 21, 0, 0), 0.4)
|
920
920
|
case_credit_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), 0.2)
|
@@ -937,8 +937,8 @@ class Standard
|
|
937
937
|
########################################
|
938
938
|
# Defrost schedule
|
939
939
|
defrost_sch = OpenStudio::Model::ScheduleRuleset.new(model)
|
940
|
-
defrost_sch.setName(
|
941
|
-
defrost_sch.defaultDaySchedule.setName(
|
940
|
+
defrost_sch.setName("#{ref_walkin.name} Defrost")
|
941
|
+
defrost_sch.defaultDaySchedule.setName("#{ref_walkin.name} Defrost Default")
|
942
942
|
defrost_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, i, 0, 0), 0)
|
943
943
|
defrost_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, i, 59, 0), 1)
|
944
944
|
defrost_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, i + 10, 0, 0), 0)
|
@@ -946,8 +946,8 @@ class Standard
|
|
946
946
|
defrost_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), 0)
|
947
947
|
# Dripdown schedule
|
948
948
|
dripdown_sch = OpenStudio::Model::ScheduleRuleset.new(model)
|
949
|
-
dripdown_sch.setName(
|
950
|
-
dripdown_sch.defaultDaySchedule.setName(
|
949
|
+
dripdown_sch.setName("#{ref_walkin.name} Defrost")
|
950
|
+
dripdown_sch.defaultDaySchedule.setName("#{ref_walkin.name} Defrost Default")
|
951
951
|
dripdown_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, i, 0, 0), 0)
|
952
952
|
dripdown_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, i, 59, 0), 1)
|
953
953
|
dripdown_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, i + 10, 0, 0), 0)
|
@@ -365,7 +365,7 @@ module OpenstudioStandards
|
|
365
365
|
else
|
366
366
|
num_timesteps = model.getTimestep.numberOfTimestepsPerHour
|
367
367
|
day_timeseries = schedule_day.timeSeries.values.to_a
|
368
|
-
schedule_values = day_timeseries.each_slice(num_timesteps).map { |slice| slice.sum / slice.size.to_f }
|
368
|
+
schedule_values = day_timeseries.each_slice(num_timesteps).map { |slice| (slice.sum / slice.size.to_f).round(10) }
|
369
369
|
end
|
370
370
|
|
371
371
|
unless schedule_values.size == 24
|
@@ -1056,7 +1056,7 @@ module OpenstudioStandards
|
|
1056
1056
|
remainder = days_to_fill - value[:days_used]
|
1057
1057
|
day_for_rule = days_to_fill - remainder
|
1058
1058
|
if remainder.size < days_to_fill.size
|
1059
|
-
autogen_rules[profile_index] = { days_to_fill: day_for_rule, hoo_start: hoo_start, hoo_end: hoo_end}
|
1059
|
+
autogen_rules[profile_index] = { days_to_fill: day_for_rule, hoo_start: hoo_start, hoo_end: hoo_end }
|
1060
1060
|
end
|
1061
1061
|
days_to_fill = remainder
|
1062
1062
|
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
module OpenstudioStandards
|
2
|
+
# The ServiceWaterHeating module provides methods to create, modify, and get information about service water heating
|
3
|
+
module ServiceWaterHeating
|
4
|
+
# @!group Create Piping Losses
|
5
|
+
# Methods to add service water heating piping losses
|
6
|
+
|
7
|
+
# Adds piping losses to a service water heating Loop.
|
8
|
+
# Assumes the piping system use insulated 0.75 inch copper piping.
|
9
|
+
# For circulating systems, assume length of piping is proportional to the building floor area and number of stories.
|
10
|
+
# For non-circulating systems, assume that the water heaters are close to the point of use.
|
11
|
+
#
|
12
|
+
# @param model [OpenStudio::Model::Model] OpenStudio model object
|
13
|
+
# @param service_water_loop [OpenStudio::Model::PlantLoop] the service water heating loop
|
14
|
+
# @param circulating [Boolean] use true for circulating systems, false for non-circulating systems
|
15
|
+
# @param pipe_insulation_thickness [Double] the thickness of the pipe insulation, in m. Use 0 for no insulation
|
16
|
+
# @param floor_area [Double] the area of building served by the service water heating loop, in m^2
|
17
|
+
# If nil, will use the total building floor area. Only used if circulating is true.
|
18
|
+
# @param number_of_stories [Integer] the number of stories served by the service water heating loop
|
19
|
+
# If nil, will use the total building number of stories. Only used if circulating is true.
|
20
|
+
# @param pipe_length [Double] the length of the pipe in meters. Default is 6.1 m / 20 ft.
|
21
|
+
# Only used if circulating is false.
|
22
|
+
# @param air_temperature [Double] the temperature of the air surrounding the piping, in C. Default is 21.1 C / 70 F.
|
23
|
+
# @return [Boolean] returns true if successful, false if not
|
24
|
+
def self.create_service_water_heating_piping_losses(model,
|
25
|
+
service_water_loop,
|
26
|
+
circulating: true,
|
27
|
+
pipe_insulation_thickness: 0.0,
|
28
|
+
floor_area: nil,
|
29
|
+
number_of_stories: nil,
|
30
|
+
pipe_length: 6.1,
|
31
|
+
air_temperature: 21.1)
|
32
|
+
|
33
|
+
# Estimate pipe length
|
34
|
+
if circulating
|
35
|
+
# For circulating systems, get pipe length based on the size of the building.
|
36
|
+
# Formula from A.3.1 PrototypeModelEnhancements_2014_0.pdf
|
37
|
+
|
38
|
+
# get the floor area
|
39
|
+
floor_area = model.getBuilding.floorArea if floor_area.nil?
|
40
|
+
floor_area_ft2 = OpenStudio.convert(floor_area, 'm^2', 'ft^2').get
|
41
|
+
|
42
|
+
# get the number of stories
|
43
|
+
number_of_stories = model.getBuilding.buildingStories.size if number_of_stories.nil?
|
44
|
+
|
45
|
+
# calculate the piping length
|
46
|
+
pipe_length_ft = 2.0 * (Math.sqrt(floor_area_ft2 / number_of_stories) + (10.0 * (number_of_stories - 1.0)))
|
47
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.ServiceWaterHeating', "Pipe length #{pipe_length_ft.round}ft = 2.0 * ( (#{floor_area_ft2.round}ft2 / #{number_of_stories} stories)^0.5 + (10.0ft * (#{number_of_stories} stories - 1.0) ) )")
|
48
|
+
else
|
49
|
+
# For non-circulating systems, assume water heater is close to point of use
|
50
|
+
|
51
|
+
# get pipe length
|
52
|
+
pipe_length_m = pipe_length.nil? ? 6.1 : pipe_length
|
53
|
+
|
54
|
+
pipe_length_ft = OpenStudio.convert(pipe_length_m, 'm', 'ft').get
|
55
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.ServiceWaterHeating', "Pipe length #{pipe_length_ft.round}ft. For non-circulating systems, assume water heater is close to point of use.")
|
56
|
+
end
|
57
|
+
|
58
|
+
# For systems whose water heater object represents multiple pieces
|
59
|
+
# of equipment, multiply the piping length by the number of pieces of equipment.
|
60
|
+
service_water_loop.supplyComponents('OS_WaterHeater_Mixed'.to_IddObjectType).each do |sc|
|
61
|
+
next unless sc.to_WaterHeaterMixed.is_initialized
|
62
|
+
|
63
|
+
water_heater = sc.to_WaterHeaterMixed.get
|
64
|
+
|
65
|
+
# get number of water heaters
|
66
|
+
if water_heater.additionalProperties.getFeatureAsInteger('component_quantity').is_initialized
|
67
|
+
comp_qty = water_heater.additionalProperties.getFeatureAsInteger('component_quantity').get
|
68
|
+
else
|
69
|
+
comp_qty = 1
|
70
|
+
end
|
71
|
+
|
72
|
+
# if more than 1 water heater, multiply the pipe length by the number of water heaters,
|
73
|
+
# unless the user has specified a pipe length
|
74
|
+
if comp_qty > 1 && pipe_length.nil?
|
75
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.ServiceWaterHeating', "Piping length has been multiplied by #{comp_qty}X because #{water_heater.name} represents #{comp_qty} pieces of equipment.")
|
76
|
+
pipe_length_ft *= comp_qty
|
77
|
+
break
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Service water heating piping heat loss scheduled air temperature
|
82
|
+
air_temperature_f = OpenStudio.convert(air_temperature, 'C', 'F').get
|
83
|
+
swh_piping_air_temp_sch = OpenstudioStandards::Schedules.create_constant_schedule_ruleset(model,
|
84
|
+
air_temperature,
|
85
|
+
name: "#{service_water_loop.name} Piping Air Temp - #{air_temperature_f.round}F",
|
86
|
+
schedule_type_limit: 'Temperature')
|
87
|
+
|
88
|
+
# Service water heating piping heat loss scheduled air velocity
|
89
|
+
swh_piping_air_velocity_m_per_s = 0.3
|
90
|
+
swh_piping_air_velocity_mph = OpenStudio.convert(swh_piping_air_velocity_m_per_s, 'm/s', 'mile/hr').get
|
91
|
+
swh_piping_air_velocity_sch = OpenstudioStandards::Schedules.create_constant_schedule_ruleset(model,
|
92
|
+
swh_piping_air_velocity_m_per_s,
|
93
|
+
name: "#{service_water_loop.name} Piping Air Velocity - #{swh_piping_air_velocity_mph.round(2)}mph")
|
94
|
+
|
95
|
+
# Material for 3/4in type L (heavy duty) copper pipe
|
96
|
+
copper_pipe = OpenStudio::Model::StandardOpaqueMaterial.new(model)
|
97
|
+
copper_pipe.setName('Copper pipe 0.75in type L')
|
98
|
+
copper_pipe.setRoughness('Smooth')
|
99
|
+
copper_pipe.setThickness(OpenStudio.convert(0.045, 'in', 'm').get)
|
100
|
+
copper_pipe.setThermalConductivity(386.0)
|
101
|
+
copper_pipe.setDensity(OpenStudio.convert(556, 'lb/ft^3', 'kg/m^3').get)
|
102
|
+
copper_pipe.setSpecificHeat(OpenStudio.convert(0.092, 'Btu/lb*R', 'J/kg*K').get)
|
103
|
+
copper_pipe.setThermalAbsorptance(0.9) # @todo find reference for property
|
104
|
+
copper_pipe.setSolarAbsorptance(0.7) # @todo find reference for property
|
105
|
+
copper_pipe.setVisibleAbsorptance(0.7) # @todo find reference for property
|
106
|
+
|
107
|
+
# Construction for pipe
|
108
|
+
pipe_construction = OpenStudio::Model::Construction.new(model)
|
109
|
+
|
110
|
+
# Add insulation material to insulated pipe
|
111
|
+
if pipe_insulation_thickness > 0
|
112
|
+
# Material for fiberglass insulation
|
113
|
+
# R-value from Owens-Corning 1/2in fiberglass pipe insulation
|
114
|
+
# https://www.grainger.com/product/OWENS-CORNING-1-2-Thick-40PP22
|
115
|
+
# but modified until simulated heat loss = 17.7 Btu/hr/ft of pipe with 140F water and 70F air
|
116
|
+
pipe_insulation_thickness_in = OpenStudio.convert(pipe_insulation_thickness, 'm', 'in').get
|
117
|
+
insulation = OpenStudio::Model::StandardOpaqueMaterial.new(model)
|
118
|
+
insulation.setName("Fiberglass batt #{pipe_insulation_thickness_in.round(2)}in")
|
119
|
+
insulation.setRoughness('Smooth')
|
120
|
+
insulation.setThickness(OpenStudio.convert(pipe_insulation_thickness_in, 'in', 'm').get)
|
121
|
+
insulation.setThermalConductivity(OpenStudio.convert(0.46, 'Btu*in/hr*ft^2*R', 'W/m*K').get)
|
122
|
+
insulation.setDensity(OpenStudio.convert(0.7, 'lb/ft^3', 'kg/m^3').get)
|
123
|
+
insulation.setSpecificHeat(OpenStudio.convert(0.2, 'Btu/lb*R', 'J/kg*K').get)
|
124
|
+
insulation.setThermalAbsorptance(0.9) # Irrelevant for Pipe:Indoor; no radiation model is used
|
125
|
+
insulation.setSolarAbsorptance(0.7) # Irrelevant for Pipe:Indoor; no radiation model is used
|
126
|
+
insulation.setVisibleAbsorptance(0.7) # Irrelevant for Pipe:Indoor; no radiation model is used
|
127
|
+
|
128
|
+
pipe_construction.setName("Copper pipe 0.75in type L with #{pipe_insulation_thickness_in.round(2)}in fiberglass batt")
|
129
|
+
pipe_construction.setLayers([insulation, copper_pipe])
|
130
|
+
else
|
131
|
+
pipe_construction.setName('Uninsulated copper pipe 0.75in type L')
|
132
|
+
pipe_construction.setLayers([copper_pipe])
|
133
|
+
end
|
134
|
+
|
135
|
+
heat_loss_pipe = OpenStudio::Model::PipeIndoor.new(model)
|
136
|
+
heat_loss_pipe.setName("#{service_water_loop.name} Pipe #{pipe_length_ft.round}ft")
|
137
|
+
heat_loss_pipe.setEnvironmentType('Schedule')
|
138
|
+
heat_loss_pipe.setAmbientTemperatureSchedule(swh_piping_air_temp_sch)
|
139
|
+
heat_loss_pipe.setAmbientAirVelocitySchedule(swh_piping_air_velocity_sch)
|
140
|
+
heat_loss_pipe.setConstruction(pipe_construction)
|
141
|
+
heat_loss_pipe.setPipeInsideDiameter(OpenStudio.convert(0.785, 'in', 'm').get)
|
142
|
+
heat_loss_pipe.setPipeLength(OpenStudio.convert(pipe_length_ft, 'ft', 'm').get)
|
143
|
+
|
144
|
+
heat_loss_pipe.addToNode(service_water_loop.demandInletNode)
|
145
|
+
|
146
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.ServiceWaterHeating', "Added #{pipe_length_ft.round}ft of #{pipe_construction.name} losing heat to #{air_temperature_f.round}F air to #{service_water_loop.name}.")
|
147
|
+
return true
|
148
|
+
end
|
149
|
+
|
150
|
+
# @!endgroup Create Piping Losses
|
151
|
+
end
|
152
|
+
end
|