openstudio-extension 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
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 +18 -75
  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