Exemple #1
0
 def test_invalid_values(self):
     voxel_coords = np.array([[2, 0], [2, 1], [-2, 1]])
     with self.assertRaises(ValueError, msg="Calling with negative R didn't error"):
         AxisymmetricVoxel(voxel_coords)
     voxel_coords = np.array([[2, 0], [3, 1]])
     with self.assertRaises(TypeError, msg="Calling with 2 vertices didn't error"):
         AxisymmetricVoxel(voxel_coords)
     voxel_coords = np.asarray(RECTANGULAR_VOXEL_COORDS[0])
     with self.assertRaises(ValueError, msg="Calling with bogus primitive type didn't error"):
         AxisymmetricVoxel(voxel_coords, primitive_type="nonexistant")
Exemple #2
0
 def test_constant_emissivity(self):
     def emiss_function(r, phi, z):
         return 5
     # Emissivity in the voxel should be the constant value of emiss_function
     for polygon in TRIANGLE_VOXEL_COORDS + RECTANGULAR_VOXEL_COORDS + ARBITRARY_VOXEL_COORDS:
         coords = np.asarray(polygon)
         voxel = AxisymmetricVoxel(coords)
         emiss = voxel.emissivity_from_function(emiss_function, 1000)
         expected_emiss = emiss_function(0, 0, 0)
         self.assertEqual(emiss, expected_emiss)
Exemple #3
0
 def test_invalid_types(self):
     voxel_coords = {'v1': (2, 0), 'v2': (2, 1), 'v3': (3, 1)}
     with self.assertRaises(TypeError, msg="Calling with dict with string keys didn't error"):
         AxisymmetricVoxel(voxel_coords)
     voxel_coords = {1: (2, 0), 2: (2, 1), 3: (3, 1)}
     with self.assertRaises(TypeError, msg="Calling with dict with int keys didn't error"):
         AxisymmetricVoxel(voxel_coords)
     voxel_coords = [Point3D(2, 0, 0), Point3D(2, 0, 1), Point3D(3, 0, 1)]
     with self.assertRaises(TypeError, msg="Calling with list of Point3D didn't error"):
         AxisymmetricVoxel(voxel_coords)
     voxel_coords = np.asarray([[2, 0, 0], [2, 0, 1], [3, 0, 1]])
     with self.assertRaises(TypeError, msg="Calling with Nx3 array didn't error"):
         AxisymmetricVoxel(voxel_coords)
Exemple #4
0
    def test_numpy_array(self):
        voxel_coords = np.asarray(RECTANGULAR_VOXEL_COORDS[0])
        voxel = AxisymmetricVoxel(voxel_coords)

        for coord, vertex in zip(voxel_coords, voxel.vertices):
            self.assertEqual([coord[0], coord[1]], [vertex.x, vertex.y],
                             "Nx2 array coordinate mismatch")
Exemple #5
0
 def test_rectangle_centroid(self):
     for rectangle in RECTANGULAR_VOXEL_COORDS:
         coords = np.asarray(rectangle)
         voxel = AxisymmetricVoxel(coords)
         x0, y0 = coords.mean(axis=0)
         expected_centroid = Point2D(x0, y0)
         self.assertEqual(voxel.cross_section_centroid, expected_centroid)
Exemple #6
0
 def voxel_matches_polygon(self, coordinate_list):
     for voxel_coords in coordinate_list:
         voxel_coords = np.asarray(voxel_coords)
         rmax = voxel_coords[:, 0].max()
         rmin = voxel_coords[:, 0].min()
         zmax = voxel_coords[:, 1].max()
         zmin = voxel_coords[:, 1].min()
         router = 1.5 * rmax
         rinner = 0.5 * rmin
         zupper = 1.5 * zmax if zmax > 0 else 0.5 * zmax
         zlower = 0.5 * zmin if zmin > 0 else 1.5 * zmin
         test_rs = np.linspace(rinner, router, int(100 * (router - rinner)))
         test_zs = np.linspace(zlower, zupper, int(100 * (zupper - zlower)))
         voxel = AxisymmetricVoxel(voxel_coords, primitive_type='csg')
         polygon = Polygon(voxel_coords, closed=True)
         test_verts = list(itertools.product(test_rs, test_zs))
         try:
             inside_poly = polygon.contains_points(test_verts)
         except AttributeError:
             # Polygon.contains_points was only introduced in Matplotlib 2.2.
             # Before that we need to convert to Path
             inside_poly = Path(polygon.get_verts()).contains_points(test_verts)
         inside_csg = [any(child.contains(Point3D(r, 0, z)) for child in voxel.children)
                       for (r, z) in test_verts]
         self.assertSequenceEqual(inside_csg, inside_poly.tolist())
