Files
SwissMX/detector.py

281 lines
8.9 KiB
Python

import logging
_log=logging.getLogger(__name__)
#from glob import glob
from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot
#import eventer
#import qsingleton
#from detector_integration_api import DetectorIntegrationClient
#from app_config import settings, appsconf, simulated
#config = appsconf['jungfrau']
#dia_client = DetectorIntegrationClient(config['uri'])
class JungfrauWaiter(QObject):
finished = pyqtSignal()
def __init__(self):
super().__init__()
@pyqtSlot()
def work(self):
pass
class JungfrauMissingConfiguration(Exception):
pass
class Jungfrau(QObject):
pedestal_selected = pyqtSignal(str)
configured = pyqtSignal()
armed = pyqtSignal()
started = pyqtSignal()
triggered = pyqtSignal()
aborted = pyqtSignal()
def __init__(self, parent=None, **kwargs):
super(Jungfrau, self).__init__(parent, **kwargs)
self._save_raw = True
self._runJungfrau = False
self._number_of_frames = 1
#self._gain_maps = config["gain_maps"]
self._uid = None
#self._serial_number = config['serialnr']
self.writer_config = {}
self.backend_config = {}
self.detector_config = {}
self.bsread_config = {}
@pyqtSlot(bool)
def set_run_jungfrau(self, run):
"""running or not jungfrau, global simulated flag overrides"""
_log.warning(f"{'' if run else 'not '}running jungfrau detector")
if not self._simulated:
self._runJungfrau = run
else:
self._runJungfrau = False
@pyqtSlot(bool)
def set_save_raw(self, save_raw):
"""enable or not writer_config"""
_log.warning(f"{'' if save_raw else 'not '}saving data")
self._save_raw = save_raw
@pyqtSlot(str)
def set_detector_serial(self, serial_number):
"""set serial number for main detector"""
_log.info(f"jungfrau serial number: {serial_number}")
self._serial_number = serial_number
def is_saving_data(self):
"""if False writer_config is not issued"""
return self._save_raw
def is_running_detector(self):
"""if False nothing is actually called"""
return self._runJungfrau
@pyqtSlot(int)
def set_number_of_frames(self, frames):
_log.info(f"jungfrau number of frames: {frames}")
self._number_of_frames = frames
@pyqtSlot(int)
def set_data_owner_uid(self, uid):
_log.info(f"data owner set to UID = {uid}")
self._uid = uid
@pyqtSlot(str)
def set_gain_filename(self, gainfile:str):
_log.info(f"gain file: {gainfile}")
self._gain_maps = gainfile
def configure(self, outfile=None, outdir=None, **kwargs):
if not self._runJungfrau:
_log.warning("jungfrau not required: configure dismissed")
return
if self._gain_maps is None:
raise JungfrauMissingConfiguration("missing gain maps filename")
gain_filename = self._gain_maps
if self._uid is None:
raise JungfrauMissingConfiguration("missing data owner p-group UID")
uid = self._uid
n_frames = self._number_of_frames
pede_pattern = "/sf/bernina/data/p{}/res/JF_pedestals/pedestal_*.JF07T32V01.res.h5".format(
uid
)
try:
pf = sorted(glob(pede_pattern))[-1]
pf = pf[: pf.index(".JF07T32V01")]
except IndexError:
pf = None
pede_filename = pf
_log.info(f"Pedestal file {pede_filename}")
exptime = 0.000005
instrument = "Bernina"
self.writer_config = {
"output_file": outdir + "/" + outfile,
"user_id": uid,
"n_frames": n_frames,
"general/user": str(uid),
"general/process": __name__,
"general/created": str(datetime.now()),
"general/instrument": instrument,
}
if not self._save_raw:
self.writer_config["output_file"] = "/dev/null"
self.detector_config = {
"exptime": exptime,
"frames": 1,
"cycles": n_frames,
"timing": "trigger",
"dr": 16,
}
self.backend_config = {
"n_frames": n_frames,
"bit_depth": 16,
"run_name": outfile,
"beam_center_x": 2110.0,
"beam_center_y": 2210.0,
"beam_energy": 6000.0,
"detector_distance": 0.06,
"hitfinder_min_snr": 6.0,
"hitfinder_min_pix_count": 5,
"hitfinder_adc_thresh": 20.0,
"swissmx_trajectory_method": "grid",
"swissmx_trajectory_details_1": [100],
"swissmx_trajectory_details_2": [n_frames // 100 + 1],
}
backend_extras = kwargs.get("backend_extras", None)
if backend_extras:
self.backend_config.update(backend_extras)
# """
# "swissmx_trajectory_method": "grid",
# "swissmx_trajectory_details_1": [100],
# "swissmx_trajectory_details_2": [n_frames//100+1],
#
# "swissmx_trajectory_method": "rotation",
# "swissmx_trajectory_details_1": [360],
# "swissmx_trajectory_details_2": [0.1],
#
# "swissmx_trajectory_method": "trajectory",
# "swissmx_trajectory_details_1": [random()*100 for i in range(int(n_frames*0.9))],
# "swissmx_trajectory_details_2": [random()*100 for i in range(int(n_frames*0.9))],
#
# """
self.bsread_config = {
"output_file": outdir + "/" + outfile,
"user_id": uid,
"general/user": str(uid),
"general/process": __name__,
"general/created": str(datetime.now()),
"general/instrument": instrument,
}
if gain_filename != "" or pede_filename != "":
self.backend_config["gain_corrections_filename"] = gain_filename
self.backend_config["gain_corrections_dataset"] = "gains"
self.backend_config["pede_corrections_filename"] = pede_filename
self.backend_config["pede_corrections_dataset"] = "gains"
self.backend_config["pede_mask_dataset"] = "pixel_mask"
self.backend_config["activate_corrections_preview"] = True
_log.info("Corrections in online viewer activated")
configuration = {
"writer": self.writer_config,
"backend": self.backend_config,
"detector": self.detector_config,
"bsread": self.bsread_config,
}
_log.info("resetting & configuring detector: approx. 6 seconds")
dia_client.reset()
dia_client.set_config(configuration)
_log.info(dia_client.get_config())
def arm(self) -> int:
"""arm detector and return an ID for this series"""
if not self._runJungfrau:
_log.warning("jungfrau not required: arm dismissed")
return
_log.info("arming detector: approx. 2 seconds")
dia_client.start(trigger_start=False)
def wait_finished(self):
"""close shutter after this wait is finished regardless of exceptions"""
if not self._runJungfrau:
_log.warning("jungfrau not required: wait_finished dismissed")
return
try:
dia_client.wait_for_status(["IntegrationStatus.FINISHED"], polling_interval=0.1)
except:
_log.info("Got IntegrationStatus ERROR")
_log.info(dia_client.get_status())
_log.info(dia_client.get_status_details())
_log.info("Stopping acquisition")
dia_client.reset()
_log.info("Done")
def disarm(self) -> int:
"""arm detector and return an ID for this series"""
if not self._runJungfrau:
_log.warning("jungfrau not required: disarm dismissed")
return
dia_client.reset()
def trigger(self):
if not self._runJungfrau:
_log.warning("jungfrau not required: trigger dismissed")
return
_log.info("Trigger in detector is called")
eventer.start()
def abort(self):
if not self._runJungfrau:
_log.warning("jungfrau not required: abort dismissed")
return
self.disarm()
eventer.stop()
if __name__=='__main__':
def main():
jungfrau_detector = Jungfrau()
import argparse
from datetime import datetime
date_string = datetime.now().strftime("%Y%m%d_%H%M")
parser = argparse.ArgumentParser(description="Create a pedestal file for Jungrau")
parser.add_argument("--api", default="http://sf-daq-1:10000", required=True)
parser.add_argument("--filename", default="run_%s.h5" % date_string, help="Output file name")
parser.add_argument("--pede", default="", help="File containing pedestal corrections")
parser.add_argument("--gain", default="", help="File containing gain corrections")
parser.add_argument("--directory", default="/sf/bernina/data/raw/p16582", help="Output directory")
parser.add_argument("--uid", default=16582, help="User ID which needs to own the file", type=int)
parser.add_argument("--period", default=0.01, help="Period (default is 10Hz - 0.01)", type=float)
parser.add_argument("--exptime",default=0.000010,help="Integration time (default 0.000010 - 10us)",type=float,)
parser.add_argument("--frames", default=10, help="Number of frames to take", type=int)
parser.add_argument("--save", default=False, help="Save data file", action="store_true")
parser.add_argument("--highgain", default=False, help="Enable High Gain (HG0)", action="store_true")
parser.add_argument("--instrument", default="", help="Name of the instrument, e.g. Alvra")
# parser.add_argument("--caput", default=False, help="Use the CAPUT trick (experts only!!!)", action="store_true")
args = parser.parse_args()
main()