In [1]:
from spectrocrunch.materials import element
element1 = element.Element("Ca")
print(element1)
as compounds
In [2]:
from spectrocrunch.materials import compoundfromformula
from spectrocrunch.materials import compoundfromname
from spectrocrunch.materials import compoundfromlist
from spectrocrunch.materials import types
compound1 = compoundfromformula.CompoundFromFormula("PbSO4",density=6.29)
compound2 = compoundfromformula.CompoundFromFormula("CaSO4",density=2.32)
compound3 = compoundfromname.compoundfromname("linseed oil")
compound4 = compoundfromlist.CompoundFromList(["Ca","C","O"],[1,1,3],\
types.fraction.mole,2.71,name="calcite")
print(compound1,compound2,compound3,compound4)
and as mixtures of compounds
In [3]:
from spectrocrunch.materials import mixture
mixture1 = mixture.Mixture([compound1,compound2],[0.5,0.5],\
types.fraction.mass,name="My mixture")
print(mixture1)
These materials can be used in a particular geometry (currently only flat multi-layered samples)
In [4]:
from spectrocrunch.materials import multilayer
from spectrocrunch.detectors import xrf as xrfdetectors
from spectrocrunch.geometries import xrf as xrfgeometries
from spectrocrunch.sources import xray as xraysources
source = xraysources.factory("synchrotron")
detector = xrfdetectors.factory("leia")
geometry = xrfgeometries.factory("sxm120",detectorposition=-15.,detector=detector,source=source)
sample = multilayer.Multilayer(material=[element1,compound1,mixture1],\
thickness=[1e-4,1e-4,1e-4],geometry = geometry)
print(sample)
print("")
print(geometry)
The main usage of the material classes is to calculate cross sections. Current back-ends are xraylib (elemental database, neglecting environment) and FDMNES (calculation with environment).
In [5]:
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
energy = np.linspace(2,60,100)
material = mixture1
mu = material.mass_att_coeff(energy)
plt.plot(energy,mu,label='Total')
mu = material.mass_abs_coeff(energy)
plt.plot(energy,mu,label='Absorption')
mu = material.rayleigh_cross_section(energy)
plt.plot(energy,mu,label='Coherent')
mu = material.compton_cross_section(energy)
plt.plot(energy,mu,label='Incoherent')
plt.title(str(material))
plt.xlabel('Energy (keV)')
plt.ylabel('Cross-section (cm$^2$/g)')
plt.legend(loc='best')
plt.gca().set_yscale('log', basey=10)
plt.tight_layout()
plt.show()
In [6]:
material = mixture1
material.unmarkabsorber()
print("Partial cross-section: no selection")
print('\n'.join(list(material.markinfo())))
energy = np.linspace(3,5,100)
mu = material.mass_abs_coeff(energy)
plt.plot(energy,mu,label='Absorption')
material.unmarkabsorber()
material.markabsorber("Ca",shells=['K'])
print("\nPartial cross-section: selected Ca-K")
print('\n'.join(list(material.markinfo())))
mu = material.partial_mass_abs_coeff(energy)
plt.plot(energy,mu,label='Ca-K')
mu = material.fluorescence_cross_section(energy)
plt.plot(energy,mu,label='Fluo (Ca-K)')
material.unmarkabsorber()
material.markabsorber("Ca",shells=['K'],fluolines=['KA'])
print("\nPartial cross-section: selected Ca-Ka")
print('\n'.join(list(material.markinfo())))
mu = material.fluorescence_cross_section(energy)
plt.plot(energy,mu,label='Fluo (Ca-Ka)')
plt.title(str(material))
plt.xlabel('Energy (keV)')
plt.ylabel('Cross-section (cm$^2$/g)')
plt.legend(loc='best')
plt.gca().set_yscale('log', basey=10)
plt.tight_layout()
plt.show()
material.unmarkabsorber()
In [7]:
azimuth = np.linspace(0,360,100)
polar = np.linspace(0,180,50)
extent = [azimuth[0],azimuth[-1],polar[0],polar[-1]]
azimuth,polar = np.meshgrid(np.radians(azimuth),np.radians(polar))
energy = 5
material = mixture1
print(material)
def plotcs(cs):
plt.imshow(cs,origin="lower",extent=extent)
plt.axhline(y=90)
for x in [90,180,270]:
plt.axvline(x=x)
plt.xlabel("Azimuth (deg)")
plt.ylabel("Polar (deg)")
plt.colorbar(label="cm$^2$/g/sr")
cs = material.diff_rayleigh_cross_section(energy,source=source)
plotcs(cs(azimuth,polar))
plt.title("Elastic")
plt.show()
cs = material.diff_compton_cross_section(energy,source=source)
plotcs(cs(azimuth,polar))
plt.title("Inelastic")
plt.show()
material.markabsorber(energybounds=[1,energy])
cs = material.diff_fluorescence_cross_section(energy,source=source)
cs = np.full_like(azimuth,sum(cs.values()))
plotcs(np.full_like(azimuth,cs))
plt.title("Fluorescence")
plt.show()
X-ray spectra are calculated from the cross-sections (including self-absorption). Alternatively the fisx library can be used as a back-end (no scattering; including self-absorption and secondary fluorescence).
In [10]:
fig,axs = plt.subplots(2,2,figsize=(10,10))
energy = [5,5.1]
weights = [2,1]
emin = 2
emax = 5.5
azimuth = 0
polar = np.pi/2
plt.sca(axs[0][0])
spectrum = element1.xrayspectrum(energy,weights=weights,emax=emax,emin=emin,\
source=source,azimuth=azimuth,polar=polar)
spectrum.plot()
plt.sca(axs[0][1])
spectrum = compound1.xrayspectrum(energy,weights=weights,emax=emax,emin=emin,\
source=source,azimuth=azimuth,polar=polar)
spectrum.plot()
plt.sca(axs[1][0])
spectrum = mixture1.xrayspectrum(energy,weights=weights,emax=emax,emin=emin,\
source=source,azimuth=azimuth,polar=polar)
spectrum.plot()
plt.sca(axs[1][1])
# sample already connected to a geometry
spectrum = sample.xrayspectrum(energy,weights=weights,emax=emax,emin=emin)
spectrum.plot()
plt.tight_layout()
plt.show()