Compare commits

...

4 commits

Author SHA1 Message Date
Ava
324f479434 stand 2025-12-01, threads fehlerhaft 2025-12-01 17:50:50 +01:00
Ava
8809c2e595 define outputcolumns via macro 2025-12-01 14:16:36 +01:00
Ava
02f57fd562 particle type via macro 2025-12-01 13:46:34 +01:00
Ava
a25c6ee795 particle energy via macro 2025-12-01 13:27:21 +01:00
11 changed files with 342 additions and 162 deletions

View file

@ -1,16 +1,24 @@
#ifndef AACTIONINITIALIZATION_H #ifndef AACTIONINITIALIZATION_H
#define AACTIONINITIALIZATION_H #define AACTIONINITIALIZATION_H
#pragma once
#include "G4VUserActionInitialization.hh" #include "G4VUserActionInitialization.hh"
class ARunAction;
class APrimaryGenerator;
class ASensitiveDetector;
class AActionInitialization : public G4VUserActionInitialization class AActionInitialization : public G4VUserActionInitialization
{ {
public: public:
AActionInitialization(); AActionInitialization(ASensitiveDetector* sd);
virtual ~AActionInitialization(); virtual ~AActionInitialization();
virtual void Build() const override; virtual void Build() const override;
virtual void BuildForMaster() const override; virtual void BuildForMaster() const override;
private:
ASensitiveDetector* fSD; // Pointer auf den Sensitive Detector
}; };
#endif #endif

View file

@ -32,6 +32,8 @@ public:
virtual G4VPhysicalVolume* Construct(); virtual G4VPhysicalVolume* Construct();
void ConstructSDandField(); void ConstructSDandField();
ASensitiveDetector* GetSensitiveDetector() const { return fSD; }
private: private:
std::vector<G4LogicalVolume*> detectorVolumes; std::vector<G4LogicalVolume*> detectorVolumes;

View file

@ -1,22 +1,25 @@
#ifndef AMESSENGER_HH #pragma once
#define AMESSENGER_HH
#include "G4UImessenger.hh" #include "G4UImessenger.hh"
#include "G4UIcmdWithAString.hh" #include "G4UIcmdWithAString.hh"
#include "G4UIcmdWithADoubleAndUnit.hh"
class ASensitiveDetector; class ASensitiveDetector;
class APrimaryGenerator;
class AMessenger : public G4UImessenger class AMessenger : public G4UImessenger
{ {
public: public:
AMessenger(ASensitiveDetector* sd); AMessenger(ASensitiveDetector* sd, APrimaryGenerator* generator = nullptr);
~AMessenger(); ~AMessenger();
virtual void SetNewValue(G4UIcommand* cmd, G4String value) override; void SetNewValue(G4UIcommand* cmd, G4String value) override;
private: private:
ASensitiveDetector* fSD; ASensitiveDetector* fSD;
G4UIcmdWithAString* fOutputFileCmd; APrimaryGenerator* fGenerator; // Referenz zum Primärgenerator
};
#endif G4UIcmdWithAString* fOutputFileCmd;
G4UIcmdWithAString* fParticleTypeCmd;
G4UIcmdWithADoubleAndUnit* fEnergyCmd;
G4UIcmdWithAString* fOutputColumnsCmd;
};

View file

@ -13,10 +13,15 @@ public:
APrimaryGenerator(); APrimaryGenerator();
~APrimaryGenerator(); ~APrimaryGenerator();
virtual void GeneratePrimaries(G4Event *); virtual void GeneratePrimaries(G4Event * anEvent) override;
void SetParticleEnergy(G4double energy) { fParticleEnergy = energy; }
void SetParticleName(const G4String& name) { fParticleName = name; }
private: private:
G4ParticleGun *fParticleGun; G4ParticleGun *fParticleGun;
G4double fParticleEnergy;
G4String fParticleName;
}; };
#endif #endif

View file

