コード例 #1
0
def test_TMM_ellipsometry():
    GaAs = material("GaAs")(T=300)

    my_structure = Structure(
        [Layer(si(3000, "nm"), material=GaAs), Layer(si(300, "um"), material=GaAs)]
    )

    wavelength = np.linspace(450, 1100, 300)
    idx = np.argmin(abs(wavelength - 800))

    angles = [60, 65, 70]
    out = calculate_ellipsometry(my_structure, wavelength, angle=angles)

    data = (
        22.2849089096,
        181.488417672,
        16.4604621886,
        182.277656469,
        9.10132195668,
        184.509752582,
    )

    for i in range(len(angles)):
        assert data[2 * i] == approx(out["psi"][idx, i])
        assert data[2 * i + 1] == approx(out["Delta"][idx, i])
コード例 #2
0
    def plot(self, log: bool = True) -> None:
        """ Plots the expeirmental and the modelled data.

        :param log: If the X scale should be log.
        :return: None
        """

        mod_data = calculate_ellipsometry(self.stack,
                                          self.range,
                                          angle=self.data.angles)

        fig, ax = plt.subplots(nrows=2, ncols=1, sharex=True)
        min_wl = 0
        max_wl = 1e6

        if log:
            for i, ang in enumerate(self.data.angles):
                new_wl = self.data.data[ang][0]
                if min(new_wl) > min_wl: min_wl = min(new_wl)
                if max(new_wl) < max_wl: max_wl = max(new_wl)

                psi = np.interp(new_wl, self.range / 1000., mod_data['psi'][:,
                                                                            i])
                delta = np.interp(new_wl, self.range / 1000.,
                                  mod_data['Delta'][:, i])

                ax[0].semilogx(new_wl, self.data.data[ang][1], 'o', mfc='none')
                ax[1].semilogx(new_wl, self.data.data[ang][3], 'o', mfc='none')
                ax[0].semilogx(new_wl, psi, 'r')
                ax[1].semilogx(new_wl, delta, 'b')

        else:
            for i, ang in enumerate(self.data.angles):
                new_wl = self.data.data[ang][0] * 1000.
                if min(new_wl) > min_wl: min_wl = min(new_wl)
                if max(new_wl) < max_wl: max_wl = max(new_wl)

                psi = np.interp(new_wl, self.range / 1000., mod_data['psi'][:,
                                                                            i])
                delta = np.interp(new_wl, self.range / 1000.,
                                  mod_data['Delta'][:, i])

                ax[0].plot(new_wl, self.data.data[ang][1], 'o', mfc='none')
                ax[1].plot(new_wl, self.data.data[ang][3], 'o', mfc='none')
                ax[0].semilogx(new_wl, psi, 'r')
                ax[1].semilogx(new_wl, delta, 'b')

        ax[0].set_xlim((min_wl, max_wl))
        ax[1].set_xlim((min_wl, max_wl))

        x = [0.3, 0.4, 0.5, 0.7, 1, 2, 3, 4, 5, 7, 10, 20]
        plt.xticks(x, x)
        plt.xlabel('Wavelength (µm)')
        ax[0].set_ylabel(r'$\Psi$ (º)')
        ax[1].set_ylabel(r'$\Delta$ (º)')
        plt.show()
コード例 #3
0
    def test_44_TMM_ellipsometry(self):
        GaAs = material('GaAs')(T=300)

        my_structure = Structure([
            Layer(si(3000, 'nm'), material=GaAs),
            Layer(si(300, 'um'), material=GaAs),
        ])

        wavelength = np.linspace(450, 1100, 300)
        idx = np.argmin(abs(wavelength - 800))

        angles = [60, 65, 70]
        out = calculate_ellipsometry(my_structure, wavelength, angle=angles)

        data = (22.2849089096, 181.488417672, 16.4604621886, 182.277656469,
                9.10132195668, 184.509752582)

        for i in range(len(angles)):
            self.assertAlmostEqual(data[2 * i], out['psi'][idx, i])
            self.assertAlmostEqual(data[2 * i + 1], out['Delta'][idx, i])
