Version: SMASH-2.1
thermodynamiclatticeoutput.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 
11 
12 #include <fstream>
13 #include <memory>
14 
15 #include <boost/filesystem.hpp>
16 
17 #include "smash/clock.h"
18 #include "smash/config.h"
19 #include "smash/density.h"
23 #include "smash/vtkoutput.h"
24 
25 namespace smash {
26 
180 /* initialization of the static member version */
181 const double_t ThermodynamicLatticeOutput::version = 1.0;
182 
184  const bf::path &path, const std::string &name,
185  const OutputParameters &out_par, const bool enable_ascii,
186  const bool enable_binary)
187  : OutputInterface(name),
188  out_par_(out_par),
189  base_path_(std::move(path)),
190  enable_ascii_(enable_ascii),
191  enable_binary_(enable_binary) {
192  if (enable_ascii_ || enable_binary_) {
193  enable_output_ = true;
194  } else {
195  enable_output_ = false;
196  }
197  if (enable_ascii_) {
198  if (out_par_.td_rho_eckart) {
200  std::make_shared<std::ofstream>(nullptr);
201  }
202  if (out_par_.td_tmn_landau) {
204  std::make_shared<std::ofstream>(nullptr);
205  }
206  if (out_par_.td_tmn) {
208  std::make_shared<std::ofstream>(nullptr);
209  }
210  if (out_par_.td_v_landau) {
212  std::make_shared<std::ofstream>(nullptr);
213  }
214  if (out_par_.td_jQBS) {
216  std::make_shared<std::ofstream>(nullptr);
217  }
218  }
219  if (enable_binary_) {
220  if (out_par_.td_rho_eckart) {
222  std::make_shared<std::ofstream>(nullptr);
223  }
224  if (out_par_.td_tmn_landau) {
226  std::make_shared<std::ofstream>(nullptr);
227  }
228  if (out_par_.td_tmn) {
230  std::make_shared<std::ofstream>(nullptr);
231  }
232  if (out_par_.td_v_landau) {
234  std::make_shared<std::ofstream>(nullptr);
235  }
236  if (out_par_.td_jQBS) {
238  std::make_shared<std::ofstream>(nullptr);
239  }
240  }
241 }
242 
244 
246  const int event_number, const ThermodynamicQuantity tq,
247  const DensityType dens_type, RectangularLattice<DensityOnLattice> lattice) {
248  if (!enable_output_) {
249  return;
250  }
251  assert((tq == ThermodynamicQuantity::EckartDensity) ||
253  // at the next refactoring of the code,
254  // this piece should go in the constructor
255  const auto dim = lattice.n_cells();
256  const auto cs = lattice.cell_sizes();
257  const auto orig = lattice.origin();
258  for (int l = 0; l < 3; l++) {
259  nodes_[l] = dim[l];
260  sizes_[l] = cs[l];
261  origin_[l] = orig[l];
262  }
263  std::shared_ptr<std::ofstream> fp(nullptr);
264  std::string varname;
265  std::string filename;
266  varname = make_varname(tq, dens_type);
268  if (enable_ascii_) {
269  filename = make_filename(varname, event_number, 'a');
270  try {
272  filename, std::ios::out);
273  } catch (std::ofstream::failure &e) {
274  logg[LogArea::Main::id].fatal()
275  << "Error in opening " << filename << std::endl;
276  throw std::runtime_error(
277  "Not possible to write thermodynamic "
278  "lattice output to file.");
279  }
282  }
283  if (enable_binary_) {
284  filename = make_filename(varname, event_number, 'b');
285  try {
287  filename, std::ios::out | std::ios::binary);
288  } catch (std::ofstream::failure &e) {
289  logg[LogArea::Main::id].fatal()
290  << "Error in opening " << filename << std::endl;
291  throw std::runtime_error(
292  "Not possible to write thermodynamic "
293  "lattice output to file.");
294  }
297  }
298  } else {
299  if (enable_ascii_) {
300  filename = make_filename(varname, event_number, 'a');
301  try {
303  std::ios::out);
304  } catch (std::ofstream::failure &e) {
305  logg[LogArea::Main::id].fatal()
306  << "Error in opening " << filename << std::endl;
307  throw std::runtime_error(
308  "Not possible to write thermodynamic "
309  "lattice output to file.");
310  }
313  }
314  if (enable_binary_) {
315  filename = make_filename(varname, event_number, 'b');
316  try {
318  filename, std::ios::out | std::ios::binary);
319  } catch (std::ofstream::failure &e) {
320  logg[LogArea::Main::id].fatal()
321  << "Error in opening " << filename << std::endl;
322  throw std::runtime_error(
323  "Not possible to write thermodynamic "
324  "lattice output to file.");
325  }
328  }
329  }
330 }
331 
333  const int event_number, const ThermodynamicQuantity tq,
334  const DensityType dens_type,
336  if (!enable_output_) {
337  return;
338  }
339  const auto dim = lattice.n_cells();
340  const auto cs = lattice.cell_sizes();
341  const auto orig = lattice.origin();
342  for (int l = 0; l < 3; l++) {
343  nodes_[l] = dim[l];
344  sizes_[l] = cs[l];
345  origin_[l] = orig[l];
346  }
347  std::shared_ptr<std::ofstream> fp(nullptr);
348  std::string varname;
349  std::string filename;
350  varname = make_varname(tq, dens_type);
351  if (enable_ascii_) {
352  filename = make_filename(varname, event_number, 'a');
354  try {
356  filename, std::ios::out);
357  } catch (std::ofstream::failure &e) {
358  logg[LogArea::Main::id].fatal()
359  << "Error in opening " << filename << std::endl;
360  throw std::runtime_error(
361  "Not possible to write thermodynamic "
362  "lattice output to file.");
363  }
365  } else if (tq == ThermodynamicQuantity::Tmn) {
366  try {
368  std::ios::out);
369  } catch (std::ofstream::failure &e) {
370  logg[LogArea::Main::id].fatal()
371  << "Error in opening " << filename << std::endl;
372  throw std::runtime_error(
373  "Not possible to write thermodynamic "
374  "lattice output to file.");
375  }
377  } else if (tq == ThermodynamicQuantity::LandauVelocity) {
378  try {
380  filename, std::ios::out);
381  } catch (std::ofstream::failure &e) {
382  logg[LogArea::Main::id].fatal()
383  << "Error in opening " << filename << std::endl;
384  throw std::runtime_error(
385  "Not possible to write thermodynamic "
386  "lattice output to file.");
387  }
389  } else {
390  try {
392  std::ios::out);
393  } catch (std::ofstream::failure &e) {
394  logg[LogArea::Main::id].fatal()
395  << "Error in opening " << filename << std::endl;
396  throw std::runtime_error(
397  "Not possible to write thermodynamic "
398  "lattice output to file.");
399  }
400  }
402  }
403  if (enable_binary_) {
404  filename = make_filename(varname, event_number, 'b');
406  try {
408  filename, std::ios::out | std::ios::binary);
409  } catch (std::ofstream::failure &e) {
410  logg[LogArea::Main::id].fatal()
411  << "Error in opening " << filename << std::endl;
412  throw std::runtime_error(
413  "Not possible to write thermodynamic "
414  "lattice output to file.");
415  }
417  } else if (tq == ThermodynamicQuantity::Tmn) {
418  try {
420  filename, std::ios::out | std::ios::binary);
421  } catch (std::ofstream::failure &e) {
422  logg[LogArea::Main::id].fatal()
423  << "Error in opening " << filename << std::endl;
424  throw std::runtime_error(
425  "Not possible to write thermodynamic "
426  "lattice output to file.");
427  }
429  } else if (tq == ThermodynamicQuantity::LandauVelocity) {
430  try {
432  filename, std::ios::out | std::ios::binary);
433  } catch (std::ofstream::failure &e) {
434  logg[LogArea::Main::id].fatal()
435  << "Error in opening " << filename << std::endl;
436  throw std::runtime_error(
437  "Not possible to write thermodynamic "
438  "lattice output to file.");
439  }
441  } else {
442  try {
444  std::ios::out);
445  } catch (std::ofstream::failure &e) {
446  logg[LogArea::Main::id].fatal()
447  << "Error in opening " << filename << std::endl;
448  throw std::runtime_error(
449  "Not possible to write thermodynamic "
450  "lattice output to file.");
451  }
452  }
454  }
455 }
456 
458  if (!enable_output_) {
459  return;
460  }
462  if (enable_ascii_) {
464  }
465  if (enable_binary_) {
467  }
468  return;
469  }
470  if (tq == ThermodynamicQuantity::Tmn) {
471  if (enable_ascii_) {
473  }
474  if (enable_binary_) {
476  }
477  return;
478  }
480  if (enable_ascii_) {
482  }
483  if (enable_binary_) {
485  }
486  return;
487  }
489  if (enable_ascii_) {
491  }
492  if (enable_binary_) {
494  }
495  return;
496  }
497  if (tq == ThermodynamicQuantity::j_QBS) {
498  if (enable_ascii_) {
500  }
501  if (enable_binary_) {
503  }
504  return;
505  }
506 }
507 
509  RectangularLattice<DensityOnLattice> &lattice, double ctime) {
510  double result;
511  const auto dim = lattice.n_cells();
512  std::shared_ptr<std::ofstream> fp(nullptr);
513  if (enable_ascii_) {
515  *fp << std::setprecision(14);
516  *fp << std::scientific;
517  *fp << ctime << std::endl;
518  }
519  if (enable_binary_) {
521  assert(sizeof(ctime) == sizeof(double));
522  fp->write(reinterpret_cast<char *>(&ctime), sizeof(ctime));
523  }
524  lattice.iterate_sublattice(
525  {0, 0, 0}, dim, [&](DensityOnLattice &node, int ix, int, int) {
526  if (enable_ascii_) {
527  *fp << node.rho() << " ";
528  if (ix == dim[0] - 1) {
529  *fp << "\n";
530  }
531  }
532  if (enable_binary_) {
533  result = node.rho();
534  fp->write(reinterpret_cast<char *>(&result), sizeof(double));
535  }
536  });
537 }
538 
540  RectangularLattice<DensityOnLattice> &lattice, double ctime,
541  const std::vector<Particles> &ensembles,
542  const DensityParameters &dens_param) {
543  if (!enable_output_) {
544  return;
545  }
546  double result;
547  const auto dim = lattice.n_cells();
548  std::shared_ptr<std::ofstream> fp(nullptr);
549  FourVector jQ = FourVector(), jB = FourVector(), jS = FourVector();
550  constexpr bool compute_gradient = false;
551  if (enable_ascii_) {
553  *fp << std::setprecision(14);
554  *fp << std::scientific;
555  *fp << ctime << std::endl;
556  }
557  if (enable_binary_) {
559  assert(sizeof(ctime) == sizeof(double));
560  fp->write(reinterpret_cast<char *>(&ctime), sizeof(ctime));
561  }
562  lattice.iterate_sublattice(
563  {0, 0, 0}, dim, [&](DensityOnLattice &, int ix, int iy, int iz) {
564  const ThreeVector position = lattice.cell_center(ix, iy, iz);
565  jQ.reset();
566  jB.reset();
567  jS.reset();
568  for (const Particles &particles : ensembles) {
569  jQ += std::get<1>(current_eckart(
570  position, particles, dens_param, DensityType::Charge,
571  compute_gradient, out_par_.td_smearing));
572  jB += std::get<1>(current_eckart(
573  position, particles, dens_param, DensityType::Baryon,
574  compute_gradient, out_par_.td_smearing));
575  jS += std::get<1>(current_eckart(
576  position, particles, dens_param, DensityType::Strangeness,
577  compute_gradient, out_par_.td_smearing));
578  }
579  if (enable_ascii_) {
580  *fp << jQ[0];
581  for (int l = 1; l < 4; l++) {
582  *fp << " " << jQ[l];
583  }
584  for (int l = 0; l < 4; l++) {
585  *fp << " " << jB[l];
586  }
587  for (int l = 0; l < 4; l++) {
588  *fp << " " << jS[l];
589  }
590  *fp << "\n";
591  }
592  if (enable_binary_) {
593  for (int l = 0; l < 4; l++) {
594  result = jQ[l];
595  fp->write(reinterpret_cast<char *>(&result), sizeof(double));
596  }
597  for (int l = 0; l < 4; l++) {
598  result = jB[l];
599  fp->write(reinterpret_cast<char *>(&result), sizeof(double));
600  }
601  for (int l = 0; l < 4; l++) {
602  result = jS[l];
603  fp->write(reinterpret_cast<char *>(&result), sizeof(double));
604  }
605  }
606  });
607 }
608 
610  const ThermodynamicQuantity tq,
611  RectangularLattice<EnergyMomentumTensor> &lattice, double ctime) {
612  if (!enable_output_) {
613  return;
614  }
615  double result;
616  const auto dim = lattice.n_cells();
617  std::shared_ptr<std::ofstream> fp(nullptr);
618  if (enable_ascii_) {
619  switch (tq) {
622  break;
625  break;
628  break;
629  default:
630  return;
631  }
632  *fp << std::setprecision(14);
633  *fp << std::scientific;
634  *fp << ctime << std::endl;
635  }
636  if (enable_binary_) {
637  switch (tq) {
640  break;
643  break;
646  break;
647  default:
648  return;
649  }
650  assert(sizeof(ctime) == sizeof(double));
651  fp->write(reinterpret_cast<char *>(&ctime), sizeof(double));
652  }
653  switch (tq) {
655  for (int i = 0; i < 4; i++) {
656  for (int j = i; j < 4; j++) {
657  lattice.iterate_sublattice(
658  {0, 0, 0}, dim,
659  [&](EnergyMomentumTensor &node, int ix, int, int) {
660  if (enable_ascii_) {
661  *fp << node[EnergyMomentumTensor::tmn_index(i, j)] << " ";
662  if (ix == dim[0] - 1) {
663  *fp << "\n";
664  }
665  }
666  if (enable_binary_) {
667  result = node[EnergyMomentumTensor::tmn_index(i, j)];
668  fp->write(reinterpret_cast<char *>(&result), sizeof(double));
669  }
670  });
671  }
672  }
673  break;
675  for (int i = 0; i < 4; i++) {
676  for (int j = i; j < 4; j++) {
677  lattice.iterate_sublattice(
678  {0, 0, 0}, dim,
679  [&](EnergyMomentumTensor &node, int ix, int, int) {
680  if (enable_ascii_) {
681  const FourVector u = node.landau_frame_4velocity();
682  const EnergyMomentumTensor Tmn_L = node.boosted(u);
683  *fp << Tmn_L[EnergyMomentumTensor::tmn_index(i, j)] << " ";
684  if (ix == dim[0] - 1) {
685  *fp << "\n";
686  }
687  }
688  if (enable_binary_) {
689  const FourVector u = node.landau_frame_4velocity();
690  const EnergyMomentumTensor Tmn_L = node.boosted(u);
691  result = Tmn_L[EnergyMomentumTensor::tmn_index(i, j)];
692  fp->write(reinterpret_cast<char *>(&result), sizeof(double));
693  }
694  });
695  }
696  }
697  break;
699  lattice.iterate_sublattice(
700  {0, 0, 0}, dim, [&](EnergyMomentumTensor &node, int, int, int) {
701  if (enable_ascii_) {
702  const FourVector u = node.landau_frame_4velocity();
703  const ThreeVector v = -u.velocity();
704  *fp << v.x1() << " " << v.x2() << " " << v.x3() << "\n";
705  }
706  if (enable_binary_) {
707  const FourVector u = node.landau_frame_4velocity();
708  ThreeVector v = -u.velocity();
709  fp->write(reinterpret_cast<char *>(&v), 3 * sizeof(double));
710  }
711  });
712  break;
713  default:
714  return;
715  }
716 }
717 
719  switch (tq) {
721  return 0;
723  return 1;
725  return 2;
727  return 3;
729  return 4;
730  default:
731  throw std::runtime_error(
732  "Error when converting a thermodynamic quantity "
733  "to an int, unknown quantity.");
734  }
735 }
736 
737 std::string ThermodynamicLatticeOutput::make_filename(const std::string &descr,
738  const int event_number,
739  const char type) {
740  char suffix[13];
741  assert((type == 'a') || (type == 'b'));
742  if (type == 'a') {
743  snprintf(suffix, sizeof(suffix), "_%07i.dat", event_number);
744  } else {
745  snprintf(suffix, sizeof(suffix), "_%07i.bin", event_number);
746  }
747  return base_path_.string() + std::string("/") + descr + std::string(suffix);
748 }
749 
751  const ThermodynamicQuantity tq, const DensityType dens_type) {
752  return std::string(to_string(dens_type)) + std::string("_") +
753  std::string(to_string(tq));
754 }
755 
757  std::shared_ptr<std::ofstream> fp, const ThermodynamicQuantity &tq) {
758  *fp << std::setprecision(2);
759  *fp << std::fixed;
760  *fp << "#Thermodynamic Lattice Output version: "
761  << ThermodynamicLatticeOutput::version << std::endl;
762  *fp << std::setprecision(6);
763  *fp << "#Quantity:"
764  << " " << std::string(to_string(tq)) << std::endl;
765  *fp << "#Grid dimensions: " << nodes_[0] << " " << nodes_[1] << " "
766  << nodes_[2] << std::endl;
767  *fp << "#Grid spacing: " << sizes_[0] << " " << sizes_[1] << " " << sizes_[2]
768  << std::endl;
769  *fp << "#Grid origin: " << origin_[0] << " " << origin_[1] << " "
770  << origin_[2] << std::endl;
771 }
772 
774  std::shared_ptr<std::ofstream> fp, const ThermodynamicQuantity &tq) {
775  auto variable_id = to_int(tq);
776  fp->write(
777  reinterpret_cast<const char *>(&ThermodynamicLatticeOutput::version),
778  sizeof(double));
779  fp->write(reinterpret_cast<char *>(&variable_id), sizeof(int));
780  fp->write(reinterpret_cast<char *>(&nodes_), sizeof(nodes_));
781  fp->write(reinterpret_cast<char *>(&sizes_), sizeof(sizes_));
782  fp->write(reinterpret_cast<char *>(&origin_), sizeof(origin_));
783 }
784 } // namespace smash
A class for time-efficient (time-memory trade-off) calculation of density on the lattice.
Definition: density.h:310
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)
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:481
ThreeVector velocity() const
Get the velocity (3-vector divided by zero component).
Definition: fourvector.h:328
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
const bf::path base_path_
filesystem path for output
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.
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)
ThermodynamicLatticeOutput(const bf::path &path, const std::string &name, const OutputParameters &out_par, const bool enable_ascii, const bool enable_binary)
Construct Output.
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
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:173
double x2() const
Definition: threevector.h:169
double x1() const
Definition: threevector.h:165
ThermodynamicQuantity
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)
Definition: density.cc:167
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?