Model Fitting

Parametric models

FunctionDescription
parse_model(dict, fit_params)Compile a flat parameter dict into a FlatModel
model_to_vis(model, x, uv)Evaluate complex visibilities for a model (alias: eval_model)
eval_model_grad(model, x, uv)Evaluate visibilities + Jacobian
display_model(dict, fit_params)Pretty-print model parameters
fit_model(dict, fit_params, data)Fit model via gradient descent (NLopt)
fit_model_lsqfit(dict, fit_params, data)Fit model via Levenberg-Marquardt (LsqFit)
fit_model_ultranest(dict, fit_params, data)Fit model via nested sampling (UltraNest)
model_to_obs(model, x, data)Compute observables (V², T3amp, T3phi) from a model
model_to_residuals(model, x, data)Compute normalised residuals (model - data) / error
model_to_chi2(model, x, data)Compute weighted chi² (alias: chi2_flat)
model_to_chi2_fg(model, x, data)Compute chi² + gradient (alias: chi2_flat_fg)
model_to_image(model, x; nx, pixsize)Synthesize a model image via inverse FFT
model_to_sed(model, x, wl_grid)Compute spectral energy distribution
resample_data(data)Bootstrap resample data (add Gaussian noise from error bars)
OITOOLS.parse_modelFunction
parse_model(param_dict, fit_params; nB_workspace=100) -> FlatModel

Compile a flat parameter dict into a FlatModel ready for evaluation.

Arguments

paramdict : Dict{String,Any} with "component,param" keys. Values may be Float64 (fixed or free) or String (expression). Special string key "component,profile" triggers the Hankel pathway. fitparams : Vector{String} of keys to optimize (must be numeric in paramdict). nBworkspace : Pre-allocated baseline grid size for HankelWorkspace buffers. Should be ≥ the number of baselines you will evaluate at.

Returns

A FlatModel whose evalmodel / evalmodel_grad methods can be called in a loop with zero Dict allocation.

Example

param = Dict(
    "star,ud"      => 0.8,
    "star,f"       => 0.6,
    "ring,profile" => "exp(-(\$R / \$scale)^2 / 2)",
    "ring,scale"   => 1.5,
    "ring,udout"   => 12.0,
    "ring,f"       => "1 - \$star,f",
)
fit_params = ["star,ud", "star,f", "ring,scale"]
model = parse_model(param, fit_params)
source
OITOOLS.model_to_visFunction
model_to_vis(model, x, uv; wl=nothing, mjd=nothing, n=0)

Alias for eval_model. Compute complex visibilities from a parametric model, for consistency with the model_to_obs / model_to_chi2 family.

source
OITOOLS.eval_modelFunction
eval_model(model, x, uv; wl=nothing, mjd=nothing, n=0) -> Vector{ComplexF64}

Evaluate the model visibility at the given parameter vector x and baselines uv.

Arguments

model : FlatModel from parsemodel x : current free-parameter values, length = length(model.fitparams) uv : 2×N matrix of (u,v) spatial frequencies in cycles/rad wl : wavelength per UV point (metres), length N — enables WL in expressions mjd : MJD per UV point, length N — enables MJD in expressions n : Bessel order for Hankel components (default 0)

Returns

V : complex visibility vector, length N

source
OITOOLS.eval_model_gradFunction
eval_model_grad(model, x, uv; wl=nothing, mjd=nothing, n=0) -> (V, J)

Evaluate model visibility and its Jacobian w.r.t. x.

Returns

V : complex visibility vector (length nB) J : Jacobian, Matrix{ComplexF64} of shape (nB, length(x))

Uses ForwardDiff for the resolver and analytic components; for Hankel components uses the cached-K chain rule via hankelvisfwd! + pullback. This is more efficient than naive ForwardDiff through the full Hankel loop when nB is large, since Bessel evaluations are shared across parameters.

source
OITOOLS.display_modelFunction
display_model(param_dict, fit_params; lb, ub)

Print a human-readable summary of the model setup, grouped by component. Shows each parameter's value (or expression), whether it is free or fixed, and its bounds. Warns about common mistakes (value out of bounds, missing bounds, flux fractions that don't sum to 1).

