11/*
2- Draft EXP ascii particle phase-space data HDF5 converter
2+ EXP ascii particle phase-space data HDF5 converter
33
44This is a possible template for implementing HDF5 input files for
55EXP. The code reads an ASCII file with particle data and writes it to
@@ -71,9 +71,11 @@ style by porting over the ascii_to_hdf5 routine().
7171#include < filesystem>
7272#include < iostream>
7373#include < iomanip>
74+ #include < cstdlib>
7475#include < fstream>
7576#include < sstream>
7677#include < chrono>
78+ #include < cmath>
7779#include < vector>
7880#include < stdexcept>
7981#include < variant>
@@ -126,9 +128,10 @@ void parse_particle_line(const std::string& line,
126128 T val;
127129
128130 // Parse core PSP fields
129- if (!(iss >> data.m [particle_idx]
130- >> data.x [particle_idx] >> data.y [particle_idx] >> data.z [particle_idx]
131- >> data.u [particle_idx] >> data.v [particle_idx] >> data.w [particle_idx])) {
131+ if (!(iss
132+ >> data.m [particle_idx]
133+ >> data.x [particle_idx] >> data.y [particle_idx] >> data.z [particle_idx]
134+ >> data.u [particle_idx] >> data.v [particle_idx] >> data.w [particle_idx])) {
132135 throw std::runtime_error (" Failed to parse core fields at particle " +
133136 std::to_string (particle_idx));
134137 }
@@ -269,7 +272,8 @@ void ascii_to_hdf5_impl(const std::string& ascii_file,
269272 // Define compression filters
270273 DataSetCreateProps props;
271274 hsize_t chunk = static_cast <hsize_t >(std::max (num_particles / 10 , 1024 ));
272- if (chunk > static_cast <hsize_t >(num_particles)) chunk = static_cast <hsize_t >(num_particles);
275+ if (chunk > static_cast <hsize_t >(num_particles))
276+ chunk = static_cast <hsize_t >(num_particles);
273277 props.add (Chunking (std::vector<hsize_t >{chunk}));
274278 props.add (Shuffle ());
275279 props.add (Deflate (4 )); // This is a good compromise between
@@ -334,20 +338,22 @@ struct ParticleDataVariant
334338// Detect float precision by inspecting dataset type
335339FloatPrecision detect_precision (const DataSet& dataset)
336340{
337- auto datatype = dataset.getDataType ();
338- auto class_type = datatype.getClass ();
341+ const auto datatype = dataset.getDataType ();
342+ if (datatype.getClass () != DataTypeClass::Float) {
343+ throw std::runtime_error (" Unexpected dataset type for precision detection (expected float)" );
344+ }
339345
340346 // Get the size in bytes
341- size_t type_size = datatype.getSize ();
347+ const size_t type_size = datatype.getSize ();
342348
343349 // Float32 is 4 bytes, Float64 is 8 bytes
344350 if (type_size == 4 ) {
345351 return FloatPrecision::FLOAT32 ;
346352 } else if (type_size == 8 ) {
347353 return FloatPrecision::FLOAT64 ;
348- } else {
349- throw std::runtime_error (" Unexpected float type size: " + std::to_string (type_size));
350354 }
355+
356+ throw std::runtime_error (" Unexpected float type size: " + std::to_string (type_size));
351357}
352358
353359
@@ -374,8 +380,7 @@ ParticleDataVariant read_hdf5_data(const std::string& hdf5_file)
374380 data.num_aux_floats = num_aux_floats;
375381 data.precision = precision;
376382
377- std::string precision_str = (precision == FloatPrecision::FLOAT32 ) ? " float32" : " float64" ;
378- std::cout << " Detected precision: " << precision_str << std::endl;
383+ // Precision is available in data.precision; caller decides whether to print it.
379384
380385 // Lambda to read float or double based on precision
381386 auto read_dataset = [&particles_group, precision](const std::string& name) -> FloatData {
@@ -388,9 +393,11 @@ ParticleDataVariant read_hdf5_data(const std::string& hdf5_file)
388393
389394 // Read core PSP fields
390395 data.m = read_dataset (" m" );
396+
391397 data.x = read_dataset (" x" );
392398 data.y = read_dataset (" y" );
393399 data.z = read_dataset (" z" );
400+
394401 data.u = read_dataset (" u" );
395402 data.v = read_dataset (" v" );
396403 data.w = read_dataset (" w" );
@@ -627,10 +634,14 @@ precision is used.
627634
628635 std::string line_orig, line_rest;
629636 size_t line_num = 0 ;
630- bool mismatch_found = false ;
631-
637+
632638 std::vector<double > max_diff (7 , 0.0 ); // For m, x, y, z, u, v, w
633639 std::vector<double > vec_orig (7 ), vec_rest (7 );
640+ std::vector<double > max_aux_int_diff;
641+ std::vector<double > max_aux_float_diff;
642+ std::vector<int > aux_int_orig, aux_int_rest;
643+ std::vector<double > aux_float_orig, aux_float_rest;
644+ int num_aux_ints = -1 , num_aux_floats = -1 ;
634645
635646 while (std::getline (original, line_orig) && std::getline (restored, line_rest)) {
636647 ++line_num;
@@ -650,16 +661,25 @@ precision is used.
650661 std::cerr << " Header mismatch at line 1:\n "
651662 << " Original: " << line_orig << " \n "
652663 << " Restored: " << line_rest << " \n " ;
653- mismatch_found = true ;
654664 break ;
655665 }
666+
667+ num_aux_ints = total_aux_ints_orig;
668+ num_aux_floats = total_aux_floats_orig;
669+ max_aux_int_diff.assign (num_aux_ints, 0.0 );
670+ max_aux_float_diff.assign (num_aux_floats, 0.0 );
671+ aux_int_orig.assign (num_aux_ints, 0 );
672+ aux_int_rest.assign (num_aux_ints, 0 );
673+ aux_float_orig.assign (num_aux_floats, 0.0 );
674+ aux_float_rest.assign (num_aux_floats, 0.0 );
656675
657676 continue ;
658677 }
659678
660679 for (int i = 0 ; i < 7 ; ++i) {
661- ss_orig >> vec_orig[i];
662- ss_rest >> vec_rest[i];
680+ if (!(ss_orig >> vec_orig[i]) || !(ss_rest >> vec_rest[i])) {
681+ throw std::runtime_error (" Failed to parse core field at line " + std::to_string (line_num));
682+ }
663683 }
664684
665685 for (int i = 0 ; i < 7 ; ++i) {
@@ -668,6 +688,30 @@ precision is used.
668688 }
669689
670690 }
691+
692+ for (int i = 0 ; i < num_aux_ints; ++i) {
693+ if (!(ss_orig >> aux_int_orig[i]) || !(ss_rest >> aux_int_rest[i])) {
694+ throw std::runtime_error (" Failed to parse auxiliary integer field at line " + std::to_string (line_num));
695+ }
696+ }
697+
698+ for (int i = 0 ; i < num_aux_ints; ++i) {
699+ auto diff_i = std::llabs (static_cast <long long >(aux_int_orig[i]) -
700+ static_cast <long long >(aux_int_rest[i]));
701+ double diff = static_cast <double >(diff_i);
702+ if (diff > max_aux_int_diff[i]) max_aux_int_diff[i] = diff;
703+ }
704+
705+ for (int i = 0 ; i < num_aux_floats; ++i) {
706+ if (!(ss_orig >> aux_float_orig[i]) || !(ss_rest >> aux_float_rest[i])) {
707+ throw std::runtime_error (" Failed to parse auxiliary float field at line " + std::to_string (line_num));
708+ }
709+ }
710+
711+ for (int i = 0 ; i < num_aux_floats; ++i) {
712+ double diff = std::abs (aux_float_orig[i] - aux_float_rest[i]);
713+ if (diff > max_aux_float_diff[i]) max_aux_float_diff[i] = diff;
714+ }
671715 }
672716
673717 std::cout << " Maximum absolute differences for core fields"
@@ -679,6 +723,28 @@ precision is used.
679723 << max_diff[4 ] << " , "
680724 << max_diff[5 ] << " , "
681725 << max_diff[6 ] << std::endl;
726+
727+ std::cout << " Maximum absolute differences for auxiliary integer fields: " ;
728+ if (max_aux_int_diff.empty ()) {
729+ std::cout << " (none)" ;
730+ } else {
731+ for (size_t i = 0 ; i < max_aux_int_diff.size (); ++i) {
732+ if (i) std::cout << " , " ;
733+ std::cout << max_aux_int_diff[i];
734+ }
735+ }
736+ std::cout << std::endl;
737+
738+ std::cout << " Maximum absolute differences for auxiliary float fields: " ;
739+ if (max_aux_float_diff.empty ()) {
740+ std::cout << " (none)" ;
741+ } else {
742+ for (size_t i = 0 ; i < max_aux_float_diff.size (); ++i) {
743+ if (i) std::cout << " , " ;
744+ std::cout << max_aux_float_diff[i];
745+ }
746+ }
747+ std::cout << std::endl;
682748 }
683749
684750 } catch (const std::exception& e) {
@@ -746,4 +812,3 @@ precision is used.
746812
747813 return 0 ;
748814}
749-
0 commit comments