urbanopt-reporting 0.4.2 → 0.6.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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -1
  3. data/LICENSE.md +17 -17
  4. data/doc_templates/LICENSE.md +17 -17
  5. data/doc_templates/copyright_erb.txt +2 -2
  6. data/doc_templates/copyright_js.txt +2 -2
  7. data/doc_templates/copyright_ruby.txt +1 -1
  8. data/docs/package-lock.json +15717 -1407
  9. data/lib/measures/.rubocop.yml +4 -2
  10. data/lib/measures/default_feature_reports/measure.rb +101 -36
  11. data/lib/measures/export_modelica_loads/measure.rb +2 -1
  12. data/lib/measures/export_time_series_modelica/measure.rb +58 -59
  13. data/lib/measures/export_time_series_modelica/resources/os_lib_helper_methods.rb +3 -5
  14. data/lib/urbanopt/reporting/default_reports/construction_cost.rb +2 -1
  15. data/lib/urbanopt/reporting/default_reports/date.rb +2 -1
  16. data/lib/urbanopt/reporting/default_reports/distributed_generation.rb +25 -7
  17. data/lib/urbanopt/reporting/default_reports/end_use.rb +1 -1
  18. data/lib/urbanopt/reporting/default_reports/end_uses.rb +2 -1
  19. data/lib/urbanopt/reporting/default_reports/extension.rb +1 -1
  20. data/lib/urbanopt/reporting/default_reports/feature_report.rb +9 -8
  21. data/lib/urbanopt/reporting/default_reports/generator.rb +1 -2
  22. data/lib/urbanopt/reporting/default_reports/location.rb +2 -1
  23. data/lib/urbanopt/reporting/default_reports/logger.rb +2 -2
  24. data/lib/urbanopt/reporting/default_reports/power_distribution.rb +22 -6
  25. data/lib/urbanopt/reporting/default_reports/program.rb +2 -1
  26. data/lib/urbanopt/reporting/default_reports/reporting_period.rb +30 -7
  27. data/lib/urbanopt/reporting/default_reports/scenario_power_distribution.rb +148 -0
  28. data/lib/urbanopt/reporting/default_reports/scenario_report.rb +20 -14
  29. data/lib/urbanopt/reporting/default_reports/schema/scenario_csv_columns.txt +18 -0
  30. data/lib/urbanopt/reporting/default_reports/schema/scenario_schema.json +240 -6
  31. data/lib/urbanopt/reporting/default_reports/solar_pv.rb +42 -3
  32. data/lib/urbanopt/reporting/default_reports/storage.rb +1 -1
  33. data/lib/urbanopt/reporting/default_reports/thermal_storage.rb +1 -1
  34. data/lib/urbanopt/reporting/default_reports/timeseries_csv.rb +2 -1
  35. data/lib/urbanopt/reporting/default_reports/validator.rb +1 -1
  36. data/lib/urbanopt/reporting/default_reports/wind.rb +11 -2
  37. data/lib/urbanopt/reporting/default_reports.rb +1 -1
  38. data/lib/urbanopt/reporting/derived_extension.rb +1 -1
  39. data/lib/urbanopt/reporting/version.rb +2 -2
  40. data/lib/urbanopt/reporting.rb +1 -1
  41. data/urbanopt-reporting-gem.gemspec +3 -4
  42. metadata +16 -15
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt™, Copyright (c) 2019-2021, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt™, Copyright (c) 2019-2022, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
 
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -192,6 +192,15 @@ module URBANopt
192
192
  #
193
193
  attr_accessor :probs_of_surviving_by_hour_of_the_day
194
194
 
195
+ ##
196
+ # _String_ - Filepath of reopt assumptions file used, if known
197
+ attr_accessor :reopt_assumptions_file_path
198
+
199
+ ##
200
+ # _Float_ - Annual percentage of electricity supplied by renewable sources
201
+ #
202
+ attr_accessor :annual_renewable_electricity_pct
203
+
195
204
  ##
196
205
  # Initialize distributed generation system design and financial metrics.
197
206
  #
@@ -206,6 +215,7 @@ module URBANopt
206
215
  def initialize(hash = {})
207
216
  hash.delete_if { |k, v| v.nil? }
208
217
 
218
+ @annual_renewable_electricity_pct = hash[:annual_renewable_electricity_pct]
209
219
  @lcc_us_dollars = hash[:lcc_us_dollars]
