1 /**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line 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. The authors make no claims *
12 * about the suitability of this software for any purpose. It is *
13 * provided "as is" without express or implied warranty. *
14 **************************************************************************/
16 //____________________________________________________________________
17 // This is a class that constructs ReconstParticles (reconstructed
18 // particles) out of Digits
21 // This class reads either digits from a TClonesArray or raw data from
22 // a DDL file (or similar), and stores the read ADC counts in an
23 // internal cache (fAdcs).
25 // From the cached values it then calculates the number of particles
26 // that hit a region of the FMDs, as specified by the user.
28 // The reconstruction can be done in two ways: Either via counting the
29 // number of empty strips (Poisson method), or by converting the ADC
30 // signal to an energy deposition, and then dividing by the typical
31 // energy loss of a particle.
33 // Currently, this class only reads the digits from a TClonesArray,
34 // and the Poission method for reconstruction.
37 //-- Authors: Evgeny Karpechev(INR) and Alla Maevsksia
38 // Latest changes by Christian Holm Christensen <cholm@nbi.dk>
41 //____________________________________________________________________
47 # include "AliFMDDigit.h"
49 #ifndef ALIFMDPARTICLES_H
50 # include "AliFMDParticles.h"
52 #ifndef ALIFMDRECONSTRUCTOR_H
53 # include "AliFMDReconstructor.h"
55 #ifndef ALIALTROBUFFER_H
56 # include "AliAltroBuffer.h"
64 #ifndef ALIRUNLOADER_H
65 # include "AliRunLoader.h"
68 # include "AliLoader.h"
71 # include "AliHeader.h"
73 #ifndef ALIGENEVENTHEADER_H
74 # include "AliGenEventHeader.h"
76 #ifndef ALIRAWREADERFILE_H
77 # include "AliRawReaderFile.h"
79 #ifndef ALIFMDRAWSTREAM_H
80 # include "AliFMDRawStream.h"
83 //____________________________________________________________________
84 ClassImp(AliFMDReconstructor);
86 //____________________________________________________________________
87 AliFMDReconstructor::AliFMDReconstructor()
89 fAdcs(kMaxDetectors, kMaxRings, kMaxSectors, kMaxStrips),
101 fParticles = new TClonesArray("AliFMDParticles", 1000);
107 //____________________________________________________________________
109 AliFMDReconstructor::SetPedestal(Float_t mean, Float_t width)
111 // Set the pedestal, and pedestal width
113 fPedestalWidth = width;
116 //____________________________________________________________________
118 AliFMDReconstructor::Reconstruct(AliRunLoader* runLoader,
119 AliRawReader* rawReader) const
121 // Collects all digits in the same active volume into number of
124 // Reconstruct number of particles in given group of pads for given
125 // FMDvolume determined by numberOfVolume,
126 // numberOfMinSector, numberOfMaxSector, numberOfMinRing,
129 // The reconstruction method is choosen based on the number of empty
133 Error("Exec","Run Loader loader is NULL - Session not opened");
136 fRunLoader = runLoader;
137 fFMDLoader = runLoader->GetLoader("FMDLoader");
139 Fatal("AliFMDReconstructor","Can not find FMD (loader) "
140 "in specified event");
142 // Get the AliRun object
143 if (!fRunLoader->GetAliRun()) fRunLoader->LoadgAlice();
145 // Get the AliFMD object
146 fFMD = static_cast<AliFMD*>(fRunLoader->GetAliRun()->GetDetector("FMD"));
148 AliError("Can not get FMD from gAlice");
151 fFMDLoader->LoadRecPoints("RECREATE");
153 if (!fRunLoader->TreeE()) fRunLoader->LoadHeader();
155 TClonesArray* digits = fFMD->Digits();
158 while (rawReader->NextEvent()) {
159 ProcessEvent(event, rawReader, digits);
164 Int_t nEvents= Int_t(fRunLoader->TreeE()->GetEntries());
165 for(Int_t event = 0; event < nEvents; event++)
166 ProcessEvent(event, 0, digits);
170 fFMDLoader->UnloadRecPoints();
176 //____________________________________________________________________
178 AliFMDReconstructor::Reconstruct(AliRunLoader* runLoader) const
180 // Collects all digits in the same active volume into number of
183 // Reconstruct number of particles in given group of pads for given
184 // FMDvolume determined by numberOfVolume,
185 // numberOfMinSector, numberOfMaxSector, numberOfMinRing,
188 // The reconstruction method is choosen based on the number of empty
190 Reconstruct(runLoader, 0);
194 //____________________________________________________________________
196 AliFMDReconstructor::ProcessEvent(Int_t event,
197 AliRawReader* reader,
198 TClonesArray* digits) const
200 fRunLoader->GetEvent(event) ;
201 //event z-vertex for correction eta-rad dependence
202 AliHeader *header = fRunLoader->GetHeader();
204 Warning("ProcessEvent", "no AliHeader found!");
205 AliGenEventHeader* genHeader = (header ? header->GenEventHeader() : 0);
207 // Get the Z--coordinate from the event header
209 if (genHeader) genHeader->PrimaryVertex(o);
210 Float_t zVertex = o.At(2);
212 // If the recontruction tree isn't loaded, load it
213 if(fFMDLoader->TreeR()==0) fFMDLoader->MakeTree("R");
215 //Make branches to hold the reconstructed particles
216 const Int_t kBufferSize = 16000;
217 fFMDLoader->TreeR()->Branch("FMD", &fParticles, kBufferSize);
219 // Load or recreate the digits
220 if (fFMDLoader->LoadDigits((reader ? "UPDATE" : "READ"))) {
222 Error("Exec","Error occured while loading digits. Exiting.");
227 // Get the digits tree
228 TTree* digitTree = fFMDLoader->TreeD();
231 Error("Exec","Can not get Tree with Digits. "
232 "Nothing to reconstruct - Exiting");
235 fFMDLoader->MakeTree("D");
236 digitTree = fFMDLoader->TreeD();
239 // Get the FMD branch holding the digits.
240 TBranch *digitBranch = digitTree->GetBranch("FMD");
243 Error("Exec", "No digit branch for the FMD found");
246 fFMD->MakeBranchInTree(digitTree, fFMD->GetName(), &(digits), 4000, 0);
248 if (!reader) digitBranch->SetAddress(&digits);
253 if (reader) ok = ReadAdcs(reader);
254 else if (digits) ok = ReadAdcs(digits);
257 ReconstructFromCache(zVertex);
261 fFMDLoader->WriteDigits("OVERWRITE");
263 fFMDLoader->UnloadDigits();
264 fFMDLoader->TreeR()->Reset();
265 fFMDLoader->TreeR()->Fill();
266 fFMDLoader->WriteRecPoints("OVERWRITE");
269 //____________________________________________________________________
271 AliFMDReconstructor::ReadAdcs(TClonesArray* digits) const
273 AliDebug(10, "Reading ADCs from Digits array");
274 // read Digits, and reconstruct the particles
275 if (!fFMDLoader->TreeD()->GetEvent(0)) return kFALSE;
277 // Reads the digits from the array, and fills up the cache (fAdcs)
279 Int_t nDigits = digits->GetEntries();
280 for (Int_t digit = 0; digit < nDigits; digit++) {
281 AliFMDDigit* fmdDigit =
282 static_cast<AliFMDDigit*>(digits->UncheckedAt(digit));
284 ProcessDigit(fmdDigit);
289 //____________________________________________________________________
291 AliFMDReconstructor::ReadAdcs(AliRawReader* reader) const
293 AliDebug(10, "Reading ADCs from RawReader");
294 // Reads the digits from a RAW data
298 if (!reader->ReadHeader()) {
299 Error("ReadAdcs", "Couldn't read header");
303 // Use AliAltroRawStream to read the ALTRO format. No need to
304 // reinvent the wheel :-)
305 AliFMDRawStream input(reader);
307 reader->Select(AliFMD::kBaseDDL >> 8);
311 UShort_t detector = 1; // Must be one here
312 UShort_t oldDetector = 0;
313 // Loop over data in file
326 Int_t ddl = reader->GetDDLID();
328 || input.IsNewStrip()
330 // Make a new digit, if we have some data!
331 if (counts[0] >= 0) {
333 AliDebug(10, Form("Add a new strip: FMD%d%c[%2d,%3d] "
334 "(current: FMD%d%c[%2d,%3d])",
335 oldDetector, input.PrevRing(),
336 input.PrevSector() , input.PrevStrip(),
337 detector , input.Ring(), input.Sector(),
339 fFMD->AddDigit(oldDetector,
343 counts[0], counts[1], counts[2]);
345 static_cast<AliFMDDigit*>(fFMD->Digits()->
346 UncheckedAt(fFMD->GetNdigits()-1));
351 AliDebug(10, Form("Read %d channels for FMD%d",
352 count + 1, detector));
357 // If we got a new DDL, it means we have a new detector.
360 AliDebug(10, Form("Read %d channels for FMD%d",
361 count + 1, detector));
362 // Reset counts, and update the DDL cache
365 // Check that we're processing a FMD detector
366 Int_t detId = reader->GetDetectorID();
367 if (detId != (AliFMD::kBaseDDL >> 8)) {
368 Error("ReadAdcs", "Detector ID %d != %d",
369 detId, (AliFMD::kBaseDDL >> 8));
372 // Figure out what detector we're deling with
373 oldDetector = detector;
375 case 0: detector = 1; break;
376 case 1: detector = 2; break;
377 case 2: detector = 3; break;
379 Error("ReadAdcs", "Unknown DDL 0x%x for FMD", ddl);
382 AliDebug(10, Form("Reading ADCs for 0x%x - That is FMD%d",
383 reader->GetEquipmentId(), detector));
389 counts[offset] = input.Count();
392 AliDebug(10, Form("ADC of FMD%d%c[%2d,%3d] += %d",
393 detector, input.Ring(), input.Sector(),
394 input.Strip(), input.Count()));
395 oldDetector = detector;
400 //____________________________________________________________________
402 AliFMDReconstructor::ProcessDigit(AliFMDDigit* digit) const
404 // Process a digit. Derived classes can overload this member
405 // function to do stuff to the digit. However, it should write the
406 // ADC count to the internal cache
408 // fAdcs(detector - 1, ring, sector, strip) = counts;
410 // In this implementation, we count the number of strips below
411 // threshold. This we do to later choose what kind of
412 // reconstruction algorithm we'd like to use.
414 UShort_t detector = digit->Detector();
415 Char_t ring = digit->Ring();
416 UShort_t sector = digit->Sector();
417 UShort_t strip = digit->Strip();
419 UShort_t counts = SubtractPedestal(digit);
421 fAdcs(detector - 1, ring, sector, strip) = counts;
422 if (counts < fThreshold) fEmptyStrips++;
426 //____________________________________________________________________
428 AliFMDReconstructor::SubtractPedestal(AliFMDDigit* digit) const
430 // Member function to subtract the pedestal from a digit
431 // This implementation does nothing, but a derived class could over
432 // load this to subtract a pedestal that was given in a database or
433 // something like that.
436 TMath::Max(Int_t(digit->Count1() - fPedestal - 3 * fPedestalWidth), 0);
437 if (digit->Count2() >= 0)
439 TMath::Max(Int_t(digit->Count2() - fPedestal - 3 * fPedestalWidth), 0);
440 if (digit->Count3() >= 0)
442 TMath::Max(Int_t(digit->Count3() - fPedestal - 3 * fPedestalWidth), 0);
444 if (counts < 0) counts = 0;
445 return UShort_t(counts);
448 //____________________________________________________________________
450 AliFMDReconstructor::ReconstructFromCache(Float_t zVertex) const
452 // Based on the information in the cache, do the reconstruction.
454 // Loop over the detectors
455 for (Int_t i = 1; i <= 3; i++) {
456 AliFMDSubDetector* sub = 0;
458 case 1: sub = fFMD->GetFMD1(); break;
459 case 2: sub = fFMD->GetFMD2(); break;
460 case 3: sub = fFMD->GetFMD3(); break;
464 // Loop over the rings in the detector
465 for (Int_t j = 0; j < 2; j++) {
469 case 0: r = sub->GetInner(); rZ = sub->GetInnerZ(); break;
470 case 1: r = sub->GetOuter(); rZ = sub->GetOuterZ(); break;
474 // Calculate low/high theta and eta
475 // FIXME: Is this right?
476 Float_t realZ = zVertex + rZ;
477 Float_t thetaOut = TMath::ATan2(r->GetHighR(), realZ);
478 Float_t thetaIn = TMath::ATan2(r->GetLowR(), realZ);
479 Float_t etaOut = - TMath::Log(TMath::Tan(thetaOut / 2));
480 Float_t etaIn = - TMath::Log(TMath::Tan(thetaIn / 2));
481 if (TMath::Abs(etaOut) > TMath::Abs(etaIn)) {
487 //-------------------------------------------------------------
489 // Here starts poisson method
491 // Calculate eta step per strip, number of eta steps, number of
492 // phi steps, and check the sign of the eta increment
493 Float_t stripEta = (Float_t(r->GetNStrips()) / (etaIn - etaOut));
494 Int_t nEta = Int_t(TMath::Abs(etaIn - etaOut) / fDeltaEta);
495 Int_t nPhi = Int_t(360. / fDeltaPhi);
496 Float_t sign = TMath::Sign(Float_t(1.), etaIn);
498 AliDebug(10, Form("FMD%d%c Eta range: %f, %f %d Phi steps",
499 sub->GetId(), r->GetId(), etaOut, etaIn, nPhi));
501 // Loop over relevant phi values
502 for (Int_t p = 0; p < nPhi; p++) {
503 Float_t minPhi = p * fDeltaPhi;
504 Float_t maxPhi = minPhi + fDeltaPhi;
505 UShort_t minSector = UShort_t(minPhi / 360) * r->GetNSectors();
506 UShort_t maxSector = UShort_t(maxPhi / 360) * r->GetNSectors();
508 AliDebug(10, Form(" Now in phi range %f, %f (sectors %d,%d)",
509 minPhi, maxPhi, minSector, maxSector));
510 // Loop over relevant eta values
511 for (Int_t e = nEta; e >= 0; --e) {
512 Float_t maxEta = etaIn - sign * e * fDeltaEta;
513 Float_t minEta = maxEta - sign * fDeltaEta;
514 if (sign > 0) minEta = TMath::Max(minEta, etaOut);
515 else minEta = TMath::Min(minEta, etaOut);
516 Float_t theta1 = 2 * TMath::ATan(TMath::Exp(-minEta));
517 Float_t theta2 = 2 * TMath::ATan(TMath::Exp(-maxEta));
518 Float_t minR = TMath::Abs(realZ * TMath::Tan(theta2));
519 Float_t maxR = TMath::Abs(realZ * TMath::Tan(theta1));
520 UShort_t minStrip = UShort_t((etaIn - maxEta) * stripEta + 0.5);
521 UShort_t maxStrip = UShort_t((etaIn - minEta) * stripEta + 0.5);
523 AliDebug(10, Form(" Now in eta range %f, %f (strips %d, %d)\n"
524 " [radii %f, %f, thetas %f, %f, sign %d]",
525 minEta, maxEta, minStrip, maxStrip,
526 minR, maxR, theta1, theta2, sign));
528 // Count number of empty strips
529 Int_t emptyStrips = 0;
530 for (Int_t sector = minSector; sector < maxSector; sector++)
531 for (Int_t strip = minStrip; strip < maxStrip; strip++)
532 if (fAdcs(sub->GetId() - 1, r->GetId(), sector, strip)
533 < fThreshold) emptyStrips++;
535 // The total number of strips
536 Float_t nTotal = (maxSector - minSector) * (maxStrip - minStrip);
538 // Log ratio of empty to total number of strips
539 AliDebug(10, Form("Lambda= %d / %d = %f",
541 Float_t(emptyStrips) / nTotal));
543 Double_t lambda = (emptyStrips > 0 ?
544 - TMath::Log(Double_t(emptyStrips) / nTotal) :
547 // The reconstructed number of particles is then given by
548 Int_t reconstructed = Int_t(lambda * nTotal + 0.5);
550 // Add a AliFMDParticles to the reconstruction tree.
551 new((*fParticles)[nRecon])
552 AliFMDParticles(sub->GetId(), r->GetId(),
553 minSector, maxSector, minStrip, maxStrip,
554 minEta, maxEta, minPhi, maxPhi,
555 reconstructed, AliFMDParticles::kPoission);
564 //____________________________________________________________________
566 AliFMDReconstructor::FillESD(AliRunLoader* /*fRunLoader*/,
567 AliESD* /*esd*/) const
569 // nothing to be done