LCOV - code coverage report
Current view: top level - src/module - ElectronPairProduction.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 85 92 92.4 %
Date: 2024-04-29 14:43:01 Functions: 9 10 90.0 %

          Line data    Source code
       1             : #include "crpropa/module/ElectronPairProduction.h"
       2             : #include "crpropa/Units.h"
       3             : #include "crpropa/ParticleID.h"
       4             : #include "crpropa/ParticleMass.h"
       5             : #include "crpropa/Random.h"
       6             : 
       7             : #include <fstream>
       8             : #include <limits>
       9             : #include <stdexcept>
      10             : 
      11             : namespace crpropa {
      12             : 
      13          10 : ElectronPairProduction::ElectronPairProduction(ref_ptr<PhotonField> photonField,
      14          10 :                 bool haveElectrons, double limit) {
      15          10 :         this->haveElectrons = haveElectrons;
      16          10 :         this->limit = limit;
      17          10 :         setPhotonField(photonField);
      18          10 : }
      19             : 
      20          19 : void ElectronPairProduction::setPhotonField(ref_ptr<PhotonField> photonField) {
      21          19 :         this->photonField = photonField;
      22          19 :         std::string fname = photonField->getFieldName();
      23          19 :         setDescription("ElectronPairProduction: " + fname);
      24          57 :         initRate(getDataPath("ElectronPairProduction/lossrate_" + fname + ".txt"));
      25          19 :         if (haveElectrons) { // Load secondary spectra only if electrons should be produced
      26           0 :                 initSpectrum(getDataPath("ElectronPairProduction/spectrum_" + fname.substr(0,3) + ".txt"));
      27             :         }
      28          19 : }
      29             : 
      30           1 : void ElectronPairProduction::setHaveElectrons(bool haveElectrons) {
      31           1 :         this->haveElectrons = haveElectrons;
      32           1 :         if (haveElectrons) { // Load secondary spectra in case haveElectrons was changed to true
      33           1 :                 std::string fname = photonField->getFieldName();
      34           3 :                 initSpectrum(getDataPath("ElectronPairProduction/spectrum_" + fname.substr(0,3) + ".txt"));
      35             :         }
      36           1 : }
      37             : 
      38           0 : void ElectronPairProduction::setLimit(double limit) {
      39           0 :         this->limit = limit;
      40           0 : }
      41             : 
      42          19 : void ElectronPairProduction::initRate(std::string filename) {
      43          19 :         std::ifstream infile(filename.c_str());
      44             : 
      45          19 :         if (!infile.good())
      46           0 :                 throw std::runtime_error("ElectronPairProduction: could not open file " + filename);
      47             : 
      48             :         // clear previously loaded interaction rates
      49          19 :         tabLorentzFactor.clear();
      50          19 :         tabLossRate.clear();
      51             : 
      52        2853 :         while (infile.good()) {
      53        2834 :                 if (infile.peek() != '#') {
      54             :                         double a, b;
      55             :                         infile >> a >> b;
      56        2777 :                         if (infile) {
      57        2758 :                                 tabLorentzFactor.push_back(pow(10, a));
      58        2758 :                                 tabLossRate.push_back(b / Mpc);
      59             :                         }
      60             :                 }
      61        2834 :                 infile.ignore(std::numeric_limits < std::streamsize > ::max(), '\n');
      62             :         }
      63          19 :         infile.close();
      64          19 : }
      65             : 
      66           1 : void ElectronPairProduction::initSpectrum(std::string filename) {
      67           1 :         std::ifstream infile(filename.c_str());
      68           1 :         if (!infile.good())
      69           0 :                 throw std::runtime_error("ElectronPairProduction: could not open file " + filename);
      70             : 
      71             :         double dNdE;
      72           1 :         tabSpectrum.resize(70);
      73          71 :         for (size_t i = 0; i < 70; i++) {
      74          70 :                 tabSpectrum[i].resize(170);
      75       11970 :                 for (size_t j = 0; j < 170; j++) {
      76             :                         infile >> dNdE;
      77       11900 :                         tabSpectrum[i][j] = dNdE * pow(10, (7 + 0.1 * j)); // read electron distribution pdf(Ee) ~ dN/dEe * Ee
      78             :                 }
      79       11900 :                 for (size_t j = 1; j < 170; j++) {
      80       11830 :                         tabSpectrum[i][j] += tabSpectrum[i][j - 1]; // cdf(Ee), unnormalized
      81             :                 }
      82             :         }
      83           1 :         infile.close();
      84           1 : }
      85             : 
      86       65362 : double ElectronPairProduction::lossLength(int id, double lf, double z) const {
      87       65362 :         double Z = chargeNumber(id);
      88       65362 :         if (Z == 0)
      89             :                 return std::numeric_limits<double>::max(); // no pair production on uncharged particles
      90             : 
      91       64916 :         lf *= (1 + z);
      92       64916 :         if (lf < tabLorentzFactor.front())
      93             :                 return std::numeric_limits<double>::max(); // below energy threshold
      94             : 
      95             :         double rate;
      96       64893 :         if (lf < tabLorentzFactor.back())
      97       64893 :                 rate = interpolate(lf, tabLorentzFactor, tabLossRate); // interpolation
      98             :         else
      99           0 :                 rate = tabLossRate.back() * pow(lf / tabLorentzFactor.back(), -0.6); // extrapolation
     100             : 
     101       64893 :         double A = nuclearMass(id) / mass_proton; // more accurate than massNumber(Id)
     102       64893 :         rate *= Z * Z / A * pow_integer<3>(1 + z) * photonField->getRedshiftScaling(z);
     103       64893 :         return 1. / rate;
     104             : }
     105             : 
     106       65363 : void ElectronPairProduction::process(Candidate *c) const {
     107       65363 :         int id = c->current.getId();
     108       65363 :         if (not (isNucleus(id)))
     109             :                 return; // only nuclei
     110             : 
     111       65362 :         double lf = c->current.getLorentzFactor();
     112       65362 :         double z = c->getRedshift();
     113       65362 :         double losslen = lossLength(id, lf, z);  // energy loss length
     114       65362 :         if (losslen >= std::numeric_limits<double>::max())
     115             :                 return;
     116             : 
     117       64893 :         double step = c->getCurrentStep() / (1 + z); // step size in local frame
     118       64893 :         double loss = step / losslen;  // relative energy loss
     119             : 
     120       64893 :         if (haveElectrons) {
     121           1 :                 double dE = c->current.getEnergy() * loss;  // energy loss
     122           1 :                 int i = round((log10(lf) - 6.05) * 10);  // find closest cdf(Ee|log10(gamma))
     123           1 :                 i = std::min(std::max(i, 0), 69);
     124           1 :                 Random &random = Random::instance();
     125             : 
     126             :                 // draw pairs as long as their energy is smaller than the pair production energy loss
     127        7131 :                 while (dE > 0) {
     128        7131 :                         size_t j = random.randBin(tabSpectrum[i]);
     129        7131 :                         double Ee = pow(10, 6.95 + (j + random.rand()) * 0.1) * eV;
     130        7131 :                         double Epair = 2 * Ee; // NOTE: electron and positron in general don't have same lab frame energy, but averaged over many draws the result is consistent
     131             :                         // if the remaining energy is not sufficient check for random accepting
     132        7131 :                         if (Epair > dE)
     133           1 :                                 if (random.rand() > (dE / Epair))
     134             :                                         break; // not accepted
     135             : 
     136             :                         // create pair and repeat with remaining energy
     137        7130 :                         dE -= Epair;
     138        7130 :                         Vector3d pos = random.randomInterpolatedPosition(c->previous.getPosition(), c->current.getPosition());
     139        7130 :                         c->addSecondary( 11, Ee, pos, 1., interactionTag);
     140        7130 :                         c->addSecondary(-11, Ee, pos, 1., interactionTag);
     141             :                 }
     142             :         }
     143             : 
     144       64893 :         c->current.setLorentzFactor(lf * (1 - loss));
     145       64893 :         c->limitNextStep(limit * losslen);
     146             : }
     147             : 
     148           1 : void ElectronPairProduction::setInteractionTag(std::string tag) {
     149           1 :         interactionTag = tag;
     150           1 : }
     151             : 
     152           2 : std::string ElectronPairProduction::getInteractionTag() const {
     153           2 :         return interactionTag;
     154             : }
     155             : 
     156             : 
     157             : } // namespace crpropa

Generated by: LCOV version 1.14