Errors keep showing when generating events

Dear all experts,
I am trying to run my simulation to generate events and record in the root file, but this error is always showing…
My mentor provided me the source codes, including main.cc file, DetectorConstruction, PrimaryGeneratorAction, Recorder, and so on.
But she was using an old Geant4 version 10.05 and I am very new to Geant4, I was wonder if these errors are caused because of the gap of Geant4 versions, like some header files of Geant4 classes are different, new, or removed in my source codes.

Please guide me to figure it out, thanks for helping :sob:

### Run 0 starts.
### Run 0 start.
Create ROOT file to record data ......
G4WT4 > ### Run 0 starts on worker thread 4.
G4WT3 > ### Run 0 starts on worker thread 3.
G4WT7 > ### Run 0 starts on worker thread 7.
G4WT5 > ### Run 0 starts on worker thread 5.
G4WT5 > ### Run 0 start.
G4WT2 > ### Run 0 starts on worker thread 2.
G4WT5 > Create ROOT file to record data ......
G4WT1 > ### Run 0 starts on worker thread 1.
G4WT4 > ### Run 0 start.
G4WT4 > Create ROOT file to record data ......
G4WT3 > ### Run 0 start.
G4WT7 > ### Run 0 start.
G4WT7 > Create ROOT file to record data ......
G4WT6 > ### Run 0 starts on worker thread 6.
G4WT6 > ### Run 0 start.
G4WT6 > Create ROOT file to record data ......
G4WT1 > ### Run 0 start.
G4WT1 > Create ROOT file to record data ......
G4WT2 > ### Run 0 start.
sim(62396,0x16d4b3000) malloc: *** error for object 0x60000344a600: pointer being freed was not allocated
G4WT0 > ### Run 0 starts on worker thread 0.
sim(62396,0x16d4b3000) malloc: *** set a breakpoint in malloc_error_break to debug
G4WT2 > Create ROOT file to record data ......
G4WT3 > Create ROOT file to record data ......
G4WT0 > ### Run 0 start.
G4WT0 > Create ROOT file to record data ......
G4WT5 > --> Event 0 starts with initial seeds (15470735,58711377).
G4WT5 > 
 event: 0

Geant4 Version: 11.3.0
Operating System: macOS Sonoma 14.7.6
Compiler/Version: Apple clang Xcode 16.2
CMake Version: 4.0.3
ROOT Version: 6.36.00


That’s mostly normal “start of run” output. Each of the lines beginning "G4WT_ > " is from one of your eight worker threads (0 to 7). It looks like you’re creating a separate ROOT file for each thread, is that your intention? If it’s not what you had in mind, you will need to do some reworking of the code.

If you’re using ROOT directly (e.g., you have TFIle.hh, TTree.hh, etc. in your code) you might want to investigate whether switching to G4analysis would help. Geant4 can write out ROOT I/O formatted files, without using any ROOT code directly.

Hi @mkelsey,
Creating different root files for each thread was not my intention. my plan is to create one root file that contains different branches by setting tr = new TTree() and each tr->Branch() points to the total energy deposition of different part of the Detector Geometry, and yes I’ve set to create 8 branches in my recorder.cc file.
below is the begin of recording run in my recorder.cc file

Project_Recorder::Project_Recorder()
{
  rootFileName = "unknownFile.root";
  recMessenger = new  Project_RecorderMessenger(this);
}

namespace {
  G4Mutex rootFileMutex = G4MUTEX_INITIALIZER;
} //added

Project_Recorder::~KSNaIGe_Recorder()
{
  delete rootFile;
  delete recMessenger;
}

