Example #1
0
    def setWithRays(self, pencil, plane):
        """
        Set PSF from RayPencil in a specifed OpticalPlane, note this work
        for curved planes, such as optics.surface.SphericalOpticalPlane
        as well as the normal flat planes.

        :param pencil: The RayPencil (note only valid rays are considered)
        :type pencil: RayPencil
        :param plane: The OpticalPlane, of if float OpticalPlane as (0,0,plane)
        :type plane: OpticalPlane or float or None

        This is th main used method to calcaute a psf in a plane.
        """

        if isinstance(plane, (float, int)) or isinstance(plane, Vector3d):
            plane = OpticalPlane(plane)
        #          Form the moments

        moments = FixedMoments()  # Initialse
        for r in pencil:
            if r:
                pt = r.pointInPlane(plane)
                moments.addPoint(pt)
                self.wavelength = r.wavelength

        # Get the poisting of the centre of the Psf from the moments.
        self.set(plane.getSourcePoint(moments.centroid()))
        # Get the other parameters from the moments.
        self.major, self.minor, self.alpha = moments.ellipse()
        return self
Example #2
0
    def draw(self, plane, drawpsf=True):
        """
        Draw the spot disagram to the current active MatPlotLib as circles
        with the centre given my the wavelelength of the first ray.

        :param plane: the plane where the diagram is located.
        :param drawpsf: draw the geometric psf on the disgram, (default = True)

        """

        # Make an optical plane if needed
        if isinstance(plane, float) or isinstance(plane, Vector3d):
            plane = OpticalPlane(plane)

        xData = []  # X and Y point locations
        yData = []

        for r in self.raypencil:
            if r:
                pt = r.pointInPlane(plane)  # Find the point in the plane
                xData.append(pt.x)
                yData.append(pt.y)

        #     Get the colour of the ray as a hex string
        col = WavelengthColour(self.raypencil[0].wavelength)
        #     Scatter plot to the current figure
        axis('equal')
        scatter(xData, yData, color=col, marker='o')
        if drawpsf:  # Make a psf if required and plot it
            psf = Psf().setWithRays(self.raypencil, plane)
            psf.draw()
Example #3
0
    def optimalArea(self, pencil, plane):
        """
        Method to find the optimal area PSF from a raypencil starting
        as the guess locaion plane.

        This uses a simple itterative search bit provided that a reasonable guess is
        given for the inituial plane it converes quickly. The initial guess would normally
        be the paraxial image plane.

        :param pencil: the pencil or rays
        :param plane: the guess at the optimal plane, typically the paraxial plane.
        :return: the optimal psf

        Note the rays in the pencil are NOT changed.
        """
        if isinstance(plane, float) or isinstance(plane, Vector3d):
            plane = OpticalPlane(plane)

        #            set with initial condition tio local psf.
        psf = self.setWithRays(pencil, plane)
        area = psf.area()
        wave = pencil[0].wavelength / 1000  # Wavelengh in mm
        delta = -0.25  # Initial plane movement (usually it optmimal is short)
        deltaReduced = True  # reversal flag

        #            Loop looking for best
        while True:
            pl = plane.incrementSurface(delta)  # Increment plane by delta
            self = Psf().setWithRays(pencil, pl)  # Make new psf
            na = self.area()
            if na < area:  # Accept
                plane = pl  # Accept plane
                area = na
                deltaReduced = False
                if abs(delta) < wave:
                    break
            else:  # Dont accept
                if deltaReduced:  # Delta not reduced last time
                    delta = -delta
                    deltaReduced = False
                else:
                    delta *= 0.25  # Reduce delta
                    deltaReduced = True
        #
        #        Found best PSF, in self, just return

        return self
Example #4
0
    def draw(self, delta=0.0, drawpsf=True):
        """
        Draw the diagram

        :param delta: displacement of plane from reference point (Default = 0.0)
        :type delta: float
        :param drawpsf: draw the geometric psf (Default = True)

        """
        #        Calcualte location of the plane
        self.plane = OpticalPlane(self.pt.z + delta)
        SpotDiagram.draw(self, self.plane, drawpsf)  # Use underlying draw
