void oskar_telescope_set_noise_freq(oskar_Telescope* model,
        double start_hz, double inc_hz, int num_channels, int* status)
{
    int i;
    oskar_Mem* noise_freq_hz;
    noise_freq_hz = oskar_mem_create(model->precision, OSKAR_CPU,
            num_channels, status);
    if (*status) return;
    if (model->precision == OSKAR_DOUBLE)
    {
        double* f = oskar_mem_double(noise_freq_hz, status);
        for (i = 0; i < num_channels; ++i) f[i] = start_hz + i * inc_hz;
    }
    else
    {
        float* f = oskar_mem_float(noise_freq_hz, status);
        for (i = 0; i < num_channels; ++i) f[i] = start_hz + i * inc_hz;
    }

    /* Set noise frequency for all top-level stations. */
    for (i = 0; i < model->num_stations; ++i)
    {
        oskar_Mem* t;
        t = oskar_station_noise_freq_hz(model->station[i]);
        oskar_mem_realloc(t, num_channels, status);
        oskar_mem_copy(t, noise_freq_hz, status);
    }
    oskar_mem_free(noise_freq_hz, status);
}
Beispiel #2
0
void oskar_fft_exec(oskar_FFT* h, oskar_Mem* data, int* status)
{
    oskar_Mem *data_copy = 0, *data_ptr = data;
    if (oskar_mem_location(data) != h->location)
    {
        data_copy = oskar_mem_create_copy(data, h->location, status);
        data_ptr = data_copy;
    }
    if (h->location == OSKAR_CPU)
    {
        if (h->num_dim == 1)
        {
            *status = OSKAR_ERR_FUNCTION_NOT_AVAILABLE;
        }
        else if (h->num_dim == 2)
        {
            if (h->precision == OSKAR_DOUBLE)
                oskar_fftpack_cfft2f(h->dim_size, h->dim_size, h->dim_size,
                        oskar_mem_double(data_ptr, status),
                        oskar_mem_double(h->fftpack_wsave, status),
                        oskar_mem_double(h->fftpack_work, status));
            else
                oskar_fftpack_cfft2f_f(h->dim_size, h->dim_size, h->dim_size,
                        oskar_mem_float(data_ptr, status),
                        oskar_mem_float(h->fftpack_wsave, status),
                        oskar_mem_float(h->fftpack_work, status));
            /* This step not needed for W-kernel generation, so turn it off. */
            if (h->ensure_consistent_norm)
                oskar_mem_scale_real(data_ptr, (double)h->num_cells_total,
                        0, h->num_cells_total, status);
        }
    }
    else if (h->location == OSKAR_GPU)
    {
#ifdef OSKAR_HAVE_CUDA
        if (h->precision == OSKAR_DOUBLE)
            cufftExecZ2Z(h->cufft_plan,
                    (cufftDoubleComplex*) oskar_mem_void(data_ptr),
                    (cufftDoubleComplex*) oskar_mem_void(data_ptr),
                    CUFFT_FORWARD);
        else
            cufftExecC2C(h->cufft_plan,
                    (cufftComplex*) oskar_mem_void(data_ptr),
                    (cufftComplex*) oskar_mem_void(data_ptr),
                    CUFFT_FORWARD);
#endif
    }
    else
        *status = OSKAR_ERR_BAD_LOCATION;
    if (oskar_mem_location(data) != h->location)
        oskar_mem_copy(data, data_ptr, status);
    oskar_mem_free(data_copy, status);
}
Beispiel #3
0
void oskar_imager_finalise(oskar_Imager* h,
        int num_output_images, oskar_Mem** output_images,
        int num_output_grids, oskar_Mem** output_grids, int* status)
{
    int t, c, p, i;
    if (*status || !h->planes) return;

    /* Adjust normalisation if required. */
    if (h->scale_norm_with_num_input_files)
    {
        for (i = 0; i < h->num_planes; ++i)
            h->plane_norm[i] /= h->num_files;
    }

    /* Copy grids to output grid planes if given. */
    for (i = 0; (i < h->num_planes) && (i < num_output_grids); ++i)
    {
        oskar_mem_copy(output_grids[i], h->planes[i], status);
        oskar_mem_scale_real(output_grids[i], 1.0 / h->plane_norm[i], status);
    }

    /* Check if images are required. */
    if (h->fits_file[0] || output_images)
    {
        /* Finalise all the planes. */
        for (i = 0; i < h->num_planes; ++i)
        {
            oskar_imager_finalise_plane(h,
                    h->planes[i], h->plane_norm[i], status);
            oskar_imager_trim_image(h->planes[i],
                    h->grid_size, h->image_size, status);
        }

        /* Copy images to output image planes if given. */
        for (i = 0; (i < h->num_planes) && (i < num_output_images); ++i)
        {
            memcpy(oskar_mem_void(output_images[i]),
                    oskar_mem_void_const(h->planes[i]), h->image_size *
                    h->image_size * oskar_mem_element_size(h->imager_prec));
        }

        /* Write to files if required. */
        for (t = 0, i = 0; t < h->im_num_times; ++t)
            for (c = 0; c < h->im_num_channels; ++c)
                for (p = 0; p < h->im_num_pols; ++p, ++i)
                    write_plane(h, h->planes[i], t, c, p, status);
    }

    /* Reset imager memory. */
    oskar_imager_reset_cache(h, status);
}
Beispiel #4
0
oskar_Mem* oskar_mem_create_copy_from_raw(void* ptr, int type, int location,
        size_t num_elements, int* status)
{
    oskar_Mem *m = 0, *t = 0;
    if (*status) return 0;

    /* Create the handles. */
    m = oskar_mem_create(type, location, num_elements, status);
    t = oskar_mem_create_alias_from_raw(ptr, type, location, num_elements,
            status);
    oskar_mem_copy(m, t, status);
    oskar_mem_free(t, status);

    /* Return a handle the structure .*/
    return m;
}
void oskar_binary_read_mem_ext(oskar_Binary* handle, oskar_Mem* mem,
        const char* name_group, const char* name_tag, int user_index,
        int* status)
{
    int type;
    oskar_Mem *temp = 0, *data = 0;
    size_t size_bytes = 0, element_size = 0;

    /* Check if safe to proceed. */
    if (*status) return;

    /* Get the data type. */
    type = oskar_mem_type(mem);

    /* Initialise temporary (to zero length). */
    temp = oskar_mem_create(type, OSKAR_CPU, 0, status);

    /* Check if data is in CPU or GPU memory. */
    data = (oskar_mem_location(mem) == OSKAR_CPU) ? mem : temp;

    /* Query the tag index to find out how big the block is. */
    element_size = oskar_mem_element_size(type);
    oskar_binary_query_ext(handle, (unsigned char)type,
            name_group, name_tag, user_index, &size_bytes, status);

    /* Resize memory block if necessary, so that it can hold the data. */
    oskar_mem_realloc(data, size_bytes / element_size, status);

    /* Load the memory. */
    oskar_binary_read_ext(handle, (unsigned char)type, name_group, name_tag,
            user_index, size_bytes, oskar_mem_void(data), status);

    /* Copy to GPU memory if required. */
    if (oskar_mem_location(mem) != OSKAR_CPU)
        oskar_mem_copy(mem, temp, status);

    /* Free the temporary. */
    oskar_mem_free(temp, status);
}
void oskar_telescope_set_noise_rms(oskar_Telescope* model,
        double start, double end, int* status)
{
    int i, j, num_channels;
    double inc;
    oskar_Station* s;
    oskar_Mem *noise_rms_jy, *h;

    /* Set noise RMS for all top-level stations. */
    if (*status) return;
    for (i = 0; i < model->num_stations; ++i)
    {
        s = model->station[i];
        h = oskar_station_noise_rms_jy(s);
        num_channels = (int)oskar_mem_length(oskar_station_noise_freq_hz(s));
        if (num_channels == 0)
        {
            *status = OSKAR_ERR_OUT_OF_RANGE;
            return;
        }
        oskar_mem_realloc(h, num_channels, status);
        noise_rms_jy = oskar_mem_create(model->precision, OSKAR_CPU,
                num_channels, status);
        inc = (end - start) / (double)num_channels;
        if (model->precision == OSKAR_DOUBLE)
        {
            double* r = oskar_mem_double(noise_rms_jy, status);
            for (j = 0; j < num_channels; ++j) r[j] = start + j * inc;
        }
        else
        {
            float* r = oskar_mem_float(noise_rms_jy, status);
            for (j = 0; j < num_channels; ++j) r[j] = start + j * inc;
        }
        oskar_mem_copy(h, noise_rms_jy, status);
        oskar_mem_free(noise_rms_jy, status);
    }
}
oskar_Telescope* oskar_telescope_create_copy(const oskar_Telescope* src,
        int location, int* status)
{
    int i = 0;
    oskar_Telescope* telescope;

    /* Create a new, empty model. */
    telescope = oskar_telescope_create(oskar_telescope_precision(src),
            location, 0, status);

    /* Copy private meta-data. */
    telescope->precision = src->precision;
    telescope->mem_location = location;

    /* Copy the meta-data. */
    telescope->pol_mode = src->pol_mode;
    telescope->num_stations = src->num_stations;
    telescope->max_station_size = src->max_station_size;
    telescope->max_station_depth = src->max_station_depth;
    telescope->identical_stations = src->identical_stations;
    telescope->allow_station_beam_duplication = src->allow_station_beam_duplication;
    telescope->enable_numerical_patterns = src->enable_numerical_patterns;
    telescope->lon_rad = src->lon_rad;
    telescope->lat_rad = src->lat_rad;
    telescope->alt_metres = src->alt_metres;
    telescope->pm_x_rad = src->pm_x_rad;
    telescope->pm_y_rad = src->pm_y_rad;
    telescope->phase_centre_coord_type = src->phase_centre_coord_type;
    telescope->phase_centre_ra_rad = src->phase_centre_ra_rad;
    telescope->phase_centre_dec_rad = src->phase_centre_dec_rad;
    telescope->channel_bandwidth_hz = src->channel_bandwidth_hz;
    telescope->time_average_sec = src->time_average_sec;
    telescope->uv_filter_min = src->uv_filter_min;
    telescope->uv_filter_max = src->uv_filter_max;
    telescope->uv_filter_units = src->uv_filter_units;
    telescope->noise_enabled = src->noise_enabled;
    telescope->noise_seed = src->noise_seed;

    /* Copy the coordinates. */
    oskar_mem_copy(telescope->station_true_x_offset_ecef_metres,
            src->station_true_x_offset_ecef_metres, status);
    oskar_mem_copy(telescope->station_true_y_offset_ecef_metres,
            src->station_true_y_offset_ecef_metres, status);
    oskar_mem_copy(telescope->station_true_z_offset_ecef_metres,
            src->station_true_z_offset_ecef_metres, status);
    oskar_mem_copy(telescope->station_true_x_enu_metres,
            src->station_true_x_enu_metres, status);
    oskar_mem_copy(telescope->station_true_y_enu_metres,
            src->station_true_y_enu_metres, status);
    oskar_mem_copy(telescope->station_true_z_enu_metres,
            src->station_true_z_enu_metres, status);
    oskar_mem_copy(telescope->station_measured_x_offset_ecef_metres,
            src->station_measured_x_offset_ecef_metres, status);
    oskar_mem_copy(telescope->station_measured_y_offset_ecef_metres,
            src->station_measured_y_offset_ecef_metres, status);
    oskar_mem_copy(telescope->station_measured_z_offset_ecef_metres,
            src->station_measured_z_offset_ecef_metres, status);
    oskar_mem_copy(telescope->station_measured_x_enu_metres,
            src->station_measured_x_enu_metres, status);
    oskar_mem_copy(telescope->station_measured_y_enu_metres,
            src->station_measured_y_enu_metres, status);
    oskar_mem_copy(telescope->station_measured_z_enu_metres,
            src->station_measured_z_enu_metres, status);

    /* Copy each station. */
    telescope->station = malloc(src->num_stations * sizeof(oskar_Station*));
    for (i = 0; i < src->num_stations; ++i)
    {
        telescope->station[i] = oskar_station_create_copy(
                oskar_telescope_station_const(src, i), location, status);
    }

    /* Return pointer to data structure. */
    return telescope;
}
Beispiel #8
0
static void set_up_vis_header(oskar_Simulator* h, int* status)
{
    int num_stations, vis_type;
    const double rad2deg = 180.0/M_PI;
    int write_autocorr = 0, write_crosscorr = 0;
    if (*status) return;

    /* Check type of correlations to produce. */
    if (h->correlation_type == 'C')
        write_crosscorr = 1;
    else if (h->correlation_type == 'A')
        write_autocorr = 1;
    else if (h->correlation_type == 'B')
    {
        write_autocorr = 1;
        write_crosscorr = 1;
    }

    /* Create visibility header. */
    num_stations = oskar_telescope_num_stations(h->tel);
    vis_type = h->prec | OSKAR_COMPLEX;
    if (oskar_telescope_pol_mode(h->tel) == OSKAR_POL_MODE_FULL)
        vis_type |= OSKAR_MATRIX;
    h->header = oskar_vis_header_create(vis_type, h->prec,
            h->max_times_per_block, h->num_time_steps, h->num_channels,
            h->num_channels, num_stations, write_autocorr, write_crosscorr,
            status);

    /* Add metadata from settings. */
    oskar_vis_header_set_freq_start_hz(h->header, h->freq_start_hz);
    oskar_vis_header_set_freq_inc_hz(h->header, h->freq_inc_hz);
    oskar_vis_header_set_time_start_mjd_utc(h->header, h->time_start_mjd_utc);
    oskar_vis_header_set_time_inc_sec(h->header, h->time_inc_sec);

    /* Add settings file contents if defined. */
    if (h->settings_path)
    {
        oskar_Mem* temp;
        temp = oskar_mem_read_binary_raw(h->settings_path,
                OSKAR_CHAR, OSKAR_CPU, status);
        oskar_mem_copy(oskar_vis_header_settings(h->header), temp, status);
        oskar_mem_free(temp, status);
    }

    /* Copy other metadata from telescope model. */
    oskar_vis_header_set_time_average_sec(h->header,
            oskar_telescope_time_average_sec(h->tel));
    oskar_vis_header_set_channel_bandwidth_hz(h->header,
            oskar_telescope_channel_bandwidth_hz(h->tel));
    oskar_vis_header_set_phase_centre(h->header, 0,
            oskar_telescope_phase_centre_ra_rad(h->tel) * rad2deg,
            oskar_telescope_phase_centre_dec_rad(h->tel) * rad2deg);
    oskar_vis_header_set_telescope_centre(h->header,
            oskar_telescope_lon_rad(h->tel) * rad2deg,
            oskar_telescope_lat_rad(h->tel) * rad2deg,
            oskar_telescope_alt_metres(h->tel));
    oskar_mem_copy(oskar_vis_header_station_x_offset_ecef_metres(h->header),
            oskar_telescope_station_true_x_offset_ecef_metres_const(h->tel),
            status);
    oskar_mem_copy(oskar_vis_header_station_y_offset_ecef_metres(h->header),
            oskar_telescope_station_true_y_offset_ecef_metres_const(h->tel),
            status);
    oskar_mem_copy(oskar_vis_header_station_z_offset_ecef_metres(h->header),
            oskar_telescope_station_true_z_offset_ecef_metres_const(h->tel),
            status);
}
Beispiel #9
0
void oskar_imager_finalise_plane(oskar_Imager* h, oskar_Mem* plane,
        double plane_norm, int* status)
{
    int size, num_cells;
    DeviceData* d;
    if (*status) return;

    /* Apply normalisation. */
    if (plane_norm > 0.0 || plane_norm < 0.0)
        oskar_mem_scale_real(plane, 1.0 / plane_norm, status);
    if (h->algorithm == OSKAR_ALGORITHM_DFT_2D ||
            h->algorithm == OSKAR_ALGORITHM_DFT_3D)
        return;

    /* Check plane is complex type, as plane must be gridded visibilities. */
    if (!oskar_mem_is_complex(plane))
    {
        *status = OSKAR_ERR_TYPE_MISMATCH;
        return;
    }

    /* Make image using FFT and apply grid correction. */
    size = h->grid_size;
    num_cells = size * size;
    d = &h->d[0];
    if (oskar_mem_precision(plane) == OSKAR_DOUBLE)
    {
        oskar_fftphase_cd(size, size, oskar_mem_double(plane, status));
        if (h->fft_on_gpu)
        {
#ifdef OSKAR_HAVE_CUDA
            oskar_device_set(h->cuda_device_ids[0], status);
            oskar_mem_copy(d->plane_gpu, plane, status);
            cufftExecZ2Z(h->cufft_plan, oskar_mem_void(d->plane_gpu),
                    oskar_mem_void(d->plane_gpu), CUFFT_FORWARD);
            oskar_mem_copy(plane, d->plane_gpu, status);
#else
            *status = OSKAR_ERR_CUDA_NOT_AVAILABLE;
#endif
        }
        else
        {
            oskar_fftpack_cfft2f(size, size, size,
                    oskar_mem_double(plane, status),
                    oskar_mem_double(h->fftpack_wsave, status),
                    oskar_mem_double(h->fftpack_work, status));
            oskar_mem_scale_real(plane, (double)num_cells, status);
        }
        oskar_fftphase_cd(size, size, oskar_mem_double(plane, status));
        oskar_grid_correction_d(size, oskar_mem_double(h->corr_func, status),
                oskar_mem_double(plane, status));
    }
    else
    {
        oskar_fftphase_cf(size, size, oskar_mem_float(plane, status));
        if (h->fft_on_gpu)
        {
#ifdef OSKAR_HAVE_CUDA
            oskar_device_set(h->cuda_device_ids[0], status);
            oskar_mem_copy(d->plane_gpu, plane, status);
            cufftExecC2C(h->cufft_plan, oskar_mem_void(d->plane_gpu),
                    oskar_mem_void(d->plane_gpu), CUFFT_FORWARD);
            oskar_mem_copy(plane, d->plane_gpu, status);
#else
            *status = OSKAR_ERR_CUDA_NOT_AVAILABLE;
#endif
        }
        else
        {
            oskar_fftpack_cfft2f_f(size, size, size,
                    oskar_mem_float(plane, status),
                    oskar_mem_float(h->fftpack_wsave, status),
                    oskar_mem_float(h->fftpack_work, status));
            oskar_mem_scale_real(plane, (double)num_cells, status);
        }
        oskar_fftphase_cf(size, size, oskar_mem_float(plane, status));
        oskar_grid_correction_f(size, oskar_mem_double(h->corr_func, status),
                oskar_mem_float(plane, status));
    }
}
oskar_Station* oskar_station_create_copy(const oskar_Station* src,
        int location, int* status)
{
    int i = 0;
    oskar_Station* model = 0;

    /* Check if safe to proceed. */
    if (*status) return model;

    /* Create the new model. */
    model = oskar_station_create(oskar_station_precision(src), location,
            oskar_station_num_elements(src), status);

    /* Set meta-data. */
    model->unique_id = src->unique_id;
    model->precision = src->precision;
    model->mem_location = location;

    /* Copy common station parameters. */
    model->station_type = src->station_type;
    model->normalise_final_beam = src->normalise_final_beam;
    model->lon_rad = src->lon_rad;
    model->lat_rad = src->lat_rad;
    model->alt_metres = src->alt_metres;
    model->pm_x_rad = src->pm_x_rad;
    model->pm_y_rad = src->pm_y_rad;
    model->beam_lon_rad = src->beam_lon_rad;
    model->beam_lat_rad = src->beam_lat_rad;
    model->beam_coord_type = src->beam_coord_type;
    oskar_mem_copy(model->noise_freq_hz, src->noise_freq_hz, status);
    oskar_mem_copy(model->noise_rms_jy, src->noise_rms_jy, status);

    /* Copy aperture array data, except num_element_types (done later). */
    model->identical_children = src->identical_children;
    model->num_elements = src->num_elements;
    model->normalise_array_pattern = src->normalise_array_pattern;
    model->enable_array_pattern = src->enable_array_pattern;
    model->common_element_orientation = src->common_element_orientation;
    model->array_is_3d = src->array_is_3d;
    model->apply_element_errors = src->apply_element_errors;
    model->apply_element_weight = src->apply_element_weight;
    model->seed_time_variable_errors = src->seed_time_variable_errors;
    model->num_permitted_beams = src->num_permitted_beams;

    /* Copy Gaussian station beam data. */
    model->gaussian_beam_fwhm_rad = src->gaussian_beam_fwhm_rad;
    model->gaussian_beam_reference_freq_hz = src->gaussian_beam_reference_freq_hz;

    /* Copy memory blocks. */
    oskar_mem_copy(model->element_true_x_enu_metres,
            src->element_true_x_enu_metres, status);
    oskar_mem_copy(model->element_true_y_enu_metres,
            src->element_true_y_enu_metres, status);
    oskar_mem_copy(model->element_true_z_enu_metres,
            src->element_true_z_enu_metres, status);
    oskar_mem_copy(model->element_measured_x_enu_metres,
            src->element_measured_x_enu_metres, status);
    oskar_mem_copy(model->element_measured_y_enu_metres,
            src->element_measured_y_enu_metres, status);
    oskar_mem_copy(model->element_measured_z_enu_metres,
            src->element_measured_z_enu_metres, status);
    oskar_mem_copy(model->element_weight, src->element_weight, status);
    oskar_mem_copy(model->element_gain, src->element_gain, status);
    oskar_mem_copy(model->element_gain_error, src->element_gain_error, status);
    oskar_mem_copy(model->element_phase_offset_rad,
            src->element_phase_offset_rad, status);
    oskar_mem_copy(model->element_phase_error_rad,
            src->element_phase_error_rad, status);
    oskar_mem_copy(model->element_x_alpha_cpu,
            src->element_x_alpha_cpu, status);
    oskar_mem_copy(model->element_x_beta_cpu,
            src->element_x_beta_cpu, status);
    oskar_mem_copy(model->element_x_gamma_cpu,
            src->element_x_gamma_cpu, status);
    oskar_mem_copy(model->element_y_alpha_cpu,
            src->element_y_alpha_cpu, status);
    oskar_mem_copy(model->element_y_beta_cpu,
            src->element_y_beta_cpu, status);
    oskar_mem_copy(model->element_y_gamma_cpu,
            src->element_y_gamma_cpu, status);
    oskar_mem_copy(model->element_types, src->element_types, status);
    oskar_mem_copy(model->element_types_cpu, src->element_types_cpu, status);
    oskar_mem_copy(model->element_mount_types_cpu, src->element_mount_types_cpu, status);
    oskar_mem_copy(model->permitted_beam_az_rad, src->permitted_beam_az_rad, status);
    oskar_mem_copy(model->permitted_beam_el_rad, src->permitted_beam_el_rad, status);

    /* Copy element models, if set. */
    if (oskar_station_has_element(src))
    {
        /* Ensure enough space for element model data. */
        oskar_station_resize_element_types(model, src->num_element_types,
                status);

        /* Copy the element model data. */
        for (i = 0; i < src->num_element_types; ++i)
        {
            oskar_element_copy(model->element[i], src->element[i], status);
        }
    }

    /* Recursively copy child stations. */
    if (oskar_station_has_child(src))
    {
        model->child = malloc(src->num_elements * sizeof(oskar_Station*));
        if (!model->child)
        {
            *status = OSKAR_ERR_MEMORY_ALLOC_FAILURE;
            return model;
        }

        for (i = 0; i < src->num_elements; ++i)
        {
            model->child[i] = oskar_station_create_copy(
                    oskar_station_child_const(src, i), location, status);
        }
    }

    return model;
}
Beispiel #11
0
/*
 * Translation layer from new file format to old structure.
 * This will be deleted when the old oskar_Vis structure is fully retired.
 */
