Demand share per timestep as decision variable¶
Description¶
Allows the model to decide on how a unitless of demand for a carrier is met by the given group of technologies, which will each have the same share in each timestep.
Variables and constraints defined here could be extended to iterate over nodes and over carriers if desired.
If summing over nodes, remove the summation over nodes in the constraints and add it into the list in demand_share_per_timestep_decision_sum (if using).
If summing over carriers, the slicing of sink_use_equals will need to change per carrier by using a where statement in slices: ....
The share is relative to the flow sink from a specified demand technology (or group thereof) only.
Specifying relaxation inside the constraint to a non-zero value allows the constraint some flexibility around a given value, making a model easier to solve.
New indexed parameters:
relaxation(defined here directly)demand_share_limit(defined here directly)
Helper functions used:
- sum (expression)
- select_from_lookup_arrays (expression)
YAML definition¶
parameters:
demand_share_relaxation:
description: >-
If given, the degree to which total demand share can deviate from demand_share_limit.
That is, (lhs == rhs -> lhs >= 0.99 * rhs & lhs <= 1.01 * rhs).
0 == no relaxation, 0.01 == 1% relaxation.
This is usually only required to mitigate against numerical trouble when solving.
default: 0
unit: unitless
demand_share_limit:
description: The total share of demand that the technologies must meet in total.
default: 1
unit: unitless
lookups:
decide_demand_share:
description: >-
Link between a generating technology and the consuming (i.e., demand)
technology whose inflow they will be generating a share of.
dtype: string
demand_share_carrier:
description: The carrier that is being tracked between generating and consuming technologies when setting the demand share.
dtype: string
variables:
demand_share_per_timestep_decision:
description: >
Relative share of demand that a given technology must meet per node.
unit: unitless
default: 0
foreach: [nodes, techs]
where: decide_demand_share
bounds:
min: 0
max: .inf
checks:
demand_share_is_fraction:
where: demand_share_limit > 1 OR demand_share_limit < 0
message: The demand share limit must be a fraction of demand, i.e. between 0 and 1.
errors: raise
# The two main constraints enforce that the shares are the same in each timestep,
# with an optional relaxation.
constraints:
demand_share_per_timestep_decision_main_min:
description: >-
Limit the lower bound of a technology's outflow to the share of demand
that the model has decided it will meet.
foreach: [nodes, techs, timesteps]
where: demand_share_per_timestep_decision
equations:
- expression: >
flow_out[carriers=$carrier] >=
(1 - demand_share_relaxation)
* select_from_lookup_arrays(sink_use_equals, techs=decide_demand_share)
* demand_share_per_timestep_decision
slices: &slice
carrier:
- expression: demand_share_carrier # assigned as an indexed parameter
demand_share_per_timestep_decision_main_max:
description: >-
Limit the upper bound of a technology's outflow to
the share of demand that the model has decided it will meet.
foreach: [nodes, techs, timesteps]
where: demand_share_per_timestep_decision
equations:
- expression: >
flow_out[carriers=$carrier] <=
(1 + demand_share_relaxation)
* select_from_lookup_arrays(sink_use_equals, techs=decide_demand_share)
* demand_share_per_timestep_decision
slices: *slice
# The optional additional sum constraint ensures that all decision shares add up
# to a specified share of carrier demand (here, 50% = 0.5 of electricity demand).
demand_share_per_timestep_decision_sum:
description: >-
Limit the total share of demand that can be met by technologies controlled
by the `demand_share_per_timestep_decision` variable.
foreach: [nodes, timesteps]
where: demand_share_per_timestep_decision AND demand_share_limit
equations:
- expression: >
sum(demand_share_per_timestep_decision, over=[techs])
== demand_share_limit