|
7 | 7 | from scipy.stats import chi2 |
8 | 8 | import pytest |
9 | 9 | import openmc |
| 10 | +import random |
| 11 | +import itertools |
10 | 12 | import openmc.lib |
11 | 13 | from openmc.utility_funcs import change_directory |
12 | 14 | from uncertainties.unumpy import uarray, nominal_values, std_devs |
@@ -723,6 +725,48 @@ def test_mesh_material_volumes_serialize(): |
723 | 725 | assert new_volumes.by_element(2) == [(2, 0.5), (1, 0.5)] |
724 | 726 | assert new_volumes.by_element(3) == [(2, 1.0)] |
725 | 727 |
|
| 728 | +def test_mesh_material_volumes_serialize_with_bboxes(): |
| 729 | + materials = np.array([ |
| 730 | + [1, -1, -2], |
| 731 | + [-1, -2, -2], |
| 732 | + [2, 1, -2], |
| 733 | + [2, -2, -2] |
| 734 | + ]) |
| 735 | + volumes = np.array([ |
| 736 | + [0.5, 0.5, 0.0], |
| 737 | + [1.0, 0.0, 0.0], |
| 738 | + [0.5, 0.5, 0.0], |
| 739 | + [1.0, 0.0, 0.0] |
| 740 | + ]) |
| 741 | + |
| 742 | + # (xmin, ymin, zmin, xmax, ymax, zmax) |
| 743 | + bboxes = np.empty((4, 3, 6)) |
| 744 | + bboxes[..., 0:3] = np.inf |
| 745 | + bboxes[..., 3:6] = -np.inf |
| 746 | + bboxes[0, 0] = [-1.0, -2.0, -3.0, 1.0, 2.0, 3.0] # material 1 |
| 747 | + bboxes[0, 1] = [-5.0, -6.0, -7.0, 5.0, 6.0, 7.0] # void |
| 748 | + bboxes[1, 0] = [0.0, 0.0, 0.0, 10.0, 1.0, 2.0] # void |
| 749 | + bboxes[2, 0] = [-1.0, -1.0, -1.0, 0.0, 0.0, 0.0] # material 2 |
| 750 | + bboxes[2, 1] = [0.0, 0.0, 0.0, 1.0, 1.0, 1.0] # material 1 |
| 751 | + bboxes[3, 0] = [-2.0, -2.0, -2.0, 2.0, 2.0, 2.0] # material 2 |
| 752 | + |
| 753 | + mmv = openmc.MeshMaterialVolumes(materials, volumes, bboxes) |
| 754 | + with TemporaryDirectory() as tmpdir: |
| 755 | + path = f'{tmpdir}/volumes_bboxes.npz' |
| 756 | + mmv.save(path) |
| 757 | + loaded = openmc.MeshMaterialVolumes.from_npz(path) |
| 758 | + |
| 759 | + assert loaded.has_bounding_boxes |
| 760 | + first = loaded.by_element(0, include_bboxes=True)[0][2] |
| 761 | + assert isinstance(first, openmc.BoundingBox) |
| 762 | + np.testing.assert_array_equal(first.lower_left, (-1.0, -2.0, -3.0)) |
| 763 | + np.testing.assert_array_equal(first.upper_right, (1.0, 2.0, 3.0)) |
| 764 | + |
| 765 | + second = loaded.by_element(0, include_bboxes=True)[1][2] |
| 766 | + assert isinstance(second, openmc.BoundingBox) |
| 767 | + np.testing.assert_array_equal(second.lower_left, (-5.0, -6.0, -7.0)) |
| 768 | + np.testing.assert_array_equal(second.upper_right, (5.0, 6.0, 7.0)) |
| 769 | + |
726 | 770 |
|
727 | 771 | def test_mesh_material_volumes_boundary_conditions(sphere_model): |
728 | 772 | """Test the material volumes method using a regular mesh |
@@ -751,6 +795,51 @@ def test_mesh_material_volumes_boundary_conditions(sphere_model): |
751 | 795 | assert evaluated[0] == expected[0] |
752 | 796 | assert evaluated[1] == pytest.approx(expected[1], rel=1e-2) |
753 | 797 |
|
| 798 | +def test_mesh_material_volumes_bounding_boxes(): |
| 799 | + # Create a model with 8 spherical cells at known locations with random radii |
| 800 | + box = openmc.model.RectangularParallelepiped( |
| 801 | + -10, 10, -10, 10, -10, 10, boundary_type='vacuum') |
| 802 | + |
| 803 | + mat = openmc.Material() |
| 804 | + mat.add_nuclide('H1', 1.0) |
| 805 | + |
| 806 | + sph_cells = [] |
| 807 | + for x, y, z in itertools.product((-5., 5.), repeat=3): |
| 808 | + mat_i = mat.clone() |
| 809 | + sph = openmc.Sphere(x, y, z, r=random.uniform(0.5, 1.5)) |
| 810 | + sph_cells.append(openmc.Cell(region=-sph, fill=mat_i)) |
| 811 | + background = openmc.Cell(region=-box & openmc.Intersection([~c.region for c in sph_cells])) |
| 812 | + |
| 813 | + model = openmc.Model() |
| 814 | + model.geometry = openmc.Geometry(sph_cells + [background]) |
| 815 | + model.settings.particles = 1000 |
| 816 | + model.settings.batches = 10 |
| 817 | + |
| 818 | + # Create a one-element mesh that encompasses the entire geometry |
| 819 | + mesh = openmc.RegularMesh() |
| 820 | + mesh.lower_left = (-10., -10., -10.) |
| 821 | + mesh.upper_right = (10., 10., 10.) |
| 822 | + mesh.dimension = (1, 1, 1) |
| 823 | + |
| 824 | + # Run material volume calculation with bounding boxes |
| 825 | + n_samples = (400, 400, 400) |
| 826 | + mmv = mesh.material_volumes(model, n_samples, max_materials=10, bounding_boxes=True) |
| 827 | + assert mmv.has_bounding_boxes |
| 828 | + |
| 829 | + # Create a mapping of material ID to bounding box |
| 830 | + bbox_by_mat = { |
| 831 | + mat_id: bbox |
| 832 | + for mat_id, vol, bbox in mmv.by_element(0, include_bboxes=True) |
| 833 | + if mat_id is not None and vol > 0.0 |
| 834 | + } |
| 835 | + |
| 836 | + # Match the mesh ray spacing used for the bounding box estimator. |
| 837 | + tol = 0.5 * mesh.bounding_box.width[0] / n_samples[0] |
| 838 | + for cell in sph_cells: |
| 839 | + bbox = bbox_by_mat[cell.fill.id] |
| 840 | + cell_bbox = cell.bounding_box |
| 841 | + np.testing.assert_allclose(bbox.lower_left, cell_bbox.lower_left, atol=tol) |
| 842 | + np.testing.assert_allclose(bbox.upper_right, cell_bbox.upper_right, atol=tol) |
754 | 843 |
|
755 | 844 | def test_raytrace_mesh_infinite_loop(run_in_tmpdir): |
756 | 845 | # Create a model with one large spherical cell |
@@ -1217,7 +1306,10 @@ def test_write_ascii_vtk_unchanged(run_in_tmpdir): |
1217 | 1306 |
|
1218 | 1307 | # This should work without requiring vtk module changes |
1219 | 1308 | vtkIOLegacy = pytest.importorskip("vtkmodules.vtkIOLegacy") |
1220 | | - mesh.write_data_to_vtk(datasets={"data": ref_data}, filename=filename) |
| 1309 | + mesh.write_data_to_vtk(datasets={"data": ref_data}, |
| 1310 | + filename=filename, |
| 1311 | + volume_normalization=False |
| 1312 | + ) |
1221 | 1313 |
|
1222 | 1314 | assert Path(filename).exists() |
1223 | 1315 |
|
|
0 commit comments