66#include < numeric>
77
88#include < catch2/catch.hpp>
9+ #include < optional>
910
1011#if openPMD_HAVE_ADIOS2 && openPMD_HAVE_MPI
1112#include < adios2.h>
@@ -120,24 +121,13 @@ static void create_file_in_serial(bool use_group_table)
120121 " __openPMD_groups/data" , step, " " , " /" , true );
121122 IO.DefineAttribute <size_t >(
122123 " __openPMD_groups/data/meshes" , step, " " , " /" , true );
123- IO.DefineAttribute <size_t >(
124- " __openPMD_groups/data/meshes/theta" , step, " " , " /" , true );
125124 }
126125
127126 std::vector<int > data{0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 };
128127 engine.Put (variable, data.data ());
129128 if (step % 2 == 1 )
130129 {
131130 engine.Put (variable2, data.data ());
132- if (use_group_table)
133- {
134- IO.DefineAttribute <size_t >(
135- " __openPMD_groups/data/meshes/e_chargeDensity" ,
136- step,
137- " " ,
138- " /" ,
139- true );
140- }
141131 }
142132
143133 engine.EndStep ();
@@ -147,13 +137,16 @@ static void create_file_in_serial(bool use_group_table)
147137 }
148138}
149139
150- auto read_file_in_parallel (bool use_group_table) -> void
140+ auto read_file_in_parallel (
141+ std::optional<std::string> const &dont_verify_homogeneous_extents) -> void
151142{
152143 openPMD::Series read (
153144 " ../samples/read_variablebased_randomaccess.bp" ,
154145 openPMD::Access::READ_ONLY,
155146 MPI_COMM_WORLD,
156- " adios2.engine.type = \" bp5\" " );
147+ json::merge (
148+ " adios2.engine.type = \" bp5\" " ,
149+ dont_verify_homogeneous_extents.value_or (" {}" )));
157150 for (auto &[index, iteration] : read.snapshots ())
158151 {
159152 auto data = iteration.meshes [" theta" ].loadChunk <int >({0 }, {10 });
@@ -163,42 +156,56 @@ auto read_file_in_parallel(bool use_group_table) -> void
163156 REQUIRE (data.get ()[i] == int (i));
164157 }
165158 // clang-format off
166- /*
167- * Step 0:
168- * uint64_t /data/snapshot attr = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
169- * Step 1:
170- * int32_t /data/meshes/e_chargeDensity {10}
171- * uint64_t /data/snapshot attr = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}
172- * Step 2:
173- * uint64_t /data/snapshot attr = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29}
174- * Step 3:
175- * int32_t /data/meshes/e_chargeDensity {10}
176- * uint64_t /data/snapshot attr = {30, 31, 32, 33, 34, 35, 36, 37, 38, 39}
177- * Step 4:
178- * uint64_t /data/snapshot attr = {40, 41, 42, 43, 44, 45, 46, 47, 48, 49}
179- */
159+ /*
160+ * Step 0:
161+ * uint64_t /data/snapshot attr = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
162+ * Step 1:
163+ * int32_t /data/meshes/e_chargeDensity {10}
164+ * uint64_t /data/snapshot attr = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}
165+ * Step 2:
166+ * uint64_t /data/snapshot attr = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29}
167+ * Step 3:
168+ * int32_t /data/meshes/e_chargeDensity {10}
169+ * uint64_t /data/snapshot attr = {30, 31, 32, 33, 34, 35, 36, 37, 38, 39}
170+ * Step 4:
171+ * uint64_t /data/snapshot attr = {40, 41, 42, 43, 44, 45, 46, 47, 48, 49}
172+ */
180173 // clang-format on
181174 size_t adios_step = index / 10 ; // 10 iterations per step
182175 bool step_has_charge_density = adios_step % 2 == 1 ;
183- if (use_group_table)
176+ // Without a group table, the groups need to be recovered from
177+ // attributes and variables found in the ADIOS2 file. But since the
178+ // e_chargeDensity mesh exists only in a subselection of steps, its
179+ // attributes will leak into the other steps, making the API see just an
180+ // empty mesh. The behavior now depends on how strictly we are parsing:
181+ //
182+ // 1. If verify_homogeneous_extent == true (default): The reader will
183+ // notice that no extent is defined anywhere, the mesh will be erased
184+ // with a warning.
185+ // 2. If verify_homogeneous_extent == false: An empty mesh will be
186+ // returned.
187+ if (!dont_verify_homogeneous_extents.has_value ())
184188 {
185189 REQUIRE (
186190 iteration.meshes .contains (" e_chargeDensity" ) ==
187191 step_has_charge_density);
192+ if (step_has_charge_density)
193+ {
194+ REQUIRE (iteration.meshes [" e_chargeDensity" ].scalar ());
195+ }
188196 }
189197 else
190198 {
191- // Without a group table, the groups need to be recovered from
192- // attributes and variables found in the ADIOS2 file. But since the
193- // e_chargeDensity mesh exists only in a subselection of steps, its
194- // attributes will leak into the other steps, making the API think
195- // that there is data where there is none.
196199 REQUIRE (iteration.meshes .contains (" e_chargeDensity" ));
197200 // Only when the variable is also found, the reading routines will
198201 // correctly determine that this is a scalar mesh.
199202 REQUIRE (
200203 iteration.meshes [" e_chargeDensity" ].scalar () ==
201204 step_has_charge_density);
205+ if (!step_has_charge_density)
206+ {
207+ REQUIRE (iteration.meshes [" e_chargeDensity" ].size () == 0 );
208+ }
202209 }
203210 if (step_has_charge_density)
204211 {
@@ -222,13 +229,14 @@ auto read_variablebased_randomaccess() -> void
222229 create_file_in_serial (true );
223230 }
224231 MPI_Barrier (MPI_COMM_WORLD);
225- read_file_in_parallel (true );
232+ // read_file_in_parallel(std::nullopt );
226233 if (rank == 0 )
227234 {
228235 create_file_in_serial (false );
229236 }
230237 MPI_Barrier (MPI_COMM_WORLD);
231- read_file_in_parallel (false );
238+ read_file_in_parallel (std::nullopt );
239+ read_file_in_parallel (R"( {"verify_homogeneous_extents": false})" );
232240}
233241} // namespace read_variablebased_randomaccess
234242#else
0 commit comments