HI @mkelsey,
According to what you suggest, and I followed some guideline on the internet, I have replaced the ROOT stuff (mostly) in the runcation file and my own defined recorder file with the G4AnalysisManager class.
#include "MyRecorder.hh"
#include "MyRecorderMessenger.hh"
#include "G4RootAnalysisManager.hh"
#include "G4Run.hh"
#include "G4Event.hh"
#include "G4Step.hh"
#include "G4ParticleGun.hh"
#include "G4VProcess.hh"
#include "G4ThreeVector.hh"
#include "G4GeneralParticleSource.hh"
#include "G4RunManager.hh"
#include "G4AnalysisManager.hh" //added
#include "G4UnitsTable.hh"
#include "G4SystemOfUnits.hh"
#include "G4ParticleDefinition.hh"
#include "G4ParticleTypes.hh"
#include "G4Track.hh"
#include "G4Threading.hh"
#include <iostream>
#include <fstream>
MyRecorder::MyRecorder()
{
rootFileName = "unknownFile.root";
recMessenger = new MyRecorderMessenger(this);
}
namespace {
G4Mutex rootFileMutex = G4MUTEX_INITIALIZER;
} //added
MyRecorder::~MyRecorder()
{
//delete rootFile;
delete recMessenger;
}
void MyRecorder::BeginOfRecordingRun(const G4Run *aRun)
{
G4cout << "### Run " << aRun->GetRunID() << " start." << G4endl;
G4cout << "Create ROOT file to record data ......" << G4endl;
auto analysisManager = G4AnalysisManager::Instance();
analysisManager->SetVerboseLevel(1);
analysisManager->SetNtupleMerging(true); // Enable merging in MT mode
analysisManager->OpenFile(rootFileName);
// Define your output ntuple structure
analysisManager->CreateNtuple("Data", "Simulation Data");
analysisManager->CreateNtupleIColumn("idevt");
analysisManager->CreateNtupleDColumn("Et_1");
analysisManager->CreateNtupleDColumn("Et_2");
analysisManager->CreateNtupleDColumn("Et_3");
analysisManager->CreateNtupleDColumn("Et_4");
analysisManager->CreateNtupleDColumn("Et_5");
analysisManager->CreateNtupleDColumn("Et_6");
analysisManager->CreateNtupleDColumn("Et_7");
analysisManager->CreateNtupleDColumn("x0");
analysisManager->CreateNtupleDColumn("y0");
analysisManager->CreateNtupleDColumn("z0");
analysisManager->CreateNtupleDColumn("x1");
analysisManager->CreateNtupleDColumn("y1");
analysisManager->CreateNtupleDColumn("z1");
analysisManager->CreateNtupleDColumn("x2");
analysisManager->CreateNtupleDColumn("y2");
analysisManager->CreateNtupleDColumn("z2");
analysisManager->FinishNtuple();
}
void MyRecorder::BeginOfRecordingEvent(const G4Event *aEvent)
{
ResetAllMembers();
idevt = aEvent->GetEventID();
totalEnergyDep = 0.;
}
void MyRecorder::EndOfRecordingEvent(const G4Event *aEvent)
{
auto analysisManager = G4AnalysisManager::Instance();
analysisManager->FillNtupleIColumn(0, idevt);
analysisManager->FillNtupleDColumn(1, Et_1);
analysisManager->FillNtupleDColumn(2, Et_2);
analysisManager->FillNtupleDColumn(3, Et_3);
analysisManager->FillNtupleDColumn(4, Et_4);
analysisManager->FillNtupleDColumn(5, Et_5);
analysisManager->FillNtupleDColumn(6, Et_6);
analysisManager->FillNtupleDColumn(7, Et_7);
analysisManager->FillNtupleDColumn(8, x0);
analysisManager->FillNtupleDColumn(9, y0);
analysisManager->FillNtupleDColumn(10, z0);
analysisManager->FillNtupleDColumn(11, x1);
analysisManager->FillNtupleDColumn(12, y1);
analysisManager->FillNtupleDColumn(13, z1);
analysisManager->FillNtupleDColumn(14, x2);
analysisManager->FillNtupleDColumn(15, y2);
analysisManager->FillNtupleDColumn(16, z2);
//G4double energyDep = 0.;
analysisManager->AddNtupleRow();
}
void MyRecorder::BeginOfRecordingStep(const G4Step *aStep)
{
G4double edep = aStep->GetTotalEnergyDeposit();
if (edep <= 0.0) return;
totalEnergyDep += edep;
G4StepPoint* preStep = aStep->GetPreStepPoint();
G4String volumeName = preStep->GetTouchableHandle()->GetVolume()->GetName();
if (volumeName == "phy_1") Et_1 += edep;
else if (volumeName == "phy_2") Et_2 += edep;
else if (volumeName == "phy_3") Et_3 += edep;
else if (volumeName == "phy_4") Et_4 += edep;
else if (volumeName == "phy_5") Et_5 += edep;
else if (volumeName == "phy_6") Et_6 += edep;
else if (volumeName == "phy_7") Et_7 += edep;
...
}
void MyRecorder::EndOfRecordingRun(const G4Run *aRun)
{
G4cout << "### Run " << aRun->GetRunID() << " end." << G4endl;
auto analysisManager = G4AnalysisManager::Instance();
analysisManager->Write();
analysisManager->CloseFile();
}
void MyRecorder::SetFileName(const G4String &fName)
{
rootFileName = fName;
}
Fortunately, the simulation start recording events; however, Im not sure if the following messages show recording is complete or not..
G4WT0 >
event: 9997000
G4WT1 >
event: 9999000
G4WT0 > ### Run 0 end.
G4WT1 > ### Run 0 end.
### Run 0 end.
... write file : 20250715_50x50_GeDet_withInnerShielding_Xe135_Uniform_10M.root - done
... close file : 20250715_50x50_GeDet_withInnerShielding_Xe135_Uniform_10M.root - done
Graphics systems deleted.
Visualization Manager deleting...
*** Break *** segmentation violation
[/usr/lib/system/libsystem_platform.dylib] _sigtramp (no debug info)
[<unknown binary>] (no debug info)
[/usr/lib/system/libsystem_c.dylib] __cxa_finalize_ranges (no debug info)
[/usr/lib/system/libsystem_c.dylib] exit (no debug info)
[/usr/lib/system/libdyld.dylib] dyld4::LibSystemHelpers::getenv(char const*) const (no debug info)
[/usr/lib/dyld] start (no debug info)
Non-critical error: mutex lock failure in ~G4Cache<P15G4HadFinalState>.
If the RunManagerKernel has been deleted, it failed to delete an allocated resource
and this destructor is being called after the statics were destroyed.
Exception: [code: system:22] caught: mutex lock failed: Invalid argument
Non-critical error: mutex lock failure in ~G4Cache<P15G4HadFinalState>.
If the RunManagerKernel has been deleted, it failed to delete an allocated resource
and this destructor is being called after the statics were destroyed.
Exception: [code: system:22] caught: mutex lock failed: Invalid argument
thanks!