Skip to content

fix: remove duplicate bidding strategy#827

Merged
maurerle merged 3 commits into
mainfrom
market_improvements
Jul 1, 2026
Merged

fix: remove duplicate bidding strategy#827
maurerle merged 3 commits into
mainfrom
market_improvements

Conversation

@maurerle

@maurerle maurerle commented Jun 30, 2026

Copy link
Copy Markdown
Member

User description

Description

This removes the redundant DsmCapacityHeuristicBalancingNegStrategy/DsmCapacityHeuristicBalancingPosStrategy - it is fine to have both names resolving to the same class, but not good to have duplicated codebase without benefit.

It looks similar, and actually was.

Additionally a bug in the base_market for the list of currently open auctions is fixed. This did not have any known use yet. This was also found in #810

Also
fixes #823

Checklist

  • Documentation updated (docstrings, READMEs, user guides, inline comments, docs folder updates, etc.)
  • New unit/integration tests added (if applicable)
  • Changes noted in release notes (if any)
  • Consent to release this PR's code under the GNU Affero General Public License v3.0

Additional Notes (optional)


PR Type

Bug fix, Enhancement, Documentation, Tests


Description

  • Filter empty additional_fields entries early

  • Correctly remove cleared products from open_auctions

  • Deduplicate DSM CRM strategies into one

  • Update docs, notebook, and tests


Diagram Walkthrough

flowchart LR
  cfg["Market config (additional_fields)"]
  mo["MarketConfig.__post_init__ validation"]
  bm["BaseMarket.clear_market"]
  oa["open_auctions set maintenance"]
  stratinit["assume.strategies registry"]
  dsm["DsmCapacityHeuristicBalancingStrategy"]
  tests["Updated tests/docs/examples"]

  cfg -- "sanitize/ignore empty key" --> mo
  bm -- "set subtraction fix" --> oa
  stratinit -- "map pos/neg DSM to one" --> dsm
  dsm -- "usage updated" --> tests
Loading

File Walkthrough

Relevant files
Error handling
1 files
market_objects.py
Warn and drop empty `additional_fields`                                   
+8/-1     
Bug fix
1 files
base_market.py
Fix `open_auctions` set subtraction bug                                   
+1/-1     
Enhancement
2 files
__init__.py
Repoint DSM CRM keys to unified strategy                                 
+7/-8     
naive_strategies.py
Merge DSM pos/neg CRM strategy classes                                     
+2/-41   
Tests
1 files
test_steam_plant.py
Update imports and CRM strategy fixtures                                 
+5/-6     
Documentation
2 files
bidding_strategies.rst
Refresh strategy API references after rename                         
+1/-2     
10a_DSU_and_flexibility.ipynb
Update notebook to unified DSM strategy                                   
+6/-8     

@github-actions

github-actions Bot commented Jun 30, 2026

Copy link
Copy Markdown

PR Reviewer Guide 🔍

(Review updated until commit ad71102)

Here are some key observations to aid the review process:

🎫 Ticket compliance analysis 🔶

810 - Partially compliant

Compliant requirements:

  • Preserve existing functionality and expected model behavior while applying fixes.

Non-compliant requirements:

  • Reduce memory growth during long-running, concurrent/multi-simulation workloads.
  • Clean up likely sources of retained objects / long-lived references / cache and lifecycle issues.
  • Note changes in release notes (if any).

Requires further human verification:

  • Update documentation related to the changes.
  • Reduce memory growth during long-running, concurrent/multi-simulation workloads (requires profiling/benchmarking in representative workloads to confirm).

823 - Partially compliant

Compliant requirements:

  • Ensure empty string keys in market config additional_fields are omitted.
  • Warn/fail early during config validation rather than later failing/printing "empty column name" during store_dfs writes.

Non-compliant requirements:

(empty)

Requires further human verification:

(empty)

⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🧪 PR contains tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Behavior Change

The new DsmCapacityHeuristicBalancingStrategy no longer includes a market_id field in generated bid dicts (the previous POS/NEG classes set market_id to CRM_pos/CRM_neg). If any downstream code relies on bid["market_id"] for routing, serialization, or grouping, this can trigger a KeyError or mis-classify bids specifically for CRM markets.

