DataReader.cpp 19.8 KB
Newer Older
1
2
3
4
 /** @defgroup ana Analysis
 *   @ingroup ana
 *   @file DataReader.cpp
 *   @brief Implementation of DataReader.
5
 *
6
7
 *  Function definitions for DataReader are provided.
 *  This class reads a rootfile with raw waveforms
8
9
10
11
12
13
14
15
16
17
18
 *  that are processed by rcdaqAnalysis running on prdf files.
 *  Then, in the event loop, analysis classes can be called.
 *
 *  @author Yakov Kulinich, Riccardo Longo
 *  @bug No known bugs.
 */

#include <TFile.h>
#include <TTree.h>

#include <iostream>
19
#include <fstream>
20
21

#include "DataReader.h"
Yakov Kulinich's avatar
Yakov Kulinich committed
22
#include "Analysis.h"
23
#include "Containers.h"
24
25
#include "RPD.h"
#include "ZDC.h"
26
#include "Visualizer.h"
27

28
29
30
31
32
33
34
35
36

/** @brief Default Constructor for DataReader.
 */
DataReader::DataReader() : DataReader( 0, 0, "", 0 ){

}

/** @brief Constructor for DataReader.
 *
37
38
 *  @param nCh Number of channels being read
 *  @param nSamp Number of samples per channel
39
40
41
42
43
44
45
46
47
48
49
 */
DataReader::DataReader( const unsigned int nCh, const unsigned int nSamp )
  : DataReader( nCh, nSamp, "", 0 ){

  // here say we will read in list of files, maybe
  // there is better way to do it, just an idea for now.
  m_readListOfFiles = true;
}

/** @brief Constructor for DataReader.
 *
50
51
52
 *  @param nCh Number of channels being read
 *  @param nSamp Number of samples per channel
 *  @param fNameIn Input filename.
53
54
55
56
 */
DataReader::DataReader( const uint nCh, const uint nSamp,
			const std::string& fNameIn )
  : DataReader( nCh, nSamp, fNameIn, 0 ){
57

58
59
60
61
62
}


/** @brief Constructor for DataReader.
 *
63
64
65
66
 *  @param nCh Number of channels being read
 *  @param nSamp Number of samples per channel
 *  @param4 fNameIn Output file name (custom)
 *  @param3 runNum Run number being used.
67

68
69
70
 */
DataReader::DataReader( const uint nCh, const uint nSamp,
			const std::string& fNameIn, const uint runNum )
Yakov Kulinich's avatar
Yakov Kulinich committed
71
72
73
  : m_nCh( nCh ), m_nSamp( nSamp ), m_fNameIn( fNameIn ),
    m_runNumber( runNum ), m_readListOfFiles( false ), m_fIn( NULL ){

74
75
76
77
78
79
}


/** @brief Destructor for DataReader.
 */
DataReader::~DataReader(){
Yakov Kulinich's avatar
Yakov Kulinich committed
80

81

82
83
84
85
86
87
  for( auto& time : m_time ){
      delete time; time = NULL;
  }
  for( auto& det : m_detectors ){
      delete det; det = NULL;
  }
Yakov Kulinich's avatar
Yakov Kulinich committed
88
89
90
  for( auto& ana : m_ana ){
    delete ana; ana = NULL;
  }
91
92
93
  for( auto& det_ana : m_det_ana ){
    delete det_ana; det_ana = NULL;
  }
94

95
96
  //This line deletes all histograms so we don't have to
  gDirectory->GetList()->Delete();
97

98
99
100
  delete m_alignment; m_alignment = NULL;
  delete m_fOut; m_fOut = NULL;
  delete m_fIn; m_fIn = NULL;
101

Yakov Kulinich's avatar
Yakov Kulinich committed
102
103
}

104
/** @brief Adds an analysis to vector of analysis to be executed before the detector analysis (e.g. WaveForm Analysis)
Yakov Kulinich's avatar
Yakov Kulinich committed
105
 *
106
 *  @param ana Pointer to an Analysis.
Yakov Kulinich's avatar
Yakov Kulinich committed
107
108
109
 *
 *  @return none
 */
110
void DataReader::AddPreAnalysis( Analysis* ana ){
clantz's avatar
clantz committed
111
  ana->SetVerbosity( m_verbose );
Yakov Kulinich's avatar
Yakov Kulinich committed
112
  m_ana.push_back( ana );
113
114
}

115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/** @brief Adds an analysis to vector of detector analysis (e.g. ZDC, RPD or combined)
 *
 *  @param ana Pointer to an Analysis.
 *
 *  @return none
 */
void DataReader::AddDetectorAnalysis( Analysis* det_ana ){
  det_ana->SetVerbosity( m_verbose );
  m_det_ana.push_back( det_ana );
}

/**
 * @brief Allows the user to select which detectors will enter the waveform analysis and the detector analysis s
 * @param _useZDC1 set it true to look to ZDC1
 * @param _useZDC2 set it true to look to ZDC2
 * @param _useRPD  set it true to look to the RPD
 */
void DataReader::SelectDetectorForAnalysis(bool _useZDC1, bool _useZDC2, bool _useRPD){

    useZDC1 = _useZDC1;
    useZDC2 = _useZDC2;
    useRPD = _useRPD;

    std::string enableDet;
    enableDet = "Detectors Selected for Analysis: ";

    if (useZDC1) enableDet += " ZDC1 " ;
    if (useZDC2) enableDet += " ZDC2 " ;
    if (useRPD) enableDet += " RPD " ;

    enableDet += ";";
    std::cout << enableDet << std::endl;
}
148
149
150

/** @brief Enables the read from list of files option for DataReader
 *
151
 *  @param listname name of the list of files to be processed (with the full path if it's not in the execution folder)
152
153
154
 *
 *  @return none
 */
Yakov Kulinich's avatar
Yakov Kulinich committed
155
void DataReader::ReadListOfFiles( std::string listname ){
156
157
158
159
160

    m_readListOfFiles = true;
    m_fListOfFiles = listname;
}

Riccardo Longo's avatar
Riccardo Longo committed
161
162
163
164
165

/**
 * @brief Reads the .xml configuration file and load characteristics for all the channels, immediately sorted into detectors objects
 * @param _inFile
 */
166
void DataReader::LoadAlignmentFile(std::string _inFile ){
Riccardo Longo's avatar
Riccardo Longo committed
167
168
169
170
171
172
173
174

    m_XMLparser = new XMLSettingsReader();

    if (!m_XMLparser->parseFile(_inFile)) {
            std::cerr << " Data Reader could not parse file : " << _inFile << std::endl;
            return;
    }

175
    m_alignment = new Alignment();
176
    m_alignment->runNumber = m_runNumber;
177

Riccardo Longo's avatar
Riccardo Longo committed
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
    std::cout << "Loading .xml Alignment File..." << std::endl;
    std::cout << "Found " << m_XMLparser->getBaseNodeCount("Alignment") << " alignment entries " << std::endl;
    std::cout << "Retrieving the information for run " << m_runNumber << std::endl;

    int run;
    for (unsigned int i = 0; i < m_XMLparser->getBaseNodeCount("Alignment"); i++) {
        m_XMLparser->getChildValue("Alignment",i,"run",run);
        if(run != m_runNumber) continue;
        std::cout << "Found Run Entry in Alignment file for run " << m_runNumber << std::endl;
        m_XMLparser->getChildValue("Alignment",i,"x_table",m_alignment->x_table);
        m_XMLparser->getChildValue("Alignment",i,"y_table",m_alignment->y_table);
        m_XMLparser->getChildValue("Alignment",i,"upstream_Det",m_alignment->upstream_Det);
        m_XMLparser->getChildValue("Alignment",i,"mid_Det",m_alignment->mid_Det);
        m_XMLparser->getChildValue("Alignment",i,"downstream_Det",m_alignment->downstream_Det);
        m_XMLparser->getChildValue("Alignment",i,"target_In",m_alignment->target_In);
        m_XMLparser->getChildValue("Alignment",i,"lead_In",m_alignment->lead_In);
        m_XMLparser->getChildValue("Alignment",i,"magnet_On",m_alignment->magnet_On);
    }

    if(m_alignment == NULL) std::cout << "WARNING: ALIGNMENT NOT FOUND!!!" << std::endl;
198
    delete m_XMLparser; m_XMLparser = NULL;
Riccardo Longo's avatar
Riccardo Longo committed
199
    return;
200

Riccardo Longo's avatar
Riccardo Longo committed
201
202
}

