Exemplo n.º 1
0
def load_vessel_world(mesh_parts, shift_p5=False):
    """Load the world containing the vessel mesh parts.

    <mesh_parts> is a list of filenames containing mesh files in either
    RSM or OBJ format, which are to be loaded into the world.

    If shift_p5 is True, the mesh files representing the P5 coils will
    have a downward shift applied to them to account for the UEP sag.
    This is described in CD/MU/04783.

    Returns world, the root of the scenegraph.
    """
    world = World()
    for path, _ in mesh_parts:
        print("importing {}  ...".format(os.path.split(path)[1]))
        filename = os.path.split(path)[-1]
        name, ext = filename.split('.')
        if 'P5_' in path and shift_p5:
            p5_zshift = -0.00485  # From CD/MU/04783
            transform = translate(0, 0, p5_zshift)
        else:
            transform = None
        if ext.lower() == 'rsm':
            Mesh.from_file(path,
                           parent=world,
                           material=AbsorbingSurface(),
                           transform=transform,
                           name=name)
        elif ext.lower() == 'obj':
            import_obj(path,
                       parent=world,
                       material=AbsorbingSurface(),
                       name=name)
        else:
            raise ValueError("Only RSM and OBJ meshes are supported.")
    # Add a solid cylinder at R=0 to prevent rays finding their way through the
    # gaps in the centre column armour. This is only necessary for the MAST
    # meshes, but it does no harm to add it to MAST-U meshes too
    height = 6
    radius = 0.1
    Cylinder(radius=radius,
             height=height,
             parent=world,
             transform=translate(0, 0, -height / 2),
             material=AbsorbingSurface(),
             name='Blocking Cylinder')
    return world
Exemplo n.º 2
0
 def point(self, value):
     if not (self._direction.x == 0 and self._direction.y == 0
             and self._direction.z == 1):
         up = Vector3D(0, 0, 1)
     else:
         up = Vector3D(1, 0, 0)
     self._point = value
     self._observer.transform = translate(
         value.x, value.y, value.z) * rotate_basis(self._direction, up)
Exemplo n.º 3
0
 def direction(self, value):
     if value.x != 0 and value.y != 0 and value.z != 1:
         up = Vector3D(0, 0, 1)
     else:
         up = Vector3D(1, 0, 0)
     self._direction = value
     self._observer.transform = translate(self._point.x, self._point.y,
                                          self._point.z) * rotate_basis(
                                              value, up)
Exemplo n.º 4
0
    def __init__(self, slit_id, centre_point, basis_x, dx, basis_y, dy, dz=0.001,
                 parent=None, csg_aperture=False, curvature_radius=0):

        # perform validation of input parameters

        if not isinstance(dx, (float, int)):
            raise TypeError("dx argument for BolometerSlit must be of type float/int.")
        if not dx > 0:
            raise ValueError("dx argument for BolometerSlit must be greater than zero.")

        if not isinstance(dy, (float, int)):
            raise TypeError("dy argument for BolometerSlit must be of type float/int.")
        if not dy > 0:
            raise ValueError("dy argument for BolometerSlit must be greater than zero.")

        if not isinstance(centre_point, Point3D):
            raise TypeError("centre_point argument for BolometerSlit must be of type Point3D.")

        if not isinstance(curvature_radius, (float, int)):
            raise TypeError("curvature_radius argument for BolometerSlit "
                            "must be of type float/int.")
        if curvature_radius < 0:
            raise ValueError("curvature_radius argument for BolometerSlit "
                             "must not be negative.")

        if not isinstance(basis_x, Vector3D):
            raise TypeError("The basis vectors of BolometerSlit must be of type Vector3D.")
        if not isinstance(basis_y, Vector3D):
            raise TypeError("The basis vectors of BolometerSlit must be of type Vector3D.")

        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
        self._curvature_radius = curvature_radius

        # 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

        # round off the detector corners, if applicable
        if self._curvature_radius > 0:
            mask_corners(self)
Exemplo n.º 5
0
def main():
    camera = sys.argv[1]
    try:
        istart = int(sys.argv[2])
        iend = int(sys.argv[3])
    except (IndexError, ValueError):
        istart = None
        iend = None

    shift_p5 = False
    camera_transform = None

    if camera in ("Outer", "Upper"):
        MESH_PARTS = MASTU_FULL_MESH
        grid = "sxdl"
    elif camera in ("Poloidal", "Tangential"):
        MESH_PARTS = MASTU_FULL_MESH
        shift_p5 = True
        grid = "core"
    elif camera in ("PoloidalHighRes", "TangentialHighRes"):
        MESH_PARTS = MASTU_FULL_MESH
        shift_p5 = True
        grid = "core_high_res"
        # Trim off the HighRes suffix from the camera
        camera = camera[:-7]
    elif camera == "Poloidal-MAST":
        MESH_PARTS = MAST_FULL_MESH
        # MAST sensors were displaced by 100mm in the y direction compared with
        # the main chamber sensors at the beginning of MAST-U operation
        camera_transform = translate(0, 0.1, 0)
        grid = "core"
    else:
        raise ValueError("The following cameras are supported: "
                         "'Outer', 'Upper', 'Poloidal', 'Tangential', "
                         "'PoloidalHighRes', 'TangentialHighRes', "
                         "'Poloidal-MAST'")

    calculate_and_save_sensitivities(grid, camera, MESH_PARTS, istart, iend,
                                     shift_p5, camera_transform)
Exemplo n.º 6
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
Exemplo n.º 7
0
pini_8_1 = load_pini_from_ppf(PULSE, '8.1', plasma, adas,
                              attenuation_instructions,
                              beam_emission_instructions, world)
pini_8_2 = load_pini_from_ppf(PULSE, '8.2', plasma, adas,
                              attenuation_instructions,
                              beam_emission_instructions, world)
pini_8_5 = load_pini_from_ppf(PULSE, '8.5', plasma, adas,
                              attenuation_instructions,
                              beam_emission_instructions, world)
pini_8_6 = load_pini_from_ppf(PULSE, '8.6', plasma, adas,
                              attenuation_instructions,
                              beam_emission_instructions, world)

# ############################### OBSERVATION ############################### #
print('Observation')

los = Point3D(4.22950, -0.791368, 0.269430)
direction = Vector3D(-0.760612, -0.648906, -0.0197396).normalise()
los = los + direction * 0.9
up = Vector3D(0, 0, 1)

