urbanopt-rnm-us 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bfd1fdcbaf0908d6ec884147fd9a26c78429181063cadb15fd5210e89bacd83e
4
- data.tar.gz: d8ca20d16669801961c405b8609f6a8adf21bfc2c5862e604e74f90732cece6d
3
+ metadata.gz: f7601a8b6f72052bb8b84d726e2bf579d955b00a69fe4087400f89934ed68ea2
4
+ data.tar.gz: cd015470a41029e2c0b9c811467ac0609b6fea56beb1f885ba9c86ddd13c1e1d
5
5
  SHA512:
6
- metadata.gz: 9364a3a2cd150e57ee2dff2e1f070065fdc83b35dc519361e9c076393e7f3ee9b290899fef8952b26eae42abc8872989fe5ad8a7ef00b7a1a35397273578a3c7
7
- data.tar.gz: 0fcaf071315fac36a51abace8a64f3278d80c854fd6d85bbb7a63affa774cd0a09e7c4196e2aa0e71ee446d7e8f9cd8349e3c068b67d4ae7c235b82f03433a79
6
+ metadata.gz: b823b847e4774a055c7923388a349aa7552527fb2974d5b061fcf820ffa71a4e77dfb4c5b874f72d1223e3c4da9d5877d3a1b8353b5e08ae5a0aed925bdef55e
7
+ data.tar.gz: d62a00a1f4869153476975a00299d730d16dde5789f8ab114395846b2e466dc47dabb378821c1f008b2eddccede50af2f3bcd26e1e81afa5f677ba14fb6e5dcc
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## Version 0.1.1
4
+
5
+ Date Range 07/22/21 - 10/28/21
6
+
7
+ - Fixed [#10]( https://github.com/urbanopt/urbanopt-rnm-us-gem/issues/7 ), Fix peak profile generation for prosumer profiles
8
+ - Fixed [#8]( https://github.com/urbanopt/urbanopt-rnm-us-gem/issues/8 ), Use timestep_per_hour defined in UO feature report for the interval reporting
9
+ - Fixed [#10]( https://github.com/urbanopt/urbanopt-rnm-us-gem/issues/10 ), Add other residential types to prosumer/consumer calculations
10
+
3
11
  ## Version 0.1.0
4
12
 
5
13
  Initial version of the RNM-US gem.
@@ -175,7 +175,7 @@ module URBANopt
175
175
  conservative_factor = 0.8 # considered as a reasonable assumption, but this value could be changed
176
176
  average_peak_folder = JSON.parse(File.read(@average_building_peak_catalog_path))
177
177
  for i in 0..feature_file.length - 1
178
- area = (feature_file[i]['floor_area']).round(2)
178
+ area = feature_file[i].has_key?('floor_area') ? (feature_file[i]['floor_area']).round(2) : feature_file[i]['floor_area_sqft'].round(2)
179
179
  building_type = feature_file[i]['building_type'] # it specifies the type of building, sometimes it is directly the sub-type
180
180
  counter = 0 # counter to find number of buildings type belonging to same "category"
181
181
  average_peak_folder.each do |building_class|
@@ -214,16 +214,17 @@ module URBANopt
214
214
  # the method passes as arguments the urbanopt json and csv output file for each feature and the building coordinates previously calculated
215
215
  # and the "extreme" hour used to plan the network
216
216
  def customer_files_load(csv_feature_report, json_feature_report, building_map, building_nodes, hour)
217
+ n_timestep_per_hour = json_feature_report["timesteps_per_hour"].to_i
217
218
  profiles = Hash.new { |h, k| h[k] = [] }
218
219
  single_values = Hash.new(0)
219
- hours = 23
220
+ hours = 24 * n_timestep_per_hour -1
220
221
  feature_type = json_feature_report['program']['building_types'][0]['building_type']
221
- residential_building_types = 'Single-Family Detached' # add the other types
222
+ residential_building_types = ["Single-Family Detached", "Single-Family Attached", "Multifamily"]
222
223
  # finding the index where to start computing and saving the info, from the value of the "worst-case hour" for the max peak consumption of the district
223
224
  if residential_building_types.include? feature_type
224
- profile_start_max = hour.hour_index_max_res - hour.peak_hour_max_res
225
+ profile_start_max = hour.hour_index_max_res - ((hour.peak_hour_max_res.split(':')[0].to_i + (hour.peak_hour_max_res.split(':')[1].to_i / 60)) * n_timestep_per_hour)
225
226
  else
226
- profile_start_max = hour.hour_index_max_comm - hour.peak_hour_max_comm
227
+ profile_start_max = hour.hour_index_max_comm - ((hour.peak_hour_max_comm.split(':')[0].to_i + (hour.peak_hour_max_comm.split(':')[1].to_i / 60)) * n_timestep_per_hour)
227
228
  end
228
229
  k = 0 # index for each hour of the year represented in the csv file
229
230
  i = 0 # to represent the 24 hours of a day
@@ -74,7 +74,7 @@ module URBANopt
74
74
 
75
75
  # method defined for the case of a single node where both battery, DG and consumers are placed
76
76
  # evaluation of the peak power in each node to define the type of connection (e.g. voltage level and n phases)
77
- def construct_prosumer_general(profiles, single_values, building_map, area, height, users, der_capacity)
77
+ def construct_prosumer_general(profiles, profiles_planning, single_values, building_map, area, height, users, der_capacity)
78
78
  id = building_map[3]
79
79
  id_dg = "#{building_map[3]}_DG"
80
80
  id_batt = "#{building_map[3]}_battery"
@@ -84,8 +84,8 @@ module URBANopt
84
84
  # in the hour with generation max peak
85
85
  # in the hour with storage max peak
86
86
 
87
- for i in 0..profiles[:planning_profile_cust_active].length - 1
88
- hourly_app_power = ((profiles[:planning_profile_cust_active][i] + profiles[:planning_profile_storage_active][i] - profiles[:planning_profile_dg_active][i]) / @power_factor).abs
87
+ for i in 0..profiles_planning[:planning_profile_cust_active].length-1
88
+ hourly_app_power = ((profiles_planning[:planning_profile_cust_active][i] + profiles_planning[:planning_profile_storage_active][i] - profiles_planning[:planning_profile_dg_active][i])/@power_factor).abs
89
89
  if hourly_app_power > peak_app_power_node
90
90
  peak_app_power_node = hourly_app_power
91
91
  end
@@ -99,22 +99,22 @@ module URBANopt
99
99
  end
100
100
  @customers.push([building_map, id, voltage_default, single_values[:peak_active_power_cons], single_values[:peak_reactive_power_cons], phases])
101
101
  @customers_ext.push([building_map, id, voltage_default, single_values[:peak_active_power_cons], single_values[:peak_reactive_power_cons], phases, area, height, (single_values[:energy]).round(2), single_values[:peak_active_power_cons], single_values[:peak_reactive_power_cons], users])
102
- @profile_customer_q.push([id, 48, profiles[:planning_profile_cust_reactive]])
103
- @profile_customer_p.push([id, 48, profiles[:planning_profile_cust_active]])
102
+ @profile_customer_q.push([id, 48, profiles_planning[:planning_profile_cust_reactive]])
103
+ @profile_customer_p.push([id, 48, profiles_planning[:planning_profile_cust_active]])
104
104
  @profile_customer_p_ext.push([id, 8760, profiles[:yearly_profile_cust_active]])
105
105
  @profile_customer_q_ext.push([id, 8760, profiles[:yearly_profile_cust_reactive]])
106
-
107
- if !der_capacity[:storage].nil? && der_capacity[:storage] > 0
108
- @customers.push([building_map, id_batt, voltage_default, single_values[:peak_active_power_storage], single_values[:peak_reactive_power_storage], phases])
106
+
107
+ if der_capacity[:storage] != nil && der_capacity[:storage] > 0
108
+ @customers.push([building_map, id_batt, voltage_default, single_values[:peak_active_power_storage],single_values[:peak_reactive_power_storage], phases])
109
109
  @customers_ext.push([building_map, id_batt, voltage_default, single_values[:peak_active_power_storage], single_values[:peak_reactive_power_storage], phases, area, height, (single_values[:energy]).round(2), single_values[:peak_active_power_storage], single_values[:peak_reactive_power_storage], users])
110
- @profile_customer_q.push([id_batt, 48, profiles[:planning_profile_storage_reactive]])
111
- @profile_customer_p.push([id_batt, 48, profiles[:planning_profile_storage_active]])
110
+ @profile_customer_q.push([id_batt, 48, profiles_planning[:planning_profile_storage_reactive]])
111
+ @profile_customer_p.push([id_batt, 48, profiles_planning[:planning_profile_storage_active]])
112
112
  @profile_customer_p_ext.push([id_batt, 8760, profiles[:yearly_profile_storage_active]])
113
113
  @profile_customer_q_ext.push([id_batt, 8760, profiles[:yearly_profile_storage_reactive]])
114
114
  end
115
115
  @dg.push([building_map, id_dg, voltage_default, der_capacity[:dg], single_values[:peak_active_power_dg].round(2), single_values[:peak_reactive_power_dg].round(2), phases])
116
- @dg_profile_p.push([id_dg, 48, profiles[:planning_profile_dg_active]])
117
- @dg_profile_q.push([id_dg, 48, profiles[:planning_profile_dg_reactive]])
116
+ @dg_profile_p.push([id_dg, 48, profiles_planning[:planning_profile_dg_active]])
117
+ @dg_profile_q.push([id_dg, 48, profiles_planning[:planning_profile_dg_reactive]])
118
118
  @profile_dg_p_extended.push([id_dg, 8760, profiles[:yearly_profile_dg_active]])
119
119
  @profile_dg_q_extended.push([id_dg, 8760, profiles[:yearly_profile_dg_reactive]])
120
120
  end
@@ -127,7 +127,7 @@ module URBANopt
127
127
  # this method is called only if the user sets the option of "only LV nodes" to true
128
128
  # defining a certain numb of nodes for each building and distributing the peak power values equally
129
129
  # among the nodes of each building
130
- def construct_prosumer_lv(nodes_per_bldg = 0, profiles, single_values, building_map, building_nodes, area, height, users, der_capacity)
130
+ def construct_prosumer_lv(nodes_per_bldg = 0, profiles, profiles_planning, single_values, building_map, building_nodes, area, height, users, der_capacity)
131
131
  # the default variables are defined (i.e. type and rurality type)
132
132
  planning_profile_node_active = []
133
133
  planning_profile_node_reactive = []
@@ -138,6 +138,7 @@ module URBANopt
138
138
  cont = 1
139
139
  cont_reverse = 1
140
140
  nodes_consumers = nodes_per_bldg - 1
141
+
141
142
  for i in 1..nodes_per_bldg
142
143
  coordinates = building_map
143
144
  node = closest_node + cont # to set the new nodes with enough distance among each others
@@ -145,10 +146,10 @@ module URBANopt
145
146
  if i > 1 && node <= building_nodes.length - 2
146
147
  coordinates = building_nodes[node] # take the closest building node index to the street and pass the nodes after it
147
148
  cont += 1
148
- elsif i > 1
149
+ elsif i > 1
149
150
  coordinates = building_nodes[node_reverse]
150
151
  cont_reverse += 1
151
- end
152
+ end
152
153
  # this condition is used to firstly place the building consumption nodes and then the last node
153
154
  # to be placed is the one referred to DG and battery for the building
154
155
  if i < nodes_per_bldg # considering the consumers nodes
@@ -157,12 +158,12 @@ module URBANopt
157
158
  peak_active_power_cons = (single_values[:peak_active_power_cons] / nodes_consumers).round(2)
158
159
  peak_reactive_power_cons = (single_values[:peak_reactive_power_cons] / nodes_consumers).round(2)
159
160
  voltage_default, phases = voltage_values(peak_active_power_cons / @power_factor)
160
- for k in 0..profiles[:planning_profile_cust_active].length - 1
161
- planning_profile_node_active[k] = (profiles[:planning_profile_cust_active][k] / nodes_consumers).round(2)
162
- planning_profile_node_reactive[k] = (profiles[:planning_profile_cust_reactive][k] / nodes_consumers).round(2)
161
+ for k in 0..profiles_planning[:planning_profile_cust_active].length - 1
162
+ planning_profile_node_active[k] = (profiles_planning[:planning_profile_cust_active][k] / nodes_consumers).round(2)
163
+ planning_profile_node_reactive[k] = (profiles_planning[:planning_profile_cust_reactive][k] / nodes_consumers).round(2)
163
164
  end
164
165
  for k in 0..profiles[:yearly_profile_cust_active].length - 1
165
- yearly_profile_node_active[k] = (profiles[:yearly_profile_cust_active][k] / nodes_consumers).round(2)
166
+ yearly_profile_node_active[k] = (profiles[:yearly_profile_cust_active][k] / nodes_consumers).round(2)
166
167
  yearly_profile_node_reactive[k] = (profiles[:yearly_profile_cust_reactive][k] / nodes_consumers).round(2)
167
168
  end
168
169
  @customers.push([coordinates, id, voltage_default, peak_active_power_cons, peak_reactive_power_cons, phases])
@@ -173,20 +174,20 @@ module URBANopt
173
174
  @profile_customer_q_ext.push([id, 8760, yearly_profile_node_reactive])
174
175
  else
175
176
  # considering the DG and battery
176
- voltage_default, phases = voltage_values(der_capacity[:dg]) # assuming that the pv capacity is always higher than battery capacity
177
+ voltage_default, phases = voltage_values(der_capacity[:dg]) #assuming that the pv capacity is always higher than battery capacity
177
178
  id_dg = "#{coordinates[3]}_DG"
178
179
  id_batt = "#{coordinates[3]}_battery"
179
180
  coordinates.pop
180
181
  @dg.push([coordinates, id_dg, voltage_default, der_capacity[:dg], single_values[:peak_active_power_dg].round(2), single_values[:peak_reactive_power_dg].round(2), phases])
181
- @dg_profile_p.push([id_dg, 48, profiles[:planning_profile_dg_active]])
182
- @dg_profile_q.push([id_dg, 48, profiles[:planning_profile_dg_reactive]])
182
+ @dg_profile_p.push([id_dg, 48, profiles_planning[:planning_profile_dg_active]])
183
+ @dg_profile_q.push([id_dg, 48, profiles_planning[:planning_profile_dg_reactive]])
183
184
  @profile_dg_p_extended.push([id_dg, 8760, profiles[:yearly_profile_dg_active]])
184
185
  @profile_dg_q_extended.push([id_dg, 8760, profiles[:yearly_profile_dg_reactive]])
185
- if !der_capacity[:storage].nil? && der_capacity[:storage] > 0
186
+ if der_capacity[:storage] != nil && der_capacity[:storage] > 0
186
187
  @customers.push([coordinates, id_batt, voltage_default, single_values[:peak_active_power_storage], single_values[:peak_reactive_power_storage], phases])
187
188
  @customers_ext.push([coordinates, id_batt, voltage_default, single_values[:peak_active_power_storage], single_values[:peak_reactive_power_storage], phases, area, height, (single_values[:energy]).round(2), single_values[:peak_active_power_storage], single_values[:peak_reactive_power_storage], users])
188
- @profile_customer_q.push([id_batt, 48, profiles[:planning_profile_storage_reactive]])
189
- @profile_customer_p.push([id_batt, 48, profiles[:planning_profile_storage_active]])
189
+ @profile_customer_q.push([id_batt, 48, profiles_planning[:planning_profile_storage_reactive]])
190
+ @profile_customer_p.push([id_batt, 48, profiles_planning[:planning_profile_storage_active]])
190
191
  @profile_customer_p_ext.push([id_batt, 8760, profiles[:yearly_profile_storage_active]])
191
192
  @profile_customer_q_ext.push([id_batt, 8760, profiles[:yearly_profile_storage_reactive]])
192
193
  end
@@ -247,16 +248,16 @@ module URBANopt
247
248
  conservative_factor = 0.8 # considered as a reasonable assumption, but this value could be changed
248
249
  average_peak_folder = JSON.parse(File.read(@average_building_peak_catalog_path))
249
250
  for i in 0..feature_file.length - 1
250
- area = (feature_file[i]['floor_area']).round(2)
251
- building_type = feature_file[i]['building_type'] # it specifies the type of building, sometimes it is directly the sub-type
251
+ area = feature_file[i].key?('floor_area') ? (feature_file[i]['floor_area']).round(2) : (feature_file[i]['floor_area_sqft']).round(2)
252
+ building_type = feature_file[i]['building_type'] #it specifies the type of building, sometimes it is directly the sub-type
252
253
  counter = 0 # counter to find number of buildings type belonging to same "category"
253
254
  average_peak_folder.each do |building_class|
254
- if building_type == building_class['building type'] || building_type == building_class['sub-type']
255
+ if (building_type == building_class["building type"] || building_type == building_class["sub-type"])
255
256
  average_peak = (building_class['average peak demand (kW/ft2)'].to_f * area).to_f.round(4) # finding the average peak considering the floor area of the bilding under consideration
256
257
  average_peak_by_size[counter] = average_peak
257
258
  floor_area[counter] = (building_class['floor_area (ft2)'] - area).abs # minimum difference among area and area from the prototypes defined by DOE
258
259
  counter += 1
259
- # in this way I don t consider residential and I assume it s average_peak = 0, it is ok because we assume always 1 node per RES consumers, single-detached family houses
260
+ # in this way I don t consider residential and I assume it s average_peak = 0, it is ok because we assume always 1 node per RES consumers, single-detached family houses
260
261
  end
261
262
  end
262
263
  if counter > 1
@@ -272,100 +273,107 @@ module URBANopt
272
273
  average_peak = mixed_use_av_peak # average peak per mixed use considering the building types which are in this building
273
274
  area = area_mixed_use
274
275
  end
275
- nodes_per_bldg = (average_peak / (@lv_limit[:three_phase] * @power_factor * conservative_factor)).to_f.ceil # computing number of nodes per building
276
- if nodes_per_bldg > @max_num_lv_nodes # defined as reasonable maximum
276
+ nodes_per_bldg = ((average_peak / (@lv_limit[:three_phase] * @power_factor * conservative_factor)).to_f).ceil # computing number of nodes per building
277
+ if nodes_per_bldg > @max_num_lv_nodes #that it is equal to how it was before
277
278
  nodes_per_bldg = 1
278
279
  @medium_voltage = true
279
280
  end
280
-
281
- nodes_per_bldg += 1 # tacking into account the extra node for distributed generation and the battery
282
-
281
+
282
+ nodes_per_bldg += 1 # tacking into account the extra node for distributed generation and the battery
283
283
  return nodes_per_bldg, area
284
284
  end
285
285
 
286
+ # method to order profiles consistently
287
+ def profiles_planning_creation(profiles_planning, power, single_values, i, hours, power_factor)
288
+ profiles_planning[:planning_profile_cust_active][i] = power["REopt:Electricity:Load:Total(kw)"].to_f
289
+ profiles_planning[:planning_profile_storage_active][i] = power['REopt:Electricity:Grid:ToBattery(kw)'].to_f + power['REopt:ElectricityProduced:Generator:ToBattery(kw)'].to_f + power['REopt:ElectricityProduced:PV:ToBattery(kw)'].to_f + power['REopt:ElectricityProduced:Wind:ToBattery(kw)'].to_f - power['REopt:Electricity:Storage:ToLoad(kw)'].to_f - power['REopt:Electricity:Storage:ToGrid(kw)'].to_f
290
+ profiles_planning[:planning_profile_dg_active][i] = power["REopt:ElectricityProduced:Total(kw)"].to_f
291
+ profiles_planning[:planning_profile_cust_reactive][i] = profiles_planning[:planning_profile_cust_active][i] * Math.tan(Math.acos(power_factor))
292
+ profiles_planning[:planning_profile_storage_reactive][i] = profiles_planning[:planning_profile_storage_active][i] * Math.tan(Math.acos(power_factor))
293
+ profiles_planning[:planning_profile_dg_reactive][i] = profiles_planning[:planning_profile_dg_active][i] * Math.tan(Math.acos(power_factor))
294
+ if profiles_planning[:planning_profile_cust_active][i] > single_values[:peak_active_power_cons]
295
+ single_values[:peak_active_power_cons] = profiles_planning[:planning_profile_cust_active][i]
296
+ single_values[:peak_reactive_power_cons] = single_values[:peak_active_power_cons] * Math.tan(Math.acos(power_factor))
297
+ end
298
+ if profiles_planning[:planning_profile_storage_active][i] > single_values[:peak_active_power_storage]
299
+ single_values[:peak_active_power_storage] = profiles_planning[:planning_profile_storage_active][i]
300
+ single_values[:peak_reactive_power_storage] = single_values[:peak_active_power_storage] * Math.tan(Math.acos(power_factor))
301
+ end
302
+ if profiles_planning[:planning_profile_dg_active][i] > single_values[:peak_active_power_dg]
303
+ single_values[:peak_active_power_dg] = profiles_planning[:planning_profile_dg_active][i]
304
+ single_values[:peak_reactive_power_dg] = single_values[:peak_active_power_dg] * (Math.tan(Math.acos(power_factor)))
305
+ end
306
+ return profiles_planning, single_values
307
+ end
308
+
286
309
  # defining a method for the customers and generators files creation:
287
310
  # obtaining all the needed input from each feature_report.csv file (active & apparent power and tot energy consumed and produced)
288
311
  # and from each feature_report.json file (area, height, number of users, DG capacity)
289
312
  # the method passes as arguments the urbanopt json and csv output file for each feature and the building coordinates previously calculated
290
313
  # and the "extreme" hours used to plan the network
291
314
  def prosumer_files_load(csv_feature_report, json_feature_report, building_map, building_nodes, hour)
292
- profiles = Hash.new { |h, k| h[k] = [] }
315
+ # add variable to include how many timestep per hour, so the profiles become 48 * n_timestep_per_hour
316
+ n_timestep_per_hour = json_feature_report["timesteps_per_hour"].to_i
317
+ profiles_planning = Hash.new{|h, k| h[k] = Array.new(48*n_timestep_per_hour, 0)} # initializing each profile hash to 0 for the number of intervals considered for the planning of the network
318
+ profiles = Hash.new{|h, k| h[k] = []}
293
319
  single_values = Hash.new(0)
294
320
  @medium_voltage = false
295
- hours = 23
296
- feature_type = json_feature_report['program']['building_types'][0]['building_type']
297
- residential_building_types = 'Single-Family Detached' # add the other types
321
+ hours = 24 * n_timestep_per_hour -1 # change name, maybe to intervals
322
+ feature_type = json_feature_report['program']['building_types'][0]["building_type"]
323
+ residential_building_types = ["Single-Family Detached", "Single-Family Attached", "Multifamily"]
298
324
  # finding the index where to start computing and saving the info, from the value of the "worst-case hour" for the max peak consumption of the district
325
+ # considering num timestep per hours and the fact that each day starts from 1 am
299
326
  if residential_building_types.include? feature_type
300
- profile_start_max = hour.hour_index_max_res - hour.peak_hour_max_res
301
- profile_start_min = hour.hour_index_min_res - hour.peak_hour_min_res
327
+ profile_start_max = hour.hour_index_max_res - ((hour.peak_hour_max_res.split(':')[0].to_i + (hour.peak_hour_max_res.split(':')[1].to_i / 60)) * n_timestep_per_hour)
328
+ profile_start_min = hour.hour_index_min_res - ((hour.peak_hour_min_res.split(':')[0].to_i + (hour.peak_hour_min_res.split(':')[1].to_i / 60)) * n_timestep_per_hour)
302
329
  else
303
- profile_start_max = hour.hour_index_max_comm - hour.peak_hour_max_comm
304
- profile_start_min = hour.hour_index_min_comm - hour.peak_hour_min_comm
330
+ profile_start_max = hour.hour_index_max_comm - ((hour.peak_hour_max_comm.split(':')[0].to_i + (hour.peak_hour_max_comm.split(':')[1].to_i / 60)) * n_timestep_per_hour)
331
+ profile_start_min = hour.hour_index_min_comm - ((hour.peak_hour_min_comm.split(':')[0].to_i + (hour.peak_hour_min_comm.split(':')[1].to_i / 60)) * n_timestep_per_hour)
305
332
  end
306
333
  # finding the index where to start computing and saving the info, from the value of the "most extreme hours" for the max peak consumption of the district
307
- # profile_start_max = hour.hour_index_max - hour.peak_hour_max
308
- # profile_start_min = hour.hour_index_min - hour.peak_hour_min
309
- k = 0 # index for each hour of the year represented in the csv file
310
- i = 0 # to represent the 24 hours
334
+ k = 0 # index for each hour of the year represented in the csv file
335
+ i = hours +1 # to represent the 24 hours in case of max_net_generation day
336
+ j = 0 # to represent the 24 hours in case of peak_demand_day
311
337
  h_cons_batt = 0
312
338
  h_dg_max = 0 # hour with max DG generation
313
339
  h_stor_max = 0 # hour with max storage absorption
314
340
  max_peak = 0
315
- # content = CSV.foreach(csv_feature_report, headers: true) do |power|
316
341
  CSV.foreach(csv_feature_report, headers: true) do |power|
317
- @power_factor = power['Electricity:Facility Power(kW)'].to_f / power['Electricity:Facility Apparent Power(kVA)'].to_f
318
- profiles[:yearly_profile_cust_active].push(power['REopt:Electricity:Load:Total(kw)'].to_f)
342
+ @power_factor = power["Electricity:Facility Power(kW)"].to_f / power["Electricity:Facility Apparent Power(kVA)"].to_f
343
+ profiles[:yearly_profile_cust_active].push(power["REopt:Electricity:Load:Total(kw)"].to_f)
319
344
  profiles[:yearly_profile_cust_reactive].push(profiles[:yearly_profile_cust_active][k] * Math.tan(Math.acos(@power_factor)))
320
- profiles[:yearly_profile_dg_active].push(power['REopt:ElectricityProduced:Total(kw)'].to_f)
345
+ profiles[:yearly_profile_dg_active].push(power["REopt:ElectricityProduced:Total(kw)"].to_f)
321
346
  profiles[:yearly_profile_dg_reactive].push(profiles[:yearly_profile_dg_active][k] * Math.tan(Math.acos(@power_factor)))
322
347
  profiles[:yearly_profile_storage_active].push(power['REopt:Electricity:Grid:ToBattery(kw)'].to_f + power['REopt:ElectricityProduced:Generator:ToBattery(kw)'].to_f + power['REopt:ElectricityProduced:PV:ToBattery(kw)'].to_f + power['REopt:ElectricityProduced:Wind:ToBattery(kw)'].to_f - power['REopt:Electricity:Storage:ToLoad(kw)'].to_f - power['REopt:Electricity:Storage:ToGrid(kw)'].to_f)
323
348
  profiles[:yearly_profile_storage_reactive].push(profiles[:yearly_profile_storage_active][k] * Math.tan(Math.acos(@power_factor)))
324
- single_values[:energy] += power['REopt:Electricity:Load:Total(kw)'].to_f # calculating the yearly energy consumed by each feature
325
- single_values[:energy_dg] += power['REopt:ElectricityProduced:Total(kw)'].to_f
349
+ single_values[:energy] += power["REopt:Electricity:Load:Total(kw)"].to_f # calculating the yearly energy consumed by each feature
350
+ single_values[:energy_dg] += power["REopt:ElectricityProduced:Total(kw)"].to_f
326
351
  single_values[:energy_storage] += power['REopt:Electricity:Grid:ToBattery(kw)'].to_f + power['REopt:ElectricityProduced:Generator:ToBattery(kw)'].to_f + power['REopt:ElectricityProduced:PV:ToBattery(kw)'].to_f + power['REopt:ElectricityProduced:Wind:ToBattery(kw)'].to_f - power['REopt:Electricity:Storage:ToLoad(kw)'].to_f - power['REopt:Electricity:Storage:ToGrid(kw)'].to_f
327
- if k >= profile_start_max && k <= profile_start_max + hours || k >= profile_start_min && k <= profile_start_min + hours
328
- profiles[:planning_profile_cust_active].push(power['REopt:Electricity:Load:Total(kw)'].to_f)
329
- if profiles[:planning_profile_cust_active][i] > single_values[:peak_active_power_cons]
330
- single_values[:peak_active_power_cons] = profiles[:planning_profile_cust_active][i]
331
- single_values[:peak_reactive_power_cons] = single_values[:peak_active_power_cons] * Math.tan(Math.acos(power_factor))
332
- single_values[:h_cons_max] = i
333
- end
334
- profiles[:planning_profile_storage_active].push((power['REopt:Electricity:Grid:ToBattery(kw)'].to_f + power['REopt:ElectricityProduced:Generator:ToBattery(kw)'].to_f + power['REopt:ElectricityProduced:PV:ToBattery(kw)'].to_f + power['REopt:ElectricityProduced:Wind:ToBattery(kw)'].to_f - power['REopt:Electricity:Storage:ToLoad(kw)'].to_f - power['REopt:Electricity:Storage:ToGrid(kw)'].to_f))
335
- if profiles[:planning_profile_storage_active][i] > single_values[:peak_active_power_storage]
336
- single_values[:peak_active_power_storage] = profiles[:planning_profile_storage_active][i]
337
- single_values[:peak_reactive_power_storage] = single_values[:peak_active_power_storage] * Math.tan(Math.acos(power_factor))
338
- single_values[:h_stor_max] = i
339
- end
340
- profiles[:planning_profile_dg_active].push(power['REopt:ElectricityProduced:Total(kw)'].to_f)
341
- if profiles[:planning_profile_dg_active][i] > single_values[:peak_active_power_dg]
342
- single_values[:peak_active_power_dg] = profiles[:planning_profile_dg_active][i]
343
- single_values[:peak_reactive_power_dg] = single_values[:peak_active_power_dg] * Math.tan(Math.acos(power_factor))
344
- single_values[:h_dg_max] = i
345
- end
346
- profiles[:planning_profile_cust_reactive].push(profiles[:planning_profile_cust_active][i] * Math.tan(Math.acos(power_factor)))
347
- profiles[:planning_profile_storage_reactive].push(profiles[:planning_profile_storage_active][i] * Math.tan(Math.acos(power_factor)))
348
- profiles[:planning_profile_dg_reactive].push(profiles[:planning_profile_dg_active][i] * Math.tan(Math.acos(power_factor)))
349
- i += 1
352
+ case k
353
+ when profile_start_min..profile_start_min + (hours)
354
+ profiles_planning, single_values = self.profiles_planning_creation(profiles_planning, power, single_values, i, hours, power_factor)
355
+ i+=1
356
+ when profile_start_max..profile_start_max + (hours)
357
+ profiles_planning, single_values = self.profiles_planning_creation(profiles_planning, power, single_values, j, hours, power_factor)
358
+ j+=1
350
359
  end
351
- k += 1
360
+ k+=1
352
361
  end
353
362
  height = (json_feature_report['program']['maximum_roof_height_ft']).round(2)
354
363
  users = json_feature_report['program']['number_of_residential_units']
355
- der_capacity = sum_dg(json_feature_report['distributed_generation'])
364
+ der_capacity = self.sum_dg(json_feature_report['distributed_generation'])
356
365
  if @only_lv_consumers
357
- nodes_per_bldg, area = av_peak_cons_per_building_type(json_feature_report['program']['building_types'])
358
- if @max_num_lv_nodes == 1
359
- construct_prosumer_general(profiles, single_values, building_map, area, height, users, der_capacity)
366
+ nodes_per_bldg, area = self.av_peak_cons_per_building_type(json_feature_report['program']['building_types'])
367
+ if @max_num_nodes == 1
368
+ self.construct_prosumer_general(profiles, profiles_planning, single_values, building_map, area, height, users, der_capacity)
360
369
  else
361
- construct_prosumer_lv(nodes_per_bldg, profiles, single_values, building_map, building_nodes, area, height, users, der_capacity)
370
+ self.construct_prosumer_lv(nodes_per_bldg, profiles, profiles_planning, single_values, building_map, building_nodes, area, height, users, der_capacity)
362
371
  end
363
372
  else
364
- # this key seems to change between floor_area or floor_area_ft
365
- area = json_feature_report['program'].key?('floor_area') ? (json_feature_report['program']['floor_area']).round(2) : (json_feature_report['program']['floor_area_sqft']).round(2)
373
+ area = json_feature_report['program'].has_key?('floor_area') ? (json_feature_report['program']['floor_area']).round(2) : (json_feature_report['program']['floor_area_sqft']).round(2)
366
374
  # associating 2 nodes (consumers & DG and battery in the same node) per building considering the consumer, the battery and DG
367
- construct_prosumer_general(profiles, single_values, building_map, area, height, users, der_capacity)
368
- end
375
+ self.construct_prosumer_general(profiles, profiles_planning, single_values, building_map, area, height, users, der_capacity)
376
+ end
369
377
  end
370
378
  end
371
379
  end
@@ -73,23 +73,23 @@ module URBANopt
73
73
  (0..@commercial_consumption.length - 1).each do |j|
74
74
  if @commercial_consumption[j] > max_net_load_comm
75
75
  max_net_load_comm = @commercial_consumption[j]
76
- @peak_hour_max_comm = (@time[j].split(' ')[1]).split(':')[0].to_i # defined the most-stressing scenario
76
+ @peak_hour_max_comm = (@time[j].split(' ')[1]) # defined the most-stressing scenario
77
77
  @hour_index_max_comm = j
78
78
  end
79
79
  if @commercial_consumption[j] < min_net_load_comm
80
80
  min_net_load_comm = @commercial_consumption[j]
81
- @peak_hour_min_comm = (@time[j].split(' ')[1]).split(':')[0].to_i # defined the most-stressing scenario
81
+ @peak_hour_min_comm = (@time[j].split(' ')[1]) # defined the most-stressing scenario
82
82
  @hour_index_min_comm = j
83
83
  end
84
84
 
85
85
  if @res_consumption[j] > max_net_load_res
86
86
  max_net_load_res = @res_consumption[j]
87
- @peak_hour_max_res = (@time[j].split(' ')[1]).split(':')[0].to_i # defined the most-stressing scenario
87
+ @peak_hour_max_res = (@time[j].split(' ')[1]) # defined the most-stressing scenario
88
88
  @hour_index_max_res = j
89
89
  end
90
90
  if @res_consumption[j] < min_net_load_res
91
91
  min_net_load_res = @res_consumption[j]
92
- @peak_hour_min_res = (@time[j].split(' ')[1]).split(':')[0].to_i # defined the most-stressing scenario
92
+ @peak_hour_min_res = (@time[j].split(' ')[1]) # defined the most-stressing scenario
93
93
  @hour_index_min_res = j
94
94
  end
95
95
  end
@@ -98,12 +98,12 @@ module URBANopt
98
98
  (0..@commercial_consumption.length - 1).each do |j|
99
99
  if @commercial_consumption[j] > max_net_load_comm
100
100
  max_net_load_comm = @commercial_consumption[j]
101
- @peak_hour_max_comm = (@time[j].split(' ')[1]).split(':')[0].to_i # defined the most-stressing scenario
101
+ @peak_hour_max_comm = (@time[j].split(' ')[1]) # defined the most-stressing scenario
102
102
  @hour_index_max_comm = j
103
103
  end
104
104
  if @res_consumption[j] > max_net_load_res
105
105
  max_net_load_res = @res_consumption[j]
106
- @peak_hour_max_res = (@time[j].split(' ')[1]).split(':')[0].to_i # defined the most-stressing scenario
106
+ @peak_hour_max_res = (@time[j].split(' ')[1]) # defined the most-stressing scenario
107
107
  @hour_index_max_res = j
108
108
  end
109
109
  end
@@ -40,6 +40,6 @@
40
40
 
41
41
  module URBANopt
42
42
  module RNM
43
- VERSION = '0.1.0'.freeze
43
+ VERSION = '0.1.1'.freeze
44
44
  end
45
45
  end
@@ -26,7 +26,7 @@ Gem::Specification.new do |spec|
26
26
  spec.add_dependency 'faraday', '1.0.1'
27
27
  spec.add_dependency 'geoutm', '~>1.0.2'
28
28
  spec.add_dependency 'rubyzip', '2.3.0'
29
- spec.add_dependency 'urbanopt-geojson', '~> 0.6.5'
29
+ spec.add_dependency 'urbanopt-geojson', '~> 0.6.6'
30
30
 
31
31
  spec.add_development_dependency 'bundler', '~> 2.1'
32
32
  spec.add_development_dependency 'rake', '~> 13.0'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: urbanopt-rnm-us
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Katherine Fleming
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2021-07-22 00:00:00.000000000 Z
12
+ date: 2021-10-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: faraday
@@ -59,14 +59,14 @@ dependencies:
59
59
  requirements:
60
60
  - - "~>"
61
61
  - !ruby/object:Gem::Version
62
- version: 0.6.5
62
+ version: 0.6.6
63
63
  type: :runtime
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
67
  - - "~>"
68
68
  - !ruby/object:Gem::Version
69
- version: 0.6.5
69
+ version: 0.6.6
70
70
  - !ruby/object:Gem::Dependency
71
71
  name: bundler
72
72
  requirement: !ruby/object:Gem::Requirement