xzos/PyZDDE

PyZDDE zGetPsf

B2015 opened this issue · 10 comments

B2015 commented

Hello,
I read with interest the other issue opened a while ago about a problem with the zGetPsf() method when the encoding was not properly set.

I however currently come accross the same problem when calling zGetPsf() and get the following error message:

File "C:\Python27\lib\site-packages\pyzdde-2.0.1-py2.7.egg\pyzdde\zdde.py" line 7548 in zGetPsf data_spacing_line = line_list[_getFirstLineOfInterest(line_list, ' Data_spacing')])] Type error: List indices must be integers, not NoneType

Is this problem related to the other one? I tried both encoding to check but none worked out.

All the best

Hi @B2015,

You are seeing this error because the function _getFirstLineOfInterest() couldn't find the pattern Data spacing in the text file outputted by Zemax. If the code has no bugs (although possible, I have used this function several times in the past, and there is a less chance that it is a bug), then typically the problem is either with encoding or that the pattern is not present in the file itself. Since you have already ensured that the encoding is proper, I would recommend that you check the text file that Zemax produces (using the arguments txtFile, keepFile when calling zGetPSF()).
Also, which version of Zemax are you using?

B2015 commented

Hello,

I'm currently using Optical Studio 15. Coming back to my question, when I printed out the LineList result I realized that Zemax was pointing out that the sampling was too low, so no information was returned in the string and that is why Pyzdde was not able to find the field.

I changed the resolution with zSetFFTPSFSettings but still have a remaining problem while parsing the string. I put the reult of printing the LineList below:

[u'Listing of FFT PSF Data', u'', u'File : L:\Desktop\mytelescope.zmx', u'Title:', u'Date : 30/10/2015', u'', u'', u'FFT PSF', u'0,7200 \xb5m at 0,00, 0,00 mm.', u'Data spacing is 0,843 \xb5m.', u'Data area is 53,978 \xb5m wide.', u'Surface: Image', u'Reference Coordinates: 0,00000E+000, -2,69952E-001', u'Pupil grid size: 32 by 32', u'Image grid size: 64 by 64', u'Center point is: row 33, column 32', u'Values are not normalized.', u'', u' 8,0691E-006\t 3,0835E-006\t 7,2444E-006\t 2,1113E-005\t 2,0548E-005\t 3,1996E-006\t 3,4700E-006\t 1,1565E-005\t 7,0222E-006\t 1,1207E-005\t 5,2486E-005\t 8,7449E-005\t 6,7769E-005\t 1,8759E-005\t 7,6149E-006\t
... I erased the other psf data ...
8,8907E-005\t 5,4364E-005\t 1,0082E-005\t 1,6920E-005\t 1,2396E-005\t 5,2237E-007\t 6,8376E-006\t 3,9252E-006\t 1,2925E-006\t 6,2847E-006\t 4,2395E-006\t 2,8782E-007\t 3,0919E-006']

but I still get the following error message:

Traceback (most recent call last):
File "L:/Desktop/telescope_psf.py", line 93, in
psfInfo, psfData = ln.zGetPSF(which='fft',keepFile=True)
File "C:\Python27\lib\site-packages\pyzdde-2.0.1-py2.7.egg\pyzdde\zdde.py", line 7555, in zGetPSF
data_spacing = float(_re.search(r'\d{1,3}.\d{2,6}', data_spacing_line).group())
AttributeError: 'NoneType' object has no attribute 'group'

So from my point of view it looks like now the information is all here, but there may be a problem in the string parsing? But I'm probably missing something out here.

EDIT: Investigating about the regex applied to the ZEMAX string, I found out that my zemax version prints out ',' instead of '.' within the numbers and that is why the method is failing.

@B2015 I will take a look tonight or during the weekend. Thanks for the detailed info. As you pointed out, it seems to be that updating the regex pattern to include a both comma and period may fix it. Can you try it out? And if that fixes the problem, I will be more than happy to accept a pull request from you.

Regards,
Indranil.

B2015 commented

I was far away from my computer this weekend so I only got to reply today.

Indeed the only problem was that the regex in zGetPSF was expecting for numbers in american/english notation. Zemax uses the number notation from the OS so if you happen to be working on a european set computer, you will have problem when using some methods that returns strings that have to be parsed.

I'm not quite sure how this problem should be tackled best though. The regex could be modified or we could use the locale-aware way in which the setting is read. What's your take on this?

Behind this, I added to zGetPSF() a regex and variables to return the real coordinates of the center of the returned frame. That can be a useful information in some cases. I can provide it if you are interested.

Regards

Hi @B2015,

I'm not quite sure how this problem should be tackled best though. 
The regex could be modified or we could use the locale-aware way 
in which the setting is read. What's your take on this?

Will it be possible for you to send me a "sample" PSF file outputted by Zemax that is showing the problem? I would like to have a better understanding before I can suggest or do any modification.

I added to zGetPSF() a regex and variables to return the real 
coordinates of the center of the returned frame. That can be 
a useful information in some cases. I can provide it if you are 
interested.

(Please feel free to correct me). Isn't that info redundant? Since the function returns both the data spacing and the center point information?

B2015 commented

For the first point, a sample is avalable above (I copy part of it here, to illustrate the problem) :

[u'Listing of FFT PSF Data', u'', u'File : L:\Desktop\mytelescope.zmx', u'Title:', u'Date : 30/10/2015', u'', u'', u'FFT PSF', u'0,7200 \xb5m at 0,00, 0,00 mm.', u'Data spacing is 0,843 \xb5m.', u'Data area is 53,978 \xb5m wide.', u'Surface: Image', u'Reference Coordinates: ...]

As you can see, the "Data spacing" field has a value '0,843' and not '0.843' such as expected from the parser found in function zGetPSF() (lines after L7547 within pyZDDE.py) which uses the regex:
_re.search(r'\d{1,3}.\d{2,6}' . Hence since a ',' delimitates the decimals instead of a '.', it returns an empty list hence the problem. A solution would then be to look for _re.search(r'\d{1,3},\d{2,6}' and then transform the ',' in '.' to be transformed to float in python for furthert processing. Or the regex could be modified to look for either a ',' or a '.'.

For the second point, I do not think (though I may be wrong too) that the information is redundant. Let me explain: what is currently returned is:

['dataSpacing', 'dataArea', 'pupilGridX', 'pupilGridY', 'imgGridX', 'imgGridY', 'centerPtX', 'centerPtY']

This is enough to have a look at the PSF though with these information you can not get the absolute position of the PSF in the image plane: you are only given the number of pixel, sampling and position (as the pixel number) of the central pixel. From these data you cannot compute the true position in image plane, and e.g. compute an image using the image position dependant PSF.

Cheers

Hi @B2015

Sorry, I had been a little busy during the last few days, hence the delay in response.

Regarding the first issue, we can surely make the change in the regex to include both comma and period. However, before doing the change, I would like to know why Zemax formatted the output that way. This is the first time I am encountering such format in Zemax, and so I am a little curious. Is that the default behavior of Zemax at your end? Is there any particular setting that is check in the Zemax project preference?

Now, regarding the second issue. I think I now understand it. I would certainly like to see what you have.

Regards.

B2015 commented

Hello,
I've been away too last week so we are even :)

I think that Zemax (and that is what my colleagues told me) uses the number setting from the OS you use. For some obscure reason, the IT guy set my windows 7 session in french with european style numbers (eg using ',' for the decimals and the '.' for the thousands). Zemax does not have a setting within the preferences in order to set the number format, so it takes the setting from what it finds within the OS. So until now when I was using Zemax, if I wanted a curvature radius of "20.5" mm I had to type in "20,5"; otherwise Zemax would chop off the unrecognized character and understand that I'd typed in 205 mm. Now that I ve changed the number format preference in my windows 7 setting to US/British numbering, Zemax uses the US/British number format. The problem was, when the number format was still French/European that the output of ZEMAX was also in that format, which python would not understand since it uses '.' for the decimals.

For the second issue, all I have for now is a quick and dirty fix within zdde in which the code reading in the PSF meta data has been changed to:

    # Meta data
    data_spacing_line = line_list[_getFirstLineOfInterest(line_list, 'Data spacing')]
    data_spacing = float(_re.search(r'\d{1,3}\.\d{2,6}', data_spacing_line).group())
    data_area_line = line_list[_getFirstLineOfInterest(line_list, 'Data area')]
    data_area = float(_re.search(r'\d{1,5}\.\d{2,6}', data_area_line).group())
    if which=='huygens':
        center_reference_line = line_list[_getFirstLineOfInterest(line_list, 'Center coordinates')]
        center_img_x, center_img_y = [float(i) for i in _re.findall("[+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?", center_reference_line)]
    if which=='fft':
        center_reference_line = line_list[_getFirstLineOfInterest(line_list, 'Reference Coordinates')]
        center_img_x, center_img_y = [float(i) for i in _re.findall("[+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?", center_reference_line)]
    img_grid_line = line_list[_getFirstLineOfInterest(line_list, 'Image grid size')]
    img_grid_x, img_grid_y = [int(i) for i in _re.findall(r'\d{2,5}', img_grid_line)]
    pupil_grid_line = line_list[_getFirstLineOfInterest(line_list, 'Pupil grid size')]
    pupil_grid_x, pupil_grid_y = [int(i) for i in _re.findall(r'\d{2,5}', pupil_grid_line)]
    center_point_line = line_list[_getFirstLineOfInterest(line_list, 'Center point')]
    center_point_x, center_point_y = [int(i) for i in _re.findall(r'\d{2,5}', center_point_line)]

I say quick and dirty because the calls to Huygens and FFT data returns different parameters so it may be wiser to use the naming found in the DDE. But I'm still wondering whether all the info should or not be outputed within the PsfInfo dict.

cheers

Hi @B2015

The information regarding the difference between French/European vs US/British number format is interesting, and I had no idea! Anyway, since you seem to have resolved the issue by changing your system to use US/British, I guess that I will keep this information in mind, and probably not modify the code. Later if there is demand we can always add it.

For the second issue, I agree with you that we should also pack and send this info to the user. However, do you think that the regex pattern r'-?\d\.\d{4,10}[Ee][-\+]\d{3}' will not work?

I also agree with you that we should follow the naming convention used by Zemax in the psfInfo dict. Here is a rough sketch:

# Metadata

[...]

if which=='huygens':
        ctr_ref_line = line_list[_getFirstLineOfInterest(line_list, 'Center coordinates')]
else:
        ctr_ref_line = line_list[_getFirstLineOfInterest(line_list, 'Reference Coordinates')]

ctr_ref_x, ctr_ref_y = [float(i) for i in _re.findallr'-?\d\.\d{4,10}[Ee][-\+]\d{3}', ctr_ref_line)]

[...]

if which=='huygens':
        psfi = _co.namedtuple('PSFinfo', ['dataSpacing', 'dataArea', 'pupilGridX',
                                          'pupilGridY', 'imgGridX', 'imgGridY',
                                          'centerPtX', 'centerPtY', 
                                          'centerCoordX', 'centerCoordY'])
else:
        psfi = _co.namedtuple('PSFinfo', ['dataSpacing', 'dataArea', 'pupilGridX',
                                          'pupilGridY', 'imgGridX', 'imgGridY',
                                          'centerPtX', 'centerPtY', 
                                          'refCoordX', 'refCoordY'])

psfInfo = psfi(data_spacing, data_area, pupil_grid_x, pupil_grid_y,
                       img_grid_x, img_grid_y, center_point_x, center_point_y,
                       ctr_ref_x, ctr_ref_y)

[...]

Please critique, discard, incorporate as you find appropriate, and please send a pull request when you are happy with the changes.

Regards.

Closing this issue. Appropriate changes incorporated from #58