210
220
  @lcc_bau_us_dollars = hash[:lcc_bau_us_dollars]
211
221
  @npv_us_dollars = hash[:npv_us_dollars]
@@ -227,6 +237,12 @@ module URBANopt
227
237
  @probs_of_surviving_by_month = hash[:probs_of_surviving_by_month]
228
238
  @probs_of_surviving_by_hour_of_the_day = hash[:probs_of_surviving_by_hour_of_the_day]
229
239
 
240
+ # optional
241
+ @reopt_assumptions_file_path = nil
242
+ if hash[:reopt_assumptions_file_path]
243
+ @reopt_assumptions_file_path = hash[:reopt_assumptions_file_path]
244
+ end
245
+
230
246
  @total_solar_pv_kw = nil
231
247
  @total_wind_kw = nil
232
248
  @total_generator_kw = nil
@@ -234,7 +250,7 @@ module URBANopt
234
250
  @total_storage_kwh = nil
235
251
 
236
252
  @solar_pv = []
237
- if hash[:solar_pv].class == Hash
253
+ if hash[:solar_pv].instance_of?(Hash)
238
254
  hash[:solar_pv] = [hash[:solar_pv]]
239
255
  elsif hash[:solar_pv].nil?
240
256
  hash[:solar_pv] = []
@@ -252,7 +268,7 @@ module URBANopt
252
268
  end
253
269
 
254
270
  @wind = []
255
- if hash[:wind].class == Hash
271
+ if hash[:wind].instance_of?(Hash)
256
272
  hash[:wind] = [hash[:wind]]
257
273
  elsif hash[:wind].nil?
258
274
  hash[:wind] = []
@@ -270,7 +286,7 @@ module URBANopt
270
286
  end
271
287
 
272
288
  @generator = []
273
- if hash[:generator].class == Hash
289
+ if hash[:generator].instance_of?(Hash)
274
290
  hash[:generator] = [hash[:generator]]
275
291
  elsif hash[:generator].nil?
276
292
  hash[:generator] = []
@@ -288,7 +304,7 @@ module URBANopt
288
304
  end
289
305
 
290
306
  @storage = []
291
- if hash[:storage].class == Hash
307
+ if hash[:storage].instance_of?(Hash)
292
308
  hash[:storage] = [hash[:storage]]
293
309
  elsif hash[:storage].nil?
294
310
  hash[:storage] = []
@@ -363,7 +379,8 @@ module URBANopt
363
379
  ##
364
380
  def to_hash
365
381
  result = {}
366
-
382
+ result[:reopt_assumptions_file_path] = @reopt_assumptions_file_path if @reopt_assumptions_file_path
383
+ result[:annual_renewable_electricity_pct] = @annual_renewable_electricity_pct if @annual_renewable_electricity_pct
367
384
  result[:lcc_us_dollars] = @lcc_us_dollars if @lcc_us_dollars
368
385
  result[:lcc_bau_us_dollars] = @lcc_bau_us_dollars if @lcc_bau_us_dollars
369
386
  result[:npv_us_dollars] = @npv_us_dollars if @npv_us_dollars
@@ -433,6 +450,7 @@ module URBANopt
433
450
  # Merge a distributed generation system with a new system
434
451
  ##
435
452
  def self.merge_distributed_generation(existing_dgen, new_dgen)
453
+ existing_dgen.annual_renewable_electricity_pct = add_values(existing_dgen.annual_renewable_electricity_pct, new_dgen.annual_renewable_electricity_pct)
436
454
  existing_dgen.lcc_us_dollars = add_values(existing_dgen.lcc_us_dollars, new_dgen.lcc_us_dollars)
437
455
  existing_dgen.lcc_bau_us_dollars = add_values(existing_dgen.lcc_bau_us_dollars, new_dgen.lcc_bau_us_dollars)
438
456
  existing_dgen.npv_us_dollars = add_values(existing_dgen.npv_us_dollars, new_dgen.npv_us_dollars)
@@ -476,7 +494,7 @@ module URBANopt
476
494
 
477
495
  new_dgen.storage.each do |storage|
478
496
  existing_dgen.storage.push storage
479
- if existing_dgen.total_wind_kw.nil?
497
+ if existing_dgen.total_storage_kw.nil?
480
498
  existing_dgen.total_storage_kw = storage.size_kw
