Version: SMASH-3.1
thermodynamiclatticeoutput.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2014-2022
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
11 
12 #include <filesystem>
13 #include <fstream>
14 #include <memory>
15 
16 #include "smash/clock.h"
17 #include "smash/config.h"
18 #include "smash/density.h"
22 #include "smash/vtkoutput.h"
23 
24 namespace smash {
25 
181 /* initialization of the static member version */
182 const double_t ThermodynamicLatticeOutput::version = 1.0;
183 
185  const std::filesystem::path &path, const std::string &name,
186  const OutputParameters &out_par, const bool enable_ascii,
187  const bool enable_binary)
188  : OutputInterface(name),
189  out_par_(out_par),
190  base_path_(std::move(path)),
191  enable_ascii_(enable_ascii),
192  enable_binary_(enable_binary) {
193  if (enable_ascii_ || enable_binary_) {
194  enable_output_ = true;
195  } else {
196  enable_output_ = false;
197  }
198  if (enable_ascii_) {
199  if (out_par_.td_rho_eckart) {
201  std::make_shared<std::ofstream>(nullptr);
202  }
203  if (out_par_.td_tmn_landau) {
205  std::make_shared<std::ofstream>(nullptr);
206  }
207  if (out_par_.td_tmn) {
209  std::make_shared<std::ofstream>(nullptr);
210  }
211  if (out_par_.td_v_landau) {
213  std::make_shared<std::ofstream>(nullptr);
214  }
215  if (out_par_.td_jQBS) {
217  std::make_shared<std::ofstream>(nullptr);
218  }
219  }
220  if (enable_binary_) {
221  if (out_par_.td_rho_eckart) {
223  std::make_shared<std::ofstream>(nullptr);
224  }
225  if (out_par_.td_tmn_landau) {
227  std::make_shared<std::ofstream>(nullptr);
228  }
229  if (out_par_.td_tmn) {
231  std::make_shared<std::ofstream>(nullptr);
232  }
233  if (out_par_.td_v_landau) {
235  std::make_shared<std::ofstream>(nullptr);
236  }
237  if (out_par_.td_jQBS) {
239  std::make_shared<std::ofstream>(nullptr);
240  }
241  }
242 }
243 
245 
247  const int event_number, const ThermodynamicQuantity tq,
248  const DensityType dens_type, RectangularLattice<DensityOnLattice> lattice) {
249  if (!enable_output_) {
250  return;
251  }
252  assert((tq == ThermodynamicQuantity::EckartDensity) ||
254  // at the next refactoring of the code,
255  // this piece should go in the constructor
256  const auto dim = lattice.n_cells();
257  const auto cs = lattice.cell_sizes();
258  const auto orig = lattice.origin();
259  for (int l = 0; l < 3; l++) {
260  nodes_[l] = dim[l];
261  sizes_[l] = cs[l];
262  origin_[l] = orig[l];
263  }
264  std::shared_ptr<std::ofstream> fp(nullptr);
265  std::string varname;
266  std::string filename;
267  varname = make_varname(tq, dens_type);
269  if (enable_ascii_) {
270  filename = make_filename(varname, event_number, 'a');
271  try {
273  filename, std::ios::out);
274  } catch (std::ofstream::failure &e) {
275  logg[LogArea::Main::id].fatal()
276  << "Error in opening " << filename << std::endl;
277  throw std::runtime_error(
278  "Not possible to write thermodynamic "
279  "lattice output to file.");
280  }
283  }
284  if (enable_binary_) {
285  filename = make_filename(varname, event_number, 'b');
286  try {
288  filename, std::ios::out | std::ios::binary);
289  } catch (std::ofstream::failure &e) {
290  logg[LogArea::Main::id].fatal()
291  << "Error in opening " << filename << std::endl;
292  throw std::runtime_error(
293  "Not possible to write thermodynamic "
294  "lattice output to file.");
295  }
298  }
299  } else {
300  if (enable_ascii_) {
301  filename = make_filename(varname, event_number, 'a');
302  try {
304  std::ios::out);
305  } catch (std::ofstream::failure &e) {
306  logg[LogArea::Main::id].fatal()
307  << "Error in opening " << filename << std::endl;
308  throw std::runtime_error(
309  "Not possible to write thermodynamic "
310  "lattice output to file.");
311  }
314  }
315  if (enable_binary_) {
316  filename = make_filename(varname, event_number, 'b');
317  try {
319  filename, std::ios::out | std::ios::binary);
320  } catch (std::ofstream::failure &e) {
321  logg[LogArea::Main::id].fatal()
322  << "Error in opening " << filename << std::endl;
323  throw std::runtime_error(
324  "Not possible to write thermodynamic "
325  "lattice output to file.");
326  }
329  }
330  }
331 }
332 
334  const int event_number, const ThermodynamicQuantity tq,
335  const DensityType dens_type,
337  if (!enable_output_) {
338  return;
339  }
340  const auto dim = lattice.n_cells();
341  const auto cs = lattice.cell_sizes();
342  const auto orig = lattice.origin();
343  for (int l = 0; l < 3; l++) {
344  nodes_[l] = dim[l];
345  sizes_[l] = cs[l];
346  origin_[l] = orig[l];
347  }
348  std::shared_ptr<std::ofstream> fp(nullptr);
349  std::string varname;
350  std::string filename;
351  varname = make_varname(tq, dens_type);
352  if (enable_ascii_) {
353  filename = make_filename(varname, event_number, 'a');
355  try {
357  filename, std::ios::out);
358  } catch (std::ofstream::failure &e) {
359  logg[LogArea::Main::id].fatal()
360  << "Error in opening " << filename << std::endl;
361  throw std::runtime_error(
362  "Not possible to write thermodynamic "
363  "lattice output to file.");
364  }
366  } else if (tq == ThermodynamicQuantity::Tmn) {
367  try {
369  std::ios::out);
370  } catch (std::ofstream::failure &e) {
371  logg[LogArea::Main::id].fatal()
372  << "Error in opening " << filename << std::endl;
373  throw std::runtime_error(
374  "Not possible to write thermodynamic "
375  "lattice output to file.");
376  }
378  } else if (tq == ThermodynamicQuantity::LandauVelocity) {
379  try {
381  filename, std::ios::out);
382  } catch (std::ofstream::failure &e) {
383  logg[LogArea::Main::id].fatal()
384  << "Error in opening " << filename << std::endl;
385  throw std::runtime_error(
386  "Not possible to write thermodynamic "
387  "lattice output to file.");
388  }
390  } else {
391  try {
393  std::ios::out);
394  } catch (std::ofstream::failure &e) {
395  logg[LogArea::Main::id].fatal()
396  << "Error in opening " << filename << std::endl;
397  throw std::runtime_error(
398  "Not possible to write thermodynamic "
399  "lattice output to file.");
400  }
401  }
403  }
404  if (enable_binary_) {
405  filename = make_filename(varname, event_number, 'b');
407  try {
409  filename, std::ios::out | std::ios::binary);
410  } catch (std::ofstream::failure &e) {
411  logg[LogArea::Main::id].fatal()
412  << "Error in opening " << filename << std::endl;
413  throw std::runtime_error(
414  "Not possible to write thermodynamic "
415  "lattice output to file.");
416  }
418  } else if (tq == ThermodynamicQuantity::Tmn) {
419  try {
421  filename, std::ios::out | std::ios::binary);
422  } catch (std::ofstream::failure &e) {
423  logg[LogArea::Main::id].fatal()
424  << "Error in opening " << filename << std::endl;
425  throw std::runtime_error(
426  "Not possible to write thermodynamic "
427  "lattice output to file.");
428  }
430  } else if (tq == ThermodynamicQuantity::LandauVelocity) {
431  try {
433  filename, std::ios::out | std::ios::binary);
434  } catch (std::ofstream::failure &e) {
435  logg[LogArea::Main::id].fatal()
436  << "Error in opening " << filename << std::endl;
437  throw std::runtime_error(
438  "Not possible to write thermodynamic "
439  "lattice output to file.");
440  }
442  } else {
443  try {
445  std::ios::out);
446  } catch (std::ofstream::failure &e) {
447  logg[LogArea::Main::id].fatal()
448  << "Error in opening " << filename << std::endl;
449  throw std::runtime_error(
450  "Not possible to write thermodynamic "
451  "lattice output to file.");
452  }
453  }
455  }
456 }
457 
459  if (!enable_output_) {
460  return;
461  }
463  if (enable_ascii_) {
465  }
466  if (enable_binary_) {
468  }
469  return;
470  }
471  if (tq == ThermodynamicQuantity::Tmn) {
472  if (enable_ascii_) {
474  }
475  if (enable_binary_) {
477  }
478  return;
479  }
481  if (enable_ascii_) {
483  }
484  if (enable_binary_) {
486  }
487  return;
488  }
490  if (enable_ascii_) {
492  }
493  if (enable_binary_) {
495  }
496  return;
497  }
498  if (tq == ThermodynamicQuantity::j_QBS) {
499  if (enable_ascii_) {
501  }
502  if (enable_binary_) {
504  }
505  return;
506  }
507 }
508 
510  RectangularLattice<DensityOnLattice> &lattice, double ctime) {
511  double result;
512  const auto dim = lattice.n_cells();
513  std::shared_ptr<std::ofstream> fp(nullptr);
514  if (enable_ascii_) {
516  *fp << std::setprecision(14);
517  *fp << std::scientific;
518  *fp << ctime << std::endl;
519  }
520  if (enable_binary_) {
522  assert(sizeof(ctime) == sizeof(double));
523  fp->write(reinterpret_cast<char *>(&ctime), sizeof(ctime));
524  }
525  lattice.iterate_sublattice(
526  {0, 0, 0}, dim, [&](DensityOnLattice &node, int ix, int, int) {
527  if (enable_ascii_) {
528  *fp << node.rho() << " ";
529  if (ix == dim[0] - 1) {
530  *fp << "\n";
531  }
532  }
533  if (enable_binary_) {
534  result = node.rho();
535  fp->write(reinterpret_cast<char *>(&result), sizeof(double));
536  }
537  });
538 }
539 
541  RectangularLattice<DensityOnLattice> &lattice, double ctime,
542  const std::vector<Particles> &ensembles,
543  const DensityParameters &dens_param) {
544  if (!enable_output_) {
545  return;
546  }
547  double result;
548  const auto dim = lattice.n_cells();
549  std::shared_ptr<std::ofstream> fp(nullptr);
550  FourVector jQ = FourVector(), jB = FourVector(), jS = FourVector();
551  constexpr bool compute_gradient = false;
552  if (enable_ascii_) {
554  *fp << std::setprecision(14);
555  *fp << std::scientific;
556  *fp << ctime << std::endl;
557  }
558  if (enable_binary_) {
560  assert(sizeof(ctime) == sizeof(double));
561  fp->write(reinterpret_cast<char *>(&ctime), sizeof(ctime));
562  }
563  lattice.iterate_sublattice(
564  {0, 0, 0}, dim, [&](DensityOnLattice &, int ix, int iy, int iz) {
565  const ThreeVector position = lattice.cell_center(ix, iy, iz);
566  jQ.reset();
567  jB.reset();
568  jS.reset();
569  for (const Particles &particles : ensembles) {
570  jQ += std::get<1>(current_eckart(
571  position, particles, dens_param, DensityType::Charge,
572  compute_gradient, out_par_.td_smearing));
573  jB += std::get<1>(current_eckart(
574  position, particles, dens_param, DensityType::Baryon,
575  compute_gradient, out_par_.td_smearing));
576  jS += std::get<1>(current_eckart(
577  position, particles, dens_param, DensityType::Strangeness,
578  compute_gradient, out_par_.td_smearing));
579  }
580  if (enable_ascii_) {
581  *fp << jQ[0];
582  for (int l = 1; l < 4; l++) {
583  *fp << " " << jQ[l];
584  }
585  for (int l = 0; l < 4; l++) {
586  *fp << " " << jB[l];
587  }
588  for (int l = 0; l < 4; l++) {
589  *fp << " " << jS[l];
590  }
591  *fp << "\n";
592  }
593  if (enable_binary_) {
594  for (int l = 0; l < 4; l++) {
595  result = jQ[l];
596  fp->write(reinterpret_cast<char *>(&result), sizeof(double));
597  }
598  for (int l = 0; l < 4; l++) {
599  result = jB[l];
600  fp->write(reinterpret_cast<char *>(&result), sizeof(double));
601  }
602  for (int l = 0; l < 4; l++) {
603  result = jS[l];
604  fp->write(reinterpret_cast<char *>(&result), sizeof(double));
605  }
606  }
607  });
608 }
609 
611  const ThermodynamicQuantity tq,
612  RectangularLattice<EnergyMomentumTensor> &lattice, double ctime) {
613  if (!enable_output_) {
614  return;
615  }
616  double result;
617  const auto dim = lattice.n_cells();
618  std::shared_ptr<std::ofstream> fp(nullptr);
619  if (enable_ascii_) {
620  switch (tq) {
623  break;
626  break;
629  break;
630  default:
631  return;
632  }
633  *fp << std::setprecision(14);
634  *fp << std::scientific;
635  *fp << ctime << std::endl;
636  }
637  if (enable_binary_) {
638  switch (tq) {
641  break;
644  break;
647  break;
648  default:
649  return;
650  }
651  assert(sizeof(ctime) == sizeof(double));
652  fp->write(reinterpret_cast<char *>(&ctime), sizeof(double));
653  }
654  switch (tq) {
656  for (int i = 0; i < 4; i++) {
657  for (int j = i; j < 4; j++) {
658  lattice.iterate_sublattice(
659  {0, 0, 0}, dim,
660  [&](EnergyMomentumTensor &node, int ix, int, int) {
661  if (enable_ascii_) {
662  *fp << node[EnergyMomentumTensor::tmn_index(i, j)] << " ";
663  if (ix == dim[0] - 1) {
664  *fp << "\n";
665  }
666  }
667  if (enable_binary_) {
668  result = node[EnergyMomentumTensor::tmn_index(i, j)];
669  fp->write(reinterpret_cast<char *>(&result), sizeof(double));
670  }
671  });
672  }
673  }
674  break;
676  for (int i = 0; i < 4; i++) {
677  for (int j = i; j < 4; j++) {
678  lattice.iterate_sublattice(
679  {0, 0, 0}, dim,
680  [&](EnergyMomentumTensor &node, int ix, int, int) {
681  if (enable_ascii_) {
682  const FourVector u = node.landau_frame_4velocity();
683  const EnergyMomentumTensor Tmn_L = node.boosted(u);
684  *fp << Tmn_L[EnergyMomentumTensor::tmn_index(i, j)] << " ";
685  if (ix == dim[0] - 1) {
686  *fp << "\n";
687  }
688  }
689  if (enable_binary_) {
690  const FourVector u = node.landau_frame_4velocity();
691  const EnergyMomentumTensor Tmn_L = node.boosted(u);
692  result = Tmn_L[EnergyMomentumTensor::tmn_index(i, j)];
693  fp->write(reinterpret_cast<char *>(&result), sizeof(double));
694  }
695  });
696  }
697  }
698  break;
700  lattice.iterate_sublattice(
701  {0, 0, 0}, dim, [&](EnergyMomentumTensor &node, int, int, int) {
702  if (enable_ascii_) {
703  const FourVector u = node.landau_frame_4velocity();
704  const ThreeVector v = -u.velocity();
705  *fp << v.x1() << " " << v.x2() << " " << v.x3() << "\n";
706  }
707  if (enable_binary_) {
708  const FourVector u = node.landau_frame_4velocity();
709  ThreeVector v = -u.velocity();
710  fp->write(reinterpret_cast<char *>(&v), 3 * sizeof(double));
711  }
712  });
713  break;
714  default:
715  return;
716  }
717 }
718 
720  switch (tq) {
722  return 0;
724  return 1;
726  return 2;
728  return 3;
730  return 4;
731  default:
732  throw std::runtime_error(
733  "Error when converting a thermodynamic quantity "
734  "to an int, unknown quantity.");
735  }
736 }
737 
738 std::string ThermodynamicLatticeOutput::make_filename(const std::string &descr,
739  const int event_number,
740  const char type) {
741  char suffix[13];
742  assert((type == 'a') || (type == 'b'));
743  if (type == 'a') {
744  snprintf(suffix, sizeof(suffix), "_%07i.dat", event_number);
745  } else {
746  snprintf(suffix, sizeof(suffix), "_%07i.bin", event_number);
747  }
748  return base_path_.string() + std::string("/") + descr + std::string(suffix);
749 }
750 
752  const ThermodynamicQuantity tq, const DensityType dens_type) {
753  return std::string(to_string(dens_type)) + std::string("_") +
754  std::string(to_string(tq));
755 }
756 
758  std::shared_ptr<std::ofstream> fp, const ThermodynamicQuantity &tq) {
759  *fp << std::setprecision(2);
760  *fp << std::fixed;
761  *fp << "#Thermodynamic Lattice Output version: "
762  << ThermodynamicLatticeOutput::version << std::endl;
763  *fp << std::setprecision(6);
764  *fp << "#Quantity:"
765  << " " << std::string(to_string(tq)) << std::endl;
766  *fp << "#Grid dimensions: " << nodes_[0] << " " << nodes_[1] << " "
767  << nodes_[2] << std::endl;
768  *fp << "#Grid spacing: " << sizes_[0] << " " << sizes_[1] << " " << sizes_[2]
769  << std::endl;
770  *fp << "#Grid origin: " << origin_[0] << " " << origin_[1] << " "
771  << origin_[2] << std::endl;
772 }
773 
775  std::shared_ptr<std::ofstream> fp, const ThermodynamicQuantity &tq) {
776  auto variable_id = to_int(tq);
777  fp->write(
778  reinterpret_cast<const char *>(&ThermodynamicLatticeOutput::version),
779  sizeof(double));
780  fp->write(reinterpret_cast<char *>(&variable_id), sizeof(int));
781  fp->write(reinterpret_cast<char *>(&nodes_), sizeof(nodes_));
782  fp->write(reinterpret_cast<char *>(&sizes_), sizeof(sizes_));
783  fp->write(reinterpret_cast<char *>(&origin_), sizeof(origin_));
784 }
785 } // namespace smash
A class for time-efficient (time-memory trade-off) calculation of density on the lattice.
Definition: density.h:315
A class to pre-calculate and store parameters relevant for density calculation.
Definition: density.h:108
The EnergyMomentumTensor class represents a symmetric positive semi-definite energy-momentum tensor .
EnergyMomentumTensor boosted(const FourVector &u) const
Boost to a given 4-velocity.
static std::int8_t tmn_index(std::int8_t mu, std::int8_t nu)
Access the index of component .
The FourVector class holds relevant values in Minkowski spacetime with (+, −, −, −) metric signature.
Definition: fourvector.h:33
void reset()
Set all the 4-vector components to 0.
Definition: fourvector.h:486
ThreeVector velocity() const
Get the velocity (3-vector divided by zero component).
Definition: fourvector.h:333
Abstraction of generic output.
const char * to_string(const ThermodynamicQuantity tq)
Convert thermodynamic quantities to strings.
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:47
const std::array< double, 3 > & origin() const
Definition: lattice.h:163
const std::array< int, 3 > & n_cells() const
Definition: lattice.h:157
void iterate_sublattice(const std::array< int, 3 > &lower_bounds, const std::array< int, 3 > &upper_bounds, F &&func)
A sub-lattice iterator, which iterates in a 3D-structured manner and calls a function on every cell.
Definition: lattice.h:571
ThreeVector cell_center(int ix, int iy, int iz) const
Find the coordinates of a given cell.
Definition: lattice.h:131
const std::array< double, 3 > & cell_sizes() const
Definition: lattice.h:160
std::array< int, 3 > nodes_
number of nodes in the lattice along the three axes
std::map< ThermodynamicQuantity, std::shared_ptr< std::ofstream > > output_ascii_files_
map of output file handlers for ASCII format
bool enable_binary_
enable output type Binary
void at_eventstart(const int event_number, const ThermodynamicQuantity tq, const DensityType dens_type, const RectangularLattice< DensityOnLattice > lattice) override
Output launched at event start after initialization, when particles are generated but not yet propaga...
std::string make_filename(const std::string &description, const int event_number, const char type)
Makes a file name given a description and a counter.
static const double_t version
Version of the thermodynamic lattice output.
std::map< ThermodynamicQuantity, std::shared_ptr< std::ofstream > > output_binary_files_
map of output file handlers for binary format
int to_int(const ThermodynamicQuantity &tq)
Convert a ThermodynamicQuantity into an int.
void write_therm_lattice_binary_header(std::shared_ptr< std::ofstream > file, const ThermodynamicQuantity &tq)
Writes the header for the binary output files.
void write_therm_lattice_ascii_header(std::shared_ptr< std::ofstream > file, const ThermodynamicQuantity &tq)
Writes the header for the ASCII output files.
const std::filesystem::path base_path_
filesystem path for output
void thermodynamics_lattice_output(RectangularLattice< DensityOnLattice > &lattice, double current_time) override
Prints the density lattice on a grid.
void at_eventend(const ThermodynamicQuantity tq) override
Final actions at the end of each event (it closes the output files).
const OutputParameters out_par_
Structure that holds all the information about what to printout.
bool enable_output_
enable output, of any kind (if False, the object does nothing)
std::string make_varname(const ThermodynamicQuantity tq, const DensityType dens_type)
Makes a variable name given quantity and density type.
bool enable_ascii_
enable output type ASCII
std::array< double, 3 > sizes_
lattice resolution along the three axes
ThermodynamicLatticeOutput(const std::filesystem::path &path, const std::string &name, const OutputParameters &out_par, const bool enable_ascii, const bool enable_binary)
Construct Output.
std::array< double, 3 > origin_
lattice origin orientation: if 0,0,0 is the origin of a cube with face widths 10, the center is at 5,...
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
ThermodynamicQuantity
Represents thermodynamic quantities that can be printed out See user guide description for more infor...
@ EckartDensity
Density in the Eckart frame.
@ Tmn
Energy-momentum tensor in lab frame.
@ LandauVelocity
Velocity of the Landau rest frame.
@ j_QBS
Electric (Q), baryonic (B) and strange (S) currents.
@ TmnLandau
Energy-momentum tensor in Landau rest frame.
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
Definition: logging.cc:39
Definition: action.h:24
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:171
DensityType
Allows to choose which kind of density to calculate.
Definition: density.h:36
Helper structure for Experiment to hold output options and parameters.
bool td_v_landau
Print out Landau velocity of type td_dens_type or not?
bool td_tmn_landau
Print out energy-momentum tensor in Landau rest frame (of type td_dens_type) or not?
bool td_jQBS
Print out QBS 4-currents or not?
bool td_tmn
Print out energy-momentum tensor of type td_dens_type or not?
bool td_smearing
Whether smearing is on or off; WARNING : if smearing is off, then final result is in GeV instead of G...
bool td_rho_eckart
Print out Eckart rest frame density of type td_dens_type or not?