Skip to main content
Solved

ZOS-API: NumSegs=0 from IRayTraceNSCData.ReadNextResult for All Manually Added Rays


Hi all,

I'm using the ZOS-API in Python (OpticStudio 2024 R1) with IBatchRayTrace to trace manually defined NSC rays. I'm creating the interface using teh batch tool and adding rays using nscData.AddRay(...).

The trace completes successfully (batchTool.Succeeded is True, and RunAndWaitForCompletion() doesn't crash ). However, when I read the results using nscData.ReadNextResult(), the numSegments output parameter is consistently 0 for all rays. This happens even when:

  1. The system is minimal (new file, 1 wavelength, 1 Standard Lens, 1 Detector Rectangle).
  2. Rays are defined with various trace options (None, UsePolarization, UseSplitting, UseScattering, and combinations).
  3. The ray path clearly interacts with objects (e.g., passes through the lens and hits the detector).

It also doesnt show any errors...

Is it expected that IRayTraceNSCData.ReadNextResult will return numSegments = 0 for simple interactions like refraction or absorption when rays are launched via AddRay? If so, what is the intended way to get detailed segment-by-segment path data (hit object, coordinates, path length per segment) for such manually defined rays using IBatchRayTrace? Or is this interface primarily for other types of results, and should I use ZRD files for detailed segment history?

Thanks!

Best answer by MichaelH

Hey Max,

I just tested the IBatchRayTrace in non-sequential and everything looks to be working as expected.  I’m using a simple Source Ray, Standard Lens, and Detector Rectangle.  The code to create the system is below:


# load local variables
ZOSAPI = zos.ZOSAPI
TheApplication = zos.TheApplication
TheSystem = zos.TheSystem

# ensure the system is non-sequential...some analysis and tools won't work if in sequential
zos.TheSystem.New(False)
zos.TheSystem.MakeNonSequential()

# create a simple system of 1 ray, 1 lens and 1 detector
o1 = TheSystem.NCE.GetObjectAt(1)
o1.ChangeType(o1.GetObjectTypeSettings(ZOSAPI.Editors.NCE.ObjectType.SourceRay))
o1.YPosition = 0.9
o1.ZPosition = -1
o1.ObjectData.__implementation__.NumberOfLayoutRays = 1
o1.ObjectData.__implementation__.NumberOfAnalysisRays = 1
o1.ObjectData.__implementation__.ZCosine = 1

o2 = TheSystem.NCE.InsertNewObjectAt(2)
o2.ChangeType(o2.GetObjectTypeSettings(ZOSAPI.Editors.NCE.ObjectType.StandardLens))
o2.Material = 'N-BK7'
o2.ObjectData.__implementation__.Radius1 = 12.5

o3 = TheSystem.NCE.InsertNewObjectAt(3)
o3.ChangeType(o3.GetObjectTypeSettings(ZOSAPI.Editors.NCE.ObjectType.DetectorRectangle))
o3.ZPosition = 24.6
o3.ObjectData.__implementation__.NumberOfXPixels = 100
o3.ObjectData.__implementation__.NumberOfYPixels = 100

Then, to perform the ray trace, I wanted to add the same values as the Source Ray above, namely (x, y, z) = (0, 0.9, -1.0) and (l, m, n) = (0, 0, 1):

from System import Enum
tool = TheSystem.Tools.OpenBatchRayTrace()

# setup raytrace
nsc_raytrace = tool.CreateNSC(1, 10, 0)

# if using anything other than `None` or `UseScattering`, you need to ensure your e-fields are normalized to 1.0
nsc_raytrace.AddRay(1, 1, Enum.Parse(zos.ZOSAPI.Tools.RayTrace.NSCTraceOptions, 'None'), 0, 0.9, -1, 0, 0, 1, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)

# run raytrace
tool.RunAndWaitForCompletion()

# read results
nsc_raytrace.StartReadingResults()
sr, rn, _, _, ns = nsc_raytrace.ReadNextResult(1, 1, 1, 1)
while sr:
    ss, seglevel, segpar, hit, _, x, y, z, l, m, n, _, _, _, _, _, _, intensity, opl = nsc_raytrace.ReadNextSegment(1, 1, 1, 1, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0)

    while ss:
        ss, seglevel, segpar, hit, _, x, y, z, l, m, n, _, _, _, _, _, _, intensity, opl = nsc_raytrace.ReadNextSegment(1, 1, 1, 1, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0)
        print(f'(x, y, z) : ({x:8.5f}, {y:8.5f}, {z:8.5f})')
    sr, rn, _, _, ns = nsc_raytrace.ReadNextResult(1, 1, 1, 1)

tool.Close()

The output is shown below and this matches the new Single Ray Trace feature with the same initial inputs:

(x, y, z) : ( 0.00000,  0.90000,  0.03244)
(x, y, z) : ( 0.00000,  0.87616,  1.00000)
(x, y, z) : ( 0.00000, -0.00703, 24.60000)
(x, y, z) : ( 0.00000, -0.10277, 27.15821)
(x, y, z) : ( 0.00000,  0.00000,  0.00000)

The one thing I’ll note is if you’re using NSCTraceOptions that uses any Polarization (only None and UseScattering don’t use Polarization) and your e-field is not normalized to 1.0, then you’ll get incorrect data.

If this still isn’t working for you, please post your code so the community can help out.

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

5 replies

MichaelH
Ansys Staff
Forum|alt.badge.img+2
  • Ansys Staff
  • 366 replies
  • Answer
  • May 13, 2025

Hey Max,

I just tested the IBatchRayTrace in non-sequential and everything looks to be working as expected.  I’m using a simple Source Ray, Standard Lens, and Detector Rectangle.  The code to create the system is below:


# load local variables
ZOSAPI = zos.ZOSAPI
TheApplication = zos.TheApplication
TheSystem = zos.TheSystem

# ensure the system is non-sequential...some analysis and tools won't work if in sequential
zos.TheSystem.New(False)
zos.TheSystem.MakeNonSequential()

# create a simple system of 1 ray, 1 lens and 1 detector
o1 = TheSystem.NCE.GetObjectAt(1)
o1.ChangeType(o1.GetObjectTypeSettings(ZOSAPI.Editors.NCE.ObjectType.SourceRay))
o1.YPosition = 0.9
o1.ZPosition = -1
o1.ObjectData.__implementation__.NumberOfLayoutRays = 1
o1.ObjectData.__implementation__.NumberOfAnalysisRays = 1
o1.ObjectData.__implementation__.ZCosine = 1

o2 = TheSystem.NCE.InsertNewObjectAt(2)
o2.ChangeType(o2.GetObjectTypeSettings(ZOSAPI.Editors.NCE.ObjectType.StandardLens))
o2.Material = 'N-BK7'
o2.ObjectData.__implementation__.Radius1 = 12.5

o3 = TheSystem.NCE.InsertNewObjectAt(3)
o3.ChangeType(o3.GetObjectTypeSettings(ZOSAPI.Editors.NCE.ObjectType.DetectorRectangle))
o3.ZPosition = 24.6
o3.ObjectData.__implementation__.NumberOfXPixels = 100
o3.ObjectData.__implementation__.NumberOfYPixels = 100

Then, to perform the ray trace, I wanted to add the same values as the Source Ray above, namely (x, y, z) = (0, 0.9, -1.0) and (l, m, n) = (0, 0, 1):

from System import Enum
tool = TheSystem.Tools.OpenBatchRayTrace()

# setup raytrace
nsc_raytrace = tool.CreateNSC(1, 10, 0)

# if using anything other than `None` or `UseScattering`, you need to ensure your e-fields are normalized to 1.0
nsc_raytrace.AddRay(1, 1, Enum.Parse(zos.ZOSAPI.Tools.RayTrace.NSCTraceOptions, 'None'), 0, 0.9, -1, 0, 0, 1, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)

# run raytrace
tool.RunAndWaitForCompletion()

# read results
nsc_raytrace.StartReadingResults()
sr, rn, _, _, ns = nsc_raytrace.ReadNextResult(1, 1, 1, 1)
while sr:
    ss, seglevel, segpar, hit, _, x, y, z, l, m, n, _, _, _, _, _, _, intensity, opl = nsc_raytrace.ReadNextSegment(1, 1, 1, 1, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0)

    while ss:
        ss, seglevel, segpar, hit, _, x, y, z, l, m, n, _, _, _, _, _, _, intensity, opl = nsc_raytrace.ReadNextSegment(1, 1, 1, 1, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0)
        print(f'(x, y, z) : ({x:8.5f}, {y:8.5f}, {z:8.5f})')
    sr, rn, _, _, ns = nsc_raytrace.ReadNextResult(1, 1, 1, 1)

tool.Close()

The output is shown below and this matches the new Single Ray Trace feature with the same initial inputs:

(x, y, z) : ( 0.00000,  0.90000,  0.03244)
(x, y, z) : ( 0.00000,  0.87616,  1.00000)
(x, y, z) : ( 0.00000, -0.00703, 24.60000)
(x, y, z) : ( 0.00000, -0.10277, 27.15821)
(x, y, z) : ( 0.00000,  0.00000,  0.00000)

The one thing I’ll note is if you’re using NSCTraceOptions that uses any Polarization (only None and UseScattering don’t use Polarization) and your e-field is not normalized to 1.0, then you’ll get incorrect data.

If this still isn’t working for you, please post your code so the community can help out.


  • Author
  • Monochrome
  • 4 replies
  • May 14, 2025

Dear Michael,

thanks for the support, that actually fixed my problem. Apparently, I had to set the surf value to 1, which you did. Mine was always at 0 and that seems to have caused the issue. The segments now correctly show up like you demonstrated.

I’m currently having trouble analyzing detector outputs when running a batch ray trace. the detector always shows up empty and in the documentation I can’t find any example on how to do this. I tried using .zrd files but couldnt find and SaveRays function for the BatchRayTrace. Is there more information on how to do this available that you can pin point me to? Thanks!


MichaelH
Ansys Staff
Forum|alt.badge.img+2
  • Ansys Staff
  • 366 replies
  • May 14, 2025

When in non-sequential mode, the surface number always has to be 1; OpticStudio has mixed-mode where you can insert a Non-Sequential Component as a surface (cannot be S0) so there are mixed-mode cases where the surface number might be higher than 1.  Therefore, for pure non-sequential operations, you always need to use Surface=1.

 

When you use the IBatchRayTrace, you will only have access to the direct results of the ReadNextResult/ReadNextSegment of the interface; there is no saved information about any detectors.  If you want to see the irradiance on a detector, you should use the TheSystem.Tools.OpenNSCRayTrace() interface which will perform the stand ray trace and then you can access the TheSystem.Analyses.New_AnalysesSettingsFirst(ZOSAPI.Analysis.AnalysisIDM.DetectorViewer) to access the irradiance on the detector.  

 

If you need to individually define your rays and analyze them on a detector, I would suggest writing your rays to a Source File and running a standard ray trace.  


  • Author
  • Monochrome
  • 4 replies
  • May 15, 2025

Okay, looks like  IBatchRayTrace might be the wrong choice. I wanted to pick this because I want to simulate a large number of rays as quickly as possible. Just for my understanding, The ReadNextResult/ReadNextSegment only output the intersections with surfaces but I don’t get Detector Views and I also don’t trace the power of the rays (i.e. losses due to absorption). Also, when I activate scattering in the IBatchRayTrace, will this create new rays that are traced or how is this handled? Can I read power for these rays?


MichaelH
Ansys Staff
Forum|alt.badge.img+2
  • Ansys Staff
  • 366 replies
  • May 18, 2025

Hi Max,

For your first question, yes, you’re correct that the ReadNextResult/ReadNextSegment from the IRayTraceNSCData interface will give you the intersections at surfaces and they won’t give you Detector Viewer results.  You would have to re-implement the entire logic of binning the pixels on a detector viewer based on the XY intercept of the Detector Rectangle and sum up the binned rays’ intensities.  There is no way right now to do in-memory (as opposed to saving rays to disk as a ZRD) to easily reproduce the data from the Detector Viewer using the IBatchRayTrace interface.

When you activate scattering, this will create new rays at any scattering face and these rays will be propagated until termination (missed object, ray-geometry error, minimum threshold or hitting ABSORB face).  There is nothing else you need to do to handle scattering rays.

The easiest way to simulate a large number of rays and analyzing the Detector Viewer output will be to write the rays to a Source File, perform a normal ray trace via OpenNSCRayTrace(), and then use the AnalysisIDM.DetectorViewer directly.  This does involve writing each ray’s initial coordinates to a file on disk, but Python can handle this pretty efficiently.  Then, everything else will be handled in-memory by the ZOS-API and you can analyze your results.  


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