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 "crpropa/Common.h"
#include "kiss/logger.h"
#include "kiss/path.h"
#include <fstream>
namespace crpropa {
TabularPhotonField::TabularPhotonField(std::string fieldName, bool isRedshiftDependent) {
this->fieldName = fieldName;
this->isRedshiftDependent = isRedshiftDependent;
this->isPositionDependent = false;
this->surface = NULL;
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 Vector3d &pos) 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 Vector3d &pos) const{
return photonEnergies[0];
}
double TabularPhotonField::getMaximumPhotonEnergy(double z, const Vector3d &pos) 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");
}
}
}
TabularSpatialPhotonField::TabularSpatialPhotonField(std::string fieldName, ref_ptr<Surface> surface) {
this->fieldName = fieldName;
this->isRedshiftDependent = isRedshiftDependent;
this->isPositionDependent = true;
this->surface = surface;
std::string dirE = getDataPath("") + "Scaling/" + this->fieldName + "/photonEnergy/";
if (!is_directory(dirE)) {
std::cout << "Photon tables not found in " << dirE << std::endl;
return;
}
std::unordered_map<int, Vector3d> photonDict;
int iFile = 0;
std::vector<std::string> dirsE;
if(!list_directory(dirE, dirsE))
throw std::runtime_error("Could not find any files in " + dirE + "!\n");
for (auto const& dir_entry : dirsE) {
std::vector<double> vE = readPhotonEnergy(concat_path(dirE, dir_entry));
this->photonEnergies = vE;
break;
}
std::string dirD = getDataPath("") + "Scaling/" + this->fieldName + "/photonDensity/";
if (!is_directory(dirD)) {
std::cout << "Photon tables not found in " << dirD << std::endl;
return;
}
std::vector<std::string> dirsD;
if(!list_directory(dirD, dirsD))
throw std::runtime_error("Could not find any files in " + dirD + "!\n");
for (auto const& dir_entry : dirsD) {
double x, y, z;
std::string str;
std::stringstream ss;
std::string filename = splitFilename(dir_entry);
ss << filename;
//Getline function to take and store the x, y, z coordinates of each node
int iLine = 0;
// it ensures the double numbers are of the type 1.00329, with the . for the decimal part
std::locale::global(std::locale("C"));
while (getline(ss, str, '_')) {
if (iLine == 2) {
x = stod(str) * kpc;
}
if (iLine == 3) {
y = stod(str) * kpc;
}
if (iLine == 4) {
z = stod(str) * kpc;
}
iLine = iLine + 1;
}
Vector3d vPos(x, y, z);
// Continue when not "inside" surface
if (getSurface() && getSurface()->distance(vPos)>=0)
continue;
photonDict[iFile] = vPos;
iFile = iFile + 1;
std::vector<double> vD = readPhotonDensity(concat_path(dirD, dir_entry));
this->photonDensity.push_back(vD);
}
if (this->photonDensity.empty())
throw std::runtime_error("Tabular spatial photon field for " + fieldName + " empty! Check if the surface is properly set.");
this->photonDict = photonDict;
checkInputData();
}
void TabularSpatialPhotonField::setSurface(ref_ptr<Surface> surface) {
this->surface = surface;
}
double TabularSpatialPhotonField::getPhotonDensity(const double ePhoton, double z, const Vector3d &pos) const {
double dMin = 1000.;
int iMin = -1;
for (const auto& el : this->photonDict) {
Vector3d posNode = el.second;
double d;
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));
if (d<dMin) {
dMin = d;
iMin = el.first;
}
}
if (iMin == -1) {
return -1.;
} else {
if ((ePhoton < photonEnergies[0]) || (ePhoton > photonEnergies[photonEnergies.size() - 1])) {
return 0;
} else {
std::vector<double> rowE = this->photonEnergies; // assuming all the nodes have the same energy binning
std::vector<double> rowD = this->photonDensity[iMin];
return interpolate(ePhoton, rowE, rowD);
}
}
}
double TabularSpatialPhotonField::getMinimumPhotonEnergy(double z, const Vector3d &pos) const {
return photonEnergies[0]; // assuming all the nodes have the same energy bins
}
double TabularSpatialPhotonField::getMaximumPhotonEnergy(double z, const Vector3d &pos) const {
return photonEnergies[photonEnergies.size() - 1]; // assuming all the nodes have the same energy bins
}
std::vector<double> TabularSpatialPhotonField::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;
std::vector<double> vE;
while (std::getline(infile, line)) {
if ((line.size() > 0) & (line[0] != '#') ) {
vE.insert(vE.begin(),std::stod(line));
}
}
infile.close();
return vE;
}
std::vector<double> TabularSpatialPhotonField::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;
std::vector<double> vD;
while (std::getline(infile, line)) {
if ((line.size() > 0) & (line[0] != '#') )
vD.insert(vD.begin(),std::stod(line));
}
infile.close();
return vD;
}
void TabularSpatialPhotonField::checkInputData() const {
std::size_t numRowsDens = this->photonEnergies.size();
std::size_t numRowsEn = this->photonDensity.size();
for (int j = 0; j < this->photonDensity.size(); ++j) { //take the proper row size!
if (this->photonEnergies.size() != this->photonDensity[j].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("TabularSpatialPhotonField::checkInputData: a value in the photon energy input is not positive");
if (e <= ePrevious)
throw std::runtime_error("TabularSpatialPhotonField::checkInputData: photon energy values are not strictly increasing");
ePrevious = e;
}
for (int i = 0; i < this->photonDensity[j].size(); ++i) {
if (this->photonDensity[j][i] < 0.)
throw std::runtime_error("TabularSpatialPhotonField::checkInputData: a value in the photon density input is negative");
}
}
}
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 Vector3d &pos) 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 Vector3d &pos) 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 Vector3d &pos) 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