Esempio n. 1
0
    def _generate_rays(self, template, ray_count):

        origin_vectors = self._sphere_sampler(ray_count)
        directions = self._vector_sampler(ray_count)

        rays = []
        for n in range(ray_count):

            # calculate surface point
            origin = origin_vectors[n].copy()
            origin.length = self._radius
            origin = Point3D(*origin)

            # calculate surface normal
            normal = -origin_vectors[n]

            # transform sampling direction from surface space
            direction = directions[n].transform(
                rotate_basis(normal, normal.orthogonal()))

            # USE WITH HEMISPHERECOSINESAMPLER
            # cosine weighted distribution, projected area weight is
            # implicit in distribution, so set weight appropriately
            rays.append((template.copy(origin, direction), 0.5))

        return rays
Esempio n. 2
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_vertex_points = [Point2D(*v) for v in voxel_coords]
         voxel = AxisymmetricVoxel(voxel_vertex_points,
                                   parent=None,
                                   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())
Esempio n. 3
0
def plot_brdf(light_angle):

    light_position = Point3D(np.sin(np.deg2rad(light_angle)), 0,
                             np.cos(np.deg2rad(light_angle)))
    light_direction = origin.vector_to(light_position).normalise()

    phis = np.linspace(0, 360, 200)
    num_phis = len(phis)
    thetas = np.linspace(0, 90, 100)
    num_thetas = len(thetas)

    values = np.zeros((num_thetas, num_phis))
    for i in range(num_thetas):
        for j in range(num_phis):
            theta = np.deg2rad(thetas[i])
            phi = np.deg2rad(phis[j])
            outgoing = Vector3D(
                np.cos(phi) * np.sin(theta),
                np.sin(phi) * np.sin(theta), np.cos(theta))
            values[i, j] = aluminium.bsdf(light_direction, outgoing, 500.0)

    fig, ax = plt.subplots(subplot_kw=dict(projection='polar'))
    cs = ax.contourf(np.deg2rad(phis), thetas, values, extend="both")
    cs.cmap.set_under('k')
    plt.title("Light angle: {} degrees".format(light_angle))
Esempio n. 4
0
    def _check_barrel_surface(self, lens, azimuths, barrel_z):
        """
        Checks barrel surface of a lens by calculating ray-lens intersection. Hit point position and angle of incidence
        are compared to predicted ones.

        :param lens: Spherical lens object to test plane surface of.
        :param azimuths: Azimuth angles to test lens surface at.
        :param barrel_z:
        """

        lens_radius = lens.diameter / 2

        for z in barrel_z:
            for ta in azimuths:
                # get x-y coordinates of the surface point from azimuth
                x = lens_radius * cos(ta)
                y = lens_radius * sin(ta)

                # get origin by surface point offset and calculate ray direction
                surface_point = Point3D(x, y, z)
                direction = Vector3D(-x, -y, 0)
                origin = Point3D(1.1 * x, 1.1 * y, z)

                # calculate ray-lens intersection
                intersection = lens.hit(CoreRay(origin, direction))
                hit_point = intersection.hit_point.transform(
                    intersection.primitive_to_world)

                # distance of expected surface point and the ray hit point
                distance = hit_point.vector_to(surface_point).length
                self.assertAlmostEqual(
                    distance,
                    0,
                    self.tolerance_distance,
                    msg=
                    "Ray-curved surface hit point and predicted surface point difference"
                    " is larger than tolerance.")

                # angle of incidence on the sphere surface should be perpendicular
                cos_angle_incidence = intersection.normal.dot(
                    intersection.ray.direction.normalise())
                self.assertAlmostEqual(
                    fabs(cos_angle_incidence),
                    1,
                    self.tolerance_angle,
                    msg="Angle of incidence differs from perpendicular.")
Esempio n. 5
0
def generate_annulus_mesh_segments(lower_corner, upper_corner, theta_width,
                                   theta_offset, world):

    material = UnityVolumeEmitter()

    # Set of points in x-z plane
    p1a = Point3D(lower_corner.x, 0,
                  lower_corner.y)  # corresponds to lower corner is x-z plane
    p2a = Point3D(lower_corner.x, 0, upper_corner.y)
    p3a = Point3D(upper_corner.x, 0,
                  upper_corner.y)  # corresponds to upper corner in x-z plane
    p4a = Point3D(upper_corner.x, 0, lower_corner.y)

    # Set of points rotated away from x-z plane
    p1b = p1a.transform(rotate_z(theta_width))
    p2b = p2a.transform(rotate_z(theta_width))
    p3b = p3a.transform(rotate_z(theta_width))
    p4b = p4a.transform(rotate_z(theta_width))

    vertices = [[p1a.x, p1a.y, p1a.z], [p2a.x, p2a.y, p2a.z],
                [p3a.x, p3a.y, p3a.z], [p4a.x, p4a.y, p4a.z],
                [p1b.x, p1b.y, p1b.z], [p2b.x, p2b.y, p2b.z],
                [p3b.x, p3b.y, p3b.z], [p4b.x, p4b.y, p4b.z]]

    triangles = [
        [1, 0, 3],
        [1, 3, 2],  # front face (x-z)
        [7, 4, 5],
        [7, 5, 6],  # rear face (rotated out of x-z plane)
        [5, 1, 2],
        [5, 2, 6],  # top face (x-y plane)
        [3, 0, 4],
        [3, 4, 7],  # bottom face (x-y plane)
        [4, 0, 5],
        [1, 5, 0],  # inner face (y-z plane)
        [2, 3, 7],
        [2, 7, 6]
    ]  # outer face (y-z plane)

    return Mesh(vertices=vertices,
                triangles=triangles,
                smoothing=False,
                transform=rotate_z(theta_offset),
                material=material,
                parent=world)
