DCC-Lab/RayTracing

GRIN

Closed this issue · 1 comments

dccote commented

Adding GRIN is not easy: they need to be split in smaller GRINs for display purposes. Here is some code that works, but is not that good looking:

from raytracing import *


class GRIN(MatrixGroup):
    r"""Gradient index (GRIN) lens of length L, with a quadratic index of refraction.

    The index is given by n^2 = n0^2 * ( 1 - r^2 alpha^2) ≈ n0 * ( 1 - 1/2 * r^2 alpha^2)
    At Thorlabs, the alpha parameter is equal to √A.
    An example is here: https://www.thorlabs.com/newgrouppage9.cfm?objectgroup_ID=11167

    A ray propagating in a GRIN will oscillate up and down.  The number of complete oscillations
    is called the pitch. You can initialize with either the alpha parameter (which is a physical parameter)
    or the pitch (which is a usage parameter).

    Parameters
    ----------
    d : float
        the length of the GRIN
    n0 : float
        The base refraction index of the GRIN. This value cannot be negative. (default=1)
    alpha : float
        The quadratic parameter for the index (default= None)
    pitch : float
        The pitch parameter of the the GRIN (number of oscillations alpha*L = 2*pi*pitch) (default=None)
    diameter: float
        Diameter of GRIN (default = infinity)
    label : string
        The label of the free space

    """

    def __init__(self, L, N=100, n0=1, alpha=None, pitch=None, diameter=float('+Inf'), label=''):

        if alpha is None and pitch is None:
            raise ValueError("You must set either alpha or the pitch (but not both)")

        if alpha is None:
            alpha = 2*pi*pitch/L
        elif pitch is None:
            pitch = alpha*L/2/pi

        self.n0 = n0
        self.alpha = alpha
        self.pitch = pitch
        self.dz = L/N # 20 pts per cycle
        if self.pitch > 1:
            self.dz /= self.pitch

        elements = []
        for i in range(N):
            dzMatrix = Matrix(A=cos(alpha*self.dz),
                            B=1/alpha*sin(alpha*self.dz),
                            C=-alpha*sin(alpha*self.dz),
                            D=cos(alpha*self.dz),
                            physicalLength=self.dz,
                            frontVertex=0,
                            backVertex=self.dz,
                            frontIndex=n0,
                            backIndex=n0,
                            apertureDiameter=diameter,
                            label=label)
            elements.append(dzMatrix)

        super().__init__(elements=elements)

    def transferMatrix(self, upTo=float('+Inf'), startingAt=float(0)):
        """ Returns a Matrix() corresponding to a partial propagation
        if the requested distance is smaller than the length of this element.
        You can have a 

        Parameters
        ----------
        upTo : float
            The length of the propagation (default=Inf)

        Returns
        -------
        transferMatrix : object of class Matrix
            the corresponding matrix to the propagation

        """
        if upTo > self.L:
            upTo = self.L

        if startingAt > upTo:
            raise ValueError("In transferMatrix(), `startingAt` {0} must be smaller than `upTo` {1}".format(startingAt, upTo))

        distance = upTo-startingAt

        if distance < self.L:
            return GRIN(L=distance, n0=self.n0, alpha=self.alpha, diameter=self.apertureDiameter, label=self.label)
        else:
            return self

if __name__ == "__main__":
    path = ImagingPath()
    path.append(Space(d=10))
    path.append(GRIN(10, n0=1, pitch=1, diameter=8, label=''))
    path.display()

Stale issue message