I’m working on a system in which I evaluate physical optics propagation (POP) for beams of several different sizes in the merit function. The way I change the beam size within POP is using a little macro I wrote (see snippet below).
This code works well when I’m optimizing or playing with values in the LDE, but it does not yield consistent results when I run a tolerance analysis. I suspect this is because of how .cfg files are handled during tolerancing.
Is there a better way to modify the POP parameters so that they are modified appropriately during tolerancing?
path$ = $PATHNAME() + "\"
lensFilename$ = $FILENAME()
lengthFilename = SLEN(lensFilename$)
shortenFilename$ = $LEFTSTRING(lensFilename$, lengthFilename-3)
cfgFilename$ = path$ + shortenFilename$ + "CFG"
w0_in = PVHX() # read in the HX parameter. "PV" is a mnenomic for "pass value"
! change the beam waist of the light coming from the fiber
MODIFYSETTINGS cfgFilename$, POP_PARAM1, w0_in # Waist X of beam definition tab
MODIFYSETTINGS cfgFilename$, POP_PARAM2, w0_in # Waist Y of beam definition tab
Best answer by Sandrine AuriolView original
When tolerancing, are you using more than 1 core:
Tolerancing by default, both during SA and MC, will make a copy of your optical system in memory and attempt to evaluate this optical system independent of the other optical systems.
A ZPL script is always single-threaded. The
MODIFYSETTINGSkeyword puts a write-lock on the file (if only for a few milliseconds) when trying to modify the settings and once it closes the file, it removes the lock. When using either a script or a ZPLM, the single-threaded nature of the ZPL ensures that the MODIFYSETTINGS is correctly written and subsequent calls will always use the latest values written by the MODIFYSETTINGS keyword.
However, since the tolerancing makes multiple copies of the optical system, when both System A and System B call MODIFYSETTINGS from the ZPLM, there is no conflict resolution to make sure the POPD operand called from System A uses System A’s MODIFYSETTINGS; rather, the POPD will simply use the last values written to the POP.CFG.
So, if you want to keep your current workflow, I suggest dropping the # of Cores to 1; this is significantly increase your tolerancing time but you won’t have to change anything else about your workflow.
If you need the speed of multi-threading for tolerancing, I would suggest using a stand-in for POPD. Paul Colbourne has a really good method for using pure geometric rays to describe the beam envelope of a TEM00 beam which could be used as a stand-in for POP:
Using skew rays to model Gaussian beams - webinar – Knowledgebase (zemax.com)
It looks like you are using the Hx cell in a ZPLM merit function operand to pass a starting beam waist value to POP. Just curious, how do you go about setting the Hx cell as a variable for optimization and/or tolerancing? I can think of one possible approach, but I’m curious to know how you are doing it.
That’s right -- but I actually haven’t set the Hx cell as a variable. That would make the macro a lot more useful. Can you share how were you imagining going about that?
Well, the approach I have in mind is a little bit convoluted, and I would prefer to test it before proposing it as a solution. Let me see if I can do that in the next day or so.
Going back to your current situation, I assume then you are using the ZPLM operand to manually enter the starting beam waist size in the Hx cell, and subsequently conducting optimization and tolerancing with various POPD operands -- is that correct? If so, why do you need the ZPLM operand in the first place when you could simply change/save the POP parameters via the GUI before optimization and/or tolerancing? I don’t understand the need for the ZPLM operand. Can you explain?
One way I could think of setting an input as a variable (which would be convoluted like Jeff said) would be to simply bypass the PVHX() function and rather to use the multi-config editor to set a dummy value as a variable. It would be a 3 step process:
If you then need to use this variable as an input to an operand, you can use OPEV(). If you have a long running operand which can benefit from multiple adjacent operands in the MFE, then you can use the SETOPERAND keyword for the Col 1-8 input values. The row value in the SETOPERAND keyword would have to be hard-coded and the operand you modify must be below the ZPLM, otherwise the operand will update on the next (n+1) cycle and not on the current (n) cycle.
Also, an approach I could see of using the waist as an input to the MODIFYSETTINGS via a PVHX would be to save multiple merit functions with different Hx (waist) values before running a tolerance and to use a TSC with LOADMERIT to evaluate the perturbed system for different size Gaussian beams (just my best guess as to a use case for something like this).
Hi Michael & Liz,
My idea is similar, although it uses two ZPLM operands (both with zero weights) and continues to use the PVHX function:
Now the CRVT operand in the MCE (i.e., the starting POP beam waist) can be set as a variable for optimization, or it can be set as a parameter for tolerancing by using a TMCO operand in the Tolerance Data Editor.
It seems like this should work, but it is a bit convoluted with a lot of “moving parts,” so it should be carefully tested to make sure it works properly before spending a lot of time generating results. Also, since both optimization and tolerancing can be multi-threaded, I assume that 1 core should be selected in either case to avoid the problem Michael describes above.
I hope you don’t mind but I have modified the title of the original post so that it can be more easily found by other users. I think it is indeed an interesting topic.
I had a similar question on support and worked on the same idea of using a dummy surface (I used a dummy Biconic surface and used the conic and X conic parameters of the biconic surface as the input values for the X and Y waist size) to optimize for the input beam. The difference was that we were using the skew gaussian beam operands GBS*.
Here is the macro for reference.
I haven’t tried it but for POP, it may work with a user operand in C# that modifies POP settings and then runs the analysis.
I’ve found this to be quite useful--but slow. I would very much appreciate if Zemax can implement a multi-core way to do this! If you do, please let me know! Thanks!