Esempio n. 6
0
    def test_planoconcave(self):
        """
        Test planoconcave lens for a range of curvatures and center thickness combinations.
        """

        # combinations of lens parameters to test
        diameter = 75
        curvatures = np.array([0.5, 0.75, 1, 1.5, 5]) * diameter
        threshold_ratios = np.array([1, 1.05, 2, 3, 5, 10])

        radius = diameter / 2
        radius2 = radius**2

        for curvature in curvatures:
            for threshold_ratio in threshold_ratios:

                # center thickness calculated from the minimum threshold
                front_thickness = curvature - sqrt(curvature**2 - radius2)
                center_thickness = threshold_ratio * front_thickness

                lens = PlanoConcave(diameter, center_thickness, curvature)

                # calculate coordinates of center of curvature of the lens front surface
                center_front = Point3D(0, 0, center_thickness + curvature)

                # check lens front and back surface by inside and outside envelopes
                azimuths = np.linspace(0,
                                       2 * pi,
                                       self.n_testpoints,
                                       endpoint=False)
                min_altitude = self.pad_constant

                max_altitude = asin(radius / curvature) - self.pad_constant
                altitude = np.linspace(max_altitude,
                                       min_altitude,
                                       self.n_testpoints,
                                       endpoint=True)
                radii = curvature * np.sin(altitude)
                self._check_spherical_surface(curvature, lens, center_front,
                                              True, False, azimuths, radii)

                radii = np.linspace(radius - self.pad_constant,
                                    self.pad_constant, self.n_testpoints)
                self._check_plane_surface(lens, azimuths, radii)

                # check lens barrel surface by inside and outside envelope
                min_z = 0
                max_z = center_thickness + front_thickness
                if max_z - min_z <= 3 * self.pad_constant:
                    barrel_z = np.array(((min_z + max_z) / 2), ndmin=1)
                else:
                    barrel_z = np.linspace(min_z + self.pad_constant,
                                           max_z - self.pad_constant,
                                           self.n_testpoints,
                                           endpoint=True)
                self._check_barrel_surface(lens, azimuths, barrel_z)
Esempio n. 7
0
    def csg_aperture(self, value):

        if value is True:
            width = max(self.dx, self.dy)
            face = Box(Point3D(-width, -width, -self.dz / 2),
                       Point3D(width, width, self.dz / 2))
            slit = Box(lower=Point3D(-self.dx / 2, -self.dy / 2,
                                     -self.dz / 2 - self.dz * 0.1),
                       upper=Point3D(self.dx / 2, self.dy / 2,
                                     self.dz / 2 + self.dz * 0.1))
            self._csg_aperture = Subtract(face,
                                          slit,
                                          parent=self,
                                          material=AbsorbingSurface(),
                                          name=self.name + ' - CSG Aperture')

        else:
            if isinstance(self._csg_aperture, Primitive):
                self._csg_aperture.parent = None
            self._csg_aperture = None
Esempio n. 8
0
    def _mayavi_source_from_raysect_object(self):

        lower = self._raysect_object.lower
        upper = self._raysect_object.upper
        # more negative face in x-z plane
        p1a = lower  # lower corner in x-z plane
        p2a = Point3D(lower.x, lower.y, upper.z)
        p3a = Point3D(upper.x, lower.y, upper.z)  # upper corner in x-z plane
        p4a = Point3D(upper.x, lower.y, lower.z)
        # more positive face in x-z plane
        p1b = Point3D(lower.x, upper.y, lower.z)
        p2b = Point3D(lower.x, upper.y, upper.z)
        p3b = upper
        p4b = Point3D(upper.x, upper.y, lower.z)
        vertices = [[p1a.x, p1a.y, p1a.z], [p2a.x, p2a.y, p2a.z],
                    [p3a.x, p3a.y, p3a.z], [p4a.x, p4a.y, p4a.z],
                    [p1b.x, p1b.y, p1b.z], [p2b.x, p2b.y, p2b.z],
                    [p3b.x, p3b.y, p3b.z], [p4b.x, p4b.y, p4b.z]]
        triangles = [[1, 0, 3], [1, 3, 2],  # front face (x-z)
                    [7, 4, 5], [7, 5, 6],  # rear face (x-z)
                    [5, 1, 2], [5, 2, 6],  # top face (x-y)
                    [3, 0, 4], [3, 4, 7],  # bottom face (x-y)
                    [4, 0, 5], [1, 5, 0],  # left face (y-z)
                    [2, 3, 7], [2, 7, 6]]  # right face (y-z)

        mesh = Mesh(vertices, triangles)
        self._raysect_mesh = subdivide(mesh)
Esempio n. 9
0
def load_dms_output(config, world, plasma, spec, fibgeom):
    from raysect.optical.observer import FibreOptic, PowerPipeline0D, SpectralRadiancePipeline0D
    from raysect.optical import translate, rotate, rotate_basis
    from raysect.core import Vector3D, Point3D

    power_arr = np.zeros(fibgeom.numfibres)
    spectra_arr = np.zeros((spec.pixels, fibgeom.numfibres))

    for i, f in enumerate(power_arr):
        print("Analysing fibre: ", int(i + 1))
        fibgeom.set_fibre(number=int(i + 1))
        start_point = Point3D(fibgeom.origin[0], fibgeom.origin[1],
                              fibgeom.origin[2])
        forward_vector = Vector3D(fibgeom.xhat(), fibgeom.yhat(),
                                  fibgeom.zhat()).normalise()
        up_vector = Vector3D(0, 0, 1.0)
        if config['dms']['power_pipeline']:
            power = PowerPipeline0D()
            fibre = FibreOptic([power],
                               acceptance_angle=1,
                               radius=0.001,
                               spectral_bins=spec.pixels,
                               spectral_rays=1,
                               pixel_samples=5,
                               transform=translate(*start_point) *
                               rotate_basis(forward_vector, up_vector),
                               parent=world)
            fibre.min_wavelength = spec.wlower
            fibre.max_wavelength = spec.wupper
            fibre.observe()
            power_arr[i] = power.value.mean
        else:
            power_arr[i] = None
        if config['dms']['radiance_pipeline']:
            spectra = SpectralRadiancePipeline0D(display_progress=False)
            fibre = FibreOptic([spectra],
                               acceptance_angle=1,
                               radius=0.001,
                               spectral_bins=spec.pixels,
                               spectral_rays=1,
                               pixel_samples=5,
                               transform=translate(*start_point) *
                               rotate_basis(forward_vector, up_vector),
                               parent=world)
            fibre.min_wavelength = spec.wlower
            fibre.max_wavelength = spec.wupper
            fibre.observe()
            spectra_arr[:, i] = spectra.samples.mean
        else:
            spectra_arr[:, i] = None

    return power_arr, spectra_arr
