1
0
Fork 0
mirror of https://github.com/gwm17/spspy.git synced 2024-11-23 02:28:50 -05:00

Compare commits

..

No commits in common. "eb092d6c4b7d41e9c73379434799f685df1219aa" and "2562156943150d5d95f0369c9cc485ee16c9b4be" have entirely different histories.

5 changed files with 19 additions and 20 deletions

View File

@ -4,8 +4,6 @@ from .data.NuclearData import *
from dataclasses import dataclass, field from dataclasses import dataclass, field
import csv import csv
DEG2RAD: float = np.pi / 180.0
@dataclass @dataclass
class Excitation: class Excitation:
excitation: float = 0.0 #MeV excitation: float = 0.0 #MeV
@ -47,7 +45,7 @@ class SPSPlot:
def update_reactions(self) -> None: def update_reactions(self) -> None:
for datum in self.data.values(): for datum in self.data.values():
datum.rxn.update_parameters(self.beamEnergy, self.spsAngle * DEG2RAD, self.magneticField) datum.rxn.update_parameters(self.beamEnergy, self.spsAngle, self.magneticField)
if datum.rxn.targetMaterial.name in self.targets: if datum.rxn.targetMaterial.name in self.targets:
datum.rxn.targetMaterial = self.targets[datum.rxn.targetMaterial.name] datum.rxn.targetMaterial = self.targets[datum.rxn.targetMaterial.name]
for ex in datum.excitations: for ex in datum.excitations:

View File

@ -1,4 +1,4 @@
from .SPSPlot import SPSPlot, DEG2RAD from .SPSPlot import SPSPlot
from .SPSReaction import RxnParameters from .SPSReaction import RxnParameters
from .ui.MPLCanvas import MPLCanvas from .ui.MPLCanvas import MPLCanvas
from .ui.ReactionDialog import ReactionDialog from .ui.ReactionDialog import ReactionDialog
@ -236,7 +236,7 @@ class SPSPlotGUI(QMainWindow):
def add_reaction(self, rxnParams: RxnParameters, targName: str) -> None: def add_reaction(self, rxnParams: RxnParameters, targName: str) -> None:
rxnParams.beamEnergy = self.bkeInput.value() rxnParams.beamEnergy = self.bkeInput.value()
rxnParams.spsAngle = self.angleInput.value() * DEG2RAD rxnParams.spsAngle = self.angleInput.value()
rxnParams.magneticField = self.bfieldInput.value() rxnParams.magneticField = self.bfieldInput.value()
self.sps.add_reaction(rxnParams, targName) self.sps.add_reaction(rxnParams, targName)
self.update_plot() self.update_plot()

View File

