Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Variable and Emission Cost Accounting #90

Open
SutubraResearch opened this issue Nov 22, 2024 · 3 comments
Open

Variable and Emission Cost Accounting #90

SutubraResearch opened this issue Nov 22, 2024 · 3 comments

Comments

@SutubraResearch
Copy link
Collaborator

SutubraResearch commented Nov 22, 2024

There appears to be an issue with how variable costs (and emission costs) are represented in the objective function.

Some background:

  1. Decision Variables in Temoa: Temoa has two main sets of decision variables: those related to capacity ("V_Capacity") and those related to dispatch ("V_FlowOut"). These variables are connected through several equations, including the Capacity_Constraint (discussed further below).
  2. Modeling Discrete Future Years: Temoa typically models a discrete set of future years (e.g., 2020, 2025, 2030, etc.).
  3. Accounting for End-of-Life Technologies: Temoa includes logic to account for situations where technologies reach their end-of-life during the middle of a model period (e.g., in 2023). In such cases, the effective capacities—and consequently, the dispatch—of these technologies are scaled down proportionally to the fraction of the model period during which they are active (e.g., for 2023 in a 2020–2025 period, the fraction would be 3/5​=0.6).

Some notes on variable names

  • ModelProcessLife, or MPL, represents the number of years during the period in question over which the technology remains operational. This is the lesser of the period length and the remaining process lifetime of the technology. For example, in the case above, MPL would be min⁡(5,3)=3.
  • ProcessLifeFrac is the fraction representing the ratio of the two arguments in MPL, e.g., 3/5=0.6.

Guts

The Capacity_Constraint is as follows:
capacity * value(M.CapacityToActivity[r, t]) * value(M.SegFrac[s, d]) * value(M.ProcessLifeFrac[r, p, t, v]) * M.V_Capacity[r, p, t, v] >= useful_activity

If we assume the technology only has one input commodity and one output commodity, and if we assume this technology is not governed by capacity factors, this simplifies to:

1 * value(M.CapacityToActivity[r, t]) * value(M.SegFrac[s, d]) * value(M.ProcessLifeFrac[r, p, t, v]) * M.V_Capacity[r, p, t, v] >= M.V_FlowOut[r, p, s, d, i, t, v, o]

This implies the following:

  • The capacity-related decision variables, V_Capacity, are the total, nameplate capacity without any end-of-life scaling applied.
  • The activity of the technology, V_FlowOut, takes into account end-of-life scaling (by the inclusion of ProcessLifeFrac).

OK. So this brings us to the objective function.

Fixed Costs
Notes:

  1. I'm going to use code from v2 of Temoa, where the cost logic is a little more explicit/clear.
  2. I'm also omitting the for loops over the indexed parameters for clarity.
  3. And we're assuming the global discount rate is 0%.

fixed_costs = sum( M.V_Capacity[r, p, S_t, S_v] * ( value(M.CostFixed[r, p, S_t, S_v]) * ( value(MPL[r, p, S_t, S_v]) ) )

Here, we see the fixed costs are scaled by MPL, which makes sense. We take the capacity, V_Capacity, which has not yet been scaled for end-of-life effects, and scale it by MPL. Logic: you pay fixed costs only in the years in which that technology exists.

Variable Costs
variable_costs = sum( M.V_FlowOut[r, p, s, d, S_i, S_t, S_v, S_o] * ( value(M.CostVariable[r, p, S_t, S_v]) * ( value(MPL[r, p, S_t, S_v]) ) )

Here, we see the variable costs are scaled by MPL as well. And I believe this is a bug. The activity (V_FlowOut) has already taken into account the end-of-life effects by the presence of PLF in the Capacity_Constraint. Therefore, it should be multiplied here by the period length (e.g., 5 years), not the MPL (e.g., 3 years).

Example
Let's imagine an NGCC plant w/ 1 GW capacity operating in a model period of length 5 years (e.g. 2020-2025) and the technology reaches its EOL 3 years into that period (2023). Then we have:

  • MPL = 3
  • PLF = 3/5 = 0.6

Capacity constraint:
value(M.CapacityToActivity[r, t]) * value(M.SegFrac[s, d]) * value(M.ProcessLifeFrac[r, p, t, v]) * M.V_Capacity[r, p, t, v] >= M.V_FlowOut[r, p, s, d, i, t, v, o]

simplifies to:

8760 GWh/GW * 1/8760 * 0.6 * 1 GW >= M.V_FlowOut

which is equivalent to

V_FlowOut <= 0.6 GWh

This makes sense. That plant can operate at it's namplelate capacity of 1 GW in 3 of the 5 years, resulting in an average annual activity of 0.6 GWh.

Given that, the objective function should multiply this activity by the period length (5 years = 3 GWh), and not the MPL of 3 years (1.8 GWh).

Impact
Fairly minimal. This bug effectively discounts variable costs for technologies in the model period in which they reach their EOL. This discount is proportional to its MPL.

Proposed Fix
Fairly straightforward. The MPL parameter in the variable cost and emission cost logic within the objective function should be replaced by the period length, M.PeriodLength[p]

@idelder
Copy link

idelder commented Nov 22, 2024

I agree that this is a bug. Ignoring capacity entirely, with the current math, if a technology retires at 3/5 years

MPL = 3
PLF = 3/5 = 0.6

and it outputs 1 unit of flow per year at a cost of $1 per unit of flow, it's total cost for that period will be:

flow * cost * mpl
= 1 * $1 * 3
= $3

The commodity balance constraint does not adjust for EOL. The model is operating assuming that this flow is being supplied over all 5 years of that period, and so the cost should be the full $5.

@jeff-ws
Copy link

jeff-ws commented Nov 22, 2024

I think you are on-point. It would be nice to make a tiny test case to prove (a) that it's broke (but that is pretty convincing) and (b) show the fix works. I have a small dataset "smallville" that might be useful if someone wants to mod it for a unit test... I'm thinking 2 techs (one cheap that is limited by MPL) and one expensive for 1 time period should show this.

@idelder
Copy link

idelder commented Nov 22, 2024

Ran a wee test on utopia already and pretty satisfied that it is indeed broken in both discounted and undiscounted terms, and that the change above fixes both.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants