Optimization MethodsΒΆ
OptimizationAccessor
ΒΆ
OptimizationAccessor(n: Network)
Optimization accessor for building and solving models using linopy.
Methods:
-
__call__βOptimize the pypsa network using linopy.
-
add_load_sheddingβAdd load shedding in form of generators to all or a subset of buses.
-
assign_dualsβMap dual values i.e. shadow prices to network components.
-
assign_solutionβMap solution to network components.
-
build_linexpr_from_weightsβBuild a linopy LinearExpression from the given weights.
-
create_modelβCreate a linopy.Model instance from a pypsa network.
-
fix_optimal_capacitiesβFix capacities of extendable assets to optimized capacities.
-
fix_optimal_dispatchβFix dispatch of all assets to optimized values.
-
optimize_and_run_non_linear_powerflowβOptimizes the network and then performs a non-linear power flow for all snapshots.
-
optimize_mgaβRun modelling-to-generate-alternatives (MGA) on network to find near-optimal solutions.
-
optimize_mga_in_directionβRun MGA in a given direction in a low-dimension projection.
-
optimize_mga_in_multiple_directionsβRun MGA optimization in multiple directions in parallel.
-
optimize_security_constrainedβCompute Security-Constrained Linear Optimal Power Flow (SCLOPF).
-
optimize_transmission_expansion_iterativelyβRun iterative linear optimization.
-
optimize_with_rolling_horizonβOptimizes the network in a rolling horizon fashion.
-
post_processingβPost-process the optimized network.
-
project_solvedβProject solved model onto low-dimensional space.
-
solve_modelβSolve an already created model and assign its solution to the network.
pypsa.Network.optimize.__call__
ΒΆ
__call__(
snapshots: Sequence | None = None,
multi_investment_periods: bool = False,
transmission_losses: int = 0,
linearized_unit_commitment: bool = False,
model_kwargs: dict | None = None,
extra_functionality: Callable | None = None,
assign_all_duals: bool = False,
solver_name: str | None = None,
solver_options: dict | None = None,
compute_infeasibilities: bool = False,
**kwargs: Any,
) -> tuple[str, str]
Optimize the pypsa network using linopy.
Parameters:
-
snapshots(list or index slice, default:None) βA list of snapshots to optimise, must be a subset of n.snapshots, defaults to n.snapshots
-
multi_investment_periods(bool, default:False) βWhether to optimise as a single investment period or to optimise in multiple investment periods. Then, snapshots should be a
pd.MultiIndex. -
transmission_losses(int, default:0) βWhether an approximation of transmission losses should be included in the linearised power flow formulation. A passed number will denote the number of tangents used for the piecewise linear approximation. Defaults to 0, which ignores losses.
-
linearized_unit_commitment(bool, default:False) βWhether to optimise using the linearised unit commitment formulation or not.
-
model_kwargs(dict, default:None) βKeyword arguments used by
linopy.Model, such assolver_dirorchunk. Defaults to module wide option (default: {}). Seehttps://go.pypsa.org/options-paramsfor more information. -
extra_functionality(callable, default:None) βThis function must take two arguments
extra_functionality(n, snapshots)and is called after the model building is complete, but before it is sent to the solver. It allows the user to add/change constraints and add/change the objective function. -
assign_all_duals(bool, default:False) βWhether to assign all dual values or only those that already have a designated place in the network.
-
solver_name(str, default:None) βName of the solver to use. Defaults to module wide option (default: 'highs'). See
https://go.pypsa.org/options-paramsfor more information. -
solver_options(dict, default:None) βKeyword arguments used by the solver. Can also be passed via
**kwargs. Defaults to module wide option (default: {}). Seehttps://go.pypsa.org/options-paramsfor more information. -
compute_infeasibilities(bool, default:False) βWhether to compute and print Irreducible Inconsistent Subsystem (IIS) in case of an infeasible solution. Requires Gurobi.
-
**kwargs(Any, default:{}) βKeyword argument used by
linopy.Model.solve, such assolver_name,problem_fnor solver options directly passed to the solver.
Returns:
-
status(str) βThe status of the optimization, either "ok" or one of the codes listed in linopy.constants.SolverStatus
-
condition(str) βThe termination condition of the optimization, either "optimal" or one of the codes listed in linopy.constants.TerminationCondition
pypsa.Network.optimize.add_load_shedding
ΒΆ
add_load_shedding(
suffix: str = " load shedding",
buses: Index | None = None,
sign: float | Series = 0.001,
marginal_cost: float | Series = 100.0,
p_nom: float | Series = 1000000000.0,
) -> Index
Add load shedding in form of generators to all or a subset of buses.
For more information on load shedding see http://journal.frontiersin.org/article/10.3389/fenrg.2015.00055/full
Parameters:
-
suffix(str, default:" load shedding") βSuffix of the load shedding generators. See suffix parameter of [pypsa.Network.add].
-
buses(Index, default:None) βSubset of buses where load shedding should be available. Defaults to all buses.
-
sign(float / Series, default:0.001) βScaling of the load shedding. This is used to scale the price of the load shedding. The default is 1e-3 which translates to a measure in kW instead of MW.
-
marginal_cost(float / Series, default:100.0) βPrice of the load shedding. The default is 1e2.
-
p_nom(float / Series, default:1000000000.0) βMaximal load shedding. The default is 1e9 (kW).
pypsa.Network.optimize.assign_duals
ΒΆ
assign_duals(assign_all_duals: bool = False) -> None
Map dual values i.e. shadow prices to network components.
Parameters:
-
assign_all_duals(bool, default:False) βWhether to assign all dual values or only those that already have a designated place in the network.
pypsa.Network.optimize.assign_solution
ΒΆ
assign_solution() -> None
Map solution to network components.
pypsa.Network.optimize.build_linexpr_from_weights
ΒΆ
build_linexpr_from_weights(
weights: dict, model: Model | None = None
) -> LinearExpression
Build a linopy LinearExpression from the given weights.
Parameters:
-
weights(dict) βA dictionary specifying the weights for different components and their attributes. The structure should be
{'component_name': {'attribute_name': coefficients}}. Coefficients can be a float,pd.Series, orpd.DataFrame. -
model(Model | None, default:None) βThe linopy model to use. If None,
self._n.modelis used. Defaults to None.
Returns:
-
LinearExpressionβA linear expression built according to the specified weights.
pypsa.Network.optimize.create_model
ΒΆ
create_model(
snapshots: Sequence | None = None,
multi_investment_periods: bool = False,
transmission_losses: int = 0,
linearized_unit_commitment: bool = False,
consistency_check: bool = True,
**kwargs: Any,
) -> Model
Create a linopy.Model instance from a pypsa network.
The model is stored at n.model.
Parameters:
-
snapshots(list or index slice, default:None) βA list of snapshots to optimise, must be a subset of n.snapshots, defaults to n.snapshots
-
multi_investment_periods(bool, default:False) βWhether to optimise as a single investment period or to optimize in multiple investment periods. Then, snapshots should be a
pd.MultiIndex. -
transmission_losses(int, default:0) βWhether an approximation of transmission losses should be included in the linearised power flow formulation.
-
linearized_unit_commitment(bool, default:False) βWhether to optimise using the linearised unit commitment formulation or not.
-
consistency_check(bool, default:True) βWhether to run the consistency check before building the model.
-
**kwargs(Any, default:{}) βKeyword arguments used by
linopy.Model(), such assolver_dirorchunk.
Returns:
-
modelβ
pypsa.Network.optimize.fix_optimal_capacities
ΒΆ
fix_optimal_capacities() -> None
Fix capacities of extendable assets to optimized capacities.
Use this function when a capacity expansion optimization was already performed and a operational optimization should be done afterwards.
pypsa.Network.optimize.fix_optimal_dispatch
ΒΆ
fix_optimal_dispatch() -> None
Fix dispatch of all assets to optimized values.
Use this function when the optimal dispatch should be used as an
starting point for power flow calculation (Network.pf).
pypsa.Network.optimize.optimize_and_run_non_linear_powerflow
ΒΆ
optimize_and_run_non_linear_powerflow(
snapshots: Sequence | None = None,
skip_pre: bool = False,
x_tol: float = 1e-06,
use_seed: bool = False,
distribute_slack: bool = False,
slack_weights: str = "p_set",
**kwargs: Any,
) -> dict
Optimizes the network and then performs a non-linear power flow for all snapshots.
Parameters:
-
snapshots(Sequence | None, default:None) βSet of snapshots to consider in the optimization and power flow. If None, uses all snapshots in the network.
-
skip_pre(bool, default:False) βSkip the preliminary steps of the power flow, by default False.
-
x_tol(float, default:1e-06) βPower flow convergence tolerance, by default 1e-06.
-
use_seed(bool, default:False) βUse the last solution as initial guess, by default False.
-
distribute_slack(bool, default:False) βDistribute slack power across generators, by default False.
-
slack_weights(str, default:'p_set') βHow to distribute slack power, by default 'p_set'.
-
**kwargs(Any, default:{}) βKeyword arguments passed to the optimize function.
Returns:
-
Tuple[str, str, Dict]βA tuple containing: - optimization status - optimization condition - dictionary of power flow results for all snapshots
pypsa.Network.optimize.optimize_mga
ΒΆ
optimize_mga(
snapshots: Sequence | None = None,
multi_investment_periods: bool = False,
weights: dict | None = None,
sense: str | int = "min",
slack: float = 0.05,
model_kwargs: dict | None = None,
**kwargs: Any,
) -> tuple[str, str]
Run modelling-to-generate-alternatives (MGA) on network to find near-optimal solutions.
Parameters:
-
snapshots(list - like, default:None) βSet of snapshots to consider in the optimization. The default is None.
-
multi_investment_periods(bool, default:False) βWhether to optimise as a single investment period or to optimize in multiple investment periods. Then, snapshots should be a
pd.MultiIndex. -
weights(dict - like, default:None) βWeights for alternate objective function. The default is None, which minimizes generation capacity. The weights dictionary should be keyed with the component and variable (see
pypsa/data/variables.csv), followed by a float, dict, pd.Series or pd.DataFrame for the coefficients of the objective function. -
sense(str | int, default:'min') βOptimization sense of alternate objective function. Defaults to 'min'. Can also be 'max'.
-
slack(float, default:0.05) βCost slack for budget constraint. Defaults to 0.05.
-
model_kwargs(dict, default:None) βKeyword arguments used by
linopy.Model, such assolver_dirorchunk. Defaults to module wide option (default: {}). Seehttps://go.pypsa.org/options-params` for more information. -
**kwargs(Any, default:{}) βKeyword argument used by
linopy.Model.solve, such assolver_name,
Returns:
-
status(str) βThe status of the optimization, either "ok" or one of the codes listed in linopy.constants.SolverStatus.
-
condition(str) βThe termination condition of the optimization, either "optimal" or one of the codes listed in linopy.constants.TerminationCondition
pypsa.Network.optimize.optimize_mga_in_direction
ΒΆ
optimize_mga_in_direction(
direction: dict | Series,
dimensions: dict,
snapshots: Sequence | None = None,
multi_investment_periods: bool = False,
slack: float = 0.05,
model_kwargs: dict | None = None,
**kwargs: Any,
) -> tuple[str, str, Series | None]
Run MGA in a given direction in a low-dimension projection.
Parameters:
-
direction(dict | Series) βA dictionary or pd.Series representing the direction in the low-dimensional space. The keys or index are user-defined names for the dimensions, and the values are vector coordinates.
-
dimensions(dict) βA dictionary representing the dimensions of the low-dimensional space. The keys are user-defined names for the dimensions (matching those in the
directionargument), and the values are dictionaries with the same structure as theweightsargument inoptimize_mga. -
snapshots(Sequence | None, default:None) βSet of snapshots to consider in the optimization. If None, uses all snapshots from the network. Defaults to None.
-
multi_investment_periods(bool, default:False) βWhether to optimise as a single investment period or to optimize in multiple investment periods. Then, snapshots should be a
pd.MultiIndex. -
slack(float, default:0.05) βCost slack for budget constraint. Defaults to 0.05.
-
model_kwargs(dict, default:None) βKeyword arguments used by
linopy.Model, such assolver_dirorchunk. Defaults to module wide option (default: {}). Seehttps://go.pypsa.org/options-params` for more information. -
**kwargs(Any, default:{}) βKeyword argument used by
linopy.Model.solve, such assolver_name,
Returns:
-
status(str) βThe status of the optimization, either "ok" or one of the codes listed in linopy.constants.SolverStatus.
-
condition(str) βThe termination condition of the optimization, either "optimal" or one of the codes listed in linopy.constants.TerminationCondition
-
coordinates(Series | None) βIf the optimization status is "ok", then the final return value is a pd.Series representing the coordinates of the solved network in dimensions given by the user. The index consists of the keys in the
dimensionsargument; values are floats. If the optimization status is not "ok", then this value is None.
pypsa.Network.optimize.optimize_mga_in_multiple_directions
ΒΆ
optimize_mga_in_multiple_directions(
directions: list[dict] | DataFrame,
dimensions: dict,
snapshots: Sequence | None = None,
multi_investment_periods: bool = False,
slack: float = 0.05,
model_kwargs: dict | None = None,
max_parallel: int = 4,
**kwargs: Any,
) -> tuple[DataFrame, DataFrame]
Run MGA optimization in multiple directions in parallel.
This method performs modelling-to-generate-alternatives (MGA) optimization across multiple directions simultaneously using parallel processing. Each direction represents a different objective in the low-dimensional projection space defined by the dimensions parameter.
Note that, in order to achieve parallelism, this method exports the network to a temporary NetCDF file which is then re-imported in each parallel process. This leads to a slight overhead in IO and disk space. The temporary file is always cleaned up after the optimization is complete, regardless of whether any errors occurred during the optimization.
Parameters:
-
directions(list[dict] | DataFrame) βMultiple directions in the low-dimensional space. If a list, each element should be a dictionary with keys matching those in
dimensionsand values representing vector coordinates. If a DataFrame, rows represent directions and columns represent dimension names. -
dimensions(dict) βA dictionary representing the dimensions of the low-dimensional space. The keys are user-defined names for the dimensions (matching those in the
directionsargument), and the values are dictionaries with the same structure as theweightsargument inoptimize_mga. -
snapshots(Sequence | None, default:None) βSet of snapshots to consider in the optimization. If None, uses all snapshots from the network. Defaults to None.
-
multi_investment_periods(bool, default:False) βWhether to optimize as a single investment period or to optimize in multiple investment periods. Then, snapshots should be a
pd.MultiIndex. -
slack(float, default:0.05) βCost slack for budget constraint. Defaults to 0.05.
-
model_kwargs(dict, default:None) βKeyword arguments used by
linopy.Model, such assolver_dirorchunk. Defaults to module wide option (default: {}). Seehttps://go.pypsa.org/options-paramsfor more information. -
max_parallel(int, default:4) βMaximum number of parallel processes to use for solving multiple directions. Defaults to 4.
-
**kwargs(Any, default:{}) βKeyword argument used by
linopy.Model.solve, such assolver_name,
Returns:
-
directions_df(DataFrame) βDataFrame containing the successfully solved directions, where each row represents a direction and columns correspond to dimension names.
-
coordinates_df(DataFrame) βDataFrame containing the coordinates of each successfully solved network in the user-defined dimensions. Rows correspond to solved directions and columns to dimension names.
Examples:
>>> dimensions = {
... "wind": {"Generator": {"p_nom": {"wind": 1}}},
... "solar": {"Generator": {"p_nom": {"solar": 1}}}
... }
>>> directions = pypsa.optimization.mga.generate_directions_random(["wind", "solar"], 10)
>>> dirs_df, coords_df = n.optimize.optimize_mga_in_multiple_directions(
... directions, dimensions, max_parallel=2
... )
>>> dirs_df
wind solar
0 0.958766 0.284198
1 -0.937432 -0.348170
2 -0.805652 0.592389
...
>>> coords_df
wind solar
0 0.0 0.0
1 0.0 0.0
2 0.0 0.0
...
pypsa.Network.optimize.optimize_security_constrained
ΒΆ
optimize_security_constrained(
snapshots: Sequence | None = None,
branch_outages: Sequence
| Index
| MultiIndex
| None = None,
multi_investment_periods: bool = False,
model_kwargs: dict | None = None,
**kwargs: Any,
) -> tuple[str, str]
Compute Security-Constrained Linear Optimal Power Flow (SCLOPF).
This ensures that no branch is overloaded even given the branch outages.
Parameters:
-
snapshots(list - like, default:None) βSet of snapshots to consider in the optimization. The default is None.
-
branch_outages(list - like / Index / MultiIndex, default:None) βSubset of passive branches to consider as possible outages. If a list or a pandas.Index is passed, it is assumed to identify lines. If a multiindex is passed, its first level has to contain the component names, the second the assets. The default None results in all passive branches to be considered.
-
multi_investment_periods(bool, default:False) βWhether to optimise as a single investment period or to optimise in multiple investment periods. Then, snapshots should be a
pd.MultiIndex. -
model_kwargs(dict, default:None) βKeyword arguments used by
linopy.Model, such assolver_dirorchunk. Defaults to module wide option (default: {}). Seehttps://go.pypsa.org/options-paramsfor more information. -
**kwargs(Any, default:{}) βKeyword argument used by
linopy.Model.solve, such assolver_name,problem_fnor solver options directly passed to the solver.
pypsa.Network.optimize.optimize_transmission_expansion_iteratively
ΒΆ
optimize_transmission_expansion_iteratively(
snapshots: Sequence | None = None,
msq_threshold: float = 0.05,
min_iterations: int = 1,
max_iterations: int = 100,
track_iterations: bool = False,
line_unit_size: float | None = None,
link_unit_size: dict | None = None,
line_threshold: float | None = None,
link_threshold: dict | None = None,
fractional_last_unit_size: bool = False,
**kwargs: Any,
) -> tuple[str, str]
Run iterative linear optimization.
Updating the line parameters for passive AC and DC lines. This is helpful when line expansion is enabled. After each successful solving, line impedances and line resistance are recalculated based on the optimization result. If warmstart is possible, it uses the result from the previous iteration to fasten the optimization.
Parameters:
-
snapshots(list or index slice, default:None) βA list of snapshots to optimise, must be a subset of n.snapshots, defaults to n.snapshots
-
msq_threshold(float, default:0.05) βMaximal mean square difference between optimized line capacity of the current and the previous iteration. As soon as this threshold is undercut, and the number of iterations is bigger than 'min_iterations' the iterative optimization stops
-
min_iterations(integer, default:1) βMinimal number of iteration to run regardless whether the msq_threshold is already undercut
-
max_iterations(integer, default:100) βMaximal number of iterations to run regardless whether msq_threshold is already undercut
-
track_iterations(bool, default:False) βIf True, the intermediate branch capacities and values of the objective function are recorded for each iteration. The values of iteration 0 represent the initial state.
-
line_unit_size(float | None, default:None) βThe unit size for line components. Use None if no discretization is desired.
-
link_unit_size(dict | None, default:None) βA dictionary containing the unit sizes for link components, with carrier names as keys. Use None if no discretization is desired.
-
line_threshold(float | None, default:None) βThe threshold relative to the unit size for discretizing line components.
-
link_threshold(dict | None, default:None) βThe threshold relative to the unit size for discretizing link components.
-
fractional_last_unit_size(bool, default:False) βWhether only multiples of the unit size or in case of a maximum capacity fractions of unit size is allowed.
-
**kwargs(Any, default:{}) βKeyword arguments of the
n.optimizefunction which runs at each iteration
pypsa.Network.optimize.optimize_with_rolling_horizon
ΒΆ
optimize_with_rolling_horizon(
snapshots: Sequence | None = None,
horizon: int = 100,
overlap: int = 0,
**kwargs: Any,
) -> Network
Optimizes the network in a rolling horizon fashion.
Parameters:
-
snapshots(list - like, default:None) βSet of snapshots to consider in the optimization. The default is None.
-
horizon(int, default:100) βNumber of snapshots to consider in each iteration. Defaults to 100.
-
overlap(int, default:0) βNumber of snapshots to overlap between two iterations. Defaults to 0.
-
**kwargs(Any, default:{}) βKeyword argument used by
linopy.Model.solve, such assolver_name,
pypsa.Network.optimize.post_processing
ΒΆ
post_processing() -> None
Post-process the optimized network.
This calculates quantities derived from the optimized values such as power injection per bus and snapshot, voltage angle.
pypsa.Network.optimize.project_solved
ΒΆ
project_solved(dimensions: dict) -> Series
Project solved model onto low-dimensional space.
Parameters:
-
dimensions(dict) βA dictionary representing the dimensions of the low-dimensional space. The keys are user-defined names for the dimensions (matching those in the
directionargument), and the values are dictionaries with the same structure as theweightsargument inoptimize_mga.
Returns:
-
SeriesβA pd.Series representing the coordinates of a solved network in the dimensions given by the user. The index consists of the keys in the
dimensionsargument; values are floats.
pypsa.Network.optimize.solve_model
ΒΆ
solve_model(
extra_functionality: Callable | None = None,
solver_name: str | None = None,
solver_options: dict | None = None,
assign_all_duals: bool = False,
**kwargs: Any,
) -> tuple[str, str]
Solve an already created model and assign its solution to the network.
Parameters:
-
extra_functionality(callable, default:None) βThis function must take two arguments
extra_functionality(n, snapshots)and is called after the model building is complete, but before it is sent to the solver. It allows the user to add/change constraints and add/change the objective function. -
solver_name(str | None, default:None) βName of the solver to use. Defaults to module wide option (default: 'highs'). See
https://go.pypsa.org/options-paramsfor more information. -
solver_options(dict | None, default:None) βKeyword arguments used by the solver. Defaults to module wide option (default: {}). Can also be passed via
**kwargs. Seehttps://go.pypsa.org/options-paramsfor more information. -
assign_all_duals(bool, default:False) βWhether to assign all dual values or only those that already have a designated place in the network.
-
**kwargs(Any, default:{}) βKeyword argument used by
linopy.Model.solve, such assolver_name,problem_fnor solver options directly passed to the solver.
Returns:
-
status(str) βThe status of the optimization, either "ok" or one of the codes listed in linopy.constants.SolverStatus
-
condition(str) βThe termination condition of the optimization, either "optimal" or one of the codes listed in linopy.constants.TerminationCondition
mga
ΒΆ
Run modelling-to-generate-alternatives (MGA) optimizations.
Functions:
-
generate_directions_evenly_spacedβGenerate evenly spaced directions in a 2D space.
-
generate_directions_haltonβGenerate directions using a Halton sequence for MGA in a given low-dimensional space.
-
generate_directions_randomβGenerate random directions for MGA in a given low-dimensional space.
pypsa.optimization.mga.generate_directions_evenly_spaced
ΒΆ
generate_directions_evenly_spaced(
keys: Sequence[str], n_directions: int
) -> DataFrame
Generate evenly spaced directions in a 2D space.
This function generates directions that are uniformly distributed on a unit circle. It only supports exactly two keys (dimensions).
Parameters:
-
keys(Sequence[str]) βA sequence of exactly two strings representing the keys (dimensions) for which to generate evenly spaced directions.
-
n_directions(int) βThe number of evenly spaced directions to generate.
Returns:
-
DataFrameβA DataFrame containing the generated evenly spaced directions, where each row represents a direction and each column corresponds to a key from
keys.
pypsa.optimization.mga.generate_directions_halton
ΒΆ
generate_directions_halton(
keys: Sequence[str],
n_directions: int,
seed: int | None = None,
) -> DataFrame
Generate directions using a Halton sequence for MGA in a given low-dimensional space.
The directions are normalized to unit vectors, providing a quasi-random distribution that tends to fill the space more uniformly than a purely random sequence.
Parameters:
-
keys(Sequence[str]) βA sequence of strings representing the keys (dimensions) for which to generate directions.
-
n_directions(int) βThe number of directions to generate.
-
seed(int | None, default:None) βA seed for the random number generator to ensure reproducibility when initializing the Halton sampler. If None, a random seed will be used. Defaults to None.
Returns:
-
DataFrameβA DataFrame containing the generated directions, where each row represents a direction and each column corresponds to a key from
keys.
pypsa.optimization.mga.generate_directions_random
ΒΆ
generate_directions_random(
keys: Sequence[str],
n_directions: int,
seed: int | None = None,
) -> DataFrame
Generate random directions for MGA in a given low-dimensional space.
The directions are normalized to unit vectors.
Parameters:
-
keys(Sequence[str]) βA sequence of strings representing the keys (dimensions) for which to generate random directions.
-
n_directions(int) βThe number of random directions to generate.
-
seed(int | None, default:None) βA seed for the random number generator to ensure reproducibility. If None, a random seed will be used. Defaults to None.
Returns:
-
DataFrameβA DataFrame containing the generated random directions, where each row represents a direction and each column corresponds to a key from
keys.