32 std::string defaultGeomList{
"ALICE2"};
33 if (isUpgrade ==
true) {
34 defaultGeomList =
"ALICE3";
37 int nsimworkersdefault = std::max(1u, std::thread::hardware_concurrency() / 2);
38 options.add_options()(
39 "mcEngine,e", bpo::value<std::string>()->default_value(
"TGeant4"),
"VMC backend to be used.")(
40 "generator,g", bpo::value<std::string>()->default_value(
"boxgen"),
"Event generator to be used.")(
41 "trigger,t", bpo::value<std::string>()->default_value(
""),
"Event generator trigger to be used.")(
42 "modules,m", bpo::value<std::vector<std::string>>()->multitoken()->default_value(std::vector<std::string>({
"all"}),
"all modules"),
"list of modules included in geometry")(
43 "skipModules", bpo::value<std::vector<std::string>>()->multitoken()->default_value(std::vector<std::string>({
""}),
""),
"list of modules excluded in geometry (precendence over -m")(
44 "readoutDetectors", bpo::value<std::vector<std::string>>()->multitoken()->default_value(std::vector<std::string>(),
""),
"list of detectors creating hits, all if not given; added to to active modules")(
45 "skipReadoutDetectors", bpo::value<std::vector<std::string>>()->multitoken()->default_value(std::vector<std::string>(),
""),
"list of detectors to skip hit creation (precendence over --readoutDetectors")(
46 "detectorList", bpo::value<std::string>()->default_value(defaultGeomList),
47 "Use a specific version of ALICE, e.g., a predefined list."
48 "There is an 'official' list provided with:"
49 "\nALICE2 : The default configuration for Run 3"
50 "\nALICE2.1: The future configuration for Run 4"
51 "\nALICE3 : The far-future configuration for Run 5-6"
52 "\nAdditionally one can provide their own custom list of modules which should be included in the geometry."
53 "\nBy specifiying LIST:JSONFILE where LIST is a list present in JSONFILE.")(
54 "nEvents,n", bpo::value<unsigned int>()->default_value(0),
"number of events")(
55 "startEvent", bpo::value<unsigned int>()->default_value(0),
"index of first event to be used (when applicable)")(
56 "extKinFile", bpo::value<std::string>()->default_value(
"Kinematics.root"),
57 "name of kinematics file for event generator from file (when applicable)")(
58 "embedIntoFile", bpo::value<std::string>()->default_value(
""),
59 "filename containing the reference events to be used for the embedding")(
60 "bMax,b", bpo::value<float>()->default_value(0.),
"maximum value for impact parameter sampling (when applicable)")(
61 "isMT", bpo::value<bool>()->default_value(
false),
"multi-threaded mode (Geant4 only")(
62 "outPrefix,o", bpo::value<std::string>()->default_value(
"o2sim"),
"prefix of output files")(
63 "logseverity", bpo::value<std::string>()->default_value(
"INFO"),
"severity level for FairLogger")(
64 "logverbosity", bpo::value<std::string>()->default_value(
"medium"),
"level of verbosity for FairLogger (low, medium, high, veryhigh)")(
65 "configKeyValues", bpo::value<std::string>()->default_value(
""),
"semicolon separated key=value strings (e.g.: 'TPC.gasDensity=1;...")(
66 "configFile", bpo::value<std::string>()->default_value(
""),
"Path to an INI or JSON configuration file")(
67 "chunkSize", bpo::value<unsigned int>()->default_value(500),
"max size of primary chunk (subevent) distributed by server")(
68 "chunkSizeI", bpo::value<int>()->default_value(-1),
"internalChunkSize")(
69 "seed", bpo::value<ULong_t>()->default_value(0),
"initial seed as ULong_t (default: 0 == random)")(
70 "field", bpo::value<std::string>()->default_value(
"-5"),
"L3 field rounded to kGauss, allowed values +-2,+-5 and 0; +-<intKGaus>U for uniform field; \"ccdb\" for taking it from CCDB ")(
"vertexMode", bpo::value<std::string>()->default_value(
"kDiamondParam"),
"Where the beam-spot vertex should come from. Must be one of kNoVertex, kDiamondParam, kCCDB")(
71 "nworkers,j", bpo::value<int>()->default_value(nsimworkersdefault),
"number of parallel simulation workers (only for parallel mode)")(
72 "noemptyevents",
"only writes events with at least one hit")(
74 "timestamp", bpo::value<uint64_t>(),
"global timestamp value in ms (for anchoring) - default is now ... or beginning of run if ALICE run number was given")(
75 "run", bpo::value<int>()->default_value(-1),
"ALICE run number")(
76 "asservice", bpo::value<bool>()->default_value(
false),
"run in service/server mode")(
77 "noGeant", bpo::bool_switch(),
"prohibits any Geant transport/physics (by using tight cuts)")(
78 "forwardKine", bpo::bool_switch(),
"forward kinematics on a FairMQ channel")(
79 "noDiscOutput", bpo::bool_switch(),
"switch off writing sim results to disc (useful in combination with forwardKine)")(
80 "extGeomFile", bpo::value<std::string>()->default_value(
""),
"Path to a JSON file describing external (CAD) geometry modules to inject (see Detectors/Passive ExternalModule). Modules are added when their 'name' is part of the active module list.");
81 options.add_options()(
"fromCollContext", bpo::value<std::string>()->default_value(
""),
"Use a pregenerated collision context to infer number of events to simulate, how to embedd them, the vertex position etc. Takes precedence of other options such as \"--nEvents\". The format is COLLISIONCONTEXTFILE.root[:SIGNALNAME] where SIGNALNAME is the event part in the context which is relevant.");
84void SimConfig::determineActiveModules(std::vector<std::string>
const& inputargs, std::vector<std::string>
const& skippedModules, std::vector<std::string>& activeModules,
bool isUpgrade)
90 activeModules = inputargs;
92 if (activeModules[0] !=
"all") {
94 for (
int i = 0;
i < activeModules.size(); ++
i) {
95 if (activeModules[
i] !=
"A3IP" &&
96 activeModules[
i] !=
"IT3" &&
97 activeModules[
i] !=
"TRK" &&
98 activeModules[
i] !=
"FT3" &&
99 activeModules[
i] !=
"FCT" &&
100 activeModules[
i] !=
"TF3" &&
101 activeModules[
i] !=
"RCH" &&
102 activeModules[
i] !=
"MI3" &&
103 activeModules[
i] !=
"ECL" &&
104 activeModules[
i] !=
"FD3") {
105 LOGP(fatal,
"List of active modules contains {}, which is not a module from the upgrades.", activeModules[
i]);
110 for (
int i = 0;
i < activeModules.size(); ++
i) {
111 if (activeModules[
i] ==
"A3IP" ||
112 activeModules[
i] ==
"TRK" ||
113 activeModules[
i] ==
"FT3" ||
114 activeModules[
i] ==
"FCT" ||
115 activeModules[
i] ==
"TF3" ||
116 activeModules[
i] ==
"RCH" ||
117 activeModules[
i] ==
"MI3" ||
118 activeModules[
i] ==
"ECL" ||
119 activeModules[
i] ==
"FD3") {
120 LOGP(fatal,
"List of active modules contains {}, which is not a run 3 module", activeModules[
i]);
126 if (activeModules.size() == 1 && activeModules[0] ==
"all") {
127 activeModules.clear();
128#ifdef ENABLE_UPGRADES
131 if (d == DetID::TRK ||
142 activeModules.emplace_back(
"A3IP");
143 activeModules.emplace_back(
"A3ABSO");
144 activeModules.emplace_back(
"A3MAG");
148 activeModules.emplace_back(
"HALL");
149 activeModules.emplace_back(
"MAG");
150 activeModules.emplace_back(
"DIPO");
151 activeModules.emplace_back(
"COMP");
152 activeModules.emplace_back(
"PIPE");
153 activeModules.emplace_back(
"ABSO");
154 activeModules.emplace_back(
"SHIL");
156#ifdef ENABLE_UPGRADES
157 if (d != DetID::IT3 && d != DetID::TRK && d != DetID::FT3 && d != DetID::FCT && d != DetID::TF3 && d != DetID::RCH && d != DetID::ECL && d != DetID::FD3 && d != DetID::MI3) {
166 filterSkippedElements(activeModules, skippedModules);
173 if (
auto pos =
version.find(
':');
pos != std::string::npos) {
177 LOGP(error,
"Could not parse {}; check errors above!", ppath);
180 if (map.find(pversion) == map.end()) {
181 LOGP(error,
"List {} is not defined in custom JSON file!", pversion);
185 modules = map[pversion];
186 LOGP(info,
"Running with version {} from custom detector list '{}'", pversion, ppath);
189 auto o2env = std::getenv(
"O2_ROOT");
191 LOGP(error,
"O2_ROOT environment not defined");
194 const std::string rootpath(fmt::format(
"{}/share/config/o2simdefaultdetectorlist.json", o2env));
196 LOGP(error,
"Could not parse {} -> check errors above!", rootpath);
199 if (map.find(
version) == map.end()) {
200 LOGP(error,
"List {} is not defined in 'official' JSON file!",
version);
205 static std::string last_version{};
207 LOGP(info,
"Running with official detector version '{}'",
version);
212 if (inputargs.size() != 1 || inputargs[0] !=
"all") {
213 std::vector<std::string> diff;
214 for (
const auto& in : inputargs) {
215 if (std::find(modules.begin(), modules.end(), in) == std::end(modules)) {
216 diff.emplace_back(in);
220 LOGP(error,
"Modules specified that are not present in detector list {}",
version);
221 for (
int j{0};
const auto&
m : diff) {
222 LOGP(info,
" - {: <2}. {}",
j++,
m);
229 std::copy_if(modules.begin(), modules.end(), std::back_inserter(activeModules),
230 [&inputargs](
const auto& e) { return (inputargs.size() == 1 && inputargs[0] ==
"all") || (std::find(inputargs.begin(), inputargs.end(), e) != inputargs.end()); });
231 return filterSkippedElements(activeModules, skippedModules);
234void SimConfig::determineReadoutDetectors(std::vector<std::string>
const& activeModules, std::vector<std::string>
const& enableReadout, std::vector<std::string>
const& disableReadout, std::vector<std::string>& readoutDetectors)
238 readoutDetectors.clear();
240 auto isDet = [](std::string
const& s) {
244 if (enableReadout.empty()) {
246 for (
auto& am : activeModules) {
251 readoutDetectors.emplace_back(am);
254 for (
auto& er : enableReadout) {
257 LOG(fatal) <<
"Enabled readout for " << er <<
" which is not a detector.";
259 if (std::find(activeModules.begin(), activeModules.end(), er) == activeModules.end()) {
261 LOG(fatal) <<
"Module " << er <<
" not constructed and cannot be used for readout (make sure it is contained in -m option).";
263 readoutDetectors.emplace_back(er);
266 for (
auto& dr : disableReadout) {
269 LOG(fatal) <<
"Disabled readout for " << dr <<
" which is not a detector.";
271 if (std::find(activeModules.begin(), activeModules.end(), dr) == activeModules.end()) {
273 LOG(fatal) <<
"Module " << dr <<
" not constructed, makes no sense to disable its readout (make sure it is contained in -m option).";
275 auto iter = std::find(readoutDetectors.begin(), readoutDetectors.end(), dr);
276 if (iter != readoutDetectors.end()) {
277 readoutDetectors.erase(iter);
300 mConfigData.
mMCEngine = vm[
"mcEngine"].as<std::string>();
301 mConfigData.
mNoGeant = vm[
"noGeant"].as<
bool>();
308 if (!
determineActiveModulesList(vm[
"detectorList"].as<std::string>(), vm[
"modules"].as<std::vector<std::string>>(), vm[
"skipModules"].as<std::vector<std::string>>(), mConfigData.
mActiveModules)) {
316 mConfigData.
mMCEngine =
"O2TrivialMCEngine";
317 }
else if (mConfigData.
mMCEngine.compare(
"O2TrivialMCEngine") == 0) {
318 LOG(error) <<
"The O2TrivialMCEngine engine can only be used with --noGeant option";
327 mConfigData.
mGenerator = vm[
"generator"].as<std::string>();
328 mConfigData.
mTrigger = vm[
"trigger"].as<std::string>();
329 mConfigData.
mNEvents = vm[
"nEvents"].as<
unsigned int>();
332 mConfigData.
mStartEvent = vm[
"startEvent"].as<
unsigned int>();
333 mConfigData.
mBMax = vm[
"bMax"].as<
float>();
334 mConfigData.
mIsMT = vm[
"isMT"].as<
bool>();
335 mConfigData.
mOutputPrefix = vm[
"outPrefix"].as<std::string>();
336 mConfigData.
mLogSeverity = vm[
"logseverity"].as<std::string>();
337 mConfigData.
mLogVerbosity = vm[
"logverbosity"].as<std::string>();
339 mConfigData.
mConfigFile = vm[
"configFile"].as<std::string>();
342 mConfigData.
mStartSeed = vm[
"seed"].as<ULong_t>();
343 mConfigData.
mSimWorkers = vm[
"nworkers"].as<
int>();
344 if (vm.count(
"timestamp")) {
345 mConfigData.
mTimestamp = vm[
"timestamp"].as<uint64_t>();
348 mConfigData.
mTimestamp = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
352 mConfigData.
mCCDBUrl = vm[
"CCDBUrl"].as<std::string>();
353 mConfigData.
mAsService = vm[
"asservice"].as<
bool>();
354 mConfigData.
mForwardKine = vm[
"forwardKine"].as<
bool>();
355 mConfigData.
mWriteToDisc = !vm[
"noDiscOutput"].as<
bool>();
356 if (vm.count(
"noemptyevents")) {
359 mConfigData.
mExtGeomFile = vm[
"extGeomFile"].as<std::string>();
362 adjustFromCollContext(collcontext_simprefix.first, collcontext_simprefix.second);
371 auto& fieldstring = vm[
"field"].as<std::string>();
372 std::regex re(
"(ccdb)|([+-]?(0|[2-9]|[12][0-9]|20)U?)");
373 if (!std::regex_match(fieldstring, re)) {
374 LOG(error) <<
"Invalid field option " << fieldstring;
377 if (fieldstring ==
"ccdb") {
379 }
else if (fieldstring.find(
"U") != std::string::npos) {
382 if (fieldstring !=
"ccdb") {
383 mConfigData.
mField = std::stoi((vm[
"field"].as<std::string>()).substr(0, (vm[
"field"].as<std::string>()).rfind(
"U")));
549 bpo::options_description options(
"Allowed options");
551 options.add_options()(
552 "nEvents,n", bpo::value<unsigned int>(&
data.nEvents)->default_value(0),
"number of events")(
553 "generator,g", bpo::value<std::string>(&
data.generator)->default_value(
"boxgen"),
"Event generator to be used.")(
554 "trigger,t", bpo::value<std::string>(&
data.trigger)->default_value(
""),
"Event generator trigger to be used.")(
555 "startEvent", bpo::value<unsigned int>(&
data.startEvent)->default_value(0),
"index of first event to be used (when applicable)")(
556 "extKinFile", bpo::value<std::string>(&
data.extKinfileName)->default_value(
"Kinematics.root"),
557 "name of kinematics file for event generator from file (when applicable)")(
558 "embedIntoFile", bpo::value<std::string>(&
data.embedIntoFileName)->default_value(
""),
559 "filename containing the reference events to be used for the embedding")(
560 "bMax,b", bpo::value<float>(&
data.mBMax)->default_value(0.),
"maximum value for impact parameter sampling (when applicable)")(
561 "outPrefix,o", bpo::value<std::string>(&
data.outputPrefix)->default_value(
"o2sim"),
"prefix of output files")(
562 "outDir,d", bpo::value<std::string>(&
data.outputDir),
"directory where to put simulation output (created when non-existant")(
563 "configKeyValues", bpo::value<std::string>(&
data.keyValueTokens)->default_value(
""),
"semicolon separated key=value strings (e.g.: 'TPC.gasDensity=1;...")(
564 "configFile", bpo::value<std::string>(&
data.configFile)->default_value(
""),
"Path to an INI or JSON configuration file")(
565 "chunkSize", bpo::value<unsigned int>(&
data.primaryChunkSize)->default_value(500),
"max size of primary chunk (subevent) distributed by server")(
566 "seed", bpo::value<ULong_t>(&
data.startSeed)->default_value(0L),
"initial seed as ULong_t (default: 0 == random)")(
567 "stop", bpo::value<bool>(&
data.stop)->default_value(
false),
"control command to shut down daemon");
569 bpo::variables_map vm;
571 bpo::store(bpo::command_line_parser(bpo::split_unix(argumentstring))
576 }
catch (
const bpo::error& e) {
577 std::cerr << e.what() <<
"\n\n";
578 std::cerr <<
"Error parsing ReConfig data; Available options:\n";
579 std::cerr << options << std::endl;
static DigitizationContext * loadFromFile(std::string_view filename="")