NAME

Physics::Ellipsometry::VASE - Variable Angle Spectroscopic Ellipsometry data fitting

VERSION

Version 0.02

SYNOPSIS

use PDL;
use PDL::NiceSlice;
use Physics::Ellipsometry::VASE;

# Create a VASE fitter for a single-layer model
my $vase = Physics::Ellipsometry::VASE->new(layers => 1);

# Load experimental data (auto-detects Woollam format)
$vase->load_data('measurement.dat');

# Define an optical model
sub cauchy_model {
    my ($params, $x) = @_;
    my $wavelength = $x->(:,0);   # nm
    my $psi   = $params->(0) + $params->(1) / $wavelength**2;
    my $delta = $params->(2) + $params->(3) * $wavelength;
    return cat($psi, $delta)->flat;
}

$vase->set_model(\&cauchy_model);

my $fitted = $vase->fit(pdl [45, 1e4, 120, 0.01]);

# Plot results (requires PDL::Graphics::Gnuplot)
$vase->plot($fitted, output => 'fit.png');

DESCRIPTION

Physics::Ellipsometry::VASE provides a framework for fitting optical thin-film models to variable angle spectroscopic ellipsometry (VASE) data using the Levenberg-Marquardt algorithm.

Ellipsometry measures the change in polarization state of light reflected from a sample surface. The two measured quantities are Psi (related to the amplitude ratio of p- and s-polarized reflectances) and Delta (the phase difference). By fitting a physical model to these measurements across wavelength and angle of incidence, one can extract optical constants (refractive index, extinction coefficient) and film thicknesses.

The module handles:

  • Loading data in both simple whitespace-delimited format and the native J.A. Woollam VASE instrument format (auto-detected).

  • Automatic numerical Jacobian computation via relative-step finite differences.

  • Weighted fitting using measured uncertainties (sigma columns in Woollam files).

  • Multi-angle plotting of data and fit overlays via PDL::Graphics::Gnuplot.

CONSTRUCTOR

new

my $vase = Physics::Ellipsometry::VASE->new(%args);

Creates a new VASE analysis object.

layers (optional, default 1)

Number of thin-film layers in the optical model. Currently informational; the actual layer structure is encoded in the user-supplied model function.

model (optional)

A code reference for the model function. Can also be set later with "set_model".

METHODS

load_data

my $data = $vase->load_data($filename);

Reads ellipsometry data from $filename. The format is auto-detected:

Simple format

Whitespace-separated columns. Lines starting with # are comments; blank lines are skipped.

# Wavelength(nm)  Angle(deg)  Psi(deg)  Delta(deg)
400  70  45.0  120.0
410  70  44.5  121.0
Woollam VASE format

