diff --git a/Gate.cc b/Gate.cc index b906f184f..dc7270575 100644 --- a/Gate.cc +++ b/Gate.cc @@ -6,7 +6,7 @@ * \brief To launch GATE: * - 'Gate' or 'Gate --qt' using the Qt visualization * - 'Gate your_macro.mac' or 'Gate --qt your_macro.mac' using the Qt visualization - * - 'Gate -d your_macro.mac' using the DigiGate + * - 'Gate your_macro.mac --d hits.root' for Offline Digitizer * - 'Gate -a [activity,10]' using the parameterized macro creating an alias in your macro */ @@ -36,7 +36,7 @@ #include "GateOutputMgr.hh" #include "GatePrimaryGeneratorAction.hh" #include "GateUserActions.hh" -#include "GateDigitizer.hh" +#include "GateDigitizerMgr.hh" #include "GateClock.hh" #include "GateUIcontrolMessenger.hh" #ifdef G4ANALYSIS_USE_ROOT @@ -69,7 +69,9 @@ void printHelpAndQuit( G4String msg ) GateMessage( "Core", 0, " -h, --help print the help" << G4endl ); GateMessage( "Core", 0, " -v, --version print the version" << G4endl ); GateMessage( "Core", 0, " -a, --param set alias. format is '[alias1,value1] [alias2,value2] ...'" << G4endl ); - GateMessage( "Core", 0, " --d use the DigiMode" << G4endl ); + GateMessage( "Core", 0, +" --d FILE use Offline Digi mode with input ROOT file" +<< G4endl ); GateMessage( "Core", 0, " --qt use the Qt visualization mode" << G4endl ); exit( EXIT_FAILURE ); } @@ -200,6 +202,7 @@ int main( int argc, char* argv[] ) // analyzing arguments static G4int isDigiMode = 0; // DigiMode false by default + G4String digiInputFile = ""; static G4int isQt = 0; // Enable Qt or not G4String listOfParameters = ""; // List of parameters for parameterized macro DigiMode aDigiMode = kruntimeMode; @@ -214,7 +217,7 @@ int main( int argc, char* argv[] ) static struct option longOptions[] = { { "help", no_argument, 0, 'h' }, { "version", no_argument, 0, 'v' }, - { "d", no_argument, &isDigiMode, 1 }, + { "d", required_argument, 0, 'd' }, { "qt", no_argument, &isQt, 1 }, { "param", required_argument, 0, 'a' } }; @@ -262,6 +265,10 @@ int main( int argc, char* argv[] ) case 'a': listOfParameters = optarg; break; + case 'd': + isDigiMode = 1; + digiInputFile = optarg; + break; default: printHelpAndQuit( "Out of switch options" ); break; @@ -271,7 +278,19 @@ int main( int argc, char* argv[] ) // Checking if the DigiMode is activated if( isDigiMode ) aDigiMode = kofflineMode; - + + if (isDigiMode) + { + if (digiInputFile.empty()) + { + G4cerr << "Error: Offline Digi mode requires an input ROOT file.\n" + << "Usage: Gate main.mac --d input.root\n"; + return EXIT_FAILURE; + } + + GateHitFileReader::GetInstance()->SetFileName(digiInputFile); + GateDigitizerMgr::GetInstance()->SetOfflineMode(true); + } // Analyzing parameterized macro std::queue< G4String > commandQueue = decodeParameters( listOfParameters ); diff --git a/source/digits_hits/include/GateDigitizerMgr.hh b/source/digits_hits/include/GateDigitizerMgr.hh index e5f9c5778..7b22066d0 100644 --- a/source/digits_hits/include/GateDigitizerMgr.hh +++ b/source/digits_hits/include/GateDigitizerMgr.hh @@ -105,11 +105,26 @@ public: GateCoincidenceDigitizer* FindCoincidenceDigitizer(G4String mName); /// End of methods for Coincidences + + //Methods for OfflineDigi + + void SetOfflineMode(bool b) { mOfflineMode = b; } + bool IsOfflineMode() const { return mOfflineMode; } + + GateHitsCollection* GetOfflineHitsCollection(); + + void SetOfflineHitsCollection(GateHitsCollection* hc); + void ClearOfflineHitsCollection(); + + + + private: GateDigitizerMgrMessenger *fMessenger; - + GateHitsCollection* mOfflineHitsCollection = nullptr; + bool mOfflineMode = false; static GateDigitizerMgr* theDigitizerMgr; protected: diff --git a/source/digits_hits/include/GateHitFileReader.hh b/source/digits_hits/include/GateHitFileReader.hh index b15e51e4a..a8530bae2 100644 --- a/source/digits_hits/include/GateHitFileReader.hh +++ b/source/digits_hits/include/GateHitFileReader.hh @@ -91,6 +91,21 @@ public: virtual void Describe(size_t indent=0); + const std::vector& GetHitVector() const + { + return m_hitVector; + } + + std::vector& GetHitVector() + { + return m_hitVector; + } + + bool IsFinished() const + { + return m_finished; + } + protected: //! Reads a set of hit data from the hit-tree, and stores them into the root-hit buffer @@ -111,15 +126,13 @@ protected: //!< The hit-data are loaded into this buffer by LoadHitData() //!< They are then transformed into a crystal-hit by PrepareNextEvent() - std::queue m_hitQueue; //!< Queue of waiting hits for the current event - //!< For each event, the queue is filled (from data read out of the hit-file) at - //!< the beginning of each event by PrepareNextEvent(). It is emptied into - //!< a crystal-hit collection at the end of each event by PrepareEndOfEvent() + std::vector m_hitVector; GateHitFileReaderMessenger *m_messenger; //!< Messenger; private: static GateHitFileReader* instance; //!< Instance of the GateHitFielReader singleton + bool m_finished; }; #endif diff --git a/source/digits_hits/include/GateToRoot.hh b/source/digits_hits/include/GateToRoot.hh index 18f85be23..ddb20631d 100644 --- a/source/digits_hits/include/GateToRoot.hh +++ b/source/digits_hits/include/GateToRoot.hh @@ -109,6 +109,8 @@ public: void RecordOpticalData(const G4Event *event); // v. cuplov - optical photons + void SetOfflineOutputFileName(); + void RecordVoxels(const G4Step *); void BookBeginOfAquisition(); diff --git a/source/digits_hits/src/GateDigitizerInitializationModule.cc b/source/digits_hits/src/GateDigitizerInitializationModule.cc index d0902f908..d99e7f992 100644 --- a/source/digits_hits/src/GateDigitizerInitializationModule.cc +++ b/source/digits_hits/src/GateDigitizerInitializationModule.cc @@ -28,6 +28,7 @@ #include "G4SDManager.hh" #include "G4DigiManager.hh" #include "G4ios.hh" +#include "GateDigitizerMgr.hh" GateDigitizerInitializationModule::GateDigitizerInitializationModule(GateSinglesDigitizer *digitizer) :GateVDigitizerModule("DigiInit","digitizerMgr/"+digitizer->GetSD()->GetName()+"/SinglesDigitizer/"+digitizer->m_digitizerName+"/digiInit",digitizer, digitizer->GetSD()), @@ -65,7 +66,23 @@ void GateDigitizerInitializationModule::Digitize() } - GateHitsCollection* inHC = (GateHitsCollection*) (DigiMan->GetHitsCollection(m_HCID));// DigiMan->GetHitsCollectionID(HCname))); + GateHitsCollection* inHC; + GateDigitizerMgr* digitizerMgr=GateDigitizerMgr::GetInstance(); + + + if (GateDigitizerMgr::GetInstance()->IsOfflineMode() && + digitizerMgr->GetOfflineHitsCollection() == nullptr) + { + GateMessage("OfflineDigi", 1, + "No offline hits, skipping digitization."); + return; + } + + + if (GateDigitizerMgr::GetInstance()->IsOfflineMode()) + inHC = digitizerMgr->GetOfflineHitsCollection(); + else + inHC = (GateHitsCollection*)DigiMan->GetHitsCollection(m_HCID); if (inHC) diff --git a/source/digits_hits/src/GateDigitizerMgr.cc b/source/digits_hits/src/GateDigitizerMgr.cc index 54076c8de..18dadf165 100644 --- a/source/digits_hits/src/GateDigitizerMgr.cc +++ b/source/digits_hits/src/GateDigitizerMgr.cc @@ -538,6 +538,35 @@ void GateDigitizerMgr::RunCoincidenceDigitizers() //m_alreadyRun=true; } + +GateHitsCollection* GateDigitizerMgr::GetOfflineHitsCollection() +{ + + if (mOfflineHitsCollection) + return mOfflineHitsCollection; + +} + + +void GateDigitizerMgr::SetOfflineHitsCollection(GateHitsCollection* hc) +{ + if (mOfflineHitsCollection) + delete mOfflineHitsCollection; + + mOfflineHitsCollection = hc; +} + + +void GateDigitizerMgr::ClearOfflineHitsCollection() +{ + delete mOfflineHitsCollection; + mOfflineHitsCollection = nullptr; +} + + + + + void GateDigitizerMgr::ShowSummary() { G4cout<<"-----------------------"<IsOpen())) - { - G4String msg = "Could not open the requested hit file '" + m_fileName + ".root'!"; - G4Exception( "GateHitFileReader::PrepareBeforeAcquisition", "PrepareBeforeAcquisition", FatalException, msg ); - } + + m_hitFile = TFile::Open(m_fileName.c_str(), "READ"); + + if (!m_hitFile || m_hitFile->IsZombie()) + { + G4String msg = + "Could not open hit file '" + m_fileName + "'"; + G4Exception("GateHitFileReader::PrepareBeforeAcquisition", "PrepareBeforeAcquisition", FatalException, msg); + } // Get the hit tree m_hitTree = (TTree*)( m_hitFile->Get(GateHitConvertor::GetOutputAlias()) ); if (!m_hitTree) { - G4String msg = "Could not find a tree of hits in the ROOT file '" + m_fileName + ".root'!"; + G4String msg = "Could not find a tree of hits in the ROOT file '" + m_fileName + "'!"; G4Exception( "GateHitFileReader::PrepareBeforeAcquisition", "PrepareBeforeAcquisition", FatalException, msg); } // Reset the entry counters @@ -103,6 +102,7 @@ void GateHitFileReader::PrepareAcquisition() // Load the first hit into the root-hit structure LoadHitData(); + } @@ -119,14 +119,22 @@ void GateHitFileReader::PrepareAcquisition() */ G4int GateHitFileReader::PrepareNextEvent(G4Event* ) { - G4cout << " GateHitFileReader::PrepareNextEvent\n"; + + for (auto hit : m_hitVector) + delete hit; + + m_hitVector.clear(); + // Store the current runID and eventID G4int currentEventID = m_hitBuffer.eventID; G4int currentRunID = m_hitBuffer.runID; // We've reached the end-of-file if ( (currentEventID==-1) && (currentRunID==-1) ) - return 0; + { + m_finished = true; + return 0; + } // Load the hits for the current event // We loop until the data that have been read are found to be for a different event or run @@ -134,35 +142,18 @@ G4int GateHitFileReader::PrepareNextEvent(G4Event* ) // Create a new hit and store it into the hit-queue GateHit* aHit = m_hitBuffer.CreateHit(); - m_hitQueue.push(aHit); + m_hitVector.push_back(aHit); // Load the next set of hit-data into the root-hit structure LoadHitData(); } - if (currentRunID==m_hitBuffer.runID){ - // We got a set of hits for the current run -> return 1 - return 1; - } - else - { - // We got a set of hits for a later run -> return 0 + if (!m_hitVector.empty()) + return 1; return 0; - } } -// This method is meant to be called by output manager before calling the methods RecordEndOfEvent() of the output modules. -// It creates a new hit-collection, based on the queue of hits previously filled by PrepareNextEvent() -void GateHitFileReader::PrepareEndOfEvent() -{ - // We loop until the hit-queue is empty - // Each hit is inserted into the crystalSD hit-collection, then removed from the queue - while (m_hitQueue.size()) { - GateOutputMgr::GetInstance()->GetHitCollection()->insert(m_hitQueue.front()); - m_hitQueue.pop(); - } -} @@ -176,11 +167,10 @@ void GateHitFileReader::TerminateAfterAcquisition() m_hitFile=0; } - // If the hit queue was not empty (it should be), clear it up - while (m_hitQueue.size()) { - delete m_hitQueue.front(); - m_hitQueue.pop(); - } + for (auto hit : m_hitVector) + delete hit; + + m_hitVector.clear(); // Note that we don't delete the tree: it was based on the file so // I assume it was destroyed at the same time as the file was closed (true?) diff --git a/source/digits_hits/src/GateOutputMgr.cc b/source/digits_hits/src/GateOutputMgr.cc index bf1c4b3f4..bc8226dbd 100644 --- a/source/digits_hits/src/GateOutputMgr.cc +++ b/source/digits_hits/src/GateOutputMgr.cc @@ -90,10 +90,11 @@ GateOutputMgr::GateOutputMgr(const G4String name) } #endif - if (m_digiMode==kruntimeMode) { + GateAnalysis* gateAnalysis = new GateAnalysis("analysis", this,m_digiMode); AddOutputModule((GateVOutputModule*)gateAnalysis); + if (m_digiMode==kruntimeMode) { GateMultiPhotonAnalysis* gateMultiPhotonAnalysis = new GateMultiPhotonAnalysis("multianalysis", this, m_digiMode); AddOutputModule((GateVOutputModule*)gateMultiPhotonAnalysis); @@ -195,11 +196,6 @@ void GateOutputMgr::RecordEndOfEvent(const G4Event* event) { GateMessage("Output", 5, "GateOutputMgr::RecordEndOfEvent\n";); -#ifdef G4ANALYSIS_USE_ROOT - if (m_digiMode==kofflineMode) - GateHitFileReader::GetInstance()->PrepareEndOfEvent(); -#endif - for (size_t iMod=0; iModIsEnabled() ) { diff --git a/source/digits_hits/src/GateToRoot.cc b/source/digits_hits/src/GateToRoot.cc index 2626daf8d..5f3c5a374 100644 --- a/source/digits_hits/src/GateToRoot.cc +++ b/source/digits_hits/src/GateToRoot.cc @@ -54,6 +54,7 @@ #include "GateVVolume.hh" #include "GateToRootMessenger.hh" #include "GateVGeometryVoxelStore.hh" +#include "GateHitFileReader.hh" #include "TROOT.h" #include "TApplication.h" @@ -376,6 +377,10 @@ void GateToRoot::RecordBeginOfAcquisition() { ////////// // Open the output file if (nVerboseLevel > 0) G4cout << "GateToRoot: ROOT: files creation...\n"; + + if (m_digiMode == kofflineMode) + SetOfflineOutputFileName(); + switch (m_digiMode) { case kruntimeMode: // In run-time mode, we open the file in RECREATE mode @@ -1818,6 +1823,30 @@ void GateToRoot::RecordTracks(GateSteppingAction *mySteppingAction) { } + +void GateToRoot::SetOfflineOutputFileName() +{ + G4String input = GateHitFileReader::GetInstance()->GetFileName(); + + // Remove ".root" if present + if (input.length() > 5 && + input.substr(input.length() - 5) == ".root") + { + input = input.substr(0, input.length() - 5); + } + + m_fileName = input + "_digi"; + + G4cout << G4endl + << "Offline Digi mode:" << G4endl + << " Input : " << GateHitFileReader::GetInstance()->GetFileName() << G4endl + << " Output: " << m_fileName << ".root" << G4endl + << G4endl; +} + + + + /*PY Descourt 08/09/2009 */ //-------------------------------------------------------------------------- diff --git a/source/general/src/GateApplicationMgr.cc b/source/general/src/GateApplicationMgr.cc index 4fe2e6086..4f6141b77 100644 --- a/source/general/src/GateApplicationMgr.cc +++ b/source/general/src/GateApplicationMgr.cc @@ -21,6 +21,7 @@ #include "GateVSource.hh" #include "GateSourceMgr.hh" #include "GateOutputMgr.hh" +#include "GateHitFileReader.hh" #include /* min and max */ GateApplicationMgr* GateApplicationMgr::instance = 0; @@ -326,6 +327,7 @@ void GateApplicationMgr::StartDAQComplete(G4ThreeVector param) //------------------------------------------------------------------------------------------ + //------------------------------------------------------------------------------------------ void GateApplicationMgr::StartDAQ() { @@ -334,6 +336,21 @@ void GateApplicationMgr::StartDAQ() // filename given. In this case we disable the output module and send a warning. GateOutputMgr::GetInstance()->CheckFileNameForAllOutput(); + if (mOutputMode) + { + + GateMessage("Acquisition", 0," ! OFFLINE DIGI MODE ! \n"); + GateMessage("Acquisition", 0, "============= Source initialization =============\n"); + GateMessage("Acquisition", 0, "IGNORED\n"); + + GateMessage("Acquisition", 0," \n"); + GateMessage("Acquisition", 0, "============= Acquisition starts! =============\n"); + GateMessage("Acquisition", 0, "IGNORED\n"); + + } + else + { + GateMessage("Acquisition", 0," \n"); GateMessage("Acquisition", 0, "============= Source initialization =============\n"); @@ -354,18 +371,21 @@ void GateApplicationMgr::StartDAQ() GateRandomEngine* theRandomEngine = GateRandomEngine::GetInstance(); theRandomEngine->Initialize(); if (theRandomEngine->GetVerbosity()>=1) theRandomEngine->ShowStatus(); - + } GateClock* theClock = GateClock::GetInstance(); m_clusterStart = mTimeSlices.front(); m_clusterStop = mTimeSlices.back(); if (mOutputMode) - GateOutputMgr::GetInstance()->RecordBeginOfAcquisition(); + GateOutputMgr::GetInstance()->RecordBeginOfAcquisition(); + + + bool offlineFinished = false; G4int slice=0; m_time = mTimeSlices.front(); - while(m_time < mTimeSlices.back()) + while(m_time < mTimeSlices.back() && !offlineFinished) { // Informational message about the current slice @@ -380,8 +400,10 @@ void GateApplicationMgr::StartDAQ() GateMessage("Geometry", 5, " Time is going to change : = " << m_time/s << Gateendl;); theClock->SetTime(m_time); + + if (mReadNumberOfPrimariesInAFileIsUsed) { - GateRunManager::GetRunManager()->SetRunIDCounter(slice); // Must explicitly keep the RunID in sync with the slice # + GateRunManager::GetRunManager()->SetRunIDCounter(slice); // Must explicitly keep the RunID in sync with the slice # GateRunManager::GetRunManager()->BeamOn(mNumberOfPrimariesPerRun[slice]); m_time = mTimeSlices[slice+1]; } @@ -400,6 +422,7 @@ void GateApplicationMgr::StartDAQ() - int(mTimeSlices[slice]/mTimeStepInTotalAmountOfPrimariesMode); } GateRunManager::GetRunManager()->SetRunIDCounter(slice); // Must explicitly keep the RunID in sync with the slice # + //G4cout << "Calling BeamOn(" << mRequestedAmountOfPrimariesPerRun << ")" << G4endl; GateRunManager::GetRunManager()->BeamOn(mRequestedAmountOfPrimariesPerRun); // otherwise RunID is automatically incremented m_time = mTimeSlices[slice+1]; } @@ -408,9 +431,21 @@ void GateApplicationMgr::StartDAQ() while(m_timeSetRunIDCounter(slice); // Must explicitly keep the RunID in sync with the slice # + //G4cout << "Calling BeamOn(INT_MAX)" << G4endl; + GateRunManager::GetRunManager()->BeamOn(INT_MAX); // otherwise RunID is automatically incremented + #ifdef G4ANALYSIS_USE_ROOT + if (GateOutputMgr::GetInstance()->GetDigiMode()==kofflineMode && + GateHitFileReader::GetInstance()->IsFinished()) + { + offlineFinished = true; + break; + } + #endif theClock->SetTimeNoGeoUpdate(m_time); } + + } slice++; @@ -428,6 +463,7 @@ void GateApplicationMgr::StartDAQ() //------------------------------------------------------------------------------------------ + //------------------------------------------------------------------------------------------ void GateApplicationMgr::StartDAQCluster(G4ThreeVector param) { diff --git a/source/general/src/GatePrimaryGeneratorAction.cc b/source/general/src/GatePrimaryGeneratorAction.cc index bca4bebbe..71e223d8e 100644 --- a/source/general/src/GatePrimaryGeneratorAction.cc +++ b/source/general/src/GatePrimaryGeneratorAction.cc @@ -23,8 +23,9 @@ See LICENSE.md for further details #include "GateApplicationMgr.hh" #include "GateSourceMgr.hh" -//#include "GateOutputMgr.hh" -//#include "GateHitFileReader.hh" +#include "GateOutputMgr.hh" +#include "GateHitFileReader.hh" +#include "GateDigitizerMgr.hh" #include "GateConfiguration.h" @@ -66,11 +67,12 @@ void GatePrimaryGeneratorAction::SetVerboseLevel(G4int value) //--------------------------------------------------------------------------- void GatePrimaryGeneratorAction::GeneratePrimaries(G4Event* event) { - // if (GateOutputMgr::GetInstance()->GetDigiMode() == kruntimeMode) - // else - // GenerateDigitisationPrimaries(event); + if (!m_useGPS) { - GenerateSimulationPrimaries(event); + if (GateOutputMgr::GetInstance()->GetDigiMode() == kruntimeMode) + GenerateSimulationPrimaries(event); + else + GenerateDigitisationPrimaries(event); } else { static int i=0; @@ -122,36 +124,50 @@ void GatePrimaryGeneratorAction::GenerateSimulationPrimaries(G4Event* event) } //--------------------------------------------------------------------------- -/* + //--------------------------------------------------------------------------- void GatePrimaryGeneratorAction::GenerateDigitisationPrimaries(G4Event* event) { - #ifdef G4ANALYSIS_USE_ROOT -GateHitFileReader* digiSource = GateHitFileReader::GetInstance(); + GateHitFileReader* reader = GateHitFileReader::GetInstance(); -G4int numEvent = digiSource->PrepareNextEvent(event); + G4int ok = reader->PrepareNextEvent(event); + if (!ok) + { + GateDigitizerMgr::GetInstance()->SetOfflineHitsCollection(nullptr); -//! stop the run if no particle has been generated by the source manager -if (numEvent == 0) { -GateRunManager* runManager = GateRunManager::GetRunManager(); + GateRunManager::GetRunManager()->AbortRun(true); -runManager->AbortRun(true); -if (m_nVerboseLevel>1) G4cout << "GatePrimaryGeneratorAction::GeneratePrimaries: numVertices == 0, run aborted \n"; -} else { -m_nEvents++; -if (m_nVerboseLevel>0) { -if ((m_nEvents%m_printModulo) == 0) { -G4cout << "GatePrimaryGeneratorAction::GeneratePrimaries: m_nEvents " << m_nEvents << Gateendl; -} -} -} + return; + } + // Build the hit collection for this event + GateHitsCollection* hc = + new GateHitsCollection("crystal", "CrystalCollection"); + + for (auto hit : reader->GetHitVector()) + hc->insert(hit); + + + // The collection now owns the hits + reader->GetHitVector().clear(); + + GateDigitizerMgr::GetInstance()->SetOfflineHitsCollection(hc); + + + m_nEvents++; + + + /*G4cout << "Finished = " + << GateHitFileReader::GetInstance()->IsFinished() + << G4endl;*/ #endif } -*/ + //--------------------------------------------------------------------------- + + //--------------------------------------------------------------------------- void GatePrimaryGeneratorAction::AddEvent() {