LCOV - code coverage report
Current view: top level - src - Source.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 459 784 58.5 %
Date: 2024-04-29 14:43:01 Functions: 81 146 55.5 %

          Line data    Source code
       1             : #include "crpropa/Source.h"
       2             : #include "crpropa/Random.h"
       3             : #include "crpropa/Cosmology.h"
       4             : #include "crpropa/Common.h"
       5             : #include "crpropa/Units.h"
       6             : #include "crpropa/ParticleID.h"
       7             : 
       8             : #ifdef CRPROPA_HAVE_MUPARSER
       9             : #include "muParser.h"
      10             : #endif
      11             : 
      12             : #include <sstream>
      13             : #include <stdexcept>
      14             : 
      15             : namespace crpropa {
      16             : 
      17             : // Source ---------------------------------------------------------------------
      18          19 : void Source::add(SourceFeature* property) {
      19          19 :         features.push_back(property);
      20          19 : }
      21             : 
      22        2103 : ref_ptr<Candidate> Source::getCandidate() const {
      23        4206 :         ref_ptr<Candidate> candidate = new Candidate();
      24        7512 :         for (int i = 0; i < features.size(); i++)
      25        5409 :                 (*features[i]).prepareCandidate(*candidate);
      26        2103 :         return candidate;
      27             : }
      28             : 
      29           0 : std::string Source::getDescription() const {
      30           0 :         std::stringstream ss;
      31           0 :         ss << "Cosmic ray source\n";
      32           0 :         for (int i = 0; i < features.size(); i++)
      33           0 :                 ss << "    " << features[i]->getDescription();
      34           0 :         return ss.str();
      35           0 : }
      36             : 
      37             : // SourceList------------------------------------------------------------------
      38           3 : void SourceList::add(Source* source, double weight) {
      39           6 :         sources.push_back(source);
      40           3 :         if (cdf.size() > 0)
      41           1 :                 weight += cdf.back();
      42           3 :         cdf.push_back(weight);
      43           3 : }
      44             : 
      45        1002 : ref_ptr<Candidate> SourceList::getCandidate() const {
      46        1002 :         if (sources.size() == 0)
      47           1 :                 throw std::runtime_error("SourceList: no sources set");
      48        1001 :         size_t i = Random::instance().randBin(cdf);
      49        1001 :         return (sources[i])->getCandidate();
      50             : }
      51             : 
      52           0 : std::string SourceList::getDescription() const {
      53           0 :         std::stringstream ss;
      54           0 :         ss << "List of cosmic ray sources\n";
      55           0 :         for (int i = 0; i < sources.size(); i++)
      56           0 :                 ss << "  " << sources[i]->getDescription();
      57           0 :         return ss.str();
      58           0 : }
      59             : 
      60             : // SourceFeature---------------------------------------------------------------
      61        5407 : void SourceFeature::prepareCandidate(Candidate& candidate) const {
      62        5407 :         ParticleState &source = candidate.source;
      63        5407 :         prepareParticle(source);
      64             :         candidate.created = source;
      65             :         candidate.current = source;
      66             :         candidate.previous = source;
      67        5407 : }
      68             : 
      69           0 : std::string SourceFeature::getDescription() const {
      70           0 :         return description;
      71             : }
      72             : 
      73             : // ----------------------------------------------------------------------------
      74           3 : SourceParticleType::SourceParticleType(int id) :
      75           3 :                 id(id) {
      76           3 :         setDescription();
      77           3 : }
      78             : 
      79        1101 : void SourceParticleType::prepareParticle(ParticleState& particle) const {
      80        1101 :         particle.setId(id);
      81        1101 : }
      82             : 
      83           3 : void SourceParticleType::setDescription() {
      84           3 :         std::stringstream ss;
      85           3 :         ss << "SourceParticleType: " << id << "\n";
      86           3 :         description = ss.str();
      87           3 : }
      88             : 
      89             : // ----------------------------------------------------------------------------
      90           0 : SourceMultipleParticleTypes::SourceMultipleParticleTypes() {
      91           0 :         setDescription();
      92           0 : }
      93             : 
      94           0 : void SourceMultipleParticleTypes::add(int id, double a) {
      95           0 :         particleTypes.push_back(id);
      96           0 :         if (cdf.size() > 0)
      97           0 :                 a += cdf.back();
      98           0 :         cdf.push_back(a);
      99           0 :         setDescription();
     100           0 : }
     101             : 
     102           0 : void SourceMultipleParticleTypes::prepareParticle(ParticleState& particle) const {
     103           0 :         if (particleTypes.size() == 0)
     104           0 :                 throw std::runtime_error("SourceMultipleParticleTypes: no nuclei set");
     105           0 :         size_t i = Random::instance().randBin(cdf);
     106           0 :         particle.setId(particleTypes[i]);
     107           0 : }
     108             : 
     109           0 : void SourceMultipleParticleTypes::setDescription() {
     110           0 :         std::stringstream ss;
     111           0 :         ss << "SourceMultipleParticleTypes: Random particle type\n";
     112           0 :         for (int i = 0; i < particleTypes.size(); i++)
     113           0 :                 ss << "      ID = " << particleTypes[i] << "\n";
     114           0 :         description = ss.str();
     115           0 : }
     116             : 
     117             : // ----------------------------------------------------------------------------
     118           2 : SourceEnergy::SourceEnergy(double energy) :
     119           2 :                 E(energy) {
     120           2 :         setDescription();
     121           2 : }
     122             : 
     123        1000 : void SourceEnergy::prepareParticle(ParticleState& p) const {
     124        1000 :         p.setEnergy(E);
     125        1000 : }
     126             : 
     127           2 : void SourceEnergy::setDescription() {
     128           2 :         std::stringstream ss;
     129           2 :         ss << "SourceEnergy: " << E / EeV << " EeV\n";
     130           2 :         description = ss.str();
     131           2 : }
     132             : 
     133             : // ----------------------------------------------------------------------------
     134           4 : SourcePowerLawSpectrum::SourcePowerLawSpectrum(double Emin, double Emax,
     135           4 :                 double index) :
     136           4 :                 Emin(Emin), Emax(Emax), index(index) {
     137           4 :         setDescription();
     138           4 : }
     139             : 
     140        1102 : void SourcePowerLawSpectrum::prepareParticle(ParticleState& particle) const {
     141        1102 :         Random &random = Random::instance();
     142        1102 :         double E = random.randPowerLaw(index, Emin, Emax);
     143        1102 :         particle.setEnergy(E);
     144        1102 : }
     145             : 
     146           4 : void SourcePowerLawSpectrum::setDescription() {
     147           4 :         std::stringstream ss;
     148           4 :         ss << "SourcePowerLawSpectrum: Random energy ";
     149           8 :         ss << "E = " << Emin / EeV << " - " << Emax / EeV << " EeV, ";
     150           4 :         ss << "dN/dE ~ E^" << index  << "\n";
     151           4 :         description = ss.str();
     152           4 : }
     153             : 
     154             : // ----------------------------------------------------------------------------
     155           3 : SourceComposition::SourceComposition(double Emin, double Rmax, double index) :
     156           3 :                 Emin(Emin), Rmax(Rmax), index(index) {
     157           3 :         setDescription();
     158           3 : }
     159             : 
     160           5 : void SourceComposition::add(int id, double weight) {
     161           5 :         nuclei.push_back(id);
     162           5 :         int A = massNumber(id);
     163           5 :         int Z = chargeNumber(id);
     164             : 
     165           5 :         double a = 1 + index;
     166           5 :         if (std::abs(a) < std::numeric_limits<double>::min())
     167           5 :                 weight *= log(Z * Rmax / Emin);
     168             :         else
     169           0 :                 weight *= (pow(Z * Rmax, a) - pow(Emin, a)) / a;
     170             : 
     171           5 :         weight *= pow(A, -a);
     172             : 
     173           5 :         if (cdf.size() > 0)
     174           3 :                 weight += cdf.back();
     175           5 :         cdf.push_back(weight);
     176           5 :         setDescription();
     177           5 : }
     178             : 
     179           4 : void SourceComposition::add(int A, int Z, double a) {
     180           4 :         add(nucleusId(A, Z), a);
     181           4 : }
     182             : 
     183           3 : void SourceComposition::prepareParticle(ParticleState& particle) const {
     184           3 :         if (nuclei.size() == 0)
     185           1 :                 throw std::runtime_error("SourceComposition: No source isotope set");
     186             : 
     187           2 :         Random &random = Random::instance();
     188             : 
     189             :         // draw random particle type
     190           2 :         size_t i = random.randBin(cdf);
     191           2 :         int id = nuclei[i];
     192           2 :         particle.setId(id);
     193             : 
     194             :         // random energy from power law
     195           2 :         int Z = chargeNumber(id);
     196           2 :         particle.setEnergy(random.randPowerLaw(index, Emin, Z * Rmax));
     197           2 : }
     198             : 
     199           8 : void SourceComposition::setDescription() {
     200           8 :         std::stringstream ss;
     201           8 :         ss << "SourceComposition: Random element and energy ";
     202          16 :         ss << "E = " << Emin / EeV << " - Z*" << Rmax / EeV << " EeV, ";
     203           8 :         ss << "dN/dE ~ E^" << index << "\n";
     204          19 :         for (int i = 0; i < nuclei.size(); i++)
     205          11 :                 ss << "      ID = " << nuclei[i] << "\n";
     206           8 :         description = ss.str();
     207           8 : }
     208             : 
     209             : // ----------------------------------------------------------------------------
     210           5 : SourcePosition::SourcePosition(Vector3d position) :
     211           5 :                 position(position) {
     212           5 :         setDescription();
     213           5 : }
     214             : 
     215           0 : SourcePosition::SourcePosition(double d) :
     216           0 :                 position(Vector3d(d, 0, 0)) {
     217           0 :         setDescription();
     218           0 : }
     219             : 
     220        1103 : void SourcePosition::prepareParticle(ParticleState& particle) const {
     221        1103 :         particle.setPosition(position);
     222        1103 : }
     223             : 
     224           5 : void SourcePosition::setDescription() {
     225           5 :         std::stringstream ss;
     226           5 :         ss << "SourcePosition: " << position / Mpc << " Mpc\n";
     227           5 :         description = ss.str();
     228           5 : }
     229             : 
     230             : // ----------------------------------------------------------------------------
     231           1 : SourceMultiplePositions::SourceMultiplePositions() {
     232           1 :         setDescription();
     233           1 : }
     234             : 
     235           2 : void SourceMultiplePositions::add(Vector3d pos, double weight) {
     236           2 :         positions.push_back(pos);
     237           2 :         if (cdf.size() > 0)
     238           1 :                 weight += cdf.back();
     239           2 :         cdf.push_back(weight);
     240           2 : }
     241             : 
     242       10000 : void SourceMultiplePositions::prepareParticle(ParticleState& particle) const {
     243       10000 :         if (positions.size() == 0)
     244           0 :                 throw std::runtime_error("SourceMultiplePositions: no position set");
     245       10000 :         size_t i = Random::instance().randBin(cdf);
     246       10000 :         particle.setPosition(positions[i]);
     247       10000 : }
     248             : 
     249           1 : void SourceMultiplePositions::setDescription() {
     250           1 :         std::stringstream ss;
     251           1 :         ss << "SourceMultiplePositions: Random position from list\n";
     252           1 :         for (int i = 0; i < positions.size(); i++)
     253           0 :                 ss << "  " << positions[i] / Mpc << " Mpc\n";
     254           1 :         description = ss.str();
     255           1 : }
     256             : 
     257             : // ----------------------------------------------------------------------------
     258           1 : SourceUniformSphere::SourceUniformSphere(Vector3d center, double radius) :
     259           1 :                 center(center), radius(radius) {
     260           1 :         setDescription();
     261           1 : }
     262             : 
     263           1 : void SourceUniformSphere::prepareParticle(ParticleState& particle) const {
     264           1 :         Random &random = Random::instance();
     265           1 :         double r = pow(random.rand(), 1. / 3.) * radius;
     266           1 :         particle.setPosition(center + random.randVector() * r);
     267           1 : }
     268             : 
     269           1 : void SourceUniformSphere::setDescription() {
     270           1 :         std::stringstream ss;
     271           1 :         ss << "SourceUniformSphere: Random position within a sphere at ";
     272           1 :         ss << center / Mpc << " Mpc with";
     273           1 :         ss  << radius / Mpc << " Mpc radius\n";
     274           1 :         description = ss.str();
     275           1 : }
     276             : 
     277             : // ----------------------------------------------------------------------------
     278           1 : SourceUniformHollowSphere::SourceUniformHollowSphere(
     279             :                 Vector3d center,
     280             :                 double radius_inner,
     281           1 :                 double radius_outer) :
     282           1 :                 center(center), radius_inner(radius_inner),
     283           1 :                 radius_outer(radius_outer) {
     284           1 :         setDescription();
     285           1 : }
     286             : 
     287         100 : void SourceUniformHollowSphere::prepareParticle(ParticleState& particle) const {
     288         100 :         Random &random = Random::instance();
     289         100 :         double r = radius_inner + pow(random.rand(), 1. / 3.) * (radius_outer - radius_inner);
     290         100 :         particle.setPosition(center + random.randVector() * r);
     291         100 : }
     292             : 
     293           1 : void SourceUniformHollowSphere::setDescription() {
     294           1 :         std::stringstream ss;
     295           1 :         ss << "SourceUniformHollowSphere: Random position within a sphere at ";
     296           1 :         ss << center / Mpc << " Mpc with";
     297           1 :         ss << radius_inner / Mpc << " Mpc inner radius\n";
     298           1 :         ss << radius_outer / Mpc << " Mpc outer radius\n";
     299           1 :         description = ss.str();
     300           1 : }
     301             : 
     302             : // ----------------------------------------------------------------------------
     303           0 : SourceUniformShell::SourceUniformShell(Vector3d center, double radius) :
     304           0 :                 center(center), radius(radius) {
     305           0 :         setDescription();
     306           0 : }
     307             : 
     308           0 : void SourceUniformShell::prepareParticle(ParticleState& particle) const {
     309           0 :         Random &random = Random::instance();
     310           0 :         particle.setPosition(center + random.randVector() * radius);
     311           0 : }
     312             : 
     313           0 : void SourceUniformShell::setDescription() {
     314           0 :         std::stringstream ss;
     315           0 :         ss << "SourceUniformShell: Random position on a spherical shell at ";
     316           0 :         ss << center / Mpc << " Mpc with ";
     317           0 :         ss << radius / Mpc << " Mpc radius\n";
     318           0 :         description = ss.str();
     319           0 : }
     320             : 
     321             : // ----------------------------------------------------------------------------
     322           1 : SourceUniformBox::SourceUniformBox(Vector3d origin, Vector3d size) :
     323           1 :                 origin(origin), size(size) {
     324           1 :         setDescription();
     325           1 : }
     326             : 
     327           1 : void SourceUniformBox::prepareParticle(ParticleState& particle) const {
     328           1 :         Random &random = Random::instance();
     329           1 :         Vector3d pos(random.rand(), random.rand(), random.rand());
     330           1 :         particle.setPosition(pos * size + origin);
     331           1 : }
     332             : 
     333           1 : void SourceUniformBox::setDescription() {
     334           1 :         std::stringstream ss;
     335           1 :         ss << "SourceUniformBox: Random uniform position in box with ";
     336           1 :         ss << "origin = " << origin / Mpc << " Mpc and ";
     337           1 :         ss << "size = " << size / Mpc << " Mpc\n";
     338           1 :         description = ss.str();
     339           1 : }
     340             : 
     341             : // ---------------------------------------------------------------------------
     342           1 : SourceUniformCylinder::SourceUniformCylinder(Vector3d origin, double height, double radius) :
     343           1 :     origin(origin), height(height), radius(radius) {
     344           1 : }
     345             : 
     346           1 : void SourceUniformCylinder::prepareParticle(ParticleState& particle) const {
     347           1 :   Random &random = Random::instance();
     348           1 :   double phi = 2*M_PI*random.rand();
     349           1 :   double RandRadius = radius*pow(random.rand(), 1. / 2.);
     350           1 :   Vector3d pos(cos(phi)*RandRadius, sin(phi)*RandRadius, (-0.5+random.rand())*height);
     351           1 :   particle.setPosition(pos + origin);
     352           1 :   }
     353             : 
     354           0 : void SourceUniformCylinder::setDescription() {
     355           0 :         std::stringstream ss;
     356           0 :         ss << "SourceUniformCylinder: Random uniform position in cylinder with ";
     357           0 :         ss << "origin = " << origin / Mpc << " Mpc and ";
     358           0 :         ss << "radius = " << radius / Mpc << " Mpc and";
     359           0 :         ss << "height = " << height / Mpc << " Mpc\n";
     360           0 :         description = ss.str();
     361           0 : }
     362             : 
     363             : // ---------------------------------------------------------------------------
     364           0 : SourceSNRDistribution::SourceSNRDistribution() :
     365           0 :     rEarth(8.5 * kpc), beta(3.53), zg(0.3 * kpc) {
     366           0 :         setAlpha(2.);
     367           0 :         setFrMax();
     368           0 :         setFzMax(0.3 * kpc);
     369           0 :         setRMax(20 * kpc);
     370           0 :         setZMax(5 * kpc);
     371           0 : }
     372             : 
     373           1 : SourceSNRDistribution::SourceSNRDistribution(double rEarth, double alpha, double beta, double zg) :
     374           1 :     rEarth(rEarth), beta(beta), zg(zg) {
     375           1 :         setAlpha(alpha);
     376           1 :         setFrMax();
     377           1 :         setFzMax(zg);
     378           1 :         setRMax(20 * kpc);
     379           1 :         setZMax(5 * kpc);
     380           1 : }
     381             : 
     382      100001 : void SourceSNRDistribution::prepareParticle(ParticleState& particle) const {
     383      100001 :         Random &random = Random::instance();
     384             :         double RPos;
     385             :         while (true) {
     386      192306 :                 RPos = random.rand() * rMax;
     387      192306 :                 double fTest = random.rand() * frMax;
     388      192306 :                 double fR = fr(RPos);
     389      192306 :                 if (fTest <= fR) {
     390             :                         break;
     391             :                 }
     392             :         }
     393             :         double ZPos;
     394             :         while (true) {
     395     1666581 :                 ZPos = (random.rand() - 0.5) * 2 * zMax;
     396     1666581 :                 double fTest = random.rand() * fzMax;
     397     1666581 :                 double fZ=fz(ZPos);
     398     1666581 :                 if (fTest<=fZ) {
     399             :                         break;
     400             :                 }
     401             :         }
     402      100001 :         double phi = random.rand() * 2 * M_PI;
     403      100001 :         Vector3d pos(cos(phi) * RPos, sin(phi) * RPos, ZPos);
     404      100001 :         particle.setPosition(pos);
     405      100001 : }
     406             : 
     407      192306 : double SourceSNRDistribution::fr(double r) const {
     408      192306 :         return pow(r / rEarth, alpha) * exp(- beta * (r - rEarth) / rEarth);
     409             : }
     410             : 
     411     1666581 : double SourceSNRDistribution::fz(double z) const{
     412             :         double Az = 1.;
     413     1666581 :         double f = 1. / zg * exp(- fabs(z) / zg);
     414             :         double fz = Az * f;
     415     1666581 :         return fz;
     416             : }
     417             : 
     418           0 : double SourceSNRDistribution::getAlpha() const {
     419           0 :         return alpha - 1;  // -1 to account for the R-term in the volume element dV = R * dR * dphi * dz
     420             : }
     421             : 
     422           0 : double SourceSNRDistribution::getBeta() const {
     423           0 :         return beta;
     424             : }
     425             : 
     426           2 : void SourceSNRDistribution::setFrMax() {
     427           2 :         frMax = pow(alpha / beta, alpha) * exp(beta - alpha);
     428           2 :         return;
     429             : }
     430             : 
     431           1 : void SourceSNRDistribution::setFzMax(double zg) {
     432           1 :         fzMax = 1. / zg;
     433           1 :         return;
     434             : }
     435             : 
     436           2 : void SourceSNRDistribution::setRMax(double r) {
     437           2 :         rMax = r;
     438           2 :         return;
     439             : }
     440             : 
     441           1 : void SourceSNRDistribution::setZMax(double z) {
     442           1 :         zMax = z;
     443           1 :         return;
     444             : }
     445             : 
     446           0 : double SourceSNRDistribution::getFrMax() const {
     447           0 :         return frMax;
     448             : }
     449             : 
     450           0 : double SourceSNRDistribution::getFzMax() const {
     451           0 :         return fzMax;
     452             : }
     453             : 
     454           0 : double SourceSNRDistribution::getRMax() const {
     455           0 :         return rMax;
     456             : }
     457             : 
     458           0 : double SourceSNRDistribution::getZMax() const {
     459           0 :         return zMax;
     460             : }
     461             : 
     462           1 : void SourceSNRDistribution::setAlpha(double a) {
     463           1 :         alpha = a + 1.; // add 1 for dV = r * dR * dphi * dz
     464           1 :         setRMax(rMax);
     465           1 :         setFrMax();
     466           1 : }
     467             : 
     468           0 : void SourceSNRDistribution::setBeta(double b) {
     469           0 :         beta = b;
     470           0 :         setRMax(rMax);
     471           0 :         setFrMax();
     472           0 : }
     473             : 
     474           0 : void SourceSNRDistribution::setDescription() {
     475           0 :         std::stringstream ss;
     476           0 :         ss << "SourceSNRDistribution: Random position according to SNR distribution";
     477           0 :         ss << "rEarth = " << rEarth / kpc << " kpc and ";
     478           0 :         ss << "zg = " << zg / kpc << " kpc and";
     479           0 :         ss << "beta = " << beta << " \n";
     480           0 :         description = ss.str();
     481           0 : }
     482             : 
     483             : // ---------------------------------------------------------------------------
     484           0 : SourcePulsarDistribution::SourcePulsarDistribution() :
     485           0 :     rEarth(8.5*kpc), beta(3.53), zg(0.3*kpc) {
     486           0 :         setFrMax(8.5*kpc, 3.53);
     487           0 :         setFzMax(0.3*kpc);
     488           0 :         setRMax(22*kpc);
     489           0 :         setZMax(5*kpc);
     490           0 :         setRBlur(0.07);
     491           0 :         setThetaBlur(0.35/kpc);
     492           0 : }
     493             : 
     494           0 : SourcePulsarDistribution::SourcePulsarDistribution(double rEarth, double beta, double zg, double rB, double tB) :
     495           0 :     rEarth(rEarth), beta(beta), zg(zg) {
     496           0 :         setFrMax(rEarth, beta);
     497           0 :         setFzMax(zg);
     498           0 :         setRBlur(rB);
     499           0 :         setThetaBlur(tB);
     500           0 :         setRMax(22 * kpc);
     501           0 :         setZMax(5 * kpc);
     502           0 : }
     503             : 
     504           0 : void SourcePulsarDistribution::prepareParticle(ParticleState& particle) const {
     505           0 :         Random &random = Random::instance();
     506             :         double Rtilde;
     507             :         while (true) {
     508           0 :                 Rtilde = random.rand() * rMax;
     509           0 :                 double fTest = random.rand() * frMax * 1.1;
     510           0 :                 double fR = fr(Rtilde);
     511           0 :                 if (fTest <= fR) {
     512             :                         break;
     513             :                 }
     514             :         }
     515             :         double ZPos;
     516             :         while (true) {
     517           0 :                 ZPos = (random.rand() - 0.5) * 2 * zMax;
     518           0 :                 double fTest = random.rand() * fzMax;
     519           0 :                 double fZ = fz(ZPos);
     520           0 :                 if (fTest <= fZ) {
     521             :                         break;
     522             :                 }
     523             :         }
     524             : 
     525           0 :         int i = random.randInt(3);
     526           0 :         double thetaTilde = ftheta(i, Rtilde);
     527           0 :         double RPos = blurR(Rtilde);
     528           0 :         double phi = blurTheta(thetaTilde, Rtilde);
     529           0 :         Vector3d pos(cos(phi) * RPos, sin(phi) * RPos, ZPos);
     530             : 
     531           0 :         particle.setPosition(pos);
     532           0 :   }
     533             : 
     534           0 : double SourcePulsarDistribution::fr(double r) const {
     535           0 :         double f = r * pow(r / rEarth, 2.) * exp(-beta * (r - rEarth) / rEarth);
     536           0 :         return f;
     537             : }
     538             : 
     539           0 : double SourcePulsarDistribution::fz(double z) const{
     540             :         double Az = 1.;
     541           0 :         double f = 1. / zg * exp(- fabs(z) / zg);
     542             :         double fz = Az * f;
     543           0 :         return fz;
     544             : }
     545             : 
     546           0 : double SourcePulsarDistribution::ftheta(int i, double r) const {
     547           0 :         const double k_0[] = {4.25, 4.25, 4.89, 4.89};
     548           0 :         const double r_0[] = {3.48 * kpc, 3.48 * kpc, 4.9 * kpc, 4.9 * kpc};
     549           0 :         const double theta_0[] = {0., 3.14, 2.52, -0.62};
     550           0 :         double K = k_0[i];
     551           0 :         double R = r_0[i];
     552           0 :         double Theta = theta_0[i];
     553             : 
     554           0 :         double theta = K * log(r / R) + Theta;
     555             : 
     556           0 :         return theta;
     557             : }
     558             : 
     559           0 : double SourcePulsarDistribution::blurR(double rTilde) const {
     560           0 :         Random &random = Random::instance();
     561           0 :         return random.randNorm(rTilde, rBlur * rTilde);
     562             : }
     563             : 
     564           0 : double SourcePulsarDistribution::blurTheta(double thetaTilde, double rTilde) const {
     565           0 :         Random &random = Random::instance();
     566           0 :         double thetaCorr = (random.rand() - 0.5) * 2 * M_PI;
     567           0 :         double tau = thetaCorr * exp(- thetaBlur * rTilde);
     568           0 :         return thetaTilde + tau;
     569             : }
     570             : 
     571           0 : void SourcePulsarDistribution::setFrMax(double R, double b) {
     572           0 :         double r = 3 * R / b;
     573           0 :         frMax = fr(r);
     574           0 : }
     575             : 
     576           0 : void SourcePulsarDistribution::setFzMax(double zg) {
     577           0 :         fzMax = 1. / zg;
     578           0 :         return;
     579             : }
     580             : 
     581           0 : void SourcePulsarDistribution::setRMax(double r) {
     582           0 :         rMax = r;
     583           0 :         return;
     584             : }
     585             : 
     586           0 : void SourcePulsarDistribution::setZMax(double z) {
     587           0 :         zMax = z;
     588           0 :         return;
     589             : }
     590             : 
     591           0 : void SourcePulsarDistribution::setRBlur(double r) {
     592           0 :         rBlur = r;
     593           0 :         return;
     594             : }
     595             : 
     596           0 : void SourcePulsarDistribution::setThetaBlur(double theta) {
     597           0 :         thetaBlur = theta;
     598           0 :         return;
     599             : }
     600             : 
     601           0 : double SourcePulsarDistribution::getFrMax() {
     602           0 :         return frMax;
     603             : }
     604             : 
     605           0 : double SourcePulsarDistribution::getFzMax() {
     606           0 :         return fzMax;
     607             : }
     608             : 
     609           0 : double SourcePulsarDistribution::getRMax() {
     610           0 :         return rMax;
     611             : }
     612             : 
     613           0 : double SourcePulsarDistribution::getZMax() {
     614           0 :         return zMax;
     615             : }
     616             : 
     617           0 : double SourcePulsarDistribution::getRBlur() {
     618           0 :         return rBlur;
     619             : }
     620             : 
     621           0 : double SourcePulsarDistribution::getThetaBlur() {
     622           0 :         return thetaBlur;
     623             : }
     624             : 
     625             : 
     626           0 : void SourcePulsarDistribution::setDescription() {
     627           0 :         std::stringstream ss;
     628           0 :         ss << "SourcePulsarDistribution: Random position according to pulsar distribution";
     629           0 :         ss << "rEarth = " << rEarth / kpc << " kpc and ";
     630           0 :         ss << "zg = " << zg / kpc << " kpc and ";
     631           0 :         ss << "beta = " << beta << " and ";
     632           0 :         ss << "r_blur = " << rBlur << " and ";
     633           0 :         ss << "theta blur = " << thetaBlur << "\n";
     634           0 :         description = ss.str();
     635           0 : }
     636             : 
     637             : // ----------------------------------------------------------------------------
     638           1 : SourceUniform1D::SourceUniform1D(double minD, double maxD, bool withCosmology) {
     639           1 :         this->withCosmology = withCosmology;
     640           1 :         if (withCosmology) {
     641           1 :                 this->minD = comoving2LightTravelDistance(minD);
     642           1 :                 this->maxD = comoving2LightTravelDistance(maxD);
     643             :         } else {
     644           0 :                 this->minD = minD;
     645           0 :                 this->maxD = maxD;
     646             :         }
     647           1 :         setDescription();
     648           1 : }
     649             : 
     650           1 : void SourceUniform1D::prepareParticle(ParticleState& particle) const {
     651           1 :         Random& random = Random::instance();
     652           1 :         double d = random.rand() * (maxD - minD) + minD;
     653           1 :         if (withCosmology)
     654           1 :                 d = lightTravel2ComovingDistance(d);
     655           1 :         particle.setPosition(Vector3d(d, 0, 0));
     656           1 : }
     657             : 
     658           1 : void SourceUniform1D::setDescription() {
     659           1 :         std::stringstream ss;
     660           1 :         ss << "SourceUniform1D: Random uniform position in D = ";
     661           2 :         ss << minD / Mpc << " - " << maxD / Mpc << " Mpc";
     662           1 :         if (withCosmology)
     663           1 :                 ss << " (including cosmology)";
     664           1 :         ss << "\n";
     665           1 :         description = ss.str();
     666           1 : }
     667             : 
     668             : // ----------------------------------------------------------------------------
     669           2 : SourceDensityGrid::SourceDensityGrid(ref_ptr<Grid1f> grid) :
     670           2 :                 grid(grid) {
     671             :         float sum = 0;
     672          14 :         for (int ix = 0; ix < grid->getNx(); ix++) {
     673         116 :                 for (int iy = 0; iy < grid->getNy(); iy++) {
     674        1112 :                         for (int iz = 0; iz < grid->getNz(); iz++) {
     675        1008 :                                 sum += grid->get(ix, iy, iz);
     676        1008 :                                 grid->get(ix, iy, iz) = sum;
     677             :                         }
     678             :                 }
     679             :         }
     680           2 :         setDescription();
     681           2 : }
     682             : 
     683       10001 : void SourceDensityGrid::prepareParticle(ParticleState& particle) const {
     684       10001 :         Random &random = Random::instance();
     685             : 
     686             :         // draw random bin
     687       10001 :         size_t i = random.randBin(grid->getGrid());
     688       10001 :         Vector3d pos = grid->positionFromIndex(i);
     689             : 
     690             :         // draw uniform position within bin
     691       10001 :         double dx = random.rand() - 0.5;
     692       10001 :         double dy = random.rand() - 0.5;
     693       10001 :         double dz = random.rand() - 0.5;
     694             :         pos += Vector3d(dx, dy, dz) * grid->getSpacing();
     695             : 
     696       10001 :         particle.setPosition(pos);
     697       10001 : }
     698             : 
     699           2 : void SourceDensityGrid::setDescription() {
     700           2 :         description = "SourceDensityGrid: 3D source distribution according to density grid\n";
     701           2 : }
     702             : 
     703             : // ----------------------------------------------------------------------------
     704           2 : SourceDensityGrid1D::SourceDensityGrid1D(ref_ptr<Grid1f> grid) :
     705           2 :                 grid(grid) {
     706           2 :         if (grid->getNy() != 1)
     707           0 :                 throw std::runtime_error("SourceDensityGrid1D: Ny != 1");
     708           2 :         if (grid->getNz() != 1)
     709           0 :                 throw std::runtime_error("SourceDensityGrid1D: Nz != 1");
     710             : 
     711             :         float sum = 0;
     712          22 :         for (int ix = 0; ix < grid->getNx(); ix++) {
     713          20 :                 sum += grid->get(ix, 0, 0);
     714          20 :                 grid->get(ix, 0, 0) = sum;
     715             :         }
     716           2 :         setDescription();
     717           2 : }
     718             : 
     719         101 : void SourceDensityGrid1D::prepareParticle(ParticleState& particle) const {
     720         101 :         Random &random = Random::instance();
     721             : 
     722             :         // draw random bin
     723         101 :         size_t i = random.randBin(grid->getGrid());
     724         101 :         Vector3d pos = grid->positionFromIndex(i);
     725             : 
     726             :         // draw uniform position within bin
     727         101 :         double dx = random.rand() - 0.5;
     728         101 :         pos.x += dx * grid->getSpacing().x;
     729             : 
     730         101 :         particle.setPosition(pos);
     731         101 : }
     732             : 
     733           2 : void SourceDensityGrid1D::setDescription() {
     734           2 :         description = "SourceDensityGrid1D: 1D source distribution according to density grid\n";
     735           2 : }
     736             : 
     737             : // ----------------------------------------------------------------------------
     738           3 : SourceIsotropicEmission::SourceIsotropicEmission() {
     739           3 :         setDescription();
     740           3 : }
     741             : 
     742        1101 : void SourceIsotropicEmission::prepareParticle(ParticleState& particle) const {
     743        1101 :         Random &random = Random::instance();
     744        1101 :         particle.setDirection(random.randVector());
     745        1101 : }
     746             : 
     747           3 : void SourceIsotropicEmission::setDescription() {
     748           3 :         description = "SourceIsotropicEmission: Random isotropic direction\n";
     749           3 : }
     750             : 
     751             : // ----------------------------------------------------------------------------
     752           1 : SourceDirectedEmission::SourceDirectedEmission(Vector3d mu, double kappa): mu(mu), kappa(kappa) {
     753           1 :         if (kappa <= 0)
     754           0 :                 throw std::runtime_error("The concentration parameter kappa should be larger than 0.");
     755           1 :         setDescription();
     756           1 : }
     757             : 
     758        1000 : void SourceDirectedEmission::prepareCandidate(Candidate &candidate) const {
     759        1000 :         Random &random = Random::instance();
     760             : 
     761             :         Vector3d muvec = mu / mu.getR();
     762        1000 :         Vector3d v = random.randFisherVector(muvec, kappa);
     763             : 
     764        1000 :         v = v.getUnitVector();
     765        1000 :         candidate.source.setDirection(v);
     766        1000 :         candidate.created.setDirection(v);
     767        1000 :         candidate.previous.setDirection(v);
     768        1000 :         candidate.current.setDirection(v);
     769             : 
     770             :         //set the weight of the particle, see eq. 3.1 of PoS(ICRC2019)447
     771        1000 :         double pdfVonMises = kappa / (2. * M_PI * (1. - exp(-2. * kappa))) * exp(-kappa * (1. - v.dot(mu)));
     772        1000 :         double weight = 1. / (4. * M_PI * pdfVonMises);
     773        1000 :         candidate.setWeight(weight);
     774        1000 : }
     775             : 
     776           1 : void SourceDirectedEmission::setDescription() {
     777           1 :         std::stringstream ss;
     778           1 :         ss << "SourceDirectedEmission: Random directed emission following the von-Mises-Fisher distribution with mean direction ";
     779           1 :         ss << mu << " and concentration parameter kappa = ";
     780           1 :         ss << kappa << "\n";
     781           1 :         description = ss.str();
     782           1 : }
     783             : 
     784             : // ----------------------------------------------------------------------------
     785           0 : SourceLambertDistributionOnSphere::SourceLambertDistributionOnSphere(const Vector3d &center, double radius, bool inward) :
     786           0 :                 center(center), radius(radius) {
     787           0 :         this->inward = inward;
     788           0 :         setDescription();
     789           0 : }
     790             : 
     791           0 : void SourceLambertDistributionOnSphere::prepareParticle(ParticleState& particle) const {
     792           0 :         Random &random = Random::instance();
     793           0 :         Vector3d normalVector = random.randVector();
     794           0 :         particle.setPosition(center + normalVector * radius);
     795           0 :         double sign = inward ? -1 : 1; // negative (positive) Lamberts vector for inward (outward) directed emission
     796           0 :         particle.setDirection(Vector3d(0, 0, 0) + sign * random.randVectorLamberts(normalVector));
     797           0 : }
     798             : 
     799           0 : void SourceLambertDistributionOnSphere::setDescription() {
     800           0 :         std::stringstream ss;
     801           0 :         ss << "SourceLambertDistributionOnSphere: Random position and direction on a Sphere with center ";
     802           0 :         ss << center / kpc << " kpc and ";
     803           0 :         ss << radius / kpc << " kpc radius\n";
     804           0 :         description = ss.str();
     805           0 : }
     806             : 
     807             : // ----------------------------------------------------------------------------
     808           0 : SourceDirection::SourceDirection(Vector3d direction) :
     809           0 :                 direction(direction) {
     810           0 :         setDescription();
     811           0 : }
     812             : 
     813           0 : void SourceDirection::prepareParticle(ParticleState& particle) const {
     814           0 :         particle.setDirection(direction);
     815           0 : }
     816             : 
     817           0 : void SourceDirection::setDescription() {
     818           0 :         std::stringstream ss;
     819           0 :         ss <<  "SourceDirection: Emission direction = " << direction << "\n";
     820           0 :         description = ss.str();
     821           0 : }
     822             : 
     823             : // ----------------------------------------------------------------------------
     824           0 : SourceEmissionMap::SourceEmissionMap(EmissionMap *emissionMap) : emissionMap(emissionMap) {
     825           0 :         setDescription();
     826           0 : }
     827             : 
     828           0 : void SourceEmissionMap::prepareCandidate(Candidate &candidate) const {
     829           0 :         if (emissionMap) {
     830           0 :                 bool accept = emissionMap->checkDirection(candidate.source);
     831           0 :                 candidate.setActive(accept);
     832             :         }
     833           0 : }
     834             : 
     835           0 : void SourceEmissionMap::setDescription() {
     836           0 :         description = "SourceEmissionMap: accept only directions from emission map\n";
     837           0 : }
     838             : 
     839           0 : void SourceEmissionMap::setEmissionMap(EmissionMap *emissionMap) {
     840           0 :         this->emissionMap = emissionMap;
     841           0 : }
     842             : 
     843             : // ----------------------------------------------------------------------------
     844           1 : SourceEmissionCone::SourceEmissionCone(Vector3d direction, double aperture) :
     845           1 :         aperture(aperture) {
     846           1 :         setDirection(direction);
     847           1 :         setDescription();
     848             :         
     849           1 : }
     850             : 
     851           1 : void SourceEmissionCone::prepareParticle(ParticleState& particle) const {
     852           1 :         Random &random = Random::instance();
     853           1 :         particle.setDirection(random.randConeVector(direction, aperture));
     854           1 : }
     855             : 
     856           1 : void SourceEmissionCone::setDirection(Vector3d dir) {
     857           1 :         if (dir.getR() == 0) {
     858           0 :                 throw std::runtime_error("SourceEmissionCone: The direction vector was a null vector.");
     859             :         } else {
     860           1 :                 direction = dir.getUnitVector();
     861             :         }
     862           1 : }
     863             : 
     864           1 : void SourceEmissionCone::setDescription() {
     865           1 :         std::stringstream ss;
     866           1 :         ss << "SourceEmissionCone: Jetted emission in ";
     867           1 :         ss << "direction = " << direction << " with ";
     868           1 :         ss << "half-opening angle = " << aperture << " rad\n";
     869           1 :         description = ss.str();
     870           1 : }
     871             : 
     872             : // ----------------------------------------------------------------------------
     873           1 : SourceRedshift::SourceRedshift(double z) :
     874           1 :                 z(z) {
     875           1 :         setDescription();
     876           1 : }
     877             : 
     878           1 : void SourceRedshift::prepareCandidate(Candidate& candidate) const {
     879           1 :         candidate.setRedshift(z);
     880           1 : }
     881             : 
     882           1 : void SourceRedshift::setDescription() {
     883           1 :         std::stringstream ss;
     884           1 :         ss << "SourceRedshift: Redshift z = " << z << "\n";
     885           1 :         description = ss.str();
     886           1 : }
     887             : 
     888             : // ----------------------------------------------------------------------------
     889           0 : SourceUniformRedshift::SourceUniformRedshift(double zmin, double zmax) :
     890           0 :                 zmin(zmin), zmax(zmax) {
     891           0 :         setDescription();
     892           0 : }
     893             : 
     894           0 : void SourceUniformRedshift::prepareCandidate(Candidate& candidate) const {
     895           0 :         double z = Random::instance().randUniform(zmin, zmax);
     896           0 :         candidate.setRedshift(z);
     897           0 : }
     898             : 
     899           0 : void SourceUniformRedshift::setDescription() {
     900           0 :         std::stringstream ss;
     901           0 :         ss << "SourceUniformRedshift: Uniform redshift in z = ";
     902           0 :         ss << zmin << " - " << zmax << "\n";
     903           0 :         description = ss.str();
     904           0 : }
     905             : 
     906             : // ----------------------------------------------------------------------------
     907           2 : SourceRedshiftEvolution::SourceRedshiftEvolution(double m, double zmin, double zmax) : m(m), zmin(zmin), zmax(zmax) {
     908           2 :         std::stringstream ss;
     909             :         ss << "SourceRedshiftEvolution: (1+z)^m, m = " << m;
     910           2 :         ss << ", z = " << zmin << " - " << zmax << "\n";
     911           2 :         description = ss.str();
     912           2 : }
     913             : 
     914         200 : void SourceRedshiftEvolution::prepareCandidate(Candidate& candidate) const {
     915         200 :         double x = Random::instance().randUniform(0, 1);
     916             :         double norm, z;
     917             : 
     918             :         // special case: m=-1
     919         200 :         if ((std::abs(m+1)) < std::numeric_limits<double>::epsilon()) {
     920         100 :                 norm = log1p(zmax) - log1p(zmin);
     921         100 :                 z = exp(norm*x) * (1+zmin) - 1;
     922             :         } else {
     923         100 :                 norm = ( pow(1+zmax, m+1) - pow(1+zmin, m+1) ) / (m+1);
     924         100 :                 z = pow( norm*(m+1)*x + pow(1+zmin, m+1), 1./(m+1)) - 1;
     925             :         }
     926         200 :         candidate.setRedshift(z);
     927         200 : }
     928             : 
     929             : // ----------------------------------------------------------------------------
     930           1 : SourceRedshift1D::SourceRedshift1D() {
     931           1 :         setDescription();
     932           1 : }
     933             : 
     934           1 : void SourceRedshift1D::prepareCandidate(Candidate& candidate) const {
     935           1 :         double d = candidate.source.getPosition().getR();
     936           1 :         double z = comovingDistance2Redshift(d);
     937           1 :         candidate.setRedshift(z);
     938           1 : }
     939             : 
     940           1 : void SourceRedshift1D::setDescription() {
     941           1 :         description = "SourceRedshift1D: Redshift according to source distance\n";
     942           1 : }
     943             : 
     944             : // ----------------------------------------------------------------------------
     945             : #ifdef CRPROPA_HAVE_MUPARSER
     946           1 : SourceGenericComposition::SourceGenericComposition(double Emin, double Emax, std::string expression, size_t bins) :
     947           2 :         Emin(Emin), Emax(Emax), expression(expression), bins(bins) {
     948             : 
     949             :         // precalculate energy bins
     950           1 :         double logEmin = ::log10(Emin);
     951           1 :         double logEmax = ::log10(Emax);
     952           1 :         double logStep = (logEmax - logEmin) / bins;
     953           1 :         energy.resize(bins + 1);
     954        1026 :         for (size_t i = 0; i <= bins; i++) {
     955        1025 :                 energy[i] = ::pow(10, logEmin + i * logStep);
     956             :         }
     957           1 :         setDescription();
     958           1 : }
     959             : 
     960           2 : void SourceGenericComposition::add(int id, double weight) {
     961           2 :         int A = massNumber(id);
     962           2 :         int Z = chargeNumber(id);
     963             : 
     964             :         Nucleus n;
     965           2 :         n.id = id;
     966             : 
     967             :         // calculate nuclei cdf
     968           2 :         mu::Parser p;
     969             :         double E;
     970           2 :         p.DefineVar("E", &E);
     971           2 :         p.DefineConst("Emin", Emin);
     972           2 :         p.DefineConst("Emax", Emax);
     973           2 :         p.DefineConst("bins", bins);
     974           2 :         p.DefineConst("A", (double)A);
     975           2 :         p.DefineConst("Z", (double)Z);
     976             : 
     977           2 :         p.DefineConst("MeV", MeV);
     978           2 :         p.DefineConst("GeV", GeV);
     979           2 :         p.DefineConst("TeV", TeV);
     980           2 :         p.DefineConst("PeV", PeV);
     981           2 :         p.DefineConst("EeV", EeV);
     982             : 
     983           2 :         p.SetExpr(expression);
     984             : 
     985             :         // calculate pdf
     986           2 :         n.cdf.resize(bins + 1);
     987             : 
     988        2052 :         for (std::size_t i=0; i<=bins; ++i) {
     989        2050 :                 E = energy[i];
     990        2050 :                 n.cdf[i] = p.Eval();
     991             :         }
     992             : 
     993             :         // integrate
     994        2050 :         for (std::size_t i=bins; i>0; --i) {
     995        2048 :                 n.cdf[i] = (n.cdf[i-1] + n.cdf[i]) * (energy[i] - energy[i-1]) / 2;
     996             :         }
     997           2 :         n.cdf[0] = 0;
     998             : 
     999             :         // cumulate
    1000        2050 :         for (std::size_t i=1; i<=bins; ++i) {
    1001        2048 :                 n.cdf[i] += n.cdf[i-1];
    1002             :         }
    1003             : 
    1004           2 :         nuclei.push_back(n);
    1005             : 
    1006             :         // update composition cdf
    1007           2 :         if (cdf.size() == 0)
    1008           1 :                 cdf.push_back(weight * n.cdf.back());
    1009             :         else
    1010           1 :                 cdf.push_back(cdf.back() + weight * n.cdf.back());
    1011           2 : }
    1012             : 
    1013           0 : void SourceGenericComposition::add(int A, int Z, double a) {
    1014           0 :         add(nucleusId(A, Z), a);
    1015           0 : }
    1016             : 
    1017      100000 : void SourceGenericComposition::prepareParticle(ParticleState& particle) const {
    1018      100000 :         if (nuclei.size() == 0)
    1019           0 :                 throw std::runtime_error("SourceComposition: No source isotope set");
    1020             : 
    1021      100000 :         Random &random = Random::instance();
    1022             : 
    1023             : 
    1024             :         // draw random particle type
    1025      100000 :         size_t iN = random.randBin(cdf);
    1026             :         const Nucleus &n = nuclei.at(iN);
    1027      100000 :         particle.setId(n.id);
    1028             : 
    1029             :         // random energy
    1030      100000 :         double E = interpolate(random.rand() * n.cdf.back(), n.cdf, energy);
    1031      100000 :         particle.setEnergy(E);
    1032      100000 : }
    1033             : 
    1034           1 : void SourceGenericComposition::setDescription() {
    1035           1 :         description = "Generice source composition" + expression;
    1036           1 : }
    1037             : 
    1038             : #endif
    1039             : 
    1040             : // ----------------------------------------------------------------------------
    1041             : 
    1042           1 : SourceTag::SourceTag(std::string tag) {
    1043           1 :         setTag(tag);
    1044           1 : }
    1045             : 
    1046           1 : void SourceTag::prepareCandidate(Candidate &cand) const {
    1047           1 :         cand.setTagOrigin(sourceTag);
    1048           1 : }
    1049             : 
    1050           1 : void SourceTag::setDescription() {
    1051           1 :         description = "SourceTag: " + sourceTag;
    1052           1 : }
    1053             : 
    1054           1 : void SourceTag::setTag(std::string tag) {
    1055           1 :         sourceTag = tag;
    1056           1 :         setDescription();
    1057           1 : }
    1058             : 
    1059             : // ----------------------------------------------------------------------------
    1060             : 
    1061           0 : SourceMassDistribution::SourceMassDistribution(ref_ptr<Density> density, double max, double x, double y, double z) : 
    1062           0 :         density(density), maxDensity(max), xMin(-x), xMax(x), yMin(-y), yMax(y), zMin(-z), zMax(z) {}
    1063             : 
    1064           0 : void SourceMassDistribution::setMaximalDensity(double maxDensity) {
    1065           0 :         if (maxDensity <= 0) {
    1066           0 :                 KISS_LOG_WARNING << "SourceMassDistribution: maximal density must be larger than 0. Nothing changed.\n";
    1067           0 :                 return;
    1068             :         }
    1069           0 :         this->maxDensity = maxDensity;
    1070             : }
    1071             : 
    1072           0 : void SourceMassDistribution::setXrange(double xMin, double xMax) {
    1073           0 :         if (xMin > xMax) {
    1074           0 :                 KISS_LOG_WARNING << "SourceMassDistribution: minimal x-value must not exceed the maximal one\n";
    1075           0 :                 return;
    1076             :         }
    1077           0 :         this -> xMin = xMin;
    1078           0 :         this -> xMax = xMax;
    1079             : }
    1080             : 
    1081           0 : void SourceMassDistribution::setYrange(double yMin, double yMax) {
    1082           0 :         if (yMin > yMax) {
    1083           0 :                 KISS_LOG_WARNING << "SourceMassDistribution: minimal y-value must not exceed the maximal one\n";
    1084           0 :                 return;
    1085             :         }
    1086           0 :         this -> yMin = yMin;
    1087           0 :         this -> yMax = yMax;
    1088             : }
    1089             : 
    1090           0 : void SourceMassDistribution::setZrange(double zMin, double zMax) {
    1091           0 :         if (zMin > zMax) {
    1092           0 :                 KISS_LOG_WARNING << "SourceMassDistribution: minimal z-value must not exceed the maximal one\n";
    1093           0 :                 return;
    1094             :         }
    1095           0 :         this -> zMin = zMin;
    1096           0 :         this -> zMax = zMax;
    1097             : }
    1098             : 
    1099           0 : Vector3d SourceMassDistribution::samplePosition() const {
    1100             :         Vector3d pos; 
    1101           0 :         Random &rand = Random::instance();
    1102             : 
    1103           0 :         for (int i = 0; i < maxTries; i++) {
    1104           0 :                 pos.x = rand.randUniform(xMin, xMax);
    1105           0 :                 pos.y = rand.randUniform(yMin, yMax);
    1106           0 :                 pos.z = rand.randUniform(zMin, zMax);
    1107             : 
    1108           0 :                 double n_density = density->getDensity(pos) / maxDensity;
    1109           0 :                 double n_test = rand.rand();
    1110           0 :                 if (n_test < n_density) {
    1111             :                         return pos;
    1112             :                 }
    1113             :         }
    1114           0 :         KISS_LOG_WARNING << "SourceMassDistribution: sampling a position was not possible within " 
    1115           0 :                 << maxTries << " tries. Please check the maximum density or increse the number of maximal tries. \n";
    1116             :         return Vector3d(0.);
    1117             : }       
    1118             : 
    1119           0 : void SourceMassDistribution::prepareParticle(ParticleState &state) const {
    1120           0 :         Vector3d pos = samplePosition();
    1121           0 :         state.setPosition(pos);
    1122           0 : }
    1123             : 
    1124           0 : void SourceMassDistribution::setMaximalTries(int tries) {
    1125           0 :         this -> maxTries = tries;
    1126           0 : }
    1127             : 
    1128           0 : std::string SourceMassDistribution::getDescription() {
    1129           0 :         std::stringstream ss;
    1130           0 :         ss << "SourceMassDistribuion: following the density distribution :\n";
    1131           0 :         ss << "\t" << density -> getDescription();
    1132           0 :         ss << "with a maximal density of " << maxDensity << " / m^3 \n";
    1133           0 :         ss << "using the sampling range: \n";
    1134           0 :         ss << "\t x in [" << xMin / kpc << " ; " << xMax / kpc << "] kpc \n";
    1135           0 :         ss << "\t y in [" << yMin / kpc << " ; " << yMax / kpc << "] kpc \n";
    1136           0 :         ss << "\t z in [" << zMin / kpc << " ; " << zMax / kpc << "] kpc \n";
    1137           0 :         ss << "with maximal number of tries for sampling of " << maxTries << "\n";
    1138             : 
    1139           0 :         return ss.str();
    1140           0 : }
    1141             : 
    1142             : } // namespace crpropa

Generated by: LCOV version 1.14