Imaging visibility data sets

Simulated visibilities can be saved to a CASA Measurement Set, so any imager capable of working with Measurement Sets can be used to image them.

For convenience, OSKAR includes an imager which can be used if all that is required is a dirty (or residual) image, and it also provides the option to make images directly from data in numpy arrays. This can often be faster than writing visibilities out to a Measurement Set and loading them back again in order to make an image using another program.

An oskar.Imager instance can be created in Python using a settings tree for the oskar_imager application. For example:

params = {
    'image/fov_deg': 5.0,
    'image/size': 6144,
    'image/algorithm': 'W-projection',  # default is FFT (2D only)
    # The following two options are recommended for large images
    # (particularly when using W-projection),
    # as long as you have enough GPU RAM to hold the complex visibility
    # grid as well as the convolution kernels.
    'image/fft/use_gpu': True,
    'image/fft/grid_on_gpu': True,
    'image/input_vis_data': 'example.vis',  # or 'example.ms'
    'image/root_path': 'example_image'  # Optional: see below
}
settings = oskar.SettingsTree('oskar_imager')
settings.from_dict(params)
imager = oskar.Imager(settings=settings)

This will generate an image using the visibility data in the file example.vis (or example.ms if a Measurement Set is specified instead), and will write a FITS image in Stokes I called example_image_I.fits.

The image will be centred on the phase centre used in the observation by default, but it can be re-centred on a different direction by adding the parameters:

params = {
    ...  (other parameters here)
    'image/direction': 'RA, Dec.',
    'image/direction/ra_deg': 12.34,  # Insert the required coordinates.
    'image/direction/dec_deg': 56.78
}

The full list of settings parameters is shown in the OSKAR GUI for the oskar_imager application, and also in the settings documentation.

After setting it up, call oskar.Imager.run() to make the image. If required, the image(s) can be returned directly to Python as a numpy array instead of (or as well as) writing a FITS file. Use return_images=1 as an argument to oskar.Imager.run() and assign the return value to a variable. This will be a dictionary of arrays holding the image(s), which can be accessed using the ‘images’ dictionary key as follows:

output = imager.run(return_images=1)
image = output['images'][0]  # Stokes I image.

Making dirty or residual images automatically

Many simulation runs need to make either dirty images, or images of residual visibilities. The residuals are generated by subtracting a reference (or model) visibility data set first.

For convenience, the ResidualImageSimulator class, described below, can be used to make either dirty or residual images at the same time as running a simulation. It combines the functionality of oskar.Interferometer and oskar.Imager, so that residual visibilities can be generated as needed and processed on-the-fly as the simulation progresses, without needing to write out visibilities and load them back again to make each image. If generating residuals, only the reference visibilities need to be saved, and multiple subsequent runs can use the same reference data set.

This simulator is configured in the same way as oskar.Interferometer, and can optionally be passed an instance of an imager, and a filename containing the reference visibility data. Use it in place of oskar.Interferometer if you need to make an image of a simulated data set.

Similar to oskar.Imager, any images created using this simulator will be returned directly as numpy arrays from the run() method:

output = sim.run()
image = output['images'][0]  # Stokes I image.

See the notes and example in the class documentation (included below) for usage instructions.

class scripts.ResidualImageSimulator(*args: Any, **kwargs: Any)[source]

Interferometer simulator which generates both reference and residual visibilities, optionally imaging them.

This class inherits oskar.Interferometer, so it requires the same settings parameters. Each visibility block can be imaged if required in the overridden process_block() method.

To generate (and image) residual visibilities, two simulations must be run using separate instances of this class:

  1. The first run generates the reference visibility data set, which must be saved to an OSKAR visibility data file.

  2. The reference visibilities are then subtracted from the visibilities generated in the second run.

Dirty/residual images of the visibilities can be returned for either run by specifying an imager to use when constructing the simulator.