Example #5
0
    def setWithRay(self,ray, plane, refpt = None):
        """
        Set the value in a specifed plane using a ray and optional reference point. This is
        the main method used to calcuuate wavefront abberations in a plane wrt to a specificied
        refererence point.

        :param ray: The intensity ray
        :param plane: The flat plan in which to form the wavepoint
        :param refpt: The reference point. This assumed to be the image point.

        """

        if isinstance(plane,float):                               # If plane as float, make a plane
            plane = OpticalPlane(plane)

        self.wavelength = ray.wavelength
        self.set(ray.pointInPlane(plane))                          # set self to point in plane.
        distance = plane.getDistance(ray.position,ray.director)    # get distance from ray to plane.

        if refpt != None:                                          # Deal with reference point
            ref = refpt - plane.getPoint()                         # Ref point relative to centre of plane.

            xc = self.x - ref.x         # Position relative to ref
            yc = self.y - ref.y
            c = 1.0/ref.z               # Curvature
            u = ray.director             # direction of ray
            #
            #     Distance to reference sphere (same code as in QuadricSurface)
            f = c*(xc*xc + yc*yc)
            g = u.z - c*(xc*u.x + yc*u.y)
            a = g*g - c*f
            if a < 0:
                raise ValueError("analysis.WavePoint: ray misses reference sphere")
            else:
                distance += f/(g + math.sqrt(a))

        # set total pathlength, pathleng of ray + pathlength to plane
        self.pathlength = ray.pathlength + distance*ray.refractiveindex.getValue(ray.wavelength)

        return self
Example #6
0
    def getWavePointSet(self,source,wave = None,nrays = 10,refopt = 1):
        """
        Get the WavePointSet for collimated beam in the exitpupil of the lens

        :param source: source of input beeam, either SourcePoint, Unit3d or angle.
        :type source: SourcePoint, Unit3d, Angle or float
        :param wave: analysis wavelength
        :type wave: float
        :param nrays: number of raays across input aperture, (Default = 10)
        :type nrays: int
        :param refopt: reference point option, 0 = paraxial, 1 = centre of PSF in image plane, 2 = optimal area PSF
        :type refopt: int
        """
        #       Sort out angle
        if isinstance(source,SourcePoint):
            u = Vector3d(source)
        elif isinstance(source,float) or isinstance(source,int):
            u = Unit3d(Angle(source))
        else:
            u = Unit3d(source)

        #      Make pencil with array and record path, and propagate through lens
        pencil = RayPencil().addBeam(self.lens,u,"array",nrays=nrays,wavelength=wave,path=True)
        pencil *= self.lens

        #        Get image point of object
        self.refpt = self.lens.imagePoint(u,self.design)    # Paraxial point location
        pt = self.lens.getPoint()
        self.ip = OpticalPlane(Vector3d(pt.x,pt.y,self.refpt.z))

        if refopt == 0:       # got what we need aready
            None
        elif refopt == 1:
            self.refpt = Psf().setWithRays(pencil,self.ip)              # Centre of PSF in image plane
        elif refopt == 2:
            self.refpt = Psf().optimalArea(pencil,self.ip)              # Optimal area PSF, not in image plane
        else:
            print("Illegal ref type")

        ep = self.lens.exitPupil(self.design)         # Exit pupil of lens

        #     Form the wavefront
        wf = WavePointSet(ep.getRadius()).setWithRays(pencil,ep,self.refpt)
        return wf
Example #7
0
    def setWithRays(self,pencil,plane,refpt = None):
        """
        Create a set of wavepoint from a pencil, in a specified plane with an optional reference point

        :param pencil: The raypencil containing a list of arrays
        :param plane: the plane of the wavepoints.
        :param refpt: The reference point, may be None.

        """

        if isinstance(plane,float):      # If plane as float, make a plane
            plane = OpticalPlane(plane)
        self.plane = plane               # Record plane
        #if hasattr(plane, "maxRadius"):
        #    self.maxRadius = plane.maxRadius # Set to plane maxradius if defined
        for r in pencil:
            if r:                        # Only take valid rays.
                self.add(WavePoint().setWithRay(r,plane,refpt))

        return self
