LCOV - code coverage report
Current view: top level - src - EmissionMap.cpp (source / functions) Coverage Total Hit
Test: coverage.info.cleaned Lines: 53.2 % 156 83
Test Date: 2026-06-18 09:49:19 Functions: 54.5 % 33 18

            Line data    Source code
       1              : #include "crpropa/EmissionMap.h"
       2              : #include "crpropa/Random.h"
       3              : #include "crpropa/Units.h"
       4              : 
       5              : #include "kiss/logger.h"
       6              : 
       7              : #include <fstream>
       8              : 
       9              : namespace crpropa {
      10              : 
      11            0 : CylindricalProjectionMap::CylindricalProjectionMap() : nPhi(360), nTheta(180), dirty(false), pdf(nPhi* nTheta, 0), cdf(nPhi* nTheta, 0) {
      12            0 :         sPhi = 2. * M_PI / nPhi;
      13            0 :         sTheta = 2. / nTheta;
      14            0 : }
      15              : 
      16            6 : CylindricalProjectionMap::CylindricalProjectionMap(size_t nPhi, size_t nTheta) : nPhi(nPhi), nTheta(nTheta), dirty(false), pdf(nPhi* nTheta, 0), cdf(nPhi* nTheta, 0) {
      17            6 :         sPhi = 2 * M_PI / nPhi;
      18            6 :         sTheta = 2. / nTheta;
      19            6 : }
      20              : 
      21            4 : void CylindricalProjectionMap::fillBin(const Vector3d& direction, double weight) {
      22            4 :         size_t bin = binFromDirection(direction);
      23            4 :         fillBin(bin, weight);
      24            4 : }
      25              : 
      26       129604 : void CylindricalProjectionMap::fillBin(size_t bin, double weight) {
      27       129604 :         pdf[bin] += weight;
      28       129604 :         dirty = true;
      29       129604 : }
      30              : 
      31            1 : Vector3d CylindricalProjectionMap::drawDirection() const {
      32            1 :         if (dirty)
      33            1 :                 updateCdf();
      34              : 
      35            1 :         size_t bin = Random::instance().randBin(cdf);
      36              : 
      37            1 :         return directionFromBin(bin);
      38              : }
      39              : 
      40            0 : bool CylindricalProjectionMap::checkDirection(const Vector3d &direction) const {
      41            0 :         size_t bin = binFromDirection(direction);
      42            0 :         return pdf[bin];
      43              : }
      44              : 
      45              : 
      46            0 : const std::vector<double>& CylindricalProjectionMap::getPdf() const {
      47            0 :         return pdf;
      48              : }
      49              : 
      50            5 : std::vector<double>& CylindricalProjectionMap::getPdf() {
      51            5 :         return pdf;
      52              : }
      53              : 
      54            0 : const std::vector<double>& CylindricalProjectionMap::getCdf() const {
      55            0 :         return cdf;
      56              : }
      57              : 
      58            0 : size_t CylindricalProjectionMap::getNPhi() {
      59            0 :         return nPhi;
      60              : }
      61              : 
      62            0 : size_t CylindricalProjectionMap::getNTheta() {
      63            0 :         return nTheta;
      64              : }
      65              : 
      66              : /*
      67              :  * Cylindrical Coordinates
      68              :  * iPhi -> [0, 2*pi]
      69              :  * iTheta -> [0, 2]
      70              :  *
      71              :  * Spherical Coordinates
      72              :  * phi -> [-pi, pi]
      73              :  * theta -> [0, pi]
      74              :  */
      75            6 : size_t CylindricalProjectionMap::binFromDirection(const Vector3d& direction) const {
      76              :         // convert to cylindrical
      77            6 :         double phi = direction.getPhi() + M_PI;
      78            6 :         double theta = sin(M_PI_2 - direction.getTheta()) + 1;
      79              : 
      80              :         // to indices
      81            6 :         size_t iPhi = phi / sPhi;
      82            6 :         size_t iTheta = theta / sTheta;
      83              : 
      84              :         // interleave
      85            6 :         size_t bin =  iTheta * nPhi + iPhi;
      86            6 :         return bin;
      87              : }
      88              : 
      89            2 : Vector3d CylindricalProjectionMap::directionFromBin(size_t bin) const {
      90              :         // deinterleave
      91            2 :         double iPhi = bin % nPhi;
      92            2 :         double iTheta = bin / nPhi;
      93              : 
      94              :         // any where in the bin
      95            2 :         iPhi += Random::instance().rand();
      96            2 :         iTheta += Random::instance().rand();
      97              : 
      98              :         // cylindrical Coordinates
      99            2 :         double phi = iPhi * sPhi;
     100            2 :         double theta = iTheta * sTheta;
     101              : 
     102              :         // sphericala Coordinates
     103            2 :         phi = phi - M_PI;
     104            2 :         theta = M_PI_2 - asin(theta - 1);
     105              : 
     106              :         Vector3d v;
     107            2 :         v.setRThetaPhi(1.0, theta, phi);
     108            2 :         return v;
     109              : }
     110              : 
     111            1 : void CylindricalProjectionMap::updateCdf() const {
     112            1 :         if (dirty) {
     113            1 :                 cdf[0] = pdf[0];
     114        64800 :                 for (size_t i = 1; i < pdf.size(); i++) {
     115        64799 :                         cdf[i] = cdf[i-1] + pdf[i];
     116              :                 }
     117            1 :                 dirty = false;
     118              :         }
     119            1 : }
     120              : 
     121            2 : EmissionMap::EmissionMap() : minEnergy(0.0001 * EeV), maxEnergy(10000 * EeV),
     122            2 :         nEnergy(8*2), nPhi(360), nTheta(180) {
     123            2 :         logStep = log10(maxEnergy / minEnergy) / nEnergy;
     124            2 : }
     125              : 
     126            0 : EmissionMap::EmissionMap(size_t nPhi, size_t nTheta, size_t nEnergy) : minEnergy(0.0001 * EeV), maxEnergy(10000 * EeV),
     127            0 :         nEnergy(nEnergy), nPhi(nPhi), nTheta(nTheta) {
     128            0 :         logStep = log10(maxEnergy / minEnergy) / nEnergy;
     129            0 : }
     130              : 
     131            1 : EmissionMap::EmissionMap(size_t nPhi, size_t nTheta, size_t nEnergy, double minEnergy, double maxEnergy) : minEnergy(minEnergy), maxEnergy(maxEnergy), nEnergy(nEnergy), nPhi(nPhi), nTheta(nTheta) {
     132            1 :         logStep = log10(maxEnergy / minEnergy) / nEnergy;
     133            1 : }
     134              : 
     135            1 : double EmissionMap::energyFromBin(size_t bin) const {
     136            1 :         return pow(10, log10(minEnergy) + logStep * bin);
     137              : }
     138              : 
     139           11 : size_t EmissionMap::binFromEnergy(double energy) const {
     140           11 :         return log10(energy / minEnergy) / logStep;
     141              : }
     142              : 
     143            4 : void EmissionMap::fillMap(int pid, double energy, const Vector3d& direction, double weight) {
     144            4 :         getMap(pid, energy)->fillBin(direction, weight);
     145            4 : }
     146              : 
     147            0 : void EmissionMap::fillMap(const ParticleState& state, double weight) {
     148            0 :         fillMap(state.getId(), state.getEnergy(), state.getDirection(), weight);
     149            0 : }
     150              : 
     151            1 : EmissionMap::map_t &EmissionMap::getMaps() {
     152            1 :         return maps;
     153              : }
     154              : 
     155            2 : const EmissionMap::map_t &EmissionMap::getMaps() const {
     156            2 :         return maps;
     157              : }
     158              : 
     159            3 : bool EmissionMap::drawDirection(int pid, double energy, Vector3d& direction) const {
     160            3 :         key_t key(pid, binFromEnergy(energy));
     161              :         map_t::const_iterator i = maps.find(key);
     162              : 
     163            3 :         if (i == maps.end() || !i->second.valid()) {
     164              :                 return false;
     165              :         } else {
     166            1 :                 direction = i->second->drawDirection();
     167            1 :                 return true;
     168              :         }
     169              : }
     170              : 
     171            0 : bool EmissionMap::drawDirection(const ParticleState& state, Vector3d& direction) const {
     172            0 :         return drawDirection(state.getId(), state.getEnergy(), direction);
     173              : }
     174              : 
     175            0 : bool EmissionMap::checkDirection(int pid, double energy, const Vector3d& direction) const {
     176            0 :         key_t key(pid, binFromEnergy(energy));
     177              :         map_t::const_iterator i = maps.find(key);
     178              : 
     179            0 :         if (i == maps.end() || !i->second.valid()) {
     180              :                 return false;
     181              :         } else {
     182            0 :                 return i->second->checkDirection(direction);
     183              :         }
     184              : }
     185              : 
     186            0 : bool EmissionMap::checkDirection(const ParticleState& state) const {
     187            0 :         return checkDirection(state.getId(), state.getEnergy(), state.getDirection());
     188              : }
     189              : 
     190            0 : bool EmissionMap::hasMap(int pid, double energy) {
     191            0 :     key_t key(pid, binFromEnergy(energy));
     192              :     map_t::iterator i = maps.find(key);
     193            0 :     if (i == maps.end() || !i->second.valid())
     194              :                 return false;
     195              :         else
     196            0 :                 return true;
     197              : }
     198              : 
     199            7 : ref_ptr<CylindricalProjectionMap> EmissionMap::getMap(int pid, double energy) {
     200            7 :         key_t key(pid, binFromEnergy(energy));
     201              :         map_t::iterator i = maps.find(key);
     202            7 :         if (i == maps.end() || !i->second.valid()) {
     203            5 :                 ref_ptr<CylindricalProjectionMap> cpm = new CylindricalProjectionMap(nPhi, nTheta);
     204            5 :                 maps[key] = cpm;
     205              :                 return cpm;
     206              :         } else {
     207              :                 return i->second;
     208              :         }
     209              : }
     210              : 
     211            0 : void EmissionMap::save(const std::string &filename) {
     212            0 :         std::ofstream out(filename.c_str());
     213            0 :         out.imbue(std::locale("C"));
     214              : 
     215            0 :         for (map_t::iterator i = maps.begin(); i != maps.end(); i++) {
     216            0 :                 if (!i->second.valid())
     217            0 :                         continue;
     218            0 :                 out << i->first.first << " " << i->first.second << " " << energyFromBin(i->first.second) << " ";
     219            0 :                 out << i->second->getNPhi() << " " << i->second->getNTheta();
     220            0 :                 const std::vector<double> &pdf = i->second->getPdf();
     221            0 :                 for (size_t i = 0; i < pdf.size(); i++)
     222            0 :                         out << " " << pdf[i];
     223              :                 out << std::endl;
     224              :         }
     225            0 : }
     226              : 
     227            1 : void EmissionMap::merge(const EmissionMap *other) {
     228            1 :         if (other == 0)
     229              :                 return;
     230            1 :         map_t::const_iterator i = other->getMaps().begin();
     231            1 :         map_t::const_iterator end = other->getMaps().end();
     232            3 :         for(;i != end; i++) {
     233            2 :                 if (!i->second.valid())
     234            0 :                         continue;
     235              : 
     236            2 :                 std::vector<double> &otherpdf = i->second->getPdf();
     237            2 :                 ref_ptr<CylindricalProjectionMap> cpm = getMap(i->first.first, i->first.second);
     238              : 
     239            2 :                 if (otherpdf.size() != cpm->getPdf().size()) {
     240            0 :                         throw std::runtime_error("PDF size mismatch!");
     241              :                         break;
     242              :                 }
     243              : 
     244       129602 :                 for (size_t k = 0; k < otherpdf.size(); k++) {
     245       129600 :                         cpm->fillBin(k, otherpdf[k]);
     246              :                 }
     247              :         }
     248              : }
     249              : 
     250            0 : void EmissionMap::merge(const std::string &filename) {
     251            0 :         EmissionMap em;
     252            0 :         em.load(filename);
     253            0 :         merge(&em);
     254            0 : }
     255              : 
     256            0 : void EmissionMap::load(const std::string &filename) {
     257            0 :         std::ifstream in(filename.c_str());
     258            0 :         in.imbue(std::locale("C"));
     259              : 
     260            0 :         while(in.good()) {
     261            0 :                 key_t key;
     262              :                 double tmp;
     263              :                 size_t nPhi_, nTheta_;
     264            0 :                 in >> key.first >> key.second >> tmp;
     265              :                 in >> nPhi_ >> nTheta_;
     266              : 
     267            0 :                 if (!in.good()) {
     268            0 :                         KISS_LOG_ERROR << "Invalid line: " << key.first << " " << key.second << " " << nPhi_ << " " << nTheta_;
     269            0 :                         break;
     270              :                 }
     271              : 
     272            0 :                 if (nPhi != nPhi_) {
     273            0 :                         KISS_LOG_WARNING << "nPhi mismatch: " << nPhi << " " << nPhi_;
     274              :                 }
     275            0 :                 if (nTheta != nTheta_) {
     276            0 :                         KISS_LOG_WARNING << "nTheta mismatch: " << nTheta << " " << nTheta_;
     277              :                 }
     278              : 
     279            0 :                 ref_ptr<CylindricalProjectionMap> cpm = new CylindricalProjectionMap(nPhi_, nTheta_);
     280            0 :                 std::vector<double> &pdf = cpm->getPdf();
     281            0 :                 for (size_t i = 0; i < pdf.size(); i++)
     282              :                         in >> pdf[i];
     283              : 
     284            0 :                 if (in.good()) {
     285            0 :                         maps[key] = cpm;
     286              :                         // std::cout << "added " << key.first << " " << key.second << std::endl;
     287              :                 } else {
     288            0 :                         KISS_LOG_WARNING << "Invalid data in line: " << key.first << " " << key.second << " " << nPhi_ << " " << nTheta_ << "\n";
     289              :                 }
     290              :         }
     291              : 
     292            0 : }
     293              : 
     294              : } // namespace crpropa
        

Generated by: LCOV version 2.0-1