diff --git a/src/aare/daq/daq.py b/src/aare/daq/daq.py index 1a105633..57968015 100644 --- a/src/aare/daq/daq.py +++ b/src/aare/daq/daq.py @@ -46,7 +46,10 @@ from aare.common.exception_handler import ( MountingFailed, WarningTellException, CriticalTellException, - AXCFailed, SmargonCommunicationError, TellCommunicationError, + AXCFailed, + SmargonCommunicationError, + TellCommunicationError, + JFJochCommunicationError ) logger = setup_logger("aareDAQ") @@ -474,14 +477,14 @@ class AareDAQ: except Exception as e: self.__cfg.state_busy = False logger.debug(f"Failed to mount sample: {e}") - self.__aare.sample_failed(target, f"Mount failed due to {e}") + # self.__aare.sample_failed(target, f"Mount failed due to {e}") raise e workflows.rse2sa(devs=self.__devs, cfg=self.__cfg) self.__cfg.state_busy = False - if target is not None: - if target.db_id is not None: - self.__aare.sample_mounted(target) - self.save_screenshot_db(target.db_id, f"{target.db_id}_mounted") + # if target is not None: + # if target.db_id is not None: + # self.__aare.sample_mounted(target) + # self.save_screenshot_db(target.db_id, f"{target.db_id}_mounted") @property @@ -727,8 +730,9 @@ class AareDAQ: efficiency=1.0, bkg=0.0, spots=0, + spots_low_res=0, + spots_indexed=0, index=0, - mos=0.0, b=0.0, ) for i in range(max(1, image_count)) @@ -765,24 +769,46 @@ class AareDAQ: logger.info(f'raster grid request: {request}') total_time = request.exp_time_s*request.n_x*request.n_y - #self.__jfjoch.measure_raster(r, status) + if not self.__cfg.simulated_detector: + try: + logger.info('initialise detector') + self.__jfjoch.measure_raster(request, status) + logger.info('detector initialised') + except JFJochCommunicationError as e: + logger.warning(f"Failed to communicate with jfjoch: {e}") - self.__devs.aerotech.grid_scan(grid_elem_size_y_um=request.grid_size_mm.y*1000, - grid_elem_size_x_um=request.grid_size_mm.x*1000, - grid_elem_count_x=request.n_x, - grid_elem_count_y=request.n_y, - time_sec=request.exp_time_s, - run_async=True) + else: + logger.info("Simulated detector mode enabled; returning fake zero raster result.") - self.__devs.aerotech.wait_till_done(timeout=int(round(total_time*2,0))) + try: + self.__devs.aerotech.grid_scan(grid_elem_size_y_um=request.grid_size_mm.y*1000, + grid_elem_size_x_um=request.grid_size_mm.x*1000, + grid_elem_count_x=request.n_x, + grid_elem_count_y=request.n_y, + time_sec=request.exp_time_s, + run_async=True) - self.__devs.aerotech_pos = self.__cfg.abr_meas_pos + self.__devs.aerotech.wait_till_done(timeout=int(round(total_time*2,0))) - #result = self.__jfjoch.wait_till_done(60) - #return None + self.__devs.aerotech_pos = self.__cfg.abr_meas_pos - return self._build_fake_raster_result(request=request) - #return CompletedRasterGridElem(request=copy.deepcopy(request), result=result, centre_of_mass=None) + try: + result = self.__jfjoch.wait_till_done(60) + except JFJochCommunicationError as e: + logger.warning(f"Failed to communicate with jfjoch: {e}") + return self._build_fake_raster_result(request) + + if result is None: + logger.warning("JFJoch returned no ScanResult; using fake result for raster scan.") + return self._build_fake_raster_result(request) + + return CompletedRasterGridElem(request=copy.deepcopy(request), result=result, centre_of_mass=None) + + except JFJochCommunicationError: + raise + except Exception as e: + logger.error(f"Failed during raster: {e}") + raise Exception(f"Failed during raster: {e}") from e def measure_raster(self, r: RasterGridRequest, auto: bool) -> CompletedRasterGrid: self.__cfg.try_set_busy(timeout=ceil(360)) @@ -809,20 +835,18 @@ class AareDAQ: raise e def __rotation(self, request: RotationScanRequest) -> CompletedRotationScan: - omega_start = self.omega status = self.status + #self.__aare.create_rotation_run(self.sample, request, status) total_time = request.exp_time_s * request.steps try: - # if self.__cfg.simulated_detector: - # logger.info("Simulated detector mode enabled; skipping JFJoch start.") - # result = self._build_fake_rotation_result(request) - - #else: - #self.__jfjoch.measure_rotation(request, status, self.__cfg.xrf) + if self.__cfg.simulated_detector: + logger.info("Simulated detector mode enabled; skipping JFJoch start.") + else: + self.__jfjoch.measure_rotation(request, status, self.__cfg.xrf) if request.screening: self.__devs.aerotech.screening_scan( @@ -833,14 +857,13 @@ class AareDAQ: run_async=True, ) else: - #logger.info(f"rotation scan {request}") self.__devs.aerotech.rotation_scan( rotation_deg=request.steps*request.incr_omega_deg, time_sec=total_time, start_pos_deg=request.start_omega_deg, run_async=True, ) - #logger.info(f"rotation scan in progress {request}") + #Is this for helical scans...? do we do smargon scans? if request.start is not None and request.end is not None: smargon_time_step = request.time_sec / float(request.steps) @@ -852,33 +875,34 @@ class AareDAQ: ) time.sleep(smargon_time_step) - #logger.info(f"wait till rotation scan done {request}") self.__devs.aerotech.wait_till_done(timeout=int(round(total_time + 60,0))) - #logger.info(f"move aerotech to omega start: {omega_start}") self.__devs.aerotech_omega = omega_start - #result = self.__jfjoch.wait_till_done(60) # self.__aare.sample_collected(self.sample) - # if result is None: - # logger.warning("JFJoch returned no ScanResult; using fake result for rotation scan.") - # result = self._build_fake_rotation_result(request) + if self.__cfg.simulated_detector: + logger.warning("Detector in simulation mode, returning fake zero rotation result.") + result = self._build_fake_rotation_result(request) - if self.sample is not None and self.sample.db_id is not None: - self.save_screenshot_db(self.sample.db_id, "after_dc") + else: + # Let JFJochCommunicationError propagate + result = self.__jfjoch.wait_till_done(60) + + # if self.sample is not None and self.sample.db_id is not None: + # self.save_screenshot_db(self.sample.db_id, "after_dc") # try: # self.__aare.ingest_scan(sample=self.sample, result=result, # geom=self.sample_geometry, beam_mark_pxl=self.__cfg.get_beam_mark(self.zoom)) # # except Exception as e: # logger.error(f"Exception ingesting scan: {e}") + except JFJochCommunicationError: + raise except Exception as e: - logger.error(f"Exception during rotation scan: {e}") - #result = self._build_fake_rotation_result(request) + raise - return self._build_fake_rotation_result(request) - #return CompletedRotationScan(request=copy.deepcopy(request), result=result) + return CompletedRotationScan(request=copy.deepcopy(request), result=result) def measure_rotation(self, request: RotationScanRequest) -> CompletedRotationScan: total_time = request.exp_time_s * request.steps @@ -1879,7 +1903,7 @@ class AareDAQ: def cancel(self): if self.__cfg.state == BeamlineStateEnum.DataCollection: - self.__devs.aerotech_stop() + self.__devs.aerotech.cancel() self.__jfjoch.cancel() def anneal(self, time_s: float): diff --git a/src/aare/gui/threads/daq_worker.py b/src/aare/gui/threads/daq_worker.py index 43cdc327..7984bf57 100644 --- a/src/aare/gui/threads/daq_worker.py +++ b/src/aare/gui/threads/daq_worker.py @@ -692,12 +692,38 @@ class DAQWorker(QObject): def handle_rotation_scan_response(self, reply: QNetworkReply): try: + # Check for HTTP errors first + if reply.error() != QNetworkReply.NetworkError.NoError: + status = reply.attribute(QNetworkRequest.Attribute.HttpStatusCodeAttribute) + err_msg = reply.errorString() + + try: + raw_body = reply.readAll().data().decode("utf-8") + if raw_body: + body_json = json.loads(raw_body) + if isinstance(body_json, dict): + err_msg = body_json.get("message", err_msg) + code = body_json.get("code", "") + + # Check if this is a JFJoch error + if code == "JFJOCH_UNAVAILABLE" or status == 503: + self._emit_detector_message(f"JFJoch: {err_msg}", is_error=True) + except Exception: + pass + + logger.error(f"Rotation scan failed: {err_msg}") + self.http_error.emit(err_msg) + reply.deleteLater() + return + response_data = self.handle_response(reply) parsed_response = CompletedRotationScan.model_validate_json(response_data) self.standard_scan_completed.emit(parsed_response) except Exception as e: logger.error(f"Exception from rotation scan response: {e}") self.http_error.emit(str(e)) + finally: + reply.deleteLater() @Slot(RotationScanRequest) def standard_scan(self, r: RotationScanRequest): @@ -712,12 +738,40 @@ class DAQWorker(QObject): def handle_raster_scan_response(self, reply: QNetworkReply): try: + # Check for HTTP errors first + if reply.error() != QNetworkReply.NetworkError.NoError: + status = reply.attribute(QNetworkRequest.Attribute.HttpStatusCodeAttribute) + raw_body = "" + body_json = None + err_msg = reply.errorString() + + try: + raw_body = reply.readAll().data().decode("utf-8") + if raw_body: + body_json = json.loads(raw_body) + if isinstance(body_json, dict): + err_msg = body_json.get("message", err_msg) + code = body_json.get("code", "") + + # Check if this is a JFJoch error + if code == "JFJOCH_UNAVAILABLE" or status == 503: + self._emit_detector_message(f"JFJoch: {err_msg}", is_error=True) + except Exception: + pass + + logger.error(f"Raster scan failed: {err_msg}") + self.http_error.emit(err_msg) + reply.deleteLater() + return + response_data = self.handle_response(reply) parsed_response = CompletedRasterGrid.model_validate_json(response_data) self.raster_scan_completed.emit(parsed_response) except Exception as e: logger.error(f"Exception from raster scan response: {e}") self.http_error.emit(str(e)) + finally: + reply.deleteLater() @Slot(RasterGridRequest) def raster_scan(self, r: RasterGridRequest): @@ -736,13 +790,14 @@ class DAQWorker(QObject): bkg = random.gauss(3.0, 0.1), spots= random.randint(0, 250), index= random.randint(0, 1), - mos = random.uniform(0, 0.1), b= random.uniform(15.0, 80.0) )) - logger.debug("check that this works - raster scan - complete raster grid") - reply = CompletedRasterGrid(request = new_copy, - result = ScanResult(file_prefix=r.file_prefix, images=images)) - logger.debug(f"It appears to work {reply}") + raster_elem = CompletedRasterGridElem( + request=new_copy, + result=ScanResult(file_prefix=r.file_prefix, images=images), + centre_of_mass = None, + ) + reply = CompletedRasterGrid(r=[raster_elem]) self.raster_scan_completed.emit(reply) return @@ -769,13 +824,14 @@ class DAQWorker(QObject): bkg=random.gauss(3.0, 0.1), spots=random.randint(0, 250), index=random.randint(0, 1), - mos=random.uniform(0, 0.1), b=random.uniform(15.0, 80.0) )) - logger.debug("check that this works - raster scan auto - complete raster grid") - reply = CompletedRasterGrid(request=new_copy, - result=ScanResult(file_prefix=r.file_prefix, images=images)) - logger.debug(f"It appears to work {reply}") + raster_elem = CompletedRasterGridElem( + request=new_copy, + result=ScanResult(file_prefix=r.file_prefix, images=images), + centre_of_mass = None, + ) + reply = CompletedRasterGrid(r=[raster_elem]) self.raster_scan_completed.emit(reply) return