Multilayer fit

Fits a multilayer model to an ALD grown TiO2 sample on SiO2 / Si.

import elli
from elli.fitting import ParamsHist, fit

Load data

Load data collected with Sentech Ellipsometer and cut the spectral range (to use Si Aspnes file)

The sample is an ALD grown TiO2 sample (with 400 cycles) on commercially available SiO2 / Si substrate.

tss = elli.read_spectraray_psi_delta("TiO2_400cycles.txt").loc[70.06].loc[400:800]

Set start parameters

Here we set the start parameters for the TiO2 and SiO2 layer. We set the SiO2 layer parameters to a fixed value from another fit of the substrate. See the Basic usage example for details on how to perform such a fit. In general it is a good idea to fit your data layer-wise if possible to yield a better fit quality.

params = ParamsHist()
params.add("SiO2_n0", value=1.452, min=-100, max=100, vary=False)
params.add("SiO2_n1", value=36.0, min=-40000, max=40000, vary=False)
params.add("SiO2_n2", value=0, min=-40000, max=40000, vary=False)
params.add("SiO2_k0", value=0, min=-100, max=100, vary=False)
params.add("SiO2_k1", value=0, min=-40000, max=40000, vary=False)
params.add("SiO2_k2", value=0, min=-40000, max=40000, vary=False)
params.add("SiO2_d", value=276.36, min=0, max=40000, vary=False)

params.add("TiO2_n0", value=2.236, min=-100, max=100, vary=True)
params.add("TiO2_n1", value=451, min=-40000, max=40000, vary=True)
params.add("TiO2_n2", value=251, min=-40000, max=40000, vary=True)
params.add("TiO2_k0", value=0, min=-100, max=100, vary=False)
params.add("TiO2_k1", value=0, min=-40000, max=40000, vary=False)
params.add("TiO2_k2", value=0, min=-40000, max=40000, vary=False)

params.add("TiO2_d", value=20, min=0, max=40000, vary=True)

Load silicon dispersion from the refractiveindexinfo database

You can load any material from the index refractiveindex.info, which is embedded into the software (so you may use it offline, too). Here, we are interested in the literature values for the silicon substrate. First we need to load the database with rii_db = elli.db.RII() and then we can query it with rii_db.get_mat("Si", "Aspnes") to load this entry.

rii_db = elli.db.RII()
Si = rii_db.get_mat("Si", "Aspnes")

Building the model

Here the model is build and the experimental structure is returned. For details on this process please refer to the Basic usage example. When executed in an jupyter notebook this displays an interactive graph with which you can select the start parameters before fitting the data.

@fit(tss, params)
def model(lbda, params):
    SiO2 = elli.Cauchy(
        params["SiO2_n0"],
        params["SiO2_n1"],
        params["SiO2_n2"],
        params["SiO2_k0"],
        params["SiO2_k1"],
        params["SiO2_k2"],
    ).get_mat()
    TiO2 = elli.Cauchy(
        params["TiO2_n0"],
        params["TiO2_n1"],
        params["TiO2_n2"],
        params["TiO2_k0"],
        params["TiO2_k1"],
        params["TiO2_k2"],
    ).get_mat()

    Layer = [elli.Layer(TiO2, params["TiO2_d"]), elli.Layer(SiO2, params["SiO2_d"])]

    return elli.Structure(elli.AIR, Layer, Si).evaluate(lbda, 70, solver=elli.Solver2x2)
    # Alternative: Use 4x4 Solver with scipy propagator
    # return elli.Structure(elli.AIR, Layer, Si).evaluate(lbda, 70, solver=elli.Solver4x4, propagator=elli.PropagatorExpm())

Plot & Fit model

We plot the model to see the deviation with the initial parameters.

model.plot()
FigureWidget({
    'data': [{'hovertemplate': 'variable=Ψ<br>Wavelength=%{x}<br>value=%{y}<extra></extra>',
              'legendgroup': 'Ψ',
              'line': {'color': '#636efa', 'dash': 'solid'},
              'marker': {'symbol': 'circle'},
              'mode': 'lines',
              'name': 'Ψ',
              'showlegend': True,
              'type': 'scattergl',
              'uid': 'fb5bf86c-aabf-402b-a95a-b0e940e52235',
              'x': array([400.07646, 400.51975, 400.96301, ..., 798.88197, 799.30046, 799.71891],
                         shape=(1852,)),
              'xaxis': 'x',
              'y': array([32.75947, 32.84076, 32.84675, ...,      nan,      nan,      nan],
                         shape=(1852,)),
              'yaxis': 'y'},
             {'hovertemplate': 'variable=Δ<br>Wavelength=%{x}<br>value=%{y}<extra></extra>',
              'legendgroup': 'Δ',
              'line': {'color': '#EF553B', 'dash': 'solid'},
              'marker': {'symbol': 'circle'},
              'mode': 'lines',
              'name': 'Δ',
              'showlegend': True,
              'type': 'scattergl',
              'uid': '9eba3673-b7e8-4d01-9af7-7432636bbb67',
              'x': array([400.07646, 400.51975, 400.96301, ..., 798.88197, 799.30046, 799.71891],
                         shape=(1852,)),
              'xaxis': 'x',
              'y': array([-132.57268, -132.11725, -131.5141 , ...,        nan,        nan,
                                 nan], shape=(1852,)),
              'yaxis': 'y'},
             {'hovertemplate': 'variable=Ψ_fit<br>Wavelength=%{x}<br>value=%{y}<extra></extra>',
              'legendgroup': 'Ψ_fit',
              'line': {'color': '#00cc96', 'dash': 'solid'},
              'marker': {'symbol': 'circle'},
              'mode': 'lines',
              'name': 'Ψ_fit',
              'showlegend': True,
              'type': 'scattergl',
              'uid': '663a7d35-a879-49f7-8dc1-d9ccd4a05b3d',
              'x': array([400.07646, 400.51975, 400.96301, ..., 798.88197, 799.30046, 799.71891],
                         shape=(1852,)),
              'xaxis': 'x',
              'y': array([        nan,         nan,         nan, ..., 21.13502205, 21.16231399,
                          21.18955407], shape=(1852,)),
              'yaxis': 'y'},
             {'hovertemplate': 'variable=Δ_fit<br>Wavelength=%{x}<br>value=%{y}<extra></extra>',
              'legendgroup': 'Δ_fit',
              'line': {'color': '#ab63fa', 'dash': 'solid'},
              'marker': {'symbol': 'circle'},
              'mode': 'lines',
              'name': 'Δ_fit',
              'showlegend': True,
              'type': 'scattergl',
              'uid': 'f29299e0-376f-499f-90fc-09ce40160e05',
              'x': array([400.07646, 400.51975, 400.96301, ..., 798.88197, 799.30046, 799.71891],
                         shape=(1852,)),
              'xaxis': 'x',
              'y': array([          nan,           nan,           nan, ..., -111.09599625,
                          -110.98086027, -110.86609469], shape=(1852,)),
              'yaxis': 'y'}],
    'layout': {'legend': {'title': {'text': 'variable'}, 'tracegroupgap': 0},
               'margin': {'t': 60},
               'template': '...',
               'xaxis': {'anchor': 'y', 'domain': [0.0, 1.0], 'title': {'text': 'Wavelength'}},
               'yaxis': {'anchor': 'x', 'domain': [0.0, 1.0], 'title': {'text': 'value'}}}
})

