This article explains how to utilize a user-defined Zemax Programming Language (ZPL) macro to calculate and return a value to the Merit Function Editor (MFE) for optimization.
Authored By Dan Hill
Even though there are 300+ built-in optimization operands, there are cases where you might wish to return or optimize a value that the existing operands do not calculate. For this reason, OpticStudio supports the flexibility of a user defined program (ZPL macro) for defining the data computed by an operand in the Merit Function Editor.
ZPL macros are simple to program, fast to execute, well integrated into OpticStudio, and require little programming experience. Additionally, the ZPLM operand can quickly call a ZPL macro from within the Merit Function.
In this article, we will show how to utilize a macro to calculate and return a value to the Merit Function, which may be targeted for optimization via the ZPLM operand.
If you are unfamiliar with how to create, edit, save, and execute macros, you may want to start with the article, What is ZPL?, prior to proceeding with this exercise.
Start by opening the attached file. Let’s assume that we would like to calculate and optimize for a specific Working F/#. Of course, OpticStudio contains a pre-programmed operand for this operation (WFNO), but for demonstration purposes, let’s assume that this operand was not available to us. As an alternative, we can calculate this value via a macro, return the calculated value to the Merit Function, and optimize for a desired target. In OpticStudio, the Working F/#, is defined as:
where n is the index of refraction of image space, and θ is the real marginal ray angle in image space. Given this relationship, we may trace a real marginal ray within a macro and calculate the Working F/#.
Note the use of the OPRETURN keyword. This keyword stores the resulting value for X in the global array position 0. It is this global array position number which is entered into the Data column of the ZPLM operand in the Merit Function Editor (MFE).
The Mac# in the diagram above corresponds to the macro number. Each macro which is created for the purposes of being called by a ZPLM operand must follow a specific file name: ZPLxx.ZPL. The macro number may be any number between 0 and 99, so ZPL17.ZPL is a valid filename which may be executed by specifying a Mac# of 17 in appropriate cell in the MFE.
In the current example, name the macro ZPL10.ZPL and save it into the appropriate directory. In the Merit Function Editor, insert a ZPLM operand and insert a Mac# and Dat of 10 and 0, respectively.
To execute the macro and return the extracted value, update the Merit Function Editor.
Our calculated and returned Working F/# is 4.9782. Let’s see how we did. Insert a WFNO operand (the built-in calculation of the Working F/#) and update the Merit Function Editor. Note that the values are identical!
This technique may be used to return multiple values in a single call to the macro (to learn more, please refer to the section of the User’s Guide referenced earlier), which may be used for optimization or simply for the purposes of reporting a value to the MFE for further analysis. ZPLM provides incredible speed and flexibility for returning and optimizing values which are not currently supported by one of the many built-in optimization operands.
You might find yourself asking how significant the computation times will be affected when you have user defined operands in the Merit Function Editor. This really depends upon the complexity of the computation performed within the macro, but in general the execution of a macro during optimization is extremely fast. To demonstrate, we can optimize the Cooke Triplet twice: once using the ZPLM operand and our constructed macro, and once using the pre-programmed operand, WFNO.
For the first case, Target the ZPLM operand to be 5, and give it a Weight of 1. You may leave the WFNO operand in place but leave its Weight at zero. Construct a Default Merit Function using the following settings.
Run the Damped Least Squares (DLS) local optimization. The approximate execution time is 4 seconds.
Undo the changes made by the optimization (press F3 to do so). Change the Weight of the ZPLM operand to 0, set the Target of the WFNO operand to 5 and its Weight to 1. Re-optimize.
The execution time with the native operand is roughly 3.5 seconds. The difference between the two is roughly one-half-second! As you can see, OpticStudio can still optimize very efficiently, even in cases which call user-defined macros or an externally compiled program.