openstudio-standards 0.8.3 → 0.8.4
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/lib/openstudio-standards/btap/costing/README.md +502 -0
- data/lib/openstudio-standards/btap/costing/btap_costing.rb +473 -0
- data/lib/openstudio-standards/btap/costing/btap_measure_helper.rb +359 -0
- data/lib/openstudio-standards/btap/costing/btap_workflow.rb +117 -0
- data/lib/openstudio-standards/btap/costing/common_paths.rb +78 -0
- data/lib/openstudio-standards/btap/costing/common_resources/ConstructionProperties.csv +52 -0
- data/lib/openstudio-standards/btap/costing/common_resources/Constructions.csv +37 -0
- data/lib/openstudio-standards/btap/costing/common_resources/construction_sets.csv +1270 -0
- data/lib/openstudio-standards/btap/costing/common_resources/constructions_glazing.csv +61 -0
- data/lib/openstudio-standards/btap/costing/common_resources/constructions_opaque.csv +2256 -0
- data/lib/openstudio-standards/btap/costing/common_resources/costs.csv +1904 -0
- data/lib/openstudio-standards/btap/costing/common_resources/costs_local_factors.csv +2315 -0
- data/lib/openstudio-standards/btap/costing/common_resources/hvac_vent_ahu.csv +925 -0
- data/lib/openstudio-standards/btap/costing/common_resources/lighting.csv +364 -0
- data/lib/openstudio-standards/btap/costing/common_resources/lighting_sets.csv +2667 -0
- data/lib/openstudio-standards/btap/costing/common_resources/locations.csv +75 -0
- data/lib/openstudio-standards/btap/costing/common_resources/materials_glazing.csv +35 -0
- data/lib/openstudio-standards/btap/costing/common_resources/materials_hvac.csv +1699 -0
- data/lib/openstudio-standards/btap/costing/common_resources/materials_lighting.csv +267 -0
- data/lib/openstudio-standards/btap/costing/common_resources/materials_opaque.csv +164 -0
- data/lib/openstudio-standards/btap/costing/copy_test_results_files_to_expected_results.rb +11 -0
- data/lib/openstudio-standards/btap/costing/cost_building_from_file.rb +136 -0
- data/lib/openstudio-standards/btap/costing/costing_database_wrapper.rb +177 -0
- data/lib/openstudio-standards/btap/costing/daylighting_sensor_control_costing.rb +353 -0
- data/lib/openstudio-standards/btap/costing/dcv_costing.rb +314 -0
- data/lib/openstudio-standards/btap/costing/dummy.epw +8768 -0
- data/lib/openstudio-standards/btap/costing/dummy.osm +5320 -0
- data/lib/openstudio-standards/btap/costing/envelope_costing.rb +284 -0
- data/lib/openstudio-standards/btap/costing/heating_cooling_costing.rb +2584 -0
- data/lib/openstudio-standards/btap/costing/led_lighting_costing.rb +155 -0
- data/lib/openstudio-standards/btap/costing/lighting_costing.rb +209 -0
- data/lib/openstudio-standards/btap/costing/mech_sizing.json +502 -0
- data/lib/openstudio-standards/btap/costing/neb_end_use_prices.csv +42 -0
- data/lib/openstudio-standards/btap/costing/necb_2011_spacetype_info.csv +225 -0
- data/lib/openstudio-standards/btap/costing/necb_reference_runs.csv +28705 -0
- data/lib/openstudio-standards/btap/costing/nv_costing.rb +547 -0
- data/lib/openstudio-standards/btap/costing/parallel_tests.rb +92 -0
- data/lib/openstudio-standards/btap/costing/pv_ground_costing.rb +687 -0
- data/lib/openstudio-standards/btap/costing/shw_costing.rb +705 -0
- data/lib/openstudio-standards/btap/costing/test_list.txt +17 -0
- data/lib/openstudio-standards/btap/costing/test_run_all_test_locally.rb +26 -0
- data/lib/openstudio-standards/btap/costing/test_run_costing_tests.rb +80 -0
- data/lib/openstudio-standards/btap/costing/ventilation_costing.rb +2616 -0
- data/lib/openstudio-standards/constructions/modify.rb +2 -1
- data/lib/openstudio-standards/standards/Standards.Model.rb +39 -9
- data/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb +2 -2
- data/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/ashrae_90_1_prm.UserData.rb +6 -1
- data/lib/openstudio-standards/standards/necb/BTAPPRE1980/btap_pre1980.rb +2 -27
- data/lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_system_3_and_8_single_speed.rb +68 -27
- data/lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_system_4.rb +64 -25
- data/lib/openstudio-standards/standards/necb/BTAPPRE1980/hvac_system_6.rb +9 -14
- data/lib/openstudio-standards/standards/necb/ECMS/hvac_systems.rb +46 -20
- data/lib/openstudio-standards/standards/necb/NECB2011/autozone.rb +635 -248
- data/lib/openstudio-standards/standards/necb/NECB2011/data/constants.json +43 -7
- data/lib/openstudio-standards/standards/necb/NECB2011/data/fuel_type_sets.json +7 -1
- data/lib/openstudio-standards/standards/necb/NECB2011/data/geometry/HighriseApartmentMult.osm +14272 -0
- data/lib/openstudio-standards/standards/necb/NECB2011/data/necb_2015_table_c1.json +1 -1
- data/lib/openstudio-standards/standards/necb/NECB2011/data/space_types.json +437 -437
- data/lib/openstudio-standards/standards/necb/NECB2011/data/systems.json +516 -0
- data/lib/openstudio-standards/standards/necb/NECB2011/data/systems_including_sys5.json +588 -0
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_namer.rb +489 -0
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_1_single_speed.rb +16 -6
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_2_and_5.rb +48 -5
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_3_and_8_multi_speed.rb +2 -2
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_3_and_8_single_speed.rb +35 -27
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_4.rb +34 -23
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_6.rb +8 -6
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_systems.rb +42 -13
- data/lib/openstudio-standards/standards/necb/NECB2011/necb_2011.rb +214 -25
- data/lib/openstudio-standards/standards/necb/NECB2011/system_fuels.rb +61 -1
- data/lib/openstudio-standards/standards/necb/NECB2015/data/space_types.json +636 -636
- data/lib/openstudio-standards/standards/necb/NECB2015/data/unitary_acs.json +38 -38
- data/lib/openstudio-standards/standards/necb/NECB2015/hvac_systems.rb +15 -6
- data/lib/openstudio-standards/standards/necb/NECB2017/data/space_types.json +636 -636
- data/lib/openstudio-standards/standards/necb/NECB2020/data/chillers.json +71 -71
- data/lib/openstudio-standards/standards/necb/README.md +343 -0
- data/lib/openstudio-standards/standards/necb/common/btap_data.rb +190 -28
- data/lib/openstudio-standards/standards/necb/common/btap_datapoint.rb +14 -5
- data/lib/openstudio-standards/standards/necb/common/eccc_electric_grid_intensity_20250311.csv +14 -0
- data/lib/openstudio-standards/standards/necb/common/nir_gas_grid_intensity_20250311.csv +14 -0
- data/lib/openstudio-standards/standards/necb/common/system_types.yaml +0 -0
- data/lib/openstudio-standards/utilities/logging.rb +18 -14
- data/lib/openstudio-standards/version.rb +1 -1
- data/lib/openstudio-standards/weather/modify.rb +2 -2
- data/lib/openstudio-standards.rb +12 -0
- metadata +53 -2
@@ -29,9 +29,10 @@ class NECB2011 < Standard
|
|
29
29
|
return default if variable.nil?
|
30
30
|
if variable.is_a? String
|
31
31
|
return true if variable.to_s.downcase == 'true'
|
32
|
-
return false
|
32
|
+
return false if variable.to_s.downcase == 'false'
|
33
|
+
return default
|
33
34
|
end
|
34
|
-
return
|
35
|
+
return variable if variable.is_a?(TrueClass) || variable.is_a?(FalseClass)
|
35
36
|
return default
|
36
37
|
end
|
37
38
|
|
@@ -214,6 +215,11 @@ class NECB2011 < Standard
|
|
214
215
|
custom_weather_folder: nil,
|
215
216
|
debug: false,
|
216
217
|
sizing_run_dir: Dir.pwd,
|
218
|
+
hvac_system_primary: nil,
|
219
|
+
hvac_system_dwelling_units: nil,
|
220
|
+
hvac_system_washrooms: nil,
|
221
|
+
hvac_system_corridor: nil,
|
222
|
+
hvac_system_storage: nil,
|
217
223
|
primary_heating_fuel: 'Electricity',
|
218
224
|
swh_fuel: nil,
|
219
225
|
dcv_type: 'NECB_Default',
|
@@ -271,6 +277,7 @@ class NECB2011 < Standard
|
|
271
277
|
necb_hdd: true,
|
272
278
|
boiler_fuel: nil,
|
273
279
|
boiler_cap_ratio: nil,
|
280
|
+
airloop_fancoils_heating: nil,
|
274
281
|
oerd_utility_pricing: nil)
|
275
282
|
model = load_building_type_from_library(building_type: building_type)
|
276
283
|
return model_apply_standard(model: model,
|
@@ -279,6 +286,11 @@ class NECB2011 < Standard
|
|
279
286
|
epw_file: epw_file,
|
280
287
|
custom_weather_folder: custom_weather_folder,
|
281
288
|
sizing_run_dir: sizing_run_dir,
|
289
|
+
hvac_system_primary: nil,
|
290
|
+
hvac_system_dwelling_units: nil,
|
291
|
+
hvac_system_washrooms: nil,
|
292
|
+
hvac_system_corridor: nil,
|
293
|
+
hvac_system_storage: nil,
|
282
294
|
primary_heating_fuel: primary_heating_fuel,
|
283
295
|
swh_fuel: swh_fuel,
|
284
296
|
dcv_type: dcv_type, # Four options: (1) 'NECB_Default', (2) 'No_DCV', (3) 'Occupancy_based_DCV' , (4) 'CO2_based_DCV'
|
@@ -334,6 +346,7 @@ class NECB2011 < Standard
|
|
334
346
|
necb_hdd: necb_hdd,
|
335
347
|
boiler_fuel: boiler_fuel,
|
336
348
|
boiler_cap_ratio: boiler_cap_ratio,
|
349
|
+
airloop_fancoils_heating: airloop_fancoils_heating,
|
337
350
|
oerd_utility_pricing: oerd_utility_pricing
|
338
351
|
)
|
339
352
|
end
|
@@ -355,9 +368,15 @@ class NECB2011 < Standard
|
|
355
368
|
tbd_interpolate: nil,
|
356
369
|
epw_file:,
|
357
370
|
custom_weather_folder: nil,
|
371
|
+
btap_weather: true,
|
358
372
|
sizing_run_dir: Dir.pwd,
|
359
373
|
necb_reference_hp: false,
|
360
374
|
necb_reference_hp_supp_fuel: 'DefaultFuel',
|
375
|
+
hvac_system_primary: 'NECB_Default',
|
376
|
+
hvac_system_dwelling_units: 'NECB_Default',
|
377
|
+
hvac_system_washrooms: 'NECB_Default',
|
378
|
+
hvac_system_corridor: 'NECB_Default',
|
379
|
+
hvac_system_storage: 'NECB_Default',
|
361
380
|
primary_heating_fuel: 'Electricity',
|
362
381
|
swh_fuel: nil,
|
363
382
|
dcv_type: 'NECB_Default',
|
@@ -413,9 +432,13 @@ class NECB2011 < Standard
|
|
413
432
|
necb_hdd: true,
|
414
433
|
boiler_fuel: nil,
|
415
434
|
boiler_cap_ratio: nil,
|
435
|
+
airloop_fancoils_heating: nil,
|
416
436
|
oerd_utility_pricing: nil)
|
417
437
|
|
418
|
-
apply_weather_data(model: model,
|
438
|
+
apply_weather_data(model: model,
|
439
|
+
epw_file: epw_file,
|
440
|
+
custom_weather_folder: custom_weather_folder,
|
441
|
+
btap_weather: btap_weather)
|
419
442
|
primary_heating_fuel = validate_primary_heating_fuel(primary_heating_fuel: primary_heating_fuel, model: model)
|
420
443
|
self.fuel_type_set = SystemFuels.new()
|
421
444
|
self.fuel_type_set.set_defaults(standards_data: @standards_data, primary_heating_fuel: primary_heating_fuel)
|
@@ -426,11 +449,21 @@ class NECB2011 < Standard
|
|
426
449
|
boiler_fuel = convert_arg_to_string(variable: boiler_fuel, default: nil)
|
427
450
|
boiler_cap_ratio = convert_arg_to_string(variable: boiler_cap_ratio, default: nil)
|
428
451
|
swh_fuel = convert_arg_to_string(variable: swh_fuel, default: nil)
|
452
|
+
airloop_fancoils_heating = convert_arg_to_bool(variable: airloop_fancoils_heating, default: false)
|
453
|
+
|
454
|
+
# Check if custom systems are assigned to dwelling units, washrooms, corridors, and storage rooms. If they are, set
|
455
|
+
# them to be the same as the primary system type. If no primary system type is defined then set them to be nil.
|
456
|
+
hvac_system_dwelling_units, hvac_system_corridor, hvac_system_storage, hvac_system_washrooms = reset_hvac_system_if_required(hvac_system_primary: hvac_system_primary,
|
457
|
+
hvac_system_dwelling_units: hvac_system_dwelling_units,
|
458
|
+
hvac_system_corridor: hvac_system_corridor,
|
459
|
+
hvac_system_storage: hvac_system_storage,
|
460
|
+
hvac_system_washrooms: hvac_system_washrooms)
|
429
461
|
oerd_utility_pricing = convert_arg_to_bool(variable: oerd_utility_pricing, default: false)
|
430
462
|
|
431
463
|
boiler_cap_ratios = set_boiler_cap_ratios(boiler_cap_ratio: boiler_cap_ratio, boiler_fuel: boiler_fuel) unless boiler_cap_ratio.nil? && boiler_fuel.nil?
|
432
464
|
self.fuel_type_set.set_boiler_fuel(standards_data: @standards_data, boiler_fuel: boiler_fuel, boiler_cap_ratios: boiler_cap_ratios) unless boiler_fuel.nil?
|
433
465
|
self.fuel_type_set.set_swh_fuel(swh_fuel: swh_fuel) unless swh_fuel.nil? || swh_fuel.to_s.downcase == 'defaultfuel'
|
466
|
+
self.fuel_type_set.set_airloop_fancoils_heating() if airloop_fancoils_heating
|
434
467
|
|
435
468
|
# Ensure the volume calculation in all spaces is done automatically
|
436
469
|
model.getSpaces.sort.each do |space|
|
@@ -479,6 +512,11 @@ class NECB2011 < Standard
|
|
479
512
|
apply_kiva_foundation(model)
|
480
513
|
apply_systems_and_efficiencies(model: model,
|
481
514
|
sizing_run_dir: sizing_run_dir,
|
515
|
+
hvac_system_primary: hvac_system_primary,
|
516
|
+
hvac_system_dwelling_units: hvac_system_dwelling_units,
|
517
|
+
hvac_system_washrooms: hvac_system_washrooms,
|
518
|
+
hvac_system_corridor: hvac_system_corridor,
|
519
|
+
hvac_system_storage: hvac_system_storage,
|
482
520
|
primary_heating_fuel: primary_heating_fuel,
|
483
521
|
dcv_type: dcv_type,
|
484
522
|
ecm_system_name: ecm_system_name,
|
@@ -551,6 +589,11 @@ class NECB2011 < Standard
|
|
551
589
|
|
552
590
|
def apply_systems_and_efficiencies(model:,
|
553
591
|
sizing_run_dir:,
|
592
|
+
hvac_system_primary: 'NECB_Default',
|
593
|
+
hvac_system_dwelling_units: 'NECB_Default',
|
594
|
+
hvac_system_washrooms: 'NECB_Default',
|
595
|
+
hvac_system_corridor: 'NECB_Default',
|
596
|
+
hvac_system_storage: 'NECB_Default',
|
554
597
|
primary_heating_fuel:,
|
555
598
|
dcv_type: 'NECB_Default',
|
556
599
|
ecm_system_name: 'NECB_Default',
|
@@ -582,6 +625,11 @@ class NECB2011 < Standard
|
|
582
625
|
|
583
626
|
# Create Default Systems.
|
584
627
|
apply_systems(model: model,
|
628
|
+
hvac_system_primary: hvac_system_primary,
|
629
|
+
hvac_system_dwelling_units: hvac_system_dwelling_units,
|
630
|
+
hvac_system_washrooms: hvac_system_washrooms,
|
631
|
+
hvac_system_corridor: hvac_system_corridor,
|
632
|
+
hvac_system_storage: hvac_system_storage,
|
585
633
|
sizing_run_dir: sizing_run_dir,
|
586
634
|
shw_scale: shw_scale,
|
587
635
|
baseline_system_zones_map_option: baseline_system_zones_map_option)
|
@@ -620,9 +668,9 @@ class NECB2011 < Standard
|
|
620
668
|
ecm.add_airloop_economizer(model: model, airloop_economizer_type: airloop_economizer_type)
|
621
669
|
# Perform a second sizing run if needed
|
622
670
|
if (!unitary_cop.nil? && unitary_cop != 'NECB_Default') || !model.getPlantLoops.empty?
|
623
|
-
|
624
|
-
|
625
|
-
end
|
671
|
+
# Do a sizing run
|
672
|
+
try_sizing_run(model: model, sizing_run_dir: sizing_run_dir, sizing_run_subdir: 'SR2')
|
673
|
+
#end
|
626
674
|
end
|
627
675
|
# apply unitary cop
|
628
676
|
ecm.modify_unitary_cop(model: model, unitary_cop: unitary_cop, sizing_done: true, sql_db_vars_map: sql_db_vars_map)
|
@@ -689,7 +737,7 @@ class NECB2011 < Standard
|
|
689
737
|
ecm.scale_oa_loads(model: model, scale: oa_scale)
|
690
738
|
end
|
691
739
|
|
692
|
-
def apply_weather_data(model:, epw_file:, custom_weather_folder: nil)
|
740
|
+
def apply_weather_data(model:, epw_file:, custom_weather_folder: nil, btap_weather: true)
|
693
741
|
# Create full path to weather file
|
694
742
|
weather_files = File.absolute_path(File.join(__FILE__, '..', '..', '..', '..', '..' , '..', "data/weather"))
|
695
743
|
weather_file = File.join(weather_files, epw_file)
|
@@ -699,7 +747,7 @@ class NECB2011 < Standard
|
|
699
747
|
# Check if btap_batch transferred the weather file
|
700
748
|
weather_transfer = check_datapoint_weather_folder(epw_file: epw_file, weather_folder: weather_files, custom_weather_folder: custom_weather_folder)
|
701
749
|
# If btap_batch didn't transfer the weather file, download it.
|
702
|
-
get_weather_file_from_repo(epw_file: epw_file) unless weather_transfer
|
750
|
+
get_weather_file_from_repo(epw_file: epw_file, btap_weather: btap_weather) unless weather_transfer
|
703
751
|
end
|
704
752
|
|
705
753
|
# Fix EMS references. Temporary workaround for OS issue #2598
|
@@ -1080,10 +1128,10 @@ class NECB2011 < Standard
|
|
1080
1128
|
|
1081
1129
|
# @param necb_reference_hp [Boolean] if true, NECB reference model rules for heat pumps will be used.
|
1082
1130
|
def apply_standard_efficiencies(model:, sizing_run_dir:, dcv_type: 'NECB_Default', necb_reference_hp: false)
|
1083
|
-
|
1131
|
+
# Do a sizing run
|
1132
|
+
try_sizing_run(model: model, sizing_run_dir: sizing_run_dir, sizing_run_subdir: 'plant_loops')
|
1084
1133
|
|
1085
1134
|
climate_zone = 'NECB HDD Method'
|
1086
|
-
raise("sizing run 1 failed! check #{sizing_run_dir}") if model_run_sizing_run(model, "#{sizing_run_dir}/plant_loops", true) == false
|
1087
1135
|
|
1088
1136
|
# This is needed for NECB2011 as a workaround for sizing the reheat boxes.
|
1089
1137
|
model.getAirTerminalSingleDuctVAVReheats.each { |iobj| air_terminal_single_duct_vav_reheat_set_heating_cap(iobj) }
|
@@ -2286,28 +2334,42 @@ class NECB2011 < Standard
|
|
2286
2334
|
return model
|
2287
2335
|
end
|
2288
2336
|
|
2289
|
-
# This method handles looking for the epw_file in
|
2337
|
+
# This method handles looking for the epw_file in btap_weather or Climate.OneBuilding.Org. It
|
2290
2338
|
# checks for the epw_file in the historical data first. If it is not there then it looks in the future weather data.
|
2291
2339
|
# If it is not there either, it throws an error.
|
2292
|
-
# epw_file (String):
|
2293
|
-
#
|
2294
|
-
|
2340
|
+
# epw_file (String): The name of the epw file. The different weather files all share the same name as the epw file,
|
2341
|
+
# only the extension changes.
|
2342
|
+
# btap_weather (Boolean): Determines whether to download from the btap_weather repository or Climate.OneBuilding.Org.
|
2343
|
+
def get_weather_file_from_repo(epw_file:, btap_weather:)
|
2295
2344
|
# Get just the weather file name without the extension
|
2296
2345
|
weather_loc = epw_file[0..-5]
|
2297
2346
|
# Get the url of the file containing the historical weather data file names in the repository and the repository
|
2298
2347
|
# folder containing the files
|
2299
|
-
|
2300
|
-
|
2348
|
+
if btap_weather
|
2349
|
+
historic_weather_files_loc = @standards_data['constants']['historic_weather_file_list_btap']['value'].to_s
|
2350
|
+
historic_folder = @standards_data['constants']['historic_weather_folder_url_btap']['value'].to_s
|
2351
|
+
future_weather_files_loc = @standards_data['constants']['future_weather_file_list_btap']['value'].to_s
|
2352
|
+
future_folder = @standards_data['constants']['future_weather_folder_url_btap']['value'].to_s
|
2353
|
+
else
|
2354
|
+
historic_weather_files_loc = @standards_data['constants']['historic_weather_file_list']['value'].to_s
|
2355
|
+
historic_folder = @standards_data['constants']['historic_weather_folder_url']['value'].to_s
|
2356
|
+
future_weather_files_loc = @standards_data['constants']['future_weather_file_list']['value'].to_s
|
2357
|
+
future_folder = @standards_data['constants']['future_weather_folder_url']['value'].to_s
|
2358
|
+
end
|
2301
2359
|
# Get the files from the repository
|
2302
|
-
success_flag = download_and_save_file(weather_list_url: historic_weather_files_loc,
|
2360
|
+
success_flag = download_and_save_file(weather_list_url: historic_weather_files_loc,
|
2361
|
+
weather_loc: weather_loc,
|
2362
|
+
download_folder: historic_folder,
|
2363
|
+
btap_weather: btap_weather)
|
2303
2364
|
return if success_flag
|
2304
2365
|
# If the file could not be found in the historical data look for it with the future weather data.
|
2305
2366
|
puts "Could not find #{epw_file} in historical weather data files, looking in future weather data files."
|
2306
|
-
|
2307
|
-
|
2308
|
-
|
2367
|
+
success_flag = download_and_save_file(weather_list_url: future_weather_files_loc,
|
2368
|
+
weather_loc: weather_loc,
|
2369
|
+
download_folder: future_folder,
|
2370
|
+
btap_weather: btap_weather)
|
2309
2371
|
return if success_flag
|
2310
|
-
raise("Could not locate the following file in
|
2372
|
+
raise("Could not locate the following file in #{btap_weather ? "btap_weather" : "Climate.OneBuilding.Org"} or could not extract the data: #{epw_file} Please check the spelling of the file or visit #{btap_weather ? "https://github.com/canmet-energy/btap_weather" : "https://climate.onebuilding.org/WMO_Region_4_North_and_Central_America/"} to see if the file exists.")
|
2311
2373
|
end
|
2312
2374
|
|
2313
2375
|
# This method actually looks for and downloads the zip file from the https://github.com/canmet-energy/btap_weather
|
@@ -2321,7 +2383,8 @@ class NECB2011 < Standard
|
|
2321
2383
|
# weather_loc (string): the name of the epw file we are looking for without the .epw extension
|
2322
2384
|
# git_folder (string): the url of the folder containing the weather files. As of 2023-07-07 this this is either the
|
2323
2385
|
# url of the historical weather data folder or the future weather data folder.
|
2324
|
-
|
2386
|
+
# btap_weather (Boolean): Determines whether to download from the btap_weather repository or Climate.OneBuilding.Org.
|
2387
|
+
def download_and_save_file(weather_list_url:, weather_loc:, download_folder:, btap_weather:)
|
2325
2388
|
status = false
|
2326
2389
|
attempt = 1
|
2327
2390
|
# Try to download the list of weather files 5 times, waiting 5 seconds between each attempt.
|
@@ -2341,7 +2404,27 @@ class NECB2011 < Standard
|
|
2341
2404
|
unless zip_name.nil?
|
2342
2405
|
# Found the weather file on the list
|
2343
2406
|
# Define the full url of the weather zip file we want to download
|
2344
|
-
|
2407
|
+
if btap_weather
|
2408
|
+
save_file_url = download_folder + zip_name
|
2409
|
+
else
|
2410
|
+
# Used to resolve the Climate.OneBuilding.Org download link from using just the filename.
|
2411
|
+
abbreviation_map = {
|
2412
|
+
'AB' => 'AB_Alberta/',
|
2413
|
+
'BC' => 'BC_British_Columbia/',
|
2414
|
+
'MB' => 'MB_Manitoba/',
|
2415
|
+
'NB' => 'NB_New_Brunswick/',
|
2416
|
+
'NL' => 'NL_Newfoundland_and_Labrador/',
|
2417
|
+
'NS' => 'NS_Nova_Scotia/',
|
2418
|
+
'NT' => 'NT_Northwest_Territories/',
|
2419
|
+
'NU' => 'NU_Nunavut/',
|
2420
|
+
'ON' => 'ON_Ontario/',
|
2421
|
+
'PE' => 'PE_Prince_Edward_Island/',
|
2422
|
+
'QC' => 'QC_Quebec/',
|
2423
|
+
'SK' => 'SK_Saskatchewan/',
|
2424
|
+
'YT' => 'YT_Yukon/'
|
2425
|
+
}
|
2426
|
+
save_file_url = download_folder + abbreviation_map[zip_name[4..5]] + zip_name
|
2427
|
+
end
|
2345
2428
|
# Define the local location of where the weather zip file will be saved
|
2346
2429
|
weather_dir = File.absolute_path(File.join(__FILE__, '..', '..', '..', '..', '..' , '..', "data/weather"))
|
2347
2430
|
save_file = File.join(weather_dir, zip_name)
|
@@ -2417,6 +2500,9 @@ class NECB2011 < Standard
|
|
2417
2500
|
def extract_weather_data(zipped_file:, weather_dir:)
|
2418
2501
|
# Set a flag to check if the weather data is for future weather.
|
2419
2502
|
future_file = false
|
2503
|
+
|
2504
|
+
# Data structure to determine if the weather file contains all necessary elements.
|
2505
|
+
checklist = {'.epw' => false, '.stat' => false, '.ddy' => false}
|
2420
2506
|
# Start expanding the data.
|
2421
2507
|
Zip::File.open(zipped_file) do |zip_file|
|
2422
2508
|
puts "Expanding #{zipped_file}"
|
@@ -2429,7 +2515,7 @@ class NECB2011 < Standard
|
|
2429
2515
|
# to just '.ddy'. This is so the rest of BTAP uses the _ASHRAE.ddy file.
|
2430
2516
|
entry_name = entry.name.to_s
|
2431
2517
|
if entry_name.length > 11
|
2432
|
-
future_file = true if entry_name
|
2518
|
+
future_file = true if entry_name.end_with?('_ASHRAE.ddy')
|
2433
2519
|
end
|
2434
2520
|
# entry.extract # This was required before but now it isn't. I'm confused so am saving this comment to
|
2435
2521
|
# remind me if there are problems later.
|
@@ -2437,6 +2523,12 @@ class NECB2011 < Standard
|
|
2437
2523
|
content = entry.get_input_stream.read
|
2438
2524
|
# Save the data locally
|
2439
2525
|
File.open(curr_save_file, 'wb') { |save_f| save_f.write(content) }
|
2526
|
+
|
2527
|
+
# Add the file extension of the current entry to the checklist.
|
2528
|
+
file_extension = entry_name[entry_name.rindex('.')..]
|
2529
|
+
if checklist.key?(file_extension)
|
2530
|
+
checklist[file_extension] = true
|
2531
|
+
end
|
2440
2532
|
end
|
2441
2533
|
end
|
2442
2534
|
if future_file
|
@@ -2453,6 +2545,13 @@ class NECB2011 < Standard
|
|
2453
2545
|
FileUtils.cp(orig_ddy_name, rev_ddy_name)
|
2454
2546
|
FileUtils.cp(ashrae_ddy_name, orig_ddy_name)
|
2455
2547
|
end
|
2548
|
+
|
2549
|
+
# Return false if not all files are present:
|
2550
|
+
if !checklist.values.all?()
|
2551
|
+
puts "Error: Not all files present in #{zipped_file}. Missing #{checklist.select { |k, v| v == false}.keys.join(", ") } file(s). Exiting..."
|
2552
|
+
exit(1)
|
2553
|
+
end
|
2554
|
+
|
2456
2555
|
# Return true if everything worked out
|
2457
2556
|
return true
|
2458
2557
|
end
|
@@ -2521,6 +2620,24 @@ class NECB2011 < Standard
|
|
2521
2620
|
return boiler_cap_ratios
|
2522
2621
|
end
|
2523
2622
|
|
2623
|
+
# Until someone has time to allow dwelling units, washrooms, cooridors, and storage rooms can get their own custom
|
2624
|
+
# system types (beyond the default necb_system), this metod will set the system type for those rooms to either be
|
2625
|
+
# their default or to the primary system type (if one is defined and the other sytems are not set to default)
|
2626
|
+
def reset_hvac_system_if_required(hvac_system_primary: nil, hvac_system_dwelling_units: nil, hvac_system_corridor: nil, hvac_system_storage: nil, hvac_system_washrooms: nil)
|
2627
|
+
if hvac_system_primary.nil? || hvac_system_primary.to_s.downcase == "necb_default"
|
2628
|
+
hvac_system_dwelling_units = "NECB_Default"
|
2629
|
+
hvac_system_corridor = "NECB_Default"
|
2630
|
+
hvac_system_storage = "NECB_Default"
|
2631
|
+
hvac_system_washrooms = "NECB_Default"
|
2632
|
+
else
|
2633
|
+
hvac_system_dwelling_units = hvac_system_primary unless hvac_system_dwelling_units.nil? || hvac_system_dwelling_units.to_s.downcase == "necb_default"
|
2634
|
+
hvac_system_corridor = hvac_system_primary unless hvac_system_corridor.nil? || hvac_system_corridor.to_s.downcase == "necb_default"
|
2635
|
+
hvac_system_storage = hvac_system_primary unless hvac_system_storage.nil? || hvac_system_storage.to_s.downcase == "necb_default"
|
2636
|
+
hvac_system_washrooms = hvac_system_primary unless hvac_system_washrooms.nil? || hvac_system_washrooms.to_s.downcase == "necb_default"
|
2637
|
+
end
|
2638
|
+
return hvac_system_dwelling_units, hvac_system_corridor, hvac_system_storage, hvac_system_washrooms
|
2639
|
+
end
|
2640
|
+
|
2524
2641
|
# This method checks if the output_meters argument contains a net electricity meter with 'timestep' frequency. If one
|
2525
2642
|
# is then the method does nothing. If one is not then it is added. This is used in conjunction with the
|
2526
2643
|
# 'oerd_utility_pricing' argument. If that argument is present then a net electricity meter with 'timestep' frequency
|
@@ -2531,17 +2648,89 @@ class NECB2011 < Standard
|
|
2531
2648
|
{
|
2532
2649
|
"name" => "ElectricityNet:Facility",
|
2533
2650
|
"frequency" => "Hourly"
|
2651
|
+
},
|
2652
|
+
{
|
2653
|
+
"name" => "Heating:Electricity",
|
2654
|
+
"frequency" => "Hourly"
|
2655
|
+
},
|
2656
|
+
{
|
2657
|
+
"name" => "WaterSystems:Electricity",
|
2658
|
+
"frequency" => "Hourly"
|
2534
2659
|
}
|
2535
2660
|
]
|
2536
2661
|
else
|
2537
|
-
electnet_facility = output_meters.select { |output_meter| (output_meter["name"].to_s.downcase == "electricitynet:facility") && (output_meter["frequency"].to_s.downcase == "
|
2662
|
+
electnet_facility = output_meters.select { |output_meter| (output_meter["name"].to_s.downcase == "electricitynet:facility") && (output_meter["frequency"].to_s.downcase == "hourly") }
|
2538
2663
|
if electnet_facility.empty?
|
2539
2664
|
output_meters << {
|
2540
2665
|
"name" => "ElectricityNet:Facility",
|
2541
2666
|
"frequency" => "Hourly"
|
2542
2667
|
}
|
2543
2668
|
end
|
2669
|
+
heating_elec = output_meters.select { |output_meter| (output_meter["name"].to_s.downcase == "heating:electricity") && (output_meter["frequency"].to_s.downcase == "hourly") }
|
2670
|
+
if electnet_facility.empty?
|
2671
|
+
output_meters << {
|
2672
|
+
"name" => "Heating:Electricity",
|
2673
|
+
"frequency" => "Hourly"
|
2674
|
+
}
|
2675
|
+
end
|
2676
|
+
watersys_elec = output_meters.select { |output_meter| (output_meter["name"].to_s.downcase == "watersystems:electricity") && (output_meter["frequency"].to_s.downcase == "hourly") }
|
2677
|
+
if electnet_facility.empty?
|
2678
|
+
output_meters << {
|
2679
|
+
"name" => "WaterSystems:Electricity",
|
2680
|
+
"frequency" => "Hourly"
|
2681
|
+
}
|
2682
|
+
end
|
2544
2683
|
end
|
2545
2684
|
return output_meters
|
2546
2685
|
end
|
2686
|
+
|
2687
|
+
# This method is used to do a sizing run on the model. It will return true if the sizing run was successful and
|
2688
|
+
# will generate an error if it was not. The method will also resize any DX heating coils that have a capacity less than 1.0 kW to
|
2689
|
+
# 1.0 kW and rerun the sizing run until it succeeds or the sizing run continues to fail.
|
2690
|
+
#
|
2691
|
+
# Arguments:
|
2692
|
+
# model (OpenStudio::Model::Model): The model to run the sizing run on.
|
2693
|
+
# sizing_run_dir (String): The directory where the sizing run files will be saved.
|
2694
|
+
def try_sizing_run(model:, sizing_run_dir:, sizing_run_subdir:)
|
2695
|
+
raise('validation of model failed.') unless validate_initial_model(model)
|
2696
|
+
|
2697
|
+
# Do a sizing run to determine the system capacities. If a sizing run fails, hard size any failing DX heating coils
|
2698
|
+
# to 1.0 kW and rerun the sizing run until it succeeds. If no DX heating coils are found, or none had a small
|
2699
|
+
# capacity then raise an error.
|
2700
|
+
loop do
|
2701
|
+
sizing_run_success = model_run_sizing_run(model, "#{sizing_run_dir}/#{sizing_run_subdir}", true)
|
2702
|
+
break if sizing_run_success
|
2703
|
+
|
2704
|
+
# Sizing run failed, check all DX heating coils and set their size to 1 if less than 1
|
2705
|
+
dx_coil_changed = false
|
2706
|
+
|
2707
|
+
model.getCoilHeatingDXSingleSpeeds.each do |coil|
|
2708
|
+
autosized_capacity = coil.autosizedRatedTotalHeatingCapacity
|
2709
|
+
if autosized_capacity.is_initialized && autosized_capacity.get < 1.0
|
2710
|
+
coil.setRatedTotalHeatingCapacity(1.0)
|
2711
|
+
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.")
|
2712
|
+
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."
|
2713
|
+
dx_coil_changed = true
|
2714
|
+
end
|
2715
|
+
end
|
2716
|
+
model.getCoilHeatingDXMultiSpeeds.each do |coil|
|
2717
|
+
coil.stages.each do |stage|
|
2718
|
+
autosized_capacity = stage.autosizedGrossRatedHeatingCapacity
|
2719
|
+
if autosized_capacity.is_initialized && autosized_capacity.get < 1.0
|
2720
|
+
stage.setGrossRatedHeatingCapacity(1.0)
|
2721
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "A DX Heating Coil #{coil.name.to_s} stage has a rated capacity less than 1.0 kW and has been resized to 1.0 kW to avoid sizing run failure.")
|
2722
|
+
puts "A DX Heating Coil #{coil.name.to_s} stage has a rated capacity less than 1.0 kW and has been resized to 1.0 kW to avoid sizing run failure."
|
2723
|
+
dx_coil_changed = true
|
2724
|
+
end
|
2725
|
+
end
|
2726
|
+
end
|
2727
|
+
|
2728
|
+
# If no DX coil was changed, break loop and raise error
|
2729
|
+
if !dx_coil_changed
|
2730
|
+
raise("sizing run failed! check #{sizing_run_dir}/#{sizing_run_subdir} (DX coil sizes adjusted, but no further changes possible)")
|
2731
|
+
end
|
2732
|
+
puts "Rerunning sizing run after adjusting DX heating coil capacity to 1.0 kW."
|
2733
|
+
# Otherwise, loop will rerun sizing
|
2734
|
+
end
|
2735
|
+
end
|
2547
2736
|
end
|
@@ -9,6 +9,7 @@ class SystemFuels
|
|
9
9
|
attr_accessor :mau_heating_coil_type
|
10
10
|
attr_accessor :mau_cooling_type
|
11
11
|
attr_accessor :chiller_type
|
12
|
+
attr_accessor :heating_coil_type_sys2
|
12
13
|
attr_accessor :heating_coil_type_sys3
|
13
14
|
attr_accessor :heating_coil_type_sys4
|
14
15
|
attr_accessor :heating_coil_type_sys6
|
@@ -17,6 +18,8 @@ class SystemFuels
|
|
17
18
|
attr_accessor :fan_type
|
18
19
|
attr_accessor :ecm_fueltype
|
19
20
|
attr_accessor :swh_fueltype
|
21
|
+
attr_accessor :force_boiler
|
22
|
+
attr_accessor :force_airloop_hot_water
|
20
23
|
|
21
24
|
def set_defaults(standards_data:, primary_heating_fuel:)
|
22
25
|
# Get fuelset.
|
@@ -33,6 +36,7 @@ class SystemFuels
|
|
33
36
|
@mau_cooling_type = system_fuel_defaults['mau_cooling_type']
|
34
37
|
@chiller_type = system_fuel_defaults['chiller_type']
|
35
38
|
@mau_heating_coil_type = system_fuel_defaults['mau_heating_coil_type']
|
39
|
+
@heating_coil_type_sys2 = system_fuel_defaults['heating_coil_type_sys2']
|
36
40
|
@heating_coil_type_sys3 = system_fuel_defaults['heating_coil_type_sys3']
|
37
41
|
@heating_coil_type_sys4 = system_fuel_defaults['heating_coil_type_sys4']
|
38
42
|
@heating_coil_type_sys6 = system_fuel_defaults['heating_coil_type_sys6']
|
@@ -41,6 +45,8 @@ class SystemFuels
|
|
41
45
|
@fan_type = system_fuel_defaults['fan_type']
|
42
46
|
@swh_fueltype = system_fuel_defaults['swh_fueltype']
|
43
47
|
@ecm_fueltype = system_fuel_defaults['ecm_fueltype']
|
48
|
+
@force_boiler = false
|
49
|
+
@force_airloop_hot_water = false
|
44
50
|
end
|
45
51
|
|
46
52
|
# Forces a boiler to be generated. It searches boiler_fuel_type_sets.json for the boiler_fuel string and sets the
|
@@ -52,12 +58,66 @@ class SystemFuels
|
|
52
58
|
@backup_boiler_fueltype = boiler_fuel_defaults['backup_boiler_fueltype']
|
53
59
|
@secondary_boiler_cap_frac = boiler_cap_ratios[:secondary_ratio]
|
54
60
|
@baseboard_type = boiler_fuel_defaults['baseboard_type']
|
55
|
-
@mau_heating_coil_type = boiler_fuel_defaults['mau_heating_coil_type'] unless @mau_heating_coil_type == 'DX'
|
56
61
|
@heating_coil_type_sys6 = boiler_fuel_defaults['heating_coil_type_sys6']
|
62
|
+
@force_boiler = true
|
57
63
|
end
|
58
64
|
|
59
65
|
# Reset the Service Hot Water fuel.
|
60
66
|
def set_swh_fuel(swh_fuel:)
|
61
67
|
@swh_fueltype = swh_fuel
|
62
68
|
end
|
69
|
+
|
70
|
+
#Forces heating_coils to be 'Hot Water' except when using HPs
|
71
|
+
def set_airloop_fancoils_heating()
|
72
|
+
@force_airloop_hot_water = true
|
73
|
+
@mau_heating_coil_type = "Hot Water" unless @mau_heating_coil_type == 'DX'
|
74
|
+
@heating_coil_type_sys2 = "Hot Water" unless @heating_coil_type_sys2 == 'DX'
|
75
|
+
@heating_coil_type_sys3 = "Hot Water" unless @heating_coil_type_sys3 == 'DX'
|
76
|
+
@heating_coil_type_sys4 = "Hot Water" unless @heating_coil_type_sys4 == 'DX'
|
77
|
+
@heating_coil_type_sys6 = "Hot Water" unless @heating_coil_type_sys6 == 'DX'
|
78
|
+
if @mau_heating_coil_type == 'DX' || @heating_coil_type_sys3 == 'DX' || @heating_coil_type_sys4 == 'DX' || @heating_coil_type_sys6 == 'DX' || @heating_coil_type_sys2 == 'DX'
|
79
|
+
@necb_reference_hp_supp_fuel = 'Hot Water'
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Reset system fuels to match parameters defined by hvac_system_primary
|
84
|
+
def set_fuel_to_hvac_system_primary(hvac_system_primary:, standards_data:)
|
85
|
+
hvac_system_data = standards_data['hvac_types'].find { |system| system['description'].to_s.downcase == hvac_system_primary.to_s.downcase }
|
86
|
+
return if hvac_system_data.nil? || hvac_system_data.empty?
|
87
|
+
@baseboard_type = hvac_system_data["baseboard_type"].to_s unless hvac_system_data["baseboard_type"].nil? || @force_boiler == true
|
88
|
+
@mau_heating_coil_type = hvac_system_data["mau_heating_type"].to_s unless hvac_system_data["mau_heating_type"].nil? || @force_airloop_hot_water == true
|
89
|
+
@mau_type = hvac_system_data["mau_type"].to_bool unless hvac_system_data["mau_type"].nil?
|
90
|
+
@necb_reference_hp = hvac_system_data["necb_reference_hp"].to_bool unless hvac_system_data["necb_reference_hp"].nil?
|
91
|
+
@necb_reference_hp_supp_fuel = hvac_system_data["necb_reference_hp_supp_fuel"] unless hvac_system_data["necb_reference_hp_supp_fuel"].nil? || @force_airloop_hot_water == true
|
92
|
+
# If applying a hvac_system_primary with an NECB reference HP, make sure that the system 4 systems (if left at
|
93
|
+
# NECB_Default) work with the NECB reference HP.
|
94
|
+
if hvac_system_data["necb_reference_hp"].to_bool
|
95
|
+
@heating_coil_type_sys4 = "DX"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Reset to default fuel info
|
100
|
+
def reset_default_fuel_info(init_fuel_type:)
|
101
|
+
@name = init_fuel_type[:name]
|
102
|
+
@boiler_fueltype = init_fuel_type[:boiler_fueltype]
|
103
|
+
@backup_boiler_fueltype = init_fuel_type[:backup_boiler_fueltype]
|
104
|
+
@primary_boiler_cap_frac = init_fuel_type[:primary_boiler_cap_frac]
|
105
|
+
@secondary_boiler_cap_frac = init_fuel_type[:secondary_boiler_cap_frac]
|
106
|
+
@baseboard_type = init_fuel_type[:baseboard_type]
|
107
|
+
@mau_type = init_fuel_type[:mau_type]
|
108
|
+
@mau_heating_coil_type = init_fuel_type[:mau_heating_coil_type]
|
109
|
+
@mau_cooling_type = init_fuel_type[:mau_cooling_type]
|
110
|
+
@chiller_type = init_fuel_type[:chiller_type]
|
111
|
+
@heating_coil_type_sys2 = init_fuel_type[:heating_coil_type_sys2]
|
112
|
+
@heating_coil_type_sys3 = init_fuel_type[:heating_coil_type_sys3]
|
113
|
+
@heating_coil_type_sys4 = init_fuel_type[:heating_coil_type_sys4]
|
114
|
+
@heating_coil_type_sys6 = init_fuel_type[:heating_coil_type_sys6]
|
115
|
+
@necb_reference_hp = init_fuel_type[:necb_reference_hp]
|
116
|
+
@necb_reference_hp_supp_fuel = init_fuel_type[:necb_reference_hp_supp_fuel]
|
117
|
+
@fan_type = init_fuel_type[:fan_type]
|
118
|
+
@ecm_fueltype = init_fuel_type[:ecm_fueltype]
|
119
|
+
@swh_fueltype = init_fuel_type[:swh_fueltype]
|
120
|
+
@force_boiler = init_fuel_type[:force_boiler]
|
121
|
+
@force_airloop_hot_water = init_fuel_type[:force_airloop_hot_water]
|
122
|
+
end
|
63
123
|
end
|