urbanopt-scenario 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +7 -0
  2. data/.github/CONTRIBUTING.md +58 -0
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +27 -0
  4. data/.github/ISSUE_TEMPLATE/feature_request.md +23 -0
  5. data/.github/pull_request_template.md +23 -0
  6. data/.gitignore +26 -0
  7. data/.rdoc_options +36 -0
  8. data/.rspec +3 -0
  9. data/.rubocop.yml +10 -0
  10. data/.travis.yml +23 -0
  11. data/CHANGELOG.md +19 -0
  12. data/Gemfile +43 -0
  13. data/Jenkinsfile +10 -0
  14. data/LICENSE.md +27 -0
  15. data/RDOC_MAIN.md +39 -0
  16. data/README.md +39 -0
  17. data/Rakefile +51 -0
  18. data/deploy_docs.sh +5 -0
  19. data/doc_templates/LICENSE.md +27 -0
  20. data/doc_templates/README.md.erb +42 -0
  21. data/doc_templates/copyright_erb.txt +31 -0
  22. data/doc_templates/copyright_js.txt +4 -0
  23. data/doc_templates/copyright_ruby.txt +29 -0
  24. data/docs/.gitignore +3 -0
  25. data/docs/.vuepress/components/InnerJsonSchema.vue +84 -0
  26. data/docs/.vuepress/components/JsonSchema.vue +12 -0
  27. data/docs/.vuepress/components/ScenarioSchema.vue +12 -0
  28. data/docs/.vuepress/components/StaticLink.vue +8 -0
  29. data/docs/.vuepress/config.js +15 -0
  30. data/docs/.vuepress/highlight.js +8 -0
  31. data/docs/.vuepress/public/custom_rdoc_styles.css +74 -0
  32. data/docs/.vuepress/utils.js +17 -0
  33. data/docs/README.md +39 -0
  34. data/docs/package-lock.json +11817 -0
  35. data/docs/package.json +26 -0
  36. data/docs/schemas/scenario-schema.md +3 -0
  37. data/lib/change_log.rb +147 -0
  38. data/lib/measures/.rubocop.yml +5 -0
  39. data/lib/measures/default_feature_reports/LICENSE.md +27 -0
  40. data/lib/measures/default_feature_reports/README.md +56 -0
  41. data/lib/measures/default_feature_reports/README.md.erb +42 -0
  42. data/lib/measures/default_feature_reports/measure.rb +742 -0
  43. data/lib/measures/default_feature_reports/measure.xml +139 -0
  44. data/lib/measures/default_feature_reports/tests/USA_CO_Golden-NREL.724666_TMY3.epw +8768 -0
  45. data/lib/measures/default_feature_reports/tests/default_feature_reports_test.rb +238 -0
  46. data/lib/measures/default_feature_reports/tests/example_model.osm +4378 -0
  47. data/lib/urbanopt-scenario.rb +31 -0
  48. data/lib/urbanopt/scenario.rb +45 -0
  49. data/lib/urbanopt/scenario/default_reports.rb +40 -0
  50. data/lib/urbanopt/scenario/default_reports/construction_cost.rb +169 -0
  51. data/lib/urbanopt/scenario/default_reports/date.rb +97 -0
  52. data/lib/urbanopt/scenario/default_reports/distributed_generation.rb +187 -0
  53. data/lib/urbanopt/scenario/default_reports/end_use.rb +159 -0
  54. data/lib/urbanopt/scenario/default_reports/end_uses.rb +140 -0
  55. data/lib/urbanopt/scenario/default_reports/feature_report.rb +213 -0
  56. data/lib/urbanopt/scenario/default_reports/generator.rb +92 -0
  57. data/lib/urbanopt/scenario/default_reports/location.rb +99 -0
  58. data/lib/urbanopt/scenario/default_reports/logger.rb +44 -0
  59. data/lib/urbanopt/scenario/default_reports/program.rb +261 -0
  60. data/lib/urbanopt/scenario/default_reports/reporting_period.rb +298 -0
  61. data/lib/urbanopt/scenario/default_reports/scenario_report.rb +300 -0
  62. data/lib/urbanopt/scenario/default_reports/schema/README.md +34 -0
  63. data/lib/urbanopt/scenario/default_reports/schema/scenario_csv_columns.txt +13 -0
  64. data/lib/urbanopt/scenario/default_reports/schema/scenario_schema.json +830 -0
  65. data/lib/urbanopt/scenario/default_reports/solar_pv.rb +92 -0
  66. data/lib/urbanopt/scenario/default_reports/storage.rb +105 -0
  67. data/lib/urbanopt/scenario/default_reports/timeseries_csv.rb +258 -0
  68. data/lib/urbanopt/scenario/default_reports/validator.rb +97 -0
  69. data/lib/urbanopt/scenario/default_reports/wind.rb +92 -0
  70. data/lib/urbanopt/scenario/extension.rb +63 -0
  71. data/lib/urbanopt/scenario/logger.rb +42 -0
  72. data/lib/urbanopt/scenario/scenario_base.rb +79 -0
  73. data/lib/urbanopt/scenario/scenario_csv.rb +122 -0
  74. data/lib/urbanopt/scenario/scenario_datapoint_base.rb +162 -0
  75. data/lib/urbanopt/scenario/scenario_post_processor_base.rb +69 -0
  76. data/lib/urbanopt/scenario/scenario_post_processor_default.rb +98 -0
  77. data/lib/urbanopt/scenario/scenario_runner_base.rb +63 -0
  78. data/lib/urbanopt/scenario/scenario_runner_osw.rb +158 -0
  79. data/lib/urbanopt/scenario/simulation_dir_base.rb +90 -0
  80. data/lib/urbanopt/scenario/simulation_dir_osw.rb +261 -0
  81. data/lib/urbanopt/scenario/simulation_mapper_base.rb +47 -0
  82. data/lib/urbanopt/scenario/version.rb +35 -0
  83. data/urbanopt-scenario-gem.gemspec +38 -0
  84. metadata +251 -0
