raster: now do auto_centre_line_scan based off of target_y instead of just above and below beam cente, if target avaialble, now submit iamges to databse, reduced number of significant figures inr aster message to db, grid_to_image and iamge_to_grid fucntions
This commit is contained in:
@@ -88,3 +88,52 @@ class RasterPayloadModel(BaseModel):
|
||||
beam_mark_pxl: tuple[float, float]
|
||||
beam_size_mm: Annotated[Coordinate, AfterValidator(positive_coords)]
|
||||
|
||||
def grid_to_image_id(grid_x: int, grid_y: int, number_of_cols: int) -> int:
|
||||
"""
|
||||
Get the associated image id for a given grid position (grid_x, grid_y)
|
||||
using serpentine row ordering.
|
||||
|
||||
grid_x: 1-based column index
|
||||
grid_y: 1-based row index
|
||||
number_of_cols: total number of columns in the grid
|
||||
"""
|
||||
if number_of_cols < 1:
|
||||
raise ValueError("number_of_cols must be >= 1")
|
||||
if grid_x < 1:
|
||||
raise ValueError("grid_x must be >= 1")
|
||||
if grid_y < 1:
|
||||
raise ValueError("grid_y must be >= 1")
|
||||
if grid_x > number_of_cols:
|
||||
raise ValueError("grid_x cannot be greater than number_of_cols")
|
||||
|
||||
col = grid_x - 1
|
||||
row = grid_y - 1
|
||||
|
||||
if row % 2 == 0: # left -> right
|
||||
return row * number_of_cols + col
|
||||
else: # right -> left
|
||||
return row * number_of_cols + (number_of_cols - 1 - col)
|
||||
|
||||
|
||||
def image_id_to_grid(image_id: int, number_of_cols: int) -> tuple[int, int]:
|
||||
"""
|
||||
Get the associated grid position (grid_x, grid_y) for a given image id
|
||||
using serpentine row ordering.
|
||||
"""
|
||||
if number_of_cols < 1:
|
||||
raise ValueError("number_of_cols must be >= 1")
|
||||
if image_id < 0:
|
||||
raise ValueError("image_id must be >= 0")
|
||||
|
||||
row = image_id // number_of_cols
|
||||
pos_in_row = image_id % number_of_cols
|
||||
|
||||
if row % 2 == 0: # left -> right
|
||||
col = pos_in_row
|
||||
else: # right -> left
|
||||
col = number_of_cols - 1 - pos_in_row
|
||||
|
||||
grid_x = col + 1
|
||||
grid_y = row + 1
|
||||
|
||||
return grid_x, grid_y
|
||||
+195
-15
@@ -4,7 +4,7 @@ import time
|
||||
import traceback
|
||||
|
||||
from datetime import datetime
|
||||
from math import ceil
|
||||
from math import ceil, floor
|
||||
from pathlib import Path
|
||||
from typing import List, Tuple, Optional, Callable
|
||||
|
||||
@@ -39,7 +39,7 @@ from aare.common.automation_models import (
|
||||
StepStatus,
|
||||
WorkflowStateKind,
|
||||
)
|
||||
from aare.common.raster_grid import RasterGridRequest, CompletedRasterGrid, CompletedRasterGridElem
|
||||
from aare.common.raster_grid import RasterGridRequest, CompletedRasterGrid, CompletedRasterGridElem, grid_to_image_id
|
||||
from aare.common.rotation_scan import RotationScanRequest, CompletedRotationScan
|
||||
from aare.common.sample_geometry import SampleGeometryModel
|
||||
from aare.daq.spreadsheetupdater import beamline
|
||||
@@ -1090,26 +1090,33 @@ class AareDAQ:
|
||||
self.__set_state(BeamlineStateEnum.DataCollection)
|
||||
|
||||
grid.n_x = 1
|
||||
# TODO generate y scan rather than had code for 1x50
|
||||
grid.n_y = 50
|
||||
grid.file_prefix = f"{old_prefix}_{grid.omega_deg}deg"
|
||||
grid.grid_size_mm = Coordinate(x=geom.beam_size_mm.x, y=geom.beam_size_mm.y * 0.25)
|
||||
offset = Coordinate(x=-grid.grid_size_mm.x / 2.0, y=-(grid.n_y + 0.5) * grid.grid_size_mm.y / 2.0)
|
||||
geom = self.sample_geometry
|
||||
logger.debug(f"set offset y scan {offset}")
|
||||
grid.smargon_top_left = geom.translate_smargon(offset)
|
||||
grid.grid_size_mm = Coordinate(x=geom.beam_size_mm.x, y=geom.beam_size_mm.y * 0.25)
|
||||
grid.smargon_top_left, grid.n_y = self._auto_center_line_scan_top_left(
|
||||
omega_deg=grid.omega_deg,
|
||||
file_prefix=grid.file_prefix,
|
||||
grid_size_mm=grid.grid_size_mm,
|
||||
default_n_y=50,
|
||||
y_retarget_threshold_mm=max(
|
||||
geom.beam_size_mm.y * 2.0,
|
||||
grid.grid_size_mm.y * 4.0,
|
||||
),
|
||||
y_padding_fraction_each_side=0.10,
|
||||
)
|
||||
|
||||
logger.info(
|
||||
"Prepared second auto-center raster",
|
||||
extra={
|
||||
"file_prefix": grid.file_prefix,
|
||||
"omega_deg": grid.omega_deg,
|
||||
"offset_x_mm": offset.x,
|
||||
"offset_y_mm": offset.y,
|
||||
"offset_z_mm": offset.z,
|
||||
"top_left_x_mm": getattr(grid.smargon_top_left.sh_mm, "x", None),
|
||||
"top_left_y_mm": getattr(grid.smargon_top_left.sh_mm, "y", None),
|
||||
"top_left_z_mm": getattr(grid.smargon_top_left.sh_mm, "z", None),
|
||||
"n_x": grid.n_x,
|
||||
"n_y": grid.n_y,
|
||||
"grid_size_x_mm": getattr(grid.grid_size_mm, "x", None),
|
||||
"grid_size_y_mm": getattr(grid.grid_size_mm, "y", None),
|
||||
},
|
||||
)
|
||||
|
||||
@@ -1241,6 +1248,30 @@ class AareDAQ:
|
||||
centre_of_mass=None,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _grid_image_id_from_centre_offset(
|
||||
*,
|
||||
x_mm: float,
|
||||
y_mm: float,
|
||||
request: RasterGridRequest,
|
||||
) -> int:
|
||||
if request.grid_size_mm.x <= 0 or request.grid_size_mm.y <= 0:
|
||||
raise ValueError("grid_size_mm must be positive")
|
||||
if request.n_x < 1 or request.n_y < 1:
|
||||
raise ValueError("Raster grid dimensions must be >= 1")
|
||||
|
||||
grid_x = floor(x_mm / request.grid_size_mm.x) + 1
|
||||
grid_y = floor(y_mm / request.grid_size_mm.y) + 1
|
||||
|
||||
grid_x = min(max(1, grid_x), request.n_x)
|
||||
grid_y = min(max(1, grid_y), request.n_y)
|
||||
|
||||
return grid_to_image_id(
|
||||
grid_x=grid_x,
|
||||
grid_y=grid_y,
|
||||
number_of_cols=request.n_x,
|
||||
)
|
||||
|
||||
def __raster(self, request: RasterGridRequest, wait_for_screenshot: float | None = 0.2) -> CompletedRasterGridElem:
|
||||
smargon_top_left =request.smargon_top_left
|
||||
self.__devs.set_smargon_pos(
|
||||
@@ -1273,7 +1304,7 @@ class AareDAQ:
|
||||
try:
|
||||
if self.sample is not None and self.sample.db_id is not None:
|
||||
self.__aare.send_sample_event(self.sample, SampleEventType.RASTERING,
|
||||
comment=f"Raster at {request.omega_deg} deg")
|
||||
comment=f"Raster at {request.omega_deg:.1f} deg")
|
||||
self.__aare.create_gridscan_run(self.sample, request, status)
|
||||
|
||||
if not self.__cfg.simulated_detector:
|
||||
@@ -1291,7 +1322,6 @@ class AareDAQ:
|
||||
time_sec=request.exp_time_s,
|
||||
run_async=True,
|
||||
)
|
||||
|
||||
self.__devs.aerotech.wait_till_done(timeout=int(round(total_time * 2, 0)))
|
||||
# go back to aerotech x,y,z home not U home (0 degrees).
|
||||
if isinstance(self.__cfg.abr_meas_pos, Coordinate):
|
||||
@@ -1352,8 +1382,10 @@ class AareDAQ:
|
||||
file_prefix=request.file_prefix,
|
||||
image_count=request.n_x * request.n_y,
|
||||
)
|
||||
com = None
|
||||
else:
|
||||
scan_result = self.__jfjoch.wait_till_done(60)
|
||||
com = None
|
||||
if scan_result is None:
|
||||
logger.error(
|
||||
"JFJoch returned no ScanResult for raster",
|
||||
@@ -1374,7 +1406,7 @@ class AareDAQ:
|
||||
self.__set_state(BeamlineStateEnum.XtalSnapshot)
|
||||
if wait_for_screenshot and wait_for_screenshot > 0:
|
||||
time.sleep(wait_for_screenshot)
|
||||
self.save_screenshot_db(sample_id, f"{sample_id}_post_raster_{request.omega_deg}deg")
|
||||
self.save_screenshot_db(sample_id, f"{sample_id}_post_raster_{int(request.omega_deg)}deg")
|
||||
self.__aare.ingest_gridscan(
|
||||
sample=self.sample,
|
||||
raster_result=scan_result,
|
||||
@@ -1383,10 +1415,22 @@ class AareDAQ:
|
||||
com=None,
|
||||
beam_mark_pxl=self.__cfg.get_beam_mark(self.zoom),
|
||||
)
|
||||
if com is not None and com.max_image is not None:
|
||||
diffraction_image_filename = f"{self.sample.db_id}_best_diffraction_from_raster_image_{com.max_image}"
|
||||
diffraction_image_id = com.max_image
|
||||
else:
|
||||
diffraction_image_filename = f"{self.sample.db_id}_diffraction_image_near_grid_scan"
|
||||
diffraction_image_id = self._grid_image_id_from_centre_offset(
|
||||
x_mm=x,
|
||||
y_mm=y,
|
||||
request=request,
|
||||
)
|
||||
diffraction_image = self.__jfjoch.get_diffraction_image(diffraction_image_id)
|
||||
self.__aare.upload_jpg(self.sample.db_id, diffraction_image_filename, diffraction_image)
|
||||
self.__aare.send_sample_event(
|
||||
self.sample,
|
||||
event_type=SampleEventType.RASTERED,
|
||||
comment=f"Raster completed at {request.omega_deg} deg"
|
||||
comment=f"Raster completed at {request.omega_deg:.1f} deg"
|
||||
)
|
||||
|
||||
logger.info(
|
||||
@@ -2048,6 +2092,142 @@ class AareDAQ:
|
||||
)
|
||||
return calculated_target
|
||||
|
||||
def _auto_center_line_scan_top_left(
|
||||
self,
|
||||
*,
|
||||
omega_deg: float,
|
||||
file_prefix: str | None,
|
||||
grid_size_mm: Coordinate,
|
||||
default_n_y: int = 50,
|
||||
y_retarget_threshold_mm: float | None = None,
|
||||
y_padding_fraction_each_side: float = 0.10,
|
||||
) -> tuple[SmargonCoordinate, int]:
|
||||
geom = self.sample_geometry
|
||||
beam_x_pxl = geom.beam_location_pxl.x
|
||||
beam_y_pxl = geom.beam_location_pxl.y
|
||||
|
||||
line_scan_centre = geom.picture_to_smargon(
|
||||
Coordinate(x=beam_x_pxl, y=beam_y_pxl)
|
||||
)
|
||||
n_y = default_n_y
|
||||
|
||||
prediction_result: MLBoxPredictionResult = self.__mlbox.predict(
|
||||
preferred_class=(3, 0),
|
||||
return_image=False,
|
||||
return_bundle_meta=True,
|
||||
)
|
||||
self._log_ml_bundle_meta(
|
||||
f"auto_center_line_scan_{omega_deg:.2f}deg",
|
||||
target_point=prediction_result.target_point,
|
||||
focus=prediction_result.focus,
|
||||
)
|
||||
|
||||
target_point = prediction_result.target_point
|
||||
prediction_box = prediction_result.box
|
||||
|
||||
if target_point is not None:
|
||||
target_y_pxl = target_point[1]
|
||||
y_delta_mm = abs(target_y_pxl - beam_y_pxl) * geom.pixel_in_mm
|
||||
|
||||
if y_retarget_threshold_mm is None:
|
||||
y_retarget_threshold_mm = geom.beam_size_mm.y * 2.0
|
||||
|
||||
if y_delta_mm > y_retarget_threshold_mm:
|
||||
line_scan_centre = geom.picture_to_smargon(
|
||||
Coordinate(x=beam_x_pxl, y=target_y_pxl)
|
||||
)
|
||||
logger.info(
|
||||
"Using ML target y for second auto-center raster",
|
||||
extra={
|
||||
"file_prefix": file_prefix,
|
||||
"omega_deg": omega_deg,
|
||||
"beam_y_pxl": beam_y_pxl,
|
||||
"target_y_pxl": target_y_pxl,
|
||||
"y_delta_mm": y_delta_mm,
|
||||
"threshold_mm": y_retarget_threshold_mm,
|
||||
"target_sh_x_mm": line_scan_centre.x,
|
||||
"target_sh_y_mm": line_scan_centre.y,
|
||||
"target_sh_z_mm": line_scan_centre.z,
|
||||
},
|
||||
)
|
||||
else:
|
||||
logger.info(
|
||||
"Keeping beam-centred y line scan because ML target y shift is small",
|
||||
extra={
|
||||
"file_prefix": file_prefix,
|
||||
"omega_deg": omega_deg,
|
||||
"beam_y_pxl": beam_y_pxl,
|
||||
"target_y_pxl": target_y_pxl,
|
||||
"y_delta_mm": y_delta_mm,
|
||||
"threshold_mm": y_retarget_threshold_mm,
|
||||
},
|
||||
)
|
||||
else:
|
||||
logger.info(
|
||||
"No ML target point for second auto-center raster; using beam-centred line scan",
|
||||
extra={
|
||||
"file_prefix": file_prefix,
|
||||
"omega_deg": omega_deg,
|
||||
"beam_x_pxl": beam_x_pxl,
|
||||
"beam_y_pxl": beam_y_pxl,
|
||||
},
|
||||
)
|
||||
|
||||
if prediction_box is not None and prediction_box.box is not None and grid_size_mm.y > 0:
|
||||
box_height_pxl = abs(prediction_box.box.bottom_y - prediction_box.box.top_y)
|
||||
padded_height_mm = box_height_pxl * geom.pixel_in_mm * (1.0 + 2.0 * y_padding_fraction_each_side)
|
||||
n_y = max(1, int(ceil(padded_height_mm / grid_size_mm.y)))
|
||||
logger.info(
|
||||
"Computed second auto-center raster y size from ML box height",
|
||||
extra={
|
||||
"file_prefix": file_prefix,
|
||||
"omega_deg": omega_deg,
|
||||
"box_height_pxl": box_height_pxl,
|
||||
"pixel_in_mm": geom.pixel_in_mm,
|
||||
"grid_size_y_mm": grid_size_mm.y,
|
||||
"padding_fraction_each_side": y_padding_fraction_each_side,
|
||||
"padded_height_mm": padded_height_mm,
|
||||
"computed_n_y": n_y,
|
||||
},
|
||||
)
|
||||
else:
|
||||
logger.info(
|
||||
"Using default y size for second auto-center raster",
|
||||
extra={
|
||||
"file_prefix": file_prefix,
|
||||
"omega_deg": omega_deg,
|
||||
"default_n_y": default_n_y,
|
||||
"has_prediction_box": prediction_box is not None and prediction_box.box is not None,
|
||||
},
|
||||
)
|
||||
|
||||
offset = Coordinate(
|
||||
x=-grid_size_mm.x / 2.0,
|
||||
y=-(n_y - 1) * grid_size_mm.y / 2.0,
|
||||
)
|
||||
top_left = SmargonCoordinate(
|
||||
sh_mm=line_scan_centre + geom.smargon_nudge(offset),
|
||||
phi_deg=geom.smargon.phi_deg,
|
||||
chi_deg=geom.smargon.chi_deg,
|
||||
)
|
||||
|
||||
logger.info(
|
||||
"Prepared second auto-center raster top-left from helper",
|
||||
extra={
|
||||
"file_prefix": file_prefix,
|
||||
"omega_deg": omega_deg,
|
||||
"n_y": n_y,
|
||||
"offset_x_mm": offset.x,
|
||||
"offset_y_mm": offset.y,
|
||||
"offset_z_mm": offset.z,
|
||||
"top_left_x_mm": getattr(top_left.sh_mm, "x", None),
|
||||
"top_left_y_mm": getattr(top_left.sh_mm, "y", None),
|
||||
"top_left_z_mm": getattr(top_left.sh_mm, "z", None),
|
||||
},
|
||||
)
|
||||
|
||||
return top_left, n_y
|
||||
|
||||
def __loop_center_sequence(
|
||||
self,
|
||||
sample_id: Optional[int] = None,
|
||||
|
||||
Reference in New Issue
Block a user