/* EnergyLoss.cpp Code for calculating the energy loss of a charged, massive particle through an arbitrary medium. Based on code written by D.W. Visser at Yale for the original SPANC. Uses energy loss calulations described by Ziegler in various SRIM textbooks. Written by G.W. McCann Aug. 2020 */ #include "Eloss_Tables.h" #include "EnergyLoss.h" #include "KinematicsExceptions.h" #include namespace Mask { EnergyLoss::EnergyLoss() : ZP(-1), AP(-1), MP(-1.0), comp_denom(0) { } EnergyLoss::~EnergyLoss() {} /*Targets are defined by their atomic number, total number of nucleons, and their stoichiometry within the target compound*/ void EnergyLoss::SetTargetComponents(std::vector& Zt, std::vector& At, std::vector& Stoich) { comp_denom = 0; ZT = Zt; AT = At; for(unsigned int i=0; i MAX_Z) throw ELossException("Maximum allowed target Z exceeded"); } targ_composition.resize(Stoich.size()); for(unsigned int i=0; i MAX_FRACTIONAL_STEP && depth < MAX_DEPTH) { depth++; x_step *= 0.5; e_step = GetTotalStoppingPower(e_final)*x_step/1000.0; } else if((x_step + x_traversed) >= thickness) { //last chunk go = false; x_step = thickness - x_traversed; //get valid portion of last chunk e_final -= GetTotalStoppingPower(e_final)*x_step/1000.0; if(e_final <= e_threshold) return e_initial; } else if(depth == MAX_DEPTH) { return e_initial; } else { x_traversed += x_step; e_step = GetTotalStoppingPower(e_final)*x_step/1000.0; e_final -= e_step; if(e_final <= e_threshold) return e_initial; } } return e_initial - e_final; } /* Returns units of MeV; thickness in ug/cm^2; e_final in units of MeV Energy loss going through the target using energy of particle after traversal */ double EnergyLoss::GetReverseEnergyLoss(int zp, int ap, double e_final, double thickness) { if( ZP != zp) { ZP = zp; AP = ap; MP = MassLookup::GetInstance().FindMass(ZP, AP)*MEV2U; } double e_initial = e_final; double x_traversed = 0.0; double x_step = 0.25*thickness; //initial step in x double e_step = GetTotalStoppingPower(e_initial)*x_step/1000.0; //initial step in E bool go = true; while(go) { if(e_step/e_initial > MAX_FRACTIONAL_STEP) { x_step *= 0.5; e_step = GetTotalStoppingPower(e_initial)*x_step/1000.0; } else if (x_traversed+x_step > thickness) { go = false; x_step = thickness - x_traversed; e_initial += GetTotalStoppingPower(e_initial)*x_step/1000.0; } else { x_traversed += x_step; e_step = GetTotalStoppingPower(e_initial)*x_step/1000.0; e_initial += e_step; } } return e_initial-e_final; } /* Returns units of keV/(ug/cm^2) Calculates Electronic stopping power by first calculating SE for hydrogen through the target and then using corrections to calculate SE for projectile of interest */ double EnergyLoss::GetElectronicStoppingPower(double energy) { //Wants in units of keV energy *= 1000.0; double e_per_u = energy/MP; std::vector values; if(e_per_u > MAX_H_E_PER_U) { throw ELossException("Exceeded maximum allowed energy per nucleon"); } else if (e_per_u > 1000.0) { for(auto& z: ZT) values.push_back(Hydrogen_dEdx_High(e_per_u, energy, z)); } else if (e_per_u > 10.0) { for(auto& z: ZT) values.push_back(Hydrogen_dEdx_Med(e_per_u, z)); } else if (e_per_u > 0.0) { for(auto& z: ZT) values.push_back(Hydrogen_dEdx_Low(e_per_u, z)); } else { throw ELossException("Negative energy per nucleon"); } if(values.size() == 0) throw ELossException("Size of value array is 0. Unable to iterate over target components"); if(ZP > 1) { //not hydrogen, need to account for effective charge for(unsigned int i=0; i