Mathematical formulation

This section details the mathematical formulation of the different components. For each component, a link to the actual implementing function in the Calliope code is given.

Decision variables

calliope.backend.pyomo.variables.initialize_decision_variables(backend_model)[source]

Defines decision variables.

Variable Dimensions
energy_cap loc_techs
carrier_prod loc_tech_carriers_prod, timesteps
carrier_con loc_tech_carriers_con, timesteps
cost costs, loc_techs_cost
resource_area loc_techs_area,
storage_cap loc_techs_store
storage loc_techs_store, timesteps
resource_con loc_techs_supply_plus, timesteps
resource_cap loc_techs_supply_plus
carrier_export loc_tech_carriers_export, timesteps
cost_var costs, loc_techs_om_cost, timesteps
cost_investment costs, loc_techs_investment_cost
purchased loc_techs_purchase
units loc_techs_milp
operating_units loc_techs_milp, timesteps
unmet_demand loc_carriers, timesteps

Objective functions

calliope.backend.pyomo.objective.minmax_cost_optimization(backend_model, cost_class, sense)[source]

Minimize or maximise total system cost for specified cost class.

If unmet_demand is in use, then the calculated cost of unmet_demand is added or subtracted from the total cost in the opposite sense to the objective.

\[min: z = \sum_{loc::tech_{cost}} cost(loc::tech, cost=cost_{k})) + \sum_{loc::carrier,timestep} unmet\_demand(loc::carrier, timestep) \times bigM max: z = \sum_{loc::tech_{cost}} cost(loc::tech, cost=cost_{k})) - \sum_{loc::carrier,timestep} unmet\_demand(loc::carrier, timestep) \times bigM\]
calliope.backend.pyomo.objective.check_feasibility(backend_model, **kwargs)[source]

Dummy objective, to check that there are no conflicting constraints.

\[min: z = 1\]

Constraints

Energy Balance

calliope.backend.pyomo.constraints.energy_balance.system_balance_constraint_rule(backend_model, loc_carrier, timestep)[source]

System balance ensures that, within each location, the production and consumption of each carrier is balanced.

\[\sum_{loc::tech::carrier_{prod} \in loc::carrier} \boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep) + \sum_{loc::tech::carrier_{con} \in loc::carrier} \boldsymbol{carrier_{con}}(loc::tech::carrier, timestep) + \sum_{loc::tech::carrier_{export} \in loc::carrier} \boldsymbol{carrier_{export}}(loc::tech::carrier, timestep) \quad \forall loc::carrier \in loc::carriers, \forall timestep \in timesteps\]
calliope.backend.pyomo.constraints.energy_balance.balance_supply_constraint_rule(backend_model, loc_tech, timestep)[source]

Limit production from supply techs to their available resource

\[min\_use(loc::tech) \times available\_resource(loc::tech, timestep) \leq \frac{\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep)}{\eta_{energy}(loc::tech, timestep)} \geq available\_resource(loc::tech, timestep) \quad \forall loc::tech \in loc::techs_{supply}, \forall timestep \in timesteps\]

If \(force\_resource(loc::tech)\) is set:

\[\frac{\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep)}{\eta_{energy}(loc::tech, timestep)} = available\_resource(loc::tech, timestep) \quad \forall loc::tech \in loc::techs_{supply}, \forall timestep \in timesteps\]

Where:

\[available\_resource(loc::tech, timestep) = resource(loc::tech, timestep) \times resource\_scale(loc::tech)\]

if \(loc::tech\) is in \(loc::techs_{area}\):

\[available\_resource(loc::tech, timestep) = resource(loc::tech, timestep) \times resource\_scale(loc::tech) \times \boldsymbol{resource_{area}}(loc::tech)\]
calliope.backend.pyomo.constraints.energy_balance.balance_demand_constraint_rule(backend_model, loc_tech, timestep)[source]

Limit consumption from demand techs to their required resource.

\[\boldsymbol{carrier_{con}}(loc::tech::carrier, timestep) \times \eta_{energy}(loc::tech, timestep) \geq required\_resource(loc::tech, timestep) \quad \forall loc::tech \in loc::techs_{demand}, \forall timestep \in timesteps\]

If \(force\_resource(loc::tech)\) is set:

\[\boldsymbol{carrier_{con}}(loc::tech::carrier, timestep) \times \eta_{energy}(loc::tech, timestep) = required\_resource(loc::tech, timestep) \quad \forall loc::tech \in loc::techs_{demand}, \forall timestep \in timesteps\]

Where:

\[required\_resource(loc::tech, timestep) = resource(loc::tech, timestep) \times resource\_scale(loc::tech)\]

if \(loc::tech\) is in \(loc::techs_{area}\):

\[required\_resource(loc::tech, timestep) = resource(loc::tech, timestep) \times resource\_scale(loc::tech) \times \boldsymbol{resource_{area}}(loc::tech)\]
calliope.backend.pyomo.constraints.energy_balance.resource_availability_supply_plus_constraint_rule(backend_model, loc_tech, timestep)[source]

