111 particleChangeLoss(0),
113 energyLossLimit(0.01),
117 genericIonPDGMass = genericIon -> GetPDGMass();
133 lowerEnergyEdgeIntegr = 0.025 *
MeV;
139 cacheElecMassRatio = 0;
140 cacheChargeSquare = 0;
143 rangeCacheParticle = 0;
144 rangeCacheMatCutsCouple = 0;
145 rangeCacheEnergyRange = 0;
146 rangeCacheRangeEnergy = 0;
149 dedxCacheParticle = 0;
150 dedxCacheMaterial = 0;
151 dedxCacheEnergyCut = 0;
152 dedxCacheIter = lossTableList.end();
153 dedxCacheTransitionEnergy = 0.0;
154 dedxCacheTransitionFactor = 0.0;
155 dedxCacheGenIonMassRatio = 0.0;
163 RangeEnergyTable::iterator iterRange = r.begin();
164 RangeEnergyTable::iterator iterRange_end = r.end();
166 for(;iterRange != iterRange_end; iterRange++)
delete iterRange ->
second;
170 EnergyRangeTable::iterator iterEnergy = E.begin();
171 EnergyRangeTable::iterator iterEnergy_end = E.end();
173 for(;iterEnergy != iterEnergy_end; iterEnergy++)
delete iterEnergy ->
second;
177 LossTableList::iterator iterTables = lossTableList.begin();
178 LossTableList::iterator iterTables_end = lossTableList.end();
180 for(;iterTables != iterTables_end; iterTables++)
delete *iterTables;
181 lossTableList.clear();
184 delete betheBlochModel;
185 delete braggIonModel;
194 return couple -> GetMaterial() -> GetIonisation() ->
195 GetMeanExcitationEnergy();
216 if(particle != cacheParticle) UpdateCache(particle);
218 G4double tau = kineticEnergy/cacheMass;
220 (1. + 2.0 * (tau + 1.) * cacheElecMassRatio +
221 cacheElecMassRatio * cacheElecMassRatio);
233 G4double chargeSquareRatio = corrections ->
234 EffectiveChargeSquareRatio(particle,
237 corrFactor = chargeSquareRatio *
238 corrections -> EffectiveChargeCorrection(particle,
263 cacheElecMassRatio = 0;
264 cacheChargeSquare = 0;
267 rangeCacheParticle = 0;
268 rangeCacheMatCutsCouple = 0;
269 rangeCacheEnergyRange = 0;
270 rangeCacheRangeEnergy = 0;
273 dedxCacheParticle = 0;
274 dedxCacheMaterial = 0;
275 dedxCacheEnergyCut = 0;
276 dedxCacheIter = lossTableList.end();
277 dedxCacheTransitionEnergy = 0.0;
278 dedxCacheTransitionFactor = 0.0;
279 dedxCacheGenIonMassRatio = 0.0;
282 LossTableList::iterator iterTables = lossTableList.begin();
283 LossTableList::iterator iterTables_end = lossTableList.end();
285 for(;iterTables != iterTables_end; iterTables++)
286 (*iterTables) -> ClearCache();
290 RangeEnergyTable::iterator iterRange = r.begin();
291 RangeEnergyTable::iterator iterRange_end = r.end();
293 for(;iterRange != iterRange_end; iterRange++)
delete iterRange ->
second;
296 EnergyRangeTable::iterator iterEnergy = E.begin();
297 EnergyRangeTable::iterator iterEnergy_end = E.end();
299 for(;iterEnergy != iterEnergy_end; iterEnergy++)
delete iterEnergy ->
second;
303 size_t size = cuts.size();
305 for(
size_t i = 0; i < size; i++) cutEnergies.push_back(cuts[i]);
310 size_t nmbCouples = coupleTable -> GetTableSize();
312 #ifdef PRINT_TABLE_BUILT
313 G4cout <<
"G4IonParametrisedLossModel::Initialise():"
314 <<
" Building dE/dx vectors:"
318 for (
size_t i = 0; i < nmbCouples; i++) {
321 coupleTable -> GetMaterialCutsCouple(i);
326 for(
G4int atomicNumberIon = 3; atomicNumberIon < 102; atomicNumberIon++) {
328 LossTableList::iterator iter = lossTableList.begin();
329 LossTableList::iterator iter_end = lossTableList.end();
331 for(;iter != iter_end; iter++) {
334 G4cout <<
"G4IonParametrisedLossModel::Initialise():"
335 <<
" Skipping illegal table."
340 (*iter) -> BuildDEDXTable(atomicNumberIon, material);
343 #ifdef PRINT_TABLE_BUILT
344 G4cout <<
" Atomic Number Ion = " << atomicNumberIon
345 <<
", Material = " << material ->
GetName()
346 <<
", Table = " << (*iter) ->
GetName()
356 if(! particleChangeLoss) {
365 betheBlochModel ->
Initialise(particle, cuts);
390 G4double maxEnergy = std::min(tmax, maxKinEnergy);
392 if(cutEnergy < tmax) {
395 G4double betaSquared = kineticEnergy *
396 (energy + cacheMass) / (energy * energy);
398 crosssection = 1.0 / cutEnergy - 1.0 / maxEnergy -
399 betaSquared * std::log(maxEnergy / cutEnergy) / tmax;
404 #ifdef PRINT_DEBUG_CS
405 G4cout <<
"########################################################"
407 <<
"# G4IonParametrisedLossModel::ComputeCrossSectionPerAtom"
409 <<
"# particle =" << particle -> GetParticleName()
411 <<
"# cut(MeV) = " << cutEnergy/
MeV
416 << std::setw(14) <<
"CS(um)"
417 << std::setw(14) <<
"E_max_sec(MeV)"
419 <<
"# ------------------------------------------------------"
423 << std::setw(14) << crosssection / (um * um)
424 << std::setw(14) << tmax /
MeV
428 crosssection *= atomicNumber;
442 G4double nbElecPerVolume = material -> GetTotNbOfElectPerVolume();
488 UpdateDEDXCache(particle, material, cutEnergy);
490 LossTableList::iterator iter = dedxCacheIter;
492 if(iter != lossTableList.end()) {
494 G4double transitionEnergy = dedxCacheTransitionEnergy;
496 if(transitionEnergy > kineticEnergy) {
498 dEdx = (*iter) -> GetDEDX(particle, material, kineticEnergy);
504 dEdx -= dEdxDeltaRays;
507 G4double massRatio = dedxCacheGenIonMassRatio;
512 G4double scaledKineticEnergy = kineticEnergy * massRatio;
513 G4double scaledTransitionEnergy = transitionEnergy * massRatio;
517 if(scaledTransitionEnergy >= lowEnergyLimit) {
520 material, genericIon,
521 scaledKineticEnergy, cutEnergy);
523 dEdx *= chargeSquare;
525 dEdx += corrections -> ComputeIonCorrections(particle,
526 material, kineticEnergy);
528 G4double factor = 1.0 + dedxCacheTransitionFactor /
539 if(particle != genericIon) {
542 massRatio = genericIonPDGMass / particle -> GetPDGMass();
545 G4double scaledKineticEnergy = kineticEnergy * massRatio;
548 if(scaledKineticEnergy < lowEnergyLimit) {
550 material, genericIon,
551 scaledKineticEnergy, cutEnergy);
553 dEdx *= chargeSquare;
557 material, genericIon,
558 lowEnergyLimit, cutEnergy);
561 material, genericIon,
562 lowEnergyLimit, cutEnergy);
564 if(particle != genericIon) {
565 G4double chargeSquareLowEnergyLimit =
567 lowEnergyLimit / massRatio);
569 dEdxLimitParam *= chargeSquareLowEnergyLimit;
570 dEdxLimitBetheBloch *= chargeSquareLowEnergyLimit;
572 dEdxLimitBetheBloch +=
573 corrections -> ComputeIonCorrections(particle,
574 material, lowEnergyLimit / massRatio);
577 G4double factor = (1.0 + (dEdxLimitParam/dEdxLimitBetheBloch - 1.0)
578 * lowEnergyLimit / scaledKineticEnergy);
581 material, genericIon,
582 scaledKineticEnergy, cutEnergy);
584 dEdx *= chargeSquare;
586 if(particle != genericIon) {
587 dEdx += corrections -> ComputeIonCorrections(particle,
588 material, kineticEnergy);
596 if (dEdx < 0.0) dEdx = 0.0;
611 G4double atomicMassNumber = particle -> GetAtomicMass();
612 G4double materialDensity = material -> GetDensity();
614 G4cout <<
"# dE/dx table for " << particle -> GetParticleName()
615 <<
" in material " << material ->
GetName()
616 <<
" of density " << materialDensity /
g *
cm3
619 <<
"# Projectile mass number A1 = " << atomicMassNumber
621 <<
"# ------------------------------------------------------"
625 << std::setw(14) <<
"E/A1"
626 << std::setw(14) <<
"dE/dx"
627 << std::setw(14) <<
"1/rho*dE/dx"
631 << std::setw(14) <<
"(MeV)"
632 << std::setw(14) <<
"(MeV/cm)"
633 << std::setw(14) <<
"(MeV*cm2/mg)"
635 <<
"# ------------------------------------------------------"
638 G4double energyLowerBoundary = lowerBoundary * atomicMassNumber;
639 G4double energyUpperBoundary = upperBoundary * atomicMassNumber;
643 energyLowerBoundary = std::log(energyLowerBoundary);
644 energyUpperBoundary = std::log(energyUpperBoundary);
647 G4double deltaEnergy = (energyUpperBoundary - energyLowerBoundary) /
650 for(
int i = 0; i < numBins + 1; i++) {
653 if(logScaleEnergy) energy = std::exp(energy);
658 << std::setw(14) << energy / atomicMassNumber /
MeV
659 << std::setw(14) << dedx /
MeV *
cm
660 << std::setw(14) << dedx / materialDensity / (
MeV*
cm2/(0.001*
g))
675 LossTableList::iterator iter = lossTableList.begin();
676 LossTableList::iterator iter_end = lossTableList.end();
678 for(;iter != iter_end; iter++) {
682 lowerBoundary, upperBoundary,
683 numBins,logScaleEnergy);
692 std::vector<G4DynamicParticle*>* secondaries,
726 std::min(rossiMaxKinEnergySec, userMaxKinEnergySec);
728 if(cutKinEnergySec >= maxKinEnergySec)
return;
730 G4double kineticEnergy = particle -> GetKineticEnergy();
734 G4double betaSquared = kineticEnergy *
735 (energy + cacheMass) / (energy * energy);
744 kinEnergySec = cutKinEnergySec * maxKinEnergySec /
745 (maxKinEnergySec * (1.0 - xi) + cutKinEnergySec * xi);
749 grej = 1.0 - betaSquared * kinEnergySec / rossiMaxKinEnergySec;
752 G4cout <<
"G4IonParametrisedLossModel::SampleSecondary Warning: "
754 << grej <<
" for e= " << kinEnergySec
763 G4double totMomentum = energy*std::sqrt(betaSquared);
765 (momentumSec * totMomentum);
766 if(cost > 1.0) cost = 1.0;
767 G4double sint = std::sqrt((1.0 - cost)*(1.0 + cost));
771 G4ThreeVector directionSec(sint*std::cos(phi),sint*std::sin(phi), cost) ;
779 secondaries -> push_back(delta);
782 kineticEnergy -= kinEnergySec;
783 G4ThreeVector finalP = direction*totMomentum - directionSec*momentumSec;
784 finalP = finalP.
unit();
786 particleChangeLoss -> SetProposedKineticEnergy(kineticEnergy);
787 particleChangeLoss -> SetProposedMomentumDirection(finalP);
792 void G4IonParametrisedLossModel::UpdateRangeCache(
800 if(particle == rangeCacheParticle &&
801 matCutsCouple == rangeCacheMatCutsCouple) {
804 rangeCacheParticle = particle;
805 rangeCacheMatCutsCouple = matCutsCouple;
808 LossTableList::iterator iter =
IsApplicable(particle, material);
811 if(iter != lossTableList.end()) {
814 IonMatCouple ionMatCouple = std::make_pair(particle, matCutsCouple);
815 RangeEnergyTable::iterator iterRange = r.find(ionMatCouple);
817 if(iterRange == r.end()) BuildRangeVector(particle, matCutsCouple);
819 rangeCacheEnergyRange = E[ionMatCouple];
820 rangeCacheRangeEnergy = r[ionMatCouple];
823 rangeCacheEnergyRange = 0;
824 rangeCacheRangeEnergy = 0;
831 void G4IonParametrisedLossModel::UpdateDEDXCache(
844 if(particle == dedxCacheParticle &&
845 material == dedxCacheMaterial &&
846 cutEnergy == dedxCacheEnergyCut) {
850 dedxCacheParticle = particle;
852 dedxCacheEnergyCut = cutEnergy;
854 G4double massRatio = genericIonPDGMass / particle -> GetPDGMass();
855 dedxCacheGenIonMassRatio = massRatio;
857 LossTableList::iterator iter =
IsApplicable(particle, material);
858 dedxCacheIter = iter;
861 if(iter != lossTableList.end()) {
865 (*iter) -> GetUpperEnergyEdge(particle, material);
866 dedxCacheTransitionEnergy = transitionEnergy;
870 G4double dEdxParam = (*iter) -> GetDEDX(particle, material,
877 dEdxParam -= dEdxDeltaRays;
884 G4double scaledTransitionEnergy = transitionEnergy * massRatio;
888 material, genericIon,
889 scaledTransitionEnergy, cutEnergy);
890 dEdxBetheBloch *= transitionChargeSquare;
894 corrections -> ComputeIonCorrections(particle,
895 material, transitionEnergy);
898 dedxCacheTransitionFactor =
899 (dEdxParam - dEdxBetheBloch)/dEdxBetheBloch
904 dedxCacheParticle = particle;
906 dedxCacheEnergyCut = cutEnergy;
908 dedxCacheGenIonMassRatio =
909 genericIonPDGMass / particle -> GetPDGMass();
911 dedxCacheTransitionEnergy = 0.0;
912 dedxCacheTransitionFactor = 0.0;
939 const G4Material* material = couple -> GetMaterial();
941 G4double kineticEnergy = dynamicParticle -> GetKineticEnergy();
943 if(kineticEnergy == eloss) {
return; }
946 size_t cutIndex = couple -> GetIndex();
947 cutEnergy = cutEnergies[cutIndex];
949 UpdateDEDXCache(particle, material, cutEnergy);
951 LossTableList::iterator iter = dedxCacheIter;
955 if(iter != lossTableList.end()) {
962 kineticEnergy, cutEnergy);
966 G4cout <<
"########################################################"
968 <<
"# G4IonParametrisedLossModel::CorrectionsAlongStep"
970 <<
"# cut(MeV) = " << cutEnergy/
MeV
975 << std::setw(14) <<
"l(um)"
976 << std::setw(14) <<
"l*dE/dx(MeV)"
977 << std::setw(14) <<
"(l*dE/dx)/E"
979 <<
"# ------------------------------------------------------"
983 << std::setw(14) << length / um
984 << std::setw(14) << eloss /
MeV
985 << std::setw(14) << eloss / kineticEnergy * 100.0
993 if(eloss > energyLossLimit * kineticEnergy) {
996 kineticEnergy,length);
999 G4cout <<
"# Correction applied:"
1003 << std::setw(14) << length / um
1004 << std::setw(14) << eloss /
MeV
1005 << std::setw(14) << eloss / kineticEnergy * 100.0
1015 if(energy < 0.0) energy = kineticEnergy * 0.5;
1017 G4double chargeSquareRatio = corrections ->
1018 EffectiveChargeSquareRatio(particle,
1029 G4double transitionEnergy = dedxCacheTransitionEnergy;
1031 if(iter != lossTableList.end() && transitionEnergy < kineticEnergy) {
1032 chargeSquareRatio *= corrections -> EffectiveChargeCorrection(particle,
1036 G4double chargeSquareRatioCorr = chargeSquareRatio/corrFactor;
1037 eloss *= chargeSquareRatioCorr;
1039 else if (iter == lossTableList.end()) {
1041 chargeSquareRatio *= corrections -> EffectiveChargeCorrection(particle,
1045 G4double chargeSquareRatioCorr = chargeSquareRatio/corrFactor;
1046 eloss *= chargeSquareRatioCorr;
1052 if(iter == lossTableList.end()) {
1054 G4double scaledKineticEnergy = kineticEnergy * dedxCacheGenIonMassRatio;
1058 if(scaledKineticEnergy > lowEnergyLimit)
1060 corrections -> IonHighOrderCorrections(particle, couple, energy);
1066 void G4IonParametrisedLossModel::BuildRangeVector(
1071 size_t cutIndex = matCutsCouple -> GetIndex();
1072 cutEnergy = cutEnergies[cutIndex];
1074 const G4Material* material = matCutsCouple -> GetMaterial();
1076 G4double massRatio = genericIonPDGMass / particle -> GetPDGMass();
1078 G4double lowerEnergy = lowerEnergyEdgeIntegr / massRatio;
1079 G4double upperEnergy = upperEnergyEdgeIntegr / massRatio;
1081 G4double logLowerEnergyEdge = std::log(lowerEnergy);
1082 G4double logUpperEnergyEdge = std::log(upperEnergy);
1084 G4double logDeltaEnergy = (logUpperEnergyEdge - logLowerEnergyEdge) /
1093 energyRangeVector -> SetSpline(
true);
1100 G4double range = 2.0 * lowerEnergy / dedxLow;
1102 energyRangeVector -> PutValues(0, lowerEnergy, range);
1104 G4double logEnergy = std::log(lowerEnergy);
1105 for(
size_t i = 1; i < nmbBins+1; i++) {
1107 G4double logEnergyIntegr = logEnergy;
1109 for(
size_t j = 0; j < nmbSubBins; j++) {
1111 G4double binLowerBoundary = std::exp(logEnergyIntegr);
1112 logEnergyIntegr += logDeltaIntegr;
1114 G4double binUpperBoundary = std::exp(logEnergyIntegr);
1115 G4double deltaIntegr = binUpperBoundary - binLowerBoundary;
1117 G4double energyIntegr = binLowerBoundary + 0.5 * deltaIntegr;
1124 if(dedxValue > 0.0) range += deltaIntegr / dedxValue;
1126 #ifdef PRINT_DEBUG_DETAILS
1128 <<
" MeV -> dE = " << deltaIntegr/
MeV
1129 <<
" MeV -> dE/dx = " << dedxValue/
MeV*
mm
1130 <<
" MeV/mm -> dE/(dE/dx) = " << deltaIntegr /
1132 <<
" mm -> range = " << range /
mm
1137 logEnergy += logDeltaEnergy;
1141 energyRangeVector -> PutValues(i, energy, range);
1143 #ifdef PRINT_DEBUG_DETAILS
1144 G4cout <<
"G4IonParametrisedLossModel::BuildRangeVector() bin = "
1146 << energy /
MeV <<
" MeV, R = "
1147 << range /
mm <<
" mm"
1156 energyRangeVector -> GetValue(lowerEnergy, b);
1158 energyRangeVector -> GetValue(upperEnergy, b);
1164 rangeEnergyVector -> SetSpline(
true);
1166 for(
size_t i = 0; i < nmbBins+1; i++) {
1168 rangeEnergyVector ->
1169 PutValues(i, energyRangeVector -> GetValue(energy, b), energy);
1172 #ifdef PRINT_DEBUG_TABLES
1173 G4cout << *energyLossVector
1174 << *energyRangeVector
1175 << *rangeEnergyVector <<
G4endl;
1178 IonMatCouple ionMatCouple = std::make_pair(particle, matCutsCouple);
1180 E[ionMatCouple] = energyRangeVector;
1181 r[ionMatCouple] = rangeEnergyVector;
1194 UpdateRangeCache(particle, matCutsCouple);
1199 if(energyRange != 0 && rangeEnergy != 0) {
1202 G4double lowerEnEdge = energyRange -> GetLowEdgeEnergy( 0 );
1203 G4double lowerRangeEdge = rangeEnergy -> GetLowEdgeEnergy( 0 );
1206 G4double range = energyRange -> GetValue(kineticEnergy, b);
1209 if(kineticEnergy < lowerEnEdge) {
1211 range = energyRange -> GetValue(lowerEnEdge, b);
1212 range *= std::sqrt(kineticEnergy / lowerEnEdge);
1216 G4cout <<
"G4IonParametrisedLossModel::ComputeLossForStep() range = "
1217 << range /
mm <<
" mm, step = " << stepLength /
mm <<
" mm"
1222 G4double remRange = range - stepLength;
1226 if(remRange < 0.0) loss = kineticEnergy;
1227 else if(remRange < lowerRangeEdge) {
1229 G4double ratio = remRange / lowerRangeEdge;
1230 loss = kineticEnergy - ratio * ratio * lowerEnEdge;
1234 G4double energy = rangeEnergy -> GetValue(range - stepLength, b);
1235 loss = kineticEnergy -
energy;
1239 if(loss < 0.0) loss = 0.0;
1252 G4cerr <<
"G4IonParametrisedLossModel::AddDEDXTable() Cannot "
1253 <<
" add table: Invalid pointer."
1260 LossTableList::iterator iter = lossTableList.begin();
1261 LossTableList::iterator iter_end = lossTableList.end();
1263 for(;iter != iter_end; iter++) {
1266 if(tableName == nam) {
1267 G4cerr <<
"G4IonParametrisedLossModel::AddDEDXTable() Cannot "
1268 <<
" add table: Name already exists."
1276 if(scalingAlgorithm == 0)
1282 lossTableList.push_front(handler);
1292 LossTableList::iterator iter = lossTableList.begin();
1293 LossTableList::iterator iter_end = lossTableList.end();
1295 for(;iter != iter_end; iter++) {
1298 if(tableName == nam) {
1302 lossTableList.erase(iter);
1305 RangeEnergyTable::iterator iterRange = r.begin();
1306 RangeEnergyTable::iterator iterRange_end = r.end();
1308 for(;iterRange != iterRange_end; iterRange++)
1309 delete iterRange ->
second;
1312 EnergyRangeTable::iterator iterEnergy = E.begin();
1313 EnergyRangeTable::iterator iterEnergy_end = E.end();
1315 for(;iterEnergy != iterEnergy_end; iterEnergy++)
1316 delete iterEnergy ->
second;