Skip to content

Commit 496a281

Browse files
committed
Fix JSON chunk detection
Former algorithm left some chunks split apart, fix that.
1 parent 8bc2261 commit 496a281

File tree

4 files changed

+99
-13
lines changed

4 files changed

+99
-13
lines changed

include/openPMD/Dataset.hpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,14 @@ class Dataset
5555

5656
struct Chunk
5757
{
58-
Offset const offset;
59-
Extent const extent;
60-
unsigned int const rank;
58+
Offset offset;
59+
Extent extent;
60+
unsigned int rank = 0;
6161

6262
/*
6363
* If rank is smaller than zero, will be converted to zero.
6464
*/
65+
explicit Chunk() = default;
6566
Chunk( Offset, Extent, int rank );
6667
Chunk( Offset, Extent );
6768

src/IO/JSON/JSONIOHandlerImpl.cpp

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,87 @@ namespace openPMD
331331
}
332332
return res;
333333
}
334+
335+
std::pair< bool, Chunk >
336+
mergeChunks( Chunk const & _c1, Chunk const & _c2 )
337+
{
338+
Chunk const *c1( &_c1 ), *c2( &_c2 );
339+
unsigned dimensionality = _c1.extent.size();
340+
for( unsigned dim = 0; dim < dimensionality; ++dim )
341+
{
342+
// check if one chunk is the extension of the other at
343+
// dimension dim
344+
if( c1->offset[ dim ] > c2->offset[ dim ] )
345+
{
346+
std::swap( c1, c2 );
347+
}
348+
// now, c1 begins at the lower of both offsets
349+
// next check, that both chunks border one another exactly
350+
if( c2->offset[ dim ] != c1->offset[ dim ] + c1->extent[ dim ] )
351+
{
352+
continue;
353+
}
354+
// we've got a candidate
355+
// verify that all other dimensions have equal values
356+
auto equalValues = [ dimensionality, dim, c1, c2 ]() {
357+
for( unsigned j = 0; j < dimensionality; ++j )
358+
{
359+
if( j == dim )
360+
{
361+
continue;
362+
}
363+
if( c1->offset[ j ] != c2->offset[ j ] ||
364+
c1->extent[ j ] != c2->extent[ j ] )
365+
{
366+
return false;
367+
}
368+
}
369+
return true;
370+
};
371+
if( !equalValues() )
372+
{
373+
continue;
374+
}
375+
// we can merge the chunks
376+
Offset offset( c1->offset );
377+
Extent extent( c1->extent );
378+
extent[ dim ] += c2->extent[ dim ];
379+
return std::make_pair( true, Chunk( offset, extent ) );
380+
}
381+
return std::make_pair( false, Chunk() );
382+
}
383+
384+
void
385+
mergeChunks( ChunkTable & table )
386+
{
387+
bool stillChanging;
388+
do
389+
{
390+
stillChanging = false;
391+
auto innerLoops = [ &table ]() {
392+
for( auto i = table.begin(); i < table.end(); ++i )
393+
{
394+
for( auto j = i + 1; j < table.end(); ++j )
395+
{
396+
std::pair< bool, Chunk > merged =
397+
mergeChunks( *i, *j );
398+
if( merged.first )
399+
{
400+
// erase order is important due to iterator
401+
// invalidation
402+
table.erase( j );
403+
table.erase( i );
404+
table.emplace_back(
405+
std::move( merged.second ) );
406+
return true;
407+
}
408+
}
409+
}
410+
return false;
411+
};
412+
stillChanging = innerLoops();
413+
} while( stillChanging );
414+
}
334415
} // namespace
335416

336417
void
@@ -342,6 +423,7 @@ namespace openPMD
342423
auto filePosition = setAndGetFilePosition( writable );
343424
auto & j = obtainJsonContents( writable )[ "data" ];
344425
*parameters.chunks = chunksInJSON( j );
426+
mergeChunks( *parameters.chunks );
345427
}
346428

347429
void JSONIOHandlerImpl::openFile(

test/SerialIOTest.cpp

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,14 @@ TEST_CASE( "available_chunks_test_json", "[serial][json]" )
100100
* 4 ****
101101
* 5 ****
102102
* 6 ****
103-
* 7 _**_
104-
* 8 _**_
105-
* 9 ____
103+
* 7 **__
104+
* 8 **_*
105+
* 9 ___*
106106
*
107-
* Will be read as two chunks:
107+
* Will be read as three chunks:
108108
* 1. (2,0) -- (5,4) (offset -- extent)
109-
* 2. (7,1) -- (2,2) (offset -- extent)
109+
* 2. (7,0) -- (2,2) (offset -- extent)
110+
* 3. (8,3) -- (2,1) (offset -- extent)
110111
*
111112
*/
112113
constexpr unsigned height = 10;
@@ -124,8 +125,9 @@ TEST_CASE( "available_chunks_test_json", "[serial][json]" )
124125
}
125126
for( unsigned line = 7; line < 9; ++line )
126127
{
127-
E_x.storeChunk( data, { line, 1 }, { 1, 2 } );
128+
E_x.storeChunk( data, { line, 0 }, { 1, 2 } );
128129
}
130+
E_x.storeChunk( data, { 8, 3 }, {2, 1 } );
129131
it0.close();
130132
}
131133

@@ -134,9 +136,10 @@ TEST_CASE( "available_chunks_test_json", "[serial][json]" )
134136
Iteration it0 = read.iterations[ 0 ];
135137
auto E_x = it0.meshes[ "E" ][ "x" ];
136138
ChunkTable table = E_x.availableChunks();
137-
REQUIRE( table.size() == 2 );
138-
REQUIRE( table[ 0 ] == Chunk( { 2, 0 }, { 5, 4 }, -1 ) );
139-
REQUIRE( table[ 1 ] == Chunk( { 7, 1 }, { 2, 2 }, -1 ) );
139+
REQUIRE( table.size() == 3 );
140+
REQUIRE( table[ 0 ] == Chunk( { 2, 0 }, { 5, 4 } ) );
141+
REQUIRE( table[ 1 ] == Chunk( { 7, 0 }, { 2, 2 } ) );
142+
REQUIRE( table[ 2 ] == Chunk( { 8, 3 }, { 2, 1 } ) );
140143
}
141144
}
142145

test/python/unittest/API/APITest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1516,7 +1516,7 @@ def testCloseIteration(self):
15161516
self.makeCloseIterationRoundTrip(ext)
15171517

15181518
def makeAvailableChunksRoundTrip(self, ext):
1519-
if ext == "json" or ext == "h5":
1519+
if ext == "h5":
15201520
return
15211521
name = "../samples/available_chunks_python." + ext
15221522
write = io.Series(

0 commit comments

Comments
 (0)