Skip to content

Conversation

@abhishek0208
Copy link
Contributor

This functionality allows for flexible user-defined constraints to be added. It allows for creation of relationships between the capacities and activities of specific technologies. For instance, the total new capacity of all renewable powerplants can be set using such a relationship. It is an expansion of the OEP presented here. The formulation of the constraints is as follows:

s.t. UDC0_UserDefinedConstraintEquality{r in REGION, u in UDC, y in YEAR: UDCTag[r,u] = 0}: 
sum{t in TECHNOLOGY}UDCMultiplierTotalCapacity[r,t,u,y]*TotalCapacityAnnual[r,t,y] + 
sum{t in TECHNOLOGY}UDCMultiplierNewCapacity[r,t,u,y]*NewCapacity[r,t,y] +
sum{t in TECHNOLOGY}UDCMultiplierActivity[r,t,u,y]*TotalTechnologyAnnualActivity[r,t,y] = UDCConstant[r,u,y];

s.t. UDC1_UserDefinedConstraintInequality{r in REGION, u in UDC, y in YEAR: UDCTag[r,u] = 1}: 
sum{t in TECHNOLOGY}UDCMultiplierTotalCapacity[r,t,u,y]*TotalCapacityAnnual[r,t,y] + 
sum{t in TECHNOLOGY}UDCMultiplierNewCapacity[r,t,u,y]*NewCapacity[r,t,y] +
sum{t in TECHNOLOGY}UDCMultiplierActivity[r,t,u,y]*TotalTechnologyAnnualActivity[r,t,y] >= UDCConstant[r,u,y];

s.t. UDC2_UserDefinedConstraintInequality{r in REGION, u in UDC, y in YEAR: UDCTag[r,u] = 2}: 
sum{t in TECHNOLOGY}UDCMultiplierTotalCapacity[r,t,u,y]*TotalCapacityAnnual[r,t,y] + 
sum{t in TECHNOLOGY}UDCMultiplierNewCapacity[r,t,u,y]*NewCapacity[r,t,y] +
sum{t in TECHNOLOGY}UDCMultiplierActivity[r,t,u,y]*TotalTechnologyAnnualActivity[r,t,y] <= UDCConstant[r,u,y];

where UDCTag specifies whether a user-defined constraint is an equality [0], LHS>=RHS [1], or LHS<=RHS [2]; UDCConstant is the RHS of the UDC; three multipliers - UDCMultiplier* - are used as co-efficients for TotalCapacityAnnual, NewCapacity, TotalTechnologyAnnualActivity.

Below is a summary of additions:
1 new set:
set UDC

5 new parameters:
param UDCMultiplierTotalCapacity
param UDCMultiplierNewCapacity
param UDCMultiplierActivity
param UDCConstant
param UDCTag

and 3 new constraints:
s.t. UDC0_UserDefinedConstraintEquality
s.t. UDC1_UserDefinedConstraintInequality
s.t. UDC2_UserDefinedConstraintInequality

A simple test case 'simplicity_udc.txt' has been used to test these constraints for all three versions of the OSeMOSYS_GNU_MathProg code. In this example, three user-defined constraints are created:

  1. TotalCapacityAnnual of GAS_EXTRACTION and GAS_IMPORT must together equal 10.
  2. TotalTechnologyAnnualActivity of SOLPV1, SOLPV2, and WINDPOWER must be >= 50% of SpecifiedAnnualDemand of FEL1
  3. NewCapacity of SOLPV1 and SOLPV2 together must be <= 0

@abhishek0208 abhishek0208 added the enhancement New feature or request label Nov 15, 2021
@tniet
Copy link
Contributor

tniet commented Nov 15, 2021

@abhishek0208 - looks like a good enhancement and I think the formulation looks good as well. Does this allow us to require a given land area for an installed capacity of solar in CLEWs? I think it does but wanted to get your thoughts on that.

I think we should consider the data for the constraints you've added and decide if these are reasonable for Simplicity and then make the TravisCI checks work for the added constraints. Maybe @willu47 can provide some assistance with updating the checks/constraints to work?

@abhishek0208
Copy link
Contributor Author

Thanks @tniet. My understanding is that this formulation will allow a user to set the total or minimum land area for a given capacity of a technology (e.g. solar). I don't think it'll quite work to set land area per unit capacity of a technology (we can use other parameters for that: InputToTotalCapacityRatio and InputToNewCapacityRatio). Happy to be corrected on this.

@tniet
Copy link
Contributor

tniet commented Nov 15, 2021

@abhishek0208 It seems to me that these can allow you to link installed capacity, new capacity and activity for any user defined group of techs and commodities, so I think you should be able to do what you've described. Might be easier and clearer to have separate constraints, but nominally I think it should work.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces user-defined constraints that allow the formulation of relationships between capacities and activities in the system. Key changes include the addition of a new set (UDC), the introduction of five new parameters to support flexible multiplier and constant definitions, and three new constraints (equality, ≥, and ≤) applied across different model variants.

Reviewed Changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
src/osemosys_short.txt Added UDC-related set, parameters, and constraints using computed capacity expressions.
src/osemosys_fast.txt Added UDC-related set, parameters, and constraints with expressions using MODEperTECHNOLOGY for activity.
src/osemosys.txt Added UDC-related set, parameters, and constraints using TotalCapacityAnnual directly.
Comments suppressed due to low confidence (2)

src/osemosys_fast.txt:562

  • The use of MODEperTECHNOLOGY[t] here for iterating over activity contrasts with the MODE_OF_OPERATION used in other files. Verify that this variation is intended to reflect differing model formulations.
