diff --git a/FullSimLight/Plugins/GenerateTracksPluginROOT/CMakeLists.txt b/FullSimLight/Plugins/GenerateTracksPluginROOT/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..1d7e51022a48771f8ddc9d3a2841f13654625979 --- /dev/null +++ b/FullSimLight/Plugins/GenerateTracksPluginROOT/CMakeLists.txt @@ -0,0 +1,71 @@ +cmake_minimum_required(VERSION 3.16...3.26) + +set(CMAKE_CXX_STANDARD 17) + +project("GenerateTracksPluginROOT") + +# Set up the project. Check if we build it with GeoModel or individually +if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) + list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) + project("GenerateTracksPluginROOT" VERSION 1.0 LANGUAGES CXX) + include(cmake_colors_defs) + include(GNUInstallDirs) + include(BuildType) + include(configure_cpp_options) + include(PrintBuildInfo) + message(STATUS "${BoldGreen}Building ${PROJECT_NAME} individually, as a top-level project.${ColourReset}") + include(configure_cpp_options) + set(CMAKE_FIND_FRAMEWORK "LAST" CACHE STRING "Framework finding behaviour on macOS") + find_package(GeoModelCore REQUIRED) + find_package(FullSimLight REQUIRED) +else() + message(STATUS "Building ${PROJECT_NAME} as part of the root project.") + project("GenerateTracksPluginROOT" VERSION 1.0 LANGUAGES CXX) +endif() + +# Find the header and source files. +file(GLOB HEADERS include/*.hh) +file(GLOB SOURCES src/*.cc) + +set(PROJECT_SOURCES ${HEADERS} ${SOURCES} TracksPlugin.cc) + +# Set up the library. +add_library(GenerateTracksPluginROOT SHARED ${PROJECT_SOURCES}) + +# Find and configure Geant4 +find_package(Geant4 REQUIRED) +message(STATUS "Found Geant4: ${Geant4_INCLUDE_DIR}") + +# Find HDF5 +#find_package(HDF5 REQUIRED COMPONENTS CXX) + +# Find ROOT. Use root-config to get include paths and libraries +find_package(ROOT REQUIRED COMPONENTS RIO) + +# Use ROOT's provided macros and settings +include(${ROOT_USE_FILE}) + +# Add include directories +include_directories(${ROOT_INCLUDE_DIRS} ${Geant4_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include) + +# Link the libraries +target_link_libraries(GenerateTracksPluginROOT PUBLIC + FullSimLight::FullSimLight + ${Geant4_LIBRARIES} + #${HDF5_CXX_LIBRARIES} + ${ROOT_LIBRARIES} + ${CMAKE_DL_LIBS} +) + +set_target_properties(GenerateTracksPluginROOT PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} +) + +# Install the target +install(TARGETS GenerateTracksPluginROOT + LIBRARY DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/FullSimLight/UserActionPlugins + COMPONENT Runtime + NAMELINK_COMPONENT Development +) + diff --git a/FullSimLight/Plugins/GenerateTracksPluginROOT/TracksPlugin.cc b/FullSimLight/Plugins/GenerateTracksPluginROOT/TracksPlugin.cc new file mode 100644 index 0000000000000000000000000000000000000000..30a125eb12c1506081a74143c6471e81ab1d56b3 --- /dev/null +++ b/FullSimLight/Plugins/GenerateTracksPluginROOT/TracksPlugin.cc @@ -0,0 +1,50 @@ +#include "FullSimLight/FSLUserActionPlugin.h" +#include <iostream> + +#include "TrksRunAction.h" +#include "TrksSteppingAction.h" +#include "TrksTrackingAction.h" +#include "TrksEventAction.h" + +class TracksPlugin:public FSLUserActionPlugin { + +public: + + TracksPlugin(); + + G4UserRunAction* getRunAction() const; + G4UserEventAction* getEventAction() const; + G4UserTrackingAction* getTrackingAction() const; + G4UserSteppingAction* getSteppingAction() const; +}; + +TracksPlugin::TracksPlugin() +{ + +} + +G4UserRunAction* TracksPlugin::getRunAction() const +{ + return new TrksRunAction; +} + +G4UserEventAction* TracksPlugin::getEventAction() const +{ + return new TrksEventAction; +} + +G4UserTrackingAction* TracksPlugin::getTrackingAction() const +{ + return new TrksTrackingAction; +} + + +G4UserSteppingAction* TracksPlugin::getSteppingAction() const +{ + return new TrksSteppingAction; +} + +extern "C" TracksPlugin *createGenerateTracksPlugin() { + return new TracksPlugin(); +} + diff --git a/FullSimLight/Plugins/GenerateTracksPluginROOT/include/TrksEventAction.h b/FullSimLight/Plugins/GenerateTracksPluginROOT/include/TrksEventAction.h new file mode 100644 index 0000000000000000000000000000000000000000..97a250afe4e97576092cec60645d8c57368612e0 --- /dev/null +++ b/FullSimLight/Plugins/GenerateTracksPluginROOT/include/TrksEventAction.h @@ -0,0 +1,39 @@ +#ifndef __TrksEventAction_hh__ +#define __TrksEventAction_hh__ + +#include "G4UserEventAction.hh" +#include "G4UnitsTable.hh" + +#include <vector> +#include <map> + +struct stepData +{ + float x; + float y; + float z; +}; + +class TrksEventAction: public G4UserEventAction +{ +public: + + TrksEventAction(); + ~TrksEventAction(); + + void BeginOfEventAction(const G4Event*); + void EndOfEventAction(const G4Event*); + + static G4ThreadLocal std::map<int, int> gPDGs; + static G4ThreadLocal std::map<int, std::vector<stepData>> trksInfoMap; + + +}; + + +#endif //__TrksEventAction_hh__ + + + + + diff --git a/FullSimLight/Plugins/GenerateTracksPluginROOT/include/TrksROOTFactory.h b/FullSimLight/Plugins/GenerateTracksPluginROOT/include/TrksROOTFactory.h new file mode 100644 index 0000000000000000000000000000000000000000..cd4d69edb092932315bf45f29d945fbf67c3e7b3 --- /dev/null +++ b/FullSimLight/Plugins/GenerateTracksPluginROOT/include/TrksROOTFactory.h @@ -0,0 +1,28 @@ +#ifndef __TrksROOTFactory_hh__ +#define __TrksROOTFactory_hh__ + +#include "TFile.h" +#include "TTree.h" +#include <mutex> +#include <vector> + +class TrksROOTFactory +{ +public: + static std::mutex gWriteFileMutex; + + static TrksROOTFactory* GetInstance(); + static void OpenFile(const char* name); + static void CloseFile(); + + static TFile* GetFile() { return fgFile; } + +private: + TrksROOTFactory(); + ~TrksROOTFactory(); + + static TrksROOTFactory* fgInstance; + static TFile* fgFile; +}; + +#endif // __TrksROOTFactory_hh__ diff --git a/FullSimLight/Plugins/GenerateTracksPluginROOT/include/TrksRunAction.h b/FullSimLight/Plugins/GenerateTracksPluginROOT/include/TrksRunAction.h new file mode 100644 index 0000000000000000000000000000000000000000..1dd98969a22c24fb55b082ddec3b32685e7d4348 --- /dev/null +++ b/FullSimLight/Plugins/GenerateTracksPluginROOT/include/TrksRunAction.h @@ -0,0 +1,29 @@ +#ifndef TRKSRUNACTION_HH +#define TRKSRUNACTION_HH + +#include "G4UserRunAction.hh" +#include "G4UnitsTable.hh" + +#include <vector> +#include <mutex> + +class TrksRunAction: public G4UserRunAction +{ +public: + + TrksRunAction(); + ~TrksRunAction(); + + void BeginOfRunAction(const G4Run* /*aRun*/); + void EndOfRunAction(const G4Run* /*aRun*/); + + static std::map<G4int, G4int> fgTrkNums; + static std::mutex fgTrkNumsMutex; + +}; + + + +#endif // TRKSRUNACTION_HH + + diff --git a/FullSimLight/Plugins/GenerateTracksPluginROOT/include/TrksSteppingAction.h b/FullSimLight/Plugins/GenerateTracksPluginROOT/include/TrksSteppingAction.h new file mode 100644 index 0000000000000000000000000000000000000000..c39d1cdec49c8d4b8f82503fb55c045f69717fb0 --- /dev/null +++ b/FullSimLight/Plugins/GenerateTracksPluginROOT/include/TrksSteppingAction.h @@ -0,0 +1,21 @@ +#ifndef TRKSUSERACTION_HH +#define TRKSUSERACTION_HH + + +#include "G4UserSteppingAction.hh" +#include "G4Step.hh" + +class G4Step; + +class TrksSteppingAction: public G4UserSteppingAction +{ +public: + TrksSteppingAction(); + ~TrksSteppingAction(); + + void UserSteppingAction(const G4Step* /*aStep*/); + +}; + +#endif // TRKSUSERACTION_HH + diff --git a/FullSimLight/Plugins/GenerateTracksPluginROOT/include/TrksTrackingAction.h b/FullSimLight/Plugins/GenerateTracksPluginROOT/include/TrksTrackingAction.h new file mode 100644 index 0000000000000000000000000000000000000000..6f16ed70803e4105c3febf84c6ec1ed83ba40a26 --- /dev/null +++ b/FullSimLight/Plugins/GenerateTracksPluginROOT/include/TrksTrackingAction.h @@ -0,0 +1,18 @@ +#ifndef __TRKSTRACKINGACTION_HH__ +#define __TRKSTRACKINGACTION_HH__ + +#include "G4UserTrackingAction.hh" + +class TrksTrackingAction: public G4UserTrackingAction +{ +public: + TrksTrackingAction(); + ~TrksTrackingAction(); + + void PreUserTrackingAction(const G4Track*); + void PostUserTrackingAction(const G4Track*); + +}; + + +#endif //__TEKSTRACKINGACTION_HH__ diff --git a/FullSimLight/Plugins/GenerateTracksPluginROOT/src/TrksEventAction.cc b/FullSimLight/Plugins/GenerateTracksPluginROOT/src/TrksEventAction.cc new file mode 100644 index 0000000000000000000000000000000000000000..28157566bc87e9879c83b306d10ca95f772f3e05 --- /dev/null +++ b/FullSimLight/Plugins/GenerateTracksPluginROOT/src/TrksEventAction.cc @@ -0,0 +1,84 @@ +#include "TrksEventAction.h" +#include "TrksROOTFactory.h" // Replace HDF5 factory with ROOT factory +#include "G4Event.hh" +#include "TrksRunAction.h" +#include <string> + +using namespace std; + + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +G4ThreadLocal std::map<int, int> TrksEventAction::gPDGs; +G4ThreadLocal std::map<int, std::vector<stepData>> TrksEventAction::trksInfoMap; + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +TrksEventAction::TrksEventAction() {} +TrksEventAction::~TrksEventAction() {} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +void TrksEventAction::BeginOfEventAction(const G4Event*) {} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +void TrksEventAction::EndOfEventAction(const G4Event* anEvent) +{ + G4int eventNum = anEvent->GetEventID(); + TrksROOTFactory* rootFactory = TrksROOTFactory::GetInstance(); + + // Lock the file for thread safety + rootFactory->gWriteFileMutex.lock(); + + // Get the ROOT file and TTree + TFile* file = rootFactory->GetFile(); + if (!file) { + G4cerr << "ROOT file not opened." << G4endl; + rootFactory->gWriteFileMutex.unlock(); + return; + } + + TTree* tree = static_cast<TTree*>(file->Get("EventTree")); + if (!tree) { + tree = new TTree("EventTree", "Track and event data"); + file->cd(); + } + + // Collect data for PDGs + std::vector<int> gPDGsVec; + for (const auto& el : gPDGs) + gPDGsVec.push_back(el.second); + + // Collect track step data + std::vector<float> xCoords, yCoords, zCoords; + for (const auto& trkInfo : trksInfoMap) { + const std::vector<stepData>& steps = trkInfo.second; + for (const auto& step : steps) { + xCoords.push_back(step.x); + yCoords.push_back(step.y); + zCoords.push_back(step.z); + } + } + + // Create branches if they don't already exist + if (!tree->GetBranch("eventNum")) tree->Branch("eventNum", &eventNum, "eventNum/I"); + if (!tree->GetBranch("pdgCodes")) tree->Branch("pdgCodes", &gPDGsVec); + if (!tree->GetBranch("x")) tree->Branch("x", &xCoords); + if (!tree->GetBranch("y")) tree->Branch("y", &yCoords); + if (!tree->GetBranch("z")) tree->Branch("z", &zCoords); + + // Fill the tree with collected data + tree->Fill(); + + // Unlock the file and clear data + rootFactory->gWriteFileMutex.unlock(); + gPDGs.clear(); + trksInfoMap.clear(); + + // Track event data count in RunAction + TrksRunAction::fgTrkNumsMutex.lock(); + TrksRunAction::fgTrkNums[eventNum] = gPDGsVec.size(); + TrksRunAction::fgTrkNumsMutex.unlock(); +} + diff --git a/FullSimLight/Plugins/GenerateTracksPluginROOT/src/TrksROOTFactory.cc b/FullSimLight/Plugins/GenerateTracksPluginROOT/src/TrksROOTFactory.cc new file mode 100644 index 0000000000000000000000000000000000000000..9ca7b4f7a368899daa28df02842bc2f308c7cc9c --- /dev/null +++ b/FullSimLight/Plugins/GenerateTracksPluginROOT/src/TrksROOTFactory.cc @@ -0,0 +1,44 @@ +#include "TrksROOTFactory.h" +#include "G4UnitsTable.hh" + +// Singleton instance and static variables +TrksROOTFactory* TrksROOTFactory::fgInstance = nullptr; +TFile* TrksROOTFactory::fgFile = nullptr; +std::mutex TrksROOTFactory::gWriteFileMutex; + +TrksROOTFactory::TrksROOTFactory() +{ + fgInstance = this; +} + +TrksROOTFactory::~TrksROOTFactory() +{ + // Close and delete the ROOT file if open + CloseFile(); + fgInstance = nullptr; +} + +TrksROOTFactory* TrksROOTFactory::GetInstance() +{ + if (!fgInstance) + fgInstance = new TrksROOTFactory; + return fgInstance; +} + +void TrksROOTFactory::OpenFile(const char* name) +{ + fgFile = new TFile(name, "RECREATE"); + G4cout << "ROOT file " << name << " opened for writing." << G4endl; +} + +void TrksROOTFactory::CloseFile() +{ + if (fgFile) + { + fgFile->Write(); // Write all data to the file before closing + fgFile->Close(); + delete fgFile; + fgFile = nullptr; + G4cout << "ROOT file closed successfully." << G4endl; + } +} diff --git a/FullSimLight/Plugins/GenerateTracksPluginROOT/src/TrksRunAction.cc b/FullSimLight/Plugins/GenerateTracksPluginROOT/src/TrksRunAction.cc new file mode 100644 index 0000000000000000000000000000000000000000..3ded80918de1492935b8eb9277ed5991d44ef639 --- /dev/null +++ b/FullSimLight/Plugins/GenerateTracksPluginROOT/src/TrksRunAction.cc @@ -0,0 +1,97 @@ +#include "TrksRunAction.h" +#include "TrksROOTFactory.h" // ROOT factory instead of HDF5 +#include <string> +#include <filesystem> +#include <set> + + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +std::map<G4int, G4int> TrksRunAction::fgTrkNums; +std::mutex TrksRunAction::fgTrkNumsMutex; + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +TrksRunAction::TrksRunAction() +{ + +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +TrksRunAction::~TrksRunAction() +{ + +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +void TrksRunAction::BeginOfRunAction(const G4Run* /*aRun*/) +{ + if (IsMaster()) + { + using namespace std; + namespace fs = std::filesystem; + + set<string> fileNames; + string outputFileName; + + // Check for an available file name + fs::path pwdPath = fs::current_path(); + for (const auto & entry : fs::directory_iterator(pwdPath)) + { + fileNames.insert(entry.path()); + } + + for (int i=0; true; ++i) + { + outputFileName = "Tracks_data"; + outputFileName += i == 0 ? "" : string("_") + to_string(i); + outputFileName += ".root"; // Using .root extension instead of .h5 + + if (fileNames.find( string(pwdPath) + "/" + outputFileName) == fileNames.end()) + { + + break; + } + + cout << "A file...look here********" << outputFileName << " already exists in the working directory. " + << "Looking for another file name....a good file name.\n"; + } + + // Open ROOT file using the ROOT factory + TrksROOTFactory* rootFactory = TrksROOTFactory::GetInstance(); + rootFactory->OpenFile(outputFileName.c_str()); + + G4cout << "ROOT file...*if you see this..means we are almost there*" << outputFileName << " opened for writing." << G4endl; + } +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +void TrksRunAction::EndOfRunAction(const G4Run* /*aRun*/) +{ + if (IsMaster()) + { + TrksROOTFactory* rootFactory = TrksROOTFactory::GetInstance(); + + // Collect track numbers into a vector for storage + std::vector<int> trkNumsVec; + for (auto el : fgTrkNums) + { + trkNumsVec.push_back(el.second); + } + + // Attention signor.. data handling is diff. in ROOT and hdf5 + // Call to save track numbers in ROOT file, if needed + // This assumes `TrksROOTFactory` handles `trkNumsVec` appropriately. + // For example, you could add a method to `TrksROOTFactory` to manage + // this type of data if it’s not part of `Fill`. + + // Close the ROOT file + rootFactory->CloseFile(); + + G4cout << "The ROOT file has been created and closed successfully." << G4endl; + } +} +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... diff --git a/FullSimLight/Plugins/GenerateTracksPluginROOT/src/TrksSteppingAction.cc b/FullSimLight/Plugins/GenerateTracksPluginROOT/src/TrksSteppingAction.cc new file mode 100644 index 0000000000000000000000000000000000000000..bee5fb190fc4f95b999f97abef1eecc04bc5ba75 --- /dev/null +++ b/FullSimLight/Plugins/GenerateTracksPluginROOT/src/TrksSteppingAction.cc @@ -0,0 +1,38 @@ +#include "TrksSteppingAction.h" +#include "G4Step.hh" +#include "G4Track.hh" +#include "G4UnitsTable.hh" +#include "G4SystemOfUnits.hh" +#include "TrksEventAction.h" + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +TrksSteppingAction::TrksSteppingAction(): G4UserSteppingAction() +{ + +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +TrksSteppingAction::~TrksSteppingAction() +{ + // --- +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +void TrksSteppingAction::UserSteppingAction(const G4Step * aStep) +{ + + int trkNum = aStep->GetTrack()->GetTrackID(); + + stepData tmpStepData; + tmpStepData.x = aStep->GetPostStepPoint()->GetPosition().getX(); + tmpStepData.y = aStep->GetPostStepPoint()->GetPosition().getY(); + tmpStepData.z = aStep->GetPostStepPoint()->GetPosition().getZ(); + + std::map<int, std::vector<stepData>> &trksInfoMap = TrksEventAction::trksInfoMap; + + trksInfoMap[trkNum].push_back(tmpStepData); + +} \ No newline at end of file diff --git a/FullSimLight/Plugins/GenerateTracksPluginROOT/src/TrksTrackingAction.cc b/FullSimLight/Plugins/GenerateTracksPluginROOT/src/TrksTrackingAction.cc new file mode 100644 index 0000000000000000000000000000000000000000..589bffb584ebf3a11e44fb1f3ea96c773054354c --- /dev/null +++ b/FullSimLight/Plugins/GenerateTracksPluginROOT/src/TrksTrackingAction.cc @@ -0,0 +1,63 @@ +#include "TrksTrackingAction.h" +#include "G4UnitsTable.hh" +#include "G4Track.hh" +#include "TrksRunAction.h" +#include "G4RunManager.hh" +#include "G4StepPoint.hh" +#include "TrksEventAction.h" + +//#include "H5Cpp.h" + +#include <mutex> +#include <string> + +using std::string; +using std::to_string; + +TrksTrackingAction::TrksTrackingAction():G4UserTrackingAction() +{ + +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +TrksTrackingAction::~TrksTrackingAction() +{ + +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +void TrksTrackingAction::PreUserTrackingAction(const G4Track* aTrack) +{ + int trkNum = aTrack->GetTrackID(); + + std::map<int, std::vector<stepData>> &trksInfoMap = TrksEventAction::trksInfoMap; + + stepData tmpStepData; + tmpStepData.x = aTrack->GetPosition().getX(); + tmpStepData.y = aTrack->GetPosition().getY(); + tmpStepData.z = aTrack->GetPosition().getZ(); + + if (trksInfoMap.find(trkNum) != trksInfoMap.end()) //track ID already in the map + { + std::vector<stepData> &v = trksInfoMap[trkNum]; + v.push_back(tmpStepData); + } + else //There is no such track with given track ID + { + std::vector<stepData> newV = {tmpStepData}; + trksInfoMap[trkNum] = newV; + } + + G4int particlePDG = aTrack->GetParticleDefinition()->GetPDGEncoding(); + TrksEventAction::gPDGs[trkNum] = particlePDG; + +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +void TrksTrackingAction::PostUserTrackingAction(const G4Track* /*aTrack*/) +{ + +} \ No newline at end of file