LCOV - code coverage report
Current view: top level - src - PhotonBackground.cpp (source / functions) Coverage Total Hit
Test: coverage.info.cleaned Lines: 42.3 % 208 88
Test Date: 2026-07-13 06:03:10 Functions: 52.2 % 23 12

            Line data    Source code
       1              : #include "crpropa/PhotonBackground.h"
       2              : #include "crpropa/Units.h"
       3              : #include "crpropa/Random.h"
       4              : #include "crpropa/Common.h"
       5              : 
       6              : #include "kiss/logger.h"
       7              : #include "kiss/path.h"
       8              : 
       9              : #include <fstream>
      10              : 
      11              : namespace crpropa {
      12              : 
      13           95 : TabularPhotonField::TabularPhotonField(std::string fieldName, bool isRedshiftDependent) {
      14           95 :         this->fieldName = fieldName;
      15           95 :         this->isRedshiftDependent = isRedshiftDependent;
      16           95 :         this->isPositionDependent = false;
      17              :         this->surface = NULL;
      18              :         
      19          285 :         readPhotonEnergy(getDataPath("") + "Scaling/" + this->fieldName + "_photonEnergy.txt");
      20          285 :         readPhotonDensity(getDataPath("") + "Scaling/" + this->fieldName + "_photonDensity.txt");
      21              :         
      22           95 :         if (this->isRedshiftDependent)
      23          296 :                 readRedshift(getDataPath("") + "Scaling/" + this->fieldName + "_redshift.txt");
      24              :         
      25           95 :         checkInputData();
      26              :         
      27           95 :         if (this->isRedshiftDependent)
      28           74 :                 initRedshiftScaling();
      29           95 : }
      30              : 
      31              : 
      32      9541130 : double TabularPhotonField::getPhotonDensity(double Ephoton, double z, const Vector3d &pos) const {
      33      9541130 :         if (this->isRedshiftDependent) {
      34              :                 // fix behaviour for future redshift. See issue #414
      35              :                 // with redshift < 0 the photon density is set to 0 in interpolate2d.
      36              :                 // 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.
      37      9541130 :                 double zMin = this->redshifts[0];
      38              :                 
      39      9541130 :                 if(z < zMin){
      40            0 :                         if(z < -1) {
      41            0 :                                 KISS_LOG_WARNING << "Photon Field " << fieldName << " uses FutureRedshift with z < -1. The photon density is set to n(Ephoton, z=0). \n";
      42              :                         }
      43            0 :                         return getPhotonDensity(Ephoton, zMin);
      44              :                 } else {
      45      9541130 :                         return interpolate2d(Ephoton, z, this->photonEnergies, this->redshifts, this->photonDensity);
      46              :                 }
      47              :         } else {
      48            0 :                 return interpolate(Ephoton, this->photonEnergies, this->photonDensity);
      49              :         }
      50              : }
      51              : 
      52         3988 : double TabularPhotonField::getRedshiftScaling(double z) const {
      53         3988 :         if (!this->isRedshiftDependent)
      54              :                 return 1.;
      55         3708 :         if (z < this->redshifts.front())
      56              :                 return 1.;
      57         3708 :         if (z > this->redshifts.back())
      58              :                 return 0.;
      59         3708 :         return interpolate(z, this->redshifts, this->redshiftScalings);
      60              : }
      61              : 
      62            0 : double TabularPhotonField::getMinimumPhotonEnergy(double z, const Vector3d &pos) const{
      63            0 :         return photonEnergies[0];
      64              : }
      65              : 
      66            0 : double TabularPhotonField::getMaximumPhotonEnergy(double z, const Vector3d &pos) const{
      67            0 :         return photonEnergies[photonEnergies.size() -1];
      68              : }
      69              : 
      70           95 : void TabularPhotonField::readPhotonEnergy(std::string filePath) {
      71           95 :         std::ifstream infile(filePath.c_str());
      72              :         
      73           95 :         if (!infile.good())
      74            0 :                 throw std::runtime_error("TabularPhotonField::readPhotonEnergy: could not open " + filePath);
      75              :         
      76              :         std::string line;
      77        15425 :         while (std::getline(infile, line)) {
      78        15330 :                 if ((line.size() > 0) & (line[0] != '#') )
      79        15045 :                         this->photonEnergies.push_back(std::stod(line));
      80              :         }
      81           95 :         infile.close();
      82           95 : }
      83              : 
      84           95 : void TabularPhotonField::readPhotonDensity(std::string filePath) {
      85           95 :         std::ifstream infile(filePath.c_str());
      86              :         
      87           95 :         if (!infile.good())
      88            0 :                 throw std::runtime_error("TabularPhotonField::readPhotonDensity: could not open " + filePath);
      89              : 
      90              :         std::string line;
      91      4774543 :         while (std::getline(infile, line)) {
      92      4774448 :                 if ((line.size() > 0) & (line[0] != '#') )
      93      4774163 :                         this->photonDensity.push_back(std::stod(line));
      94              :         }
      95           95 :         infile.close();
      96           95 : }
      97              : 
      98           74 : void TabularPhotonField::readRedshift(std::string filePath) {
      99           74 :         std::ifstream infile(filePath.c_str());
     100              :         
     101           74 :         if (!infile.good())
     102            0 :                 throw std::runtime_error("TabularPhotonField::initRedshift: could not open " + filePath);
     103              :         
     104              :         std::string line;
     105        14623 :         while (std::getline(infile, line)) {
     106        14549 :                 if ((line.size() > 0) & (line[0] != '#') )
     107        14327 :                         this->redshifts.push_back(std::stod(line));
     108              :         }
     109           74 :         infile.close();
     110           74 : }
     111              : 
     112           74 : void TabularPhotonField::initRedshiftScaling() {
     113              :         double n0 = 0.;
     114              :         
     115        14401 :         for (int i = 0; i < this->redshifts.size(); ++i) {
     116              :                 
     117        14327 :                 double z = this->redshifts[i];
     118              :                 double n = 0.;
     119              :                 
     120      4772042 :                 for (int j = 0; j < this->photonEnergies.size()-1; ++j) {
     121      4757715 :                         double e_j = this->photonEnergies[j];
     122      4757715 :                         double e_j1 = this->photonEnergies[j+1];
     123      4757715 :                         double deltaLogE = std::log10(e_j1) - std::log10(e_j);
     124      4757715 :                         if (z == 0.)
     125        12850 :                                 n0 += (getPhotonDensity(e_j, 0) + getPhotonDensity(e_j1, 0)) / 2. * deltaLogE;
     126      4757715 :                         n += (getPhotonDensity(e_j, z) + getPhotonDensity(e_j1, z)) / 2. * deltaLogE;
     127              :                 }
     128        14327 :                 this->redshiftScalings.push_back(n / n0);
     129              :         }
     130           74 : }
     131              : 
     132           95 : void TabularPhotonField::checkInputData() const {
     133           95 :         if (this->isRedshiftDependent) {
     134              :                 
     135           74 :         if (this->photonDensity.size() != this->photonEnergies.size() * this-> redshifts.size())
     136            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");
     137              :         } else {
     138           21 :                 if (this->photonEnergies.size() != this->photonDensity.size())
     139            0 :                         throw std::runtime_error("TabularPhotonField::checkInputData: length of photon energy input is unequal to length of photon density input");
     140              :         }
     141              : 
     142        15140 :         for (int i = 0; i < this->photonEnergies.size(); ++i) {
     143              :                 double ePrevious = 0.;
     144        15045 :                 double e = this->photonEnergies[i];
     145              :                 
     146        15045 :                 if (e <= 0.)
     147            0 :                         throw std::runtime_error("TabularPhotonField::checkInputData: a value in the photon energy input is not positive");
     148              :                 if (e <= ePrevious)
     149              :                         throw std::runtime_error("TabularPhotonField::checkInputData: photon energy values are not strictly increasing");
     150              :                 ePrevious = e;
     151              :         }
     152              : 
     153      4774258 :         for (int i = 0; i < this->photonDensity.size(); ++i) {
     154      4774163 :                 if (this->photonDensity[i] < 0.)
     155            0 :                         throw std::runtime_error("TabularPhotonField::checkInputData: a value in the photon density input is negative");
     156              :         }
     157              : 
     158           95 :         if (this->isRedshiftDependent) {
     159              :                 
     160           74 :                 if (this->redshifts[0] != 0.)
     161            0 :                         throw std::runtime_error("TabularPhotonField::checkInputData: redshift input must start with zero");
     162              : 
     163        14401 :                 for (int i = 0; i < this->redshifts.size(); ++i) {
     164              :                         double zPrevious = -1.;
     165        14327 :                         double z = this->redshifts[i];
     166              :                         
     167        14327 :                         if (z < 0.)
     168            0 :                                 throw std::runtime_error("TabularPhotonField::checkInputData: a value in the redshift input is negative");
     169              :                         if (z <= zPrevious)
     170              :                                 throw std::runtime_error("TabularPhotonField::checkInputData: redshift values are not strictly increasing");
     171              :                         zPrevious = z;
     172              :                 }
     173              : 
     174           74 :                 for (int i = 0; i < this->redshiftScalings.size(); ++i) {
     175            0 :                         double scalingFactor = this->redshiftScalings[i];
     176            0 :                         if (scalingFactor <= 0.)
     177            0 :                                 throw std::runtime_error("TabularPhotonField::checkInputData: initRedshiftScaling has created a non-positive scaling factor");
     178              :                 }
     179              :         }
     180           95 : }
     181              : 
     182            0 : TabularSpatialPhotonField::TabularSpatialPhotonField(std::string fieldName, ref_ptr<Surface> surface) {
     183              :         
     184            0 :         this->fieldName = fieldName;
     185            0 :         this->isRedshiftDependent = isRedshiftDependent;
     186            0 :         this->isPositionDependent = true;
     187            0 :         this->surface = surface;
     188              :         
     189            0 :         std::string dirE = getDataPath("") + "Scaling/" + this->fieldName + "/photonEnergy/";
     190            0 :         if (!is_directory(dirE)) {
     191              :                 std::cout << "Photon tables not found in " << dirE << std::endl;
     192              :                 return;
     193              :         }
     194              :         
     195              :         std::unordered_map<int, Vector3d> photonDict;
     196            0 :         int iFile = 0;
     197              : 
     198              :         std::vector<std::string> dirsE;
     199            0 :         if(!list_directory(dirE, dirsE))
     200            0 :                 throw std::runtime_error("Could not find any files in " + dirE + "!\n");
     201              :         
     202            0 :         for (auto const& dir_entry : dirsE) {
     203            0 :                 std::vector<double> vE = readPhotonEnergy(concat_path(dirE, dir_entry));
     204              :                 
     205            0 :                 this->photonEnergies = vE;
     206              :                 break;
     207            0 :         }
     208              :         
     209            0 :         std::string dirD = getDataPath("") + "Scaling/" + this->fieldName + "/photonDensity/";
     210            0 :         if (!is_directory(dirD)) {
     211              :                 std::cout << "Photon tables not found in " << dirD << std::endl;
     212              :                 return;
     213              :         }
     214              : 
     215              :         std::vector<std::string> dirsD;
     216            0 :         if(!list_directory(dirD, dirsD))
     217            0 :                 throw std::runtime_error("Could not find any files in " + dirD + "!\n");
     218              :         
     219            0 :         for (auto const& dir_entry : dirsD) {
     220              :                 double x, y, z;
     221              :                 std::string str;
     222            0 :                 std::stringstream ss;
     223              :                 
     224            0 :                 std::string filename = splitFilename(dir_entry);
     225              :                 ss << filename;
     226              :                 
     227              :                 //Getline function to take and store the x, y, z coordinates of each node
     228              :                 int iLine = 0;
     229              :                 // it ensures the double numbers are of the type 1.00329, with the . for the decimal part
     230            0 :                 std::locale::global(std::locale("C"));
     231              :                 
     232            0 :                 while (getline(ss, str, '_')) {
     233            0 :                         if (iLine == 2) {
     234            0 :                                 x = stod(str) * kpc;
     235              :                         }
     236            0 :                         if (iLine == 3) {
     237            0 :                                 y = stod(str) * kpc;
     238              :                         }
     239            0 :                         if (iLine == 4) {
     240            0 :                                 z = stod(str) * kpc;
     241              :                         }
     242            0 :                         iLine = iLine + 1;
     243              :                 }
     244              :                 
     245              :                 Vector3d vPos(x, y, z);
     246              :                 
     247              :                 // Continue when not "inside" surface
     248            0 :                 if (getSurface() && getSurface()->distance(vPos)>=0)
     249              :                         continue;
     250              :                 
     251              :                 photonDict[iFile] = vPos;
     252            0 :                 iFile = iFile + 1;
     253              :                 
     254            0 :                 std::vector<double> vD = readPhotonDensity(concat_path(dirD, dir_entry));
     255            0 :                 this->photonDensity.push_back(vD);
     256            0 :         }
     257              :         
     258            0 :         if (this->photonDensity.empty())
     259            0 :                 throw std::runtime_error("Tabular spatial photon field for " + fieldName + " empty! Check if the surface is properly set.");
     260              :         
     261              :         this->photonDict = photonDict;
     262            0 :         checkInputData();
     263            0 : }
     264              : 
     265            0 : void TabularSpatialPhotonField::setSurface(ref_ptr<Surface> surface) {
     266            0 :                 this->surface = surface;
     267            0 : }
     268              : 
     269            0 : double TabularSpatialPhotonField::getPhotonDensity(const double ePhoton, double z, const Vector3d &pos) const {
     270              :         double dMin = 1000.;
     271              :         int iMin = -1;
     272              :         
     273            0 :         for (const auto& el : this->photonDict) {
     274              :                 Vector3d posNode = el.second;
     275              :                 double d;
     276            0 :                 d = sqrt((- posNode.x / kpc  - pos.x / kpc) * (- posNode.x / kpc - pos.x / kpc) + (posNode.y / kpc - pos.y / kpc) * (posNode.y / kpc - pos.y / kpc ) + (posNode.z / kpc - pos.z / kpc) * (posNode.z / kpc - pos.z / kpc));
     277              :                 
     278            0 :                 if (d<dMin) {
     279              :                         dMin = d;
     280            0 :                         iMin = el.first;
     281              :                 }
     282              :         }
     283              :         
     284            0 :         if (iMin == -1) {
     285              :                 return -1.;
     286              :         } else {
     287            0 :                 if ((ePhoton < photonEnergies[0]) || (ePhoton > photonEnergies[photonEnergies.size() - 1])) {
     288              :                         return 0;
     289              :                 } else {
     290            0 :                         std::vector<double> rowE = this->photonEnergies; // assuming all the nodes have the same energy binning
     291            0 :                         std::vector<double> rowD = this->photonDensity[iMin];
     292            0 :                         return interpolate(ePhoton, rowE, rowD);
     293            0 :                 }
     294              :         }
     295              : }
     296              : 
     297            0 : double TabularSpatialPhotonField::getMinimumPhotonEnergy(double z, const Vector3d &pos) const {
     298            0 :         return photonEnergies[0]; // assuming all the nodes have the same energy bins
     299              : }
     300              : 
     301            0 : double TabularSpatialPhotonField::getMaximumPhotonEnergy(double z, const Vector3d &pos) const {
     302            0 :         return photonEnergies[photonEnergies.size() - 1]; // assuming all the nodes have the same energy bins
     303              : }
     304              : 
     305            0 : std::vector<double> TabularSpatialPhotonField::readPhotonEnergy(std::string filePath) {
     306            0 :         std::ifstream infile(filePath.c_str());
     307              :         
     308            0 :         if (!infile.good())
     309            0 :                 throw std::runtime_error("TabularPhotonField::readPhotonEnergy: could not open " + filePath);
     310              :         
     311              :         std::string line;
     312              :         std::vector<double> vE;
     313              :         
     314            0 :         while (std::getline(infile, line)) {
     315            0 :                 if ((line.size() > 0) & (line[0] != '#') ) {
     316            0 :                         vE.insert(vE.begin(),std::stod(line));
     317              :                 }
     318              :         }
     319              :         
     320            0 :         infile.close();
     321            0 :         return vE;
     322            0 : }
     323              :  
     324            0 : std::vector<double> TabularSpatialPhotonField::readPhotonDensity(std::string filePath) {
     325            0 :         std::ifstream infile(filePath.c_str());
     326              : 
     327            0 :         if (!infile.good())
     328            0 :                 throw std::runtime_error("TabularPhotonField::readPhotonDensity: could not open " + filePath);
     329              :         
     330              :         std::string line;
     331              :         std::vector<double> vD;
     332              :         
     333            0 :         while (std::getline(infile, line)) {
     334            0 :                 if ((line.size() > 0) & (line[0] != '#') )
     335            0 :                         vD.insert(vD.begin(),std::stod(line));
     336              :         }
     337              :         
     338            0 :         infile.close();
     339            0 :         return vD;
     340            0 : }
     341              : 
     342            0 : void TabularSpatialPhotonField::checkInputData() const {
     343              :         
     344              :         std::size_t numRowsDens = this->photonEnergies.size();
     345              :         std::size_t numRowsEn = this->photonDensity.size();
     346              :         
     347            0 :         for (int j = 0; j < this->photonDensity.size(); ++j) { //take the proper row size!
     348              : 
     349            0 :                 if (this->photonEnergies.size() != this->photonDensity[j].size())
     350            0 :                         throw std::runtime_error("TabularPhotonField::checkInputData: length of photon energy input is unequal to length of photon density input");
     351              :                 
     352            0 :                 for (int i = 0; i < this->photonEnergies.size(); ++i) {
     353              :                         double ePrevious = 0.;
     354            0 :                         double e = this->photonEnergies[i];
     355              :                         
     356            0 :                         if (e <= 0.)
     357            0 :                                 throw std::runtime_error("TabularSpatialPhotonField::checkInputData: a value in the photon energy input is not positive");
     358              :                         if (e <= ePrevious)
     359              :                                 throw std::runtime_error("TabularSpatialPhotonField::checkInputData: photon energy values are not strictly increasing");
     360              :                         ePrevious = e;
     361              :                 }
     362              :                 
     363            0 :                 for (int i = 0; i < this->photonDensity[j].size(); ++i) {
     364              :         
     365            0 :                         if (this->photonDensity[j][i] < 0.)
     366            0 :                                 throw std::runtime_error("TabularSpatialPhotonField::checkInputData: a value in the photon density input is negative");
     367              :                 }
     368              :         }
     369            0 : }
     370              : 
     371           47 : BlackbodyPhotonField::BlackbodyPhotonField(std::string fieldName, double blackbodyTemperature) {
     372           47 :                 this->fieldName = fieldName;
     373           47 :                 this->blackbodyTemperature = blackbodyTemperature;
     374           47 :                 this->quantile = 0.0001; // tested to be sufficient, only used for extreme values of primary energy or temperature
     375           47 : }
     376              : 
     377         9626 : double BlackbodyPhotonField::getPhotonDensity(double Ephoton, double z, const Vector3d &pos) const {
     378         9626 :         return 8 * M_PI * pow_integer<3>(Ephoton / (h_planck * c_light)) / std::expm1(Ephoton / (k_boltzmann * this->blackbodyTemperature));
     379              : }
     380              : 
     381           26 : double BlackbodyPhotonField::getMinimumPhotonEnergy(double z, const Vector3d &pos) const {
     382              :         double A;
     383           26 :         int quantile_int = 10000 * quantile;
     384           26 :         switch (quantile_int)
     385              :         {
     386              :         case 1: // 0.01 % percentil
     387              :                 A = 1.093586e-5 * eV / kelvin;
     388              :                 break;
     389            0 :         case 10:                // 0.1 % percentil
     390              :                 A = 2.402189e-5 * eV / kelvin;
     391            0 :                 break;
     392            0 :         case 100:               // 1 % percentil
     393              :                 A = 5.417942e-5 * eV / kelvin;
     394            0 :                 break;
     395            0 :         default:
     396            0 :                 throw std::runtime_error("Quantile not understood. Please use 0.01 (1%), 0.001 (0.1%) or 0.0001 (0.01%) \n");
     397              :                 break;
     398              :         }
     399           26 :         return A * this -> blackbodyTemperature;
     400              : }
     401              : 
     402           51 : double BlackbodyPhotonField::getMaximumPhotonEnergy(double z, const Vector3d &pos) const {
     403           51 :         double factor = std::max(1., blackbodyTemperature / 2.73);
     404           51 :         return 0.1 * factor * eV; // T dependent scaling, starting at 0.1 eV as suitable for CMB
     405              : }
     406              : 
     407            0 : void BlackbodyPhotonField::setQuantile(double q) {
     408            0 :         if(not ((q == 0.0001) or (q == 0.001) or (q == 0.01)))
     409            0 :                 throw std::runtime_error("Quantile not understood. Please use 0.01 (1%), 0.001 (0.1%) or 0.0001 (0.01%) \n");
     410            0 :         this -> quantile = q;
     411            0 : }
     412              : 
     413              : } // namespace crpropa
        

Generated by: LCOV version 2.0-1