Esempio n. 10
0
def visualise_scenegraph(camera, focal_distance=1, zoom=1):

    if not isinstance(camera, Observer):
        raise TypeError("The vtk visualisation function takes a Raysect Observer object as its argument.")

    world = camera.root

    if not isinstance(world, World):
        raise TypeError("The vtk visualisation function requires the Raysect Observer object to be connected to a valid scene-graph.")

    # Add the actors to the renderer
    renderer = vtk.vtkRenderer()
    renderer.SetBackground(0, 0, 0)
    for child in world.children:
        vtk_element = map_raysect_element_to_vtk(child)
        if isinstance(vtk_element, VTKAssembly):
            renderer.AddActor(vtk_element.assembly)
        else:
            renderer.AddActor(vtk_element.actor)

    axes = vtk.vtkAxesActor()
    renderer.AddActor(axes)

    renWin = vtk.vtkRenderWindow()
    renWin.AddRenderer(renderer)
    renWin.SetSize(512, 512)

    iren = vtk.vtkRenderWindowInteractor()
    iren.SetRenderWindow(renWin)
    iren.SetInteractorStyle(vtk.vtkInteractorStyleTrackballCamera())
    iren.Initialize()

    camera_origin = Point3D(0, 0, 0).transform(camera.transform)
    camera_direction = Vector3D(0, 0, 1).transform(camera.transform)
    up_direction = Vector3D(0, 1, 0).transform(camera.transform)
    focal_point = camera_origin + camera_direction * focal_distance

    vtk_camera = vtk.vtkCamera()
    vtk_camera.SetPosition(camera_origin.x, camera_origin.y, camera_origin.z)
    vtk_camera.SetFocalPoint(focal_point.x, focal_point.y, focal_point.z)
    vtk_camera.SetViewUp(up_direction.x, up_direction.y, up_direction.z)
    vtk_camera.ComputeViewPlaneNormal()
    vtk_camera.SetDistance(focal_distance)
    vtk_camera.Zoom(zoom)
    renderer.SetActiveCamera(vtk_camera)
    renderer.SetBackground(1.0, 0.9688, 0.8594)
    renderer.SetBackground(vtk_colors.GetColor3d("SlateGray"))

    # Start the event loop.
    iren.Start()
Esempio n. 11
0
    def __init__(self,
                 slit_id,
                 centre_point,
                 basis_x,
                 dx,
                 basis_y,
                 dy,
                 dz=0.001,
                 parent=None,
                 csg_aperture=False):

        self._centre_point = centre_point
        self._basis_x = basis_x.normalise()
        self.dx = dx
        self._basis_y = basis_y.normalise()
        self.dy = dy
        self.dz = dz

        # NOTE - target primitive and aperture surface cannot be co-incident otherwise numerics will cause Raysect
        # to be blind to one of the two surfaces.
        slit_normal = basis_x.cross(basis_y)
        transform = translate(centre_point.x, centre_point.y,
                              centre_point.z) * rotate_basis(
                                  slit_normal, basis_y)

        super().__init__(parent=parent, transform=transform, name=slit_id)

        self.target = Box(lower=Point3D(-dx / 2 * 1.01, -dy / 2 * 1.01,
                                        -dz / 2),
                          upper=Point3D(dx / 2 * 1.01, dy / 2 * 1.01, dz / 2),
                          transform=None,
                          material=NullMaterial(),
                          parent=self,
                          name=slit_id + ' - target')

        self._csg_aperture = None
        self.csg_aperture = csg_aperture
Esempio n. 12
0
    def fibre_distance_world(self, world):

        from cherab.tools.observers.intersections import find_wall_intersection
        from raysect.core import Vector3D, Point3D

        start_point = Point3D(self.origin[0] + 1.0 * self.xhat(),
                              self.origin[1] + 1.0 * self.yhat(),
                              self.origin[2] + 1.0 * self.zhat())
        forward_vector = Vector3D(self.xhat(), self.yhat(), self.zhat())

        hit_point, primitive = find_wall_intersection(world,
                                                      start_point,
                                                      forward_vector,
                                                      delta=1E-3)

        return abs((self.origin[0] - hit_point[0]) / self.xhat())
Esempio n. 13
0
def box_to_mesh(box):

    if not isinstance(box, Box):
        raise TypeError("The _box_to_mesh() function takes a Raysect Box primitive as an argument, "
                        "wrong type '{}' given.".format(type(box)))

    lower = box.lower
    upper = box.upper
    # more negative face in x-z plane
    p1a = lower  # lower corner in x-z plane
    p2a = Point3D(lower.x, lower.y, upper.z)
    p3a = Point3D(upper.x, lower.y, upper.z)  # upper corner in x-z plane
    p4a = Point3D(upper.x, lower.y, lower.z)
    # more positive face in x-z plane
    p1b = Point3D(lower.x, upper.y, lower.z)
    p2b = Point3D(lower.x, upper.y, upper.z)
    p3b = upper
    p4b = Point3D(upper.x, upper.y, lower.z)
    vertices = [[p1a.x, p1a.y, p1a.z], [p2a.x, p2a.y, p2a.z],
                [p3a.x, p3a.y, p3a.z], [p4a.x, p4a.y, p4a.z],
                [p1b.x, p1b.y, p1b.z], [p2b.x, p2b.y, p2b.z],
                [p3b.x, p3b.y, p3b.z], [p4b.x, p4b.y, p4b.z]]
    triangles = [[1, 0, 3], [1, 3, 2],  # front face (x-z)
                 [7, 4, 5], [7, 5, 6],  # rear face (x-z)
                 [5, 1, 2], [5, 2, 6],  # top face (x-y)
                 [3, 0, 4], [3, 4, 7],  # bottom face (x-y)
                 [4, 0, 5], [1, 5, 0],  # left face (y-z)
                 [2, 3, 7], [2, 7, 6]]  # right face (y-z)

    mesh = Mesh(vertices, triangles)
    mesh = subdivide(mesh)

    vertices = np.array(mesh.data.vertices)
    triangles = np.array(mesh.data.triangles)

    if box.parent:
        to_world = box.to_root()
    else:
        to_world = box.transform

    # Convert vertices to positions in world coordinates
    for i in range(vertices.shape[0]):
        p = Point3D(vertices[i, 0], vertices[i, 1], vertices[i, 2]).transform(to_world)
        vertices[i, 0] = p.x
        vertices[i, 1] = p.y
        vertices[i, 2] = p.z

    return vertices, triangles
Esempio n. 14
0
def mesh_to_mesh(mesh):

    vertices = mesh.data.vertices.copy()
    triangles = mesh.data.triangles.copy()[:, 0:3]

    if mesh.parent:
        to_world = mesh.to_root()
    else:
        to_world = mesh.transform

    # Convert vertices to positions in world coordinates
    for i in range(vertices.shape[0]):
        p = Point3D(vertices[i, 0], vertices[i, 1], vertices[i, 2]).transform(to_world)
        vertices[i, 0] = p.x
        vertices[i, 1] = p.y
        vertices[i, 2] = p.z

    return vertices, triangles
