Project
Loading...
Searching...
No Matches
emc-channel-data-producer.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
15
19
20#include "Framework/Task.h"
22
27#include <random>
28
29#include "TFile.h"
30#include "TH2.h"
31#include "TH1.h"
32
33#include <unistd.h>
34
35using namespace o2::framework;
36
37DataProcessorSpec generateData(const std::string nameRootFile, const std::string nameInputHist, const std::string nameInputHistAdd, const bool isTimeCalib, const int nCellsPerEvent, const int nEventsMax);
38
39// we need to add workflow options before including Framework/runDataProcessing
40void customize(std::vector<ConfigParamSpec>& workflowOptions)
41{
42 std::vector<ConfigParamSpec> options{
43 {"inputRootFile", VariantType::String, "", {"input root file from which data is taken, if empty, random data will be produced"}},
44 {"nameInputHist", VariantType::String, "", {"name of the 2d histogram inside the root file used for the data generation"}},
45 {"nameInputHistAdd", VariantType::String, "", {"Same as nameInputHist but can be added in addition if the time distribution is also needed for the bad channel calibration"}},
46 {"isInputTimeCalib", VariantType::Bool, false, {"input is produced for time clibration or bad channel calibration. Information is needed if inputRootFiel is specified as it has ifferent content for bad channel calib and time calib"}},
47 {"nEvents", VariantType::Int, 10000, {"number of events that will be processed"}},
48 {"nCellsPerEvent", VariantType::Int, 5, {"number of cells per emcal triggered event"}}};
49
50 std::swap(workflowOptions, options);
51}
52
54
56{
57
58 const std::string nameRootFile = config.options().get<std::string>("inputRootFile");
59 const std::string nameInputHist = config.options().get<std::string>("nameInputHist");
60 const std::string nameInputHistAdd = config.options().get<std::string>("nameInputHistAdd");
61 const bool isTimeCalib = config.options().get<bool>("isInputTimeCalib");
62 int nEventsMax = config.options().get<int>("nEvents");
63 const int nCellsPerEvent = config.options().get<int>("nCellsPerEvent");
64
65 WorkflowSpec workflow;
66 workflow.emplace_back(generateData(nameRootFile, nameInputHist, nameInputHistAdd, isTimeCalib, nCellsPerEvent, nEventsMax));
67
68 return workflow;
69}
70
71DataProcessorSpec generateData(const std::string nameRootFile, const std::string nameInputHist, const std::string nameInputHistAdd, const bool isTimeCalib, const int nCellsPerEvent, const int nEventsMax)
72{
73 std::vector<OutputSpec> outputSpecs;
74 outputSpecs.emplace_back(o2::header::gDataOriginEMC, "CELLS", 0, o2::framework::Lifetime::Timeframe);
75 outputSpecs.emplace_back(o2::header::gDataOriginEMC, "CELLSTRGR", 0, o2::framework::Lifetime::Timeframe);
76
77 // bool if realistic time distribution should be used in bad channel calib
78 bool useBadCellTimeInfo = false;
79
80 // initialize random number generators to generate cell time, cell energy and cellID
81 std::default_random_engine generator;
82 std::uniform_real_distribution<> disCellID(0, 17663);
83 std::exponential_distribution<float> disEnergy(3.5);
84 std::normal_distribution<float> disTime(20, 10);
85
86 // load 2d root file in case the paths are specified
87 TH2F* h2d = nullptr;
88 std::array<TH1F*, 17664> arrCellTimeHists;
89 if (nameRootFile.find(".root") != std::string::npos) {
90
91 TFile* f = TFile::Open(nameRootFile.c_str());
92 if (!f) {
93 LOG(error) << "root file does not exist " << nameRootFile;
94 }
95 h2d = (TH2F*)f->Get(nameInputHist.c_str());
96 if (!h2d) {
97 LOG(error) << "histogram does not exist " << nameInputHist;
98 }
99 h2d->SetDirectory(nullptr);
100 if (!nameInputHistAdd.empty()) {
101 TH2F* h2dAdd = (TH2F*)f->Get(nameInputHistAdd.c_str());
102 if (!h2dAdd) {
103 LOG(error) << "histogram does not exist " << nameInputHistAdd;
104 }
105 h2dAdd->SetDirectory(nullptr);
106 useBadCellTimeInfo = true;
107 for (int i = 0; i < 17664; ++i) {
108 arrCellTimeHists[i] = (TH1F*)h2dAdd->ProjectionX(Form("proj_cell_time_%i", i), i + 1, i + 1);
109 arrCellTimeHists[i]->SetDirectory(nullptr);
110 }
111 }
112 }
113
114 return DataProcessorSpec{
115 "emcal-cell-data-producer",
116 Inputs{},
117 outputSpecs,
119 [=](ProcessingContext& ctx) mutable {
120 // set up event counter. Return as soon as maximum number of events is reached
121 static int nEvent = 0;
122 if (nEvent >= nEventsMax) {
123 LOG(info) << "reached maximum amount of events requested " << nEvent << ". returning now";
124 ctx.services().get<o2::framework::ControlService>().endOfStream();
125 }
126 LOG(debug) << "process event " << nEvent;
127 nEvent++;
128
129 // loop over cells
130 // ToDo: Make more realistic assumption that we dont always have the same amount of cells per event
132 for (int i = 0; i < nCellsPerEvent; ++i) {
133 double cellID = 0;
134 double cellE = 0;
135 double cellTime = 0;
136 if (h2d) { // get values from histogram
137 // case for time calibration
138 if (isTimeCalib) {
139 h2d->GetRandom2(cellTime, cellID);
140 cellE = disEnergy(generator);
141 // bad channel calibration
142 } else {
143 h2d->GetRandom2(cellE, cellID);
144 if (useBadCellTimeInfo) {
145 cellTime = arrCellTimeHists[cellID]->GetRandom();
146 } else {
147 cellTime = disTime(generator);
148 }
149 }
150 } else { // get values from random distributions
151 cellID = disCellID(generator);
152 cellE = disEnergy(generator);
153 cellTime = disTime(generator);
154 }
155 // for now only consider low gain cells. Maybe implement high gain cells
156 CellOutput.emplace_back(static_cast<int>(cellID), cellE, cellTime, o2::emcal::ChannelType_t::LOW_GAIN);
157 }
158 // send output
159 LOG(debug) << "sending " << CellOutput.size() << "cells";
161 TriggerOutput.emplace_back(0, 0, 0, CellOutput.size());
162
163 ctx.outputs().adoptContainer(Output{o2::header::gDataOriginEMC, "CELLS", 0}, std::move(CellOutput));
164 ctx.outputs().adoptContainer(Output{o2::header::gDataOriginEMC, "CELLSTRGR", 0}, std::move(TriggerOutput));
165 }}};
166}
int32_t i
Helper function to tokenize sequences and ranges of integral numbers.
std::ostringstream debug
ConfigParamRegistry & options() const
DataProcessorSpec generateData(const std::string nameRootFile, const std::string nameInputHist, const std::string nameInputHistAdd, const bool isTimeCalib, const int nCellsPerEvent, const int nEventsMax)
WorkflowSpec defineDataProcessing(ConfigContext const &config)
void customize(std::vector< ConfigParamSpec > &workflowOptions)
GLdouble f
Definition glcorearb.h:310
constexpr o2::header::DataOrigin gDataOriginEMC
Definition DataHeader.h:565
@ LOW_GAIN
Low gain channel.
Definition Constants.h:34
Defining PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
std::vector< DataProcessorSpec > WorkflowSpec
std::vector< InputSpec > Inputs
std::vector< T, o2::pmr::polymorphic_allocator< T > > vector
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"