The following code shows a minimal but complete example of how this class could be used. Note that there are two separate simulators created.

 1 import oskar
 2
 3 # Create a 9-by-9 unit-amplitude point-source sky model
 4 # at the phase centre.
 5 # First, define the phase centre coordinates.
 6 ra0_deg = 0
 7 dec0_deg = -30
 8 grid_width_deg = 4.0  # Width of the source grid in degrees.
 9 sky = oskar.Sky.generate_grid(ra0_deg, dec0_deg, 9, grid_width_deg)
10
11 # Create and set up an imager to make the residual images.
12 params_img = {
13     'image/fov_deg': grid_width_deg + 0.5,
14     'image/size': 6144,
15     'image/fft/use_gpu': True
16 }
17 settings_img = oskar.SettingsTree('oskar_imager')
18 settings_img.from_dict(params_img)
19 imager = oskar.Imager(settings=settings_img)
20
21 # Define base parameters for a simulated observation
22 # using oskar.Interferometer.
23 obs_length_sec = 4 * 3600.0  # 4 hours, in seconds.
24 base_params_sim = {
25     'observation/start_frequency_hz': 110e6,  # One channel at 110 MHz
26     'observation/phase_centre_ra_deg': ra0_deg,
27     'observation/phase_centre_dec_deg': dec0_deg,
28     'observation/num_time_steps': 24,  # Simulate 24 correlator dumps
29     'observation/start_time_utc': get_start_time(ra0_deg, obs_length_sec),
30     'observation/length': obs_length_sec,
31     'interferometer/channel_bandwidth_hz': 10e3,
32     'interferometer/time_average_sec': 1.0,
33     # Ignore w-components only if the sky model allows for it,
34     # with all sources well within the imaged field of view!
35     # (W-smearing will be disabled for all sources.)
36     'interferometer/ignore_w_components': True
37 }
38 settings_sim = oskar.SettingsTree('oskar_sim_interferometer')
39 settings_sim.from_dict(base_params_sim)
40
41 # Set the parameters for the reference simulation, including a
42 # reference telescope model, and the output visibility file name.
43 settings_sim['telescope/input_directory'] = '/path/to/reference_telescope_model_folder.tm'
44 settings_sim['interferometer/oskar_vis_filename'] = 'reference_data.vis'
45
46 # Run the reference simulation.
47 # No image is made at this point, but visibilities are saved to a file.
48 sim = ResidualImageSimulator(settings=settings_sim)
49 sim.set_sky_model(sky)
50 sim.run()
51
52 # Set the parameters for the comparison simulation, including a new
53 # telescope model. We don't need to save the residual visibilities,
54 # so the output file name is blank.
55 settings_sim['telescope/input_directory'] = '/path/to/comparison_telescope_model_folder.tm'
56 settings_sim['interferometer/oskar_vis_filename'] = ''
57
58 # Run the comparison simulation.
59 # Note that the pre-configured imager and the filename of the
60 # reference visibility data are both passed in the constructor.
61 sim = ResidualImageSimulator(
62     imager=imager, settings=settings_sim, ref_vis='reference_data.vis')
63 sim.set_sky_model(sky)
64
65 # The residual image(s) is (are) returned by the run() method.
66 output = sim.run()
67 image = output['images'][0]  # Stokes I residual image
__init__(imager=None, settings=None, ref_vis=None)[source]

Creates the simulator, storing a handle to the imager.

Parameters:
  • imager (Optional[oskar.Imager]) – Imager to use.

  • settings (Optional[oskar.SettingsTree]) – Optional settings to use to set up the simulator.

  • ref_vis (Optional[str]) – Pathname of reference visibility file.

finalise()[source]

Called automatically by the base class at the end of run().

process_block(block, block_index)[source]

Processes the visibility block.

Residual visibilities are generated if appropriate by subtracting the corresponding reference visibilities. The (modified) visibility block is also sent to the imager if one was set, and written to any open visibility data files defined in the settings.

Parameters:
  • block (oskar.VisBlock) – A handle to the block to be processed.

  • block_index (int) – The index of the visibility block.

run()[source]

Runs the interferometer simulator and imager, if set.

Any images will be returned in an array accessed by the ‘images’ dictionary key, for example:

output = sim.run()
image = output['images'][0]  # Stokes I image.