예제 #1
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);
}
예제 #2
0
static void evaluate_station_ECEF_coords(
        double* station_x, double* station_y, double* station_z,
        int stationID, const oskar_Telescope* telescope)
{
    double st_x, st_y, st_z;
    double lon, lat, alt;
    const oskar_Station* station;
    const void *x_, *y_, *z_;

    x_ = oskar_mem_void_const(
            oskar_telescope_station_true_x_offset_ecef_metres_const(telescope));
    y_ = oskar_mem_void_const(
            oskar_telescope_station_true_y_offset_ecef_metres_const(telescope));
    z_ = oskar_mem_void_const(
            oskar_telescope_station_true_z_offset_ecef_metres_const(telescope));
    station = oskar_telescope_station_const(telescope, stationID);
    lon = oskar_station_lon_rad(station);
    lat = oskar_station_lat_rad(station);
    alt = oskar_station_alt_metres(station);

    if (oskar_mem_type(
            oskar_telescope_station_true_x_offset_ecef_metres_const(telescope)) ==
            OSKAR_DOUBLE)
    {
        st_x = ((const double*)x_)[stationID];
        st_y = ((const double*)y_)[stationID];
        st_z = ((const double*)z_)[stationID];
    }
    else
    {
        st_x = (double)((const float*)x_)[stationID];
        st_y = (double)((const float*)y_)[stationID];
        st_z = (double)((const float*)z_)[stationID];
    }

    oskar_convert_offset_ecef_to_ecef(1, &st_x, &st_y, &st_z, lon, lat, alt,
            station_x, station_y, station_z);
}
예제 #3
0
void oskar_imager_rotate_vis(size_t num_vis, const oskar_Mem* uu,
        const oskar_Mem* vv, const oskar_Mem* ww, oskar_Mem* amps,
        const double delta_l, const double delta_m, const double delta_n)
{
    size_t i;

    if (oskar_mem_precision(amps) == OSKAR_DOUBLE)
    {
        const double *u, *v, *w;
        double2* a;
        u = (const double*)oskar_mem_void_const(uu);
        v = (const double*)oskar_mem_void_const(vv);
        w = (const double*)oskar_mem_void_const(ww);
        a = (double2*)oskar_mem_void(amps);

        for (i = 0; i < num_vis; ++i)
        {
            double arg, phase_re, phase_im, re, im;
            arg = 2.0*M_PI * (u[i] * delta_l + v[i] * delta_m + w[i] * delta_n);
            phase_re = cos(arg);
            phase_im = sin(arg);
            re = a[i].x * phase_re - a[i].y * phase_im;
            im = a[i].x * phase_im + a[i].y * phase_re;
            a[i].x = re;
            a[i].y = im;
        }
    }
    else
    {
        const float *u, *v, *w;
        float2* a;
        u = (const float*)oskar_mem_void_const(uu);
        v = (const float*)oskar_mem_void_const(vv);
        w = (const float*)oskar_mem_void_const(ww);
        a = (float2*)oskar_mem_void(amps);

        for (i = 0; i < num_vis; ++i)
        {
            float arg, phase_re, phase_im, re, im;
            arg = 2.0*M_PI * (u[i] * delta_l + v[i] * delta_m + w[i] * delta_n);
            phase_re = cos(arg);
            phase_im = sin(arg);
            re = a[i].x * phase_re - a[i].y * phase_im;
            im = a[i].x * phase_im + a[i].y * phase_re;
            a[i].x = re;
            a[i].y = im;
        }
    }
}
void oskar_imager_update_plane_wproj(oskar_Imager* h, size_t num_vis,
        const oskar_Mem* uu, const oskar_Mem* vv, const oskar_Mem* ww,
        const oskar_Mem* amps, const oskar_Mem* weight, oskar_Mem* plane,
        double* plane_norm, size_t* num_skipped, int* status)
{
    int grid_size;
    size_t num_cells;
    if (*status) return;
    grid_size = oskar_imager_plane_size(h);
    num_cells = grid_size * grid_size;
    if (oskar_mem_precision(plane) != h->imager_prec)
        *status = OSKAR_ERR_TYPE_MISMATCH;
    if (oskar_mem_length(plane) < num_cells)
        oskar_mem_realloc(plane, num_cells, status);
    if (*status) return;
    if (h->imager_prec == OSKAR_DOUBLE)
        oskar_grid_wproj_d(h->num_w_planes,
                oskar_mem_int_const(h->w_support, status),
                h->oversample, h->conv_size_half,
                oskar_mem_double_const(h->w_kernels, status), num_vis,
                oskar_mem_double_const(uu, status),
                oskar_mem_double_const(vv, status),
                oskar_mem_double_const(ww, status),
                oskar_mem_double_const(amps, status),
                oskar_mem_double_const(weight, status),
                h->cellsize_rad, h->w_scale,
                grid_size, num_skipped, plane_norm,
                oskar_mem_double(plane, status));
    else
    {
        char *fname = 0;
#if SAVE_INPUT_DAT || SAVE_OUTPUT_DAT || SAVE_GRID
        fname = (char*) calloc(20 +
                h->input_root ? strlen(h->input_root) : 0, 1);
#endif
#if SAVE_INPUT_DAT
        {
            const float cellsize_rad_tmp = (const float) (h->cellsize_rad);
            const float w_scale_tmp = (const float) (h->w_scale);
            const size_t num_w_planes = (size_t) (h->num_w_planes);
            FILE* f;
            sprintf(fname, "%s_INPUT.dat", h->input_root);
            f = fopen(fname, "wb");
            fwrite(&num_w_planes, sizeof(size_t), 1, f);
            fwrite(oskar_mem_void_const(h->w_support),
                    sizeof(int), num_w_planes, f);
            fwrite(&h->oversample, sizeof(int), 1, f);
            fwrite(&h->conv_size_half, sizeof(int), 1, f);
            fwrite(oskar_mem_void_const(h->w_kernels), 2 * sizeof(float),
                    h->num_w_planes * h->conv_size_half * h->conv_size_half, f);
            fwrite(&num_vis, sizeof(size_t), 1, f);
            fwrite(oskar_mem_void_const(uu), sizeof(float), num_vis, f);
            fwrite(oskar_mem_void_const(vv), sizeof(float), num_vis, f);
            fwrite(oskar_mem_void_const(ww), sizeof(float), num_vis, f);
            fwrite(oskar_mem_void_const(amps), 2 * sizeof(float), num_vis, f);
            fwrite(oskar_mem_void_const(weight), sizeof(float), num_vis, f);
            fwrite(&cellsize_rad_tmp, sizeof(float), 1, f);
            fwrite(&w_scale_tmp, sizeof(float), 1, f);
            fwrite(&grid_size, sizeof(int), 1, f);
            fclose(f);
        }
#endif
        oskar_grid_wproj_f(h->num_w_planes,
                oskar_mem_int_const(h->w_support, status),
                h->oversample, h->conv_size_half,
                oskar_mem_float_const(h->w_kernels, status), num_vis,
                oskar_mem_float_const(uu, status),
                oskar_mem_float_const(vv, status),
                oskar_mem_float_const(ww, status),
                oskar_mem_float_const(amps, status),
                oskar_mem_float_const(weight, status),
                (float) (h->cellsize_rad), (float) (h->w_scale),
                grid_size, num_skipped, plane_norm,
                oskar_mem_float(plane, status));
#if SAVE_OUTPUT_DAT
        {
            FILE* f;
            sprintf(fname, "%s_OUTPUT.dat", h->input_root);
            f = fopen(fname, "wb");
            fwrite(num_skipped, sizeof(size_t), 1, f);
            fwrite(plane_norm, sizeof(double), 1, f);
            fwrite(&grid_size, sizeof(int), 1, f);
            fwrite(oskar_mem_void_const(plane), 2 * sizeof(float), num_cells, f);
            fclose(f);
        }
#endif
#if SAVE_GRID
        sprintf(fname, "%s_GRID", h->input_root);
        oskar_mem_write_fits_cube(plane, fname,
                grid_size, grid_size, 1, 0, status);
#endif
        free(fname);
    }
}
예제 #5
0
void oskar_mem_save_ascii(FILE* file, size_t num_mem,
        size_t offset, size_t num_elements, int* status, ...)
{
    int type;
    size_t i, j;
    va_list args;
    oskar_Mem** handles; /* Array of oskar_Mem pointers in CPU memory. */

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

    /* Check there are at least the number of specified elements in
     * each array. */
    va_start(args, status);
    for (i = 0; i < num_mem; ++i)
    {
        const oskar_Mem* mem;
        mem = va_arg(args, const oskar_Mem*);
        if (oskar_mem_length(mem) < num_elements)
            *status = OSKAR_ERR_DIMENSION_MISMATCH;
    }
    va_end(args);

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

    /* Allocate and set up the handle array. */
    handles = (oskar_Mem**) malloc(num_mem * sizeof(oskar_Mem*));
    va_start(args, status);
    for (i = 0; i < num_mem; ++i)
    {
        oskar_Mem* mem;
        mem = va_arg(args, oskar_Mem*);
        if (oskar_mem_location(mem) != OSKAR_CPU)
        {
            handles[i] = oskar_mem_create_copy(mem, OSKAR_CPU, status);
        }
        else
        {
            handles[i] = mem;
        }
    }
    va_end(args);

    for (j = 0; j < num_elements; ++j)
    {
        /* Break if error. */
        if (*status) break;

        for (i = 0; i < num_mem; ++i)
        {
            const void* data;
            data = oskar_mem_void_const(handles[i]);
            type = oskar_mem_type(handles[i]);
            switch (type)
            {
            case OSKAR_SINGLE:
            {
                fprintf(file, SDF, ((const float*)data)[j + offset]);
                continue;
            }
            case OSKAR_DOUBLE:
            {
                fprintf(file, SDD, ((const double*)data)[j + offset]);
                continue;
            }
            case OSKAR_SINGLE_COMPLEX:
            {
                float2 d;
                d = ((const float2*)data)[j + offset];
                fprintf(file, SDF SDF, d.x, d.y);
                continue;
            }
            case OSKAR_DOUBLE_COMPLEX:
            {
                double2 d;
                d = ((const double2*)data)[j + offset];
                fprintf(file, SDD SDD, d.x, d.y);
                continue;
            }
            case OSKAR_SINGLE_COMPLEX_MATRIX:
            {
                float4c d;
                d = ((const float4c*)data)[j + offset];
                fprintf(file, SDF SDF SDF SDF SDF SDF SDF SDF,
                        d.a.x, d.a.y, d.b.x, d.b.y, d.c.x, d.c.y, d.d.x, d.d.y);
                continue;
            }
            case OSKAR_DOUBLE_COMPLEX_MATRIX:
            {
                double4c d;
                d = ((const double4c*)data)[j + offset];
                fprintf(file, SDD SDD SDD SDD SDD SDD SDD SDD,
                        d.a.x, d.a.y, d.b.x, d.b.y, d.c.x, d.c.y, d.d.x, d.d.y);
                continue;
            }
            case OSKAR_CHAR:
            {
                putc(((const char*)data)[j + offset], file);
                continue;
            }
            case OSKAR_INT:
            {
                fprintf(file, "%5d ", ((const int*)data)[j + offset]);
                continue;
            }
            default:
            {
                *status = OSKAR_ERR_BAD_DATA_TYPE;
                continue;
            }
            }
        }
        putc('\n', file);
    }

    /* Free any temporary memory used by this function. */
    va_start(args, status);
    for (i = 0; i < num_mem; ++i)
    {
        const oskar_Mem* mem;
        mem = va_arg(args, const oskar_Mem*);
        if (oskar_mem_location(mem) != OSKAR_CPU)
        {
            oskar_mem_free(handles[i], status);
        }
    }
    va_end(args);

    /* Free the handle array. */
    free(handles);
}
예제 #6
0
const int* oskar_station_element_types_cpu_const(const oskar_Station* model)
{
    return (const int*) oskar_mem_void_const(model->element_types_cpu);
}
예제 #7
0
double oskar_station_element_y_gamma_rad(const oskar_Station* model,
        int index)
{
    return ((const double*)
            oskar_mem_void_const(model->element_y_gamma_cpu))[index];
}
예제 #8
0
void oskar_vis_block_write_ms(const oskar_VisBlock* blk,
        const oskar_VisHeader* header, oskar_MeasurementSet* ms, int* status)
{
    const oskar_Mem *in_acorr, *in_xcorr, *in_uu, *in_vv, *in_ww;
    oskar_Mem *temp_vis = 0, *temp_uu = 0, *temp_vv = 0, *temp_ww = 0;
    double exposure_sec, interval_sec, t_start_mjd, t_start_sec;
    double ra_rad, dec_rad, ref_freq_hz;
    unsigned int a1, a2, num_baseln_in, num_baseln_out, num_channels;
    unsigned int num_pols_in, num_pols_out, num_stations, num_times, b, c, t;
    unsigned int i, i_out, prec, start_time_index, start_chan_index;
    unsigned int have_autocorr, have_crosscorr;
    const void *xcorr, *acorr;
    void* out;

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

    /* Pull data from visibility structures. */
    num_pols_out     = oskar_ms_num_pols(ms);
    num_pols_in      = oskar_vis_block_num_pols(blk);
    num_stations     = oskar_vis_block_num_stations(blk);
    num_baseln_in    = oskar_vis_block_num_baselines(blk);
    num_channels     = oskar_vis_block_num_channels(blk);
    num_times        = oskar_vis_block_num_times(blk);
    in_acorr         = oskar_vis_block_auto_correlations_const(blk);
    in_xcorr         = oskar_vis_block_cross_correlations_const(blk);
    in_uu            = oskar_vis_block_baseline_uu_metres_const(blk);
    in_vv            = oskar_vis_block_baseline_vv_metres_const(blk);
    in_ww            = oskar_vis_block_baseline_ww_metres_const(blk);
    have_autocorr    = oskar_vis_block_has_auto_correlations(blk);
    have_crosscorr   = oskar_vis_block_has_cross_correlations(blk);
    start_time_index = oskar_vis_block_start_time_index(blk);
    start_chan_index = oskar_vis_block_start_channel_index(blk);
    ra_rad           = oskar_vis_header_phase_centre_ra_deg(header) * D2R;
    dec_rad          = oskar_vis_header_phase_centre_dec_deg(header) * D2R;
    exposure_sec     = oskar_vis_header_time_average_sec(header);
    interval_sec     = oskar_vis_header_time_inc_sec(header);
    t_start_mjd      = oskar_vis_header_time_start_mjd_utc(header);
    ref_freq_hz      = oskar_vis_header_freq_start_hz(header);
    prec             = oskar_mem_precision(in_xcorr);
    t_start_sec      = t_start_mjd * 86400.0 +
            interval_sec * (start_time_index + 0.5);

    /* Check that there is something to write. */
    if (!have_autocorr && !have_crosscorr) return;

    /* Get number of output baselines. */
    num_baseln_out = num_baseln_in;
    if (have_autocorr)
        num_baseln_out += num_stations;

    /* Check polarisation dimension consistency:
     * num_pols_in can be less than num_pols_out, but not vice-versa. */
    if (num_pols_in > num_pols_out)
    {
        *status = OSKAR_ERR_DIMENSION_MISMATCH;
        return;
    }

    /* Check the dimensions match. */
    if (oskar_ms_num_pols(ms) != num_pols_out ||
            oskar_ms_num_stations(ms) != num_stations)
    {
        *status = OSKAR_ERR_DIMENSION_MISMATCH;
        return;
    }

    /* Check the reference frequencies match. */
    if (fabs(oskar_ms_ref_freq_hz(ms) - ref_freq_hz) > 1e-10)
    {
        *status = OSKAR_ERR_VALUE_MISMATCH;
        return;
    }

    /* Check the phase centres are the same. */
    if (fabs(oskar_ms_phase_centre_ra_rad(ms) - ra_rad) > 1e-10 ||
            fabs(oskar_ms_phase_centre_dec_rad(ms) - dec_rad) > 1e-10)
    {
        *status = OSKAR_ERR_VALUE_MISMATCH;
        return;
    }

    /* Add visibilities and u,v,w coordinates. */
    temp_vis = oskar_mem_create(prec | OSKAR_COMPLEX, OSKAR_CPU,
            num_baseln_out * num_channels * num_pols_out, status);
    temp_uu = oskar_mem_create(prec, OSKAR_CPU, num_baseln_out, status);
    temp_vv = oskar_mem_create(prec, OSKAR_CPU, num_baseln_out, status);
    temp_ww = oskar_mem_create(prec, OSKAR_CPU, num_baseln_out, status);
    xcorr   = oskar_mem_void_const(in_xcorr);
    acorr   = oskar_mem_void_const(in_acorr);
    out     = oskar_mem_void(temp_vis);
    if (prec == OSKAR_DOUBLE)
    {
        const double *uu_in, *vv_in, *ww_in;
        double *uu_out, *vv_out, *ww_out;
        uu_in = oskar_mem_double_const(in_uu, status);
        vv_in = oskar_mem_double_const(in_vv, status);
        ww_in = oskar_mem_double_const(in_ww, status);
        uu_out = oskar_mem_double(temp_uu, status);
        vv_out = oskar_mem_double(temp_vv, status);
        ww_out = oskar_mem_double(temp_ww, status);
        for (t = 0; t < num_times; ++t)
        {
            /* Construct the baseline coordinates for the given time. */
            int start_row = (start_time_index + t) * num_baseln_out;
            for (a1 = 0, b = 0, i_out = 0; a1 < num_stations; ++a1)
            {
                if (have_autocorr)
                {
                    uu_out[i_out] = 0.0;
                    vv_out[i_out] = 0.0;
                    ww_out[i_out] = 0.0;
                    ++i_out;
                }
                if (have_crosscorr)
                {
                    for (a2 = a1 + 1; a2 < num_stations; ++a2, ++b, ++i_out)
                    {
                        i = num_baseln_in * t + b;
                        uu_out[i_out] = uu_in[i];
                        vv_out[i_out] = vv_in[i];
                        ww_out[i_out] = ww_in[i];
                    }
                }
            }

            for (c = 0, i_out = 0; c < num_channels; ++c)
            {
                /* Construct amplitude data for the given time and channel. */
                if (num_pols_in == 4)
                {
                    for (a1 = 0, b = 0; a1 < num_stations; ++a1)
                    {
                        if (have_autocorr)
                        {
                            i = num_stations * (t * num_channels + c) + a1;
                            ((double4c*)out)[i_out++] =
                                    ((const double4c*)acorr)[i];
                        }
                        if (have_crosscorr)
                        {
                            for (a2 = a1 + 1; a2 < num_stations; ++b, ++a2)
                            {
                                i = num_baseln_in * (t * num_channels + c) + b;
                                ((double4c*)out)[i_out++] =
                                        ((const double4c*)xcorr)[i];
                            }
                        }
                    }
                }
                else if (num_pols_in == 1 && num_pols_out == 1)
                {
                    for (a1 = 0, b = 0; a1 < num_stations; ++a1)
                    {
                        if (have_autocorr)
                        {
                            i = num_stations * (t * num_channels + c) + a1;
                            ((double2*)out)[i_out++] =
                                    ((const double2*)acorr)[i];
                        }
                        if (have_crosscorr)
                        {
                            for (a2 = a1 + 1; a2 < num_stations; ++b, ++a2)
                            {
                                i = num_baseln_in * (t * num_channels + c) + b;
                                ((double2*)out)[i_out++] =
                                        ((const double2*)xcorr)[i];
                            }
                        }
                    }
                }
                else
                {
                    double2 vis_amp, *out_;
                    out_ = (double2*)out;
                    for (a1 = 0, b = 0; a1 < num_stations; ++a1)
                    {
                        if (have_autocorr)
                        {
                            i = num_stations * (t * num_channels + c) + a1;
                            vis_amp = ((const double2*)acorr)[i];
                            out_[i_out + 0] = vis_amp;  /* XX */
                            out_[i_out + 1].x = 0.0;    /* XY */
                            out_[i_out + 1].y = 0.0;    /* XY */
                            out_[i_out + 2].x = 0.0;    /* YX */
                            out_[i_out + 2].y = 0.0;    /* YX */
                            out_[i_out + 3] = vis_amp;  /* YY */
                            i_out += 4;
                        }
                        if (have_crosscorr)
                        {
                            for (a2 = a1 + 1; a2 < num_stations; ++b, ++a2)
                            {
                                i = num_baseln_in * (t * num_channels + c) + b;
                                vis_amp = ((const double2*)xcorr)[i];
                                out_[i_out + 0] = vis_amp;  /* XX */
                                out_[i_out + 1].x = 0.0;    /* XY */
                                out_[i_out + 1].y = 0.0;    /* XY */
                                out_[i_out + 2].x = 0.0;    /* YX */
                                out_[i_out + 2].y = 0.0;    /* YX */
                                out_[i_out + 3] = vis_amp;  /* YY */
                                i_out += 4;
                            }
                        }
                    }
                }
            }
            oskar_ms_write_coords_d(ms, start_row, num_baseln_out,
                    uu_out, vv_out, ww_out, exposure_sec, interval_sec,
                    t_start_sec + (t * interval_sec));
            oskar_ms_write_vis_d(ms, start_row, start_chan_index,
                    num_channels, num_baseln_out, (const double*)out);
        }
    }
    else if (prec == OSKAR_SINGLE)
    {
        const float *uu_in, *vv_in, *ww_in;
        float *uu_out, *vv_out, *ww_out;
        uu_in = oskar_mem_float_const(in_uu, status);
        vv_in = oskar_mem_float_const(in_vv, status);
        ww_in = oskar_mem_float_const(in_ww, status);
        uu_out = oskar_mem_float(temp_uu, status);
        vv_out = oskar_mem_float(temp_vv, status);
        ww_out = oskar_mem_float(temp_ww, status);
        for (t = 0; t < num_times; ++t)
        {
            /* Construct the baseline coordinates for the given time. */
            int start_row = (start_time_index + t) * num_baseln_out;
            for (a1 = 0, b = 0, i_out = 0; a1 < num_stations; ++a1)
            {
                if (have_autocorr)
                {
                    uu_out[i_out] = 0.0;
                    vv_out[i_out] = 0.0;
                    ww_out[i_out] = 0.0;
                    ++i_out;
                }
                if (have_crosscorr)
                {
                    for (a2 = a1 + 1; a2 < num_stations; ++a2, ++b, ++i_out)
                    {
                        i = num_baseln_in * t + b;
                        uu_out[i_out] = uu_in[i];
                        vv_out[i_out] = vv_in[i];
                        ww_out[i_out] = ww_in[i];
                    }
                }
            }

            for (c = 0, i_out = 0; c < num_channels; ++c)
            {
                /* Construct amplitude data for the given time and channel. */
                if (num_pols_in == 4)
                {
                    for (a1 = 0, b = 0; a1 < num_stations; ++a1)
                    {
                        if (have_autocorr)
                        {
                            i = num_stations * (t * num_channels + c) + a1;
                            ((float4c*)out)[i_out++] =
                                    ((const float4c*)acorr)[i];
                        }
                        if (have_crosscorr)
                        {
                            for (a2 = a1 + 1; a2 < num_stations; ++b, ++a2)
                            {
                                i = num_baseln_in * (t * num_channels + c) + b;
                                ((float4c*)out)[i_out++] =
                                        ((const float4c*)xcorr)[i];
                            }
                        }
                    }
                }
                else if (num_pols_in == 1 && num_pols_out == 1)
                {
                    for (a1 = 0, b = 0; a1 < num_stations; ++a1)
                    {
                        if (have_autocorr)
                        {
                            i = num_stations * (t * num_channels + c) + a1;
                            ((float2*)out)[i_out++] =
                                    ((const float2*)acorr)[i];
                        }
                        if (have_crosscorr)
                        {
                            for (a2 = a1 + 1; a2 < num_stations; ++b, ++a2)
                            {
                                i = num_baseln_in * (t * num_channels + c) + b;
                                ((float2*)out)[i_out++] =
                                        ((const float2*)xcorr)[i];
                            }
                        }
                    }
                }
                else
                {
                    float2 vis_amp, *out_;
                    out_ = (float2*)out;
                    for (a1 = 0, b = 0; a1 < num_stations; ++a1)
                    {
                        if (have_autocorr)
                        {
                            i = num_stations * (t * num_channels + c) + a1;
                            vis_amp = ((const float2*)acorr)[i];
                            out_[i_out + 0] = vis_amp;  /* XX */
                            out_[i_out + 1].x = 0.0;    /* XY */
                            out_[i_out + 1].y = 0.0;    /* XY */
                            out_[i_out + 2].x = 0.0;    /* YX */
                            out_[i_out + 2].y = 0.0;    /* YX */
                            out_[i_out + 3] = vis_amp;  /* YY */
                            i_out += 4;
                        }
                        if (have_crosscorr)
                        {
                            for (a2 = a1 + 1; a2 < num_stations; ++b, ++a2)
                            {
                                i = num_baseln_in * (t * num_channels + c) + b;
                                vis_amp = ((const float2*)xcorr)[i];
                                out_[i_out + 0] = vis_amp;  /* XX */
                                out_[i_out + 1].x = 0.0;    /* XY */
                                out_[i_out + 1].y = 0.0;    /* XY */
                                out_[i_out + 2].x = 0.0;    /* YX */
                                out_[i_out + 2].y = 0.0;    /* YX */
                                out_[i_out + 3] = vis_amp;  /* YY */
                                i_out += 4;
                            }
                        }
                    }
                }
            }
            oskar_ms_write_coords_f(ms, start_row, num_baseln_out,
                    uu_out, vv_out, ww_out, exposure_sec, interval_sec,
                    t_start_sec + (t * interval_sec));
            oskar_ms_write_vis_f(ms, start_row, start_chan_index,
                    num_channels, num_baseln_out, (const float*)out);
        }
    }
    else
    {
        *status = OSKAR_ERR_BAD_DATA_TYPE;
    }

    /* Cleanup. */
    oskar_mem_free(temp_vis, status);
    oskar_mem_free(temp_uu, status);
    oskar_mem_free(temp_vv, status);
    oskar_mem_free(temp_ww, status);
}