|
1 | 1 | from math import pi |
2 | 2 | from tempfile import TemporaryDirectory |
3 | 3 | from pathlib import Path |
| 4 | +import itertools |
| 5 | +import random |
4 | 6 |
|
5 | 7 | import h5py |
6 | 8 | import numpy as np |
@@ -642,6 +644,7 @@ def test_mesh_get_homogenized_materials(): |
642 | 644 |
|
643 | 645 | @pytest.fixture |
644 | 646 | def sphere_model(): |
| 647 | + openmc.reset_auto_ids() |
645 | 648 | # Model with three materials separated by planes x=0 and z=0 |
646 | 649 | mats = [] |
647 | 650 | for i in range(3): |
@@ -768,6 +771,49 @@ def test_mesh_material_volumes_serialize_with_bboxes(): |
768 | 771 | np.testing.assert_array_equal(second.upper_right, (5.0, 6.0, 7.0)) |
769 | 772 |
|
770 | 773 |
|
| 774 | +def test_mesh_material_volumes_serialize_with_bboxes(): |
| 775 | + materials = np.array([ |
| 776 | + [1, -1, -2], |
| 777 | + [-1, -2, -2], |
| 778 | + [2, 1, -2], |
| 779 | + [2, -2, -2] |
| 780 | + ]) |
| 781 | + volumes = np.array([ |
| 782 | + [0.5, 0.5, 0.0], |
| 783 | + [1.0, 0.0, 0.0], |
| 784 | + [0.5, 0.5, 0.0], |
| 785 | + [1.0, 0.0, 0.0] |
| 786 | + ]) |
| 787 | + |
| 788 | + # (xmin, ymin, zmin, xmax, ymax, zmax) |
| 789 | + bboxes = np.empty((4, 3, 6)) |
| 790 | + bboxes[..., 0:3] = np.inf |
| 791 | + bboxes[..., 3:6] = -np.inf |
| 792 | + bboxes[0, 0] = [-1.0, -2.0, -3.0, 1.0, 2.0, 3.0] # material 1 |
| 793 | + bboxes[0, 1] = [-5.0, -6.0, -7.0, 5.0, 6.0, 7.0] # void |
| 794 | + bboxes[1, 0] = [0.0, 0.0, 0.0, 10.0, 1.0, 2.0] # void |
| 795 | + bboxes[2, 0] = [-1.0, -1.0, -1.0, 0.0, 0.0, 0.0] # material 2 |
| 796 | + bboxes[2, 1] = [0.0, 0.0, 0.0, 1.0, 1.0, 1.0] # material 1 |
| 797 | + bboxes[3, 0] = [-2.0, -2.0, -2.0, 2.0, 2.0, 2.0] # material 2 |
| 798 | + |
| 799 | + mmv = openmc.MeshMaterialVolumes(materials, volumes, bboxes) |
| 800 | + with TemporaryDirectory() as tmpdir: |
| 801 | + path = f'{tmpdir}/volumes_bboxes.npz' |
| 802 | + mmv.save(path) |
| 803 | + loaded = openmc.MeshMaterialVolumes.from_npz(path) |
| 804 | + |
| 805 | + assert loaded.has_bounding_boxes |
| 806 | + first = loaded.by_element(0, include_bboxes=True)[0][2] |
| 807 | + assert isinstance(first, openmc.BoundingBox) |
| 808 | + np.testing.assert_array_equal(first.lower_left, (-1.0, -2.0, -3.0)) |
| 809 | + np.testing.assert_array_equal(first.upper_right, (1.0, 2.0, 3.0)) |
| 810 | + |
| 811 | + second = loaded.by_element(0, include_bboxes=True)[1][2] |
| 812 | + assert isinstance(second, openmc.BoundingBox) |
| 813 | + np.testing.assert_array_equal(second.lower_left, (-5.0, -6.0, -7.0)) |
| 814 | + np.testing.assert_array_equal(second.upper_right, (5.0, 6.0, 7.0)) |
| 815 | + |
| 816 | + |
771 | 817 | def test_mesh_material_volumes_boundary_conditions(sphere_model): |
772 | 818 | """Test the material volumes method using a regular mesh |
773 | 819 | that overlaps with a vacuum boundary condition.""" |
@@ -841,6 +887,53 @@ def test_mesh_material_volumes_bounding_boxes(): |
841 | 887 | np.testing.assert_allclose(bbox.lower_left, cell_bbox.lower_left, atol=tol) |
842 | 888 | np.testing.assert_allclose(bbox.upper_right, cell_bbox.upper_right, atol=tol) |
843 | 889 |
|
| 890 | +def test_mesh_material_volumes_bounding_boxes(): |
| 891 | + # Create a model with 8 spherical cells at known locations with random radii |
| 892 | + box = openmc.model.RectangularParallelepiped( |
| 893 | + -10, 10, -10, 10, -10, 10, boundary_type='vacuum') |
| 894 | + |
| 895 | + mat = openmc.Material() |
| 896 | + mat.add_nuclide('H1', 1.0) |
| 897 | + |
| 898 | + sph_cells = [] |
| 899 | + for x, y, z in itertools.product((-5., 5.), repeat=3): |
| 900 | + mat_i = mat.clone() |
| 901 | + sph = openmc.Sphere(x, y, z, r=random.uniform(0.5, 1.5)) |
| 902 | + sph_cells.append(openmc.Cell(region=-sph, fill=mat_i)) |
| 903 | + background = openmc.Cell(region=-box & openmc.Intersection([~c.region for c in sph_cells])) |
| 904 | + |
| 905 | + model = openmc.Model() |
| 906 | + model.geometry = openmc.Geometry(sph_cells + [background]) |
| 907 | + model.settings.particles = 1000 |
| 908 | + model.settings.batches = 10 |
| 909 | + |
| 910 | + # Create a one-element mesh that encompasses the entire geometry |
| 911 | + mesh = openmc.RegularMesh() |
| 912 | + mesh.lower_left = (-10., -10., -10.) |
| 913 | + mesh.upper_right = (10., 10., 10.) |
| 914 | + mesh.dimension = (1, 1, 1) |
| 915 | + |
| 916 | + # Run material volume calculation with bounding boxes |
| 917 | + n_samples = (400, 400, 400) |
| 918 | + mmv = mesh.material_volumes(model, n_samples, max_materials=10, bounding_boxes=True) |
| 919 | + assert mmv.has_bounding_boxes |
| 920 | + |
| 921 | + # Create a mapping of material ID to bounding box |
| 922 | + bbox_by_mat = { |
| 923 | + mat_id: bbox |
| 924 | + for mat_id, vol, bbox in mmv.by_element(0, include_bboxes=True) |
| 925 | + if mat_id is not None and vol > 0.0 |
| 926 | + } |
| 927 | + |
| 928 | + # Match the mesh ray spacing used for the bounding box estimator. |
| 929 | + tol = 0.5 * mesh.bounding_box.width[0] / n_samples[0] |
| 930 | + for cell in sph_cells: |
| 931 | + bbox = bbox_by_mat[cell.fill.id] |
| 932 | + cell_bbox = cell.bounding_box |
| 933 | + np.testing.assert_allclose(bbox.lower_left, cell_bbox.lower_left, atol=tol) |
| 934 | + np.testing.assert_allclose(bbox.upper_right, cell_bbox.upper_right, atol=tol) |
| 935 | + |
| 936 | + |
844 | 937 | def test_raytrace_mesh_infinite_loop(run_in_tmpdir): |
845 | 938 | # Create a model with one large spherical cell |
846 | 939 | sphere = openmc.Sphere(r=100, boundary_type='vacuum') |
@@ -953,10 +1046,6 @@ def test_filter_time_mesh(run_in_tmpdir): |
953 | 1046 | ) |
954 | 1047 |
|
955 | 1048 |
|
956 | | -# ============================================================================= |
957 | | -# VTKHDF Format Tests for StructuredMeshes |
958 | | -# ============================================================================= |
959 | | - |
960 | 1049 | def test_regular_mesh_get_indices_at_coords(): |
961 | 1050 | """Test get_indices_at_coords method for RegularMesh""" |
962 | 1051 | # Create a 10x10x10 mesh from (0,0,0) to (1,1,1) |
|
0 commit comments