def test_trace_with_geometric_objects_1(self): """ Only one of the geometric objects has a transformation applied. """ root = Node(name="Root", geometry=Sphere(radius=10.0)) a = Node(name="A", parent=root, geometry=Sphere(radius=1.0)) b = Node(name="B", parent=root, geometry=Sphere(radius=1.0)) b.translate((5.0, 0.0, 0.0)) scene = Scene(root) tracer = PhotonTracer(scene) position = (-3.0, 0.0, 0.0) direction = (1.0, 0.0, 0.0) initial_ray = Ray( position=position, direction=direction, wavelength=555.0, is_alive=True ) expected_history = [ initial_ray, # Starting ray replace(initial_ray, position=(-1.0, 0.0, 0.0)), # Moved to intersection replace(initial_ray, position=(1.0, 0.0, 0.0)), # Moved to intersection replace(initial_ray, position=(4.0, 0.0, 0.0)), # Moved to intersection replace(initial_ray, position=(6.0, 0.0, 0.0)), # Moved to intersection replace(initial_ray, position=(10.0, 0.0, 0.0), is_alive=False), # Exit ray ] history = tracer.follow(initial_ray) for pair in zip(history, expected_history): a, b = pair print("Testing {} {}".format(a.position, b.position)) assert np.allclose(a.position, b.position)
def test_is_entering_false(self): a = Node(name="A", parent=None) b = Node(name="B", parent=a) b.geometry = Sphere(radius=1.0) surface_point = (-1.0, 0.0, 0.0) entering_direction = (-1.0, 0.0, 0.0) assert b.geometry.is_entering(surface_point, entering_direction) == False
def test_trace_with_material_object(self): """ Root node and test object has a material attached. """ np.random.seed(1) # No reflections # np.random.seed(2) # Reflection at last inteface root = Node(name="Root", geometry=Sphere(radius=10.0, material=Dielectric.make_constant((400, 800), 1.0))) b = Node(name="B", parent=root, geometry=Sphere(radius=1.0, material=Dielectric.make_constant((400, 800), 1.5))) b.translate((5.0, 0.0, 0.0)) scene = Scene(root) tracer = PhotonTracer(scene) position = (-3.0, 0.0, 0.0) direction = (1.0, 0.0, 0.0) initial_ray = Ray( position=position, direction=direction, wavelength=555.0, is_alive=True ) expected_history = [ initial_ray, # Starting ray replace(initial_ray, position=(4.0, 0.0, 0.0)), # Moved to intersection replace(initial_ray, position=(4.0, 0.0, 0.0)), # Refracted into A replace(initial_ray, position=(6.0, 0.0, 0.0)), # Moved to intersection replace(initial_ray, position=(6.0, 0.0, 0.0)), # Refracted out of A replace(initial_ray, position=(10.0, 0.0, 0.0), is_alive=False), # Exit ray ] history = tracer.follow(initial_ray) for pair in zip(history, expected_history): a, b = pair print("Testing {} {}".format(a.position, b.position)) assert np.allclose(a.position, b.position)
def test_is_entering_false(self): a = Node(name="A", parent=None) b = Node(name="B", parent=a) b.geometry = Sphere(radius=1.0) surface_point = (-1.0, 0.0, 0.0) entering_direction = (-1.0, 0.0, 0.0) assert b.geometry.is_entering(surface_point, entering_direction) == False
def test_intersections(self): a = Node(name="A", parent=None) b = Node(name="B", parent=a) b.geometry = Sphere(radius=1.0) loc = (-1.0, 0.0, 0.0) vec = (1.0, 0.0, 0.0) intersections = b.intersections(loc, vec) points = np.array([x.point for x in intersections]) assert np.allclose(points, ((-1.0, 0.0, 0.0), (1.0, 0.0, 0.0)))
def test_intersections(self): a = Node(name="A", parent=None) b = Node(name="B", parent=a) b.geometry = Sphere(radius=1.0) loc = (-1.0, 0.0, 0.0) vec = (1.0, 0.0, 0.0) intersections = b.intersections(loc, vec) points = np.array([x.point for x in intersections]) assert np.allclose(points, ((-1.0, 0.0, 0.0), (1.0, 0.0, 0.0)))
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(zmq_url='tcp://127.0.0.1:6000') r.render(s) time.sleep(0.5) r.remove(s)
def test_intersection_when_on_surface(self): """ Make sure we return intersection points even with zero distance from ray. """ a = Node(name="A", parent=None) a.geometry = Sphere(radius=1.0) loc = (-1.0, 0.0, 0.0) vec = (1.0, 0.0, 0.0) intersections = a.intersections(loc, vec) points = np.array([x.point for x in intersections]) expected = np.array([(-1.0, 0.0, 0.0), (1.0, 0.0, 0.0)]) assert np.allclose(points, expected)
def test_intersection_when_on_surface(self): """ Make sure we return intersection points even with zero distance from ray. """ a = Node(name="A", parent=None) a.geometry = Sphere(radius=1.0) loc = (-1.0, 0.0, 0.0) vec = (1.0, 0.0, 0.0) intersections = a.intersections(loc, vec) points = np.array([x.point for x in intersections]) expected = np.array([(-1.0, 0.0, 0.0), (1.0, 0.0, 0.0)]) assert np.allclose(points, expected)
def node_tree(): b_pos = (1.0, 0.0, 0.0) b_axis = (0.0, 1.0, 0.0) b_rads = 3.14159265 / 2 c_pos = (1.0, 0.0, 0.0) a = Node(name="a", parent=None) b = Node(name="b", parent=a) b.location = b_pos b.rotate(b_rads, b_axis) c = b.add_child_node(name="c") c.location = c_pos return a, b, c
def test_no_interaction(self): np.random.seed(0) mat = Dielectric.make_constant((400, 800), 1.0) root = Node(name="Root", parent=None) root.geometry = Sphere(radius=10.0, material=mat) a = Node(name="A", parent=root) a.geometry = Sphere(radius=1.0, material=mat) ray = Ray(position=(-1.0, 0.0, 0.0), direction=(1.0, 0.0, 0.0), wavelength=555.0, is_alive=True) volume = Volume(a, 2.0) new_ray = volume.trace(ray) expected = replace(ray, position=(1.0, 0.0, 0.0)) assert new_ray == expected
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))
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)))
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_zero_reflection(self): np.random.seed(0) mat1 = Dielectric.make_constant((400, 800), 1.0) mat2 = Dielectric.make_constant((400, 800), 1.0) root = Node(name="Root", parent=None) root.geometry = Sphere(radius=10.0, material=mat1) a = Node(name="A", parent=root) a.geometry = Sphere(radius=1.0, material=mat2) ray = Ray(position=(-1.0, 0.0, 0.0), direction=(0.0, 0.0, 1.0), wavelength=555.0, is_alive=True) from_node = root to_node = a interface = DielectricInterface(from_node, to_node) new_ray = interface.trace(ray) expected = ray # unchanged assert new_ray == expected
def test_init(self): node = Node(name='A') inter = Intersection(coordsys=Node, hit=Node, point=(0.0, 0.0, 0.0), distance=0.0) assert type(inter) == Intersection
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_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))
def representation(self, from_node: Node, to_node: Node) -> Ray: """ Representation of the ray in another coordinate system. Parameters ---------- from_node : Node The node which represents the ray's current coordinate system to_node : Node The node in which the new ray should be represented. Notes ----- Use this method to express the ray location and direction as viewed in the `to_node` coordinate system. """ new_position = from_node.point_to_node(self.position, to_node) new_direction = from_node.vector_to_node(self.direction, to_node) new_ray = replace(self, position=new_position, direction=new_direction) return new_ray
def representation(self, from_node: Node, to_node: Node) -> Ray: """ Representation of the ray in another coordinate system. Parameters ---------- from_node : Node The node which represents the ray's current coordinate system to_node : Node The node in which the new ray should be represented. Notes ----- Use this method to express the ray location and direction as viewed in the `to_node` coordinate system. """ new_position = from_node.point_to_node(self.position, to_node) new_direction = from_node.vector_to_node(self.direction, to_node) new_ray = replace(self, position=new_position, direction=new_direction) return new_ray
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 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))
def test_equality(self): node = Node(name='A') inter1 = Intersection(coordsys=Node, hit=Node, point=(0.0, 0.0, 0.0), distance=0.0) inter2 = Intersection(coordsys=Node, hit=Node, point=(0.0, 0.0, 0.0), distance=0.0) assert inter1 == inter2
def test_ray_reflecting_interaction(self): # low > very high refractive index np.random.seed(2) mat1 = Dielectric.make_constant((400, 800), 1.0) mat2 = Dielectric.make_constant((400, 800), 6.0) root = Node(name="Root", parent=None) root.geometry = Sphere(radius=10.0, material=mat1) a = Node(name="A", parent=root) a.geometry = Sphere(radius=1.0, material=mat2) ray = Ray(position=(-1.0, 0.0, 0.0), direction=norm((-0.2, 0.2, 1.0)), wavelength=555.0, is_alive=True) from_node = root to_node = a interface = DielectricInterface(from_node, to_node) new_ray = interface.trace(ray) assert np.sign(ray.direction[0]) != np.sign(new_ray.direction[0]) # Reflected # Direction should be different after refracting interface assert all([not np.allclose(new_ray.direction, ray.direction), np.allclose(new_ray.position, ray.position), new_ray.wavelength == ray.wavelength, new_ray.is_alive == ray.is_alive])
def test_intersection_with_translation(self): a = Node(name="A", parent=None) b = Node(name="B", parent=a) b.geometry = Sphere(radius=1.0) b.translate((1.0, 0.0, 0.0)) aloc = (-2.0, 0.0, 0.0) avec = (1.0, 0.0, 0.0) bloc = b.point_to_node(aloc, b) bvec = b.vector_to_node(avec, b) intersections = b.intersections(bloc, bvec) points = tuple(x.point for x in intersections) assert np.allclose(points, ((-1.0, 0.0, 0.0), (1.0, 0.0, 0.0))) # In local frame of b sphere is at origin intersections = a.intersections(aloc, avec) points = np.array(tuple(x.to(a).point for x in intersections)) expected = np.array(((0.0, 0.0, 0.0), (2.0, 0.0, 0.0))) # In frame of a everything is shifed 1 along x assert np.allclose(points, expected)
def test_trace_with_translated_geometric_object(self): """ Single translated geometric objects. """ root = Node(name="Root", geometry=Sphere(radius=10.0)) a = Node(name="A", parent=root, geometry=Sphere(radius=1.0)) a.translate((5.0, 0.0, 0.0)) scene = Scene(root) tracer = PhotonTracer(scene) position = (-2.0, 0.0, 0.0) direction = (1.0, 0.0, 0.0) initial_ray = Ray( position=position, direction=direction, wavelength=555.0, is_alive=True ) expected_history = [ initial_ray, # Starting ray replace(initial_ray, position=(4.0, 0.0, 0.0)), # First intersection replace(initial_ray, position=(6.0, 0.0, 0.0)), # Second intersection replace(initial_ray, position=(10.0, 0.0, 0.0), is_alive=False), # Exit ray ] history = tracer.follow(initial_ray) for pair in zip(history, expected_history): assert pair[0] == pair[1]
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
def test_trace_raises_trace_error(self): """ Tests interface between objects in which only one of them has a material. This should raise a RuntimeError because it cannot be traced in a physically correct way. """ np.random.seed(2) root = Node(name="Root", geometry=Sphere(radius=10.0)) b = Node(name="B", parent=root, geometry=Sphere(radius=1.0, material=Dielectric.make_constant((400, 800), 1.5))) b.translate((5.0, 0.0, 0.0)) scene = Scene(root) tracer = PhotonTracer(scene) position = (-3.0, 0.0, 0.0) direction = (1.0, 0.0, 0.0) initial_ray = Ray( position=position, direction=direction, wavelength=555.0, is_alive=True ) did_raise = False try: tracer.follow(initial_ray) except TraceError as err: did_raise = True assert did_raise
def node_tree(): b_pos = (1.0, 0.0, 0.0) b_axis = (0.0, 1.0, 0.0) b_rads = 3.14159265 / 2 c_pos = (1.0, 0.0, 0.0) a = Node(name="a", parent=None) b = Node(name="b", parent=a) b.location = b_pos b.rotate(b_rads, b_axis) c = b.add_child_node(name="c") c.location = c_pos return a, b, c
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 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)))
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))
from pvtrace.scene.renderer import MeshcatRenderer from pvtrace.geometry.utils import magnitude import logging # We want to see pvtrace logging here #logging.getLogger('pvtrace').setLevel(logging.CRITICAL) logging.getLogger('trimesh').setLevel(logging.CRITICAL) logging.getLogger('matplotlib').setLevel(logging.CRITICAL) wavelength_range = (200, 800) wavelength = np.linspace(*wavelength_range, 1000) lumogen = Lumophore.make_lumogen_f_red(wavelength, 1000, 1.0) linear_background = Lumophore.make_linear_background(wavelength, 1.0) # Make a world coordinate system world_node = Node(name='world') world_node.geometry = Sphere( radius=10.0, material=Dielectric.make_constant((300, 1000.0), 1.0) ) refractive_index = np.column_stack( (wavelength, np.ones(wavelength.shape) * 1.5) ) # Add LSC size = (1.0, 1.0, 0.02) lsc = Node(name="LSC", parent=world_node) lsc.geometry = Box( size, material=Host( refractive_index, # LSC refractive index
def test_init(self): assert type(Node()) == Node
def test_name(self): assert Node(name="a").name == 'a'
material = Host( np.column_stack( # refractive index spectrum (wavelength, np.ones(wavelength.size) * 1.5) ), [lumophore], # list of lumophores, reuse the one we already have. ) # Make the cylinder node with length 5cm and radius 0.02cm and give the material we # just made. cylinder = Node( name="cylinder (glass)", geometry=Cylinder( length=5.0, radius=0.02, material=material ), parent=world ) # Make a light source. This is a laser emitting light along the whole length of the # cylinder. We need to translate and rotate the light source to get it to fire along # the axis. We use the position delegate to generate photons along the same length # as the cylinder. light = Node( name="light (555nm laser)", light=Light(position_delegate=lambda : (np.random.uniform(-2.5, 2.5), 0.0, 0.0)), parent=world )
def test_parent(self): a = Node() b = Node(parent=a) assert a.parent == None assert b.parent == a
""" from pvtrace.geometry.cylinder import Cylinder from pvtrace.geometry.sphere import Sphere from pvtrace.scene.renderer import MeshcatRenderer from pvtrace.scene.scene import Scene from pvtrace.scene.node import Node from pvtrace.light.light import Light from pvtrace.algorithm import photon_tracer from pvtrace.material.dielectric import Dielectric import numpy as np import functools import sys import time # World node contains the simulation; large sphere filled with air world = Node(name="world (air)", geometry=Sphere(radius=10.0, material=Dielectric.air())) # A small cylinder shape made from glass 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))
def test_coodinate_system_conversions(self): a = Node(name='a') b = Node(name='b', parent=a) c = Node(name='c', parent=b) d = Node(name='d', parent=a) b.translate((1, 1, 1)) c.translate((0, 1, 1)) d.translate((-1, -1, -1)) theta = 0.5 * np.pi b.rotate(theta, (0, 0, 1)) c.rotate(theta, (1, 0, 0)) d.rotate(theta, (0, 1, 0)) # Points in node d to a require just travelling up the nodes. assert np.allclose(d.point_to_node((0, 0, 0), a), (-1, -1, -1)) assert np.allclose(d.point_to_node((1, 1, 1), a), (0, 0, -2)) # Directions in node d to a require just travelling up the nodes. assert np.allclose(d.vector_to_node((1, 0, 0), a), (0, 0, -1)) assert np.allclose(d.vector_to_node((0, 1, 0), a), (0, 1, 0)) assert np.allclose(d.vector_to_node((0, 0, 1), a), (1, 0, 0)) # Points in node d to c requires going up and down nodes assert np.allclose(c.point_to_node((0, 0, 0), d), (-3, 2, 1)) assert np.allclose(c.point_to_node((1, 1, 1), d), (-4, 3, 2)) # Directions in node d to c require going up and down nodes assert np.allclose(c.vector_to_node((1, 0, 0), d), (0, 1, 0)) assert np.allclose(c.vector_to_node((0, 1, 0), d), (-1, 0, 0)) assert np.allclose(c.vector_to_node((0, 0, 1), d), (0, 0, 1))
radius=10.0, material=Dielectric.air() ) ) cylinder = Node( name="cylinder (glass)", geometry=Cylinder( length=1.0, radius=1.0, material=Dielectric.glass() ), parent=world ) 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)) rend = MeshcatRenderer() scene = Scene(world) tracer = PhotonTracer(scene) rend.render(scene) for ray in light.emit(10): path = tracer.follow(ray) print(path) rend.add_ray_path(path) while True: try: time.sleep(.3)
def test_intersection_with_translation(self): a = Node(name="A", parent=None) b = Node(name="B", parent=a) b.geometry = Sphere(radius=1.0) b.translate((1.0, 0.0, 0.0)) aloc = (-2.0, 0.0, 0.0) avec = (1.0, 0.0, 0.0) bloc = b.point_to_node(aloc, b) bvec = b.vector_to_node(avec, b) intersections = b.intersections(bloc, bvec) points = tuple(x.point for x in intersections) assert np.allclose(points, ((-1.0, 0.0, 0.0), (1.0, 0.0, 0.0))) # In local frame of b sphere is at origin intersections = a.intersections(aloc, avec) points = np.array(tuple(x.to(a).point for x in intersections)) expected = np.array(((0.0, 0.0, 0.0), (2.0, 0.0, 0.0))) # In frame of a everything is shifed 1 along x assert np.allclose(points, expected)
from pvtrace.scene.node import Node from pvtrace.scene.scene import Scene from pvtrace.scene.renderer import MeshcatRenderer from pvtrace.geometry.sphere import Sphere from pvtrace.material.dielectric import Dielectric from pvtrace.light.light import Light from pvtrace.algorithm import photon_tracer import time import functools import numpy as np # Add nodes to the scene graph world = Node(name="world (air)", geometry=Sphere(radius=10.0, material=Dielectric.air())) sphere = Node(name="sphere (glass)", geometry=Sphere(radius=1.0, material=Dielectric.glass()), parent=world) sphere.translate((0, 0, 2)) # Add source of photons light = Node(name="Light (555nm)", light=Light(divergence_delegate=functools.partial( Light.cone_divergence, np.radians(20)))) # Use meshcat to render the scene (optional) viewer = MeshcatRenderer(open_browser=True) scene = Scene(world) for ray in light.emit(100): # Do something with the photon trace information... info = photon_tracer.follow(ray, scene) rays, events = zip(*info)
def test_coodinate_system_conversions(self): a = Node(name='a') b = Node(name='b', parent=a) c = Node(name='c', parent=b) d = Node(name='d', parent=a) b.translate((1,1,1)) c.translate((0,1,1)) d.translate((-1, -1, -1)) theta = 0.5 * np.pi b.rotate(theta, (0, 0, 1)) c.rotate(theta, (1, 0, 0)) d.rotate(theta, (0, 1, 0)) # Points in node d to a require just travelling up the nodes. assert np.allclose(d.point_to_node((0, 0, 0), a), (-1, -1, -1)) assert np.allclose(d.point_to_node((1, 1, 1), a), (0, 0, -2)) # Directions in node d to a require just travelling up the nodes. assert np.allclose(d.vector_to_node((1, 0, 0), a), (0, 0, -1)) assert np.allclose(d.vector_to_node((0, 1, 0), a), (0, 1, 0)) assert np.allclose(d.vector_to_node((0, 0, 1), a), (1, 0, 0)) # Points in node d to c requires going up and down nodes assert np.allclose(c.point_to_node((0, 0, 0), d), (-3, 2, 1)) assert np.allclose(c.point_to_node((1, 1, 1), d), (-4, 3, 2)) # Directions in node d to c require going up and down nodes assert np.allclose(c.vector_to_node((1, 0, 0), d), (0, 1, 0)) assert np.allclose(c.vector_to_node((0, 1, 0), d), (-1, 0, 0)) assert np.allclose(c.vector_to_node((0, 0, 1), d), (0, 0, 1))
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)