Limit production from supply_plus techs to their available resource.

\[\boldsymbol{resource_{con}}(loc::tech, timestep) \leq available\_resource(loc::tech, timestep) \quad \forall loc::tech \in loc::techs_{supply^{+}}, \forall timestep \in timesteps\]

If \(force\_resource(loc::tech)\) is set:

\[\boldsymbol{resource_{con}}(loc::tech, timestep) = available\_resource(loc::tech, timestep) \quad \forall loc::tech \in loc::techs_{supply^{+}}, \forall timestep \in timesteps\]

Where:

\[available\_resource(loc::tech, timestep) = resource(loc::tech, timestep) \times resource_{scale}(loc::tech)\]

if \(loc::tech\) is in \(loc::techs_{area}\):

\[available\_resource(loc::tech, timestep) = resource(loc::tech, timestep) \times resource_{scale}(loc::tech) \times resource_{area}(loc::tech)\]
calliope.backend.pyomo.constraints.energy_balance.balance_transmission_constraint_rule(backend_model, loc_tech, timestep)[source]

Balance carrier production and consumption of transmission technologies

\[-1 * \boldsymbol{carrier_{con}}(loc_{from}::tech:loc_{to}::carrier, timestep) \times \eta_{energy}(loc::tech, timestep) = \boldsymbol{carrier_{prod}}(loc_{to}::tech:loc_{from}::carrier, timestep) \quad \forall loc::tech:loc \in locs::techs:locs_{transmission}, \forall timestep \in timesteps\]

Where a link is the connection between \(loc_{from}::tech:loc_{to}\) and \(loc_{to}::tech:loc_{from}\) for locations to and from.

calliope.backend.pyomo.constraints.energy_balance.balance_supply_plus_constraint_rule(backend_model, loc_tech, timestep)[source]

Balance carrier production and resource consumption of supply_plus technologies alongside any use of resource storage.

\[\boldsymbol{storage}(loc::tech, timestep) = \boldsymbol{storage}(loc::tech, timestep_{previous}) \times (1 - storage\_loss(loc::tech, timestep))^{timestep\_resolution(timestep)} + \boldsymbol{resource_{con}}(loc::tech, timestep) \times \eta_{resource}(loc::tech, timestep) - \frac{\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep)}{\eta_{energy}(loc::tech, timestep) \times \eta_{parasitic}(loc::tech, timestep)} \quad \forall loc::tech \in loc::techs_{supply^{+}}, \forall timestep \in timesteps\]

If no storage is defined for the technology, this reduces to:

\[\boldsymbol{resource_{con}}(loc::tech, timestep) \times \eta_{resource}(loc::tech, timestep) = \frac{\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep)}{\eta_{energy}(loc::tech, timestep) \times \eta_{parasitic}(loc::tech, timestep)} \quad \forall loc::tech \in loc::techs_{supply^{+}}, \forall timestep \in timesteps\]
calliope.backend.pyomo.constraints.energy_balance.balance_storage_constraint_rule(backend_model, loc_tech, timestep)[source]

Balance carrier production and consumption of storage technologies, alongside any use of the stored volume.

\[\boldsymbol{storage}(loc::tech, timestep) = \boldsymbol{storage}(loc::tech, timestep_{previous}) \times (1 - storage\_loss(loc::tech, timestep))^{resolution(timestep)} - \boldsymbol{carrier_{con}}(loc::tech::carrier, timestep) \times \eta_{energy}(loc::tech, timestep) - \frac{\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep)}{\eta_{energy}(loc::tech, timestep)} \quad \forall loc::tech \in loc::techs_{storage}, \forall timestep \in timesteps\]

Capacity

calliope.backend.pyomo.constraints.capacity.storage_capacity_constraint_rule(backend_model, loc_tech)[source]

Set maximum storage capacity. Supply_plus & storage techs only

The first valid case is applied:

\[\begin{split}\boldsymbol{storage_{cap}}(loc::tech) \begin{cases} = storage_{cap, equals}(loc::tech),& \text{if } storage_{cap, equals}(loc::tech)\\ \leq storage_{cap, max}(loc::tech),& \text{if } storage_{cap, max}(loc::tech)\\ \text{unconstrained},& \text{otherwise} \end{cases} \forall loc::tech \in loc::techs_{store}\end{split}\]

and (if equals not enforced):

\[\boldsymbol{storage_{cap}}(loc::tech) \geq storage_{cap, min}(loc::tech) \quad \forall loc::tech \in loc::techs_{store}\]
calliope.backend.pyomo.constraints.capacity.energy_capacity_storage_constraint_rule(backend_model, loc_tech)[source]

Set an additional energy capacity constraint on storage technologies, based on their use of charge_rate.

