RaDMaX online

A web application for the determination of strain and disorder profiles in irradiated materials from XRD data

View the Project on GitHub

RaDMaX online is a web-based program that allows to retrieve strain and disorder depth-profiles in ion-irradiated materials from the simulation of X-ray diffraction data recorded in symmetric geometry.

If you use this software in an academic work, please cite:

A. Boulle & V. Mergnac, “RaDMaX online: a web-based program for the determination of strain and damage profiles in irradiated crystals using X-ray diffraction”, J. Appl. Cryst. 53 (2020).

https://doi.org/10.1107/S1600576720002514

RaDMaX online is written in Python, using the NumPy and SciPy libraries. The graphical user interface is written within a Jupyter notebook using ipywidgets for interactive widgets and bqplot for interactive plots. The html/css/javascript rendering is achieved with voilà. Some crystallographic calculations are performed using xrayutilities. The crystal structures (“crystallographic information file”) are obtained from the Crystallography Open Database.

Data privacy: no data is stored on the server. All data files uploaded to RaDMaX online and all calculations performed with RaDMaX online are stored in RAM and are definitely lost when uploading a new data set or when closing the program. Session saving capabilities are available if you run the Jupyter notebook in offline mode (see below).

Help and support: new crystal structures can be added upon request. Bug reports and improvement suggestions are welcome. Contact info: alexandre.boulle@unilim.fr

Program usage

RaDMaX online is a web application hosted at Universtiy of Limoges (the page may take a few seconds to load):

unilim

If for any reason the previous link doesn’t work properly, a Binder instance of RaDMaX online can be launched here:

Binder

At first launch Binder converts the github repository into a Docker image which might take some time (up to a few minutes). See the Binder website for further details.

Video tutorial

Offline mode

The Jupyter notebook can also be executed locally. Clone or download this repository and install all required dependencies. Using pip :

pip install numpy scipy jupyter ipywidgets bqplot voila xrayutilities

If you are using anaconda, the scipy stack and jupyter are already installed:

conda install -c conda-forge ipywidgets bqplot voila

then

pip install xrayutilities

When working in local mode change the first line of RaDMaX.ipynb to local = True to benefit from automatic session saving capabilities.

Scientific background

In RaDMaX online the diffracted X-ray intensity is computed within the framework of the dynamical theory of diffraction from distorted crystals as first theorized by S. Takagi and D. Taupin which is the state of the art approach for the analysis of irradiated crystals using XRD. More specifically, RaDMaX online implements the 1D solution to the Takagi - Taupin equations as derived by Bartels, Hornstra and Lobeek. Within this approach, the irradiated region is divided in a number of sub-layers each having distinct, but fixed, compostion/strain/disorder. The scattering from the ensemble is computed iteratively, starting from the film-substrate interface, up to the surface. The X-ray amplitude ratio at the top of a layer is related to the amplitude ratio at the bottom, , by :

with

The amplitude ratio is given by (in order not to overly complexify the equations, the index n is ommited below):

is dynamical theory’s deviation parameter:

and is related to the sub-layer thickness:

where , and . is the polarization of the incident beam, and are the incident and diffracted beam amplitudes, and are the direction cosines of the incident and diffracted beam with respect to the surface normal. In the above equations, is the sub-layer thickness, and are the structure factor of the and reflections and is the Bragg angle within the given layer. This angle is related to the strain component via:

where is the lattice spacing of the bulk (unstrained) material. The structure factor is sensitive to the atomic disorder via:

where is he structure factor of the bulk material and is the Debye-Waller factor which ranges between 0 and 1. The is related to random atomic displacements via:

The equations above are used to generated the diffracted intensity for all values provided by the user. The fitting procedure consist in finding the best and values so that the calculated curve matches the experimental data provided by the user. This can be done either manually (via the interactive strain/DW plots), or automatically using a least-squares fitting procedure.

In order to limit the number of adjustable parameters and avoid numerical instabilities, the values of and are constrained to exhibit a cubic spline shape. This is performed using cubic B-spline functions:

where is the number of B-splines used to describe the strain (‘S’) and disorder (‘D’) profiles (typical values are in the 5-15 range), are the weights to be determined in the fitting procedure and is the third-degree basis function, and is the depth coordinate.

Furter details regarding B-spline functions and the theoretical background can be found in the following references: Boulle & Debelle, 2010, Souilah, Boulle & Debelle, 2016 and Boulle & Mergnac, 2020

The python code implementing these equations for the case of a single crystal is given below:

def f_Refl_Default(th, param, cst):
    offset = cst["offset"]*np.pi/360
    G = cst["G"]
    thB_S = cst["thB_S"]
    wl = cst["wl"]
    t = cst["t"]
    N = cst["N"]
    resol = cst["resol"]
    b_S = cst["b_S"]
    phi = cst["phi"]
    t_l = cst["t_l"]
    z = cst["z"]
    FH = cst["FH"]
    FmH = cst["FmH"]
    F0 = cst["F0"]
    Nspline = cst["sdw_basis"]
    model = cst["sdw_model"]
    bkg = cst["bkg"]

    th = th + offset
    strain = f_strain(z, param[:Nspline:], t, model)
    DW = f_DW(z, param[Nspline:2*Nspline:], t, model)
    thB = thB_S - strain * np.tan(thB_S)

    eta = (-b_S*(th-thB_S)*np.sin(2*thB_S) - 0.5*G*F0*(1-b_S))\
    /(b_S)**0.5)*G*(FH*FmH)**0.5 )
    res = (eta - np.sign(eta.real)*((eta*eta - 1)**0.5))

    n = 1
    while (n<=N):
        g0 = np.sin(thB[n] - phi)
        gH = -np.sin(thB[n] + phi)
        b = g0 / gH
        T = np.pi * G * ((FH*FmH)**0.5) * t_l * DW[n]/ (wl\
        *(abs(g0*gH)**0.5) )
        eta = (-b*(th-thB[n])*np.sin(2*thB_S) - 0.5*G*F0*(1-b))\
        /((abs(b)**0.5)*G*DW[n]*(FH*FmH)**0.5)
        sqrt_eta2 = (eta*eta-1)**0.5

        S1 = (res - eta + sqrt_eta2)*np.exp(-1j*T*sqrt_eta2)
        S2 = (res - eta - sqrt_eta2)*np.exp(1j*T*sqrt_eta2)

        res = (eta + sqrt_eta2*((S1+S2)/(S1-S2)))
        n += 1

    ical = np.convolve(abs(res)**2, resol, mode='same')
    return (ical/ical.max())+bkg

License

This program is licensed under the CeCILL license. See LICENSE file.