Call this before fit_model / fit_model_ultranest to verify your setup.

source
OITOOLS.fit_modelFunction
fit_model(param_dict, fit_params, data; kwargs...) -> FitResult

Fit a parametric model to interferometric data using NLopt.

Arguments

  • param_dict::Dict{String} — flat parameter dictionary (values are numbers or expression strings)
  • fit_params::Vector{String} — names of the free parameters to optimize
  • data::OIdata — interferometric data

Keywords

  • lb, ubDict{String,Float64} of lower/upper bounds per parameter (default: ±Inf)
  • weights — observable weights [V2, T3amp, T3phi, visamp, visphi, flux, diffphase]
  • priors — Vector of (expr_str, target, sigma) tuples for Gaussian penalties
  • method — NLopt algorithm (default :LD_LBFGS; use :LN_NELDERMEAD for gradient-free)
  • maxeval — maximum function evaluations (default 2000)
  • ftol_rel, xtol_rel — convergence tolerances
  • vonmises — use von Mises statistic for T3phi
  • nB_workspace — Hankel workspace size (default: nuv from data)
  • verb — print per-evaluation chi2 breakdown
source
OITOOLS.fit_model_lsqfitFunction
fit_model_lsqfit(param_dict, fit_params, data; kwargs...) -> LsqFitResult

Fit a parametric model to interferometric data using Levenberg-Marquardt (LsqFit.jl). Returns parameter covariance and 1σ uncertainties.

Uses the analytic Jacobian from residuals_flat_jac (Wirtinger chain rule through the complex visibility Jacobian), so no finite-difference overhead.

Arguments

  • param_dict::Dict{String} — flat parameter dictionary
  • fit_params::Vector{String} — names of the free parameters to optimize
  • data::OIdata — interferometric data

Keywords

  • lb, ubDict{String,Float64} of lower/upper bounds per parameter
  • weights — observable weights [V2, T3amp, T3phi, visamp, visphi, flux, diffphase]
  • vonmises — use von Mises statistic for T3phi
  • nB_workspace — Hankel workspace size
  • maxIter — maximum iterations (default 200)
  • verb — print per-evaluation chi2 breakdown
source
OITOOLS.fit_model_ultranestFunction
fit_model_ultranest(param_dict, fit_params, data; kwargs...) -> UltraNestResult

Fit a parametric model to interferometric data using UltraNest nested sampling.

Requires PyCall and the Python ultranest package.

Arguments

  • param_dict::Dict{String} — flat parameter dictionary
  • fit_params::Vector{String} — names of the free parameters
  • data::OIdata — interferometric data

Keywords

  • lb, ubDict{String,Float64} of lower/upper bounds (REQUIRED for all fit_params)
  • weights — observable weights [V2, T3amp, T3phi, visamp, visphi, flux, diffphase]
  • vonmises — use von Mises statistic for T3phi
  • nB_workspace — Hankel workspace size
  • min_num_live_points — minimum number of live points (default 400)
  • cluster_num_live_points — live points for clustering (default 100)
  • num_bootstraps — number of bootstraps for evidence (default 30)
  • use_stepsampler — use RegionSliceSampler (default false)
  • nsteps — steps per slice for stepsampler (default 400)
  • frac_remain — termination fraction (default 0.001)
  • log_interval — logging interval (default 100)
  • verb — print progress (default true)
  • cornerplot — show corner plot (default true)
source
OITOOLS.model_to_obsFunction
model_to_obs(model, x, data) -> (v2, t3amp, t3phi, visamp, visphi)

Evaluate a FlatModel at parameter vector x and return the model observables matching the data structure.

Returns a NamedTuple with fields v2, t3amp, t3phi (degrees), visamp, visphi (degrees). Empty vectors are returned for observable types not present in data.

source
OITOOLS.model_to_residualsFunction
model_to_residuals(model, x, data)

Compute normalised residuals (model - data) / error for each observable type. Returns a NamedTuple with fields v2, t3amp, t3phi, visamp, visphi. Phase residuals (t3phi, visphi) are wrapped to [-180, 180] before dividing by error.

