xzos / PyZDDE

Zemax/ OpticStudio Extension using Python
MIT License
159 stars 67 forks source link

GetPSF and GetZernike #41

Closed aaronroodman closed 9 years ago

aaronroodman commented 9 years ago

Hi, Two questions:

1) is there a way to retrieve the Zernike coefficients themselves? ie. the functionality of the GetZernike command in ZPL. I can get the text file with them using the 'Zst' button, but what I could really use is the coefficients returned to the python layer.

2) when using the zGetPSF method, I get the error:

TypeError: list indices must be integers, not NoneType

at line 7223 of zGetPSF

thanks Aaron

indranilsinharoy commented 9 years ago

Hi Aaron,

I will look into both the issues ASAP. I am surprised that the zGetPSF method returns the error. I have used it before without problem. Can you send me the script in which you are using zGetPSF ?

aaronroodman commented 9 years ago

Indranil,

thanks for much for your help - and for making this great tool for using Zemax.

The script I used is just:

import sys import os import matplotlib.pyplot as plt import pyzdde.zdde as pyz

file path

zDir = "C:\Users\roodman\Documents\LSSTsmb://Users//roodman//Documents//LSST" zmxfile = 'LSST_Ver_3.3_Baseline_Design_Spiders_Baffles.ZMX' filename = os.path.join(os.path.expanduser('~'), zDir, zmxfile)

ln = pyz.createLink() ln.zLoadFile(filename) ln.zGetPSF()

or with a settingsFile

ln.zGetPSF(which=‘fft’,settingsFile=zDir+’\fftpsf’)

both ways give this error

Aaron

On Jan 23, 2015, at 8:08 PM, Indranil Sinharoy notifications@github.com<mailto:notifications@github.com> wrote:

Hi Aaron,

I will look into both the issues ASAP. I am surprised that the zGetPSF method returns the error. I have used it before without problem. Can you send me the script in which you are using zGetPSF ?

— Reply to this email directly or view it on GitHubhttps://github.com/indranilsinharoy/PyZDDE/issues/41#issuecomment-71299449.


Prof. Aaron Roodman

SLAC National Accelerator Laboratory Stanford University

SLAC National Accelerator Laboratory E-mail: roodman@slac.stanford.edumailto:roodman@slac.stanford.edu 2575 Sand Hill Rd. Phone: 650-926-2705 MS 29 Fax: 650-926-2657 Menlo Park, CA 94025 URL: http://www.slac.stanford.edu/~roodman


indranilsinharoy commented 9 years ago

Dear Prof. Aaron,

Thanks for your kind words. The pleasure is really all mine. I will only get to work on this tonight. I hope that I will be able to get back to you with something by tomorrow.

Indranil.

indranilsinharoy commented 9 years ago

Also, if you have some time, and if you want to take a look at how the zGetPSF() function works, you may have a look at http://nbviewer.ipython.org/gist/indranilsinharoy/d6857951dce508427b36. It is an IPython notebook containing some of basic tests that I did when I wrote these functions. In any case, I will check out the problem tonight.

indranilsinharoy commented 9 years ago

Dear Prof. Aaron,

This is regarding the 2nd problem:

I had a quick look at your script, and there is nothing suspicious there. The only reason for the error to show up is that PyZDDE is unable to find the phrase "Data spacing" in the text file generated by Analysis >> PSF >> FFT/Huygens PSF. This could happen if there is a mismatch in the text encoding set for PyZDDE and the text encoding set in Zemax (i.e. Zemax >> Preferences >> Miscellaneous >> TXT File Encoding). Can you check to see if both of them are the same (i.e. either ANSI or Unicode)? You can check the text encoding setting of PyZDDE using the module level function pyz.getTextEncoding(), and set the text encoding using pyz.setTextEncoding(). I was able to reproduce the above error by purposefully mismatching the text encoding as you can see below (after I get the error, I changed the text encoding back to the right one as per my Zemax settings, and error went away):

Please let me know if this solved your second problem.

Indranil.

In [11]: psfdata = ln.zGetPSF()        # NO ERROR HERE

In [12]: pyz.getTextEncoding()       
Out[12]: 'ascii'

In [13]: pyz.setTextEncoding(1)      # CHANGE TEXT ENCODING TO THE WRONG ONE
Successfully changed to UNICODE

In [14]: psfdata = ln.zGetPSF()          # EXPECTING TO SEE ERROR
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-14-f38e799448ed> in <module>()
----> 1 psfdata = ln.zGetPSF()

C:\PROGRAMSANDEXPERIMENTS\PYTHON\OPTICS\PyZDDE\pyzdde\zdde.pyc in zGetPSF(self, which, settingsFile, txtFile, keepFile, timeout)
   7221 
   7222         # Meta data
-> 7223         data_spacing_line = line_list[_getFirstLineOfInterest(line_list, 'Data spacing')]
   7224         data_spacing = float(_re.search(r'\d{1,3}\.\d{2,6}', data_spacing_line).group())
   7225         data_area_line = line_list[_getFirstLineOfInterest(line_list, 'Data area')]

TypeError: list indices must be integers, not NoneType

In [15]: pyz.setTextEncoding(0)   # BACK TO WHAT IT SHOULD BE
Successfully changed to ASCII

In [16]: psfdata = ln.zGetPSF()    # NO ERROR NOW
indranilsinharoy commented 9 years ago

Dear Prof. Aaron,

This is regarding your 1st question -- "is there a way to retrieve the Zernike coefficients themselves? ie. the functionality of the GetZernike command in ZPL. I can get the text file with them using the 'Zst' button, but what I could really use is the coefficients returned to the python layer."

I have added a function called 'zGetZernike()` in the branch: https://github.com/indranilsinharoy/PyZDDE/tree/getzernikecoeff

The function returns the meta data, and the coefficients to the Python layer (see the basic test examples below). Please let me know if that works for your, or any other suggestions on improving.

There are some limitations though, as the following examples will show. The limitation is that we cannot change the settings for the aberration coefficient analysis using PyZDDE. This is because Zemax hasn't provided the necessary handles for changing these settings (for example, by using MODIFYSETTINGS). So, the current method is to create the settings files manually (if the settings are different from the default values), and call the function with the specific settings file.

Here I have copy-pasted a section of basic testing I did for the function in an IPython notebook ... you will get an idea on how to use the function: (Note that I have manually added the python prompts, >>> in order to differentiate between inputs and outputs)

>>> import pyzdde.zdde as pyz
>>> ln = pyz.createLink()
>>> ln.zLoadFile(r"C:\PROGRAMSANDEXPERIMENTS\PYTHON\OPTICS\zemaxInteractions\Cooke 40 degree field annular aperture.zmx")
0

# with default settings
>>> zInfo, zCoeff = ln.zGetZernike(which='fringe')
>>> zInfo
zInfo(peakToVal=0.05367696, rmsToZero=0.05367696, rmsToChief=0.01548394, rmsToCentroid=0.01548394, variance=0.00023975, strehl=0.9905796, rmsFitErr=0.0, maxFitErr=0.0)
>>> zInfo.rmsToChief   # access a specific parameter
0.01548394
>>> len(zCoeff)
37
>>> print zCoeff
[-0.48704178, 0.0, 0.0, -0.27949432, 0.0, 0.0, 0.0, 0.0, 0.19193398, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.01634558, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.00077357, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -2.854e-05, -1.22e-06]
>>> zInfo, zCoeff = ln.zGetZernike(which='standard')
>>> zInfo
zInfo(peakToVal=0.05367696, rmsToZero=0.05367696, rmsToChief=0.01548394, rmsToCentroid=0.01548394, variance=0.00023975, strehl=0.9905796, rmsFitErr=3.5e-07, maxFitErr=1.24e-06)
>>> len(zCoeff)
37
>>> print zCoeff
[-0.48725154, 0.0, 0.0, -0.1610763, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.08560151, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.00604793, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.00030513]
>>> zInfo, zCoeff = ln.zGetZernike(which='annular')
>>> zInfo
zInfo(peakToVal=0.05367696, rmsToZero=0.05367696, rmsToChief=0.01548394, rmsToCentroid=0.01548394, variance=0.00023975, strehl=0.9905796, rmsFitErr=0.01859785, maxFitErr=0.03642746)

# Change settings for Zernike fringe coefficients from Zemax main application and save the settings
# in the local directory
# Changes: 1. Sampling: 256x256, 2. Max term: 20, 3. Wavelength: 1
# Alternatively, call the function with a settings files (created using Zemax) with the above settings

>>> ln.zPushLens(1)
0
>>> zInfo, zCoeff = ln.zGetZernike(which='fringe')
>>> zInfo
zInfo(peakToVal=0.08586185, rmsToZero=0.08586185, rmsToChief=0.02360218, rmsToCentroid=0.02360218, variance=0.00055706, strehl=0.97824809, rmsFitErr=2.457e-05, maxFitErr=6.511e-05)
>>> len(zCoeff)
20
aaronroodman commented 9 years ago

Indranil,

This works, as does making sure the text settings match - thanks very much,

regards,

Aaron

On Jan 27, 2015, at 11:36 AM, Indranil Sinharoy notifications@github.com<mailto:notifications@github.com> wrote:

Dear Prof. Aaron,

This is regarding your 1st question -- "is there a way to retrieve the Zernike coefficients themselves? ie. the functionality of the GetZernike command in ZPL. I can get the text file with them using the 'Zst' button, but what I could really use is the coefficients returned to the python layer."

I have added a function called 'zGetZernike()` in the branch: https://github.com/indranilsinharoy/PyZDDE/tree/getzernikecoeff

The function returns the meta data, and the coefficients to the Python layer (see the basic test examples below). Please let me know if that works for your, or any other suggestions on improving.

There are some limitations though, as the following examples will show. The limitation is that we cannot change the settings for the aberration coefficient analysis using PyZDDE. This is because Zemax hasn't provided the necessary handles for changing these settings (for example, by using MODIFYSETTINGS). So, the current method is to create the settings files manually (if the settings are different from the default values), and call the function with the specific settings file.

Here I have copy-pasted a section of basic testing I did for the function in an IPython notebook ... you will get an idea on how to use the function: (Note that I have manually added the python prompts, >>> in order to differentiate between inputs and outputs)

import pyzdde.zdde as pyz ln = pyz.createLink() ln.zLoadFile(r"C:\PROGRAMSANDEXPERIMENTS\PYTHON\OPTICS\zemaxInteractions\Cooke 40 degree field annular aperture.zmx") 0

with default settings

zInfo, zCoeff = ln.zGetZernike(which='fringe') zInfo zInfo(peakToVal=0.05367696, rmsToZero=0.05367696, rmsToChief=0.01548394, rmsToCentroid=0.01548394, variance=0.00023975, strehl=0.9905796, rmsFitErr=0.0, maxFitErr=0.0) zInfo.rmsToChief # access a specific parameter 0.01548394 len(zCoeff) 37 print zCoeff [-0.48704178, 0.0, 0.0, -0.27949432, 0.0, 0.0, 0.0, 0.0, 0.19193398, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.01634558, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.00077357, 0.0, 0. 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -2.854e-05, -1.22e-06] zInfo, zCoeff = ln.zGetZernike(which='standard') zInfo zInfo(peakToVal=0.05367696, rmsToZero=0.05367696, rmsToChief=0.01548394, rmsToCentroid=0.01548394, variance=0.00023975, strehl=0.9905796, rmsFitErr=3.5e-07, maxFitErr=1.24e-06) len(zCoeff) 37 print zCoeff [-0.48725154, 0.0, 0.0, -0.1610763, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.08560151, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.00604793, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.00030513] zInfo, zCoeff = ln.zGetZernike(which='annular') zInfo zInfo(peakToVal=0.05367696, rmsToZero=0.05367696, rmsToChief=0.01548394, rmsToCentroid=0.01548394, variance=0.00023975, strehl=0.9905796, rmsFitErr=0.01859785, maxFitErr=0.03642746)

Change settings for Zernike fringe coefficients from Zemax main application and save the settings

in the local directory

Changes: 1. Sampling: 256x256, 2. Max term: 20, 3. Wavelength: 1

Alternatively, call the function with a settings files (created using Zemax) with the above settings

ln.zPushLens(1) 0 zInfo, zCoeff = ln.zGetZernike(which='fringe') zInfo zInfo(peakToVal=0.08586185, rmsToZero=0.08586185, rmsToChief=0.02360218, rmsToCentroid=0.02360218, variance=0.00055706, strehl=0.97824809, rmsFitErr=2.457e-05, maxFitErr=6.511e-05) len(zCoeff) 20

— Reply to this email directly or view it on GitHubhttps://github.com/indranilsinharoy/PyZDDE/issues/41#issuecomment-71712595.


Prof. Aaron Roodman

SLAC National Accelerator Laboratory Stanford University

SLAC National Accelerator Laboratory E-mail: roodman@slac.stanford.edumailto:roodman@slac.stanford.edu 2575 Sand Hill Rd. Phone: 650-926-2705 MS 29 Fax: 650-926-2657 Menlo Park, CA 94025 URL: http://www.slac.stanford.edu/~roodman


indranilsinharoy commented 9 years ago

Dear Prof. Aaron (@aaronroodman),

I just wanted to update you with some minor changes I made the the function zGetZernike() before merging into the main branch. The changes shouldn't break any existing code. Nevertheless here are the changes:

  1. Corrected the zInfo named tuple so that Peak to valley (to centroid) is the right name of the parameter returned in zInfo and not "RMS to the zero OPD line". The ZPL macro GETZERNIKE returns "RMS to the zero OPD line". However, I wasn't sure how to calculate this. So, I decided to just return the values from the Zernike analysis text window.
  2. zCoeff is now a named tuple.