Program Listing for File ParticleMapsContainer.cpp
↰ Return to documentation for file (src/magneticLens/ParticleMapsContainer.cpp
)
#include "HepPID/ParticleIDMethods.hh"
#include "crpropa/Random.h"
#include "crpropa/magneticLens/ParticleMapsContainer.h"
#include "crpropa/Units.h"
#include <iostream>
#include <fstream>
namespace crpropa {
ParticleMapsContainer::~ParticleMapsContainer() {
for(std::map<int, std::map<int, double*> >::iterator pid_iter = _data.begin();
pid_iter != _data.end(); ++pid_iter) {
for(std::map<int, double*>::iterator energy_iter = pid_iter->second.begin();
energy_iter != pid_iter->second.end(); ++energy_iter) {
delete[] (energy_iter->second);
}
}
}
int ParticleMapsContainer::energy2Idx(double energy) const {
double lE = log10(energy / eV);
return int((lE - _bin0lowerEdge) / _deltaLogE);
}
double ParticleMapsContainer::idx2Energy(int idx) const {
return pow(10, idx * _deltaLogE + _bin0lowerEdge + _deltaLogE / 2) * eV;
}
double* ParticleMapsContainer::getMap(const int particleId, double energy) {
_weightsUpToDate = false;
if (_data.find(particleId) == _data.end()) {
std::cerr << "No map for ParticleID " << particleId << std::endl;
return NULL;
}
int energyIdx = energy2Idx(energy);
if (_data[particleId].find(energyIdx) == _data[particleId].end()) {
std::cerr << "No map for ParticleID and energy" << energy / eV << " eV" << std::endl;
return NULL;
}
return _data[particleId][energy2Idx(energy)];
}
void ParticleMapsContainer::addParticle(const int particleId, double energy, double galacticLongitude, double galacticLatitude, double weight) {
_weightsUpToDate = false;
if (_data.find(particleId) == _data.end()) {
map<int, double*> M;
_data[particleId] = M;
}
int energyIdx = energy2Idx(energy);
if (_data[particleId].find(energyIdx) == _data[particleId].end()) {
_data[particleId][energyIdx] = new double[_pixelization.getNumberOfPixels()];
std::fill(_data[particleId][energyIdx], _data[particleId][energyIdx] + _pixelization.getNumberOfPixels(), 0);
}
uint32_t pixel = _pixelization.direction2Pix(galacticLongitude, galacticLatitude);
_data[particleId][energyIdx][pixel] += weight;
}
void ParticleMapsContainer::addParticle(const int particleId, double energy, const Vector3d &p, double weight) {
double galacticLongitude = atan2(-p.y, -p.x);
double galacticLatitude = M_PI / 2 - acos(-p.z / p.getR());
addParticle(particleId, energy, galacticLongitude, galacticLatitude, weight);
}
std::vector<int> ParticleMapsContainer::getParticleIds() {
std::vector<int> ids;
for(std::map<int, std::map<int, double*> >::iterator pid_iter = _data.begin();
pid_iter != _data.end(); ++pid_iter) {
ids.push_back(pid_iter->first);
}
return ids;
}
std::vector<double> ParticleMapsContainer::getEnergies(int pid) {
std::vector<double> energies;
if (_data.find(pid) != _data.end()) {
for(std::map<int, double*>::iterator iter = _data[pid].begin();
iter != _data[pid].end(); ++iter) {
energies.push_back( idx2Energy(iter->first) / eV );
}
}
return energies;
}
void ParticleMapsContainer::applyLens(MagneticLens &lens) {
// if lens is normalized, this should not be necessary.
_weightsUpToDate = false;
for(std::map<int, std::map<int, double*> >::iterator pid_iter = _data.begin();
pid_iter != _data.end(); ++pid_iter) {
for(std::map<int, double*>::iterator energy_iter = pid_iter->second.begin();
energy_iter != pid_iter->second.end(); ++energy_iter) {
// transform only nuclei
double energy = idx2Energy(energy_iter->first);
int chargeNumber = HepPID::Z(pid_iter->first);
if (chargeNumber != 0 && lens.rigidityCovered(energy / chargeNumber)) {
lens.transformModelVector(energy_iter->second, energy / chargeNumber);
} else { // still normalize the vectors
for(size_t j=0; j< _pixelization.getNumberOfPixels() ; j++) {
energy_iter->second[j] /= lens.getNorm();
}
}
}
}
}
void ParticleMapsContainer::_updateWeights() {
if (_weightsUpToDate)
return;
for(std::map<int, std::map<int, double*> >::iterator pid_iter = _data.begin();
pid_iter != _data.end(); ++pid_iter) {
_weightsPID[pid_iter->first] = 0;
for(std::map<int, double*>::iterator energy_iter = pid_iter->second.begin();
energy_iter != pid_iter->second.end(); ++energy_iter) {
_weights_pidEnergy[pid_iter->first][energy_iter->first] = 0;
for(size_t j = 0; j< _pixelization.getNumberOfPixels() ; j++) {
_weights_pidEnergy[pid_iter->first][energy_iter->first] +=energy_iter->second[j];
_weightsPID[pid_iter->first]+=energy_iter->second[j];
}
_sumOfWeights+=_weights_pidEnergy[pid_iter->first][energy_iter->first];
}
}
_weightsUpToDate = true;
}
void ParticleMapsContainer::getRandomParticles(size_t N, vector<int> &particleId,
vector<double> &energy, vector<double> &galacticLongitudes,
vector<double> &galacticLatitudes) {
_updateWeights();
particleId.resize(N);
energy.resize(N);
galacticLongitudes.resize(N);
galacticLatitudes.resize(N);
for(size_t i=0; i< N; i++) {
//get particle
double r = Random::instance().rand() * _sumOfWeights;
std::map<int, double>::iterator iter = _weightsPID.begin();
while ((r-= iter->second) > 0) {
++iter;
}
particleId[i] = iter->first;
//get energy
r = Random::instance().rand() * iter->second;
iter = _weights_pidEnergy[particleId[i]].begin();
while ((r-= iter->second) > 0) {
++iter;
}
energy[i] = idx2Energy(iter->first) / eV;
placeOnMap(particleId[i], energy[i] * eV, galacticLongitudes[i], galacticLatitudes[i]);
}
}
bool ParticleMapsContainer::placeOnMap(int pid, double energy, double &galacticLongitude, double &galacticLatitude) {
_updateWeights();
if (_data.find(pid) == _data.end()) {
return false;
}
int energyIdx = energy2Idx(energy);
if (_data[pid].find(energyIdx) == _data[pid].end()) {
return false;
}
double r = Random::instance().rand() * _weights_pidEnergy[pid][energyIdx];
for(size_t j = 0; j< _pixelization.getNumberOfPixels(); j++) {
r -= _data[pid][energyIdx][j];
if (r <= 0) {
_pixelization.getRandomDirectionInPixel(j, galacticLongitude, galacticLatitude);
return true;
}
}
return false;
}
void ParticleMapsContainer::forceWeightUpdate() {
_weightsUpToDate = false;
}
} // namespace crpropa