]> git.uio.no Git - u/mrichter/AliRoot.git/blame - RALICE/icepack/IceMakeHits.cxx
23-jan-2007 NvE Bug fixed by Garmt in IceMakeHits.cxx.
[u/mrichter/AliRoot.git] / RALICE / icepack / IceMakeHits.cxx
CommitLineData
cf3100fa 1/*******************************************************************************
2 * Copyright(c) 2003, IceCube Experiment at the South Pole. All rights reserved.
3 *
4 * Author: The IceCube RALICE-based Offline Project.
5 * Contributors are mentioned in the code where appropriate.
6 *
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 *******************************************************************************/
15
16// $Id$
17
18///////////////////////////////////////////////////////////////////////////
19// Class IceMakeHits
20// TTask derived class to perform hit extraction from waveforms.
21//
22// The code in this processor is based on the algorithms as developed by
23// Nick van Eijndhoven and Garmt de Vries-Uiterweerd (Utrecht University, The Netherlands).
24//
25// Procedure applied for Amanda TWR data :
26// ---------------------------------------
27//
28// 1) The waveform is fed to a TSpectrum object, and the peak locations
29// are determined with the TSpectrum::Search() function.
30//
31// 2) The waveform is divided into regions corresponding to the peaks found by
32// TSpectrum. The region boundary between two peaks is at the location of
33// the minimum between the two peaks.
34//
35// 3) For each region the "effective baseline" (used in the
36// evaluation of the leading edge value) is determined as :
37// effective baseline = fBasefracXXX * value at lower region boundary.
38// This takes into account the effect from the previous pulse.
39// For the first pulse, the effective baseline is equal to the overall
40// baseline.
41//
42// 4) For each region, the point of steepest rise between the lower region
43// boundary and the peak location is determined. The tangent at this point
44// is extrapolated to the effective baseline. The point of intersection yields the
45// leading edge.
46//
47// 5) For each region the range of charge integration is determined as :
48// - Start of integration at the lower region boundary or at the leading edge,
49// whichever comes last;
50// - End of integration at the upper region boundary or at the point where the
51// signal drops below the overall baseline, whichever comes first.
52//
53// 6) For each region the integrated charge is determined as :
54// Sum over bins in integration range of (value in bin - overall baseline).
55//
56// 7) For each pulse the quality is evaluated by requiring that :
57// peak location - lower region boundary > lower region boundary - leading edge.
58// For a too shallow steepest rise, the leading edge value is unreliable, in
59// which case the pulse is merged with the previous pulse.
60//
61// 8) Each pulse is checked for saturation and discarded if necessary.
62//
63// 9) TSpectrum needs a minimum number of bins for its Search function, otherwise
64// the clipping window is too large, which causes an error. If a waveform does
65// not contain enough bins, the following alternative approach is used :
66// - A loop over all bins is performed.
67// - As soon as the signal exceeds a given threshold, a pulse is started.
68// - The pulse ends when the signal drops below the threshold again.
69// - While looping, the charge is integrated for each pulse.
70//
71// The defaults of the various parameters can be changed by the corresponding
72// Set memberfunctions.
73//
74// Information about the actual parameter settings can be found in the event
75// structure itself via the device named "IceMakeHits".
76//
77//--- Author: Nick van Eijndhoven and Garmt de Vries-Uiterweerd 15-jan-2007 Utrecht University
78//- Modified: NvE $Date$ Utrecht University
79///////////////////////////////////////////////////////////////////////////
80
81#include "IceMakeHits.h"
82#include "Riostream.h"
83
84ClassImp(IceMakeHits) // Class implementation to enable ROOT I/O
85
86IceMakeHits::IceMakeHits(const char* name,const char* title) : TTask(name,title)
87{
88// Default constructor.
89 fEvt=0;
90 fDaq=0;
91 fBasefracA=0.5;
92 fSigmaA=1.5;
93 fMaxPeaksA=10;
94 fMinPulseHeightA=50;
95 fThresholdA=0.2;
96}
97///////////////////////////////////////////////////////////////////////////
98IceMakeHits::~IceMakeHits()
99{
100// Default destructor.
101}
102///////////////////////////////////////////////////////////////////////////
103void IceMakeHits::SetBasefracA(Float_t val)
104{
105// Set baseline fractional update for Amanda TWR extraction.
106// The default as set in the constructor of this class is 0.5.
107 fBasefracA=val;
108}
109///////////////////////////////////////////////////////////////////////////
110void IceMakeHits::SetSigmaA(Float_t val)
111{
112// Set clipping window width for Amanda TWR extraction.
113// The default as set in the constructor of this class is 1.5.
114 fSigmaA=val;
115}
116///////////////////////////////////////////////////////////////////////////
117void IceMakeHits::SetMaxPeaksA(Int_t val)
118{
119// Set maximum number of peaks in a waveform for Amanda TWR extraction.
120// The default as set in the constructor of this class is 10.
121 fMaxPeaksA=val;
122}
123///////////////////////////////////////////////////////////////////////////
124void IceMakeHits::SetMinPulseHeightA(Float_t val)
125{
126// Set minimum required pulse height for Amanda TWR extraction.
127// This is used only for narrow pulses that cannot be handled with TSpectrum.
128// The default as set in the constructor of this class is 50.
129 fMinPulseHeightA=val;
130}
131///////////////////////////////////////////////////////////////////////////
132void IceMakeHits::SetThresholdA(Float_t val)
133{
134// Set threshold for use in analysis of narrow pulses for Amanda TWR extraction.
135// A peak is assumed to start when the signal rises above threshold*maxval,
136// where maxval is the maximum value found in the waveform.
137// The default as set in the constructor of this class is 0.2.
138 fThresholdA=val;
139}
140///////////////////////////////////////////////////////////////////////////
141void IceMakeHits::Exec(Option_t* opt)
142{
143// Implementation of the hit cleaning procedures.
144
145 TString name=opt;
146 AliJob* parent=(AliJob*)(gROOT->GetListOfTasks()->FindObject(name.Data()));
147
148 if (!parent) return;
149
150 fEvt=(IceEvent*)parent->GetObject("IceEvent");
151 if (!fEvt) return;
152
153 fDaq=(AliDevice*)fEvt->GetDevice("Daq");
154 if (!fDaq) return;
155
156 // Storage of the used parameters in the IceMakeHits device
157 AliSignal params;
158 params.SetNameTitle("IceMakeHits","IceMakeHits processor parameters");
159 params.SetSlotName("BasefracA",1);
160 params.SetSlotName("SigmaA",2);
161 params.SetSlotName("MaxPeaksA",3);
162 params.SetSignal(fBasefracA,1);
163 params.SetSignal(fSigmaA,2);
164 params.SetSignal(fMaxPeaksA,3);
165
166 fEvt->AddDevice(params);
167
168 Amanda();
169 InIce();
170 IceTop();
a32bc6c6 171
cf3100fa 172}
173///////////////////////////////////////////////////////////////////////////
174void IceMakeHits::Amanda()
175{
176// Hit extraction from the Amanda TWR data.
177
178 // Arrays for storing info
179 Float_t* baseline=new Float_t[fMaxPeaksA];
180 Int_t* lowend=new Int_t[fMaxPeaksA];
181 Int_t* upend=new Int_t[fMaxPeaksA];
182 Int_t* startcharge=new Int_t[fMaxPeaksA];
183 Int_t* stopcharge=new Int_t[fMaxPeaksA];
a32bc6c6 184 Int_t* status=new Int_t[fMaxPeaksA]; // 0=OK, 1=rejected, 2=saturation, 3=completely below baseline
cf3100fa 185 Float_t* leadingedge=new Float_t[fMaxPeaksA];
186 Float_t* charge=new Float_t[fMaxPeaksA];
187 Float_t* tot=new Float_t[fMaxPeaksA];
188
189 // Some objects and variables we will need
190 TH1F foo, diff;
a32bc6c6 191 TSpectrum spec(fMaxPeaksA);
cf3100fa 192 Int_t nrIterations=(Int_t)(7*fSigmaA+0.5); // Number of iterations used in TSpectrum::SearchHighRes()
193 Int_t npeaks=0, ibin=0, lookforsteepestuntilbin=0, steep=0;
194 Float_t maxval=0, rise=0, rc=0, yyy=0;
195 Bool_t pulsegoingon=false;
196 Int_t* index=new Int_t[fMaxPeaksA];
197
198 // Update the DAQ device data for the nature of the hit info
199 fDaq->AddNamedSlot("TWR");
200 fDaq->SetSignal(1,"TWR");
201 Int_t idx=fDaq->GetSlotIndex("Muon");
202 if (idx) fDaq->SetSignal(0,idx);
203
204 // All Amanda OMs with a signal
205 TObjArray* aoms=fEvt->GetDevices("IceAOM");
206
207 // OM, waveform and hit
208 IceAOM* omx=0;
209 TH1F* wf=0;
210 AliSignal hit;
211 hit.SetSlotName("ADC",1);
212 hit.SetSlotName("LE",2);
213 hit.SetSlotName("TOT",3);
214
215 // Loop over all fired OMs and extract the hit info
216 for (Int_t iom=0; iom<aoms->GetEntries(); iom++)
217 {
218 omx=(IceAOM*)aoms->At(iom);
219 if (!omx) continue;
220 // Remove all existing hits of this OM
221 omx->RemoveHits();
cf3100fa 222 // Should we skip OMs that we know from the dbase to have problems ?
223//// if (omx->GetDeadValue("ADC") || omx->GetDeadValue("LE") || omx->GetDeadValue("TOT")) continue;
224
225 // Investigate all waveforms for this OM
226 for (Int_t iwf=1; iwf<=omx->GetNwaveforms(); iwf++)
227 {
228 wf=omx->GetWaveform(iwf);
229 if (!wf) continue;
cf3100fa 230 maxval=wf->GetMaximum();
cf3100fa 231 // Check if clipping window is not too large
232 if(wf->GetNbinsX() > 2*nrIterations+1)
233 {
234 // Find peaks with TSpectrum
a32bc6c6 235 npeaks=spec.Search(wf,fSigmaA,"goff");
cf3100fa 236 // Discard waveform if no or too many peaks found
237 if(npeaks<1 || npeaks>fMaxPeaksA) continue;
238
239 // Get differential of WF
240 diff=*wf;
241 for(ibin=2;ibin<diff.GetNbinsX();ibin++)
242 {
243 diff.SetBinContent(ibin,wf->GetBinContent(ibin)-wf->GetBinContent(ibin-1));
244 }
245 diff.SetBinContent(1,0);
cf3100fa 246 // Set baseline and lower end for first peak,
247 baseline[0]=0;
248 lowend[0]=1;
249
250 // Sort peaks in time
a32bc6c6 251 TMath::Sort(npeaks,spec.GetPositionX(),index,false);
cf3100fa 252 // For each of the peaks,
253 for(Int_t ipeak=0; ipeak<npeaks; ipeak++)
254 {
255 // Find baseline and region around peak
256 foo=*wf;
257 // (Second and later peaks: lower edge = upper edge previous peak,
258 // baseline is average of previous baseline and minimum value between two
259 // peaks)
260 if(ipeak>0)
261 {
262 lowend[ipeak]=upend[ipeak-1]+1;
263 baseline[ipeak]=fBasefracA*foo.GetBinContent(lowend[ipeak]);
264 }
265 // (Upper edge range is minimum between this and next peak)
266 if(ipeak<npeaks-1)
267 {
a32bc6c6 268 foo.SetAxisRange(spec.GetPositionX()[index[ipeak]],spec.GetPositionX()[index[ipeak+1]]);
cf3100fa 269 upend[ipeak]=foo.GetMinimumBin();
270 }
271 // (Last peak: upper edge is end of histo)
272 else
273 {
274 upend[ipeak]=wf->GetNbinsX();
275 }
cf3100fa 276 // Find steepest rise
a32bc6c6 277 lookforsteepestuntilbin=wf->FindBin(spec.GetPositionX()[index[ipeak]]);
cf3100fa 278 foo=diff;
a32bc6c6 279 // Look for steepest rise between lower edge and peak position
280 foo.SetAxisRange(wf->GetBinCenter(lowend[ipeak]),wf->GetBinCenter(lookforsteepestuntilbin));
281 // Signal should be above baseline at location of steepest rise
cf3100fa 282 do
283 {
284 steep=foo.GetMaximumBin();
285 rise=foo.GetBinContent(steep);
a32bc6c6 286 if(rise==-1e9) break;
cf3100fa 287 foo.SetBinContent(steep,-1e9);
288 } while(wf->GetBinContent(steep)<baseline[ipeak]);
a32bc6c6 289 if(rise==-1e9)
290 {
291 status[ipeak]=3;
292 continue;
293 }
cf3100fa 294
295 // Extrapolate tangent to find leading edge
296 yyy=wf->GetBinContent(steep)-baseline[ipeak];
297 rc=rise/foo.GetBinWidth(steep);
298 if(rc>0) leadingedge[ipeak]=wf->GetBinCenter(steep)-yyy/rc; else leadingedge[ipeak]=0;
299
300 // Determine peak status
301 status[ipeak]=0;
302 // Check for saturation
a32bc6c6 303 if(rc<0.1 && wf->GetBinContent(wf->FindBin(spec.GetPositionX()[index[ipeak]])) == maxval)
cf3100fa 304 {
305 status[ipeak]=2;
306 }
307 // Check quality: LE should not be too far below lower edge
308 // Otherwise, ignore this peak and set baseline back to what it was
a32bc6c6 309 else if(wf->GetBinLowEdge(lowend[ipeak]) - leadingedge[ipeak] > spec.GetPositionX()[index[ipeak]] - wf->GetBinLowEdge(lowend[ipeak]))
cf3100fa 310 {
311 status[ipeak]=1;
312 if(ipeak>0) baseline[ipeak]=baseline[ipeak-1];
313 }
314
315 // Start charge integration at LE, or at lower edge of range
316 startcharge[ipeak]=wf->FindBin(leadingedge[ipeak]);
317 if(lowend[ipeak]>startcharge[ipeak]) startcharge[ipeak]=lowend[ipeak];
318
319 // Integrate charge until pulse drop below baseline, or else until edge of range
320 stopcharge[ipeak]=upend[ipeak];
a32bc6c6 321 for(ibin=wf->FindBin(spec.GetPositionX()[index[ipeak]]); ibin<=upend[ipeak]; ibin++)
cf3100fa 322 {
323 if(wf->GetBinContent(ibin)<0)
324 {
325 stopcharge[ipeak]=ibin-1;
326 break;
327 }
328 }
329
330 // Determine time over threshold
331 tot[ipeak]=wf->GetBinLowEdge(stopcharge[ipeak]+1)-wf->GetBinLowEdge(startcharge[ipeak]);
332
333 // Determine charge
334 charge[ipeak]=0;
335 for(ibin=startcharge[ipeak]; ibin<=stopcharge[ipeak]; ibin++)
336 {
337 charge[ipeak]+=wf->GetBinContent(ibin);
338 }
339
340 } // end loop over peaks
341
342 // Check all peaks, from latest to earliest
343 for(int ipeak=npeaks-1; ipeak>=0; ipeak--)
344 {
345
346 // If this peak was rejected, add charge and TOT to previous peak (if there is one)
347 if(status[ipeak]==1 && ipeak>0)
348 {
349 charge[ipeak-1]+=charge[ipeak];
350 charge[ipeak]=0;
351 tot[ipeak-1]+=tot[ipeak];
352 tot[ipeak]=0;
353 }
354
355 // If this peak is OK, add hit info
356 if(status[ipeak]==0)
357 {
358 hit.Reset();
359 hit.SetSignal(charge[ipeak],"ADC");
360 hit.SetSignal(leadingedge[ipeak],"LE");
361 hit.SetSignal(tot[ipeak],"TOT");
362 omx->AddHit(hit);
363 }
364
365 } // end loop over peaks
366
367 // If number of bins too small, use different method
368 }
369 else
370 {
371 // If maximum value high enough to suspect presence of peak,
372 if(maxval>fMinPulseHeightA)
373 {
374 // Loop over bins
375 pulsegoingon=false;
376 npeaks=0;
377 for(ibin=1; ibin<=wf->GetNbinsX(); ibin++)
378 {
379 // If bin content above threshold, start pulse
380 if(wf->GetBinContent(ibin)>fThresholdA*maxval){
381 if(!pulsegoingon)
382 {
383 // Pulse starts here
384 pulsegoingon=true;
385 leadingedge[npeaks]=wf->GetBinLowEdge(ibin);
386 charge[npeaks]=wf->GetBinContent(ibin);
387 }
388 else
389 {
390 // Pulse continues
391 charge[npeaks]+=wf->GetBinContent(ibin);
392 }
393 }
394 else
395 {
396 if(pulsegoingon)
397 {
398 // Pulse ends here
399 tot[npeaks]=wf->GetBinLowEdge(ibin)-leadingedge[npeaks];
400
401 // Store pulse information
402 hit.Reset();
403 hit.SetSignal(charge[npeaks],"ADC");
404 hit.SetSignal(leadingedge[npeaks],"LE");
405 hit.SetSignal(tot[npeaks],"TOT");
406 omx->AddHit(hit);
407
408 // Get ready for next pulse
409 pulsegoingon=false;
410 npeaks++;
411 }
412 }
413
414 } // End of loop over bins
415 }
416
417 } // End of alternative method for narrow pulses
418
419 } // End of WF loop
420 } // End of OM loop
421
422 // Clean up
423 delete[] baseline;
424 delete[] lowend;
425 delete[] upend;
426 delete[] startcharge;
427 delete[] stopcharge;
428 delete[] status;
429 delete[] leadingedge;
430 delete[] charge;
431 delete[] tot;
432 delete[] index;
433}
434///////////////////////////////////////////////////////////////////////////
435void IceMakeHits::InIce()
436{
437// Hit extraction from IceCube InIce ATWD data.
438}
439///////////////////////////////////////////////////////////////////////////
440void IceMakeHits::IceTop()
441{
442// Hit extraction from IceTop ATWD data.
443}
444///////////////////////////////////////////////////////////////////////////