203
204
205
206
/**
 * @brief Reads the .xml configuration file and load characteristics for all the channels, immediately sorted into detectors objects
 * @param _inFile
 */
207
void DataReader::LoadConfigurationFile(std::string _inFile ){
208
209
210
211
212

    m_XMLparser = new XMLSettingsReader();

    if (!m_XMLparser->parseFile(_inFile)) {
            std::cerr << " Data Reader could not parse file : " << _inFile << std::endl;
213
            return;
214
215
216
217
218
    }

    std::cout << "Loading .xml Configuration File..." << std::endl;
    std::cout << "Found " << m_XMLparser->getBaseNodeCount("channel") << " channel entries " << std::endl;

219
    std::vector < Channel* > channelEntries;
220
221
222
    int first_run, last_run;

    for (unsigned int i = 0; i < m_XMLparser->getBaseNodeCount("channel"); i++) {
223
        Channel *buffer_ch = new Channel();
224
225
226
227
        m_XMLparser->getChildValue("channel",i,"start_run",first_run);
        m_XMLparser->getChildValue("channel",i,"end_run",last_run);

        //Discard entries for any channel that does not apply to our run
228
        if(m_runNumber < first_run || m_runNumber > last_run) continue;
229
230

        //If the entry applies, we store it in the vector
231
232
233
234
235
236
237
238
239
        m_XMLparser->getChildValue("channel",i,"detector",buffer_ch->detector);
        m_XMLparser->getChildValue("channel",i,"name",buffer_ch->name);
        m_XMLparser->getChildValue("channel",i,"mapping_row",buffer_ch->mapping_row);
        m_XMLparser->getChildValue("channel",i,"mapping_column",buffer_ch->mapping_column);
        m_XMLparser->getChildValue("channel",i,"delay",buffer_ch->delay);
        m_XMLparser->getChildValue("channel",i,"offset",buffer_ch->offset);
        m_XMLparser->getChildValue("channel",i,"HV",buffer_ch->HV);
        m_XMLparser->getChildValue("channel",i,"is_on",buffer_ch->is_on);
        m_XMLparser->getChildValue("channel",i,"Vop",buffer_ch->Vop);
240

241
242
243
244
245
246
247
248
        bool isNew(true);
        for( int k = 0; k < channelEntries.size(); k++){
            if(buffer_ch->name == channelEntries.at(k)->name){
                std::cout << "WARNING!!! Redundancy in your settings file for " << buffer_ch->name << ". Check it carefully. The second entry found will be skipped..." << std::endl;
                isNew = false;
            }
        }
        if(isNew) channelEntries.push_back(buffer_ch);
249
250
251
    }

    std::cout << "Loaded " << channelEntries.size() << " configuration entries " << std::endl;
252
    if( channelEntries.size() < 18 ) std::cout << "WARNING!!!! Number of Channels < 18. Seems that some entry is missed for this run in the config.xml. BE CAREFUL!" << std::endl;
253
254
    ZDC* zdc1 = new ZDC(channelEntries,m_runNumber,1);
    ZDC* zdc2 = new ZDC(channelEntries,m_runNumber,2);
255
    RPD* rpd = new RPD(channelEntries,m_runNumber, "TRPD18");
256

257
258
259
260
    m_detectors.push_back(zdc1); //Position 0 goes for ZDC1
    m_detectors.push_back(zdc2); //Position 1 goes for ZDC2
    m_detectors.push_back(rpd); //Position 2 goes for the RPD

261
    std::cout << "Detector configuration: loading complete! " << std::endl;
262
    delete m_XMLparser; m_XMLparser = NULL;
263
    return;
264
265
}

