urbanopt-reopt 1.0.0 → 1.2.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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/nightly_ci_build.yml +1 -1
  3. data/CHANGELOG.md +11 -0
  4. data/CONTRIBUTING.md +3 -3
  5. data/Gemfile +24 -19
  6. data/LICENSE.md +1 -1
  7. data/RDOC_MAIN.md +2 -2
  8. data/README.md +2 -2
  9. data/Rakefile +1 -1
  10. data/developer_nrel_key.rb +1 -1
  11. data/doc_templates/LICENSE.md +1 -1
  12. data/doc_templates/copyright_erb.txt +1 -1
  13. data/doc_templates/copyright_js.txt +1 -1
  14. data/doc_templates/copyright_ruby.txt +1 -1
  15. data/docs/README.md +2 -2
  16. data/docs/package.json +1 -1
  17. data/index.md +2 -2
  18. data/lib/urbanopt/reopt/extension.rb +1 -1
  19. data/lib/urbanopt/reopt/feature_report_adapter.rb +10 -11
  20. data/lib/urbanopt/reopt/{reopt_ghp_adapter.rb → reopt_ghp_adapter_ghp.rb} +238 -48
  21. data/lib/urbanopt/reopt/reopt_ghp_api.rb +3 -3
  22. data/lib/urbanopt/reopt/reopt_ghp_files/reopt_ghp_assumption.json +3 -3
  23. data/lib/urbanopt/reopt/reopt_ghp_post_processor.rb +13 -4
  24. data/lib/urbanopt/reopt/reopt_ghp_result.rb +145 -0
  25. data/lib/urbanopt/reopt/reopt_lite_api.rb +54 -13
  26. data/lib/urbanopt/reopt/reopt_logger.rb +1 -1
  27. data/lib/urbanopt/reopt/reopt_post_processor.rb +54 -18
  28. data/lib/urbanopt/reopt/reopt_schema/REopt-BAU-input.json +174 -0
  29. data/lib/urbanopt/reopt/reopt_schema/REopt-GHP-input.json +263 -95
  30. data/lib/urbanopt/reopt/scenario/reopt_scenario_csv.rb +1 -1
  31. data/lib/urbanopt/reopt/scenario_report_adapter.rb +8 -9
  32. data/lib/urbanopt/reopt/utilities.rb +1 -1
  33. data/lib/urbanopt/reopt/version.rb +2 -2
  34. data/lib/urbanopt/reopt.rb +3 -2
  35. data/lib/urbanopt/reopt_scenario.rb +1 -1
  36. data/lib/urbanopt-reopt.rb +1 -1
  37. data/urbanopt-reopt.gemspec +6 -3
  38. metadata +53 -9
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt (tm), Copyright (c) Alliance for Sustainable Energy, LLC.
2
+ # URBANopt (tm), Copyright (c) Alliance for Energy Innovation, LLC.
3
3
  # See also https://github.com/urbanopt/urbanopt-reopt-gem/blob/develop/LICENSE.md
4
4
  # *********************************************************************************
5
5
 
@@ -10,11 +10,16 @@ module URBANopt # :nodoc:
10
10
  def initialize
11
11
  # initialize @@logger
12
12
  @@logger ||= URBANopt::REopt.reopt_logger
13
- # Define class variable
13
+ # Define class variables
14
14
  @@hours_in_year = 8760
15
+ @@nat_gas_dollars_per_mmbtu = 13.5
16
+ @@year_of_simulation = 2023
17
+ @@year_of_simulation = 2023
18
+ @@small_multiplier = [0.00001]
19
+
15
20
  end
16
21
 
17
- def create_reopt_input_building(run_dir, system_parameter_hash, reopt_ghp_assumptions_hash, building_id, modelica_result)
22
+ def create_reopt_input_building_ghp(run_dir, system_parameter_hash, reopt_ghp_assumptions_hash, building_id, modelica_result)
18
23
 
19
24
  # Define variables
20
25
  reopt_inputs_building = {}
@@ -28,9 +33,6 @@ module URBANopt # :nodoc:
28
33
  SpaceHeatingLoad: {},
29
34
  DomesticHotWaterLoad: {},
30
35
  ElectricLoad: {},
31
- ElectricTariff: {
32
- urdb_label: ""
33
- },
34
36
  GHP: {},
35
37
  ExistingBoiler: {}