コード例 #4
0
    def mse(self, v: List[float] = None) -> np.ndarray:
        """ Calculates the mean-squared error between the experimental data and the modelled one. If the vars input
        is given, the variables are first updated and then the MSE is calculated.

        Since the experimental data might have a lot of wavelength points, we use a reduced number of them as defined
        in self.range in order to speed up the calculation of the ellipsometric parameters. The modelled data is then
        interpolated to the experimental one in order to calculate the MSE. While this will lead to higher uncertainties
        when the experimental data varies rapidly, it makes the calculation much faster.

        :param v: The free variables to update.
        :return: The mean-squared error between the experimental data and the modelled one
        """
        assert self.range is not None, 'Error: A wavelength range must be defined before calculating the MSE'

        if v is not None:
            self.update_variables(v)
            num_var = len(v)
        else:
            num_var = 0

        out = 0.
        elements = 0.

        mod_data = calculate_ellipsometry(self.stack,
                                          self.range,
                                          angle=self.data.angles)

        for i, ang in enumerate(self.data.angles):
            new_wl = self.data.data[ang][0] * 1000.
            elements += len(new_wl)
            psi = np.interp(new_wl, self.range, mod_data['psi'][:, i])
            delta = np.interp(new_wl, self.range, mod_data['Delta'][:, i])

            p = (self.data.data[ang][1] - psi) / self.data.data[ang][1]
            d = (self.data.data[ang][3] - delta) / self.data.data[ang][4]

            out += np.sum(p**2 + d**2)

        out = np.sqrt(1. / (2 * elements - num_var) * out)

        return np.array(out)
コード例 #5
0
# First we defined a couple of materials, for example, GaAs and AlGAs
GaAs = material('GaAs')(T=300)
AlGaAs = material('AlGaAs')(T=300, Al=0.3)

# Now, let's build the structure. We don't add a substrate and assume that there is an infinitely thick absorbing
# material in the back.
my_structure = Structure([
    Layer(si(40, 'nm'), material=AlGaAs),
    Layer(si(3000, 'nm'), material=GaAs),
])

# We want to calculate the ellipsometry of this structure as a function of the wavelength for a few angles
wavelength = np.linspace(400, 1000, 200)
angles = [65, 70, 75]

out = calculate_ellipsometry(my_structure, wavelength, angle=angles)

# This results must be taken with care. As the ellipsometry routine can only deal with coherent light, there might be
# strange oscillations related with intereference in thick layers, something that should not happen.
# Setting no_back_reflection=True (the default) should take care of most of this effects, but might add other unexpected
# ones.
fig, ax1 = plt.subplots(1, 1)
ax2 = ax1.twinx()

ax1.plot(wavelength, out['psi'][:, 0], 'b', label=r'$\Psi$')
ax2.plot(wavelength, out['Delta'][:, 0], 'r', label=r'$\Delta$')
for i in range(1, len(angles)):
    ax1.plot(wavelength, out['psi'][:, i], 'b')
    ax2.plot(wavelength, out['Delta'][:, i], 'r')

ax1.set_xlabel("Wavelength (nm)")
コード例 #6
0
                                            A1=0.80686642, L1=0.68972606E-1,
                                            A2=0.71815848, L2=0.15396605,
                                            A3=0.85416831, L3=0.11841931E2)
])

GeO2_nk = cppb().nk_calc(oscillator_structure=GeO2, energy_array=E_eV)

## Step 2 :: use this modelled n and k to calculate the ellipsometry data...
# Define a structure for the optical stack...
OptiStack = Structure([
    [4.4, 1240/E_eV, GeO2_nk["n"], GeO2_nk["k"]], # Layer 1 :: GeO2 native oxide layer
    [350000, 1240/E_eV, n_spline, k_spline]      # Layer 2/ Substrate :: Bulk Ge
])

# Calculate Ellipsometry data...
Out = calculate_ellipsometry(OptiStack, 1240/E_eV, angle=Exp_Angles)

# Convert Ellipsometry data to complex dielectric function...
# Define functions for the quick conversion of data...
i = 2

rho = lambda psi, delta: np.tan(psi) * np.exp(1j * delta)
eps = lambda r, theta: np.sin(theta)**2 * (1 + np.tan(theta)**2 * ((1 - r)/(1 + r))**2)

# Experimental data...
Exp_rho = rho(np.radians(Exp_Data.data[Exp_Angles[i]][1]), np.radians((Exp_Data.data[Exp_Angles[i]][3])))
Exp_eps = eps(Exp_rho, np.radians(Exp_Angles[i]))

# Modelled data...
Mod_rho = rho(np.radians(Out["psi"][:,i]), np.radians(Out["Delta"][:,i]))
Mod_eps = eps(Mod_rho, np.radians(Exp_Angles[i]))