Example #8
0
def main():

    #      Get lens from database
    lens = DataBaseLens()

    #           Get angle of beam and wavelnegth
    angle = getFloat("Angle in degrees", 0.0, 0.0, 15.0)
    u = Unit3d(Angle().setDegrees(angle))  # Angle as unit vectr
    w = getFloat("Wavelength", Default)

    #    Make two ray pencils, one for spot diagram and one for display (vertical only)
    pencil = RayPencil().addBeam(lens, u, "array", wavelength=w)
    vpencil = RayPencil().addBeam(lens, u, "vl",
                                  wavelength=w).addMonitor(RayPath())
    bf = lens.backFocalPlane()

    #            Propagate through lens to back focal plane
    pencil *= lens

    vpencil *= lens
    vpencil *= bf

    #            Get optimal area psf and create a SpotDiagram
    sd = SpotDiagram(pencil)

    #             Go round loop plotting the sopt diagram as various zplane positions

    while True:
        zp = getFloat("Zplane", bf.getPoint().z)
        plane = OpticalPlane(zp)
        plt.subplot(2, 1, 1)
        lens.draw()
        vpencil.draw()
        plt.axis("equal")
        plt.title("Lens " + lens.title)

        plt.subplot(2, 1, 2)
        sd.draw(plane, True)
        plt.title("Spot diagram")
        plt.show(block=True)
Example #9
0
    def drawAberrationPlot(self,angle,wavelength = None ,colour=["r","g","b"],legend = "lower left"):
        """
        Form and draw the plots at specified angle

        :param angle: the ray angle
        :type angle: float or Angle or Unit3d
        :param colour: line colours is three elemnts list, Default = ["r","g","b"])
        :param legend: location of ledgend, (Default = "lower left")
        :type legend: str
        """
        if isinstance(angle,float):
            u = Unit3d(Angle(angle))                     # direction of beam
        else:
            u = Unit3d(angle)
            angle = Angle(u).theta

        wavelength = getDefaultWavelength(wavelength)
        ref = self.lens.imagePoint(u,self.design)    # Get image point at design wavelength
        ip = OpticalPlane(ref)                        # Image plane

        nrays = 50
        ca = self.lens.entranceAperture()


        #         Make list for plots
        mvals = []                # Meridional
        svalsx = []               # Sagittal x
        svalsy = []               # Sagittal y


        #              Start of loop to make rays
        rscan = np.linspace(-ca.maxRadius,ca.maxRadius,nrays + 1)
        for r in rscan:
            # Make two rays
            mray = IntensityRay(ca.point + Vector3d(0.0, r, 0.0), u, wavelength)
            sray = IntensityRay(ca.point + Vector3d(r, 0.0, 0.0), u, wavelength)

            #       Add to pencil and propagate both back to clear lens
            pencil = RayPencil(mray,sray).propagate(-ca.maxRadius)
            #         propagate through lens to image surafce
            pencil *= self.lens
            pencil *= ip

            #            If rays valid (so not blocked), abberations to list
            if mray:
                mpos = mray.position - ref
                mvals.append(mpos.y)
            else:
                mvals.append(float("nan"))
            if sray:
                spos = sray.position - ref
                svalsx.append(spos.x)
                svalsy.append(spos.y)
            else:
                svalsx.append(float("nan"))
                svalsy.append(float("nan"))


        # plots with suitable labels to the current axis.

        plt.plot(rscan,mvals, color = colour[0], label="Meridional")
        plt.plot(rscan,svalsx,color = colour[1], label="Sagittal x")
        plt.plot(rscan,svalsy,color = colour[2], label="Sagittal y")
        plt.title("{0:s}: a: {1:4.2f} w: {2:4.2f} d: {3:4.2f}".\
                  format(self.lens.title,math.degrees(angle),wavelength,\
                  self.design))
        plt.legend(loc=legend,fontsize="small")
        plt.grid()