virgil.grid_fit
Grid searches. Contrast limits built on them are in virgil.limits.
Grid searches over model parameters.
Grids are built with indexing="ij": every output has one axis per grid
key, in the order of grid. For {"dra", "ddec", ...} axis 0 is
dra (East offset) and axis 1 is ddec (North offset), so 2D maps need
a transpose to be shown as images with North up;
plot_grid_map handles this.
The functions that optimize a flux at every grid position find it as the one
key whose last part is flux (flux, comp.flux, ...), unless
flux_param says otherwise. Fluxes are relative to the primary (at flux
1), so for a companion the flux is its companion/primary flux ratio; see
virgil.limits for converting to contrast or Δmag.
Contrast limits (Ruffio, Absil) are in virgil.limits.
LogUniform
Bases: NamedTuple
Log-uniform (scale-invariant) prior on the companion flux ratio.
p(f) = 1 / (f ln(f_max / f_min)) on f_min <= f <= f_max. The flux
ratio is a scale parameter spanning decades, so this is the invariant
measure of the scaling group (the Jeffreys prior under that group
action), not the root-Fisher-information prior of the linearized
likelihood, which has constant Fisher information in f and so would
be flat. It is improper without bounds, so the evidence needs
0 < f_min < f_max (finite), in the units of
the flux (companion/primary).
f_min
instance-attribute
f_max
instance-attribute
Gaussian
Bases: NamedTuple
Gaussian prior N(mean, sd**2) on the companion flux ratio.
Gaussian-prior evidence (a computational approximation; f may go
negative): the prior has support on negative flux, so its evidence is
only a convenient closed form. Prefer LogUniform.
mean
instance-attribute
sd
instance-attribute
likelihood_grid(model, data, grid, *, batch_size=None)
Evaluate the log likelihood at every point of a parameter grid.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
SourceModel or class
|
Template model whose parameters at the paths in |
required |
data
|
OIData
|
Data to fit. |
required |
grid
|
dict[str, array - like]
|
Grid axes, as a mapping from parameter name or path to 1D values
(e.g. |
required |
batch_size
|
int
|
Number of grid points evaluated at once. By default, enough for about 220 model visibilities on a CPU and 223 on other backends (GPU, TPU), and at least 256. Larger can be faster for small data; smaller bounds memory for large models. |
None
|
Returns:
| Type | Description |
|---|---|
array - like
|
Log likelihood with shape
|
optimized_likelihood_grid(model, data, grid, *, flux_param=None, batch_size=None)
optimized_flux_grid(model, data, grid, *, flux_param=None, batch_size=None)
linear_flux_grid(model, data, grid, *, flux_param=None, batch_size=None, n_iter=0, prior=None)
Linearized best-fit companion flux at every grid position, in closed form.
A fast first pass for companion searches, beside the iterative
optimized_flux_grid, and the
equivalent of fouriever's linear contrast map (lincmap). For a faint
companion (flux f much smaller than 1) the whitened residuals
r of virgil's likelihood are linear in f at fixed position:
r(f) = r(0) + f g, where g = dr/df at f = 0 is computed
exactly by forward-mode automatic differentiation of the model (no
finite difference, no hand-derived closure-phase derivative). The
weighted least-squares solution is then
f_hat = -(g . r(0)) / (g . g), sigma_f = (g . g) ** -0.5,
which is (gᵀ C⁻¹ (d - m₀)) / (gᵀ C⁻¹ g) with C the data
covariance, because r is already whitened: correlated closure phases
are handled exactly as in the likelihood
(whitened_residuals), and
every observable in the data (|V| or V², and phases) contributes.
One model evaluation with its derivative per grid position, and no
optimizer.
f_hat is not constrained to be positive (as with
optimized_flux_grid and fouriever's lincmap), so noise gives
negative values with SNR of either sign. Unlike fouriever, whose
lincmap returns the variance 1 / (g . g) (and warns not to
trust it), sigma_f here is the standard deviation.
Limitation, and n_iter. With n_iter=0 the linearization
holds only for f much smaller than 1. The
closure phase of a binary scales as f only to first order, with
corrections of order f**2 (and f times the |V| change for
amplitudes), so for a bright companion (for example f ~ 0.3)
f_hat is biased, by tens of percent, and sigma_f is
unreliable. n_iter Gauss–Newton steps soften this: each relinearizes
at the current f_hat per pixel (g = dr/df at f_hat, then
f_hat <- f_hat - (g . r(f_hat)) / (g . g)), and sigma_f comes
from the final g, so a few steps (3 at f ~ 0.3) reach
the optimizer's f_hat and the Laplace sigma_f, at
n_iter + 1 model evaluations per pixel. The steps are not
safeguarded, so for companions far brighter than the primary or
strongly non-linear residuals they can fail to converge; use
optimized_flux_grid to refine
candidates. At
Δ-phase residuals of order 1 rad the phase wrapping is not
linear either. A companion at a position where g is nearly zero
(for example at a null of the baselines) has a large sigma_f
and so a small SNR.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
SourceModel or class
|
Template model whose parameters at the paths in |
required |
data
|
OIData
|
Data to fit. |
required |
grid
|
dict[str, array - like]
|
Grid axes, as for
|
required |
flux_param
|
str
|
The key of |
None
|
batch_size
|
int
|
Number of grid points evaluated at once, by default enough for
a fixed number of model visibilities; see
|
None
|
n_iter
|
int
|
Number of Gauss–Newton refinement steps after the first
linearization at |
0
|
prior
|
numpyro LogUniform or Normal
|
Prior on the flux ratio Recommended:
(Luger, Foreman-Mackey & Hogg 2017, arXiv:1710.11136). |
None
|
Returns:
| Type | Description |
|---|---|
LinearFluxGrid
|
A named tuple, always of the same type, whose fields are arrays with
one axis per coordinate key (axis 0 is the first, e.g.
Because there are six fields, unpack by attribute ( |
Examples:
>>> grid = {
... "dra": np.linspace(-300.0, 300.0, 61),
... "ddec": np.linspace(-300.0, 300.0, 61),
... "flux": np.array([1e-3]), # ignored: only names the parameter
... }
>>> res = linear_flux_grid(
... BinaryModelCartesian, data, grid
... )
>>> i, j = np.unravel_index(
... np.nanargmax(res.snr), res.snr.shape
... )
laplace_flux_uncertainty_grid(model, data, grid, flux=None, *, flux_param=None, batch_size=None)
Laplace uncertainty of the flux at every grid position.
At each position the coordinates are held fixed and the uncertainty is the inverse square root of the curvature of the negative log likelihood along the flux.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
SourceModel or class
|
Template model or model class, as for :func: |
required |
data
|
OIData
|
Data to fit. |
required |
grid
|
dict[str, array - like]
|
Grid axes, as for :func: |
required |
flux
|
array - like
|
Flux at which to evaluate the curvature, with one axis per
coordinate key. By default this is the best fit from
:func: |
None
|
flux_param
|
str
|
The key of |
None
|
batch_size
|
int
|
Number of grid points evaluated at once, by default enough for
a fixed number of model visibilities; see
|
None
|
Returns:
| Type | Description |
|---|---|
array - like
|
One-sigma flux uncertainty, with one axis per coordinate key. It is NaN where the curvature is not positive (the flux is not at a likelihood maximum). |
best_grid_point(loglike_grid, grid)
Return the grid point with the highest log likelihood.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
loglike_grid
|
array - like
|
Output of |
required |
grid
|
dict[str, array - like]
|
The grid axes used to compute |
required |
Returns:
| Type | Description |
|---|---|
dict[str, float]
|
|