Recognised when line 2 starts with VASEmethod[. The four-line header is parsed and stored as object attributes:

$vase->{sample_name}    # line 1
$vase->{vase_method}    # VASEmethod[...] content
$vase->{original_file}  # Original[...] content
$vase->{units}          # line 4 (e.g. "nm")

Columns 5-6 (sigma_psi, sigma_delta) are extracted into $vase->{sigma} and automatically used as weights during fitting.

Returns a PDL piddle of shape (4, npts) where the columns are wavelength, angle, psi, delta.

set_model

$vase->set_model(\&my_model);

Sets the model function used for fitting. The function receives two arguments:

sub my_model {
    my ($params, $x) = @_;
    # $params - PDL piddle of fit parameters
    # $x      - PDL piddle of shape (npts, 2):
    #           column 0 = wavelength (nm)
    #           column 1 = angle of incidence (degrees)

    my $psi   = ...;  # compute psi   (npts values)
    my $delta = ...;  # compute delta (npts values)

    return cat($psi, $delta)->flat;   # concatenated 1-D piddle
}

The return value must be a flat piddle of length 2*npts with all psi values followed by all delta values.

fit

my $fitted_params = $vase->fit($initial_params);

Performs a Levenberg-Marquardt fit of the current model to the loaded data.

$initial_params is a PDL piddle of starting parameter values. Returns a piddle of optimised parameters.

After fitting, the following attributes are available:

$vase->{covar}  # covariance matrix (PDL)
$vase->{iters}  # number of LM iterations
$vase->{ym}     # model values at the fitted parameters

The fit uses relative-step finite differences for the numerical Jacobian (step size |p_i| * 1e-7 + 1e-10) and converges when the relative change in chi-squared falls below 1e-7, or after 300 iterations.

plot

$vase->plot($fit_params, %options);

Plots measured data with the model fit overlaid. Requires PDL::Graphics::Gnuplot (loaded on demand).

Options:

output

Filename for the plot image. The format is inferred from the extension: .png, .pdf, .svg, .eps. If omitted, an interactive window is opened.

title

Title string for the plot (default: "VASE Fit Results").

When multiple angles of incidence are present, each angle is plotted as a separate colour-coded series.

DATA FORMAT

Simple Format

# Wavelength(nm)  Angle(deg)  Psi(deg)  Delta(deg)
400  70  45.0  120.0

Woollam VASE Format

sample_name
VASEmethod[EllipsometerType=4, ...]
Original[filename.dat]
nm
400.000  70.000  45.000  120.000  0.010  0.020
...

Columns: wavelength, angle, psi, delta, sigma_psi, sigma_delta.

EXAMPLES

The examples/ directory in the distribution contains:

fit_linear.pl

Minimal example fitting a linear dispersion model.

vase_test_fit.pl

Cauchy thin-film model with complex Fresnel equations for Ta2O5 on Si.

vase_tauc_lorentz_fit.pl

Tauc-Lorentz oscillator model with numerical Kramers-Kronig integration.

DEPENDENCIES

PDL (≥ 2.0)
PDL::Fit::LM
PDL::NiceSlice
PDL::Graphics::Gnuplot (optional, for plotting)

SEE ALSO

PDL, PDL::Fit::LM, PDL::Graphics::Gnuplot

H. Fujiwara, Spectroscopic Ellipsometry: Principles and Applications, John Wiley & Sons, 2007.

G.E. Jellison and F.A. Modine, "Parameterization of the optical functions of amorphous materials in the interband region", Appl. Phys. Lett. 69, 371 (1996).

AUTHOR

Jovan Trujillo <jtrujil1 at asu.edu>

LICENSE AND COPYRIGHT

Copyright 2026 Jovan Trujillo.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. See https://dev.perl.org/licenses/ for details.

NAME

Physics::Ellipsometry::VASE - Variable Angle Spectroscopic Ellipsometry data fitting

VERSION

Version 0.01

SYNOPSIS

use PDL;
use PDL::NiceSlice;
use Physics::Ellipsometry::VASE;

my $vase = Physics::Ellipsometry::VASE->new(layers => 1);
$vase->load_data('data.dat');

sub my_model {
    my ($params, $x) = @_;
    my $a = $params->(0);
    my $b = $params->(1);
    my $c = $params->(2);
    my $d = $params->(3);
    my $wavelength = $x->(:,0);

    my $psi   = $a - $b * $wavelength;
    my $delta = $c + $d * $wavelength;

    return cat($psi, $delta)->flat;
}

$vase->set_model(\&my_model);

my $fit_params = $vase->fit(pdl [65, 0.05, 80, 0.1]);
print "Fitted: $fit_params\n";

DESCRIPTION

Physics::Ellipsometry::VASE provides Levenberg-Marquardt fitting of user-defined optical models to variable angle spectroscopic ellipsometry (VASE) data. It wraps PDL::Fit::LM and handles the bookkeeping of mapping between the simple user model interface and the lmfit calling convention, including automatic numerical computation of the Jacobian via finite differences.

Ellipsometry measures the change in polarization state of light reflected from a surface. The two measured quantities are Psi (amplitude ratio) and Delta (phase difference). This module fits models that predict both Psi and Delta simultaneously as a function of wavelength and angle of incidence.

DATA FORMAT

Input files should contain whitespace-separated columns:

# Wavelength(nm)  Angle(deg)  Psi(deg)  Delta(deg)
400  70  45.0  120.0
410  70  44.5  121.0

Lines beginning with # and blank lines are skipped.

MODEL FUNCTIONS

A model function receives two arguments and must return a single flattened PDL piddle:

sub model {
    my ($params, $x) = @_;

    # $params: PDL piddle of fit parameters
    # $x:      PDL piddle of shape (npoints, 2)
    #          $x->(:,0) = wavelength (nm)
    #          $x->(:,1) = angle of incidence (deg)

    my $psi   = ...;   # compute Psi  (npoints)
    my $delta = ...;   # compute Delta (npoints)

    return cat($psi, $delta)->flat;
}

The Jacobian (partial derivatives with respect to parameters) is computed automatically via numerical finite differences.

METHODS

new

my $vase = Physics::Ellipsometry::VASE->new(%args);

Constructor. Accepts:

layers

Number of layers in the optical model (default: 1).

model

Optional code reference to a model function.

load_data

$vase->load_data($filename);

Reads ellipsometry data from a whitespace-delimited file. Returns the loaded data as a PDL piddle.

set_model

$vase->set_model(\&model_func);

Sets the model function used for fitting.

fit

my $fitted_params = $vase->fit($initial_params);

Performs Levenberg-Marquardt fitting. $initial_params is a PDL piddle of initial guesses. Returns a PDL piddle of fitted parameters.

plot

$vase->plot($fit_params);
$vase->plot($fit_params, output => 'fit.png');
$vase->plot($fit_params, output => 'fit.pdf', title => 'My Fit');

Plots raw data points with model fit overlay in a two-panel layout (Psi on top, Delta on bottom). Requires PDL::Graphics::Gnuplot.

Options:

output

File path for saving the plot. Format is inferred from the extension (.png, .pdf, .svg, .eps). If omitted, displays an interactive window.

title

Overall plot title (default: VASE Fit Results).

DEPENDENCIES

PDL, PDL::Fit::LM, PDL::NiceSlice

PDL::Graphics::Gnuplot is required only for the plot method.

AUTHOR

jtrujil1

LICENSE AND COPYRIGHT

This software is copyright (c) 2026.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.