DoubleDataChunkTest.java
/**
* Copyright (c) 2017, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/
package com.powsybl.timeseries;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.powsybl.commons.json.JsonUtil;
import com.powsybl.timeseries.json.TimeSeriesJsonModule;
import org.junit.jupiter.api.Test;
import org.threeten.extra.Interval;
import java.io.IOException;
import java.nio.DoubleBuffer;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
/**
* @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
*/
class DoubleDataChunkTest {
@Test
void baseTest() {
UncompressedDoubleDataChunk chunk = new UncompressedDoubleDataChunk(1, new double[] {1d, 2d, 3d});
assertEquals(1, chunk.getOffset());
assertEquals(3, chunk.getLength());
assertArrayEquals(new double[]{1d, 2d, 3d}, chunk.getValues(), 0d);
assertEquals(24, chunk.getEstimatedSize());
assertFalse(chunk.isCompressed());
assertEquals(1d, chunk.getCompressionFactor(), 0d);
DoubleBuffer buffer = DoubleBuffer.allocate(4);
for (int i = 0; i < 4; i++) {
buffer.put(i, Double.NaN);
}
chunk.fillBuffer(buffer, 0);
assertArrayEquals(new double[] {Double.NaN, 1d, 2d, 3d}, buffer.array(), 0d);
String jsonRef = String.join(System.lineSeparator(),
"{",
" \"offset\" : 1,",
" \"values\" : [ 1.0, 2.0, 3.0 ]",
"}");
assertEquals(jsonRef, JsonUtil.toJson(chunk::writeJson));
RegularTimeSeriesIndex index = RegularTimeSeriesIndex.create(Interval.parse("2015-01-01T00:00:00Z/2015-01-01T00:45:00Z"),
Duration.ofMinutes(15));
assertEquals(List.of(new DoublePoint(1, Instant.parse("2015-01-01T00:15:00Z"), 1d),
new DoublePoint(2, Instant.parse("2015-01-01T00:30:00Z"), 2d),
new DoublePoint(3, Instant.parse("2015-01-01T00:45:00Z"), 3d)),
chunk.stream(index).toList());
}
@Test
void compressTest() throws IOException {
UncompressedDoubleDataChunk chunk = new UncompressedDoubleDataChunk(1, new double[] {1d, 2d, 2d, 2d, 2d, 3d});
DoubleDataChunk maybeCompressedChunk = chunk.tryToCompress();
assertInstanceOf(CompressedDoubleDataChunk.class, maybeCompressedChunk);
CompressedDoubleDataChunk compressedChunk = (CompressedDoubleDataChunk) maybeCompressedChunk;
assertEquals(1, compressedChunk.getOffset());
assertEquals(6, compressedChunk.getLength());
assertTrue(compressedChunk.isCompressed());
assertEquals(36, compressedChunk.getEstimatedSize());
assertEquals(36d / 48, compressedChunk.getCompressionFactor(), 0d);
assertArrayEquals(new double[] {1d, 2d, 3d}, compressedChunk.getStepValues(), 0d);
assertArrayEquals(new int[] {1, 4, 1}, compressedChunk.getStepLengths());
DoubleBuffer buffer = DoubleBuffer.allocate(7);
for (int i = 0; i < 7; i++) {
buffer.put(i, Double.NaN);
}
compressedChunk.fillBuffer(buffer, 0);
assertArrayEquals(new double[] {Double.NaN, 1d, 2d, 2d, 2d, 2d, 3d}, buffer.array(), 0d);
// json test
String jsonRef = String.join(System.lineSeparator(),
"{",
" \"offset\" : 1,",
" \"uncompressedLength\" : 6,",
" \"stepValues\" : [ 1.0, 2.0, 3.0 ],",
" \"stepLengths\" : [ 1, 4, 1 ]",
"}");
assertEquals(jsonRef, JsonUtil.toJson(compressedChunk::writeJson));
// test json with object mapper
ObjectMapper objectMapper = JsonUtil.createObjectMapper()
.registerModule(new TimeSeriesJsonModule());
List<DoubleDataChunk> chunks = objectMapper.readValue(objectMapper.writeValueAsString(Arrays.asList(chunk, compressedChunk)),
TypeFactory.defaultInstance().constructCollectionType(List.class, DoubleDataChunk.class));
assertEquals(2, chunks.size());
assertEquals(chunk, chunks.get(0));
assertEquals(compressedChunk, chunks.get(1));
// check base class (DataChunk) deserializer
assertInstanceOf(DoubleDataChunk.class, objectMapper.readValue(objectMapper.writeValueAsString(chunk), DataChunk.class));
// stream test
RegularTimeSeriesIndex index = RegularTimeSeriesIndex.create(Interval.parse("2015-01-01T00:00:00Z/2015-01-01T01:30:00Z"),
Duration.ofMinutes(15));
assertEquals(List.of(new DoublePoint(1, Instant.parse("2015-01-01T00:15:00Z"), 1d),
new DoublePoint(2, Instant.parse("2015-01-01T00:30:00Z"), 2d),
new DoublePoint(6, Instant.parse("2015-01-01T01:30:00Z"), 3d)),
compressedChunk.stream(index).toList());
}
@Test
void compressConstrTest() {
assertThrows(IllegalArgumentException.class, () -> new CompressedDoubleDataChunk(-3, 1, new double[] {1d}, new int[] {1}));
}
@Test
void compressConstrTest2() {
assertThrows(IllegalArgumentException.class, () -> new CompressedDoubleDataChunk(0, 0, new double[] {1d}, new int[] {1}));
}
@Test
void compressConstrTest3() {
assertThrows(IllegalArgumentException.class, () -> new CompressedDoubleDataChunk(0, 1, new double[] {}, new int[] {}));
}
@Test
void compressConstrTest4() {
assertThrows(IllegalArgumentException.class, () -> new CompressedDoubleDataChunk(0, 1, new double[] {1d}, new int[] {}));
}
@Test
void compressFailureTest() throws IOException {
UncompressedDoubleDataChunk chunk = new UncompressedDoubleDataChunk(1, new double[] {1d, 2d, 2d, 3d});
assertSame(chunk, chunk.tryToCompress());
}
@Test
void uncompressedSplitTest() throws IOException {
UncompressedDoubleDataChunk chunk = new UncompressedDoubleDataChunk(1, new double[]{1d, 2d, 3d});
try {
chunk.splitAt(1);
fail();
} catch (IllegalArgumentException ignored) {
}
try {
chunk.splitAt(4);
fail();
} catch (IllegalArgumentException ignored) {
}
DataChunk.Split<DoublePoint, DoubleDataChunk> split = chunk.splitAt(2);
assertNotNull(split.getChunk1());
assertNotNull(split.getChunk2());
assertEquals(1, split.getChunk1().getOffset());
assertInstanceOf(UncompressedDoubleDataChunk.class, split.getChunk1());
assertArrayEquals(new double[] {1d}, ((UncompressedDoubleDataChunk) split.getChunk1()).getValues(), 0d);
assertEquals(2, split.getChunk2().getOffset());
assertInstanceOf(UncompressedDoubleDataChunk.class, split.getChunk2());
assertArrayEquals(new double[] {2d, 3d}, ((UncompressedDoubleDataChunk) split.getChunk2()).getValues(), 0d);
}
@Test
void compressedSplitTest() throws IOException {
// index 0 1 2 3 4 5
// value NaN 1 1 2 2 2
// [-------] [---]
CompressedDoubleDataChunk chunk = new CompressedDoubleDataChunk(1, 5, new double[] {1d, 2d}, new int[] {2, 3});
try {
chunk.splitAt(0);
fail();
} catch (IllegalArgumentException ignored) {
}
try {
chunk.splitAt(6);
fail();
} catch (IllegalArgumentException ignored) {
}
DataChunk.Split<DoublePoint, DoubleDataChunk> split = chunk.splitAt(4);
assertNotNull(split.getChunk1());
assertNotNull(split.getChunk2());
assertEquals(1, split.getChunk1().getOffset());
assertInstanceOf(CompressedDoubleDataChunk.class, split.getChunk1());
assertEquals(3, ((CompressedDoubleDataChunk) split.getChunk1()).getUncompressedLength());
assertArrayEquals(new double[] {1d, 2d}, ((CompressedDoubleDataChunk) split.getChunk1()).getStepValues(), 0d);
assertArrayEquals(new int[] {2, 1}, ((CompressedDoubleDataChunk) split.getChunk1()).getStepLengths());
assertEquals(4, split.getChunk2().getOffset());
assertInstanceOf(CompressedDoubleDataChunk.class, split.getChunk2());
assertEquals(2, ((CompressedDoubleDataChunk) split.getChunk2()).getUncompressedLength());
assertArrayEquals(new double[] {2d}, ((CompressedDoubleDataChunk) split.getChunk2()).getStepValues(), 0d);
assertArrayEquals(new int[] {2}, ((CompressedDoubleDataChunk) split.getChunk2()).getStepLengths());
}
@Test
void uncompressedMergeTest() {
UncompressedDoubleDataChunk chunk1 = new UncompressedDoubleDataChunk(1, new double[]{1d, 2d, 3d, 4d, 5d});
UncompressedDoubleDataChunk chunk2 = new UncompressedDoubleDataChunk(6, new double[]{6d, 7d, 8d});
UncompressedDoubleDataChunk chunk3 = new UncompressedDoubleDataChunk(1, new double[]{6d, 7d, 8d});
//Merge chunk1 + chunk2
DoubleDataChunk merge = chunk1.append(chunk2);
assertNotNull(merge);
assertInstanceOf(UncompressedDoubleDataChunk.class, merge);
assertEquals(1, merge.getOffset());
assertArrayEquals(new double[] {1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d}, ((UncompressedDoubleDataChunk) merge).getValues(), 0d);
//Merge chunk1 + chunk3
try {
chunk1.append(chunk3);
fail();
} catch (IllegalArgumentException ignored) {
}
}
@Test
void compressedMergeTest() {
CompressedDoubleDataChunk chunk1 = new CompressedDoubleDataChunk(1, 5, new double[]{1d, 2d}, new int[]{2, 3});
CompressedDoubleDataChunk chunk2 = new CompressedDoubleDataChunk(6, 5, new double[]{3d, 4d}, new int[]{2, 3});
CompressedDoubleDataChunk chunk3 = new CompressedDoubleDataChunk(11, 6, new double[]{4d, 5d}, new int[]{5, 1});
//Merge chunk1 + chunk2
DoubleDataChunk merge = chunk1.append(chunk2);
assertNotNull(merge);
assertInstanceOf(CompressedDoubleDataChunk.class, merge);
assertEquals(1, merge.getOffset());
assertEquals(10, merge.getLength());
assertArrayEquals(new double[] {1d, 2d, 3d, 4d}, ((CompressedDoubleDataChunk) merge).getStepValues(), 0d);
assertArrayEquals(new int[] {2, 3, 2, 3}, ((CompressedDoubleDataChunk) merge).getStepLengths());
//Merge chunk2 + chunk3
merge = chunk2.append(chunk3);
assertNotNull(merge);
assertInstanceOf(CompressedDoubleDataChunk.class, merge);
assertEquals(6, merge.getOffset());
assertEquals(11, merge.getLength());
assertArrayEquals(new double[] {3d, 4d, 5d}, ((CompressedDoubleDataChunk) merge).getStepValues(), 0d);
assertArrayEquals(new int[] {2, 8, 1}, ((CompressedDoubleDataChunk) merge).getStepLengths());
//Merge chunk1 + chunk3
try {
chunk1.append(chunk3);
fail();
} catch (IllegalArgumentException ignored) {
}
}
@Test
void nanIssueTest() {
UncompressedDoubleDataChunk chunk = new UncompressedDoubleDataChunk(0, new double[] {1d, Double.NaN, Double.NaN});
String json = JsonUtil.toJson(chunk::writeJson);
String jsonRef = String.join(System.lineSeparator(),
"{",
" \"offset\" : 0,",
" \"values\" : [ 1.0, NaN, NaN ]",
"}");
assertEquals(jsonRef, json);
List<DoubleDataChunk> doubleChunks = new ArrayList<>();
List<StringDataChunk> stringChunks = new ArrayList<>();
JsonUtil.parseJson(json, parser -> {
DataChunk.parseJson(parser, doubleChunks, stringChunks);
return null;
});
assertEquals(1, doubleChunks.size());
assertEquals(0, stringChunks.size());
assertInstanceOf(UncompressedDoubleDataChunk.class, doubleChunks.get(0));
assertArrayEquals(new double[] {1d, Double.NaN, Double.NaN}, ((UncompressedDoubleDataChunk) doubleChunks.get(0)).getValues(), 0d);
}
}