481
499
  existing_dgen.total_storage_kwh = storage.size_kwh
482
500
  else
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt™, Copyright (c) 2019-2021, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt™, Copyright (c) 2019-2022, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
 
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt™, Copyright (c) 2019-2021, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt™, Copyright (c) 2019-2022, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
 
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -50,6 +50,7 @@ module URBANopt
50
50
  ##
51
51
  class EndUses
52
52
  attr_accessor :electricity_kwh, :natural_gas_kwh, :propane_kwh, :fuel_oil_kwh, :other_fuels_kwh, :district_cooling_kwh, :district_heating_kwh, :water_qbft # :nodoc:
53
+
53
54
  ##
54
55
  # EndUses class intialize end_uses(fuel type) attributes: +:electricity_kwh+ , +:natural_gas_kwh+ , +:propane_kwh+ , +:fuel_oil_kwh+ , +:other_fuels_kwh+ ,
55
56
  # +:district_cooling_kwh+ , +:district_heating_kwh+ , +:water_qbft+
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt™, Copyright (c) 2019-2021, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt™, Copyright (c) 2019-2022, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
 
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt™, Copyright (c) 2019-2021, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt™, Copyright (c) 2019-2022, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
 
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -65,6 +65,7 @@ module URBANopt
65
65
  class FeatureReport
66
66
  attr_accessor :id, :name, :directory_name, :feature_type, :timesteps_per_hour, :simulation_status,
67
67
  :timeseries_csv, :location, :program, :design_parameters, :construction_costs, :reporting_periods, :distributed_generation, :power_distribution, :thermal_storage # :nodoc:
68
+
68
69
  ##
69
70
  # Each FeatureReport object corresponds to a single Feature.
70
71
  ##
@@ -254,15 +255,15 @@ module URBANopt
254
255
  # create feature reports directory
255
256
  Dir.mkdir(results_dir_path) unless Dir.exist?(File.join(@directory_name, 'feature_reports'))
256
257
 
257
- @timeseries_csv.path = File.join(@directory_name, 'feature_reports', file_name + '.csv')
258
+ @timeseries_csv.path = File.join(@directory_name, 'feature_reports', "#{file_name}.csv")
258
259
  FileUtils.mkdir_p File.dirname(@timeseries_csv.path)
259
260
  @timeseries_csv.save_data
260
261
 
261
- ## save json rport
262
+ ## save json report
262
263
  # feature_hash
263
264
  feature_hash = to_hash
264
265
 
265
- json_name_path = File.join(results_dir_path, file_name + '.json')
266
+ json_name_path = File.join(results_dir_path, "#{file_name}.json")
266
267
 
267
268
  File.open(json_name_path, 'w') do |f|
268
269
  f.puts JSON.pretty_generate(feature_hash)
@@ -277,7 +278,7 @@ module URBANopt
277
278
  if !old_timeseries_path.nil?
278
279
  @timeseries_csv.path = old_timeseries_path
279
280
  else
280
- @timeseries_csv.path = File.join(@directory_name, file_name + '.csv')
281
+ @timeseries_csv.path = File.join(@directory_name, "#{file_name}.csv")
281
282
  end
282
283
 
283
284
  return true
@@ -312,7 +313,7 @@ module URBANopt
312
313
  # feature_hash
313
314
  feature_hash = to_hash
314
315
 
315
- json_name_path = File.join(results_dir_path, file_name + '.json')
316
+ json_name_path = File.join(results_dir_path, "#{file_name}.json")
316
317
 
317
318
  File.open(json_name_path, 'w') do |f|
318
319
  f.puts JSON.pretty_generate(feature_hash)
@@ -327,7 +328,7 @@ module URBANopt
327
328
 
328
329
  ##
329
330
  # Saves the 'default_feature_report.csv' file to the results directory
330
- # This method only copies the CSV feature reports from the folder generated by the reporting measure
331
+ # This method only copies the CSV feature reports from the folder generated by the reporting measure
331
332
  # (<meausure number>_default_feature_reports/) to the new feature_reports/ folder
332
333
  ##
333
334
  # [parameters]:
@@ -347,7 +348,7 @@ module URBANopt
347
348
  # copy the CSV report to the new feature_reports folder
348
349
  directory_folders.each do |f|
349
350
  if f.include? '_default_feature_reports'
