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 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_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 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_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_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 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_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_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 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 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 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_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 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
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
""" 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_name(self): assert Node(name="a").name == 'a'
def test_parent(self): a = Node() b = Node(parent=a) assert a.parent == None assert b.parent == a
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 _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)