Пример #1
0
def linearpolarizer(field, rotation=0):
    """
    Definition that represents a linear polarizer.

    Parameters
    ----------
    field        : ndarray
                   Polarization vector of an input beam.
    rotation     : float
                   Represents rotation of the polarizer along propagation direction in angles (couter-clockwise).

    Returns
    ----------
    result       : ndarray
                   Polarization vector of an output beam.
    """
    rotation = np.radians(rotation)
    rotmat = np.array([[float(np.cos(rotation)),
                        float(np.sin(rotation))],
                       [float(-np.sin(rotation)),
                        float(np.cos(rotation))]])
    linearpolarizer = np.array([[1, 0], [0, 0]])
    linearpolarizer = np.dot(rotmat.transpose(),
                             np.dot(linearpolarizer, rotmat))
    result = np.dot(linearpolarizer, field)
    return result
Пример #2
0
    def intersect(self,ray):
        """
        A  definition to find out which surface to intersect a ray(s).

        Parameters
        ----------
        ray          : ndarray
                       Ray(s) to be intersected. 
        """
        convex_normal,convex_distance = intersect_w_sphere(
                                                           ray,
                                                           self.convex_surface
                                                          )
        plane_normal,plane_distance   = intersect_w_circle(
                                                           ray,
                                                           self.plane_surface
                                                          )
        test_normal                   = convex_normal
        if len(test_normal.shape) < 3:
            test_normal = convex_normal[0]
        is_it_in_lens                 = same_side(
                                                  test_normal,
                                                  self.convex_point,
                                                  self.plane_surface[0][1],
                                                  self.plane_surface[0][2]
                                                 )
        surface_normals               = np.array([convex_normal,plane_normal],dtype=np.float)
        surface_distances             = np.array([convex_distance,plane_distance],dtype=np.float)
        which_surface                 = np.amin(surface_distances,axis=0)
        ids                           = np.where(surface_distances==which_surface)
        ids                           = np.asarray(ids)
#        ids[0]                        = ids[0] | is_it_in_lens
        normal                        = surface_normals[ids[0],ids[1]]
        distance                      = surface_distances[ids[0],ids[1]]
        return normal,distance
Пример #3
0
 def define_geometry(self):
     """
     A definition to define geometry of a plano-convex lens.
     """
     self.center         = np.array([
                                     0.,
                                     0.,
                                     self.radius-self.thickness 
                                    ])
     self.center,_,_,_   = rotate_point(
                                        self.center,
                                        angles=self.rotation,
                                        offset=self.location
                                       )
     
     self.plane_center   = np.array([0.,0.,0.])+self.location
     self.convex_point   = self.plane_center-self.thickness
     self.convex_surface = define_sphere(
                                         self.center,
                                         self.radius
                                        )
     self.plane_surface  = define_circle(
                                         self.plane_center,
                                         self.diameter,
                                         self.rotation
                                        )
Пример #4
0
def calculate_intersection_of_two_rays(ray0, ray1):
    """
    Definition to calculate the intersection of two rays.

    Parameters
    ----------
    ray0       : ndarray
                 A ray.
    ray1       : ndarray
                 A ray.

    Returns
    ----------
    point      : ndarray
                 Point in X,Y,Z.
    distances  : ndarray
                 Distances.
    """
    A = np.array([[float(ray0[1][0]), float(ray1[1][0])],
                  [float(ray0[1][1]), float(ray1[1][1])],
                  [float(ray0[1][2]), float(ray1[1][2])]])
    B = np.array([
        ray0[0][0] - ray1[0][0], ray0[0][1] - ray1[0][1],
        ray0[0][2] - ray1[0][2]
    ])
    distances = np.linalg.lstsq(A, B)[0]
    if np.allclose(np.dot(A, distances), B) == False:
        distances = np.array([0, 0])
    distances = distances[np.argsort(-distances)]
    point = propagate_a_ray(ray0, distances[0])[0]
    return point, distances
Пример #5
0
def create_ray(x0y0z0, abg):
    """
    Definition to create a ray.

    Parameters
    ----------
    x0y0z0       : list
                   List that contains X,Y and Z start locations of a ray.
    abg          : list
                   List that contaings angles in degrees with respect to the X,Y and Z axes.

    Returns
    ----------
    ray          : ndarray
                   Array that contains starting points and cosines of a created ray.
    """
    # Due to Python 2 -> Python 3.
    x0, y0, z0 = x0y0z0
    alpha, beta, gamma = abg
    # Create a vector with the given points and angles in each direction
    point = np.array([x0, y0, z0], dtype=np.float)
    alpha = np.cos(np.radians(alpha))
    beta = np.cos(np.radians(beta))
    gamma = np.cos(np.radians(gamma))
    # Cosines vector.
    cosines = np.array([alpha, beta, gamma], dtype=np.float)
    ray = np.array([point, cosines], dtype=np.float)
    return ray
Пример #6
0
def test():
    start0 = np.array([0., 5., 0.])
    start1 = np.array([0., -5., 0.])
    intersection = np.array([0., 0., 100.])
    ray0 = raytracer.create_ray_from_two_points(start0, intersection)
    ray1 = raytracer.create_ray_from_two_points(start1, intersection)
    c0, c1 = raytracer.find_nearest_points(ray0, ray1)
    print(c0, c1)
    assert True == True
Пример #7
0
def batch_of_rays(entry, exit):
    """
    Definition to generate a batch of rays with given entry point(s) and exit point(s). Note that the mapping is one to one, meaning nth item in your entry points list will exit from nth item in your exit list and generate that particular ray. Note that you can have a combination like nx3 points for entry or exit and 1 point for entry or exit. But if you have multiple points both for entry and exit, the number of points have to be same both for entry and exit.

    Parameters
    ----------
    entry      : ndarray
                 Either a single point with size of 3 or multiple points with the size of nx3.
    exit       : ndarray
                 Either a single point with size of 3 or multiple points with the size of nx3.

    Returns
    ----------
    rays       : ndarray
                 Generated batch of rays.
    """
    norays = np.array([0, 0])
    if len(entry.shape) == 1:
        entry = entry.reshape((1, 3))
    if len(exit.shape) == 1:
        exit = exit.reshape((1, 3))
    norays = np.amax(np.asarray([entry.shape[0], exit.shape[0]]))
    if norays > exit.shape[0]:
        exit = np.repeat(exit, norays, axis=0)
    elif norays > entry.shape[0]:
        entry = np.repeat(entry, norays, axis=0)
    rays = []
    norays = int(norays)
    for i in range(norays):
        rays.append(create_ray_from_two_points(entry[i], exit[i]))
    rays = np.asarray(rays)
    return rays
Пример #8
0
def circular_uniform_random_sample(no=[10, 50],
                                   radius=10.,
                                   center=[0., 0., 0.],
                                   angles=[0., 0., 0.]):
    """ 
    Definition to generate sample inside a circle uniformly but randomly.

    Parameters
    ----------
    no          : list
                  Number of samples.
    radius      : float
                  Radius of the circle.
    center      : list
                  Center location of the surface.
    angles      : list
                  Tilt of the surface.

    Returns
    ----------
    samples     : ndarray
                  Samples generated.
    """
    samples = np.empty((0, 3))
    rs = np.sqrt(np.random.uniform(0, 1, no[0]))
    angs = np.random.uniform(0, 2 * np.pi, no[1])
    for i in rs:
        for angle in angs:
            r = radius * i
            point = np.array(
                [float(r * np.cos(angle)),
                 float(r * np.sin(angle)), 0])
            samples = np.vstack((samples, point))
    samples = rotate_points(samples, angles=angles, offset=center)
    return samples
Пример #9
0
def circular_uniform_sample(no=[10, 50],
                            radius=10.,
                            center=[0., 0., 0.],
                            angles=[0., 0., 0.]):
    """
    Definition to generate sample inside a circle uniformly.

    Parameters
    ----------
    no          : list
                  Number of samples.
    radius      : float
                  Radius of the circle.
    center      : list
                  Center location of the surface.
    angles      : list
                  Tilt of the surface.

    Returns
    ----------
    samples     : ndarray
                  Samples generated.
    """
    samples = np.empty((0, 3))
    for i in range(0, no[0]):
        r = i / no[0] * radius
        ang_no = no[1] * i / no[0]
        for j in range(0, int(no[1] * i / no[0])):
            angle = j / ang_no * 2 * np.pi
            point = np.array(
                [float(r * np.cos(angle)),
                 float(r * np.sin(angle)), 0])
            samples = np.vstack((samples, point))
    samples = rotate_points(samples, angles=angles, offset=center)
    return samples
Пример #10
0
def reflect(input_ray, normal):
    """ 
    Definition to reflect an incoming ray from a surface defined by a surface normal. Used method described in G.H. Spencer and M.V.R.K. Murty, "General Ray-Tracing Procedure", 1961.

    Parameters
    ----------
    input_ray    : ndarray
                   A vector/ray (2x3). It can also be a list of rays (nx2x3).
    normal       : ndarray
                   A surface normal (2x3). It also be a list of normals (nx2x3).

    Returns
    ----------
    output_ray   : ndarray
                   Array that contains starting points and cosines of a reflected ray.
    """
    input_ray = np.asarray(input_ray)
    normal = np.asarray(normal)
    if len(input_ray.shape) == 2:
        input_ray = input_ray.reshape((1, 2, 3))
    if len(normal.shape) == 2:
        normal = normal.reshape((1, 2, 3))
    mu = 1
    div = normal[:, 1, 0]**2 + normal[:, 1, 1]**2 + normal[:, 1, 2]**2
    a = mu * (input_ray[:, 1, 0] * normal[:, 1, 0] + input_ray[:, 1, 1] *
              normal[:, 1, 1] + input_ray[:, 1, 2] * normal[:, 1, 2]) / div
    n = np.int(np.amax(np.array([normal.shape[0], input_ray.shape[0]])))
    output_ray = np.zeros((n, 2, 3))
    output_ray[:, 0] = normal[:, 0]
    output_ray[:, 1] = input_ray[:, 1] - 2 * a * normal[:, 1]
    if output_ray.shape[0] == 1:
        output_ray = output_ray.reshape((2, 3))
    return output_ray
Пример #11
0
def rotate_points(points,angles=[0,0,0],mode='XYZ',origin=[0,0,0],offset=[0,0,0]):
    """
    Definition to rotate points.

    Parameters
    ----------
    points       : ndarray
                   Points.
    angles       : list
                   Rotation angles in degrees. 
    mode         : str
                   Rotation mode determines ordering of the rotations at each axis. There are XYZ,YXZ,ZXY and ZYX modes.
    origin       : list
                   Reference point for a rotation.
    offset       : list
                   Shift with the given offset.

    Returns
    ----------
    result       : ndarray
                   Result of the rotation   
    """
    points  = np.asarray(points)
    if angles[0] == 0 and angles[1] == 0 and angles[2] ==0:
        result = np.array(offset) + points
        return result
    points -= np.array(origin)
    rotx    = rotmatx(angles[0])
    roty    = rotmaty(angles[1])
    rotz    = rotmatz(angles[2])
    if mode == 'XYZ':
        result = np.dot(rotz,np.dot(roty,np.dot(rotx,points.T))).T
    elif mode == 'XZY':
        result = np.dot(roty,np.dot(rotz,np.dot(rotx,points.T))).T
    elif mode == 'YXZ':
        result = np.dot(rotz,np.dot(rotx,np.dot(roty,points.T))).T
    elif mode == 'ZXY':
        result = np.dot(roty,np.dot(rotx,np.dot(rotz,points.T))).T
    elif mode == 'ZYX':
        result = np.dot(rotx,np.dot(roty,np.dot(rotz,points.T))).T
    result += np.array(origin)
    result += np.array(offset)
    return result
Пример #12
0
def test():
    detector_location = [2., 0., 0.]
    triangle = np.array([[10., 10., 10.], [0., 10., 10.], [0., 0., 10.]])
    circle_center = [0., 0., 0.]
    circle_angles = [0., 0., 0.]
    circle_radius = 15.
    circle = raytracer.define_circle(angles=circle_angles,
                                     center=circle_center,
                                     radius=circle_radius)

    opl = detector_to_light_source(detector_location, triangle, circle)
    assert True == True