Esempio n. 15
0
def get_pini_alignment(pulse, oct8_pini):

    import idlbridge as idl

    global _idl_was_setup
    if not _idl_was_setup:
        _setup_idl()
        _idl_was_setup = True

    # Note: array index starts at zero, so actual pini index equals pini number - 1/.
    oct8_pini -= 1

    idl.execute("ret = get_cherab_pinialignment(pulse={})".format(pulse))
    ret = idl.get("ret")

    # Pull out the origin points from the IDL structure, convert to Point3D
    origin = Point3D(ret['origin'][oct8_pini][0] / 1000,
                     ret['origin'][oct8_pini][1] / 1000,
                     ret['origin'][oct8_pini][2] / 1000)

    # Pull out the direction vector from the IDL structure, convert to Vector3D
    direction = Vector3D(ret['vector'][oct8_pini][0],
                         ret['vector'][oct8_pini][1],
                         ret['vector'][oct8_pini][2])

    # TODO - note divergence numbers are different between Carine and Corentin.
    div_u = ret['divu'][oct8_pini] / (2 * PI) * 360
    div_v = ret['divv'][oct8_pini] / (2 * PI) * 360
    divergence = (div_u, div_v)

    # Minimal 1/e width (at the source) of the beam (scalar in meters)
    initial_width = 0.001  # Approximate with 1mm as an effective point source.

    pini_length = PINI_LENGTHS[oct8_pini]

    pini_geometry = (origin, direction, divergence, initial_width, pini_length)

    return pini_geometry
Esempio n. 16
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))
Esempio n. 17
0
def box_to_mesh(box):

    if not isinstance(box, Box):
        raise TypeError(
            "The _box_to_mesh() function takes a Raysect Box primitive as an argument, "
            "wrong type '{}' given.".format(type(box)))

    lower = box.lower
    upper = box.upper
    # more negative face in x-z plane
    p1a = lower  # lower corner in x-z plane
    p2a = Point3D(lower.x, lower.y, upper.z)
    p3a = Point3D(upper.x, lower.y, upper.z)  # upper corner in x-z plane
    p4a = Point3D(upper.x, lower.y, lower.z)
    # more positive face in x-z plane
    p1b = Point3D(lower.x, upper.y, lower.z)
    p2b = Point3D(lower.x, upper.y, upper.z)
    p3b = upper
    p4b = Point3D(upper.x, upper.y, lower.z)
    vertices = [[p1a.x, p1a.y, p1a.z], [p2a.x, p2a.y, p2a.z],
                [p3a.x, p3a.y, p3a.z], [p4a.x, p4a.y, p4a.z],
                [p1b.x, p1b.y, p1b.z], [p2b.x, p2b.y, p2b.z],
                [p3b.x, p3b.y, p3b.z], [p4b.x, p4b.y, p4b.z]]
    triangles = [
        [1, 0, 3],
        [1, 3, 2],  # front face (x-z)
        [7, 4, 5],
        [7, 5, 6],  # rear face (x-z)
        [5, 1, 2],
        [5, 2, 6],  # top face (x-y)
        [3, 0, 4],
        [3, 4, 7],  # bottom face (x-y)
        [4, 0, 5],
        [1, 5, 0],  # left face (y-z)
        [2, 3, 7],
        [2, 7, 6]
    ]  # right face (y-z)
    return Mesh(vertices=vertices,
                triangles=triangles,
                smoothing=False,
                transform=box.transform,
                material=box.material,
                name=box.name)
Esempio n. 18
0
def cone_to_mesh(cone, vertical_divisions=10, cylindrical_divisions=36, base_radial_divisions=5):

    if not isinstance(cone, Cone):
        raise TypeError("The _cone_to_mesh() function takes a Raysect Cone primitive as an argument, "
                        "wrong type '{}' given.".format(type(cone)))

    radius = cone.radius
    height = cone.height

    # first make the cone body

    working_cylindrical_divisions = cylindrical_divisions

    cone_body_vertices = []
    for i in range(vertical_divisions):

        working_radius = radius * (1 - (i / vertical_divisions))
        working_height = height * (i / vertical_divisions)
        theta_step = 360 / working_cylindrical_divisions

        for j in range(working_cylindrical_divisions):
            theta_rad = np.deg2rad(j * theta_step)
            cone_body_vertices.append([working_radius * np.cos(theta_rad), working_radius * np.sin(theta_rad), working_height])

        working_cylindrical_divisions -= int(cylindrical_divisions / (vertical_divisions + 1))
        if working_cylindrical_divisions < 5:
            working_cylindrical_divisions = 5

    # Finally, add centre point
    cone_body_vertices.append([0, 0, height])

    # Triangulate the vertices
    vertices_2d = np.array(cone_body_vertices)[:, 0:2]
    cone_body_triangles = Delaunay(vertices_2d).simplices.tolist()


    # Now make the cone base

    working_cylindrical_divisions = cylindrical_divisions
    cone_base_vertices = []
    for i in range(base_radial_divisions):

        working_radius = radius * (1 - (i / base_radial_divisions))
        theta_step = 360 / working_cylindrical_divisions

        for j in range(working_cylindrical_divisions):
            theta_rad = np.deg2rad(j * theta_step)
            cone_base_vertices.append([working_radius * np.cos(theta_rad), working_radius * np.sin(theta_rad), 0])

        working_cylindrical_divisions -= int(cylindrical_divisions / (base_radial_divisions + 1))
        if working_cylindrical_divisions < 5:
            working_cylindrical_divisions = 5

    # Finally, add centre point
    cone_base_vertices.append([0, 0, 0])

    # Triangulate the vertices
    vertices_2d = np.array(cone_base_vertices)[:, 0:2]
    cone_base_triangles = np.flip(Delaunay(vertices_2d).simplices + len(cone_body_vertices), 1).tolist()

    # Combine the resulting triangles together
    vertices = cone_body_vertices + cone_base_vertices
    triangles = cone_body_triangles + cone_base_triangles

    vertices = np.array(vertices)
    triangles = np.array(triangles)

    if cone.parent:
        to_world = cone.to_root()
    else:
        to_world = cone.transform

    # Convert vertices to positions in world coordinates
    for i in range(vertices.shape[0]):
        p = Point3D(vertices[i, 0], vertices[i, 1], vertices[i, 2]).transform(to_world)
        vertices[i, 0] = p.x
        vertices[i, 1] = p.y
        vertices[i, 2] = p.z

    return vertices, triangles