\[\boldsymbol{energy_{cap}}(loc::tech) \leq \boldsymbol{storage_{cap}}(loc::tech) \times charge\_rate(loc::tech) \quad \forall loc::tech \in loc::techs_{store}\]
calliope.backend.pyomo.constraints.capacity.resource_capacity_constraint_rule(backend_model, loc_tech)[source]

Add upper and lower bounds for resource_cap.

The first valid case is applied:

\[\begin{split}\boldsymbol{resource_{cap}}(loc::tech) \begin{cases} = resource_{cap, equals}(loc::tech),& \text{if } resource_{cap, equals}(loc::tech)\\ \leq resource_{cap, max}(loc::tech),& \text{if } resource_{cap, max}(loc::tech)\\ \text{unconstrained},& \text{otherwise} \end{cases} \forall loc::tech \in loc::techs_{finite\_resource\_supply\_plus}\end{split}\]

and (if equals not enforced):

\[\boldsymbol{resource_{cap}}(loc::tech) \geq resource_{cap, min}(loc::tech) \quad \forall loc::tech \in loc::techs_{finite\_resource\_supply\_plus}\]
calliope.backend.pyomo.constraints.capacity.resource_capacity_equals_energy_capacity_constraint_rule(backend_model, loc_tech)[source]

Add equality constraint for resource_cap to equal energy_cap, for any technologies which have defined resource_cap_equals_energy_cap.

\[\boldsymbol{resource_{cap}}(loc::tech) = \boldsymbol{energy_{cap}}(loc::tech) \quad \forall loc::tech \in loc::techs_{finite\_resource\_supply\_plus} \text{ if } resource\_cap\_equals\_energy\_cap = \text{True}\]
calliope.backend.pyomo.constraints.capacity.resource_area_constraint_rule(backend_model, loc_tech)[source]

Set upper and lower bounds for resource_area.

The first valid case is applied:

\[\begin{split}\boldsymbol{resource_{area}}(loc::tech) \begin{cases} = resource_{area, equals}(loc::tech),& \text{if } resource_{area, equals}(loc::tech)\\ \leq resource_{area, max}(loc::tech),& \text{if } resource_{area, max}(loc::tech)\\ \text{unconstrained},& \text{otherwise} \end{cases} \forall loc::tech \in loc::techs_{area}\end{split}\]

and (if equals not enforced):

\[\boldsymbol{resource_{area}}(loc::tech) \geq resource_{area, min}(loc::tech) \quad \forall loc::tech \in loc::techs_{area}\]
calliope.backend.pyomo.constraints.capacity.resource_area_per_energy_capacity_constraint_rule(backend_model, loc_tech)[source]

Add equality constraint for resource_area to equal a percentage of energy_cap, for any technologies which have defined resource_area_per_energy_cap

\[\boldsymbol{resource_{area}}(loc::tech) = \boldsymbol{energy_{cap}}(loc::tech) \times area\_per\_energy\_cap(loc::tech) \quad \forall loc::tech \in locs::techs_{area} \text{ if } area\_per\_energy\_cap(loc::tech)\]
calliope.backend.pyomo.constraints.capacity.resource_area_capacity_per_loc_constraint_rule(backend_model, loc)[source]

Set upper bound on use of area for all locations which have available_area constraint set. Does not consider resource_area applied to demand technologies

\[\sum_{tech} \boldsymbol{resource_{area}}(loc::tech) \leq available\_area \quad \forall loc \in locs \text{ if } available\_area(loc)\]
calliope.backend.pyomo.constraints.capacity.energy_capacity_constraint_rule(backend_model, loc_tech)[source]

Set upper and lower bounds for energy_cap.

The first valid case is applied:

\[\begin{split}\frac{\boldsymbol{energy_{cap}}(loc::tech)}{energy_{cap, scale}(loc::tech)} \begin{cases} = energy_{cap, equals}(loc::tech),& \text{if } energy_{cap, equals}(loc::tech)\\ \leq energy_{cap, max}(loc::tech),& \text{if } energy_{cap, max}(loc::tech)\\ \text{unconstrained},& \text{otherwise} \end{cases} \forall loc::tech \in loc::techs\end{split}\]

and (if equals not enforced):

\[\frac{\boldsymbol{energy_{cap}}(loc::tech)}{energy_{cap, scale}(loc::tech)} \geq energy_{cap, min}(loc::tech) \quad \forall loc::tech \in loc::techs\]
calliope.backend.pyomo.constraints.capacity.energy_capacity_systemwide_constraint_rule(backend_model, tech)[source]

Set constraints to limit the capacity of a single technology type across all locations in the model.

The first valid case is applied:

\[\begin{split}\sum_{loc}\boldsymbol{energy_{cap}}(loc::tech) \begin{cases} = energy_{cap, equals, systemwide}(loc::tech),& \text{if } energy_{cap, equals, systemwide}(loc::tech)\\ \leq energy_{cap, max, systemwide}(loc::tech),& \text{if } energy_{cap, max, systemwide}(loc::tech)\\ \text{unconstrained},& \text{otherwise} \end{cases} \forall tech \in techs\end{split}\]

