2222#include < TParticle.h>
2323#include < TTree.h>
2424#include < sstream>
25+ #include < filesystem>
26+ #include < TGrid.h>
2527
2628namespace o2
2729{
@@ -249,6 +251,7 @@ bool GeneratorFromO2Kine::importParticles()
249251 // Randomize the order of events in the input file
250252 if (mRandomize ) {
251253 mEventCounter = gRandom ->Integer (mEventsAvailable );
254+ LOG (info) << " GeneratorFromO2Kine - Picking event " << mEventCounter ;
252255 }
253256
254257 double dPhi = 0 .;
@@ -352,8 +355,235 @@ void GeneratorFromO2Kine::updateHeader(o2::dataformats::MCEventHeader* eventHead
352355 eventHeader->putInfo <int >(" forwarding-generator_inputEventNumber" , mEventCounter - 1 );
353356}
354357
358+ namespace
359+ {
360+ // some helper to execute a command and capture it's output in a vector
361+ std::vector<std::string> executeCommand (const std::string& command)
362+ {
363+ std::vector<std::string> result;
364+ std::unique_ptr<FILE, decltype (&pclose)> pipe (popen (command.c_str (), " r" ), pclose);
365+ if (!pipe) {
366+ throw std::runtime_error (" Failed to open pipe" );
367+ }
368+
369+ char buffer[1024 ];
370+ while (fgets (buffer, sizeof (buffer), pipe.get ()) != nullptr ) {
371+ std::string line (buffer);
372+ // Remove trailing newline character, if any
373+ if (!line.empty () && line.back () == ' \n ' ) {
374+ line.pop_back ();
375+ }
376+ result.push_back (line);
377+ }
378+ return result;
379+ }
380+ } // namespace
381+
382+ GeneratorFromEventPool::GeneratorFromEventPool (EventPoolGenConfig const & pars) : mConfig {pars}
383+ {
384+ }
385+
386+ bool GeneratorFromEventPool::Init ()
387+ {
388+ // initialize the event pool
389+ if (mConfig .rngseed > 0 ) {
390+ mRandomEngine .seed (mConfig .rngseed );
391+ } else {
392+ std::random_device rd;
393+ mRandomEngine .seed (rd ());
394+ }
395+ mPoolFilesAvailable = setupFileUniverse (mConfig .eventPoolPath );
396+
397+ if (mPoolFilesAvailable .size () == 0 ) {
398+ LOG (error) << " No file found that can be used with EventPool generator" ;
399+ return false ;
400+ }
401+
402+ // now choose the actual file
403+ std::uniform_int_distribution<int > distribution (0 , mPoolFilesAvailable .size ());
404+ mFileChosen = mPoolFilesAvailable [distribution (mRandomEngine )];
405+ LOG (info) << " EventPool is using file " << mFileChosen ;
406+
407+ // we bring up the internal mO2KineGenerator
408+ auto kine_config = O2KineGenConfig{
409+ .skipNonTrackable = mConfig .skipNonTrackable ,
410+ .continueMode = false ,
411+ .roundRobin = false ,
412+ .randomize = mConfig .randomize ,
413+ .rngseed = mConfig .rngseed ,
414+ .randomphi = mConfig .randomphi ,
415+ .fileName = mFileChosen };
416+ mO2KineGenerator .reset (new GeneratorFromO2Kine (kine_config));
417+ return mO2KineGenerator ->Init ();
418+ }
419+
420+ namespace
421+ {
422+ namespace fs = std::filesystem;
423+ // checks a single file name
424+ bool checkFileName (std::string const & pathStr)
425+ {
426+ // LOG(info) << "Checking filename " << pathStr;
427+ try {
428+ // Remove optional protocol prefix "alien://"
429+ const std::string protocol = " alien://" ;
430+ std::string finalPathStr (pathStr);
431+ if (pathStr.starts_with (protocol)) {
432+ finalPathStr = pathStr.substr (protocol.size ());
433+ }
434+ fs::path path (finalPathStr);
435+
436+ // Check if the filename is "eventpool.root"
437+ return path.filename () == GeneratorFromEventPool::eventpool_filename;
438+ } catch (const fs::filesystem_error& e) {
439+ // Invalid path syntax will throw an exception
440+ std::cerr << " Filesystem error: " << e.what () << ' \n ' ;
441+ return false ;
442+ } catch (...) {
443+ // Catch-all for other potential exceptions
444+ std::cerr << " An unknown error occurred while checking the path.\n " ;
445+ return false ;
446+ }
447+ }
448+
449+ // checks a whole universe of file names
450+ bool checkFileUniverse (std::vector<std::string> const & universe)
451+ {
452+ if (universe.size () == 0 ) {
453+ return false ;
454+ }
455+ for (auto & fn : universe) {
456+ if (!checkFileName (fn)) {
457+ return false ;
458+ }
459+ }
460+ // TODO: also check for a common path structure with maximally 00X as only difference
461+
462+ return true ;
463+ }
464+
465+ std::vector<std::string> readLines (const std::string& filePath)
466+ {
467+ std::vector<std::string> lines;
468+
469+ // Check if the file is a valid text file
470+ fs::path path (filePath);
471+
472+ // Open the file
473+ std::ifstream file (filePath);
474+ if (!file.is_open ()) {
475+ throw std::ios_base::failure (" Failed to open the file." );
476+ }
477+
478+ // Read up to n lines
479+ std::string line;
480+ while (std::getline (file, line)) {
481+ lines.push_back (line);
482+ }
483+ return lines;
484+ }
485+
486+ // Function to find all files named eventpool_filename under a given path
487+ std::vector<std::string> getLocalFileList (const fs::path& rootPath)
488+ {
489+ std::vector<std::string> result;
490+
491+ // Ensure the root path exists and is a directory
492+ if (!fs::exists (rootPath) || !fs::is_directory (rootPath)) {
493+ throw std::invalid_argument (" The provided path is not a valid directory." );
494+ }
495+
496+ // Iterate over the directory and subdirectories
497+ for (const auto & entry : fs::recursive_directory_iterator (rootPath)) {
498+ if (entry.is_regular_file () && entry.path ().filename () == GeneratorFromEventPool::eventpool_filename) {
499+ result.push_back (entry.path ().string ());
500+ }
501+ }
502+ return result;
503+ }
504+
505+ } // end anonymous namespace
506+
507+ // / A function determining the universe of event pool files, as determined by the path string
508+ // / returns empty vector if it fails
509+ std::vector<std::string> GeneratorFromEventPool::setupFileUniverse (std::string const & path) const
510+ {
511+ // the path could refer to a local or alien filesystem; find out first
512+ bool onAliEn = strncmp (path.c_str (), std::string (alien_protocol_prefix).c_str (), alien_protocol_prefix.size ()) == 0 ;
513+ std::vector<std::string> result;
514+
515+ if (onAliEn) {
516+ // AliEn case
517+ // we support: (a) an actual evtgen file and (b) a path containing multiple eventfiles
518+
519+ auto alienStatTypeCommand = std::string (" alien.py stat " ) + mConfig .eventPoolPath + std::string (" 2>/dev/null | grep Type " );
520+ auto typeString = executeCommand (alienStatTypeCommand);
521+ if (typeString.size () == 0 ) {
522+ return result;
523+ } else if (typeString.size () == 1 && typeString.front () == std::string (" Type: f" )) {
524+ // this is a file ... simply use it
525+ result.push_back (mConfig .eventPoolPath );
526+ return result;
527+ } else if (typeString.size () == 1 && typeString.front () == std::string (" Type: d" )) {
528+ // this is a directory
529+ // construct command to find actual event files
530+ std::string alienSearchCommand = std::string (" alien.py find " ) +
531+ mConfig .eventPoolPath + " / " + std::string (eventpool_filename);
532+
533+ auto universe_vector = executeCommand (alienSearchCommand);
534+ // check vector
535+ if (!checkFileUniverse (universe_vector)) {
536+ return result;
537+ }
538+ for (auto & f : universe_vector) {
539+ f = std::string (alien_protocol_prefix) + f;
540+ }
541+
542+ return universe_vector;
543+ } else {
544+ LOG (error) << " Unsupported file type" ;
545+ return result;
546+ }
547+ } else {
548+ // local file case
549+ // check if the path is a regular file
550+ auto is_actual_file = std::filesystem::is_regular_file (path);
551+ if (is_actual_file) {
552+ // The files must match a criteria of being canonical paths ending with eventpool_Kine.root
553+ if (checkFileName (path)) {
554+ TFile rootfile (path.c_str (), " OPEN" );
555+ if (!rootfile.IsZombie ()) {
556+ result.push_back (path);
557+ return result;
558+ }
559+ } else {
560+ // otherwise assume it is a text file containing a list of files themselves
561+ auto files = readLines (path);
562+ if (checkFileUniverse (files)) {
563+ result = files;
564+ return result;
565+ }
566+ }
567+ } else {
568+ // check if the path is just a path
569+ // In this case we need to search something and check
570+ auto is_dir = std::filesystem::is_directory (path);
571+ if (!is_dir) {
572+ return result;
573+ }
574+ auto files = getLocalFileList (path);
575+ if (checkFileUniverse (files)) {
576+ result = files;
577+ return result;
578+ }
579+ }
580+ }
581+ return result;
582+ }
583+
355584} // namespace eventgen
356585} // end namespace o2
357586
587+ ClassImp (o2::eventgen::GeneratorFromEventPool);
358588ClassImp (o2::eventgen::GeneratorFromFile);
359- ClassImp (o2::eventgen::GeneratorFromO2Kine);
589+ ClassImp (o2::eventgen::GeneratorFromO2Kine);
0 commit comments