source: trunk/MagicSoft/Mars/msimreflector/MSimReflector.cc@ 9322

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