Skip to content

update appraisal documentation#1125

Merged
Aurashk merged 25 commits intomainfrom
update-npv-docs
Mar 4, 2026
Merged

update appraisal documentation#1125
Aurashk merged 25 commits intomainfrom
update-npv-docs

Conversation

@Aurashk
Copy link
Copy Markdown
Collaborator

@Aurashk Aurashk commented Feb 12, 2026

Description

I went through the documentation for npv and tried to ensure that it accurately reflects what is done in the code. I think there was a couple of erroneous - signs in the docs but please double check. When we choose the best asset using profitability index we used to negate them so that the smallest is best, but this was just to allow us to deal with NPV and LCOX metrics in the same way. When it comes to calculating activity coefficients, I don't see a negation like this in the code, and it makes sense that we would want to maximise annualised revenue rather than minimise it.

I modified/added a couple of bits to try and make the documentation clearer but let me know what you think:

  • Split up the NPV and LCOX activity coefficients into separate expressions, they are very similar but for me the subtle differences make it harder to register what the activity coefficients actually represent.
  • Added an example subsection at the end to help the reader understand the different interpretations (maximise profit vs minimise cost). Maybe this should be in it's own file though.

Fixes #1103

Type of change

  • Bug fix (non-breaking change to fix an issue)
  • New feature (non-breaking change to add functionality)
  • Refactoring (non-breaking, non-functional change to improve maintainability)
  • Optimization (non-breaking change to speed up the code)
  • Breaking change (whatever its nature)
  • Documentation (improve or add documentation)

Key checklist

  • All tests pass: $ cargo test
  • The documentation builds and looks OK: $ cargo doc
  • Update release notes for the latest release if this PR adds a new feature or fixes a bug
    present in the previous release

Further checks

  • Code is commented, particularly in hard-to-understand areas
  • Tests added that prove fix is effective or that feature works

Copilot AI review requested due to automatic review settings February 12, 2026 16:44
@Aurashk Aurashk requested a review from alexdewar February 12, 2026 16:45
@codecov
Copy link
Copy Markdown

codecov Bot commented Feb 12, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.30%. Comparing base (9dd37de) to head (c5d5234).
⚠️ Report is 61 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1125      +/-   ##
==========================================
- Coverage   87.48%   87.30%   -0.18%     
==========================================
  Files          55       57       +2     
  Lines        7660     7706      +46     
  Branches     7660     7706      +46     
==========================================
+ Hits         6701     6728      +27     
- Misses        657      673      +16     
- Partials      302      305       +3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Contributor

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 updates the documentation for NPV (Net Present Value) and LCOX (Levelised Cost of X) investment appraisal methods to accurately reflect their implementation in the codebase. The changes fix erroneous negative signs in the formulas, separate NPV and LCOX activity coefficient expressions for clarity, and add a comprehensive worked example using a gas power plant.

Changes:

  • Corrected mathematical formulas for NPV and LCOX activity coefficients, removing incorrect negative signs and adding proper superscript notation (AC_t^NPV and AC_t^LCOX)
  • Separated NPV and LCOX formulas into distinct expressions to highlight their differences
  • Added detailed gas power plant example demonstrating NPV and LCOX calculations across two time periods with complete numerical workthrough

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/model/investment.md Outdated
Comment thread docs/model/investment.md Outdated
Comment on lines +224 to +225
\text{Cost Index} = \frac{\text{AFC} \times \text{cap}_r + \sum_t \text{act}_t
\times \text{AC}_t^{\text{LCOX}}}{\sum_t \text{act}_t}
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

Inconsistent LaTeX formatting for variable names. The cost index formula at lines 224-225 uses '\text{act}_t', '\text{AC}_t', etc. with the \text{} wrapper, but the equivalent cost index formula in the example section at line 386 uses 'act_t', 'AC_t', etc. without the \text{} wrapper. Similarly, line 182 uses '\text{act}_t' for the profitability index, but line 317 uses 'act_t' in the example. For consistency, either use \text{} for all variable names in standalone formulas, or don't use it for any. The most readable option would be to consistently use \text{} for all variable names in metric formulas (lines 224-225, 182) and update the example formulas (lines 317, 325, 386) to match.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Hmm... It seems like we weren't consistently using \text before this PR, but we probably don't also want to be changing act to \text{act} haphazardly, without updating it everywhere (although the latter is arguably more correct).