@ -8,14 +8,20 @@
#include "G4Track.hh" #include "G4Track.hh"
#include "G4SystemOfUnits.hh" #include "G4SystemOfUnits.hh"
#include "G4UnitsTable.hh" #include "G4UnitsTable.hh"
#include "G4UImessenger.hh"
#include "G4UIcmdWithAString.hh"
#include <unordered_map> #include <unordered_map>
#include <fstream> #include <fstream>
#include <functional>
#include <map>
#include <vector>
class AMessenger; class AMessenger;
//
// Makro für die OutputMap gleiche Logik wie beim Kollegen
//
#define OUTMAP [](const HitInfo& hit, std::ostream& out)
class ASensitiveDetector : public G4VSensitiveDetector class ASensitiveDetector : public G4VSensitiveDetector
{ {
public: public:
@ -23,39 +29,89 @@ public:
~ASensitiveDetector(); ~ASensitiveDetector();
virtual void Initialize(G4HCofThisEvent* hce) override; virtual void Initialize(G4HCofThisEvent* hce) override;
virtual G4bool ProcessHits(G4Step* step, G4TouchableHistory* touch) override;
virtual void EndOfEvent(G4HCofThisEvent* hce) override; virtual void EndOfEvent(G4HCofThisEvent* hce) override;
virtual G4bool ProcessHits(G4Step* step, G4TouchableHistory* touchHist) override;
//Filename void SetOutputFilename(const G4String& f) { fOutputFilename = f; }
void SetOutputFilename(const G4String& name) { fOutputFilename = name; } void SetOutputColumns(const std::vector<G4String>& cols) { fOutputColumns = cols; }
void SetMessenger(AMessenger* messenger) { fMessenger = messenger; } void SetMessenger(AMessenger* m) { fMessenger = m; }
void RegisterVolumeName(G4LogicalVolume* lv, const std::string& cleanName) {
fCleanNames[lv] = cleanName;}
private: private:
AMessenger* fMessenger = nullptr; // jetzt optional AMessenger* fMessenger = nullptr;
G4String fOutputFilename = "outfiles/shower_setup.txt"; G4String fOutputFilename;
G4int fCurrentEventID = -1; // speichert die aktuelle Event-ID G4int fCurrentEventID = -1;
struct HitInfo { public:
G4int eventID; //
G4int trackID; // HitInfo enthält ALLE üblichen Parameter
G4int parentID; //
G4String particleName; struct HitInfo
G4double particleEnergy; {
G4String primaryParticleName; // --- Basis-identifikation ---
G4double primaryEnergy; G4int eventID; // Nummer des Events
G4double energyDeposited; G4int trackID; // Track ID
G4String detectorName; G4int parentID; // Parent Track ID
G4String cleanDetectorName;
HitInfo() // --- Teilchen ---
: trackID(-1), parentID(-1), particleEnergy(0.), primaryEnergy(0.), energyDeposited(0.) {} G4String particleName; // Name des Teilchens
G4int pdg; // PDG-Code
G4double particleEnergy;// kinetische Energie am Vertex
// --- Primärinformation ---
G4String primaryName; // Name des Primärteilchens
G4double primaryEnergy; // Primärenergie
// --- Energien ---
G4double edep; // Deposited Energy
G4double ekin; // aktuelle kinetische Energie
// --- Positionen ---
G4ThreeVector prePos; // Position vor dem Step
G4ThreeVector postPos; // Position nach dem Step
// --- Richtung ---
G4ThreeVector preDir; // Richtung vor dem Step
G4ThreeVector postDir; // Richtung nach dem Step
// --- Zeiten ---
G4double globalTime; // absolute Zeit
G4double localTime; // lokale Zeit
// --- Step-Information ---
G4double stepLength; // Step-Länge
G4String processName; // Prozess, der diesen Step erzeugt hat
// --- Detektor ---
G4String detectorName; // voller Name
G4String cleanName; // aufgeräumter Name ohne _phys
HitInfo() :
eventID(0), trackID(0), parentID(0),
pdg(0),
particleEnergy(0.), primaryEnergy(0.),
edep(0.), ekin(0.),
globalTime(0.), localTime(0.),
stepLength(0.)
{}
}; };
G4String fDetectorName; private:
std::unordered_map<G4LogicalVolume*, std::string> fCleanNames; //
std::unordered_map<G4int, HitInfo> fTrackHitMap; // TrackID → HitInfo // OutputMap: string → Lambda(hit, out)
//
using OutputLambda = std::function<void(const HitInfo&, std::ostream&)>;
std::map<std::string, OutputLambda> outputMap;
//
// interne Daten
//
std::vector<G4String> fOutputColumns;
std::unordered_map<G4int, HitInfo> fTrackHitMap;
//
// interne Hilfsfunktionen
//
void InitializeOutputMap();
}; };
#endif #endif

17
macros/defrun.mac Normal file
View file

