Skip to main content
Solved

ZRD ray database processing in MATLAB, why does the output power changes magnitude?

  • February 15, 2023
  • 7 replies
  • 304 views

Priscilla

Hi all!

I am processing ZRD ray databases in Matlab using batch processing improved method. However, the intensity reading appears to be incorrect, as I expected to see the total intensity in microns based on the trends in the original files. Is there anything done to convert the values, or is there something I am missing at some point in the processing? Note that I used the sample Matlab file provided in the tutorial with some changes to support my own data.

Here is the output power calculated!

Best answer by MichaelH

Hi Priscilla,

I think the DLL is working fine and as-intended but you’re not applying the proper Filter String to only look at the intensity hitting your detector.  Each segment of a NSC ray has intensity and you’re summing all the individual segment’s intensity.  On line 58, you have a blank Filter with zrdReader.Filter = ''; and on line 111, you are getting all the intensity values for all the segments with intensityData = zrdData.Intensity.double;.  The zrdData.Intensity is the same array of data as looking at Intensity Column in the Ray Database Viewer (highlighted in yellow below for the Double Gauss 28 degree field.zmx converted to non-sequential mode):

You can see that for the on-axis chief ray, the total intensity for all the segments is 11.618W but the intensity for the last segment hitting Detector 20 (H20 filter string) is only 0.934W.  The same is true for the on-axis marginal ray with a total intensity for all the segments of 11.354W but the intensity for the last segment is only 0.887W.

If you either apply a filter for the HitObj array passing back from the ZRDLoaderFull.dll or using a Filter String when originally creating the ZRD file, then you should get the intensity you’re looking for.

View original
Did this topic help you find an answer to your question?

7 replies

David.Nguyen
Luminary
Forum|alt.badge.img+2
  • Luminary
  • 1085 replies
  • February 15, 2023

Hi Priscilla,

 

Can you post the link to the method you are refering to? Also, do you have a sample file with instructions to reproduce the issue? That would be really helpful for troubleshooting.

Take care,


David


Priscilla
  • Author
  • Infrared
  • 11 replies
  • February 16, 2023

Hi David,

 

Thank you for responding. Yes the files are referring are found here:

https://support.zemax.com/hc/en-us/articles/1500005576882-Batch-Processing-of-Ray-Trace-Data-using-ZOS-API-in-MATLAB-or-Python

 

And here is the sample zrd file I am processing using the code provided in the link above. I have uploaded the txt version since ZRD file is too big to be uploaded.

 


David.Nguyen
Luminary
Forum|alt.badge.img+2
  • Luminary
  • 1085 replies
  • February 20, 2023

Hi Priscilla,

 

It’ll be hard to troubleshoot like this, at least for me. I have no idea what your code is like, and your file seems quite complex. Are you refering to this particular example: MATLAB_ZRDLoaderFull.m or PythonNET_ZRDLoaderFull.py?

How can you judge the trend in the file? If you trace millions of ray, each with a power in uW, and they all add up on the detector, then you get Watts.

Any chance you can make a simple file that demonstrate the issue and also includes your code?

Take care,


David


Priscilla
  • Author
  • Infrared
  • 11 replies
  • February 21, 2023

Hi David,

 

Thank you for clarifying. I apologize for not attaching the codes to read the file, as I stated earlier I was unable to attach the zos file unless I copy and paste here. I agree that we can convert uW to Watts, but in my case, the transmitted power is 1W, and we should not expect to receive more than this while the computed power is about 7.6169, which made me doubt the process. Unfortunately, I was unable to debug my code.

 

Here are the MATLAB codes used:

function [ r ] = MATLABRayDatabaseExample_improved_4( args )

if ~exist('args', 'var')
    args = [];
end

% Initialize the OpticStudio connection
TheApplication = InitConnection();
if isempty(TheApplication)
    % failed to initialize a connection
    r = [];
else
    try
        r = BeginApplication(TheApplication, args);
        CleanupConnection(TheApplication);
    catch err
        CleanupConnection(TheApplication);
        rethrow(err);
    end
end
end

function [r] = BeginApplication(TheApplication, args)

import ZOSAPI.*;

TheSystem = TheApplication.PrimarySystem;

% Add your custom code here...


for k = 1:20
    fname = sprintf('Clear_weather_Simulation_zmx_%d',k);

samplesDir = TheApplication.SamplesDir;
fileDir = System.IO.Path.Combine(samplesDir, 'Non-sequential', 'Simulations');
lensFile = System.IO.Path.Combine(fileDir, [fname,'.zmx']);
zrdFile = System.IO.Path.Combine(fileDir, [fname,'.zrd']);

ReadZRDFile(TheSystem, lensFile, zrdFile);

r = [];

end
end


function [] = ReadZRDFile(sys, lensFile, zrdFile)

sys.LoadFile(lensFile, false);

if ~isempty(sys.Tools.CurrentTool)
    sys.Tools.CurrentTool.Close();
end

zrdReader = sys.Tools.OpenRayDatabaseReader();
zrdReader.ZRDFile = zrdFile;
zrdReader.Filter = '';

% start processing
zrdReader.RunAndWaitForCompletion();
res = zrdReader.GetResults();

if ~isempty(res)
    ProcessZRD1(res, 1000000);
end

zrdReader.Close();

end

function [] = ProcessZRD1(res, maxRays)
% Directly use the ZRD Reader API without the .NET helper DLL
import ZOSAPI.Tools.RayTrace.*;

