Program Listing for File PhotoPionProduction.cpp
↰ Return to documentation for file (src/module/PhotoPionProduction.cpp
)
#include "crpropa/module/PhotoPionProduction.h"
#include "crpropa/Units.h"
#include "crpropa/ParticleID.h"
#include "crpropa/Random.h"
#include "kiss/convert.h"
#include "kiss/logger.h"
#include "sophia.h"
#include <limits>
#include <cmath>
#include <sstream>
#include <fstream>
#include <stdexcept>
namespace crpropa {
PhotoPionProduction::PhotoPionProduction(ref_ptr<PhotonField> field, bool photons, bool neutrinos, bool electrons, bool antiNucleons, double l, bool redshift) {
havePhotons = photons;
haveNeutrinos = neutrinos;
haveElectrons = electrons;
haveAntiNucleons = antiNucleons;
haveRedshiftDependence = redshift;
limit = l;
setPhotonField(field);
}
void PhotoPionProduction::setPhotonField(ref_ptr<PhotonField> field) {
photonField = field;
std::string fname = photonField->getFieldName();
if (haveRedshiftDependence) {
if (photonField->hasRedshiftDependence() == false){
std::cout << "PhotoPionProduction: tabulated redshift dependence not needed for " + fname + ", switching off" << std::endl;
haveRedshiftDependence = false;
}
else {
KISS_LOG_WARNING << "PhotoPionProduction: You are using the 2-dimensional tabulated redshift evolution, which is not available for other interactions. To be consistent across all interactions you may deactivate this <setHaveRedshiftDependence(False)>.";
}
}
setDescription("PhotoPionProduction: " + fname);
if (haveRedshiftDependence){
initRate(getDataPath("PhotoPionProduction/rate_" + fname.replace(0, 3, "IRBz") + ".txt"));
}
else
initRate(getDataPath("PhotoPionProduction/rate_" + fname + ".txt"));
}
void PhotoPionProduction::setHavePhotons(bool b) {
havePhotons = b;
}
void PhotoPionProduction::setHaveElectrons(bool b) {
haveElectrons = b;
}
void PhotoPionProduction::setHaveNeutrinos(bool b) {
haveNeutrinos = b;
}
void PhotoPionProduction::setHaveAntiNucleons(bool b) {
haveAntiNucleons = b;
}
void PhotoPionProduction::setHaveRedshiftDependence(bool b) {
haveRedshiftDependence = b;
setPhotonField(photonField);
}
void PhotoPionProduction::setLimit(double l) {
limit = l;
}
void PhotoPionProduction::initRate(std::string filename) {
// clear previously loaded tables
tabLorentz.clear();
tabRedshifts.clear();
tabProtonRate.clear();
tabNeutronRate.clear();
std::ifstream infile(filename.c_str());
if (!infile.good())
throw std::runtime_error("PhotoPionProduction: could not open file " + filename);
if (haveRedshiftDependence) {
double zOld = -1, aOld = -1;
while (infile.good()) {
if (infile.peek() == '#') {
infile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
continue;
}
double z, a, b, c;
infile >> z >> a >> b >> c;
if (!infile)
break;
if (z > zOld) {
tabRedshifts.push_back(z);
zOld = z;
}
if (a > aOld) {
tabLorentz.push_back(pow(10, a));
aOld = a;
}
tabProtonRate.push_back(b / Mpc);
tabNeutronRate.push_back(c / Mpc);
}
} else {
while (infile.good()) {
if (infile.peek() == '#') {
infile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
continue;
}
double a, b, c;
infile >> a >> b >> c;
if (!infile)
break;
tabLorentz.push_back(pow(10, a));
tabProtonRate.push_back(b / Mpc);
tabNeutronRate.push_back(c / Mpc);
}
}
infile.close();
}
double PhotoPionProduction::nucleonMFP(double gamma, double z, bool onProton) const {
const std::vector<double> &tabRate = (onProton)? tabProtonRate : tabNeutronRate;
// scale nucleus energy instead of background photon energy
gamma *= (1 + z);
if (gamma < tabLorentz.front() or (gamma > tabLorentz.back()))
return std::numeric_limits<double>::max();
double rate;
if (haveRedshiftDependence)
rate = interpolate2d(z, gamma, tabRedshifts, tabLorentz, tabRate);
else
rate = interpolate(gamma, tabLorentz, tabRate) * photonField->getRedshiftScaling(z);
// cosmological scaling
rate *= pow_integer<2>(1 + z);
return 1. / rate;
}
double PhotoPionProduction::nucleiModification(int A, int X) const {
if (A == 1)
return 1.;
if (A <= 8)
return 0.85 * pow(X, 2. / 3.);
return 0.85 * X;
}
void PhotoPionProduction::process(Candidate *candidate) const {
double step = candidate->getCurrentStep();
double z = candidate->getRedshift();
// the loop is processed at least once for limiting the next step
do {
// check if nucleus
int id = candidate->current.getId();
if (!isNucleus(id))
return;
// find interaction with minimum random distance
Random &random = Random::instance();
double randDistance = std::numeric_limits<double>::max();
double meanFreePath;
double totalRate = 0;
bool onProton = true; // interacting particle: proton or neutron
int A = massNumber(id);
int Z = chargeNumber(id);
int N = A - Z;
double gamma = candidate->current.getLorentzFactor();
// check for interaction on protons
if (Z > 0) {
meanFreePath = nucleonMFP(gamma, z, true) / nucleiModification(A, Z);
randDistance = -log(random.rand()) * meanFreePath;
totalRate += 1. / meanFreePath;
}
// check for interaction on neutrons
if (N > 0) {
meanFreePath = nucleonMFP(gamma, z, false) / nucleiModification(A, N);
totalRate += 1. / meanFreePath;
double d = -log(random.rand()) * meanFreePath;
if (d < randDistance) {
randDistance = d;
onProton = false;
}
}
// check if interaction does not happen
if (step < randDistance) {
if (totalRate > 0.)
candidate->limitNextStep(limit / totalRate);
return;
}
// interact and repeat with remaining step
performInteraction(candidate, onProton);
step -= randDistance;
} while (step > 0);
}
void PhotoPionProduction::performInteraction(Candidate *candidate, bool onProton) const {
int id = candidate->current.getId();
int A = massNumber(id);
int Z = chargeNumber(id);
double E = candidate->current.getEnergy();
double EpA = E / A;
double z = candidate->getRedshift();
// SOPHIA simulates interactions only for protons / neutrons.
// For anti-protons / neutrons assume charge symmetry and change all
// interaction products from particle <--> anti-particle (sign)
int sign = (id > 0) ? 1 : -1;
// check if below SOPHIA's energy threshold
double E_threshold = (photonField->getFieldName() == "CMB") ? 3.72e18 * eV : 5.83e15 * eV;
if (EpA * (1 + z) < E_threshold)
return;
// SOPHIA - input:
int nature = 1 - static_cast<int>(onProton); // 0=proton, 1=neutron
double Ein = EpA / GeV; // GeV is the SOPHIA standard unit
double eps = sampleEps(onProton, EpA, z) / GeV; // GeV for SOPHIA
// SOPHIA - output:
double outputEnergy[5][2000]; // [GeV/c, GeV/c, GeV/c, GeV, GeV/c^2]
int outPartID[2000];
int nParticles;
#pragma omp critical
{
sophiaevent_(nature, Ein, eps, outputEnergy, outPartID, nParticles);
}
Random &random = Random::instance();
Vector3d pos = random.randomInterpolatedPosition(candidate->previous.getPosition(), candidate->current.getPosition());
std::vector<int> pnType; // filled with either 13 (proton) or 14 (neutron)
std::vector<double> pnEnergy; // corresponding energies of proton or neutron
if (nParticles == 0)
return;
for (int i = 0; i < nParticles; i++) { // loop over out-going particles
double Eout = outputEnergy[3][i] * GeV; // only the energy is used; could be changed for more detail
int pType = outPartID[i];
switch (pType) {
case 13: // proton
case 14: // neutron
// proton and neutron data is taken to determine primary particle in a later step
pnType.push_back(pType);
pnEnergy.push_back(Eout);
break;
case -13: // anti-proton
case -14: // anti-neutron
if (haveAntiNucleons)
try
{
candidate->addSecondary(-sign * nucleusId(1, 14 + pType), Eout, pos, 1., interactionTag);
}
catch (std::runtime_error &e)
{
KISS_LOG_ERROR<< "Something went wrong in the PhotoPionProduction (anti-nucleon production)\n" << "Something went wrong in the PhotoPionProduction\n"<< "Please report this error on https://github.com/CRPropa/CRPropa3/issues including your simulation setup and the following random seed:\n" << Random::instance().getSeed_base64();
throw;
}
break;
case 1: // photon
if (havePhotons)
candidate->addSecondary(22, Eout, pos, 1., interactionTag);
break;
case 2: // positron
if (haveElectrons)
candidate->addSecondary(sign * -11, Eout, pos, 1., interactionTag);
break;
case 3: // electron
if (haveElectrons)
candidate->addSecondary(sign * 11, Eout, pos, 1., interactionTag);
break;
case 15: // nu_e
if (haveNeutrinos)
candidate->addSecondary(sign * 12, Eout, pos, 1., interactionTag);
break;
case 16: // anti-nu_e
if (haveNeutrinos)
candidate->addSecondary(sign * -12, Eout, pos, 1., interactionTag);
break;
case 17: // nu_mu
if (haveNeutrinos)
candidate->addSecondary(sign * 14, Eout, pos, 1., interactionTag);
break;
case 18: // anti-nu_mu
if (haveNeutrinos)
candidate->addSecondary(sign * -14, Eout, pos, 1., interactionTag);
break;
default:
throw std::runtime_error("PhotoPionProduction: unexpected particle " + kiss::str(pType));
}
}
double maxEnergy = *std::max_element(pnEnergy.begin(), pnEnergy.end()); // criterion for being declared primary
for (int i = 0; i < pnEnergy.size(); ++i) {
if (pnEnergy[i] == maxEnergy) { // nucleon is primary particle
if (A == 1) {
// single interacting nucleon
candidate->current.setEnergy(pnEnergy[i]);
try
{
candidate->current.setId(sign * nucleusId(1, 14 - pnType[i]));
}
catch (std::runtime_error &e)
{
KISS_LOG_ERROR<< "Something went wrong in the PhotoPionProduction (primary particle, A==1)\n" << "Please report this error on https://github.com/CRPropa/CRPropa3/issues including your simulation setup and the following random seed:\n" << Random::instance().getSeed_base64();
throw;
}
} else {
// interacting nucleon is part of nucleus: it is emitted from the nucleus
candidate->current.setEnergy(E - EpA);
try
{
candidate->current.setId(sign * nucleusId(A - 1, Z - int(onProton)));
candidate->addSecondary(sign * nucleusId(1, 14 - pnType[i]), pnEnergy[i], pos, 1., interactionTag);
}
catch (std::runtime_error &e)
{
KISS_LOG_ERROR<< "Something went wrong in the PhotoPionProduction (primary particle, A!=1)\n" << "Please report this error on https://github.com/CRPropa/CRPropa3/issues including your simulation setup and the following random seed:\n" << Random::instance().getSeed_base64();
throw;
}
}
} else { // nucleon is secondary proton or neutron
candidate->addSecondary(sign * nucleusId(1, 14 - pnType[i]), pnEnergy[i], pos, 1., interactionTag);
}
}
}
double PhotoPionProduction::lossLength(int id, double gamma, double z) {
int A = massNumber(id);
int Z = chargeNumber(id);
int N = A - Z;
double lossRate = 0;
if (Z > 0)
lossRate += 1 / nucleonMFP(gamma, z, true) * nucleiModification(A, Z);
if (N > 0)
lossRate += 1 / nucleonMFP(gamma, z, false) * nucleiModification(A, N);
// approximate the relative energy loss
// - nucleons keep the fraction of mass to delta-resonance mass
// - nuclei lose the energy 1/A the interacting nucleon is carrying
double relativeEnergyLoss = (A == 1) ? 1 - 938. / 1232. : 1. / A;
lossRate *= relativeEnergyLoss;
// scaling factor: interaction rate --> energy loss rate
lossRate *= (1 + z);
return 1. / lossRate;
}
SophiaEventOutput PhotoPionProduction::sophiaEvent(bool onProton, double Ein, double eps) const {
// SOPHIA - input:
int nature = 1 - static_cast<int>(onProton); // 0=proton, 1=neutron
Ein /= GeV; // GeV is the SOPHIA standard unit
eps /= GeV; // GeV for SOPHIA
// SOPHIA - output:
double outputEnergy[5][2000]; // [Px GeV/c, Py GeV/c, Pz GeV/c, E GeV, m0 GeV/c^2]
int outPartID[2000];
int nParticles;
sophiaevent_(nature, Ein, eps, outputEnergy, outPartID, nParticles);
// convert SOPHIA IDs to PDG naming convention & create particles
SophiaEventOutput output;
output.nParticles = nParticles;
for (int i = 0; i < nParticles; ++i) {
int id = 0;
int partType = outPartID[i];
switch (partType) {
case 13: // proton
case 14: // neutron
id = nucleusId(1, 14 - partType);
break;
case -13: // anti-proton
case -14: // anti-neutron
id = -nucleusId(1, 14 + partType);
break;
case 1: // photon
id = 22;
break;
case 2: // positron
id = -11;
break;
case 3: // electron
id = 11;
break;
case 15: // nu_e
id = 12;
break;
case 16: // anti-nu_e
id = -12;
break;
case 17: // nu_mu
id = 14;
break;
case 18: // anti-nu_mu
id = -14;
break;
default:
throw std::runtime_error("PhotoPionProduction: unexpected particle " + kiss::str(partType));
}
output.energy.push_back(outputEnergy[3][i] * GeV); // only the energy is used; could be changed for more detail
output.id.push_back(id);
}
return output;
}
double PhotoPionProduction::sampleEps(bool onProton, double E, double z) const {
// sample eps between epsMin ... epsMax
double Ein = E / GeV;
double epsMin = std::max(photonField -> getMinimumPhotonEnergy(z) / eV, epsMinInteraction(onProton, Ein));
double epsMax = photonField -> getMaximumPhotonEnergy(z) / eV;
double pEpsMax = probEpsMax(onProton, Ein, z, epsMin, epsMax);
Random &random = Random::instance();
for (int i = 0; i < 1000000; i++) {
double eps = epsMin + random.rand() * (epsMax - epsMin);
double pEps = probEps(eps, onProton, Ein, z);
if (random.rand() * pEpsMax < pEps)
return eps * eV;
}
throw std::runtime_error("error: no photon found in sampleEps, please make sure that photon field provides photons for the interaction by adapting the energy range of the tabulated photon field.");
}
double PhotoPionProduction::epsMinInteraction(bool onProton, double Ein) const {
// labframe energy of least energetic photon where PPP can occur
// this kind-of ties samplingEps to the PPP and SOPHIA
const double m = mass(onProton);
const double p = momentum(onProton, Ein);
double epsMin = 1.e9 * (1.1646 - m * m) / 2. / (Ein + p); // eV
return epsMin;
}
double PhotoPionProduction::probEpsMax(bool onProton, double Ein, double z, double epsMin, double epsMax) const {
// find pEpsMax by testing photon energies (eps) for their interaction
// probabilities (p) in order to find the maximum (max) probability
const int nrSteps = 100;
double pEpsMaxTested = 0.;
double step = 0.;
if (sampleLog){
// sample in logspace with stepsize that is at max Δlog(E/eV) = 0.01 or otherwise dep. on size of energy range with nrSteps+1 steps log. equidis. spaced
step = std::min(0.01, std::log10(epsMax / epsMin) / nrSteps);
} else
step = (epsMax - epsMin) / nrSteps;
double epsDummy = 0.;
int i = 0;
while (epsDummy < epsMax) {
if (sampleLog)
epsDummy = epsMin * pow(10, step * i);
else
epsDummy = epsMin + step * i;
double p = probEps(epsDummy, onProton, Ein, z);
if(p > pEpsMaxTested)
pEpsMaxTested = p;
i++;
}
// the following factor corrects for only trying to find the maximum on nrIteration photon energies
// the factor should be determined in convergence tests
double pEpsMax = pEpsMaxTested * correctionFactor;
if(pEpsMax == 0) {
KISS_LOG_WARNING << "pEpsMax is 0 in the following configuration: \n"
<< "\t" << "onProton: " << onProton << "\n"
<< "\t" << "Ein: " << Ein << " [GeV] \n"
<< "\t" << "epsRange [eV] " << epsMin << "\t" << epsMax << "\n"
<< "\t" << "redshift: " << z << "\n"
<< "\t" << "sample Log " << sampleLog << " with step " << step << " [eV] \n";
}
return pEpsMax;
}
double PhotoPionProduction::probEps(double eps, bool onProton, double Ein, double z) const {
// probEps returns "probability to encounter a photon of energy eps", given a primary nucleon
// note, probEps does not return a normalized probability [0,...,1]
double photonDensity = photonField->getPhotonDensity(eps * eV, z) * ccm / eps;
if (photonDensity != 0.) {
const double p = momentum(onProton, Ein);
const double sMax = mass(onProton) * mass(onProton) + 2. * eps * (Ein + p) / 1.e9;
if (sMax <= sMin())
return 0;
double sIntegr = gaussInt([this, onProton](double s) { return this->functs(s, onProton); }, sMin(), sMax);
return photonDensity * sIntegr / eps / eps / p / 8. * 1.e18 * 1.e6;
}
return 0;
}
double PhotoPionProduction::momentum(bool onProton, double Ein) const {
const double m = mass(onProton);
const double momentumHadron = sqrt(Ein * Ein - m * m); // GeV/c
return momentumHadron;
}
double PhotoPionProduction::crossection(double eps, bool onProton) const {
const double m = mass(onProton);
const double s = m * m + 2. * m * eps;
if (s < sMin())
return 0.;
double cross_res = 0.;
double cross_dir = 0.;
double cross_dir1 = 0.;
double cross_dir2 = 0.;
double sig_res[9];
// first half of array: 9x proton resonance data | second half of array 9x neutron resonance data
static const double AMRES[18] = {1.231, 1.440, 1.515, 1.525, 1.675, 1.680, 1.690, 1.895, 1.950, 1.231, 1.440, 1.515, 1.525, 1.675, 1.675, 1.690, 1.895, 1.950};
static const double BGAMMA[18] = {5.6, 0.5, 4.6, 2.5, 1.0, 2.1, 2.0, 0.2, 1.0, 6.1, 0.3, 4.0, 2.5, 0.0, 0.2, 2.0, 0.2, 1.0};
static const double WIDTH[18] = {0.11, 0.35, 0.11, 0.1, 0.16, 0.125, 0.29, 0.35, 0.3, 0.11, 0.35, 0.11, 0.1, 0.16, 0.150, 0.29, 0.35, 0.3};
static const double RATIOJ[18] = {1., 0.5, 1., 0.5, 0.5, 1.5, 1., 1.5, 2., 1., 0.5, 1., 0.5, 0.5, 1.5, 1., 1.5, 2.};
static const double AM2[2] = {0.882792, 0.880351};
const int idx = onProton? 0 : 9;
double SIG0[9];
for (int i = 0; i < 9; ++i) {
SIG0[i] = 4.893089117 / AM2[int(onProton)] * RATIOJ[i + idx] * BGAMMA[i + idx];
}
if (eps <= 10.) {
cross_res = breitwigner(SIG0[0], WIDTH[0 + idx], AMRES[0 + idx], eps, onProton) * Ef(eps, 0.152, 0.17);
sig_res[0] = cross_res;
for (int i = 1; i < 9; ++i) {
sig_res[i] = breitwigner(SIG0[i], WIDTH[i + idx], AMRES[i + idx], eps, onProton) * Ef(eps, 0.15, 0.38);
cross_res += sig_res[i];
}
// direct channel
if ((eps > 0.1) && (eps < 0.6)) {
cross_dir1 = 92.7 * Pl(eps, 0.152, 0.25, 2.0) // single pion production
+ 40. * std::exp(-(eps - 0.29) * (eps - 0.29) / 0.002)
- 15. * std::exp(-(eps - 0.37) * (eps - 0.37) / 0.002);
} else {
cross_dir1 = 92.7 * Pl(eps, 0.152, 0.25, 2.0); // single pion production
}
cross_dir2 = 37.7 * Pl(eps, 0.4, 0.6, 2.0); // double pion production
cross_dir = cross_dir1 + cross_dir2;
}
// fragmentation 2:
double cross_frag2 = onProton? 80.3 : 60.2;
cross_frag2 *= Ef(eps, 0.5, 0.1) * std::pow(s, -0.34);
// multipion production/fragmentation 1 cross section
double cs_multidiff = 0.;
double cs_multi = 0.;
double cross_diffr1 = 0.;
double cross_diffr2 = 0.;
double cross_diffr = 0.;
if (eps > 0.85) {
double ss1 = (eps - 0.85) / 0.69;
double ss2 = onProton? 29.3 : 26.4;
ss2 *= std::pow(s, -0.34) + 59.3 * std::pow(s, 0.095);
cs_multidiff = (1. - std::exp(-ss1)) * ss2;
cs_multi = 0.89 * cs_multidiff;
// diffractive scattering:
cross_diffr1 = 0.099 * cs_multidiff;
cross_diffr2 = 0.011 * cs_multidiff;
cross_diffr = 0.11 * cs_multidiff;
// **************************************
ss1 = std::pow(eps - 0.85, 0.75) / 0.64;
ss2 = 74.1 * std::pow(eps, -0.44) + 62. * std::pow(s, 0.08);
double cs_tmp = 0.96 * (1. - std::exp(-ss1)) * ss2;
cross_diffr1 = 0.14 * cs_tmp;
cross_diffr2 = 0.013 * cs_tmp;
double cs_delta = cross_frag2 - (cross_diffr1 + cross_diffr2 - cross_diffr);
if (cs_delta < 0.) {
cross_frag2 = 0.;
cs_multi += cs_delta;
} else {
cross_frag2 = cs_delta;
}
cross_diffr = cross_diffr1 + cross_diffr2;
cs_multidiff = cs_multi + cross_diffr;
// in the original SOPHIA code, here is a switch for the return argument.
// Here, only one case (compare in SOPHIA: NDIR=3) is needed.
}
return cross_res + cross_dir + cs_multidiff + cross_frag2;
}
double PhotoPionProduction::Pl(double eps, double epsTh, double epsMax, double alpha) const {
if (epsTh > eps)
return 0.;
const double a = alpha * epsMax / epsTh;
const double prod1 = std::pow((eps - epsTh) / (epsMax - epsTh), a - alpha);
const double prod2 = std::pow(eps / epsMax, -a);
return prod1 * prod2;
}
double PhotoPionProduction::Ef(double eps, double epsTh, double w) const {
const double wTh = w + epsTh;
if (eps <= epsTh) {
return 0.;
} else if ((eps > epsTh) && (eps < wTh)) {
return (eps - epsTh) / w;
} else if (eps >= wTh) {
return 1.;
} else {
throw std::runtime_error("error in function Ef");
}
}
double PhotoPionProduction::breitwigner(double sigma0, double gamma, double DMM, double epsPrime, bool onProton) const {
const double m = mass(onProton);
const double s = m * m + 2. * m * epsPrime;
const double gam2s = gamma * gamma * s;
return sigma0 * (s / epsPrime / epsPrime) * gam2s / ((s - DMM * DMM) * (s - DMM * DMM) + gam2s);
}
double PhotoPionProduction::functs(double s, bool onProton) const {
const double m = mass(onProton);
const double factor = s - m * m;
const double epsPrime = factor / 2. / m;
const double sigmaPg = crossection(epsPrime, onProton);
return factor * sigmaPg;
}
double PhotoPionProduction::mass(bool onProton) const {
const double m = onProton ? mass_proton : mass_neutron;
return m / GeV * c_squared;
}
double PhotoPionProduction::sMin() const {
return 1.1646; // [GeV^2] head-on collision
}
void PhotoPionProduction::setSampleLog(bool b) {
sampleLog = b;
}
void PhotoPionProduction::setCorrectionFactor(double factor) {
correctionFactor = factor;
}
ref_ptr<PhotonField> PhotoPionProduction::getPhotonField() const {
return photonField;
}
bool PhotoPionProduction::getHavePhotons() const {
return havePhotons;
}
bool PhotoPionProduction::getHaveNeutrinos() const {
return haveNeutrinos;
}
bool PhotoPionProduction::getHaveElectrons() const {
return haveElectrons;
}
bool PhotoPionProduction::getHaveAntiNucleons() const {
return haveAntiNucleons;
}
bool PhotoPionProduction::getHaveRedshiftDependence() const {
return haveRedshiftDependence;
}
double PhotoPionProduction::getLimit() const {
return limit;
}
bool PhotoPionProduction::getSampleLog() const {
return sampleLog;
}
double PhotoPionProduction::getCorrectionFactor() const {
return correctionFactor;
}
void PhotoPionProduction::setInteractionTag(std::string tag) {
interactionTag = tag;
}
std::string PhotoPionProduction::getInteractionTag() const {
return interactionTag;
}
} // namespace crpropa