Files
beta_shape_pnpi/create_comparison_plot.py
T
unzhakov 876e1e3ab8 Add massive neutrino support and improve CSV/CLI output
- Add neutrino mass parameter to SpectrumConfig and CLI interface
- Update PhaseSpace component to handle neutrino mass effects properly
- Update CSV headers to show basic endpoint and all transition types
- Add --csv-verbosity option to CLI with 'full' and 'concise' options
- Fix comparison plots to properly show linear scale variations
- Add comprehensive tests for neutrino mass functionality
2026-07-02 10:33:28 +03:00

145 lines
4.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
Script to create a comparison plot of total beta spectra for edge neutrino masses (1.5 keV and 2.5 keV)
"""
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# Input files
mass_1_5_csv = "/home/unzhakov/workspace/massive_nu_pr/pr144_nu_mass_1_50keV.csv"
mass_2_45_csv = "/home/unzhakov/workspace/massive_nu_pr/pr144_nu_mass_2_45keV.csv"
# Output file
output_png = (
"/home/unzhakov/workspace/massive_nu_pr/pr144_comparison_1_5_vs_2_45_keV.png"
)
print(f"Reading data from {mass_1_5_csv} and {mass_2_45_csv}...")
# Read CSV files, skipping metadata headers
# The metadata headers start with '#'
def read_csv_with_metadata(filepath):
with open(filepath, "r") as f:
lines = f.readlines()
# Find the line where data starts (not starting with '#')
data_start_line = 0
for i, line in enumerate(lines):
if not line.startswith("#"):
data_start_line = i
break
# Read the data
df = pd.read_csv(filepath, skiprows=data_start_line)
return df
# Read the data
df_1_5 = read_csv_with_metadata(mass_1_5_csv)
df_2_45 = read_csv_with_metadata(mass_2_45_csv)
print("Data loaded successfully.")
# Extract energy and spectrum data
energies_1_5 = df_1_5["energy_MeV"].values
spectrum_1_5 = df_1_5["spectrum"].values
energies_2_45 = df_2_45["energy_MeV"].values
spectrum_2_45 = df_2_45["spectrum"].values
print(
f"Energy range: {energies_1_5[0] * 1000:.1f} eV to {energies_1_5[-1] * 1000:.1f} eV"
)
# Create comparison plot
fig, ax = plt.subplots(figsize=(12, 8))
# Plot both spectra
ax.plot(energies_1_5 * 1000, spectrum_1_5, "b-", lw=2, label="m_ν = 1.5 keV")
ax.plot(energies_2_45 * 1000, spectrum_2_45, "r--", lw=2, label="m_ν = 2.45 keV")
# Set labels and title
ax.set_xlabel(r"Electron kinetic energy $E$ [keV]", fontsize=12)
ax.set_ylabel("Normalized Spectrum", fontsize=12)
ax.set_title(
"Pr144 -> Nd144 Beta Decay: Comparison of Neutrino Mass Effects\n"
"(1.5 keV vs 2.45 keV)",
fontsize=14,
)
# Set log scale for y-axis to see the endpoint region clearly
ax.set_yscale("log")
# Add grid
ax.grid(True, alpha=0.3)
# Add legend
ax.legend(fontsize=12)
# Focus on the endpoint region (last part of the spectrum)
# Find the energy range near the endpoint
max_energy_keV = max(energies_1_5) * 1000
# Show last 10 keV of the spectrum
start_energy_keV = max_energy_keV - 10.0
ax.set_xlim(start_energy_keV, max_energy_keV)
# Save the plot
plt.tight_layout()
plt.savefig(output_png, dpi=150, bbox_inches="tight")
print(f"Comparison plot saved to {output_png}")
# Also create a linear scale plot for the endpoint region
fig_linear, ax_linear = plt.subplots(figsize=(12, 6))
# Plot both spectra in linear scale
ax_linear.plot(energies_1_5 * 1000, spectrum_1_5, "b-", lw=2, label="m_ν = 1.5 keV")
ax_linear.plot(energies_2_45 * 1000, spectrum_2_45, "r--", lw=2, label="m_ν = 2.45 keV")
# Set labels and title
ax_linear.set_xlabel(r"Electron kinetic energy $E$ [keV]", fontsize=12)
ax_linear.set_ylabel("Normalized Spectrum", fontsize=12)
ax_linear.set_title(
"Pr144 -> Nd144 Beta Decay: Comparison of Neutrino Mass Effects (Endpoint Region)\n"
"(1.5 keV vs 2.45 keV) - Linear Scale",
fontsize=14,
)
# Set linear scale for y-axis
ax_linear.set_yscale("linear")
# Set y-axis limits to show the variation in the spectrum
# Find the min and max values in the endpoint region to set appropriate limits
min_spec_1_5 = np.min(spectrum_1_5[-100:]) # Last 100 points
max_spec_1_5 = np.max(spectrum_1_5[-100:])
min_spec_2_45 = np.min(spectrum_2_45[-100:])
max_spec_2_45 = np.max(spectrum_2_45[-100:])
overall_min = (
min(min_spec_1_5, min_spec_2_45) * 0.9
if min(min_spec_1_5, min_spec_2_45) > 0
else 0
)
overall_max = max(max_spec_1_5, max_spec_2_45) * 1.1
ax_linear.set_ylim(overall_min, overall_max)
# Add grid
ax_linear.grid(True, alpha=0.3)
# Add legend
ax_linear.legend(fontsize=12)
# Focus on the endpoint region (last part of the spectrum)
ax_linear.set_xlim(start_energy_keV, max_energy_keV)
# Save the linear plot
plt.tight_layout()
linear_output_png = (
"/home/unzhakov/workspace/massive_nu_pr/pr144_comparison_1_5_vs_2_45_keV_linear.png"
)
plt.savefig(linear_output_png, dpi=150, bbox_inches="tight")
print(f"Linear comparison plot saved to {linear_output_png}")