Dispatch

calliope.backend.pyomo.constraints.dispatch.carrier_production_max_constraint_rule(backend_model, loc_tech_carrier, timestep)[source]

Set maximum carrier production. All technologies.

\[\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep) \leq energy_{cap}(loc::tech) \times timestep\_resolution(timestep) \times parasitic\_eff(loc::tec)\]
calliope.backend.pyomo.constraints.dispatch.carrier_production_min_constraint_rule(backend_model, loc_tech_carrier, timestep)[source]

Set minimum carrier production. All technologies except conversion_plus.

\[\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep) \geq energy_{cap}(loc::tech) \times timestep\_resolution(timestep) \times energy_{cap,min\_use}(loc::tec)\]
calliope.backend.pyomo.constraints.dispatch.carrier_consumption_max_constraint_rule(backend_model, loc_tech_carrier, timestep)[source]

Set maximum carrier consumption for demand, storage, and transmission techs.

\[\boldsymbol{carrier_{con}}(loc::tech::carrier, timestep) \geq -1 \times energy_{cap}(loc::tech) \times timestep\_resolution(timestep)\]
calliope.backend.pyomo.constraints.dispatch.resource_max_constraint_rule(backend_model, loc_tech, timestep)[source]

Set maximum resource consumed by supply_plus techs.

\[\boldsymbol{resource_{con}}(loc::tech, timestep) \leq timestep\_resolution(timestep) \times resource_{cap}(loc::tech)\]
calliope.backend.pyomo.constraints.dispatch.storage_max_constraint_rule(backend_model, loc_tech, timestep)[source]

Set maximum stored energy. Supply_plus & storage techs only.

\[\boldsymbol{storage}(loc::tech, timestep) \leq storage_{cap}(loc::tech)\]
calliope.backend.pyomo.constraints.dispatch.ramping_up_constraint_rule(backend_model, loc_tech_carrier, timestep)[source]

Ramping up constraint.

\[diff(loc::tech::carrier, timestep) \leq max\_ramping\_rate(loc::tech::carrier, timestep)\]
calliope.backend.pyomo.constraints.dispatch.ramping_down_constraint_rule(backend_model, loc_tech_carrier, timestep)[source]

Ramping down constraint.

\[-1 \times max\_ramping\_rate(loc::tech::carrier, timestep) \leq diff(loc::tech::carrier, timestep)\]
calliope.backend.pyomo.constraints.dispatch.ramping_constraint(backend_model, loc_tech_carrier, timestep, direction=0)[source]

Ramping rate constraints.

Direction: 0 is up, 1 is down.

\[ \begin{align}\begin{aligned}\boldsymbol{max\_ramping\_rate}(loc::tech::carrier, timestep) = energy_{ramping}(loc::tech, timestep) \times energy_{cap}(loc::tech)\\\boldsymbol{diff}(loc::tech::carrier, timestep) = (carrier_{prod}(loc::tech::carrier, timestep) + carrier_{con}(loc::tech::carrier, timestep)) / timestep\_resolution(timestep) - (carrier_{prod}(loc::tech::carrier, timestep-1) + carrier_{con}(loc::tech::carrier, timestep-1)) / timestep\_resolution(timestep-1)\end{aligned}\end{align} \]

Costs

calliope.backend.pyomo.constraints.costs.cost_constraint_rule(backend_model, cost, loc_tech)[source]

Combine investment and time varying costs into one cost per technology

\[\boldsymbol{cost}(cost, loc::tech) = \boldsymbol{cost_{investment}}(cost, loc::tech) + \sum_{timestep \in timesteps} \boldsymbol{cost_{var}}(cost, loc::tech, timestep)\]
calliope.backend.pyomo.constraints.costs.cost_investment_constraint_rule(backend_model, cost, loc_tech)[source]

Calculate costs from capacity decision variables.

Transmission technologies “exist” at two locations, so their cost is divided by 2.

\[ \begin{align}\begin{aligned}\boldsymbol{cost_{investment}}(cost, loc::tech) = cost_{fractional\_om}(cost, loc::tech) + cost_{fixed\_om}(cost, loc::tech) + cost_{con}(cost, loc::tech)\\cost_{con}(cost, loc::tech) = depreciation\_rate * ts\_weight * (cost_{energy\_cap}(cost, loc::tech) \times \boldsymbol{energy_{cap}}(loc::tech) + cost_{storage\_cap}(cost, loc::tech) \times \boldsymbol{storage_{cap}}(loc::tech) + cost_{resource\_cap}(cost, loc::tech) \times \boldsymbol{resource_{cap}}(loc::tech) + cost_{resource\_area}(cost, loc::tech)) \times \boldsymbol{resource_{area}}(loc::tech)\\\begin{split}depreciation\_rate = \begin{cases} = 1 / plant\_life,& \text{if } interest\_rate = 0\\ = \frac{interest\_rate \times (1 + interest\_rate)^{plant\_life}}{(1 + interest\_rate)^{plant\_life} - 1},& \text{if } interest\_rate \gt 0\\ \end{cases}\end{split}\\ts\_weight = \sum_{timestep \in timesteps} (time\_res(timestep) \times weight(timestep)) \times \frac{1}{8760}\end{aligned}\end{align} \]
calliope.backend.pyomo.constraints.costs.cost_var_constraint_rule(backend_model, cost, loc_tech, timestep)[source]