350
- FileUtils.cp(File.join(f, 'default_feature_reports.csv'), File.join(results_dir_path, @file_name + '.csv'))
351
+ FileUtils.cp(File.join(f, 'default_feature_reports.csv'), File.join(results_dir_path, "#{@file_name}.csv"))
351
352
  end
352
353
  end
353
354
  end
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt™, Copyright (c) 2019-2021, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt™, Copyright (c) 2019-2022, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
 
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -80,7 +80,6 @@ module URBANopt
80
80
  result = {}
81
81
 
82
82
  result[:size_kw] = @size_kw if @size_kw
83
-
84
83
  return result
85
84
  end
86
85
 
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt™, Copyright (c) 2019-2021, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt™, Copyright (c) 2019-2022, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
 
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -50,6 +50,7 @@ module URBANopt
50
50
  ##
51
51
  class Location
52
52
  attr_accessor :latitude_deg, :longitude_deg, :surface_elevation_ft, :weather_filename #:nodoc:
53
+
53
54
  ##
54
55
  # Location class initialize location attributes: +:latitude_deg+ , +:longitude_deg+ , +:surface_elevation_ft+ , +:weather_filename+
55
56
  ##
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt™, Copyright (c) 2019-2021, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt™, Copyright (c) 2019-2022, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
 
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -43,7 +43,7 @@ require 'logger'
43
43
  module URBANopt
44
44
  module Reporting
45
45
  module DefaultReports
46
- @@logger = Logger.new(STDOUT)
46
+ @@logger = Logger.new($stdout)
47
47
  ##
48
48
  # Definining class variable "@@logger" to log errors, info and warning messages.
49
49
  def self.logger
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt™, Copyright (c) 2019-2021, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt™, Copyright (c) 2019-2022, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
 
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -50,10 +50,12 @@ module URBANopt
50
50
  # power_distributio include eletrical power distribution systems information.
51
51
  ##
52
52
  class PowerDistribution
53
- attr_accessor :under_voltage_hours, :over_voltage_hours # :nodoc:
53
+ attr_accessor :under_voltage_hours, :over_voltage_hours, :nominal_capacity,
54
+ :reactance_resistance_ratio, :nominal_voltage, :max_power_kw, :max_reactive_power_kvar # :nodoc:
55
+
54
56
  ##
55
- # PowerDistrinution class intialize all power_distribution attributes:
56
- # +:under_voltage_hours+ , +:over_voltage_hours+
57
+ # PowerDistribution class initialize all power_distribution attributes:
58
+ # +:under_voltage_hours+ , +:over_voltage_hours+, +:nominal_capacity+, +:reactance_resistance_ratio+
57
59
  ##
58
60
  # [parameters:]
59
61
  # +hash+ - _Hash_ - A hash which may contain a deserialized power_distribution.
@@ -64,7 +66,11 @@ module URBANopt
64
66
 
65
67
  @under_voltage_hours = hash[:under_voltage_hours]
66
68
  @over_voltage_hours = hash[:over_voltage_hours]
67
-
69
+ @nominal_capacity = hash[:nominal_capacity]
70
+ @reactance_resistance_ratio = hash[:reactance_resistance_ratio]
71
+ @nominal_voltage = hash[:nominal_voltage] # in V
72
+ @max_power_kw = hash[:max_power_kw]
73
+ @max_reactive_power_kvar = hash[:max_reactive_power_kvar]
68
74
  # initialize class variables @@validator and @@schema
69
75
  @@validator ||= Validator.new
70
76
  @@schema ||= @@validator.schema
@@ -77,6 +83,11 @@ module URBANopt
77
83
  hash = {}
78
84
  hash[:under_voltage_hours] = nil
79
85
  hash[:over_voltage_hours] = nil
86
+ hash[:nominal_capacity] = nil
87
+ hash[:reactance_resistance_ratio] = nil
88
+ hash[:nominal_voltage] = nil
89
+ hash[:max_power_kw] = nil
90
+ hash[:max_reactive_power_kvar] = nil
80
91
 
81
92
  return hash
82
93
  end
@@ -91,6 +102,11 @@ module URBANopt
91
102
  result = {}
92
103
  result[:under_voltage_hours] = @under_voltage_hours if @under_voltage_hours
93
104
  result[:over_voltage_hours] = @over_voltage_hours if @over_voltage_hours
