예제 #1
0
def calibrate_visibility(vt: Visibility,
                         model: Image = None,
                         components=None,
                         predict=predict_2d,
                         **kwargs) -> Visibility:
    """ calibrate Visibility with respect to model and optionally components

    :param vt: Visibility
    :param model: Model image
    :param components: Sky components
    :return: Calibrated visibility
    """
    assert model is not None or components is not None, "calibration requires a model or skycomponents"

    vtpred = copy_visibility(vt, zero=True)

    if model is not None:
        vtpred = predict(vtpred, model, **kwargs)
        if components is not None:
            vtpred = predict_skycomponent_visibility(vtpred, components)
    else:
        vtpred = predict_skycomponent_visibility(vtpred, components)

    bvt = decoalesce_visibility(vt)
    bvtpred = decoalesce_visibility(vtpred)
    gt = solve_gaintable(bvt, bvtpred, **kwargs)
    bvt = apply_gaintable(bvt,
                          gt,
                          inverse=get_parameter(kwargs, "inverse", False))
    return convert_blockvisibility_to_visibility(bvt)
예제 #2
0
def skymodel_cal_fit_skymodel(vis, calskymodel, gain=0.1, method='fit', **kwargs):
    """Fit a single skymodel to a visibility

    This is the update to the component part of the window.

    :param evis: Expected vis for this ssm
    :param calskymodel: scm element being fit i.e. (skymodel, gaintable) tuple
    :param gain: Gain in step
    :param method: 'fit' or 'sum'
    :param kwargs:
    :return: skycomponent
    """
    cvis = convert_blockvisibility_to_visibility(vis)
    new_comps = list()
    for comp in calskymodel[0].components:
        new_comp = copy_skycomponent(comp)
        if method == 'sum':
            new_flux, _ = sum_visibility(cvis, new_comp.direction)
            new_comp.flux = gain * new_flux + (1.0 - gain) * comp[0].flux
        else:
            new_comp, _ = fit_visibility(cvis, new_comp)
            new_comp.flux = gain * new_comp.flux + (1.0 - gain) * comp.flux
        new_comps.append(new_comp)

    return SkyModel(components=new_comps)
예제 #3
0
def calibrate_blockvisibility(bvt: BlockVisibility,
                              model=None,
                              components=None,
                              predict=predict_2d,
                              **kwargs):
    """ calibrate BlockVisibility with respect to model and optionally components

    :param bvt: BlockVisibility
    :param model: Model image
    :param components: Sky components
    :returns: Calibrated BlockVisibility

    """
    assert model is not None or components is not None, "calibration requires a model or skycomponents"

    if model is not None:
        vtpred = convert_blockvisibility_to_visibility(bvt)
        vtpred = predict(vtpred, model, **kwargs)
        bvtpred = decoalesce_visibility(vtpred)
        if components is not None:
            bvtpred = predict_skycomponent_blockvisibility(bvtpred, components)
    else:
        bvtpred = copy_visibility(bvt, zero=True)
        bvtpred = predict_skycomponent_blockvisibility(bvtpred, components)

    gt = solve_gaintable(bvt, bvtpred, **kwargs)
    return apply_gaintable(bvt, gt, **kwargs)
예제 #4
0
 def test_convert_decoalesce_zero(self):
     cvis = convert_blockvisibility_to_visibility(self.blockvis)
     assert numpy.min(cvis.frequency) == numpy.min(self.frequency)
     assert numpy.min(cvis.frequency) > 0.0
     dvis = decoalesce_visibility(cvis)
     assert dvis.nvis == self.blockvis.nvis
     dvis = decoalesce_visibility(cvis, overwrite=True)
     assert dvis.nvis == self.blockvis.nvis
예제 #5
0
 def test_coalesce_decoalesce_with_iter(self):
     for rows in vis_timeslice_iter(self.blockvis):
         visslice = create_visibility_from_rows(self.blockvis, rows)
         cvisslice = convert_blockvisibility_to_visibility(visslice)
         assert numpy.min(cvisslice.frequency) == numpy.min(self.frequency)
         assert numpy.min(cvisslice.frequency) > 0.0
         dvisslice = decoalesce_visibility(cvisslice)
         assert dvisslice.nvis == visslice.nvis
 def test_convert_blockvisibility(self):
     self.vis = create_blockvisibility(
         self.lowcore,
         self.times,
         self.frequency,
         phasecentre=self.phasecentre,
         weight=1.0,
         channel_bandwidth=self.channel_bandwidth)
     vis = convert_blockvisibility_to_visibility(self.vis)
     assert vis.nvis == len(vis.time)
     assert numpy.unique(vis.time).size == self.vis.time.size
