Ejemplo n.º 1
0
def get_abs_corr_zeta(
        weight_percent, mass_thickness,
        take_off_angle):  # take_off_angle, temporary value for testing
    """
    Calculate absorption correction terms.

    Parameters
    ----------
    weight_percent: list of signal
        Composition in weight percent.
    mass_thickness: signal
        Density-thickness map in kg/m^2
    take_off_angle: float
        X-ray take-off angle in degrees.
    """
    from hyperspy.misc import material

    toa_rad = np.radians(take_off_angle)
    csc_toa = 1.0 / np.sin(toa_rad)
    # convert from cm^2/g to m^2/kg
    mac = stack(
        material.mass_absorption_mixture(weight_percent=weight_percent),
        show_progressbar=False) * 0.1
    acf = mac.data * mass_thickness.data * csc_toa
    acf = acf / (1.0 - np.exp(-(acf)))

    return acf
Ejemplo n.º 2
0
def atomic_to_weight(atomic_percent, elements='auto'):
    """Convert atomic percent to weight percent.

    Parameters
    ----------
    atomic_percent: list of float or list of signals
        The atomic fractions (composition) of the sample.
    elements: list of str
        A list of element abbreviations, e.g. ['Al','Zn']. If elements is
        'auto', take the elements in en each signal metadata of the
        atomic_percent list.

    Returns
    -------
    weight_percent : as atomic_percent
        composition in weight percent.

    Examples
    --------
    Calculate the weight percent of modern bronze given its atomic percent:
    >>> hs.material.atomic_to_weight([93.2, 6.8], ("Cu", "Sn"))
    array([ 88.00501989,  11.99498011])

    """
    from hyperspy.signals import BaseSignal
    elements = _elements_auto(atomic_percent, elements)
    if isinstance(atomic_percent[0], BaseSignal):
        weight_percent = stack(atomic_percent)
        weight_percent.data = _atomic_to_weight(
            weight_percent.data, elements)
        weight_percent = weight_percent.split()
        return weight_percent
    else:
        return _atomic_to_weight(atomic_percent, elements)
Ejemplo n.º 3
0
def atomic_to_weight(atomic_percent, elements="auto"):
    """Convert atomic percent to weight percent.

    Parameters
    ----------
    atomic_percent: list of float or list of signals
        The atomic fractions (composition) of the sample.
    elements: list of str
        A list of element abbreviations, e.g. ['Al','Zn']. If elements is
        'auto', take the elements in en each signal metadata of the
        atomic_percent list.

    Returns
    -------
    weight_percent : as atomic_percent
        composition in weight percent.

    Examples
    --------
    Calculate the weight percent of modern bronze given its atomic percent:
    >>> hs.material.atomic_to_weight([93.2, 6.8], ("Cu", "Sn"))
    array([ 88.00501989,  11.99498011])

    """
    from hyperspy.signals import Signal

    elements = _elements_auto(atomic_percent, elements)
    if isinstance(atomic_percent[0], Signal):
        weight_percent = stack(atomic_percent)
        weight_percent.data = _atomic_to_weight(weight_percent.data, elements)
        weight_percent = weight_percent.split()
        return weight_percent
    else:
        return _atomic_to_weight(atomic_percent, elements)
Ejemplo n.º 4
0
def weight_to_atomic(weight_percent, elements='auto'):
    """Convert weight percent (wt%) to atomic percent (at.%).

    Parameters
    ----------
    weight_percent: list of float or list of signals
        The weight fractions (composition) of the sample.
    elements: list of str
        A list of element abbreviations, e.g. ['Al','Zn']. If elements is
        'auto', take the elements in en each signal metadata of th
        weight_percent list.

    Returns
    -------
    atomic_percent : as weight_percent
        Composition in atomic percent.

    Examples
    --------
    Calculate the atomic percent of modern bronze given its weight percent:
    >>> utils.material.weight_to_atomic((88, 12), ("Cu", "Sn"))
    array([ 93.19698614,   6.80301386])

    """
    from hyperspy.signals import Signal
    elements = _elements_auto(weight_percent, elements)

    if isinstance(weight_percent[0], Signal):
        atomic_percent = stack(weight_percent)
        atomic_percent.data = _weight_to_atomic(atomic_percent.data, elements)
        atomic_percent.data = np.nan_to_num(atomic_percent.data)
        atomic_percent = atomic_percent.split()
        return atomic_percent
    else:
        return _weight_to_atomic(weight_percent, elements)
