Program Listing for File EMDoublePairProduction.cpp
↰ Return to documentation for file (src/module/EMDoublePairProduction.cpp
)
#include "crpropa/module/EMDoublePairProduction.h"
#include "crpropa/Units.h"
#include "crpropa/Random.h"
#include <fstream>
#include <limits>
#include <stdexcept>
namespace crpropa {
EMDoublePairProduction::EMDoublePairProduction(ref_ptr<PhotonField> photonField, bool haveElectrons, double thinning, double limit) {
setPhotonField(photonField);
setHaveElectrons(haveElectrons);
setLimit(limit);
setThinning(thinning);
}
void EMDoublePairProduction::setPhotonField(ref_ptr<PhotonField> photonField) {
this->photonField = photonField;
std::string fname = photonField->getFieldName();
setDescription("EMDoublePairProduction: " + fname);
initRate(getDataPath("EMDoublePairProduction/rate_" + fname + ".txt"));
}
void EMDoublePairProduction::setHaveElectrons(bool haveElectrons) {
this->haveElectrons = haveElectrons;
}
void EMDoublePairProduction::setLimit(double limit) {
this->limit = limit;
}
void EMDoublePairProduction::setThinning(double thinning) {
this->thinning = thinning;
}
void EMDoublePairProduction::initRate(std::string filename) {
std::ifstream infile(filename.c_str());
if (!infile.good())
throw std::runtime_error("EMDoublePairProduction: could not open file " + filename);
// clear previously loaded interaction rates
tabEnergy.clear();
tabRate.clear();
while (infile.good()) {
if (infile.peek() != '#') {
double a, b;
infile >> a >> b;
if (infile) {
tabEnergy.push_back(pow(10, a) * eV);
tabRate.push_back(b / Mpc);
}
}
infile.ignore(std::numeric_limits < std::streamsize > ::max(), '\n');
}
infile.close();
}
void EMDoublePairProduction::performInteraction(Candidate *candidate) const {
// the photon is lost after the interaction
candidate->setActive(false);
if (not haveElectrons)
return;
// Use assumption of Lee 96 arXiv:9604098
// Energy is equally shared between one e+e- pair, but take mass of second e+e- pair into account.
// This approximation has been shown to be valid within -1.5%.
double z = candidate->getRedshift();
double E = candidate->current.getEnergy() * (1 + z);
double Ee = (E - 2 * mass_electron * c_squared) / 2;
Random &random = Random::instance();
Vector3d pos = random.randomInterpolatedPosition(candidate->previous.getPosition(), candidate->current.getPosition());
double f = Ee / E;
if (haveElectrons) {
if (random.rand() < pow(1 - f, thinning)) {
double w = 1. / pow(1 - f, thinning);
candidate->addSecondary( 11, Ee / (1 + z), pos, w, interactionTag);
}
if (random.rand() < pow(f, thinning)) {
double w = 1. / pow(f, thinning);
candidate->addSecondary(-11, Ee / (1 + z), pos, w, interactionTag);
}
}
}
void EMDoublePairProduction::process(Candidate *candidate) const {
// check if photon
if (candidate->current.getId() != 22)
return;
// scale the electron energy instead of background photons
double z = candidate->getRedshift();
double E = (1 + z) * candidate->current.getEnergy();
// check if in tabulated energy range
if (E < tabEnergy.front() or (E > tabEnergy.back()))
return;
// interaction rate
double rate = interpolate(E, tabEnergy, tabRate);
rate *= pow_integer<2>(1 + z) * photonField->getRedshiftScaling(z);
// check for interaction
Random &random = Random::instance();
double randDistance = -log(random.rand()) / rate;
double step = candidate->getCurrentStep();
if (step < randDistance) {
candidate->limitNextStep(limit / rate);
return;
} else { // after performing interaction photon ceases to exist (hence return)
performInteraction(candidate);
return;
}
}
void EMDoublePairProduction::setInteractionTag(std::string tag) {
interactionTag = tag;
}
std::string EMDoublePairProduction::getInteractionTag() const {
return interactionTag;
}
} // namespace crpropa