urbanopt-reporting 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +24 -0
  3. data/.rubocop.yml +10 -0
  4. data/CHANGELOG.md +7 -0
  5. data/CONTRIBUTING.md +58 -0
  6. data/Gemfile +18 -0
  7. data/Jenkinsfile +10 -0
  8. data/LICENSE.md +27 -0
  9. data/README.md +40 -0
  10. data/Rakefile +45 -0
  11. data/doc_templates/LICENSE.md +27 -0
  12. data/doc_templates/README.md.erb +42 -0
  13. data/doc_templates/copyright_erb.txt +31 -0
  14. data/doc_templates/copyright_js.txt +4 -0
  15. data/doc_templates/copyright_ruby.txt +29 -0
  16. data/lib/measures/.rubocop.yml +5 -0
  17. data/lib/measures/default_feature_reports/LICENSE.md +27 -0
  18. data/lib/measures/default_feature_reports/README.md +26 -0
  19. data/lib/measures/default_feature_reports/README.md.erb +42 -0
  20. data/lib/measures/default_feature_reports/measure.rb +1012 -0
  21. data/lib/measures/default_feature_reports/measure.xml +160 -0
  22. data/lib/urbanopt/reporting.rb +37 -0
  23. data/lib/urbanopt/reporting/default_reports.rb +44 -0
  24. data/lib/urbanopt/reporting/default_reports/construction_cost.rb +169 -0
  25. data/lib/urbanopt/reporting/default_reports/date.rb +97 -0
  26. data/lib/urbanopt/reporting/default_reports/distributed_generation.rb +379 -0
  27. data/lib/urbanopt/reporting/default_reports/end_use.rb +159 -0
  28. data/lib/urbanopt/reporting/default_reports/end_uses.rb +140 -0
  29. data/lib/urbanopt/reporting/default_reports/extension.rb +15 -0
  30. data/lib/urbanopt/reporting/default_reports/feature_report.rb +266 -0
  31. data/lib/urbanopt/reporting/default_reports/generator.rb +92 -0
  32. data/lib/urbanopt/reporting/default_reports/location.rb +99 -0
  33. data/lib/urbanopt/reporting/default_reports/logger.rb +44 -0
  34. data/lib/urbanopt/reporting/default_reports/power_distribution.rb +103 -0
  35. data/lib/urbanopt/reporting/default_reports/program.rb +265 -0
  36. data/lib/urbanopt/reporting/default_reports/reporting_period.rb +300 -0
  37. data/lib/urbanopt/reporting/default_reports/scenario_report.rb +317 -0
  38. data/lib/urbanopt/reporting/default_reports/schema/README.md +33 -0
  39. data/lib/urbanopt/reporting/default_reports/schema/scenario_csv_columns.txt +34 -0
  40. data/lib/urbanopt/reporting/default_reports/schema/scenario_schema.json +857 -0
  41. data/lib/urbanopt/reporting/default_reports/solar_pv.rb +93 -0
  42. data/lib/urbanopt/reporting/default_reports/storage.rb +105 -0
  43. data/lib/urbanopt/reporting/default_reports/timeseries_csv.rb +300 -0
  44. data/lib/urbanopt/reporting/default_reports/validator.rb +112 -0
  45. data/lib/urbanopt/reporting/default_reports/wind.rb +92 -0
  46. data/lib/urbanopt/reporting/derived_extension.rb +63 -0
  47. data/lib/urbanopt/reporting/version.rb +35 -0
  48. data/urbanopt-reporting-gem.gemspec +33 -0
  49. metadata +176 -0