Calculate costs from time-varying decision variables

\[ \begin{align}\begin{aligned}\boldsymbol{cost_{var}}(cost, loc::tech, timestep) = cost_{prod}(cost, loc::tech, timestep) + cost_{con}(cost, loc::tech, timestep)\\cost_{prod}(cost, loc::tech, timestep) = cost_{om\_prod}(cost, loc::tech, timestep) \times weight(timestep) \times \boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep)\\\begin{split}prod\_con\_eff = \begin{cases} = \boldsymbol{resource_{con}}(loc::tech, timestep),& \text{if } loc::tech \in loc\_techs\_supply\_plus \\ = \frac{\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep)}{energy_eff(loc::tech, timestep)},& \text{if } loc::tech \in loc\_techs\_supply \\ \end{cases}\end{split}\\cost_{con}(cost, loc::tech, timestep) = cost_{om\_con}(cost, loc::tech, timestep) \times weight(timestep) \times prod\_con\_eff\end{aligned}\end{align} \]

Export

calliope.backend.pyomo.constraints.export.update_system_balance_constraint(backend_model, loc_carrier, timestep)[source]

Update system balance constraint (from energy_balance.py) to include export

Math given in system_balance_constraint_rule()

calliope.backend.pyomo.constraints.export.export_balance_constraint_rule(backend_model, loc_tech_carrier, timestep)[source]

Ensure no technology can ‘pass’ its export capability to another technology with the same carrier_out, by limiting its export to the capacity of its production

\[\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep) \geq \boldsymbol{carrier_{export}}(loc::tech::carrier, timestep) \quad \forall loc::tech::carrier \in locs::tech::carriers_{export}, \forall timestep \in timesteps\]
calliope.backend.pyomo.constraints.export.update_costs_var_constraint(backend_model, cost, loc_tech, timestep)[source]

Update time varying cost constraint (from costs.py) to include export

\[\boldsymbol{cost_{var}}(cost, loc::tech, timestep) += cost_{export}(cost, loc::tech, timestep) \times \boldsymbol{carrier_{export}}(loc::tech::carrier, timestep) * timestep_{weight} \quad \forall cost \in costs, \forall loc::tech \in loc::techs_{cost_{var}, export}, \forall timestep \in timesteps\]
calliope.backend.pyomo.constraints.export.export_max_constraint_rule(backend_model, loc_tech_carrier, timestep)[source]

Set maximum export. All exporting technologies.

\[\boldsymbol{carrier_{export}}(loc::tech::carrier, timestep) \leq export_{cap}(loc::tech) \quad \forall loc::tech::carrier \in locs::tech::carriers_{export}, \forall timestep \in timesteps\]

If the technology is defined by integer units, not a continuous capacity, this constraint becomes:

\[\boldsymbol{carrier_{export}}(loc::tech::carrier, timestep) \leq export_{cap}(loc::tech) \times \boldsymbol{operating_{units}}(loc::tech, timestep)\]

MILP

calliope.backend.pyomo.constraints.milp.unit_commitment_constraint_rule(backend_model, loc_tech, timestep)[source]

Constraining the number of integer units \(operating_units(loc_tech, timestep)\) of a technology which can operate in a given timestep, based on maximum purchased units \(units(loc_tech)\)

\[\boldsymbol{operating\_units}(loc::tech, timestep) \leq \boldsymbol{units}(loc::tech) \quad \forall loc::tech \in loc::techs_{milp}, \forall timestep \in timesteps\]
calliope.backend.pyomo.constraints.milp.unit_capacity_constraint_rule(backend_model, loc_tech)[source]

Add upper and lower bounds for purchased units of a technology

\[\begin{split}\boldsymbol{units}(loc::tech) \begin{cases} = units_{equals}(loc::tech),& \text{if } units_{equals}(loc::tech)\\ \leq units_{max}(loc::tech),& \text{if } units_{max}(loc::tech)\\ \text{unconstrained},& \text{otherwise} \end{cases} \quad \forall loc::tech \in loc::techs_{milp}\end{split}\]

and (if equals not enforced):

\[\boldsymbol{units}(loc::tech) \geq units_{min}(loc::tech) \quad \forall loc::tech \in loc::techs_{milp}\]
calliope.backend.pyomo.constraints.milp.carrier_production_max_milp_constraint_rule(backend_model, loc_tech_carrier, timestep)[source]

