openstudio-extension 0.7.1 → 0.8.0

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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +14 -0
  4. data/LICENSE.md +1 -1
  5. data/README.md +2 -0
  6. data/lib/openstudio/extension/runner.rb +12 -8
  7. data/lib/openstudio/extension/runner_config.rb +33 -6
  8. data/lib/openstudio/extension/version.rb +1 -1
  9. data/openstudio-extension.gemspec +6 -6
  10. metadata +15 -66
  11. data/lib/openstudio/extension/core/CreateResults.rb +0 -1033
  12. data/lib/openstudio/extension/core/check_air_sys_temps.rb +0 -160
  13. data/lib/openstudio/extension/core/check_calibration.rb +0 -125
  14. data/lib/openstudio/extension/core/check_cond_zns.rb +0 -54
  15. data/lib/openstudio/extension/core/check_domestic_hot_water.rb +0 -304
  16. data/lib/openstudio/extension/core/check_envelope_conductance.rb +0 -423
  17. data/lib/openstudio/extension/core/check_eui_by_end_use.rb +0 -132
  18. data/lib/openstudio/extension/core/check_eui_reasonableness.rb +0 -105
  19. data/lib/openstudio/extension/core/check_fan_pwr.rb +0 -68
  20. data/lib/openstudio/extension/core/check_internal_loads.rb +0 -363
  21. data/lib/openstudio/extension/core/check_mech_sys_capacity.rb +0 -196
  22. data/lib/openstudio/extension/core/check_mech_sys_efficiency.rb +0 -296
  23. data/lib/openstudio/extension/core/check_mech_sys_part_load_eff.rb +0 -434
  24. data/lib/openstudio/extension/core/check_mech_sys_type.rb +0 -109
  25. data/lib/openstudio/extension/core/check_part_loads.rb +0 -421
  26. data/lib/openstudio/extension/core/check_placeholder.rb +0 -45
  27. data/lib/openstudio/extension/core/check_plant_cap.rb +0 -93
  28. data/lib/openstudio/extension/core/check_plant_temps.rb +0 -129
  29. data/lib/openstudio/extension/core/check_plenum_loads.rb +0 -57
  30. data/lib/openstudio/extension/core/check_pump_pwr.rb +0 -78
  31. data/lib/openstudio/extension/core/check_sch_coord.rb +0 -211
  32. data/lib/openstudio/extension/core/check_schedules.rb +0 -281
  33. data/lib/openstudio/extension/core/check_simultaneous_heating_and_cooling.rb +0 -128
  34. data/lib/openstudio/extension/core/check_supply_air_and_thermostat_temp_difference.rb +0 -118
  35. data/lib/openstudio/extension/core/check_weather_files.rb +0 -102
  36. data/lib/openstudio/extension/core/deer_vintages.rb +0 -281
  37. data/lib/openstudio/extension/core/os_lib_aedg_measures.rb +0 -461
  38. data/lib/openstudio/extension/core/os_lib_constructions.rb +0 -353
  39. data/lib/openstudio/extension/core/os_lib_geometry.rb +0 -1169
  40. data/lib/openstudio/extension/core/os_lib_helper_methods.rb +0 -383
  41. data/lib/openstudio/extension/core/os_lib_hvac.rb +0 -2163
  42. data/lib/openstudio/extension/core/os_lib_lighting_and_equipment.rb +0 -184
  43. data/lib/openstudio/extension/core/os_lib_model_generation.rb +0 -3584
  44. data/lib/openstudio/extension/core/os_lib_model_simplification.rb +0 -1019
  45. data/lib/openstudio/extension/core/os_lib_outdoorair_and_infiltration.rb +0 -135
  46. data/lib/openstudio/extension/core/os_lib_reporting_qaqc.rb +0 -170
  47. data/lib/openstudio/extension/core/os_lib_schedules.rb +0 -933