@ -0,0 +1,17 @@
/run/numberOfThreads 2
# --- Output Datei setzen ---
/my/outputFilename outfiles/test1000_100MeV_e
# --- Particle Type setzen ---
/my/particleType e-
# --- Particle Energy setzen ---
/my/particleEnergy 100 MeV
# --- Spalten setzen (ohne Kommata) ---
/my/outputColumns event track parent part pdg ekin edep x y z dir step proc det
/run/initialize
/run/beamOn 10

6
sim.cc
View file

@ -26,10 +26,12 @@ int main(int argc, char** argv)
runManager->SetUserInitialization(new APhysicsList()); runManager->SetUserInitialization(new APhysicsList());
// Detector // Detector
runManager->SetUserInitialization(new ADetectorConstruction()); ADetectorConstruction* detector = new ADetectorConstruction();
runManager->SetUserInitialization(detector);
// Actions // Actions
runManager->SetUserInitialization(new AActionInitialization()); runManager->SetUserInitialization(new AActionInitialization(detector->GetSensitiveDetector()));
// Visualization // Visualization
G4VisManager* visManager = new G4VisExecutive(); G4VisManager* visManager = new G4VisExecutive();

View file

@ -1,9 +1,10 @@
#include "AActionInitialization.hh" #include "AActionInitialization.hh"
#include "AMessenger.hh"
#include "APrimaryGenerator.hh" #include "APrimaryGenerator.hh"
#include "ARunAction.hh" #include "ARunAction.hh"
AActionInitialization::AActionInitialization() AActionInitialization::AActionInitialization(ASensitiveDetector* sd)
: G4VUserActionInitialization() : G4VUserActionInitialization(), fSD(sd)
{ {
} }
@ -12,7 +13,10 @@ AActionInitialization::~AActionInitialization() {}
void AActionInitialization::Build() const void AActionInitialization::Build() const
{ {
// Primärgenerator // Primärgenerator
SetUserAction(new APrimaryGenerator()); APrimaryGenerator* primaryGen = new APrimaryGenerator();
SetUserAction(primaryGen);
AMessenger* messenger = new AMessenger(fSD, primaryGen);
// RunAction // RunAction
SetUserAction(new ARunAction()); SetUserAction(new ARunAction());

View file

@ -1,18 +1,42 @@
#include "AMessenger.hh" #include "AMessenger.hh"
#include "ASensitiveDetector.hh" #include "ASensitiveDetector.hh"
#include "APrimaryGenerator.hh"
#include "G4SystemOfUnits.hh"
AMessenger::AMessenger(ASensitiveDetector* sd) AMessenger::AMessenger(ASensitiveDetector* sd, APrimaryGenerator* generator)
: fSD(sd) : fSD(sd), fGenerator(generator)
{ {
// eigenes UI Kommando // eigenes UI Kommando
fOutputFileCmd = new G4UIcmdWithAString("/my/outputFilename", this); fOutputFileCmd = new G4UIcmdWithAString("/my/outputFilename", this);
fOutputFileCmd->SetGuidance("Set output filename for SD text output."); fOutputFileCmd->SetGuidance("Set output filename for SD text output.");
fOutputFileCmd->SetParameterName("filename", false); fOutputFileCmd->SetParameterName("filename", false);
// Kommando für Teilchentyp
fParticleTypeCmd = new G4UIcmdWithAString("/my/particleType", this);
fParticleTypeCmd->SetGuidance("Set particle type (e-, e+, gamma, proton, neutron).");
fParticleTypeCmd->SetParameterName("particle", false);
fParticleTypeCmd->AvailableForStates(G4State_PreInit, G4State_Idle);
// Kommando für Teilchenenergie
fEnergyCmd = new G4UIcmdWithADoubleAndUnit("/my/particleEnergy", this);
fEnergyCmd->SetGuidance("Set particle energy.");
fEnergyCmd->SetParameterName("energy", false);
fEnergyCmd->SetUnitCategory("Energy");
fEnergyCmd->AvailableForStates(G4State_PreInit, G4State_Idle);
//Kommando für Parameterreihenfolge
fOutputColumnsCmd = new G4UIcmdWithAString("/my/outputColumns", this);
fOutputColumnsCmd->SetGuidance("Set output columns and order (comma separated). E.g.: particle,Epart,Dname,Edep");
fOutputColumnsCmd->SetParameterName("columns", false);
fOutputColumnsCmd->AvailableForStates(G4State_PreInit, G4State_Idle);
} }
AMessenger::~AMessenger() AMessenger::~AMessenger()
{ {
delete fOutputFileCmd; delete fOutputFileCmd;
delete fParticleTypeCmd;
delete fEnergyCmd;
delete fOutputColumnsCmd;
} }
void AMessenger::SetNewValue(G4UIcommand* cmd, G4String value) void AMessenger::SetNewValue(G4UIcommand* cmd, G4String value)
@ -21,4 +45,24 @@ void AMessenger::SetNewValue(G4UIcommand* cmd, G4String value)
{ {
fSD->SetOutputFilename(value); fSD->SetOutputFilename(value);
} }
else if(cmd == fEnergyCmd && fGenerator)
{
fGenerator->SetParticleEnergy(fEnergyCmd->GetNewDoubleValue(value));
}
else if (cmd == fParticleTypeCmd && fGenerator)
{
fGenerator->SetParticleName(value);
}
else if(cmd == fOutputColumnsCmd && fSD)
{
std::vector<G4String> cols;
std::istringstream iss(value);
G4String token;
while(iss >> token)
{
cols.push_back(token);
}
fSD->SetOutputColumns(cols);
}
} }

