LCOV - code coverage report
Current view: top level - src/module - EMTripletPairProduction.cpp (source / functions) Coverage Total Hit
Test: coverage.info.cleaned Lines: 79.3 % 92 73
Test Date: 2026-07-13 06:03:10 Functions: 68.8 % 16 11

            Line data    Source code
       1              : #include "crpropa/module/EMTripletPairProduction.h"
       2              : #include "crpropa/Units.h"
       3              : #include "crpropa/Random.h"
       4              : #include "crpropa/Common.h"
       5              : 
       6              : #include <vector>
       7              : #include <cmath>
       8              : 
       9              : namespace crpropa {
      10              : 
      11              : static const double mec2 = mass_electron * c_squared;
      12              : 
      13            3 : EMTripletPairProduction::EMTripletPairProduction(ref_ptr<PhotonField> photonField, bool haveElectrons, double thinning, double limit, ref_ptr<Surface> surface) {
      14            6 :         setSurface(surface);
      15            3 :         setPhotonField(photonField);
      16            3 :         setHaveElectrons(haveElectrons);
      17            3 :         setLimit(limit);
      18            3 :         setThinning(thinning);
      19            3 : }
      20              : 
      21           15 : void EMTripletPairProduction::setPhotonField(ref_ptr<PhotonField> photonField) {
      22           15 :         this->photonField = photonField;
      23           15 :         std::string fname = photonField->getFieldName();
      24           30 :         setDescription("EMTripletPairProduction: " + fname);
      25           15 :         if (!this->photonField->hasPositionDependence()){
      26              :                 this->interactionRates = new InteractionRatesHomogeneous(
      27           45 :                         getDataPath("EMTripletPairProduction/rate_" + fname + ".txt"),
      28           45 :                         getDataPath("EMTripletPairProduction/cdf_" + fname + ".txt")
      29           30 :                 );
      30              :         } else {
      31              :                 this->interactionRates = new InteractionRatesPositionDependent(
      32            0 :                         getDataPath("EMTripletPairProduction/"+fname+"/Rate/"),
      33            0 :                         getDataPath("EMTripletPairProduction/"+fname+"/CumulativeRate/"),
      34              :                         this->surface
      35            0 :                 );              
      36              :         }
      37           15 : }
      38              : 
      39            4 : void EMTripletPairProduction::setHaveElectrons(bool haveElectrons) {
      40            4 :         this->haveElectrons = haveElectrons;
      41            4 : }
      42              : 
      43            3 : void EMTripletPairProduction::setLimit(double limit) {
      44            3 :         this->limit = limit;
      45            3 : }
      46              : 
      47            3 : void EMTripletPairProduction::setThinning(double thinning) {
      48            3 :         this->thinning = thinning;
      49            3 : }
      50              : 
      51            3 : void EMTripletPairProduction::setSurface(ref_ptr<Surface> surface) {
      52            3 :         this->surface = surface;
      53            3 : }
      54              : 
      55            0 : ref_ptr<Surface> EMTripletPairProduction::getSurface() const {
      56            0 :         return this->surface;
      57              : }
      58              : 
      59            0 : void EMTripletPairProduction::setInteractionRates(ref_ptr<InteractionRates> intRates) {
      60            0 :         this->interactionRates = intRates;
      61            0 : }
      62              : 
      63            0 : ref_ptr<InteractionRates> EMTripletPairProduction::getInteractionRates() const {
      64            0 :         return this->interactionRates;
      65              : }
      66              : 
      67            0 : void EMTripletPairProduction::initRate(std::string path) {
      68            0 :         this->interactionRates->initRate(path);
      69            0 : }
      70              : 
      71            0 : void EMTripletPairProduction::initCumulativeRate(std::string path) {
      72            0 :         this->interactionRates->initCumulativeRate(path);
      73            0 : }
      74              : 
      75            1 : double EMTripletPairProduction::getRate(double E, const Vector3d &position, double z) const {
      76            1 :         return this->interactionRates->getProcessRate(E, position) * pow_integer<2>(1 + z) * photonField->getRedshiftScaling(z);
      77              : }
      78              : 
      79            1 : void EMTripletPairProduction::performInteraction(Candidate *candidate) const {
      80              :         
      81              :         // scale the particle energy instead of background photons
      82            1 :         double z = candidate->getRedshift();
      83            1 :         double E = candidate->current.getEnergy() * (1 + z);
      84            1 :         Vector3d position = candidate->current.getPosition();
      85              :         
      86              :         std::vector<double> tabE;
      87              :         std::vector<double> tabs;
      88              :         std::vector<std::vector<double>> tabCDF;
      89              :         
      90            1 :         this->interactionRates->loadPerformInteractionTabs(position, tabE, tabs, tabCDF);
      91              :         
      92            1 :         if (E < tabE.front() or E > tabE.back())
      93              :                 return;
      94              :         
      95              :         // sample the value of eps
      96            1 :         Random &random = Random::instance();
      97            1 :         size_t i = closestIndex(E, tabE);
      98            1 :         size_t j = random.randBin(tabCDF[i]);
      99            1 :         double s_kin = pow(10, log10(tabs[j]) + (random.rand() - 0.5) * 0.1);
     100            1 :         double eps = s_kin / 4. / E; // random background photon energy
     101              :         
     102              :         // Use approximation from A. Mastichiadis et al., Astroph. Journ. 300:178-189 (1986), eq. 30.
     103              :         // This approx is valid only for alpha >=100 where alpha = p0*eps*costheta - E0*eps
     104              :         // For our purposes, me << E0 --> p0~E0 --> alpha = E0*eps*(costheta - 1) >= 100
     105            1 :         double Epp = 5.7e-1 * pow(eps / mec2, -0.56) * pow(E / mec2, 0.44) * mec2;
     106              :         
     107            1 :         double f = Epp / E;
     108              :         
     109            1 :         if (haveElectrons) {
     110            1 :                 Vector3d pos = random.randomInterpolatedPosition(candidate->previous.getPosition(), candidate->current.getPosition());
     111            1 :                 if (random.rand() < pow(1 - f, thinning)) {
     112            1 :                         double w = 1. / pow(1 - f, thinning);
     113            1 :                         candidate->addSecondary(11, Epp / (1 + z), pos, w, interactionTag);
     114              :                 }
     115            1 :                 if (random.rand() < pow(f, thinning)) {
     116            1 :                         double w = 1. / pow(f, thinning);
     117            1 :                         candidate->addSecondary(-11, Epp / (1 + z), pos, w, interactionTag);
     118              :                 }
     119              :         }
     120              :         
     121              :         // Update the primary particle energy.
     122              :         // This is done after adding the secondaries to correctly set the secondaries parent
     123            1 :         candidate->current.setEnergy((E - 2 * Epp) / (1. + z));
     124            1 : }
     125              : 
     126            1 : void EMTripletPairProduction::process(Candidate *candidate) const {
     127              :         // check if electron / positron
     128            1 :         int id = candidate->current.getId();
     129            1 :         if (abs(id) != 11)
     130            1 :                 return;
     131              :         
     132              :         // scale the particle energy instead of background photons
     133            1 :         double z = candidate->getRedshift();
     134            1 :         double E = (1 + z) * candidate->current.getEnergy();
     135            1 :         Vector3d position = candidate->current.getPosition();
     136              :         
     137              :         // interaction rate
     138            1 :         double rate = getRate(E, position, z);
     139            1 :         if (rate < 0)
     140              :                 return;
     141              :         
     142              :         
     143              :         // run this loop at least once to limit the step size
     144            1 :         double step = candidate->getCurrentStep();
     145            1 :         Random &random = Random::instance();
     146              :         do {
     147            1 :                 double randDistance = -log(random.rand()) / rate;
     148              :                 // check for interaction; if it doesn't occur, limit next step
     149            1 :                 if (step < randDistance) {
     150            1 :                         candidate->limitNextStep(limit / rate);
     151            1 :                         return;
     152              :                 }
     153            0 :                 performInteraction(candidate);
     154            0 :                 step -= randDistance;
     155            0 :         } while (step > 0.);
     156              : }
     157              : 
     158            1 : void EMTripletPairProduction::setInteractionTag(std::string tag) {
     159            1 :         interactionTag = tag;
     160            1 : }
     161              : 
     162            2 : std::string EMTripletPairProduction::getInteractionTag() const {
     163            2 :         return interactionTag;
     164              : }
     165              : 
     166              : } // namespace crpropa
        

Generated by: LCOV version 2.0-1