Esempio n. 1
0
/* Wrapper. */
void oskar_evaluate_jones_K(oskar_Jones* K, int num_sources,
        const oskar_Mem* l, const oskar_Mem* m, const oskar_Mem* n,
        const oskar_Mem* u, const oskar_Mem* v, const oskar_Mem* w,
        double frequency_hz, const oskar_Mem* source_filter,
        double source_filter_min, double source_filter_max, int* status)
{
    int num_stations, jones_type, base_type, location;
    double wavenumber;

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

    /* Get the Jones matrix block meta-data. */
    jones_type = oskar_jones_type(K);
    base_type = oskar_type_precision(jones_type);
    location = oskar_jones_mem_location(K);
    num_stations = oskar_jones_num_stations(K);
    wavenumber = 2.0 * M_PI * frequency_hz / 299792458.0;

    /* Check that the data is in the right location. */
    if (oskar_mem_location(l) != location ||
            oskar_mem_location(m) != location ||
            oskar_mem_location(n) != location ||
            oskar_mem_location(source_filter) != location ||
            oskar_mem_location(u) != location ||
            oskar_mem_location(v) != location ||
            oskar_mem_location(w) != location)
    {
        *status = OSKAR_ERR_LOCATION_MISMATCH;
        return;
    }

    /* Check that the data are of the right type. */
    if (!oskar_type_is_complex(jones_type) ||
            oskar_type_is_matrix(jones_type))
    {
        *status = OSKAR_ERR_BAD_DATA_TYPE;
        return;
    }
    if (base_type != oskar_mem_type(l) || base_type != oskar_mem_type(m) ||
            base_type != oskar_mem_type(n) || base_type != oskar_mem_type(u) ||
            base_type != oskar_mem_type(v) || base_type != oskar_mem_type(w) ||
            base_type != oskar_mem_type(source_filter))
    {
        *status = OSKAR_ERR_TYPE_MISMATCH;
        return;
    }

    /* Evaluate Jones matrices. */
    if (location == OSKAR_GPU)
    {
#ifdef OSKAR_HAVE_CUDA
        if (jones_type == OSKAR_SINGLE_COMPLEX)
        {
            oskar_evaluate_jones_K_cuda_f(oskar_jones_float2(K, status),
                    num_sources,
                    oskar_mem_float_const(l, status),
                    oskar_mem_float_const(m, status),
                    oskar_mem_float_const(n, status),
                    num_stations,
                    oskar_mem_float_const(u, status),
                    oskar_mem_float_const(v, status),
                    oskar_mem_float_const(w, status), wavenumber,
                    oskar_mem_float_const(source_filter, status),
                    source_filter_min, source_filter_max);
        }
        else if (jones_type == OSKAR_DOUBLE_COMPLEX)
        {
            oskar_evaluate_jones_K_cuda_d(oskar_jones_double2(K, status),
                    num_sources,
                    oskar_mem_double_const(l, status),
                    oskar_mem_double_const(m, status),
                    oskar_mem_double_const(n, status),
                    num_stations,
                    oskar_mem_double_const(u, status),
                    oskar_mem_double_const(v, status),
                    oskar_mem_double_const(w, status), wavenumber,
                    oskar_mem_double_const(source_filter, status),
                    source_filter_min, source_filter_max);
        }
        oskar_device_check_error(status);
#else
        *status = OSKAR_ERR_CUDA_NOT_AVAILABLE;
#endif
    }
    else if (location == OSKAR_CPU)
    {
        if (jones_type == OSKAR_SINGLE_COMPLEX)
        {
            oskar_evaluate_jones_K_f(oskar_jones_float2(K, status),
                    num_sources,
                    oskar_mem_float_const(l, status),
                    oskar_mem_float_const(m, status),
                    oskar_mem_float_const(n, status),
                    num_stations,
                    oskar_mem_float_const(u, status),
                    oskar_mem_float_const(v, status),
                    oskar_mem_float_const(w, status), wavenumber,
                    oskar_mem_float_const(source_filter, status),
                    source_filter_min, source_filter_max);

        }
        else if (jones_type == OSKAR_DOUBLE_COMPLEX)
        {
            oskar_evaluate_jones_K_d(oskar_jones_double2(K, status),
                    num_sources,
                    oskar_mem_double_const(l, status),
                    oskar_mem_double_const(m, status),
                    oskar_mem_double_const(n, status),
                    num_stations,
                    oskar_mem_double_const(u, status),
                    oskar_mem_double_const(v, status),
                    oskar_mem_double_const(w, status), wavenumber,
                    oskar_mem_double_const(source_filter, status),
                    source_filter_min, source_filter_max);
        }
    }
}
Esempio n. 2
0
static void set_up_device_data(oskar_Simulator* h, int* status)
{
    int i, dev_loc, complx, vistype, num_stations, num_src;
    if (*status) return;

    /* Get local variables. */
    num_stations = oskar_telescope_num_stations(h->tel);
    num_src      = h->max_sources_per_chunk;
    complx       = (h->prec) | OSKAR_COMPLEX;
    vistype      = complx;
    if (oskar_telescope_pol_mode(h->tel) == OSKAR_POL_MODE_FULL)
        vistype |= OSKAR_MATRIX;

    /* Expand the number of devices to the number of selected GPUs,
     * if required. */
    if (h->num_devices < h->num_gpus)
        oskar_simulator_set_num_devices(h, h->num_gpus);

    for (i = 0; i < h->num_devices; ++i)
    {
        DeviceData* d = &h->d[i];
        d->previous_chunk_index = -1;

        /* Select the device. */
        if (i < h->num_gpus)
        {
            oskar_device_set(h->gpu_ids[i], status);
            dev_loc = OSKAR_GPU;
        }
        else
        {
            dev_loc = OSKAR_CPU;
        }

        /* Timers. */
        if (!d->tmr_compute)
        {
            d->tmr_compute   = oskar_timer_create(OSKAR_TIMER_NATIVE);
            d->tmr_copy      = oskar_timer_create(OSKAR_TIMER_NATIVE);
            d->tmr_clip      = oskar_timer_create(OSKAR_TIMER_NATIVE);
            d->tmr_E         = oskar_timer_create(OSKAR_TIMER_NATIVE);
            d->tmr_K         = oskar_timer_create(OSKAR_TIMER_NATIVE);
            d->tmr_join      = oskar_timer_create(OSKAR_TIMER_NATIVE);
            d->tmr_correlate = oskar_timer_create(OSKAR_TIMER_NATIVE);
        }

        /* Visibility blocks. */
        if (!d->vis_block)
        {
            d->vis_block = oskar_vis_block_create_from_header(dev_loc,
                    h->header, status);
            d->vis_block_cpu[0] = oskar_vis_block_create_from_header(OSKAR_CPU,
                    h->header, status);
            d->vis_block_cpu[1] = oskar_vis_block_create_from_header(OSKAR_CPU,
                    h->header, status);
        }
        oskar_vis_block_clear(d->vis_block, status);
        oskar_vis_block_clear(d->vis_block_cpu[0], status);
        oskar_vis_block_clear(d->vis_block_cpu[1], status);

        /* Device scratch memory. */
        if (!d->tel)
        {
            d->u = oskar_mem_create(h->prec, dev_loc, num_stations, status);
            d->v = oskar_mem_create(h->prec, dev_loc, num_stations, status);
            d->w = oskar_mem_create(h->prec, dev_loc, num_stations, status);
            d->chunk = oskar_sky_create(h->prec, dev_loc, num_src, status);
            d->chunk_clip = oskar_sky_create(h->prec, dev_loc, num_src, status);
            d->tel = oskar_telescope_create_copy(h->tel, dev_loc, status);
            d->J = oskar_jones_create(vistype, dev_loc, num_stations, num_src,
                    status);
            d->R = oskar_type_is_matrix(vistype) ? oskar_jones_create(vistype,
                    dev_loc, num_stations, num_src, status) : 0;
            d->E = oskar_jones_create(vistype, dev_loc, num_stations, num_src,
                    status);
            d->K = oskar_jones_create(complx, dev_loc, num_stations, num_src,
                    status);
            d->Z = 0;
            d->station_work = oskar_station_work_create(h->prec, dev_loc,
                    status);
        }
    }
}
Esempio n. 3
0
oskar_VisHeader* oskar_vis_header_create(int amp_type, int coord_precision,
        int max_times_per_block, int num_times_total,
        int max_channels_per_block, int num_channels_total, int num_stations,
        int write_autocorr, int write_crosscor, int* status)
{
    oskar_VisHeader* hdr = 0;

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

    /* Check type. */
    if (!oskar_type_is_complex(amp_type))
    {
        *status = OSKAR_ERR_BAD_DATA_TYPE;
        return 0;
    }

    /* Allocate the structure. */
    hdr = (oskar_VisHeader*) malloc(sizeof(oskar_VisHeader));
    if (!hdr)
    {
        *status = OSKAR_ERR_MEMORY_ALLOC_FAILURE;
        return 0;
    }
    hdr->amp_type = amp_type;
    hdr->coord_precision = coord_precision;

    /* Set number of tags per block in the binary file. */
    /* This must be updated if the number of fields written to file from
     * the oskar_VisBlock structure is changed. */
    hdr->num_tags_per_block = 1;
    if (write_crosscor) hdr->num_tags_per_block += 4;
    if (write_autocorr) hdr->num_tags_per_block += 1;

    /* Set dimensions. */
    hdr->max_times_per_block    = max_times_per_block;
    hdr->num_times_total        = num_times_total;
    hdr->max_channels_per_block = max_channels_per_block;
    hdr->num_channels_total     = num_channels_total;
    hdr->num_stations           = num_stations;

    /* Set default polarisation type. */
    if (oskar_type_is_matrix(amp_type))
        hdr->pol_type = OSKAR_VIS_POL_TYPE_LINEAR_XX_XY_YX_YY;
    else
        hdr->pol_type = OSKAR_VIS_POL_TYPE_STOKES_I;

    /* Initialise meta-data. */
    hdr->write_autocorr = write_autocorr;
    hdr->write_crosscorr = write_crosscor;
    hdr->freq_start_hz = 0.0;
    hdr->freq_inc_hz = 0.0;
    hdr->channel_bandwidth_hz = 0.0;
    hdr->time_start_mjd_utc = 0.0;
    hdr->time_inc_sec = 0.0;
    hdr->time_average_sec = 0.0;
    hdr->phase_centre_type = 0;
    hdr->phase_centre_deg[0] = 0.0;
    hdr->phase_centre_deg[1] = 0.0;
    hdr->telescope_centre_lon_deg = 0.0;
    hdr->telescope_centre_lat_deg = 0.0;
    hdr->telescope_centre_alt_m = 0.0;

    /* Initialise CPU memory. */
    hdr->telescope_path = oskar_mem_create(OSKAR_CHAR, OSKAR_CPU, 0, status);
    hdr->settings = oskar_mem_create(OSKAR_CHAR, OSKAR_CPU, 0, status);
    hdr->station_x_offset_ecef_metres = oskar_mem_create(coord_precision,
            OSKAR_CPU, num_stations, status);
    hdr->station_y_offset_ecef_metres = oskar_mem_create(coord_precision,
            OSKAR_CPU, num_stations, status);
    hdr->station_z_offset_ecef_metres = oskar_mem_create(coord_precision,
            OSKAR_CPU, num_stations, status);

    /* Return handle to structure. */
    return hdr;
}
void oskar_auto_correlate(oskar_Mem* vis, int n_sources, const oskar_Jones* J,
        const oskar_Sky* sky, int* status)
{
    int jones_type, base_type, location, matrix_type, n_stations;

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

    /* Get the data dimensions. */
    n_stations = oskar_jones_num_stations(J);

    /* Check data locations. */
    location = oskar_sky_mem_location(sky);
    if (oskar_jones_mem_location(J) != location ||
            oskar_mem_location(vis) != location)
    {
        *status = OSKAR_ERR_LOCATION_MISMATCH;
        return;
    }

    /* Check for consistent data types. */
    jones_type = oskar_jones_type(J);
    base_type = oskar_sky_precision(sky);
    matrix_type = oskar_type_is_matrix(jones_type) &&
            oskar_mem_is_matrix(vis);
    if (oskar_mem_precision(vis) != base_type ||
            oskar_type_precision(jones_type) != base_type)
    {
        *status = OSKAR_ERR_TYPE_MISMATCH;
        return;
    }
    if (oskar_mem_type(vis) != jones_type)
    {
        *status = OSKAR_ERR_TYPE_MISMATCH;
        return;
    }

    /* If neither single or double precision, return error. */
    if (base_type != OSKAR_SINGLE && base_type != OSKAR_DOUBLE)
    {
        *status = OSKAR_ERR_BAD_DATA_TYPE;
        return;
    }

    /* Check the input dimensions. */
    if (oskar_jones_num_sources(J) < n_sources)
    {
        *status = OSKAR_ERR_DIMENSION_MISMATCH;
        return;
    }

    /* Select kernel. */
    if (base_type == OSKAR_DOUBLE)
    {
        const double *I_, *Q_, *U_, *V_;
        I_ = oskar_mem_double_const(oskar_sky_I_const(sky), status);
        Q_ = oskar_mem_double_const(oskar_sky_Q_const(sky), status);
        U_ = oskar_mem_double_const(oskar_sky_U_const(sky), status);
        V_ = oskar_mem_double_const(oskar_sky_V_const(sky), status);

        if (matrix_type)
        {
            double4c *vis_;
            const double4c *J_;
            vis_ = oskar_mem_double4c(vis, status);
            J_   = oskar_jones_double4c_const(J, status);

            if (location == OSKAR_GPU)
            {
#ifdef OSKAR_HAVE_CUDA
                oskar_auto_correlate_cuda_d(n_sources, n_stations,
                        J_, I_, Q_, U_, V_, vis_);
                oskar_device_check_error(status);
#else
                *status = OSKAR_ERR_CUDA_NOT_AVAILABLE;
#endif
            }
            else /* CPU */
            {
                oskar_auto_correlate_omp_d(n_sources, n_stations,
                        J_, I_, Q_, U_, V_, vis_);
            }
        }
        else /* Scalar version. */
        {
            double2 *vis_;
            const double2 *J_;
            vis_ = oskar_mem_double2(vis, status);
            J_   = oskar_jones_double2_const(J, status);

            if (location == OSKAR_GPU)
            {
#ifdef OSKAR_HAVE_CUDA
                oskar_auto_correlate_scalar_cuda_d(n_sources, n_stations,
                        J_, I_, vis_);
                oskar_device_check_error(status);
#else
                *status = OSKAR_ERR_CUDA_NOT_AVAILABLE;
#endif
            }
            else /* CPU */
            {
                oskar_auto_correlate_scalar_omp_d(n_sources, n_stations,
                        J_, I_, vis_);
            }
        }
    }
    else /* Single precision. */
    {
        const float *I_, *Q_, *U_, *V_;
        I_ = oskar_mem_float_const(oskar_sky_I_const(sky), status);
        Q_ = oskar_mem_float_const(oskar_sky_Q_const(sky), status);
        U_ = oskar_mem_float_const(oskar_sky_U_const(sky), status);
        V_ = oskar_mem_float_const(oskar_sky_V_const(sky), status);

        if (matrix_type)
        {
            float4c *vis_;
            const float4c *J_;
            vis_ = oskar_mem_float4c(vis, status);
            J_   = oskar_jones_float4c_const(J, status);

            if (location == OSKAR_GPU)
            {
#ifdef OSKAR_HAVE_CUDA
                oskar_auto_correlate_cuda_f(n_sources, n_stations,
                        J_, I_, Q_, U_, V_, vis_);
                oskar_device_check_error(status);
#else
                *status = OSKAR_ERR_CUDA_NOT_AVAILABLE;
#endif
            }
            else /* CPU */
            {
                oskar_auto_correlate_omp_f(n_sources, n_stations,
                        J_, I_, Q_, U_, V_, vis_);
            }
        }
        else /* Scalar version. */
        {
            float2 *vis_;
            const float2 *J_;
            vis_ = oskar_mem_float2(vis, status);
            J_   = oskar_jones_float2_const(J, status);

            if (location == OSKAR_GPU)
            {
#ifdef OSKAR_HAVE_CUDA
                oskar_auto_correlate_scalar_cuda_f(n_sources, n_stations,
                        J_, I_, vis_);
                oskar_device_check_error(status);
#else
                *status = OSKAR_ERR_CUDA_NOT_AVAILABLE;
#endif
            }
            else /* CPU */
            {
                oskar_auto_correlate_scalar_omp_f(n_sources, n_stations,
                        J_, I_, vis_);
            }
        }
    }
}
void oskar_imager_read_coords_vis(oskar_Imager* h, const char* filename,
        int i_file, int num_files, int* percent_done, int* percent_next,
        int* status)
{
    oskar_Binary* vis_file;
    oskar_VisHeader* header;
    oskar_Mem *uu, *vv, *ww, *weight, *time_centroid, *time_slice;
    int coord_prec, max_times_per_block, tags_per_block, i_block, num_blocks;
    int num_times_total, num_stations, num_baselines, num_pols;
    double time_start_mjd, time_inc_sec;
    if (*status) return;

    /* Read the header. */
    vis_file = oskar_binary_create(filename, 'r', status);
    header = oskar_vis_header_read(vis_file, status);
    if (*status)
    {
        oskar_vis_header_free(header, status);
        oskar_binary_free(vis_file);
        return;
    }
    coord_prec = oskar_vis_header_coord_precision(header);
    max_times_per_block = oskar_vis_header_max_times_per_block(header);
    tags_per_block = oskar_vis_header_num_tags_per_block(header);
    num_times_total = oskar_vis_header_num_times_total(header);
    num_stations = oskar_vis_header_num_stations(header);
    num_baselines = num_stations * (num_stations - 1) / 2;
    num_pols = oskar_type_is_matrix(oskar_vis_header_amp_type(header)) ? 4 : 1;
    num_blocks = (num_times_total + max_times_per_block - 1) /
            max_times_per_block;
    time_start_mjd = oskar_vis_header_time_start_mjd_utc(header) * 86400.0;
    time_inc_sec = oskar_vis_header_time_inc_sec(header);

    /* Set visibility meta-data. */
    oskar_imager_set_vis_frequency(h,
            oskar_vis_header_freq_start_hz(header),
            oskar_vis_header_freq_inc_hz(header),
            oskar_vis_header_num_channels_total(header));
    oskar_imager_set_vis_phase_centre(h,
            oskar_vis_header_phase_centre_ra_deg(header),
            oskar_vis_header_phase_centre_dec_deg(header));

    /* Create scratch arrays. Weights are all 1. */
    uu = oskar_mem_create(coord_prec, OSKAR_CPU, 0, status);
    vv = oskar_mem_create(coord_prec, OSKAR_CPU, 0, status);
    ww = oskar_mem_create(coord_prec, OSKAR_CPU, 0, status);
    time_centroid = oskar_mem_create(OSKAR_DOUBLE,
            OSKAR_CPU, num_baselines * max_times_per_block, status);
    time_slice = oskar_mem_create_alias(0, 0, 0, status);
    weight = oskar_mem_create(h->imager_prec,
            OSKAR_CPU, num_baselines * num_pols * max_times_per_block, status);
    oskar_mem_set_value_real(weight, 1.0, 0, 0, status);

    /* Loop over visibility blocks. */
    for (i_block = 0; i_block < num_blocks; ++i_block)
    {
        int t, num_times, num_channels, start_time, start_chan, end_chan;
        int dim_start_and_size[6];
        size_t num_rows;
        if (*status) break;

        /* Read block metadata. */
        oskar_timer_resume(h->tmr_read);
        oskar_binary_set_query_search_start(vis_file,
                i_block * tags_per_block, status);
        oskar_binary_read(vis_file, OSKAR_INT,
                OSKAR_TAG_GROUP_VIS_BLOCK,
                OSKAR_VIS_BLOCK_TAG_DIM_START_AND_SIZE, i_block,
                sizeof(dim_start_and_size), dim_start_and_size, status);
        start_time   = dim_start_and_size[0];
        start_chan   = dim_start_and_size[1];
        num_times    = dim_start_and_size[2];
        num_channels = dim_start_and_size[3];
        num_rows     = num_times * num_baselines;
        end_chan     = start_chan + num_channels - 1;

        /* Fill in the time centroid values. */
        for (t = 0; t < num_times; ++t)
        {
            oskar_mem_set_alias(time_slice, time_centroid,
                    t * num_baselines, num_baselines, status);
            oskar_mem_set_value_real(time_slice,
                    time_start_mjd + (start_time + t + 0.5) * time_inc_sec,
                    0, num_baselines, status);
        }

        /* Read the baseline coordinates. */
        oskar_binary_read_mem(vis_file, uu, OSKAR_TAG_GROUP_VIS_BLOCK,
                OSKAR_VIS_BLOCK_TAG_BASELINE_UU, i_block, status);
        oskar_binary_read_mem(vis_file, vv, OSKAR_TAG_GROUP_VIS_BLOCK,
                OSKAR_VIS_BLOCK_TAG_BASELINE_VV, i_block, status);
        oskar_binary_read_mem(vis_file, ww, OSKAR_TAG_GROUP_VIS_BLOCK,
                OSKAR_VIS_BLOCK_TAG_BASELINE_WW, i_block, status);

        /* Update the imager with the data. */
        oskar_timer_pause(h->tmr_read);
        oskar_imager_update(h, num_rows, start_chan, end_chan, num_pols,
                uu, vv, ww, 0, weight, time_centroid, status);
        *percent_done = (int) round(100.0 * (
                (i_block + 1) / (double)(num_blocks * 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(uu, status);
    oskar_mem_free(vv, status);
    oskar_mem_free(ww, status);
    oskar_mem_free(weight, status);
    oskar_mem_free(time_centroid, status);
    oskar_mem_free(time_slice, status);
    oskar_vis_header_free(header, status);
    oskar_binary_free(vis_file);
}
Esempio n. 6
0
/* Wrapper. */
void oskar_evaluate_jones_R(oskar_Jones* R, int num_sources,
        const oskar_Mem* ra_rad, const oskar_Mem* dec_rad,
        const oskar_Telescope* telescope, double gast, int* status)
{
    int i, n, num_stations, jones_type, base_type, location;
    double latitude, lst;
    oskar_Mem *R_station;

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

    /* Get the Jones matrix block meta-data. */
    jones_type = oskar_jones_type(R);
    base_type = oskar_type_precision(jones_type);
    location = oskar_jones_mem_location(R);
    num_stations = oskar_jones_num_stations(R);
    n = (oskar_telescope_allow_station_beam_duplication(telescope) ? 1 : num_stations);

    /* Check that the data dimensions are OK. */
    if (num_sources > (int)oskar_mem_length(ra_rad) ||
            num_sources > (int)oskar_mem_length(dec_rad) ||
            num_sources > oskar_jones_num_sources(R) ||
            num_stations != oskar_telescope_num_stations(telescope))
    {
        *status = OSKAR_ERR_DIMENSION_MISMATCH;
        return;
    }

    /* Check that the data is in the right location. */
    if (location != oskar_mem_location(ra_rad) ||
            location != oskar_mem_location(dec_rad))
    {
        *status = OSKAR_ERR_LOCATION_MISMATCH;
        return;
    }

    /* Check that the data is of the right type. */
    if (!oskar_type_is_matrix(jones_type))
    {
        *status = OSKAR_ERR_BAD_DATA_TYPE;
        return;
    }
    if (base_type != oskar_mem_precision(ra_rad) ||
            base_type != oskar_mem_precision(dec_rad))
    {
        *status = OSKAR_ERR_TYPE_MISMATCH;
        return;
    }

    /* Evaluate Jones matrix for each source for appropriate stations. */
    R_station = oskar_mem_create_alias(0, 0, 0, status);
    if (location == OSKAR_GPU)
    {
#ifdef OSKAR_HAVE_CUDA
        for (i = 0; i < n; ++i)
        {
            const oskar_Station* station;

            /* Get station data. */
            station = oskar_telescope_station_const(telescope, i);
            latitude = oskar_station_lat_rad(station);
            lst = gast + oskar_station_lon_rad(station);
            oskar_jones_get_station_pointer(R_station, R, i, status);

            /* Evaluate source parallactic angles. */
            if (base_type == OSKAR_SINGLE)
            {
                oskar_evaluate_jones_R_cuda_f(
                        oskar_mem_float4c(R_station, status), num_sources,
                        oskar_mem_float_const(ra_rad, status),
                        oskar_mem_float_const(dec_rad, status),
                        (float)latitude, (float)lst);
            }
            else if (base_type == OSKAR_DOUBLE)
            {
                oskar_evaluate_jones_R_cuda_d(
                        oskar_mem_double4c(R_station, status), num_sources,
                        oskar_mem_double_const(ra_rad, status),
                        oskar_mem_double_const(dec_rad, status),
                        latitude, lst);
            }
        }
        oskar_device_check_error(status);
#else
        *status = OSKAR_ERR_CUDA_NOT_AVAILABLE;
#endif
    }
    else if (location == OSKAR_CPU)
    {
        for (i = 0; i < n; ++i)
        {
            const oskar_Station* station;

            /* Get station data. */
            station = oskar_telescope_station_const(telescope, i);
            latitude = oskar_station_lat_rad(station);
            lst = gast + oskar_station_lon_rad(station);
            oskar_jones_get_station_pointer(R_station, R, i, status);

            /* Evaluate source parallactic angles. */
            if (base_type == OSKAR_SINGLE)
            {
                oskar_evaluate_jones_R_f(
                        oskar_mem_float4c(R_station, status), num_sources,
                        oskar_mem_float_const(ra_rad, status),
                        oskar_mem_float_const(dec_rad, status),
                        (float)latitude, (float)lst);
            }
            else if (base_type == OSKAR_DOUBLE)
            {
                oskar_evaluate_jones_R_d(
                        oskar_mem_double4c(R_station, status), num_sources,
                        oskar_mem_double_const(ra_rad, status),
                        oskar_mem_double_const(dec_rad, status),
                        latitude, lst);
            }
        }
    }

    /* Copy data for station 0 to stations 1 to n, if using a common sky. */
    if (oskar_telescope_allow_station_beam_duplication(telescope))
    {
        oskar_Mem* R0;
        R0 = oskar_mem_create_alias(0, 0, 0, status);
        oskar_jones_get_station_pointer(R0, R, 0, status);
        for (i = 1; i < num_stations; ++i)
        {
            oskar_jones_get_station_pointer(R_station, R, i, status);
            oskar_mem_copy_contents(R_station, R0, 0, 0,
                    oskar_mem_length(R0), status);
        }
        oskar_mem_free(R0, status);
    }
    oskar_mem_free(R_station, status);
}