.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_examples/plot_01_basic_usage.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_examples_plot_01_basic_usage.py: Basic usage of pyElli ===================== Basic usage of building a model and fitting it to measurement data of SiO2 on Si. .. GENERATED FROM PYTHON SOURCE LINES 10-15 .. code-block:: Python import elli from elli.fitting import ParamsHist, fit .. GENERATED FROM PYTHON SOURCE LINES 17-28 Reading data ------------------------ We load the data from the generated `NeXus file `_ and select the angle we want to analyse. You may set the ANGLE constant to 50 or 60 to select other angles of incidence from the example file. Additionally, we're cutting the wavelength axis to be in between 210 nm and 800 nm. This is because we're using literature values for Si, which are only defined in this wavelength range. .. GENERATED FROM PYTHON SOURCE LINES 28-31 .. code-block:: Python ANGLE = 70 psi_delta = elli.read_nexus_psi_delta("SiO2onSi.ellips.nxs").loc[ANGLE].loc[210:800] .. GENERATED FROM PYTHON SOURCE LINES 32-44 Setting parameters ------------------------ As an example we analyse an oxidation layer of SiO2 on Si. Prior to defining our model, we have to set the parameters we want to use. We're going to use a :ref:`Cauchy model ` for SiO2 and load the Si values from `literature values `_. The parameter names can be chosen freely, but you have to use the exact same name in the later model definition. The package uses lmfit as fitting tool and you may refer to their `documentation `_ for details on parameter definition. .. GENERATED FROM PYTHON SOURCE LINES 44-54 .. code-block:: Python 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=20, min=0, max=40000, vary=True) .. GENERATED FROM PYTHON SOURCE LINES 55-65 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 `__. .. GENERATED FROM PYTHON SOURCE LINES 65-69 .. code-block:: Python rii_db = elli.db.RII() Si = rii_db.get_mat("Si", "Aspnes") .. GENERATED FROM PYTHON SOURCE LINES 70-114 Building the model ------------------------ For simple parameter estimation, the fit decorator (**@fit**) in conjunction with the model definition is used. The fitting decorator takes a pandas dataframe containing the psi/delta measurement data (**psi_delta**) and the model parameters (**params**) as an input. It then passes the wavelength from measurement dataframe (**lbda**) and the parameters to the actual model function. Inside the model function the optical model is built, i.e. the Si literature values are loaded and the fitting parameters are filled into the Cauchy dispersion. For details on how to insert data into the Cauchy model or other optical dispersion models, you may refer to the documentation of pyElli. Please keep in mind that the parameters you use here have to be defined in the parameter object **param**. From the dispersion model isotropic materials are generated (could also be an anisotropic material, refer to the docs for an overview). This is done by calling the :code:`elli.IsotropicMaterial(...)` function with a dispersion model as a parameter or simply calling :code:`.get_mat()` on a dispersion model. These two approaches are equivalent. From these materials the layer is build, which only consists of the SiO2 layer in this example. The final structure consists of an incoming half-space, the layers and an outgoing half space. Specifically, typically the light is coming from air and finally gets absorbed by the bulk material, in our example this is Si, i.e. we call :code:`elli.Structure(elli.AIR, Layer, Si)`. To provide simulated data, we have to evaluate the structure by calling the :code:`evaluate(...)` function, which takes the experimental wavelength array **lbda**, **ANGLE** under which the experiment was performed and the solver to be used to solve the transfer-matrix problem. Here, we use a simple 2x2 matrix approach, which splits the interaction in s and p-parts and therefore cannot account for anisotropy. There exist 4x4 matrix solvers as well. You may refer to the :ref:`solver documentation ` for further details. Executing the cell below in a jupyter notebook displays a comparison of the simulated Ψ / Δ values at the current parameter values with their measured counterparts. Additionally, input fields for each model parameter are shown. You may change the parameters and the calculated data will change accordingly. For clarification the modeled data is shown with `_calc` postfix in the legend. .. GENERATED FROM PYTHON SOURCE LINES 114-142 .. code-block:: Python @fit(psi_delta, params) def model(lbda, params): # Generate the cauchy model from the current lmfit parameters SiO2 = elli.Cauchy( params["SiO2_n0"], params["SiO2_n1"], params["SiO2_n2"], params["SiO2_k0"], params["SiO2_k1"], params["SiO2_k2"], ).get_mat() # get_mat() generates an IsotropicMaterial from the dispersion relation # Construct the layers you expect in your sample # Here, it only consists of one layer SiO2 in between air and Si. # We build the structure coming from air, through the layers, # represented as an array, and having Si as bulk material. structure = elli.Structure( elli.AIR, # Input medium [elli.Layer(SiO2, params["SiO2_d"])], # Overlayer structure Si, ) # Output medium / Substrate # The model should return the evaluation of the structure at the experimental wavelengths lbda, # the experimental angle ANGLE and it should define a solver to calculate the transfer matrix. return structure.evaluate(lbda, ANGLE, solver=elli.Solver2x2) .. GENERATED FROM PYTHON SOURCE LINES 143-150 Fit and plot fit results ------------------------ The fit of the data can be executed by calling the fit() function on the model function, which automatically gets attached by the @fit decorator in the cell above. The following cell basically executes the fit and plots a comparison between the measurement and fitted data. .. GENERATED FROM PYTHON SOURCE LINES 150-153 .. code-block:: Python fit_stats = model.fit() model.plot() .. rst-class:: sphx-glr-script-out .. code-block:: none FigureWidget({ 'data': [{'hovertemplate': 'variable=Ψ
Wavelength=%{x}
value=%{y}', 'legendgroup': 'Ψ', 'line': {'color': '#636efa', 'dash': 'solid'}, 'marker': {'symbol': 'circle'}, 'mode': 'lines', 'name': 'Ψ', 'showlegend': True, 'type': 'scattergl', 'uid': 'e4001476-a7e8-4d4d-a579-adf38dc39191', 'x': array([210., 211., 212., ..., 798., 799., 800.], shape=(1182,)), 'xaxis': 'x', 'y': array([36.548481, 36.480022, 36.433453, ..., nan, nan, nan], shape=(1182,)), 'yaxis': 'y'}, {'hovertemplate': 'variable=Δ
Wavelength=%{x}
value=%{y}', 'legendgroup': 'Δ', 'line': {'color': '#EF553B', 'dash': 'solid'}, 'marker': {'symbol': 'circle'}, 'mode': 'lines', 'name': 'Δ', 'showlegend': True, 'type': 'scattergl', 'uid': 'd847ce2b-2397-43a2-b502-9772e5161a24', 'x': array([210., 211., 212., ..., 798., 799., 800.], shape=(1182,)), 'xaxis': 'x', 'y': array([97.499702, 97.92762 , 98.323624, ..., nan, nan, nan], shape=(1182,)), 'yaxis': 'y'}, {'hovertemplate': 'variable=Ψ_fit
Wavelength=%{x}
value=%{y}', 'legendgroup': 'Ψ_fit', 'line': {'color': '#00cc96', 'dash': 'solid'}, 'marker': {'symbol': 'circle'}, 'mode': 'lines', 'name': 'Ψ_fit', 'showlegend': True, 'type': 'scattergl', 'uid': '12378046-5523-43dc-aa21-119f9735e67b', 'x': array([210., 211., 212., ..., 798., 799., 800.], shape=(1182,)), 'xaxis': 'x', 'y': array([ nan, nan, nan, ..., 9.18875929, 9.1824316 , 9.17610219], shape=(1182,)), 'yaxis': 'y'}, {'hovertemplate': 'variable=Δ_fit
Wavelength=%{x}
value=%{y}', 'legendgroup': 'Δ_fit', 'line': {'color': '#ab63fa', 'dash': 'solid'}, 'marker': {'symbol': 'circle'}, 'mode': 'lines', 'name': 'Δ_fit', 'showlegend': True, 'type': 'scattergl', 'uid': '78585ed3-26e1-45c9-a7d8-9af188213af0', 'x': array([210., 211., 212., ..., 798., 799., 800.], shape=(1182,)), 'xaxis': 'x', 'y': array([ nan, nan, nan, ..., 174.48896139, 174.49555625, 174.50214175], shape=(1182,)), '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'}}} }) .. GENERATED FROM PYTHON SOURCE LINES 154-167 Extracting the optical properties from the fit ---------------------------------------------- Since we want to extract the dispersion relation of a layer in our measured stack, we can use our fitted parameters. The fit parameters are contained in the fits output :code:`params` attribute, i.e. :code:`fit_stats.params` for our example. We can use it to call our dispersion relation we used in our model (here it is a Cauchy dispersion relation) and fill in our fitted value. By calling :code:`get_dielectric_df()` we can get the dielectric function of the material, which is plotted here as an example. :code:`get_dielectric_df` uses a default wavelength range which can also be changed by inputting a wavelength array as a parameter. .. GENERATED FROM PYTHON SOURCE LINES 167-178 .. code-block:: Python fitted_model = elli.Cauchy( fit_stats.params["SiO2_n0"], fit_stats.params["SiO2_n1"], fit_stats.params["SiO2_n2"], fit_stats.params["SiO2_k0"], fit_stats.params["SiO2_k1"], fit_stats.params["SiO2_k2"], ) fitted_model.get_dielectric_df().plot(backend="plotly") .. raw:: html


.. GENERATED FROM PYTHON SOURCE LINES 179-181 We can also call :code:`get_refractive_index_df()` to get the refractive index of the material as dataframe. .. GENERATED FROM PYTHON SOURCE LINES 181-183 .. code-block:: Python fitted_model.get_refractive_index_df().plot(backend="plotly") .. raw:: html


.. GENERATED FROM PYTHON SOURCE LINES 184-186 If you want to write your data to a file you simply call pandas :code:`to_csv(...)` function to write a csv file, i.e. for the dielectric function this writes as .. GENERATED FROM PYTHON SOURCE LINES 186-188 .. code-block:: Python fitted_model.get_dielectric_df().to_csv("SiO2_diel_func.csv") .. GENERATED FROM PYTHON SOURCE LINES 189-190 You may also access a single value of your optical model .. GENERATED FROM PYTHON SOURCE LINES 190-192 .. code-block:: Python fit_stats.params["SiO2_n0"].value .. rst-class:: sphx-glr-script-out .. code-block:: none 1.452 .. GENERATED FROM PYTHON SOURCE LINES 193-194 Our simply print the fitted values in a list together with their fitting errors .. GENERATED FROM PYTHON SOURCE LINES 194-196 .. code-block:: Python fit_stats.params .. raw:: html


.. GENERATED FROM PYTHON SOURCE LINES 197-203 Show fit statistics -------------------- Now, we may also print out the fit statictics from the model fit in the cell above. The fit statistics are simple `lmfit fit statistics `_, too. Typically, one uses chi square values as a figure of merit for the fit quality. It is stored in the chisqr attribute of the fit_stats variable we defined above. .. GENERATED FROM PYTHON SOURCE LINES 203-205 .. code-block:: Python fit_stats.chisqr .. rst-class:: sphx-glr-script-out .. code-block:: none np.float64(0.016923374970708012) .. GENERATED FROM PYTHON SOURCE LINES 206-207 We can print the full fit statistics, too. .. GENERATED FROM PYTHON SOURCE LINES 207-209 .. code-block:: Python fit_stats .. raw:: html

Fit Result



.. GENERATED FROM PYTHON SOURCE LINES 210-214 References ---------- `Here `_ you can find the latest jupyter notebook and data files of this example. .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 1.247 seconds) .. _sphx_glr_download_auto_examples_plot_01_basic_usage.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_01_basic_usage.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_01_basic_usage.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_01_basic_usage.zip `