How to save histograms/ntuples for several consecutive Runs

_Geant4 Version:_11.3.0
_Operating System:_Windows
_Compiler/Version:_VS2022
CMake Version:

Hello all,

In my application I would like to change world/detector geometry between runs and save histograms and ntuples as CSV files with unique names based on RunID for each run. And I use MT to reduce computation time.

In reality I see that G4 creates ntuples for Master and Workers threads as expected and it just removes empty ntuple for Master after end of the run. But for histograms the situation quite different!
Geant4 create histograms only once with RunID = 0 and after that it ignores OpenFile() with a new name and overwrites existing histograms for each new run.

Is it possible to save histograms and ntuples with unique names for multiple consecutive runs???

Vyacheslav

P.S. Just for example few peaces of my code…

in main.cpp
{
...
	  UI->ApplyCommand("/control/execute input.mac");
	  for(int i = nStartID; i<dDepth.size(); i++)
	  {
		  G4ThreeVector pos(0., 0., dDepth[i] * CLHEP::cm);
		  det->SetSensorPosition(pos);
		  det->UpdateGeometry();
		  runManager->BeamOn(10000);
	  }
...
}

in RunAction …

RunAction::RunAction() : G4UserRunAction()
{
...
   auto man = G4AnalysisManager::Instance();
   man->SetVerboseLevel(1);
   G4cout << "Using " << man->GetType() << G4endl;
   man->SetNtupleDirectoryName("tuples");
   man->SetHistoDirectoryName("hists");
...
//Define histograms and tuples
...
}






void RunAction::BeginOfRunAction(const G4Run* aRun)
{
G4cout << “RunAction::BeginOfRunAction. Run " << aRun->GetRunID() << " start.” << G4endl;

auto man = G4AnalysisManager::Instance();

//set file format
std::stringstream stm("");
stm << "RUN" << std::setw(5) << std::setfill('0') << aRun->GetRunID();
man->OpenFile(stm.str());

if (!IsMaster()) //it is a slave, do nothing else
{
    G4cout << "ooo Run " << aRun->GetRunID() << " starts on slave." << G4endl;
    return;
}
else //Master or sequential
{
    G4cout << "ooo Run " << aRun->GetRunID() << " starts (global)." << G4endl;

    if (seed < 0) //not initialized by anybody else
    {
        seed = (G4long)time(0);
        G4Random::setTheSeed(seed, luxury);
        G4Random::showEngineStatus();
    }
}

}

void RunAction::EndOfRunAction(const G4Run* aRun)
{
G4cout << "RunAction::EndOfRunAction. number of event = " << aRun->GetNumberOfEvent() << G4endl;

auto man = G4AnalysisManager::Instance();
// Save histograms
man->Write();
man->CloseFile();

if (!IsMaster())
{
    G4cout << "### Run " << aRun->GetRunID() << " (slave) ended." << G4endl;
}
else
{
    G4cout << "### Run " << aRun->GetRunID() << " (global) ended." << G4endl;
}

}

Yes, please, take a look in the Geant4 extended analysis/AnaEx03 example.

and also related documentation

Best regards,

Yes, you are right - AnaEx03 works fine, but it uses hard-coded output file names “e-”, “proton” only.

In my case, I make many consecutive Runs in cycle and a file name generation using “GetRunID()” is the simplest solution. Unfortunately, it not works correctly for histograms. It is definitely some bug in code “GetRunID”, because when I use stupid solution in my code with private static variable, all works fine!

I was just hoping to hear that maybe there is another explanation for this effect.

My stupid solution:


class RunAction : public G4UserRunAction
{
...
    static G4int nGloabalID;
...
}
 
and in *.cc file:

G4int RunAction:: nGloabalID = 0;

void RunAction::BeginOfRunAction(const G4Run* aRun)
{
 ...
    //set file format
    std::stringstream stm("");
    stm << "RUN" << std::setw(5) << std::setfill('0') << nGloabalID;
    man->OpenFile(stm.str());
...
}


void RunAction::EndOfRunAction(const G4Run* aRun)
{
    G4cout << "RunAction::EndOfRunAction. number of event = " << aRun->GetNumberOfEvent() << G4endl;

    auto man = G4AnalysisManager::Instance();
    // Save histograms
    man->Write();
    man->CloseFile();

    if (!IsMaster())
    {
        G4cout << "### Run " << aRun->GetRunID() << " (slave) ended." << G4endl;
    }
    else
    {
        G4cout << "### Run " << aRun->GetRunID() << " (global) ended." << G4endl;
        //Increment RUNID for master only
        nGloabalID++;
    }
}

By default, histograms are created only once, at the first run, and they are reset with each CloseFile call. It is possible to disable this resetting histograms with calling CloseFile with false argument. Then the content of the histograms will be preserved.

In my case, I make many consecutive Runs in cycle and a file name generation using “GetRunID()” is the simplest solution. Unfortunately, it not works correctly for histograms.

GetRunID() has nothing to do with histograms and if used in RunAction::BeginOfRunAction, it should work. Could you give more details why you find it failing on your side ? (Eg. post your output)

And also, which version of Geant4 do you use ? Thank you.

I have found the reason of my troubles.

This code works correctly:

int main(int argc,char** argv)
{
...
  auto* runManager = G4RunManagerFactory::CreateRunManager();  
...

but in my application I used another constructor:

...
  auto* runManager = G4RunManagerFactory::CreateRunManager(G4RunManagerType::MT);
...

and it was a reason my troubles.

just for illustration how it looks: green arrows correct behavior, the red ones - incorrect


I cannot reproduce this (GetRunID) failure with the current version of Geant4. Can you, please, reply my question what is your Geant4 version?