camera = PinholeCamera(
    (512, 512),
    fov=45,
    parent=world,
    transform=translate(los.x, los.y, los.z) * rotate_basis(direction, up))
camera.pixel_samples = 50
camera.spectral_bins = 15

camera.observe()
Exemplo n.º 8
0
    export_vtk(mesh, basename + '.vtk', triangle_data=triangle_data)


samples = 1000000

sphere_radius = 0.01

min_wl = 400
max_wl = 401

# set-up scenegraph
world = World()
emitter = Sphere(radius=sphere_radius,
                 parent=world,
                 transform=rotate_x(-90) *
                 translate(-0.05409, -0.01264, 0.10064))

base_path = os.path.split(os.path.realpath(__file__))[0]
mesh = import_obj(os.path.join(base_path, "../resources/stanford_bunny.obj"),
                  material=AbsorbingSurface(),
                  parent=world,
                  flip_normals=True)

power = PowerPipeline0D(accumulate=False)
observer = MeshPixel(mesh,
                     pipelines=[power],
                     parent=world,
                     min_wavelength=min_wl,
                     max_wavelength=max_wl,
                     spectral_bins=1,
                     pixel_samples=samples,
Exemplo n.º 9
0
c6_species = Species(carbon, 6, c6_distribution)

#define plasma parameters - electron distribution, impurity composition and B field from EFIT
plasma.electron_distribution = e_distribution
plasma.composition = [d1_species, c6_species]
plasma.b_field = VectorAxisymmetricMapper(equil_time_slice.b_field)
sigma = 0.25
integration_step = 0.02

#define the plasma geometry

plasma.integrator.step = integration_step
plasma.integrator.min_samples = 1000
plasma.atomic_data = adas
plasma.geometry = Cylinder(sigma * 2, sigma * 10.0)
plasma.geometry_transform = translate(0, -sigma * 5.0, 0) * rotate(0, 90, 0)

# # # ########################### NBI CONFIGURATION ############################# #

#Geometry
south_pos = Point3D(0.188819939, -6.88824321,
                    0.0)  #Position of PINI grid center
duct_pos = Point3D(0.539, -1.926, 0.00)  #position of beam duct
south_pos.vector_to(duct_pos)  #beam vector
beam_axis = south_pos.vector_to(duct_pos).normalise()

up = Vector3D(0, 0, 1)
beam_rotation = rotate_basis(beam_axis, up)

beam_position = translate(south_pos.x, south_pos.y, south_pos.z)
Exemplo n.º 10
0
from mayavi import mlab

from raysect.core import translate, Point3D, rotate_basis, Vector3D, rotate
from raysect.optical import World
from raysect.primitive import Box, Sphere, Cylinder, Cone
from raysect.primitive import Sphere, Mesh, Intersect, Subtract, Union

from raysect_mayavi import visualise_scenegraph

########################################################################################################################
# Spheres

s1 = Sphere(0.5, transform=translate(-0.25, 0, 0), name='s1')
s2 = Sphere(0.5, transform=translate(0.25, 0, 0), name='s2')

world = World()
Union(s1, s2, parent=world)
visualise_scenegraph(world)
input('pause...')

world = World()
Intersect(s1, s2, parent=world)
visualise_scenegraph(world)
input('pause...')

world = World()
Subtract(s1, s2, parent=world)
visualise_scenegraph(world)
input('pause...')

########################################################################################################################
Exemplo n.º 11
0
        if x >= 0:
            return True
        return False

    def t2(self, x):
        if x <= 0:
            return True
        return False


# OPERATION = Union()
OPERATION = Intersection()
# OPERATION = Difference()

world = World()
s1 = Sphere(0.5, transform=translate(-0.25, 0, 0), name='s1')
s2 = Sphere(0.5, transform=translate(0.25, 0, 0), name='s2')

s1_vertices, s1_triangles = to_mesh(s1)
n_s1_vertices = s1_vertices.shape[0]
n_s1_triangles = s1_triangles.shape[0]
s1_mesh = Mesh(vertices=s1_vertices, triangles=s1_triangles, smoothing=False)
print()
print('n_s1_triangles', n_s1_triangles)

s2_vertices, s2_triangles = to_mesh(s2)
n_s2_vertices = s2_vertices.shape[0]
n_s2_triangles = s2_triangles.shape[0]
s2_mesh = Mesh(vertices=s2_vertices, triangles=s2_triangles, smoothing=False)
print('n_s2_triangles', n_s2_triangles)
Exemplo n.º 12
0
r, _, z, t_samples = sample3d(h0.distribution.density, (-1, 2, 200), (0, 0, 1),
                              (-1, 1, 200))
plt.imshow(np.transpose(np.squeeze(t_samples)), extent=[-1, 2, -1, 1])
plt.colorbar()
plt.axis('equal')
plt.xlabel('x axis')
plt.ylabel('z axis')
plt.title("Neutral Density profile in x-z plane")

###########################
# Inject beam into plasma #

adas = OpenADAS(permit_extrapolation=True, missing_rates_return_null=True)

integration_step = 0.0025
beam_transform = translate(-0.5, 0.0, 0) * rotate_basis(
    Vector3D(1, 0, 0), Vector3D(0, 0, 1))

beam_energy = 50000  # keV

beam_full = Beam(parent=world, transform=beam_transform)
beam_full.plasma = plasma
beam_full.atomic_data = adas
beam_full.energy = beam_energy
beam_full.power = 3e6
beam_full.element = deuterium
beam_full.sigma = 0.05
beam_full.divergence_x = 0.5
beam_full.divergence_y = 0.5
beam_full.length = 3.0
beam_full.attenuator = SingleRayAttenuator(clamp_to_zero=True)
Exemplo n.º 13
0
from cherab.core.atomic import hydrogen
from cherab.core.model import SingleRayAttenuator
from cherab.tools.plasmas.slab import build_slab_plasma

from cherab.openadas import OpenADAS

# create atomic data source
adas = OpenADAS(permit_extrapolation=True)

world = World()

# PLASMA ----------------------------------------------------------------------
plasma = build_slab_plasma(peak_density=5e19, world=world)

integration_step = 0.0025
beam_transform = translate(-0.000001, 0.0, 0) * rotate_basis(
    Vector3D(1, 0, 0), Vector3D(0, 0, 1))

beam_full = Beam(parent=world, transform=beam_transform)
beam_full.plasma = plasma
beam_full.atomic_data = adas
beam_full.energy = 100000
beam_full.power = 3e6
beam_full.element = hydrogen
beam_full.sigma = 0.05
beam_full.divergence_x = 0.5
beam_full.divergence_y = 0.5
beam_full.length = 3.0
beam_full.attenuator = SingleRayAttenuator(clamp_to_zero=True)
beam_full.integrator.step = integration_step
beam_full.integrator.min_samples = 10
Exemplo n.º 14
0
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(gamma/360 * (2*np.pi)) / distance**2


def raytraced_etendue(distance, detector_radius=0.001, ray_count=100000, batches=10):

    # generate the transform to the detector position and orientation
    detector_transform = translate(0, 0, distance) * rotate_basis(Vector3D(0, 0, -1), Vector3D(0, -1, 0))
Exemplo n.º 15
0
max_wl = 401

# sanity check!
if cube_size <= 2 * sphere_radius:
    raise ValueError("The cube dimensions must be larger that the sphere.")

# set-up scenegraph
world = World()
emitter = Sphere(radius=sphere_radius, parent=world)

# The observer plane covers 1 side of a cube - to work out total power, multiply result by 6
power = PowerPipeline0D(accumulate=False)
observing_plane = Pixel([power], x_width=cube_size, y_width=cube_size,
                        min_wavelength=min_wl, max_wavelength=max_wl,
                        spectral_bins=1, pixel_samples=samples,
                        parent=world, transform=rotate(0, 0, 0)*translate(0, 0, -cube_size / 2))

# Emitter is a sphere volume emitter located at the origin
# Volume of the sphere is 4/3 * Pi * r^3, emission over 4 * pi
# UnityVolumeEmitter emits 1W/str/m^3/ x nm, where x is the wavelength interval, integrated over length

print("Starting observations with volume emitter...")
calculated_volume_emission = 16 / 3 * pi**2 * sphere_radius**3 * (max_wl - min_wl)

emitter.material = UnityVolumeEmitter()
observing_plane.observe()
measured_volume_emission = 6 * power.value.mean
measured_volume_error = 6 * power.value.error()

# Emitter is a sphere surface emitter located at the origin
# Surface area of the sphere is 4 * Pi * r^2, lambert emitter
Exemplo n.º 16
0
    ExcitationLine(d_beta),
    ExcitationLine(d_gamma),
    ExcitationLine(d_delta),
    ExcitationLine(d_epsilon),
    RecombinationLine(d_alpha),
    RecombinationLine(d_beta),
    RecombinationLine(d_gamma),
    RecombinationLine(d_delta),
    RecombinationLine(d_epsilon)
]

