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