diff --git a/workflow/repo_data/config/config.default.yaml b/workflow/repo_data/config/config.default.yaml index 51d4a4a7..95170475 100644 --- a/workflow/repo_data/config/config.default.yaml +++ b/workflow/repo_data/config/config.default.yaml @@ -13,7 +13,6 @@ scenario: simpl: [75] opts: [REM-3h] ll: [v1.0] - scope: "total" # "urban", "rural", or "total" sector: "" # G planning_horizons: [2030, 2040, 2050] #(2018-2023, 2030, 2040, 2050) @@ -134,33 +133,6 @@ costs: 12hr_PHS: 0.3 max_growth: # {carrier: {base:, rate:}} -# docs : -sector: - co2_sequestration_potential: 0 - natural_gas: - allow_imports_exports: true # false to be implemented - cyclic_storage: false - heating: - heat_pump_sink_T: 55. - demand: - profile: - residential: eulp # efs, eulp - commercial: eulp # efs, eulp - transport: efs # efs - industry: efs # efs - scale: - residential: aeo # efs, aeo - commercial: aeo # efs, aeo - transport: aeo # efs, aeo - industry: aeo # efs, aeo - disaggregation: - residential: pop # pop - commercial: pop # pop - transport: pop # pop - industry: pop # pop - scenarios: - aeo: reference - # docs : clustering: simplify_network: diff --git a/workflow/repo_data/config/config.sector.yaml b/workflow/repo_data/config/config.sector.yaml index 7d9bf632..19ea2bc2 100644 --- a/workflow/repo_data/config/config.sector.yaml +++ b/workflow/repo_data/config/config.sector.yaml @@ -49,8 +49,10 @@ sector: transport_sector: brownfield: True # false to be implemented dynamic_costs: True # false to be implemented - exogenous: True # false to be implemented - ev_policy: "config/policy_constraints/ev_policy.csv" + investment: + exogenous: False + ev_policy: "config/policy_constraints/ev_policy.csv" + must_run_evs: True modes: # false to be implemented vehicle: true rail: true diff --git a/workflow/rules/build_sector.smk b/workflow/rules/build_sector.smk index 991da7e7..f24f5770 100644 --- a/workflow/rules/build_sector.smk +++ b/workflow/rules/build_sector.smk @@ -30,7 +30,9 @@ def sector_input_files(wildcards): + "{interconnect}/cop_air_urban_elec_s{simpl}_c{clusters}.nc", "clustered_pop_layout": RESOURCES + "{interconnect}/pop_layout_elec_s{simpl}_c{clusters}.csv", - "ev_policy": config["sector"]["transport_sector"]["ev_policy"], + "ev_policy": config["sector"]["transport_sector"]["investment"][ + "ev_policy" + ], "residential_stock": "repo_data/sectors/residential_stock", "commercial_stock": "repo_data/sectors/commercial_stock", } diff --git a/workflow/scripts/add_sectors.py b/workflow/scripts/add_sectors.py index 44cca1c8..fe2aa7f0 100644 --- a/workflow/scripts/add_sectors.py +++ b/workflow/scripts/add_sectors.py @@ -28,7 +28,11 @@ get_residential_stock, get_transport_stock, ) -from build_transportation import apply_exogenous_ev_policy, build_transportation +from build_transportation import ( + apply_endogenous_road_investments, + apply_exogenous_ev_policy, + build_transportation, +) from constants import STATE_2_CODE, STATES_INTERCONNECT_MAPPER from constants_sector import RoadTransport from shapely.geometry import Point @@ -340,10 +344,10 @@ def get_pwr_co2_intensity(carrier: str, costs: pd.DataFrame) -> float: snakemake = mock_snakemake( "add_sectors", interconnect="western", - simpl="33", + simpl="11", clusters="4m", ll="v1.0", - opts="2190SEG", + opts="3h", sector="E-G", ) configure_logging(snakemake) @@ -462,11 +466,18 @@ def get_pwr_co2_intensity(carrier: str, costs: pd.DataFrame) -> float: ) # add transportation - ev_policy = pd.read_csv(snakemake.input.ev_policy, index_col=0) - apply_exogenous_ev_policy(n, ev_policy) + exogenous_transport = snakemake.params.sector["transport_sector"]["investment"].get("exogenous", False) + if exogenous_transport: + ev_policy = pd.read_csv(snakemake.input.ev_policy, index_col=0) + apply_exogenous_ev_policy(n, ev_policy) + must_run_evs = None + else: + must_run_evs = snakemake.params.sector["transport_sector"]["investment"].get("must_run_evs", True) build_transportation( n=n, costs=costs, + exogenous=exogenous_transport, + must_run_evs=must_run_evs, dynamic_pricing=True, eia=eia_api, year=dynamic_cost_year, @@ -493,6 +504,7 @@ def get_pwr_co2_intensity(carrier: str, costs: pd.DataFrame) -> float: growth_multiplier, ratios, costs, + exogenous_transport, ) if snakemake.params.sector["service_sector"]["brownfield"]: diff --git a/workflow/scripts/build_stock_data.py b/workflow/scripts/build_stock_data.py index 35f3f3ab..2db9d287 100644 --- a/workflow/scripts/build_stock_data.py +++ b/workflow/scripts/build_stock_data.py @@ -609,12 +609,54 @@ def _get_brownfield_template_df( return df[["bus1", "name", "suffix", "state", "p_max"]] +def _get_endogenous_transport_brownfield_template_df( + n: pypsa.Network, + fuel: str, + veh_mode: Optional[str] = None, +) -> pd.DataFrame: + """ + Gets a dataframe in the following form. + + | | bus1 | name | suffix | state | p_max | + |-----|--------------------|--------|-------------|-------|-----------| + | 0 | p480 0 trn-veh-lgt | p480 0 | trn-veh-lgt | TX | 90.0544 | + | 1 | p600 0 trn-veh-hvy | p600 0 | trn-veh-hvy | TX | 716.606 | + | 2 | p610 0 trn-veh-med | p610 0 | trn-veh-med | TX | 1999.486 | + | ... | ... | ... | ... | ... | ... | + """ + + sector = SecNames.TRANSPORT.value + subsector = Transport.ROAD.value + if veh_mode: + vehicles = [veh_mode] + else: + vehicles = [x.value for x in RoadTransport] + + carriers = [f"{sector}-{subsector}-{x}" for x in vehicles] + + loads = n.loads[n.loads.carrier.isin(carriers)] + + if loads.empty: + return pd.DataFrame(columns=["bus1", "name", "suffix", "state", "p_max"]) + + df = n.loads_t.p_set[loads.index].max().to_frame(name="p_max") + + df["bus1"] = df.index + df["state"] = df.index.map(n.buses.STATE) + df["name"] = df.bus1.map(lambda x: x.split(f" {sector}")[0]) + df["suffix"] = [bus.split(name)[1].strip() for (bus, name) in df[["bus1", "name"]].values] + df["suffix"] = df.suffix.str.replace(f"{sector}-", f"{sector}-{fuel}-") + + return df.reset_index(drop=True)[["bus1", "name", "suffix", "state", "p_max"]] + + def add_road_transport_brownfield( n: pypsa.Network, vehicle_mode: str, # lgt, hvy, ect.. growth_multiplier: float, ratios: pd.DataFrame, costs: pd.DataFrame, + exogenous_transport: bool, ) -> None: """ Adds existing stock to transportation sector. @@ -654,11 +696,11 @@ def add_brownfield_ev( efficiency = costs.at[costs_name, "efficiency"] / 1000 lifetime = costs.at[costs_name, "lifetime"] - df["bus0"] = df.name + f" {sector}-elec-{veh_type}" - df["carrier"] = f"{sector}-elec-{veh_type}-{vehicle_mode}" + df["bus0"] = df.name + f" {sector}-{elec_fuel}-{veh_type}" + df["carrier"] = f"{sector}-{elec_fuel}-{veh_type}-{vehicle_mode}" df["ratio"] = ratios.at["electricity", ratio_name] - df["p_nom"] = df.p_max.mul(df.ratio).div(100) # div to convert from % + df["p_nom"] = df.p_max.mul(df.ratio).div(100).div(efficiency).round(2) # div to convert from % # roll back vehicle stock in 5 year segments step = 5 # years @@ -732,6 +774,9 @@ def add_brownfield_lpg( case _: raise NotImplementedError + if df.empty: + return + # dont bother adding in extra for less than 0.5% market share if ratios.at["lpg", ratio_name] < 0.5: logger.info(f"No Brownfield for {costs_name}") @@ -745,11 +790,11 @@ def add_brownfield_lpg( efficiency *= (1 / wh_per_gallon) * 1000000 / 1000 lifetime = costs.at[costs_name, "lifetime"] - df["bus0"] = df.name + f" {sector}-lpg-{veh_type}" - df["carrier"] = f"{sector}-lpg-{veh_type}-{vehicle_mode}" + df["bus0"] = df.name + f" {sector}-{lpg_fuel}-{veh_type}" + df["carrier"] = f"{sector}-{lpg_fuel}-{veh_type}-{vehicle_mode}" df["ratio"] = ratios.at["lpg", ratio_name] - df["p_nom"] = df.p_max.mul(df.ratio).div(100) # div to convert from % + df["p_nom"] = df.p_max.mul(df.ratio).div(100).div(efficiency).round(2) # div to convert from % marginal_cost = _get_marginal_cost(n, df.bus1.to_list()) @@ -797,20 +842,49 @@ def add_brownfield_lpg( marginal_cost=mc, ) + # different naming conventions for exogenous/endogenous transport investment + sector = SecNames.TRANSPORT.value veh_type = Transport.ROAD.value - veh_name = f"{veh_type}-{vehicle_mode}" + elec_fuel = SecCarriers.ELECTRICITY.value + lpg_fuel = SecCarriers.LPG.value - # ev brownfield - df = _get_brownfield_template_df(n, fuel="elec", sector=sector, subsector=veh_name) - df["p_nom"] = df.p_max.mul(growth_multiplier) - add_brownfield_ev(n, df, vehicle_mode, ratios, costs) + if exogenous_transport: - # lpg brownfield - df = _get_brownfield_template_df(n, fuel="lpg", sector=sector, subsector=veh_name) - df["p_nom"] = df.p_max.mul(growth_multiplier) - add_brownfield_lpg(n, df, vehicle_mode, ratios, costs) + veh_name = f"{veh_type}-{vehicle_mode}" + + # ev brownfield + df = _get_brownfield_template_df( + n, + fuel=elec_fuel, + sector=sector, + subsector=veh_name, + ) + df["p_nom"] = df.p_max.mul(growth_multiplier) + add_brownfield_ev(n, df, vehicle_mode, ratios, costs) + + # lpg brownfield + df = _get_brownfield_template_df( + n, + fuel=lpg_fuel, + sector=sector, + subsector=veh_name, + ) + df["p_nom"] = df.p_max.mul(growth_multiplier) + add_brownfield_lpg(n, df, vehicle_mode, ratios, costs) + + else: + + # elec brownfield + df = _get_endogenous_transport_brownfield_template_df(n, fuel=elec_fuel, veh_mode=vehicle_mode) + df["p_nom"] = df.p_max.mul(growth_multiplier) + add_brownfield_ev(n, df, vehicle_mode, ratios, costs) + + # lpg brownfield + df = _get_endogenous_transport_brownfield_template_df(n, fuel=lpg_fuel, veh_mode=vehicle_mode) + df["p_nom"] = df.p_max.mul(growth_multiplier) + add_brownfield_lpg(n, df, vehicle_mode, ratios, costs) def add_service_brownfield( @@ -859,7 +933,7 @@ def add_brownfield_gas_furnace( df["carrier"] = df.carrier + "-gas-furnace" df["ratio"] = df.state.map(ratios.gas) - df["p_nom"] = df.p_max.mul(df.ratio).div(100) # div to convert from % + df["p_nom"] = df.p_max.mul(df.ratio).div(100).div(efficiency).round(2) # div to convert from % marginal_cost_names = [x.replace("heat", "gas-furnace") for x in df.bus1.to_list()] marginal_cost = _get_marginal_cost(n, marginal_cost_names) @@ -875,7 +949,7 @@ def add_brownfield_gas_furnace( furnaces = df.copy() furnaces["name"] = furnaces.name + f" existing_{build_year} " + furnaces.carrier - furnaces["p_nom"] = furnaces.p_nom.mul(percent).div(100).div(efficiency).mul(2).round(2) + furnaces["p_nom"] = furnaces.p_nom.mul(percent).div(100).round(2) furnaces = furnaces.set_index("name") if isinstance(marginal_cost, pd.DataFrame): @@ -936,7 +1010,7 @@ def add_brownfield_oil_furnace( df["carrier"] = df.carrier + "-lpg-furnace" df["ratio"] = df.state.map(ratios.lpg) - df["p_nom"] = df.p_max.mul(df.ratio).div(100) # div to convert from % + df["p_nom"] = df.p_max.mul(df.ratio).div(100).div(efficiency) # div to convert from % marginal_cost_names = [x.replace("heat", "lpg-furnace") for x in df.bus1.to_list()] marginal_cost = _get_marginal_cost(n, marginal_cost_names) @@ -952,7 +1026,7 @@ def add_brownfield_oil_furnace( furnaces = df.copy() furnaces["name"] = furnaces.name + f" existing_{build_year} " + furnaces.carrier - furnaces["p_nom"] = furnaces.p_nom.mul(percent).div(100).div(efficiency).round(2) + furnaces["p_nom"] = furnaces.p_nom.mul(percent).div(100).round(2) furnaces = furnaces.set_index("name") if isinstance(marginal_cost, pd.DataFrame): @@ -1010,7 +1084,7 @@ def add_brownfield_elec_furnace( df["carrier"] = df.carrier + "-elec-furnace" df["ratio"] = df.state.map(ratios.electricity) - df["p_nom"] = df.p_max.mul(df.ratio).div(100) # div to convert from % + df["p_nom"] = df.p_max.mul(df.ratio).div(100).div(efficiency) # div to convert from % start_year = n.investment_periods[0] # start_year = start_year if start_year >= 2023 else 2023 @@ -1346,10 +1420,11 @@ def add_brownfield_water_heater( if __name__ == "__main__": - print(get_residential_stock("./../repo_data/sectors/residential_stock", "cooling")) + # print(get_residential_stock("./../repo_data/sectors/residential_stock", "cooling")) # with open("./../config/config.api.yaml") as file: # yaml_data = yaml.safe_load(file) # api = yaml_data["api"]["eia"] # print(get_transport_stock(api, 2024)) + pass diff --git a/workflow/scripts/build_transportation.py b/workflow/scripts/build_transportation.py index b08ecfe2..670e668a 100644 --- a/workflow/scripts/build_transportation.py +++ b/workflow/scripts/build_transportation.py @@ -24,12 +24,14 @@ def build_transportation( n: pypsa.Network, costs: pd.DataFrame, + exogenous: bool = False, air: bool = True, rail: bool = True, boat: bool = True, dynamic_pricing: bool = False, eia: Optional[str] = None, # for dynamic pricing year: Optional[int] = None, # for dynamic pricing + must_run_evs: Optional[bool] = None, # for endogenous EV investment ) -> None: """ Main funtion to interface with. @@ -56,6 +58,10 @@ def build_transportation( add_elec_vehicle(n, road_suffix, vehicle, costs) add_lpg_vehicle(n, road_suffix, vehicle, costs, lpg_cost) + if not exogenous: + assert isinstance(must_run_evs, bool) + apply_endogenous_road_investments(n, must_run_evs) + if air: air_suffix = Transport.AIR.value add_lpg_infrastructure(n, air_suffix, costs) @@ -453,6 +459,161 @@ def add_rail( ) +def _create_endogenous_buses(n: pypsa.Network) -> None: + """Creats new bus for grouped endogenous vehicle load""" + + buses = n.buses[ + n.buses.carrier.str.startswith("trn") + & n.buses.carrier.str.contains("veh") + & ~n.buses.carrier.str.endswith("veh") + ].copy() + buses["veh"] = buses.carrier.map(lambda x: x.split("-")[-1]) + buses["name"] = buses.country + " trn-veh-" + buses.veh + buses["carrier"] = "trn-veh-" + buses.veh + buses = buses.drop_duplicates(subset="name") + buses = buses.set_index("name") + + n.madd( + "Bus", + buses.index, + x=buses.x, + y=buses.y, + carrier=buses.carrier, + STATE=buses.STATE, + STATE_NAME=buses.STATE_NAME, + unit=buses.unit, + interconnect=buses.interconnect, + state=buses.state, + country=buses.country, + reeds_ba=buses.reeds_ba, + reeds_state=buses.reeds_state, + nerc_reg=buses.nerc_reg, + trans_reg=buses.trans_reg, + ) + + +def _create_endogenous_loads(n: pypsa.Network) -> None: + """Creates aggregated vehicle load + + - Removes LPG load + - Transfers EV load to central bus + """ + + loads = n.loads[n.loads.carrier.str.startswith("trn") & n.loads.carrier.str.contains("veh")] + to_remove = [x for x in loads.index if "-lpg-" in x] + to_shift = [x for x in loads.index if "-elec-" in x] + assert (len(to_remove) + len(to_shift)) == len(loads) + + new_name_mapper = {x: x.replace("-elec", "") for x in to_shift} + new_names = [x for _, x in new_name_mapper.items()] + + # remove LPG loads + n.mremove( + "Load", + to_remove, + ) + + # rename elec loads to general loads + n.loads_t["p_set"] = n.loads_t["p_set"].rename(columns=new_name_mapper) + n.loads = n.loads.rename(index=new_name_mapper) + + # transfer elec load buses to general bus + n.loads.loc[new_names, "bus"] = n.loads.loc[new_names, "bus"].map(new_name_mapper) + n.loads.loc[new_names, "carrier"] = n.loads.loc[new_names, "carrier"].map(lambda x: x.replace("trn-elec-", "trn-")) + n.loads.loc[new_names, "carrier"] = n.loads.loc[new_names, "carrier"].map(lambda x: x.replace("trn-lpg-", "trn-")) + + +def _create_endogenous_links(n: pypsa.Network) -> None: + """Creates links for LPG and EV to load bus + + Just involves transfering bus1 from exogenous load bus to endogenous load bus + """ + + slicer = ( + n.links.carrier.str.startswith("trn") + & n.links.carrier.str.contains("veh") + & ~n.links.carrier.str.endswith("veh") + ) + n.links.loc[slicer, "bus1"] = n.links.loc[slicer, "bus1"].map(lambda x: x.replace("trn-elec-", "trn-")) + n.links.loc[slicer, "bus1"] = n.links.loc[slicer, "bus1"].map(lambda x: x.replace("trn-lpg-", "trn-")) + + +def _remove_exogenous_buses(n: pypsa.Network) -> None: + """Removes buses that are used for exogenous vehicle loads""" + + buses = n.buses[ + (n.buses.index.str.contains("trn-elec-veh") | n.buses.index.str.contains("trn-lpg-veh")) + & ~(n.buses.index.str.endswith("-veh")) + ].index.to_list() + n.mremove("Bus", buses) + + +def _constrain_charing_rates(n: pypsa.Network, must_run_evs: bool) -> None: + """Applies limits to p_min_pu/p_max_pu on links + + must_run_evs: + True + Both the p_min_pu and p_max_pu of only EVs are set to match the load profile + False + p_max_pu of both EVs and LPGs are set to match the load profile. + p_min_pu is left unchanged (ie. zero) + """ + + links = n.links[n.links.carrier.str.contains("-veh") & ~n.links.carrier.str.endswith("-veh")] + evs = links[links.carrier.str.contains("-elec-")] + lpgs = links[links.carrier.str.contains("-lpg-")] + + # these must be done seperatly, as they share bus1 names + ev_mapper = evs.reset_index().set_index("bus1")["Link"].to_dict() + lpg_mapper = lpgs.reset_index().set_index("bus1")["Link"].to_dict() + + assert len(evs) + len(lpgs) == len(links) + + p_max_pu_evs = n.loads_t["p_set"][evs.bus1.tolist()] + p_max_pu_evs = p_max_pu_evs.rename(columns=ev_mapper) + + if must_run_evs: + p_min_pu = n.loads_t["p_set"][evs.bus1.tolist()] + p_min_pu = p_min_pu.rename(columns=ev_mapper) + p_max_pu = p_max_pu_evs.copy() + else: + p_min_pu = pd.DataFrame() + p_max_pu_lpg = n.loads_t["p_set"][lpgs.bus1.tolist()] + p_max_pu_lpg = p_max_pu_lpg.rename(columns=lpg_mapper) + p_max_pu = pd.concat([p_max_pu_evs, p_max_pu_lpg], axis=1) + + # normalize to get profiles + # add small buffer for computation issues while solving + if not p_min_pu.empty: + p_min_pu = (p_min_pu - p_min_pu.min()) / (p_min_pu.max() - p_min_pu.min()) + p_min_pu = p_min_pu.sub(0.01).clip(lower=0).round(2) + n.links_t["p_min_pu"] = pd.concat([n.links_t["p_min_pu"], p_min_pu], axis=1) + + p_max_pu = (p_max_pu - p_max_pu.min()) / (p_max_pu.max() - p_max_pu.min()) + p_max_pu = p_max_pu = p_max_pu.add(0.01).clip(upper=1).round(2) + n.links_t["p_max_pu"] = pd.concat([n.links_t["p_max_pu"], p_max_pu], axis=1) + + +def apply_endogenous_road_investments(n: pypsa.Network, must_run_evs: bool = False) -> None: + """Merges EV and LPG load into a single load. + + This function will do the following: + - Create a new bus that the combined load will apply to + - Shift the EV load to the new bus. This load will retain the EV profile and full + magnitude, as this represents all vehicle load in the system. The load is renamed. + - Remove the LPG load + - Create two links. 1) from EV to new bus for aggregate load. 2) from LPG to new + bus for aggregate load + - Costrain the new EV link to match the vehicle load profile + (ie. p_nom_min(ev) = p_nom_max(ev) = p_nom_t(load)) + """ + _create_endogenous_buses(n) + _create_endogenous_loads(n) + _create_endogenous_links(n) + _remove_exogenous_buses(n) + _constrain_charing_rates(n, must_run_evs) + + def apply_exogenous_ev_policy(n: pypsa.Network, policy: pd.DataFrame) -> None: """ If transport investment is exogenous, applies policy to control loads. diff --git a/workflow/scripts/cluster_network.py b/workflow/scripts/cluster_network.py index 7b69f4a0..f8f9d0e5 100644 --- a/workflow/scripts/cluster_network.py +++ b/workflow/scripts/cluster_network.py @@ -512,10 +512,12 @@ def convert_to_transport( # Dissolve TX for particular zones according to default reeds configurations clustering.network.links.loc[ - clustering.network.links.bus0.isin(["p119"]) & clustering.network.links.bus1.isin(["p122"]), "p_nom" + clustering.network.links.bus0.isin(["p119"]) & clustering.network.links.bus1.isin(["p122"]), + "p_nom", ] = 1e9 clustering.network.links.loc[ - clustering.network.links.bus1.isin(["p119"]) & clustering.network.links.bus0.isin(["p122"]), "p_nom" + clustering.network.links.bus1.isin(["p119"]) & clustering.network.links.bus0.isin(["p122"]), + "p_nom", ] = 1e9 # Dissolve p124 and p99 if "p124" in clustering.network.buses.index and "p99" in clustering.network.buses.index: diff --git a/workflow/scripts/plot_statistics_sector.py b/workflow/scripts/plot_statistics_sector.py index 36e9cdfa..2fea2c58 100644 --- a/workflow/scripts/plot_statistics_sector.py +++ b/workflow/scripts/plot_statistics_sector.py @@ -1451,14 +1451,14 @@ def _initialize_metadata(data: dict[str, Any]) -> list[PlottingData]: from _helpers import mock_snakemake snakemake = mock_snakemake( - "plot_sector_production", - simpl="33", - opts="2190SEG", + "plot_sector_capacity", + simpl="11", + opts="3h", clusters="4m", ll="v1.0", sector_opts="", sector="E-G", - planning_horizons="2020", + planning_horizons="2018", interconnect="western", ) rootpath = ".." diff --git a/workflow/scripts/plot_validation_sector.py b/workflow/scripts/plot_validation_sector.py index 899e2480..423899a9 100644 --- a/workflow/scripts/plot_validation_sector.py +++ b/workflow/scripts/plot_validation_sector.py @@ -677,13 +677,13 @@ def save_fig( snakemake = mock_snakemake( "plot_sector_validation", - simpl="33", - opts="2190SEG", + simpl="11", + opts="3h", clusters="4m", ll="v1.0", sector_opts="", sector="E-G", - planning_horizons="2019", + planning_horizons="2018", interconnect="western", ) rootpath = ".." diff --git a/workflow/scripts/solve_network.py b/workflow/scripts/solve_network.py index d5bc938a..8e2cfadd 100644 --- a/workflow/scripts/solve_network.py +++ b/workflow/scripts/solve_network.py @@ -1458,16 +1458,6 @@ def solve_network(n, config, solving, opts="", **kwargs): n = pypsa.Network(snakemake.input.network) - # lks = n.links[n.links.carrier.str.endswith("-gas-furnace")].index - # n.links.loc[lks, "capital_cost"] = 0 - - # n.links.loc["CA gas production", "p_nom_extendable"] = True - # n.links.loc["CA gas production", "p_nom_max"] = np.inf - # n.links.loc["CA gas production", "capital_cost"] = 1 - - lks = n.links[(n.links.carrier.str.contains("ashp")) & (n.links.carrier.str.startswith("com"))].index.to_list() - n.links.loc[lks, "p_nom"] = 1250 - n = prepare_network( n, solve_opts, diff --git a/workflow/scripts/summary_sector.py b/workflow/scripts/summary_sector.py index 9cc28255..00308c75 100644 --- a/workflow/scripts/summary_sector.py +++ b/workflow/scripts/summary_sector.py @@ -178,7 +178,7 @@ def _get_opt_capacity_per_node( # remove the double accounting if sector in ("res", "com"): df = df[ - ~(df.carrier.str.endswith("-gshp-cool")) + ~(df.index.str.endswith("-gshp-cool")) & ~(df.index.str.endswith("-ashp-cool")) & ~(df.index.str.endswith("-charger")) ] @@ -239,7 +239,7 @@ def _get_total_capacity_per_node( # remove the double accounting if sector in ("res", "com"): df = df[ - ~(df.carrier.str.endswith("-gshp-cool")) + ~(df.index.str.endswith("-gshp-cool")) & ~(df.index.str.endswith("-ashp-cool")) & ~(df.index.str.endswith("-charger")) ] @@ -326,7 +326,7 @@ def _get_brownfield_capacity_per_node( # remove the double accounting if sector in ("res", "com"): df = df[ - ~(df.carrier.str.endswith("-gshp-cool")) + ~(df.index.str.endswith("-gshp-cool")) & ~(df.index.str.endswith("-ashp-cool")) & ~(df.index.str.endswith("-charger")) ] @@ -633,7 +633,7 @@ def get_historical_power_production(year: int, api: str) -> pd.DataFrame: } df = ElectricPowerData("electric_power", year, api).get_data() - df = df[df.fueltypeid.isin(fuel_mapper)] + df = df[df.fueltypeid.isin(fuel_mapper)].copy() df["value"] = df.value.mul(1000) # thousand mwh to mwh df = df.reset_index()