Skip to content

Add output threshold and myopic capacity config#272

Open
SutubraResearch wants to merge 4 commits intoTemoaProject:unstablefrom
SutubraResearch:pr/small-features
Open

Add output threshold and myopic capacity config#272
SutubraResearch wants to merge 4 commits intoTemoaProject:unstablefrom
SutubraResearch:pr/small-features

Conversation

@SutubraResearch
Copy link
Collaborator

@SutubraResearch SutubraResearch commented Mar 11, 2026

Summary

Two independent small features that add configurability:

  • Output threshold filtering: Add output_threshold parameters to config that filter near-zero flow values from output tables. Reduces output database size significantly for large models where many technology-vintage combinations have negligible flows. Default 0.01 preserves current behaviour for small models.
  • Myopic capacity threshold: Allow the capacity threshold for carrying forward existing capacity in myopic mode to be set in the scenario config rather than hardcoded. Default remains 10 MW.

Files changed

File Change
temoa/_internal/table_writer.py Threshold filtering logic
temoa/core/config.py New config parameters
temoa/db_schema/temoa_schema_v4.sql Schema column for threshold
temoa/tutorial_assets/config_sample.toml Sample config documentation
temoa/extensions/myopic/myopic_sequencer.py Read threshold from config

Test plan

  • All 190 tests pass
  • Default values preserve existing behaviour
  • Both features are independent

Summary by CodeRabbit

  • New Features
    • Per-category configurable output thresholds for capacity, activity, emission, and cost, with sensible defaults and validation.
    • Thresholds applied across reporting and polling so tiny values can be filtered per output type.
  • Bug Fixes / Improvements
    • Cost output now aggregates components and omits rows when all cost parts fall below the cost threshold.
    • Sequencing/cleanup logic now respects the configured capacity threshold.
  • Documentation
    • Added sample config entries showing the new per-output thresholds.

@coderabbitai
Copy link

coderabbitai bot commented Mar 11, 2026

Walkthrough

This PR adds per-type output filtering thresholds for capacity, activity, emission, and cost. TemoaConfig gains four new optional threshold fields. TableWriter resolves and applies per-type thresholds (with validation and defaults) throughout output generation and cost row writing. The myopic sequencer uses a configurable capacity threshold instead of a hard-coded epsilon.

Changes

Cohort / File(s) Summary
Configuration Layer
temoa/core/config.py, temoa/tutorial_assets/config_sample.toml
Added four optional output threshold parameters (output_threshold_capacity, output_threshold_activity, output_threshold_emission, output_threshold_cost) to TemoaConfig and example TOML entries.
Output Filtering Implementation
temoa/_internal/table_writer.py
Added OUTPUT_THRESHOLD_DEFAULTS constant; introduced _validate_threshold and _resolve_output_threshold; removed single epsilon parameter and added per-type thresholds (output_threshold_capacity, output_threshold_activity, output_threshold_emission, output_threshold_cost); applied per-type thresholds across emission, capacity, flow/activity, and cost write paths; expanded cost row aggregation and per-record threshold skipping.
Extension Integration
temoa/extensions/myopic/myopic_sequencer.py
Replaced hard-coded capacity epsilon with a configurable threshold sourced from config.myopic_inputs.capacity_threshold (fallback default applied) and passed it into removal/delete operations.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.32% 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 'Add output threshold and myopic capacity config' accurately summarizes the main changes: introducing configurable output thresholds for filtering near-zero values and making the myopic capacity threshold configurable.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

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

@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/_internal/table_writer.py (1)

84-111: 🧹 Nitpick | 🔵 Trivial

The epsilon parameter is effectively dead code.

The __init__ signature accepts epsilon: float = 1e-5 at Line 84, but this value is immediately overwritten at Lines 106-111 with the minimum of the resolved per-type thresholds. Any caller passing an epsilon value will have it silently ignored.

Consider removing the parameter to avoid confusion:

♻️ Proposed fix
-    def __init__(self, config: TemoaConfig, epsilon: float = 1e-5) -> None:
+    def __init__(self, config: TemoaConfig) -> None:
         self.config = config
-        self.epsilon = epsilon
         self.tech_sectors: dict[str, str] | None = None
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@temoa/_internal/table_writer.py` around lines 84 - 111, The __init__
parameter epsilon is unused because self.epsilon is overwritten later by the min
of resolved thresholds (_resolve_output_threshold), so remove the epsilon
parameter from the __init__ signature and any initial assignment (remove
"epsilon: float = 1e-5" and the early "self.epsilon = epsilon"), leaving the
final self.epsilon = min(...) logic intact; update any call sites / tests that
instantiate this class to stop passing an epsilon and adjust any docstrings or
type annotations referencing the constructor parameter.
🤖 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/extensions/myopic/myopic_sequencer.py`:
- Around line 67-75: Update the sample TOML to document the new myopic option:
add a capacity_threshold entry under the [myopic] section (matching the default
used by the code where config.myopic_inputs.get('capacity_threshold',
default_cap_threshold) sets self.capacity_epsilon) with the default value 10 and
a short comment like "minimum capacity (MW) to carry forward between periods" so
users can discover and override the capacity_threshold used by the myopic
sequencer.

---

Outside diff comments:
In `@temoa/_internal/table_writer.py`:
- Around line 84-111: The __init__ parameter epsilon is unused because
self.epsilon is overwritten later by the min of resolved thresholds
(_resolve_output_threshold), so remove the epsilon parameter from the __init__
signature and any initial assignment (remove "epsilon: float = 1e-5" and the
early "self.epsilon = epsilon"), leaving the final self.epsilon = min(...) logic
intact; update any call sites / tests that instantiate this class to stop
passing an epsilon and adjust any docstrings or type annotations referencing the
constructor parameter.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: d2dd4959-b16b-4a93-bd60-6ec6438a7a36

📥 Commits

Reviewing files that changed from the base of the PR and between 7f7ff86 and 39a0231.

📒 Files selected for processing (5)
  • temoa/_internal/table_writer.py
  • temoa/core/config.py
  • temoa/db_schema/temoa_schema_v4.sql
  • temoa/extensions/myopic/myopic_sequencer.py
  • temoa/tutorial_assets/config_sample.toml

Copy link

@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

🤖 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/tutorial_assets/config_sample.toml`:
- Around line 95-96: The comment about precedence is inaccurate because
table_writer.py::_resolve_output_threshold currently only reads the TOML config
value and falls back to OUTPUT_THRESHOLD_DEFAULTS without checking any
"metadata_real in output db"; either update the doc comment to reflect actual
behavior ("Precedence is: TOML value > internal defaults") or implement the
missing DB lookup by adding a metadata read in _resolve_output_threshold that
checks the output DB for metadata_real and uses it as the middle precedence
before falling back to OUTPUT_THRESHOLD_DEFAULTS.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0cf090f8-d51a-4cfd-a7ff-c07c5a732b6a

📥 Commits

Reviewing files that changed from the base of the PR and between 39a0231 and 5dbc761.

📒 Files selected for processing (11)
  • temoa/_internal/table_writer.py
  • temoa/core/config.py
  • temoa/extensions/myopic/myopic_sequencer.py
  • temoa/tutorial_assets/config_sample.toml
  • tests/testing_data/mediumville_sets.json
  • tests/testing_data/test_system_sets.json
  • tests/testing_data/utopia_sets.json
  • tests/utilities/capture_set_values_for_cache.py
  • tests/utilities/config_mediumville.toml
  • tests/utilities/config_test_system.toml
  • tests/utilities/config_utopia.toml

Add output_threshold config option to filter near-zero values from
result tables. Defaults to 0 (no filtering). Controlled entirely via
config file, no database schema changes.
Copy link

@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: 3

♻️ Duplicate comments (1)
temoa/extensions/myopic/myopic_sequencer.py (1)

67-69: ⚠️ Potential issue | 🟡 Minor

Please add capacity_threshold to the sample [myopic] config docs.

This code advertises TOML configurability, but temoa/tutorial_assets/config_sample.toml still does not show the option under [myopic], which makes discovery difficult for users.

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

In `@temoa/extensions/myopic/myopic_sequencer.py` around lines 67 - 69, The sample
config is missing the advertised TOML key for the myopic capacity threshold; add
a capacity_threshold entry under the [myopic] section in
temoa/tutorial_assets/config_sample.toml (key name: capacity_threshold) with a
brief comment and the default value 10 to match default_cap_threshold in
myopic_sequencer.py so users can discover and override the setting.
🤖 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/_internal/table_writer.py`:
- Around line 249-260: The _validate_threshold function currently allows
non-finite floats; update it to reject NaN and infinities by checking
math.isfinite(numeric_value) after converting threshold_value to float and
raising ValueError if not finite (include threshold_name in the message); use
the standard library math.isfinite to perform the check in the
_validate_threshold method so non-finite values are rejected during config
parsing.
- Around line 102-111: The constructor currently ignores a passed-in epsilon
because after resolving per-type thresholds via _resolve_output_threshold() you
overwrite epsilon with the minimum of those resolved values; update the
constructor so that if an explicit epsilon argument is provided it is applied to
all per-type thresholds (output_threshold_capacity, output_threshold_activity,
output_threshold_emission, output_threshold_cost) before or instead of calling
_resolve_output_threshold(), or else mark epsilon deprecated and remove it;
specifically, detect a non-None/explicit epsilon value in __init__ and assign it
to each output_threshold_* or bypass _resolve_output_threshold() accordingly,
ensuring self.epsilon retains the caller-provided value and that
_resolve_output_threshold() is only used for unspecified per-type threshold
values.

In `@temoa/extensions/myopic/myopic_sequencer.py`:
- Around line 67-75: The carry-forward delete/query in
update_myopic_efficiency_table is missing the capacity threshold check so
[myopic].capacity_threshold (stored on self.capacity_epsilon) is ignored; update
the SQL/ORM delete and any selection logic in update_myopic_efficiency_table to
only carry forward rows whose capacity magnitude meets the configured threshold
(e.g., add a WHERE ABS(capacity) >= :capacity_epsilon or capacity >=
:capacity_epsilon using self.capacity_epsilon), and ensure the parameter is
passed as a numeric value from the initialized self.capacity_epsilon.