105
+ result[:nominal_capacity] = @nominal_capacity if @nominal_capacity
106
+ result[:reactance_resistance_ratio] = @reactance_resistance_ratio if @reactance_resistance_ratio
107
+ result[:nominal_voltage] = @nominal_voltage if @nominal_voltage
108
+ result[:max_power_kw] = @max_power_kw if @max_power_kw
109
+ result[:max_reactive_power_kvar] = @max_reactive_power_kvar if @max_reactive_power_kvar
94
110
 
95
111
  # validate power_distribution properties against schema
96
112
  if @@validator.validate(@@schema[:definitions][:PowerDistribution][:properties], result).any?
@@ -104,7 +120,7 @@ module URBANopt
104
120
  # Merges muliple power distribution results together.
105
121
  ##
106
122
  # +new_costs+ - _Array_ - An array of ConstructionCost objects.
107
- def merge_power_distribition
123
+ def merge_power_distribution
108
124
  # method to be developed for any attributes to be aggregated or merged
109
125
  end
110
126
  end
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt™, Copyright (c) 2019-2021, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt™, Copyright (c) 2019-2022, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
 
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -56,6 +56,7 @@ module URBANopt
56
56
  :maximum_number_of_parking_stories_above_ground, :number_of_residential_units, :building_types, :building_type, :maximum_occupancy,
57
57
  :area_sqft, :window_area_sqft, :north_window_area_sqft, :south_window_area_sqft, :east_window_area_sqft, :west_window_area_sqft, :wall_area_sqft, :roof_area_sqft, :equipment_roof_area_sqft,
58
58
  :photovoltaic_roof_area_sqft, :available_roof_area_sqft, :total_roof_area_sqft, :orientation_deg, :aspect_ratio, :total_construction_cost_dollar # :nodoc:
59
+
59
60
  # Program class initialize building program attributes: +:site_area_sqft+ , +:floor_area_sqft+ , +:conditioned_area_sqft+ , +:unconditioned_area_sqft+ ,
60
61
  # +:footprint_area_sqft+ , +:maximum_roof_height_ft, +:maximum_number_of_stories+ , +:maximum_number_of_stories_above_ground+ , +:parking_area_sqft+ ,
61
62
  # +:number_of_parking_spaces+ , +:number_of_parking_spaces_charging+ , +:parking_footprint_area_sqft+ , +:maximum_parking_height_ft+ , +:maximum_number_of_parking_stories+ ,
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt™, Copyright (c) 2019-2021, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt™, Copyright (c) 2019-2022, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
 
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -57,13 +57,18 @@ module URBANopt
57
57
  :net_site_energy_kwh, :net_source_energy_kwh, :total_utility_cost_dollar, :net_utility_cost_dollar, :utility_costs_dollar, :electricity_kwh, :natural_gas_kwh, :propane_kwh, :fuel_oil_kwh, :other_fuels_kwh, :district_cooling_kwh,
58
58
  :district_heating_kwh, :water_qbft, :electricity_produced_kwh, :end_uses, :energy_production_kwh, :photovoltaic,
59
59
  :fuel_type, :total_cost_dollar, :usage_cost_dollar, :demand_cost_dollar, :comfort_result, :time_setpoint_not_met_during_occupied_cooling,
60
- :time_setpoint_not_met_during_occupied_heating, :time_setpoint_not_met_during_occupied_hours, :hours_out_of_comfort_bounds_PMV, :hours_out_of_comfort_bounds_PPD #:nodoc:
60
+ :time_setpoint_not_met_during_occupied_heating, :time_setpoint_not_met_during_occupied_hours, :hours_out_of_comfort_bounds_PMV, :hours_out_of_comfort_bounds_PPD,
61
+ :emissions, :future_annual_emissions_mt, :future_hourly_emissions_mt, :historical_annual_emissions_mt, :historical_hourly_emissions_mt,
62
+ :future_annual_emissions_intensity_kg_per_ft2, :future_hourly_emissions_intensity_kg_per_ft2, :historical_annual_emissions_intensity_kg_per_ft2, :historical_hourly_emissions_intensity_kg_per_ft2 #:nodoc:
63
+
61
64
  # ReportingPeriod class initializes the reporting period attributes:
62
65
  # +:id+ , +:name+ , +:multiplier+ , +:start_date+ , +:end_date+ , +:month+ , +:day_of_month+ , +:year+ , +:total_site_energy_kwh+ , +:total_source_energy_kwh+ , +:site_EUI_kwh_per_m2+, +:site_EUI_kbtu_per_ft2+, +:source_EUI_kwh_per_m2+, +:source_EUI_kbtu_per_ft2+,
