Reading OIFITS files

Basic usage

readoifits loads an OIFITS file and returns a 2D array of OIdata{T} indexed as [nwavbin, ntimebin]. The simplest call reads everything into a single bin:

using OITOOLS
data = readoifits("mystar.oifits")        # returns Array{OIdata{Float64}, 2}
data[1]                                   # the single OIdata bin

Use T=Float32 to halve memory usage for large datasets:

data = readoifits("mystar.oifits"; T=Float32)

Keyword reference

KeywordDefaultDescription
Target selection
targetname""Select a single target by name (all targets if empty)
Spectral / temporal binning
spectralbin[[]]Vector of [λ_min, λ_max] windows (metres)
temporalbin[[]]Vector of [mjd_min, mjd_max] windows
polychromaticfalseOne spectral bin per channel (overrides spectralbin)
merge_oi_wavelengthfalseDeduplicate compatible OI_WAVELENGTH tables (polychromatic mode)
splittingfalseForce multi-bin mode even with default bin vectors
get_specbin_filetrueAuto-derive spectral bins from the file
get_timebin_filetrueAuto-derive temporal bins from the file
Observable selection
use_vistrueLoad complex visibilities
use_v2trueLoad squared visibilities
use_t3trueLoad triple products
use_fluxtrueLoad flux spectra
Quality filtering
filter_bad_datatrueApply quality cuts (flags, NaN, SNR, range) on load
force_full_visfalseRequire both visamp and visphi to be valid
force_full_t3falseRequire both t3amp and t3phi to be valid
cutoff_minv2-1Minimum V² (points below are discarded)
cutoff_maxv22.0Maximum V²
cutoff_mint3amp-1.0Minimum T3 amplitude
cutoff_maxt3amp1.5Maximum T3 amplitude
filter_v2_snr_threshold0.01Minimum |V²/σ| to keep
special_filter_diffvisfalseKeep only vis points common across all spectral bins
UV deduplication
redundance_removetrueMerge UV points closer than uvtol
uvtol200.0Merge radius in cycles/rad (B/λ)
Output
warntruePrint warnings about non-standard files
verbosetruePrint summary of loaded tables
TFloat64Element type for all numeric arrays

The OIdata struct

Each OIdata{T} bin holds flat vectors for every observable:

FieldDescription
v2, v2_err, v2_baseline, v2_lam, v2_mjdSquared visibilities
t3phi, t3phi_err, t3amp, t3amp_errClosure phases and triple amplitudes
visamp, visamp_err, visphi, visphi_errComplex visibility amplitude/phase
flux, flux_err, flux_lam, flux_sta_indexFlux spectra (0 = calibrated)
uv, uv_lam, uv_baselineUV coverage (2×nuv matrix, λ in metres)
indx_v2, indx_t3_1/2/3, indx_visIndices mapping observables → UV points
sta_name, tel_name, sta_indexStation / telescope names
mean_mjdMean MJD of the bin (always Float64)
nv2, nt3phi, nt3amp, nvisamp, nvisphi, nflux, nuvCounts

Call display(data) or display(data[1]) to print a compact summary.

Correlated data (OI_CORR)

OITOOLS reads OIFITSv2 OI_CORR tables and stores the correlation matrix and per-point indices in the OIdata struct:

FieldDescription
v2_corr, v2_corr_idxV² correlation matrix and per-point index
t3phi_corr, t3phi_corr_idxClosure-phase correlation
t3amp_corr, t3amp_corr_idxTriple-amplitude correlation
visamp_corr, visamp_corr_idxVisibility amplitude correlation
visphi_corr, visphi_corr_idxVisibility phase correlation
flux_corr, flux_corr_idxFlux correlation

*_corr_idx[i] == 0 means point i has no associated correlation row.

Multi-baseline correlation blocks (e.g. GRAVITY, where NDATA > nwave) are automatically detected and expanded so that each baseline within a timestamp maps to the correct slice of the correlation matrix.

See example_chi2_correlated.jl for a worked example computing whitened (correlated) chi-squared from GRAVITY data.

