urbanopt-rnm-us 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +32 -0
- data/.rubocop.yml +9 -0
- data/CHANGELOG.md +5 -0
- data/CONTRIBUTING.md +58 -0
- data/Gemfile +10 -0
- data/LICENSE.md +38 -0
- data/README.md +49 -0
- data/Rakefile +166 -0
- data/catalogs/average_peak_per_building_type.json +94 -0
- data/catalogs/extended_catalog.json +15109 -0
- data/lib/urbanopt-rnm.rb +41 -0
- data/lib/urbanopt/rnm.rb +59 -0
- data/lib/urbanopt/rnm/api_client.rb +296 -0
- data/lib/urbanopt/rnm/capacitor_opendss.rb +57 -0
- data/lib/urbanopt/rnm/carson_eq.rb +389 -0
- data/lib/urbanopt/rnm/consumers.rb +255 -0
- data/lib/urbanopt/rnm/conversion_to_opendss.rb +152 -0
- data/lib/urbanopt/rnm/geojson_input.rb +261 -0
- data/lib/urbanopt/rnm/input_files.rb +335 -0
- data/lib/urbanopt/rnm/logger.rb +52 -0
- data/lib/urbanopt/rnm/oh_ug_rate.rb +129 -0
- data/lib/urbanopt/rnm/post_processor.rb +220 -0
- data/lib/urbanopt/rnm/processor_opendss_catalog.rb +73 -0
- data/lib/urbanopt/rnm/prosumers.rb +372 -0
- data/lib/urbanopt/rnm/rnm_us_catalog_conversion.rb +140 -0
- data/lib/urbanopt/rnm/runner.rb +177 -0
- data/lib/urbanopt/rnm/scenario_report.rb +145 -0
- data/lib/urbanopt/rnm/substation_location.rb +63 -0
- data/lib/urbanopt/rnm/transformer_opendss.rb +67 -0
- data/lib/urbanopt/rnm/version.rb +45 -0
- data/lib/urbanopt/rnm/wires_class.rb +70 -0
- data/lib/urbanopt/rnm/wires_opendss.rb +93 -0
- data/urbanopt-rnm-us-gem.gemspec +37 -0
- metadata +218 -0
@@ -0,0 +1,52 @@
|
|
1
|
+
# *********************************************************************************
|
2
|
+
# URBANopt (tm), Copyright (c) 2019-2021, 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 'logger'
|
42
|
+
|
43
|
+
module URBANopt
|
44
|
+
module RNM
|
45
|
+
@@logger = Logger.new($stdout)
|
46
|
+
|
47
|
+
# Definining class variable "@@logger" to log errors, info and warning messages.
|
48
|
+
def self.logger
|
49
|
+
@@logger
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
# *********************************************************************************
|
2
|
+
# URBANopt (tm), Copyright (c) 2019-2021, 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
|
+
# find when the power lines in a street have to be considered OH or UG
|
42
|
+
# according to a threshold height obtained from the %UG defined by the user
|
43
|
+
module URBANopt
|
44
|
+
module RNM
|
45
|
+
class OhUgRate
|
46
|
+
attr_accessor :av_height, :type, :n_buildings_street
|
47
|
+
|
48
|
+
def initialize
|
49
|
+
@av_height = av_height
|
50
|
+
@type = type
|
51
|
+
@n_buildings_street = n_buildings_street
|
52
|
+
end
|
53
|
+
|
54
|
+
# for each street calculate the average height given the buildings in the streets
|
55
|
+
# and it calculates the number of buildings in each street
|
56
|
+
def height_building(coordinates_building, coordinates_street, floors)
|
57
|
+
height = []
|
58
|
+
id_building = []
|
59
|
+
height_sum = 0
|
60
|
+
n_buildings_street = 0
|
61
|
+
for i in 0..coordinates_street.length - 1
|
62
|
+
dist_min = 5000
|
63
|
+
for j in 0..floors.length - 1
|
64
|
+
for k in 0..coordinates_building[j].length - 1
|
65
|
+
y = coordinates_building[j][k][1] - coordinates_street[i][1]
|
66
|
+
x = coordinates_building[j][k][0] - coordinates_street[i][0]
|
67
|
+
distance = (x + y) / 2 # finding the distance of each building node with each street node
|
68
|
+
if distance < dist_min
|
69
|
+
distance = (x**2 + y**2)**0.5
|
70
|
+
if distance < dist_min
|
71
|
+
dist_min = distance
|
72
|
+
height[i] = floors[j]
|
73
|
+
id_building[i] = coordinates_building[j][k][3].split('_')[0] # for future implementations set as attributes :id, :coordinates
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
ii = 0
|
79
|
+
while ii != i && id_building[i] != id_building[ii] # id_building[ii] != id_bui
|
80
|
+
ii += 1
|
81
|
+
if ii == i
|
82
|
+
n_buildings_street += 1
|
83
|
+
end
|
84
|
+
end
|
85
|
+
height_sum += height[i]
|
86
|
+
end
|
87
|
+
@n_buildings_street = n_buildings_street
|
88
|
+
@av_height = (height_sum / (i + 1)).to_f.round(2)
|
89
|
+
end
|
90
|
+
|
91
|
+
# defining a method which defines the "threshold height", in an iterative way and adding 0.1m of height until the threhold limit is reached
|
92
|
+
# when the % of streets in the district above the threshold is equal to the UG rate defined by the user
|
93
|
+
def threshold_height(street_type, ug_ratio)
|
94
|
+
h_threshold = 0
|
95
|
+
tot_build_in_streets = 0
|
96
|
+
n_street_oh = []
|
97
|
+
for i in 0..street_type.length - 1
|
98
|
+
tot_build_in_streets += street_type[i].n_buildings_street
|
99
|
+
end
|
100
|
+
# puts tot_build_in_streets
|
101
|
+
street_set_oh = (tot_build_in_streets * (1 - ug_ratio)).round
|
102
|
+
ii = 0
|
103
|
+
while ii == 0 || n_street_oh[ii - 1] < street_set_oh
|
104
|
+
n_street_oh[ii] = 0
|
105
|
+
for i in 0..street_type.length - 1
|
106
|
+
if street_type[i].av_height < h_threshold
|
107
|
+
n_street_oh[ii] += street_type[i].n_buildings_street
|
108
|
+
end
|
109
|
+
end
|
110
|
+
ii += 1
|
111
|
+
h_threshold += 0.10
|
112
|
+
end
|
113
|
+
h_threshold -= 0.10
|
114
|
+
return h_threshold
|
115
|
+
end
|
116
|
+
|
117
|
+
# defining a method that decides to place each street either OH or UG, according to its average height and the threshold height,
|
118
|
+
# if the street has a height below the threshold height it has to modelled has OH, otherwise UG
|
119
|
+
def classify_street_type(street_type, ug_ratio)
|
120
|
+
h = threshold_height(street_type, ug_ratio)
|
121
|
+
if @av_height < h
|
122
|
+
@type = 'A' # 'OH'
|
123
|
+
else
|
124
|
+
@type = 'S' # 'UG'
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,220 @@
|
|
1
|
+
# *********************************************************************************
|
2
|
+
# URBANopt (tm), Copyright (c) 2019-2021, 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 'urbanopt/rnm/logger'
|
42
|
+
|
43
|
+
module URBANopt
|
44
|
+
module RNM
|
45
|
+
class PostProcessor
|
46
|
+
##
|
47
|
+
# Initialize Post-Processor
|
48
|
+
##
|
49
|
+
# [parameters:]
|
50
|
+
# * +results+ - _Hash_ - Hash of RNM-US results returned from the API
|
51
|
+
# * +scenario+ - _String_ - Path to scenario_dir
|
52
|
+
def initialize(results, scenario_dir, feature_file, reopt: false)
|
53
|
+
@results = results
|
54
|
+
@scenario_dir = scenario_dir
|
55
|
+
@results_dir = File.join(@scenario_dir, 'rnm-us', 'results')
|
56
|
+
@report_filename = 'scenario_report_rnm.json'
|
57
|
+
@geojson_filename = 'feature_file_rnm.json'
|
58
|
+
@feature_file = feature_file
|
59
|
+
@reopt = reopt
|
60
|
+
end
|
61
|
+
|
62
|
+
##
|
63
|
+
# Post Process report and feature file
|
64
|
+
##
|
65
|
+
def post_process
|
66
|
+
generate_report
|
67
|
+
generate_feature_file
|
68
|
+
puts "RNM results were added to scenario report and feature file. New files can be found in #{@results_dir}"
|
69
|
+
end
|
70
|
+
|
71
|
+
##
|
72
|
+
# Generate Scenario report
|
73
|
+
##
|
74
|
+
def generate_report
|
75
|
+
|
76
|
+
# calculate rnm statistics
|
77
|
+
rnm_stats = calculate_stats
|
78
|
+
|
79
|
+
# get scenario
|
80
|
+
scenario = get_scenario
|
81
|
+
|
82
|
+
# merge stats with scenario report (before feature_reports section)
|
83
|
+
|
84
|
+
scenario['scenario_report']['rnm_results'] = rnm_stats
|
85
|
+
|
86
|
+
# save back to scenario directory as scenario_report_rnm.json
|
87
|
+
File.open(File.join(@scenario_dir, @report_filename), "w") do |f|
|
88
|
+
f.write(JSON.pretty_generate(scenario))
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
##
|
94
|
+
# Load Scenario Report
|
95
|
+
##
|
96
|
+
def get_scenario
|
97
|
+
if @reopt
|
98
|
+
# get reopt scenario report
|
99
|
+
return JSON.parse(File.read(File.join(@scenario_dir, 'feature_optimization.json')))
|
100
|
+
else
|
101
|
+
# get default scenario report
|
102
|
+
return JSON.parse(File.read(File.join(@scenario_dir, 'default_scenario_report.json')))
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
##
|
107
|
+
# Generate new GeoJSON file
|
108
|
+
##
|
109
|
+
def generate_feature_file
|
110
|
+
|
111
|
+
# get results GeoJSON file and read in
|
112
|
+
results = JSON.parse(File.read(File.join(@results_dir, 'GeoJSON', 'Distribution_system.json')))
|
113
|
+
|
114
|
+
# merge the two files
|
115
|
+
results['features'].each do |feature|
|
116
|
+
@feature_file['features'].append(feature)
|
117
|
+
end
|
118
|
+
|
119
|
+
# save back to scenario directory as features_and_rnm.json
|
120
|
+
File.open(File.join(@scenario_dir, @geojson_filename), "w") do |f|
|
121
|
+
f.write(JSON.pretty_generate(@feature_file))
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
##
|
126
|
+
# Calculate report statistics from raw results
|
127
|
+
##
|
128
|
+
def calculate_stats
|
129
|
+
# calculate statistics and append to scenario report
|
130
|
+
stats = {}
|
131
|
+
# demand generation planning
|
132
|
+
stats['demand_generation_planning'] = []
|
133
|
+
@results['Demand/generation and number of consumers/distributed generators'].each do |item|
|
134
|
+
rec = {}
|
135
|
+
case item['Voltage level']
|
136
|
+
when 'LV'
|
137
|
+
rec['type'] = "Low Voltage (LV) #{item['Type'].strip}"
|
138
|
+
when 'MV'
|
139
|
+
rec['type'] = "Medium Voltage (MV) #{item['Type'].strip}"
|
140
|
+
else
|
141
|
+
rec['type'] = item['Voltage level'] + item['Type'].strip
|
142
|
+
end
|
143
|
+
if item['Type'].strip == 'Consumers'
|
144
|
+
# consumers
|
145
|
+
rec['peak_demand_kw'] = item['Peak demand/generation (kW)']
|
146
|
+
elsif item['Type'].include? 'generators'
|
147
|
+
# generators
|
148
|
+
rec['max_generation_kw'] = item['Peak demand/generation (kW)']
|
149
|
+
else
|
150
|
+
rec['peak_demand_generation_kw'] = item['Peak demand/generation (kW)']
|
151
|
+
end
|
152
|
+
rec['number_of_nodes_in_network'] = item['Number']
|
153
|
+
stats['demand_generation_planning'] << rec
|
154
|
+
end
|
155
|
+
|
156
|
+
# lines LV and MV
|
157
|
+
stats['electrical_lines_length'] = {}
|
158
|
+
km_to_mi = 0.621371
|
159
|
+
@results['Length of overhead and underground electrical lines'].each do |item|
|
160
|
+
case item['Voltage level']
|
161
|
+
when 'Lines LV'
|
162
|
+
stats['electrical_lines_length']['low_voltage'] = {}
|
163
|
+
stats['electrical_lines_length']['low_voltage']['overhead_mi'] = (item['Overhead (km)'] * km_to_mi).round(4)
|
164
|
+
stats['electrical_lines_length']['low_voltage']['underground_mi'] = (item['Underground (km)'] * km_to_mi).round(4)
|
165
|
+
when 'Lines MV'
|
166
|
+
stats['electrical_lines_length']['medium_voltage'] = {}
|
167
|
+
stats['electrical_lines_length']['medium_voltage']['overhead_mi'] = (item['Overhead (km)'] * km_to_mi).round(4)
|
168
|
+
stats['electrical_lines_length']['medium_voltage']['underground_mi'] = (item['Underground (km)'] * km_to_mi).round(4)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
transformer_capacity = 0
|
172
|
+
@results['Substations and distribution transformers'].each do |item|
|
173
|
+
transformer_capacity += item['Size (kVA)'] * item['Number']
|
174
|
+
end
|
175
|
+
stats['distribution_transformers_capacity_kva'] = transformer_capacity
|
176
|
+
|
177
|
+
# costs
|
178
|
+
stats['costs'] = {}
|
179
|
+
stats['costs']['investment'] = {}
|
180
|
+
stats['costs']['yearly_maintenance'] = {}
|
181
|
+
@results['Summary'].each do |item|
|
182
|
+
case item['Level']
|
183
|
+
when 'LV'
|
184
|
+
stats['costs']['investment']['low_voltage_network'] = item['Investment cost']
|
185
|
+
stats['costs']['yearly_maintenance']['low_voltage_network'] = item['Preventive maintenance (yearly)']
|
186
|
+
when 'MV'
|
187
|
+
stats['costs']['investment']['medium_voltage_network'] = item['Investment cost']
|
188
|
+
stats['costs']['yearly_maintenance']['medium_voltage_network'] = item['Preventive maintenance (yearly)']
|
189
|
+
when 'Dist.Transf.'
|
190
|
+
stats['costs']['investment']['distribution_transformers'] = item['Investment cost']
|
191
|
+
stats['costs']['yearly_maintenance']['distribution_transformers'] = item['Preventive maintenance (yearly)']
|
192
|
+
when 'HV/MV Subest.'
|
193
|
+
stats['costs']['investment']['primary_substations'] = item['Investment cost']
|
194
|
+
stats['costs']['yearly_maintenance']['primary_substations'] = item['Preventive maintenance (yearly)']
|
195
|
+
end
|
196
|
+
end
|
197
|
+
# cost totals
|
198
|
+
inv_tot = 0
|
199
|
+
stats['costs']['investment'].each do |key, val|
|
200
|
+
inv_tot += val
|
201
|
+
end
|
202
|
+
stats['costs']['investment']['total'] = inv_tot
|
203
|
+
maint_tot = 0
|
204
|
+
stats['costs']['yearly_maintenance'].each do |key, val|
|
205
|
+
maint_tot += val
|
206
|
+
end
|
207
|
+
stats['costs']['yearly_maintenance']['total'] = maint_tot
|
208
|
+
|
209
|
+
# reliability indexes
|
210
|
+
stats['reliability_indexes'] = {}
|
211
|
+
# sum of interruptions duration / num customers. 6 would be too high
|
212
|
+
stats['reliability_indexes']['SAIDI'] = @results['Reliability indexes'][0]['ASIDI']
|
213
|
+
# num interruptions / num customers. should be < 1
|
214
|
+
stats['reliability_indexes']['SAIFI'] = @results['Reliability indexes'][0]['ASIFI']
|
215
|
+
|
216
|
+
return stats
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# *********************************************************************************
|
2
|
+
# URBANopt (tm), Copyright (c) 2019-2021, 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
|
+
module URBANopt
|
41
|
+
module RNM
|
42
|
+
# class created to verify that if a component is repeated more than once in the extended catalog
|
43
|
+
# than it is parsed only one time for the OpenDSS catalog
|
44
|
+
class ProcessorOpendss
|
45
|
+
attr_accessor :cont, :list
|
46
|
+
|
47
|
+
def initialize
|
48
|
+
@list = list
|
49
|
+
@cont = cont
|
50
|
+
end
|
51
|
+
|
52
|
+
def process_data(catalog_data)
|
53
|
+
for kk in 0..catalog_data.length - 1 # inside each component
|
54
|
+
zz = 0
|
55
|
+
if @list.nil?
|
56
|
+
@cont = 0
|
57
|
+
@list = []
|
58
|
+
else
|
59
|
+
if catalog_data[kk].include? 'Probability' # referring to transformers
|
60
|
+
zz += 1 while zz < @cont && @list[zz]['Name'] != catalog_data[kk]['Name']
|
61
|
+
else
|
62
|
+
zz += 1 while zz < @cont && @list[zz] != catalog_data[kk]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
if zz == @cont
|
66
|
+
@list[@cont] = catalog_data[kk] # associating conductores values in this list
|
67
|
+
@cont += 1
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|