1 '''Defines the Lens class for theia.'''
2
3
4
5
6
7
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
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 '''
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
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
108 HRDict['face'] = 'HR'
109 ARDict['face'] = 'AR'
110 SideDict['face'] = 'Side'
111
112
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
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
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
193 if K == 0.:
194 localNorm = Norm
195 else:
196 try:
197 theta = np.arcsin(self.Dia * K/2.)
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
211 if np.dot(beam.Dir, Norm) < 0.:
212
213 n1 = beam.N
214 n2 = self.N
215 else:
216
217 n1 = self.N
218 n2 = 1.
219
220
221 dir2 = geometry.newDir(beam.Dir, localNorm, n1, n2)
222
223
224 if dir2['TR'] and settings.info:
225 print "theia: Info: Total reflection of " + beam.Ref + ' on '\
226 + faceTag +' of '\
227 + self.Name + " (" + self.Ref + ")."
228
229
230 if beam.P * self.HRt < threshold or dir2['t'] is None:
231 ans['t'] = None
232
233
234 if beam.P * self.HRr < threshold or beam.StrayOrder + 1 > order :
235 ans['r'] = None
236
237
238 if len(ans) == 2:
239 if settings.info:
240 print "theia: Info: Reached leaf of tree by interaction ("\
241 + beam.Ref + " on " + self.Ref + ', ' + faceTag + ').'
242 return ans
243
244
245 if not 'r' in ans:
246 Uxr, Uyr = geometry.basis(dir2['r'])
247 Uzr = dir2['r']
248
249 if not 't' in ans:
250 Uxt, Uyt = geometry.basis(dir2['t'])
251 Uzt = dir2['t']
252
253 Lx, Ly = geometry.basis(localNorm)
254
255
256 C = np.array([[K, 0.], [0, K]])
257 Ki = np.array([[np.dot(beam.U[0], Lx), np.dot(beam.U[0], Ly)],
258 [np.dot(beam.U[1], Lx), np.dot(beam.U[1], Ly)]])
259 Qi = beam.Q(d)
260 Kit = np.transpose(Ki)
261 Xi = np.matmul(np.matmul(Kit, Qi), Ki)
262
263 if not 't' in ans:
264 Kt = np.array([[np.dot(Uxt, Lx), np.dot(Uxt, Ly)],
265 [np.dot(Uyt, Lx), np.dot(Uyt, Ly)]])
266 Ktt = np.transpose(Kt)
267 Ktinv = np.linalg.inv(Kt)
268 Kttinv = np.linalg.inv(Ktt)
269 Xt = (np.dot(localNorm, beam.Dir) -n2*np.dot(localNorm, Uzt)/n1) * C
270 Qt = n1*np.matmul(np.matmul(Kttinv, Xi - Xt), Ktinv)/n2
271
272 if not 'r' in ans:
273 Kr = np.array([[np.dot(Uxr, Lx), np.dot(Uxr, Ly)],
274 [np.dot(Uyr, Lx), np.dot(Uyr, Ly)]])
275 Krt = np.transpose(Kr)
276 Krinv = np.linalg.inv(Kr)
277 Krtinv = np.linalg.inv(Krt)
278 Xr = (np.dot(localNorm, beam.Dir) - np.dot(localNorm, Uzr)) * C
279 Qr = np.matmul(np.matmul(Krtinv, Xi - Xr), Krinv)
280
281
282 if not 'r' in ans:
283 ans['r'] = GaussianBeam(Q = Qr,
284 Pos = point, Dir = Uzr, Ux = Uxr, Uy = Uyr,
285 N = n1, Wl = beam.Wl, P = beam.P * self.HRr,
286 StrayOrder = beam.StrayOrder + 1, Ref = beam.Ref + 'r',
287 Optic = self.Ref, Face = faceTag,
288 Length = 0., OptDist = 0.)
289
290 if not 't' in ans:
291 ans['t'] = GaussianBeam(Q = Qt, Pos = point,
292 Dir = Uzt, Ux = Uxt, Uy = Uyt, N = n2, Wl = beam.Wl,
293 P = beam.P * self.HRt, StrayOrder = beam.StrayOrder,
294 Ref = beam.Ref + 't', Optic = self.Ref, Face = faceTag,
295 Length = 0., OptDist = 0.)
296
297 return ans
298