1+ """This module contains a Pydantic model to parameterize compressors.
2+
3+ Important Objects:
4+ - Blosc: A Pydantic model that represents a Blosc compression setup.
5+ - ZFP: Class that represents the ZFP compression model.
6+ """
7+
8+ from __future__ import annotations
9+
10+ from enum import IntEnum
11+ from enum import StrEnum
12+
13+ from pydantic import Field
14+ from pydantic import model_validator
15+
16+ from mdio .schema .core import CamelCaseStrictModel
17+
18+
19+ class BloscAlgorithm (StrEnum ):
20+ """Enum for Blosc algorithm options."""
21+
22+ BLOSCLZ = "blosclz"
23+ LZ4 = "lz4"
24+ LZ4HC = "lz4hc"
25+ ZLIB = "zlib"
26+ ZSTD = "zstd"
27+
28+
29+ class BloscShuffle (IntEnum ):
30+ """Enum for Blosc shuffle options."""
31+
32+ NOSHUFFLE = 0
33+ SHUFFLE = 1
34+ BITSHUFFLE = 2
35+ AUTOSHUFFLE = - 1
36+
37+
38+ class Blosc (CamelCaseStrictModel ):
39+ """Data Model for Blosc options."""
40+
41+ name : str = Field (default = "blosc" , description = "Name of the compressor." )
42+ algorithm : BloscAlgorithm = Field (
43+ default = BloscAlgorithm .LZ4 ,
44+ description = "The Blosc compression algorithm to be used." ,
45+ )
46+ level : int = Field (default = 5 , ge = 0 , le = 9 , description = "The compression level." )
47+ shuffle : BloscShuffle = Field (
48+ default = BloscShuffle .SHUFFLE ,
49+ description = "The shuffle strategy to be applied before compression." ,
50+ )
51+ blocksize : int = Field (
52+ default = 0 ,
53+ description = "The size of the block to be used for compression." ,
54+ )
55+
56+ def make_instance (self ): # noqa: ANN201
57+ """Translate parameters to compressor kwargs.."""
58+ from zarr .codecs import Blosc as _Blosc
59+
60+ return _Blosc (
61+ cname = self .algorithm ,
62+ clevel = self .level ,
63+ shuffle = self .shuffle ,
64+ blocksize = self .blocksize ,
65+ )
66+
67+
68+ zfp_mode_map = {
69+ "fixed_rate" : 2 ,
70+ "fixed_precision" : 3 ,
71+ "fixed_accuracy" : 4 ,
72+ "reversible" : 5 ,
73+ }
74+
75+
76+ class ZFPMode (StrEnum ):
77+ """Enum for ZFP algorithm modes."""
78+
79+ FIXED_RATE = "fixed_rate"
80+ FIXED_PRECISION = "fixed_precision"
81+ FIXED_ACCURACY = "fixed_accuracy"
82+ REVERSIBLE = "reversible"
83+
84+ @property
85+ def int_code (self ) -> int :
86+ """Return the integer code of ZFP mode."""
87+ return zfp_mode_map [self .value ]
88+
89+
90+ class ZFP (CamelCaseStrictModel ):
91+ """Data Model for ZFP options."""
92+
93+ name : str = Field (default = "zfp" , description = "Name of the compressor." )
94+ mode : ZFPMode = Field ()
95+
96+ tolerance : float | None = Field (
97+ default = None ,
98+ description = "Fixed accuracy in terms of absolute error tolerance." ,
99+ )
100+
101+ rate : float | None = Field (
102+ default = None ,
103+ description = "Fixed rate in terms of number of compressed bits per value." ,
104+ )
105+
106+ precision : int | None = Field (
107+ default = None ,
108+ description = "Fixed precision in terms of number of uncompressed bits per value." ,
109+ )
110+
111+ write_header : bool = Field (
112+ default = True ,
113+ description = "Encode array shape, scalar type, and compression parameters." ,
114+ )
115+
116+ @model_validator (mode = "after" )
117+ def check_requirements (self ) -> ZFP :
118+ """Check if ZFP parameters make sense."""
119+ mode = self .mode
120+
121+ # Check if reversible mode is provided without other parameters.
122+ if mode == ZFPMode .REVERSIBLE and any (
123+ getattr (self , key ) is not None for key in ["tolerance" , "rate" , "precision" ]
124+ ):
125+ msg = "Other fields must be None in REVERSIBLE mode"
126+ raise ValueError (msg )
127+
128+ if mode == ZFPMode .FIXED_ACCURACY and self .tolerance is None :
129+ msg = "Tolerance required for FIXED_ACCURACY mode"
130+ raise ValueError (msg )
131+
132+ if mode == ZFPMode .FIXED_RATE and self .rate is None :
133+ msg = "Rate required for FIXED_RATE mode"
134+ raise ValueError (msg )
135+
136+ if mode == ZFPMode .FIXED_PRECISION and self .precision is None :
137+ msg = "Precision required for FIXED_PRECISION mode"
138+ raise ValueError (msg )
139+
140+ return self
141+
142+ def make_instance (self ): # noqa: ANN201
143+ """Translate parameters to compressor kwargs.."""
144+ from zarr .codecs import ZFPY as _ZFPY
145+
146+ return _ZFPY (
147+ mode = self .mode .int_code ,
148+ tolerance = self .tolerance ,
149+ rate = self .rate ,
150+ precision = self .precision ,
151+ )
152+
153+
154+ class CompressorModel (CamelCaseStrictModel ):
155+ """Model representing compressor configuration."""
156+
157+ compressor : Blosc | ZFP | None = Field (
158+ default = None , description = "Compression settings."
159+ )
0 commit comments