source: trunk/Mars/msimreflector/MSimReflector.cc@ 20105

Last change on this file since 20105 was 19586, checked in by tbretz, 5 years ago
Propagate the wavelength to the optics to allow for refraction calculation.
File size: 21.2 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, 1/2009 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: CheObs Software Development, 2000-2010
21!
22!
23\* ======================================================================== */
24
25//////////////////////////////////////////////////////////////////////////////
26//
27// MSimReflector
28//
29// fDetectorFrame is a radius in centimeter, defining a disk in the focal
30// plane around the focal point, in which photons are absorbed. If
31// fDetectorFrame<=0 the virtual HitFrame function of the camera
32// geometry container is used instead.
33//
34// fDetectorMargin is a margin (in mm) which is given to the
35// MGeomCam::HitDetector. It should define a margin around the area
36// defined in HitDetector on the focal plane in which photons are kept.
37// Usually this can be 0 because photons not hitting the detector are
38// obsolete except they can later be "moved" inside the detector, e.g.
39// if you use MSimPSF to emulate a PSF by moving photons randomly
40// on the focal plane. To switch off this check set detector margin to -1.
41//
42//////////////////////////////////////////////////////////////////////////////
43#include "MSimReflector.h"
44
45#include <TMath.h>
46#include <TRandom.h>
47
48#include "MGeomCam.h"
49
50#include "MLog.h"
51#include "MLogManip.h"
52
53#include "MParList.h"
54
55#include "MQuaternion.h"
56#include "MMirror.h"
57#include "MOptics.h"
58#include "MReflector.h"
59#include "MReflection.h"
60
61#include "MCorsikaEvtHeader.h"
62//#include "MCorsikaRunHeader.h"
63
64#include "MPhotonEvent.h"
65#include "MPhotonData.h"
66
67#include "MPointingPos.h"
68
69ClassImp(MSimReflector);
70
71using namespace std;
72
73// USEFUL CORSIKA OPTIONS:
74// NOCLONG
75
76// --------------------------------------------------------------------------
77//
78// Default Constructor.
79//
80MSimReflector::MSimReflector(const char* name, const char *title)
81 : fEvt(0), fMirror0(0), fMirror1(0), fMirror2(0), fMirror3(0),
82 fMirror4(0), /*fRunHeader(0),*/ fEvtHeader(0), fReflector(0),
83 fGeomCam(0), fPointing(0), fNameReflector("MReflector"),
84 fDetectorFrame(0), fDetectorMargin(0)
85{
86 fName = name ? name : "MSimReflector";
87 fTitle = title ? title : "Task to calculate reflection os a mirror";
88}
89
90// --------------------------------------------------------------------------
91//
92// Search for the necessary parameter containers.
93//
94Int_t MSimReflector::PreProcess(MParList *pList)
95{
96 fMirror0 = (MPhotonEvent*)pList->FindCreateObj("MPhotonEvent", "MirrorPlane0");
97 if (!fMirror0)
98 return kFALSE;
99 fMirror1 = (MPhotonEvent*)pList->FindCreateObj("MPhotonEvent", "MirrorPlane1");
100 if (!fMirror1)
101 return kFALSE;
102 fMirror2 = (MPhotonEvent*)pList->FindCreateObj("MPhotonEvent", "MirrorPlane2");
103 if (!fMirror2)
104 return kFALSE;
105 fMirror3 = (MPhotonEvent*)pList->FindCreateObj("MPhotonEvent", "MirrorPlane3");
106 if (!fMirror3)
107 return kFALSE;
108 fMirror4 = (MPhotonEvent*)pList->FindCreateObj("MPhotonEvent", "MirrorPlane4");
109 if (!fMirror4)
110 return kFALSE;
111
112 fReflector = (MOptics*)pList->FindObject(fNameReflector, "MOptics");
113 if (!fReflector)
114 {
115 *fLog << err << fNameReflector << " [MOptics] not found..." << endl;
116 return kFALSE;
117 }
118
119 if (!fReflector->IsValid())
120 {
121 *fLog << err << "ERROR - Optics '" << fNameReflector << "' invalid." << endl;
122 return kFALSE;
123 }
124
125 fGeomCam = (MGeomCam*)pList->FindObject(fNameGeomCam, "MGeomCam");
126 if (!fGeomCam)
127 {
128 if (!fNameGeomCam.IsNull())
129 *fLog << inf << fNameGeomCam << " [MGeomCam] not found..." << endl;
130
131 fGeomCam = (MGeomCam*)pList->FindObject("MGeomCam");
132 if (!fGeomCam)
133 {
134 *fLog << err << "MGeomCam not found... aborting." << endl;
135 return kFALSE;
136 }
137 }
138
139 fEvt = (MPhotonEvent*)pList->FindObject("MPhotonEvent");
140 if (!fEvt)
141 {
142 *fLog << err << "MPhotonEvent not found... aborting." << endl;
143 return kFALSE;
144 }
145 /*
146 fRunHeader = (MCorsikaRunHeader*)pList->FindObject("MCorsikaRunHeader");
147 if (!fRunHeader)
148 {
149 *fLog << err << "MCorsikaRunHeader not found... aborting." << endl;
150 return kFALSE;
151 }
152 */
153 fEvtHeader = (MCorsikaEvtHeader*)pList->FindObject("MCorsikaEvtHeader");
154 if (!fEvtHeader)
155 {
156 *fLog << err << "MCorsikaEvtHeader not found... aborting." << endl;
157 return kFALSE;
158 }
159
160 fPointing = (MPointingPos*)pList->FindObject(/*"PointingCorsika",*/ "MPointingPos");
161 if (!fPointing)
162 {
163 *fLog << err << "MPointingPos not found... aborting." << endl;
164 return kFALSE;
165 }
166
167 return kTRUE;
168}
169
170// --------------------------------------------------------------------------
171//
172// The main point of calculating the reflection is to determine the
173// coincidence point of the particle trajectory on the mirror surface.
174//
175// If the position and the trajectory of a particle is known it is enough
176// to calculate the z-value of coincidence. x and y are then well defined.
177//
178// Since the problem (mirror) has a rotational symmetry we only have to care
179// about the distance from the z-axis.
180//
181// Given:
182//
183// p: position vector of particle (z=0)
184// u: direction vector of particle
185// F: Focal distance of the mirror
186//
187// We define:
188//
189// q := (px, py )
190// v := (ux/uz, uy/uz)
191// r^2 := x^2 + y^2
192//
193//
194// Distance from z-axis:
195// ---------------------
196//
197// q' = q - z*v (z>0)
198//
199// Calculate distance r (|q|)
200//
201// r^2 = (px-z*ux)^2 + (py-z*uy)^2
202// r^2 = px^2+py^2 + z^2*(ux^2+uy^2) - 2*z*(px*ux+py*uy)
203// r^2 = |q|^2 + z^2*|v|^2 - 2*z* q*v
204//
205//
206// Spherical Mirror Surface: (distance of surface point from 0/0/0)
207// -------------------------
208//
209// Sphere: r^2 + z^2 = R^2 | Parabola: z = p*r^2
210// Mirror: r^2 + (z-R)^2 = R^2 | Mirror: z = p*r^2
211// |
212// Focal length: F=R/2 | Focal length: F = 1/4p
213// |
214// r^2 + (z-2*F)^2 = (2*F)^2 | z = r^2/4F
215// |
216// z = -sqrt(4*F*F - r*r) + 2*F |
217// z-2*F = -sqrt(4*F*F - r*r) |
218// (z-2*F)^2 = 4*F*F - r*r |
219// z^2-4*F*z+4*F^2 = 4*F*F - r*r (4F^2-r^2>0) | z - r^2/4F = 0
220// z^2-4*F*z+r^2 = 0
221//
222// Find the z for which our particle has the same distance from the z-axis
223// as the mirror surface.
224//
225// substitute r^2
226//
227//
228// Equation to solve:
229// ------------------
230//
231// z^2*(1+|v|^2) - 2*z*(2*F+q*v) + |q|^2 = 0 | z^2*|v|^2 - 2*z*(2*F+q*v) + |q|^2 = 0
232//
233// z = (-b +- sqrt(b*b - 4ac))/(2*a)
234//
235// a = 1+|v|^2 | a = |v|^2
236// b = - 2*b' with b' = 2*F+q*v | b = - 2*b' with b' = 2*F+q*v
237// c = |q|^2 | c = |q|^2
238// |
239//
240// substitute b := 2*b'
241//
242// z = (2*b' +- 2*sqrt(b'*b' - ac))/(2*a)
243// z = ( b' +- sqrt(b'*b' - ac))/a
244// z = (b'/a +- sqrt(b'*b' - ac))/a
245//
246// substitute f := b'/a
247//
248// z = f +- sqrt(f^2 - c/a)
249//
250// =======================================================================================
251//
252// After z of the incident point has been determined the position p is
253// propagated along u to the plane with z=z. Now it is checked if the
254// mirror was really hit (this is implemented in HasHit).
255// From the position on the surface and the mirrors curvature we can
256// now calculate the normal vector at the incident point.
257// This normal vector is smeared out with MMirror::PSF (basically a
258// random gaussian) and then the trajectory is reflected on the
259// resulting normal vector.
260//
261Bool_t MMirror::ExecuteReflection(MQuaternion &p, MQuaternion &u) const
262{
263 // If the z-componenet of the direction vector is normalized to 1
264 // the calculation of the incident points becomes very simple and
265 // the resulting z is just the z-coordinate of the incident point.
266 const TVector2 v(u.XYvector()/u.Z());
267 const TVector2 q(p.XYvector());
268
269 // Radius of curvature
270 const Double_t G = 2*fFocalLength;
271
272 // Find the incident point of the vector to the mirror
273 // u corresponds to downward going particles, thus we use -u here
274 const Double_t b = G - q*v;
275 const Double_t a = v.Mod2();
276 const Double_t c = q.Mod2();
277
278 // Solution for q spherical (a+1) (parabolic mirror (a) instead of (a+1))
279 const Double_t A = fShape ? a : a+1;
280
281 const Double_t f = b/A;
282 const Double_t g = c/A;
283
284 // Solution of second order polynomial (transformed: a>0)
285 // (The second solution can be omitted, it is the intersection
286 // with the upper part of the sphere)
287 const Double_t z = a==0 ? c/(2*b) : f - TMath::Sqrt(f*f - g);
288
289 // Move the photon along its trajectory to the x/y plane of the
290 // mirror's coordinate frame. Therefor stretch the vector
291 // until its z-component is the distance from the vector origin
292 // until the vector hits the mirror surface.
293 // p += z/u.Z()*u;
294 // p is at the mirror plane and we want to propagate back to the mirror surface
295 p.PropagateZ(u, z);
296
297 // MirrorShape: Now check if the photon really hit the mirror or just missed it
298 if (!HasHit(p))
299 return kFALSE;
300
301 // Get normal vector for reflection by calculating the derivatives
302 // of a the mirror's surface along x and y
303 const Double_t d = fShape ? G : TMath::Sqrt(G*G - p.R2());
304
305 // The solution for the normal vector is
306 // TVector3 n(-p.X()/d, -p.Y()/d, 1));
307 // Since the normal vector doesn't need to be of normal
308 // length we can avoid an obsolete division
309 TVector3 n(p.X(), p.Y(), -d);
310
311 if (fSigmaPSF>0)
312 n += SimPSF(n);
313
314 // Changes also the sign of the z-direction of flight
315 // This is faster giving identical results
316 u *= MReflection(n);
317 //u *= MReflection(p.X(), p.Y(), -d);
318
319 return kTRUE;
320}
321
322// --------------------------------------------------------------------------
323//
324// Converts the coordinates into the coordinate frame of the mirror.
325// Executes the reflection calling ExecuteReflection and converts
326// the coordinates back.
327// Depending on whether the mirror was hit kTRUE or kFALSE is returned.
328// It the mirror was not hit the result coordinates are wrong.
329//
330Bool_t MMirror::ExecuteMirror(MQuaternion &p, MQuaternion &u) const
331{
332 // Move the mirror to the point of origin and rotate the position into
333 // the individual mirrors coordinate frame.
334 // Rotate the direction vector into the mirror's coordinate frame
335 p -= fPos;
336 p *= fTilt;
337 u *= fTilt;
338
339 // Move the photon along its trajectory to the x/y plane of the
340 // mirror's coordinate frame. Therefor stretch the vector
341 // until its z-component vanishes.
342 //p -= p.Z()/u.Z()*u;
343
344 // p is at the reflector plane and we want to propagate back to the mirror plane
345 p.PropagateZ0(u);
346
347 // Now try to propagate the photon from the plane to the mirror
348 // and reflect its direction vector on the mirror.
349 if (!ExecuteReflection(p, u))
350 return kFALSE;
351
352 // Derotate from mirror coordinates and shift the photon back to
353 // reflector coordinates.
354 // Derotate the direction vector
355 u *= fTilt.Inverse();
356 p *= fTilt.Inverse();
357 p += fPos;
358
359 return kTRUE;
360}
361
362// Jeder Spiegel sollte eine Liste aller andern Spiegel in der
363// reihenfolge Ihrer Entfernung enthalten. Wir starten mit der Suche
364// immer beim zuletzt getroffenen Spiegel!
365//
366// --------------------------------------------------------------------------
367//
368// Loops over all mirrors of the reflector. After doing a rough check
369// whether the mirror can be hit at all the reflection is executed
370// calling the ExecuteMirror function of the mirrors.
371//
372// If a mirror was hit its index is returned, -1 otherwise.
373//
374// FIXME: Do to lopping over all mirrors for all photons this is the
375// most time consuming function in teh reflector simulation. By a more
376// intelligent way of finding the right mirror then just testing all
377// this could be accelerated a lot.
378//
379Int_t MReflector::ExecuteOptics(MQuaternion &p, MQuaternion &u, const Short_t &) const
380{
381 //static const TObjArray *arr = &((MMirror*)fMirrors[0])->fNeighbors;
382
383 // This way of access is somuch faster than the program is
384 // a few percent slower if accessed by UncheckedAt
385 const MMirror **s = GetFirstPtr();
386 const MMirror **e = s+GetNumMirrors();
387 //const MMirror **s = (const MMirror**)fMirrors.GetObjectRef(0);
388 //const MMirror **e = s+fMirrors.GetEntriesFast();
389 //const MMirror **s = (const MMirror**)arr->GetObjectRef(0);
390 //const MMirror **e = s+arr->GetEntriesFast();
391
392 // Loop over all mirrors
393 for (const MMirror **m=s; m<e; m++)
394 {
395 const MMirror &mirror = **m;
396
397 // FIXME: Can we speed up using lookup tables or
398 // indexed tables?
399
400 // MirrorShape: Check if this mirror can be hit at all
401 // This is to avoid time consuming calculation if there is no
402 // chance of a coincidence.
403 // FIXME: Inmprove search algorithm (2D Binary search?)
404 if (!mirror.CanHit(p))
405 continue;
406
407 // Make a local copy of position and direction which can be
408 // changed by ExecuteMirror.
409 MQuaternion q(p);
410 MQuaternion v(u);
411
412 // Check if this mirror is hit, and if it is hit return
413 // the reflected position and direction vector.
414 // If the mirror is missed we go on with the next mirror.
415 if (!mirror.ExecuteMirror(q, v))
416 continue;
417
418 // We hit a mirror. Restore the local copy of position and
419 // direction back into p und u.
420 p = q;
421 u = v;
422
423 //arr = &mirror->fNeighbors;
424
425 return m-s;
426 }
427
428 return -1;
429}
430
431// --------------------------------------------------------------------------
432//
433// Converts the photons into the telscope coordinate frame using the
434// pointing position from MPointingPos.
435//
436// Reflects all photons on all mirrors and stores the final photons on
437// the focal plane. Also intermediate photons are stored for debugging.
438//
439Int_t MSimReflector::Process()
440{
441 // Get arrays from event container
442 TClonesArray &arr = fEvt->GetArray();
443
444 // Because we knwo in advance what the maximum storage space could
445 // be we allocated it in advance (or shrink it if it was extremely
446 // huge before)
447 // Note, that the drawback is that an extremly large event
448 // will take about five times its storage space
449 // for a moment even if a lot from it is unused.
450 // It will be freed in the next step.
451 fMirror0->Resize(arr.GetEntriesFast()); // Free memory of allocated MPhotonData
452 fMirror2->Resize(arr.GetEntriesFast()); // Free memory of allocated MPhotonData
453 fMirror3->Resize(arr.GetEntriesFast()); // Free memory of allocated MPhotonData
454 fMirror4->Resize(arr.GetEntriesFast()); // Free memory of allocated MPhotonData
455
456 // Initialize mirror properties
457 const Double_t F = fGeomCam->GetCameraDist()*100; // Focal length [cm]
458
459 // Local sky coordinates (direction of telescope axis)
460 const Double_t zd = fPointing->GetZdRad(); // x==north
461 const Double_t az = fPointing->GetAzRad();
462
463 // Rotation matrix to derotate sky
464 // For the new coordinate system see the Wiki
465 TRotation rot; // The signs are positive because we align the incident point on ground to the telescope axis
466 rot.RotateZ( az); // Rotate point on ground to align it with the telescope axis
467 rot.RotateX(-zd); // tilt the point from ground to make it parallel to the mirror plane
468
469 // Now get the impact point from Corsikas output
470 const TVector3 impact(fEvtHeader->GetX(), fEvtHeader->GetY(), 0);
471
472 // Counter for number of total and final events
473 UInt_t cnt[6] = { 0, 0, 0, 0, 0, 0 };
474
475 const Int_t nentries = arr.GetEntriesFast();
476 for (Int_t idx=0; idx<nentries; idx++)
477 {
478 MPhotonData *dat = static_cast<MPhotonData*>(arr.UncheckedAt(idx));
479
480 // w is pointing away from the direction the photon comes from
481 // CORSIKA-orig: x(north), y(west), z(up), t(time)
482 // NOW: x(east), y(north), z(up), t(time)
483 MQuaternion p(dat->GetPosQ()); // z=0
484 MQuaternion w(dat->GetDirQ()); // z<0
485
486 // Shift the coordinate system to the telescope. Corsika's
487 // coordinate system is always w.r.t. to the particle axis
488 p -= impact;
489
490 // Rotate the coordinates into the reflector's coordinate system.
491 // It is assumed that the z-plane is parallel to the focal plane.
492 // (The reflector coordinate system is defined by the telescope orientation)
493 p *= rot;
494 w *= rot;
495
496 // ---> Simulate star-light!
497 // w.fVectorPart.SetXYZ(0.2/17, 0.2/17, -(1-TMath::Hypot(0.3, 0.2)/17));
498
499 // FIXME: Take refractive index into account!
500
501 // Now propagate the photon to the z-plane in the new coordinate system
502 p.PropagateZ0(w);
503
504 // Store new position and direction in the reflector's coordinate frame
505 dat->SetPosition(p);
506 dat->SetDirection(w);
507
508 (*fMirror0)[cnt[0]++] = *dat;
509 //*static_cast<MPhotonData*>(cpy0.UncheckedAt(cnt[0]++)) = *dat;
510
511 // Check if the photon has hit the camera housing and holding
512 if (fGeomCam->HitFrame(p, w, fDetectorFrame))
513 continue;
514
515 // FIXME: Do we really need this one??
516 //(*fMirror1)[cnt[1]++] = *dat;
517 //*static_cast<MPhotonData*>(cpy1.UncheckedAt(cnt[1]++)) = *dat;
518
519 // Check if the reflector can be hit at all
520 if (!fReflector->CanHit(p))
521 continue;
522
523 (*fMirror2)[cnt[2]++] = *dat;
524 //*static_cast<MPhotonData*>(cpy2.UncheckedAt(cnt[2]++)) = *dat;
525
526 // FIXME: Set refractive index to air at 2200m!
527
528 // Now execute the reflection of the photon on the mirrors' surfaces
529 const Int_t num = fReflector->ExecuteOptics(p, w, dat->GetWavelength());
530 if (num<0)
531 continue;
532
533 // Set new position and direction (w.r.t. to the reflector's coordinate system)
534 // Set also the index of the mirror which was hit as tag.
535 dat->SetTag(num);
536 dat->SetPosition(p);
537 dat->SetDirection(w);
538
539 // FTemme: As dat.fTag is later changed from mirror ID to pixel ID, here
540 // also dat.fMirrorTag is set to num:
541 dat->SetMirrorTag(num);
542
543 (*fMirror3)[cnt[3]++] = *dat;
544 //*static_cast<MPhotonData*>(cpy3.UncheckedAt(cnt[3]++)) = *dat;
545
546 // Propagate the photon along its trajectory to the focal plane z=F
547 p.PropagateZ(w, F);
548
549 // Store new position
550 dat->SetPosition(p);
551
552 (*fMirror4)[cnt[4]++] = *dat;
553 //*static_cast<MPhotonData*>(cpy4.UncheckedAt(cnt[4]++)) = *dat;
554
555 // FIXME: It make make sense to move this out of this class
556 // It is detector specific not reflector specific
557 // Discard all photons which definitly can not hit the detector surface
558 if (fDetectorMargin>=0 && !fGeomCam->HitDetector(p, fDetectorMargin))
559 continue;
560
561 // Copy this event to the next 'new' in the list
562 *static_cast<MPhotonData*>(arr.UncheckedAt(cnt[5]++)) = *dat;
563 }
564
565 // Now we shrink the array to a storable size (for details see
566 // MPhotonEvent::Shrink).
567 fMirror0->Shrink(cnt[0]);
568 //fMirror1->Shrink(cnt[1]);
569 fMirror2->Shrink(cnt[2]);
570 fMirror3->Shrink(cnt[3]);
571 fMirror4->Shrink(cnt[4]);
572 fEvt->Shrink(cnt[5]);
573
574 // Doesn't seem to be too time consuming. But we could also sort later!
575 // (after cones, inside the camera)
576 fEvt->Sort(kTRUE);
577
578 // FIXME FIXME FIXME: Set maxindex, first and last time.
579 // SetMaxIndex(fReflector->GetNumMirrors()-1)
580 // if (fEvt->GetNumPhotons())
581 // {
582 // SetTime(fEvt->GetFirst()->GetTime(), fEvt->GetLast()->GetTime());
583 // }
584
585 return kTRUE;
586}
587
588// --------------------------------------------------------------------------
589//
590// DetectorMargin: 0
591//
592Int_t MSimReflector::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
593{
594 Bool_t rc = kFALSE;
595 if (IsEnvDefined(env, prefix, "DetectorFrame", print))
596 {
597 rc = kTRUE;
598 fDetectorFrame = GetEnvValue(env, prefix, "DetectorFrame", 0);
599 }
600 if (IsEnvDefined(env, prefix, "DetectorMargin", print))
601 {
602 rc = kTRUE;
603 fDetectorMargin = GetEnvValue(env, prefix, "DetectorMargin", 0);
604 }
605
606 return rc;
607}
Note: See TracBrowser for help on using the repository browser.