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
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;
202 last.bc = o2::constants::lhc::LHCMaxBunches;
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
std::vector< std::string > header
configStandalone Light OpenGL display display_light Apply smoothing to points Enable Z buffer Highlight links Highlight seeds Highlight sector tracks Highlight final tracks Show individual sector
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error First event to Number of events to Number of iterations to Number of iterations to Number of initial iterations excluded from const char Directory with events to Events directory is and not inside events Show standalone event Run event generator maximum time bin of continuous for triggered for automatic continuous for automatic continuous triggered uint64_t
container for the LHC InterFace data
char error[CURL_ERROR_SIZE]
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
GLint first
Definition glcorearb.h:399
GLenum GLint * range
Definition glcorearb.h:1899
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
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"