Описание проблемы
При написании симулятора частиц Монте-Карло (броуновское движение и излучение фотонов) на python / numpy. Мне нужно сохранить результат моделирования (>> 10 ГБ) в файл и обработать данные на втором этапе. Совместимость как с Windows, так и с Linux очень важна.
Количество частиц (n_particles
) 10-100. Количество временных шагов (time_size
) составляет ~ 10 ^ 9.
Симуляция состоит из 3 шагов (код ниже для версии, полностью в ОЗУ):
Смоделируйте (и сохраните) массив ставок
emission
(содержит много почти нулевых элементов):- shape (
n_particles
xtime_size
), float32, size 80GB
- shape (
Вычислить массив
counts
(случайные значения из процесса Пуассона с ранее вычисленными скоростями):shape (
n_particles
xtime_size
), uint8, размер 20 ГБcounts = np.random.poisson(lam=emission).astype(np.uint8)
Найдите отметки времени (или индекс) отсчетов. Счетчики почти всегда равны 0, поэтому массивы временных меток умещаются в ОЗУ.
# Loop across the particles timestamps = [np.nonzero(c) for c in counts]
Я делаю шаг 1 один раз, затем повторяю шаг 2-3 много (~ 100) раз. В будущем мне может потребоваться предварительная обработка emission
(применение cumsum
или других функций) перед вычислением counts
.
Вопрос
У меня есть работающая реализация в памяти, и я пытаюсь понять, как лучше всего реализовать версию вне ядра, которая может масштабироваться для (гораздо) более длительных симуляций.
Что бы я хотел, чтобы он существовал
Мне нужно сохранять массивы в файл, и я хотел бы использовать один файл для моделирования. Мне также нужен «простой» способ сохранить и вызвать словарь параметров моделирования (скаляры).
В идеале мне нужен массив numpy с файловой поддержкой, который я могу предварительно выделить и заполнить кусками. Затем я хотел бы, чтобы методы массива numpy (max
, cumsum
, ...) работали прозрачно, требуя только ключевого слова chunksize
, чтобы указать, какую часть массива загружать на каждой итерации.
Еще лучше, мне бы хотелось, чтобы Numexpr работал не между кешем и ОЗУ, а между ОЗУ и жестким диском.
Какие есть практические варианты
В качестве первого варианта я начал экспериментировать с pyTables, но меня не устраивают его сложность и абстракции (настолько отличные от numpy). Более того, мое текущее решение (читайте ниже) УЖАСНО и не очень эффективно.
Итак, мои варианты, на которые я ищу ответ, следующие:
реализовать массив numpy с требуемой функциональностью (как?)
умнее использовать pytable (разные структуры данных / методы)
используйте другую библиотеку: h5py, blaze, pandas ... (я пока ни одну из них не пробовал).
Предварительное решение (pyTables)
Я сохраняю параметры моделирования в группе '/parameters'
: каждый параметр преобразуется в скаляр массива numpy. Подробное решение, но оно работает.
Я сохраняю emission
как расширяемый массив (EArray
), потому что я генерирую данные по частям, и мне нужно добавлять каждый новый фрагмент (хотя я знаю окончательный размер). Сохранить counts
проблематичнее. Если сохранить его как массив pytable, будет сложно выполнять такие запросы, как «counts> = 2». Поэтому я сохранил счетчики в виде нескольких таблиц (по одной на частицу) [УГРОЗНО] и запрашиваю с .get_where_list('counts >= 2')
. Я не уверен, что это занимает много места, и создание всех этих таблиц вместо использования одного массива значительно затирает файл HDF5. Более того, как ни странно, создание этих таблиц требует создания настраиваемого dtype (даже для стандартных numpy dtypes):
dt = np.dtype([('counts', 'u1')])
for ip in xrange(n_particles):
name = "particle_%d" % ip
data_file.create_table(
group, name, description=dt, chunkshape=chunksize,
expectedrows=time_size,
title='Binned timetrace of emitted ph (bin = t_step)'
' - particle_%d' % particle)
Каждая «таблица» подсчета частиц имеет другое имя (name = "particle_%d" % ip
), и мне нужно поместить их в список Python для упрощения итерации.
РЕДАКТИРОВАТЬ. Результатом этого вопроса является симулятор броуновского движения под названием PyBroMo.
emission
является результатом функции, вычисленной на траекториях частиц (трехмерное броуновское движение). Траектории представляют собой полные массивы, но отбрасываются после расчета выбросов. Выбросы в большинстве случаев небольшие (но не 0). Это приводит к тому, что значениеcounts
в большинстве случаев равно 0. В принципе, я мог бы хранить толькоtimestamps
, то есть индекс гдеcounts > 0
. Ноcounts
не умещается в оперативной памяти, поэтому индекс нужно искать по частям (что требует некоторой арифметики индекса). Но да, это возможный способ, если окажется, что хранениеcounts
слишком дорого. - person user2304916   schedule 07.01.2014