Source code for nexusLIMS.extractors.edax

#  NIST Public License - 2023
#
#  This software was developed by employees of the National Institute of
#  Standards and Technology (NIST), an agency of the Federal Government
#  and is being made available as a public service. Pursuant to title 17
#  United States Code Section 105, works of NIST employees are not subject
#  to copyright protection in the United States.  This software may be
#  subject to foreign copyright.  Permission in the United States and in
#  foreign countries, to the extent that NIST may hold copyright, to use,
#  copy, modify, create derivative works, and distribute this software and
#  its documentation without fee is hereby granted on a non-exclusive basis,
#  provided that this notice and disclaimer of warranty appears in all copies.
#
#  THE SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND,
#  EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED
#  TO, ANY WARRANTY THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY
#  IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
#  AND FREEDOM FROM INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION
#  WILL CONFORM TO THE SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE
#  ERROR FREE.  IN NO EVENT SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING,
#  BUT NOT LIMITED TO, DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES,
#  ARISING OUT OF, RESULTING FROM, OR IN ANY WAY CONNECTED WITH THIS SOFTWARE,
#  WHETHER OR NOT BASED UPON WARRANTY, CONTRACT, TORT, OR OTHERWISE, WHETHER
#  OR NOT INJURY WAS SUSTAINED BY PERSONS OR PROPERTY OR OTHERWISE, AND
#  WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT OF THE RESULTS OF,
#  OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER.
#
"""Parse metadata from EDAX EDS spectra saved as .spc and .msa files."""
import logging
from pathlib import Path
from typing import Dict, Optional

from hyperspy.io import load

from nexusLIMS.extractors.utils import _set_instr_name_and_time
from nexusLIMS.utils import try_getting_dict_value

logger = logging.getLogger(__name__)


[docs]def get_spc_metadata(filename: Path) -> Optional[Dict]: """ Return the metadata (as a dict) from a .spc file. This type of file is produced by EDAX EDS software. It is read by HyperSpy's file reader and relevant metadata extracted and returned Parameters ---------- filename path to a .spc file saved by EDAX software (Genesis, TEAM, etc.) Returns ------- metadata : Optional[Dict] The metadata of interest extracted from the file. If None, the file could not be opened """ mdict = {"nx_meta": {}} # assume all .spc datasets are EDS single spectra mdict["nx_meta"]["DatasetType"] = "Spectrum" mdict["nx_meta"]["Data Type"] = "EDS_Spectrum" _set_instr_name_and_time(mdict, filename) s = load(filename, lazy=True) # original_metadata puts the entire xml under the root node "spc_header", # so this will just bump that all up to the root level for ease of use. mdict["original_metadata"] = s.original_metadata["spc_header"].as_dictionary() term_mapping = { "azimuth": "Azimuthal Angle (deg)", "liveTime": "Live Time (s)", "detReso": "Detector Energy Resolution (eV)", "elevation": "Elevation Angle (deg)", "evPerChan": "Channel Size (eV)", "kV": "Accelerating Voltage (kV)", "numPts": "Number of Spectrum Channels", "startEnergy": "Starting Energy (keV)", "endEnergy": "Ending Energy (keV)", "tilt": "Stage Tilt (deg)", } for in_term, out_term in term_mapping.items(): if try_getting_dict_value(mdict["original_metadata"], in_term) != "not found": mdict["nx_meta"][out_term] = mdict["original_metadata"][in_term] # add any elements present: if "Sample" in s.metadata and "elements" in s.metadata.Sample: mdict["nx_meta"]["Elements"] = s.metadata.Sample.elements return mdict
[docs]def get_msa_metadata(filename: Path) -> Optional[Dict]: """ Return the metadata (as a dict) from an .msa spectrum file. This file may be saved by a number of different EDS acquisition software, but most often is produced as an export from EDAX or Oxford software. This format is a standard, but vendors (such as EDAX) often add other values into the metadata header. See https://www.microscopy.org/resources/scientific_data/ for the fomal specification. Parameters ---------- filename path to a .msa file saved by various EDS software packages Returns ------- metadata : Optional[Dict] The metadata of interest extracted from the file. If None, the file could not be opened """ s = load(filename, lazy=True) mdict = {"nx_meta": {}} mdict["original_metadata"] = s.original_metadata.as_dictionary() # assume all .spc datasets are EDS single spectra mdict["nx_meta"]["DatasetType"] = "Spectrum" mdict["nx_meta"]["Data Type"] = "EDS_Spectrum" _set_instr_name_and_time(mdict, filename) term_mapping = { "AZIMANGLE-dg": "Azimuthal Angle (deg)", "AmpTime (usec)": "Amplifier Time (μs)", "Analyzer Type": "Analyzer Type", "BEAMKV -kV": "Beam Energy (keV)", "CHOFFSET": "Channel Offset", "COMMENT": "EDAX Comment", "DATATYPE": "Data Format", "DATE": "EDAX Date", "ELEVANGLE-dg": "Elevation Angle (deg)", "Elements": "User-Selected Elements", "FILENAME": "Originating File of MSA Export", "FORMAT": "File Format", "FPGA Version": "FPGA Version", "LIVETIME -s": "Live Time (s)", "NCOLUMNS": "Number of Data Columns", "NPOINTS": "Number of Data Points", "OFFSET": "Offset", "OWNER": "EDAX Owner", "REALTIME -s": "Real Time (s)", "RESO (MnKa)": "Energy Resolution (eV)", "SIGNALTYPE": "Signal Type", "TACTYLR -cm": "Active Layer Thickness (cm)", "TBEWIND -cm": "Be Window Thickness (cm)", "TDEADLYR -cm": "Dead Layer Thickness (cm)", "TIME": "EDAX Time", "TITLE": "EDAX Title", "TakeOff Angle": "TakeOff Angle (deg)", "Tilt Angle": "Stage Tilt (deg)", "VERSION": "MSA Format Version", "XLABEL": "X Column Label", "XPERCHAN": "X Units Per Channel", "XUNITS": "X Column Units", "YLABEL": "Y Column Label", "YUNITS": "Y Column Units", } for in_term, out_term in term_mapping.items(): if try_getting_dict_value(mdict["original_metadata"], in_term) != "not found": mdict["nx_meta"][out_term] = mdict["original_metadata"][in_term] return mdict