예제 #7
0
def calibrate_function(vis, model_vis, context='T', controls=None, iteration=0, **kwargs):
    """ Calibrate using algorithm specified by context
    
    The context string can denote a sequence of calibrations e.g. TGB with different timescales.

    :param vis:
    :param model_vis:
    :param context: calibration contexts in order of correction e.g. 'TGB'
    :param control: controls dictionary, modified as necessary
    :param iteration: Iteration number to be compared to the 'first_selfcal' field.
    :param kwargs:
    :return: Calibrated data, dict(gaintables)
    """
    gaintables = {}
    
    if controls is None:
        controls = create_calibration_controls(**kwargs)
    
    isVis = isinstance(vis, Visibility)
    if isVis:
        avis = convert_visibility_to_blockvisibility(vis)
    else:
        avis = vis
    
    isMVis = isinstance(model_vis, Visibility)
    if isMVis:
        amvis = convert_visibility_to_blockvisibility(model_vis)
    else:
        amvis = model_vis
    
    for c in context:
        if iteration >= controls[c]['first_selfcal']:
            gaintables[c] = \
                create_gaintable_from_blockvisibility(avis,
                                                      timeslice=controls[c]['timeslice'])
            gaintables[c] = solve_gaintable(avis, amvis,
                                            timeslice=controls[c]['timeslice'],
                                            phase_only=controls[c]['phase_only'],
                                            crosspol=controls[c]['shape'] == 'matrix')
            log.debug('calibrate_function: Jones matrix %s, iteration %d' % (c, iteration))
            log.debug(qa_gaintable(gaintables[c], context='Jones matrix %s, iteration %d' % (c, iteration)))
            avis = apply_gaintable(avis, gaintables[c],
                                   inverse=True,
                                   timeslice=controls[c]['timeslice'])
        else:
            log.debug('calibrate_function: Jones matrix %s not solved, iteration %d' % (c, iteration))
    if isVis:
        return convert_blockvisibility_to_visibility(avis), gaintables
    else:
        return avis, gaintables
 def test_sagecal_solve_delayed(self):
     self.actualSetup()
     sagecal_graph = create_sagecal_solve_graph(self.vis, self.components, niter=30, gain=0.25, tol=1e-8)
     sagecal_graph.visualize("%s/sagecal.svg" % self.dir)
     
     thetas, residual_vis = sagecal_graph.compute()
     
     residual_vis = convert_blockvisibility_to_visibility(residual_vis)
     residual_vis, _, _ = weight_visibility(residual_vis, self.beam)
     dirty, sumwt = invert_function(residual_vis, self.beam, context='2d')
     export_image_to_fits(dirty, "%s/test_sagecal-delayed-final_residual.fits" % self.dir)
     
     qa = qa_image(dirty)
     assert qa.data['rms'] < 4e-3, qa
 def test_sagecal_solve(self):
     self.actualSetup()
     thetas, residual_vis = sagecal_solve(self.vis, self.components, niter=30, gain=0.25, tol=1e-8)
     
     residual_vis = convert_blockvisibility_to_visibility(residual_vis)
     residual_vis, _, _ = weight_visibility(residual_vis, self.beam)
     dirty, sumwt = invert_function(residual_vis, self.beam, context='2d')
     export_image_to_fits(dirty, "%s/test_sagecal-final_residual.fits" % self.dir)
     
     # for i, theta in enumerate(thetas):
     #     print('Component %d, original flux = %s, recovered flux = %s, gain residual = %s' %
     #           (i, str(self.components[i].flux[0, 0]), str(theta[0].flux[0, 0]),
     #            str(numpy.max(theta[1].residual))))
     #
     qa = qa_image(dirty)
     assert qa.data['rms'] < 4e-3, qa
