1 /*******************************************************************************
2 * Copyright(c) 2003, IceCube Experiment at the South Pole. All rights reserved.
4 * Author: The IceCube RALICE-based Offline Project.
5 * Contributors are mentioned in the code where appropriate.
7 * Permission to use, copy, modify and distribute this software and its
8 * documentation strictly for non-commercial purposes is hereby granted
9 * without fee, provided that the above copyright notice appears in all
10 * copies and that both the copyright notice and this permission notice
11 * appear in the supporting documentation.
12 * The authors make no claims about the suitability of this software for
13 * any purpose. It is provided "as is" without express or implied warranty.
14 *******************************************************************************/
18 ///////////////////////////////////////////////////////////////////////////
20 // TTask derived class to perform hit extraction from waveforms.
22 // In case an event has been rejected by an AliEventSelector (based) processor,
23 // this task (and its sub-tasks) is not executed.
25 // The code in this processor is based on the algorithms as developed by
26 // Nick van Eijndhoven and Garmt de Vries-Uiterweerd (Utrecht University, The Netherlands).
28 // Procedure applied for Amanda TWR data :
29 // ---------------------------------------
31 // 1) The waveform is fed to a TSpectrum object, and the peak locations
32 // are determined with the TSpectrum::Search() function.
34 // 2) The waveform is divided into regions corresponding to the peaks found by
35 // TSpectrum. The region boundary between two peaks is at the location of
36 // the minimum between the two peaks.
38 // 3) For each region the "effective baseline" (used in the
39 // evaluation of the leading edge value) is determined as :
40 // effective baseline = fBasefracXXX * value at lower region boundary.
41 // This takes into account the effect from the previous pulse.
42 // For the first pulse, the effective baseline is equal to the overall
45 // 4) For each region, the point of steepest rise between the lower region
46 // boundary and the peak location is determined. The tangent at this point
47 // is extrapolated to the effective baseline. The point of intersection yields the
50 // 5) For each region the range of charge integration is determined as :
51 // - Start of integration at the lower region boundary or at the leading edge,
52 // whichever comes last;
53 // - End of integration at the upper region boundary or at the point where the
54 // signal drops below the overall baseline, whichever comes first.
56 // 6) For each region the integrated charge is determined as :
57 // Sum over bins in integration range of (value in bin - overall baseline).
59 // 7) For each pulse the quality is evaluated by requiring that :
60 // peak location - lower region boundary > lower region boundary - leading edge.
61 // For a too shallow steepest rise, the leading edge value is unreliable, in
62 // which case the pulse is merged with the previous pulse.
64 // 8) Each pulse is checked for saturation and discarded if necessary.
66 // 9) TSpectrum needs a minimum number of bins for its Search function, otherwise
67 // the clipping window is too large, which causes an error. If a waveform does
68 // not contain enough bins, the following alternative approach is used :
69 // - A loop over all bins is performed.
70 // - As soon as the signal exceeds a given threshold, a pulse is started.
71 // - The pulse ends when the signal drops below the threshold again.
72 // - While looping, the charge is integrated for each pulse.
74 // The defaults of the various parameters can be changed by the corresponding
75 // Set memberfunctions.
77 // Information about the actual parameter settings can be found in the event
78 // structure itself via the device named "IceMakeHits".
80 //--- Author: Nick van Eijndhoven and Garmt de Vries-Uiterweerd 15-jan-2007 Utrecht University
81 //- Modified: GdV $Date$ Utrecht University
82 ///////////////////////////////////////////////////////////////////////////
84 #include "IceMakeHits.h"
85 #include "Riostream.h"
87 ClassImp(IceMakeHits) // Class implementation to enable ROOT I/O
89 IceMakeHits::IceMakeHits(const char* name,const char* title) : TTask(name,title)
91 // Default constructor.
100 ///////////////////////////////////////////////////////////////////////////
101 IceMakeHits::~IceMakeHits()
103 // Default destructor.
105 ///////////////////////////////////////////////////////////////////////////
106 void IceMakeHits::SetBasefracA(Float_t val)
108 // Set baseline fractional update for Amanda TWR extraction.
109 // The default as set in the constructor of this class is 0.5.
112 ///////////////////////////////////////////////////////////////////////////
113 void IceMakeHits::SetSigmaA(Float_t val)
115 // Set clipping window width for Amanda TWR extraction.
116 // The default as set in the constructor of this class is 1.5.
119 ///////////////////////////////////////////////////////////////////////////
120 void IceMakeHits::SetMaxPeaksA(Int_t val)
122 // Set maximum number of peaks in a waveform for Amanda TWR extraction.
123 // The default as set in the constructor of this class is 10.
126 ///////////////////////////////////////////////////////////////////////////
127 void IceMakeHits::SetMinPulseHeightA(Float_t val)
129 // Set minimum required pulse height for Amanda TWR extraction.
130 // This is used only for narrow pulses that cannot be handled with TSpectrum.
131 // The default as set in the constructor of this class is 50.
132 fMinPulseHeightA=val;
134 ///////////////////////////////////////////////////////////////////////////
135 void IceMakeHits::SetThresholdA(Float_t val)
137 // Set threshold for use in analysis of narrow pulses for Amanda TWR extraction.
138 // A peak is assumed to start when the signal rises above threshold*maxval,
139 // where maxval is the maximum value found in the waveform.
140 // The default as set in the constructor of this class is 0.2.
143 ///////////////////////////////////////////////////////////////////////////
144 void IceMakeHits::Exec(Option_t* opt)
146 // Implementation of the hit cleaning procedures.
149 AliJob* parent=(AliJob*)(gROOT->GetListOfTasks()->FindObject(name.Data()));
153 fEvt=(IceEvent*)parent->GetObject("IceEvent");
156 // Only process accepted events
157 AliDevice* seldev=(AliDevice*)fEvt->GetDevice("AliEventSelector");
160 if (seldev->GetSignal("Select") < 0.1) return;
163 fDaq=(AliDevice*)fEvt->GetDevice("Daq");
166 // Storage of the used parameters in the IceMakeHits device
168 params.SetNameTitle("IceMakeHits","IceMakeHits processor parameters");
169 params.SetSlotName("BasefracA",1);
170 params.SetSlotName("SigmaA",2);
171 params.SetSlotName("MaxPeaksA",3);
172 params.SetSignal(fBasefracA,1);
173 params.SetSignal(fSigmaA,2);
174 params.SetSignal(fMaxPeaksA,3);
176 fEvt->AddDevice(params);
178 // Suppress (TSpectrum) warning messages
179 gErrorIgnoreLevel=kError; // Only provide error messages
185 // Activate all messages
186 gErrorIgnoreLevel=kWarning; // Error and warning messages
189 ///////////////////////////////////////////////////////////////////////////
190 void IceMakeHits::Amanda()
192 // Hit extraction from the Amanda TWR data.
194 // Arrays for storing info
195 Float_t* baseline=new Float_t[fMaxPeaksA];
196 Int_t* lowend=new Int_t[fMaxPeaksA];
197 Int_t* upend=new Int_t[fMaxPeaksA];
198 Int_t* startcharge=new Int_t[fMaxPeaksA];
199 Int_t* stopcharge=new Int_t[fMaxPeaksA];
200 Int_t* status=new Int_t[fMaxPeaksA]; // 0=OK, 1=rejected, 2=saturation
201 Float_t* leadingedge=new Float_t[fMaxPeaksA];
202 Float_t* charge=new Float_t[fMaxPeaksA];
203 Float_t* tot=new Float_t[fMaxPeaksA];
205 // Some objects and variables we will need
207 TSpectrum spec(fMaxPeaksA);
208 Int_t nrIterations=(Int_t)(7*fSigmaA+0.5); // Number of iterations used in TSpectrum::SearchHighRes()
209 Int_t npeaks=0, ibin=0, lookforsteepestuntilbin=0, steep=0;
210 Float_t maxval=0, rise=0, rc=0, yyy=0;
211 Bool_t pulsegoingon=false;
212 Int_t* index=new Int_t[fMaxPeaksA];
214 // Update the DAQ device data for the nature of the hit info
215 fDaq->AddNamedSlot("TWR");
216 fDaq->SetSignal(1,"TWR");
217 Int_t idx=fDaq->GetSlotIndex("Muon");
218 if (idx) fDaq->SetSignal(0,idx);
220 // All Amanda OMs with a signal
221 TObjArray* aoms=fEvt->GetDevices("IceAOM");
224 // OM, waveform and hit
228 hit.SetSlotName("ADC",1);
229 hit.SetSlotName("LE",2);
230 hit.SetSlotName("TOT",3);
232 // Loop over all fired OMs and extract the hit info
233 for (Int_t iom=0; iom<aoms->GetEntries(); iom++)
235 omx=(IceAOM*)aoms->At(iom);
237 // Remove all existing hits of this OM
239 // Should we skip OMs that we know from the dbase to have problems ?
240 //// if (omx->GetDeadValue("ADC") || omx->GetDeadValue("LE") || omx->GetDeadValue("TOT")) continue;
242 // Investigate all waveforms for this OM
243 for (Int_t iwf=1; iwf<=omx->GetNwaveforms(); iwf++)
245 wf=omx->GetWaveform(iwf);
247 maxval=wf->GetMaximum();
248 // Check if clipping window is not too large
249 if(wf->GetNbinsX() > 2*nrIterations+1)
251 // Find peaks with TSpectrum
252 npeaks=spec.Search(wf,fSigmaA,"goff");
253 // Discard waveform if no or too many peaks found
254 if(npeaks<1 || npeaks>fMaxPeaksA) continue;
256 // Get differential of WF
258 for(ibin=2;ibin<diff.GetNbinsX();ibin++)
260 diff.SetBinContent(ibin,wf->GetBinContent(ibin)-wf->GetBinContent(ibin-1));
262 diff.SetBinContent(1,0);
263 // Set baseline and lower end for first peak,
267 // Sort peaks in time
268 TMath::Sort(npeaks,spec.GetPositionX(),index,false);
269 // For each of the peaks,
270 for(Int_t ipeak=0; ipeak<npeaks; ipeak++)
272 // Find baseline and region around peak
274 // (Second and later peaks: lower edge = upper edge previous peak,
275 // baseline is average of previous baseline and minimum value between two
279 lowend[ipeak]=upend[ipeak-1]+1;
280 baseline[ipeak]=fBasefracA*foo.GetBinContent(lowend[ipeak]);
282 // (Upper edge range is minimum between this and next peak)
285 foo.SetAxisRange(spec.GetPositionX()[index[ipeak]],spec.GetPositionX()[index[ipeak+1]]);
286 upend[ipeak]=foo.GetMinimumBin()-1;
288 // (Last peak: upper edge is end of histo)
291 upend[ipeak]=wf->GetNbinsX();
293 // Find steepest rise
294 lookforsteepestuntilbin=wf->FindBin(spec.GetPositionX()[index[ipeak]]);
296 // Look for steepest rise between lower edge and peak position
297 foo.SetAxisRange(wf->GetBinCenter(lowend[ipeak]),wf->GetBinCenter(lookforsteepestuntilbin));
298 steep=foo.GetMaximumBin();
299 rise=foo.GetBinContent(steep);
301 // Extrapolate tangent to find leading edge
302 yyy=wf->GetBinContent(steep)-baseline[ipeak];
303 rc=rise/foo.GetBinWidth(steep);
304 if(rc>0) leadingedge[ipeak]=wf->GetBinCenter(steep)-yyy/rc; else leadingedge[ipeak]=0;
306 // Determine peak status
308 // Check for saturation
309 if(rc<0.1 && wf->GetBinContent(wf->FindBin(spec.GetPositionX()[index[ipeak]])) == maxval)
313 // Check quality: LE should not be too far below lower edge
314 // Otherwise, ignore this peak and set baseline back to what it was
315 else if(wf->GetBinLowEdge(lowend[ipeak]) - leadingedge[ipeak] > spec.GetPositionX()[index[ipeak]] - wf->GetBinLowEdge(lowend[ipeak]))
318 if(ipeak>0) baseline[ipeak]=baseline[ipeak-1];
321 // Start charge integration at LE, or at lower edge of range
322 startcharge[ipeak]=wf->FindBin(leadingedge[ipeak]);
323 if(lowend[ipeak]>startcharge[ipeak]) startcharge[ipeak]=lowend[ipeak];
325 // Integrate charge until pulse drop below baseline, or else until edge of range
326 stopcharge[ipeak]=upend[ipeak];
327 for(ibin=wf->FindBin(spec.GetPositionX()[index[ipeak]]); ibin<=upend[ipeak]; ibin++)
329 if(wf->GetBinContent(ibin)<0)
331 stopcharge[ipeak]=ibin-1;
336 // Determine time over threshold
337 tot[ipeak]=wf->GetBinLowEdge(stopcharge[ipeak]+1)-wf->GetBinLowEdge(startcharge[ipeak]);
341 for(ibin=startcharge[ipeak]; ibin<=stopcharge[ipeak]; ibin++)
343 charge[ipeak]+=wf->GetBinContent(ibin);
346 } // end loop over peaks
348 // Check all peaks, from latest to earliest
349 for(int ipeak=npeaks-1; ipeak>=0; ipeak--)
352 // If this peak was rejected, add charge and TOT to previous peak (if there is one)
353 if(status[ipeak]==1 && ipeak>0)
355 charge[ipeak-1]+=charge[ipeak];
357 tot[ipeak-1]+=tot[ipeak];
361 // If this peak is OK, add hit info
365 hit.SetSignal(charge[ipeak],"ADC");
366 hit.SetSignal(leadingedge[ipeak],"LE");
367 hit.SetSignal(tot[ipeak],"TOT");
371 } // end loop over peaks
372 // If number of bins too small, use different method
376 // If maximum value high enough to suspect presence of peak,
377 if(maxval>fMinPulseHeightA)
382 for(ibin=1; ibin<=wf->GetNbinsX(); ibin++)
384 // If bin content above threshold, start pulse
385 if(wf->GetBinContent(ibin)>fThresholdA*maxval){
390 leadingedge[npeaks]=wf->GetBinLowEdge(ibin);
391 charge[npeaks]=wf->GetBinContent(ibin);
396 charge[npeaks]+=wf->GetBinContent(ibin);
404 tot[npeaks]=wf->GetBinLowEdge(ibin)-leadingedge[npeaks];
406 // Store pulse information
408 hit.SetSignal(charge[npeaks],"ADC");
409 hit.SetSignal(leadingedge[npeaks],"LE");
410 hit.SetSignal(tot[npeaks],"TOT");
413 // Get ready for next pulse
419 } // End of loop over bins
422 } // End of alternative method for narrow pulses
431 delete[] startcharge;
434 delete[] leadingedge;
439 ///////////////////////////////////////////////////////////////////////////
440 void IceMakeHits::InIce()
442 // Hit extraction from IceCube InIce ATWD data.
444 ///////////////////////////////////////////////////////////////////////////
445 void IceMakeHits::IceTop()
447 // Hit extraction from IceTop ATWD data.
449 ///////////////////////////////////////////////////////////////////////////