---

Duplicate comments:
In `@temoa/extensions/myopic/myopic_sequencer.py`:
- Around line 67-69: The sample config is missing the advertised TOML key for
the myopic capacity threshold; add a capacity_threshold entry under the [myopic]
section in temoa/tutorial_assets/config_sample.toml (key name:
capacity_threshold) with a brief comment and the default value 10 to match
default_cap_threshold in myopic_sequencer.py so users can discover and override
the setting.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: d533b442-237e-49ef-8f30-625d6a9a5fa5

📥 Commits

Reviewing files that changed from the base of the PR and between 5dbc761 and 233fea0.

📒 Files selected for processing (4)
  • temoa/_internal/table_writer.py
  • temoa/core/config.py
  • temoa/extensions/myopic/myopic_sequencer.py
  • temoa/tutorial_assets/config_sample.toml

Copy link

@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

🤖 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/extensions/myopic/myopic_sequencer.py`:
- Around line 67-75: The value assigned to self.capacity_epsilon must be
validated like TableWriter._validate_threshold(): retrieve the raw value from
config.myopic_inputs.get('capacity_threshold', default_cap_threshold), ensure it
is finite (not NaN/inf) and >= 0, and either call/reuse
TableWriter._validate_threshold(raw_value) or perform the same checks and raise
ValueError (or fall back to default_cap_threshold) if invalid; update the
assignment of capacity_epsilon accordingly so negative or non-finite config
values cannot be used in later SQL comparisons.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4546d0ad-f9a7-428f-b8a9-cac862aa575e

📥 Commits

Reviewing files that changed from the base of the PR and between 233fea0 and 6a7dd79.

📒 Files selected for processing (2)
  • temoa/_internal/table_writer.py
  • temoa/extensions/myopic/myopic_sequencer.py

Comment on lines +67 to +75
# Minimum capacity (MW) to carry forward between myopic periods.
# Configurable via [myopic] capacity_threshold in TOML.
default_cap_threshold = 1e-3
if config and config.myopic_inputs:
self.capacity_epsilon = config.myopic_inputs.get(
'capacity_threshold', default_cap_threshold
)
else:
self.capacity_epsilon = default_cap_threshold
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Missing validation for capacity_threshold from config.

TableWriter._validate_threshold() rejects negative and non-finite values, but here the value from config.myopic_inputs.get('capacity_threshold', ...) is used directly without validation. If a user configures a negative, NaN, or inf value, the SQL query behavior becomes undefined (e.g., ABS(capacity) >= NaN is always false).

Consider adding validation consistent with TableWriter:

♻️ Proposed fix to add validation
+import math
+
+def _validate_capacity_threshold(value: float, default: float) -> float:
+    """Validate capacity threshold, returning default if invalid."""
+    if not isinstance(value, (int, float)):
+        return default
+    if not math.isfinite(value) or value < 0:
+        return default
+    return float(value)
+
 class MyopicSequencer:
     ...
     def __init__(self, config: TemoaConfig | None):
         # Minimum capacity (MW) to carry forward between myopic periods.
         # Configurable via [myopic] capacity_threshold in TOML.
         default_cap_threshold = 1e-3
         if config and config.myopic_inputs:
-            self.capacity_epsilon = config.myopic_inputs.get(
+            raw_threshold = config.myopic_inputs.get(
                 'capacity_threshold', default_cap_threshold
             )
+            self.capacity_epsilon = _validate_capacity_threshold(raw_threshold, default_cap_threshold)
         else:
             self.capacity_epsilon = default_cap_threshold
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Minimum capacity (MW) to carry forward between myopic periods.
# Configurable via [myopic] capacity_threshold in TOML.
default_cap_threshold = 1e-3
if config and config.myopic_inputs:
self.capacity_epsilon = config.myopic_inputs.get(
'capacity_threshold', default_cap_threshold
)
else:
self.capacity_epsilon = default_cap_threshold
# Minimum capacity (MW) to carry forward between myopic periods.
# Configurable via [myopic] capacity_threshold in TOML.
default_cap_threshold = 1e-3
if config and config.myopic_inputs:
raw_threshold = config.myopic_inputs.get(
'capacity_threshold', default_cap_threshold
)
self.capacity_epsilon = _validate_capacity_threshold(raw_threshold, default_cap_threshold)
else:
self.capacity_epsilon = default_cap_threshold
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@temoa/extensions/myopic/myopic_sequencer.py` around lines 67 - 75, The value
assigned to self.capacity_epsilon must be validated like
TableWriter._validate_threshold(): retrieve the raw value from
config.myopic_inputs.get('capacity_threshold', default_cap_threshold), ensure it
is finite (not NaN/inf) and >= 0, and either call/reuse
TableWriter._validate_threshold(raw_value) or perform the same checks and raise
ValueError (or fall back to default_cap_threshold) if invalid; update the
assignment of capacity_epsilon accordingly so negative or non-finite config
values cannot be used in later SQL comparisons.

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.

1 participant