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.
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!
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.
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.