Skip to content

agipdutils_ff

BadPixelsFF

Bases: IntFlag

The SlopesFF Bad Pixel Encoding

This is only used internally in the AGIPD FF notebooks and must always be converted to corresponding values of BadPixels before saving to file.

Source code in /usr/src/app/checkouts/readthedocs.org/user_builds/european-xfel-offline-calibration/envs/latest/lib/python3.8/site-packages/cal_tools/agipdutils_ff.py
class BadPixelsFF(IntFlag):
    """ The SlopesFF Bad Pixel Encoding

    This is only used internally in the AGIPD FF notebooks and must
    always be converted to corresponding values of BadPixels before
    saving to file.
    """

    FIT_FAILED               = 0b000000000000000000001 # bit 1
    CHI2_THRESHOLD           = 0b000000000000000000010 # bit 2
    NOISE_PEAK_THRESHOLD     = 0b000000000000000000100 # bit 3
    GAIN_THRESHOLD           = 0b000000000000000001000 # bit 4
    PEAK_WIDTH_THRESHOLD     = 0b000000000000000010000 # bit 5
    ACCURATE_COVAR           = 0b000000000000000100000 # bit 6
    BAD_DARK                 = 0b000000000000001000000 # bit 6
    NO_ENTRY                 = 0b000000000000010000000 # bit 7
    GAIN_DEVIATION           = 0b000000000000100000000 # bit 8

fit_n_peaks(x, y, pars, x_range, do_minos=False, n_peaks=4, fix_d01=True, sigma_limit=0)

Fit histogram with n-Gaussian function.

:param x: Center of bins of the histogram :param y: Value of bins of the histogram :param pars: Dictionary of initial parameters for fitting :param x_range: x Range to be considered for the fitting :param do_minos: Run Minos if True :param n_peaks: Number of Gaussian peaks to fit (min 2, max 4) :param fix_d01: Fix position of peaks to the distance between noise and first photon peak. :param sigma_limit: Repeat fit keeping only bins within mu +- sigma_limit sigma :return: minuit object

Source code in /usr/src/app/checkouts/readthedocs.org/user_builds/european-xfel-offline-calibration/envs/latest/lib/python3.8/site-packages/cal_tools/agipdutils_ff.py
def fit_n_peaks(x: np.ndarray,
                y: np.ndarray,
                pars: Dict[str, Any],
                x_range: Tuple[float, float],
                do_minos: Optional[bool] = False,
                n_peaks: Optional[int] = 4,
                fix_d01: Optional[bool] = True,
                sigma_limit: Optional[float] = 0
               ) -> Minuit:
    """
    Fit histogram with n-Gaussian function.

    :param x: Center of bins of the histogram
    :param y: Value of bins of the histogram
    :param pars: Dictionary of initial parameters for fitting
    :param x_range: x Range to be considered for the fitting
    :param do_minos: Run Minos if True
    :param n_peaks: Number of Gaussian peaks to fit (min 2, max 4)
    :param fix_d01: Fix position of peaks to the distance between noise and
    first photon peak.
    :param sigma_limit: Repeat fit keeping only bins within mu +-
    sigma_limit sigma
    :return: minuit object
    """
    sel = (x >= x_range[0]) & (x < x_range[1])

    # Square of bin errors
    yrr2 = np.copy(y)
    yrr2[yrr2 == 0] = 1  # bins with zero events have error=1

    if fix_d01:
        pars['fix_g2mean'] = True
        pars['fix_g3mean'] = True

    if n_peaks < 4:
        pars['g3n'] = 0
        pars['fix_g3n'] = True
        pars['g3sigma'] = 1
        pars['fix_g3sigma'] = True
        pars['fix_g3mean'] = True

    if n_peaks < 3:
        pars['g2n'] = 0
        pars['fix_g2n'] = True
        pars['g2sigma'] = 1
        pars['fix_g2sigma'] = True
        pars['fix_g2mean'] = True

    def chi2_f(g0n, g0mean, g0sigma,
               g1n, g1mean, g1sigma,
               g2n, g2mean, g2sigma,
               g3n, g3mean, g3sigma, ):

        d01 = (g1mean - g0mean)

        if 'fix_g2mean' in pars and pars['fix_g2mean']:
            g2mean = g0mean + d01 * 2

        if 'fix_g3mean' in pars and pars['fix_g3mean']:
            g3mean = g0mean + d01 * 3

        if g3n == 0:
            n_peaks = 3
        elif g2n == 0:
            n_peaks = 2
        else:
            n_peaks = 4

        yt = gaussian_sum(x[sel], n_peaks,
                          g0n, g0mean, g0sigma,
                          g1n, g1mean, g1sigma,
                          g2n, g2mean, g2sigma,
                          g3n, g3mean, g3sigma,)
        return np.nansum((yt - y[sel]) ** 2 / yrr2[sel])

    minuit = Minuit(chi2_f, **pars, pedantic=False)
    minuit.migrad()

    if sigma_limit > 0 :
        res = minuit.fitarg
        sel2 = (np.abs(x - res['g0mean']) < sigma_limit*res['g0sigma']) | \
               (np.abs(x - res['g1mean']) < sigma_limit*res['g1sigma']) | \
               (np.abs(x - res['g2mean']) < sigma_limit*res['g2sigma']) | \
               (np.abs(x - res['g3mean']) < sigma_limit*res['g3sigma'])
        sel = sel & sel2
        minuit.migrad()

    if do_minos:
        if minuit.get_fmin().is_valid:
            minuit.minos()

    return minuit

gaussian(x, norm=1, mean=0, sigma=1)

Return value of Gaussian function

:param x: Argument (float of 1D array) of Gaussian function :param norm: Normalization of Gaussian function :param mean: Mean parameter :param sigma: Sigma parameter :return: Value of gaussian function.

Source code in /usr/src/app/checkouts/readthedocs.org/user_builds/european-xfel-offline-calibration/envs/latest/lib/python3.8/site-packages/cal_tools/agipdutils_ff.py
def gaussian(x: np.ndarray, norm: int = 1, mean: int = 0, sigma: int = 1) -> float:  # noqa
    """
    Return value of Gaussian function

    :param x: Argument (float of 1D array) of Gaussian function
    :param norm: Normalization of Gaussian function
    :param mean: Mean parameter
    :param sigma: Sigma parameter
    :return: Value of gaussian function.
    """
    return norm * np.exp(-1 / 2 * ((x - mean) / sigma) ** 2) / (sigma * np.sqrt(2 * np.pi))  # noqa

gaussian_sum(x, ng=4, *p)

Sum of ng Gaussian functions

:param x: Argument (float of 1D array) of the function :param ng: Number of Gaussian functions :param p: List of parameters (norm1,mean1,sigma1,norm2,mean2,sigma2,...)

Source code in /usr/src/app/checkouts/readthedocs.org/user_builds/european-xfel-offline-calibration/envs/latest/lib/python3.8/site-packages/cal_tools/agipdutils_ff.py
def gaussian_sum(x: np.ndarray, ng: int = 4, *p: Tuple[Any]) -> float:
    """Sum of ng Gaussian functions

    :param x: Argument (float of 1D array) of the function
    :param ng: Number of Gaussian functions
    :param p: List of parameters (norm1,mean1,sigma1,norm2,mean2,sigma2,...)
    """
    r = 0.
    for i in range(ng):
        r += gaussian(x, *p[i * 3:(i + 1) * 3])
    return r

get_mask(fit_summary, peak_lim, d0_lim, chi2_lim, peak_width_lim)

Calculate Bad pixels mask based on fit results and given limits

:param fit_summary: Dictionary of the fit output from Multi-Gaussian fit :param peak_lim: Limits on noise peak position :param d0_lim: Limits on distance between noise and first photon peak :param chi2_lim: Limits on reduced chi^2 value :param peak_width_lim: Limits on noise peak width :return: Bad pixel mask

Source code in /usr/src/app/checkouts/readthedocs.org/user_builds/european-xfel-offline-calibration/envs/latest/lib/python3.8/site-packages/cal_tools/agipdutils_ff.py
def get_mask(fit_summary: Dict[str, Any],
             peak_lim: List,
             d0_lim: List,
             chi2_lim: List,
             peak_width_lim: np.array) -> int:
    """
    Calculate Bad pixels mask based on fit results and given limits

    :param fit_summary: Dictionary of the fit output from Multi-Gaussian fit
    :param peak_lim: Limits on noise peak position
    :param d0_lim: Limits on distance between noise and first photon peak
    :param chi2_lim: Limits on reduced chi^2 value
    :param peak_width_lim: Limits on noise peak width
    :return: Bad pixel mask
    """
    if not fit_summary['is_valid']:
        return BadPixelsFF.FIT_FAILED

    m0 = fit_summary['g0mean']
    s0 = fit_summary['g0sigma']
    s1 = fit_summary['g1sigma']
    s2 = fit_summary['g2sigma']
    chi2_ndof = fit_summary['chi2_ndof']
    d01 = fit_summary['g1mean'] - m0

    mask = 0
    if not fit_summary['has_accurate_covar']:
        mask |= BadPixelsFF.ACCURATE_COVAR

    if not peak_lim[0] <= m0 <= peak_lim[1]:
        mask |= BadPixelsFF.NOISE_PEAK_THRESHOLD

    if not d0_lim[0] <= d01 <= d0_lim[1]:
        mask |= BadPixelsFF.GAIN_THRESHOLD

    if not chi2_lim[0] <= chi2_ndof <= chi2_lim[1]:
        mask |= BadPixelsFF.CHI2_THRESHOLD

    width_lim = peak_width_lim[0] * s0
    inside_s1 = width_lim[0] <= s1 <= width_lim[1]

    width_lim = peak_width_lim[1] * s0
    inside_s2 = width_lim[0] <= s2 <= width_lim[1]

    if not inside_s1 and inside_s2:
        mask |= BadPixelsFF.PEAK_WIDTH_THRESHOLD

    return mask

