From f8fbf69e87133fd2df397e8605b693fb72d5032d Mon Sep 17 00:00:00 2001 From: apigott Date: Thu, 11 Jun 2026 06:45:28 -0600 Subject: [PATCH 01/12] update breaking function calls --- workflow/scripts/add_demand.py | 2 +- workflow/scripts/add_electricity.py | 12 +-- workflow/scripts/add_extra_components.py | 82 ++++++++++---------- workflow/scripts/add_sectors.py | 10 +-- workflow/scripts/build_base_network.py | 29 +++---- workflow/scripts/build_electricity_sector.py | 34 ++++---- workflow/scripts/build_emission_tracking.py | 8 +- workflow/scripts/build_heat.py | 58 +++++++------- workflow/scripts/build_natural_gas.py | 28 +++---- workflow/scripts/build_stock_data.py | 20 ++--- workflow/scripts/build_transportation.py | 34 ++++---- workflow/scripts/cluster_network.py | 18 ++--- workflow/scripts/opts/policy.py | 2 +- workflow/scripts/opts/reserves.py | 4 +- workflow/scripts/plot_sankey_energy.py | 2 +- workflow/scripts/simplify_network.py | 4 +- workflow/scripts/solve_network.py | 4 +- workflow/scripts/test/test_reserves.py | 4 +- 18 files changed, 179 insertions(+), 176 deletions(-) diff --git a/workflow/scripts/add_demand.py b/workflow/scripts/add_demand.py index a7c5a4afc..4beffb801 100644 --- a/workflow/scripts/add_demand.py +++ b/workflow/scripts/add_demand.py @@ -31,7 +31,7 @@ def attach_demand(n: pypsa.Network, df: pd.DataFrame, carrier: str, suffix: str) n.snapshots, ), "Demand time series length does not match network snapshots" df.index = n.snapshots - n.madd( + n.add( "Load", df.columns, suffix=suffix, diff --git a/workflow/scripts/add_electricity.py b/workflow/scripts/add_electricity.py index 76918bfbd..6a288eb0f 100755 --- a/workflow/scripts/add_electricity.py +++ b/workflow/scripts/add_electricity.py @@ -78,7 +78,7 @@ def add_missing_carriers(n, carriers): """Function to add missing carriers to the network without raising errors.""" missing_carriers = set(carriers) - set(n.carriers.index) if len(missing_carriers) > 0: - n.madd("Carrier", missing_carriers) + n.add("Carrier", missing_carriers) def clean_locational_multiplier(df: pd.DataFrame): @@ -489,7 +489,7 @@ def attach_conventional_generators( # Define generators using modified ppl DataFrame caps = plants.groupby("carrier").p_nom.sum().div(1e3).round(2) logger.info(f"Adding {len(plants)} generators with capacities [GW] \n{caps}") - n.madd( + n.add( "Generator", plants.index, carrier=plants.carrier, @@ -656,7 +656,7 @@ def attach_wind_and_solar( logger.info(f"Adding {car} capacity-factor profiles to the network.") - n.madd( + n.add( "Generator", bus_list, " " + car, @@ -769,7 +769,7 @@ def attach_egs( f"Adding EGS (Resource Quality-{q}) capacity-factor profiles to the network.", ) - n.madd( + n.add( "Generator", bus_list, suffix, @@ -801,7 +801,7 @@ def attach_battery_storage( ) plants_filt = plants_filt.dropna(subset=["energy_storage_capacity_mwh"]) - n.madd( # Adds storage units which can retire economically or at their lifetime + n.add( # Adds storage units which can retire economically or at their lifetime "StorageUnit", plants_filt.index, carrier="battery", @@ -960,7 +960,7 @@ def attach_breakthrough_renewable_plants( p_max_pu = p_max_pu.drop(leap_day.index) p_max_pu = broadcast_investment_horizons_index(n, p_max_pu) - n.madd( + n.add( "Generator", tech_plants.index, bus=tech_plants.bus_id, diff --git a/workflow/scripts/add_extra_components.py b/workflow/scripts/add_extra_components.py index b65c44b71..be9dd23c7 100644 --- a/workflow/scripts/add_extra_components.py +++ b/workflow/scripts/add_extra_components.py @@ -10,7 +10,7 @@ from add_electricity import add_missing_carriers from eia import FuelCosts from opts._helpers import get_region_buses -from pypsa.descriptors import get_switchable_as_dense as get_as_dense +from pypsa.definitions.structures import get_switchable_as_dense as get_as_dense from shapely.geometry import Point idx = pd.IndexSlice @@ -68,7 +68,7 @@ def attach_storageunits(n, costs, elec_opts, investment_year): max_hours = int(carrier.split("hr_")[0]) roundtrip_correction = 0.5 if "battery" in carrier else 1 - n.madd( + n.add( "StorageUnit", buses_i, suffix=f" {carrier}_{investment_year}", @@ -167,7 +167,7 @@ def attach_phs_storageunits(n: pypsa.Network, elec_opts, costs: pd.DataFrame): costs.at["PHS", "co2_emissions"] = 0 add_missing_carriers(n, ["PHS"]) add_co2_emissions(n, costs, ["PHS"]) - n.madd( + n.add( "StorageUnit", region_onshore_psh_grp.index, bus=region_onshore_psh_grp.name, @@ -193,9 +193,9 @@ def attach_stores(n, costs, elec_opts, investment_year): bus_sub_dict = {k: n.buses[k].values for k in ["x", "y", "country"]} if "H2" in carriers: - h2_buses_i = n.madd("Bus", buses_i + " H2", carrier="H2", **bus_sub_dict) + h2_buses_i = n.add("Bus", buses_i + " H2", carrier="H2", **bus_sub_dict) - n.madd( + n.add( "Store", h2_buses_i, bus=h2_buses_i, @@ -208,7 +208,7 @@ def attach_stores(n, costs, elec_opts, investment_year): suffix=f" {investment_year}", ) - n.madd( + n.add( "Link", h2_buses_i + " Electrolysis", bus0=buses_i, @@ -223,7 +223,7 @@ def attach_stores(n, costs, elec_opts, investment_year): suffix=str(investment_year), ) - n.madd( + n.add( "Link", h2_buses_i + " Fuel Cell", bus0=h2_buses_i, @@ -313,7 +313,7 @@ def split_retirement_gens( # Adding Expanding generators for the first investment period # There are generators that exist today and could expand # in the first time horizon - n.madd( + n.add( "Generator", retirement_gens.index, carrier=retirement_gens.carrier, @@ -382,7 +382,7 @@ def attach_multihorizon_existing_generators( if gens.empty or len(n.investment_periods) == 1: return - n.madd( + n.add( "Generator", gens.index, suffix=f" {investment_year}", @@ -447,7 +447,7 @@ def attach_multihorizon_egs( base_year = n.investment_periods[0] learning_ratio = costs.loc["EGS", "capex_per_kw"] / costs_dict[base_year].loc["EGS", "capex_per_kw"] capital_cost = learning_ratio * gens["capital_cost"] - n.madd( + n.add( "Generator", gens.index, suffix=f" {investment_year}", @@ -546,7 +546,7 @@ def attach_multihorizon_new_generators(n, costs, carriers, investment_year): p_max_pu_t = n.get_switchable_as_dense("Generator", "p_max_pu") p_max_pu_t = (p_max_pu_t[[x for x in existing_gens.index if x in p_max_pu_t.columns]]).mean().mean() - n.madd( + n.add( "Generator", buses_i, suffix=f" {carrier}_{investment_year}", @@ -660,7 +660,7 @@ def add_demand_response( # two storageunits for forward and backwards load shifting - n.madd( + n.add( "Bus", names=df.index, suffix="-fwd-dr", @@ -678,7 +678,7 @@ def add_demand_response( substation_lv=df.substation_lv, ) - n.madd( + n.add( "Bus", names=df.index, suffix="-bck-dr", @@ -698,7 +698,7 @@ def add_demand_response( # seperate charging/discharging links for easier constraint generation - n.madd( + n.add( "Link", names=df.index, suffix="-fwd-dr-charger", @@ -709,7 +709,7 @@ def add_demand_response( p_nom=np.inf, ) - n.madd( + n.add( "Link", names=df.index, suffix="-fwd-dr-discharger", @@ -720,7 +720,7 @@ def add_demand_response( p_nom=np.inf, ) - n.madd( + n.add( "Link", names=df.index, suffix="-bck-dr-charger", @@ -731,7 +731,7 @@ def add_demand_response( p_nom=np.inf, ) - n.madd( + n.add( "Link", names=df.index, suffix="-bck-dr-discharger", @@ -745,7 +745,7 @@ def add_demand_response( # backward stores have positive marginal cost storage and postive e # forward stores have negative marginal cost storage and negative e - n.madd( + n.add( "Store", names=df.index, suffix="-bck-dr", @@ -759,7 +759,7 @@ def add_demand_response( marginal_cost_storage=marginal_cost_storage, ) - n.madd( + n.add( "Store", names=df.index, suffix="-fwd-dr", @@ -814,17 +814,17 @@ def trim_network(n, trim_topology): component = n.df(c) rm = component[component.bus.isin(buses_to_remove.index)] if not rm.empty: - n.mremove(c, rm.index) + n.remove(c, rm.index) # Remove lines and links at buses being removed for c in ["Line", "Link"]: component = n.df(c) rm = component[~component.bus0.isin(internal_buses.index) & ~component.bus1.isin(internal_buses.index)] if not rm.empty: - n.mremove(c, rm.index) + n.remove(c, rm.index) # Remove the buses - n.mremove("Bus", buses_to_remove.index) + n.remove("Bus", buses_to_remove.index) # Get OCGT generators and calculate average marginal cost ocgt_gens = n.generators[n.generators.carrier == "OCGT"] @@ -837,7 +837,7 @@ def trim_network(n, trim_topology): rm = component[component.bus.isin(external_buses_to_keep.index)] if not rm.empty: logger.info(f"Removing {c} at external buses {external_buses_to_keep.index} with components {rm.index}") - n.mremove(c, rm.index) + n.remove(c, rm.index) # Handle external buses and their generators for bus in external_buses_to_keep.index: @@ -878,7 +878,7 @@ def trim_network(n, trim_topology): n.links.index.str.contains("exp") & (n.links.bus0.isin(external_buses_to_keep.index) | n.links.bus1.isin(external_buses_to_keep.index)) ] - n.mremove("Link", links_to_remove.index) + n.remove("Link", links_to_remove.index) # Update network topology n.determine_network_topology() @@ -996,7 +996,7 @@ def _add_import_export_buses(n: pypsa.Network, regions_2_add: list[str], directi # cant add in the reeds_state, reeds_zone, reeds_ba, interconnect, trans_reg, trans_grp # because this information has already been filtered out of the network - n.madd( + n.add( "Bus", regions_2_add, suffix=suffix, @@ -1007,7 +1007,7 @@ def _add_import_export_buses(n: pypsa.Network, regions_2_add: list[str], directi def _add_import_export_stores(n: pypsa.Network, regions_2_add: list[str], direction: str) -> None: """Adds import and export stores to the network.""" if direction == "imports": - n.madd( + n.add( "Store", regions_2_add, bus=[f"{x}_imports" for x in regions_2_add], @@ -1024,7 +1024,7 @@ def _add_import_export_stores(n: pypsa.Network, regions_2_add: list[str], direct marginal_cost=0, ) elif direction == "exports": - n.madd( + n.add( "Store", regions_2_add, bus=[f"{x}_exports" for x in regions_2_add], @@ -1141,7 +1141,7 @@ def add_co2_storage(n: pypsa.Network, config: dict, co2_storage_csv: str, costs: co2_storage = pd.read_csv(co2_storage_csv).set_index("node") # add carrier to represent CO2 - n.madd( + n.add( "Carrier", ["co2"], color=config["plotting"]["tech_colors"]["co2"], @@ -1149,7 +1149,7 @@ def add_co2_storage(n: pypsa.Network, config: dict, co2_storage_csv: str, costs: ) # add buses to represent node level CO2 captured by different processes - n.madd( + n.add( "Bus", co2_storage.index, suffix=" co2 capture", @@ -1157,7 +1157,7 @@ def add_co2_storage(n: pypsa.Network, config: dict, co2_storage_csv: str, costs: ) # add stores to represent node level CO2 (underground) storage - n.madd( + n.add( "Store", co2_storage.index, suffix=" co2 storage", @@ -1171,7 +1171,7 @@ def add_co2_storage(n: pypsa.Network, config: dict, co2_storage_csv: str, costs: # add carrier to represent CC only (i.e. without S) carriers = n.carriers.query("Carrier.str.endswith('CCS')") if not carriers.empty: - n.madd( + n.add( "Carrier", carriers.index.str.replace("CCS", "CC", regex=True), color=carriers["color"], @@ -1239,7 +1239,7 @@ def add_co2_storage(n: pypsa.Network, config: dict, co2_storage_csv: str, costs: # add buses to represent node level electricity CC generator indexes = n.generators.loc[generators].index - n.madd( + n.add( "Bus", indexes, carrier=n.generators.loc[generators].carrier, @@ -1276,14 +1276,14 @@ def add_co2_storage(n: pypsa.Network, config: dict, co2_storage_csv: str, costs: buses_atmosphere = buses_atmosphere_unique # add buses to represent (air) atmosphere where CO2 emissions are sent to - n.madd( + n.add( "Bus", buses_atmosphere_unique, carrier="co2", ) # add stores to represent (air) atmosphere where CO2 emissions are stored - n.madd( + n.add( "Store", buses_atmosphere_unique, bus=buses_atmosphere_unique, @@ -1313,7 +1313,7 @@ def add_co2_storage(n: pypsa.Network, config: dict, co2_storage_csv: str, costs: efficiency3.append(efficiency * (1 - cc_level) / cc_level) # add links to represent sending electricity (in MW) to the electricity bus (e.g. "p9" if ReEDS or "p100 0" if TAMU) as well as sending emitted CO2 (by the generator) to both the atmosphere bus and the co2 capture bus - n.madd( + n.add( "Link", indexes, bus0=indexes, @@ -1350,7 +1350,7 @@ def add_co2_network(n: pypsa.Network, config: dict): ) # add links to represent CO2 (transportation) network based on electricity connections layout - n.madd( + n.add( "Link", connections.index, suffix=" co2 transport", @@ -1421,14 +1421,14 @@ def add_dac(n: pypsa.Network, config: dict, sector: bool): exists_dac.add(dac) # add node or state level buses to represent (air) atmosphere where CO2 emissions are sent to (on a per sector basis) - n.madd( + n.add( "Bus", buses_atmosphere_unique, carrier="co2", ) # add links from node or state level buses that represent (air) atmosphere to state level buses tracking CO2 emissions (on a per sector basis) - n.madd( + n.add( "Link", buses_atmosphere_unique, bus0=buses_atmosphere_unique, @@ -1451,7 +1451,7 @@ def add_dac(n: pypsa.Network, config: dict, sector: bool): links_dac = buses_co2_capture.str.replace(" co2 capture", " dac") # add carrier to represent DAC - n.madd( + n.add( "Carrier", ["dac"], color=config["plotting"]["tech_colors"]["dac"], @@ -1467,7 +1467,7 @@ def add_dac(n: pypsa.Network, config: dict, sector: bool): ) # add links to represent node level DAC capabilities - n.madd( + n.add( "Link", links_dac, bus0=buses_atmosphere, @@ -1563,7 +1563,7 @@ def add_dac(n: pypsa.Network, config: dict, sector: bool): if not multi_horizon_gens.empty and not len(n.investment_periods) == 1: # Remove duplicate generators from first investment period, # created by attach_multihorizon_generators - n.mremove("Generator", multi_horizon_gens.index) + n.remove("Generator", multi_horizon_gens.index) apply_itc(n, snakemake.config["costs"]["itc_modifier"]) apply_ptc(n, snakemake.config["costs"]["ptc_modifier"], costs) diff --git a/workflow/scripts/add_sectors.py b/workflow/scripts/add_sectors.py index 9a4c7e0a8..352ed62b8 100644 --- a/workflow/scripts/add_sectors.py +++ b/workflow/scripts/add_sectors.py @@ -137,7 +137,7 @@ def add_sector_foundation( points = points[~points.index.isin(existing)] - n.madd( + n.add( "Bus", names=points.index, suffix=f" {carrier}", @@ -173,7 +173,7 @@ def add_sector_foundation( marginal_cost = 0 if add_supply: - n.madd( + n.add( "Store", names=points.index, suffix=f" {carrier}", @@ -414,7 +414,7 @@ def convert_generators_2_links( if cols: pnl[param] = df[cols] - n.madd( + n.add( "Link", names=plants.index, bus0=plants.STATE + bus0_suffix, @@ -439,7 +439,7 @@ def convert_generators_2_links( for param, df in pnl.items(): n.links_t[param] = n.links_t[param].join(df, how="inner") - n.mremove("Generator", plants.index) + n.remove("Generator", plants.index) # existing links will give a 'nan in efficiency2' warning n.links["efficiency2"] = n.links.efficiency2.fillna(0) @@ -459,7 +459,7 @@ def split_loads_by_carrier(n: pypsa.Network): for bus in n.buses.index.unique(): df = n.loads[n.loads.bus == bus][["bus", "carrier"]] - n.madd( + n.add( "Bus", df.index, v_nom=1, diff --git a/workflow/scripts/build_base_network.py b/workflow/scripts/build_base_network.py index 1c1745696..ad85859ba 100644 --- a/workflow/scripts/build_base_network.py +++ b/workflow/scripts/build_base_network.py @@ -46,7 +46,7 @@ def add_buses_from_file( logger.info(f"Adding {len(buses)} buses to the network.") - n.madd( + n.add( "Bus", buses.index, Pd=buses.Pd, # used to decompose zone demand to bus demand @@ -83,7 +83,7 @@ def add_branches_from_file(n: pypsa.Network, fn_branches: str) -> pypsa.Network: logger.info(f"Adding {len(tech_branches)} branches as {tech}s to the network.") # S_base = 100 MVA - n.madd( + n.add( tech, tech_branches.index, bus0=tech_branches.from_bus_id, @@ -121,7 +121,7 @@ def add_dclines_from_file(n: pypsa.Network, fn_dclines: str) -> pypsa.Network: logger.info(f"Adding {len(dclines)} dc-lines as Links to the network.") - n.madd( + n.add( "Link", dclines.index, suffix="_fwd", @@ -132,7 +132,7 @@ def add_dclines_from_file(n: pypsa.Network, fn_dclines: str) -> pypsa.Network: underwater_fraction=0.0, # DC line in bay is underwater, but does network have this line? ) - n.madd( + n.add( "Link", dclines.index, suffix="_rev", @@ -286,7 +286,7 @@ def build_offshore_buses( def add_offshore_buses(n: pypsa.Network, offshore_buses: pd.DataFrame) -> pypsa.Network: """Add offshore buses to network and assigns it a POI.""" - n.madd( + n.add( "Bus", offshore_buses.index, Pd=0, @@ -356,7 +356,10 @@ def match_missing_buses(buses_to_match_to, missing_buses): missing_buses[["x", "y"]].values, # The input array for the query k=1, # The number of nearest neighbors ) - missing_buses["bus_assignment"] = buses_to_match_to.reset_index().iloc[missing_buses.id_nearest].Bus.values + + foo = buses_to_match_to.reset_index().iloc[missing_buses.id_nearest]#.name.values + breakpoint() + missing_buses["bus_assignment"] = foo.name.values missing_buses = missing_buses.drop(columns=["id_nearest"]) return missing_buses @@ -367,11 +370,11 @@ def remove_breakthrough_offshore(n: pypsa.Network) -> pypsa.Network: original BE network. """ # rm any lines/buses associated with offshore substation buses - n.mremove( + n.remove( "Line", n.lines.loc[n.lines.bus0.isin(n.buses.loc[n.buses.substation_off].index)].index, ) - n.mremove("Bus", n.buses.loc[n.buses.substation_off].index) + n.remove("Bus", n.buses.loc[n.buses.substation_off].index) return n @@ -599,10 +602,10 @@ def main(snakemake): (n.transformers.bus0.isin(rm_buses.index)) | (n.transformers.bus1.isin(rm_buses.index)) ] rm_links = n.links.loc[(n.links.bus0.isin(rm_buses.index)) | (n.links.bus1.isin(rm_buses.index))] - n.mremove("Line", rm_lines.index.tolist()) - n.mremove("Transformer", rm_transformers.index.tolist()) - n.mremove("Link", rm_links.index.tolist()) - n.mremove("Bus", rm_buses.index.tolist()) + n.remove("Line", rm_lines.index.tolist()) + n.remove("Transformer", rm_transformers.index.tolist()) + n.remove("Link", rm_links.index.tolist()) + n.remove("Bus", rm_buses.index.tolist()) logger.info( f"Filtered network to {model_topology[region_type]}. Removed {len(rm_buses)} buses, {len(n.buses)} remaining.", ) @@ -677,6 +680,6 @@ def main(snakemake): if "snakemake" not in globals(): from _helpers import mock_snakemake - snakemake = mock_snakemake("build_base_network", interconnect="texas") + snakemake = mock_snakemake("build_base_network", interconnect="western", configfiles=["config.default.yaml"]) configure_logging(snakemake) main(snakemake) diff --git a/workflow/scripts/build_electricity_sector.py b/workflow/scripts/build_electricity_sector.py index 36339f5a7..63e3d8ffe 100644 --- a/workflow/scripts/build_electricity_sector.py +++ b/workflow/scripts/build_electricity_sector.py @@ -68,7 +68,7 @@ def add_electricity_infrastructure( df.index = df["bus0"] + " " + df["sector"] df["carrier"] = df["sector"] + f"-{elec}" - n.madd( + n.add( "Link", df.index, suffix=suffix, @@ -119,7 +119,7 @@ def add_electricity_dr( # two buses for forward and backwards load shifting - n.madd( + n.add( "Bus", df.index, suffix="-fwd-dr", @@ -131,7 +131,7 @@ def add_electricity_dr( STATE_NAME=df.STATE_NAME, ) - n.madd( + n.add( "Bus", df.index, suffix="-bck-dr", @@ -145,7 +145,7 @@ def add_electricity_dr( # seperate charging/discharging links to follow conventions - n.madd( + n.add( "Link", df.index, suffix="-fwd-dr-charger", @@ -158,7 +158,7 @@ def add_electricity_dr( build_year=n.investment_periods[0], ) - n.madd( + n.add( "Link", df.index, suffix="-fwd-dr-discharger", @@ -171,7 +171,7 @@ def add_electricity_dr( build_year=n.investment_periods[0], ) - n.madd( + n.add( "Link", df.index, suffix="-bck-dr-charger", @@ -184,7 +184,7 @@ def add_electricity_dr( build_year=n.investment_periods[0], ) - n.madd( + n.add( "Link", df.index, suffix="-bck-dr-discharger", @@ -200,7 +200,7 @@ def add_electricity_dr( # backward stores have positive marginal cost storage and postive e # forward stores have negative marginal cost storage and negative e - n.madd( + n.add( "Store", df.index, suffix="-bck-dr", @@ -217,7 +217,7 @@ def add_electricity_dr( standing_loss=0, ) - n.madd( + n.add( "Store", df.index, suffix="-fwd-dr", @@ -272,7 +272,7 @@ def _split_urban_rural_load( # strip out the 'res-heat' and 'com-heat' to add in 'rural' and 'urban' new_buses.index = new_buses.index.str.rstrip(f" {sector}-{fuel}") - n.madd( + n.add( "Bus", new_buses.index, suffix=f" {sector}-{system}-{fuel}", @@ -292,7 +292,7 @@ def _split_urban_rural_load( ) loads_t = loads_t.mul(ratios[f"{system}_fraction"]) - n.madd( + n.add( "Load", new_buses.index, suffix=f" {sector}-{system}-{fuel}", @@ -302,8 +302,8 @@ def _split_urban_rural_load( ) # remove old combined loads from the network - n.mremove("Load", load_names) - n.mremove("Bus", load_names) + n.remove("Load", load_names) + n.remove("Bus", load_names) def _format_total_load( @@ -333,7 +333,7 @@ def _format_total_load( # strip out the 'res-heat' and 'com-heat' to add in 'rural' and 'urban' new_buses.index = new_buses.index.str.rstrip(f" {sector}-{fuel}") - n.madd( + n.add( "Bus", new_buses.index, suffix=f" {sector}-total-{fuel}", @@ -352,7 +352,7 @@ def _format_total_load( columns={x: x.rstrip(f" {sector}-{fuel}") for x in loads_t.columns}, ) - n.madd( + n.add( "Load", new_buses.index, suffix=f" {sector}-total-{fuel}", @@ -362,5 +362,5 @@ def _format_total_load( ) # remove old combined loads from the network - n.mremove("Load", load_names) - n.mremove("Bus", load_names) + n.remove("Load", load_names) + n.remove("Bus", load_names) diff --git a/workflow/scripts/build_emission_tracking.py b/workflow/scripts/build_emission_tracking.py index 50f5e933d..90d321279 100644 --- a/workflow/scripts/build_emission_tracking.py +++ b/workflow/scripts/build_emission_tracking.py @@ -78,7 +78,7 @@ def _build_co2_bus(n: pypsa.Network, states: list[str], sectors: list[str]): df = pd.DataFrame(itertools.product(states, sectors), columns=["state", "sector"]) df.index = df.state + " " + df.sector - n.madd("Bus", df.index, suffix="-co2", carrier="co2", STATE=df.state) + n.add("Bus", df.index, suffix="-co2", carrier="co2", STATE=df.state) def _build_co2_store(n: pypsa.Network, states: list[str], sectors: list[str]): @@ -86,7 +86,7 @@ def _build_co2_store(n: pypsa.Network, states: list[str], sectors: list[str]): df = pd.DataFrame(itertools.product(states, sectors), columns=["state", "sector"]) df.index = df.state + " " + df.sector - n.madd( + n.add( "Store", df.index, suffix="-co2", @@ -122,7 +122,7 @@ def _build_ch4_bus(n: pypsa.Network, states: list[str]): df = pd.DataFrame(states, columns=["state"]) df.index = df.state - n.madd("Bus", df.index, suffix=" gas-ch4", carrier="ch4", STATE=df.state) + n.add("Bus", df.index, suffix=" gas-ch4", carrier="ch4", STATE=df.state) def _build_ch4_store(n: pypsa.Network, states: list[str]): @@ -130,7 +130,7 @@ def _build_ch4_store(n: pypsa.Network, states: list[str]): df = pd.DataFrame(states, columns=["state"]) df.index = df.state - n.madd( + n.add( "Store", df.index, suffix=" gas-ch4", diff --git a/workflow/scripts/build_heat.py b/workflow/scripts/build_heat.py index f8735b90f..424a5e2d4 100644 --- a/workflow/scripts/build_heat.py +++ b/workflow/scripts/build_heat.py @@ -443,7 +443,7 @@ def add_air_cons( acs["carrier"] = f"{sector}-{heat_system}-air-con" acs.index = acs.bus0 - n.madd( + n.add( "Link", acs.index, suffix=f" {sector}-{heat_system}-air-con", @@ -507,7 +507,7 @@ def add_service_heat_pumps_cooling( build_year = n.investment_periods[0] # use suffix to retain COP profiles - n.madd( + n.add( "Link", cool_links.index, bus0=cool_links.bus0, @@ -559,7 +559,7 @@ def _split_urban_rural_load( # strip out the 'res-heat' and 'com-heat' to add in 'rural' and 'urban' new_buses.index = new_buses.index.str.rstrip(f" {sector}-{fuel}") - n.madd( + n.add( "Bus", new_buses.index, suffix=f" {sector}-{system}-{fuel}", @@ -579,7 +579,7 @@ def _split_urban_rural_load( ) loads_t = loads_t.mul(ratios[f"{system}_fraction"]) - n.madd( + n.add( "Load", new_buses.index, suffix=f" {sector}-{system}-{fuel}", @@ -589,8 +589,8 @@ def _split_urban_rural_load( ) # remove old combined loads from the network - n.mremove("Load", load_names) - n.mremove("Bus", load_names) + n.remove("Load", load_names) + n.remove("Bus", load_names) def _format_total_load( @@ -617,7 +617,7 @@ def _format_total_load( # strip out the 'res-heat' and 'com-heat' to add in 'rural' and 'urban' new_buses.index = new_buses.index.str.rstrip(f" {sector}-{fuel}") - n.madd( + n.add( "Bus", new_buses.index, suffix=f" {sector}-total-{fuel}", @@ -636,7 +636,7 @@ def _format_total_load( columns={x: x.rstrip(f" {sector}-{fuel}") for x in loads_t.columns}, ) - n.madd( + n.add( "Load", new_buses.index, suffix=f" {sector}-total-{fuel}", @@ -646,8 +646,8 @@ def _format_total_load( ) # remove old combined loads from the network - n.mremove("Load", load_names) - n.mremove("Bus", load_names) + n.remove("Load", load_names) + n.remove("Bus", load_names) def add_service_furnace( @@ -726,7 +726,7 @@ def add_service_furnace( df["efficiency2"] = costs.at[fuel, "co2_emissions"] if fuel == "elec": - n.madd( + n.add( "Link", df.index, suffix=f" {new_carrier}", @@ -740,7 +740,7 @@ def add_service_furnace( build_year=build_year, ) else: - n.madd( + n.add( "Link", df.index, suffix=f" {new_carrier}", @@ -819,7 +819,7 @@ def add_heat_dr( # two buses for forward and backwards load shifting - n.madd( + n.add( "Bus", df.index, suffix="-fwd-dr", @@ -831,7 +831,7 @@ def add_heat_dr( STATE_NAME=df.STATE_NAME, ) - n.madd( + n.add( "Bus", df.index, suffix="-bck-dr", @@ -845,7 +845,7 @@ def add_heat_dr( # seperate charging/discharging links to follow conventions - n.madd( + n.add( "Link", df.index, suffix="-fwd-dr-charger", @@ -858,7 +858,7 @@ def add_heat_dr( build_year=build_year, ) - n.madd( + n.add( "Link", df.index, suffix="-fwd-dr-discharger", @@ -871,7 +871,7 @@ def add_heat_dr( build_year=build_year, ) - n.madd( + n.add( "Link", df.index, suffix="-bck-dr-charger", @@ -884,7 +884,7 @@ def add_heat_dr( build_year=build_year, ) - n.madd( + n.add( "Link", df.index, suffix="-bck-dr-discharger", @@ -900,7 +900,7 @@ def add_heat_dr( # backward stores have positive marginal cost storage and postive e # forward stores have negative marginal cost storage and negative e - n.madd( + n.add( "Store", df.index, suffix="-bck-dr", @@ -917,7 +917,7 @@ def add_heat_dr( build_year=build_year, ) - n.madd( + n.add( "Store", df.index, suffix="-fwd-dr", @@ -1031,7 +1031,7 @@ def add_service_water_store( build_year = n.investment_periods[0] buses = df.copy().set_index("bus1") - n.madd( + n.add( "Bus", buses.index, x=buses.x, @@ -1042,7 +1042,7 @@ def add_service_water_store( # limitless one directional link from primary energy to water store if fuel == "elec": - n.madd( + n.add( "Link", df.index, suffix=f"-{fuel}-heater-charger", @@ -1057,7 +1057,7 @@ def add_service_water_store( build_year=build_year, ) else: # emission tracking - n.madd( + n.add( "Link", df.index, suffix=f"-{fuel}-heater-charger", @@ -1075,7 +1075,7 @@ def add_service_water_store( ) # limitless one directional link from water store to water demand - n.madd( + n.add( "Link", df.index, suffix=f"-{fuel}-heater-discharger", @@ -1090,7 +1090,7 @@ def add_service_water_store( ) # limitless water store. - n.madd( + n.add( "Store", df.index, suffix=f"-{fuel}-heater", @@ -1182,7 +1182,7 @@ def add_service_heat_pumps( build_year = n.investment_periods[0] # use suffix to retain COP profiles - n.madd( + n.add( "Link", hps.index, # suffix=suffix, @@ -1234,7 +1234,7 @@ def add_industrial_gas_furnace( else: mc = 0 - n.madd( + n.add( "Link", furnaces.index, suffix="-gas-furnace", # 'ind' included in index already @@ -1293,7 +1293,7 @@ def add_industrial_coal_furnace( else: mc = 0 - n.madd( + n.add( "Link", furnace.index, suffix="-coal-furnace", # 'ind' included in index already @@ -1335,7 +1335,7 @@ def add_indusrial_heat_pump( hp["carrier"] = f"{sector}-heat-pump" hp.index = hp.index.map(lambda x: x.split("-heat")[0]) - n.madd( + n.add( "Link", hp.index, suffix="-heat-pump", # 'ind' included in index already diff --git a/workflow/scripts/build_natural_gas.py b/workflow/scripts/build_natural_gas.py index 10cde0b04..88459e97c 100644 --- a/workflow/scripts/build_natural_gas.py +++ b/workflow/scripts/build_natural_gas.py @@ -238,7 +238,7 @@ def build_infrastructure(self, n: Network) -> None: states = df.set_index("STATE") - n.madd( + n.add( "Bus", names=states.index, suffix=" gas", @@ -334,7 +334,7 @@ def build_infrastructure(self, n: pypsa.Network, **kwargs): if "gas storage" not in n.carriers.index: n.add("Carrier", "gas storage", color="#d35050", nice_name="Gas Storage") - n.madd( + n.add( "Bus", names=df.index, suffix=" gas storage", @@ -345,7 +345,7 @@ def build_infrastructure(self, n: pypsa.Network, **kwargs): ) cyclic_storage = kwargs.get("cyclic_storage", True) - n.madd( + n.add( "Store", names=df.index, suffix=" gas storage", @@ -365,7 +365,7 @@ def build_infrastructure(self, n: pypsa.Network, **kwargs): # must do two links, rather than a bidirectional one, to constrain charge limits # Right now, chanrge limits are set at being able to drain the reservoir # over one full month - n.madd( + n.add( "Link", names=df.index, suffix=" charge gas storage", @@ -381,7 +381,7 @@ def build_infrastructure(self, n: pypsa.Network, **kwargs): build_year=n.investment_periods[0], ) - n.madd( + n.add( "Link", names=df.index, suffix=" discharge gas storage", @@ -467,7 +467,7 @@ def build_infrastructure(self, n: pypsa.Network, **kwargs): nice_name="Gas Production", ) - n.madd( + n.add( "Bus", names=df.index, suffix=" gas production", @@ -484,7 +484,7 @@ def build_infrastructure(self, n: pypsa.Network, **kwargs): # (63 CAD/ 1000 m3) (1 m3 / 35.5 CF) (1,000,000 CF / MMCF) (1 MMCF / 303.5 MWH) (1 USD / 0.75 CAD) # ~7.5 $/MWh - n.madd( + n.add( "Link", names=df.index, suffix=" gas production", @@ -503,7 +503,7 @@ def build_infrastructure(self, n: pypsa.Network, **kwargs): build_year=n.investment_periods[0], ) - n.madd( + n.add( "Store", names=df.index, unit="MWh", @@ -751,7 +751,7 @@ def build_infrastructure(self, n: pypsa.Network) -> None: df.index = df.STATE_FROM + " " + df.STATE_TO - n.madd( + n.add( "Link", names=df.index, suffix=" pipeline", @@ -1100,7 +1100,7 @@ def build_infrastructure(self, n: pypsa.Network, **kwargs) -> None: if "gas trade" not in n.carriers.index: n.add("Carrier", "gas trade", color="#d35050", nice_name="Gas Trade") - n.madd( + n.add( "Bus", names=template.index, suffix=" gas trade", @@ -1110,7 +1110,7 @@ def build_infrastructure(self, n: pypsa.Network, **kwargs) -> None: interconnect=self.interconnect, ) - n.madd( + n.add( "Link", names=template.index, suffix=" gas trade", @@ -1128,7 +1128,7 @@ def build_infrastructure(self, n: pypsa.Network, **kwargs) -> None: build_year=n.investment_periods[0], ) - n.madd( + n.add( "Store", names=store_exports.index, suffix=" gas trade", @@ -1149,7 +1149,7 @@ def build_infrastructure(self, n: pypsa.Network, **kwargs) -> None: build_year=n.investment_periods[0], ) - n.madd( + n.add( "Store", names=store_imports.index, unit="MWh", @@ -1282,7 +1282,7 @@ def build_infrastructure(self, n: pypsa.Network, **kwargs) -> None: cyclic_storage = kwargs.get("cyclic_storage", True) standing_loss = kwargs.get("standing_loss", 0) - n.madd( + n.add( "Store", names=df.index, unit="MWh_th", diff --git a/workflow/scripts/build_stock_data.py b/workflow/scripts/build_stock_data.py index c97bb6f07..9abf1eff3 100644 --- a/workflow/scripts/build_stock_data.py +++ b/workflow/scripts/build_stock_data.py @@ -808,7 +808,7 @@ def add_brownfield_ev( vehicles["p_nom"] = vehicles.p_nom.mul(percent).round(2) vehicles = vehicles.set_index("name") - n.madd( + n.add( "Link", vehicles.index, bus0=vehicles.bus0, @@ -904,7 +904,7 @@ def add_brownfield_lpg( vehicles["p_nom"] = vehicles.p_nom.mul(percent).round(2) vehicles = vehicles.set_index("name") - n.madd( + n.add( "Link", vehicles.index, bus0=vehicles.bus0, @@ -1028,7 +1028,7 @@ def add_brownfield_gas_furnace( furnaces["p_nom"] = furnaces.p_nom.mul(percent).div(100).round(2) furnaces = furnaces.set_index("name") - n.madd( + n.add( "Link", furnaces.index, bus0=furnaces.bus0, @@ -1092,7 +1092,7 @@ def add_brownfield_oil_furnace( furnaces["p_nom"] = furnaces.p_nom.mul(percent).div(100).round(2) furnaces = furnaces.set_index("name") - n.madd( + n.add( "Link", furnaces.index, bus0=furnaces.bus0, @@ -1151,7 +1151,7 @@ def add_brownfield_elec_furnace( furnaces["p_nom"] = furnaces.p_nom.mul(percent).div(100).round(2) furnaces = furnaces.set_index("name") - n.madd( + n.add( "Link", furnaces.index, bus0=furnaces.bus0, @@ -1216,7 +1216,7 @@ def add_brownfield_aircon( aircon["p_nom"] = aircon.p_nom.mul(percent).div(100).round(2) aircon = aircon.set_index("name") - n.madd( + n.add( "Link", aircon.index, bus0=aircon.bus0, @@ -1294,7 +1294,7 @@ def add_brownfield_water_heater_simple_storage( heater["p_nom"] = heater.p_nom.mul(percent).div(100).div(efficiency).round(2) heater = heater.set_index("name") - n.madd( + n.add( "Link", heater.index, suffix="-discharger", @@ -1373,7 +1373,7 @@ def add_brownfield_water_heater( heater["p_nom"] = heater.p_nom.mul(percent).div(100).round(2) heater = heater.set_index("name") - n.madd( + n.add( "Store", heater.index, bus=heater.bus, @@ -1500,7 +1500,7 @@ def add_brownfield_gas_furnace( furnaces["p_nom"] = furnaces.p_nom.mul(percent).div(100).round(2) furnaces = furnaces.set_index("name") - n.madd( + n.add( "Link", furnaces.index, bus0=furnaces.bus0, @@ -1563,7 +1563,7 @@ def add_brownfield_coal_furnace( furnaces["p_nom"] = furnaces.p_nom.mul(percent).div(100).round(2) furnaces = furnaces.set_index("name") - n.madd( + n.add( "Link", furnaces.index, bus0=furnaces.bus0, diff --git a/workflow/scripts/build_transportation.py b/workflow/scripts/build_transportation.py index 52e40a3f7..406226a83 100644 --- a/workflow/scripts/build_transportation.py +++ b/workflow/scripts/build_transportation.py @@ -78,7 +78,7 @@ def add_ev_infrastructure( """Adds bus that all EVs attach to at a node level.""" nodes = n.buses[n.buses.carrier == "AC"] - n.madd( + n.add( "Bus", nodes.index, suffix=f" trn-elec-{vehicle}", @@ -90,7 +90,7 @@ def add_ev_infrastructure( carrier=f"trn-elec-{vehicle}", ) - n.madd( + n.add( "Link", nodes.index, suffix=f" trn-elec-{vehicle}", @@ -113,7 +113,7 @@ def add_lpg_infrastructure( """Adds lpg connections for vehicle type.""" nodes = n.buses[n.buses.carrier == "AC"] - n.madd( + n.add( "Bus", nodes.index, suffix=f" trn-lpg-{vehicle}", @@ -134,7 +134,7 @@ def add_lpg_infrastructure( else: efficiency2 = 0 - n.madd( + n.add( "Link", nodes.index, suffix=f" trn-lpg-{vehicle}", @@ -171,7 +171,7 @@ def add_transport_dr(n: pypsa.Network, vehicle: str, dr_config: dict[str, Any]) # two buses for forward and backwards load shifting - n.madd( + n.add( "Bus", df.index, suffix="-fwd-dr", @@ -183,7 +183,7 @@ def add_transport_dr(n: pypsa.Network, vehicle: str, dr_config: dict[str, Any]) STATE_NAME=df.STATE_NAME, ) - n.madd( + n.add( "Bus", df.index, suffix="-bck-dr", @@ -197,7 +197,7 @@ def add_transport_dr(n: pypsa.Network, vehicle: str, dr_config: dict[str, Any]) # seperate charging/discharging links to follow conventions - n.madd( + n.add( "Link", df.index, suffix="-fwd-dr-charger", @@ -210,7 +210,7 @@ def add_transport_dr(n: pypsa.Network, vehicle: str, dr_config: dict[str, Any]) build_year=build_year, ) - n.madd( + n.add( "Link", df.index, suffix="-fwd-dr-discharger", @@ -223,7 +223,7 @@ def add_transport_dr(n: pypsa.Network, vehicle: str, dr_config: dict[str, Any]) build_year=build_year, ) - n.madd( + n.add( "Link", df.index, suffix="-bck-dr-charger", @@ -236,7 +236,7 @@ def add_transport_dr(n: pypsa.Network, vehicle: str, dr_config: dict[str, Any]) build_year=build_year, ) - n.madd( + n.add( "Link", df.index, suffix="-bck-dr-discharger", @@ -252,7 +252,7 @@ def add_transport_dr(n: pypsa.Network, vehicle: str, dr_config: dict[str, Any]) # backward stores have positive marginal cost storage and postive e # forward stores have negative marginal cost storage and negative e - n.madd( + n.add( "Store", df.index, suffix="-bck-dr", @@ -269,7 +269,7 @@ def add_transport_dr(n: pypsa.Network, vehicle: str, dr_config: dict[str, Any]) standing_loss=0, ) - n.madd( + n.add( "Store", df.index, suffix="-fwd-dr", @@ -343,7 +343,7 @@ def add_elec_vehicle( vehicles["bus1"] = vehicles.index + f" trn-{vehicle}-{mode}" vehicles["carrier"] = f"trn-elec-{vehicle}-{mode}" - n.madd( + n.add( "Link", vehicles.index, suffix=f" trn-elec-{vehicle}-{mode}", @@ -420,7 +420,7 @@ def add_lpg_vehicle( else: raise TypeError - n.madd( + n.add( "Link", vehicles.index, suffix=f" trn-lpg-{vehicle}-{mode}", @@ -466,7 +466,7 @@ def add_air( vehicles["bus1"] = vehicles.index + f" trn-{vehicle}-{mode}" vehicles["carrier"] = f"trn-lpg-{vehicle}-{mode}" - n.madd( + n.add( "Link", vehicles.index, suffix=f" trn-lpg-{vehicle}-{mode}", @@ -509,7 +509,7 @@ def add_boat( vehicles["bus1"] = vehicles.index + f" trn-{vehicle}-{mode}" vehicles["carrier"] = f"trn-lpg-{vehicle}-{mode}" - n.madd( + n.add( "Link", vehicles.index, suffix=f" trn-lpg-{vehicle}-{mode}", @@ -568,7 +568,7 @@ def add_rail( vehicles["bus1"] = vehicles.index + f" trn-{vehicle}-{mode}" vehicles["carrier"] = f"trn-lpg-{vehicle}-{mode}" - n.madd( + n.add( "Link", vehicles.index, suffix=f" trn-lpg-{vehicle}-{mode}", diff --git a/workflow/scripts/cluster_network.py b/workflow/scripts/cluster_network.py index 751b8ab30..d3ff8e598 100644 --- a/workflow/scripts/cluster_network.py +++ b/workflow/scripts/cluster_network.py @@ -268,13 +268,13 @@ def fix_country_assignment_for_hac(n): component = n.df(c) rm = component[component.bus.isin(buses_remove.index)] logger.warning(f"Removing {rm.shape} component {c}") - n.mremove(c, rm.index) + n.remove(c, rm.index) for c in ["Line", "Link"]: component = n.df(c) rm = component[component.bus0.isin(buses_remove.index) | component.bus1.isin(buses_remove.index)] logger.warning(f"Removing {rm.shape} component {c}") - n.mremove(c, rm.index) - n.mremove("Bus", buses_remove.index) + n.remove(c, rm.index) + n.remove("Bus", buses_remove.index) n.determine_network_topology() def busmap_for_country(x): @@ -392,7 +392,7 @@ def add_itls(buses, itls, itl_cost, expansion=True): itls["efficiency"] = 1 - ((itls.length_miles / 100) * 0.01) # The fwd and rev links will be made extendable in prepare_network, so no need to add AC_exp - clustering.network.madd( + clustering.network.add( "Link", names=itls.interface, # itl name suffix="_fwd", @@ -411,7 +411,7 @@ def add_itls(buses, itls, itl_cost, expansion=True): carrier="AC", ) - clustering.network.madd( + clustering.network.add( "Link", names=itls.interface, # itl name suffix="_rev", @@ -444,7 +444,7 @@ def convert_to_transport( Replaces all Lines according to Links with the transfer capacity specified by the ITLs. """ - clustering.network.mremove("Line", clustering.network.lines.index) + clustering.network.remove("Line", clustering.network.lines.index) buses = clustering.network.buses.copy() itls = pd.read_csv(itl_fn) @@ -523,7 +523,7 @@ def convert_to_transport( buses_p20 = clustering.network.buses[clustering.network.buses.reeds_zone == "p20"] existing_links = clustering.network.links[clustering.network.links.bus0.isin(buses_p19.index)] if existing_links.empty: - clustering.network.madd( + clustering.network.add( "Link", names=["p19_to_p20"], bus0=buses_p19.iloc[0].name, @@ -738,7 +738,7 @@ def calibrate_tamu_transmission_capacity( # Remove lines not in REEDS data if lines_not_in_reeds: - clustering.network.mremove("Line", lines_not_in_reeds) + clustering.network.remove("Line", lines_not_in_reeds) logger.info( f"REEDS capacity corrections completed: {lines_updated} lines updated with REEDS data, " @@ -849,7 +849,7 @@ def calibrate_tamu_transmission_capacity( # Batch add all new lines using madd if new_lines_data: new_lines_df = pd.DataFrame(new_lines_data) - clustering.network.madd( + clustering.network.add( "Line", names=new_lines_df["name"], bus0=new_lines_df["bus0"].values, diff --git a/workflow/scripts/opts/policy.py b/workflow/scripts/opts/policy.py index 420ec7959..86028acc8 100644 --- a/workflow/scripts/opts/policy.py +++ b/workflow/scripts/opts/policy.py @@ -10,7 +10,7 @@ get_model_horizon, get_region_buses, ) -from pypsa.descriptors import get_switchable_as_dense as get_as_dense +from pypsa.definitions.structures import get_switchable_as_dense as get_as_dense logger = logging.getLogger(__name__) diff --git a/workflow/scripts/opts/reserves.py b/workflow/scripts/opts/reserves.py index 89d5ca958..1a4f9b802 100644 --- a/workflow/scripts/opts/reserves.py +++ b/workflow/scripts/opts/reserves.py @@ -13,13 +13,13 @@ import pypsa from linopy import merge from opts._helpers import get_region_buses -from pypsa.descriptors import ( +from pypsa.definitions.structures import ( expand_series, get_activity_mask, get_bounds_pu, nominal_attrs, ) -from pypsa.descriptors import ( +from pypsa.definitions.structures import ( get_switchable_as_dense as get_as_dense, ) from pypsa.optimization.common import reindex diff --git a/workflow/scripts/plot_sankey_energy.py b/workflow/scripts/plot_sankey_energy.py index 59f9128ad..f574e107a 100644 --- a/workflow/scripts/plot_sankey_energy.py +++ b/workflow/scripts/plot_sankey_energy.py @@ -13,7 +13,7 @@ from _helpers import configure_logging, mock_snakemake from constants import ATB_TECH_MAPPER, TBTU_2_MWH from constants_sector import TransportEfficiency -from pypsa.descriptors import get_switchable_as_dense +from pypsa.definitions.structures import get_switchable_as_dense from summary_sector import _get_gens_in_state, _get_links_in_state # These are node colors! Energy Services and Rejected Energy links do not diff --git a/workflow/scripts/simplify_network.py b/workflow/scripts/simplify_network.py index 44543a0eb..9ee946e05 100644 --- a/workflow/scripts/simplify_network.py +++ b/workflow/scripts/simplify_network.py @@ -80,8 +80,8 @@ def remove_transformers(n): if col.startswith("bus"): df[col] = df[col].map(trafo_map) - n.mremove("Transformer", n.transformers.index) - n.mremove("Bus", n.buses.index.difference(trafo_map)) + n.remove("Transformer", n.transformers.index) + n.remove("Bus", n.buses.index.difference(trafo_map)) return n, trafo_map diff --git a/workflow/scripts/solve_network.py b/workflow/scripts/solve_network.py index b9e444568..fad468071 100644 --- a/workflow/scripts/solve_network.py +++ b/workflow/scripts/solve_network.py @@ -93,7 +93,7 @@ def prepare_network(n, solve_opts=None): # TODO: do not scale via sign attribute (use Eur/MWh instead of Eur/kWh) load_shedding = 1e2 # Eur/kWh - n.madd( + n.add( "Generator", buses_i, " load", @@ -288,7 +288,7 @@ def prepare_brownfield(n, planning_horizon): for df_idx in df.index: if nm == "Generator": - n.madd( + n.add( nm, [df_idx], carrier=df.loc[df_idx].carrier, diff --git a/workflow/scripts/test/test_reserves.py b/workflow/scripts/test/test_reserves.py index d058514c3..9d7054d09 100644 --- a/workflow/scripts/test/test_reserves.py +++ b/workflow/scripts/test/test_reserves.py @@ -10,10 +10,10 @@ import numpy as np import pandas as pd import pytest -from pypsa.descriptors import ( +from pypsa.definitions.structures import ( get_activity_mask, ) -from pypsa.descriptors import ( +from pypsa.definitions.structures import ( get_switchable_as_dense as get_as_dense, ) From 11b8ab9b990dca8fa2414e5a67dfa3f30b00bfe0 Mon Sep 17 00:00:00 2001 From: apigott Date: Thu, 11 Jun 2026 06:45:51 -0600 Subject: [PATCH 02/12] update pypsa --- workflow/envs/environment.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/workflow/envs/environment.yaml b/workflow/envs/environment.yaml index bac128657..138663511 100644 --- a/workflow/envs/environment.yaml +++ b/workflow/envs/environment.yaml @@ -7,9 +7,9 @@ dependencies: - python==3.11.9 - pip -- pypsa==0.30.2 +- pypsa>=0.35.2 - atlite==0.3.0 -- linopy==0.3.14 +- linopy>=0.6.1 # Dependencies of the workflow itself - pandas==2.2.2 From f6c76f6d4fc9b5814b1e461b1e37a70ac8ee3898 Mon Sep 17 00:00:00 2001 From: apigott Date: Thu, 11 Jun 2026 06:46:04 -0600 Subject: [PATCH 03/12] update breaking function calls --- workflow/scripts/_helpers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/workflow/scripts/_helpers.py b/workflow/scripts/_helpers.py index 2b59a855f..8f5bae163 100644 --- a/workflow/scripts/_helpers.py +++ b/workflow/scripts/_helpers.py @@ -103,7 +103,7 @@ def load_network(import_name=None, custom_components=None): ------- pypsa.Network """ - from pypsa.descriptors import Dict + from pypsa.definitions.structures import Dict override_components = None override_component_attrs = None @@ -373,7 +373,7 @@ def mock_snakemake(rulename, **wildcards): import snakemake as sm from packaging.version import Version, parse - from pypsa.descriptors import Dict + from pypsa.definitions.structures import Dict from snakemake.script import Snakemake script_dir = Path(__file__).parent.resolve() From dcc8e9d032d1045b4935ab5e86a8345d15e729d8 Mon Sep 17 00:00:00 2001 From: apigott Date: Thu, 11 Jun 2026 06:47:01 -0600 Subject: [PATCH 04/12] default add config.default.yaml --- workflow/Snakefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/workflow/Snakefile b/workflow/Snakefile index 770fc678c..93bdc5378 100644 --- a/workflow/Snakefile +++ b/workflow/Snakefile @@ -87,9 +87,7 @@ configfile: "config/config.common.yaml" configfile: "config/config.plotting.yaml" configfile: "config/config.api.yaml" configfile: "config/config.sector.yaml" - - -# configfile: "config/config.default.yaml" +configfile: "config/config.default.yaml" run = config.get("run", {}) From 3a55cc9b406a09a1ff498acafcee55aa94cf9ec9 Mon Sep 17 00:00:00 2001 From: apigott Date: Thu, 11 Jun 2026 10:18:34 -0600 Subject: [PATCH 05/12] add level assignment based on pypsa version --- workflow/scripts/_helpers.py | 2 ++ workflow/scripts/add_electricity.py | 12 ++++++++---- workflow/scripts/build_base_network.py | 19 ++++++++++++------- workflow/scripts/build_bus_regions.py | 12 ++++++++---- 4 files changed, 30 insertions(+), 15 deletions(-) diff --git a/workflow/scripts/_helpers.py b/workflow/scripts/_helpers.py index 8f5bae163..7389d6dd1 100644 --- a/workflow/scripts/_helpers.py +++ b/workflow/scripts/_helpers.py @@ -16,6 +16,8 @@ REGION_COLS = ["geometry", "name", "x", "y", "country"] +PYPSA_V1 = bool(re.match(r"^1\.\d", pypsa.__version__)) + def configure_logging(snakemake, skip_handlers=False): """ diff --git a/workflow/scripts/add_electricity.py b/workflow/scripts/add_electricity.py index 6a288eb0f..5e76df195 100755 --- a/workflow/scripts/add_electricity.py +++ b/workflow/scripts/add_electricity.py @@ -21,6 +21,7 @@ export_network_for_gis_mapping, update_p_nom_max, weighted_avg, + PYPSA_V1 ) from sklearn.neighbors import BallTree @@ -265,7 +266,8 @@ def match_nearest_bus(plants_subset, buses_subset): ) # Map the nearest bus information back to the plants subset - plants_subset["bus_assignment"] = buses_subset.reset_index().iloc[indices.flatten()]["Bus"].values + level = "name" if PYPSA_V1 else "Bus" + plants_subset["bus_assignment"] = buses_subset.reset_index().iloc[indices.flatten()][level].values plants_subset["distance_nearest"] = distances.flatten() return plants_subset @@ -467,7 +469,7 @@ def attach_conventional_generators( plants["efficiency"] = plants.efficiency.astype(float).fillna(plants.efficiency_r) committable_fields = ["start_up_cost", "min_down_time", "min_up_time"] - defaults = pypsa.components.component_attrs["Generator"].default + defaults = pypsa.components["Generator"].default if unit_commitment: for attr in committable_fields: plants[attr] = plants[attr].astype(float).fillna(defaults[attr]) @@ -539,6 +541,7 @@ def attach_wind_and_solar( config.get("renewable", {}).get("dataset") == "godeeep" and config["renewable_scenarios"][0] != "historical" ) + level = "name" if PYPSA_V1 else "Bus" for car in carriers: if car in ["hydro", "EGS"]: continue @@ -548,7 +551,7 @@ def attach_wind_and_solar( bus2sub = ( pd.read_csv(input_profiles.bus2sub, dtype=str) .drop("interconnect", axis=1) - .rename(columns={"Bus": "bus_id"}) + .rename(columns={level: "bus_id"}) .drop_duplicates(subset="sub_id") ) @@ -694,6 +697,7 @@ def attach_egs( discount_rate = 0.07 # load_costs(snakemake.input.tech_costs).loc["geothermal", "wacc_real"] drilling_cost = snakemake.config["renewable"]["EGS"]["drilling_cost"] + level = "name" if PYPSA_V1 else "Bus" with ( xr.open_dataset( getattr(input_profiles, "specs_egs"), @@ -705,7 +709,7 @@ def attach_egs( bus2sub = ( pd.read_csv(input_profiles.bus2sub, dtype=str) .drop("interconnect", axis=1) - .rename(columns={"Bus": "bus_id"}) + .rename(columns={level: "bus_id"}) ) # IGNORE: Remove dropna(). Rather, apply dropna when creating the original dataset diff --git a/workflow/scripts/build_base_network.py b/workflow/scripts/build_base_network.py index ad85859ba..2475c7b7f 100644 --- a/workflow/scripts/build_base_network.py +++ b/workflow/scripts/build_base_network.py @@ -7,12 +7,16 @@ import numpy as np import pandas as pd import pypsa -from _helpers import configure_logging +from _helpers import ( + configure_logging, + PYPSA_V1 +) from build_shapes import load_na_shapes from constants import REC_TRADING_ZONE_MAPPER from shapely.geometry import Polygon from sklearn.neighbors import BallTree +LEVEL = "name" if PYPSA_V1 else "name" def haversine_np(lon1, lat1, lon2, lat2): """ @@ -358,7 +362,6 @@ def match_missing_buses(buses_to_match_to, missing_buses): ) foo = buses_to_match_to.reset_index().iloc[missing_buses.id_nearest]#.name.values - breakpoint() missing_buses["bus_assignment"] = foo.name.values missing_buses = missing_buses.drop(columns=["id_nearest"]) return missing_buses @@ -384,7 +387,7 @@ def assign_missing_state_regions(gdf_bus: gpd.GeoDataFrame): value. """ buses = gdf_bus.copy() - buses = buses.reset_index().rename(columns={"bus_id": "Bus", "lon": "x", "lat": "y"}).set_index("Bus") + buses = buses.reset_index().rename(columns={"bus_id": LEVEL, "lon": "x", "lat": "y"}).set_index(LEVEL) missing = buses.loc[buses.full_state.isna()] if missing.empty: @@ -394,13 +397,13 @@ def assign_missing_state_regions(gdf_bus: gpd.GeoDataFrame): missing = match_missing_buses(buses, missing) # check if error western / texas. can make this a function - missing = missing.reset_index().drop_duplicates("Bus").set_index("Bus") - buses = buses.reset_index().drop_duplicates("Bus").set_index("Bus") + missing = missing.reset_index().drop_duplicates(LEVEL).set_index(LEVEL) + buses = buses.reset_index().drop_duplicates(LEVEL).set_index(LEVEL) missing.full_state = buses.loc[missing.bus_assignment.values].full_state.values - buses = buses.reset_index().rename(columns={"Bus": "bus_id", "x": "lon", "y": "lat"}).set_index("bus_id") - missing = missing.reset_index().rename(columns={"Bus": "bus_id", "x": "lon", "y": "lat"}).set_index("bus_id") + buses = buses.reset_index().rename(columns={LEVEL: "bus_id", "x": "lon", "y": "lat"}).set_index("bus_id") + missing = missing.reset_index().rename(columns={LEVEL: "bus_id", "x": "lon", "y": "lat"}).set_index("bus_id") # reassigning values to original dataframe gdf_bus.loc[missing.index, "full_state"] = missing.full_state @@ -550,6 +553,7 @@ def main(snakemake): gdf_bus = map_bus_to_region(gdf_bus, county_shape, ["county"]) # assign load allocation factors to buses for state level dissagregation + breakpoint() gdf_bus = assign_missing_state_regions(gdf_bus) # if dissagregating based with breakthrough energy on states, the LAF must @@ -571,6 +575,7 @@ def main(snakemake): if interconnect == "Texas" or interconnect == "usa": n = assign_texas_poi(n) n = remove_breakthrough_offshore(n) + breakpoint() assign_missing_regions(n) # build offshore network configuration diff --git a/workflow/scripts/build_bus_regions.py b/workflow/scripts/build_bus_regions.py index 49c6ecbab..7ff5c6d28 100644 --- a/workflow/scripts/build_bus_regions.py +++ b/workflow/scripts/build_bus_regions.py @@ -7,12 +7,15 @@ import numpy as np import pandas as pd import pypsa -from _helpers import REGION_COLS, configure_logging +from _helpers import ( + REGION_COLS, + configure_logging, + PYPSA_V1 +) from scipy.spatial import Voronoi from shapely.geometry import Polygon from sklearn.neighbors import BallTree - def voronoi_partition_pts(points, outline): """ Compute the polygons of a voronoi partition of `points` within the @@ -96,13 +99,14 @@ def main(snakemake): all_locs = bus2sub[["x", "y"]] onshore_buses = n.buses[~n.buses.substation_off] + level= "name" if PYPSA_V1 else "Bus" bus2sub = pd.merge( bus2sub.reset_index(), n.buses[["reeds_zone", "reeds_ba"]], - left_on="Bus", + left_on=level, right_on=n.buses.index, ).set_index("sub_id") - bus2sub_onshore = bus2sub[bus2sub.Bus.isin(onshore_buses.index)] + bus2sub_onshore = bus2sub[bus2sub[level].isin(onshore_buses.index)] logger.info("Building Onshore Regions") onshore_regions = [] From af5f5545d17c761118469bec77b839bf42864bd6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 16:20:54 +0000 Subject: [PATCH 06/12] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- workflow/scripts/add_electricity.py | 2 +- workflow/scripts/build_base_network.py | 7 ++++--- workflow/scripts/build_bus_regions.py | 7 ++++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/workflow/scripts/add_electricity.py b/workflow/scripts/add_electricity.py index 5e76df195..c66ad44f6 100755 --- a/workflow/scripts/add_electricity.py +++ b/workflow/scripts/add_electricity.py @@ -16,12 +16,12 @@ import pypsa import xarray as xr from _helpers import ( + PYPSA_V1, calculate_annuity, configure_logging, export_network_for_gis_mapping, update_p_nom_max, weighted_avg, - PYPSA_V1 ) from sklearn.neighbors import BallTree diff --git a/workflow/scripts/build_base_network.py b/workflow/scripts/build_base_network.py index 2475c7b7f..926555e9b 100644 --- a/workflow/scripts/build_base_network.py +++ b/workflow/scripts/build_base_network.py @@ -8,8 +8,8 @@ import pandas as pd import pypsa from _helpers import ( + PYPSA_V1, configure_logging, - PYPSA_V1 ) from build_shapes import load_na_shapes from constants import REC_TRADING_ZONE_MAPPER @@ -18,6 +18,7 @@ LEVEL = "name" if PYPSA_V1 else "name" + def haversine_np(lon1, lat1, lon2, lat2): """ Calculate the great circle distance between two points on the earth @@ -360,8 +361,8 @@ def match_missing_buses(buses_to_match_to, missing_buses): missing_buses[["x", "y"]].values, # The input array for the query k=1, # The number of nearest neighbors ) - - foo = buses_to_match_to.reset_index().iloc[missing_buses.id_nearest]#.name.values + + foo = buses_to_match_to.reset_index().iloc[missing_buses.id_nearest] # .name.values missing_buses["bus_assignment"] = foo.name.values missing_buses = missing_buses.drop(columns=["id_nearest"]) return missing_buses diff --git a/workflow/scripts/build_bus_regions.py b/workflow/scripts/build_bus_regions.py index 7ff5c6d28..ef5752219 100644 --- a/workflow/scripts/build_bus_regions.py +++ b/workflow/scripts/build_bus_regions.py @@ -8,14 +8,15 @@ import pandas as pd import pypsa from _helpers import ( - REGION_COLS, + PYPSA_V1, + REGION_COLS, configure_logging, - PYPSA_V1 ) from scipy.spatial import Voronoi from shapely.geometry import Polygon from sklearn.neighbors import BallTree + def voronoi_partition_pts(points, outline): """ Compute the polygons of a voronoi partition of `points` within the @@ -99,7 +100,7 @@ def main(snakemake): all_locs = bus2sub[["x", "y"]] onshore_buses = n.buses[~n.buses.substation_off] - level= "name" if PYPSA_V1 else "Bus" + level = "name" if PYPSA_V1 else "Bus" bus2sub = pd.merge( bus2sub.reset_index(), n.buses[["reeds_zone", "reeds_ba"]], From 24e3f024cda169281c9cc046553e5aa47f5dbcda Mon Sep 17 00:00:00 2001 From: apigott Date: Thu, 11 Jun 2026 11:10:46 -0600 Subject: [PATCH 07/12] remove explicit add of default params -- isn't this already covered? --- workflow/scripts/add_electricity.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/workflow/scripts/add_electricity.py b/workflow/scripts/add_electricity.py index c66ad44f6..a84937587 100755 --- a/workflow/scripts/add_electricity.py +++ b/workflow/scripts/add_electricity.py @@ -469,10 +469,10 @@ def attach_conventional_generators( plants["efficiency"] = plants.efficiency.astype(float).fillna(plants.efficiency_r) committable_fields = ["start_up_cost", "min_down_time", "min_up_time"] - defaults = pypsa.components["Generator"].default + # defaults = pypsa.components.component_attrs["Generator"].default if unit_commitment: - for attr in committable_fields: - plants[attr] = plants[attr].astype(float).fillna(defaults[attr]) + # for attr in committable_fields: + # plants[attr] = plants[attr].astype(float).fillna(defaults[attr]) plants["p_min_pu"] = ( (plants.minimum_load_mw / plants.p_nom) .clip( @@ -483,9 +483,9 @@ def attach_conventional_generators( .fillna(0) .mul(0.95) ) - else: - for attr in committable_fields: - plants[attr] = defaults[attr] + # else: + # for attr in committable_fields: + # plants[attr] = defaults[attr] committable_attrs = {attr: plants[attr] for attr in committable_fields} # Define generators using modified ppl DataFrame From a6a4d217e8017c0fedcec7af204673292df4a794 Mon Sep 17 00:00:00 2001 From: apigott Date: Thu, 11 Jun 2026 11:50:20 -0600 Subject: [PATCH 08/12] update network import --- workflow/scripts/build_natural_gas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow/scripts/build_natural_gas.py b/workflow/scripts/build_natural_gas.py index 88459e97c..56774e3db 100644 --- a/workflow/scripts/build_natural_gas.py +++ b/workflow/scripts/build_natural_gas.py @@ -25,7 +25,7 @@ import pypsa import yaml from constants import CODE_2_STATE, EMPTY_STATES, NG_MWH_2_MMCF, STATE_2_CODE, STATES_INTERCONNECT_MAPPER -from pypsa.components import Network +from pypsa import Network logger = logging.getLogger(__name__) From ca51f32304391e901bbd2a2c185a8d9569a07903 Mon Sep 17 00:00:00 2001 From: apigott Date: Thu, 11 Jun 2026 11:51:17 -0600 Subject: [PATCH 09/12] update get_switchable_as_dense call --- workflow/scripts/add_extra_components.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/workflow/scripts/add_extra_components.py b/workflow/scripts/add_extra_components.py index be9dd23c7..1964bf6a4 100644 --- a/workflow/scripts/add_extra_components.py +++ b/workflow/scripts/add_extra_components.py @@ -10,7 +10,6 @@ from add_electricity import add_missing_carriers from eia import FuelCosts from opts._helpers import get_region_buses -from pypsa.definitions.structures import get_switchable_as_dense as get_as_dense from shapely.geometry import Point idx = pd.IndexSlice @@ -828,7 +827,7 @@ def trim_network(n, trim_topology): # Get OCGT generators and calculate average marginal cost ocgt_gens = n.generators[n.generators.carrier == "OCGT"] - avg_marginal_cost = get_as_dense(n, "Generator", "marginal_cost").loc[:, ocgt_gens.index].mean().mean() + avg_marginal_cost = n.get_switchable_as_dense("Generator", "marginal_cost").loc[:, ocgt_gens.index].mean().mean() n.add("Carrier", "imports", co2_emissions=0.428, nice_name="imports") # remove existing oneport components at bus @@ -893,7 +892,7 @@ def calc_import_export_costs(n: pypsa.Network, carrier: str) -> float: component = "Link" if gens.empty: raise ValueError(f"No generators or links found for carrier to calculate imports/exports costs: {carrier}") - costs = get_as_dense(n, component, "marginal_cost").loc[:, gens.index].mean().mean() + costs = n.get_switchable_as_dense(component, "marginal_cost").loc[:, gens.index].mean().mean() if costs <= 0.01: raise ValueError( f"Average marginal cost for {carrier} is less than or equal to 0.01. Check the fuel costs configuration.", From 0ec46d390f7b12b900e3bde7d73703301a5151a1 Mon Sep 17 00:00:00 2001 From: apigott Date: Thu, 11 Jun 2026 11:51:45 -0600 Subject: [PATCH 10/12] update network copy call --- workflow/scripts/cluster_network.py | 84 ++++++++++++++--------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/workflow/scripts/cluster_network.py b/workflow/scripts/cluster_network.py index d3ff8e598..e332419db 100644 --- a/workflow/scripts/cluster_network.py +++ b/workflow/scripts/cluster_network.py @@ -392,9 +392,9 @@ def add_itls(buses, itls, itl_cost, expansion=True): itls["efficiency"] = 1 - ((itls.length_miles / 100) * 0.01) # The fwd and rev links will be made extendable in prepare_network, so no need to add AC_exp - clustering.network.add( + clustering.n.add( "Link", - names=itls.interface, # itl name + name=itls.interface, # itl name suffix="_fwd", bus0=buses.loc[itls.r].index, bus1=buses.loc[itls.rr].index, @@ -411,9 +411,9 @@ def add_itls(buses, itls, itl_cost, expansion=True): carrier="AC", ) - clustering.network.add( + clustering.n.add( "Link", - names=itls.interface, # itl name + name=itls.interface, # itl name suffix="_rev", bus0=buses.loc[itls.rr].index, bus1=buses.loc[itls.r].index, @@ -444,20 +444,20 @@ def convert_to_transport( Replaces all Lines according to Links with the transfer capacity specified by the ITLs. """ - clustering.network.remove("Line", clustering.network.lines.index) - buses = clustering.network.buses.copy() + clustering.n.remove("Line", clustering.n.lines.index) + buses = clustering.n.buses.copy() itls = pd.read_csv(itl_fn) itl_cost = pd.read_csv(itl_cost_fn) itls.columns = itls.columns.str.lower() if topological_boundaries == "state": # use reeds_state - abbreviations itls_filt = itls[ - itls.r.isin(clustering.network.buses["reeds_state"]) & itls.rr.isin(clustering.network.buses["reeds_state"]) + itls.r.isin(clustering.n.buses["reeds_state"]) & itls.rr.isin(clustering.n.buses["reeds_state"]) ] else: itls_filt = itls[ - itls.r.isin(clustering.network.buses[f"{topological_boundaries}"]) - & itls.rr.isin(clustering.network.buses[f"{topological_boundaries}"]) + itls.r.isin(clustering.n.buses[f"{topological_boundaries}"]) + & itls.rr.isin(clustering.n.buses[f"{topological_boundaries}"]) ] add_itls(buses, itls_filt, itl_cost) @@ -510,20 +510,20 @@ def convert_to_transport( else: itls = itls_filt - clustering.network.add("Carrier", "AC_exp", co2_emissions=0) + clustering.n.add("Carrier", "AC_exp", co2_emissions=0) # If bus 'p19' is in the network, add a link from it to 'p20' # reeds dataset is missing link to and from this zone if ( topological_boundaries == "reeds_zone" - and "p19" in clustering.network.buses.reeds_zone.unique() - and "p20" in clustering.network.buses.reeds_zone.unique() + and "p19" in clustering.n.buses.reeds_zone.unique() + and "p20" in clustering.n.buses.reeds_zone.unique() ): - buses_p19 = clustering.network.buses[clustering.network.buses.reeds_zone == "p19"] - buses_p20 = clustering.network.buses[clustering.network.buses.reeds_zone == "p20"] - existing_links = clustering.network.links[clustering.network.links.bus0.isin(buses_p19.index)] + buses_p19 = clustering.n.buses[clustering.n.buses.reeds_zone == "p19"] + buses_p20 = clustering.n.buses[clustering.n.buses.reeds_zone == "p20"] + existing_links = clustering.n.links[clustering.n.links.bus0.isin(buses_p19.index)] if existing_links.empty: - clustering.network.add( + clustering.n.add( "Link", names=["p19_to_p20"], bus0=buses_p19.iloc[0].name, @@ -537,7 +537,7 @@ def convert_to_transport( # Remove any disconnected buses unique_buses = buses.loc[itls.r].index.union(buses.loc[itls.rr].index).unique() - disconnected_buses = clustering.network.buses.index[~clustering.network.buses.index.isin(unique_buses)] + disconnected_buses = clustering.n.buses.index[~clustering.n.buses.index.isin(unique_buses)] if len(disconnected_buses) > 0: logger.warning( @@ -644,13 +644,13 @@ def calibrate_tamu_transmission_capacity( matched_reeds_interfaces = set() # Get lines from the network - lines = clustering.network.lines.copy() + lines = clustering.n.lines.copy() lines_not_in_reeds = [] lines_updated = 0 # Build region to bus mapping for later adding missing lines region_to_bus = {} - for bus_id, bus in clustering.network.buses.iterrows(): + for bus_id, bus in clustering.n.buses.iterrows(): if use_original_region: region_field = f"original_{topological_boundaries}" if region_field in bus.index: @@ -675,8 +675,8 @@ def calibrate_tamu_transmission_capacity( # Update existing lines for line_idx in lines.index: line = lines.loc[line_idx] - bus0 = clustering.network.buses.loc[line.bus0] - bus1 = clustering.network.buses.loc[line.bus1] + bus0 = clustering.n.buses.loc[line.bus0] + bus1 = clustering.n.buses.loc[line.bus1] # Determine which field to use for region identification if use_original_region: @@ -716,20 +716,20 @@ def calibrate_tamu_transmission_capacity( capacity_ratio = new_s_nom / old_s_nom # Update s_nom - clustering.network.lines.loc[line_idx, "s_nom"] = new_s_nom + clustering.n.lines.loc[line_idx, "s_nom"] = new_s_nom # Update electrical parameters based on power system principles if capacity_ratio != 1.0: # r (resistance) and x (reactance) are inversely proportional to capacity # (capacity increase through increased conductor cross-section) if line["r"] > 0: - clustering.network.lines.loc[line_idx, "r"] = line["r"] / capacity_ratio + clustering.n.lines.loc[line_idx, "r"] = line["r"] / capacity_ratio if line["x"] > 0: - clustering.network.lines.loc[line_idx, "x"] = line["x"] / capacity_ratio + clustering.n.lines.loc[line_idx, "x"] = line["x"] / capacity_ratio # b (susceptance) and g (conductance) are proportional to capacity - clustering.network.lines.loc[line_idx, "b"] = line["b"] * capacity_ratio - clustering.network.lines.loc[line_idx, "g"] = line["g"] * capacity_ratio + clustering.n.lines.loc[line_idx, "b"] = line["b"] * capacity_ratio + clustering.n.lines.loc[line_idx, "g"] = line["g"] * capacity_ratio lines_updated += 1 else: @@ -738,7 +738,7 @@ def calibrate_tamu_transmission_capacity( # Remove lines not in REEDS data if lines_not_in_reeds: - clustering.network.remove("Line", lines_not_in_reeds) + clustering.n.remove("Line", lines_not_in_reeds) logger.info( f"REEDS capacity corrections completed: {lines_updated} lines updated with REEDS data, " @@ -747,7 +747,7 @@ def calibrate_tamu_transmission_capacity( # Calculate average line parameters per unit length and capacity from existing lines # These will be used to estimate parameters for new lines - existing_lines = clustering.network.lines + existing_lines = clustering.n.lines # Calculate per-unit parameters: parameter / (length * s_nom) # For r and x: Ohm = (Ohm*km*MW) / (km * MW) avg_r_per_length_capacity = (existing_lines["r"] / existing_lines["length"] * existing_lines["s_nom"]).mean() @@ -784,8 +784,8 @@ def calibrate_tamu_transmission_capacity( bus0_id = region_to_bus[region0][0] bus1_id = region_to_bus[region1][0] - bus0 = clustering.network.buses.loc[bus0_id] - bus1 = clustering.network.buses.loc[bus1_id] + bus0 = clustering.n.buses.loc[bus0_id] + bus1 = clustering.n.buses.loc[bus1_id] # Calculate distance using PyPSA's haversine function bus0_coords = pd.DataFrame([[bus0["x"], bus0["y"]]], columns=["x", "y"]) @@ -849,7 +849,7 @@ def calibrate_tamu_transmission_capacity( # Batch add all new lines using madd if new_lines_data: new_lines_df = pd.DataFrame(new_lines_data) - clustering.network.add( + clustering.n.add( "Line", names=new_lines_df["name"], bus0=new_lines_df["bus0"].values, @@ -1072,7 +1072,7 @@ def calibrate_tamu_transmission_capacity( # add interconnect information back to clustered network if topological_boundaries == "state": - clustering.network.buses["interconnect"] = clustering.network.buses["reeds_state"].map( + clustering.n.buses["interconnect"] = clustering.n.buses["reeds_state"].map( STATES_INTERCONNECT_MAPPER, ) @@ -1089,7 +1089,7 @@ def calibrate_tamu_transmission_capacity( ) else: # Use standard transmission cost estimates - update_transmission_costs(clustering.network, costs) + update_transmission_costs(clustering.n, costs) if not transport_model: # Apply REEDS transmission capacity corrections @@ -1114,8 +1114,8 @@ def calibrate_tamu_transmission_capacity( # Check if topology_aggregation was used (original region info saved) use_original_region = False - if hasattr(clustering.network.buses, "columns"): - use_original_region = f"original_{topological_boundaries}" in clustering.network.buses.columns + if hasattr(clustering.n.buses, "columns"): + use_original_region = f"original_{topological_boundaries}" in clustering.n.buses.columns # Apply corrections calibrate_tamu_transmission_capacity( @@ -1128,26 +1128,26 @@ def calibrate_tamu_transmission_capacity( use_original_region=use_original_region, ) - update_p_nom_max(clustering.network) - clustering.network.generators.land_region = clustering.network.generators.land_region.fillna( - clustering.network.generators.bus, + update_p_nom_max(clustering.n) + clustering.n.generators.land_region = clustering.n.generators.land_region.fillna( + clustering.n.generators.bus, ) if params.cluster_network.get("consider_efficiency_classes"): labels = [f" {label} efficiency" for label in ["low", "medium", "high"]] - nc = clustering.network + nc = clustering.n nc.generators["carrier"] = nc.generators.carrier.replace(labels, "", regex=True) - clustering.network.meta = dict( + clustering.n.meta = dict( snakemake.config, **dict(wildcards=dict(snakemake.wildcards)), ) - clustering.network.set_investment_periods( + clustering.n.set_investment_periods( periods=snakemake.params.planning_horizons, ) - clustering.network.export_to_netcdf(snakemake.output.network) + clustering.n.export_to_netcdf(snakemake.output.network) for attr in ( "busmap", From 96b40fce3857cf7ba80e92645e5c82d675cd2f8f Mon Sep 17 00:00:00 2001 From: apigott Date: Thu, 11 Jun 2026 11:52:29 -0600 Subject: [PATCH 11/12] update network copy call --- workflow/scripts/prepare_network.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow/scripts/prepare_network.py b/workflow/scripts/prepare_network.py index a097d9bba..074de8e07 100644 --- a/workflow/scripts/prepare_network.py +++ b/workflow/scripts/prepare_network.py @@ -144,7 +144,7 @@ def set_transmission_limit(n, ll_type, factor): def average_every_nhours(n, offset): logger.info(f"Resampling the network to {offset}") - m = n.copy(with_time=False) + m = n.copy(snapshots=None) def resample_multi_index(df, offset, func): sw = [] From 849ce4690572fe52d68627d85ecc69c69b5a2bfb Mon Sep 17 00:00:00 2001 From: apigott Date: Thu, 11 Jun 2026 11:53:04 -0600 Subject: [PATCH 12/12] clustering.network -> clustering.n --- workflow/scripts/simplify_network.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/workflow/scripts/simplify_network.py b/workflow/scripts/simplify_network.py index 9ee946e05..a2927997a 100644 --- a/workflow/scripts/simplify_network.py +++ b/workflow/scripts/simplify_network.py @@ -140,7 +140,7 @@ def aggregate_to_substations( "zonal_aggregation must be either balancing_area, country, or state", ) - network_s = clustering.network + network_s = clustering.n network_s.buses["interconnect"] = substations.interconnect network_s.buses["x"] = substations.x @@ -295,7 +295,7 @@ def assign_line_lengths(n, line_length_factor): aggregation_strategies=params.aggregation_strategies, weighting_strategy=params.simplify_network.get("weighting_strategy", None), ) - n = clustering.network + n = clustering.n cluster_regions((clustering.busmap,), snakemake.input, snakemake.output) else: