Skip to content

GEOPY-2604: add validation to exclude plate-simulation and depth of investigation…#395

Open
benk-mira wants to merge 1 commit intorelease/GA_4.8from
GEOPY-2604
Open

GEOPY-2604: add validation to exclude plate-simulation and depth of investigation…#395
benk-mira wants to merge 1 commit intorelease/GA_4.8from
GEOPY-2604

Conversation

@benk-mira
Copy link
Copy Markdown
Contributor

@benk-mira benk-mira commented Apr 30, 2026

GEOPY-2604 - Validate incorrect SimPEGGroups in tile estimator and fail gracefully
… SimPEGGroups

Copilot AI review requested due to automatic review settings April 30, 2026 18:29
@benk-mira benk-mira changed the title add validation to exclude plate-simulation and depth of investigation… GEOPY-2604 Apr 30, 2026
@github-actions github-actions Bot changed the title GEOPY-2604 GEOPY-2604: add validation to exclude plate-simulation and depth of investigation… Apr 30, 2026
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

Adds input validation to the tile estimation workflow to prevent unsupported SimPEGGroup targets (plate simulation and depth of investigation) from being used with the tile estimator.

Changes:

  • Added a Pydantic field validator on TileParameters.simulation to reject plate_simulation and depth_of_investigation run commands.
  • Added a new test asserting that plate simulation groups are rejected during TileParameters validation.

Reviewed changes

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

File Description
simpeg_drivers/utils/tile_estimate.py Introduces validation logic to exclude unsupported simulation targets for tile estimation.
tests/utils_tile_estimate_test.py Adds a regression test for the new simulation-target validation.

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

Comment on lines +21 to +30
def test_simulation_validation_rejects_plate_simulation(tmp_path):
simulation = MagicMock(spec=SimPEGGroup)
simulation.options = {
"run_command": "simpeg_drivers.plate_simulation.driver",
"title": "Plate Simulation",
}

with Workspace.create(tmp_path / "test.geoh5") as geoh5:
with pytest.raises(ValidationError, match="not a valid target"):
TileParameters(geoh5=geoh5, simulation=simulation)
Copy link

Copilot AI Apr 30, 2026

Choose a reason for hiding this comment

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

This only tests rejection of plate_simulation. Since the new validator also rejects depth_of_investigation (and should still accept valid forward/inverse drivers), add tests covering at least one depth_of_investigation.* run_command and one allowed run_command to avoid regressions.

Suggested change
def test_simulation_validation_rejects_plate_simulation(tmp_path):
simulation = MagicMock(spec=SimPEGGroup)
simulation.options = {
"run_command": "simpeg_drivers.plate_simulation.driver",
"title": "Plate Simulation",
}
with Workspace.create(tmp_path / "test.geoh5") as geoh5:
with pytest.raises(ValidationError, match="not a valid target"):
TileParameters(geoh5=geoh5, simulation=simulation)
@pytest.mark.parametrize(
("run_command", "title"),
[
("simpeg_drivers.plate_simulation.driver", "Plate Simulation"),
(
"simpeg_drivers.depth_of_investigation.driver",
"Depth of Investigation",
),
],
)
def test_simulation_validation_rejects_invalid_targets(tmp_path, run_command, title):
simulation = MagicMock(spec=SimPEGGroup)
simulation.options = {
"run_command": run_command,
"title": title,
}
with Workspace.create(tmp_path / "test.geoh5") as geoh5:
with pytest.raises(ValidationError, match="not a valid target"):
TileParameters(geoh5=geoh5, simulation=simulation)
def test_simulation_validation_accepts_valid_target(tmp_path):
simulation = MagicMock(spec=SimPEGGroup)
simulation.options = {
"run_command": "simpeg_drivers.electricals.direct_current.three_dimensions.driver",
"title": "Direct Current 3D",
}
with Workspace.create(tmp_path / "test.geoh5") as geoh5:
params = TileParameters(geoh5=geoh5, simulation=simulation)
assert params.simulation is simulation

Copilot uses AI. Check for mistakes.
Comment on lines +50 to +56
@field_validator("simulation", mode="before")
@classmethod
def forward_and_inverse_drivers_only(cls, value):
run_command = value.options["run_command"]
invalid = ["plate_simulation", "depth_of_investigation"]
if any(k in run_command for k in invalid):
title = value.options["title"]
Copy link

Copilot AI Apr 30, 2026

Choose a reason for hiding this comment

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

The validator assumes simulation.options always contains run_command and title and indexes them directly. If a SimPEGGroup is missing either key (or options is None/not a dict), this will raise a KeyError/AttributeError and produce an unhelpful ValidationError instead of the intended message. Consider using defensive access (e.g., .get) and raising a clear ValueError when required option keys are absent; also consider running this check after parsing so simulation has been resolved to a SimPEGGroup instance.

Suggested change
@field_validator("simulation", mode="before")
@classmethod
def forward_and_inverse_drivers_only(cls, value):
run_command = value.options["run_command"]
invalid = ["plate_simulation", "depth_of_investigation"]
if any(k in run_command for k in invalid):
title = value.options["title"]
@field_validator("simulation", mode="after")
@classmethod
def forward_and_inverse_drivers_only(cls, value):
options = getattr(value, "options", None)
if not isinstance(options, dict):
raise ValueError(
"Simulation options must be provided as a dictionary containing "
"'run_command' and 'title'."
)
run_command = options.get("run_command")
if not isinstance(run_command, str) or not run_command:
raise ValueError(
"Simulation options must include a non-empty 'run_command'."
)
title = options.get("title")
if not isinstance(title, str) or not title:
raise ValueError("Simulation options must include a non-empty 'title'.")
invalid = ["plate_simulation", "depth_of_investigation"]
if any(k in run_command for k in invalid):

Copilot uses AI. Check for mistakes.
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 30, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.20%. Comparing base (f8dca34) to head (8abcd94).

Additional details and impacted files
@@                Coverage Diff                 @@
##           release/GA_4.8     #395      +/-   ##
==================================================
+ Coverage           90.17%   90.20%   +0.03%     
==================================================
  Files                 129      129              
  Lines                6474     6484      +10     
  Branches              817      818       +1     
==================================================
+ Hits                 5838     5849      +11     
  Misses                422      422              
+ Partials              214      213       -1     
Files with missing lines Coverage Δ
simpeg_drivers/utils/tile_estimate.py 87.59% <100.00%> (+0.97%) ⬆️

... and 1 file with indirect coverage changes

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

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.

2 participants