Oct 14, 2021

How to create a User Analysis using ZOS-API

Category: Product News
How to create a User Analysis using ZOS-API

The application programming interface (ZOS-API) available for OpticStudio enables connections to, and customization of, the application using the latest software technology. ZOS-API is a COM-based interface rooted in .NET libraries that provides users with the ability to program in several languages including C++, Python, and Matlab.

For this blog post, we will focus on the User Analysis Mode. This mode is linked to a single analysis window and is used to populate data for custom analysis. The data is displayed OpticStudio graphics windows. This mode only allows changes to a copy of the current system. User analyses can be written using either C++ (COM) or C# (.NET) – depending on the user’s comfort with either language.

This post shows an example of a bespoke User Analysis created using ZOS-API.

Open new boilerplate template

To create a User Analysis in C#, we need to select Programming...C#...User Analysis.

Create a User Analysis in C#

Windows Explorer opens with the solution folder {Zemax}\ZOS-API Projects\CSharpUserAnalysisApplication1. Your default C# development program will also open. The solution contains a boilerplate code that can be used as the basis for any User Analysis.

Reading in the Lens Data Editor

We will create a User Analysis specifically for the Double Gauss example file located in {Zemax}\Samples\Sequential\Objectives\Double Gauss 28-degree field.zmx.

We will vary the thickness of Surface 6 by +/- 1 mm in steps of 10 um and study the behavior of the Modulation Transfer Function (MTF) at 30, 40 and 50 cycles/mm.

Reading in the Lens Data Editor

First, add 3 lines at the top of the code. We need to set a namespace and then can use the interfaces inside without specifying the full path.

using ZOSAPI.Editors.MFE;
using ZOSAPI.Editors;
using ZOSAPI.Tools.General;

Then, find the "// Add your custom code here..." and start coding. We change the window title, and read in the Lens Data Editor (LDE) and declare arrays to hold the analysis data.

// Add your custom code here...

TheAnalysisData.WindowTitle = "MTF vs. Thickness";

ILensDataEditor TheLDE = TheSystem.LDE;

ILDERow surf6 = TheLDE.GetSurfaceAt(6);

double[ ] MTFs30 = new double[201];
double[ ] MTFs40 = new double[201];
double[ ] MTFs50 = new double[201];
double[ ] surf6Thic = new double[201];

Please remember that C# is strongly typed, which means you have to specify the data type of your variable when you declare it.

Setting up the Merit Function Editor

Next, add 3 operands, change them to MTFS (Modulation transfer function, sagittal), set the sampling (Parameter 1) to 64x64 and the frequency (Parameter 4) to 30, 40, and 50 cycles/mm respectively. As these blocks are very similar, you should be able to make use of Copy & Paste (Ctrl+C, Ctrl+V).

IMeritFunctionEditor TheMFE = TheSystem.MFE;
IMFERow Operand_1 = TheMFE.AddOperand();
IEditorCell Op1Samp = Operand_1.GetOperandCell(MeritColumn.Param1);
Op1Samp.IntegerValue = 2;  
IEditorCell Op1Freq = Operand_1.GetOperandCell(MeritColumn.Param4);

Op1Freq.DoubleValue = 30;

IMFERow Operand_2 = TheMFE.AddOperand();
IEditorCell Op2Samp = Operand_2.GetOperandCell(MeritColumn.Param1);
Op2Samp.IntegerValue = 2;
IEditorCell Op2Freq = Operand_2.GetOperandCell(MeritColumn.Param4);
Op2Freq.DoubleValue = 40;

IMFERow Operand_3 = TheMFE.AddOperand();
IEditorCell Op3Samp = Operand_3.GetOperandCell(MeritColumn.Param1);
Op3Samp.IntegerValue = 2;
IEditorCell Op3Freq = Operand_3.GetOperandCell(MeritColumn.Param4);
Op3Freq.DoubleValue = 50;

Setting up the Merit Function Editor

Using a loop to compute analysis data points

To fill the arrays with data, vary the thickness of surface 6 and run a QuickFocus before computing the Merit Function. Then we can write each Operand value in its respective data array.

double step = 0.01;
surf6.Thickness = surf6.Thickness - 100 * step;

for (int i = 0; i < 201; i++)

surf6.Thickness = surf6.Thickness + step;
surf6Thic[i] = surf6.Thickness;

quickFocus = TheSystem.Tools.OpenQuickFocus();
quickFocus.Criterion = QuickFocusCriterion.SpotSizeRadial;
quickFocus.UseCentroid = true;


MTFs30[i] = Operand_1.Value;
MTFs40[i] = Operand_2.Value;
MTFs50[i] = Operand_3.Value;

Plot results

Finally, use TheAnalysisData to create a specific plot type and populate the data. If you have ever created a user analysis using DDE you will find the plotting via ZOS-API much more straightforward and flexible. 

IUser2DLineData linePlot = TheAnalysisData.Make2DLinePlot

("MTF vs. Surface 6 Thickness", 201, surf6Thic);

linePlot.AddSeries("MTF 30 cycles/mm", ZemaxColor.Color1, 201, MTFs30);
linePlot.AddSeries("MTF 40 cycles/mm", ZemaxColor.Color2, 201, MTFs40);
linePlot.AddSeries("MTF 50 cycles/mm", ZemaxColor.Color3, 201, MTFs50);

linePlot.XLabel = "Surface 6 Thickness [mm]";
linePlot.YLabel = "MTF";

There are currently four types of data that can be calculated and displayed:

  • 2D Line Plot
  • 2D Grid Plot
  • 2D RGB Grid Plot
  • Text Data 

Note that only one format of data is allowed per User Analysis.

Save, build and move executable

We build the solution as a Release. Using Debug mode is fine when you’re debugging, but when distributing a plugin, you should always use Release mode, since the Debug libraries are not redistributable. Therefore let’s switch to release mode and rebuild.

Release mode and rebuild
Build solution

We need to navigate to our solution folder ({Zemax}\ZOS-API Projects\...), locate the project folder and then move the finished application to {Zemax}\ZOS-API\User Analysis.

Run the User Analysis

To check our new User Analysis, we can now start OpticStudio and open the lens file {Zemax}\Samples\Sequential\Objectives\Double Gauss 28 degree field.zmx.

Under the Programming tab, we go to User Analyses, there should now be the analysis that we just made.


When we click it, we get the results of our User Analysis!

User Analysis Results

Further possibilities 

In this example, the surface is varied, the variation range and step size and the spatial frequencies at which the MTF is reported are hardcoded, but it is straightforward to add a settings dialogue to allow these inputs to be specified by the user. This way we can create a User Analysis that can be used more universally. Settings are stored in a simple dictionary consisting of key-value pairs. The dictionary is empty when your Analysis is first launched. However, any entries you add to the Settings Dictionary will be saved between updates and can be stored with the session.

We have now covered what a User Analysis is, how to open a boilerplate template, and how to generate and plot bespoke analysis data. To learn much more about how to harness the power of ZOS-API please check out the comprehensive free tutorial Getting Started with ZOS-API. To try out Zemax capabilities please download a free trial here.


Dr. Thomas Pickering
Senior Product Manager
Zemax, LLC