Ejemplo n.º 5
0
def get_abs_corr_cross_section(
        composition, number_of_atoms, take_off_angle,
        probe_area):  # take_off_angle, temporary value for testing
    """
    Calculate absorption correction terms.

    Parameters
    ----------
    number_of_atoms: list of signal
        Stack of maps with number of atoms per pixel.
    take_off_angle: float
        X-ray take-off angle in degrees.
    """
    from hyperspy.misc import material

    toa_rad = np.radians(take_off_angle)
    Av = constants.Avogadro
    elements = [
        intensity.metadata.Sample.elements[0] for intensity in number_of_atoms
    ]
    atomic_weights = np.array([
        elements_db[element]['General_properties']['atomic_weight']
        for element in elements
    ])

    number_of_atoms = stack(number_of_atoms).data

    #calculate the total_mass per pixel, or mass thicknessself.
    total_mass = np.zeros_like(number_of_atoms[0], dtype='float')
    for i, (weight) in enumerate(atomic_weights):
        total_mass += (number_of_atoms[i] * weight / Av / probe_area / 1E-15)

    # determine mass absorption coefficients and convert from cm^2/g to m^2/atom.
    mac = stack(
        material.mass_absorption_mixture(
            weight_percent=material.atomic_to_weight(composition))) * 0.1

    acf = np.zeros_like(number_of_atoms)
    constant = 1 / (Av * math.sin(toa_rad) * probe_area * 1E-16)

    #determine an absorption coeficcient per element per pixel.
    for i, (weight) in enumerate(atomic_weights):
        expo = (mac.data[i] * total_mass * constant)
        acf[i] = expo / (1 - math.e**(-expo))

    return acf
Ejemplo n.º 6
0
 def test_quantification(self):
     s = self.s
     m = s.create_model()
     m.fit()
     intensities = m.get_lines_intensity()
     quant = s.quantification(intensities, method='CL',
                              factors=[1.0, 1.0, 1.0],
                              composition_units='weight')
     np.testing.assert_allclose(utils.stack(quant, axis=0), [50, 20, 30])
Ejemplo n.º 7
0
 def test_quantification(self):
     s = self.s
     # to have enough intensities, so that the default values for
     # `navigation_mask` of 1.0 in `quantification` doesn't mask the data
     s = s * 1000
     m = s.create_model()
     m.fit()
     intensities = m.get_lines_intensity()
     quant = s.quantification(intensities, method='CL',
                              factors=[1.0, 1.0, 1.0],
                              composition_units='weight')
     np.testing.assert_allclose(utils.stack(quant, axis=0), [50, 20, 30])
Ejemplo n.º 8
0
def density_of_mixture_of_pure_elements(weight_percent,
                                        elements='auto',
                                        mean='harmonic'):
    """Calculate the density of a mixture of elements.

    The density of the elements is retrieved from an internal database. The
    calculation is only valid if there is no interaction between the
    components.

    Parameters
    ----------
    weight_percent: list of float or list of signals
        A list of weight percent for the different elements. If the total
        is not equal to 100, each weight percent is divided by the sum
        of the list (normalization).
    elements: list of str
        A list of element symbols, e.g. ['Al', 'Zn']. If elements is 'auto',
        take the elements in en each signal metadata of the weight_percent
        list.
    mean: 'harmonic' or 'weighted'
        The type of mean use to estimate the density

    Returns
    -------
    density: The density in g/cm3.

    Examples
    --------
    Calculate the density of modern bronze given its weight percent:
    >>> utils.material.density_of_mixture_of_pure_elements(
            (88, 12),("Cu", "Sn"))
    8.6903187973131466

    """
    from hyperspy.signals import Signal
    elements = _elements_auto(weight_percent, elements)
    if isinstance(weight_percent[0], Signal):
        density = weight_percent[0]._deepcopy_with_new_data(
            _density_of_mixture_of_pure_elements(stack(weight_percent).data,
                                                 elements,
                                                 mean=mean))
        return density
    else:
        return _density_of_mixture_of_pure_elements(weight_percent,
                                                    elements,
                                                    mean=mean)
Ejemplo n.º 9
0
def density_of_mixture_of_pure_elements(weight_percent,
                                        elements='auto',
                                        mean='harmonic'):
    """Calculate the density of a mixture of elements.

    The density of the elements is retrieved from an internal database. The
    calculation is only valid if there is no interaction between the
    components.

    Parameters
    ----------
    weight_percent: list of float or list of signals
        A list of weight percent for the different elements. If the total
        is not equal to 100, each weight percent is divided by the sum
        of the list (normalization).
    elements: list of str
        A list of element symbols, e.g. ['Al', 'Zn']. If elements is 'auto',
        take the elements in en each signal metadata of the weight_percent
        list.
    mean: 'harmonic' or 'weighted'
        The type of mean use to estimate the density

    Returns
    -------
    density: The density in g/cm3.

    Examples
    --------
    Calculate the density of modern bronze given its weight percent:
    >>> utils.material.density_of_mixture_of_pure_elements(
            (88, 12),("Cu", "Sn"))
    8.6903187973131466

    """
    from hyperspy.signals import Signal
    elements = _elements_auto(weight_percent, elements)
    if isinstance(weight_percent[0], Signal):
        density = weight_percent[0]._deepcopy_with_new_data(
            _density_of_mixture_of_pure_elements(
                stack(weight_percent).data, elements, mean=mean))
        return density
    else:
        return _density_of_mixture_of_pure_elements(weight_percent,
                                                    elements, mean=mean)
Ejemplo n.º 10
0
def get_derivative(signal, diff_axes, diff_order):
    if signal.axes_manager.signal_dimension == 1:
        signal = signal.diff(order=diff_order, axis=-1)
    else:
        # n-d signal case.
        # Compute the differences for each signal axis, unfold the
        # signal axes and stack the differences over the signal
        # axis.
        if diff_axes is None:
            diff_axes = signal.axes_manager.signal_axes
            iaxes = [axis.index_in_axes_manager for axis in diff_axes]
        else:
            iaxes = diff_axes
        diffs = [signal.derivative(order=diff_order, axis=i) for i in iaxes]
        for signal in diffs:
            signal.unfold()
        signal = stack(diffs, axis=-1)
        del diffs
    return signal
Ejemplo n.º 11
0
def get_derivative(signal, diff_axes, diff_order):
    if signal.axes_manager.signal_dimension == 1:
        signal = signal.diff(order=diff_order, axis=-1)
    else:
        # n-d signal case.
        # Compute the differences for each signal axis, unfold the
        # signal axes and stack the differences over the signal
        # axis.
        if diff_axes is None:
            diff_axes = signal.axes_manager.signal_axes
            iaxes = [axis.index_in_axes_manager
                     for axis in diff_axes]
        else:
            iaxes = diff_axes
        diffs = [signal.derivative(order=diff_order, axis=i)
                 for i in iaxes]
        for signal in diffs:
            signal.unfold()
        signal = stack(diffs, axis=-1)
        del diffs
    return signal
Ejemplo n.º 12
0
def weight_to_atomic(weight_percent, elements='auto'):
    """Convert weight percent (wt%) to atomic percent (at.%).

    Parameters
    ----------
    weight_percent: list of float or list of signals
        The weight fractions (composition) of the sample.
    elements: list of str
        A list of element abbreviations, e.g. ['Al','Zn']. If elements is
        'auto', take the elements in en each signal metadata of th
        weight_percent list.

    Returns
    -------
    atomic_percent : as weight_percent
        Composition in atomic percent.

    Examples
    --------
    Calculate the atomic percent of modern bronze given its weight percent:
    >>> hs.material.weight_to_atomic((88, 12), ("Cu", "Sn"))
    array([ 93.19698614,   6.80301386])

    """
    from hyperspy.signals import BaseSignal
    elements = _elements_auto(weight_percent, elements)

    if isinstance(weight_percent[0], BaseSignal):
        atomic_percent = stack(weight_percent)
        atomic_percent.data = _weight_to_atomic(
            atomic_percent.data, elements)
        atomic_percent.data = np.nan_to_num(atomic_percent.data)
        atomic_percent = atomic_percent.split()
        for i, el in enumerate(elements):
            atomic_percent[i].metadata.General.title = 'atomic percent of ' + el
        return atomic_percent
    else:
        return _weight_to_atomic(weight_percent, elements)
