Skip to content

nxxas_loader

Functions to load data from i06-1 and i10-1 beamline XAS measurements

create_xas_scan(name, energy, monitor, raw_signals, filename='', beamline='', scan_no=0, start_date_iso='', end_date_iso='', cmd='', default_mode='tey', pol='pc', sample_name='', temp=300, mag_field=0, pitch=0, element_edge=None)

Function to load data from i06-1 and i10-1 beamline XAS measurements

Source code in mmg_toolbox/xas/nxxas_loader.py
def create_xas_scan(name, energy: np.ndarray, monitor: np.ndarray, raw_signals: dict[str, np.ndarray],
                    filename: str = '', beamline: str = '', scan_no: int = 0, start_date_iso: str = '',
                    end_date_iso: str = '', cmd: str = '', default_mode: str = 'tey', pol: str = 'pc',
                    sample_name: str = '', temp: float = 300, mag_field: float = 0, pitch: float = 0,
                    element_edge: str | None = None) -> SpectraContainer:
    """
    Function to load data from i06-1 and i10-1 beamline XAS measurements
    """
    # Check spectra
    if default_mode not in raw_signals:
        raise KeyError(f"mode '{default_mode}' is not available in {list(raw_signals.keys())}")
    if element_edge is None:
        element, edge = energy_range_edge_label(energy.min(), energy.max())
    else:
        element, edge = element_edge.split()

    for detector, array in raw_signals.items():
        if len(array) != len(energy):
            print(f"Removing signal '{detector}' as the length is wrong")
            raw_signals.pop(detector)
        if np.max(array) < 0.1:
            print(f"Removing signal '{detector}' as the values are 0")
            raw_signals.pop(detector)
    if len(raw_signals) == 0:
        raise ValueError("No raw_signals found")

    # perform Analysis steps
    spectra = {
        name: Spectra(energy, signal / monitor, mode=name, process_label='raw', process=f"{name} / monitor")
        for name, signal in raw_signals.items()
    }
    metadata = {
        'filename': filename,
        'beamline': beamline,
        'scan_no': scan_no,
        'start_date_iso': start_date_iso,
        'end_date_iso': end_date_iso,
        'cmd': cmd,
        'default_mode': default_mode,
        'pol': pol,
        'sample_name': sample_name,
        'temp': temp,
        'mag_field': mag_field,
        'pitch': pitch,
        'element': element,
        'edge': edge,
        'energy': energy,
        'raw_signals': raw_signals,
        'monitor': monitor,
    }
    m = XasMetadata(**metadata)
    return SpectraContainer(name, spectra, metadata=m)

find_similar_measurements(*filenames, temp_tol=1.0, field_tol=0.1)

Find similar measurements based on energy, temperature and field.

Each measurement is compared to the first one in the list, using energy, temperature and field tolerances.

The polarisation is also checked to be similar (lh, lv or cl, cr).

Scans with different or missing metadata are removed from the list.

Parameters:

Name Type Description Default
filenames str

List of filenames to compare

()
temp_tol

Tolerance for temperature comparison (default: 0.1 K)

1.0
field_tol

Tolerance for field comparison (default: 0.1 T)

0.1

Returns:

Type Description
list[SpectraContainer]

List of similar measurements