source
OITOOLS.model_to_chi2Function
model_to_chi2(model, x, data; weights=[1,1,1,0,0,0,0], verb=false, vonmises=false)

Alias for chi2_flat. Compute the weighted chi-squared of a parametric model against data, for consistency with the model_to_obs / model_to_vis family.

source
OITOOLS.model_to_chi2_fgFunction
model_to_chi2_fg(model, x, data; weights=[1,1,1,0,0,0,0], verb=false, vonmises=false)

Alias for chi2_flat_fg. Compute chi-squared and its gradient w.r.t. x, for consistency with the model_to_obs / model_to_vis family.

source
OITOOLS.model_to_imageFunction
model_to_image(model, x; nx=256, pixsize=0.1, oversample=1, normalize=true, wl=nothing)
    -> Matrix{Float64}

Synthesise an image from a FlatModel at parameter vector x.

The image is computed by evaluating the model visibility on the 2-D FFT frequency grid and applying an inverse real FFT (irfft), which exploits the Hermitian symmetry V(-u,-v) = conj(V(u,v)) to halve the number of visibility evaluations.

Arguments

  • model::FlatModel — compiled model from parse_model
  • x::AbstractVector — current free-parameter values

Keywords

  • nx — image size in pixels (default 256)
  • pixsize — pixel size in mas (default 0.1)
  • oversample — oversampling factor (default 1)
  • normalize — normalize image to unit sum (default true)
  • wl — wavelength in microns (scalar); enables $WL in spectrum expressions

Returns

imgnx × nx Matrix{Float64}

source
OITOOLS.model_to_sedFunction
model_to_sed(model, x, wl_grid) -> (total, components)

Evaluate the spectral energy distribution of a FlatModel by computing V(u=0, v=0) at each wavelength — the zero-baseline visibility equals the total flux.

Per-component fluxes are obtained by resolving the f / spectrum parameters at each wavelength.

Arguments

  • model::FlatModel — compiled model from parse_model
  • x::AbstractVector — current free-parameter values
  • wl_grid — wavelength array in microns

Returns

  • total::Vector{Float64} — total flux at each wavelength (= V(0,0))
  • components::Dict{String,Vector{Float64}} — per-component flux
source
OITOOLS.resample_dataFunction
resample_data(data::OIdata)

Create a bootstrapped copy of the data by adding Gaussian noise (drawn from the error bars) to the observables. Useful for bootstrap uncertainty estimation.

source
TypeDescription
FitResultResult from fit_model (fields: x_opt, chi2r, model, ...)
LsqFitResultResult from fit_model_lsqfit (adds stderror, covar, converged)
UltraNestResultResult from fit_model_ultranest (adds logz, logzerr, posterior)

Visibility functions

Analytic visibility functions for standard source geometries. All take baseline spatial frequency arguments and return complex visibilities.

FunctionModel
visibility_ud(b, diam)Uniform disk
visibility_ldlin(b, diam, u)Linear limb-darkened disk
visibility_ldquad(b, diam, u, w)Quadratic limb-darkened disk
visibility_ldquad_alt(b, diam, u, w)Quadratic LD disk (alternative convention)
visibility_ldpow(b, diam, alpha)Power-law limb-darkened disk
visibility_ldsquareroot(b, diam, u, w)Square-root limb-darkened disk
visibility_annulus(b, din, dout)Uniform annulus
visibility_ellipse_uniform(u, v, a, b, pa)Uniform ellipse
visibility_ellipse_quad(u, v, a, b, pa, c1, c2)Quadratic LD ellipse
visibility_thin_ring(b, diam)Infinitely thin ring
visibility_Gaussian_ring(b, diam, fwhm)Gaussian ring
visibility_Gaussian_ring_az(...)Gaussian ring with azimuthal modulation
visibility_Lorentzian_ring(b, diam, fwhm)Lorentzian ring
visibility_GaussianLorentzian_ring_az(...)Gaussian-Lorentzian ring with azimuthal modulation