LCOV - code coverage report
Current view: top level - src/module - EMDoublePairProduction.cpp (source / functions) Coverage Total Hit
Test: coverage.info.cleaned Lines: 94.2 % 69 65
Test Date: 2026-06-18 09:49:19 Functions: 100.0 % 10 10

            Line data    Source code
       1              : #include "crpropa/module/EMDoublePairProduction.h"
       2              : #include "crpropa/Units.h"
       3              : #include "crpropa/Random.h"
       4              : 
       5              : #include <fstream>
       6              : #include <limits>
       7              : #include <stdexcept>
       8              : 
       9              : namespace crpropa {
      10              : 
      11            3 : EMDoublePairProduction::EMDoublePairProduction(ref_ptr<PhotonField> photonField, bool haveElectrons, double thinning, double limit) {
      12            3 :         setPhotonField(photonField);
      13            3 :         setHaveElectrons(haveElectrons);
      14            3 :         setLimit(limit);
      15            3 :         setThinning(thinning);
      16            3 : }
      17              : 
      18           15 : void EMDoublePairProduction::setPhotonField(ref_ptr<PhotonField> photonField) {
      19           15 :         this->photonField = photonField;
      20           15 :         std::string fname = photonField->getFieldName();
      21           15 :         setDescription("EMDoublePairProduction: " + fname);
      22           45 :         initRate(getDataPath("EMDoublePairProduction/rate_" + fname + ".txt"));
      23           15 : }
      24              : 
      25            4 : void EMDoublePairProduction::setHaveElectrons(bool haveElectrons) {
      26            4 :         this->haveElectrons = haveElectrons;
      27            4 : }
      28              : 
      29            3 : void EMDoublePairProduction::setLimit(double limit) {
      30            3 :         this->limit = limit;
      31            3 : }
      32              : 
      33            3 : void EMDoublePairProduction::setThinning(double thinning) {
      34            3 :         this->thinning = thinning;
      35            3 : }
      36              : 
      37           15 : void EMDoublePairProduction::initRate(std::string filename) {
      38           15 :         std::ifstream infile(filename.c_str());
      39              : 
      40           15 :         if (!infile.good())
      41            0 :                 throw std::runtime_error("EMDoublePairProduction: could not open file " + filename);
      42              : 
      43              :         // clear previously loaded interaction rates
      44              :         tabEnergy.clear();
      45              :         tabRate.clear();
      46              : 
      47         3306 :         while (infile.good()) {
      48         3291 :                 if (infile.peek() != '#') {
      49              :                         double a, b;
      50              :                         infile >> a >> b;
      51         3231 :                         if (infile) {
      52         3216 :                                 tabEnergy.push_back(pow(10, a) * eV);
      53         3216 :                                 tabRate.push_back(b / Mpc);
      54              :                         }
      55              :                 }
      56         3291 :                 infile.ignore(std::numeric_limits < std::streamsize > ::max(), '\n');
      57              :         }
      58           15 :         infile.close();
      59           15 : }
      60              : 
      61              : 
      62            1 : void EMDoublePairProduction::performInteraction(Candidate *candidate) const {
      63              :         // the photon is lost after the interaction
      64            1 :         candidate->setActive(false);
      65              : 
      66            1 :         if (not haveElectrons)
      67            0 :                 return;
      68              : 
      69              :         // Use assumption of Lee 96 arXiv:9604098
      70              :         // Energy is equally shared between one e+e- pair, but take mass of second e+e- pair into account.
      71              :         // This approximation has been shown to be valid within -1.5%.
      72            1 :         double z = candidate->getRedshift();
      73            1 :         double E = candidate->current.getEnergy() * (1 + z);
      74            1 :         double Ee = (E - 2 * mass_electron * c_squared) / 2;
      75              : 
      76            1 :         Random &random = Random::instance();
      77            1 :         Vector3d pos = random.randomInterpolatedPosition(candidate->previous.getPosition(), candidate->current.getPosition());
      78              : 
      79            1 :         double f = Ee / E;
      80              : 
      81            1 :                 if (random.rand() < pow(1 - f, thinning)) {
      82            1 :                         double w = 1. / pow(1 - f, thinning);
      83            1 :                         candidate->addSecondary( 11, Ee / (1 + z), pos, w, interactionTag);
      84              :                 } 
      85            1 :                 if (random.rand() < pow(f, thinning)) {
      86            1 :                         double w = 1. / pow(f, thinning);
      87            1 :                         candidate->addSecondary(-11, Ee / (1 + z), pos, w, interactionTag);
      88              :                 }
      89              : }
      90              : 
      91            1 : void EMDoublePairProduction::process(Candidate *candidate) const {
      92              :         // check if photon
      93            1 :         if (candidate->current.getId() != 22)
      94              :                 return;
      95              : 
      96              :         // scale the electron energy instead of background photons
      97            1 :         double z = candidate->getRedshift();
      98            1 :         double E = (1 + z) * candidate->current.getEnergy();
      99              : 
     100              :         // check if in tabulated energy range
     101            1 :         if (E < tabEnergy.front() or (E > tabEnergy.back()))
     102              :                 return;
     103              : 
     104              :         // interaction rate
     105            1 :         double rate = interpolate(E, tabEnergy, tabRate);
     106            1 :         rate *= pow_integer<2>(1 + z) * photonField->getRedshiftScaling(z);
     107              : 
     108              :         // check for interaction
     109            1 :         Random &random = Random::instance();
     110            1 :         double randDistance = -log(random.rand()) / rate;
     111            1 :         double step = candidate->getCurrentStep();
     112            1 :         if (step < randDistance) {
     113            1 :                 candidate->limitNextStep(limit / rate);
     114            1 :                 return;
     115              :         } else { // after performing interaction photon ceases to exist (hence return)
     116            0 :                 performInteraction(candidate);
     117            0 :                 return;
     118              :         }
     119              : 
     120              : }
     121              : 
     122            1 : void EMDoublePairProduction::setInteractionTag(std::string tag) {
     123            1 :         interactionTag = tag;
     124            1 : }
     125              : 
     126            2 : std::string EMDoublePairProduction::getInteractionTag() const {
     127            2 :         return interactionTag;
     128              : }
     129              : 
     130              : 
     131              : } // namespace crpropa
        

Generated by: LCOV version 2.0-1