63
66
  # +:net_site_energy_kwh+ , +:net_source_energy_kwh+ , +:total_utility_cost_dollar , +:net_utility_cost_dollar+ , +:utility_costs_dollar+ , +:electricity_kwh+ , +:natural_gas_kwh+ , +:propane_kwh+ , +:fuel_oil_kwh+ , +:other_fuels_kwh+ , +:district_cooling_kwh+ ,
64
67
  # +:district_heating_kwh+ , +:water_qbft+ , +:electricity_produced_kwh+ , +:end_uses+ , +:energy_production_kwh+ , +:photovoltaic_kwh+ ,
65
68
  # +:fuel_type+ , +:total_cost_dollar+ , +:usage_cost_dollar+ , +:demand_cost_dollar+ , +:comfort_result+ , +:time_setpoint_not_met_during_occupied_cooling+ ,
66
- # +:time_setpoint_not_met_during_occupied_heating+ , +:time_setpoint_not_met_during_occupied_hours+
69
+ # +:time_setpoint_not_met_during_occupied_heating+ , +:time_setpoint_not_met_during_occupied_hours+ , +:hours_out_of_comfort_bounds_PMV , +:hours_out_of_comfort_bounds_PPD ,
70
+ # +:emissions, +:future_annual_emissions_mt, +:future_hourly_emissions_mt, +:historical_annual_emissions_mt, +:historical_hourly_emissions_mt,
71
+ # +:future_annual_emissions_intensity_kg_per_ft2, +:future_hourly_emissions_intensity_kg_per_ft2, +:historical_annual_emissions_intensity_kg_per_ft2, +:historical_hourly_emissions_intensity_kg_per_ft2
67
72
  ##
68
73
  # [parameters:]
69
74
  # +hash+ - _Hash_ - A hash which may contain a deserialized reporting_period.
@@ -105,6 +110,8 @@ module URBANopt
105
110
 
106
111
  @comfort_result = hash[:comfort_result]
107
112
 
113
+ @emissions = hash[:emissions]
114
+
108
115
  # initialize class variables @@validator and @@schema
109
116
  @@validator ||= Validator.new
110
117
  @@schema ||= @@validator.schema
@@ -146,6 +153,8 @@ module URBANopt
146
153
  hash[:utility_costs_dollar] = [{ fuel_type: nil, total_cost_dollar: nil, usage_cost_dollar: nil, demand_cost_dollar: nil }]
147
154
  hash[:comfort_result] = { time_setpoint_not_met_during_occupied_cooling: nil, time_setpoint_not_met_during_occupied_heating: nil,
148
155
  time_setpoint_not_met_during_occupied_hours: nil, hours_out_of_comfort_bounds_PMV: nil, hours_out_of_comfort_bounds_PPD: nil }
156
+ hash[:emissions] = { future_annual_emissions_mt: nil, future_hourly_emissions_mt: nil, historical_annual_emissions_mt: nil, historical_hourly_emissions_mt: nil,
157
+ future_annual_emissions_intensity_kg_per_ft2: nil, future_hourly_emissions_kg_per_ft2: nil, historical_annual_emissions_kg_per_ft2: nil, historical_hourly_emissions_kg_per_ft2: nil }
149
158
 
150
159
  return hash
151
160
  end
@@ -204,6 +213,10 @@ module URBANopt
204
213
  comfort_result_hash.delete_if { |k, v| v.nil? }
205
214
  result[:comfort_result] = comfort_result_hash if @comfort_result
206
215
 
216
+ emissions_hash = @emissions if @emissions
217
+ emissions_hash.delete_if { |k, v| v.nil? }
218
+ result[:emissions] = emissions_hash if @emissions
219
+
207
220
  # validates +reporting_period+ properties against schema for reporting period.
208
221
  if @@validator.validate(@@schema[:definitions][:ReportingPeriod][:properties], result).any?
209
222
  raise "feature_report properties does not match schema: #{@@validator.validate(@@schema[:definitions][:ReportingPeriod][:properties], result)}"
@@ -258,10 +271,8 @@ module URBANopt
258
271
  new_end_uses = new_period.end_uses
259
272
  existing_period.end_uses&.merge_end_uses!(new_end_uses)
260
273
 
