netcdf檔案複製並修改

槑孒發表於2024-11-29
import numpy as np
from netCDF4 import Dataset
from datetime import datetime

# 獲取當前時間
current_time = datetime.now()

# 格式化為只顯示時間
formatted_time = current_time.strftime("%m-%d-%H-%M-%S")


def extend_list(lst, extension_count):
    """
    擴充套件列表兩端,增加指定數量的元素
    :param lst: 原始列表
    :param extension_count: 擴充套件的元素數量
    :return: 擴充套件後的列表
    """
    original_type = type(lst[0])
    delta = lst[1] - lst[0]

    # 向左擴充套件
    left_extension = [original_type(lst[0] - delta * i) for i in range(1, extension_count + 1)]
    left_extension.reverse()

    # 向右擴充套件
    right_extension = [original_type(lst[-1] + delta * i) for i in range(1, extension_count + 1)]

    # 合併擴充套件後的結果
    extended_lst = np.concatenate([left_extension, lst, right_extension])

    return extended_lst


def copy_variable_attributes(src_var, dst_var):
    """
    複製變數的所有屬性並設定分塊大小
    :param src_var: 源變數
    :param dst_var: 目標變數
    """
    # 複製變數的屬性
    for attr_name in src_var.ncattrs():
        if attr_name != '_FillValue':  # 跳過 _FillValue
            dst_var.setncattr(attr_name, src_var.getncattr(attr_name))


def copy_polar_stereographic(src_nc, dst_nc):
    """
    複製 polar_stereographic 變數及其屬性
    :param src_nc: 源 NetCDF 檔案
    :param dst_nc: 目標 NetCDF 檔案
    """
    polar_stereographic_src = src_nc.variables['polar_stereographic']
    polar_stereographic_target = dst_nc.createVariable(
        'polar_stereographic', polar_stereographic_src.datatype, polar_stereographic_src.dimensions
    )

    # 複製所有屬性
    for attr in polar_stereographic_src.ncattrs():
        polar_stereographic_target.setncattr(attr, polar_stereographic_src.getncattr(attr))

    # 複製資料(如果是一個簡單的標量資料,可以直接複製)
    polar_stereographic_target[:] = polar_stereographic_src[:]

    x_max = int(dst_nc.variables['x'][:][-1] + 3125)
    y_yax = int(dst_nc.variables['y'][:][-1] + 3125)
    # 設定 GeoTransform(示例值,可以根據需要調整)
    polar_stereographic_target.GeoTransform = f'-{x_max} 6250 0 {y_yax} 0 -6250'


def create_and_save_nc(input_file_path, output_file_path, extension_count=100):
    """
    擴充套件原始 NetCDF 資料並儲存到新檔案
    :param input_file_path: 輸入的 NetCDF 檔案路徑
    :param output_file_path: 輸出的 NetCDF 檔案路徑
    :param extension_count: 要擴充套件的座標數(預設擴充套件 100)
    """
    # 開啟原始 NetCDF 檔案並讀取資料
    with Dataset(input_file_path, mode='r') as nc_file:
        # 讀取現有的 x、y 和 z
        x = nc_file.variables['x'][:]
        y = nc_file.variables['y'][:]
        z = nc_file.variables['z'][:]

        # 獲取現有的形狀
        x_size, y_size = x.shape[0], y.shape[0]

        # 計算新座標,增加指定數量的座標點
        new_x = extend_list(x, extension_count)  # 在 x 軸增加指定數量的點
        new_y = extend_list(y, extension_count)  # 在 y 軸增加指定數量的點

        # 建立新的 z 陣列,形狀為新的 x 和 y 的交叉形狀
        new_z = np.full((new_y.shape[0], new_x.shape[0]), 50, dtype=np.float32)  # 新陣列賦值為 50

        # 將現有的 z 陣列放入新的 z 陣列中,保持原有資料
        new_z[extension_count:y_size + extension_count, extension_count:x_size + extension_count] = z  # 現有資料放入新陣列的中間

        # 建立新的 NetCDF 檔案來儲存資料
        with Dataset(output_file_path, mode='w', format='NETCDF4') as new_nc_file:
            # 建立新的維度
            new_nc_file.createDimension('x', new_x.shape[0])
            new_nc_file.createDimension('y', new_y.shape[0])

            # 建立新的變數並儲存資料
            x_var = new_nc_file.createVariable('x', 'f8', ('x',), zlib=False)
            y_var = new_nc_file.createVariable('y', 'f8', ('y',), zlib=False)

            # 設定分塊大小 (例如: 'x' 維度塊大小為 1,'y' 維度塊大小為 1264)
            chunk_sizes = (1, x_var.size)  # 根據你的需求設定塊大小
            z_var = new_nc_file.createVariable('z', np.float32, ('y', 'x'),
                                               fill_value=nc_file.variables['z']._FillValue, chunksizes=chunk_sizes,
                                               zlib=True)

            # 將資料寫入變數
            x_var[:] = new_x
            y_var[:] = new_y
            z_var[:] = new_z

            # 複製原始變數的屬性並設定分塊
            copy_variable_attributes(nc_file.variables['x'], x_var)
            copy_variable_attributes(nc_file.variables['y'], y_var)
            copy_variable_attributes(nc_file.variables['z'], z_var)

            # 複製空間參考資訊
            copy_polar_stereographic(nc_file, new_nc_file)

    print(f"資料已儲存到 {output_file_path}")


if __name__ == '__main__':
    input_file_path = r'F:\Polar\data\sea_ice_concentration_241130.nc'
    output_file_path = fr'F:\Polar\data\{formatted_time}-sea_ice_concentration_241130.nc'

    create_and_save_nc(input_file_path, output_file_path, extension_count=100)

相關文章