Version: SMASH-3.3
vtkoutput.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2014-2022,2024-2025
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
10 #include "smash/vtkoutput.h"
11 
12 #include <fstream>
13 #include <memory>
14 #include <utility>
15 
16 #include "smash/clock.h"
17 #include "smash/config.h"
18 #include "smash/file.h"
20 #include "smash/particles.h"
21 
22 namespace smash {
23 
24 VtkOutput::VtkOutput(const std::filesystem::path &path, const std::string &name,
25  const OutputParameters &out_par)
26  : OutputInterface(name),
27  base_path_(std::move(path)),
28  is_thermodynamics_output_(name == "Thermodynamics"),
29  is_fields_output_(name == "Fields") {
30  if (out_par.part_extended) {
31  logg[LOutput].warn()
32  << "Creating VTK output: There is no extended VTK format.";
33  }
34 }
35 
37 
65 void VtkOutput::at_eventstart(const Particles &particles,
66  const EventLabel &event_label,
67  const EventInfo &) {
73 
74  current_event_ = event_label.event_number;
75  current_ensemble_ = event_label.ensemble_number;
78  write(particles);
80  }
81 }
82 
83 void VtkOutput::at_eventend(const Particles & /*particles*/,
84  const EventLabel & /*event_number*/,
85  const EventInfo &) {}
86 
88  const std::unique_ptr<Clock> &,
89  const DensityParameters &,
90  const EventLabel &event_label,
91  const EventInfo &) {
92  current_event_ = event_label.event_number;
93  current_ensemble_ = event_label.ensemble_number;
95  write(particles);
97  }
98 }
99 
100 void VtkOutput::write(const Particles &particles) {
101  char filename[64];
102  snprintf(filename, sizeof(filename), "pos_ev%05i_ens%05i_tstep%05i.vtk",
105  FilePtr file_{std::fopen((base_path_ / filename).native().c_str(), "w")};
106 
107  /* Legacy VTK file format */
108  std::fprintf(file_.get(), "# vtk DataFile Version 2.0\n");
109  std::fprintf(file_.get(), "Generated from molecular-offset data %s\n",
110  SMASH_VERSION);
111  std::fprintf(file_.get(), "ASCII\n");
112 
113  /* Unstructured data sets are composed of points, lines, polygons, .. */
114  std::fprintf(file_.get(), "DATASET UNSTRUCTURED_GRID\n");
115  std::fprintf(file_.get(), "POINTS %zu double\n", particles.size());
116  for (const auto &p : particles) {
117  std::fprintf(file_.get(), "%g %g %g\n", p.position().x1(),
118  p.position().x2(), p.position().x3());
119  }
120  std::fprintf(file_.get(), "CELLS %zu %zu\n", particles.size(),
121  particles.size() * 2);
122  for (size_t point_index = 0; point_index < particles.size(); point_index++) {
123  std::fprintf(file_.get(), "1 %zu\n", point_index);
124  }
125  std::fprintf(file_.get(), "CELL_TYPES %zu\n", particles.size());
126  for (size_t point_index = 0; point_index < particles.size(); point_index++) {
127  std::fprintf(file_.get(), "1\n");
128  }
129  std::fprintf(file_.get(), "POINT_DATA %zu\n", particles.size());
130  std::fprintf(file_.get(), "SCALARS pdg_codes int 1\n");
131  std::fprintf(file_.get(), "LOOKUP_TABLE default\n");
132  for (const auto &p : particles) {
133  std::fprintf(file_.get(), "%s\n", p.pdgcode().string().c_str());
134  }
135  std::fprintf(file_.get(), "SCALARS is_formed int 1\n");
136  std::fprintf(file_.get(), "LOOKUP_TABLE default\n");
137  double current_time = particles.time();
138  for (const auto &p : particles) {
139  std::fprintf(file_.get(), "%s\n",
140  (p.formation_time() > current_time) ? "0" : "1");
141  }
142  std::fprintf(file_.get(), "SCALARS cross_section_scaling_factor double 1\n");
143  std::fprintf(file_.get(), "LOOKUP_TABLE default\n");
144  for (const auto &p : particles) {
145  std::fprintf(file_.get(), "%g\n", p.xsec_scaling_factor());
146  }
147  std::fprintf(file_.get(), "SCALARS mass double 1\n");
148  std::fprintf(file_.get(), "LOOKUP_TABLE default\n");
149  for (const auto &p : particles) {
150  std::fprintf(file_.get(), "%g\n", p.effective_mass());
151  }
152  std::fprintf(file_.get(), "SCALARS N_coll int 1\n");
153  std::fprintf(file_.get(), "LOOKUP_TABLE default\n");
154  for (const auto &p : particles) {
155  std::fprintf(file_.get(), "%i\n", p.get_history().collisions_per_particle);
156  }
157  std::fprintf(file_.get(), "SCALARS particle_ID int 1\n");
158  std::fprintf(file_.get(), "LOOKUP_TABLE default\n");
159  for (const auto &p : particles) {
160  std::fprintf(file_.get(), "%i\n", p.id());
161  }
162  std::fprintf(file_.get(), "SCALARS baryon_number int 1\n");
163  std::fprintf(file_.get(), "LOOKUP_TABLE default\n");
164  for (const auto &p : particles) {
165  std::fprintf(file_.get(), "%i\n", p.pdgcode().baryon_number());
166  }
167  std::fprintf(file_.get(), "SCALARS strangeness int 1\n");
168  std::fprintf(file_.get(), "LOOKUP_TABLE default\n");
169  for (const auto &p : particles) {
170  std::fprintf(file_.get(), "%i\n", p.pdgcode().strangeness());
171  }
172  std::fprintf(file_.get(), "VECTORS momentum double\n");
173  for (const auto &p : particles) {
174  std::fprintf(file_.get(), "%g %g %g\n", p.momentum().x1(),
175  p.momentum().x2(), p.momentum().x3());
176  }
177 }
178 
187 template <typename T>
188 void VtkOutput::write_vtk_header(std::ofstream &file,
189  RectangularLattice<T> &lattice,
190  const std::string &description) {
191  const auto dim = lattice.n_cells();
192  const auto cs = lattice.cell_sizes();
193  const auto orig = lattice.origin();
194  file << "# vtk DataFile Version 2.0\n"
195  << description << "\n"
196  << "ASCII\n"
197  << "DATASET STRUCTURED_POINTS\n"
198  << "DIMENSIONS " << dim[0] << " " << dim[1] << " " << dim[2] << "\n"
199  << "SPACING " << cs[0] << " " << cs[1] << " " << cs[2] << "\n"
200  << "ORIGIN " << orig[0] << " " << orig[1] << " " << orig[2] << "\n"
201  << "POINT_DATA " << lattice.size() << "\n";
202 }
203 
204 template <typename T, typename F>
205 void VtkOutput::write_vtk_scalar(std::ofstream &file,
206  RectangularLattice<T> &lattice,
207  const std::string &varname, F &&get_quantity) {
208  file << "SCALARS " << varname << " double 1\n"
209  << "LOOKUP_TABLE default\n";
210  file << std::setprecision(3);
211  file << std::fixed;
212  const auto dim = lattice.n_cells();
213  lattice.iterate_sublattice({0, 0, 0}, dim, [&](T &node, int ix, int, int) {
214  const double f_from_node = get_quantity(node);
215  file << f_from_node << " ";
216  if (ix == dim[0] - 1) {
217  file << "\n";
218  }
219  });
220 }
221 
222 template <typename T, typename F>
223 void VtkOutput::write_vtk_vector(std::ofstream &file,
224  RectangularLattice<T> &lattice,
225  const std::string &varname, F &&get_quantity) {
226  file << "VECTORS " << varname << " double\n";
227  file << std::setprecision(3);
228  file << std::fixed;
229  const auto dim = lattice.n_cells();
230  lattice.iterate_sublattice({0, 0, 0}, dim, [&](T &node, int, int, int) {
231  const ThreeVector v = get_quantity(node);
232  file << v.x1() << " " << v.x2() << " " << v.x3() << "\n";
233  });
234 }
235 
236 std::string VtkOutput::make_filename(const std::string &descr, int counter) {
237  char suffix[22];
238  snprintf(suffix, sizeof(suffix), "_%05i_tstep%05i.vtk", current_event_,
239  counter);
240  return base_path_.string() + std::string("/") + descr + std::string(suffix);
241 }
242 
244  const DensityType dens_type) {
245  return std::string(to_string(dens_type)) + std::string("_") +
246  std::string(to_string(tq));
247 }
248 
250  const ThermodynamicQuantity tq, const DensityType dens_type,
253  return;
254  }
255  std::ofstream file;
256  const std::string varname = make_varname(tq, dens_type);
257  file.open(make_filename(varname, vtk_density_output_counter_), std::ios::out);
258  write_vtk_header(file, lattice, varname);
259  write_vtk_scalar(file, lattice, varname,
260  [&](DensityOnLattice &node) { return node.rho(); });
262 }
263 
279  const ThermodynamicQuantity tq, const DensityType dens_type,
282  return;
283  }
284  std::ofstream file;
285  const std::string varname = make_varname(tq, dens_type);
286 
287  if (tq == ThermodynamicQuantity::Tmn) {
288  file.open(make_filename(varname, vtk_tmn_output_counter_++), std::ios::out);
289  write_vtk_header(file, Tmn_lattice, varname);
290  for (int i = 0; i < 4; i++) {
291  for (int j = i; j < 4; j++) {
292  write_vtk_scalar(file, Tmn_lattice,
293  varname + std::to_string(i) + std::to_string(j),
294  [&](EnergyMomentumTensor &node) {
295  return node[EnergyMomentumTensor::tmn_index(i, j)];
296  });
297  }
298  }
299  } else if (tq == ThermodynamicQuantity::TmnLandau) {
300  file.open(make_filename(varname, vtk_tmn_landau_output_counter_++),
301  std::ios::out);
302  write_vtk_header(file, Tmn_lattice, varname);
303  for (int i = 0; i < 4; i++) {
304  for (int j = i; j < 4; j++) {
305  write_vtk_scalar(file, Tmn_lattice,
306  varname + std::to_string(i) + std::to_string(j),
307  [&](EnergyMomentumTensor &node) {
308  const FourVector u = node.landau_frame_4velocity();
309  const EnergyMomentumTensor Tmn_L = node.boosted(u);
310  return Tmn_L[EnergyMomentumTensor::tmn_index(i, j)];
311  });
312  }
313  }
314  } else {
315  file.open(make_filename(varname, vtk_v_landau_output_counter_++),
316  std::ios::out);
317  write_vtk_header(file, Tmn_lattice, varname);
318  write_vtk_vector(file, Tmn_lattice, varname,
319  [&](EnergyMomentumTensor &node) {
320  const FourVector u = node.landau_frame_4velocity();
321  return -u.velocity();
322  });
323  }
324 }
325 
327  const std::string name1, const std::string name2,
328  RectangularLattice<std::pair<ThreeVector, ThreeVector>> &lat) {
329  if (!is_fields_output_) {
330  return;
331  }
332  std::ofstream file1;
333  file1.open(make_filename(name1, vtk_fields_output_counter_), std::ios::out);
334  write_vtk_header(file1, lat, name1);
336  file1, lat, name1,
337  [&](std::pair<ThreeVector, ThreeVector> &node) { return node.first; });
338  std::ofstream file2;
339  file2.open(make_filename(name2, vtk_fields_output_counter_), std::ios::out);
340  write_vtk_header(file2, lat, name2);
342  file2, lat, name2,
343  [&](std::pair<ThreeVector, ThreeVector> &node) { return node.second; });
345 }
346 
349  return;
350  }
351  std::ofstream file;
352  file.open(make_filename("fluidization_td", vtk_fluidization_counter_++),
353  std::ios::out);
354  write_vtk_header(file, gct.lattice(), "fluidization_td");
355  write_vtk_scalar(file, gct.lattice(), "e",
356  [&](ThermLatticeNode &node) { return node.e(); });
357  write_vtk_scalar(file, gct.lattice(), "p",
358  [&](ThermLatticeNode &node) { return node.p(); });
359  write_vtk_vector(file, gct.lattice(), "v",
360  [&](ThermLatticeNode &node) { return node.v(); });
361  write_vtk_scalar(file, gct.lattice(), "T",
362  [&](ThermLatticeNode &node) { return node.T(); });
363  write_vtk_scalar(file, gct.lattice(), "mub",
364  [&](ThermLatticeNode &node) { return node.mub(); });
365  write_vtk_scalar(file, gct.lattice(), "mus",
366  [&](ThermLatticeNode &node) { return node.mus(); });
367 }
368 
369 } // namespace smash
A class for time-efficient (time-memory trade-off) calculation of density on the lattice.
Definition: density.h:299
double rho(const double norm_factor=1.0)
Compute the net Eckart density on the local lattice.
Definition: density.h:368
A class to pre-calculate and store parameters relevant for density calculation.
Definition: density.h:92
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.
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
ThreeVector velocity() const
Get the velocity (3-vector divided by zero component).
Definition: fourvector.h:333
The GrandCanThermalizer class implements the following functionality:
RectangularLattice< ThermLatticeNode > & lattice() const
Getter function for the lattice.
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
double time() const
Returns the time of the computational frame.
Definition: particles.h:100
size_t size() const
Definition: particles.h:87
A container class to hold all the arrays on the lattice and access them.
Definition: lattice.h:49
const std::array< double, 3 > & origin() const
Definition: lattice.h:165
const std::array< int, 3 > & n_cells() const
Definition: lattice.h:159
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:581
std::size_t size() const
Definition: lattice.h:190
const std::array< double, 3 > & cell_sizes() const
Definition: lattice.h:162
The ThermLatticeNode class is intended to compute thermodynamical quantities in a cell given a set of...
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
void write_vtk_scalar(std::ofstream &file, RectangularLattice< T > &lat, const std::string &varname, F &&function)
Write a VTK scalar.
Definition: vtkoutput.cc:205
int vtk_density_output_counter_
Number of density lattice vtk output in current event.
Definition: vtkoutput.h:202
void fields_output(const std::string name1, const std::string name2, RectangularLattice< std::pair< ThreeVector, ThreeVector >> &lat) override
Write fields in vtk output Fields are a pair of threevectors for example electric and magnetic field.
Definition: vtkoutput.cc:326
bool is_fields_output_
Is the VTK output an output for fields.
Definition: vtkoutput.h:216
std::pair< int, int > counter_key()
Create the key to access the vtk_output_counter_ map.
Definition: vtkoutput.h:183
void write(const Particles &particles)
Write the given particles to the output.
Definition: vtkoutput.cc:100
int vtk_fluidization_counter_
Number of fluidization output.
Definition: vtkoutput.h:210
int current_event_
Event number.
Definition: vtkoutput.h:191
VtkOutput(const std::filesystem::path &path, const std::string &name, const OutputParameters &out_par)
Create a new VTK output.
Definition: vtkoutput.cc:24
int current_ensemble_
Ensemble number.
Definition: vtkoutput.h:193
void write_vtk_header(std::ofstream &file, RectangularLattice< T > &lat, const std::string &description)
Write the VTK header.
Definition: vtkoutput.cc:188
int vtk_fields_output_counter_
Number of fields output in current event.
Definition: vtkoutput.h:212
void write_vtk_vector(std::ofstream &file, RectangularLattice< T > &lat, const std::string &varname, F &&function)
Write a VTK vector.
Definition: vtkoutput.cc:223
std::map< std::pair< int, int >, int > vtk_output_counter_
Counters to keep track of time steps per event and per ensemble.
Definition: vtkoutput.h:199
void at_eventend(const Particles &particles, const EventLabel &event_label, const EventInfo &event) override
Writes the final particle information list of an event to the VTK output.
Definition: vtkoutput.cc:83
std::string make_varname(const ThermodynamicQuantity tq, const DensityType dens_type)
Make a variable name given quantity and density type.
Definition: vtkoutput.cc:243
bool is_thermodynamics_output_
Is the VTK output a thermodynamics output.
Definition: vtkoutput.h:214
int vtk_tmn_landau_output_counter_
Number of Landau frame energy-momentum tensor vtk output in current event.
Definition: vtkoutput.h:206
void thermodynamics_output(const ThermodynamicQuantity tq, const DensityType dt, RectangularLattice< DensityOnLattice > &lattice) override
Prints the density lattice in VTK format on a grid.
Definition: vtkoutput.cc:249
int vtk_v_landau_output_counter_
Number of Landau rest frame velocity vtk output in current event.
Definition: vtkoutput.h:208
void at_intermediate_time(const Particles &particles, const std::unique_ptr< Clock > &clock, const DensityParameters &dens_param, const EventLabel &event_label, const EventInfo &event) override
Writes out all current particles.
Definition: vtkoutput.cc:87
const std::filesystem::path base_path_
filesystem path for output
Definition: vtkoutput.h:188
void at_eventstart(const Particles &particles, const EventLabel &event_label, const EventInfo &event) override
Writes the initial particle information list of an event to the VTK output.
Definition: vtkoutput.cc:65
std::string make_filename(const std::string &description, int counter)
Make a file name given a description and a counter.
Definition: vtkoutput.cc:236
int vtk_tmn_output_counter_
Number of energy-momentum tensor lattice vtk output in current event.
Definition: vtkoutput.h:204
ThermodynamicQuantity
Represents thermodynamic quantities that can be printed out See user guide description for more infor...
@ Tmn
Energy-momentum tensor in lab frame.
@ TmnLandau
Energy-momentum tensor in Landau rest frame.
DensityType
Allows to choose which kind of density to calculate.
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
Definition: logging.cc:40
constexpr int p
Proton.
Definition: action.h:24
std::unique_ptr< std::FILE, FileDeleter > FilePtr
A RAII type to replace std::FILE *.
Definition: file.h:61
std::string to_string(ThermodynamicQuantity quantity)
Convert a ThermodynamicQuantity enum value to its corresponding string.
Definition: stringify.cc:26
FilePtr fopen(const std::filesystem::path &filename, const std::string &mode)
Open a file with given mode.
Definition: file.cc:14
static constexpr int LOutput
Structure to contain custom data for output.
Structure to contain information about the event and ensemble numbers.
int32_t ensemble_number
The number of the ensemble.
int32_t event_number
The number of the event.
Helper structure for Experiment to hold output options and parameters.
bool part_extended
Extended format for particles output.