get_starting_parameters(xe, ye, limits, n_peaks=3, f_lim=2)

Estimate starting parameters for Gaussian fit of several peaks.

:param xe: Center of bins of the histogram :param ye: Value of bins of the histogram :param limits: Position of each peak ((left1, right1), (left2, right2), ...) to be considered. :param n_peaks: Number of peaks :param f_lim: Limits in units of standard deviation to consider

Source code in /usr/src/app/checkouts/readthedocs.org/user_builds/european-xfel-offline-calibration/envs/latest/lib/python3.8/site-packages/cal_tools/agipdutils_ff.py
def get_starting_parameters(xe: np.ndarray,
                            ye: np.ndarray,
                            limits: np.ndarray,
                            n_peaks: int = 3,
                            f_lim: int = 2) -> Tuple[Dict[str, Any], List[Tuple]]:  # noqa
    """
    Estimate starting parameters for Gaussian fit of several peaks.

    :param xe: Center of bins of the histogram
    :param ye: Value of bins of the histogram
    :param limits: Position of each peak ((left1, right1),
    (left2, right2), ...) to be considered.
    :param n_peaks: Number of peaks
    :param f_lim: Limits in units of standard deviation to consider
    """
    parameters = {}
    shapes = []
    for peak in range(n_peaks):
        n, m, rms, idx = get_statistical_parameters(xe, ye, limits[peak])
        limits2 = [m - f_lim * rms, m + f_lim * rms]
        n, m, rms, idx = get_statistical_parameters(xe, ye, limits2)
        shapes.append((n, m, rms, idx))

        parameters.update({f'g{peak}sigma': rms,
                           f'g{peak}n': float(n),
                           f'g{peak}mean': m})
    return parameters, shapes

get_statistical_parameters(x, y, x_range)

Return statistical parameters of selected part of a histogram.

:param x: Center of bins of the histogram :param y: Value of bins of the histogram :param x_range: x range to be considered :return: Sum of histogram, Mean value, Standard deviation, List of selected bins

Source code in /usr/src/app/checkouts/readthedocs.org/user_builds/european-xfel-offline-calibration/envs/latest/lib/python3.8/site-packages/cal_tools/agipdutils_ff.py
def get_statistical_parameters(x: np.ndarray,
                               y: np.ndarray,
                               x_range: List) -> Tuple[np.uint64, np.float64, np.float64, np.ndarray]:  # noqa
    """Return statistical parameters of selected part of a histogram.

    :param x: Center of bins of the histogram
    :param y: Value of bins of the histogram
    :param x_range: x range to be considered
    :return: Sum of histogram, Mean value, Standard deviation,
             List of selected bins
    """
    # TODO: Check if wq.median works better than mean
    sel = (x >= x_range[0]) & (x < x_range[1])
    h_sum = np.sum(y[sel])
    h_norm = y[sel] / h_sum
    h_mean = np.sum(h_norm * x[sel])
    h_sqr = (x[sel] - h_mean) ** 2
    h_std = np.sqrt(np.sum(h_norm * h_sqr))

    return h_sum, h_mean, h_std, sel

set_par_limits(pars, peak_range, peak_norm_range, peak_width_range, n_peaks=4)

Set limits on initial fit parameters based on given values

:param pars: Dictionary of initial fit parameters :param peak_range: Limits on peak positions :param peak_norm_range: Limits on normalization of Gaussian peaks :param peak_width_range: Limits on width of Gaussian peaks :param n_peaks: Number of Gaussian peaks

Source code in /usr/src/app/checkouts/readthedocs.org/user_builds/european-xfel-offline-calibration/envs/latest/lib/python3.8/site-packages/cal_tools/agipdutils_ff.py
def set_par_limits(pars: Dict[str, Any],
                   peak_range: np.ndarray,
                   peak_norm_range: np.ndarray,
                   peak_width_range: np.ndarray,
                   n_peaks: Optional[int] = 4):
    """
    Set limits on initial fit parameters based on given values

    :param pars: Dictionary of initial fit parameters
    :param peak_range: Limits on peak positions
    :param peak_norm_range: Limits on normalization of Gaussian peaks
    :param peak_width_range: Limits on width of Gaussian peaks
    :param n_peaks: Number of Gaussian peaks
    """
    for peak in range(n_peaks):
        pars.update({f'limit_g{peak}n': peak_norm_range[peak],
                     f'limit_g{peak}mean': peak_range[peak],
                     f'limit_g{peak}sigma': peak_width_range[peak],
                     })