From 80f041f15e26b668c646a7a359c049dc97f8ba56 Mon Sep 17 00:00:00 2001 From: lmlepin9 Date: Thu, 9 Apr 2026 22:56:14 -0500 Subject: [PATCH 1/2] Adding helper class to read AmBe root files --- include/WCSimAmBePrimaryReader.hh | 93 ++++++++++++ src/WCSimAmBePrimaryReader.cc | 217 ++++++++++++++++++++++++++++ test/test_WCSimAmBePrimaryReader.cc | 68 +++++++++ 3 files changed, 378 insertions(+) create mode 100644 include/WCSimAmBePrimaryReader.hh create mode 100644 src/WCSimAmBePrimaryReader.cc create mode 100644 test/test_WCSimAmBePrimaryReader.cc diff --git a/include/WCSimAmBePrimaryReader.hh b/include/WCSimAmBePrimaryReader.hh new file mode 100644 index 000000000..d50188729 --- /dev/null +++ b/include/WCSimAmBePrimaryReader.hh @@ -0,0 +1,93 @@ +#ifndef WCSIMAMBEPRIMARYREADER_HH +#define WCSIMAMBEPRIMARYREADER_HH + +#include +#include + +#include "Math/Vector4D.h" + +class TFile; +class TTree; + +struct WCSimAmBeParticle { + int track_id; + int parent_id; + int pdg; + ROOT::Math::XYZTVector position; + ROOT::Math::XYZTVector momentum; + std::string process; + + WCSimAmBeParticle() + : track_id(-1), + parent_id(-1), + pdg(0), + position(), + momentum(), + process("") {} +}; + +struct WCSimAmBeEvent { + int rank; + int thread_id; + int event_id; + std::vector particles; + + WCSimAmBeEvent() : rank(-1), thread_id(-1), event_id(-1), particles() {} + + void Clear() { + rank = -1; + thread_id = -1; + event_id = -1; + particles.clear(); + } +}; + +class WCSimAmBePrimaryReader { + public: + WCSimAmBePrimaryReader(); + virtual ~WCSimAmBePrimaryReader(); + + bool Open(const std::string& filename, + const std::string& treeName = "EmergingParticles"); + void Close(); + + bool IsOpen() const; + bool HasTree() const; + + bool NextEvent(WCSimAmBeEvent& event); + void Reset(); + + long long GetEntries() const; + long long GetCurrentEntry() const; + std::string GetFileName() const; + std::string GetTreeName() const; + + private: + bool SetupBranches(); + void ClearBranchPointers(); + bool ValidateCurrentEntry() const; + + private: + TFile* fFile; + TTree* fTree; + + std::string fFileName; + std::string fTreeName; + long long fCurrentEntry; + long long fNEntries; + + // Event-level branches + int fbranchEmergingRank; + int fbranchEmergingThreadId; + int fbranchEmergingEventId; + + // Particle-level branches + std::vector* fbranchEmergingId; + std::vector* fbranchEmergingParentId; + std::vector* fbranchEmergingPDG; + std::vector* fbranchEmergingPos; + std::vector* fbranchEmergingP; + std::vector* fbranchEmergingProcess; +}; + +#endif \ No newline at end of file diff --git a/src/WCSimAmBePrimaryReader.cc b/src/WCSimAmBePrimaryReader.cc new file mode 100644 index 000000000..cbf6568a0 --- /dev/null +++ b/src/WCSimAmBePrimaryReader.cc @@ -0,0 +1,217 @@ +#include "WCSimAmBePrimaryReader.hh" + +#include + +// ROOT +#include "TFile.h" +#include "TTree.h" + +WCSimAmBePrimaryReader::WCSimAmBePrimaryReader() + : fFile(0), + fTree(0), + fFileName(""), + fTreeName("EmergingParticles"), + fCurrentEntry(0), + fNEntries(0), + fbranchEmergingRank(-1), + fbranchEmergingThreadId(-1), + fbranchEmergingEventId(-1), + fbranchEmergingId(0), + fbranchEmergingParentId(0), + fbranchEmergingPDG(0), + fbranchEmergingPos(0), + fbranchEmergingP(0), + fbranchEmergingProcess(0) {} + +WCSimAmBePrimaryReader::~WCSimAmBePrimaryReader() { + Close(); +} + +bool WCSimAmBePrimaryReader::Open(const std::string& filename, + const std::string& treeName) { + Close(); + + fFileName = filename; + fTreeName = treeName; + fCurrentEntry = 0; + fNEntries = 0; + + fFile = TFile::Open(filename.c_str(), "READ"); + if (!fFile || fFile->IsZombie()) { + std::cerr << "WCSimAmBePrimaryReader::Open(): failed to open file: " + << filename << std::endl; + Close(); + return false; + } + + fTree = dynamic_cast(fFile->Get(treeName.c_str())); + if (!fTree) { + std::cerr << "WCSimAmBePrimaryReader::Open(): failed to find tree '" + << treeName << "' in file: " << filename << std::endl; + Close(); + return false; + } + + if (!SetupBranches()) { + std::cerr << "WCSimAmBePrimaryReader::Open(): failed to set branch addresses" + << std::endl; + Close(); + return false; + } + + fNEntries = static_cast(fTree->GetEntries()); + + std::cout << "WCSimAmBePrimaryReader: opened file " << fFileName + << " with tree " << fTreeName + << " containing " << fNEntries << " entries." << std::endl; + + return true; +} + +void WCSimAmBePrimaryReader::Close() { + ClearBranchPointers(); + + if (fFile) { + fFile->Close(); + delete fFile; + fFile = 0; + } + + fTree = 0; + fFileName = ""; + fTreeName = "EmergingParticles"; + fCurrentEntry = 0; + fNEntries = 0; + fbranchEmergingRank = -1; + fbranchEmergingThreadId = -1; + fbranchEmergingEventId = -1; +} + +bool WCSimAmBePrimaryReader::IsOpen() const { + return (fFile != 0); +} + +bool WCSimAmBePrimaryReader::HasTree() const { + return (fTree != 0); +} + +void WCSimAmBePrimaryReader::Reset() { + fCurrentEntry = 0; +} + +long long WCSimAmBePrimaryReader::GetEntries() const { + return fNEntries; +} + +long long WCSimAmBePrimaryReader::GetCurrentEntry() const { + return fCurrentEntry; +} + +std::string WCSimAmBePrimaryReader::GetFileName() const { + return fFileName; +} + +std::string WCSimAmBePrimaryReader::GetTreeName() const { + return fTreeName; +} + +bool WCSimAmBePrimaryReader::SetupBranches() { + if (!fTree) return false; + + ClearBranchPointers(); + + fTree->SetBranchAddress("Rank", &fbranchEmergingRank); + fTree->SetBranchAddress("Thread", &fbranchEmergingThreadId); + fTree->SetBranchAddress("EventId", &fbranchEmergingEventId); + fTree->SetBranchAddress("TrackId", &fbranchEmergingId); + fTree->SetBranchAddress("ParentId", &fbranchEmergingParentId); + fTree->SetBranchAddress("PDG", &fbranchEmergingPDG); + fTree->SetBranchAddress("Vertex", &fbranchEmergingPos); + fTree->SetBranchAddress("Momentum", &fbranchEmergingP); + fTree->SetBranchAddress("Process", &fbranchEmergingProcess); + + return true; +} + +void WCSimAmBePrimaryReader::ClearBranchPointers() { + fbranchEmergingId = 0; + fbranchEmergingParentId = 0; + fbranchEmergingPDG = 0; + fbranchEmergingPos = 0; + fbranchEmergingP = 0; + fbranchEmergingProcess = 0; +} + +bool WCSimAmBePrimaryReader::ValidateCurrentEntry() const { + if (!fbranchEmergingId || + !fbranchEmergingParentId || + !fbranchEmergingPDG || + !fbranchEmergingPos || + !fbranchEmergingP || + !fbranchEmergingProcess) { + std::cerr << "WCSimAmBePrimaryReader::ValidateCurrentEntry(): " + << "one or more branch pointers are null." << std::endl; + return false; + } + + const std::size_t n = fbranchEmergingPDG->size(); + + if (fbranchEmergingId->size() != n || + fbranchEmergingParentId->size() != n || + fbranchEmergingPos->size() != n || + fbranchEmergingP->size() != n || + fbranchEmergingProcess->size() != n) { + std::cerr << "WCSimAmBePrimaryReader::ValidateCurrentEntry(): " + << "inconsistent vector sizes in EventId " + << fbranchEmergingEventId << std::endl; + return false; + } + + return true; +} + +bool WCSimAmBePrimaryReader::NextEvent(WCSimAmBeEvent& event) { + event.Clear(); + + if (!fTree) { + std::cerr << "WCSimAmBePrimaryReader::NextEvent(): no tree is loaded." + << std::endl; + return false; + } + + if (fCurrentEntry >= fNEntries) { + return false; + } + + Long64_t bytesRead = fTree->GetEntry(fCurrentEntry); + if (bytesRead <= 0) { + std::cerr << "WCSimAmBePrimaryReader::NextEvent(): failed to read entry " + << fCurrentEntry << std::endl; + return false; + } + + if (!ValidateCurrentEntry()) { + return false; + } + + event.rank = fbranchEmergingRank; + event.thread_id = fbranchEmergingThreadId; + event.event_id = fbranchEmergingEventId; + + event.particles.reserve(fbranchEmergingPDG->size()); + + for (std::size_t i = 0; i < fbranchEmergingPDG->size(); ++i) { + WCSimAmBeParticle particle; + particle.track_id = fbranchEmergingId->at(i); + particle.parent_id = fbranchEmergingParentId->at(i); + particle.pdg = fbranchEmergingPDG->at(i); + particle.position = fbranchEmergingPos->at(i); + particle.momentum = fbranchEmergingP->at(i); + particle.process = fbranchEmergingProcess->at(i); + + event.particles.push_back(particle); + } + + ++fCurrentEntry; + return true; +} \ No newline at end of file diff --git a/test/test_WCSimAmBePrimaryReader.cc b/test/test_WCSimAmBePrimaryReader.cc new file mode 100644 index 000000000..82840c85f --- /dev/null +++ b/test/test_WCSimAmBePrimaryReader.cc @@ -0,0 +1,68 @@ +#include +#include + +#include "WCSimAmBePrimaryReader.hh" + +int main(int argc, char** argv) { + if (argc < 2) { + std::cerr << "Usage: " << argv[0] << " input.root [tree_name]" << std::endl; + return 1; + } + + std::string inputFile = argv[1]; + std::string treeName = "EmergingParticles"; + if (argc >= 3) { + treeName = argv[2]; + } + + WCSimAmBePrimaryReader reader; + + if (!reader.Open(inputFile, treeName)) { + std::cerr << "ERROR: failed to open input file/tree" << std::endl; + return 2; + } + + std::cout << "Opened file: " << reader.GetFileName() << std::endl; + std::cout << "Tree name: " << reader.GetTreeName() << std::endl; + std::cout << "Entries: " << reader.GetEntries() << std::endl; + + WCSimAmBeEvent event; + int nToPrint = 3; + int nRead = 0; + + while (nRead < nToPrint && reader.NextEvent(event)) { + std::cout << "\n========================================" << std::endl; + std::cout << "Reader entry: " << reader.GetCurrentEntry() - 1 << std::endl; + std::cout << "Rank: " << event.rank << std::endl; + std::cout << "Thread: " << event.thread_id << std::endl; + std::cout << "EventId: " << event.event_id << std::endl; + std::cout << "N particles: " << event.particles.size() << std::endl; + + for (std::size_t i = 0; i < event.particles.size(); ++i) { + const auto& p = event.particles[i]; + + std::cout << " Particle " << i << std::endl; + std::cout << " track_id: " << p.track_id << std::endl; + std::cout << " parent_id: " << p.parent_id << std::endl; + std::cout << " pdg: " << p.pdg << std::endl; + std::cout << " process: " << p.process << std::endl; + + std::cout << " position: (" + << p.position.X() << ", " + << p.position.Y() << ", " + << p.position.Z() << ", " + << p.position.T() << ")" << std::endl; + + std::cout << " momentum: (" + << p.momentum.X() << ", " + << p.momentum.Y() << ", " + << p.momentum.Z() << ", " + << p.momentum.T() << ")" << std::endl; + } + + ++nRead; + } + + std::cout << "\nDone." << std::endl; + return 0; +} \ No newline at end of file From 6e3537f57c230167b3d098a01ddd0078350c031e Mon Sep 17 00:00:00 2001 From: lmlepin9 Date: Thu, 9 Apr 2026 22:59:43 -0500 Subject: [PATCH 2/2] Adding modifcations to accept AmBe root files for primary particle simulation --- include/WCSimPrimaryGeneratorAction.hh | 24 ++++- include/WCSimPrimaryGeneratorMessenger.hh | 5 + src/WCSimPrimaryGeneratorAction.cc | 119 +++++++++++++++++++++- src/WCSimPrimaryGeneratorMessenger.cc | 56 +++++++++- 4 files changed, 200 insertions(+), 4 deletions(-) diff --git a/include/WCSimPrimaryGeneratorAction.hh b/include/WCSimPrimaryGeneratorAction.hh index d7594a6ee..b6dfd4c7c 100644 --- a/include/WCSimPrimaryGeneratorAction.hh +++ b/include/WCSimPrimaryGeneratorAction.hh @@ -20,6 +20,8 @@ #include "Framework/Interaction/Interaction.h" #endif #include "WCSimRootOptions.hh" +#include "G4ThreeVector.hh" + class WCSimDetectorConstruction; class G4ParticleGun; @@ -28,6 +30,9 @@ class G4Event; class WCSimPrimaryGeneratorMessenger; class G4Generator; +class WCSimAmBePrimaryReader; + + class WCSimPrimaryGeneratorAction : public G4VUserPrimaryGeneratorAction { public: @@ -78,6 +83,12 @@ public: void SaveOptionsToOutput(WCSimRootOptions * wcopt); + + // For AmBe source sim + G4bool OpenAmBePrimaryFile(const G4String& fileName); + void SetAmBePositionOffset(const G4ThreeVector& v) { amBePositionOffset = v; } + G4ThreeVector GetAmBePositionOffset() const { return amBePositionOffset; } + private: WCSimDetectorConstruction* myDetector; G4ParticleGun* particleGun; @@ -140,7 +151,12 @@ private: G4String neutrinosDirectory; G4bool loadNewPrimaries; G4int primariesoffset; - + + // AmBe external ROOT-input mode + G4bool useAmBeRootInput; + G4String amBeInputFileName; + WCSimAmBePrimaryReader* amBeReader; + G4ThreeVector amBePositionOffset; public: inline void SetMulineEvtGenerator(G4bool choice) { useMulineEvt = choice; } @@ -159,6 +175,12 @@ public: inline void SetGPSEvtGenerator(G4bool choice) { useGPSEvt = choice; } inline G4bool IsUsingGPSEvtGenerator() { return useGPSEvt; } + inline void SetAmBeRootGenerator(G4bool choice) { useAmBeRootInput = choice; } + inline G4bool IsUsingAmBeRootGenerator() const { return useAmBeRootInput; } + + inline void SetAmBeInputFileName(const G4String& fileName) { amBeInputFileName = fileName; } + inline G4String GetAmBeInputFileName() const { return amBeInputFileName; } + inline void OpenVectorFile(G4String fileName) { if ( inputFile.is_open() ) diff --git a/include/WCSimPrimaryGeneratorMessenger.hh b/include/WCSimPrimaryGeneratorMessenger.hh index e245a9e60..a2e4bfc82 100644 --- a/include/WCSimPrimaryGeneratorMessenger.hh +++ b/include/WCSimPrimaryGeneratorMessenger.hh @@ -5,6 +5,7 @@ class WCSimPrimaryGeneratorAction; class G4UIdirectory; class G4UIcmdWithAString; class G4UIcmdWithAnInteger; +class G4UIcmdWith3VectorAndUnit; #include "G4UImessenger.hh" #include "globals.hh" @@ -29,6 +30,10 @@ class WCSimPrimaryGeneratorMessenger: public G4UImessenger G4UIcmdWithAString* primariesfileDirectoryCmd; G4UIcmdWithAString* neutrinosfileDirectoryCmd; G4UIcmdWithAnInteger* primariesStartEventCmd; + + // For AmBe simulation + G4UIcmdWithAString* ambeFileCmd; + G4UIcmdWith3VectorAndUnit* ambeOffsetCmd; }; diff --git a/src/WCSimPrimaryGeneratorAction.cc b/src/WCSimPrimaryGeneratorAction.cc index d326ba13b..278e2316f 100644 --- a/src/WCSimPrimaryGeneratorAction.cc +++ b/src/WCSimPrimaryGeneratorAction.cc @@ -24,6 +24,8 @@ #include #include +#include "WCSimAmBePrimaryReader.hh" // For AmBe simulation + #include "G4Navigator.hh" #include "G4TransportationManager.hh" #include "G4UImanager.hh" @@ -64,7 +66,8 @@ inline int atoi( const string& s ) {return std::atoi( s.c_str() );} WCSimPrimaryGeneratorAction::WCSimPrimaryGeneratorAction( WCSimDetectorConstruction* myDC) - :myDetector(myDC), loadNewPrimaries(true), inputdata(0), primariesDirectory(""), neutrinosDirectory(""), vectorFileName("") + :myDetector(myDC), loadNewPrimaries(true), inputdata(0), primariesDirectory(""), neutrinosDirectory(""), vectorFileName(""),useAmBeRootInput(false), +amBeInputFileName(""), amBePositionOffset(0.,0.,0.) { //T. Akiri: Initialize GPS to allow for the laser use MyGPS = new G4GeneralParticleSource(); @@ -134,6 +137,12 @@ WCSimPrimaryGeneratorAction::~WCSimPrimaryGeneratorAction() } } + + if (amBeReader) { + delete amBeReader; + amBeReader = 0; +} + } void WCSimPrimaryGeneratorAction::GeneratePrimaries(G4Event* anEvent) @@ -883,6 +892,87 @@ void WCSimPrimaryGeneratorAction::GeneratePrimaries(G4Event* anEvent) } } } + + + else if (useAmBeRootInput){ + if (!amBeReader) { + G4Exception("WCSimPrimaryGeneratorAction::GeneratePrimaries", + "AmBeReaderMissing", + FatalException, + "AmBe ROOT input mode is enabled, but no reader is available."); + return; + } + + WCSimAmBeEvent inputEvent; + if (!amBeReader->NextEvent(inputEvent)) { + G4Exception("WCSimPrimaryGeneratorAction::GeneratePrimaries", + "AmBeEndOfFile", + RunMustBeAborted, + "No more events in AmBe ROOT input file."); + return; + } + + G4cout << "WCSim AmBe input: reader entry " << amBeReader->GetCurrentEntry() - 1 + << ", EventId " << inputEvent.event_id + << ", N particles " << inputEvent.particles.size() + << G4endl; + + for (std::size_t i = 0; i < inputEvent.particles.size(); ++i) { + const WCSimAmBeParticle& p = inputEvent.particles[i]; + G4ThreeVector localPos( + p.position.X() * cm, + p.position.Y() * cm, + p.position.Z() * cm + ); + + G4ThreeVector globalPos = localPos + amBePositionOffset; + + G4PrimaryVertex* vertex = new G4PrimaryVertex( + globalPos, + p.position.T() * ns + ); + G4double t = p.position.T() * CLHEP::ns; + + + // DEBUG MESSAGE + G4cout << "[AmBe DEBUG] Particle " << i + << " PDG=" << p.pdg + << " proc=" << p.process + << G4endl; + + G4cout << " pos (cm,ns): (" + << globalPos.x()/cm << ", " + << globalPos.y()/cm << ", " + << globalPos.z()/cm << ", " + << t << ")" + << G4endl; + + G4cout << " mom (MeV): (" + << p.momentum.X() << ", " + << p.momentum.Y() << ", " + << p.momentum.Z() << ", " + << p.momentum.T() << ")" + << G4endl; + + G4ParticleDefinition* particleDef = + G4ParticleTable::GetParticleTable()->FindParticle(p.pdg); + + if (!particleDef) { + G4cout << "Skipping unknown PDG code: " << p.pdg << G4endl; + continue; + } + + G4PrimaryParticle* primary = new G4PrimaryParticle( + particleDef, + p.momentum.X() * CLHEP::MeV, + p.momentum.Y() * CLHEP::MeV, + p.momentum.Z() * CLHEP::MeV + ); + + vertex->SetPrimary(primary); + anEvent->AddPrimaryVertex(vertex); + } + } } void WCSimPrimaryGeneratorAction::SaveOptionsToOutput(WCSimRootOptions * wcopt) @@ -1013,3 +1103,30 @@ void WCSimPrimaryGeneratorAction::LoadNewPrimaries(){ loadNewPrimaries=false; } + +//------------------- For AmBe sim --------------- +G4bool WCSimPrimaryGeneratorAction::OpenAmBePrimaryFile(const G4String& fileName) +{ + if (amBeReader) { + delete amBeReader; + amBeReader = 0; + } + + amBeReader = new WCSimAmBePrimaryReader(); + + if (!amBeReader->Open(fileName, "EmergingParticles")) { + G4cerr << "WCSimPrimaryGeneratorAction::OpenAmBePrimaryFile(): " + << "failed to open file " << fileName << G4endl; + + delete amBeReader; + amBeReader = 0; + return false; + } + + amBeInputFileName = fileName; + + G4cout << "Opened AmBe primary ROOT file: " << amBeInputFileName << G4endl; + G4cout << "Entries available: " << amBeReader->GetEntries() << G4endl; + + return true; +} \ No newline at end of file diff --git a/src/WCSimPrimaryGeneratorMessenger.cc b/src/WCSimPrimaryGeneratorMessenger.cc index 621eca679..ac2620ebc 100644 --- a/src/WCSimPrimaryGeneratorMessenger.cc +++ b/src/WCSimPrimaryGeneratorMessenger.cc @@ -4,6 +4,9 @@ #include "G4UIcmdWithAString.hh" #include "G4UIcmdWithAnInteger.hh" #include "G4ios.hh" +#include "G4UIcmdWith3VectorAndUnit.hh" +#include "G4ThreeVector.hh" +#include "G4SystemOfUnits.hh" WCSimPrimaryGeneratorMessenger::WCSimPrimaryGeneratorMessenger(WCSimPrimaryGeneratorAction* pointerToAction) :myAction(pointerToAction) @@ -14,11 +17,11 @@ WCSimPrimaryGeneratorMessenger::WCSimPrimaryGeneratorMessenger(WCSimPrimaryGener genCmd = new G4UIcmdWithAString("/mygen/generator",this); genCmd->SetGuidance("Select primary generator."); //T. Akiri: Addition of laser - genCmd->SetGuidance(" Available generators : muline, gun, laser, gps, beam"); + genCmd->SetGuidance("Select generator type: muline, gun, laser, gps, beam, AmBe"); genCmd->SetParameterName("generator",true); genCmd->SetDefaultValue("beam"); // previously muline //T. Akiri: Addition of laser - genCmd->SetCandidates("muline gun laser gps beam"); + genCmd->SetCandidates("muline gun laser gps beam AmBe"); fileNameCmd = new G4UIcmdWithAString("/mygen/vecfile",this); fileNameCmd->SetGuidance("Select the file of vectors."); @@ -40,6 +43,19 @@ WCSimPrimaryGeneratorMessenger::WCSimPrimaryGeneratorMessenger(WCSimPrimaryGener primariesStartEventCmd->SetGuidance("The starting entry number for reading primaries"); primariesStartEventCmd->SetParameterName("primariesoffset",true); primariesStartEventCmd->SetDefaultValue(0); + + // For AmBe sim + ambeFileCmd = new G4UIcmdWithAString("/mygen/AmBefile", this); + ambeFileCmd->SetGuidance("Set the input ROOT file for the AmBe external primary generator."); + ambeFileCmd->SetParameterName("AmBefile", false); + ambeFileCmd->AvailableForStates(G4State_PreInit, G4State_Idle); + + ambeOffsetCmd = new G4UIcmdWith3VectorAndUnit("/mygen/ambeoffset", this); + ambeOffsetCmd->SetGuidance("Set the translation offset for AmBe input positions."); + ambeOffsetCmd->SetGuidance("This shifts the ROOT-file particle vertices into detector coordinates."); + ambeOffsetCmd->SetParameterName("X", "Y", "Z", false); + ambeOffsetCmd->SetDefaultUnit("cm"); + ambeOffsetCmd->AvailableForStates(G4State_PreInit, G4State_Idle); } WCSimPrimaryGeneratorMessenger::~WCSimPrimaryGeneratorMessenger() @@ -50,6 +66,8 @@ WCSimPrimaryGeneratorMessenger::~WCSimPrimaryGeneratorMessenger() delete neutrinosfileDirectoryCmd; delete mydetDirectory; delete primariesStartEventCmd; + delete ambeFileCmd; + delete ambeOffsetCmd; } void WCSimPrimaryGeneratorMessenger::SetNewValue(G4UIcommand * command,G4String newValue) @@ -101,6 +119,20 @@ void WCSimPrimaryGeneratorMessenger::SetNewValue(G4UIcommand * command,G4String myAction->SetBeamEvtGenerator(false); myAction->SetGPSEvtGenerator(true); } + + else if (newValue == "AmBe") { + myAction->SetAmBeRootGenerator(true); + + // Existing messenger likely already turns the others off here. + // Keep that same pattern, for example: + myAction->SetMulineEvtGenerator(false); + myAction->SetGunEvtGenerator(false); + myAction->SetLaserEvtGenerator(false); + myAction->SetGPSEvtGenerator(false); + myAction->SetBeamEvtGenerator(false); + + G4cout << "Primary generator set to external AmBe ROOT input." << G4endl; + } } if( command == fileNameCmd ) @@ -128,6 +160,26 @@ void WCSimPrimaryGeneratorMessenger::SetNewValue(G4UIcommand * command,G4String G4cout << "Primary files will be read starting from entry "<SetAmBeInputFileName(newValue); + + if (!myAction->OpenAmBePrimaryFile(newValue)) { + G4cerr << "Failed to open AmBe input ROOT file: " << newValue << G4endl; + } + else { + G4cout << "Configured AmBe input ROOT file: " << newValue << G4endl; + } + } + + if (command == ambeOffsetCmd) { + G4ThreeVector offset = ambeOffsetCmd->GetNew3VectorValue(newValue); + myAction->SetAmBePositionOffset(offset); + G4cout << "Set AmBe position offset to " + << offset.x()/cm << " " + << offset.y()/cm << " " + << offset.z()/cm << " cm" + << G4endl; + } } G4String WCSimPrimaryGeneratorMessenger::GetCurrentValue(G4UIcommand* command)