1 '''Defines the Mirror class for theia.'''
2
3
4
5
6
7
8
9
10
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
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
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
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
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
117 if settings.warning:
118 self.geoCheck("mirror")
119
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
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
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
189 HRDict['face'] = 'HR'
190 ARDict['face'] = 'AR'
191 SideDict['face'] = 'Side'
192
193
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
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
259 if self.HRK == 0.:
260 localNorm = self.HRNorm
261 else:
262 try:
263 theta = np.arcsin(self.Dia * self.HRK/2.)
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
278 if np.dot(beam.Dir, self.HRNorm) < 0.:
279
280 n1 = beam.N
281 n2 = self.N
282 else:
283
284 n1 = self.N
285 n2 = 1.
286
287
288 dir2 = geometry.newDir(beam.Dir, localNorm, n1, n2)
289
290
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
296 if beam.P * self.HRt < threshold or beam.StrayOrder + 1 > order\
297 or dir2['t'] is None:
298 ans['t'] = None
299
300
301 if beam.P * self.HRr < threshold:
302 ans['r'] = None
303
304
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
312 if not 'r' in ans:
313 Uxr, Uyr = geometry.basis(dir2['r'])
314 Uzr = dir2['r']
315
316 if not 't' in ans:
317 Uxt, Uyt = geometry.basis(dir2['t'])
318 Uzt = dir2['t']
319
320 Lx, Ly = geometry.basis(localNorm)
321
322
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
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
384 if self.ARK == 0.:
385 localNorm = self.ARNorm
386 else:
387 try:
388 theta = np.arcsin(self.Dia * self.ARK/2.)
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
401 if np.dot(beam.Dir, self.ARNorm) < 0.:
402
403 n1 = beam.N
404 n2 = self.N
405 else:
406
407 n1 = self.N
408 n2 = 1.
409
410
411 dir2 = geometry.newDir(beam.Dir, localNorm, n1, n2)
412
413
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
419 if beam.P * self.ARt < threshold or dir2['t'] is None:
420 ans['t'] = None
421
422
423 if beam.P * self.ARr < threshold or beam.StrayOrder + 1 > order:
424 ans['r'] = None
425
426
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
434 if not 'r' in ans:
435 Uxr, Uyr = geometry.basis(dir2['r'])
436 Uzr = dir2['r']
437
438 if not 't' in ans:
439 Uxt, Uyt = geometry.basis(dir2['t'])
440 Uzt = dir2['t']
441
442 Lx, Ly = geometry.basis(localNorm)
443
444
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
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