% This method assumes the helper dll is in the .m file directory.
p = mfilename('fullpath');
[path] = fileparts(p);
p = strcat(path, '\', 'ZRDLoaderFull.dll');
NET.addAssembly(p);
import ZRDLoaderFull.*

tic();

% Attach the helper class to the ray database reader
dataReader = ReadZRDData(res);
% Configure the maximum number of segments to read at one time.
% Note that this is a tradeoff between speed and memory usage
maxSeg = 1000000;
zrdData = dataReader.InitializeOutput(maxSeg);

isFinished = false;
totalSegRead = 0;
totalRaysRead = 0;
pow = 0.0;
global powArray
powArray = [];
global PL
PL = [];
while ~isFinished
    % fill the next block of data
    readSegments = dataReader.ReadNextBlock(zrdData);
    if readSegments == 0
        isFinished = true;
    else
        totalSegRead = totalSegRead + readSegments;
        % Note - MATLAB arrays 1-base, however .NET arrays are 0-based, so we have to be careful...
        totalRaysRead = int32(zrdData.RayNumber(readSegments-1));

        % retrieve whatever data is needed
        intensityData = zrdData.Intensity.double;
        %xData = zrdData.X.double;

        pow = pow + sum(intensityData(1:readSegments));

        powArray = [powArray pow];

        pathLoss = 10*log10(pow);
        PL = [PL pathLoss];

    end

    if totalRaysRead >= maxRays
        isFinished = true;
    end
end
toc();

%disp(['Rays read: ', num2str(totalRaysRead)]);
%disp(['Segments read: ', num2str(totalSegRead)]);
disp('The power array formed is:');
disp(powArray);
disp(['Total power: ', num2str(pow)]);
disp('The power array in DB is:');
disp(PL);

end

function app = InitConnection()

import System.Reflection.*;

% Find the installed version of OpticStudio.
zemaxData = winqueryreg('HKEY_CURRENT_USER', 'Software\Zemax', 'ZemaxRoot');
NetHelper = strcat(zemaxData, '\ZOS-API\Libraries\ZOSAPI_NetHelper.dll');
% Note -- uncomment the following line to use a custom NetHelper path
% NetHelper = 'C:\Users\michael.humphreys\Documents\Zemax\ZOS-API\Libraries\ZOSAPI_NetHelper.dll';
% This is the path to OpticStudio
NET.addAssembly(NetHelper);

success = ZOSAPI_NetHelper.ZOSAPI_Initializer.Initialize();
% Note -- uncomment the following line to use a custom initialization path
% success = ZOSAPI_NetHelper.ZOSAPI_Initializer.Initialize('C:\Program Files\Zemax OpticStudio\');
if success == 1
    LogMessage(strcat('Found OpticStudio at: ', char(ZOSAPI_NetHelper.ZOSAPI_Initializer.GetZemaxDirectory())));
else
    app = [];
    return;
end

% Now load the ZOS-API assemblies
NET.addAssembly(AssemblyName('ZOSAPI_Interfaces'));
NET.addAssembly(AssemblyName('ZOSAPI'));

% Create the initial connection class
TheConnection = ZOSAPI.ZOSAPI_Connection();

% Attempt to create a Standalone connection

app = TheConnection.CreateNewApplication();
if isempty(app)
  HandleError('An unknown connection error occurred!');
end
if ~app.IsValidLicenseForAPI
    HandleError('License check failed!');
  app = [];
end

end

function LogMessage(msg)
disp(msg);
end

function HandleError(error)
ME = MXException(error);
throw(ME);
end

function  CleanupConnection(TheApplication)
% Note - this will close down the connection.

% If you want to keep the application open, you should skip this step
% and store the instance somewhere instead.
TheApplication.CloseApplication();
end

 

 

 

Thank you in advance for your time.

Priscilla.


David.Nguyen
Luminary
Forum|alt.badge.img+2
  • Luminary
  • 1085 replies
  • February 21, 2023

Hi Priscilla,

 

If you want to attach your file, please create an archive (File..Create Archive) and embed it into a *.zip before uploading it.

Before I spend some time looking at your code, what does the Analyze..Detector Viewer say about the total power? Also, are your detectors material set to ABSORB? If the detector material is not ABSORB, it could be that a ray goes through the detector (its energy is recorded) then gets reflected elsewhere and comes back to the detector and is detected a second (or more) times.

Take care,

 

David


Priscilla
  • Author
  • Infrared
  • 11 replies
  • February 21, 2023

Hi David,

Thank you for your response,

Yes my detector is set to ABSORB rays. And the detector viewer shows the total power 1.2817e-3 Watts as shown in figure below.

 


MichaelH
Ansys Staff
Forum|alt.badge.img+2
  • Ansys Staff
  • 342 replies
  • Answer
  • February 21, 2023

Hi Priscilla,

I think the DLL is working fine and as-intended but you’re not applying the proper Filter String to only look at the intensity hitting your detector.  Each segment of a NSC ray has intensity and you’re summing all the individual segment’s intensity.  On line 58, you have a blank Filter with zrdReader.Filter = ''; and on line 111, you are getting all the intensity values for all the segments with intensityData = zrdData.Intensity.double;.  The zrdData.Intensity is the same array of data as looking at Intensity Column in the Ray Database Viewer (highlighted in yellow below for the Double Gauss 28 degree field.zmx converted to non-sequential mode):

You can see that for the on-axis chief ray, the total intensity for all the segments is 11.618W but the intensity for the last segment hitting Detector 20 (H20 filter string) is only 0.934W.  The same is true for the on-axis marginal ray with a total intensity for all the segments of 11.354W but the intensity for the last segment is only 0.887W.

If you either apply a filter for the HitObj array passing back from the ZRDLoaderFull.dll or using a Filter String when originally creating the ZRD file, then you should get the intensity you’re looking for.


Reply


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings