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

Source Code for Module theia.optics.mirror

  1  '''Defines the Mirror class for theia.''' 
  2   
  3  # Provides: 
  4  #   class Mirror 
  5  #       __init__ 
  6  #       lines 
  7  #       isHit 
  8  #       hit 
  9  #       hitHR 
 10  #       hitAR 
 11   
 12  import numpy as np 
 13  from ..helpers import geometry, settings 
 14  from ..helpers.units import deg, cm, pi 
 15  from .optic import Optic 
 16  from .beam import GaussianBeam 
 17   
18 -class Mirror(Optic):
19 ''' 20 21 Mirror class. 22 23 This class represents semi reflective mirrors composed of two faces (HR, AR) 24 and with a wedge angle. These are the objects with which the beams will 25 interqct during the ray tracing. Please see the documentation for details 26 on the geometric construction of these mirrors. 27 28 *=== Attributes ===* 29 SetupCount (inherited): class attribute, counts all setup components. 30 [integer] 31 OptCount (inherited): class attribute, counts optical components. [string] 32 HRCenter (inherited): center of the 'chord' of the HR surface. [3D vector] 33 HRNorm (inherited): unitary normal to the 'chord' of the HR (always pointing 34 towards the outside of the component). [3D vector] 35 Thick (inherited): thickness of the optic, counted in opposite direction to 36 HRNorm. [float] 37 Dia (inherited): diameter of the component. [float] 38 Name (inherited): name of the component. [string] 39 Ref (inherited): reference string (for keeping track with the lab). [string] 40 ARCenter (inherited): center of the 'chord' of the AR surface. [3D vector] 41 ARNorm (inherited): unitary normal to the 'chord' of the AR (always pointing 42 towards the outside of the component). [3D vector] 43 N (inherited): refraction index of the material. [float] 44 HRK, ARK (inherited): curvature of the HR, AR surfaces. [float] 45 HRr, HRt, ARr, ARt (inherited): power reflectance and transmission 46 coefficients of the HR and AR surfaces. [float] 47 KeepI (inherited): whether of not to keep data of rays for interference 48 calculations on the HR. [boolean] 49 Wedge: wedge angle of the mirror, please refer to the documentation for 50 detaild on the geometry of mirrors and their implementation here. 51 [float] 52 Alpha: rotation alngle used in the geometrical construction of the mirror 53 (see doc, it is the amgle between the projection of Ex on the AR plane 54 and the vector from ARCenter to the point where the cylinder and the AR 55 face meet). [float] 56 57 **Note**: the curvature of any surface is positive for a concave surface 58 (coating inside the sphere). 59 Thus kurv*HRNorm/|kurv| always points to the center 60 of the sphere of the surface, as is the convention for the lineSurfInter of 61 geometry module. Same for AR. 62 63 ******* HRK > 0 and ARK > 0 ******* HRK > 0 and ARK < 0 64 ***** ******** and |ARK| > |HRK| 65 H***A H*********A 66 ***** ******** 67 ******* ******* 68 69 ''' 70
71 - def __init__(self, Wedge = 0., Alpha = 0., X = 0. ,Y = 0., Z = 0., 72 Theta = pi/2., Phi = 0., Diameter = 10.e-2, 73 HRr = .99, HRt = .01, ARr = .1, ARt = .9, 74 HRK = 0.01, ARK = 0, Thickness = 2.e-2, 75 N = 1.4585, KeepI = False, Name = 'Mirror', Ref = None):
76 '''Mirror initializer. 77 78 Parameters are the attributes and the angles theta and phi are spherical 79 coordinates of HRNorm. 80 81 Returns a mirror. 82 83 ''' 84 # Initialize input data 85 self.Wedge = float(Wedge) 86 self.Alpha = float(Alpha) 87 Theta = float(Theta) 88 Phi = float(Phi) 89 Diameter = float(Diameter) 90 Thickness = float(Thickness) 91 92 #prepare for mother initializer 93 HRNorm = np.array([np.sin(Theta)*np.cos(Phi), 94 np.sin(Theta) * np.sin(Phi), 95 np.cos(Theta)], dtype = np.float64) 96 97 HRCenter = np.array([X, Y, Z], dtype = np.float64) 98 99 #Calculate ARCenter and ARNorm with wedge and alpha and thickness: 100 ARCenter = HRCenter\ 101 - (Thickness + .5*np.tan(self.Wedge)*Diameter)*HRNorm 102 103 a,b = geometry.basis(HRNorm) 104 ARNorm = -np.cos(self.Wedge) * HRNorm\ 105 + np.sin(self.Wedge)*(np.cos(self.Alpha) * a\ 106 + np.sin(self.Alpha) * b) 107 108 super(Mirror, self).__init__(ARCenter = ARCenter, ARNorm = ARNorm, 109 N = N, HRK = HRK, ARK = ARK, ARr = ARr, ARt = ARt, HRr = HRr, HRt = HRt, 110 KeepI = KeepI, HRCenter = [X, Y, Z], HRNorm = HRNorm, 111 Thickness = Thickness, Diameter = Diameter, Name = Name, Ref = Ref) 112 113 #Warnings for console output 114 if settings.warning: 115 self.geoCheck("mirror")
116
117 - def lines(self):
118 '''Returns the list of lines necessary to print the object. 119 ''' 120 ans = [] 121 ans.append("Mirror: " + self.Name + " (" + str(self.Ref) + ") {") 122 ans.append("Thick: " + str(self.Thick/cm) + "cm") 123 ans.append("Diameter: " + str(self.Dia/cm) + "cm") 124 ans.append("Wedge: " + str(self.Wedge/deg) + "deg") 125 ans.append("Alpha: " + str(self.Alpha/deg) + "deg") 126 ans.append("HRCenter: " + str(self.HRCenter)) 127 sph = geometry.rectToSph(self.HRNorm) 128 ans.append("HRNorm: (" + str(sph[0]/deg) + ', ' \ 129 + str(sph[1]/deg) + ')deg') 130 ans.append("Index: " + str(self.N)) 131 ans.append("HRKurv, ARKurv: " + str(self.HRK) + ", " + str(self.ARK)) 132 ans.append("HRr, HRt, ARr, ARt: " +str(self.HRr) + ", " + str(self.HRt)\ 133 + ", " + str(self.ARr) + ", " + str(self.ARt) ) 134 ans.append("}") 135 136 return ans
137
138 - def isHit(self, beam):
139 '''Determine if a beam hits the Optic. 140 141 This is a function for mirrors, using their geometrical 142 attributes. This uses the line***Inter functions from the geometry 143 module to find characteristics of impact of beams on mirrors. 144 145 beam: incoming beam. [GaussianBeam] 146 147 Returns a dictionary with keys: 148 'isHit': whether the beam hits the optic. [boolean] 149 'intersection point': point in space where it is first hit. 150 [3D vector] 151 'face': to indicate which face is first hit, can be 'HR', 'AR' or 152 'side'. [string] 153 'distance': geometrical distance from beam origin to impact. [float] 154 155 ''' 156 noInterDict = {'isHit': False, 157 'intersection point': np.array([0., 0., 0.], 158 dtype=np.float64), 159 'face': None, 160 'distance': 0.} 161 162 # get impact parameters on HR, AR and side: 163 if np.abs(self.HRK) > 0.: 164 HRDict = geometry.lineSurfInter(beam.Pos, 165 beam.Dir, self.HRCenter, 166 self.HRK*self.HRNorm/np.abs(self.HRK), 167 np.abs(self.HRK), 168 self.Dia) 169 else: 170 HRDict = geometry.linePlaneInter(beam.Pos, beam.Dir, self.HRCenter, 171 self.HRNorm, self.Dia) 172 173 if np.abs(self.ARK) > 0.: 174 ARDict = geometry.lineSurfInter(beam.Pos, 175 beam.Dir, self.ARCenter, 176 self.ARK*self.ARNorm/np.abs(self.ARK), 177 np.abs(self.ARK), 178 self.Dia/np.cos(self.Wedge)) 179 else: 180 ARDict = geometry.linePlaneInter(beam.Pos, beam.Dir, self.ARCenter, 181 self.ARNorm, self.Dia) 182 183 SideDict = geometry.lineCylInter(beam.Pos, beam.Dir, 184 self.HRCenter, self.HRNorm, 185 self.Thick, self.Dia) 186 187 # face tags 188 HRDict['face'] = 'HR' 189 ARDict['face'] = 'AR' 190 SideDict['face'] = 'Side' 191 192 # determine first hit 193 hitFaces = filter(lambda dic: dic['isHit'], [HRDict, ARDict, SideDict]) 194 195 if len(hitFaces) == 0: 196 return noInterDict 197 198 dist = hitFaces[0]['distance'] 199 j=0 200 201 for i in range(len(hitFaces)): 202 if hitFaces[i]['distance'] < dist: 203 dist = hitFaces[i]['distance'] 204 j=i 205 206 return {'isHit': True, 207 'intersection point': hitFaces[j]['intersection point'], 208 'face': hitFaces[j]['face'], 209 'distance': hitFaces[j]['distance'] 210 }
211
212 - def hit(self, beam, order, threshold):
213 '''Compute the refracted and reflected beams after interaction. 214 215 The beams returned are those selected after the order and threshold 216 criterion. 217 218 beam: incident beam. [GaussianBeam] 219 order: maximum strayness of daughter beams, whixh are not returned if 220 their strayness is over this order. [integer] 221 threshold: idem for the power of the daughter beams. [float] 222 223 Returns a dictionary of beams with keys: 224 't': refracted beam. [GaussianBeam] 225 'r': reflected beam. [GaussianBeam] 226 227 ''' 228 # get impact parameters and update beam 229 dic = self.isHit(beam) 230 beam.Length = dic['distance'] 231 beam.OptDist = beam.N * beam.Length 232 233 if dic['face'] == 'HR': 234 return self.hitHR(beam, dic['intersection point'], order, threshold) 235 elif dic['face'] == 'AR': 236 return self.hitAR(beam, dic['intersection point'], order, threshold) 237 else: 238 return self.hitSide(beam)
239
240 - def hitHR(self, beam, point, order, threshold):
241 '''Compute the daughter beams after interaction on HR at point. 242 243 beam: incident beam. [GaussianBeam] 244 point: point in space of interaction. [3D vector] 245 order: maximum strayness of daughter beams, whixh are not returned if 246 their strayness is over this order. [integer] 247 threshold: idem for the power of the daughter beams. [float] 248 249 Returns a dictionary of beams with keys: 250 't': refracted beam. [GaussianBeam] 251 'r': reflected beam. [GaussianBeam] 252 253 ''' 254 255 ans = {} 256 d = np.linalg.norm(point - beam.Pos) 257 # Calculate the local normal in opposite direction 258 if self.HRK == 0.: 259 localNorm = self.HRNorm 260 else: 261 try: 262 theta = np.arcsin(self.Dia * self.HRK/2.) #undertending angle 263 except FloatingPointError: 264 theta = pi/2. 265 266 sphereC = self.HRCenter + np.cos(theta)*self.HRNorm/self.HRK 267 localNorm = sphereC - point 268 localNorm = localNorm/np.linalg.norm(localNorm) 269 270 if np.dot(beam.Dir, localNorm) > 0.: 271 localNorm = - localNorm 272 K = np.abs(self.HRK) 273 else: 274 K = -np.abs(self.HRK) 275 276 # determine whether we're entering or exiting the substrate 277 if np.dot(beam.Dir, self.HRNorm) < 0.: 278 #entering 279 n1 = beam.N 280 n2 = self.N 281 else: 282 #exiting 283 n1 = self.N 284 n2 = 1. 285 286 # daughter directions 287 dir2 = geometry.newDir(beam.Dir, localNorm, n1, n2) 288 289 #warn on total reflection 290 if dir2['TR'] and settings.info: 291 print "theia: Info: Total reflection of " + beam.Ref + ' on HR of'\ 292 + self.Name + " (" + self.Ref + ")." 293 294 # if there is no refracted 295 if beam.P * self.HRt < threshold or beam.StrayOrder + 1 > order\ 296 or dir2['t'] is None: 297 ans['t'] = None 298 299 # if there is no reflected 300 if beam.P * self.HRr < threshold: 301 ans['r'] = None 302 303 # we're done if there are two Nones 304 if len(ans) == 2: 305 if settings.info: 306 print "theia: Info: Reached leaf of tree by interaction ("\ 307 + beam.Ref + " on " + self.Ref + ', ' + 'HR).' 308 return ans 309 310 # Calculate new basis 311 if not 'r' in ans: # for reflected 312 Uxr, Uyr = geometry.basis(dir2['r']) 313 Uzr = dir2['r'] 314 315 if not 't' in ans: # for refracted 316 Uxt, Uyt = geometry.basis(dir2['t']) 317 Uzt = dir2['t'] 318 319 Lx, Ly = geometry.basis(localNorm) 320 321 # Calculate daughter curv tensors 322 C = np.array([[K, 0.], [0, K]]) 323 Ki = np.array([[np.dot(beam.U[0], Lx), np.dot(beam.U[0], Ly)], 324 [np.dot(beam.U[1], Lx), np.dot(beam.U[1], Ly)]]) 325 Qi = beam.Q(d) 326 Kit = np.transpose(Ki) 327 Xi = np.matmul(np.matmul(Kit, Qi), Ki) 328 329 if not 't' in ans: 330 Kt = np.array([[np.dot(Uxt, Lx), np.dot(Uxt, Ly)], 331 [np.dot(Uyt, Lx), np.dot(Uyt, Ly)]]) 332 Ktt = np.transpose(Kt) 333 Ktinv = np.linalg.inv(Kt) 334 Kttinv = np.linalg.inv(Ktt) 335 Xt = (np.dot(localNorm, beam.Dir) -n2*np.dot(localNorm, Uzt)/n1) * C 336 Qt = n1*np.matmul(np.matmul(Kttinv, Xi - Xt), Ktinv)/n2 337 338 if not 'r' in ans: 339 Kr = np.array([[np.dot(Uxr, Lx), np.dot(Uxr, Ly)], 340 [np.dot(Uyr, Lx), np.dot(Uyr, Ly)]]) 341 Krt = np.transpose(Kr) 342 Krinv = np.linalg.inv(Kr) 343 Krtinv = np.linalg.inv(Krt) 344 Xr = (np.dot(localNorm, beam.Dir) - np.dot(localNorm, Uzr)) * C 345 Qr = np.matmul(np.matmul(Krtinv, Xi - Xr), Krinv) 346 347 # Create new beams 348 if not 'r' in ans: 349 ans['r'] = GaussianBeam(Q = Qr, 350 Pos = point, Dir = Uzr, Ux = Uxr, Uy = Uyr, 351 N = n1, Wl = beam.Wl, P = beam.P * self.HRr, 352 StrayOrder = beam.StrayOrder, Ref = beam.Ref + 'r', 353 Optic = self.Ref, Face = 'HR', Name = "Beam", 354 Length = 0., OptDist = 0.) 355 356 if not 't' in ans: 357 ans['t'] = GaussianBeam(Q = Qt, Pos = point, Name = "Beam", 358 Dir = Uzt, Ux = Uxt, Uy = Uyt, N = n2, Wl = beam.Wl, 359 P = beam.P * self.HRt, StrayOrder = beam.StrayOrder + 1, 360 Ref = beam.Ref + 't', Optic = self.Ref, Face = 'HR', 361 Length = 0., OptDist = 0.) 362 363 return ans
364
365 - def hitAR(self, beam, point, order, threshold):
366 '''Compute the daughter beams after interaction on AR at point. 367 368 beam: incident beam. [GaussianBeam] 369 point: point in space of interaction. [3D vector] 370 order: maximum strayness of daughter beams, which are not returned if 371 their strayness is over this order. [integer] 372 threshold: idem for the power of the daughter beams. [float] 373 374 Returns a dictionary of beams with keys: 375 't': refracted beam. [GaussianBeam] 376 'r': reflected beam. [GaussianBeam] 377 378 ''' 379 380 ans = {} 381 d = np.linalg.norm(point - beam.Pos) 382 # Calculate the local normal 383 if self.ARK == 0.: 384 localNorm = self.ARNorm 385 else: 386 try: 387 theta = np.arcsin(self.Dia * self.ARK/2.) #undertending angle 388 except FloatingPointError: 389 theta = pi/2. 390 sphereC = self.ARCenter + np.cos(theta)*self.ARNorm/self.ARK 391 localNorm = sphereC - point 392 localNorm = localNorm/np.linalg.norm(localNorm) 393 394 if np.dot(beam.Dir, localNorm) > 0.: 395 localNorm = - localNorm 396 K = np.abs(self.ARK) 397 else: 398 K = - np.abs(self.ARK) 399 # determine whether we're entering or exiting the substrate 400 if np.dot(beam.Dir, self.ARNorm) < 0.: 401 #entering 402 n1 = beam.N 403 n2 = self.N 404 else: 405 #exiting 406 n1 = self.N 407 n2 = 1. 408 409 # daughter directions 410 dir2 = geometry.newDir(beam.Dir, localNorm, n1, n2) 411 412 #warn on total reflection 413 if dir2['TR'] and settings.info: 414 print "theia: Info: Total reflection of " + beam.Ref + ' on AR of'\ 415 + self.Name + " (" + self.Ref + ")." 416 417 # if there is no refracted 418 if beam.P * self.ARt < threshold or dir2['t'] is None: 419 ans['t'] = None 420 421 # if there is no reflected 422 if beam.P * self.ARr < threshold or beam.StrayOrder + 1 > order: 423 ans['r'] = None 424 425 # we're done if there are two Nones 426 if len(ans) == 2: 427 if settings.info: 428 print "theia: Info: Reached leaf of tree by interaction ("\ 429 + beam.Ref + " on " + self.Ref + ', ' + 'AR).' 430 return ans 431 432 # Calculate new basis 433 if not 'r' in ans: # for reflected 434 Uxr, Uyr = geometry.basis(dir2['r']) 435 Uzr = dir2['r'] 436 437 if not 't' in ans: # for refracted 438 Uxt, Uyt = geometry.basis(dir2['t']) 439 Uzt = dir2['t'] 440 441 Lx, Ly = geometry.basis(localNorm) 442 443 # Calculate daughter curv tensors 444 C = np.array([[K, 0.], [0, K]]) 445 Ki = np.array([[np.dot(beam.U[0], Lx), np.dot(beam.U[0], Ly)], 446 [np.dot(beam.U[1], Lx), np.dot(beam.U[1], Ly)]]) 447 Qi = beam.Q(d) 448 Kit = np.transpose(Ki) 449 Xi = np.matmul(np.matmul(Kit, Qi), Ki) 450 451 if not 't' in ans: 452 Kt = np.array([[np.dot(Uxt, Lx), np.dot(Uxt, Ly)], 453 [np.dot(Uyt, Lx), np.dot(Uyt, Ly)]]) 454 Ktt = np.transpose(Kt) 455 Ktinv = np.linalg.inv(Kt) 456 Kttinv = np.linalg.inv(Ktt) 457 Xt = (np.dot(localNorm, beam.Dir) -n2*np.dot(localNorm, Uzt)/n1) * C 458 Qt = n1*np.matmul(np.matmul(Kttinv, Xi - Xt), Ktinv)/n2 459 460 if not 'r' in ans: 461 Kr = np.array([[np.dot(Uxr, Lx), np.dot(Uxr, Ly)], 462 [np.dot(Uyr, Lx), np.dot(Uyr, Ly)]]) 463 Krt = np.transpose(Kr) 464 Krinv = np.linalg.inv(Kr) 465 Krtinv = np.linalg.inv(Krt) 466 Xr = (np.dot(localNorm, beam.Dir) - np.dot(localNorm, Uzr)) * C 467 Qr = np.matmul(np.matmul(Krtinv, Xi - Xr), Krinv) 468 469 # Create new beams 470 if not 'r' in ans: 471 ans['r'] = GaussianBeam(Q = Qr, Name = "Beam", 472 Pos = point, Dir = Uzr, Ux = Uxr, Uy = Uyr, 473 N = n1, Wl = beam.Wl, P = beam.P * self.ARr, 474 StrayOrder = beam.StrayOrder + 1, Ref = beam.Ref + 'r', 475 Optic = self.Ref, Face = 'AR', 476 Length = 0., OptDist = 0.) 477 478 if not 't' in ans: 479 ans['t'] = GaussianBeam(Q = Qt, Pos = point, 480 Dir = Uzt, Ux = Uxt, Uy = Uyt, N = n2, Wl = beam.Wl, 481 P = beam.P * self.ARt, StrayOrder = beam.StrayOrder, 482 Ref = beam.Ref + 't', Optic = self.Ref, Face = 'AR', 483 Length = 0., OptDist =0., Name = "Beam") 484 485 return ans
486