This article provides sample code for performing some basic actions using the ZOS-API through MATLAB, including interacting with the lens data and running a ray trace in both Sequential and Non-Sequential modes. The techniques demonstrated here can also be transferred to other similar API functionality.

Authored By Michael Humphreys


In this article, we present a series of code snippets in MATLAB to demonstrate a few specific actions via the API. For a more general introduction to the ZOS-API, or for alternative examples written in Python, please visit the linked related articles.

Sequential single ray trace

The sample code below performs a single ray trace and will output the results to the file C:\temp\output_file.txt. Currently, the API does not support the detailed analysis results, so the results object will be empty.

% Single Ray Trace

TheAnalyses  = TheSystem.Analyses;

newWin = TheAnalyses.New_Analysis(ZOSAPI.Analysis.AnalysisIDM.RayTrace);   

newWin_Settings = newWin.GetSettings();
newWin_Settings.Hx = 0;
newWin_Settings.Hy = 1;
newWin_Settings.Px = 0;
newWin_Settings.Py = 1;
newWin_Settings.Type = ZOSAPI.Analysis.Settings.Aberrations.RayTraceType.DirectionCosines;

% Get and Save the results
newWin_Results = newWin.GetResults();

Create NSC file and insert object

The sample code below creates a new file in Non-Sequential Mode in MATLAB. The boilerplate code only uses .PrimarySystem, which is either Sequential or Non-Sequential Mode depending on the user defaults. Here, a new system is initialized in Non-Sequential Mode explicitly, and then performs some interactions with the Non-Sequential Component Editor.

% Initializes new NSC system, inserts an object, changes an object type, and saves system
% Initializes into NSC Mode
TheSystem = TheApplication.CreateNewSystem(ZOSAPI.SystemType.NonSequential);

% Creates new file

% Non-sequential component editor & changing object
TheNCE = TheSystem.NCE;
Object_1 = TheNCE.InsertNewObjectAt(1);
Object_2 = TheNCE.GetObjectAt(1);
oType_1 = Object_1.GetObjectTypeSettings(ZOSAPI.Editors.NCE.ObjectType.StandardLens);

% Saving System

Change parameter in Sequential Mode

The code below inserts a new surface via MATLAB, changes the surface type, and sets the material and parameter 1 columns to a string variable and a double variable respectively.

% Inserts new lens, changes surface type & changes parameter 1 value


Surface_1 = TheLDE.GetSurfaceAt(1);

colVal = Surface_1.GetSurfaceCell(ZOSAPI.Editors.LDE.SurfaceColumn.Material).Col;
Surface_1.GetCellAt(colVal).Value = 'SF2';
colVal = Surface_1.GetSurfaceCell(ZOSAPI.Editors.LDE.SurfaceColumn.Par1).Col;

% can also use .IntegerValue for integers
Surface_1.GetCellAt(colVal).DoubleValue = 0.1;

Create a solve in Sequential Mode

There are some properties hardcoded into the ZOS-API that use invalid characters in MATLAB, such as starting the property name with an underscore. For example, setting an F/# curvature solve on a cell is documented as using _S_FNumber as the property but this is invalid syntax for MATLAB. To list all the properties of a given object, simply print out the object by not including a semicolon at the end, determine the MATLAB specific property name and use this as you would normally with the ZOS-API documentation.

% creates the LDE
TheLDE = TheSystem.LDE;
Surface_3 = TheLDE.InsertNewSurfaceAt(3);

% lists the properties of the CreateSolveType method
Solver = Surface_3.RadiusCell.CreateSolveType(ZOSAPI.Editors.SolveType.FNumber)

Scrolling down in the MATLAB Command Window, you can see that the property name is S_FNumber_ with the underscore trailing the property name and not before the property name. 

The full FNumber solve will then look like:

% creates the LDE
TheLDE = TheSystem.LDE;
Surface_3 = TheLDE.InsertNewSurfaceAt(3);

% lists the properties of the CreateSolveType method
Solver = Surface_3.RadiusCell.CreateSolveType(ZOSAPI.Editors.SolveType.FNumber);
Solver.S_FNumber_.FNumber = 10;

Insert operand (index to 10 decimal places)

When modeling a glass in the LDE, the LDE will always return 2 decimal places for the index and 1 decimal place for the Abbe number if you use TheLDE.GetSurfaceAt(1).Material property. In order to see more decimal places, the Merit Function must be used to get the values.

% Set up primary optical system
TheSystem = TheApplication.CreateNewSystem(ZOSAPI.SystemType.Sequential);
surface = 1;

% creates new file
TheLDE = TheSystem.LDE;

% sets surface 1 to N-BK7 and then changes this to a model material
s1 = TheLDE.GetSurfaceAt(surface);
s1.Material = 'N-BK7';

% get value directly from LDE (only shows 2 sig figs)
TheLDE = TheSystem.LDE;

% get value from merit function (shows double precision)
TheMFE = TheSystem.MFE;
mfo_1 = TheMFE.InsertNewOperandAt(1);
mfo_1.GetCellAt(2).IntegerValue = surface;  % surface
mfo_1.GetCellAt(3).IntegerValue = 1;        % wavelength

% abbe number by using a boundary operand (independent of wavelength)
mfo_2 = TheMFE.InsertNewOperandAt(2);
mfo_2.GetCellAt(2).IntegerValue = surface;
mfo_2.GetCellAt(3).IntegerValue = surface;

