ZEMAX Users' Knowledge Base - http://www.zemax.com/kb
How to Use the PLOT2D keyword in ZPL
http://www.zemax.com/kb/articles/248/1/How-to-Use-the-PLOT2D-keyword-in-ZPL/Page1.html
By Sanjay Gangadhara
Published on 24 June 2008
 
This article describes use of the PLOT2D keyword for generating graphical displays of 2D numerical data in ZEMAX. Examples are provided to demonstrate use of the keyword, and its application in creating through-focus PSF plots.

Introduction
Plots of 2D numeric data may be easily created in ZPL using the PLOT2D keyword. This keyword supports a number of arguments, making it easy to generate surface, contour, grey scale, and false color plots. In this article, we provide a simple example demonstrating the use of the PLOT2D keyword. An example is also provided to illustrate how through-focus PSF plots may be generated using PLOT2D.

A simple example

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:

False color plot of a radially symmetric distribution, using PLOT2D

As you can see, the PLOT2D keyword provides the user with a simple method for generating graphical displays of 2D numeric data.


Through-focus PSF plots

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:

False color plot of the XZ PSF

Surface plot of the YZ PSF


Summary
The PLOT2D keyword can be used to easily generate surface, contour, grey scale, and false color plots in ZEMAX. This tool is valuable for looking at cross-section plots of 3D numerical data, as well as any other 2D data of interest.