Ejemplo n.º 13
0
    def blind_source_separation(self,
                                number_of_components=None,
                                algorithm='sklearn_fastica',
                                diff_order=1,
                                diff_axes=None,
                                factors=None,
                                comp_list=None,
                                mask=None,
                                on_loadings=False,
                                pretreatment=None,
                                **kwargs):
        """Blind source separation (BSS) on the result on the
        decomposition.

        Available algorithms: FastICA, JADE, CuBICA, and TDSEP

        Parameters
        ----------
        number_of_components : int
            number of principal components to pass to the BSS algorithm
        algorithm : {FastICA, JADE, CuBICA, TDSEP}
        diff_order : int
            Sometimes it is convenient to perform the BSS on the derivative of
            the signal. If diff_order is 0, the signal is not differentiated.
        diff_axes : None or list of ints or strings
            If None, when `diff_order` is greater than 1 and `signal_dimension`
            (`navigation_dimension`) when `on_loadings` is False (True) is
            greater than 1, the differences are calculated across all
            signal (navigation) axes. Otherwise the axes can be specified in
            a list.
        factors : Signal or numpy array.
            Factors to decompose. If None, the BSS is performed on the
            factors of a previous decomposition. If a Signal instance the
            navigation dimension must be 1 and the size greater than 1. If a
            numpy array (deprecated) the factors are stored in a 2d array
            stacked over the last axis.
        comp_list : boolen numpy array
            choose the components to use by the boolean list. It permits
             to choose non contiguous components.
        mask : bool numpy array or Signal instance.
            If not None, the signal locations marked as True are masked. The
            mask shape must be equal to the signal shape
            (navigation shape) when `on_loadings` is False (True).
        on_loadings : bool
            If True, perform the BSS on the loadings of a previous
            decomposition. If False, performs it on the factors.
        pretreatment: dict

        **kwargs : extra key word arguments
            Any keyword arguments are passed to the BSS algorithm.

        """
        from hyperspy.signal import Signal
        from hyperspy._signals.spectrum import Spectrum

        lr = self.learning_results

        if factors is None:
            if not hasattr(lr, 'factors') or lr.factors is None:
                raise AttributeError(
                    'A decomposition must be performed before blind '
                    'source seperation or factors must be provided.')

            else:
                if on_loadings:
                    factors = self.get_decomposition_loadings()
                else:
                    factors = self.get_decomposition_factors()

        # Check factors
        if not isinstance(factors, Signal):
            if isinstance(factors, np.ndarray):
                warnings.warn(
                    "factors as numpy arrays will raise an error in "
                    "HyperSpy 0.9 and newer. From them on only passing "
                    "factors as HyperSpy Signal instances will be "
                    "supported.",
                    DeprecationWarning)
                # We proceed supposing that the factors are spectra stacked
                # over the last dimension to reproduce the deprecated
                # behaviour.
                # TODO: Don't forget to change `factors` docstring when
                # removing this.
                factors = Spectrum(factors.T)
            else:
                # Change next error message when removing the
                # DeprecationWarning
                raise ValueError(
                    "`factors` must be either a Signal instance or a "
                    "numpy array but an object of type %s was provided." %
                    type(factors))

        # Check factor dimensions
        if factors.axes_manager.navigation_dimension != 1:
            raise ValueError("`factors` must have navigation dimension"
                             "equal one, but the navigation dimension "
                             "of the given factors is %i." %
                             factors.axes_manager.navigation_dimension
                             )
        elif factors.axes_manager.navigation_size < 2:
            raise ValueError("`factors` must have navigation size"
                             "greater than one, but the navigation "
                             "size of the given factors is %i." %
                             factors.axes_manager.navigation_size)

        # Check mask dimensions
        if mask is not None:
            ref_shape, space = (factors.axes_manager.signal_shape,
                                "navigation" if on_loadings else "signal")
            if isinstance(mask, np.ndarray):
                warnings.warn(
                    "Bare numpy array masks are deprecated and will be removed"
                    " in next HyperSpy 0.9.",
                    DeprecationWarning)
                ref_shape = ref_shape[::-1]
                if mask.shape != ref_shape:
                    raise ValueError(
                        "The `mask` shape is not equal to the %s shape."
                        "Mask shape: %s\tSignal shape in array: %s" %
                        (space, str(mask.shape), str(ref_shape)))
                else:
                    if on_loadings:
                        mask = self._get_navigation_signal(data=mask)
                    else:
                        mask = self._get_signal_signal(data=mask)
            elif isinstance(mask, Signal):
                if mask.axes_manager.signal_shape != ref_shape:
                    raise ValueError(
                        "The `mask` signal shape is not equal to the %s shape."
                        " Mask shape: %s\t%s shape:%s" %
                        (space,
                         str(mask.axes_manager.signal_shape),
                         space,
                         str(ref_shape)))

        # Note that we don't check the factor's signal dimension. This is on
        # purpose as an user may like to apply pretreaments that change their
        # dimensionality.

        # The diff_axes are given for the main signal. We need to compute
        # the correct diff_axes for the factors.
        # Get diff_axes index in axes manager
        if diff_axes is not None:
            diff_axes = [1 + axis.index_in_axes_manager for axis in
                         [self.axes_manager[axis] for axis in diff_axes]]
            if not on_loadings:
                diff_axes = [index - self.axes_manager.navigation_dimension
                             for index in diff_axes]
        # Select components to separate
        if number_of_components is not None:
            comp_list = range(number_of_components)
        elif comp_list is not None:
            number_of_components = len(comp_list)
        else:
            if lr.output_dimension is not None:
                number_of_components = lr.output_dimension
                comp_list = range(number_of_components)
            else:
                raise ValueError(
                    "No `number_of_components` or `comp_list` provided.")
        factors = stack([factors.inav[i] for i in comp_list])

        # Apply differences pre-processing if requested.
        if diff_order > 0:
            factors = get_derivative(factors,
                                     diff_axes=diff_axes,
                                     diff_order=diff_order)
            if mask is not None:
                # The following is a little trick to dilate the mask as
                # required when operation on the differences. It exploits the
                # fact that np.diff autimatically "dilates" nans. The trick has
                # a memory penalty which should be low compare to the total
                # memory required for the core application in most cases.
                mask_diff_axes = (
                    [iaxis - 1 for iaxis in diff_axes]
                    if diff_axes is not None
                    else None)
                mask.change_dtype("float")
                mask.data[mask.data == 1] = np.nan
                mask = get_derivative(mask,
                                      diff_axes=mask_diff_axes,
                                      diff_order=diff_order)
                mask.data[np.isnan(mask.data)] = 1
                mask.change_dtype("bool")

        # Unfold in case the signal_dimension > 1
        factors.unfold()
        if mask is not None:
            mask.unfold()
            factors = factors.data.T[~mask.data]
        else:
            factors = factors.data.T

        # Center and scale the data
        factors, invsqcovmat = centering_and_whitening(factors)

        # Perform actual BSS
        if algorithm == 'orthomax':
            _, unmixing_matrix = orthomax(factors, **kwargs)
            unmixing_matrix = unmixing_matrix.T

        elif algorithm == 'sklearn_fastica':
            if not import_sklearn.sklearn_installed:
                raise ImportError(
                    "The optional package scikit learn is not installed "
                    "and it is required for this feature.")
            if 'tol' not in kwargs:
                kwargs['tol'] = 1e-10
            lr.bss_node = import_sklearn.FastICA(
                **kwargs)
            lr.bss_node.whiten = False
            lr.bss_node.fit(factors)
            try:
                unmixing_matrix = lr.bss_node.unmixing_matrix_
            except AttributeError:
                # unmixing_matrix was renamed to components
                unmixing_matrix = lr.bss_node.components_
        else:
            if mdp_installed is False:
                raise ImportError(
                    'MDP is not installed. Nothing done')
            temp_function = getattr(mdp.nodes, algorithm + "Node")
            lr.bss_node = temp_function(**kwargs)
            lr.bss_node.train(factors)
            unmixing_matrix = lr.bss_node.get_recmatrix()
        w = np.dot(unmixing_matrix, invsqcovmat)
        if lr.explained_variance is not None:
            # The output of ICA is not sorted in any way what makes it
            # difficult to compare results from different unmixings. The
            # following code is an experimental attempt to sort them in a
            # more predictable way
            sorting_indices = np.argsort(np.dot(
                lr.explained_variance[:number_of_components],
                np.abs(w.T)))[::-1]
            w[:] = w[sorting_indices, :]
        lr.unmixing_matrix = w
        lr.on_loadings = on_loadings
        self._unmix_components()
        self._auto_reverse_bss_component(lr)
        lr.bss_algorithm = algorithm
