LCOV - code coverage report
Current view: top level - src - PhotonBackground.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 92 120 76.7 %
Date: 2024-04-29 14:43:01 Functions: 14 15 93.3 %

          Line data    Source code
       1             : #include "crpropa/PhotonBackground.h"
       2             : #include "crpropa/Units.h"
       3             : #include "crpropa/Random.h"
       4             : 
       5             : #include "kiss/logger.h"
       6             : 
       7             : #include <fstream>
       8             : #include <stdexcept>
       9             : #include <limits>
      10             : #include <cmath>
      11             : 
      12             : namespace crpropa {
      13             : 
      14          94 : TabularPhotonField::TabularPhotonField(std::string fieldName, bool isRedshiftDependent) {
      15          94 :         this->fieldName = fieldName;
      16          94 :         this->isRedshiftDependent = isRedshiftDependent;
      17             : 
      18         188 :         readPhotonEnergy(getDataPath("") + "Scaling/" + this->fieldName + "_photonEnergy.txt");
      19         188 :         readPhotonDensity(getDataPath("") + "Scaling/" + this->fieldName + "_photonDensity.txt");
      20          94 :         if (this->isRedshiftDependent)
      21         146 :                 readRedshift(getDataPath("") + "Scaling/" + this->fieldName + "_redshift.txt");
      22             : 
      23          94 :         checkInputData();
      24             : 
      25          94 :         if (this->isRedshiftDependent)
      26          73 :                 initRedshiftScaling();
      27          94 : }
      28             : 
      29             : 
      30     9586406 : double TabularPhotonField::getPhotonDensity(double Ephoton, double z) const {   
      31     9586406 :         if ((this->isRedshiftDependent)) {
      32             :                 // fix behaviour for future redshift. See issue #414
      33             :                 // with redshift < 0 the photon density is set to 0 in interpolate2d. 
      34             :                 // Therefore it is assumed that the photon density does not change from values at z = 0. This is only valid for small changes in redshift.
      35     9586406 :                 double zMin = this->redshifts[0];
      36     9586406 :                 if(z < zMin){
      37           0 :                         if(z < -1) {
      38           0 :                                 KISS_LOG_WARNING << "Photon Field " << fieldName << " uses FutureRedshift with z < -1. The photon density is set to n(Ephoton, z=0). \n";
      39             :                         }
      40           0 :                         return getPhotonDensity(Ephoton, zMin);
      41             :                 } else {
      42     9586406 :                         return interpolate2d(Ephoton, z, this->photonEnergies, this->redshifts, this->photonDensity);
      43             :                 }
      44             :         } else {
      45           0 :                 return interpolate(Ephoton, this->photonEnergies, this->photonDensity);
      46             :         }
      47             : }
      48             : 
      49             : 
      50       66390 : double TabularPhotonField::getRedshiftScaling(double z) const {
      51       66390 :         if (!this->isRedshiftDependent)
      52             :                 return 1.;
      53             :  
      54       66206 :         if (z < this->redshifts.front())
      55             :                 return 1.;
      56             :  
      57       66206 :         if (z > this->redshifts.back())
      58             :                 return 0.;
      59             :  
      60       66206 :         return interpolate(z, this->redshifts, this->redshiftScalings);
      61             : }
      62             : 
      63          22 : double TabularPhotonField::getMinimumPhotonEnergy(double z) const{
      64          22 :         return photonEnergies[0];
      65             : }
      66             : 
      67          22 : double TabularPhotonField::getMaximumPhotonEnergy(double z) const{
      68          22 :         return photonEnergies[photonEnergies.size() -1];
      69             : }
      70             : 
      71          94 : void TabularPhotonField::readPhotonEnergy(std::string filePath) {
      72          94 :         std::ifstream infile(filePath.c_str());
      73          94 :         if (!infile.good())
      74           0 :                 throw std::runtime_error("TabularPhotonField::readPhotonEnergy: could not open " + filePath);
      75             : 
      76             :         std::string line;
      77       15320 :         while (std::getline(infile, line)) {
      78       15226 :                 if ((line.size() > 0) & (line[0] != '#') )
      79       14944 :                         this->photonEnergies.push_back(std::stod(line));
      80             :         }
      81          94 :         infile.close();
      82          94 : }
      83             : 
      84          94 : void TabularPhotonField::readPhotonDensity(std::string filePath) {
      85          94 :         std::ifstream infile(filePath.c_str());
      86          94 :         if (!infile.good())
      87           0 :                 throw std::runtime_error("TabularPhotonField::readPhotonDensity: could not open " + filePath);
      88             : 
      89             :         std::string line;
      90     4772519 :         while (std::getline(infile, line)) {
      91     4772425 :                 if ((line.size() > 0) & (line[0] != '#') )
      92     4772143 :                         this->photonDensity.push_back(std::stod(line));
      93             :         }
      94          94 :         infile.close();
      95          94 : }
      96             : 
      97          73 : void TabularPhotonField::readRedshift(std::string filePath) {
      98          73 :         std::ifstream infile(filePath.c_str());
      99          73 :         if (!infile.good())
     100           0 :                 throw std::runtime_error("TabularPhotonField::initRedshift: could not open " + filePath);
     101             : 
     102             :         std::string line;
     103       14599 :         while (std::getline(infile, line)) {
     104       14526 :                 if ((line.size() > 0) & (line[0] != '#') )
     105       14307 :                         this->redshifts.push_back(std::stod(line));
     106             :         }
     107          73 :         infile.close();
     108          73 : }
     109             : 
     110          73 : void TabularPhotonField::initRedshiftScaling() {
     111             :         double n0 = 0.;
     112       14380 :         for (int i = 0; i < this->redshifts.size(); ++i) {
     113       14307 :                 double z = this->redshifts[i];
     114             :                 double n = 0.;
     115     4770022 :                 for (int j = 0; j < this->photonEnergies.size()-1; ++j) {
     116     4755715 :                         double e_j = this->photonEnergies[j];
     117     4755715 :                         double e_j1 = this->photonEnergies[j+1];
     118     4755715 :                         double deltaLogE = std::log10(e_j1) - std::log10(e_j);
     119     4755715 :                         if (z == 0.)
     120       12750 :                                 n0 += (getPhotonDensity(e_j, 0) + getPhotonDensity(e_j1, 0)) / 2. * deltaLogE;
     121     4755715 :                         n += (getPhotonDensity(e_j, z) + getPhotonDensity(e_j1, z)) / 2. * deltaLogE;
     122             :                 }
     123       14307 :                 this->redshiftScalings.push_back(n / n0);
     124             :         }
     125          73 : }
     126             : 
     127          94 : void TabularPhotonField::checkInputData() const {
     128          94 :         if (this->isRedshiftDependent) {
     129          73 :                 if (this->photonDensity.size() != this->photonEnergies.size() * this-> redshifts.size())
     130           0 :                         throw std::runtime_error("TabularPhotonField::checkInputData: length of photon density input is unequal to length of photon energy input times length of redshift input");
     131             :         } else {
     132          21 :                 if (this->photonEnergies.size() != this->photonDensity.size())
     133           0 :                         throw std::runtime_error("TabularPhotonField::checkInputData: length of photon energy input is unequal to length of photon density input");
     134             :         }
     135             : 
     136       15038 :         for (int i = 0; i < this->photonEnergies.size(); ++i) {
     137             :                 double ePrevious = 0.;
     138       14944 :                 double e = this->photonEnergies[i];
     139       14944 :                 if (e <= 0.)
     140           0 :                         throw std::runtime_error("TabularPhotonField::checkInputData: a value in the photon energy input is not positive");
     141             :                 if (e <= ePrevious)
     142             :                         throw std::runtime_error("TabularPhotonField::checkInputData: photon energy values are not strictly increasing");
     143             :                 ePrevious = e;
     144             :         }
     145             : 
     146     4772237 :         for (int i = 0; i < this->photonDensity.size(); ++i) {
     147     4772143 :                 if (this->photonDensity[i] < 0.)
     148           0 :                         throw std::runtime_error("TabularPhotonField::checkInputData: a value in the photon density input is negative");
     149             :         }
     150             : 
     151          94 :         if (this->isRedshiftDependent) {
     152          73 :                 if (this->redshifts[0] != 0.)
     153           0 :                         throw std::runtime_error("TabularPhotonField::checkInputData: redshift input must start with zero");
     154             : 
     155       14380 :                 for (int i = 0; i < this->redshifts.size(); ++i) {
     156             :                         double zPrevious = -1.;
     157       14307 :                         double z = this->redshifts[i];
     158       14307 :                         if (z < 0.)
     159           0 :                                 throw std::runtime_error("TabularPhotonField::checkInputData: a value in the redshift input is negative");
     160       14307 :                         if (z <= zPrevious)
     161           0 :                                 throw std::runtime_error("TabularPhotonField::checkInputData: redshift values are not strictly increasing");
     162             :                         zPrevious = z;
     163             :                 }
     164             : 
     165          73 :                 for (int i = 0; i < this->redshiftScalings.size(); ++i) {
     166           0 :                         double scalingFactor = this->redshiftScalings[i];
     167           0 :                         if (scalingFactor <= 0.)
     168           0 :                                 throw std::runtime_error("TabularPhotonField::checkInputData: initRedshiftScaling has created a non-positive scaling factor");
     169             :                 }
     170             :         }
     171          94 : }
     172             : 
     173          40 : BlackbodyPhotonField::BlackbodyPhotonField(std::string fieldName, double blackbodyTemperature) {
     174          40 :         this->fieldName = fieldName;
     175          40 :         this->blackbodyTemperature = blackbodyTemperature;
     176          40 :         this->quantile = 0.0001; // tested to be sufficient, only used for extreme values of primary energy or temperature
     177          40 : }
     178             : 
     179       14419 : double BlackbodyPhotonField::getPhotonDensity(double Ephoton, double z) const {
     180       14419 :         return 8 * M_PI * pow_integer<3>(Ephoton / (h_planck * c_light)) / std::expm1(Ephoton / (k_boltzmann * this->blackbodyTemperature));
     181             : }
     182             : 
     183          44 : double BlackbodyPhotonField::getMinimumPhotonEnergy(double z) const {
     184             :         double A;
     185          44 :         int quantile_int = 10000 * quantile;
     186          44 :         switch (quantile_int)
     187             :         {
     188             :         case 1: // 0.01 % percentil
     189             :                 A = 1.093586e-5 * eV / kelvin;
     190             :                 break;
     191           0 :         case 10:                // 0.1 % percentil
     192             :                 A = 2.402189e-5 * eV / kelvin;
     193           0 :                 break;
     194           0 :         case 100:               // 1 % percentil
     195             :                 A = 5.417942e-5 * eV / kelvin;
     196           0 :                 break;
     197           0 :         default:
     198           0 :                 throw std::runtime_error("Quantile not understood. Please use 0.01 (1%), 0.001 (0.1%) or 0.0001 (0.01%) \n");
     199             :                 break;
     200             :         }
     201          44 :         return A * this -> blackbodyTemperature;
     202             : }
     203             : 
     204          44 : double BlackbodyPhotonField::getMaximumPhotonEnergy(double z) const {
     205          44 :         double factor = std::max(1., blackbodyTemperature / 2.73);
     206          44 :         return 0.1 * factor * eV; // T dependent scaling, starting at 0.1 eV as suitable for CMB
     207             : }
     208             : 
     209           0 : void BlackbodyPhotonField::setQuantile(double q) {
     210           0 :         if(not ((q == 0.0001) or (q == 0.001) or (q == 0.01)))
     211           0 :                 throw std::runtime_error("Quantile not understood. Please use 0.01 (1%), 0.001 (0.1%) or 0.0001 (0.01%) \n");
     212           0 :         this -> quantile = q;
     213           0 : }
     214             : 
     215             : } // namespace crpropa

Generated by: LCOV version 1.14