Selecting a target

Files with multiple targets require a targetname filter:

data = readoifits("multi_target.oifits"; targetname="Betelgeuse")

Use list_oifits_targets("multi_target.oifits") to see all available targets.

Polychromatic (per-channel) mode

To keep each spectral channel as a separate bin, pass polychromatic=true. The bin boundaries are derived automatically from midpoints between adjacent channel centres, so each stored λ value falls in exactly one bin:

data = readoifits("my_spectrum.oifits"; polychromatic=true)
# data is nchannels×1; data[k,1] is the k-th channel bin

To specify bins manually:

spectralbin = [[1.6e-6, 1.8e-6], [2.0e-6, 2.4e-6]]   # two K-band bins
data = readoifits("my_spectrum.oifits"; spectralbin)

Similarly for time bins:

temporalbin = [[58000.0, 58100.0], [58200.0, 58300.0]]
data = readoifits("mystar.oifits"; temporalbin)

Quality filtering

filter_bad_data=true (the default) removes flagged points and applies sanity cuts. Key thresholds can be adjusted:

data = readoifits("mystar.oifits";
    filter_bad_data        = true,
    cutoff_minv2           = -0.05,
    cutoff_maxv2           = 1.05,
    cutoff_mint3amp        = -0.1,
    cutoff_maxt3amp        = 1.5,
    filter_v2_snr_threshold = 1.0)   # require SNR > 1 for V²

To selectively disable loading of specific observable types:

data = readoifits("mystar.oifits"; use_flux=false, use_vis=false)

Verbose output

By default readoifits prints a data summary. Pass verb=false to suppress all output, or verbose=true to additionally print OI_VIS amplitude/phase type information (AMPTYP/PHITYP):

data = readoifits("mystar.oifits"; verbose=true)   # print table summary
data = readoifits("mystar.oifits"; warn=false)      # suppress warnings

UV deduplication

Redundant UV points (within uvtol cycles/rad, i.e. B/λ; default 200) are merged:

data = readoifits("mystar.oifits"; redundance_remove=true, uvtol=100.0)

Disable with redundance_remove=false.

Post-load filtering

After loading, use set_data_filter + filter_data to apply additional cuts without re-reading the file:

idx = set_data_filter(data[1];
    filter_bad_data      = true,
    baseline_range       = [10.0e6, 300.0e6],
    wav_range            = [1.6e-6, 1.8e-6])
data_filtered = filter_data(data[1], idx)

Reading multiple files

Multi-epoch — each file is one epoch; returns a Matrix{OIdata}:

files = ["epoch1.oifits", "epoch2.oifits", "epoch3.oifits"]
data = readoifits_multiepochs(files)   # 1×3 Matrix{OIdata}

Multi-colour — each file is a different waveband; use readoifits_multiepochs with one file per band:

files = ["H_band.oifits", "K_band.oifits"]
data = readoifits_multiepochs(files)   # 1×2 Matrix — one column per file

Error inflation

oifits_prep inflates error bars in-place, which is useful for preventing underestimated uncertainties from dominating the fit:

oifits_prep(data[1];
    min_v2_err_add   = 0.01,    # additive floor for V² errors
    min_v2_err_rel   = 0.02,    # relative floor (2% of |V²|)
    v2_err_mult      = 1.0,     # multiplicative scaling
    min_t3phi_err_add = 1.0,    # additive floor for T3φ errors (degrees)
    t3phi_err_mult   = 1.0,
    quad             = false)   # true = combine in quadrature

By default errors are replaced when the floor exceeds the original; set quad=true to add floors in quadrature instead.

ASPRO-compatible FITS headers

updatefits_aspro adds WCS metadata (pixel scale, reference pixel) to a FITS image so that ASPRO can read it:

updatefits_aspro("input.fits", "output.fits", 0.1)   # pixsize in mas

OIFITSv1 compatibility

Files following the older OIFITS v1 standard (0-based station indices) are loaded automatically. A warning is printed indicating that station indices have been reindexed from 1 internally.