Repository navigation
Expand file tree
/
Copy patharrayTraceClient.py
More file actions
134 lines (125 loc) · 5.92 KB
/
Copy patharrayTraceClient.py
File metadata and controls
134 lines (125 loc) · 5.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# Python file
# Note: Before executing this module please ensure that a lens file has been
# loaded into Zemax. Specifically, for using the function replicateArrayDemo()
# load the file ...\ZEMAX\Samples\Sequential\Objectives\Cooke 40 degree field.zmx
from __future__ import print_function, division
import os as os
import sys as sys
import time as time
from ctypes import WinDLL, c_int, c_double, Structure, POINTER, c_char_p, create_string_buffer
import matplotlib.pyplot as plt
import pyzdde.zdde as pyz
#import numpy as np
#from numpy.ctypeslib import load_library
def is64bit():
"""Returns True if 64 bit, False if not (i.e. if 32 bit Python environment)
This is just a helper function and not really required for array ray tracing
"""
return sys.maxsize > 2**31 - 1
# Ray data structure
# Following fields in the 0th array element have special meaning:
# 1. "opd" - used to specify ray-trace-mode (0 == GetTrace, 1 == GetTraceDirect,
# 2 == GetPolTrace, 3 == GetPolTraceDirect)
# 2. "wave" - used to specify real or paraxial mode (0 == real, 1 == paraxial)
# 3. "error" - used to specify the number of rays in the array
# 4. "vigcode" - used to specify the start surface in mode 1, mode 3
# 5. "want_opd" - used to specify the last surface (-1 for image, or any valid surface number)
class DdeArrayData(Structure):
_fields_ = [( 'x', c_double), ('y', c_double), ('z', c_double),
( 'l', c_double), ('m', c_double), ('n', c_double),
('opd', c_double), ('intensity', c_double),
('Exr', c_double), ('Exi', c_double),
('Eyr', c_double), ('Eyi', c_double),
('Ezr', c_double), ('Ezi', c_double),
('wave', c_int), ('error', c_int),
('vigcode', c_int), ('want_opd', c_int)]
def print_ray_data(rd, infoText):
# Print the ray data for debugging
print(infoText)
print("\n")
num_rays = rd[0].error
for i in range(num_rays + 1):
print("rd[{}].x = ".format(i), rd[i].x)
print("rd[{}].y = ".format(i), rd[i].y)
print("rd[{}].z = ".format(i), rd[i].z)
print("rd[{}].l = ".format(i), rd[i].l)
print("rd[{}].m = ".format(i), rd[i].m)
print("rd[{}].n = ".format(i), rd[i].n)
print("rd[{}].opd = ".format(i), rd[i].opd)
print("rd[{}].intensity = ".format(i), rd[i].intensity)
print("rd[{}].Exr = ".format(i), rd[i].Exr)
print("rd[{}].Exi = ".format(i), rd[i].Exi)
print("rd[{}].Eyr = ".format(i), rd[i].Eyr)
print("rd[{}].Eyi = ".format(i), rd[i].Eyi)
print("rd[{}].Ezr = ".format(i), rd[i].Ezr)
print("rd[{}].Ezi = ".format(i), rd[i].Ezi)
print("rd[{}].wave = ".format(i), rd[i].wave)
print("rd[{}].error = ".format(i), rd[i].error)
print("rd[{}].vigcode = ".format(i), rd[i].vigcode)
print("rd[{}].want_opd = ".format(i), rd[i].want_opd)
print("\n")
def getArrayTraceFunction(dllName, dllpath):
"""returns the array ray tracing function
"""
# load the arrayTrace library
#array_trace_lib = load_library(dllName, dllpath)
array_trace_lib = WinDLL(dllpath + dllName)
arrayTrace = array_trace_lib.arrayTrace
# specify argtypes and restype
arrayTrace.restype = c_int
arrayTrace.argtypes = [POINTER(DdeArrayData)]
return arrayTrace
def replicateArrayDemo(func):
"""Emulate Zemax example output of ArrayDemo.c that ships with Zemax.
Compare the output of this funcntion, which is in the file named
"arrayDemo.txt" with the text file "arrayDemoRef.txt" that was
generated by running ArrayDemo.c without any modification.
"""
# Set up ray data. In this example, we are using mode 0 (similar
# to GetTrace) for 441 rays, at wavelength number 1. hx, hy = 0,
# 0 for all rays;
num_rays = 441
rd = (DdeArrayData * (num_rays + 1))()
# Setup a basic ray data array for test
rd[0].opd = 0.0 # mode 0, like GetTrace
rd[0].wave = 0 # real ray tracing
rd[0].error = c_int(num_rays) # number of rays
rd[0].want_opd = -1 # trace upto image surface
k = 0
for i in xrange(-10, 11, 1):
for j in xrange(-10, 11, 1):
k += 1
rd[k].z = i/20 # px
rd[k].l = j/20 # py
rd[k].intensity = 1.0
rd[k].wave = 1
#print_ray_data(rd, "Ray data info @ Python side before sending to C side:") # for visual debugging
tmp_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), "arrayDemo.txt")
start_time = time.clock()
ret = func(rd)
end_time = time.clock()
print("Time before tracing: ", (start_time)*10e6, "micro seconds")
print("Ray tracing took", (end_time - start_time)*10e3, " milli seconds")
print("ret = ", ret)
if ret==0:
#print_ray_data(rd, "Ray data info @ Python AFTER ray tracing:")
k = 0
with open(tmp_file, 'w') as f:
f.write("Listing of Array trace data\n")
f.write(" px py error xout yout trans\n")
for i in xrange(-10, 11, 1):
for j in xrange(-10, 11, 1):
k += 1
line = ("{:7.3f} {:7.3f} {:5d} {:15.6E} {:15.6E} {:7.4f}\n"
.format(i/20, j/20, rd[k].error, rd[k].x, rd[k].y, rd[k].intensity))
f.write(line)
else:
print("There was some problem in ray tracing")
print("OK!")
if __name__ == '__main__':
dllDir = "x64\\Release\\" if is64bit() else "Release\\"
dllName = "ArrayTrace.dll"
dllpath = os.path.join(os.path.dirname(os.path.realpath(__file__)), dllDir)
arrayTrace = getArrayTraceFunction(dllName, dllpath)
# Different functions for testing
replicateArrayDemo(arrayTrace) # produces output that match the original ArrayDemo.c output