36
38
  }
@@ -38,7 +40,7 @@ module URBANopt # :nodoc:
38
40
 
39
41
  # The URDB label is required to be specified in the input assumption file
40
42
  if reopt_inputs_building[:ElectricTariff][:urdb_label].nil? || reopt_inputs_building[:ElectricTariff][:urdb_label].empty?
41
- raise "Missing value for urdb_label - this is a required input"
43
+ raise "Missing value for urdb_label - this is a required input"
42
44
  end
43
45
 
44
46
  scenario_json_path = File.join(run_dir, "default_scenario_report.json")
@@ -50,7 +52,6 @@ module URBANopt # :nodoc:
50
52
  @longitude = scenario_json_data[:scenario_report][:location][:longitude_deg]
51
53
  reopt_inputs_building[:Site][:latitude] = @latitude
52
54
  reopt_inputs_building[:Site][:longitude] = @longitude
53
-
54
55
  end
55
56
  end
56
57
 
@@ -72,8 +73,8 @@ module URBANopt # :nodoc:
72
73
  end
73
74
  # Check if the total kBtu is zero
74
75
  if total_kbtu.zero?
75
- # If zero, populate with hourly values meet reopts formatting requirements
76
- reopt_inputs_building[:SpaceHeatingLoad][:fuel_loads_mmbtu_per_hour] = [0.000001] * @@hours_in_year
76
+ # If zero, populate with near zero hourly values to meet reopts formatting requirements
77
+ reopt_inputs_building[:SpaceHeatingLoad][:fuel_loads_mmbtu_per_hour] = @@small_multiplier * @@hours_in_year
77
78
  else
78
79
  # If not zero, convert and append to the array
79
80
  timeseries_data.each do |row|
@@ -86,8 +87,8 @@ module URBANopt # :nodoc:
86
87
  end
87
88
 
88
89
  else
89
- # Calculate space heating load
90
- reopt_inputs_building[:SpaceHeatingLoad][:fuel_loads_mmbtu_per_hour] = [0.000001] * @@hours_in_year
90
+ # populate with near zero hourly values to meet reopts formatting requirements
91
+ reopt_inputs_building[:SpaceHeatingLoad][:fuel_loads_mmbtu_per_hour] = @@small_multiplier * @@hours_in_year
91
92
  puts "Existing heating fuel cost was not taken into consideration in result calculations."
92
93
  end
93
94
 
@@ -103,12 +104,21 @@ module URBANopt # :nodoc:
103
104
 
104
105
  if File.exist?(@modelica_csv)
105
106
  modelica_data = CSV.read(@modelica_csv, headers: true)
106
- heating_power = "heating_electric_power_#{building_id}"
107
- cooling_power = "cooling_electric_power_#{building_id}"
107
+ heating_power_header = modelica_data.headers.select{ |h| h.to_s.start_with?("heating_electric_power") }
108
+ prefix = ""
109
+
110
+ if heating_power_header[0].split("_")[-1].include? ("B")
111
+ prefix = "B"
112
+ else
113
+ prefix = ""
114
+ end
115
+
116
+ heating_power = "heating_electric_power_#{prefix}#{building_id}"
117
+ cooling_power = "cooling_electric_power_#{prefix}#{building_id}"
118
+ ets_pump_power = "ets_pump_power_#{prefix}#{building_id}"
119
+ heating_system_capacity = "heating_system_capacity_#{prefix}#{building_id}"
120
+ cooling_system_capacity = "cooling_system_capacity_#{prefix}#{building_id}"
108
121
  pump_power = "pump_power_#{building_id}"
109
- ets_pump_power = "ets_pump_power_#{building_id}"
110
- heating_system_capacity = "heating_system_capacity_#{building_id}"
111
- cooling_system_capacity = "cooling_system_capacity_#{building_id}"
112
122
 
113
123
  heating_power_values = cooling_power_values = pump_power_values = ets_pump_power_values = []
114
124
  total_electric_load_building = []
@@ -130,7 +140,6 @@ module URBANopt # :nodoc:
130
140
  # Convert watts to kilowatts
131
141
  elements.map { |e| e.to_f / 1000 }.sum
132
142
  end
133
-
134
143
  peak_combined_heatpump_thermal_ton = 0
135
144
 
136
145
  if modelica_data.headers.include?(heating_system_capacity)
@@ -139,13 +148,13 @@ module URBANopt # :nodoc:
139
148
  if modelica_data.headers.include?(cooling_system_capacity)
140
149
  cooling_system_capacity_value = modelica_data[cooling_system_capacity][0]
141
150
  end
142
-
151
+
143
152
  watts_per_ton_cooling_capacity = 3517
144
153
  peak_combined_heatpump_thermal_ton = ([heating_system_capacity_value.to_f.abs, cooling_system_capacity_value.to_f.abs].max) / watts_per_ton_cooling_capacity
145
154
 
146
155
  # Store the result in reopt_inputs_building ElectricLoad
147
156
  reopt_inputs_building[:ElectricLoad][:loads_kw] = total_electric_load_building
148
-
157
+ reopt_inputs_building[:ElectricLoad][:year] = @@year_of_simulation
149
158
 
150
159
  domestic_hot_water = total_electric_load_building.map do |load|
151
160
  load * 0
@@ -156,16 +165,29 @@ module URBANopt # :nodoc:
156
165
 
157
166
  # Add GHP Fields
158
167
  reopt_inputs_building[:GHP] = {}
168
+
169
+ # Add avoided capital cost of all buildings
170
+ if reopt_inputs_building[:features] && !reopt_inputs_building[:features].empty?
171
+ # Find the feature matching this building_id
172
+ matching_feature = reopt_inputs_building[:features].find { |feature| feature[:feature_id] == building_id.to_i}
173
+
174
+ if matching_feature
175
+ # Set avoided capex value into GHP block
176
+ reopt_inputs_building[:GHP][:avoided_capex_by_ghp_present_value] = matching_feature[:avoided_capex_by_ghp_present_value]
177
+ end
178
+ end
159
179
  # REopt default
160
180
  reopt_inputs_building[:GHP][:require_ghp_purchase] = 1
161
181
  reopt_inputs_building[:GHP][:om_cost_per_sqft_year] = 0
162
182
  reopt_inputs_building[:GHP][:heatpump_capacity_sizing_factor_on_peak_load] = 1.0
163
183
  # Add the floor area
164
184
  building_json_path = File.join(run_dir, building_id.to_s, "feature_reports", "default_feature_report.json")
185
+
165
186
  if File.exist?(building_json_path)
187
+ puts building_json_path
166
188
  File.open(building_json_path, 'r') do |file|
167
189
  building_json_data = JSON.parse(file.read, symbolize_names: true)
168
- reopt_inputs_building[:GHP][:building_sqft] = building_json_data[:program][:floor_area_sqft]
190
+ reopt_inputs_building[:GHP][:building_sqft] = building_json_data[:program][:footprint_area_sqft].to_f
169
191
  end
170
192
  else
171
193
  puts "File not found: #{building_json_path}"
@@ -173,8 +195,8 @@ module URBANopt # :nodoc:
173
195
 
174
196
  # Add existing boiler fuel cost
175
197
  # TODO : Add this as optional user input
176
- nat_gas_dollars_per_mmbtu = 13.5
177
- reopt_inputs_building[:ExistingBoiler][:fuel_cost_per_mmbtu] = nat_gas_dollars_per_mmbtu
198
+ # Cost of Natural Gas in $/mmbtu as per REopt Defaults
199
+ reopt_inputs_building[:ExistingBoiler][:fuel_cost_per_mmbtu] = @@nat_gas_dollars_per_mmbtu
178
200
 
179
201
  # Add ghpghx_responses
180
202
  ghpghx_output = {}
@@ -192,7 +214,8 @@ module URBANopt # :nodoc:
192
214
  ghpghx_output[:outputs][:yearly_heating_heatpump_electric_consumption_series_kw] = total_electric_load_building
193
215
  ghpghx_output[:outputs][:yearly_cooling_heatpump_electric_consumption_series_kw] = [0] * @@hours_in_year
194
216
  # This is not used in REopt calculation but required for formatting.
195
- ghpghx_output[:inputs][:heating_thermal_load_mmbtu_per_hr] = [0.0001] * @@hours_in_year
217
+ # populate with near zero hourly values to meet reopts formatting requirements
218
+ ghpghx_output[:inputs][:heating_thermal_load_mmbtu_per_hr] = @@small_multiplier * @@hours_in_year
196
219
  # This is not used in REopt calculation but required for formatting.
