0
# EDS Tomography
1
2
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.
3
4
## Capabilities
5
6
### Characteristic X-ray Emission
7
8
Functions for analyzing characteristic X-ray emission lines and fluorescence data using the Elam database.
9
10
```python { .api }
11
def GetElamFluorescenceLines(element, emission_type='Ka'):
12
"""
13
Get fluorescence lines from Elam database for specified element.
14
15
Parameters:
16
- element: str, chemical element symbol (e.g., 'Fe', 'Cu')
17
- emission_type: str, X-ray emission type ('Ka', 'Kb', 'La', 'Lb', 'Ma')
18
19
Returns:
20
dict: Dictionary containing:
21
- 'energies': numpy.ndarray, emission line energies (keV)
22
- 'intensities': numpy.ndarray, relative intensities
23
- 'transitions': list, transition labels
24
"""
25
26
def GetFluorescenceLineEnergy(element, transition):
27
"""
28
Get specific fluorescence line energy for element and transition.
29
30
Parameters:
31
- element: str, chemical element symbol
32
- transition: str, specific transition (e.g., 'Ka1', 'Kb1')
33
34
Returns:
35
float: Emission line energy in keV
36
"""
37
38
def GetWeightedSum(spectra, weights):
39
"""
40
Calculate weighted sum of spectral data.
41
42
Parameters:
43
- spectra: numpy.ndarray, spectral data array
44
- weights: numpy.ndarray, weighting factors
45
46
Returns:
47
numpy.ndarray: Weighted sum spectrum
48
"""
49
```
50
51
### Bruker System Integration
52
53
Functions for working with Bruker EDS system data including tilt series and spatial/energy calibration.
54
55
```python { .api }
56
def GetTiltsFromBrukerSequence(sequence_file):
57
"""
58
Extract tilt angles from Bruker sequence file.
59
60
Parameters:
61
- sequence_file: str, path to Bruker sequence file
62
63
Returns:
64
numpy.ndarray: Array of tilt angles in degrees
65
"""
66
67
def GetSpatialDimension(bruker_data):
68
"""
69
Get spatial dimension information from Bruker data.
70
71
Parameters:
72
- bruker_data: dict, Bruker data structure
73
74
Returns:
75
dict: Spatial calibration information including:
76
- 'pixel_size': tuple, (x_size, y_size) in physical units
77
- 'units': str, spatial units
78
- 'dimensions': tuple, (width, height) in pixels
79
"""
80
81
def GetEnergyDimension(bruker_data):
82
"""
83
Get energy dimension calibration from Bruker data.
84
85
Parameters:
86
- bruker_data: dict, Bruker data structure
87
88
Returns:
89
dict: Energy calibration information including:
90
- 'energy_scale': numpy.ndarray, energy values for each channel
91
- 'energy_offset': float, energy offset (keV)
92
- 'energy_gain': float, energy per channel (keV/channel)
93
- 'num_channels': int, number of energy channels
94
"""
95
96
def ExtractRawSignalsFromBrukerSequence(sequence_file, output_path):
97
"""
98
Extract raw EDS signals from Bruker sequence file.
99
100
Parameters:
101
- sequence_file: str, path to Bruker sequence file
102
- output_path: str, directory for extracted signals
103
104
Returns:
105
dict: Extraction results including:
106
- 'num_projections': int, number of tilt projections
107
- 'signal_files': list, paths to extracted signal files
108
- 'metadata': dict, acquisition metadata
109
"""
110
```
111
112
### Data Preprocessing
113
114
Comprehensive preprocessing functions for EDS tomography data preparation including spatial binning, normalization, and alignment.
115
116
```python { .api }
117
def BinEDSSpatialDimensions(eds_data, bin_factor):
118
"""
119
Bin EDS spatial dimensions to reduce data size and improve SNR.
120
121
Parameters:
122
- eds_data: numpy.ndarray, 4D EDS data (tilts, y, x, energy)
123
- bin_factor: int or tuple, binning factor for spatial dimensions
124
125
Returns:
126
numpy.ndarray: Spatially binned EDS data
127
"""
128
129
def ExtractSignalsFromEMD(emd_file, element_list, energy_windows=None):
130
"""
131
Extract elemental signals from EMD EDS data file.
132
133
Parameters:
134
- emd_file: str, path to EMD file containing EDS data
135
- element_list: list, chemical elements to extract
136
- energy_windows: dict, custom energy windows for each element
137
138
Returns:
139
dict: Dictionary with element names as keys and signal arrays as values
140
"""
141
142
def NormalizeSignals(signal_data, method='dose'):
143
"""
144
Normalize EDS signal intensities across projections.
145
146
Parameters:
147
- signal_data: numpy.ndarray, 3D signal data (tilts, y, x)
148
- method: str, normalization method ('dose', 'total_counts', 'background')
149
150
Returns:
151
numpy.ndarray: Normalized signal data
152
"""
153
154
def GetNormalizationCurve(signal_data, reference_region=None):
155
"""
156
Calculate normalization curve for intensity correction.
157
158
Parameters:
159
- signal_data: numpy.ndarray, signal data to analyze
160
- reference_region: tuple, (y_slice, x_slice) for reference region
161
162
Returns:
163
numpy.ndarray: Normalization factors for each projection
164
"""
165
166
def ReadImageJTranslations(translation_file):
167
"""
168
Read translation data from ImageJ alignment results.
169
170
Parameters:
171
- translation_file: str, path to ImageJ translation file
172
173
Returns:
174
numpy.ndarray: Translation vectors (N, 2) for (x, y) shifts
175
"""
176
177
def ReadTomVizTranslations(translation_file):
178
"""
179
Read translation data from TomViz alignment results.
180
181
Parameters:
182
- translation_file: str, path to TomViz translation file
183
184
Returns:
185
numpy.ndarray: Translation vectors (N, 2) for (x, y) shifts
186
"""
187
188
def ApplyTranslations(signal_data, translations):
189
"""
190
Apply translation corrections to signal data.
191
192
Parameters:
193
- signal_data: numpy.ndarray, 3D signal data (tilts, y, x)
194
- translations: numpy.ndarray, translation vectors from alignment
195
196
Returns:
197
numpy.ndarray: Translation-corrected signal data
198
"""
199
```
200
201
### File I/O for Reconstruction
202
203
Functions for interfacing with tomographic reconstruction software and managing intermediate data files.
204
205
```python { .api }
206
def WriteSignalsToTIFFs(signal_data, output_dir, element_name):
207
"""
208
Write signal projections to TIFF files for external processing.
209
210
Parameters:
211
- signal_data: numpy.ndarray, 3D signal data (tilts, y, x)
212
- output_dir: str, output directory path
213
- element_name: str, element identifier for file naming
214
215
Returns:
216
list: Paths to written TIFF files
217
"""
218
219
def ReadSignalsFromTIFFs(tiff_dir, pattern='*.tiff'):
220
"""
221
Read signal projections from TIFF files.
222
223
Parameters:
224
- tiff_dir: str, directory containing TIFF files
225
- pattern: str, file pattern for matching TIFF files
226
227
Returns:
228
numpy.ndarray: 3D signal data array (tilts, y, x)
229
"""
230
231
def WriteMetaDataFiles(metadata, output_dir):
232
"""
233
Write metadata files for reconstruction software.
234
235
Parameters:
236
- metadata: dict, reconstruction metadata including angles, pixel sizes
237
- output_dir: str, output directory path
238
"""
239
240
def ReadMetaDataFiles(metadata_dir):
241
"""
242
Read metadata files from reconstruction directory.
243
244
Parameters:
245
- metadata_dir: str, directory containing metadata files
246
247
Returns:
248
dict: Reconstruction metadata
249
"""
250
251
def WriteSignalsToGENFIRE(signal_data, angles, output_file, **kwargs):
252
"""
253
Write signals in GENFIRE-compatible format for reconstruction.
254
255
Parameters:
256
- signal_data: numpy.ndarray, 3D signal data (tilts, y, x)
257
- angles: numpy.ndarray, tilt angles in degrees
258
- output_file: str, output file path
259
- **kwargs: additional GENFIRE parameters
260
"""
261
```
262
263
### Postprocessing
264
265
Functions for processing reconstruction results and extracting quantitative information.
266
267
```python { .api }
268
def ReadGENFIRESignals(results_file):
269
"""
270
Read GENFIRE reconstruction results.
271
272
Parameters:
273
- results_file: str, path to GENFIRE results file
274
275
Returns:
276
dict: Dictionary containing:
277
- 'reconstruction': numpy.ndarray, 3D reconstructed volume
278
- 'error_metrics': dict, reconstruction quality metrics
279
- 'parameters': dict, reconstruction parameters used
280
"""
281
282
def SquareCropSignal(signal_data, crop_size=None):
283
"""
284
Square crop signal data around center.
285
286
Parameters:
287
- signal_data: numpy.ndarray, input signal data
288
- crop_size: int, size of square crop region
289
290
Returns:
291
numpy.ndarray: Square-cropped signal data
292
"""
293
```
294
295
## Usage Examples
296
297
### Complete EDS Tomography Workflow
298
299
```python
300
import ncempy.edstomo as eds
301
import numpy as np
302
303
# 1. Extract signals from Bruker data
304
sequence_file = 'eds_tilt_series.bcf'
305
raw_signals = eds.ExtractRawSignalsFromBrukerSequence(sequence_file, './raw_data/')
306
307
# 2. Load and preprocess EDS data
308
emd_file = 'eds_data.emd'
309
elements = ['Fe', 'O', 'Ti']
310
signals = eds.ExtractSignalsFromEMD(emd_file, elements)
311
312
# 3. Bin spatially to improve SNR
313
for element in elements:
314
signals[element] = eds.BinEDSSpatialDimensions(signals[element], bin_factor=2)
315
316
# 4. Normalize signals
317
for element in elements:
318
signals[element] = eds.NormalizeSignals(signals[element], method='dose')
319
320
# 5. Apply alignment corrections if available
321
translations = eds.ReadImageJTranslations('alignment_results.txt')
322
for element in elements:
323
signals[element] = eds.ApplyTranslations(signals[element], translations)
324
325
# 6. Prepare for reconstruction
326
tilt_angles = eds.GetTiltsFromBrukerSequence(sequence_file)
327
for element in elements:
328
eds.WriteSignalsToGENFIRE(signals[element], tilt_angles,
329
f'genfire_input_{element}.h5')
330
331
print(f"Preprocessed {len(elements)} elements for reconstruction")
332
print(f"Tilt series: {len(tilt_angles)} projections from {tilt_angles.min():.1f}° to {tilt_angles.max():.1f}°")
333
```
334
335
### Characteristic X-ray Analysis
336
337
```python
338
import ncempy.edstomo as eds
339
import matplotlib.pyplot as plt
340
341
# Analyze characteristic X-rays for iron
342
iron_lines = eds.GetElamFluorescenceLines('Fe', 'Ka')
343
print(f"Iron Ka lines: {iron_lines['transitions']}")
344
print(f"Energies: {iron_lines['energies']} keV")
345
346
# Get specific line energy
347
ka1_energy = eds.GetFluorescenceLineEnergy('Fe', 'Ka1')
348
print(f"Fe Ka1 energy: {ka1_energy:.3f} keV")
349
350
# Plot characteristic X-ray spectrum
351
plt.figure(figsize=(10, 6))
352
for i, (energy, intensity, transition) in enumerate(zip(
353
iron_lines['energies'], iron_lines['intensities'], iron_lines['transitions'])):
354
plt.vlines(energy, 0, intensity, colors='red', alpha=0.7)
355
plt.text(energy, intensity + 0.1, transition, rotation=90, ha='center')
356
357
plt.xlabel('Energy (keV)')
358
plt.ylabel('Relative Intensity')
359
plt.title('Iron Ka Characteristic X-ray Lines')
360
plt.grid(True, alpha=0.3)
361
plt.show()
362
```
363
364
### Multi-Element Signal Extraction
365
366
```python
367
import ncempy.edstomo as eds
368
import matplotlib.pyplot as plt
369
370
# Define elements and energy windows
371
elements = ['Fe', 'Ti', 'O', 'C']
372
energy_windows = {
373
'Fe': (6.2, 6.6), # Fe Ka region
374
'Ti': (4.4, 4.7), # Ti Ka region
375
'O': (0.4, 0.7), # O Ka region
376
'C': (0.2, 0.4) # C Ka region
377
}
378
379
# Extract signals from EDS data
380
eds_file = 'multielement_eds.emd'
381
signals = eds.ExtractSignalsFromEMD(eds_file, elements, energy_windows)
382
383
# Display signal maps for first projection
384
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
385
axes = axes.flatten()
386
387
for i, element in enumerate(elements):
388
signal_map = signals[element][0] # First projection
389
im = axes[i].imshow(signal_map, cmap='hot')
390
axes[i].set_title(f'{element} Signal Map')
391
plt.colorbar(im, ax=axes[i])
392
393
plt.tight_layout()
394
plt.show()
395
396
# Print signal statistics
397
for element in elements:
398
signal = signals[element]
399
print(f"{element}: {signal.shape[0]} projections, "
400
f"total counts = {signal.sum():.0f}")
401
```
402
403
### Data Preprocessing Pipeline
404
405
```python
406
import ncempy.edstomo as eds
407
import numpy as np
408
409
# Load raw EDS data
410
raw_data = load_eds_data() # Shape: (tilts, y, x, energy)
411
412
# 1. Spatial binning
413
binned_data = eds.BinEDSSpatialDimensions(raw_data, bin_factor=(2, 2))
414
print(f"Binned from {raw_data.shape} to {binned_data.shape}")
415
416
# 2. Extract elemental signals
417
elements = ['Fe', 'Ni', 'Cr']
418
signals = {}
419
for element in elements:
420
# Get characteristic energy for element
421
ka_energy = eds.GetFluorescenceLineEnergy(element, 'Ka1')
422
423
# Extract signal in energy window around Ka line
424
energy_window = (ka_energy - 0.2, ka_energy + 0.2)
425
signals[element] = extract_signal_window(binned_data, energy_window)
426
427
# 3. Normalize signals
428
normalization_curves = {}
429
for element in elements:
430
normalization_curves[element] = eds.GetNormalizationCurve(signals[element])
431
signals[element] = eds.NormalizeSignals(signals[element])
432
433
# 4. Apply alignment if available
434
if alignment_file_exists:
435
translations = eds.ReadImageJTranslations('alignment.txt')
436
for element in elements:
437
signals[element] = eds.ApplyTranslations(signals[element], translations)
438
439
# 5. Write preprocessed data
440
for element in elements:
441
eds.WriteSignalsToTIFFs(signals[element], './preprocessed/', element)
442
443
print("Preprocessing complete")
444
```
445
446
### Reconstruction Interface
447
448
```python
449
import ncempy.edstomo as eds
450
import subprocess
451
452
# Prepare data for GENFIRE reconstruction
453
element = 'Fe'
454
signal_data = preprocessed_signals[element]
455
tilt_angles = np.array([-60, -45, -30, -15, 0, 15, 30, 45, 60])
456
457
# Write GENFIRE input file
458
genfire_file = f'genfire_input_{element}.h5'
459
eds.WriteSignalsToGENFIRE(signal_data, tilt_angles, genfire_file,
460
iterations=50, oversample=3)
461
462
# Write metadata files
463
metadata = {
464
'angles': tilt_angles,
465
'pixel_size': 0.5, # nm
466
'element': element
467
}
468
eds.WriteMetaDataFiles(metadata, './reconstruction/')
469
470
print(f"GENFIRE input prepared: {genfire_file}")
471
print(f"Ready for reconstruction with {len(tilt_angles)} projections")
472
473
# After GENFIRE reconstruction completes...
474
results = eds.ReadGENFIRESignals('genfire_results.h5')
475
reconstruction = results['reconstruction']
476
477
print(f"Reconstruction shape: {reconstruction.shape}")
478
print(f"Reconstruction quality metrics: {results['error_metrics']}")
479
480
# Postprocess reconstruction
481
cropped_recon = eds.SquareCropSignal(reconstruction, crop_size=256)
482
```
483
484
### Batch Processing Multiple Elements
485
486
```python
487
import ncempy.edstomo as eds
488
import os
489
490
# Process multiple elements in batch
491
elements = ['Fe', 'Ni', 'Cr', 'Ti']
492
input_dir = './raw_eds_data/'
493
output_dir = './processed_signals/'
494
495
os.makedirs(output_dir, exist_ok=True)
496
497
for element in elements:
498
print(f"Processing {element}...")
499
500
# Load element-specific data
501
element_file = os.path.join(input_dir, f'{element}_eds.emd')
502
if os.path.exists(element_file):
503
signals = eds.ExtractSignalsFromEMD(element_file, [element])
504
505
# Preprocess
506
signals[element] = eds.NormalizeSignals(signals[element])
507
508
# Save processed signals
509
output_file = os.path.join(output_dir, f'{element}_processed.tiff')
510
eds.WriteSignalsToTIFFs(signals[element], output_dir, element)
511
512
print(f" Processed {signals[element].shape[0]} projections")
513
else:
514
print(f" Skipping {element} - file not found")
515
516
print("Batch processing complete")
517
```