@@ -1,1033 +0,0 @@
1
- # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
3
- # See also https://openstudio.net/license
4
- # *******************************************************************************
5
-
6
- module OsLib_CreateResults
7
- # Reports out the detailed simulation results needed by EDAPT.
8
- # Results are output as both OpenStudio::Attributes (for OpenStudio 1.X)
9
- # and runner.registerValue (for OpenStudio 2.X).
10
- # @param skip_weekends [Bool] if true, weekends will not be included in the peak demand window
11
- # @param skip_holidays [Bool] if true, holidays will not be included in the peak demand window
12
- # @param start_mo [String] the start month for the peak demand window
13
- # @param start_day [Integer] the start day for the peak demand window
14
- # @param start_hr [Integer] the start hour for the peak demand window, using 24-hr clock
15
- # @param end_mo [String] the end month for the peak demand window
16
- # @param end_day [Integer] the end day for the peak demand window
17
- # @param end_hr [Integer] the end hour for the peak demand window, using 24-hr clock
18
- # @param electricity_consumption_tou_periods [Array<Hash>] optional array of hashes to add
19
- # time-of-use electricity consumption values to the annual consumption information.
20
- # Periods may overlap, but should be listed in the order in which they must be checked,
21
- # where the value will be assigned to the first encountered period it falls into.
22
- # An example hash looks like this:
23
- # {
24
- # 'tou_name' => 'system_peak',
25
- # 'tou_id' => 1,
26
- # 'skip_weekends' => true,
27
- # 'skip_holidays' => true,
28
- # 'start_mo' => 'July',
29
- # 'start_day' => 1,
30
- # 'start_hr' => 14,
31
- # 'end_mo' => 'August',
32
- # 'end_day' => 31,
33
- # 'end_hr' => 18
34
- # }
35
- # @return [OpenStudio::AttributeVector] a vector of results needed by EDAPT
36
- def create_results(skip_weekends = true,
37
- skip_holidays = true,
38
- start_mo = 'June',
39
- start_day = 1,
40
- start_hr = 14,
41
- end_mo = 'September',
42
- end_day = 30,
43
- end_hr = 18,
44
- electricity_consumption_tou_periods = [])
45
-
46
- # get the current version of OS being used to determine if sql query
47
- # changes are needed (for when E+ changes).
48
- os_version = OpenStudio::VersionString.new(OpenStudio.openStudioVersion)
49
-
50
- # create an attribute vector to hold results
51
- result_elems = OpenStudio::AttributeVector.new
52
-
53
- # floor_area
54
- floor_area_query = "SELECT Value FROM tabulardatawithstrings WHERE ReportName='AnnualBuildingUtilityPerformanceSummary' AND ReportForString='Entire Facility' AND TableName='Building Area' AND RowName='Net Conditioned Building Area' AND ColumnName='Area' AND Units='m2'"
55
- floor_area = @sql.execAndReturnFirstDouble(floor_area_query)
56
- if floor_area.is_initialized
57
- result_elems << OpenStudio::Attribute.new('floor_area', floor_area.get, 'm^2')
58
- @runner.registerValue('charsfloor_area', floor_area.get, 'm^2')
59
- else
60
- @runner.registerWarning('Building floor area not found')
61
- return false
62
- end
63
-
64
- # inflation approach
65
- inf_appr_query = "SELECT Value FROM tabulardatawithstrings WHERE ReportName='Life-Cycle Cost Report' AND ReportForString='Entire Facility' AND TableName='Life-Cycle Cost Parameters' AND RowName='Inflation Approach' AND ColumnName='Value'"
66
- inf_appr = @sql.execAndReturnFirstString(inf_appr_query)
67
- if inf_appr.is_initialized
68
- if inf_appr.get == 'ConstantDollar'
69
- inf_appr = 'Constant Dollar'
70
- elsif inf_appr.get == 'CurrentDollar'
71
- inf_appr = 'Current Dollar'
72
- else
73
- @runner.registerError("Inflation approach: #{inf_appr.get} not recognized")
74
- return OpenStudio::Attribute.new('report', result_elems)
75
- end
76
- @runner.registerInfo("Inflation approach = #{inf_appr}")
77
- else
78
- @runner.registerError('Could not determine inflation approach used')
79
- return OpenStudio::Attribute.new('report', result_elems)
80
- end
81
-
82
- # base year
83
- base_yr_query = "SELECT Value FROM tabulardatawithstrings WHERE ReportName='Life-Cycle Cost Report' AND ReportForString='Entire Facility' AND TableName='Life-Cycle Cost Parameters' AND RowName='Base Date' AND ColumnName='Value'"
84
- base_yr = @sql.execAndReturnFirstString(base_yr_query)
85
- if base_yr.is_initialized
86
- if base_yr.get =~ /\d\d\d\d/
87
- base_yr = base_yr.get.match(/\d\d\d\d/)[0].to_f
88
- else
89
- @runner.registerError("Could not determine the analysis start year from #{base_yr.get}")
90
- return OpenStudio::Attribute.new('report', result_elems)
91
- end
92
- else
93
- @runner.registerError('Could not determine analysis start year')
94
- return OpenStudio::Attribute.new('report', result_elems)
95
- end
96
-
97
- # analysis length
98
- length_yrs_query = "SELECT Value FROM tabulardatawithstrings WHERE ReportName='Life-Cycle Cost Report' AND ReportForString='Entire Facility' AND TableName='Life-Cycle Cost Parameters' AND RowName='Length of Study Period in Years' AND ColumnName='Value'"
99
- length_yrs = @sql.execAndReturnFirstInt(length_yrs_query)
100
- if length_yrs.is_initialized
101
- @runner.registerInfo "Analysis length = #{length_yrs.get} yrs"
102
- length_yrs = length_yrs.get
103
- else
104
- @runner.registerError('Could not determine analysis length')
105
- return OpenStudio::Attribute.new('report', result_elems)
106
- end
107
-
108
- # cash flows
109
- cash_flow_elems = OpenStudio::AttributeVector.new
110
-
111
- # setup a vector for each type of cash flow
112
- cap_cash_flow_elems = OpenStudio::AttributeVector.new
113
- om_cash_flow_elems = OpenStudio::AttributeVector.new
114
- energy_cash_flow_elems = OpenStudio::AttributeVector.new
115
- water_cash_flow_elems = OpenStudio::AttributeVector.new
116
- tot_cash_flow_elems = OpenStudio::AttributeVector.new
117
-
118
- # add the type to the element
119
- cap_cash_flow_elems << OpenStudio::Attribute.new('type', "#{inf_appr} Capital Costs")
120
- om_cash_flow_elems << OpenStudio::Attribute.new('type', "#{inf_appr} Operating Costs")
121
- energy_cash_flow_elems << OpenStudio::Attribute.new('type', "#{inf_appr} Energy Costs")
122
- water_cash_flow_elems << OpenStudio::Attribute.new('type', "#{inf_appr} Water Costs")
123
- tot_cash_flow_elems << OpenStudio::Attribute.new('type', "#{inf_appr} Total Costs")
124
-
125
- @runner.registerValue('cash_flows_capital_type', "#{inf_appr} Capital Costs")
126
- @runner.registerValue('cash_flows_operating_type', "#{inf_appr} Operating Costs")
127
- @runner.registerValue('cash_flows_energy_type', "#{inf_appr} Energy Costs")
128
- @runner.registerValue('cash_flows_water_type', "#{inf_appr} Water Costs")
129
- @runner.registerValue('cash_flows_total_type', "#{inf_appr} Total Costs")
130
-
131
- # record the cash flow in these hashes
132
- cap_cash_flow = {}
133
- om_cash_flow = {}
134
- energy_cash_flow = {}
135
- water_cash_flow = {}
136
- tot_cash_flow = {}
137
-
138
- # loop through each year and record the cash flow
139
- for i in 0..(length_yrs - 1) do
140
- new_yr = base_yr + i
141
-
142
- yr = nil
143
- if os_version > OpenStudio::VersionString.new('1.5.3')
144
- yr = "January #{new_yr.round}"
145
- else
146
- yr = "January #{new_yr.round}"
147
- end
148
-
149
- ann_cap_cash = 0.0
150
- ann_om_cash = 0.0
151
- ann_energy_cash = 0.0
152
- ann_water_cash = 0.0
153
- ann_tot_cash = 0.0
154
-
155
- # capital cash flow
156
- cap_cash_query = "SELECT Value FROM tabulardatawithstrings WHERE ReportName='Life-Cycle Cost Report' AND ReportForString='Entire Facility' AND TableName='Capital Cash Flow by Category (Without Escalation)' AND RowName='#{yr}' AND ColumnName='Total'"
157
- cap_cash = @sql.execAndReturnFirstDouble(cap_cash_query)
158
- if cap_cash.is_initialized
159
- ann_cap_cash += cap_cash.get
160
- ann_tot_cash += cap_cash.get
161
- end
162
-
163
- # o&m cash flow (excluding utility costs)
164
- om_types = ['Maintenance', 'Repair', 'Operation', 'Replacement', 'MinorOverhaul', 'MajorOverhaul', 'OtherOperational']
165
- om_types.each do |om_type|
166
- om_cash_query = "SELECT Value FROM tabulardatawithstrings WHERE ReportName='Life-Cycle Cost Report' AND ReportForString='Entire Facility' AND TableName='Operating Cash Flow by Category (Without Escalation)' AND RowName='#{yr}' AND ColumnName='#{om_type}'"
167
- om_cash = @sql.execAndReturnFirstDouble(om_cash_query)
168
- if om_cash.is_initialized
169
- ann_om_cash += om_cash.get
170
- ann_tot_cash += om_cash.get
171
- end
172
- end
173
-
174
- # energy cash flow
175
- energy_cash_query = "SELECT Value FROM tabulardatawithstrings WHERE ReportName='Life-Cycle Cost Report' AND ReportForString='Entire Facility' AND TableName='Operating Cash Flow by Category (Without Escalation)' AND RowName='#{yr}' AND ColumnName='Energy'"
176
- energy_cash = @sql.execAndReturnFirstDouble(energy_cash_query)
177
- if energy_cash.is_initialized
178
- ann_energy_cash += energy_cash.get
179
- ann_tot_cash += energy_cash.get
180
- end
181
-
182
- # water cash flow
183
- water_cash_query = "SELECT Value FROM tabulardatawithstrings WHERE ReportName='Life-Cycle Cost Report' AND ReportForString='Entire Facility' AND TableName='Operating Cash Flow by Category (Without Escalation)' AND RowName='#{yr}' AND ColumnName='Water'"
184
- water_cash = @sql.execAndReturnFirstDouble(water_cash_query)
185
- if water_cash.is_initialized
186
- ann_water_cash += water_cash.get
187
- ann_tot_cash += water_cash.get
188
- end
189
-
190
- # log the values for this year
191
- cap_cash_flow[yr] = ann_cap_cash
192
- om_cash_flow[yr] = ann_om_cash
193
- energy_cash_flow[yr] = ann_energy_cash
194
- water_cash_flow[yr] = ann_water_cash
195
- tot_cash_flow[yr] = ann_tot_cash
196
-
197
- cap_cash_flow_elems << OpenStudio::Attribute.new('year', ann_cap_cash, 'dollars')
198
- om_cash_flow_elems << OpenStudio::Attribute.new('year', ann_om_cash, 'dollars')
199
- energy_cash_flow_elems << OpenStudio::Attribute.new('year', ann_energy_cash, 'dollars')
200
- water_cash_flow_elems << OpenStudio::Attribute.new('year', ann_water_cash, 'dollars')
201
- tot_cash_flow_elems << OpenStudio::Attribute.new('year', ann_tot_cash, 'dollars')
202
-
203
- @runner.registerValue("cash_flows_capital_year_#{i + 1}", ann_cap_cash, 'dollars')
204
- @runner.registerValue("cash_flows_operating_year_#{i + 1}", ann_om_cash, 'dollars')
205
- @runner.registerValue("cash_flows_energy_year_#{i + 1}", ann_energy_cash, 'dollars')
206
- @runner.registerValue("cash_flows_water_year_#{i + 1}", ann_water_cash, 'dollars')
207
- @runner.registerValue("cash_flows_total_year_#{i + 1}", ann_tot_cash, 'dollars')
208
-
209
- end # next year
210
-
211
- # end cash flows
212
- cash_flow_elems << OpenStudio::Attribute.new('cash_flow', cap_cash_flow_elems)
213
- cash_flow_elems << OpenStudio::Attribute.new('cash_flow', om_cash_flow_elems)
214
- cash_flow_elems << OpenStudio::Attribute.new('cash_flow', energy_cash_flow_elems)
215
- cash_flow_elems << OpenStudio::Attribute.new('cash_flow', water_cash_flow_elems)
216
- cash_flow_elems << OpenStudio::Attribute.new('cash_flow', tot_cash_flow_elems)
217
- result_elems << OpenStudio::Attribute.new('cash_flows', cash_flow_elems)
218
-
219
- # list of all end uses in OpenStudio
220
- end_use_cat_types = []
221
- OpenStudio::EndUseCategoryType.getValues.each do |end_use_val|
222
- end_use_cat_types << OpenStudio::EndUseCategoryType.new(end_use_val)
223
- end
224
-
225
- # list of all end use fule types in OpenStudio
226
- end_use_fuel_types = []
227
- OpenStudio::EndUseFuelType.getValues.each do |end_use_fuel_type_val|
228
- end_use_fuel_types << OpenStudio::EndUseFuelType.new(end_use_fuel_type_val)
229
- end
230
-
231
- # list of the 12 months of the year in OpenStudio
232
- months = []
233
- OpenStudio::MonthOfYear.getValues.each do |month_of_year_val|
234
- if (month_of_year_val >= 1) && (month_of_year_val <= 12)
235
- months << OpenStudio::MonthOfYear.new(month_of_year_val)
236
- end
237
- end
238
-
239
- # map each end use category type to the name that will be used in the xml
240
- end_use_map = {
241
- OpenStudio::EndUseCategoryType.new('Heating').value => 'heating',
242
- OpenStudio::EndUseCategoryType.new('Cooling').value => 'cooling',
243
- OpenStudio::EndUseCategoryType.new('InteriorLights').value => 'lighting_interior',
244
- OpenStudio::EndUseCategoryType.new('ExteriorLights').value => 'lighting_exterior',
245
- OpenStudio::EndUseCategoryType.new('InteriorEquipment').value => 'equipment_interior',
246
- OpenStudio::EndUseCategoryType.new('ExteriorEquipment').value => 'equipment_exterior',
247
- OpenStudio::EndUseCategoryType.new('Fans').value => 'fans',
248
- OpenStudio::EndUseCategoryType.new('Pumps').value => 'pumps',
249
- OpenStudio::EndUseCategoryType.new('HeatRejection').value => 'heat_rejection',
250
- OpenStudio::EndUseCategoryType.new('Humidifier').value => 'humidification',
251
- OpenStudio::EndUseCategoryType.new('HeatRecovery').value => 'heat_recovery',
252
- OpenStudio::EndUseCategoryType.new('WaterSystems').value => 'water_systems',
253
- OpenStudio::EndUseCategoryType.new('Refrigeration').value => 'refrigeration',
254
- OpenStudio::EndUseCategoryType.new('Generators').value => 'generators'
255
- }
256
-
257
- # map each fuel type in EndUseFuelTypes to a specific FuelTypes
258
- fuel_type_map = {
259
- OpenStudio::EndUseFuelType.new('Electricity').value => OpenStudio::FuelType.new('Electricity'),
260
- OpenStudio::EndUseFuelType.new('Gas').value => OpenStudio::FuelType.new('Gas'),
261
- OpenStudio::EndUseFuelType.new('AdditionalFuel').value => OpenStudio::FuelType.new('Diesel'), # TODO: add other fuel types
262
- OpenStudio::EndUseFuelType.new('DistrictCooling').value => OpenStudio::FuelType.new('DistrictCooling'),
263
- OpenStudio::EndUseFuelType.new('DistrictHeating').value => OpenStudio::FuelType.new('DistrictHeating'),
264
- OpenStudio::EndUseFuelType.new('Water').value => OpenStudio::FuelType.new('Water')
265
- }
266
-
267
- # map each fuel type in EndUseFuelTypes to a specific FuelTypes
268
- fuel_type_alias_map = {
269
- OpenStudio::EndUseFuelType.new('Electricity').value => 'electricity',
270
- OpenStudio::EndUseFuelType.new('Gas').value => 'gas',
271
- OpenStudio::EndUseFuelType.new('AdditionalFuel').value => 'other_energy',
272
- OpenStudio::EndUseFuelType.new('DistrictCooling').value => 'district_cooling',
273
- OpenStudio::EndUseFuelType.new('DistrictHeating').value => 'district_heating',
274
- OpenStudio::EndUseFuelType.new('Water').value => 'water'
275
- }
276
-
277
- # annual "annual"
278
- annual_elems = OpenStudio::AttributeVector.new
279
-
280
- # consumption "consumption"
281
- cons_elems = OpenStudio::AttributeVector.new
282
-
283
- # electricity
284
- electricity = @sql.electricityTotalEndUses
285
- if electricity.is_initialized
286
- cons_elems << OpenStudio::Attribute.new('electricity', electricity.get, 'GJ')
287
- @runner.registerValue('annual_consumption_electricity', electricity.get, 'GJ')
288
- else
289
- cons_elems << OpenStudio::Attribute.new('electricity', 0.0, 'GJ')
290
- @runner.registerValue('annual_consumption_electricity', 0.0, 'GJ')
291
- end
292
-
293
- # gas
294
- gas = @sql.naturalGasTotalEndUses
295
- if gas.is_initialized
296
- cons_elems << OpenStudio::Attribute.new('gas', gas.get, 'GJ')
297
- @runner.registerValue('annual_consumption_gas', gas.get, 'GJ')
298
- else
299
- cons_elems << OpenStudio::Attribute.new('gas', 0.0, 'GJ')
300
- @runner.registerValue('annual_consumption_gas', 0.0, 'GJ')
301
- end
302
-
303
- # other_energy
304
- other_energy = @sql.otherFuelTotalEndUses
305
- if other_energy.is_initialized
306
- cons_elems << OpenStudio::Attribute.new('other_energy', other_energy.get, 'GJ')
307
- @runner.registerValue('annual_consumption_other_energy', other_energy.get, 'GJ')
308
- else
309
- cons_elems << OpenStudio::Attribute.new('other_energy', 0.0, 'GJ')
310
- @runner.registerValue('annual_consumption_other_energy', 0.0, 'GJ')
311
- end
312
-
313
- # district_cooling
314
- district_cooling = @sql.districtCoolingTotalEndUses
315
- if district_cooling.is_initialized
316
- cons_elems << OpenStudio::Attribute.new('district_cooling', district_cooling.get, 'GJ')
317
- @runner.registerValue('annual_consumption_district_cooling', district_cooling.get, 'GJ')
318
- else
319
- cons_elems << OpenStudio::Attribute.new('district_cooling', 0.0, 'GJ')
320
- @runner.registerValue('annual_consumption_district_cooling', 0.0, 'GJ')
321
- end
322
-
323
- # district_heating
324
- district_heating = @sql.districtHeatingTotalEndUses
325
- if district_heating.is_initialized
326
- cons_elems << OpenStudio::Attribute.new('district_heating', district_heating.get, 'GJ')
327
- @runner.registerValue('annual_consumption_district_heating', district_heating.get, 'GJ')
328
- else
329
- cons_elems << OpenStudio::Attribute.new('district_heating', 0.0, 'GJ')
330
- @runner.registerValue('annual_consumption_district_heating', 0.0, 'GJ')
331
- end
332
-
333
- # water
334
- water = @sql.waterTotalEndUses
335
- if water.is_initialized
336
- cons_elems << OpenStudio::Attribute.new('water', water.get, 'm^3')
337
- @runner.registerValue('annual_consumption_water', water.get, 'm^3')
338
- else
339
- cons_elems << OpenStudio::Attribute.new('water', 0.0, 'm^3')
340
- @runner.registerValue('annual_consumption_water', 0.0, 'm^3')
341
- end
342
-
343
- # end consumption
344
- annual_elems << OpenStudio::Attribute.new('consumption', cons_elems)
345
-
346
- # demand "demand"
347
- demand_elems = OpenStudio::AttributeVector.new
348
-
349
- # get the weather file run period (as opposed to design day run period)
350
- ann_env_pd = nil
351
- @sql.availableEnvPeriods.each do |env_pd|
352
- env_type = @sql.environmentType(env_pd)
353
- if env_type.is_initialized
354
- if env_type.get == OpenStudio::EnvironmentType.new('WeatherRunPeriod')
355
- ann_env_pd = env_pd
356
- end
357
- end
358
- end
359
-
360
- # only try to get the annual peak demand if an annual simulation was run
361
- if ann_env_pd
362
-
363
- # create some units to use
364
- joule_unit = OpenStudio.createUnit('J').get
365
- gigajoule_unit = OpenStudio.createUnit('GJ').get
366
- hrs_unit = OpenStudio.createUnit('h').get
367
- kilowatt_unit = OpenStudio.createUnit('kW').get
368
-
369
- # get the annual hours simulated
370
- hrs_sim = '(0 - no partial annual simulation)'
371
- if @sql.hoursSimulated.is_initialized
372
- hrs_sim = @sql.hoursSimulated.get
373
- if hrs_sim != 8760
374
- @runner.registerError("Simulation was only #{hrs_sim} hrs; EDA requires an annual simulation (8760 hrs)")
375
- return OpenStudio::Attribute.new('report', result_elems)
376
- end
377
- end
378
-
379
- # Get the electricity timeseries to determine the year used
380
- elec = @sql.timeSeries(ann_env_pd, 'Zone Timestep', 'Electricity:Facility', '')
381
- timeseries_yr = nil
382
- if elec.is_initialized
383
- timeseries_yr = elec.get.dateTimes[0].date.year
384
- else
385
- @runner.registerError('Peak Demand timeseries (Electricity:Facility at zone timestep) could not be found, cannot determine the informatino needed to calculate savings or incentives.')
386
- end
387
- # Setup the peak demand time window based on input arguments.
388
- # Note that holidays and weekends are not excluded because
389
- # of a bug in EnergyPlus dates.
390
- # This will only impact corner-case buildings that have
391
- # peak demand on weekends or holidays, which is unusual.
392
- @runner.registerInfo("Peak Demand window is #{start_mo} #{start_day} to #{end_mo} #{end_day} from #{start_hr}:00 to #{end_hr}:00.")
393
- start_date = OpenStudio::DateTime.new(OpenStudio::Date.new(OpenStudio::MonthOfYear.new(start_mo), start_day, timeseries_yr), OpenStudio::Time.new(0, 0, 0, 0))
394
- end_date = OpenStudio::DateTime.new(OpenStudio::Date.new(OpenStudio::MonthOfYear.new(end_mo), end_day, timeseries_yr), OpenStudio::Time.new(0, 24, 0, 0))
395
- start_time = OpenStudio::Time.new(0, start_hr, 0, 0)
396
- end_time = OpenStudio::Time.new(0, end_hr, 0, 0)
397
-
398
- # Get the day type timeseries.
399
- day_types = nil
400
- day_type_indices = @sql.timeSeries(ann_env_pd, 'Zone Timestep', 'Site Day Type Index', 'Environment')
401
- if day_type_indices.is_initialized
402
- # Put values into array
403
- day_types = []
404
- day_type_vals = day_type_indices.get.values
405
- for i in 0..(day_type_vals.size - 1)
406
- day_types << day_type_vals[i]
407
- end
408
- else
409
- @runner.registerError('Day Type timeseries (Site Day Type Index at zone timestep) could not be found, cannot accurately determine the peak demand.')
410
- end
411
-
412
- # electricity_peak_demand
413
- electricity_peak_demand = -1.0
414
- electricity_peak_demand_time = nil
415
- # deduce the timestep based on the hours simulated and the number of datapoints in the timeseries
416
- if elec.is_initialized && day_types
417
- elec = elec.get
418
- num_int = elec.values.size
419
- int_len_hrs = OpenStudio::Quantity.new(hrs_sim / num_int, hrs_unit)
420
-
421
- # Put timeseries into array
422
- elec_vals = []
423
- ann_elec_vals = elec.values
424
- for i in 0..(ann_elec_vals.size - 1)
425
- elec_vals << ann_elec_vals[i]
426
- end
427
-
428
- # Put values into array
429
- elec_times = []
430
- ann_elec_times = elec.dateTimes
431
- for i in 0..(ann_elec_times.size - 1)
432
- elec_times << ann_elec_times[i]
433
- end
434
-
435
- # Loop through the time/value pairs and find the peak
436
- # excluding the times outside of the Xcel peak demand window
437
- elec_times.zip(elec_vals).each_with_index do |vs, ind|
438
- date_time = vs[0]
439
- val = vs[1]
440
- day_type = day_types[ind]
441
- time = date_time.time
442
- date = date_time.date
443
- day_of_week = date.dayOfWeek
444
- # Convert the peak demand to kW
445
- val_J_per_hr = val / int_len_hrs.value
446
- val_kW = OpenStudio.convert(val_J_per_hr, 'J/h', 'kW').get
447
-
448
- # puts("#{val_kW}kW; #{date}; #{time}; #{day_of_week.valueName}")
449
-
450
- # Skip times outside of the correct months
451
- next if date_time < start_date || date_time > end_date
452
- # Skip times before 2pm and after 6pm
453
- next if time < start_time || time > end_time
454
- # Skip weekends if asked
455
- if skip_weekends
456
- # Sunday = 1, Saturday = 7
457
- next if day_type == 1 || day_type == 7
458
- end
459
- # Skip holidays if asked
460
- if skip_holidays
461
- # Holiday = 8
462
- next if day_type == 8
463
- end
464
-
465
- # puts("VALID #{val_kW}kW; #{date}; #{time}; #{day_of_week.valueName}")
466
-
467
- # Check peak demand against this timestep
468
- # and update if this timestep is higher.
469
- if val > electricity_peak_demand
470
- electricity_peak_demand = val
471
- electricity_peak_demand_time = date_time
472
- end
473
- end
474
- elec_peak_demand_timestep_J = OpenStudio::Quantity.new(electricity_peak_demand, joule_unit)
475
- num_int = elec.values.size
476
- int_len_hrs = OpenStudio::Quantity.new(hrs_sim / num_int, hrs_unit)
477
- elec_peak_demand_hourly_J_per_hr = elec_peak_demand_timestep_J / int_len_hrs
478
- electricity_peak_demand = OpenStudio.convert(elec_peak_demand_hourly_J_per_hr, kilowatt_unit).get.value
479
- demand_elems << OpenStudio::Attribute.new('electricity_peak_demand', electricity_peak_demand, 'kW')
480
- @runner.registerValue('annual_demand_electricity_peak_demand', electricity_peak_demand, 'kW')
481
- @runner.registerInfo("Peak Demand = #{electricity_peak_demand.round(2)}kW on #{electricity_peak_demand_time}")
482
- else
483
- @runner.registerError('Peak Demand timeseries (Electricity:Facility at zone timestep) could not be found, cannot determine the informatino needed to calculate savings or incentives.')
484
- demand_elems << OpenStudio::Attribute.new('electricity_peak_demand', 0.0, 'kW')
485
- @runner.registerValue('annual_demand_electricity_peak_demand', 0.0, 'kW')
486
- end
487
-
488
- # Describe the TOU periods
489
- electricity_consumption_tou_periods.each do |tou_pd|
490
- @runner.registerInfo("TOU period #{tou_pd['tou_id']} represents #{tou_pd['tou_name']} and covers #{tou_pd['start_mo']}-#{tou_pd['start_day']} to #{tou_pd['end_mo']}-#{tou_pd['end_day']} from #{tou_pd['start_hr']} to #{tou_pd['end_hr']}, skip weekends = #{tou_pd['skip_weekends']}, skip holidays = #{tou_pd['skip_holidays']}")
491
- end
492
-
493
- # electricity time-of-use periods
494
- elec = @sql.timeSeries(ann_env_pd, 'Zone Timestep', 'Electricity:Facility', '')
495
- if elec.is_initialized && day_types
496
- elec = elec.get
497
- # Put timeseries into array
498
- elec_vals = []
499
- ann_elec_vals = elec.values
500
- for i in 0..(ann_elec_vals.size - 1)
501
- elec_vals << ann_elec_vals[i]
502
- end
503
-
504
- # Put values into array
505
- elec_times = []
506
- ann_elec_times = elec.dateTimes
507
- for i in 0..(ann_elec_times.size - 1)
508
- elec_times << ann_elec_times[i]
509
- end
510
-
511
- # Loop through the time/value pairs and find the peak
512
- # excluding the times outside of the Xcel peak demand window
513
- electricity_tou_vals = Hash.new(0)
514
- elec_times.zip(elec_vals).each_with_index do |vs, ind|
515
- date_time = vs[0]
516
- joules = vs[1]
517
- day_type = day_types[ind]
518
- time = date_time.time
519
- date = date_time.date
520
-
521
- # puts("#{val_kW}kW; #{date}; #{time}; #{day_of_week.valueName}")
522
-
523
- # Determine which TOU period this hour falls into
524
- tou_period_assigned = false
525
- electricity_consumption_tou_periods.each do |tou_pd|
526
- pd_start_date = OpenStudio::DateTime.new(OpenStudio::Date.new(OpenStudio::MonthOfYear.new(tou_pd['start_mo']), tou_pd['start_day'], timeseries_yr), OpenStudio::Time.new(0, 0, 0, 0))
527
- pd_end_date = OpenStudio::DateTime.new(OpenStudio::Date.new(OpenStudio::MonthOfYear.new(tou_pd['end_mo']), tou_pd['end_day'], timeseries_yr), OpenStudio::Time.new(0, 24, 0, 0))
528
- pd_start_time = OpenStudio::Time.new(0, tou_pd['start_hr'], 0, 0)
529
- pd_end_time = OpenStudio::Time.new(0, tou_pd['end_hr'], 0, 0)
530
- # Skip times outside of the correct months
531
- next if date_time < pd_start_date || date_time > pd_end_date
532
- # Skip times before some time and after another time
533
- next if time < pd_start_time || time > pd_end_time
534
- # Skip weekends if asked
535
- if tou_pd['skip_weekends']
536
- # Sunday = 1, Saturday = 7
537
- next if day_type == 1 || day_type == 7
538
- end
539
- # Skip holidays if asked
540
- if tou_pd['skip_holidays']
541
- # Holiday = 8
542
- next if day_type == 8
543
- end
544
- # If here, this hour falls into the specified period
545
- tou_period_assigned = true
546
- electricity_tou_vals[tou_pd['tou_id']] += joules
547
- break
548
- end
549
- # Ensure that the value fell into a period
550
- unless tou_period_assigned
551
- @runner.registerError("Did not find a TOU period covering #{time} on #{date}, kWh will not be included in any TOU period.")
552
- end
553
- end
554
- # Register values for any time-of-use period with kWh
555
- electricity_tou_vals.each do |tou_pd_id, joules_in_pd|
556
- gj_in_pd = OpenStudio.convert(joules_in_pd, 'J', 'GJ').get
557
- kwh_in_pd = OpenStudio.convert(joules_in_pd, 'J', 'kWh').get
558
- @runner.registerValue("annual_consumption_electricity_tou_#{tou_pd_id}", gj_in_pd, 'GJ')
559
- @runner.registerInfo("TOU period #{tou_pd_id} annual electricity consumption = #{kwh_in_pd} kWh.")
560
- end
561
- else
562
- @runner.registerError('Electricity timeseries (Electricity:Facility at zone timestep) could not be found, cannot determine the information needed to calculate savings or incentives.')
563
- end
564
-
565
- # electricity_annual_avg_peak_demand
566
- val = @sql.electricityTotalEndUses
567
- if val.is_initialized
568
- ann_elec_gj = OpenStudio::Quantity.new(val.get, gigajoule_unit)
569
- ann_hrs = OpenStudio::Quantity.new(hrs_sim, hrs_unit)
570
- elec_ann_avg_peak_demand_hourly_GJ_per_hr = ann_elec_gj / ann_hrs
571
- electricity_annual_avg_peak_demand = OpenStudio.convert(elec_ann_avg_peak_demand_hourly_GJ_per_hr, kilowatt_unit).get.value
572
- demand_elems << OpenStudio::Attribute.new('electricity_annual_avg_peak_demand', electricity_annual_avg_peak_demand, 'kW')
573
- @runner.registerValue('annual_demand_electricity_annual_avg_peak_demand', electricity_annual_avg_peak_demand, 'kW')
574
- else
575
- demand_elems << OpenStudio::Attribute.new('electricity_annual_avg_peak_demand', 0.0, 'kW')
576
- @runner.registerValue('annual_demand_electricity_annual_avg_peak_demand', 0.0, 'kW')
577
- end
578
-
579
- # district_cooling_peak_demand
580
- district_cooling_peak_demand = -1.0
581
- ann_dist_clg_peak_demand_time = nil
582
- dist_clg = @sql.timeSeries(ann_env_pd, 'Zone Timestep', 'DistrictCooling:Facility', '')
583
- # deduce the timestep based on the hours simulated and the number of datapoints in the timeseries
584
- if dist_clg.is_initialized && day_types
585
- dist_clg = dist_clg.get
586
- num_int = dist_clg.values.size
587
- int_len_hrs = OpenStudio::Quantity.new(hrs_sim / num_int, hrs_unit)
588
-
589
- # Put timeseries into array
590
- dist_clg_vals = []
591
- ann_dist_clg_vals = dist_clg.values
592
- for i in 0..(ann_dist_clg_vals.size - 1)
593
- dist_clg_vals << ann_dist_clg_vals[i]
594
- end
595
-
596
- # Put values into array
597
- dist_clg_times = []
598
- ann_dist_clg_times = dist_clg.dateTimes
599
- for i in 0..(ann_dist_clg_times.size - 1)
600
- dist_clg_times << ann_dist_clg_times[i]
601
- end
602
-
603
- # Loop through the time/value pairs and find the peak
604
- # excluding the times outside of the Xcel peak demand window
605
- dist_clg_times.zip(dist_clg_vals).each_with_index do |vs, ind|
606
- date_time = vs[0]
607
- val = vs[1]
608
- day_type = day_types[ind]
609
- time = date_time.time
610
- date = date_time.date
611
- day_of_week = date.dayOfWeek
612
- # Convert the peak demand to kW
613
- val_J_per_hr = val / int_len_hrs.value
614
- val_kW = OpenStudio.convert(val_J_per_hr, 'J/h', 'kW').get
615
-
616
- # puts("#{val_kW}kW; #{date}; #{time}; #{day_of_week.valueName}")
617
-
618
- # Skip times outside of the correct months
619
- next if date_time < start_date || date_time > end_date
620
- # Skip times before 2pm and after 6pm
621
- next if time < start_time || time > end_time
622
- # Skip weekends if asked
623
- if skip_weekends
624
- # Sunday = 1, Saturday = 7
625
- next if day_type == 1 || day_type == 7
626
- end
627
- # Skip holidays if asked
628
- if skip_holidays
629
- # Holiday = 8
630
- next if day_type == 8
631
- end
632
-
633
- # puts("VALID #{val_kW}kW; #{date}; #{time}; #{day_of_week.valueName}")
634
-
635
- # Check peak demand against this timestep
636
- # and update if this timestep is higher.
637
- if val > district_cooling_peak_demand
638
- district_cooling_peak_demand = val
639
- ann_dist_clg_peak_demand_time = date_time
640
- end
641
- end
642
- dist_clg_peak_demand_timestep_J = OpenStudio::Quantity.new(district_cooling_peak_demand, joule_unit)
643
- num_int = dist_clg.values.size
644
- int_len_hrs = OpenStudio::Quantity.new(hrs_sim / num_int, hrs_unit)
645
- dist_clg_peak_demand_hourly_J_per_hr = dist_clg_peak_demand_timestep_J / int_len_hrs
646
- district_cooling_peak_demand = OpenStudio.convert(dist_clg_peak_demand_hourly_J_per_hr, kilowatt_unit).get.value
647
- demand_elems << OpenStudio::Attribute.new('district_cooling_peak_demand', district_cooling_peak_demand, 'kW')
648
- @runner.registerValue('annual_demand_district_cooling_peak_demand', district_cooling_peak_demand, 'kW')
649
- @runner.registerInfo("District Cooling Peak Demand = #{district_cooling_peak_demand.round(2)}kW on #{ann_dist_clg_peak_demand_time}")
650
- else
651
- demand_elems << OpenStudio::Attribute.new('district_cooling_peak_demand', 0.0, 'kW')
652
- @runner.registerValue('annual_demand_district_cooling_peak_demand', 0.0, 'kW')
653
- end
654
-
655
- # district cooling time-of-use periods
656
- dist_clg = @sql.timeSeries(ann_env_pd, 'Zone Timestep', 'DistrictCooling:Facility', '')
657
- if dist_clg.is_initialized && day_types
658
- dist_clg = dist_clg.get
659
- # Put timeseries into array
660
- dist_clg_vals = []
661
- ann_dist_clg_vals = dist_clg.values
662
- for i in 0..(ann_dist_clg_vals.size - 1)
663
- dist_clg_vals << ann_dist_clg_vals[i]
664
- end
665
-
666
- # Put values into array
667
- dist_clg_times = []
668
- ann_dist_clg_times = dist_clg.dateTimes
669
- for i in 0..(ann_dist_clg_times.size - 1)
670
- dist_clg_times << ann_dist_clg_times[i]
671
- end
672
-
673
- # Loop through the time/value pairs and find the peak
674
- # excluding the times outside of the Xcel peak demand window
675
- dist_clg_tou_vals = Hash.new(0)
676
- dist_clg_times.zip(dist_clg_vals).each_with_index do |vs, ind|
677
- date_time = vs[0]
678
- joules = vs[1]
679
- day_type = day_types[ind]
680
- time = date_time.time
681
- date = date_time.date
682
-
683
- # puts("#{val_kW}kW; #{date}; #{time}; #{day_of_week.valueName}")
684
-
685
- # Determine which TOU period this hour falls into
686
- tou_period_assigned = false
687
- electricity_consumption_tou_periods.each do |tou_pd|
688
- pd_start_date = OpenStudio::DateTime.new(OpenStudio::Date.new(OpenStudio::MonthOfYear.new(tou_pd['start_mo']), tou_pd['start_day'], timeseries_yr), OpenStudio::Time.new(0, 0, 0, 0))
689
- pd_end_date = OpenStudio::DateTime.new(OpenStudio::Date.new(OpenStudio::MonthOfYear.new(tou_pd['end_mo']), tou_pd['end_day'], timeseries_yr), OpenStudio::Time.new(0, 24, 0, 0))
690
- pd_start_time = OpenStudio::Time.new(0, tou_pd['start_hr'], 0, 0)
691
- pd_end_time = OpenStudio::Time.new(0, tou_pd['end_hr'], 0, 0)
692
- # Skip times outside of the correct months
693
- next if date_time < pd_start_date || date_time > pd_end_date
694
- # Skip times before some time and after another time
695
- next if time < pd_start_time || time > pd_end_time
696
- # Skip weekends if asked
697
- if tou_pd['skip_weekends']
698
- # Sunday = 1, Saturday = 7
699
- next if day_type == 1 || day_type == 7
700
- end
701
- # Skip holidays if asked
702
- if tou_pd['skip_holidays']
703
- # Holiday = 8
704
- next if day_type == 8
705
- end
706
- # If here, this hour falls into the specified period
707
- tou_period_assigned = true
708
- dist_clg_tou_vals[tou_pd['tou_id']] += joules
709
- break
710
- end
711
- # Ensure that the value fell into a period
712
- unless tou_period_assigned
713
- @runner.registerError("Did not find a TOU period covering #{time} on #{date}, kWh will not be included in any TOU period.")
714
- end
715
- end
716
- # Register values for any time-of-use period with kWh
717
- dist_clg_tou_vals.each do |tou_pd_id, joules_in_pd|
718
- gj_in_pd = OpenStudio.convert(joules_in_pd, 'J', 'GJ').get
719
- kwh_in_pd = OpenStudio.convert(joules_in_pd, 'J', 'kWh').get
720
- @runner.registerValue("annual_consumption_district_cooling_tou_#{tou_pd_id}", gj_in_pd, 'GJ')
721
- @runner.registerInfo("TOU period #{tou_pd_id} annual district cooling consumption = #{kwh_in_pd} kWh.")
722
- end
723
- else
724
- # If TOU periods were specified but this model has no district cooling, report zeroes
725
- if electricity_consumption_tou_periods.size > 0
726
- # Get the TOU ids
727
- tou_ids = []
728
- electricity_consumption_tou_periods.each do |tou_pd|
729
- tou_ids << tou_pd['tou_id']
730
- end
731
- tou_ids.uniq.each do |tou_id|
732
- @runner.registerValue("annual_consumption_district_cooling_tou_#{tou_id}", 0.0, 'GJ')
733
- end
734
- end
735
- end
736
-
737
- else
738
- @runner.registerError('Could not find an annual run period')
739
- return OpenStudio::Attribute.new('report', result_elems)
740
- end
741
-
742
- # end demand
743
- annual_elems << OpenStudio::Attribute.new('demand', demand_elems)
744
-
745
- # utility_cost
746
- utility_cost_elems = OpenStudio::AttributeVector.new
747
- annual_utility_cost_map = {}
748
-
749
- # electricity
750
- electricity = @sql.annualTotalCost(OpenStudio::FuelType.new('Electricity'))
751
- if electricity.is_initialized
752
- utility_cost_elems << OpenStudio::Attribute.new('electricity', electricity.get, 'dollars')
753
- @runner.registerValue('annual_utility_cost_electricity', electricity.get, 'dollars')
754
- annual_utility_cost_map[OpenStudio::EndUseFuelType.new('Electricity').valueName] = electricity.get
755
- else
756
- utility_cost_elems << OpenStudio::Attribute.new('electricity', 0.0, 'dollars')
757
- @runner.registerValue('annual_utility_cost_electricity', 0.0, 'dollars')
758
- annual_utility_cost_map[OpenStudio::EndUseFuelType.new('Electricity').valueName] = 0.0
759
- end
760
-
761
- # electricity_consumption_charge and electricity_demand_charge
762
- electric_consumption_charge = 0.0
763
- electric_demand_charge = 0.0
764
-
765
- electric_rate_query = "SELECT value FROM tabulardatawithstrings WHERE ReportName='LEEDsummary' AND ReportForString='Entire Facility' AND TableName='EAp2-3. Energy Type Summary' AND RowName='Electricity' AND ColumnName='Utility Rate'"
766
- electric_rate_name = @sql.execAndReturnFirstString(electric_rate_query)
767
- if electric_rate_name.is_initialized
768
- electric_rate_name = electric_rate_name.get.strip
769
-
770
- # electricity_consumption_charge
771
- electric_consumption_charge_query = "SELECT value FROM tabulardatawithstrings WHERE ReportName='Tariff Report' AND ReportForString='#{electric_rate_name}' AND TableName='Categories' AND RowName='EnergyCharges (~~$~~)' AND ColumnName='Sum'"
772
- val = @sql.execAndReturnFirstDouble(electric_consumption_charge_query)
773
- if val.is_initialized
774
- electric_consumption_charge = val.get
775
- end
776
-
777
- # electricity_demand_charge
778
- electric_demand_charge_query = "SELECT value FROM tabulardatawithstrings WHERE ReportName='Tariff Report' AND ReportForString='#{electric_rate_name}' AND TableName='Categories' AND RowName='DemandCharges (~~$~~)' AND ColumnName='Sum'"
779
- val = @sql.execAndReturnFirstDouble(electric_demand_charge_query)
780
- if val.is_initialized
781
- electric_demand_charge = val.get
782
- end
783
-
784
- end
785
- utility_cost_elems << OpenStudio::Attribute.new('electricity_consumption_charge', electric_consumption_charge, 'dollars')
786
- @runner.registerValue('annual_utility_cost_electricity_consumption_charge', electric_consumption_charge, 'dollars')
787
- utility_cost_elems << OpenStudio::Attribute.new('electricity_demand_charge', electric_demand_charge, 'dollars')
788
- @runner.registerValue('annual_utility_cost_electricity_demand_charge', electric_demand_charge, 'dollars')
789
-
790
- # gas
791
- gas = @sql.annualTotalCost(OpenStudio::FuelType.new('Gas'))
792
- if gas.is_initialized
793
- annual_utility_cost_map[OpenStudio::EndUseFuelType.new('Gas').valueName] = gas.get
794
- else
795
- annual_utility_cost_map[OpenStudio::EndUseFuelType.new('Gas').valueName] = 0.0
796
- end
797
-
798
- # district_cooling
799
- district_cooling_charge = 0.0
800
-
801
- district_cooling_rate_query = "SELECT value FROM tabulardatawithstrings WHERE ReportName='LEEDsummary' AND ReportForString='Entire Facility' AND TableName='EAp2-3. Energy Type Summary' AND RowName='District Cooling' AND ColumnName='Utility Rate'"
802
- district_cooling_rate_name = @sql.execAndReturnFirstString(district_cooling_rate_query)
803
- if district_cooling_rate_name.is_initialized
804
- district_cooling_rate_name = district_cooling_rate_name.get.strip
805
-
806
- # district_cooling_charge
807
- district_cooling_charge_query = "SELECT value FROM tabulardatawithstrings WHERE ReportName='Tariff Report' AND ReportForString='#{district_cooling_rate_name}' AND TableName='Categories' AND RowName='Basis (~~$~~)' AND ColumnName='Sum'"
808
- val = @sql.execAndReturnFirstDouble(district_cooling_charge_query)
809
- if val.is_initialized
810
- district_cooling_charge = val.get
811
- end
812
-
813
- end
814
- annual_utility_cost_map[OpenStudio::EndUseFuelType.new('DistrictCooling').valueName] = district_cooling_charge
815
-
816
- # district_heating
817
- district_heating_charge = 0.0
818
-
819
- district_heating_rate_query = "SELECT value FROM tabulardatawithstrings WHERE ReportName='LEEDsummary' AND ReportForString='Entire Facility' AND TableName='EAp2-3. Energy Type Summary' AND RowName='District Heating' AND ColumnName='Utility Rate'"
820
- district_heating_rate_name = @sql.execAndReturnFirstString(district_heating_rate_query)
821
- if district_heating_rate_name.is_initialized
822
- district_heating_rate_name = district_heating_rate_name.get.strip
823
-
824
- # district_heating_charge
825
- district_heating_charge_query = "SELECT value FROM tabulardatawithstrings WHERE ReportName='Tariff Report' AND ReportForString='#{district_heating_rate_name}' AND TableName='Categories' AND RowName='Basis (~~$~~)' AND ColumnName='Sum'"
826
- val = @sql.execAndReturnFirstDouble(district_heating_charge_query)
827
- if val.is_initialized
828
- district_heating_charge = val.get
829
- end
830
-
831
- end
832
- annual_utility_cost_map[OpenStudio::EndUseFuelType.new('DistrictHeating').valueName] = district_heating_charge
833
-
834
- # water
835
- water = @sql.annualTotalCost(OpenStudio::FuelType.new('Water'))
836
- if water.is_initialized
837
- annual_utility_cost_map[OpenStudio::EndUseFuelType.new('Water').valueName] = water.get
838
- else
839
- annual_utility_cost_map[OpenStudio::EndUseFuelType.new('Water').valueName] = 0.0
840
- end
841
-
842
- # total
843
- total_query = "SELECT Value from tabulardatawithstrings where (reportname = 'Economics Results Summary Report') and (ReportForString = 'Entire Facility') and (TableName = 'Annual Cost') and (ColumnName ='Total') and (((RowName = 'Cost') and (Units = '~~$~~')) or (RowName = 'Cost (~~$~~)'))"
844
- total = @sql.execAndReturnFirstDouble(total_query)
845
-
846
- # other_energy
847
- # Subtract off the already accounted for fuel types from the total
848
- # to account for fuels on custom meters where the fuel type is not known.
849
- prev_tot = 0.0
850
- annual_utility_cost_map.each do |fuel, val|
851
- prev_tot += val
852
- end
853
- if total.is_initialized
854
- other_val = total.get - prev_tot
855
- annual_utility_cost_map[OpenStudio::EndUseFuelType.new('AdditionalFuel').valueName] = other_val
856
- else
857
- annual_utility_cost_map[OpenStudio::EndUseFuelType.new('AdditionalFuel').valueName] = 0.0
858
- end
859
-
860
- # export remaining costs in the correct order
861
- # gas
862
- utility_cost_elems << OpenStudio::Attribute.new('gas', annual_utility_cost_map[OpenStudio::EndUseFuelType.new('Gas').valueName], 'dollars')
863
- @runner.registerValue('annual_utility_cost_gas', annual_utility_cost_map[OpenStudio::EndUseFuelType.new('Gas').valueName], 'dollars')
864
- # other_energy
865
- utility_cost_elems << OpenStudio::Attribute.new('other_energy', annual_utility_cost_map[OpenStudio::EndUseFuelType.new('AdditionalFuel').valueName], 'dollars')
866
- @runner.registerValue('annual_utility_cost_other_energy', annual_utility_cost_map[OpenStudio::EndUseFuelType.new('AdditionalFuel').valueName], 'dollars')
867
- # district_cooling
868
- utility_cost_elems << OpenStudio::Attribute.new('district_cooling', annual_utility_cost_map[OpenStudio::EndUseFuelType.new('DistrictCooling').valueName], 'dollars')
869
- @runner.registerValue('annual_utility_cost_district_cooling', annual_utility_cost_map[OpenStudio::EndUseFuelType.new('DistrictCooling').valueName], 'dollars')
870
- # district_heating
871
- utility_cost_elems << OpenStudio::Attribute.new('district_heating', annual_utility_cost_map[OpenStudio::EndUseFuelType.new('DistrictHeating').valueName], 'dollars')
872
- @runner.registerValue('annual_utility_cost_district_heating', annual_utility_cost_map[OpenStudio::EndUseFuelType.new('DistrictHeating').valueName], 'dollars')
873
- # water
874
- utility_cost_elems << OpenStudio::Attribute.new('water', annual_utility_cost_map[OpenStudio::EndUseFuelType.new('Water').valueName], 'dollars')
875
- @runner.registerValue('annual_utility_cost_water', annual_utility_cost_map[OpenStudio::EndUseFuelType.new('Water').valueName], 'dollars')
876
- # total
877
- if total.is_initialized
878
- utility_cost_elems << OpenStudio::Attribute.new('total', total.get, 'dollars')
879
- @runner.registerValue('annual_utility_cost_total', total.get, 'dollars')
880
- else
881
- utility_cost_elems << OpenStudio::Attribute.new('total', 0.0, 'dollars')
882
- @runner.registerValue('annual_utility_cost_total', 0.0, 'dollars')
883
- end
884
-
885
- # end_uses - utility costs by end use using average blended cost
886
- end_uses_elems = OpenStudio::AttributeVector.new
887
- # map to store the costs by end use
888
- cost_by_end_use = {}
889
-
890
- # fill the map with 0.0's to start
891
- end_use_cat_types.each do |end_use_cat_type|
892
- cost_by_end_use[end_use_cat_type] = 0.0
893
- end
894
-
895
- # only attempt to get monthly data if enduses table is available
896
- if @sql.endUses.is_initialized
897
- end_uses_table = @sql.endUses.get
898
- # loop through all the fuel types
899
- end_use_fuel_types.each do |end_use_fuel_type|
900
- # get the annual total cost for this fuel type
901
- ann_cost = annual_utility_cost_map[end_use_fuel_type.valueName]
902
- # get the total annual usage for this fuel type in all end use categories
903
- # loop through all end uses, adding the annual usage value to the aggregator
904
- ann_usg = 0.0
905
- end_use_cat_types.each do |end_use_cat_type|
906
- ann_usg += end_uses_table.getEndUse(end_use_fuel_type, end_use_cat_type)
907
- end
908
- # figure out the annual blended rate for this fuel type
909
- avg_ann_rate = 0.0
910
- if ann_cost > 0 && ann_usg > 0
911
- avg_ann_rate = ann_cost / ann_usg
912
- end
913
- # for each end use category, figure out the cost if using
914
- # the avg ann rate; add this cost to the map
915
- end_use_cat_types.each do |end_use_cat_type|
916
- cost_by_end_use[end_use_cat_type] += end_uses_table.getEndUse(end_use_fuel_type, end_use_cat_type) * avg_ann_rate
917
- end
918
- end
919
- # loop through the end uses and record the annual total cost based on the avg annual rate
920
- end_use_cat_types.each do |end_use_cat_type|
921
- # record the value
922
- end_uses_elems << OpenStudio::Attribute.new(end_use_map[end_use_cat_type.value], cost_by_end_use[end_use_cat_type], 'dollars')
923
- @runner.registerValue("annual_utility_cost_end_uses_#{end_use_map[end_use_cat_type.value]}", cost_by_end_use[end_use_cat_type], 'dollars')
924
- end
925
- else
926
- @runner.registerError('End-Use table not available in results; could not retrieve monthly costs by end use')
927
- return OpenStudio::Attribute.new('report', result_elems)
928
- end
929
-
930
- # end end_uses
931
- utility_cost_elems << OpenStudio::Attribute.new('end_uses', end_uses_elems)
932
-
933
- # end utility_costs
934
- annual_elems << OpenStudio::Attribute.new('utility_cost', utility_cost_elems)
935
-
936
- # end annual
937
- result_elems << OpenStudio::Attribute.new('annual', annual_elems)
938
-
939
- # monthly
940
- monthly_elems = OpenStudio::AttributeVector.new
941
-
942
- # consumption
943
- cons_elems = OpenStudio::AttributeVector.new
944
- # loop through all end uses
945
- end_use_cat_types.each do |end_use_cat|
946
- end_use_elems = OpenStudio::AttributeVector.new
947
- end_use_name = end_use_map[end_use_cat.value]
948
- # in each end use, loop through all fuel types
949
- end_use_fuel_types.each do |end_use_fuel_type|
950
- fuel_type_elems = OpenStudio::AttributeVector.new
951
- fuel_type_name = fuel_type_alias_map[end_use_fuel_type.value]
952
- ann_energy_cons = 0.0
953
- # in each end use, loop through months and get monthly enedy consumption
954
- months.each_with_index do |month, i|
955
- mon_energy_cons = 0.0
956
- val = @sql.energyConsumptionByMonth(end_use_fuel_type, end_use_cat, month)
957
- if val.is_initialized
958
- monthly_consumption_J = OpenStudio::Quantity.new(val.get, joule_unit)
959
- monthly_consumption_GJ = OpenStudio.convert(monthly_consumption_J, gigajoule_unit).get.value
960
- mon_energy_cons = monthly_consumption_GJ
961
- ann_energy_cons += monthly_consumption_GJ
962
- end
963
- # record the monthly value
964
- if end_use_fuel_type == OpenStudio::EndUseFuelType.new('Water')
965
- fuel_type_elems << OpenStudio::Attribute.new('month', mon_energy_cons, 'm^3')
966
- @runner.registerValue("monthly_consumption_#{end_use_name}_#{fuel_type_name}_month_#{i + 1}", mon_energy_cons, 'm^3')
967
- else
968
- fuel_type_elems << OpenStudio::Attribute.new('month', mon_energy_cons, 'GJ')
969
- @runner.registerValue("monthly_consumption_#{end_use_name}_#{fuel_type_name}_month_#{i + 1}", mon_energy_cons, 'GJ')
970
- end
971
- end
972
- # record the annual total
973
- fuel_type_elems << OpenStudio::Attribute.new('year', ann_energy_cons, 'GJ')
974
- @runner.registerValue("monthly_consumption_#{end_use_name}_#{fuel_type_name}_year", ann_energy_cons, 'GJ')
975
- # add this fuel type
976
- end_use_elems << OpenStudio::Attribute.new(fuel_type_alias_map[end_use_fuel_type.value], fuel_type_elems)
977
- end
978
- # add this end use
979
- cons_elems << OpenStudio::Attribute.new(end_use_map[end_use_cat.value], end_use_elems)
980
- end
981
- # end consumption
982
- monthly_elems << OpenStudio::Attribute.new('consumption', cons_elems)
983
-
984
- # create a unit to use
985
- watt_unit = OpenStudio.createUnit('W').get
986
- kilowatt_unit = OpenStudio.createUnit('kW').get
987
-
988
- # demand
989
- demand_elems = OpenStudio::AttributeVector.new
990
- # loop through all end uses
991
- end_use_cat_types.each do |end_use_cat|
992
- end_use_elems = OpenStudio::AttributeVector.new
993
- end_use_name = end_use_map[end_use_cat.value]
994
- # in each end use, loop through all fuel types
995
- end_use_fuel_types.each do |end_use_fuel_type|
996
- fuel_type_elems = OpenStudio::AttributeVector.new
997
- fuel_type_name = fuel_type_alias_map[end_use_fuel_type.value]
998
- ann_peak_demand = 0.0
999
- # in each end use, loop through months and get monthly enedy consumption
1000
- months.each_with_index do |month, i|
1001
- mon_peak_demand = 0.0
1002
- val = @sql.peakEnergyDemandByMonth(end_use_fuel_type, end_use_cat, month)
1003
- if val.is_initialized
1004
- mon_peak_demand_W = OpenStudio::Quantity.new(val.get, watt_unit)
1005
- mon_peak_demand = OpenStudio.convert(mon_peak_demand_W, kilowatt_unit).get.value
1006
- end
1007
- # record the monthly value
1008
- fuel_type_elems << OpenStudio::Attribute.new('month', mon_peak_demand, 'kW')
1009
- @runner.registerValue("monthly_demand_#{end_use_name}_#{fuel_type_name}_month_#{i + 1}", mon_peak_demand, 'kW')
1010
- # if month peak demand > ann peak demand make this new ann peak demand
1011
- if mon_peak_demand > ann_peak_demand
1012
- ann_peak_demand = mon_peak_demand
1013
- end
1014
- end
1015
- # record the annual peak demand
1016
- fuel_type_elems << OpenStudio::Attribute.new('year', ann_peak_demand, 'kW')
1017
- @runner.registerValue("monthly_demand_#{end_use_name}_#{fuel_type_name}_year", ann_peak_demand, 'kW')
1018
- # add this fuel type
1019
- end_use_elems << OpenStudio::Attribute.new(fuel_type_alias_map[end_use_fuel_type.value], fuel_type_elems)
1020
- end
1021
- # add this end use
1022
- demand_elems << OpenStudio::Attribute.new(end_use_map[end_use_cat.value], end_use_elems)
1023
- end
1024
- # end demand
1025
- monthly_elems << OpenStudio::Attribute.new('demand', demand_elems)
1026
-
1027
- # end monthly
1028
- result_elems << OpenStudio::Attribute.new('monthly', monthly_elems)
1029
-
1030
- result_elem = OpenStudio::Attribute.new('results', result_elems)
1031
- return result_elem
1032
- end # end create_results
1033
- end