197
220
  ghpghx_output[:inputs][:cooling_thermal_load_ton] = [0] * @@hours_in_year
198
221
 
@@ -210,7 +233,7 @@ module URBANopt # :nodoc:
210
233
 
211
234
  end
212
235
 
213
- def create_reopt_input_district(run_dir, system_parameter_hash, reopt_ghp_assumptions_hash, ghp_id, modelica_result)
236
+ def create_reopt_input_district_ghp(run_dir, system_parameter_hash, reopt_ghp_assumptions_hash, ghp_id, modelica_result)
214
237
 
215
238
  reopt_inputs_district = {}
216
239
 
@@ -238,27 +261,29 @@ module URBANopt # :nodoc:
238
261
  # The URDB label is required to be specified in the input assumption file
239
262
  if reopt_inputs_district[:ElectricTariff][:urdb_label].nil? || reopt_inputs_district[:ElectricTariff][:urdb_label].empty?
240
263
 
241
- raise "Missing value for urdb_label - this is a required input"
264
+ raise "Missing value for urdb_label - this is a required input"
242
265
 
243
266
  end
244
-
267
+ # populate with near zero hourly values to meet reopts formatting requirements
245
268
  # This is not used in REopt calculation but required for formatting.
246
- reopt_inputs_district[:SpaceHeatingLoad][:fuel_loads_mmbtu_per_hour] = [0.000001]*@@hours_in_year
269
+ reopt_inputs_district[:SpaceHeatingLoad][:fuel_loads_mmbtu_per_hour] = @@small_multiplier*@@hours_in_year
270
+ # populate with near zero hourly values to meet reopts formatting requirements
247
271
  # This is not used in REopt calculation but required for formatting.
248
- reopt_inputs_district[:DomesticHotWaterLoad][:fuel_loads_mmbtu_per_hour] = [0.0000001]*@@hours_in_year
272
+ reopt_inputs_district[:DomesticHotWaterLoad][:fuel_loads_mmbtu_per_hour] = @@small_multiplier*@@hours_in_year
249
273
 
250
- # Adding year for ElectricLoad so district electric load can be calculated with REopt API v3.11
251
- reopt_inputs_district[:ElectricLoad] = {:year => 2017}
252
- #required for reopt formatting
253
- reopt_inputs_district[:ElectricLoad][:loads_kw] = [0.00001]*@@hours_in_year
274
+ reopt_inputs_district[:ElectricLoad] = {}
275
+ # populate with near zero hourly values to meet reopts formatting requirements
276
+ # This is not used in REopt calculation but required for formatting.
277
+ reopt_inputs_district[:ElectricLoad][:loads_kw] = @@small_multiplier*@@hours_in_year
278
+ reopt_inputs_district[:ElectricLoad][:year] = @@year_of_simulation
254
279
 
255
280
  reopt_inputs_district[:ExistingBoiler] = {}
256
- reopt_inputs_district[:ExistingBoiler][:fuel_cost_per_mmbtu] = 13.5
281
+ reopt_inputs_district[:ExistingBoiler][:fuel_cost_per_mmbtu] = @@nat_gas_dollars_per_mmbtu
257
282
 
258
283
  # GHP inputs
259
284
  reopt_inputs_district[:GHP] = {}
260
285
  reopt_inputs_district[:GHP][:require_ghp_purchase] = 1
261
- reopt_inputs_district[:GHP][:building_sqft] = 0.00001
286
+ reopt_inputs_district[:GHP][:building_sqft] = format('%.8f', @@small_multiplier[0]).to_f
262
287
  reopt_inputs_district[:GHP][:om_cost_per_sqft_year] = 0
263
288
  reopt_inputs_district[:GHP][:heatpump_capacity_sizing_factor_on_peak_load] = 1.0
264
289
 
@@ -272,15 +297,39 @@ module URBANopt # :nodoc:
272
297
 
273
298
 
274
299
  # Read GHX sizes from system parameter hash
