class SizingDash: def __init__(self, output_dir, test_number=None): # Load css css_folder = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets/") self.app = dash.Dash(__name__, assets_url_path=css_folder) # Load net # If no test_number is specified, take the last run self.current_test_number = test_number if self.current_test_number is None: self.current_test_number = sorted(os.listdir(output_dir))[-1] self.output_dir = output_dir self.net = Network() self.net.import_from_csv_folder(f"{self.output_dir}{self.current_test_number}/") if len(self.net.lines) != 0: self.current_line_id = self.net.lines.index[0] if len(self.net.links) != 0: self.current_link_id = self.net.links.index[0] self.current_bus_id = self.net.buses.index[0] self.selected_types = sorted(list(set(self.net.generators.type.values))) def built_app(self): def get_map(): map_coords = [min(self.net.buses["x"].values) - 5, max(self.net.buses["x"].values) + 5, min(self.net.buses["y"].values) - 2, max(self.net.buses["y"].values) + 2] fig = go.Figure(layout=go.Layout( showlegend=False, geo=dict( showcountries=True, scope='world', lonaxis=dict( showgrid=True, gridwidth=1, range=[map_coords[0], map_coords[1]], dtick=5 ), lataxis=dict( showgrid=True, gridwidth=1, range=[map_coords[2], map_coords[3]], dtick=5 ) ) )) # Adding lines to map if len(self.net.lines) != 0: # Get minimum s_nom_opt s_nom_opt_min = min(self.net.lines.s_nom_opt[self.net.lines.s_nom_opt > 0].values) for i, idx in enumerate(self.net.lines.index): bus0_id = self.net.lines.loc[idx, ("bus0",)] bus1_id = self.net.lines.loc[idx, ("bus1",)] bus0_x = self.net.buses.loc[bus0_id, ("x",)] bus0_y = self.net.buses.loc[bus0_id, ("y",)] bus1_x = self.net.buses.loc[bus1_id, ("x",)] bus1_y = self.net.buses.loc[bus1_id, ("y",)] color = 'rgba(0,0,255,0.8)' name = 'AC' s_nom_mul = self.net.lines.loc[idx, ('s_nom_opt',)] / s_nom_opt_min if self.net.lines.loc[idx, ("carrier",)] == "DC": color = 'rgba(255,0,0,0.8)' name = 'DC' fig.add_trace(go.Scattergeo( mode='lines', lon=[bus0_x, (bus0_x + bus1_x) / 2, bus1_x], lat=[bus0_y, (bus0_y + bus1_y) / 2, bus1_y], line=dict( width=np.log(1 + s_nom_mul), color=color), text=[idx, idx, idx], hoverinfo='text', name=name )) # Adding links to map if len(self.net.links) != 0: # Get minimum p_nom_opt p_nom_opt_min = min(self.net.links.p_nom_opt[self.net.links.p_nom_opt > 0].values) for i, idx in enumerate(self.net.links.index): bus0_id = self.net.links.loc[idx, ("bus0", )] bus1_id = self.net.links.loc[idx, ("bus1", )] bus0_x = self.net.buses.loc[bus0_id, ("x", )] bus0_y = self.net.buses.loc[bus0_id, ("y", )] bus1_x = self.net.buses.loc[bus1_id, ("x", )] bus1_y = self.net.buses.loc[bus1_id, ("y", )] color = 'rgba(0,0,255,0.8)' name = 'AC' p_nom_mul = self.net.links.loc[idx, 'p_nom_opt']/p_nom_opt_min if self.net.links.loc[idx, ("carrier", )] == "DC": color = 'rgba(255,0,0,0.8)' name = 'DC' fig.add_trace(go.Scattergeo( mode='lines', lon=[bus0_x, (bus0_x+bus1_x)/2, bus1_x], lat=[bus0_y, (bus0_y+bus1_y)/2, bus1_y], line=dict( width=np.log(1+p_nom_mul)/4, color=color), text=["", f"Init Capacity: {self.net.links.loc[idx, 'p_nom']}<br>" f"Opt Capacity: {self.net.links.loc[idx, 'p_nom_opt']}", ""], hoverinfo='text', name=name )) # Add points to map p_noms = np.zeros((len(self.net.buses.index, ))) color = tech_colors['All'] if len(self.selected_types) == 1: color = tech_colors[self.selected_types[0]] colors = [color]*len(self.net.buses.index) for i, bus_id in enumerate(self.net.buses.index): total_gens = 0 generators = self.net.generators[self.net.generators.bus == bus_id] # Keep only the reactors of the type we want to display for t in self.selected_types: generators_filter = generators[generators.type == t] p_noms[i] += np.sum(generators_filter["p_nom_opt"].values) total_gens += len(generators_filter["p_nom"].values) if total_gens == 0: # No allowed generation building colors[i] = 'grey' elif p_noms[i] == 0: colors[i] = 'black' p_nom_max = np.max(p_noms) if p_nom_max == 0: p_nom_max = 1 # Prevents cases where there is no installed capacity at all fig.add_trace(go.Scattergeo( mode="markers", lat=self.net.buses['y'].values, lon=self.net.buses['x'].values, text=self.net.buses.index, hoverinfo='text', marker=dict( size=10+40*np.log(1+p_noms/p_nom_max), color=colors ), name='bus' )) return fig def get_line_info(): fig = go.Figure(data=go.Scatter( x=[i for i in range(len(self.net.snapshots))], y=self.net.links_t.p0[self.current_link_id], marker=dict(color='blue'), name='Power flow'), layout=go.Layout( title=f"Power flow for {self.current_line_id}", xaxis={'title': 'Time stamps'}, yaxis={'title': 'GWh (or GW)'})) # Original capacity capacity = self.net.links.loc[self.current_link_id, 'p_nom'] fig.add_trace(go.Scatter( x=[i for i in range(len(self.net.snapshots))], y=[capacity]*len(self.net.snapshots), marker=dict(color='red'), name='Original capacity' )) fig.add_trace(go.Scatter( x=[i for i in range(len(self.net.snapshots))], y=[-capacity]*len(self.net.snapshots), marker=dict(color='red', opacity=0.5), name='Original capacity' )) # New capacity capacity = self.net.links.loc[self.current_link_id, 'p_nom_opt'] fig.add_trace(go.Scatter( x=[i for i in range(len(self.net.snapshots))], y=[capacity] * len(self.net.snapshots), marker=dict(color='green'), name='Updated capacity' )) fig.add_trace(go.Scatter( x=[i for i in range(len(self.net.snapshots))], y=[-capacity] * len(self.net.snapshots), marker=dict(color='green'), name='Updated capacity' )) return fig # Application layout def get_generation(): gens = self.net.generators fig = go.Figure( layout=go.Layout( title=f"Generation in {self.current_bus_id}", xaxis={'title': 'Time stamps'}, yaxis={'title': 'GWh (or GW)'} )) types = list(set(gens.type.values)) # Put nuclear first if present if 'nuclear' in types: types.remove("nuclear") types.insert(0, "nuclear") for t in types: total_generation = [0] * len(self.net.snapshots) types_gens = gens[gens.type == t] generations_by_type = self.net.generators_t.p[types_gens.index].values if len(generations_by_type) != 0: total_generation = np.sum(generations_by_type, axis=1) fig.add_trace(go.Scatter( x=[i for i in range(len(self.net.snapshots))], y=total_generation, opacity=0.5, stackgroup='one', mode='none', fillcolor=tech_colors[t], marker=dict(color=tech_colors[t], opacity=0.5), name=t)) return fig def get_generation_per_node(): gens = self.net.generators[self.net.generators.bus == self.current_bus_id] """installed_cap = gens['p_nom_opt'].sum() available_power_per_gen = gens['p_nom_opt'].values gens_p_max_pu = np.zeros((len(gens.index), len(self.net.snapshots))) for i, idx in enumerate(gens.index): if idx in self.net.generators_t.p_max_pu.keys(): gens_p_max_pu[i] = self.net.generators_t.p_max_pu[idx].values available_power_per_bus = available_power_per_gen @ gens_p_max_pu """ fig = go.Figure( layout=go.Layout( title=f"Generation in {self.current_bus_id}", xaxis={'title': 'Time stamps'}, yaxis={'title': 'GWh (or GW)'} )) """ fig.add_trace(go.Scatter( x=[i for i in range(len(self.net.snapshots))], y=[installed_cap]*len(self.net.snapshots), name='Gen Capacity')) fig.add_trace(go.Scatter( x=[i for i in range(len(self.net.snapshots))], y=available_power_per_bus, name='Available Cap')) """ types = list(set(gens.type.values)) # Put nuclear first if present if 'nuclear' in types: types.remove("nuclear") types.insert(0, "nuclear") for t in types: total_generation = [0] * len(self.net.snapshots) types_gens = gens[gens.type == t] generations_by_type = self.net.generators_t.p[types_gens.index].values if len(generations_by_type) != 0: total_generation = np.sum(generations_by_type, axis=1) fig.add_trace(go.Scatter( x=[i for i in range(len(self.net.snapshots))], y=total_generation, opacity=0.5, stackgroup='one', mode='none', fillcolor=tech_colors[t], marker=dict(color=tech_colors[t], opacity=0.5), name=t)) return fig def get_demand_balancing(): # Compute total load, first line is useful in case there is no load at the selected bus load = np.zeros(len(self.net.snapshots)) loads = self.net.loads[self.net.loads.bus == self.current_bus_id] if len(loads) != 0: load += self.net.loads_t.p_set[loads.index].sum(axis=1) demand_balancing = np.zeros((len(self.net.snapshots))) # Generation gens = self.net.generators[self.net.generators.bus == self.current_bus_id] demand_balancing += self.net.generators_t.p[gens.index].sum(axis=1) # Add imports and remove exports links_out = self.net.links[self.net.links.bus0 == self.current_bus_id] links_in = self.net.links[self.net.links.bus1 == self.current_bus_id] inflow = self.net.links_t.p1[links_out.index].sum(axis=1) + self.net.links_t.p0[links_in.index].sum(axis=1) demand_balancing += inflow # Add discharge of battery and remove store storages = self.net.storage_units[self.net.storage_units.bus == self.current_bus_id] demand_balancing += self.net.storage_units_t.p[storages.index].sum(axis=1) fig = go.Figure( data=go.Scatter( x=[i for i in range(len(self.net.snapshots))], y=load, name='Load', marker=dict(color='red', opacity=0.5) ), layout=go.Layout( title=f"Demand balancing in {self.current_bus_id}", xaxis={'title': 'Time stamps'}, yaxis={'title': 'GWh (or GW)'} )) fig.add_trace(go.Scatter( x=[i for i in range(len(self.net.snapshots))], y=demand_balancing, opacity=0.5, stackgroup='one', mode='none', name='Demand balancing', fillcolor='blue', marker=dict(color='blue', opacity=0.5))) return fig def get_state_of_charge(): # Get storages at the current node storages = self.net.storages\ .where(self.net.storages.bus == self.current_bus_id, drop=True) # State of charge fig = go.Figure( data=go.Scatter( x=[i for i in range(len(self.net.snapshots))], y=np.sum(storages.state_of_charge.values, axis=0), name='SOF'), layout=go.Layout( title=f"State of charge in {self.current_bus_id}", xaxis={'title': 'Time stamps'}, yaxis={'title': 'GWh (or GW)'}, )) # Maximum level of charge fig.add_trace(go.Scatter( x=[i for i in range(len(self.net.snapshots))], y=[storages.p_nom_opt.values.item()*storages.max_hours.values.item()]*len(self.net.snapshots), name='Max Storage' )) return fig def get_charge_discharge(): # Get storages at the current node storages = self.net.storages\ .where(self.net.storages.bus == self.current_bus_id, drop=True) # State of charge fig = go.Figure( data=go.Scatter( x=[i for i in range(len(self.net.snapshots))], y=np.sum(storages.charge.values, axis=0), name='Charge-Discharge'), layout=go.Layout( title=f"Charge in {self.current_bus_id}", xaxis={'title': 'Time stamps'}, yaxis={'title': 'GWh (or GW)'}, )) # Maximum level of charge fig.add_trace(go.Scatter( x=[i for i in range(len(self.net.snapshots))], y=[storages.p_nom_opt.values.item()]*len(self.net.snapshots), name='Max in power' )) # Maximum level of discharge fig.add_trace(go.Scatter( x=[i for i in range(len(self.net.snapshots))], y=[-storages.p_nom_opt.values.item()]*len(self.net.snapshots), name='Max out power' )) return fig def get_costs_table(): #costs_fn = f"{self.output_dir}{self.current_test_number}/costs.yaml" #costs = yaml.load(open(costs_fn, "r"), Loader=yaml.FullLoader) # Generation gen_types = set(self.net.generators.type.values) total_new_gen_cap = dict.fromkeys(gen_types, 0) gen_invest_cost = dict.fromkeys(gen_types, 0) gen_op_cost = dict.fromkeys(gen_types, 0) for idx in self.net.generators.index: gen = self.net.generators.loc[idx] t = gen.type invest_cost = gen.capital_cost new_gen_cap = gen.p_nom_opt - gen.p_nom total_new_gen_cap[t] += new_gen_cap gen_invest_cost[t] += new_gen_cap * invest_cost gen_op_cost[t] += np.sum(self.net.generators_t.p[idx]) * gen.marginal_cost # Transmission trans_invest_cost = 0 total_new_trans_cap = 0 for idx in self.net.lines.index: line = self.net.lines.loc[idx] new_trans_cap = line.s_nom_opt - line.s_nom total_new_trans_cap += new_trans_cap trans_invest_cost += new_trans_cap * line.capital_cost # Storage store_invest_cost = 0 total_new_store_cap = 0 for idx in self.net.storage_units.index: storage = self.net.storage_units.loc[idx] new_store_cap = storage.p_nom_opt - storage.p_nom total_new_store_cap += new_store_cap store_invest_cost += new_store_cap * storage.capital_cost # Lost load """ lost_load_cost = 0 lost_load_cost_per_unit = costs["lost_load"] for idx in self.net.buses.index: load = self.net.loads_t.where(self.net.loads.bus == idx).p_set.values[0] generation = np.sum(self.net.generators_t .where(self.net.generators.bus == idx).p.values, axis=0) inflows = np.sum(self.net.lines_t.where(self.net.lines.bus1 == idx).s.values, axis=0) outflows = np.sum(self.net.lines_t.where(self.net.lines.bus0 == idx).s.values, axis=0) battery_charge = np.sum(self.net.storages_t.where(self.net.storages.bus == idx).charge.values, axis=0) lost_load = np.sum(load - generation - inflows + outflows + battery_charge) print(lost_load) lost_load_cost += lost_load * lost_load_cost_per_unit """ table = [] diviser = 1000.0 for t in gen_types: gen_invest_cost[t] /= diviser gen_op_cost[t] /= diviser total_gen_invest_cost = sum([gen_invest_cost[t] for t in gen_types]) total_gen_op_cost = sum([gen_op_cost[t] for t in gen_types]) total_gen_cost = total_gen_invest_cost + total_gen_op_cost trans_invest_cost /= diviser store_invest_cost /= diviser #lost_load_cost /= diviser for t in gen_types: table.append({"Tech": t, "Investment": f"{gen_invest_cost[t]:.4f}", "Operation": f"{gen_op_cost[t]:.4f}", "Total": f"{gen_invest_cost[t] + gen_op_cost[t]:.4f}"}) table.append({"Tech": "Gen Total", "Investment": f"{total_gen_invest_cost:.4f}", "Operation": f"{total_gen_op_cost:.4f}", "Total": f"{total_gen_cost:.4f}"}) table.append({"Tech": "Trans Total", "Investment": f"{trans_invest_cost:.4f}", "Operation": 0, "Total": f"{trans_invest_cost:.4f}"}) table.append({"Tech": "Store Total", "Investment": f"{store_invest_cost:.4f}", "Operation": 0, "Total": f"{store_invest_cost:.4f}"}) #table.append({"Tech": "Lost load", "Investment": "N/A", "Operation": "N/A", # "Total": f"{lost_load_cost:.4f}"}) table.append({"Tech": "Total", "Investment": f"{trans_invest_cost+total_gen_invest_cost:.4f}", "Operation": f"{total_gen_op_cost:.4f}", "Total": f"{trans_invest_cost+total_gen_cost+store_invest_cost:.4f}"}) return table def get_output_folders(): return [{'label': dir_name, 'value': dir_name} for dir_name in sorted(os.listdir(self.output_dir))] def get_parameters_list(): attrs = yaml.load(open(f"{self.output_dir}{self.current_test_number}/config.yaml", "rb"), Loader=yaml.FullLoader) return [{'name': key, 'value': str(attrs[key])} for key in attrs] def get_tech_type_list(): return [{'label': t, 'value': t} for t in self.selected_types] def get_capacities(): all_cap = dict.fromkeys(sorted(set(self.net.generators.type))) for key in all_cap: all_cap[key] = np.sum(self.net.generators[self.net.generators.type == key].p_nom_opt.values)/1000.0 fig = go.Figure( data=go.Pie( title="Capacities (GW)", values=list(all_cap.values()), labels=list(all_cap.keys()), marker=dict(colors=[tech_colors[key] for key in all_cap.keys()]))) return fig def get_capacities_for_node(): gens_at_bus = self.net.generators[self.net.generators.bus == self.current_bus_id] all_types = sorted(set(gens_at_bus.type.values)) data = [] for tech in all_types: data.append(go.Bar(name=tech, x=["Capacity"], y=[np.sum(gens_at_bus[self.net.generators.type == tech].p_nom_opt.values)/1000.0], marker=dict(color=tech_colors[tech]))) fig = go.Figure(data=data) fig.update_layout(barmode='stack') return fig def get_total_generation(): all_cap = dict.fromkeys(sorted(set(self.net.generators.type))) for key in all_cap: all_cap[key] = np.sum(self.net.generators_t.p[ self.net.generators[self.net.generators.type == key].index].values)/1000.0 fig = go.Figure( data=go.Pie( title="Generation (GWh)", values=list(all_cap.values()), labels=list(all_cap.keys()), marker=dict(colors=[tech_colors[key] for key in all_cap.keys()]))) return fig def get_total_generation_for_node(): gens_at_bus = self.net.generators[self.net.generators.bus == self.current_bus_id] all_types = sorted(set(gens_at_bus.type.values)) data = [] for tech in all_types: data.append(go.Bar(name=tech, x=["Generation"], y=[np.sum(self.net.generators_t.p[gens_at_bus[gens_at_bus.type == tech].index].values)/1000.0], marker=dict(color=tech_colors[tech]))) fig = go.Figure(data=data) fig.update_layout(barmode='stack') return fig def get_load_gen(): # Get the total load for every time stamp total_load = np.sum(self.net.loads_t.p_set.values, axis=1) # Get the total gen for every time stamp total_gen = np.zeros(len(total_load)) techs = self.selected_types for tech in techs: total_gen += np.sum(self.net.generators_t.p[ self.net.generators[self.net.generators.type == tech].index].values, axis=1) fig = go.Figure( data=go.Scatter( x=[i for i in range(len(self.net.snapshots))], y=total_load, name='Total Load'), layout=go.Layout( title='Total Load vs Total Gen', xaxis={'title': 'Time stamps'}, yaxis={'title': 'MWh (or MW)'}, )) # Maximum level of charge fig.add_trace(go.Scatter( x=[i for i in range(len(self.net.snapshots))], y=total_gen, name='Generation' )) return fig self.app.layout = html.Div([ html.H1('Interactive network representation'), html.Div([ # Parameters and costs html.Div([ dcc.Dropdown( id='output-selector', options=get_output_folders(), value=self.current_test_number ), html.Div([ dash_table.DataTable( id='parameters-table', columns=[{"name": "name", "id": "name"}, {"name": "value", "id": "value"}], data=get_parameters_list()), dcc.Checklist( id="tech-types", options=get_tech_type_list(), value=self.selected_types ), html.Button(id='submit-button', n_clicks=0, children='Submit') ]), html.Div([ dash_table.DataTable( id='cost-table', columns=[{"name": "Tech", "id": "Tech"}, {"name": "Investment (G€)", "id": "Investment"}, {"name": "Operation (G€)", "id": "Operation"}, {"name": "Total (G€)", "id": "Total"}], data=get_costs_table()), ]) ], style={"width": 1000}), # Graphs html.Div([ # Map and general info html.Div([ # Map html.Div([ dcc.Graph( id='map', figure=get_map(), style={'height': 700} ) ]), html.Div([ dcc.Graph( id='tot-cap', figure=get_capacities(), ), dcc.Graph( id='tot-gen', figure=get_total_generation(), ) ]), dcc.Graph( id='load-gen', figure=get_load_gen(), ) ], style={'display': 'flex'}), # Per-node info html.Div([ html.Div([ # Line power flow dcc.Graph( id='line-power-flow', figure=get_line_info(), ), # Demand balancing graph dcc.Graph( id='demand-balancing', figure=get_demand_balancing(), ), dcc.Graph( id='gen-per-bus', figure=get_generation_per_node(), ), dcc.Graph( id='gen', figure=get_generation(), ) ]), """ html.Div([ dcc.Graph( id='state-of-charge', figure=get_state_of_charge() ), dcc.Graph( id='charge-discharge', figure=get_charge_discharge() ) ])""", html.Div([ dcc.Graph( id='cap-per-bus', figure=get_capacities_for_node(), ), dcc.Graph( id='tot-gen-per-bus', figure=get_total_generation_for_node(), ) ]) ], style={'display': 'flex'}) ], style={'display': 'flex', 'flex-wrap': 'wrap'}) ]) ]) @self.app.callback( [Output('demand-balancing', 'figure'), # Output('state-of-charge', 'figure'), # Output('charge-discharge', 'figure'), Output('cap-per-bus', 'figure'), Output('tot-gen-per-bus', 'figure'), Output('gen-per-bus', 'figure'), Output('gen', 'figure')], [Input('map', 'clickData')]) def update_demand_balancing(clickData): if clickData is not None and 'points' in clickData: points = clickData['points'][0] if 'text' in points and '-' not in points['text']: self.current_bus_id = points['text'] return get_demand_balancing(), get_capacities_for_node(), get_total_generation_for_node(), \ get_generation_per_node(), get_generation() # , get_state_of_charge(), get_charge_discharge(), \ raise PreventUpdate """ @self.app.callback( Output('line-power-flow', 'figure'), [Input('map', 'clickData')]) def update_line_power_flow(clickData): if clickData is not None and 'points' in clickData: points = clickData['points'][0] if 'text' in points and '-' in points['text']: self.current_line_id = points['text'] return get_line_info() raise PreventUpdate """ @self.app.callback( Output('parameters-table', 'data'), [Input('output-selector', 'value')]) def update_param_table(value): self.current_test_number = value return get_parameters_list() @self.app.callback( [Output('map', 'figure'), Output('cost-table', 'data'), Output('tot-cap', 'figure'), Output('tot-gen', 'figure'), Output('load-gen', 'figure')], [Input('submit-button', 'n_clicks')], [State('output-selector', 'value'), State('tech-types', 'value')]) def update_network(n_clicks, value1, value2): print(value2) self.net = Network() self.net.import_from_csv_folder(f"{self.output_dir}{value1}/") self.current_link_id = self.net.links.index[0] self.current_bus_id = self.net.buses.index[0] self.selected_types = value2 return get_map(), get_costs_table(), get_capacities(), get_total_generation(), get_load_gen() return self.app
main_output_dir = f'../output/{topology}/' results = 'compare' # 'compare', 'single' resolution = 'H' start = datetime(2015, 12, 13, 0, 0, 0) end = datetime(2015, 12, 19, 23, 0, 0) if results == 'single': run_id = '20200429_123543' output_dir = f"{main_output_dir}{run_id}/" net = Network() net.import_from_csv_folder(output_dir) pprp = SizingResultsSingleNet(net, start, end, resolution) pprp.make_plots_one_net() else: # first_run_id = '20200429_123543' # second_run_id = '20200429_132039' first_run_id = '20200429_123543' second_run_id = '20200429_154728' first_output_dir = f"{main_output_dir}{first_run_id}/" second_output_dir = f"{main_output_dir}{second_run_id}/"
config_fn = join(output_dir, 'config.yaml') config = yaml.load(open(config_fn, 'r'), Loader=yaml.FullLoader) run_name = config["res"]["sites_dir"] + "_" + \ config["res"]["sites_fn"].split("_")[0].upper() name = run_name.split("_")[-3:] if "MAX" in name: name = "PROD" else: name = "COMP_c = " + name[1][1:] + "_" + name[0] run_names.append(name) net = Network() net.import_from_csv_folder(output_dir) nets += [net] with open(join(output_dir, "solver.log"), 'r') as f: for line in f: if "objective" in line: objectives[name] = float(line.split(' ')[-1]) * 1e-5 caption = ", ".join(run_name.split('_')[:-2]) table = generate_costs_table(nets, run_names, [ "ccgt", "wind_offshore", "wind_onshore", "pv_utility", "pv_residential", "AC", "DC", "Li-ion" ]) text = convert_cost_table_to_latex(table, objectives, caption)
def load_topology(nuts_codes, config, voltages: List[float] = None, plot: bool = False): net = Network() net.import_from_csv_folder( f"{data_path}topologies/pypsa_entsoe_gridkit/generated/base_network/") if 1: import matplotlib.pyplot as plt net.plot(bus_sizes=0.001) plt.show() exit() # Remove all buses outside desired regions region_shapes_ds = get_shapes(nuts_codes, save=True)["geometry"] buses_in_nuts_regions = \ net.buses[['x', 'y']].apply(lambda p: any([shape.contains(Point(p)) for shape in region_shapes_ds]), axis=1) net.buses = net.buses[buses_in_nuts_regions] if 0: plt.figure() net.plot(bus_sizes=0.001) # Remove all buses which are not at the desired voltage buses_with_v_nom_to_keep_b = net.buses.v_nom.isnull() if voltages is not None: buses_with_v_nom_to_keep_b |= net.buses.v_nom.isin(voltages) logger.info( "Removing buses with voltages {}" "".format( pd.Index( net.buses.v_nom.unique()).dropna().difference(voltages))) net.buses = net.buses[buses_with_v_nom_to_keep_b] if 1: plt.figure() net.plot(bus_sizes=0.001) plt.show() # Remove dangling branches net.lines = remove_dangling_branches(net.lines, net.buses.index) net.links = remove_dangling_branches(net.links, net.buses.index) net.transformers = remove_dangling_branches(net.transformers, net.buses.index) # Set electrical parameters set_electrical_parameters_lines(net, config['lines'], net.buses.v_nom.dropna().unique().tolist()) set_electrical_parameters_links(net, config['links']) set_electrical_parameters_transformers(net, config['transformers']) # Allows to set under construction links and lines to 0 or remove them completely, # and remove some unconnected components that might appear as a result net = adjust_capacities_of_under_construction_branches( net, config['lines'], config['links']) # Remove unconnected components # TODO: allow to simplify the network (i.e. convert everything to 380) or not ? net = cluster_network(net, nuts_codes) if plot: from epippy.topologies.core.plot import plot_topology all_lines = pd.concat( (net.links[['bus0', 'bus1']], net.lines[['bus0', 'bus1']])) plot_topology(net.buses, all_lines) plt.show() return net