Program Listing for File PhotonBackground.cpp
↰ Return to documentation for file (src/PhotonBackground.cpp
)
#include "crpropa/PhotonBackground.h"
#include "crpropa/Units.h"
#include "crpropa/Random.h"
#include "kiss/logger.h"
#include <fstream>
#include <stdexcept>
#include <limits>
#include <cmath>
namespace crpropa {
TabularPhotonField::TabularPhotonField(std::string fieldName, bool isRedshiftDependent) {
this->fieldName = fieldName;
this->isRedshiftDependent = isRedshiftDependent;
readPhotonEnergy(getDataPath("") + "Scaling/" + this->fieldName + "_photonEnergy.txt");
readPhotonDensity(getDataPath("") + "Scaling/" + this->fieldName + "_photonDensity.txt");
if (this->isRedshiftDependent)
readRedshift(getDataPath("") + "Scaling/" + this->fieldName + "_redshift.txt");
checkInputData();
if (this->isRedshiftDependent)
initRedshiftScaling();
}
double TabularPhotonField::getPhotonDensity(double Ephoton, double z) const {
if ((this->isRedshiftDependent)) {
// fix behaviour for future redshift. See issue #414
// with redshift < 0 the photon density is set to 0 in interpolate2d.
// 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.
double zMin = this->redshifts[0];
if(z < zMin){
if(z < -1) {
KISS_LOG_WARNING << "Photon Field " << fieldName << " uses FutureRedshift with z < -1. The photon density is set to n(Ephoton, z=0). \n";
}
return getPhotonDensity(Ephoton, zMin);
} else {
return interpolate2d(Ephoton, z, this->photonEnergies, this->redshifts, this->photonDensity);
}
} else {
return interpolate(Ephoton, this->photonEnergies, this->photonDensity);
}
}
double TabularPhotonField::getRedshiftScaling(double z) const {
if (!this->isRedshiftDependent)
return 1.;
if (z < this->redshifts.front())
return 1.;
if (z > this->redshifts.back())
return 0.;
return interpolate(z, this->redshifts, this->redshiftScalings);
}
double TabularPhotonField::getMinimumPhotonEnergy(double z) const{
return photonEnergies[0];
}
double TabularPhotonField::getMaximumPhotonEnergy(double z) const{
return photonEnergies[photonEnergies.size() -1];
}
void TabularPhotonField::readPhotonEnergy(std::string filePath) {
std::ifstream infile(filePath.c_str());
if (!infile.good())
throw std::runtime_error("TabularPhotonField::readPhotonEnergy: could not open " + filePath);
std::string line;
while (std::getline(infile, line)) {
if ((line.size() > 0) & (line[0] != '#') )
this->photonEnergies.push_back(std::stod(line));
}
infile.close();
}
void TabularPhotonField::readPhotonDensity(std::string filePath) {
std::ifstream infile(filePath.c_str());
if (!infile.good())
throw std::runtime_error("TabularPhotonField::readPhotonDensity: could not open " + filePath);
std::string line;
while (std::getline(infile, line)) {
if ((line.size() > 0) & (line[0] != '#') )
this->photonDensity.push_back(std::stod(line));
}
infile.close();
}
void TabularPhotonField::readRedshift(std::string filePath) {
std::ifstream infile(filePath.c_str());
if (!infile.good())
throw std::runtime_error("TabularPhotonField::initRedshift: could not open " + filePath);
std::string line;
while (std::getline(infile, line)) {
if ((line.size() > 0) & (line[0] != '#') )
this->redshifts.push_back(std::stod(line));
}
infile.close();
}
void TabularPhotonField::initRedshiftScaling() {
double n0 = 0.;
for (int i = 0; i < this->redshifts.size(); ++i) {
double z = this->redshifts[i];
double n = 0.;
for (int j = 0; j < this->photonEnergies.size()-1; ++j) {
double e_j = this->photonEnergies[j];
double e_j1 = this->photonEnergies[j+1];
double deltaLogE = std::log10(e_j1) - std::log10(e_j);
if (z == 0.)
n0 += (getPhotonDensity(e_j, 0) + getPhotonDensity(e_j1, 0)) / 2. * deltaLogE;
n += (getPhotonDensity(e_j, z) + getPhotonDensity(e_j1, z)) / 2. * deltaLogE;
}
this->redshiftScalings.push_back(n / n0);
}
}
void TabularPhotonField::checkInputData() const {
if (this->isRedshiftDependent) {
if (this->photonDensity.size() != this->photonEnergies.size() * this-> redshifts.size())
throw std::runtime_error("TabularPhotonField::checkInputData: length of photon density input is unequal to length of photon energy input times length of redshift input");
} else {
if (this->photonEnergies.size() != this->photonDensity.size())
throw std::runtime_error("TabularPhotonField::checkInputData: length of photon energy input is unequal to length of photon density input");
}
for (int i = 0; i < this->photonEnergies.size(); ++i) {
double ePrevious = 0.;
double e = this->photonEnergies[i];
if (e <= 0.)
throw std::runtime_error("TabularPhotonField::checkInputData: a value in the photon energy input is not positive");
if (e <= ePrevious)
throw std::runtime_error("TabularPhotonField::checkInputData: photon energy values are not strictly increasing");
ePrevious = e;
}
for (int i = 0; i < this->photonDensity.size(); ++i) {
if (this->photonDensity[i] < 0.)
throw std::runtime_error("TabularPhotonField::checkInputData: a value in the photon density input is negative");
}
if (this->isRedshiftDependent) {
if (this->redshifts[0] != 0.)
throw std::runtime_error("TabularPhotonField::checkInputData: redshift input must start with zero");
for (int i = 0; i < this->redshifts.size(); ++i) {
double zPrevious = -1.;
double z = this->redshifts[i];
if (z < 0.)
throw std::runtime_error("TabularPhotonField::checkInputData: a value in the redshift input is negative");
if (z <= zPrevious)
throw std::runtime_error("TabularPhotonField::checkInputData: redshift values are not strictly increasing");
zPrevious = z;
}
for (int i = 0; i < this->redshiftScalings.size(); ++i) {
double scalingFactor = this->redshiftScalings[i];
if (scalingFactor <= 0.)
throw std::runtime_error("TabularPhotonField::checkInputData: initRedshiftScaling has created a non-positive scaling factor");
}
}
}
BlackbodyPhotonField::BlackbodyPhotonField(std::string fieldName, double blackbodyTemperature) {
this->fieldName = fieldName;
this->blackbodyTemperature = blackbodyTemperature;
this->quantile = 0.0001; // tested to be sufficient, only used for extreme values of primary energy or temperature
}
double BlackbodyPhotonField::getPhotonDensity(double Ephoton, double z) const {
return 8 * M_PI * pow_integer<3>(Ephoton / (h_planck * c_light)) / std::expm1(Ephoton / (k_boltzmann * this->blackbodyTemperature));
}
double BlackbodyPhotonField::getMinimumPhotonEnergy(double z) const {
double A;
int quantile_int = 10000 * quantile;
switch (quantile_int)
{
case 1: // 0.01 % percentil
A = 1.093586e-5 * eV / kelvin;
break;
case 10: // 0.1 % percentil
A = 2.402189e-5 * eV / kelvin;
break;
case 100: // 1 % percentil
A = 5.417942e-5 * eV / kelvin;
break;
default:
throw std::runtime_error("Quantile not understood. Please use 0.01 (1%), 0.001 (0.1%) or 0.0001 (0.01%) \n");
break;
}
return A * this -> blackbodyTemperature;
}
double BlackbodyPhotonField::getMaximumPhotonEnergy(double z) const {
double factor = std::max(1., blackbodyTemperature / 2.73);
return 0.1 * factor * eV; // T dependent scaling, starting at 0.1 eV as suitable for CMB
}
void BlackbodyPhotonField::setQuantile(double q) {
if(not ((q == 0.0001) or (q == 0.001) or (q == 0.01)))
throw std::runtime_error("Quantile not understood. Please use 0.01 (1%), 0.001 (0.1%) or 0.0001 (0.01%) \n");
this -> quantile = q;
}
} // namespace crpropa