# ########################### NBI CONFIGURATION ############################# #

# BEAM ------------------------------------------------------------------------

beam = Beam(parent=world, transform=translate(1.0, 0.0, 0) * rotate(90, 0, 0))
beam.plasma = plasma
beam.atomic_data = adas
beam.energy = 65000
beam.power = 3e6
beam.element = elements.deuterium
beam.sigma = 0.025
beam.divergence_x = 0.5
beam.divergence_y = 0.5
beam.length = 3.0
beam.attenuator = SingleRayAttenuator(clamp_to_zero=True)
beam.models = [
    BeamCXLine(Line(elements.helium, 1, (4, 3))),
    BeamCXLine(Line(elements.helium, 1, (6, 4))),
    BeamCXLine(Line(elements.carbon, 5, (8, 7))),
    BeamCXLine(Line(elements.carbon, 5, (9, 8))),
Exemplo n.º 17
0
emitting_sphere_radius = 0.5
collection_sphere_radius = 5

min_wl = 400
max_wl = 401

# sanity check!
if collection_sphere_radius <= emitting_sphere_radius:
    raise ValueError("The collecting sphere radius must be larger that the emitting sphere.")

power = PowerPipeline0D(accumulate=False)

# set-up scenegraph
world = World()
emitter = Sphere(radius=emitting_sphere_radius, parent=world, transform=translate(4, 0, 0))
observer = ObservingSphere([power], radius=collection_sphere_radius,
                           min_wavelength=min_wl, max_wavelength=max_wl,
                           spectral_bins=1, pixel_samples=samples,
                           parent=world)


# Emitter is a sphere volume emitter located at the origin
# Volume of the sphere is 4/3 * Pi * r^3, emission over 4 * pi
# UnityVolumeEmitter emits 1W/str/m^3/ x nm, where x is the wavelength interval, integrated over length

print("Starting observations with volume emitter...")
calculated_volume_emission = (4 * pi) * (4/3 * pi * emitting_sphere_radius**3) * (max_wl - min_wl)

emitter.material = UnityVolumeEmitter()
# emitter.material = UniformVolumeEmitter(ConstantSF(1.0))
    def make_cherab_image(self):
        """
        run cherab to generate the synthetic spectral cube
        :return:
        """
        if self.radiance is not NotImplemented:
            self.radiance.close()
        if self.spectral_radiance is not NotImplemented:
            self.spectral_radiance.close()

        import_mastu_mesh(self.world, )

        # first, define camera, calculate view vectors and calculate ray lengths
        pipeline_spectral = SpectralPowerPipeline2D()
        pipeline_spectral_rad = SpectralRadiancePipeline2D()
        pipelines = [pipeline_spectral, pipeline_spectral_rad, ]
        camera = PinholeCamera(self.sensor_format_ds, fov=self.fov, pipelines=pipelines, parent=self.world)

        # orient and position the camera
        init_view_vector, init_up_vector = Vector3D(0, 0, 1), Vector3D(0, 1, 0)
        axle_1 = init_view_vector.cross(self.view_vector)
        angle = init_view_vector.angle(self.view_vector)
        t_1 = rotate_vector(angle, axle_1)

        final_up_vector = rotate_vector(-90, axle_1) * self.view_vector
        intermediate_up_vector = t_1 * init_up_vector
        angle_between = intermediate_up_vector.angle(final_up_vector)
        t_2 = rotate_vector(-angle_between, self.view_vector)

        camera.transform = translate(self.pupil_point[0],
                                     self.pupil_point[1],
                                     self.pupil_point[2], ) * t_2 * t_1

        vector_xyz = np.arange(3)
        vector_xyz = xr.DataArray(vector_xyz, coords=(vector_xyz, ), dims=('vector_xyz',), name='vector_xyz', )

        # calculating the pixel view directions
        view_vectors = xr.combine_nested(
            [xr.zeros_like(self.x_pixel_ds + self.y_pixel_ds) + self.view_vector[i] for i in [0, 1, 2, ]],
            concat_dim=(vector_xyz,), )
        view_vectors = view_vectors.rename('view_vectors')

        def v3d2da(v3d):
            """
            raysect Vector3D to xarray DataArray

            :param v3d:
            :return:
            """
            da = np.array([v3d.x, v3d.y, v3d.z, ])
            da = xr.DataArray(da, coords=(np.arange(3),), dims=('vector_xyz',), )
            return da

        # basis unit vectors defining camera view -- v_z is forward and v_y is up
        v_y = final_up_vector.normalise()
        v_x = self.view_vector.cross(v_y).normalise()
        v_z = self.view_vector.normalise()
        v_x, v_y, v_z = [v3d2da(i) for i in [v_x, v_y, v_z, ]]

        # FOV defines the widest view, with pixels defined as square.
        sensor_aspect = self.sensor_format[1] / self.sensor_format[0]
        if sensor_aspect > 1:
            fov_v = self.fov
            fov_h = self.fov / sensor_aspect
        elif sensor_aspect == 1:
            fov_v = fov_h = self.fov
        elif sensor_aspect < 1:
            fov_h = self.fov
            fov_v = self.fov * sensor_aspect
        else:
            raise Exception()

        pixel_projection = 2 * np.tan(fov_h * np.pi / 360) / self.sensor_format[0]
        view_vectors = view_vectors + (v_x * (self.x_pixel_ds - self.sensor_format[0] / 2 + 0.5) * pixel_projection) + \
                       (v_y * (self.y_pixel_ds - self.sensor_format[1] / 2 + 0.5) * pixel_projection)

        if self.verbose:
            print('--status: calculating ray lengths')
        # TODO there has to be a better way of doing this?!
        ray_lengths = xr.DataArray(np.zeros(self.sensor_format_ds), dims=('x', 'y', ), coords=(self.x_ds, self.y_ds, ))
        for idx_x, x_pixel in enumerate(self.x_pixel_ds.values):
            if self.verbose and idx_x % 10 == 0:
                print('x =', str(x_pixel))
            for idx_y, y_pixel in enumerate(self.y_pixel_ds.values):
                direction = Vector3D(*list(view_vectors.isel(x=idx_x, y=idx_y, ).values))

                intersections = []
                for p in self.world.primitives:
                    intersection = p.hit(CoreRay(self.pupil_point, direction, ))
                    if intersection is not None:
                        intersections.append(intersection)

                # find the intersection corresponding to the shortest ray length
                no_intersections = len(intersections)
                if no_intersections == 0:
                    ray_lengths.values[idx_x, idx_y] = 3
                else:
                    ray_lengths.values[idx_x, idx_y] = min([i.ray_distance for i in intersections if i.primitive.name != 'Plasma Geometry'])

        camera.spectral_bins = 40
        camera.pixel_samples = 10
        camera.min_wavelength = self.wl_min_nm
        camera.max_wavelength = self.wl_max_nm
        camera.quiet = not self.verbose
        camera.observe()

        # output to netCDF via xarray
        wl = pipeline_spectral.wavelengths
        wl = xr.DataArray(wl, coords=(wl, ), dims=('wavelength', )) * 1e-9  # ( m )
        spec_power_ds = pipeline_spectral.frame.mean * 1e9  # converting units from (W/nm) --> (W/m)
        spec_radiance_ds = pipeline_spectral_rad.frame.mean * 1e9
        coords = (self.x_ds, self.y_ds, wl, )
        dims = ('x', 'y', 'wavelength', )
        name = 'spec_power'
        attrs = {'units': 'W/m^2/str/m'}
        spec_power_ds = xr.DataArray(np.flip(spec_power_ds, axis=1), coords=coords, dims=dims, name=name, attrs=attrs, )
        spec_radiance_ds = xr.DataArray(np.flip(spec_radiance_ds, axis=1, ), coords=coords, dims=dims, name=name, attrs=attrs, )

        # calculate the centre-of-mass wavelength
        radiance_ds = spec_power_ds.integrate(dim='wavelength').assign_attrs({'units': 'W/m^2/str', })

        ds_ds = xr.Dataset({'spectral_radiance_ds': spec_radiance_ds,
                            'radiance_ds': radiance_ds,
                            'view_vectors_ds': view_vectors,
                            'ray_lengths_ds': ray_lengths
                            })

        x_p_y = self.x + self.y
        spec_power = spec_power_ds.interp_like(x_p_y) / self.cherab_down_sample  # to conserve power
        ds = xr.Dataset({'spectral_radiance': spec_power, })
        ds_ds.to_netcdf(self.fpath_ds, mode='w', )
        ds.to_netcdf(self.fpath, mode='w', )
Exemplo n.º 19
0
start = time.time()

for i, detector in enumerate(aug_wall_detectors):

    print()
    print("detector {}".format(i))

    y_width = detector[2]
    centre_point = detector[3]
    normal_vector = detector[4]
    y_vector = detector[5]
    pixel_area = X_WIDTH * y_width

    power_data = PowerPipeline0D()

    pixel_transform = translate(centre_point.x, centre_point.y,
                                centre_point.z) * rotate_basis(
                                    normal_vector, y_vector)
    pixel = Pixel([power_data],
                  x_width=X_WIDTH,
                  y_width=y_width,
                  name='pixel-{}'.format(i),
                  spectral_bins=1,
                  transform=pixel_transform,
                  parent=world,
                  pixel_samples=500)

    pixel.observe()

    powers.append(power_data.value.mean / pixel_area)
    power_errors.append(power_data.value.error() / pixel_area)
    detector_numbers.append(i)
Exemplo n.º 20
0
r, _, z, t_samples = sample3d(h0_dens, (-1, 2, 200), (0, 0, 1), (-1, 1, 200))
plt.imshow(np.transpose(np.squeeze(t_samples)), extent=[-1, 2, -1, 1])
plt.colorbar()
plt.axis('equal')
plt.xlabel('x axis')
plt.ylabel('z axis')
plt.title("Neutral Density profile in x-z plane")

###########################
# Inject beam into plasma #

cVI_8_7 = Line(carbon, 5, (8, 7))
cVI_10_8 = Line(carbon, 5, (10, 8))

integration_step = 0.0025
beam_transform = translate(-0.5, 0.0, 0) * rotate_basis(
    Vector3D(1, 0, 0), Vector3D(0, 0, 1))
beam_energy = 50000  # keV

beam_full = Beam(parent=world, transform=beam_transform)
beam_full.plasma = plasma
beam_full.atomic_data = adas
beam_full.energy = beam_energy
beam_full.power = 3e6
beam_full.element = deuterium
beam_full.sigma = 0.05
beam_full.divergence_x = 0.5
beam_full.divergence_y = 0.5
beam_full.length = 3.0
beam_full.attenuator = SingleRayAttenuator(clamp_to_zero=True)
beam_full.models = [BeamCXLine(cVI_8_7), BeamCXLine(cVI_10_8)]
Exemplo n.º 21
0
    def __init__(self, detector_id, centre_point, basis_x, dx, basis_y, dy, slit,
                 parent=None, units="Power", accumulate=False, curvature_radius=0):

        # perform validation of input parameters

        if not isinstance(dx, (float, int)):
            raise TypeError("dx argument for BolometerFoil must be of type float/int.")
        if not dx > 0:
            raise ValueError("dx argument for BolometerFoil must be greater than zero.")

        if not isinstance(dy, (float, int)):
            raise TypeError("dy argument for BolometerFoil must be of type float/int.")
        if not dy > 0:
            raise ValueError("dy argument for BolometerFoil must be greater than zero.")

        if not isinstance(slit, BolometerSlit):
            raise TypeError("slit argument for BolometerFoil must be of type BolometerSlit.")

        if not isinstance(centre_point, Point3D):
            raise TypeError("centre_point argument for BolometerFoil must be of type Point3D.")

        if not isinstance(curvature_radius, (float, int)):
            raise TypeError("curvature_radius argument for BolometerFoil "
                            "must be of type float/int.")
        if curvature_radius < 0:
            raise ValueError("curvature_radius argument for BolometerFoil "
                             "must not be negative.")

        if not isinstance(basis_x, Vector3D):
            raise TypeError("The basis vectors of BolometerFoil must be of type Vector3D.")
        if not isinstance(basis_y, Vector3D):
            raise TypeError("The basis vectors of BolometerFoil must be of type Vector3D.")

        self._centre_point = centre_point
        self._basis_x = basis_x.normalise()
        self._basis_y = basis_y.normalise()
        self._normal_vec = self._basis_x.cross(self._basis_y)
        self._slit = slit
        self._foil_to_slit_vec = self._centre_point.vector_to(self._slit.centre_point).normalise()
        self._curvature_radius = curvature_radius
        self.units = units

        # setup root bolometer foil transform
        translation = translate(self._centre_point.x, self._centre_point.y, self._centre_point.z)
        rotation = rotate_basis(self._normal_vec, self._basis_y)

        if self.units == "Power":
            pipeline = PowerPipeline0D(accumulate=accumulate)
        elif self.units == "Radiance":
            pipeline = RadiancePipeline0D(accumulate=accumulate)
        else:
            raise ValueError("The units argument of BolometerFoil must be one of 'Power' or 'Radiance'.")

        super().__init__([slit.target], targetted_path_prob=1.0,
                         pipelines=[pipeline],
                         pixel_samples=1000, x_width=dx, y_width=dy, spectral_bins=1, quiet=True,
                         parent=parent, transform=translation * rotation, name=detector_id)

        # round off the detector corners, if applicable
        if self._curvature_radius > 0:
            mask_corners(self)
Exemplo n.º 22
0
def raytraced_etendue(distance, detector_radius=0.001, ray_count=100000, batches=10):

    # generate the transform to the detector position and orientation
    detector_transform = translate(0, 0, distance) * rotate_basis(Vector3D(0, 0, -1), Vector3D(0, -1, 0))

    # generate bounding sphere and convert to local coordinate system
    sphere = target.bounding_sphere()
    spheres = [(sphere.centre.transform(detector_transform), sphere.radius, 1.0)]

    # instance targetted pixel sampler
    targetted_sampler = TargettedHemisphereSampler(spheres)

    point_sampler = DiskSampler3D(detector_radius)

    detector_area = detector_radius**2 * np.pi
    solid_angle = 2 * np.pi
    etendue_sampled = solid_angle * detector_area

    etendues = []
    for i in range(batches):

        # sample pixel origins
        origins = point_sampler(samples=ray_count)

        passed = 0.0
        for origin in origins:

            # obtain targetted vector sample
            direction, pdf = targetted_sampler(origin, pdf=True)
            path_weight = R_2_PI * direction.z/pdf

            origin = origin.transform(detector_transform)
            direction = direction.transform(detector_transform)

            while True:

                # Find the next intersection point of the ray with the world
                intersection = world.hit(CoreRay(origin, direction))

                if intersection is None:
                    passed += 1 * path_weight
                    break

                elif isinstance(intersection.primitive.material, NullMaterial):
                    hit_point = intersection.hit_point.transform(intersection.primitive_to_world)
                    origin = hit_point + direction * 1E-9
                    continue

                else:
                    break

        if passed == 0:
            raise ValueError("Something is wrong with the scene-graph, calculated etendue should not zero.")

        etendue_fraction = passed / ray_count
        etendues.append(etendue_sampled * etendue_fraction)

    etendue = np.mean(etendues)
    etendue_error = np.std(etendues)

    return etendue, etendue_error
Exemplo n.º 23
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(
Exemplo n.º 24
0
def load_kb1_camera(parent=None):

    camera_id = 'KB1'

    # Transforms, read from KB1 CAD model for INDIVIDUAL_BOLOMETER_ASSEMBLY
    # Note that the rotation angle is positive when Axis is the Z axis, and
    # negative when Axis is the -Z axis
    camera_transforms = [
        translate(-1.73116, 2.59086, 3.31650) * rotate_z(123.75),
        translate(-3.05613, 0.60790, 3.31650) * rotate_z(168.75),
        translate(1.73116, -2.59086, 3.31650) * rotate_z(-56.25),
        translate(3.05613, -0.60790, 3.31650) * rotate_z(-11.25),
    ]
    # Transform for INDIVIDUAL_BOLOMETER_ASSEMBLY/SINGLE_BOLOMETER_ASSEMBLY/FOIL 1
    # in CAD model
    foil_camera_transform = translate(0, 0, 18.70e-3)
    # Foils point downwards towards the plasma
    foil_orientation_transform = rotate_basis(Vector3D(0, 0, -1),
                                              Vector3D(0, 1, 0))
    # Dimensions read from edge to edge (and adjacent vertices defining rounded corners) on
    # INDIVIDUAL_BOLOMETER_ASSEMBLY/SINGLE_BOLOMETER_ASSEMBLY/FOIL SUPPORT 1,
    # edges (and vertices) closest to the foil
    foil_width = 11e-3
    foil_height = 11e-3
    foil_curvature_radius = 1e-3

    # KB1 does not really have a slit, per-se. The vessel functions as the
    # aperture. To ensure a sufficiently displaced bounding sphere for the
    # TargettedPixel, we'll put a dummy slit at the exit of the port through
    # which the camera views. Note that with the camera transform defined above,
    # the y axis is in the toroidal direction and the x axis in the inward
    # radial direction.
    #
    # The foil is not centred on the centre of the port. To measure the
    # displacement, the centre of the port was read from the CAD model for
    # KB1-1, then the vector from the foil centre to the centre of the port exit
    # for this channel was calculated in the foil's local coordinate system.
    foil_slit_transform = translate(-0.05025, 0, 1.38658)
    slit_width = 0.25  # slightly larger than widest point of port (~225 mm)
    slit_height = 0.09  # sligtly larger than length of port (~73.84 mm)

    num_slits = len(camera_transforms)
    num_foils = len(camera_transforms)

    bolometer_camera = BolometerCamera(name=camera_id, parent=parent)

    slit_objects = {}
    for i in range(num_slits):
        slit_id = '{}_Slit_#{}'.format(camera_id, i + 1)
        slit_transform = (camera_transforms[i] * foil_orientation_transform *
                          foil_slit_transform * foil_camera_transform)
        centre_point = Point3D(0, 0, 0).transform(slit_transform)
        basis_x = Vector3D(1, 0, 0).transform(slit_transform)
        basis_y = Vector3D(0, 1, 0).transform(slit_transform)
        dx = slit_width
        dy = slit_height
        slit_objects[slit_id] = BolometerSlit(slit_id,
                                              centre_point,
                                              basis_x,
                                              dx,
                                              basis_y,
                                              dy,
                                              csg_aperture=True,
                                              parent=bolometer_camera)

    for i in range(num_foils):
        foil_id = '{}_CH{}_Foil'.format(camera_id, i + 1)
        slit_id = '{}_Slit_#{}'.format(camera_id, i + 1)
        foil_transform = (camera_transforms[i] * foil_orientation_transform *
                          foil_camera_transform)
        centre_point = Point3D(0, 0, 0).transform(foil_transform)
        basis_x = Vector3D(1, 0, 0).transform(foil_transform)
        basis_y = Vector3D(0, 1, 0).transform(foil_transform)
        dx = foil_width
        dy = foil_height
        rc = foil_curvature_radius
        foil = BolometerFoil(foil_id,
                             centre_point,
                             basis_x,
                             dx,
                             basis_y,
                             dy,
                             slit_objects[slit_id],
                             curvature_radius=rc,
                             parent=bolometer_camera)

        bolometer_camera.add_foil_detector(foil)

    return bolometer_camera
Exemplo n.º 25
0
import numpy as np
from mayavi import mlab
from raysect.core import translate, Point3D
from raysect.optical import World
from raysect.primitive import Sphere, Mesh
from raysect_mayavi.primitives import to_mesh
from raysect_mayavi.primitives.triangle import triangle3d_intersects_triangle3d


# OPERATION = 'UNION'
# OPERATION = 'INTERSECTION'
OPERATION = 'DIFFERENCE'


world = World()
s1 = Sphere(0.5, transform=translate(-0.25, 0, 0), name='s1')
s2 = Sphere(0.5, transform=translate(0.25, 0, 0), name='s2')


s1_vertices, s1_triangles = to_mesh(s1)
n_s1_vertices = s1_vertices.shape[0]
n_s1_triangles = s1_triangles.shape[0]
s1_mesh = Mesh(vertices=s1_vertices, triangles=s1_triangles, smoothing=False)
print()
print('n_s1_triangles', n_s1_triangles)

s2_vertices, s2_triangles = to_mesh(s2)
n_s2_vertices = s2_vertices.shape[0]
n_s2_triangles = s2_triangles.shape[0]
s2_mesh = Mesh(vertices=s2_vertices, triangles=s2_triangles, smoothing=False)
print('n_s2_triangles', n_s2_triangles)
Exemplo n.º 26
0
    def create_plasma(self, parent=None, transform=None, name=None):
        """
        Make a CHERAB plasma object from this SOLEGE2D simulation.

        :param Node parent: The plasma's parent node in the scenegraph, e.g. a World object.
        :param AffineMatrix3D transform: Affine matrix describing the location and orientation
        of the plasma in the world.
        :param str name: User friendly name for this plasma (default = "SOLEDGE2D Plasma").
        :rtype: Plasma
        """

        mesh = self.mesh
        name = name or "SOLEDGE2D Plasma"
        plasma = Plasma(parent=parent, transform=transform, name=name)
        radius = mesh.mesh_extent['maxr']
        height = mesh.mesh_extent['maxz'] - mesh.mesh_extent['minz']
        plasma.geometry = Cylinder(radius, height)
        plasma.geometry_transform = translate(0, 0, mesh.mesh_extent['minz'])

        tri_index_lookup = self.mesh.triangle_index_lookup
        tri_to_grid = self.mesh.triangle_to_grid_map

        if isinstance(self._b_field_vectors, np.ndarray):
            plasma.b_field = SOLEDGE2DVectorFunction3D(
                tri_index_lookup, tri_to_grid, self._b_field_vectors_cartesian)
        else:
            print(
                'Warning! No magnetic field data available for this simulation.'
            )

        # Create electron species
        triangle_data = _map_data_onto_triangles(self._electron_temperature)
        electron_te_interp = Discrete2DMesh(mesh.vertex_coords,
                                            mesh.triangles,
                                            triangle_data,
                                            limit=False)
        electron_temp = AxisymmetricMapper(electron_te_interp)
        triangle_data = _map_data_onto_triangles(self._electron_density)
        electron_ne_interp = Discrete2DMesh.instance(electron_te_interp,
                                                     triangle_data)
        electron_dens = AxisymmetricMapper(electron_ne_interp)
        electron_velocity = lambda x, y, z: Vector3D(0, 0, 0)
        plasma.electron_distribution = Maxwellian(electron_dens, electron_temp,
                                                  electron_velocity,
                                                  electron_mass)

        if not isinstance(self.velocities_cartesian, np.ndarray):
            print(
                'Warning! No velocity field data available for this simulation.'
            )

        b2_neutral_i = 0  # counter for B2 neutrals
        for k, sp in enumerate(self.species_list):

            # Identify the species based on its symbol
            symbol, charge = re.match(_SPECIES_REGEX, sp).groups()
            charge = int(charge)
            species_type = _species_symbol_map[symbol]

            # If neutral and B" atomic density available,  use B2 density, otherwise use fluid species density.
            if isinstance(self.b2_neutral_densities,
                          np.ndarray) and charge == 0:
                species_dens_data = self.b2_neutral_densities[:, :,
                                                              b2_neutral_i]
                b2_neutral_i += 1
            else:
                species_dens_data = self.species_density[:, :, k]

            triangle_data = _map_data_onto_triangles(species_dens_data)
            dens = AxisymmetricMapper(
                Discrete2DMesh.instance(electron_te_interp, triangle_data))
            # dens = SOLPSFunction3D(tri_index_lookup, tri_to_grid, species_dens_data)

            # Create the velocity vector lookup function
            if isinstance(self.velocities_cartesian, np.ndarray):
                velocity = SOLEDGE2DVectorFunction3D(
                    tri_index_lookup, tri_to_grid,
                    self.velocities_cartesian[:, :, k, :])
            else:
                velocity = lambda x, y, z: Vector3D(0, 0, 0)

            distribution = Maxwellian(dens, electron_temp, velocity,
                                      species_type.atomic_weight * atomic_mass)
            plasma.composition.add(Species(species_type, charge, distribution))

        return plasma
Exemplo n.º 27
0
    triangle_data = {'PowerDensity': power_density, 'PowerDensityError': error}
    export_vtk(mesh, basename + '.vtk', triangle_data=triangle_data)


samples = 1000000

sphere_radius = 0.01

min_wl = 400
max_wl = 401


# set-up scenegraph
world = World()
emitter = Sphere(radius=sphere_radius, parent=world, transform=rotate_x(-90)*translate(-0.05409, -0.01264, 0.10064))


base_path = os.path.split(os.path.realpath(__file__))[0]
mesh = import_obj(os.path.join(base_path, "../resources/stanford_bunny.obj"),
                  material=AbsorbingSurface(), parent=world, flip_normals=True)


power = PowerPipeline0D(accumulate=False)
observer = MeshPixel(mesh, pipelines=[power], parent=world,
                     min_wavelength=min_wl, max_wavelength=max_wl,
                     spectral_bins=1, pixel_samples=samples, surface_offset=1E-6)


print("Starting observations with volume emitter...")
calculated_volume_emission = 16 / 3 * pi**2 * sphere_radius**3 * (max_wl - min_wl)
Exemplo n.º 28
0
if fibre_distance <= sphere_radius:
    raise ValueError("The fibre must be outside the sphere.")
cone_radius_on_axis = np.tan(np.deg2rad(fibre_half_angle)) * fibre_distance
if cone_radius_on_axis <= sphere_radius + fibre_radius:
    raise ValueError("The fibre's acceptance angle must be large enough to see all of the sphere's radiance.")

# set-up scenegraph
world = World()
emitter = Sphere(radius=sphere_radius, parent=world, material=UnityVolumeEmitter())

# The observer plane covers 1 side of a cube - to work out total power, multiply result by 6
fibre_power = PowerPipeline0D(accumulate=False)
optical_fibre = FibreOptic([fibre_power], acceptance_angle=fibre_half_angle, radius=fibre_radius,
                           min_wavelength=min_wl, max_wavelength=max_wl,
                           spectral_bins=1, pixel_samples=samples,
                           parent=world, transform=rotate(0, 0, 0)*translate(0, 0, -fibre_distance))


approximate_fraction_of_sphere = np.pi*fibre_radius**2 / (4 * np.pi * fibre_distance**2)


# Emitter is a sphere volume emitter located at the origin
# Volume of the sphere is 4/3 * Pi * r^3, emission over 4 * pi
# UnityVolumeEmitter emits 1W/str/m^3/ x nm, where x is the wavelength interval, integrated over length

print("Starting observations with volume emitter...")
calculated_volume_emission = 16 / 3 * pi**2 * sphere_radius**3 * (max_wl - min_wl)


optical_fibre.observe()
measured_volume_emission = fibre_power.value.mean / approximate_fraction_of_sphere
Exemplo n.º 29
0
import vtk
from raysect.core import translate
from raysect_vtk.utility import convert_to_vtk_transform


sphereSource1 = vtk.vtkSphereSource()
sphereSource1.SetPhiResolution(50)
sphereSource1.SetThetaResolution(50)
sphereSource1.Update()
transform_filter1 = vtk.vtkTransformPolyDataFilter()
transform_filter1.SetInputConnection(sphereSource1.GetOutputPort())
transform_filter1.SetTransform(convert_to_vtk_transform(translate(0.25, 0, 0)))
transform_filter1.Update()
sphere1Tri = vtk.vtkTriangleFilter()
sphere1Tri.SetInputData(transform_filter1.GetOutput())

sphereSource2 = vtk.vtkSphereSource()
sphereSource2.SetPhiResolution(50)
sphereSource2.SetThetaResolution(50)
sphereSource2.Update()
transform_filter2 = vtk.vtkTransformPolyDataFilter()
transform_filter2.SetInputConnection(sphereSource2.GetOutputPort())
transform_filter2.SetTransform(convert_to_vtk_transform(translate(-0.25, 0, 0)))
transform_filter2.Update()
sphere2Tri = vtk.vtkTriangleFilter()
sphere2Tri.SetInputData(transform_filter2.GetOutput())


booleanOperation1 = vtk.vtkBooleanOperationPolyDataFilter()
booleanOperation1.SetOperationToIntersection()
Exemplo n.º 30
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
Exemplo n.º 31
0
from raysect.optical import World
from raysect.optical.observer import PinholeCamera, SightLine, PowerPipeline0D, SpectralPowerPipeline0D

from cherab.core.atomic import lithium, Line
from cherab.tools.plasmas.slab import build_slab_plasma

from renate.cherab_models import RenateBeamEmissionLine, RenateBeam

world = World()

# PLASMA ----------------------------------------------------------------------
plasma = build_slab_plasma(peak_density=5e19, world=world)

# BEAM SETUP ------------------------------------------------------------------
integration_step = 0.0025
beam_transform = translate(-0.5, 0.0, 0) * rotate_basis(
    Vector3D(1, 0, 0), Vector3D(0, 0, 1))
line = Line(lithium, 0, ('2p', '2s'))

beam = RenateBeam(parent=world, transform=beam_transform)
beam.plasma = plasma
beam.energy = 60000
beam.power = 1e5
beam.element = lithium
beam.temperature = 30
beam.sigma = 0.03
beam.divergence_x = 0.5
beam.divergence_y = 0.5
beam.length = 3.0
beam.models = [RenateBeamEmissionLine(line)]
beam.integrator.step = integration_step
Exemplo n.º 32
0
def raytraced_etendue(distance,
                      detector_radius=0.001,
                      ray_count=100000,
                      batches=10):

    # generate the transform to the detector position and orientation
    detector_transform = translate(0, 0, distance) * rotate_basis(
        Vector3D(0, 0, -1), Vector3D(0, -1, 0))

    # generate bounding sphere and convert to local coordinate system
    sphere = target.bounding_sphere()
    spheres = [(sphere.centre.transform(detector_transform), sphere.radius,
                1.0)]

    # instance targetted pixel sampler
    targetted_sampler = TargettedHemisphereSampler(spheres)

    point_sampler = DiskSampler3D(detector_radius)

    detector_area = detector_radius**2 * np.pi
    solid_angle = 2 * np.pi
    etendue_sampled = solid_angle * detector_area

    etendues = []
    for i in range(batches):

        # sample pixel origins
        origins = point_sampler(samples=ray_count)

        passed = 0.0
        for origin in origins:

            # obtain targetted vector sample
            direction, pdf = targetted_sampler(origin, pdf=True)
            path_weight = R_2_PI * direction.z / pdf

            origin = origin.transform(detector_transform)
            direction = direction.transform(detector_transform)

            while True:

                # Find the next intersection point of the ray with the world
                intersection = world.hit(CoreRay(origin, direction))

                if intersection is None:
                    passed += 1 * path_weight
                    break

                elif isinstance(intersection.primitive.material, NullMaterial):
                    hit_point = intersection.hit_point.transform(
                        intersection.primitive_to_world)
                    origin = hit_point + direction * 1E-9
                    continue

                else:
                    break

        if passed == 0:
            raise ValueError(
                "Something is wrong with the scene-graph, calculated etendue should not zero."
            )

        etendue_fraction = passed / ray_count
        etendues.append(etendue_sampled * etendue_fraction)

    etendue = np.mean(etendues)
    etendue_error = np.std(etendues)

    return etendue, etendue_error
Exemplo n.º 33
0
diameter = 1
center_thickness = 0.5
front_curvature = 2
back_curvature = 2

biconvex_lens = BiConvex(diameter,
                         center_thickness,
                         front_curvature,
                         back_curvature,
                         parent=world)
biconcave_lens = BiConcave(diameter,
                           center_thickness,
                           front_curvature,
                           back_curvature,
                           parent=world,
                           transform=translate(0, 0, 1))
planoconvex_lens = PlanoConvex(diameter,
                               center_thickness,
                               front_curvature,
                               parent=world,
                               transform=translate(0, 0, 2))
planoconcave_lens = PlanoConcave(diameter,
                                 center_thickness,
                                 front_curvature,
                                 parent=world,
                                 transform=translate(0, 0, 3))
meniscus_lens = Meniscus(diameter,
                         center_thickness,
                         front_curvature,
                         back_curvature,
                         parent=world,
Exemplo n.º 34
0
# set-up scenegraph
world = World()
emitter = Sphere(radius=sphere_radius, parent=world)

# The observer plane covers 1 side of a cube - to work out total power, multiply result by 6
power = PowerPipeline0D(accumulate=False)
observing_plane = Pixel([power],
                        x_width=cube_size,
                        y_width=cube_size,
                        min_wavelength=min_wl,
                        max_wavelength=max_wl,
                        spectral_bins=1,
                        pixel_samples=samples,
                        parent=world,
                        transform=rotate(0, 0, 0) *
                        translate(0, 0, -cube_size / 2))

# Emitter is a sphere volume emitter located at the origin
# Volume of the sphere is 4/3 * Pi * r^3, emission over 4 * pi
# UnityVolumeEmitter emits 1W/str/m^3/ x nm, where x is the wavelength interval, integrated over length

print("Starting observations with volume emitter...")
calculated_volume_emission = 16 / 3 * pi**2 * sphere_radius**3 * (max_wl -
                                                                  min_wl)

emitter.material = UnityVolumeEmitter()
observing_plane.observe()
measured_volume_emission = 6 * power.value.mean
measured_volume_error = 6 * power.value.error()

# Emitter is a sphere surface emitter located at the origin
Exemplo n.º 35
0
from cherab.tools.plasmas.slab import build_slab_plasma

from renate.cherab_models import RenateBeamEmissionLine, RenateBeam


world = World()


# PLASMA ----------------------------------------------------------------------
plasma = build_slab_plasma(peak_density=5e19, world=world)
plasma.b_field = ConstantVector3D(Vector3D(0, 0.6, 0))


# BEAM SETUP ------------------------------------------------------------------
integration_step = 0.0025
beam_transform = translate(-0.5, 0.0, 0) * rotate_basis(Vector3D(1, 0, 0), Vector3D(0, 0, 1))
line = Line(hydrogen, 0, (3, 2))

beam = RenateBeam(parent=world, transform=beam_transform)
beam.plasma = plasma
beam.energy = 100000
beam.power = 3e6
beam.element = hydrogen
beam.temperature = 30
beam.sigma = 0.05
beam.divergence_x = 0.
beam.divergence_y = 0.
beam.length = 3.0
beam.models = [RenateBeamEmissionLine(line)]
beam.integrator.step = integration_step
beam.integrator.min_samples = 10