Compare commits

..

2 commits

Author SHA1 Message Date
Ava
62d264b11c use step instead of track info 2026-01-06 12:42:16 +01:00
Ava
1cb4fa4956 shower BGO zylinder 2025-12-17 17:54:48 +01:00
12 changed files with 626 additions and 147 deletions

View file

@ -1,3 +1,27 @@
// #pragma once
// #include "G4VUserDetectorConstruction.hh"
// #include "ASensitiveDetector.hh"
// #include "AMessenger.hh"
// class G4VPhysicalVolume;
// class ADetectorConstruction : public G4VUserDetectorConstruction
// {
// public:
// ADetectorConstruction();
// ~ADetectorConstruction() override;
// G4VPhysicalVolume* Construct() override;
// void ConstructSDandField() override;
// ASensitiveDetector* GetSensitiveDetector() const { return fSD; }
// private:
// ASensitiveDetector* fSD;
// AMessenger* fMessenger;
// };
#ifndef ADETECTORCONSTRUCTION_HH #ifndef ADETECTORCONSTRUCTION_HH
#define ADETECTORCONSTRUCTION_HH #define ADETECTORCONSTRUCTION_HH

View file

@ -1,3 +1,31 @@
// #pragma once
// #include "G4VSensitiveDetector.hh"
// #include "G4THitsCollection.hh"
// #include "G4Step.hh"
// #include <fstream>
// #include <vector>
// #include <string>
// class ASensitiveDetector : public G4VSensitiveDetector
// {
// public:
// ASensitiveDetector(const G4String& name);
// ~ASensitiveDetector() override;
// void Initialize(G4HCofThisEvent*) override;
// G4bool ProcessHits(G4Step* step, G4TouchableHistory*) override;
// void EndOfEvent(G4HCofThisEvent*) override;
// void SetOutputFilename(const G4String& filename) { fOutputFilename = filename; }
// void SetOutputColumns(const std::vector<G4String>& cols) { fOutputColumns = cols; }
// private:
// std::ofstream fOutputFile;
// G4String fOutputFilename;
// std::vector<G4String> fOutputColumns;
// };
#ifndef ASENSITIVEDETECTOR_HH #ifndef ASENSITIVEDETECTOR_HH
#define ASENSITIVEDETECTOR_HH #define ASENSITIVEDETECTOR_HH
@ -20,7 +48,9 @@ class AMessenger;
// //
// Makro für die OutputMap gleiche Logik wie beim Kollegen // Makro für die OutputMap gleiche Logik wie beim Kollegen
// //
#define OUTMAP [](const HitInfo& hit, std::ostream& out) //#define OUTMAP [](const HitInfo& hit, std::ostream& out)
#define OUTMAP [&, safeString, safeDouble, safeVec3](const HitInfo& hit, std::ostream& out)
class ASensitiveDetector : public G4VSensitiveDetector class ASensitiveDetector : public G4VSensitiveDetector
{ {
@ -95,6 +125,15 @@ public:
{} {}
}; };
struct StepHit
{
G4int eventID;
G4int trackID;
G4double edep; // MeV
G4double z; // cm
G4double r; // cm
};
private: private:
// //
// OutputMap: string → Lambda(hit, out) // OutputMap: string → Lambda(hit, out)
@ -106,7 +145,8 @@ private:
// interne Daten // interne Daten
// //
std::vector<G4String> fOutputColumns; std::vector<G4String> fOutputColumns;
std::unordered_map<G4int, HitInfo> fTrackHitMap; //std::unordered_map<G4int, HitInfo> fTrackHitMap;
std::vector<StepHit> fStepHits;
// //
// interne Hilfsfunktionen // interne Hilfsfunktionen

20
macros/BGO_map_energy.mac Normal file
View file

@ -0,0 +1,20 @@
# Anzahl Threads
/run/numberOfThreads 1
# Output-Datei
/my/outputFilename out/BGO_shower_100MeV
# Particle Type
/my/particleType e-
# Particle Energy
/my/particleEnergy 100 MeV
# Output-Spalten
/my/outputColumns event track parent part pdg ekin edep z r
# Initialisierung
/run/initialize
# Simulation starten (10000 Hits)
/run/beamOn 50000

20
macros/BGO_map_test.mac Normal file
View file

@ -0,0 +1,20 @@
# Anzahl Threads
/run/numberOfThreads 1
# Output-Datei setzen **vor** /run/initialize
/my/outputFilename out/BGO_shower_test1
# Particle Type
/my/particleType e-
# Particle Energy
/my/particleEnergy 100 MeV
# Output-Spalten
/my/outputColumns event track parent part pdg ekin edep z r
# Initialisierung
/run/initialize
# Simulation starten
/run/beamOn 10

25
macros/bgo_test.mac Normal file
View file

@ -0,0 +1,25 @@
# --- Öffne die Visualisierung ---
/vis/open OGLSX
/vis/viewer/set/background white
/vis/scene/create
# --- Alle Volumes sichtbar machen ---
# Zeige das World-Volume und alles darin rekursiv
/vis/scene/add/volume /World recursive
/vis/scene/endOfEventAction accumulate
# --- Darstellung einstellen ---
/vis/representation/set wireframe
/vis/scene/add/axes 0 0 0 1 m
# --- Kameraeinstellungen ---
/vis/viewer/set/viewpointThetaPhi 60 30
/vis/viewer/set/autoRefresh true
# --- Farben und Transparenz optional ---
# (BGO ist standardmäßig rot, du kannst eigene Farben setzen)
/vis/scene/modifyVolume BGO_vol visAttributes/solidColor 1 0 0 1
# --- Initialisierung der Run-Manager ---
/run/initialize

17
macros/trajectoryrun.mac Normal file
View file

@ -0,0 +1,17 @@
/run/numberOfThreads 1
# --- Output Datei setzen ---
/my/outputFilename outfiles/trajectory-01
# --- 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

13
macros/vis_bgo.mac Normal file
View file

@ -0,0 +1,13 @@
/control/execute bgo.gdml
/run/initialize
/vis/open OGL 600x600-0+x600
/vis/viewer/set/viewpointVector 1 1 1
/vis/viewer/set/autoRefresh true
/vis/drawVolume
/vis/scene/add/trajectories smooth
/vis/scene/endOfEventAction accumulate
/vis/scene/add/scale 10 cm
/vis/scene/add/axes
/vis/scene/add/eventID

27
macros/vis_shower.mac Normal file
View file

@ -0,0 +1,27 @@
run/initialize
# --- Open visualization window ---
/vis/open OGLI 600x600-0+0
/vis/viewer/set/viewpointVector 1 1 1
/vis/viewer/set/autoRefresh true
# --- Draw volumes first ---
/vis/drawVolume
# --- Add other elements ---
/vis/scene/add/trajectories smooth
/vis/scene/endOfEventAction accumulate
/vis/scene/add/scale 10 cm
/vis/scene/add/axes
/vis/scene/add/eventID
# --- Set colors (erst jetzt, nachdem die Szene existiert) ---
/vis/att/set SSD1 color orange 0.6
/vis/att/set SSD2 color orange 0.6
/vis/att/set SSD3 color orange 0.6
/vis/att/set SSD4 color orange 0.6
/vis/att/set BGO1 color green 0.6
/vis/att/set BGO2 color green 0.6
/vis/att/set BGO3 color green 0.6
/vis/viewer/refresh

59
sim.cc
View file

@ -1,3 +1,62 @@
// #include "G4RunManager.hh"
// #include "G4MTRunManager.hh"
// #include "G4UImanager.hh"
// #include "G4VisExecutive.hh"
// #include "G4UIExecutive.hh"
// #include "APhysicsList.hh"
// #include "ADetectorConstruction.hh"
// #include "AActionInitialization.hh"
// int main(int argc, char** argv)
// {
// G4UIExecutive* ui = nullptr;
// if (argc == 1)
// ui = new G4UIExecutive(argc, argv);
// #ifdef G4MULTITHREADED
// auto* runManager = new G4MTRunManager;
// #else
// auto* runManager = new G4RunManager;
// #endif
// // Physics
// runManager->SetUserInitialization(new APhysicsList());
// // Detector
// auto* detector = new ADetectorConstruction();
// runManager->SetUserInitialization(detector);
// // Actions (SD wird korrekt übergeben)
// runManager->SetUserInitialization(
// new AActionInitialization(detector->GetSensitiveDetector())
// );
// // Visualization
// auto* visManager = new G4VisExecutive();
// visManager->Initialize();
// auto* UImanager = G4UImanager::GetUIpointer();
// if (ui)
// {
// UImanager->ApplyCommand("/control/execute vis.mac");
// ui->SessionStart();
// delete ui;
// }
// else
// {
// UImanager->ApplyCommand(
// G4String("/control/execute ") + argv[1]
// );
// }
// delete visManager;
// delete runManager;
// return 0;
// }
#include <iostream> #include <iostream>
#include "G4RunManager.hh" #include "G4RunManager.hh"
#include "G4MTRunManager.hh" #include "G4MTRunManager.hh"

View file

@ -1,3 +1,75 @@
// #include "ADetectorConstruction.hh"
// #include "G4NistManager.hh"
// #include "G4PVPlacement.hh"
// #include "G4LogicalVolume.hh"
// #include "G4VisAttributes.hh"
// #include "G4SystemOfUnits.hh"
// #include "G4SDManager.hh"
// #include "G4Box.hh"
// #include "G4Tubs.hh"
// #include "ASensitiveDetector.hh"
// #include "AMessenger.hh"
// ADetectorConstruction::ADetectorConstruction()
// {
// // Sensitives Detektorobjekt erstellen
// fSD = new ASensitiveDetector("shower_setup");
// // Messenger initialisieren und an SD übergeben
// fMessenger = new AMessenger(fSD, nullptr);
// }
// ADetectorConstruction::~ADetectorConstruction()
// {
// delete fSD;
// delete fMessenger;
// }
// G4VPhysicalVolume* ADetectorConstruction::Construct()
// {
// auto* nist = G4NistManager::Instance();
// G4bool checkOverlaps = true;
// // Weltmaterial
// auto* worldMat = nist->FindOrBuildMaterial("G4_Galactic");
// // Weltvolumen
// auto* solidWorld = new G4Box("World", 0.5*m, 0.5*m, 0.5*m);
// auto* logicWorld = new G4LogicalVolume(solidWorld, worldMat, "World");
// auto* physWorld = new G4PVPlacement(nullptr, {}, logicWorld,
// "World", nullptr, false, 0, checkOverlaps);
// logicWorld->SetVisAttributes(G4VisAttributes::GetInvisible());
// // BGO-Material
// auto* bgo = nist->FindOrBuildMaterial("G4_BGO");
// // Zylindrisches BGO-Volumen
// auto* solidBGO = new G4Tubs("BGO", 0, 8*cm, 5*cm, 0, 360*deg);
// auto* logicBGO = new G4LogicalVolume(solidBGO, bgo, "BGO_logic");
// new G4PVPlacement(nullptr, G4ThreeVector(0,0,5*cm), logicBGO,
// "BGO_phys", logicWorld, false, 0, checkOverlaps);
// // Sensitives Detektor-Volumen setzen
// logicBGO->SetSensitiveDetector(fSD);
// // Transparente Visualisierung: grünlich mit 50% Deckkraft
// auto* visAttr = new G4VisAttributes(G4Colour(0.0, 1.0, 0.0, 0.5));
// visAttr->SetForceSolid(true); // Volumen ausfüllen
// logicBGO->SetVisAttributes(visAttr);
// return physWorld;
// }
// void ADetectorConstruction::ConstructSDandField()
// {
// G4SDManager::GetSDMpointer()->AddNewDetector(fSD);
// }
#include "ADetectorConstruction.hh" #include "ADetectorConstruction.hh"
#include "ASensitiveDetector.hh" #include "ASensitiveDetector.hh"
#include "AMessenger.hh" #include "AMessenger.hh"
@ -10,6 +82,7 @@
#include "G4Color.hh" #include "G4Color.hh"
#include "G4SDManager.hh" #include "G4SDManager.hh"
#include "G4SystemOfUnits.hh" #include "G4SystemOfUnits.hh"
#include "G4Tubs.hh"
ADetectorConstruction::ADetectorConstruction() ADetectorConstruction::ADetectorConstruction()
{ {
@ -44,60 +117,87 @@ G4VPhysicalVolume* ADetectorConstruction::Construct()
G4VPhysicalVolume* physWorld = new G4PVPlacement( G4VPhysicalVolume* physWorld = new G4PVPlacement(
nullptr, G4ThreeVector(), logicWorld, "physWorld", nullptr, false, 0, checkOverlaps); nullptr, G4ThreeVector(), logicWorld, "physWorld", nullptr, false, 0, checkOverlaps);
// --- Layergrößen --- // // --- Layergrößen ---
G4double sizeXY = 5.0*cm; // G4double sizeXY = 5.0*cm;
G4double thSSD = 0.5*mm; // G4double thSSD = 0.5*mm;
G4double thBGO = 20.0*mm; // G4double thBGO = 20.0*mm;
G4double gap = 5.0*mm; // G4double gap = 5.0*mm;
// --- Startposition --- // // --- Startposition ---
G4double zPos = 0.0; // G4double zPos = 0.0;
// // --- Visualisierung ---
// G4VisAttributes* ssdVis = new G4VisAttributes(G4Color(0.,0.,1.,0.6));
// ssdVis->SetForceSolid(true);
// G4VisAttributes* bgoVis = new G4VisAttributes(G4Color(0.,1.,0.,0.6));
// bgoVis->SetForceSolid(true);
// // --- Indizes für eindeutige Namen ---
// int ssdIndex = 1;
// int bgoIndex = 1;
// // --- 7 Layer bauen ---
// for(int i = 0; i < 7; i++)
// {
// bool isSSD = (i % 2 == 0);
// G4double thickness = isSSD ? thSSD : thBGO;
// G4Material* mat = isSSD ? ssdMat : bgoMat;
// // Eindeutiger Name
// G4String baseName = isSSD ? "SSD" + std::to_string(ssdIndex++)
// : "BGO" + std::to_string(bgoIndex++);
// // Solid + Logical Volume
// G4Box* solid = new G4Box(baseName, 0.5*sizeXY, 0.5*sizeXY, 0.5*thickness);
// G4LogicalVolume* lv = new G4LogicalVolume(solid, mat, baseName + "_logic");
// // Platzierung
// new G4PVPlacement(nullptr,
// G4ThreeVector(0.,0.,zPos + 0.5*thickness),
// lv,
// baseName + "_phys",
// logicWorld,
// false,
// i,
// checkOverlaps);
// // Visualisierung
// lv->SetVisAttributes(isSSD ? ssdVis : bgoVis);
// // Für SD merken
// detectorVolumes.push_back(lv);
// // Update z-Position
// zPos += thickness + gap;
// --- Zylinder-Detektor ---
G4double radius = 8.0*cm;
G4double height = 10.0*cm;
G4double startAngle = 0*deg;
G4double spanningAngle = 360*deg;
G4Tubs* solidCylinder = new G4Tubs("BGO_Cylinder", 0, radius, height/2, startAngle, spanningAngle);
G4LogicalVolume* logicCylinder = new G4LogicalVolume(solidCylinder, bgoMat, "BGO_Cylinder_logic");
// --- Visualisierung --- // --- Visualisierung ---
G4VisAttributes* ssdVis = new G4VisAttributes(G4Color(0.,0.,1.,0.6)); G4VisAttributes* visAttr = new G4VisAttributes(G4Color(0.,1.,0.,0.6)); // grün
ssdVis->SetForceSolid(true); visAttr->SetForceSolid(true);
logicCylinder->SetVisAttributes(visAttr);
G4VisAttributes* bgoVis = new G4VisAttributes(G4Color(0.,1.,0.,0.6)); // --- Platzierung ---
bgoVis->SetForceSolid(true); new G4PVPlacement(
nullptr,
G4ThreeVector(0., 0., height/2), // Mittelpunkt so verschieben, dass Unterkante z=0
logicCylinder,
"BGO_Cylinder_phys",
logicWorld,
false,
0,
checkOverlaps
);
// --- Indizes für eindeutige Namen --- detectorVolumes.push_back(logicCylinder);
int ssdIndex = 1;
int bgoIndex = 1;
// --- 7 Layer bauen ---
for(int i = 0; i < 7; i++)
{
bool isSSD = (i % 2 == 0);
G4double thickness = isSSD ? thSSD : thBGO;
G4Material* mat = isSSD ? ssdMat : bgoMat;
// Eindeutiger Name
G4String baseName = isSSD ? "SSD" + std::to_string(ssdIndex++)
: "BGO" + std::to_string(bgoIndex++);
// Solid + Logical Volume
G4Box* solid = new G4Box(baseName, 0.5*sizeXY, 0.5*sizeXY, 0.5*thickness);
G4LogicalVolume* lv = new G4LogicalVolume(solid, mat, baseName + "_logic");
// Platzierung
new G4PVPlacement(nullptr,
G4ThreeVector(0.,0.,zPos + 0.5*thickness),
lv,
baseName + "_phys",
logicWorld,
false,
i,
checkOverlaps);
// Visualisierung
lv->SetVisAttributes(isSSD ? ssdVis : bgoVis);
// Für SD merken
detectorVolumes.push_back(lv);
// Update z-Position
zPos += thickness + gap;
}
return physWorld; return physWorld;
} }

