]> git.uio.no Git - u/mrichter/AliRoot.git/blame - PHOS/AliPHOSDigitizer.cxx
Fix which prevents the decoder crash in case of corrupted RCU trailer data (Per Thomas)
[u/mrichter/AliRoot.git] / PHOS / AliPHOSDigitizer.cxx
CommitLineData
990119d6 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
702ab87e 18/* History of cvs commits:
19 *
20 * $Log$
b8274834 21 * Revision 1.99 2007/09/30 17:08:20 schutz
22 * Introducing the notion of QA data acquisition cycle (needed by online)
23 *
5b188f2f 24 * Revision 1.98 2007/09/26 14:22:17 cvetan
25 * Important changes to the reconstructor classes. Complete elimination of the run-loaders, which are now steered only from AliReconstruction. Removal of the corresponding Reconstruct() and FillESD() methods.
26 *
d76c31f4 27 * Revision 1.97 2007/08/07 14:12:03 kharlov
28 * Quality assurance added (Yves Schutz)
29 *
ddd1a39c 30 * Revision 1.96 2007/04/28 10:43:36 policheh
31 * Dead channels simulation: digit energy sets to 0.
32 *
1c6a163f 33 * Revision 1.95 2007/04/10 07:20:52 kharlov
34 * Decalibration should use the same CDB as calibration in AliPHOSClusterizerv1
35 *
1a197b77 36 * Revision 1.94 2007/02/01 10:34:47 hristov
37 * Removing warnings on Solaris x86
38 *
ad4aeaf4 39 * Revision 1.93 2006/10/17 13:17:01 kharlov
40 * Replace AliInfo by AliDebug
41 *
d6e8d7d3 42 * Revision 1.92 2006/08/28 10:01:56 kharlov
43 * Effective C++ warnings fixed (Timur Pocheptsov)
44 *
3663622c 45 * Revision 1.91 2006/04/29 20:25:30 hristov
46 * Decalibration is implemented (Yu.Kharlov)
47 *
877695e7 48 * Revision 1.90 2006/04/22 10:30:17 hristov
49 * Add fEnergy to AliPHOSDigit and operate with EMC amplitude in energy units (Yu.Kharlov)
50 *
27a73a5d 51 * Revision 1.89 2006/04/11 15:22:59 hristov
52 * run number in query set to -1: forces AliCDBManager to use its run number (A.Colla)
53 *
28871337 54 * Revision 1.88 2006/03/13 14:05:43 kharlov
55 * Calibration objects for EMC and CPV
56 *
fc6706cb 57 * Revision 1.87 2005/08/24 15:33:49 kharlov
58 * Calibration data for raw digits
59 *
a8ec0771 60 * Revision 1.86 2005/07/12 20:07:35 hristov
61 * Changes needed to run simulation and reconstrruction in the same AliRoot session
62 *
7c193632 63 * Revision 1.85 2005/05/28 14:19:04 schutz
64 * Compilation warnings fixed by T.P.
65 *
702ab87e 66 */
88cb7938 67
990119d6 68//_________________________________________________________________________
990119d6 69//*-- Author : Dmitri Peressounko (SUBATECH & Kurchatov Institute)
70//////////////////////////////////////////////////////////////////////////////
a4e98857 71// This TTask performs digitization of Summable digits (in the PHOS case it is just
72// the sum of contributions from all primary particles into a given cell).
990119d6 73// In addition it performs mixing of summable digits from different events.
7b7c1533 74// The name of the TTask is also the title of the branch that will contain
75// the created SDigits
76// The title of the TTAsk is the name of the file that contains the hits from
77// which the SDigits are created
bca3b32a 78//
79// For each event two branches are created in TreeD:
80// "PHOS" - list of digits
81// "AliPHOSDigitizer" - AliPHOSDigitizer with all parameters used in digitization
82//
a4e98857 83// Note, that one can set a title for new digits branch, and repeat digitization with
bca3b32a 84// another set of parameters.
85//
a4e98857 86// Use case:
990119d6 87// root[0] AliPHOSDigitizer * d = new AliPHOSDigitizer() ;
88// root[1] d->ExecuteTask()
89// Warning in <TDatabasePDG::TDatabasePDG>: object already instantiated
90// //Digitizes SDigitis in all events found in file galice.root
bca3b32a 91//
8cb3533f 92// root[2] AliPHOSDigitizer * d1 = new AliPHOSDigitizer("galice1.root") ;
93// // Will read sdigits from galice1.root
94// root[3] d1->MixWith("galice2.root")
990119d6 95// Warning in <TDatabasePDG::TDatabasePDG>: object already instantiated
a4e98857 96// // Reads another set of sdigits from galice2.root
8cb3533f 97// root[3] d1->MixWith("galice3.root")
a4e98857 98// // Reads another set of sdigits from galice3.root
8cb3533f 99// root[4] d->ExecuteTask("deb timing")
100// // Reads SDigits from files galice1.root, galice2.root ....
101// // mixes them and stores produced Digits in file galice1.root
102// // deb - prints number of produced digits
103// // deb all - prints list of produced digits
104// // timing - prints time used for digitization
990119d6 105//
990119d6 106
107// --- ROOT system ---
990119d6 108#include "TTree.h"
109#include "TSystem.h"
8cb3533f 110#include "TBenchmark.h"
e957fea8 111#include "TRandom.h"
ba54256b 112
990119d6 113// --- Standard library ---
114
115// --- AliRoot header files ---
351dd634 116#include "AliLog.h"
3f81a70b 117#include "AliRunDigitizer.h"
990119d6 118#include "AliPHOSDigit.h"
7b7c1533 119#include "AliPHOSGetter.h"
990119d6 120#include "AliPHOSDigitizer.h"
121#include "AliPHOSSDigitizer.h"
8cb3533f 122#include "AliPHOSGeometry.h"
7437a0f7 123#include "AliPHOSTick.h"
b8274834 124#include "AliPHOSQADataMaker.h"
990119d6 125
126ClassImp(AliPHOSDigitizer)
127
128
129//____________________________________________________________________________
3663622c 130AliPHOSDigitizer::AliPHOSDigitizer() :
131 AliDigitizer("",""),
132 fDefaultInit(kTRUE),
133 fDigitsInRun(0),
134 fInit(kFALSE),
135 fInput(0),
136 fInputFileNames(0x0),
137 fEventNames(0x0),
138 fEmcCrystals(0),
139 fPinNoise(0.f),
140 fEMCDigitThreshold(0.f),
141 fCPVNoise(0.f),
142 fCPVDigitThreshold(0.f),
143 fTimeResolution(0.f),
144 fTimeThreshold(0.f),
145 fTimeSignalLength(0.f),
146 fADCchanelEmc(0.f),
147 fADCpedestalEmc(0.f),
148 fNADCemc(0),
149 fADCchanelCpv(0.f),
150 fADCpedestalCpv(0.f),
151 fNADCcpv(0),
152 fEventFolderName(""),
153 fFirstEvent(0),
ddd1a39c 154 fLastEvent(0),
155 fQADM (0x0),
156 fEventCounter(0)
990119d6 157{
158 // ctor
8d0f3f77 159 InitParameters() ;
fbf811ec 160 fManager = 0 ; // We work in the standalong mode
88cb7938 161}
3f81a70b 162
163//____________________________________________________________________________
e191bb57 164AliPHOSDigitizer::AliPHOSDigitizer(TString alirunFileName,
165 TString eventFolderName):
3663622c 166 AliDigitizer("PHOS"+AliConfig::Instance()->GetDigitizerTaskName(), alirunFileName),
167 fDefaultInit(kFALSE),
168 fDigitsInRun(0),
169 fInit(kFALSE),
170 fInput(0),
171 fInputFileNames(0x0),
172 fEventNames(0x0),
173 fEmcCrystals(0),
174 fPinNoise(0.f),
175 fEMCDigitThreshold(0.f),
176 fCPVNoise(0.f),
177 fCPVDigitThreshold(0.f),
178 fTimeResolution(0.f),
179 fTimeThreshold(0.f),
180 fTimeSignalLength(0.f),
181 fADCchanelEmc(0.f),
182 fADCpedestalEmc(0.f),
183 fNADCemc(0),
184 fADCchanelCpv(0.f),
185 fADCpedestalCpv(0.f),
186 fNADCcpv(0),
187 fEventFolderName(eventFolderName),
188 fFirstEvent(0),
ddd1a39c 189 fLastEvent(0),
190 fQADM (0x0),
191 fEventCounter(0)
3f81a70b 192{
193 // ctor
8d0f3f77 194 InitParameters() ;
3f81a70b 195 Init() ;
92f521a9 196 fDefaultInit = kFALSE ;
88cb7938 197 fManager = 0 ; // We work in the standalong mode
ddd1a39c 198 //Initialize the quality assurance data maker only once
b8274834 199 fQADM = new AliPHOSQADataMaker() ;
5b188f2f 200 //FIXME: get the run number
201 Int_t run = 0 ;
202 //EMXIF
b8274834 203 GetQADataMaker()->Init(AliQA::kDIGITS, run, fgkCycles) ;
204 GetQADataMaker()->StartOfCycle(AliQA::kDIGITS) ;
88cb7938 205}
206
207//____________________________________________________________________________
3663622c 208AliPHOSDigitizer::AliPHOSDigitizer(const AliPHOSDigitizer & d) :
209 AliDigitizer(d),
210 fDefaultInit(d.fDefaultInit),
211 fDigitsInRun(d.fDigitsInRun),
212 fInit(d.fInit),
213 fInput(d.fInput),
214 fInputFileNames(0x0),//?
215 fEventNames(0x0),//?
216 fEmcCrystals(d.fEmcCrystals),
217 fPinNoise(d.fPinNoise),
218 fEMCDigitThreshold(d.fEMCDigitThreshold),
219 fCPVNoise(d.fCPVNoise),
220 fCPVDigitThreshold(d.fCPVDigitThreshold),
221 fTimeResolution(d.fTimeResolution),
222 fTimeThreshold(d.fTimeThreshold),
223 fTimeSignalLength(d.fTimeSignalLength),
224 fADCchanelEmc(d.fADCchanelEmc),
225 fADCpedestalEmc(d.fADCpedestalEmc),
226 fNADCemc(d.fNADCemc),
227 fADCchanelCpv(d.fADCchanelCpv),
228 fADCpedestalCpv(d.fADCpedestalCpv),
229 fNADCcpv(d.fNADCcpv),
230 fEventFolderName(d.fEventFolderName),
231 fFirstEvent(d.fFirstEvent),
ddd1a39c 232 fLastEvent(d.fLastEvent),
233 fQADM (d.fQADM),
234 fEventCounter(0)
235
88cb7938 236{
237 // copyy ctor
88cb7938 238 SetName(d.GetName()) ;
239 SetTitle(d.GetTitle()) ;
ddd1a39c 240//Initialize the quality assurance data maker only once
5b188f2f 241 //FIXME: get the run number
242 Int_t run = 0 ;
243 //EMXIF
b8274834 244 GetQADataMaker()->Init(AliQA::kDIGITS, run, fgkCycles) ;
245 GetQADataMaker()->StartOfCycle(AliQA::kDIGITS) ;
990119d6 246}
247
990119d6 248//____________________________________________________________________________
3663622c 249AliPHOSDigitizer::AliPHOSDigitizer(AliRunDigitizer * rd) :
250 AliDigitizer(rd,"PHOS"+AliConfig::Instance()->GetDigitizerTaskName()),
251 fDefaultInit(kFALSE),
252 fDigitsInRun(0),
253 fInit(kFALSE),
254 fInput(0),
255 fInputFileNames(0x0),
256 fEventNames(0x0),
257 fEmcCrystals(0),
258 fPinNoise(0.f),
259 fEMCDigitThreshold(0.f),
260 fCPVNoise(0.f),
261 fCPVDigitThreshold(0.f),
262 fTimeResolution(0.f),
263 fTimeThreshold(0.f),
264 fTimeSignalLength(0.f),
265 fADCchanelEmc(0.f),
266 fADCpedestalEmc(0.f),
267 fNADCemc(0),
268 fADCchanelCpv(0.f),
269 fADCpedestalCpv(0.f),
270 fNADCcpv(0),
271 fEventFolderName(fManager->GetInputFolderName(0)),
272 fFirstEvent(0),
ddd1a39c 273 fLastEvent(0),
274 fQADM (0x0),
275 fEventCounter(0)
276
990119d6 277{
45fa49ca 278 // ctor Init() is called by RunDigitizer
88cb7938 279 fManager = rd ;
88cb7938 280 SetTitle(dynamic_cast<AliStream*>(fManager->GetInputStream(0))->GetFileName(0));
b22e4735 281 InitParameters() ;
fbf811ec 282 fDefaultInit = kFALSE ;
ddd1a39c 283//Initialize the quality assurance data maker only once
b8274834 284 fQADM = new AliPHOSQADataMaker() ;
5b188f2f 285 //FIXME: get the run number
286 Int_t run = 0 ;
287 //EMXIF
b8274834 288 GetQADataMaker()->Init(AliQA::kDIGITS, run) ;
289 GetQADataMaker()->StartOfCycle(AliQA::kDIGITS) ;
990119d6 290}
291
292//____________________________________________________________________________
293 AliPHOSDigitizer::~AliPHOSDigitizer()
294{
7c193632 295 AliPHOSGetter * gime = AliPHOSGetter::Instance(GetTitle()) ;
296
297 // Clean Digitizer from the white board
298 gime->PhosLoader()->CleanDigitizer() ;
990119d6 299 // dtor
88cb7938 300 delete [] fInputFileNames ;
301 delete [] fEventNames ;
ddd1a39c 302
303 delete fQADM ;
304
990119d6 305}
306
307//____________________________________________________________________________
fc7e2f43 308void AliPHOSDigitizer::Digitize(Int_t event)
a4e98857 309{
310
311 // Makes the digitization of the collected summable digits.
312 // It first creates the array of all PHOS modules
dc986a1d 313 // filled with noise (different for EMC, and CPV) and
a4e98857 314 // then adds contributions from SDigits.
315 // This design avoids scanning over the list of digits to add
316 // contribution to new SDigits only.
990119d6 317
f98c06a1 318 AliPHOSGetter * gime = AliPHOSGetter::Instance(GetTitle()) ;
45fa49ca 319 Int_t ReadEvent = event ;
320 if (fManager)
321 ReadEvent = dynamic_cast<AliStream*>(fManager->GetInputStream(0))->GetCurrentEventNumber() ;
d6e8d7d3 322 AliDebug(1,Form("Adding event %d from input stream 0 %s %s",
323 ReadEvent, GetTitle(), fEventFolderName.Data())) ;
45fa49ca 324 gime->Event(ReadEvent, "S") ;
88cb7938 325 TClonesArray * digits = gime->Digits() ;
7b7c1533 326 digits->Clear() ;
990119d6 327
7b7c1533 328 const AliPHOSGeometry *geom = gime->PHOSGeometry() ;
990119d6 329 //Making digits with noise, first EMC
330 Int_t nEMC = geom->GetNModules()*geom->GetNPhi()*geom->GetNZ();
331
332 Int_t nCPV ;
990119d6 333 Int_t absID ;
990119d6 334
88cb7938 335 nCPV = nEMC + geom->GetNumberOfCPVPadsZ() * geom->GetNumberOfCPVPadsPhi() * geom->GetNModules() ;
336
9688c1dd 337 digits->Expand(nCPV) ;
8cb3533f 338
88cb7938 339 // get first the sdigitizer from the tasks list
340 if ( !gime->SDigitizer() )
341 gime->LoadSDigitizer();
342 AliPHOSSDigitizer * sDigitizer = gime->SDigitizer();
343
344 if ( !sDigitizer )
351dd634 345 AliFatal(Form("SDigitizer with name %s %s not found",
346 GetTitle(), fEventFolderName.Data() )) ;
88cb7938 347
348 //take all the inputs to add together and load the SDigits
349 TObjArray * sdigArray = new TObjArray(fInput) ;
350 sdigArray->AddAt(gime->SDigits(), 0) ;
351 Int_t i ;
352 for(i = 1 ; i < fInput ; i++){
353 TString tempo(fEventNames[i]) ;
354 tempo += i ;
ad4aeaf4 355 AliPHOSGetter * gime1 = AliPHOSGetter::Instance(fInputFileNames[i], tempo) ;
45fa49ca 356 if (fManager)
357 ReadEvent = dynamic_cast<AliStream*>(fManager->GetInputStream(i))->GetCurrentEventNumber() ;
351dd634 358 AliInfo(Form("Adding event %d from input stream %d %s %s",
359 ReadEvent, i, fInputFileNames[i].Data(), tempo.Data())) ;
ad4aeaf4 360 gime1->Event(ReadEvent,"S");
361 sdigArray->AddAt(gime1->SDigits(), i) ;
38bb0fd5 362 }
9688c1dd 363
27a73a5d 364 //Find the first crystal with signal
9688c1dd 365 Int_t nextSig = 200000 ;
88cb7938 366 TClonesArray * sdigits ;
367 for(i = 0 ; i < fInput ; i++){
368 sdigits = dynamic_cast<TClonesArray *>(sdigArray->At(i)) ;
a6eedfad 369 if ( !sdigits->GetEntriesFast() )
7a9d98f9 370 continue ;
88cb7938 371 Int_t curNext = dynamic_cast<AliPHOSDigit *>(sdigits->At(0))->GetId() ;
372 if(curNext < nextSig)
373 nextSig = curNext ;
9688c1dd 374 }
88cb7938 375
376 TArrayI index(fInput) ;
9688c1dd 377 index.Reset() ; //Set all indexes to zero
88cb7938 378
9688c1dd 379 AliPHOSDigit * digit ;
380 AliPHOSDigit * curSDigit ;
88cb7938 381
7437a0f7 382 TClonesArray * ticks = new TClonesArray("AliPHOSTick",1000) ;
88cb7938 383
9688c1dd 384 //Put Noise contribution
88cb7938 385 for(absID = 1 ; absID <= nEMC ; absID++){
9688c1dd 386 Float_t noise = gRandom->Gaus(0., fPinNoise) ;
27a73a5d 387 // YVK: do not digitize amplitudes for EMC
388// new((*digits)[absID-1]) AliPHOSDigit( -1, absID, sDigitizer->Digitize(noise), TimeOfNoise() ) ;
389 new((*digits)[absID-1]) AliPHOSDigit( -1, absID, noise, TimeOfNoise() ) ;
9688c1dd 390 //look if we have to add signal?
88cb7938 391 digit = dynamic_cast<AliPHOSDigit *>(digits->At(absID-1)) ;
392
9688c1dd 393 if(absID==nextSig){
394 //Add SDigits from all inputs
7437a0f7 395 ticks->Clear() ;
9688c1dd 396 Int_t contrib = 0 ;
27a73a5d 397 Float_t a = digit->GetEnergy() ;
88cb7938 398 Float_t b = TMath::Abs( a / fTimeSignalLength) ;
399 //Mark the beginning of the signal
7437a0f7 400 new((*ticks)[contrib++]) AliPHOSTick(digit->GetTime(),0, b);
27a73a5d 401 //Mark the end of the signal
7437a0f7 402 new((*ticks)[contrib++]) AliPHOSTick(digit->GetTime()+fTimeSignalLength, -a, -b);
88cb7938 403
9688c1dd 404 //loop over inputs
88cb7938 405 for(i = 0 ; i < fInput ; i++){
406 if( dynamic_cast<TClonesArray *>(sdigArray->At(i))->GetEntriesFast() > index[i] )
407 curSDigit = dynamic_cast<AliPHOSDigit*>(dynamic_cast<TClonesArray *>(sdigArray->At(i))->At(index[i])) ;
5c9dfca0 408 else
409 curSDigit = 0 ;
9688c1dd 410 //May be several digits will contribute from the same input
411 while(curSDigit && curSDigit->GetId() == absID){
412 //Shift primary to separate primaries belonging different inputs
413 Int_t primaryoffset ;
9891b76e 414 if(fManager)
415 primaryoffset = fManager->GetMask(i) ;
9688c1dd 416 else
21c293b7 417 primaryoffset = 10000000*i ;
418 curSDigit->ShiftPrimary(primaryoffset) ;
7437a0f7 419
27a73a5d 420 a = curSDigit->GetEnergy() ;
7437a0f7 421 b = a /fTimeSignalLength ;
422 new((*ticks)[contrib++]) AliPHOSTick(curSDigit->GetTime(),0, b);
423 new((*ticks)[contrib++]) AliPHOSTick(curSDigit->GetTime()+fTimeSignalLength, -a, -b);
88cb7938 424
3663622c 425 *digit += *curSDigit ; //add energies
27a73a5d 426
9688c1dd 427 index[i]++ ;
88cb7938 428 if( dynamic_cast<TClonesArray *>(sdigArray->At(i))->GetEntriesFast() > index[i] )
429 curSDigit = dynamic_cast<AliPHOSDigit*>(dynamic_cast<TClonesArray *>(sdigArray->At(i))->At(index[i])) ;
5c9dfca0 430 else
431 curSDigit = 0 ;
9688c1dd 432 }
433 }
88cb7938 434
9688c1dd 435 //calculate and set time
7437a0f7 436 Float_t time = FrontEdgeTime(ticks) ;
9688c1dd 437 digit->SetTime(time) ;
88cb7938 438
9688c1dd 439 //Find next signal module
7437a0f7 440 nextSig = 200000 ;
88cb7938 441 for(i = 0 ; i < fInput ; i++){
442 sdigits = dynamic_cast<TClonesArray *>(sdigArray->At(i)) ;
5c9dfca0 443 Int_t curNext = nextSig ;
444 if(sdigits->GetEntriesFast() > index[i] ){
88cb7938 445 curNext = dynamic_cast<AliPHOSDigit *>(sdigits->At(index[i]))->GetId() ;
5c9dfca0 446 }
9688c1dd 447 if(curNext < nextSig) nextSig = curNext ;
7b7c1533 448 }
449 }
990119d6 450 }
3f81a70b 451
7437a0f7 452 ticks->Delete() ;
453 delete ticks ;
88cb7938 454
9688c1dd 455 //Now CPV digits (different noise and no timing)
456 for(absID = nEMC+1; absID <= nCPV; absID++){
457 Float_t noise = gRandom->Gaus(0., fCPVNoise) ;
458 new((*digits)[absID-1]) AliPHOSDigit( -1,absID,sDigitizer->Digitize(noise), TimeOfNoise() ) ;
459 //look if we have to add signal?
460 if(absID==nextSig){
88cb7938 461 digit = dynamic_cast<AliPHOSDigit *>(digits->At(absID-1)) ;
9688c1dd 462 //Add SDigits from all inputs
88cb7938 463 for(i = 0 ; i < fInput ; i++){
464 if( dynamic_cast<TClonesArray *>(sdigArray->At(i))->GetEntriesFast() > index[i] )
465 curSDigit = dynamic_cast<AliPHOSDigit*>( dynamic_cast<TClonesArray *>(sdigArray->At(i))->At(index[i])) ;
5c9dfca0 466 else
467 curSDigit = 0 ;
a6eedfad 468
9688c1dd 469 //May be several digits will contribute from the same input
470 while(curSDigit && curSDigit->GetId() == absID){
471 //Shift primary to separate primaries belonging different inputs
472 Int_t primaryoffset ;
9891b76e 473 if(fManager)
474 primaryoffset = fManager->GetMask(i) ;
9688c1dd 475 else
476 primaryoffset = 10000000*i ;
477 curSDigit->ShiftPrimary(primaryoffset) ;
478
479 //add energies
3663622c 480 *digit += *curSDigit ;
9688c1dd 481 index[i]++ ;
88cb7938 482 if( dynamic_cast<TClonesArray *>(sdigArray->At(i))->GetEntriesFast() > index[i] )
483 curSDigit = dynamic_cast<AliPHOSDigit*>( dynamic_cast<TClonesArray *>(sdigArray->At(i))->At(index[i]) ) ;
5c9dfca0 484 else
485 curSDigit = 0 ;
9688c1dd 486 }
487 }
a6eedfad 488
9688c1dd 489 //Find next signal module
a6eedfad 490 nextSig = 200000 ;
88cb7938 491 for(i = 0 ; i < fInput ; i++){
492 sdigits = dynamic_cast<TClonesArray *>(sdigArray->At(i)) ;
5c9dfca0 493 Int_t curNext = nextSig ;
494 if(sdigits->GetEntriesFast() > index[i] )
88cb7938 495 curNext = dynamic_cast<AliPHOSDigit *>( sdigits->At(index[i]) )->GetId() ;
9688c1dd 496 if(curNext < nextSig) nextSig = curNext ;
497 }
498
499 }
500 }
88cb7938 501
502 delete sdigArray ; //We should not delete its contents
9688c1dd 503
990119d6 504 //remove digits below thresholds
88cb7938 505 for(i = 0 ; i < nEMC ; i++){
548f0134 506 digit = dynamic_cast<AliPHOSDigit*>( digits->At(i) ) ;
877695e7 507 DecalibrateEMC(digit);
27a73a5d 508 if(digit->GetEnergy() < fEMCDigitThreshold)
a6eedfad 509 digits->RemoveAt(i) ;
aaf8a71c 510 else
511 digit->SetTime(gRandom->Gaus(digit->GetTime(),fTimeResolution) ) ;
512 }
513
a6eedfad 514
515 for(i = nEMC; i < nCPV ; i++)
27a73a5d 516// if( sDigitizer->Calibrate( dynamic_cast<AliPHOSDigit*>(digits->At(i))->GetAmp() ) < fCPVDigitThreshold )
517 if( dynamic_cast<AliPHOSDigit*>(digits->At(i))->GetEnergy() < fCPVDigitThreshold )
a6eedfad 518 digits->RemoveAt(i) ;
9688c1dd 519
7b7c1533 520 digits->Compress() ;
990119d6 521
7b7c1533 522 Int_t ndigits = digits->GetEntriesFast() ;
7b7c1533 523 digits->Expand(ndigits) ;
990119d6 524
3758d9fc 525 //Set indexes in list of digits and make true digitization of the energy
990119d6 526 for (i = 0 ; i < ndigits ; i++) {
548f0134 527 digit = dynamic_cast<AliPHOSDigit*>( digits->At(i) ) ;
990119d6 528 digit->SetIndexInList(i) ;
27a73a5d 529 if(digit->GetId() > fEmcCrystals){ //digitize CPV only
877695e7 530 digit->SetAmp(DigitizeCPV(digit->GetEnergy(),digit->GetId()) ) ;
27a73a5d 531 }
990119d6 532 }
1c6a163f 533
534 Int_t relId[4];
535
536 //set amplitudes in bad channels to zero
537 for(i = 0 ; i <digits->GetEntries(); i++){
538 digit = dynamic_cast<AliPHOSDigit*>( digits->At(i) ) ;
539 gime->PHOSGeometry()->AbsToRelNumbering(digit->GetId(),relId);
540 if(relId[1] == 0) // Emc
541 if(gime->CalibData()->IsBadChannelEmc(relId[0],relId[3],relId[2])) digit->SetEnergy(0.);
542 }
543
7b7c1533 544}
548f0134 545
3758d9fc 546//____________________________________________________________________________
877695e7 547void AliPHOSDigitizer::DecalibrateEMC(AliPHOSDigit *digit)
3758d9fc 548{
877695e7 549 // Decalibrate EMC digit, i.e. change its energy by a factor read from CDB
550
551 AliPHOSGetter* gime = AliPHOSGetter::Instance();
552
553 if(!gime->CalibData()) {
554 AliPHOSCalibData* cdb = new AliPHOSCalibData(-1);
555 gime->SetCalibData(cdb);
556 }
557
558 //Determine rel.position of the cell absolute ID
559 Int_t relId[4];
560 gime->PHOSGeometry()->AbsToRelNumbering(digit->GetId(),relId);
561 Int_t module=relId[0];
562 Int_t row =relId[2];
563 Int_t column=relId[3];
564 Float_t decalibration = gime->CalibData()->GetADCchannelEmc(module,column,row);
1a197b77 565 Float_t energy = digit->GetEnergy() / decalibration;
877695e7 566 digit->SetEnergy(energy);
567}
568//____________________________________________________________________________
569Int_t AliPHOSDigitizer::DigitizeCPV(Float_t charge, Int_t absId)
570{
571 // Returns digitized value of the CPV charge in a pad absId
0bc3b8ed 572
a8ec0771 573 AliPHOSGetter* gime = AliPHOSGetter::Instance();
574
fc6706cb 575 if(!gime->CalibData()) {
28871337 576 AliPHOSCalibData* cdb = new AliPHOSCalibData(-1); // use AliCDBManager's run number
fc6706cb 577 gime->SetCalibData(cdb);
578 }
579
a8ec0771 580 //Determine rel.position of the cell absId
581 Int_t relId[4];
582 gime->PHOSGeometry()->AbsToRelNumbering(absId,relId);
583 Int_t module=relId[0];
27a73a5d 584 Int_t row =relId[2];
a8ec0771 585 Int_t column=relId[3];
586
877695e7 587 Int_t channel = 0;
a8ec0771 588
877695e7 589 if(absId > fEmcCrystals){ //digitize CPV only
a8ec0771 590
591 //reading calibration data for cell absId.
592 //If no calibration DB found, accept default values.
593
fc6706cb 594 if(gime->CalibData()) {
27a73a5d 595 fADCpedestalCpv = gime->CalibData()->GetADCpedestalCpv(module,column,row);
877695e7 596 fADCchanelCpv = gime->CalibData()->GetADCchannelCpv( module,column,row);
fc6706cb 597 }
598
877695e7 599 channel = (Int_t) TMath::Ceil((charge - fADCpedestalCpv)/fADCchanelCpv) ;
600 if(channel > fNADCcpv ) channel = fNADCcpv ;
3758d9fc 601 }
877695e7 602 return channel ;
3758d9fc 603}
548f0134 604
7b7c1533 605//____________________________________________________________________________
606void AliPHOSDigitizer::Exec(Option_t *option)
607{
212d1c0f 608 // Steering method to process digitization for events
609 // in the range from fFirstEvent to fLastEvent.
610 // This range is optionally set by SetEventRange().
45fa49ca 611 // if fLastEvent=-1, then process events until the end.
612 // by default fLastEvent = fFirstEvent (process only one event)
88cb7938 613
614 if (!fInit) { // to prevent overwrite existing file
351dd634 615 AliError(Form("Give a version name different from %s",
616 fEventFolderName.Data() )) ;
88cb7938 617 return ;
618 }
990119d6 619
7b7c1533 620 if (strstr(option,"print")) {
88cb7938 621 Print();
7b7c1533 622 return ;
8cb3533f 623 }
990119d6 624
7b7c1533 625 if(strstr(option,"tim"))
626 gBenchmark->Start("PHOSDigitizer");
3f81a70b 627
fb43ada4 628 AliPHOSGetter * gime = AliPHOSGetter::Instance(GetTitle()) ;
88cb7938 629
5b4d2c50 630 // Post Digitizer to the white board
631 gime->PostDigitizer(this) ;
632
212d1c0f 633 if (fLastEvent == -1)
634 fLastEvent = gime->MaxEvent() - 1 ;
396a348e 635 else if (fManager)
636 fLastEvent = fFirstEvent ;
45fa49ca 637
212d1c0f 638 Int_t nEvents = fLastEvent - fFirstEvent + 1;
639
7b7c1533 640 Int_t ievent ;
88cb7938 641
212d1c0f 642 for (ievent = fFirstEvent; ievent <= fLastEvent; ievent++) {
ddd1a39c 643 fEventCounter++ ;
88cb7938 644 gime->Event(ievent,"S") ;
b22e4735 645
7b7c1533 646 Digitize(ievent) ; //Add prepared SDigits to digits and add the noise
88cb7938 647
ddd1a39c 648 //makes the quality assurance data
b8274834 649 if (GetQADataMaker()->IsCycleDone() ) {
650 GetQADataMaker()->EndOfCycle(AliQA::kDIGITS) ;
651 GetQADataMaker()->StartOfCycle(AliQA::kDIGITS) ;
5b188f2f 652 }
b8274834 653 GetQADataMaker()->Exec(AliQA::kDIGITS, gime->Digits()) ;
654 GetQADataMaker()->Increment() ;
ddd1a39c 655
90cceaf6 656 WriteDigits() ;
88cb7938 657
01a599c9 658 if(strstr(option,"deb"))
659 PrintDigits(option);
94de8339 660
661 //increment the total number of Digits per run
662 fDigitsInRun += gime->Digits()->GetEntriesFast() ;
88cb7938 663 }
ddd1a39c 664
665 //Write the quality assurance data only after the last event
5b188f2f 666 if ( fEventCounter == gime->MaxEvent() ) {
b8274834 667 GetQADataMaker()->EndOfCycle(AliQA::kDIGITS) ;
668 GetQADataMaker()->Finish(AliQA::kDIGITS) ;
5b188f2f 669 }
88cb7938 670
5b4d2c50 671 gime->PhosLoader()->CleanDigitizer();
672
8cb3533f 673 if(strstr(option,"tim")){
674 gBenchmark->Stop("PHOSDigitizer");
21cd0c07 675 TString message ;
676 message = " took %f seconds for Digitizing %f seconds per event\n" ;
351dd634 677 AliInfo(Form( message.Data(),
21cd0c07 678 gBenchmark->GetCpuTime("PHOSDigitizer"),
351dd634 679 gBenchmark->GetCpuTime("PHOSDigitizer")/nEvents ));
21cd0c07 680 }
990119d6 681}
682
9688c1dd 683//____________________________________________________________________________
0bc3b8ed 684Float_t AliPHOSDigitizer::FrontEdgeTime(TClonesArray * ticks) const
685{
686 // Returns the shortest time among all time ticks
687
7437a0f7 688 ticks->Sort() ; //Sort in accordance with times of ticks
689 TIter it(ticks) ;
690 AliPHOSTick * ctick = (AliPHOSTick *) it.Next() ;
691 Float_t time = ctick->CrossingTime(fTimeThreshold) ;
692
693 AliPHOSTick * t ;
694 while((t=(AliPHOSTick*) it.Next())){
695 if(t->GetTime() < time) //This tick starts before crossing
696 *ctick+=*t ;
697 else
698 return time ;
699
700 time = ctick->CrossingTime(fTimeThreshold) ;
9688c1dd 701 }
702 return time ;
9688c1dd 703}
8d0f3f77 704
7b7c1533 705//____________________________________________________________________________
3f81a70b 706Bool_t AliPHOSDigitizer::Init()
8d0f3f77 707{
fbf811ec 708 // Makes all memory allocations
88cb7938 709 fInit = kTRUE ;
710 AliPHOSGetter * gime = AliPHOSGetter::Instance(GetTitle(), fEventFolderName) ;
8d0f3f77 711 if ( gime == 0 ) {
351dd634 712 AliFatal(Form("Could not obtain the Getter object for file %s and event %s !",
713 GetTitle(), fEventFolderName.Data()));
8d0f3f77 714 return kFALSE;
715 }
716
717 const AliPHOSGeometry * geom = gime->PHOSGeometry() ;
b22e4735 718
88cb7938 719 fEmcCrystals = geom->GetNModules() * geom->GetNCristalsInModule() ;
8d0f3f77 720
88cb7938 721 TString opt("Digits") ;
722 if(gime->VersionExists(opt) ) {
351dd634 723 AliError(Form("Give a version name different from %s",
724 fEventFolderName.Data() )) ;
88cb7938 725 fInit = kFALSE ;
726 }
727
45fa49ca 728 fFirstEvent = 0 ;
729 fLastEvent = fFirstEvent ;
88cb7938 730 if (fManager)
731 fInput = fManager->GetNinputs() ;
732 else
733 fInput = 1 ;
734
735 fInputFileNames = new TString[fInput] ;
736 fEventNames = new TString[fInput] ;
737 fInputFileNames[0] = GetTitle() ;
738 fEventNames[0] = fEventFolderName.Data() ;
739 Int_t index ;
740 for (index = 1 ; index < fInput ; index++) {
741 fInputFileNames[index] = dynamic_cast<AliStream*>(fManager->GetInputStream(index))->GetFileName(0);
742 TString tempo = fManager->GetInputFolderName(index) ;
45fa49ca 743 fEventNames[index] = tempo.Remove(tempo.Length()-1) ; // strip of the stream number added by fManager
8d0f3f77 744 }
88cb7938 745
746 //to prevent cleaning of this object while GetEvent is called
747 gime->PhosLoader()->GetDigitsDataLoader()->GetBaseTaskLoader()->SetDoNotReload(kTRUE);
748
749 return fInit ;
8d0f3f77 750}
751
752//____________________________________________________________________________
753void AliPHOSDigitizer::InitParameters()
a4e98857 754{
45fa49ca 755 // Set initial parameters Digitizer
0bc3b8ed 756
27a73a5d 757 fPinNoise = 0.004 ; // [GeV]
758 fEMCDigitThreshold = 0.012 ; // [GeV]
759 fCPVNoise = 0.01; // [aux units]
760 fCPVDigitThreshold = 0.09 ; // [aux units]
761 fTimeResolution = 0.5e-9 ; // [sec]
762 fTimeSignalLength = 1.0e-9 ; // [sec]
3758d9fc 763 fDigitsInRun = 0 ;
877695e7 764 fADCchanelEmc = 1.0; // Coefficient between real and measured energies in EMC
765 fADCpedestalEmc = 0. ; //
3758d9fc 766 fNADCemc = (Int_t) TMath::Power(2,16) ; // number of channels in EMC ADC
767
768 fADCchanelCpv = 0.0012 ; // width of one ADC channel in CPV 'popugais'
769 fADCpedestalCpv = 0.012 ; //
770 fNADCcpv = (Int_t) TMath::Power(2,12); // number of channels in CPV ADC
771
27a73a5d 772// fTimeThreshold = 0.001*10000000 ; //Means 1 MeV in terms of SDigits amplitude
773 fTimeThreshold = 0.001 ; // [GeV]
212d1c0f 774 SetEventRange(0,-1) ;
8cb3533f 775
990119d6 776}
7b7c1533 777
990119d6 778//__________________________________________________________________
fc7e2f43 779void AliPHOSDigitizer::MixWith(TString alirunFileName, TString eventFolderName)
a4e98857 780{
ba54256b 781 // Allows to produce digits by superimposing background and signal event.
bca3b32a 782 // It is assumed, that headers file with SIGNAL events is opened in
a4e98857 783 // the constructor.
784 // Sets the BACKGROUND event, with which the SIGNAL event is to be mixed
785 // Thus we avoid writing (changing) huge and expensive
bca3b32a 786 // backgound files: all output will be writen into SIGNAL, i.e.
787 // opened in constructor file.
788 //
a4e98857 789 // One can open as many files to mix with as one needs.
7b7c1533 790 // However only Sdigits with the same name (i.e. constructed with the same SDigitizer)
791 // can be mixed.
bca3b32a 792
88cb7938 793 if( strcmp(fEventFolderName, "") == 0 )
8cb3533f 794 Init() ;
795
9891b76e 796 if(fManager){
88cb7938 797 Warning("MixWith", "Cannot use this method with AliRunDigitizer\n" ) ;
3f81a70b 798 return ;
799 }
88cb7938 800 // looking for file which contains AliRun
801 if (gSystem->AccessPathName(alirunFileName)) {// file does not exist
351dd634 802 AliError(Form("File %s does not exist!", alirunFileName.Data())) ;
88cb7938 803 return ;
990119d6 804 }
88cb7938 805 // looking for the file which contains SDigits
806 AliPHOSGetter * gime = AliPHOSGetter::Instance() ;
807 TString fileName( gime->GetSDigitsFileName() ) ;
e191bb57 808 if ( eventFolderName != AliConfig::GetDefaultEventFolderName()) // only if not the default folder name
88cb7938 809 fileName = fileName.ReplaceAll(".root", "") + "_" + eventFolderName + ".root" ;
810 if ( (gSystem->AccessPathName(fileName)) ) {
351dd634 811 AliError(Form("The file %s does not exist!", fileName.Data())) ;
88cb7938 812 return ;
7b7c1533 813 }
88cb7938 814 // need to increase the arrays
815 TString tempo = fInputFileNames[fInput-1] ;
816 delete [] fInputFileNames ;
817 fInputFileNames = new TString[fInput+1] ;
818 fInputFileNames[fInput-1] = tempo ;
819
820 tempo = fEventNames[fInput-1] ;
821 delete [] fEventNames ;
822 fEventNames = new TString[fInput+1] ;
823 fEventNames[fInput-1] = tempo ;
824
825 fInputFileNames[fInput] = alirunFileName ;
826 fEventNames[fInput] = eventFolderName ;
827 fInput++ ;
990119d6 828}
7b7c1533 829
990119d6 830//__________________________________________________________________
702ab87e 831void AliPHOSDigitizer::Print(const Option_t *)const
21cd0c07 832{
dd5c4038 833 // Print Digitizer's parameters
351dd634 834 AliInfo(Form("\n------------------- %s -------------", GetName() )) ;
88cb7938 835 if( strcmp(fEventFolderName.Data(), "") != 0 ){
836 printf(" Writing Digits to branch with title %s\n", fEventFolderName.Data()) ;
837
838 Int_t nStreams ;
839 if (fManager)
840 nStreams = GetNInputStreams() ;
841 else
842 nStreams = fInput ;
843
844 Int_t index = 0 ;
845 for (index = 0 ; index < nStreams ; index++) {
846 TString tempo(fEventNames[index]) ;
847 tempo += index ;
848 AliPHOSGetter * gime = AliPHOSGetter::Instance(fInputFileNames[index], tempo) ;
849 TString fileName( gime->GetSDigitsFileName() ) ;
e191bb57 850 if ( fEventNames[index] != AliConfig::GetDefaultEventFolderName()) // only if not the default folder name
88cb7938 851 fileName = fileName.ReplaceAll(".root", "") + "_" + fEventNames[index] + ".root" ;
852 printf ("Adding SDigits from %s %s\n", fInputFileNames[index].Data(), fileName.Data()) ;
853 }
854 AliPHOSGetter * gime = AliPHOSGetter::Instance(GetTitle(), fEventFolderName) ;
855 printf("\nWriting digits to %s", gime->GetDigitsFileName().Data()) ;
856
857 printf("\nWith following parameters:\n") ;
27a73a5d 858 printf(" Electronics noise in EMC (fPinNoise) = %f GeV\n", fPinNoise ) ;
859 printf(" Threshold in EMC (fEMCDigitThreshold) = %f GeV\n", fEMCDigitThreshold ) ;
860 printf(" Noise in CPV (fCPVNoise) = %f aux units\n", fCPVNoise ) ;
861 printf(" Threshold in CPV (fCPVDigitThreshold) = %f aux units\n",fCPVDigitThreshold ) ;
88cb7938 862 printf(" ---------------------------------------------------\n") ;
990119d6 863 }
8cb3533f 864 else
351dd634 865 AliInfo(Form("AliPHOSDigitizer not initialized" )) ;
8cb3533f 866
867}
88cb7938 868
8cb3533f 869//__________________________________________________________________
21cd0c07 870 void AliPHOSDigitizer::PrintDigits(Option_t * option)
871{
3bf72d32 872 // Print a table of digits
21cd0c07 873
88cb7938 874 AliPHOSGetter * gime = AliPHOSGetter::Instance(GetTitle(), fEventFolderName) ;
3bf72d32 875 TClonesArray * digits = gime->Digits() ;
876
351dd634 877 AliInfo(Form("%d", digits->GetEntriesFast())) ;
88cb7938 878 printf("\nevent %d", gAlice->GetEvNumber()) ;
879 printf("\n Number of entries in Digits list %d", digits->GetEntriesFast() ) ;
880
11f9c5ff 881
3bf72d32 882 if(strstr(option,"all")||strstr(option,"EMC")){
8cb3533f 883 //loop over digits
884 AliPHOSDigit * digit;
88cb7938 885 printf("\nEMC digits (with primaries):\n") ;
886 printf("\n Id Amplitude Time Index Nprim: Primaries list \n") ;
9688c1dd 887 Int_t maxEmc = gime->PHOSGeometry()->GetNModules()*gime->PHOSGeometry()->GetNCristalsInModule() ;
8cb3533f 888 Int_t index ;
a6eedfad 889 for (index = 0 ; (index < digits->GetEntriesFast()) &&
88cb7938 890 (dynamic_cast<AliPHOSDigit *>(digits->At(index))->GetId() <= maxEmc) ; index++) {
7b7c1533 891 digit = (AliPHOSDigit * ) digits->At(index) ;
21cd0c07 892 if(digit->GetNprimary() == 0)
893 continue;
27a73a5d 894// printf("%6d %8d %6.5e %4d %2d :",
895// digit->GetId(), digit->GetAmp(), digit->GetTime(), digit->GetIndexInList(), digit->GetNprimary()) ; // YVK
896 printf("%6d %.4f %6.5e %4d %2d :",
897 digit->GetId(), digit->GetEnergy(), digit->GetTime(), digit->GetIndexInList(), digit->GetNprimary()) ;
8cb3533f 898 Int_t iprimary;
21cd0c07 899 for (iprimary=0; iprimary<digit->GetNprimary(); iprimary++) {
88cb7938 900 printf("%d ",digit->GetPrimary(iprimary+1) ) ;
21cd0c07 901 }
81d5f731 902 printf("\n") ;
21cd0c07 903 }
9688c1dd 904 }
3bf72d32 905
9688c1dd 906 if(strstr(option,"all")||strstr(option,"CPV")){
8cb3533f 907
9688c1dd 908 //loop over CPV digits
909 AliPHOSDigit * digit;
88cb7938 910 printf("\nCPV digits (with primaries):\n") ;
911 printf("\n Id Amplitude Time Index Nprim: Primaries list \n") ;
9688c1dd 912 Int_t maxEmc = gime->PHOSGeometry()->GetNModules()*gime->PHOSGeometry()->GetNCristalsInModule() ;
913 Int_t index ;
a6eedfad 914 for (index = 0 ; index < digits->GetEntriesFast(); index++) {
9688c1dd 915 digit = (AliPHOSDigit * ) digits->At(index) ;
916 if(digit->GetId() > maxEmc){
81d5f731 917 printf("%6d %8d %4d %2d :",
11f9c5ff 918 digit->GetId(), digit->GetAmp(), digit->GetIndexInList(), digit->GetNprimary()) ;
9688c1dd 919 Int_t iprimary;
21cd0c07 920 for (iprimary=0; iprimary<digit->GetNprimary(); iprimary++) {
88cb7938 921 printf("%d ",digit->GetPrimary(iprimary+1) ) ;
21cd0c07 922 }
81d5f731 923 printf("\n") ;
21cd0c07 924 }
9688c1dd 925 }
8cb3533f 926 }
88cb7938 927
8cb3533f 928}
7b7c1533 929
9688c1dd 930//__________________________________________________________________
0bc3b8ed 931Float_t AliPHOSDigitizer::TimeOfNoise(void) const
9688c1dd 932{ // Calculates the time signal generated by noise
26a2ef9d 933 //PH Info("TimeOfNoise", "Change me") ;
04f0bda3 934 return gRandom->Rndm() * 1.28E-5;
8cb3533f 935}
7b7c1533 936
88cb7938 937//__________________________________________________________________
938void AliPHOSDigitizer::Unload()
939{
940
941 Int_t i ;
942 for(i = 1 ; i < fInput ; i++){
943 TString tempo(fEventNames[i]) ;
944 tempo += i ;
945 AliPHOSGetter * gime = AliPHOSGetter::Instance(fInputFileNames[i], tempo) ;
946 gime->PhosLoader()->UnloadSDigits() ;
947 }
948
949 AliPHOSGetter * gime = AliPHOSGetter::Instance(GetTitle(), fEventFolderName) ;
950 gime->PhosLoader()->UnloadDigits() ;
951}
952
7b7c1533 953//____________________________________________________________________________
90cceaf6 954void AliPHOSDigitizer::WriteDigits()
7b7c1533 955{
956
957 // Makes TreeD in the output file.
958 // Check if branch already exists:
959 // if yes, exit without writing: ROOT TTree does not support overwriting/updating of
960 // already existing branches.
961 // else creates branch with Digits, named "PHOS", title "...",
962 // and branch "AliPHOSDigitizer", with the same title to keep all the parameters
963 // and names of files, from which digits are made.
964
f98c06a1 965 AliPHOSGetter * gime = AliPHOSGetter::Instance(GetTitle()) ;
88cb7938 966 const TClonesArray * digits = gime->Digits() ;
967 TTree * treeD = gime->TreeD();
968
7b7c1533 969 // -- create Digits branch
970 Int_t bufferSize = 32000 ;
2524c56f 971 TBranch * digitsBranch = treeD->Branch("PHOS","TClonesArray",&digits,bufferSize);
88cb7938 972 digitsBranch->SetTitle(fEventFolderName);
973 digitsBranch->Fill() ;
fbf811ec 974
88cb7938 975 gime->WriteDigits("OVERWRITE");
976 gime->WriteDigitizer("OVERWRITE");
977
978 Unload() ;
b3690abb 979
7b7c1533 980}