Skip to content

Clean up capacity index sets#289

Merged
ParticularlyPythonicBS merged 6 commits intoTemoaProject:unstablefrom
idelder:rework/capacity_indices
Mar 27, 2026
Merged

Clean up capacity index sets#289
ParticularlyPythonicBS merged 6 commits intoTemoaProject:unstablefrom
idelder:rework/capacity_indices

Conversation

@idelder
Copy link
Copy Markdown
Collaborator

@idelder idelder commented Mar 27, 2026

The constraint indices sets in components/capacity.py were indented to the centre of the earth. Brought them in line with set comprehension standards laid out in docs.

Also clarified naming of activity_capacity sets and tidied up their instantiation. Cleaned up the weird "using cost fixed constraint indices for other things" situation. Clarified naming and usage generally.

As a result, found that capacity factors for storage were being silently ignored, which I thought were intentionally not supported until I found there are storage capacity factors in utopia. Turned these capacity factors on inside the storage_throughput_constraint (i.e., charge + discharge flows now constrained by CF, if defined). Made sure all capacity factor calls are using the efficient prepared dictionary lookup.

Finally, unified the formatting for declaration of index functions. <--- I think this may need to be reflected in docs after those are updated. As part of this, removed the | None type for construction sets as they are explicitly declared with = set() so therefore are never none (and this triggers mypy hell where you need to handle the none case everywhere)

Summary by CodeRabbit

  • Refactoring

    • Simplified many index-set helpers to return computed sets directly and centralized capacity-factor logic in a shared utility, streamlining constraint and variable indexing.
    • Reorganized internal capacity indexing and initialization for greater consistency.
  • Behavioral

    • Storage throughput and reserve calculations now use the unified capacity-factor lookup, producing slightly updated model results.
  • Chores

    • Tightened type annotations (removed nullable set types) and updated test expected values to match current outputs.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 27, 2026

Walkthrough

Refactors capacity-related indexing and moves capacity-factor selection into utils.get_capacity_factor; simplifies many index-set builders to direct set comprehensions; removes nullable set type annotations; updates model initialization to use the new index sources and adjusts storage/reserve throughput calculations and tests accordingly.

Changes

Cohort / File(s) Summary
Capacity core & utils
temoa/components/capacity.py, temoa/components/utils.py
Moved capacity-factor selection into get_capacity_factor; renamed/reshaped capacity index helpers (capacity_variable_indicesnew_capacity_variable_indices, new capacity_variable_indices returning RPTV); rebuilt capacity set constructors to use process_periods/process_vintages and model.active_capacity_rptv.
Model wiring
temoa/core/model.py
Rewired internal index sources: capacity_var_rptv now from capacity.capacity_variable_indices; new_capacity_var_rtv from capacity.new_capacity_variable_indices; replaced active_capacity_available_rptv with active_capacity_rptv.
Reserves & storage updates
temoa/components/reserves.py, temoa/components/storage.py
Replaced direct capacity-factor parameter lookups with get_capacity_factor(...) in reserve_margin_dynamic; added capacity-factor multiplier in storage_throughput_constraint; removed conditional empty-set returns in several storage index builders.
Costs & capacity indices
temoa/components/costs.py, temoa/components/capacity.py
cost_fixed_indices now returns model.active_capacity_rptv; cost_variable_indices returns model.active_activity_rptv; capacity index helper return shapes adjusted to match new sets.
Index-set simplifications across components
temoa/components/commodities.py, temoa/components/emissions.py, temoa/components/limits.py, temoa/components/operations.py, temoa/components/flows.py, temoa/components/technology.py
Replaced intermediate indices locals and explicit return indices with direct return { ... } set comprehensions; removed `
Type alias normalization
temoa/types/set_types.py
Removed `
Tests updated
tests/legacy_test_values.py, tests/test_full_runs.py
Adjusted expected numeric test values: legacy objective and specific test expectations updated to new values.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested labels

refactor, Maintenance

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.82% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Clean up capacity index sets' directly summarizes the main change: refactoring and simplifying capacity-related index set functions and their declarations across the codebase.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
temoa/components/reserves.py (1)

150-165: ⚠️ Potential issue | 🔴 Critical

Fix KeyError in get_capacity_factor when called with exchange region keys.

The get_capacity_factor function at lines 150 and 161 calls get_capacity_factor(model, r1r2, s, d, t, v) with exchange region keys (e.g., "REG1-REG2"). However, get_capacity_factor directly accesses model.is_capacity_factor_process[r, t, v] without a fallback. The dictionary is only populated during check_capacity_factor_process for (r, t, v) tuples where (r, t) appears in capacity_factor_rsdt, which is derived from active_capacity_available_rpt. Since active_capacity_available_rpt is built from process_vintages and process_vintages can contain exchange region keys (from efficiency entries with regional_indices), an exchange technology with efficiency but no capacity_factor_tech entry will cause a KeyError when get_capacity_factor is invoked.

