An example macro (PLOT2D_TEST.ZPL) illustrating use of the PLOT2D keyword is provided as a part of the ZEMAX installation (i.e. the macro is located in the directory \ZEMAX\Macros\). This macro can be run with any ZEMAX file, as it does not use any data from the lens file.
The macro begins by defining a two-dimension data array (xy_data), and then specifying values for the array according to a radially symmetric distribution:
! Set up an array to hold 2D data
nx = 100 # Number of X points
ny = 100 # Number of Y points
DECLARE xy_data, DOUBLE, 2, nx, ny # 2D array of XY
data points
! Fill the 2D array with a radially symmetric distribution
maxval = 5000.0 # Maximum value for
the array
FOR i, 1, nx, 1
FOR j, 1, ny, 1
radsqr = (i - 0.5*nx)*(i - 0.5*nx) +
(j - 0.5*ny)*(j - 0.5*ny)
xy_data(i,j) = maxval - radsqr
NEXT j
NEXT i
Settings for the various PLOT2D arguments are then provided:
! Define settings for data plot
title$ = "Plot of XY data" # Plot title
comment1$ = "This is a simple test" # Plot comment
line #1
comment2$ = "to determine if the" # Plot comment
line #2
comment3$ = "PLOT2D keyword is" # Plot comment
line #3
comment4$ = "working correctly" # Plot comment
line #4
comment5$ = "for all inputs." # Plot comment
line #5
rmin = 0.0 # Minimum plot value
rmax = maxval # Maximum plot value
ratio = 1.0 # Plot aspect ratio
winrat = 0 # Window aspect ratio
actlft = -10.0 # Active cursor
left value
actbot = -10.0 # Active cursor
bottom value
actrgt = 10.0 # Active cursor
right value
acttop = 10.0 # Active cursor
top value
distyp = 5 # Display type
cnval$ = "900.0 2700.0 3400.0" # Contour format
sscale = 0.75 # Surface scaling
factor
lgpeak = 4 # Log plot peak value
lgdecd = 4 # Log plot decade
value
lgtype = 0 # Log plot flag
addshow = 1 # Flag for whether
to show address
in plot
conshow = 0 # Flag for whether
to show config
number in plot
Settings have been provided for the plot title (title$), plot range (rmin, rmax), etc. A number of PLOT2D commands are then issued to plot the results in a graphical display window, with the corresponding title, plot range, etc.:
! Plot the data
PLOT2D NEW
PLOT2D TITLE, ti$
PLOT2D COMM1, cm1$
PLOT2D COMM2, cm2$
PLOT2D COMM3, cm3$
PLOT2D COMM4, cm4$
PLOT2D COMM5, cm5$
PLOT2D RANGE, rmin, rmax
PLOT2D ASPECT, ratio
PLOT2D WINASPECT, winrat
PLOT2D ACTIVECURSOR, actlft, actrgt, actbot, acttop
PLOT2D DISPLAYTYPE, distyp
IF (distyp == 1) THEN PLOT2D SURFACESCALE, sscale
IF (distyp == 2) THEN PLOT2D CONTOURINTERVAL, cnval$
IF (lgtype == 1)
FOR i, 1, nx, 1
FOR j, 1, ny, 1
xy_data(i,j) = LOGT(xy_data(i,j))
NEXT j
NEXT i
PLOT2D LOGPLOT, lgpeak, lgdecd
ENDIF
PLOT2D HIDEADDRESS, addshow
PLOT2D CONFIG, conshow
PLOT2D DATA, xy_data
PLOT2D GO
Comments are provided in the macro for each of the PLOT2D commands (those comments have been omitted from this article for display purposes), and a full description of each of these commands may be found in the chapter of the ZEMAX manual entitled “ZEMAX Programming Language”. For the settings provided above, the resulting graphical output is:
As you can see, the PLOT2D keyword provides the user with a simple method for generating graphical displays of 2D numeric data.
An interesting use of the PLOT2D keyword is to generate through-focus PSF plots. An example macro (PLOT2D_PSF.ZPL) illustrating how this is done is also provided in the .ZIP file located at the end of this article. This macro is intended to be used with the Cooke triplet sample file (Cooke 40 degree field.zmx) provided with the ZEMAX installation (in the \ZEMAX\Samples\Sequential\Objectives\ directory).
Through-focus results are generated by obtaining results for the XY PSF at various values of the back focal length (BFL). The macro starts by defining
settings for the PSF calculation, as well as arrays to hold the resultant data:
! Define the settings for the PSF data to obtain (e.g.
! for the primary wavelength, at the on-axis field
! point, ...)
wavnum = PWAV() # Primary wavelength number
fldnum = 1 # Field point number for on-
axis field point
samnum = 2 # Sampling (1 = 32x32, 2 =
64x64, ...)
unflag = 1 # Unnormalized flag (0 =
normalized, 1 =
unnormalized)
phflag = 0 # Flag for data to return (0 =
intensity, 1 = phase)
imdelt = 0 # Image delta (0 = default)
n = 2*32*samnum # Number of PSF data points in
each direction
vsize = n*n + 1000 # Vector size
SETVECSIZE vsize # Set vector size
! Set up an array to hold XYZ PSF data
nz = n # Number of Z planes at which
calculation is done
DECLARE xyz_psf, DOUBLE, 3, n, n, nz # Full 3D array of
XYZ PSF data
DECLARE psf_data, DOUBLE, 2, n, n # 2D array to hold
XY PSF data at
each Z value
DECLARE psf_size, DOUBLE, 1, nz # Spacing between
data points
Calculations for the PSF are then performed for a number of Z locations, using a FOR loop. The first step in the loop is to change the BFL of the system, using the SURP keyword:
! Loop over all Z planes
bf_surf = NSUR() - 1 # Last surface before image
plane
bf_thic = THIC(bf_surf) # Thickness of last surface
before image plane
deltaz = 0.12 # Total range for back focal
length
bf_inc = deltaz/(nz - 1) # Incremental thickness change
cent_indx = 0.5*(nz + 1) # Index value corresponding to
nominal thickness
FOR i, 1, nz, 1
! Change the thickness of the last surface before
! image plane
new_thic = bf_thic + bf_inc*(i - cent_indx)
SURP bf_surf, 3, new_thic
UPDATE ALL
At each new value of the BFL, the XY PSF is obtained using the GETPSF keyword. Tests are conducted to ensure that the data were obtained successfully:
! Get the PSF data for this system
GETPSF wavnum, fldnum, samnum, 1, unflag, phflag, imdelt
! Test that the data was obtained successfully
np = vec1(0)
IF (np == 0)
PRINT "PSF Computation aborted."
GOTO 1
ENDIF
IF (np == -1)
PRINT "SETVECSIZE too small for PSF data."
GOTO 1
ENDIF
IF (np == -2)
PRINT "Not enough system RAM for PSF data."
GOTO 1
ENDIF
IF (np == -3)
PRINT "A general error occured while computing the PSF."
GOTO 1
ENDIF
The PSF data are then written into a 3D array, as well as into a 2D array that is used to generate plots of the XY PSF data at each value of the BFL:
! Write PSF data into the 3D array, as well as into
! a 2D array for plotting
FOR j, 1, n, 1
FOR k, 1, n, 1
pos = n*(j-1) + k
xyz_psf(k,j,i) = vec1(pos)
psf_data(k,j) = vec1(pos)
NEXT k
NEXT j
! Determine the grid spacing for the PSF calculation
psf_size(i) = vec1(np+1)
! Plot the XY results at different planes, if desired
xy_plot = 0
IF (xy_plot == 1)
PLOT2D NEW
PLOT2D TITLE, "XY PSF"
PLOT2D COMM1, $STR(WAVL(wavnum))+" MICRONS AT (X,Y) =
("+$STR(FLDX(fldnum))+", "+$STR(FLDY(fldnum))+")"
PLOT2D COMM2, "THICKNESS OF THE LAST SURFACE =
"+$STR(new_thic)
PLOT2D DATA, psf_data
PLOT2D GO
ENDIF
LABEL 1
NEXT i
The grid spacing for the PSF calculation is also read into a variable. This data is used to check that calculations are performed with the same spacing at each value of the BFL:
! Make sure that the spacing between points was the same
! for all focal planes
psf_temp = psf_size(1)
psf_flag = 1
FOR i, 2, nz, 1
psf_delta = psf_size(i)
IF (psf_delta != psf_temp)
PRINT "Array sizes do not agree!"
psf_flag = 0
GOTO 2
ELSE
psf_temp = psf_delta
ENDIf
NEXT i
psf_totsiz = n*psf_delta # Total size of
the image in
X and Y, in
microns
psf_totsiz = psf_totsiz/1000.0 # Convert size
to lens units
(assumes lens
units = mm)
psf_ratio = psf_totsiz/deltaz # Ratio of X/Y-
width to Z-width
Finally, separate 2D arrays are created for plotting the XZ PSF data at Y=0 and the YZ PSF data at X=0:
! Plot XZ PSF data at Y = 0, false color
DECLARE xz_psf, DOUBLE, 2, n, nz
ypos = n/2 # Index value for y = 0
FOR i, 1, nz, 1
FOR j, 1, n, 1
xz_psf(j,i) = xyz_psf(j,ypos,i)
NEXT j
NEXT i
PLOT2D NEW
PLOT2D TITLE, "XZ PSF"
PLOT2D COMM1, "SURFACE: Y = 0"
PLOT2D COMM2, $STR(WAVL(wavnum))+" MICRONS AT (X,Y) =
("+$STR(FLDX(fldnum))+", "+$STR(FLDY(fldnum))+")"
PLOT2D COMM3, "TOTAL X-SIZE (X-AXIS), LENS UNITS = "+
$STR(psf_totsiz)
PLOT2D COMM4, "TOTAL Z-SIZE (Y-AXIS), LENS UNITS = "+
$STR(deltaz)
PLOT2D ASPECT, psf_ratio
PLOT2D DISPLAYTYPE, 5
PLOT2D HIDEADDRESS, 1
PLOT2D DATA, xz_psf
PLOT2D GO
! Plot YZ PSF data at X = 0, false color
DECLARE yz_psf, DOUBLE, 2, n, nz
xpos = n/2 # Index value for x = 0
FOR i, 1, nz, 1
FOR j, 1, n, 1
yz_psf(j,i) = xyz_psf(xpos,j,i)
NEXT j
NEXT i
PLOT2D NEW
PLOT2D TITLE, "YZ PSF"
PLOT2D COMM1, "SURFACE: X = 0"
PLOT2D COMM2, $STR(WAVL(wavnum))+" MICRONS AT (X,Y) =
("+$STR(FLDX(fldnum))+", "+$STR(FLDY(fldnum))+")"
PLOT2D COMM3, "TOTAL Y-SIZE (X-AXIS), LENS UNITS = "+
$STR(psf_totsiz)
PLOT2D COMM4, "TOTAL Z-SIZE (Y-AXIS), LENS UNITS = "+
$STR(deltaz)
PLOT2D ASPECT, psf_ratio
PLOT2D DISPLAYTYPE, 5
PLOT2D HIDEADDRESS, 1
PLOT2D DATA, yz_psf
PLOT2D GO
! Plot YZ PSF data at X = 0, surface
PLOT2D NEW
PLOT2D TITLE, "YZ PSF"
PLOT2D COMM1, "SURFACE: X = 0"
PLOT2D COMM2, $STR(WAVL(wavnum))+" MICRONS AT (X,Y) =
("+$STR(FLDX(fldnum))+", "+$STR(FLDY(fldnum))+")"
PLOT2D COMM3, "TOTAL Y-SIZE (X-AXIS), LENS UNITS = "+
$STR(psf_totsiz)
PLOT2D COMM4, "TOTAL Z-SIZE (Y-AXIS), LENS UNITS = "+
$STR(deltaz)
PLOT2D DISPLAYTYPE, 1
PLOT2D HIDEADDRESS, 1
PLOT2D DATA, yz_psf
PLOT2D GO
The number of iterations in the loop, as given by the variable nz, is the number of BFL values for which the 3D XYZ PSF data were calculated. For the above case, nz =128, while the BFL varies by a total distance of 120 mm (nz was chosen according to the sampling used to generate the XY PSF at each Z plane; the values for nz and for the range of BFL values ensure that there are the same number of points in X, Y, and Z and that they cover the same physical space). For such a large number of calculations, the computation will be slow, so be sure to exercise some patience while running the macro! However, once the PSF calculations are complete, PLOT2D may be used to plot the data in multiple formats if you like, without any noticeable change to the computational time. In other words, the computational time is determined by the time required perform the PSF calculations, and not the time required to perform the plotting. To demonstrate this fact, the macro uses PLOT2D to generate both a false color plot and a surface plot of the YZ PSF data. For the Cooke triplet on-axis, the results are the same for both the XZ and YZ PSF:
