コード例 #1
0
 def uncertainty(coefficient, process, region):
     u = self.calculation(process, region)
     # self.calculation.calculation is the nominal calculation
     n = self.calculation.calculation(process, region)
     u = to_shape(u, n)
     return (None, None, multiply(coefficient, u[2]),
             multiply(coefficient, u[3]))
コード例 #2
0
ファイル: uncertainty.py プロジェクト: spiiph/owls-hep
def to_shape(uncertainty, nominal):
    """Converts an overall uncertainty to a shape uncertainty.

    If the uncertainty has no overall component, it is returned as-is.

    If the uncertainty has an overall component and a shape component, the
    shape component is disregarded and replaced by the newly converted shape
    component.

    Args:
        uncertainty: A tuple of the form
            (overall_up, overall_down, shape_up, shape_down)
        nominal: The nominal shape result

    Returns:
        A tuple of the form
            (None, None, shape_up, shape_down)
    """
    # Extract overall uncertainties
    overall_up, overall_down, _, _ = uncertainty

    # If we don't have overall components, bail
    if overall_up is None or overall_down is None:
        return uncertainty

    # Compute the result
    return (
        None,
        None,
        multiply(overall_up, nominal),
        multiply(overall_down, nominal)
    )
コード例 #3
0
def to_shape(uncertainty, nominal):
    """Converts an overall uncertainty to a shape uncertainty.

    If the uncertainty has no overall component, it is returned as-is.

    If the uncertainty has an overall component and a shape component, the
    shape component is disregarded and replaced by the newly converted shape
    component.

    Args:
        uncertainty: A tuple of the form
            (overall_up, overall_down, shape_up, shape_down)
        nominal: The nominal shape result

    Returns:
        A tuple of the form
            (None, None, shape_up, shape_down)
    """
    # Extract overall uncertainties
    overall_up, overall_down, _, _ = uncertainty

    # If we don't have overall components, bail
    if overall_up is None or overall_down is None:
        return uncertainty

    # Compute the result
    return (None, None, multiply(overall_up,
                                 nominal), multiply(overall_down, nominal))
コード例 #4
0
ファイル: estimation.py プロジェクト: spiiph/owls-hep
 def uncertainty(coefficient, process, region):
     u = self.calculation(process, region)
     # self.calculation.calculation is the nominal calculation
     n = self.calculation.calculation(process, region)
     u = to_shape(u, n)
     return (
         None,
         None,
         multiply(coefficient[1], u[2]),
         multiply(coefficient[2], u[3])
     )
コード例 #5
0
ファイル: estimation.py プロジェクト: spiiph/owls-hep
 def nominal(coefficient, process, region):
     # self.calculation.calculation is the nominal calculation
     n = multiply(
         coefficient[0],
         self.calculation.calculation(process, region)
     )
     return (None, None, n, n)
コード例 #6
0
 def nominal(coefficient, process, region):
     # self.calculation.calculation is the nominal calculation
     n = multiply(coefficient,
                  self.calculation.calculation(process, region))
     return (None, None, n, n)
コード例 #7
0
    def __call__(self, process, region, weighted_combination=True):
        """Executes the background estimation scheme.

        This method combines components which enter into backgruond estimation.
        Implementers should NOT override this method.  Instead, they should
        return a tuple of the components entering background estimation by
        overriding the `components` method.

        This method is designed to handle the following types of calculations:

            - Count
            - Histogram
            - Uncertainty

        Args:
            process: The process to consider
            region: The region to consider
            weighted_combination: Whether or not to apply weights from
                components

        Returns:
            The combined background estimation.
        """
        # Get components
        components = self.components(process, region)

        # Watch for empty components
        if len(components) == 0:
            raise ValueError('must have at least one component for estimation')

        # If we're not using weights, switch all coefficients to 1
        if not weighted_combination:
            components = [(1.0, c[1], c[2], c[3]) for c in components]

        # Determine if we're dealing with an uncertainty or not
        is_uncertainty = isinstance(self.calculation, Uncertainty)

        # If we're dealing with an uncertainty calculation, then create a
        # calculation that will compute a faux-uncertainty ntuple with the
        # nominal value for components that shouldn't have the uncertainty
        # applied.  Also have it support the coefficient.
        if is_uncertainty:

            def nominal(coefficient, process, region):
                # self.calculation.calculation is the nominal calculation
                n = multiply(coefficient,
                             self.calculation.calculation(process, region))
                return (None, None, n, n)

        # If we're dealing with an uncertainty calculation, then create a
        # calculation that will convert any overall systematics to shape
        # systematics so that they can be combined with the other components of
        # the estimation.  Also have it support the coefficient.
        if is_uncertainty:

            def uncertainty(coefficient, process, region):
                u = self.calculation(process, region)
                # self.calculation.calculation is the nominal calculation
                n = self.calculation.calculation(process, region)
                u = to_shape(u, n)
                return (None, None, multiply(coefficient, u[2]),
                        multiply(coefficient, u[3]))

        # Compute the first value which we'll use as the basis of the result
        coefficient, use_nominal, process, region = components[0]
        if is_uncertainty:
            if use_nominal:
                result = nominal(coefficient, process, region)
            else:
                result = uncertainty(coefficient, process, region)
        else:
            result = multiply(coefficient, self.calculation(process, region))

        # Compute the remaining values
        for coefficient, use_nominal, process, region in components[1:]:
            if is_uncertainty:
                if use_nominal:
                    value = nominal(coefficient, process, region)
                else:
                    value = uncertainty(coefficient, process, region)
                result = (
                    None,
                    None,
                    # NOTE: Coefficient already handled above
                    add(1.0, result[2], 1.0, value[2]),
                    add(1.0, result[3], 1.0, value[3]))
            else:
                result = add(1.0, result, coefficient,
                             self.calculation(process, region))

        # All done
        return result
コード例 #8
0
ファイル: estimation.py プロジェクト: spiiph/owls-hep
    def __call__(self, process, region, weighted_combination = True):
        """Executes the background estimation scheme.

        This method combines components which enter into backgruond estimation.
        Implementers should NOT override this method.  Instead, they should
        return a tuple of the components entering background estimation by
        overriding the `components` method.

        This method is designed to handle the following types of calculations:

            - Count
            - Histogram
            - Uncertainty

        Args:
            process: The process to consider
            region: The region to consider
            weighted_combination: Whether or not to apply weights from
                components

        Returns:
            The combined background estimation.
        """
        # Get components
        components = self.components(process, region)

        # Watch for empty components
        if len(components) == 0:
            raise ValueError('must have at least one component for estimation')

        # If we're not using weights, switch all coefficients to 1
        if not weighted_combination:
            components = [(1.0, c[1], c[2], c[3]) for c in components]

        # Determine if we're dealing with an uncertainty or not
        is_uncertainty = isinstance(self.calculation, Uncertainty)

        # Uncertainty calculations need 3-valued coefficients, to accomodate
        # for up/down variations. Convert 1-valued coefficients to 3-tuples
        # with the same value.
        def to_tuple(v):
            return (v, v, v) if isinstance(v, float) else v
        components = [(to_tuple(c[0]), c[1], c[2], c[3])
                      for c
                      in components]

        # If we're dealing with an uncertainty calculation, then create a
        # calculation that will compute a faux-uncertainty ntuple with the
        # nominal value for components that shouldn't have the uncertainty
        # applied.  Also have it support the coefficient.
        if is_uncertainty:
            def nominal(coefficient, process, region):
                # self.calculation.calculation is the nominal calculation
                n = multiply(
                    coefficient[0],
                    self.calculation.calculation(process, region)
                )
                return (None, None, n, n)

        # If we're dealing with an uncertainty calculation, then create a
        # calculation that will convert any overall systematics to shape
        # systematics so that they can be combined with the other components of
        # the estimation.  Also have it support the coefficient.
        if is_uncertainty:
            def uncertainty(coefficient, process, region):
                u = self.calculation(process, region)
                # self.calculation.calculation is the nominal calculation
                n = self.calculation.calculation(process, region)
                u = to_shape(u, n)
                return (
                    None,
                    None,
                    multiply(coefficient[1], u[2]),
                    multiply(coefficient[2], u[3])
                )

        # Compute the first value which we'll use as the basis of the result
        coefficient, use_nominal, process, region = components[0]
        if is_uncertainty:
            if use_nominal:
                result = nominal(coefficient, process, region)
            else:
                result = uncertainty(coefficient, process, region)
        else:
            result = multiply(coefficient[0],
                              self.calculation(process, region))

        # Compute the remaining values
        for coefficient, use_nominal, process, region in components[1:]:
            if is_uncertainty:
                if use_nominal:
                    value = nominal(coefficient, process, region)
                else:
                    value = uncertainty(coefficient, process, region)
                result = (
                    None,
                    None,
                    # NOTE: Coefficient already handled above
                    add(1.0, result[2], 1.0, value[2]),
                    add(1.0, result[3], 1.0, value[3])
                )
            else:
                result = add(
                    1.0,
                    result,
                    coefficient[0],
                    self.calculation(process, region)
                )

        # Allow the HigherOrderCalculation to polish the result
        # (e.g. special treatment of overflow bin for Histogram)
        self.calculation.finalize_result(result)

        if 'estimation' in process.metadata().get('print_me', []):
            print('Final estimate: {:.2f}'.format(integral(result, False)))
        return result
