@@ -6345,9 +6345,46 @@ TEST_CASE("varying_zero_pattern", "[serial]")
63456345 }
63466346}
63476347
6348+ enum class ParseMode
6349+ {
6350+ /*
6351+ * Conventional workflow. Just parse the whole thing and yield iterations
6352+ * in rising order.
6353+ */
6354+ NoSteps,
6355+ /*
6356+ * The Series is parsed ahead of time upon opening, but it has steps.
6357+ * Parsing ahead of time is the conventional workflow to support
6358+ * random-access.
6359+ * Reading such a Series with the streaming API is only possible if all
6360+ * steps are in ascending order, otherwise the openPMD-api has no way of
6361+ * associating IO steps with interation indices.
6362+ * Reading such a Series with the Streaming API will become possible with
6363+ * the Linear read mode to be introduced by #1291.
6364+ */
6365+ AheadOfTimeWithoutSnapshot,
6366+ /*
6367+ * A Series of the BP5 engine is not parsed ahead of time, but step-by-step,
6368+ * giving the openPMD-api a way to associate IO steps with iterations.
6369+ * No snapshot attribute exists, so the fallback mode is chosen:
6370+ * Iterations are returned in ascending order.
6371+ * If an IO step returns an iteration whose index is lower than the
6372+ * last one, it will be skipped.
6373+ * This mode of parsing will be generalized into the Linear read mode with
6374+ * PR #1291.
6375+ */
6376+ LinearWithoutSnapshot,
6377+ /*
6378+ * Snapshot attribute exists and dictates the iteration index returned by
6379+ * an IO step. Duplicate iterations will be skipped.
6380+ */
6381+ WithSnapshot
6382+ };
6383+
63486384void append_mode (
63496385 std::string const &extension,
63506386 bool variableBased,
6387+ ParseMode parseMode,
63516388 std::string jsonConfig = " {}" )
63526389{
63536390
@@ -6455,26 +6492,60 @@ void append_mode(
64556492 }
64566493 {
64576494 Series read (filename, Access::READ_ONLY );
6458- if (variableBased || extension == " bp5 " )
6495+ switch (parseMode )
64596496 {
6497+ case ParseMode::NoSteps: {
6498+ unsigned counter = 0 ;
6499+ uint64_t iterationOrder[] = {0 , 1 , 2 , 3 , 4 , 7 , 10 , 11 };
6500+ for (auto const &iteration : read.readIterations ())
6501+ {
6502+ REQUIRE (iteration.iterationIndex == iterationOrder[counter]);
6503+ ++counter;
6504+ }
6505+ REQUIRE (counter == 8 );
6506+ }
6507+ break ;
6508+ case ParseMode::LinearWithoutSnapshot: {
6509+ unsigned counter = 0 ;
6510+ uint64_t iterationOrder[] = {0 , 1 , 2 , 3 , 4 , 10 , 11 };
6511+ for (auto const &iteration : read.readIterations ())
6512+ {
6513+ REQUIRE (iteration.iterationIndex == iterationOrder[counter]);
6514+ ++counter;
6515+ }
6516+ REQUIRE (counter == 7 );
6517+ }
6518+ break ;
6519+ case ParseMode::WithSnapshot: {
64606520 // in variable-based encodings, iterations are not parsed ahead of
64616521 // time but as they go
64626522 unsigned counter = 0 ;
64636523 uint64_t iterationOrder[] = {0 , 1 , 2 , 3 , 4 , 10 , 7 , 11 };
64646524 for (auto const &iteration : read.readIterations ())
64656525 {
6466- std::cout << " Seeing iteration " << iteration.iterationIndex
6467- << " of series " << filename << std::endl;
64686526 REQUIRE (iteration.iterationIndex == iterationOrder[counter]);
64696527 ++counter;
64706528 }
64716529 REQUIRE (counter == 8 );
64726530 // Cannot do listSeries here because the Series is already drained
64736531 REQUIRE_THROWS_AS (helper::listSeries (read), error::WrongAPIUsage);
64746532 }
6475- else
6476- {
6533+ break ;
6534+ case ParseMode::AheadOfTimeWithoutSnapshot: {
64776535 REQUIRE (read.iterations .size () == 8 );
6536+ unsigned counter = 0 ;
6537+ uint64_t iterationOrder[] = {0 , 1 , 2 , 3 , 4 , 7 , 10 , 11 };
6538+ /*
6539+ * Use conventional read API since streaming API is not possible
6540+ * without Linear read mode.
6541+ * (See also comments inside ParseMode enum).
6542+ */
6543+ for (auto const &iteration : read.iterations )
6544+ {
6545+ REQUIRE (iteration.first == iterationOrder[counter]);
6546+ ++counter;
6547+ }
6548+ REQUIRE (counter == 8 );
64786549 /*
64796550 * Roadmap: for now, reading this should work by ignoring the last
64806551 * duplicate iteration.
@@ -6484,6 +6555,8 @@ void append_mode(
64846555 */
64856556 helper::listSeries (read);
64866557 }
6558+ break ;
6559+ }
64876560 }
64886561#if 100000000 * ADIOS2_VERSION_MAJOR + 1000000 * ADIOS2_VERSION_MINOR + \
64896562 10000 * ADIOS2_VERSION_PATCH + 100 * ADIOS2_VERSION_TWEAK >= \
@@ -6520,16 +6593,47 @@ void append_mode(
65206593 }
65216594 {
65226595 Series read (filename, Access::READ_ONLY );
6523- // in variable-based encodings, iterations are not parsed ahead of
6524- // time but as they go
6525- unsigned counter = 0 ;
6526- for (auto const &iteration : read.readIterations ())
6596+ switch (parseMode)
65276597 {
6528- REQUIRE (iteration.iterationIndex == counter);
6529- ++counter;
6598+ case ParseMode::LinearWithoutSnapshot: {
6599+ uint64_t iterationOrder[] = {0 , 1 , 2 , 3 , 4 , 10 };
6600+ unsigned counter = 0 ;
6601+ for (auto const &iteration : read.readIterations ())
6602+ {
6603+ REQUIRE (
6604+ iteration.iterationIndex == iterationOrder[counter]);
6605+ ++counter;
6606+ }
6607+ REQUIRE (counter == 6 );
6608+ // Cannot do listSeries here because the Series is already
6609+ // drained
6610+ REQUIRE_THROWS_AS (
6611+ helper::listSeries (read), error::WrongAPIUsage);
6612+ }
6613+ break ;
6614+ case ParseMode::WithSnapshot: {
6615+ // in variable-based encodings, iterations are not parsed ahead
6616+ // of time but as they go
6617+ unsigned counter = 0 ;
6618+ uint64_t iterationOrder[] = {0 , 1 , 2 , 3 , 4 , 10 , 7 , 5 };
6619+ for (auto const &iteration : read.readIterations ())
6620+ {
6621+ REQUIRE (
6622+ iteration.iterationIndex == iterationOrder[counter]);
6623+ ++counter;
6624+ }
6625+ REQUIRE (counter == 8 );
6626+ // Cannot do listSeries here because the Series is already
6627+ // drained
6628+ REQUIRE_THROWS_AS (
6629+ helper::listSeries (read), error::WrongAPIUsage);
6630+ }
6631+ break ;
6632+ case ParseMode::NoSteps:
6633+ case ParseMode::AheadOfTimeWithoutSnapshot:
6634+ throw std::runtime_error (" Test configured wrong." );
6635+ break ;
65306636 }
6531- REQUIRE (counter == 6 );
6532- helper::listSeries (read);
65336637 }
65346638 }
65356639#endif
@@ -6539,9 +6643,7 @@ TEST_CASE("append_mode", "[serial]")
65396643{
65406644 for (auto const &t : testedFileExtensions ())
65416645 {
6542- if (t == " bp" || t == " bp4" || t == " bp5" )
6543- {
6544- std::string jsonConfigOld = R"END(
6646+ std::string jsonConfigOld = R"END(
65456647{
65466648 "adios2":
65476649 {
@@ -6552,7 +6654,7 @@ TEST_CASE("append_mode", "[serial]")
65526654 }
65536655 }
65546656})END" ;
6555- std::string jsonConfigNew = R"END(
6657+ std::string jsonConfigNew = R"END(
65566658{
65576659 "adios2":
65586660 {
@@ -6563,14 +6665,25 @@ TEST_CASE("append_mode", "[serial]")
65636665 }
65646666 }
65656667})END" ;
6566- append_mode (t, false , jsonConfigOld);
6567- append_mode (t, false , jsonConfigNew);
6568- append_mode (t, true , jsonConfigOld);
6569- append_mode (t, true , jsonConfigNew);
6668+ if (t == " bp5" )
6669+ {
6670+ append_mode (
6671+ t, false , ParseMode::LinearWithoutSnapshot, jsonConfigOld);
6672+ append_mode (t, false , ParseMode::WithSnapshot, jsonConfigNew);
6673+ append_mode (t, true , ParseMode::WithSnapshot, jsonConfigOld);
6674+ append_mode (t, true , ParseMode::WithSnapshot, jsonConfigNew);
6675+ }
6676+ else if (t == " bp" || t == " bp4" || t == " bp5" )
6677+ {
6678+ append_mode (
6679+ t, false , ParseMode::AheadOfTimeWithoutSnapshot, jsonConfigOld);
6680+ append_mode (t, false , ParseMode::WithSnapshot, jsonConfigNew);
6681+ append_mode (t, true , ParseMode::WithSnapshot, jsonConfigOld);
6682+ append_mode (t, true , ParseMode::WithSnapshot, jsonConfigNew);
65706683 }
65716684 else
65726685 {
6573- append_mode (t, false );
6686+ append_mode (t, false , ParseMode::NoSteps );
65746687 }
65756688 }
65766689}
0 commit comments