Simple Point Source Example#

This tutorial shows you hwo to work with pylira using a simple simulated point source and Gaussian shaped point spread function.

We first define the required imports:

[1]:
%matplotlib inline
import copy
import numpy as np
import matplotlib.pyplot as plt
from regions import CirclePixelRegion, PixCoord
from multiprocessing import Pool

from pylira.data import point_source_gauss_psf, gauss_and_point_sources_gauss_psf
from pylira.utils.plot import plot_example_dataset, plot_hyperpriors_lira
from pylira import LIRADeconvolver, LIRADeconvolverResult, LIRASignificanceEstimator

random_state = np.random.RandomState(148)

Dataset#

Then we can use the method point_source_gauss_psf to get a pre-defined test dataset:

[2]:
data = point_source_gauss_psf(random_state=random_state)
print(data.keys())
dict_keys(['counts', 'psf', 'exposure', 'background', 'flux'])

The data variable is a dict containing the counts, psf, exposure, background and ground truth for flux. We can illustrate the data using:

[3]:
plot_example_dataset(data)
../../../../_images/pylira_user_tutorials_notebooks_point_source_5_0.png

Configure and Run Deconvolution#

Next we define the LIRADeconvolver class, which holds the configuration the algorithm will be run with:

[4]:
alpha_init = 0.1 * np.ones(np.log2(data["counts"].shape[0]).astype(int))

dec = LIRADeconvolver(
    alpha_init=alpha_init,
    n_iter_max=5_000,
    n_burn_in=200,
    fit_background_scale=False,
    random_state=random_state
)

We can print the instance to see the full configuration:

[5]:
print(dec)
LIRADeconvolver
---------------

    alpha_init           : [0.1, 0.1, 0.1, 0.1, 0.1]
    n_iter_max           : 5000
    n_burn_in            : 200
    fit_background_scale : False
    save_thin            : True
    ms_ttlcnt_pr         : 1
    ms_ttlcnt_exp        : 0.05
    ms_al_kap1           : 0.0
    ms_al_kap2           : 1000.0
    ms_al_kap3           : 3.0

Now we can also visualize the hyperprior distribution of the alpha parameter:

[6]:
plot_hyperpriors_lira(
    ncols=1,
    figsize=(8, 5),
    alphas=np.linspace(0, 0.3, 100),
    ms_al_kap1=0,
    ms_al_kap2=1000,
    ms_al_kap3=3
);
../../../../_images/pylira_user_tutorials_notebooks_point_source_11_0.png

Now we have to define the initial guess for the flux and add it to the data dictionary. For this we use the reserved "flux_init"key:

[7]:
data["flux_init"] = random_state.gamma(10, size=data["counts"].shape)

Finally we can run the LIRA algorithm using .run():

[8]:
%%time
result = dec.run(data)
CPU times: user 1min 50s, sys: 469 ms, total: 1min 50s
Wall time: 1min 50s

Results and Diagnosis#

To check the validity of the result we can plot the posterior mean:

[9]:
result.plot_posterior_mean(from_image_trace=True)
../../../../_images/pylira_user_tutorials_notebooks_point_source_17_0.png

As well as the parameter traces:

[10]:
result.plot_parameter_traces()
/home/docs/checkouts/readthedocs.org/user_builds/pylira/envs/latest/lib/python3.7/site-packages/numpy/core/_methods.py:230: RuntimeWarning: invalid value encountered in subtract
  x = asanyarray(arr - arrmean)
../../../../_images/pylira_user_tutorials_notebooks_point_source_19_1.png

We can also plot the parameter distributions:

[11]:
result.plot_parameter_distributions()
../../../../_images/pylira_user_tutorials_notebooks_point_source_21_0.png

And pixel traces in a given region, to check for correlations with neighbouring pixels:

[12]:
result.plot_pixel_traces_region(center_pix=(16, 16), radius_pix=2);
../../../../_images/pylira_user_tutorials_notebooks_point_source_23_0.png

Significance Estimation#

The signifiance estimation follows the method proposed by Stein et al. 2015.

Null Hypothesis Simulations#

First we simulate (“fake”) observations for the null hypothesis: in this case we assume the null hypothesis includes the background only:

[13]:
# number of simulations
n_iter = 10

# reduce number of iterations for LIRA
dec.n_iter_max = 1_000
[14]:
datasets = []
data_null = copy.deepcopy(data)

for idx in range(n_iter):
    data_null["counts"] = random_state.poisson(data["background"])
    data_null["flux_init"] = random_state.gamma(10, size=data["counts"].shape)
    datasets.append(data_null)
[15]:
%%time
with Pool(processes=8) as pool:
    results = pool.map(dec.run, datasets)
CPU times: user 259 ms, sys: 137 ms, total: 396 ms
Wall time: 2min 45s

Define Regions of Interest#

[16]:
# Region of interest for the source
region_src = CirclePixelRegion(
    center=PixCoord(16, 16),
    radius=2
)

# Some control region
region_bkg = CirclePixelRegion(
    center=PixCoord(23, 8),
    radius=5
)

labels = np.zeros((32, 32))

for idx, region in enumerate([region_src, region_bkg]):
    mask = region.to_mask()
    labels += (idx + 1) * mask.to_image(shape=labels.shape)
[17]:
plt.imshow(labels)
plt.colorbar();
../../../../_images/pylira_user_tutorials_notebooks_point_source_30_0.png

Estimate and Visualize Distributions of \(\xi\)#

First we instantiate the LIRASignificanceEstimator with the result obtained before, the results from the null hypothesis simulations and the label image:

[18]:
est = LIRASignificanceEstimator(
    result_observed_im=result,
    result_replicates=results,
    labels_im=labels
)

Now we first estimate the p-values for the regions defined by the labels.

[19]:
result_p_values = est.estimate_p_values(
    data=data, gamma=0.005
)

For the we consider the parameter \(\xi\), defined as:

\(\xi = \tau_1 / (\tau_1 + \tau_0)\)

So the proportion of the total image intensity that is due to the added component \(\tau_1\). The distribution of \(\xi\) can be plotted the different regions. First the region of interest in the center:

[20]:
ax = est.plot_xi_dist(
    xi_obs=result_p_values[2],
    xi_repl=result_p_values[1],
    region_id="1.0"
);
ax.set_ylim(0, 0.2);
ax.set_xlim(-8.3, 0.2);
../../../../_images/pylira_user_tutorials_notebooks_point_source_36_0.png

In this case all the probability mass is in the region of the bright point source and the mean of \(\xi\) approaches 1.

We also illustrate the distribution of \(\xi\) for second region, where we only expect background:

[21]:
ax = est.plot_xi_dist(
    xi_obs=result_p_values[2],
    xi_repl=result_p_values[1],
    region_id="2.0"
);
ax.set_ylim(0, 0.2);
ax.set_xlim(-8.3, 0.2);
../../../../_images/pylira_user_tutorials_notebooks_point_source_39_0.png

In this case the distribution is fully compatible with the distribution of the null hypothesis.

[ ]:

Notebook file for download: point_source.ipynb