Source code for ewoksfluo.xrffit.fit.slow_fit_native

from typing import Optional

import numpy
from PyMca5.PyMcaPhysics.xrf.LegacyMcaAdvancedFitBatch import (
    McaAdvancedFitBatch as LegacyMcaAdvancedFitBatch,
)
from PyMca5.PyMcaPhysics.xrf.McaAdvancedFitBatch import McaAdvancedFitBatch

from ..pymca_config import PyMcaXrfConfiguration
from ..pymca_config import pymca_configdict_from_model
from ._utils.parse_native import parse_native_fit_output
from ._utils.parse_native import parse_native_legacy_fit_output
from .types import XRFBatchFitResult


[docs] def fit_xrf_spectra( xrf_spectra: numpy.ndarray, configuration: PyMcaXrfConfiguration, quantification: Optional[bool] = None, individual_weights: Optional[bool] = None, live_times: Optional[numpy.ndarray] = None, positive_peak_areas: Optional[bool] = None, diagnostics: Optional[bool] = None, ) -> XRFBatchFitResult: """Slow fitting refers to fitting XRF spectra one-by-one. This function uses the high-level API from PyMca. :param xrf_spectra: shape `(num_spectra, num_channels)` :param configuration: PyMca configuration. :param quantification: Calculate mass fractions from peak area's. :param individual_weights: When fitting with weights, use the weight of each spectrum (slow) instead of the average weight. :param live_times: 1D array with one value for each XRF spectrum. Only used for mass fractions with fundamental parameters. :param positive_peak_areas: :param diagnostics: fit model and residuals. """ if quantification is None: quantification = True if individual_weights is None: individual_weights = True if positive_peak_areas is None: positive_peak_areas = True if diagnostics is None: diagnostics = False if not positive_peak_areas: raise NotImplementedError("'positive_peak_areas' must be True") if live_times is not None: raise NotImplementedError("'live_times' is not supported") if not individual_weights: raise NotImplementedError("'individual_weights' must be True") batch = McaAdvancedFitBatch( None, filelist=xrf_spectra, concentrations=int(quantification), fitfiles=0, fitconcfile=0, nosave=True, saveResiduals=True, saveFit=True, saveData=True, diagnostics=True, saveFOM=True, ) # WARNING: McaAdvancedFitBatch ignores `use_limit=False` # and always uses xmin/xmax from the configuration. if not configuration.fit.use_limit: configuration.fit.xmin = 0 configuration.fit.xmax = xrf_spectra.shape[1] _ = batch.mcafit.configure(pymca_configdict_from_model(configuration)) with numpy.errstate(over="ignore"): # Stores results in float32 batch.processList() return parse_native_fit_output( xrf_spectra, batch.mcafit, batch.outbuffer, quantification, diagnostics, fast_fitting=False, )
class _LegacyMcaAdvancedFitBatch(LegacyMcaAdvancedFitBatch): def __log(self, text): # Base class does `print` pass
[docs] def fit_xrf_spectra_legacy( xrf_spectra: numpy.ndarray, configuration: PyMcaXrfConfiguration, quantification: Optional[bool] = None, individual_weights: Optional[bool] = None, live_times: Optional[numpy.ndarray] = None, positive_peak_areas: Optional[bool] = None, diagnostics: Optional[bool] = None, ) -> XRFBatchFitResult: """Slow fitting refers to fitting XRF spectra one-by-one. This function uses the high-level API from PyMca. :param xrf_spectra: shape `(num_spectra, num_channels)` :param configuration: PyMca configuration. :param quantification: Calculate mass fractions from peak area's. :param individual_weights: When fitting with weights, use the weight of each spectrum (slow) instead of the average weight. :param live_times: 1D array with one value for each XRF spectrum. Only used for mass fractions with fundamental parameters. :param positive_peak_areas: :param diagnostics: fit model and residuals. """ if quantification is None: quantification = True if individual_weights is None: individual_weights = True if positive_peak_areas is None: positive_peak_areas = True if diagnostics is None: diagnostics = False if not positive_peak_areas: raise NotImplementedError("'positive_peak_areas' must be True") if live_times is not None: raise NotImplementedError("'live_times' is not supported") if not individual_weights: raise NotImplementedError("'individual_weights' must be True") batch = _LegacyMcaAdvancedFitBatch( None, filelist=xrf_spectra, concentrations=int(quantification), fitfiles=0, nosave=True, ) class Dummy: def getConcentrationsAsAscii(self, _): # Prevent saving of _concentrations.txt file return [] batch._toolConversion = Dummy() # WARNING: McaAdvancedFitBatch ignores `use_limit=False` # and always uses xmin/xmax from the configuration. if not configuration.fit.use_limit: configuration.fit.xmin = 0 configuration.fit.xmax = xrf_spectra.shape[1] _ = batch.mcafit.configure(pymca_configdict_from_model(configuration)) with numpy.errstate(over="ignore"): # Stores results in float32 batch.processList() images = batch._McaAdvancedFitBatch__images sigmas = batch._McaAdvancedFitBatch__sigmas parameter_names = list(sigmas) parameters = numpy.array([images[name] for name in parameter_names]) uncertainties = numpy.array([sigmas[name] for name in parameter_names]) outputdict = {"parameters": parameters, "uncertainties": uncertainties} names = list(parameter_names) if quantification: concentrations = [] for name in parameter_names: key = f"{name} mass fraction" if key in images: concentrations.append(images[key]) names.append(f"C({name})") layeri = 0 has_layeri = True while has_layeri: layeri += 1 has_layeri = False for name in parameter_names: key = f"{name} Layer{layeri}" if key in images: concentrations.append(images[key]) names.append(f"C({name})-Layer{layeri}") has_layeri = True outputdict["concentrations"] = numpy.array(concentrations) outputdict["names"] = names return parse_native_legacy_fit_output( xrf_spectra, batch.mcafit, outputdict, quantification, diagnostics, fast_fitting=False, )