Class: URBANopt::RNM::Prosumers
- Inherits:
-
Object
- Object
- URBANopt::RNM::Prosumers
- Defined in:
- lib/urbanopt/rnm/prosumers.rb
Overview
creating a class that creates the consumers input required by the RNM-US model, according to their geographic location, energy consumption and peak demand, and power consumption profiles
Instance Attribute Summary collapse
-
#customers ⇒ Object
Returns the value of attribute customers.
-
#customers_ext ⇒ Object
Returns the value of attribute customers_ext.
-
#dg ⇒ Object
Returns the value of attribute dg.
-
#dg_profile_p ⇒ Object
Returns the value of attribute dg_profile_p.
-
#dg_profile_q ⇒ Object
Returns the value of attribute dg_profile_q.
-
#power_factor ⇒ Object
Returns the value of attribute power_factor.
-
#profile_customer_p ⇒ Object
Returns the value of attribute profile_customer_p.
-
#profile_customer_p_ext ⇒ Object
Returns the value of attribute profile_customer_p_ext.
-
#profile_customer_q ⇒ Object
Returns the value of attribute profile_customer_q.
-
#profile_customer_q_ext ⇒ Object
Returns the value of attribute profile_customer_q_ext.
-
#profile_date_time ⇒ Object
Returns the value of attribute profile_date_time.
-
#profile_date_time_ext ⇒ Object
Returns the value of attribute profile_date_time_ext.
-
#profile_dg_p_extended ⇒ Object
Returns the value of attribute profile_dg_p_extended.
-
#profile_dg_q_extended ⇒ Object
Returns the value of attribute profile_dg_q_extended.
Instance Method Summary collapse
-
#av_peak_cons_per_building_type(feature_file) ⇒ Object
creating a method to define the number of nodes for each building in case the user set the option “only LV” to true.
-
#construct_prosumer_general(profiles, profiles_planning, single_values, building_map, area, height, users, der_capacity) ⇒ Object
method defined for the case of a single node where both battery, DG and consumers are placed evaluation of the peak power in each node to define the type of connection (e.g. voltage level and n phases).
-
#construct_prosumer_lv(nodes_per_bldg = 0, profiles, profiles_planning, single_values, building_map, building_nodes, area, height, users, der_capacity) ⇒ Object
this method is called only if the user sets the option of “only LV nodes” to true defining a certain numb of nodes for each building and distributing the peak power values equally among the nodes of each building.
-
#initialize(reopt, only_lv_consumers = false, max_num_lv_nodes, average_building_peak_catalog_path, lv_limit) ⇒ Prosumers
constructor
initializing all the attributes to build the inputs files required by the RNM-US model.
-
#profiles_planning_creation(profiles_planning, power, single_values, i, hours, power_factor) ⇒ Object
method to order profiles consistently.
-
#prosumer_files_load(csv_feature_report, json_feature_report, building_map, building_nodes, hour) ⇒ Object
defining a method for the customers and generators files creation: obtaining all the needed input from each feature_report.csv file (active & apparent power and tot energy consumed and produced) and from each feature_report.json file (area, height, number of users, DG capacity) the method passes as arguments the urbanopt json and csv output file for each feature and the building coordinates previously calculated and the “extreme” hours used to plan the network.
-
#sum_dg(dg) ⇒ Object
defining a method to calculate the total sum of DG and battery capacity for each building in the district.
-
#voltage_values(peak_apparent_power) ⇒ Object
creating a function that for each node defines the connection (e.g LV, MV, single-phase, 3-phase) according to the catalog limits previously calculated.
Constructor Details
#initialize(reopt, only_lv_consumers = false, max_num_lv_nodes, average_building_peak_catalog_path, lv_limit) ⇒ Prosumers
initializing all the attributes to build the inputs files required by the RNM-US model
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/urbanopt/rnm/prosumers.rb', line 16 def initialize(reopt, only_lv_consumers = false, max_num_lv_nodes, average_building_peak_catalog_path, lv_limit) @reopt = reopt @average_building_peak_catalog_path = average_building_peak_catalog_path @only_lv_consumers = only_lv_consumers @max_num_lv_nodes = max_num_lv_nodes @customers = [] @customers_ext = [] @profile_date_time = [] @profile_customer_p = [] @profile_customer_q = [] @profile_date_time_ext = [] @profile_customer_p_ext = [] @profile_customer_q_ext = [] @dg = [] @dg_profile_p = [] @dg_profile_q = [] @profile_dg_p_extended = [] @profile_dg_q_extended = [] @power_factor = power_factor @lv_limit = lv_limit end |
Instance Attribute Details
#customers ⇒ Object
Returns the value of attribute customers.
13 14 15 |
# File 'lib/urbanopt/rnm/prosumers.rb', line 13 def customers @customers end |
#customers_ext ⇒ Object
Returns the value of attribute customers_ext.
13 14 15 |
# File 'lib/urbanopt/rnm/prosumers.rb', line 13 def customers_ext @customers_ext end |
#dg ⇒ Object
Returns the value of attribute dg.
13 14 15 |
# File 'lib/urbanopt/rnm/prosumers.rb', line 13 def dg @dg end |
#dg_profile_p ⇒ Object
Returns the value of attribute dg_profile_p.
13 14 15 |
# File 'lib/urbanopt/rnm/prosumers.rb', line 13 def dg_profile_p @dg_profile_p end |
#dg_profile_q ⇒ Object
Returns the value of attribute dg_profile_q.
13 14 15 |
# File 'lib/urbanopt/rnm/prosumers.rb', line 13 def dg_profile_q @dg_profile_q end |
#power_factor ⇒ Object
Returns the value of attribute power_factor.
13 14 15 |
# File 'lib/urbanopt/rnm/prosumers.rb', line 13 def power_factor @power_factor end |
#profile_customer_p ⇒ Object
Returns the value of attribute profile_customer_p.
13 14 15 |
# File 'lib/urbanopt/rnm/prosumers.rb', line 13 def profile_customer_p @profile_customer_p end |
#profile_customer_p_ext ⇒ Object
Returns the value of attribute profile_customer_p_ext.
13 14 15 |
# File 'lib/urbanopt/rnm/prosumers.rb', line 13 def profile_customer_p_ext @profile_customer_p_ext end |
#profile_customer_q ⇒ Object
Returns the value of attribute profile_customer_q.
13 14 15 |
# File 'lib/urbanopt/rnm/prosumers.rb', line 13 def profile_customer_q @profile_customer_q end |
#profile_customer_q_ext ⇒ Object
Returns the value of attribute profile_customer_q_ext.
13 14 15 |
# File 'lib/urbanopt/rnm/prosumers.rb', line 13 def profile_customer_q_ext @profile_customer_q_ext end |
#profile_date_time ⇒ Object
Returns the value of attribute profile_date_time.
13 14 15 |
# File 'lib/urbanopt/rnm/prosumers.rb', line 13 def profile_date_time @profile_date_time end |
#profile_date_time_ext ⇒ Object
Returns the value of attribute profile_date_time_ext.
13 14 15 |
# File 'lib/urbanopt/rnm/prosumers.rb', line 13 def profile_date_time_ext @profile_date_time_ext end |
#profile_dg_p_extended ⇒ Object
Returns the value of attribute profile_dg_p_extended.
13 14 15 |
# File 'lib/urbanopt/rnm/prosumers.rb', line 13 def profile_dg_p_extended @profile_dg_p_extended end |
#profile_dg_q_extended ⇒ Object
Returns the value of attribute profile_dg_q_extended.
13 14 15 |
# File 'lib/urbanopt/rnm/prosumers.rb', line 13 def profile_dg_q_extended @profile_dg_q_extended end |
Instance Method Details
#av_peak_cons_per_building_type(feature_file) ⇒ Object
creating a method to define the number of nodes for each building in case the user set the option “only LV” to true. this method calculates the number of nodes for each building in the project and in case the numb of nodes is higher than 4 than the building is considered as a single node connected in MV the numb of nodes is calculated based on the average_peak_catalog which is obtained from DOE open_source data per location and per building type
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
# File 'lib/urbanopt/rnm/prosumers.rb', line 219 def av_peak_cons_per_building_type(feature_file) average_peak_by_size = [] floor_area = [] average_peak = 5 # defining a random value first, since now the residential buildings are not considered in the catalog mixed_use_av_peak = 0 area_mixed_use = 0 # defining a conservative factor which creates some margin with the number of nodes found using the av_peak catalog, with the # actual nodes that could be found with the current buildings peak consumptions in the project conservative_factor = 0.8 # considered as a reasonable assumption, but this value could be changed average_peak_folder = JSON.parse(File.read(@average_building_peak_catalog_path)) for i in 0..feature_file.length - 1 area = feature_file[i].key?('floor_area') ? (feature_file[i]['floor_area']).round(2) : (feature_file[i]['floor_area_sqft']).round(2) building_type = feature_file[i]['building_type'] # it specifies the type of building, sometimes it is directly the sub-type counter = 0 # counter to find number of buildings type belonging to same "category" average_peak_folder.each do |building_class| if building_type == building_class['building type'] || building_type == building_class['sub-type'] 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 average_peak_by_size[counter] = average_peak floor_area[counter] = (building_class['floor_area (ft2)'] - area).abs # minimum difference among area and area from the prototypes defined by DOE counter += 1 # 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 end end if counter > 1 index = floor_area.index(floor_area.min) average_peak = average_peak_by_size[index] end if feature_file.length > 1 # defined for Mixed_use buildings, which include more building types mixed_use_av_peak += average_peak area_mixed_use += area end end if feature_file.length > 1 average_peak = mixed_use_av_peak # average peak per mixed use considering the building types which are in this building area = area_mixed_use end nodes_per_bldg = (average_peak / (@lv_limit[:three_phase] * @power_factor * conservative_factor)).to_f.ceil # computing number of nodes per building if nodes_per_bldg > @max_num_lv_nodes # that it is equal to how it was before nodes_per_bldg = 1 @medium_voltage = true end nodes_per_bldg += 1 # tacking into account the extra node for distributed generation and the battery return nodes_per_bldg, area end |
#construct_prosumer_general(profiles, profiles_planning, single_values, building_map, area, height, users, der_capacity) ⇒ Object
method defined for the case of a single node where both battery, DG and consumers are placed evaluation of the peak power in each node to define the type of connection (e.g. voltage level and n phases)
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/urbanopt/rnm/prosumers.rb', line 44 def construct_prosumer_general(profiles, profiles_planning, single_values, building_map, area, height, users, der_capacity) id = building_map[3] id_dg = "#{building_map[3]}_DG" id_batt = "#{building_map[3]}_battery" building_map.pop # deleting the last_element of the list which represents the id peak_app_power_node = 0 # defining the max peak in the hour with consumption max peak # in the hour with generation max peak # in the hour with storage max peak for i in 0..profiles_planning[:planning_profile_cust_active].length - 1 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 if hourly_app_power > peak_app_power_node peak_app_power_node = hourly_app_power end end # creating the customer text files (treating also the battery as a consumer) & the DG text file if @medium_voltage voltage_default = 12.47 phases = 3 else voltage_default, phases = voltage_values(peak_app_power_node / 0.9) # margin to consider 0.9 for safety reasons end @customers.push([building_map, id, voltage_default, single_values[:peak_active_power_cons], single_values[:peak_reactive_power_cons], phases]) @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]) @profile_date_time.push([profiles_planning[:planning_date_time]]) @profile_customer_q.push([id, 48, profiles_planning[:planning_profile_cust_reactive]]) @profile_customer_p.push([id, 48, profiles_planning[:planning_profile_cust_active]]) @profile_date_time_ext.push([profiles[:yearly_date_time]]) @profile_customer_p_ext.push([id, 8760, profiles[:yearly_profile_cust_active]]) @profile_customer_q_ext.push([id, 8760, profiles[:yearly_profile_cust_reactive]]) if !der_capacity[:storage].nil? && der_capacity[:storage] > 0 @customers.push([building_map, id_batt, voltage_default, single_values[:peak_active_power_storage], single_values[:peak_reactive_power_storage], phases]) @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]) @profile_date_time.push([profiles_planning[:planning_date_time]]) @profile_customer_q.push([id_batt, 48, profiles_planning[:planning_profile_storage_reactive]]) @profile_customer_p.push([id_batt, 48, profiles_planning[:planning_profile_storage_active]]) @profile_date_time_ext.push([profiles[:yearly_date_time]]) @profile_customer_p_ext.push([id_batt, 8760, profiles[:yearly_profile_storage_active]]) @profile_customer_q_ext.push([id_batt, 8760, profiles[:yearly_profile_storage_reactive]]) end @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]) @dg_profile_p.push([id_dg, 48, profiles_planning[:planning_profile_dg_active]]) @dg_profile_q.push([id_dg, 48, profiles_planning[:planning_profile_dg_reactive]]) @profile_dg_p_extended.push([id_dg, 8760, profiles[:yearly_profile_dg_active]]) @profile_dg_q_extended.push([id_dg, 8760, profiles[:yearly_profile_dg_reactive]]) end |
#construct_prosumer_lv(nodes_per_bldg = 0, profiles, profiles_planning, single_values, building_map, building_nodes, area, height, users, der_capacity) ⇒ Object
this method is called only if the user sets the option of “only LV nodes” to true defining a certain numb of nodes for each building and distributing the peak power values equally among the nodes of each building
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/urbanopt/rnm/prosumers.rb', line 101 def construct_prosumer_lv(nodes_per_bldg = 0, profiles, profiles_planning, single_values, building_map, building_nodes, area, height, users, der_capacity) # the default variables are defined (i.e. type and rurality type) planning_date_time = [] planning_profile_node_active = [] planning_profile_node_reactive = [] yearly_date_time = [] yearly_profile_node_active = [] yearly_profile_node_reactive = [] closest_node = building_map[3].split('_')[1].to_i # refers to the closest node of the building in consideration to the street node = closest_node cont = 1 cont_reverse = 1 nodes_consumers = nodes_per_bldg - 1 for i in 1..nodes_per_bldg coordinates = building_map node = closest_node + cont # to set the new nodes with enough distance among each others node_reverse = closest_node - cont_reverse if i > 1 && node <= building_nodes.length - 2 coordinates = building_nodes[node] # take the closest building node index to the street and pass the nodes after it cont += 1 elsif i > 1 coordinates = building_nodes[node_reverse] cont_reverse += 1 end # this condition is used to firstly place the building consumption nodes and then the last node # to be placed is the one referred to DG and battery for the building if i < nodes_per_bldg # considering the consumers nodes id = coordinates[3] coordinates.pop peak_active_power_cons = (single_values[:peak_active_power_cons] / nodes_consumers).round(2) peak_reactive_power_cons = (single_values[:peak_reactive_power_cons] / nodes_consumers).round(2) voltage_default, phases = voltage_values(peak_active_power_cons / @power_factor) for k in 0..profiles_planning[:planning_profile_cust_active].length - 1 planning_date_time[k]=profiles_planning[:planning_date_time][k] planning_profile_node_active[k] = (profiles_planning[:planning_profile_cust_active][k] / nodes_consumers).round(2) planning_profile_node_reactive[k] = (profiles_planning[:planning_profile_cust_reactive][k] / nodes_consumers).round(2) end for k in 0..profiles[:yearly_profile_cust_active].length - 1 yearly_date_time[k]=profiles[:yearly_date_time][k] yearly_profile_node_active[k] = (profiles[:yearly_profile_cust_active][k] / nodes_consumers).round(2) yearly_profile_node_reactive[k] = (profiles[:yearly_profile_cust_reactive][k] / nodes_consumers).round(2) end @customers.push([coordinates, id, voltage_default, peak_active_power_cons, peak_reactive_power_cons, phases]) @customers_ext.push([coordinates, id, voltage_default, peak_active_power_cons, peak_reactive_power_cons, phases, area, height, (single_values[:energy] / nodes_consumers).round(2), peak_active_power_cons, peak_reactive_power_cons, users]) @profile_date_time.push([planning_date_time]) @profile_customer_q.push([id, 48, planning_profile_node_reactive]) @profile_customer_p.push([id, 48, planning_profile_node_active]) @profile_date_time_ext.push([yearly_date_time]) @profile_customer_p_ext.push([id, 8760, yearly_profile_node_active]) @profile_customer_q_ext.push([id, 8760, yearly_profile_node_reactive]) else # considering the DG and battery voltage_default, phases = voltage_values(der_capacity[:dg]) # assuming that the pv capacity is always higher than battery capacity id_dg = "#{coordinates[3]}_DG" id_batt = "#{coordinates[3]}_battery" coordinates.pop @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]) @dg_profile_p.push([id_dg, 48, profiles_planning[:planning_profile_dg_active]]) @dg_profile_q.push([id_dg, 48, profiles_planning[:planning_profile_dg_reactive]]) @profile_dg_p_extended.push([id_dg, 8760, profiles[:yearly_profile_dg_active]]) @profile_dg_q_extended.push([id_dg, 8760, profiles[:yearly_profile_dg_reactive]]) if !der_capacity[:storage].nil? && der_capacity[:storage] > 0 @customers.push([coordinates, id_batt, voltage_default, single_values[:peak_active_power_storage], single_values[:peak_reactive_power_storage], phases]) @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]) @profile_date_time.push([profiles[:planning_date_time]]) @profile_customer_q.push([id_batt, 48, profiles_planning[:planning_profile_storage_reactive]]) @profile_customer_p.push([id_batt, 48, profiles_planning[:planning_profile_storage_active]]) @profile_date_time_ext.push([profiles[:yearly_date_time]]) @profile_customer_p_ext.push([id_batt, 8760, profiles[:yearly_profile_storage_active]]) @profile_customer_q_ext.push([id_batt, 8760, profiles[:yearly_profile_storage_reactive]]) end end end end |
#profiles_planning_creation(profiles_planning, power, single_values, i, hours, power_factor) ⇒ Object
method to order profiles consistently
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
# File 'lib/urbanopt/rnm/prosumers.rb', line 266 def profiles_planning_creation(profiles_planning, power, single_values, i, hours, power_factor) profiles_planning[:planning_date_time][i]=power['Datetime'] profiles_planning[:planning_profile_cust_active][i] = power['REopt:Electricity:Load:Total(kw)'].to_f 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 profiles_planning[:planning_profile_dg_active][i] = power['REopt:ElectricityProduced:Total(kw)'].to_f profiles_planning[:planning_profile_cust_reactive][i] = profiles_planning[:planning_profile_cust_active][i] * Math.tan(Math.acos(power_factor)) profiles_planning[:planning_profile_storage_reactive][i] = profiles_planning[:planning_profile_storage_active][i] * Math.tan(Math.acos(power_factor)) profiles_planning[:planning_profile_dg_reactive][i] = profiles_planning[:planning_profile_dg_active][i] * Math.tan(Math.acos(power_factor)) if profiles_planning[:planning_profile_cust_active][i] > single_values[:peak_active_power_cons] single_values[:peak_active_power_cons] = profiles_planning[:planning_profile_cust_active][i] single_values[:peak_reactive_power_cons] = single_values[:peak_active_power_cons] * Math.tan(Math.acos(power_factor)) end if profiles_planning[:planning_profile_storage_active][i] > single_values[:peak_active_power_storage] single_values[:peak_active_power_storage] = profiles_planning[:planning_profile_storage_active][i] single_values[:peak_reactive_power_storage] = single_values[:peak_active_power_storage] * Math.tan(Math.acos(power_factor)) end if profiles_planning[:planning_profile_dg_active][i] > single_values[:peak_active_power_dg] single_values[:peak_active_power_dg] = profiles_planning[:planning_profile_dg_active][i] single_values[:peak_reactive_power_dg] = single_values[:peak_active_power_dg] * Math.tan(Math.acos(power_factor)) end return profiles_planning, single_values end |
#prosumer_files_load(csv_feature_report, json_feature_report, building_map, building_nodes, hour) ⇒ Object
defining a method for the customers and generators files creation: obtaining all the needed input from each feature_report.csv file (active & apparent power and tot energy consumed and produced) and from each feature_report.json file (area, height, number of users, DG capacity) the method passes as arguments the urbanopt json and csv output file for each feature and the building coordinates previously calculated and the “extreme” hours used to plan the network
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 |
# File 'lib/urbanopt/rnm/prosumers.rb', line 294 def prosumer_files_load(csv_feature_report, json_feature_report, building_map, building_nodes, hour) # add variable to include how many timestep per hour, so the profiles become 48 * n_timestep_per_hour n_timestep_per_hour = json_feature_report['timesteps_per_hour'].to_i 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 profiles = Hash.new { |h, k| h[k] = [] } single_values = Hash.new(0) @medium_voltage = false hours = 24 * n_timestep_per_hour - 1 # change name, maybe to intervals feature_type = json_feature_report['program']['building_types'][0]['building_type'] residential_building_types = ['Single-Family Detached', 'Single-Family Attached', 'Multifamily', 'Single-Family', 'Multifamily Detached (2 to 4 units)', 'Multifamily Detached (5 or more units)'] # 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 # considering num timestep per hours and the fact that each day starts from 1 am if residential_building_types.include? feature_type 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) 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) else 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) 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) end # 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 k = 0 # index for each hour of the year represented in the csv file i = hours + 1 # to represent the 24 hours in case of max_net_generation day j = 0 # to represent the 24 hours in case of peak_demand_day h_cons_batt = 0 h_dg_max = 0 # hour with max DG generation h_stor_max = 0 # hour with max storage absorption max_peak = 0 CSV.foreach(csv_feature_report, headers: true) do |power| @power_factor = power['Electricity:Facility Power(kW)'].to_f / power['Electricity:Facility Apparent Power(kVA)'].to_f profiles[:yearly_date_time].push(power['Datetime']) profiles[:yearly_profile_cust_active].push(power['REopt:Electricity:Load:Total(kw)'].to_f) profiles[:yearly_profile_cust_reactive].push(profiles[:yearly_profile_cust_active][k] * Math.tan(Math.acos(@power_factor))) profiles[:yearly_profile_dg_active].push(power['REopt:ElectricityProduced:Total(kw)'].to_f) profiles[:yearly_profile_dg_reactive].push(profiles[:yearly_profile_dg_active][k] * Math.tan(Math.acos(@power_factor))) 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) profiles[:yearly_profile_storage_reactive].push(profiles[:yearly_profile_storage_active][k] * Math.tan(Math.acos(@power_factor))) single_values[:energy] += power['REopt:Electricity:Load:Total(kw)'].to_f # calculating the yearly energy consumed by each feature single_values[:energy_dg] += power['REopt:ElectricityProduced:Total(kw)'].to_f 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 case k when profile_start_min..profile_start_min + hours profiles_planning, single_values = profiles_planning_creation(profiles_planning, power, single_values, i, hours, power_factor) i += 1 when profile_start_max..profile_start_max + hours profiles_planning, single_values = profiles_planning_creation(profiles_planning, power, single_values, j, hours, power_factor) j += 1 end k += 1 end height = (json_feature_report['program']['maximum_roof_height_ft']).round(2) users = json_feature_report['program']['number_of_residential_units'] der_capacity = sum_dg(json_feature_report['distributed_generation']) if @only_lv_consumers nodes_per_bldg, area = av_peak_cons_per_building_type(json_feature_report['program']['building_types']) if @max_num_nodes == 1 construct_prosumer_general(profiles, profiles_planning, single_values, building_map, area, height, users, der_capacity) else construct_prosumer_lv(nodes_per_bldg, profiles, profiles_planning, single_values, building_map, building_nodes, area, height, users, der_capacity) end else 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) # associating 2 nodes (consumers & DG and battery in the same node) per building considering the consumer, the battery and DG construct_prosumer_general(profiles, profiles_planning, single_values, building_map, area, height, users, der_capacity) end end |
#sum_dg(dg) ⇒ Object
defining a method to calculate the total sum of DG and battery capacity for each building in the district
200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
# File 'lib/urbanopt/rnm/prosumers.rb', line 200 def sum_dg(dg) capacity = Hash.new(0) for i in 0..dg['solar_pv'].length - 1 capacity[:dg] += dg['solar_pv'][i]['size_kw'].to_f.round(2) end for i in 0..dg['wind'].length - 1 capacity[:dg] += dg['wind'][i]['size_kw'].to_f.round(2) end for i in 0..dg['generator'].length - 1 capacity[:dg] += dg['generator'][i]['size_kw'].to_f.round(2) end capacity[:storage] = dg['total_storage_kw'] return capacity end |
#voltage_values(peak_apparent_power) ⇒ Object
creating a function that for each node defines the connection (e.g LV, MV, single-phase, 3-phase) according to the catalog limits previously calculated
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/urbanopt/rnm/prosumers.rb', line 179 def voltage_values(peak_apparent_power) case peak_apparent_power when -10000..@lv_limit[:single_phase] # set by the catalog limits phases = 1 voltage_default = 0.12 when @lv_limit[:single_phase]..@lv_limit[:three_phase] # defined from the catalog (from the wires) phases = 3 voltage_default = 0.48 # MV and 3 phases untill 16 MVA defined by SMART-DS project when @lv_limit[:three_phase]..16000 phases = 3 voltage_default = 12.47 else # HV and 3 phases for over 16 MVA phases = 3 voltage_default = 69 end return voltage_default, phases end |