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