Ejemplo n.º 14
0
    def blind_source_separation(self,
                                number_of_components=None,
                                algorithm='sklearn_fastica',
                                diff_order=1,
                                diff_axes=None,
                                factors=None,
                                comp_list=None,
                                mask=None,
                                on_loadings=False,
                                pretreatment=None,
                                **kwargs):
        """Blind source separation (BSS) on the result on the
        decomposition.

        Available algorithms: FastICA, JADE, CuBICA, and TDSEP

        Parameters
        ----------
        number_of_components : int
            number of principal components to pass to the BSS algorithm
        algorithm : {FastICA, JADE, CuBICA, TDSEP}
        diff_order : int
            Sometimes it is convenient to perform the BSS on the derivative of
            the signal. If diff_order is 0, the signal is not differentiated.
        diff_axes : None or list of ints or strings
            If None, when `diff_order` is greater than 1 and `signal_dimension`
            (`navigation_dimension`) when `on_loadings` is False (True) is
            greater than 1, the differences are calculated across all
            signal (navigation) axes. Otherwise the axes can be specified in
            a list.
        factors : Signal or numpy array.
            Factors to decompose. If None, the BSS is performed on the
            factors of a previous decomposition. If a Signal instance the
            navigation dimension must be 1 and the size greater than 1. If a
            numpy array (deprecated) the factors are stored in a 2d array
            stacked over the last axis.
        comp_list : boolen numpy array
            choose the components to use by the boolean list. It permits
             to choose non contiguous components.
        mask : bool numpy array or Signal instance.
            If not None, the signal locations marked as True are masked. The
            mask shape must be equal to the signal shape
            (navigation shape) when `on_loadings` is False (True).
        on_loadings : bool
            If True, perform the BSS on the loadings of a previous
            decomposition. If False, performs it on the factors.
        pretreatment: dict

        **kwargs : extra key word arguments
            Any keyword arguments are passed to the BSS algorithm.

        """
        from hyperspy.signal import Signal
        from hyperspy._signals.spectrum import Spectrum

        lr = self.learning_results

        if factors is None:
            if not hasattr(lr, 'factors') or lr.factors is None:
                raise AttributeError(
                    'A decomposition must be performed before blind '
                    'source seperation or factors must be provided.')

            else:
                if on_loadings:
                    factors = self.get_decomposition_loadings()
                else:
                    factors = self.get_decomposition_factors()

        # Check factors
        if not isinstance(factors, Signal):
            if isinstance(factors, np.ndarray):
                warnings.warn(
                    "factors as numpy arrays will raise an error in "
                    "HyperSpy 0.9 and newer. From them on only passing "
                    "factors as HyperSpy Signal instances will be "
                    "supported.", DeprecationWarning)
                # We proceed supposing that the factors are spectra stacked
                # over the last dimension to reproduce the deprecated
                # behaviour.
                # TODO: Don't forget to change `factors` docstring when
                # removing this.
                factors = Spectrum(factors.T)
            else:
                # Change next error message when removing the
                # DeprecationWarning
                raise ValueError(
                    "`factors` must be either a Signal instance or a "
                    "numpy array but an object of type %s was provided." %
                    type(factors))

        # Check factor dimensions
        if factors.axes_manager.navigation_dimension != 1:
            raise ValueError("`factors` must have navigation dimension"
                             "equal one, but the navigation dimension "
                             "of the given factors is %i." %
                             factors.axes_manager.navigation_dimension)
        elif factors.axes_manager.navigation_size < 2:
            raise ValueError("`factors` must have navigation size"
                             "greater than one, but the navigation "
                             "size of the given factors is %i." %
                             factors.axes_manager.navigation_size)

        # Check mask dimensions
        if mask is not None:
            ref_shape, space = (factors.axes_manager.signal_shape,
                                "navigation" if on_loadings else "signal")
            if isinstance(mask, np.ndarray):
                warnings.warn(
                    "Bare numpy array masks are deprecated and will be removed"
                    " in next HyperSpy 0.9.", DeprecationWarning)
                ref_shape = ref_shape[::-1]
                if mask.shape != ref_shape:
                    raise ValueError(
                        "The `mask` shape is not equal to the %s shape."
                        "Mask shape: %s\tSignal shape in array: %s" %
                        (space, str(mask.shape), str(ref_shape)))
                else:
                    if on_loadings:
                        mask = self._get_navigation_signal(data=mask)
                    else:
                        mask = self._get_signal_signal(data=mask)
            elif isinstance(mask, Signal):
                if mask.axes_manager.signal_shape != ref_shape:
                    raise ValueError(
                        "The `mask` signal shape is not equal to the %s shape."
                        " Mask shape: %s\t%s shape:%s" %
                        (space, str(mask.axes_manager.signal_shape), space,
                         str(ref_shape)))

        # Note that we don't check the factor's signal dimension. This is on
        # purpose as an user may like to apply pretreaments that change their
        # dimensionality.

        # The diff_axes are given for the main signal. We need to compute
        # the correct diff_axes for the factors.
        # Get diff_axes index in axes manager
        if diff_axes is not None:
            diff_axes = [
                1 + axis.index_in_axes_manager
                for axis in [self.axes_manager[axis] for axis in diff_axes]
            ]
            if not on_loadings:
                diff_axes = [
                    index - self.axes_manager.navigation_dimension
                    for index in diff_axes
                ]
        # Select components to separate
        if number_of_components is not None:
            comp_list = range(number_of_components)
        elif comp_list is not None:
            number_of_components = len(comp_list)
        else:
            if lr.output_dimension is not None:
                number_of_components = lr.output_dimension
                comp_list = range(number_of_components)
            else:
                raise ValueError(
                    "No `number_of_components` or `comp_list` provided.")
        factors = stack([factors.inav[i] for i in comp_list])

        # Apply differences pre-processing if requested.
        if diff_order > 0:
            factors = get_derivative(factors,
                                     diff_axes=diff_axes,
                                     diff_order=diff_order)
            if mask is not None:
                # The following is a little trick to dilate the mask as
                # required when operation on the differences. It exploits the
                # fact that np.diff autimatically "dilates" nans. The trick has
                # a memory penalty which should be low compare to the total
                # memory required for the core application in most cases.
                mask_diff_axes = ([iaxis - 1 for iaxis in diff_axes]
                                  if diff_axes is not None else None)
                mask.change_dtype("float")
                mask.data[mask.data == 1] = np.nan
                mask = get_derivative(mask,
                                      diff_axes=mask_diff_axes,
                                      diff_order=diff_order)
                mask.data[np.isnan(mask.data)] = 1
                mask.change_dtype("bool")

        # Unfold in case the signal_dimension > 1
        factors.unfold()
        if mask is not None:
            mask.unfold()
            factors = factors.data.T[~mask.data]
        else:
            factors = factors.data.T

        # Center and scale the data
        factors, invsqcovmat = centering_and_whitening(factors)

        # Perform actual BSS
        if algorithm == 'orthomax':
            _, unmixing_matrix = orthomax(factors, **kwargs)
            unmixing_matrix = unmixing_matrix.T

        elif algorithm == 'sklearn_fastica':
            if not import_sklearn.sklearn_installed:
                raise ImportError(
                    "The optional package scikit learn is not installed "
                    "and it is required for this feature.")
            if 'tol' not in kwargs:
                kwargs['tol'] = 1e-10
            lr.bss_node = import_sklearn.FastICA(**kwargs)
            lr.bss_node.whiten = False
            lr.bss_node.fit(factors)
            try:
                unmixing_matrix = lr.bss_node.unmixing_matrix_
            except AttributeError:
                # unmixing_matrix was renamed to components
                unmixing_matrix = lr.bss_node.components_
        else:
            if mdp_installed is False:
                raise ImportError('MDP is not installed. Nothing done')
            temp_function = getattr(mdp.nodes, algorithm + "Node")
            lr.bss_node = temp_function(**kwargs)
            lr.bss_node.train(factors)
            unmixing_matrix = lr.bss_node.get_recmatrix()
        w = np.dot(unmixing_matrix, invsqcovmat)
        if lr.explained_variance is not None:
            # The output of ICA is not sorted in any way what makes it
            # difficult to compare results from different unmixings. The
            # following code is an experimental attempt to sort them in a
            # more predictable way
            sorting_indices = np.argsort(
                np.dot(lr.explained_variance[:number_of_components],
                       np.abs(w.T)))[::-1]
            w[:] = w[sorting_indices, :]
        lr.unmixing_matrix = w
        lr.on_loadings = on_loadings
        self._unmix_components()
        self._auto_reverse_bss_component(lr)
        lr.bss_algorithm = algorithm
