source: trunk/Mars/msimreflector/MFresnelLens.cc@ 19614

Last change on this file since 19614 was 19614, checked in by tbretz, 5 years ago
Added comment
File size: 9.7 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of CheObs, the Modular Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appears in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Thomas Bretz, 6/2019 <mailto:tbretz@physik.rwth-aachen.de>
19!
20! Copyright: CheObs Software Development, 2000-2009
21!
22!
23\* ======================================================================== */
24
25//////////////////////////////////////////////////////////////////////////////
26//
27// MFresnelLens
28//
29//////////////////////////////////////////////////////////////////////////////
30#include "MFresnelLens.h"
31
32#include <fstream>
33#include <errno.h>
34
35#include "MQuaternion.h"
36
37#include "MLog.h"
38#include "MLogManip.h"
39
40ClassImp(MFresnelLens);
41
42using namespace std;
43
44// --------------------------------------------------------------------------
45//
46// Default constructor
47//
48MFresnelLens::MFresnelLens(const char *name, const char *title)
49{
50 fName = name ? name : "MFresnelLens";
51 fTitle = title ? title : "Parameter container storing a collection of several mirrors (reflector)";
52
53 fMaxR = 55/2.;
54}
55
56// --------------------------------------------------------------------------
57//
58// Return the total Area of all mirrors. Note, that it is recalculated
59// with any call.
60//
61Double_t MFresnelLens::GetA() const
62{
63 return fMaxR*fMaxR*TMath::Pi();
64}
65
66// --------------------------------------------------------------------------
67//
68// Check with a rough estimate whether a photon can hit the reflector.
69//
70Bool_t MFresnelLens::CanHit(const MQuaternion &p) const
71{
72 // p is given in the reflectory coordinate frame. This is meant as a
73 // fast check without lengthy calculations to omit all photons which
74 // cannot hit the reflector at all
75 return p.R2()<fMaxR*fMaxR;
76}
77
78struct Groove
79{
80 double fTheta;
81 double fPeakZ;
82
83 double fTanTheta;
84 double fTanTheta2[3];
85
86 Groove() { }
87 Groove(double theta, double z) : fTheta(theta), fPeakZ(z)
88 {
89 fTanTheta = tan(theta);
90
91 fTanTheta2[0] = fTanTheta*fTanTheta;
92 fTanTheta2[1] = fTanTheta*fTanTheta * fPeakZ;
93 fTanTheta2[2] = fTanTheta*fTanTheta * fPeakZ*fPeakZ;
94 }
95};
96
97double CalcIntersection(const MQuaternion &p, const MQuaternion &u, const Groove &g, const double &fThickness)
98{
99 // p is the position in the plane of the lens (px, py, 0, t)
100 // u is the direction of the photon (ux, uy, dz, dt)
101
102 // Assuming a cone with peak at z and opening angle theta
103
104 // Radius at distance z+dz from the tip and at distance r from the axis of the cone
105 // r = (z+dz) * tan(theta)
106
107 // Defining
108 // zc := z+dz
109
110 // Surface of the cone
111 // (X) ( tan(theta) * sin(phi) )
112 // (Y) = zc * ( tan(theta) * cos(phi) )
113 // (Z) ( 1 )
114
115 // Line
116 // (X) (u.x) (p.x)
117 // (Y) = dz * (u.y) + (p.y)
118 // (Z) (u.z) ( 0 )
119
120 // Equality
121 //
122 // X^2+Y^2 = r^2
123 //
124 // (dz*u.x+p.x)^2 + (dz*u.y+p.y)^2 = (z+dz)^2 * tan(theta)^2
125 //
126 // dz^2*ux^2 + px^2 + 2*dz*ux*px + dz^2*uy^2 + py^2 + 2*dz*uy*py = (z^2*tan(theta)^2 + dz^2*tan(theta)^2 + 2*z*dz*tan(theta)^2
127 //
128 // dz^2*(ux^2 + uy^2 - tan(theta)^2) + 2*dz*(ux*px + uy*py - z*tan(theta)^2) + (px^2+py^2 - z^2*tan(theta)^2) = 0
129
130 // t := tan(theta)
131 // a := ux^2 + uy^2 - t^2
132 // b/2 := ux*px + uy*py - z *t^2 := B
133 // c := px^2 + py^2 - z^2*t^2
134
135 // dz = [ -b +- sqrt(b^2 - 4*a*c) ] / [2*a]
136 // dz = [ -B +- sqrt(B^2 - a*c) ] / a
137
138 const double a = u.R2() - g.fTanTheta2[0];
139 const double B = u.XYvector()*p.XYvector() - g.fTanTheta2[1];
140 const double c = p.R2() - g.fTanTheta2[2];
141
142 const double B2 = B*B;
143 const double ac = a*c;
144
145 if (B2<ac)
146 return 0;
147
148 const double sqrtBac = sqrt(B2 - a*c);
149
150 if (a==0)
151 return 0;
152
153 const double dz[2] =
154 {
155 (sqrtBac+B) / a,
156 (sqrtBac-B) / a
157 };
158
159 // Only one dz[i] can be within the lens (due to geometrical reasons
160
161 if (dz[0]<0 && dz[0]>fThickness)
162 return dz[0];
163
164 if (dz[1]<0 && dz[1]>fThickness)
165 return dz[1];
166
167 return 0;
168}
169
170double CalcRefractiveIndex(double lambda)
171{
172 // https://refractiveindex.info/?shelf=organic&book=poly(methyl_methacrylate)&page=Szczurowski
173
174 // n^2-1=\frac{0.99654λ^2}{λ^2-0.00787}+\frac{0.18964λ^2}{λ^2-0.02191}+\frac{0.00411λ^2}{λ^2-3.85727}
175
176 const double l2 = lambda*lambda;
177
178 const double c0 = 0.99654/(1-0.00787e6/l2);
179 const double c1 = 0.18964/(1-0.02191e6/l2);
180 const double c2 = 0.00411/(1-3.85727e6/l2);
181
182 return sqrt(1+c0+c1+c2);
183}
184
185bool ApplyRefraction(MQuaternion &u, const TVector3 &n, const double &n1, const double &n2)
186{
187 // From: https://stackoverflow.com/questions/29758545/how-to-find-refraction-vector-from-incoming-vector-and-surface-normal
188 // Note that as a default u is supposed to be normalized such that z=1!
189
190 // u: incoming direction (normalized!)
191 // n: normal vector of surface (pointing back into the old medium?)
192 // n1: refractive index of old medium
193 // n2: refractive index of new medium
194
195 // V_refraction = r*V_incedence + (rc - sqrt(1- r^2 (1-c^2)))n
196 // r = n1/n2
197 // c = -n dot V_incedence.
198
199 // The vector should be normalized already
200 // u.NormalizeVector();
201
202 const double r = n2/n1;
203 const double c = n*u.fVectorPart;
204
205 const double rc = r*c;
206
207 const double R = 1 - r*r + rc*rc; // = 1 - (r*r*(1-c*c));
208
209 // What is this? Total reflection?
210 if (R<0)
211 return false;
212
213 const double v = rc + sqrt(R);
214
215 u.fVectorPart = r*u.fVectorPart - v*n;
216
217 return true;
218}
219
220Int_t MFresnelLens::ExecuteOptics(MQuaternion &p, MQuaternion &u, const Short_t &wavelength) const
221{
222 // Corsika Coordinates are in cm!
223
224 const double D = 54.92; // [cm] Diameter
225 const double F = 50.21; // [cm] focal length (see also MGeomCamFAMOUS!)
226
227 const double R = D/2; // [cm] radius of lens
228 const double w = 0.0100; // [cm] Width of a single groove
229 const double H = 0.25; // [cm] Thickness (from pdf)
230
231 // Focal length is given at this wavelength
232 const double n0 = CalcRefractiveIndex(546);
233
234 const double n = CalcRefractiveIndex(wavelength==0 ? 546 : wavelength);
235
236 // Ray has missed the lens
237 if (p.R()>R)
238 return -1;
239
240 const int nth = TMath::FloorNint(p.R()/w); // Ray will hit the nth groove
241
242 const double r0 = nth *w; // Lower radius of nth groove
243 const double r1 = (nth+1) *w; // Upper radius of nth groove
244 const double rc = (nth+0.5)*w; // Center of nth groove
245
246 // FIXME: Do we have to check the nth-1 and nth+1 groove as well?
247
248 // Angle of grooves
249 // https://shodhganga.inflibnet.ac.in/bitstream/10603/131007/13/09_chapter%202.pdf
250
251 // This might be a better reference (Figure 1 Variant 1)
252 // https://link.springer.com/article/10.3103/S0003701X13010064
253
254 // I suggest we just do the calculation ourselves (but we need to
255 // find out how our lens looks like)
256 // Not 100% sure, but I think we have SC943
257 // https://www.orafol.com/en/europe/products/optic-solutions/productlines#pl1
258
259 // From the web-page:
260 // Positive Fresnel Lenses ... are usually corrected for spherical aberration.
261
262 // Tim Niggemann:
263 // The surface of the lens follows the shape of a parabolic lens to compensate spherical aberration
264 // Draft angle: psi(r) = 3deg + r * 0.0473deg/mm
265
266 // sin(omega) = R / sqrt(R^2+f^2)
267 // tan(alpha) = sin(omega) / [ 1 - sqrt(n^2-sin(omega)^2) ]
268
269 const double so = rc / sqrt(rc*rc + F*F);
270 const double alpha = atan(so / (1-sqrt(n0*n0 - so*so))); // alpha<0
271
272 // theta peak_z
273 const Groove g(TMath::Pi()/2 + alpha, -r0*tan(alpha));
274
275 // Calculate the insersection between the ray and the cone and z between 0 and -H
276 const double dz = CalcIntersection(p, u, g, -H);
277
278 // No groove was hit
279 if (dz>=0)
280 return -1;
281
282 // Propagate to the hit point at z=dz (dz<0)
283 p.PropagateZ(u, dz);
284
285 // Check where the ray has hit
286 // If the ray has not hit within the right radius.. reject
287 if (p.R()<=r0 || p.R()>r1)
288 return -1;
289
290 // Normal vector of the surface at the hit point
291 // FIXME: Surface roughness?
292 TVector3 norm;;
293 norm.SetMagThetaPhi(1, alpha, p.XYvector().Phi());
294
295 // Apply refraction at lens entrance (change directional vector)
296 // FIXME: Surace roughness
297 if (!ApplyRefraction(u, norm, 1, n))
298 return -1;
299
300 // Propagate ray until bottom of lens
301 const double v = u.fRealPart; // c changes in the medium
302 u.fRealPart = n*v;
303 p.PropagateZ(u, -H);
304 u.fRealPart = v; // Set back to c
305
306 // Apply refraction at lens exit (change directional vector)
307 // Normal surface (bottom of lens)
308 // FIXME: Surace roughness
309 if (!ApplyRefraction(u, TVector3(0, 0, 1), n, 1))
310 return -1;
311
312 // To make this consistent with a mirror system,
313 // we now change our coordinate system
314 // Rays from the lens to the camera are up-going (positive sign)
315 u.fVectorPart.SetZ(-u.Z());
316
317 // In the datasheet, it looks as if F is calculated
318 // towards the center of the lens.
319 p.fVectorPart.SetZ(-H/2);
320
321 return nth; // Keep track of groove index
322}
Note: See TracBrowser for help on using the repository browser.