source: trunk/MagicSoft/Mars/msim/MPhotonEvent.cc@ 9435

Last change on this file since 9435 was 9349, checked in by tbretz, 16 years ago
*** empty log message ***
File size: 19.9 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, 12/2000 <mailto:tbretz@astro.uni-wuerzburg.de>
19! Author(s): Qi Zhe, 06/2007 <mailto:qizhe@astro.uni-wuerzburg.de>
20!
21! Copyright: CheObs Software Development, 2000-2009
22!
23!
24\* ======================================================================== */
25
26/////////////////////////////////////////////////////////////////////////////
27//
28// MPhotonEvent
29//
30// Storage container to store photon collections
31//
32// The class is designed to be extremely fast which is important taking into
33// account the extremely high number of photons. This has some impacts on
34// its handling.
35//
36// The list has to be kept consistent, i.e. without holes.
37//
38// There are two ways to achieve this:
39//
40// a) Use RemoveAt to remove an entry somewhere
41// b) Compress() the TClonesArray afterwards
42//
43// Compress is not the fastes, so there is an easier way.
44//
45// a) When you loop over the list and want to remove an entry copy all
46// following entry backward in the list, so that the hole will
47// be created at its end.
48// b) Call Shrink(n) with n the number of valid entries in your list.
49//
50// To loop over the TClonesArray you can use a TIter which has some
51// unnecessary overhead and therefore is slower than necessary.
52//
53// Since the list is kept consistent you can use a simple loop saving
54// a lot of CPU time taking into account the high number of calls to
55// TObjArrayIter::Next which you would create.
56//
57// Here is an example (how to remove every second entry)
58//
59// ---------------------------------------------------------------------
60//
61// Int_t cnt = 0;
62//
63// const Int_t num = event->GetNumPhotons();
64// for (Int_t idx=0; idx<num; idx++)
65// {
66// if (idx%2==0)
67// continue;
68//
69// MPhotonData *dat = (*event)[idx];
70//
71// (*event)[cnt++] = *dat;
72// }
73//
74// event->Shrink(cnt);
75//
76// ---------------------------------- or -------------------------------
77//
78// TClonesArray &arr = MPhotonEvent->GetArray();
79//
80// Int_t cnt = 0;
81//
82// const Int_t num = arr.GetEntriesFast();
83// for (Int_t idx=0; idx<num; idx++)
84// {
85// if (idx%2==0)
86// continue;
87//
88// MPhotonData *dat = static_cast<MPhotonData*>(arr.UncheckedAt(idx));
89//
90// *static_cast<MPhotonData*>(arr.UncheckedAt(cnt++)) = *dat;
91// }
92//
93// MPhotonEvent->Shrink(cnt);
94//
95// ---------------------------------------------------------------------
96//
97// The flag for a sorted array is for speed reasons not in all conditions
98// maintained automatically. Especially Add() doesn't reset it.
99//
100// So be sure that if you want to sort your array it is really sorted.
101//
102//
103// Version 1:
104// ----------
105// - First implementation
106//
107/////////////////////////////////////////////////////////////////////////////
108#include "MPhotonEvent.h"
109
110#include <fstream>
111#include <iostream>
112
113#include <TMarker.h>
114
115#include <MMath.h>
116
117#include "MArrayF.h"
118
119#include "MLog.h"
120#include "MLogManip.h"
121
122#include "MPhotonData.h"
123
124ClassImp(MPhotonEvent);
125
126using namespace std;
127
128// ==========================================================================
129
130class MyClonesArray : public TClonesArray
131{
132public:
133 TObject **FirstRef() { return fCont; }
134
135 // --------------------------------------------------------------------------
136 //
137 // This is an extremly optimized version of ExpandCreateFast. It only resets
138 // the marker for the last element (fLast) to n-1 and doen't change anything
139 // else. This implicitly assumes that the stored objects don't allocate
140 // memory. It does not necessarily mean that the slots after fLast
141 // are empty (set to 0). This is what is assumed in the TClonesArray.
142 // We also don't call Changed() because it would reset Sorted. If the
143 // array was sorted before it is also sorted now. You MUST make sure
144 // that you only set n in a range for which valid entries have been
145 // created before (e.g. by ExpandCreateFast).
146 //
147 void FastShrink(Int_t n)
148 {
149 fLast = n - 1;
150 }
151
152 // --------------------------------------------------------------------------
153 //
154 // This is a optimized (faster) version of Delete which deletes consequtive
155 // entries from index idx1 to idx2 (both included) and calls their
156 // destructor. Note that there is no range checking done!
157 //
158 void FastRemove(Int_t idx1, Int_t idx2)
159 {
160 // Remove object at index idx.
161
162 //if (!BoundsOk("RemoveAt", idx1)) return 0;
163 //if (!BoundsOk("RemoveAt", idx2)) return 0;
164
165 Long_t dtoronly = TObject::GetDtorOnly();
166
167 idx1 -= fLowerBound;
168 idx2 -= fLowerBound;
169
170 for (TObject **obj=fCont+idx1; obj<=fCont+idx2; obj++)
171 {
172 if (!*obj)
173 continue;
174
175 if ((*obj)->TestBit(kNotDeleted)) {
176 // Tell custom operator delete() not to delete space when
177 // object fCont[i] is deleted. Only destructors are called
178 // for this object.
179 TObject::SetDtorOnly(*obj);
180 delete *obj;
181 }
182
183 *obj = 0;
184 // recalculate array size
185 }
186 TObject::SetDtorOnly((void*)dtoronly);
187
188 if (idx1<=fLast && fLast<=idx2)
189 {
190 do {
191 fLast--;
192 } while (fLast >= 0 && fCont[fLast] == 0);
193 }
194
195 Changed();
196 }
197
198
199 //void SetSorted() { fSorted = kTRUE; }
200
201 // --------------------------------------------------------------------------
202 //
203 // This is an optimized version of Sort which doesn't check the
204 // IsSortable flag before. It only sorts the entries from 0
205 // to GetEntriesFast().
206 //
207 void UncheckedSort()
208 {
209 if (fSorted)
210 return;
211
212 const Int_t nentries = GetEntriesFast();
213 if (nentries <= 0)
214 return;
215
216 QSort(GetObjectRef(First()), fKeep->GetObjectRef(fKeep->First()),
217 0, TMath::Min(nentries, kMaxInt-fLowerBound));
218
219 fSorted = kTRUE;
220 }
221};
222
223// ==========================================================================
224
225// --------------------------------------------------------------------------
226//
227// Default constructor. It initializes all arrays with zero size.
228//
229MPhotonEvent::MPhotonEvent(const char *name, const char *title)
230 : fData("MPhotonData", 1)
231{
232 fName = name ? name : "MPhotonEvent";
233 fTitle = title ? title : "Corsika Event Data Information";
234
235 fData.SetBit(TClonesArray::kForgetBits);
236 fData.BypassStreamer(kFALSE);
237}
238
239// --------------------------------------------------------------------------
240//
241// This is an extremly optimized version of ExpandCreateFast. It only resets
242// the marker for the last element (fLast) to n-1 and doen't change anything
243// else. This has the advantage that the allocated memory is kept but only
244// valid entries are written to a file.
245//
246// If the array was sorted before it is also sorted now. You MUST make sure
247// that you only set n in a range for which valid entries have been
248// created before (e.g. by ExpandCreateFast).
249//
250Int_t MPhotonEvent::Shrink(Int_t n)
251{
252 /*
253 // The number of object written by the streamer is defined by
254 // GetEntriesFast(), i.e. this number must be shrinked to
255 // the real array size. We use RemoveAt instead of ExpandCreate
256 // because RemoveAt doesn't free memory. Thus in the next
257 // iteration it can be reused and doesn't need to be reallocated.
258 // Do not change this. It is optimized for execution speed
259 // for (int i=fData.GetSize()-1; i>=n; i--)
260 // fData.RemoveAt(i);
261 const Bool_t sorted = fData.IsSorted();
262
263 MyClonesArray &loc = static_cast<MyClonesArray&>(fData);
264
265 loc.FastRemove(n, fData.GetSize()-1);
266
267 // If it was sorted before it is also sorted now.
268 if (sorted)
269 loc.SetSorted();
270 */
271
272 // fData.ExpandCreateFast(n); // Just set fLast = n -1
273
274 // Just set fLast = n -1
275 static_cast<MyClonesArray&>(fData).FastShrink(n);
276 return fData.GetEntriesFast();
277}
278
279// --------------------------------------------------------------------------
280//
281// The resized the array. If it has to be increased in size it is done
282// with ExpandCreateFast. If it should be shrinked it is done with
283// ExpandCreateFast if n>fData.GetSize()/100 or n==0. This keeps the allocated
284// memory and just sets the marker for the last element in the array (fLast).
285//
286// If the allocated memory grew to huge we reset the allocated memory
287// by calling ExpandCreate(n) (frees the allocated storage for the
288// objects) and Expand(n) (frees the allocated memory for the list
289// of pointers to the objects)
290//
291// 100 hundred is an arbitrary number taking into account that todays
292// computers have a lot of memory and we don't want to free and allocate
293// new memory too often.
294//
295// In priciple there might be more clever methods to handle the memory.
296//
297void MPhotonEvent::Resize(Int_t n)
298{
299 if (n==0 || n*100>fData.GetSize())
300 fData.ExpandCreateFast(n); // Just set fLast = n -1
301 else
302 {
303 fData.ExpandCreate(n); // Free memory of allocated MPhotonData
304 fData.Expand(n); // Free memory of allocated pointers
305 }
306}
307
308// --------------------------------------------------------------------------
309//
310// If n is smaller than the current allocated array size a reference to
311// the n-th entry is returned, otherwise an entry at n is created
312// calling the default constructor. Note, that there is no range check
313// but it is not recommended to call this function with
314// n>fData.GetSize()
315//
316MPhotonData &MPhotonEvent::Add(Int_t n)
317{
318 // Do not modify this. It is optimized for execution
319 // speed and flexibility!
320 TObject *o = 0;
321 if (n<fData.GetSize() && fData.UncheckedAt(n))
322 {
323 o=fData.UncheckedAt(n);
324 static_cast<MyClonesArray&>(fData).FastShrink(n+1);
325 }
326 else
327 {
328 o=fData.New(n);
329 }
330 return static_cast<MPhotonData&>(*o);
331}
332
333// --------------------------------------------------------------------------
334//
335// Add a new photon (MPhtonData) at the end of the array.
336// In this case the default constructor of MPhotonData is called.
337//
338// A reference to the new object is returned.
339//
340MPhotonData &MPhotonEvent::Add()
341{
342 return Add(GetNumPhotons());
343}
344
345void MPhotonEvent::Sort(Bool_t force)
346{
347 if (force)
348 fData.UnSort();
349
350 static_cast<MyClonesArray&>(fData).UncheckedSort(); /*Sort(GetEntriesFast())*/
351}
352
353// --------------------------------------------------------------------------
354//
355// Get the i-th photon from the array. Not, for speed reasons there is no
356// range check so you are responsible that you do not excess the number
357// of photons (GetNumPhotons)
358//
359MPhotonData &MPhotonEvent::operator[](UInt_t idx)
360{
361 return *static_cast<MPhotonData*>(fData.UncheckedAt(idx));
362}
363
364// --------------------------------------------------------------------------
365//
366// Get the i-th photon from the array. Not, for speed reasons there is no
367// range check so you are responsible that you do not excess the number
368// of photons (GetNumPhotons)
369//
370const MPhotonData &MPhotonEvent::operator[](UInt_t idx) const
371{
372 return *static_cast<MPhotonData*>(fData.UncheckedAt(idx));
373}
374
375// --------------------------------------------------------------------------
376//
377// Return a pointer to the first photon if available.
378//
379MPhotonData *MPhotonEvent::GetFirst() const
380{
381 return fData.GetEntriesFast()==0 ? 0 : static_cast<MPhotonData*>(fData.First());
382}
383
384// --------------------------------------------------------------------------
385//
386// Return a pointer to the last photon if available.
387//
388MPhotonData *MPhotonEvent::GetLast() const
389{
390 return fData.GetEntriesFast()==0 ? 0 : static_cast<MPhotonData*>(fData.Last());
391}
392
393// --------------------------------------------------------------------------
394//
395// Return the number of "external" photons, i.e. which are not NightSky
396//
397Int_t MPhotonEvent::GetNumExternal() const
398{
399 Int_t n=0;
400
401 for (int i=0; i<GetNumPhotons(); i++)
402 if ((*this)[i].GetPrimary()!=MMcEvtBasic::kNightSky)
403 n++;
404
405 return n;
406}
407
408// --------------------------------------------------------------------------
409//
410// Return time of first photon, 0 if none in array.
411// Note: If you want this to be the earliest make sure that the array
412// is properly sorted.
413//
414Float_t MPhotonEvent::GetTimeFirst() const
415{
416 const MPhotonData *dat=GetFirst();
417 return dat ? dat->GetTime() : 0;
418}
419
420// --------------------------------------------------------------------------
421//
422// Return time of first photon, 0 if none in array.
423// Note: If you want this to be the latest make sure that the array
424// is properly sorted.
425//
426Float_t MPhotonEvent::GetTimeLast() const
427{
428 const MPhotonData *dat=GetLast();
429 return dat ? dat->GetTime() : 0;
430}
431
432// --------------------------------------------------------------------------
433//
434// Return the median devian from the median of all arrival times.
435// The median deviation is calculated using MMath::MedianDev.
436// It is the half width in which one sigma (~68%) of all times are
437// contained around the median.
438//
439Double_t MPhotonEvent::GetTimeMedianDev() const
440{
441 const UInt_t n = GetNumPhotons();
442
443 MArrayF arr(n);
444 for (UInt_t i=0; i<n; i++)
445 arr[i] = operator[](i).GetTime();
446
447 return MMath::MedianDev(n, arr.GetArray()/*, Double_t &med*/);
448}
449
450// --------------------------------------------------------------------------
451//
452// Read the Event section from the file
453//
454Int_t MPhotonEvent::ReadCorsikaEvt(istream &fin)
455{
456 Int_t n = 0;
457
458 // --- old I/O ---
459 // Read only + Reflector (no absorption)
460 // Muons: 1.06GB/115s = 9.2MB/s (100kEvs)
461 // Gammas: 1.57GB/275s = 5.7MB/s ( 1kEvs)
462
463 // Read only:
464 // Gammas: 1.57GB/158s = 9.9MB/s ( 1kEvs)
465 // Muons: 1.06GB/ 77s = 13.8MB/s (100kEvs)
466
467 // --- new I/O ---
468 // Read only (don't allocate storage space):
469 // Gammas: 1.57GB/143s = 11.0MB/s ( 1kEvs)
470 // Muons: 1.06GB/ 77s = 13.8MB/s (100kEvs)
471
472 // Read only in blocks (with storage allocation):
473 // Gammas: 1.57GB/28s = 56MB/s ( 1kEvs)
474 // Muons: 1.06GB/5.2s = 204MB/s (100kEvs)
475
476 // Read only in blocks (without storage allocation):
477 // similar to just copy
478
479 // Copy with cp
480 // 1.57GB/ 5s CPU
481 // 1.57GB/28s REAL
482 // 1.06GB/ 3s CPU
483 // 1.06GB/22s REAL
484
485 while (1)
486 {
487 // Stprage for one block
488 char c[273*4];
489
490 // Read the first four byte to check whether the next block
491 // doen't belong to the event anymore
492 fin.read(c, 4);
493 if (!fin)
494 return kFALSE;
495
496 // Check if the event is finished
497 if (!memcmp(c, "EVTE", 4))
498 break;
499
500 // Now read the rest of the data
501 fin.read(c+4, 272*4);
502
503 Float_t *ptr = reinterpret_cast<Float_t*>(c);
504 Float_t *end = ptr + 273;
505
506 // Loop over all sub-blocks (photons) in the block and if
507 // they contain valid data add them to the array
508 while (ptr<end)
509 {
510 // Get/Add the n-th entry from the array and
511 // fill it with the current 7 floats
512 const Int_t rc = Add(n).FillCorsika(ptr);
513 ptr += 7;
514
515 switch (rc)
516 {
517 case kCONTINUE: continue; // No data in this bunch... skip it.
518 case kERROR: return kERROR; // Error occured
519 //case kFALSE: return kFALSE; // End of stream
520 }
521
522 // This is a photon we would like to keep later.
523 // Increase the counter by one
524 n++;
525 }
526 }
527/*
528 while (1)
529 {
530 // Check the first four bytes
531 char c[4];
532 fin.read(c, 4);
533
534 // End of stream
535 if (!fin)
536 return kFALSE;
537
538 // Check if we found the end of the event
539 if (!memcmp(c, "EVTE", 4))
540 break;
541
542 // The first for byte contained data already --> go back
543 fin.seekg(-4, ios::cur);
544
545 // Do not modify this. It is optimized for execution
546 // speed and flexibility!
547 MPhotonData &ph = Add(n);
548 // It checks how many entries the lookup table has. If it has enough
549 // entries and the entry was already allocated, we can re-use it,
550 // otherwise we have to allocate it.
551
552 // Now we read a single cherenkov bunch. Note that for speed reason we have not
553 // called the constructor if the event was already constructed (virtual table
554 // set), consequently we must make sure that ReadCorsikaEvent does reset
555 // all data mebers no matter whether they are read or not.
556 const Int_t rc = ph.ReadCorsikaEvt(fin);
557
558 // Evaluate result from reading event
559 switch (rc)
560 {
561 case kCONTINUE: continue; // No data in this bunch... skip it.
562 case kFALSE: return kFALSE; // End of stream
563 case kERROR: return kERROR; // Error occured
564 }
565
566 // FIXME: If fNumPhotons!=1 add the photon more than once
567
568 // Now increase the number of entries which are kept,
569 // i.e. keep this photon(s)
570 n++;
571 }
572 */
573
574 Resize(n);
575 fData.UnSort();
576
577 SetReadyToSave();
578
579 //*fLog << all << "Number of photon bunches: " << fData.GetEntriesFast() << endl;
580 return kTRUE;
581}
582
583// --------------------------------------------------------------------------
584//
585Int_t MPhotonEvent::ReadRflEvt(std::istream &fin)
586{
587 Int_t n = 0;
588
589 while (1)
590 {
591 // Check the first four bytes
592 char c[13];
593 fin.read(c, 13);
594
595 // End of stream
596 if (!fin)
597 return kFALSE;
598
599 // Check if we found the end of the event
600 if (!memcmp(c, "\nEND---EVENT\n", 13))
601 break;
602
603 // The first for byte contained data already --> go back
604 fin.seekg(-13, ios::cur);
605
606 // Do not modify this. It is optimized for execution
607 // speed and flexibility!
608 //TObject *o = n<fData.GetSize() && fData.UncheckedAt(n) ? fData.UncheckedAt(n) : fData.New(n);
609
610 // Now we read a single cherenkov bunch
611 //const Int_t rc = static_cast<MPhotonData*>(o)->ReadRflEvt(fin);
612 const Int_t rc = Add(n).ReadRflEvt(fin);
613
614 // Evaluate result from reading event
615 switch (rc)
616 {
617 case kCONTINUE: continue; // No data in this bunch... skip it.
618 case kFALSE: return kFALSE; // End of stream
619 case kERROR: return kERROR; // Error occured
620 }
621
622 // Now increase the number of entries which are kept,
623 // i.e. keep this photon(s)
624 n++;
625 }
626
627 Shrink(n);
628
629 SetReadyToSave();
630
631 //*fLog << all << "Number of photon bunches: " << fData.GetEntriesFast() << endl;
632 return kTRUE;
633}
634
635// --------------------------------------------------------------------------
636//
637// Print the array
638//
639void MPhotonEvent::Print(Option_t *) const
640{
641 fData.Print();
642}
643
644// ------------------------------------------------------------------------
645//
646// You can call Draw() to add the photons to the current pad.
647// The photons are painted each tim ethe pad is updated.
648// Make sure that you use the right (world) coordinate system,
649// like created, eg. by the MHCamera histogram.
650//
651void MPhotonEvent::Paint(Option_t *)
652{
653 MPhotonData *ph=NULL;
654
655 TMarker m;
656 m.SetMarkerStyle(kFullDotMedium); // Gtypes.h
657
658 TIter Next(&fData);
659 while ((ph=(MPhotonData*)Next()))
660 {
661 m.SetX(ph->GetPosY()*10); // north
662 m.SetY(ph->GetPosX()*10); // east
663 m.Paint();
664 }
665}
Note: See TracBrowser for help on using the repository browser.