User Scripts

In the ./scripts directory of the repository you can find several scripts for various tasks. Since they are using the mascado module, you have to make that available in your python path (for example by installing the package via, or run the scripts from the repository root using:

$ scripts/SCRIPTNAME ARGS...

Zemax Grid Distortion Data


In Zemax export distortions by clicking Analysis in the menu. Then select Miscellaneous and Grid Distortion. After a right click into the window, a dialog with setup options pops up. Click on Text in the menu to get a text file with the data points and save that somewhere. The exported TXT file is Latin-1 encoded and should look like:

Listing of Grid Distortion Data

File : ...
Title: EELT Optical System Specification
Date : ...

Units are Millimeters.
Field units are degrees
Wavelength: 1.00000 µm
Reference Coordinates: Xref = 0.00000E+000, Yref = 0.00000E+000

   i    j       X-Field       Y-Field       R-Field   Predicted X   Predicted Y        Real X        Real Y     Distortion
  -6   -6 -7.50000E-003 -7.50000E-003  1.06066E-002 -8.95381E+001 -8.95381E+001 -8.95362E+001 -8.95362E+001     -0.00
   6    6  7.50000E-003  7.50000E-003  1.06066E-002  8.95381E+001  8.95381E+001  8.95362E+001  8.95362E+001     -0.002150%

Maximum distortion: -0.0021%
Predicted coordinate ABCD matrix:
A =    6.84e+005
B =            0
C =            0
D =    6.84e+005

SMIA TV Distortion -0.0011%

The mascado_analyze and mascado_compare scripts read these files and use the X-Field, Y-Field, Real X, and Real Y columns to calculate properties of the distortion pattern. The plate scale from Zemax is not used, but an affine transformation, defined be the least-squares solution of Real to Field coordinates translates the distorted pattern back onto the sky. For that reason the pattern displayed to you looks a bit different than the pattern displayed in Zemax. Polynomial fits are done in the transformed coordinate set, i.e. sky coordinates.

The Field units are assumed to be degrees. If that is not the case, use the --scale command line argument to define a plate scale relating to degrees. Otherwise the displayed units are wrong. In any case, try the --help argument for a description of script options.

An example invocation would be:

$ mascado_analyze --maxorder 6 "../Zemax Grids/ELT_MC20.TXT" --saveplot ../tmp/MC20.png

If your exported Zemax file has a different encoding than Latin-1 (ISO 8859-1), use the --encoding argument of the scripts. Although UTF-8 and Latin-1 are indistinguishable for ASCII characters.


The output figure has four panels. The upper left panel shows the distortions in sky coordinates after the affine transform. The reference point in Zemax is irrelevant, because a least-squares solution is used to relate the detector to on-sky coordinates. The upper right panel shows the residuals of the highest order fit and their marginalized distributions. The arrow key is, similar to the first panel, twice the RMS of the residuals. With simulation data the residuals often show small scale systematic patterns that may come from the accuracy of Zemax’s simulations.

The steps performed to obtain the polynomial fit are as follows:

  1. Read on-sky grid \(x_\text{ref}\) and detector grid \(x_\text{detector}\) from data file.

  2. Compute affine transform \(A\) from detector coordinates to sky coordinates and apply: \(\hat x = A x_\text{detector}\). (The compare_grids script applies the same trafo to both input grids.)

  3. The distortions are defined as \(d = \hat x - x_\text{ref}\). The affine trafo was chosen in the previous step, such that the distortions are minimal in the least-squares sense. (The drift in compare_grids is calculated by subtracting the two distortions grids: \(d = d_2 - d_1\).)

  4. Normalize the reference positions \(x_\text{norm} = x_\text{ref} / \text{scale} - \text{shift}\) by a shift and a scale into the domain \([-1, 1]\times[-1, 1]\). This normalization is transparent in the script (you don’t have to care about it) but an important thing to remember when reusing the code. The offset of the normalization is not restored, such that the resulting field is always centered on \((0, 0)\). The magnitude of the distortions is not scaled during calculations.

  5. Fit a polynomial vector field \(P(x_\text{norm}) \approx d\).

The lower two panels are scatter plots showing properties of the polynomial fit at different orders. Since the polynomial is used to fit the distortions only, the zeroth and first order terms are incomplete, because the affine transform was already removed. The drift in compare_grids compares two distortion solutions after the same affine trafo, so the zeroth and first order terms have a significant interpretation that is only influenced by the scale of the affine trafo.

The lower left panel shows the RMS of residuals \((r_{x,i}, r_{y,i})\), \(i=1...n\), calculated as

\[\operatorname{rms} r = \sqrt{\frac{\sum_i^n \left(r_{x,i}^2 + r_{y,i}^2\right)}{2 n}} = \operatorname{rms}\{\operatorname{rms} r_x, \operatorname{rms} r_y\}\]

The lower right panel shows the RMS of the distortions encoded by the terms of a specific order in the highest order fit. It is calculated by setting the coefficients for all other terms to zero and evaluating the model on a regular \(100\times100\) point grid.

Input Format Variants

Scripts and macros in Zemax might produce different outputs, so some slightly different formats might be implemented over time. Currently there are two variants additional to the default format.

In most cases the exact content of non-tabular lines is ignored, because only a specific number of lines is skipped in the beginning and end.

The format variant can be chosen using the --format LETTER argument.

Variant B:

Executing PATH
A -7.44068E+005
B 1.70508E-003
C -3.78466E-005
D -7.50941E+005
EFFL  -6.31490E+005   mm
       Npoint         Input_X deg     Input_Y         Distorted_X mm          Distorted_Y
1.00000E+000 -7.49999E-003  -7.49995E-003  9.44980E+001  9.66661E+001
2.00000E+000 -7.49993E-003  -6.74997E-003  9.47787E+001  8.72730E+001

Variant C:

X_error[deg],     Y_error[deg],     X_perfect[deg],      Y_perfect[deg],    X_FP_dist[mm],    Y_FP_dist[mm]
 -0.00749242   -0.00749241   -0.00749243   -0.00749243        96.782     99.0399
 -0.00749243   -0.00699296   -0.00749243   -0.00699293        96.981       92.63
 -0.00749243   -0.00649344   -0.00749243   -0.00649343       97.1762     86.2092

which will compare X_error,Y_error against X_FP_dist,Y_FP_dist.

Power Spectra

With the additional argument --psd to one of the scripts a second figure with another four panels is created and displayed after closing the first figure. By supplying --savepsdplot, displaying the plot is suppressed but it is written to an image file.

The upper two panels contain the unbinned 2D power spectrum for the x- and y-components of the vector field with logarithmic color bar and an arbitrary linear power unit. The lower left panel shows the binned power spectra. The lower right panel displays the cumulative version of the lower left panel, where the distributions in x- and y-direction are expressed relative to the total power.

The “critically sampling pinhole spacing” is the maximum spacing for a pinhole grid covering the FOV for which the corresponding frequency critically sampled. For example the offset needs only one point, so an infinite spacing is enough. The first frequency is one oscillation across the FOV which needs two points, so the maximum spacing is FOV/2.

Please take the results of the PSD with a grain of salt, because we are working with Polynomial vector fields, which are usually not band-limited with respect to the chosen sampling. Therefore, even when the cumulative PSD plot shows 100%, some information is lost. Additionally, no window function is used!