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()