Compare commits

...

10 commits

Author SHA1 Message Date
Ava
f5e1a55e29 implement gdml 2026-03-09 13:48:13 +01:00
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
Ava
f003c1697a clean detectorname 2025-12-01 13:00:40 +01:00
Ava
22a080911f sort outfile 2025-12-01 12:54:53 +01:00
Ava
f193790483 external filename 2025-12-01 12:19:23 +01:00
Ava
6c121232f8 first running sample with outfile 2025-11-27 14:17:58 +01:00
Ava
f6596f7fcb add gitignore 2025-11-27 10:56:55 +01:00
20 changed files with 1244 additions and 259 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
build

View file

@ -2,18 +2,30 @@ cmake_minimum_required(VERSION 3.2 FATAL_ERROR)
project(Tutorial)
find_package(Geant4 REQUIRED ui_all vis_all)
# Nur einmal find_package, mit allen nötigen Features
find_package(Geant4 REQUIRED ui_all vis_all gdml)
# Setze Include-Verzeichnisse
include(${Geant4_USE_FILE})
include_directories(${PROJECT_SOURCE_DIR}/include)
# Sammle alle .cc Dateien
file(GLOB sources ${PROJECT_SOURCE_DIR}/src/*.cc)
# Entferne unerwünschte Dateien
list(REMOVE_ITEM sources
${PROJECT_SOURCE_DIR}/src/ADetectorConstructionv2.cc
${PROJECT_SOURCE_DIR}/src/ASensitiveDetectorv2.cc
${PROJECT_SOURCE_DIR}/src/ARunMessenger.cc
${PROJECT_SOURCE_DIR}/src/ARunActionv2.cc
)
# Makros kopieren
file(GLOB MACRO_FILES "macros/*.mac")
file(COPY ${MACRO_FILES} DESTINATION ${CMAKE_BINARY_DIR}/)
# Executable erstellen
add_executable(sim sim.cc ${sources})
target_link_libraries(sim ${Geant4_LIBRARIES})
add_custom_target(Tutorial DEPENDS sim)
# Geant4 Libraries verlinken
target_link_libraries(sim PUBLIC ${Geant4_LIBRARIES})

80
gdml/bgo.gdml Normal file
View file

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<gdml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://service-spi.web.cern.ch/service-spi/app/releases/GDML/schema/gdml.xsd">
<define>
<position name="origin" unit="cm" x="0" y="0" z="0" />
</define>
<materials>
<element Z="1." formula="H" name="H">
<atom type="A" value="1.0079"/>
</element>
<element Z="6." formula="C" name="C">
<atom type="A" value="12.011"/>
</element>
<element Z="7." formula="N" name="N">
<atom type="A" value="14.007"/>
</element>
<element Z="8." formula="O" name="O">
<atom type="A" value="15.999"/>
</element>
<element Z="32." formula="Ge" name="Ge">
<atom type="A" value="72.63"/>
</element>
<element Z="83." formula="Bi" name="Bi">
<atom type="A" value="208.98"/>
</element>
<material Z="14." formula="Si" name="Silicon">
<D value="2.3296" unit="g/cm3"/>
<atom type="A" value="28.0855"/>
</material>
<material name="HiVacuum" formula="Vacuum">
<D value="1.29e-16" unit="g/cm3"/>
<fraction n="0.7" ref="N"/>
<fraction n="0.3" ref="O"/>
</material>
<material name="BGO" formula="BGO">
<D value="7.13" unit="g/cm3"/>
<composite n="12" ref="O"/>
<composite n="3" ref="Ge"/>
<composite n="4" ref="Bi"/>
</material>
<material name="BC430" formula="BC430">
<D value="1.032" unit="g/cm3"/>
<composite n="523" ref="H"/>
<composite n="472" ref="C"/>
</material>
</materials>
<solids>
<sphere name="world" rmin="0" rmax="25" deltaphi="360" deltatheta="180" aunit="deg" lunit="cm"/>
<tube name="bgo_solid" rmin="0" rmax="8" deltaphi="2*pi" z="10" aunit="radian" lunit="cm"/>
</solids>
<structure>
<volume name="BGO_vol">
<materialref ref="BGO"/>
<solidref ref="bgo_solid"/>
<auxiliary auxtype="sensi" auxvalue="BGO" auxunit="name"/>
</volume>
<volume name="World">
<materialref ref="HiVacuum"/>
<solidref ref="world"/>
<physvol>
<volumeref ref="BGO_vol"/>
<positionref ref="origin"/>
</physvol>
</volume>
</structure>
<setup name="Default" version="1.0">
<world ref="World"/>
</setup>
</gdml>

View file

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8"?>
<gdml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://service-spi.web.cern.ch/service-spi/app/releases/GDML/schema/gdml.xsd">
<define>
<position name="origin" unit="cm" x="0" y="0" z="0"/>
</define>
<materials>
<element Z="1" name="H">
<atom value="1.0079"/>
</element>
<element Z="6" name="C">
<atom value="12.011"/>
</element>
<element Z="7" name="N">
<atom value="14.007"/>
</element>
<element Z="8" name="O">
<atom value="15.999"/>
</element>
<element Z="32" name="Ge">
<atom value="72.63"/>
</element>
<element Z="83" name="Bi">
<atom value="208.98"/>
</element>
<material name="HiVacuum">
<D value="1.29e-16" unit="g/cm3"/>
<fraction n="0.7" ref="N"/>
<fraction n="0.3" ref="O"/>
</material>
<material name="BGO">
<D value="7.13" unit="g/cm3"/>
<composite n="12" ref="O"/>
<composite n="3" ref="Ge"/>
<composite n="4" ref="Bi"/>
</material>
</materials>
<solids>
<sphere name="world" rmin="0" rmax="25"
deltaphi="360"
deltatheta="180"
aunit="deg"
lunit="cm"/>
<tube name="bgo_cylinder"
rmin="0"
rmax="2.5"
z="2"
deltaphi="360"
aunit="deg"
lunit="cm"/>
</solids>
<structure>
<volume name="BGO_vol">
<materialref ref="BGO"/>
<solidref ref="bgo_cylinder"/>
<auxiliary auxtype="sensi" auxvalue="BGO"/>
</volume>
<volume name="World">
<materialref ref="HiVacuum"/>
<solidref ref="world"/>
<physvol>
<volumeref ref="BGO_vol"/>
<positionref ref="origin"/>
</physvol>
</volume>
</structure>
<setup name="Default" version="1.0">
<world ref="World"/>
</setup>
</gdml>

115
gdml/shower_setup1.gdml Normal file
View file

@ -0,0 +1,115 @@
<?xml version="1.0" encoding="UTF-8"?>
<gdml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://service-spi.web.cern.ch/service-spi/app/releases/GDML/schema/gdml.xsd">
<define>
<position name="origin" unit="cm" x="0" y="0" z="0"/>
</define>
<materials>
<!-- Elemente -->
<element Z="1" formula="H" name="H"><atom type="A" value="1.0079"/></element>
<element Z="6" formula="C" name="C"><atom type="A" value="12.011"/></element>
<element Z="8" formula="O" name="O"><atom type="A" value="15.999"/></element>
<element Z="14" formula="Si" name="Si"><atom type="A" value="28.0855"/></element>
<element Z="32" formula="Ge" name="Ge"><atom type="A" value="72.63"/></element>
<element Z="83" formula="Bi" name="Bi"><atom type="A" value="208.98"/></element>
<!-- Materialien -->
<material name="HiVacuum" formula="Vacuum">
<D value="1.29e-16" unit="g/cm3"/>
<fraction n="0.7" ref="H"/>
<fraction n="0.3" ref="O"/>
</material>
<material name="BGO" formula="BGO">
<D value="7.13" unit="g/cm3"/>
<composite n="12" ref="O"/>
<composite n="3" ref="Ge"/>
<composite n="4" ref="Bi"/>
</material>
<material name="Silicon">
<D value="2.3296" unit="g/cm3"/>
<fraction n="1" ref="Si"/>
</material>
</materials>
<solids>
<box name="World" x="50" y="50" z="100" lunit="cm"/>
<box name="SSD_solid" x="5" y="5" z="0.025" lunit="cm"/>
<box name="BGO_solid" x="5" y="5" z="2.0" lunit="cm"/>
</solids>
<structure>
<!-- Layer Volumes mit Transparenz -->
<volume name="SSD1">
<materialref ref="Silicon"/>
<solidref ref="SSD_solid"/>
<auxiliary auxtype="sensi" auxvalue="shower_setup"/>
<auxiliary auxtype="VisAttributes" auxvalue="orange 0.6"/>
</volume>
<volume name="BGO1">
<materialref ref="BGO"/>
<solidref ref="BGO_solid"/>
<auxiliary auxtype="sensi" auxvalue="shower_setup"/>
<auxiliary auxtype="VisAttributes" auxvalue="green 0.6"/>
</volume>
<volume name="SSD2">
<materialref ref="Silicon"/>
<solidref ref="SSD_solid"/>
<auxiliary auxtype="sensi" auxvalue="shower_setup"/>
<auxiliary auxtype="VisAttributes" auxvalue="orange 0.6"/>
</volume>
<volume name="BGO2">
<materialref ref="BGO"/>
<solidref ref="BGO_solid"/>
<auxiliary auxtype="sensi" auxvalue="shower_setup"/>
<auxiliary auxtype="VisAttributes" auxvalue="green 0.6"/>
</volume>
<volume name="SSD3">
<materialref ref="Silicon"/>
<solidref ref="SSD_solid"/>
<auxiliary auxtype="sensi" auxvalue="shower_setup"/>
<auxiliary auxtype="VisAttributes" auxvalue="orange 0.6"/>
</volume>
<volume name="BGO3">
<materialref ref="BGO"/>
<solidref ref="BGO_solid"/>
<auxiliary auxtype="sensi" auxvalue="shower_setup"/>
<auxiliary auxtype="VisAttributes" auxvalue="green 0.6"/>
</volume>
<volume name="SSD4">
<materialref ref="Silicon"/>
<solidref ref="SSD_solid"/>
<auxiliary auxtype="sensi" auxvalue="shower_setup"/>
<auxiliary auxtype="VisAttributes" auxvalue="orange 0.6"/>
</volume>
<!-- World Volume mit allen Layern physisch -->
<volume name="World_vol">
<materialref ref="HiVacuum"/>
<solidref ref="World"/>
<physvol><volumeref ref="SSD1"/><position unit="cm" x="0" y="0" z="0.025"/></physvol>
<physvol><volumeref ref="BGO1"/><position unit="cm" x="0" y="0" z="1.55"/></physvol>
<physvol><volumeref ref="SSD2"/><position unit="cm" x="0" y="0" z="3.075"/></physvol>
<physvol><volumeref ref="BGO2"/><position unit="cm" x="0" y="0" z="4.6"/></physvol>
<physvol><volumeref ref="SSD3"/><position unit="cm" x="0" y="0" z="6.125"/></physvol>
<physvol><volumeref ref="BGO3"/><position unit="cm" x="0" y="0" z="7.65"/></physvol>
<physvol><volumeref ref="SSD4"/><position unit="cm" x="0" y="0" z="9.175"/></physvol>
</volume>
</structure>
<setup name="Default" version="1.0">
<world ref="World_vol"/>
</setup>
</gdml>

View file

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

View file

@ -2,48 +2,34 @@
#define ADETECTORCONSTRUCTION_HH
#include "G4VUserDetectorConstruction.hh"
#include "G4UImessenger.hh"
#include "G4Cache.hh"
#include "G4Box.hh"
#include "G4LogicalVolume.hh"
#include "G4VPhysicalVolume.hh"
#include "G4PVPlacement.hh"
#include "G4Material.hh"
#include "G4NistManager.hh"
#include "G4SystemOfUnits.hh"
#include "G4UnitsTable.hh"
#include "G4VisAttributes.hh"
#include "G4Color.hh"
#include "G4SDManager.hh"
#include "ASensitiveDetector.hh"
#include "G4UImessenger.hh"
#include "G4Cache.hh"
#include "G4UImessenger.hh"
#include "G4Cache.hh"
#include "G4GDMLParser.hh"
#include "G4String.hh"
#include <vector>
//#include "G4GDMLParser.hh"
class G4LogicalVolume;
class G4VPhysicalVolume;
class ASensitiveDetector;
class ADetectorConstruction : public G4VUserDetectorConstruction, public G4UImessenger
class ADetectorConstruction : public G4VUserDetectorConstruction
{
public:
ADetectorConstruction();
virtual ~ADetectorConstruction();
virtual G4VPhysicalVolume *Construct();
virtual G4VPhysicalVolume* Construct(); // GDML laden
virtual void ConstructSDandField(); // SD setzen
void ConstructSDandField();
void SetGDMLFile(const G4String& file); // GDML-Datei setzen
ASensitiveDetector* GetSensitiveDetector() const { return fSD; }
private:
std::vector<G4LogicalVolume*> detectorVolumes;
G4GDMLParser fParser; // GDML Parser
G4String fGDMLFile; // GDML Datei
ASensitiveDetector* fSD; // Sensitive Detector
std::vector<G4LogicalVolume*> detectorVolumes; // Alle Volumes mit SD
};
#endif

34
include/AMessenger.hh Normal file
View file

@ -0,0 +1,34 @@
#pragma once
#include "G4UImessenger.hh"
#include "G4UIcmdWithAString.hh"
#include "G4UIcmdWithADoubleAndUnit.hh"
class ASensitiveDetector;
class APrimaryGenerator;
class ADetectorConstruction;
class AMessenger : public G4UImessenger
{
public:
// Konstruktor: SD, optional Primärgenerator, optional DetectorConstruction
AMessenger(ASensitiveDetector* sd,
APrimaryGenerator* generator = nullptr,
ADetectorConstruction* detector = nullptr);
~AMessenger();
// UI-Kommandos verarbeiten
void SetNewValue(G4UIcommand* cmd, G4String value) override;
private:
ASensitiveDetector* fSD; // Referenz zum SensitiveDetector
APrimaryGenerator* fGenerator; // Referenz zum Primärgenerator
ADetectorConstruction* fDetector; // Referenz zur DetectorConstruction für GDML
// UI-Kommandos
G4UIcmdWithAString* fOutputFileCmd;
G4UIcmdWithAString* fParticleTypeCmd;
G4UIcmdWithADoubleAndUnit* fEnergyCmd;
G4UIcmdWithAString* fOutputColumnsCmd;
G4UIcmdWithAString* fGDMLFileCmd; // Neu: GDML-Datei setzen
};

View file

@ -13,10 +13,15 @@ public:
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:
G4ParticleGun *fParticleGun;
G4double fParticleEnergy;
G4String fParticleName;
};
#endif

View file

@ -1,28 +1,149 @@
// #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
#define ASENSITIVEDETECTOR_HH
#include "G4VSensitiveDetector.hh"
#include "G4HCofThisEvent.hh"
#include "G4TouchableHistory.hh"
#include "G4Step.hh"
#include "G4Track.hh"
#include "G4SystemOfUnits.hh"
#include "G4UnitsTable.hh"
#include <unordered_map>
#include <fstream>
#include <functional>
#include <map>
#include <vector>
class AMessenger;
//
// Makro für die OutputMap gleiche Logik wie beim Kollegen
//
#define OUTMAP [](const HitInfo& hit, std::ostream& out)
//#define OUTMAP [&, safeString, safeDouble, safeVec3](const HitInfo& hit, std::ostream& out)
class ASensitiveDetector : public G4VSensitiveDetector
{
public:
ASensitiveDetector(G4String);
ASensitiveDetector(G4String name);
~ASensitiveDetector();
virtual void Initialize(G4HCofThisEvent* hce) override;
virtual G4bool ProcessHits(G4Step* step, G4TouchableHistory* touch) override;
virtual void EndOfEvent(G4HCofThisEvent* hce) override;
void SetOutputFilename(const G4String& f) { fOutputFilename = f; }
//void SetOutputColumns(const std::vector<G4String>& cols) { fOutputColumns = cols; }
void SetOutputColumns(const std::vector<G4String>& cols);
void SetMessenger(AMessenger* m) { fMessenger = m; }
private:
G4double fTotalEnergyDeposited;
AMessenger* fMessenger = nullptr;
G4String fOutputFilename;
G4int fCurrentEventID = -1;
virtual void Initialize(G4HCofThisEvent *) override; //hit collection
virtual void EndOfEvent(G4HCofThisEvent *) override;
public:
//
// HitInfo enthält ALLE üblichen Parameter
//
struct HitInfo
{
// --- Basis-identifikation ---
G4int eventID; // Nummer des Events
G4int trackID; // Track ID
G4int parentID; // Parent Track ID
virtual G4bool ProcessHits(G4Step *, G4TouchableHistory *);
// --- Teilchen ---
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.)
{}
};
private:
//
// 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;
//std::vector<StepHit> fStepHits;
//
// interne Hilfsfunktionen
//
void InitializeOutputMap();
};
#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

View file

@ -2,5 +2,5 @@
/run/initialize
/run/beamOn 1000
/run/beamOn 1

20
macros/test_gdml.mac Normal file
View file

@ -0,0 +1,20 @@
# Anzahl Threads
/run/numberOfThreads 1
# --- Output-Datei ---
/my/outputFilename outfiles/gdml_test_zylinder.hits
# --- Partikeltyp ---
/my/particleType e-
# --- Partikelenergie ---
/my/particleEnergy 100 MeV
# --- Output-Spalten ---
/my/outputColumns event track parent part pdg edep ekin proc det
# --- Initialisierung Geant4 ---
/run/initialize
# --- Simulation starten (z.B. 50.000 Hits) ---
/run/beamOn 1000

View file

@ -1,6 +1,6 @@
/run/initialize
/vis/open OGL 600x600-0+x600
/vis/open OGLI 600x600-0+0 # OGLI = OpenGL Immediate
/vis/viewer/set/viewpointVector 1 1 1
/vis/viewer/set/autoRefresh true

140
sim.cc
View file

@ -1,7 +1,4 @@
//Including header files
#include <iostream>
// Including Geant4 stuff, G4MT is for multithreading
#include "G4RunManager.hh"
#include "G4MTRunManager.hh"
#include "G4UImanager.hh"
@ -15,52 +12,121 @@
int main(int argc, char** argv)
{
//G4UIExecutive *ui = new G4UIExecutive(argc, argv);
G4UIExecutive *ui = 0;
if (argc == 1)
{
ui = new G4UIExecutive(argc, argv);
// --- UI: Interaktiv, falls keine Argumente ---
G4UIExecutive* ui = (argc == 1) ? new G4UIExecutive(argc, argv) : nullptr;
#ifdef G4MULTITHREADED
G4MTRunManager* runManager = new G4MTRunManager;
#else
G4RunManager* runManager = new G4RunManager;
#endif
// --- Physics ---
runManager->SetUserInitialization(new APhysicsList());
// --- Detector Construction ---
ADetectorConstruction* detector = new ADetectorConstruction();
runManager->SetUserInitialization(detector);
// GDML-Datei setzen (1. Argument)
if(argc > 1) {
detector->SetGDMLFile(argv[1]);
}
#ifdef G4MULTITHREADED
G4MTRunManager *runManager = new G4MTRunManager;
#else
G4RunManager *runManager = new G4RunManager;
#endif
// --- User Actions ---
runManager->SetUserInitialization(new AActionInitialization(detector->GetSensitiveDetector()));
// Physics list
runManager->SetUserInitialization(static_cast<G4VUserPhysicsList*>(new APhysicsList()));
// Detector Construction
runManager->SetUserInitialization(static_cast<G4VUserDetectorConstruction*>(new ADetectorConstruction()));
// Action initialization
runManager->SetUserInitialization(static_cast<G4VUserActionInitialization*>(new AActionInitialization()));
G4VisManager *visManager = new G4VisExecutive();
// --- Visualization ---
G4VisManager* visManager = new G4VisExecutive();
visManager->Initialize();
G4UImanager *UImanager = G4UImanager::GetUIpointer();
// --- UI Manager ---
G4UImanager* UImanager = G4UImanager::GetUIpointer();
if (ui)
{
G4cout << "ui exists" << G4endl;
UImanager->ApplyCommand("/control/execute vis.mac");
if(ui) {
// Interaktiv
UImanager->ApplyCommand("/control/execute ../macros/vis_shower.mac");
ui->SessionStart();
delete ui;
}
else
{
G4cout << "ui does not exists" << G4endl;
G4String command = "/control/execute ";
G4String fileName = argv[1];
UImanager->ApplyCommand(command + fileName);
else if(argc > 2) {
// Batch mit Macro
G4String macroFile = argv[2];
UImanager->ApplyCommand("/control/execute " + macroFile);
}
else {
// Batch ohne Macro
UImanager->ApplyCommand("/run/initialize");
}
//clean up
// --- Clean up ---
delete runManager;
delete visManager;
if (ui) delete ui;
return 0;
}
// #include "G4RunManager.hh"
// #include "G4MTRunManager.hh"
// #include "G4UImanager.hh"
// #include "G4VisManager.hh"
// #include "G4VisExecutive.hh"
// #include "G4UIExecutive.hh"
// #include "APhysicsList.hh"
// #include "ADetectorConstruction.hh"
// #include "AActionInitialization.hh"
// int main(int argc, char** argv)
// {
// // UI Executive für interaktive Sitzung
// G4UIExecutive* ui = nullptr;
// if(argc == 1) {
// ui = new G4UIExecutive(argc, argv);
// }
// // Run Manager (MT oder Single Thread)
// #ifdef G4MULTITHREADED
// G4MTRunManager* runManager = new G4MTRunManager;
// #else
// G4RunManager* runManager = new G4RunManager;
// #endif
// // Physics
// runManager->SetUserInitialization(new APhysicsList());
// // Detector
// G4String gdmlFile = (argc > 1) ? argv[1] : "";
// ADetectorConstruction* detector = new ADetectorConstruction(gdmlFile);
// runManager->SetUserInitialization(detector);
// // Actions
// runManager->SetUserInitialization(new AActionInitialization(detector->GetSensitiveDetector()));
// // Initialize RunManager
// runManager->Initialize();
// // Visualization
// G4VisManager* visManager = new G4VisExecutive();
// visManager->Initialize();
// // UI Manager
// G4UImanager* UImanager = G4UImanager::GetUIpointer();
// if(ui) {
// // Interaktive Sitzung: vis.mac automatisch ausführen
// UImanager->ApplyCommand("/control/execute ../macros/vis.mac");
// ui->SessionStart();
// } else if(argc > 2) {
// // Batch: Macro ausführen
// G4String macroFile = argv[2];
// UImanager->ApplyCommand("/control/execute " + macroFile);
// }
// // Clean up
// delete runManager;
// delete visManager;
// if(ui) delete ui;
// return 0;
// }

View file

@ -1,40 +1,28 @@
#include "AActionInitialization.hh"
//#include "PrimaryGeneratorAction.hh"
#include "AMessenger.hh"
#include "APrimaryGenerator.hh"
#include "ARunAction.hh"
AActionInitialization::AActionInitialization()
AActionInitialization::AActionInitialization(ASensitiveDetector* sd)
: G4VUserActionInitialization(), fSD(sd)
{
}
AActionInitialization::~AActionInitialization()
AActionInitialization::~AActionInitialization() {}
void AActionInitialization::Build() const
{
// Primärgenerator
APrimaryGenerator* primaryGen = new APrimaryGenerator();
SetUserAction(primaryGen);
AMessenger* messenger = new AMessenger(fSD, primaryGen);
// RunAction
SetUserAction(new ARunAction());
}
void AActionInitialization::BuildForMaster() const
{
// This is needed to avoid problems due to multithreading when writing the data.
ARunAction *runAction = new ARunAction();
SetUserAction(runAction);
SetUserAction(new ARunAction());
}
void AActionInitialization::Build() const
{
// PrimaryGenerator and SteppingAction do not have to be set in BuildForMaster because they only
// regard individual threads.
APrimaryGenerator *generator = new APrimaryGenerator();
SetUserAction(generator);
ARunAction *runAction = new ARunAction();
SetUserAction(runAction);
// SteppingAction *steppingAction = new SteppingAction();
// SetUserAction(steppingAction);
}
// void UserActionInitialization::Build() const {
// SetUserAction(new PrimaryGeneratorAction);
// }
//
// void UserActionInitialization::BuildForMaster() const {
// }

View file

@ -1,114 +1,101 @@
#include "ADetectorConstruction.hh"
#include "ASensitiveDetector.hh"
#include "AMessenger.hh"
#include "G4LogicalVolumeStore.hh"
#include "G4SDManager.hh"
#include "G4GDMLAuxStructType.hh"
#include "G4SystemOfUnits.hh"
#include "G4Tubs.hh"
#include "G4Box.hh"
#include "G4VisAttributes.hh"
#include "G4Color.hh"
#include "G4PVPlacement.hh"
#include "G4NistManager.hh"
#include "G4ios.hh"
ADetectorConstruction::ADetectorConstruction()
: fSD(nullptr)
{
// Ein einziges SensitiveDetector erzeugen
fSD = new ASensitiveDetector("shower_setup");
// Messenger für den SD erzeugen
AMessenger* messenger = new AMessenger(fSD);
fSD->SetMessenger(messenger);
}
ADetectorConstruction::~ADetectorConstruction()
{
delete fSD; // SD + Messenger aufräumen
}
G4VPhysicalVolume *ADetectorConstruction::Construct()
void ADetectorConstruction::SetGDMLFile(const G4String& file)
{
G4bool checkOverlaps = true;
fGDMLFile = file;
}
// --- Materials ---
G4NistManager *nist = G4NistManager::Instance();
//G4Material *worldMat = nist->FindOrBuildMaterial("G4_AIR");
G4Material *worldMat = nist->FindOrBuildMaterial("G4_Galactic");
G4Material *ssdMat = nist->FindOrBuildMaterial("G4_Si");
G4Material *bgoMat = nist->FindOrBuildMaterial("G4_BGO");
// --- World volume ---
G4double worldSize = 1.0 * m;
G4Box *solidWorld = new G4Box("solidWorld", 0.5*worldSize, 0.5*worldSize, 0.5*worldSize);
G4LogicalVolume *logicWorld = new G4LogicalVolume(solidWorld, worldMat, "logicalWorld");
G4VPhysicalVolume *physWorld =
new G4PVPlacement(0, G4ThreeVector(), logicWorld,
"physWorld", 0, false, 0, checkOverlaps);
// --- Layer sizes ---
G4double sizeXY = 5.0 * cm;
G4double thSSD = 0.5 * mm;
G4double thBGO = 20.0 * mm;
G4double gap = 5.0 * mm;
// --- Startposition ---
G4double totalThickness = 4*thSSD + 3*thBGO + 6*gap;
G4double zPos = 0.0;
// --- Visualization ---
G4VisAttributes *ssdVis = new G4VisAttributes(G4Color(0.0, 0.0, 1.0, 0.6));
ssdVis->SetForceSolid(true);
G4VisAttributes *bgoVis = new G4VisAttributes(G4Color(0.0, 1.0, 0.0, 0.6));
bgoVis->SetForceSolid(true);
// --- Build SSD BGO SSD BGO SSD BGO SSD ---
for(int i = 0; i < 7; i++)
G4VPhysicalVolume* ADetectorConstruction::Construct()
{
if(fGDMLFile.empty())
{
G4bool isSSD = (i % 2 == 0);
G4double thickness = isSSD ? thSSD : thBGO;
G4Material *mat = isSSD ? ssdMat : bgoMat;
// G4String baseName = isSSD ? "SSD_" : "BGO_";
// baseName += std::to_string(i);
int ssdIndex = 1;
int bgoIndex = 1;
G4String baseName;
if(isSSD) {
baseName = "SSD" + std::to_string(ssdIndex);
ssdIndex++;
}
else {
baseName = "BGO" + std::to_string(bgoIndex);
bgoIndex++;
G4Exception("ADetectorConstruction::Construct()",
"NoGDMLFile",
FatalException,
"No GDML file specified.");
}
G4Box *solid = new G4Box(baseName,
0.5*sizeXY,
0.5*sizeXY,
0.5*thickness);
G4cout << "Loading GDML geometry: " << fGDMLFile << G4endl;
G4LogicalVolume *lv =
new G4LogicalVolume(solid, mat, baseName + "_logic");
// GDML-Datei einlesen
fParser.Read(fGDMLFile, false);
new G4PVPlacement(0,
G4ThreeVector(0. ,0. , zPos + 0.5*thickness),
lv,
baseName + "_phys",
logicWorld,
false,
i,
checkOverlaps);
// Weltvolumen aus GDML holen
G4VPhysicalVolume* world = fParser.GetWorldVolume();
// Farbe
if(isSSD)
lv->SetVisAttributes(ssdVis);
else
lv->SetVisAttributes(bgoVis);
// Für SD merken
detectorVolumes.push_back(lv);
// Update z
zPos += thickness + gap;
if(!world)
{
G4Exception("ADetectorConstruction::Construct()",
"InvalidGDML",
FatalException,
"GDML world volume not found.");
}
return physWorld;
G4cout << "GDML geometry successfully loaded." << G4endl;
// --- LogicalVolumes iterieren und SD zuweisen ---
detectorVolumes.clear();
auto lvStore = G4LogicalVolumeStore::GetInstance();
for(auto lv : *lvStore)
{
// AuxList vom GDML Parser holen
G4GDMLAuxListType auxList = fParser.GetVolumeAuxiliaryInformation(lv);
for(const auto& aux : auxList)
{
if(aux.type == "sensi")
{
lv->SetSensitiveDetector(fSD);
detectorVolumes.push_back(lv); // merken für SD-Registrierung
}
}
}
G4cout << "Assigned SensitiveDetector to " << detectorVolumes.size() << " volumes." << G4endl;
return world;
}
void ADetectorConstruction::ConstructSDandField()
{
ASensitiveDetector *sensDet = new ASensitiveDetector("MySensitiveDetector");
G4SDManager::GetSDMpointer()->AddNewDetector(sensDet);
// SD bei Geant4 registrieren
G4SDManager::GetSDMpointer()->AddNewDetector(fSD);
// alle SSDs und BGOs sensitive machen
for(size_t i = 0; i < detectorVolumes.size(); i++)
// Alle Layer bekommen denselben SD (bereits in Construct gesetzt)
for(auto lv : detectorVolumes)
{
detectorVolumes[i]->SetSensitiveDetector(sensDet);
lv->SetSensitiveDetector(fSD);
}
G4cout << "SensitiveDetector registered for " << detectorVolumes.size() << " volumes." << G4endl;
}

85
src/AMessenger.cc Normal file
View file

@ -0,0 +1,85 @@
#include "AMessenger.hh"
#include "ASensitiveDetector.hh"
#include "APrimaryGenerator.hh"
#include "ADetectorConstruction.hh"
#include "G4SystemOfUnits.hh"
#include "G4UIcmdWithAString.hh"
#include "G4UIcmdWithADoubleAndUnit.hh"
#include "G4UImanager.hh"
#include <sstream>
AMessenger::AMessenger(ASensitiveDetector* sd, APrimaryGenerator* generator, ADetectorConstruction* detector)
: fSD(sd), fGenerator(generator), fDetector(detector)
{
// Kommando: Output-Datei für SD
fOutputFileCmd = new G4UIcmdWithAString("/my/outputFilename", this);
fOutputFileCmd->SetGuidance("Set output filename for SD text output.");
fOutputFileCmd->SetParameterName("filename", false);
// Kommando: Partikeltyp
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: Partikelenergie
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: Output-Spalten
fOutputColumnsCmd = new G4UIcmdWithAString("/my/outputColumns", this);
fOutputColumnsCmd->SetGuidance("Set output columns and order (space separated). E.g.: event track parent part edep");
fOutputColumnsCmd->SetParameterName("columns", false);
fOutputColumnsCmd->AvailableForStates(G4State_PreInit, G4State_Idle);
// Kommando: GDML-Datei
fGDMLFileCmd = new G4UIcmdWithAString("/my/gdmlFile", this);
fGDMLFileCmd->SetGuidance("Set GDML input file");
fGDMLFileCmd->SetParameterName("filename", false);
fGDMLFileCmd->AvailableForStates(G4State_PreInit);
}
AMessenger::~AMessenger()
{
delete fOutputFileCmd;
delete fParticleTypeCmd;
delete fEnergyCmd;
delete fOutputColumnsCmd;
delete fGDMLFileCmd;
}
void AMessenger::SetNewValue(G4UIcommand* cmd, G4String value)
{
if (cmd == fOutputFileCmd && fSD)
{
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);
}
else if (cmd == fGDMLFileCmd && fDetector)
{
fDetector->SetGDMLFile(value);
}
}

View file

@ -3,29 +3,16 @@
APrimaryGenerator::APrimaryGenerator()
{
fParticleGun = new G4ParticleGun(1); // 1 particles per event
fParticleEnergy = 100.*MeV; // Default-Energie
fParticleName = "e-"; //default
//Particle position
G4double x = 0. * m;
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();
// possibilities: "e+","e-","gamma", ,"proton", "neutron"
G4ParticleDefinition *particle = particleTable->FindParticle("e-");
G4ThreeVector pos(0.,0.,-1.*cm);
G4ThreeVector mom(0.,0.,1.);
G4ParticleTable* particleTable = G4ParticleTable::GetParticleTable();
G4ParticleDefinition* particle = particleTable->FindParticle("e-");
fParticleGun->SetParticlePosition(pos);
fParticleGun->SetParticleMomentumDirection(mom);
fParticleGun->SetParticleEnergy(100 * MeV); //or GeV
fParticleGun->SetParticleDefinition(particle);
}
@ -36,6 +23,15 @@ APrimaryGenerator::~APrimaryGenerator()
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);
}

View file

@ -1,32 +1,404 @@
#include "ASensitiveDetector.hh"
#include <cmath>
// #include "G4Step.hh"
// #include "G4SystemOfUnits.hh"
// #include <iomanip>
ASensitiveDetector::ASensitiveDetector(G4String name) : G4VSensitiveDetector(name)
// 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 "AMessenger.hh"
#include "G4Event.hh"
#include "G4RunManager.hh"
#include "G4Threading.hh"
#include <filesystem>
#include <iostream>
ASensitiveDetector::ASensitiveDetector(G4String name)
: G4VSensitiveDetector(name), fOutputFilename("outfiles/shower_setup")
{
fTotalEnergyDeposited = 0.;
std::filesystem::create_directories("outfiles");
InitializeOutputMap();
if(fOutputColumns.empty()) {
fOutputColumns = {"event", "track", "parent", "part", "edep", "det"};
}
}
ASensitiveDetector::~ASensitiveDetector()
ASensitiveDetector::~ASensitiveDetector() {}
void ASensitiveDetector::Initialize(G4HCofThisEvent*)
{
fTrackHitMap.clear();
//fStepHits.clear();
}
void ASensitiveDetector::Initialize(G4HCofThisEvent *)
// 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 = {
// {"event", OUTMAP { out << hit.eventID; }},
// {"track", OUTMAP { out << hit.trackID; }},
// {"parent", OUTMAP { out << hit.parentID; }},
// {"part", OUTMAP { out << safeString(hit.particleName); }},
// {"pdg", OUTMAP { out << hit.pdg; }},
// {"ekin", OUTMAP { out << safeDouble(hit.ekin/MeV); }},
// {"edep", OUTMAP { out << safeDouble(hit.edep/MeV); }},
// {"x", OUTMAP { out << safeDouble(hit.postPos.x()/mm); }},
// {"y", OUTMAP { out << safeDouble(hit.postPos.y()/mm); }},
// {"z", OUTMAP { out << safeDouble(hit.postPos.z()/mm); }},
// {"pos", OUTMAP {
// 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(); }},
// {"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 << safeString(hit.processName); }},
// {"det", OUTMAP { out << safeString(hit.cleanName); }}
// };
// }
void ASensitiveDetector::InitializeOutputMap()
{
fTotalEnergyDeposited = 0.;
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; }},
{"primary", OUTMAP { out<<hit.primaryName; }},
{"primaryE",OUTMAP { out<<hit.primaryEnergy; }},
{"edep", OUTMAP { out<<hit.edep; }},
{"ekin", OUTMAP { out<<hit.ekin; }},
{"x", OUTMAP { out<<hit.postPos.x(); }},
{"y", OUTMAP { out<<hit.postPos.y(); }},
{"z", OUTMAP { out<<hit.postPos.z(); }},
{"r", OUTMAP {
out<<std::sqrt(hit.postPos.x()*hit.postPos.x()
+ hit.postPos.y()*hit.postPos.y());
}},
{"dx", OUTMAP { out<<hit.postDir.x(); }},
{"dy", OUTMAP { out<<hit.postDir.y(); }},
{"dz", OUTMAP { out<<hit.postDir.z(); }},
{"global_t", OUTMAP { out<<hit.globalTime; }},
{"local_t", OUTMAP { out<<hit.localTime; }},
{"step", OUTMAP { out<<hit.stepLength; }},
{"proc", OUTMAP { out<<hit.processName; }},
{"det", OUTMAP { out<<hit.cleanName; }}
};
}
void ASensitiveDetector::EndOfEvent(G4HCofThisEvent *)
void ASensitiveDetector::SetOutputColumns(
const std::vector<G4String>& cols)
{
G4cout << "Deposited energy: " << fTotalEnergyDeposited << G4endl;
}
G4bool ASensitiveDetector::ProcessHits(G4Step *aStep, G4TouchableHistory *touchHist)
{
G4double fEnergyDeposited = aStep->GetTotalEnergyDeposit();
if(fEnergyDeposited > 0)
for(const auto& c : cols)
{
fTotalEnergyDeposited += fEnergyDeposited;
if(!outputMap.count(c))
{
G4Exception("InvalidColumn",
"BadColumn",
FatalException,
("Unknown column: " + c).c_str());
}
}
fOutputColumns = cols;
}
// G4bool ASensitiveDetector::ProcessHits(G4Step* step, G4TouchableHistory*)
// {
// if(!step) return false;
// G4double edep = step->GetTotalEnergyDeposit();
// if(edep <= 0) return false;
// auto track = step->GetTrack();
// auto post = step->GetPostStepPoint();
// if(!track || !post) return false;
// auto pos = post->GetPosition();
// StepHit hit;
// hit.eventID = G4RunManager::GetRunManager()
// ->GetCurrentEvent()->GetEventID();
// hit.trackID = track->GetTrackID();
// hit.parentID = track->GetParentID();
// hit.particleName = track->GetDefinition()->GetParticleName();
// hit.edep = edep / MeV;
// hit.z = pos.z() / cm;
// hit.r = std::sqrt(pos.x()*pos.x() + pos.y()*pos.y()) / cm;
// fStepHits.push_back(hit);
// return true;
// }
G4bool ASensitiveDetector::ProcessHits(G4Step* step, G4TouchableHistory*)
{
if(!step) return false;
G4Track* track = step->GetTrack();
if(!track) return false;
const G4Event* event =
G4RunManager::GetRunManager()->GetCurrentEvent();
if(!event) return false;
G4int trackID = track->GetTrackID();
G4int eventID = event->GetEventID();
// Referenz auf Track-Container
HitInfo& hit = fTrackHitMap[trackID];
// ===== Basis =====
hit.eventID = eventID;
hit.trackID = trackID;
hit.parentID = track->GetParentID();
if(track->GetDefinition())
{
hit.particleName =
track->GetDefinition()->GetParticleName();
hit.pdg =
track->GetDefinition()->GetPDGEncoding();
}
hit.ekin = track->GetKineticEnergy()/MeV;
// ===== Primärinfo =====
if(auto vertex = event->GetPrimaryVertex())
{
if(auto prim = vertex->GetPrimary())
{
if(auto code = prim->GetG4code())
{
hit.primaryName =
code->GetParticleName();
hit.primaryEnergy =
prim->GetKineticEnergy()/MeV;
}
}
}
// ===== Energie aufsummieren =====
hit.edep += step->GetTotalEnergyDeposit()/MeV;
// ===== Step Info =====
auto pre = step->GetPreStepPoint();
auto post = step->GetPostStepPoint();
if(pre && post)
{
hit.prePos = pre->GetPosition()/mm;
hit.postPos = post->GetPosition()/mm;
hit.preDir = pre->GetMomentumDirection();
hit.postDir = post->GetMomentumDirection();
hit.globalTime = post->GetGlobalTime()/ns;
hit.localTime = post->GetLocalTime()/ns;
hit.stepLength += step->GetStepLength()/mm;
hit.processName =
post->GetProcessDefinedStep()
? post->GetProcessDefinedStep()->GetProcessName()
: "none";
if(pre->GetTouchable())
{
auto vol = pre->GetTouchable()->GetVolume();
if(vol)
{
hit.detectorName = vol->GetName();
auto pos = hit.detectorName.find("_phys");
hit.cleanName =
(pos == std::string::npos)
? hit.detectorName
: hit.detectorName.substr(0,pos);
}
}
}
return true;
}
// void ASensitiveDetector::EndOfEvent(G4HCofThisEvent*)
// {
// // Thread-ID für Datei
// G4int tid = G4Threading::G4GetThreadId();
// // Thread-local Datei
// thread_local std::ofstream out;
// // Datei öffnen, wenn noch nicht offen
// if(!out.is_open()) {
// 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;
// }
// // Header einmal pro Datei
// for(size_t i=0; i<fOutputColumns.size(); ++i) {
// out << fOutputColumns[i];
// if(i+1 < fOutputColumns.size()) out << "\t";
// }
// out << "\n";
// }
// // Hits schreiben
// // for(auto& [id, hit] : fTrackHitMap) {
// // for(size_t i=0; i<fOutputColumns.size(); ++i) {
// // 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";
// // }
// // // 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";
// }
// fStepHits.clear();
// }
void ASensitiveDetector::EndOfEvent(G4HCofThisEvent*)
{
G4int tid = G4Threading::G4GetThreadId();
thread_local std::ofstream out;
if(!out.is_open())
{
std::filesystem::create_directories("outfiles");
std::string filename =
fOutputFilename + "_" +
std::to_string(tid) + ".hits";
//out.open(filename, std::ios::app); //anhängen
out.open(filename, std::ios::out); //datei überschreieben
if(!out.is_open())
{
G4cerr << "Cannot open file "
<< filename << G4endl;
return;
}
// Header schreiben
for(size_t i=0;i<fOutputColumns.size();++i)
{
out << fOutputColumns[i];
if(i+1<fOutputColumns.size())
out << "\t";
}
out << "\n";
}
// ===== Daten schreiben =====
for(const auto& [id, hit] : fTrackHitMap)
{
for(size_t i=0;i<fOutputColumns.size();++i)
{
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";
}
fTrackHitMap.clear();
}