openstudio-standards 0.8.5 → 0.8.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/data/standards/test_performance_expected_dd_results.csv +90 -90
- data/lib/openstudio-standards/btap/activity.rb +858 -61
- data/lib/openstudio-standards/btap/attributes.rb +297 -103
- data/lib/openstudio-standards/btap/bridging.rb +1335 -593
- data/lib/openstudio-standards/btap/btap.rb +60 -181
- data/lib/openstudio-standards/btap/carbon/btap_carbon.rb +199 -142
- data/lib/openstudio-standards/btap/common/constructions.json +1275 -0
- data/lib/openstudio-standards/btap/common/costs.csv +1969 -0
- data/lib/openstudio-standards/btap/common/costs_local_factors.csv +2315 -0
- data/lib/openstudio-standards/btap/common/materials_glazing.csv +61 -0
- data/lib/openstudio-standards/btap/{common_resources → common}/materials_hvac.csv +1685 -1685
- data/lib/openstudio-standards/btap/{common_resources → common}/materials_lighting.csv +266 -266
- data/lib/openstudio-standards/btap/common/materials_opaque.csv +214 -0
- data/lib/openstudio-standards/btap/common/necb_building_types.csv +35 -0
- data/lib/openstudio-standards/btap/common/necb_space_types.csv +110 -0
- data/lib/openstudio-standards/btap/common/thermal_bridging.csv +73 -0
- data/lib/openstudio-standards/btap/costing/btap_costing.rb +346 -429
- data/lib/openstudio-standards/btap/costing/database.rb +104 -0
- data/lib/openstudio-standards/btap/costing/daylighting_sensor_control_costing.rb +356 -344
- data/lib/openstudio-standards/btap/costing/dcv_costing.rb +282 -296
- data/lib/openstudio-standards/btap/costing/envelope_costing.rb +179 -192
- data/lib/openstudio-standards/btap/costing/heating_cooling_costing.rb +2477 -2316
- data/lib/openstudio-standards/btap/costing/led_lighting_costing.rb +127 -142
- data/lib/openstudio-standards/btap/costing/lighting_costing.rb +216 -198
- data/lib/openstudio-standards/btap/costing/nv_costing.rb +522 -523
- data/lib/openstudio-standards/btap/costing/pv_ground_costing.rb +649 -649
- data/lib/openstudio-standards/btap/costing/shw_costing.rb +626 -625
- data/lib/openstudio-standards/btap/costing/thermal_bridging_costing.rb +72 -0
- data/lib/openstudio-standards/btap/costing/ventilation_costing.rb +2363 -2361
- data/lib/openstudio-standards/btap/deprecated.rb +1033 -0
- data/lib/openstudio-standards/btap/envelope.rb +313 -572
- data/lib/openstudio-standards/btap/fileio.rb +152 -1070
- data/lib/openstudio-standards/btap/geometry.rb +486 -766
- data/lib/openstudio-standards/btap/linear_regression.rb +130 -0
- data/lib/openstudio-standards/btap/paths.rb +46 -0
- data/lib/openstudio-standards/btap/qaqc/analysis.rb +163 -0
- data/lib/openstudio-standards/btap/qaqc/data.rb +2293 -0
- data/lib/openstudio-standards/btap/qaqc/datapoint.rb +641 -0
- data/lib/openstudio-standards/btap/schedules.rb +11 -611
- data/lib/openstudio-standards/btap/structure.rb +574 -189
- data/lib/openstudio-standards/constructions/materials/information.rb +1 -1
- data/lib/openstudio-standards/create_typical/create_typical.rb +1 -1
- data/lib/openstudio-standards/exterior_lighting/create.rb +135 -85
- data/lib/openstudio-standards/exterior_lighting/data/typical_exterior_lighting.json +20 -0
- data/lib/openstudio-standards/exterior_lighting/information.rb +23 -2
- data/lib/openstudio-standards/geometry/create.rb +7 -3
- data/lib/openstudio-standards/prototypes/ashrae_90_1/ashrae_90_1_2016/ashrae_90_1_2016.Model.rb +3 -2
- data/lib/openstudio-standards/prototypes/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.Model.rb +3 -2
- data/lib/openstudio-standards/prototypes/common/data/thermostat_schedule_lookup.json +84 -84
- data/lib/openstudio-standards/prototypes/common/objects/Prototype.hvac_systems.rb +4 -4
- data/lib/openstudio-standards/refrigeration/create_walkin.rb +45 -5
- data/lib/openstudio-standards/refrigeration/data/refrigerated_walkins.csv +75 -75
- data/lib/openstudio-standards/schedules/parametric.rb +6 -0
- data/lib/openstudio-standards/service_water_heating/create_typical.rb +10 -3
- data/lib/openstudio-standards/service_water_heating/create_water_heating_loop.rb +30 -14
- data/lib/openstudio-standards/service_water_heating/information.rb +4 -1
- data/lib/openstudio-standards/sql_file/unmet_hours.rb +2 -1
- data/lib/openstudio-standards/standards/Standards.CoilCoolingDXSingleSpeed.rb +3 -1
- data/lib/openstudio-standards/standards/Standards.CoilHeatingDXSingleSpeed.rb +3 -1
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/data/ashrae_90_1_2004.boilers.json +12 -0
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/data/ashrae_90_1_2004.construction_properties.json +18432 -3072
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/data/ashrae_90_1_2007.boilers.json +26 -0
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/data/ashrae_90_1_2007.construction_properties.json +8532 -1422
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/data/ashrae_90_1_2010.boilers.json +26 -0
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/data/ashrae_90_1_2010.construction_properties.json +8532 -1422
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.boilers.json +16 -0
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.computer_room_acs.json +30 -30
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.construction_properties.json +7560 -1260
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/ashrae_90_1_2016.PumpVariableSpeed.rb +1 -2
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/data/ashrae_90_1_2016.boilers.json +16 -0
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2016/data/ashrae_90_1_2016.construction_properties.json +7560 -1260
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.AirLoopHVAC.rb +3 -3
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/ashrae_90_1_2019.PumpVariableSpeed.rb +1 -2
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/data/ashrae_90_1_2019.boilers.json +22 -0
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/data/ashrae_90_1_2019.construction_properties.json +7236 -1206
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2019/data/ashrae_90_1_2019.furnaces.json +223 -19
- data/lib/openstudio-standards/standards/ashrae_90_1/data/ashrae_90_1.schedules.json +37 -1
- data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.boilers.json +3 -0
- data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm_2019/data/ashrae_90_1_prm_2019.construction_properties.json +6900 -1150
- data/lib/openstudio-standards/standards/cbes/data/cbes.schedules.json +1 -1
- data/lib/openstudio-standards/standards/deer/data/deer.schedules.json +1 -1
- data/lib/openstudio-standards/standards/necb/BTAP1980TO2010/data/surface_thermal_transmittance.json +76 -40
- data/lib/openstudio-standards/standards/necb/BTAPPRE1980/data/surface_thermal_transmittance.json +76 -40
- data/lib/openstudio-standards/standards/necb/ECMS/hvac_systems.rb +6 -4
- data/lib/openstudio-standards/standards/necb/NECB2011/NECB2011_QAQC.json +2988 -0
- data/lib/openstudio-standards/standards/necb/NECB2011/autozone.rb +25 -3
- data/lib/openstudio-standards/standards/necb/NECB2011/building_envelope.rb +672 -534
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/Hospital.osm +1791 -1792
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/LEEPMultiTower.osm +7 -1
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/LEEPTownHouse.osm +7 -1
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/LargeHotel.osm +5 -6
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/LargeOffice.osm +8 -9
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/NorthernEducation.osm +10 -4
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/NorthernHealthCare.osm +14 -15
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/Outpatient.osm +7 -1
- data/lib/openstudio-standards/standards/necb/NECB2011/data/surface_thermal_transmittance.json +76 -40
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_systems.rb +14 -6
- data/lib/openstudio-standards/standards/necb/NECB2011/necb_2011.rb +542 -130
- data/lib/openstudio-standards/standards/necb/NECB2011/qaqc/necb_qaqc.rb +30 -63
- data/lib/openstudio-standards/standards/necb/NECB2011/service_water_heating.rb +7 -2
- data/lib/openstudio-standards/standards/necb/NECB2015/data/surface_thermal_transmittance.json +90 -0
- data/lib/openstudio-standards/standards/necb/NECB2015/necb_2015.rb +8 -6
- data/lib/openstudio-standards/standards/necb/NECB2017/data/surface_thermal_transmittance.json +76 -40
- data/lib/openstudio-standards/standards/necb/NECB2017/necb_2017.rb +2 -1
- data/lib/openstudio-standards/standards/necb/NECB2020/building_envelope.rb +0 -117
- data/lib/openstudio-standards/standards/necb/NECB2020/data/surface_thermal_transmittance.json +76 -45
- data/lib/openstudio-standards/standards/necb/NECB2020/necb_2020.rb +218 -0
- data/lib/openstudio-standards/standards/necb/common/construction_defaults.osm +12 -7
- data/lib/openstudio-standards/standards/standard.rb +1 -1
- data/lib/openstudio-standards/version.rb +1 -1
- data/lib/openstudio-standards.rb +9 -4
- metadata +59 -66
- data/data/inventory/thermal_bridging.csv +0 -90
- data/data/standards/OpenStudio_Standards-ashrae_90_1-ALL-comstock(space_types).xlsx +0 -0
- data/data/standards/openstudio_standards_duplicates_log.csv +0 -7962
- data/lib/openstudio-standards/btap/NECB_building_types.csv +0 -35
- data/lib/openstudio-standards/btap/NECB_space_types.csv +0 -109
- data/lib/openstudio-standards/btap/WeatherData1.json +0 -2110
- data/lib/openstudio-standards/btap/WeatherData1.xlsx +0 -0
- data/lib/openstudio-standards/btap/btap_result.rb +0 -1144
- data/lib/openstudio-standards/btap/btap_test_helper.rb +0 -86
- data/lib/openstudio-standards/btap/common_paths.rb +0 -81
- data/lib/openstudio-standards/btap/common_resources/ConstructionProperties.csv +0 -52
- data/lib/openstudio-standards/btap/common_resources/Constructions.csv +0 -37
- data/lib/openstudio-standards/btap/common_resources/construction_sets.csv +0 -1270
- data/lib/openstudio-standards/btap/common_resources/constructions_glazing.csv +0 -121
- data/lib/openstudio-standards/btap/common_resources/constructions_opaque.csv +0 -2256
- data/lib/openstudio-standards/btap/common_resources/costs.csv +0 -1897
- data/lib/openstudio-standards/btap/common_resources/costs_local_factors.csv +0 -2315
- data/lib/openstudio-standards/btap/common_resources/materials_glazing.csv +0 -35
- data/lib/openstudio-standards/btap/common_resources/materials_opaque.csv +0 -164
- data/lib/openstudio-standards/btap/costing/btap_measure_helper.rb +0 -359
- data/lib/openstudio-standards/btap/costing/btap_workflow.rb +0 -117
- data/lib/openstudio-standards/btap/costing/copy_test_results_files_to_expected_results.rb +0 -11
- data/lib/openstudio-standards/btap/costing/cost_building_from_file.rb +0 -136
- data/lib/openstudio-standards/btap/costing/costing_database_wrapper.rb +0 -173
- data/lib/openstudio-standards/btap/costing/dummy.epw +0 -8768
- data/lib/openstudio-standards/btap/costing/dummy.osm +0 -5320
- data/lib/openstudio-standards/btap/costing/neb_end_use_prices.csv +0 -42
- data/lib/openstudio-standards/btap/costing/necb_2011_spacetype_info.csv +0 -225
- data/lib/openstudio-standards/btap/costing/necb_reference_runs.csv +0 -28705
- data/lib/openstudio-standards/btap/costing/parallel_tests.rb +0 -92
- data/lib/openstudio-standards/btap/costing/test_list.txt +0 -15
- data/lib/openstudio-standards/btap/costing/test_run_all_test_locally.rb +0 -27
- data/lib/openstudio-standards/btap/costing/test_run_costing_tests.rb +0 -80
- data/lib/openstudio-standards/btap/necb_2011_spacetype_info.csv +0 -225
- data/lib/openstudio-standards/btap/utilities/Add_template_field_to_json.rb +0 -22
- data/lib/openstudio-standards/btap/utilities/convert_surfaces_to_adiabatic_necb_8426.rb +0 -204
- data/lib/openstudio-standards/btap/utilities/generate_space_types.rb +0 -8
- data/lib/openstudio-standards/btap/utilities/necb_to_epw_map.rb +0 -50
- data/lib/openstudio-standards/btap/utilities/os_sim_extract.rb +0 -48
- data/lib/openstudio-standards/btap/utilities/rename_surfaces.rb +0 -24
- data/lib/openstudio-standards/btap/utilities/round_surf_coords.rb +0 -32
- data/lib/openstudio-standards/btap/utilities/sched_create.rb +0 -145
- data/lib/openstudio-standards/btap/utilities/set_mult_to_adiabatic.rb +0 -53
- data/lib/openstudio-standards/btap/utilities/space_type.rb +0 -78
- data/lib/openstudio-standards/btap/utilities/weatherData1_xlsx_to_json.rb +0 -56
- data/lib/openstudio-standards/btap/vintagizer.rb +0 -161
- data/lib/openstudio-standards/btap/visualization.rb +0 -72
- data/lib/openstudio-standards/standards/necb/NECB2011/data/necb_2011_spacetype_info.csv +0 -225
- data/lib/openstudio-standards/standards/necb/common/btap_analysis.rb +0 -79
- data/lib/openstudio-standards/standards/necb/common/btap_data.rb +0 -2656
- data/lib/openstudio-standards/standards/necb/common/btap_datapoint.rb +0 -653
- data/lib/openstudio-standards/standards/necb/common/necb_reference_runs.csv +0 -28705
- data/lib/openstudio-standards/standards/necb/common/utility_pricing_2025-02-20.csv +0 -92
- /data/lib/openstudio-standards/btap/{common_resources → common}/carbon_frame.csv +0 -0
- /data/lib/openstudio-standards/btap/{common_resources → common}/carbon_glazing.csv +0 -0
- /data/lib/openstudio-standards/btap/{common_resources → common}/carbon_opaque.csv +0 -0
- /data/lib/openstudio-standards/btap/{common_resources → common}/hvac_vent_ahu.csv +0 -0
- /data/lib/openstudio-standards/btap/{common_resources → common}/lighting.csv +0 -0
- /data/lib/openstudio-standards/btap/{common_resources → common}/lighting_sets.csv +0 -0
- /data/lib/openstudio-standards/btap/{common_resources → common}/locations.csv +0 -0
- /data/lib/openstudio-standards/btap/{costing → common}/mech_sizing.json +0 -0
|
@@ -293,6 +293,7 @@ class NECB2011 < Standard
|
|
|
293
293
|
scale_x: nil,
|
|
294
294
|
scale_y: nil,
|
|
295
295
|
scale_z: nil,
|
|
296
|
+
footprint_aspect_ratio: nil,
|
|
296
297
|
pv_ground_type: nil,
|
|
297
298
|
pv_ground_total_area_pv_panels_m2: nil,
|
|
298
299
|
pv_ground_tilt_angle: nil,
|
|
@@ -366,6 +367,7 @@ class NECB2011 < Standard
|
|
|
366
367
|
scale_x: scale_x,
|
|
367
368
|
scale_y: scale_y,
|
|
368
369
|
scale_z: scale_z,
|
|
370
|
+
footprint_aspect_ratio: footprint_aspect_ratio,
|
|
369
371
|
pv_ground_type: pv_ground_type, # Two options: (1) nil/none/false/'NECB_Default', (2) 'add_pv_ground'
|
|
370
372
|
pv_ground_total_area_pv_panels_m2: pv_ground_total_area_pv_panels_m2, # Options: (1) nil/none/false, (2) 'NECB_Default' (i.e. building footprint), (3) area value (e.g. 50)
|
|
371
373
|
pv_ground_tilt_angle: pv_ground_tilt_angle, # Options: (1) nil/none/false, (2) 'NECB_Default' (i.e. latitude), (3) tilt angle value (e.g. 20)
|
|
@@ -402,7 +404,7 @@ class NECB2011 < Standard
|
|
|
402
404
|
# Created this method so that additional methods can be addded for bulding the prototype model in later
|
|
403
405
|
# code versions without modifying the build_protoype_model method or copying it wholesale for a few changes.
|
|
404
406
|
def model_apply_standard(model:,
|
|
405
|
-
construction_opt: '',
|
|
407
|
+
construction_opt: 'structure',
|
|
406
408
|
tbd_option: 'none',
|
|
407
409
|
tbd_interpolate: true,
|
|
408
410
|
epw_file:,
|
|
@@ -450,6 +452,7 @@ class NECB2011 < Standard
|
|
|
450
452
|
scale_x: nil,
|
|
451
453
|
scale_y: nil,
|
|
452
454
|
scale_z: nil,
|
|
455
|
+
footprint_aspect_ratio: nil,
|
|
453
456
|
nv_type: nil,
|
|
454
457
|
nv_opening_fraction: nil,
|
|
455
458
|
nv_temp_out_min: nil,
|
|
@@ -475,6 +478,7 @@ class NECB2011 < Standard
|
|
|
475
478
|
airloop_fancoils_heating: nil,
|
|
476
479
|
oerd_utility_pricing: nil)
|
|
477
480
|
|
|
481
|
+
oerd_utility_pricing = false
|
|
478
482
|
apply_weather_data(model: model,
|
|
479
483
|
epw_file: epw_file,
|
|
480
484
|
custom_weather_folder: custom_weather_folder,
|
|
@@ -482,20 +486,38 @@ class NECB2011 < Standard
|
|
|
482
486
|
primary_heating_fuel = validate_primary_heating_fuel(primary_heating_fuel: primary_heating_fuel, model: model)
|
|
483
487
|
self.fuel_type_set = SystemFuels.new()
|
|
484
488
|
self.fuel_type_set.set_defaults(standards_data: @standards_data, primary_heating_fuel: primary_heating_fuel)
|
|
485
|
-
clean_and_scale_model(model: model,
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
489
|
+
clean_and_scale_model(model: model,
|
|
490
|
+
rotation_degrees: rotation_degrees,
|
|
491
|
+
scale_x: scale_x,
|
|
492
|
+
scale_y: scale_y,
|
|
493
|
+
scale_z: scale_z,
|
|
494
|
+
footprint_aspect_ratio: footprint_aspect_ratio)
|
|
495
|
+
|
|
496
|
+
ext_floor_cond = convert_arg_to_f(variable: ext_floor_cond, default: nil)
|
|
497
|
+
ext_roof_cond = convert_arg_to_f(variable: ext_roof_cond, default: nil)
|
|
498
|
+
ext_wall_cond = convert_arg_to_f(variable: ext_wall_cond, default: nil)
|
|
499
|
+
ground_floor_cond = convert_arg_to_f(variable: ground_floor_cond, default: nil)
|
|
500
|
+
ground_roof_cond = convert_arg_to_f(variable: ground_roof_cond, default: nil)
|
|
501
|
+
ground_wall_cond = convert_arg_to_f(variable: ground_wall_cond, default: nil)
|
|
502
|
+
door_construction_cond = convert_arg_to_f(variable: door_construction_cond, default: nil)
|
|
503
|
+
fixed_window_cond = convert_arg_to_f(variable: fixed_window_cond, default: nil)
|
|
504
|
+
fixed_wind_solar_trans = convert_arg_to_f(variable: fixed_wind_solar_trans, default: nil)
|
|
505
|
+
skylight_solar_trans = convert_arg_to_f(variable: skylight_solar_trans, default: nil)
|
|
506
|
+
glass_door_solar_trans = convert_arg_to_f(variable: glass_door_solar_trans, default: nil)
|
|
507
|
+
fdwr_set = convert_arg_to_f(variable: fdwr_set, default: -1)
|
|
508
|
+
srr_set = convert_arg_to_f(variable: srr_set, default: -1)
|
|
509
|
+
srr_opt = convert_arg_to_string(variable: srr_opt, default: '')
|
|
510
|
+
construction_opt = convert_arg_to_string(variable: construction_opt, default: 'structure')
|
|
511
|
+
tbd_option = convert_arg_to_string(variable: tbd_option, default: 'none')
|
|
512
|
+
tbd_interpolate = convert_arg_to_bool(variable: tbd_interpolate, default: true)
|
|
513
|
+
necb_hdd = convert_arg_to_bool(variable: necb_hdd, default: true)
|
|
514
|
+
boiler_fuel = convert_arg_to_string(variable: boiler_fuel, default: nil)
|
|
515
|
+
boiler_cap_ratio = convert_arg_to_string(variable: boiler_cap_ratio, default: nil)
|
|
516
|
+
swh_fuel = convert_arg_to_string(variable: swh_fuel, default: nil)
|
|
497
517
|
airloop_fancoils_heating = convert_arg_to_bool(variable: airloop_fancoils_heating, default: false)
|
|
498
518
|
|
|
519
|
+
massive = construction_opt == 'structure'
|
|
520
|
+
|
|
499
521
|
# Check if custom systems are assigned to dwelling units, washrooms, corridors, and storage rooms. If they are, set
|
|
500
522
|
# them to be the same as the primary system type. If no primary system type is defined then set them to be nil.
|
|
501
523
|
hvac_system_dwelling_units, hvac_system_corridor, hvac_system_storage, hvac_system_washrooms = reset_hvac_system_if_required(hvac_system_primary: hvac_system_primary,
|
|
@@ -517,7 +539,7 @@ class NECB2011 < Standard
|
|
|
517
539
|
|
|
518
540
|
output_meters = check_output_meters(output_meters: output_meters) if oerd_utility_pricing
|
|
519
541
|
|
|
520
|
-
assign_building_activity(model: model)
|
|
542
|
+
assign_building_activity(model: model, option: construction_opt)
|
|
521
543
|
assign_building_structure(model: model, activity: @activity, massive: massive)
|
|
522
544
|
apply_loads(model: model,
|
|
523
545
|
lights_type: lights_type,
|
|
@@ -527,8 +549,6 @@ class NECB2011 < Standard
|
|
|
527
549
|
oa_scale: oa_scale)
|
|
528
550
|
apply_envelope(model: model,
|
|
529
551
|
construction_opt: construction_opt,
|
|
530
|
-
bldg_category: @activity.category,
|
|
531
|
-
bldg_structure: @structure.structure,
|
|
532
552
|
ext_wall_cond: ext_wall_cond,
|
|
533
553
|
ext_floor_cond: ext_floor_cond,
|
|
534
554
|
ext_roof_cond: ext_roof_cond,
|
|
@@ -550,6 +570,7 @@ class NECB2011 < Standard
|
|
|
550
570
|
srr_set: srr_set,
|
|
551
571
|
srr_opt: srr_opt,
|
|
552
572
|
necb_hdd: necb_hdd)
|
|
573
|
+
set_construction_air_film_resistances(model: model)
|
|
553
574
|
apply_thermal_bridging(model: model,
|
|
554
575
|
necb_hdd: necb_hdd,
|
|
555
576
|
structure: @structure,
|
|
@@ -562,7 +583,7 @@ class NECB2011 < Standard
|
|
|
562
583
|
sizing_run_dir: sizing_run_dir,
|
|
563
584
|
lights_type: lights_type,
|
|
564
585
|
lights_scale: lights_scale)
|
|
565
|
-
apply_kiva_foundation(model
|
|
586
|
+
apply_kiva_foundation(model)
|
|
566
587
|
apply_systems_and_efficiencies(model: model,
|
|
567
588
|
sizing_run_dir: sizing_run_dir,
|
|
568
589
|
hvac_system_primary: hvac_system_primary,
|
|
@@ -600,7 +621,7 @@ class NECB2011 < Standard
|
|
|
600
621
|
end
|
|
601
622
|
|
|
602
623
|
# This method cleans the model of any existing HVAC systems and applies any desired ratation or scaling to the model.
|
|
603
|
-
def clean_and_scale_model(model:, rotation_degrees: nil, scale_x: nil, scale_y: nil, scale_z: nil)
|
|
624
|
+
def clean_and_scale_model(model:, rotation_degrees: nil, scale_x: nil, scale_y: nil, scale_z: nil, footprint_aspect_ratio: nil)
|
|
604
625
|
# clean model..
|
|
605
626
|
BTAP::Resources::Envelope::remove_all_envelope_information(model)
|
|
606
627
|
model = OpenstudioStandards::HVAC.remove_all_hvac(model)
|
|
@@ -624,9 +645,6 @@ class NECB2011 < Standard
|
|
|
624
645
|
model.getSpaces.sort.each { |space| space.designSpecificationOutdoorAir(&:remove) }
|
|
625
646
|
model.getThermostatSetpointDualSetpoints.each(&:remove)
|
|
626
647
|
|
|
627
|
-
scale_x = 1.0
|
|
628
|
-
scale_y = 1.0
|
|
629
|
-
scale_z = 1.0
|
|
630
648
|
# Rotate to model if requested
|
|
631
649
|
rotation_degrees = convert_arg_to_f(variable: rotation_degrees, default: 0.0)
|
|
632
650
|
BTAP::Geometry.rotate_building(model: model, degrees: rotation_degrees) unless rotation_degrees == 0.0
|
|
@@ -635,9 +653,10 @@ class NECB2011 < Standard
|
|
|
635
653
|
scale_x = convert_arg_to_f(variable: scale_x, default: 1.0)
|
|
636
654
|
scale_y = convert_arg_to_f(variable: scale_y, default: 1.0)
|
|
637
655
|
scale_z = convert_arg_to_f(variable: scale_z, default: 1.0)
|
|
638
|
-
|
|
656
|
+
BTAP::Geometry.scale_model(model, scale_x, scale_y, scale_z) if scale_x != 1.0 || scale_y != 1.0 || scale_z != 1.0
|
|
639
657
|
|
|
640
|
-
|
|
658
|
+
footprint_aspect_ratio = convert_arg_to_f(variable: footprint_aspect_ratio, default: nil)
|
|
659
|
+
BTAP::Geometry.set_footprint_aspect_ratio(model, footprint_aspect_ratio) unless footprint_aspect_ratio.nil?
|
|
641
660
|
end
|
|
642
661
|
|
|
643
662
|
def apply_systems_and_efficiencies(model:,
|
|
@@ -812,8 +831,6 @@ class NECB2011 < Standard
|
|
|
812
831
|
|
|
813
832
|
def apply_envelope(model:,
|
|
814
833
|
construction_opt: '',
|
|
815
|
-
bldg_category: '',
|
|
816
|
-
bldg_structure: '',
|
|
817
834
|
ext_wall_cond: nil,
|
|
818
835
|
ext_floor_cond: nil,
|
|
819
836
|
ext_roof_cond: nil,
|
|
@@ -839,30 +856,99 @@ class NECB2011 < Standard
|
|
|
839
856
|
model.getOutsideSurfaceConvectionAlgorithm.setAlgorithm('TARP')
|
|
840
857
|
|
|
841
858
|
construction_opt = '' unless construction_opt.respond_to?(:to_sym)
|
|
842
|
-
bldg_structure = '' unless bldg_structure.respond_to?(:to_sym)
|
|
843
859
|
construction_opt = construction_opt.to_s.downcase
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
argh
|
|
849
|
-
argh[:
|
|
850
|
-
argh[:
|
|
851
|
-
argh[:
|
|
852
|
-
argh[:
|
|
853
|
-
argh[:
|
|
854
|
-
argh[:
|
|
855
|
-
argh[:
|
|
856
|
-
argh[:
|
|
857
|
-
argh[:
|
|
858
|
-
argh[:
|
|
859
|
-
argh[:
|
|
860
|
-
argh[:
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
860
|
+
|
|
861
|
+
if construction_opt == 'structure'
|
|
862
|
+
argh = {}
|
|
863
|
+
argh[:eWallU ] = ext_wall_cond if ext_wall_cond
|
|
864
|
+
argh[:eFloorU ] = ext_floor_cond if ext_floor_cond
|
|
865
|
+
argh[:eRoofU ] = ext_roof_cond if ext_roof_cond
|
|
866
|
+
argh[:gWallU ] = ground_wall_cond if ground_wall_cond
|
|
867
|
+
argh[:gFloorU ] = ground_floor_cond if ground_floor_cond
|
|
868
|
+
argh[:gRoofU ] = ground_roof_cond if ground_roof_cond
|
|
869
|
+
argh[:doorU ] = door_construction_cond if door_construction_cond
|
|
870
|
+
argh[:fenU ] = fixed_window_cond if fixed_window_cond
|
|
871
|
+
argh[:skyU ] = skylight_solar_trans if skylight_solar_trans
|
|
872
|
+
argh[:fenSHGC ] = fixed_wind_solar_trans if fixed_wind_solar_trans
|
|
873
|
+
argh[:skySHGC ] = skylight_solar_trans if skylight_solar_trans
|
|
874
|
+
argh[:category ] = @activity.category
|
|
875
|
+
argh[:structure] = @structure.structure
|
|
876
|
+
argh[:framing ] = @structure.framing
|
|
877
|
+
argh[:cladding ] = @structure.cladding
|
|
878
|
+
argh[:finish ] = @structure.finish
|
|
879
|
+
|
|
880
|
+
# Hard-set (full-height) basement floor constructions.
|
|
881
|
+
set_basement_floor_construction(model)
|
|
882
|
+
|
|
883
|
+
# Add default BUILDING construction sets.
|
|
884
|
+
unless add_construction_sets(model.getSpaces, true, necb_hdd, argh)
|
|
885
|
+
raise('NECB: Failed to assign default BUILDING construction sets')
|
|
886
|
+
end
|
|
887
|
+
|
|
888
|
+
# Add default construction sets to customized spaces. Group spaces along
|
|
889
|
+
# customized STRUCTURE, FRAMING, CLADDING and/or FINISH.
|
|
890
|
+
unless @structure.spaces.empty?
|
|
891
|
+
custom = []
|
|
892
|
+
id = @structure.spaces.keys.first
|
|
893
|
+
sp = @structure.spaces.values.first
|
|
894
|
+
espace = model.getSpaceByName(id)
|
|
895
|
+
|
|
896
|
+
unless espace.empty?
|
|
897
|
+
espace = espace.get
|
|
898
|
+
|
|
899
|
+
first = {}
|
|
900
|
+
first[:spaces ] = [espace]
|
|
901
|
+
first[:structure] = sp[:structure]
|
|
902
|
+
first[:framing ] = sp[:framing]
|
|
903
|
+
first[:cladding ] = sp[:cladding]
|
|
904
|
+
first[:finish ] = sp[:finish]
|
|
905
|
+
custom << first
|
|
906
|
+
|
|
907
|
+
# Group spaces when sharing common attributes.
|
|
908
|
+
@structure.spaces.each do |id, sp|
|
|
909
|
+
space = model.getSpaceByName(id)
|
|
910
|
+
next if space.empty?
|
|
911
|
+
|
|
912
|
+
match = false
|
|
913
|
+
space = space.get
|
|
914
|
+
next if space == espace
|
|
915
|
+
|
|
916
|
+
custom.each do |csp|
|
|
917
|
+
break if match
|
|
918
|
+
|
|
919
|
+
if sp[:structure] == csp[:structure] &&
|
|
920
|
+
sp[:framing ] == csp[:framing ] &&
|
|
921
|
+
sp[:cladding ] == csp[:cladding ] &&
|
|
922
|
+
sp[:finish ] == csp[:finish ]
|
|
923
|
+
|
|
924
|
+
csp[:spaces] << space
|
|
925
|
+
match = true
|
|
926
|
+
end
|
|
927
|
+
end
|
|
928
|
+
|
|
929
|
+
unless match
|
|
930
|
+
spx = {}
|
|
931
|
+
spx[:spaces ] = [space]
|
|
932
|
+
spx[:structure] = sp[:structure]
|
|
933
|
+
spx[:framing ] = sp[:framing]
|
|
934
|
+
spx[:cladding ] = sp[:cladding]
|
|
935
|
+
spx[:finish ] = sp[:finish]
|
|
936
|
+
custom << spx
|
|
937
|
+
end
|
|
938
|
+
end
|
|
939
|
+
|
|
940
|
+
custom.each do |csp|
|
|
941
|
+
argh[:structure] = csp[:structure]
|
|
942
|
+
argh[:framing ] = csp[:framing]
|
|
943
|
+
argh[:cladding ] = csp[:cladding]
|
|
944
|
+
argh[:finish ] = csp[:finish]
|
|
945
|
+
|
|
946
|
+
unless add_construction_sets(csp[:spaces], false, necb_hdd, argh)
|
|
947
|
+
raise('NECB: Failed to assign (custom) SPACE construction sets')
|
|
948
|
+
end
|
|
949
|
+
end
|
|
950
|
+
end
|
|
951
|
+
end
|
|
866
952
|
else
|
|
867
953
|
model_add_constructions(model)
|
|
868
954
|
apply_standard_construction_properties(model: model,
|
|
@@ -886,82 +972,281 @@ class NECB2011 < Standard
|
|
|
886
972
|
model_create_thermal_zones(model, @space_multiplier_map)
|
|
887
973
|
end
|
|
888
974
|
|
|
975
|
+
##
|
|
976
|
+
# Assign surface area-weighted air film resistances (in m2.K/W) to insulated
|
|
977
|
+
# (opaque) layered constructions (as AdditionalProperty "btap_film"), as well
|
|
978
|
+
# as the (net) area of surfaces referencing each construction. The solution
|
|
979
|
+
# initially targets constructions having a valid AdditionalProperty "btap_uo"
|
|
980
|
+
# (auto-generated with option "structure"). If no constructions are tagged
|
|
981
|
+
# with "btap_uo" in the model, the fallback is to instead target all outdoor-
|
|
982
|
+
# facing, above-grade layered constructions. In case of latter scenario,
|
|
983
|
+
# AdditionalProperties "btap_uo", "btap_ut", "btap_id", "btap_type" &
|
|
984
|
+
# "btap_area" are added. All constructions having (or inherting) a "btap_uo"
|
|
985
|
+
# property are adjusted to match the specified Uo (factoring in "btap_film").
|
|
986
|
+
#
|
|
987
|
+
# @author: denis@rd2.ca
|
|
988
|
+
#
|
|
989
|
+
# @param model [OpenStudio::Model::Model] a model
|
|
990
|
+
#
|
|
991
|
+
# @return [Boolean] true if successful
|
|
992
|
+
def set_construction_air_film_resistances(model: nil)
|
|
993
|
+
return false unless model.is_a?(OpenStudio::Model::Model)
|
|
994
|
+
|
|
995
|
+
ok = false
|
|
996
|
+
hdd = get_necb_hdd18(model: model, necb_hdd: true)
|
|
997
|
+
|
|
998
|
+
model.getLayeredConstructions.each do |lc|
|
|
999
|
+
next unless lc.additionalProperties.hasFeature("btap_uo")
|
|
1000
|
+
|
|
1001
|
+
ok = true
|
|
1002
|
+
fR = lc.isFenestration ? 0 : filmR(lc)
|
|
1003
|
+
lc.additionalProperties.setFeature("btap_film", fR)
|
|
1004
|
+
lc.additionalProperties.setFeature("btap_area", lc.getNetArea)
|
|
1005
|
+
end
|
|
1006
|
+
|
|
1007
|
+
# No "btap_uo" AdditionalProperty?
|
|
1008
|
+
model.getSurfaces.each do |surface|
|
|
1009
|
+
break if ok
|
|
1010
|
+
|
|
1011
|
+
tp = surface.surfaceType.downcase
|
|
1012
|
+
bc = surface.outsideBoundaryCondition.downcase
|
|
1013
|
+
next unless bc == "outdoors"
|
|
1014
|
+
|
|
1015
|
+
lc = surface.construction
|
|
1016
|
+
next if lc.empty?
|
|
1017
|
+
|
|
1018
|
+
lc = lc.get.to_LayeredConstruction
|
|
1019
|
+
next if lc.empty?
|
|
1020
|
+
|
|
1021
|
+
lc = lc.get
|
|
1022
|
+
m2 = lc.getNetArea
|
|
1023
|
+
next unless m2 > 0
|
|
1024
|
+
|
|
1025
|
+
uo = max_u_necb(tp, bc, hdd)
|
|
1026
|
+
ty = case tp
|
|
1027
|
+
when "wall" then :walls
|
|
1028
|
+
when "floor" then :floors
|
|
1029
|
+
else :roofs
|
|
1030
|
+
end
|
|
1031
|
+
|
|
1032
|
+
unless lc.additionalProperties.hasFeature("btap_film")
|
|
1033
|
+
lc.additionalProperties.setFeature("btap_film", filmR(lc))
|
|
1034
|
+
end
|
|
1035
|
+
|
|
1036
|
+
unless lc.additionalProperties.hasFeature("btap_area")
|
|
1037
|
+
lc.additionalProperties.setFeature("btap_area", m2)
|
|
1038
|
+
end
|
|
1039
|
+
|
|
1040
|
+
unless lc.additionalProperties.hasFeature("btap_type")
|
|
1041
|
+
lc.additionalProperties.setFeature("btap_type", ty.to_s)
|
|
1042
|
+
end
|
|
1043
|
+
|
|
1044
|
+
unless lc.additionalProperties.hasFeature("btap_uo")
|
|
1045
|
+
lc.additionalProperties.setFeature("btap_uo", uo)
|
|
1046
|
+
end
|
|
1047
|
+
|
|
1048
|
+
unless lc.additionalProperties.hasFeature("btap_ut")
|
|
1049
|
+
lc.additionalProperties.setFeature("btap_ut", uo)
|
|
1050
|
+
end
|
|
1051
|
+
|
|
1052
|
+
unless lc.additionalProperties.hasFeature("btap_id")
|
|
1053
|
+
argh = {}
|
|
1054
|
+
argh[:perform] = :lp
|
|
1055
|
+
argh[:stype ] = ty
|
|
1056
|
+
argh[:uo ] = uo
|
|
1057
|
+
id = BTAP::Bridging.costed_assembly(argh)
|
|
1058
|
+
lc.additionalProperties.setFeature("btap_id", id)
|
|
1059
|
+
end
|
|
1060
|
+
end
|
|
1061
|
+
|
|
1062
|
+
# Isolate building default exterior wall construction.
|
|
1063
|
+
wlc = nil
|
|
1064
|
+
set = model.getBuilding.defaultConstructionSet
|
|
1065
|
+
|
|
1066
|
+
unless set.empty?
|
|
1067
|
+
ext = set.get.defaultExteriorSurfaceConstructions
|
|
1068
|
+
|
|
1069
|
+
unless ext.empty?
|
|
1070
|
+
wlc = ext.get.wallConstruction
|
|
1071
|
+
wlc = wlc.empty? ? nil : wlc.get
|
|
1072
|
+
end
|
|
1073
|
+
end
|
|
1074
|
+
|
|
1075
|
+
# Adjust tagged insulated constructions.
|
|
1076
|
+
model.getLayeredConstructions.each do |lc|
|
|
1077
|
+
id = lc.additionalProperties.getFeatureAsString("btap_id")
|
|
1078
|
+
uo = lc.additionalProperties.getFeatureAsDouble("btap_uo")
|
|
1079
|
+
ut = lc.additionalProperties.getFeatureAsDouble("btap_ut")
|
|
1080
|
+
fr = lc.additionalProperties.getFeatureAsDouble("btap_film")
|
|
1081
|
+
ty = lc.additionalProperties.getFeatureAsString("btap_type")
|
|
1082
|
+
m2 = lc.additionalProperties.getFeatureAsString("btap_area")
|
|
1083
|
+
next if id.empty?
|
|
1084
|
+
next if uo.empty?
|
|
1085
|
+
next if ut.empty?
|
|
1086
|
+
next if fr.empty?
|
|
1087
|
+
next if ty.empty?
|
|
1088
|
+
next if m2.empty?
|
|
1089
|
+
next if lc.isFenestration
|
|
1090
|
+
|
|
1091
|
+
id = id.get
|
|
1092
|
+
uo = uo.get
|
|
1093
|
+
ut = ut.get
|
|
1094
|
+
fr = fr.get
|
|
1095
|
+
ty = ty.get
|
|
1096
|
+
m2 = m2.get
|
|
1097
|
+
il = TBD.insulatingLayer(lc)
|
|
1098
|
+
next if id.downcase.chr == "g"
|
|
1099
|
+
next unless il[:index]
|
|
1100
|
+
|
|
1101
|
+
TBD.resetUo(lc, fr, il[:index], uo)
|
|
1102
|
+
|
|
1103
|
+
# Add default exterior wall construction tags to building.
|
|
1104
|
+
if lc == wlc
|
|
1105
|
+
next unless ty == "walls"
|
|
1106
|
+
|
|
1107
|
+
model.getBuilding.additionalProperties.setFeature("btap_id", id)
|
|
1108
|
+
model.getBuilding.additionalProperties.setFeature("btap_uo", uo)
|
|
1109
|
+
model.getBuilding.additionalProperties.setFeature("btap_ut", uo)
|
|
1110
|
+
model.getBuilding.additionalProperties.setFeature("btap_film", fr)
|
|
1111
|
+
model.getBuilding.additionalProperties.setFeature("btap_type", ty)
|
|
1112
|
+
model.getBuilding.additionalProperties.setFeature("btap_area", m2)
|
|
1113
|
+
end
|
|
1114
|
+
end
|
|
1115
|
+
|
|
1116
|
+
true
|
|
1117
|
+
end
|
|
1118
|
+
|
|
1119
|
+
##
|
|
889
1120
|
# Apply Kiva foundation model to floors/walls with ground boundary condition.
|
|
890
|
-
# created by: Kamel Haddad (kamel.haddad@nrcan-rncan.gc.ca)
|
|
891
|
-
# 'massive' edit: denis@rd2.ca
|
|
892
1121
|
#
|
|
893
|
-
# @
|
|
894
|
-
|
|
895
|
-
|
|
1122
|
+
# @author kamel.haddad@nrcan-rncan.gc.ca
|
|
1123
|
+
# @author denis@rd2.ca
|
|
1124
|
+
#
|
|
1125
|
+
# @param model [OpenStudio::Model::Model] a model
|
|
1126
|
+
#
|
|
1127
|
+
# @return [Float] slab-on-grade perimeter area (0 if not applicable)
|
|
1128
|
+
def apply_kiva_foundation(model)
|
|
1129
|
+
hdd = get_necb_hdd18(model: model, necb_hdd: true)
|
|
1130
|
+
slb = false
|
|
1131
|
+
|
|
896
1132
|
bldg_kiva_model = OpenStudio::Model::FoundationKiva.new(model)
|
|
897
1133
|
bldg_kiva_model.setName("Bldg Kiva Foundation")
|
|
898
1134
|
bldg_kiva_model.setWallHeightAboveGrade(0.0)
|
|
899
1135
|
bldg_kiva_model.setWallDepthBelowSlab(0.0)
|
|
1136
|
+
|
|
900
1137
|
model.getThermalZones.sort.each do |zone|
|
|
901
1138
|
zone_kiva_models = [bldg_kiva_model]
|
|
902
1139
|
zone_grd_flr_counter = 0
|
|
1140
|
+
|
|
903
1141
|
zone.spaces.sort.each do |space|
|
|
904
|
-
#
|
|
1142
|
+
# Store space floors and walls in contact with ground and exterior walls.
|
|
905
1143
|
space_ground_floors = []
|
|
906
1144
|
space_ground_walls = []
|
|
907
1145
|
space_ext_walls = []
|
|
908
1146
|
space_ground_floors += space.surfaces.select {|surf| surf.surfaceType.downcase == 'floor' && surf.isGroundSurface }
|
|
909
1147
|
space_ground_walls += space.surfaces.select {|surf| surf.surfaceType.downcase == 'wall' && surf.isGroundSurface }
|
|
910
1148
|
space_ext_walls += space.surfaces.select {|surf| surf.surfaceType.downcase == 'wall' && surf.outsideBoundaryCondition.downcase == 'outdoors'}
|
|
911
|
-
|
|
1149
|
+
|
|
1150
|
+
# Slab-on-grade (not basement) if no ground-facing walls. Add perimeter
|
|
1151
|
+
# insulation to building KIVA foundation.
|
|
1152
|
+
unless space_ground_floors.empty?
|
|
1153
|
+
if space_ground_walls.empty?
|
|
1154
|
+
if hdd < 7000
|
|
1155
|
+
xps38 = model.getStandardOpaqueMaterialByName("XPS 38mm")
|
|
1156
|
+
|
|
1157
|
+
if xps38.empty?
|
|
1158
|
+
xps38 = OpenStudio::Model::StandardOpaqueMaterial.new(model)
|
|
1159
|
+
xps38.setName("XPS 38mm")
|
|
1160
|
+
xps38.setRoughness("Smooth")
|
|
1161
|
+
xps38.setThickness(0.038)
|
|
1162
|
+
xps38.setConductivity(0.029)
|
|
1163
|
+
xps38.setDensity(28)
|
|
1164
|
+
xps38.setSpecificHeat(1450)
|
|
1165
|
+
else
|
|
1166
|
+
xps38 = xps38.get
|
|
1167
|
+
end
|
|
1168
|
+
|
|
1169
|
+
zone_kiva_models.last.setInteriorHorizontalInsulationMaterial(xps38)
|
|
1170
|
+
zone_kiva_models.last.setInteriorHorizontalInsulationWidth(1.2)
|
|
1171
|
+
|
|
1172
|
+
slb = true
|
|
1173
|
+
end
|
|
1174
|
+
end
|
|
1175
|
+
end
|
|
1176
|
+
|
|
1177
|
+
# Loop through space floors in contact with ground and assign a Kiva
|
|
1178
|
+
# model for each.
|
|
912
1179
|
space_ground_floors.each do |gfloor|
|
|
913
1180
|
zone_grd_flr_counter += 1
|
|
1181
|
+
|
|
1182
|
+
# A new Kiva model is needed for each additional floor in contact with
|
|
1183
|
+
# the ground in the zone.
|
|
914
1184
|
if zone_grd_flr_counter > 1
|
|
915
|
-
# a new Kiva model is needed for each additional floor in contact with the ground in the zone
|
|
916
1185
|
kiva_model = OpenStudio::Model::FoundationKiva.new(model)
|
|
917
1186
|
kiva_model.setName("#{gfloor.name.to_s} Kiva Foundation")
|
|
918
1187
|
kiva_model.setWallHeightAboveGrade(0.0)
|
|
919
1188
|
kiva_model.setWallDepthBelowSlab(0.0)
|
|
1189
|
+
|
|
1190
|
+
# Slab-on-grade (not basement) if no ground-facing walls. Add
|
|
1191
|
+
# perimeter insulation to building KIVA foundation.
|
|
1192
|
+
if space_ground_walls.empty?
|
|
1193
|
+
if hdd < 7000
|
|
1194
|
+
xps38 = model.getStandardOpaqueMaterialByName("XPS 38mm")
|
|
1195
|
+
|
|
1196
|
+
if xps38.empty?
|
|
1197
|
+
xps38 = OpenStudio::Model::StandardOpaqueMaterial.new(model)
|
|
1198
|
+
xps38.setName("XPS 38mm")
|
|
1199
|
+
xps38.setRoughness("Smooth")
|
|
1200
|
+
xps38.setThickness(0.038)
|
|
1201
|
+
xps38.setConductivity(0.029)
|
|
1202
|
+
xps38.setDensity(28)
|
|
1203
|
+
xps38.setSpecificHeat(1450)
|
|
1204
|
+
else
|
|
1205
|
+
xps38 = xps38.get
|
|
1206
|
+
end
|
|
1207
|
+
|
|
1208
|
+
kiva_model.setInteriorHorizontalInsulationMaterial(xps38)
|
|
1209
|
+
kiva_model.setInteriorHorizontalInsulationWidth(1.2)
|
|
1210
|
+
|
|
1211
|
+
slb = true
|
|
1212
|
+
end
|
|
1213
|
+
end
|
|
1214
|
+
|
|
920
1215
|
zone_kiva_models << kiva_model
|
|
921
1216
|
end
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
c = gfloor.construction.get.to_LayeredConstruction.get
|
|
928
|
-
gfloor.setOutsideBoundaryCondition('Foundation')
|
|
929
|
-
gfloor.setAdjacentFoundation(zone_kiva_models.last)
|
|
930
|
-
gfloor.setConstruction(c)
|
|
931
|
-
else
|
|
932
|
-
replace_massless_material_with_std_material(model,gfloor)
|
|
933
|
-
gfloor.setOutsideBoundaryCondition('Foundation')
|
|
934
|
-
gfloor.setAdjacentFoundation(zone_kiva_models.last)
|
|
935
|
-
end
|
|
1217
|
+
|
|
1218
|
+
c = gfloor.construction.get.to_LayeredConstruction.get
|
|
1219
|
+
gfloor.setOutsideBoundaryCondition('Foundation')
|
|
1220
|
+
gfloor.setAdjacentFoundation(zone_kiva_models.last)
|
|
1221
|
+
gfloor.setConstruction(c)
|
|
936
1222
|
|
|
937
1223
|
# Set the exposed perimeter for space floors in contact with the ground.
|
|
938
1224
|
floor_exp_per = 0.0
|
|
1225
|
+
|
|
939
1226
|
if !space_ground_walls.empty?
|
|
940
|
-
floor_exp_per += get_surface_exp_per(gfloor,space_ground_walls)
|
|
1227
|
+
floor_exp_per += get_surface_exp_per(gfloor, space_ground_walls)
|
|
941
1228
|
elsif !space_ext_walls.empty?
|
|
942
|
-
floor_exp_per += get_surface_exp_per(gfloor,space_ext_walls)
|
|
1229
|
+
floor_exp_per += get_surface_exp_per(gfloor, space_ext_walls)
|
|
943
1230
|
end
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
1231
|
+
|
|
1232
|
+
gfloor.createSurfacePropertyExposedFoundationPerimeter('TotalExposedPerimeter', floor_exp_per)
|
|
1233
|
+
|
|
1234
|
+
# Specify a foundation boundary condition for space walls in contact
|
|
1235
|
+
# with the ground and in contact with the space floor in contact with
|
|
1236
|
+
# ground 'gfloor'.
|
|
947
1237
|
space_ground_walls.each do |gwall|
|
|
948
|
-
if surfaces_are_in_contact?(gfloor,gwall)
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
gwall.setConstruction(c)
|
|
954
|
-
else
|
|
955
|
-
replace_massless_material_with_std_material(model,gwall)
|
|
956
|
-
gwall.setOutsideBoundaryCondition('Foundation')
|
|
957
|
-
gwall.setAdjacentFoundation(zone_kiva_models.last)
|
|
958
|
-
end
|
|
1238
|
+
if surfaces_are_in_contact?(gfloor, gwall)
|
|
1239
|
+
c = gwall.construction.get.to_LayeredConstruction.get
|
|
1240
|
+
gwall.setOutsideBoundaryCondition('Foundation')
|
|
1241
|
+
gwall.setAdjacentFoundation(zone_kiva_models.last)
|
|
1242
|
+
gwall.setConstruction(c)
|
|
959
1243
|
end
|
|
960
1244
|
end
|
|
961
1245
|
end
|
|
962
1246
|
end
|
|
963
1247
|
end
|
|
964
|
-
|
|
1248
|
+
|
|
1249
|
+
slb == true ? BTAP::Geometry::Spaces.perimeter_m2(model.getSpaces, 1.2) : 0
|
|
965
1250
|
end
|
|
966
1251
|
|
|
967
1252
|
# check if two surfaces are in contact. For every two consecutive vertices on surface 1,
|
|
@@ -1012,7 +1297,7 @@ class NECB2011 < Standard
|
|
|
1012
1297
|
# with the name: 'Insulation: Expanded polystyrene - extruded (smooth skin surface) (HCFC-142b exp.)'.
|
|
1013
1298
|
# The thickness of the new material is based on the thermal resistance of the massless material it replaces.
|
|
1014
1299
|
# created by: Kamel Haddad (kamel.haddad@nrcan-rncan.gc.ca)
|
|
1015
|
-
def replace_massless_material_with_std_material(model,surf)
|
|
1300
|
+
def replace_massless_material_with_std_material(model, surf)
|
|
1016
1301
|
std_const_name = "#{surf.construction.get.name.to_s}_std"
|
|
1017
1302
|
std_const = model.getLayeredConstructions.select {|const| const.name.to_s == std_const_name}
|
|
1018
1303
|
new_const = nil
|
|
@@ -1150,10 +1435,11 @@ class NECB2011 < Standard
|
|
|
1150
1435
|
# Initiates a BTAP building ACTIVITY.
|
|
1151
1436
|
#
|
|
1152
1437
|
# @param model [OpenStudio::Model::Model] a model
|
|
1438
|
+
# @param option ["", "structure"] construction option
|
|
1153
1439
|
#
|
|
1154
1440
|
# @return [BTAP::Activity] a BTAP building ACTIVITY (see logs if failed)
|
|
1155
|
-
def assign_building_activity(model: nil)
|
|
1156
|
-
@activity = BTAP::Activity.new(model)
|
|
1441
|
+
def assign_building_activity(model: nil, option: "")
|
|
1442
|
+
@activity = BTAP::Activity.new(model, option)
|
|
1157
1443
|
end
|
|
1158
1444
|
|
|
1159
1445
|
# Initiates a BTAP building STRUCTURE.
|
|
@@ -1169,7 +1455,7 @@ class NECB2011 < Standard
|
|
|
1169
1455
|
|
|
1170
1456
|
##
|
|
1171
1457
|
# (Optionally) uprates - then derates - envelope surface constructions due to
|
|
1172
|
-
#
|
|
1458
|
+
# linear thermal bridges (e.g. roof parapets, corners, fenestration
|
|
1173
1459
|
# perimeters). See lib/openstudio-standards/btap/bridging.rb, which relies on
|
|
1174
1460
|
# the Thermal Bridging & Derating (TBD) gem.
|
|
1175
1461
|
#
|
|
@@ -1186,14 +1472,14 @@ class NECB2011 < Standard
|
|
|
1186
1472
|
def apply_thermal_bridging(model: nil,
|
|
1187
1473
|
necb_hdd: true,
|
|
1188
1474
|
structure: nil,
|
|
1189
|
-
option:
|
|
1475
|
+
option: "none",
|
|
1190
1476
|
interpolate: false,
|
|
1191
1477
|
wallU: nil,
|
|
1192
1478
|
floorU: nil,
|
|
1193
1479
|
roofU: nil)
|
|
1194
1480
|
necb_hdd = true unless [true, false].include?(necb_hdd)
|
|
1195
1481
|
return true unless option.respond_to?(:to_sym)
|
|
1196
|
-
return true if option.to_s.downcase ==
|
|
1482
|
+
return true if option.to_s.downcase == "none"
|
|
1197
1483
|
|
|
1198
1484
|
hdd = get_necb_hdd18(model: model, necb_hdd: necb_hdd)
|
|
1199
1485
|
wallU = wallU ? wallU : max_u_necb("wall", "outdoors", hdd)
|
|
@@ -1206,19 +1492,19 @@ class NECB2011 < Standard
|
|
|
1206
1492
|
argh[:floors ] = { uo: floorU }
|
|
1207
1493
|
argh[:roofs ] = { uo: roofU }
|
|
1208
1494
|
|
|
1209
|
-
case option.downcase
|
|
1210
|
-
when
|
|
1211
|
-
argh[:walls
|
|
1212
|
-
argh[:floors
|
|
1213
|
-
argh[:roofs
|
|
1214
|
-
when
|
|
1495
|
+
case option.to_s.downcase
|
|
1496
|
+
when "uprate"
|
|
1497
|
+
argh[:walls ][:ut] = wallU
|
|
1498
|
+
argh[:floors][:ut] = floorU
|
|
1499
|
+
argh[:roofs ][:ut] = roofU
|
|
1500
|
+
when "good"
|
|
1215
1501
|
argh[:quality] = :good
|
|
1216
1502
|
else
|
|
1217
1503
|
argh[:quality] = :bad
|
|
1218
1504
|
end
|
|
1219
1505
|
|
|
1220
1506
|
argh[:interpolate] = interpolate
|
|
1221
|
-
argh[:interpolate] = false unless [true
|
|
1507
|
+
argh[:interpolate] = false unless argh[:interpolate] == true
|
|
1222
1508
|
|
|
1223
1509
|
@tbd = BTAP::Bridging.new(model, argh)
|
|
1224
1510
|
|
|
@@ -1317,10 +1603,8 @@ class NECB2011 < Standard
|
|
|
1317
1603
|
end
|
|
1318
1604
|
|
|
1319
1605
|
def apply_loop_pump_power(model:, sizing_run_dir:)
|
|
1320
|
-
#
|
|
1321
|
-
#
|
|
1322
|
-
# First time it ran in the super() within model_apply_standard() method
|
|
1323
|
-
# model = return BTAP::FileIO::remove_duplicate_materials_and_constructions(model)
|
|
1606
|
+
# Note For NECB2015 This is the 2nd time this method is being run.
|
|
1607
|
+
# First time it ran in the super() within model_apply_standard() method.
|
|
1324
1608
|
return model
|
|
1325
1609
|
end
|
|
1326
1610
|
|
|
@@ -1736,15 +2020,41 @@ class NECB2011 < Standard
|
|
|
1736
2020
|
end
|
|
1737
2021
|
end
|
|
1738
2022
|
|
|
1739
|
-
|
|
2023
|
+
# Match both the NECB2011 name ('Office - enclosed') and the NECB2015+/
|
|
2024
|
+
# NECB2020 names ('Office enclosed <= 25 m2' / 'Office enclosed > 25 m2');
|
|
2025
|
+
# the exact-2011-string comparison meant the >= 25 m2 office exemption
|
|
2026
|
+
# NEVER fired on 2015+ models.
|
|
2027
|
+
if daylight_space.spaceType.get.standardsSpaceType.get.to_s =~ /office\s*-?\s*enclosed/i && daylight_space_area >= 25.0
|
|
1740
2028
|
offices_larger_25m2 << daylight_space.name.to_s
|
|
1741
2029
|
end
|
|
1742
2030
|
end
|
|
1743
2031
|
|
|
1744
2032
|
##### find daylight_spaces which do not need daylight sensor controls based on the primary_sidelighted_area as per NECB2011: 4.2.2.8.
|
|
1745
2033
|
##### Note: Office spaces >= 25m2 are excluded (i.e. they should have daylighting controls even if their primary_sidelighted_area <= 100m2), as per NECB2011: 4.2.2.2.
|
|
2034
|
+
# The exception criteria for sidelighting (4.2.2.8/4.2.2.10) only apply to
|
|
2035
|
+
# spaces WITH exterior windows, and the skylight criteria (4.2.2.4/4.2.2.7)
|
|
2036
|
+
# only to spaces WITH skylights. Previously every criterion was applied to
|
|
2037
|
+
# every space, so a window-only space was ALWAYS excepted (its skylight
|
|
2038
|
+
# area is 0 <= 400 m2) and a skylight-only space likewise — with the
|
|
2039
|
+
# practical result that almost no space ever received a daylighting sensor.
|
|
2040
|
+
spaces_with_windows = []
|
|
2041
|
+
spaces_with_skylights = []
|
|
2042
|
+
daylight_spaces.sort.each do |daylight_space|
|
|
2043
|
+
daylight_space.surfaces.sort.each do |surface|
|
|
2044
|
+
surface.subSurfaces.sort.each do |subsurface|
|
|
2045
|
+
next unless subsurface.outsideBoundaryCondition == 'Outdoors'
|
|
2046
|
+
|
|
2047
|
+
if subsurface.subSurfaceType == 'FixedWindow' || subsurface.subSurfaceType == 'OperableWindow'
|
|
2048
|
+
spaces_with_windows << daylight_space.name.to_s
|
|
2049
|
+
elsif subsurface.subSurfaceType == 'Skylight'
|
|
2050
|
+
spaces_with_skylights << daylight_space.name.to_s
|
|
2051
|
+
end
|
|
2052
|
+
end
|
|
2053
|
+
end
|
|
2054
|
+
end
|
|
1746
2055
|
daylight_spaces_exception = []
|
|
1747
2056
|
primary_sidelighted_area_hash.sort.each do |key_daylight_space_name, value_primary_sidelighted_area|
|
|
2057
|
+
next unless spaces_with_windows.include?(key_daylight_space_name)
|
|
1748
2058
|
if value_primary_sidelighted_area <= 100.0 && [key_daylight_space_name].any? { |word| offices_larger_25m2.include?(word) } == false
|
|
1749
2059
|
daylight_spaces_exception << key_daylight_space_name
|
|
1750
2060
|
end
|
|
@@ -1753,6 +2063,7 @@ class NECB2011 < Standard
|
|
|
1753
2063
|
##### find daylight_spaces which do not need daylight sensor controls based on the sidelighting_effective_aperture as per NECB2011: 4.2.2.8.
|
|
1754
2064
|
##### Note: Office spaces >= 25m2 are excluded (i.e. they should have daylighting controls even if their sidelighting_effective_aperture <= 10%), as per NECB2011: 4.2.2.2.
|
|
1755
2065
|
sidelighting_effective_aperture_hash.sort.each do |key_daylight_space_name, value_sidelighting_effective_aperture|
|
|
2066
|
+
next unless spaces_with_windows.include?(key_daylight_space_name)
|
|
1756
2067
|
if value_sidelighting_effective_aperture <= 0.1 && [key_daylight_space_name].any? { |word| offices_larger_25m2.include?(word) } == false
|
|
1757
2068
|
daylight_spaces_exception << key_daylight_space_name
|
|
1758
2069
|
end
|
|
@@ -1761,6 +2072,7 @@ class NECB2011 < Standard
|
|
|
1761
2072
|
##### find daylight_spaces which do not need daylight sensor controls based on the daylighted_area_under_skylights as per NECB2011: 4.2.2.4.
|
|
1762
2073
|
##### Note: Office spaces >= 25m2 are excluded (i.e. they should have daylighting controls even if their daylighted_area_under_skylights <= 400m2), as per NECB2011: 4.2.2.2.
|
|
1763
2074
|
daylighted_area_under_skylights_hash.sort.each do |key_daylight_space_name, value_daylighted_area_under_skylights|
|
|
2075
|
+
next unless spaces_with_skylights.include?(key_daylight_space_name)
|
|
1764
2076
|
if value_daylighted_area_under_skylights <= 400.0 && [key_daylight_space_name].any? { |word| offices_larger_25m2.include?(word) } == false
|
|
1765
2077
|
daylight_spaces_exception << key_daylight_space_name
|
|
1766
2078
|
end
|
|
@@ -1769,6 +2081,7 @@ class NECB2011 < Standard
|
|
|
1769
2081
|
##### find daylight_spaces which do not need daylight sensor controls based on the skylight_effective_aperture criterion as per NECB2011: 4.2.2.4.
|
|
1770
2082
|
##### Note: Office spaces >= 25m2 are excluded (i.e. they should have daylighting controls even if their skylight_effective_aperture <= 0.6%), as per NECB2011: 4.2.2.2.
|
|
1771
2083
|
skylight_effective_aperture_hash.sort.each do |key_daylight_space_name, value_skylight_effective_aperture|
|
|
2084
|
+
next unless spaces_with_skylights.include?(key_daylight_space_name)
|
|
1772
2085
|
if value_skylight_effective_aperture <= 0.006 && [key_daylight_space_name].any? { |word| offices_larger_25m2.include?(word) } == false
|
|
1773
2086
|
daylight_spaces_exception << key_daylight_space_name
|
|
1774
2087
|
end
|
|
@@ -2146,7 +2459,7 @@ class NECB2011 < Standard
|
|
|
2146
2459
|
# Interate through all spaces in model.. not just ones that have space type defined.. Is this right sara?
|
|
2147
2460
|
space_type.spaces.sort.each do |space|
|
|
2148
2461
|
# Get only the wall type surfaces and iterate throught them.
|
|
2149
|
-
space.surfaces.sort.select
|
|
2462
|
+
space.surfaces.sort.select { |surface| surface.surfaceType == 'Wall' }.each do |wall_surface|
|
|
2150
2463
|
# Find the vertex with the max z value.
|
|
2151
2464
|
vertex_with_max_height = wall_surface.vertices.max_by(&:z)
|
|
2152
2465
|
# replace max if this surface has something bigger.
|
|
@@ -2393,7 +2706,6 @@ class NECB2011 < Standard
|
|
|
2393
2706
|
# if skylight_vertex_0_distance == skylight_vertex_1_distance
|
|
2394
2707
|
end
|
|
2395
2708
|
|
|
2396
|
-
daylighted_under_skylight_area += daylighted_under_skylight_length * daylighted_under_skylight_width
|
|
2397
2709
|
# if subsurface.subSurfaceType == "FixedWindow" || subsurface.subSurfaceType == "OperableWindow"
|
|
2398
2710
|
end
|
|
2399
2711
|
# surface.subSurfaces.each do |subsurface|
|
|
@@ -2402,6 +2714,11 @@ class NECB2011 < Standard
|
|
|
2402
2714
|
end
|
|
2403
2715
|
# daylight_space.surfaces.each do |surface|
|
|
2404
2716
|
end
|
|
2717
|
+
# Accumulate ONCE per skylight. Previously the accumulation sat inside
|
|
2718
|
+
# the exterior-window loop above, so (a) spaces with skylights but no
|
|
2719
|
+
# exterior windows always computed ZERO daylighted area, and (b) each
|
|
2720
|
+
# additional exterior window double-counted the whole area.
|
|
2721
|
+
daylighted_under_skylight_area += daylighted_under_skylight_length * daylighted_under_skylight_width
|
|
2405
2722
|
# if subsurface.subSurfaceType == "Skylight"
|
|
2406
2723
|
end
|
|
2407
2724
|
# surface.subSurfaces.each do |subsurface|
|
|
@@ -2812,45 +3129,140 @@ class NECB2011 < Standard
|
|
|
2812
3129
|
# Arguments:
|
|
2813
3130
|
# model (OpenStudio::Model::Model): The model to run the sizing run on.
|
|
2814
3131
|
# sizing_run_dir (String): The directory where the sizing run files will be saved.
|
|
2815
|
-
def try_sizing_run(model:, sizing_run_dir:, sizing_run_subdir:)
|
|
3132
|
+
def try_sizing_run(model:, sizing_run_dir:, sizing_run_subdir:, retry: 0)
|
|
2816
3133
|
raise('validation of model failed.') unless validate_initial_model(model)
|
|
2817
3134
|
|
|
2818
3135
|
# Do a sizing run to determine the system capacities. If a sizing run fails, hard size any failing DX heating coils
|
|
2819
3136
|
# to 1.0 kW and rerun the sizing run until it succeeds. If no DX heating coils are found, or none had a small
|
|
2820
3137
|
# capacity then raise an error.
|
|
3138
|
+
dx_coil_changed = false
|
|
3139
|
+
num_changes = 0
|
|
2821
3140
|
loop do
|
|
2822
3141
|
sizing_run_success = model_run_sizing_run(model, "#{sizing_run_dir}/#{sizing_run_subdir}", true)
|
|
2823
3142
|
break if sizing_run_success
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
3143
|
+
num_changes += 1
|
|
3144
|
+
|
|
3145
|
+
# Report severe or fatal errors in the run
|
|
3146
|
+
error_query = "SELECT ErrorMessage
|
|
3147
|
+
FROM Errors
|
|
3148
|
+
WHERE ErrorType in(1,2)"
|
|
3149
|
+
errs = model.sqlFile.get.execAndReturnVectorOfString(error_query)
|
|
3150
|
+
if errs.is_initialized
|
|
3151
|
+
errs = errs.get
|
|
3152
|
+
end
|
|
3153
|
+
# Get error and get any DX coils with issues
|
|
3154
|
+
|
|
3155
|
+
issue_coils = []
|
|
3156
|
+
errs.each do |err|
|
|
3157
|
+
# Find any DX heating coil names that are in the error message
|
|
3158
|
+
error_heating_coils = model.getCoilHeatingDXSingleSpeeds.select { |coil| err.to_s.downcase.include?(coil.name.to_s.downcase) }
|
|
3159
|
+
# If more the DX heating coil name appears more than one time in the error message, only select the one without a number at the end of the name.
|
|
3160
|
+
if error_heating_coils.length > 1
|
|
3161
|
+
error_heating_coils.each do |coil|
|
|
3162
|
+
if coil.name.to_s.downcase.match(/\d/)
|
|
3163
|
+
# Skip coils if there is another number in the error message after the name of the coil (e.g. coilheatingdx 1 appears but so does coilheatingdx 10 or coilheatingdx 13).
|
|
3164
|
+
error_index = err.to_s.downcase.index(coil.name.to_s.downcase) + coil.name.to_s.length
|
|
3165
|
+
next if err.to_s[error_index].match(/\d/)
|
|
3166
|
+
heating_coil_element = {}
|
|
3167
|
+
heating_coil_element[:heating_coil] = coil
|
|
3168
|
+
heating_coil_element[:is_autosized] = true if coil.isRatedTotalHeatingCapacityAutosized
|
|
3169
|
+
heating_coil_element[:is_autosized] = false unless coil.isRatedTotalHeatingCapacityAutosized
|
|
3170
|
+
heating_coil_element[:capacity] = coil.ratedTotalHeatingCapacity.to_f
|
|
3171
|
+
issue_coils << heating_coil_element
|
|
3172
|
+
end
|
|
3173
|
+
end
|
|
3174
|
+
elsif error_heating_coils.length == 1
|
|
3175
|
+
heating_coil_element = {}
|
|
3176
|
+
heating_coil_element[:heating_coil] = error_heating_coils[0]
|
|
3177
|
+
heating_coil_element[:is_autosized] = true if error_heating_coils[0].isRatedTotalHeatingCapacityAutosized
|
|
3178
|
+
heating_coil_element[:is_autosized] = false unless error_heating_coils[0].isRatedTotalHeatingCapacityAutosized
|
|
3179
|
+
heating_coil_element[:capacity] = error_heating_coils[0].ratedTotalHeatingCapacity.to_f
|
|
3180
|
+
issue_coils << heating_coil_element
|
|
3181
|
+
end
|
|
3182
|
+
# Find any DX cooling coil names that are in the error message
|
|
3183
|
+
error_cooling_coils = model.getCoilCoolingDXSingleSpeeds.select { |coil| err.to_s.downcase.include?(coil.name.to_s.downcase) }
|
|
3184
|
+
# If more the DX cooling coil name appears more than one time in the error message, only select the one without a number at the end of the name.
|
|
3185
|
+
if error_cooling_coils.length > 1
|
|
3186
|
+
error_cooling_coils.each do |coil|
|
|
3187
|
+
if coil.name.to_s.downcase.match(/\d/)
|
|
3188
|
+
# Skip coils if there is another number in the error message after the name of the coil (e.g. coilcoolingdx 1 appears but so does coilcoolingdx 10 or coilcoolingdx 13).
|
|
3189
|
+
error_index = err.to_s.downcase.index(coil.name.to_s.downcase) + coil.name.to_s.downcase.length
|
|
3190
|
+
next if err.to_s[error_index].match(/\d/)
|
|
3191
|
+
cooling_coil_element = {}
|
|
3192
|
+
cooling_coil_element[:cooling_coil] = coil
|
|
3193
|
+
cooling_coil_element[:is_autosized] = true if coil.isRatedTotalCoolingCapacityAutosized
|
|
3194
|
+
cooling_coil_element[:is_autosized] = false unless coil.isRatedTotalCoolingCapacityAutosized
|
|
3195
|
+
cooling_coil_element[:capacity] = coil.ratedTotalCoolingCapacity.to_f
|
|
3196
|
+
issue_coils << cooling_coil_element
|
|
3197
|
+
end
|
|
3198
|
+
end
|
|
3199
|
+
elsif error_cooling_coils.length == 1
|
|
3200
|
+
cooling_coil_element = {}
|
|
3201
|
+
cooling_coil_element[:cooling_coil] = error_cooling_coils[0]
|
|
3202
|
+
cooling_coil_element[:is_autosized] = true if error_cooling_coils[0].isRatedTotalCoolingCapacityAutosized
|
|
3203
|
+
cooling_coil_element[:is_autosized] = false unless error_cooling_coils[0].isRatedTotalCoolingCapacityAutosized
|
|
3204
|
+
cooling_coil_element[:capacity] = error_cooling_coils[0].ratedTotalCoolingCapacity.to_f
|
|
3205
|
+
issue_coils << cooling_coil_element
|
|
2835
3206
|
end
|
|
2836
3207
|
end
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
3208
|
+
issue_coils.uniq!
|
|
3209
|
+
|
|
3210
|
+
# Adjust the capacity of DX coils with issues. This resolves most sizing run issues.
|
|
3211
|
+
issue_coils.each do |issue_coil|
|
|
3212
|
+
# If the coil is autosized and has a capacity less than 1.0 kW, resize the coil (and similar coils) to 1.0 kW
|
|
3213
|
+
if issue_coil[:is_autosized] == true && issue_coil[:capacity].to_f < 1.0
|
|
3214
|
+
if issue_coil.key?(:heating_coil)
|
|
3215
|
+
resize_coils = model.getCoilHeatingDXSingleSpeeds.select { |coil| coil.isRatedTotalHeatingCapacityAutosized && coil.ratedTotalHeatingCapacity.to_f < 1.0 }
|
|
3216
|
+
resize_coils.each do |coil|
|
|
3217
|
+
coil.setRatedTotalHeatingCapacity(1.0)
|
|
3218
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "DX Heating Coil #{coil.name.to_s} has a rated capacity less than 1.0 kW and has been resized to 1.0 kW to avoid sizing run failure.")
|
|
3219
|
+
puts "DX Heating Coil #{coil.name.to_s} has a rated capacity less than 1.0 kW and has been resized to 1.0 kW to avoid sizing run failure."
|
|
3220
|
+
dx_coil_changed = true
|
|
3221
|
+
end
|
|
3222
|
+
elsif issue_coil.key?(:cooling_coil)
|
|
3223
|
+
resize_coils = model.getCoilCoolingDXSingleSpeeds.select { |coil| coil.isRatedTotalCoolingCapacityAutosized && coil.ratedTotalCoolingCapacity.to_f < 1.0 }
|
|
3224
|
+
resize_coils.each do |coil|
|
|
3225
|
+
coil.setRatedTotalCoolingCapacity(1.0)
|
|
3226
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "DX Cooling Coil #{coil.name.to_s} has a rated capacity less than 1.0 kW and has been resized to 1.0 kW to avoid sizing run failure.")
|
|
3227
|
+
puts "DX Cooling Coil #{coil.name.to_s} has a rated capacity less than 1.0 kW and has been resized to 1.0 kW to avoid sizing run failure."
|
|
3228
|
+
dx_coil_changed = true
|
|
3229
|
+
end
|
|
3230
|
+
end
|
|
3231
|
+
# If the coil is not autosized, or has a capacity larger than 1 kW, increase the capacity by 1% to avoid sizing run issues with rounding
|
|
3232
|
+
else
|
|
3233
|
+
if issue_coil.key?(:heating_coil)
|
|
3234
|
+
cooling_coil_name = issue_coil[:heating_coil].name.to_s.gsub('CoilHeatingDX','CoilCoolingDX')
|
|
3235
|
+
cooling_coil = model.getCoilCoolingDXSingleSpeeds.select { |coil| cooling_coil_name.to_s.downcase == coil.name.to_s.downcase }[0]
|
|
3236
|
+
if cooling_coil.ratedTotalCoolingCapacity.to_f.round(0) == issue_coil[:capacity].to_f.round(0)
|
|
3237
|
+
revised_capacity = issue_coil[:capacity].to_f * 1.01
|
|
3238
|
+
issue_coil[:heating_coil].setRatedTotalHeatingCapacity(revised_capacity)
|
|
3239
|
+
cooling_coil.setRatedTotalCoolingCapacity(revised_capacity)
|
|
3240
|
+
dx_coil_changed = true
|
|
3241
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "DX heating and cooling coil #{issue_coil[:heating_coil].name.to_s} has been resized #{revised_capacity}W to avoid sizing run failure.")
|
|
3242
|
+
puts "Adjusted both heating and cooling coil #{issue_coil[:heating_coil].name.to_s} capacity to #{revised_capacity}W to avoid sizing run failure."
|
|
3243
|
+
dx_coil_changed = true
|
|
3244
|
+
end
|
|
3245
|
+
elsif issue_coil.key?(:cooling_coil)
|
|
3246
|
+
heating_coil_name = issue_coil[:cooling_coil].name.to_s.gsub('CoilCoolingDX','CoilHeatingDX')
|
|
3247
|
+
heating_coil = model.getCoilHeatingDXSingleSpeeds.select { |coil| heating_coil_name.to_s.downcase == coil.name.to_s.downcase }[0]
|
|
3248
|
+
if heating_coil.ratedTotalHeatingCapacity.to_f.round(0) == issue_coil[:capacity].to_f.round(0)
|
|
3249
|
+
revised_capacity = issue_coil[:capacity].to_f * 1.01
|
|
3250
|
+
issue_coil[:cooling_coil].setRatedTotalCoolingCapacity(revised_capacity)
|
|
3251
|
+
heating_coil.setRatedTotalHeatingCapacity(revised_capacity)
|
|
3252
|
+
dx_coil_changed = true
|
|
3253
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "DX heating and cooling coil #{issue_coil[:cooling_coil].name.to_s} has been resized #{revised_capacity}W to avoid sizing run failure.")
|
|
3254
|
+
puts "Adjusted both heating and cooling coil #{issue_coil[:cooling_coil].name.to_s} capacity to #{revised_capacity}W to avoid sizing run failure."
|
|
3255
|
+
dx_coil_changed = true
|
|
3256
|
+
end
|
|
2845
3257
|
end
|
|
2846
3258
|
end
|
|
2847
3259
|
end
|
|
2848
3260
|
|
|
2849
|
-
# If no DX coil was changed, break loop and raise error
|
|
2850
|
-
if !dx_coil_changed
|
|
3261
|
+
# If no DX coil was changed, or too many changes were made, break loop and raise error
|
|
3262
|
+
if !dx_coil_changed || num_changes > 100
|
|
2851
3263
|
raise("sizing run failed! check #{sizing_run_dir}/#{sizing_run_subdir} (DX coil sizes adjusted, but no further changes possible)")
|
|
2852
3264
|
end
|
|
2853
|
-
puts "Rerunning sizing run after adjusting
|
|
3265
|
+
puts "Rerunning sizing run after adjusting coil capacity this many times: #{num_changes}."
|
|
2854
3266
|
# Otherwise, loop will rerun sizing
|
|
2855
3267
|
end
|
|
2856
3268
|
end
|