Example #1
0
 def test_intersection(self):
     root = Node(name='Root')
     a = Node(name="A", parent=root)
     b = Node(name="B", parent=a)
     b.geometry = Sphere(radius=1.0)
     a.translate((1.0, 0.0, 0.0))
     loc = (-2.0, 0.0, 0.0)
     vec = (1.0, 0.0, 0.0)
     scene = Scene(root=root)
     intersections = scene.intersections(loc, vec)
     points = tuple([x.point for x in intersections])
     # In frame of a everything is shifed 1 along x
     assert points == ((0.0, 0.0, 0.0), (2.0, 0.0, 0.0))
Example #2
0
 def test_intersection(self):
     root = Node(name='Root')
     a = Node(name="A", parent=root)
     b = Node(name="B", parent=a)
     b.geometry = Sphere(radius=1.0)
     a.translate((1.0, 0.0, 0.0))
     loc = (-2.0, 0.0, 0.0)
     vec = (1.0, 0.0, 0.0)
     scene = Scene(root=root)
     intersections = scene.intersections(loc, vec)
     points = tuple([x.point for x in intersections])
     # In frame of a everything is shifed 1 along x
     assert points == ((0.0, 0.0, 0.0), (2.0, 0.0, 0.0))
Example #3
0
 def test_intersection_with_rotation_around_z(self):
     root = Node(name='Root')
     a = Node(name="A", parent=root)
     b = Node(name="B", parent=a)
     b.geometry = Sphere(radius=1.0)
     a.translate((1.0, 0.0, 0.0))
     # This rotation make an z translation in b becomes a -y translation in a
     a.rotate(np.pi / 2, axis=(0.0, 0.0, 1.0))
     loc = (-2.0, 0.0, 0.0)
     vec = (1.0, 0.0, 0.0)
     scene = Scene(root=root)
     intersections = scene.intersections(loc, vec)
     points = tuple([x.point for x in intersections])
     assert np.allclose(points, ((0.0, 0.0, 0.0), (2.0, 0.0, 0.0)))
Example #4
0
 def test_intersection_with_rotation_around_x(self):
     root = Node(name='Root')
     a = Node(name="A", parent=root)
     b = Node(name="B", parent=a)
     b.geometry = Sphere(radius=1.0)
     b.translate((1.0, 0.0, 0.0))
     # Rotation around x therefore no displace in x
     b.rotate(np.pi / 2, (1.0, 0.0, 0.0))
     loc = (-2.0, 0.0, 0.0)
     vec = (1.0, 0.0, 0.0)
     scene = Scene(root=root)
     intersections = scene.intersections(loc, vec)
     points = tuple([x.point for x in intersections])
     assert points == ((0.0, 0.0, 0.0), (2.0, 0.0, 0.0))
Example #5
0
 def test_intersection_with_rotation_around_z(self):
     root = Node(name='Root')
     a = Node(name="A", parent=root)
     b = Node(name="B", parent=a)
     b.geometry = Sphere(radius=1.0)
     a.translate((1.0, 0.0, 0.0))
     # This rotation make an z translation in b becomes a -y translation in a
     a.rotate(np.pi/2, axis=(0.0, 0.0, 1.0))
     loc = (-2.0, 0.0, 0.0)
     vec = (1.0, 0.0, 0.0)
     scene = Scene(root=root)
     intersections = scene.intersections(loc, vec)
     points = tuple([x.point for x in intersections])
     assert np.allclose(points, ((0.0, 0.0, 0.0), (2.0, 0.0, 0.0)))
Example #6
0
 def test_intersection_with_rotation_around_x(self):
     root = Node(name='Root')
     a = Node(name="A", parent=root)
     b = Node(name="B", parent=a)
     b.geometry = Sphere(radius=1.0)
     b.translate((1.0, 0.0, 0.0))
     # Rotation around x therefore no displace in x
     b.rotate(np.pi/2, (1.0, 0.0, 0.0))
     loc = (-2.0, 0.0, 0.0)
     vec = (1.0, 0.0, 0.0)
     scene = Scene(root=root)
     intersections = scene.intersections(loc, vec)
     points = tuple([x.point for x in intersections])
     assert points == ((0.0, 0.0, 0.0), (2.0, 0.0, 0.0))