def sagecal_fit_component(evis, theta, gain=0.1, method='fit', **kwargs):
    """Fit a single component to a visibility i.e. A13

    This is the update to the component part of the window

    :param evis:
    :param theta:
    :param kwargs:
    :return:
    """
    cvis = convert_blockvisibility_to_visibility(evis)
    new_comp = copy_skycomponent(theta[0])
    if method == 'sum':
        new_flux, _ = sum_visibility(cvis, new_comp.direction)
        new_comp.flux = gain * new_flux + (1.0 - gain) * theta[0].flux
    else:
        new_comp, _ = fit_visibility(cvis, new_comp)
        new_comp.flux = gain * new_comp.flux + (1.0 - gain) * theta[0].flux

    return new_comp
def trial_case(results,
               seed=180555,
               context='wstack',
               nworkers=8,
               threads_per_worker=1,
               processes=True,
               order='frequency',
               nfreqwin=7,
               ntimes=3,
               rmax=750.0,
               facets=1,
               wprojection_planes=1):
    """ Single trial for performance-timings
    
    Simulates visibilities from GLEAM including phase errors
    Makes dirty image and PSF
    Runs ICAL pipeline
    
    The results are in a dictionary:
    
    'context': input - a string describing concisely the purpose of the test
    'time overall',  overall execution time (s)
    'time create gleam', time to create GLEAM prediction graph
    'time predict', time to execute GLEAM prediction graph
    'time corrupt', time to corrupt data
    'time invert', time to make dirty image
    'time psf invert', time to make PSF
    'time ICAL graph', time to create ICAL graph
    'time ICAL', time to execute ICAL graph
    'context', type of imaging e.g. 'wstack'
    'nworkers', number of workers to create
    'threads_per_worker',
    'nnodes', Number of nodes,
    'processes', 'order', Ordering of data
    'nfreqwin', Number of frequency windows in simulation
    'ntimes', Number of hour angles in simulation
    'rmax', Maximum radius of stations used in simulation (m)
    'facets', Number of facets in deconvolution and imaging
    'wprojection_planes', Number of wprojection planes
    'vis_slices', Number of visibility slices (per Visibbility)
    'npixel', Number of pixels in image
    'cellsize', Cellsize in radians
    'seed', Random number seed
    'dirty_max', Maximum in dirty image
    'dirty_min', Minimum in dirty image
    'psf_max',
    'psf_min',
    'restored_max',
    'restored_min',
    'deconvolved_max',
    'deconvolved_min',
    'residual_max',
    'residual_min',
    'git_info', GIT hash (not definitive since local mods are possible)
    
    :param results: Initial state
    :param seed: Random number seed (used in gain simulations)
    :param context: imaging context
    :param context: Type of context: '2d'|'timeslice'|'wstack'
    :param nworkers: Number of dask workers to use
    :param threads_per_worker: Number of threads per worker
    :param processes: Use processes instead of threads 'processes'|'threads'
    :param order: See create_simulate_vis_graph
    :param nfreqwin: See create_simulate_vis_graph
    :param ntimes: See create_simulate_vis_graph
    :param rmax: See create_simulate_vis_graph
    :param facets: Number of facets to use
    :param wprojection_planes: Number of wprojection planes to use
    :param kwargs:
    :return: results dictionary
    """
    def check_workers(client, nworkers_initial):
        nworkers_final = len(client.scheduler_info()['workers'])
        assert nworkers_final == nworkers_initial, "Started %d workers, only %d at end" % \
                                                   (nworkers_initial, nworkers_final)

    numpy.random.seed(seed)
    results['seed'] = seed

    start_all = time.time()

    results['context'] = context
    results['hostname'] = socket.gethostname()
    results['git_hash'] = git_hash()
    results['epoch'] = time.strftime("%Y-%m-%d %H:%M:%S")

    zerow = False
    print("Context is %s" % context)

    results['nworkers'] = nworkers
    results['threads_per_worker'] = threads_per_worker
    results['processes'] = processes
    results['order'] = order
    results['nfreqwin'] = nfreqwin
    results['ntimes'] = ntimes
    results['rmax'] = rmax
    results['facets'] = facets
    results['wprojection_planes'] = wprojection_planes

    print("At start, configuration is {0!r}".format(results))

    # Parameters determining scale
    frequency = numpy.linspace(0.8e8, 1.2e8, nfreqwin)
    if nfreqwin > 1:
        channel_bandwidth = numpy.array(nfreqwin *
                                        [frequency[1] - frequency[0]])
    else:
        channel_bandwidth = numpy.array([1e6])
    times = numpy.linspace(-numpy.pi / 3.0, numpy.pi / 3.0, ntimes)

    phasecentre = SkyCoord(ra=+30.0 * u.deg,
                           dec=-60.0 * u.deg,
                           frame='icrs',
                           equinox='J2000')

    vis_graph_list = create_simulate_vis_graph(
        'LOWBD2',
        frequency=frequency,
        channel_bandwidth=channel_bandwidth,
        times=times,
        phasecentre=phasecentre,
        order=order,
        format='blockvis',
        rmax=rmax)

    client = get_dask_Client(n_workers=nworkers,
                             threads_per_worker=threads_per_worker,
                             processes=processes)

    nworkers_initial = len(client.scheduler_info()['workers'])
    check_workers(client, nworkers_initial)
    results['nnodes'] = len(numpy.unique(findNodes(client)))
    print("Defined %d workers on %d nodes" % (nworkers, results['nnodes']))

    print("****** Visibility creation ******")
    vis_graph_list = compute_list(client, vis_graph_list)
    print("After creating vis_graph_list", client)

    # Find the best imaging parameters.
    wprojection_planes = 1
    advice = advise_wide_field(convert_blockvisibility_to_visibility(
        vis_graph_list[0]),
                               guard_band_image=6.0,
                               delA=0.02,
                               facets=facets,
                               wprojection_planes=wprojection_planes,
                               oversampling_synthesised_beam=4.0)

    kernel = advice['kernel']

    npixel = advice['npixels2']
    cellsize = advice['cellsize']

    if context == 'timeslice':
        vis_slices = ntimes
    elif context == '2d':
        vis_slices = 1
        kernel = '2d'
    else:
        vis_slices = advice['vis_slices']

    results['vis_slices'] = vis_slices
    results['cellsize'] = cellsize
    results['npixel'] = npixel

    gleam_model_graph = [
        delayed(create_low_test_image_from_gleam)(
            npixel=npixel,
            frequency=[frequency[f]],
            channel_bandwidth=[channel_bandwidth[f]],
            cellsize=cellsize,
            phasecentre=phasecentre,
            polarisation_frame=PolarisationFrame("stokesI"),
            flux_limit=0.1,
            applybeam=True) for f, freq in enumerate(frequency)
    ]

    start = time.time()
    print("****** Starting GLEAM model creation ******")
    gleam_model_graph = compute_list(client, gleam_model_graph)
    cmodel = smooth_image(gleam_model_graph[0])
    export_image_to_fits(cmodel, "pipelines-timings-delayed-gleam_cmodel.fits")
    end = time.time()
    results['time create gleam'] = end - start
    print("Creating GLEAM model took %.2f seconds" % (end - start))

    vis_graph_list = create_predict_graph(vis_graph_list,
                                          gleam_model_graph,
                                          vis_slices=51,
                                          context=context,
                                          kernel=kernel)
    start = time.time()
    print("****** Starting GLEAM model visibility prediction ******")
    vis_graph_list = compute_list(client, vis_graph_list)

    end = time.time()
    results['time predict'] = end - start
    print("After prediction", client)
    print("GLEAM model Visibility prediction took %.2f seconds" %
          (end - start))

    # Corrupt the visibility for the GLEAM model
    print("****** Visibility corruption ******")
    vis_graph_list = create_corrupt_vis_graph(vis_graph_list, phase_error=1.0)
    start = time.time()
    vis_graph_list = compute_list(client, vis_graph_list)
    end = time.time()
    results['time corrupt'] = end - start
    print("After corrupt", client)
    print("Visibility corruption took %.2f seconds" % (end - start))

    # Create an empty model image
    model_graph = [
        delayed(create_image_from_visibility)(
            vis_graph_list[f],
            npixel=npixel,
            cellsize=cellsize,
            frequency=[frequency[f]],
            channel_bandwidth=[channel_bandwidth[f]],
            polarisation_frame=PolarisationFrame("stokesI"))
        for f, freq in enumerate(frequency)
    ]
    model_graph = client.compute(model_graph, sync=True)

    psf_graph = create_invert_graph(vis_graph_list,
                                    model_graph,
                                    vis_slices=vis_slices,
                                    context=context,
                                    facets=facets,
                                    dopsf=True,
                                    kernel=kernel)
    start = time.time()
    print("****** Starting PSF calculation ******")
    psf, sumwt = client.compute(psf_graph, sync=True)[0]
    check_workers(client, nworkers_initial)
    end = time.time()
    results['time psf invert'] = end - start
    print("PSF invert took %.2f seconds" % (end - start))
    print("After psf", client)

    results['psf_max'] = qa_image(psf).data['max']
    results['psf_min'] = qa_image(psf).data['min']

    dirty_graph = create_invert_graph(vis_graph_list,
                                      model_graph,
                                      vis_slices=vis_slices,
                                      context=context,
                                      facets=facets,
                                      kernel=kernel)
    start = time.time()
    print("****** Starting dirty image calculation ******")
    dirty, sumwt = client.compute(dirty_graph, sync=True)[0]
    check_workers(client, nworkers_initial)
    end = time.time()
    print("After dirty image", client)
    results['time invert'] = end - start
    print("Dirty image invert took %.2f seconds" % (end - start))
    print("Maximum in dirty image is ", numpy.max(numpy.abs(dirty.data)),
          ", sumwt is ", sumwt)
    qa = qa_image(dirty)
    results['dirty_max'] = qa.data['max']
    results['dirty_min'] = qa.data['min']

    # Create the ICAL pipeline to run 5 major cycles, starting selfcal at cycle 1. A global solution across all
    # frequencies (i.e. Visibilities) is performed.
    start = time.time()
    print("****** Starting ICAL ******")
    start = time.time()
    ical_graph = create_ical_pipeline_graph(vis_graph_list,
                                            model_graph=model_graph,
                                            context=context,
                                            do_selfcal=1,
                                            nchan=nfreqwin,
                                            vis_slices=vis_slices,
                                            algorithm='mmclean',
                                            nmoments=3,
                                            niter=1000,
                                            fractional_threshold=0.1,
                                            scales=[0, 3, 10],
                                            threshold=0.1,
                                            nmajor=5,
                                            gain=0.7,
                                            timeslice='auto',
                                            global_solution=True,
                                            window_shape='quarter')
    end = time.time()
    results['time ICAL graph'] = end - start
    print("Construction of ICAL graph took %.2f seconds" % (end - start))

    # Execute the graph
    start = time.time()
    result = client.compute(ical_graph, sync=True)
    deconvolved, residual, restored = result
    check_workers(client, nworkers_initial)
    end = time.time()
    print("After ICAL", client)

    results['time ICAL'] = end - start
    print("ICAL graph execution took %.2f seconds" % (end - start))
    qa = qa_image(deconvolved[0])
    results['deconvolved_max'] = qa.data['max']
    results['deconvolved_min'] = qa.data['min']
    export_image_to_fits(deconvolved[0],
                         "pipelines-timings-delayed-ical_deconvolved.fits")

    qa = qa_image(residual[0][0])
    results['residual_max'] = qa.data['max']
    results['residual_min'] = qa.data['min']
    export_image_to_fits(residual[0][0],
                         "pipelines-timings-delayed-ical_residual.fits")

    qa = qa_image(restored[0])
    results['restored_max'] = qa.data['max']
    results['restored_min'] = qa.data['min']
    export_image_to_fits(restored[0],
                         "pipelines-timings-delayed-ical_restored.fits")
    #
    client.shutdown()

    end_all = time.time()
    results['time overall'] = end_all - start_all

    print("At end, results are {0!r}".format(results))

    return results
