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
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)
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)
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)
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
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])
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])
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)
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)
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
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)
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
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
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