sum{t in TECHNOLOGY}UDCMultiplierActivity[r,t,u,y]*sum{l in TIMESLICE, m in MODEperTECHNOLOGY[t]} RateOfActivity[r,l,t,m,y]*YearSplit[l,y]

src/osemosys_short.txt:526

  • The activity multiplier iterates over MODE_OF_OPERATION here, which differs from the fast version's MODEperTECHNOLOGY usage. Please confirm that this discrepancy is intentional and aligns with the overall model design.
sum{t in TECHNOLOGY}UDCMultiplierActivity[r,t,u,y]*sum{l in TIMESLICE, m in MODE_OF_OPERATION} RateOfActivity[r,l,t,m,y]*YearSplit[l,y]

Comment on lines +824 to +834
sum{t in TECHNOLOGY}UDCMultiplierTotalCapacity[r,t,u,y]*TotalCapacityAnnual[r,t,y] +
sum{t in TECHNOLOGY}UDCMultiplierNewCapacity[r,t,u,y]*NewCapacity[r,t,y] +
sum{t in TECHNOLOGY}UDCMultiplierActivity[r,t,u,y]*TotalTechnologyAnnualActivity[r,t,y] = UDCConstant[r,u,y];

s.t. UDC1_UserDefinedConstraintInequality{r in REGION, u in UDC, y in YEAR: UDCTag[r,u] = 1}:
sum{t in TECHNOLOGY}UDCMultiplierTotalCapacity[r,t,u,y]*TotalCapacityAnnual[r,t,y] +
sum{t in TECHNOLOGY}UDCMultiplierNewCapacity[r,t,u,y]*NewCapacity[r,t,y] +
sum{t in TECHNOLOGY}UDCMultiplierActivity[r,t,u,y]*TotalTechnologyAnnualActivity[r,t,y] >= UDCConstant[r,u,y];

s.t. UDC2_UserDefinedConstraintInequality{r in REGION, u in UDC, y in YEAR: UDCTag[r,u] = 2}:
sum{t in TECHNOLOGY}UDCMultiplierTotalCapacity[r,t,u,y]*TotalCapacityAnnual[r,t,y] +
Copy link

Copilot AI Jun 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The UDC constraints in this file use TotalCapacityAnnual directly while the other versions compute capacity as a sum over NewCapacity and ResidualCapacity. Ensure this difference is intentional and that the constraint formulations remain consistent with the model requirements.

Suggested change
sum{t in TECHNOLOGY}UDCMultiplierTotalCapacity[r,t,u,y]*TotalCapacityAnnual[r,t,y] +
sum{t in TECHNOLOGY}UDCMultiplierNewCapacity[r,t,u,y]*NewCapacity[r,t,y] +
sum{t in TECHNOLOGY}UDCMultiplierActivity[r,t,u,y]*TotalTechnologyAnnualActivity[r,t,y] = UDCConstant[r,u,y];
s.t. UDC1_UserDefinedConstraintInequality{r in REGION, u in UDC, y in YEAR: UDCTag[r,u] = 1}:
sum{t in TECHNOLOGY}UDCMultiplierTotalCapacity[r,t,u,y]*TotalCapacityAnnual[r,t,y] +
sum{t in TECHNOLOGY}UDCMultiplierNewCapacity[r,t,u,y]*NewCapacity[r,t,y] +
sum{t in TECHNOLOGY}UDCMultiplierActivity[r,t,u,y]*TotalTechnologyAnnualActivity[r,t,y] >= UDCConstant[r,u,y];
s.t. UDC2_UserDefinedConstraintInequality{r in REGION, u in UDC, y in YEAR: UDCTag[r,u] = 2}:
sum{t in TECHNOLOGY}UDCMultiplierTotalCapacity[r,t,u,y]*TotalCapacityAnnual[r,t,y] +
sum{t in TECHNOLOGY}UDCMultiplierTotalCapacity[r,t,u,y]*(NewCapacity[r,t,y] + ResidualCapacity[r,t,y]) +
sum{t in TECHNOLOGY}UDCMultiplierNewCapacity[r,t,u,y]*NewCapacity[r,t,y] +
sum{t in TECHNOLOGY}UDCMultiplierActivity[r,t,u,y]*TotalTechnologyAnnualActivity[r,t,y] = UDCConstant[r,u,y];
s.t. UDC1_UserDefinedConstraintInequality{r in REGION, u in UDC, y in YEAR: UDCTag[r,u] = 1}:
sum{t in TECHNOLOGY}UDCMultiplierTotalCapacity[r,t,u,y]*(NewCapacity[r,t,y] + ResidualCapacity[r,t,y]) +
sum{t in TECHNOLOGY}UDCMultiplierNewCapacity[r,t,u,y]*NewCapacity[r,t,y] +
sum{t in TECHNOLOGY}UDCMultiplierActivity[r,t,u,y]*TotalTechnologyAnnualActivity[r,t,y] >= UDCConstant[r,u,y];
s.t. UDC2_UserDefinedConstraintInequality{r in REGION, u in UDC, y in YEAR: UDCTag[r,u] = 2}:
sum{t in TECHNOLOGY}UDCMultiplierTotalCapacity[r,t,u,y]*(NewCapacity[r,t,y] + ResidualCapacity[r,t,y]) +

Copilot uses AI. Check for mistakes.
Copy link
Contributor

@HauHe HauHe Sep 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The usage of the TotalCapacityAnnual in the osemosys.txt is fine. In the other code versions this variable just can't be used since it is commented out.
So this shouldn't prevent closing the PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you agree that the use of TotalCapacityAnnual in the osemosys.txt is fine @abhishek0208 ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

6 participants