Example #7
0
 def test_intersection_coordinate_system(self):
     root = Node(name="Root", geometry=Sphere(radius=10.0))
     a = Node(name="A", parent=root, geometry=Sphere(radius=1.0))
     a.translate((1.0, 0.0, 0.0))
     scene = Scene(root)
     initial_ray = Ray(
         position=(-2.0, 0.0, 0.0),
         direction=(1.0, 0.0, 0.0),
         wavelength=None,
         is_alive=True,
     )
     scene_intersections = scene.intersections(initial_ray.position,
                                               initial_ray.direction)
     a_intersections = tuple(map(lambda x: x.to(root), scene_intersections))
     assert scene_intersections == a_intersections
Example #8
0
def follow(ray: Ray, scene: Scene, max_iters=1000, renderer=None) -> [Tuple[Ray, Decision]]:
    """ Follow the ray through a scene.
    
        This the highest level ray-tracing function. It moves the ray through the
        scene and returns a list of rays a Monte Carlo decision events. Each decision
        is an interaction which alters one of the rays properties such as position, 
        direction or wavelength.

        Raises
        ------
        TraceError
            If an error occurred while tracing.

        Returns
        -------
        List of (Ray, Decision) tuples.
    
    """
    path = [(ray, Decision.EMIT)]
    idx = 0
    last_ray = ray
    while ray.is_alive:
        intersections = scene.intersections(ray.position, ray.direction)
        points, nodes = zip(*[(x.point, x.hit) for x in intersections])
        for ray, decision in step(ray, points, nodes, renderer=renderer):
            path.append((ray, decision))
        if points_equal(ray.position, last_ray.position) and np.allclose(ray.direction, last_ray.direction):
            raise TraceError("Ray did not move.")
        last_ray = ray
        if idx > max_iters:
            raise TraceError("Ray got stuck.")
    return path
Example #9
0
 def test_intersection_coordinate_system(self):
     root = Node(name="Root", geometry=Sphere(radius=10.0))
     a = Node(name="A", parent=root, geometry=Sphere(radius=1.0))
     a.translate((1.0, 0.0, 0.0))
     scene = Scene(root)
     initial_ray = Ray(
         position=(-2.0, 0.0, 0.0),
         direction=(1.0, 0.0, 0.0),
         wavelength=None,
         is_alive=True,
     )
     scene_intersections = scene.intersections(
         initial_ray.position,
         initial_ray.direction
     )
     a_intersections = tuple(map(lambda x: x.to(root), scene_intersections))
     assert scene_intersections == a_intersections
 def test_basic_scene(self):
     a = Node(name="A", parent=None)
     b = Node(name="B", parent=a)
     b.geometry = Sphere(radius=1.0)
     b.translate((2.0, 0.0, 0.0))
     s = Scene(root=a)
     r = MeshcatRenderer()
     r.render(s)
     time.sleep(0.5)
     r.remove(s)
def make_touching_scene(n1=1.5, n2=1.5, n3=1.5):
    world = Node(
        name="world (air)",
        geometry=Sphere(
            radius=10.0,
            material=Dielectric.air()
        )
    )
    box1 = Node(
        name="box one (glass)",
        geometry=Box(
            (1.0, 1.0, 1.0),
            material=Dielectric.make_constant(
                x_range=(300.0, 4000.0), refractive_index=n1
            )
        ),
        parent=world
    )
    box2 = Node(
        name="box two (glass)",
        geometry=Box(
            (1.0, 1.0, 1.0),
            material=Dielectric.make_constant(
                x_range=(300.0, 4000.0), refractive_index=n2
            )
        ),
        parent=world
    )
    box2.translate((0.0, 0.0, 1.0))
    box3 = Node(
        name="box three (glass)",
        geometry=Box(
            (1.0, 1.0, 1.0),
            material=Dielectric.make_constant(
                x_range=(300.0, 4000.0), refractive_index=n3
            )
        ),
        parent=world
    )
    box3.translate((0.0, 0.0, 2.0))
    scene = Scene(world)
    return scene, world, box1, box2, box3
def make_embedded_scene(n1=1.5):
    world = Node(
        name="world (air)",
        geometry=Sphere(
            radius=10.0,
            material=Dielectric.air()
        )
    )
    box = Node(
        name="box (glass)",
        geometry=Box(
            (1.0, 1.0, 1.0),
            material=Dielectric.make_constant(
                x_range=(300.0, 4000.0), refractive_index=n1
            )
        ),
        parent=world
    )
    scene = Scene(world)
    return scene, world, box