Esempio n. 19
0
def cylinder_to_mesh(cylinder, vertical_divisions=10, cylindrical_divisions=36, radial_divisions=5):

    if not isinstance(cylinder, Cylinder):
        raise TypeError("The _cylinder_to_mesh() function takes a Raysect Cylinder primitive as an argument, "
                        "wrong type '{}' given.".format(type(cylinder)))

    radius = cylinder.radius
    height = cylinder.height

    # first make the main cylinder
    theta_step = 360 / cylindrical_divisions

    vertices = []
    for i in range(vertical_divisions):
        z = (i / (vertical_divisions - 1)) * height
        for j in range(cylindrical_divisions):
            theta_rad = np.deg2rad(j * theta_step)
            vertices.append([radius * np.cos(theta_rad), radius * np.sin(theta_rad), z])

    triangles = []
    for i in range(vertical_divisions - 1):

        row_start = cylindrical_divisions * i
        next_row_start = cylindrical_divisions * (i + 1)

        for j in range(cylindrical_divisions):

            v1 = row_start + j
            if j != cylindrical_divisions - 1:
                v2 = row_start + j + 1
                v3 = next_row_start + j + 1
            else:
                v2 = row_start
                v3 = next_row_start
            v4 = next_row_start + j

            triangles.append([v1, v2, v3])
            triangles.append([v3, v4, v1])

    def _make_cap_triangles(n_cylindrical_segments, n_radial_segments, radius, z_height):

        working_cylindrical_segments = n_cylindrical_segments

        cap_vertices = []

        for i in range(n_radial_segments):

            working_radius = radius * (1 - (i / n_radial_segments))
            theta_step = 360 / working_cylindrical_segments

            for j in range(working_cylindrical_segments):
                theta_rad = np.deg2rad(j * theta_step)
                cap_vertices.append([working_radius * np.cos(theta_rad), working_radius * np.sin(theta_rad), z_height])

            working_cylindrical_segments -= int(n_cylindrical_segments/(n_radial_segments+1))
            if working_cylindrical_segments < 5:
                working_cylindrical_segments = 5

        # Finally, add centre point
        cap_vertices.append([0, 0, z_height])

        vertices_2d = np.array(cap_vertices)[:, 0:2]

        triangles = Delaunay(vertices_2d).simplices

        return cap_vertices, triangles

    # Make the upper and lower end caps
    lower_cap_vertices, lower_cap_triangles = _make_cap_triangles(cylindrical_divisions, radial_divisions, radius, 0)
    lower_cap_triangles = np.flip(lower_cap_triangles, 1)
    lower_cap_triangles += len(vertices)
    lower_cap_triangles = lower_cap_triangles.tolist()

    vertices += lower_cap_vertices
    triangles += lower_cap_triangles

    upper_cap_vertices, upper_cap_triangles = _make_cap_triangles(cylindrical_divisions, radial_divisions, radius, height)
    upper_cap_triangles += len(vertices)
    upper_cap_triangles = upper_cap_triangles.tolist()

    vertices += upper_cap_vertices
    triangles += upper_cap_triangles

    vertices = np.array(vertices)
    triangles = np.array(triangles)

    if cylinder.parent:
        to_world = cylinder.to_root()
    else:
        to_world = cylinder.transform

    # Convert vertices to positions in world coordinates
    for i in range(vertices.shape[0]):
        p = Point3D(vertices[i, 0], vertices[i, 1], vertices[i, 2]).transform(to_world)
        vertices[i, 0] = p.x
        vertices[i, 1] = p.y
        vertices[i, 2] = p.z

    return vertices, triangles
Esempio n. 20
0
##########################
# add machine components #

config_file = get_resource("ST40-IVC1", "configuration", 'st40_ivc1_config')
load_wall_configuration(config_file, world)


eq002 = get_resource("ST40-IVC1", "equilibrium", "eq_006_2T_export")
fiesta = Fiesta(eq002)
b_field = fiesta.b_field
lcfs = fiesta.get_midplane_lcfs()[1]


seed_points = [
    Point3D(0.75, 0, 0),
    Point3D(lcfs + 0.001, 0, 0),
    Point3D(lcfs + 0.01, 0, 0),
    Point3D(lcfs + 0.02, 0, -0.01)
]


field_tracer = FieldlineTracer(b_field, method=RK2(step_size=0.0001))

end_point, _, trajectory1 = field_tracer.trace(world, seed_points[0], save_trajectory=True, max_length=15)
end_point, _, trajectory2 = field_tracer.trace(world, seed_points[1], save_trajectory=True, max_length=15)
end_point, _, trajectory3 = field_tracer.trace(world, seed_points[2], save_trajectory=True, max_length=15)
end_point, _, trajectory4 = field_tracer.trace(world, seed_points[3], save_trajectory=True, max_length=15)

# mlab.plot3d([0, 0.005, 0.001], [0, 0, 0], [0, 0, 0], tube_radius=0.0005, color=(1, 0, 0))
# mlab.plot3d([0, 0, 0], [0, 0.005, 0.001], [0, 0, 0], tube_radius=0.0005, color=(0, 1, 0))
Esempio n. 21
0
##############################
# calculate heatflux mapping #

mesh_powers = {}
null_intersections = 0
lost_power = 0

power_per_fieldline = TOTAL_POWER / NUM_OF_FIELDLINES

t_start = time.time()
for i in range(NUM_OF_FIELDLINES):

    seed_radius = q_to_s_func(random()) + lcfs_radius
    seed_angle = random() * 45
    seed_point = Point3D(seed_radius * np.cos(np.deg2rad(seed_angle)),
                         seed_radius * np.sin(np.deg2rad(seed_angle)), 0)

    end_point, intersection, _ = field_tracer.trace(world,
                                                    seed_point,
                                                    max_length=15)

    if intersection is not None:
        try:
            powers = mesh_powers[intersection.primitive.name]
        except KeyError:
            mesh = intersection.primitive
            powers = np.zeros((mesh.data.triangles.shape[0]))
            mesh_powers[intersection.primitive.name] = powers

        tri_id = intersection.primitive_coords[0]
        powers[tri_id] += power_per_fieldline
