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