KAHIBARO
Discord Login Register

18.2. Histograms

Creating histograms

In Geant4, histograms are created and managed through the G4AnalysisManager class. For beginners you typically create histograms in your RunAction class, inside the BeginOfRunAction method, after you have obtained the analysis manager instance.

The basic sequence is always the same. First, get the singleton analysis manager:

cpp
auto analysisManager = G4AnalysisManager::Instance();

Then configure output once, usually in your RunAction constructor. You choose a file name, an output type, and optional settings:

cpp
analysisManager->SetVerboseLevel(1);
analysisManager->SetFirstHistoId(0);   // optional, default is 0
analysisManager->OpenFile("output");   // "output.root", "output.csv", etc.

To create a one dimensional histogram you call CreateH1. The minimal arguments are an internal name, a title, the number of bins, and the lower and upper edges of the x axis:

cpp
G4int idEdep =
  analysisManager->CreateH1("Edep",
                            "Energy deposition in detector",
                            100,        // number of bins
                            0.*keV,     // lower edge
                            10.*MeV);   // upper edge

The return value is the histogram ID. You can store this ID in a member variable or use the fact that histograms are numbered sequentially starting from GetFirstHistoId(). For absolute beginners it is often simpler to remember the order and use hard coded IDs like 0, 1, and so on. Later, you can keep IDs in constants or enums for clarity.

You can also create two dimensional histograms with CreateH2, for example to correlate depth and energy deposition:

cpp
G4int idDepthEdep =
  analysisManager->CreateH2("DepthEdep",
                            "Depth vs energy deposition",
                            100, 0.*mm, 200.*mm,   // x axis: depth
                            100, 0.*keV, 10.*MeV); // y axis: energy

The typical arguments to the creation methods are:

MethodPurposeTypical arguments
CreateH11D histogramname, title, nbins, xlow, xup
CreateH22D histogramname, title, nbinx, xlow, xup, nbiny, ylow, yup

You can call CreateH1 or CreateH2 only once per histogram, before the run starts. Do not create histograms inside event or stepping actions for each event or step.

Always create histograms once at initialization time. Do not recreate them during the run or in loops over events.

You finally close the output file in EndOfRunAction:

cpp
analysisManager->Write();
analysisManager->CloseFile();

This ensures that all histogram data are written correctly to disk, for example in a ROOT or CSV file.

Filling histograms

Filling histograms is done while the simulation runs, usually from your user action classes such as EventAction, SteppingAction, or SensitiveDetector. The key rule is that you must always fill with values in Geant4 internal units, not already converted to your preferred output units. The binning range you specified when creating the histogram must use the same units as the values you pass when filling.

To fill a 1D histogram, use FillH1 with the histogram ID and the x value. There is an optional weight argument, which is usually 1.0:

cpp
auto analysisManager = G4AnalysisManager::Instance();
// Example in a SteppingAction, filling deposited energy per step
G4double edep = step->GetTotalEnergyDeposit(); // in internal energy units
analysisManager->FillH1(0, edep);              // 0 is the histogram ID

For a 2D histogram, use FillH2 with the histogram ID, x value, y value, and optional weight:

cpp
// Example: fill depth vs deposited energy
G4double z = postStepPoint->GetPosition().z(); // in internal length units
G4double edep = step->GetTotalEnergyDeposit();
analysisManager->FillH2(0, z, edep);           // 0 is the 2D histogram ID

If you stored the histogram ID returned by CreateH1, you should use that ID instead of hard coded numbers:

cpp
// Suppose idEdep was stored when calling CreateH1
analysisManager->FillH1(idEdep, edep);

Histogram filling can be done in any user action where you have access to the quantities you want to record. Common places include:

In SteppingAction, for distributions per step such as step length, energy deposition per step, or position.

In EventAction, for quantities per event such as total deposited energy, number of secondaries, or event time.

In RunAction, rarely, for very global quantities accumulated over all events.

A typical pattern for an energy deposition spectrum is to accumulate the energy per event in EventAction and fill the histogram only once per event:

cpp
// EventAction.hh
private:
  G4double fEdepEvent;
// EventAction.cc
void EventAction::BeginOfEventAction(const G4Event*)
{
  fEdepEvent = 0.;
}
void EventAction::EndOfEventAction(const G4Event*)
{
  auto analysisManager = G4AnalysisManager::Instance();
  analysisManager->FillH1(0, fEdepEvent);
}

In this case you would increment fEdepEvent in your SteppingAction or SensitiveDetector and then fill the histogram at the end of the event. This produces a histogram of energy per event instead of per step.

Always fill histograms with values expressed in the same units used to define the histogram range. Do not mix units. Do not convert to human readable units when filling. Convert only when you plot or analyze the results later.

Histogram filling is cumulative over events and runs. Each call to FillH1 or FillH2 increments the content of the corresponding bin by the specified weight. The analysis manager takes care of keeping counts and will write the complete histogram when you call Write() and CloseFile() in your RunAction.

Views: 11

Comments

Please login to add a comment.

Don't have an account? Register now!