@@ -0,0 +1,140 @@
1
+ # *********************************************************************************
2
+ # URBANopt, Copyright (c) 2019-2020, 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
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20
+ # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22
+ # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23
+ # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24
+ # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27
+ # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28
+ # OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ # *********************************************************************************
30
+
31
+ require_relative 'end_use'
32
+ require_relative 'validator'
33
+ require 'json-schema'
34
+
35
+ module URBANopt
36
+ module Reporting
37
+ module DefaultReports
38
+ ##
39
+ # Enduses class inlclude results for each fuel type.
40
+ ##
41
+ class EndUses
42
+ attr_accessor :electricity, :natural_gas, :additional_fuel, :district_cooling, :district_heating, :water # :nodoc:
43
+ ##
44
+ # EndUses class intialize end_uses(fuel type) attributes: +:electricity+ , +:natural_gas+ , +:additional_fuel+ ,
45
+ # +:district_cooling+ , +:district_heating+ , +:water+
46
+ ##
47
+ # [parameters:]
48
+ # +hash+ - _Hash_ - A hash which may contain a deserialized end_uses.
49
+ ##
50
+ def initialize(hash = {})
51
+ hash.delete_if { |k, v| v.nil? }
52
+ hash = defaults.merge(hash)
53
+
54
+ @electricity = EndUse.new(hash[:electricity])
55
+ @natural_gas = EndUse.new(hash[:natural_gas])
56
+ @additional_fuel = EndUse.new(hash[:additional_fuel])
57
+ @district_cooling = EndUse.new(hash[:district_cooling])
58
+ @district_heating = EndUse.new(hash[:district_heating])
59
+ @water = EndUse.new(hash[:water])
60
+
61
+ # initialize class variables @@validator and @@schema
62
+ @@validator ||= Validator.new
63
+ @@schema ||= @@validator.schema
64
+ end
65
+
66
+ ##
67
+ # Converts to a Hash equivalent for JSON serialization.
68
+ ##
69
+ # - Exclude attributes with nil values.
70
+ # - Validate end_uses hash properties against schema.
71
+ ##
72
+ def to_hash
73
+ result = {}
74
+
75
+ electricity_hash = @electricity.to_hash if @electricity.to_hash
76
+ electricity_hash.delete_if { |k, v| v.nil? }
77
+ result[:electricity] = electricity_hash if @electricity
78
+
79
+ natural_gas_hash = @natural_gas.to_hash if @natural_gas
80
+ natural_gas_hash.delete_if { |k, v| v.nil? }
81
+ result[:natural_gas] = natural_gas_hash if @natural_gas
82
+
83
+ additional_fuel_hash = @additional_fuel.to_hash if @additional_fuel
84
+ additional_fuel_hash.delete_if { |k, v| v.nil? }
85
+ result[:additional_fuel] = additional_fuel_hash if @additional_fuel
86
+
87
+ district_cooling_hash = @district_cooling.to_hash if @district_cooling
88
+ district_cooling_hash.delete_if { |k, v| v.nil? }
89
+ result[:district_cooling] = district_cooling_hash if @district_cooling
90
+
91
+ district_heating_hash = @district_heating.to_hash if @district_heating
92
+ district_heating_hash.delete_if { |k, v| v.nil? }
93
+ result[:district_heating] = district_heating_hash if @district_heating
94
+
95
+ water_hash = @water.to_hash if @water
96
+ water_hash.delete_if { |k, v| v.nil? }
97
+ result[:water] = water_hash if @water
98
+
99
+ # validate end_uses properties against schema
100
+ if @@validator.validate(@@schema[:definitions][:EndUses][:properties], result).any?
101
+ raise "end_uses properties does not match schema: #{@@validator.validate(@@schema[:definitions][:EndUses][:properties], result)}"
102
+ end
103
+
104
+ return result
105
+ end
106
+
107
+ ##
108
+ # Assigns default values if values do not exist.
109
+ ##
110
+ def defaults
111
+ hash = {}
112
+ hash[:electricity] = EndUse.new.to_hash
113
+ hash[:natural_gas] = EndUse.new.to_hash
114
+ hash[:additional_fuel] = EndUse.new.to_hash
115
+ hash[:district_cooling] = EndUse.new.to_hash
116
+ hash[:district_heating] = EndUse.new.to_hash
117
+ hash[:water] = EndUse.new.to_hash
118
+
119
+ return hash
120
+ end
121
+
122
+ ##
123
+ # Aggregates the values of each EndUse attribute.
124
+ ##
125
+ # [Parameters:]
126
+ # +new_end_uses+ - _EndUses_ - An object of EndUses class.
127
+ ##
128
+ def merge_end_uses!(new_end_uses)
129
+ # modify the existing_period by summing up the results ; # sum results only if they exist
130
+ @electricity.merge_end_use!(new_end_uses.electricity)
131
+ @natural_gas.merge_end_use!(new_end_uses.natural_gas)
132
+ @additional_fuel.merge_end_use!(new_end_uses.additional_fuel)
133
+ @district_cooling.merge_end_use!(new_end_uses.district_cooling)
134
+ @district_heating.merge_end_use!(new_end_uses.district_heating)
135
+ return self
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,15 @@
1
+ require 'version'
2
+ require 'openstudio/extension'
3
+
4
+ module URBANopt
5
+ module Reporting
6
+ class Extension < OpenStudio::Extension::Extension
7
+ # Override the base class
8
+ def initialize
9
+ super
10
+
11
+ @root_dir = File.absolute_path(File.join(File.dirname(__FILE__), '..'))
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,266 @@
1
+ # *********************************************************************************
2
+ # URBANopt, Copyright (c) 2019-2020, 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
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20
+ # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22
+ # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23
+ # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24
+ # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27
+ # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28
+ # OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ # *********************************************************************************
30
+
31
+ require_relative 'construction_cost'
32
+ require_relative 'program'
33
+ require_relative 'location'
34
+ require_relative 'reporting_period'
35
+ require_relative 'timeseries_csv'
36
+ require_relative 'distributed_generation'
37
+ require_relative 'power_distribution'
38
+ require_relative 'validator'
39
+
40
+ require 'json-schema'
41
+ require 'json'
42
+
43
+ module URBANopt
44
+ module Reporting
45
+ module DefaultReports
46
+ ##
47
+ # FeatureReport generates two types of reports in a simulation_dir.
48
+ # The default_feature_reports measure writes a 'default_feature_reports.json' file containing
49
+ # information on all features in the simulation. It also writes a 'default_feature_reports.csv'
50
+ # containing timeseries data for all features in the simulation.
51
+ # The DefaultPostProcessor reads these feature reports and aggregates them to create a ScenarioReport.
52
+ ##
53
+ class FeatureReport
54
+ attr_accessor :id, :name, :directory_name, :feature_type, :timesteps_per_hour, :simulation_status,
55
+ :timeseries_csv, :location, :program, :design_parameters, :construction_costs, :reporting_periods, :distributed_generation, :power_distribution # :nodoc:
56
+ ##
57
+ # Each FeatureReport object corresponds to a single Feature.
58
+ ##
59
+ # [parameters:]
60
+ # +hash+ - _Hash_ - A hash which may contain a deserialized feature_report.
61
+ ##
62
+ def initialize(hash = {})
63
+ hash.delete_if { |k, v| v.nil? }
64
+ hash = defaults.merge(hash)
65
+
66
+ @id = hash[:id]
67
+ @name = hash[:name]
68
+ @directory_name = hash[:directory_name]
69
+ @feature_type = hash[:feature_type]
70
+ @timesteps_per_hour = hash[:timesteps_per_hour]
71
+ @simulation_status = hash[:simulation_status]
72
+ @timeseries_csv = TimeseriesCSV.new(hash[:timeseries_csv])
73
+ @timeseries_csv.run_dir_name(@directory_name)
74
+ @location = Location.new(hash[:location])
75
+ @program = Program.new(hash[:program])
76
+ # design_parameters to add later
77
+ @construction_costs = []
78
+ hash[:construction_costs].each do |cc|
79
+ @constructiion_costs << ConstructionCost.new(cc)
80
+ end
81
+
82
+ @reporting_periods = []
83
+ hash[:reporting_periods].each do |rp|
84
+ @reporting_periods << ReportingPeriod.new(rp)
85
+ end
86
+
87
+ @distributed_generation = DistributedGeneration.new(hash[:distributed_generation])
88
+
89
+ @power_distribution = PowerDistribution.new(hash[:power_distribution])
90
+
91
+ # initialize class variables @@validator and @@schema
92
+ @@validator ||= Validator.new
93
+ @@schema ||= @@validator.schema
94
+
95
+ # initialize feature report file name to be saved.
96
+ @file_name = 'default_feature_report'
97
+ end
98
+
99
+ ##
100
+ # Assign default values if values does not exist.
101
+ ##
102
+ def defaults
103
+ hash = {}
104
+ hash[:timeseries_csv] = {}
105
+ hash[:location] = {}
106
+ hash[:program] = {}
107
+ hash[:construction_costs] = []
108
+ hash[:reporting_periods] = []
109
+ hash[:distributed_generation] = {}
110
+ hash[:power_distribution] = {}
111
+ return hash
112
+ end
113
+
114
+ ##
115
+ # Return an Array of FeatureReports for the simulation_dir as multiple Features can be simulated together in a single simulation directory.
116
+ ##
117
+ # - Ensure that +simulation_dir+ include only one feature.
118
+ # - Read in the reports written by measure if they exist.
119
+ ##
120
+ # [parameters:]
121
+ # +simulation_dir+ - _SimulationDirOSW_ - A simulation directory from an OSW simulation, must include 'default_feature_reports' measure.
122
+ ##
123
+ def self.from_simulation_dir(simulation_dir)
124
+ result = []
125
+
126
+ # simulation dir can include only one feature
127
+ features = simulation_dir.features
128
+ if features.size != 1
129
+ raise 'FeatureReport cannot support multiple features per OSW'
130
+ end
131
+
132
+ # read in the reports written by measure
133
+ default_feature_reports_json = nil
134
+ default_feature_reports_csv = nil
135
+
136
+ simulation_status = simulation_dir.simulation_status
137
+ if simulation_status == 'Complete' || simulation_status == 'Failed'
138
+
139
+ # read in the scenario reports JSON and CSV
140
+ Dir.glob(File.join(simulation_dir.run_dir, '*_default_feature_reports/')).each do |dir|
141
+ scenario_reports_json_path = File.join(dir, 'default_feature_reports.json')
142
+ if File.exist?(scenario_reports_json_path)
143
+ File.open(scenario_reports_json_path, 'r') do |file|
144
+ default_feature_reports_json = JSON.parse(file.read, symbolize_names: true)
145
+ end
146
+ end
147
+ scenario_reports_csv_path = File.join(dir, 'default_feature_reports.csv')
148
+ if File.exist?(scenario_reports_csv_path)
149
+ default_feature_reports_csv = scenario_reports_csv_path
150
+ end
151
+ end
152
+
153
+ end
154
+
155
+ # if we loaded the json
156
+ if default_feature_reports_json # && default_feature_reports_json[:feature_reports]
157
+ # default_feature_reports_json.each do |feature_report|
158
+ # result << FeatureReport.new(feature_report)
159
+ # end
160
+ result << FeatureReport.new(default_feature_reports_json) # should we keep it as an array !? or each each report can only include 1 feature
161
+
162
+ else
163
+ # we did not find a report
164
+ features.each do |feature|
165
+ hash = {}
166
+ hash[:id] = feature.id
167
+ hash[:name] = feature.name
168
+ hash[:directory_name] = simulation_dir.run_dir
169
+ hash[:simulation_status] = simulation_status
170
+ result << FeatureReport.new(hash)
171
+ end
172
+ end
173
+
174
+ # validate feature_report json against schema
175
+ if @@validator.validate(@@schema[:definitions][:FeatureReport][:properties], default_feature_reports_json).any?
176
+ raise "default_feature_report_json properties does not match schema: #{@@validator.validate(@@schema[:definitions][:FeatureReport][:properties], default_feature_reports_json)}"
177
+ end
178
+
179
+ return result
180
+ end
181
+
182
+ ##
183
+ # Convert to a Hash equivalent for JSON serialization
184
+ ##
185
+ # - Exclude attributes with nil values.
186
+ # - Validate feature_report hash properties against schema.
187
+ ##
188
+ def to_hash
189
+ result = {}
190
+ result[:id] = @id if @id
191
+ result[:name] = @name if @name
192
+ result[:directory_name] = @directory_name if @directory_name
193
+ result[:feature_type] = @feature_type if @feature_type
194
+ result[:timesteps_per_hour] = @timesteps_per_hour if @timesteps_per_hour
195
+ result[:simulation_status] = @simulation_status if @simulation_status
196
+ result[:timeseries_csv] = @timeseries_csv.to_hash
197
+
198
+ result[:location] = @location.to_hash if @location
199
+
200
+ result[:program] = @program.to_hash
201
+
202
+ result[:construction_costs] = []
203
+ @construction_costs.each { |cc| result[:construction_costs] << cc.to_hash }
204
+
205
+ result[:reporting_periods] = []
206
+ @reporting_periods.each { |rp| result[:reporting_periods] << rp.to_hash }
207
+
208
+ result[:distributed_generation] = @distributed_generation.to_hash if @distributed_generation
209
+
210
+ result[:power_distribution] = @power_distribution.to_hash if @power_distribution
211
+
212
+ # validate feature_report properties against schema
213
+ if @@validator.validate(@@schema[:definitions][:FeatureReport][:properties], result).any?
214
+ raise "feature_report properties does not match schema: #{@@validator.validate(@@schema[:definitions][:FeatureReport][:properties], result)}"
215
+ end
216
+
217
+ return result
218
+ end
219
+
220
+ ##
221
+ # Saves the 'default_feature_report.json' and 'default_feature_report.csv' files
222
+ ##
223
+ # [parameters]:
224
+ # +file_name+ - _String_ - Assign a name to the saved feature report results file without an extension
225
+ def save_feature_report(file_name = 'default_feature_report')
226
+ # reassign the initialize local variable @file_name to the file name input.
227
+ @file_name = file_name
228
+
229
+ # create feature reports directory
230
+ Dir.mkdir(File.join(@directory_name, 'feature_reports')) unless Dir.exist?(File.join(@directory_name, 'feature_reports'))
231
+
232
+ # save the csv data
233
+ old_timeseries_path = nil
234
+ if !@timeseries_csv.path.nil?
235
+ old_timeseries_path = @timeseries_csv.path
236
+ end
237
+
238
+ @timeseries_csv.path = File.join(@directory_name, 'feature_reports', file_name + '.csv')
239
+ @timeseries_csv.save_data
240
+
241
+ # feature_hash
242
+ feature_hash = to_hash
243
+
244
+ json_name_path = File.join(@directory_name, 'feature_reports', file_name + '.json')
245
+
246
+ File.open(json_name_path, 'w') do |f|
247
+ f.puts JSON.pretty_generate(feature_hash)
248
+ # make sure data is written to the disk one way or the other
249
+ begin
250
+ f.fsync
251
+ rescue StandardError
252
+ f.flush
253
+ end
254
+ end
255
+
256
+ if !old_timeseries_path.nil?
257
+ @timeseries_csv.path = old_timeseries_path
258
+ else
259
+ @timeseries_csv.path = File.join(@directory_name, 'feature_reports', file_name + '.csv')
260
+ end
261
+ return true
262
+ end
263
+ end
264
+ end
265
+ end
266
+ end
@@ -0,0 +1,92 @@
1
+ # *********************************************************************************
2
+ # URBANopt, Copyright (c) 2019-2020, 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
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20
+ # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22
+ # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23
+ # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24
+ # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27
+ # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28
+ # OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ # *********************************************************************************
30
+
31
+ require 'json'
32
+ require 'json-schema'
33
+
34
+ module URBANopt
35
+ module Reporting
36
+ module DefaultReports
37
+ ##
38
+ # Onsite generator system attributes
39
+ ##
40
+ class Generator
41
+ ##
42
+ # _Float_ - power capacity in kilowatts
43
+ #
44
+ attr_accessor :size_kw
45
+
46
+ ##
47
+ # Intialize Generator attributes from a hash. Generator attributes currently are limited to power capacity.
48
+ ##
49
+ # [parameters:]
50
+ #
51
+ # * +hash+ - _Hash_ - A hash containting a +:size_kw+ key/value pair which represents the nameplate capacity in kilowatts (kW)
52
+ #
53
+ def initialize(hash = {})
54
+ hash.delete_if { |k, v| v.nil? }
55
+
56
+ @size_kw = hash[:size_kw]
57
+
58
+ # initialize class variables @@validator and @@schema
59
+ @@validator ||= Validator.new
60
+ @@schema ||= @@validator.schema
61
+
62
+ # initialize @@logger
63
+ @@logger ||= URBANopt::Scenario::DefaultReports.logger
64
+ end
65
+
66
+ ##
67
+ # Convert to a Hash equivalent for JSON serialization
68
+ ##
69
+ def to_hash
70
+ result = {}
71
+
72
+ result[:size_kw] = @size_kw if @size_kw
73
+
74
+ return result
75
+ end
76
+
77
+ ##
78
+ # Merge Generator systems
79
+ ##
80
+ def self.add_generator(existing_generator, new_generator)
81
+ if existing_generator.size_kw.nil? && new_generator.size_kw.nil?
82
+ existing_generator.size_kw = nil
83
+ else
84
+ existing_generator.size_kw = (existing_generator.size_kw || 0) + (new_generator.size_kw || 0)
85
+ end
86
+
87
+ return existing_generator
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end