首页 > 解决方案 > 使用 Astropy 打开 FITS 时出现 OSError 24

问题描述

首先,我已经阅读了以下内容:

还有一些来自第一个的链接,但没有一个有效......

我的问题是在 Jupyter Notebook 中打开巨大的 (>80 Mb/pc.) 和大量 (~3000) FITS 文件。相关代码片段如下:

# Dictionary to store NxN data matrices of cropped image tiles
CroppedObjects = {}

# Defining some other, here used variable....
# ...

# Interate over all images ('j'), which contain the current object, indexed by 'i'
for i in range(0, len(finalObjects)):
    for j in range(0, len(containingImages[containedObj[i]])):

        countImages += 1

        # Path to the current image: 'mnt/...'
        current_image_path = ImagePaths[int(containingImages[containedObj[i]][j])]

        # Open .fits images
        with fits.open(current_image_path, memmap=False) as hdul:
            # Collect image data
            image_data = fits.getdata(current_image_path)

            # Collect WCS data from the current .fits's header
            ImageWCS = wcs.WCS(hdul[1].header)

            # Cropping parameters:
            # 1. Sky-coordinates of the croppable object
            # 2. Size of the crop, already defined above
            Coordinates = coordinates.SkyCoord(finalObjects[i][1]*u.deg,finalObjects[i][2]*u.deg, frame='fk5')
            size = (cropSize*u.pixel, cropSize*u.pixel)

            try:
                # Cut out the image tile
                cutout = Cutout2D(image_data, position=Coordinates, size=size, wcs=ImageWCS, mode='strict')

                # Write the cutout to a new FITS file
                cutout_filename = "Cropped_Images_Sorted/Cropped_" + str(containedObj[i]) + current_image_path[-23:]

                # Sava data to dictionary
                CroppedObjects[cutout_filename] = cutout.data

                foundImages += 1

            except:
                pass

            else:
                del image_data
                continue

        # Memory maintainance                
        gc.collect()

        # Progress bar
        sys.stdout.write("\rProgress: [{0}{1}] {2:.3f}%\tElapsed: {3}\tRemaining: {4}  {5}".format(u'\u2588' * int(countImages/allCrops * progressbar_width),
                                                                                                   u'\u2591' * (progressbar_width - int(countImages/allCrops * progressbar_width)),
                                                                                                   countImages/allCrops * 100,
                                                                                                   datetime.now()-starttime,
                                                                                                   (datetime.now()-starttime)/countImages * (allCrops - countImages),
                                                                                                   foundImages))

        sys.stdout.flush()

好吧,它实际上做了三件事:

  1. 打开特定的 FITS 文件
  2. 从中切出一个正方形(但是strict,如果数组仅部分重叠,则try语句跳转到循环中的下一步)
  3. 更新进度条

然后转到下一个文件,做同样的事情并遍历我所有的 FITS 文件。

但是:如果我尝试运行此代码,在找到大约 1000 张图片后,它会停止并给出并OSError: [Errno 24] Too many open files在线:

image_data = fits.getdata(current_image_path)

我尝试了所有应该解决问题的方法,但没有任何帮助...甚至没有将内存映射设置为false或使用fits.getdataand gc.collect()...还尝试了许多小的更改,例如在没有try语句的情况下运行,切掉所有图像图块,没有任何限制。delelse语句里面也是我的又一次惨痛尝试。我还能尝试什么来使它最终起作用?
另外,如果有不清楚的地方,请随时问我!我也会尽力帮助你理解问题!

标签: pythonjupyter-notebookastropyfits

解决方案


我过去也遇到过类似的问题(请参阅此处)。最后我让它大致像这样工作:

total = 0
for filename in filenames:
    with fits.open(filename, memmap=False) as hdulist:
        data = hdulist['spam'].data
    total += data.sum()

一些注意事项:

  • 用于fits.open打开文件,使用memmap=False
  • 在 with 块中使用它,以使文件关闭可靠
  • 保持 with 块简短,只需将您需要的数据加载到内存中,然后通过退出来关闭文件
  • 关闭文件后对数据执行您需要执行的操作;这可能并不真正需要,但如果 Python 对文件中数据的引用是阻止它被关闭的问题,这可以简化情况。我不认为剪切代码是您示例中的问题,但它可能是 - 尝试取消注释它?
  • 不要做额外的事情fits.getdata,我认为会再次打开文件
  • 并且不应该是必需的delgc.collect如果代码按照这里建议的那样简单,就不会有循环引用,Python 将可靠地删除作用域末尾的对象

现在这可能无济于事,您仍然会遇到问题。在这种情况下,继续进行的方法是制作一个对 Astropy 开发人员可以运行的对您不起作用的最小可重复示例(就像我在这里所做的那样),然后向 Astropy 提出问题,提供您的 Python 版本,Astropy 版本和操作系统,或在此处发布。关键是:这很复杂,并且可能取决于运行时/版本,因此需要尝试确定任何人都可以运行的示例,但对您来说失败了。


推荐阅读