Пример #1
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);
}
Пример #2
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;
        }
    }
}
Пример #3
0
static PyObject* auto_correlations(PyObject* self, PyObject* args)
{
    oskar_VisBlock* h = 0;
    oskar_Mem* m = 0;
    PyObject *capsule = 0;
    PyArrayObject *array = 0;
    npy_intp dims[4];
    if (!PyArg_ParseTuple(args, "O", &capsule)) return 0;
    if (!(h = (oskar_VisBlock*) get_handle(capsule, name))) return 0;

    /* Check that auto-correlations exist. */
    if (!oskar_vis_block_has_auto_correlations(h))
    {
        PyErr_SetString(PyExc_RuntimeError, "No auto-correlations in block.");
        return 0;
    }

    /* Return an array reference to Python. */
    m = oskar_vis_block_auto_correlations(h);
    dims[0] = oskar_vis_block_num_times(h);
    dims[1] = oskar_vis_block_num_channels(h);
    dims[2] = oskar_vis_block_num_stations(h);
    dims[3] = oskar_vis_block_num_pols(h);
    array = (PyArrayObject*)PyArray_SimpleNewFromData(4, dims,
            (oskar_mem_is_double(m) ? NPY_CDOUBLE : NPY_CFLOAT),
            oskar_mem_void(m));
    return Py_BuildValue("N", array); /* Don't increment refcount. */
}
Пример #4
0
oskar_Mem* oskar_mem_read_binary_raw(const char* filename, int type,
        int location, int* status)
{
    size_t num_elements, element_size, size_bytes;
    oskar_Mem *mem = 0;
    FILE* stream;

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

    /* Open the input file. */
    stream = fopen(filename, "rb");
    if (!stream)
    {
        *status = OSKAR_ERR_FILE_IO;
        return 0;
    }

    /* Get the file size. */
    fseek(stream, 0, SEEK_END);
    size_bytes = ftell(stream);

    /* Create memory block of the right size. */
    element_size = oskar_mem_element_size(type);
    num_elements = (size_t)ceil(size_bytes / element_size);
    mem = oskar_mem_create(type, OSKAR_CPU, num_elements, status);
    if (*status)
    {
        oskar_mem_free(mem, status);
        fclose(stream);
        return 0;
    }

    /* Read the data. */
    fseek(stream, 0, SEEK_SET);
    if (fread(oskar_mem_void(mem), 1, size_bytes, stream) != size_bytes)
    {
        oskar_mem_free(mem, status);
        fclose(stream);
        *status = OSKAR_ERR_FILE_IO;
        return 0;
    }

    /* Close the input file. */
    fclose(stream);

    /* Copy to GPU memory if required. */
    if (location != OSKAR_CPU)
    {
        oskar_Mem* gpu;
        gpu = oskar_mem_create_copy(mem, location, status);
        oskar_mem_free(mem, status);
        return gpu;
    }

    return mem;
}
Пример #5
0
static void write_pixels(oskar_Mem* data, const char* filename,
        int width, int height, int num_planes, int i_plane, int* status)
{
    long naxes[3], firstpix[3], num_pix;
    int dims_ok = 0;
    fitsfile* f = 0;
    if (*status) return;
    if (oskar_file_exists(filename))
    {
        int naxis = 0, imagetype = 0;
        fits_open_file(&f, filename, READWRITE, status);
        fits_get_img_param(f, 3, &imagetype, &naxis, naxes, status);
        if (naxis == 3 &&
                naxes[0] == width &&
                naxes[1] == height &&
                naxes[2] == num_planes)
        {
            dims_ok = 1;
        }
        else
        {
            *status = 0;
            fits_close_file(f, status);
            remove(filename);
            f = 0;
        }
    }
    if (!dims_ok)
    {
        naxes[0] = width;
        naxes[1] = height;
        naxes[2] = num_planes;
        fits_create_file(&f, filename, status);
        fits_create_img(f, oskar_mem_is_double(data) ? DOUBLE_IMG : FLOAT_IMG,
                3, naxes, status);
    }
    if (*status || !f)
    {
        if (f) fits_close_file(f, status);
        *status = OSKAR_ERR_FILE_IO;
        return;
    }
    num_pix = width * height;
    firstpix[0] = 1;
    firstpix[1] = 1;
    firstpix[2] = 1 + i_plane;
    if (i_plane < 0)
    {
        firstpix[2] = 1;
        num_pix *= num_planes;
    }
    fits_write_pix(f, oskar_mem_is_double(data) ? TDOUBLE : TFLOAT,
            firstpix, num_pix, oskar_mem_void(data), status);
    fits_close_file(f, status);
}
Пример #6
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);
}
Пример #7
0
void write_plane(oskar_Imager* h, oskar_Mem* plane,
        int t, int c, int p, int* status)
{
    int datatype, num_pixels;
    long firstpix[4];
    if (*status) return;
    if (!h->fits_file[p]) return;
    datatype = (oskar_mem_is_double(plane) ? TDOUBLE : TFLOAT);
    firstpix[0] = 1;
    firstpix[1] = 1;
    firstpix[2] = 1 + c;
    firstpix[3] = 1 + t;
    num_pixels = h->image_size * h->image_size;
    fits_write_pix(h->fits_file[p], datatype, firstpix, num_pixels,
            oskar_mem_void(plane), status);
}
Пример #8
0
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);
}
Пример #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));
    }
}
int main(int argc, char** argv)
{
    int status = 0;
    oskar::OptionParser opt("oskar_evaulate_pierce_points",
            oskar_version_string());
    opt.add_required("settings file");
    if (!opt.check_options(argc, argv)) return EXIT_FAILURE;

    const char* settings_file = opt.get_arg();

    // Create the log.
    oskar_Log* log = oskar_log_create(OSKAR_LOG_MESSAGE, OSKAR_LOG_STATUS);
    oskar_log_message(log, 'M', 0, "Running binary %s", argv[0]);

    // Enum values used in writing time-freq data binary files
    enum OSKAR_TIME_FREQ_TAGS
    {
        TIME_IDX       = 0,
        FREQ_IDX       = 1,
        TIME_MJD_UTC   = 2,
        FREQ_HZ        = 3,
        NUM_FIELDS     = 4,
        NUM_FIELD_TAGS = 5,
        HEADER_OFFSET  = 10,
        DATA           = 0,
        DIMS           = 1,
        LABEL          = 2,
        UNITS          = 3,
        GRP            = OSKAR_TAG_GROUP_TIME_FREQ_DATA
    };

    oskar_Settings_old settings;
    oskar_settings_old_load(&settings, log, settings_file, &status);
    oskar_log_set_keep_file(log, settings.sim.keep_log_file);
    if (status) return status;

    oskar_Telescope* tel = oskar_settings_to_telescope(&settings, log, &status);
    oskar_Sky* sky = oskar_settings_to_sky(&settings, log, &status);

    // FIXME remove this restriction ... (see evaluate Z)
    if (settings.ionosphere.num_TID_screens != 1)
        return OSKAR_ERR_SETUP_FAIL;

    int type = settings.sim.double_precision ? OSKAR_DOUBLE : OSKAR_SINGLE;
    int loc = OSKAR_CPU;

    int num_sources = oskar_sky_num_sources(sky);
    oskar_Mem *hor_x, *hor_y, *hor_z;
    hor_x = oskar_mem_create(type, loc, num_sources, &status);
    hor_y = oskar_mem_create(type, loc, num_sources, &status);
    hor_z = oskar_mem_create(type, loc, num_sources, &status);

    oskar_Mem *pp_lon, *pp_lat, *pp_rel_path;
    int num_stations = oskar_telescope_num_stations(tel);

    int num_pp = num_stations * num_sources;
    pp_lon = oskar_mem_create(type, loc, num_pp, &status);
    pp_lat = oskar_mem_create(type, loc, num_pp, &status);
    pp_rel_path = oskar_mem_create(type, loc, num_pp, &status);

    // Pierce points for one station (non-owned oskar_Mem pointers)
    oskar_Mem *pp_st_lon, *pp_st_lat, *pp_st_rel_path;
    pp_st_lon = oskar_mem_create_alias(0, 0, 0, &status);
    pp_st_lat = oskar_mem_create_alias(0, 0, 0, &status);
    pp_st_rel_path = oskar_mem_create_alias(0, 0, 0, &status);

    int num_times = settings.obs.num_time_steps;
    double obs_start_mjd_utc = settings.obs.start_mjd_utc;
    double dt_dump = settings.obs.dt_dump_days;

    // Binary file meta-data
    std::string label1 = "pp_lon";
    std::string label2 = "pp_lat";
    std::string label3 = "pp_path";
    std::string units  = "radians";
    std::string units2 = "";
    oskar_Mem *dims = oskar_mem_create(OSKAR_INT, loc, 2, &status);
    /* FIXME is this the correct dimension order ?
     * FIXME get the MATLAB reader to respect dimension ordering */
    oskar_mem_int(dims, &status)[0] = num_sources;
    oskar_mem_int(dims, &status)[1] = num_stations;

    const char* filename = settings.ionosphere.pierce_points.filename;
    oskar_Binary* h = oskar_binary_create(filename, 'w', &status);

    double screen_height_m = settings.ionosphere.TID->height_km * 1000.0;

//    printf("Number of times    = %i\n", num_times);
//    printf("Number of stations = %i\n", num_stations);

    void *x_, *y_, *z_;
    x_ = oskar_mem_void(oskar_telescope_station_true_x_offset_ecef_metres(tel));
    y_ = oskar_mem_void(oskar_telescope_station_true_y_offset_ecef_metres(tel));
    z_ = oskar_mem_void(oskar_telescope_station_true_z_offset_ecef_metres(tel));

    for (int t = 0; t < num_times; ++t)
    {
        double t_dump = obs_start_mjd_utc + t * dt_dump; // MJD UTC
        double gast = oskar_convert_mjd_to_gast_fast(t_dump + dt_dump / 2.0);

        for (int i = 0; i < num_stations; ++i)
        {
            const oskar_Station* station =
                    oskar_telescope_station_const(tel, i);
            double lon = oskar_station_lon_rad(station);
            double lat = oskar_station_lat_rad(station);
            double alt = oskar_station_alt_metres(station);
            double x_ecef, y_ecef, z_ecef, x_offset, y_offset, z_offset;

            if (type == OSKAR_DOUBLE)
            {
                x_offset = ((double*)x_)[i];
                y_offset = ((double*)y_)[i];
                z_offset = ((double*)z_)[i];
            }
            else
            {
                x_offset = (double)((float*)x_)[i];
                y_offset = (double)((float*)y_)[i];
                z_offset = (double)((float*)z_)[i];
            }

            oskar_convert_offset_ecef_to_ecef(1, &x_offset, &y_offset,
                    &z_offset, lon, lat, alt, &x_ecef, &y_ecef, &z_ecef);
            double last = gast + lon;

            if (type == OSKAR_DOUBLE)
            {
                oskar_convert_apparent_ra_dec_to_enu_directions_d(num_sources,
                        oskar_mem_double_const(oskar_sky_ra_rad_const(sky), &status),
                        oskar_mem_double_const(oskar_sky_dec_rad_const(sky), &status),
                        last, lat, oskar_mem_double(hor_x, &status),
                        oskar_mem_double(hor_y, &status),
                        oskar_mem_double(hor_z, &status));
            }
            else
            {
                oskar_convert_apparent_ra_dec_to_enu_directions_f(num_sources,
                        oskar_mem_float_const(oskar_sky_ra_rad_const(sky), &status),
                        oskar_mem_float_const(oskar_sky_dec_rad_const(sky), &status),
                        last, lat, oskar_mem_float(hor_x, &status),
                        oskar_mem_float(hor_y, &status),
                        oskar_mem_float(hor_z, &status));
            }

            int offset = i * num_sources;
            oskar_mem_set_alias(pp_st_lon, pp_lon, offset, num_sources,
                    &status);
            oskar_mem_set_alias(pp_st_lat, pp_lat, offset, num_sources,
                    &status);
            oskar_mem_set_alias(pp_st_rel_path, pp_rel_path, offset,
                    num_sources, &status);
            oskar_evaluate_pierce_points(pp_st_lon, pp_st_lat, pp_st_rel_path,
                    x_ecef, y_ecef, z_ecef, screen_height_m,
                    num_sources, hor_x, hor_y, hor_z, &status);
        } // Loop over stations.

        if (status != 0)
            continue;

        int index = t; // could be = (num_times * f) + t if we have frequency data
        int num_fields = 3;
        int num_field_tags = 4;
        double freq_hz = 0.0;
        int freq_idx = 0;

        // Write the header TAGS
        oskar_binary_write_int(h, GRP, TIME_IDX, index, t, &status);
        oskar_binary_write_double(h, GRP, FREQ_IDX, index, freq_idx, &status);
        oskar_binary_write_double(h, GRP, TIME_MJD_UTC, index, t_dump, &status);
        oskar_binary_write_double(h, GRP, FREQ_HZ, index, freq_hz, &status);
        oskar_binary_write_int(h, GRP, NUM_FIELDS, index, num_fields, &status);
        oskar_binary_write_int(h, GRP, NUM_FIELD_TAGS, index, num_field_tags,
                &status);

        // Write data TAGS (fields)
        int field, tagID;
        field = 0;
        tagID = HEADER_OFFSET + (num_field_tags * field);
        oskar_binary_write_mem(h, pp_lon, GRP, tagID + DATA,
                index, 0, &status);
        oskar_binary_write_mem(h, dims, GRP, tagID  + DIMS,
                index, 0, &status);
        oskar_binary_write(h, OSKAR_CHAR, GRP, tagID + LABEL,
                index, label1.size()+1, label1.c_str(), &status);
        oskar_binary_write(h, OSKAR_CHAR, GRP, tagID + UNITS,
                index, units.size()+1, units.c_str(), &status);
        field = 1;
        tagID = HEADER_OFFSET + (num_field_tags * field);
        oskar_binary_write_mem(h, pp_lat, GRP, tagID + DATA,
                index, 0, &status);
        oskar_binary_write_mem(h, dims, GRP, tagID  + DIMS,
                index, 0, &status);
        oskar_binary_write(h, OSKAR_CHAR, GRP, tagID + LABEL,
                index, label2.size()+1, label2.c_str(), &status);
        oskar_binary_write(h, OSKAR_CHAR, GRP, tagID + UNITS,
                index, units.size()+1, units.c_str(), &status);
        field = 2;
        tagID = HEADER_OFFSET + (num_field_tags * field);
        oskar_binary_write_mem(h, pp_rel_path, GRP, tagID + DATA,
                index, 0, &status);
        oskar_binary_write_mem(h, dims, GRP, tagID  + DIMS,
                index, 0, &status);
        oskar_binary_write(h, OSKAR_CHAR, GRP, tagID + LABEL,
                index, label3.size()+1, label3.c_str(), &status);
        oskar_binary_write(h, OSKAR_CHAR, GRP, tagID + UNITS,
                index, units2.size()+1, units2.c_str(), &status);
    } // Loop over times

    // Close the OSKAR binary file.
    oskar_binary_free(h);

    // clean up memory
    oskar_mem_free(hor_x, &status);
    oskar_mem_free(hor_y, &status);
    oskar_mem_free(hor_z, &status);
    oskar_mem_free(pp_lon, &status);
    oskar_mem_free(pp_lat, &status);
    oskar_mem_free(pp_rel_path, &status);
    oskar_mem_free(pp_st_lon, &status);
    oskar_mem_free(pp_st_lat, &status);
    oskar_mem_free(pp_st_rel_path, &status);
    oskar_mem_free(dims, &status);
    oskar_telescope_free(tel, &status);
    oskar_sky_free(sky, &status);

    // Check for errors.
    if (status)
        oskar_log_error(log, "Run failed: %s.", oskar_get_error_string(status));
    oskar_log_free(log);

    return status;
}
Пример #11
0
void oskar_element_load_scalar(oskar_Element* data,
        double freq_hz, const char* filename,
        double closeness, double closeness_inc, int ignore_at_poles,
        int ignore_below_horizon, int* status)
{
    int i, n = 0, type = OSKAR_DOUBLE;
    oskar_Splines *scalar_re = 0, *scalar_im = 0;
    oskar_Mem *theta = 0, *phi = 0, *re = 0, *im = 0, *weight = 0;

    /* Declare the line buffer. */
    char *line = NULL;
    size_t bufsize = 0;
    FILE* file;

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

    /* Check the data type. */
    if (oskar_element_precision(data) != type)
    {
        *status = OSKAR_ERR_TYPE_MISMATCH;
        return;
    }

    /* Check the location. */
    if (oskar_element_mem_location(data) != OSKAR_CPU)
    {
        *status = OSKAR_ERR_BAD_LOCATION;
        return;
    }

    /* Check if this frequency has already been set, and get its index if so. */
    n = data->num_freq;
    for (i = 0; i < n; ++i)
    {
        if (fabs(data->freqs_hz[i] - freq_hz) <= freq_hz * DBL_EPSILON)
            break;
    }

    /* Expand arrays to hold data for a new frequency, if needed. */
    if (i >= data->num_freq)
    {
        i = data->num_freq;
        oskar_element_resize_freq_data(data, i + 1, status);
        data->freqs_hz[i] = freq_hz;
    }

    /* Get pointers to surface data based on frequency index. */
    scalar_re = data->scalar_re[i];
    scalar_im = data->scalar_im[i];

    /* Open the file. */
    file = fopen(filename, "r");
    if (!file)
    {
        *status = OSKAR_ERR_FILE_IO;
        return;
    }

    /* Create local arrays to hold data for fitting. */
    theta  = oskar_mem_create(type, OSKAR_CPU, 0, status);
    phi    = oskar_mem_create(type, OSKAR_CPU, 0, status);
    re     = oskar_mem_create(type, OSKAR_CPU, 0, status);
    im     = oskar_mem_create(type, OSKAR_CPU, 0, status);
    weight = oskar_mem_create(type, OSKAR_CPU, 0, status);
    if (*status) return;

    /* Loop over and read each line in the file. */
    n = 0;
    while (oskar_getline(&line, &bufsize, file) != OSKAR_ERR_EOF)
    {
        double re_, im_;
        double par[] = {0., 0., 0., 0.}; /* theta, phi, amp, phase (optional) */
        void *p_theta = 0, *p_phi = 0, *p_re = 0, *p_im = 0, *p_weight = 0;

        /* Parse the line, and skip if data were not read correctly. */
        if (oskar_string_to_array_d(line, 4, par) < 3)
            continue;

        /* Ignore data below horizon if requested. */
        if (ignore_below_horizon && par[0] > 90.0) continue;

        /* Ignore data at poles if requested. */
        if (ignore_at_poles)
            if (par[0] < 1e-6 || par[0] > (180.0 - 1e-6)) continue;

        /* Convert angular measures to radians. */
        par[0] *= DEG2RAD; /* theta */
        par[1] *= DEG2RAD; /* phi */
        par[3] *= DEG2RAD; /* phase */

        /* Ensure enough space in arrays. */
        if (n % 100 == 0)
        {
            const int size = n + 100;
            oskar_mem_realloc(theta, size, status);
            oskar_mem_realloc(phi, size, status);
            oskar_mem_realloc(re, size, status);
            oskar_mem_realloc(im, size, status);
            oskar_mem_realloc(weight, size, status);
            if (*status) break;
        }
        p_theta  = oskar_mem_void(theta);
        p_phi    = oskar_mem_void(phi);
        p_re     = oskar_mem_void(re);
        p_im     = oskar_mem_void(im);
        p_weight = oskar_mem_void(weight);

        /* Amp,phase to real,imag conversion. */
        re_ = par[2] * cos(par[3]);
        im_ = par[2] * sin(par[3]);

        /* Store the surface data. */
        ((double*)p_theta)[n]  = par[0];
        ((double*)p_phi)[n]    = par[1];
        ((double*)p_re)[n]     = re_;
        ((double*)p_im)[n]     = im_;
        ((double*)p_weight)[n] = 1.0;

        /* Increment array pointer. */
        n++;
    }

    /* Free the line buffer and close the file. */
    free(line);
    fclose(file);

    /* Fit splines to the surface data. */
    fit_splines(scalar_re, n, theta, phi, re, weight,
            closeness, closeness_inc, "Scalar [real]", status);
    fit_splines(scalar_im, n, theta, phi, im, weight,
            closeness, closeness_inc, "Scalar [imag]", status);

    /* Store the filename. */
    oskar_mem_append_raw(data->filename_scalar[i], filename, OSKAR_CHAR,
                OSKAR_CPU, 1 + strlen(filename), status);

    /* Free local arrays. */
    oskar_mem_free(theta, status);
    oskar_mem_free(phi, status);
    oskar_mem_free(re, status);
    oskar_mem_free(im, status);
    oskar_mem_free(weight, status);
}
void oskar_imager_read_coords_ms(oskar_Imager* h, const char* filename,
        int i_file, int num_files, int* percent_done, int* percent_next,
        int* status)
{
#ifndef OSKAR_NO_MS
    oskar_MeasurementSet* ms;
    oskar_Mem *uvw, *u, *v, *w, *weight, *time_centroid;
    int num_channels, num_stations, num_baselines, num_pols;
    int start_row, num_rows;
    double *uvw_, *u_, *v_, *w_;
    if (*status) return;

    /* Read the header. */
    ms = oskar_ms_open(filename);
    if (!ms)
    {
        *status = OSKAR_ERR_FILE_IO;
        return;
    }
    num_rows = (int) oskar_ms_num_rows(ms);
    num_stations = (int) oskar_ms_num_stations(ms);
    num_baselines = num_stations * (num_stations - 1) / 2;
    num_pols = (int) oskar_ms_num_pols(ms);
    num_channels = (int) oskar_ms_num_channels(ms);

    /* Set visibility meta-data. */
    oskar_imager_set_vis_frequency(h,
            oskar_ms_freq_start_hz(ms),
            oskar_ms_freq_inc_hz(ms), num_channels);
    oskar_imager_set_vis_phase_centre(h,
            oskar_ms_phase_centre_ra_rad(ms) * 180/M_PI,
            oskar_ms_phase_centre_dec_rad(ms) * 180/M_PI);

    /* Create arrays. */
    uvw = oskar_mem_create(OSKAR_DOUBLE, OSKAR_CPU, 3 * num_baselines, status);
    u = oskar_mem_create(OSKAR_DOUBLE, OSKAR_CPU, num_baselines, status);
    v = oskar_mem_create(OSKAR_DOUBLE, OSKAR_CPU, num_baselines, status);
    w = oskar_mem_create(OSKAR_DOUBLE, OSKAR_CPU, num_baselines, status);
    weight = oskar_mem_create(OSKAR_SINGLE, OSKAR_CPU,
            num_baselines * num_pols, status);
    time_centroid = oskar_mem_create(OSKAR_DOUBLE, OSKAR_CPU, num_baselines,
            status);
    uvw_ = oskar_mem_double(uvw, status);
    u_ = oskar_mem_double(u, status);
    v_ = oskar_mem_double(v, status);
    w_ = oskar_mem_double(w, status);

    /* Loop over visibility blocks. */
    for (start_row = 0; start_row < num_rows; start_row += num_baselines)
    {
        int i, block_size;
        size_t allocated, required;
        if (*status) break;

        /* Read coordinates and weights from Measurement Set. */
        oskar_timer_resume(h->tmr_read);
        block_size = num_rows - start_row;
        if (block_size > num_baselines) block_size = num_baselines;
        allocated = oskar_mem_length(uvw) *
                oskar_mem_element_size(oskar_mem_type(uvw));
        oskar_ms_read_column(ms, "UVW", start_row, block_size,
                allocated, oskar_mem_void(uvw), &required, status);
        allocated = oskar_mem_length(weight) *
                oskar_mem_element_size(oskar_mem_type(weight));
        oskar_ms_read_column(ms, "WEIGHT", start_row, block_size,
                allocated, oskar_mem_void(weight), &required, status);
        allocated = oskar_mem_length(time_centroid) *
                oskar_mem_element_size(oskar_mem_type(time_centroid));
        oskar_ms_read_column(ms, "TIME_CENTROID", start_row, block_size,
                allocated, oskar_mem_void(time_centroid), &required, status);

        /* Split up baseline coordinates. */
        for (i = 0; i < block_size; ++i)
        {
            u_[i] = uvw_[3*i + 0];
            v_[i] = uvw_[3*i + 1];
            w_[i] = uvw_[3*i + 2];
        }

        /* Update the imager with the data. */
        oskar_timer_pause(h->tmr_read);
        oskar_imager_update(h, block_size, 0, num_channels - 1, num_pols,
                u, v, w, 0, weight, time_centroid, status);
        *percent_done = (int) round(100.0 * (
                (start_row + block_size) / (double)(num_rows * num_files) +
                i_file / (double)num_files));
        if (h->log && percent_next && *percent_done >= *percent_next)
        {
            oskar_log_message(h->log, 'S', -2, "%3d%% ...", *percent_done);
            *percent_next = 10 + 10 * (*percent_done / 10);
        }
    }
    oskar_mem_free(uvw, status);
    oskar_mem_free(u, status);
    oskar_mem_free(v, status);
    oskar_mem_free(w, status);
    oskar_mem_free(weight, status);
    oskar_mem_free(time_centroid, status);
    oskar_ms_close(ms);
#else
    (void) filename;
    (void) i_file;
    (void) num_files;
    (void) percent_done;
    (void) percent_next;
    oskar_log_error(h->log, "OSKAR was compiled without Measurement Set support.");
    *status = OSKAR_ERR_FUNCTION_NOT_AVAILABLE;
#endif
}
Пример #13
0
TEST(imager, grid_sum)
{
    int status = 0, type = OSKAR_DOUBLE;
    int size = 2048, grid_size = size * size;

    // Create and set up the imager.
    oskar_Imager* im = oskar_imager_create(type, &status);
    oskar_imager_set_grid_kernel(im, "pillbox", 1, 1, &status);
    oskar_imager_set_fov(im, 5.0);
    oskar_imager_set_size(im, size, &status);
    oskar_Mem* grid = oskar_mem_create(type | OSKAR_COMPLEX, OSKAR_CPU,
            grid_size, &status);
    ASSERT_EQ(0, status);

    // Create visibility data.
    int num_vis = 10000;
    oskar_Mem* uu = oskar_mem_create(type, OSKAR_CPU, num_vis, &status);
    oskar_Mem* vv = oskar_mem_create(type, OSKAR_CPU, num_vis, &status);
    oskar_Mem* ww = oskar_mem_create(type, OSKAR_CPU, num_vis, &status);
    oskar_Mem* vis = oskar_mem_create(type | OSKAR_COMPLEX, OSKAR_CPU, num_vis,
            &status);
    oskar_Mem* weight = oskar_mem_create(type, OSKAR_CPU, num_vis, &status);
    oskar_mem_random_gaussian(uu, 0, 1, 2, 3, 100.0, &status);
    oskar_mem_random_gaussian(vv, 4, 5, 6, 7, 100.0, &status);
    oskar_mem_set_value_real(vis, 1.0, 0, num_vis, &status);
    oskar_mem_set_value_real(weight, 1.0, 0, num_vis, &status);

    // Grid visibility data.
    double plane_norm = 0.0;
    oskar_imager_update_plane(im, num_vis, uu, vv, ww, vis, weight, grid,
            &plane_norm, 0, &status);
    ASSERT_DOUBLE_EQ((double)num_vis, plane_norm);

    // Sum the grid.
    double2* t = oskar_mem_double2(grid, &status);
    double sum = 0.0;
    for (int i = 0; i < grid_size; i++) sum += t[i].x;
    ASSERT_DOUBLE_EQ((double)num_vis, sum);

    // Finalise the image.
    oskar_imager_finalise_plane(im, grid, plane_norm, &status);
    ASSERT_EQ(0, status);

#ifdef WRITE_FITS
    // Get the real part only.
    if (oskar_mem_precision(grid) == OSKAR_DOUBLE)
    {
        double *t = oskar_mem_double(grid, &status);
        for (int j = 0; j < grid_size; ++j) t[j] = t[2 * j];
    }
    else
    {
        float *t = oskar_mem_float(grid, &status);
        for (int j = 0; j < grid_size; ++j) t[j] = t[2 * j];
    }

    // Save the real part.
    fitsfile* f;
    long naxes[2] = {size, size}, firstpix[2] = {1, 1};
    fits_create_file(&f, "test_imager_grid_sum.fits", &status);
    fits_create_img(f, (type == OSKAR_DOUBLE ? DOUBLE_IMG : FLOAT_IMG),
            2, naxes, &status);
    fits_write_pix(f, (type == OSKAR_DOUBLE ? TDOUBLE : TFLOAT),
            firstpix, grid_size, oskar_mem_void(grid), &status);
    fits_close_file(f, &status);
#endif

    // Clean up.
    oskar_imager_free(im, &status);
    oskar_mem_free(uu, &status);
    oskar_mem_free(vv, &status);
    oskar_mem_free(ww, &status);
    oskar_mem_free(vis, &status);
    oskar_mem_free(weight, &status);
    oskar_mem_free(grid, &status);
}
Пример #14
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);
}
void oskar_element_load_cst(oskar_Element* data, oskar_Log* log,
        int port, double freq_hz, const char* filename,
        double closeness, double closeness_inc, int ignore_at_poles,
        int ignore_below_horizon, int* status)
{
    int i, n = 0, type = OSKAR_DOUBLE;
    size_t fname_len;
    oskar_Splines *data_h_re = 0, *data_h_im = 0;
    oskar_Splines *data_v_re = 0, *data_v_im = 0;
    oskar_Mem *theta, *phi, *h_re, *h_im, *v_re, *v_im, *weight;

    /* Declare the line buffer. */
    char *line = 0, *dbi = 0, *ludwig3 = 0;
    size_t bufsize = 0;
    FILE* file;

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

    /* Check port number. */
    if (port != 0 && port != 1 && port != 2)
    {
        *status = OSKAR_ERR_INVALID_ARGUMENT;
        return;
    }

    /* Check the data type. */
    if (oskar_element_precision(data) != type)
    {
        *status = OSKAR_ERR_TYPE_MISMATCH;
        return;
    }

    /* Check the location. */
    if (oskar_element_mem_location(data) != OSKAR_CPU)
    {
        *status = OSKAR_ERR_BAD_LOCATION;
        return;
    }

    /* Check if this frequency has already been set, and get its index if so. */
    n = data->num_freq;
    for (i = 0; i < n; ++i)
    {
        if (fabs(data->freqs_hz[i] - freq_hz) <= freq_hz * DBL_EPSILON)
            break;
    }

    /* Expand arrays to hold data for a new frequency, if needed. */
    if (i >= data->num_freq)
    {
        i = data->num_freq;
        oskar_element_resize_freq_data(data, i + 1, status);
        data->freqs_hz[i] = freq_hz;
    }

    /* Get pointers to surface data based on port number and frequency index. */
    if (port == 1 || port == 0)
    {
        data_h_re = oskar_element_x_h_re(data, i);
        data_h_im = oskar_element_x_h_im(data, i);
        data_v_re = oskar_element_x_v_re(data, i);
        data_v_im = oskar_element_x_v_im(data, i);
    }
    else if (port == 2)
    {
        data_h_re = oskar_element_y_h_re(data, i);
        data_h_im = oskar_element_y_h_im(data, i);
        data_v_re = oskar_element_y_v_re(data, i);
        data_v_im = oskar_element_y_v_im(data, i);
    }

    /* Open the file. */
    fname_len = 1 + strlen(filename);
    file = fopen(filename, "r");
    if (!file)
    {
        *status = OSKAR_ERR_FILE_IO;
        return;
    }

    /* Read the first line to check units and coordinate system. */
    if (oskar_getline(&line, &bufsize, file) < 0)
    {
        *status = OSKAR_ERR_FILE_IO;
        free(line);
        fclose(file);
        return;
    }

    /* Check for presence of "dBi". */
    dbi = strstr(line, "dBi");

    /* Check for data in Ludwig-3 polarisation system. */
    ludwig3 = strstr(line, "Horiz");

    /* Create local arrays to hold data for fitting. */
    theta  = oskar_mem_create(type, OSKAR_CPU, 0, status);
    phi    = oskar_mem_create(type, OSKAR_CPU, 0, status);
    h_re   = oskar_mem_create(type, OSKAR_CPU, 0, status);
    h_im   = oskar_mem_create(type, OSKAR_CPU, 0, status);
    v_re   = oskar_mem_create(type, OSKAR_CPU, 0, status);
    v_im   = oskar_mem_create(type, OSKAR_CPU, 0, status);
    weight = oskar_mem_create(type, OSKAR_CPU, 0, status);
    if (*status) return;

    /* Loop over and read each line in the file. */
    n = 0;
    while (oskar_getline(&line, &bufsize, file) != OSKAR_ERR_EOF)
    {
        double t = 0., p = 0., abs_theta_horiz, phase_theta_horiz;
        double abs_phi_verti, phase_phi_verti;
        double theta_horiz_re, theta_horiz_im, phi_verti_re, phi_verti_im;
        double h_re_, h_im_, v_re_, v_im_;
        void *p_theta = 0, *p_phi = 0, *p_h_re = 0, *p_h_im = 0, *p_v_re = 0;
        void *p_v_im = 0, *p_weight = 0;

        /* Parse the line, and skip if data were not read correctly. */
        if (sscanf(line, "%lf %lf %*f %lf %lf %lf %lf %*f", &t, &p,
                    &abs_theta_horiz, &phase_theta_horiz,
                    &abs_phi_verti, &phase_phi_verti) != 6)
            continue;

        /* Ignore data below horizon if requested. */
        if (ignore_below_horizon && t > 90.0) continue;

        /* Ignore data at poles if requested. */
        if (ignore_at_poles)
            if (t < 1e-6 || t > (180.0 - 1e-6)) continue;

        /* Convert angular measures to radians. */
        t *= DEG2RAD;
        p *= DEG2RAD;
        phase_theta_horiz *= DEG2RAD;
        phase_phi_verti *= DEG2RAD;

        /* Ensure enough space in arrays. */
        if (n % 100 == 0)
        {
            int size;
            size = n + 100;
            oskar_mem_realloc(theta, size, status);
            oskar_mem_realloc(phi, size, status);
            oskar_mem_realloc(h_re, size, status);
            oskar_mem_realloc(h_im, size, status);
            oskar_mem_realloc(v_re, size, status);
            oskar_mem_realloc(v_im, size, status);
            oskar_mem_realloc(weight, size, status);
            if (*status) break;
        }
        p_theta  = oskar_mem_void(theta);
        p_phi    = oskar_mem_void(phi);
        p_h_re   = oskar_mem_void(h_re);
        p_h_im   = oskar_mem_void(h_im);
        p_v_re   = oskar_mem_void(v_re);
        p_v_im   = oskar_mem_void(v_im);
        p_weight = oskar_mem_void(weight);

        /* Convert decibel to linear scale if necessary. */
        if (dbi)
        {
            abs_theta_horiz = pow(10.0, abs_theta_horiz / 10.0);
            abs_phi_verti   = pow(10.0, abs_phi_verti / 10.0);
        }

        /* Amp,phase to real,imag conversion. */
        theta_horiz_re = abs_theta_horiz * cos(phase_theta_horiz);
        theta_horiz_im = abs_theta_horiz * sin(phase_theta_horiz);
        phi_verti_re = abs_phi_verti * cos(phase_phi_verti);
        phi_verti_im = abs_phi_verti * sin(phase_phi_verti);

        /* Convert to Ludwig-3 polarisation system if required. */
        if (ludwig3)
        {
            /* Already in Ludwig-3: No conversion required. */
            h_re_ = theta_horiz_re;
            h_im_ = theta_horiz_im;
            v_re_ = phi_verti_re;
            v_im_ = phi_verti_im;
        }
        else
        {
            /* Convert from theta/phi to Ludwig-3. */
            double cos_p, sin_p;
            sin_p = sin(p);
            cos_p = cos(p);
            h_re_ = theta_horiz_re * cos_p - phi_verti_re * sin_p;
            h_im_ = theta_horiz_im * cos_p - phi_verti_im * sin_p;
            v_re_ = theta_horiz_re * sin_p + phi_verti_re * cos_p;
            v_im_ = theta_horiz_im * sin_p + phi_verti_im * cos_p;
        }

        /* Store the surface data in Ludwig-3 format. */
        ((double*)p_theta)[n]  = t;
        ((double*)p_phi)[n]    = p;
        ((double*)p_h_re)[n]   = h_re_;
        ((double*)p_h_im)[n]   = h_im_;
        ((double*)p_v_re)[n]   = v_re_;
        ((double*)p_v_im)[n]   = v_im_;
        ((double*)p_weight)[n] = 1.0;

        /* Increment array pointer. */
        n++;
    }

    /* Free the line buffer and close the file. */
    free(line);
    fclose(file);

    /* Fit splines to the surface data. */
    fit_splines(log, data_h_re, n, theta, phi, h_re, weight,
            closeness, closeness_inc, "H [real]", status);
    fit_splines(log, data_h_im, n, theta, phi, h_im, weight,
            closeness, closeness_inc, "H [imag]", status);
    fit_splines(log, data_v_re, n, theta, phi, v_re, weight,
            closeness, closeness_inc, "V [real]", status);
    fit_splines(log, data_v_im, n, theta, phi, v_im, weight,
            closeness, closeness_inc, "V [imag]", status);

    /* Store the filename. */
    if (port == 0)
    {
        oskar_mem_append_raw(data->filename_x[i], filename, OSKAR_CHAR,
                OSKAR_CPU, fname_len, status);
        oskar_mem_append_raw(data->filename_y[i], filename, OSKAR_CHAR,
                OSKAR_CPU, fname_len, status);
    }
    else if (port == 1)
    {
        oskar_mem_append_raw(data->filename_x[i], filename, OSKAR_CHAR,
                OSKAR_CPU, fname_len, status);
    }
    else if (port == 2)
    {
        oskar_mem_append_raw(data->filename_y[i], filename, OSKAR_CHAR,
                OSKAR_CPU, fname_len, status);
    }

    /* Copy X to Y if both ports are the same. */
    if (port == 0)
    {
        oskar_splines_copy(data->y_h_re[i], data->x_h_re[i], status);
        oskar_splines_copy(data->y_h_im[i], data->x_h_im[i], status);
        oskar_splines_copy(data->y_v_re[i], data->x_v_re[i], status);
        oskar_splines_copy(data->y_v_im[i], data->x_v_im[i], status);
    }

    /* Free local arrays. */
    oskar_mem_free(theta, status);
    oskar_mem_free(phi, status);
    oskar_mem_free(h_re, status);
    oskar_mem_free(h_im, status);
    oskar_mem_free(v_re, status);
    oskar_mem_free(v_im, status);
    oskar_mem_free(weight, status);
}