266
267
268
269
270
271
272
273
274
275

/** @brief Loads calibrated timing information for DRS4 modules based on run number
 *  @param _inFile Optional argument for loading a custom file
 *
 *  Uses run number to determine scan number and loads the appropriate DRS4 timing
 *  information from the 2018 Testbeam. After loading, we hand each Channel a
 *  pointer to its timing vector. Must be run after LoadConfigurationFile()
 *
 */
void DataReader::LoadTimingFile(std::string _inFile){
276

277
278
279
280
281
282
283
284
    std::string inFile,buffer;
    char data[12];
    float dat;
    std::vector< Channel* > vChannel;
    m_time.resize(5);
    for(int i = 0; i < 5; i++){
        m_time[i] = new std::vector< float >;
    }
285

286
287
288
289
    int chNo;
    int start[] = {79,  152, 190, 202, 215, 258 };
    int stop[]  = {112, 171, 200, 213, 231, 413 };
    int scanNum = 0;
290

291
292
293
294
295
296
    //If the user has selected a file, use it and skip determining the scan number
    if(_inFile != ""){
        std::cout << "Using timing file definied by user " << _inFile << std::endl;
        inFile = _inFile;
        goto open;
    }
297

298
299
300
301
302
303
304
305
306
307
308
    //Determine scan number using ranges defined by start and stop.
    //Scan 6-13 have identical timing data, so we treat them all as scan 6
    for(int i = 0; i < 6; i++){
        if(start[i]<=m_runNumber && stop[i]>=m_runNumber){
            scanNum = i+1;
        }
    }
    if(scanNum == 0){
        std::cerr << "Scan number not defined, defaulting timing data to Scan 1" << std::endl;
        scanNum = 1;
    }
309
    inFile = (std::string)std::getenv("JZCaPA") + Form("/Utils/Timing_data/2018scan%d.txt",scanNum);
310

311
312
313
314
315
316
    open:
    std::ifstream file( inFile.c_str() );
    if( !file.is_open() ){
        std::cerr << "WARNING: Timing data file didn't open " << inFile << std::endl;
        return;
    }
317

318
319
320
    //Get the headers out
    getline(file,buffer);
    getline(file,buffer);
321

322
323
324
    while(!file.eof()){
        getline(file,buffer);
        if(buffer == "") break;
325
326

        //Loop through the DRS4 modules pushing the data into the vector
327
328
329
330
331
332
333
334
335
336
337
        //and chopping off the front of the string
        for(int drs = 0; drs<4; drs++){
            buffer.copy( data , 11 );
            dat = atof(data);
            m_time[drs]->push_back( dat );
            buffer.erase(buffer.front(),11);
        }
        //The spacing on the file is a bit weird, so fill the last one differently
        m_time[4]->push_back( atof( buffer.c_str() ) );
    }
    file.close();
338

339
340
341
342
343
344
345
346
347
    //Loop through the detector vector and their Channel vectors assigning the
    //time vector based on hardware channel number (Channel::name)
    for( auto& det : m_detectors ){
        vChannel = det->GetChannelsVector();
        for( Channel* ch : vChannel ){
            buffer = ch->name;
            //Remove "Signal" from name and convert to int
            buffer.erase(0,6);
            chNo = atoi( buffer.c_str() );
348

349
350
351
352
353
354
355
356
357
358
            //If the channel already has a time vector, print an error and continue
            if(ch->pTimeVec != 0){
                std::cerr << "WARNING: Overwriting Channel time vector" << std::endl;
            }
            ch->pTimeVec = m_time[chNo/4];
        }
    }
    std::cout << "DRS4 Timing: loading complete " << std::endl;
}

359
360
361
362
363
364
365
366
367
368
369
370
/**
 * @brief DataReader::GetDetector allows the user to access the detectors objects after loading them at the beginning of the execution
 * @param _detName can be ZDC1 (upstream module), ZDC2 (downstream module) or RPD.
 * @return
 */
Detector* DataReader::GetDetector( std::string _detName ){

    if(_detName != "ZDC1" && _detName != "ZDC2" && _detName != "zdc1" && _detName != "zdc2" && _detName != "RPD" && _detName != "rpd")
    {
        std::cout << "The detector you're looking for is not ZDC1, ZDC2 or RPD. Please check and correct your request " << std::endl;
        return NULL;
    }
Riccardo Longo's avatar
Riccardo Longo committed
371
372
373
    if( _detName == "ZDC1" || _detName == "zdc1" ) return m_detectors.at(0);
    if( _detName == "ZDC2" || _detName == "zdc2" ) return m_detectors.at(1);
    if( _detName == "RPD" || _detName == "rpd" ) return m_detectors.at(2);
374

Riccardo Longo's avatar
Riccardo Longo committed
375
376
    std::cout << "WARNING: detector recognition glitch. NULL pointer being returned..." << std::endl;
    return NULL;
377
378
}

379

380
381
382
383
384
385
/** @brief Console output update
 *  @return none
 *
 *  Called by the TTimer in ProcessEvents
 *  Updates the console with CPU and RAM usage,
 *  number of events processed and events/second
clantz's avatar
clantz committed
386
 *  if verbosity is not zero
387
 */
388
void DataReader::UpdateConsole( Long_t _updateRate){
389

clantz's avatar
clantz committed
390
    if( m_verbose == 0 ){ return; }
391
    if(m_event!=0){
392
393


394
395
        // Get CPU information
        gSystem->GetCpuInfo(&cpuInfo, 100);
396
        gSystem->GetProcInfo( &procInfo );
397
398
399
400
401
        // Get Memory information
        gSystem->GetMemInfo(&memInfo);
        // Get events/second
        double rate = 1000*(m_event-m_event_old)/_updateRate;
        m_event_old = m_event;
402

403
404
        std::cout << "\r" << std::left <<  Form("Processed %5d events, ", m_event);
        std::cout << Form( "%5.1f ev/s, ", rate);
clantz's avatar
clantz committed
405
        std::cout << Form( "CPU use/time: %3d%%/%6.1fs, ", (int)cpuInfo.fTotal, (double)procInfo.fCpuSys + procInfo.fCpuUser);
406
407
        std::cout << Form( "RAM:%4.1f/%4.1fGB, ", (double)memInfo.fMemUsed/1024, (double)memInfo.fMemTotal/1024);
        std::cout << Form( "RAM used by process: %ldMB   ", (procInfo.fMemResident + procInfo.fMemVirtual)/1024 );
408
409
        std::cout << std::flush;
    }
410
411
}

412
/** @brief Run method for DataReader
413
 *  @return none
414
415
416
 *
 *  Call Initialize, ProcessEvents, and Finalize
 *  Made so the driver class only has to call one method.
417
 *
418
419
420
 */
void DataReader::Run(){

421
  std::cout << "Initializing " << std::endl;
422
  Initialize();
423
  std::cout << "Initialization done " << std::endl;
424
425
426
427
  if( !m_fIn ){
      std::cerr << "Input file didn't open... exiting" << std::endl;
      return;
  }
428
  ProcessEvents();
429
  std::cout << "Events done " << std::endl;
430
431
432
  Finalize();
}

433
434
435
436
437
438
/** @brief Initialization method for DataReader
 *
 *  Select which file(s) to read. For now just a single
 *  file, later this can be extended to read many and make
 *  chain of files for example. Also create and initialize
 *  the analysis that will be running.
439
 *
440
441
442
443
444
 *  @return none
 */
void DataReader::Initialize(){

  if( m_readListOfFiles ){
445
446
447
448
449
450
451
452
453
454
455
456
457

    // Riccardo - 21/01/2019 - TChain implementation
    // The file list name is supposed to be already set
    m_fileChain = new TChain("tree");
    std::ifstream inFile;
    inFile.open(m_fListOfFiles.c_str());
    std::string reader_buff;
    while(inFile >> reader_buff){
        //Let's push all the files in the list into the TChain
        m_fileChain->Add(reader_buff.c_str());
    }
    /** TODO - Add fileChain reading below
     */
458
  } else {
Yakov Kulinich's avatar
Yakov Kulinich committed
459
    m_fIn = TFile::Open( m_fNameIn.c_str() );
460
  }
Yakov Kulinich's avatar
Yakov Kulinich committed
461

462
463
464
465
466
467
  // If no output directory is specified by the user
  // one is created for this run in $JZCaPA/results
  if( m_outputDir == "" ){
      m_outputDir = (std::string)std::getenv("JZCaPA") + Form("/results/run%d/",m_runNumber);
      gSystem->Exec( ("mkdir -p " + m_outputDir).c_str() );
  }
468

Yakov Kulinich's avatar
Yakov Kulinich committed
469
470
471
472
  // If we are reading a list of files, or have no run number
  // make default name output.root, otherwise make it
  // outputN.root, where N is a run number of a file.
  std::string fNameOut = m_readListOfFiles ?
473
    (m_outputDir + "output.root") : Form( (m_outputDir + "output%d.root").c_str(), m_runNumber );
Yakov Kulinich's avatar
Yakov Kulinich committed
474
475

  m_fOut = new TFile( fNameOut.c_str(), "RECREATE" );
476
477
478
  m_tOut = new TTree("AnalysisTree","AnalysisTree");
  m_tOut->Branch("runNumber", &m_runNumber, "m_runNumber/i");
  m_tOut->Branch("evNo", &m_event, "m_event/I");
479
480
  m_tOut->Branch("x_table", &m_alignment->x_table, "x_table/D");
  m_tOut->Branch("y_table", &m_alignment->y_table, "y_table/D");
481

482
483
484
  for( uint detID = 0; detID < (int) m_detectors.size(); detID++ ){
     m_detectors.at(detID)->SetAlignment(m_alignment);
  }
Yakov Kulinich's avatar
Yakov Kulinich committed
485
486
487
488
  for( auto& ana : m_ana ){
    ana->Initialize();
    ana->SetupHistograms();
  }
489
  std::cout << "After loop suspect " << std::endl;
490
  for( auto& det_ana : m_det_ana ){
491
    det_ana->Initialize( m_detectors );
492
    det_ana->SetupHistograms();
493
    det_ana->SetBranches( m_tOut );
494
  }
495
496
497
498
499
500
501
502
503
504
505
506
507
508
}



/** @brief Process Events method for DataReader
 *
 *  Connect to files / chain of files.
 *  Read tree event by event, and fill basic waveforms.
 *  So far (12.12.18) For each event - Read Raw data for all channels,
 *  put it into 2D vector size NxM where N = nCh, M = nSamp
 *  Also, For each event - Fill N 1D histos that have size M.
 *  Then one can send these to any Analysis function they make.
 *  Here for example (12.12.18), we send to WFAnalysis::AnalyzeEvent( .. )
 *  See below - Have fun!
509
 *
510
511
512
 *  @return none
 */
