- Home
- Programming ZEMAX
- ZPL
- How to Call a ZPL Macro From Within a ZPL Macro
How to Call a ZPL Macro From Within a ZPL Macro
- By Sanjay Gangadhara
- Published 21 February 2008
- ZPL
- Unrated
Calling a macro from within another macro
When writing a ZPL macro in which many steps are performed, it is generally good programming practice to perform each step in a separate piece of code. This may be done with ZPL subroutines, using the GOSUB, SUB, RETURN, and END keywords. However, there are cases where it may be easier to perform each step in a separate macro, and then call each of these individual (“child”) macros from a main (“parent”) macro. For instance, if the same calculation is to be performed in many different macros, it would be much more efficient to perform this calculation in a child macro which is subsequently called by various parent macros. This can be done in ZEMAX using the CALLMACRO keyword. A description of this keyword and its implementation may be found in Chapter 22 of the ZEMAX manual (“Calling a Macro from within a Macro”).
An example of a parent macro which calls two separate child macros may be found in the .ZIP file located at the end of this article. These macros should be placed in the \ZEMAX\Macros directory, and are meant to be used with the file Cooke 40 degree field.zmx, located in the \ZEMAX\Samples\Objectives directory.
The parent macro (CALLMACRO_TEST_PARENT.ZPL) starts by defining arrays to hold data which will be returned by the child macros. The parent macro then fills the master macro buffer with both numeric values using the CALLSETDBL keyword and string values using the CALLSETSTR keyword:
FOR i, 1, n_vals, 1
CALLSETDBL i, 2*i # Test values to demonstrate use of
# CALLSETDBL, CALLSETSTR keywords
A$ = call_str$ + $STR(i)
CALLSETSTR i, A$
NEXT i
In this case the numeric and string values are simple test values used to demonstrate the method of passing data back and forth between parent and child macros.
The parent macro then calls the first child macro (CALLMACRO_TEST_CHILD1.ZPL) using the CALLMACRO keyword. In the child macro, values stored in the macro buffer are printed to the output window using the CALD and $CALLSTR numeric functions:
! Print values passed from parent macro
FOR i, 1, n_vals, 1
FORMAT 6.4
PRINT "Doule precision value = ", CALD(i)
FORMAT 2 INT
A$ = $CALLSTR(i)
PRINT A$
NEXT i
The macro then calculates the optical path difference for various tangential pupil coordinates (Py) at fixed sagittal pupil coordinate (Px = 0) and fixed field coordinates (Hx = Hy = 0) using the RAYTRACE keyword and the OPDC function:
! Calculate OPD
DECLARE x, DOUBLE, 1, n_vals # Variables to store OPD data
DECLARE y, DOUBLE, 1, n_vals
FOR i, 1, n_vals, 1
py = 0.04*i-1.04
RAYTRACE 0, 0, 0, py, 1
x(i) = py
y(i) = OPDC()
NEXT i
In this child macro, the values for the pupil coordinate (stored in the x array) are passed back to the parent macro using CALLSETDBL:
! Reset values to normalized pupil coordinates and pass
! them back to parent macro
call_str$ = "This is the string for variable number "
FOR i, 1, n_vals, 1
CALLSETDBL i, x(i)
A$ = call_str$ + $STR(i+50)
CALLSETSTR i, A$
NEXT i
New string values are also placed in the macro buffer as a test to ensure that this data is passed back to the parent. Once the child macro is finished, ZEMAX returns to the parent macro, and values for the pupil coordinate are stored in the appropriate array:
! Save values passed back from child macro 1
FOR i, 1, n_vals, 1
x(i) = CALD(i)
A$ = $CALLSTR(i)
PRINT A$
NEXT i
The parent macro then calls the second child macro (CALLMACRO_TEST_CHILD2.ZPL). This macro is identical to the first child macro – the only difference is that in this case, the OPD data (stored in the y array) are passed back to the parent macro rather than the pupil coordinates:
! Reset values to OPD results and pass them back to
! parent macro
call_str$ = "This is the string for variable number "
FOR i, 1, n_vals, 1
CALLSETDBL i, y(i)
A$ = call_str$ + $STR(i+100)
CALLSETSTR i, A$
NEXT i
New string values are again placed in the macro buffer as a test to ensure that this data is passed back to the parent. The numeric OPD data are then stored into an array in the parent macro:
! Save values passed back from child macro 2
FOR i, 1, n_vals, 1
y(i) = CALD(i)
A$ = $CALLSTR(i)
PRINT A$
NEXT i
Finally, the parent macro plots the OPD vs. pupil coordinate data using the PLOT keyword:
! Plot data
PLOT NEW
PLOT TITLE, "OPD FOR FIELD POINT 1, WAVELENGTH 1"
PLOT TITLEX, "NORMALIZED PUPIL COORDINATE"
PLOT TITLEY, "OPTICAL PATH DIFFERENCE (WAVES)"
PLOT RANGEX, -1.0, 1.0
PLOT RANGEY, -1.0, 1.0
PLOT DATA, x, y, n_vals, 1, 1, 1
PLOT GO
More information on this keyword may be found in Chapter 22 of the ZEMAX manual, and in the following Knowledge Base article: “How to Use the PLOT keyword in ZPL”. Results are then plotted to a graphics window:

This example illustrates how the CALLMACRO keyword may be used to call child macros from within a parent macro, and how data may be passed back and forth between these programs.