View file

@ -3,29 +3,16 @@
APrimaryGenerator::APrimaryGenerator() APrimaryGenerator::APrimaryGenerator()
{ {
fParticleGun = new G4ParticleGun(1); // 1 particles per event fParticleGun = new G4ParticleGun(1); // 1 particles per event
fParticleEnergy = 100.*MeV; // Default-Energie
fParticleName = "e-"; //default
//Particle position G4ThreeVector pos(0.,0.,-1.*cm);
G4double x = 0. * m; G4ThreeVector mom(0.,0.,1.);
G4double y = 0. * m;
G4double z = -1. * cm;
G4ThreeVector pos(x, y, z);
//Particle direction
G4double px = 0.;
G4double py = 0.;
G4double pz = 1.;
G4ThreeVector mom(px,py,pz);
//Particle type
G4ParticleTable* particleTable = G4ParticleTable::GetParticleTable(); G4ParticleTable* particleTable = G4ParticleTable::GetParticleTable();
// possibilities: "e+","e-","gamma", ,"proton", "neutron"
G4ParticleDefinition* particle = particleTable->FindParticle("e-"); G4ParticleDefinition* particle = particleTable->FindParticle("e-");
fParticleGun->SetParticlePosition(pos); fParticleGun->SetParticlePosition(pos);
fParticleGun->SetParticleMomentumDirection(mom); fParticleGun->SetParticleMomentumDirection(mom);
fParticleGun->SetParticleEnergy(100 * MeV); //or GeV
fParticleGun->SetParticleDefinition(particle); fParticleGun->SetParticleDefinition(particle);
} }
@ -36,6 +23,15 @@ APrimaryGenerator::~APrimaryGenerator()
void APrimaryGenerator::GeneratePrimaries(G4Event *anEvent) void APrimaryGenerator::GeneratePrimaries(G4Event *anEvent)
{ {
//Create vertex G4ParticleTable* particleTable = G4ParticleTable::GetParticleTable();
G4ParticleDefinition* particle = particleTable->FindParticle(fParticleName);
if (!particle)
{
G4cerr << "Unknown particle: " << fParticleName << ". Using e- as default." << G4endl;
particle = particleTable->FindParticle("e-");
}
fParticleGun->SetParticleDefinition(particle);
fParticleGun->SetParticleEnergy(fParticleEnergy); // dynamisch vom Macro
fParticleGun->GeneratePrimaryVertex(anEvent); fParticleGun->GeneratePrimaryVertex(anEvent);
} }

View file

