Version: SMASH-3.4
energymomentumtensor.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2015-2019,2021-2022,2026
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
11 
12 #include <iomanip>
13 #include <iostream>
14 
15 GCC_IGNORE_BEGIN("-Wnull-dereference")
16 #include "Eigen/Dense"
18 
19 #include "smash/logging.h"
20 #include "smash/numerics.h"
21 
22 namespace smash {
23 static constexpr int LTmn = LogArea::Tmn::id;
24 
26  using Eigen::Matrix4d;
27  using Eigen::Vector4d;
28  /* We want to solve the generalized eigenvalue problem
29  T^{\mu \nu} h_{nu} = \lambda g^{\mu \nu} h_{nu}, or in the other way
30  T_{\mu}^{\nu} h_{nu} = \lambda h_{mu}. The eigenvector
31  corresponding to the largest (and the only positive) eigenvalue is
32  proportional to 4-velocity of the Landau frame.
33  Denote T^{\mu}_{\nu} as A and g^{\mu \nu} as B.
34  A is symmetric and positive semi-definite. B is symmetric.
35  A x = \lambda B x. I have to solve generalized eigenvalue
36  problem, because A can be not positively definite (e.g. if
37  energy-momentum tensor is computed for particles with momenta lying
38  in one plane). For positively definite A a more efficient solution
39  is possible, but I (oliiny) do not consider it, until it becomes
40  important for SMASH performance.
41  */
42  Matrix4d A;
43  // A = T_{\mu}^{\nu} = g_{\mu \mu'} T^{\mu' \nu}
44  // clang-format off
45  A << Tmn_[0], Tmn_[1], Tmn_[2], Tmn_[3],
46  -Tmn_[1], -Tmn_[4], -Tmn_[5], -Tmn_[6],
47  -Tmn_[2], -Tmn_[5], -Tmn_[7], -Tmn_[8],
48  -Tmn_[3], -Tmn_[6], -Tmn_[8], -Tmn_[9];
49  // clang-format on
50 
51  logg[LTmn].debug("Looking for Landau frame for T_{mu}^{nu} ", A);
52  Eigen::EigenSolver<Matrix4d> es(A);
53 
54  Vector4d eig_im = es.eigenvalues().imag();
55  Vector4d eig_re = es.eigenvalues().real();
56  size_t i_maxeigenvalue = 0;
57  for (size_t i = 0; i < 4; i++) {
58  if (eig_re(i_maxeigenvalue) < eig_re(i)) {
59  i_maxeigenvalue = i;
60  }
61  }
62 
63  // Sanity checks
64  // Eigen values of A should be strictly real, the largest one corresponding
65  // to energy density should be non-negative, the other ones
66  // corresponding to pressure should be non-positive, because of the
67  // metric tensor gmunu = (1, -1, -1, -1) convention.
68  if (i_maxeigenvalue != 0) {
69  logg[LTmn].warn(
70  "The Tmn diagonalization code previously relied on assumption that"
71  " 0th eigenvalue is the largest one. It seems to be always fulfilled "
72  "in practice, but not guaranteed by Eigen. Here is Tmn * gmn, ",
73  A, " for which it is not fulfilled. Please let Dima(oliiny) know.");
74  }
75  for (size_t i = 0; i < 4; i++) {
76  if (std::abs(eig_im(i)) > really_small) {
77  logg[LTmn].error("Tmn*gmn\n ", A, "\n has a complex eigenvalue ",
78  eig_re(i), " + i * ", eig_im(i));
79  }
80  if (i == i_maxeigenvalue && eig_re(i) < -really_small) {
81  logg[LTmn].error("Tmn*gmn\n", A,
82  "\nenergy density eigenvalue is not positive ",
83  eig_re(i), " + i * ", eig_im(i));
84  logg[LTmn].error("i_max = ", i_maxeigenvalue);
85  }
86  if (i != i_maxeigenvalue && eig_re(i) > really_small) {
87  logg[LTmn].error("Tmn*gmn\n", A, "\npressure eigenvalue is not negative ",
88  eig_re(i), " + i * ", eig_im(i));
89  }
90  }
91 
92  Vector4d tmp = es.eigenvectors().col(i_maxeigenvalue).real();
93  // Choose sign so that zeroth component is positive because we want
94  // 4-velocity to have 0-component positive
95  if (tmp(0) < 0.0) {
96  tmp = -tmp;
97  }
98 
99  FourVector u(tmp(0), tmp(1), tmp(2), tmp(3));
100  const double u_sqr = u.sqr();
101  if (u_sqr > really_small) {
102  u /= std::sqrt(u_sqr);
103  } else {
104  logg[LTmn].error(
105  "Landau frame is not defined.", " Eigen vector", u, " of ", A,
106  " is not time-like and",
107  " cannot be 4-velocity. This may happen if energy-momentum",
108  " tensor was constructed for a massless particle.");
109  u = FourVector(1., 0., 0., 0.);
110  }
111  return u;
112 }
113 
115  using Eigen::Matrix4d;
116  Matrix4d A, L, R;
117  // Energy-momentum tensor
118  // clang-format off
119  A << Tmn_[0], Tmn_[1], Tmn_[2], Tmn_[3],
120  Tmn_[1], Tmn_[4], Tmn_[5], Tmn_[6],
121  Tmn_[2], Tmn_[5], Tmn_[7], Tmn_[8],
122  Tmn_[3], Tmn_[6], Tmn_[8], Tmn_[9];
123  // clang-format on
124  // Compute Lorentz matrix of boost
125  const ThreeVector tmp = u.threevec() / (1.0 + u[0]);
126  // clang-format off
127  L << u[0], u[1], u[2], u[3],
128  u[1], u[1] * tmp.x1() + 1.0, u[2] * tmp.x1(), u[3] * tmp.x1(),
129  u[2], u[1] * tmp.x2(), u[2] * tmp.x2() + 1.0, u[3] * tmp.x2(),
130  u[3], u[1] * tmp.x3(), u[2] * tmp.x3(), u[3] * tmp.x3() + 1.0;
131  // clang-format on
132  // Boost
133  R = L * A * L;
134  // clang-format off
135  return EnergyMomentumTensor({R(0, 0), R(0, 1), R(0, 2), R(0, 3),
136  R(1, 1), R(1, 2), R(1, 3),
137  R(2, 2), R(2, 3),
138  R(3, 3)});
139  // clang-format on
140 }
141 
143  const ThreeVector tmp = mom.threevec() / mom[0];
144  Tmn_[0] += mom[0];
145  Tmn_[1] += mom[1];
146  Tmn_[2] += mom[2];
147  Tmn_[3] += mom[3];
148  Tmn_[4] += mom[1] * tmp.x1();
149  Tmn_[5] += mom[1] * tmp.x2();
150  Tmn_[6] += mom[1] * tmp.x3();
151  Tmn_[7] += mom[2] * tmp.x2();
152  Tmn_[8] += mom[2] * tmp.x3();
153  Tmn_[9] += mom[3] * tmp.x3();
154 }
155 
156 void EnergyMomentumTensor::add_particle(const ParticleData &p, double factor) {
157  if (factor != 0) {
158  add_particle(p.momentum() * factor);
159  }
160 }
161 
162 std::ostream &operator<<(std::ostream &out, const EnergyMomentumTensor &Tmn) {
163  out.width(12);
164  for (size_t mu = 0; mu < 4; mu++) {
165  for (size_t nu = 0; nu < 4; nu++) {
166  out << std::setprecision(3) << std::setw(12) << std::fixed
168  }
169  out << std::endl;
170  }
171  return out;
172 }
173 
174 } // namespace smash
The EnergyMomentumTensor class represents a symmetric positive semi-definite energy-momentum tensor .
EnergyMomentumTensor boosted(const FourVector &u) const
Boost to a given 4-velocity.
FourVector landau_frame_4velocity() const
Find the Landau frame 4-velocity from energy-momentum tensor.
tmn_type Tmn_
The internal storage of the components.
EnergyMomentumTensor()
Default constructor (nulls all components)
static std::int8_t tmn_index(std::int8_t mu, std::int8_t nu)
Access the index of component .
void add_particle(const FourVector &mom)
Given momentum of the particle adds to the energy momentum tensor.
The FourVector class holds relevant values in Minkowski spacetime with (+, −, −, −) metric signature.
Definition: fourvector.h:33
double sqr() const
calculate the square of the vector (which is a scalar)
Definition: fourvector.h:460
ThreeVector threevec() const
Definition: fourvector.h:329
ParticleData contains the dynamic information of a certain particle.
Definition: particledata.h:59
The ThreeVector class represents a physical three-vector with the components .
Definition: threevector.h:31
double x3() const
Definition: threevector.h:194
double x2() const
Definition: threevector.h:190
double x1() const
Definition: threevector.h:186
@ Tmn
Energy-momentum tensor in lab frame.
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 GCC_IGNORE_END()
Non-GCC compilers: fallback empty macro.
Definition: macros.h:67
#define GCC_IGNORE_BEGIN(warning)
Non-GCC compilers: fallback empty macro.
Definition: macros.h:61
constexpr int p
Proton.
Definition: action.h:24
static constexpr int LTmn
constexpr double really_small
Numerical error tolerance.
Definition: constants.h:41
Generic numerical functions.
#define R(x, n)
Definition: sha256.cc:55