def equilateral_prism(width=1.0, height=1.0, parent=None, transform=None, material=None): half_width = width / 2 mid_point = half_width * tan(60 / 180 * pi) / 2 centre = Box(Point3D(-half_width * 1.001, 0, 0), Point3D(half_width * 1.001, height, width)) left = Box(Point3D(0, -height * 0.001, -width * 0.001), Point3D(width, height * 1.001, 2 * width), transform=translate(half_width, 0, 0) * rotate(30, 0, 0)) right = Box(Point3D(-width, -height * 0.001, -width * 0.001), Point3D(0.0, height * 1.001, 2 * width), transform=translate(-half_width, 0, 0) * rotate(-30, 0, 0)) csg_prism = Subtract(Subtract(centre, left), right, parent=parent, transform=transform * translate(0, 0, -mid_point), material=material) return csg_prism
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
def light_box(parent, transform=None): # Notice that this function is creating and returning a parent node which holds references # to the underlying primitives. node = Node(parent=parent, transform=transform) outer = Box(Point3D(-0.01, 0, -0.05), Point3D(0.01, 0.15, 0.0)) slit = Box(Point3D(-0.0015, 0.03, -0.045), Point3D(0.0015, 0.12, 0.0001)) Subtract(outer, slit, parent=node, material=Lambert(reflectivity=ConstantSF(0.1))) Box(Point3D(-0.0015, 0.03, -0.045), Point3D(0.0015, 0.12, -0.04), parent=node, material=UniformSurfaceEmitter(d65_white, 250)) return node
def __init__(self, radius_outer, height, n_radius, n_height, radius_inner=0, n_polar=0, period=360., step=None, voxel_map=None, mask=None, parent=None, transform=None): grid_shape = (n_radius, n_polar, n_height) if n_polar else (n_radius, n_height) if n_polar: if not 0 < period <= 360.: raise ValueError('period must be > 0 and <= 360') dr = (radius_outer - radius_inner) / n_radius dz = height / n_height dphi = period / n_polar if n_polar else 0 grid_steps = (dr, dphi, dz) if n_polar else (dr, dz) eps_r = 1.e-5 * dr eps_z = 1.e-5 * dz step = step or 0.1 * min(dr, dz) material = CylindricalRayTransferEmitter(grid_shape, grid_steps, mask=mask, voxel_map=voxel_map, integrator=CylindricalRayTransferIntegrator(step), rmin=radius_inner, period=period) primitive = Subtract(Cylinder(radius_outer - eps_r, height - eps_z), Cylinder(radius_inner + eps_r, height - eps_z), material=material, parent=parent, transform=transform) super().__init__(primitive)
def test_evaluate_function_2d(self): """ Unlike test_integration_2d() in TestRayTransferCylinder here we test how CylindricalRayTransferEmitter works with NumericalIntegrator in axysimmetric case. Testing against ToroidalVoxelGrid. """ world = World() material = CylindricalRayTransferEmitter( (2, 2), (1., 1.), rmin=2., integrator=NumericalIntegrator(0.0001)) primitive = Subtract(Cylinder(3.999999, 1.999999), Cylinder(2.0, 1.999999), material=material, parent=world) ray = Ray(origin=Point3D(4., 1., 2.), direction=Vector3D(-4., -1., -2.) / np.sqrt(21.), min_wavelength=500., max_wavelength=501., bins=4) spectrum = ray.trace(world) world = World() vertices = [] for rv in [2., 3.]: for zv in [0., 1.]: vertices.append([ Point2D(rv, zv + 1.), Point2D(rv + 1., zv + 1.), Point2D(rv + 1., zv), Point2D(rv, zv) ]) tvg = ToroidalVoxelGrid(vertices, parent=world, primitive_type='csg', active='all') tvg.set_active('all') spectrum_test = ray.trace(world) self.assertTrue( np.allclose(spectrum_test.samples, spectrum.samples, atol=0.001))
def test_evaluate_function_3d(self): """ Unlike test_integration_3d() in TestRayTransferCylinder here we test how CylindricalRayTransferEmitter works with NumericalIntegrator in 3D case. """ world = World() material = CylindricalRayTransferEmitter( (2, 3, 2), (1., 30., 1.), period=90., integrator=NumericalIntegrator(0.0001)) primitive = Subtract(Cylinder(1.999999, 1.999999), Cylinder(0.000001, 1.999999), material=material, parent=world) ray = Ray(origin=Point3D(np.sqrt(2.), np.sqrt(2.), 2.), direction=Vector3D(-1., -1., -np.sqrt(2.)) / 2., min_wavelength=500., max_wavelength=501., bins=12) spectrum = ray.trace(world) spectrum_test = np.zeros(12) spectrum_test[2] = spectrum_test[9] = np.sqrt(2.) self.assertTrue( np.allclose(spectrum_test, spectrum.samples, atol=0.001))
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
enclosure_thickness = 0.001 + padding glass_thickness = 0.003 light_box = Node(parent=world) enclosure_outer = Box( Point3D(-0.10 - enclosure_thickness, -0.02 - enclosure_thickness, -0.10 - enclosure_thickness), Point3D(0.10 + enclosure_thickness, 0.0, 0.10 + enclosure_thickness)) enclosure_inner = Box( Point3D(-0.10 - padding, -0.02 - padding, -0.10 - padding), Point3D(0.10 + padding, 0.001, 0.10 + padding)) enclosure = Subtract(enclosure_outer, enclosure_inner, material=Lambert(ConstantSF(0.2)), parent=light_box) glass_outer = Box(Point3D(-0.10, -0.02, -0.10), Point3D(0.10, 0.0, 0.10)) glass_inner = Box( Point3D(-0.10 + glass_thickness, -0.02 + glass_thickness, -0.10 + glass_thickness), Point3D(0.10 - glass_thickness, 0.0 - glass_thickness, 0.10 - glass_thickness)) glass = Subtract(glass_outer, glass_inner, material=schott("N-BK7"), parent=light_box)
Point3D(1000, 0, 1000), parent=world, material=Lambert()) # construct prism from utility method prism = equilateral_prism(0.06, 0.15, parent=world, material=schott("SF11"), transform=translate(0, 0.0 + 1e-6, -0.01)) # Curved target screen for collecting rainbow light stand = Intersect( Box(Point3D(-10, -10, -10), Point3D(10, 10, 0)), Subtract(Cylinder(0.21, 0.15), Cylinder(0.20, 0.16, transform=translate(0, 0, -0.005)), transform=rotate(0, 90, 0)), transform=translate(0.0, 1e-6, 0.0), parent=world, material=schott("N-BK7") # RoughIron(0.25) ) surface = Intersect(Box(Point3D(-10, -10, -10), Point3D(10, 10, -0.015)), Subtract(Cylinder(0.1999, 0.12, transform=translate(0, 0, 0.015)), Cylinder(0.1998, 0.13, transform=translate(0, 0, 0.010)), transform=rotate(0, 90, 0)), parent=stand,
# construct diffuse floor surface floor = Box(Point3D(-1000, -0.1, -1000), Point3D(1000, 0, 1000), parent=world, material=Lambert()) # construct prism from utility method prism = equilateral_prism(0.06, 0.15, parent=world, material=schott("SF11"), transform=translate(0, 0.0 + 1e-6, 0)) # Curved target screen for collecting rainbow light screen = Intersect( Box(Point3D(-10, -10, -10), Point3D(10, 10, 0)), Subtract(Cylinder(0.22, 0.15), Cylinder(0.20, 0.16, transform=translate(0, 0, -0.005)), transform=rotate(0, 90, 0)), parent=world, material=Lambert() ) # construct main collimated light source prism_light = light_box(parent=world, transform=rotate(-35.5, 0, 0) * translate(0.10, 0, 0) * rotate(90, 0, 0)) # background light source top_light = Sphere(0.5, parent=world, transform=translate(0, 2, -1), material=UniformSurfaceEmitter(d65_white, scale=2))
green_glass = Dielectric(index=Sellmeier(1.03961212, 0.231792344, 1.01046945, 6.00069867e-3, 2.00179144e-2, 1.03560653e2), transmission=InterpolatedSF([300, 490, 510, 590, 610, 800], array([0.0, 0.0, 1.0, 1.0, 0.0, 0.0])*0.7)) blue_glass = Dielectric(index=Sellmeier(1.03961212, 0.231792344, 1.01046945, 6.00069867e-3, 2.00179144e-2, 1.03560653e2), transmission=InterpolatedSF([300, 490, 510, 590, 610, 800], array([1.0, 1.0, 0.0, 0.0, 0.0, 0.0])*0.7)) world = World() cyl_x = Cylinder(1, 4.2, transform=rotate(90, 0, 0)*translate(0, 0, -2.1)) cyl_y = Cylinder(1, 4.2, transform=rotate(0, 90, 0)*translate(0, 0, -2.1)) cyl_z = Cylinder(1, 4.2, transform=rotate(0, 0, 0)*translate(0, 0, -2.1)) cube = Box(Point3D(-1.5, -1.5, -1.5), Point3D(1.5, 1.5, 1.5)) sphere = Sphere(2.0) Intersect(sphere, Subtract(cube, Union(Union(cyl_x, cyl_y), cyl_z)), world, translate(-2.1,2.1,2.5)*rotate(30, -20, 0), schott("N-LAK9")) Intersect(sphere, Subtract(cube, Union(Union(cyl_x, cyl_y), cyl_z)), world, translate(2.1,2.1,2.5)*rotate(-30, -20, 0), schott("SF6")) Intersect(sphere, Subtract(cube, Union(Union(cyl_x, cyl_y), cyl_z)), world, translate(2.1,-2.1,2.5)*rotate(-30, 20, 0), schott("LF5G19")) Intersect(sphere, Subtract(cube, Union(Union(cyl_x, cyl_y), cyl_z)), world, translate(-2.1,-2.1,2.5)*rotate(30, 20, 0), schott("N-BK7")) s1 = Sphere(1.0, transform=translate(0, 0, 1.0-0.01)) s2 = Sphere(0.5, transform=translate(0, 0, -0.5+0.01)) Intersect(s1, s2, world, translate(0,0,-3.6)*rotate(50,50,0), schott("N-BK7")) Box(Point3D(-50, -50, 50), Point3D(50, 50, 50.1), world, material=Checkerboard(4, d65_white, d65_white, 0.4, 0.8)) Box(Point3D(-100, -100, -100), Point3D(100, 100, 100), world, material=UniformSurfaceEmitter(d65_white, 0.1)) ion() # create and setup the camera rgb = RGBPipeline2D()
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...') ######################################################################################################################## # Cubes b1 = Box(Point3D(0, 0, 0), Point3D(1, 1, 1)) b2 = Box(Point3D(0, 0, 0), Point3D(1, 1, 1), transform=translate(0.6, 0.6, 0.6)) world = World() Union(b1, b2, parent=world) visualise_scenegraph(world) input('pause...')
transform=translate(0, 4, -3.5) * rotate(0, -48, 180)) # b = BiConvex(0.0508, 0.0036, 1.0295, 1.0295, parent=camera, transform=translate(0, 0, 0.1), material=schott("N-BK7")) # b = BiConvex(0.0508, 0.0062, 0.205, 0.205, parent=camera, transform=translate(0, 0, 0.05), material=schott("N-BK7")) lens = BiConvex(0.0508, 0.0144, 0.0593, 0.0593, parent=camera, transform=translate(0, 0, 0.0536), material=schott("N-BK7")) body = Subtract(Subtract( Cylinder(0.0260, 0.07, transform=translate(0, 0, 0)), Cylinder(0.0255, 0.06, transform=translate(0, 0, 0.005))), Cylinder(0.015, 0.007, transform=translate(0, 0, 0.064)), parent=camera, transform=translate(0, 0, -0.01), material=AbsorbingSurface()) aperture = Cylinder(0.016, 0.0009, parent=camera, transform=translate(0, 0, 0.064), material=NullMaterial()) rgb = RGBPipeline2D(display_unsaturated_fraction=0.98, name="sRGB") bayer = BayerPipeline2D(ciexyz_x, ciexyz_y, ciexyz_z, display_unsaturated_fraction=0.98,
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
import numpy as np from matplotlib import pyplot as plt from raysect.primitive import Cylinder, Subtract from raysect.optical import World, translate, rotate from raysect.optical.observer import PinholeCamera, FullFrameSampler2D from cherab.tools.raytransfer import RayTransferPipeline2D, RayTransferCylinder from cherab.tools.raytransfer import RoughNickel world = World() # creating the scene cylinder_inner = Cylinder(radius=80., height=140.) cylinder_outer = Cylinder(radius=220., height=140.) wall = Subtract(cylinder_outer, cylinder_inner, material=RoughNickel(0.1), parent=world, transform=translate(0, 0, -70.)) # creating ray transfer cylinder with 200 (m) outer radius, 100 (m) inner radius, 140 (m) height # for axisymmetric cylindrical emission profile defined on a 100 x 100 (R, Z) gird rtc = RayTransferCylinder(200., 100., 100, 100, radius_inner=100.) # n_polar=0 by default (axisymmetric case) rtc.parent = world rtc.transform = translate(0, 0, -50.) # unlike the demo with a mask, here we not only cut out a circle but also # create 50 ring-shaped light sources using the voxel map rad_circle = 50. xsqr = np.linspace(-49.5, 49.5, 100) ** 2 rad = np.sqrt(xsqr[:, None] + xsqr[None, :]) voxel_map = np.zeros((100, 100), dtype=np.int) voxel_map[rad > 50.] = -1 # removing the area outside the circle
blue_glass = Dielectric( index=Sellmeier(1.03961212, 0.231792344, 1.01046945, 6.00069867e-3, 2.00179144e-2, 1.03560653e2), transmission=InterpolatedSF([300, 490, 510, 590, 610, 800], array([1.0, 1.0, 0.0, 0.0, 0.0, 0.0]) * 0.7)) world = World() cyl_x = Cylinder(1, 4.2, transform=rotate(90, 0, 0) * translate(0, 0, -2.1)) cyl_y = Cylinder(1, 4.2, transform=rotate(0, 90, 0) * translate(0, 0, -2.1)) cyl_z = Cylinder(1, 4.2, transform=rotate(0, 0, 0) * translate(0, 0, -2.1)) cube = Box(Point3D(-1.5, -1.5, -1.5), Point3D(1.5, 1.5, 1.5)) sphere = Sphere(2.0) Intersect(sphere, Subtract(cube, Union(Union(cyl_x, cyl_y), cyl_z)), world, translate(-2.1, 2.1, 2.5) * rotate(30, -20, 0), schott("N-LAK9")) Intersect(sphere, Subtract(cube, Union(Union(cyl_x, cyl_y), cyl_z)), world, translate(2.1, 2.1, 2.5) * rotate(-30, -20, 0), schott("SF6")) Intersect(sphere, Subtract(cube, Union(Union(cyl_x, cyl_y), cyl_z)), world, translate(2.1, -2.1, 2.5) * rotate(-30, 20, 0), schott("LF5G19")) Intersect(sphere, Subtract(cube, Union(Union(cyl_x, cyl_y), cyl_z)), world, translate(-2.1, -2.1, 2.5) * rotate(30, 20, 0), schott("N-BK7")) s1 = Sphere(1.0, transform=translate(0, 0, 1.0 - 0.01)) s2 = Sphere(0.5, transform=translate(0, 0, -0.5 + 0.01)) Intersect(s1, s2, world, translate(0, 0, -3.6) * rotate(50, 50, 0), schott("N-BK7")) Box(Point3D(-50, -50, 50), Point3D(50, 50, 50.1),
mm(20.4942), parent=l2, transform=translate(0, 0, mm(-7.949)), material=schott("N-LAK9")) image_plane = Node(parent=l3, transform=translate(0, 0, mm( -41.5))) # tweaked position gives a sharper image (original: 41.10346 mm) # disable importance sampling of the lenses (enabled by default for dielectrics and emitters) l1.material.importance = 0.0 l2.material.importance = 0.0 l3.material.importance = 0.0 # cylinder body holding the lenses and CCD body = Subtract(Cylinder(mm(26), mm(80.0), transform=translate(0, 0, mm(-63))), Cylinder(mm(25), mm(79.1), transform=translate(0, 0, mm(-62))), parent=camera, transform=translate(0, 0, 0), material=AbsorbingSurface()) # L1 lens mount l1_mount = Subtract(Cylinder(mm(25.5), mm(5.0), transform=translate(0, 0, mm(0))), Cylinder(mm(21 / 2 + 0.01), mm(5.1), transform=translate(0, 0, mm(-0.05))), parent=l1, transform=translate(0, 0, mm(0)), material=AbsorbingSurface()) # L2 lens mount