Program Listing for File EmissionMap.cpp

Return to documentation for file (src/EmissionMap.cpp)

#include "crpropa/EmissionMap.h"
#include "crpropa/Random.h"
#include "crpropa/Units.h"

#include "kiss/logger.h"

#include <fstream>

namespace crpropa {

CylindricalProjectionMap::CylindricalProjectionMap() : nPhi(360), nTheta(180), dirty(false), pdf(nPhi* nTheta, 0), cdf(nPhi* nTheta, 0) {
        sPhi = 2. * M_PI / nPhi;
        sTheta = 2. / nTheta;
}

CylindricalProjectionMap::CylindricalProjectionMap(size_t nPhi, size_t nTheta) : nPhi(nPhi), nTheta(nTheta), dirty(false), pdf(nPhi* nTheta, 0), cdf(nPhi* nTheta, 0) {
        sPhi = 2 * M_PI / nPhi;
        sTheta = 2. / nTheta;
}

void CylindricalProjectionMap::fillBin(const Vector3d& direction, double weight) {
        size_t bin = binFromDirection(direction);
        fillBin(bin, weight);
}

void CylindricalProjectionMap::fillBin(size_t bin, double weight) {
        pdf[bin] += weight;
        dirty = true;
}

Vector3d CylindricalProjectionMap::drawDirection() const {
        if (dirty)
                updateCdf();

        size_t bin = Random::instance().randBin(cdf);

        return directionFromBin(bin);
}

bool CylindricalProjectionMap::checkDirection(const Vector3d &direction) const {
        size_t bin = binFromDirection(direction);
        return pdf[bin];
}


const std::vector<double>& CylindricalProjectionMap::getPdf() const {
        return pdf;
}

std::vector<double>& CylindricalProjectionMap::getPdf() {
        return pdf;
}

const std::vector<double>& CylindricalProjectionMap::getCdf() const {
        return cdf;
}

size_t CylindricalProjectionMap::getNPhi() {
        return nPhi;
}

size_t CylindricalProjectionMap::getNTheta() {
        return nTheta;
}

/*
 * Cylindrical Coordinates
 * iPhi -> [0, 2*pi]
 * iTheta -> [0, 2]
 *
 * Spherical Coordinates
 * phi -> [-pi, pi]
 * theta -> [0, pi]
 */
size_t CylindricalProjectionMap::binFromDirection(const Vector3d& direction) const {
        // convert to cylindrical
        double phi = direction.getPhi() + M_PI;
        double theta = sin(M_PI_2 - direction.getTheta()) + 1;

        // to indices
        size_t iPhi = phi / sPhi;
        size_t iTheta = theta / sTheta;

        // interleave
        size_t bin =  iTheta * nPhi + iPhi;
        return bin;
}

Vector3d CylindricalProjectionMap::directionFromBin(size_t bin) const {
        // deinterleave
        double iPhi = bin % nPhi;
        double iTheta = bin / nPhi;

        // any where in the bin
        iPhi += Random::instance().rand();
        iTheta += Random::instance().rand();

        // cylindrical Coordinates
        double phi = iPhi * sPhi;
        double theta = iTheta * sTheta;

        // sphericala Coordinates
        phi = phi - M_PI;
        theta = M_PI_2 - asin(theta - 1);

        Vector3d v;
        v.setRThetaPhi(1.0, theta, phi);
        return v;
}

void CylindricalProjectionMap::updateCdf() const {
        if (dirty) {
                cdf[0] = pdf[0];
                for (size_t i = 1; i < pdf.size(); i++) {
                        cdf[i] = cdf[i-1] + pdf[i];
                }
                dirty = false;
        }
}

EmissionMap::EmissionMap() : minEnergy(0.0001 * EeV), maxEnergy(10000 * EeV),
        nEnergy(8*2), nPhi(360), nTheta(180) {
        logStep = log10(maxEnergy / minEnergy) / nEnergy;
}

EmissionMap::EmissionMap(size_t nPhi, size_t nTheta, size_t nEnergy) : minEnergy(0.0001 * EeV), maxEnergy(10000 * EeV),
        nEnergy(nEnergy), nPhi(nPhi), nTheta(nTheta) {
        logStep = log10(maxEnergy / minEnergy) / nEnergy;
}

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) {
        logStep = log10(maxEnergy / minEnergy) / nEnergy;
}

double EmissionMap::energyFromBin(size_t bin) const {
        return pow(10, log10(minEnergy) + logStep * bin);
}

size_t EmissionMap::binFromEnergy(double energy) const {
        return log10(energy / minEnergy) / logStep;
}

void EmissionMap::fillMap(int pid, double energy, const Vector3d& direction, double weight) {
        getMap(pid, energy)->fillBin(direction, weight);
}

void EmissionMap::fillMap(const ParticleState& state, double weight) {
        fillMap(state.getId(), state.getEnergy(), state.getDirection(), weight);
}

EmissionMap::map_t &EmissionMap::getMaps() {
        return maps;
}

const EmissionMap::map_t &EmissionMap::getMaps() const {
        return maps;
}

bool EmissionMap::drawDirection(int pid, double energy, Vector3d& direction) const {
        key_t key(pid, binFromEnergy(energy));
        map_t::const_iterator i = maps.find(key);

        if (i == maps.end() || !i->second.valid()) {
                return false;
        } else {
                direction = i->second->drawDirection();
                return true;
        }
}

bool EmissionMap::drawDirection(const ParticleState& state, Vector3d& direction) const {
        return drawDirection(state.getId(), state.getEnergy(), direction);
}

bool EmissionMap::checkDirection(int pid, double energy, const Vector3d& direction) const {
        key_t key(pid, binFromEnergy(energy));
        map_t::const_iterator i = maps.find(key);

        if (i == maps.end() || !i->second.valid()) {
                return false;
        } else {
                return i->second->checkDirection(direction);
        }
}

bool EmissionMap::checkDirection(const ParticleState& state) const {
        return checkDirection(state.getId(), state.getEnergy(), state.getDirection());
}

bool EmissionMap::hasMap(int pid, double energy) {
    key_t key(pid, binFromEnergy(energy));
    map_t::iterator i = maps.find(key);
    if (i == maps.end() || !i->second.valid())
                return false;
        else
                return true;
}

ref_ptr<CylindricalProjectionMap> EmissionMap::getMap(int pid, double energy) {
        key_t key(pid, binFromEnergy(energy));
        map_t::iterator i = maps.find(key);
        if (i == maps.end() || !i->second.valid()) {
                ref_ptr<CylindricalProjectionMap> cpm = new CylindricalProjectionMap(nPhi, nTheta);
                maps[key] = cpm;
                return cpm;
        } else {
                return i->second;
        }
}

void EmissionMap::save(const std::string &filename) {
        std::ofstream out(filename.c_str());
        out.imbue(std::locale("C"));

        for (map_t::iterator i = maps.begin(); i != maps.end(); i++) {
                if (!i->second.valid())
                        continue;
                out << i->first.first << " " << i->first.second << " " << energyFromBin(i->first.second) << " ";
                out << i->second->getNPhi() << " " << i->second->getNTheta();
                const std::vector<double> &pdf = i->second->getPdf();
                for (size_t i = 0; i < pdf.size(); i++)
                        out << " " << pdf[i];
                out << std::endl;
        }
}

void EmissionMap::merge(const EmissionMap *other) {
        if (other == 0)
                return;
        map_t::const_iterator i = other->getMaps().begin();
        map_t::const_iterator end = other->getMaps().end();
        for(;i != end; i++) {
                if (!i->second.valid())
                        continue;

                std::vector<double> &otherpdf = i->second->getPdf();
                ref_ptr<CylindricalProjectionMap> cpm = getMap(i->first.first, i->first.second);

                if (otherpdf.size() != cpm->getPdf().size()) {
                        throw std::runtime_error("PDF size mismatch!");
                        break;
                }

                for (size_t k = 0; k < otherpdf.size(); k++) {
                        cpm->fillBin(k, otherpdf[k]);
                }
        }
}

void EmissionMap::merge(const std::string &filename) {
        EmissionMap em;
        em.load(filename);
        merge(&em);
}

void EmissionMap::load(const std::string &filename) {
        std::ifstream in(filename.c_str());
        in.imbue(std::locale("C"));

        while(in.good()) {
                key_t key;
                double tmp;
                size_t nPhi_, nTheta_;
                in >> key.first >> key.second >> tmp;
                in >> nPhi_ >> nTheta_;

                if (!in.good()) {
                        KISS_LOG_ERROR << "Invalid line: " << key.first << " " << key.second << " " << nPhi_ << " " << nTheta_;
                        break;
                }

                if (nPhi != nPhi_) {
                        KISS_LOG_WARNING << "nPhi mismatch: " << nPhi << " " << nPhi_;
                }
                if (nTheta != nTheta_) {
                        KISS_LOG_WARNING << "nTheta mismatch: " << nTheta << " " << nTheta_;
                }

                ref_ptr<CylindricalProjectionMap> cpm = new CylindricalProjectionMap(nPhi_, nTheta_);
                std::vector<double> &pdf = cpm->getPdf();
                for (size_t i = 0; i < pdf.size(); i++)
                        in >> pdf[i];

                if (in.good()) {
                        maps[key] = cpm;
                        // std::cout << "added " << key.first << " " << key.second << std::endl;
                } else {
                        KISS_LOG_WARNING << "Invalid data in line: " << key.first << " " << key.second << " " << nPhi_ << " " << nTheta_ << "\n";
                }
        }

}

} // namespace crpropa