NCFS-Pack
A generic (astro)particle physics analysis framework
 
Loading...
Searching...
No Matches
IceMakeHits.cxx
Go to the documentation of this file.
1
17
19
105
106#include "IceMakeHits.h"
107#include "Riostream.h"
108
109#include "TCanvas.h"
110
111ClassImp(IceMakeHits); // Class implementation to enable ROOT I/O
112
114IceMakeHits::IceMakeHits(const char* name,const char* title) : TTask(name,title)
115{
121
122 fEvt=0;
123 // Parameters for Amanda TWR hit extraction
124 fBasefracA=0.5;
125 fSigmaA=1.5;
126 fMaxPeaksA=10;
128 fThresholdA=0.2;
129 // Parameters for IceCube ATWD/FADC hit extraction
130 fBasefracI=0.5;
131 fSigmaI=1.+1.e-6;
132 fMaxPeaksI=100;
134 fMinPulseHeightI=1.e-12;
135 fThresholdI=0.2;
136 fUseNamesI=0;
137}
138
140{
146
147 if (fUseNamesI)
148 {
149 delete fUseNamesI;
150 fUseNamesI=0;
151 }
152}
153
155{
162
163 fBasefracA=val;
164}
165
166void IceMakeHits::SetSigmaA(Float_t val)
167{
174
175 fSigmaA=val;
176}
177
179{
186
187 fMaxPeaksA=val;
188}
189
191{
199
201}
202
204{
213
214 fThresholdA=val;
215}
216
218{
225
226 fBasefracI=val;
227}
228
229void IceMakeHits::SetSigmaI(Float_t val)
230{
237
238 fSigmaI=val;
239}
240
242{
249
250 fMaxPeaksI=val;
251}
252
254{
261
263}
264
266{
274
276}
277
279{
288
289 fThresholdI=val;
290}
291
292void IceMakeHits::SetWaveformNameI(const char* name)
293{
310
311 if (fUseNamesI)
312 {
313 delete fUseNamesI;
314 fUseNamesI=0;
315 }
316
317 TString s=name;
319}
320
322{
348
349 if (!fUseNamesI)
350 {
351 fUseNamesI=new TObjArray();
352 fUseNamesI->SetOwner();
353 }
354
355 // Check if this name (or pattern) has already been specified before.
356 // In case the new name pattern is more generic than matching existing ones
357 // it will replace these already existing patterns.
358 TString s;
359 Int_t nen=fUseNamesI->GetEntries();
360 for (Int_t i=0; i<nen; i++)
361 {
362 TObjString* sx=(TObjString*)fUseNamesI->At(i);
363 if (!sx) continue;
364 s=sx->GetString();
365
366 // Exact match or new name is less generic than existing one --> Keep existing one
367 if (name==s || name.Contains(s)) return;
368
369 // New name (pattern) is more generic than existing one --> Remove existing one
370 if (s.Contains(name))
371 {
372 sx=(TObjString*)fUseNamesI->RemoveAt(i);
373 if (sx) delete sx;
374 }
375 }
376
377 // New name (pattern) to be added into the storage
378 fUseNamesI->Compress();
379 nen=fUseNamesI->GetEntries();
380 if (nen >= fUseNamesI->GetSize()) fUseNamesI->Expand(nen+1);
381
382 TObjString* newname=new TObjString();
383 newname->SetString(name.Data());
384 fUseNamesI->Add(newname);
385}
386
388{
394
395 cout << " *IceMakeHits::PrintWaveformNamesI* InIce waveform names (or patterns) that will be analysed." << endl;
396 if (!fUseNamesI)
397 {
398 cout << " No name (pattern) has been specified." << endl;
399 }
400 else
401 {
402 TString s;
403 Int_t nen=fUseNamesI->GetEntries();
404 for (Int_t i=0; i<nen; i++)
405 {
406 TObjString* sx=(TObjString*)fUseNamesI->At(i);
407 if (!sx) continue;
408 s=sx->GetString();
409 cout << " " << s.Data() << endl;
410 }
411 }
412}
413
414void IceMakeHits::Exec(Option_t* opt)
415{
421
422 TString name=opt;
423 NcJob* parent=(NcJob*)(gROOT->GetListOfTasks()->FindObject(name.Data()));
424
425 if (!parent) return;
426
427 fEvt=(IceEvent*)parent->GetObject("IceEvent");
428 if (!fEvt) return;
429
430 // Only process accepted events
431 NcDevice* seldev=(NcDevice*)fEvt->GetDevice("NcEventSelector");
432 if (seldev)
433 {
434 if (seldev->GetSignal("Select") < 0.1) return;
435 }
436
437 // Storage of the used parameters in the IceMakeHits device
438 NcDevice params;
439 params.SetNameTitle("IceMakeHits","IceMakeHits processor parameters");
440
441 // Amanda hit extraction
442 params.AddNamedSlot("BasefracA");
443 params.AddNamedSlot("SigmaA");
444 params.AddNamedSlot("MaxPeaksA");
445 params.AddNamedSlot("MinPulseHeightA");
446 params.AddNamedSlot("ThresholdA");
447 params.SetSignal(fBasefracA,"BasefracA");
448 params.SetSignal(fSigmaA,"SigmaA");
449 params.SetSignal(fMaxPeaksA,"MaxPeaksA");
450 params.SetSignal(fMinPulseHeightA,"MinPulseHeightA");
451 params.SetSignal(fThresholdA,"ThresholdA");
452
453 // IceCube hit extraction
454 params.AddNamedSlot("BasefracI");
455 params.AddNamedSlot("SigmaI");
456 params.AddNamedSlot("MaxPeaksI");
457 params.AddNamedSlot("MinPulseHeightI");
458 params.AddNamedSlot("ThresholdI");
459 params.SetSignal(fBasefracI,"BasefracI");
460 params.SetSignal(fSigmaI,"SigmaI");
461 params.SetSignal(fMaxPeaksI,"MaxPeaksI");
462 params.SetSignal(fMinPulseHeightI,"MinPulseHeightI");
463 params.SetSignal(fThresholdI,"ThresholdI");
464
465 fEvt->AddDevice(params);
466
467 Int_t oldlevel=gErrorIgnoreLevel;
468 gErrorIgnoreLevel=kFatal; // Suppress all (NcSpectrum) error and warning messages
469
470 Amanda();
471 IceCube();
472// InIce();
473// DeepCore();
474// IceTop();
475
476 gErrorIgnoreLevel=oldlevel; // Re-activate previous info level
477
478}
479
481{
487
488 // All Amanda OMs with a signal
489 TObjArray* aoms=fEvt->GetDevices("IceAOM");
490 if (!aoms) return;
491
492 // Arrays for storing info
493 Float_t* baseline=new Float_t[fMaxPeaksA];
494 Int_t* lowend=new Int_t[fMaxPeaksA];
495 Int_t* upend=new Int_t[fMaxPeaksA];
496 Int_t* startcharge=new Int_t[fMaxPeaksA];
497 Int_t* stopcharge=new Int_t[fMaxPeaksA];
498 Int_t* status=new Int_t[fMaxPeaksA]; // 0=OK, 1=rejected, 2=saturation
499 Float_t* leadingedge=new Float_t[fMaxPeaksA];
500 Float_t* charge=new Float_t[fMaxPeaksA];
501 Float_t* tot=new Float_t[fMaxPeaksA];
502
503 // Some objects and variables we will need
504 TH1F htemp, diff;
506 Int_t nrIterations=(Int_t)(7*fSigmaA+0.5); // Number of iterations used in NcSpectrum::SearchHighRes()
507 Int_t npeaks=0, ibin=0, lookforsteepestuntilbin=0, steep=0;
508 Float_t maxval=0, rise=0, rc=0, yyy=0;
509 Bool_t pulsegoingon=false;
510 Int_t* index=new Int_t[fMaxPeaksA];
511
512 // OM, waveform and hit
513 IceAOM* omx=0;
514 TH1F* wf=0;
515 NcSignal hit;
516 hit.SetSlotName("ADC",1);
517 hit.SetSlotName("LE",2);
518 hit.SetSlotName("TOT",3);
519
520 // Loop over all fired OMs and extract the hit info
521 for (Int_t iom=0; iom<aoms->GetEntries(); iom++)
522 {
523 omx=(IceAOM*)aoms->At(iom);
524 if (!omx) continue;
525 // Remove all existing hits of this OM
526 omx->RemoveHits();
527 // Reset (de)calibration functions to indicate uncalibrated data
528 omx->SetCalFunction(0,"ADC");
529 omx->SetCalFunction(0,"LE");
530 omx->SetCalFunction(0,"TOT");
531 omx->SetDecalFunction(0,"ADC");
532 omx->SetDecalFunction(0,"LE");
533 omx->SetDecalFunction(0,"TOT");
534 // Should we skip OMs that we know from the dbase to have problems ?
535//@@ if (omx->GetDeadValue("ADC") || omx->GetDeadValue("LE") || omx->GetDeadValue("TOT")) continue;
536
537 // Investigate all waveforms for this OM
538 for (Int_t iwf=1; iwf<=omx->GetNwaveforms(); iwf++)
539 {
540 wf=omx->GetWaveform(iwf);
541 if (!wf) continue;
542 maxval=wf->GetMaximum();
543 // Check if clipping window is not too large
544 if(wf->GetNbinsX() > 2*nrIterations+1)
545 {
546 // Find peaks with NcSpectrum
547 npeaks=spec.Search(wf,fSigmaA,"goff");
548 // Discard waveform if no or too many peaks found
549 if(npeaks<1 || npeaks>fMaxPeaksA) continue;
550
551 // Get differential of WF
552 diff=*wf;
553 for(ibin=2;ibin<diff.GetNbinsX();ibin++)
554 {
555 diff.SetBinContent(ibin,wf->GetBinContent(ibin)-wf->GetBinContent(ibin-1));
556 }
557 diff.SetBinContent(1,0);
558 // Set baseline and lower end for first peak,
559 baseline[0]=0;
560 lowend[0]=1;
561
562 // Sort peaks in time
563 TMath::Sort(npeaks,spec.GetPositionX(),index,false);
564 // For each of the peaks,
565 for(Int_t ipeak=0; ipeak<npeaks; ipeak++)
566 {
567 // Find baseline and region around peak
568 htemp=*wf;
569 // (Second and later peaks: lower edge = upper edge previous peak,
570 // baseline is average of previous baseline and minimum value between two
571 // peaks)
572 if(ipeak>0)
573 {
574 lowend[ipeak]=upend[ipeak-1]+1;
575 baseline[ipeak]=fBasefracA*htemp.GetBinContent(lowend[ipeak]);
576 }
577 // (Upper edge range is minimum between this and next peak)
578 if(ipeak<npeaks-1)
579 {
580 htemp.SetAxisRange(spec.GetPositionX()[index[ipeak]],spec.GetPositionX()[index[ipeak+1]]);
581 upend[ipeak]=htemp.GetMinimumBin()-1;
582 }
583 // (Last peak: upper edge is end of histo)
584 else
585 {
586 upend[ipeak]=wf->GetNbinsX();
587 }
588 // Find steepest rise
589 lookforsteepestuntilbin=wf->FindBin(spec.GetPositionX()[index[ipeak]]);
590 htemp=diff;
591 // Look for steepest rise between lower edge and peak position
592 htemp.SetAxisRange(wf->GetBinCenter(lowend[ipeak]),wf->GetBinCenter(lookforsteepestuntilbin));
593 steep=htemp.GetMaximumBin();
594 rise=htemp.GetBinContent(steep);
595
596 // Extrapolate tangent to find leading edge
597 yyy=wf->GetBinContent(steep)-baseline[ipeak];
598 rc=rise/htemp.GetBinWidth(steep);
599 if(rc>0) leadingedge[ipeak]=wf->GetBinCenter(steep)-yyy/rc; else leadingedge[ipeak]=0;
600
601 // Determine peak status
602 status[ipeak]=0;
603 // Check for saturation
604 if(rc<0.1 && wf->GetBinContent(wf->FindBin(spec.GetPositionX()[index[ipeak]])) == maxval)
605 {
606 status[ipeak]=2;
607 }
608 // Check quality: LE should not be too far below lower edge
609 // Otherwise, ignore this peak and set baseline back to what it was
610 else if(wf->GetBinLowEdge(lowend[ipeak]) - leadingedge[ipeak] > spec.GetPositionX()[index[ipeak]] - wf->GetBinLowEdge(lowend[ipeak]))
611 {
612 status[ipeak]=1;
613 if(ipeak>0) baseline[ipeak]=baseline[ipeak-1];
614 }
615
616 // Start charge integration at LE, or at lower edge of range
617 startcharge[ipeak]=wf->FindBin(leadingedge[ipeak]);
618 if(lowend[ipeak]>startcharge[ipeak]) startcharge[ipeak]=lowend[ipeak];
619
620 // Integrate charge until pulse drop below baseline, or else until edge of range
621 stopcharge[ipeak]=upend[ipeak];
622 for(ibin=wf->FindBin(spec.GetPositionX()[index[ipeak]]); ibin<=upend[ipeak]; ibin++)
623 {
624 if(wf->GetBinContent(ibin)<0)
625 {
626 stopcharge[ipeak]=ibin-1;
627 break;
628 }
629 }
630
631 // Determine time over threshold
632 tot[ipeak]=wf->GetBinLowEdge(stopcharge[ipeak]+1)-wf->GetBinLowEdge(startcharge[ipeak]);
633
634 // Determine charge
635 charge[ipeak]=0;
636 for(ibin=startcharge[ipeak]; ibin<=stopcharge[ipeak]; ibin++)
637 {
638 charge[ipeak]+=wf->GetBinContent(ibin);
639 }
640
641 } // end loop over peaks
642
643 // Check all peaks, from latest to earliest
644 for(int ipeak=npeaks-1; ipeak>=0; ipeak--)
645 {
646
647 // If this peak was rejected, add charge and TOT to previous peak (if there is one)
648 if(status[ipeak]==1 && ipeak>0)
649 {
650 charge[ipeak-1]+=charge[ipeak];
651 charge[ipeak]=0;
652 tot[ipeak-1]+=tot[ipeak];
653 tot[ipeak]=0;
654 }
655
656 // If this peak is OK, add hit info
657 if(status[ipeak]==0)
658 {
659 hit.Reset();
660 hit.SetSignal(charge[ipeak],"ADC");
661 hit.SetSignal(leadingedge[ipeak],"LE");
662 hit.SetSignal(tot[ipeak],"TOT");
663 omx->AddHit(hit);
664 }
665
666 } // end loop over peaks
667 // If number of bins too small, use different method
668 }
669 else
670 {
671 // If maximum value high enough to suspect presence of peak,
672 if(maxval>fMinPulseHeightA)
673 {
674 // Loop over bins
675 pulsegoingon=false;
676 npeaks=0;
677 for(ibin=1; ibin<=wf->GetNbinsX(); ibin++)
678 {
679 // If bin content above threshold, start pulse
680 if(wf->GetBinContent(ibin)>fThresholdA*maxval){
681 if(!pulsegoingon)
682 {
683 // Pulse starts here
684 pulsegoingon=true;
685 leadingedge[npeaks]=wf->GetBinLowEdge(ibin);
686 charge[npeaks]=wf->GetBinContent(ibin);
687 }
688 else
689 {
690 // Pulse continues
691 charge[npeaks]+=wf->GetBinContent(ibin);
692 }
693 }
694 else
695 {
696 if(pulsegoingon)
697 {
698 // Pulse ends here
699 tot[npeaks]=wf->GetBinLowEdge(ibin)-leadingedge[npeaks];
700
701 // Store pulse information
702 hit.Reset();
703 hit.SetSignal(charge[npeaks],"ADC");
704 hit.SetSignal(leadingedge[npeaks],"LE");
705 hit.SetSignal(tot[npeaks],"TOT");
706 omx->AddHit(hit);
707
708 // Get ready for next pulse
709 pulsegoingon=false;
710 npeaks++;
711 }
712 }
713
714 } // End of loop over bins
715 }
716
717 } // End of alternative method for narrow pulses
718
719 } // End of WF loop
720 } // End of OM loop
721
722 // Clean up
723 delete[] baseline;
724 delete[] lowend;
725 delete[] upend;
726 delete[] startcharge;
727 delete[] stopcharge;
728 delete[] status;
729 delete[] leadingedge;
730 delete[] charge;
731 delete[] tot;
732 delete[] index;
733}
734
736{
742
743 // All IceCube (incl. IceTop) DOMs with a signal
744 TObjArray* idoms=fEvt->GetDevices("IceDOM");
745 if (!idoms) return;
746
747 // The number of different waveform names (or patterns) to be analysed
748 Int_t npatterns=0;
749 if (fUseNamesI) npatterns=fUseNamesI->GetEntries();
750
751
752 // Arrays for storing individual peak info
753 // Peak status indicator :
754 // 0=OK, 1=LE<peak window low edge, 2=saturation, 3=not high enough, 5=adjacent to later higher peak
755 Float_t* baseline=new Float_t[fMaxPeaksI];
756 Int_t* lowend=new Int_t[fMaxPeaksI];
757 Int_t* upend=new Int_t[fMaxPeaksI];
758 Int_t* startcharge=new Int_t[fMaxPeaksI];
759 Int_t* stopcharge=new Int_t[fMaxPeaksI];
760 Int_t* status=new Int_t[fMaxPeaksI];
761 Float_t* leadingedge=new Float_t[fMaxPeaksI];
762 Float_t* charge=new Float_t[fMaxPeaksI];
763 Float_t* tot=new Float_t[fMaxPeaksI];
764 Int_t* index=new Int_t[fMaxPeaksI];
765
766 // Some objects and variables we will need
767 TH1F htemp, diff;
769 spec.SetDeconIterations(50);
770 Int_t nrIterations=(Int_t)(7*fSigmaI+0.5); // Number of iterations used in NcSpectrum::SearchHighRes()
771 Int_t npeaks=0, ibin=0, lookforsteepestuntilbin=0, steep=0;
772 Float_t maxval=0, base1=0, rise=0, rc=0, yyy=0;
773 Bool_t pulsegoingon=false;
774 TString slotname;
775 TString wfname;
776 TString wfnamepattern;
777 Int_t patternmatch=0;
778
779 // OM, waveform and hit
780 IceDOM* omx=0;
781 TH1F* wf=0;
782 Int_t nbinswf=0;
783 Float_t wfbinvalue=0;
784 NcSample amplitudes;
785 amplitudes.SetStoreMode(1);
786 Float_t basemedian=0;
787 Float_t basespread=0;
788 Float_t cutlevel=0;
789 TString hitclass="none"; // Name of the hit class (e.g. CAL-ATWD, SLC etc...)
790 NcSignal hit;
791 hit.SetSlotName("ADC",1);
792 hit.SetSlotName("LE",2);
793 hit.SetSlotName("TOT",3);
794 hit.SetSlotName(hitclass,4);
795 hit.SetSlotName("SLC",5);
796
797 // Loop over all fired OMs and extract the hit info
798 Int_t nwf=0;
799 Int_t slc=0;
800 for (Int_t iom=0; iom<idoms->GetEntries(); iom++)
801 {
802 omx=(IceIDOM*)idoms->At(iom);
803 if (!omx) continue;
804
805 // Remove all existing hits of this OM
806 omx->RemoveHits();
807
808 // Reset (de)calibration functions to indicate uncalibrated data
809 omx->SetCalFunction(0,"ADC");
810 omx->SetCalFunction(0,"LE");
811 omx->SetCalFunction(0,"TOT");
812 omx->SetDecalFunction(0,"ADC");
813 omx->SetDecalFunction(0,"LE");
814 omx->SetDecalFunction(0,"TOT");
815
816 // Should we skip OMs that we know from the dbase to have problems ?
817//@@ if (omx->GetDeadValue("ADC") || omx->GetDeadValue("LE") || omx->GetDeadValue("TOT")) continue;
818
819 // Investigate all requested waveforms for this OM
820 nwf=omx->GetNwaveforms();
821 for (Int_t iwf=1; iwf<=nwf; iwf++)
822 {
823 wf=omx->GetWaveform(iwf);
824 if (!wf) continue;
825 wfname=wf->GetName();
826
827 // Check whether the waveform name matches any of the specified name patterns
828 patternmatch=0;
829 for (Int_t ipat=0; ipat<npatterns; ipat++)
830 {
831 TObjString* sx=(TObjString*)fUseNamesI->At(ipat);
832 if (!sx) continue;
833 wfnamepattern=sx->GetString();
834 if (wfname.Contains(wfnamepattern))
835 {
836 patternmatch=1;
837 break;
838 }
839 }
840
841 if (!patternmatch) continue;
842
843 // Determine the name of the hitclass for this waveform
844 hitclass="none";
845 slc=0;
846 if (wfname.Contains("CAL-ATWD")) hitclass="CAL-ATWD";
847 if (wfname.Contains("CAL-FADC")) hitclass="CAL-FADC";
848 if (wfname.Contains("RAW-ATWD0")) hitclass="RAW-ATWD0";
849 if (wfname.Contains("RAW-ATWD1")) hitclass="RAW-ATWD1";
850 if (wfname.Contains("RAW-ATWD2")) hitclass="RAW-ATWD2";
851 if (wfname.Contains("RAW-ATWD3")) hitclass="RAW-ATWD3";
852 if (wfname.Contains("RAW-FADC")) hitclass="RAW-FADC";
853 if (wfname.Contains("STAMP"))
854 {
855 hitclass="Q-STAMP";
856 if (nwf==1) slc=1;
857 }
858
859 // Determination of the baseline and cutlevel for the minimal peak height in this waveform
860 maxval=wf->GetMaximum();
861 base1=amplitudes.GetMedian(wf,2); // First approximation of baseline
862 cutlevel=base1+0.2*(maxval-base1); // Cut level for entries contributing to new baseline sampling
863
864 // RAW waveforms consist of integer counts, so the minimal cutlevel is set
865 // slightly higher than 1 count above the base1 for these RAW waveforms to get a better sampling of the baseline
866 if (hitclass.Contains("RAW") && (cutlevel-base1)<1.1) cutlevel=base1+1.1;
867
868 // Determination of the baseline and its spread for this waveform
869 nbinswf=wf->GetNbinsX();
870 amplitudes.Reset();
871 for (Int_t jbin=1; jbin<=nbinswf; jbin++)
872 {
873 wfbinvalue=wf->GetBinContent(jbin);
874 if (wfbinvalue<cutlevel) amplitudes.Enter(wfbinvalue);
875 }
876 basemedian=amplitudes.GetMedian(1);
877 basespread=amplitudes.GetSpread(1);
878
879 // Determination of the cutlevel to require a minimal peak height
880 // In view of the fact that the CAL-ATWD may have a very large dynamic range because it may be
881 // built out of several RAW-ATWD channels with different gains, the cutlevel will be limited for CAL-ATWD
882 // in order not to remove good peaks in the presence of very high ones.
883 // For CAL-ATWD a 1 PE signal corresponds roughly to 5 mV, so the cutlevel will be limited to 1 mV,
884 // corresponding to about 0.2 PE.
885 // RAW waveforms consist of integer counts, so the minimal cutlevel will be set slightly higher than 1 count
886 // above the baseline for these RAW waveforms in order to prevent construction of fake peaks.
887 cutlevel=basemedian+fPeakAcceptanceLevelI*basespread;
888 if (hitclass.Contains("CAL-ATWD") && cutlevel>1) cutlevel=1;
889 if (hitclass.Contains("RAW") && (cutlevel-basemedian)<1.1) cutlevel=basemedian+1.1;
890
891 // Store the baseline and its spread in the DOM attributes
892 slotname="BASELINE-WF";
893 slotname+=iwf;
894 omx->AddNamedSlot(slotname);
895 omx->SetSignal(basemedian,slotname);
896 omx->SetSignalError(basespread,slotname);
897
898 // Check if clipping window is not too large
899 if(nbinswf > 2*nrIterations+1)
900 {
901 // Find peaks with NcSpectrum
902 if ((cutlevel-basemedian) && (maxval-basemedian))
903 {
904 npeaks=spec.Search(wf,fSigmaI,"goff",fabs((cutlevel-basemedian)/(maxval-basemedian)));
905 }
906 else
907 {
908 npeaks=spec.Search(wf,fSigmaI,"goff",0.002);
909 }
910 // Discard waveform if no or too many peaks found
911 if(npeaks<1 || npeaks>fMaxPeaksI) continue;
912
913 // Get differential of WF
914 diff=*wf;
915 for(ibin=2;ibin<diff.GetNbinsX();ibin++)
916 {
917 diff.SetBinContent(ibin,wf->GetBinContent(ibin)-wf->GetBinContent(ibin-1));
918 }
919 diff.SetBinContent(1,0);
920 // Set baseline and lower end for first peak,
921 baseline[0]=basemedian;
922 lowend[0]=1;
923
924 // Sort peaks in time in increasing order
925 TMath::Sort(npeaks,spec.GetPositionX(),index,false);
926
927 // Analyse each individual peak
928 for(Int_t ipeak=0; ipeak<npeaks; ipeak++)
929 {
930 // Find baseline and region around peak
931 // Second and later peaks: lower edge = upper edge previous peak,
932 // baseline is a predefined fraction between the previous baseline and minimum value between two peaks
933 // In case the "minimum value between the peaks" is below the overall baseline, the pulses are obviously
934 // well separated and the effective baseline is set to the overall baseline again.
935 htemp=*wf;
936 if(ipeak>0)
937 {
938 lowend[ipeak]=upend[ipeak-1]+1;
939 baseline[ipeak]=baseline[ipeak-1]+fBasefracI*(htemp.GetBinContent(lowend[ipeak])-baseline[ipeak-1]);
940 if (htemp.GetBinContent(lowend[ipeak])<=basemedian) baseline[ipeak]=basemedian;
941 }
942 if(ipeak<npeaks-1) // Upper edge range is minimum between this and next peak
943 {
944 htemp.SetAxisRange(spec.GetPositionX()[index[ipeak]],spec.GetPositionX()[index[ipeak+1]]);
945 upend[ipeak]=htemp.GetMinimumBin()-1;
946 }
947 else // Last peak: upper edge is end of histo
948 {
949 upend[ipeak]=wf->GetNbinsX();
950 }
951
952 // Find steepest rise
953 lookforsteepestuntilbin=wf->FindBin(spec.GetPositionX()[index[ipeak]]);
954 htemp=diff;
955 // Look for steepest rise between lower edge and peak position
956 htemp.SetAxisRange(wf->GetBinCenter(lowend[ipeak]),wf->GetBinCenter(lookforsteepestuntilbin));
957 steep=htemp.GetMaximumBin();
958 rise=htemp.GetBinContent(steep);
959
960 // Extrapolate tangent to find leading edge
961 yyy=wf->GetBinContent(steep)-baseline[ipeak];
962 rc=rise/htemp.GetBinWidth(steep);
963 if (rc>0)
964 {
965 leadingedge[ipeak]=wf->GetBinCenter(steep)-yyy/rc;
966 }
967 else
968 {
969 leadingedge[ipeak]=0;
970 }
971
972 // Determine peak status
973 status[ipeak]=0;
974 // Check for saturation in RAW waveform data
975 if ((hitclass.Contains("RAW") || hitclass.Contains("STAMP")) &&
976 rc<1./wf->GetBinWidth(1) && wf->GetBinContent(wf->FindBin(spec.GetPositionX()[index[ipeak]])) == maxval)
977 {
978 status[ipeak]=2;
979 }
980
981 // Check quality: LE should not be too far below lower edge
982 // Otherwise, ignore this peak and set baseline back to what it was
983 if (wf->GetBinLowEdge(lowend[ipeak])-leadingedge[ipeak]>spec.GetPositionX()[index[ipeak]]-wf->GetBinLowEdge(lowend[ipeak]) &&
984 ipeak>0 && status[ipeak-1]!=5)
985 {
986 status[ipeak]=1;
987 if(ipeak>0) baseline[ipeak]=baseline[ipeak-1];
988 }
989
990 // Check if peak is adjacent to a higher, later peak.
991 // If this is the case, flag it with status 5.
992 // The smaller bump will then lateron be merged with the larger adjacent peak.
993 if (upend[ipeak]-wf->FindBin(spec.GetPositionX()[index[ipeak]])<0) status[ipeak]=5;
994
995 // Check if peak is high enough
996 if(wf->GetBinContent(lookforsteepestuntilbin) < cutlevel) status[ipeak]=3;
997
998 // Start charge integration at LE, or at lower edge of range
999 startcharge[ipeak]=wf->FindBin(leadingedge[ipeak]);
1000 if(lowend[ipeak]>startcharge[ipeak]) startcharge[ipeak]=lowend[ipeak];
1001
1002 // Integrate charge until pulse drops below its baseline, or else until edge of range
1003 stopcharge[ipeak]=upend[ipeak];
1004 for (ibin=wf->FindBin(spec.GetPositionX()[index[ipeak]]); ibin<=upend[ipeak]; ibin++)
1005 {
1006 if(wf->GetBinContent(ibin)<=baseline[ipeak])
1007 {
1008 stopcharge[ipeak]=ibin-1;
1009 break;
1010 }
1011 }
1012
1013 // Determine time over threshold
1014 tot[ipeak]=wf->GetBinLowEdge(stopcharge[ipeak]+1)-wf->GetBinLowEdge(startcharge[ipeak]);
1015
1016 // Determine the charge corrected for the baseline
1017 charge[ipeak]=0;
1018 for(ibin=startcharge[ipeak]; ibin<=stopcharge[ipeak]; ibin++)
1019 {
1020 charge[ipeak]+=(wf->GetBinContent(ibin))-baseline[ipeak];
1021 }
1022
1023 } // end loop over peaks
1024
1025 // Check all peaks, from latest to earliest
1026 for(int ipeak=npeaks-1; ipeak>=0; ipeak--)
1027 {
1028 // If this peak was rejected, add charge and TOT to previous peak (if there is one)
1029 if(status[ipeak]==1 && ipeak>0)
1030 {
1031 charge[ipeak-1]+=charge[ipeak];
1032 charge[ipeak]=0;
1033 tot[ipeak-1]+=tot[ipeak];
1034 tot[ipeak]=0;
1035 }
1036
1037 // If earlier peak was rejected by status 5, add charge, TOT and set LE of that peak to this peak
1038 if (status[ipeak-1]==5)
1039 {
1040 charge[ipeak]+=charge[ipeak-1];
1041 charge[ipeak-1]=0;
1042 tot[ipeak]+=tot[ipeak-1];
1043 tot[ipeak-1]=0;
1044 leadingedge[ipeak]=leadingedge[ipeak-1];
1045 leadingedge[ipeak-1]=0;
1046 }
1047
1048 // If this peak is OK, add hit info
1049 if(status[ipeak]==0 && charge[ipeak]>0)
1050 {
1051 hit.Reset();
1052 hit.SetSignal(charge[ipeak],"ADC");
1053 hit.SetSignal(leadingedge[ipeak],"LE");
1054 hit.SetSignal(tot[ipeak],"TOT");
1055 hit.SetSlotName(hitclass,4);
1056 hit.SetSignal(1,hitclass);
1057 if (slc)
1058 {
1059 hit.SetSignal(1,"SLC");
1060 }
1061 else
1062 {
1063 hit.SetSignal(0,"SLC");
1064 }
1065 omx->AddHit(hit);
1066 }
1067
1068 } // end loop over peaks
1069 }
1070 else // If number of bins too small, use different method
1071 {
1072 // If maximum value high enough to suspect presence of peak,
1073 if(maxval>fMinPulseHeightI)
1074 {
1075 // Loop over bins
1076 pulsegoingon=false;
1077 npeaks=0;
1078 for(ibin=1; ibin<=wf->GetNbinsX(); ibin++)
1079 {
1080 // If bin content above threshold, start pulse
1081 if(wf->GetBinContent(ibin)>fThresholdI*maxval){
1082 if(!pulsegoingon)
1083 {
1084 // Pulse starts here
1085 pulsegoingon=true;
1086 leadingedge[npeaks]=wf->GetBinLowEdge(ibin);
1087 charge[npeaks]=(wf->GetBinContent(ibin))-basemedian;
1088 }
1089 else
1090 {
1091 // Pulse continues
1092 charge[npeaks]+=(wf->GetBinContent(ibin))-basemedian;
1093 }
1094 }
1095 else
1096 {
1097 if(pulsegoingon)
1098 {
1099 // Pulse ends here
1100 tot[npeaks]=wf->GetBinLowEdge(ibin)-leadingedge[npeaks];
1101
1102 // Store pulse information
1103 hit.Reset();
1104 hit.SetSignal(charge[npeaks],"ADC");
1105 hit.SetSignal(leadingedge[npeaks],"LE");
1106 hit.SetSignal(tot[npeaks],"TOT");
1107 hit.SetSlotName(hitclass,4);
1108 hit.SetSignal(1,hitclass);
1109 if (slc)
1110 {
1111 hit.SetSignal(1,"SLC");
1112 }
1113 else
1114 {
1115 hit.SetSignal(0,"SLC");
1116 }
1117 omx->AddHit(hit);
1118
1119 // Get ready for next pulse
1120 pulsegoingon=false;
1121 npeaks++;
1122 }
1123 }
1124
1125 } // End of loop over bins
1126 }
1127
1128 } // End of alternative method for narrow pulses
1129
1130 } // End of WF loop
1131 } // End of OM loop
1132
1133 // Clean up
1134 delete[] baseline;
1135 delete[] lowend;
1136 delete[] upend;
1137 delete[] startcharge;
1138 delete[] stopcharge;
1139 delete[] status;
1140 delete[] leadingedge;
1141 delete[] charge;
1142 delete[] tot;
1143 delete[] index;
1144}
1145
ClassImp(IceMakeHits)
Signal (Hit) handling of a generic Amanda Optical Module (AOM).
Definition IceAOM.h:12
Signal (Hit) handling of a generic IceCube Digital Optical Module (DOM).
Definition IceDOM.h:12
Handling of IceCube event data.
Definition IceEvent.h:20
Signal (Hit) handling of a generic IceCube In-ice Digital Optical Module (IDOM).
Definition IceIDOM.h:12
TTask derived class to perform hit extraction from waveforms.
Definition IceMakeHits.h:26
Float_t fMinPulseHeightA
Definition IceMakeHits.h:51
void SetMaxPeaksI(Int_t val)
IceMakeHits(const char *name="IceMakeHits", const char *title="Hit extraction")
void SetMinPulseHeightA(Float_t val)
void SetThresholdI(Float_t val)
virtual void Exec(Option_t *opt)
void UseWaveformNameI(TString name)
Float_t fThresholdA
Definition IceMakeHits.h:52
void SetMinPulseHeightI(Float_t val)
void SetBasefracA(Float_t val)
void SetThresholdA(Float_t val)
void SetMaxPeaksA(Int_t val)
void SetBasefracI(Float_t val)
void SetSigmaA(Float_t val)
Int_t fMaxPeaksI
Definition IceMakeHits.h:55
Float_t fBasefracI
Definition IceMakeHits.h:53
void SetPeakAcceptanceLevelI(Float_t val)
void SetWaveformNameI(const char *name)
Float_t fSigmaA
Definition IceMakeHits.h:49
Float_t fPeakAcceptanceLevelI
Definition IceMakeHits.h:56
void SetSigmaI(Float_t val)
Float_t fMinPulseHeightI
Definition IceMakeHits.h:57
TObjArray * fUseNamesI
Definition IceMakeHits.h:59
void PrintWaveformNamesI() const
Float_t fBasefracA
Definition IceMakeHits.h:48
Float_t fThresholdI
Definition IceMakeHits.h:58
Int_t fMaxPeaksA
Definition IceMakeHits.h:50
virtual ~IceMakeHits()
Float_t fSigmaI
Definition IceMakeHits.h:54
IceEvent * fEvt
Definition IceMakeHits.h:47
void SetCalFunction(TF1 *f, Int_t j=1)
void AddNamedSlot(TString s)
void SetDecalFunction(TF1 *f, Int_t j=1)
void SetSlotName(TString s, Int_t j=1)
Signal (Hit) handling of a generic device.
Definition NcDevice.h:14
void AddHit(NcSignal &s)
Definition NcDevice.cxx:336
void RemoveHits()
Definition NcDevice.cxx:412
Base class for top level job in a task based procedure.
Definition NcJob.h:18
TObject * GetObject(const char *classname) const
Definition NcJob.cxx:456
Sampling and statistics tools for various multi-dimensional data samples.
Definition NcSample.h:28
Double_t GetMedian(Int_t i)
void Reset()
Definition NcSample.cxx:255
void Enter(Double_t x)
Definition NcSample.cxx:357
void SetStoreMode(Int_t mode=1, Int_t nmax=0, Int_t i=0)
Double_t GetSpread(Int_t i, Int_t model=0, Double_t vref=0)
Generic handling of (extrapolated) detector signals.
Definition NcSignal.h:23
Int_t GetNwaveforms() const
virtual void Reset(Int_t mode=0)
Definition NcSignal.cxx:334
TH1F * GetWaveform(Int_t j=1) const
virtual void SetSignal(Double_t sig, Int_t j=1)
Definition NcSignal.cxx:516
virtual Float_t GetSignal(Int_t j=1, Int_t mode=0) const
Definition NcSignal.cxx:651
virtual void SetSignalError(Double_t dsig, Int_t j=1)
Definition NcSignal.cxx:845
Facilities for advanced spectral analysis.
Definition NcSpectrum.h:26
virtual Int_t Search(const TH1 *hist, Double_t sigma=2, Option_t *option="", Double_t threshold=0.05)
static void SetDeconIterations(Int_t n=3)
Float_t * GetPositionX() const
Definition NcSpectrum.h:66