@ -1,131 +1,174 @@
#include "ASensitiveDetector.hh" #include "ASensitiveDetector.hh"
#include "AMessenger.hh" #include "AMessenger.hh"
#include "G4RunManager.hh"
#include "G4Event.hh" #include "G4Event.hh"
#include "G4PrimaryVertex.hh" #include "G4RunManager.hh"
#include "G4PrimaryParticle.hh" #include "G4Threading.hh"
#include "G4SystemOfUnits.hh"
#include <filesystem> #include <filesystem>
#include <iostream> #include <iostream>
ASensitiveDetector::ASensitiveDetector(G4String name) ASensitiveDetector::ASensitiveDetector(G4String name)
: G4VSensitiveDetector(name), fDetectorName(name) : G4VSensitiveDetector(name), fOutputFilename("outfiles/shower_setup")
{ {
fOutputFilename = "outfiles/shower_setup.txt";
std::filesystem::create_directories("outfiles"); std::filesystem::create_directories("outfiles");
InitializeOutputMap();
if(fOutputColumns.empty()) {
fOutputColumns = {"event", "track", "parent", "part", "edep", "det"};
}
} }
ASensitiveDetector::~ASensitiveDetector() ASensitiveDetector::~ASensitiveDetector() {}
{
} void ASensitiveDetector::Initialize(G4HCofThisEvent*)
void ASensitiveDetector::Initialize(G4HCofThisEvent* /*hce*/)
{ {
fTrackHitMap.clear(); fTrackHitMap.clear();
} }
G4bool ASensitiveDetector::ProcessHits(G4Step* step, G4TouchableHistory* /*touchHist*/) void ASensitiveDetector::InitializeOutputMap()
{ {
const G4Event* event = G4RunManager::GetRunManager()->GetCurrentEvent(); outputMap = {
{"event", OUTMAP { out << hit.eventID; }},
{"track", OUTMAP { out << hit.trackID; }},
{"parent", OUTMAP { out << hit.parentID; }},
{"part", OUTMAP { out << hit.particleName; }},
{"pdg", OUTMAP { out << hit.pdg; }},
{"ekin", OUTMAP { out << hit.ekin / MeV; }},
{"edep", OUTMAP { out << hit.edep / MeV; }},
{"x", OUTMAP { out << hit.postPos.x() / mm; }},
{"y", OUTMAP { out << hit.postPos.y() / mm; }},
{"z", OUTMAP { out << hit.postPos.z() / mm; }},
{"pos", OUTMAP { out << hit.postPos.x()/mm<<" "<<hit.postPos.y()/mm<<" "<<hit.postPos.z()/mm; }},
{"dx", OUTMAP { out << hit.postDir.x(); }},
{"dy", OUTMAP { out << hit.postDir.y(); }},
{"dz", OUTMAP { out << hit.postDir.z(); }},
{"dir", OUTMAP { out << hit.postDir.x()<<" "<<hit.postDir.y()<<" "<<hit.postDir.z(); }},
{"global_t", OUTMAP { out << hit.globalTime; }},
{"local_t", OUTMAP { out << hit.localTime; }},
{"step", OUTMAP { out << hit.stepLength / mm; }},
{"proc", OUTMAP { out << hit.processName; }},
{"det", OUTMAP { out << hit.cleanName; }}
};
}
G4bool ASensitiveDetector::ProcessHits(G4Step* step, G4TouchableHistory*)
{
if(!step) return false;
G4Track* trk = step->GetTrack();
if(!trk) return false;
const G4Event* event = G4RunManager::GetRunManager()->GetCurrentEvent();
if(!event) return false; if(!event) return false;
// Event-ID direkt hier setzen
fCurrentEventID = event->GetEventID(); fCurrentEventID = event->GetEventID();
G4int id = trk->GetTrackID();
G4Track* track = step->GetTrack(); HitInfo& hit = fTrackHitMap[id];
G4int trackID = track->GetTrackID();
auto it = fTrackHitMap.find(trackID); // Basisdaten
if (it == fTrackHitMap.end())
{
HitInfo hit;
hit.eventID = fCurrentEventID; hit.eventID = fCurrentEventID;
hit.trackID = trackID; hit.trackID = id;
hit.parentID = track->GetParentID(); hit.parentID = trk->GetParentID();
hit.particleName = track->GetDefinition()->GetParticleName(); if(trk->GetDefinition()) {
hit.particleEnergy = track->GetVertexKineticEnergy(); hit.particleName = trk->GetDefinition()->GetParticleName();
hit.detectorName = step->GetPreStepPoint()->GetTouchable()->GetVolume()->GetName(); hit.pdg = trk->GetDefinition()->GetPDGEncoding();
std::string detNameStr = hit.detectorName; }
size_t pos = detNameStr.find("_phys"); hit.ekin = trk->GetKineticEnergy();
if (pos != std::string::npos)
detNameStr = detNameStr.substr(0, pos); // nur Basisname // Primärteilchen (sicher prüfen)
hit.cleanDetectorName = detNameStr; if(auto vertex = event->GetPrimaryVertex()) {
// Primary particle info if(auto prim = vertex->GetPrimary()) {
G4PrimaryVertex* pv = event->GetPrimaryVertex(); if(auto code = prim->GetG4code()) {
if (pv) hit.primaryName = code->GetParticleName();
{ hit.primaryEnergy = prim->GetKineticEnergy();
G4PrimaryParticle* pp = pv->GetPrimary(); }
if (pp && pp->GetG4code()) }
hit.primaryParticleName = pp->GetG4code()->GetParticleName();
if (pp)
hit.primaryEnergy = pp->GetKineticEnergy();
} }
hit.energyDeposited = step->GetTotalEnergyDeposit(); // Energie aufsummieren
fTrackHitMap[trackID] = hit; hit.edep += step->GetTotalEnergyDeposit();
// PreStep/PostStep prüfen
auto pre = step->GetPreStepPoint();
auto post = step->GetPostStepPoint();
if(pre && post) {
hit.prePos = pre->GetPosition();
hit.postPos = post->GetPosition();
hit.preDir = pre->GetMomentumDirection();
hit.postDir = post->GetMomentumDirection();
hit.globalTime = post->GetGlobalTime();
hit.localTime = post->GetLocalTime();
hit.stepLength = step->GetStepLength();
hit.processName = post->GetProcessDefinedStep() ? post->GetProcessDefinedStep()->GetProcessName() : "none";
// Detektorname prüfen
if(pre->GetTouchable()) {
auto vol = pre->GetTouchable()->GetVolume();
if(vol) {
auto full = vol->GetName();
hit.detectorName = full;
auto pos = full.find("_phys");
hit.cleanName = (pos == std::string::npos ? full : full.substr(0, pos));
} else {
hit.detectorName = "none";
hit.cleanName = "none";
}
} else {
hit.detectorName = "none";
hit.cleanName = "none";
} }
else
{
it->second.energyDeposited += step->GetTotalEnergyDeposit();
} }
return true; return true;
} }
void ASensitiveDetector::EndOfEvent(G4HCofThisEvent*)
void ASensitiveDetector::EndOfEvent(G4HCofThisEvent* /*hce*/)
{ {
if (fOutputFilename.empty()) fOutputFilename = "outfiles/shower_setup.txt"; // Thread-ID für Datei
std::filesystem::create_directories("outfiles"); G4int tid = G4Threading::G4GetThreadId();
std::ofstream out(fOutputFilename, std::ios::app); // Thread-local Datei
thread_local std::ofstream out;
// Datei öffnen, wenn noch nicht offen
if(!out.is_open()) { if(!out.is_open()) {
G4cerr << "Cannot open file " << fOutputFilename << "!" << G4endl; std::filesystem::create_directories("outfiles");
std::string threadFile = fOutputFilename + "_" + std::to_string(tid) + ".hits";
out.open(threadFile, std::ios::app);
if(!out.is_open()) {
G4cerr << "Cannot open output file: " << threadFile << G4endl;
return; return;
} }
static bool headerWritten = false; // Header einmal pro Datei
if (!headerWritten) { for(size_t i=0; i<fOutputColumns.size(); ++i) {
out << "eventID\ttrackID\tparentID\tparticle\tEpart\tPrimparticle\tEprim\tDname\tEdep\n"; out << fOutputColumns[i];
headerWritten = true; if(i+1 < fOutputColumns.size()) out << "\t";
}
out << "\n";
} }
// Hits nur für das aktuelle Event // Hits schreiben
std::vector<HitInfo> hits; for(auto& [id, hit] : fTrackHitMap) {
for (const auto& [trackID, hit] : fTrackHitMap) { for(size_t i=0; i<fOutputColumns.size(); ++i) {
hits.push_back(hit); const auto& col = fOutputColumns[i];
if(outputMap.count(col))
outputMap[col](hit, out);
else
out << "NA";
if(i+1 < fOutputColumns.size()) out << "\t";
}
out << "\n";
} }
// Sortieren: parentID -> trackID // Map zurücksetzen
std::sort(hits.begin(), hits.end(), [](const HitInfo& a, const HitInfo& b) {
if (a.parentID != b.parentID)
return a.parentID < b.parentID;
return a.trackID < b.trackID;
});
// Schreiben
for (const auto& hit : hits)
{
out << hit.eventID
<< "\t" << hit.trackID
<< "\t" << hit.parentID
<< "\t" << hit.particleName
<< "\t" << hit.particleEnergy / MeV
<< "\t" << hit.primaryParticleName
<< "\t" << hit.primaryEnergy / MeV
<< "\t" << hit.cleanDetectorName
<< "\t" << hit.energyDeposited / MeV
<< "\n";
}
out.close();
// Map leeren für nächstes Event
fTrackHitMap.clear(); fTrackHitMap.clear();
} }