Skip to main content

Hello,

A comment on ZOSPy. I did already spent countless hours on my own python wrapper and I am very happy to see a team of skilled programmers working on that. Just getting rid of tons of boilerplate code is worth the effort!

Getting connected to Zemax from my jupyter-lab to zemax as “Interactive Extension” works with ZOSPy or with the pasting several lines of boilerplate and directly acessing ZOS-API via pythonnet 3.x.

Via ZOSPy I can add lenses, changes become visible in zemax. So I assume there is no general problem with library loading, connecting, etc..

However, I cannot figure how to run a FFT MTF using ZOSPy. 

 With the bare pythonnet this looks like this (Boilerplat-part from example 04 skipped)

# Create analysis
TheAnalyses = TheSystem.Analyses
newWin = TheAnalyses.New_FftMtf()
# Settings
newWin_Settings = newWin.GetSettings()
newWin_Settings.MaximumFrequency = 50
newWin_Settings.SampleSize = ZOSAPI.Analysis.SampleSizes.S_256x256

FFT MFT Window appears.

And afterwards

# Run Analysis
newWin.ApplyAndWaitForCompletion()
# Get Analysis Results
newWin_Results = newWin.GetResults()
#! re04s04_py]

Results appear and the numbers go into newWin_Results. Still having to get them converted from .net-datatypes to python-data.

 

With ZOSPy I can successfully:

oss = zos.connect(mode="extension")
fftmtf = zp.analyses.base.new_analysis(oss, analysis_type = zp.constants.Analysis.AnalysisIDM.FftMtf)
fftmtf = zp.analyses.base.new_analysis(oss, analysis_type = zp.constants.Analysis.AnalysisIDM.FftMtf)

Which creates a new FFT MTF window.

 

fftmtf.Settings.MaximumFrequency = 50.
fftmtf.Settings.SampleSize = zp.constants.Analysis.SampleSizes.S_256x256
print((fftmtf.Settings.MaximumFrequency, fftmtf.Settings.SampleSize))

output: (50.0, <SampleSizes.S_256x256: 4>)

Settings somehow seem to work, but I cannot figure the equivalent of “AppyAndWaitForCompletion()” or just “Apply()”.

I did go thru https://zospy.readthedocs.io/en/latest/api/zospy.analyses.mtf.html

Is there an “emergency exit” from the ZOSPy world to the underlying pythonnet-objects and -methods? 

 

Best regards,

    Axel

 


 

@Axel.Heinrici

 

It doesn’t seem like the FFT MTF has been implemented specifically into ZOSPy. Therefore, I believe you should call the FFT MTF like so (for an Interactive Extension):

import zospy as zp


zos = zp.ZOS()
oss = zos.connect("extension")

fft_mtf = oss.Analyses.New_Analysis_SettingsFirst(zp.constants.Analysis.AnalysisIDM.FftMtf)

fft_mtf_settings = fft_mtf.GetSettings()
fft_mtf_settings.MaximumFrequency = 50

fft_mtf.ApplyAndWaitForCompletion()

Let me know if this works for you.

Take care,


David


Hi @Axel.Heinrici,

Thanks for your question and good to hear that ZOSPy makes using the ZOS-API easier for you!
I tested your example code with ZOSPy 1.2.0 and everything works. I can also run the analysis by running:

fftmtf.ApplyAndWaitForCompletion()

What happens if you call this function? Do you get an error?
When using the analysis object returned by zp.analyses.base.new_analysis like you are doing in your example code, you are basically interacting directly with the ZOS-API / Python.NET objects. So an emergency exit should not be necessary here, because you are not really in the ZOSPy  world anymore ;)

More on the emergency exit:

If you need direct access to the ZOS-API, this is always possible through zos.ZOSAPI. Note that this basically defeats the purpose of ZOSPy. Furthermore, if something in ZOSPy looks like the normal ZOS-API, it most probably is the ZOS-API; we only add wrappers if it improves efficiency (e.g. for the connection methods and analyses; and hopefully soon for optimizers as well).

 

Edit: I see @David.Nguyen already answered this question when I was writing a response. Thanks, David!


Hello,

the problem was that “Apply()” and “ApplyAndWaitForCompletion()” don’t show up in dir(fftmtf) and not accessible through tab completion.
To me it is a little missleading to have methods that are not displayed on a dir() call.

 

Best regards,

    Axel 


Yes, I understand that's confusing but this is unfortunately related to how the analysis objects are implemented. We are currently using a wrapper so we can simplify access to some parts of the output. dir will therefore only display the attributes of this wrapper; you can access the attributes of the wrapped object with dir(fftmtf._analysis). Note that dir will not tell you what's not there, and its output will be incomplete for other parts of ZOSPy (e.g. parts of the analysis output) as well.

The tab completion is also just there for your convenience, and only intended to as complete as possible (i.e. it will always be incomplete).  For example, for analyses it's impossible to know beforehand which analysis type will be returned, so it is impossible to add completions for the analysis-specific settings. Therefore, fftmtf.Settings.MaximumFrequency will not show up in the tab completions, unless your IDE adds additional inspections on top of dir.


Addition to my previous post: it turns out to be relatively easy to let dir return the members of the wrapped analysis as well, without getting recursion problems. We will consider adding this to ZOSPy in a future release.


@Axel.Heinrici if you could make your wrapper for the FFT MTF function in a nice universal way (probably a lot of copy-paste from the  fft_through_focus_mtf() which already included in ZOSPy) and make a Pull Request, we are happy to include in a future version so others can benefit from it.


Hi @Axel.Heinrici,

might be for the meanwhile also you could try 

fftmtf = zp.analyses.base.new_analysis(oss, analysis_type = zp.constants.Analysis.AnalysisIDM.FftMtf).__implementation__

this should unveil the ApplyAndWaitForCompletion() method.

 


@dgeorgiev unfortunately, that suggestion is not applicable in this case. Judging from the example code, @Axel.Heinrici is using ZOSPy 1.2.0, which automatically calls __implementation__ where needed:

In addition, it has never been necessary to call  __implementation__ for analysis objects, as zp.analyses.base.new_analysis was introduced in ZOSPy 1.0.0 to fix this. Trying to access __implementation__ will only raise an AttributeError because the attribute is not present. The behavior mentioned by @Axel.Heinrici is caused by the way Python's dir function discovers members of a class. We aim to solve this in a future release, but fortunately this does not in any way impede the functionality of ZOSPy.


 Hi @chaasjes ,

i greatly appreciate your brilliant work and myself use v1.2.0 because of convenience and elegance.

However meanwhile in this seldom case, until you fix it the right way in the future,

I proposed this fix, which seems to work for me on v1.2.0:  

 

fftmtf1 = zp.analyses.base.new_analysis(oss, analysis_type = zp.constants.Analysis.AnalysisIDM.FftMtf)
fftmtf2 = zp.analyses.base.new_analysis(oss, analysis_type = zp.constants.Analysis.AnalysisIDM.FftMtf).__implementation__
type(fftmtf1)
<zospy.analyses.base.Analysis object>
type(fftmtf2)
<ZemaxUI.ZOSAPI.Analysis.Mtf.A_FftMtf object>

Here fftmtf2 has the required method ApplyAndWaitForCompletion().

 

 


Hi @dgeorgiev,

Thanks for your response! I appreciate your willingness to help other ZOSPy users. However, my previous post was an attempt to explain why your suggestions are off-topic. They are not related to the problem experienced by the topic starter and do not provide a fix for this problem. Contrary to what your previous post implicitly suggests, the Apply and ApplyAndWaitForCompletion methods are also available on fftmtf1 and not only on fftmtf2.

It is indeed true that you can still call __implementation__ on zospy.analyses.base.Analysis objects, because automatic downcasting is not used for analysis objects, but only on analysis settings objects. However, Apply and ApplyAndWaitForCompletion can also be used without downcasting. While it is true that dir(fftmtf1) won't show these methods and dir(fftmtf1.__implementation__) will show them, the same result can also be accomplished with dir(fftmtf1._analysis), as stated in an earlier post. None of these methods are real solutions to the counterintuitive behavior reported by @Axel.Heinrici, because they require prior knowledge about how ZOSPy works.

 

On a different note: the Python documentation for the dir function states its output is intentionally incomplete.


Addition to my previous post: it turns out to be relatively easy to let dir return the members of the wrapped analysis as well, without getting recursion problems. We will consider adding this to ZOSPy in a future release.

I’d like to share that this improvement has just been released with ZOSPy 1.2.1.


Reply