Файл NetCDF - почему размер файла составляет 1/3 после исправления размера записи?

Я изо всех сил пытаюсь справиться с этим.

Я создаю файл netcdf4 со следующими размерами и переменными (обратите внимание, в частности, на неограниченный размер point):

dimensions:
    point = UNLIMITED ; // (275935 currently)
    realization = 24 ;
variables:
    short mod_hs(realization, point) ;
        mod_hs:scale_factor = 0.01 ;
    short mod_ws(realization, point) ;
        mod_ws:scale_factor = 0.01 ;
    short obs_hs(point) ;
        obs_hs:scale_factor = 0.01 ;
    short obs_ws(point) ;
        obs_ws:scale_factor = 0.01 ;
    short fchr(point) ;
    float obs_lat(point) ;
    float obs_lon(point) ;
    double obs_datetime(point) ;
}

У меня есть программа Python, которая заполняет этот файл данными в цикле (отсюда и неограниченный размер записи - я априори не знаю, насколько большим будет файл).

После заполнения файла его размер составляет 103 МБ.

Моя проблема в том, что чтение данных из этого файла происходит довольно медленно. Я догадался, что это как-то связано с чанкингом и неограниченным point измерением?

Я запустил ncks --fix_rec_dmn для файла, и (после долгой обработки) он создал новый файл netCDF размером всего 32 МБ (что примерно соответствует размеру содержащихся в нем данных).

Это огромная разница в размере - почему исходный файл такой раздутый? Кроме того, доступ к данным в этом файле на несколько порядков быстрее. Например, в Python чтение содержимого переменной hs занимает 2 секунды в исходном файле и 40 миллисекунд в файле с фиксированным размером записи.

Моя проблема заключается в том, что некоторые из моих файлов содержат много точек и кажутся слишком большими для запуска ncks (на моей машине заканчивается память, а у меня 8 ГБ), поэтому я не могу преобразовать все данные в фиксированную запись. измерение.

Может ли кто-нибудь объяснить, почему размеры файлов такие разные и как я могу сделать исходные файлы меньше и эффективнее для чтения?

Кстати, я не использую сжатие zlib (я выбрал масштабирование значений с плавающей запятой до целого числа).

Крис

РЕДАКТИРОВАТЬ Мой код Python, по сути, создает один файл временных рядов совмещенных моделей и данных наблюдений из нескольких файлов прогнозов отдельных моделей за 3 месяца. Моя модель прогноза запускается 4 раза в день, и я собираю данные за 3 месяца, так что получается ~120 файлов.

Программа извлекает подмножество прогнозируемого периода из каждого файла (например, T+24h -> T+48h), поэтому объединить файлы не так просто.

Это грубое приближение к тому, что делает мой код (на самом деле он читает/записывает больше переменных, но я просто показываю здесь 2 для ясности):

# Create output file:
dout = nc.Dataset(fn, mode='w', clobber=True, format="NETCDF4")

dout.createDimension('point', size=None)
dout.createDimension('realization', size=24)

for varname in ['mod_hs','mod_ws']:
    v = ncd.createVariable(varname, np.short, 
            dimensions=('point', 'realization'), zlib=False)
    v.scale_factor = 0.01

# Cycle over dates
date = <some start start>
end_dat = <some end date>

# Keeo track if record dimension ('point') size:
n = 0

while date < end_date: 
    din = nc.Dataset("<path to input file>", mode='r')
    fchr = din.variables['fchr'][:]

    # get mask for specific forecast hour range
    m = np.logical_and(fchr >= 24, fchr < 48)
    sz = np.count_nonzero(m)

    if sz == 0:
        continue

    dout.variables['mod_hs'][n:n+sz,:] = din.variables['mod_hs'][:][m,:]
    dout.variables['mod_ws'][n:n+sz,:] = din.variables['mod_wspd'][:][m,:]

    # Increment record dimension count:
    n += sz

    din.close()

    # Goto next file
    date += dt.timedelta(hours=6)

