Line data Source code
1 : /**************************************************************************
2 : * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3 : * *
4 : * Author: The ALICE Off-line 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. 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 : **************************************************************************/
15 :
16 : // $Id$
17 :
18 :
19 : #include "AliMUONDigitizerV3.h"
20 :
21 : #include "AliMUON.h"
22 : #include "AliMUONCalibrationData.h"
23 : #include "AliMUONConstants.h"
24 : #include "AliMUONDigit.h"
25 : #include "AliMUONLogger.h"
26 : #include "AliMUONTriggerElectronics.h"
27 : #include "AliMUONTriggerStoreV1.h"
28 : #include "AliMUONVCalibParam.h"
29 : #include "AliMUONVDigitStore.h"
30 : #include "AliMUONGeometryTransformer.h" //ADDED for trigger noise
31 : #include "AliMUONRecoParam.h"
32 : #include "AliMUONTriggerChamberEfficiency.h"
33 : #include "AliMUONTriggerUtilities.h"
34 :
35 : #include "AliMpCDB.h"
36 : #include "AliMpSegmentation.h"
37 : #include "AliMpCathodType.h"
38 : #include "AliMpConstants.h"
39 : #include "AliMpDEIterator.h"
40 : #include "AliMpDEManager.h"
41 : #include "AliMpPad.h"
42 : #include "AliMpStationType.h"
43 : #include "AliMpVSegmentation.h"
44 : #include "AliMpDDLStore.h"
45 :
46 : #include "AliCDBManager.h"
47 : #include "AliCodeTimer.h"
48 : #include "AliLog.h"
49 : #include "AliRun.h"
50 : #include "AliDigitizationInput.h"
51 : #include "AliLoader.h"
52 : #include "AliRunLoader.h"
53 :
54 : #include <Riostream.h>
55 : #include <TF1.h>
56 : #include <TFile.h>
57 : #include <TMath.h>
58 : #include <TRandom.h>
59 : #include <TString.h>
60 : #include <TSystem.h>
61 : #include <TTree.h>
62 :
63 : //-----------------------------------------------------------------------------
64 : /// \class AliMUONDigitizerV3
65 : ///
66 : /// The digitizer is performing the transformation to go from SDigits (digits
67 : /// w/o any electronic noise) to Digits (w/ electronic noise, and decalibration)
68 : ///
69 : /// The decalibration is performed by doing the reverse operation of the
70 : /// calibration, that is we do (Signal+pedestal)/gain -> ADC
71 : ///
72 : /// Note also that the digitizer takes care of merging sdigits that belongs
73 : /// to the same pad, either because we're merging several input sdigit files
74 : /// or with a single file because the sdigitizer does not merge sdigits itself
75 : /// (for performance reason mainly, and because anyway we know we have to do it
76 : /// here, at the digitization level).
77 : ///
78 : /// August 2011. In order to remove the need for specific MC OCDB storages,
79 : /// we're introducing a dependence of simulation on AliMUONRecoParam (stored
80 : /// in MUON/Calib/RecoParam in OCDB), which is normally (or conceptually, if
81 : /// you will) only a reconstruction object. That's not a pretty solution, but,
82 : /// well, we have to do it...
83 : /// This dependence comes from the fact that we must know how to decalibrate
84 : /// the digits, so that the decalibration (done here) - calibration (done during
85 : /// reco) process is (as much as possible) neutral.
86 : ///
87 : ///
88 : /// \author Laurent Aphecetche
89 : ///
90 : //-----------------------------------------------------------------------------
91 :
92 : namespace
93 : {
94 : AliMUON* muon()
95 : {
96 2 : return static_cast<AliMUON*>(gAlice->GetModule("MUON"));
97 : }
98 :
99 : //ADDED for trigger noise
100 : const AliMUONGeometryTransformer* GetTransformer()
101 : {
102 0 : return muon()->GetGeometryTransformer();
103 : }
104 : }
105 :
106 : Double_t AliMUONDigitizerV3::fgNSigmas = 4.0;
107 :
108 : /// \cond CLASSIMP
109 16 : ClassImp(AliMUONDigitizerV3)
110 : /// \endcond
111 :
112 : //_____________________________________________________________________________
113 : AliMUONDigitizerV3::AliMUONDigitizerV3(AliDigitizationInput* digInput,
114 : Int_t generateNoisyDigits)
115 1 : : AliDigitizer(digInput),
116 1 : fIsInitialized(kFALSE),
117 1 : fCalibrationData(0x0),
118 1 : fTriggerProcessor(0x0),
119 1 : fNoiseFunctionTrig(0x0),
120 1 : fGenerateNoisyDigits(generateNoisyDigits),
121 3 : fLogger(new AliMUONLogger(4207)), /* 4207 = 25% of the 16828 MCH manus */
122 3 : fTriggerStore(new AliMUONTriggerStoreV1),
123 1 : fDigitStore(0x0),
124 1 : fOutputDigitStore(0x0),
125 1 : fInputDigitStores(0x0),
126 1 : fRecoParam(0x0),
127 1 : fTriggerEfficiency(0x0),
128 1 : fTriggerUtilities(0x0),
129 2 : fEfficiencyResponse(2*AliMUONConstants::NTriggerCh()*AliMUONConstants::NTriggerCircuit())
130 5 : {
131 : /// Ctor.
132 :
133 5 : AliDebug(1,Form("AliDigitizationInput=%p",fDigInput));
134 :
135 2 : }
136 :
137 : //_____________________________________________________________________________
138 : AliMUONDigitizerV3::~AliMUONDigitizerV3()
139 6 : {
140 : /// Dtor. Note we're the owner of some pointers.
141 :
142 5 : AliDebug(1,"dtor");
143 :
144 : // delete fCalibrationData;
145 2 : delete fTriggerProcessor;
146 1 : delete fNoiseFunctionTrig;
147 2 : delete fTriggerStore;
148 2 : delete fDigitStore;
149 2 : delete fOutputDigitStore;
150 2 : delete fInputDigitStores;
151 2 : delete fTriggerUtilities;
152 :
153 2 : AliInfo("Summary of messages");
154 1 : fLogger->Print();
155 :
156 2 : delete fLogger;
157 3 : }
158 :
159 : //_____________________________________________________________________________
160 : void
161 : AliMUONDigitizerV3::ApplyResponseToTrackerDigit(AliMUONVDigit& digit, Bool_t addNoise)
162 : {
163 : /// For tracking digits, starting from an ideal digit's charge, we :
164 : ///
165 : /// - "divide" by a gain (thus decalibrating the digit)
166 : /// - add a pedestal (thus decalibrating the digit)
167 : /// - add some electronics noise (thus leading to a realistic adc), if requested to do so
168 : /// - sets the signal to zero if below 3*sigma of the noise
169 :
170 857 : Float_t charge = digit.Charge();
171 :
172 857 : if (!digit.IsChargeInFC())
173 : {
174 0 : charge *= AliMUONConstants::DefaultADC2MV()*AliMUONConstants::DefaultA0()*AliMUONConstants::DefaultCapa();
175 0 : fLogger->Log("CHECK ME ! WAS NOT SUPPOSED TO BE HERE !!! ARE YOU RECONSTRUCTING OLD SIMULATIONS ? ");
176 0 : AliError("CHECK ME ! WAS NOT SUPPOSED TO BE HERE !!! ARE YOU RECONSTRUCTING OLD SIMULATIONS ? ");
177 0 : }
178 :
179 : // We set the charge to 0, as the only relevant piece of information
180 : // after Digitization is the ADC value.
181 857 : digit.SetCharge(0);
182 :
183 857 : Int_t detElemId = digit.DetElemId();
184 857 : Int_t manuId = digit.ManuId();
185 :
186 857 : AliMUONVCalibParam* pedestal = fCalibrationData->Pedestals(detElemId,manuId);
187 857 : if (!pedestal)
188 : {
189 0 : fLogger->Log(Form("%s:%d:Could not get pedestal for DE=%4d manuId=%4d. Disabling.",
190 : __FILE__,__LINE__,
191 : detElemId,manuId));
192 0 : digit.SetADC(0);
193 0 : return;
194 : }
195 :
196 857 : Int_t manuChannel = digit.ManuChannel();
197 :
198 1714 : if ( pedestal->ValueAsFloat(manuChannel,0) == AliMUONVCalibParam::InvalidFloatValue() ||
199 857 : pedestal->ValueAsFloat(manuChannel,1) == AliMUONVCalibParam::InvalidFloatValue() )
200 : {
201 : // protection against invalid pedestal value
202 0 : digit.SetADC(0);
203 0 : return;
204 : }
205 :
206 1714 : Int_t adc = DecalibrateTrackerDigit(*pedestal,manuChannel,charge,addNoise,
207 857 : digit.IsNoiseOnly());
208 :
209 857 : digit.SetADC(adc);
210 1714 : }
211 :
212 :
213 : //_____________________________________________________________________________
214 : void
215 : AliMUONDigitizerV3::ApplyResponseToTriggerDigit(AliMUONVDigit& digit)
216 : {
217 : /// For trigger digits, starting from an ideal digit, we :
218 : ///
219 : /// - apply efficiency (on demand)
220 : /// - apply trigger masks
221 :
222 224 : Int_t detElemId = digit.DetElemId();
223 112 : Int_t localCircuit = digit.ManuId();
224 112 : Int_t strip = digit.ManuChannel();
225 112 : Int_t cathode = digit.Cathode();
226 112 : Int_t trigCh = detElemId/100 - 11;
227 :
228 : // Masked channels
229 112 : Bool_t isMasked = fTriggerUtilities->IsMasked(digit);
230 336 : AliDebug(1,Form("detElemId %i cath %i board %i strip %i is masked %i\n", detElemId, cathode, localCircuit, strip, isMasked));
231 112 : if ( isMasked ) {
232 0 : digit.SetCharge(0);
233 0 : digit.SetADC(0);
234 : //AliDebug(1,Form("ch %i cath %i board %i strip %i masked\n", trigCh, cathode, localCircuit, strip));
235 0 : return;
236 : }
237 :
238 :
239 112 : Int_t arrayIndex = GetArrayIndex(cathode, trigCh, localCircuit);
240 :
241 : // Trigger chamber efficiency
242 112 : if ( fTriggerEfficiency ) {
243 112 : if ( fEfficiencyResponse[arrayIndex] < 0 ) {
244 43 : Bool_t isTrig[2] = {kTRUE, kTRUE};
245 43 : fTriggerEfficiency->IsTriggered(detElemId, localCircuit, isTrig[0], isTrig[1]);
246 43 : Int_t arrayIndexBend = GetArrayIndex(0, trigCh, localCircuit);
247 43 : Int_t arrayIndexNonBend = GetArrayIndex(1, trigCh, localCircuit);
248 43 : fEfficiencyResponse[arrayIndexBend] = isTrig[0];
249 43 : fEfficiencyResponse[arrayIndexNonBend] = isTrig[1];
250 43 : }
251 336 : AliDebug(1,Form("detElemId %i cath %i board %i strip %i efficiency %i\n", detElemId, cathode, localCircuit, strip, fEfficiencyResponse[arrayIndex]));
252 112 : if ( fEfficiencyResponse[arrayIndex] == 0 ) {
253 0 : digit.SetCharge(0);
254 0 : digit.SetADC(0);
255 : //AliDebug(1,Form("ch %i cath %i board %i strip %i NOT efficient\n", trigCh, cathode, localCircuit, strip));
256 0 : return;
257 : }
258 : }
259 224 : }
260 :
261 :
262 :
263 : //_____________________________________________________________________________
264 : void
265 : AliMUONDigitizerV3::ApplyResponse(const AliMUONVDigitStore& store,
266 : AliMUONVDigitStore& filteredStore)
267 : {
268 : /// Loop over all chamber digits, and apply the response to them
269 : /// Note that this method may remove digits.
270 :
271 8 : filteredStore.Clear();
272 :
273 : const Bool_t kAddNoise = kTRUE;
274 :
275 4 : TIter next(store.CreateIterator());
276 : AliMUONVDigit* digit;
277 :
278 8 : if ( fTriggerEfficiency ) fEfficiencyResponse.Reset(-1);
279 :
280 2915 : while ( ( digit = static_cast<AliMUONVDigit*>(next()) ) )
281 : {
282 1938 : AliMp::StationType stationType = AliMpDEManager::GetStationType(digit->DetElemId());
283 :
284 969 : if ( stationType != AliMp::kStationTrigger )
285 : {
286 : Bool_t addNoise = kAddNoise;
287 1714 : if (digit->IsConverted()) addNoise = kFALSE; // No need to add extra noise to a converted real digit
288 857 : ApplyResponseToTrackerDigit(*digit,addNoise);
289 857 : }
290 : else {
291 112 : ApplyResponseToTriggerDigit(*digit);
292 : }
293 :
294 2460 : if ( digit->ADC() > 0 || digit->Charge() > 0 )
295 : {
296 820 : filteredStore.Add(*digit,AliMUONVDigitStore::kIgnore);
297 : }
298 : }
299 4 : }
300 :
301 : //_____________________________________________________________________________
302 : Int_t
303 : AliMUONDigitizerV3::DecalibrateTrackerDigit(const AliMUONVCalibParam& pedestals,
304 : Int_t channel,
305 : Float_t charge,
306 : Bool_t addNoise,
307 : Bool_t noiseOnly)
308 : {
309 : /// Decalibrate (i.e. go from charge to adc) a tracker digit, given its
310 : /// pedestal and gain parameters.
311 : /// Must insure before calling that channel is valid (i.e. between 0 and
312 : /// pedestals->GetSize()-1, but also corresponding to a valid channel
313 : /// otherwise results are not predictible...)
314 : ///
315 : /// This method is completely tied to what happens in its sister method :
316 : /// AliMUONDigitCalibrator::CalibrateDigit, which is doing the reverse work...
317 : ///
318 :
319 : static const Int_t kMaxADC = (1<<12)-1; // We code the charge on a 12 bits ADC.
320 :
321 : Int_t thres(4095);
322 : Int_t qual(0xF);
323 857 : Float_t capa(AliMUONConstants::DefaultCapa()); // capa = 0.2 and a0 = 1.25
324 857 : Float_t a0(AliMUONConstants::DefaultA0()); // is equivalent to gain = 4 mV/fC
325 857 : Float_t adc2mv(AliMUONConstants::DefaultADC2MV()); // 1 ADC channel = 0.61 mV
326 :
327 857 : Float_t pedestalMean = pedestals.ValueAsFloat(channel,0);
328 857 : Float_t pedestalSigma = pedestals.ValueAsFloat(channel,1);
329 :
330 2571 : AliDebugClass(2,Form("DE %04d MANU %04d CH %02d PEDMEAN %7.2f PEDSIGMA %7.2f",
331 : pedestals.ID0(),pedestals.ID1(),channel,pedestalMean,pedestalSigma));
332 :
333 857 : if ( qual <= 0 ) return 0;
334 :
335 : Float_t chargeThres = a0*thres;
336 :
337 857 : Float_t padc = charge/a0; // (adc - ped) value
338 :
339 857 : padc /= capa*adc2mv;
340 :
341 : Int_t adc(0);
342 :
343 : Float_t adcNoise = 0.0;
344 :
345 857 : if ( addNoise )
346 : {
347 857 : if ( noiseOnly )
348 : {
349 0 : adcNoise = NoiseFunction()->GetRandom()*pedestalSigma;
350 0 : }
351 : else
352 : {
353 857 : adcNoise = gRandom->Gaus(0.0,pedestalSigma);
354 : }
355 : }
356 :
357 857 : adc = TMath::Nint(padc + pedestalMean + adcNoise + 0.5);
358 :
359 857 : if ( adc < TMath::Nint(pedestalMean + fgNSigmas*pedestalSigma + 0.5) )
360 : {
361 : // this is an error only in specific cases
362 447 : if ( !addNoise || (addNoise && noiseOnly) )
363 : {
364 0 : AliDebugClass(1,Form(" DE %04d Manu %04d Channel %02d "
365 : " a0 %7.2f thres %04d ped %7.2f pedsig %7.2f adcNoise %7.2f "
366 : " charge=%7.2f padc=%7.2f adc=%04d ZS=%04d fgNSigmas=%e addNoise %d noiseOnly %d ",
367 : pedestals.ID0(),pedestals.ID1(),channel,
368 : a0, thres, pedestalMean, pedestalSigma, adcNoise,
369 : charge, padc, adc,
370 : TMath::Nint(pedestalMean + fgNSigmas*pedestalSigma + 0.5),
371 : fgNSigmas,addNoise,noiseOnly));
372 : }
373 :
374 : adc = 0;
375 149 : }
376 :
377 : // be sure we stick to 12 bits.
378 857 : if ( adc > kMaxADC )
379 : {
380 : adc = kMaxADC;
381 0 : }
382 :
383 : return adc;
384 857 : }
385 :
386 : //_____________________________________________________________________________
387 : void
388 : AliMUONDigitizerV3::CreateInputDigitStores()
389 : {
390 : /// Create input digit stores
391 : ///
392 :
393 2 : if (fInputDigitStores)
394 : {
395 0 : AliFatal("Should be called only once !");
396 0 : }
397 :
398 2 : fInputDigitStores = new TObjArray;
399 :
400 1 : fInputDigitStores->SetOwner(kTRUE);
401 :
402 4 : for ( Int_t iFile = 0; iFile < fDigInput->GetNinputs(); ++iFile )
403 : {
404 1 : AliLoader* inputLoader = GetLoader(fDigInput->GetInputFolderName(iFile));
405 :
406 1 : inputLoader->LoadSDigits("READ");
407 :
408 1 : TTree* iTreeS = inputLoader->TreeS();
409 1 : if (!iTreeS)
410 : {
411 0 : AliFatal(Form("Could not get access to input file #%d",iFile));
412 0 : }
413 :
414 1 : fInputDigitStores->AddAt(AliMUONVDigitStore::Create(*iTreeS),iFile);
415 : }
416 1 : }
417 :
418 : //_____________________________________________________________________________
419 : void
420 : AliMUONDigitizerV3::Digitize(Option_t*)
421 : {
422 : /// Main method.
423 : /// We first loop over input files, and merge the sdigits we found there.
424 : /// Second, we digitize all the resulting sdigits
425 : /// Then we generate noise-only digits (for tracker only)
426 : /// And we finally generate the trigger outputs.
427 :
428 8 : AliCodeTimerAuto("",0)
429 :
430 4 : if ( fDigInput->GetNinputs() == 0 )
431 : {
432 0 : AliWarning("No input set. Nothing to do.");
433 0 : return;
434 : }
435 :
436 4 : if ( !fIsInitialized )
437 : {
438 0 : AliError("Not initialized. Cannot perform the work. Sorry");
439 0 : return;
440 : }
441 :
442 4 : Int_t nInputFiles = fDigInput->GetNinputs();
443 :
444 16 : AliLoader* outputLoader = GetLoader(fDigInput->GetOutputFolderName());
445 :
446 4 : outputLoader->MakeDigitsContainer();
447 :
448 4 : TTree* oTreeD = outputLoader->TreeD();
449 :
450 4 : if (!oTreeD)
451 : {
452 0 : AliFatal("Cannot create output TreeD");
453 : }
454 :
455 : // Loop over all the input files, and merge the sdigits found in those
456 : // files.
457 :
458 16 : for ( Int_t iFile = 0; iFile < nInputFiles; ++iFile )
459 : {
460 8 : AliLoader* inputLoader = GetLoader(fDigInput->GetInputFolderName(iFile));
461 :
462 4 : inputLoader->LoadSDigits("READ");
463 :
464 4 : TTree* iTreeS = inputLoader->TreeS();
465 4 : if (!iTreeS)
466 : {
467 0 : AliFatal(Form("Could not get access to input file #%d",iFile));
468 : }
469 :
470 4 : if (!fInputDigitStores)
471 : {
472 1 : CreateInputDigitStores();
473 : }
474 :
475 8 : AliMUONVDigitStore* dstore = static_cast<AliMUONVDigitStore*>(fInputDigitStores->At(iFile));
476 :
477 4 : dstore->Connect(*iTreeS);
478 :
479 4 : iTreeS->GetEvent(0);
480 :
481 4 : MergeWithSDigits(fDigitStore,*dstore,fDigInput->GetMask(iFile));
482 :
483 4 : inputLoader->UnloadSDigits();
484 :
485 4 : dstore->Clear();
486 : }
487 :
488 :
489 : // At this point, we do have digit arrays (one per chamber) which contains
490 : // the merging of all the sdigits of the input file(s).
491 : // We now massage them to apply the detector response, i.e. this
492 : // is here that we do the "digitization" work.
493 :
494 4 : if (!fOutputDigitStore)
495 : {
496 2 : fOutputDigitStore = fDigitStore->Create();
497 1 : }
498 :
499 4 : if ( fGenerateNoisyDigits>=2 )
500 : {
501 : // Generate noise-only digits for trigger.
502 0 : GenerateNoisyDigitsForTrigger(*fDigitStore);
503 : }
504 4 : ApplyResponse(*fDigitStore,*fOutputDigitStore);
505 :
506 4 : if ( fGenerateNoisyDigits )
507 : {
508 : // Generate noise-only digits for tracker.
509 4 : GenerateNoisyDigits(*fOutputDigitStore);
510 : }
511 :
512 : // We generate the global and local trigger decisions.
513 4 : fTriggerProcessor->Digits2Trigger(*fOutputDigitStore,*fTriggerStore);
514 :
515 : // Prepare output tree
516 8 : Bool_t okD = fOutputDigitStore->Connect(*oTreeD,kFALSE);
517 8 : Bool_t okT = fTriggerStore->Connect(*oTreeD,kFALSE);
518 8 : if (!okD || !okT)
519 : {
520 0 : AliError(Form("Could not make branch : Digit %d Trigger %d",okD,okT));
521 0 : return;
522 : }
523 :
524 : // Fill the output treeD
525 4 : oTreeD->Fill();
526 :
527 : // Write to the output tree(D).
528 : // Please note that as GlobalTrigger, LocalTrigger and Digits are in the same
529 : // tree (=TreeD) in different branches, this WriteDigits in fact writes all of
530 : // the 3 branches.
531 4 : outputLoader->WriteDigits("OVERWRITE");
532 :
533 4 : outputLoader->UnloadDigits();
534 :
535 : // Finally, we clean up after ourselves.
536 4 : fTriggerStore->Clear();
537 4 : fDigitStore->Clear();
538 4 : fOutputDigitStore->Clear();
539 8 : }
540 :
541 :
542 : //_____________________________________________________________________________
543 : void
544 : AliMUONDigitizerV3::GenerateNoisyDigits(AliMUONVDigitStore& digitStore)
545 : {
546 : /// According to a given probability, generate digits that
547 : /// have a signal above the noise cut (ped+n*sigma_ped), i.e. digits
548 : /// that are "only noise".
549 :
550 8 : AliCodeTimerAuto("",0)
551 :
552 132 : for ( Int_t i = 0; i < AliMUONConstants::NTrackingCh(); ++i )
553 : {
554 40 : AliMpDEIterator it;
555 :
556 40 : it.First(i);
557 :
558 1328 : while ( !it.IsDone() )
559 : {
560 3744 : for ( Int_t cathode = 0; cathode < 2; ++cathode )
561 : {
562 2496 : GenerateNoisyDigitsForOneCathode(digitStore,it.CurrentDEId(),cathode);
563 : }
564 624 : it.Next();
565 : }
566 40 : }
567 4 : }
568 :
569 : //_____________________________________________________________________________
570 : void
571 : AliMUONDigitizerV3::GenerateNoisyDigitsForOneCathode(AliMUONVDigitStore& digitStore,
572 : Int_t detElemId, Int_t cathode)
573 : {
574 : /// Generate noise-only digits for one cathode of one detection element.
575 : /// Called by GenerateNoisyDigits()
576 :
577 : const AliMpVSegmentation* seg
578 2496 : = AliMpSegmentation::Instance()->GetMpSegmentation(detElemId,AliMp::GetCathodType(cathode));
579 1248 : Int_t nofPads = seg->NofPads();
580 :
581 1248 : Int_t maxIx = seg->MaxPadIndexX();
582 1248 : Int_t maxIy = seg->MaxPadIndexY();
583 :
584 1251 : static const Double_t kProbToBeOutsideNsigmas = TMath::Erfc(fgNSigmas/TMath::Sqrt(2.0)) / 2. ;
585 :
586 1248 : Int_t nofNoisyPads = TMath::Nint(kProbToBeOutsideNsigmas*nofPads);
587 2496 : if ( !nofNoisyPads ) return;
588 :
589 : nofNoisyPads =
590 0 : TMath::Nint(gRandom->Gaus(nofNoisyPads,
591 0 : nofNoisyPads/TMath::Sqrt(nofNoisyPads)));
592 :
593 0 : AliDebug(3,Form("DE %d cath %d nofNoisyPads %d",detElemId,cathode,nofNoisyPads));
594 :
595 0 : for ( Int_t i = 0; i < nofNoisyPads; ++i )
596 : {
597 : Int_t ix(-1);
598 : Int_t iy(-1);
599 0 : AliMpPad pad;
600 :
601 0 : do {
602 0 : ix = gRandom->Integer(maxIx+1);
603 0 : iy = gRandom->Integer(maxIy+1);
604 0 : pad = seg->PadByIndices(ix,iy,kFALSE);
605 0 : } while ( !pad.IsValid() );
606 :
607 0 : Int_t manuId = pad.GetManuId();
608 0 : Int_t manuChannel = pad.GetManuChannel();
609 :
610 0 : AliMUONVCalibParam* pedestals = fCalibrationData->Pedestals(detElemId,manuId);
611 :
612 0 : if (!pedestals)
613 : {
614 : // no pedestal available for this channel, simply give up
615 0 : continue;
616 : }
617 :
618 0 : AliMUONVDigit* d = digitStore.CreateDigit(detElemId,manuId,manuChannel,cathode);
619 :
620 0 : d->SetPadXY(ix,iy);
621 :
622 0 : d->SetCharge(0.0); // charge is zero, the ApplyResponseToTrackerDigit will add the noise
623 0 : d->NoiseOnly(kTRUE);
624 0 : ApplyResponseToTrackerDigit(*d,kTRUE);
625 0 : if ( d->ADC() > 0 )
626 : {
627 0 : Bool_t ok = digitStore.Add(*d,AliMUONVDigitStore::kDeny);
628 : // this can happen (that we randomly chose a digit that is
629 : // already there). We simply ignore this, but log the occurence
630 : // to cross-check that it's not too frequent.
631 0 : if (!ok)
632 : {
633 0 : fLogger->Log("Collision while adding noiseOnly digit");
634 : }
635 : else
636 : {
637 0 : fLogger->Log("Added noiseOnly digit");
638 : }
639 0 : }
640 0 : delete d;
641 0 : }
642 1248 : }
643 :
644 :
645 : //_____________________________________________________________________________
646 : void
647 : AliMUONDigitizerV3::GenerateNoisyDigitsForTrigger(AliMUONVDigitStore& digitStore)
648 : {
649 : /// Generate noise-only digits for one cathode of one detection element.
650 : /// Called by GenerateNoisyDigits()
651 :
652 0 : if ( !fNoiseFunctionTrig )
653 : {
654 0 : fNoiseFunctionTrig = new TF1("AliMUONDigitizerV3::fNoiseFunctionTrig","landau",
655 : 50.,270.);
656 :
657 0 : fNoiseFunctionTrig->SetParameters(3.91070e+02, 9.85026, 9.35881e-02);
658 0 : }
659 :
660 0 : AliMpPad pad[2];
661 0 : AliMUONVDigit *d[2]={0x0};
662 :
663 0 : for ( Int_t chamberId = AliMUONConstants::NTrackingCh(); chamberId < AliMUONConstants::NCh(); ++chamberId )
664 : {
665 :
666 : Int_t nofNoisyPads = 50;
667 :
668 0 : Float_t r=-1, fi = 0., gx, gy, x, y, z, xg01, yg01, zg, xg02, yg02;
669 0 : AliMpDEIterator it;
670 :
671 0 : AliDebug(3,Form("Chamber %d nofNoisyPads %d",chamberId,nofNoisyPads));
672 :
673 0 : for ( Int_t i = 0; i < nofNoisyPads; ++i )
674 : {
675 : //printf("Generating noise %i\n",i);
676 : Int_t ix(-1);
677 : Int_t iy(-1);
678 : Bool_t isOk = kFALSE;
679 : Int_t detElemId = -1;
680 0 : do {
681 : //r = gRandom->Landau(9.85026, 9.35881e-02);
682 0 : r = fNoiseFunctionTrig->GetRandom();
683 0 : fi = 2. * TMath::Pi() * gRandom->Rndm();
684 : //printf("r = %f\tfi = %f\n", r, fi);
685 0 : gx = r * TMath::Cos(fi);
686 0 : gy = r * TMath::Sin(fi);
687 :
688 0 : for ( it.First(chamberId); ! it.IsDone(); it.Next() ){
689 0 : Int_t currDetElemId = it.CurrentDEId();
690 : const AliMpVSegmentation* seg
691 0 : = AliMpSegmentation::Instance()->GetMpSegmentation(currDetElemId,AliMp::GetCathodType(0));
692 0 : if (!seg) continue;
693 0 : Float_t deltax = seg->GetDimensionX();
694 0 : Float_t deltay = seg->GetDimensionY();
695 0 : GetTransformer()->Local2Global(currDetElemId, -deltax, -deltay, 0, xg01, yg01, zg);
696 0 : GetTransformer()->Local2Global(currDetElemId, deltax, deltay, 0, xg02, yg02, zg);
697 0 : Float_t xg1 = xg01, xg2 = xg02, yg1 = yg01, yg2 = yg02;
698 0 : if(xg01>xg02){
699 : xg1 = xg02;
700 : xg2 = xg01;
701 0 : }
702 0 : if(yg01>yg02){
703 : yg1 = yg02;
704 : yg2 = yg01;
705 0 : }
706 0 : if(gx>=xg1 && gx<=xg2 && gy>=yg1 && gy<=yg2){
707 : detElemId = currDetElemId;
708 0 : GetTransformer()->Global2Local(detElemId, gx, gy, 0, x, y, z);
709 0 : pad[0] = seg->PadByPosition(x,y,kFALSE);
710 0 : if(!pad[0].IsValid()) continue;
711 : isOk = kTRUE;
712 0 : break;
713 : }
714 0 : } // loop on slats
715 0 : } while ( !isOk );
716 :
717 : const AliMpVSegmentation* seg1
718 0 : = AliMpSegmentation::Instance()->GetMpSegmentation(detElemId,AliMp::GetCathodType(1));
719 0 : pad[1] = seg1->PadByPosition(x,y,kFALSE);
720 :
721 0 : for ( Int_t cathode = 0; cathode < 2; ++cathode ){
722 0 : Int_t manuId = pad[cathode].GetLocalBoardId(0);
723 0 : Int_t manuChannel = pad[cathode].GetLocalBoardChannel(0);
724 0 : d[cathode] = digitStore.CreateDigit(detElemId,manuId,manuChannel,cathode);
725 0 : ix = pad[cathode].GetIx();
726 0 : iy = pad[cathode].GetIy();
727 0 : d[cathode]->SetPadXY(ix,iy);
728 : //d[cathode].SetSignal(1);
729 : //d[cathode].SetPhysicsSignal(0);
730 0 : d[cathode]->SetCharge(1);
731 0 : d[cathode]->NoiseOnly(kTRUE);
732 0 : AliDebug(3,Form("Adding a pure noise digit :"));
733 :
734 0 : Bool_t ok = digitStore.Add(*d[cathode],AliMUONVDigitStore::kDeny);
735 0 : if (!ok)
736 : {
737 0 : fLogger->Log("Collision while adding TriggerNoise digit");
738 : }
739 : else
740 : {
741 0 : fLogger->Log("Added triggerNoise digit");
742 : }
743 : } //loop on cathodes
744 : } // loop on noisy pads
745 0 : } // loop on chambers
746 0 : }
747 :
748 :
749 : //_____________________________________________________________________________
750 : AliLoader*
751 : AliMUONDigitizerV3::GetLoader(const TString& folderName)
752 : {
753 : /// Get a MUON loader
754 :
755 36 : AliDebug(2,Form("Getting access to folder %s",folderName.Data()));
756 9 : AliLoader* loader = AliRunLoader::GetDetectorLoader("MUON",folderName.Data());
757 9 : if (!loader)
758 : {
759 0 : AliError(Form("Could not get MuonLoader from folder %s",folderName.Data()));
760 0 : return 0x0;
761 : }
762 9 : return loader;
763 9 : }
764 :
765 : //_____________________________________________________________________________
766 : Bool_t
767 : AliMUONDigitizerV3::Init()
768 : {
769 : /// Initialization of the digitization :
770 : /// a) create the calibrationData, according to run number
771 : /// b) create the trigger processing task
772 :
773 4 : AliDebug(2,"");
774 :
775 1 : if ( fIsInitialized )
776 : {
777 0 : AliError("Object already initialized.");
778 0 : return kFALSE;
779 : }
780 :
781 1 : if (!fDigInput)
782 : {
783 0 : AliError("fDigInput is null !");
784 0 : return kFALSE;
785 : }
786 :
787 : // Load mapping
788 1 : if ( ! AliMpCDB::LoadDDLStore() ) {
789 0 : AliFatal("Could not access mapping from OCDB !");
790 0 : }
791 :
792 1 : if (!fCalibrationData)
793 0 : AliFatal("Calibration data object not defined");
794 :
795 1 : if ( !fCalibrationData->Pedestals() )
796 : {
797 0 : AliFatal("Could not access pedestals from OCDB !");
798 0 : }
799 :
800 1 : AliInfo("Using trigger configuration from CDB");
801 :
802 2 : fTriggerProcessor = new AliMUONTriggerElectronics(fCalibrationData);
803 :
804 3 : AliDebug(1, Form("Will %s generate noise-only digits for tracker",
805 : (fGenerateNoisyDigits ? "":"NOT")));
806 :
807 2 : fTriggerUtilities = new AliMUONTriggerUtilities(fCalibrationData);
808 :
809 1 : if ( muon()->GetTriggerEffCells() ) {
810 : // Apply trigger efficiency
811 3 : AliDebug(1, "Will apply trigger efficiency");
812 3 : fTriggerEfficiency = new AliMUONTriggerChamberEfficiency(fCalibrationData->TriggerEfficiency());
813 1 : }
814 :
815 1 : fIsInitialized = kTRUE;
816 1 : return kTRUE;
817 1 : }
818 :
819 :
820 : //_____________________________________________________________________________
821 : Int_t AliMUONDigitizerV3::GetArrayIndex(Int_t cathode, Int_t trigCh, Int_t localCircuit)
822 : {
823 : /// Get index of array with trigger status map or efficiency
824 198 : return
825 594 : AliMUONConstants::NTriggerCircuit() * AliMUONConstants::NTriggerCh() * cathode +
826 396 : AliMUONConstants::NTriggerCircuit() * trigCh + localCircuit-1;
827 : }
828 :
829 :
830 : //_____________________________________________________________________________
831 : void
832 : AliMUONDigitizerV3::MergeWithSDigits(AliMUONVDigitStore*& outputStore,
833 : const AliMUONVDigitStore& input,
834 : Int_t mask)
835 : {
836 : /// Merge the sdigits in inputData with the digits already present in outputData
837 :
838 9 : if ( !outputStore ) outputStore = input.Create();
839 :
840 4 : TIter next(input.CreateIterator());
841 : AliMUONVDigit* sdigit;
842 :
843 2919 : while ( ( sdigit = static_cast<AliMUONVDigit*>(next()) ) )
844 : {
845 : // Update the track references using the mask.
846 : // FIXME: this is dirty, for backward compatibility only.
847 : // Should re-design all this way of keeping track of MC information...
848 969 : if ( mask ) sdigit->PatchTracks(mask);
849 : // Then add or update the digit to the output.
850 969 : AliMUONVDigit* added = outputStore->Add(*sdigit,AliMUONVDigitStore::kMerge);
851 969 : if (!added)
852 : {
853 0 : AliError("Could not add digit in merge mode");
854 : }
855 : }
856 4 : }
857 :
858 : //_____________________________________________________________________________
859 : TF1*
860 : AliMUONDigitizerV3::NoiseFunction()
861 : {
862 : /// Return noise function
863 : static TF1* f = 0x0;
864 0 : if (!f)
865 : {
866 0 : f = new TF1("AliMUONDigitizerV3::NoiseFunction","gaus",fgNSigmas,fgNSigmas*10);
867 0 : f->SetParameters(1,0,1);
868 0 : }
869 0 : return f;
870 0 : }
871 :
872 : //_____________________________________________________________________________
873 : void AliMUONDigitizerV3::SetCalibrationData(AliMUONCalibrationData* calibrationData,
874 : AliMUONRecoParam* recoParam)
875 : {
876 2 : fCalibrationData = calibrationData;
877 1 : fRecoParam = recoParam;
878 1 : if (!fRecoParam)
879 : {
880 0 : AliError("Cannot work (e.g. decalibrate) without recoparams !");
881 0 : }
882 1 : }
883 :
|