Exemple #7
0
 def test_rectangle_area(self):
     for rectangle in RECTANGULAR_VOXEL_COORDS:
         coords = np.asarray(rectangle)
         voxel = AxisymmetricVoxel(coords)
         dx = coords[:, 0].ptp()
         dy = coords[:, 1].ptp()
         expected_area = dx * dy
         self.assertEqual(voxel.cross_sectional_area, expected_area)
Exemple #8
0
 def test_polygon_area(self):
     for polygon in ARBITRARY_VOXEL_COORDS:
         coords = np.asarray(polygon)
         voxel = AxisymmetricVoxel(coords)
         # Shoelace formula
         x = coords[:, 0]
         y = coords[:, 1]
         expected_area = abs(np.dot(x, np.roll(y, 1)) - np.dot(y, np.roll(x, 1))) / 2
         self.assertEqual(voxel.cross_sectional_area, expected_area)
Exemple #9
0
    def test_variable_emissivity_arbitrary(self):
        # Use the same seed as Raysect's random tests
        seed(1234567890)

        quadpy_precalculated_emiss = {
            ((2, -1), (2, 2), (3, 4), (4, 3), (4, -1)): 3.5833333333333326,
            ((2, -1), (2, 2), (3, 4), (4, 3), (4, 0)): 4.349999999999999,
            ((2, -1), (2, 2), (3, 4), (4, 3), (5, 0)): 4.0482456140350855,
        }

        def emiss_function(r, phi, z):
            return r * z

        for polygon in ARBITRARY_VOXEL_COORDS:
            coords = np.asarray(polygon)
            voxel = AxisymmetricVoxel(coords)
            nsamples = 10000
            emiss = voxel.emissivity_from_function(emiss_function, nsamples)
            if HAVE_QUADPY:
                # Calculate the expected emissivity
                triangle_indices = triangulate2d(coords)
                triangles = coords[triangle_indices]
                expected_emiss = 0
                polygon_area = 0
                for triangle in triangles:
                    # Calculate the area with the shoelace formula
                    x1, y1 = triangle[0]
                    x2, y2 = triangle[1]
                    x3, y3 = triangle[2]
                    triangle_area = 0.5 * abs(x1 * y2 + x2 * y3 + x3 * y1
                                              - x2 * y1 - x3 * y2 - x1 * y3)
                    # Total emissivity is the area-weighted emissivity for each triangle
                    expected_emiss += quadpy.triangle.integrate(
                        lambda x: emiss_function(x[0], 0, x[1]), triangle, quadpy.triangle.Strang(6)
                    )
                    polygon_area += triangle_area
                expected_emiss /= polygon_area
            else:
                # Use pre-calculated values from a machine which had quadpy
                expected_emiss = quadpy_precalculated_emiss[tuple(polygon)]
            max_relative_error = 0.0225  # Measured with seed(1234567890)
            self.assertAlmostEqual(emiss, expected_emiss, delta=emiss * max_relative_error)
Exemple #10
0
 def test_triangle_centroid(self):
     for triangle in TRIANGLE_VOXEL_COORDS:
         coords = np.asarray(triangle)
         voxel = AxisymmetricVoxel(coords)
         # The centroid for a triangle is simply the mean position
         # of the vertices
         expected_centroid = Point2D(*coords.mean(axis=0))
         if voxel.cross_sectional_area == 0:
             self.assertRaises(ZeroDivisionError, getattr, voxel, "cross_section_centroid")
         else:
             self.assertEqual(voxel.cross_section_centroid, expected_centroid)
Exemple #11
0
    def test_variable_emissivity_rectangular(self):
        # Use the same seed as Raysect's random tests
        seed(1234567890)

        def emiss_function(r, phi, z):
            return r * z

        # We can calculate the integrated emissivity analytically
        for polygon in RECTANGULAR_VOXEL_COORDS:
            coords = np.asarray(polygon)
            voxel = AxisymmetricVoxel(coords)
            nsamples = 10000
            emiss = voxel.emissivity_from_function(emiss_function, nsamples)
            rmax = coords[:, 0].max()
            rmin = coords[:, 0].min()
            zmax = coords[:, 1].max()
            zmin = coords[:, 1].min()
            area = (rmax - rmin) * (zmax - zmin)
            expected_emiss = (rmax**2 - rmin**2) * (zmax**2 - zmin**2) / 4 / area
            max_relative_error = 0.0221  # Measured with seed(1234567890)
            self.assertAlmostEqual(emiss, expected_emiss, delta=emiss * max_relative_error)