def ical(block_vis: BlockVisibility,
         model: Image,
         components=None,
         context='2d',
         controls=None,
         **kwargs):
    """ Post observation image, deconvolve, and self-calibrate
   
    :param vis:
    :param model: Model image
    :param components: Initial components
    :param context: Imaging context
    :param controls: Calibration controls dictionary
    :return: model, residual, restored
    """
    nmajor = get_parameter(kwargs, 'nmajor', 5)
    log.info("ical: Performing %d major cycles" % nmajor)

    do_selfcal = get_parameter(kwargs, "do_selfcal", False)

    if controls is None:
        controls = create_calibration_controls(**kwargs)

    # The model is added to each major cycle and then the visibilities are
    # calculated from the full model
    vis = convert_blockvisibility_to_visibility(block_vis)
    block_vispred = copy_visibility(block_vis, zero=True)
    vispred = convert_blockvisibility_to_visibility(block_vispred)
    vispred.data['vis'][...] = 0.0
    visres = copy_visibility(vispred)

    vispred = predict_function(vispred, model, context=context, **kwargs)

    if components is not None:
        vispred = predict_skycomponent_visibility(vispred, components)

    if do_selfcal:
        vis, gaintables = calibrate_function(vis,
                                             vispred,
                                             'TGB',
                                             controls,
                                             iteration=-1)

    visres.data['vis'] = vis.data['vis'] - vispred.data['vis']
    dirty, sumwt = invert_function(visres, model, context=context, **kwargs)
    log.info("Maximum in residual image is %.6f" %
             (numpy.max(numpy.abs(dirty.data))))

    psf, sumwt = invert_function(visres,
                                 model,
                                 dopsf=True,
                                 context=context,
                                 **kwargs)

    thresh = get_parameter(kwargs, "threshold", 0.0)

    for i in range(nmajor):
        log.info("ical: Start of major cycle %d of %d" % (i, nmajor))
        cc, res = deconvolve_cube(dirty, psf, **kwargs)
        model.data += cc.data
        vispred.data['vis'][...] = 0.0
        vispred = predict_function(vispred, model, context=context, **kwargs)
        if do_selfcal:
            vis, gaintables = calibrate_function(vis,
                                                 vispred,
                                                 'TGB',
                                                 controls,
                                                 iteration=i)
        visres.data['vis'] = vis.data['vis'] - vispred.data['vis']

        dirty, sumwt = invert_function(visres,
                                       model,
                                       context=context,
                                       **kwargs)
        log.info("Maximum in residual image is %s" %
                 (numpy.max(numpy.abs(dirty.data))))
        if numpy.abs(dirty.data).max() < 1.1 * thresh:
            log.info("ical: Reached stopping threshold %.6f Jy" % thresh)
            break
        log.info("ical: End of major cycle")

    log.info("ical: End of major cycles")
    restored = restore_cube(model, psf, dirty, **kwargs)

    return model, dirty, restored