Add a .get() fallback in get_capacity_factor to return capacity_factor_tech as the default when the process is not in is_capacity_factor_process.

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@temoa/components/capacity.py`:
- Around line 152-155: The nullable return annotations in
new_capacity_variable_indices and capacity_available_variable_indices are
incorrect because TemoaModel.__init__ initializes new_capacity_rtv and
active_capacity_rptv to empty sets; remove the " | None" from both function
return types so they return set[tuple[Region, Technology, Vintage]]
consistently. Locate the functions new_capacity_variable_indices and
capacity_available_variable_indices and change their signatures to return
set[tuple[Region, Technology, Vintage]] (not nullable), keeping the bodies that
return model.new_capacity_rtv and model.active_capacity_rptv respectively.

In `@temoa/components/utils.py`:
- Around line 85-91: In get_capacity_factor, remove the unnecessary else after
the first return to satisfy style linter Ruff RET505: keep the if branch
returning value(model.capacity_factor_process[...]) and then directly return
value(model.capacity_factor_tech[...]) (reference function get_capacity_factor
and the keys model.is_capacity_factor_process, model.capacity_factor_process,
model.capacity_factor_tech).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9fae0944-7ab2-479c-aa1b-82578ec5288b

📥 Commits

Reviewing files that changed from the base of the PR and between cb703e5 and 3bfc489.

📒 Files selected for processing (13)
  • temoa/components/capacity.py
  • temoa/components/commodities.py
  • temoa/components/costs.py
  • temoa/components/emissions.py
  • temoa/components/limits.py
  • temoa/components/operations.py
  • temoa/components/reserves.py
  • temoa/components/storage.py
  • temoa/components/utils.py
  • temoa/core/model.py
  • temoa/types/set_types.py
  • tests/legacy_test_values.py
  • tests/test_full_runs.py

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
temoa/components/storage.py (1)

519-523: ⚠️ Potential issue | 🟡 Minor

Refresh the throughput equation to include the capacity factor.

The implementation now derates storage throughput with get_capacity_factor(...), but the docstring still documents the old CAP * C2A * SEG bound. Please update the math block so the code and generated docs describe the same formulation.

📝 Suggested doc fix
-          \textbf{CAP}_{r,t,v} \cdot C2A_{r,t} \cdot SEG_{s,d}
+          \text{CF}_{r,s,d,t,v} \cdot \textbf{CAP}_{r,t,v} \cdot C2A_{r,t} \cdot SEG_{s,d}

Also applies to: 542-547

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@temoa/components/storage.py` around lines 519 - 523, The docstring math
blocks still show the old bound "CAP_{r,t,v} * C2A_{r,t} * SEG_{s,d}" but the
code derates throughput using get_capacity_factor(...); update both affected
LaTeX/math blocks (the one with FO, FIS, EFF and the other at the later block)
to multiply the right-hand side by the capacity factor (e.g., CAP_{r,t,v} *
C2A_{r,t} * SEG_{s,d} * CF_{r,t,v} or explicitly call out
get_capacity_factor(r,t,v)), keeping the original symbols FO_{...}, FIS_{...},
EFF_{...}, CAP_{...}, C2A_{...}, SEG_{...} unchanged so docs match the
implementation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@temoa/components/capacity.py`:
- Around line 648-652: The docstring for create_capacity_and_retirement_sets()
still refers to model.active_capacity_available_rptv while the implementation
populates model.active_capacity_rptv; update the function docstring to mention
model.active_capacity_rptv (and any explanatory text that uses the old name) so
the documentation matches the actual set created by the function and avoid the
old name model.active_capacity_available_rptv.

---

Outside diff comments:
In `@temoa/components/storage.py`:
- Around line 519-523: The docstring math blocks still show the old bound
"CAP_{r,t,v} * C2A_{r,t} * SEG_{s,d}" but the code derates throughput using
get_capacity_factor(...); update both affected LaTeX/math blocks (the one with
FO, FIS, EFF and the other at the later block) to multiply the right-hand side
by the capacity factor (e.g., CAP_{r,t,v} * C2A_{r,t} * SEG_{s,d} * CF_{r,t,v}
or explicitly call out get_capacity_factor(r,t,v)), keeping the original symbols
FO_{...}, FIS_{...}, EFF_{...}, CAP_{...}, C2A_{...}, SEG_{...} unchanged so
docs match the implementation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6540de56-6352-4fe7-b89a-69375bf70bc1

📥 Commits

Reviewing files that changed from the base of the PR and between 3bfc489 and b28e082.

📒 Files selected for processing (5)
  • temoa/components/capacity.py
  • temoa/components/flows.py
  • temoa/components/storage.py
  • temoa/components/technology.py
  • temoa/components/utils.py

Comment on lines +648 to 652
model.active_capacity_rptv = {
(r, p, t, v)
for r, p, t in model.process_vintages
for r, p, t in model.active_capacity_available_rpt
for v in model.process_vintages[r, p, t]
if t not in model.tech_uncap
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Rename the documented set to active_capacity_rptv.

create_capacity_and_retirement_sets() now populates model.active_capacity_rptv, but the function docstring still advertises model.active_capacity_available_rptv. That leaves the new capacity-index naming self-contradictory right where the rename was introduced.

📝 Suggested doc fix
-        - model.active_capacity_available_rptv: set of (r, p, t, v) where vintage capacity is
+        - model.active_capacity_rptv: set of (r, p, t, v) where vintage capacity is
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@temoa/components/capacity.py` around lines 648 - 652, The docstring for
create_capacity_and_retirement_sets() still refers to
model.active_capacity_available_rptv while the implementation populates
model.active_capacity_rptv; update the function docstring to mention
model.active_capacity_rptv (and any explanatory text that uses the old name) so
the documentation matches the actual set created by the function and avoid the
old name model.active_capacity_available_rptv.

@ParticularlyPythonicBS ParticularlyPythonicBS merged commit 5627935 into TemoaProject:unstable Mar 27, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants