Program Listing for File EMCascade.cpp

Return to documentation for file (src/module/EMCascade.cpp)

#include "crpropa/module/EMCascade.h"
#include "crpropa/Cosmology.h"
#include "crpropa/Units.h"

#include "dint/DintEMCascade.h"
#include "kiss/logger.h"

#include <fstream>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <stdexcept>
#include <cmath>

namespace crpropa {

EMCascade::EMCascade() : nE(170), logEmin(7), logEmax(24), dlogE(0.1) {
        KISS_LOG_WARNING << "EMCascade is deprecated and is no longer supported. Please use the EM* (EMPairProduction, EMInverseComptonScattering, ...) modules instead.\n";
        setDistanceBinning(1000 * Mpc, 1000);
}

void EMCascade::setDistanceBinning(double Dmax, int nD) {
        this->Dmax = Dmax;
        this->nD = nD;
        this->dD = Dmax / nD;
        init();
}

void EMCascade::init() {
        photonHist.reserve(nD * nE);
        photonHist.assign(nD * nE, 0);
        electronHist.reserve(nD * nE);
        electronHist.assign(nD * nE, 0);
        positronHist.reserve(nD * nE);
        positronHist.assign(nD * nE, 0);
}

std::string EMCascade::getDescription() const {
        std::stringstream s;
        s << "EMCascade";
        return s.str();
}

void EMCascade::process(Candidate *candidate) const {
        int id = candidate->current.getId();
        if ((id != 22) and (id != 11) and (id != -11))
                return;

        candidate->setActive(false);

        double logE = log10(candidate->current.getEnergy() / eV);
        double D = candidate->current.getPosition().getR();  // distance to (0,0,0)

        if ((logE < logEmin) or (logE > logEmax))
                return;
        if (D > Dmax)
                return;

        int iE = (logE - logEmin) / dlogE;
        int iD = D / dD;
        int i = (iD * nE) + iE;

#pragma omp critical
        {
        if (id == 22)
                photonHist[i] += 1;
        else if (id == 11)
                electronHist[i] += 1;
        else
                positronHist[i] += 1;
        }
}

void EMCascade::save(const std::string &filename) {
        std::ofstream outfile(filename.c_str());
        if (!outfile) {
                std::stringstream s;
                s << "EMCascade: could not open " << filename;
                throw std::runtime_error(s.str());
        }
        outfile << "# D/Mpc log10(E/eV) nPhotons nElectrons nPositrons\n";
        for (int i = 0; i < (nD * nE); i++) {
                div_t divresult = div(i, nE);
                double D = (divresult.quot + 0.5) * dD / Mpc;
                double logE = logEmin + (divresult.rem + 0.5) * dlogE;
                outfile << D << "\t";
                outfile << logE << "\t";
                outfile << photonHist[i] << "\t";
                outfile << electronHist[i] << "\t";
                outfile << positronHist[i] << "\n";
        }
        outfile.close();
}

void EMCascade::load(const std::string &filename) {
        std::ifstream infile(filename.c_str());
        if (!infile) {
                std::stringstream s;
                s << "EMCascade: could not open " << filename;
                throw std::runtime_error(s.str());
        }

        infile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // skip header
        double D, lE, h1, h2, h3;
        for (int i = 0; i < (nD * nE); i++) {
                infile >> D >> lE >> h1 >> h2 >> h3;
                if (!infile.good())
                        throw std::runtime_error("EMCascde: error reading file");
                photonHist[i] += h1;
                electronHist[i] += h2;
                positronHist[i] += h3;
        }
        infile.close();
}

void EMCascade::runCascade(const std::string &filename, int IRBFlag,
                int RadioFlag, double Bfield, double cutCascade) {

        // set up DINT
        std::string dataPath = getDataPath("dint");
        double B = Bfield / gauss;
        double h = H0() * Mpc / 1000;
        DintEMCascade dint(IRBFlag, RadioFlag, dataPath, B, h, omegaM(), omegaL());

        Spectrum inputSpectrum, outputSpectrum;
        NewSpectrum(&inputSpectrum, nE);
        NewSpectrum(&outputSpectrum, nE);
        InitializeSpectrum(&outputSpectrum);

        // step-wise cascade calculation
        for (int iD = nD - 1; iD >= 0; iD--) {
                // make output of previous step the new input and reset output
                SetSpectrum(&inputSpectrum, &outputSpectrum);
                InitializeSpectrum(&outputSpectrum);

                // add new particles to input
                double count = 0;
                for (int iE = 0; iE < nE; iE++) {
                        int i = (iD * nE) + iE;
                        inputSpectrum.spectrum[PHOTON][iE] += photonHist[i];
                        inputSpectrum.spectrum[ELECTRON][iE] += electronHist[i];
                        inputSpectrum.spectrum[POSITRON][iE] += positronHist[i];
                        count += inputSpectrum.spectrum[PHOTON][iE];
                        count += inputSpectrum.spectrum[ELECTRON][iE];
                        count += inputSpectrum.spectrum[POSITRON][iE];
                }
                // skip step if input spectrum empty
                if (count == 0)
                        continue;

                // start and stop distance [Mpc,light travel] from bin center to bin center
                double D1 = comoving2LightTravelDistance( (iD + 0.5) * dD );
                double D0 = comoving2LightTravelDistance( std::max((iD - 0.5) * dD, 0.) );

                // propagate distance step
                dint.propagate(D1/Mpc, D0/Mpc, &inputSpectrum, &outputSpectrum, cutCascade);
        }

        // write output
        std::ofstream outfile(filename.c_str());
        if (!outfile) {
                std::stringstream s;
                s << "EMCascade: could not open " << filename;
                throw std::runtime_error(s.str());
        }
        outfile << "# log10(E/eV) photons electrons positrons\n";
        for (int iE = 0; iE < nE; iE++) {
                outfile << std::setw(5) << logEmin + (iE + 0.5) * dlogE;
                for (int s = 0; s < 3; s++)
                        outfile << std::setw(13) << outputSpectrum.spectrum[s][iE];
                outfile << "\n";
        }
        outfile.close();

        // clear the histogram
        photonHist.assign(nD * nE, 0);
        electronHist.assign(nD * nE, 0);
        positronHist.assign(nD * nE, 0);

        DeleteSpectrum(&outputSpectrum);
        DeleteSpectrum(&inputSpectrum);
}

} // namespace crpropa