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 %s on (%s, %s)." \ 226 %(beam.Ref, self.Ref, faceTag) 227 228 # if there is no refracted 229 if beam.P * self.HRt < threshold or dir2['t'] is None: 230 ans['t'] = None 231 232 # if there is no reflected 233 if beam.P * self.HRr < threshold or beam.StrayOrder + 1 > order : 234 ans['r'] = None 235 236 # we're done if there are two Nones 237 if len(ans) == 2: 238 if settings.info: 239 print ("theia: Info: Reached leaf of tree by interaction "\ 240 + "(%s on %s, %s).") %(beam.Ref, self.Ref, faceTag) 241 return ans 242 243 # Calculate new basis 244 if not 'r' in ans: # for reflected 245 Uxr, Uyr = geometry.basis(dir2['r']) 246 Uzr = dir2['r'] 247 248 if not 't' in ans: # for refracted 249 Uxt, Uyt = geometry.basis(dir2['t']) 250 Uzt = dir2['t'] 251 252 Lx, Ly = geometry.basis(localNorm) 253 254 # Calculate daughter curv tensors 255 C = np.array([[K, 0.], [0, K]]) 256 Ki = np.array([[np.dot(beam.U[0], Lx), np.dot(beam.U[0], Ly)], 257 [np.dot(beam.U[1], Lx), np.dot(beam.U[1], Ly)]]) 258 Qi = beam.Q(d) 259 Kit = np.transpose(Ki) 260 Xi = np.dot(np.dot(Kit, Qi), Ki) 261 262 if not 't' in ans: 263 Kt = np.array([[np.dot(Uxt, Lx), np.dot(Uxt, Ly)], 264 [np.dot(Uyt, Lx), np.dot(Uyt, Ly)]]) 265 Ktt = np.transpose(Kt) 266 Ktinv = np.linalg.inv(Kt) 267 Kttinv = np.linalg.inv(Ktt) 268 Xt = (np.dot(localNorm, beam.Dir) -n2*np.dot(localNorm, Uzt)/n1) * C 269 Qt = n1*np.dot(np.dot(Kttinv, Xi - Xt), Ktinv)/n2 270 271 if not 'r' in ans: 272 Kr = np.array([[np.dot(Uxr, Lx), np.dot(Uxr, Ly)], 273 [np.dot(Uyr, Lx), np.dot(Uyr, Ly)]]) 274 Krt = np.transpose(Kr) 275 Krinv = np.linalg.inv(Kr) 276 Krtinv = np.linalg.inv(Krt) 277 Xr = (np.dot(localNorm, beam.Dir) - np.dot(localNorm, Uzr)) * C 278 Qr = np.dot(np.dot(Krtinv, Xi - Xr), Krinv) 279 280 # Create new beams 281 if not 'r' in ans: 282 ans['r'] = GaussianBeam(Q = Qr, 283 Pos = point, Dir = Uzr, Ux = Uxr, Uy = Uyr, 284 N = n1, Wl = beam.Wl, P = beam.P * self.HRr, 285 StrayOrder = beam.StrayOrder + 1, Ref = beam.Ref + 'r', 286 Optic = self.Ref, Face = faceTag, 287 Length = 0., OptDist = 0.) 288 289 if not 't' in ans: 290 ans['t'] = GaussianBeam(Q = Qt, Pos = point, 291 Dir = Uzt, Ux = Uxt, Uy = Uyt, N = n2, Wl = beam.Wl, 292 P = beam.P * self.HRt, StrayOrder = beam.StrayOrder, 293 Ref = beam.Ref + 't', Optic = self.Ref, Face = faceTag, 294 Length = 0., OptDist = 0.) 295 296 return ans
297