1
0
Fork 0
mirror of https://github.com/gwm17/spspy.git synced 2025-12-17 09:55:51 -05:00

added the ability to export excitation energy calibration data to CSV

modified:   .gitignore
	modified:   spspy/Spanc.py
	modified:   spspy/SpancUI.py
This commit is contained in:
alconley 2025-12-09 17:16:26 -05:00
parent 06d60e18b5
commit b2906cf5a8
3 changed files with 126 additions and 2 deletions

3
.gitignore vendored
View File

@ -5,4 +5,5 @@ __pycache__/
.vs/
*.sps
*.spanc
*.csv
*.csv
*.DS_Store

View File

@ -126,4 +126,82 @@ class Spanc:
for calibration in self.calibrations.values():
rxn = self.reactions[calibration.rxnName]
calibration.rho = rxn.convert_ejectile_KE_2_rho(rxn.calculate_ejectile_KE(calibration.excitation))
calibration.rhoErr = np.abs(rxn.convert_ejectile_KE_2_rho(rxn.calculate_ejectile_KE(calibration.excitation + calibration.excitationErr)) - calibration.rho)
calibration.rhoErr = np.abs(rxn.convert_ejectile_KE_2_rho(rxn.calculate_ejectile_KE(calibration.excitation + calibration.excitationErr)) - calibration.rho)
def get_excitation_curves(self,
x_min: float = -300.0,
x_max: float = 300.0,
n_bins: int = 601):
"""
Compute excitation-energy curves for every reaction by evaluating
Ex = reaction.calculate_excitation( rho(x) ) across a grid of
focal-plane positions.
Returns:
x_vals: array of FP bin centers
ex_curves: { rxn_name: Ex_array_in_MeV }
"""
# Bin centers (e.g. 601 values from -300 to 300)
x_vals = np.linspace(x_min, x_max, n_bins)
# ρ(x) uses your fitted polynomial a0 + a1 x + ... + aN x^N
params = self.fitter.get_parameters() # [a0, a1, ..., aN]
rho_vals = np.polyval(params[::-1], x_vals) # reverse order for numpy poly
ex_curves: dict[str, np.ndarray] = {}
for rxn_name, rxn in self.reactions.items():
ex_vals = np.array(
[rxn.calculate_excitation(rho) for rho in rho_vals],
dtype=float,
)
ex_curves[rxn_name] = ex_vals
return x_vals, ex_curves
def export_excitation_csv(self,
filename: str,
x_min: float = -300.0,
x_max: float = 300.0,
n_bins: int = 601):
"""
Export excitation-energy calibration table as CSV.
CSV format:
FP_x_mm, Ex_rxn1_MeV, Ex_rxn2_MeV, ...
FP_x_mm runs from x_min to x_max with n_bins steps (inclusive).
"""
import csv
import numpy as np
# Generate FP positions (601 values from -300 to 300)
x_vals = np.linspace(x_min, x_max, n_bins)
# Compute rho(x) using fitted polynomial
params = self.fitter.get_parameters() # [a0, a1, ..., aN]
rho_vals = np.polyval(params[::-1], x_vals)
# Compute excitation for each reaction
rxn_names = list(self.reactions.keys())
ex_mev = {rxn: [] for rxn in rxn_names}
for rho in rho_vals:
for rxn_name, rxn in self.reactions.items():
ex = rxn.calculate_excitation(rho)
ex_mev[rxn_name].append(ex)
# Write CSV
with open(filename, "w", newline="") as csvfile:
writer = csv.writer(csvfile)
# Header row
header = ["x_mm"] + [f"Ex_{rxn}_MeV" for rxn in rxn_names]
writer.writerow(header)
# Data rows
for i, x in enumerate(x_vals):
row = [f"{x:.6f}"]
for rxn in rxn_names:
row.append(f"{ex_mev[rxn][i]:.9f}")
writer.writerow(row)

View File

@ -95,6 +95,17 @@ class SpancGUI(QMainWindow):
fitOptionLayout.addWidget(QLabel("Polynomial Order", self.fitOptionGroup))
fitOptionLayout.addWidget(self.fitOrderBox)
fitOptionLayout.addWidget(self.fitButton)
# NEW: button to plot excitation curves for all reactions
self.exCurveButton = QPushButton("Plot Ex vs x", self.fitOptionGroup)
self.exCurveButton.clicked.connect(self.plot_excitation_curves)
fitOptionLayout.addWidget(self.exCurveButton)
# Button to export excitation calibration CSV
self.exportCSVButton = QPushButton("Export Ex(x) CSV", self.fitOptionGroup)
self.exportCSVButton.clicked.connect(self.handle_export_excitation_csv)
fitOptionLayout.addWidget(self.exportCSVButton)
self.fitOptionGroup.setLayout(fitOptionLayout)
fitLayout.addWidget(QLabel("Fit", self.fitCanvas))
@ -374,8 +385,42 @@ class SpancGUI(QMainWindow):
f"## Parameter Uncertanties (ua0 -> uaN): {np.array_str(self.spanc.fitter.get_parameter_errors(), precision=3)} \n \n"
f"## Residuals (x0 -> xN): {np.array_str(residuals, precision=3)} \n \n"
f"## Studentized Residuals (x0 -> xN): {np.array_str(studentizedResiduals, precision=3)} \n \n")
self.fitResultText.setMarkdown(markdownString)
def plot_excitation_curves(self):
# Require a fit so rho(x) is defined
if not self.spanc.isFit:
print("Run the calibration fit first before plotting Ex vs x.")
return
# Compute Ex at 600 bin centers from -300 to 300 for all reactions
x_vals, ex_curves = self.spanc.get_excitation_curves(
x_min=-300.0,
x_max=300.0,
n_bins=600,
)
self.fitCanvas.axes.cla()
for rxn_name, ex_vals in ex_curves.items():
self.fitCanvas.axes.plot(x_vals, ex_vals, label=rxn_name)
self.fitCanvas.axes.set_xlabel(r"$x$ (mm)")
self.fitCanvas.axes.set_ylabel(r"$E_x$ (MeV)")
self.fitCanvas.axes.set_title("Excitation energy vs focal-plane position")
self.fitCanvas.axes.grid(True)
self.fitCanvas.axes.legend()
self.fitCanvas.fig.tight_layout()
self.fitCanvas.draw()
def handle_export_excitation_csv(self):
fileName = QFileDialog.getSaveFileName(
self, "Export Excitation CSV", "./", "CSV Files (*.csv)"
)
if fileName[0]:
self.spanc.export_excitation_csv(fileName[0])
print(f"Exported excitation calibration to {fileName[0]}")
def run_spanc_ui() :
mpl.use("Qt5Agg")
app = QApplication.instance()