Esempio n. 22
0
    def map_power(self,
                  power,
                  angle_period,
                  field_tracer,
                  world,
                  num_of_fieldlines=50000,
                  max_tracing_length=15,
                  phi_offset=0,
                  debug_output=False,
                  debug_count=10000,
                  write_output=True):
        """
        Map the power from this surface onto the wall tiles.

        :param float power: The total power that will be mapped onto the tiles using the
          specified distribution.
        :param float angle_period: the spatial period for the interface surface in degrees,
          e.g. 45 degrees. Exploiting cylindrical symmetry will enable a significant speed up
          of the calculations.
        :param FieldlineTracer field_tracer: a pre-configured field line tracer object.
        :param World world; A world scenegraph to be mapped. This scenegraph must contain all the
          desired meshes for power tracking calculations.
        :param int num_of_fieldlines: the number of fieldlines to launch in the mapping process.
          Defaults to 50000 fieldlines.
        :param float max_tracing_length: the maximum length for tracing fieldlines.
        :param float phi_offset: the angular range offset for collision point mapping.
          Important for cases where the periodic divertor tiles straddle phi=0.
        :param bool debug_output: toggle to print extra debug information output, such as the meshes
          collided with and the amount of lost power.
        """

        if not (isinstance(power, (float, int)) and power > 0):
            raise TypeError("The interface power must be a float/int > 0.")

        if not (isinstance(angle_period,
                           (float, int)) and 0 < angle_period <= 360):
            raise TypeError(
                "The angle period must be a float/int between (0, 360].")

        if 360 % angle_period:
            raise ValueError(
                "The angle period must be divisible into 360 degrees an integer number of times."
            )

        if not (isinstance(num_of_fieldlines, int) and num_of_fieldlines > 0):
            raise TypeError(
                "The number of fieldlines to trace must be an integer > 0.")

        # reduce power when exploiting  cylindrical symmetry
        reduction_factor = 360 / angle_period
        total_power = power / reduction_factor
        power_per_fieldline = total_power / num_of_fieldlines

        meshes = {}
        mesh_powers = {}
        mesh_hitpoints = {}
        mesh_seedpoints = {}
        null_intersections = 0
        lost_power = 0

        t_start = time.time()
        for i in range(num_of_fieldlines):

            seed_point_2d = self._generate_sample_point()
            seed_angle = random() * angle_period
            seed_point = Point3D(
                seed_point_2d.x * np.cos(np.deg2rad(seed_angle)),
                seed_point_2d.x * np.sin(np.deg2rad(seed_angle)),
                seed_point_2d.y)

            end_point, intersection, _ = field_tracer.trace(
                world, seed_point, max_length=max_tracing_length)

            # log the collision information for power tallies
            if intersection is not None:

                # catch primitive for later if we haven't encountered it before
                try:
                    meshes[intersection.primitive.name]
                except KeyError:
                    meshes[
                        intersection.primitive.name] = intersection.primitive

                # extract power array for intersected mesh and save results
                try:
                    powers = mesh_powers[intersection.primitive.name]
                except KeyError:
                    mesh = intersection.primitive
                    powers = np.zeros((mesh.data.triangles.shape[0]))
                    mesh_powers[intersection.primitive.name] = powers

                tri_id = intersection.primitive_coords[0]
                powers[tri_id] += power_per_fieldline

                # save hit points for saving to a separate vtk file
                try:
                    hitpoints = mesh_hitpoints[intersection.primitive.name]
                except KeyError:
                    hitpoints = []
                    mesh_hitpoints[intersection.primitive.name] = hitpoints

                # save seed points for separate analysis
                try:
                    seedpoints = mesh_seedpoints[intersection.primitive.name]
                except KeyError:
                    seedpoints = []
                    mesh_seedpoints[intersection.primitive.name] = seedpoints

                # map the hit point back to the starting sector (angular period)
                hit_point = intersection.hit_point.transform(
                    intersection.primitive_to_world)
                phi = np.rad2deg(atan2(hit_point.y, hit_point.x)) - phi_offset
                phase_phi = phi - phi % angle_period
                mapped_point = hit_point.transform(rotate_z(-phase_phi))
                hitpoints.append(
                    (mapped_point.x, mapped_point.y, mapped_point.z))

                seedpoints.append(seed_point)

            else:
                null_intersections += 1
                lost_power += power_per_fieldline

            if not i % debug_count and debug_output:
                print("Tracing fieldline {}.".format(i))

        t_end = time.time()

        if debug_output:
            print("Meshes collided with:")
            for mesh_name, mesh_values in mesh_powers.items():
                power_fraction = mesh_values.sum() / total_power * 100
                print('{} - {:.4G}%'.format(mesh_name, power_fraction))
            print("Fraction of lost power - {:.4G}%".format(lost_power /
                                                            total_power))

            print()
            print("execution time: {}".format(t_end - t_start))
            print()

        if write_output:

            for mesh_name in mesh_powers.keys():

                mesh_primitive = meshes[mesh_name]
                powers = mesh_powers[mesh_name]
                hitpoints = np.array(mesh_hitpoints[mesh_name])

                output_filename = mesh_name + ".vtk"
                self._write_mesh_power_vtk(output_filename, powers,
                                           mesh_primitive)

                point_filename = mesh_name + ".vtp"
                self._write_mesh_points_vtk(point_filename, hitpoints,
                                            power_per_fieldline)

        return mesh_powers, mesh_hitpoints, mesh_seedpoints
Esempio n. 23
0
s1_from_s2_signed_distance = np.empty(n_s1_triangles)
s1_from_s2_signed_distance[:] = 1E999

s2_intersects = np.zeros(n_s2_triangles)
s2s1_distance = np.empty(n_s2_triangles)
s2s1_distance[:] = 1E999
s2_from_s1_signed_distance = np.empty(n_s2_triangles)
s2_from_s1_signed_distance[:] = 1E999
s2_pair = np.zeros(n_s1_triangles)


for s1_tri_id in range(n_s1_triangles):

    v1, v2, v3 = s1_triangles[s1_tri_id]
    u1x, u1y, u1z = s1_vertices[v1]
    u1 = Point3D(u1x, u1y, u1z)
    u2x, u2y, u2z = s1_vertices[v2]
    u2 = Point3D(u2x, u2y, u2z)
    u3x, u3y, u3z = s1_vertices[v3]
    u3 = Point3D(u3x, u3y, u3z)
    uc = Point3D((u1x + u2x + u3x) / 3, (u1y + u2y + u3y) / 3, (u1z + u2z + u3z) / 3)
    n_pi1 = u1.vector_to(u2).cross(u1.vector_to(u3)).normalise()  # normal vector of plane 1

    for s2_tri_id in range(n_s2_triangles):

        v1, v2, v3 = s2_triangles[s2_tri_id]
        v1x, v1y, v1z = s2_vertices[v1]
        v1 = Point3D(v1x, v1y, v1z)
        v2x, v2y, v2z = s2_vertices[v2]
        v2 = Point3D(v2x, v2y, v2z)
        v3x, v3y, v3z = s2_vertices[v3]
Esempio n. 24
0
import numpy as np
import matplotlib.pyplot as plt

from raysect.core import Point3D, Vector3D, rotate_basis, translate, Ray as CoreRay
from raysect.core.math.sampler import DiskSampler3D, RectangleSampler3D, TargettedHemisphereSampler
from raysect.optical import World
from raysect.primitive import Box, Cylinder, Subtract
from raysect.optical.material import AbsorbingSurface, NullMaterial