Пример #13
0
    def add_line(self,point_start,point_end,row=1,column=1,color='red'):
        """
        Definition to add a ray to the figure.

        Parameters
        ----------
        point_start    : ndarray
                         Starting point(s).
        point_end      : ndarray
                         Ending point(s).
        row            : int
                         Row number of the figure.
        column         : int
                         Column number of the figure.
        color          : str
                         Color of the lune to be drawn.
        """
        if np.__name__ == 'cupy':
            point_start = np.asnumpy(point_start)
            point_end   = np.asnumpy(point_end)
        if len(point_start.shape) == 1:
            point_start = point_start.reshape((1,3))
        if len(point_end.shape) == 1:
            point_end   = point_end.reshape((1,3))
        if point_start.shape != point_end.shape:
            print('Size mismatch in line plot. Sizes are {} and {}.'.format(point_start.shape,point_end.shape))
            sys.exit()
        for point_id in range(0,point_start.shape[0]):
            points = np.array(
                              [
                               point_start[point_id],
                               point_end[point_id]
                              ]
                             )
            points = points.reshape((2,3))
            if np.__name__ == 'cupy':
                points = np.asnumpy(points)
            self.fig.add_trace(
                               go.Scatter3d(
                                            x=points[:,0],
                                            y=points[:,1],
                                            z=points[:,2],
                                            mode='lines',
                                            line=dict(
                                                      width=self.settings["line width"],
                                                      color=color,
                                                     ),
                                            opacity=self.settings["opacity"]
                                           ),
                               row=row,
                               col=column
                              )
Пример #14
0
def load_image(fn):
    """ 
    Definition to load an image from a given location as a Numpy array.

    Parameters
    ----------
    fn           : str
                   Filename.

    Returns
    ----------
    image        :  ndarray
                    Image loaded as a Numpy array.

    """
    image = Image.open(fn)
    return np.array(image)
Пример #15
0
def electricfield(px, py):
    """
    Definition to create an electric field vector (polarization vector).

    Parameters
    ----------
    px           : float
                   Amplitude of the electric field along X axis.
    py           : float
                   Amplitude of the electric field along Y axis.

    Returns
    ----------
    field        : ndarray
                   An electric field vector (polarization vector).
    """
    field = np.array([[px], [py]])
    return field
Пример #16
0
def cross_product(vector1, vector2):
    """
    Definition to cross product two vectors and return the resultant vector. Used method described under: http://en.wikipedia.org/wiki/Cross_product

    Parameters
    ----------
    vector1      : ndarray
                   A vector/ray.
    vector2      : ndarray
                   A vector/ray.

    Returns
    ----------
    ray          : ndarray
                   Array that contains starting points and cosines of a created ray.
    """
    angle = np.cross(vector1[1].T, vector2[1].T)
    angle = np.asarray(angle)
    ray = np.array([vector1[0], angle], dtype=np.float)
    return ray
Пример #17
0
def rotmatz(angle):
    """
    Definition to generate a rotation matrix along Z axis.

    Parameters
    ----------
    angles       : list
                   Rotation angles in degrees.

    Returns
    ----------
    rotz         : ndarray
                   Rotation matrix along Z axis.
    """
    angle = np.radians(angle)
    rotz  = np.array([
                      [ math.cos(angle), -math.sin(angle), 0.],
                      [ math.sin(angle),  math.cos(angle), 0.],
                      [              0.,               0., 1.]
                     ],dtype=np.float)
    return rotz
