18.6 Closing Analysis Files
Table of Contents
Writing data
In a Geant4 application the G4AnalysisManager buffers your histograms and ntuples in memory during the run. Nothing is written to disk until you explicitly tell the analysis manager to write and then close the output. For a beginner project this is usually done in RunAction, at the end of the run.
The typical pattern is:
- Create and configure
G4AnalysisManagerinRunActionconstructor. - Open the output file at the beginning of the run.
- Fill histograms and ntuples during events and steps.
- Write and close the file at the end of the run.
A minimal example in RunAction might look like this:
#include "RunAction.hh"
#include "G4AnalysisManager.hh"
#include "G4Run.hh"
RunAction::RunAction() {
auto analysisManager = G4AnalysisManager::Instance();
analysisManager->SetVerboseLevel(1);
analysisManager->SetFileName("output");
// Example: create a histogram and an ntuple
analysisManager->CreateH1("Edep", "Energy deposition", 100, 0., 10.*MeV);
analysisManager->CreateNtuple("ntuple", "Event data");
analysisManager->CreateNtupleDColumn("Edep");
analysisManager->FinishNtuple();
}
void RunAction::BeginOfRunAction(const G4Run*) {
auto analysisManager = G4AnalysisManager::Instance();
analysisManager->OpenFile(); // uses the name "output"
}
The actual writing to disk is separated from filling the data. Geant4 collects the filled values in memory, then Write() transfers them into the output backend, for example a ROOT file, CSV files, or other formats depending on your configuration.
You usually call Write() at the end of the run:
void RunAction::EndOfRunAction(const G4Run*) {
auto analysisManager = G4AnalysisManager::Instance();
// Flush in‑memory histograms and ntuples into the file
analysisManager->Write();
// Close file and cleanup
analysisManager->CloseFile();
}
When you use multithreading, Geant4 handles merging per thread internally if you use G4AnalysisManager. You still call Write() only once in the master thread, typically from EndOfRunAction that runs on the master. The analysis manager performs the collection of data from all worker threads before writing.
If you change the output file name between runs, you should set the file name before the OpenFile() call for each run, for example from a macro command that changes the name, or by calling SetFileName() in BeginOfRunAction before OpenFile().
Always call analysisManager->Write() before analysisManager->CloseFile(). If you forget Write(), your histograms and ntuples may not be stored correctly, even though the file is created.
For ROOT output, Write() ensures that histograms and ntuples become proper ROOT objects in the file. For CSV output, Write() creates and fills the .csv text files that correspond to your histograms and ntuples. In both cases, CloseFile() then finalizes and closes the underlying files.
Closing files correctly
Closing analysis files correctly is essential to avoid corrupted or incomplete output. The sequence inside EndOfRunAction should always be:
void RunAction::EndOfRunAction(const G4Run*) {
auto analysisManager = G4AnalysisManager::Instance();
analysisManager->Write(); // 1) write data
analysisManager->CloseFile(); // 2) close file
}
The CloseFile() call ensures that all output buffers are flushed by the backend library, that file headers and footers are written, and that the file is left in a consistent state. This is especially important for ROOT files where an improperly closed file can later appear damaged or unreadable.
You typically create the G4AnalysisManager once and never delete it manually. Geant4 cleans it up at the end of the job. You should not create new instances for each run. Instead, reuse the same singleton instance and only open and close the file at the beginning and end of each run.
In interactive sessions you might run several runs in a row with different configurations. For each run, Geant4 will call:
BeginOfRunAction -> OpenFile()
... events ...
EndOfRunAction -> Write(), CloseFile()
As long as you follow this pattern the output is separated cleanly per run. If you want a new file per run, set a new file name before calling OpenFile() in BeginOfRunAction.
If your application terminates unexpectedly before EndOfRunAction is called, the file may not be properly closed. During debugging, check that your run reaches EndOfRunAction, or manually trigger a write and close from a macro if you have implemented such commands in your code.
Correct order for finishing analysis:
OpenFile()at the start of the run.- Fill histograms and ntuples during the run.
Write()at the end of the run.CloseFile()at the end of the run.
Never callCloseFile()without a matchingOpenFile(), and never expect data to be saved if the run ends beforeWrite()andCloseFile()are executed.
For multithreaded applications, only the master thread should close the file. The standard G4AnalysisManager usage already assumes this, so you should keep your write and close calls in the master RunAction. Worker threads only fill data, they do not open or close files.
When your application exits, do not try to call Write() or CloseFile() from destructors of global objects or static variables. Keep all analysis finalization inside EndOfRunAction or explicit user code that runs before the application finishes. This avoids ordering problems during program shutdown.
By consistently following this pattern you ensure that your Geant4 simulations always produce complete, usable analysis files that can be opened later in ROOT or other tools without trouble.
Views: 8
KAHIBARO