275
- ghe_specific_params = system_parameter_hash[:district_system][:fifth_generation][:ghe_parameters][:ghe_specific_params]
276
- ghe_specific_params.each do |ghe_specific_param|
277
- if ghe_specific_param[:ghe_id] = ghp_id
278
- number_of_boreholes = ghe_specific_param[:borehole][:number_of_boreholes]
279
- length_of_boreholes = ghe_specific_param[:borehole][:length_of_boreholes]
280
- ghpghx_output[:outputs][:number_of_boreholes] = number_of_boreholes
281
- # convert meters to feet
282
- ghpghx_output[:outputs][:length_boreholes_ft] = (length_of_boreholes)*3.28084
283
- end
300
+ ghe_specific_params = system_parameter_hash[:district_system][:fifth_generation][:ghe_parameters][:borefields]
301
+
302
+ ghe_specific_params.each do |ghe|
303
+ if ghe[:ghe_id] == ghp_id
304
+ unless ghe[:pre_designed_borefield]
305
+ if ghe[:autosized_rectangle_borefield]
306
+ borefield = ghe[:autosized_rectangle_borefield]
307
+
308
+ elsif ghe[:autosized_rectangle_constrained_borefield]
309
+ borefield = ghe[:autosized_rectangle_constrained_borefield]
310
+
311
+ elsif ghe[:autosized_birectangle_borefield]
312
+ borefield = ghe[:autosized_birectangle_borefield]
313
+
314
+ elsif ghe[:autosized_birectangle_constrained_borefield]
315
+ borefield = ghe[:autosized_birectangle_constrained_borefield]
316
+
317
+ elsif ghe[:autosized_bizoned_rectangle_borefield]
318
+ borefield = ghe[:autosized_bizoned_rectangle_borefield]
319
+
320
+ elsif ghe[:autosized_near_square_borefield]
321
+ borefield = ghe[:autosized_near_square_borefield]
322
+
323
+ elsif ghe[:autosized_rowwise_borefield]
324
+ borefield = ghe[:autosized_rowwise_borefield]
325
+ end
326
+ end
327
+
328
+ ghpghx_output[:outputs][:number_of_boreholes] = borefield[:number_of_boreholes]
329
+ # convert meters to feet by multiplying with 3.28084
330
+ ghpghx_output[:outputs][:length_boreholes_ft] = (borefield[:borehole_length])*3.28084
331
+
332
+ end
284
333
  end
285
334
 
286
335
  if File.exist?(@modelica_csv)
@@ -309,16 +358,19 @@ module URBANopt # :nodoc:
309
358
  # column_values = modelica_data.by_col[ghp_column]
310
359
 
311
360
  ghpghx_output[:outputs][:yearly_ghx_pump_electric_consumption_series_kw] = electrical_power_consumed_kw
312
- else
313
- ghpghx_output[:outputs][:yearly_ghx_pump_electric_consumption_series_kw] = [0.000000001]*@@hours_in_year
361
+ else
362
+ # populate with near zero hourly values to meet reopts formatting requirements
363
+ # This is not used in REopt calculation but required for formatting.
364
+ ghpghx_output[:outputs][:yearly_ghx_pump_electric_consumption_series_kw] = @@small_multiplier*@@hours_in_year
314
365
  end
315
366
 
316
367
  # This is not used in REopt calculation but required for formatting.
317
368
  ghpghx_output[:outputs][:peak_combined_heatpump_thermal_ton] = 0.000000001
318
369
 
319
370
  ghpghx_output[:outputs][:heat_pump_configuration] = "WSHP"
320
- # Required for REpot formatting
321
- ghpghx_output[:outputs][:yearly_total_electric_consumption_series_kw] = [0.00001] * @@hours_in_year
371
+ # populate with near zero hourly values to meet reopts formatting requirements
372
+ # This is not used in REopt calculation but required for formatting.
373
+ ghpghx_output[:outputs][:yearly_total_electric_consumption_series_kw] = @@small_multiplier * @@hours_in_year
322
374
  ghpghx_output[:outputs][:yearly_heating_heatpump_electric_consumption_series_kw] = [0] * @@hours_in_year
323
375
  ghpghx_output[:outputs][:yearly_cooling_heatpump_electric_consumption_series_kw] = [0] * @@hours_in_year
324
376
 
@@ -332,6 +384,144 @@ module URBANopt # :nodoc:
332
384
  File.write(json_file_path, pretty_json)
333
385
  end
334
386
 
