NAME

PDL::Demos::Ellipsometry - Interactive PDL demo for spectroscopic ellipsometry analysis

SYNOPSIS

Launch from the perldl or pdl2 shell:

pdl> demo ellipsometry

Requires PDL::Graphics::Simple for plotting.

DESCRIPTION

This demo provides a hands-on walkthrough of thin-film optical modelling and Levenberg-Marquardt fitting using Physics::Ellipsometry::VASE and PDL. It progresses from simple linear models to realistic multi-layer structures, showing the code at each step and generating interactive plots.

DEMO SECTIONS

The demo is divided into three parts of increasing complexity. Each part shows the code being executed, prints results to the terminal, and produces plots via PDL::Graphics::Simple.

Part 1 — Linear model (synthetic data)

Introduces the basic VASE workflow with a trivial linear model. This verifies the fitting infrastructure without any optics:

Step 1: Generate synthetic data

$wavelength = pdl [400, 410, 420, 430, 440];
$angle      = 70 * ones(5);
$psi        = 45.0 - 0.05 * $wavelength;
$delta      = 80.0 + 0.10 * $wavelength;

Step 2: Write to a file and load into a VASE object

$vase = Physics::Ellipsometry::VASE->new(layers => 1);
$data = $vase->load_data($tmpfile);

Step 3: Define and fit a linear model

sub linear_model {
    my ($params, $x) = @_;
    my ($a, $b, $c, $d) = map { $params->slice("($_)") } 0..3;
    my $wl  = $x->slice(",(0)")->flat;
    my $psi = $a - $b * $wl;
    my $del = $c + $d * $wl;
    return cat($psi, $del)->flat;
}

$vase->set_model(\&linear_model);
$fit = $vase->fit(pdl [65, 0.05, 80, 0.1]);

Step 4: Plot — two-panel plot of Psi and Delta vs wavelength, showing data points and the fitted line.

Part 2 — Cauchy dispersion on Si (simulated data)

Introduces real thin-film physics: the Cauchy dispersion model combined with Fresnel equations and thin-film interference.

The Cauchy model predicts the refractive index of a transparent film:

n(lambda) = A + B/lambda^2 + C/lambda^4

Step 1: Simulate realistic SiO2/Si data

$wl_sim = sequence(21) * 15 + 400;    # 400–700 nm
$n_true = 1.46 + 3400.0 / $wl_sim**2;

Step 2: Define the Fresnel + Cauchy model — computes Psi and Delta from a single-layer Air/SiO2/Si stack using explicit Fresnel coefficients, Snell's law, and thin-film phase thickness:

sub fresnel_cauchy {
    my ($par, $x) = @_;
    my $n1 = $A + $B / $lam**2;          # Cauchy dispersion
    my $beta = (2*PI/$lam) * $n1 * $d * cos($th1);  # phase
    # ... Fresnel coefficients, Airy formula ...
    my $rho = $rp / $rs;
    my $psi = atan(abs($rho)) * (180/PI);
    my $delta = carg($rho) * (180/PI);
    return cat($psi->re, $delta->re)->flat->double;
}

Step 3: Fit from a deliberately offset starting guess

$true_params = pdl [1.46, 0.34, 3.87, 100.0];  # A, B, n_sub, d
$guess       = pdl [1.50, 0.50, 3.50,  80.0];  # wrong on purpose
$cauchy_fit  = $cauchy_vase->fit($guess);

Step 4: Plot — Psi and Delta panels comparing noisy simulated data with the converged fit.

Part 3 — Multi-layer TMM fit (real VASE data)

The most advanced section: fits a three-layer model to real multi-angle spectroscopic ellipsometry data using the built-in TMM, Dispersion, EMA, and Materials sub-modules.

Sample structure:

Air / Ta2O5 (Cauchy) / EMA roughness / Ta metal substrate

Modules used:

use Physics::Ellipsometry::VASE::TMM qw(psi_delta);
use Physics::Ellipsometry::VASE::Dispersion qw(cauchy_nk);
use Physics::Ellipsometry::VASE::EMA qw(ema_linear);
use Physics::Ellipsometry::VASE::Materials qw(load_material
                                               interpolate_material);

Step 1: Load tabulated Ta metal substrate

$ta_metal = load_material("${demo_dir}demo_ta_metal.mat");

Step 2: Load real Woollam VASE data (three angles of incidence: 65°, 70°, 75°, ~500 data points):

$ml_vase = Physics::Ellipsometry::VASE->new(
    layers => 3, circular_delta => 1,
);
$ml_vase->load_data("${demo_dir}demo_wafer.dat");

Step 3: Define the 6-parameter multi-layer model

sub multilayer_model {
    my ($params, $x_data) = @_;
    # Cauchy dispersion for Ta2O5
    my ($n1, $k1) = cauchy_nk($lambda, $A, $B, $C);
    # EMA roughness layer (Ta2O5 + void)
    my $N2 = sqrt(ema_linear($N1**2, $eps_void, $vf_void));
    # Ta metal substrate from tabulated data
    my ($n_ta, $k_ta) = interpolate_material($ta_metal, $lambda);
    # TMM for the full stack
    my ($psi, $delta) = psi_delta($lambda, $theta,
        [$N0, $N1, $N2, $N3], [$d_film, $d_ema]);
    return $psi->append($delta);
}

Step 4: Grid search over thickness to find the correct interference order, then Levenberg-Marquardt refinement:

# Grid search
for my $d_s (map { $_ * 0.02 + 1.5 } (0..50)) { ... }

# LM refinement from grid-search starting point
$ml_fit = $ml_vase->fit($ml_guess);

Step 5: Plot — colour-coded multi-angle data and fit curves for both Psi and Delta.

DATA FILES

Two data files are shipped alongside this module and used by the multi-layer demo:

demo_wafer.dat

Woollam VASE measurement of a Ta2O5-on-Ta sample at three angles of incidence.

demo_ta_metal.mat

Point-by-point optical constants (n, k vs eV) for the tantalum metal substrate.

SEE ALSO

Physics::Ellipsometry::VASE, Physics::Ellipsometry::VASE::TMM, Physics::Ellipsometry::VASE::Dispersion, Physics::Ellipsometry::VASE::EMA, Physics::Ellipsometry::VASE::Materials, PDL::Demos, PDL::Fit::LM, PDL::Graphics::Simple

AUTHOR

Jovan Trujillo <jtrujil1@asu.edu>