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 %s on (%s, %s)." \
226 %(beam.Ref, self.Ref, faceTag)
227
228
229 if beam.P * self.HRt < threshold or dir2['t'] is None:
230 ans['t'] = None
231
232
233 if beam.P * self.HRr < threshold or beam.StrayOrder + 1 > order :
234 ans['r'] = None
235
236
237 if len(ans) == 2:
238 if settings.info:
239 print ("theia: Info: Reached leaf of tree by interaction "\
240 + "(%s on %s, %s).") %(beam.Ref, self.Ref, faceTag)
241 return ans
242
243
244 if not 'r' in ans:
245 Uxr, Uyr = geometry.basis(dir2['r'])
246 Uzr = dir2['r']
247
248 if not 't' in ans:
249 Uxt, Uyt = geometry.basis(dir2['t'])
250 Uzt = dir2['t']
251
252 Lx, Ly = geometry.basis(localNorm)
253
254
255 C = np.array([[K, 0.], [0, K]])
256 Ki = np.array([[np.dot(beam.U[0], Lx), np.dot(beam.U[0], Ly)],
257 [np.dot(beam.U[1], Lx), np.dot(beam.U[1], Ly)]])
258 Qi = beam.Q(d)
259 Kit = np.transpose(Ki)
260 Xi = np.dot(np.dot(Kit, Qi), Ki)
261
262 if not 't' in ans:
263 Kt = np.array([[np.dot(Uxt, Lx), np.dot(Uxt, Ly)],
264 [np.dot(Uyt, Lx), np.dot(Uyt, Ly)]])
265 Ktt = np.transpose(Kt)
266 Ktinv = np.linalg.inv(Kt)
267 Kttinv = np.linalg.inv(Ktt)
268 Xt = (np.dot(localNorm, beam.Dir) -n2*np.dot(localNorm, Uzt)/n1) * C
269 Qt = n1*np.dot(np.dot(Kttinv, Xi - Xt), Ktinv)/n2
270
271 if not 'r' in ans:
272 Kr = np.array([[np.dot(Uxr, Lx), np.dot(Uxr, Ly)],
273 [np.dot(Uyr, Lx), np.dot(Uyr, Ly)]])
274 Krt = np.transpose(Kr)
275 Krinv = np.linalg.inv(Kr)
276 Krtinv = np.linalg.inv(Krt)
277 Xr = (np.dot(localNorm, beam.Dir) - np.dot(localNorm, Uzr)) * C
278 Qr = np.dot(np.dot(Krtinv, Xi - Xr), Krinv)
279
280
281 if not 'r' in ans:
282 ans['r'] = GaussianBeam(Q = Qr,
283 Pos = point, Dir = Uzr, Ux = Uxr, Uy = Uyr,
284 N = n1, Wl = beam.Wl, P = beam.P * self.HRr,
285 StrayOrder = beam.StrayOrder + 1, Ref = beam.Ref + 'r',
286 Optic = self.Ref, Face = faceTag,
287 Length = 0., OptDist = 0.)
288
289 if not 't' in ans:
290 ans['t'] = GaussianBeam(Q = Qt, Pos = point,
291 Dir = Uzt, Ux = Uxt, Uy = Uyt, N = n2, Wl = beam.Wl,
292 P = beam.P * self.HRt, StrayOrder = beam.StrayOrder,
293 Ref = beam.Ref + 't', Optic = self.Ref, Face = faceTag,
294 Length = 0., OptDist = 0.)
295
296 return ans
297