Source code for autoemxsp.runners.Fit_and_Quantify_Spectrum

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Fitting and quantification of a single X-ray spectrum.

For spectrum-level analysis of fitting and quantification performance.

Created on Tue Jul 29 13:18:16 2025

@author: Andrea
"""

import time
import logging

from autoemxsp.utils import print_double_separator
from autoemxsp.core.XSp_quantifier import XSp_Quantifier

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s %(levelname)s: %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S",
)

__all__ = ["fit_and_quantify_spectrum"]

[docs] def fit_and_quantify_spectrum( spectrum_vals, spectrum_lims, microscope_ID, meas_type, meas_mode, det_ch_offset, det_ch_width, beam_energy, emergence_angle, sp_collection_time = None, sample_ID = '', els_sample: list = None, els_substrate: list = None, background_vals=None, fit_tol: float = 1e-4, is_particle: bool = False, quantify_plot: bool = True, max_undetectable_w_fr: float = 0, force_single_iteration: bool = False, interrupt_fits_bad_spectra: bool = False, standards_dict = None, plot_signal: bool = True, plot_title = '', zoom_plot: bool = False, line_to_plot: str = '', print_results: bool = True, quant_verbose: bool = True, fitting_verbose: bool = True ): """ Fit and (optionally) quantify a single spectrum. Parameters ---------- spectrum_vals : numpy.ndarray The measured EDS spectrum (counts per channel). spectrum_lims : tuple of int Tuple specifying the start and end indices for the spectrum region to analyze. microscope_ID : str Microscope identifier for detector calibration data. meas_type : str Measurement type (e.g., 'EDS'). meas_mode : str Measurement mode, defining detector calibrations and (optionally) beam current (e.g., 'point'). det_ch_offset : float Detector channel energy offset (keV). det_ch_width : float Detector channel width (keV). beam_energy : float Electron beam energy (keV). emergence_angle : float Detector emergence (take-off) angle (degrees). sp_collection_time : float or None Live time of spectrum acquisition (in seconds). sample_ID : str Sample identifier. els_sample : list, optional List of elements in the sample. els_substrate : list, optional List of substrate elements. background_vals : array-like or None, optional Background spectrum to subtract. If None, the background will be modeled during fitting. fit_tol : float, optional scipy fit tolerance. Defines conditions of fit convergence is_particle : bool, optional If True, treats sample as particle (powder). Uses particle geometry fitting parameters quantify_plot : bool, optional Whether to quantify the spectrum. max_undetectable_w_fr : float, optional Maximum allowed weight fraction for undetectable elements (default: 0). Total mass fraction of fitted elements is forced to be between [1-max_undetectable_w_fr, 1] force_single_iteration : bool, optional If True, quantification will be run for a single iteration only (default: False). interrupt_fits_bad_spectra : bool, optional If True, interrupt fitting if spectrum is detected to lead to poor quantification (default: False). standards_dict: dict, optional Dictionary of standard values to use for quantification. plot_signal : bool, optional Whether to plot the fitted spectrum. plot_title : str String printed as plot title. zoom_plot : bool, optional Whether to zoom on a specific line. line_to_plot : str, optional Line to zoom on. print_results : bool, optional If True, prints all fitted parameters and their values (default: True). quant_verbose : bool, optional If True, prints quantification operations fitting_verbose : bool, optional If True, prints fitting operations Returns ------- quantifier : XSp_Quantifier The quantifier object containing the results, fit parameters, and methods for further analysis and plotting. """ sample_processing_time_start = time.time() # Quantification quantifier = XSp_Quantifier( spectrum_vals = spectrum_vals, spectrum_lims = spectrum_lims, microscope_ID = microscope_ID, meas_type = meas_type, meas_mode = meas_mode, det_ch_offset=det_ch_offset, det_ch_width=det_ch_width, beam_e=beam_energy, emergence_angle=emergence_angle, background_vals=background_vals, els_sample=els_sample, els_substrate=els_substrate, els_w_fr=None, is_particle=is_particle, sp_collection_time=sp_collection_time, max_undetectable_w_fr=max_undetectable_w_fr, fit_tol=fit_tol, verbose=quant_verbose, fitting_verbose=fitting_verbose, standards_dict = standards_dict ) try: if quantify_plot: quant_result, _, flag = quantifier.quantify_spectrum( force_single_iteration=force_single_iteration, interrupt_fits_bad_spectra=interrupt_fits_bad_spectra, print_result=print_results ) else: quantifier.initialize_and_fit_spectrum( print_results=print_results ) except Exception as e: logging.exception(f"Error during spectral quantification for '{sample_ID}': {e}") return if plot_signal: line_to_zoom = line_to_plot if zoom_plot else '' quantifier.plot_quantified_spectrum( plot_title=plot_title, peaks_to_zoom=line_to_zoom, annotate_peaks='main' ) total_process_time = (time.time() - sample_processing_time_start) print_double_separator() time_str = f"{total_process_time/60:.1f} min" if total_process_time > 100 else f"{total_process_time:.1f} sec" quant_str = 'quantified' if quantify_plot else 'fitted' logging.info(f"Sample '{sample_ID}' successfully {quant_str} in {time_str}.") return quantifier