コード例 #9
0
ファイル: estimation.py プロジェクト: havoc-io/owls-hep
    def __call__(self, process, region, weighted_combination = True):
        """Executes the background estimation scheme.

        This method combines components which enter into backgruond estimation.
        Implementers should NOT override this method.  Instead, they should
        return a tuple of the components entering background estimation by
        overriding the `components` method.

        This method is designed to handle the following types of calculations:

            - Count
            - Histogram
            - Uncertainty

        Args:
            process: The process to consider
            region: The region to consider
            weighted_combination: Whether or not to apply weights from
                components

        Returns:
            The combined background estimation.
        """
        # Get components
        components = self.components(process, region)

        # Watch for empty components
        if len(components) == 0:
            raise ValueError('must have at least one component for estimation')

        # If we're not using weights, switch all coefficients to 1
        if not weighted_combination:
            components = [(1.0, c[1], c[2], c[3]) for c in components]

        # Determine if we're dealing with an uncertainty or not
        is_uncertainty = isinstance(self.calculation, Uncertainty)

        # If we're dealing with an uncertainty calculation, then create a
        # calculation that will compute a faux-uncertainty ntuple with the
        # nominal value for components that shouldn't have the uncertainty
        # applied.  Also have it support the coefficient.
        if is_uncertainty:
            def nominal(coefficient, process, region):
                # self.calculation.calculation is the nominal calculation
                n = multiply(
                    coefficient,
                    self.calculation.calculation(process, region)
                )
                return (None, None, n, n)

        # If we're dealing with an uncertainty calculation, then create a
        # calculation that will convert any overall systematics to shape
        # systematics so that they can be combined with the other components of
        # the estimation.  Also have it support the coefficient.
        if is_uncertainty:
            def uncertainty(coefficient, process, region):
                u = self.calculation(process, region)
                # self.calculation.calculation is the nominal calculation
                n = self.calculation.calculation(process, region)
                u = to_shape(u, n)
                return (
                    None,
                    None,
                    multiply(coefficient, u[2]),
                    multiply(coefficient, u[3])
                )

        # Compute the first value which we'll use as the basis of the result
        coefficient, use_nominal, process, region = components[0]
        if is_uncertainty:
            if use_nominal:
                result = nominal(coefficient, process, region)
            else:
                result = uncertainty(coefficient, process, region)
        else:
            result = multiply(coefficient, self.calculation(process, region))

        # Compute the remaining values
        for coefficient, use_nominal, process, region in components[1:]:
            if is_uncertainty:
                if use_nominal:
                    value = nominal(coefficient, process, region)
                else:
                    value = uncertainty(coefficient, process, region)
                result = (
                    None,
                    None,
                    # NOTE: Coefficient already handled above
                    add(1.0, result[2], 1.0, value[2]),
                    add(1.0, result[3], 1.0, value[3])
                )
            else:
                result = add(
                    1.0,
                    result,
                    coefficient,
                    self.calculation(process, region)
                )

        # All done
        return result
