DesignAnalysis/stopping_sensi.py
2026-06-17 09:56:04 +02:00

254 lines
No EOL
6.4 KiB
Python

#!/usr/bin/env python3
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from pathlib import Path
import sys
from matplotlib.lines import Line2D
sys.path.append(str(Path(__file__).resolve().parents[1]))
import plotstyle
MODE = "paper"
plotstyle.set_style(MODE)
WITH_ELECTRON = False
PLOT_ELECTRON_ONLY = False
PARTICLES_BASE_NEW = {
'proton': 'outBGO/threeBGO_prob_proton.0.hits',
'alpha': 'outBGO/threeBGO_prob_helium.0.hits',
'mu-': 'outBGO/threeBGO_prob_muon.0.hits',
'e-': 'outBGO/threeBGO_electron1000.0.hits'
}
colors = {
'proton': 'red',
'alpha': 'green',
'mu-': (0.5, 0.3, 0.8),
'e-': 'blue'
}
LABELS = {
'proton': 'Proton',
'alpha': 'Helium',
'mu-': 'Muon',
'e-': 'Electron'
}
LINSTYLES = {
2: '-',
4: '--',
6: ':'
}
THICKNESSES = [2, 4, 6]
DETECTOR_MAP = {
2: ['B1'],
4: ['B1', 'B2'],
6: ['B1', 'B2', 'B3']
}
def load_stopprob_data(filename, part_name, label):
try:
columns = ['event', 'track', 'det', 'primaryE', 'edep', 'nioni']
df = pd.read_csv(filename, sep=r'\s+', comment='#', names=columns)
df = df[df['track'] == 1].copy()
if len(df) == 0:
print(f" -> {label}: KEINE Primärteilchen gefunden!")
return None
all_stats = []
for thickness, detectors in DETECTOR_MAP.items():
df_sel = df[df['det'].isin(detectors)].copy()
if len(df_sel) == 0:
continue
df_sel['edep_abs'] = df_sel['edep'].abs()
df_event = (
df_sel
.groupby(['event', 'primaryE'])['edep_abs']
.sum()
.reset_index()
)
df_event['stopped'] = (df_event['edep_abs'] >= 0.999 * df_event['primaryE']).astype(int)
hit_stats = (
df_event
.groupby('primaryE')['stopped']
.agg(['mean', 'count'])
.reset_index()
)
hit_stats.columns = ['E0', 'stop_prob', 'N']
hit_stats['stop_prob'] *= 100.0
hit_stats['thickness'] = thickness
all_stats.append(hit_stats)
if len(all_stats) == 0:
return None
return pd.concat(all_stats, ignore_index=True)
except FileNotFoundError:
print(f" -> Datei '{filename}' nicht gefunden!")
return None
except Exception as e:
print(f" -> Fehler bei {label}: {e}")
return None
all_stats = {}
for part_g4 in PARTICLES_BASE_NEW.keys():
if part_g4 == 'e-' and not WITH_ELECTRON:
continue
if PLOT_ELECTRON_ONLY and part_g4 != 'e-':
continue
label = LABELS[part_g4]
filename = PARTICLES_BASE_NEW[part_g4]
print(f"\n=== {label} stopping probability ({part_g4}) ===")
print(f" Datei: {filename}")
df = load_stopprob_data(filename, part_g4, label)
if df is None:
print(f" -> {label}: KEINE DATEN")
continue
print(f" -> {label}: {len(df)} Energien")
for thickness in THICKNESSES:
df_thick = df[df['thickness'] == thickness].copy()
if len(df_thick) > 0:
all_stats[(part_g4, thickness)] = df_thick
else:
print(f" -> {label} / {thickness} cm: KEINE DATEN")
all_stats[(part_g4, thickness)] = None
print("\n=== Stopping probability [%] pro Startenergie ===")
for (part_g4, thickness), df in all_stats.items():
label = LABELS[part_g4]
thickness_label = f"{thickness} cm"
if df is not None:
print(f"\n{label} ({thickness_label}):")
print(df.round(3))
else:
print(f"\n{label} ({thickness_label}): KEINE DATEN")
plt.figure()
plotted_particles = set()
for (part_g4, thickness), stats in all_stats.items():
if stats is None or len(stats) == 0:
continue
color = colors.get(part_g4, 'black')
linestyle = LINSTYLES[thickness]
x = stats['E0']
y = stats['stop_prob']
n = stats['N']
yerr = np.sqrt((y / 100.0) * (1.0 - y / 100.0) / n) * 100.0 *3
# Energie bestimmen, bei der die 50%-Schwelle unterschritten wird
if np.any(y <= 50):
idx = np.where(y <= 50)[0][0]
if idx > 0:
# lineare Interpolation zwischen den beiden Punkten um E50 genauer zu bestimmen
x1, x2 = x.iloc[idx - 1], x.iloc[idx]
y1, y2 = y.iloc[idx - 1], y.iloc[idx]
E50 = x1 + (50.0 - y1) * (x2 - x1) / (y2 - y1)
else:
E50 = x.iloc[0]
plt.axvline(
E50,
color=color,
linestyle=linestyle,
linewidth=1,
alpha=0.7
)
plt.text(
E50 * 0.9,
45, # y-ausrichtung
f"{E50:.0f} MeV",
rotation=90,
color=color,
fontsize=22,
ha='left',
va='center'
)
# plt.errorbar(
# x, y, yerr=yerr,
# color=color,
# linestyle=linestyle,
# marker='None',
# linewidth=2,
# capsize=2,
# label=f"{LABELS[part_g4]} ({thickness} cm)"
# )
plt.plot(
x, y,
color=color,
linestyle=linestyle,
linewidth=2,
label=f"{LABELS[part_g4]} ({thickness} cm)"
)
plt.fill_between(
x,
y - yerr,
y + yerr,
color=color,
alpha=0.2
)
plotted_particles.add(part_g4)
plt.xscale('log')
plt.ylim(-2, 102)
plt.xlim(29, 3000)
plt.xlabel('Start energy $E_0$ in MeV')
#plt.ylabel("Stopping probability in %")
plt.ylabel(r"$\mathrm{Stopping\ probability\ in\ \%}$")
plt.grid(True, which='both', ls='--', lw=0.5)
legend_particle_handles = []
for part in ['proton', 'alpha', 'mu-', 'e-']:
if part not in plotted_particles:
continue
legend_particle_handles.append(
Line2D([0], [0], color=colors[part], lw=2, label=LABELS[part])
)
legend_thickness_handles = [
Line2D([0], [0], color='black', linestyle='-', lw=2, label='2 cm'),
Line2D([0], [0], color='black', linestyle='--', lw=2, label='4 cm'),
Line2D([0], [0], color='black', linestyle=':', lw=2, label='6 cm')
]
legend1 = plt.legend(handles=legend_particle_handles, loc='upper right', title='Particles')
legend2 = plt.legend(handles=legend_thickness_handles, loc='lower right', title='BGO thickness')
plt.gca().add_artist(legend1)
plt.tight_layout()
plotstyle.savefig("BGO_stopping_probability_246cm", category="BB")
plt.show()