def __init__(self, pos, dirn, wavelength=None, intensity=1.0, index=AirIndex()): """ Constructor for to set parameters """ if isinstance(pos, ParaxialRay): Ray.__init__(self, pos.wavelength, pos.intensity, pos.refractiveindex) self.position = Vector3d(0.0, pos.h, pos.z) self.director = Unit3d(Angle(pos.u)) else: if isinstance(pos, SourcePoint): intensity = pos.spectrum Ray.__init__(self, wavelength, intensity, index) # Set wavelnegth intensity and index in super self.position = Vector3d( pos ) # Make localcopy of Position and Director (since they get updated) self.director = Unit3d(dirn) self.pathlength = None # Set opl to none (not calculated)
def getAngleDegrees(prompt, default=None): """ Read a Angle in theta/psi from the terminal in Degrees with checking. Format from terminal may be theta,psi OR '[theta,psi]', also each componet will be evaluated. :param prompt: the prompt to be displayed :type prompt: str :param default: the default value (may be None), this is assumes to be in radians. :type default: Angle :return: the Angle (note will always return an Angle in radians) Note: input values are in degrees but the returned Angle values are in radians. """ if default != None and isinstance(default, Angle): # Convert to degree for default default = default.getDegrees() while True: val = __getInput(prompt, default) try: if isinstance(val, str): # Its a string val = eval(val) # Eval list return Angle().setDegrees(val) except (ValueError, NameError, ZeroDivisionError, SyntaxError): logger.error("Conversion of '{0:s}' to Angle failed.".format(str(val)))
def main(): angle = Angle().setDegrees(30, 80) # Angle with theta = 30 , psi = 80 degrees tprint("Angle is : ", angle) # print, note tprint() automaticall take str() u = Unit3d(angle) # Convert to Unit3d tprint(repr(u)) # print using repr() angle = u.getAngle() # get angle from Unit3d theta, psi = angle.getDegrees() # get the angle as a list in degrees tprint("Theta is : ", theta, " and psi is : ", psi) # print it angle = getAngleDegrees("Get angle in degtrees") tprint(repr(angle)) u = Unit3d(angle) # Convert to Unit3d tprint(repr(u)) # print using repr()
def getAngle(self): """ Get the director an an Angle :return: Angle if valid, else None """ if self.isValid(): return Angle(self.director) else: return None
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
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)
def __init__(self, lens, source, refopt=0, wave=Default, design=None): """ The constrcutor """ self.lens = lens if isinstance(source, ray.SourcePoint): # From a sourcepoint self.source = source elif isinstance(source, float): self.source = Unit3d(Angle(source)) # Infinite Object else: self.source = Unit3d(source) self.setReference(refopt) self.wavelength = float(wave) if design == None: self.design = self.wavelength else: self.design = float(design) # Set up a basic knife edge aperture at 0,0,0 with default knife distance, angle and shift self.knife = KnifeAperture(0.0, self.lens.exitAperture().maxRadius)
def main(): # Get the materail type and make a prism of default angle, size and location n = MaterialIndex() prism = Prism(index=n) tprint(repr(prism)) # Get input point on prism and min deviation at Mercury_i line pt = prism.getInputPoint() dev = prism.minDeviation(Mercury_e) tprint("Min deviation : ", math.degrees(dev), " at : ", Mercury_e) tprint("Max resolutions is ", prism.maxResolution(Mercury_e)) tprint("Resolution with 20 mm diameter beam : ", prism.resolution(10, Mercury_e)) u = Unit3d().parseAngle(dev / 2) # Set ray input angle at half min deviation # Form np array of wavelength and angle wavelengths = np.linspace(Mercury_i, Helium_r, 50) angle = np.zeros(wavelengths.size) # Go through each wavelength, make a ray and trace it for i, wave in enumerate(wavelengths): ray = r.IntensityRay(pt, u, wave) ray *= prism # Extract angle of ray in degrees angle[i] = math.degrees(Angle(ray.director).theta) # Do the plotting plt.plot(wavelengths, angle) plt.title("Spectrometer Output angle") plt.xlabel("Wavelength in microns") plt.ylabel("Output angle in degrees") plt.grid() plt.show()
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 wave = getFloat("Wavelength", getDefaultWavelength()) # Get optimal area psf and create a SpotDiagram sd = SpotAnalysis(lens, u, 0, wavelength=wave) # Go round loop plotting the sopt diagram as various zplane positions while True: zp = getFloat("Delta", 0.0) sd.draw(zp, True) pos = sd.plane.getPoint().z print("Plane pos " + str(pos)) plt.title("Spot diagram") plt.show(block=True)
def __init__(self, lens, source=0.0, refopt=0, wavelength=None, design=None): """ The constrcutor """ # Sort out source if isinstance(source, ray.SourcePoint): # From a sourcepoint self.source = source elif isinstance(source, float): self.source = Unit3d(Angle(source)) # Infinite Object else: self.source = Unit3d(source) wave = getDefaultWavelength(wavelength) design = getDesignWavelength(design) # Make raypencil (this is used in draw()) self.raypencil = ray.RayPencil().addBeam(lens, source, "array", wavelength=wave) self.raypencil *= lens # Propagate through lens self.pt = lens.imagePoint(source, design) if refopt == 1: self.pt = Psf().setWithRays( self.raypencil, self.pt.z) # Centre of PSF in image plane if refopt == 2: self.pt = Psf().optimalArea( self.raypencil, self.pt.z) # Optimal area PSF, not in image plane
def getAngle(prompt, default=None): """ Read a Angle in theta/psi fromat the terminal with checking. Format from terminal may be 'theta,psi' OR '[theta,psi]', also each componet will be evaluated. :param prompt: the prompt to be displayed :type prompt: str :param default: the default value (may be None) :type default: Angle :return: the Angle (note will always return an Angle) Note: input values are in radians. """ while True: val = __getInput(prompt, default) try: if isinstance(val, str): # Its a string val = eval(val) # Eval list return Angle(val) except (ValueError, NameError, ZeroDivisionError, SyntaxError): logger.error("Conversion of '{0:s}' to Angle failed.".format(str(val)))
def getWavelength(prism, inAngle, outAngle, wavelengths=[0.25, 1.0]): # Get prism point and angle of input at Unit3d # pt = prism.getInputPoint() u = Unit3d(Angle(inAngle)) # Guess at initial wavelngth wave = (wavelengths[1] - wavelengths[0]) / 2 # Make input ray at guess wavelength ray = IntensityRay(pt, u, wave) # Parameters for seaerch delta = 0.1 forward = True na = float("inf") # New angle while abs(na - outAngle) > 1.0e-9 / abs(outAngle): nray = ray * prism # New Ray through prism na = nray.getAngle() na = na.theta * math.cos(na.psi) # In radians if na < outAngle: # Less that target wave += delta forward = True else: if forward: # Half step delta *= 0.5 forward = False wave -= delta if wave < wavelengths[0] or wave > wavelengths[1]: print("Out of wavelength range :") return float("nan") ray.wavelength = wave # Update wavelength of ray return ray.getWavelength() # End of loop, so success
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()