Version: SMASH-3.4
density.h
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2014-2022,2024,2026
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 #ifndef SRC_INCLUDE_SMASH_DENSITY_H_
10 #define SRC_INCLUDE_SMASH_DENSITY_H_
11 
12 #include <iostream>
13 #include <tuple>
14 #include <typeinfo>
15 #include <utility>
16 #include <vector>
17 
18 #include "energymomentumtensor.h"
19 #include "experimentparameters.h"
20 #include "forwarddeclarations.h"
21 #include "fourvector.h"
22 #include "lattice.h"
23 #include "particledata.h"
24 #include "particles.h"
25 #include "pdgcode.h"
26 #include "threevector.h"
27 
28 namespace smash {
29 static constexpr int LDensity = LogArea::Density::id;
30 
31 /**
32  * Create the output operator for the densities
33  *
34  * \param[out] os Output operator for the densities
35  * \param[in] dt Type of density (e.g. baryon density)
36  * \return An output operator for the densities
37  */
38 std::ostream &operator<<(std::ostream &os, DensityType dt);
39 
40 /**
41  * Get the factor that determines how much a particle contributes to the
42  * density type that is computed. E.g. positive pion contributes with
43  * factor 1 to total particle density and with factor 0 to baryon density.
44  * Proton contributes with factor 1 to baryon density, anti-proton - with
45  * factor -1 to baryon density, and so on.
46  *
47  * \param[in] type type of the particle to be tested
48  * \param[in] dens_type The density type
49  * \return The corresponding factor (0 if the particle doesn't
50  * contribute at all).
51  */
52 double density_factor(const ParticleType &type, DensityType dens_type);
53 
54 /**
55  * Norm of the Gaussian smearing function
56  *
57  * \param[in] two_sigma_sqr \f$2 \sigma^2 \f$ [fm\f$^2\f$],
58  * \f$ \sigma \f$ - width of gaussian smearing
59  * \return \f$ (2 \pi \sigma^2)^{3/2}\f$ [fm\f$^3\f$]
60  */
61 inline double smearing_factor_norm(const double two_sigma_sqr) {
62  const double tmp = two_sigma_sqr * M_PI;
63  return tmp * std::sqrt(tmp);
64 }
65 
66 /**
67  * Gaussians used for smearing are cut at radius \f$r_{cut} = a \sigma \f$
68  * for calculation speed-up. In the limit of \f$a \to \infty \f$ smearing
69  * factor is normalized to 1:
70  * \f[ \frac{4 \pi}{(2 \pi \sigma^2)^{3/2}}
71  * \int_0^{\infty} e^{-r^2/2 \sigma^2} r^2 dr = 1 \f]
72  * However, for finite \f$ a\f$ integral is less than one:
73  * \f[ g(a) \equiv \frac{4 \pi}{(2 \pi \sigma^2)^{3/2}}
74  * \int_0^{a \sigma} e^{-r^2/2 \sigma^2} r^2 dr =
75  * -\sqrt{\frac{2}{\pi}} a e^{-a^2/2} + Erf[a/\sqrt{2}]
76  * \f] This \f$ g(a) \f$ is typically close to 1. For example,
77  * for \f$r_{cut} = 3 \sigma \f$, and thus \f$ a=3 \f$, g(3) = 0.9707;
78  * g(4) = 0.9987. The aim of this function is to compensate for this factor.
79  *
80  * \param[in] rcut_in_sigma \f$ a = r_{cut} / \sigma\f$
81  * \return \f$ g(a) \f$
82  */
83 inline double smearing_factor_rcut_correction(const double rcut_in_sigma) {
84  const double x = rcut_in_sigma / std::sqrt(2.0);
85  return -2.0 / std::sqrt(M_PI) * x * std::exp(-x * x) + std::erf(x);
86 }
87 
88 /**
89  * A class to pre-calculate and store parameters relevant for density
90  * calculation. It has to be initialized only once per SMASH run.
91  */
93  public:
94  /**
95  * Constructor of DensityParameters.
96  *
97  * \param[in] par Struct containing the Gaussian smearing width \f$\sigma\f$,
98  * the cutoff factor \f$a\f$ where the cutoff radius
99  * \f$r_{\rm cut}=a\sigma\f$, the test-particle number, the number
100  * of ensembles, the mode of calculating the derivatives, the
101  * smearing mode, the central weight for Discrete smearing, the
102  * range (in units of lattice spacing) for Triangular smearing
103  * and the flag about using only participants or also spectators
104  */
106  : sig_(par.gaussian_sigma),
107  r_cut_(par.gauss_cutoff_in_sigma * par.gaussian_sigma),
108  ntest_(par.testparticles),
109  nensembles_(par.n_ensembles),
110  derivatives_(par.derivatives_mode),
111  rho_derivatives_(par.rho_derivatives_mode),
112  smearing_(par.smearing_mode),
113  central_weight_(par.discrete_weight),
118  const double two_sig_sqr = 2 * sig_ * sig_;
119  two_sig_sqr_inv_ = 1. / two_sig_sqr;
120  const double norm = smearing_factor_norm(two_sig_sqr);
121  const double corr_factor =
123  norm_factor_sf_ = 1. / (norm * ntest_ * nensembles_ * corr_factor);
124  }
125  /// \return Testparticle number
126  int ntest() const { return ntest_; }
127  /// \return Number of ensembles
128  int nensembles() const { return nensembles_; }
129  /// \return Mode of gradient calculation
131  /// \return Mode of rest frame density derivatives (on or off)
133  return rho_derivatives_;
134  }
135  /// \return Smearing mode
136  SmearingMode smearing() const { return smearing_; }
137  /// \return Weight of the central cell in the discrete smearing
138  double central_weight() const { return central_weight_; }
139  /// \return Range of the triangular smearing, in units of lattice spacing
140  double triangular_range() const { return triangular_range_; }
141  /// \return Cut-off radius [fm]
142  double r_cut() const { return r_cut_; }
143  /// \return Squared cut-off radius [fm\f$^2\f$]
144  double r_cut_sqr() const { return r_cut_sqr_; }
145  /// \return \f$ (2 \sigma^2)^{-1} \f$ [fm\f$^{-2}\f$]
146  double two_sig_sqr_inv() const { return two_sig_sqr_inv_; }
147  /**
148  * \return Normalization for smearing factor. Unnormalized smearing factor
149  * \f$ sf(\mathbf{r}) \f$ has to be multiplied by this to have
150  * \f$ \int d^3r \, sf(\mathbf{r}) = 1 \f$.
151  */
152  double norm_factor_sf() const { return norm_factor_sf_; }
153  /// \return counting only participants (true) or also spectators (false)
154  bool only_participants() const { return only_participants_; }
155  /// \return whether unformed particles are ignored
156  bool ignore_unformed() const { return ignore_unformed_; }
157 
158  private:
159  /// Gaussian smearing width [fm]
160  const double sig_;
161  /// Cut-off radius [fm]
162  const double r_cut_;
163  /// Squared cut-off radius [fm\f$^2\f$]
164  double r_cut_sqr_;
165  /// \f$ (2 \sigma^2)^{-1} \f$ [fm\f$^{-2}\f$]
167  /// Normalization for Gaussian smearing factor
169  /// Testparticle number
170  const int ntest_;
171  /// Number of ensembles
172  const int nensembles_;
173  /// Mode of calculating the gradients
175  /// Whether to calculate the rest frame density derivatives
177  /// Mode of smearing
179  /// Weight of the central cell in the discrete smearing
180  const double central_weight_;
181  /// Range of the triangular smearing
182  const double triangular_range_;
183  /// Flag to take into account only participants
185  /// Flag to ignore unformed particles
186  const bool ignore_unformed_;
187 };
188 
189 /**
190  * Implements gaussian smearing for any quantity.
191  * Computes smearing factor taking Lorentz contraction into account.
192  * Integral of unnormalized smearing factor over space should be
193  * \f$ (2 \pi \sigma^2)^{3/2} \f$. Division over norm is split
194  * for efficiency: it is not nice to recalculate the same constant
195  * norm at every call.
196  *
197  * \param[in] r vector from the particle to the point of interest [fm]
198  * \param[in] p particle 4-momentum to account for Lorentz contraction [GeV]
199  * \param[in] m_inv particle mass, \f$ (E^2 - p^2)^{-1/2} \f$ [GeV]
200  * \param[in] dens_par object containing precomputed parameters for
201  * density calculation.
202  * \param[in] compute_gradient option, true - compute gradient, false - no
203  * \return (smearing factor, the gradient of the smearing factor or a zero
204  * three vector)
205  */
206 std::pair<double, ThreeVector> unnormalized_smearing_factor(
207  const ThreeVector &r, const FourVector &p, const double m_inv,
208  const DensityParameters &dens_par, const bool compute_gradient = false);
209 
210 /**
211  * Calculates Eckart rest frame density and 4-current of a given density type
212  * and optionally the gradient of the density in an arbitary frame (grad j0),
213  * the curl of the 3-current, and the time, x, y, and z derivatives of the
214  * 4-current.
215  * \f[
216  * j^{\mu} = (\sqrt{2\pi} \sigma )^{-3} \sum_{i=1}^N C_i u^{\mu}_i \exp
217  * \left(
218  * - \frac{\bigl[\mathbf{r} - \mathbf{r}_i + \frac{\gamma_i^2}{1 + \gamma_i}
219  * \boldsymbol{\beta}_i (\boldsymbol{\beta}_i, \mathbf{r} - \mathbf{r}_i)
220  * \bigr]^2}{2\sigma^2}
221  * \right)
222  * \f]
223  * \f[ \rho^{Eckart} = \sqrt{j^{\mu} j_{\mu}} \f]
224  * Here \f$ C_i \f$ is a corresponding value of "charge". If baryon
225  * current option is selected then \f$ C_i \f$ is 1 for baryons,
226  * -1 for antibaryons and 0 otherwise. For proton/neutron
227  * current \f$ C_i = 1\f$ for proton/neutron and 0 otherwise.
228  *
229  * To avoid the problems with Eckart frame definition, densities for
230  * positive and negative charges, \f$\rho_+ \f$ and \f$ \rho_-\f$,
231  * are computed separately and final density is \f$\rho_+ - \rho_-\f$.
232  *
233  * \param[in] r Arbitrary space point where 4-current is calculated [fm];
234  ignored if smearing is false
235  * \param[in] plist List of all particles to be used in \f$j^{\mu}\f$
236  * calculation. If smearing is false or if the distance
237  * between particle and calculation point r,
238  * \f$ |r-r_i| > r_{cut} \f$ then particle input
239  * to density will be ignored.
240  *
241  * Next four values are taken from ExperimentalParameters structure:
242  *
243  * \param[in] par Set of parameters packed in one structure.
244  * From them the cutting radius r_cut \f$ r_{cut} / \sigma \f$,
245  * number of test-particles ntest and the gaussian width
246  * gs_sigma are needed.
247  * \param[in] dens_type type of four-currect to be calculated:
248  * baryon, proton or neutron options are currently available
249  * \param[in] compute_gradient true - compute gradient, false - no
250  * \param[in] smearing whether to use gaussian smearing or not. If false,
251  * this parameter will use ALL particles equally to calculate the
252  * current, and that as such it will not be normalized wrt volume.
253  * This should be true for any internal calculation of any quantity
254  * and only makes sense to turn off for output purposes in a box.
255  * \return (rest frame density in the local Eckart frame [fm\f$^{-3}\f$],
256  * \f$ j^\mu \f$ as a 4-vector,
257  * \f$ \boldsymbol{\nabla}\cdot j^0 \f$ or a 0 3-vector,
258  * \f$ \boldsymbol{\nabla} \times \mathbf{j} \f$ or a 0 3-vector,
259  * \f$ \partial_t j^\mu \f$ or a 0 4-vector,
260  * \f$ \partial_x j^\mu \f$ or a 0 4-vector,
261  * \f$ \partial_y j^\mu \f$ or a 0 4-vector,
262  * \f$ \partial_z j^\mu \f$ or a 0 4-vector).
263  */
266 current_eckart(const ThreeVector &r, const ParticleList &plist,
267  const DensityParameters &par, DensityType dens_type,
268  bool compute_gradient, bool smearing);
269 /// convenience overload of the above (ParticleList -> Particles)
272 current_eckart(const ThreeVector &r, const Particles &plist,
273  const DensityParameters &par, DensityType dens_type,
274  bool compute_gradient, bool smearing);
275 
276 /**
277  * A class for time-efficient (time-memory trade-off) calculation of density
278  * on the lattice. It holds six FourVectors - positive and negative
279  * summands of 4-current, and the time and spatial derivatives of the compound
280  * current. These four-vectors are additive by particles. It is efficient to
281  * calculate additive \f$j^\mu\f$ and \f$\partial_\nu j^\mu \f$ in one loop over
282  * particles and then calculate the Eckart density, the gradient of the density,
283  * the curl, the time derivative of the current, and derivatives of the rest
284  * frame density accordingly.
285  * Splitting into positive and negative parts of \f$j^\mu\f$ is necessary to
286  * avoid problems with the definition of Eckart rest frame.
287  *
288  * Intended usage of the class:
289  * -# Add particles from some list using add_particle(), setting jmu_pos and
290  * jmu_neg. Calculate derivatives using either add_particle_for_derivatives()
291  * (in case of Gaussian derivatives) or calculating finite difference
292  * derivatives; this sets djmu_dxnu. If needed, calculate rest frame density
293  * derivatives, setting drho_dxnu.
294  * -# Get the net current via jmu_net().
295  * -# Get the net rest frame density via rho().
296  * -# Get the derivatives of the net current via djmu_dxnu()
297  * -# Get the derivatives of the net rest frame baryon density via drho_dxnu()
298  * -# Get \f$\boldsymbol{\nabla} j^0\f$ via grad_j0()
299  * -# Get \f$\boldsymbol{\nabla} \times \mathbf{j}\f$ via curl_vecj()
300  * -# Get \f$\partial_t\,\mathbf{j}\f$ via dvecj_dt()
301  * -# Get \f$(\boldsymbol{\nabla} \rho) \times \mathbf{j}\f$ via
302  * grad_rho_cross_vecj()
303  */
305  public:
306  /// Default constructor
308  : jmu_pos_(FourVector()),
309  jmu_neg_(FourVector()),
311  drho_dxnu_(FourVector()) {}
312 
313  /**
314  * Adds particle to 4-current: \f$j^{\mu} += p^{\mu}/p^0 \cdot factor \f$.
315  * Two private class members jmu_pos_ and jmu_neg_ indicating the 4-current
316  * of the positively and negatively charged particles are updated by this
317  * function.
318  *
319  * \param[in] part Particle would be added to the current density
320  * on the lattice.
321  * \param[in] FactorTimesSf particle contribution to given density type (e.g.
322  * anti-proton contributes with factor -1 to baryon density,
323  * proton - with factor 1) times the smearing factor.
324  */
325  void add_particle(const ParticleData &part, double FactorTimesSf) {
326  const FourVector part_four_velocity = FourVector(1.0, part.velocity());
327  if (FactorTimesSf > 0.0) {
328  jmu_pos_ += part_four_velocity * FactorTimesSf;
329  } else {
330  jmu_neg_ += part_four_velocity * FactorTimesSf;
331  }
332  }
333 
334  /**
335  * Adds particle to the time and spatial derivatives of the 4-current.
336  * An array of four private 4-vectors djmu_dxnu_ indicating the derivatives
337  * of the compound current are updated by this function.
338  *
339  * \param[in] part Particle would be added to the current density
340  * on the lattice.
341  * \param[in] factor particle contribution to given density type (e.g.
342  * anti-proton contributes with factor -1 to baryon density,
343  * proton - with factor 1).
344  * \param[in] sf_grad Smearing factor of the gradients
345  */
346  void add_particle_for_derivatives(const ParticleData &part, double factor,
347  ThreeVector sf_grad) {
348  const FourVector PartFourVelocity = FourVector(1.0, part.velocity());
349  for (int k = 1; k <= 3; k++) {
350  djmu_dxnu_[k] += factor * PartFourVelocity * sf_grad[k - 1];
351  djmu_dxnu_[0] -=
352  factor * PartFourVelocity * sf_grad[k - 1] * part.velocity()[k - 1];
353  }
354  }
355 
356  /**
357  * Compute the net Eckart density on the local lattice
358  *
359  * Note that the net Eckart density is calculated by taking the difference
360  * between the Eckart density of the positively charged particles and that
361  * of the negatively charged particles, which are, in general, defined in
362  * different frames. So the net Eckart density is not the net density in the
363  * Eckart local rest frame. However, this is the only way we can think of
364  * to be applied to the case where the density current is space-like. And
365  * fortunately, the net eckart densities are only used for calculating the
366  * potentials which are valid only in the low-energy collisions where the
367  * amount of the negatively charged particles are negligible. May be in the
368  * future, the net Eckart density can be calculated in a smarter way.
369  *
370  * \param[in] norm_factor Normalization factor
371  * \return Net Eckart density on the local lattice \f$\rho\f$ [fm\f$^{-3}\f$]
372  */
373  double rho(const double norm_factor = 1.0) {
374  return (jmu_pos_.abs() - jmu_neg_.abs()) * norm_factor;
375  }
376 
377  /**
378  * Compute curl of the current on the local lattice
379  *
380  * \param[in] norm_factor Normalization factor
381  * \return \f$\boldsymbol{\nabla}\times\mathbf{j}\f$ [fm \f$^{-4}\f$]
382  */
383  ThreeVector curl_vecj(const double norm_factor = 1.0) {
384  ThreeVector curl_vec_j = ThreeVector();
385  curl_vec_j.set_x1(djmu_dxnu_[2].x3() - djmu_dxnu_[3].x2());
386  curl_vec_j.set_x2(djmu_dxnu_[3].x1() - djmu_dxnu_[1].x3());
387  curl_vec_j.set_x3(djmu_dxnu_[1].x2() - djmu_dxnu_[2].x1());
388  curl_vec_j *= norm_factor;
389  return curl_vec_j;
390  }
391 
392  /**
393  * Compute gradient of the the zeroth component of the four-current j^mu
394  * (that is of the computational frame density) on the local lattice
395  *
396  * \param[in] norm_factor Normalization factor
397  * \return \f$\boldsymbol{\nabla} j^0\f$ [fm \f$^{-4}\f$]
398  */
399  ThreeVector grad_j0(const double norm_factor = 1.0) {
400  ThreeVector j0_grad = ThreeVector();
401  for (int i = 1; i < 4; i++) {
402  j0_grad[i - 1] = djmu_dxnu_[i].x0() * norm_factor;
403  }
404  return j0_grad;
405  }
406 
407  /**
408  * Compute time derivative of the current density on the local lattice
409  *
410  * \param[in] norm_factor Normalization factor
411  * \return \f$\partial_t \mathbf{j}\f$ [fm \f$^{-4}\f$]
412  */
413  ThreeVector dvecj_dt(const double norm_factor = 1.0) {
414  return djmu_dxnu_[0].threevec() * norm_factor;
415  }
416 
417  /**
418  * \return Net current density
419  *
420  * There is a "+" operator in between, because the negative symbol
421  * of the charge has already be included in FactorTimesSF.
422  */
423  FourVector jmu_net() const { return jmu_pos_ + jmu_neg_; }
424 
425  /**
426  * Add to the positive density current.
427  * \param[in] additional_jmu_B Value of positive density current to be added
428  */
429  void add_to_jmu_pos(FourVector additional_jmu_B) {
430  jmu_pos_ += additional_jmu_B;
431  }
432 
433  /**
434  * Add to the negative density current.
435  * \param[in] additional_jmu_B Value of negative density current to be added
436  */
437  void add_to_jmu_neg(FourVector additional_jmu_B) {
438  jmu_neg_ += additional_jmu_B;
439  }
440 
441  /**
442  * Return the FourGradient of the rest frame density
443  * \f$\partial_{\nu}\rho\f$
444  * \return the FourGradient of the rest frame density
445  * \f$\partial_{\nu}\rho\f$
446  */
447  FourVector drho_dxnu() const { return drho_dxnu_; }
448 
449  /**
450  * Return the FourGradient of the net baryon current
451  * \f$\partial_{\nu} j^\mu\f$
452  * \return the array of FourGradients of \f$\partial_{\nu} j^\mu\f$
453  */
454  std::array<FourVector, 4> djmu_dxnu() const { return djmu_dxnu_; }
455 
456  /**
457  * Compute the cross product of \f$\boldsymbol{\nabla}\rho\f$ and \f$j^\mu\f$
458  * \return the cross product of \f$\boldsymbol{\nabla} \rho\f$ and
459  * \f$\mathbf{j}\f$
460  */
462  const ThreeVector grad_rho = drho_dxnu_.threevec();
463  const ThreeVector vecj = jmu_net().threevec();
464  const ThreeVector Drho_cross_vecj = grad_rho.cross_product(vecj);
465 
466  return Drho_cross_vecj;
467  }
468 
469  /**
470  * Overwrite the time derivative of the current to zero.
471  */
473  djmu_dxnu_[0] = FourVector(0.0, 0.0, 0.0, 0.0);
474  }
475 
476  /**
477  * Overwrite the time derivative of the rest frame density to zero.
478  */
480 
481  /**
482  * Overwrite the rest frame density derivatives to provided values.
483  * \param[in] computed_drho_dxnu a FourGradient of the rest frame density rho
484  */
485  void overwrite_drho_dxnu(FourVector computed_drho_dxnu) {
486  drho_dxnu_ = computed_drho_dxnu;
487  }
488 
489  /**
490  * Overwrite all density current derivatives to provided values.
491  * \param[in] djmu_dt time derivative of the current FourVector jmu
492  * \param[in] djmu_dx x derivative of the current FourVector jmu
493  * \param[in] djmu_dy y derivative of the current FourVector jmu
494  * \param[in] djmu_dz z derivative of the current FourVector jmu
495  */
497  FourVector djmu_dy, FourVector djmu_dz) {
498  djmu_dxnu_[0] = djmu_dt;
499  djmu_dxnu_[1] = djmu_dx;
500  djmu_dxnu_[2] = djmu_dy;
501  djmu_dxnu_[3] = djmu_dz;
502  }
503 
504  private:
505  /// Four-current density of the positively charged particle.
507  /// Four-current density of the negatively charged particle.
509  /// Four-gradient of the four-current density, \f$\partial_\nu j^\mu \f$
510  std::array<FourVector, 4> djmu_dxnu_;
511  /// Four-gradient of the rest frame density, \f$\partial_\nu \rho \f$
513 };
514 
515 /// Conveniency typedef for lattice of density
517 
518 /**
519  * Updates the contents on the lattice.
520  *
521  * \param[inout] lat The lattice on which the content will be updated
522  * \param[in] update tells if called for update at printout or at timestep
523  * \param[in] dens_type density type to be computed on the lattice
524  * \param[in] par a structure containing testparticles number and gaussian
525  * smearing parameters.
526  * \param[in] plist the particle list to compute the lattice quantities
527  * \param[in] compute_gradient Whether to compute the gradients
528  * \param[in] lattice_reset Whether to start with a new lattice
529  * \tparam T LatticeType
530  */
531 template <typename T>
533  const LatticeUpdate update,
534  const DensityType dens_type,
535  const DensityParameters &par,
536  const ParticleList &plist,
537  const bool compute_gradient,
538  const bool lattice_reset = true) {
539  // Do not proceed if lattice does not exists/update not required
540  if (lat == nullptr || lat->when_update() != update) {
541  return;
542  }
543  if (lattice_reset) {
544  lat->reset();
545  }
546  for (const ParticleData &part : plist) {
547  if (par.only_participants()) {
548  // if this conditions holds, the hadron is a spectator
549  if (part.get_history().collisions_per_particle == 0) {
550  continue;
551  }
552  }
553  if (par.ignore_unformed()) {
554  if (part.xsec_scaling_factor() < 1) {
555  continue;
556  }
557  }
558  const double dens_factor = density_factor(part.type(), dens_type);
559  if (std::abs(dens_factor) < really_small) {
560  continue;
561  }
562  const FourVector p_mu = part.momentum();
563  const ThreeVector pos = part.position().threevec();
564 
565  // act accordingly to which smearing is used
567  // get the normalization factor for the covariant Gaussian smearing
568  const double norm_factor_gaus = par.norm_factor_sf();
569  const double m = p_mu.abs();
570  if (unlikely(m < really_small)) {
571  logg[LDensity].warn("Gaussian smearing is undefined for momentum ",
572  p_mu);
573  continue;
574  }
575  const double m_inv = 1.0 / m;
576 
577  // unweighted contribution to density
578  const double common_weight = dens_factor * norm_factor_gaus;
579  lat->iterate_in_cube(
580  pos, par.r_cut(), [&](T &node, int ix, int iy, int iz) {
581  // find the weight for smearing
582  const ThreeVector r = lat->cell_center(ix, iy, iz);
583  const auto sf = unnormalized_smearing_factor(pos - r, p_mu, m_inv,
584  par, compute_gradient);
585  node.add_particle(part, sf.first * common_weight);
586  if (par.derivatives() == DerivativesMode::CovariantGaussian) {
587  node.add_particle_for_derivatives(part, dens_factor,
588  sf.second * norm_factor_gaus);
589  }
590  });
591  } else if (par.smearing() == SmearingMode::Discrete) {
592  // get the volume of the cell and weights for discrete smearing
593  const double V_cell = (lat->cell_sizes())[0] * (lat->cell_sizes())[1] *
594  (lat->cell_sizes())[2];
595  // weights for coarse smearing
596  const double big = par.central_weight();
597  const double small = (1.0 - big) / 6.0;
598  // unweighted contribution to density
599  const double common_weight =
600  dens_factor / (par.ntest() * par.nensembles() * V_cell);
602  pos, [&](T &node, int iterated_index, int center_index) {
603  node.add_particle(
604  part, common_weight *
605  // the contribution to density is weighted depending
606  // on what node it is added to
607  (iterated_index == center_index ? big : small));
608  });
609  } else if (par.smearing() == SmearingMode::Triangular) {
610  // get the radii for triangular smearing
611  const std::array<double, 3> triangular_radius = {
612  par.triangular_range() * (lat->cell_sizes())[0],
613  par.triangular_range() * (lat->cell_sizes())[1],
614  par.triangular_range() * (lat->cell_sizes())[2]};
615  const double prefactor_triangular =
616  1.0 /
617  (par.ntest() * par.nensembles() * triangular_radius[0] *
618  triangular_radius[0] * triangular_radius[1] * triangular_radius[1] *
619  triangular_radius[2] * triangular_radius[2]);
620  // unweighted contribution to density
621  const double common_weight = dens_factor * prefactor_triangular;
623  pos, triangular_radius, [&](T &node, int ix, int iy, int iz) {
624  // compute the position of the node
625  const ThreeVector cell_center = lat->cell_center(ix, iy, iz);
626  // compute smearing weight
627  const double weight_x =
628  triangular_radius[0] - std::abs(cell_center[0] - pos[0]);
629  const double weight_y =
630  triangular_radius[1] - std::abs(cell_center[1] - pos[1]);
631  const double weight_z =
632  triangular_radius[2] - std::abs(cell_center[2] - pos[2]);
633  // add the contribution to the node
634  node.add_particle(part,
635  common_weight * weight_x * weight_y * weight_z);
636  });
637  }
638  }
639 }
640 
641 /**
642  * Updates the contents on the lattice when ensembles are used.
643  *
644  * \param[out] lat The lattice on which the content will be updated
645  * \param[in] update tells if called for update at printout or at timestep
646  * \param[in] dens_type density type to be computed on the lattice
647  * \param[in] par a structure containing testparticles number and gaussian
648  * smearing parameters.
649  * \param[in] ensembles the particles vector for each ensemble
650  * \param[in] compute_gradient Whether to compute the gradients
651  * \tparam T LatticeType
652  */
653 template <typename T>
655  RectangularLattice<T> *lat, const LatticeUpdate update,
656  const DensityType dens_type, const DensityParameters &par,
657  const std::vector<Particles> &ensembles, const bool compute_gradient) {
658  // Do not proceed if lattice does not exists/update not required
659  if (lat == nullptr || lat->when_update() != update) {
660  return;
661  }
662  lat->reset();
663  for (const Particles &particles : ensembles) {
664  update_lattice_with_list_of_particles(lat, update, dens_type, par,
665  particles.copy_to_vector(),
666  compute_gradient, false);
667  }
668 }
669 
670 /**
671  * Updates the contents on the lattice of DensityOnLattice type.
672  *
673  * \param[out] lat The lattice of DensityOnLattice type on which the content
674  * will be updated
675  * \param[in] old_jmu Auxiliary lattice, filled with current values at t0,
676  * needed for calculating time derivatives
677  * \param[in] new_jmu Auxiliary lattice,filled with current values at t0 + dt,
678  * needed for calculating time derivatives
679  * \param[in] four_grad_lattice Auxiliary lattice for calculating the
680  * fourgradient of the current
681  * \param[in] update Tells if called for update at printout or at timestep
682  * \param[in] dens_type Density type to be computed on the lattice
683  * \param[in] par a structure containing testparticles number and gaussian
684  * smearing parameters.
685  * \param[in] ensembles The particles vector for each ensemble
686  * \param[in] time_step Time step used in the simulation
687  * \param[in] compute_gradient Whether to compute the gradients
688  */
689 void update_lattice(
690  RectangularLattice<DensityOnLattice> *lat,
691  RectangularLattice<FourVector> *old_jmu,
692  RectangularLattice<FourVector> *new_jmu,
693  RectangularLattice<std::array<FourVector, 4>> *four_grad_lattice,
694  const LatticeUpdate update, const DensityType dens_type,
695  const DensityParameters &par, const std::vector<Particles> &ensembles,
696  const double time_step, const bool compute_gradient);
697 } // namespace smash
698 
699 #endif // SRC_INCLUDE_SMASH_DENSITY_H_
A class for time-efficient (time-memory trade-off) calculation of density on the lattice.
Definition: density.h:304
std::array< FourVector, 4 > djmu_dxnu() const
Return the FourGradient of the net baryon current .
Definition: density.h:454
std::array< FourVector, 4 > djmu_dxnu_
Four-gradient of the four-current density, .
Definition: density.h:510
double rho(const double norm_factor=1.0)
Compute the net Eckart density on the local lattice.
Definition: density.h:373
ThreeVector grad_j0(const double norm_factor=1.0)
Compute gradient of the the zeroth component of the four-current j^mu (that is of the computational f...
Definition: density.h:399
void overwrite_djmu_dxnu(FourVector djmu_dt, FourVector djmu_dx, FourVector djmu_dy, FourVector djmu_dz)
Overwrite all density current derivatives to provided values.
Definition: density.h:496
ThreeVector grad_rho_cross_vecj() const
Compute the cross product of and .
Definition: density.h:461
void add_particle(const ParticleData &part, double FactorTimesSf)
Adds particle to 4-current: .
Definition: density.h:325
ThreeVector dvecj_dt(const double norm_factor=1.0)
Compute time derivative of the current density on the local lattice.
Definition: density.h:413
void add_to_jmu_pos(FourVector additional_jmu_B)
Add to the positive density current.
Definition: density.h:429
FourVector drho_dxnu_
Four-gradient of the rest frame density, .
Definition: density.h:512
void add_to_jmu_neg(FourVector additional_jmu_B)
Add to the negative density current.
Definition: density.h:437
void overwrite_drho_dxnu(FourVector computed_drho_dxnu)
Overwrite the rest frame density derivatives to provided values.
Definition: density.h:485
void overwrite_djmu_dt_to_zero()
Overwrite the time derivative of the current to zero.
Definition: density.h:472
FourVector jmu_pos_
Four-current density of the positively charged particle.
Definition: density.h:506
void overwrite_drho_dt_to_zero()
Overwrite the time derivative of the rest frame density to zero.
Definition: density.h:479
DensityOnLattice()
Default constructor.
Definition: density.h:307
ThreeVector curl_vecj(const double norm_factor=1.0)
Compute curl of the current on the local lattice.
Definition: density.h:383
FourVector jmu_net() const
Definition: density.h:423
void add_particle_for_derivatives(const ParticleData &part, double factor, ThreeVector sf_grad)
Adds particle to the time and spatial derivatives of the 4-current.
Definition: density.h:346
FourVector drho_dxnu() const
Return the FourGradient of the rest frame density .
Definition: density.h:447
FourVector jmu_neg_
Four-current density of the negatively charged particle.
Definition: density.h:508
A class to pre-calculate and store parameters relevant for density calculation.
Definition: density.h:92
double r_cut_sqr_
Squared cut-off radius [fm ].
Definition: density.h:164
const double central_weight_
Weight of the central cell in the discrete smearing.
Definition: density.h:180
const double triangular_range_
Range of the triangular smearing.
Definition: density.h:182
bool ignore_unformed() const
Definition: density.h:156
const SmearingMode smearing_
Mode of smearing.
Definition: density.h:178
const int nensembles_
Number of ensembles.
Definition: density.h:172
double triangular_range() const
Definition: density.h:140
double r_cut() const
Definition: density.h:142
RestFrameDensityDerivativesMode rho_derivatives() const
Definition: density.h:132
SmearingMode smearing() const
Definition: density.h:136
const DerivativesMode derivatives_
Mode of calculating the gradients.
Definition: density.h:174
bool only_participants_
Flag to take into account only participants.
Definition: density.h:184
bool only_participants() const
Definition: density.h:154
const double sig_
Gaussian smearing width [fm].
Definition: density.h:160
DerivativesMode derivatives() const
Definition: density.h:130
double two_sig_sqr_inv() const
Definition: density.h:146
double central_weight() const
Definition: density.h:138
const RestFrameDensityDerivativesMode rho_derivatives_
Whether to calculate the rest frame density derivatives.
Definition: density.h:176
const bool ignore_unformed_
Flag to ignore unformed particles.
Definition: density.h:186
const int ntest_
Testparticle number.
Definition: density.h:170
double norm_factor_sf() const
Definition: density.h:152
int nensembles() const
Definition: density.h:128
double r_cut_sqr() const
Definition: density.h:144
const double r_cut_
Cut-off radius [fm].
Definition: density.h:162
double norm_factor_sf_
Normalization for Gaussian smearing factor.
Definition: density.h:168
DensityParameters(const ExperimentParameters &par)
Constructor of DensityParameters.
Definition: density.h:105
double two_sig_sqr_inv_
[fm ]
Definition: density.h:166
The FourVector class holds relevant values in Minkowski spacetime with (+, −, −, −) metric signature.
Definition: fourvector.h:33
double abs() const
calculate the lorentz invariant absolute value
Definition: fourvector.h:464
ThreeVector threevec() const
Definition: fourvector.h:329
ParticleData contains the dynamic information of a certain particle.
Definition: particledata.h:59
ThreeVector velocity() const
Get the velocity 3-vector.
Definition: particledata.h:321
Particle type contains the static properties of a particle species.
Definition: particletype.h:100
The Particles class abstracts the storage and manipulation of particles.
Definition: particles.h:33
A container class to hold all the arrays on the lattice and access them.
Definition: lattice.h:49
void reset()
Sets all values on lattice to zeros.
Definition: lattice.h:106
LatticeUpdate when_update() const
Definition: lattice.h:171
ThreeVector cell_center(int ix, int iy, int iz) const
Find the coordinates of a given cell.
Definition: lattice.h:133
void iterate_in_cube(const ThreeVector &point, const double r_cut, F &&func)
Iterates only nodes whose cell centers lie not further than r_cut in x, y, z directions from the give...
Definition: lattice.h:627
void iterate_nearest_neighbors(const ThreeVector &point, F &&func)
Iterates only over nodes corresponding to the center cell (the cell containing the given point) and i...
Definition: lattice.h:737
void iterate_in_rectangle(const ThreeVector &point, const std::array< double, 3 > &rectangle, F &&func)
Iterates only nodes whose cell centers lie not further than d_x in x-, d_y in y-, and d_z in z-direct...
Definition: lattice.h:693
const std::array< double, 3 > & cell_sizes() const
Definition: lattice.h:162
The ThreeVector class represents a physical three-vector with the components .
Definition: threevector.h:31
void set_x1(double x)
set first component
Definition: threevector.h:188
void set_x3(double z)
set third component
Definition: threevector.h:196
void set_x2(double y)
set second component
Definition: threevector.h:192
ThreeVector cross_product(const ThreeVector &b) const
Definition: threevector.h:255
SmearingMode
Modes of smearing.
RestFrameDensityDerivativesMode
This enum is here only to serve InputKeys class, but it is unused and referring to a removed SMASH in...
DerivativesMode
Modes of calculating the gradients.
DensityType
Allows to choose which kind of density to calculate.
std::ostream & operator<<(std::ostream &out, const ActionPtr &action)
Convenience: dereferences the ActionPtr to Action.
Definition: action.h:546
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > & logg
An array that stores all pre-configured Logger objects.
Definition: logging.h:245
#define unlikely(x)
Tell the branch predictor that this expression is likely false.
Definition: macros.h:16
constexpr int p
Proton.
Definition: action.h:24
double smearing_factor_norm(const double two_sigma_sqr)
Norm of the Gaussian smearing function.
Definition: density.h:61
std::tuple< double, FourVector, ThreeVector, ThreeVector, FourVector, FourVector, FourVector, FourVector > current_eckart(const ThreeVector &r, const ParticleList &plist, const DensityParameters &par, DensityType dens_type, bool compute_gradient, bool smearing)
Calculates Eckart rest frame density and 4-current of a given density type and optionally the gradien...
Definition: density.cc:176
void update_lattice_accumulating_ensembles(RectangularLattice< T > *lat, const LatticeUpdate update, const DensityType dens_type, const DensityParameters &par, const std::vector< Particles > &ensembles, const bool compute_gradient)
Updates the contents on the lattice when ensembles are used.
Definition: density.h:654
void update_lattice(RectangularLattice< DensityOnLattice > *lat, RectangularLattice< FourVector > *old_jmu, RectangularLattice< FourVector > *new_jmu, RectangularLattice< std::array< FourVector, 4 >> *four_grad_lattice, const LatticeUpdate update, const DensityType dens_type, const DensityParameters &par, const std::vector< Particles > &ensembles, const double time_step, const bool compute_gradient)
Updates the contents on the lattice of DensityOnLattice type.
Definition: density.cc:191
LatticeUpdate
Enumerator option for lattice updates.
Definition: lattice.h:38
double smearing_factor_rcut_correction(const double rcut_in_sigma)
Gaussians used for smearing are cut at radius for calculation speed-up.
Definition: density.h:83
std::pair< double, ThreeVector > unnormalized_smearing_factor(const ThreeVector &r, const FourVector &p, const double m_inv, const DensityParameters &dens_par, const bool compute_gradient=false)
Implements gaussian smearing for any quantity.
Definition: density.cc:38
void update_lattice_with_list_of_particles(RectangularLattice< T > *lat, const LatticeUpdate update, const DensityType dens_type, const DensityParameters &par, const ParticleList &plist, const bool compute_gradient, const bool lattice_reset=true)
Updates the contents on the lattice.
Definition: density.h:532
RectangularLattice< DensityOnLattice > DensityLattice
Conveniency typedef for lattice of density.
Definition: density.h:516
constexpr double really_small
Numerical error tolerance.
Definition: constants.h:41
double density_factor(const ParticleType &type, DensityType dens_type)
Get the factor that determines how much a particle contributes to the density type that is computed.
Definition: density.cc:17
static constexpr int LDensity
Definition: density.h:29
Helper structure for Experiment.
double gauss_cutoff_in_sigma
Distance at which gaussian is cut, i.e. set to zero, IN SIGMA (not fm)