将NetCDF文件转换为TileDB或Zarr数组的适配器
项目描述
tiledb_netcdf
将NetCDF文件转换为TileDB或Zarr数组的适配器。
用法示例
我们将演示如何使用此库将NetCDF文件转换为TileDB和Zarr,并使用Iris和Xarray读取结果。
转换为TileDB
TileDB支持直接与公共云平台提供的blob存储进行交互。目前此库仅支持Azure Blob Storage容器,但我们将在未来版本中添加AWS支持。如果您现在需要此支持,请提出问题👆!
1. 创建通用数据模型
使用数据模型类NCDataModel
创建数据模型
from nctotdb import NCDataModel
data_model = NCDataModel('/path/to/my/file.nc')
data_model.populate()
手动修改分类
NetCDF变量的分类远非精确的科学,有时可能会错误地分类变量。在这种情况下,您可以通过使用以下方式手动修改分类过程,而不是调用data_model.populate()
data_model = NCDataModel('/path/to/my/file.nc')
my_bespoke_data_var_name = 'foobarbaz'
with data_model.open_netcdf():
data_model.classify_variables()
data_model.data_var_names = [my_bespoke_data_var_name]
data_model.get_metadata()
2. 编写数据模型
创建数据模型后,我们可以将NetCDF文件的内容转换为支持的云就绪文件格式(其中一个是TileDB
或Zarr
)。这里我们将演示写入TileDB,Zarr将在下一节中介绍。
如前所述,我们可以写入posix-like文件路径或直接写入Azure Storage账户blob容器。让我们逐一介绍这些。
2a. 文件路径
from nctotdb import TileDBWriter
# TileDB.
tiledb_save_path = '/path/to/my_tdb'
tiledb_name = 'my_tiledb'
unlimited_dims = 'z' # Useful if you know you're going to need to append to the `z` dimension
writer = TileDBWriter(data_model,
array_filepath=tiledb_save_path,
array_name=tiledb_name,
unlimited_dims=unlimited_dims)
writer.create_domains()
2b. Blob容器
为了与Azure存储账户的Blob容器接口,需要进行一些配置。我们需要为Azure存储账户提供认证,并配置TileDB操作以与我们要写入的Blob容器协同工作。
import tiledb
# Azure blob storage definitions.
storage_account_name = 'my_azure_storage_account_name'
container = 'my_blob_container_name'
uri = f'azure://{container}'
access_key = 'my_azure_access_key'
# TileDB configuration for Azure Blob.
cfg = tiledb.Config()
cfg['vfs.azure.storage_account_name'] = storage_account_name
cfg['vfs.azure.storage_account_key'] = access_key
cfg["vfs.s3.use_multipart_upload"] = 'false'
ctx = tiledb.Ctx(config=cfg)
重要!不要共享或发布您的Azure存储账户密钥!您还可以设置一个环境变量,TileDB将使用该变量而不是将账户密钥粘贴到您的代码中。
现在我们可以写入我们的TileDB数组。这与使用posix-like路径相似,不同之处在于我们必须传递TileDB Ctx
(上下文)对象,并指定一个容器而不是一个保存的文件路径。
writer = TileDBWriter(data_model,
container=container,
array_name=tiledb_name,
unlimited_dims=unlimited_dims,
ctx=ctx)
writer.create_domains()
3. 追加
我们还可以沿着一个命名维度追加一个或多个额外的NetCDF文件的内容。这些额外的NetCDF文件可以指定为一个文件路径列表,或为一个数据模型对象列表。如果指定了文件路径,它们将自动转换为数据模型对象。
append_files = ['file1.nc', 'file2.nc', 'file3.nc']
data_array_name = 'data' # The name of the data arrays in the TileDB array, typically `data`.
writer.append(append_files, unlimited_dims, data_array_name)
您可以通过启用详细模式来跟踪追加操作的进度。
writer.append(append_files, unlimited_dims, data_array_name,
verbose=True)
如果您有大量文件要追加,或者您只想让追加操作更快完成,tiledb_netcdf
可以使用dask并行化每个文件的追加操作。假设您已经设置了一个dask集群,名为my_cluster
。
client = dask.distributed.Client(my_cluster)
logfile = "append.log"
writer.append(append_files, unlimited_dims, data_array_name,
parallel=True, logfile=logfile)
注意:建议您也记录并行追加日志,以便在追加过程中发生错误时进行错误跟踪。
3a. 标量追加
需要单独处理追加的一个情况是,要追加的数据集在追加维度上是标量的。例如,您可能希望沿着time
维度追加,但基础数据集和要追加的所有文件只包含一个(即标量)时间点。在这种情况下,需要进行标量追加。
通常,追加算法使用追加维度上点之间的间隔来计算所有要追加的数据集的偏移量。由于追加维度上只有一个点,这不可能实现,因此您需要向追加调用提供一个文件,以便计算文件之间的偏移量。为了确保正确计算偏移量,此文件必须描述从最初用于创建TileDB数组文件中使用的文件开始的追加维度的下一步。
用于计算偏移量的文件通过使用baseline
关键字参数传递到追加操作中。例如
append_files = ['file1.nc', 'file2.nc', 'file3.nc', 'file4.nc', 'file5.nc']
data_array_name = 'data'
writer.append(append_files, unlimited_dims, data_array_name,
baselines={unlimited_dims: append_files[0]})
注意:用于计算偏移量的文件不会像用于计算偏移量那样被追加。您需要将偏移量文件包含在追加文件中!
注意:所有具有标量追加维度的追加都必须提供一个baseline
文件来计算偏移量,即使追加已经成功执行也是如此。您还必须在字典{"append_dim": baseline_file}
中为每个标量追加维度指定一个基线文件。
如果您尝试在没有提供用于计算偏移量的baseline
文件的情况下沿着标量维度执行追加,您将遇到错误消息。
ValueError: Cannot determine scalar step without a baseline dataset.
3b. 自定义追加文件之间的偏移量
您可能偶尔需要覆盖连续追加文件之间的偏移量,例如在文件之间引入一些填充,或处理意外的短文件。这可以通过使用append
的override_offsets
关键字参数来实现。与指定baselines
一样,您需要传递一个字典,将命名追加维度链接到要应用于该维度的偏移量覆盖。例如
append_files = ['file1.nc', 'file2.nc', 'file3_short.nc', 'file4.nc', 'file5.nc']
expected_dim_len = 10
data_array_name = 'data'
writer.append(append_files, unlimited_dims, data_array_name,
override_offsets={unlimited_dims: expected_dim_len})
在这种情况下,第三个文件比预期要短(如文件名所示),覆盖偏移量允许我们在文件长度不足的地方用缺失数据填充附加维度。我们可以在追加完成后使用 fill_missing_points
方法来填充相关维度坐标的间隙。
writer.fill_missing_points(unlimited_dims)
注意:您不需要为每个追加维度提供覆盖偏移量。
4. 读取转换后的数组
我们可以使用 Reader
类来读取我们的 TileDB 数组,使用 Iris 或 Xarray。
from nctotdb import TileDBReader
# From a posix-like filepath:
tiledb_reader = TileDBReader(tiledb_name, array_filepath=tiledb_save_path)
# Or directly from Azure Blob:
tiledb_reader = TileDBReader(tiledb_name, container=container, ctx=ctx)
# TileDB to Iris.
cubes = tiledb_reader.to_iris() # Convert all TileDB arrays to Iris Cubes.
cube = tiledb_reader.to_iris('array_name') # Convert a named variable to an Iris Cube.
# TileDB to Xarray.
dss = tiledb_reader.to_xarray() # Convert all TileDB arrays to Xarray.
ds = tiledb_reader.to_xarray('array_name') # Convert a named variable to an Xarray dataset.
转换为 Zarr
我们还可以使用此库将 NetCDF 文件转换为 Zarr,并将这些 Zarr 读取回 Iris 和 Xarray。为 Zarr 提供的 API 与为 TileDB 提供的相似。
1. 创建通用数据模型
这完全与 TileDB 相同。区别在于下一步,我们选择用于存储数据模型表示的 NetCDF 文件内容的表示格式。
from nctotdb import NCDataModel
my_nc_filepath = '/path/to/my/file.nc'
data_model = NCDataModel(my_nc_file)
data_model.populate()
2. 写入 Zarr
创建数据模型后,我们可以将 NetCDF 文件的内容写入 Zarr。
from nctotdb import ZarrWriter
zarr_writer = ZarrWriter(data_model, '/path/to/my_zarr',
array_name='my_zarr')
zarr_writer.create_zarr()
3. 追加
我们还可以将其他 NetCDF 文件的内容添加到我们创建的 Zarr 中,并扩展 Zarr 中的一个维度。
my_other_nc_filepath = '/path/to/my/other_file.nc'
other_data_model = NCDataModel(my_other_nc_file)
append_var_name = 'array_name'
append_dim = 'dimension_name'
zarr_writer.append(other_data_model, append_var_name, append_dim)
4. 读取 Zarr
最后,我们可以将创建的 Zarr 读取到 Iris 和 Xarray 中。
from nctotdb import ZarrReader
zarr_reader = ZarrReader('/path/to/my_zarr')
cubes = zarr_reader.to_iris()
ds = zarr_reader.to_xarray()
项目详情
下载文件
下载您平台的文件。如果您不确定选择哪个,请了解有关 安装包 的更多信息。