Set maximum carrier production of MILP techs that aren’t conversion plus

\[\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep) \leq energy_{cap, per unit}(loc::tech) \times timestep\_resolution(timestep) \times \boldsymbol{operating\_units}(loc::tech, timestep) \times \eta_{parasitic}(loc::tech, timestep) \quad \forall loc::tech \in loc::techs_{milp}, \forall timestep \in timesteps\]

\(\eta_{parasitic}\) is only activated for supply_plus technologies

calliope.backend.pyomo.constraints.milp.carrier_production_max_conversion_plus_milp_constraint_rule(backend_model, loc_tech, timestep)[source]

Set maximum carrier production of conversion_plus MILP techs

\[\sum_{loc::tech::carrier \in loc::tech::carriers_{out}} \boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep) \leq energy_{cap, per unit}(loc::tech) \times timestep\_resolution(timestep) \times \boldsymbol{operating\_units}(loc::tech, timestep) \times \eta_{parasitic}(loc::tech, timestep) \quad \forall loc::tech \in loc::techs_{milp, conversion^{+}}, \forall timestep \in timesteps\]
calliope.backend.pyomo.constraints.milp.carrier_production_min_milp_constraint_rule(backend_model, loc_tech_carrier, timestep)[source]

Set minimum carrier production of MILP techs that aren’t conversion plus

\[\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep) \geq energy_{cap, per unit}(loc::tech) \times timestep\_resolution(timestep) \times \boldsymbol{operating\_units}(loc::tech, timestep) \times energy_{cap, min use}(loc::tech) \quad \forall loc::tech \in loc::techs_{milp}, \forall timestep \in timesteps\]
calliope.backend.pyomo.constraints.milp.carrier_production_min_conversion_plus_milp_constraint_rule(backend_model, loc_tech, timestep)[source]

Set minimum carrier production of conversion_plus MILP techs

\[\sum_{loc::tech::carrier \in loc::tech::carriers_{out}} \boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep) \geq energy_{cap, per unit}(loc::tech) \times timestep\_resolution(timestep) \times \boldsymbol{operating\_units}(loc::tech, timestep) \times energy_{cap, min use}(loc::tech) \quad \forall loc::tech \in loc::techs_{milp, conversion^{+}}, \forall timestep \in timesteps\]
calliope.backend.pyomo.constraints.milp.carrier_consumption_max_milp_constraint_rule(backend_model, loc_tech_carrier, timestep)[source]

Set maximum carrier consumption of demand, storage, and transmission MILP techs

\[\boldsymbol{carrier_{con}}(loc::tech::carrier, timestep) \geq -1 * energy_{cap, per unit}(loc::tech) \times timestep\_resolution(timestep) \times \boldsymbol{operating\_units}(loc::tech, timestep) \times \eta_{parasitic}(loc::tech, timestep) \quad \forall loc::tech \in loc::techs_{milp, con}, \forall timestep \in timesteps\]
calliope.backend.pyomo.constraints.milp.energy_capacity_units_constraint_rule(backend_model, loc_tech)[source]

Set energy capacity decision variable as a function of purchased units

\[\boldsymbol{energy_{cap}}(loc::tech) = \boldsymbol{units}(loc::tech) \times energy_{cap, per unit}(loc::tech) \quad \forall loc::tech \in loc::techs_{milp}\]
calliope.backend.pyomo.constraints.milp.storage_capacity_units_constraint_rule(backend_model, loc_tech)[source]

Set storage capacity decision variable as a function of purchased units

\[\boldsymbol{storage_{cap}}(loc::tech) = \boldsymbol{units}(loc::tech) \times storage_{cap, per unit}(loc::tech) \quad \forall loc::tech \in loc::techs_{milp, store}\]
calliope.backend.pyomo.constraints.milp.energy_capacity_max_purchase_constraint_rule(backend_model, loc_tech)[source]

Set maximum energy capacity decision variable upper bound as a function of binary purchase variable

The first valid case is applied:

\[\begin{split}\frac{\boldsymbol{energy_{cap}}(loc::tech)}{energy_{cap, scale}(loc::tech)} \begin{cases} = energy_{cap, equals}(loc::tech) \times \boldsymbol{purchased}(loc::tech),& \text{if } energy_{cap, equals}(loc::tech)\\ \leq energy_{cap, max}(loc::tech) \times \boldsymbol{purchased}(loc::tech),& \text{if } energy_{cap, max}(loc::tech)\\ \text{unconstrained},& \text{otherwise} \end{cases} \forall loc::tech \in loc::techs_{purchase}\end{split}\]
calliope.backend.pyomo.constraints.milp.energy_capacity_min_purchase_constraint_rule(backend_model, loc_tech)[source]

Set minimum energy capacity decision variable upper bound as a function of binary purchase variable

and (if equals not enforced):