dout.close()

Интересно, что если я сделаю формат выходного файла NETCDF3_CLASSIC, а не NETCDF4, размер вывода будет таким, как я ожидал. Вывод NETCDF4 кажется раздутым.


person ccbunney    schedule 29.10.2015    source источник
comment
Вы на правильном пути, правильное разбиение на фрагменты должно решить проблему как с размером файла, так и со скоростью чтения. Но для того, чтобы дать Вам совет по лучшему фрагментированию, мне нужно сначала увидеть минимальный рабочий пример кода.   -  person kakk11    schedule 30.10.2015
comment
@ kakk11: Спасибо, что посмотрели это - я добавил пример кода.   -  person ccbunney    schedule 30.10.2015


Ответы (3)


Пожалуйста, попробуйте предоставить код, который работает без изменений, если это возможно, мне пришлось отредактировать, чтобы заставить его работать, но это было не так уж сложно.

import netCDF4 as nc
import numpy as np
dout = nc.Dataset('testdset.nc4', mode='w', clobber=True, format="NETCDF4")
dout.createDimension('point', size=None)
dout.createDimension('realization', size=24)
for varname in ['mod_hs','mod_ws']:
    v = dout.createVariable(varname, np.short, 
            dimensions=('point', 'realization'), zlib=False,chunksizes=[1000,24])
    v.scale_factor = 0.01
date = 1
end_date = 5000
n = 0
while date < end_date: 
    sz=100
    dout.variables['mod_hs'][n:n+sz,:] = np.ones((sz,24))
    dout.variables['mod_ws'][n:n+sz,:] = np.ones((sz,24))
    n += sz
    date += 1
dout.close()

Основное отличие заключается в команде createVariable. Что касается размера файла, то, не указывая «размеры фрагментов» при создании переменной, я также получил вдвое больший файл по сравнению с тем, когда я его добавил. Так что для размера файла это должно сработать. Для чтения переменных из файла я на самом деле не заметил никакой разницы, может быть, я должен добавить больше переменных? В любом случае, теперь должно быть ясно, как добавить размер фрагмента. Возможно, вам нужно немного протестировать, чтобы получить хорошую конфигурацию для вашей проблемы. Не стесняйтесь спрашивать больше, если это все еще не работает для Вас, и если Вы хотите узнать больше о фрагментации, прочитайте документы hdf5

person kakk11    schedule 30.10.2015
comment
Из некоторых моих поисков в Google по фрагментам у меня сложилось впечатление, что неограниченное измерение должно иметь размер фрагмента, равный 1, для измерения записи ... хотя здесь это явно не так, и, похоже, это работает! - person ccbunney; 03.11.2015

По моему опыту, размер куска по умолчанию для размеров записи зависит от версии библиотеки netCDF. Для 4.3.3.1 это 524288. 275935 записей — это примерно половина записи. ncks автоматически выбирает (не сообщая вам) более разумные размеры фрагментов, чем значения по умолчанию netCDF, поэтому вывод лучше оптимизирован. Я думаю, что это то, что происходит. См. http://nco.sf.net/nco.html#cnk.

person Charlie Zender    schedule 07.11.2015

Я думаю, ваша проблема в том, что размер фрагмента по умолчанию для неограниченных измерений равен 1, что создает огромное количество внутренних структур HDF5. При явной установке размера фрагмента (очевидно, это нормально для неограниченных размеров) второй пример работает намного лучше в пространстве и времени.

Неограниченные размеры требуют фрагментации в HDF5/netCDF4, поэтому, если вам нужны неограниченные размерности, вы должны подумать о производительности фрагментации, как вы обнаружили.

Подробнее здесь:

https://www.unidata.ucar.edu/software/netcdf/docs/netcdf_perf_chunking.html

person John Caron    schedule 06.11.2015