def make_embedded_lumophore_scene(n1=1.5):
    world = Node(
        name="world (air)",
        geometry=Sphere(
            radius=10.0,
            material=Dielectric.air()
        )
    )
    box = Node(
        name="box (lumophore)",
        geometry=Box(
            (1.0, 1.0, 1.0),
            material=Lumophore.make_lumogen_f_red(
                x=np.linspace(300.0, 4000.0),
                absorption_coefficient=10.0,
                quantum_yield=1.0
            )
        ),
        parent=world
    )
    scene = Scene(world)
    return scene, world, box
Example #14
0
cylinder = Node(name="cylinder (glass)",
                geometry=Cylinder(length=1.0,
                                  radius=1.0,
                                  material=Dielectric.glass()),
                parent=world)

# A light source with 60-deg divergence
light = Node(name="light (555nm laser)",
             light=Light(divergence_delegate=functools.partial(
                 Light.cone_divergence, np.radians(60))),
             parent=world)
light.translate((0.0, 0.0, -1.0))

# Make a renderer object and scene for tracing
viewer = MeshcatRenderer(open_browser=True)
scene = Scene(world)
viewer.render(scene)

# Generate some rays from the light source and trace them through the scene
for ray in light.emit(10):
    info = photon_tracer.follow(ray, scene)
    rays, events = zip(*info)
    viewer.add_ray_path(rays)

# Wait for Ctrl-C to terminate the script; keep the window open
print("Ctrl-C to close")
while True:
    try:
        time.sleep(.3)
    except KeyboardInterrupt:
        print("Bye")
Example #15
0
    def _make_scene(self):
        """ Creates the scene based on configuration values.
        """
        # Make world node
        (l, w, d) = self.size
        world = Node(
            name="World",
            geometry=Box((l * 100, w * 100, d * 100),
                         material=Material(refractive_index=self.n0)),
        )

        # Create components (Absorbers, Luminophores and Scatteres)
        if len(self._user_components) == 0:
            self._user_components = self._make_default_components()
        components = []
        for component_data in self._user_components:
            cls = component_data.pop("cls")
            coefficient = component_data.pop("coefficient")
            component = cls(coefficient, **component_data)
            components.append(component)

        # Create LSC node
        lsc = Node(
            name="LSC",
            geometry=Box(
                (l, w, d),
                material=Material(
                    refractive_index=self.n1,
                    components=components,
                    surface=Surface(delegate=OptionalMirrorAndSolarCell(self)),
                ),
            ),
            parent=world,
        )

        if self._air_gap_mirror_info["want_air_gap_mirror"]:
            sheet_thickness = 0.25 * d  # make it appear thinner than the LSC
            air_gap_mirror = Node(
                name="Air Gap Mirror",
                geometry=Box(
                    (l, w, sheet_thickness),  # same surface air but very thin
                    material=Material(
                        refractive_index=self.n0,
                        components=[],
                        surface=Surface(delegate=AirGapMirror(self)),
                    ),
                ),
                parent=world,
            )
            # Move adjacent to bottom surface with a small air gap
            air_gap_mirror.translate((0.0, 0.0, -(0.5 * d + sheet_thickness)))

        # Use user light if any have been given, otherwise use default values.
        if len(self._user_lights) == 0:
            self._user_lights = self._make_default_lights()

        # Create light nodes
        for light_data in self._user_lights:
            name = light_data["name"]
            light = Light(
                name=name,
                direction=light_data["direction"],
                wavelength=light_data["wavelength"],
                position=light_data["position"],
            )
            light_node = Node(name=name, light=light, parent=world)
            light_node.location = light_data["location"]
            if light_data["rotation"]:
                light_node.rotate(*light_data["rotation"])

        self._scene = Scene(world)
Example #16
0
)

# Light source
light = Light(
    divergence_delegate=functools.partial(
        Light.cone_divergence,
        np.radians(20)
    )
)
light_node = Node(
    name='light',
    parent=world_node,
    location=(0.0, 0.0, 1.0)
)
light_node.rotate(np.radians(180), (1, 0, 0))
light_node.light = light
scene = Scene(root=world_node)
renderer = MeshcatRenderer(max_histories=None, open_browser=True)
renderer.render(scene)


if __name__ == "__main__":
    np.random.seed(1)
    for light_node in scene.light_nodes:
        for ray in light.emit(20):
            ray = ray.representation(light_node, world_node)
            steps = photon_tracer.follow(ray, scene, renderer=renderer)
            path, decisions = zip(*steps)
            print(decisions)
            renderer.add_ray_path(path)