@@ -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 Scenario
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
@@ -0,0 +1,99 @@
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 'urbanopt/scenario/default_reports/validator'
32
+ require 'json-schema'
33
+ require 'json'
34
+
35
+ module URBANopt
36
+ module Scenario
37
+ module DefaultReports
38
+ ##
39
+ # Location include all location information.
40
+ ##
41
+ class Location
42
+ attr_accessor :latitude, :longitude, :surface_elevation, :weather_filename #:nodoc:
43
+ ##
44
+ # Location class initialize location attributes: +:latitude+ , +:longitude+ , +:surface_elevation+ , +:weather_filename+
45
+ ##
46
+ # [parameters:]
47
+ # +hash+ - _Hash_ - A hash which may contain a deserialized location.
48
+ ##
49
+ def initialize(hash = {})
50
+ hash.delete_if { |k, v| v.nil? }
51
+ hash = defaults.merge(hash)
52
+
53
+ @latitude = hash[:latitude]
54
+ @longitude = hash[:longitude]
55
+ @surface_elevation = hash[:surface_elevation]
56
+ @weather_filename = hash[:weather_filename]
57
+
58
+ # initialize class variables @@validator and @@schema
59
+ @@validator ||= Validator.new
60
+ @@schema ||= @@validator.schema
61
+ end
62
+
63
+ ##
64
+ # Convert to a Hash equivalent for JSON serialization.
65
+ ##
66
+ # - Exclude attributes with nil values.
67
+ # - Validate location hash properties against schema.
68
+ ##
69
+ def to_hash
70
+ result = {}
71
+ result[:latitude] = @latitude if @latitude
72
+ result[:longitude] = @longitude if @longitude
73
+ result[:surface_elevation] = @surface_elevation if @surface_elevation
74
+ result[:weather_filename] = @weather_filename if @weather_filename
75
+
76
+ # validate location properties against schema
77
+ if @@validator.validate(@@schema[:definitions][:Location][:properties], result).any?
78
+ raise "end_uses properties does not match schema: #{@@validator.validate(@@schema[:definitions][:Location][:properties], result)}"
79
+ end
80
+
81
+ return result
82
+ end
83
+
84
+ ##
85
+ # Assign default values if values does not exist
86
+ ##
87
+ def defaults
88
+ hash = {}
89
+ hash[:latitude] = nil
90
+ hash[:longitude] = nil
91
+ hash[:surface_elevation] = nil
92
+ hash[:weather_filename] = nil
93
+
94
+ return hash
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,44 @@
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 'logger'
32
+
33
+ module URBANopt
34
+ module Scenario
35
+ module DefaultReports
36
+ @@logger = Logger.new(STDOUT)
37
+ ##
38
+ # Definining class variable "@@logger" to log errors, info and warning messages.
39
+ def self.logger
40
+ @@logger
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,261 @@
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 'urbanopt/scenario/default_reports/validator'
32
+ require 'json-schema'
33
+ require 'json'
34
+
35
+ module URBANopt
36
+ module Scenario
37
+ module DefaultReports
38
+ ##
39
+ # Program includes all building program related information.
40
+ ##
41
+ class Program
42
+ attr_accessor :site_area, :floor_area, :conditioned_area, :unconditioned_area, :footprint_area, :maximum_roof_height,
43
+ :maximum_number_of_stories, :maximum_number_of_stories_above_ground, :parking_area, :number_of_parking_spaces,
44
+ :number_of_parking_spaces_charging, :parking_footprint_area, :maximum_parking_height, :maximum_number_of_parking_stories,
45
+ :maximum_number_of_parking_stories_above_ground, :number_of_residential_units, :building_types, :building_type, :maximum_occupancy,
46
+ :area, :window_area, :north_window_area, :south_window_area, :east_window_area, :west_window_area, :wall_area, :roof_area, :equipment_roof_area,
47
+ :photovoltaic_roof_area, :available_roof_area, :total_roof_area, :orientation, :aspect_ratio # :nodoc:
48
+ # Program class initialize building program attributes: +:site_area+ , +:floor_area+ , +:conditioned_area+ , +:unconditioned_area+ ,
49
+ # +:footprint_area+ , +:maximum_roof_height, +:maximum_number_of_stories+ , +:maximum_number_of_stories_above_ground+ , +:parking_area+ ,
50
+ # +:number_of_parking_spaces+ , +:number_of_parking_spaces_charging+ , +:parking_footprint_area+ , +:maximum_parking_height+ , +:maximum_number_of_parking_stories+ ,
51
+ # +:maximum_number_of_parking_stories_above_ground+ , +:number_of_residential_units+ , +:building_types+ , +:building_type+ , +:maximum_occupancy+ ,
52
+ # +:area+ , +:window_area+ , +:north_window_area+ , +:south_window_area+ , +:east_window_area+ , +:west_window_area+ , +:wall_area+ , +:roof_area+ ,
53
+ # +:equipment_roof_area+ , +:photovoltaic_roof_area+ , +:available_roof_area+ , +:total_roof_area+ , +:orientation+ , +:aspect_ratio+
54
+ ##
55
+ # [parameters:]
56
+ # +hash+ - _Hash_ - A hash which may contain a deserialized program.
57
+ ##
58
+ def initialize(hash = {})
59
+ hash.delete_if { |k, v| v.nil? }
60
+ hash = defaults.merge(hash)
61
+
62
+ @site_area = hash[:site_area]
63
+ @floor_area = hash[:floor_area]
64
+ @conditioned_area = hash[:conditioned_area]
65
+ @unconditioned_area = hash[:unconditioned_area]
66
+ @footprint_area = hash[:footprint_area]
67
+ @maximum_roof_height = hash[:maximum_roof_height]
68
+ @maximum_number_of_stories = hash[:maximum_number_of_stories]
69
+ @maximum_number_of_stories_above_ground = hash[:maximum_number_of_stories_above_ground]
70
+ @parking_area = hash[:parking_area]
71
+ @number_of_parking_spaces = hash[:number_of_parking_spaces]
72
+ @number_of_parking_spaces_charging = hash[:number_of_parking_spaces_charging]
73
+ @parking_footprint_area = hash[:parking_footprint_area]
74
+ @maximum_parking_height = hash[:maximum_parking_height]
75
+ @maximum_number_of_parking_stories = hash[:maximum_number_of_parking_stories]
76
+ @maximum_number_of_parking_stories_above_ground = hash[:maximum_number_of_parking_stories_above_ground]
77
+ @number_of_residential_units = hash[:number_of_residential_units]
78
+ @building_types = hash[:building_types]
79
+ @window_area = hash[:window_area]
80
+ @wall_area = hash[:wall_area]
81
+ @roof_area = hash[:roof_area]
82
+ @orientation = hash[:orientation]
83
+ @aspect_ratio = hash[:aspect_ratio]
84
+
85
+ # initialize class variables @@validator and @@schema
86
+ @@validator ||= Validator.new
87
+ @@schema ||= @@validator.schema
88
+ end
89
+
90
+ ##
91
+ # Assigns default values if values do not exist.
92
+ ##
93
+ def defaults
94
+ hash = {}
95
+ hash[:site_area] = nil
96
+ hash[:floor_area] = nil
97
+ hash[:conditioned_area] = nil
98
+ hash[:unconditioned_area] = nil
99
+ hash[:footprint_area] = nil
100
+ hash[:maximum_roof_height] = nil
101
+ hash[:maximum_number_of_stories] = nil
102
+ hash[:maximum_number_of_stories_above_ground] = nil
103
+ hash[:parking_area] = nil
104
+ hash[:number_of_parking_spaces] = nil
105
+ hash[:number_of_parking_spaces_charging] = nil
106
+ hash[:parking_footprint_area] = nil
107
+ hash[:maximum_parking_height] = nil
108
+ hash[:maximum_number_of_parking_stories] = nil
109
+ hash[:maximum_number_of_parking_stories_above_ground] = nil
110
+ hash[:number_of_residential_units] = nil
111
+ hash[:building_types] = [{ building_type: nil, maximum_occupancy: nil, floor_area: nil }]
112
+ hash[:window_area] = { north_window_area: nil, south_window_area: nil, east_window_area: nil, west_window_area: nil, total_window_area: nil }
113
+ hash[:wall_area] = { north_wall_area: nil, south_wall_area: nil, east_wall_area: nil, west_wall_area: nil, total_wall_area: nil }
114
+ hash[:roof_area] = { equipment_roof_area: nil, photovoltaic_roof_area: nil, available_roof_area: nil, total_roof_area: nil }
115
+ hash[:orientation] = nil
116
+ hash[:aspect_ratio] = nil
117
+ return hash
118
+ end
119
+
120
+ ##
121
+ # Convert to a Hash equivalent for JSON serialization.
122
+ ##
123
+ # - Exclude attributes with nil values.
124
+ # - Validate program hash properties against schema.
125
+ ##
126
+ def to_hash
127
+ result = {}
128
+ result[:site_area] = @site_area if @site_area
129
+ result[:floor_area] = @floor_area if @floor_area
130
+ result[:conditioned_area] = @conditioned_area if @conditioned_area
131
+ result[:unconditioned_area] = @unconditioned_area if @unconditioned_area
132
+ result[:footprint_area] = @footprint_area if @footprint_area
133
+ result[:maximum_roof_height] = @maximum_roof_height if @maximum_roof_height
134
+ result[:maximum_number_of_stories] = @maximum_number_of_stories if @maximum_number_of_stories
135
+ result[:maximum_number_of_stories_above_ground] = @maximum_number_of_stories_above_ground if @maximum_number_of_parking_stories_above_ground
136
+ result[:parking_area] = @parking_area if @parking_area
137
+ result[:number_of_parking_spaces] = @number_of_parking_spaces if @number_of_parking_spaces
138
+ result[:number_of_parking_spaces_charging] = @number_of_parking_spaces_charging if @number_of_parking_spaces_charging
139
+ result[:parking_footprint_area] = @parking_footprint_area if @parking_footprint_area
140
+ result[:maximum_parking_height] = @maximum_parking_height if @maximum_parking_height
141
+ result[:maximum_number_of_parking_stories] = @maximum_number_of_parking_stories if @maximum_number_of_parking_stories
142
+ result[:maximum_number_of_parking_stories_above_ground] = @maximum_number_of_parking_stories_above_ground if @maximum_number_of_parking_stories_above_ground
143
+ result[:number_of_residential_units] = @number_of_residential_units if @number_of_residential_units
144
+
145
+ if @building_types.any?
146
+ result[:building_types] = @building_types
147
+ @building_types.each do |bt|
148
+ bt.delete_if { |k, v| v.nil? } if bt
149
+ end
150
+ end
151
+
152
+ # result[:window_area] = @window_area if @window_area
153
+ window_area_hash = @window_area if @window_area
154
+ window_area_hash.delete_if { |k, v| v.nil? }
155
+ result[:window_area] = window_area_hash if @window_area
156
+
157
+ # result[:wall_area] = @wall_area if @wall_area
158
+ wall_area_hash = @wall_area if @wall_area
159
+ wall_area_hash.delete_if { |k, v| v.nil? }
160
+ result[:wall_area] = wall_area_hash if @wall_area
161
+
162
+ # result[:roof_area] = @roof_area if @roof_area
163
+ roof_area_hash = @roof_area if @roof_area
164
+ roof_area_hash.delete_if { |k, v| v.nil? }
165
+ result[:roof_area] = roof_area_hash if @roof_area
166
+
167
+ result[:orientation] = @orientation if @orientation
168
+ result[:aspect_ratio] = @aspect_ratio if @aspect_ratio
169
+
170
+ # validate program properties against schema
171
+ if @@validator.validate(@@schema[:definitions][:Program][:properties], result).any?
172
+ raise "program properties does not match schema: #{@@validator.validate(@@schema[:definitions][:Program][:properties], result)}"
173
+ end
174
+
175
+ return result
176
+ end
177
+
178
+ ##
179
+ # Return the maximum value from +existing_value+ and +new_value+.
180
+ ##
181
+ # [parameters:]
182
+ # +existing_value+ - _Float_ - A value corresponding to a Program attribute.
183
+ ##
184
+ # +new_value+ - _Float_ - A value corresponding to a Program attribute.
185
+ ##
186
+ def max_value(existing_value, new_value)
187
+ if existing_value && new_value
188
+ [existing_value, new_value].max
189
+ elsif new_value
190
+ existing_value = new_value
191
+ end
192
+ return existing_value
193
+ end
194
+
195
+ ##
196
+ # Adds up +existing_value+ and +new_values+ if not nill.
197
+ ##
198
+ # [parameters:]
199
+ # +existing_value+ - _Float_ - A value corresponding to a Program attribute.
200
+ ##
201
+ # +new_value+ - _Float_ - A value corresponding to a Program attribute.
202
+ ##
203
+ def add_values(existing_value, new_value)
204
+ if existing_value && new_value
205
+ existing_value += new_value
206
+ elsif new_value
207
+ existing_value = new_value
208
+ end
209
+ return existing_value
210
+ end
211
+
212
+ ##
213
+ # Merges program objects to each other by summing up values or taking the maximum value of the attributes.
214
+ ##
215
+ # [parameters:]
216
+ # +other+ - _Program_ - An object of Program class.
217
+ ##
218
+ # rubocop:disable Metrics/AbcSize # :nodoc:
219
+ def add_program(other)
220
+ @site_area = add_values(@site_area, other.site_area)
221
+
222
+ @floor_area = add_values(@floor_area, other.floor_area)
223
+ @conditioned_area = add_values(@conditioned_area, other.conditioned_area)
224
+ @unconditioned_area = add_values(@unconditioned_area, other.unconditioned_area)
225
+ @footprint_area = add_values(@footprint_area, other.footprint_area)
226
+ @maximum_roof_height = max_value(@maximum_roof_height, other.maximum_roof_height)
227
+ @maximum_number_of_stories = max_value(@maximum_number_of_stories, other.maximum_number_of_stories)
228
+ @maximum_number_of_stories_above_ground = max_value(@maximum_number_of_stories_above_ground, other.maximum_number_of_stories_above_ground)
229
+ @parking_area = add_values(@parking_area, other.parking_area)
230
+ @number_of_parking_spaces = add_values(@number_of_parking_spaces, other.number_of_parking_spaces)
231
+ @number_of_parking_spaces_charging = add_values(@number_of_parking_spaces_charging, other.number_of_parking_spaces_charging)
232
+ @parking_footprint_area = add_values(@parkig_footprint_area, other.parking_footprint_area)
233
+ @maximum_parking_height = max_value(@maximum_parking_height, other.maximum_parking_height)
234
+ @maximum_number_of_parking_stories = max_value(@maximum_number_of_parking_stories, other.maximum_number_of_parking_stories)
235
+ @maximum_number_of_parking_stories_above_ground = max_value(maximum_number_of_parking_stories_above_ground, other.maximum_number_of_parking_stories_above_ground)
236
+ @number_of_residential_units = add_values(@number_of_residential_units, other.number_of_residential_units)
237
+
238
+ @building_types = other.building_types
239
+
240
+ @window_area[:north_window_area] = add_values(@window_area[:north_window_area], other.window_area[:north_window_area])
241
+ @window_area[:south_window_area] = add_values(@window_area[:south_window_area], other.window_area[:south_window_area])
242
+ @window_area[:east_window_area] = add_values(@window_area[:east_window_area], other.window_area[:east_window_area])
243
+ @window_area[:west_window_area] = add_values(@window_area[:west_window_area], other.window_area[:west_window_area])
244
+ @window_area[:total_window_area] = add_values(@window_area[:total_window_area], other.window_area[:total_window_area])
245
+
246
+ @wall_area[:north_wall_area] = add_values(@wall_area[:north_wall_area], other.wall_area[:north_wall_area])
247
+ @wall_area[:south_wall_area] = add_values(@wall_area[:south_wall_area], other.wall_area[:south_wall_area])
248
+ @wall_area[:east_wall_area] = add_values(@wall_area[:east_wall_area], other.wall_area[:east_wall_area])
249
+ @wall_area[:west_wall_area] = add_values(@wall_area[:west_wall_area], other.wall_area[:west_wall_area])
250
+ @wall_area[:total_wall_area] = add_values(@wall_area[:total_wall_area], other.wall_area[:total_wall_area])
251
+
252
+ @roof_area[:equipment_roof_area] = add_values(@roof_area[:equipment_roof_area], other.roof_area[:equipment_roof_area])
253
+ @roof_area[:photovoltaic_roof_area] = add_values(@roof_area[:photovoltaic_roof_area], other.roof_area[:photovoltaic_roof_area])
254
+ @roof_area[:available_roof_area] = add_values(@roof_area[:available_roof_area], other.roof_area[:available_roof_area])
255
+ @roof_area[:total_roof_area] = add_values(@roof_area[:total_roof_area], other.roof_area[:total_roof_area])
256
+ end
257
+ # rubocop:enable Metrics/AbcSize
258
+ end
259
+ end
260
+ end
261
+ end