Program Listing for File TextOutput.cpp

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

#include "crpropa/module/TextOutput.h"
#include "crpropa/module/ParticleCollector.h"
#include "crpropa/Units.h"
#include "crpropa/Version.h"
#include "crpropa/Random.h"
#include "crpropa/base64.h"

#include "kiss/string.h"

#include <cstdio>
#include <stdexcept>
#include <iostream>

#ifdef CRPROPA_HAVE_ZLIB
#include <izstream.hpp>
#include <ozstream.hpp>
#endif

namespace crpropa {

TextOutput::TextOutput() : Output(), out(&std::cout), storeRandomSeeds(false) {
}

TextOutput::TextOutput(OutputType outputtype) : Output(outputtype), out(&std::cout), storeRandomSeeds(false) {
}

TextOutput::TextOutput(std::ostream &out) : Output(), out(&out), storeRandomSeeds(false) {
}

TextOutput::TextOutput(std::ostream &out,
                OutputType outputtype) : Output(outputtype), out(&out), storeRandomSeeds(false) {
}

TextOutput::TextOutput(const std::string &filename) :  Output(), outfile(filename.c_str(),
                                std::ios::binary), out(&outfile),  filename(
                                filename), storeRandomSeeds(false) {
        if (!outfile.is_open())
                throw std::runtime_error(std::string("Cannot create file: ") + filename);
        if (kiss::ends_with(filename, ".gz"))
                gzip();
}

TextOutput::TextOutput(const std::string &filename,
                                OutputType outputtype) : Output(outputtype), outfile(filename.c_str(),
                                std::ios::binary), out(&outfile), filename(
                                filename), storeRandomSeeds(false) {
        if (!outfile.is_open())
                throw std::runtime_error(std::string("Cannot create file: ") + filename);
        if (kiss::ends_with(filename, ".gz"))
                gzip();
}

void TextOutput::printHeader() const {
        *out << "#";
        if (fields.test(TrajectoryLengthColumn))
                *out << "\tD";
        if (fields.test(RedshiftColumn))
                *out << "\tz";
        if (fields.test(SerialNumberColumn))
                *out << "\tSN";
        if (fields.test(CurrentIdColumn))
                *out << "\tID";
        if (fields.test(CurrentEnergyColumn))
                *out << "\tE";
        if (fields.test(CurrentPositionColumn) && oneDimensional)
                *out << "\tX";
        if (fields.test(CurrentPositionColumn) && not oneDimensional)
                *out << "\tX\tY\tZ";
        if (fields.test(CurrentDirectionColumn) && not oneDimensional)
                *out << "\tPx\tPy\tPz";
        if (fields.test(SerialNumberColumn))
                *out << "\tSN0";
        if (fields.test(SourceIdColumn))
                *out << "\tID0";
        if (fields.test(SourceEnergyColumn))
                *out << "\tE0";
        if (fields.test(SourcePositionColumn) && oneDimensional)
                *out << "\tX0";
        if (fields.test(SourcePositionColumn) && not oneDimensional)
                *out << "\tX0\tY0\tZ0";
        if (fields.test(SourceDirectionColumn) && not oneDimensional)
                *out << "\tP0x\tP0y\tP0z";
        if (fields.test(SerialNumberColumn))
                *out << "\tSN1";
        if (fields.test(CreatedIdColumn))
                *out << "\tID1";
        if (fields.test(CreatedEnergyColumn))
                *out << "\tE1";
        if (fields.test(CreatedPositionColumn) && oneDimensional)
                *out << "\tX1";
        if (fields.test(CreatedPositionColumn) && not oneDimensional)
                *out << "\tX1\tY1\tZ1";
        if (fields.test(CreatedDirectionColumn) && not oneDimensional)
                *out << "\tP1x\tP1y\tP1z";
        if (fields.test(WeightColumn))
                *out << "\tW";
        if (fields.test(CandidateTagColumn))
                *out << "\ttag";
        for(std::vector<Property>::const_iterator iter = properties.begin();
                        iter != properties.end(); ++iter)
        {
                *out << "\t" << (*iter).name;
        }

        *out << "\n#\n";
        if (fields.test(TrajectoryLengthColumn))
                *out << "# D             Trajectory length [" << lengthScale / Mpc
                                << " Mpc]\n";
        if (fields.test(RedshiftColumn))
                *out << "# z             Redshift\n";
        if (fields.test(SerialNumberColumn))
                *out << "# SN/SN0/SN1    Serial number. Unique (within this run) id of the particle.\n";
        if (fields.test(CurrentIdColumn) || fields.test(CreatedIdColumn)
                        || fields.test(SourceIdColumn))
                *out << "# ID/ID0/ID1    Particle type (PDG MC numbering scheme)\n";
        if (fields.test(CurrentEnergyColumn) || fields.test(CreatedEnergyColumn)
                        || fields.test(SourceEnergyColumn))
                *out << "# E/E0/E1       Energy [" << energyScale / EeV << " EeV]\n";
        if (fields.test(CurrentPositionColumn) || fields.test(CreatedPositionColumn)
                        || fields.test(SourcePositionColumn))
                *out << "# X/X0/X1...    Position [" << lengthScale / Mpc << " Mpc]\n";
        if (fields.test(CurrentDirectionColumn)
                        || fields.test(CreatedDirectionColumn)
                        || fields.test(SourceDirectionColumn))
                *out << "# Px/P0x/P1x... Heading (unit vector of momentum)\n";
        if (fields.test(WeightColumn))
                *out << "# W             Weights" << " \n";
        if (fields.test(CandidateTagColumn)) {
                *out << "# tag           Candidate tag can be given by the source feature (user defined tag) or by the following interaction process \n";
                *out << "#\tES  \tElasticScattering \n" << "#\tEPP \tElectronPairProduction \n" << "#\tEMPP\tEMPairProduction\n"
                        << "#\tEMDP\tEMDoublePairProduction\n" << "#\tEMTP\tEMTripletPairProduction \n" << "#\tEMIC\tEMInverseComptonScattering\n"
                        << "#\tND  \tNuclearDecay\n" << "#\tPD  \tPhotoDisintegration\n" << "#\tPPP  \tPhotoPionProduction\n" << "#\tSYN \tSynchrotronRadiation\n"
                        << "#\tPRIM/SEC\t primary / secondary particle\n";
        }
        for(std::vector<Property>::const_iterator iter = properties.begin();
                        iter != properties.end(); ++iter)
        {
                        *out << "# " << (*iter).name << " " << (*iter).comment << "\n";
        }

        *out << "# no index = current, 0 = at source, 1 = at point of creation\n#\n";
        *out << "# CRPropa version: " << g_GIT_DESC << "\n#\n";

        if (storeRandomSeeds)
        {
                *out << "# Random seeds:\n";
                std::vector< std::vector<uint32_t> > seeds = Random::getSeedThreads();

                for (size_t i =0; i < seeds.size(); i++)
                {
                        std::string encoded_data = Base64::encode((unsigned char*) &seeds[i][0], sizeof(seeds[i][0]) * seeds[i].size() / sizeof(unsigned char));
                        *out << "#   Thread " << i << ": ";
                        *out << encoded_data;
                        *out << "\n";
                }
        }
}

void TextOutput::process(Candidate *c) const {
        if (fields.none() && properties.empty())
                return;

        char buffer[1024];
        size_t p = 0;

        std::locale old_locale = std::locale::global(std::locale::classic());

        if (fields.test(TrajectoryLengthColumn))
                p += std::sprintf(buffer + p, "%8.5E\t",
                                c->getTrajectoryLength() / lengthScale);

        if (fields.test(RedshiftColumn))
                p += std::sprintf(buffer + p, "%1.5E\t", c->getRedshift());

        if (fields.test(SerialNumberColumn))
                p += std::sprintf(buffer + p, "%10lu\t",
                                c->getSerialNumber());
        if (fields.test(CurrentIdColumn))
                p += std::sprintf(buffer + p, "%10i\t", c->current.getId());
        if (fields.test(CurrentEnergyColumn))
                p += std::sprintf(buffer + p, "%8.5E\t",
                                c->current.getEnergy() / energyScale);
        if (fields.test(CurrentPositionColumn)) {
                if (oneDimensional) {
                        p += std::sprintf(buffer + p, "%8.5E\t",
                                        c->current.getPosition().x / lengthScale);
                } else {
                        const Vector3d pos = c->current.getPosition() / lengthScale;
                        p += std::sprintf(buffer + p, "%8.5E\t%8.5E\t%8.5E\t", pos.x, pos.y,
                                        pos.z);
                }
        }
        if (fields.test(CurrentDirectionColumn)) {
                if (not oneDimensional) {
                        const Vector3d pos = c->current.getDirection();
                        p += std::sprintf(buffer + p, "%8.5E\t%8.5E\t%8.5E\t", pos.x, pos.y,
                                        pos.z);
                }
        }

        if (fields.test(SerialNumberColumn))
                p += std::sprintf(buffer + p, "%10lu\t", c->getSourceSerialNumber());
        if (fields.test(SourceIdColumn))
                p += std::sprintf(buffer + p, "%10i\t", c->source.getId());
        if (fields.test(SourceEnergyColumn))
                p += std::sprintf(buffer + p, "%8.5E\t",
                                c->source.getEnergy() / energyScale);
        if (fields.test(SourcePositionColumn)) {
                if (oneDimensional) {
                        p += std::sprintf(buffer + p, "%8.5E\t",
                                        c->source.getPosition().x / lengthScale);
                } else {
                        const Vector3d pos = c->source.getPosition() / lengthScale;
                        p += std::sprintf(buffer + p, "%8.5E\t%8.5E\t%8.5E\t", pos.x, pos.y,
                                        pos.z);
                }
        }
        if (fields.test(SourceDirectionColumn)) {
                if (not oneDimensional) {
                        const Vector3d pos = c->source.getDirection();
                        p += std::sprintf(buffer + p, "%8.5E\t%8.5E\t%8.5E\t", pos.x, pos.y,
                                        pos.z);
                }

        }

        if (fields.test(SerialNumberColumn))
                p += std::sprintf(buffer + p, "%10lu\t",
                                c->getCreatedSerialNumber());
        if (fields.test(CreatedIdColumn))
                p += std::sprintf(buffer + p, "%10i\t", c->created.getId());
        if (fields.test(CreatedEnergyColumn))
                p += std::sprintf(buffer + p, "%8.5E\t",
                                c->created.getEnergy() / energyScale);
        if (fields.test(CreatedPositionColumn)) {
                if (oneDimensional) {
                        p += std::sprintf(buffer + p, "%8.5E\t",
                                        c->created.getPosition().x / lengthScale);
                } else {
                        const Vector3d pos = c->created.getPosition() / lengthScale;
                        p += std::sprintf(buffer + p, "%8.5E\t%8.5E\t%8.5E\t", pos.x, pos.y,
                                        pos.z);
                }
        }
        if (fields.test(CreatedDirectionColumn)) {
                if (not oneDimensional) {
                        const Vector3d pos = c->created.getDirection();
                        p += std::sprintf(buffer + p, "%8.5E\t%8.5E\t%8.5E\t", pos.x, pos.y,
                                        pos.z);
                }
        }
        if (fields.test(WeightColumn)) {
                p += std::sprintf(buffer + p, "%8.5E\t", c->getWeight());
        }
        if (fields.test(CandidateTagColumn)) {
                p += std::sprintf(buffer + p, "%s\t", c->getTagOrigin().c_str());
        }

        for(std::vector<Output::Property>::const_iterator iter = properties.begin();
                        iter != properties.end(); ++iter) {
                  Variant v;
                        if (c->hasProperty((*iter).name)) {
                                v = c->getProperty((*iter).name);
                        } else {
                                v = (*iter).defaultValue;
                        }
                        p += std::sprintf(buffer + p, "%s", v.toString("\t").c_str());
                        p += std::sprintf(buffer + p, "\t");
        }
        buffer[p - 1] = '\n';

        std::locale::global(old_locale);

#pragma omp critical
        {
                if (count == 0)
                        printHeader();
                Output::process(c);
                out->write(buffer, p);
        }

}

void TextOutput::load(const std::string &filename, ParticleCollector *collector){

        std::string line;
        std::istream *in;
        std::ifstream infile(filename.c_str());

        double lengthScale = Mpc; // default Mpc
        double energyScale = EeV; // default EeV

        if (!infile.good())
                throw std::runtime_error("crpropa::TextOutput: could not open file " + filename);
        in = &infile;

        if (kiss::ends_with(filename, ".gz")){
#ifdef CRPROPA_HAVE_ZLIB
                in = new zstream::igzstream(*in);
#else
                throw std::runtime_error("CRPropa was built without Zlib compression!");
#endif
        }

        while (std::getline(*in, line)) {
                std::stringstream stream(line);
                if (stream.peek() == '#')
                        continue;

                ref_ptr<Candidate> c = new Candidate();
                double val_d; int val_i;
                double x, y, z;
                stream >> val_d;
                c->setTrajectoryLength(val_d*lengthScale); // D
                stream >> val_d;
                c->setRedshift(val_d); // z
                stream >> val_i;
                c->setSerialNumber(val_i); // SN
                stream >> val_i;
                c->current.setId(val_i); // ID
                stream >> val_d;
                c->current.setEnergy(val_d*energyScale); // E
                stream >> x >> y >> z;
                c->current.setPosition(Vector3d(x, y, z)*lengthScale); // X, Y, Z
                stream >> x >> y >> z;
                c->current.setDirection(Vector3d(x, y, z)*lengthScale); // Px, Py, Pz
                stream >> val_i; // SN0 (TODO: Reconstruct the parent-child relationship)
                stream >> val_i;
                c->source.setId(val_i); // ID0
                stream >> val_d;
                c->source.setEnergy(val_d*energyScale); // E0
                stream >> x >> y >> z;
                c->source.setPosition(Vector3d(x, y, z)*lengthScale); // X0, Y0, Z0
                stream >> x >> y >> z;
                c->source.setDirection(Vector3d(x, y, z)*lengthScale); // P0x, P0y, P0z
                stream >> val_i; // SN1
                stream >> val_i;
                c->created.setId(val_i); // ID1
                stream >> val_d;
                c->created.setEnergy(val_d*energyScale); // E1
                stream >> x >> y >> z;
                c->created.setPosition(Vector3d(x, y, z)*lengthScale); // X1, Y1, Z1
                stream >> x >> y >> z;
                c->created.setDirection(Vector3d(x, y, z)*lengthScale); // P1x, P1y, P1z
                stream >> val_d;
                c->setWeight(val_d); // W

                collector->process(c);
        }
        infile.close();
}

std::string TextOutput::getDescription() const {
        return "TextOutput";
}

void TextOutput::close() {
#ifdef CRPROPA_HAVE_ZLIB
        zstream::ogzstream *zs = dynamic_cast<zstream::ogzstream *>(out);
        if (zs) {
                zs->close();
                delete out;
                out = 0;
        }
#endif
        outfile.flush();
}

TextOutput::~TextOutput() {
        close();
}

void TextOutput::gzip() {
#ifdef CRPROPA_HAVE_ZLIB
        out = new zstream::ogzstream(*out);
#else
        throw std::runtime_error("CRPropa was built without Zlib compression!");
#endif
}

} // namespace crpropa