Source code in mmg_toolbox/xas/nxxas_loader.py
def find_similar_measurements(*filenames: str, temp_tol=1., field_tol=0.1) -> list[SpectraContainer]:
    """
    Find similar measurements based on energy, temperature and field.

    Each measurement is compared to the first one in the list, using energy, temperature and field tolerances.

    The polarisation is also checked to be similar (lh, lv or cl, cr).

    Scans with different or missing metadata are removed from the list.

    :param filenames: List of filenames to compare
    :param temp_tol: Tolerance for temperature comparison (default: 0.1 K)
    :param field_tol: Tolerance for field comparison (default: 0.1 T)
    :return: List of similar measurements
    """
    from mmg_toolbox.nexus.nexus_reader import find_matching_scans
    ini_scan = load_xas_scans(filenames[0])[0]
    if len(filenames) == 1:
        filenames = find_matching_scans(filenames[0])
    element = ini_scan.metadata.element
    edge = ini_scan.metadata.edge
    temperature = ini_scan.metadata.temp
    field_z = abs(ini_scan.metadata.mag_field)  # allow +/- field
    pol = ini_scan.metadata.pol
    if pol in ['lh', 'lv']:
        similar_pols = ['lh', 'lv']
    elif pol in ['cl', 'cr']:
        similar_pols = ['cl', 'cr']
    elif pol in ['nc', 'pc']:
        similar_pols = ['nc', 'pc']
    else:
        raise ValueError(f"Unknown polarisation: {pol}")

    similar = []
    for filename in filenames:
        try:
            scan = load_xas_scans(filename)[0]
        except ValueError as ve:
            print(f"Error loading {filename} as xas_scan: {ve}")
            continue
        m = scan.metadata
        if (
            m.element == element and
            m.edge == edge and
            abs(m.temp - temperature) < temp_tol and
            abs(abs(m.mag_field) - field_z) < field_tol and
            m.pol in similar_pols
        ):
            similar.append(scan)
        else:
            print(f"Measurement {repr(scan)} is not similar to {repr(ini_scan)}")
    return similar

load_from_nxs_using_hdfmap(filename, sample_name=None, element_edge=None)

Load ScanContainer

Source code in mmg_toolbox/xas/nxxas_loader.py
def load_from_nxs_using_hdfmap(filename: str, sample_name=None, element_edge=None) -> SpectraContainer:
    """Load ScanContainer"""
    import hdfmap

    with hdfmap.load_hdf(filename) as hdf:
        # HdfMap creates data-path namespace
        m = hdfmap.NexusMap()
        m.populate(hdf)

        # scan data
        scan_no = m.eval(hdf, 'entry_identifier', default=get_scan_number(filename))
        energy = m.eval(hdf, Md.energy)
        monitor = m.eval(hdf, Md.monitor)
        mode = 'tey'
        signals = {
            'tey': m.eval(hdf, Md.tey),
            'tfy': m.eval(hdf, Md.tfy),
        }
        # metadata
        beamline = m.eval(hdf, 'f"{beamline}_{end_station}" if end_station else instrument_name')
        start_date_iso = m.eval(hdf, 'str(start_time)')
        end_date_iso = m.eval(hdf, 'str(end_time)')
        cmd = m.eval(hdf, Md.cmd)
        pol = check_polarisation(m.eval(hdf, Md.pol))
        if sample_name is None:
            sample_name = m.eval(hdf, 'sample_name', '')
        temp = m.eval(hdf, Md.temp)
        mag_field = m.eval(hdf, Md.field_z)
        pitch = m.eval(hdf, Md.rot)
    return create_xas_scan(
        name=str(scan_no),
        energy=energy,
        raw_signals=signals,
        monitor=monitor,
        filename=filename,
        beamline=beamline,
        scan_no=scan_no,
        start_date_iso=start_date_iso,
        end_date_iso=end_date_iso,
        cmd=cmd,
        default_mode=mode,
        pol=pol,
        sample_name=sample_name,
        temp=temp,
        mag_field=mag_field,
        pitch=pitch,
        element_edge=element_edge
    )

load_xas_scans(*filenames, sample_name='')

Load scans from a list of filenames, return {'pol': [scan1, scan2, ...]}

Source code in mmg_toolbox/xas/nxxas_loader.py
def load_xas_scans(*filenames: str, sample_name='') -> list[SpectraContainer]:
    """Load scans from a list of filenames, return {'pol': [scan1, scan2, ...]}"""
    scans = [
        load_from_dat(filename, sample_name=sample_name)
        if filename.endswith('.dat') else load_from_nxs_using_hdfmap(filename)
        for filename in filenames
    ]
    return scans