Version: SMASH-1.8
pauliblocking.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2014-2019
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
10 #include "smash/pauliblocking.h"
11 #include "smash/constants.h"
12 #include "smash/logging.h"
13 
14 namespace smash {
15 static constexpr int LPauliBlocking = LogArea::PauliBlocking::id;
16 
18  const ExperimentParameters &param)
19  : sig_(param.gaussian_sigma),
20  rc_(conf.take({"Gaussian_Cutoff"}, 2.2)),
21  rr_(conf.take({"Spatial_Averaging_Radius"}, 1.86)),
22  rp_(conf.take({"Momentum_Averaging_Radius"}, 0.08)),
23  ntest_(param.testparticles) {
37  if (ntest_ < 20) {
38  logg[LPauliBlocking].warn(
39  "Phase-space density calculation in Pauli blocking"
40  " will not work reasonably for a small number of testparticles."
41  " The recommended number of testparticles is 20.");
42  }
43 
44  if (rc_ < rr_ || rr_ < 0.0 || rp_ < 0) {
45  logg[LPauliBlocking].error(
46  "Please choose reasonable parameters for Pauli blocking:"
47  "All radii have to be positive and Gaussian_Cutoff should"
48  "be larger than Spatial_Averaging_Radius");
49  }
50 
51  init_weights_analytical();
52 }
53 
54 PauliBlocker::~PauliBlocker() {}
55 
56 double PauliBlocker::phasespace_dens(const ThreeVector &r, const ThreeVector &p,
57  const Particles &particles,
58  const PdgCode pdg,
59  const ParticleList &disregard) const {
60  double f = 0.0;
61 
62  /* TODO(oliiny): looping over all particles is inefficient,
63  * I need only particles within rp_ radius in momentum and
64  * within rr_+rc_ in coordinate space. Some search algorithm might help. */
65  for (const auto &part : particles) {
66  // Only consider identical particles
67  if (part.pdgcode() != pdg) {
68  continue;
69  }
70  // Only consider momenta in sphere of radius rp_ with center at p
71  const double pdist_sqr = (part.momentum().threevec() - p).sqr();
72  if (pdist_sqr > rp_ * rp_) {
73  continue;
74  }
75  const double rdist_sqr = (part.position().threevec() - r).sqr();
76  // Only consider coordinates in sphere of radius rr_+rc_ with center at r
77  if (rdist_sqr >= (rr_ + rc_) * (rr_ + rc_)) {
78  continue;
79  }
80  // Do not count particles that should be disregarded.
81  bool to_disregard = false;
82  for (const auto &disregard_part : disregard) {
83  if (part.id() == disregard_part.id()) {
84  to_disregard = true;
85  }
86  }
87  if (to_disregard) {
88  continue;
89  }
90  // 1st order interpolation using tabulated values
91  const double i_real = std::sqrt(rdist_sqr) / (rr_ + rc_) * weights_.size();
92  const size_t i = std::floor(i_real);
93  const double rest = i_real - i;
94  if (likely(i + 1 < weights_.size())) {
95  f += weights_[i] * rest + weights_[i + 1] * (1. - rest);
96  }
97  }
98  return f / ntest_;
99 }
100 
101 void PauliBlocker::init_weights_analytical() {
102  const double pi = M_PI;
103  const double sqrt2 = std::sqrt(2.);
104  const double sqrt_2pi = std::sqrt(2. * pi);
105  // Volume of the phase-space area; Factor 2 stands for spin.
106  const double phase_volume =
107  2 * (4. / 3. * pi * rr_ * rr_ * rr_) * (4. / 3. * pi * rp_ * rp_ * rp_) /
108  ((2 * pi * hbarc) * (2 * pi * hbarc) * (2 * pi * hbarc));
109  // Analytical expression for integral in denominator
110  const double norm =
111  std::erf(rc_ / sqrt2 / sig_) -
112  rc_ * 2 / sqrt_2pi / sig_ * std::exp(-0.5 * rc_ * rc_ / sig_ / sig_);
113 
114  double integral;
115  // Step of the table for tabulated integral
116  const double d_pos = (rr_ + rc_) / static_cast<double>(weights_.size());
117 
118  for (size_t k = 0; k < weights_.size(); k++) {
119  // rdist = 0 ... rc_ (gauss cut) + rr_ (position cut)
120  const double rj = d_pos * k;
121  if (rj < really_small) {
122  // Assuming rc_ > rr_
123  const double A = rr_ / sqrt2 / sig_;
124  integral = sqrt_2pi * sig_ * std::erf(A) - 2 * rr_ * std::exp(-A * A);
125  integral *= sig_ * sig_;
126  } else if (rc_ > rj + rr_) {
127  const double A = (rj + rr_) / sqrt2 / sig_;
128  const double B = (rj - rr_) / sqrt2 / sig_;
129  integral = sig_ / rj * (std::exp(-A * A) - std::exp(-B * B)) +
130  0.5 * sqrt_2pi * (std::erf(A) - std::erf(B));
131  integral *= sig_ * sig_ * sig_;
132  } else {
133  const double A = rc_ / sqrt2 / sig_;
134  const double B = (rj - rr_) / sqrt2 / sig_;
135  const double C = (rc_ - rj) * (rc_ - rj) - rr_ * rr_ + 2 * sig_ * sig_;
136  integral =
137  (0.5 * std::exp(-A * A) * C - sig_ * sig_ * std::exp(-B * B)) / rj +
138  0.5 * sqrt_2pi * sig_ * (std::erf(A) - std::erf(B));
139  integral *= sig_ * sig_;
140  }
141  integral *= 2 * pi / std::pow(2 * pi * sig_ * sig_, 1.5);
142  weights_[k] = integral / norm / phase_volume;
143  logg[LPauliBlocking].debug("Analytical weights[", k, "] = ", weights_[k]);
144  }
145 }
146 
147 } // namespace smash
smash
Definition: action.h:24
smash::LPauliBlocking
static constexpr int LPauliBlocking
Definition: action.cc:28
smash::hbarc
constexpr double hbarc
GeV <-> fm conversion factor.
Definition: constants.h:25
smash::logg
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
Definition: logging.cc:39
smash::really_small
constexpr double really_small
Numerical error tolerance.
Definition: constants.h:37
pauliblocking.h
smash::Configuration
Interface to the SMASH configuration files.
Definition: configuration.h:464
smash::ThreeVector
Definition: threevector.h:31
smash::PdgCode
Definition: pdgcode.h:108
smash::Particles
Definition: particles.h:33
smash::PauliBlocker::PauliBlocker
PauliBlocker(Configuration conf, const ExperimentParameters &parameters)
PauliBlocker constructor.
constants.h
logging.h
smash::ExperimentParameters
Helper structure for Experiment.
Definition: experimentparameters.h:23
likely
#define likely(x)
Tell the branch predictor that this expression is likely true.
Definition: macros.h:14
smash::pdg::p
constexpr int p
Proton.
Definition: pdgcode_constants.h:28