\[\frac{\boldsymbol{energy_{cap}}(loc::tech)}{energy_{cap, scale}(loc::tech)} \geq energy_{cap, min}(loc::tech) \times \boldsymbol{purchased}(loc::tech) \quad \forall loc::tech \in loc::techs\]
calliope.backend.pyomo.constraints.milp.storage_capacity_max_purchase_constraint_rule(backend_model, loc_tech)[source]

Set maximum storage capacity.

The first valid case is applied:

\[\begin{split}\boldsymbol{storage_{cap}}(loc::tech) \begin{cases} = storage_{cap, equals}(loc::tech) \times \boldsymbol{purchased},& \text{if } storage_{cap, equals} \\ \leq storage_{cap, max}(loc::tech) \times \boldsymbol{purchased},& \text{if } storage_{cap, max}(loc::tech)\\ \text{unconstrained},& \text{otherwise} \end{cases} \forall loc::tech \in loc::techs_{purchase, store}\end{split}\]
calliope.backend.pyomo.constraints.milp.storage_capacity_min_purchase_constraint_rule(backend_model, loc_tech)[source]

Set minimum storage capacity decision variable as a function of binary purchase variable

if equals not enforced for storage_cap:

\[\boldsymbol{storage_{cap}}(loc::tech) \geq storage_{cap, min}(loc::tech) \times \boldsymbol{purchased}(loc::tech) \quad \forall loc::tech \in loc::techs_{purchase, store}\]
calliope.backend.pyomo.constraints.milp.update_costs_investment_units_constraint(backend_model, cost, loc_tech)[source]

Add MILP investment costs (cost * number of units purchased)

\[\boldsymbol{cost_{investment}}(cost, loc::tech) += \boldsymbol{units}(loc::tech) \times cost_{purchase}(cost, loc::tech) * timestep_{weight} * depreciation \quad \forall cost \in costs, \forall loc::tech \in loc::techs_{cost_{investment}, milp}\]
calliope.backend.pyomo.constraints.milp.update_costs_investment_purchase_constraint(backend_model, cost, loc_tech)[source]

Add binary investment costs (cost * binary_purchased_unit)

\[\boldsymbol{cost_{investment}}(cost, loc::tech) += \boldsymbol{purchased}(loc::tech) \times cost_{purchase}(cost, loc::tech) * timestep_{weight} * depreciation \quad \forall cost \in costs, \forall loc::tech \in loc::techs_{cost_{investment}, purchase}\]

Conversion

calliope.backend.pyomo.constraints.conversion.balance_conversion_constraint_rule(backend_model, loc_tech, timestep)[source]

Balance energy carrier consumption and production

\[-1 * \boldsymbol{carrier_{con}}(loc::tech::carrier, timestep) \times \eta_{energy}(loc::tech, timestep) = \boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep) \times \eta_{energy}(loc::tech, timestep) \quad \forall loc::tech \in locs::techs_{conversion}, \forall timestep \in timesteps\]
calliope.backend.pyomo.constraints.conversion.cost_var_conversion_constraint_rule(backend_model, cost, loc_tech, timestep)[source]

Add time-varying conversion technology costs

\[\boldsymbol{cost_{var}}(loc::tech, cost, timestep) = \boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep) \times timestep_{weight}(timestep) \times cost_{om, prod}(loc::tech, cost, timestep) + \boldsymbol{carrier_{con}}(loc::tech::carrier, timestep) \times timestep_{weight}(timestep) \times cost_{om, con}(loc::tech, cost, timestep) \quad \forall loc::tech \in loc::techs_{cost_{var}, conversion}\]

Conversion_plus

calliope.backend.pyomo.constraints.conversion_plus.balance_conversion_plus_primary_constraint_rule(backend_model, loc_tech, timestep)[source]

Balance energy carrier consumption and production for carrier_in and carrier_out

\[\sum_{loc::tech::carrier \in loc::tech::carriers_{out}} \frac{\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep)}{ carrier\_ratio(loc::tech::carrier, `out')} = -1 * \sum_{loc::tech::carrier \in loc::tech::carriers_{in}} ( \boldsymbol{carrier_{con}}(loc::tech::carrier, timestep) * carrier\_ratio(loc::tech::carrier, `in') * \eta_{energy}(loc::tech, timestep)) \quad \forall loc::tech \in loc::techs_{conversion^{+}}, \forall timestep \in timesteps\]
calliope.backend.pyomo.constraints.conversion_plus.carrier_production_max_conversion_plus_constraint_rule(backend_model, loc_tech, timestep)[source]

Set maximum conversion_plus carrier production.

\[\sum_{loc::tech::carrier \in loc::tech::carriers_{out}} \boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep) \leq \boldsymbol{energy_{cap}}(loc::tech) \times timestep\_resolution(timestep) \quad \forall loc::tech \in loc::techs_{conversion^{+}}, \forall timestep \in timesteps\]
calliope.backend.pyomo.constraints.conversion_plus.carrier_production_min_conversion_plus_constraint_rule(backend_model, loc_tech, timestep)[source]

Set minimum conversion_plus carrier production.

\[\sum_{loc::tech::carrier \in loc::tech::carriers_{out}} \boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep) \leq \boldsymbol{energy_{cap}}(loc::tech) \times timestep\_resolution(timestep) \times energy_{cap, min use}(loc::tech) \quad \forall loc::tech \in loc::techs_{conversion^{+}}, \forall timestep \in timesteps\]
calliope.backend.pyomo.constraints.conversion_plus.cost_var_conversion_plus_constraint_rule(backend_model, cost, loc_tech, timestep)[source]

