18.5. Writing Output Files
Table of Contents
ROOT output
Geant4 provides built‑in support for writing analysis results to ROOT files through G4AnalysisManager. Once you have created histograms and ntuples earlier in your code, the output step is mainly about choosing the file name, opening the file before the run, and closing it properly at the end.
You normally obtain the singleton analysis manager with
auto analysisManager = G4AnalysisManager::Instance(); in your user action classes. To enable ROOT output, you either build Geant4 with ROOT support or link your application to the ROOT analysis backend that came with your Geant4 installation. For a beginner, this usually only means using the standard Geant4 build from your system, which already has ROOT analysis enabled.
Before any events are simulated, typically in RunAction::BeginOfRunAction, you open the output file. You do not specify the extension, only the base name. The analysis manager automatically adds .root.
Rule: Always call
analysisManager->OpenFile("myOutput");
before filling histograms or ntuples, and always call
analysisManager->Write(); followed by analysisManager->CloseFile();
exactly once at the end of the run.
A minimal pattern in your run action looks like:
void RunAction::BeginOfRunAction(const G4Run*)
{
auto analysisManager = G4AnalysisManager::Instance();
analysisManager->OpenFile("output"); // creates "output.root"
}
void RunAction::EndOfRunAction(const G4Run*)
{
auto analysisManager = G4AnalysisManager::Instance();
analysisManager->Write(); // writes all histograms and ntuples
analysisManager->CloseFile(); // closes "output.root"
}
The file name you pass to OpenFile controls the final ROOT file name. If you want to organize multiple runs, you can change this name using macro commands, for example /analysis/setFileName run1, and then call OpenFile() without arguments. This lets you run parameter scans without recompiling.
The table below summarizes the essential ROOT output functions:
| Function | Purpose |
|---|---|
OpenFile("name") | Create and open name.root for output |
SetFileName("name") | Set base name, used if OpenFile() called with no argument |
Write() | Write all booked histograms and ntuples |
CloseFile() | Close the current ROOT file |
If you use multithreading, G4AnalysisManager internally merges the per‑thread histograms and ntuples when you call Write(). You do not need to implement any manual merging for standard use cases, but you must still ensure that Write() and CloseFile() are called only in the master thread, which is exactly what happens if you place them in the run action provided by ActionInitialization.
When you later open the ROOT file in the ROOT environment, you will find your histograms as TH1 objects and your ntuples as TTree objects, with names and titles that match those you set when creating them. This link between Geant4 output and ROOT analysis is the basis for the later chapters that focus on data analysis with ROOT.
CSV output
Besides ROOT, Geant4 can write analysis results to plain text formats, such as CSV. This is useful if you want to inspect results quickly, use spreadsheet software, or run simple scripts in Python, MATLAB, or similar tools without relying on ROOT.
To use CSV output, you select the CSV analysis backend, usually by a macro command at runtime. For a beginner, the most practical approach is to control the output format entirely from macros, without changing your C++ code. The analysis manager interface stays the same, only the backend changes.
In a macro file, you can set the output type to CSV and define the base file name:
/analysis/setFileName results
/analysis/setFileType csv
/analysis/openFile
This creates one or more .csv files instead of a .root file. The exact naming pattern depends on what you have defined. Commonly, each histogram or ntuple is written into its own CSV file, or ntuples are written with one row per entry and one column per ntuple column.
Rule: When using CSV output, you still must open the file with /analysis/openFile (or OpenFile() in C++) before filling data, and you must call Write() and CloseFile() at the end of the run, exactly as for ROOT.
In C++, the pattern is identical to the ROOT case, because G4AnalysisManager hides the backend details:
void RunAction::BeginOfRunAction(const G4Run*)
{
auto analysisManager = G4AnalysisManager::Instance();
// Name and type may be set from a macro
analysisManager->OpenFile(); // uses name and type already configured
}
void RunAction::EndOfRunAction(const G4Run*)
{
auto analysisManager = G4AnalysisManager::Instance();
analysisManager->Write();
analysisManager->CloseFile();
}A typical CSV file created from an ntuple has a header line with column names, followed by one line per row:
Edep, x, y, z
0.532, 0.0, 0.0, 5.0
1.247, 0.1, -0.2, 4.8
...This can be read directly by many tools. For instance, in Python with NumPy you can use:
import numpy as np
data = np.genfromtxt("results_ntuple0.csv", delimiter=",", names=True)For quick checks and for users unfamiliar with ROOT, CSV output is often the simplest way to get from a Geant4 simulation to basic plots or tables. ROOT output remains more powerful for large simulations and complex analyses, but CSV provides a very accessible alternative while using exactly the same analysis manager interface in your Geant4 code.
Views: 7
KAHIBARO