Now lets perform the fit and plot the comparison of calculation and experimental data afterwards.

fit_stats = model.fit()
model.plot()
FigureWidget({
    'data': [{'hovertemplate': 'variable=Ψ<br>Wavelength=%{x}<br>value=%{y}<extra></extra>',
              'legendgroup': 'Ψ',
              'line': {'color': '#636efa', 'dash': 'solid'},
              'marker': {'symbol': 'circle'},
              'mode': 'lines',
              'name': 'Ψ',
              'showlegend': True,
              'type': 'scattergl',
              'uid': '47ae734b-cb6f-447a-8539-12f1de4f01f0',
              'x': array([400.07646, 400.51975, 400.96301, ..., 798.88197, 799.30046, 799.71891],
                         shape=(1852,)),
              'xaxis': 'x',
              'y': array([32.75947, 32.84076, 32.84675, ...,      nan,      nan,      nan],
                         shape=(1852,)),
              'yaxis': 'y'},
             {'hovertemplate': 'variable=Δ<br>Wavelength=%{x}<br>value=%{y}<extra></extra>',
              'legendgroup': 'Δ',
              'line': {'color': '#EF553B', 'dash': 'solid'},
              'marker': {'symbol': 'circle'},
              'mode': 'lines',
              'name': 'Δ',
              'showlegend': True,
              'type': 'scattergl',
              'uid': '8c339219-8be3-4a41-b89f-aa50858a51ae',
              'x': array([400.07646, 400.51975, 400.96301, ..., 798.88197, 799.30046, 799.71891],
                         shape=(1852,)),
              'xaxis': 'x',
              'y': array([-132.57268, -132.11725, -131.5141 , ...,        nan,        nan,
                                 nan], shape=(1852,)),
              'yaxis': 'y'},
             {'hovertemplate': 'variable=Ψ_fit<br>Wavelength=%{x}<br>value=%{y}<extra></extra>',
              'legendgroup': 'Ψ_fit',
              'line': {'color': '#00cc96', 'dash': 'solid'},
              'marker': {'symbol': 'circle'},
              'mode': 'lines',
              'name': 'Ψ_fit',
              'showlegend': True,
              'type': 'scattergl',
              'uid': 'c46707d8-305a-4a2f-bc5a-908b1d9b752d',
              'x': array([400.07646, 400.51975, 400.96301, ..., 798.88197, 799.30046, 799.71891],
                         shape=(1852,)),
              'xaxis': 'x',
              'y': array([        nan,         nan,         nan, ..., 20.20488814, 20.23141868,
                          20.25790068], shape=(1852,)),
              'yaxis': 'y'},
             {'hovertemplate': 'variable=Δ_fit<br>Wavelength=%{x}<br>value=%{y}<extra></extra>',
              'legendgroup': 'Δ_fit',
              'line': {'color': '#ab63fa', 'dash': 'solid'},
              'marker': {'symbol': 'circle'},
              'mode': 'lines',
              'name': 'Δ_fit',
              'showlegend': True,
              'type': 'scattergl',
              'uid': 'f334f609-ee0c-4b63-8093-7ce816309490',
              'x': array([400.07646, 400.51975, 400.96301, ..., 798.88197, 799.30046, 799.71891],
                         shape=(1852,)),
              'xaxis': 'x',
              'y': array([          nan,           nan,           nan, ..., -118.64650333,
                          -118.5165033 , -118.38691231], shape=(1852,)),
              'yaxis': 'y'}],
    'layout': {'legend': {'title': {'text': 'variable'}, 'tracegroupgap': 0},
               'margin': {'t': 60},
               'template': '...',
               'xaxis': {'anchor': 'y', 'domain': [0.0, 1.0], 'title': {'text': 'Wavelength'}},
               'yaxis': {'anchor': 'x', 'domain': [0.0, 1.0], 'title': {'text': 'value'}}}
})

We can also have a look at the fit statistics.

fit_stats

Fit Result



References

Here you can find the latest jupyter notebook and data files of this example.

Total running time of the script: (0 minutes 1.161 seconds)