KAHIBARO
Discord Login Register

15.4. Hit Collections

Storing detector hits

In Geant4, a hit collection is the container that stores all hits created by a given sensitive detector in a single event. Each sensitive detector can create its own type of hit object, and each event can contain multiple collections, one for each active sensitive detector.

You typically start by defining a hit class that inherits from G4VHit, for example MyDetectorHit. To store many instances of this hit class, Geant4 uses a collection type based on G4THitsCollection. The pattern is usually:

cpp
using MyDetectorHitsCollection = G4THitsCollection<MyDetectorHit>;

Inside your class derived from G4VSensitiveDetector, you declare a collection ID and a pointer to the collection. The collection itself is created at the beginning of each event in the Initialize method of the sensitive detector. The event object provides a G4HCofThisEvent, which is the container of all hit collections for that event. You must create your hits collection and register it into this container so that Geant4 can manage it.

A typical Initialize implementation looks like this in outline:

cpp
void MyDetectorSD::Initialize(G4HCofThisEvent* hce)
{
  fHitsCollection =
    new MyDetectorHitsCollection(SensitiveDetectorName, collectionName[0]);
  static G4int hcID = -1;
  if (hcID < 0) {
    hcID = GetCollectionID(0);
  }
  hce->AddHitsCollection(hcID, fHitsCollection);
}

The SensitiveDetectorName and collectionName[0] are strings that identify your detector and the specific collection. The call to GetCollectionID(0) queries Geant4 for an integer ID associated with this collection name. This ID is stable across events and lets you retrieve the collection later. The G4HCofThisEvent object, hce, will own the hits collection for the duration of the event and delete it at the end.

Each time a relevant interaction occurs, the ProcessHits method of your sensitive detector is called with a G4Step and a G4TouchableHistory. Inside ProcessHits, you decide whether to record a hit. If so, you create a new instance of your hit class, fill it with information from the step, and insert it into the hits collection.

For example:

cpp
G4bool MyDetectorSD::ProcessHits(G4Step* step, G4TouchableHistory*)
{
  G4double edep = step->GetTotalEnergyDeposit();
  if (edep == 0.) return false;
  auto hit = new MyDetectorHit();
  hit->SetEdep(edep);
  hit->SetPosition(step->GetPreStepPoint()->GetPosition());
  fHitsCollection->insert(hit);
  return true;
}

Here, only steps with nonzero energy deposition generate hits. The new hit is pushed into fHitsCollection, which gathers all hits for this sensitive detector in the current event.

A hits collection exists per event, not globally. Always create the hits collection in Initialize(G4HCofThisEvent*), register it with the event, and fill it only within that event. Never try to reuse a hits collection across events.

Accessing hits

To use the information stored in a hits collection, you normally access it in an event-level user action, typically EventAction. At the end of the event, all hits collections from all sensitive detectors are available through the G4HCofThisEvent object that is passed to EndOfEventAction.

Inside EndOfEventAction(const G4Event* event), you first retrieve the G4HCofThisEvent pointer:

cpp
auto hce = event->GetHCofThisEvent();
if (!hce) return;

From this event-wide container, you can get your specific hits collection either by collection ID or by name. The most robust way is to cache the collection ID the first time you need it, then reuse it in later calls, since looking up by name is more expensive.

A typical pattern is:

cpp
static G4int hcID = -1;
if (hcID < 0) {
  hcID = G4SDManager::GetSDMpointer()
           ->GetCollectionID("MyDetectorSD/MyDetectorHitsCollection");
}
auto hitsCollection =
  static_cast<MyDetectorHitsCollection*>(hce->GetHC(hcID));
if (!hitsCollection) return;

The string "MyDetectorSD/MyDetectorHitsCollection" must match the sensitive detector name and collection name you used when you created the collection in Initialize. Once you have the MyDetectorHitsCollection*, you can loop over all hits and read their data.

For example, to accumulate total energy deposition in the detector for the event, you might do:

cpp
G4double totalEdep = 0.;
for (size_t i = 0; i < hitsCollection->GetSize(); ++i) {
  auto hit = (*hitsCollection)[i];
  totalEdep += hit->GetEdep();
}

You can also extract positions, times, or detector IDs stored in each hit and send them to your analysis manager. This commonly happens in EndOfEventAction, where you fill histograms or ntuples with per-event information.

Sometimes you need to access hits collections in other user actions, for example in SteppingAction. In that case, you must obtain the current event (G4RunManager::GetRunManager()->GetCurrentEvent()), then retrieve G4HCofThisEvent, and finally get the collection in the same way. For simple applications, keeping all hit processing in EventAction is usually clearer and easier to maintain.

Always check that G4HCofThisEvent* and the hits collection pointer are not null before using them. Use a cached collection ID for efficient and consistent access. The collection name used to retrieve the ID must exactly match the name used when the collection was created.

Once you have extracted the needed information from the hits collection, you are free to discard the pointers. Geant4 will manage the memory and delete the hits and their collection at the end of the event, so you must not attempt to delete them yourself.

Views: 9

Comments

Please login to add a comment.

Don't have an account? Register now!