コード例 #10
0
ファイル: estimation.py プロジェクト: spiiph/owls-hep
    def __call__(self, process, region, weighted_combination=True):
        """Executes the background estimation scheme.

        This method combines components which enter into backgruond estimation.
        Implementers should NOT override this method.  Instead, they should
        return a tuple of the components entering background estimation by
        overriding the `components` method.

        This method is designed to handle the following types of calculations:

            - Count
            - Histogram
            - Uncertainty

        Args:
            process: The process to consider
            region: The region to consider
            weighted_combination: Whether or not to apply weights from
                components

        Returns:
            The combined background estimation.
        """
        # Get components
        components = self.components(process, region)

        # Watch for empty components
        if len(components) == 0:
            raise ValueError('must have at least one component for estimation')

        # If we're not using weights, switch all coefficients to 1
        if not weighted_combination:
            components = [(1.0, c[1], c[2], c[3]) for c in components]

        # Determine if we're dealing with an uncertainty or not
        is_uncertainty = isinstance(self.calculation, Uncertainty)

        # Uncertainty calculations need 3-valued coefficients, to accomodate
        # for up/down variations. Convert 1-valued coefficients to 3-tuples
        # with the same value.
        def to_tuple(v):
            return (v, v, v) if isinstance(v, float) else v

        components = [(to_tuple(c[0]), c[1], c[2], c[3]) for c in components]

        # If we're dealing with an uncertainty calculation, then create a
        # calculation that will compute a faux-uncertainty ntuple with the
        # nominal value for components that shouldn't have the uncertainty
        # applied.  Also have it support the coefficient.
        if is_uncertainty:

            def nominal(coefficient, process, region):
                # self.calculation.calculation is the nominal calculation
                n = multiply(coefficient[0],
                             self.calculation.calculation(process, region))
                return (None, None, n, n)

        # If we're dealing with an uncertainty calculation, then create a
        # calculation that will convert any overall systematics to shape
        # systematics so that they can be combined with the other components of
        # the estimation.  Also have it support the coefficient.
        if is_uncertainty:

            def uncertainty(coefficient, process, region):
                u = self.calculation(process, region)
                # self.calculation.calculation is the nominal calculation
                n = self.calculation.calculation(process, region)
                u = to_shape(u, n)
                return (None, None, multiply(coefficient[1], u[2]),
                        multiply(coefficient[2], u[3]))

        # Compute the first value which we'll use as the basis of the result
        coefficient, use_nominal, process, region = components[0]
        if is_uncertainty:
            if use_nominal:
                result = nominal(coefficient, process, region)
            else:
                result = uncertainty(coefficient, process, region)
        else:
            result = multiply(coefficient[0],
                              self.calculation(process, region))

        # Compute the remaining values
        for coefficient, use_nominal, process, region in components[1:]:
            if is_uncertainty:
                if use_nominal:
                    value = nominal(coefficient, process, region)
                else:
                    value = uncertainty(coefficient, process, region)
                result = (
                    None,
                    None,
                    # NOTE: Coefficient already handled above
                    add(1.0, result[2], 1.0, value[2]),
                    add(1.0, result[3], 1.0, value[3]))
            else:
                result = add(1.0, result, coefficient[0],
                             self.calculation(process, region))

        # Allow the HigherOrderCalculation to polish the result
        # (e.g. special treatment of overflow bin for Histogram)
        self.calculation.finalize_result(result)

        if 'estimation' in process.metadata().get('print_me', []):
            print('Final estimate: {:.2f}'.format(integral(result, False)))
        return result