387
+ def create_reopt_input_building_bau(run_dir, system_parameter_hash, reopt_ghp_assumptions_hash, building_id, modelica_result)
388
+ reopt_inputs_building_bau = {}
389
+ if !reopt_ghp_assumptions_hash.nil?
390
+ reopt_inputs_building_bau = reopt_ghp_assumptions_hash
391
+ else
392
+ @@logger.info('Using default REopt assumptions')
393
+ # create a dictionary for REopt Inputs
394
+ reopt_inputs_building_bau = {
395
+ Site: {},
396
+ SpaceHeatingLoad: {},
397
+ DomesticHotWaterLoad: {},
398
+ ElectricLoad: {},
399
+ ElectricTariff: {
400
+ urdb_label: ""
401
+ },
402
+ ExistingBoiler: {}
403
+ }
404
+ end
405
+
406
+ # The URDB label is required to be specified in the input assumption file
407
+ if reopt_inputs_building_bau.nil? || reopt_inputs_building_bau[:ElectricTariff].nil? || reopt_inputs_building_bau[:ElectricTariff][:urdb_label].nil? || reopt_inputs_building_bau[:ElectricTariff][:urdb_label].empty?
408
+ raise "Missing value for urdb_label - this is a required input"
409
+ end
410
+
411
+ scenario_json_path = File.join(run_dir, "default_scenario_report.json")
412
+ if File.exist?(scenario_json_path)
413
+ File.open(scenario_json_path, 'r') do |file|
414
+ scenario_json_data = JSON.parse(file.read, symbolize_names: true)
415
+ # update site location
416
+ @latitude = scenario_json_data[:scenario_report][:location][:latitude_deg]
417
+ @longitude = scenario_json_data[:scenario_report][:location][:longitude_deg]
418
+ reopt_inputs_building_bau[:Site][:latitude] = @latitude
419
+ reopt_inputs_building_bau[:Site][:longitude] = @longitude
420
+
421
+ end
422
+ end
423
+
424
+ reopt_inputs_building_bau[:SpaceHeatingLoad][:fuel_loads_mmbtu_per_hour] = []
425
+ # Read the default csv report
426
+ default_feature_report_path = File.join(run_dir, building_id.to_s, "feature_reports", "default_feature_report.csv")
427
+ if File.exist?(default_feature_report_path)
428
+ timeseries_data = CSV.read(default_feature_report_path, headers: true)
429
+
430
+ # Initialize the total kBtu sum
431
+ heating_kbtu = 0.0
432
+ cooling_kbtu = 0.0
433
+ total_kwh_heating = 0.0
434
+ total_kwh_cooling = 0.0
435
+
436
+ # TODO : add other Heating Fuels if present (Heating:Propane(kBtu) etc.)
437
+ # Convert each value in "Heating:NaturalGas(kBtu)" to MMBtu and store in the array
438
+ timeseries_data.each do |row|
439
+ if row['Heating:NaturalGas(kBtu)'] # Ensure the value exists
440
+ heating_kBtu_value = row['Heating:NaturalGas(kBtu)'].to_f # Convert to float
441
+ heating_kbtu += heating_kBtu_value # Sum kBtu values
442
+ end
443
+ if row.headers.include?('Cooling:NaturalGas(kBtu)') && row['Cooling:NaturalGas(kBtu)']
444
+ cooling_kBtu_value = row['Cooling:NaturalGas(kBtu)'].to_f # Convert to float
445
+ cooling_kbtu += cooling_kBtu_value
446
+ end
447
+ if row['Heating:Electricity(kWh)']
448
+ heating_value = row['Heating:Electricity(kWh)'].to_f # Convert to float
449
+ total_kwh_heating += heating_value # Sum heating values
450
+ end
451
+ if row['Cooling:Electricity(kWh)']
452
+ cooling_value = row['Cooling:Electricity(kWh)'].to_f # Convert to float
453
+ total_kwh_cooling += cooling_value # Sum cooling values
454
+ end
455
+ end
456
+ # Check if the heating kBtu is zero
457
+ if heating_kbtu.zero?
458
+ # If zero, populate with near zero hourly values to meet reopts formatting requirements
459
+ reopt_inputs_building_bau[:SpaceHeatingLoad][:fuel_loads_mmbtu_per_hour] = @@small_multiplier * @@hours_in_year
460
+ else
461
+ # If not zero, convert and append to the array
462
+ timeseries_data.each do |row|
463
+ if row['Heating:NaturalGas(kBtu)'] # Ensure the value exists
464
+ kBtu_value = row['Heating:NaturalGas(kBtu)'].to_f # Convert to float
465
+ mMBtu_value = kBtu_value / 1000 # Convert kBtu to MMBtu
466
+ reopt_inputs_building_bau[:SpaceHeatingLoad][:fuel_loads_mmbtu_per_hour] << mMBtu_value # Append to the array
467
+ end
468
+ end
469
+ # Add fuel cost for existing boiler
470
+ reopt_inputs_building_bau[:ExistingBoiler][:fuel_cost_per_mmbtu] = @@nat_gas_dollars_per_mmbtu
471
+ end
472
+
473
+
474
+ # if cooling_kbtu.zero?
475
+ # # If zero, populate with near zero hourly values to meet reopts formatting requirements
476
+ # reopt_inputs_building_bau[:CoolingLoad][:fuel_loads_mmbtu_per_hour] = @@small_multiplier * @@hours_in_year
477
+ # else
478
+
479
+ # if there is cooling through natural gas it needs to be added to coolingload. If there is electricity based cooling, it is included in electric load
480
+ if !cooling_kbtu.zero?
481
+ # Add fuel load values for cooling
482
+ reopt_inputs_building_bau[:CoolingLoad] = {}
483
+ # If not zero, convert and append to the array
484
+ timeseries_data.each do |row|
485
+ if row['Cooling:NaturalGas(kBtu)'] # Ensure the value exists
486
+ kBtu_value = row['Cooling:NaturalGas(kBtu)'].to_f # Convert to float
487
+ ton_value = kBtu_value / 12 # Convert kBtu to ton
488
+ reopt_inputs_building_bau[:CoolingLoad][:thermal_loads_ton] << ton_value # Append to the array
489
+ end
490
+ end
491
+ # Add fuel cost for existing chiller
492
+ reopt_inputs_building_bau[:ExistingChiller][:fuel_cost_per_mmbtu] = @@nat_gas_dollars_per_mmbtu
493
+ end
494
+
495
+ total_kwh_load = total_kwh_heating + total_kwh_cooling
496
+ reopt_inputs_building_bau[:ElectricLoad][:year] = @@year_of_simulation
497
+
498
+ # Check if the total kwh is zero
499
+ if total_kwh_load.zero?
500
+ # This is the total of heating and cooling electricity loads
501
+ reopt_inputs_building_bau[:ElectricLoad][:loads_kw] = @@small_multiplier * @@hours_in_year
502
+ else
503
+ total_value_kwh = [] # Initialize the array
504
+
505
+ timeseries_data.each do |row|
506
+ heating_value_kwh = row['Heating:Electricity(kWh)'] ? row['Heating:Electricity(kWh)'].to_f : 0.0
507
+ cooling_value_kwh = row['Cooling:Electricity(kWh)'] ? row['Cooling:Electricity(kWh)'].to_f : 0.0
508
+
509
+ total = heating_value_kwh + cooling_value_kwh # Sum the values
510
+ total_value_kwh << total # Append to the array
511
+ reopt_inputs_building_bau[:ElectricLoad][:loads_kw] = total_value_kwh
512
+ end
513
+ end
514
+
515
+ end
516
+
517
+ #save output report in reopt_ghp directory
518
+ reopt_ghp_dir = File.join(run_dir, "reopt_ghp", "reopt_ghp_inputs")
519
+ json_file_path = File.join(reopt_ghp_dir, "BAU_building_#{building_id}.json")
520
+ pretty_json = JSON.pretty_generate(reopt_inputs_building_bau)
521
+ File.write(json_file_path, pretty_json)
522
+
523
+ end
524
+
335
525
  end
