Skip to content

Algorithms

This module defines the algorithms used to process the data.

calculate_detector_center_on_a_frame(calibrated_data, memory_cell_id, config, PF8Config)

Calculate the detector center on a frame.

Parameters:

Name Type Description Default
calibrated_data array

The data in which the center determination will be performed.

required
memory_cell_id int

The memory cell id of the frame, only necessary when operating in storage cell mode.

required
config dict

A configuration dictionary in the format expected by beambusters.

required
PF8Config PF8Info

Peakfinder8 parameters.

required

Returns:

Name Type Description
results list

A list with the calculated detector center shit in x and y in mm, if it is a hit, if it was pre-centered and if the center was refined.

Source code in beambusters/algorithms.py
def calculate_detector_center_on_a_frame(
    calibrated_data: np.array, memory_cell_id: int, config: dict, PF8Config: PF8Info
) -> list:
    """
    Calculate the detector center on a frame.

    Args:
        calibrated_data (np.array): The data in which the center determination will be performed.

        memory_cell_id (int): The memory cell id of the frame, only necessary when operating in storage cell mode.

        config (dict): A configuration dictionary in the format expected by beambusters.

        PF8Config (PF8Info): Peakfinder8 parameters.

    Returns:
        results (list): A list with the calculated detector center shit in x and y in mm, if it is a hit, if it was pre-centered and if the center was refined.
    """
    plots_info = {"filename": "", "folder_name": "", "root_path": ""}
    config["plots_flag"] = False

    if "center_of_mass" not in config["skip_centering_methods"]:
        center_of_mass_method = CenterOfMass(
            config=config, PF8Config=PF8Config, plots_info=plots_info
        )
        detector_center_from_center_of_mass = center_of_mass_method(
            data=calibrated_data
        )
    else:
        detector_center_from_center_of_mass = [-1, -1]
    if "circle_detection" not in config["skip_centering_methods"]:
        for rank in range(config["hough"]["maximum_rank"]):
            config["hough_rank"] = rank
            circle_detection_method = CircleDetection(
                config=config, PF8Config=PF8Config, plots_info=plots_info
            )
            detector_center_from_circle_detection = circle_detection_method(
                data=calibrated_data
            )

            ## Calculate distance from the calculated center to the reference point in each axis
            distance_in_x = math.sqrt(
                (
                    detector_center_from_circle_detection[0]
                    - config["reference_center"]["x"]
                )
                ** 2
            )

            distance_in_y = math.sqrt(
                (
                    detector_center_from_circle_detection[1]
                    - config["reference_center"]["y"]
                )
                ** 2
            )

            if (
                distance_in_x < config["hough"]["outlier_distance"]["x"]
                and distance_in_y < config["hough"]["outlier_distance"]["y"]
            ):
                break
        ## Check for the case where rank reached the maximum value and the detector center is not within the allowed region
        else:
            detector_center_from_circle_detection = [-1, -1]
    else:
        detector_center_from_circle_detection = [-1, -1]
    if "minimize_peak_fwhm" not in config["skip_centering_methods"]:
        minimize_peak_fwhm_method = MinimizePeakFWHM(
            config=config, PF8Config=PF8Config, plots_info=plots_info
        )
        detector_center_from_minimize_peak_fwhm = minimize_peak_fwhm_method(
            data=calibrated_data, initial_guess=detector_center_from_circle_detection
        )
    else:
        detector_center_from_minimize_peak_fwhm = [-1, -1]

    ## Define the initial_guess
    initial_guess = [-1, -1]
    pre_centering_flag = 0
    is_a_hit = 0
    refined_center_flag = 0

    if config["centering_method_for_initial_guess"] == "center_of_mass":
        calculated_detector_center = detector_center_from_center_of_mass
        distance_in_x = math.sqrt(
            (calculated_detector_center[0] - config["reference_center"]["x"]) ** 2
        )
        distance_in_y = math.sqrt(
            (calculated_detector_center[1] - config["reference_center"]["y"]) ** 2
        )

        if (
            distance_in_x < config["outlier_distance"]["x"]
            and distance_in_y < config["outlier_distance"]["y"]
        ):
            pre_centering_flag = 1
            initial_guess = detector_center_from_center_of_mass
    elif config["centering_method_for_initial_guess"] == "circle_detection":
        calculated_detector_center = detector_center_from_circle_detection
        distance_in_x = math.sqrt(
            (calculated_detector_center[0] - config["reference_center"]["x"]) ** 2
        )
        distance_in_y = math.sqrt(
            (calculated_detector_center[1] - config["reference_center"]["y"]) ** 2
        )
        if (
            distance_in_x < config["outlier_distance"]["x"]
            and distance_in_y < config["outlier_distance"]["y"]
        ):
            pre_centering_flag = 1
            initial_guess = detector_center_from_circle_detection
    elif config["centering_method_for_initial_guess"] == "minimize_peak_fwhm":
        calculated_detector_center = detector_center_from_minimize_peak_fwhm
        distance_in_x = math.sqrt(
            (calculated_detector_center[0] - config["reference_center"]["x"]) ** 2
        )
        distance_in_y = math.sqrt(
            (calculated_detector_center[1] - config["reference_center"]["y"]) ** 2
        )

        if (
            distance_in_x < config["outlier_distance"]["x"]
            and distance_in_y < config["outlier_distance"]["y"]
        ):
            pre_centering_flag = 1
            initial_guess = detector_center_from_minimize_peak_fwhm
    elif config["centering_method_for_initial_guess"] == "manual_input":
        initial_guess = [
            config["manual_input"][f"{memory_cell_id}"]["x"],
            config["manual_input"][f"{memory_cell_id}"]["y"],
        ]

    # If the method chosen didn't converge change to the detector center from the geometry file
    if initial_guess[0] == -1 and initial_guess[1] == -1:
        initial_guess = PF8Config.detector_center_from_geom

    # Force center override the initial guess calculated to coordinates defined in config
    if config["force_center"]["state"]:
        if config["force_center"]["anchor_x"]:
            initial_guess[0] = config["force_center"]["x"]
        if config["force_center"]["anchor_y"]:
            initial_guess[1] = config["force_center"]["y"]

    # Compares if the calculated center is within the outlier distance in each axis
    distance_in_x = math.sqrt((initial_guess[0] - config["reference_center"]["x"]) ** 2)
    distance_in_y = math.sqrt((initial_guess[1] - config["reference_center"]["y"]) ** 2)

    # Start refine the detector center by FriedelPairs
    center_is_refined = False

    if (
        distance_in_x < config["outlier_distance"]["x"]
        and distance_in_y < config["outlier_distance"]["y"]
    ):

        ## Ready for detector center refinement
        PF8Config.update_pixel_maps(
            initial_guess[0] - PF8Config.detector_center_from_geom[0],
            initial_guess[1] - PF8Config.detector_center_from_geom[1],
        )
        pf8 = PF8(PF8Config)
        peak_list = pf8.get_peaks_pf8(data=calibrated_data)

        if config["vds_format"] and config["vds_id"] == "vds_spb_jf4m":
            geometry_filename = (
                config["geometry_file"].split(".geom")[0] + "_hyperslab.geom"
            )
        else:
            geometry_filename = config["geometry_file"]

        PF8Config.set_geometry_from_file(geometry_filename)

        if (
            "friedel_pairs" not in config["skip_centering_methods"]
            and peak_list["num_peaks"] > config["pf8"]["min_num_peaks"]
        ):
            is_a_hit = 1
            friedel_pairs_method = FriedelPairs(
                config=config, PF8Config=PF8Config, plots_info=plots_info
            )
            detector_center_from_friedel_pairs = friedel_pairs_method(
                data=calibrated_data, initial_guess=initial_guess
            )
            if centering_converged(detector_center_from_friedel_pairs):
                center_is_refined = True
            else:
                center_is_refined = False
    else:
        center_is_refined = False
    ## Refined detector center assignement
    if center_is_refined:
        refined_detector_center = detector_center_from_friedel_pairs
        refined_center_flag = 1
    else:
        refined_detector_center = initial_guess

    # Global offset
    if "offset" in config:
        if "x" in config["offset"]:
            refined_detector_center[0] += config["offset"]["x"]
        if "y" in config["offset"]:
            refined_detector_center[1] += config["offset"]["y"]

    beam_position_shift_in_pixels = [
        refined_detector_center[x] - PF8Config.detector_center_from_geom[x]
        for x in range(2)
    ]

    detector_shift_in_mm = [
        round(-1 * x * 1e3 / PF8Config.pixel_resolution, 4)
        for x in beam_position_shift_in_pixels
    ]
    detector_shift_x_in_mm = detector_shift_in_mm[0]
    detector_shift_y_in_mm = detector_shift_in_mm[1]

    return [
        detector_shift_x_in_mm,
        detector_shift_y_in_mm,
        is_a_hit,
        pre_centering_flag,
        refined_center_flag,
    ]