Add time-varying conversion_plus technology costs

\[\boldsymbol{cost_{var}}(loc::tech, cost, timestep) = \boldsymbol{carrier_{prod}}(loc::tech::carrier_{primary}, timestep) \times timestep_{weight}(timestep) \times cost_{om, prod}(loc::tech, cost, timestep) + \boldsymbol{carrier_{con}}(loc::tech::carrier_{primary}, timestep) \times timestep_{weight}(timestep) \times cost_{om, con}(loc::tech, cost, timestep) \quad \forall loc::tech \in loc::techs_{cost_{var}, conversion^{+}}\]
calliope.backend.pyomo.constraints.conversion_plus.balance_conversion_plus_tiers_constraint_rule(backend_model, tier, loc_tech, timestep)[source]

Force all carrier_in_2/carrier_in_3 and carrier_out_2/carrier_out_3 to follow carrier_in and carrier_out (respectively).

If tier in [‘out_2’, ‘out_3’]:

\[\sum_{loc::tech::carrier \in loc::tech::carriers_{out}} ( \frac{\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep)}{ carrier\_ratio(loc::tech::carrier, `out')} = \sum_{loc::tech::carrier \in loc::tech::carriers_{tier}} ( \frac{\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep)}{ carrier\_ratio(loc::tech::carrier, tier)} \quad \forall \text { tier } \in [`out_2', `out_3'], \forall loc::tech \in loc::techs_{conversion^{+}}, \forall timestep \in timesteps\]

If tier in [‘in_2’, ‘in_3’]:

\[\sum_{loc::tech::carrier \in loc::tech::carriers_{in}} \frac{\boldsymbol{carrier_{con}}(loc::tech::carrier, timestep)}{ carrier\_ratio(loc::tech::carrier, `in')} = \sum_{loc::tech::carrier \in loc::tech::carriers_{tier}} \frac{\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep)}{ carrier\_ratio(loc::tech::carrier, tier)} \quad \forall \text{ tier } \in [`in_2', `in_3'], \forall loc::tech \in loc::techs_{conversion^{+}}, \forall timestep \in timesteps\]

Network

calliope.backend.pyomo.constraints.network.symmetric_transmission_constraint_rule(backend_model, loc_tech)[source]

Constrain e_cap symmetrically for transmission nodes. Transmission techs only.

\[energy_{cap}(loc1::tech:loc2) = energy_{cap}(loc2::tech:loc1)\]

Policy

calliope.backend.pyomo.constraints.policy.group_share_energy_cap_constraint_rule(backend_model, techlist, what)[source]

Enforce shares in energy_cap for groups of technologies. Applied to supply and supply_plus technologies only.

\[\sum_{loc::tech \in given\_group} energy_{cap}(loc::tech) = fraction \times \sum_{loc::tech \in loc\_techs\_supply \or loc\_techs\_supply\_plus} energy_{cap}(loc::tech)\]
calliope.backend.pyomo.constraints.policy.group_share_carrier_prod_constraint_rule(backend_model, techlist_carrier, what)[source]

Enforce shares in carrier_prod for groups of technologies. Applied to loc_tech_carriers_supply_all, which includes supply, supply_plus, conversion, and conversion_plus.

\[\sum_{loc::tech::carrier \in given\_group, timestep \in timesteps} carrier_{prod}(loc::tech::carrier, timestep) = fraction \times \sum_{loc::tech:carrier \in loc\_tech\_carriers\_supply\_all, timestep\in timesteps} carrier_{prod}(loc::tech::carrier, timestep)\]
calliope.backend.pyomo.constraints.policy.reserve_margin_constraint_rule(backend_model, carrier)[source]

Enforces a system reserve margin per carrier.

\[\sum_{loc::tech::carrier \in loc\_tech\_carriers\_supply\_all} energy_{cap}(loc::tech::carrier, timestep_{max\_demand}) \geq \sum_{loc::tech::carrier \in loc\_tech\_carriers\_demand} carrier_{con}(loc::tech::carrier, timestep_{max\_demand}) \times -1 \times \frac{1}{time\_resolution_{max\_demand}} \times (1 + reserve\_margin)\]

Previous: Listing of configuration options | Next: Development guide