Мне дали короткий 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). Новый код и DS9 будут работать всю ночь при подаче фокусирующих изображений 6,5 МБ. Но после загрузки первых двух полноразмерных образов размером 85 МБ DS9 блокируется и требует «kill -9», чтобы избавиться от него.
Версии OS, xpa и DS9 совпадают, предполагая, что ошибка лежит в моем сценарии. Сложность в ожидании процесса, который записывает файлы FITS в fini sh и закрывает файлы.
В интересах краткости, я надеюсь, что причина замораживания 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