### Build and Upload Distribution Source: https://github.com/refnx/refellips/blob/main/release_notes.txt Install the build package, build the distribution, and upload it to PyPI using twine. ```bash python -m pip install build python -m build . twine upload dist/* ``` -------------------------------- ### Prepare for Release Source: https://github.com/refnx/refellips/blob/main/release_notes.txt Fetch latest changes, checkout master, rebase, and clean the working directory before starting a release. ```bash git fetch refellips git checkout master git rebase refellips/master git clean -xdf ``` -------------------------------- ### Complete Spectroscopic Ellipsometry Fitting Workflow Source: https://context7.com/refnx/refellips/llms.txt A comprehensive example covering data loading, material definition, model construction, fitting, and result visualization. ```python import numpy as np import matplotlib.pyplot as plt from refnx.analysis import CurveFitter from refellips import ( DataSE, ObjectiveSE, ReflectModelSE, RI, Cauchy, load_material ) from refellips.dataSE import open_EP4file # 1. Load experimental data data = DataSE(data="sample_data.txt") # Or for Accurion EP4 format: # data = open_EP4file("sample.dat", reflect_delta=False) # 2. Define materials air = load_material("air") silicon = load_material("silicon") silica = load_material("silica") # Polymer with Cauchy dispersion polymer = Cauchy(A=1.47, B=0.00495, C=0, name="PNIPAM") # 3. Build layer structure # Create layers with initial thickness estimates polymer_layer = polymer(thick=150, rough=5) polymer_layer.name = "polymer" polymer_layer.thick.setp(vary=True, bounds=(50, 500)) oxide_layer = silica(thick=20, rough=3) oxide_layer.name = "native_oxide" oxide_layer.thick.setp(vary=True, bounds=(5, 50)) # Build structure: fronting | layers | backing structure = air(0, 0) | polymer_layer | oxide_layer | silicon(0, 0) # 4. Create model and objective model = ReflectModelSE(structure, delta_offset=0) model.delta_offset.setp(vary=False, bounds=(-10, 10)) objective = ObjectiveSE(model, data, name="polymer_on_silicon") # 5. Initial comparison fig, ax = objective.plot() plt.title("Before fitting") plt.show() # 6. Perform fitting fitter = CurveFitter(objective) # Global optimization first fitter.fit(method="differential_evolution") # Refine with local optimization fitter.fit(method="least_squares") # 7. Print results print("\n=== Fit Results ===") print(f"Chi-squared: {objective.chisqr():.4f}") print(f"\nFitted parameters:") for param in objective.varying_parameters(): print(f" {param.name}: {param.value:.3f} +/- {param.stderr:.3f}") # 8. Plot final fit fig, ax = objective.plot() plt.title("After fitting") plt.show() # 9. Plot structure profile fig2, ax2 = structure.plot() plt.title("Refractive Index Profile") plt.show() # 10. Save results import pickle with open("fit_results.pkl", "wb") as f: pickle.dump(objective, f) # Export fitted data to CSV wavelength_aoi = np.column_stack([data.wavelength, data.aoi]) psi_fit, delta_fit = model(wavelength_aoi) results = np.column_stack([ data.wavelength, data.aoi, data.psi, psi_fit, data.delta, delta_fit ]) np.savetxt("fit_comparison.csv", results, header="wavelength,aoi,psi_data,psi_fit,delta_data,delta_fit", delimiter=",") ``` -------------------------------- ### Install refellips via pip Source: https://github.com/refnx/refellips/blob/main/docs/installation.md Use this command to install the refellips package from PyPI. ```bash pip install refellips ``` -------------------------------- ### Import refellips and refnx Source: https://github.com/refnx/refellips/blob/main/demos/refellipsDemo_UserDefinedOscillator.ipynb Imports the refellips and refnx libraries and prints their versions. This confirms that the libraries are installed and accessible. ```python import refellips, refnx print(f"refellips: {refellips.__version__}\nrefnx: {refnx.__version__}") ``` -------------------------------- ### Checking software versions Source: https://github.com/refnx/refellips/blob/main/docs/getting_started.ipynb Prints the versions of the installed libraries to ensure reproducibility. ```python print( f"refellips: {refellips.version.version}\n" f"refnx: {refnx.version.version}\n" f"scipy: {scipy.version.version}\n" f"numpy: {np.version.version}" ) ``` -------------------------------- ### Check library versions Source: https://github.com/refnx/refellips/blob/main/demos/corefine_Ellipsometry_XRR_NR.ipynb Verify the versions of the installed analysis packages. ```python print( f"refellips: {refellips.version.version}\nrefnx: {refnx.version.version}\nscipy: {scipy.version.version}\nnumpy: {np.version.version}" ) ``` -------------------------------- ### Defining the dataset file path Source: https://github.com/refnx/refellips/blob/main/docs/getting_started.ipynb Locates the test dataset file within the refellips installation directory. ```python pth = os.path.dirname(refellips.__file__) dname = "testData1_11nm_PNIPAM_on_Si_EP4.dat" file_path = pjoin(pth, "../", "demos", dname) ``` -------------------------------- ### Example Fitting Output Source: https://github.com/refnx/refellips/blob/main/demos/corefine_Ellipsometry_XRR_NR.ipynb Represents a typical output line from a fitting process, indicating the number of iterations and the time elapsed per iteration. ```text 52it [01:31, 1.77s/it] ``` -------------------------------- ### Compare refellips to WVASE (2nm SiO2, 65nm Al2O3) Source: https://github.com/refnx/refellips/blob/main/refellips/tests/TestSuite.ipynb Compares refellips results to WVASE data for a thin film stack of 2 nm SiO2 and 65 nm Al2O3 in air. Requires DataSE and RI for material loading. ```python data = DataSE("WVASE_example_2nmSiO2_65nmAl2O3_MultiWavelength.txt") si = RI("../materials/silicon.csv") sio2 = RI("../materials/silica.csv") al2o3 = RI("../materials/aluminium_oxide.csv") air = RI("../materials/air.csv") struc = air() | al2o3(650) | sio2(20) | si() model = ReflectModelSE(struc, delta_offset=0) model._flip_delta = True fig, ax = plt.subplots() axt = ax.twinx() wavelength, aoi, d_psi, d_delta = data.data psi, delta = model(np.c_[wavelength, np.ones_like(wavelength) * aoi]) ax.plot(wavelength, d_psi, ls="dotted", color="k", label="wvase", zorder=3) axt.plot(wavelength, d_delta, ls="dotted", color="k", zorder=3) ax.plot(wavelength, psi, color="r", label="refellips") axt.plot(wavelength, delta, color="r") ax.legend(frameon=False, loc="lower center") ax.set(ylabel="Psi", xlabel="Wavelength (nm)") axt.set(ylabel="Delta") assert_allclose(psi, d_psi, rtol=4e-5) assert_allclose(delta, d_delta, rtol=2e-4) ``` -------------------------------- ### Get Varying Parameters Source: https://github.com/refnx/refellips/blob/main/docs/refellips.objectiveSE.md Retrieves the Parameter objects that are allowed to vary during a fit. ```APIDOC ## varying_parameters() ### Returns **varying_parameters** – The varying Parameter objects allowed to vary during the fit. ### Return type refnx.analysis.Parameters ``` -------------------------------- ### Build technique-specific models Source: https://github.com/refnx/refellips/blob/main/demos/corefine_Ellipsometry_XRR_NR.ipynb Construct the physical models for ellipsometry, X-ray, and neutron reflectometry. ```python si = load_material("silicon") sio2 = load_material("silica") PNIPAM = load_material("pnipam") air = load_material("air") polymer_layer = PNIPAM(polymer_thickness, polymer_roughness) polymer_layer.name = "PNIPAM" silica_layer = sio2(silica_thickness, silica_roughness) silica_layer.name = "Silica" structure_ellips = air() | polymer_layer | silica_layer | si() structure_ellips.contract = 1.5 model_ellips = ReflectModelSE(structure_ellips) ``` ```python si = SLD(20.1, "silicon") sio2 = SLD(22, "silica") PNIPAM = SLD(10.2, "pnipam") air = SLD(0, "air") polymer_layer = PNIPAM(polymer_thickness, polymer_roughness) polymer_layer.name = "PNIPAM" polymer_layer.sld.real.setp(vary=True, bounds=(9.5, 11)) silica_layer = sio2(silica_thickness, silica_roughness) silica_layer.name = "Silica" silica_layer.sld.real.setp(vary=True, bounds=(20, 23)) structure_xray = air() | polymer_layer | silica_layer | si() structure_xray.contract = 1.5 model_xray = ReflectModel(structure_xray) model_xray.bkg.setp(vary=True, bounds=(1e-9, 5e-6)) model_xray.scale.setp(value=1, vary=True, bounds=(0.7, 1.1)) ``` ```python si = SLD(2.07, "silicon") sio2 = SLD(3.47, "silica") PNIPAM = SLD(0.8, "pnipam") air = SLD(0, "air") polymer_layer = PNIPAM(polymer_thickness, polymer_roughness) polymer_layer.name = "PNIPAM" polymer_layer.sld.real.setp(vary=True, bounds=(0.5, 0.9)) silica_layer = sio2(silica_thickness, silica_roughness) silica_layer.name = "Silica" silica_layer.sld.real.setp(vary=False) structure_nr = air() | polymer_layer | silica_layer | si() structure_nr.contract = 1.5 model_nr = ReflectModel(structure_nr) model_nr.bkg.setp(vary=True, bounds=(1e-9, 5e-6)) model_nr.scale.setp(value=1, vary=True, bounds=(0.9, 1.1)) ``` -------------------------------- ### Compare refellips to WVASE (10nm SiO2, 325nm Al2O3) Source: https://github.com/refnx/refellips/blob/main/refellips/tests/TestSuite.ipynb Compares refellips results to WVASE data for a thin film stack of 10 nm SiO2 and 325 nm Al2O3 in air. Requires DataSE and RI for material loading. ```python data = DataSE("WVASE_example_10nmSiO2_325nmAl2O3_MultiWavelength.txt") si = RI("../materials/silicon.csv") sio2 = RI("../materials/silica.csv") al2o3 = RI("../materials/aluminium_oxide.csv") air = RI("../materials/air.csv") struc = air() | al2o3(3250) | sio2(100) | si() model = ReflectModelSE(struc, delta_offset=0) model._flip_delta = True fig, ax = plt.subplots() axt = ax.twinx() wavelength, aoi, d_psi, d_delta = data.data psi, delta = model(np.c_[wavelength, np.ones_like(wavelength) * aoi]) ax.plot(wavelength, d_psi, ls="dotted", color="k", label="wvase", zorder=3) axt.plot(wavelength, d_delta, ls="dotted", color="k", zorder=3) ax.plot(wavelength, psi, color="r", label="refellips") axt.plot(wavelength, delta, color="r") ax.legend(frameon=False, loc="lower center") ax.set(ylabel="Psi", xlabel="Wavelength (nm)") axt.set(ylabel="Delta") assert_allclose(psi, d_psi, rtol=4e-5) assert_allclose(delta, d_delta, rtol=2e-4) ``` -------------------------------- ### Load Ellipsometry Data Files Source: https://github.com/refnx/refellips/blob/main/demos/refellipsDemo_Map.ipynb Uses glob to find all .dat files in the 'ExampleMaps' directory and opens them using open_EP4file. Data is stored in a dictionary keyed by a simplified filename. ```python mapnames = glob.glob("ExampleMaps//*.dat") maps = {} for name in mapnames: prettyname = " ".join(os.path.basename(name).split("_")[:1]) print(prettyname) maps[prettyname] = open_EP4file(name) ``` -------------------------------- ### GET /refellips/dispersion/load_material Source: https://github.com/refnx/refellips/blob/main/docs/refellips.dispersion.md Loads a pre-defined dispersion curve from the refellips library based on the provided material name. ```APIDOC ## GET /refellips/dispersion/load_material ### Description Loads a dispersion curve from a file distributed with refellips. ### Method GET ### Endpoint refellips.dispersion.load_material(material) ### Parameters #### Path Parameters - **material** (str) - Required - One of the materials in refellips.materials ### Response #### Success Response (200) - **ri** (refellips.RI) - The loaded refractive index object. ``` -------------------------------- ### Importing refellips and dependencies Source: https://github.com/refnx/refellips/blob/main/docs/getting_started.ipynb Initializes the environment by importing refellips, refnx, and standard scientific computing libraries. ```python import sys import os from os.path import join as pjoin import numpy as np import matplotlib.pyplot as plt import scipy import refnx from refnx.analysis import CurveFitter from refnx.reflect import Slab import refellips from refellips.dataSE import DataSE, open_EP4file from refellips.reflect_modelSE import ReflectModelSE from refellips.objectiveSE import ObjectiveSE from refellips.dispersion import RI, Cauchy, load_material ``` -------------------------------- ### Load experimental data Source: https://github.com/refnx/refellips/blob/main/demos/corefine_Ellipsometry_XRR_NR.ipynb Load ellipsometry, XRR, and NR datasets from files. ```python data_ellips = open_EP4file("corefine_PNIPAM_ellipsometry.dat") data_xray = RD("corefine_PNIPAM_XRR.dat") data_nr = RD("corefine_PNIPAM_NR.dat") ``` -------------------------------- ### Loading the dataset Source: https://github.com/refnx/refellips/blob/main/docs/getting_started.ipynb Imports the ellipsometry dataset using the DataSE class. ```python data = DataSE(data=file_path) ``` -------------------------------- ### Create Feature Branch for Release Source: https://github.com/refnx/refellips/blob/main/release_notes.txt Create a new branch for the release, bump the version number in setup.py, set ISRELEASED to True, commit, and push the branch. ```bash git checkout -B # if necessary bump version number in setup.py, but only do it once # change ISRELEASED to True in setup.py git commit -a -m'REL: vX.Y.Z' git push origin ``` -------------------------------- ### Create Spectroscopic Ellipsometry Model Source: https://github.com/refnx/refellips/blob/main/demos/refellipsDemo_UserDefinedOscillator.ipynb Initializes a ReflectModelSE object with the defined sample structure for ellipsometric analysis. ```python model = ReflectModelSE(struc) ``` -------------------------------- ### Create Ellipsometry Model and Objective Source: https://github.com/refnx/refellips/blob/main/demos/corefine_polyBrush.ipynb Initializes the ReflectModelSE and ObjectiveSE for ellipsometry data analysis. The objective requires the model, experimental data, and an option to use weights. ```python model_ellips = ReflectModelSE(structure_ellips) objective_ellips = ObjectiveSE(model_ellips, data_ellips, use_weights=False) ``` -------------------------------- ### Create Lorentz oscillators Source: https://github.com/refnx/refellips/blob/main/docs/refellips.dispersion.md Demonstrates initializing single and multi-oscillator Lorentz models and calculating the refractive index at a specific wavelength. ```pycon >>> # Create a single Lorentz oscillator >>> Lorentz(5, 0.25, 2, Einf=1) >>> # Create a 2 oscillator dispersion curve >>> lo = Lorentz([5, 10], [0.25, 0.5], [2, 4], Einf=2) >>> lo.complex(658) # calculates the refractive index at 658 nm. ``` -------------------------------- ### Visualize Pre-fit Model Source: https://github.com/refnx/refellips/blob/main/demos/refellipsDemo_Spectroscopic.ipynb Plot the initial model against experimental data before optimization. ```python fig, ax = plt.subplots() axt = ax.twinx() for idx, wav in enumerate(np.unique(data.wavelength)): wavelength, aoi, d_psi, d_delta = list(data.unique_wavelength_data())[idx] psi, delta = model(np.c_[np.ones_like(aoi) * wavelength, aoi]) ax.plot(aoi, psi, color="r") axt.plot(aoi, delta, color="b") p = ax.scatter(aoi, d_psi, color="r") d = axt.scatter(aoi, d_delta, color="b") ax.legend(handles=[p, d], labels=["Psi", "Delta"]) ax.set(ylabel="Psi", xlabel="AOI (°)") axt.set(ylabel="Delta"); ``` -------------------------------- ### Create a Slab Layer with Cauchy Model Source: https://context7.com/refnx/refellips/llms.txt Demonstrates creating a slab layer using the Cauchy dispersion model and setting parameter bounds for fitting. ```python polymer_layer = polymer(thick=200, rough=5) # 200 A thick, 5 A roughness polymer_layer.thick.setp(vary=True, bounds=(100, 500)) ``` ```python print(f"A = {polymer.A.value}, B = {polymer.B.value}, C = {polymer.C.value}") ``` -------------------------------- ### Load Data and Define Model Source: https://github.com/refnx/refellips/blob/main/demos/refellipsDemo_Spectroscopic.ipynb Load experimental data and construct the physical layer structure for the ellipsometry model. ```python dname = "WVASE_example_2nmSiO2_20nmPNIPAM_MultiWavelength.txt" data = DataSE(data=dname) ``` ```python si = load_material("silicon") sio2 = load_material("silica") PNIPAM = RI("../refellips/materials/pnipam.csv") air = RI("../refellips/materials/air.csv") PNIPAM_layer = PNIPAM(150) PNIPAM_layer.thick.setp(vary=True, bounds=(100, 500)) struc = air() | PNIPAM_layer | sio2(20) | si() model = ReflectModelSE(struc) ``` -------------------------------- ### Load datasets Source: https://github.com/refnx/refellips/blob/main/demos/corefine_polyBrush.ipynb Load neutron reflectometry data using ReflectDataset and ellipsometry data using open_EP4file. ```python # Load in the NR data data_nr = RD("corefine_polyBrush_nr.dat") # Load in the ellipsometry data data_ellips = open_EP4file("corefine_polyBrush_ellipsometry.dat") ``` -------------------------------- ### Assemble Sample Structure Source: https://github.com/refnx/refellips/blob/main/demos/refellipsDemo_UserDefinedOscillator.ipynb Defines the layered structure of the sample, including substrate, film, and ambient layers. ```python struc = air() | film_layer | sio2(20) | si() ``` -------------------------------- ### Plot Model and Data Before Fitting Source: https://github.com/refnx/refellips/blob/main/demos/refellipsDemo.ipynb Visualizes the ellipsometry data (Psi and Delta) along with the initial model predictions across different wavelengths and angles of incidence. Requires matplotlib. ```python fig, ax = plt.subplots() axt = ax.twinx() for dat in data.unique_wavelength_data(): wavelength, aois, psi_d, delta_d = dat wavelength_aois = np.c_[np.ones_like(aois) * wavelength, aois] psi, delta = model(wavelength_aois) ax.plot(aois, psi, color="r") p = ax.scatter(data.aoi, data.psi, color="r") axt.plot(aois, delta, color="b") d = axt.scatter(data.aoi, data.delta, color="b") ax.legend(handles=[p, d], labels=["Psi", "Delta"]) ax.set(ylabel="Psi", xlabel="AOI, °") axt.set(ylabel="Delta") plt.show() ``` -------------------------------- ### Compare refellips to WVASE (SiO2, Polymer, Maxwell-Garnett EMA) Source: https://github.com/refnx/refellips/blob/main/refellips/tests/TestSuite.ipynb Compares refellips results to WVASE data for a film stack including SiO2 and a polymer layer with 20% solvent, using the Maxwell-Garnett EMA method. Requires DataSE, load_material, and Cauchy for material definition. ```python data = DataSE("WVASE_example_3nmSiO2_90nmPNIPAM_20EMA-MG_MultiWavelength.txt") si = load_material("silicon") sio2 = load_material("silica") polymer = Cauchy(A=1.47, B=0.00495) water = Cauchy(A=1.3242, B=0.003064) polymer_layer = polymer(900) polymer_layer.name = "PNIPAM" polymer_layer.vfsolv.setp(value=0.2) struc = water() | polymer_layer | sio2(30) | si() struc.solvent = water struc.ema = "maxwell-garnett" struc.depolarisation_factor = 1 / 3 model = ReflectModelSE(struc, delta_offset=0) model._flip_delta = True fig, ax = plt.subplots() axt = ax.twinx() wavelength, aoi, d_psi, d_delta = data.data psi, delta = model(np.c_[wavelength, np.ones_like(wavelength) * aoi]) ax.plot(wavelength, d_psi, ls="dotted", color="k", label="wvase", zorder=3) axt.plot(wavelength, d_delta, ls="dotted", color="k", zorder=3) ax.plot(wavelength, psi, color="r", label="refellips") axt.plot(wavelength, delta, color="r") ax.legend(frameon=False, loc="upper center") ax.set(ylabel="Psi", xlabel="Wavelength (nm)") axt.set(ylabel="Delta") assert_allclose(psi, d_psi, rtol=7e-4) assert_allclose(delta, d_delta, rtol=4e-4) ``` -------------------------------- ### Compare refellips to WVASE (SiO2, Polymer, Bruggeman EMA) Source: https://github.com/refnx/refellips/blob/main/refellips/tests/TestSuite.ipynb Compares refellips results to WVASE data for a film stack including SiO2 and a polymer layer with 70% solvent, using the Bruggeman EMA method. Requires DataSE, load_material, and Cauchy for material definition. ```python data = DataSE("WVASE_example_6nmSiO2_145nmPolymer_70EMA-BG_MultiWavelength.txt") si = load_material("silicon") sio2 = load_material("silica") polymer = Cauchy(A=1.66, B=0.006) water = load_material("water") polymer_layer = polymer(1450) polymer_layer.name = "PNIPAM" polymer_layer.vfsolv.setp(value=0.70) struc = water() | polymer_layer | sio2(60) | si() struc.solvent = water struc.ema = "bruggeman" struc.depolarisation_factor = 0.2 model = ReflectModelSE(struc, delta_offset=0) model._flip_delta = True fig, ax = plt.subplots() axt = ax.twinx() wavelength, aoi, d_psi, d_delta = data.data psi, delta = model(np.c_[wavelength, np.ones_like(wavelength) * aoi]) ax.plot(wavelength, d_psi, ls="dotted", color="k", label="wvase", zorder=3) axt.plot(wavelength, d_delta, ls="dotted", color="k", zorder=3) ax.plot(wavelength, psi, color="r", label="refellips") axt.plot(wavelength, delta, color="r") ax.legend(frameon=False, loc="upper right") ax.set(ylabel="Psi", xlabel="Wavelength (nm)") axt.set(ylabel="Delta") assert_allclose(psi, d_psi, rtol=2e-4) assert_allclose(delta, d_delta, rtol=7e-5) ``` -------------------------------- ### Import refellips and refnx Modules Source: https://github.com/refnx/refellips/blob/main/demos/refellipsDemo_Map.ipynb Imports specific modules from refellips and refnx for ellipsometry data handling and reflection modeling. ```python from refellips.dataSE import DataSE, open_EP4file, custom_round from refellips import ReflectModelSE, ObjectiveSE, RI, Cauchy, load_material ``` -------------------------------- ### Import refellips Dependencies Source: https://github.com/refnx/refellips/blob/main/refellips/tests/TestSuite.ipynb Imports necessary libraries and refellips modules for ellipsometry modeling. ```python import numpy as np import sys import matplotlib.pyplot as plt from numpy.testing import assert_allclose sys.path.append("../") import refellips from refellips.dataSE import DataSE from refellips.reflect_modelSE import ReflectModelSE from refellips.objectiveSE import ObjectiveSE, circular_distance from refellips.dispersion import Cauchy, RI, load_material ``` -------------------------------- ### Importing required refellips and refnx modules Source: https://github.com/refnx/refellips/blob/main/demos/refellipsDemo_UserDefinedOscillator.ipynb Load necessary classes and utilities for building a custom dielectric function. ```python from refellips import ScattererSE, nm_eV_conversion from refnx.analysis import ( Parameters, possibly_create_parameter, sequence_to_parameters, ) ``` -------------------------------- ### Load Experimental Data Source: https://github.com/refnx/refellips/blob/main/demos/refellipsDemo_Spectroscopic_SL.ipynb Loads ellipsometry data from a specified file path. ```python dname = "WVASE_example_2nmSiO2_100nmPNIPAM_MultiWavelength_Water.dat" data = DataSE(data=dname) ``` -------------------------------- ### Define global parameters Source: https://github.com/refnx/refellips/blob/main/demos/corefine_Ellipsometry_XRR_NR.ipynb Create shared parameters for thickness and roughness across all models. ```python silica_thickness = Parameter( 20, vary=True, bounds=(1, 30), name="silica_thickness" ) polymer_thickness = Parameter( 250, vary=True, bounds=(150, 400), name="polymer_thickness" ) silica_roughness = Parameter( 0.1, vary=True, bounds=(0.01, 10), name="silica_roughness" ) polymer_roughness = Parameter( 10, vary=True, bounds=(0.01, 20), name="polymer_roughness" ) ``` -------------------------------- ### Initialize Objective Function for Fitting Source: https://github.com/refnx/refellips/blob/main/demos/refellipsDemo.ipynb Creates an ObjectiveSE object, which combines the ellipsometry model and the experimental data, preparing it for the fitting process. ```python objective = ObjectiveSE(model, data) ``` -------------------------------- ### Create Uniform Slab Layer with SlabSE Source: https://context7.com/refnx/refellips/llms.txt Represents a single layer with a uniform refractive index using `SlabSE`. Demonstrates loading materials, creating a slab, accessing properties, and setting parameters for fitting. ```python from refellips import RI, load_material, SlabSE # Create materials silica = load_material("silica") silicon = load_material("silicon") # Create slab using ScattererSE.__call__ sio2_layer = silica(thick=20, rough=3, vfsolv=0) # Access slab properties print(f"Thickness: {sio2_layer.thick.value} Angstrom") print(f"Roughness: {sio2_layer.rough.value} Angstrom") print(f"Solvent fraction: {sio2_layer.vfsolv.value}") # Set parameter to vary during fitting sio2_layer.thick.setp(vary=True, bounds=(10, 50)) sio2_layer.name = "SiO2 layer" # Get all parameters print(sio2_layer.parameters) # Get slab representation (thickness, n, k, roughness, vfsolv) slabs = sio2_layer.slabs() print(f"Slab array shape: {slabs.shape}") ``` -------------------------------- ### Import Dependencies Source: https://github.com/refnx/refellips/blob/main/demos/refellipsDemo_Spectroscopic.ipynb Load necessary libraries for data analysis, modeling, and material definitions. ```python import sys import os import numpy as np import pandas as pd import matplotlib.pyplot as plt import glob from refnx.analysis import CurveFitter from refnx.reflect import Slab ``` ```python from refellips.dataSE import DataSE, open_EP4file from refellips.reflect_modelSE import ReflectModelSE from refellips.objectiveSE import ObjectiveSE from refellips.dispersion import RI, load_material ``` ```python # Include plotting tools sys.path.insert(1, "../tools") from plottools import plot_ellipsdata, plot_structure ``` -------------------------------- ### Generate Final Plots Source: https://github.com/refnx/refellips/blob/main/demos/refellipsDemo_Spectroscopic.ipynb Use custom plotting tools to visualize the ellipsometry data and the final structural model. ```python fig, ax = plt.subplots(1, 2, figsize=(10, 4)) plot_ellipsdata(ax[0], data=data, model=model, xaxis="aoi") plot_structure(ax[1], objective=objective) fig.tight_layout() ``` -------------------------------- ### Validate Bare Silicon Interface Source: https://github.com/refnx/refellips/blob/main/refellips/tests/TestSuite.ipynb Compares bare interface ellipsometry calculations against WVASE reference data. ```python dname = "TestData_bareSI.txt" data = DataSE(data=dname) si = RI("../materials/silicon.csv") void = RI("../materials/void.csv") struc = void() | si() model = ReflectModelSE(struc) fig, ax = plt.subplots() axt = ax.twinx() test_arr = [] for idx, wav in enumerate(np.unique(data.wavelength)): wavelength, aoi, d_psi, d_delta = list(data.unique_wavelength_data())[idx] psi, delta = model(np.c_[np.ones_like(aoi) * wavelength, aoi]) ax.scatter(aoi, psi, facecolor="none", color="r", marker="s") p = ax.scatter(aoi, d_psi, facecolor="none", color="r") test_arr.append(np.abs(np.array(psi - d_psi) / d_psi) < 0.005) test_arr.append(np.abs(np.array(delta - d_delta) / d_delta) < 0.005) axt.scatter(aoi, delta, facecolor="none", color="b", marker="s") d = axt.scatter(aoi, d_delta, facecolor="none", color="b") ax.legend(handles=[p, d], labels=["Psi", "Delta"]) ax.set(ylabel="Psi", xlabel="AOI, °") axt.set(ylabel="Delta") test_arr = np.array(test_arr) if np.prod(test_arr, dtype=bool): print("Test passed") else: print("test failed") ``` -------------------------------- ### Load Ellipsometry Data Source: https://github.com/refnx/refellips/blob/main/demos/refellipsDemo.ipynb Loads ellipsometry data from a specified file and also reads WVASE output for comparison. ```python # Ellipsometry data to model using refellips dname = "testData1_11nm_PNIPAM_on_Si_EP4.dat" data = DataSE(data=dname) # Ellipsometry data modelled in WVASE WVASE_test = pd.read_csv( open("WVASE_example_2nmSiO2_11nmPNIPAM_658nm.txt", "r") ) ``` -------------------------------- ### Verify library versions Source: https://github.com/refnx/refellips/blob/main/demos/corefine_polyBrush.ipynb Print the versions of the loaded libraries to ensure compatibility. ```python print( f"refnx: {refnx.version.version}\nrefellips: {refellips.version.version}\nscipy: {scipy.version.version}\nnumpy: {np.version.version}" ) ``` -------------------------------- ### Configure Material Properties Source: https://github.com/refnx/refellips/blob/main/docs/getting_started.ipynb Set names, vary thickness, and fix volume fraction of solvent for material layers. Thickness can be varied within specified bounds. ```python silica_layer.name = "Silica" silica_layer.thick.setp(vary=True, bounds=(1, 30)) silica_layer.vfsolv.setp(vary=False, value=0) polymer_layer.name = "PNIPAM" polymer_layer.thick.setp(vary=True, bounds=(100, 500)) polymer_layer.vfsolv.setp(vary=False, value=0) ``` -------------------------------- ### Open HORIBA File Source: https://github.com/refnx/refellips/blob/main/docs/refellips.dataSE.md Loads data from a Horiba ellipsometer .spe file. ```APIDOC ## refellips.dataSE.open_HORIBAfile ### Description Opening and loading in a data file created by a Horiba ellipsometer. Data file loaded should be of the Horiba file format .spe. Note: This file parser has been written for a specific ellipsometer, no work has been done to ensure it is compatable with all Horiba ellipsometers. If you have trouble with this parser contact the maintainers through github. ### Method Not specified (assumed to be a function call) ### Endpoint Not applicable (local function) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **fname** (file-handle or string) - Required - File to load the dataset from. - **reflect_delta** (bool) - Optional - Option to reflect delta around 180 degrees (as WVASE would). - **lambda_cutoffs** (list) - Optional - Specifies the minimum and maximum wavelengths of data to be loaded. List has length 2. ### Request Example ```python # Example usage (assuming refellips is imported and data is available) # data = refellips.dataSE.open_HORIBAfile('path/to/your/file.spe', reflect_delta=True, lambda_cutoffs=[400, 700]) ``` ### Response #### Success Response (200) - **DataSE** (DataSE structure) - The data file structure from the loaded Horiba file. #### Response Example ```json { "example": "DataSE structure" } ``` ``` -------------------------------- ### Perform Optimization Source: https://github.com/refnx/refellips/blob/main/demos/refellipsDemo_Spectroscopic.ipynb Create an objective function and run the least-squares fitter. ```python objective = ObjectiveSE(model, data) ``` ```python objective.residuals() ``` ```python fitter = CurveFitter(objective) fitter.fit(method="least_squares"); ``` -------------------------------- ### Import required libraries Source: https://github.com/refnx/refellips/blob/main/demos/corefine_Ellipsometry_XRR_NR.ipynb Initial imports for data handling, plotting, and the refellips/refnx analysis frameworks. ```python import numpy as np import pandas as pd import scipy import matplotlib.pyplot as plt ``` ```python import refellips from refellips.dataSE import open_EP4file from refellips import ReflectModelSE, ObjectiveSE, load_material ``` ```python import refnx from refnx.dataset import ReflectDataset as RD from refnx.analysis import ( CurveFitter, Parameter, Objective, GlobalObjective, Transform, ) from refnx.reflect import Linear, Erf, SLD, ReflectModel ``` -------------------------------- ### Create Sellmeier Oscillator and Layer Source: https://context7.com/refnx/refellips/llms.txt Models refractive index using the Sellmeier equation. Use this for accurate modeling in infrared wavelengths. Parameters include amplitude, center wavelength, pole position, and offset. ```python from refellips import Sellmeier # Create Sellmeier oscillator # Parameters: Am (amplitude), En (center wavelength in um), P (pole position), Einf (offset) glass_sellmeier = Sellmeier(Am=2.0, En=0.1, P=0.11, Einf=1, name="glass") # Get refractive index ri = glass_sellmeier.complex(wavelength=658) print(f"n at 658 nm: {ri.real:.4f}") # Create layer from Sellmeier material glass_layer = glass_sellmeier(thick=1000, rough=3) # Access and modify parameters glass_sellmeier.Am.setp(vary=True, bounds=(1, 5)) glass_sellmeier.En.setp(vary=True, bounds=(0.05, 0.5)) ``` -------------------------------- ### Calculate Psi and Delta with ReflectModelSE Source: https://context7.com/refnx/refellips/llms.txt Use the transfer matrix method to calculate ellipsometric parameters from a defined structure. ```python import numpy as np from refellips import RI, Cauchy, load_material, ReflectModelSE, StructureSE # Build structure air = load_material("air") sio2 = load_material("silica") silicon = load_material("silicon") polymer = Cauchy(A=1.47, B=0.005, name="polymer") structure = air(0, 0) | polymer(200, 5) | sio2(20, 3) | silicon(0, 0) # Create reflection model model = ReflectModelSE(structure, delta_offset=0, name="my_model") # Calculate Psi and Delta # Input: array of shape (N, 2) with [wavelength (nm), AOI (degrees)] wavelength_aoi = np.array([ [658, 50], [658, 55], [658, 60], [658, 65], ]) psi, delta = model(wavelength_aoi) print(f"Psi: {psi}") print(f"Delta: {delta}") # Calculate for spectroscopic data wavelengths = np.linspace(400, 800, 50) aoi = 65 * np.ones_like(wavelengths) wavelength_aoi_spectro = np.column_stack([wavelengths, aoi]) psi_spec, delta_spec = model(wavelength_aoi_spectro) # Set delta offset to vary model.delta_offset.setp(value=0, vary=True, bounds=(-10, 10)) # Access all model parameters print(model.parameters) # Get log-probability (for Bayesian fitting) logp = model.logp() ``` -------------------------------- ### Tag and Push Release Source: https://github.com/refnx/refellips/blob/main/release_notes.txt Tag the release with a version number and push the tag to the refellips remote. ```bash git tag -a vX.Y.Z git push refellips vX.Y.Z ``` -------------------------------- ### Supply Single Wavelength Refractive Index and Extinction Coefficient Source: https://github.com/refnx/refellips/blob/main/docs/faq.md Provide a refractive index (n) and extinction coefficient (k) for a single wavelength measurement. ```default my_material = RI([n, k]) ``` -------------------------------- ### Validate 2 nm SiO2 and 20 nm polymer film system Source: https://github.com/refnx/refellips/blob/main/refellips/tests/TestSuite.ipynb Models a complex system with a 2 nm SiO2 layer and a 20 nm polymer layer containing 50% solvent, using Cauchy dispersion models. ```python data = DataSE("WVASE_example_2nmSiO2_20nmPNIPAM_50EMA_MultiWavelength.txt") si = RI("../materials/silicon.csv") sio2 = RI("../materials/silica.csv") polymer = Cauchy(A=1.47, B=0.00495) h2o = Cauchy(A=1.3242, B=0.003064) polymer_layer = polymer(200) polymer_layer.name = "PNIPAM" polymer_layer.vfsolv.setp(value=0.5) struc = h2o() | polymer_layer | sio2(20) | si() struc.solvent = h2o struc.ema = "linear" model = ReflectModelSE(struc, delta_offset=0) model._flip_delta = True fig, ax = plt.subplots() axt = ax.twinx() wavelength, aoi, d_psi, d_delta = data.data psi, delta = model(np.c_[wavelength, np.ones_like(wavelength) * aoi]) ax.plot(wavelength, d_psi, ls="dotted", color="k", label="wvase", zorder=3) axt.plot(wavelength, d_delta, ls="dotted", color="k", zorder=3) ax.plot(wavelength, psi, color="r", label="refellips") axt.plot(wavelength, delta, color="r") ax.legend(frameon=False, loc="upper center") ax.set(ylabel="Psi", xlabel="Wavelength (nm)") axt.set(ylabel="Delta") assert_allclose(psi, d_psi, rtol=6e-4) assert_allclose(delta, d_delta, rtol=6e-4) ``` -------------------------------- ### ReflectModelSE Source: https://github.com/refnx/refellips/blob/main/docs/modules.md Reflection modeling utilities for spectroscopic ellipsometry. ```APIDOC ## ReflectModelSE ### Methods - `Delta_Psi_TMM()`: Calculate Delta and Psi using TMM. - `ReflectModelSE.logp()`: Log-probability for the reflection model. - `ReflectModelSE.model()`: Generate model output. - `coh_tmm()`: Coherent transfer matrix method. - `interface_r_p()`: Interface reflection coefficient (p-polarization). - `interface_r_s()`: Interface reflection coefficient (s-polarization). - `interface_t_p()`: Interface transmission coefficient (p-polarization). - `interface_t_s()`: Interface transmission coefficient (s-polarization). ### Properties - `ReflectModelSE.parameters`: Model parameters. - `ReflectModelSE.structure`: Model structure. ``` -------------------------------- ### Utility: open_EP4file Source: https://github.com/refnx/refellips/blob/main/docs/refellips.dataSE.md Loads data from an Accurion EP4 formatted file. ```APIDOC ## Function refellips.dataSE.open_EP4file ### Description Open and load an Accurion EP4 formatted data file (typically .dat). ### Parameters - **fname** (file-handle or string) - Required - File to load the dataset from. - **reflect_delta** (bool) - Optional - Option to reflect delta around 180 degrees. ### Response - **datasets** (DataSE) - Structure containing wavelength, angle of incidence, psi, and delta. ``` -------------------------------- ### Import required libraries Source: https://github.com/refnx/refellips/blob/main/demos/corefine_polyBrush.ipynb Load necessary scientific and analysis packages for data processing and modeling. ```python %matplotlib inline import scipy import numpy as np import matplotlib.pyplot as plt ``` ```python import refnx from refnx.dataset import ReflectDataset as RD from refnx.analysis import ( Transform, CurveFitter, Objective, GlobalObjective, Parameter, ) from refnx.reflect import SLD, ReflectModel ``` ```python import refellips from refellips.dataSE import open_EP4file from refellips.reflect_modelSE import ReflectModelSE from refellips.objectiveSE import ObjectiveSE from refellips.dispersion import load_material ``` -------------------------------- ### Import Necessary Libraries Source: https://github.com/refnx/refellips/blob/main/demos/refellipsDemo.ipynb Imports essential libraries for data analysis, manipulation, and visualization, including refnx components. ```python import sys import os from os.path import join as pjoin import numpy as np import pandas as pd import matplotlib.pyplot as plt import glob from refnx.analysis import CurveFitter from refnx.reflect import Slab ``` -------------------------------- ### Create analysis objectives Source: https://github.com/refnx/refellips/blob/main/demos/corefine_Ellipsometry_XRR_NR.ipynb Define the objectives for each technique without internal weighting. ```python objective_ellips = ObjectiveSE(model_ellips, data_ellips, use_weights=False) objective_xray = Objective( model_xray, data_xray, transform=Transform("logY"), use_weights=False ) objective_nr = Objective( model_nr, data_nr, transform=Transform("logY"), use_weights=False ) ``` -------------------------------- ### Import refellips Modules Source: https://github.com/refnx/refellips/blob/main/demos/refellipsDemo.ipynb Imports specific modules from the refellips library for ellipsometry data handling and modeling. ```python import refellips from refellips.dataSE import open_EP4file from refellips import ( ObjectiveSE, ReflectModelSE, RI, Cauchy, load_material, DataSE, ) ``` -------------------------------- ### Load and Handle Ellipsometry Data with DataSE Source: https://context7.com/refnx/refellips/llms.txt The DataSE class loads and manages ellipsometry datasets. It can load from files or arrays and provides methods to access and save data. ```python import numpy as np from refellips import DataSE from refellips.dataSE import open_EP4file, open_HORIBAfile, open_M2000file, open_FilmSenseFile # Load from a tab-delimited text file (columns: wavelength, AOI, Psi, Delta) data = DataSE(data="ellipsometry_data.txt") # Create from arrays wavelength = np.array([658.0, 658.0, 658.0, 658.0]) # nm aoi = np.array([50.0, 55.0, 60.0, 65.0]) # degrees psi = np.array([23.5, 25.2, 27.8, 31.1]) # degrees delta = np.array([125.3, 118.7, 108.2, 94.5]) # degrees data = DataSE(data=(wavelength, aoi, psi, delta)) # Load Accurion EP4 format data ep4_data = open_EP4file("sample.dat", reflect_delta=False) # Load Horiba ellipsometer data horiba_data = open_HORIBAfile("sample.spe", lambda_cutoffs=[400, 800]) # Load Woolam M2000/CompleteEASE data m2000_data = open_M2000file("sample.txt", dropdatapoints=2) # Load FilmSense ellipsometer data filmsense_data = open_FilmSenseFile("sample.txt") # Access data properties print(f"Wavelengths: {data.wavelength}") print(f"Angles of incidence: {data.aoi}") print(f"Psi values: {data.psi}") print(f"Delta values: {data.delta}") print(f"Number of points: {len(data)}") # Iterate through unique wavelengths for wavelength, aoi, psi, delta in data.unique_wavelength_data(): print(f"Wavelength {wavelength} nm: {len(aoi)} points") # Save data to file data.save("output_data.txt") ```