Project
Loading...
Searching...
No Matches
SimReaderSpec.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
12#include "SimReaderSpec.h"
13
18#include "Framework/Lifetime.h"
27#include <fairlogger/Logger.h>
28#include <memory> // std::unique_ptr
29#include <cstring> // memcpy
30#include <string> // std::string
31#include <cassert>
32#include <chrono>
33#include <thread>
34#include <algorithm>
35#include <filesystem>
36#include <boost/interprocess/sync/named_semaphore.hpp>
37
38using namespace o2::framework;
39namespace o2lhc = o2::constants::lhc;
40
42namespace o2
43{
44namespace steer
45{
46
47std::vector<o2::ctp::CTPDigit>* ctptrigger = nullptr;
48float gIntRate = -1.;
49
50DataProcessorSpec getSimReaderSpec(SubspecRange range, const std::vector<std::string>& simprefixes, const std::vector<int>& tpcsectors, bool withTrigger)
51{
52 uint64_t activeSectors = 0;
53 for (const auto& tpcsector : tpcsectors) {
54 activeSectors |= (uint64_t)0x1 << tpcsector;
55 }
56
57 auto doit = [range, tpcsectors, activeSectors, withTrigger](ProcessingContext& pc) {
59 auto& context = mgr.getDigitizationContext();
60 auto eventrecords = context.getEventRecords();
61
62 if (withTrigger) {
63 // fetch the digits and transport them as part of the context
64 LOG(info) << "Setting CTP trigger object to " << ctptrigger;
65 context.setCTPDigits(ctptrigger);
66 }
67
68 // inject the global interaction rate information
69 context.setDigitizerInteractionRate(gIntRate);
70
71 for (auto const& sector : tpcsectors) {
72 // Note: the TPC sector header was serving the sector to lane mapping before
73 // now the only remaining purpose is to propagate the mask of valid sectors
74 // in principle even that is not necessary any more because every sector has
75 // a dedicated route bound to the sector numbers as subspecification and the
76 // merging can be done based on that. However if we in the future go over to
77 // a multipart scheme again, we again will need the information, so we keep it
78 // For the moment, sector member in the sector header is in sync with
79 // subspecification of the route
80 o2::tpc::TPCSectorHeader header{sector};
81 header.activeSectors = activeSectors;
82 pc.outputs().snapshot(OutputRef{"collisioncontext", static_cast<SubSpecificationType>(sector), {header}},
83 context);
84 }
85
86 // the first 36 channel numbers are reserved for the TPC, now publish the remaining
87 // channels
88 for (int subchannel = range.min; subchannel < range.max; ++subchannel) {
89 LOG(info) << "SENDING SOMETHING TO OTHERS";
90 pc.outputs().snapshot(
91 OutputRef{"collisioncontext", static_cast<SubSpecificationType>(subchannel)},
92 context);
93 }
94 pc.outputs().snapshot(OutputRef{"bunchFilling"}, mgr.getInteractionSampler().getBunchFilling());
95 // digitizer workflow runs only once
96 // send endOfData control event and mark the reader as ready to finish
97 pc.services().get<ControlService>().endOfStream();
98 pc.services().get<ControlService>().readyToQuit(QuitRequest::Me);
99 };
100
101 // init function return a lambda taking a ProcessingContext
102 auto initIt = [simprefixes, doit, withTrigger](InitContext& ctx) {
103 // initialize fundamental objects
105
106 if (withTrigger) {
107 // fetch the ctp trigger/digit information from the CTP file
108 auto triggerf = TFile(ctx.options().get<std::string>("triggerfile").c_str(), "OPEN");
109 auto tr = (TTree*)triggerf.Get("o2sim");
110 if (!tr) {
111 LOG(fatal) << "Did not find CTP TTree";
112 }
113 auto br = tr->GetBranch("CTPDigits");
114 if (!br) {
115 LOG(fatal) << "Did not find CTPDigit branch";
116 }
117 br->SetAddress(&ctptrigger);
118 br->GetEntry(0);
119 LOG(info) << " Read " << ctptrigger->size() << " CTP digits ";
120 }
121
122 // init gRandom
123 gRandom->SetSeed(ctx.options().get<int>("seed"));
124
125 if (simprefixes.size() == 0) {
126 LOG(error) << "No simulation prefix available";
127 } else {
128 LOG(info) << "adding " << simprefixes[0] << "\n";
129 mgr.addInputFile(simprefixes[0]);
130 for (int part = 1; part < simprefixes.size(); ++part) {
131 mgr.addInputSignalFile(simprefixes[part]);
132 }
133 }
134
135 gIntRate = ctx.options().get<float>("interactionRate"); // is interaction rate requested?
136 if (gIntRate < 1.f) {
137 gIntRate = 1.f;
138 }
139 // do we start from an existing context
140 auto incontextstring = ctx.options().get<std::string>("incontext");
141 LOG(info) << "INCONTEXTSTRING " << incontextstring;
142 if (incontextstring.size() > 0) {
143 auto success = mgr.setupRunFromExistingContext(incontextstring.c_str());
144 if (!success) {
145 LOG(fatal) << "Could not read collision context from " << incontextstring;
146 }
147 } else {
148 LOG(info) << "Imposing hadronic interaction rate " << gIntRate << "Hz";
149 mgr.getInteractionSampler().setInteractionRate(gIntRate);
152 mgr.getInteractionSampler().setFirstIR({0, o2::raw::HBFUtils::Instance().orbitFirstSampled});
153 mgr.getDigitizationContext().setFirstOrbitForSampling(o2::raw::HBFUtils::Instance().orbitFirstSampled);
154
155 auto setBCFillingHelper = [](auto& sampler, auto& bcPatternString) {
156 if (bcPatternString == "ccdb") {
157 LOG(info) << "Fetch bcPattern information from CCDB";
158 // fetch the GRP Object
160 auto grpLHC = ccdb.get<o2::parameters::GRPLHCIFData>("GLO/Config/GRPLHCIF");
161 LOG(info) << "Fetched injection scheme " << grpLHC->getInjectionScheme() << " from CCDB";
162 sampler.setBunchFilling(grpLHC->getBunchFilling());
163 } else {
164 sampler.setBunchFilling(bcPatternString);
165 }
166 };
167
168 auto bcPatternFile = ctx.options().get<std::string>("bcPatternFile");
169 if (!bcPatternFile.empty()) {
170 setBCFillingHelper(mgr.getInteractionSampler(), bcPatternFile);
171 }
172
173 mgr.getInteractionSampler().init();
174 mgr.getInteractionSampler().print();
175
176 // doing a random event selection/subsampling?
177 mgr.setRandomEventSequence(ctx.options().get<int>("randomsample") > 0);
178
179 // finalize collisions (with number of collisions asked)
180 auto col = ctx.options().get<int>("ncollisions");
181 if (col != 0) {
182 mgr.setupRun(col);
183 } else {
184 mgr.setupRun();
185 }
186
187 // --- we add QED contributions to the digitization context
188 // --- for now in between first and last real collision
189 auto qedprefix = ctx.options().get<std::string>("simPrefixQED");
190 if (qedprefix.size() > 0) {
191 o2::steer::InteractionSampler qedInteractionSampler;
192 if (!bcPatternFile.empty()) {
193 setBCFillingHelper(qedInteractionSampler, bcPatternFile);
194 }
195
196 // get first and last "hadronic" interaction records and let
197 // QED events range from the first bunch crossing to the last bunch crossing
198 // in this range
199 auto first = mgr.getDigitizationContext().getEventRecords().front();
200 auto last = mgr.getDigitizationContext().getEventRecords().back();
201 first.bc = 0;
203
204 const float ratio = ctx.options().get<float>("qed-x-section-ratio");
205 if (ratio <= 0.) {
206 throw std::runtime_error("no meaningful qed-x-section-ratio was provided");
207 }
208 const float hadronicrate = ctx.options().get<float>("interactionRate");
209 const float qedrate = ratio * hadronicrate;
210 LOG(info) << "QED RATE " << qedrate;
211 qedInteractionSampler.setInteractionRate(qedrate);
212 qedInteractionSampler.setFirstIR(first);
213 qedInteractionSampler.init();
214 qedInteractionSampler.print();
215 std::vector<o2::InteractionTimeRecord> qedinteractionrecords;
217 LOG(info) << "GENERATING COL TIMES";
218 t = qedInteractionSampler.generateCollisionTime();
219 while ((t = qedInteractionSampler.generateCollisionTime()) < last) {
220 qedinteractionrecords.push_back(t);
221 }
222 LOG(info) << "DONE GENERATING COL TIMES";
223
224 // get digitization context and add QED stuff
225 mgr.getDigitizationContext().fillQED(qedprefix, qedinteractionrecords);
226 mgr.getDigitizationContext().printCollisionSummary(true, 2000); // print with QED but truncate output
227 }
228 // --- end addition of QED contributions
229
230 LOG(info) << "Initializing Spec ... have " << mgr.getDigitizationContext().getEventRecords().size() << " times ";
231 LOG(info) << "Serializing Context for later reuse";
232 mgr.writeDigitizationContext(ctx.options().get<std::string>("outcontext").c_str());
233 }
234
235 return doit;
236 };
237
238 std::vector<OutputSpec> outputs;
239 for (auto const& tpcsector : tpcsectors) {
240 outputs.emplace_back(
241 OutputSpec{{"collisioncontext"}, "SIM", "COLLISIONCONTEXT", static_cast<SubSpecificationType>(tpcsector), Lifetime::Timeframe});
242 }
243 for (int subchannel = range.min; subchannel < range.max; ++subchannel) {
244 outputs.emplace_back(
245 OutputSpec{{"collisioncontext"}, "SIM", "COLLISIONCONTEXT", static_cast<SubSpecificationType>(subchannel), Lifetime::Timeframe});
246 }
247
248 outputs.emplace_back(OutputSpec{{"bunchFilling"}, "SIM", "BUNCHFILLING", 0, Lifetime::Timeframe});
249
250 return DataProcessorSpec{
251 /*ID*/ "SimReader",
252 /*INPUT CHANNELS*/ Inputs{}, outputs,
253 /* ALGORITHM */
254 AlgorithmSpec{initIt},
255 /* OPTIONS */
256 Options{
257 {"interactionRate", VariantType::Float, 50000.0f, {"Total hadronic interaction rate (Hz)"}},
258 {"bcPatternFile", VariantType::String, "", {"Interacting BC pattern file (e.g. from CreateBCPattern.C)"}},
259 {"simPrefixQED", VariantType::String, "", {"Sim (QED) input prefix (example: path/o2qed). The prefix allows to find files like path/o2qed_Kine.root etc."}},
260 {"qed-x-section-ratio", VariantType::Float, -1.f, {"Ratio of cross sections QED/hadronic events. Determines QED interaction rate from hadronic interaction rate."}},
261 {"outcontext", VariantType::String, "collisioncontext.root", {"Output file for collision context"}},
262 {"incontext", VariantType::String, "", {"Take collision context from this file"}},
263 {"triggerfile", VariantType::String, "ctpdigits.root", {"Name of the CTP trigger/digit file to use"}},
264 {"seed", VariantType::Int, 0, {"Random seed for collision context generation"}},
265 {"ncollisions,n",
266 VariantType::Int,
267 0,
268 {"number of collisions to sample (default is given by number of entries in chain"}},
269 {"randomsample", VariantType::Int, 0, {"Draw collisions random instead of linear sequence. (Default no = 0)"}}}};
270}
271} // namespace steer
272} // namespace o2
o2::framework::DataAllocator::SubSpecificationType SubSpecificationType
container for the LHC InterFace data
Definition of the Names Generator class.
uint32_t col
Definition RawData.h:4
static BasicCCDBManager & instance()
o2::header::DataHeader::SubSpecificationType SubSpecificationType
const std::string & getInjectionScheme() const
static HitProcessingManager & instance()
get access to singleton instance
void setFirstIR(const o2::InteractionRecord &ir)
const o2::InteractionTimeRecord & generateCollisionTime()
void setInteractionRate(float rateHz)
GLuint sampler
Definition glcorearb.h:1630
GLenum GLint * range
Definition glcorearb.h:1899
constexpr int LHCMaxBunches
Defining PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
std::vector< ConfigParamSpec > Options
header::DataHeader::SubSpecificationType SubSpecificationType
std::vector< InputSpec > Inputs
DataProcessorSpec getSimReaderSpec(SubspecRange range, const std::vector< std::string > &simprefixes, const std::vector< int > &tpcsectors, bool withTrigger)
std::vector< o2::ctp::CTPDigit > * ctptrigger
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
void checkConsistency() const
Definition HBFUtils.cxx:53
void print() const
Definition HBFUtils.h:134
uint32_t orbitFirstSampled
1st orbit sampled in the MC
Definition HBFUtils.h:142
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"