void Project_Recorder::BeginOfRecordingRun(const G4Run *aRun)
{
  G4cout << "### Run " << aRun->GetRunID() << " start." << G4endl;
  G4cout << "Create ROOT file to record data ......" << G4endl;

  #ifdef G4MULTITHREADED
 
  if (G4Threading::IsMasterThread()) {
    rootFile = new TFile(rootFileName, "RECREATE");
    }
  #else
  rootFile = new TFile(rootFileName, "RECREATE");
  #endif
  
    if (rootFile->IsZombie()) {

      G4cout << "Error opening file." << G4endl;
      exit(-1);
    }
    else
    {
      tr = new TTree("tr", "spec Simulation");

      tr->Branch("idevt",    &idevt,    "idevt/I");

      
      tr->Branch("Et_1",       &Et_1,       "Et_1/D");
      tr->Branch("Et_2",       &Et_2,       "Et_2/D");
      tr->Branch("Et_3",         &Et_3,         "Et_3/D");
      tr->Branch("Et_4",         &Et_4,         "Et_4/D");
      tr->Branch("Et_5",             &Et_5,          "Et_5/D");
      tr->Branch("Et_6",         &Et_6,         "Et_6/D");
      tr->Branch("Et_7",    &Et_7,    "Et_7/D");
     
      tr->Branch("x0",    &x0,    "x0/D");
      tr->Branch("y0",    &y0,    "y0/D");
      tr->Branch("z0",    &z0,    "z0/D");

      tr->Branch("x1",    &x1,    "x1/D");
      tr->Branch("y1",    &y1,    "y1/D");
      tr->Branch("z1",    &z1,    "z1/D");
      
      tr->Branch("x2",    &x2,    "x2/D");
      tr->Branch("y2",    &y2,    "y2/D");
      tr->Branch("z2",    &z2,    "z2/D");

    }
  

and those are the classes’ header file I use in the same recorder.cc file

#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 "G4AutoLock.hh" // added

#include <iostream>
#include <fstream>

is there any problem with my current code?

and this is the run.in file I use, and the command after making executable file is ./sim run.in

/run/initialize
#/tracking/verbose 2


/Project/RecMsg/SetFileName Uniform_1M.root

/run/printProgress 10000
/run/beamOn 1000000

Not sure where to change or it’s good

The problem is that ROOT is not thread-safe. You’re right to just create the one file on the master thread, but then you create individual TTrees and TBranches in each of the worker threads. Those collide with one another (called a “data race”) and mess up both the file and the pointers in memory.

Making this work will involve turning your Recorder into a singleton object, with mutexes to protect calls from different threads. Unless you’re experienced with multithreaded programming already, I wouldn’t recommend it.

Since your TTree is very simple (just a bunch of doubles), I would recommend looking at replacing all of the ROOT stuff with G4analysis, writing the output in “ROOT I/O” format. Then you’ll be able to read it back in using ROOT, just as you are now.

Thanks @mkelsey , I will look at it and see what I can do! Btw, I’m not very clear with what you said about replacing “all” the ROOT stuff with G4analysis… which part is the ROOT stuff you mean specifically? and Is there any module I can take as an reference for g4 analysis?

Many (most?) of the examples use G4analysis, and several dozen use it to produce ROOT-format output. For your purposes, basic/B5 should be sufficient. For the complete set of all examples, try this in your terminal:

$ cd <my-geant4>/examples
$ find . -name '*.cc' | xargs grep analysis | grep root | cut -f1 -d:

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!

It looks like your output files did get closed successfully, That segfault and traceback come after the “file closed” message, which is good, but seem related to the hadronics part of your physics list. I’m not familiar enough with those internals (I worked on G4 hadronics before the multithreading support, G4Cache, etc., were deployed) to give you advice.

It might be worth posting that last error as a new topic under “Physics processes.”

1 Like

I see, I will try posting this error under that category.
Thanks!

Btw, these are the error messages as well:

Non-critical error: mutex lock failure in ~G4Cache<N26G4ParticleHPContAngularPar10toBeCachedE>. 
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<PNSt3__16vectorIiNS_9allocatorIiEEEE>. 
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<N26G4VParticleHPEnergyAngular10toBeCachedE>. 
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

Please, see thread #12772.
This issue is not yet resolved, pending a revision of the HP code. The warning message is harmless.