A comprehensive collection of algorithms and routines for electron microscopy data analysis and simulation.
—
Specialized functionality for energy-dispersive X-ray spectroscopy (EDS) tomography including preprocessing, reconstruction interface with GENFIRE, postprocessing tools, and characteristic X-ray emission analysis for quantitative elemental mapping.
Functions for analyzing characteristic X-ray emission lines and fluorescence data using the Elam database.
def GetElamFluorescenceLines(element, emission_type='Ka'):
"""
Get fluorescence lines from Elam database for specified element.
Parameters:
- element: str, chemical element symbol (e.g., 'Fe', 'Cu')
- emission_type: str, X-ray emission type ('Ka', 'Kb', 'La', 'Lb', 'Ma')
Returns:
dict: Dictionary containing:
- 'energies': numpy.ndarray, emission line energies (keV)
- 'intensities': numpy.ndarray, relative intensities
- 'transitions': list, transition labels
"""
def GetFluorescenceLineEnergy(element, transition):
"""
Get specific fluorescence line energy for element and transition.
Parameters:
- element: str, chemical element symbol
- transition: str, specific transition (e.g., 'Ka1', 'Kb1')
Returns:
float: Emission line energy in keV
"""
def GetWeightedSum(spectra, weights):
"""
Calculate weighted sum of spectral data.
Parameters:
- spectra: numpy.ndarray, spectral data array
- weights: numpy.ndarray, weighting factors
Returns:
numpy.ndarray: Weighted sum spectrum
"""Functions for working with Bruker EDS system data including tilt series and spatial/energy calibration.
def GetTiltsFromBrukerSequence(sequence_file):
"""
Extract tilt angles from Bruker sequence file.
Parameters:
- sequence_file: str, path to Bruker sequence file
Returns:
numpy.ndarray: Array of tilt angles in degrees
"""
def GetSpatialDimension(bruker_data):
"""
Get spatial dimension information from Bruker data.
Parameters:
- bruker_data: dict, Bruker data structure
Returns:
dict: Spatial calibration information including:
- 'pixel_size': tuple, (x_size, y_size) in physical units
- 'units': str, spatial units
- 'dimensions': tuple, (width, height) in pixels
"""
def GetEnergyDimension(bruker_data):
"""
Get energy dimension calibration from Bruker data.
Parameters:
- bruker_data: dict, Bruker data structure
Returns:
dict: Energy calibration information including:
- 'energy_scale': numpy.ndarray, energy values for each channel
- 'energy_offset': float, energy offset (keV)
- 'energy_gain': float, energy per channel (keV/channel)
- 'num_channels': int, number of energy channels
"""
def ExtractRawSignalsFromBrukerSequence(sequence_file, output_path):
"""
Extract raw EDS signals from Bruker sequence file.
Parameters:
- sequence_file: str, path to Bruker sequence file
- output_path: str, directory for extracted signals
Returns:
dict: Extraction results including:
- 'num_projections': int, number of tilt projections
- 'signal_files': list, paths to extracted signal files
- 'metadata': dict, acquisition metadata
"""Comprehensive preprocessing functions for EDS tomography data preparation including spatial binning, normalization, and alignment.
def BinEDSSpatialDimensions(eds_data, bin_factor):
"""
Bin EDS spatial dimensions to reduce data size and improve SNR.
Parameters:
- eds_data: numpy.ndarray, 4D EDS data (tilts, y, x, energy)
- bin_factor: int or tuple, binning factor for spatial dimensions
Returns:
numpy.ndarray: Spatially binned EDS data
"""
def ExtractSignalsFromEMD(emd_file, element_list, energy_windows=None):
"""
Extract elemental signals from EMD EDS data file.
Parameters:
- emd_file: str, path to EMD file containing EDS data
- element_list: list, chemical elements to extract
- energy_windows: dict, custom energy windows for each element
Returns:
dict: Dictionary with element names as keys and signal arrays as values
"""
def NormalizeSignals(signal_data, method='dose'):
"""
Normalize EDS signal intensities across projections.
Parameters:
- signal_data: numpy.ndarray, 3D signal data (tilts, y, x)
- method: str, normalization method ('dose', 'total_counts', 'background')
Returns:
numpy.ndarray: Normalized signal data
"""
def GetNormalizationCurve(signal_data, reference_region=None):
"""
Calculate normalization curve for intensity correction.
Parameters:
- signal_data: numpy.ndarray, signal data to analyze
- reference_region: tuple, (y_slice, x_slice) for reference region
Returns:
numpy.ndarray: Normalization factors for each projection
"""
def ReadImageJTranslations(translation_file):
"""
Read translation data from ImageJ alignment results.
Parameters:
- translation_file: str, path to ImageJ translation file
Returns:
numpy.ndarray: Translation vectors (N, 2) for (x, y) shifts
"""
def ReadTomVizTranslations(translation_file):
"""
Read translation data from TomViz alignment results.
Parameters:
- translation_file: str, path to TomViz translation file
Returns:
numpy.ndarray: Translation vectors (N, 2) for (x, y) shifts
"""
def ApplyTranslations(signal_data, translations):
"""
Apply translation corrections to signal data.
Parameters:
- signal_data: numpy.ndarray, 3D signal data (tilts, y, x)
- translations: numpy.ndarray, translation vectors from alignment
Returns:
numpy.ndarray: Translation-corrected signal data
"""Functions for interfacing with tomographic reconstruction software and managing intermediate data files.
def WriteSignalsToTIFFs(signal_data, output_dir, element_name):
"""
Write signal projections to TIFF files for external processing.
Parameters:
- signal_data: numpy.ndarray, 3D signal data (tilts, y, x)
- output_dir: str, output directory path
- element_name: str, element identifier for file naming
Returns:
list: Paths to written TIFF files
"""
def ReadSignalsFromTIFFs(tiff_dir, pattern='*.tiff'):
"""
Read signal projections from TIFF files.
Parameters:
- tiff_dir: str, directory containing TIFF files
- pattern: str, file pattern for matching TIFF files
Returns:
numpy.ndarray: 3D signal data array (tilts, y, x)
"""
def WriteMetaDataFiles(metadata, output_dir):
"""
Write metadata files for reconstruction software.
Parameters:
- metadata: dict, reconstruction metadata including angles, pixel sizes
- output_dir: str, output directory path
"""
def ReadMetaDataFiles(metadata_dir):
"""
Read metadata files from reconstruction directory.
Parameters:
- metadata_dir: str, directory containing metadata files
Returns:
dict: Reconstruction metadata
"""
def WriteSignalsToGENFIRE(signal_data, angles, output_file, **kwargs):
"""
Write signals in GENFIRE-compatible format for reconstruction.
Parameters:
- signal_data: numpy.ndarray, 3D signal data (tilts, y, x)
- angles: numpy.ndarray, tilt angles in degrees
- output_file: str, output file path
- **kwargs: additional GENFIRE parameters
"""Functions for processing reconstruction results and extracting quantitative information.
def ReadGENFIRESignals(results_file):
"""
Read GENFIRE reconstruction results.
Parameters:
- results_file: str, path to GENFIRE results file
Returns:
dict: Dictionary containing:
- 'reconstruction': numpy.ndarray, 3D reconstructed volume
- 'error_metrics': dict, reconstruction quality metrics
- 'parameters': dict, reconstruction parameters used
"""
def SquareCropSignal(signal_data, crop_size=None):
"""
Square crop signal data around center.
Parameters:
- signal_data: numpy.ndarray, input signal data
- crop_size: int, size of square crop region
Returns:
numpy.ndarray: Square-cropped signal data
"""import ncempy.edstomo as eds
import numpy as np
# 1. Extract signals from Bruker data
sequence_file = 'eds_tilt_series.bcf'
raw_signals = eds.ExtractRawSignalsFromBrukerSequence(sequence_file, './raw_data/')
# 2. Load and preprocess EDS data
emd_file = 'eds_data.emd'
elements = ['Fe', 'O', 'Ti']
signals = eds.ExtractSignalsFromEMD(emd_file, elements)
# 3. Bin spatially to improve SNR
for element in elements:
signals[element] = eds.BinEDSSpatialDimensions(signals[element], bin_factor=2)
# 4. Normalize signals
for element in elements:
signals[element] = eds.NormalizeSignals(signals[element], method='dose')
# 5. Apply alignment corrections if available
translations = eds.ReadImageJTranslations('alignment_results.txt')
for element in elements:
signals[element] = eds.ApplyTranslations(signals[element], translations)
# 6. Prepare for reconstruction
tilt_angles = eds.GetTiltsFromBrukerSequence(sequence_file)
for element in elements:
eds.WriteSignalsToGENFIRE(signals[element], tilt_angles,
f'genfire_input_{element}.h5')
print(f"Preprocessed {len(elements)} elements for reconstruction")
print(f"Tilt series: {len(tilt_angles)} projections from {tilt_angles.min():.1f}° to {tilt_angles.max():.1f}°")import ncempy.edstomo as eds
import matplotlib.pyplot as plt
# Analyze characteristic X-rays for iron
iron_lines = eds.GetElamFluorescenceLines('Fe', 'Ka')
print(f"Iron Ka lines: {iron_lines['transitions']}")
print(f"Energies: {iron_lines['energies']} keV")
# Get specific line energy
ka1_energy = eds.GetFluorescenceLineEnergy('Fe', 'Ka1')
print(f"Fe Ka1 energy: {ka1_energy:.3f} keV")
# Plot characteristic X-ray spectrum
plt.figure(figsize=(10, 6))
for i, (energy, intensity, transition) in enumerate(zip(
iron_lines['energies'], iron_lines['intensities'], iron_lines['transitions'])):
plt.vlines(energy, 0, intensity, colors='red', alpha=0.7)
plt.text(energy, intensity + 0.1, transition, rotation=90, ha='center')
plt.xlabel('Energy (keV)')
plt.ylabel('Relative Intensity')
plt.title('Iron Ka Characteristic X-ray Lines')
plt.grid(True, alpha=0.3)
plt.show()import ncempy.edstomo as eds
import matplotlib.pyplot as plt
# Define elements and energy windows
elements = ['Fe', 'Ti', 'O', 'C']
energy_windows = {
'Fe': (6.2, 6.6), # Fe Ka region
'Ti': (4.4, 4.7), # Ti Ka region
'O': (0.4, 0.7), # O Ka region
'C': (0.2, 0.4) # C Ka region
}
# Extract signals from EDS data
eds_file = 'multielement_eds.emd'
signals = eds.ExtractSignalsFromEMD(eds_file, elements, energy_windows)
# Display signal maps for first projection
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
axes = axes.flatten()
for i, element in enumerate(elements):
signal_map = signals[element][0] # First projection
im = axes[i].imshow(signal_map, cmap='hot')
axes[i].set_title(f'{element} Signal Map')
plt.colorbar(im, ax=axes[i])
plt.tight_layout()
plt.show()
# Print signal statistics
for element in elements:
signal = signals[element]
print(f"{element}: {signal.shape[0]} projections, "
f"total counts = {signal.sum():.0f}")import ncempy.edstomo as eds
import numpy as np
# Load raw EDS data
raw_data = load_eds_data() # Shape: (tilts, y, x, energy)
# 1. Spatial binning
binned_data = eds.BinEDSSpatialDimensions(raw_data, bin_factor=(2, 2))
print(f"Binned from {raw_data.shape} to {binned_data.shape}")
# 2. Extract elemental signals
elements = ['Fe', 'Ni', 'Cr']
signals = {}
for element in elements:
# Get characteristic energy for element
ka_energy = eds.GetFluorescenceLineEnergy(element, 'Ka1')
# Extract signal in energy window around Ka line
energy_window = (ka_energy - 0.2, ka_energy + 0.2)
signals[element] = extract_signal_window(binned_data, energy_window)
# 3. Normalize signals
normalization_curves = {}
for element in elements:
normalization_curves[element] = eds.GetNormalizationCurve(signals[element])
signals[element] = eds.NormalizeSignals(signals[element])
# 4. Apply alignment if available
if alignment_file_exists:
translations = eds.ReadImageJTranslations('alignment.txt')
for element in elements:
signals[element] = eds.ApplyTranslations(signals[element], translations)
# 5. Write preprocessed data
for element in elements:
eds.WriteSignalsToTIFFs(signals[element], './preprocessed/', element)
print("Preprocessing complete")import ncempy.edstomo as eds
import subprocess
# Prepare data for GENFIRE reconstruction
element = 'Fe'
signal_data = preprocessed_signals[element]
tilt_angles = np.array([-60, -45, -30, -15, 0, 15, 30, 45, 60])
# Write GENFIRE input file
genfire_file = f'genfire_input_{element}.h5'
eds.WriteSignalsToGENFIRE(signal_data, tilt_angles, genfire_file,
iterations=50, oversample=3)
# Write metadata files
metadata = {
'angles': tilt_angles,
'pixel_size': 0.5, # nm
'element': element
}
eds.WriteMetaDataFiles(metadata, './reconstruction/')
print(f"GENFIRE input prepared: {genfire_file}")
print(f"Ready for reconstruction with {len(tilt_angles)} projections")
# After GENFIRE reconstruction completes...
results = eds.ReadGENFIRESignals('genfire_results.h5')
reconstruction = results['reconstruction']
print(f"Reconstruction shape: {reconstruction.shape}")
print(f"Reconstruction quality metrics: {results['error_metrics']}")
# Postprocess reconstruction
cropped_recon = eds.SquareCropSignal(reconstruction, crop_size=256)import ncempy.edstomo as eds
import os
# Process multiple elements in batch
elements = ['Fe', 'Ni', 'Cr', 'Ti']
input_dir = './raw_eds_data/'
output_dir = './processed_signals/'
os.makedirs(output_dir, exist_ok=True)
for element in elements:
print(f"Processing {element}...")
# Load element-specific data
element_file = os.path.join(input_dir, f'{element}_eds.emd')
if os.path.exists(element_file):
signals = eds.ExtractSignalsFromEMD(element_file, [element])
# Preprocess
signals[element] = eds.NormalizeSignals(signals[element])
# Save processed signals
output_file = os.path.join(output_dir, f'{element}_processed.tiff')
eds.WriteSignalsToTIFFs(signals[element], output_dir, element)
print(f" Processed {signals[element].shape[0]} projections")
else:
print(f" Skipping {element} - file not found")
print("Batch processing complete")Install with Tessl CLI
npx tessl i tessl/pypi-ncempy