diff --git a/include/openPMD/Iteration.hpp b/include/openPMD/Iteration.hpp index 3d8ccb4567..964319c6ea 100644 --- a/include/openPMD/Iteration.hpp +++ b/include/openPMD/Iteration.hpp @@ -102,6 +102,14 @@ namespace internal * Otherwise empty. */ std::optional m_deferredParseAccess{}; + + /** + * Upon reading a file, set this field to the used file name. + * In inconsistent iteration paddings, we must remember the name of the + * file since it cannot be reconstructed from the filename pattern + * alone. + */ + std::optional m_overrideFilebasedFilename{}; }; } // namespace internal /** @brief Logical compilation of data from one snapshot (e.g. a single diff --git a/src/IO/JSON/JSONIOHandlerImpl.cpp b/src/IO/JSON/JSONIOHandlerImpl.cpp index c225155da1..61f8d239d5 100644 --- a/src/IO/JSON/JSONIOHandlerImpl.cpp +++ b/src/IO/JSON/JSONIOHandlerImpl.cpp @@ -916,7 +916,7 @@ JSONIOHandlerImpl::getFilehandle(File fileName, Access access) fs->open(path, std::ios_base::in); break; } - VERIFY(fs->good(), "[JSON] Failed opening a file"); + VERIFY(fs->good(), "[JSON] Failed opening a file '" + path + "'"); return fs; } diff --git a/src/Iteration.cpp b/src/Iteration.cpp index 73c8a46847..057d47c1bb 100644 --- a/src/Iteration.cpp +++ b/src/Iteration.cpp @@ -364,6 +364,7 @@ void Iteration::readFileBased( auto series = retrieveSeries(); series.readOneIterationFileBased(filePath); + get().m_overrideFilebasedFilename = filePath; read_impl(groupPath); } diff --git a/src/Series.cpp b/src/Series.cpp index 68059e2af9..e240c9da52 100644 --- a/src/Series.cpp +++ b/src/Series.cpp @@ -1191,14 +1191,34 @@ void Series::readBase() std::string Series::iterationFilename(uint64_t i) { + /* + * The filename might have been overridden at the Series level or at the + * Iteration level. See the struct members' documentation for the reasons. + */ auto &series = get(); if (series.m_overrideFilebasedFilename.has_value()) { return series.m_overrideFilebasedFilename.value(); } - std::stringstream iteration(""); - iteration << std::setw(series.m_filenamePadding) << std::setfill('0') << i; - return series.m_filenamePrefix + iteration.str() + series.m_filenamePostfix; + else if (auto iteration = iterations.find(i); // + iteration != iterations.end() && + iteration->second.get().m_overrideFilebasedFilename.has_value()) + { + return iteration->second.get().m_overrideFilebasedFilename.value(); + } + else + { + + /* + * If no filename has been explicitly stored, we use the filename + * pattern to compute it. + */ + std::stringstream iterationNr(""); + iterationNr << std::setw(series.m_filenamePadding) << std::setfill('0') + << i; + return series.m_filenamePrefix + iterationNr.str() + + series.m_filenamePostfix; + } } Series::iterations_iterator Series::indexOf(Iteration const &iteration) diff --git a/test/SerialIOTest.cpp b/test/SerialIOTest.cpp index 92de22aa43..ac7a7e4d1c 100644 --- a/test/SerialIOTest.cpp +++ b/test/SerialIOTest.cpp @@ -5659,3 +5659,47 @@ TEST_CASE("late_setting_of_iterationencoding", "[serial]") REQUIRE( auxiliary::file_exists("../samples/change_name_and_encoding_10.json")); } + +void varying_pattern(std::string const file_ending) +{ + { + std::string filename = "../samples/varying_pattern_%06T." + file_ending; + ::openPMD::Series series = + ::openPMD::Series(filename, ::openPMD::Access::CREATE); + + for (auto i : {0, 8000, 10000, 100000, 2000000}) + { + auto it = series.iterations[i]; + it.setAttribute("my_step", i); + } + series.flush(); + } + { + std::string filename = "../samples/varying_pattern_%T." + file_ending; + ::openPMD::Series series = + ::openPMD::Series(filename, ::openPMD::Access::READ_ONLY); + + REQUIRE(series.iterations.size() == 5); + for (auto const &[step, it] : series.iterations) + { + std::cout << "Iteration: " << step << "\n"; + REQUIRE(it.getAttribute("my_step").get() == int(step)); + } + + helper::listSeries(series, true, std::cout); + + for (auto i : {0, 8000, 10000, 100000, 2000000}) + { + auto it = series.iterations[i]; + REQUIRE(it.getAttribute("my_step").get() == i); + } + } +} + +TEST_CASE("varying_zero_pattern", "[serial]") +{ + for (auto const &t : testedFileExtensions()) + { + varying_pattern(t); + } +}