Source code for drtsans.mono.biosans.beam_finder

# local imports
import drtsans.beam_finder as bf
from drtsans.beam_finder import fbc_options_json
from drtsans.samplelogs import SampleLogs

# third party imports
from mantid import mtd
from mantid.kernel import logger
import numpy as np

# standard imports
from typing import Tuple


__all__ = ["center_detector", "find_beam_center", "fbc_options_json"]


def _beam_center_gravitational_drop(
    ws,
    beam_center_y,
    sample_det_cent_main_detector,
    sample_det_cent_curved_detector,
    vertical_offset=0.0135,
):
    """This method is used for correcting for gravitational drop by
    finding the difference in drop between the main and curved (wing or midrange)
    detectors. The center in the curved detector will be higher because
    the neutrons fall due to gravity until they hit the main detector.

    Parameters
    ----------
    ws : ~mantid.api.MatrixWorkspace, str
        The workspace to get the sample to the main detector distance
    beam_center_y : float
        The Y center coordinate in the main detector in meters
    sample_det_cent_main_detector: float
        :ref:`sample to detector center distance <devdocs-standardnames>` of the main detector
        in meters
    sample_det_cent_curved_detector : float
        :ref:`sample to detector center distance <devdocs-standardnames>` of the wing or midrange detector
        in meters
    vertical_offset: float
        :vertical offset between main detector and curved detector in m

    Returns
    -------
    float
        The new y beam center of the curved detector

    """
    sl = SampleLogs(ws)

    wavelength = np.mean(sl.wavelength.value)

    # this comes back as a positive number
    drop_main = bf._calculate_neutron_drop(sample_det_cent_main_detector, wavelength)
    drop_curved = bf._calculate_neutron_drop(sample_det_cent_curved_detector, wavelength)

    new_beam_center_y = beam_center_y + drop_main - drop_curved + (vertical_offset)
    logger.information(
        "Beam Center Y before gravity (drop = {:.3}): {:.3}"
        " after = {:.3} and vertical offset between main and curved detector= {:.3}.".format(
            drop_main - drop_curved, beam_center_y, new_beam_center_y, vertical_offset
        )
    )

    return new_beam_center_y


[docs] def find_beam_center( input_workspace, method="center_of_mass", mask=None, mask_options={}, centering_options={}, sample_det_cent_main_detector=None, sample_det_cent_wing_detector=None, sample_det_cent_midrange_detector=None, solid_angle_method="VerticalTube", ) -> Tuple[float, float, float, float, dict]: """Finds the beam center in a 2D SANS data set. This is based on (and uses) :func:`drtsans.find_beam_center` Parameters ---------- input_workspace: str, ~mantid.api.MatrixWorkspace, ~mantid.api.IEventWorkspace method: str Method to calculate the beam center. Available methods are: - 'center_of_mass', invokes :ref:`FindCenterOfMassPosition <algm-FindCenterOfMassPosition-v1>`. mask: mask file path, `MaskWorkspace``, :py:obj:`list`. Mask to be passed on to ~drtsans.mask_utils.mask_apply. mask_options: dict Additional arguments to be passed on to ~drtsans.mask_utils.mask_apply. centering_options: dict Arguments to be passed on to the centering method. sample_det_cent_wing_detector : float :ref:`sample to detector center distance <devdocs-standardnames>`, in meters, of the wing detector. solid_angle_method: bool, str specify which solid angle correction is needed Returns ------- ``(center_x, center_y, center_y_wing, center_y_midrange, fit_results)`` where - ``center_y_wing`` is used to correct BIOSANS wing detector Y position. - ``center_y_midrange`` is used to correct BIOSANS midrange detector Y position. if sample_det_cent_midrange_detector is specified then a float number is returned, else None. - ``fit_results`` produced by fitting the beam center intensities to a 2D Gaussian model of the lmfit package """ ws = mtd[str(input_workspace)] # find the center on the main detector center_x, center_y, fit_results = bf.find_beam_center( ws, method, mask, mask_options=mask_options, centering_options=centering_options, solid_angle_method=solid_angle_method, ) if sample_det_cent_main_detector is None or sample_det_cent_main_detector == 0.0: sample_det_cent_main_detector = ws.getInstrument().getComponentByName("detector1").getPos().norm() # get the distance to center of the main and wing detectors if sample_det_cent_wing_detector is None or sample_det_cent_wing_detector == 0.0: sample_det_cent_wing_detector = ws.getInstrument().getComponentByName("wing_detector").getPos().norm() if sample_det_cent_wing_detector == 0.0: try: # old IDF sample_det_cent_wing_detector = ws.getInstrument().getComponentByName("wing_tube_0").getPos().norm() except AttributeError: # new IDF sample_det_cent_wing_detector = ws.getInstrument().getComponentByName("bank49").getPos().norm() center_y_wing = _beam_center_gravitational_drop( ws, center_y, sample_det_cent_main_detector, sample_det_cent_wing_detector ) # get the distance to center of the main and the midrange detectors center_y_midrange = np.nan if sample_det_cent_midrange_detector is None or sample_det_cent_midrange_detector == 0.0: if ws.getInstrument().getComponentByName("midrange_detector") is not None: sample_det_cent_midrange_detector = ( ws.getInstrument().getComponentByName("midrange_detector").getPos().norm() ) if sample_det_cent_midrange_detector == 0.0: sample_det_cent_midrange_detector = ws.getInstrument().getComponentByName("bank89").getPos().norm() if sample_det_cent_midrange_detector is not None: # vertical offset between the South and Midrange detectors vertical_offset = 0.00 center_y_midrange = _beam_center_gravitational_drop( ws, center_y, sample_det_cent_main_detector, sample_det_cent_midrange_detector, vertical_offset=vertical_offset, ) logger.information( "Beam Center: x={:.3} y={:.3} y_wing={:.3} y_midrange={}.".format( center_x, center_y, center_y_wing, center_y_midrange ) ) return center_x, center_y, center_y_wing, center_y_midrange, fit_results
[docs] def center_detector(input_workspace, center_x, center_y, center_y_wing, center_y_midrange=None): """Center the detector and adjusts the height for the main wing and midrange detectors This uses :func:`drtsans.center_detector` **Mantid algorithms used:** :ref:`MoveInstrumentComponent <algm-MoveInstrumentComponent-v1>` Parameters ---------- input_workspace : ~mantid.api.MatrixWorkspace, str The workspace to be centered center_x : float The x-coordinate of the beam center in meters center_y : float The y-coordinate of the beam center on the main detector in meters center_y_wing : float The y-coordinate of the beam center on the wing detector in meters center_y_midrange : float The y-coordinate of the beam center on the midrange detector in meters Returns ------- ~mantid.api.MatrixWorkspace reference to the corrected ``input_workspace`` """ # move the main detector bf.center_detector(input_workspace, center_x, center_y) # move the wing detector for the gravity drop # the x position of the wing is calibrated differently bf.center_detector(input_workspace, 0, center_y_wing, component="wing_detector") # move the midrange detector for the gravity drop if center_y_midrange is not None and not np.isnan(center_y_midrange): bf.center_detector(input_workspace, 0, center_y_midrange, component="midrange_detector")