Esempio n. 1
0
 def trace_surface(
     self,
     local_ray: "Ray",
     container_geometry: "Geometry",
     to_geometry: "Geometry",
     surface_geometry: "Geometry",
 ) -> Tuple[Decision, dict]:
     """ 
     """
     # Get reflectivity for the ray
     normal = surface_geometry.normal(local_ray.position)
     n1 = container_geometry.material.refractive_index(local_ray.wavelength)
     n2 = to_geometry.material.refractive_index(local_ray.wavelength)
     # Be flexible with how the normal is defined
     if np.dot(normal, local_ray.direction) < 0.0:
         normal = flip(normal)
     angle = angle_between(normal, np.array(local_ray.direction))
     if angle < 0.0 or angle > 0.5 * np.pi:
         raise TraceError("The incident angle must be between 0 and pi/2.")
     incident = local_ray.direction
     reflectivity = self._return_mechanism.reflectivity(angle, n1, n2)
     #print("Reflectivity: {}, n1: {}, n2: {}, angle: {}".format(reflectivity, n1, n2, angle))
     gamma = np.random.uniform()
     info = {"normal": normal, "n1": n1, "n2": n2}
     # Pick between reflection (return) and transmission (transit)
     if gamma < reflectivity:
         new_ray = self._return_mechanism.transform(local_ray, info)
         decision = Decision.RETURN
         yield new_ray, decision
     else:
         new_ray = self._transit_mechanism.transform(local_ray, info)
         decision = Decision.TRANSIT
         yield new_ray, decision
Esempio n. 2
0
    def probability(self, ray: Ray) -> float:
        """ Returns the probability that the interaction will occur.
        """
        context = self.context
        normal = np.array(context.normal)
        n1 = context.n1
        n2 = context.n2
        
        # Be flexible with how the normal is defined
        ray_ = ray.representation(context.normal_node.root, context.normal_node)
        if np.dot(normal, ray_.direction) < 0.0:
            normal = flip(normal)
        angle = angle_between(normal, np.array(ray_.direction))
        logger.debug("Incident angle {:.2f}".format(np.degrees(angle)))
        if angle < 0.0 or angle > 0.5 * np.pi:
            raise ValueError("The incident angle must be between 0 and pi/2.")

        # Catch TIR case
        if n2 < n1 and angle > np.arcsin(n2/n1):
            return 1.0
        c = np.cos(angle)
        s = np.sin(angle)
        k = np.sqrt(1 - (n1/n2 * s)**2)
        Rs1 = n1 * c - n2 * k
        Rs2 = n1 * c + n2 * k
        Rs = (Rs1/Rs2)**2
        Rp1 = n1 * k - n2 * c
        Rp2 = n1 * k + n2 * c
        Rp = (Rp1/Rp2)**2
        return 0.5 * (Rs + Rp)
Esempio n. 3
0
 def test_angle_between_acute(self):
     # 45 deg. between vectors (pi/4)
     v1 = norm((1.0, 1.0, 0.0))
     v2 = norm((1.0, 0.0, 0.0))
     rads = angle_between(v1, v2)
     expected = np.pi / 4.0
     assert np.isclose(rads, expected)
Esempio n. 4
0
 def reflectivity(self, surface, ray, geometry, container, adjacent):
     """ Returns the reflectivity given the interaction.
     
         Parameters
         ----------
         surface: Surface
             The surface object owned by the material.
         ray: Ray
             The incident ray.
         geometry: Geometry
             The geometry being hit.
         container: Node
             The node containing the incident ray.
         adjacent: Node
             The node that would contain the ray if transmitted.
     """
     # Calculate Fresnel reflectivity
     n1 = container.geometry.material.refractive_index
     n2 = adjacent.geometry.material.refractive_index
     # Be tolerance with definition of surface normal
     normal = geometry.normal(ray.position)
     if np.dot(normal, ray.direction) < 0.0:
         normal = flip(normal)
     angle = angle_between(normal, np.array(ray.direction))
     r = fresnel_reflectivity(angle, n1, n2)
     return float(r)
Esempio n. 5
0
 def test_angle_between_obtuse(self):
     """ Negative dot product means vectors form an obtuse angle.
     """
     v1 = norm((1.0, 1.0, 0.0))
     v2 = norm((-1.0, 0.0, 0.0))
     d = np.dot(v1, v2)
     assert d < 0.0
     rads = angle_between(v1, v2)
     expected = np.pi - np.pi / 4.0
     assert np.isclose(rads, expected)
