MESQUAL Congestion Rent Calculator¶
CongestionRentCalculator
dataclass
¶
Calculates congestion rents for electricity transmission lines.
Congestion rent represents the economic value captured by transmission assets due to price differences between nodes. It's calculated as the product of power flow, price spread, and time granularity.
The calculator handles bidirectional flows (up/down) and accounts for transmission losses by using separate sent and received quantities. This provides accurate congestion rent calculations that reflect actual market conditions and physical constraints.
Mathematical formulation: - Congestion rent (up) = granularity × (received_up × price_to - sent_up × price_from) - Congestion rent (down) = granularity × (received_down × price_from - sent_down × price_to) - Total congestion rent = congestion_rent_up + congestion_rent_down
Attributes:
| Name | Type | Description |
|---|---|---|
sent_up |
Series
|
Power sent in up direction (MW or MWh) |
received_up |
Series
|
Power received in up direction after losses (MW or MWh) |
sent_down |
Series
|
Power sent in down direction (MW or MWh) |
received_down |
Series
|
Power received in down direction after losses (MW or MWh) |
price_node_from |
Series
|
Price at sending node (€/MWh) |
price_node_to |
Series
|
Price at receiving node (€/MWh) |
granularity_hrs |
Series | float
|
Time granularity in hours (auto-detected if None) |
Example:
>>> import pandas as pd
>>> # Time series data
>>> index = pd.date_range('2024-01-01', periods=3, freq='h')
>>> # Flow and price data
>>> calc = CongestionRentCalculator(
... sent_up=pd.Series([100, 150, 200], index=index),
... received_up=pd.Series([95, 142, 190], index=index), # 5% losses
... sent_down=pd.Series([50, 75, 100], index=index),
... received_down=pd.Series([48, 71, 95], index=index), # 4% losses
... price_node_from=pd.Series([45, 50, 55], index=index),
... price_node_to=pd.Series([65, 70, 75], index=index)
... )
>>> total_rent = calc.calculate()
>>> print(total_rent) # Congestion rent in €
Source code in submodules/mesqual/mesqual/energy_data_handling/variable_utils/congestion_rent.py
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 | |
congestion_rent_up
property
¶
congestion_rent_up: Series
Calculate congestion rent for up direction flows.
Returns:
| Type | Description |
|---|---|
Series
|
Series with congestion rents in up direction (€) |
congestion_rent_down
property
¶
congestion_rent_down: Series
Calculate congestion rent for down direction flows.
Returns:
| Type | Description |
|---|---|
Series
|
Series with congestion rents in down direction (€) |
congestion_rent_total
property
¶
congestion_rent_total: Series
Calculate total congestion rent (sum of up and down directions).
Returns:
| Type | Description |
|---|---|
Series
|
Series with total congestion rents (€) |
__post_init__
¶
__post_init__()
Initialize granularity and validate input consistency.
Source code in submodules/mesqual/mesqual/energy_data_handling/variable_utils/congestion_rent.py
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | |
__check_indices
¶
__check_indices()
Validate that all input Series have matching indices.
Raises:
| Type | Description |
|---|---|
ValueError
|
If any Series has mismatched index with sent_up |
Source code in submodules/mesqual/mesqual/energy_data_handling/variable_utils/congestion_rent.py
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | |
calculate
¶
calculate() -> Series
Calculate total congestion rent (convenience method).
Returns:
| Type | Description |
|---|---|
Series
|
Series with total congestion rents in € (same as congestion_rent_total property) |
Source code in submodules/mesqual/mesqual/energy_data_handling/variable_utils/congestion_rent.py
129 130 131 132 133 134 135 | |
from_net_flow_without_losses
classmethod
¶
from_net_flow_without_losses(net_flow: Series, price_node_from: Series, price_node_to: Series, granularity_hrs: float = None) -> Series
Calculate congestion rent from net flow data assuming no losses.
Convenience method for cases where transmission losses are negligible or not available. Splits net flow into unidirectional components and assumes sent equals received for each direction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
net_flow
|
Series
|
Net power flow (positive = up direction, negative = down direction) in MW or MWh |
required |
price_node_from
|
Series
|
Price at sending node (€/MWh) |
required |
price_node_to
|
Series
|
Price at receiving node (€/MWh) |
required |
granularity_hrs
|
float
|
Time granularity in hours (auto-detected if None) |
None
|
Returns:
| Type | Description |
|---|---|
Series
|
Series with total congestion rents in € |
Example:
>>> # Net flow with price data
>>> net_flow = pd.Series([100, -50, 75], index=time_index)
>>> rent = CongestionRentCalculator.from_net_flow_without_losses(
... net_flow, price_from, price_to
... )
Source code in submodules/mesqual/mesqual/energy_data_handling/variable_utils/congestion_rent.py
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | |
from_up_and_down_flow_without_losses
classmethod
¶
from_up_and_down_flow_without_losses(flow_up: Series, flow_down: Series, price_node_from: Series, price_node_to: Series, granularity_hrs: float = None) -> Series
Calculate congestion rent from bidirectional flow data assuming no losses.
Convenience method for cases where flows are already separated into up/down directions and transmission losses are negligible. Assumes sent equals received for each direction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
flow_up
|
Series
|
Power flow in up direction (MW or MWh, non-negative) |
required |
flow_down
|
Series
|
Power flow in down direction (MW or MWh, non-negative) |
required |
price_node_from
|
Series
|
Price at sending node (€/MWh) |
required |
price_node_to
|
Series
|
Price at receiving node (€/MWh) |
required |
granularity_hrs
|
float
|
Time granularity in hours (auto-detected if None) |
None
|
Returns:
| Type | Description |
|---|---|
Series
|
Series with total congestion rents in € |
Example:
>>> # Separate up/down flows
>>> flow_up = pd.Series([100, 0, 75], index=time_index)
>>> flow_down = pd.Series([0, 50, 0], index=time_index)
>>> rent = CongestionRentCalculator.from_up_and_down_flow_without_losses(
... flow_up, flow_down, price_from, price_to
... )
Source code in submodules/mesqual/mesqual/energy_data_handling/variable_utils/congestion_rent.py
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 | |