我得到了一个简短的 Python 2.7 脚本,它监视新的 FITS 文件放入目录中,使用 XPA 命令 DS9 8.0.1(Fedora 30,xpa-devel.x86_64 2.1.18-7.f30)的实例一次显示两个帧。
原始脚本使用一系列Popen()
命令启动xpaset
以格式化 DS9 窗口并指示要加载的文件。该代码已有十年之久,如果没有它和/或 DS9 崩溃/冻结,则无法通过一夜的观察,部分原因是网络延迟影响了 XPA。
我使用 Python 3.7 和 pyds9 (pyds9.noarch 1.8.1-3.2) 从头开始重新实现了脚本。当输入 6.5MB 聚焦图像时,新代码和 DS9 将运行一整夜。但是,在加载前两个全尺寸 85MB 图像后,DS9 锁定并需要“kill -9”才能摆脱它。
操作系统、xpa 和 DS9 版本相同,这表明错误出在我的脚本中。复杂情况一直在等待写入 FITS 文件的进程完成并关闭文件。
为简洁起见,我希望 DS9 在使用 pyds9 时冻结的原因从下面的精简样本中可以明显看出。否则,我将对其进行编辑以包含功能代码。
编辑:针对@Iguananaut 的评论,我整合了 DS9 启动等待时间,并将新文件搜索和 wait_til_file_is_stable 函数添加到较新的代码示例中。
原始的基于 Popen() 的指令:
#!/bin/env python
from subprocess import Popen
from time import sleep
import uuid
new_fits_filename = ""
old_fits_filename = ""
display_id='This_Script-' + uuid.uuid4().hex[:6].upper()
ds9_pid = Popen(['ds9','-geometry','940x1200','-title',display_id]).pid
if Popen(['xpaget',display_id,'blink'],stdout=DEVNULL,stderr=DEVNULL).wait() == 0:
break
sleep(.5)
Popen(['xpaset','-p',display_id,'scale','mode','zscale'])
Popen(['xpaset','-p',display_id,'frame','1'])
Popen(['xpaset','-p',display_id,'cmap','cool'])
Popen(['xpaset','-p',display_id,'frame','2'])
Popen(['xpaset','-p',display_id,'cmap','bb'])
Popen(['xpaset','-p',display_id,'tile'])
while True:
[detect new FITS file in NFS target directory]
Popen(['xpaset','-p',display_id,'frame','1'])
Popen(['xpaset','-p',display_id,'file','mosaicimage','wcs',directory+'/'+new_fits_filename])
sleep(1) # Sleep again to avoid DS9 crashing
Popen(['xpaset','-p',display_id,'zoom','to','fit'])
if old_fits_filename != "":
Popen(['xpaset','-p',display_id,'frame','2'])
Popen(['xpaset','-p',display_id ,'file','mosaicimage','wcs',directory+ '/'+ old_fits_filename])
sleep(1) # Sleep again to avoid DS9 crashing
Popen(['xpaset','-p',display_id,'zoom','to','fit'])
old_fits_filename = new_fits_filename
新的基于 pyds9 的指令:
#!/bin/env python3
import glob
import os
from pathlib import Path
import pyds9
from time import sleep
import uuid
def wait_til_file_is_stable(filename):
the_file = Path(filename)
the_current_size = 0
the_previous_size = -1
while the_current_size != the_previous_size:
the_previous_size = the_current_size
the_current_size = the_file.stat().st_size
sleep(0.5)
global_d = None
fits_folder = Path("/data/fits/new/") # an NFS mount
fits_file_prefix = "image"
fits_file_pattern = fits_file_prefix + "*.fits"
fits_full_path = str(fits_folder.resolve() / fits_file_pattern)
new_fits_filename = ""
old_fits_filename = ""
wait_time_launch = 70
display_id = 'This_Script-' + uuid.uuid4().hex[:6].upper()
global_d = pyds9.DS9(display_id, start="-geometry 940x1200", wait=wait_time_launch, verify=True)
global_d.set('scale mode zscale')
global_d.set('frame 1')
global_d.set('cmap cool')
global_d.set('frame 2')
global_d.set('cmap bb')
global_d.set('tile')
while True:
sleep(0.5)
# detect new FITS file in NFS target directory
dirlisting = glob.glob(fits_full_path)
if len(dirlisting) > 0:
new_fits_filename = max(filter(lambda fname: fits_file_prefix in fname, dirlisting), key=os.path.getctime)
wait_til_file_is_stable(new_fits_filename)
global_d.set('frame 1')
global_d.set('file mosaicimage wcs ' + str(new_fits_filename))
global_d.set('zoom to fit')
if old_fits_filename != "":
global_d.set('frame 2')
global_d.set('file mosaicimage wcs ' + str(old_fits_filename))
global_d.set('zoom to fit')
old_fits_filename = new_fits_filename