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