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
|
@@ -1,653 +0,0 @@
|
|
|
1
|
-
require 'openstudio'
|
|
2
|
-
require 'securerandom'
|
|
3
|
-
require 'optparse'
|
|
4
|
-
require 'yaml'
|
|
5
|
-
# require 'git-revision'
|
|
6
|
-
# resource_folder = File.join(__dir__, '..', '..', 'measures/btap_results/resources')
|
|
7
|
-
# OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
|
|
8
|
-
|
|
9
|
-
class BTAPDatapoint
|
|
10
|
-
def initialize(input_folder: nil,
|
|
11
|
-
output_folder: nil,
|
|
12
|
-
weather_folder: nil,
|
|
13
|
-
input_folder_cache: File.join(__dir__, 'input_cache'))
|
|
14
|
-
@failed = false
|
|
15
|
-
|
|
16
|
-
# set default input folder.
|
|
17
|
-
if input_folder.nil?
|
|
18
|
-
input_folder = File.join(__dir__, 'input')
|
|
19
|
-
end
|
|
20
|
-
if output_folder.nil?
|
|
21
|
-
output_folder = File.join(__dir__, 'output')
|
|
22
|
-
end
|
|
23
|
-
# Create an empty weather folder if one doesn't exist. This is to avoid issues later.
|
|
24
|
-
if weather_folder.nil?
|
|
25
|
-
weather_folder = File.join(__dir__, 'weather')
|
|
26
|
-
end
|
|
27
|
-
puts("INPUT FOLDER:#{input_folder}")
|
|
28
|
-
puts("OUTPUT FOLDER:#{output_folder}")
|
|
29
|
-
|
|
30
|
-
# Set local temp cache folders. These are created new for each datapoint.
|
|
31
|
-
# Location of the datapoint input folder. Could be local, cloud, or VM host.
|
|
32
|
-
@dp_input_folder = File.join(input_folder)
|
|
33
|
-
# Location of temp folder, it is always local.
|
|
34
|
-
@dp_temp_folder = File.join(__dir__, 'temp_folder')
|
|
35
|
-
|
|
36
|
-
# Make sure temp folder is always clean.
|
|
37
|
-
FileUtils.rm_rf(@dp_temp_folder)
|
|
38
|
-
FileUtils.mkdir_p(@dp_temp_folder)
|
|
39
|
-
|
|
40
|
-
# Create local cache for datapoint folder. Makes everything faster an easier to have a local copy. Mirroring logic
|
|
41
|
-
# even if running locally to be consistent.
|
|
42
|
-
FileUtils.rm_rf(input_folder_cache)
|
|
43
|
-
FileUtils.mkdir_p(input_folder_cache)
|
|
44
|
-
|
|
45
|
-
# Check if input where input is from.
|
|
46
|
-
if @dp_input_folder.start_with?('s3:')
|
|
47
|
-
# Lets dissect the information from the s3 path.
|
|
48
|
-
m = @dp_input_folder.match(%r{s3://(.*?)/(.*)})
|
|
49
|
-
puts(m)
|
|
50
|
-
puts(m[1])
|
|
51
|
-
puts(m[2])
|
|
52
|
-
@s3_bucket = m[1]
|
|
53
|
-
@s3_input_folder_object = m[2]
|
|
54
|
-
m = output_folder.match(%r{s3://(.*?)/(.*)})
|
|
55
|
-
puts(m)
|
|
56
|
-
puts(m[1])
|
|
57
|
-
puts(m[2])
|
|
58
|
-
@s3_output_folder_object = m[2]
|
|
59
|
-
puts("s3_bucket:#{@s3_bucket}")
|
|
60
|
-
puts("s3_input_folder_object:#{@s3_input_folder_object}")
|
|
61
|
-
puts("s3_output_folder_object:#{@s3_output_folder_object}")
|
|
62
|
-
|
|
63
|
-
s3_copy(source_folder: @dp_input_folder, target_folder: input_folder_cache)
|
|
64
|
-
else
|
|
65
|
-
raise("input folder dne:#{@dp_input_folder}") unless Dir.exist?(@dp_input_folder)
|
|
66
|
-
|
|
67
|
-
puts @dp_input_folder
|
|
68
|
-
puts input_folder_cache
|
|
69
|
-
FileUtils.cp_r(File.join(@dp_input_folder, '.'), input_folder_cache)
|
|
70
|
-
end
|
|
71
|
-
run_options_path = File.join(input_folder_cache, 'run_options.yml')
|
|
72
|
-
raise("Could not read input from #{run_options_path}") unless File.file?(run_options_path)
|
|
73
|
-
|
|
74
|
-
@options = YAML.load_file(run_options_path)
|
|
75
|
-
|
|
76
|
-
# Location of datapoint output folder. Could be local, cloud, or VM host.
|
|
77
|
-
@dp_output_folder = File.join(output_folder, @options[:datapoint_id])
|
|
78
|
-
|
|
79
|
-
# Show versions in yml file.
|
|
80
|
-
@options[:os_git_revision] = OpenstudioStandards.git_revision
|
|
81
|
-
|
|
82
|
-
# Get users' inputs for the parameters needed for the calculation af net present value
|
|
83
|
-
@npv_start_year = @options[:npv_start_year]
|
|
84
|
-
@npv_end_year = @options[:npv_end_year]
|
|
85
|
-
@npv_discount_rate = @options[:npv_discount_rate]
|
|
86
|
-
@npv_discount_rate_carbon = @options[:npv_discount_rate_carbon]
|
|
87
|
-
|
|
88
|
-
# Save configuration to temp folder.
|
|
89
|
-
File.open(File.join(@dp_temp_folder, 'run_options.yml'), 'w') { |file| file.write(@options.to_yaml) }
|
|
90
|
-
begin
|
|
91
|
-
# set up basic model.
|
|
92
|
-
# This dynamically creates a class by string using the factory method design pattern.
|
|
93
|
-
@options[:template] = 'NECB2011' if @options[:algorithm_type] == 'osm_batch'
|
|
94
|
-
@standard = Standard.build(@options[:template])
|
|
95
|
-
|
|
96
|
-
# Set use the convert_arg_to_bool method from the standard class to set the @oerd_utility_pricing_flag
|
|
97
|
-
@oerd_utility_pricing = @standard.convert_arg_to_bool(variable: @options[:oerd_utility_pricing], default: false)
|
|
98
|
-
@utility_pricing_year = @standard.convert_arg_to_f(variable: @options[:utility_pricing_year], default: 2020)
|
|
99
|
-
|
|
100
|
-
# This allows you to select the skeleton model from our built in starting points. You can add a custom file as
|
|
101
|
-
# it will search the libary first,.
|
|
102
|
-
# model = load_osm(@options[:building_type]) # loads skeleton file from path.
|
|
103
|
-
model = @standard.load_building_type_from_library(building_type: @options[:building_type])
|
|
104
|
-
if false == model
|
|
105
|
-
osm_model_path = File.absolute_path(File.join(input_folder_cache, @options[:building_type] + '.osm'))
|
|
106
|
-
raise("File #{osm_model_path} not found") unless File.exist?(osm_model_path)
|
|
107
|
-
|
|
108
|
-
model = BTAP::FileIO.load_osm(osm_model_path)
|
|
109
|
-
end
|
|
110
|
-
#If analysis type is osm_batch..do nothing to the osm files other than add temporal outputs and weather data.
|
|
111
|
-
if @options[:algorithm_type] == 'osm_batch'
|
|
112
|
-
@standard.set_output_variables(model: model, output_variables: @options[:output_variables])
|
|
113
|
-
@standard.set_output_meters(model: model, output_meters: @options[:output_meters])
|
|
114
|
-
climate_zone = 'NECB HDD Method'
|
|
115
|
-
model.getYearDescription.setDayofWeekforStartDay('Sunday')
|
|
116
|
-
epw_file = @options[:epw_file]
|
|
117
|
-
epw_dir = nil
|
|
118
|
-
local_epw_file_path = File.join(input_folder_cache,@options[:epw_file])
|
|
119
|
-
epw_dir = input_folder_cache if File.exist? local_epw_file_path
|
|
120
|
-
weather_file_path = OpenstudioStandards::Weather.get_standards_weather_file_path(epw_file)
|
|
121
|
-
OpenstudioStandards::Weather.model_set_building_location(model, weather_file_path: weather_file_path)
|
|
122
|
-
else
|
|
123
|
-
# Otherwise modify osm input with options.
|
|
124
|
-
@standard.model_apply_standard(model: model,
|
|
125
|
-
epw_file: @options[:epw_file],
|
|
126
|
-
custom_weather_folder: weather_folder,
|
|
127
|
-
btap_weather: @options[:btap_weather],
|
|
128
|
-
sizing_run_dir: File.join(@dp_temp_folder, 'sizing_folder'),
|
|
129
|
-
hvac_system_primary: @options[:hvac_system_primary],
|
|
130
|
-
hvac_system_dwelling_units: @options[:hvac_system_dwelling_units],
|
|
131
|
-
hvac_system_washrooms: @options[:hvac_system_washrooms],
|
|
132
|
-
hvac_system_corridor: @options[:hvac_system_corridor],
|
|
133
|
-
hvac_system_storage: @options[:hvac_system_storage],
|
|
134
|
-
primary_heating_fuel: @options[:primary_heating_fuel],
|
|
135
|
-
necb_reference_hp: @options[:necb_reference_hp],
|
|
136
|
-
necb_reference_hp_supp_fuel: @options[:necb_reference_hp_supp_fuel],
|
|
137
|
-
dcv_type: @options[:dcv_type], # Four options: @options[: (1) 'NECB_Default', (2) 'No DCV', (3) 'Occupancy-based DCV' , (4) 'CO2-based DCV'
|
|
138
|
-
lights_type: @options[:lights_type], # Two options: @options[: (1) 'NECB_Default', (2) 'LED'
|
|
139
|
-
lights_scale: @options[:lights_scale],
|
|
140
|
-
daylighting_type: @options[:daylighting_type], # Two options: @options[: (1) 'NECB_Default', (2) 'add_daylighting_controls'
|
|
141
|
-
ecm_system_name: @options[:ecm_system_name],
|
|
142
|
-
ecm_system_zones_map_option: @options[:ecm_system_zones_map_option], # (1) 'NECB_Default' (2) 'one_sys_per_floor' (3) 'one_sys_per_bldg'
|
|
143
|
-
erv_package: @options[:erv_package],
|
|
144
|
-
boiler_eff: @options[:boiler_eff],
|
|
145
|
-
# Inconsistent naming Todo Chris K.
|
|
146
|
-
unitary_cop: @options[:adv_dx_units],
|
|
147
|
-
furnace_eff: @options[:furnace_eff],
|
|
148
|
-
shw_eff: @options[:shw_eff],
|
|
149
|
-
ext_wall_cond: @options[:ext_wall_cond],
|
|
150
|
-
ext_floor_cond: @options[:ext_floor_cond],
|
|
151
|
-
ext_roof_cond: @options[:ext_roof_cond],
|
|
152
|
-
ground_wall_cond: @options[:ground_wall_cond],
|
|
153
|
-
ground_floor_cond: @options[:ground_floor_cond],
|
|
154
|
-
ground_roof_cond: @options[:ground_roof_cond],
|
|
155
|
-
door_construction_cond: @options[:door_construction_cond],
|
|
156
|
-
fixed_window_cond: @options[:fixed_window_cond],
|
|
157
|
-
glass_door_cond: @options[:glass_door_cond],
|
|
158
|
-
overhead_door_cond: @options[:overhead_door_cond],
|
|
159
|
-
skylight_cond: @options[:skylight_cond],
|
|
160
|
-
glass_door_solar_trans: @options[:glass_door_solar_trans],
|
|
161
|
-
fixed_wind_solar_trans: @options[:fixed_wind_solar_trans],
|
|
162
|
-
skylight_solar_trans: @options[:skylight_solar_trans],
|
|
163
|
-
fdwr_set: @options[:fdwr_set],
|
|
164
|
-
srr_set: @options[:srr_set],
|
|
165
|
-
rotation_degrees: @options[:rotation_degrees],
|
|
166
|
-
scale_x: @options[:scale_x],
|
|
167
|
-
scale_y: @options[:scale_y],
|
|
168
|
-
scale_z: @options[:scale_z],
|
|
169
|
-
pv_ground_type: @options[:pv_ground_type],
|
|
170
|
-
pv_ground_total_area_pv_panels_m2: @options[:pv_ground_total_area_pv_panels_m2],
|
|
171
|
-
pv_ground_tilt_angle: @options[:pv_ground_tilt_angle],
|
|
172
|
-
pv_ground_azimuth_angle: @options[:pv_ground_azimuth_angle],
|
|
173
|
-
pv_ground_module_description: @options[:pv_ground_module_description],
|
|
174
|
-
nv_type: @options[:nv_type],
|
|
175
|
-
nv_opening_fraction: @options[:nv_opening_fraction],
|
|
176
|
-
nv_temp_out_min: @options[:nv_temp_out_min],
|
|
177
|
-
nv_delta_temp_in_out: @options[:nv_delta_temp_in_out],
|
|
178
|
-
occupancy_loads_scale: @options[:occupancy_loads_scale],
|
|
179
|
-
electrical_loads_scale: @options[:electrical_loads_scale],
|
|
180
|
-
oa_scale: @options[:oa_scale],
|
|
181
|
-
infiltration_scale: @options[:infiltration_scale],
|
|
182
|
-
chiller_type: @options[:chiller_type],
|
|
183
|
-
output_variables: @options[:output_variables],
|
|
184
|
-
output_meters: @options[:output_meters],
|
|
185
|
-
airloop_economizer_type: @options[:airloop_economizer_type],
|
|
186
|
-
shw_scale: @options[:shw_scale],
|
|
187
|
-
baseline_system_zones_map_option: @options[:baseline_system_zones_map_option],
|
|
188
|
-
tbd_option: @options[:tbd_option],
|
|
189
|
-
necb_hdd: @options[:necb_hdd],
|
|
190
|
-
boiler_fuel: @options[:boiler_fuel],
|
|
191
|
-
boiler_cap_ratio: @options[:boiler_cap_ratio],
|
|
192
|
-
swh_fuel: @options[:swh_fuel],
|
|
193
|
-
airloop_fancoils_heating: @options[:airloop_fancoils_heating],
|
|
194
|
-
oerd_utility_pricing: @oerd_utility_pricing
|
|
195
|
-
)
|
|
196
|
-
end
|
|
197
|
-
|
|
198
|
-
# Save model to disk.
|
|
199
|
-
puts "saving model to #{File.join(@dp_temp_folder, 'output.osm')}"
|
|
200
|
-
BTAP::FileIO.save_osm(model, File.join(@dp_temp_folder, 'output.osm'))
|
|
201
|
-
|
|
202
|
-
# Run annual simulation of model.
|
|
203
|
-
if @options[:run_annual_simulation]
|
|
204
|
-
@run_dir = File.join(@dp_temp_folder, 'run_dir')
|
|
205
|
-
puts "running simulation in #{@run_dir}"
|
|
206
|
-
@standard.model_run_simulation_and_log_errors(model, @run_dir)
|
|
207
|
-
#Check if sql file was create.. if not we can't get much output.
|
|
208
|
-
raise('no sql file found,simulation probably could not start due to error...see error logs.') if model.sqlFile.empty?
|
|
209
|
-
# Create qaqc file and save it.
|
|
210
|
-
@qaqc = BTAPDatapoint.build_qaqc(model, @standard, @options[:datapoint_id], @options[:analysis_id])
|
|
211
|
-
|
|
212
|
-
# Load the sql file into model
|
|
213
|
-
sql_path = OpenStudio::Path.new(File.join(@run_dir, 'run/eplusout.sql'))
|
|
214
|
-
raise(OpenStudio::Error, 'openstudio.model.Model', "Results for the sizing run couldn't be found here: #{sql_path}.") unless OpenStudio.exists(sql_path)
|
|
215
|
-
|
|
216
|
-
sql = OpenStudio::SqlFile.new(sql_path)
|
|
217
|
-
# Check to make sure the sql file is readable,
|
|
218
|
-
# which won't be true if EnergyPlus crashed during simulation.
|
|
219
|
-
unless sql.connectionOpen
|
|
220
|
-
raise(OpenStudio::Error, 'openstudio.model.Model', "The run failed. Look at the eplusout.err file in #{File.dirname(sql_path.to_s)} to see the cause.")
|
|
221
|
-
return false
|
|
222
|
-
end
|
|
223
|
-
# Attach the sql file from the run to the sizing model
|
|
224
|
-
model.setSqlFile(sql)
|
|
225
|
-
|
|
226
|
-
if @options[:enable_costing] or @options[:enable_carbon]
|
|
227
|
-
@cp = CommonPaths.instance
|
|
228
|
-
post_analysis = BTAPDatapointAnalysis.new(
|
|
229
|
-
model: model,
|
|
230
|
-
output_folder: @dp_temp_folder,
|
|
231
|
-
template: @options[:template],
|
|
232
|
-
standard: @standard,
|
|
233
|
-
qaqc: @qaqc)
|
|
234
|
-
end
|
|
235
|
-
|
|
236
|
-
@cost_result = nil
|
|
237
|
-
if @options[:enable_costing]
|
|
238
|
-
@cost_result = post_analysis.run_costing(
|
|
239
|
-
costs_csv: @cp.costs_path,
|
|
240
|
-
factors_csv: @cp.costs_local_factors_path)
|
|
241
|
-
end
|
|
242
|
-
|
|
243
|
-
@carbon_result = nil
|
|
244
|
-
if @options[:enable_carbon]
|
|
245
|
-
@carbon_result = post_analysis.run_carbon
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
@qaqc[:options] = @options # This is options sent on the command line
|
|
249
|
-
# BTAPData
|
|
250
|
-
@btap_data = BTAPData.new(model: model,
|
|
251
|
-
runner: nil,
|
|
252
|
-
cost_result: @cost_result,
|
|
253
|
-
carbon_result: @carbon_result,
|
|
254
|
-
qaqc: @qaqc,
|
|
255
|
-
npv_start_year: @npv_start_year,
|
|
256
|
-
npv_end_year: @npv_end_year,
|
|
257
|
-
npv_discount_rate: @npv_discount_rate,
|
|
258
|
-
npv_discount_rate_carbon: @npv_discount_rate_carbon,
|
|
259
|
-
oerd_utility_pricing: @oerd_utility_pricing,
|
|
260
|
-
utility_pricing_year: @utility_pricing_year).btap_data
|
|
261
|
-
|
|
262
|
-
# Write Files
|
|
263
|
-
File.open(File.join(@dp_temp_folder, 'btap_data.json'), 'w') { |f| f.write(JSON.pretty_generate(@btap_data.sort.to_h, allow_nan: true)) }
|
|
264
|
-
puts "Wrote File btap_data.json in #{Dir.pwd} "
|
|
265
|
-
|
|
266
|
-
File.open(File.join(@dp_temp_folder, 'qaqc.json'), 'w') { |f| f.write(JSON.pretty_generate(@qaqc, allow_nan: true)) }
|
|
267
|
-
puts "Wrote File qaqc.json in #{Dir.pwd} "
|
|
268
|
-
|
|
269
|
-
#output hourly data
|
|
270
|
-
self.output_hourly_data(model,@dp_temp_folder, @options[:datapoint_id])
|
|
271
|
-
|
|
272
|
-
# Output timestep data
|
|
273
|
-
self.output_timestep_data(model,@dp_temp_folder, @options[:datapoint_id])
|
|
274
|
-
end
|
|
275
|
-
rescue StandardError => bang
|
|
276
|
-
puts "Error occured: #{bang}"
|
|
277
|
-
@bang = bang
|
|
278
|
-
File.open(File.join(@dp_temp_folder, 'error.txt'), 'w') { |f| f.write(@bang.message + "\n" + @bang.backtrace.join("\n")) }
|
|
279
|
-
@failed = true
|
|
280
|
-
ensure # will always get executed
|
|
281
|
-
if @dp_output_folder.start_with?('s3://')
|
|
282
|
-
@dp_output_folder = File.join(@s3_output_folder_object, @options[:datapoint_id])
|
|
283
|
-
s3_copy_folder_to_s3(bucket_name: @s3_bucket,
|
|
284
|
-
source_folder: @dp_temp_folder,
|
|
285
|
-
target_folder: @dp_output_folder)
|
|
286
|
-
else
|
|
287
|
-
# Copy results to datapoint output folder.
|
|
288
|
-
@dp_output_folder = File.join(output_folder, @options[:datapoint_id])
|
|
289
|
-
FileUtils.rm_rf(@dp_output_folder)
|
|
290
|
-
FileUtils.mkdir_p(@dp_output_folder)
|
|
291
|
-
FileUtils.cp_r(File.join(@dp_temp_folder, '.'), @dp_output_folder) # Needs dot otherwise will copy temp folder and not just contents.
|
|
292
|
-
puts "Copied output to your designated output folder in the #{@options[:datapoint_id]} subfolder."
|
|
293
|
-
end
|
|
294
|
-
|
|
295
|
-
# clean temp/cache folder up.
|
|
296
|
-
FileUtils.rm_rf(input_folder_cache)
|
|
297
|
-
FileUtils.rm_rf(@dp_temp_folder)
|
|
298
|
-
# Do not fail container if running on AWS, handle error on AWS instead to avoid isuses with large analyses.
|
|
299
|
-
unless @failed == false || (@dp_output_folder.start_with?('s3://'))
|
|
300
|
-
#if @failed == true
|
|
301
|
-
raise(@bang)
|
|
302
|
-
end
|
|
303
|
-
end
|
|
304
|
-
end
|
|
305
|
-
|
|
306
|
-
class << self
|
|
307
|
-
|
|
308
|
-
# Initializes the qaqc data structure.
|
|
309
|
-
# Scoped inside of the class so that it can be used in the intialization of
|
|
310
|
-
# this class as well as in BTAPAnalysis.
|
|
311
|
-
def build_qaqc(model, standard, datapoint_id, analysis_id)
|
|
312
|
-
qaqc = standard.init_qaqc(model)
|
|
313
|
-
command = "SELECT Value
|
|
314
|
-
FROM TabularDataWithStrings
|
|
315
|
-
WHERE ReportName='LEEDsummary'
|
|
316
|
-
AND ReportForString='Entire Facility'
|
|
317
|
-
AND TableName='Sec1.1A-General Information'
|
|
318
|
-
AND RowName = 'Principal Heating Source'
|
|
319
|
-
AND ColumnName='Data'"
|
|
320
|
-
value = model.sqlFile.get.execAndReturnFirstString(command)
|
|
321
|
-
# make sure all the data are available
|
|
322
|
-
qaqc[:building][:principal_heating_source] = 'unknown'
|
|
323
|
-
unless value.empty?
|
|
324
|
-
qaqc[:building][:principal_heating_source] = value.get
|
|
325
|
-
end
|
|
326
|
-
|
|
327
|
-
if qaqc[:building][:principal_heating_source] == 'Additional Fuel'
|
|
328
|
-
model.getPlantLoops.sort.each do |iplantloop|
|
|
329
|
-
boilers = iplantloop.components.select { |icomponent| icomponent.to_BoilerHotWater.is_initialized }
|
|
330
|
-
qaqc[:building][:principal_heating_source] = 'FuelOilNo2' unless boilers.select { |boiler| boiler.to_BoilerHotWater.get.fuelType.to_s == 'FuelOilNo2' }.empty?
|
|
331
|
-
end
|
|
332
|
-
end
|
|
333
|
-
|
|
334
|
-
qaqc[:aws_datapoint_id] = datapoint_id
|
|
335
|
-
qaqc[:aws_analysis_id] = analysis_id
|
|
336
|
-
|
|
337
|
-
return qaqc
|
|
338
|
-
end
|
|
339
|
-
end
|
|
340
|
-
|
|
341
|
-
def s3_copy_file_to_s3(bucket_name:, source_file:, target_file:, n: 0)
|
|
342
|
-
# require 'aws-sdk-core'
|
|
343
|
-
# require 'aws-sdk-s3'
|
|
344
|
-
Aws.use_bundled_cert!
|
|
345
|
-
s3_client = Aws::S3::Client.new(region: 'ca-central-1')
|
|
346
|
-
# Using transfer manager class instead of depricated method
|
|
347
|
-
transfer_manager = Aws::S3::TransferManager.new(client: s3_client)
|
|
348
|
-
|
|
349
|
-
puts("Copying File to S3. source_file:#{source_file} bucket:#{bucket_name} target_folder:#{target_file}")
|
|
350
|
-
response = nil
|
|
351
|
-
begin
|
|
352
|
-
# Using upload_file from transfer manager class instead of depricated method from older class structure
|
|
353
|
-
result = transfer_manager.upload_file(source_file, bucket: bucket_name, key: target_file)
|
|
354
|
-
|
|
355
|
-
if result == true
|
|
356
|
-
puts "Object '#{source_file}' uploaded to bucket '#{bucket_name}'."
|
|
357
|
-
else
|
|
358
|
-
puts response
|
|
359
|
-
raise("Error:Object '#{source_file}' not uploaded to bucket '#{bucket_name}'.")
|
|
360
|
-
end
|
|
361
|
-
rescue StandardError => bang
|
|
362
|
-
# Implementing exponential backoff
|
|
363
|
-
# Tried 7 times.. give up.
|
|
364
|
-
if n == 8
|
|
365
|
-
raise("Giving Up. Failed to submit send file #{source_file} #{target_file} in 8 tries while using exponential backoff. Error was:#{bang}.")
|
|
366
|
-
end
|
|
367
|
-
|
|
368
|
-
# Exponential wait time
|
|
369
|
-
wait_time = 2**n + rand
|
|
370
|
-
puts "Implementing exponential backoff for sending #{target_file} for #{wait_time}s. #{n}th try"
|
|
371
|
-
sleep(wait_time)
|
|
372
|
-
# Do recursive function.
|
|
373
|
-
return s3_copy_file_to_s3(bucket_name: bucket_name, source_file: source_file, target_file: target_file, n: n + 1)
|
|
374
|
-
end
|
|
375
|
-
return response
|
|
376
|
-
end
|
|
377
|
-
|
|
378
|
-
def s3_copy_folder_to_s3(bucket_name:,
|
|
379
|
-
source_folder:,
|
|
380
|
-
target_folder:)
|
|
381
|
-
puts("Copying Folder to S3. source_folder:#{source_folder} bucket:#{bucket_name} target_folder:#{target_folder}")
|
|
382
|
-
|
|
383
|
-
# Iterate over files in folder.
|
|
384
|
-
Dir[File.join(source_folder, '**/*')].reject { |fn| File.directory?(fn) }.each do |source_file|
|
|
385
|
-
# Convert to s3 path. Removing source parent folders and replacing with s3 output folder.
|
|
386
|
-
target_file = File.join(target_folder, source_file.gsub(source_folder, ''))
|
|
387
|
-
s3_copy_file_to_s3(bucket_name: bucket_name,
|
|
388
|
-
source_file: source_file,
|
|
389
|
-
target_file: target_file)
|
|
390
|
-
end
|
|
391
|
-
end
|
|
392
|
-
|
|
393
|
-
def s3_copy(source_folder:,
|
|
394
|
-
target_folder:)
|
|
395
|
-
require 'open3'
|
|
396
|
-
exit_code = nil
|
|
397
|
-
error = nil
|
|
398
|
-
Open3.popen2e('aws', 's3', 'cp', source_folder, target_folder, '--recursive') do |stdin, stdout_stderr, wait_thread|
|
|
399
|
-
error = stdout_stderr.read
|
|
400
|
-
exit_code = wait_thread.value
|
|
401
|
-
end
|
|
402
|
-
if exit_code != 0
|
|
403
|
-
raise(error)
|
|
404
|
-
end
|
|
405
|
-
|
|
406
|
-
return exit_code
|
|
407
|
-
end
|
|
408
|
-
|
|
409
|
-
def output_hourly_data(model, output_folder, datapoint_id)
|
|
410
|
-
osm_path = File.join(output_folder, "run_dir/in.osm")
|
|
411
|
-
sql_path = File.join(output_folder, "run_dir/run/eplusout.sql")
|
|
412
|
-
csv_output = File.join(output_folder, "hourly.csv")
|
|
413
|
-
|
|
414
|
-
hours_of_year = []
|
|
415
|
-
d = Time.new(2006, 1, 1, 1)
|
|
416
|
-
(0...8760).each do |increment|
|
|
417
|
-
hours_of_year << (d + (60 * 60) * increment).strftime('%Y-%m-%d %H:%M')
|
|
418
|
-
end
|
|
419
|
-
|
|
420
|
-
array_of_hashes = []
|
|
421
|
-
|
|
422
|
-
# Find hourly outputs available for this datapoint.
|
|
423
|
-
query = "
|
|
424
|
-
SELECT ReportDataDictionaryIndex
|
|
425
|
-
FROM ReportDataDictionary
|
|
426
|
-
WHERE ReportingFrequency == 'Hourly'
|
|
427
|
-
"
|
|
428
|
-
# Get hourly data for each output.
|
|
429
|
-
model.sqlFile.get.execAndReturnVectorOfInt(query).get.each do |rdd_index|
|
|
430
|
-
|
|
431
|
-
# Get Name
|
|
432
|
-
query = "
|
|
433
|
-
SELECT Name
|
|
434
|
-
FROM ReportDataDictionary
|
|
435
|
-
WHERE ReportDataDictionaryIndex == #{rdd_index}
|
|
436
|
-
"
|
|
437
|
-
name = model.sqlFile.get.execAndReturnFirstString(query).get
|
|
438
|
-
|
|
439
|
-
# Get KeyValue
|
|
440
|
-
query = "
|
|
441
|
-
SELECT KeyValue
|
|
442
|
-
FROM ReportDataDictionary
|
|
443
|
-
WHERE ReportDataDictionaryIndex == #{rdd_index}
|
|
444
|
-
"
|
|
445
|
-
|
|
446
|
-
# In some cases KeyValue has a value and sometimes it does not. In some cases KeyValue is null. If the command
|
|
447
|
-
# below is run and KeyValue is null then the command fails and returns an error. The fix below assumes that if
|
|
448
|
-
# the command below fails it is because KeyValue is null. In that case the "key_value" variable is set to a
|
|
449
|
-
# blank.
|
|
450
|
-
begin
|
|
451
|
-
key_value = model.sqlFile.get.execAndReturnFirstString(query).get
|
|
452
|
-
rescue StandardError => bang
|
|
453
|
-
key_value = ""
|
|
454
|
-
end
|
|
455
|
-
|
|
456
|
-
# Get Units
|
|
457
|
-
query = "
|
|
458
|
-
SELECT Units
|
|
459
|
-
FROM ReportDataDictionary
|
|
460
|
-
WHERE ReportDataDictionaryIndex == #{rdd_index}
|
|
461
|
-
"
|
|
462
|
-
units = model.sqlFile.get.execAndReturnFirstString(query).get
|
|
463
|
-
|
|
464
|
-
# Get hourly data
|
|
465
|
-
query = "
|
|
466
|
-
Select Value
|
|
467
|
-
FROM ReportData
|
|
468
|
-
WHERE
|
|
469
|
-
ReportDataDictionaryIndex = #{rdd_index}
|
|
470
|
-
"
|
|
471
|
-
hourly_values = model.sqlFile.get.execAndReturnVectorOfDouble(query).get
|
|
472
|
-
|
|
473
|
-
hourly_hash = Hash[hours_of_year.zip(hourly_values)]
|
|
474
|
-
|
|
475
|
-
data_hash = { "datapoint_id": datapoint_id, "Name": name, "KeyValue": key_value, "Units": units }.merge(hourly_hash)
|
|
476
|
-
array_of_hashes << data_hash
|
|
477
|
-
end
|
|
478
|
-
|
|
479
|
-
CSV.open(csv_output, "wb") do |csv|
|
|
480
|
-
unless array_of_hashes.empty?
|
|
481
|
-
csv << array_of_hashes.first.keys # adds the attributes name on the first line
|
|
482
|
-
array_of_hashes.each do |hash|
|
|
483
|
-
csv << hash.values
|
|
484
|
-
end
|
|
485
|
-
end
|
|
486
|
-
end
|
|
487
|
-
end
|
|
488
|
-
#=====================================================================================================================
|
|
489
|
-
def output_timestep_data(model, output_folder,datapoint_id)
|
|
490
|
-
osm_path = File.join(output_folder, "run_dir/in.osm")
|
|
491
|
-
sql_path = File.join(output_folder, "run_dir/run/eplusout.sql")
|
|
492
|
-
csv_output = File.join(output_folder, "timestep.csv")
|
|
493
|
-
#===================================================================================================================
|
|
494
|
-
# Get number of timesteps from the model
|
|
495
|
-
number_of_timesteps_per_hour = model.getTimestep.numberOfTimestepsPerHour
|
|
496
|
-
#===================================================================================================================
|
|
497
|
-
# Calculate number of timesteps of the whole year
|
|
498
|
-
number_of_timesteps_of_year = 365 * 24 * number_of_timesteps_per_hour
|
|
499
|
-
|
|
500
|
-
timesteps_of_year = []
|
|
501
|
-
d = Time.new(2006, 1, 1, 0)
|
|
502
|
-
(0...number_of_timesteps_of_year).each do |increment|
|
|
503
|
-
timesteps_of_year << (d + (60 * 60 / number_of_timesteps_per_hour) * increment).strftime('%Y-%m-%d %H:%M')
|
|
504
|
-
end
|
|
505
|
-
timesteps_index = Array(0..number_of_timesteps_of_year-1)
|
|
506
|
-
#===================================================================================================================
|
|
507
|
-
# Create a hash with indices ('timesteps_index') as keys and timesteps as values ('timesteps_of_year')
|
|
508
|
-
# Note from Sara Gilani: 'I had to do this, as when I used 'timesteps_of_year' as keys to create all hashes below
|
|
509
|
-
# (e.g. timestep_hash_datapoint_id, timestep_hash_name, timestep_hash_key_value, ...),
|
|
510
|
-
# it did not create the right number of timesteps for the whole year'
|
|
511
|
-
timesteps_of_year_with_index = Hash[timesteps_index.zip(timesteps_of_year)]
|
|
512
|
-
#===================================================================================================================
|
|
513
|
-
array_of_hashes = []
|
|
514
|
-
array_of_hashes_transposed = []
|
|
515
|
-
#===================================================================================================================
|
|
516
|
-
# Find timestep outputs available for this datapoint.
|
|
517
|
-
query = "
|
|
518
|
-
SELECT ReportDataDictionaryIndex
|
|
519
|
-
FROM ReportDataDictionary
|
|
520
|
-
WHERE ReportingFrequency == 'Zone Timestep'
|
|
521
|
-
"
|
|
522
|
-
#===================================================================================================================
|
|
523
|
-
# Get timestep data for each output.
|
|
524
|
-
model.sqlFile.get.execAndReturnVectorOfInt(query).get.each do |rdd_index|
|
|
525
|
-
#=================================================================================================================
|
|
526
|
-
# Get Name
|
|
527
|
-
query = "
|
|
528
|
-
SELECT Name
|
|
529
|
-
FROM ReportDataDictionary
|
|
530
|
-
WHERE ReportDataDictionaryIndex == #{rdd_index}
|
|
531
|
-
"
|
|
532
|
-
name = model.sqlFile.get.execAndReturnFirstString(query).get
|
|
533
|
-
#=================================================================================================================
|
|
534
|
-
# Get KeyValue
|
|
535
|
-
query = "
|
|
536
|
-
SELECT KeyValue
|
|
537
|
-
FROM ReportDataDictionary
|
|
538
|
-
WHERE ReportDataDictionaryIndex == #{rdd_index}
|
|
539
|
-
"
|
|
540
|
-
#=================================================================================================================
|
|
541
|
-
# In some cases KeyValue has a value and sometimes it does not. In some cases KeyValue is null. If the command
|
|
542
|
-
# below is run and KeyValue is null then the command fails and returns an error. The fix below assumes that if
|
|
543
|
-
# the command below fails it is because KeyValue is null. In that case the "key_value" variable is set to a
|
|
544
|
-
# blank.
|
|
545
|
-
begin
|
|
546
|
-
key_value = model.sqlFile.get.execAndReturnFirstString(query).get
|
|
547
|
-
rescue StandardError => bang
|
|
548
|
-
key_value = ""
|
|
549
|
-
end
|
|
550
|
-
#=================================================================================================================
|
|
551
|
-
# Get Units
|
|
552
|
-
query = "
|
|
553
|
-
SELECT Units
|
|
554
|
-
FROM ReportDataDictionary
|
|
555
|
-
WHERE ReportDataDictionaryIndex == #{rdd_index}
|
|
556
|
-
"
|
|
557
|
-
units = model.sqlFile.get.execAndReturnFirstString(query).get
|
|
558
|
-
#=================================================================================================================
|
|
559
|
-
# Get timestep data
|
|
560
|
-
query = "
|
|
561
|
-
Select VariableValue
|
|
562
|
-
FROM ReportVariableData
|
|
563
|
-
WHERE
|
|
564
|
-
ReportVariableDataDictionaryIndex = #{rdd_index}
|
|
565
|
-
"
|
|
566
|
-
timestep_values = model.sqlFile.get.execAndReturnVectorOfDouble(query).get
|
|
567
|
-
|
|
568
|
-
timestep_hash = Hash[timesteps_index.zip(timestep_values)]
|
|
569
|
-
|
|
570
|
-
data_hash = { "datapoint_id": datapoint_id, "Name": name, "KeyValue": key_value, "Units": units }.merge(timestep_hash)
|
|
571
|
-
|
|
572
|
-
array_of_hashes << data_hash
|
|
573
|
-
|
|
574
|
-
#=================================================================================================================
|
|
575
|
-
# Create a hash of data for having timesteps as rows instead of columns that is used for hourly outputs START
|
|
576
|
-
number_of_timesteps = timesteps_of_year.length()
|
|
577
|
-
|
|
578
|
-
array = [datapoint_id]
|
|
579
|
-
array_datapoint_id = array.zip(*[array]*number_of_timesteps).flatten
|
|
580
|
-
timestep_hash_datapoint_id = Hash[timesteps_index.zip(array_datapoint_id)]
|
|
581
|
-
|
|
582
|
-
array = [name]
|
|
583
|
-
array_name = array.zip(*[array]*number_of_timesteps).flatten
|
|
584
|
-
timestep_hash_name = Hash[timesteps_index.zip(array_name)]
|
|
585
|
-
|
|
586
|
-
array = [key_value]
|
|
587
|
-
array_key_value = array.zip(*[array]*number_of_timesteps).flatten
|
|
588
|
-
timestep_hash_key_value = Hash[timesteps_index.zip(array_key_value)]
|
|
589
|
-
|
|
590
|
-
array = [units]
|
|
591
|
-
array_units = array.zip(*[array]*number_of_timesteps).flatten
|
|
592
|
-
timestep_hash_units = Hash[timesteps_index.zip(array_units)]
|
|
593
|
-
|
|
594
|
-
timestep_hash_values = Hash[timesteps_index.zip(timestep_values)]
|
|
595
|
-
|
|
596
|
-
data_hash_transposed = Hash.new
|
|
597
|
-
timestep_hash_values.keys.each do |key|
|
|
598
|
-
data_hash_transposed[key] = [
|
|
599
|
-
timesteps_of_year_with_index[key],
|
|
600
|
-
timestep_hash_datapoint_id[key],
|
|
601
|
-
timestep_hash_name[key],
|
|
602
|
-
timestep_hash_key_value[key],
|
|
603
|
-
timestep_hash_units[key],
|
|
604
|
-
timestep_hash_values[key]
|
|
605
|
-
]
|
|
606
|
-
end
|
|
607
|
-
|
|
608
|
-
array_of_hashes_transposed << data_hash_transposed
|
|
609
|
-
# Create a hash of data for having timesteps as rows instead of columns that is used for hourly outputs END
|
|
610
|
-
#=================================================================================================================
|
|
611
|
-
|
|
612
|
-
end #model.sqlFile.get.execAndReturnVectorOfInt(query).get.each do |rdd_index|
|
|
613
|
-
#===================================================================================================================
|
|
614
|
-
# # This csv file has timesteps as the first row
|
|
615
|
-
# CSV.open(csv_output, "wb") do |csv|
|
|
616
|
-
# unless array_of_hashes.empty?
|
|
617
|
-
# csv << array_of_hashes.first.keys # adds the attributes name on the first line
|
|
618
|
-
# array_of_hashes.each do |hash|
|
|
619
|
-
# csv << hash.values
|
|
620
|
-
# end
|
|
621
|
-
# end
|
|
622
|
-
# end
|
|
623
|
-
#===================================================================================================================
|
|
624
|
-
# This csv file has timesteps as the first column
|
|
625
|
-
header = ['Index', 'Timestep', 'datapoint_id', 'Name', 'KeyValue', 'Units', 'Value']
|
|
626
|
-
CSV.open(csv_output, "wb") do |csv|
|
|
627
|
-
csv << header
|
|
628
|
-
array_of_hashes_transposed.each do |hash|
|
|
629
|
-
hash.keys().each do |index|
|
|
630
|
-
row_index = index
|
|
631
|
-
row_timestep = hash[index][0]
|
|
632
|
-
row_datapoint_id = hash[index][1]
|
|
633
|
-
row_name = hash[index][2]
|
|
634
|
-
row_key_value = hash[index][3]
|
|
635
|
-
row_units = hash[index][4]
|
|
636
|
-
row_value = hash[index][5]
|
|
637
|
-
|
|
638
|
-
row = CSV::Row.new(header,[])
|
|
639
|
-
row['Index'] = row_index
|
|
640
|
-
row['Timestep'] = row_timestep
|
|
641
|
-
row['datapoint_id'] = row_datapoint_id
|
|
642
|
-
row['Name'] = row_name
|
|
643
|
-
row['KeyValue'] = row_key_value
|
|
644
|
-
row['Units'] = row_units
|
|
645
|
-
row['Value'] = row_value
|
|
646
|
-
csv << row
|
|
647
|
-
end
|
|
648
|
-
end
|
|
649
|
-
end
|
|
650
|
-
#===================================================================================================================
|
|
651
|
-
end #output_timestep_data
|
|
652
|
-
#=====================================================================================================================
|
|
653
|
-
end
|