Пример #18
0
def intersect_w_surface(ray, points):
    """
    Definition to find intersection point inbetween a surface and a ray. For more see: http://geomalgorithms.com/a06-_intersect-2.html

    Parameters
    ----------
    ray          : ndarray
                   A vector/ray.
    points       : ndarray
                   Set of points in X,Y and Z to define a planar surface.

    Returns
    ----------
    normal       : ndarray
                   Surface normal at the point of intersection.
    distance     : float
                   Distance in between starting point of a ray with it's intersection with a planar surface.
    """
    points = np.asarray(points)
    normal = get_triangle_normal(points)
    if len(ray.shape) == 2:
        ray = ray.reshape((1, 2, 3))
    if len(points) == 2:
        points = points.reshape((1, 3, 3))
    if len(normal.shape) == 2:
        normal = normal.reshape((1, 2, 3))
    f = normal[:, 0] - ray[:, 0]
    distance = np.dot(normal[:, 1], f.T) / np.dot(normal[:, 1], ray[:, 1].T)
    n = np.int(np.amax(np.array([ray.shape[0], normal.shape[0]])))
    normal = np.zeros((n, 2, 3))
    normal[:, 0] = ray[:, 0] + distance.T * ray[:, 1]
    distance = np.abs(distance)
    if normal.shape[0] == 1:
        normal = normal.reshape((2, 3))
        distance = distance.reshape((1))
    if distance.shape[0] == 1 and len(distance.shape) > 1:
        distance = distance.reshape((distance.shape[1]))
    return normal, distance
Пример #19
0
    def raytrace(self,ray,field=None,channel=0):
        """
        A definition to calculate the intersection between given ray(s) and the detector. If a ray contributes to the detector, field will be taken into account in calculating the field over the planar detector.
 
        Parameters
        ----------
        ray          : ndarray
                       Ray(s) to be intersected.
        field        : ndarray
                       Field(s) to be used for calculating contribution of rays to the detector.
        channel      : list
                       Which color channel to contribute to in the detector plane. Default is zero. One can use a list to select multiple channels separately.
 
        Returns
        ----------
        normal       : ndarray
                       Normal for each intersection point.
        distance     : ndarray
                       Distance for each ray.
        """
        normal,distance = intersect_w_surface(ray,self.plane)
        points          = bring_plane_to_origin(
                                                normal[:,0],
                                                self.plane,
                                                shape=self.settings["shape"],
                                                center=self.settings["center"],
                                                angles=self.settings["angles"],
                                                mode=self.settings["rotation mode"]
                                               )
        if points.shape[0] == 3:
            points = points.reshape((1,3))
        # This could improve with a bilinear filter. Basically removing int with a filter.
        detector_ids = np.array(
                                [
                                 (points[:,0]+self.settings["shape"][0]/2.)/self.settings["shape"][0]*self.settings["resolution"][0]+1,
                                 (points[:,1]+self.settings["shape"][1]/2.)/self.settings["shape"][1]*self.settings["resolution"][1]+1
                                ],
                                dtype=int
                               )
        detector_ids[0,:] = (detector_ids[0,:]>=1)*detector_ids[0,:]
        detector_ids[1,:] = (detector_ids[1,:]>=1)*detector_ids[1,:]
        detector_ids[0,:] = (detector_ids[0,:]<self.settings["resolution"][0]+1)*detector_ids[0,:]
        detector_ids[1,:] = (detector_ids[1,:]<self.settings["resolution"][1]+1)*detector_ids[1,:]
        cache             = np.zeros(
                                     (
                                      self.settings["resolution"][0]+1,
                                      self.settings["resolution"][1]+1,
                                      self.field.shape[2]
                                     ),
                                     dtype=np.complex64
                                    )

        ##################################################################
        # This solution is far from ideal. There has to be a better way. #
        ##################################################################
        for detector_id in range(0,detector_ids.shape[1]):
            x           = detector_ids[0,detector_id]
            y           = detector_ids[1,detector_id]
            r2          = distance[detector_id]**2
            if type(field) == type(None):
                cache[x,y] += 1000./r2
            else:
                cache[x,y] += field[x,y]/r2
        ##################################################################
        # This solution isn't working at all as two same ids are         #
        # interpretted as one.                                           #
        ##################################################################
        #cache[
        #       detector_ids[0],
        #       detector_ids[1],
        #       channel
        #      ]           += field
        ##################################################################
        self.field      += cache[1::,1::,:]
        return normal,distance