Package theia :: Package optics :: Module beam
[hide private]
[frames] | no frames]

Source Code for Module theia.optics.beam

  1  '''Defines the GaussianBeam class for theia.''' 
  2   
  3  # Provides: 
  4  #   class GaussianBeam 
  5  #       __init__ 
  6  #       userBeam 
  7  #       __str__ 
  8  #       lines 
  9  #       Q 
 10  #       QParam 
 11  #       ROC 
 12  #       waistPos 
 13  #       rayleigh 
 14  #       width 
 15  #       waistSize 
 16  #       gouy 
 17   
 18  import numpy as np 
 19  from ..helpers import geometry 
 20  from ..helpers.tools import formatter 
 21  from ..helpers.units import pi 
22 23 -class GaussianBeam(object):
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 # counts beams 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 # external params 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 # orthonormal basis in which Q is expressed 84 self.U = (Ux, Uy) 85 86 # Curvature tensor 87 self.QTens = np.array(Q, dtype = np.complex64) 88 89 #origin optics 90 self.Optic = Optic 91 self.Face = Face 92 93 self.__class__.BeamCount = self.__class__.BeamCount + 1
94 95 @classmethod
96 - def userGaussianBeam(cls, Wx = 1.e-3, Wy = 1.e-3, WDistx = 0., WDisty = 0., 97 Wl = 1064.e-9, P = 1., X = 0., Y = 0., Z = 0., 98 Theta = pi/2., Phi = 0., Alpha = 0., Name = None, 99 Ref = None):
100 '''Constructor used for user inputed beams, separated from the class 101 initializer because the internal state of a beam is very different from 102 the input of this user-defined beam. 103 104 Input parameters are processed to make arguments for the class 105 contructor and then the corresponding beam is returned. 106 ''' 107 108 #externs 109 P = float(P) 110 Pos = np.array([X, Y, Z], dtype = np.float64) 111 Dir = np.array([np.sin(Theta) * np.cos(Phi), 112 np.sin(Theta) * np.sin(Phi), 113 np.cos(Theta)], dtype = np.float64) 114 115 # basis for Q tensor 116 Alpha = float(Alpha) 117 (u1,v1) = geometry.basis(Dir) 118 v = np.cos(Alpha)*v1 - np.sin(Alpha)*u1 119 u = np.cos(Alpha)*u1 + np.sin(Alpha)*v1 120 121 # Q tensor for orthogonal beam 122 Wl = float(Wl) 123 Wx = float(Wx) 124 Wy = float(Wy) 125 qx = complex(- float(WDistx) + 1.j * pi*Wx**2./Wl ) 126 qy = complex(- float(WDisty) + 1.j * pi*Wy**2./Wl ) 127 QTens = np.array([[1./qx, 0.],[0., 1./qy]], 128 dtype = np.complex64) 129 130 if Name is None: 131 Name = "Beam" 132 else: 133 Name = Name 134 135 if Ref is None: 136 Ref = "Beam" + str(GaussianBeam.BeamCount) 137 else: 138 Ref = Ref 139 140 return GaussianBeam(Q = QTens, N = 1., Wl = Wl, P = P, 141 Pos = Pos, Dir = Dir, 142 Ux = u, Uy = v, Name = Name, Ref = Ref, OptDist = 0., 143 Length = 0., StrayOrder = 0, Optic = 'Laser', Face = 'Out')
144
145 - def __str__(self):
146 '''String representation of the beam, when calling print(beam). 147 148 ''' 149 return formatter(self.lines())
150
151 - def lines(self):
152 '''Returns the list of lines necessary to print the object. 153 154 ''' 155 ans = [] 156 ans.append("Beam: " + self.Name + " (" + self.Ref + ") " + "{") 157 ans.append("Power: " + str(self.P) + "W/"\ 158 +"Index: " + str(self.N)\ 159 +"/Wavelength: "+str(self.Wl/nm)+"nm/Length: " + str(self.Length) + "m") 160 ans.append("Order: " + str(self.StrayOrder)) 161 ans.append("Origin: " + str(self.Pos)) 162 163 sph = geometry.rectToSph(self.Dir) 164 ans.append("Direction: (" + str(sph[0]/deg) + ', ' \ 165 + str(sph[1]/deg) + ')deg') 166 167 sphx = geometry.rectToSph(self.U[0]) 168 ans.append("Ux: (" + str(sphx[0]/deg) + ', ' \ 169 + str(sphx[1]/deg) + ')deg') 170 171 sphy = geometry.rectToSph(self.U[1]) 172 ans.append("Uy: (" + str(sphy[0]/deg) + ', ' \ 173 + str(sphy[1]/deg) + ')deg') 174 ans.append("Waist Pos: " + str(self.waistPos()) + 'm') 175 ans.append("Waist Size: (" \ 176 + str(self.waistSize()[0]/mm) + ', ' + str(self.waistSize()[1]/mm)\ 177 + ')mm') 178 ans.append("Rayleigh: " + str(self.rayleigh()) + "m") 179 ans.append("ROC: " + str(self.ROC())) 180 ans.append("}") 181 182 return ans
183
184 - def Q(self, d = 0.):
185 '''Return the Q tensor at a distance d of origin. 186 187 ''' 188 d = float(d) 189 I = np.array([[1., 0.], [0., 1.]], dtype=np.float64) 190 return np.matmul(np.linalg.inv(I + d * self.QTens),self.QTens)
191
192 - def QParam(self, d = 0.):
193 '''Compute the complex parameters q1 and q2 and theta of beam. 194 195 Returns a dictionary with keys: 196 '1': q1 [complex] 197 '2': q2 [complex] 198 'theta': theta [float] 199 ''' 200 d = float(d) 201 202 a = self.Q(d)[0][0] 203 b = self.Q(d)[0][1] 204 d = self.Q(d)[1][1] 205 206 q1inv = .5*(a + d + np.sqrt((a - d)**2. + 4.*b**2.)) 207 q2inv = .5*(a + d - np.sqrt((a - d)**2. + 4.*b**2.)) 208 209 if q1inv == q2inv: 210 theta = 0. 211 else: 212 theta = .5*np.arcsin(2.*b/(q1inv - q2inv)) 213 214 try: 215 a = 1/q1inv 216 except ZeroDivisionError: 217 a = np.inf 218 try: 219 b = 1/q2inv 220 except ZeroDivisionError: 221 b = np.inf 222 return {'1': a, '2': b, 'theta':theta}
223
224 - def ROC(self, dist = 0.):
225 '''Return the tuple of ROC of the beam. 226 227 ''' 228 dist = float(dist) 229 Q = self.QParam(dist) 230 try: 231 a = 1./np.real(1./Q['1']) 232 except FloatingPointError: 233 a = np.inf 234 try: 235 b = 1./np.real(1./Q['2']) 236 except FloatingPointError: 237 b = np.inf 238 239 return (a, b)
240
241 - def waistPos(self):
242 '''Return the tuple of positions of the waists of the beam along Dir. 243 244 ''' 245 Q = self.QParam(0.) 246 return (-np.real(Q['1']), -np.real(Q['2']))
247
248 - def rayleigh(self):
249 '''Return the tuple of Rayleigh ranges of the beam. 250 251 ''' 252 Q = self.QParam() 253 return (np.abs(np.imag(Q['1'])), np.abs(np.imag(Q['2'])))
254
255 - def width(self, d = 0.):
256 '''Return the tuple of beam widths. 257 258 ''' 259 d = float(d) 260 lam = self.Wl/self.N 261 zR = self.rayleigh() 262 D = self.waistPos() 263 264 return (np.sqrt((lam/pi)*((d - D[0])**2. + zR[0]**2.)/zR[0]) , 265 np.sqrt((lam/pi)*((d - D[1])**2. + zR[1]**2.)/zR[1]))
266
267 - def waistSize(self):
268 '''Return a tuple with the waist sizes in x and y. 269 270 ''' 271 pos = self.waistPos() 272 return (self.width(pos[0])[0], self.width(pos[1])[1] )
273
274 - def gouy(self, d = 0.):
275 '''Return the tuple of Gouy phases. 276 277 ''' 278 d = float(d) 279 zR = self.rayleigh() 280 WDist = self.waistPos() 281 return (np.arctan((d-WDist[0])/zR[0]), 282 np.arctan((d-WDist[1])/zR[1]))
283