We would like to invite to a Crash Course on NIFTy (Numerical Information Field TheorY) and on the new GRAVITY imaging tool. The course will take place *from August 24th to 27th, 2021* in an hybrid in-person/video-conference format.

The first half of the course will be done by Philipp Arras (MPA/TUM) on the Python package NIFTy. NIFTy is a versatile library that can be used in a variety of inference and data analysis applications. Examples include (x-ray, optical, radio, VLBI) imaging, data calibration applications and the reconstruction of light curves. NIFTy excels in high-dimensional Bayesian inference applications. Basic information can be found in the NIFTy documentation.

The second half of the course will be done by Julia and is specific to GRAVITY imaging with the help of NIFTy.

Closed.

- Video call: https://zoom.us/j/96371769485?pwd=UE5FdTU3aU84TmxtM2syU1I1N1UwZz09
- In person: Max Planck Institute for Extraterrestrial Physics, new seminar room

*All times refer to CEST.*

- Aug 24
- 02:00 pm – 03:45 pm: Intro to NIFTy, part 1
- 04:00 pm – 05:45 pm: Intro to NIFTy, part 2

- Aug 25
- May NIFTy be the solution to my data reduction problem?
*We will open the video conference for these two sessions but will be primarily discussing the topics by the two who raised their hand today. It may very well be that we have additional time. So if you like to discuss your applications, either send an email to Philipp (mail (at) philipp (minus) arras (dot) de) or just join the session.*- 10:30 am – 11:30 am: part 1
- 11:30 am – 12:30 am: part 2

- 02:00 pm – 03:45 pm: Intro to NIFTy, part 3
- 04:00 pm – 05:45 pm: Intro to NIFTy, part 4

- May NIFTy be the solution to my data reduction problem?
- Aug 26
- 09:30 am – 11:00 am: Intro to the new GRAVITY imaging code, part 1
- 11:15 am – 12:45 pm: Intro to the new GRAVITY imaging code, part 2
- Afternoon: Hands-on exercise, trouble shooting, code upgrades for AGN imaging

- Aug 27
- 09:30 am – 11:00 am: Intro to the new GRAVITY imaging code, part 3
- 11:15 am – 12:45 pm: Intro to the new GRAVITY imaging code, part 4
- Afternoon: Hands-on exercise, trouble shooting, code upgrades for AGN imaging

The course includes hands-on sessions during which the participants can experiment with NIFTy themselves. For this, please install NIFTy beforehand. The latest stable version is available on PyPI and can be installed via:

`pip3 install nifty7`

In order to check that the installation was successful, you may run the following script.

```
import nifty7 as ift
import numpy as np
= ift.RGSpace([500, 500], harmonic=True)
dom = ift.HarmonicTransformOperator(dom)
HT = ift.PowerSpace(dom)
pdom = ift.PowerDistributor(dom, pdom)
PD = ift.DiagonalOperator(PD(ift.PS_field(pdom, lambda k: 100./(20. + k**3))))
S = S.draw_sample_with_dtype(dtype=np.float64)
s ="nifty_test.png") ift.single_plot(HT(s), name
```

If the resulting file `nifty_test.png`

looks like the following, NIFTy is correctly installed.

Please find the tutorial scripts here.

```
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Copyright(C) 2013-2021 Max-Planck-Society
#
# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik.
import numpy as np
import nifty7 as ift
from helpers import generate_wf_data, plot_WF
# Want to implement: m = Dj = (S^{-1} + R^T N^{-1} R)^{-1} R^T N^{-1} d
111)
ift.random.push_sseq_from_seed(
= ift.RGSpace(256, 1/256)
position_space = ift.UnstructuredDomain(256)
data_space = lambda k: 1/(10. + k**2.5)
prior_spectrum
= generate_wf_data(position_space, prior_spectrum)
data, ground_truth
= ift.makeField(position_space, ground_truth)
ground_truth = ift.makeField(data_space, data)
data
"1_data", ground_truth, data)
plot_WF(
= position_space.get_default_codomain()
harmonic_space
= ift.HarmonicTransformOperator(harmonic_space, position_space) # basically just a Fast Fourier transform
HT
# Define prior covariance in harmonic space
= ift.create_power_operator(harmonic_space, prior_spectrum)
Sh
= np.ones(256, np.bool)
mask 50:150] = False
mask[180:190] = False
mask[= ift.makeField(position_space, mask)
mask
#class BoilerplateLinearOperator(ift.LinearOperator):
# def __init__(self, mask):
# self._domain = ift.makeDomain(...)
# self._target = ift.makeDomain(...)
# self._capability = self.TIMES | self.ADJOINT_TIMES
#
# def apply(self, x, mode):
# self._check_input(x, mode)
# if mode == self.TIMES:
# raise NotImplementedError
# elif mode == self.ADJOINT_TIMES:
# raise NotImplementedError
# raise RuntimeError
class MaskingOperator(ift.LinearOperator):
def __init__(self, mask):
= np.sum(mask.val)
n_data_points assert mask.s_sum() == n_data_points
self._domain = ift.makeDomain(mask.domain)
self._target = ift.makeDomain(ift.UnstructuredDomain(n_data_points))
self._capability = self.TIMES | self.ADJOINT_TIMES
self._mask = mask.val
def apply(self, x, mode):
self._check_input(x, mode)
if mode == self.TIMES:
= x.val # Unwrapping from field
x = x[self._mask] # Actual code
res return ift.makeField(self._target, res) # Wrapping as field
else: # mode == self.ADJOINT_TIMES
= x.val # Unwrapping from field
x = np.zeros(self._domain.shape, dtype=x.dtype)
res self._mask] = x
res[return ift.makeField(self._domain, res) # Wrapping as field
= MaskingOperator(mask)
mask_op
ift.extra.check_linear_operator(mask_op)
= mask_op.target
data_space = ift.makeField(data_space, data.val[mask.val])
data
= mask_op @ HT
R
= ift.ScalingOperator(data_space, 0.1)
N
= (R.adjoint @ N.inverse)(data)
j
#ift.single_plot(j)
= ift.GradientNormController(iteration_limit=256)
ic = ift.WienerFilterCurvature(R, N, Sh, ic, ic)
metric = metric.inverse
D
# Same as
#D = (Sh.inverse + R.adjoint @ N.inverse @ R).inverse
= D(j)
m
# plot_WF("1_result", ground_truth, data, HT(m))
= 10
n_samples = [HT(m + D.draw_sample()) for _ in range(n_samples)]
samples
1.)), name="1_data_coverage.png")
ift.single_plot(mask_op.adjoint(ift.full(data_space, ="1_posterior_samples.png")
ift.single_plot(samples, name
# plot_WF("1_result_sample", ground_truth, data, samples[0])
# plot_WF("1_result_uncertainty", ground_truth, data, HT(m), samples=samples)
```