Set up the FOV and number of pixels of the `nifty` space which defines the image plane.
%% Cell type:code id: tags:
``` python
x_fov,y_fov=300,300# Field of view in x and y directon in myas
x_npix,y_npix=256,256# Number of pixels
dx=rve.str2rad(f'{x_fov}muas')/x_npix
dy=rve.str2rad(f'{y_fov}muas')/y_npix
space=ift.RGSpace((x_npix,y_npix),(dx,dy))
```
%% Cell type:markdown id: tags:
Model of the sky brightness distribution
----------------------------------------
The sky model is going to be a log-normal random process (the log-brightness is Gaussian distributed). As the prior correlation structure of the log-brightness is unkown, it will be generated using a `CorrelatedField` model and the power-spectrum is inferred along with the realization.
%% Cell type:code id: tags:
``` python
# Hyperparameters (mean and std pairs) for prior models of parameters
args={# Overall offset from zero of Gaussian process
'offset_mean':-np.log(space.scalar_dvol)-10.,
# Variability of inferred offset amplitude
'offset_std':(3.,1.),
# Amplitude of field fluctuations
'fluctuations':(1.5,0.5),
# Exponent of power law power spectrum component
'loglogavgslope':(-4.,0.5),
# Amplitude of integrated Wiener process power spectrum component
'flexibility':(0.3,.1),
# How ragged the integrated Wiener process component is
'asperity':None# Passing 'None' disables this part of the model
sky_model=ift.exp(log_signal)# Exponentiate to recieve a log-normal distributed sky model
pspec=log_signal.power_spectrum# Save the model of the power-spectrum for visualization
```
%% Cell type:markdown id: tags:
Prior samples
-------------
To get a feeling for the prior variability of the sky model we generate several random realizations of the process and visualize them. The power-spectra, generated for each process realization, are depicted in the last panel.
%% Cell type:code id: tags:
``` python
pl=ift.Plot()
pspecs=[]
for_inrange(8):
mock=ift.from_random(sky_model.domain)
pl.add(sky_model(mock),cmap='afmhot')
pspecs.append(pspec.force(mock))
pl.add(pspecs)
pl.output()
```
%% Cell type:markdown id: tags:
Alternatively, one can define a log-normal process with a fixed, user-specified spectrum. Note that in case the spectrum does not match the true underlying data-generating process, this may yield suboptimal results!
Setup a mock VLBI imaging task using the `InterferometryResponse` of `resolve`. The `mock_observation` contains all information relevant to set up the likelihood, including visibility data, uv-coordinates, and the noise levels of each measurement. The `measurement_sky` contains all relevant information regarding the prior model of the sky brightness distribution. The additional parameters passed to the `InterferometryResponse` control the accuracy and behaviour of the `wgridder` used within `resolve` which defines the response function.
The `likelihood` together with the `sky_model` fully specify a Bayesian inverse problem and imply a posterior probabiltiy distribution over the degrees of freedom (DOF) of the model. This distribution is in general a high-dimensional (number of pixels + DOF of power spectrum) and non-Gaussian distribution which prohibits analytical integration. To access its information and compute posterior expectation values numerical approximations have to be made.
`nifty` provides multiple ways of psterior approximation, with Variational Inference (VI) being by far the most frequently used method. In VI the posterior distribution is approximated with another distribution by minimizing their respective forward Kullbach-Leibler divergence (KL). In the following, the Geometric VI method is employed which utilizes conceps of differential geometry to provide a local estimate of the distribution function.
Its numerical implementation (`ift.optimize_kl`) consists of a repeated and successive re-approximation of the VI objective function (the KL) via a stochastic estimate. This estimate is generated using the at the time best available approximation of the posterior, and then the KL gets minimized to further improve it. The resulting algorithm cosists of a repeated re-generation of novel samples for the estimate and a successing optimization thereof until convergence is reached.
The internal steps of `ift.optimize_kl` invoke the approximate solution of multiple interdependent optimization problems:
- For sample generation, a linear system of eqations is approximated using the `ConjugateGradient` (CG) method
- Furthermore, the sample generation invokes a non-linear optimization problem approximated using the `NewtonCG` method
- Finally, the approximative distribution is optimized by minimizing the KL between the true posterior and the approximation. This again invokes a non-linear optimization problem approximated with `NewtonCG`.
%% Cell type:markdown id: tags:
Posterior visualization
-----------------------
Before we set run the minimization routine, we set up a `plotting_callback` function for visualization. Note that additional information and plots regarding the reconstruction are generated during an `ift.optimize_kl` run and stored in the folder passed to the `output_directory` argument of `ift.optimize_kl`
The final output of `ift.optimize_kl` is a collection of approximate posterior samples and is provided via an instance of `ift.ResidualSampleList`. A `SampleList` provides a variety of convenience functions such as:
-`average`: to compute samples averages
-`sample_stat`: to get the approximate mean and variance of a model