mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-27 05:35:49 -04:00
Replace grep-style test with proper pytest that runs OpenMC simulation
Co-authored-by: jtramm <1009059+jtramm@users.noreply.github.com>
This commit is contained in:
parent
ab0cfbad52
commit
e90e6ff020
1 changed files with 131 additions and 127 deletions
|
|
@ -1,155 +1,159 @@
|
|||
"""
|
||||
Test module for verifying the fix for multiple point sources in same subdivided
|
||||
source region in the Random Ray Solver.
|
||||
Test for the Random Ray Solver multiple point sources error detection fix.
|
||||
|
||||
This test addresses the issue where multiple point sources placed in the same
|
||||
subdivided source region would silently overwrite each other. The fix adds
|
||||
proper error detection to prevent this condition.
|
||||
|
||||
The tests verify:
|
||||
1. Multiple point sources in the same subdivided region trigger an error
|
||||
2. Multiple point sources in different subdivided regions work correctly
|
||||
3. Multiple point sources work correctly when mesh subdivision is disabled
|
||||
|
||||
Note: These tests require a fully built OpenMC C++ executable to run the
|
||||
actual simulations. In CI environments where the executable is available,
|
||||
the full error detection will be tested.
|
||||
This test verifies the fix for issue #3470 where multiple point sources
|
||||
placed in the same subdivided source region would silently overwrite each other.
|
||||
The fix adds proper error detection to prevent this condition.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import openmc
|
||||
from openmc.examples import random_ray_three_region_cube
|
||||
|
||||
|
||||
def test_error_detection_setup():
|
||||
"""Test that demonstrates the setup for detecting multiple point sources error.
|
||||
def test_multiple_point_sources_same_location_error():
|
||||
"""Test that multiple point sources at the same location trigger an error
|
||||
when mesh subdivision is enabled."""
|
||||
|
||||
This test documents the scenario that should trigger the error:
|
||||
- Random ray solver with mesh subdivision enabled
|
||||
- Multiple point sources at the same location (same mesh bin)
|
||||
- Should raise RuntimeError with specific message
|
||||
# Create a basic random ray model
|
||||
model = random_ray_three_region_cube()
|
||||
|
||||
The actual error detection happens in the C++ code in:
|
||||
src/random_ray/flat_source_domain.cpp:convert_external_sources()
|
||||
"""
|
||||
# Enable mesh subdivision - this is required to trigger the error
|
||||
mesh = openmc.RegularMesh()
|
||||
mesh.dimension = (4, 4, 4)
|
||||
mesh.lower_left = (0.0, 0.0, 0.0)
|
||||
mesh.upper_right = (30.0, 30.0, 30.0)
|
||||
|
||||
# Expected error message from C++ code
|
||||
expected_error_msg = (
|
||||
"Multiple point sources detected in the same subdivided source "
|
||||
"region.This is not currently supported in the random ray solver."
|
||||
# Get the source universe to apply mesh subdivision
|
||||
source_universe = model.geometry.get_universes_by_name('source universe')[0]
|
||||
model.settings.random_ray['source_region_meshes'] = [
|
||||
(mesh, [source_universe])
|
||||
]
|
||||
|
||||
# Create multiple point sources at the exact same location
|
||||
# This should trigger the error when mesh subdivision is enabled
|
||||
point_location = openmc.stats.Point(xyz=(5.0, 5.0, 5.0))
|
||||
energy_dist = openmc.stats.Discrete([10.0], [1.0])
|
||||
|
||||
source1 = openmc.IndependentSource(
|
||||
space=point_location,
|
||||
energy=energy_dist,
|
||||
strength=1.0
|
||||
)
|
||||
source2 = openmc.IndependentSource(
|
||||
space=point_location, # Same location
|
||||
energy=energy_dist,
|
||||
strength=1.0
|
||||
)
|
||||
|
||||
# Document the test scenario
|
||||
test_scenario = {
|
||||
'solver': 'random_ray',
|
||||
'mesh_subdivision': True,
|
||||
'point_sources': [
|
||||
{'location': (5.0, 5.0, 5.0), 'strength': 1.0},
|
||||
{'location': (5.0, 5.0, 5.0), 'strength': 1.0} # Same location
|
||||
],
|
||||
'expected_result': 'RuntimeError',
|
||||
'expected_message': expected_error_msg
|
||||
}
|
||||
# Set the multiple point sources
|
||||
model.settings.source = [source1, source2]
|
||||
|
||||
# Verify the test scenario is well-defined
|
||||
assert test_scenario['solver'] == 'random_ray'
|
||||
assert test_scenario['mesh_subdivision'] is True
|
||||
assert len(test_scenario['point_sources']) == 2
|
||||
assert (test_scenario['point_sources'][0]['location'] ==
|
||||
test_scenario['point_sources'][1]['location'])
|
||||
assert test_scenario['expected_result'] == 'RuntimeError'
|
||||
assert 'Multiple point sources detected' in test_scenario['expected_message']
|
||||
# Very short simulation to just trigger initialization
|
||||
model.settings.batches = 1
|
||||
model.settings.inactive = 0
|
||||
model.settings.particles = 10
|
||||
|
||||
# The error should be triggered during initialization/conversion of external sources
|
||||
with pytest.raises(RuntimeError, match=r"Multiple point sources detected.*same subdivided.*source region"):
|
||||
model.run()
|
||||
|
||||
|
||||
def test_valid_scenarios_setup():
|
||||
"""Test scenarios that should NOT trigger the error."""
|
||||
def test_multiple_point_sources_different_locations_success():
|
||||
"""Test that multiple point sources at different locations work correctly
|
||||
with mesh subdivision enabled."""
|
||||
|
||||
valid_scenarios = [
|
||||
{
|
||||
'description': 'Different locations with mesh subdivision',
|
||||
'solver': 'random_ray',
|
||||
'mesh_subdivision': True,
|
||||
'point_sources': [
|
||||
{'location': (2.0, 2.0, 2.0), 'strength': 1.0},
|
||||
{'location': (8.0, 8.0, 8.0), 'strength': 1.0} # Different location
|
||||
],
|
||||
'expected_result': 'Success'
|
||||
},
|
||||
{
|
||||
'description': 'Same location without mesh subdivision',
|
||||
'solver': 'random_ray',
|
||||
'mesh_subdivision': False,
|
||||
'point_sources': [
|
||||
{'location': (5.0, 5.0, 5.0), 'strength': 1.0},
|
||||
{'location': (5.0, 5.0, 5.0), 'strength': 1.0} # Same location OK
|
||||
],
|
||||
'expected_result': 'Success'
|
||||
}
|
||||
# Create a basic random ray model
|
||||
model = random_ray_three_region_cube()
|
||||
|
||||
# Enable mesh subdivision
|
||||
mesh = openmc.RegularMesh()
|
||||
mesh.dimension = (4, 4, 4)
|
||||
mesh.lower_left = (0.0, 0.0, 0.0)
|
||||
mesh.upper_right = (30.0, 30.0, 30.0)
|
||||
|
||||
# Get the source universe to apply mesh subdivision
|
||||
source_universe = model.geometry.get_universes_by_name('source universe')[0]
|
||||
model.settings.random_ray['source_region_meshes'] = [
|
||||
(mesh, [source_universe])
|
||||
]
|
||||
|
||||
# Verify all valid scenarios are properly defined
|
||||
for scenario in valid_scenarios:
|
||||
assert scenario['solver'] == 'random_ray'
|
||||
assert len(scenario['point_sources']) == 2
|
||||
assert scenario['expected_result'] == 'Success'
|
||||
# Create multiple point sources at different locations
|
||||
# This should work fine
|
||||
point_location1 = openmc.stats.Point(xyz=(2.0, 2.0, 2.0))
|
||||
point_location2 = openmc.stats.Point(xyz=(8.0, 8.0, 8.0))
|
||||
energy_dist = openmc.stats.Discrete([10.0], [1.0])
|
||||
|
||||
# Verify the scenarios are actually different
|
||||
assert valid_scenarios[0]['mesh_subdivision'] != valid_scenarios[1]['mesh_subdivision']
|
||||
source1 = openmc.IndependentSource(
|
||||
space=point_location1,
|
||||
energy=energy_dist,
|
||||
strength=1.0
|
||||
)
|
||||
source2 = openmc.IndependentSource(
|
||||
space=point_location2, # Different location
|
||||
energy=energy_dist,
|
||||
strength=1.0
|
||||
)
|
||||
|
||||
# Set the multiple point sources
|
||||
model.settings.source = [source1, source2]
|
||||
|
||||
# Very short simulation to just verify it initializes correctly
|
||||
model.settings.batches = 1
|
||||
model.settings.inactive = 0
|
||||
model.settings.particles = 10
|
||||
|
||||
# This should not raise an error
|
||||
try:
|
||||
model.run()
|
||||
except RuntimeError as e:
|
||||
# If we get a RuntimeError, it should NOT be about multiple point sources
|
||||
assert "Multiple point sources detected" not in str(e)
|
||||
# Re-raise any other errors (could be due to test environment)
|
||||
raise
|
||||
|
||||
|
||||
def test_fix_implementation_verification():
|
||||
"""Verify the fix implementation details."""
|
||||
def test_multiple_point_sources_no_mesh_subdivision_success():
|
||||
"""Test that multiple point sources at the same location work correctly
|
||||
when mesh subdivision is disabled."""
|
||||
|
||||
# The fix should be in this file
|
||||
fix_file = 'src/random_ray/flat_source_domain.cpp'
|
||||
# Create a basic random ray model without mesh subdivision
|
||||
model = random_ray_three_region_cube()
|
||||
|
||||
# The fix should be in this method
|
||||
fix_method = 'convert_external_sources'
|
||||
# Explicitly ensure no mesh subdivision is configured
|
||||
# (default behavior, but being explicit for clarity)
|
||||
if 'source_region_meshes' in model.settings.random_ray:
|
||||
del model.settings.random_ray['source_region_meshes']
|
||||
|
||||
# The fix should use this logic pattern
|
||||
expected_logic = [
|
||||
'SourceRegionKey key {sr, mesh_bin}',
|
||||
'auto it = point_source_map_.find(key)',
|
||||
'if (it != point_source_map_.end())',
|
||||
'fatal_error("Multiple point sources detected...")',
|
||||
'point_source_map_[key] = es'
|
||||
]
|
||||
# Create multiple point sources at the same location
|
||||
# This should work fine without mesh subdivision
|
||||
point_location = openmc.stats.Point(xyz=(5.0, 5.0, 5.0))
|
||||
energy_dist = openmc.stats.Discrete([10.0], [1.0])
|
||||
|
||||
fix_info = {
|
||||
'file': fix_file,
|
||||
'method': fix_method,
|
||||
'logic_pattern': expected_logic,
|
||||
'lines_added': 5, # Minimal change
|
||||
'approach': 'Error detection instead of feature support'
|
||||
}
|
||||
source1 = openmc.IndependentSource(
|
||||
space=point_location,
|
||||
energy=energy_dist,
|
||||
strength=1.0
|
||||
)
|
||||
source2 = openmc.IndependentSource(
|
||||
space=point_location, # Same location, but no mesh subdivision
|
||||
energy=energy_dist,
|
||||
strength=1.0
|
||||
)
|
||||
|
||||
# Verify fix metadata
|
||||
assert fix_info['file'].endswith('flat_source_domain.cpp')
|
||||
assert fix_info['method'] == 'convert_external_sources'
|
||||
assert len(fix_info['logic_pattern']) == 5
|
||||
assert fix_info['lines_added'] == 5
|
||||
assert 'Error detection' in fix_info['approach']
|
||||
# Set the multiple point sources
|
||||
model.settings.source = [source1, source2]
|
||||
|
||||
print(f"Fix implemented in: {fix_info['file']}")
|
||||
print(f"Method: {fix_info['method']}")
|
||||
print(f"Lines added: {fix_info['lines_added']}")
|
||||
print(f"Approach: {fix_info['approach']}")
|
||||
|
||||
|
||||
# Integration test placeholder for when OpenMC is fully available
|
||||
def test_multiple_point_sources_error_detection_integration():
|
||||
"""Integration test for the actual error detection.
|
||||
# Very short simulation to just verify it initializes correctly
|
||||
model.settings.batches = 1
|
||||
model.settings.inactive = 0
|
||||
model.settings.particles = 10
|
||||
|
||||
This test should be run in environments where OpenMC C++ executable
|
||||
is built and available. It will create the actual error scenario and
|
||||
verify the RuntimeError is raised.
|
||||
|
||||
Currently marked as expected to be skipped in environments without
|
||||
the full OpenMC installation.
|
||||
"""
|
||||
pytest.skip("Requires full OpenMC C++ build - integration test placeholder")
|
||||
|
||||
# When OpenMC is available, this test would:
|
||||
# 1. Create a model with random ray solver
|
||||
# 2. Enable mesh subdivision
|
||||
# 3. Add multiple point sources at same location
|
||||
# 4. Call model.run() and expect RuntimeError
|
||||
# 5. Verify error message contains expected text
|
||||
# This should not raise an error about multiple point sources
|
||||
try:
|
||||
model.run()
|
||||
except RuntimeError as e:
|
||||
# If we get a RuntimeError, it should NOT be about multiple point sources
|
||||
assert "Multiple point sources detected" not in str(e)
|
||||
# Re-raise any other errors (could be due to test environment)
|
||||
raise
|
||||
Loading…
Add table
Add a link
Reference in a new issue