336
526
  end
337
527
  end
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt (tm), Copyright (c) Alliance for Sustainable Energy, LLC.
2
+ # URBANopt (tm), Copyright (c) Alliance for Energy Innovation, LLC.
3
3
  # See also https://github.com/urbanopt/urbanopt-reopt-gem/blob/develop/LICENSE.md
4
4
  # *********************************************************************************
5
5
 
@@ -22,7 +22,7 @@ module URBANopt # :nodoc:
22
22
  if [nil, '', '<insert your key here>'].include? DEVELOPER_NREL_KEY
23
23
  raise 'A developer.nrel.gov API key is required. Please see https://developer.nrel.gov/signup/ then update the file urbanopt-reopt-gem/developer_nrel_key.rb'
24
24
  else
25
- #Store the NREL developer key
25
+ #Store the NLR developer key
26
26
  nrel_developer_key = DEVELOPER_NREL_KEY
27
27
  end
28
28
  end
@@ -111,7 +111,7 @@ module URBANopt # :nodoc:
111
111
  run_id
112
112
  end
113
113
 
114
- def reopt_request(results_url, poll_interval = 5, max_timeout = 300)
114
+ def reopt_request(results_url, poll_interval = 5, max_timeout = 600)
115
115
 
116
116
  key_error_count = 0