예제 #13
0
def advise_wide_field(vis: Visibility,
                      delA=0.02,
                      oversampling_synthesised_beam=3.0,
                      guard_band_image=6.0,
                      facets=1,
                      wprojection_planes=1):
    """ Advise on parameters for wide field imaging.
    
    Calculate sampling requirements on various parameters
    
    For example::
    
        advice = advise_wide_field(vis, delA)
        wstep = get_parameter(kwargs, 'wstep', advice['w_sampling_primary_beam'])

    
    :param vis:
    :param delA: Allowed coherence loss (def: 0.02)
    :param oversampling_synthesised_beam: Oversampling of the synthesized beam (def: 3.0)
    :param guard_band_image: Number of primary beam half-widths-to-half-maximum to image (def: 6)
    :param facets: Number of facets on each axis
    :param wprojection_planes: Number of planes in wprojection
    :return: dict of advice
    """

    if isinstance(vis, BlockVisibility):
        svis = convert_blockvisibility_to_visibility(vis)
    else:
        svis = vis
    assert isinstance(svis, Visibility), svis

    max_wavelength = constants.c.to('m/s').value / numpy.min(svis.frequency)
    log.info("advise_wide_field: Maximum wavelength %.3f (meters)" %
             (max_wavelength))

    min_wavelength = constants.c.to('m/s').value / numpy.max(svis.frequency)
    log.info("advise_wide_field: Minimum wavelength %.3f (meters)" %
             (min_wavelength))

    maximum_baseline = numpy.max(numpy.abs(svis.uvw))  # Wavelengths
    if isinstance(svis, BlockVisibility):
        maximum_baseline = maximum_baseline / min_wavelength
    log.info("advise_wide_field: Maximum baseline %.1f (wavelengths)" %
             (maximum_baseline))

    diameter = numpy.min(svis.configuration.diameter)
    log.info("advise_wide_field: Station/antenna diameter %.1f (meters)" %
             (diameter))

    primary_beam_fov = max_wavelength / diameter
    log.info("advise_wide_field: Primary beam %s" %
             (rad_and_deg(primary_beam_fov)))

    image_fov = primary_beam_fov * guard_band_image
    log.info("advise_wide_field: Image field of view %s" %
             (rad_and_deg(image_fov)))

    facet_fov = primary_beam_fov * guard_band_image / facets
    if facets > 1:
        log.info("advise_wide_field: Facet field of view %s" %
                 (rad_and_deg(facet_fov)))

    synthesized_beam = 1.0 / (maximum_baseline)
    log.info("advise_wide_field: Synthesized beam %s" %
             (rad_and_deg(synthesized_beam)))

    cellsize = synthesized_beam / oversampling_synthesised_beam
    log.info("advise_wide_field: Cellsize %s" % (rad_and_deg(cellsize)))

    def pwr23(n):
        ex = numpy.ceil(numpy.log(n) / numpy.log(2.0)).astype('int')
        best = numpy.power(2, ex)
        if best * 3 // 4 >= n:
            best = best * 3 // 4
        return best

    npixels = int(round(image_fov / cellsize))
    log.info("advice_wide_field: Npixels per side = %d" % (npixels))

    npixels2 = pwr23(npixels)
    log.info("advice_wide_field: Npixels (power of 2, 3) per side = %d" %
             (npixels2))

    # Following equation is from Cornwell, Humphreys, and Voronkov (2012) (equation 24)
    # We will assume that the constraint holds at one quarter the entire FOV i.e. that
    # the full field of view includes the entire primary beam

    w_sampling_image = numpy.sqrt(2.0 * delA) / (numpy.pi * image_fov**2)
    log.info(
        "advice_wide_field: W sampling for full image = %.1f (wavelengths)" %
        (w_sampling_image))

    if facets > 1:
        w_sampling_facet = numpy.sqrt(2.0 * delA) / (numpy.pi * facet_fov**2)
        log.info(
            "advice_wide_field: W sampling for facet = %.1f (wavelengths)" %
            (w_sampling_facet))

    w_sampling_primary_beam = numpy.sqrt(
        2.0 * delA) / (numpy.pi * primary_beam_fov**2)
    log.info(
        "advice_wide_field: W sampling for primary beam = %.1f (wavelengths)" %
        (w_sampling_primary_beam))

    time_sampling_image = 86400.0 * w_sampling_image / (numpy.pi *
                                                        maximum_baseline)
    log.info("advice_wide_field: Time sampling for full image = %.1f (s)" %
             (time_sampling_image))

    if facets > 1:
        time_sampling_facet = 86400.0 * w_sampling_facet / (numpy.pi *
                                                            maximum_baseline)
        log.info("advice_wide_field: Time sampling for facet = %.1f (s)" %
                 (time_sampling_facet))

    time_sampling_primary_beam = 86400.0 * w_sampling_primary_beam / (
        numpy.pi * maximum_baseline)
    log.info("advice_wide_field: Time sampling for primary beam = %.1f (s)" %
             (time_sampling_primary_beam))

    freq_sampling_image = numpy.max(
        vis.frequency) * w_sampling_image / (numpy.pi * maximum_baseline)
    log.info(
        "advice_wide_field: Frequency sampling for full image = %.1f (Hz)" %
        (freq_sampling_image))

    if facets > 1:
        freq_sampling_facet = numpy.max(
            vis.frequency) * w_sampling_facet / (numpy.pi * maximum_baseline)
        log.info(
            "advice_wide_field: Frequency sampling for facet = %.1f (Hz)" %
            (freq_sampling_facet))

    freq_sampling_primary_beam = numpy.max(
        vis.frequency) * w_sampling_primary_beam / (numpy.pi *
                                                    maximum_baseline)
    log.info(
        "advice_wide_field: Frequency sampling for primary beam = %.1f (Hz)" %
        (freq_sampling_primary_beam))

    wstep = w_sampling_primary_beam
    vis_slices = max(1, int(maximum_baseline / (wstep * wprojection_planes)))
    log.info('advice_wide_field: Number of planes in w stack %d' %
             (vis_slices))
    log.info('advice_wide_field: Number of planes in w projection %d' %
             wprojection_planes)
    if wprojection_planes > 1:
        log.info(
            'advice_wide_field: Recommend that wprojection gridding is used')
        kernel = 'wprojection'
    else:
        log.info(
            'advice_wide_field: Recommend that 2d gridding (i.e. no wprojection) is used'
        )
        kernel = '2d'

    return locals()
 def actualSetup(self, sky_pol_frame='stokesI', data_pol_frame='stokesI', f=None, vnchan=1, doiso=True,
                 ntimes=1, flux_limit=18.0):
     
     nfreqwin = vnchan
     ntimes = ntimes
     rmax = 300.0
     npixel = 1024
     cellsize = 0.001
     frequency = numpy.linspace(0.8e8, 1.2e8, nfreqwin)
     if nfreqwin > 1:
         channel_bandwidth = numpy.array(nfreqwin * [frequency[1] - frequency[0]])
     else:
         channel_bandwidth = [0.4e8]
     times = numpy.linspace(-numpy.pi / 3.0, numpy.pi / 3.0, ntimes)
     
     phasecentre = SkyCoord(ra=+0.0 * u.deg, dec=-45.0 * u.deg, frame='icrs', equinox='J2000')
     
     lowcore = create_named_configuration('LOWBD2', rmax=rmax)
     
     block_vis = create_blockvisibility(lowcore, times, frequency=frequency, channel_bandwidth=channel_bandwidth,
                                        weight=1.0, phasecentre=phasecentre,
                                        polarisation_frame=PolarisationFrame("stokesI"))
     
     block_vis.data['uvw'][..., 2] = 0.0
     self.beam = create_image_from_visibility(block_vis, npixel=npixel, frequency=[numpy.average(frequency)],
                                              nchan=nfreqwin,
                                              channel_bandwidth=[numpy.sum(channel_bandwidth)], cellsize=cellsize,
                                              phasecentre=phasecentre)
     
     self.components = create_low_test_skycomponents_from_gleam(flux_limit=flux_limit, phasecentre=phasecentre,
                                                                frequency=frequency,
                                                                polarisation_frame=PolarisationFrame('stokesI'),
                                                                radius=npixel * cellsize)
     self.beam = create_low_test_beam(self.beam)
     self.components = apply_beam_to_skycomponent(self.components, self.beam, flux_limit=flux_limit / 100.0)
     print("Number of components %d" % len(self.components))
     
     self.vis = copy_visibility(block_vis, zero=True)
     gt = create_gaintable_from_blockvisibility(block_vis, timeslice='auto')
     for i, sc in enumerate(self.components):
         if sc.flux[0, 0] > 10:
             sc.flux[...] /= 10.0
         print('Component %d, flux = %s' % (i, str(sc.flux[0, 0])))
         component_vis = copy_visibility(block_vis, zero=True)
         gt = simulate_gaintable(gt, amplitude_error=0.0, phase_error=0.1, seed=None)
         component_vis = predict_skycomponent_visibility(component_vis, sc)
         component_vis = apply_gaintable(component_vis, gt)
         self.vis.data['vis'][...] += component_vis.data['vis'][...]
     
     # Do an isoplanatic selfcal
     self.model_vis = copy_visibility(self.vis, zero=True)
     self.model_vis = predict_skycomponent_visibility(self.model_vis, self.components)
     if doiso:
         gt = solve_gaintable(self.vis, self.model_vis, phase_only=True, timeslice='auto')
         self.vis = apply_gaintable(self.vis, gt, inverse=True)
     
     self.model_vis = convert_blockvisibility_to_visibility(self.model_vis)
     self.model_vis, _, _ = weight_visibility(self.model_vis, self.beam)
     self.dirty_model, sumwt = invert_function(self.model_vis, self.beam, context='2d')
     export_image_to_fits(self.dirty_model, "%s/test_sagecal-model_dirty.fits" % self.dir)
     
     lvis = convert_blockvisibility_to_visibility(self.vis)
     lvis, _, _ = weight_visibility(lvis, self.beam)
     dirty, sumwt = invert_function(lvis, self.beam, context='2d')
     print(qa_image(dirty))
     export_image_to_fits(dirty, "%s/test_sagecal-initial_dirty.fits" % self.dir)