ZEMAX (also known as OpticStudio), a
leading tool for design and analysis of optical systems, provides
an in-built DDE server
that enables access to ZEMAX’s
features externally using any Windows application.
The ability to access and control ZEMAX externally allows it to be
used in many interesting and powerful ways, some of which has been
documented in the “ZEMAX Extensions” chapter of the ZEMAX
manual. An excellent toolbox
called MZDDE, developed by Derek Griffith at CSIR,
already exists for users of MATLAB. When I tried to look for an
equivalent toolbox in Python, I couldn’t find one, so I decided to
write one myself.
PyZDDE is a Python-based toolbox for communicating with ZEMAX using
the DDE messaging protocol. It is similar to MZDDE
and very much inspired by it. Currently PyZDDE is not as extensive
as MZDDE as it is a work in progress. However, it has some
distinguishing features — it can be used with regular Python
scripts and also in an interactive environment such as
anIPython shell,QtConsoleorIPython
notebook.
The ability to interact with ZEMAX from an IPython notebook using
PyZDDE can be a powerful tool for both teaching and documentation.
Please visit thegithub repositoryfor
downloading and using the code. The github repository also contains
an accompanyingwiki pagewhich
describes briefly on how to use the PyZDDE toolbox.
Here I would like to briefly document the communication process
between ZEMAX and Python using PyZDDE. But before that I would like
to show you how simple it is to communicate with Zemax using PyZDDE
using a “Hello world” example (it gets and prints the running Zemax
version):
import pyzdde.zdde as pyz
link = pyz.createLink()
print("Hello Zemax version: ", link.zGetVersion())
link.close()
Zemax maintains a separate copy of a lens in the DDE server and all
processing/modifications using any external application is done on
this lens residing in the DDE server. The lens (if any) in the LDE
is not modified by the DDE calls. One can of course move the lens
in the DDE server to the LDE (using zPushLens)
or move the lens in the LDE to the DDE server
(using zGetRefresh).
The basic sequence of steps of accessing ZEMAX (the DDE server)
from Python (the DDE client) are as follows:
Start the ZEMAX application.
Import the pyzdde module (import
pyzdde.zdde as pyz) and create a DDE communication object
object (link
= pyz.createLink()) in a Python script, IPython QtConsole
(interactive environment) or IPython notebook.
Now, if you want to work with a lens in the LDE,
use link.zGetRefresh() to
copy the lens from the LDE to the DDE server. Else, load a ZEMAX
lens file directly into the DDE server using the
function link.zLoadFile().
You can of course build an optical system from scratch entirely
through PyZDDE.
Once all calculations (depending on the application) have
completed, use link.close() to
terminate the DDE communication.
The figure below illustrates the above
process.
Currently, all the functions (126 in total) for accessing the ZEMAX
using “data items” have been implemented. In addition, there are
few utility functions. At this point in time, a distribution
version is not available as the toolbox is being updated regularly.
Please download the code folder to a local directory in your
computer and add that directory to python search path in order to
use it (please see the github wikifor
details).
There are 4 types of functions in the toolbox:
Functions for accessing ZEMAX using the data items as defined in
the “ZEMAX EXTENSIONS” chapter of the ZEMAX manual. These
functions’ names start with “z”
and the rest of the function-names match the corresponding
data-item defined by Zemax. For examplezGetSolve, zSetSolve,
etc.
Helper functions to enhance the toolbox functionality beyond just
the data items, such aszLensScale, zCalculateHiatus, zSpiralSpot.
Also, there are other helper functions which increase the
capability of the toolbox such as zOptimize2, zSetWaveTuple,
etc. More functions are expected to be added over time.
Few functions, which start with “ipz“,
such as ipzCaptureWindow, ipzGetTextWindow can
be used to embed analysis, graphic windows and text files from
Zemax into an IPython Notebook or IPython QtConsole.
There are several other functions which can be used independent of
a running Zemax session. Examples
include showZOperandList, findZOperand, findZButtonCode,
etc. More functions are expected to be added over time.
All the functions prefixed with “z”
or “ipz”
(types 1, 2 and 3) interact with Zemax directly
and hence require a Zemax session to running
simultaneously.As
they are instance methods of a pyzdde channel object, a pyzdde
object needs to be created.
For example:
import pyzdde.zdde as pyz
ln = pyz.createLink() # create a DDE communication link
Helper functions of type 4 can be accessed the the `zdde` module
directly.
For example:
pyz.zo.findZOperand("decenter") # same as calling pyz.findZOperand("decenter")
ZEMAX settings
PUSH LENS PERMISSION: All operations through the DDE affect the
lens in the DDE server. In order to copy the lens the lens from the
DDE server to the main application/LDE, you need to “push” the lens
from the server to the LDE. TO do so, please enable the option
“Allow Extensions to Push Lenses”, under
File->Preferences->Editors tab.
ANSI/UNICODE TEXT ENCODING: PyZDDE supports both ANSI and UNICODE
text from Zemax. Please set the appropriate text encoding in PyZDDE
to by calling module functionpyz.setTextEncoding(text_encoding) (assuming
that PyZDDE was imported as import
pyzdde.zdde as pyz). By default, ANSI text encoding is set
in PyZDDE. You can check the current text encoding by
calling pyz.getTextEncoding() function.
Please note that you need to do this only when you change the text
setting in Zemax and not for every session.
PURE NSC MODE: If want to work on an optical design in pure NSC
mode, please start ZEMAX in pure NSC mode before initiating the
communication with PyZDDE. There is no way to switch the ZEMAX mode
using external interfaces.
Getting started
For getting started, please refer to
theGetting startedpage
at github wiki.
See how PyZDDE may be used interactively
at
Also, there is an example
The following is an example Python script used to produce a spiral
spot diagram (see figure below).
from __future__ import print_function
import sys
import os
import matplotlib.pyplot as plt
import pyzdde.zdde as pyz
# The ZEMAX file path
zmxfp = cd + '\\ZMXFILES\\'
zmxfile = 'Cooke 40 degree field.zmx'
filename = zmxfp + zmxfile
# Create a DDE comm link
ln = pyz.createLink()
# Load a lens file into the ZEMAX DDE server
ln.zLoadFile(filename)
hx, hy = 0.0, 0.4
spirals, rays = 100, 6000
xb, yb, _, _, = ln.zSpiralSpot(hx, hy, 1, spirals, rays)
xg, yg, _, _, = ln.zSpiralSpot(hx, hy, 2, spirals, rays)
xr, yr, _, _, = ln.zSpiralSpot(hx, hy, 3, spirals, rays)
fig = plt.figure(facecolor='w')
ax = fig.add_subplot(111)
ax.set_aspect('equal')
ax.scatter(xr, yr, s=5, c='red' , linewidth=0.35, zorder=20)
ax.scatter(xg, yg, s=5, c='lime', linewidth=0.35, zorder=21)
ax.scatter(xb, yb, s=5, c='blue', linewidth=0.35, zorder=22)
ax.set_xlabel('x')
ax.set_ylabel('y')
fig.suptitle('Spiral Spot')
ax.grid(color='lightgray', linestyle='-', linewidth=1)
ax.ticklabel_format(scilimits=(-2,2))
# close the communication channel
pyz.closeLink()
plt.show()
Output of the
above Python script.(插入一句,此spot让人感到邪恶
)
UPDATE [01/26/2014]:
I have also written a Zemax knowledge-base article called “Talking
to ZEMAX from Python using PyZDDE”. That article gives a more
complete overview of the toolbox. The link to the knowledge-base
article is
Is there anything missing?
The short answer is yes! At this time you cannot perform bulk/
array ray tracing with PyZDDE. I hope that in the near future, this
issue will be resolved.