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

Source Code for Module theia.optics.lens

  1  '''Defines the Lens class for theia.''' 
  2   
  3  # Provides: 
  4  #   class Lens 
  5  #       isHit 
  6  #       hit 
  7  #       hitActive 
  8   
  9  import numpy as np 
 10  from ..helpers import geometry, settings 
 11  from ..helpers.units import pi 
 12  from .optic import Optic 
 13  from .beam import GaussianBeam 
 14   
15 -class Lens(Optic):
16 ''' 17 18 Lens class. 19 20 This class is a base class for lenses. It implements the hit and hitActive 21 methods for all lenses. 22 23 *=== Attributes ===* 24 SetupCount (inherited): class attribute, counts all setup components. 25 [integer] 26 OptCount (inherited): class attribute, counts optical components. [integer] 27 HRCenter (inherited): center of the 'chord' of the HR surface. [3D vector] 28 HRNorm (inherited): unitary normal to the 'chord' of the HR (always pointing 29 towards the outside of the component). [3D vector] 30 Thick (inherited): thickness of the optic, counted in opposite direction to 31 HRNorm. [float] 32 Dia (inherited): diameter of the component. [float] 33 Name (inherited): name of the component. [string] 34 Ref (inherited): reference string (for keeping track with the lab). [string] 35 ARCenter (inherited): center of the 'chord' of the AR surface. [3D vector] 36 ARNorm (inherited): unitary normal to the 'chord' of the AR (always pointing 37 towards the outside of the component). [3D vector] 38 N (inherited): refraction index of the material. [float] 39 HRK, ARK (inherited): curvature of the HR, AR surfaces. [float] 40 HRr, HRt, ARr, ARt (inherited): power reflectance and transmission 41 coefficients of the HR and AR surfaces. [float] 42 KeepI (inherited): whether of not to keep data of rays for interference 43 calculations on the HR. [boolean] 44 45 **Note**: the curvature of any surface is positive for a concave surface 46 (coating inside the sphere). 47 Thus kurv*HRNorm/|kurv| always points to the center 48 of the sphere of the surface, as is the convention for the lineSurfInter of 49 geometry module. Same for AR. 50 51 ******* HRK > 0 and ARK > 0 ******* HRK > 0 and ARK < 0 52 ***** ******** and |ARK| > |HRK| 53 H***A H*********A 54 ***** ******** 55 ******* ******* 56 57 '''
58 - def isHit(self, beam):
59 '''Determine if a beam hits the Lens. 60 61 This is a generic function for all lenses, using their geometrical 62 attributes. This uses the line***Inter functions from the geometry 63 module to find characteristics of impact of beams on lenses. 64 65 beam: incoming beam. [GaussianBeam] 66 67 Returns a dictionary with keys: 68 'isHit': whether the beam hits the optic. [boolean] 69 'intersection point': point in space where it is first hit. 70 [3D vector] 71 'face': to indicate which face is first hit, can be 'HR', 'AR' or 72 'side'. [string] 73 'distance': geometrical distance from beam origin to impact. [float] 74 75 ''' 76 noInterDict = {'isHit': False, 77 'intersection point': np.array([0., 0., 0.], 78 dtype=np.float64), 79 'face': None, 80 'distance': 0.} 81 82 # get impact parameters on HR, AR and side: 83 if np.abs(self.HRK) > 0.: 84 HRDict = geometry.lineSurfInter(beam.Pos, 85 beam.Dir, self.HRCenter, 86 self.HRK*self.HRNorm/np.abs(self.HRK), 87 np.abs(self.HRK), 88 self.Dia) 89 else: 90 HRDict = geometry.linePlaneInter(beam.Pos, beam.Dir, self.HRCenter, 91 self.HRNorm, self.Dia) 92 93 if np.abs(self.ARK) > 0.: 94 ARDict = geometry.lineSurfInter(beam.Pos, 95 beam.Dir, self.ARCenter, 96 self.ARK*self.ARNorm/np.abs(self.ARK), 97 np.abs(self.ARK), 98 self.Dia) 99 else: 100 ARDict = geometry.linePlaneInter(beam.Pos, beam.Dir, self.ARCenter, 101 self.ARNorm, self.Dia) 102 103 SideDict = geometry.lineCylInter(beam.Pos, beam.Dir, 104 self.HRCenter, self.HRNorm, 105 self.Thick, self.Dia) 106 107 # face tags 108 HRDict['face'] = 'HR' 109 ARDict['face'] = 'AR' 110 SideDict['face'] = 'Side' 111 112 # determine first hit 113 hitFaces = filter(lambda dic: dic['isHit'], [HRDict, ARDict, SideDict]) 114 115 if len(hitFaces) == 0: 116 return noInterDict 117 118 dist = hitFaces[0]['distance'] 119 j=0 120 121 for i in range(len(hitFaces)): 122 if hitFaces[i]['distance'] < dist: 123 dist = hitFaces[i]['distance'] 124 j=i 125 126 return {'isHit': True, 127 'intersection point': hitFaces[j]['intersection point'], 128 'face': hitFaces[j]['face'], 129 'distance': hitFaces[j]['distance'] 130 }
131
132 - def hit(self, beam, order, threshold):
133 '''Compute the refracted and reflected beams after interaction. 134 135 This function is valid for all types of lenses. 136 The beams returned are those selected after the order and threshold 137 criterion. 138 139 beam: incident beam. [GaussianBeam] 140 order: maximum strayness of daughter beams, whixh are not returned if 141 their strayness is over this order. [integer] 142 threshold: idem for the power of the daughter beams. [float] 143 144 Returns a dictionary of beams with keys: 145 't': refracted beam. [GaussianBeam] 146 'r': reflected beam. [GaussianBeam] 147 148 ''' 149 # get impact parameters and update beam 150 dic = self.isHit(beam) 151 beam.Length = dic['distance'] 152 beam.OptDist = beam.N * beam.Length 153 154 if dic['face'] == 'HR' or dic['face'] == 'AR': 155 return self.hitActive(beam, dic['intersection point'], dic['face'], 156 order, threshold) 157 else: 158 return self.hitSide(beam)
159
160 - def hitActive(self, beam, point, faceTag, order, threshold):
161 '''Compute the daughter beams after interaction on HR or AR at point. 162 163 AR andHr are the 'active' surfaces of the lens. 164 This function is valid for all types of lenses. 165 166 beam: incident beam. [GaussianBeam] 167 point: point in space of interaction. [3D vector] 168 faceTag: either 'AR' or 'HR' depending on the face. [string] 169 order: maximum strayness of daughter beams, whixh are not returned if 170 their strayness is over this order. [integer] 171 threshold: idem for the power of the daughter beams. [float] 172 173 Returns a dictionary of beams with keys: 174 't': refracted beam. [GaussianBeam] 175 'r': reflected beam. [GaussianBeam] 176 177 ''' 178 179 ans = {} 180 d = np.linalg.norm(point - beam.Pos) 181 182 # determine global norm and center 183 if faceTag == 'AR': 184 Norm = self.ARNorm 185 Center = self.ARCenter 186 K = self.ARK 187 else: 188 Norm = self.HRNorm 189 Center = self.HRCenter 190 K = self.HRK 191 192 # Calculate the local normal in opposite direction 193 if K == 0.: 194 localNorm = Norm 195 else: 196 try: 197 theta = np.arcsin(self.Dia * K/2.) #undertending angle 198 except FloatingPointError: 199 theta = pi/2. 200 sphereC = Center + np.cos(theta)*Norm/K 201 localNorm = sphereC - point 202 localNorm = localNorm/np.linalg.norm(localNorm) 203 204 if np.dot(beam.Dir, localNorm) > 0.: 205 localNorm = - localNorm 206 K = np.abs(K) 207 else: 208 K = - np.abs(K) 209 210 # determine whether we're entering or exiting the substrate 211 if np.dot(beam.Dir, Norm) < 0.: 212 #entering 213 n1 = beam.N 214 n2 = self.N 215 else: 216 #exiting 217 n1 = self.N 218 n2 = 1. 219 220 # daughter directions 221 dir2 = geometry.newDir(beam.Dir, localNorm, n1, n2) 222 223 #warn on total reflection 224 if dir2['TR'] and settings.info: 225 print "theia: Info: Total reflection of " + beam.Ref + ' on '\ 226 + faceTag +' of '\ 227 + self.Name + " (" + self.Ref + ")." 228 229 # if there is no refracted 230 if beam.P * self.HRt < threshold or dir2['t'] is None: 231 ans['t'] = None 232 233 # if there is no reflected 234 if beam.P * self.HRr < threshold or beam.StrayOrder + 1 > order : 235 ans['r'] = None 236 237 # we're done if there are two Nones 238 if len(ans) == 2: 239 if settings.info: 240 print "theia: Info: Reached leaf of tree by interaction ("\ 241 + beam.Ref + " on " + self.Ref + ', ' + faceTag + ').' 242 return ans 243 244 # Calculate new basis 245 if not 'r' in ans: # for reflected 246 Uxr, Uyr = geometry.basis(dir2['r']) 247 Uzr = dir2['r'] 248 249 if not 't' in ans: # for refracted 250 Uxt, Uyt = geometry.basis(dir2['t']) 251 Uzt = dir2['t'] 252 253 Lx, Ly = geometry.basis(localNorm) 254 255 # Calculate daughter curv tensors 256 C = np.array([[K, 0.], [0, K]]) 257 Ki = np.array([[np.dot(beam.U[0], Lx), np.dot(beam.U[0], Ly)], 258 [np.dot(beam.U[1], Lx), np.dot(beam.U[1], Ly)]]) 259 Qi = beam.Q(d) 260 Kit = np.transpose(Ki) 261 Xi = np.matmul(np.matmul(Kit, Qi), Ki) 262 263 if not 't' in ans: 264 Kt = np.array([[np.dot(Uxt, Lx), np.dot(Uxt, Ly)], 265 [np.dot(Uyt, Lx), np.dot(Uyt, Ly)]]) 266 Ktt = np.transpose(Kt) 267 Ktinv = np.linalg.inv(Kt) 268 Kttinv = np.linalg.inv(Ktt) 269 Xt = (np.dot(localNorm, beam.Dir) -n2*np.dot(localNorm, Uzt)/n1) * C 270 Qt = n1*np.matmul(np.matmul(Kttinv, Xi - Xt), Ktinv)/n2 271 272 if not 'r' in ans: 273 Kr = np.array([[np.dot(Uxr, Lx), np.dot(Uxr, Ly)], 274 [np.dot(Uyr, Lx), np.dot(Uyr, Ly)]]) 275 Krt = np.transpose(Kr) 276 Krinv = np.linalg.inv(Kr) 277 Krtinv = np.linalg.inv(Krt) 278 Xr = (np.dot(localNorm, beam.Dir) - np.dot(localNorm, Uzr)) * C 279 Qr = np.matmul(np.matmul(Krtinv, Xi - Xr), Krinv) 280 281 # Create new beams 282 if not 'r' in ans: 283 ans['r'] = GaussianBeam(Q = Qr, 284 Pos = point, Dir = Uzr, Ux = Uxr, Uy = Uyr, 285 N = n1, Wl = beam.Wl, P = beam.P * self.HRr, 286 StrayOrder = beam.StrayOrder + 1, Ref = beam.Ref + 'r', 287 Optic = self.Ref, Face = faceTag, 288 Length = 0., OptDist = 0.) 289 290 if not 't' in ans: 291 ans['t'] = GaussianBeam(Q = Qt, Pos = point, 292 Dir = Uzt, Ux = Uxt, Uy = Uyt, N = n2, Wl = beam.Wl, 293 P = beam.P * self.HRt, StrayOrder = beam.StrayOrder, 294 Ref = beam.Ref + 't', Optic = self.Ref, Face = faceTag, 295 Length = 0., OptDist = 0.) 296 297 return ans
298