Merge pull request #903 from PyPSA/cluster-network-replace-pyomo
Cluster network replace pyomo
This commit is contained in:
commit
0bb70b42ef
10
.github/workflows/ci.yaml
vendored
10
.github/workflows/ci.yaml
vendored
@ -53,16 +53,6 @@ jobs:
|
||||
run: |
|
||||
echo -ne "url: ${CDSAPI_URL}\nkey: ${CDSAPI_TOKEN}\n" > ~/.cdsapirc
|
||||
|
||||
- name: Add solver to environment
|
||||
run: |
|
||||
echo -e "- glpk\n- ipopt<3.13.3" >> envs/environment.yaml
|
||||
if: ${{ matrix.os }} == 'windows-latest'
|
||||
|
||||
- name: Add solver to environment
|
||||
run: |
|
||||
echo -e "- glpk\n- ipopt" >> envs/environment.yaml
|
||||
if: ${{ matrix.os }} != 'windows-latest'
|
||||
|
||||
- name: Setup micromamba
|
||||
uses: mamba-org/setup-micromamba@v1
|
||||
with:
|
||||
|
@ -60,6 +60,11 @@ Upcoming Release
|
||||
* The rule ``plot_network`` has been split into separate rules for plotting
|
||||
electricity, hydrogen and gas networks.
|
||||
|
||||
* To determine the optimal topology to meet the number of clusters, the workflow used pyomo in combination with ``ipopt`` or ``gurobi``. This dependency has been replaced by using ``linopy`` in combination with ``scipopt`` or ``gurobi``. The environment file has been updated accordingly.
|
||||
|
||||
* The ``highs`` solver was added to the default environment file.
|
||||
|
||||
|
||||
|
||||
PyPSA-Eur 0.9.0 (5th January 2024)
|
||||
==================================
|
||||
|
@ -35,8 +35,9 @@ dependencies:
|
||||
- netcdf4
|
||||
- networkx
|
||||
- scipy
|
||||
- glpk
|
||||
- shapely>=2.0
|
||||
- pyomo
|
||||
- pyscipopt
|
||||
- matplotlib
|
||||
- proj
|
||||
- fiona
|
||||
@ -47,7 +48,6 @@ dependencies:
|
||||
- tabula-py
|
||||
- pyxlsb
|
||||
- graphviz
|
||||
- ipopt
|
||||
|
||||
# Keep in conda environment when calling ipython
|
||||
- ipython
|
||||
@ -60,3 +60,4 @@ dependencies:
|
||||
|
||||
- pip:
|
||||
- tsam>=2.3.1
|
||||
- highspy
|
||||
|
@ -122,14 +122,15 @@ Exemplary unsolved network clustered to 37 nodes:
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import warnings
|
||||
from functools import reduce
|
||||
|
||||
import geopandas as gpd
|
||||
import linopy
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import pyomo.environ as po
|
||||
import pypsa
|
||||
import seaborn as sns
|
||||
from _helpers import configure_logging, update_p_nom_max
|
||||
@ -214,7 +215,7 @@ def get_feature_for_hac(n, buses_i=None, feature=None):
|
||||
return feature_data
|
||||
|
||||
|
||||
def distribute_clusters(n, n_clusters, focus_weights=None, solver_name="cbc"):
|
||||
def distribute_clusters(n, n_clusters, focus_weights=None, solver_name="scip"):
|
||||
"""
|
||||
Determine the number of clusters per country.
|
||||
"""
|
||||
@ -254,31 +255,22 @@ def distribute_clusters(n, n_clusters, focus_weights=None, solver_name="cbc"):
|
||||
L.sum(), 1.0, rtol=1e-3
|
||||
), f"Country weights L must sum up to 1.0 when distributing clusters. Is {L.sum()}."
|
||||
|
||||
m = po.ConcreteModel()
|
||||
|
||||
def n_bounds(model, *n_id):
|
||||
return (1, N[n_id])
|
||||
|
||||
m.n = po.Var(list(L.index), bounds=n_bounds, domain=po.Integers)
|
||||
m.tot = po.Constraint(expr=(po.summation(m.n) == n_clusters))
|
||||
m.objective = po.Objective(
|
||||
expr=sum((m.n[i] - L.loc[i] * n_clusters) ** 2 for i in L.index),
|
||||
sense=po.minimize,
|
||||
m = linopy.Model()
|
||||
clusters = m.add_variables(
|
||||
lower=1, upper=N, coords=[L.index], name="n", integer=True
|
||||
)
|
||||
|
||||
opt = po.SolverFactory(solver_name)
|
||||
if solver_name == "appsi_highs" or not opt.has_capability("quadratic_objective"):
|
||||
logger.warning(
|
||||
f"The configured solver `{solver_name}` does not support quadratic objectives. Falling back to `ipopt`."
|
||||
m.add_constraints(clusters.sum() == n_clusters, name="tot")
|
||||
# leave out constant in objective (L * n_clusters) ** 2
|
||||
m.objective = (clusters * clusters - 2 * clusters * L * n_clusters).sum()
|
||||
if solver_name == "gurobi":
|
||||
logging.getLogger("gurobipy").propagate = False
|
||||
elif solver_name != "scip":
|
||||
logger.info(
|
||||
f"The configured solver `{solver_name}` does not support quadratic objectives. Falling back to `scip`."
|
||||
)
|
||||
opt = po.SolverFactory("ipopt")
|
||||
|
||||
results = opt.solve(m)
|
||||
assert (
|
||||
results["Solver"][0]["Status"] == "ok"
|
||||
), f"Solver returned non-optimally: {results}"
|
||||
|
||||
return pd.Series(m.n.get_values(), index=L.index).round().astype(int)
|
||||
solver_name = "scip"
|
||||
m.solve(solver_name=solver_name)
|
||||
return m.solution["n"].to_series().astype(int)
|
||||
|
||||
|
||||
def busmap_for_n_clusters(
|
||||
@ -372,7 +364,7 @@ def busmap_for_n_clusters(
|
||||
|
||||
return (
|
||||
n.buses.groupby(["country", "sub_network"], group_keys=False)
|
||||
.apply(busmap_for_country)
|
||||
.apply(busmap_for_country, include_groups=False)
|
||||
.squeeze()
|
||||
.rename("busmap")
|
||||
)
|
||||
@ -385,7 +377,7 @@ def clustering_for_n_clusters(
|
||||
aggregate_carriers=None,
|
||||
line_length_factor=1.25,
|
||||
aggregation_strategies=dict(),
|
||||
solver_name="cbc",
|
||||
solver_name="scip",
|
||||
algorithm="hac",
|
||||
feature=None,
|
||||
extended_link_costs=0,
|
||||
@ -462,7 +454,6 @@ if __name__ == "__main__":
|
||||
|
||||
params = snakemake.params
|
||||
solver_name = snakemake.config["solving"]["solver"]["name"]
|
||||
solver_name = "appsi_highs" if solver_name == "highs" else solver_name
|
||||
|
||||
n = pypsa.Network(snakemake.input.network)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user