% updates the merit function and gets the values for index and abbe
index_1 = mfo_1.ValueCell.Value
abbe_1 = mfo_2.ValueCell.Value

Run an NSC ray trace with Filter String

This allows a user to setup an NSC ray trace, apply a Filter String to the ZRD file and then extract the text results of the Detector Viewer. You can apply the property.Filter to either the NSCRayTrace or the newDetector_settings property. Also, the file location of the ZRD file has to be relative since OpticStudio looks in the current directory the lens file is located in to both save and open the ray database. Note that the ZOS-API does not yet support image export, so if you need a 2D plot of the detector, you will need to recreate this in MATLAB.

zrd_file = 'temp4.ZRD'; % this needs to be a RELATIVE path

% Creat ray trace & modify settings
NSCRayTrace = TheSystem.Tools.OpenNSCRayTrace();
NSCRayTrace.SplitNSCRays = true;
NSCRayTrace.ScatterNSCRays = false;
NSCRayTrace.UsePolarization = true;
NSCRayTrace.IgnoreErrors = true;
NSCRayTrace.SaveRays = true;
NSCRayTrace.Filter = 'H2';
NSCRayTrace.SaveRaysFile = zrd_file; 

% Run ray trace

% initializes Detector Viewer, saves the ZRD file & applies a Filter
TheAnalyses = TheSystem.Analyses;
newDetector = TheAnalyses.New_Analysis(ZOSAPI.Analysis.AnalysisIDM.DetectorViewer);
newDetector_settings = newDetector.GetSettings();
newDetector_settings.RayDatabaseFilename = zrd;

% saves the Detector Viewer results
newDetector_results = newDetector.GetResults();

Read data from a ZRD file

This allows a user to open up any ZRD file and extract the same information that you will get from the Ray Database Viewer in Non-Sequential Mode. Note that MATLAB is not as fast as compiled code for reading large files like a ZRD so MATLAB will take longer to process a ZRD than OpticStudio (by 1-2 orders of magnitude). Implementing this solution in a compiled API code such as with C#/C++ will see performance improvements.

% Set up primary optical system
TheSystem = TheApplication.CreateNewSystem(ZOSAPI.SystemType.NonSequential);
TheAnalyses  = TheSystem.Analyses;

% loads and runs ZRD ray database
zrdFile = 'C:\Temp\nsc.ZRD';
zrd = TheSystem.Tools.OpenRayDatabaseReader();
zrd.ZRDFile = zrdFile;
zrd_results = zrd.GetResults();

% reads data from ZRD file

[success,ray_num,wave,wlum,segs] = zrd_results.ReadNextResult();

while success > 0

    fprintf('Ray %i, Wave_Number %i, Wavelength %d, Segs %i, success %d \n',...

        ray_num,wave,wlum,segs, success);


        exr,exi,eyr,eyi,ezr,ezi,intensity,pathLength] = zrd_results.ReadNextSegment();

    while success > 0

        fprintf('    Segment: %+e, x: %+e, y: %+e, z: %+e, l: %+e, m: %+e, n: %+e \n',...



            exr,exi,eyr,eyi,ezr,ezi,intensity,pathLength] = zrd_results.ReadNextSegment();


    [success,ray_num,wave,wlum,segs] = zrd_results.ReadNextResult();


Sequential batch ray trace

The batch ray trace allows the user to trace a grid of rays defined by [Hx, Hy, Px, Py] through a system to a given plane. The XYZ intercept, LMN direction cosines, surface normal vector, OPD, and intensity can be extracted from the raytrace. This data can be retrieved directly from the API without having to write data to disk. For multiple surfaces, the raytrace should be placed in a FOR loop.

% Set up Batch Ray Trace
raytrace = TheSystem.Tools.OpenBatchRayTrace();
nsur = TheSystem.LDE.NumberOfSurfaces - 1;
max_rays = 2; % number of rays to be traced minus 1 (will always trace hy=0 and hy=1)
normUnPolData = raytrace.CreateNormUnpol(max_rays + 1,ZOSAPI.Tools.RayTrace.RaysType.Real,nsur);

% Adding Rays to Batch, varying normalised object height hy
waveNumber=2; hx = 0; px = 0; py = 0;
hy_ary = [0:(1 / max_rays):1];
for i = 1:max_rays+1
    normUnPolData.AddRay(waveNumber, hx, hy_ary(:,i), px, py, ...

% Run Batch Ray Trace

% Read and display results


fprintf('All results use hx=%4.2f, px=%4.2f, py=%4.2f\n', hx, px, py);

for i= 1:max_rays+1

    [success, rayNumber, errCode, vigCode, x, y, z, l, m, n, l2, m2, n2,...

        opd, intensity] = normUnPolData.ReadNextResult();

    if success == 1

        fprintf('Ray Number %i, hy=%4.2f, Error Code %i, Vignette Code %i\n', ...

            rayNumber, hy_ary(:,i), errCode, vigCode);

        if errCode == 0

            fprintf('    x %5.2f, y %5.2f, z %5.2f, l %5.2f, m %5.2f, n %5.2f, ',...

                x, y, z, l, m, n);

            fprintf('l2 %5.2f, m2 %5.2f, n2 %5.2f, opd %5.2f, intensity %5.2f\n', ...

                l2, m2, n2, opd, intensity);



        fprintf('Ray trace for %i unsuccessful', i)




Was this article helpful?
1 out of 1 found this helpful



Please sign in to leave a comment.