void DataReader::ProcessEvents(){
Yakov Kulinich's avatar
Yakov Kulinich committed
513

514

515
516
517
  /** TODO : add reading for list of files
    * Please note that many of the implementations are now for a single-file treatment
    */
518
    std::cout << "Before retrieving pointers " << std::endl;
Yakov Kulinich's avatar
Yakov Kulinich committed
519
  TTree* tree = static_cast< TTree* >( m_fIn->Get( "tree" ) );
520

521
522
523
  //Specific pointers to each detector, if needed afterwards
  ZDC* zdc1 = static_cast< ZDC* >( GetDetector("ZDC1") );
  ZDC* zdc2 = static_cast< ZDC* >( GetDetector("ZDC2") );
524
  RPD* rpd =  static_cast< RPD* >( GetDetector("TRPD") );
525

526
  std::cout << "Before looping on detectors " << std::endl;
527
528
529
530
531
532
533
534
  //All the raw channels addresses set for read-out
  for( uint detID = 0; detID < (int) m_detectors.size(); detID++ ){
       m_detectors.at(detID)->SetBranches(tree);
       m_detectors.at(detID)->SetNSamples(m_nSamp);
       m_detectors.at(detID)->DeclareHistograms();
  }

  std::cout << "File: " << m_fIn->GetName() << " has " << tree->GetEntries() << " events." << std::endl;
535

536
  // !! EVENT LOOP
537
  for( int ev = 0; ev < tree->GetEntries(); ev++ ){
538
    m_event = ev;
539
    tree->GetEntry( ev );
540

541
542
543
    // Fill the raw waveforms
    for( uint detID = 0; detID < (int) m_detectors.size(); detID++ )
        m_detectors.at(detID)->FillHistograms();
544

Yakov Kulinich's avatar
Yakov Kulinich committed
545
    // Now call all analysis and run their AnalyzeEvent.
546
547
    // Can either send a vector of histos, or a 2D vector
    // Of all the data, depending on what you want to do.
548
    // Note that at the moment none of this methods is doing anything
Yakov Kulinich's avatar
Yakov Kulinich committed
549
    for( auto& ana : m_ana ){
550
      //raw data analysis
551
552
        if(useZDC1) ana->AnalyzeEvent( zdc1->GetChannelsVector() );
        if(useZDC2) ana->AnalyzeEvent( zdc2->GetChannelsVector() );
553
        if(useRPD) ana->AnalyzeEvent( rpd->GetChannelsVector() );
554
        }
555
    for( auto& det_ana : m_det_ana ){
556
      //Detector level analysis
557
      det_ana->AnalyzeEvent(  );
Yakov Kulinich's avatar
Yakov Kulinich committed
558
    }
559

560
  m_tOut->Fill();
561

562
563
564
565
566
  } // End event loop
}

/** @brief Finalize method for DataReader
 *
567
 *  Close any input files
568
 *  Call analysis finalize methods
569
 *
570
571
572
 *  @return none
 */
void DataReader::Finalize(){
573

574
575
576
577
  if( m_fIn ){
    m_fIn->Close();
  }

Yakov Kulinich's avatar
Yakov Kulinich committed
578
579
580
581
  // enter the output file since
  // we will be writing to it now.
  m_fOut->cd();

582
583
584
585
586
  //Add label, if wanted
  //To understand the kind of measurement, we use alignments
  Visualizer* viz = new Visualizer( "ATLAS" );

  if(useLabel){
587
      viz->SetOutputDirectory( m_outputDir );
588
      viz->SetTestBeamLabel( m_runNumber, m_alignment);
589
590
  }

Yakov Kulinich's avatar
Yakov Kulinich committed
591
592
593
  for( auto& ana : m_ana ){
    ana->Finalize();
  }
594
  for( auto& det_ana : m_det_ana ){
595
    det_ana->AssignVisualizer( viz );
596
597
    det_ana->Finalize();
  }
Yakov Kulinich's avatar
Yakov Kulinich committed
598

599
  m_tOut->Write();
Yakov Kulinich's avatar
Yakov Kulinich committed
600
  m_fOut->Close();
601
}