Skip to content

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

Download the YAML example

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