From f0603be526a9080b65475b7ab04568c96b27ded7 Mon Sep 17 00:00:00 2001 From: oumaima-ech-chdig Date: Mon, 7 Oct 2024 13:59:54 +0200 Subject: [PATCH 1/4] Update of the Initialization of CParams, DParams, and Storage in Blosc2 --- examples/btune.py | 8 ++++---- examples/filler.py | 2 +- examples/pack_tensor.py | 7 +------ examples/postfilter1.py | 8 ++++---- examples/postfilter2.py | 8 ++++---- examples/postfilter3.py | 8 ++++---- examples/prefilter.py | 8 ++++---- examples/schunk.py | 10 +++++----- 8 files changed, 27 insertions(+), 32 deletions(-) diff --git a/examples/btune.py b/examples/btune.py index 6f2b414c..8b7bc44a 100644 --- a/examples/btune.py +++ b/examples/btune.py @@ -18,12 +18,12 @@ nchunks = 10 # Set the compression and decompression parameters, use BTUNE tuner -cparams = {"codec": blosc2.Codec.LZ4HC, "typesize": 4, "tuner": blosc2.Tuner.BTUNE} -dparams = {} +cparams = blosc2.CParams(codec=blosc2.Codec.LZ4HC, typesize=4, tuner=blosc2.Tuner.BTUNE) +dparams = blosc2.DParams() contiguous = True urlpath = "filename" -storage = {"contiguous": contiguous, "urlpath": urlpath, "cparams": cparams, "dparams": dparams} +storage = blosc2.Storage(contiguous=contiguous, urlpath=urlpath, mode='a') blosc2.remove_urlpath(urlpath) # Set the Btune configuration to use @@ -32,7 +32,7 @@ # Create the SChunk data = np.arange(200 * 1000 * nchunks) -schunk = blosc2.SChunk(chunksize=200 * 1000 * 4, data=data, **storage) +schunk = blosc2.SChunk(chunksize=200 * 1000 * 4, data=data, cparams=cparams, dparams=dparams, storage=storage) # Check data can be retrieved correctly data2 = np.empty(data.shape, dtype=data.dtype) diff --git a/examples/filler.py b/examples/filler.py index 7f8b1e82..bfd1c1a2 100644 --- a/examples/filler.py +++ b/examples/filler.py @@ -17,7 +17,7 @@ schunk_dtype = np.dtype(np.float64) # Set the compression parameters. We need nthreads=1 for this example. -cparams = {"typesize": schunk_dtype.itemsize, "nthreads": 1} +cparams = blosc2.CParams(typesize=schunk_dtype.itemsize, nthreads=1) # Create empty SChunk schunk = blosc2.SChunk(chunksize=chunk_len * schunk_dtype.itemsize, cparams=cparams) diff --git a/examples/pack_tensor.py b/examples/pack_tensor.py index f2b2ced9..82ec1e44 100644 --- a/examples/pack_tensor.py +++ b/examples/pack_tensor.py @@ -15,12 +15,7 @@ a = np.arange(1_000_000) -cparams = { - "codec": blosc2.Codec.ZSTD, - "clevel": 9, - "filters": [blosc2.Filter.BITSHUFFLE], - "filters_meta": [0], -} +cparams = blosc2.CParams(codec=blosc2.Codec.ZSTD, clevel=9, filters=[blosc2.Filter.BITSHUFFLE], filters_meta=[0]) cframe = blosc2.pack_tensor(a, cparams=cparams) print("Length of packed array in bytes:", len(cframe)) diff --git a/examples/postfilter1.py b/examples/postfilter1.py index a734284e..a69a2385 100644 --- a/examples/postfilter1.py +++ b/examples/postfilter1.py @@ -15,16 +15,16 @@ output_dtype = np.dtype(np.float32) # Set the compression and decompression parameters -cparams = {"codec": blosc2.Codec.LZ4, "typesize": 4} -dparams = {"nthreads": 1} +cparams = blosc2.CParams(codec=blosc2.Codec.LZ4, typesize=4) +dparams = blosc2.DParams(nthreads=1) contiguous = True urlpath = None -storage = {"contiguous": contiguous, "urlpath": urlpath, "cparams": cparams, "dparams": dparams} +storage = blosc2.Storage(contiguous=contiguous, urlpath=urlpath, mode='a') # Remove previous SChunk blosc2.remove_urlpath(urlpath) # Create and set data data = np.arange(200 * 1000 * nchunks, dtype=input_dtype) -schunk = blosc2.SChunk(chunksize=200 * 1000 * input_dtype.itemsize, data=data, **storage) +schunk = blosc2.SChunk(chunksize=200 * 1000 * input_dtype.itemsize, data=data, cparams=cparams, dparams=dparams, storage=storage) out1 = np.empty(200 * 1000 * nchunks, dtype=input_dtype) schunk.get_slice(0, 200 * 1000 * nchunks, out=out1) diff --git a/examples/postfilter2.py b/examples/postfilter2.py index c0069689..088cd95f 100644 --- a/examples/postfilter2.py +++ b/examples/postfilter2.py @@ -15,17 +15,17 @@ output_dtype = np.int64 # output dtype has to be of the same size as input # Set the compression and decompression parameters -cparams = {"codec": blosc2.Codec.LZ4, "typesize": input_dtype.itemsize} -dparams = {"nthreads": 1} +cparams = blosc2.CParams(codec=blosc2.Codec.LZ4, typesize=input_dtype.itemsize) +dparams = blosc2.DParams(nthreads=1) contiguous = True urlpath = "filename" -storage = {"contiguous": contiguous, "urlpath": urlpath, "cparams": cparams, "dparams": dparams} +storage = blosc2.Storage(contiguous=contiguous, urlpath=urlpath, mode='a') # Remove previous SChunk blosc2.remove_urlpath(urlpath) # Create and set data chunkshape = 200 * 1000 data = np.arange(0, chunkshape * nchunks, dtype=input_dtype) -schunk = blosc2.SChunk(chunksize=chunkshape * input_dtype.itemsize, data=data, **storage) +schunk = blosc2.SChunk(chunksize=chunkshape * input_dtype.itemsize, data=data, cparams=cparams, dparams=dparams, storage=storage) out1 = np.empty(chunkshape * nchunks, dtype=input_dtype) schunk.get_slice(0, chunkshape * nchunks, out=out1) diff --git a/examples/postfilter3.py b/examples/postfilter3.py index 8bbce1ec..53280fb6 100644 --- a/examples/postfilter3.py +++ b/examples/postfilter3.py @@ -14,17 +14,17 @@ input_dtype = np.dtype(np.int64) # Set the compression and decompression parameters -cparams = {"codec": blosc2.Codec.LZ4, "typesize": input_dtype.itemsize} -dparams = {"nthreads": 1} +cparams = blosc2.CParams(codec=blosc2.Codec.LZ4, typesize=input_dtype.itemsize) +dparams = blosc2.DParams(nthreads=1) contiguous = False urlpath = None -storage = {"contiguous": contiguous, "urlpath": urlpath, "cparams": cparams, "dparams": dparams} +storage = blosc2.Storage(contiguous=contiguous, urlpath=urlpath, mode='a') # Remove previous SChunk blosc2.remove_urlpath(urlpath) # Create and set data chunkshape = 20_000 data = np.zeros(chunkshape * nchunks, dtype=input_dtype) -schunk = blosc2.SChunk(chunksize=chunkshape * input_dtype.itemsize, data=data, **storage) +schunk = blosc2.SChunk(chunksize=chunkshape * input_dtype.itemsize, data=data, cparams=cparams, dparams=dparams, storage=storage) out1 = np.empty(chunkshape * nchunks, dtype=input_dtype) schunk.get_slice(0, chunkshape * nchunks, out=out1) diff --git a/examples/prefilter.py b/examples/prefilter.py index e181d72b..b9507f6f 100644 --- a/examples/prefilter.py +++ b/examples/prefilter.py @@ -17,11 +17,11 @@ output_dtype = np.dtype(np.float32) # Set the compression and decompression parameters -cparams = {"typesize": 4, "nthreads": 1} -dparams = {"nthreads": 4} -storage = {"cparams": cparams, "dparams": dparams} +cparams = blosc2.CParams(typesize=4, nthreads=1) +dparams = blosc2.DParams(nthreads=4) +storage = blosc2.Storage(mode='a') # Create empty schunk -schunk = blosc2.SChunk(chunksize=200 * 1000 * input_dtype.itemsize, **storage) +schunk = blosc2.SChunk(chunksize=200 * 1000 * input_dtype.itemsize, cparams=cparams, dparams=dparams, storage=storage) # Set prefilter with decorator diff --git a/examples/schunk.py b/examples/schunk.py index 0bd458cf..2487285d 100644 --- a/examples/schunk.py +++ b/examples/schunk.py @@ -12,19 +12,19 @@ nchunks = 10 # Set the compression and decompression parameters -cparams = {"codec": blosc2.Codec.LZ4HC, "typesize": 4} -dparams = {} +cparams = blosc2.CParams(codec=blosc2.Codec.LZ4HC, typesize=4) +dparams = blosc2.DParams() contiguous = True urlpath = "filename" -storage = {"contiguous": contiguous, "urlpath": urlpath, "cparams": cparams, "dparams": dparams} +storage = blosc2.Storage(contiguous=contiguous, urlpath=urlpath, mode='a') blosc2.remove_urlpath(urlpath) numpy_meta = {b"dtype": str(np.dtype("int32"))} test_meta = {b"lorem": 1234} meta = {"numpy": numpy_meta, "test": test_meta} # Create the empty SChunk -schunk = blosc2.SChunk(chunksize=200 * 1000 * 4, meta=meta, **storage) +schunk = blosc2.SChunk(chunksize=200 * 1000 * 4, meta=meta, cparams=cparams, dparams=dparams) # Append some chunks for i in range(nchunks): buffer = i * np.arange(200 * 1000, dtype="int32") @@ -54,7 +54,7 @@ # Update a chunk compressing the data first buffer = 11 * np.arange(200 * 1000, dtype="int32") -chunk = blosc2.compress2(buffer, **cparams) +chunk = blosc2.compress2(buffer, cparams=cparams) schunk.update_chunk(7, chunk) # Delete the 4th chunk From 5552be221f78aa07c714ec87e5456a2fb73317d1 Mon Sep 17 00:00:00 2001 From: oumaima-ech-chdig Date: Tue, 8 Oct 2024 10:33:02 +0200 Subject: [PATCH 2/4] More updated examples --- .../tutorials/00.schunk-basics.ipynb | 203 ++++---- .../01.schunk-slicing_and_beyond.ipynb | 135 +++--- .../tutorials/02.ndarray-basics.ipynb | 446 +++++++----------- .../tutorials/03.lazyarray-expressions.ipynb | 60 +-- .../tutorials/04.reductions.ipynb | 122 ++--- .../tutorials/10.ucodecs-ufilters.ipynb | 53 ++- examples/ndarray/bytedelta_filter.py | 4 +- examples/ndarray/empty_.py | 14 +- examples/ndarray/ndmean.py | 2 +- examples/ndarray/zfp_codec.py | 2 +- examples/schunk_roundtrip.py | 10 +- examples/ucodecs.py | 12 +- examples/ufilters.py | 11 +- 13 files changed, 510 insertions(+), 564 deletions(-) diff --git a/doc/getting_started/tutorials/00.schunk-basics.ipynb b/doc/getting_started/tutorials/00.schunk-basics.ipynb index c8fd71b5..b6a3a5a1 100644 --- a/doc/getting_started/tutorials/00.schunk-basics.ipynb +++ b/doc/getting_started/tutorials/00.schunk-basics.ipynb @@ -14,8 +14,8 @@ "execution_count": 1, "metadata": { "ExecuteTime": { - "end_time": "2023-06-20T08:56:06.847395Z", - "start_time": "2023-06-20T08:56:04.891386Z" + "end_time": "2024-10-08T07:48:22.080821Z", + "start_time": "2024-10-08T07:48:20.212845Z" } }, "outputs": [], @@ -36,32 +36,30 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 18, "metadata": { "ExecuteTime": { - "end_time": "2023-06-20T08:56:35.213472Z", - "start_time": "2023-06-20T08:56:35.185848Z" + "end_time": "2024-10-08T07:50:53.469230Z", + "start_time": "2024-10-08T07:50:53.461168Z" } }, "outputs": [], "source": [ - "cparams = {\n", - " \"codec\": blosc2.Codec.BLOSCLZ,\n", - " \"typesize\": 4,\n", - " \"nthreads\": 8,\n", - "}\n", + "cparams = blosc2.CParams(\n", + " codec=blosc2.Codec.BLOSCLZ,\n", + " typesize=4,\n", + " nthreads=8,\n", + ")\n", "\n", - "dparams = {\n", - " \"nthreads\": 16,\n", - "}\n", + "dparams = blosc2.DParams(\n", + " nthreads=16,\n", + ")\n", "\n", - "storage = {\n", - " \"contiguous\": True,\n", - " \"urlpath\": \"myfile.b2frame\",\n", - " \"mode\": \"w\", # create a new file\n", - " \"cparams\": cparams,\n", - " \"dparams\": dparams,\n", - "}" + "storage = blosc2.Storage(\n", + " contiguous=True,\n", + " urlpath=\"myfile.b2frame\",\n", + " mode=\"w\", # create a new file\n", + ")" ] }, { @@ -73,25 +71,27 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 19, "metadata": { "ExecuteTime": { - "end_time": "2023-06-20T08:56:39.138571Z", - "start_time": "2023-06-20T08:56:39.094692Z" + "end_time": "2024-10-08T07:50:56.622362Z", + "start_time": "2024-10-08T07:50:56.597445Z" } }, "outputs": [ { "data": { - "text/plain": "" + "text/plain": [ + "" + ] }, - "execution_count": 3, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "schunk = blosc2.SChunk(chunksize=10_000_000, **storage)\n", + "schunk = blosc2.SChunk(chunksize=10_000_000, cparams=cparams, dparams=dparams, storage=storage)\n", "schunk" ] }, @@ -113,11 +113,11 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 20, "metadata": { "ExecuteTime": { - "end_time": "2023-06-20T08:57:12.225714Z", - "start_time": "2023-06-20T08:57:11.198762Z" + "end_time": "2024-10-08T07:51:03.809479Z", + "start_time": "2024-10-08T07:51:02.468183Z" } }, "outputs": [], @@ -127,11 +127,11 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 21, "metadata": { "ExecuteTime": { - "end_time": "2023-06-20T08:57:13.599134Z", - "start_time": "2023-06-20T08:57:12.984832Z" + "end_time": "2024-10-08T07:51:08.644653Z", + "start_time": "2024-10-08T07:51:07.997097Z" } }, "outputs": [ @@ -139,8 +139,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 737 ms, sys: 223 ms, total: 959 ms\n", - "Wall time: 680 ms\n" + "CPU times: user 774 ms, sys: 289 ms, total: 1.06 s\n", + "Wall time: 639 ms\n" ] } ], @@ -153,11 +153,11 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 22, "metadata": { "ExecuteTime": { - "end_time": "2023-06-20T08:57:15.168245Z", - "start_time": "2023-06-20T08:57:15.005858Z" + "end_time": "2024-10-08T07:51:10.979618Z", + "start_time": "2024-10-08T07:51:10.824076Z" } }, "outputs": [ @@ -165,7 +165,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "-rw-r--r-- 1 martaiborra staff 53M Jun 20 10:57 myfile.b2frame\r\n" + "-rw-r--r-- 1 oma staff 54M Oct 8 09:51 myfile.b2frame\r\n" ] } ], @@ -184,11 +184,11 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 23, "metadata": { "ExecuteTime": { - "end_time": "2023-06-20T08:57:30.996015Z", - "start_time": "2023-06-20T08:57:30.983554Z" + "end_time": "2024-10-08T07:51:17.141694Z", + "start_time": "2024-10-08T07:51:17.136224Z" } }, "outputs": [], @@ -198,11 +198,11 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 24, "metadata": { "ExecuteTime": { - "end_time": "2023-06-20T08:57:32.836926Z", - "start_time": "2023-06-20T08:57:32.587284Z" + "end_time": "2024-10-08T07:51:18.278099Z", + "start_time": "2024-10-08T07:51:17.990015Z" } }, "outputs": [ @@ -210,8 +210,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 325 ms, sys: 268 ms, total: 594 ms\n", - "Wall time: 277 ms\n" + "CPU times: user 379 ms, sys: 333 ms, total: 711 ms\n", + "Wall time: 282 ms\n" ] } ], @@ -223,11 +223,11 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 25, "metadata": { "ExecuteTime": { - "end_time": "2023-06-20T08:57:35.151951Z", - "start_time": "2023-06-20T08:57:34.608295Z" + "end_time": "2024-10-08T07:51:49.498739Z", + "start_time": "2024-10-08T07:51:49.431546Z" } }, "outputs": [], @@ -247,11 +247,11 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 26, "metadata": { "ExecuteTime": { - "end_time": "2023-06-20T08:57:38.686069Z", - "start_time": "2023-06-20T08:57:38.659828Z" + "end_time": "2024-10-08T07:51:53.107201Z", + "start_time": "2024-10-08T07:51:53.089631Z" } }, "outputs": [], @@ -262,11 +262,11 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 27, "metadata": { "ExecuteTime": { - "end_time": "2023-06-20T08:57:40.609473Z", - "start_time": "2023-06-20T08:57:40.573103Z" + "end_time": "2024-10-08T07:51:54.399484Z", + "start_time": "2024-10-08T07:51:54.385346Z" } }, "outputs": [ @@ -274,15 +274,17 @@ "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 305 µs, sys: 1.14 ms, total: 1.45 ms\n", - "Wall time: 1.36 ms\n" + "CPU times: user 305 µs, sys: 1.13 ms, total: 1.43 ms\n", + "Wall time: 1.62 ms\n" ] }, { "data": { - "text/plain": "100" + "text/plain": [ + "100" + ] }, - "execution_count": 11, + "execution_count": 27, "metadata": {}, "output_type": "execute_result" } @@ -301,11 +303,11 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 28, "metadata": { "ExecuteTime": { - "end_time": "2023-06-20T08:57:43.390240Z", - "start_time": "2023-06-20T08:57:43.342470Z" + "end_time": "2024-10-08T07:51:56.639465Z", + "start_time": "2024-10-08T07:51:56.621955Z" } }, "outputs": [ @@ -313,15 +315,17 @@ "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 255 µs, sys: 1.13 ms, total: 1.38 ms\n", - "Wall time: 2.54 ms\n" + "CPU times: user 269 µs, sys: 1.05 ms, total: 1.32 ms\n", + "Wall time: 2.48 ms\n" ] }, { "data": { - "text/plain": "101" + "text/plain": [ + "101" + ] }, - "execution_count": 12, + "execution_count": 28, "metadata": {}, "output_type": "execute_result" } @@ -350,20 +354,22 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 29, "metadata": { "ExecuteTime": { - "end_time": "2023-06-20T09:33:56.509580Z", - "start_time": "2023-06-20T09:33:56.486725Z" + "end_time": "2024-10-08T07:51:58.887183Z", + "start_time": "2024-10-08T07:51:58.879102Z" }, "collapsed": false }, "outputs": [ { "data": { - "text/plain": "['meta1']" + "text/plain": [ + "['meta1']" + ] }, - "execution_count": 17, + "execution_count": 29, "metadata": {}, "output_type": "execute_result" } @@ -375,20 +381,22 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 30, "metadata": { "ExecuteTime": { - "end_time": "2023-06-20T09:34:36.117828Z", - "start_time": "2023-06-20T09:34:36.108260Z" + "end_time": "2024-10-08T07:52:02.039689Z", + "start_time": "2024-10-08T07:52:02.024043Z" }, "collapsed": false }, "outputs": [ { "data": { - "text/plain": "234" + "text/plain": [ + "234" + ] }, - "execution_count": 19, + "execution_count": 30, "metadata": {}, "output_type": "execute_result" } @@ -399,20 +407,22 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 31, "metadata": { "ExecuteTime": { - "end_time": "2023-06-20T09:35:03.927788Z", - "start_time": "2023-06-20T09:35:03.917223Z" + "end_time": "2024-10-08T07:52:02.899323Z", + "start_time": "2024-10-08T07:52:02.892155Z" }, "collapsed": false }, "outputs": [ { "data": { - "text/plain": "235" + "text/plain": [ + "235" + ] }, - "execution_count": 20, + "execution_count": 31, "metadata": {}, "output_type": "execute_result" } @@ -435,19 +445,21 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 32, "metadata": { "ExecuteTime": { - "end_time": "2023-06-20T08:58:10.944357Z", - "start_time": "2023-06-20T08:58:10.899490Z" + "end_time": "2024-10-08T07:52:06.505484Z", + "start_time": "2024-10-08T07:52:06.496675Z" } }, "outputs": [ { "data": { - "text/plain": "{b'info1': 'This is an example', b'info2': 'of user meta handling'}" + "text/plain": [ + "{b'info1': 'This is an example', b'info2': 'of user meta handling'}" + ] }, - "execution_count": 13, + "execution_count": 32, "metadata": {}, "output_type": "execute_result" } @@ -467,19 +479,21 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 33, "metadata": { "ExecuteTime": { - "end_time": "2023-06-20T08:58:19.331481Z", - "start_time": "2023-06-20T08:58:19.295516Z" + "end_time": "2024-10-08T07:52:08.528185Z", + "start_time": "2024-10-08T07:52:08.522120Z" } }, "outputs": [ { "data": { - "text/plain": "{b'info2': 'of user meta handling'}" + "text/plain": [ + "{b'info2': 'of user meta handling'}" + ] }, - "execution_count": 14, + "execution_count": 33, "metadata": {}, "output_type": "execute_result" } @@ -495,6 +509,13 @@ "source": [ "That's all for now. There are more examples in the [examples directory of the git repository](https://github.com/Blosc/python-blosc2/tree/main/examples) for you to explore. Enjoy!" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/doc/getting_started/tutorials/01.schunk-slicing_and_beyond.ipynb b/doc/getting_started/tutorials/01.schunk-slicing_and_beyond.ipynb index 718c9f48..4ff4e928 100644 --- a/doc/getting_started/tutorials/01.schunk-slicing_and_beyond.ipynb +++ b/doc/getting_started/tutorials/01.schunk-slicing_and_beyond.ipynb @@ -11,14 +11,12 @@ }, { "cell_type": "code", - "execution_count": 11, "metadata": { "ExecuteTime": { - "end_time": "2023-06-20T10:20:35.507212Z", - "start_time": "2023-06-20T10:20:35.228091Z" + "end_time": "2024-10-08T07:53:25.108040Z", + "start_time": "2024-10-08T07:53:25.079638Z" } }, - "outputs": [], "source": [ "import numpy as np\n", "\n", @@ -26,9 +24,11 @@ "\n", "nchunks = 10\n", "data = np.arange(200 * 1000 * nchunks, dtype=np.int32)\n", - "cparams = {\"typesize\": 4}\n", + "cparams = blosc2.CParams(typesize=4)\n", "schunk = blosc2.SChunk(chunksize=200 * 1000 * 4, data=data, cparams=cparams)" - ] + ], + "outputs": [], + "execution_count": 11 }, { "cell_type": "markdown", @@ -43,19 +43,19 @@ }, { "cell_type": "code", - "execution_count": 12, "metadata": { "ExecuteTime": { - "end_time": "2023-06-20T10:20:35.511148Z", - "start_time": "2023-06-20T10:20:35.270231Z" + "end_time": "2024-10-08T07:53:27.343758Z", + "start_time": "2024-10-08T07:53:27.332204Z" } }, - "outputs": [], "source": [ "out = np.empty(200 * 1000 * nchunks, dtype=np.int32)\n", "for i in range(nchunks):\n", " schunk.decompress_chunk(i, out[200 * 1000 * i : 200 * 1000 * (i + 1)])" - ] + ], + "outputs": [], + "execution_count": 12 }, { "cell_type": "markdown", @@ -66,27 +66,29 @@ }, { "cell_type": "code", - "execution_count": 13, "metadata": { "ExecuteTime": { - "end_time": "2023-06-20T10:20:35.519990Z", - "start_time": "2023-06-20T10:20:35.304350Z" + "end_time": "2024-10-08T07:53:30.596Z", + "start_time": "2024-10-08T07:53:30.569975Z" } }, + "source": [ + "out_slice = schunk[:]\n", + "type(out_slice)" + ], "outputs": [ { "data": { - "text/plain": "bytes" + "text/plain": [ + "bytes" + ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], - "source": [ - "out_slice = schunk[:]\n", - "type(out_slice)" - ] + "execution_count": 13 }, { "cell_type": "markdown", @@ -97,13 +99,18 @@ }, { "cell_type": "code", - "execution_count": 14, "metadata": { "ExecuteTime": { - "end_time": "2023-06-20T10:20:35.525236Z", - "start_time": "2023-06-20T10:20:35.336814Z" + "end_time": "2024-10-08T07:53:35.334366Z", + "start_time": "2024-10-08T07:53:35.300689Z" } }, + "source": [ + "out_slice = np.empty(200 * 1000 * nchunks, dtype=np.int32)\n", + "schunk.get_slice(out=out_slice)\n", + "np.array_equal(out, out_slice)\n", + "print(out_slice[:4])" + ], "outputs": [ { "name": "stdout", @@ -113,12 +120,7 @@ ] } ], - "source": [ - "out_slice = np.empty(200 * 1000 * nchunks, dtype=np.int32)\n", - "schunk.get_slice(out=out_slice)\n", - "np.array_equal(out, out_slice)\n", - "print(out_slice[:4])" - ] + "execution_count": 14 }, { "cell_type": "markdown", @@ -133,20 +135,20 @@ }, { "cell_type": "code", - "execution_count": 15, "metadata": { "ExecuteTime": { - "end_time": "2023-06-20T10:20:35.527561Z", - "start_time": "2023-06-20T10:20:35.353345Z" + "end_time": "2024-10-08T07:53:38.365602Z", + "start_time": "2024-10-08T07:53:38.353159Z" } }, - "outputs": [], "source": [ "start = 34\n", "stop = 1000 * 200 * 4\n", "new_value = np.ones(stop - start, dtype=np.int32)\n", "schunk[start:stop] = new_value" - ] + ], + "outputs": [], + "execution_count": 15 }, { "cell_type": "markdown", @@ -157,14 +159,12 @@ }, { "cell_type": "code", - "execution_count": 16, "metadata": { "ExecuteTime": { - "end_time": "2023-06-20T10:20:35.527871Z", - "start_time": "2023-06-20T10:20:35.368583Z" + "end_time": "2024-10-08T07:53:41.529220Z", + "start_time": "2024-10-08T07:53:41.518617Z" } }, - "outputs": [], "source": [ "schunk_nelems = 1000 * 200 * nchunks\n", "\n", @@ -172,7 +172,9 @@ "start = schunk_nelems - 123\n", "new_nitems = start + new_value.size\n", "schunk[start:new_nitems] = new_value" - ] + ], + "outputs": [], + "execution_count": 16 }, { "cell_type": "markdown", @@ -194,17 +196,17 @@ }, { "cell_type": "code", - "execution_count": 17, "metadata": { "ExecuteTime": { - "end_time": "2023-06-20T10:20:35.529947Z", - "start_time": "2023-06-20T10:20:35.379228Z" + "end_time": "2024-10-08T07:53:44.648399Z", + "start_time": "2024-10-08T07:53:44.639895Z" } }, - "outputs": [], "source": [ "buf = schunk.to_cframe()" - ] + ], + "outputs": [], + "execution_count": 17 }, { "cell_type": "markdown", @@ -215,17 +217,17 @@ }, { "cell_type": "code", - "execution_count": 18, "metadata": { "ExecuteTime": { - "end_time": "2023-06-20T10:20:35.542962Z", - "start_time": "2023-06-20T10:20:35.388249Z" + "end_time": "2024-10-08T07:53:47.319573Z", + "start_time": "2024-10-08T07:53:47.315552Z" } }, - "outputs": [], "source": [ "schunk2 = blosc2.schunk_from_cframe(cframe=buf, copy=True)" - ] + ], + "outputs": [], + "execution_count": 18 }, { "cell_type": "markdown", @@ -245,20 +247,20 @@ }, { "cell_type": "code", - "execution_count": 19, "metadata": { "ExecuteTime": { - "end_time": "2023-06-20T10:20:54.023391Z", - "start_time": "2023-06-20T10:20:35.396904Z" + "end_time": "2024-10-08T07:54:08.304326Z", + "start_time": "2024-10-08T07:53:51.028111Z" } }, - "outputs": [], "source": [ "np_array = np.arange(2**30, dtype=np.int32) # 4 GB array\n", "\n", "packed_arr2 = blosc2.pack_tensor(np_array)\n", "unpacked_arr2 = blosc2.unpack_tensor(packed_arr2)" - ] + ], + "outputs": [], + "execution_count": 19 }, { "cell_type": "markdown", @@ -271,28 +273,30 @@ }, { "cell_type": "code", - "execution_count": 20, "metadata": { "ExecuteTime": { - "end_time": "2023-06-20T10:21:15.080447Z", - "start_time": "2023-06-20T10:20:54.892944Z" + "end_time": "2024-10-08T07:54:32.551242Z", + "start_time": "2024-10-08T07:54:10.547445Z" } }, + "source": [ + "blosc2.save_tensor(np_array, urlpath=\"ondisk_array.b2frame\", mode=\"w\")\n", + "np_array2 = blosc2.load_tensor(\"ondisk_array.b2frame\")\n", + "np.array_equal(np_array, np_array2)" + ], "outputs": [ { "data": { - "text/plain": "True" + "text/plain": [ + "True" + ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], - "source": [ - "blosc2.save_tensor(np_array, urlpath=\"ondisk_array.b2frame\", mode=\"w\")\n", - "np_array2 = blosc2.load_tensor(\"ondisk_array.b2frame\")\n", - "np.array_equal(np_array, np_array2)" - ] + "execution_count": 20 }, { "cell_type": "markdown", @@ -302,6 +306,13 @@ "\n", "Now python-blosc2 offers an easy, yet fast way of creating, getting, setting and expanding data via the `SChunk` class. Moreover, you can get a contiguous compressed representation (aka [cframe](https://github.com/Blosc/c-blosc2/blob/main/README_CFRAME_FORMAT.rst)) of it and re-create it again later with no sweat.\n" ] + }, + { + "metadata": {}, + "cell_type": "code", + "outputs": [], + "execution_count": null, + "source": "" } ], "metadata": { diff --git a/doc/getting_started/tutorials/02.ndarray-basics.ipynb b/doc/getting_started/tutorials/02.ndarray-basics.ipynb index 2012a14f..04544204 100644 --- a/doc/getting_started/tutorials/02.ndarray-basics.ipynb +++ b/doc/getting_started/tutorials/02.ndarray-basics.ipynb @@ -12,19 +12,19 @@ }, { "cell_type": "code", - "execution_count": 1, "metadata": { "ExecuteTime": { - "end_time": "2024-02-01T13:48:41.426033Z", - "start_time": "2024-02-01T13:48:39.730441Z" + "end_time": "2024-10-08T07:56:33.037210Z", + "start_time": "2024-10-08T07:56:33.032553Z" } }, - "outputs": [], "source": [ "import numpy as np\n", "\n", "import blosc2" - ] + ], + "outputs": [], + "execution_count": 26 }, { "cell_type": "markdown", @@ -36,13 +36,16 @@ }, { "cell_type": "code", - "execution_count": 2, "metadata": { "ExecuteTime": { - "end_time": "2024-02-01T13:48:41.445534Z", - "start_time": "2024-02-01T13:48:41.438272Z" + "end_time": "2024-10-08T07:56:34.647278Z", + "start_time": "2024-10-08T07:56:34.623875Z" } }, + "source": [ + "array = blosc2.zeros((10000, 10000), dtype=np.int32)\n", + "print(array.info)" + ], "outputs": [ { "name": "stdout", @@ -50,11 +53,11 @@ "text": [ "type : NDArray\n", "shape : (10000, 10000)\n", - "chunks : (512, 1024)\n", - "blocks : (128, 256)\n", + "chunks : (25, 10000)\n", + "blocks : (2, 10000)\n", "dtype : int32\n", - "cratio : 65536.00\n", - "cparams : {'blocksize': 131072,\n", + "cratio : 32500.00\n", + "cparams : {'blocksize': 80000,\n", " 'clevel': 1,\n", " 'codec': ,\n", " 'codec_meta': 0,\n", @@ -65,18 +68,16 @@ " ,\n", " ],\n", " 'filters_meta': [0, 0, 0, 0, 0, 0],\n", - " 'nthreads': 6,\n", + " 'nthreads': 4,\n", " 'splitmode': ,\n", " 'typesize': 4,\n", " 'use_dict': 0}\n", - "dparams : {'nthreads': 6}\n" + "dparams : {'nthreads': 4}\n", + "\n" ] } ], - "source": [ - "array = blosc2.zeros((10000, 10000), dtype=np.int32)\n", - "print(array.info)" - ] + "execution_count": 27 }, { "cell_type": "markdown", @@ -90,87 +91,93 @@ }, { "cell_type": "code", - "execution_count": 3, "metadata": { "ExecuteTime": { - "end_time": "2024-02-01T13:48:41.497932Z", - "start_time": "2024-02-01T13:48:41.459032Z" + "end_time": "2024-10-08T07:56:36.157687Z", + "start_time": "2024-10-08T07:56:36.031592Z" } }, - "outputs": [], "source": [ "array[0, :] = np.arange(10000, dtype=array.dtype)\n", "array[:, 0] = np.arange(10000, dtype=array.dtype)" - ] + ], + "outputs": [], + "execution_count": 28 }, { "cell_type": "code", - "execution_count": 4, "metadata": { "ExecuteTime": { - "end_time": "2024-02-01T13:48:41.499948Z", - "start_time": "2024-02-01T13:48:41.473018Z" + "end_time": "2024-10-08T07:56:36.493800Z", + "start_time": "2024-10-08T07:56:36.479202Z" } }, + "source": [ + "array[0, 0]" + ], "outputs": [ { "data": { - "text/plain": "array(0, dtype=int32)" + "text/plain": [ + "array(0, dtype=int32)" + ] }, - "execution_count": 4, + "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], - "source": [ - "array[0, 0]" - ] + "execution_count": 29 }, { "cell_type": "code", - "execution_count": 5, "metadata": { "ExecuteTime": { - "end_time": "2024-02-01T13:48:41.540871Z", - "start_time": "2024-02-01T13:48:41.484602Z" + "end_time": "2024-10-08T07:56:37.078878Z", + "start_time": "2024-10-08T07:56:37.069792Z" } }, + "source": [ + "array[0, :]" + ], "outputs": [ { "data": { - "text/plain": "array([ 0, 1, 2, ..., 9997, 9998, 9999], dtype=int32)" + "text/plain": [ + "array([ 0, 1, 2, ..., 9997, 9998, 9999], dtype=int32)" + ] }, - "execution_count": 5, + "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], - "source": [ - "array[0, :]" - ] + "execution_count": 30 }, { "cell_type": "code", - "execution_count": 6, "metadata": { "ExecuteTime": { - "end_time": "2024-02-01T13:48:41.541970Z", - "start_time": "2024-02-01T13:48:41.494320Z" + "end_time": "2024-10-08T07:56:37.794476Z", + "start_time": "2024-10-08T07:56:37.731823Z" } }, + "source": [ + "array[:, 0]" + ], "outputs": [ { "data": { - "text/plain": "array([ 0, 1, 2, ..., 9997, 9998, 9999], dtype=int32)" + "text/plain": [ + "array([ 0, 1, 2, ..., 9997, 9998, 9999], dtype=int32)" + ] }, - "execution_count": 6, + "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], - "source": [ - "array[:, 0]" - ] + "execution_count": 31 }, { "cell_type": "markdown", @@ -183,13 +190,23 @@ }, { "cell_type": "code", - "execution_count": 7, "metadata": { "ExecuteTime": { - "end_time": "2024-02-01T13:48:41.592610Z", - "start_time": "2024-02-01T13:48:41.581711Z" + "end_time": "2024-10-08T07:56:40.158664Z", + "start_time": "2024-10-08T07:56:40.023997Z" } }, + "source": [ + "array = blosc2.full(\n", + " (1000, 1000),\n", + " fill_value=b\"pepe\",\n", + " chunks=(100, 100),\n", + " blocks=(50, 50),\n", + " urlpath=\"ndarray_tutorial.b2nd\",\n", + " mode=\"w\",\n", + ")\n", + "print(array.info)" + ], "outputs": [ { "name": "stdout", @@ -212,25 +229,16 @@ " ,\n", " ],\n", " 'filters_meta': [0, 0, 0, 0, 0, 0],\n", - " 'nthreads': 6,\n", + " 'nthreads': 4,\n", " 'splitmode': ,\n", " 'typesize': 4,\n", " 'use_dict': 0}\n", - "dparams : {'nthreads': 6}\n" + "dparams : {'nthreads': 4}\n", + "\n" ] } ], - "source": [ - "array = blosc2.full(\n", - " (1000, 1000),\n", - " fill_value=b\"pepe\",\n", - " chunks=(100, 100),\n", - " blocks=(50, 50),\n", - " urlpath=\"ndarray_tutorial.b2nd\",\n", - " mode=\"w\",\n", - ")\n", - "print(array.info)" - ] + "execution_count": 32 }, { "cell_type": "markdown", @@ -241,13 +249,16 @@ }, { "cell_type": "code", - "execution_count": 8, "metadata": { "ExecuteTime": { - "end_time": "2024-02-01T13:48:41.593734Z", - "start_time": "2024-02-01T13:48:41.586251Z" + "end_time": "2024-10-08T07:56:42.314419Z", + "start_time": "2024-10-08T07:56:42.308506Z" } }, + "source": [ + "array2 = blosc2.open(\"ndarray_tutorial.b2nd\")\n", + "print(array2.info)" + ], "outputs": [ { "name": "stdout", @@ -270,18 +281,16 @@ " ,\n", " ],\n", " 'filters_meta': [0, 0, 0, 0, 0, 0],\n", - " 'nthreads': 6,\n", + " 'nthreads': 1,\n", " 'splitmode': ,\n", " 'typesize': 4,\n", " 'use_dict': 0}\n", - "dparams : {'nthreads': 6}\n" + "dparams : {'nthreads': 1}\n", + "\n" ] } ], - "source": [ - "array2 = blosc2.open(\"ndarray_tutorial.b2nd\")\n", - "print(array2.info)" - ] + "execution_count": 33 }, { "cell_type": "markdown", @@ -293,13 +302,17 @@ }, { "cell_type": "code", - "execution_count": 9, "metadata": { "ExecuteTime": { - "end_time": "2024-02-01T13:48:41.679224Z", - "start_time": "2024-02-01T13:48:41.591484Z" + "end_time": "2024-10-08T08:01:21.290860Z", + "start_time": "2024-10-08T08:01:21.216404Z" } }, + "source": [ + "b = np.arange(1000000).tobytes()\n", + "array1 = blosc2.frombuffer(b, shape=(1000, 1000), dtype=np.int64, chunks=(500, 10), blocks=(50, 10))\n", + "print(array1.info)" + ], "outputs": [ { "name": "stdout", @@ -322,70 +335,52 @@ " ,\n", " ],\n", " 'filters_meta': [0, 0, 0, 0, 0, 0],\n", - " 'nthreads': 6,\n", + " 'nthreads': 4,\n", " 'splitmode': ,\n", " 'typesize': 8,\n", " 'use_dict': 0}\n", - "dparams : {'nthreads': 6}\n" + "dparams : {'nthreads': 4}\n", + "\n" ] } ], - "source": [ - "b = np.arange(1000000).tobytes()\n", - "array1 = blosc2.frombuffer(b, shape=(1000, 1000), dtype=np.int64, chunks=(500, 10), blocks=(50, 10))\n", - "print(array1.info)" - ] + "execution_count": 38 }, { "cell_type": "code", - "execution_count": 10, "metadata": { "ExecuteTime": { - "end_time": "2024-02-01T13:48:42.618064Z", - "start_time": "2024-02-01T13:48:42.598309Z" + "end_time": "2024-10-08T08:01:22.190912Z", + "start_time": "2024-10-08T08:01:22.132568Z" } }, + "source": [ + "cparams = blosc2.CParams(\n", + " codec=blosc2.Codec.ZSTD,\n", + " clevel=9,\n", + " filters=[blosc2.Filter.BITSHUFFLE],\n", + " filters_meta=[0],\n", + ")\n", + "\n", + "array2 = array1.copy(chunks=(500, 10), blocks=(50, 10), cparams=cparams)\n", + "print(array2.info)" + ], "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "type : NDArray\n", - "shape : (1000, 1000)\n", - "chunks : (500, 10)\n", - "blocks : (50, 10)\n", - "dtype : int64\n", - "cratio : 13.94\n", - "cparams : {'blocksize': 4000,\n", - " 'clevel': 9,\n", - " 'codec': ,\n", - " 'codec_meta': 0,\n", - " 'filters': [,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ],\n", - " 'filters_meta': [0, 0, 0, 0, 0, 0],\n", - " 'nthreads': 6,\n", - " 'splitmode': ,\n", - " 'typesize': 8,\n", - " 'use_dict': 0}\n", - "dparams : {'nthreads': 6}\n" + "ename": "TypeError", + "evalue": "asdict() should be called on dataclass instances", + "output_type": "error", + "traceback": [ + "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", + "\u001B[0;31mTypeError\u001B[0m Traceback (most recent call last)", + "Cell \u001B[0;32mIn[39], line 8\u001B[0m\n\u001B[1;32m 1\u001B[0m cparams \u001B[38;5;241m=\u001B[39m blosc2\u001B[38;5;241m.\u001B[39mCParams(\n\u001B[1;32m 2\u001B[0m codec\u001B[38;5;241m=\u001B[39mblosc2\u001B[38;5;241m.\u001B[39mCodec\u001B[38;5;241m.\u001B[39mZSTD,\n\u001B[1;32m 3\u001B[0m clevel\u001B[38;5;241m=\u001B[39m\u001B[38;5;241m9\u001B[39m,\n\u001B[1;32m 4\u001B[0m filters\u001B[38;5;241m=\u001B[39m[blosc2\u001B[38;5;241m.\u001B[39mFilter\u001B[38;5;241m.\u001B[39mBITSHUFFLE],\n\u001B[1;32m 5\u001B[0m filters_meta\u001B[38;5;241m=\u001B[39m[\u001B[38;5;241m0\u001B[39m],\n\u001B[1;32m 6\u001B[0m )\n\u001B[0;32m----> 8\u001B[0m array2 \u001B[38;5;241m=\u001B[39m array1\u001B[38;5;241m.\u001B[39mcopy(chunks\u001B[38;5;241m=\u001B[39m(\u001B[38;5;241m500\u001B[39m, \u001B[38;5;241m10\u001B[39m), blocks\u001B[38;5;241m=\u001B[39m(\u001B[38;5;241m50\u001B[39m, \u001B[38;5;241m10\u001B[39m), cparams\u001B[38;5;241m=\u001B[39mcparams)\n\u001B[1;32m 9\u001B[0m \u001B[38;5;28mprint\u001B[39m(array2\u001B[38;5;241m.\u001B[39minfo)\n", + "File \u001B[0;32m~/blosc/python-blosc2/src/blosc2/ndarray.py:1356\u001B[0m, in \u001B[0;36mNDArray.copy\u001B[0;34m(self, dtype, **kwargs)\u001B[0m\n\u001B[1;32m 1351\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m dtype \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m:\n\u001B[1;32m 1352\u001B[0m dtype \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mdtype\n\u001B[1;32m 1353\u001B[0m kwargs[\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mcparams\u001B[39m\u001B[38;5;124m\"\u001B[39m] \u001B[38;5;241m=\u001B[39m (\n\u001B[1;32m 1354\u001B[0m kwargs\u001B[38;5;241m.\u001B[39mget(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mcparams\u001B[39m\u001B[38;5;124m\"\u001B[39m)\u001B[38;5;241m.\u001B[39mcopy()\n\u001B[1;32m 1355\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28misinstance\u001B[39m(kwargs\u001B[38;5;241m.\u001B[39mget(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mcparams\u001B[39m\u001B[38;5;124m\"\u001B[39m), \u001B[38;5;28mdict\u001B[39m)\n\u001B[0;32m-> 1356\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m asdict(\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mschunk\u001B[38;5;241m.\u001B[39mcparams)\n\u001B[1;32m 1357\u001B[0m )\n\u001B[1;32m 1358\u001B[0m kwargs[\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mdparams\u001B[39m\u001B[38;5;124m\"\u001B[39m] \u001B[38;5;241m=\u001B[39m (\n\u001B[1;32m 1359\u001B[0m kwargs\u001B[38;5;241m.\u001B[39mget(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mdparams\u001B[39m\u001B[38;5;124m\"\u001B[39m)\u001B[38;5;241m.\u001B[39mcopy()\n\u001B[1;32m 1360\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28misinstance\u001B[39m(kwargs\u001B[38;5;241m.\u001B[39mget(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mdparams\u001B[39m\u001B[38;5;124m\"\u001B[39m), \u001B[38;5;28mdict\u001B[39m)\n\u001B[1;32m 1361\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m asdict(\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mschunk\u001B[38;5;241m.\u001B[39mdparams)\n\u001B[1;32m 1362\u001B[0m )\n\u001B[1;32m 1363\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mmeta\u001B[39m\u001B[38;5;124m\"\u001B[39m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;129;01min\u001B[39;00m kwargs:\n\u001B[1;32m 1364\u001B[0m \u001B[38;5;66;03m# Copy metalayers as well\u001B[39;00m\n", + "File \u001B[0;32m~/opt/miniconda3/lib/python3.12/dataclasses.py:1319\u001B[0m, in \u001B[0;36masdict\u001B[0;34m(obj, dict_factory)\u001B[0m\n\u001B[1;32m 1300\u001B[0m \u001B[38;5;250m\u001B[39m\u001B[38;5;124;03m\"\"\"Return the fields of a dataclass instance as a new dictionary mapping\u001B[39;00m\n\u001B[1;32m 1301\u001B[0m \u001B[38;5;124;03mfield names to field values.\u001B[39;00m\n\u001B[1;32m 1302\u001B[0m \n\u001B[0;32m (...)\u001B[0m\n\u001B[1;32m 1316\u001B[0m \u001B[38;5;124;03mtuples, lists, and dicts. Other objects are copied with 'copy.deepcopy()'.\u001B[39;00m\n\u001B[1;32m 1317\u001B[0m \u001B[38;5;124;03m\"\"\"\u001B[39;00m\n\u001B[1;32m 1318\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m _is_dataclass_instance(obj):\n\u001B[0;32m-> 1319\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mTypeError\u001B[39;00m(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124masdict() should be called on dataclass instances\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[1;32m 1320\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m _asdict_inner(obj, dict_factory)\n", + "\u001B[0;31mTypeError\u001B[0m: asdict() should be called on dataclass instances" ] } ], - "source": [ - "cparams = {\n", - " \"codec\": blosc2.Codec.ZSTD,\n", - " \"clevel\": 9,\n", - " \"filters\": [blosc2.Filter.BITSHUFFLE],\n", - " \"filters_meta\": [0],\n", - "}\n", - "\n", - "array2 = array1.copy(chunks=(500, 10), blocks=(50, 10), cparams=cparams)\n", - "print(array2.info)" - ] + "execution_count": 39 }, { "cell_type": "markdown", @@ -398,18 +393,18 @@ }, { "cell_type": "code", - "execution_count": 11, "metadata": { "ExecuteTime": { - "end_time": "2024-02-01T13:48:42.619267Z", - "start_time": "2024-02-01T13:48:42.608433Z" + "end_time": "2024-10-08T07:55:16.569975Z", + "start_time": "2024-10-08T07:55:16.569707Z" } }, - "outputs": [], "source": [ "meta = {\"dtype\": \"i8\", \"coords\": [5.14, 23.0]}\n", "array = blosc2.zeros((1000, 1000), dtype=np.int16, chunks=(100, 100), blocks=(50, 50), meta=meta)" - ] + ], + "outputs": [], + "execution_count": null }, { "cell_type": "markdown", @@ -420,49 +415,37 @@ }, { "cell_type": "code", - "execution_count": 12, - "metadata": { - "ExecuteTime": { - "end_time": "2024-02-01T13:48:42.690125Z", - "start_time": "2024-02-01T13:48:42.617894Z" - } - }, - "outputs": [ - { - "data": { - "text/plain": "" - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], + "metadata": {}, "source": [ "array.schunk.meta" - ] + ], + "outputs": [], + "execution_count": null }, { "cell_type": "code", - "execution_count": 13, "metadata": { "ExecuteTime": { - "end_time": "2024-02-01T13:48:42.691496Z", - "start_time": "2024-02-01T13:48:42.627564Z" + "end_time": "2024-10-08T07:55:16.594249Z", + "start_time": "2024-10-08T07:55:16.588761Z" } }, + "source": [ + "array.schunk.meta.keys()" + ], "outputs": [ { "data": { - "text/plain": "['b2nd', 'dtype', 'coords']" + "text/plain": [ + "['b2nd']" + ] }, - "execution_count": 13, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], - "source": [ - "array.schunk.meta.keys()" - ] + "execution_count": 23 }, { "cell_type": "markdown", @@ -473,49 +456,55 @@ }, { "cell_type": "code", - "execution_count": 14, "metadata": { "ExecuteTime": { - "end_time": "2024-02-01T13:48:42.694278Z", - "start_time": "2024-02-01T13:48:42.635275Z" + "end_time": "2024-10-08T07:55:16.642139Z", + "start_time": "2024-10-08T07:55:16.634598Z" } }, + "source": [ + "array.schunk.meta[\"b2nd\"]" + ], "outputs": [ { "data": { - "text/plain": "[0, 2, [1000, 1000], [100, 100], [50, 50], 0, ' 1\u001B[0m array\u001B[38;5;241m.\u001B[39mschunk\u001B[38;5;241m.\u001B[39mmeta[\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mcoords\u001B[39m\u001B[38;5;124m\"\u001B[39m]\n", + "File \u001B[0;32m~/blosc/python-blosc2/src/blosc2/schunk.py:122\u001B[0m, in \u001B[0;36mMeta.__getitem__\u001B[0;34m(self, item)\u001B[0m\n\u001B[1;32m 117\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m unpackb(\n\u001B[1;32m 118\u001B[0m blosc2_ext\u001B[38;5;241m.\u001B[39mmeta__getitem__(\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mschunk, item),\n\u001B[1;32m 119\u001B[0m list_hook\u001B[38;5;241m=\u001B[39mblosc2_ext\u001B[38;5;241m.\u001B[39mdecode_tuple,\n\u001B[1;32m 120\u001B[0m )\n\u001B[1;32m 121\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[0;32m--> 122\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mKeyError\u001B[39;00m(\u001B[38;5;124mf\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;132;01m{\u001B[39;00mitem\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m not found\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n", + "\u001B[0;31mKeyError\u001B[0m: 'coords not found'" + ] } ], - "source": [ - "array.schunk.meta[\"coords\"]" - ] + "execution_count": 25 }, { "cell_type": "markdown", @@ -526,36 +515,20 @@ }, { "cell_type": "code", - "execution_count": 16, "metadata": { "ExecuteTime": { - "end_time": "2024-02-01T13:48:42.802674Z", - "start_time": "2024-02-01T13:48:42.649615Z" + "end_time": "2024-10-08T07:55:16.848001Z", + "start_time": "2024-10-08T07:55:16.847803Z" } }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{}\n" - ] - }, - { - "data": { - "text/plain": "{b'info1': 'This is an example', b'info2': 'of user meta handling'}" - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "print(array.schunk.vlmeta.getall())\n", "array.schunk.vlmeta[\"info1\"] = \"This is an example\"\n", "array.schunk.vlmeta[\"info2\"] = \"of user meta handling\"\n", "array.schunk.vlmeta.getall()" - ] + ], + "outputs": [], + "execution_count": null }, { "cell_type": "markdown", @@ -566,27 +539,13 @@ }, { "cell_type": "code", - "execution_count": 17, - "metadata": { - "ExecuteTime": { - "end_time": "2024-02-01T13:48:42.803564Z", - "start_time": "2024-02-01T13:48:42.654680Z" - } - }, - "outputs": [ - { - "data": { - "text/plain": "{b'info1': 'This is a larger example', b'info2': 'of user meta handling'}" - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], + "metadata": {}, "source": [ "array.schunk.vlmeta[\"info1\"] = \"This is a larger example\"\n", "array.schunk.vlmeta.getall()" - ] + ], + "outputs": [], + "execution_count": null }, { "cell_type": "markdown", @@ -601,51 +560,18 @@ }, { "cell_type": "code", - "execution_count": 18, "metadata": { - "ExecuteTime": { - "end_time": "2024-02-01T13:48:42.821726Z", - "start_time": "2024-02-01T13:48:42.659936Z" - }, "collapsed": false }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "type : NDArray\n", - "shape : (100, 100, 100)\n", - "chunks : (64, 64, 100)\n", - "blocks : (32, 32, 32)\n", - "dtype : float64\n", - "cratio : 15.99\n", - "cparams : {'blocksize': 262144,\n", - " 'clevel': 1,\n", - " 'codec': ,\n", - " 'codec_meta': 0,\n", - " 'filters': [,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ],\n", - " 'filters_meta': [0, 0, 0, 0, 0, 0],\n", - " 'nthreads': 6,\n", - " 'splitmode': ,\n", - " 'typesize': 8,\n", - " 'use_dict': 0}\n", - "dparams : {'nthreads': 6}\n" - ] - } - ], "source": [ "shape = (100, 100, 100)\n", "dtype = np.float64\n", "nparray = np.linspace(0, 100, np.prod(shape), dtype=dtype).reshape(shape)\n", "b2ndarray = blosc2.asarray(nparray)\n", "print(b2ndarray.info)" - ] + ], + "outputs": [], + "execution_count": null }, { "cell_type": "markdown", @@ -660,38 +586,18 @@ }, { "cell_type": "code", - "execution_count": 19, "metadata": { - "ExecuteTime": { - "end_time": "2024-02-01T13:48:42.826284Z", - "start_time": "2024-02-01T13:48:42.704044Z" - }, "collapsed": false }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Compression ratio: 2.346534664543712\n" - ] - }, - { - "data": { - "text/plain": "array([[[ 5.42196142e+00, 2.73411248e-01, -8.16705224e-01,\n 1.37387920e+00, 4.67745267e+00],\n [-9.74870871e+00, 5.84935129e+00, 9.58553390e+00,\n -2.83529450e-01, 7.53172473e+00],\n [ 1.49656577e+00, 5.17716640e+00, 7.88381029e+00,\n 6.98547347e-01, -4.22113557e+00],\n [ 3.26899881e+00, -1.82539905e+00, -6.64803980e+00,\n 2.26750920e+00, -8.04904893e+00],\n [ 1.25639643e+01, 6.13877785e+00, 8.36071977e-01,\n 4.61057570e+00, 1.48929362e+01]],\n\n [[ 3.35584136e+00, 1.99526803e-01, -1.83173110e+01,\n -9.23138847e+00, -1.16172733e+00],\n [-5.03933967e+00, -1.12041458e+01, 4.03284196e+00,\n 1.00896486e+01, 1.66993503e+00],\n [-1.18575679e+01, -4.75050150e+00, 2.18309491e+00,\n 7.96693815e+00, -1.08675195e+01],\n [-8.88867651e+00, 2.61614522e+00, -1.21496391e+00,\n -1.07405006e+01, -1.62225644e+01],\n [-8.06054293e+00, 1.41019810e+01, 3.73009613e+00,\n 1.94280930e+00, -4.03920319e-01]],\n\n [[ 7.11325574e+00, 1.81344216e+00, -1.31212523e+01,\n 7.53794442e+00, 6.05015875e+00],\n [-3.72363480e+00, 1.51570884e+01, -2.04563128e-01,\n 2.48303234e+00, -2.40123746e+00],\n [-6.54960604e+00, -9.95287318e+00, -5.29298162e+00,\n 8.24236836e+00, 7.44135682e+00],\n [ 2.93987926e+00, -6.38440848e+00, -1.14590714e+00,\n 2.02831822e+00, 2.50627016e-03],\n [ 4.39693638e+00, 7.14526714e+00, -1.83301102e+00,\n 8.41598861e+00, -4.57312873e+00]],\n\n [[ 1.72690846e+01, 6.30828920e+00, -5.30917037e+00,\n 7.52455436e+00, 1.19643440e+01],\n [ 9.12355405e+00, 1.67975018e+00, 2.93640941e+00,\n -7.64215452e+00, 1.62410350e+00],\n [-1.55437404e+00, 9.49132288e-01, 8.92834289e+00,\n -1.37456729e+01, 9.86778010e+00],\n [-7.21853497e+00, -4.47973496e+00, 3.25376041e+00,\n -6.51526389e+00, 8.59162340e+00],\n [-9.83341081e+00, 9.25969121e+00, -1.36367239e+01,\n 8.07390571e+00, 6.14360462e-01]],\n\n [[ 4.65602528e+00, -1.48217159e+01, 7.67247150e+00,\n -1.41809697e+01, 8.29187072e+00],\n [-2.09188110e+01, -1.21744141e+01, -1.23980307e+00,\n -1.67901253e+01, -1.11255548e+01],\n [-1.71639719e+00, 8.41005260e+00, -9.16336234e+00,\n -9.91380613e+00, -9.34633040e-01],\n [-7.14082014e+00, -3.63309930e+00, 5.40634385e+00,\n -1.65522254e+00, 5.61551645e+00],\n [-6.91584808e-01, 1.46205820e+01, -6.56466213e+00,\n -3.79375418e+00, 6.82807996e+00]]])" - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "rng = np.random.default_rng()\n", "buffer = bytes(rng.normal(size=np.prod(shape)) * 8)\n", "b2ndarray = blosc2.frombuffer(buffer, shape, dtype=dtype)\n", "print(\"Compression ratio:\", b2ndarray.schunk.cratio)\n", "b2ndarray[:5, :5, :5]" - ] + ], + "outputs": [], + "execution_count": null }, { "cell_type": "markdown", diff --git a/doc/getting_started/tutorials/03.lazyarray-expressions.ipynb b/doc/getting_started/tutorials/03.lazyarray-expressions.ipynb index c358e63b..03d0dd2f 100644 --- a/doc/getting_started/tutorials/03.lazyarray-expressions.ipynb +++ b/doc/getting_started/tutorials/03.lazyarray-expressions.ipynb @@ -14,8 +14,8 @@ "execution_count": 1, "metadata": { "ExecuteTime": { - "end_time": "2024-06-18T11:28:44.570244Z", - "start_time": "2024-06-18T11:28:42.958292Z" + "end_time": "2024-10-08T08:02:44.264534Z", + "start_time": "2024-10-08T08:02:42.250807Z" } }, "outputs": [], @@ -38,8 +38,8 @@ "execution_count": 2, "metadata": { "ExecuteTime": { - "end_time": "2024-06-18T11:28:44.612950Z", - "start_time": "2024-06-18T11:28:44.575724Z" + "end_time": "2024-10-08T08:02:44.318974Z", + "start_time": "2024-10-08T08:02:44.270378Z" } }, "outputs": [], @@ -62,8 +62,8 @@ "execution_count": 3, "metadata": { "ExecuteTime": { - "end_time": "2024-06-18T11:28:44.623774Z", - "start_time": "2024-06-18T11:28:44.615967Z" + "end_time": "2024-10-08T08:02:44.335524Z", + "start_time": "2024-10-08T08:02:44.321803Z" } }, "outputs": [ @@ -101,8 +101,8 @@ "execution_count": 4, "metadata": { "ExecuteTime": { - "end_time": "2024-06-18T11:28:44.641281Z", - "start_time": "2024-06-18T11:28:44.626435Z" + "end_time": "2024-10-08T08:02:44.374777Z", + "start_time": "2024-10-08T08:02:44.339465Z" } }, "outputs": [ @@ -128,11 +128,11 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 7, "metadata": { "ExecuteTime": { - "end_time": "2024-06-18T11:28:44.837647Z", - "start_time": "2024-06-18T11:28:44.643376Z" + "end_time": "2024-10-08T08:03:35.576040Z", + "start_time": "2024-10-08T08:03:34.587292Z" } }, "outputs": [ @@ -140,12 +140,14 @@ "name": "stdout", "output_type": "stream", "text": [ - "Compression ratio: 2.10x\n" + "Compression ratio: 2.08x\n" ] } ], "source": [ - "cparams = {\"codec\": blosc2.Codec.ZSTD, \"filters\": [blosc2.Filter.BITSHUFFLE], \"clevel\": 9}\n", + "cparams = blosc2.CParams(\n", + " codec=blosc2.Codec.ZSTD, filters=[blosc2.Filter.BITSHUFFLE], clevel=9, filters_meta=[0]\n", + ")\n", "d = c.eval(cparams=cparams)\n", "print(f\"Compression ratio: {d.schunk.cratio:.2f}x\")" ] @@ -157,11 +159,11 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 8, "metadata": { "ExecuteTime": { - "end_time": "2024-06-18T11:28:44.848909Z", - "start_time": "2024-06-18T11:28:44.839555Z" + "end_time": "2024-10-08T08:03:38.778346Z", + "start_time": "2024-10-08T08:03:38.766508Z" } }, "outputs": [ @@ -190,11 +192,11 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 9, "metadata": { "ExecuteTime": { - "end_time": "2024-06-18T11:28:44.866877Z", - "start_time": "2024-06-18T11:28:44.850580Z" + "end_time": "2024-10-08T08:03:42.435049Z", + "start_time": "2024-10-08T08:03:42.424601Z" } }, "outputs": [], @@ -210,11 +212,11 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 10, "metadata": { "ExecuteTime": { - "end_time": "2024-06-18T11:28:44.877079Z", - "start_time": "2024-06-18T11:28:44.868540Z" + "end_time": "2024-10-08T08:03:44.143482Z", + "start_time": "2024-10-08T08:03:44.131993Z" } }, "outputs": [ @@ -243,11 +245,11 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 11, "metadata": { "ExecuteTime": { - "end_time": "2024-06-18T11:28:44.897246Z", - "start_time": "2024-06-18T11:28:44.880903Z" + "end_time": "2024-10-08T08:03:46.697195Z", + "start_time": "2024-10-08T08:03:46.656874Z" } }, "outputs": [ @@ -275,11 +277,11 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 12, "metadata": { "ExecuteTime": { - "end_time": "2024-06-18T11:28:44.916136Z", - "start_time": "2024-06-18T11:28:44.902534Z" + "end_time": "2024-10-08T08:03:47.858807Z", + "start_time": "2024-10-08T08:03:47.835261Z" } }, "outputs": [ @@ -289,7 +291,7 @@ "999999.9999999471" ] }, - "execution_count": 10, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } diff --git a/doc/getting_started/tutorials/04.reductions.ipynb b/doc/getting_started/tutorials/04.reductions.ipynb index f81ffc82..a4103df8 100644 --- a/doc/getting_started/tutorials/04.reductions.ipynb +++ b/doc/getting_started/tutorials/04.reductions.ipynb @@ -26,15 +26,13 @@ }, { "cell_type": "code", - "execution_count": 1, "id": "initial_id", "metadata": { "ExecuteTime": { - "end_time": "2024-08-23T08:35:38.283613Z", - "start_time": "2024-08-23T08:35:37.744567Z" + "end_time": "2024-10-08T08:09:33.940958Z", + "start_time": "2024-10-08T08:09:31.388787Z" } }, - "outputs": [], "source": [ "from time import time\n", "\n", @@ -42,26 +40,28 @@ "import numpy as np\n", "\n", "import blosc2" - ] + ], + "outputs": [], + "execution_count": 6 }, { "cell_type": "code", - "execution_count": 2, "id": "94a5fa3aad0a9d8b", "metadata": { "ExecuteTime": { - "end_time": "2024-08-23T08:35:38.461093Z", - "start_time": "2024-08-23T08:35:38.284710Z" + "end_time": "2024-10-08T08:09:40.296786Z", + "start_time": "2024-10-08T08:09:33.943533Z" } }, - "outputs": [], "source": [ "# Create a 3D array of type float64 (8 GB)\n", "dtype = np.float64\n", "shape = (1000, 1000, 1000)\n", "size = np.prod(shape)\n", "a = np.linspace(0, 1000, num=size, dtype=dtype).reshape(shape)" - ] + ], + "outputs": [], + "execution_count": 7 }, { "cell_type": "markdown", @@ -75,15 +75,13 @@ }, { "cell_type": "code", - "execution_count": 3, "id": "bbbd00951e2b16f6", "metadata": { "ExecuteTime": { - "end_time": "2024-08-23T08:35:38.579018Z", - "start_time": "2024-08-23T08:35:38.461714Z" + "end_time": "2024-10-08T08:09:43.197736Z", + "start_time": "2024-10-08T08:09:40.299433Z" } }, - "outputs": [], "source": [ "axes = (\"X\", \"Y\", \"Z\", \"all\")\n", "meas_np = {\"sum\": {}, \"time\": {}}\n", @@ -93,7 +91,9 @@ " meas_np[\"sum\"][axis] = np.sum(a, axis=n)\n", " t = time() - t0\n", " meas_np[\"time\"][axis] = time() - t0" - ] + ], + "outputs": [], + "execution_count": 8 }, { "cell_type": "markdown", @@ -107,20 +107,20 @@ }, { "cell_type": "code", - "execution_count": 4, "id": "21b3c02e2b03e1d8", "metadata": { "ExecuteTime": { - "end_time": "2024-08-23T08:35:38.581397Z", - "start_time": "2024-08-23T08:35:38.579700Z" + "end_time": "2024-10-08T08:09:43.206113Z", + "start_time": "2024-10-08T08:09:43.201684Z" } }, - "outputs": [], "source": [ "# Params for Blosc2\n", "clevels = (0, 5)\n", "codecs = (blosc2.Codec.LZ4, blosc2.Codec.ZSTD)" - ] + ], + "outputs": [], + "execution_count": 9 }, { "cell_type": "markdown", @@ -132,15 +132,13 @@ }, { "cell_type": "code", - "execution_count": 5, "id": "92217680c72e2ae4", "metadata": { "ExecuteTime": { - "end_time": "2024-08-23T08:35:38.585750Z", - "start_time": "2024-08-23T08:35:38.582786Z" + "end_time": "2024-10-08T08:09:43.219653Z", + "start_time": "2024-10-08T08:09:43.210405Z" } }, - "outputs": [], "source": [ "# Create a 3D array of type float64\n", "def measure_blosc2(chunks):\n", @@ -149,7 +147,7 @@ " meas[codec] = {}\n", " for clevel in clevels:\n", " meas[codec][clevel] = {\"sum\": {}, \"time\": {}}\n", - " cparams = {\"clevel\": clevel, \"codec\": codec}\n", + " cparams = blosc2.CParams(clevel=clevel, codec=codec)\n", " a1 = blosc2.asarray(a, chunks=chunks, cparams=cparams)\n", " if clevel > 0:\n", " print(f\"cratio for {codec.name} + SHUFFLE: {a1.schunk.cratio:.1f}x\")\n", @@ -165,7 +163,9 @@ " # np.testing.assert_allclose(meas[codec][clevel][\"sum\"][axis],\n", " # meas_np[\"sum\"][axis])\n", " return meas" - ] + ], + "outputs": [], + "execution_count": 10 }, { "cell_type": "markdown", @@ -177,15 +177,13 @@ }, { "cell_type": "code", - "execution_count": 6, "id": "fb0ce45807353475", "metadata": { "ExecuteTime": { - "end_time": "2024-08-23T08:35:38.590013Z", - "start_time": "2024-08-23T08:35:38.586424Z" + "end_time": "2024-10-08T08:09:43.231879Z", + "start_time": "2024-10-08T08:09:43.222961Z" } }, - "outputs": [], "source": [ "def plot_meas(meas_np, meas, chunks):\n", " _fig, ax = plt.subplots()\n", @@ -228,44 +226,46 @@ "\n", " plt.tight_layout()\n", " plt.show()" - ] + ], + "outputs": [], + "execution_count": 11 }, { "cell_type": "code", - "execution_count": 7, "id": "9314c555-f759-43dd-95dd-08772b2bfd3a", "metadata": { "ExecuteTime": { - "end_time": "2024-08-23T08:35:42.849758Z", - "start_time": "2024-08-23T08:35:38.590621Z" + "end_time": "2024-10-08T08:14:56.328625Z", + "start_time": "2024-10-08T08:09:43.235144Z" } }, + "source": [ + "# Automatic chunking: (1, 1000, 1000) for Intel 13900K\n", + "chunks = None\n", + "meas = measure_blosc2(chunks)\n", + "plot_meas(meas_np, meas, chunks)" + ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "cratio for LZ4 + SHUFFLE: 16.7x\n", - "cratio for ZSTD + SHUFFLE: 63.6x\n" + "cratio for LZ4 + SHUFFLE: 11.3x\n", + "cratio for ZSTD + SHUFFLE: 39.3x\n" ] }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAnYAAAHWCAYAAAD6oMSKAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAABTeklEQVR4nO3deXxNd/7H8fdNIoklCdkkCFH7mmRsRbVBbMWMUWpQOx1VW1NaW2OtqLHV3tqiP+3Q2scSNG1oMVQ1qqpaFaIkdokkFZLc3x8e7vQ2QUKSy/F6Ph7n8ej9nu8538+596q371muyWw2mwUAAIAnnp2tCwAAAEDeINgBAAAYBMEOAADAIAh2AAAABkGwAwAAMAiCHQAAgEEQ7AAAAAyCYAcAAGAQBDsAAACDINgBeGJERETIZDLp9OnTBT5279695e/vX+Dj5pQt3xsAjw+CHYBHcjdQ3F0cHBxUunRp9e7dW+fOnbN1ebly/vx5TZgwQTExMbYuRZIUHBxs9d7ea5kwYYKtSwXwmHCwdQEAjGHSpEkqX768bt68qf/+97+KiIjQ119/rR9++EHOzs62Li9Hzp8/r4kTJ8rf31+BgYFW65YsWaLMzMwCrWfs2LHq37+/5fU333yjuXPnasyYMapWrZqlvXbt2qpRo4b+8Y9/yMnJqUBrBPB4IdgByBNt2rRR3bp1JUn9+/eXp6en3nvvPW3evFkvv/yyjat7dIUKFSrwMVu0aGH12tnZWXPnzlWLFi0UHBycpb+9vX0BVQbgccWpWAD5okmTJpKkX3/91ar9p59+UqdOneTu7i5nZ2fVrVtXmzdvzrL9sWPH1KxZMxUuXFhlypTRlClTsp0xu9epSH9/f/Xu3duq7fr163rjjTfk7+8vJycnlSlTRj179tTly5cVHR2tevXqSZL69OljOc0ZEREhKftr7FJSUvTmm2/Kz89PTk5OqlKlimbMmCGz2ZylxsGDB2vjxo2qWbOmnJycVKNGDUVGRt7vLcyV7K6x8/f3V7t27RQdHa26deuqcOHCqlWrlqKjoyVJ69evV61ateTs7Kw6derou+++y7LfnHxet2/f1sSJE1WpUiU5OzvLw8NDzz33nHbt2pVnxwcgZ5ixA5Av7gaMEiVKWNqOHTumxo0bq3Tp0ho1apSKFi2qTz/9VB06dNC6dev097//XZKUkJCgpk2bKj093dLvww8/VOHChR+6nuTkZDVp0kTHjx9X37599Ze//EWXL1/W5s2b9dtvv6latWqaNGmSwsLC9Oqrr1qCaaNGjbLdn9ls1l//+ld9+eWX6tevnwIDA7Vjxw6NHDlS586d0+zZs636f/3111q/fr0GDRokFxcXzZ07Vy+99JLi4uLk4eHx0Mf1ICdPnlS3bt30z3/+U6+88opmzJih9u3ba/HixRozZowGDRokSQoPD9fLL7+sEydOyM7uzr/5c/p5TZgwQeHh4erfv7/q16+vpKQkHTp0SIcPH84y6wggn5kB4BGsWLHCLMn8+eefmy9dumQ+e/asee3atWYvLy+zk5OT+ezZs5a+zZs3N9eqVct88+ZNS1tmZqa5UaNG5kqVKlnahg8fbpZkPnDggKXt4sWLZjc3N7Mkc2xsrKVdknn8+PFZ6ipXrpy5V69eltdhYWFmSeb169dn6ZuZmWk2m83mb775xizJvGLFiix9evXqZS5Xrpzl9caNG82SzFOmTLHq16lTJ7PJZDKfPHnSqkZHR0ertiNHjpglmefNm5dlrHv57LPPzJLMX375ZZZ1dz+HP7435cqVM0sy79u3z9K2Y8cOsyRz4cKFzWfOnLG0f/DBB1n2ndPPKyAgwNy2bdscHweA/MOpWAB5IiQkRF5eXvLz81OnTp1UtGhRbd68WWXKlJEkXb16VV988YVefvll3bhxQ5cvX9bly5d15coVtWrVSr/88ovlLtpt27bp2WefVf369S379/LyUvfu3R+6vnXr1ikgIMAyy/RHJpMp1/vbtm2b7O3tNXToUKv2N998U2azWdu3b7dqDwkJUYUKFSyva9euLVdXV506dSrXY+dG9erV1bBhQ8vrBg0aSJKaNWumsmXLZmm/W09uPq/ixYvr2LFj+uWXX/L1WAA8GMEOQJ5YsGCBdu3apbVr1+rFF1/U5cuXre7QPHnypMxms9555x15eXlZLePHj5ckXbx4UZJ05swZVapUKcsYVapUeej6fv31V9WsWfOht/+zM2fOqFSpUnJxcbFqv3u36pkzZ6za/xii7ipRooSuXbuWZzVl58/jurm5SZL8/Pyybb9bT24+r0mTJun69euqXLmyatWqpZEjR+r777/P1+MCkD2usQOQJ+rXr2+5K7ZDhw567rnn1K1bN504cULFihWz3PgwYsQItWrVKtt9VKxYMc/qycjIyLN95YV73bFq/tONFgU17oPqyc3n9fzzz+vXX3/Vpk2btHPnTi1dulSzZ8/W4sWLrR7XAiD/EewA5Dl7e3uFh4eradOmmj9/vkaNGqVnnnlG0p3HhoSEhNx3+3LlymV7Wu/EiRNZ2kqUKKHr169btd26dUvx8fFWbRUqVNAPP/xw33Fzc0q2XLly+vzzz3Xjxg2rWbuffvrJsv5JlpvPS5Lc3d3Vp08f9enTR8nJyXr++ec1YcIEgh1QwDgVCyBfBAcHq379+pozZ45u3rwpb29vBQcH64MPPsgSuiTp0qVLlv9+8cUX9d///lcHDx60Wv/xxx9n2a5ChQras2ePVduHH36YZcbupZde0pEjR7Rhw4Ys+7g7S1W0aFFJyhIUs/Piiy8qIyND8+fPt2qfPXu2TCaT2rRp88B9PM5y83lduXLFal2xYsVUsWJFpaWl5XudAKwxYwcg34wcOVKdO3dWRESEBg4cqAULFui5555TrVq1NGDAAD3zzDO6cOGC9u/fr99++01HjhyRJL311lv6v//7P7Vu3VrDhg2zPO6kXLlyWa7d6t+/vwYOHKiXXnpJLVq00JEjR7Rjxw55enpmqWXt2rXq3Lmz+vbtqzp16ujq1avavHmzFi9erICAAFWoUEHFixfX4sWL5eLioqJFi6pBgwYqX758lmNr3769mjZtqrFjx+r06dMKCAjQzp07tWnTJg0fPtzqRoknVU4/r+rVqys4OFh16tSRu7u7Dh06pLVr12rw4ME2PgLg6UOwA5BvOnbsqAoVKmjGjBkaMGCAqlevrkOHDmnixImKiIjQlStX5O3traCgIIWFhVm28/X11ZdffqkhQ4Zo2rRp8vDw0MCBA1WqVCn169fPaowBAwYoNjZWy5YtU2RkpJo0aaJdu3apefPmVv2KFSumr776SuPHj9eGDRu0cuVKeXt7q3nz5pY7dwsVKqSVK1dq9OjRGjhwoNLT07VixYpsg52dnZ02b96ssLAwrVmzRitWrJC/v7/+9a9/6c0338yHd7Pg5fTzGjp0qDZv3qydO3cqLS1N5cqV05QpUzRy5EgbVg88nUzm/L5yFwAAAAWCa+wAAAAMgmAHAABgEAQ7AAAAgyDYAQAAGATBDgAAwCAIdgAAAAbx1D3HLjMzU+fPn5eLi0uufj4IAADAFsxms27cuKFSpUrJzu7+c3JPXbA7f/68/Pz8bF0GAABArpw9e9byQPV7eeqC3d0f6z579qxcXV1tXA0AAMD9JSUlyc/Pz5Jh7uepC3Z3T7+6uroS7AAAwBMjJ5eQcfMEAACAQRDsAAAADIJgBwAAYBBP3TV2AIAHy8jI0O3bt21dBvBUKFSokOzt7fNkXzYNdnv27NG//vUvffvtt4qPj9eGDRvUoUOH+26TlpamSZMmadWqVUpISJCvr6/CwsLUt2/fgikaAAzMbDYrISFB169ft3UpwFOlePHi8vHxeeRn7No02KWkpCggIEB9+/ZVx44dc7TNyy+/rAsXLmjZsmWqWLGi4uPjlZmZmc+VAsDT4W6o8/b2VpEiRXiQO5DPzGazUlNTdfHiRUmSr6/vI+3PpsGuTZs2atOmTY77R0ZGavfu3Tp16pTc3d0lSf7+/vlUHQA8XTIyMiyhzsPDw9blAE+NwoULS5IuXrwob2/vRzot+0TdPLF582bVrVtX06dPV+nSpVW5cmWNGDFCv//++z23SUtLU1JSktUCAMjq7jV1RYoUsXElwNPn7p+7R7229Ym6eeLUqVP6+uuv5ezsrA0bNujy5csaNGiQrly5ohUrVmS7TXh4uCZOnFjAlQLAk4vTr0DBy6s/d0/UjF1mZqZMJpM+/vhj1a9fXy+++KJmzZqllStX3nPWbvTo0UpMTLQsZ8+eLeCqAQAACsYTNWPn6+ur0qVLy83NzdJWrVo1mc1m/fbbb6pUqVKWbZycnOTk5FSQZQIAANjEExXsGjdurM8++0zJyckqVqyYJOnnn3+WnZ2dypQpY+PqAMC4/EdtLdDxTk9rm6v+vXv31sqVKxUeHq5Ro0ZZ2jdu3Ki///3vMpvNeV2ilT+eRnN1dVXNmjU1efJkNWvWLF/HBf7Mpqdik5OTFRMTo5iYGElSbGysYmJiFBcXJ+nOadSePXta+nfr1k0eHh7q06ePfvzxR+3Zs0cjR45U3759LXeUAACeTs7Oznrvvfd07do1m4y/YsUKxcfHa+/evfL09FS7du106tQpm9SCp5dNg92hQ4cUFBSkoKAgSVJoaKiCgoIUFhYmSYqPj7eEPEkqVqyYdu3apevXr6tu3brq3r272rdvr7lz59qkfgDA4yMkJEQ+Pj4KDw/Pdv2ECRMUGBho1TZnzhyrx2b17t1bHTp00NSpU1WyZEkVL15ckyZNUnp6ukaOHCl3d3eVKVMm2xv27j5gtmbNmlq0aJF+//137dq1Sx999JE8PDyUlpZm1b9Dhw7q0aPHIx838Ec2PRUbHBx83+nxiIiILG1Vq1bVrl278rEqAMCTyN7eXlOnTlW3bt00dOjQh75E54svvlCZMmW0Z88e7d27V/369dO+ffv0/PPP68CBA1qzZo3++c9/qkWLFvcc4+5ZpFu3bqlnz54aOnSoNm/erM6dO0u687yyrVu3aufOnQ93sMA9PFF3xQIAcD9///vfFRgYqPHjxz/0Ptzd3TV37lxVqVJFffv2VZUqVZSamqoxY8aoUqVKGj16tBwdHfX1119nu31qaqrGjRsne3t7vfDCCypcuLC6detmNcu3atUqlS1bVsHBwQ9dJ5CdJ+rmCdzHBLcH98mTcRILZhwAeEjvvfeemjVrphEjRjzU9jVq1JCd3f/mPUqWLKmaNWtaXtvb28vDw8PyE1B3de3aVfb29vr999/l5eWlZcuWqXbt2pKkAQMGqF69ejp37pxKly6tiIgI9e7dm2cGIs8xYwcAMJTnn39erVq10ujRo63a7ezsslz+k91T/gsVKmT12mQyZdv2598pnz17tmJiYpSQkKCEhAT16tXLsi4oKEgBAQH66KOP9O233+rYsWPq3bv3wxwecF/M2AEADGfatGkKDAxUlSpVLG1eXl5KSEiQ2Wy2zJTdfSpDXvDx8VHFihXvub5///6aM2eOzp07p5CQEPn5+eXZ2MBdzNgBAAynVq1a6t69u9VTE4KDg3Xp0iVNnz5dv/76qxYsWKDt27cXWE3dunXTb7/9piVLlqhv374FNi6eLgQ7AIAhTZo0yep0abVq1bRw4UItWLBAAQEBOnjw4ENfh/cw3Nzc9NJLL6lYsWLq0KFDgY2Lp4vJnN+P437MJCUlyc3NTYmJiXJ1dbV1OXmHmycAPKKbN28qNjZW5cuXl7Ozs63LMaTmzZurRo0aPH8VWdzvz19usgvX2AEAkM+uXbum6OhoRUdHa+HChbYuBwZGsAMAIJ8FBQXp2rVreu+996xu6ADyGsEOAIB8dvr0aVuXgKcEN08AAAAYBMEOAADAIAh2AAAABkGwAwAAMAiCHQAAgEEQ7AAAAAyCYAcAeCqcPn1aJpNJMTExti4Fjwkjfid4jh0A4MEK6mcLLePl7ucLe/furZUrV1peu7u7q169epo+fbpq166d19U90NWrVzV+/Hjt3LlTcXFx8vLyUocOHTR58mS5uRXwe4l78vPzU3x8vDw9PW1dSp5hxg4AYAitW7dWfHy84uPjFRUVJQcHB7Vr184mtZw/f17nz5/XjBkz9MMPPygiIkKRkZHq16+fTep5UmVkZCgzMzPf9m9vby8fHx85OBhnnotgBwAwBCcnJ/n4+MjHx0eBgYEaNWqUzp49q0uXLt1zm927d6t+/fpycnKSr6+vRo0apfT0dMv6tWvXqlatWipcuLA8PDwUEhKilJQUy/rly5erRo0alu0HDx4sSapZs6bWrVun9u3bq0KFCmrWrJneffdd/ec//7Ha/4NMmDBBgYGB+r//+z/5+/vLzc1N//jHP3Tjxg1Ln7S0NA0dOlTe3t5ydnbWc889p2+++ea++01LS9Pbb78tPz8/OTk5qWLFilq2bFmO35fg4GANGTJEw4cPV4kSJVSyZEktWbJEKSkp6tOnj1xcXFSxYkVt377dsk10dLRMJpO2bt2q2rVry9nZWc8++6x++OEHS5+IiAgVL15cmzdvVvXq1eXk5KS4uDilpaVpxIgRKl26tIoWLaoGDRooOjrast2ZM2fUvn17lShRQkWLFlWNGjW0bds2SXd+p7d79+7y8vJS4cKFValSJa1YsUJS9qdic3LsQ4cO1VtvvSV3d3f5+PhowoQJOftACwDBDgBgOMnJyVq1apUqVqwoDw+PbPucO3dOL774ourVq6cjR45o0aJFWrZsmaZMmSJJio+PV9euXdW3b18dP35c0dHR6tixo8xmsyRp0aJFev311/Xqq6/q6NGj2rx5sypWrHjPmhITE+Xq6prr2aFff/1VGzdu1JYtW7Rlyxbt3r1b06ZNs6x/6623tG7dOq1cuVKHDx9WxYoV1apVK129evWe++zZs6f+/e9/a+7cuTp+/Lg++OADFStWLEfvy10rV66Up6enDh48qCFDhui1115T586d1ahRIx0+fFgtW7ZUjx49lJqaarXdyJEjNXPmTH3zzTfy8vJS+/btdfv2bcv61NRUvffee1q6dKmOHTsmb29vDR48WPv379fq1av1/fffq3PnzmrdurV++eUXSdLrr7+utLQ07dmzR0ePHtV7771nOZ533nlHP/74o7Zv367jx49r0aJF9zz1mptjL1q0qA4cOKDp06dr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", "text/plain": [ "
" - ] + ], + "image/png": "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lClT9NxzzxXV4VrJycnRk08+KQcHB3344YdWp02zsrLUu3dv/ec//1H16tX1xx9/FEsN1+vVq5c2bdqkBx98UD4+PrrvvvvUvn17PfPMM3J1dbVat1q1anm2z8zMvO2+Fy5cqCVLlljeP//883r77bcLvPxWevfuLXt7e6u2X375RdWrV7/tmosSwQ4AYAht27ZVRESEJOn8+fNauHChwsLCtHv3bkswu97BgwfVsmVLqxDUqlUrpaen68SJEwoKClL79u0VGBiojh07qkOHDurZs6cqVqyoU6dOKSkpSe3bt79lXWlpaercubMaNGigiRMnFtnxXm/cuHHatWuXdu/eLRcXF6tlY8eOVf369fXUU08Vap8NGzbUsWPHJMkySpkbnCWpTZs22rhxY77b2tvbKzIyUlOnTtVXX32luLg4vfXWW5oxY4Z2794tX19fy7pff/11nppDQkIKVev1+vTpo9dee83y/u8TM261/FZmz56t0NBQq7YqVaoUus7iQrADABhC+fLlrU6FLlmyRG5ublq8eLHl9Gph2Nvba8uWLfr222+1efNmzZs3T6+99pri4uJUqVKlAu3j4sWL6tSpk1xcXLRmzRqVKVOm0HXcyooVKzRr1ix98cUXql27dp7lX331lfbv36+VK1dK+r+QVqlSJb322muaNGlSvvvdsGGDrly5IunaaeuQkBCrW8UU5Fq5qlWr6umnn9bTTz+tKVOmqE6dOlq0aJFVnzVq1MgTrv5+utrFxUWpqal59n/hwoU8s4zd3Nxuekr8VstvxcfH5462L25cYwcAMCSTySQ7Ozv99ddf+S6vX7++du3aZQk6krRz5065uLhYTg+aTCa1atVKkyZN0k8//SRHR0etWbNGLi4uCggI0NatW2/Yf1pamjp06CBHR0dFR0cXywX28fHx6t+/v6ZPn66OHTvmu86qVau0d+9excfHKz4+3nIa8uuvv9bQoUNvuG9/f3/VqlVLtWrVsox45r6vVauWqlatWqhaK1asKF9fX6vJJwVVt25d/fjjj1ZtV69e1d69e1WnTp1C78/IGLEDABhCVlaWUlJSJF07FTt//nylp6era9eu+a4/ZMgQzZkzR8OHD9ewYcN06NAhTZgwQSNHjpSdnZ3i4uK0detWdejQQd7e3oqLi9Pp06dVv359SdLEiRM1aNAgeXt7KywsTBcv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dWQ2m/X5559rw4YNltu/FPYzvP52J9OmTVOXLl30zDPPFGpfhRESEqLevXurWbNm8vT01C+//KJx48apbdu2VrcaKYiOHTuqbt266t27t6ZOnSofHx/t2bNHr7/+ul588cUCffaFsX//frm4uFjem0wmy+ny7Oxsy2/y+uVFde1jfkrV5IncoVMPDw+r9g8//FAffPCBfHx81LVrV73xxhsqV65cvvvIyspSVlaW5X3uHyQAgLHFxMTI19dX0rURpHr16umzzz5TSEhIvutXrVpVGzZs0OjRoxUUFCQPDw/179/fcgNaV1dX7dixQ3PmzFFaWpr8/f319ttvKywsTJLUt29fXbp0SbNnz9aoUaNUqVIl9ezZU9K10aG4uDhJyjNTNiEhQQEBAZKu3dYjPDw832vvEhMTtX79eklSnTp18j2GhIQENWjQQOXKldPLL7+s48ePy8nJSbVr19aSJUv09NNPF/wD1P99hg4ODqpYsaKCgoI0d+5c9e3bt1CnIAurY8eOWrZsmcaNG6fMzExVqVJFXbp00fjx4wu9LwcHB23evFnjxo1T7969dfr0adWoUUMvvviiRo4cWeS1Xz8QJV07hZ+dnS1JOnDggOU3mcvJyanQo5CFYTIXx9zo25CTk6NHHnlEFy5c0DfffGNpf++99+Tv768qVapo3759evXVV9WiRYsbTrueOHGiJk2alKc9d5q5IUx0u/U6RdZX4e6SDuCf69KlS0pISFCNGjXuaJYhCiYzM1Oenp7auHHjDcMn7h43+/OXlpYmNze3AmWZUjNiN3ToUP38889WoU6S1dTwwMBA+fr6qn379jpy5Ihq1qyZZz9jx461SuRpaWny8/MrvsIBALgN27ZtU7t27Qh1KFKlItgNGzZM69ev144dO/LcL+bv7r33XknS4cOH8w12Tk5OcnJyKpY6AQAoKp07d1bnzp1tXQYMxqbBzmw2a/jw4VqzZo1iY2NvOpU6V+7De/9+zhoAAOBuZ9NgN3ToUH300Udat26dXFxcLDNH3NzcVLZsWR05ckQfffSRHn74YXl6emrfvn166aWX9MADD6hx48a2LB0AAKDUsWmwi4iIkKQ81xdERkYqPDxcjo6O+vLLLzVnzhxlZGTIz89PPXr0sMxYAgAUvVIypw64qxTVnzubn4q9GT8/P23fvr2EqgGAu1vuUxEyMzML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5s4CAACg1CvVNygGAABAwRHsAAAADIJgBwAASsTRo0dlMpkUHx8vSYqNjZXJZNKFCxdsWpeREOxg5erVq7r//vvVvXt3q/bU1FT5+fnptddes1FlsDWz2azQ0FB17Ngxz7KFCxfK3d1dJ06csEFlsLXcv5xv9Grbtq2tSwTuGgQ7WLG3t1dUVJRiYmL04YcfWtqHDx8uDw8PTZgwwYbVwZZMJpMiIyMVFxend99919KekJCgV155RfPmzVO1atVsWCFs5f7771dycnKe17vvviuTyaQhQ4bYukTgrkGwQx516tTR9OnTNXz4cCUnJ2vdunVasWKFli9fLkdHR1uXBxvy8/PTf//7X40aNUoJCQkym83q37+/OnTooKefftrW5cFGHB0d5ePjY/U6f/68Ro0apXHjxqlXr162LhElKCYmRq1bt5a7u7s8PT3VpUsXHTlyxNZl3TW43QnyZTab1a5dO9nb22v//v0aPny4Xn/9dVuXhVKiW7duSk1NVffu3TVlyhQdOHBAXl5eti4LpcSFCxfUokUL1atXT+vWreM53XeZVatWyWQyqXHjxkpPT9f48eN19OhRxcfHKzExUTVq1NBPP/2k4OBgxcbGqm3btjp//jyP/ywiBDvc0K+//qr69esrMDBQe/bskYPDP+J+1igBp06dUsOGDXXu3DmtWrXK8ixnICcnR126dNHRo0cVFxcnFxcXW5cEGztz5oy8vLy0f/9+VahQgWBXzDgVixt6//33Va5cOSUkJHBRPKx4e3vr+eefV/369Ql1sDJu3Djt2rVL69atI9TdpX7//Xf17t1b99xzj1xdXRUQECBJSkxMtG1hdwmCHfL17bffavbs2Vq/fr1atGih/v37i8FdXM/BwYFRXFhZsWKFZs2apRUrVqh27dq2Lgc20rVrV507d06LFy9WXFyc4uLiJEmXL1+2cWV3B4Id8sjMzFR4eLgGDx6stm3baunSpdq9e7cWLVpk69IAlFLx8fHq37+/pk+fnu8tcXB3OHv2rA4dOqTXX39d7du3V/369XX+/Hlbl3VX4Z/byGPs2LEym82aPn26JCkgIECzZs3SqFGjFBYWZhlWBwDp2jVU3bp1U0hIiJ566imlpKRYLbe3t2dyzV2iYsWK8vT01HvvvSdfX18lJiZqzJgxti7rrkKwg5Xt27drwYIFio2NVbly5Sztzz//vFavXq3+/fvryy+/ZJYbAIsvvvhCx44d07Fjx+Tr65tnub+/v44ePVryhaHE2dnZacWKFXrhhRfUqFEj1a1bV3PnzlVISIitS7trMCsWAADAILjGDgAAwCAIdgAAAAZBsAMAADAIgh0AAIBBEOwAAAAMgmAHAABgEAQ7AAAAgyDYAQAAGATBDgCKmMlk0tq1a21dBoC7EMEOAPKxa9cu2dvbq3PnzoXeNjk5WWFhYcVQFQDcHI8UA4B8DBgwQBUqVNDSpUt16NAhValSxdYlAcAtMWIHAH+Tnp6uTz75RIMHD1bnzp0VFRVlWTZ58mRVqVJFZ8+etbR17txZbdu2VU5OjiTrU7GXL1/WsGHD5OvrK2dnZ/n7+2vatGkleTgA7iIEOwD4m08//VT16tVT3bp19dRTT+n9999X7smN1157TQEBARowYIAkacGCBfr222+1bNky2dnl/V/q3LlzFR0drU8//VSHDh3Shx9+qICAgJI8HAB3EQdbFwAApc3SpUv11FNPSZI6deqk1NRUbd++XSEhIbK3t9cHH3yg4OBgjRkzRnPnztWSJUtUvXr1fPeVmJio2rVrq3Xr1jKZTPL39y/JQwFwl2HEDgCuc+jQIe3evVu9e/eWJDk4OOjxxx/X0qVLLevcc889mjVrlmbMmKFHHnlETz755A33Fx4ervj4eNWtW1cvvPCCNm/eXOzHAODuxYgdAFxn6dKlys7OtposYTab5eTkpPnz58vNzU2StGPHDtnb2+vo0aPKzs6Wg0P+/zv917/+pYSEBG3cuFFffvmlHnvsMYWGhmrlypUlcjwA7i6M2AHA/5edna3ly5fr7bffVnx8vOW1d+9eValSRR9//LEk6ZNPPtHq1asVGxurxMRETZky5ab7dXV11eOPP67Fixfrk08+0apVq3Tu3LmSOCQAdxlG7ADg/1u/fr3Onz+v/v37W0bmcvXo0UNLly5Vly5dNHjwYM2YMUOtW7dWZGSkunTporCwMN1333159vnOO+/I19dXTZo0kZ2dnT777DP5+PjI3d29hI4KwN2EETsA+P+WLl2q0NDQPKFOuhbsfvjhBz3zzDNq0aKFhg0bJknq2LGjBg8erKeeekrp6el5tnNxcdHMmTPVrFkzNW/eXEePHtWGDRvynUELAHeKGxQDAAAYBP9kBAAAMAiCHQAAgEEQ7AAAAAyCYAcAAGAQBDsAAACDINgBAAAYBMEOAADAIAh2AAAABkGwAwAAMAiCHQAAgEEQ7AAAAAyCYAcAAGAQ/w8pkq97m6XDeQAAAABJRU5ErkJggg==" }, "metadata": {}, "output_type": "display_data" } ], - "source": [ - "# Automatic chunking: (1, 1000, 1000) for Intel 13900K\n", - "chunks = None\n", - "meas = measure_blosc2(chunks)\n", - "plot_meas(meas_np, meas, chunks)" - ] + "execution_count": 12 }, { "cell_type": "markdown", @@ -279,40 +279,40 @@ }, { "cell_type": "code", - "execution_count": 8, "id": "e0070348-b3e5-4936-93ab-11dbe70db445", "metadata": { "ExecuteTime": { - "end_time": "2024-08-23T08:35:48.018075Z", - "start_time": "2024-08-23T08:35:42.861338Z" + "end_time": "2024-10-08T08:20:35.190410Z", + "start_time": "2024-10-08T08:14:56.333112Z" } }, + "source": [ + "# Manual chunking\n", + "chunks = (100, 100, 100)\n", + "meas = measure_blosc2(chunks)\n", + "plot_meas(meas_np, meas, chunks)" + ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "cratio for LZ4 + SHUFFLE: 9.8x\n", - "cratio for ZSTD + SHUFFLE: 33.8x\n" + "cratio for LZ4 + SHUFFLE: 6.2x\n", + "cratio for ZSTD + SHUFFLE: 13.5x\n" ] }, { "data": { - "image/png": "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ceKEOnfurHLlyqlUqVKqX7++tm3bJun2c3p79+4td3d3lShRQjVr1lRkZKSk7E/F5uTYhw8frjfffFPly5eXh4eHJk6cmLMvtAAUimC3YMECeXt7y8nJSU2bNtWBAwfuue6KFStkMpmsXk5OTgVYLQCgsLt+/bpWrVolHx8fubq6ZrvO6dOn9cwzz6hJkyY6dOiQFi1apGXLlmnq1KmSpDNnzqhXr156+eWXdfToUcXExKhr164ym82SpEWLFun111/XK6+8osOHD2vz5s3y8fG5Z01Xr15VmTJlcj069Ntvv2njxo3asmWLtmzZoj179mjatGmW5W+++abWrVunlStX6uDBg/Lx8VG7du106dKle+6zb9+++vjjjzV37lwdPXpU77//vkqXLp2jz+WOlStXys3NTQcOHNCwYcP02muvqUePHmrevLkOHjyotm3bqk+fPkpNTbXabvTo0Zo1a5a+/vprubu7q3Pnzrp165ZleWpqqqZPn66lS5fqyJEjqlChgkJCQrR//36tXr1a33//vXr06KH27dvrl19+kSS9/vrrSktL0969e3X48GFNnz7dcjz//Oc/9eOPP2r79u06evSoFi1adM9Tr7k59lKlSik2NlYzZszQ5MmTtWvXrgd9lQXC5mOPa9asUWhoqBYvXqymTZsqIiJC7dq107Fjx1ShQoVstylTpoyOHTtmeW8yPeId0gEAf3lbtmyx/GWekpKiSpUqacuWLbKzy34MY+HChfLy8tL8+fNlMplUp04dJSYm6q233tKECRN05swZpaenq2vXrqpWrZokydfX17L91KlT9cYbb2jEiBGWtiZNmmTb14ULFzRlyhS98soruT6uzMxMrVixQs7OzpKkPn36KDo6Wu+8845SUlK0aNEirVixQh06dJAkLVmyRLt27dKyZcs0evToLPv7+eef9cknn2jXrl0KDg6WJD322GM5/lzufJ5+fn56++23JUljx47VtGnT5ObmpsGDB0uSJkyYoEWLFun777/X448/btl/WFiYnn76aUm3A1KVKlW0YcMGPf/885KkW7duaeHChfLz85MkJSQkKDIyUgkJCapcubIkadSoUYqKilJkZKTeffddJSQkqFu3bpbv58/Hk5CQoEaNGikgIECS5O3tfc/POqfH3rBhQ4WFhUmSatasqfnz5ys6OtpyXLZk8xG72bNn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", "text/plain": [ "
" - ] + ], + "image/png": "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Mn377bc6dOiQIiIibufwgJtixA4AYDhTp05VaGioateubW3z8fFRSkqKLBaLdaQsISGh0Pr08/NTjRo1brh8wIABmj17tk6dOqXw8HAFBAQUWt9ADkbsAACGExwcrF69emnOnDnWtrCwMJ05c0bTp0/Xr7/+qvnz52vjxo3FVlPPnj118uRJLVq0iEkTKDIEOwCAIU2aNMnmdGndunX17rvvav78+QoJCdGePXtu+zq82+Hp6amnnnpKZcuWVZcuXYqtX9xbTJaivh23nZnNZnl6eiotLU0eHh72LqdwMHkCQBG4fPmyEhMTVa1aNbm6utq7HENq06aN6tevbzOSCEg3//srSJbhGjsAAIrYhQsXFBcXp7i4OL377rv2LgcGRrADAKCINWrUSBcuXNC0adNsJnQAhY1gBwBAETt27Ji9S8A9gskTAAAABmHXYLdz50517txZlSpVkslk0tq1a2+47sCBA2UymTR79uxiqw8AAOBuYtdgl5GRoZCQEM2fP/+m661Zs0bffPONKlWqVEyVAQAA3H3seo1dhw4d1KFDh5uuc+rUKQ0dOlSbN29Wx44di6kyAACAu49DT564du2annvuOY0aNUr169fP1zZZWVnKysqyvjebzUVVHgAAgENx6MkT06ZNU8mSJTVs2LB8bxMVFSVPT0/ri2fxAQCAe4XDBrtvv/1W//73vxUTE2N9WHN+jBkzRmlpadbXiRMnirBKAMDd4tixYzKZTEpISLB3KXAQRvxNOOyp2C+//FKpqamqWrWqtS07O1uvvvqqZs+efcN7Arm4uMjFxaWYqgSAe0RxPspQKvDjDCMiIrR06VLrey8vLzVt2lTTp09Xw4YNC7u6Wzp//rwmTJigLVu2KCkpST4+PurSpYsmT54sT89i/ixxQwEBATp9+rQqVKhg71IKjcOO2D333HP6/vvvlZCQYH1VqlRJo0aN0ubNm+1dHgDAwbRv316nT5/W6dOntW3bNpUsWVKdOnWySy3JyclKTk7WjBkz9MMPPygmJkabNm1S//797VLP3So7O1vXrl0rsv07OTnJz89PJUs67DhXgdk12KWnp1tDmyQlJiYqISFBSUlJ8vb2VoMGDWxepUqVkp+fH49jAQDk4uLiIj8/P/n5+Sk0NFSjR4/WiRMndObMmRtus2PHDjVr1kwuLi7y9/fX6NGjdfXqVevylStXKjg4WG5ubvL29lZ4eLgyMjKsyz/44APVr1/fuv2QIUMkSQ0aNNCqVavUuXNnVa9eXa1bt9Zbb72l//3vfzb7v5XIyEiFhobqP//5j4KCguTp6alnn31Wly5dsq6TlZWlYcOGydfXV66urmrRooX27t170/1mZWXp9ddfV0BAgFxcXFSjRg0tWbIk359LWFiYhg4dquHDh6t8+fKqWLGiFi1apIyMDPXt21fu7u6qUaOGNm7caN0mLi5OJpNJn332mRo2bChXV1c9+OCD+uGHH6zrxMTEqFy5coqNjVW9evXk4uKipKQkZWVlaeTIkapcubLKlCmjBx54QHFxcdbtjh8/rs6dO6t8+fIqU6aM6tevrw0bNki6/pzeXr16ycfHR25ubqpZs6aio6Ml5X0qNj/HPmzYML322mvy8vKSn5+fIiMj8/eFFgO7Brt9+/apUaNGatSokSRpxIgRatSokcaPH2/PsgAAd7n09HQtX75cNWrUkLe3d57rnDp1So8//riaNm2qAwcOaMGCBVqyZImmTJkiSTp9+rR69Oihfv366fDhw4qLi1PXrl1lsVgkSQsWLNDgwYP14osv6uDBg4qNjVWNGjVuWFNaWpo8PDwKPDr066+/au3atVq/fr3Wr1+vHTt2aOrUqdblr732mlatWqWlS5dq//79qlGjhtq1a6fz58/fcJ/PP/+8PvroI82ZM0eHDx/We++9p7Jly+brc8mxdOlSVahQQXv27NHQoUP18ssvq3v37nr44Ye1f/9+tW3bVs8995wyMzNtths1apRmzpypvXv3ysfHR507d9aVK1esyzMzMzVt2jQtXrxYhw4dkq+vr4YMGaLdu3drxYoV+v7779W9e3e1b99eR48elSQNHjxYWVlZ2rlzpw4ePKhp06ZZj+fNN9/Ujz/+qI0bN+rw4cNasGDBDU+9FuTYy5Qpo/j4eE2fPl2TJk3S1q1bb/VVFguTJecXalBms1menp7WPyhDKM5rXQp4nQuAu9fly5eVmJioatWqydXV1XbhXXCN3fLly611Z2RkyN/fX+vXr9f9998v6froTLVq1fTdd98pNDRU48aN06pVq3T48GHrJL13331Xr7/+utLS0pSQkKDGjRvr2LFjCgwMzNVn5cqV1bdv31z/6Ofl7Nmzaty4sXr37q233nor38cVGRmpf/3rX0pJSZG7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pCtXruiNN97Qhg0b9Ntvv8nT01Ph4eGaOnWqKlWqZM+yAQAOyMXFRX5+fpIkPz8/jR49Wi1bttSZM2fk4+OT5zY7duzQqFGjdODAAXl5ealPnz6aMmWK9R/flStXauLEifrll19UunRpNWrUSOvWrVOZMmUkSR988IFmzpypX375RV5eXnrqqac0b948NWjQQKtWrbL2U716db311lvq3bu3rl69mu9/3HOOJ0dmZqYGDhyoJk2aaPbs2ZKkXbt2KS0tTYsXL7but1q1amrVqpV1u7+GEScnJ7m7u+fa998/w8qVK+v+++/Xgw8+qDZt2igmJkYDBgzIV90FFRsbq3//+996/PHHJUlBQUFq3LhxkfT1d76+vjYjfgVdfjMlS5bM83MuSnY9FZuRkaGQkBDNnz8/17LMzEzt379fb775pvbv36/Vq1fryJEjeuKJJ+xQKQDgbpKenq7ly5erRo0a8vb2znOdU6dO6fHHH1fTpk114MABLViwQEuWLNGUKVMkXR8t69Gjh/r166fDhw8rLi5OXbt2lcVikSQtWLBAgwcP1osvvqiDBw8qNjZWNWrUuGFNaWlp8vDwuKMRm759+yotLU2ffvqpdT9+fn66evWq1qxZY62tMLVu3VohISFavXp1oe87h5+fnzZs2KBLly4VWR/3CruO2HXo0EEdOnTIc5mnp6e2bt1q0zZv3jw1a9ZMSUlJqlq1anGUCAC4S6xfv946MpWRkSF/f3+tX79eJUrkPYbx7rvvKiAgQPPmzbNe+5ScnKzXX39d48eP1+nTp3X16lV17dpVgYGBkqTg4GDr9lOmTNGrr76qV155xdrWtGnTPPs6e/asJk+erBdffPG2jy8qKkqfffaZdu3apQoVKljbH3zwQY0dO1Y9e/bUwIED1axZM7Vu3VrPP/+8KlaseNv9/VWdOnWK9HrF999/X7169ZK3t7dCQkLUokULdevWTc2bN7dZ791339XixYtt2q5evSpXV9fb7rtKlSo2748fP27zHwO3Wn4zBw8ezHXqtnfv3lq4cOFtVntrd9XkibS0NJlMptseEgUAGFerVq2UkJCghIQE7dmzR+3atVOHDh10/PjxPNc/fPiwHnroIZtJCM2bN1d6erpOnjypkJAQtWnTRsHBwerevbsWLVqkCxcuSJJSU1OVnJysNm3a3LIus9msjh07ql69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" }, "metadata": {}, "output_type": "display_data" } ], - "source": [ - "# Manual chunking\n", - "chunks = (100, 100, 100)\n", - "meas = measure_blosc2(chunks)\n", - "plot_meas(meas_np, meas, chunks)" - ] + "execution_count": 13 }, { "cell_type": "markdown", @@ -394,16 +394,16 @@ }, { "cell_type": "code", - "execution_count": null, "id": "4995f5eaeff0a11a", "metadata": { "ExecuteTime": { - "end_time": "2024-08-23T08:35:54.614095Z", - "start_time": "2024-08-23T08:35:54.612202Z" + "end_time": "2024-10-08T08:20:35.205614Z", + "start_time": "2024-10-08T08:20:35.197712Z" } }, + "source": [], "outputs": [], - "source": [] + "execution_count": 13 } ], "metadata": { diff --git a/doc/getting_started/tutorials/10.ucodecs-ufilters.ipynb b/doc/getting_started/tutorials/10.ucodecs-ufilters.ipynb index 07173afe..f886f6af 100644 --- a/doc/getting_started/tutorials/10.ucodecs-ufilters.ipynb +++ b/doc/getting_started/tutorials/10.ucodecs-ufilters.ipynb @@ -31,8 +31,8 @@ "execution_count": 1, "metadata": { "ExecuteTime": { - "end_time": "2023-06-21T08:11:27.952152Z", - "start_time": "2023-06-21T08:11:26.405204Z" + "end_time": "2024-10-08T08:11:35.927616Z", + "start_time": "2024-10-08T08:11:33.929462Z" }, "pycharm": { "name": "#%%\n" @@ -47,11 +47,8 @@ "import blosc2\n", "\n", "dtype = np.dtype(np.int32)\n", - "cparams = {\n", - " \"nthreads\": 1,\n", - " \"typesize\": dtype.itemsize,\n", - "}\n", - "dparams = {\"nthreads\": 1}\n", + "cparams = blosc2.CParams(nthreads=1, typesize=dtype.itemsize)\n", + "dparams = blosc2.DParams(nthreads=1)\n", "\n", "chunk_len = 10_000\n", "schunk = blosc2.SChunk(chunksize=chunk_len * dtype.itemsize, cparams=cparams)" @@ -75,8 +72,8 @@ "execution_count": 2, "metadata": { "ExecuteTime": { - "end_time": "2023-06-21T08:11:27.962250Z", - "start_time": "2023-06-21T08:11:27.956854Z" + "end_time": "2024-10-08T08:11:41.200886Z", + "start_time": "2024-10-08T08:11:41.188272Z" }, "pycharm": { "name": "#%%\n" @@ -117,8 +114,8 @@ "execution_count": 3, "metadata": { "ExecuteTime": { - "end_time": "2023-06-21T08:11:27.970548Z", - "start_time": "2023-06-21T08:11:27.966942Z" + "end_time": "2024-10-08T08:11:43.417236Z", + "start_time": "2024-10-08T08:11:43.412230Z" }, "pycharm": { "name": "#%%\n" @@ -166,8 +163,8 @@ "execution_count": 4, "metadata": { "ExecuteTime": { - "end_time": "2023-06-21T08:11:28.003212Z", - "start_time": "2023-06-21T08:11:27.972522Z" + "end_time": "2024-10-08T08:11:51.481622Z", + "start_time": "2024-10-08T08:11:51.474227Z" }, "pycharm": { "name": "#%%\n" @@ -195,11 +192,11 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 8, "metadata": { "ExecuteTime": { - "end_time": "2023-06-21T08:11:28.004154Z", - "start_time": "2023-06-21T08:11:27.988511Z" + "end_time": "2024-10-08T08:16:59.500145Z", + "start_time": "2024-10-08T08:16:59.382269Z" }, "pycharm": { "name": "#%%\n" @@ -208,9 +205,25 @@ "outputs": [ { "data": { - "text/plain": "{'codec': 160,\n 'codec_meta': 0,\n 'clevel': 1,\n 'use_dict': 0,\n 'typesize': 4,\n 'nthreads': 1,\n 'blocksize': 0,\n 'splitmode': ,\n 'filters': [,\n ,\n ,\n ,\n ,\n ],\n 'filters_meta': [0, 0, 0, 0, 0, 0]}" + "text/plain": [ + "{'codec': 160,\n", + " 'codec_meta': 0,\n", + " 'clevel': 1,\n", + " 'use_dict': 0,\n", + " 'typesize': 4,\n", + " 'nthreads': 1,\n", + " 'blocksize': 0,\n", + " 'splitmode': ,\n", + " 'filters': [,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ],\n", + " 'filters_meta': [0, 0, 0, 0, 0, 0]}" + ] }, - "execution_count": 5, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -233,9 +246,7 @@ "name": "#%% md\n" } }, - "source": [ - "Now we can check that our codec works well by appending and recovering some data:" - ] + "source": "\"Now we can check that our codec works well by appending and recovering some data:" }, { "cell_type": "code", diff --git a/examples/ndarray/bytedelta_filter.py b/examples/ndarray/bytedelta_filter.py index 34fcb601..17fa2848 100644 --- a/examples/ndarray/bytedelta_filter.py +++ b/examples/ndarray/bytedelta_filter.py @@ -21,14 +21,14 @@ nparray = np.linspace(0, 1000, math.prod(shape)).reshape(shape) # Compress with and without bytedelta -cparams = {"filters": [blosc2.Filter.SHUFFLE]} +cparams = blosc2.CParams(filters=[blosc2.Filter.SHUFFLE], filters_meta=[0]) a = blosc2.asarray(nparray, cparams=cparams) print( f"Compression ratio with shuffle: {a.schunk.cratio:.2f} x", ) # Now with bytedelta -cparams = {"filters": [blosc2.Filter.SHUFFLE, blosc2.Filter.BYTEDELTA]} +cparams = blosc2.CParams(filters=[blosc2.Filter.SHUFFLE, blosc2.Filter.BYTEDELTA], filters_meta=[0, 0]) a = blosc2.asarray(nparray, cparams=cparams) print( f"Compression ratio with shuffle + bytedelta: {a.schunk.cratio:.2f} x", diff --git a/examples/ndarray/empty_.py b/examples/ndarray/empty_.py index 52dbeb81..ecc79185 100644 --- a/examples/ndarray/empty_.py +++ b/examples/ndarray/empty_.py @@ -10,13 +10,13 @@ import blosc2 -cparams = { - "codec": blosc2.Codec.LZ4, - "clevel": 5, - "nthreads": 4, - "filters": [blosc2.Filter.DELTA, blosc2.Filter.TRUNC_PREC, blosc2.Filter.BITSHUFFLE], - "filters_meta": [0, 3, 0], # keep just 3 bits in mantissa -} +cparams = blosc2.CParams( + codec=blosc2.Codec.LZ4, + clevel=5, + nthreads=4, + filters=[blosc2.Filter.DELTA, blosc2.Filter.TRUNC_PREC, blosc2.Filter.BITSHUFFLE], + filters_meta=[0, 3, 0], # keep just 3 bits in mantissa +) a = blosc2.empty(shape=(40, 401), blocks=(6, 26), dtype="f8", cparams=cparams) a[...] = 222 diff --git a/examples/ndarray/ndmean.py b/examples/ndarray/ndmean.py index 55d8a1bb..0f486506 100644 --- a/examples/ndarray/ndmean.py +++ b/examples/ndarray/ndmean.py @@ -20,6 +20,6 @@ random = np.random.default_rng() array = random.normal(0, 1, np.prod(shape)).reshape(shape) # Use NDMEAN filter -cparams = {"filters": [blosc2.Filter.NDMEAN], "filters_meta": [4]} +cparams = blosc2.CParams(filters=[blosc2.Filter.NDMEAN], filters_meta=[4]) a = blosc2.asarray(array, chunks=chunks, cparams=cparams) print("compression ratio:", a.schunk.cratio) diff --git a/examples/ndarray/zfp_codec.py b/examples/ndarray/zfp_codec.py index a58780a3..2a7825eb 100644 --- a/examples/ndarray/zfp_codec.py +++ b/examples/ndarray/zfp_codec.py @@ -20,6 +20,6 @@ random = np.random.default_rng() array = random.normal(0, 1, np.prod(shape)).reshape(shape) # Use ZFP_RATE codec -cparams = {"codec": blosc2.Codec.ZFP_RATE, "codec_meta": 37} +cparams = blosc2.CParams(codec=blosc2.Codec.ZFP_RATE, codec_meta=37) a = blosc2.asarray(array, chunks=chunks, cparams=cparams) print("compression ratio:", a.schunk.cratio) diff --git a/examples/schunk_roundtrip.py b/examples/schunk_roundtrip.py index f2e3732e..e89d1d83 100644 --- a/examples/schunk_roundtrip.py +++ b/examples/schunk_roundtrip.py @@ -12,17 +12,19 @@ nchunks = 10 # Set the compression and decompression parameters -cparams = {"codec": blosc2.Codec.LZ4HC, "typesize": 4} -dparams = {} +cparams = blosc2.CParams(codec=blosc2.Codec.LZ4HC, typesize=4) +dparams = blosc2.DParams() contiguous = True urlpath = "filename" -storage = {"contiguous": contiguous, "urlpath": urlpath, "cparams": cparams, "dparams": dparams} +storage = blosc2.Storage(contiguous=contiguous, urlpath=urlpath) blosc2.remove_urlpath(urlpath) # Create the SChunk data = np.arange(200 * 1000 * nchunks) -schunk = blosc2.SChunk(chunksize=200 * 1000 * 4, data=data, **storage) +schunk = blosc2.SChunk( + chunksize=200 * 1000 * 4, data=data, cparams=cparams, dparams=dparams, storage=storage +) cframe = schunk.to_cframe() diff --git a/examples/ucodecs.py b/examples/ucodecs.py index 6cf5a2f6..663ee2ca 100644 --- a/examples/ucodecs.py +++ b/examples/ucodecs.py @@ -51,14 +51,10 @@ def decoder1(input, output, meta, schunk): blosc2.register_codec(codec_name, id, encoder1, decoder1) # Set the compression and decompression parameters -cparams = { - "typesize": dtype.itemsize, - "nthreads": 1, - "filters": [blosc2.Filter.NOFILTER], - "filters_meta": [0], -} -dparams = {"nthreads": 1} -cparams["codec"] = id +cparams = blosc2.CParams( + typesize=dtype.itemsize, codec=id, nthreads=1, filters=[blosc2.Filter.NOFILTER], filters_meta=[0] +) +dparams = blosc2.DParams(nthreads=1) # Create SChunk and fill it with data data = np.arange(0, chunk_len * nchunks, 1, dtype=dtype) diff --git a/examples/ufilters.py b/examples/ufilters.py index 2b42fb0e..9285bcb4 100644 --- a/examples/ufilters.py +++ b/examples/ufilters.py @@ -37,13 +37,10 @@ def backward(input, output, meta, schunk): blosc2.register_filter(id, forward, backward) # Set the compression and decompression parameters -cparams = { - "typesize": dtype.itemsize, - "nthreads": 1, - "filters": [blosc2.Filter.NOFILTER, id], - "filters_meta": [0, 0], -} -dparams = {"nthreads": 1} +cparams = blosc2.CParams( + typesize=dtype.itemsize, nthreads=1, filters=[blosc2.Filter.NOFILTER, id], filters_meta=[0, 0] +) +dparams = blosc2.DParams(nthreads=1) # Create SChunk and fill it with data data = np.arange(0, chunk_len * nchunks, 1, dtype=dtype) From 7621087bed7d6485337a0bfe616e6b11c02db539 Mon Sep 17 00:00:00 2001 From: oumaima-ech-chdig Date: Tue, 8 Oct 2024 14:01:34 +0200 Subject: [PATCH 3/4] More updated examples of CParams, DParams and Storage --- src/blosc2/core.py | 3 +- src/blosc2/schunk.py | 92 ++++++++++++++++++++++++++++---------------- 2 files changed, 61 insertions(+), 34 deletions(-) diff --git a/src/blosc2/core.py b/src/blosc2/core.py index 1a4c4df3..e521f221 100644 --- a/src/blosc2/core.py +++ b/src/blosc2/core.py @@ -1557,7 +1557,8 @@ def schunk_from_cframe(cframe: bytes | str, copy: bool = False) -> blosc2.SChunk >>> nchunks = 4 >>> chunk_size = 200 * 1000 * 4 >>> data = np.arange(nchunks * chunk_size // 4, dtype=np.int32) - >>> schunk = blosc2.SChunk(data=data, cparams={"typesize": 4}) + >>> cparams = blosc2.CParams(typesize=4) + >>> schunk = blosc2.SChunk(data=data, cparams=cparams) >>> serialized_schunk = schunk.to_cframe() >>> print(f"Serialized SChunk length: {len(serialized_schunk)} bytes") Serialized SChunk length: 14129 bytes diff --git a/src/blosc2/schunk.py b/src/blosc2/schunk.py index b77d68df..3d44c876 100644 --- a/src/blosc2/schunk.py +++ b/src/blosc2/schunk.py @@ -175,8 +175,14 @@ def __init__(self, chunksize: int = None, data: object = None, **kwargs: dict): Examples -------- >>> import blosc2 - >>> storage = {"contiguous": True, "cparams": {}, "dparams": {}} - >>> schunk = blosc2.SChunk(**storage) + >>> import numpy as np + >>> import os.path + >>> import shutil + >>> import tempfile + >>> cparams = blosc2.CParams() + >>> dparams = blosc2.DParams() + >>> storage = blosc2.Storage(contiguous=True) + >>> schunk = blosc2.SChunk(cparams=cparams, dparams=dparams, storage=storage) In the following, we will write and read a super-chunk to and from disk via memory-mapped files. @@ -184,7 +190,8 @@ def __init__(self, chunksize: int = None, data: object = None, **kwargs: dict): >>> a = np.arange(3, dtype=np.int64) >>> chunksize = a.size * a.itemsize >>> n_chunks = 2 - >>> urlpath = getfixture('tmp_path') / "schunk.b2frame" + >>> tmpdirname = tempfile.mkdtemp() + >>> urlpath = os.path.join(tmpdirname, 'schunk.b2frame') Optional: we intend to write 2 chunks of 24 bytes each, and we expect the compressed size to be smaller than the original size. Hence, we @@ -214,6 +221,7 @@ def __init__(self, chunksize: int = None, data: object = None, **kwargs: dict): [0, 1, 2] >>> np.frombuffer(schunk_mmap.decompress_chunk(1), dtype=np.int64).tolist() [0, 2, 4] + >>> shutil.rmtree(tmpdirname) """ # Check only allowed kwarg are passed allowed_kwargs = [ @@ -452,13 +460,15 @@ def fill_special( >>> # Measure the time to create SChunk from a NumPy array >>> t0 = time.time() >>> data = np.full(nitems, np.pi, dtype) - >>> schunk = blosc2.SChunk(data=data, cparams={"typesize": dtype.itemsize}) + >>> cparams = blosc2.CParams(typesize=dtype.itemsize) + >>> schunk = blosc2.SChunk(data=data, cparams=cparams) >>> t = (time.time() - t0) * 1000. >>> f"Time creating a schunk with a numpy array: {t:10.3f} ms" Time creating a schunk with a numpy array: 710.273 ms >>> # Measure the time to create SChunk using fill_special >>> t0 = time.time() - >>> schunk = blosc2.SChunk(cparams={"typesize": dtype.itemsize}) + >>> cparams = blosc2.CParams(typesize=dtype.itemsize) + >>> schunk = blosc2.SChunk(cparams=cparams) >>> schunk.fill_special(nitems, blosc2.SpecialValue.VALUE, np.pi) >>> t = (time.time() - t0) * 1000. >>> f"Time passing directly the value to `fill_special`: {t:10.3f} ms" @@ -503,7 +513,8 @@ def decompress_chunk(self, nchunk: int, dst: object = None) -> str | bytes: Examples -------- >>> import blosc2 - >>> schunk = blosc2.SChunk(cparams={'typesize': 1}) + >>> cparams = blosc2.CParams(typesize=1) + >>> schunk = blosc2.SChunk(cparams=cparams) >>> buffer = b"wermqeoir23" >>> schunk.append_data(buffer) 1 @@ -542,7 +553,8 @@ def get_chunk(self, nchunk: int) -> bytes: >>> # Create an SChunk with 3 chunks >>> nchunks = 3 >>> data = np.arange(200 * 1000 * nchunks, dtype=np.int32) - >>> schunk = blosc2.SChunk(data=data, cparams={"typesize": 4}) + >>> cparams = blosc2.CParams(typesize=4) + >>> schunk = blosc2.SChunk(data=data, cparams=cparams) >>> # Retrieve the first chunk (index 0) >>> chunk = schunk.get_chunk(0) >>> # Check the type and length of the compressed chunk @@ -578,7 +590,8 @@ def delete_chunk(self, nchunk: int) -> int: >>> # Create an SChunk with 3 chunks >>> nchunks = 3 >>> data = np.arange(200 * 1000 * nchunks, dtype=np.int32) - >>> schunk = blosc2.SChunk(chunksize=200 * 1000 * 4, data=data, cparams={"typesize": 4}) + >>> cparams = blosc2.CParams(typesize=4) + >>> schunk = blosc2.SChunk(chunksize=200 * 1000 * 4, data=data, cparams=cparams) >>> # Check the number of chunks before deletion >>> schunk.nchunks 3 @@ -617,7 +630,8 @@ def insert_chunk(self, nchunk: int, chunk: bytes) -> int: >>> import numpy as np >>> # Create an SChunk with 2 chunks >>> data = np.arange(400 * 1000, dtype=np.int32) - >>> schunk = blosc2.SChunk(chunksize=200*1000*4, data=data, cparams={"typesize": 4}) + >>> cparams = blosc2.CParams(typesize=4) + >>> schunk = blosc2.SChunk(chunksize=200*1000*4, data=data, cparams=cparams) >>> # Get a compressed chunk from the SChunk >>> chunk = schunk.get_chunk(0) >>> # Insert a chunk in the second position (index 1)" @@ -657,7 +671,8 @@ def insert_data(self, nchunk: int, data: object, copy: bool) -> int: >>> import numpy as np >>> # Create an SChunk with 2 chunks >>> data = np.arange(400 * 1000, dtype=np.int32) - >>> schunk = blosc2.SChunk(chunksize=200*1000*4, data=data, cparams={"typesize": 4}) + >>> cparams = blosc2.CParams(typesize=4) + >>> schunk = blosc2.SChunk(chunksize=200*1000*4, data=data, cparams=cparams) >>> # Create a new array to insert into the second chunk of the SChunk >>> new_data = np.arange(200 * 1000, dtype=np.int32) >>> # Insert the new data at position 1, compressing it @@ -696,7 +711,8 @@ def update_chunk(self, nchunk: int, chunk: bytes) -> int: >>> nchunks = 5 >>> chunk_size = 200 * 1000 * 4 >>> data = np.arange(nchunks * chunk_size // 4, dtype=np.int32) - >>> schunk = blosc2.SChunk(chunksize=chunk_size, data=data, cparams={"typesize": 4}) + >>> cparams = blosc2.CParams(typesize=4) + >>> schunk = blosc2.SChunk(chunksize=chunk_size, data=data, cparams=cparams) >>> f"Initial number of chunks: {schunk.nchunks}" Initial number of chunks: 5 >>> c_index = 1 @@ -739,7 +755,8 @@ def update_data(self, nchunk: int, data: object, copy: bool) -> int: >>> nchunks = 4 >>> chunk_size = 200 * 1000 * 4 >>> data = np.arange(nchunks * chunk_size // 4, dtype=np.int32) - >>> schunk = blosc2.SChunk(chunksize=chunk_size, data=data, cparams={"typesize": 4}) + >>> cparams = blosc2.CParams(typesize=4) + >>> schunk = blosc2.SChunk(chunksize=chunk_size, data=data, cparams=cparams) >>> f"Initial number of chunks: {schunk.nchunks}" Initial number of chunks: 4 >>> c_index = 1 # Update the 2nd chunk (index 1) @@ -796,7 +813,8 @@ def get_slice(self, start: int = 0, stop: int = None, out: object = None) -> str >>> nchunks = 4 >>> chunk_size = 200 * 1000 * 4 >>> data = np.arange(nchunks * chunk_size // 4, dtype=np.int32) - >>> schunk = blosc2.SChunk(data=data, cparams={"typesize": 4}) + >>> cparams = blosc2.CParams(typesize=4) + >>> schunk = blosc2.SChunk(data=data, cparams=cparams) >>> # Define the slice parameters >>> start_index = 200 * 1000 >>> stop_index = 2 * 200 * 1000 @@ -851,7 +869,8 @@ def __getitem__(self, item: int | slice) -> str | bytes: >>> nchunks = 4 >>> chunk_size = 200 * 1000 * 4 >>> data = np.arange(nchunks * chunk_size // 4, dtype=np.int32) - >>> schunk = blosc2.SChunk(chunksize=chunk_size, data=data, cparams={"typesize": 4}) + >>> cparams = blosc2.CParams(typesize=4) + >>> schunk = blosc2.SChunk(chunksize=chunk_size, data=data, cparams=cparams) >>> # Use __getitem__ to retrieve the same slice of data from the SChunk >>> res = schunk[150:155] >>> f"Slice data: {np.frombuffer(res, dtype=np.int32)}" @@ -905,7 +924,8 @@ def __setitem__(self, key: int | slice, value: object) -> None: >>> nchunks = 4 >>> chunk_size = 200 * 1000 * 4 >>> data = np.arange(nchunks * chunk_size // 4, dtype=np.int32) - >>> schunk = blosc2.SChunk(data=data, cparams={"typesize": 4}) + >>> cparams = blosc2.CParams(typesize=4) + >>> schunk = blosc2.SChunk(data=data, cparams=cparams) >>> # Create a new array of values to update the slice (values from 1000 to 1999 multiplied by 2) >>> start_ = 1000 >>> stop = 2000 @@ -942,7 +962,8 @@ def to_cframe(self) -> bytes: >>> nchunks = 4 >>> chunk_size = 200 * 1000 * 4 >>> data = np.arange(nchunks * chunk_size // 4, dtype=np.int32) - >>> schunk = blosc2.SChunk(data=data, cparams={"typesize": 4}) + >>> cparams = blosc2.CParams(typesize=4) + >>> schunk = blosc2.SChunk(data=data, cparams=cparams) >>> # Serialize the SChunk instance to a bytes object >>> serialized_schunk = schunk.to_cframe() >>> f"Serialized SChunk length: {len(serialized_schunk)} bytes" @@ -981,7 +1002,8 @@ def iterchunks(self, dtype: np.dtype) -> Iterator[np.ndarray]: >>> import numpy as np >>> # Create sample data and an SChunk >>> data = np.arange(400 * 1000, dtype=np.int32) - >>> schunk = blosc2.SChunk(data=data, cparams={"typesize": 4}) + >>> cparams = blosc2.CParams(typesize=4) + >>> schunk = blosc2.SChunk(data=data, cparams=cparams) >>> # Iterate over chunks using the iterchunks method >>> for chunk in schunk.iterchunks(dtype=np.int32): >>> f"Chunk shape: {chunk.shape} " @@ -1031,7 +1053,8 @@ def iterchunks_info( >>> import numpy as np >>> # Create sample data and an SChunk >>> data = np.arange(400 * 1000, dtype=np.int32) - >>> schunk = blosc2.SChunk(data=data, cparams={"typesize": 4}) + >>> cparams = blosc2.CParams(typesize=4) + >>> schunk = blosc2.SChunk(data=data, cparams=cparams) >>> # Iterate over chunks and print detailed information >>> for chunk_info in schunk.iterchunks_info(): >>> f"Chunk index: {chunk_info.nchunk}" @@ -1099,10 +1122,9 @@ def postfilter(self, input_dtype: np.dtype, output_dtype: np.dtype = None) -> No # Create SChunk input_dtype = np.dtype(np.int64) - cparams = {"typesize": input_dtype.itemsize} - dparams = {"nthreads": 1} - storage = {"cparams": cparams, "dparams": dparams} - schunk = blosc2.SChunk(chunksize=20_000 * input_dtype.itemsize, **storage) + cparams = blosc2.CParams(typesize=input_dtype.itemsize) + dparams = blosc2.DParams(nthreads=1) + schunk = blosc2.SChunk(chunksize=20_000 * input_dtype.itemsize, cparams=cparams, dparams=dparams) # Create postfilter and associate it to the schunk @schunk.postfilter(input_dtype) @@ -1137,9 +1159,10 @@ def remove_postfilter(self, func_name: str, _new_ctx: bool = True) -> None: >>> import blosc2 >>> import numpy as np >>> dtype = np.dtype(np.int32) - >>> storage = {"cparams": {"typesize": dtype.itemsize}, "dparams": {"nthreads": 1}} + >>> cparams = blosc2.CParams(typesize=dtype.itemsize) + >>> dparams = blosc2.DParams(nthreads=1) >>> data = np.arange(500, dtype=np.int32) - >>> schunk = blosc2.SChunk(data=data, **storage) + >>> schunk = blosc2.SChunk(data=data, cparams=cparams, dparams=dparams) >>> # Define the postfilter function >>> @schunk.postfilter(dtype) >>> def postfilter(input, output, offset): @@ -1197,10 +1220,9 @@ def filler(self, inputs_tuple: tuple[tuple], schunk_dtype: np.dtype, nelem: int # Set the compression and decompression parameters schunk_dtype = np.dtype(np.float64) - cparams = {"typesize": schunk_dtype.itemsize, "nthreads": 1} - storage = {"cparams": cparams} + cparams = blosc2.CParams(typesize=schunk_dtype.itemsize, nthreads=1) # Create empty SChunk - schunk = blosc2.SChunk(chunksize=20_000 * schunk_dtype.itemsize, **storage) + schunk = blosc2.SChunk(chunksize=20_000 * schunk_dtype.itemsize, cparams=cparams) # Create operands op_dtype = np.dtype(np.int32) @@ -1278,7 +1300,7 @@ def prefilter(self, input_dtype: np.dtype, output_dtype: np.dtype = None) -> Non # Set the compression and decompression parameters input_dtype = np.dtype(np.int32) output_dtype = np.dtype(np.float32) - cparams = {"typesize": output_dtype.itemsize, "nthreads": 1} + cparams = blosc2.CParams(typesize=output_dtype.itemsize, nthreads=1) # Create schunk schunk = blosc2.SChunk(chunksize=200 * 1000 * input_dtype.itemsize, cparams=cparams) @@ -1316,7 +1338,7 @@ def remove_prefilter(self, func_name: str, _new_ctx: bool = True) -> None: >>> import blosc2 >>> import numpy as np >>> dtype = np.dtype(np.int32) - >>> cparams = {"typesize": dtype.itemsize, "nthreads": 1} + >>> cparams = blosc2.CParams(typesize=dtype.itemsize, nthreads=1) >>> data = np.arange(1000, dtype=np.int32) >>> output_dtype = np.float32 >>> schunk = blosc2.SChunk(cparams=cparams) @@ -1401,15 +1423,19 @@ def open( -------- >>> import blosc2 >>> import numpy as np - >>> storage = {"contiguous": True, "urlpath": getfixture('tmp_path') / "b2frame", "mode": "w"} + >>> import os + >>> import tempfile + >>> tmpdirname = tempfile.mkdtemp() + >>> urlpath = os.path.join(tmpdirname, 'b2frame') + >>> storage = blosc2.Storage(contiguous=True, urlpath=urlpath, mode="w") >>> nelem = 20 * 1000 >>> nchunks = 5 >>> chunksize = nelem * 4 // nchunks >>> data = np.arange(nelem, dtype="int32") >>> # Create SChunk and append data - >>> schunk = blosc2.SChunk(chunksize=chunksize, data=data.tobytes(), **storage) + >>> schunk = blosc2.SChunk(chunksize=chunksize, data=data.tobytes(), storage=storage) >>> # Open SChunk - >>> sc_open = blosc2.open(urlpath=storage["urlpath"]) + >>> sc_open = blosc2.open(urlpath=urlpath) >>> for i in range(nchunks): ... dest = np.empty(nelem // nchunks, dtype=data.dtype) ... schunk.decompress_chunk(i, dest) @@ -1424,7 +1450,7 @@ def open( To open the same schunk memory-mapped, we simply need to pass the `mmap_mode` parameter: - >>> sc_open_mmap = blosc2.open(urlpath=storage["urlpath"], mmap_mode="r") + >>> sc_open_mmap = blosc2.open(urlpath=urlpath, mmap_mode="r") >>> sc_open.nchunks == sc_open_mmap.nchunks True >>> all(sc_open.decompress_chunk(i, dest1) == sc_open_mmap.decompress_chunk(i, dest1) for i in range(nchunks)) From c71f8c6b60accaf52a9a2969af6f44a0098a9bcd Mon Sep 17 00:00:00 2001 From: oumaima-ech-chdig Date: Thu, 10 Oct 2024 13:45:15 +0200 Subject: [PATCH 4/4] All the examples are up to date --- bench/get_slice.py | 8 ++++---- bench/ndarray/compare_getslice.py | 16 ++++++++-------- bench/ndarray/copy_postfilter.py | 3 ++- bench/ndarray/transcode_data.py | 6 +++--- bench/set_slice.py | 8 ++++---- bench/sum_postfilter.py | 9 ++++----- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/bench/get_slice.py b/bench/get_slice.py index 2c483014..db1f2485 100644 --- a/bench/get_slice.py +++ b/bench/get_slice.py @@ -22,8 +22,8 @@ nchunks = shape // chunksize # Set the compression and decompression parameters -cparams = {"codec": blosc2.Codec.BLOSCLZ, "typesize": 8, "blocksize": blocksize * 8} -dparams = {} +cparams = blosc2.CParams(codec=blosc2.Codec.BLOSCLZ, typesize=8, blocksize=blocksize * 8) +dparams = blosc2.DParams() contiguous = True persistent = bool(sys.argv[1]) if len(sys.argv) > 1 else False @@ -32,11 +32,11 @@ else: urlpath = None -storage = {"contiguous": contiguous, "urlpath": urlpath, "cparams": cparams, "dparams": dparams} +storage = blosc2.Storage(contiguous=contiguous, urlpath=urlpath) blosc2.remove_urlpath(urlpath) # Create the empty SChunk -schunk = blosc2.SChunk(chunksize=chunksize * cparams["typesize"], **storage) +schunk = blosc2.SChunk(chunksize=chunksize * cparams.typesize, storage=storage, cparams=cparams, dparams=dparams) # Append some chunks for i in range(nchunks): diff --git a/bench/ndarray/compare_getslice.py b/bench/ndarray/compare_getslice.py index 7438e035..e3d09fee 100644 --- a/bench/ndarray/compare_getslice.py +++ b/bench/ndarray/compare_getslice.py @@ -62,14 +62,14 @@ cname = "zstd" nthreads = 8 filter = blosc2.Filter.SHUFFLE -cparams = { - "codec": blosc2.Codec.ZSTD, - "clevel": clevel, - "filters": [filter], - "filters_meta": [0], - "nthreads": nthreads, -} -dparams = {"nthreads": nthreads} +cparams = blosc2.CParams( + codec=blosc2.Codec.ZSTD, + clevel=clevel, + filters=[filter], + filters_meta=[0], + nthreads=nthreads, +) +dparams = blosc2.DParams(nthreads=nthreads) zfilter = numcodecs.Blosc.SHUFFLE blocksize = int(np.prod(blocks)) if blocks else 0 diff --git a/bench/ndarray/copy_postfilter.py b/bench/ndarray/copy_postfilter.py index fb30aeb6..236291ec 100644 --- a/bench/ndarray/copy_postfilter.py +++ b/bench/ndarray/copy_postfilter.py @@ -18,11 +18,12 @@ dtype = np.dtype(np.int32) # Set the compression and decompression parameters -dparams = {"nthreads": 1} +dparams = {"nthreads" : 1} # Create array arr = blosc2.empty(shape=(nchunks * chunkshape,), chunks=(chunkshape,), dtype=dtype, dparams=dparams) data = np.arange(chunkshape, dtype=dtype) + t0 = time() for i in range(nchunks): arr[i * chunkshape : (i + 1) * chunkshape] = data diff --git a/bench/ndarray/transcode_data.py b/bench/ndarray/transcode_data.py index 3a02a79d..f4c62bd8 100644 --- a/bench/ndarray/transcode_data.py +++ b/bench/ndarray/transcode_data.py @@ -69,9 +69,9 @@ }, } -dparams = { - "nthreads": nthreads_decomp, -} +dparams = blosc2.DParams( + nthreads=nthreads_decomp, +) dir_path = Path(dir_path) if not dir_path.is_dir(): diff --git a/bench/set_slice.py b/bench/set_slice.py index 95519cc8..65b3ad7f 100644 --- a/bench/set_slice.py +++ b/bench/set_slice.py @@ -22,8 +22,8 @@ nchunks = shape // chunksize # Set the compression and decompression parameters -cparams = {"codec": blosc2.Codec.BLOSCLZ, "typesize": 8, "blocksize": blocksize * 8} -dparams = {} +cparams = blosc2.CParams(codec=blosc2.Codec.BLOSCLZ, typesize=8, blocksize=blocksize * 8) +dparams = blosc2.DParams() contiguous = True persistent = bool(sys.argv[1]) if len(sys.argv) > 1 else False @@ -32,11 +32,11 @@ else: urlpath = None -storage = {"contiguous": contiguous, "urlpath": urlpath, "cparams": cparams, "dparams": dparams} +storage = blosc2.Storage(contiguous=contiguous, urlpath=urlpath) blosc2.remove_urlpath(urlpath) # Create the empty SChunk -schunk = blosc2.SChunk(chunksize=chunksize * cparams["typesize"], **storage) +schunk = blosc2.SChunk(chunksize=chunksize * cparams.typesize, storage=storage, cparams=cparams, dparams=dparams) # Append some chunks for i in range(nchunks): diff --git a/bench/sum_postfilter.py b/bench/sum_postfilter.py index 8a892c08..afca4397 100644 --- a/bench/sum_postfilter.py +++ b/bench/sum_postfilter.py @@ -19,13 +19,12 @@ chunksize = chunkshape * dtype.itemsize # Set the compression and decompression parameters -cparams = {"typesize": 4, "nthreads": 1} -dparams = {"nthreads": 1} -storage = {"cparams": cparams, "dparams": dparams} +cparams = blosc2.CParams(typesize=4, nthreads=1) +dparams = blosc2.DParams(nthreads=1) # Create super-chunks -schunk0 = blosc2.SChunk(chunksize=chunksize, **storage) -schunk = blosc2.SChunk(chunksize=chunksize, **storage) +schunk0 = blosc2.SChunk(chunksize=chunksize, cparams=cparams, dparams=dparams) +schunk = blosc2.SChunk(chunksize=chunksize, cparams=cparams, dparams=dparams) data = np.arange(chunkshape, dtype=dtype) t0 = time()