1818from sciagent .message_proc import print_message
1919
2020from eaa .tool .imaging .acquisition import AcquireImage
21+ from eaa .tool .imaging .line_scan_predictor import LineScanPredictor
2122from eaa .tool .imaging .param_tuning import SetParameters
2223from eaa .task_manager .tuning .base import BaseParameterTuningTaskManager
2324from eaa .tool .imaging .registration import ImageRegistration
@@ -62,6 +63,7 @@ def __init__(
6263 run_offset_calibration : bool = True ,
6364 use_linear_drift_prediction : bool = False ,
6465 n_parameter_drift_points_before_prediction : int = 3 ,
66+ line_scan_predictor_tool : Optional [LineScanPredictor ] = None ,
6567 * args , ** kwargs
6668 ):
6769 """Analytical scanning microscope focusing task manager driven
@@ -138,6 +140,14 @@ def __init__(
138140 n_parameter_drift_points_before_prediction : int, optional
139141 Number of parameter-drift samples to collect before using linear
140142 drift prediction for image acquisitions.
143+ line_scan_predictor_tool : LineScanPredictor, optional
144+ If provided, this tool is used instead of image registration to
145+ update scan positions after each 2D acquisition. It predicts the
146+ optimal line scan center from the reference image, reference line
147+ scan position, and current image, then shifts both line scan and
148+ image acquisition kwargs by the predicted drift so they stay in
149+ sync. Requires ``run_offset_calibration=True`` so that a 2D image
150+ is acquired before the prediction is made.
141151 """
142152 if acquisition_tool is None :
143153 raise ValueError ("`acquisition_tool` must be provided." )
@@ -177,6 +187,13 @@ def __init__(
177187 self .run_line_scan_checker = run_line_scan_checker
178188 self .run_offset_calibration = run_offset_calibration
179189 self .use_linear_drift_prediction = use_linear_drift_prediction
190+ if line_scan_predictor_tool is not None and not run_offset_calibration :
191+ raise ValueError (
192+ "`line_scan_predictor_tool` requires `run_offset_calibration=True` "
193+ "because a 2D image must be acquired before the predictor can run."
194+ )
195+
196+ self .line_scan_predictor_tool = line_scan_predictor_tool
180197 self .n_parameter_drift_points_before_prediction = (
181198 n_parameter_drift_points_before_prediction
182199 )
@@ -868,14 +885,17 @@ def rollback_and_shrink_delta(message_prefix: str) -> np.ndarray:
868885 if self .should_apply_linear_drift_prediction ():
869886 self .apply_predicted_image_acquisition_position (x_current )
870887 self .run_2d_scan ()
871- line_scan_pos_offset , alignment_offset = self .find_offset ()
872- if np .any (np .isnan (line_scan_pos_offset )):
873- x_current = rollback_and_shrink_delta ("Image registration failed (NaN offset)." )
874- continue
875- self .apply_offset_to_line_scan_kwargs (line_scan_pos_offset )
876- self .apply_offset_to_image_acquisition_kwargs (alignment_offset )
877- self .update_linear_drift_models (x_current )
878- self .record_linear_drift_model_visualizations ()
888+ if self .line_scan_predictor_tool is not None :
889+ self .apply_line_scan_predictor_offset ()
890+ else :
891+ line_scan_pos_offset , alignment_offset = self .find_offset ()
892+ if np .any (np .isnan (line_scan_pos_offset )):
893+ x_current = rollback_and_shrink_delta ("Image registration failed (NaN offset)." )
894+ continue
895+ self .apply_offset_to_line_scan_kwargs (line_scan_pos_offset )
896+ self .apply_offset_to_image_acquisition_kwargs (alignment_offset )
897+ self .update_linear_drift_models (x_current )
898+ self .record_linear_drift_model_visualizations ()
879899 try :
880900 fwhm = self .run_line_scan ()
881901 if np .isnan (fwhm ):
@@ -886,6 +906,28 @@ def rollback_and_shrink_delta(message_prefix: str) -> np.ndarray:
886906 self .update_optimization_model (fwhm )
887907 return
888908
909+ def apply_line_scan_predictor_offset (self ) -> None :
910+ """Update scan positions using the line scan predictor.
911+
912+ Calls :meth:`LineScanPredictor.predict_line_scan_position` to obtain
913+ the predicted line scan center in the current image, computes the
914+ drift relative to the current line scan center, then shifts both
915+ ``line_scan_kwargs`` and ``image_acquisition_kwargs`` by that drift so
916+ that the two sets of coordinates stay in sync.
917+ """
918+ current_center = self .extract_scan_position (self .line_scan_kwargs )
919+ result = json .loads (self .line_scan_predictor_tool .predict_line_scan_position ())
920+ predicted_center = np .array ([result ["center_y" ], result ["center_x" ]], dtype = float )
921+ drift = predicted_center - current_center
922+ self .record_system_message (
923+ f"Line scan predictor: current center={ current_center .tolist ()} , "
924+ f"predicted center={ predicted_center .tolist ()} , "
925+ f"drift={ drift .tolist ()} "
926+ )
927+ # apply_offset_to_*_kwargs(o) does position -= o; passing -drift gives position += drift.
928+ self .apply_offset_to_line_scan_kwargs (- drift )
929+ self .apply_offset_to_image_acquisition_kwargs (- drift )
930+
889931 def apply_user_correction_offset (self ) -> bool :
890932 message = (
891933 "Manual correction requested. Enter offset-to-subtract as 'y,x' (blank to stop): "
0 commit comments