Modelling of a Shack-Hartmann Sensor for eye aberration evaluation - original example#
This example directly mimics the knowledge base example Modelling of a Shack-Hartmann Sensor for eye aberration evaluation. It uses ZOSPy to control the API.
Included functionalities#
Sequential mode:
System design:
Usage of
zospy.functions.lde.surface_change_type()to change the surface type, including the use of user defined surfacesUsage of
zospy.functions.lde.surface_change_aperturetype()to change the aperture type of a specific surface.Usage of
zospy.solvers.material_model()to change the material of a surface.Usage of the
PhysicalOpticsDataattribute of a surface to alter specific physical optics settingsUsage of the
CoatingDataattribute of a surface to alter specific coating settingsUsage of
oss.MCEto access the multiple configurations editor and specify various configurations of the same model.Usage of
oss.SystemDatato adjust specific system settings
Analysis:
Usage of
zospy.analyses.wavefront.zernike_standard_coefficients()to perform a Zernike standard coefficients analysis.Usage of
zospy.analyses.wavefront.wavefront_map()to perform a wavefront map analysis.Usage of
zospy.analyses.extendedscene.geometric_image_analysis()to perform a geometric image analysis.Usage of
zospy.analyses.physicaloptics.pop_create_beam_parameter_dict()to obtain and alter the default beam parameters for a specific physical optics propagation beam type.Usage of
zospy.analyses.physicaloptics.physical_optics_propagation()to perform a physical optics propagation analysis.
Warranty and liability#
The examples are provided ‘as is’. There is no warranty and rights cannot be derived from them, as is also stated in the general license of this repository.
Import dependencies#
[1]:
from warnings import warn
import matplotlib.pyplot as plt
import zospy as zp
from zospy.functions.lde import surface_change_aperturetype, surface_change_type
from zospy.solvers import material_model
Initialize OpticStudio#
Establishing a connection with OpticStudio through the ZOSPy library.
In this example we connect with OpticStudio in extension mode.
[2]:
zos = zp.ZOS()
oss = zos.connect(mode="extension")
A new system is directly created and it is ensured that it is in sequential mode.
[3]:
oss.new()
oss.make_sequential()
[3]:
True
Create eye#
In this section, we create the reversed eye model.
To keep track of the amount of surfaces we have implemented, we utilize a constant called n_surf
[4]:
n_surf = 0 # Make sure we start at surface 0.
# Object
s_object = oss.LDE.GetSurfaceAt(n_surf)
n_surf += 1
s_object.Thickness = 0
# Retina
s_eye_retina = oss.LDE.InsertNewSurfaceAt(n_surf)
n_surf += 1
s_eye_retina.Comment = "Eye Retina Vitreous"
s_eye_retina.Radius = 12.0
s_eye_retina.Thickness = 17.928551
material_model(s_eye_retina.MaterialCell, refractive_index=1.336, abbe_number=50.23)
s_eye_retina.Conic = 0.0
s_eye_retina.SemiDiameter = 12
# Lens back
s_eye_lensback = oss.LDE.InsertNewSurfaceAt(n_surf)
n_surf += 1
surface_change_type(s_eye_lensback, zp.constants.Editors.LDE.SurfaceType.Gradient3)
s_eye_lensback.Comment = "Eye Lens Back"
s_eye_lensback.Radius = 8.1
s_eye_lensback.Thickness = 2.430
s_eye_lensback.Conic = 0.960
s_eye_lensback.SemiDiameter = 5
s_eye_lensback.SurfaceData.DeltaT = 1.0
s_eye_lensback.SurfaceData.n0 = 1.407
s_eye_lensback.SurfaceData.Nr2 = -1.978e-03
s_eye_lensback.SurfaceData.Nz1 = 0.0
s_eye_lensback.SurfaceData.Nz2 = -6.605e-03
s_eye_lensback.PhysicalOpticsData.UseRaysToPropagateToNextSurface = True
# Lens front
s_eye_lensfront = oss.LDE.InsertNewSurfaceAt(n_surf)
n_surf += 1
surface_change_type(s_eye_lensfront, zp.constants.Editors.LDE.SurfaceType.Gradient3)
s_eye_lensfront.Comment = "Eye Lens Front"
s_eye_lensfront.Radius = 0.0
s_eye_lensfront.Thickness = 1.590
s_eye_lensfront.Conic = 0.0
s_eye_lensfront.SemiDiameter = 5
s_eye_lensfront.SurfaceData.DeltaT = 1.0
s_eye_lensfront.SurfaceData.n0 = 1.368
s_eye_lensfront.SurfaceData.Nr2 = -1.978e-03
s_eye_lensfront.SurfaceData.Nz1 = -0.049057
s_eye_lensfront.SurfaceData.Nz2 = -0.015427
s_eye_lensfront.PhysicalOpticsData.UseRaysToPropagateToNextSurface = True
# Posterior chamber
s_eye_posteriorchamber = oss.LDE.InsertNewSurfaceAt(n_surf)
n_surf += 1
s_eye_posteriorchamber.Comment = "Posterior chamber"
s_eye_posteriorchamber.Radius = -12.40
s_eye_posteriorchamber.Thickness = 0.0
material_model(s_eye_posteriorchamber.MaterialCell, refractive_index=1.336, abbe_number=50.23)
s_eye_posteriorchamber.Conic = 0.0
s_eye_posteriorchamber.SemiDiameter = 5.0
s_eye_posteriorchamber.PhysicalOpticsData.UseRaysToPropagateToNextSurface = True
# Pupil
s_eye_pupil = oss.LDE.GetSurfaceAt(n_surf)
n_surf += 1
s_eye_pupil.Comment = "Pupil"
s_eye_pupil.Radius = 0.0 # Check
s_eye_pupil.Thickness = 3.160 # Check for oblique rays, if possible remove next surface
material_model(s_eye_pupil.MaterialCell, refractive_index=1.336, abbe_number=50.23)
s_eye_pupil.Conic = 0.0
s_eye_pupil.SemiDiameter = 2.0
surface_change_aperturetype(s_eye_pupil, zp.constants.Editors.LDE.SurfaceApertureTypes.FloatingAperture)
# Cornea back
s_eye_corneaback = oss.LDE.InsertNewSurfaceAt(n_surf)
n_surf += 1
s_eye_corneaback.Comment = "Cornea Back"
s_eye_corneaback.Radius = -6.40
s_eye_corneaback.Thickness = 0.550
material_model(s_eye_corneaback.MaterialCell, refractive_index=1.376, abbe_number=50.23)
s_eye_corneaback.Conic = -0.60
s_eye_corneaback.SemiDiameter = 5.0
# Cornea front
s_eye_corneafront = oss.LDE.InsertNewSurfaceAt(n_surf)
n_surf += 1
s_eye_corneafront.Comment = "Cornea Front"
s_eye_corneafront.Radius = -7.770
s_eye_corneafrontThickness = 0.0
s_eye_corneafront.Conic = -0.18
s_eye_corneafront.SemiDiameter = 5.0
MCE#
Now that we created a reversed eye model, we use the multi configuration editor to ensure that we can switch between several variants of the same system and analyse them.
[5]:
oss.MCE.ShowEditor()
# Insert extra configurations
oss.MCE.InsertConfiguration(2, False)
oss.MCE.InsertConfiguration(3, False)
[5]:
True
The first two rows in the MCE are of the ‘IGNM’ operand type, allowing you to ignore a (range of) surface(s) in a specific configuration. While these two rows are not used in the knowledge base example, we keep them for consistency.
[6]:
mce_1 = oss.MCE.GetOperandAt(1)
mce_1.ChangeType(zp.constants.Editors.MCE.MultiConfigOperandType.IGNM)
mce_1.GetOperandCell(1).IntegerValue = 0
mce_1.GetOperandCell(2).IntegerValue = 0
mce_1.GetOperandCell(3).IntegerValue = 0
mce_1.Param1 = s_eye_retina.SurfaceNumber - 1 # minus 1 as param 1 omits object in list
mce_1.Param2 = s_eye_posteriorchamber.SurfaceNumber
mce_2 = oss.MCE.InsertNewOperandAt(2)
mce_2.ChangeType(zp.constants.Editors.MCE.MultiConfigOperandType.IGNM)
mce_2.GetOperandCell(1).IntegerValue = 0
mce_2.GetOperandCell(2).IntegerValue = 0
mce_2.GetOperandCell(3).IntegerValue = 0
# mce_2 gets updated later as it requires the HS sensor to be defined
The third row of the MCE uses the ‘MOFF’ operand, which can be used for comments. It is used to describe the three variations of the eye model (Normal, Myopic, Hypermetropic).
[7]:
mce_3 = oss.MCE.InsertNewOperandAt(3)
mce_3.ChangeType(zp.constants.Editors.MCE.MultiConfigOperandType.MOFF)
mce_3.GetOperandCell(1).Value = "Normal"
mce_3.GetOperandCell(2).Value = "Myopia"
mce_3.GetOperandCell(3).Value = "Hyperopia"
The fourth row of the MCE uses the ‘THIC’ operand, which can be used to change the thickness of a specific surface. It is used to variate the length of the vitrous between the three states of the eye model (Normal, Myopic, Hypermetropic).
[8]:
mce_4 = oss.MCE.InsertNewOperandAt(4)
mce_4.ChangeType(zp.constants.Editors.MCE.MultiConfigOperandType.THIC)
mce_4.Param1 = s_eye_retina.SurfaceNumber
mce_4.GetOperandCell(1).DoubleValue = 17.928551048789998
mce_4.GetOperandCell(2).DoubleValue = 25.000 # 27.000
mce_4.GetOperandCell(3).DoubleValue = 11.000 # 13.000
System settings#
Now we adjust some system settings to ensure we have the same settings as the knowledge base example.
[9]:
# Aperture
oss.SystemData.Aperture.ApertureType = (
zp.constants.SystemData.ZemaxApertureType
) = zp.constants.SystemData.ZemaxApertureType.FloatByStopSize
oss.SystemData.Aperture.ApodizationType = zp.constants.SystemData.ZemaxApodizationType.Gaussian
oss.SystemData.Aperture.ApodizationFactor = 1.0
oss.SystemData.Aperture.AFocalImageSpace = False # True <- file of example does not have afocal image space
# Rayaiming
oss.SystemData.RayAiming.RayAiming = zp.constants.SystemData.RayAimingMethod.Paraxial
# Advanced
oss.SystemData.Advanced.ReferenceOPD = zp.constants.SystemData.ReferenceOPDSetting.Absolute
oss.SystemData.Advanced.HuygensIntegralMethod = zp.constants.SystemData.HuygensIntegralSettings.Planar
# Wavelength
wl1 = oss.SystemData.Wavelengths.GetWavelength(1)
wl1.Wavelength = 0.830
Telescopes#
In this section, we define the two telescopes between the eye and the Shack-Hartmann sensor.
Telescope 1#
Telescope 1 consists of 6 surfaces, some with a different surface aperture type or coating
[10]:
# Telescope 1 - surface 1
s_tel1_1 = oss.LDE.InsertNewSurfaceAt(n_surf)
n_surf += 1
s_tel1_1.Radius = 0.0
s_tel1_1.Thickness = 95.200
s_tel1_1.SemiDiameter = 10
# Telescope 1 - surface 2
s_tel1_2 = oss.LDE.InsertNewSurfaceAt(n_surf)
n_surf += 1
s_tel1_2.Radius = 102.5
s_tel1_2.Thickness = 5.0
s_tel1_2.Material = "N-BK7"
s_tel1_2.SemiDiameter = 14.5
s_tel1_2.ChipZone = 0.5
surface_change_aperturetype(
s_tel1_2, zp.constants.Editors.LDE.SurfaceApertureTypes.CircularAperture, maximum_radius=14.5
)
s_tel1_2.CoatingData.Coating = "THORB"
# Telescope 1 - surface 3
s_tel1_3 = oss.LDE.InsertNewSurfaceAt(n_surf)
n_surf += 1
s_tel1_3.Radius = -102.5
s_tel1_3.Thickness = 199.0
s_tel1_3.SemiDiameter = 14.5
s_tel1_3.ChipZone = 0.5
s_tel1_3.CoatingData.Coating = "THORB"
# Telescope 1 - surface 4
s_tel1_4 = oss.LDE.InsertNewSurfaceAt(n_surf)
n_surf += 1
s_tel1_4.Radius = 102.5
s_tel1_4.Thickness = 5.0
s_tel1_4.Material = "N-BK7"
s_tel1_4.SemiDiameter = 14.5
s_tel1_4.ChipZone = 0.5
surface_change_aperturetype(
s_tel1_4, zp.constants.Editors.LDE.SurfaceApertureTypes.CircularAperture, maximum_radius=14.5
)
s_tel1_4.CoatingData.Coating = "THORB"
# Telescope 1 - surface 5
s_tel1_5 = oss.LDE.InsertNewSurfaceAt(n_surf)
n_surf += 1
s_tel1_5.Radius = -102.5
s_tel1_5.Thickness = 99.5
s_tel1_5.SemiDiameter = 14.5
s_tel1_5.ChipZone = 0.5
s_tel1_5.CoatingData.Coating = "THORB"
# Telescope 1 - surface 6
s_tel1_6 = oss.LDE.InsertNewSurfaceAt(n_surf)
n_surf += 1
s_tel1_6.Comment = "ph"
s_tel1_6.Radius = 0.0
s_tel1_6.Thickness = 0.0
s_tel1_6.SemiDiameter = 6.0
surface_change_aperturetype(
s_tel1_6, zp.constants.Editors.LDE.SurfaceApertureTypes.CircularObscuration, minimum_radius=6, maximum_radius=12
)
We also make surface 6 of telescope 1 the global coordinate reference
[11]:
s_tel1_6.TypeData.IsGlobalCoordinateReference = True
Telescope 2#
Telescope 2 consists of 9 surfaces, some with a different surface aperture type or coating
[12]:
# Telescope 2 - surface 1
s_tel2_1 = oss.LDE.InsertNewSurfaceAt(n_surf)
n_surf += 1
s_tel2_1.Radius = 0.0
s_tel2_1.Thickness = 99.5
s_tel2_1.SemiDiameter = 6.0
s_tel2_1.MechanicalSemiDiameter = 12.0
# Telescope 2 - surface 2
s_tel2_2 = oss.LDE.InsertNewSurfaceAt(n_surf)
n_surf += 1
s_tel2_2.Radius = 102.5
s_tel2_2.Thickness = 5.0
s_tel2_2.Material = "N-BK7"
s_tel2_2.SemiDiameter = 14.5
s_tel2_2.ChipZone = 0.5
surface_change_aperturetype(
s_tel2_2, zp.constants.Editors.LDE.SurfaceApertureTypes.CircularAperture, maximum_radius=14.5
)
s_tel2_2.CoatingData.Coating = "THORB"
# Telescope 2 - surface 3
s_tel2_3 = oss.LDE.InsertNewSurfaceAt(n_surf)
n_surf += 1
s_tel2_3.Radius = -102.5
s_tel2_3.Thickness = 99.5
s_tel2_3.SemiDiameter = 14.5
s_tel2_3.ChipZone = 0.5
s_tel2_3.CoatingData.Coating = "THORB"
# Telescope 2 - surface 4
s_tel2_4 = oss.LDE.InsertNewSurfaceAt(n_surf)
n_surf += 1
s_tel2_4.Comment = "ph"
s_tel2_4.Radius = 0.0
s_tel2_4.Thickness = 0.0
s_tel2_4.SemiDiameter = 3.0
surface_change_aperturetype(
s_tel2_4, zp.constants.Editors.LDE.SurfaceApertureTypes.CircularObscuration, minimum_radius=20, maximum_radius=20
)
# Telescope 2 - surface 5
s_tel2_5 = oss.LDE.InsertNewSurfaceAt(n_surf)
n_surf += 1
s_tel2_5.Radius = 0.0
s_tel2_5.Thickness = 99.5
s_tel2_5.SemiDiameter = 14.5
# Telescope 2 - surface 6
s_tel2_6 = oss.LDE.InsertNewSurfaceAt(n_surf)
n_surf += 1
s_tel2_6.Radius = 102.5
s_tel2_6.Thickness = 5.0
s_tel2_6.Material = "N-BK7"
s_tel2_6.SemiDiameter = 14.5
s_tel2_6.ChipZone = 0.5
surface_change_aperturetype(
s_tel2_6, zp.constants.Editors.LDE.SurfaceApertureTypes.CircularAperture, maximum_radius=14.5
)
s_tel2_6.CoatingData.Coating = "THORB"
# Telescope 2 - surface 7
s_tel2_7 = oss.LDE.InsertNewSurfaceAt(n_surf)
n_surf += 1
s_tel2_7.Radius = -102.5
s_tel2_7.Thickness = 0.0
s_tel2_7.SemiDiameter = 14.5
s_tel2_7.ChipZone = 0.5
s_tel2_7.CoatingData.Coating = "THORB"
# Telescope 2 - surface 8
s_tel2_8 = oss.LDE.InsertNewSurfaceAt(n_surf)
n_surf += 1
s_tel2_8.Radius = 0.0
s_tel2_8.Thickness = 99.5
s_tel2_8.SemiDiameter = 6
# Telescope 2 - surface 9
s_tel2_9 = oss.LDE.InsertNewSurfaceAt(n_surf)
n_surf += 1
s_tel2_9.Radius = 0.0
s_tel2_9.Thickness = 0.0
Shack-Hartmann Sensor#
Now, we create the Shack-Hartmann Sensor. It consists of three surfaces. Note that on surface 1, we make sure ResampleAfterRefraction is on and configured. We also use a user defined surface with specific settings for surface 2.
[13]:
# Shack-Hartmann sensor - surface 1
s_hs_1 = oss.LDE.InsertNewSurfaceAt(n_surf)
n_surf += 1
s_hs_1.Radius = 0.0
s_hs_1.Thickness = 1.200
s_hs_1.Material = "LITHOSIL-Q"
s_hs_1.SemiDiameter = 6.000
s_hs_1.PhysicalOpticsData.ResampleAfterRefraction = True
s_hs_1.PhysicalOpticsData.XSampling = zp.constants.Editors.LDE.XYSampling.S1024
s_hs_1.PhysicalOpticsData.YSampling = zp.constants.Editors.LDE.XYSampling.S1024
s_hs_1.PhysicalOpticsData.XWidth = 10
s_hs_1.PhysicalOpticsData.YWidth = 10
surface_change_aperturetype(
s_hs_1, zp.constants.Editors.LDE.SurfaceApertureTypes.RectangularAperture, x_half_width=6, y_half_width=6
)
# Shack-Hartmann sensor - surface 2
s_hs_2 = oss.LDE.InsertNewSurfaceAt(n_surf)
n_surf += 1
surface_change_type(s_hs_2, zp.constants.Editors.LDE.SurfaceType.UserDefined, filename="us_array.dll")
s_hs_2.Radius = -2.00
s_hs_2.Thickness = 5.600
s_hs_2.SemiDiameter = 6.000
s_hs_2.GetSurfaceCell(zp.constants.Editors.LDE.SurfaceColumn.Par1).DoubleValue = 35.000
s_hs_2.GetSurfaceCell(zp.constants.Editors.LDE.SurfaceColumn.Par2).DoubleValue = 35.000
s_hs_2.GetSurfaceCell(zp.constants.Editors.LDE.SurfaceColumn.Par3).DoubleValue = 0.150
s_hs_2.GetSurfaceCell(zp.constants.Editors.LDE.SurfaceColumn.Par4).DoubleValue = 0.150
s_hs_2.PhysicalOpticsData.OutputPilotRadius = zp.constants.Editors.LDE.PilotRadiusMode.Plane
apd = s_hs_2.ApertureData.CreateApertureTypeSettings(zp.constants.Editors.LDE.SurfaceApertureTypes.RectangularAperture)
apd.XHalfWidth = 6
apd.YHalfWidth = 6
s_hs_2.ApertureData.ChangeApertureTypeSettings(apd)
# Shack-Hartmann sensor - surface 3
s_hs_3 = oss.LDE.GetSurfaceAt(n_surf)
n_surf += 1
s_hs_3.Radius = 0.0
s_hs_3.SemiDiameter = 14.5
s_hs_3.MechanicalSemiDiameter = 14.5
Don’t forget to update MCE operand 2 (mce_2), as that required the Shack-Hartmann sensor to be defined.
[14]:
mce_2.Param1 = s_hs_1.SurfaceNumber - 1 # minus 1 as param 1 omits object in list
mce_2.Param2 = s_hs_2.SurfaceNumber
Visualize the system#
[15]:
draw3d = zp.analyses.systemviewers.viewer_3d(
oss, number_of_rays=7, hide_x_bars=True, surface_line_thickness="Thick", ray_line_thickness="Thick"
)
if zos.version < (24, 1, 0):
warn("Exporting the 3D viewer data is not available for this version of OpticStudio.")
else:
plt.figure(figsize=(20, 10))
plt.imshow(draw3d.Data)
plt.axis("off")
Analyze#
Now we analyze the system using various methods.
Zernike standard coefficients#
First, we evaluate the aberrations of the system using zp.analyses.wavefront.zernike_standard_coefficients.
[16]:
zern = zp.analyses.wavefront.zernike_standard_coefficients(
oss, sampling="64x64", maximum_term=37, wavelength=1, field=1, reference_opd_to_vertex=False, surface=22
)
[17]:
zern.Data.GeneralData
[17]:
| Value | Unit | |
|---|---|---|
| File | D:\Zemax\SAMPLES\LENS.zmx | |
| Title | ||
| Date | 29-10-2024 | |
| Surface | 22 | |
| Field | 0.0 | (deg) |
| Wavelength | 0.83 | µm |
| PeakToValley(ToChief) | 12.356269 | waves |
| PeakToValley(ToCentroid) | 12.356269 | waves |
| FromIntegrationOfTheRays | ||
| Rms(ToChief) | 3.50586 | waves |
| Rms(ToCentroid) | 3.50586 | waves |
| Variance | 12.291058 | waves squared |
| StrehlRatio(Est) | 0.0 | |
| FromIntegrationOfTheFittedCoefficients | ||
| RmsFitError | 0.000209 | waves |
| MaximumFitError | 0.000687 | waves |
[18]:
zern.Data.Coefficients
[18]:
| Value | Unit | Function | |
|---|---|---|---|
| Z1 | 2.923871 | waves | 1 |
| Z2 | 0.0 | waves | 4^(1/2)(p)*COS(A) |
| Z3 | 0.0 | waves | 4^(1/2)(p)*SIN(A) |
| Z4 | 3.174647 | waves | 3^(1/2)(2p^2-1) |
| Z5 | 0.0 | waves | 6^(1/2)(p^2)*SIN(2A) |
| Z6 | 0.0 | waves | 6^(1/2)(p^2)*COS(2A) |
| Z7 | 0.0 | waves | 8^(1/2)(3p^3-2p)*SIN(A) |
| Z8 | 0.0 | waves | 8^(1/2)(3p^3-2p)*COS(A) |
| Z9 | 0.0 | waves | 8^(1/2)(p^3)*SIN(3A) |
| Z10 | 0.0 | waves | 8^(1/2)(p^3)*COS(3A) |
| Z11 | 1.465612 | waves | 5^(1/2)(6p^4-6p^2+1) |
| Z12 | 0.0 | waves | 10^(1/2)(4p^4-3p^2)*COS(2A) |
| Z13 | 0.0 | waves | 10^(1/2)(4p^4-3p^2)*SIN(2A) |
| Z14 | 0.000003 | waves | 10^(1/2)(p^4)*COS(4A) |
| Z15 | 0.0 | waves | 10^(1/2)(p^4)*SIN(4A) |
| Z16 | 0.0 | waves | 12^(1/2)(10p^5-12p^3+3p)*COS(A) |
| Z17 | 0.0 | waves | 12^(1/2)(10p^5-12p^3+3p)*SIN(A) |
| Z18 | 0.0 | waves | 12^(1/2)(5p^5-4p^3)*COS(3A) |
| Z19 | 0.0 | waves | 12^(1/2)(5p^5-4p^3)*SIN(3A) |
| Z20 | 0.0 | waves | 12^(1/2)(p^5)*COS(5A) |
| Z21 | 0.0 | waves | 12^(1/2)(p^5)*SIN(5A) |
| Z22 | 0.254067 | waves | 7^(1/2)(20p^6-30p^4+12p^2-1) |
| Z23 | 0.0 | waves | 14^(1/2)(15p^6-20p^4+6p^2)*SIN(2A) |
| Z24 | 0.0 | waves | 14^(1/2)(15p^6-20p^4+6p^2)*COS(2A) |
| Z25 | 0.0 | waves | 14^(1/2)(6p^6-5p^4)*SIN(4A) |
| Z26 | 0.000003 | waves | 14^(1/2)(6p^6-5p^4)*COS(4A) |
| Z27 | 0.0 | waves | 14^(1/2)(p^6)*SIN(6A) |
| Z28 | 0.0 | waves | 14^(1/2)(p^6)*COS(6A) |
| Z29 | 0.0 | waves | 16^(1/2)(35p^7-60p^5+30p^3-4p)*SIN(A) |
| Z30 | 0.0 | waves | 16^(1/2)(35p^7-60p^5+30p^3-4p)*COS(A) |
| Z31 | 0.0 | waves | 16^(1/2)(21p^7-30p^5+10p^3)*SIN(3A) |
| Z32 | 0.0 | waves | 16^(1/2)(21p^7-30p^5+10p^3)*COS(3A) |
| Z33 | 0.0 | waves | 16^(1/2)(7p^7-6p^5)*SIN(5A) |
| Z34 | 0.0 | waves | 16^(1/2)(7p^7-6p^5)*COS(5A) |
| Z35 | 0.0 | waves | 16^(1/2)(p^7)*SIN(7A) |
| Z36 | 0.0 | waves | 16^(1/2)(p^7)*COS(7A) |
| Z37 | -0.010255 | waves | 9^(1/2)(70p^8-140p^6+90p^4-20p^2+1) |
Wavefront map#
We create a wavefront map using zp.analyses.wavefront.wavefront_map.
[19]:
wm = zp.analyses.wavefront.wavefront_map(
oss,
sampling="64x64",
wavelength=1,
field=1,
surface="Image",
show_as="Surface",
rotation="Rotate_0",
scale=1,
polarization=None,
reference_to_primary=False,
remove_tilt=False,
use_exit_pupil=True,
oncomplete="Release",
)
[20]:
fig, ax = plt.subplots()
cbar = ax.imshow(
wm.Data,
cmap="jet",
extent=[
wm.Data.columns.values[0],
wm.Data.columns.values[-1],
wm.Data.index.values[0],
wm.Data.index.values[-1],
],
origin="lower",
)
ax.set_xlabel("X-Pupil (rel. Units)")
ax.set_ylabel("Y-Pupil (rel. Units)")
_ = fig.colorbar(cbar)
Geometric image analysis#
We also perform a geometric image analysis using zp.analyses.extendedscene.geometric_image_analysis.
[21]:
gia = zp.analyses.extendedscene.geometric_image_analysis(
oss,
field_size=0,
image_size=5,
wavelength=1,
field=1,
file="CIRCLE.IMA",
rotation=0,
rays_x_1000=500,
surface=25,
show_as="CrossX",
row_column_number="Center",
source="Uniform",
number_of_pixels=300,
use_polarization=True,
total_watts=1,
remove_vignetting_factors=False,
scatter_rays=False,
parity="Even",
delete_vignetted=False,
use_pixel_interpolation=False,
reference="Vertex",
oncomplete="Release",
)
[22]:
fig, ax = plt.subplots()
cbar = ax.imshow(
gia.Data,
cmap="gray_r",
extent=[
gia.Data.columns.values[0],
gia.Data.columns.values[-1],
gia.Data.index.values[0],
gia.Data.index.values[-1],
],
origin="lower",
)
ax.axes.get_xaxis().set_ticks([])
ax.axes.get_yaxis().set_ticks([])
_ = fig.colorbar(cbar)
[23]:
fig, ax = plt.subplots()
data = gia.Data.iloc[150]
cbar = ax.plot(
data,
)
ax.set_xlabel(f"X position in Millimeters (Y={gia.Data.index[150]})")
ax.set_ylabel("Irradiance Watts/Millimeters squared")
[23]:
Text(0, 0.5, 'Irradiance Watts/Millimeters squared')
Physical Optics Propagation#
Finally, we perform a Physical Optics Propagation analysis using zp.analyses.physicaloptics.physical_optics_propagation.
Note that we first use a ZOSPy helper function zp.analyses.physicaloptics.pop_create_beam_parameter_dict to create a dictionary that can be passed as beam_parameters to zp.analyses.physicaloptics.physical_optics_propagation
[24]:
beam_params = pop = zp.analyses.physicaloptics.pop_create_beam_parameter_dict(oss, beam_type="TopHat")
[25]:
beam_params
[25]:
{'Waist X': 2.0, 'Waist Y': 2.0, 'Decenter X': 0.0, 'Decenter Y': 0.0}
[26]:
beam_params["Waist X"] = 5.4
beam_params["Waist X"] = 5.4
beam_params["Decenter X"] = 0.0
beam_params["Decenter Y"] = 0.0
[27]:
pop = zp.analyses.physicaloptics.physical_optics_propagation(
oss,
start_surface=1,
end_surface="Image",
wavelength=1,
field=1,
surface_to_beam=0,
use_polarization=False,
separate_xy=False,
beam_type="TopHat",
x_sampling=512,
y_sampling=512,
x_width=0.112,
y_width=0.112,
use_total_power=True,
use_peak_irradiance=False,
total_power=1,
beam_parameters=beam_params,
show_as="CrossX",
data_type="Irradiance",
project="AlongBeam",
row_or_column="Center",
scale_type="Linear",
zoom_in="NoZoom",
zero_phase_level=0.001,
compute_fiber_coupling_integral=False,
oncomplete="Release",
)
[28]:
fig, ax = plt.subplots()
cbar = ax.imshow(
pop.Data,
cmap="jet",
extent=[
pop.Data.columns.values[0],
pop.Data.columns.values[-1],
pop.Data.index.values[0],
pop.Data.index.values[-1],
],
origin="lower",
)
_ = fig.colorbar(cbar)
[29]:
fig, ax = plt.subplots()
data = pop.Data.iloc[512]
cbar = ax.plot(
data,
)
ax.set_xlabel(f"X coordinate value")
ax.set_ylabel("Irradiance ( Watts per sq Millimeters)")
[29]:
Text(0, 0.5, 'Irradiance ( Watts per sq Millimeters)')