From e90e6ff02086e0311ff2c5ced0614ab412c72ef7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 10 Jul 2025 22:41:28 +0000 Subject: [PATCH] Replace grep-style test with proper pytest that runs OpenMC simulation Co-authored-by: jtramm <1009059+jtramm@users.noreply.github.com> --- .../test_random_ray_multiple_point_sources.py | 258 +++++++++--------- 1 file changed, 131 insertions(+), 127 deletions(-) diff --git a/tests/unit_tests/test_random_ray_multiple_point_sources.py b/tests/unit_tests/test_random_ray_multiple_point_sources.py index 8d6b92cf7..eea55a7a5 100644 --- a/tests/unit_tests/test_random_ray_multiple_point_sources.py +++ b/tests/unit_tests/test_random_ray_multiple_point_sources.py @@ -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 \ No newline at end of file + # 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 \ No newline at end of file