1 '''Defines the GaussianBeam class for theia.'''
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 import numpy as np
21 from ..helpers import geometry
22 from ..helpers.tools import formatter
23 from ..helpers.units import pi, nm, deg, mm
24
26 '''
27
28 GaussianBeam class.
29
30 This class represents general astigmatic Gaussian beams in 3D space.
31 These are the objects that are intended to interact with the optical
32 components during the ray tracing and that are rendered in 3D thanks to
33 FreeCAD.
34
35 *=== Attributes ===*
36 BeamCount: class attribute, counts beams. [integer]
37 Name: class attribute. [string]
38 QTens: general astigmatic complex curvature tensor at the origin.
39 [np. array of complex]
40 N: Refraction index of the medium in which the beam is placed. [float]
41 Wl: Wave-length in vacuum of the beam (frequency never changes). [float]
42 P: Power of the beam. [float]
43 Pos: Position in 3D space of the origin of the beam. [3D vector]
44 Dir: Normalized direction in 3D space of the beam axis. [3D vector]
45 U: A tuple of unitary vectors which along with Dir form a direct orthonormal
46 basis in which the Q tensor is expressed. [tuple of 3D vectors]
47 Ref: Reference to the beam. [string]
48 OptDist: Optical length. [float]
49 Length: Geometrical length of the beam. [float]
50 StrayOrder: Number representing the *strayness* of the beam. If the beams
51 results from a transmission on a HR surface or a reflection on a AR
52 surface, then its StrayOrder is the StrayOrder of the parent beam + 1.
53 [integer]
54 Optic: Ref of optic where the beam departs from ('Laser' if laser). [string]
55 Face: Face of the optic where the beam departs from. [string]
56 TargetOptic: Ref of the optic where the beam terminates (None if open
57 beam). [string]
58 TargetFace: Face of the target optic where the beam terminates. [string]
59 DWx: Distance of waist on X. [float]
60 DWy: Distance of waist on Y. [float]
61 Wx: Waist on X. [float]
62 Wy: Waist on Y. [float]
63 IWx: Width of beam on X at origin. [float]
64 IWy: Width of beam on Y at origin. [float]
65 TWx: Width of beam on X at target surface (None if open beam). [float]
66 TWy: Width of beam on Y at target surface (None if open beam).
67
68 '''
69 BeamCount = 0
70 Name = "Beam"
71
72 - def __init__(self, Q, N, Wl, P, Pos, Dir, Ux, Uy, Ref, OptDist,
73 Length, StrayOrder, Optic, Face):
74 '''Beam initializer.
75
76 This is the initializer used internally for beam creation, for user
77 inputed beams, see function userGaussianBeam.
78
79 Returns a Gaussian beam with attributes as the parameters.
80
81 '''
82
83
84 self.N = N
85 self.Wl = Wl
86 self.P = P
87 self.OptDist = OptDist
88 self.Length = Length
89 self.StrayOrder = StrayOrder
90
91 self.Ref = Ref
92
93 self.Pos = Pos
94 self.Dir = Dir
95
96
97 self.U = (Ux, Uy)
98
99
100 self.QTens = np.array(Q, dtype = np.complex64)
101
102
103 self.Optic = Optic
104 self.Face = Face
105
106
107 self.TargetOptic = None
108 self.TargetFace = None
109
110
111 self.initGaussianData()
112 self.TWx = None
113 self.TWy = None
114
115 self.__class__.BeamCount = self.__class__.BeamCount + 1
116
118 '''String representation of the beam, when calling print(beam).
119
120 '''
121 return formatter(self.lines())
122
124 '''Returns the list of lines necessary to print the object.
125
126 '''
127 sph = geometry.rectToSph(self.Dir)
128 sphx = geometry.rectToSph(self.U[0])
129 sphy = geometry.rectToSph(self.U[1])
130
131 return ["Beam: %s {" %self.Ref,
132 "Power: %sW/Index: %s/Wavelength: %snm/Length: %sm" \
133 % (str(self.P), str(self.N), str(self.Wl/nm), str(self.Length)),
134 "Order: %s" %str(self.StrayOrder),
135 "Origin: %s" %str(self.Pos),
136 "Direction: (%s, %s)deg" % (str(sph[0]/deg), str(sph[1]/deg)),
137 "Ux: (%s, %s)deg" % (str(sphx[0]/deg), str(sphx[1]/deg) ),
138 "Uy: (%s, %s)deg" % (str(sphy[0]/deg), str(sphy[1]/deg)),
139 "Waist Pos: (%s, %s)m" % ( str(self.DWx), str(self.DWy) ),
140 "Waist Size: (%s, %s)mm" % (str(self.Wx/mm), str(self.Wy/mm)),
141 "Rayleigh: %sm" % str(self.rayleigh()),
142 "ROC: " + str(self.ROC()),
143 "}"]
144
145 - def Q(self, d = 0.):
146 '''Return the Q tensor at a distance d of origin.
147
148 '''
149 d = float(d)
150 I = np.array([[1., 0.], [0., 1.]], dtype=np.float64)
151 return np.dot(np.linalg.inv(I + d * self.QTens), self.QTens)
152
154 '''Compute the complex parameters q1 and q2 and theta of beam.
155
156 What is implemented here is a straightforward calculation to extract
157 the q1, q2, and theta of the normal form of Q.
158
159 Returns a tuple q1, q2, theta
160 '''
161 Q = self.Q(float(d))
162
163 a = Q[0][0]
164 b = Q[0][1]
165 c = Q[1][1]
166
167 if a == c:
168 theta = pi/4.
169 qxinv = (a + b)
170 qyinv = (a - b)
171
172 else:
173 theta = .5*np.arctan(2*b/(a-c))
174 qxinv = 0.5*(a + c + (a - c)/np.cos(2 *theta))
175 qyinv = 0.5*(a + c - (a - c)/np.cos(2 *theta))
176
177 q1 = np.inf if qxinv == 0. else 1./qxinv
178 q2 = np.inf if qyinv == 0. else 1./qyinv
179
180 return q1, q2, theta
181
182 - def ROC(self, dist = 0.):
183 '''Return the tuple of ROC of the beam.
184
185 '''
186 dist = float(dist)
187 q1, q2, _ = self.QParam(dist)
188 try:
189 a = 1./np.real(1./q1)
190 except FloatingPointError:
191 a = np.inf
192 try:
193 b = 1./np.real(1./q2)
194 except FloatingPointError:
195 b = np.inf
196
197 return (a, b)
198
200 '''Return the tuple of positions of the waists of the beam along Dir.
201
202 '''
203 q1, q2, q3 = self.QParam(0.)
204 return (-np.real(q1), -np.real(q2))
205
207 '''Return the tuple of Rayleigh ranges of the beam.
208
209 '''
210 q1, q2, _ = self.QParam(0.)
211 return (np.abs(np.imag(q1)), np.abs(np.imag(q2)))
212
213 - def width(self, d = 0.):
214 '''Return the tuple of beam widths at distance d.
215
216 '''
217 lam = self.Wl/self.N
218 q1, q2, _ = self.QParam(float(d))
219
220 return (np.sqrt((lam/pi)*((d - np.real(q1))**2.\
221 + np.imag(q1)**2.)/np.imag(q1)),
222 np.sqrt((lam/pi)*((d - np.real(q2))**2.\
223 + np.imag(q2)**2.)/np.imag(q2)))
224
226 '''Return a tuple with the waist sizes in x and y.
227
228 '''
229 q1, q2, _ = self.QParam()
230 lam = self.Wl/self.N
231
232 return (np.sqrt(lam/pi)*np.abs(q1)/np.sqrt(np.imag(q1)) ,
233 np.sqrt(lam/pi)*np.abs(q2)/np.sqrt(np.imag(q2)))
234
235 - def gouy(self, d = 0.):
236 '''Return the tuple of Gouy phases.
237
238 '''
239 q1, q2, _ = self.QParam(float(d))
240
241 return (np.arctan(np.real(q1)/np.imag(q1)),
242 np.arctan(np.real(q2)/np.imag(q2)))
243
245 '''Writes the relevant DW, W, IW data with Q.
246
247 Is called upon construction to write the data of waist position and
248 size, initial widths once and for all.
249
250 '''
251 dist = self.waistPos()
252 size = self.waistSize()
253 initWidth = self.width(0.)
254 self.DWx = dist[0]
255 self.DWy = dist[1]
256 self.Wx = size[0]
257 self.Wy = size[1]
258 self.IWx = initWidth[0]
259 self.IWy = initWidth[1]
260
261 - def translate(self, X = 0., Y = 0., Z = 0.):
262 '''Move the beam to (current position + (X, Y, Z)).
263
264 X, Y, Z: components of the translation vector.
265
266 No return value.
267 '''
268 self.Pos = self.Pos + np.array([X, Y, Z], dtype = np.float64)
269
270 -def userGaussianBeam(Wx = 1.e-3, Wy = 1.e-3, WDistx = 0., WDisty = 0.,
271 Wl = 1064.e-9, P = 1., X = 0., Y = 0., Z = 0.,
272 Theta = pi/2., Phi = 0., Alpha = 0.,
273 Ref = None):
274 '''Constructor used for user inputed beams, separated from the class
275 initializer because the internal state of a beam is very different from
276 the input of this user-defined beam.
277
278 Input parameters are processed to make arguments for the class
279 contructor and then the corresponding beam is returned.
280 '''
281
282
283 P = float(P)
284 Pos = np.array([X, Y, Z], dtype = np.float64)
285 Dir = np.array([np.sin(Theta) * np.cos(Phi),
286 np.sin(Theta) * np.sin(Phi),
287 np.cos(Theta)], dtype = np.float64)
288
289
290 Alpha = float(Alpha)
291 (u1,v1) = geometry.basis(Dir)
292 v = np.cos(Alpha)*v1 - np.sin(Alpha)*u1
293 u = np.cos(Alpha)*u1 + np.sin(Alpha)*v1
294
295
296 Wl = np.abs(float(Wl))
297 Wx = float(Wx)
298 Wy = float(Wy)
299 qx = complex(- float(WDistx) + 1.j * pi*Wx**2./Wl )
300 qy = complex(- float(WDisty) + 1.j * pi*Wy**2./Wl )
301 QTens = np.array([[1./qx, 0.],[0., 1./qy]],
302 dtype = np.complex64)
303
304 Ref = "Beam%s-" %str(GaussianBeam.BeamCount) if Ref is None else Ref + '-'
305
306 return GaussianBeam(Q = QTens, N = 1., Wl = Wl, P = P,
307 Pos = Pos, Dir = Dir,
308 Ux = u, Uy = v, Ref = Ref, OptDist = 0.,
309 Length = 0., StrayOrder = 0, Optic = 'Laser', Face = 'Out')
310