To be able to edit code and run cells, you need to run the notebook yourself. Where would you like to run the notebook?

This notebook takes about 19 minutes to run.

In the cloud (experimental)

Binder is a free, open source service that runs scientific notebooks in the cloud! It will take a while, usually 2-7 minutes to get a session.

On your computer

(Recommended if you want to store your changes.)

  1. Copy the notebook URL:
  2. Run Pluto

    (Also see: How to install Julia and Pluto)

  3. Paste URL in the Open box

Frontmatter

If you are publishing this notebook on the web, you can set the parameters below to provide HTML metadata. This is useful for search engines and social media.

Author 1

VLBIData.jl

VLBIData reads and writes a range of data formats typically used in very long baseline interferometry (VLBI).

For convenience, it exports itself as VLBI: non-exported functions are accessed as VLBI.load.

See the table of contents and sections below for the list of supported formats. The proper file format is guessed automatically, and typically one just needs the VLBI.load(file) method.

Some formats, such as "image FITS", may actually contain multiple datasets of different kinds (eg image + model). In such cases, VLBI.load(file) reads the main dataset (image) by default. Use VLBI.load(type, file) to read the dataset of type from the file: see examples below.

👀 Reading hidden code
md"""
!!! info "VLBIData.jl"
`VLBIData` reads and writes a range of data formats typically used in very long baseline interferometry (VLBI).

For convenience, it exports itself as `VLBI`: non-exported functions are accessed as `VLBI.load`.

See the table of contents and sections below for the list of supported formats.
The proper file format is guessed automatically, and typically one just needs the `VLBI.load(file)` method.

Some formats, such as "image FITS", may actually contain multiple datasets of different kinds (eg image + model). In such cases, `VLBI.load(file)` reads the main dataset (image) by default. Use `VLBI.load(type, file)` to read the dataset of `type` from the `file`: see examples below.
"""
5.1 ms

VLBIData is well-tested. It is regularly confirmed to read all files in the Astrogeo database successfully.

👀 Reading hidden code
md"""
`VLBIData` is well-tested. It is regularly confirmed to read all files in the [Astrogeo](http://astrogeo.org/vlbi_images/) database successfully.
"""
402 μs

Image FITS

👀 Reading hidden code
md"""
# Image FITS
"""
8.0 ms

Read image itself

👀 Reading hidden code
7.7 ms

Load the image data from a FITS file:

👀 Reading hidden code
265 μs
fimg = VLBI.load("./data/map.fits");
👀 Reading hidden code
3.1 s

The returned object contains both the header information, and the image data as an array:

👀 Reading hidden code
254 μs
"J0000+0248"
fimg.header["OBJECT"]
👀 Reading hidden code
16.0 μs
KeyedArray(fimg) |> display
👀 Reading hidden code
❔
2-dimensional KeyedArray(NamedDimsArray(...)) with keys:
↓   ra ∈ 512-element StepRangeLen{Unitful.Quantity{Float64,...}dec ∈ 512-element StepRangeLen{Unitful.Quantity{Float64,...}
And data, 512×512 Matrix{Float32}:
              (-51.2 mas)(51.0 mas)
  (51.0 mas)           -4.92649f-6               0.000202965
  (50.8 mas)            2.129f-5                 0.000178501
  (50.6 mas)            7.48033f-5               0.000125342
           ⋮                         ⋱  
 (-50.6 mas)            0.000115528  …          -0.0001272
 (-50.8 mas)            8.01195f-5              -7.8384f-5
 (-51.0 mas)            9.25147f-6               5.1111f-6
 (-51.2 mas)           -7.57209f-5               9.37739f-5
2.1 s

As you see, the image data is a KeyedArray. It contains information about axes and their units for convenient look up, indexing, plotting, ...:

👀 Reading hidden code
269 μs
KeyedArray(fimg)(dec=Near(5u"mas")) |> display
👀 Reading hidden code
❔
1-dimensional KeyedArray(NamedDimsArray(...)) with keys:
↓   ra ∈ 512-element StepRangeLen{Unitful.Quantity{Float64,...}
And data, 512-element view(::Matrix{Float32}, :, 282) with eltype Float32:
  (51.00000085048702 mas)  -9.41605f-5
  (50.80000084715178 mas)  -0.00010086887
  (50.60000084381653 mas)  -0.000102033504
  (50.40000084048129 mas)  -9.566722f-5
  (50.20000083714605 mas)  -8.480035f-5
                        ⋮  
 (-50.60000084381653 mas)  -4.763418f-5
 (-50.80000084715178 mas)  -5.425684f-6
 (-51.00000085048702 mas)   1.2369155f-5
 (-51.20000085382226 mas)   3.7464752f-6
470 ms
let
fig, ax, plt = image(KeyedArray(fimg), colormap=:inferno, colorscale=SymLog(5e-4, vmin=0))
Colorbar(fig[1,2], plt, label="Jy/beam")
fig
end
👀 Reading hidden code
9.2 s

Access the so-called "image beam" - the effective point spread function - and add it to the image:

👀 Reading hidden code
736 μs
beam(fimg)
👀 Reading hidden code
145 ms
let
fig, ax, plt = image(KeyedArray(fimg)((-30..20)u"mas", (-25..25)u"mas"), colormap=:inferno, colorscale=SymLog(5e-4, vmin=0))
beampoly!(ax, ustrip(beam(fimg)), position=(0.1, 0.1), color=:lightgreen)
# plt.gca().add_artist(ScalebarArtist([(1, "mas")], loc="lower right", color=:w))
fig
end
👀 Reading hidden code
2.8 s

Read source model

👀 Reading hidden code
226 μs

FITS image files commonly contain the source model itself, often as a set of delta functions - "CLEAN components". Components are stored in the AIPS CC FITS table.

To load this model instead of the image array, pass the corresponding type to VLBI.load:

👀 Reading hidden code
296 μs
fimg_mod = VLBI.load(MultiComponentModel, "./data/map.fits")
👀 Reading hidden code
877 ms

The MultiComponentModel type, as well as components themselves, are defined in the InterferometricModels.jl package. See its help for more details on how to use these models.

👀 Reading hidden code
286 μs

For example, we can convolve the CLEAN model with the image beam:

👀 Reading hidden code
224 μs
fimg_mod_convolved = convolve(fimg_mod, beam(fimg))
👀 Reading hidden code
80.8 ms
Loading more cells...