Skip to content

Fix sliding window eviction crash in ModelDataSet#3389

Merged
quaquel merged 14 commits intomesa:mainfrom
ShreyasN707:fix/modeldataset-window-eviction
Mar 3, 2026
Merged

Fix sliding window eviction crash in ModelDataSet#3389
quaquel merged 14 commits intomesa:mainfrom
ShreyasN707:fix/modeldataset-window-eviction

Conversation

@ShreyasN707
Copy link
Copy Markdown
Contributor

Fixes a crash in ModelDataSet when window_size is enabled by standardizing how blocks are stored internally.

Issue: #3378

When the sliding window eviction runs, _evict_blocks expects blocks in the format (time, data).
However, dict-based data was being stored as a merged dictionary ({"time": time, **data}), which caused a ValueError during unpacking and crashed the data collection process.

Implementation

Unified the storage format so all blocks (including dict data) are stored as (time, data) tuples.
The merge into {"time": time, **data} is now handled only when building the final DataFrame.

Core change:

# datarecorders.py

case dict():
    storage.blocks.append((time, data))
    storage.total_rows += 1
rows = [{**data, "time": time} for time, data in storage.blocks]
return pd.DataFrame(rows)

@github-actions
Copy link
Copy Markdown

Performance benchmarks:

Model Size Init time [95% CI] Run time [95% CI]
BoltzmannWealth small 🔵 -2.0% [-2.7%, -1.2%] 🟢 -4.2% [-4.6%, -3.8%]
BoltzmannWealth large 🔵 -0.0% [-0.5%, +0.5%] 🔵 +1.3% [-0.3%, +3.2%]
Schelling small 🔵 +0.5% [-0.1%, +1.0%] 🔵 +1.8% [+1.6%, +1.9%]
Schelling large 🔵 -1.1% [-2.0%, -0.1%] 🔵 -2.0% [-4.4%, +0.5%]
WolfSheep small 🟢 -4.9% [-5.8%, -4.1%] 🔵 -2.2% [-2.6%, -1.8%]
WolfSheep large 🟢 -4.8% [-6.4%, -3.1%] 🟢 -8.7% [-10.9%, -6.4%]
BoidFlockers small 🔵 -0.8% [-1.1%, -0.5%] 🔵 -0.7% [-0.9%, -0.6%]
BoidFlockers large 🔵 -0.0% [-0.6%, +0.4%] 🔵 -0.2% [-0.5%, -0.0%]

@ShreyasN707 ShreyasN707 force-pushed the fix/modeldataset-window-eviction branch 3 times, most recently from b3da951 to 4a3b3ff Compare February 27, 2026 17:33
@ShreyasN707
Copy link
Copy Markdown
Contributor Author

@EwoutH Tests are passing now — updated the dict storage to (time, data).

@quaquel
Copy link
Copy Markdown
Member

quaquel commented Feb 28, 2026

@codebreaker32 could you take a look at this?

Copy link
Copy Markdown
Collaborator

@codebreaker32 codebreaker32 left a comment

Choose a reason for hiding this comment

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

Good catch and thanks for this PR @ShreyasN707 However I have some minor requests:

  1. Please remove "time" from the storage.metadata["columns"] as well, keeping it in the metadata columns will cause empty DataFrames to have an inconsistent schema.
  2. Could you add a specific test that explicitly guards against the ValueError crash?

I will give it a final look once you push the changes

@ShreyasN707 ShreyasN707 force-pushed the fix/modeldataset-window-eviction branch from 01dddc0 to d4cd210 Compare March 1, 2026 04:37
@ShreyasN707 ShreyasN707 force-pushed the fix/modeldataset-window-eviction branch from 6c05284 to 0985233 Compare March 1, 2026 04:49
storage.metadata["type"] = "custom"

# Update bookkeeping for evicted data
"""Update bookkeeping for evicted data"""
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please don't use triple quotes for inline comments


if not storage.blocks:
# Empty DataFrame with correct columns
""" Empty DataFrame with correct columns"""
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please don't use triple quotes for inline comments

return self._convert_modelDataSet(storage)
case _:
# Fallback
"""Fallback"""
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Same as above


def test_data_recorder_window_eviction_dict():
"""Test window eviction bookkeeping for dict data."""
def test_modeldataset_window_eviction_crash():
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why did you change the name?

Comment on lines -326 to -329
# Fill window
recorder.collect()
recorder.collect()
recorder.collect() # Should evict first
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Same as above

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Looks like I removed a few comments unintentionally during conflict resolution. My bad I’ll correct that and update the PR.

@codebreaker32
Copy link
Copy Markdown
Collaborator

codebreaker32 commented Mar 1, 2026

I still couldn't see the test that explicitly guards against the ValueError mentioned in issue

@ShreyasN707
Copy link
Copy Markdown
Contributor Author

I still couldn't see the test that explicitly guards against the ValueError mentioned in issue

I’ll recheck the branch it’s possible the test didn’t get pushed properly. I’ll confirm and fix it right away.

@ShreyasN707 ShreyasN707 force-pushed the fix/modeldataset-window-eviction branch from d364219 to 32654d6 Compare March 1, 2026 06:53
Comment on lines +172 to +173
if "time" not in columns:
columns = [*columns, "time"]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes adding "time" there was unnecessary; I'll remove it to keep the schema aligned with metadata-defined columns.

"""Convert model dict blocks to DataFrame."""
if not storage.blocks:
return pd.DataFrame(columns=storage.metadata.get("columns", []))
return pd.DataFrame(columns=[*storage.metadata.get("columns", []), "time"])
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

See above

Comment on lines +327 to +328
def test_modeldataset_window_eviction_no_valueerror():
"""Explicit regression test for ValueError during sliding window eviction (#3378)."""
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It seems repetitive to me. Isn't it similar to above test? I am fine with above tests only

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It overlapped with the existing dict eviction test. The only difference was an explicit try/except for the ValueError, but pytest already fails on uncaught exceptions, so it was redundant.

@ShreyasN707 ShreyasN707 force-pushed the fix/modeldataset-window-eviction branch from 6683a8f to 389e1db Compare March 2, 2026 10:17
@ShreyasN707 ShreyasN707 force-pushed the fix/modeldataset-window-eviction branch from d1221d9 to 805384a Compare March 2, 2026 10:22
Copy link
Copy Markdown
Collaborator

@codebreaker32 codebreaker32 left a comment

Choose a reason for hiding this comment

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

LGTM! Thanks

@quaquel
Copy link
Copy Markdown
Member

quaquel commented Mar 2, 2026

tests are failing, so that needs to be addressed before merging this PR.

@quaquel quaquel merged commit aa3787e into mesa:main Mar 3, 2026
11 of 12 checks passed
@EwoutH EwoutH added bug Release notes label experimental Release notes label labels Mar 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Release notes label experimental Release notes label

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants