PythonStandalone_25_source_spectrum_diffraction_grating
Last update: 17.07.2025 1import clr, os, winreg
2from itertools import islice
3
4import time
5import matplotlib.pyplot as plt
6import numpy as np
7
8class PythonStandaloneApplication(object):
9 class LicenseException(Exception):
10 pass
11 class ConnectionException(Exception):
12 pass
13 class InitializationException(Exception):
14 pass
15 class SystemNotPresentException(Exception):
16 pass
17
18 def __init__(self, path=None):
19 # determine location of ZOSAPI_NetHelper.dll & add as reference
20 aKey = winreg.OpenKey(winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER), r"Software\Zemax", 0, winreg.KEY_READ)
21 zemaxData = winreg.QueryValueEx(aKey, 'ZemaxRoot')
22 NetHelper = os.path.join(os.sep, zemaxData[0], r'ZOS-API\Libraries\ZOSAPI_NetHelper.dll')
23 winreg.CloseKey(aKey)
24 clr.AddReference(NetHelper)
25 import ZOSAPI_NetHelper
26
27 # Find the installed version of OpticStudio
28 if path is None:
29 isInitialized = ZOSAPI_NetHelper.ZOSAPI_Initializer.Initialize()
30 else:
31 # Note -- uncomment the following line to use a custom initialization path
32 isInitialized = ZOSAPI_NetHelper.ZOSAPI_Initializer.Initialize(path)
33
34 # determine the ZOS root directory
35 if isInitialized:
36 dir = ZOSAPI_NetHelper.ZOSAPI_Initializer.GetZemaxDirectory()
37 else:
38 raise PythonStandaloneApplication.InitializationException("Unable to locate Zemax OpticStudio. Try using a hard-coded path.")
39
40 # add ZOS-API referencecs
41 clr.AddReference(os.path.join(os.sep, dir, "ZOSAPI.dll"))
42 clr.AddReference(os.path.join(os.sep, dir, "ZOSAPI_Interfaces.dll"))
43 import ZOSAPI
44
45 # create a reference to the API namespace
46 self.ZOSAPI = ZOSAPI
47
48 # create a reference to the API namespace
49 self.ZOSAPI = ZOSAPI
50
51 # Create the initial connection class
52 self.TheConnection = ZOSAPI.ZOSAPI_Connection()
53
54 if self.TheConnection is None:
55 raise PythonStandaloneApplication.ConnectionException("Unable to initialize .NET connection to ZOSAPI")
56
57 self.TheApplication = self.TheConnection.CreateNewApplication()
58 if self.TheApplication is None:
59 raise PythonStandaloneApplication.InitializationException("Unable to acquire ZOSAPI application")
60
61 if self.TheApplication.IsValidLicenseForAPI == False:
62 raise PythonStandaloneApplication.LicenseException("License is not valid for ZOSAPI use")
63
64 self.TheSystem = self.TheApplication.PrimarySystem
65 if self.TheSystem is None:
66 raise PythonStandaloneApplication.SystemNotPresentException("Unable to acquire Primary system")
67
68 def __del__(self):
69 if self.TheApplication is not None:
70 self.TheApplication.CloseApplication()
71 self.TheApplication = None
72
73 self.TheConnection = None
74
75 def OpenFile(self, filepath, saveIfNeeded):
76 if self.TheSystem is None:
77 raise PythonStandaloneApplication.SystemNotPresentException("Unable to acquire Primary system")
78 self.TheSystem.LoadFile(filepath, saveIfNeeded)
79
80 def CloseFile(self, save):
81 if self.TheSystem is None:
82 raise PythonStandaloneApplication.SystemNotPresentException("Unable to acquire Primary system")
83 self.TheSystem.Close(save)
84
85 def SamplesDir(self):
86 if self.TheApplication is None:
87 raise PythonStandaloneApplication.InitializationException("Unable to acquire ZOSAPI application")
88
89 return self.TheApplication.SamplesDir
90
91 def ExampleConstants(self):
92 if self.TheApplication.LicenseStatus == self.ZOSAPI.LicenseStatusType.PremiumEdition:
93 return "Premium"
94 elif self.TheApplication.LicenseStatus == self.ZOSAPI.LicenseStatusTypeProfessionalEdition:
95 return "Professional"
96 elif self.TheApplication.LicenseStatus == self.ZOSAPI.LicenseStatusTypeStandardEdition:
97 return "Standard"
98 else:
99 return "Invalid"
100
101 def reshape(self, data, x, y, transpose = False):
102 """Converts a System.Double[,] to a 2D list for plotting or post processing
103
104 Parameters
105 ----------
106 data : System.Double[,] data directly from ZOS-API
107 x : x width of new 2D list [use var.GetLength(0) for dimension]
108 y : y width of new 2D list [use var.GetLength(1) for dimension]
109 transpose : transposes data; needed for some multi-dimensional line series data
110
111 Returns
112 -------
113 res : 2D list; can be directly used with Matplotlib or converted to
114 a numpy array using numpy.asarray(res)
115 """
116 if type(data) is not list:
117 data = list(data)
118 var_lst = [y] * x;
119 it = iter(data)
120 res = [list(islice(it, i)) for i in var_lst]
121 if transpose:
122 return self.transpose(res);
123 return res
124
125 def transpose(self, data):
126 """Transposes a 2D list (Python3.x or greater).
127
128 Useful for converting mutli-dimensional line series (i.e. FFT PSF)
129
130 Parameters
131 ----------
132 data : Python native list (if using System.Data[,] object reshape first)
133
134 Returns
135 -------
136 res : transposed 2D list
137 """
138 if type(data) is not list:
139 data = list(data)
140 return list(map(list, zip(*data)))
141
142if __name__ == '__main__':
143 zos = PythonStandaloneApplication()
144
145 # load local variables
146 ZOSAPI = zos.ZOSAPI
147 TheApplication = zos.TheApplication
148 TheSystem = zos.TheSystem
149 if not os.path.exists(TheApplication.SamplesDir + "\\API\\Python"):
150 os.makedirs(TheApplication.SamplesDir + "\\API\\Python")
151
152 # makes system non-seqnuential and adds 2 objects (3 in total)
153 TheSystem = TheApplication.CreateNewSystem(ZOSAPI.SystemType.NonSequential)
154
155 #! [e25s01_py]
156 # Initializes NCE and loads surfaces
157 # Inserts objects
158 TheNCE = TheSystem.NCE
159 TheNCE.InsertNewObjectAt(1)
160 TheNCE.InsertNewObjectAt(1)
161 TheNCE.InsertNewObjectAt(1)
162 TheNCE.InsertNewObjectAt(1)
163 #! [e25s01_py]
164
165 o1 = TheNCE.GetObjectAt(1)
166 o2 = TheNCE.GetObjectAt(2)
167 o3 = TheNCE.GetObjectAt(3)
168 o4 = TheNCE.GetObjectAt(4)
169 o5 = TheNCE.GetObjectAt(5)
170
171 #! [e25s02_py]
172 # Changes Object Type
173 o1.ChangeType(o1.GetObjectTypeSettings(ZOSAPI.Editors.NCE.ObjectType.SourceDiode))
174 o2.ChangeType(o2.GetObjectTypeSettings(ZOSAPI.Editors.NCE.ObjectType.SourceDiode))
175 o3.ChangeType(o3.GetObjectTypeSettings(ZOSAPI.Editors.NCE.ObjectType.NullObject))
176 o4.ChangeType(o4.GetObjectTypeSettings(ZOSAPI.Editors.NCE.ObjectType.DiffractionGrating))
177 o5.ChangeType(o5.GetObjectTypeSettings(ZOSAPI.Editors.NCE.ObjectType.DetectorColor))
178 #! [e25s02_py]
179
180 # Sets positions & materials
181 o3.ZPosition = 10
182 o3.TiltAboutX = 10
183 o4.RefObject = 3
184 o4.Material = 'MIRROR'
185 o5.YPosition = 8.45
186 o5.TiltAboutX = 40
187
188 # Sets parameters
189 o1.ObjectData.XMinusDivergence = 5
190 o2.ObjectData.XMinusDivergence = 5
191 o4.ObjectData.LinesPerMicron = 0.6
192 o4.ObjectData.DiffOrder = 1
193
194 #! [e25s03_py]
195 # Changes sourcecolor to Blackbody, sets temperature, min/max wavelength
196 o1.SourcesData.SourceColor = ZOSAPI.Editors.NCE.SourceColorMode.BlackBodySpectrum
197 o1.SourcesData.SourceColorSettings._S_BlackBodySpectrum.TemperatureK = 6000
198 o1.SourcesData.SourceColorSettings._S_BlackBodySpectrum.WavelengthFrom = 0.45
199 o1.SourcesData.SourceColorSettings._S_BlackBodySpectrum.WavelengthTo = 0.65
200 #! [e25s03_py]
201
202 o2.SourcesData.SourceColor = ZOSAPI.Editors.NCE.SourceColorMode.BlackBodySpectrum
203 o2.SourcesData.SourceColorSettings._S_BlackBodySpectrum.TemperatureK = 6000
204 o2.SourcesData.SourceColorSettings._S_BlackBodySpectrum.SpectrumCount = 100
205 o2.SourcesData.SourceColorSettings._S_BlackBodySpectrum.WavelengthFrom = 0.4
206 o2.SourcesData.SourceColorSettings._S_BlackBodySpectrum.WavelengthTo = 0.7
207
208 #! [e25s04_py]
209 # Sets up the MCE, adds configuration & operands
210 TheMCE = TheSystem.MCE
211 TheMCE.AddConfiguration(False)
212 TheMCE.AddOperand()
213 TheMCE.AddOperand()
214 TheMCE.AddOperand()
215 #! [e25s04_py]
216
217 #! [e25s05_py]
218 # change MCE to NPAR, modifies the number of Layout Rays for a Source
219 for a in range(1, 5):
220 TheMCE.GetOperandAt(a).ChangeType(ZOSAPI.Editors.MCE.MultiConfigOperandType.NPAR)
221 TheMCE.GetOperandAt(1).Param2 = 1
222 TheMCE.GetOperandAt(1).Param3 = 1
223 TheMCE.GetOperandAt(1).GetOperandCell(1).DoubleValue = 200
224 TheMCE.GetOperandAt(1).GetOperandCell(2).DoubleValue = 0
225 #! [e25s05_py]
226
227 TheMCE.GetOperandAt(2).Param2 = 1
228 TheMCE.GetOperandAt(2).Param3 = 2
229 TheMCE.GetOperandAt(2).GetOperandCell(1).DoubleValue = 1000000
230 TheMCE.GetOperandAt(2).GetOperandCell(2).DoubleValue = 0
231
232 TheMCE.GetOperandAt(3).Param2 = 2
233 TheMCE.GetOperandAt(3).Param3 = 1
234 TheMCE.GetOperandAt(3).GetOperandCell(1).DoubleValue = 0
235 TheMCE.GetOperandAt(3).GetOperandCell(2).DoubleValue = 200
236
237 TheMCE.GetOperandAt(4).Param2 = 2
238 TheMCE.GetOperandAt(4).Param3 = 2
239 TheMCE.GetOperandAt(4).GetOperandCell(1).DoubleValue = 0
240 TheMCE.GetOperandAt(4).GetOperandCell(2).DoubleValue = 1000000
241
242 # Setup detector color
243 x_width = 1.5
244 y_width = 1.5
245 x_pixel = 500
246 y_pixel = 500
247
248 o5.ObjectData.XHalfWidth = x_width
249 o5.ObjectData.YHalfWidth = x_width
250 o5.ObjectData.NumberXPixels = x_pixel
251 o5.ObjectData.NumberYPixels = y_pixel
252
253 plt.rcParams["figure.figsize"] = (10, 4)
254 for a in range(1, TheMCE.NumberOfConfigurations + 1):
255 TheMCE.SetCurrentConfiguration(a)
256 # Setup and run the ray trace
257 NSCRayTrace = TheSystem.Tools.OpenNSCRayTrace()
258 NSCRayTrace.ClearDetectors(0)
259 NSCRayTrace.SplitNSCRays = False
260 NSCRayTrace.ScatterNSCRays = False
261 NSCRayTrace.UsePolarization = False
262 NSCRayTrace.IgnoreErrors = True
263 NSCRayTrace.SaveRays = False
264 NSCRayTrace.RunAndWaitForCompletion()
265 NSCRayTrace.Close()
266
267 print('Finished ray trace')
268
269 #! [e25s06_py]
270 # Creates a new detector viewer window, changes to true color
271 det = TheSystem.Analyses.New_Analysis(ZOSAPI.Analysis.AnalysisIDM.DetectorViewer)
272 det_settings = det.GetSettings()
273 # ensure detector viewer is true color to extract RGB data
274 det_settings.ShowAs = ZOSAPI.Analysis.DetectorViewerShowAsTypes.TrueColor
275 det.ApplyAndWaitForCompletion()
276 #! [e25s06_py]
277
278 #! [e25s07_py]
279 det_raw = det.GetResults().GetDataGridRgb(0)
280 # FillValues() method still in development for Python; need to use GetValue()
281 xpix = o5.ObjectData.NumberXPixels
282 ypix = o5.ObjectData.NumberYPixels
283 data = np.zeros([ypix, xpix, 3])
284 for y in range(0, ypix):
285 for x in range(0, xpix):
286 rgb = det_raw.GetValue(x, y)
287 data[y, x, 0] = rgb.R / 255
288 data[y, x, 1] = rgb.G / 255
289 data[y, x, 2] = rgb.B / 255
290
291 #! [e25s07_py]
292 plt.subplot(1, TheMCE.NumberOfConfigurations, a)
293 plt.imshow(np.flipud(data), extent=[-x_width, x_width, -y_width, y_width])
294 plt.title('Config = ' + str(a))
295
296 TheSystem.SaveAs(TheApplication.SamplesDir + '\\API\\Python\\e25_source_spectrum_diffraction_grating.zos')
297
298 # This will clean up the connection to OpticStudio.
299 # Note that it closes down the server instance of OpticStudio, so you for maximum performance do not do
300 # this until you need to.
301 del zos
302 zos = None
303
304 # place plt.show() after clean up to release OpticStudio from memory
305 plt.show()
Definition: ZemaxService.cs:198