Source code for ewoksxrdct.tasks.read_aeroystepscan

import os
from pathlib import Path

from ewokscore import Task

from .utils.hdf5 import load_hdf5_path
from .utils.hdf5 import open_hdf5_file
from .utils.read_models import ReadInputModel
from .utils.read_models import ReadOutputModel
from .utils.validate import validate_frame_count
from .utils.validate import validate_motor_counts


[docs] class ReadAeroystepscan( Task, input_model=ReadInputModel, output_model=ReadOutputModel, ): """This task assumes the bliss master file follows ESRF's beamline conventions for aeroystepscans. The master file must contain: - `measurement/{translation_motor_name}`: 1D translation positions - `measurement/{rotation_motor_name}`: 1D rotation angles - `instrument/fscan_parameters/x_range`: scalar, total rotation range - `instrument/fscan_parameters/x_step_size`: scalar, rotation step size - `instrument/fscan_parameters/x_start_pos`: scalar, rotation start position - `instrument/fscan_parameters/y_start_pos`: scalar, translation start position - `instrument/fscan_parameters/y_step_size_arr`: scalar, translation step size - `instrument/fscan_parameters/y_npoints_arr`: scalar, number of translation points """
[docs] def run(self) -> None: """Execute the task to read the raw motor and azimuthally integrated data for aeroystepscans (ESRF-only) and derive the grid info needed for regridding.""" bliss_master = self.inputs.bliss_master_path with open_hdf5_file(bliss_master) as f: file = Path(bliss_master).name scan = f"{self.inputs.scan_number}.1" translations = load_hdf5_path( f, f"{scan}/measurement/{self.inputs.translation_motor_name}", file )[()] rotations = load_hdf5_path( f, f"{scan}/measurement/{self.inputs.rotation_motor_name}", file )[()] x_range = load_hdf5_path( f, f"{scan}/instrument/fscan_parameters/x_range", file )[()].item() x_step = load_hdf5_path( f, f"{scan}/instrument/fscan_parameters/x_step_size", file )[()].item() x_start = load_hdf5_path( f, f"{scan}/instrument/fscan_parameters/x_start_pos", file )[()].item() y_start = load_hdf5_path( f, f"{scan}/instrument/fscan_parameters/y_start_pos", file )[()].item() y_step = load_hdf5_path( f, f"{scan}/instrument/fscan_parameters/y_step_size_arr", file )[()].item() y_points = load_hdf5_path( f, f"{scan}/instrument/fscan_parameters/y_npoints_arr", file )[()].item() N_trans = y_points # x_range is already a span (last trigger minus first trigger), not # an absolute end position, so x_start does not factor into the # point count -- see fscan's AeroScanXYSMaster.validate(). N_rot = int(x_range / x_step) validate_motor_counts(N_trans * N_rot, translations, rotations) ai_filename = self.inputs.integration_output_path with open_hdf5_file(ai_filename) as f: ai_file = Path(ai_filename).name radial_axis = load_hdf5_path( f, self.inputs.integration_radial_axis_path, ai_file )[()] intensity = load_hdf5_path( f, self.inputs.integration_intensity_path, ai_file )[()] # Check the data sizing will be consistent in the final NX file. validate_frame_count(N_trans * N_rot, intensity) self.outputs.rotation_angles = rotations self.outputs.translation_values = translations self.outputs.integration_intensity_values = intensity self.outputs.integration_radial_axis = os.path.basename( self.inputs.integration_radial_axis_path ) self.outputs.integration_radial_axis_values = radial_axis # The rotation motor records the center of each angular step (see # fscan's MusstCenterCalc), not its start. self.outputs.rotation_grid_params = ( x_start + x_step / 2, x_start + x_range - x_step / 2, N_rot, ) self.outputs.translation_grid_params = ( y_start, y_start + ((y_points - 1) * y_step), N_trans, )