View file

@ -43,7 +43,7 @@ void AMessenger::SetNewValue(G4UIcommand* cmd, G4String value)
{ {
if (cmd == fOutputFileCmd) if (cmd == fOutputFileCmd)
{ {
fSD->SetOutputFilename(value); fSD->SetOutputFilename(value); // jetzt public
} }
else if(cmd == fEnergyCmd && fGenerator) else if(cmd == fEnergyCmd && fGenerator)
{ {
@ -62,7 +62,14 @@ void AMessenger::SetNewValue(G4UIcommand* cmd, G4String value)
{ {
cols.push_back(token); cols.push_back(token);
} }
fSD->SetOutputColumns(cols); fSD->SetOutputColumns(cols); // jetzt public
} }
} }
// void AMessenger::SetNewValue(G4UIcommand* cmd, G4String value)
// {
// if(cmd == fOutputFileCmd && fSD) {
// fSD->SetOutputFilename(value); // muss in SD eine Variable setzen
// fSD->OpenFile(); // optional, Datei gleich öffnen
// }
// }

View file

@ -1,3 +1,44 @@
// #include "ASensitiveDetector.hh"
// #include "G4Step.hh"
// #include "G4SystemOfUnits.hh"
// #include <iomanip>
// ASensitiveDetector::ASensitiveDetector(const G4String& name)
// : G4VSensitiveDetector(name)
// {
// }
// ASensitiveDetector::~ASensitiveDetector()
// {
// if(fOutputFile.is_open())
// fOutputFile.close();
// }
// void ASensitiveDetector::Initialize(G4HCofThisEvent*)
// {
// if(!fOutputFile.is_open() && !fOutputFilename.empty())
// fOutputFile.open(fOutputFilename);
// }
// G4bool ASensitiveDetector::ProcessHits(G4Step* step, G4TouchableHistory*)
// {
// // Beispiel: speichere Position und Energieverlust
// auto pos = step->GetPreStepPoint()->GetPosition();
// auto edep = step->GetTotalEnergyDeposit();
// if(fOutputFile.is_open())
// fOutputFile << std::fixed << std::setprecision(3)
// << pos.z()/cm << " " << pos.perp()/cm << " " << edep/MeV << G4endl;
// return true;
// }
// void ASensitiveDetector::EndOfEvent(G4HCofThisEvent*)
// {
// fOutputFile.flush();
// }
#include "ASensitiveDetector.hh" #include "ASensitiveDetector.hh"
#include "AMessenger.hh" #include "AMessenger.hh"
#include "G4Event.hh" #include "G4Event.hh"
@ -21,114 +62,190 @@ ASensitiveDetector::~ASensitiveDetector() {}
void ASensitiveDetector::Initialize(G4HCofThisEvent*) void ASensitiveDetector::Initialize(G4HCofThisEvent*)
{ {
fTrackHitMap.clear(); //fTrackHitMap.clear();
fStepHits.clear();
} }
// void ASensitiveDetector::InitializeOutputMap()
// {
// 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; }},
// {"r", OUTMAP {
// G4double r = std::sqrt(hit.postPos.x()*hit.postPos.x() + hit.postPos.y()*hit.postPos.y());
// out << r/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; }}
// };
// }
void ASensitiveDetector::InitializeOutputMap() void ASensitiveDetector::InitializeOutputMap()
{ {
// Lambda für sicheren Zugriff auf hit-Felder
auto safeString = [](const G4String& s) -> G4String {
return s.empty() ? "undefined" : s;
};
auto safeDouble = [](G4double value, G4double scale=1.0) -> G4double {
return value; // optional: prüfen auf NaN oder negative Werte
};
auto safeVec3 = [](const G4ThreeVector& v, G4double scale=1.0) -> G4ThreeVector {
return v / scale;
};
outputMap = { outputMap = {
{"event", OUTMAP { out << hit.eventID; }}, {"event", OUTMAP { out << hit.eventID; }},
{"track", OUTMAP { out << hit.trackID; }}, {"track", OUTMAP { out << hit.trackID; }},
{"parent", OUTMAP { out << hit.parentID; }}, {"parent", OUTMAP { out << hit.parentID; }},
{"part", OUTMAP { out << safeString(hit.particleName); }},
{"part", OUTMAP { out << hit.particleName; }},
{"pdg", OUTMAP { out << hit.pdg; }}, {"pdg", OUTMAP { out << hit.pdg; }},
{"ekin", OUTMAP { out << hit.ekin / MeV; }}, {"ekin", OUTMAP { out << safeDouble(hit.ekin/MeV); }},
{"edep", OUTMAP { out << hit.edep / MeV; }}, {"edep", OUTMAP { out << safeDouble(hit.edep/MeV); }},
{"x", OUTMAP { out << safeDouble(hit.postPos.x()/mm); }},
{"x", OUTMAP { out << hit.postPos.x() / mm; }}, {"y", OUTMAP { out << safeDouble(hit.postPos.y()/mm); }},
{"y", OUTMAP { out << hit.postPos.y() / mm; }}, {"z", OUTMAP { out << safeDouble(hit.postPos.z()/mm); }},
{"z", OUTMAP { out << hit.postPos.z() / mm; }}, {"pos", OUTMAP {
{"pos", OUTMAP { out << hit.postPos.x()/mm<<" "<<hit.postPos.y()/mm<<" "<<hit.postPos.z()/mm; }}, auto v = safeVec3(hit.postPos, mm);
out << v.x() << " " << v.y() << " " << v.z();
}},
{"r", OUTMAP {
G4double r = std::sqrt(hit.postPos.x()*hit.postPos.x() + hit.postPos.y()*hit.postPos.y());
out << r;
}},
{"dx", OUTMAP { out << hit.postDir.x(); }}, {"dx", OUTMAP { out << hit.postDir.x(); }},
{"dy", OUTMAP { out << hit.postDir.y(); }}, {"dy", OUTMAP { out << hit.postDir.y(); }},
{"dz", OUTMAP { out << hit.postDir.z(); }}, {"dz", OUTMAP { out << hit.postDir.z(); }},
{"dir", OUTMAP { out << hit.postDir.x()<<" "<<hit.postDir.y()<<" "<<hit.postDir.z(); }}, {"dir", OUTMAP { out << hit.postDir.x() << " " << hit.postDir.y() << " " << hit.postDir.z(); }},
{"global_t", OUTMAP { out << hit.globalTime; }}, {"global_t", OUTMAP { out << hit.globalTime; }},
{"local_t", OUTMAP { out << hit.localTime; }}, {"local_t", OUTMAP { out << hit.localTime; }},
{"step", OUTMAP { out << hit.stepLength / mm; }}, {"step", OUTMAP { out << hit.stepLength / mm; }},
{"proc", OUTMAP { out << hit.processName; }}, {"proc", OUTMAP { out << safeString(hit.processName); }},
{"det", OUTMAP { out << safeString(hit.cleanName); }}
{"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;
// fCurrentEventID = event->GetEventID();
// G4int id = trk->GetTrackID();
// HitInfo& hit = fTrackHitMap[id];
// // Basisdaten
// hit.eventID = fCurrentEventID;
// hit.trackID = id;
// hit.parentID = trk->GetParentID();
// if(trk->GetDefinition()) {
// hit.particleName = trk->GetDefinition()->GetParticleName();
// hit.pdg = trk->GetDefinition()->GetPDGEncoding();
// }
// hit.ekin = trk->GetKineticEnergy();
// // Primärteilchen (sicher prüfen)
// if(auto vertex = event->GetPrimaryVertex()) {
// if(auto prim = vertex->GetPrimary()) {
// if(auto code = prim->GetG4code()) {
// hit.primaryName = code->GetParticleName();
// hit.primaryEnergy = prim->GetKineticEnergy();
// }
// }
// }
// // Energie aufsummieren
// 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";
// }
// }
// return true;
// }
G4bool ASensitiveDetector::ProcessHits(G4Step* step, G4TouchableHistory*) G4bool ASensitiveDetector::ProcessHits(G4Step* step, G4TouchableHistory*)
{ {
if(!step) return false; if(!step) return false;
G4Track* trk = step->GetTrack(); G4double edep = step->GetTotalEnergyDeposit();
if(!trk) return false; if(edep <= 0) return false; // nur echte Deposits
const G4Event* event = G4RunManager::GetRunManager()->GetCurrentEvent();
if(!event) return false;
fCurrentEventID = event->GetEventID();
G4int id = trk->GetTrackID();
HitInfo& hit = fTrackHitMap[id];
// Basisdaten
hit.eventID = fCurrentEventID;
hit.trackID = id;
hit.parentID = trk->GetParentID();
if(trk->GetDefinition()) {
hit.particleName = trk->GetDefinition()->GetParticleName();
hit.pdg = trk->GetDefinition()->GetPDGEncoding();
}
hit.ekin = trk->GetKineticEnergy();
// Primärteilchen (sicher prüfen)
if(auto vertex = event->GetPrimaryVertex()) {
if(auto prim = vertex->GetPrimary()) {
if(auto code = prim->GetG4code()) {
hit.primaryName = code->GetParticleName();
hit.primaryEnergy = prim->GetKineticEnergy();
}
}
}
// Energie aufsummieren
hit.edep += step->GetTotalEnergyDeposit();
// PreStep/PostStep prüfen
auto pre = step->GetPreStepPoint();
auto post = step->GetPostStepPoint(); auto post = step->GetPostStepPoint();
if(pre && post) { if(!post) return false;
hit.prePos = pre->GetPosition(); auto pos = post->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 StepHit hit;
if(pre->GetTouchable()) { hit.eventID = G4RunManager::GetRunManager()
auto vol = pre->GetTouchable()->GetVolume(); ->GetCurrentEvent()->GetEventID();
if(vol) { hit.trackID = step->GetTrack()->GetTrackID();
auto full = vol->GetName(); hit.edep = edep / MeV;
hit.detectorName = full; hit.z = pos.z() / cm;
auto pos = full.find("_phys"); hit.r = std::sqrt(pos.x()*pos.x() + pos.y()*pos.y()) / cm;
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";
}
}
fStepHits.push_back(hit);
return true; return true;
} }
void ASensitiveDetector::EndOfEvent(G4HCofThisEvent*) void ASensitiveDetector::EndOfEvent(G4HCofThisEvent*)
{ {
// Thread-ID für Datei // Thread-ID für Datei
@ -156,19 +273,29 @@ void ASensitiveDetector::EndOfEvent(G4HCofThisEvent*)
} }
// Hits schreiben // Hits schreiben
for(auto& [id, hit] : fTrackHitMap) { // for(auto& [id, hit] : fTrackHitMap) {
for(size_t i=0; i<fOutputColumns.size(); ++i) { // for(size_t i=0; i<fOutputColumns.size(); ++i) {
const auto& col = fOutputColumns[i]; // const auto& col = fOutputColumns[i];
if(outputMap.count(col)) // if(outputMap.count(col))
outputMap[col](hit, out); // outputMap[col](hit, out);
else // else
out << "NA"; // out << "NA";
if(i+1 < fOutputColumns.size()) out << "\t"; // if(i+1 < fOutputColumns.size()) out << "\t";
} // }
out << "\n"; // out << "\n";
// }
// // Map zurücksetzen
// fTrackHitMap.clear();
for(const auto& hit : fStepHits) {
out << hit.eventID << "\t"
<< hit.trackID << "\t"
<< hit.edep << "\t"
<< hit.z << "\t"
<< hit.r << "\n";
} }
// Map zurücksetzen fStepHits.clear();
fTrackHitMap.clear();
} }