Exemple #12
0
 def test_triangle_area(self):
     for triangle in TRIANGLE_VOXEL_COORDS:
         coords = np.asarray(triangle)
         voxel = AxisymmetricVoxel(coords)
         # Calculate the area with the shoelace formula
         x1, y1 = coords[0]
         x2, y2 = coords[1]
         x3, y3 = coords[2]
         expected_area = 0.5 * abs(x1 * y2 + x2 * y3 + x3 * y1
                                   - x2 * y1 - x3 * y2 - x1 * y3)
         # Different algorithms have some floating point rounding error
         self.assertAlmostEqual(voxel.cross_sectional_area, expected_area)
Exemple #13
0
 def test_polygon_centroid(self):
     for polygon in ARBITRARY_VOXEL_COORDS:
         coords = np.asarray(polygon)
         voxel = AxisymmetricVoxel(coords)
         x = coords[:, 0]
         y = coords[:, 1]
         signed_area = (np.dot(x, np.roll(y, 1)) - np.dot(y, np.roll(x, 1))) / 2
         xroll = np.roll(x, 1)
         yroll = np.roll(y, 1)
         cx = np.sum((x + xroll) * (x * yroll - xroll * y)) / (6 * signed_area)
         cy = np.sum((y + yroll) * (x * yroll - xroll * y)) / (6 * signed_area)
         expected_centroid = Point2D(cx, cy)
         self.assertEqual(voxel.cross_section_centroid, expected_centroid)
Exemple #14
0
 def voxel_matches_polygon(self, coordinate_list):
     for voxel_coords in coordinate_list:
         voxel_coords = np.asarray(voxel_coords)
         rmax = voxel_coords[:, 0].max()
         rmin = voxel_coords[:, 0].min()
         zmax = voxel_coords[:, 1].max()
         zmin = voxel_coords[:, 1].min()
         router = 1.5 * rmax
         rinner = 0.5 * rmin
         zupper = 1.5 * zmax if zmax > 0 else 0.5 * zmax
         zlower = 0.5 * zmin if zmin > 0 else 1.5 * zmin
         test_rs = np.linspace(rinner, router, int(50 * (router - rinner)))
         test_zs = np.linspace(zlower, zupper, int(50 * (zupper - zlower)))
         # Test for 0 area: not supported by mesh representation
         x, y = voxel_coords.T
         area = 0.5 * np.abs(np.dot(x, np.roll(y, 1)) - np.dot(y, np.roll(x, 1)))
         if area == 0:
             continue
         voxel = AxisymmetricVoxel(voxel_coords, primitive_type='mesh')
         polygon = Polygon(voxel_coords, closed=True).get_path()
         test_verts = list(itertools.product(test_rs, test_zs))
         inside_poly = polygon.contains_points(test_verts)
         inside_voxel = [any(child.contains(Point3D(r, 0, z)) for child in voxel.children)
                         for (r, z) in test_verts]
         # Due to numerical precision, some points may be inside the
         # Matplotlib polygon but not the Mesh. Check in this case that the
         # "failing" points are just very close to the edge of the polygon
         fails = np.nonzero(np.not_equal(inside_voxel, inside_poly))[0]
         for fail in fails:
             if inside_voxel[fail] and not inside_poly[fail]:
                 # Polygon should be made slightly bigger
                 inside_poly[fail] = polygon.contains_point(test_verts[fail], radius=-0.01)
             elif inside_poly[fail] and not inside_voxel[fail]:
                 # Polygon should be made slightly smaller
                 inside_poly[fail] = polygon.contains_point(test_verts[fail], radius=0.01)
         self.assertSequenceEqual(inside_voxel, inside_poly.tolist(),
                                  "Failed for vertices {}".format(voxel_coords))
Exemple #15
0
 def test_list_of_point2d(self):
     voxel_coords = [Point2D(*v) for v in RECTANGULAR_VOXEL_COORDS[0]]
     voxel = AxisymmetricVoxel(voxel_coords)
     for coord, vertex in zip(voxel_coords, voxel.vertices):
         self.assertEqual([coord[0], coord[1]], [vertex.x, vertex.y],
                          "Nx2 array coordinate mismatch")
