Conversation
Equality constraints would require binary variables to identify the segments wouldn't it? |
fneum
left a comment
There was a problem hiding this comment.
Very nice! Thanks @lindnemi! I like that the option to go with tangents is kept.
I have some suggestions for handling the keyword arguments and perhaps @lkstrp can chip in on making the transition as smooth as possible.
A short unit test could be added to assert that losses in secant are >= tangent mode.
pypsa/optimization/constraints.py
Outdated
| transmission_losses: int, | ||
| mode: str = "secants", |
There was a problem hiding this comment.
| transmission_losses: int, | |
| mode: str = "secants", | |
| transmission_losses: int, # deprecate, use max_segments instead | |
| atol: float = 1, | |
| rtol: float = 0.1, | |
| max_segments = 30, | |
| mode: str = "secants", |
I would give a few more new keyword arguments here. The argument transmission_losses was never well designed and I would suggest to deprecate it here.
What is still needed is that the arguments can be passed through n.optimize() and n.optimize.create_model() (everywhere where transmission_losses shows up and define_loss_constraints is called).
Maybe here, the arguments could be bundled in a dictionary for transmission_losses?
n.optimize(
transmission_losses: int | dict = 0
)
transmission_losses = dict(
max_segments = 10,
atol = 10,
rtol = 0.2,
mode = "secants",
)
transmission_losses = dict(
max_segments = 3,
mode = "tangents",
)Maybe @lkstrp can help with making the transition as smooth as possible and has an idea for a good keyword argument design.
The default should probably stay as tangents for now, and change with a future version.
|
Thank you @fneum for the quick review and the valuable suggestions. I implemented the changes and refactored the code for computing the secants one last time. By algebraically rearranging the computation, it was possible to improve the numerical stability, s.t. the offsets should all be the same now (before that there were some very small rounding errors, which should not impact results, but potentially solver speed??) I also sketched a potential interface for tranmissions losses based on dicts, and a few unit tests. @lkstrp maybe you can take over from here? Of course i am very happy to support if any questions arise. |
|
btw, i noticed that for passive branch components like
@fneum
In the screenshot there is also a UserWarning visbile: @lkstrp do you if this is because i introduced the new |
What you are showing there is just the solution, which is a single xarray dataset and shares a single And the user warning should be gone if you update to I need to properly understand this and have a detailed look. But sure all the API stuff, tests etc I can take over. What about docs? Can you write up something about the additional formulation? https://docs.pypsa.org/latest/user-guide/optimization/power-flow/?h=line+loss#loss-approximation |
Yes, that was a misunderstanding on my side.
I am actually using linopy 0.5.8.
I didn't know we had docs on line losses, but that's great, I will write something up.
Great, thanks! The new secant formulation should become the default with the next PyPSA version. So maybe we need some deprecation warnings? |

Closes #1320.
Closes #1470.
Improved version of #1470.
Related to #1409.
Changes proposed in this Pull Request
Make the approximation of the loss parabola independent of
s_nom_max. To be able to do this a bound for the approximation error is needed, which has the added benefit of giving more fine-grained control of the approximation quality. Here an error bound based on absolute and relative error tolerances is used. This fixes Changings_nom_maxaffects line losses #1320.Use secants instead of tangents for the approximation. That way, the approximation error is zero at the "corners" of the stepwise linear approximation. Since the optimum of the linear program tends to be located at a corner, this will hopefully reduce the effective error of the loss approximation
Introduce lines losses close to 0. At the moment, flows smaller than
s_nom_max/(2*n_tangents)are lossless.Example
Here is a plot of how the approximation with secants for an exemplary line looks like with
atol = 1 #MWandrtol = 0.1. I chose the parameters such that the numbers of loss constraints is relatively small.The approximation could be improved by setting the endpoint of the last secant to
s_nom_max. However, that would re-introduce a dependency ons_nom_maxand should ideally only be done when it can be guaranteed that s_nom_max does not change between consecutive runs of the model.Questions
s_nom_max? Of course a similar approximation with tangents could be constructed. However, that would underestimate the error ats_nom_max.Should we use equality constraints instead of inequality constraints? The plot in Improving transmission loss approximation for DC power flow #1409 suggests that there are many snapshots when the losses are bigger than they should be, i.e. the model uses them to destroy energy.Derivation of formulas for relative and absolute error
Find a piecewise linear approximation$l(x)$ of the loss parabola $L(x) := rx^2$ on $[0, X]$ with:
We want the endpoints to be on the parabola, since the optimal solution tends to be on the corners of a simplex, and hence that is where the approximation should be best.
(2) implies that our approximation consists of secants. Denote the endpoints of a secant as$a,b$ then
The absolute error$AE(x)$ between $l_{ab}(x)$ and $L(x)$ is
This is positive for$a < x < b$ , since there the secant is above the parabola. To compute it's maximum, remember that the derivative has to be 0.
Hence the error is maximal at the midpoint. Assume we specify the absolute error tolerance as$\varepsilon$ . From this we can compute the interval length $b-a$
which implies$b(a, \varepsilon) = 2\sqrt{\frac{\varepsilon}{r}} + a$ .
Hence, to construct an approximation with absolute error at most$\varepsilon$ , we choose the endpoints of the secants at $x_i = \dots, -4\sqrt{\frac{\varepsilon}{r}}, -2\sqrt{\frac{\varepsilon}{r}}, 0, 2\sqrt{\frac{\varepsilon}{r}}, 4\sqrt{\frac{\varepsilon}{r}}, \dots$
For small error tolerances and large line flows we might need many secants, which would translate to many additional constraint and slow down solving. So, in this case we will use an approximation based on the relative error instead.
The relative error is
It's derivative is$\frac{2ab - (a+b)x}{x^3}$ , which is zero at $x_{max}=\frac{2ab}{a+b}$ .$\delta$ we get:
Assuming the relative error tolerance is
We want to build a step rule$b(a)$ to construct a new end point $b$ from a given starting point $a$ . Hence we rewrite the equation above as a polynomial in $b$ with constants $a$ and $\delta$ :
This polynomial has the roots$b = a(1 + 2\delta \pm 2\sqrt{\delta(1+\delta)})$ . It can be shown that the root with $a$ . Since we want $b>a$ we take the other root and get
-term is smaller thanFor small$a$ this gets very impractically small. Therefore we use the step based on absolute error for small $a$ , and the step based on relative error for large $a$ . Combined we have
We compute new endpoints until$x_I > X$ . Then $l(x) = \sum_{i=0}^I l_{x_{i}x_{i+1}}(x)$ .
Checklist
docs.docs/release-notes.mdof the upcoming release is included.