Проблемы с получением данных из нескольких файлов * .root ... но без проблем, используя только один - PullRequest
1 голос
/ 01 ноября 2019

Я использую Pythong версии 3.6.5 и имею зубчатое TTree с многомерной структурой. Эти данные распределены по более чем 1000 файлам с одинаковой структурой TTree.

предположим, что у меня есть два файла, и я назову их fname1.root fname2.root

Следующий код не вызывает проблем при открытии любого из них сам по себе:

import uproot as upr
import awkward
import boost_histogram as bh
import math
import matplotlib.pyplot as plt
#
# define a plotting program
# def plotter(h)
#
# preparing the file location for files
pth = '/fullpathName/'
fname1 = 'File755.root'
fname2 = 'File756.root'
fileList = [pth+fname1, pth+fname2]
#
# print out the path and filename that I've made to show the user
for file in fileList:
    print(file)
print('\n')
#
# Let's make a histogram This one has 50 bins, starts at zero and ends at 1000.0
# It will be a histogram of Jet pT's. 
jhist = bh.histogram(bh.axis.regular(50,0.0,1000.0))
#
#show what you've just done
print(jhist)
#
# does not work, only fills first file!
for chunk in upr.iterate(fileList,"bTag_AntiKt4EMTopoJets",["jet_pt"]):
    jhist.fill(chunk[b"jet_pt"][:, :2].flatten()*0.001)
#
#
# what does my histogram look like?
ptHist = plt.bar(jhist.axes[0].centers, jhist.view(), width=jhist.axes[0].widths)
plt.show()

Как я уже сказал, приведенный выше код работает, если я помещаю в файл fileList только ОДИН файл.

Наивное действие не работает. Если я создаю «список» файлов с помощью

files = [pth+fname1 , pth+fname2]

и перезапускаю этот код. Я получаю следующую ошибку ... которая очень похожа на ту, что я получал все время.

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 48, in <module>
  File "/home/huffman/.local/lib/python3.6/site-packages/uproot/tree.py", line 116, in iterate
    for tree, branchesinterp, globalentrystart, thispath, thisfile in _iterate(path, treepath, branches, awkward, localsource, xrootdsource, httpsource, **options):
  File "/home/huffman/.local/lib/python3.6/site-packages/uproot/tree.py", line 163, in _iterate
    file = uproot.rootio.open(path, localsource=localsource, xrootdsource=xrootdsource, httpsource=httpsource, **options)
  File "/home/huffman/.local/lib/python3.6/site-packages/uproot/rootio.py", line 54, in open
    return ROOTDirectory.read(openfcn(path), **options)
  File "/home/huffman/.local/lib/python3.6/site-packages/uproot/rootio.py", line 51, in <lambda>
    openfcn = lambda path: MemmapSource(path, **kwargs)
  File "/home/huffman/.local/lib/python3.6/site-packages/uproot/source/memmap.py", line 21, in __init__
    self._source = numpy.memmap(self.path, dtype=numpy.uint8, mode="r")
  File "/cvmfs/sft.cern.ch/lcg/views/LCG_94python3/x86_64-slc6-gcc8-opt/lib/python3.6/site-packages/numpy/core/memmap.py", line 264, in __new__
    mm = mmap.mmap(fid.fileno(), bytes, access=acc, offset=start)
OSError: [Errno 12] Cannot allocate memory

1 Ответ

0 голосов
/ 01 ноября 2019

Ленивые массивы - это просто интерфейс для удобства, т. Е. Вы можете преобразовать его с помощью одного вызова функции, а не выполнять итерации в явном цикле по фрагментам. Внутренне, ленивые массивы содержат неявный цикл над кусками, поэтому, если у вас не хватает памяти одним способом, у вас будет другой путь.

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

Здесь вы можете сделать несколько вещей: одно из них -

for chunk in uproot.iterate(files, "bTag_AntiKt4EMTopoJets", ["jet_pt", "jet_eta"]):
    # fill with chunk[b"jet_pt"] and chunk[b"jet_eta"], which correspond
    # to the same sets of events, one-to-one.

, чтобы явно зациклить чанки ("явный", потому что вы видите и управляете циклом здесь, и потому что вы должны указать, какие ветви вы хотите загрузить в dict chunk). Вы можете контролировать размер кусков с помощью entrysteps. Другой -

cache = uproot.ArrayCache("1 GB")
events = uproot.lazyarrays(files, "bTag_AntiKt4EMTopoJets", cache=cache)

, чтобы сохранить цикл неявным. ArrayCache будет выбрасывать куски массивов, поэтому их придется загружать снова, если он достигнет предела в 1 ГБ. Если вы сделаете этот лимит слишком маленьким, он не сможет удержать один чанк, но если вы сделаете его слишком большим, вам не хватит памяти.

Кстати, хотя вы сообщаетепроблема с памятью, есть еще одна серьезная проблема с производительностью вашего кода: вы просматриваете события в Python. Вместо

events.jet_pt[i][:2]*0.001

для получения струи pT для события i, сделайте

events.jet_pt[:, :2]*0.001

для струи pT всех событий как единого массива. Затем вам может понадобиться .flatten() этот массив, чтобы соответствовать методу fill гистограммы.

...