@ -18,6 +18,7 @@ def create_reaction_parameters(zt: int, at: int, zp: int, ap: int, ze: int, ae:
return RxnParameters(global_nuclear_data.get_data(zt, at), global_nuclear_data.get_data(zp, ap), global_nuclear_data.get_data(ze, ae)) return RxnParameters(global_nuclear_data.get_data(zt, at), global_nuclear_data.get_data(zp, ap), global_nuclear_data.get_data(ze, ae))
class Reaction: class Reaction:
DEG2RAD: float = pi/180.0 #degrees -> radians
C = 299792458 #speed of light m/s C = 299792458 #speed of light m/s
QBRHO2P = 1.0E-9*C #Converts qbrho to momentum (p) (kG*cm -> MeV/c) QBRHO2P = 1.0E-9*C #Converts qbrho to momentum (p) (kG*cm -> MeV/c)
FP_MAGNIFICATION = 0.39 FP_MAGNIFICATION = 0.39
@ -43,7 +44,7 @@ class Reaction:
return f"{self.params.target.prettyIsotopicSymbol}({self.params.projectile.prettyIsotopicSymbol},{self.params.ejectile.prettyIsotopicSymbol}){self.residual.prettyIsotopicSymbol}" return f"{self.params.target.prettyIsotopicSymbol}({self.params.projectile.prettyIsotopicSymbol},{self.params.ejectile.prettyIsotopicSymbol}){self.residual.prettyIsotopicSymbol}"
def __repr__(self) -> str: def __repr__(self) -> str:
return f"{self.params.target.isotopicSymbol}({self.params.projectile.isotopicSymbol},{self.params.ejectile.isotopicSymbol}){self.residual.isotopicSymbol}_{self.params.beamEnergy}MeV_{self.params.spsAngle}rad_{self.params.magneticField}kG" return f"{self.params.target.isotopicSymbol}({self.params.projectile.isotopicSymbol},{self.params.ejectile.isotopicSymbol}){self.residual.isotopicSymbol}_{self.params.beamEnergy}MeV_{self.params.spsAngle}deg_{self.params.magneticField}kG"
def get_latex_rep(self) -> str: def get_latex_rep(self) -> str:
return f"{self.params.target.get_latex_rep()}({self.params.projectile.get_latex_rep()},{self.params.ejectile.get_latex_rep()}){self.residual.get_latex_rep()}" return f"{self.params.target.get_latex_rep()}({self.params.projectile.get_latex_rep()},{self.params.ejectile.get_latex_rep()}){self.residual.get_latex_rep()}"
@ -51,15 +52,14 @@ class Reaction:
#MeV #MeV
def calculate_ejectile_KE(self, excitation: float) -> float: def calculate_ejectile_KE(self, excitation: float) -> float:
rxnQ = self.Qvalue - excitation rxnQ = self.Qvalue - excitation
angleRads = self.params.spsAngle * self.DEG2RAD
beamRxnEnergy = self.params.beamEnergy - self.targetMaterial.get_incoming_energyloss(self.params.projectile.Z, self.params.projectile.mass, self.params.beamEnergy, self.rxnLayer, 0.0) beamRxnEnergy = self.params.beamEnergy - self.targetMaterial.get_incoming_energyloss(self.params.projectile.Z, self.params.projectile.mass, self.params.beamEnergy, self.rxnLayer, 0.0)
threshold = -rxnQ*(self.params.ejectile.mass+self.residual.mass)/(self.params.ejectile.mass + self.residual.mass - self.params.projectile.mass) threshold = -rxnQ*(self.params.ejectile.mass+self.residual.mass)/(self.params.ejectile.mass + self.residual.mass - self.params.projectile.mass)
if beamRxnEnergy < threshold: if beamRxnEnergy < threshold:
return INVALID_KINETIC_ENERGY return INVALID_KINETIC_ENERGY
term1 = sqrt(self.params.projectile.mass * self.params.ejectile.mass * beamRxnEnergy) / (self.params.ejectile.mass + self.residual.mass) * cos(self.params.spsAngle) term1 = sqrt(self.params.projectile.mass * self.params.ejectile.mass * beamRxnEnergy) / (self.params.ejectile.mass + self.residual.mass) * cos(angleRads * self.DEG2RAD)
term2 = (beamRxnEnergy * (self.residual.mass - self.params.projectile.mass) + self.residual.mass * rxnQ) / (self.params.ejectile.mass + self.residual.mass) term2 = (beamRxnEnergy * (self.residual.mass - self.params.projectile.mass) + self.residual.mass * rxnQ) / (self.params.ejectile.mass + self.residual.mass)
if(term1**2.0 + term2) < 0:
return INVALID_KINETIC_ENERGY
ke1 = term1 + sqrt(term1**2.0 + term2) ke1 = term1 + sqrt(term1**2.0 + term2)
ke2 = term1 + sqrt(term1**2.0 + term2) ke2 = term1 + sqrt(term1**2.0 + term2)
@ -70,7 +70,7 @@ class Reaction:
else: else:
ejectileEnergy = ke2**2.0 ejectileEnergy = ke2**2.0
ejectileEnergy -= self.targetMaterial.get_outgoing_energyloss(self.params.ejectile.Z, self.params.ejectile.mass, ejectileEnergy, self.rxnLayer, self.params.spsAngle) ejectileEnergy -= self.targetMaterial.get_outgoing_energyloss(self.params.ejectile.Z, self.params.ejectile.mass, ejectileEnergy, self.rxnLayer, angleRads)
return ejectileEnergy return ejectileEnergy
def convert_ejectile_KE_2_rho(self, ejectileEnergy: float) -> float: def convert_ejectile_KE_2_rho(self, ejectileEnergy: float) -> float:
@ -82,27 +82,27 @@ class Reaction:
return qbrho / (float(self.params.ejectile.Z) * self.params.magneticField) return qbrho / (float(self.params.ejectile.Z) * self.params.magneticField)
def calculate_excitation(self, rho: float) -> float: def calculate_excitation(self, rho: float) -> float:
angleRads = self.params.spsAngle * self.DEG2RAD
ejectileP = rho * float(self.params.ejectile.Z) * self.params.magneticField * self.QBRHO2P ejectileP = rho * float(self.params.ejectile.Z) * self.params.magneticField * self.QBRHO2P
ejectileEnergy = sqrt(ejectileP**2.0 + self.params.ejectile.mass**2.0) - self.params.ejectile.mass ejectileEnergy = sqrt(ejectileP**2.0 + self.params.ejectile.mass**2.0) - self.params.ejectile.mass
ejectileRxnEnergy = ejectileEnergy + self.targetMaterial.get_outgoing_reverse_energyloss(self.params.ejectile.Z, self.params.ejectile.mass, ejectileEnergy, self.rxnLayer, self.params.spsAngle) ejectileRxnEnergy = ejectileEnergy + self.targetMaterial.get_outgoing_reverse_energyloss(self.params.ejectile.Z, self.params.ejectile.mass, ejectileEnergy, self.rxnLayer, angleRads)
ejectileRxnP = sqrt(ejectileRxnEnergy * (ejectileRxnEnergy + 2.0 * self.params.ejectile.mass)) ejectileRxnP = sqrt(ejectileRxnEnergy * (ejectileRxnEnergy + 2.0 * self.params.ejectile.mass))
beamRxnEnergy = self.params.beamEnergy - self.targetMaterial.get_incoming_energyloss(self.params.projectile.Z, self.params.projectile.mass, self.params.beamEnergy, self.rxnLayer, 0.0) beamRxnEnergy = self.params.beamEnergy - self.targetMaterial.get_incoming_energyloss(self.params.projectile.Z, self.params.projectile.mass, self.params.beamEnergy, self.rxnLayer, 0.0)
beamRxnP = sqrt(beamRxnEnergy * (beamRxnEnergy + 2.0 * self.params.projectile.mass)) beamRxnP = sqrt(beamRxnEnergy * (beamRxnEnergy + 2.0 * self.params.projectile.mass))
residRxnEnergy = beamRxnEnergy + self.params.projectile.mass + self.params.target.mass - ejectileRxnEnergy - self.params.ejectile.mass residRxnEnergy = beamRxnEnergy + self.params.projectile.mass + self.params.target.mass - ejectileRxnEnergy - self.params.ejectile.mass
residRxnP2 = beamRxnP**2.0 + ejectileRxnP**2.0 - 2.0 * ejectileRxnP * beamRxnP * cos(self.params.spsAngle) residRxnP2 = beamRxnP**2.0 + ejectileRxnP**2.0 - 2.0 * ejectileRxnP * beamRxnP * cos(angleRads)
return sqrt(residRxnEnergy**2.0 - residRxnP2) - self.residual.mass return sqrt(residRxnEnergy**2.0 - residRxnP2) - self.residual.mass
def calculate_focal_plane_offset(self, ejectileEnergy: float) -> float: def calculate_focal_plane_offset(self, ejectileEnergy: float) -> float:
if ejectileEnergy == INVALID_KINETIC_ENERGY: if ejectileEnergy == INVALID_KINETIC_ENERGY:
return 0.0 return 0.0
ejectileRho = self.convert_ejectile_KE_2_rho(ejectileEnergy) ejectileRho = self.convert_ejectile_KE_2_rho(ejectileEnergy)
k = sqrt(self.params.projectile.mass * self.params.ejectile.mass * self.params.beamEnergy / ejectileEnergy) * sin(self.params.spsAngle) k = sqrt(self.params.projectile.mass * self.params.ejectile.mass * self.params.beamEnergy / ejectileEnergy) * sin(self.params.spsAngle * self.DEG2RAD)
k /= self.params.ejectile.mass + self.residual.mass - sqrt(self.params.projectile.mass * self.params.ejectile.mass * self.params.beamEnergy/ejectileEnergy) * cos(self.params.spsAngle) k /= self.params.ejectile.mass + self.residual.mass - sqrt(self.params.projectile.mass * self.params.ejectile.mass * self.params.beamEnergy/ejectileEnergy) * cos(self.params.spsAngle * self.DEG2RAD)
return -1.0*k*ejectileRho*self.FP_DISPERSION*self.FP_MAGNIFICATION return -1.0*k*ejectileRho*self.FP_DISPERSION*self.FP_MAGNIFICATION
#(MeV, rad, kG)
def update_parameters(self, beamEnergy: float, spsAngle: float, magenticField: float): def update_parameters(self, beamEnergy: float, spsAngle: float, magenticField: float):
self.params.beamEnergy = beamEnergy self.params.beamEnergy = beamEnergy
self.params.spsAngle = spsAngle self.params.spsAngle = spsAngle

View File

@ -104,7 +104,7 @@ class SPSTarget:
def get_rxn_layer(self, zt: int, at: int) -> int: def get_rxn_layer(self, zt: int, at: int) -> int:
for idx, layer in enumerate(self.layer_details): for idx, layer in enumerate(self.layer_details):
for (z, a, s) in layer.compound_list: for (a, z, s) in layer.compound_list:
if at == a and zt == z: if at == a and zt == z:
return idx return idx
return INVALID_RXN_LAYER return INVALID_RXN_LAYER
@ -114,8 +114,9 @@ class SPSTarget:
if angle == pi*0.5: if angle == pi*0.5:
return e_initial return e_initial
projectile = catima.Projectile(ap, zp) projectile = catima.Projectile(zp, ap)
e_current = e_initial/ap e_current = e_initial/ap
for (idx, layer) in enumerate(self.layer_details): for (idx, layer) in enumerate(self.layer_details):
material = catima.Material([(global_nuclear_data.get_data(z, a).mass, z, float(s)) for (z, a, s) in layer.compound_list]) material = catima.Material([(global_nuclear_data.get_data(z, a).mass, z, float(s)) for (z, a, s) in layer.compound_list])
projectile.T(e_current) #catima wants MeV/u projectile.T(e_current) #catima wants MeV/u
@ -134,7 +135,7 @@ class SPSTarget:
if angle == pi*0.5: if angle == pi*0.5:
return e_initial return e_initial
projectile = catima.Projectile(ap, zp) projectile = catima.Projectile(zp, ap)
e_current = e_initial/ap e_current = e_initial/ap
for (idx, layer) in enumerate(self.layer_details[rxn_layer:], start=rxn_layer): for (idx, layer) in enumerate(self.layer_details[rxn_layer:], start=rxn_layer):
@ -153,7 +154,7 @@ class SPSTarget:
if angle == pi*0.5: if angle == pi*0.5:
return 0.0 return 0.0
projectile = catima.Projectile(ap, zp) projectile = catima.Projectile(zp, ap)
e_current = e_final/ap e_current = e_final/ap
sublist = self.layer_details[rxn_layer:] #only care about rxn_layer -> exit sublist = self.layer_details[rxn_layer:] #only care about rxn_layer -> exit
reveresedRxnLayer = len(sublist) -1 #when reversed rxn_layer is the last layer reveresedRxnLayer = len(sublist) -1 #when reversed rxn_layer is the last layer

View File

@ -24,7 +24,7 @@ def generate_nucleus_id(z: np.uint32, a: np.uint32) -> np.uint32 :
return z*z + z + a if z > a else a*a + z return z*z + z + a if z > a else a*a + z
class NuclearDataMap: class NuclearDataMap:
U2MEV: float = 931.493614838475 U2MEV: float = 931.4940954
ELECTRON_MASS: float = 0.000548579909 ELECTRON_MASS: float = 0.000548579909
def __init__(self): def __init__(self):