Quantifying K412 using NeXLSpectrum and NeXLMatrixCorrection

This document demonstrates the high-level API for filter fitting spectra. This API is less flexible than the low-level API discussed here.

Libraries

Use the NeXLSpectrum to load, plot, fit and report the quantification of a set of K412 spectra.

Loading NeXLSpectrum also automatically makes NeXLCore and NeXLUncertainties available.

Loading the Gadfly library adds plotting support to NeXLSpectrum.

using NeXLSpectrum              # Provides spectrum reading and fitting tools
using NeXLMatrixCorrection      # Provides `quant` to convert k-ratios to mass fraction.
using Gadfly                    # Plotting
using DataFrames, Latexify      # Tables

The reference and references functions

Use the reference and references functions to build the filtered references.

# Where to find the files relative to this script file.
path = joinpath(@__DIR__, "K412 spectra")

refs = references(
  [
    # Specify a reference for iron (arg 1), in "Fe std.msa" (arg2) that is pure iron (arg3).
    reference(n"Fe", joinpath(path, "Fe std.msa"), mat"Fe"),
    # specify a conductive surface coating layer using the `coating` named argument
    reference(n"Si", joinpath(path, "SiO2 std.msa"), mat"SiO2", coating = Film(pure(n"C"), 10.0e-7)),
    reference(n"O", joinpath(path, "SiO2 std.msa"), mat"SiO2", coating = Film(pure(n"C"), 10.0e-7)),
    reference(n"Ca", joinpath(path, "CaF2 std.msa"), mat"CaF2", coating = Film(pure(n"C"), 10.0e-7)),
    # Read the composition from the spectrum file's ##D2STDCMP tag
    reference(n"Mg", joinpath(path, "MgO std.msa"), coating = Film(pure(n"C"), 10.0e-7)),
    # Read the conductive coating from the spectrum file's ##CONDCOATING tag
    reference(n"Al", joinpath(path, "Al2O3 std.msa"), mat"Al2O3"),
  ],
  132.0  # Detector resolution at Mn Kα (eV)
)
References[
	BasicEDS[4096 chs, 1.63032 + 9.99856⋅ch eV, 132.0 eV @ Mn K-L3, 1 ch LLD, 
[Be,Sc,Ba,Pu]], 
	k[Fe L3-M5 + 13 others, Fe],
	k[Fe K-L3 + 1 other, Fe],
	k[Fe K-M3 + 3 others, Fe],
	k[Si K-L3 + 3 others, SiO2],
	k[O K-L3 + 1 other, SiO2],
	k[Ca K-L3 + 3 others, CaF2],
	k[Mg K-L3 + 1 other, MgO],
	k[Al K-L3 + 3 others, Al2O3],
]

Load the Unknowns

# Now load all the unknown spectra and assign a carbon coating`
unks = map(0:4) do i 
    s = loadspectrum(joinpath(path, "III-E K412[$i][4].msa"))
    # assign a carbon coating
    s[:Coating] = Film(pure(n"C"), 30.0e-7)
    s
end
5-element Vector{Spectrum{Float64}}:
 Spectrum{Float64}[III-E K412[0][all], 1.63032 + 9.99856⋅ch eV, 4096 ch, 20
.0 keV, K412, 8.08e6 counts]
 Spectrum{Float64}[III-E K412[1][all], 1.63032 + 9.99856⋅ch eV, 4096 ch, 20
.0 keV, K412, 8.08e6 counts]
 Spectrum{Float64}[III-E K412[2][all], 1.63032 + 9.99856⋅ch eV, 4096 ch, 20
.0 keV, K412, 8.08e6 counts]
 Spectrum{Float64}[III-E K412[3][all], 1.63032 + 9.99856⋅ch eV, 4096 ch, 20
.0 keV, K412, 8.09e6 counts]
 Spectrum{Float64}[III-E K412[4][all], 1.63032 + 9.99856⋅ch eV, 4096 ch, 20
.0 keV, K412, 8.08e6 counts]

Table: The spectra