class DsmCapacityHeuristicBalancingStrategy(MinMaxStrategy):
    """
    Strategy for Positive/Negative CRM Reserve (Demand Side, i.e., up & down, symmetric).
    """

    def calculate_bids(self, unit, market_config, product_tuples, **kwargs):
        bids = []
        max_power = unit.max_plant_capacity
        min_power = unit.min_plant_capacity

        for product in product_tuples:
            start, end, only_hours = product
            block_times = [dt for dt in unit.index.get_date_list() if start <= dt < end]

            # For all time steps in block, calculate possible symmetric bid
            up_caps = []
            down_caps = []
            for t in block_times:
                flex = unit.flex_power_requirement.at[t]
                up_caps.append(max_power - flex)
                down_caps.append(flex - min_power)
            # The symmetric bid is the minimum capacity that is possible in *all* timesteps in the block
            symmetric_capacity = min(min(up_caps), min(down_caps))
            if symmetric_capacity > 0:
                bids.append(
                    {
                        "start_time": start,
                        "end_time": end,
                        "only_hours": only_hours,
                        "price": 0,  # or unit.calculate_marginal_cost(...)
                        "volume": symmetric_capacity,
                        "unit_id": unit.id,
                    }
                )
        return self.remove_empty_bids(bids)
Possible Issue

The check "" in self.additional_fields assumes additional_fields is always an iterable of strings. If additional_fields can be None (or another non-iterable) for some configs, this will raise a TypeError during initialization. Guarding with a truthy/type check (or normalizing to an empty list) would avoid config-time crashes.

def __post_init__(self):
    """
    Post-initialization checks for checks on failing initializations.
    """

    if "" in self.additional_fields:
        warn(
            "Empty string '' found in 'additional_fields' and will be ignored.",
            UserWarning,
        )
        self.additional_fields = [f for f in self.additional_fields if f != ""]

@github-actions

github-actions Bot commented Jun 30, 2026

Copy link
Copy Markdown

PR Code Suggestions ✨

Latest suggestions up to ad71102
Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Guard against non-iterable fields

This membership check will raise if additional_fields is None or otherwise
non-iterable during initialization. Guard the check by validating it is an iterable
collection before using in, then normalize to a list when filtering.

assume/common/market_objects.py [162-167]

-if "" in self.additional_fields:
+if isinstance(self.additional_fields, (list, tuple, set)) and "" in self.additional_fields:
     warn(
         "Empty string '' found in 'additional_fields' and will be ignored.",
         UserWarning,
     )
     self.additional_fields = [f for f in self.additional_fields if f != ""]
Suggestion importance[1-10]: 5

__

Why: Adding an isinstance guard prevents TypeError if self.additional_fields is None or otherwise non-iterable when "" in self.additional_fields runs, improving robustness of __post_init__. Impact is moderate since it’s defensive and may be unnecessary if additional_fields is guaranteed to be a list elsewhere.

Low

Previous suggestions

Suggestions up to commit c2bf0a8
CategorySuggestion                                                                                                                                    Impact
General
Preserve backwards-compatible class names

Renaming/removing the two previous strategy classes can break downstream users that
still import them. Provide backward-compatible aliases to the new unified strategy
so existing imports keep working without changing behavior.

assume/strategies/naive_strategies.py [566]

 return self.remove_empty_bids(bids)
 
+
+# Backwards-compatible aliases
+DsmCapacityHeuristicBalancingPosStrategy = DsmCapacityHeuristicBalancingStrategy
+DsmCapacityHeuristicBalancingNegStrategy = DsmCapacityHeuristicBalancingStrategy
+
Suggestion importance[1-10]: 6

__

Why: Adding aliases for the removed classes (DsmCapacityHeuristicBalancingPosStrategy/NegStrategy) to point to DsmCapacityHeuristicBalancingStrategy is a practical compatibility improvement that can prevent breakage for external users still importing the old names, without changing runtime behavior of the unified strategy.

Low

@codecov

codecov Bot commented Jun 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 60.00000% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.13%. Comparing base (d8d42d5) to head (ad71102).

Files with missing lines Patch % Lines
assume/common/market_objects.py 33.33% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #827      +/-   ##
==========================================
- Coverage   82.18%   82.13%   -0.06%     
==========================================
  Files          56       56              
  Lines        9087     9072      -15     
==========================================
- Hits         7468     7451      -17     
- Misses       1619     1621       +2     
Flag Coverage Δ
pytest 82.13% <60.00%> (-0.06%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 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.

@github-actions

Copy link
Copy Markdown

Failed to generate code suggestions for PR

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown

Persistent review updated to latest commit ad71102

@reinecfi reinecfi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks good

@maurerle
maurerle merged commit 04d23ae into main Jul 1, 2026
9 of 10 checks passed
@maurerle
maurerle deleted the market_improvements branch July 1, 2026 13:58
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.

market: empty '' should be left out from additional fields in market config

2 participants