R_2_PI = 1 / (2 * np.pi)

world = World()

# Setup pinhole
target_plane = Box(Point3D(-10, -10, -0.000001), Point3D(10, 10, 0.000001))
hole = Cylinder(0.001, 0.001, transform=translate(0, 0, -0.0005))
pinhole = Subtract(target_plane,
                   hole,
                   parent=world,
                   material=AbsorbingSurface())

target = Cylinder(0.0012,
                  0.001,
                  transform=translate(0, 0, -0.0011),
                  parent=world,
                  material=NullMaterial())


def analytic_etendue(area_det, area_slit, distance, alpha, gamma):

    return area_det * area_slit * np.cos(alpha / 360 * (2 * np.pi)) * np.cos(
Esempio n. 25
0
def mask_corners(element):
    """
    Support detectors with rounded corners, by producing a mask to cover
    the corners.

    The mask is produced by placing thin rectangles of side
    element.curvature_radius at each corner, and then cylinders of
    radius element.curvature_radius centred on the inner vertex of
    those rectangles. Then each corner of the mask is the part of the
    rectangle not covered by the cylinder.

    The curvature radius should be given in units of metres.
    """
    # Make the mask very (but not infinitely) thin, so that raysect
    # can actually detect that it's there. We'll work in the local
    # coordinate system of the element, with dx=width, dy=height,
    # dz=depth.
    dz = 1e-6
    rc = element.curvature_radius  # Shorthand
    try:
        dx = element.x_width
        dy = element.y_width
    except AttributeError:
        dx = element.dx
        dy = element.dy

    # Create a box and a cylinder of the appropriate size.
    # Then position copies of these at each corner.
    box_template = Box(Point3D(0, 0, 0), Point3D(rc, rc, dz))
    cylinder_template = Cylinder(rc, dz)

    top_left_box = box_template.instance(
        transform=translate(-dx / 2, dy / 2 - rc, 0),
    )
    top_left_cylinder = cylinder_template.instance(
        transform=translate(-dx / 2 + rc, dy / 2 - rc, 0),
    )
    top_left_mask = Subtract(top_left_box,
                             Intersect(top_left_box, top_left_cylinder))

    top_right_box = box_template.instance(
        transform=translate(dx / 2 - rc, dy / 2 - rc, 0),
    )
    top_right_cylinder = cylinder_template.instance(
        transform=translate(dx / 2 - rc, dy / 2 - rc, 0),
    )
    top_right_mask = Subtract(top_right_box,
                              Intersect(top_right_box, top_right_cylinder))

    bottom_right_box = box_template.instance(
        transform=translate(dx / 2 - rc, -dy / 2, 0),
    )
    bottom_right_cylinder = cylinder_template.instance(
        transform=translate(dx / 2 - rc, -dy / 2 + rc, 0),
    )
    bottom_right_mask = Subtract(bottom_right_box,
                                 Intersect(bottom_right_box, bottom_right_cylinder))

    bottom_left_box = box_template.instance(
        transform=translate(-dx / 2, -dy / 2, 0),
    )
    bottom_left_cylinder = cylinder_template.instance(
        transform=translate(-dx / 2 + rc, -dy / 2 + rc, 0),
    )
    bottom_left_mask = Subtract(bottom_left_box,
                                Intersect(bottom_left_box, bottom_left_cylinder))

    # The foil mask is the sum of all 4 of these corner shapes
    mask = functools.reduce(Union, (top_left_mask, top_right_mask,
                                    bottom_right_mask, bottom_left_mask))
    mask.material = AbsorbingSurface()
    mask.transform = translate(0, 0, dz)
    mask.name = element.name + ' - rounded edges mask'
    mask.parent = element
Esempio n. 26
0
 def centre_point(self):
     return Point3D(0, 0, 0).transform(self.to_root())
Esempio n. 27
0
def load_ks5_sightlines(pulse, spectrometer, parent=None,
                        fibre_names=None,
                        min_wavelength = 526,
                        max_wavelength = 532,
                        spectral_bins = 500):

    if not pulse >= 76666:
        raise ValueError("Only shots >= 76666 are supported at this time.")

    if spectrometer not in ["ks5c", "ks5d"]:
        raise ValueError("Only spectrometers ['ks5c', 'ks5d'] are supported at this time.")

    import idlbridge as idl
    idl.execute('searchpath = !PATH')

    global _idl_was_setup
    if not _idl_was_setup:
        _setup_idl()
        _idl_was_setup = True

    idl.execute("ret = get_ks5_alignment(pulse={}, spec='{}')".format(pulse, spectrometer))

    # Pull out data
    cg_align = idl.get("ret")

    # Process fibres in the order that CXSfit uses.
    cxsfit_order = [i[0] for i in sorted(enumerate(cg_align['cxsfit_track']), key=lambda x:x[1], reverse=True)]

    sightline_group = LineOfSightGroup(parent=parent, name=spectrometer)

    for icg in cxsfit_order:

        fibre_name = str(cg_align['fibre_name'][icg])

        # Some fibre names are blank, meaning ignore them.
        if not fibre_name.strip():
            continue

        if fibre_names and fibre_name not in fibre_names:
             print('Skipped', fibre_name)
             continue

        # Extract the fibres origin and direction
        xi = cg_align['origin_cart']['x'][icg]/1000
        yi = cg_align['origin_cart']['y'][icg]/1000
        zi = cg_align['origin_cart']['z'][icg]/1000

        pini6 = 5
        xj = cg_align['pos_activevol_cart']['x'][pini6][icg]/1000
        yj = cg_align['pos_activevol_cart']['y'][pini6][icg]/1000
        zj = cg_align['pos_activevol_cart']['z'][pini6][icg]/1000

        los_origin = Point3D(xi, yi, zi)
        los_vec = Vector3D(xj-xi, yj-yi, zj-zi).normalise()

        sight_line = SpectroscopicSightLine(los_origin, los_vec, name=fibre_name, parent=sightline_group)
        sight_line.min_wavelength = min_wavelength
        sight_line.max_wavelength = max_wavelength
        sight_line.spectral_bins = spectral_bins

        sightline_group.add_sight_line(sight_line)

    return sightline_group
Esempio n. 28
0
def sphere_to_mesh(sphere, subdivision_count=2):

    if not isinstance(sphere, Sphere):
        raise TypeError("The _sphere_to_mesh() function takes a Raysect Box primitive as an argument, "
                        "wrong type '{}' given.".format(type(sphere)))

    # Calculate vertices and faces using the icosohedren method
    # We compute a regular icosohedren with 12 vertices and 20 faces.
    # Vertices given by all perturbations of:
    # (0, ±1, ±ϕ), (±1, ±ϕ, 0), (±ϕ, 0, ±1), where ϕ = golden ratio

    golden_ratio = 1.61803398875

    radius = sphere.radius

    v1 = Vector3D(-1.0, golden_ratio, 0.0).normalise() * radius
    v2 = Vector3D(1.0, golden_ratio, 0.0).normalise() * radius
    v3 = Vector3D(-1.0, -golden_ratio, 0.0).normalise() * radius
    v4 = Vector3D(1.0, -golden_ratio, 0.0).normalise() * radius
    v5 = Vector3D(0.0, -1.0, golden_ratio).normalise() * radius
    v6 = Vector3D(0.0, 1.0, golden_ratio).normalise() * radius
    v7 = Vector3D(0.0, -1.0, -golden_ratio).normalise() * radius
    v8 = Vector3D(0.0, 1.0, -golden_ratio).normalise() * radius
    v9 = Vector3D(golden_ratio, 0.0, -1.0).normalise() * radius
    v10 = Vector3D(golden_ratio, 0.0, 1.0).normalise() * radius
    v11 = Vector3D(-golden_ratio, 0.0, -1.0).normalise() * radius
    v12 = Vector3D(-golden_ratio, 0.0, 1.0).normalise() * radius

    vertices = [
        [v1.x, v1.y, v1.z],
        [v2.x, v2.y, v2.z],
        [v3.x, v3.y, v3.z],
        [v4.x, v4.y, v4.z],
        [v5.x, v5.y, v5.z],
        [v6.x, v6.y, v6.z],
        [v7.x, v7.y, v7.z],
        [v8.x, v8.y, v8.z],
        [v9.x, v9.y, v9.z],
        [v10.x, v10.y, v10.z],
        [v11.x, v11.y, v11.z],
        [v12.x, v12.y, v12.z],
    ]

    triangles = [
        [0, 11, 5],
        [0, 5, 1],
        [0, 1, 7],
        [0, 7, 10],
        [0, 10, 11],
        [1, 5, 9],
        [5, 11, 4],
        [11, 10, 2],
        [10, 7, 6],
        [7, 1, 8],
        [3, 9, 4],
        [3, 4, 2],
        [3, 2, 6],
        [3, 6, 8],
        [3, 8, 9],
        [4, 9, 5],
        [2, 4, 11],
        [6, 2, 10],
        [8, 6, 7],
        [9, 8, 1]
    ]

    # Optional - subdivision of icosohedren to increase resolution
    num_vertices = 12
    num_triangles = 20
    for i in range(subdivision_count):
        for j in range(num_triangles):
            triangle = triangles[j]
            # extract current triangle vertices
            v0_id = triangle[0]
            v1_id = triangle[1]
            v2_id = triangle[2]
            v0 = Vector3D(vertices[v0_id][0], vertices[v0_id][1], vertices[v0_id][2])
            v1 = Vector3D(vertices[v1_id][0], vertices[v1_id][1], vertices[v1_id][2])
            v2 = Vector3D(vertices[v2_id][0], vertices[v2_id][1], vertices[v2_id][2])

            # subdivide with three new vertices
            v3 = (v0 + v1).normalise() * radius
            v3_id = num_vertices
            v4 = (v1 + v2).normalise() * radius
            v4_id = num_vertices + 1
            v5 = (v2 + v0).normalise() * radius
            v5_id = num_vertices + 2
            vertices.append([v3.x, v3.y, v3.z])
            vertices.append([v4.x, v4.y, v4.z])
            vertices.append([v5.x, v5.y, v5.z])

            # ... and three new faces
            triangles[j] = [v0_id, v3_id, v5_id]  # replace the first face
            triangles.append([v3_id, v1_id, v4_id])
            triangles.append([v4_id, v2_id, v5_id])
            triangles.append([v3_id, v4_id, v5_id])

            num_vertices += 3
            num_triangles += 3

    vertices = np.array(vertices)
    triangles = np.array(triangles)

    if sphere.parent:
        to_world = sphere.to_root()
    else:
        to_world = sphere.transform

    # Convert vertices to positions in world coordinates
    for i in range(vertices.shape[0]):
        p = Point3D(vertices[i, 0], vertices[i, 1], vertices[i, 2]).transform(to_world)
        vertices[i, 0] = p.x
        vertices[i, 1] = p.y
        vertices[i, 2] = p.z

    return vertices, triangles
Esempio n. 29
0
import numpy as np
import matplotlib.pyplot as plt
from mayavi import mlab
from raysect.core import World, Point3D, Vector3D
from cherab.core.math import ConstantVector3D

from vita.modules.cherab import FieldlineTracer, Euler

# the world scene-graph
world = World()

b_field = ConstantVector3D(Vector3D(0, 1.5, 0))

field_tracer = FieldlineTracer(b_field, method=Euler(step_size=0.001))

start_point = Point3D(0, 0, 0)
end_point, trajectory = field_tracer.trace(world,
                                           start_point,
                                           save_trajectory=True,
                                           max_steps=1000)

num_segments = len(trajectory)
x = np.zeros(num_segments)
y = np.zeros(num_segments)
z = np.zeros(num_segments)
for ith_position, position in enumerate(trajectory):
    x[ith_position] = position.x
    y[ith_position] = position.y
    z[ith_position] = position.z

mlab.plot3d(x, y, z, tube_radius=0.0005, color=(1, 0, 0))
Esempio n. 30
0
                                  d_ion_species,
                                  inside_outside=plasma.inside_outside)
d_delta_recom.add_emitter_to_world(world, plasma)

d_epsilon_excit = ExcitationLine(d_epsilon,
                                 plasma.electron_distribution,
                                 d_atom_species,
                                 inside_outside=plasma.inside_outside)
d_epsilon_excit.add_emitter_to_world(world, plasma)
d_epsilon_recom = RecombinationLine(d_epsilon,
                                    plasma.electron_distribution,
                                    d_ion_species,
                                    inside_outside=plasma.inside_outside)
d_epsilon_recom.add_emitter_to_world(world, plasma)

start_point = Point3D(1.669, 0, -1.6502)
forward_vector = Vector3D(1 - 1.669, 0, -2 + 1.6502).normalise()
up_vector = Vector3D(0, 0, 1.0)

spectra = SpectralPipeline0D()
fibre = FibreOptic([spectra],
                   acceptance_angle=1,
                   radius=0.001,
                   spectral_bins=8000,
                   spectral_rays=1,
                   pixel_samples=5,
                   transform=translate(*start_point) *
                   rotate_basis(forward_vector, up_vector),
                   parent=world)

fibre.min_wavelength = 350.0