NameBeamEnergyProbeCurrentLiveTimeRealTimeCoatingIntegralMaterial
III-E K412[0][all]2e+041.114235.5286.330.0 nm of Pure C8.08e+06K412
III-E K412[1][all]2e+041.114235.4286.230.0 nm of Pure C8.077e+06K412
III-E K412[2][all]2e+041.112235.5286.330.0 nm of Pure C8.084e+06K412
III-E K412[3][all]2e+041.11235.4286.330.0 nm of Pure C8.087e+06K412
III-E K412[4][all]2e+041.11235.4286.230.0 nm of Pure C8.081e+06K412
Fe std2e+041.1111711529nothing5.445e+07Fe
Fe std2e+041.1111711529nothing5.445e+07Fe
Fe std2e+041.1111711529nothing5.445e+07Fe
SiO2 std2e+041.111173147010.0 nm of Pure C4.665e+07SiO2
SiO2 std2e+041.111173147010.0 nm of Pure C4.665e+07SiO2
CaF2 std2e+041.111176145610.0 nm of Pure C4.406e+07CaF2
MgO std2e+041.1061176149610.0 nm of Pure C4.985e+07MgO
Al2O3 std2e+041.111172149110.0 nm of Pure Carbon4.974e+07Al2O3

Notice that the spectra all have 1) live-time (:LiveTime); 2) probe-current (:ProbeCurrent); 3) take-off angle (:TakeOffAngle); 4) beam energy (:BeamEnergy); and detector (:Detector) properties defined. These properties are necessary for extracting the k-ratios and estimating the composition.

u=unks[1]
u[:LiveTime], u[:ProbeCurrent], u[:TakeOffAngle], u[:BeamEnergy], u[:Coating]
(235.48403, 1.11355, 0.6108652381980153, 20000.0, 30.0 nm of Pure C)

The Unknowns

display(plot(unks..., klms=[n"O",n"Mg",n"Al",n"Si",n"Ca",n"Fe"], xmax=8.0e3))

The Reference Spectra

Plot the reference spectra...

plot(spectra(refs)..., klms=collect(elms(refs)), xmax=8.0e3)

Fit the Pre-Filtered References to the Unknowns

res= [ fit_spectrum(u,refs) for u in unks ]
5-element Vector{FilterFitResult{Float64}}:
 FitResult(III-E K412[0][all])
 FitResult(III-E K412[1][all])
 FitResult(III-E K412[2][all])
 FitResult(III-E K412[3][all])
 FitResult(III-E K412[4][all])
Spectrak[O K-L3 + 1 other, SiO2]k[Fe L3-M5 + 13 others, Fe]k[Mg K-L3 + 1 other, MgO]k[Al K-L3 + 3 others, Al2O3]k[Si K-L3 + 3 others, SiO2]k[Ca K-L3 + 3 others, CaF2]k[Fe K-L3 + 1 other, Fe]k[Fe K-M3 + 3 others, Fe]
III-E K412[0][all]0.65360.041910.14760.066990.35070.19220.066830.06684
III-E K412[1][all]0.65540.041560.14750.066750.34990.19160.067080.06738
III-E K412[2][all]0.6560.041910.14790.067090.35110.19220.066880.06704
III-E K412[3][all]0.66040.041460.14810.067160.35190.19250.066820.0678
III-E K412[4][all]0.65880.040810.14820.067280.35180.19220.066940.06648

Let's take a look at a residual spectrum by plotting one of the FilterFitResult objects.

plot(res[1])

Quantify the k-ratios by Matrix Correction

quant = quantify.(res)
5-element Vector{IterationResult}:
 Converged to III-E K412[0][all][O=0.4805,Mg=0.1176,Al=0.0487,Si=0.2081,Ca=
0.1089,Fe=0.0806] in 9 steps.
 Converged to III-E K412[1][all][O=0.4809,Mg=0.1176,Al=0.0485,Si=0.2077,Ca=
0.1085,Fe=0.0810] in 8 steps.
 Converged to III-E K412[2][all][O=0.4818,Mg=0.1179,Al=0.0487,Si=0.2084,Ca=
0.1089,Fe=0.0807] in 9 steps.
 Converged to III-E K412[3][all][O=0.4844,Mg=0.1180,Al=0.0488,Si=0.2088,Ca=
0.1090,Fe=0.0807] in 8 steps.
 Converged to III-E K412[4][all][O=0.4833,Mg=0.1181,Al=0.0489,Si=0.2088,Ca=
0.1089,Fe=0.0808] in 8 steps.
MaterialOMgAlSiCaFeTotal
III-E K412[0][all]0.48050.11760.048650.20810.10890.080651.044
III-E K412[1][all]0.48090.11760.04850.20770.10850.080951.044
III-E K412[2][all]0.48180.11790.048730.20840.10890.080721.046
III-E K412[3][all]0.48440.1180.048780.20880.1090.080661.05
III-E K412[4][all]0.48330.11810.048870.20880.10890.08081.049

Finally plot the results as mass fractions.

plot(quant, known=unks[1][:Composition])

Plot the difference from the SRM value.

plot(quant, known=unks[1][:Composition], delta=true)

Plot the difference from the mean value for each element.

plot(quant, delta=true)