Version: SMASH-2.2
potentials.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2014-2021
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
10 #include "smash/potentials.h"
11 
12 #include "smash/constants.h"
13 #include "smash/density.h"
14 
15 namespace smash {
16 
17 Potentials::Potentials(Configuration conf, const DensityParameters &param)
18  : param_(param),
19  use_skyrme_(conf.has_value({"Skyrme"})),
20  use_symmetry_(conf.has_value({"Symmetry"})),
21  use_coulomb_(conf.has_value({"Coulomb"})),
22  use_vdf_(conf.has_value({"VDF"})) {
81  if (use_skyrme_) {
82  skyrme_a_ = conf.take({"Skyrme", "Skyrme_A"});
83  skyrme_b_ = conf.take({"Skyrme", "Skyrme_B"});
84  skyrme_tau_ = conf.take({"Skyrme", "Skyrme_Tau"});
85  }
86 
108  if (use_symmetry_) {
109  symmetry_S_Pot_ = conf.take({"Symmetry", "S_Pot"});
110  if (conf.has_value({"Symmetry", "gamma"})) {
111  symmetry_gamma_ = conf.take({"Symmetry", "gamma"});
112  symmetry_is_rhoB_dependent_ = true;
113  }
114  }
140  if (use_coulomb_) {
141  coulomb_r_cut_ = conf.take({"Coulomb", "R_Cut"});
142  }
212  if (use_vdf_) {
213  saturation_density_ = conf.take({"VDF", "Sat_rhoB"});
214  std::vector<double> aux_coeffs = conf.take({"VDF", "Coeffs"});
215  std::vector<double> aux_powers = conf.take({"VDF", "Powers"});
216  if (aux_coeffs.size() != aux_powers.size()) {
217  throw std::invalid_argument(
218  "The number of coefficients should equal the number of powers.");
219  }
220  const int n_terms = aux_powers.size();
221  for (int i = 0; i < n_terms; i++) {
222  if (aux_powers[i] < 0.0) {
223  throw std::invalid_argument("Powers need to be positive real numbers.");
224  }
225  // coefficients are provided in MeV, but the code uses GeV
226  coeffs_.push_back(aux_coeffs[i] * mev_to_gev);
227  powers_.push_back(aux_powers[i]);
228  }
229  }
230 }
231 
232 Potentials::~Potentials() {}
233 
234 double Potentials::skyrme_pot(const double baryon_density) const {
235  const double tmp = baryon_density / nuclear_density;
236  /* U = U(|rho|) * sgn , because the sign of the potential changes
237  * under a charge reversal transformation. */
238  const int sgn = tmp > 0 ? 1 : -1;
239  // Return in GeV
240  return mev_to_gev * sgn *
241  (skyrme_a_ * std::abs(tmp) +
242  skyrme_b_ * std::pow(std::abs(tmp), skyrme_tau_));
243 }
244 double Potentials::symmetry_S(const double baryon_density) const {
245  if (symmetry_is_rhoB_dependent_) {
246  return 12.3 * std::pow(baryon_density / nuclear_density, 2. / 3.) +
247  20.0 * std::pow(baryon_density / nuclear_density, symmetry_gamma_);
248  } else {
249  return 0.;
250  }
251 }
252 double Potentials::symmetry_pot(const double baryon_isospin_density,
253  const double baryon_density) const {
254  double pot = mev_to_gev * 2. * symmetry_S_Pot_ * baryon_isospin_density /
256  if (symmetry_is_rhoB_dependent_) {
257  pot += mev_to_gev * symmetry_S(baryon_density) * baryon_isospin_density *
258  baryon_isospin_density / (baryon_density * baryon_density);
259  }
260  return pot;
261 }
262 
263 FourVector Potentials::vdf_pot(double rhoB, const FourVector jmuB_net) const {
264  // this needs to be used in order to prevent trying to calculate something
265  // like
266  // (-rho_B)^{3.4}
267  const int sgn = rhoB > 0 ? 1 : -1;
268  double abs_rhoB = std::abs(rhoB);
269  // to prevent NAN expressions
270  if (abs_rhoB < very_small_double) {
271  abs_rhoB = very_small_double;
272  }
273  // F_2 is a multiplicative factor in front of the baryon current
274  // in the VDF potential
275  double F_2 = 0.0;
276  for (int i = 0; i < number_of_terms(); i++) {
277  F_2 += coeffs_[i] * std::pow(abs_rhoB, powers_[i] - 2.0) /
278  std::pow(saturation_density_, powers_[i] - 1.0);
279  }
280  F_2 = F_2 * sgn;
281  // Return in GeV
282  return F_2 * jmuB_net;
283 }
284 
285 double Potentials::potential(const ThreeVector &r, const ParticleList &plist,
286  const ParticleType &acts_on) const {
287  double total_potential = 0.0;
288  const bool compute_gradient = false;
289  const bool smearing = true;
290  const auto scale = force_scale(acts_on);
291 
292  if (!(acts_on.is_baryon() || acts_on.is_nucleus())) {
293  return total_potential;
294  }
295  const auto baryon_density_and_gradient = current_eckart(
296  r, plist, param_, DensityType::Baryon, compute_gradient, smearing);
297  const double rhoB = std::get<0>(baryon_density_and_gradient);
298  if (use_skyrme_) {
299  total_potential += scale.first * skyrme_pot(rhoB);
300  }
301  if (use_symmetry_) {
302  const double rho_iso = std::get<0>(
303  current_eckart(r, plist, param_, DensityType::BaryonicIsospin,
304  compute_gradient, smearing));
305  const double sym_pot = symmetry_pot(rho_iso, rhoB) * acts_on.isospin3_rel();
306  total_potential += scale.second * sym_pot;
307  }
308 
309  if (use_vdf_) {
310  const FourVector jmuB = std::get<1>(baryon_density_and_gradient);
311  const FourVector VDF_potential = vdf_pot(rhoB, jmuB);
312  total_potential += scale.first * VDF_potential.x0();
313  }
314 
315  return total_potential;
316 }
317 
318 std::pair<double, int> Potentials::force_scale(const ParticleType &data) {
319  const auto &pdg = data.pdgcode();
320  const double skyrme_or_VDF_scale =
321  (3 - std::abs(pdg.strangeness())) / 3. * pdg.baryon_number();
322  const int symmetry_scale = pdg.baryon_number();
323  return std::make_pair(skyrme_or_VDF_scale, symmetry_scale);
324 }
325 
326 std::pair<ThreeVector, ThreeVector> Potentials::skyrme_force(
327  const double rhoB, const ThreeVector grad_j0B, const ThreeVector dvecjB_dt,
328  const ThreeVector curl_vecjB) const {
329  ThreeVector E_component(0.0, 0.0, 0.0), B_component(0.0, 0.0, 0.0);
330  if (use_skyrme_) {
331  const int sgn = rhoB > 0 ? 1 : -1;
332  const double abs_rhoB = std::abs(rhoB);
333  const double dV_drho = sgn *
334  (skyrme_a_ + skyrme_b_ * skyrme_tau_ *
335  std::pow(abs_rhoB / nuclear_density,
336  skyrme_tau_ - 1)) *
338  E_component -= dV_drho * (grad_j0B + dvecjB_dt);
339  B_component += dV_drho * curl_vecjB;
340  }
341  return std::make_pair(E_component, B_component);
342 }
343 
344 std::pair<ThreeVector, ThreeVector> Potentials::symmetry_force(
345  const double rhoI3, const ThreeVector grad_j0I3,
346  const ThreeVector dvecjI3_dt, const ThreeVector curl_vecjI3,
347  const double rhoB, const ThreeVector grad_j0B, const ThreeVector dvecjB_dt,
348  const ThreeVector curl_vecjB) const {
349  ThreeVector E_component(0.0, 0.0, 0.0), B_component(0.0, 0.0, 0.0);
350  if (use_symmetry_) {
351  E_component -= dVsym_drhoI3(rhoB, rhoI3) * (grad_j0I3 + dvecjI3_dt) +
352  dVsym_drhoB(rhoB, rhoI3) * (grad_j0B + dvecjB_dt);
353  B_component += dVsym_drhoI3(rhoB, rhoI3) * curl_vecjI3 +
354  dVsym_drhoB(rhoB, rhoI3) * curl_vecjB;
355  }
356  return std::make_pair(E_component, B_component);
357 }
358 
359 std::pair<ThreeVector, ThreeVector> Potentials::vdf_force(
360  double rhoB, const double drhoB_dt, const ThreeVector grad_rhoB,
361  const ThreeVector gradrhoB_cross_vecjB, const double j0B,
362  const ThreeVector grad_j0B, const ThreeVector vecjB,
363  const ThreeVector dvecjB_dt, const ThreeVector curl_vecjB) const {
364  // this needs to be used to prevent trying to calculate something like
365  // (-rhoB)^{3.4}
366  const int sgn = rhoB > 0 ? 1 : -1;
367  ThreeVector E_component(0.0, 0.0, 0.0), B_component(0.0, 0.0, 0.0);
368  // to prevent NAN expressions
369  double abs_rhoB = std::abs(rhoB);
370  if (abs_rhoB < very_small_double) {
371  abs_rhoB = very_small_double;
372  }
373  if (use_vdf_) {
374  // F_1 and F_2 are multiplicative factors in front of the baryon current
375  // in the VDF potential
376  double F_1 = 0.0;
377  for (int i = 0; i < number_of_terms(); i++) {
378  F_1 += coeffs_[i] * (powers_[i] - 2.0) *
379  std::pow(abs_rhoB, powers_[i] - 3.0) /
380  std::pow(saturation_density_, powers_[i] - 1.0);
381  }
382  F_1 = F_1 * sgn;
383 
384  double F_2 = 0.0;
385  for (int i = 0; i < number_of_terms(); i++) {
386  F_2 += coeffs_[i] * std::pow(abs_rhoB, powers_[i] - 2.0) /
387  std::pow(saturation_density_, powers_[i] - 1.0);
388  }
389  F_2 = F_2 * sgn;
390 
391  E_component -= (F_1 * (grad_rhoB * j0B + drhoB_dt * vecjB) +
392  F_2 * (grad_j0B + dvecjB_dt));
393  B_component += F_1 * gradrhoB_cross_vecjB + F_2 * curl_vecjB;
394  }
395  return std::make_pair(E_component, B_component);
396 }
397 
398 // overload of the above
399 std::pair<ThreeVector, ThreeVector> Potentials::vdf_force(
400  const ThreeVector grad_A_0, const ThreeVector dA_dt,
401  const ThreeVector curl_A) const {
402  ThreeVector E_component(0.0, 0.0, 0.0), B_component(0.0, 0.0, 0.0);
403  if (use_vdf_) {
404  E_component -= (grad_A_0 + dA_dt);
405  B_component += curl_A;
406  }
407  return std::make_pair(E_component, B_component);
408 }
409 
410 double Potentials::dVsym_drhoI3(const double rhoB, const double rhoI3) const {
411  double term1 = 2. * symmetry_S_Pot_ / nuclear_density;
412  if (symmetry_is_rhoB_dependent_) {
413  double term2 = 2. * rhoI3 * symmetry_S(rhoB) / (rhoB * rhoB);
414  return mev_to_gev * (term1 + term2);
415  } else {
416  return mev_to_gev * term1;
417  }
418 }
419 
420 double Potentials::dVsym_drhoB(const double rhoB, const double rhoI3) const {
421  if (symmetry_is_rhoB_dependent_) {
422  double rhoB_over_rho0 = rhoB / nuclear_density;
423  double term1 = 8.2 * std::pow(rhoB_over_rho0, -1. / 3.) / nuclear_density +
424  20. * symmetry_gamma_ *
425  std::pow(rhoB_over_rho0, symmetry_gamma_) / rhoB;
426  double term2 = -2. * symmetry_S(rhoB) / rhoB;
427  return mev_to_gev * (term1 + term2) * rhoI3 * rhoI3 / (rhoB * rhoB);
428  } else {
429  return 0.;
430  }
431 }
432 
433 std::tuple<ThreeVector, ThreeVector, ThreeVector, ThreeVector>
434 Potentials::all_forces(const ThreeVector &r, const ParticleList &plist) const {
435  const bool compute_gradient = true;
436  const bool smearing = true;
437  auto F_skyrme_or_VDF =
438  std::make_pair(ThreeVector(0., 0., 0.), ThreeVector(0., 0., 0.));
439  auto F_symmetry =
440  std::make_pair(ThreeVector(0., 0., 0.), ThreeVector(0., 0., 0.));
441 
442  const auto baryon_density_and_gradient = current_eckart(
443  r, plist, param_, DensityType::Baryon, compute_gradient, smearing);
444  double rhoB = std::get<0>(baryon_density_and_gradient);
445  const ThreeVector grad_j0B = std::get<2>(baryon_density_and_gradient);
446  const ThreeVector curl_vecjB = std::get<3>(baryon_density_and_gradient);
447  const FourVector djmuB_dt = std::get<4>(baryon_density_and_gradient);
448  if (use_skyrme_) {
449  F_skyrme_or_VDF =
450  skyrme_force(rhoB, grad_j0B, djmuB_dt.threevec(), curl_vecjB);
451  }
452 
453  if (use_symmetry_) {
454  const auto density_and_gradient =
455  current_eckart(r, plist, param_, DensityType::BaryonicIsospin,
456  compute_gradient, smearing);
457  const double rhoI3 = std::get<0>(density_and_gradient);
458  const ThreeVector grad_j0I3 = std::get<2>(density_and_gradient);
459  const ThreeVector curl_vecjI3 = std::get<3>(density_and_gradient);
460  const FourVector dvecjI3_dt = std::get<4>(density_and_gradient);
461  F_symmetry =
462  symmetry_force(rhoI3, grad_j0I3, dvecjI3_dt.threevec(), curl_vecjI3,
463  rhoB, grad_j0B, djmuB_dt.threevec(), curl_vecjB);
464  }
465 
466  if (use_vdf_) {
467  const FourVector jmuB = std::get<1>(baryon_density_and_gradient);
468  const FourVector djmuB_dx = std::get<5>(baryon_density_and_gradient);
469  const FourVector djmuB_dy = std::get<6>(baryon_density_and_gradient);
470  const FourVector djmuB_dz = std::get<7>(baryon_density_and_gradient);
471 
472  // safety check to not divide by zero
473  const int sgn = rhoB > 0 ? 1 : -1;
474  if (std::abs(rhoB) < very_small_double) {
475  rhoB = sgn * very_small_double;
476  }
477 
478  const double drhoB_dt =
479  (1 / rhoB) * (jmuB.x0() * djmuB_dt.x0() - jmuB.x1() * djmuB_dt.x1() -
480  jmuB.x2() * djmuB_dt.x2() - jmuB.x3() * djmuB_dt.x3());
481 
482  const double drhoB_dx =
483  (1 / rhoB) * (jmuB.x0() * djmuB_dx.x0() - jmuB.x1() * djmuB_dx.x1() -
484  jmuB.x2() * djmuB_dx.x2() - jmuB.x3() * djmuB_dx.x3());
485 
486  const double drhoB_dy =
487  (1 / rhoB) * (jmuB.x0() * djmuB_dy.x0() - jmuB.x1() * djmuB_dy.x1() -
488  jmuB.x2() * djmuB_dy.x2() - jmuB.x3() * djmuB_dy.x3());
489 
490  const double drhoB_dz =
491  (1 / rhoB) * (jmuB.x0() * djmuB_dz.x0() - jmuB.x1() * djmuB_dz.x1() -
492  jmuB.x2() * djmuB_dz.x2() - jmuB.x3() * djmuB_dz.x3());
493 
494  const FourVector drhoB_dxnu = {drhoB_dt, drhoB_dx, drhoB_dy, drhoB_dz};
495 
496  const ThreeVector grad_rhoB = drhoB_dxnu.threevec();
497  const ThreeVector vecjB = jmuB.threevec();
498  const ThreeVector Drho_cross_vecj = grad_rhoB.cross_product(vecjB);
499 
500  F_skyrme_or_VDF = vdf_force(
501  rhoB, drhoB_dt, drhoB_dxnu.threevec(), Drho_cross_vecj, jmuB.x0(),
502  grad_j0B, jmuB.threevec(), djmuB_dt.threevec(), curl_vecjB);
503  }
504 
505  return std::make_tuple(F_skyrme_or_VDF.first, F_skyrme_or_VDF.second,
506  F_symmetry.first, F_symmetry.second);
507 }
508 
509 } // namespace smash
The FourVector class holds relevant values in Minkowski spacetime with (+, −, −, −) metric signature.
Definition: fourvector.h:33
double x3() const
Definition: fourvector.h:320
double x2() const
Definition: fourvector.h:316
ThreeVector threevec() const
Definition: fourvector.h:324
double x0() const
Definition: fourvector.h:308
double x1() const
Definition: fourvector.h:312
Particle type contains the static properties of a particle species.
Definition: particletype.h:97
bool is_baryon() const
Definition: particletype.h:203
bool is_nucleus() const
Definition: particletype.h:245
PdgCode pdgcode() const
Definition: particletype.h:156
double isospin3_rel() const
Definition: particletype.h:179
int baryon_number() const
Definition: pdgcode.h:308
Potentials(Configuration conf, const DensityParameters &parameters)
Potentials constructor.
The ThreeVector class represents a physical three-vector with the components .
Definition: threevector.h:31
ThreeVector cross_product(const ThreeVector &b) const
Definition: threevector.h:239
Collection of useful constants that are known at compile time.
int sgn(T val)
Signum function.
Definition: random.h:190
Definition: action.h:24
constexpr double mev_to_gev
MeV to GeV conversion factor.
Definition: constants.h:34
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:167
constexpr double very_small_double
A very small double, used to avoid division by zero.
Definition: constants.h:40
constexpr double nuclear_density
Ground state density of symmetric nuclear matter [fm^-3].
Definition: constants.h:48