LISE agreement

This commit is contained in:
James Szalkie 2026-07-20 13:51:50 -04:00
parent 26be64416c
commit 9848725f58
6 changed files with 30074 additions and 11023 deletions

View File

@ -104,6 +104,7 @@ int main(int argc, char **argv){
transfer.Setb(1, 1); // outgoing proton from the primary transfer transfer.Setb(1, 1); // outgoing proton from the primary transfer
transfer.SetB(30, 14); // 21Na* heavy product transfer.SetB(30, 14); // 21Na* heavy product
const double beamA = 27; // mass number of 27Al beam const double beamA = 27; // mass number of 27Al beam
const double beamE = 72.0 / 27.0; // beam energy in MeV
bool enableSequentialDecay = false; // turning to false to disable sequential decay for now, can be set to true to enable bool enableSequentialDecay = false; // turning to false to disable sequential decay for now, can be set to true to enable
const int decayDaughterA = 20; const int decayDaughterA = 20;
@ -363,6 +364,7 @@ int main(int argc, char **argv){
beamEnergy = elossBeam->Eval(beamPath_cm); // MeV beamEnergy = elossBeam->Eval(beamPath_cm); // MeV
beamEnergyLoss = elossBeam->Eval(0.0) - beamEnergy; beamEnergyLoss = elossBeam->Eval(0.0) - beamEnergy;
KEA = beamEnergy / beamA; KEA = beamEnergy / beamA;
//KEA = gRandom->Uniform(0, beamE);
transfer.SetIncidentEnergyAngle(KEA, 0, 0); transfer.SetIncidentEnergyAngle(KEA, 0, 0);
transfer.CalReactionConstant(); transfer.CalReactionConstant();

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -84,6 +84,17 @@ def get_loss_table_path(medium, particle_label):
return os.path.join(script_dir, f"{medium}Loss", f"E_vs_x_{particle_label}.dat") return os.path.join(script_dir, f"{medium}Loss", f"E_vs_x_{particle_label}.dat")
def normalize_particle_label(particle):
"""Return the canonical table label for a particle or isotope name."""
if isinstance(particle, str):
try:
_, _, _, label = resolve_particle(particle)
return label
except Exception:
return particle.strip()
return str(particle)
def clear_interpolator_cache(): def clear_interpolator_cache():
"""Drop cached energy-loss interpolators and force Python to release memory.""" """Drop cached energy-loss interpolators and force Python to release memory."""
global interp_cache global interp_cache
@ -111,30 +122,23 @@ def make_E_vs_x(
p_pa = P_TORR * 133.322 p_pa = P_TORR * 133.322
molar_density = p_pa / (R * TEMP_K) # mol/m^3 molar_density = p_pa / (R * TEMP_K) # mol/m^3
# ---------------------------
# Medium definition # Medium definition
# ---------------------------
if medium == "He": if medium == "He":
m_he = 4.0026 m_he = 4.0026
m_c = 12.0000 m_c = 12.0000
m_o = 15.9949 m_o = 15.9949
"""
# FIX: do NOT double count oxygen
material_def = [ material_def = [
(m_he, 2, 0.96), (m_he, 2, 0.96),
((m_c + 2 * m_o), 18, 0.04) # CO2 lumped correctly (m_c, 6, 0.04),
] (m_o, 8, 0.08)
] """
material_def = [(m_he, 2, 1.0)]
#m_mix_avg = 0.96 * m_he + 0.04 * (m_c + 2 * m_o) #m_mix_avg = 0.96 * m_he + 0.04 * (m_c + 2 * m_o)
m_mix_avg = m_he m_mix_avg = 1.0 * m_he
rho_g_cm3 = (molar_density * m_mix_avg) / 1e6
#rho_g_cm3 = (molar_density * m_mix_avg) / 1e6
if z == 2:
rho_g_cm3 = 0.00017
#rho_g_cm3 = 8.2928e-5
else:
rho_g_cm3 = 8.2928e-5
gas = catima.Material(material_def) gas = catima.Material(material_def)
gas.density(rho_g_cm3) gas.density(rho_g_cm3)
@ -156,10 +160,10 @@ def make_E_vs_x(
E = np.linspace(0.1, emax_mev, npoints) E = np.linspace(0.1, emax_mev, npoints)
S_mass = np.zeros_like(E) S_mass = np.zeros_like(E)
for i, energy in enumerate(E): for i, energy in enumerate(E):
projectile.T(energy) # CATIMA expects projectile energy in MeV/u, while the table axis stays in total MeV.
projectile.T(energy / mass_u)
S_mass[i] = catima.dedx(projectile, gas) # MeV/(g/cm^2) S_mass[i] = catima.dedx(projectile, gas) # MeV/(g/cm^2)
# convert to MeV/cm
S_linear = S_mass * rho_g_cm3 S_linear = S_mass * rho_g_cm3
invS = 1.0 / np.clip(S_linear, 1e-30, None) invS = 1.0 / np.clip(S_linear, 1e-30, None)
x = cumulative_trapezoid(invS[::-1], E[::-1], initial=0) x = cumulative_trapezoid(invS[::-1], E[::-1], initial=0)
@ -206,12 +210,38 @@ def load_table(filename):
def get_interpolators(particle, medium): def get_interpolators(particle, medium):
cache_key = (particle.lower(), medium.lower()) canonical_particle = normalize_particle_label(particle)
cache_key = (canonical_particle.lower(), medium.lower())
if cache_key in interp_cache: if cache_key in interp_cache:
return interp_cache[cache_key] return interp_cache[cache_key]
filename = get_loss_table_path(medium, particle) candidate_labels = [canonical_particle]
if isinstance(particle, str):
raw_particle = particle.strip()
candidate_labels.extend([
raw_particle,
canonical_particle.replace("-", "")
])
filename = None
seen_candidates = set()
for label in candidate_labels:
normalized_label = label.strip()
if not normalized_label:
continue
key = normalized_label.lower()
if key in seen_candidates:
continue
seen_candidates.add(key)
candidate_filename = get_loss_table_path(medium, normalized_label)
if os.path.exists(candidate_filename):
filename = candidate_filename
break
if filename is None:
filename = get_loss_table_path(medium, canonical_particle)
x, E = load_table(filename) x, E = load_table(filename)
@ -275,11 +305,29 @@ def resolve_particle(name):
name = name.lower().strip().rstrip("s") name = name.lower().strip().rstrip("s")
if name in particles: if name in particles:
return particles[name] return particles[name]
match = re.match(r"([a-zA-Z]+)[-\s]?(\d+)", name) match = re.match(r"([a-zA-Z]+)[-\s]?(\d+)$", name)
if match: if match:
element_symbol = match.group(1).capitalize() element_symbol = match.group(1).capitalize()
A = int(match.group(2)) A = int(match.group(2))
try:
element = pt.elements.symbol(element_symbol)
isotope = element[A]
return (
isotope.number, # Z
isotope.mass, # mass in u
30.0,
f"{element_symbol}-{A}"
)
except Exception:
raise ValueError(f"Unknown isotope: {name}")
match = re.match(r"(\d+)[-\s]?([a-zA-Z]+)$", name)
if match:
A = int(match.group(1))
element_symbol = match.group(2).capitalize()
try: try:
element = pt.elements.symbol(element_symbol) element = pt.elements.symbol(element_symbol)
isotope = element[A] isotope = element[A]
@ -898,7 +946,7 @@ class MyInteractiveApp(cmd.Cmd):
if dl > 0: if dl > 0:
print(f"\nChange in energy: {dE:.6f} MeV") print(f"\nChange in energy: {dE:.6f} MeV")
print(f"Distance travelled: {dl:.6f} cm\n") print(f"Distance travelled: {dl:.6f} cm\n")
print(f"{(dl * 10000):.6f} microns") print(f"{(dl * 10):.6f} mm")
else: else:
print("Error: remake table with larger value, fallen off map") print("Error: remake table with larger value, fallen off map")
except: except:
@ -1343,7 +1391,7 @@ class MyInteractiveApp(cmd.Cmd):
plt.figure(figsize=(7,6)) plt.figure(figsize=(7,6))
mask1 = ~np.isnan(Esx3) & ~np.isnan(Edet) & sx3_theta_plot_mask mask1 = ~np.isnan(Esx3) & ~np.isnan(Edet) & sx3_theta_plot_mask
plt.hist2d(Esx3[mask1], Edet[mask1], bins=300) plt.hist2d(Esx3[mask1], Edet[mask1], bins=300, norm="log")
plt.xlabel("Esx3") plt.xlabel("Esx3")
plt.ylabel("Edet") plt.ylabel("Edet")
plt.title("Esx3 vs Edet") plt.title("Esx3 vs Edet")
@ -1356,12 +1404,12 @@ class MyInteractiveApp(cmd.Cmd):
mask1 = ~np.isnan(qqqE) & ~np.isnan(EdetQ) & qqq_theta_plot_mask mask1 = ~np.isnan(qqqE) & ~np.isnan(EdetQ) & qqq_theta_plot_mask
plt.figure(figsize=(7,6)) plt.figure(figsize=(7,6))
plt.hist2d(qqqE[mask1], EdetQ[mask1], bins=300) plt.hist2d(qqqE[mask1], EdetQ[mask1], bins=300, norm="log")
plt.xlabel("Eqqq") plt.xlabel("Eqqq")
plt.ylabel("Edet") plt.ylabel("Edet")
plt.title("Eqqq vs Edet") plt.title("Eqqq vs Edet")
plt.yscale("log") #plt.yscale("log")
plt.xscale("log") #plt.xscale("log")
plt.colorbar(label="counts") plt.colorbar(label="counts")
plt.tight_layout() plt.tight_layout()
plt.savefig(f"{base}/Eqqq_vs_Edet.png") plt.savefig(f"{base}/Eqqq_vs_Edet.png")
@ -1418,6 +1466,7 @@ class MyInteractiveApp(cmd.Cmd):
plt.plot(theta_deg[order], path_cm[order], color='red', linewidth=2, label='0.1/sin(theta)') plt.plot(theta_deg[order], path_cm[order], color='red', linewidth=2, label='0.1/sin(theta)')
plt.legend() plt.legend()
plt.tight_layout() plt.tight_layout()
plt.gca().invert_xaxis()
plt.savefig(f"{base}/Range_vs_theta_with_path.png", dpi=300) plt.savefig(f"{base}/Range_vs_theta_with_path.png", dpi=300)
plt.show() plt.show()
except Exception: except Exception: