Skip to content

Commit 664c37f

Browse files
authored
Fix IndexingUtils.computeProjection (#48)
* test and fix IndexingUtils.computeProjection * add tests
1 parent 93b10bb commit 664c37f

3 files changed

Lines changed: 99 additions & 2 deletions

File tree

src/main/java/dev/zarr/zarrjava/utils/IndexingUtils.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ public static ChunkProjection computeProjection(
8787

8888
if (selOffset[dimIdx] + selShape[dimIdx] > dimLimit) {
8989
// selection ends after current chunk
90-
shape[dimIdx] = (int) (chunkShape[dimIdx] - (selOffset[dimIdx] % chunkShape[dimIdx]));
90+
shape[dimIdx] = chunkShape[dimIdx] - chunkOffset[dimIdx];
9191
} else {
9292
// selection ends within current chunk
9393
shape[dimIdx] = (int) (selOffset[dimIdx] + selShape[dimIdx] - dimOffset
@@ -187,5 +187,15 @@ public ChunkProjection(
187187
this.outOffset = outOffset;
188188
this.shape = shape;
189189
}
190+
191+
@Override
192+
public String toString() {
193+
return "ChunkProjection{" +
194+
"chunkCoords=" + Arrays.toString(chunkCoords) +
195+
", chunkOffset=" + Arrays.toString(chunkOffset) +
196+
", outOffset=" + Arrays.toString(outOffset) +
197+
", shape=" + Arrays.toString(shape) +
198+
'}';
199+
}
190200
}
191201
}

src/test/java/dev/zarr/zarrjava/TestUtils.java

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package dev.zarr.zarrjava;
22

33

4+
import dev.zarr.zarrjava.utils.IndexingUtils;
45
import org.junit.Test;
56
import org.junit.jupiter.api.Assertions;
67

78
import java.util.Arrays;
89

10+
import static dev.zarr.zarrjava.utils.IndexingUtils.computeChunkCoords;
911
import static dev.zarr.zarrjava.utils.Utils.inversePermutation;
1012
import static dev.zarr.zarrjava.utils.Utils.isPermutation;
1113

@@ -27,5 +29,52 @@ public void testInversePermutation() {
2729
Assertions.assertFalse(Arrays.equals(new int[]{2, 0, 1}, inversePermutation(new int[]{2, 0, 1})));
2830
}
2931

32+
@Test
33+
public void testComputeChunkCoords(){
34+
long[] arrayShape = new long[]{100, 100};
35+
int[] chunkShape = new int[]{30, 30};
36+
long[] selOffset = new long[]{50, 20};
37+
int[] selShape = new int[]{20, 1};
38+
long[][] chunkCoords = computeChunkCoords(arrayShape, chunkShape, selOffset, selShape);
39+
long[][] expectedChunkCoords = new long[][]{
40+
{1, 0},
41+
{2, 0},
42+
};
43+
Assertions.assertArrayEquals(expectedChunkCoords, chunkCoords);
44+
45+
arrayShape = new long[]{1, 52};
46+
chunkShape = new int[]{1, 17};
47+
selOffset = new long[]{0, 32};
48+
selShape = new int[]{1, 20};
49+
chunkCoords = computeChunkCoords(arrayShape, chunkShape, selOffset, selShape);
50+
expectedChunkCoords = new long[][]{
51+
{0, 1},
52+
{0, 2},
53+
{0, 3},
54+
};
55+
Assertions.assertArrayEquals(expectedChunkCoords, chunkCoords);
56+
}
57+
58+
@Test
59+
public void testComputeProjection(){
60+
// chunk (0,2) contains indexes 34-50 along axis 1
61+
// thus the overlap with selection 32-52 is 34-50
62+
// which is offset 2 in the selection and offset 0 in the chunk
63+
// and has full chunk length 17
64+
final long[] chunkCoords = new long[]{0, 2};
65+
final long[] arrayShape = new long[]{1, 52};
66+
final int[] chunkShape = new int[]{1, 17};
67+
final long[] selOffset = new long[]{0, 32};
68+
final int[] selShape = new int[]{1, 20};
69+
70+
IndexingUtils.ChunkProjection projection = IndexingUtils.computeProjection(
71+
chunkCoords, arrayShape, chunkShape, selOffset, selShape
72+
);
73+
Assertions.assertArrayEquals(chunkCoords, projection.chunkCoords);
74+
Assertions.assertArrayEquals(new int[]{0,0}, projection.chunkOffset);
75+
Assertions.assertArrayEquals(new int[]{0,2}, projection.outOffset);
76+
Assertions.assertArrayEquals(new int[]{1, 17}, projection.shape);
77+
}
78+
3079
}
3180

src/test/java/dev/zarr/zarrjava/ZarrV3Test.java

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import dev.zarr.zarrjava.core.Attributes;
77
import dev.zarr.zarrjava.store.FilesystemStore;
88
import dev.zarr.zarrjava.store.HttpStore;
9+
import dev.zarr.zarrjava.store.MemoryStore;
910
import dev.zarr.zarrjava.store.StoreHandle;
1011
import dev.zarr.zarrjava.utils.MultiArrayUtils;
1112
import dev.zarr.zarrjava.v3.*;
@@ -106,6 +107,17 @@ static Stream<Function<ArrayMetadataBuilder, ArrayMetadataBuilder>> chunkKeyEnco
106107
return Stream.concat(builders, codecBuilders().map(codecFunc -> b -> b.withCodecs(codecFunc)));
107108
}
108109

110+
static Stream<Arguments> unalignedArrayAccessProvider() {
111+
Stream.Builder<Arguments> builder = Stream.builder();
112+
builder.add(Arguments.of(52, 17, 32));
113+
builder.add(Arguments.of(71, 11, 12));
114+
builder.add(Arguments.of(52, 17, 17));
115+
builder.add(Arguments.of(50, 3, 7));
116+
builder.add(Arguments.of(50, 3, 22));
117+
builder.add(Arguments.of(13, 31, 21));
118+
return builder.build();
119+
}
120+
109121
@ParameterizedTest
110122
@MethodSource("invalidCodecBuilder")
111123
public void testCheckInvalidCodecConfiguration(Function<CodecBuilder, CodecBuilder> codecBuilder) {
@@ -735,4 +747,30 @@ public void testGroupAttributes() throws IOException, ZarrException {
735747
group = Group.open(storeHandle);
736748
Assertions.assertEquals("group_value", group.metadata().attributes().getString("group_attr"));
737749
}
738-
}
750+
751+
@ParameterizedTest
752+
@MethodSource("unalignedArrayAccessProvider")
753+
public void testUnalignedArrayAccess(int arrayShape, int chunkShape, int accessShape) throws ZarrException, IOException {
754+
Array array = Array.create(
755+
new MemoryStore().resolve(),
756+
Array.metadataBuilder()
757+
.withShape(arrayShape)
758+
.withDataType(DataType.UINT32)
759+
.withChunkShape(chunkShape)
760+
.withFillValue(0)
761+
.build()
762+
);
763+
764+
int[] testData = new int[arrayShape];
765+
Arrays.setAll(testData, p -> (byte) p);
766+
ucar.ma2.Array data = ucar.ma2.Array.factory(ucar.ma2.DataType.UINT, new int[]{arrayShape}, testData);
767+
array.write(data);
768+
769+
for (int i = 0; i < arrayShape; i += accessShape) {
770+
accessShape = Math.min(accessShape, arrayShape - i);
771+
ucar.ma2.Array result = array.read(new long[]{i}, new int[]{accessShape});
772+
int[] expectedData = Arrays.copyOfRange(testData, i, i + accessShape);
773+
Assertions.assertArrayEquals(expectedData, (int[]) result.get1DJavaArray(ucar.ma2.DataType.UINT));
774+
}
775+
}
776+
}

0 commit comments

Comments
 (0)