Up to you whether you want to revert or whatever. Not esp important.

Copy link
Copy Markdown
Collaborator Author

@Aurashk Aurashk Feb 13, 2026

Choose a reason for hiding this comment

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

should I update the rest of the file to consistently use \text as copilot says? then we can make an issue about making sure it's consistent throughout the docs? (Maybe we can assign copilot to do that too :) )

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd try not to make too much work for yourself, so I'd maybe leave it without the \text{}s and change yours so they're consistent (even if it's not quite right).

Good idea to assign it to Copilot! Maybe let's open an issue and try that.

Copy link
Copy Markdown
Member

@alexdewar alexdewar left a comment

Choose a reason for hiding this comment

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

I've suggested some tweaks and I've asked some questions, but this looks really good! The worked example is especially helpful.

Besides that:

  • We should mention the fallback behaviour for NPV when AFC==0 somewhere; I don't think we do currently.
  • I think you're right about the minus signs. Your new version looks correct to me.
  • I feel like we should probably just drop the scopes stuff (the text and the terms in the equations). I'm not convinced the equations are right as they are and we're not planning on implementing this feature any time soon anyway.

Comment thread docs/model/investment.md Outdated
Comment thread docs/model/investment.md Outdated
Comment thread docs/model/investment.md Outdated
@@ -140,10 +157,10 @@ operational constraints (e.g., minimum load levels) and the balance level of the
- **Optimise capacity and dispatch to maximise annualised profit:** Solve a small optimisation
sub-problem to maximise the asset's surplus, subject to its operational rules and the specific
demand tranche it is being asked to serve. \\(\varepsilon \approx 1×10^{-14}\\) is added to each
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The value of $\varepsilon$ in the code is actually f64::EPSILON * 100. Incidentally, do you know why we're not just using f64::EPSILON?

Copy link
Copy Markdown
Collaborator Author

@Aurashk Aurashk Feb 13, 2026

Choose a reason for hiding this comment

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

I think f64::EPSILON is too small to meaningfully nullify any floating point precision errors which made the activity coefficient tiny and negative (don't think the constant is really intended for that purpose). So it's multiplied by 100 to get it to around 1e-14. I suppose you could argue it's cleaner just to use 1e-14 directly but that would be a bit more arbitrary too.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Oh, if it's negative I feel like we should just set it to f64::EPSILON, i.e. use number.max(f64::EPSILON). I think this would be a cleaner approach than just always adding this constant. Maybe this should be done in a separate PR though...

Do you have thoughts @tsmbland?

Copy link
Copy Markdown
Collaborator Author

@Aurashk Aurashk Feb 27, 2026

Choose a reason for hiding this comment

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

Won't it lose information if we force all the coefficients to be positive though? Because the activity coefficients can be negative, and the optimiser will try and arrange the activity to favour positive within the constraints. With the epsilon value we only want to give some numerical wiggle-room where the coefficient is very close to zero.

Comment thread docs/model/investment.md Outdated
Comment thread docs/model/investment.md Outdated
Comment thread docs/model/investment.md Outdated
Comment thread docs/model/investment.md Outdated
Comment thread docs/model/investment.md Outdated
Comment thread docs/model/investment.md

- Calculate cost per unit of activity \\( AC_{t}^{LCOX} \\) (Tool B). Note that the commodity
of interest (primary output \\( c_{primary} \\)) is excluded from the price term:
\\[
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Has this block been changed, other than the indentation?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Comment thread docs/model/investment.md Outdated
Co-authored-by: Alex Dewar <alexdewar@users.noreply.github.com>
Copilot AI review requested due to automatic review settings February 13, 2026 12:10
Copy link
Copy Markdown
Contributor

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

Copilot reviewed 1 out of 1 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/model/investment.md Outdated
Comment thread docs/model/investment.md Outdated
Comment thread docs/model/investment.md Outdated
Comment on lines +289 to +292
AC_{t2}^{NPV} &= (1.0 \times 50) + (0.5 \times 15) + (-2.5 \times 25) - 5 \\\\
&= 50 + 7.5 - 62.5 - 5 \\\\
&= \text{£} -10 \text{/MWh}
\end{aligned}
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

The LaTeX rendering for the negative value in this example is likely incorrect: \text{£} -10 \text{/MWh} will typically typeset awkwardly (and may drop spacing/formatting). Prefer a single \text{...} (e.g., \text{£-10/MWh}) or otherwise format the currency/unit consistently with the other example lines.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Looks ok to me

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Me too 😄

Comment thread docs/model/investment.md Outdated

| Commodity | Notation | t1 (Peak) | t2 (Off-peak) |
|-----------|----------|-----------|---------------|
| Electricity | \\( \lambda\_{c_{elec},r,t} \\) | £90/MWh | £50/MWh |
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

In the example, electricity is introduced as the primary output using c_{primary}, but the market price table switches to c_{elec} in the price notation. Using a single symbol consistently (e.g., c_{primary} everywhere, or explicitly stating c_{primary}=c_{elec}) would prevent ambiguity.

Suggested change
| Electricity | \\( \lambda\_{c_{elec},r,t} \\) | £90/MWh | £50/MWh |
| Electricity | \\( \lambda\_{c_{primary},r,t} \\) | £90/MWh | £50/MWh |

Copilot uses AI. Check for mistakes.
Comment thread docs/model/investment.md Outdated
\\[
AC_t^{NPV} = \sum_{c} \Big( output\_{coeff}[c] - input\_{coeff}[c] \Big) \cdot \lambda_{c,r,t} - cost\_{var}[t]
\\]

Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

The example’s “general form” for AC_t^{NPV} only includes price terms and cost_{var}[t], while the earlier definition of AC_t^{NPV} also includes flow-specific costs/levies (and scope terms, even if currently unimplemented). Consider stating explicitly that the example assumes those additional terms are zero/omitted for simplicity, so readers don’t infer the implementation ignores them.

Suggested change
In this illustrative example, any additional flow-specific costs or levies (and any scope-related terms present in the full definition of \(AC_t^{NPV}\)) are assumed to be zero and are therefore omitted for simplicity.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I removed the general forms

Copilot AI review requested due to automatic review settings February 13, 2026 12:48
Copy link
Copy Markdown
Contributor

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

Copilot reviewed 1 out of 1 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/model/investment.md
Comment thread docs/model/investment.md
Comment on lines +180 to +183
\\[
\text{Profitability Index} =
\frac{\sum_t \text{act}_t \cdot \text{AC}_t^{\text{NPV}}}{\text{AFC} \cdot \text{cap}}
\\]
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

LaTeX variable formatting is inconsistent within this file: the profitability index uses \text{act}_t, \text{AC}_t, \text{AFC}, etc., while surrounding formulas and the worked example use act_t, AC_t, AFC without \text{}. Pick one style for variables in formulas (either remove \text{} here, or update the other formulas) to keep the notation consistent and easier to read.

Copilot uses AI. Check for mistakes.
Comment thread docs/model/investment.md
Copilot AI review requested due to automatic review settings February 13, 2026 13:01
Copy link
Copy Markdown
Contributor

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

Copilot reviewed 1 out of 1 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/model/investment.md Outdated
Comment on lines +223 to +225
\\[
\text{Cost Index} = \frac{\text{AFC} \times \text{cap}_r + \sum_t \text{act}_t
\times \text{AC}_t^{\text{LCOX}}}{\sum_t \text{act}_t}
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

The cost index formula introduces cap_r, but that symbol isn’t defined elsewhere in the doc (the optimisation and parameter tables use cap). Consider using the same capacity symbol/indices consistently (e.g., cap or cap_{opt,r}) to avoid confusion.

Copilot uses AI. Check for mistakes.
Comment thread docs/model/investment.md Outdated
Copilot AI review requested due to automatic review settings February 13, 2026 13:53
Copy link
Copy Markdown
Contributor

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

Copilot reviewed 1 out of 1 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/model/investment.md Outdated
Comment on lines +223 to +225
\\[
\text{Cost Index} = \frac{\text{AFC} \times \text{cap}_r + \sum_t \text{act}_t
\times \text{AC}_t^{\text{LCOX}}}{\sum_t \text{act}_t}
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

In the Cost Index formula, capacity is written as \text{cap}_r, but elsewhere in Tool B (including the objective just above) the decision variable is cap without a regional subscript. Please make the notation consistent (either always subscript capacity by region or omit it throughout) so it’s clear these refer to the same variable.

Copilot uses AI. Check for mistakes.
Comment thread docs/model/investment.md Outdated
cost\_{\text{output}}[c] \cdot output\_{\text{coeff}}[c] \Big) \\\\
&+ \sum\_{c} \Big( output\_{\text{coeff}}[c] - input\_{\text{coeff}}[c] \Big)
\cdot \lambda\_{c,r,t} \\\\
&+ \sum\_{s,c} in\\_scope[s] \cdot \Big\\{ \\\\
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

In the NPV activity-coefficient expression, in\\_scope[s] looks like an accidental extra backslash. In LaTeX, \\ is a linebreak and will likely break rendering here; it should be consistent with other escaped underscores (e.g., cost\_var) and use in\_scope instead.

Suggested change
&+ \sum\_{s,c} in\\_scope[s] \cdot \Big\\{ \\\\
&+ \sum\_{s,c} in\_scope[s] \cdot \Big\\{ \\\\

Copilot uses AI. Check for mistakes.
Comment thread docs/model/investment.md Outdated
Comment on lines 101 to 105
&- \sum\_{c \neq c_{primary}} \Big( output\_{\text{coeff}}[c] - input\_{\text{coeff}}
[c] \Big)
\cdot \lambda\_{c,r,t} \\\\
&+ \sum\_{s,c} in\\_scope[s] \cdot \Big\\{ \\\\
&\quad \quad (cost\_{\text{prod}}[s,c] - \mu\_{s,c}^{\text{prod}})
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

The AC_t^{LCOX} formula has a line break inside input_{\text{coeff}}[c] (the [c] is on the next line). This is likely to render incorrectly in LaTeX; keep the term on one line (or break between factors) so the subscripted variable isn’t split.

Suggested change
&- \sum\_{c \neq c_{primary}} \Big( output\_{\text{coeff}}[c] - input\_{\text{coeff}}
[c] \Big)
\cdot \lambda\_{c,r,t} \\\\
&+ \sum\_{s,c} in\\_scope[s] \cdot \Big\\{ \\\\
&\quad \quad (cost\_{\text{prod}}[s,c] - \mu\_{s,c}^{\text{prod}})
&- \sum\_{c \neq c_{primary}} \Big( output\_{\text{coeff}}[c] - input\_{\text{coeff}}[c] \Big)
\cdot \lambda\_{c,r,t} \\\\
&+ \sum\_{s,c} in\\_scope[s] \cdot \Big\\{ \\\\
&\quad \quad (cost\_{\text{prod}}[s,c] - \mu\_{s,c}^{\text{prod}})
&\quad \quad (cost\_{\text{prod}}[s,c] - \mu\_{s,c}^{\text{prod}})

Copilot uses AI. Check for mistakes.
Comment thread docs/model/investment.md
Comment on lines 200 to 204

\\[
minimise \Big\\{
AF \* cap + \sum_t act_t \* AC_t + VoLL \* UnmetD_t
AF \times cap + \sum_t act_t \times AC_{t}^{LCOX} + VoLL \times UnmetD_t
\Big\\}
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

Tool B’s optimisation bullet says it ‘minimise[s] annualised cost’ but then describes solving the sub-problem ‘to maximise the asset's surplus’, which is contradictory. Also, the objective uses AF × cap while the rest of the document defines the annualised fixed cost as AFC; please align the wording and notation so the objective is unambiguous and consistent with the earlier AFC_{opt,r} definition and the cost-index formula.

Copilot uses AI. Check for mistakes.
Comment thread docs/model/investment.md Outdated
Comment on lines +258 to +260
|-----------|----------|-----------|---------------|
| Electricity | \\( \lambda\_{c_{elec},r,t} \\) | £90/MWh | £50/MWh |
| Heat | \\( \lambda\_{c_{heat},r,t} \\) | £25/MWh | £15/MWh |
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

In the example, electricity is introduced as the primary output c_{primary}, but the price table uses \lambda_{c_{elec},r,t}. Either use c_{primary} consistently, or explicitly define c_{elec} = c_{primary} in the example to avoid ambiguity.

Copilot uses AI. Check for mistakes.
@Aurashk
Copy link
Copy Markdown
Collaborator Author

Aurashk commented Feb 13, 2026

I've suggested some tweaks and I've asked some questions, but this looks really good! The worked example is especially helpful.

Besides that:

  • We should mention the fallback behaviour for NPV when AFC==0 somewhere; I don't think we do currently.
  • I think you're right about the minus signs. Your new version looks correct to me.
  • I feel like we should probably just drop the scopes stuff (the text and the terms in the equations). I'm not convinced the equations are right as they are and we're not planning on implementing this feature any time soon anyway.

the equations look so much less intimidating without the scopes stuff !

Copilot AI review requested due to automatic review settings February 13, 2026 16:37
@ahawkes
Copy link
Copy Markdown
Contributor

ahawkes commented Mar 3, 2026 via email

@Aurashk
Copy link
Copy Markdown
Collaborator Author

Aurashk commented Mar 3, 2026

Can you send me the link to where this is in the docs so I can see context?

________________________________ From: Aurashk @.> Sent: 03 March 2026 12:03 To: EnergySystemsModellingLab/MUSE2 @.> Cc: Hawkes, Adam D @.>; Mention @.> Subject: Re: [EnergySystemsModellingLab/MUSE2] update appraisal documentation (PR #1125) [https://avatars.githubusercontent.com/u/9390150?s=20&v=4]Aurashk left a comment (EnergySystemsModellingLab/MUSE2#1125)<#1125 (comment)> @ahawkeshttps://github.com/ahawkes Is there a commonly accepted terminology for the second and third terms in the (NPV) activity coefficient equation below? In the code we call them flows_cost and revenue_from_flows respectively image.png (view on web)https://github.com/user-attachments/assets/4427c2ee-0248-4e80-923d-6628a8a802d1 — Reply to this email directly, view it on GitHub<#1125 (comment)>, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AC37JLLY7LWINY4PI3V47YT4O3CZVAVCNFSM6AAAAACU5MU5VGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTSOJQGU3DSNRWGY. You are receiving this because you were mentioned.Message ID: @.***>

On the investment appraisal page scrolling down to pre-calculation of metrics

@ahawkes
Copy link
Copy Markdown
Contributor

ahawkes commented Mar 3, 2026

@Aurashk the 2nd term is process_and_commodity_specific_flow_costs, and the 3rd term is commodity_price_flow_costs

@alexdewar alexdewar mentioned this pull request Mar 3, 2026
11 tasks
Copy link
Copy Markdown
Member

@alexdewar alexdewar left a comment

Choose a reason for hiding this comment

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

Last round, I think!

I've made a lot of small suggestions, but they're all basically the same thing: with mdbook you should escape underscores in math mode. Unfortunately, if you don't, it can sometimes be interpreted as meaning "italics" by the markdown parser. It renders fine for me currently, but I've had problems in the past where suddenly large blocks of the text end up italicised and the only solution seems to be to escape all the
underscores.

Thank you so much for sticking with this, btw. It's ended up being a much bigger task than I originally envisioned!

Comment thread docs/model/investment.md Outdated
Comment thread docs/model/investment.md Outdated
Comment thread docs/model/investment.md Outdated
Comment on lines +161 to +162
\\(\text{AFC}\\). If \\(\text{AFC} = 0\\), this is always preferred over options with
\\(\text{AFC} > 0\\) so the latter are discarded as investment options.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Agree with Copilot

Comment thread docs/model/investment.md Outdated
Comment thread docs/model/investment.md Outdated
Comment thread docs/model/investment.md Outdated
Comment thread docs/model/investment.md Outdated
Comment thread docs/model/investment.md Outdated
Comment thread docs/model/investment.md Outdated
Comment thread docs/model/investment.md Outdated
Comment on lines +390 to +391
Suppose the optimiser determines \\( cap = 100 \\) MW, \\( act_{t_{0}} = 150 \\) MWh,
and \\( act_{t_1} = 80 \\) MWh are the optimal capacity and activity levels:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
Suppose the optimiser determines \\( cap = 100 \\) MW, \\( act_{t_{0}} = 150 \\) MWh,
and \\( act_{t_1} = 80 \\) MWh are the optimal capacity and activity levels:
Suppose the optimiser determines \\( cap = 100 \\) MW, \\( act\_{t\_{0}} = 150 \\) MWh,
and \\( act\_{t\_1} = 80 \\) MWh are the optimal capacity and activity levels:

Co-authored-by: Alex Dewar <alexdewar@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 4, 2026 10:19
Copy link
Copy Markdown
Contributor

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

Copilot reviewed 1 out of 1 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/model/investment.md
Comment on lines +174 to +180
\frac{\sum\_t act\_t \cdot \text{AC}\_t^{\text{NPV}}}{\text{AFC} \cdot \text{cap}}
\\]

- **If \\(\text{AFC} = 0\\), Use the total annualised surplus metric \\(\text{TAS}\\):**
\\[
\text{TAS} =
\sum\_t act\_t \cdot \text{AC}\_t^{\text{NPV}}
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

Similarly, the TAS formula uses (AC_t^{NPV}) without the (\varepsilon) adjustment, but the code computes total annualised surplus from the same adjusted activity coefficients used in the optimisation. Consider reflecting that in the formula or clarifying that (\varepsilon) is included in the coefficients used for TAS.

Suggested change
\frac{\sum\_t act\_t \cdot \text{AC}\_t^{\text{NPV}}}{\text{AFC} \cdot \text{cap}}
\\]
- **If \\(\text{AFC} = 0\\), Use the total annualised surplus metric \\(\text{TAS}\\):**
\\[
\text{TAS} =
\sum\_t act\_t \cdot \text{AC}\_t^{\text{NPV}}
\frac{\sum\_t act\_t \cdot \left(\text{AC}\_t^{\text{NPV}} + \varepsilon\right)}{\text{AFC} \cdot \text{cap}}
\\]
- **If \\(\text{AFC} = 0\\), Use the total annualised surplus metric \\(\text{TAS}\\):**
\\[
\text{TAS} =
\sum\_t act\_t \cdot \left(\text{AC}\_t^{\text{NPV}} + \varepsilon\right)

Copilot uses AI. Check for mistakes.
Comment thread docs/model/investment.md Outdated
Comment on lines +69 to +73
- Calculate the specific process and commodity flow costs (SPCF):

\\[
\text{SPCF} = \sum\_{c} \Big( cost\_{\text{input}}[c] \cdot input\_{\text{coeff}}[c] +
cost\_{\text{output}}[c] \cdot output\_{\text{coeff}}[c] \Big)
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

The SPCF term is defined without any time-slice dependence, and cost_input/cost_output aren’t defined elsewhere in this doc. In the implementation, operating costs include per-flow costs plus levies/incentives that are keyed by (region, year, time_slice), so this component can vary by t (and cost_var is not time-slice indexed in code). Consider either indexing SPCF/cost terms by t (and defining them) or explicitly stating the assumptions under which they’re time-invariant.

Copilot uses AI. Check for mistakes.
Comment thread docs/model/investment.md
Comment on lines +174 to +180
\frac{\sum\_t act\_t \cdot \text{AC}\_t^{\text{NPV}}}{\text{AFC} \cdot \text{cap}}
\\]

- **If \\(\text{AFC} = 0\\), Use the total annualised surplus metric \\(\text{TAS}\\):**
\\[
\text{TAS} =
\sum\_t act\_t \cdot \text{AC}\_t^{\text{NPV}}
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

The PI formula here uses (AC_t^{NPV}) without the (\varepsilon) adjustment. In the implementation, (\varepsilon) is added directly to the NPV activity coefficients before optimisation and the profitability index is computed from those adjusted coefficients, so PI will (slightly) include (\varepsilon). Consider reflecting that in the formula or adding a note that the metric uses the adjusted coefficients.

Suggested change
\frac{\sum\_t act\_t \cdot \text{AC}\_t^{\text{NPV}}}{\text{AFC} \cdot \text{cap}}
\\]
- **If \\(\text{AFC} = 0\\), Use the total annualised surplus metric \\(\text{TAS}\\):**
\\[
\text{TAS} =
\sum\_t act\_t \cdot \text{AC}\_t^{\text{NPV}}
\frac{\sum\_t act\_t \cdot \left(\text{AC}\_t^{\text{NPV}} + \varepsilon\right)}{\text{AFC} \cdot \text{cap}}
\\]
- **If \\(\text{AFC} = 0\\), Use the total annualised surplus metric \\(\text{TAS}\\):**
\\[
\text{TAS} =
\sum\_t act\_t \cdot \left(\text{AC}\_t^{\text{NPV}} + \varepsilon\right)

Copilot uses AI. Check for mistakes.
Comment thread docs/model/investment.md
Comment on lines +233 to +235
3. If there is still a tie, the first option in the data structure storing the metrics is selected,
which is an arbitrary choice. A warning is emitted when this occurs.

Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

This list claims a final tie-breaker of selecting the first option in the data structure and emitting a warning. The current implementation only falls back to comparing (is_commissioned, commission_year) and explicitly notes that it does not guarantee all ties will be resolved; it also does not emit a warning on unresolved ties. Please update this section to reflect the actual fallback behaviour (and avoid implying deterministic selection or warnings that don’t occur).

Suggested change
3. If there is still a tie, the first option in the data structure storing the metrics is selected,
which is an arbitrary choice. A warning is emitted when this occurs.
After applying these rules, remaining ties may still exist. The current implementation does not
guarantee that all such ties are resolved deterministically and does not emit a warning when they
occur.

Copilot uses AI. Check for mistakes.
Comment thread docs/model/investment.md
Comment on lines +196 to 197
sub-problem to minimise the asset's annualised cost, subject to its operational rules and the specific
demand tranche it is being asked to serve.
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

This line exceeds the configured markdownlint MD013 line-length limit (100 chars) and will be flagged by the repo’s markdownlint pre-commit hook. Please wrap the sentence (e.g., break after a comma) to keep each line within the limit.

Suggested change
sub-problem to minimise the asset's annualised cost, subject to its operational rules and the specific
demand tranche it is being asked to serve.
sub-problem to minimise the asset's annualised cost, subject to its operational rules
and the specific demand tranche it is being asked to serve.

Copilot uses AI. Check for mistakes.
Aurashk added 2 commits March 4, 2026 10:39
change warning message to log message
Copilot AI review requested due to automatic review settings March 4, 2026 11:03
@Aurashk Aurashk requested a review from alexdewar March 4, 2026 11:04
Copy link
Copy Markdown
Contributor

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

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


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/model/investment.md Outdated
Comment on lines +145 to +149
- **Optimise capacity and dispatch to maximise annualised profit:** Solve a small optimisation
sub-problem to maximise the asset's surplus, subject to its operational rules and the specific
demand tranche it is being asked to serve. \\(\varepsilon \approx 1×10^{-14}\\) is added to each
\\(AC_t \\) to allow assets which are breakeven (or very close to breakeven) to be dispatched.
demand tranche it is being asked to serve. \\(\varepsilon \approx 1\times 10^{-14}\\) is added to
each \\(AC_{t}^{NPV} \\) to allow assets which are breakeven (or very close to breakeven) to be
dispatched.
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

NPV optimisation adds \varepsilon to each activity coefficient (as written here), and in the implementation the same epsilon-adjusted coefficients are also used when computing total annualised surplus / profitability index. Consider clarifying in the subsequent PI/TAS definitions whether AC_t^{NPV} is meant to include this \varepsilon term (even if it’s negligible), so the documentation matches the metric calculation exactly.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings March 4, 2026 11:34
Copy link
Copy Markdown
Member

@alexdewar alexdewar left a comment

Choose a reason for hiding this comment

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

I spotted a couple more unescaped underscores, but otherwise all good 🎉!

Comment thread docs/model/investment.md
their annualised CAPEX plus FOM. For existing assets, the relevant fixed cost is its FOM.

- Calculate the specific process and commodity flow costs:
- Calculate the specific process and commodity flow costs (\\(\text{SPCF}\_{t})\\):
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I guess this doesn't really need to be a math block, but it's ok this way too.

Comment thread docs/model/investment.md Outdated
Comment thread docs/model/investment.md Outdated
Comment thread docs/model/investment.md Outdated
Comment thread docs/model/investment.md Outdated
Comment thread docs/model/investment.md Outdated
| Primary output (Electricity) | \\( output\_{coeff}[c_{primary}] \\) | 1.0 MWh per unit activity | Main commodity produced |
| By-product output (Waste heat) | \\( output\_{coeff}[c_{heat}] \\) | 0.5 MWh per unit activity | Co-product from generation |
| Input (Natural gas) | \\( input\_{coeff}[c_{gas}] \\) | 2.5 MWh per unit activity | Fuel consumption |
| Variable operating cost | \\( cost\_{var}[t] \\) | £5/MWh of activity | Operating costs per unit activity |
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It worked for me when I ran npx markdown-table-formatter docs/model/investment.md.

Anyways, I've committed the result and pushed it to this branch.

Copy link
Copy Markdown
Contributor

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

Copilot reviewed 1 out of 1 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/model/investment.md
Comment on lines +232 to +237
rules are applied in order:

1. Assets which are already commissioned are preferred over new candidate assets.
2. Newer (commissioned later) assets are preferred over older assets.
3. If there is still a tie, the first option in the data structure storing the metrics is selected,
which is an arbitrary choice. A `debug` level log message is emitted in this case.
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

The “Equal-Metric Fallback” section claims that if there is still a tie then “the first option in the data structure … is selected” and that a debug log is emitted. The current implementation sorts with a fallback on commissioned status / commission year, but does not emit a log and does not guarantee preserving original order when all compared fields are equal (Rust’s sort_by is not stable). Please adjust the wording to match the actual behavior (ties may remain unresolved / ordering unspecified), or update the implementation if deterministic tie-breaking + logging is required.

Suggested change
rules are applied in order:
1. Assets which are already commissioned are preferred over new candidate assets.
2. Newer (commissioned later) assets are preferred over older assets.
3. If there is still a tie, the first option in the data structure storing the metrics is selected,
which is an arbitrary choice. A `debug` level log message is emitted in this case.
preferences are applied:
1. Assets which are already commissioned are preferred over new candidate assets.
2. Newer (commissioned later) assets are preferred over older assets.
3. If there is still a tie after applying these preferences, the relative ordering of the remaining
options is implementation-defined and may not be deterministic (for example, it may depend on the
underlying sort algorithm). No specific log message is guaranteed to be emitted in this case.

Copilot uses AI. Check for mistakes.
Comment thread docs/model/investment.md
Comment on lines +297 to +301
AC_{t\_1}^{NPV} &= (1.0 \times 50) + (0.5 \times 15) + (-2.5 \times 25) - 5 \\\\
&= 50 + 7.5 - 62.5 - 5 \\\\
&= \text{£} -10 \text{/MWh}
\end{aligned}
\\]
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

In the NPV example for the off-peak period, the rendered unit value is written as \text{£} -10 \text{/MWh}, which is likely to typeset awkwardly (currency symbol separated from the negative sign/value). Consider formatting it as a single unit/value (e.g., -\text{£}10/\text{MWh} or \text{£-10/MWh}) for readability.

Copilot uses AI. Check for mistakes.
Co-authored-by: Alex Dewar <alexdewar@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 4, 2026 12:21
@Aurashk Aurashk merged commit 04b86f7 into main Mar 4, 2026
10 checks passed
@Aurashk Aurashk deleted the update-npv-docs branch March 4, 2026 12:25
Copy link
Copy Markdown
Contributor

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

Copilot reviewed 1 out of 1 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/model/investment.md
&+ \varepsilon \\\\
\end{aligned}
\\]
\\(\varepsilon \approx 1\times 10^{-14}\\) is added to
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

The epsilon magnitude here doesn’t match the implementation. In src/simulation/investment/appraisal/coefficients.rs, the NPV activity coefficients add MoneyPerActivity(f64::EPSILON * 100.0) (≈ 2.22e-14), not ~1×10^-14. Please update the docs to reflect the actual constant (or describe it in terms of f64::EPSILON * 100).

Suggested change
\\(\varepsilon \approx 1\times 10^{-14}\\) is added to
\\(\varepsilon = \texttt{f64::EPSILON} \times 100 \approx 2.22\times 10^{-14}\\) is added to

Copilot uses AI. Check for mistakes.
Comment thread docs/model/investment.md
This method is used when the decision rule is `single` and the objective is annualised profit for
agents serving commodity \\( c \\). It iteratively builds a supply portfolio by selecting
options that offer the highest annualised profit for serving the current commodity demand. The
economic evaluation uses \\( \pi_{prevMSY} \\) prices and takes account of asset-specific
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

This section refers to \( \pi_{prevMSY} \) prices, but earlier the document defines and uses previous-milestone prices as \( \lambda_{c,r,t} \). If these are the same concept, please use one symbol consistently; if they differ, add a short clarification of the relationship to avoid ambiguity.

Suggested change
economic evaluation uses \\( \pi_{prevMSY} \\) prices and takes account of asset-specific
economic evaluation uses previous-milestone prices \\( \lambda_{c,r,t} \\) and takes account of asset-specific

Copilot uses AI. Check for mistakes.
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

Successfully merging this pull request may close these issues.

Update documentation to describe how NPV is implemented

5 participants