Esempio n. 6
0
 def normal(self, ray: Ray) -> tuple:
     """ Return outward facing surface normal at the interface intersection point. 
     """
     from_node = self.from_node
     to_node = self.to_node
     root1 = from_node.root
     root2 = to_node.root
     if root1 != root2:
         raise TraceError('Nodes are in different trees.')
     root = root1
     node1, node2 = from_node, to_node
     pos_in_node1 = root.point_to_node(ray.position, node1)
     dir_in_node1 = root.vector_to_node(ray.direction, node1)
     pos_in_node2 = root.point_to_node(ray.position, node2)
     dir_in_node2 = root.vector_to_node(ray.direction, node2)
     # Need to find the surface normal with respect to the geometry we are entering.
     # This is not necessarily the to_node for embedded nodes because we could be
     # exiting node1 and be contained in node2. The correct normal would be for 
     # node1 in this case.
     surfaces = ((node1, pos_in_node1), (node2, pos_in_node2))
     on_surfaces = [node.geometry.is_on_surface(pos) for (node, pos) in surfaces]
     touching_interface = collections.Counter([True, True])
     embedded_interface = collections.Counter([False, True])
     interface_type = collections.Counter(on_surfaces)
     if interface_type == touching_interface:
         # Use angle to determine the normal of the exiting surface
         if node1.geometry.is_entering(pos_in_node1, dir_in_node1):
             node = node1
             normal = node1.geometry.normal(pos_in_node1)
         elif node2.geometry.is_entering(pos_in_node2, dir_in_node2):
             node = node2
             normal = node2.geometry.normal(pos_in_node2)
         else:
             raise TraceError("Cannot determine how ray is crossing the interface.")
         logger.debug('Touching Interface {}|{} normal {}, angle {}.'.format(from_node, to_node, normal, np.degrees(angle)))
         return normal, node
     elif interface_type == embedded_interface:
         idx = on_surfaces.index(True)
         node, pos = surfaces[idx]
         normal = node.geometry.normal(pos)
         dirvec = None
         if node == node1:
             dirvec = dir_in_node1
         else:
             dirvec = dir_in_node2
         angle = angle_between(normal, np.array(dirvec))
         logger.debug('Embedded Interface {}|{} normal {}, angle {}.'.format(from_node, to_node, normal, np.degrees(angle)))
         return normal, node
     else:
         raise TraceError("Cannot determine how ray is crossing the interface.")
Esempio n. 7
0
    def trace_surface(
        self,
        local_ray: "Ray",
        container_geometry: "Geometry",
        to_geometry: "Geometry",
        surface_geometry: "Geometry",
    ) -> Tuple[Decision, dict]:
        """ 
        """
        # Ray both materials need a refractive index to compute Frensel reflection;
        # if they are not the both refractive then just let ray cross the interface.
        try:
            normal = surface_geometry.normal(local_ray.position)
        except Exception:
            import pdb; pdb.set_trace() 
        if not all([isinstance(x, Refractive) for x in (container_geometry.material, to_geometry.material)]):
            new_ray = CrossInterface().transform(local_ray, {"normal": normal})
            yield new_ray, Decision.TRANSIT
            return

        # Get reflectivity for the ray
        n1 = container_geometry.material.refractive_index(local_ray.wavelength)
        n2 = to_geometry.material.refractive_index(local_ray.wavelength)
        # Be flexible with how the normal is defined
        if np.dot(normal, local_ray.direction) < 0.0:
            normal = flip(normal)
        angle = angle_between(normal, np.array(local_ray.direction))
        if angle < 0.0 or angle > 0.5 * np.pi:
            raise TraceError("The incident angle must be between 0 and pi/2.")
        incident = local_ray.direction
        reflectivity = self._return_mechanism.reflectivity(angle, n1, n2)
        #print("Reflectivity: {}, n1: {}, n2: {}, angle: {}".format(reflectivity, n1, n2, angle))
        gamma = np.random.uniform()
        info = {"normal": normal, "n1": n1, "n2": n2}
        # Pick between reflection (return) and transmission (transit)
        if gamma < reflectivity:
            new_ray = self._return_mechanism.transform(local_ray, info)
            decision = Decision.RETURN
            yield new_ray, decision
        else:
            new_ray = self._transit_mechanism.transform(local_ray, info)
            decision = Decision.TRANSIT
            yield new_ray, decision
Esempio n. 8
0
 def test_angle_between(self):
     normal = norm((1.0, 0.0, 0.0))
     vector = norm((1.0, 0.0, 0.0))
     assert angle_between(normal, vector) == 0.0
     assert angle_between(-normal, vector) == np.pi