Ejemplo n.º 15
0
def mass_absorption_mixture(weight_percent,
                            elements='auto',
                            energies='auto'):
    """Calculate the mass absorption coefficient for X-ray absorbed in a
    mixture of elements.

    The mass absorption coefficient is calculated as a weighted mean of the
    weight percent and is retrieved from the database of Chantler2005.

    Parameters
    ----------
    weight_percent: list of float or list of signals
        The composition of the absorber(s) in weight percent. The first
        dimension of the matrix corresponds to the elements.
    elements: list of str or 'auto'
        The list of element symbol of the absorber, e.g. ['Al','Zn']. If
        elements is 'auto', take the elements in each signal metadata of the
        weight_percent list.
    energies: list of float or list of str or 'auto'
        The energy or energies of the X-ray in keV, or the name of the X-rays,
        e.g. 'Al_Ka'. If 'auto', take the lines in each signal metadata of the
        weight_percent list.

    Examples
    --------
    >>> hs.material.mass_absorption_mixture(
    >>>     elements=['Al','Zn'], weight_percent=[50,50], energies='Al_Ka')
    2587.41616439

    Return
    ------
    float or array of float
    mass absorption coefficient(s) in cm^2/g

    See also
    --------
    hs.material.mass_absorption_coefficient

    Note
    ----
    See http://physics.nist.gov/ffast
    Chantler, C.T., Olsen, K., Dragoset, R.A., Kishore, A.R., Kotochigova,
    S.A., and Zucker, D.S. (2005), X-Ray Form Factor, Attenuation and
    Scattering Tables (version 2.1).

    """
    from hyperspy.signals import BaseSignal
    elements = _elements_auto(weight_percent, elements)
    energies = _lines_auto(weight_percent, energies)
    if isinstance(weight_percent[0], BaseSignal):
        weight_per = np.array([wt.data for wt in weight_percent])
        mac_res = stack([weight_percent[0].deepcopy()] * len(energies))
        mac_res.data = \
            _mass_absorption_mixture(weight_per, elements, energies)
        mac_res = mac_res.split()
        for i, energy in enumerate(energies):
            mac_res[i].metadata.set_item("Sample.xray_lines", ([energy]))
            mac_res[i].metadata.General.set_item(
                "title", "Absoprtion coeff of"
                " %s in %s" % (energy, mac_res[i].metadata.General.title))
            if mac_res[i].metadata.has_item("Sample.elements"):
                del mac_res[i].metadata.Sample.elements
        return mac_res
    else:
        return _mass_absorption_mixture(weight_percent, elements, energies)
    def test_has_warning(self, axis, caplog):
        with caplog.at_level(logging.WARNING):
            _ = stack([self.s1, self.s2], axis=axis)

        assert "Axis calibration mismatch detected along axis 1" in caplog.text