117
117
  key_error_threshold = 3
@@ -14,9 +14,9 @@
14
14
  "urdb_label": "594976725457a37b1175d089"
15
15
  },
16
16
  "GHP":{
17
- "installed_cost_heatpump_per_ton": 1075,
18
- "installed_cost_ghx_per_ft": 14,
19
- "installed_cost_building_hydronic_loop_per_sqft": 1.7,
17
+ "installed_cost_heatpump_per_ton": 1904,
18
+ "installed_cost_ghx_per_ft": 17,
19
+ "installed_cost_building_hydronic_loop_per_sqft": 0,
20
20
  "om_cost_per_sqft_year": 0,
21
21
  "macrs_bonus_fraction": 0.6,
22
22
  "macrs_itc_reduction": 0.5,
@@ -1,11 +1,12 @@
1
1
  # *********************************************************************************
2
- # URBANopt (tm), Copyright (c) Alliance for Sustainable Energy, LLC.
2
+ # URBANopt (tm), Copyright (c) Alliance for Energy Innovation, LLC.
3
3
  # See also https://github.com/urbanopt/urbanopt-reopt-gem/blob/develop/LICENSE.md
4
4
  # *********************************************************************************
5
5
 
6
6
  require 'bundler/setup'
7
7
  require 'urbanopt/reopt/reopt_logger'
8
8
  require 'urbanopt/reopt/reopt_ghp_api'
9
+ require 'urbanopt/reopt/reopt_ghp_result'
9
10
  require 'csv'
10
11
  require 'json'
11
12
  require 'fileutils'
@@ -115,12 +116,14 @@ module URBANopt # :nodoc:
115
116
  end
116
117
 
117
118
  building_ids.each do |building_id|
118
- # create REopt building input file for all buildings in loop order list
119
- reopt_input_building = adapter.create_reopt_input_building(@run_dir, @system_parameter_input_hash, @reopt_ghp_assumptions_input_hash, building_id, @modelica_result_input)
119
+ # create REopt building input file for all buildings in loop order list in GHP scenario
120
+ reopt_input_building = adapter.create_reopt_input_building_ghp(@run_dir, @system_parameter_input_hash, @reopt_ghp_assumptions_input_hash, building_id, @modelica_result_input)
121
+ #create REopt building input file for all buildings in loop order list in BAU scenario
122
+ reopt_input_building_bau = adapter.create_reopt_input_building_bau(@run_dir, @system_parameter_input_hash, @reopt_ghp_assumptions_input_hash, building_id, @modelica_result_input)
120
123
  end
121
124
  ghp_ids.each do |ghp_id|
122
125
  # create REopt district input file
123
- reopt_input_district = adapter.create_reopt_input_district(@run_dir, @system_parameter_input_hash, @reopt_ghp_assumptions_input_hash, ghp_id, @modelica_result_input)
126
+ reopt_input_district = adapter.create_reopt_input_district_ghp(@run_dir, @system_parameter_input_hash, @reopt_ghp_assumptions_input_hash, ghp_id, @modelica_result_input)
124
127
  end
125
128
 
126
129
  Dir.foreach(reopt_ghp_input) do |input_file|
@@ -142,8 +145,14 @@ module URBANopt # :nodoc:
142
145
  # call the REopt API
143
146
  api = URBANopt::REopt::REoptLiteGHPAPI.new(reopt_input_data, DEVELOPER_NREL_KEY, reopt_output_file, @localhost)
144
147
  api.get_api_results
148
+
145
149
  end
150
+
151
+ ## POST PROCESS RESULTS
152
+ ghp_results = URBANopt::REopt::REoptGHPResult.new
153
+ results = ghp_results.result_calculate(reopt_ghp_dir)
146
154
  end
155
+
147
156
  end # REoptGHPPostProcessor
148
157
  end # REopt
149
158
  end # URBANopt