diff --git a/src/mx_bluesky/beamlines/i24/serial/dcid.py b/src/mx_bluesky/beamlines/i24/serial/dcid.py index a5784ecc8..79d1c2c70 100644 --- a/src/mx_bluesky/beamlines/i24/serial/dcid.py +++ b/src/mx_bluesky/beamlines/i24/serial/dcid.py @@ -1,6 +1,5 @@ import datetime import json -import logging import math import os import re @@ -10,6 +9,7 @@ import requests +from mx_bluesky.beamlines.i24.serial.log import SSX_LOGGER from mx_bluesky.beamlines.i24.serial.parameters import SSXType from mx_bluesky.beamlines.i24.serial.setup_beamline import ( Detector, @@ -25,8 +25,6 @@ except ImportError: pass -logger = logging.getLogger("I24ssx.DCID") - # Collection start/end script to kick off analysis COLLECTION_START_SCRIPT = "/dls_sw/i24/scripts/RunAtStartOfCollect-i24-ssx.sh" @@ -41,7 +39,7 @@ def get_auth_header() -> dict: """Read the credentials file and build the Authorisation header""" if not os.path.isfile(CREDENTIALS_LOCATION): - logger.warning( + SSX_LOGGER.warning( "Could not read %s; attempting to proceed without credentials", CREDENTIALS_LOCATION, ) @@ -205,12 +203,12 @@ def generate_dcid( # Log what we are doing here try: - logger.info( + SSX_LOGGER.info( "BRIDGE: POST /dc --data %s", repr(json.dumps(data)), ) except Exception: - logger.info( + SSX_LOGGER.info( "Caught exception converting data to JSON. Data:\n%s\nVERBOSE:\n%s", str({k: type(v) for k, v in data.items()}), ) @@ -224,20 +222,20 @@ def generate_dcid( ) resp.raise_for_status() self.dcid = resp.json()["dataCollectionId"] - logger.info("Generated DCID %s", self.dcid) + SSX_LOGGER.info("Generated DCID %s", self.dcid) except requests.HTTPError as e: self.error = True - logger.error( + SSX_LOGGER.error( "DCID generation Failed; Reason from server: %s", e.response.text ) if self.emit_errors: raise - logger.exception("Error generating DCID: %s", e) + SSX_LOGGER.exception("Error generating DCID: %s", e) except Exception as e: self.error = True if self.emit_errors: raise - logger.exception("Error generating DCID: %s", e) + SSX_LOGGER.exception("Error generating DCID: %s", e) def __int__(self): return self.dcid @@ -248,13 +246,13 @@ def notify_start(self): return None try: command = [COLLECTION_START_SCRIPT, str(self.dcid)] - logger.info("Running %s", " ".join(command)) + SSX_LOGGER.info("Running %s", " ".join(command)) subprocess.Popen(command) except Exception as e: self.error = True if self.emit_errors: raise - logger.warning("Error starting start of collect script: %s", e) + SSX_LOGGER.warning("Error starting start of collect script: %s", e) def notify_end(self): """Send notifications that the collection has now ended""" @@ -262,13 +260,13 @@ def notify_end(self): return try: command = [COLLECTION_END_SCRIPT, str(self.dcid)] - logger.info("Running %s", " ".join(command)) + SSX_LOGGER.info("Running %s", " ".join(command)) subprocess.Popen(command) except Exception as e: self.error = True if self.emit_errors: raise - logger.warning("Error running end of collect notification: %s", e) + SSX_LOGGER.warning("Error running end of collect notification: %s", e) def collection_complete( self, end_time: str | datetime.datetime | None = None, aborted: bool = False @@ -285,7 +283,7 @@ def collection_complete( # end_time might be a string from time.ctime if isinstance(end_time, str): end_time = datetime.datetime.strptime(end_time, "%a %b %d %H:%M:%S %Y") - logger.debug("Parsed end time: %s", end_time) + SSX_LOGGER.debug("Parsed end time: %s", end_time) if not end_time: end_time = datetime.datetime.now().astimezone() @@ -302,13 +300,13 @@ def collection_complete( if self.dcid is None: # Print what we would have sent. This means that if something is failing, # we still have the data to upload in the log files. - logger.info( + SSX_LOGGER.info( 'BRIDGE: No DCID but Would PATCH "/dc/XXXX" --data=%s', repr(json.dumps(data)), ) return - logger.info( + SSX_LOGGER.info( 'BRIDGE: PATCH "/dc/%s" --data=%s', self.dcid, repr(json.dumps(data)) ) response = requests.patch( @@ -318,7 +316,7 @@ def collection_complete( headers=get_auth_header(), ) response.raise_for_status() - logger.info("Successfully updated end time for DCID %d", self.dcid) + SSX_LOGGER.info("Successfully updated end time for DCID %d", self.dcid) except Exception as e: resp_obj = getattr(e, "response", None) try: @@ -333,7 +331,7 @@ def collection_complete( self.error = True if self.emit_errors: raise - logger.warning("Error completing DCID: %s (%s)", e, resp_str) + SSX_LOGGER.warning("Error completing DCID: %s (%s)", e, resp_str) def get_pilatus_filename_template_from_pvs() -> str: @@ -385,9 +383,9 @@ def get_beamsize() -> tuple[float | None, float | None]: h_mode = caget("BL24I-OP-MFM-01:G1:TARGETAPPLY") # Validate these and note an error otherwise if not v_mode.startswith("VMFM") or v_mode[4:] not in focus_modes: - logger.error("Unrecognised vertical beam mode %s", v_mode) + SSX_LOGGER.error("Unrecognised vertical beam mode %s", v_mode) if not h_mode.startswith("HMFM") or h_mode[4:] not in focus_modes: - logger.error("Unrecognised horizontal beam mode %s", h_mode) + SSX_LOGGER.error("Unrecognised horizontal beam mode %s", h_mode) _, h, _ = focus_modes.get(h_mode[4:], (None, None, None)) _, _, v = focus_modes.get(v_mode[4:], (None, None, None)) diff --git a/src/mx_bluesky/beamlines/i24/serial/extruder/i24ssx_Extruder_Collect_py3v2.py b/src/mx_bluesky/beamlines/i24/serial/extruder/i24ssx_Extruder_Collect_py3v2.py index 51ba7b333..754fa72d9 100755 --- a/src/mx_bluesky/beamlines/i24/serial/extruder/i24ssx_Extruder_Collect_py3v2.py +++ b/src/mx_bluesky/beamlines/i24/serial/extruder/i24ssx_Extruder_Collect_py3v2.py @@ -262,7 +262,7 @@ def main_extruder_plan( SSX_LOGGER.info("Using Eiger detector") SSX_LOGGER.debug(f"Creating the directory for the collection in {filepath}.") - Path(filepath).mkdir(parents=True) + Path(filepath).mkdir(parents=True, exist_ok=True) caput(pv.eiger_seqID, int(caget(pv.eiger_seqID)) + 1) SSX_LOGGER.info(f"Eiger quickshot setup: filepath {filepath}") diff --git a/src/mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py b/src/mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py index 5c268bd51..a402721ce 100755 --- a/src/mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py +++ b/src/mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py @@ -77,7 +77,7 @@ def calculate_collection_timeout(parameters: FixedTargetParameters) -> float: Returns: The estimated collection time, in s. """ - buffer = PMAC_MOVE_TIME * parameters.total_num_images + 2 + buffer = PMAC_MOVE_TIME * parameters.total_num_images + 600 pump_setting = parameters.pump_repeat collection_time = parameters.total_num_images * parameters.exposure_time_s if pump_setting in [ @@ -97,7 +97,7 @@ def calculate_collection_timeout(parameters: FixedTargetParameters) -> float: ) if pump_setting == PumpProbeSetting.Medium1: # Long delay between pump and probe, with fast shutter opening and closing. - timeout = timeout + SHUTTER_OPEN_TIME + timeout = timeout + SHUTTER_OPEN_TIME * parameters.total_num_images return timeout @@ -426,7 +426,11 @@ def start_i24( ) SSX_LOGGER.debug("Arm Pilatus. Arm Zebra.") - shutter_time_offset = SHUTTER_OPEN_TIME if PumpProbeSetting.Medium1 else 0.0 + shutter_time_offset = ( + SHUTTER_OPEN_TIME + if parameters.pump_repeat is PumpProbeSetting.Medium1 + else 0.0 + ) yield from setup_zebra_for_fastchip_plan( zebra, parameters.detector_name, @@ -449,7 +453,7 @@ def start_i24( SSX_LOGGER.info("Using Eiger detector") SSX_LOGGER.debug(f"Creating the directory for the collection in {filepath}.") - Path(filepath).mkdir(parents=True) + Path(filepath).mkdir(parents=True, exist_ok=True) SSX_LOGGER.info(f"Triggered Eiger setup: filepath {filepath}") SSX_LOGGER.info(f"Triggered Eiger setup: filename {filename}") @@ -485,7 +489,11 @@ def start_i24( ) SSX_LOGGER.debug("Arm Zebra.") - shutter_time_offset = SHUTTER_OPEN_TIME if PumpProbeSetting.Medium1 else 0.0 + shutter_time_offset = ( + SHUTTER_OPEN_TIME + if parameters.pump_repeat is PumpProbeSetting.Medium1 + else 0.0 + ) yield from setup_zebra_for_fastchip_plan( zebra, parameters.detector_name, diff --git a/src/mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Manager_py3v1.py b/src/mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Manager_py3v1.py index b3d7cbff7..064f3efbd 100755 --- a/src/mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Manager_py3v1.py +++ b/src/mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Manager_py3v1.py @@ -93,6 +93,9 @@ def initialise_stages( sleep(0.1) SSX_LOGGER.info("Clearing General Purpose PVs 1-120") for i in range(4, 120): + if i == 100: + # Do not clear visit PV + continue pvar = "ME14E-MO-IOC-01:GP" + str(i) caput(pvar, 0) sys.stdout.write(".") @@ -840,13 +843,13 @@ def check_dir(val): sleep(2.5) yield from set_pmac_strings_for_cs(pmac, {"cs1": cs1, "cs2": cs2, "cs3": cs3}) yield from bps.trigger(pmac.to_xyz_zero) - sleep(0.1) + sleep(2.5) yield from bps.trigger(pmac.home, wait=True) - sleep(0.1) + sleep(2.5) SSX_LOGGER.debug(f"Chip_type is {chip_type}") if chip_type == 0: yield from bps.abs_set(pmac.pmac_string, "!x0.4y0.4", wait=True) - sleep(0.1) + sleep(2.5) yield from bps.trigger(pmac.home, wait=True) else: yield from bps.trigger(pmac.home, wait=True) diff --git a/src/mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_moveonclick.py b/src/mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_moveonclick.py index bff884347..97d7f01b4 100755 --- a/src/mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_moveonclick.py +++ b/src/mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_moveonclick.py @@ -3,7 +3,6 @@ Robin Owen 12 Jan 2021 """ -import logging from collections.abc import Sequence import bluesky.plan_stubs as bps @@ -17,10 +16,9 @@ i24ssx_Chip_Manager_py3v1 as manager, ) from mx_bluesky.beamlines.i24.serial.fixed_target.ft_utils import Fiducials +from mx_bluesky.beamlines.i24.serial.log import SSX_LOGGER from mx_bluesky.beamlines.i24.serial.parameters.constants import OAV1_CAM -logger = logging.getLogger("I24ssx.moveonclick") - def _get_beam_centre(oav: OAV): """Extract the beam centre x/y positions from the display.configuration file. @@ -53,7 +51,7 @@ def _move_on_mouse_click_plan( x, y = clicked_position xmove = -1 * (beamX - x) * zoomcalibrator ymove = 1 * (beamY - y) * zoomcalibrator - logger.info(f"Moving X and Y {xmove} {ymove}") + SSX_LOGGER.info(f"Moving X and Y {xmove} {ymove}") xmovepmacstring = "#1J:" + str(xmove) ymovepmacstring = "#2J:" + str(ymove) yield from bps.abs_set(pmac.pmac_string, xmovepmacstring, wait=True) @@ -66,7 +64,7 @@ def onMouse(event, x, y, flags, param): RE = param[0] pmac = param[1] oav = param[2] - logger.info(f"Clicked X and Y {x} {y}") + SSX_LOGGER.info(f"Clicked X and Y {x} {y}") RE(_move_on_mouse_click_plan(oav, pmac, (x, y))) @@ -159,7 +157,7 @@ def start_viewer(oav: OAV, pmac: PMAC, RE: RunEngine, oav1: str = OAV1_CAM): cv.namedWindow("OAV1view") cv.setMouseCallback("OAV1view", onMouse, param=[RE, pmac, oav]) # type: ignore - logger.info("Showing camera feed. Press escape to close") + SSX_LOGGER.info("Showing camera feed. Press escape to close") # Read captured video and store them in success and frame success, frame = cap.read() diff --git a/src/mx_bluesky/beamlines/i24/serial/run_fixed_target.sh b/src/mx_bluesky/beamlines/i24/serial/run_fixed_target.sh index 285bd21f7..505c17612 100755 --- a/src/mx_bluesky/beamlines/i24/serial/run_fixed_target.sh +++ b/src/mx_bluesky/beamlines/i24/serial/run_fixed_target.sh @@ -15,12 +15,13 @@ edm_path=$1 # Export env variable for the stages edm to work properly export EDMDATAFILES="/dls_sw/prod/R3.14.12.3/support/motor/6-7-1dls14/motorApp/opi/edl" +# Get the directory of this script +current=$( realpath "$( dirname "$0" )" ) + + if [[ $NO_PROCESERV_TEST == true ]]; then echo "Start the blueapi sever" - # Get the directory of this script - current=$( realpath "$( dirname "$0" )" ) - # Run script to start blueapi serve . $current/start_blueapi.sh fi diff --git a/src/mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py b/src/mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py index 719b3c2c4..a9e2daa85 100644 --- a/src/mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py +++ b/src/mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py @@ -1,4 +1,3 @@ -import logging from time import sleep import bluesky.plan_stubs as bps @@ -7,11 +6,10 @@ from dodal.devices.i24.dual_backlight import BacklightPositions, DualBacklight from dodal.devices.i24.i24_detector_motion import DetectorMotion +from mx_bluesky.beamlines.i24.serial.log import SSX_LOGGER from mx_bluesky.beamlines.i24.serial.setup_beamline import pv from mx_bluesky.beamlines.i24.serial.setup_beamline.ca import caget, caput -logger = logging.getLogger("I24ssx.sup") - def setup_beamline_for_collection_plan( aperture: Aperture, @@ -20,7 +18,7 @@ def setup_beamline_for_collection_plan( group: str = "setup_beamline_collect", wait: bool = True, ): - logger.debug("Setup beamline: collect.") + SSX_LOGGER.debug("Setup beamline: collect.") yield from bps.abs_set(aperture.position, AperturePositions.IN, group=group) yield from bps.abs_set(backlight, BacklightPositions.OUT, group=group) yield from bps.sleep(3) # Not sure needed - to test @@ -38,8 +36,8 @@ def move_detector_stage_to_position_plan( detector_stage: DetectorMotion, detector_distance: float, ): - logger.debug("Setup beamline: moving detector stage.") - logger.debug( + SSX_LOGGER.debug("Setup beamline: moving detector stage.") + SSX_LOGGER.debug( f"Waiting for detector move. Detector distance: {detector_distance} mm." ) yield from bps.mv(detector_stage.z, detector_distance) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809 @@ -60,7 +58,7 @@ def modechange(action): caput(pv.fluo_trans, "OUT") caput(pv.cstrm_p1701, 0) caput(pv.cstrm_mp_select, "Out") - logger.debug("Pin Hand Mount Done") + SSX_LOGGER.debug("Pin Hand Mount Done") # Pin Room Tempreature Hand Mount elif action == "Pin_rt_hand_mount": @@ -75,7 +73,7 @@ def modechange(action): caput(pv.vgon_pinxs, 0) caput(pv.vgon_pinzs, 0) caput(pv.fluo_trans, "OUT") - logger.debug("RT Pin Hand Mount Done") + SSX_LOGGER.debug("RT Pin Hand Mount Done") # Pin Data Collection elif action == "Pin_data_collection": @@ -94,11 +92,11 @@ def modechange(action): caput(pv.bs_mp_select, "Data Collection") sleep(2.3) caput(pv.bl_mp_select, "In") - logger.debug("Pin Data Collection Done") + SSX_LOGGER.debug("Pin Data Collection Done") # Pin Room Tempreature Data Collection elif action == "Pin_rt_data_collection": - logger.debug("RT Mode") + SSX_LOGGER.debug("RT Mode") caput(pv.cstrm_p1701, 0) caput(pv.cstrm_mp_select, "Away") caput(pv.aptr1_mp_select, "In") @@ -114,7 +112,7 @@ def modechange(action): sleep(2.6) caput(pv.bl_mp_select, "In") caput(pv.bs_mp_select, "Data Collection") - logger.debug("RT Data Collection Done") + SSX_LOGGER.debug("RT Data Collection Done") # Tray Hand Mount elif action == "Tray_hand_mount": @@ -128,7 +126,7 @@ def modechange(action): caput(pv.bs_mp_select, "Tray Mount") while float(caget(pv.ttab_x + ".RBV")) > 3: sleep(1) - logger.debug("Tray Hand Mount Done") + SSX_LOGGER.debug("Tray Hand Mount Done") # Tray Robot Load. This action needs to be reviewed and revised elif action == "Tray_robot_load": @@ -150,11 +148,11 @@ def modechange(action): caput(pv.bs_roty, 0) sleep(4) caput(pv.bl_mp_select, "In") - logger.debug("Tray Robot Mount Done") + SSX_LOGGER.debug("Tray Robot Mount Done") # Tray Data Collection elif action == "Tray_data_collection": - logger.debug("This should be E11 on the test tray (CrystalQuickX)") + SSX_LOGGER.debug("This should be E11 on the test tray (CrystalQuickX)") caput(pv.ttab_x, 37.4) caput(pv.hgon_trayys, -8.0) caput(pv.hgon_trayzs, -2.1) @@ -171,7 +169,7 @@ def modechange(action): caput(pv.bs_roty, 0) sleep(4) caput(pv.bl_mp_select, "In") - logger.debug("Tray Data Collection Done") + SSX_LOGGER.debug("Tray Data Collection Done") # Pin Switch to Tray elif action == "Pin_switch2tray": @@ -192,19 +190,19 @@ def modechange(action): caput(pv.vgon_pinyh, 0) caput(pv.vgon_pinzs, 0) while float(caget(pv.ttab_x + ".RBV")) > 1: - logger.debug(f"moving ttab_x {caget(pv.ttab_x)}") + SSX_LOGGER.debug(f"moving ttab_x {caget(pv.ttab_x)}") sleep(0.1) while caget(pv.fluo_out_limit) == "OFF": - logger.debug("waiting on fluorescence detector") + SSX_LOGGER.debug("waiting on fluorescence detector") sleep(0.1) while caget(pv.bl_mp_select) != "Out": - logger.debug("waiting on back light to move to out") + SSX_LOGGER.debug("waiting on back light to move to out") sleep(0.1) caput(pv.bs_mp_select, "Robot") caput(pv.bs_roty, 0) while float(caget(pv.ptab_y + ".RBV")) > -89.0: sleep(1) - logger.debug("Switch To Tray Done") + SSX_LOGGER.debug("Switch To Tray Done") # Tray Switch to Pin elif action == "Tray_switch2pin": @@ -218,26 +216,26 @@ def modechange(action): while float(caget(pv.ptab_y + ".RBV")) < -1.0: sleep(1) modechange("Pin_data_collection") - logger.debug("Switch To Pin Done") + SSX_LOGGER.debug("Switch To Pin Done") else: - logger.debug(f"Unknown action: {action}") + SSX_LOGGER.debug(f"Unknown action: {action}") return 1 def pilatus(action, args_list): - logger.debug("***** Entering Pilatus") - logger.info(f"Setup pilatus - {action}") + SSX_LOGGER.debug("***** Entering Pilatus") + SSX_LOGGER.info(f"Setup pilatus - {action}") if args_list: for arg in args_list: - logger.debug(f"Argument: {arg}") + SSX_LOGGER.debug(f"Argument: {arg}") # caput(pv.pilat_wavelength, caget(pv.dcm_lambda)) caput(pv.pilat_detdist, caget(pv.det_z)) caput(pv.pilat_filtertrasm, caget(pv.attn_match)) - logger.warning("WARNING: Have you set beam X and Y?") + SSX_LOGGER.warning("WARNING: Have you set beam X and Y?") # 16 Fed 2022 last change DA - caput(pv.pilat_beamx, 1298) - caput(pv.pilat_beamy, 1307) + caput(pv.pilat_beamx, 1284.7) + caput(pv.pilat_beamy, 1308.6) sleep(0.1) # Fixed Target stage (very fast start and stop w/ triggering from GeoBrick @@ -245,12 +243,12 @@ def pilatus(action, args_list): [filepath, filename, total_numb_imgs, exptime] = args_list rampath = filepath.replace("dls/i24/data", "ramdisk") acqtime = float(exptime) - 0.001 - logger.debug(f"Filepath was set as {filepath}") - logger.debug(f"Rampath set as {rampath}") - logger.debug(f"Filename set as {filename}") - logger.debug(f"total_numb_imgs {total_numb_imgs}") - logger.debug(f"Exposure time set as {exptime} s") - logger.debug(f"Acquire time set as {acqtime} s") + SSX_LOGGER.debug(f"Filepath was set as {filepath}") + SSX_LOGGER.debug(f"Rampath set as {rampath}") + SSX_LOGGER.debug(f"Filename set as {filename}") + SSX_LOGGER.debug(f"total_numb_imgs {total_numb_imgs}") + SSX_LOGGER.debug(f"Exposure time set as {exptime} s") + SSX_LOGGER.debug(f"Acquire time set as {acqtime} s") caput(pv.pilat_startangle, 0.0) caput(pv.pilat_angleincr, 0.0) caput(pv.pilat_omegaincr, 0.0) @@ -265,7 +263,7 @@ def pilatus(action, args_list): # Quick set of images no coordinated motion elif action == "quickshot": - logger.debug("quickshot") + SSX_LOGGER.debug("quickshot") [filepath, filename, num_imgs, exptime] = args_list rampath = filepath.replace("dls/i24/data", "ramdisk") caput(pv.pilat_filepath, rampath) @@ -275,13 +273,13 @@ def pilatus(action, args_list): acqtime = float(exptime) - 0.001 caput(pv.pilat_acquiretime, str(acqtime)) caput(pv.pilat_acquireperiod, str(exptime)) - logger.debug(f"Filepath was set as {filepath}") - logger.debug(f"Rampath set as {rampath}") - logger.debug(f"Filename set as {filename}") - logger.debug(f"num_imgs {num_imgs}") - logger.debug(f"Exposure time set as {exptime} s") - logger.debug(f"Acquire time set as {acqtime} s") - logger.debug("Pilatus takes time apprx 2sec") + SSX_LOGGER.debug(f"Filepath was set as {filepath}") + SSX_LOGGER.debug(f"Rampath set as {rampath}") + SSX_LOGGER.debug(f"Filename set as {filename}") + SSX_LOGGER.debug(f"num_imgs {num_imgs}") + SSX_LOGGER.debug(f"Exposure time set as {exptime} s") + SSX_LOGGER.debug(f"Acquire time set as {acqtime} s") + SSX_LOGGER.debug("Pilatus takes time apprx 2sec") sleep(2) caput(pv.pilat_delaytime, 0.00) caput(pv.pilat_numimages, str(num_imgs)) @@ -290,7 +288,7 @@ def pilatus(action, args_list): sleep(0.2) elif action == "quickshot-internaltrig": - logger.debug("quickshot-internaltrig") + SSX_LOGGER.debug("quickshot-internaltrig") [filepath, filename, num_imgs, exptime] = args_list rampath = filepath.replace("dls/i24/data", "ramdisk") caput(pv.pilat_filepath, rampath) @@ -300,13 +298,13 @@ def pilatus(action, args_list): acqtime = float(exptime) - 0.001 caput(pv.pilat_acquiretime, str(acqtime)) caput(pv.pilat_acquireperiod, str(exptime)) - logger.debug(f"Filepath was set as {filepath}") - logger.debug(f"Rampath set as {rampath}") - logger.debug(f"Filename set as {filename}") - logger.debug(f"num_imgs {num_imgs}") - logger.debug(f"Exposure time set as {exptime} s") - logger.debug(f"Acquire time set as {acqtime} s") - logger.debug("Pilatus takes time apprx 2sec") + SSX_LOGGER.debug(f"Filepath was set as {filepath}") + SSX_LOGGER.debug(f"Rampath set as {rampath}") + SSX_LOGGER.debug(f"Filename set as {filename}") + SSX_LOGGER.debug(f"num_imgs {num_imgs}") + SSX_LOGGER.debug(f"Exposure time set as {exptime} s") + SSX_LOGGER.debug(f"Acquire time set as {acqtime} s") + SSX_LOGGER.debug("Pilatus takes time apprx 2sec") sleep(2) caput(pv.pilat_delaytime, 0.00) caput(pv.pilat_numimages, str(num_imgs)) @@ -319,24 +317,24 @@ def pilatus(action, args_list): caput(pv.pilat_imagemode, "Continuous") caput(pv.pilat_triggermode, "Ext. Trigger") caput(pv.pilat_numexpimage, 1) - logger.debug("***** leaving pilatus") + SSX_LOGGER.debug("***** leaving pilatus") sleep(0.1) return 0 def eiger(action, args_list): - logger.debug("***** Entering Eiger") - logger.info(f"Setup eiger - {action}") + SSX_LOGGER.debug("***** Entering Eiger") + SSX_LOGGER.info(f"Setup eiger - {action}") if args_list: for arg in args_list: - logger.debug(f"Argument: {arg}") + SSX_LOGGER.debug(f"Argument: {arg}") # caput(pv.eiger_wavelength, caget(pv.dcm_lambda)) caput(pv.eiger_detdist, str(float(caget(pv.det_z)) / 1000)) - logger.warning("WARNING: Have you set header info?") + SSX_LOGGER.warning("WARNING: Have you set header info?") caput(pv.eiger_wavelength, caget(pv.dcm_lambda)) caput(pv.eiger_omegaincr, 0.0) - caput(pv.eiger_beamx, 1605.7) - caput(pv.eiger_beamy, 1702.7) + caput(pv.eiger_beamx, 1600.0) + caput(pv.eiger_beamy, 1697.4) sleep(0.1) # Setup common to all collections ### caput(pv.eiger_filewriter, "No") @@ -354,7 +352,7 @@ def eiger(action, args_list): # Quick set of images no coordinated motion if action == "quickshot": # Sends a single trigger to start data collection - logger.debug("Eiger quickshot") + SSX_LOGGER.debug("Eiger quickshot") [filepath, filename, num_imgs, exptime] = args_list filename = filename + "_" + str(caget(pv.eiger_seqID)) caput(pv.eiger_ODfilepath, filepath) @@ -363,11 +361,11 @@ def eiger(action, args_list): sleep(0.1) acqtime = float(exptime) - 0.0000001 caput(pv.eiger_acquiretime, str(acqtime)) - logger.debug(f"Filepath was set as {filepath}") - logger.debug(f"Filename set as {filename}") - logger.debug(f"num_imgs {num_imgs}") - logger.debug(f"Exposure time set as {exptime} s") - logger.debug(f"Acquire time set as {acqtime} s") + SSX_LOGGER.debug(f"Filepath was set as {filepath}") + SSX_LOGGER.debug(f"Filename set as {filename}") + SSX_LOGGER.debug(f"num_imgs {num_imgs}") + SSX_LOGGER.debug(f"Exposure time set as {exptime} s") + SSX_LOGGER.debug(f"Acquire time set as {acqtime} s") caput(pv.eiger_acquireperiod, str(exptime)) caput(pv.eiger_numimages, str(num_imgs)) caput(pv.eiger_imagemode, "Continuous") @@ -376,7 +374,7 @@ def eiger(action, args_list): caput(pv.eiger_manualtrigger, "Yes") sleep(1.0) # ODIN setup - logger.info("Setting up Odin") + SSX_LOGGER.info("Setting up Odin") caput(pv.eiger_ODfilename, filename) caput(pv.eiger_ODfilepath, filepath) caput(pv.eiger_ODnumcapture, str(num_imgs)) @@ -386,17 +384,17 @@ def eiger(action, args_list): caput(pv.eiger_ODcompress, "BSL24") sleep(1.0) # All done. Now get Odin to wait for data and start Eiger - logger.info("Done: Odin waiting for data") + SSX_LOGGER.info("Done: Odin waiting for data") caput(pv.eiger_ODcapture, "Capture") # If detector fails to arm first time can try twice with a sleep inbetween - logger.info("Arming Eiger") + SSX_LOGGER.info("Arming Eiger") caput(pv.eiger_acquire, "1") # Will now wait for Manual trigger. Add the below line to your DAQ script ### # caput(pv.eiger_trigger, 1) if action == "triggered": # Send a trigger for every image. Records while TTL is high - logger.info("Eiger triggered") + SSX_LOGGER.info("Eiger triggered") [filepath, filename, num_imgs, exptime] = args_list filename = filename + "_" + str(caget(pv.eiger_seqID)) caput(pv.eiger_ODfilepath, filepath) @@ -405,11 +403,11 @@ def eiger(action, args_list): sleep(0.1) acqtime = float(exptime) - 0.0000001 caput(pv.eiger_acquiretime, str(acqtime)) - logger.debug(f"Filepath was set as {filepath}") - logger.debug(f"Filename set as {filename}") - logger.debug(f"num_imgs {num_imgs}") - logger.debug(f"Exposure time set as {exptime} s") - logger.debug(f"Acquire time set as {acqtime} s") + SSX_LOGGER.debug(f"Filepath was set as {filepath}") + SSX_LOGGER.debug(f"Filename set as {filename}") + SSX_LOGGER.debug(f"num_imgs {num_imgs}") + SSX_LOGGER.debug(f"Exposure time set as {exptime} s") + SSX_LOGGER.debug(f"Acquire time set as {acqtime} s") caput(pv.eiger_acquireperiod, str(exptime)) caput(pv.eiger_numimages, 1) caput(pv.eiger_imagemode, "Continuous") @@ -418,7 +416,7 @@ def eiger(action, args_list): caput(pv.eiger_manualtrigger, "Yes") sleep(1.0) # ODIN setup # - logger.info("Setting up Odin") + SSX_LOGGER.info("Setting up Odin") caput(pv.eiger_ODfilename, filename) caput(pv.eiger_ODfilepath, filepath) caput(pv.eiger_ODnumcapture, str(num_imgs)) @@ -428,10 +426,10 @@ def eiger(action, args_list): caput(pv.eiger_ODcompress, "BSL24") sleep(1.0) # All done. Now get Odin to wait for data and start Eiger - logger.info("Done: Odin waiting for data") + SSX_LOGGER.info("Done: Odin waiting for data") caput(pv.eiger_ODcapture, "Capture") # If detector fails to arm first time can try twice with a sleep inbetween - logger.info("Arming Eiger") + SSX_LOGGER.info("Arming Eiger") caput(pv.eiger_acquire, "1") # Will now wait for Manual trigger. Add the below line to your DAQ script # caput(pv.eiger_trigger, 1) @@ -440,17 +438,17 @@ def eiger(action, args_list): elif action == "return-to-normal": caput(pv.eiger_manualtrigger, "No") # caput(pv.eiger_seqID, int(caget(pv.eiger_seqID))+1) - logger.debug("***** leaving Eiger") + SSX_LOGGER.debug("***** leaving Eiger") sleep(0.1) return 0 def xspress3(action, args_list): - logger.debug("***** Entering xspress3") - logger.info(f"xspress3 - {action}") + SSX_LOGGER.debug("***** Entering xspress3") + SSX_LOGGER.info(f"xspress3 - {action}") if args_list: for arg in args_list: - logger.debug(f"Argument: {arg}") + SSX_LOGGER.debug(f"Argument: {arg}") if action == "stop-and-start": [exp_time, lo, hi] = args_list @@ -486,8 +484,8 @@ def xspress3(action, args_list): caput(pv.xsp3_erase, 0) else: - logger.error("Unknown action for xspress3 method:", action) + SSX_LOGGER.error("Unknown action for xspress3 method:", action) sleep(0.1) - logger.debug("***** leaving xspress3") + SSX_LOGGER.debug("***** leaving xspress3") return 1 diff --git a/src/mx_bluesky/beamlines/i24/serial/setup_beamline/setup_zebra_plans.py b/src/mx_bluesky/beamlines/i24/serial/setup_beamline/setup_zebra_plans.py index 73f3f4c1f..a656bed07 100644 --- a/src/mx_bluesky/beamlines/i24/serial/setup_beamline/setup_zebra_plans.py +++ b/src/mx_bluesky/beamlines/i24/serial/setup_beamline/setup_zebra_plans.py @@ -9,8 +9,6 @@ schematics corresponds to soft_in_2 in the code. """ -import logging - import bluesky.plan_stubs as bps from dodal.devices.zebra import ( AND3, @@ -35,6 +33,8 @@ Zebra, ) +from mx_bluesky.beamlines.i24.serial.log import SSX_LOGGER + # Detector specific outs TTL_EIGER = 1 TTL_PILATUS = 2 @@ -48,8 +48,6 @@ GATE_START = 1.0 SHUTTER_OPEN_TIME = 0.05 # For pp with long delays -logger = logging.getLogger("I24ssx.setup_zebra") - def get_zebra_settings_for_extruder( exp_time: float, @@ -71,28 +69,28 @@ def get_zebra_settings_for_extruder( def arm_zebra(zebra: Zebra): yield from bps.abs_set(zebra.pc.arm, ArmDemand.ARM, wait=True) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809 - logger.info("Zebra armed.") + SSX_LOGGER.info("Zebra armed.") def disarm_zebra(zebra: Zebra): yield from bps.abs_set(zebra.pc.arm, ArmDemand.DISARM, wait=True) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809 - logger.info("Zebra disarmed.") + SSX_LOGGER.info("Zebra disarmed.") def open_fast_shutter(zebra: Zebra): yield from bps.abs_set(zebra.inputs.soft_in_2, SoftInState.YES, wait=True) - logger.info("Fast shutter open.") + SSX_LOGGER.info("Fast shutter open.") def close_fast_shutter(zebra: Zebra): yield from bps.abs_set(zebra.inputs.soft_in_2, SoftInState.NO, wait=True) - logger.info("Fast shutter closed.") + SSX_LOGGER.info("Fast shutter closed.") def set_shutter_mode(zebra: Zebra, mode: str): # SOFT_IN:B0 has to be disabled for manual mode yield from bps.abs_set(zebra.inputs.soft_in_1, SHUTTER_MODE[mode], wait=True) - logger.info(f"Shutter mode set to {mode}.") + SSX_LOGGER.info(f"Shutter mode set to {mode}.") def setup_pc_sources( @@ -124,12 +122,12 @@ def setup_zebra_for_quickshot_plan( exp_time (float): Collection exposure time, in s. num_images (float): Number of images to be collected. """ - logger.info("Setup ZEBRA for quickshot collection.") + SSX_LOGGER.info("Setup ZEBRA for quickshot collection.") yield from bps.abs_set(zebra.pc.arm_source, ArmSource.SOFT, group=group) yield from setup_pc_sources(zebra, TrigSource.TIME, TrigSource.EXTERNAL) gate_width = exp_time * num_images + 0.5 - logger.info(f"Gate start set to {GATE_START}, with width {gate_width}.") + SSX_LOGGER.info(f"Gate start set to {GATE_START}, with width {gate_width}.") yield from bps.abs_set(zebra.pc.gate_start, GATE_START, group=group) yield from bps.abs_set(zebra.pc.gate_width, gate_width, group=group) @@ -138,7 +136,7 @@ def setup_zebra_for_quickshot_plan( if wait: yield from bps.wait(group) - logger.info("Finished setting up zebra.") + SSX_LOGGER.info("Finished setting up zebra.") def set_logic_gates_for_porto_triggering( @@ -204,7 +202,7 @@ def setup_zebra_for_extruder_with_pump_probe_plan( pulse1_delay (float, optional): Delay to start pulse1 (the laser control) after \ gate start. Defaults to 0.0. """ - logger.info("Setup ZEBRA for pump probe extruder collection.") + SSX_LOGGER.info("Setup ZEBRA for pump probe extruder collection.") yield from set_shutter_mode(zebra, "manual") @@ -226,7 +224,7 @@ def setup_zebra_for_extruder_with_pump_probe_plan( gate_width, gate_step = get_zebra_settings_for_extruder( exp_time, pump_exp, pump_delay ) - logger.info( + SSX_LOGGER.info( f""" Gate start set to {GATE_START}, with calculated width {gate_width} and step {gate_step}. @@ -241,13 +239,13 @@ def setup_zebra_for_extruder_with_pump_probe_plan( # Settings for extruder pump probe: # PULSE1_DLY is the start (0 usually), PULSE1_WID is the laser dwell set on edm # PULSE2_DLY is the laser delay set on edm, PULSE2_WID is the exposure time - logger.info( + SSX_LOGGER.info( f"Pulse1 starting at {pulse1_delay} with width set to laser dwell {pump_exp}." ) yield from bps.abs_set(zebra.output.pulse_1.input, PC_GATE, group=group) yield from bps.abs_set(zebra.output.pulse_1.delay, pulse1_delay, group=group) yield from bps.abs_set(zebra.output.pulse_1.width, pump_exp, group=group) - logger.info( + SSX_LOGGER.info( f""" Pulse2 starting at laser delay {pump_delay} with width set to \ exposure time {exp_time}. @@ -259,7 +257,7 @@ def setup_zebra_for_extruder_with_pump_probe_plan( if wait: yield from bps.wait(group) - logger.info("Finished setting up zebra.") + SSX_LOGGER.info("Finished setting up zebra.") def setup_zebra_for_fastchip_plan( @@ -302,7 +300,7 @@ def setup_zebra_for_fastchip_plan( start_time_offset (float): Delay on the start of the position compare. \ Defaults to 0.0 (standard chip collection). """ - logger.info("Setup ZEBRA for a fixed target collection.") + SSX_LOGGER.info("Setup ZEBRA for a fixed target collection.") yield from set_shutter_mode(zebra, "manual") @@ -341,7 +339,7 @@ def setup_zebra_for_fastchip_plan( if wait: yield from bps.wait(group) - logger.info("Finished setting up zebra.") + SSX_LOGGER.info("Finished setting up zebra.") def open_fast_shutter_at_each_position_plan( @@ -371,10 +369,10 @@ def open_fast_shutter_at_each_position_plan( num_exposures (int): Number of times data is collected in each aperture. exposure_time (float): Exposure time for each shot. """ - logger.info( + SSX_LOGGER.info( "ZEBRA setup for fastchip collection with long delays between exposures." ) - logger.debug("Controlling the fast shutter on PULSE2.") + SSX_LOGGER.debug("Controlling the fast shutter on PULSE2.") # Output panel pulse_2 settings yield from bps.abs_set(zebra.output.pulse_2.input, PC_GATE, group=group) yield from bps.abs_set(zebra.output.pulse_2.delay, 0.0, group=group) @@ -386,7 +384,7 @@ def open_fast_shutter_at_each_position_plan( if wait: yield from bps.wait(group=group) - logger.debug("Finished setting up for long delays.") + SSX_LOGGER.debug("Finished setting up for long delays.") def reset_pc_gate_and_pulse(zebra: Zebra, group: str = "reset_pc"): @@ -444,16 +442,16 @@ def zebra_return_to_normal_plan( if wait: yield from bps.wait(group) - logger.info("Zebra settings back to normal.") + SSX_LOGGER.info("Zebra settings back to normal.") def reset_zebra_when_collection_done_plan(zebra: Zebra): """ End of collection zebra operations: close fast shutter, disarm and reset settings. """ - logger.debug("Close the fast shutter.") + SSX_LOGGER.debug("Close the fast shutter.") yield from close_fast_shutter(zebra) - logger.debug("Disarm the zebra.") + SSX_LOGGER.debug("Disarm the zebra.") yield from disarm_zebra(zebra) - logger.debug("Set zebra back to normal.") + SSX_LOGGER.debug("Set zebra back to normal.") yield from zebra_return_to_normal_plan(zebra, wait=True) diff --git a/src/mx_bluesky/beamlines/i24/serial/write_nexus.py b/src/mx_bluesky/beamlines/i24/serial/write_nexus.py index 384394125..5a76e39cb 100644 --- a/src/mx_bluesky/beamlines/i24/serial/write_nexus.py +++ b/src/mx_bluesky/beamlines/i24/serial/write_nexus.py @@ -1,4 +1,3 @@ -import logging import os import pathlib import pprint @@ -9,14 +8,13 @@ import requests from mx_bluesky.beamlines.i24.serial.fixed_target.ft_utils import ChipType, MappingType +from mx_bluesky.beamlines.i24.serial.log import SSX_LOGGER from mx_bluesky.beamlines.i24.serial.parameters import ( ExtruderParameters, FixedTargetParameters, ) from mx_bluesky.beamlines.i24.serial.setup_beamline import Eiger, caget, cagetstring -logger = logging.getLogger("I24ssx.nexus_writer") - def call_nexgen( chip_prog_dict: dict | None, @@ -54,23 +52,23 @@ def call_nexgen( ) t0 = time.time() max_wait = 60 # seconds - logger.info(f"Watching for {meta_h5}") + SSX_LOGGER.info(f"Watching for {meta_h5}") while time.time() - t0 < max_wait: if meta_h5.exists(): - logger.info(f"Found {meta_h5} after {time.time() - t0:.1f} seconds") + SSX_LOGGER.info(f"Found {meta_h5} after {time.time() - t0:.1f} seconds") time.sleep(5) break - logger.debug(f"Waiting for {meta_h5}") + SSX_LOGGER.debug(f"Waiting for {meta_h5}") time.sleep(1) if not meta_h5.exists(): - logger.warning(f"Giving up waiting for {meta_h5} after {max_wait} seconds") + SSX_LOGGER.warning(f"Giving up waiting for {meta_h5} after {max_wait} seconds") return False transmission = (float(caget(Eiger.pv.transmission)),) if det_type == Eiger.name: bit_depth = int(caget(Eiger.pv.bit_depth)) - logger.debug( + SSX_LOGGER.debug( f"Call to nexgen server with the following chip definition: \n{chip_prog_dict}" ) @@ -96,10 +94,12 @@ def call_nexgen( "wavelength": wavelength, "bit_depth": bit_depth, } - logger.info(f"Sending POST request to {url} with payload:") - logger.info(pprint.pformat(payload)) + SSX_LOGGER.info(f"Sending POST request to {url} with payload:") + SSX_LOGGER.info(pprint.pformat(payload)) response = requests.post(url, headers=headers, json=payload) - logger.info(f"Response: {response.text} (status code: {response.status_code})") + SSX_LOGGER.info( + f"Response: {response.text} (status code: {response.status_code})" + ) # the following will raise an error if the request was unsuccessful return response.status_code == requests.codes.ok return False diff --git a/tests/unit_tests/beamlines/i24/serial/fixed_target/test_ft_collect.py b/tests/unit_tests/beamlines/i24/serial/fixed_target/test_ft_collect.py index 9d94578a8..298099867 100644 --- a/tests/unit_tests/beamlines/i24/serial/fixed_target/test_ft_collect.py +++ b/tests/unit_tests/beamlines/i24/serial/fixed_target/test_ft_collect.py @@ -46,7 +46,7 @@ def test_calculate_collection_timeout(dummy_params_without_pp): dummy_params_without_pp.total_num_images * dummy_params_without_pp.exposure_time_s ) - buffer = dummy_params_without_pp.total_num_images * PMAC_MOVE_TIME + 2 + buffer = dummy_params_without_pp.total_num_images * PMAC_MOVE_TIME + 600 timeout = calculate_collection_timeout(dummy_params_without_pp) assert timeout == expected_collection_time + buffer @@ -54,7 +54,7 @@ def test_calculate_collection_timeout(dummy_params_without_pp): def test_calculate_collection_timeout_for_eava(dummy_params_with_pp): dummy_params_with_pp.total_num_images = 400 - buffer = dummy_params_with_pp.total_num_images * PMAC_MOVE_TIME + 2 + buffer = dummy_params_with_pp.total_num_images * PMAC_MOVE_TIME + 600 expected_pump_and_probe_time = 12.05 timeout = calculate_collection_timeout(dummy_params_with_pp) diff --git a/tests/unit_tests/beamlines/i24/serial/setup_beamline/test_setup_beamline.py b/tests/unit_tests/beamlines/i24/serial/setup_beamline/test_setup_beamline.py index 694b210b6..26ee9ecbe 100644 --- a/tests/unit_tests/beamlines/i24/serial/setup_beamline/test_setup_beamline.py +++ b/tests/unit_tests/beamlines/i24/serial/setup_beamline/test_setup_beamline.py @@ -45,6 +45,15 @@ def test_pilatus_quickshot(_, fake_caget, fake_caput): assert fake_caget.call_count == 2 +@patch("mx_bluesky.beamlines.i24.serial.setup_beamline.setup_beamline.caput") +@patch("mx_bluesky.beamlines.i24.serial.setup_beamline.setup_beamline.caget") +@patch("mx_bluesky.beamlines.i24.serial.setup_beamline.setup_beamline.sleep") +def test_pilatus_fastchip(_, fake_caget, fake_caput): + setup_beamline.pilatus("fastchip", ["", "", 10, 0.1]) + assert fake_caput.call_count == 15 + assert fake_caget.call_count == 2 + + @patch("mx_bluesky.beamlines.i24.serial.setup_beamline.setup_beamline.caput") @patch("mx_bluesky.beamlines.i24.serial.setup_beamline.setup_beamline.caget") def test_eiger_raises_error_if_quickshot_and_no_args_list(fake_caget, fake_caput): @@ -58,3 +67,29 @@ def test_eiger_raises_error_if_quickshot_and_no_args_list(fake_caget, fake_caput def test_eiger_quickshot(_, fake_caget, fake_caput): setup_beamline.eiger("quickshot", ["", "", "1", "0.1"]) assert fake_caput.call_count == 32 + + +@patch("mx_bluesky.beamlines.i24.serial.setup_beamline.setup_beamline.caput") +@patch("mx_bluesky.beamlines.i24.serial.setup_beamline.setup_beamline.caget") +@patch("mx_bluesky.beamlines.i24.serial.setup_beamline.setup_beamline.sleep") +def test_eiger_triggered(_, fake_caget, fake_caput): + setup_beamline.eiger("triggered", ["", "", "10", "0.1"]) + assert fake_caget.call_count == 4 + assert fake_caput.call_count == 32 + + +@pytest.mark.parametrize( + "action, expected_caputs, expected_sleeps", + [ + ("Pin_hand_mount", 11, 0), + ("Pin_rt_hand_mount", 11, 0), + ("Pin_data_collection", 12, 2), + ("Pin_rt_data_collection", 13, 2), + ], +) +@patch("mx_bluesky.beamlines.i24.serial.setup_beamline.setup_beamline.caput") +@patch("mx_bluesky.beamlines.i24.serial.setup_beamline.setup_beamline.sleep") +def test_mode_change(fake_sleep, fake_caput, action, expected_caputs, expected_sleeps): + setup_beamline.modechange(action) + assert fake_caput.call_count == expected_caputs + assert fake_sleep.call_count == expected_sleeps diff --git a/tests/unit_tests/beamlines/i24/serial/test_dcid.py b/tests/unit_tests/beamlines/i24/serial/test_dcid.py index 1a4c1fe36..12d5a741f 100644 --- a/tests/unit_tests/beamlines/i24/serial/test_dcid.py +++ b/tests/unit_tests/beamlines/i24/serial/test_dcid.py @@ -3,6 +3,7 @@ from mx_bluesky.beamlines.i24.serial.dcid import ( get_beam_center, get_beamsize, + get_pilatus_filename_template_from_pvs, get_resolution, ) from mx_bluesky.beamlines.i24.serial.setup_beamline import Eiger, Pilatus @@ -32,3 +33,14 @@ def test_get_resolution(): assert eiger_resolution == 0.78 assert pilatus_resolution == 0.61 + + +@patch("mx_bluesky.beamlines.i24.serial.dcid.cagetstring") +@patch("mx_bluesky.beamlines.i24.serial.dcid.caget") +def test_get_pilatus_filename_from_pvs(fake_caget, fake_caget_str): + fake_caget_str.side_effect = ["test_", "%s%s%05d.cbf"] + fake_caget.return_value = 2 + + expected_template = "test_00002_#####.cbf" + res = get_pilatus_filename_template_from_pvs() + assert res == expected_template diff --git a/tests/unit_tests/beamlines/i24/serial/test_write_nexus.py b/tests/unit_tests/beamlines/i24/serial/test_write_nexus.py new file mode 100644 index 000000000..893b1cf67 --- /dev/null +++ b/tests/unit_tests/beamlines/i24/serial/test_write_nexus.py @@ -0,0 +1,43 @@ +from unittest.mock import MagicMock, patch + +import pytest + +from mx_bluesky.beamlines.i24.serial.parameters import ExtruderParameters +from mx_bluesky.beamlines.i24.serial.write_nexus import call_nexgen + + +@pytest.fixture +def dummy_params_ex(): + params = { + "visit": "foo", + "directory": "bar", + "filename": "protein", + "exposure_time_s": 0.1, + "detector_distance_mm": 100, + "detector_name": "eiger", + "num_images": 10, + "pump_status": False, + } + return ExtruderParameters(**params) + + +def test_call_nexgen_fails_for_wrong_experiment_type(dummy_params_ex): + with pytest.raises(ValueError): + call_nexgen(None, MagicMock(), dummy_params_ex, 0.6, "fixed-target") + + +@patch("mx_bluesky.beamlines.i24.serial.write_nexus.SSX_LOGGER") +@patch("mx_bluesky.beamlines.i24.serial.write_nexus.cagetstring") +@patch("mx_bluesky.beamlines.i24.serial.write_nexus.caget") +@patch("mx_bluesky.beamlines.i24.serial.write_nexus.pathlib.Path.read_text") +@patch("mx_bluesky.beamlines.i24.serial.write_nexus.pathlib.Path.exists") +def test_call_nexgen_for_extruder( + fake_path, fake_read_text, fake_caget, fake_caget_str, fake_log, dummy_params_ex +): + fake_caget_str.return_value = "protein" + fake_caget.side_effect = [1.0, 32, 1000, 1200] + fake_path.return_value = True + fake_read_text.return_value = "" + with patch("mx_bluesky.beamlines.i24.serial.write_nexus.requests") as patch_request: + call_nexgen(None, MagicMock(), dummy_params_ex, 0.6, "extruder") + patch_request.post.assert_called_once()