    

 ## On this page

  

 

 # PythonStandalone\_08\_NSCEDetectorData

 Last update: 17.07.2025 

 1import clr, os, winreg

 2from itertools import islice

 3 

 4import math

 5 

 6class PythonStandaloneApplication(object):

 7 class LicenseException(Exception):

 8 pass

 9 class ConnectionException(Exception):

 10 pass

 11 class InitializationException(Exception):

 12 pass

 13 class SystemNotPresentException(Exception):

 14 pass

 15 

 16 def __init__(self, path=None):

 17 \# determine location of ZOSAPI\_NetHelper.dll &amp; add as reference

 18 aKey = winreg.OpenKey(winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER), r"Software\\Zemax", 0, winreg.KEY_READ)

 19 zemaxData = winreg.QueryValueEx(aKey, 'ZemaxRoot')

 20 NetHelper = os.path.join(os.sep, zemaxData[0], r'ZOS-API\\Libraries\\ZOSAPI\_NetHelper.dll')

 21 winreg.CloseKey(aKey)

 22 clr.AddReference(NetHelper)

 23 import ZOSAPI_NetHelper

 24 

 25 \# Find the installed version of OpticStudio

 26 if path is None:

 27 isInitialized = ZOSAPI_NetHelper.ZOSAPI_Initializer.Initialize()

 28 else:

 29 \# Note -- uncomment the following line to use a custom initialization path

 30 isInitialized = ZOSAPI_NetHelper.ZOSAPI_Initializer.Initialize(path)

 31 

 32 \# determine the ZOS root directory

 33 if isInitialized:

 34 dir = ZOSAPI_NetHelper.ZOSAPI_Initializer.GetZemaxDirectory()

 35 else:

 36 raise PythonStandaloneApplication.InitializationException("Unable to locate Zemax OpticStudio. Try using a hard-coded path.")

 37 

 38 \# add ZOS-API referencecs

 39 clr.AddReference(os.path.join(os.sep, dir, "ZOSAPI.dll"))

 40 clr.AddReference(os.path.join(os.sep, dir, "ZOSAPI\_Interfaces.dll"))

 41 import ZOSAPI

 42 

 43 \# create a reference to the API namespace

 44 self.ZOSAPI = ZOSAPI

 45 

 46 \# create a reference to the API namespace

 47 self.ZOSAPI = ZOSAPI

 48 

 49 \# Create the initial connection class

 50 self.TheConnection = [ZOSAPI.ZOSAPI\_Connection](class_z_o_s_a_p_i_1_1_z_o_s_a_p_i___connection.xhtml)()

 51 

 52 if self.TheConnection is None:

 53 raise PythonStandaloneApplication.ConnectionException("Unable to initialize .NET connection to ZOSAPI")

 54 

 55 self.TheApplication = self.TheConnection.CreateNewApplication()

 56 if self.TheApplication is None:

 57 raise PythonStandaloneApplication.InitializationException("Unable to acquire ZOSAPI application")

 58 

 59 if self.TheApplication.IsValidLicenseForAPI == False:

 60 raise PythonStandaloneApplication.LicenseException("License is not valid for ZOSAPI use")

 61 

 62 self.TheSystem = self.TheApplication.PrimarySystem

 63 if self.TheSystem is None:

 64 raise PythonStandaloneApplication.SystemNotPresentException("Unable to acquire Primary system")

 65 

 66 def __del__(self):

 67 if self.TheApplication is not None:

 68 self.TheApplication.CloseApplication()

 69 self.TheApplication = None

 70 

 71 self.TheConnection = None

 72 

 73 def OpenFile(self, filepath, saveIfNeeded):

 74 if self.TheSystem is None:

 75 raise PythonStandaloneApplication.SystemNotPresentException("Unable to acquire Primary system")

 76 self.TheSystem.LoadFile(filepath, saveIfNeeded)

 77 

 78 def CloseFile(self, save):

 79 if self.TheSystem is None:

 80 raise PythonStandaloneApplication.SystemNotPresentException("Unable to acquire Primary system")

 81 self.TheSystem.Close(save)

 82 

 83 def SamplesDir(self):

 84 if self.TheApplication is None:

 85 raise PythonStandaloneApplication.InitializationException("Unable to acquire ZOSAPI application")

 86 

 87 return self.TheApplication.SamplesDir

 88 

 89 def ExampleConstants(self):

 90 if self.TheApplication.LicenseStatus == self.ZOSAPI.LicenseStatusType.PremiumEdition:

 91 return "Premium"

 92 elif self.TheApplication.LicenseStatus == self.ZOSAPI.LicenseStatusTypeProfessionalEdition:

 93 return "Professional"

 94 elif self.TheApplication.LicenseStatus == self.ZOSAPI.LicenseStatusTypeStandardEdition:

 95 return "Standard"

 96 else:

 97 return "Invalid"

 98 

 99 def reshape(self, data, x, y, transpose = False):

 100 """Converts a System.Double\[,\] to a 2D list for plotting or post processing

 101 

 102 Parameters

 103 ----------

 104 data : System.Double\[,\] data directly from ZOS-API 

 105 x : x width of new 2D list [use var.GetLength(0) for dimension]

 106 y : y width of new 2D list [use var.GetLength(1) for dimension]

 107 transpose : transposes data; needed for some multi-dimensional line series data

 108 

 109 Returns

 110 -------

 111 res : 2D list; can be directly used with Matplotlib or converted to

 112 a numpy array using numpy.asarray(res)

 113 """

 114 if type(data) is not list:

 115 data = list(data)

 116 var_lst = [y] * x;

 117 it = iter(data)

 118 res = [list(islice(it, i)) for i in var_lst]

 119 if transpose:

 120 return self.transpose(res);

 121 return res

 122 

 123 def transpose(self, data):

 124 """Transposes a 2D list (Python3.x or greater). 

 125 

 126 Useful for converting mutli-dimensional line series (i.e. FFT PSF)

 127 

 128 Parameters

 129 ----------

 130 data : Python native list (if using System.Data[,] object reshape first) 

 131 

 132 Returns

 133 -------

 134 res : transposed 2D list

 135 """

 136 if type(data) is not list:

 137 data = list(data)

 138 return list(map(list, zip(*data)))

 139 

 140 

 141if __name__ == '\_\_main\_\_':

 142 zos = PythonStandaloneApplication()

 143 

 144 \# - load \\Samples\\Non-Sequential\\Scattering\\Abg scattering surface.zos

 145 \# 1. delete object 3 (specular ray blocking)

 146 \# 2. insert detector polar position at same pos as object 2

 147 \# - retrieve object 2 rotation matrix, match orientation

 148 \# - size = 20

 149 \# remove absorb material from obj 4

 150 \# -. run ray trace

 151 \# 3/4. Save/Load detector data

 152 \# 5/6. get detector data for detector polar

 153 \# - retrieve single-value data with GetDetectorPolarData()

 154 \# - retrieve data grid (all pixels) with GetAllDetectorPolarDataSafe()

 155 \# 7/8. get detector rectangle data

 156 \# - retrieve single-value data with GetDetectorData()

 157 \# - retrieve data grid (all pixels) with GetAllDetectorDataSafe()

 158 \# 9/10. get coherent detector rectangle data

 159 \# - retrieve single-value data with GetCoherentData()

 160 \# - retrieve data grid (all pixels) with GetAllCoherentDataSafe()

 161 

 162 \# load local variables

 163 ZOSAPI = zos.ZOSAPI

 164 TheApplication = zos.TheApplication

 165 TheSystem = zos.TheSystem

 166 

 167 file = "\\\\Samples\\\\Non-sequential\\\\Scattering\\\\ABg scattering surface.zos"

 168 DataDir = TheApplication.ZemaxDataDir

 169 filepath = DataDir + file

 170 TheSystem.LoadFile(filepath, False)

 171 

 172 \# ! \[e08s01\_py\]

 173 \# Delete unnecessary object from NSCE

 174 TheSystem.NCE.RemoveObjectAt(3)

 175 \# Add detector co-located with another general object

 176 obj3 = TheSystem.NCE.InsertNewObjectAt(3)

 177 DetectorPolar = obj3.GetObjectTypeSettings(ZOSAPI.Editors.NCE.ObjectType.DetectorPolar)

 178 obj3.ChangeType(DetectorPolar)

 179 \# Set the detector polar radial size to 20

 180 obj3.GetCellAt(12).DoubleValue = 20 \# cell 12 corresponds to par 2 in NCE

 181 \# ! \[e08s01\_py\]

 182 

 183 \# ! \[e08s02\_py\]

 184 \# Co-locate object 3 with object 2 (here, could alternatively use Ref Object flag)

 185 \# need to use placeholders for out parameters

 186 success, R11, R12, R13, R21, R22, R23, R31, R32, R33, Xo, Yo, Zo = TheSystem.NCE.GetMatrix(2, 11, 12, 13, 21, 22, 23, 31, 32, 33, 1, 2, 3)

 187 obj3.XPosition = Xo

 188 obj3.YPosition = Yo

 189 obj3.ZPosition = Zo

 190 \# Conversion from rotation matrix to tilts described in KBA "Rotation Matrix and Tilt About X/Y/Z in OpticStudio"

 191 obj3.TiltAboutX = math.degrees(math.atan2(-1 * R23, R33))

 192 obj3.TiltAboutY = math.degrees(math.asin(R13))

 193 obj3.TiltAboutZ = math.degrees(math.atan2(-1 * R12, R11))

 194 \# ! \[e08s02\_py\]

 195 

 196 \# Remove ABSORB material from object 4

 197 TheSystem.NCE.GetObjectAt(4).Material = ''

 198 \# Run the ray trace

 199 RayTrace = TheSystem.Tools.OpenNSCRayTrace()

 200 RayTrace.ClearDetectors(0) \# clear the old detector data!

 201 RayTrace.ScatterNSCRays = True

 202 RayTrace.UsePolarization = False

 203 RayTrace.SplitNSCRays = False

 204 RayTrace.IgnoreErrors = True

 205 RayTrace.RunAndWaitForCompletion()

 206 RayTrace.Close()

 207 

 208 \# The next two steps are technically unnecessary in this case; since we just ran the

 209 \# ray trace, the results are already there. But, we demonstrate usage here anyways

 210 \# ! \[e08s03\_py\]

 211 \# Save detector data -- allows ray trace results to be loaded later

 212 \# For detector polar, the file type is .DDP; for detector rectangle, it's .DDR

 213 DetectorPolarFile = TheApplication.ZemaxDataDir + "\\\\Samples\\\\API\\\\Python\\\\detector3polar.DDP"

 214 DetectorRectFile = TheApplication.ZemaxDataDir + "\\\\Samples\\\\API\\\\Python\\\\detector4rect.DDR"

 215 TheSystem.NCE.SaveDetector(3, DetectorPolarFile)

 216 TheSystem.NCE.SaveDetector(4, DetectorRectFile)

 217 \# ! \[e08s03\_py\]

 218 

 219 \# ! \[e08s04\_py\]

 220 \# Load detector data -- for analyzing previous ray trace results

 221 \# For detector polar, the file type is .DDP; for detector rectangle, it's .DDR

 222 DetectorPolarFile = TheApplication.ZemaxDataDir + "\\\\Samples\\\\API\\\\Python\\\\detector3polar.DDP"

 223 DetectorRectFile = TheApplication.ZemaxDataDir + "\\\\Samples\\\\API\\\\Python\\\\detector4rect.DDR"

 224 TheSystem.NCE.LoadDetector(3, DetectorPolarFile, False)

 225 TheSystem.NCE.LoadDetector(4, DetectorRectFile, False)

 226 \# ! \[e08s04\_py\]

 227 

 228 \# ! \[e08s05\_py\]

 229 \# Here we read in the detector polar data from ZOS

 230 \# GetPolarDetectorData() is very similar to the MF operand NSDP;

 231 \# can retrieve RMS (degrees), total power, chromaticity, etc. (see NSDP in OpticStudio Help)

 232 \# Note: GetPolarDetectorData() uses an enumeration for data type, shown here

 233 DataFlag_Power = ZOSAPI.Editors.NCE.PolarDetectorDataType.Power

 234 DataFlag_ChromX = ZOSAPI.Editors.NCE.PolarDetectorDataType.Cx

 235 DataFlag_ChromY = ZOSAPI.Editors.NCE.PolarDetectorDataType.Cy

 236 \# need to use placeholders for out parameters

 237 success, DetPolarData_RadialRMS = TheSystem.NCE.GetPolarDetectorData(3, -4, DataFlag_Power, 0) \# obj=3, pix=-4, data=power enum

 238 success, DetPolarData_ChromX = TheSystem.NCE.GetPolarDetectorData(3, 0, DataFlag_ChromX, 0) \# obj=3, pix=0, data=chromaticityX enum

 239 success, DetPolarData_ChromY = TheSystem.NCE.GetPolarDetectorData(3, 0, DataFlag_ChromY, 0) \# obj=3, pix=0, data=chromaticityY enum

 240 \# ! \[e08s05\_py\]

 241 

 242 \# ! \[e08s06\_py\]

 243 \# To retrieve the entire data array (power, tristim. X/Y/Z, etc. for each pixel)

 244 \# can use GetAllPolarDetectorDataSafe(), or GetAllPolarDetectorData()

 245 \# Note: GetPolarDetectorData uses an enumeration for data type, shown here

 246 DataFlag_TriX = ZOSAPI.Editors.NCE.PolarDetectorDataType.TriX

 247 DataFlag_TriY = ZOSAPI.Editors.NCE.PolarDetectorDataType.TriY

 248 DataFlag_TriZ = ZOSAPI.Editors.NCE.PolarDetectorDataType.TriZ

 249 DetPolarData_TriX = TheSystem.NCE.GetAllPolarDetectorDataSafe(3, DataFlag_TriX) \# Tristimulus X value polar pixel

 250 DetPolarData_TriY = TheSystem.NCE.GetAllPolarDetectorDataSafe(3, DataFlag_TriY) \# Tristimulus Y value on each pixel

 251 DetPolarData_TriZ = TheSystem.NCE.GetAllPolarDetectorDataSafe(3, DataFlag_TriZ) \# Tristimulus Z value on each pixel

 252 \# ! \[e08s06\_py\]

 253 

 254 \# ! \[e08s07\_py\]

 255 \# Here we read in the detector rectangle data

 256 \# GetDetectorData() is very similar to the Merit Function operand NSDD

 257 \# can retrieve Std Deviation, # of rays, total power, etc.; data calculated over whole detector or individual pixel

 258 \# need to use placeholders for out parameters

 259 success, DetRectangleData_StdDev = TheSystem.NCE.GetDetectorData(4, -4, 0, 0) \# obj=4, pix=-4, data=0

 260 \# ! \[e08s07\_py\]

 261 

 262 \# ! \[e08s08\_py\]

 263 \# To retrieve the entire data array (flux, flux/area, etc.) for all pixel data,

 264 \# can use GetAllDetectorDataSafe(), or GetAllDetectorData().

 265 \# The 'Data' inputs for these functions (parameter 2) can be found in the API syntax help,

 266 \# under the listing for GetDetectorData().

 267 DetRectangleData_Flux = TheSystem.NCE.GetAllDetectorDataSafe(4, 0) \# total flux on each pixel

 268 DetRectangleData_FluxArea = TheSystem.NCE.GetAllDetectorDataSafe(4, 1) \# flux/area on each pixel

 269 DetRectangleData_FluxSAP = TheSystem.NCE.GetAllDetectorDataSafe(4, 2) \# flux/solid angle pixel on each pixel

 270 \# ! \[e08s08\_py\]

 271 

 272 \# Finally, let's read coherent data

 273 \# The coherent data isn't very meaningful in this example, but it serves to demonstrate API usage and functionality

 274 \# ! \[e08s09\_py\]

 275 \# Read in the detector rectangle coherent data

 276 \# GetCoherentData() is very similar to the operand NSDC

 277 \# can retrieve real, imaginary, amplitude, power with 'data' input

 278 \# for pix=0, get sum on detector; pix&gt;0 gives single pixel data

 279 success, DetRectangle_CoherentAmp = TheSystem.NCE.GetCoherentData(4, 0, ZOSAPI.Editors.NCE.DetectorDataType.Amplitude, 0) \# obj=4, pix=0, data=2

 280 success, DetRectangle_CoherentPower = TheSystem.NCE.GetCoherentData(4, 0, ZOSAPI.Editors.NCE.DetectorDataType.Power, 0) \# obj=4, pix=0, data=3

 281 \# ! \[e08s09\_py\]

 282 

 283 fileName = DataDir + r"\\Samples\\API\\Python\\Python8\_NSCEDetectorData.zos"

 284 TheSystem.SaveAs(fileName)

 285 print('Saved file: %s' % fileName)

 286 \# from here, we can plot or analyze any detector we want!

 287 

 288 \# This will clean up the connection to OpticStudio.

 289 \# Note that it closes down the server instance of OpticStudio, so you for maximum performance do not do

 290 \# this until you need to.

 291 del zos

 292 zos = None

[ZOSAPI.ZOSAPI\_Connection](class_z_o_s_a_p_i_1_1_z_o_s_a_p_i___connection.xhtml)

**Definition:** ZemaxService.cs:198