Exemple #16
0
    def test_variable_emissivity_triangular(self):
        # Use the same seed as Raysect's random tests
        seed(1234567890)

        quadpy_precalculated_emiss = {
            ((4, 3), (3, 2), (2, -1)): 4.333333333333331,
            ((4, 3), (3, -1), (2, -1)): 1.333333333333333,
            ((4, 3), (3, 3), (2, -1)): 5.333333333333333,
            ((4, 3), (3, -1), (2, 2)): 4.083333333333334,
            ((4, 3), (3, 2), (2, 2)): 7.083333333333333,
            ((4, 3), (3, -1), (2, 3)): 5.000000000000001,
            ((4, 2), (3, -1), (2, 3)): 3.916666666666668,
            ((4, -1), (3, -1), (2, 3)): 0.6666666666666656,
            ((4, 3), (3, -1), (2, 3)): 5.000000000000001,
            ((4, 2), (3, 3), (2, -1)): 4.250000000000001,
            ((4, -1), (3, 3), (2, -1)): 0.9999999999999998,
            ((4, 3), (3, 3), (2, -1)): 5.333333333333333,
            ((4, -1), (3, 3), (2, 2)): 3.75,
            ((4, -1), (3, 3), (2, -1)): 0.9999999999999998,
            ((4, -1), (3, 3), (2, 3)): 4.666666666666663,
            ((4, -1), (3, 2), (2, 3)): 3.6666666666666674,
            ((4, -1), (3, -1), (2, 3)): 0.6666666666666656,
            ((4, -1), (3, 3), (2, 3)): 4.666666666666663,
            ((4, 3), (4, 2), (2, -1)): 4.833333333333337,
            ((4, 3), (4, -1), (2, -1)): 1.3333333333333337,
            ((4, 3), (4, -1), (2, 2)): 4.333333333333332,
            ((4, 3), (4, -1), (2, -1)): 1.3333333333333337,
            ((4, 3), (4, -1), (2, 3)): 5.333333333333333,
            ((4, 2), (4, -1), (2, 3)): 4.166666666666666,
            ((4, 3), (4, -1), (2, 3)): 5.333333333333333,
            ((4, 2), (4, 3), (2, -1)): 4.833333333333332,
            ((4, -1), (4, 3), (2, -1)): 1.3333333333333337,
            ((4, -1), (4, 3), (2, 2)): 4.333333333333331,
            ((4, -1), (4, 3), (2, -1)): 1.3333333333333337,
            ((4, -1), (4, 3), (2, 3)): 5.333333333333331,
            ((4, -1), (4, 2), (2, 3)): 4.166666666666665,
            ((4, -1), (4, 3), (2, 3)): 5.333333333333331,
            ((4, 3), (2, 2), (2, -1)): 3.833333333333334,
            ((4, 3), (2, 3), (2, -1)): 4.666666666666666,
            ((4, 3), (2, -1), (2, 2)): 3.833333333333334,
            ((4, 3), (2, -1), (2, 3)): 4.666666666666666,
            ((4, 2), (2, -1), (2, 3)): 3.666666666666666,
            ((4, -1), (2, -1), (2, 3)): 0.6666666666666659,
            ((4, 3), (2, -1), (2, 3)): 4.666666666666666,
            ((4, 2), (2, 3), (2, -1)): 3.666666666666666,
            ((4, -1), (2, 3), (2, -1)): 0.666666666666666,
            ((4, 3), (2, 3), (2, -1)): 4.666666666666666,
            ((4, -1), (2, 3), (2, 2)): 3.16666666666666,
            ((4, -1), (2, 3), (2, -1)): 0.666666666666666,
            ((4, -1), (2, 2), (2, 3)): 3.16666666666666,
            ((4, -1), (2, -1), (2, 3)): 0.6666666666666659,
        }

        def emiss_function(r, phi, z):
            return r * z

        for polygon in TRIANGLE_VOXEL_COORDS:
            coords = np.asarray(polygon)
            voxel = AxisymmetricVoxel(coords)
            nsamples = 10000
            emiss = voxel.emissivity_from_function(emiss_function, nsamples)
            if HAVE_QUADPY:
                # Calculate the expected emissivity
                x1, y1 = coords[0]
                x2, y2 = coords[1]
                x3, y3 = coords[2]
                triangle_area = 0.5 * abs(x1 * y2 + x2 * y3 + x3 * y1
                                          - x2 * y1 - x3 * y2 - x1 * y3)
                # Doesn't make any sense to sample from a <2D cross section area
                if triangle_area == 0:
                    continue
                expected_emiss = quadpy.triangle.integrate(
                    lambda x: emiss_function(x[0], 0, x[1]), coords, quadpy.triangle.Strang(6)
                ) / triangle_area
            else:
                try:
                    expected_emiss = quadpy_precalculated_emiss[tuple(polygon)]
                except KeyError:  # For triangles with zero area
                    continue
            max_relative_error = 0.0723  # Measured with seed(1234567890)
            self.assertAlmostEqual(emiss, expected_emiss, delta=emiss * max_relative_error)