Class: URBANopt::RNM::Consumers
- Inherits:
-
Object
- Object
- URBANopt::RNM::Consumers
- Defined in:
- lib/urbanopt/rnm/consumers.rb
Instance Attribute Summary collapse
-
#customers ⇒ Object
Returns the value of attribute customers.
-
#customers_ext ⇒ Object
Returns the value of attribute customers_ext.
-
#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.
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_consumer(profiles, single_values, building_map, building_nodes, height, users, folder) ⇒ Object
the method is divided in 2 part, the first is run in case the user uses the “only LV” option to run the network, defining a certain numb of nodes for each building while the 2nd option is run in case “only LV” set to false and the consumption for each building will be placed in a single node.
-
#customer_files_load(csv_feature_report, json_feature_report, building_map, building_nodes, hour) ⇒ Object
defining a method for the customers files creation: obtaining all the needed input from each feature_report.csv file (active & apparent power and tot energy consumed) and from each feature_report.json file (area, height, number of users) the method passes as arguments the urbanopt json and csv output file for each feature and the building coordinates previously calculated and the “extreme” hour used to plan the network.
-
#initialize(reopt, only_lv_consumers = false, max_num_lv_nodes, average_building_peak_catalog_path, lv_limit) ⇒ Consumers
constructor
initializing all the attributes to build the inputs files required by the RNM-US model.
-
#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) ⇒ Consumers
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 |
# File 'lib/urbanopt/rnm/consumers.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 = [] @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/consumers.rb', line 13 def customers @customers end |
#customers_ext ⇒ Object
Returns the value of attribute customers_ext.
13 14 15 |
# File 'lib/urbanopt/rnm/consumers.rb', line 13 def customers_ext @customers_ext end |
#power_factor ⇒ Object
Returns the value of attribute power_factor.
13 14 15 |
# File 'lib/urbanopt/rnm/consumers.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/consumers.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/consumers.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/consumers.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/consumers.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/consumers.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/consumers.rb', line 13 def profile_date_time_ext @profile_date_time_ext 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
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 176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/urbanopt/rnm/consumers.rb', line 142 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 medium_voltage = false # 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 reasonable 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 # to define this as an input in the geojson file nodes_per_bldg = 1 medium_voltage = true end return nodes_per_bldg, area, medium_voltage end |
#construct_consumer(profiles, single_values, building_map, building_nodes, height, users, folder) ⇒ Object
the method is divided in 2 part, the first is run in case the user uses the “only LV” option to run the network, defining a certain numb of nodes for each building while the 2nd option is run in case “only LV” set to false and the consumption for each building will be placed in a single node
41 42 43 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 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/urbanopt/rnm/consumers.rb', line 41 def construct_consumer(profiles, single_values, building_map, building_nodes, height, users, folder) if @only_lv_consumers planning_date_time = [] planning_profile_node_active = [] planning_profile_node_reactive = [] yearly_date_time = [] yearly_profile_node_active = [] yearly_profile_node_reactive = [] nodes_per_bldg, area, medium_voltage = av_peak_cons_per_building_type(folder['building_types']) # the default variables are defined (i.e. type and rurality type) puts 'consumers 82' closest_node = building_map[3].split('_')[1].to_i # refers to the node, found in the class above node = closest_node cont = 1 cont_reverse = 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 - 1 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 # creating the lists for the customers text files required by the model id = coordinates[3] peak_active_power_cons = ((single_values[:peak_active_power_cons]) / nodes_per_bldg).round(2) peak_reactive_power_cons = ((single_values[:peak_reactive_power_cons]) / nodes_per_bldg).round(2) # introducing this for consistency if medium_voltage voltage_default = 12.47 phases = 3 else voltage_default, phases = voltage_values(peak_active_power_cons / @power_factor) end for k in 0..profiles[:planning_profile_cust_active].length - 1 planning_date_time[k]=profiles[:planning_date_time][k] planning_profile_node_active[k] = ((profiles[:planning_profile_cust_active][k]) / nodes_per_bldg).round(2) planning_profile_node_reactive[k] = ((profiles[:planning_profile_cust_reactive][k]) / nodes_per_bldg).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_per_bldg).round(2) yearly_profile_node_reactive[k] = ((profiles[:yearly_profile_cust_reactive][k]) / nodes_per_bldg).round(2) end @customers.push([coordinates, voltage_default, peak_active_power_cons, peak_reactive_power_cons, phases]) @customers_ext.push([coordinates, voltage_default, peak_active_power_cons, peak_reactive_power_cons, phases, area, height, (single_values[:energy] / nodes_per_bldg).round(2), peak_active_power_cons, peak_reactive_power_cons, users]) @profile_date_time.push([planning_date_time]) @profile_customer_q.push([id, 24, planning_profile_node_reactive]) @profile_customer_p.push([id, 24, 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]) end # 2nd option run in case the building consumption is represented by a single node else id = building_map[3] # this key seems to change between floor_area or floor_area_ft area = folder.key?('floor_area') ? (folder['floor_area']).round(2) : (folder['floor_area_sqft']).round(2) voltage_default, phases = voltage_values(single_values[:peak_active_power_cons] / @power_factor * 0.9) # applying safety factor @customers.push([building_map, voltage_default, single_values[:peak_active_power_cons], single_values[:peak_reactive_power_cons], phases]) @customers_ext.push([building_map, 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_date_time]]) @profile_customer_q.push([id, 24, profiles[:planning_profile_cust_reactive]]) @profile_customer_p.push([id, 24, profiles[: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]]) end end |
#customer_files_load(csv_feature_report, json_feature_report, building_map, building_nodes, hour) ⇒ Object
defining a method for the customers files creation: obtaining all the needed input from each feature_report.csv file (active & apparent power and tot energy consumed) and from each feature_report.json file (area, height, number of users) the method passes as arguments the urbanopt json and csv output file for each feature and the building coordinates previously calculated and the “extreme” hour used to plan the network
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
# File 'lib/urbanopt/rnm/consumers.rb', line 193 def customer_files_load(csv_feature_report, json_feature_report, building_map, building_nodes, hour) n_timestep_per_hour = json_feature_report['timesteps_per_hour'].to_i profiles = Hash.new { |h, k| h[k] = [] } single_values = Hash.new(0) hours = 24 * n_timestep_per_hour - 1 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 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) 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) end k = 0 # index for each hour of the year represented in the csv file i = 0 # to represent the 24 hours of a day # content = CSV.foreach(csv_feature_report, headers: true) do |power| 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['Electricity:Facility Power(kW)'].to_f) profiles[:yearly_profile_cust_reactive].push(profiles[:yearly_profile_cust_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 if k >= profile_start_max && k <= profile_start_max + hours profiles[:planning_date_time].push(power['Datetime']) profiles[:planning_profile_cust_active].push(power['Electricity:Facility Power(kW)'].to_f) if power['Electricity:Facility Power(kW)'].to_f > single_values[:peak_active_power_cons] single_values[:peak_active_power_cons] = power['Electricity:Facility Power(kW)'].to_f single_values[:peak_reactive_power_cons] = single_values[:peak_active_power_cons] * Math.tan(Math.acos(@power_factor)) end profiles[:planning_profile_cust_reactive][i] = profiles[:planning_profile_cust_active][i] * Math.tan(Math.acos(@power_factor)) i += 1 end k += 1 end # parsing the required information from feature.json file # folder = JSON.parse(json_feature_report) height = (json_feature_report['program']['maximum_roof_height_ft']).round(2) # here depends on the feature version users = json_feature_report['program']['number_of_residential_units'] construct_consumer(profiles, single_values, building_map, building_nodes, height, users, json_feature_report['program']) 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
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/urbanopt/rnm/consumers.rb', line 118 def voltage_values(peak_apparent_power) case peak_apparent_power when 0..@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 the 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 |