261
- if existing_period.energy_production_kwh
262
- if existing_period.energy_production_kwh[:electricity_produced_kwh]
263
- existing_period.energy_production_kwh[:electricity_produced_kwh][:photovoltaic_kwh] = add_values(existing_period.energy_production_kwh[:electricity_produced][:photovoltaic], new_period.energy_production_kwh[:electricity_produced_kwh][:photovoltaic_kwh])
264
- end
274
+ if existing_period.energy_production_kwh && existing_period.energy_production_kwh[:electricity_produced_kwh]
275
+ existing_period.energy_production_kwh[:electricity_produced_kwh][:photovoltaic_kwh] = add_values(existing_period.energy_production_kwh[:electricity_produced][:photovoltaic], new_period.energy_production_kwh[:electricity_produced_kwh][:photovoltaic_kwh])
265
276
  end
266
277
 
267
278
  existing_period.utility_costs_dollar&.each_with_index do |item, i|
@@ -279,6 +290,18 @@ module URBANopt
279
290
  existing_period.comfort_result[:hours_out_of_comfort_bounds_PPD] = add_values(existing_period.comfort_result[:hours_out_of_comfort_bounds_PPD], new_period.comfort_result[:hours_out_of_comfort_bounds_PPD])
280
291
  end
281
292
 
293
+ if existing_period.emissions
294
+ existing_period.emissions[:future_annual_emissions_mt] = add_values(existing_period.emissions[:future_annual_emissions_mt], new_period.emissions[:future_annual_emissions_mt])
295
+ existing_period.emissions[:future_hourly_emissions_mt] = add_values(existing_period.emissions[:future_hourly_emissions_mt], new_period.emissions[:future_hourly_emissions_mt])
296
+ existing_period.emissions[:historical_annual_emissions_mt] = add_values(existing_period.emissions[:historical_annual_emissions_mt], new_period.emissions[:historical_annual_emissions_mt])
297
+ existing_period.emissions[:historical_hourly_emissions_mt] = add_values(existing_period.emissions[:historical_hourly_emissions_mt], new_period.emissions[:historical_hourly_emissions_mt])
298
+
299
+ existing_period.emissions[:future_annual_emissions_intensity_kg_per_ft2] = add_values(existing_period.emissions[:future_annual_emissions_intensity_kg_per_ft2], new_period.emissions[:future_annual_emissions_intensity_kg_per_ft2])
300
+ existing_period.emissions[:future_hourly_emissions_intensity_kg_per_ft2] = add_values(existing_period.emissions[:future_hourly_emissions_intensity_kg_per_ft2], new_period.emissions[:future_hourly_emissions_intensity_kg_per_ft2])
301
+ existing_period.emissions[:historical_annual_emissions_intensity_kg_per_ft2] = add_values(existing_period.emissions[:historical_annual_emissions_intensity_kg_per_ft2], new_period.emissions[:historical_annual_emissions_intensity_kg_per_ft2])
302
+ existing_period.emissions[:historical_hourly_emissions_intensity_kg_per_ft2] = add_values(existing_period.emissions[:historical_hourly_emissions_intensity_kg_per_ft2], new_period.emissions[:historical_hourly_emissions_intensity_kg_per_ft2])
303
+ end
304
+
282
305
  return existing_period
283
306
  end
284
307
 