oskar_Vis* oskar_vis_read_new(oskar_Binary* h, int* status)
{
    oskar_VisHeader* hdr = 0;
    oskar_VisBlock* blk = 0;
    oskar_Vis* vis = 0;
    oskar_Mem* amp = 0;
    const oskar_Mem* xcorr = 0;
    int amp_type, max_times_per_block, num_channels, num_stations, num_times;
    int i, num_blocks;
    double freq_ref_hz, freq_inc_hz, time_ref_mjd_utc, time_inc_sec;

    /* Try to read the new header. */
    hdr = oskar_vis_header_read(h, status);
    if (*status)
    {
        oskar_vis_header_free(hdr, status);
        return 0;
    }

    /* Create the old vis structure. */
    amp_type = oskar_vis_header_amp_type(hdr);
    max_times_per_block = oskar_vis_header_max_times_per_block(hdr);
    num_channels = oskar_vis_header_num_channels_total(hdr);
    num_stations = oskar_vis_header_num_stations(hdr);
    num_times = oskar_vis_header_num_times_total(hdr);
    vis = oskar_vis_create(amp_type, OSKAR_CPU, num_channels, num_times,
            num_stations, status);
    if (*status)
    {
        oskar_vis_header_free(hdr, status);
        oskar_vis_free(vis, status);
        return 0;
    }

    /* Copy station coordinates and metadata. */
    freq_ref_hz = oskar_vis_header_freq_start_hz(hdr);
    freq_inc_hz = oskar_vis_header_freq_inc_hz(hdr);
    time_ref_mjd_utc = oskar_vis_header_time_start_mjd_utc(hdr);
    time_inc_sec = oskar_vis_header_time_inc_sec(hdr);
    oskar_mem_copy(oskar_vis_station_x_offset_ecef_metres(vis),
            oskar_vis_header_station_x_offset_ecef_metres_const(hdr), status);
    oskar_mem_copy(oskar_vis_station_y_offset_ecef_metres(vis),
            oskar_vis_header_station_y_offset_ecef_metres_const(hdr), status);
    oskar_mem_copy(oskar_vis_station_z_offset_ecef_metres(vis),
            oskar_vis_header_station_z_offset_ecef_metres_const(hdr), status);
    oskar_mem_copy(oskar_vis_settings(vis),
            oskar_vis_header_settings_const(hdr), status);
    oskar_mem_copy(oskar_vis_telescope_path(vis),
            oskar_vis_header_telescope_path_const(hdr), status);
    oskar_vis_set_channel_bandwidth_hz(vis,
            oskar_vis_header_channel_bandwidth_hz(hdr));
    oskar_vis_set_freq_inc_hz(vis, freq_inc_hz);
    oskar_vis_set_freq_start_hz(vis, freq_ref_hz);
    oskar_vis_set_phase_centre(vis,
            oskar_vis_header_phase_centre_ra_deg(hdr),
            oskar_vis_header_phase_centre_dec_deg(hdr));
    oskar_vis_set_telescope_position(vis,
            oskar_vis_header_telescope_lon_deg(hdr),
            oskar_vis_header_telescope_lat_deg(hdr),
            oskar_vis_header_telescope_alt_metres(hdr));
    oskar_vis_set_time_average_sec(vis,
            oskar_vis_header_time_average_sec(hdr));
    oskar_vis_set_time_inc_sec(vis, time_inc_sec);
    oskar_vis_set_time_start_mjd_utc(vis, time_ref_mjd_utc);

    /* Create a visibility block to read into. */
    blk = oskar_vis_block_create_from_header(OSKAR_CPU, hdr, status);
    amp = oskar_vis_amplitude(vis);
    xcorr = oskar_vis_block_cross_correlations_const(blk);

    /* Work out the number of blocks. */
    num_blocks = (num_times + max_times_per_block - 1) / max_times_per_block;
    for (i = 0; i < num_blocks; ++i)
    {
        int block_length, num_baselines, time_offset, total_baselines, t, c;

        /* Read the block. */
        oskar_vis_block_read(blk, hdr, h, i, status);
        num_baselines = oskar_vis_block_num_baselines(blk);
        block_length = oskar_vis_block_num_times(blk);

        /* Copy the baseline coordinate data. */
        time_offset = i * max_times_per_block * num_baselines;
        total_baselines = num_baselines * block_length;
        oskar_mem_copy_contents(oskar_vis_baseline_uu_metres(vis),
                oskar_vis_block_baseline_uu_metres_const(blk),
                time_offset, 0, total_baselines, status);
        oskar_mem_copy_contents(oskar_vis_baseline_vv_metres(vis),
                oskar_vis_block_baseline_vv_metres_const(blk),
                time_offset, 0, total_baselines, status);
        oskar_mem_copy_contents(oskar_vis_baseline_ww_metres(vis),
                oskar_vis_block_baseline_ww_metres_const(blk),
                time_offset, 0, total_baselines, status);

        /* Fill the array in the old dimension order. */
        for (t = 0; t < block_length; ++t)
        {
            for (c = 0; c < num_channels; ++c)
            {
                oskar_mem_copy_contents(amp, xcorr, num_baselines *
                        (c * num_times + i * max_times_per_block + t),
                        num_baselines * (t * num_channels + c),
                        num_baselines, status);
            }
        }
    }

    /* Clean up and return. */
    oskar_vis_block_free(blk, status);
    oskar_vis_header_free(hdr, status);
    return vis;
}