openPMD_raytrace_API  0.1.0
openPMD_io.cc
Go to the documentation of this file.
1 #include "openPMD_io.hh"
2 #include <iostream>
3 #include <openPMD/openPMD.hpp> // openPMD C++ API
4 
5 #ifdef DEBUG
6 #define DEBUG_START(_METHOD_) \
7  std::cout << "[DEBUG][openPMD_io][" << _METHOD_ << "][START] " << std::endl;
8 #define DEBUG_END(_METHOD_) \
9  std::cout << "[DEBUG][openPMD_io][" << _METHOD_ << "][END] " << std::endl;
10 #define DEBUG_INFO(_METHOD_, _MSG_) \
11  std::cout << "[DEBUG][openPMD_io][" << _METHOD_ << "][INFO] " << _MSG_ << std::endl;
12 #else
13 #define DEBUG_START(_METHOD)
14 #define DEBUG_END(_METHOD_)
15 #define DEBUG_INFO(_METHOD_, _MSG_)
16 #endif
17 
18 #include <exception>
20 // using namespace raytracing;
21 // using raytracing::openPMD_io;
26 namespace raytracing {
27 // constexpr size_t CHUNK_SIZE = 10000;
28 constexpr size_t CHUNK_SIZE = 3;
29 } // namespace raytracing
30 
33 //------------------------------------------------------------
34 
35 //------------------------------------------------------------
36 raytracing::openPMD_io::openPMD_io(const std::string& filename, std::string mc_code_name,
37  std::string mc_code_version, std::string instrument_name,
38  std::string name_current_component):
39  //, int repeat):
40  _name(filename),
41  _mc_code_name(mc_code_name),
42  _mc_code_version(mc_code_version),
43  _instrument_name(instrument_name),
44  _name_current_component(name_current_component),
45  _i_repeat(0),
46  _n_repeat(1),
47  _offset({0}),
48  _series(nullptr){};
49 
50 //------------------------------------------------------------
51 void
52 raytracing::openPMD_io::init_ray_prop(std::string name, openPMD::Dataset& dataset, bool isScalar,
53  std::map<openPMD::UnitDimension, double> const& dims,
54  double unitSI) {
55  auto rays = rays_pmd();
56 
57  rays[name].setUnitDimension(dims);
58 
59  if (isScalar) {
60  rays[name][openPMD::RecordComponent::SCALAR].resetDataset(dataset);
61  rays[name][openPMD::RecordComponent::SCALAR].setUnitSI(unitSI);
62  } else {
63  // now define the RECORD_COMPONENT
64  for (auto dim : {"x", "y", "z"}) {
65  rays[name][dim].resetDataset(dataset);
66  rays[name][dim].setUnitSI(unitSI);
67  }
68  }
69 }
70 
71 //------------------------------------------------------------
79 void
80 raytracing::openPMD_io::init_rays(std::string particle_species, unsigned long long int n_rays,
81  unsigned int iter) {
82  _max_allowed_rays = n_rays;
83  _nrays = 0;
84 
85  DEBUG_START("INIT_RAYS")
86 
87  auto rays = rays_pmd(particle_species);
88 
89  // these are a single entry to mark some general properties of the particles
90  openPMD::Dataset dataset_single_float =
91  openPMD::Dataset(openPMD::Datatype::FLOAT, openPMD::Extent{1});
92  init_ray_prop("directionOfGravity", dataset_single_float, false);
93  init_ray_prop("horizontalCoordinate", dataset_single_float, false);
94  init_ray_prop("mass", dataset_single_float, true, {{openPMD::UnitDimension::M, 1.}});
95 
96  rays.setAttribute("speciesType", particle_species);
97  rays.setAttribute("PDGID", particle_species);
98  rays.setAttribute("numParticles", 0);
99 
100  openPMD::Dataset dataset_float =
101  openPMD::Dataset(openPMD::Datatype::FLOAT, openPMD::Extent{n_rays});
102  openPMD::Dataset dataset_int =
103  openPMD::Dataset(openPMD::Datatype::INT, openPMD::Extent{n_rays});
104  openPMD::Dataset dataset_ulongint =
105  openPMD::Dataset(openPMD::Datatype::ULONGLONG, openPMD::Extent{n_rays});
106 
107  init_ray_prop("position", dataset_float, false, {{openPMD::UnitDimension::L, 1.}}, 1e-2); //cm
108  init_ray_prop("direction", dataset_float, false);
109 
110  init_ray_prop("nonPhotonPolarization", dataset_float, false);
111  init_ray_prop("photonSPolarizationAmplitude", dataset_float, false);
112  init_ray_prop("photonSPolarizationPhase", dataset_float, true);
113  init_ray_prop("photonPPolarizationAmplitude", dataset_float, false);
114  init_ray_prop("photonPPolarizationPhase", dataset_float, true);
115 
116  init_ray_prop("wavelength", dataset_float, true, {{openPMD::UnitDimension::L, 1}},
117  1); // 1.6021766e-13); // MeV ///\todo which units?
118  init_ray_prop("weight", dataset_float, true);
119  init_ray_prop("rayTime", dataset_float, true, {{openPMD::UnitDimension::T, 1.}}, 1e-3); //ms
120 
121  init_ray_prop("id", dataset_ulongint, true);
122  init_ray_prop("particleStatus", dataset_int, true);
123 
124  DEBUG_END("INIT_RAYS")
125 }
126 
127 void
128 raytracing::openPMD_io::init_write(std::string particle_species, unsigned long long int n_rays,
129  unsigned int iter) {
130  _iter = iter;
131  std::string filename = _name;
132  // assign the global variable to keep track of it
133  _series = std::unique_ptr<openPMD::Series>(
134  new openPMD::Series(filename, openPMD::Access::CREATE));
135 
136  _series->setAuthor("openPMD raytracing API");
137  // latticeName: name of the instrument
138  // latticeFile: name of the instrument file
139  // branchIndex: unique index number assigned to the latice branch the[article is in.
140  // (it should be per particle
141  //
142 
143  DEBUG_INFO("init_write", "Filename: " << filename)
144 
145  auto i = iter_pmd(iter);
146  _series->flush();
147 
148  // openPMD::Record directionOfGravity;
150  // float directionOfGravity[3] = {0.,0.,0.}; // this ensures that the attribute is
151  // float type _series->setAttribute("directionOfGravity_X", directionOfGravity[0]);
152  //_series->setAttribute("directionOfGravity_Y", directionOfGravity[1]);
153  //_series->setAttribute("directionOfGravity_Z", directionOfGravity[2]);
154 
155  DEBUG_INFO("init_write", "Iter: " << _iter)
156 
157  // set the mccode, mccode_version, component name, instrument name
158 
159  init_rays(particle_species, n_rays, iter);
160  // openPMD::Record mass = rays["mass"];
161  // openPMD::RecordComponent mass_scalar = mass[openPMD::RecordComponent::SCALAR];
162 
163  // mass_scalar.resetDataset(dataset);
164 
165  _series->flush();
166  DEBUG_INFO("init_write", "flush done")
167 }
168 
169 //------------------------------------------------------------
170 template <typename T>
171 void
172 save_write_single(openPMD::ParticleSpecies& rays, std::string field, std::string record,
173  raytracing::openPMD_io::Rays::Record<T>& rec, openPMD::Offset& offset,
174  openPMD::Extent& extent) {
175  rays[field][record].storeChunk(openPMD::shareRaw(rec.vals()), offset, extent);
176  rays[field][record].setAttribute("minValue", rec.min());
177  rays[field][record].setAttribute("maxValue", rec.max());
178 }
179 //------------------------------------------------------------
180 
181 void
183  if (_rays.size() == 0) return;
184 
185  DEBUG_INFO("save_write",
186  "Number of saved rays: " << _rays.size() << "\t" << _rays._x.vals().size())
187 
188  auto rays = rays_pmd();
189  // this check is here and not in the trace_write because I believe that loosing time for a
190  // CHUNKSIZE simulating rays that are not store is much less frequent that.
191  if (_nrays + _rays.size() > _max_allowed_rays)
192  throw std::runtime_error("Maximum number of foreseen rays reached, stopping");
193 
194  // number of new rays being written
195 #ifdef DEBUG
196  assert(_nrays == _offset[0]);
197 #endif
198  _nrays += _rays.size();
199 
200  openPMD::Extent extent = {_rays.size()};
201 
202  save_write_single(rays, "position", "x", _rays._x, _offset, extent);
203  save_write_single(rays, "position", "y", _rays._y, _offset, extent);
204  save_write_single(rays, "position", "z", _rays._z, _offset, extent);
205 
206  save_write_single(rays, "direction", "x", _rays._dx, _offset, extent);
207  save_write_single(rays, "direction", "y", _rays._dy, _offset, extent);
208  save_write_single(rays, "direction", "z", _rays._dz, _offset, extent);
209 
210  save_write_single(rays, "nonPhotonPolarization", "x", _rays._sx, _offset, extent);
211  save_write_single(rays, "nonPhotonPolarization", "y", _rays._sy, _offset, extent);
212  save_write_single(rays, "nonPhotonPolarization", "z", _rays._sz, _offset, extent);
213 
214  save_write_single(rays, "photonSPolarizationAmplitude", "x", _rays._sPolAx, _offset,
215  extent);
216  save_write_single(rays, "photonSPolarizationAmplitude", "y", _rays._sPolAy, _offset,
217  extent);
218  save_write_single(rays, "photonSPolarizationAmplitude", "z", _rays._sPolAz, _offset,
219  extent);
220  save_write_single(rays, "photonSPolarizationPhase", openPMD::RecordComponent::SCALAR,
221  _rays._sPolPh, _offset, extent);
222 
223  save_write_single(rays, "photonPPolarizationAmplitude", "x", _rays._pPolAx, _offset,
224  extent);
225  save_write_single(rays, "photonPPolarizationAmplitude", "y", _rays._pPolAy, _offset,
226  extent);
227  save_write_single(rays, "photonPPolarizationAmplitude", "z", _rays._pPolAz, _offset,
228  extent);
229  save_write_single(rays, "photonPPolarizationPhase", openPMD::RecordComponent::SCALAR,
230  _rays._pPolPh, _offset, extent);
231 
232  save_write_single(rays, "rayTime", openPMD::RecordComponent::SCALAR, _rays._time, _offset,
233  extent);
234  save_write_single(rays, "wavelength", openPMD::RecordComponent::SCALAR, _rays._wavelength,
235  _offset, extent);
236  save_write_single(rays, "weight", openPMD::RecordComponent::SCALAR, _rays._weight, _offset,
237  extent);
238 
239  save_write_single(rays, "id", openPMD::RecordComponent::SCALAR, _rays._id, _offset, extent);
240  save_write_single(rays, "particleStatus", openPMD::RecordComponent::SCALAR, _rays._status,
241  _offset, extent);
242 
243  rays.setAttribute("numParticles", _nrays);
244 
245  _series->flush();
246  _rays.clear_chunk();
247 
248  for (size_t i = 0; i < extent.size(); ++i)
249  _offset[i] += extent[i];
250 }
251 
252 //------------------------------------------------------------
253 //------------------------------------------------------------
254 template <typename T>
255 void
256 read_single(openPMD::ParticleSpecies& rays, std::string field, std::string record,
257  raytracing::openPMD_io::Rays::Record<T>& rec, openPMD::Offset& offset,
258  openPMD::Extent& chunk_size) {
259 
260  auto data = rays[field][record];
261  rec.vals().reserve(chunk_size[0]);
262  rec.vals().resize(chunk_size[0]);
263  data.loadChunk<T>(openPMD::shareRaw(rec.vals()), offset,
264  chunk_size); // data.loadChunk<T>(offset, chunk_size);
265  // if (field == "position") {
266  // for (auto i = 0; i < chunk_size[0]; ++i) {
267  // std::cout << "Data " << record << ": " << i << "\t" << rec.vals()[i] << "\t"
268  // << rec.vals().size() << std::endl;
269  // }
270  // }
271  // rec.store((ddata.get()), chunk_size[0], //
272  // rays[field][record].getAttribute("minValue").get<float>(), //
273  // rays[field][record].getAttribute("maxValue").get<float>());
274 }
275 //------------------------------------------------------------
276 
277 void
278 raytracing::openPMD_io::load_chunk(void) {
279 
280  _rays.clear(); // Necessary to set _read to zero
281  auto rays = rays_pmd();
282  DEBUG_START("load_chunk")
283 
284  unsigned long long int remaining = _nrays - _offset[0];
285  openPMD::Extent chunk_size = {remaining > raytracing::CHUNK_SIZE ? raytracing::CHUNK_SIZE
286  : remaining};
287  DEBUG_INFO("load_chunk",
288  _nrays << "\t" << _offset[0] << "\t" << remaining << "\t" << chunk_size[0])
289  DEBUG_INFO("load_chunk",
290  " Loading chunk of size " << chunk_size[0] << "; file contains " << _nrays)
291  /* I don't understand....
292  * the data type info is embedded in the data... so why do we need to declare
293  * loadChunk<float>? it should overload to the right function... and return the correct
294  * datatype.
295  */
296  read_single(rays, "position", "x", _rays._x, _offset, chunk_size);
297  read_single(rays, "position", "y", _rays._y, _offset, chunk_size);
298  read_single(rays, "position", "z", _rays._z, _offset, chunk_size);
299 
300  read_single(rays, "direction", "x", _rays._dx, _offset, chunk_size);
301  read_single(rays, "direction", "y", _rays._dy, _offset, chunk_size);
302  read_single(rays, "direction", "z", _rays._dz, _offset, chunk_size);
303 
304  read_single(rays, "nonPhotonPolarization", "x", _rays._sx, _offset, chunk_size);
305  read_single(rays, "nonPhotonPolarization", "y", _rays._sy, _offset, chunk_size);
306  read_single(rays, "nonPhotonPolarization", "z", _rays._sz, _offset, chunk_size);
307 
308  read_single(rays, "photonSPolarizationAmplitude", "x", _rays._sPolAx, _offset, chunk_size);
309  read_single(rays, "photonSPolarizationAmplitude", "y", _rays._sPolAy, _offset, chunk_size);
310  read_single(rays, "photonSPolarizationAmplitude", "z", _rays._sPolAz, _offset, chunk_size);
311  read_single(rays, "photonSPolarizationPhase", openPMD::RecordComponent::SCALAR,
312  _rays._sPolPh, _offset, chunk_size);
313 
314  read_single(rays, "photonPPolarizationAmplitude", "x", _rays._pPolAx, _offset, chunk_size);
315  read_single(rays, "photonPPolarizationAmplitude", "y", _rays._pPolAy, _offset, chunk_size);
316  read_single(rays, "photonPPolarizationAmplitude", "z", _rays._pPolAz, _offset, chunk_size);
317  read_single(rays, "photonPPolarizationPhase", openPMD::RecordComponent::SCALAR,
318  _rays._pPolPh, _offset, chunk_size);
319 
320  read_single(rays, "rayTime", openPMD::RecordComponent::SCALAR, _rays._time, _offset,
321  chunk_size);
322  read_single(rays, "wavelength", openPMD::RecordComponent::SCALAR, _rays._wavelength,
323  _offset, chunk_size);
324  read_single(rays, "weight", openPMD::RecordComponent::SCALAR, _rays._weight, _offset,
325  chunk_size);
326 
327  read_single(rays, "id", openPMD::RecordComponent::SCALAR, _rays._id, _offset, chunk_size);
328  read_single(rays, "particleStatus", openPMD::RecordComponent::SCALAR, _rays._status,
329  _offset, chunk_size);
330 
331  _rays.size(chunk_size[0]);
332  DEBUG_INFO("load_chunk", "Before flush")
333  _series->flush();
334  DEBUG_INFO("load_chunk", "After flush")
335 
336  // std::cout << _rays._x[0] << "\t" << _rays._x[2] << std::endl;
337  for (size_t i = 0; i < chunk_size.size(); ++i)
338  _offset[i] += chunk_size[i];
339  DEBUG_END("load_chunk")
340 }
341 
342 unsigned long long int
343 raytracing::openPMD_io::init_read(std::string particle_species, unsigned int iter,
344  unsigned long long int n_rays, unsigned int repeat) {
345 
346  _n_repeat = repeat;
347  _i_repeat = 0;
348  _iter = iter;
349  _offset = {0};
350  std::string filename = _name;
351 
352  // assign the global variable to keep track of it
353  _series = std::unique_ptr<openPMD::Series>(new openPMD::Series(
354  filename,
355  openPMD::Access::READ_ONLY));
356 
358  std::cout << "File information: " << filename << std::endl;
359  if (_series->containsAttribute("author"))
360  std::cout << " Author : " << _series->author() << std::endl;
361  std::cout << " Filename: " << filename << std::endl;
362  std::cout << " Number of iterations: " << _series->iterations.size() << std::endl;
363 
364  if (_series->iterations.size() == 0)
365  std::cout << " ERROR, no iterations found in openPMD series" << std::endl;
366 
368 
369  // check the maximum number of rays stored
370  _rays.clear(); // Necessary to set _read to zero
371 
372  auto i = iter_pmd(_iter);
373  _series->flush();
374  auto rays = rays_pmd(particle_species);
375  _nrays = rays.getAttribute("numParticles").get<unsigned long long int>();
376  std::cout << "numParticles: " << _nrays << std::endl;
377  if (n_rays > _nrays) {
378  std::cerr << "[ERROR] Requested a number of rays that is not available in "
379  "the "
380  "current file"
381  << std::endl;
382  throw std::runtime_error("ERROR");
383  }
384  if (n_rays != 0) {
385  std::cout << "[WARNING] Requested " << n_rays
386  << ", while available in file: " << _nrays << std::endl;
387  _nrays = n_rays;
388  }
389  _series->flush();
390  return _nrays;
391 }
392 
393 void
395  if (_rays.size() == CHUNK_SIZE) {
396 
397  DEBUG_INFO("trace_write",
398  "Reached CHUNK_SIZE:\toff=" << _offset[0] << "\tsize=" << _rays.size()
399  << "\tmax=" << _max_allowed_rays)
400 
401  save_write();
402  _rays.clear_chunk(); // clear the vector content but not the min-max values
403  }
404  _rays.push(this_ray);
405 }
406 
410  DEBUG_INFO("trace_read", "---- i_repeat=" << _i_repeat << "\tn_repeat=" << _n_repeat
411  << "\tis_chunk_finished=" << std::boolalpha
412  << _rays.is_chunk_finished())
413  if (_i_repeat++ == 0) {
414  if (_rays.is_chunk_finished()) { load_chunk(); }
415  _last_ray = _rays.pop();
416  }
417  if (_i_repeat >= _n_repeat) _i_repeat = 0;
418 
419  DEBUG_INFO("trace_read", "Ray: " << _last_ray)
420  return _last_ray;
421 }
422 
423 void
424 raytracing::openPMD_io::set_gravity_direction(float x, float y, float z) {
425  auto rays = rays_pmd();
426  openPMD::Offset offset = {0};
427  openPMD::Extent extent = {1};
428  rays["directionOfGravity"]["x"].storeChunk(openPMD::shareRaw(&x), offset, extent);
429  rays["directionOfGravity"]["y"].storeChunk(openPMD::shareRaw(&y), offset, extent);
430  rays["directionOfGravity"]["z"].storeChunk(openPMD::shareRaw(&z), offset, extent);
431  _series->flush();
432 }
433 
434 void
435 raytracing::openPMD_io::get_gravity_direction(float* x, float* y, float* z) {
436  auto rays = rays_pmd();
437  auto xx = rays["directionOfGravity"]["x"].loadChunk<float>();
438  auto yy = rays["directionOfGravity"]["y"].loadChunk<float>();
439  auto zz = rays["directionOfGravity"]["z"].loadChunk<float>();
440  _series->flush();
441  *x = xx.get()[0];
442  *y = yy.get()[0];
443  *z = zz.get()[0];
444  // std::cout << "[DEBUG] " << *x << std::endl;
445 }
446 
447 void
448 raytracing::openPMD_io::get_horizontal_direction(float* x, float* y, float* z) {
449  auto rays = rays_pmd();
450  auto xx = rays["horizontalCoordinate"]["x"].loadChunk<float>();
451  auto yy = rays["horizontalCoordinate"]["y"].loadChunk<float>();
452  auto zz = rays["horizontalCoordinate"]["z"].loadChunk<float>();
453  _series->flush();
454  *x = xx.get()[0];
455  *y = yy.get()[0];
456  *z = zz.get()[0];
457 }
I/O API for the ray trace extension of the openPMD format.
Definition: openPMD_io.hh:20
void init_write(std::string particle_species, unsigned long long int n_rays, unsigned int iter=1)
initializes the "series" object from the openPMD API in WRITE MODE
Definition: openPMD_io.cc:128
template utility class to simplify implementation It is a vector that also stores min and max values ...
Definition: openPMD_io.hh:53
Generic ray, containing all the ray information being stored by the API into the openPMD file...
Definition: ray.hh:39
defines the maximum number of rays that can be stored in memory before dumping to file ...
Definition: openPMD_io.hh:10
void trace_write(Ray this_ray)
save ray properties for further writing to file by save_write()
Definition: openPMD_io.cc:394
void init_rays(std::string particle_species, unsigned long long int n_rays, unsigned int iter)
declare the ray particle species in the file
Definition: openPMD_io.cc:80
Ray trace_read(void)
Read rays from file and returns the next in the list.
Definition: openPMD_io.cc:408
void save_write(void)
Flushes the output to file before closing it.
Definition: openPMD_io.cc:182
openPMD_io(const std::string &filename, const std::string mc_code_name="", const std::string mc_code_version="", const std::string instrument_name="", const std::string name_current_component="")
constructor
Definition: openPMD_io.cc:36