@@ -0,0 +1,148 @@
1
+ # *********************************************************************************
2
+ # URBANopt™, Copyright (c) 2019-2022, Alliance for Sustainable Energy, LLC, and other
3
+ # contributors. All rights reserved.
4
+
5
+ # Redistribution and use in source and binary forms, with or without modification,
6
+ # are permitted provided that the following conditions are met:
7
+
8
+ # Redistributions of source code must retain the above copyright notice, this list
9
+ # of conditions and the following disclaimer.
10
+
11
+ # Redistributions in binary form must reproduce the above copyright notice, this
12
+ # list of conditions and the following disclaimer in the documentation and/or other
13
+ # materials provided with the distribution.
14
+
15
+ # Neither the name of the copyright holder nor the names of its contributors may be
16
+ # used to endorse or promote products derived from this software without specific
17
+ # prior written permission.
18
+
19
+ # Redistribution of this software, without modification, must refer to the software
20
+ # by the same designation. Redistribution of a modified version of this software
21
+ # (i) may not refer to the modified version by the same designation, or by any
22
+ # confusingly similar designation, and (ii) must refer to the underlying software
23
+ # originally provided by Alliance as “URBANopt”. Except to comply with the foregoing,
24
+ # the term “URBANopt”, or any confusingly similar designation may not be used to
25
+ # refer to any modified version of this software or any modified version of the
26
+ # underlying software originally provided by Alliance without the prior written
27
+ # consent of Alliance.
28
+
29
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
30
+ # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
31
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
32
+ # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33
+ # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
34
+ # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
36
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
37
+ # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
38
+ # OF THE POSSIBILITY OF SUCH DAMAGE.
39
+ # *********************************************************************************
40
+
41
+ require_relative 'validator'
42
+
43
+ require 'json'
44
+ require 'json-schema'
45
+
46
+ module URBANopt
47
+ module Reporting
48
+ module DefaultReports
49
+ ##
50
+ # scenario_power_distribution include eletrical power distribution systems information.
51
+ ##
52
+ class ScenarioPowerDistribution
53
+ attr_accessor :substations, :distribution_lines, :capacitors
54
+
55
+ ##
56
+ # ScenarioPowerDistribution class initialize all scenario_power_distribution attributes:
57
+ # +:substations+ , +:distribution_lines+
58
+ ##
59
+ # [parameters:]
60
+ # +hash+ - _Hash_ - A hash which may contain a deserialized power_distribution.
61
+ ##
62
+ def initialize(hash = {})
63
+ hash.delete_if { |k, v| v.nil? }
64
+ hash = defaults.merge(hash)
65
+
66
+ @substations = hash[:substations]
67
+ @distribution_lines = hash[:distribution_lines]
68
+ @capacitors = hash[:capacitors]
69
+
70
+ # initialize class variables @@validator and @@schema
71
+ @@validator ||= Validator.new
72
+ @@schema ||= @@validator.schema
73
+ end
74
+
75
+ ##
76
+ # Assigns default values if attribute values do not exist.
77
+ ##
78
+ def defaults
79
+ hash = {}
80
+ hash[:substations] = []
81
+ hash[:distribution_lines] = []
82
+ hash[:capacitors] = []
83
+
84
+ return hash
85
+ end
86
+
87
+ ##
88
+ # Converts to a Hash equivalent for JSON serialization.
89
+ ##
90
+ # - Exclude attributes with nil values.
91
+ # - Validate power_distribution hash properties against schema.
92
+ ##
93
+ def to_hash
94
+ result = {}
95
+ result[:substations] = @substations if @substations
96
+ result[:distribution_lines] = @distribution_lines if @distribution_lines
97
+ result[:capacitors] = @capacitors if @capacitors
98
+
99
+ # validate power_distribution properties against schema
100
+ if @@validator.validate(@@schema[:definitions][:ScenarioPowerDistribution][:properties], result).any?
101
+ raise "scenario_power_distribution properties does not match schema: #{@@validator.validate(@@schema[:definitions][:ScenarioPowerDistribution][:properties], result)}"
102
+ end
103
+
104
+ return result
105
+ end
106
+
107
+ ##
108
+ # Add a substation
109
+ ##
110
+ def add_substation(hash = {})
111
+ hash.delete_if { |k, v| v.nil? }
112
+ hash = defaults.merge(hash)
113
+ # field: nominal_voltage
114
+ substation = {}
115
+ substation['nominal_voltage'] = hash[:nominal_voltage]
116
+ @substations << substation
117
+ end
118
+
119
+ ##
120
+ # Add a line
121
+ ##
122
+ def add_line(hash = {})
123
+ hash.delete_if { |k, v| v.nil? }
124
+ hash = defaults.merge(hash)
125
+ # fields: length, ampacity, commercial_line_type
126
+ line = {}
127
+ line['length'] = hash[:length]
128
+ line['ampacity'] = hash[:ampacity]
129
+ line['commercial_line_type'] = hash[:commercial_line_type]
130
+
131
+ @distribution_lines << line
132
+ end
133
+
134
+ ##
135
+ # Add a capacitor
136
+ ##
137
+ def add_capacitor(hash = {})
138
+ hash.delete_if { |k, v| v.nil? }
139
+ hash = defaults.merge(hash)
140
+ # fields: nominal_capacity
141
+ cap = {}
142
+ cap['nominal_capacity'] = hash[:nominal_capacity]
143
+ cap
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end