Example #1
0
void oskar_sky_copy(oskar_Sky* dst, const oskar_Sky* src, int* status)
{
    int num_sources;

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

    if (oskar_sky_precision(dst) != oskar_sky_precision(src))
    {
        *status = OSKAR_ERR_BAD_DATA_TYPE;
        return;
    }
    if (oskar_sky_capacity(dst) < oskar_sky_capacity(src))
    {
        *status = OSKAR_ERR_DIMENSION_MISMATCH;
        return;
    }

    /* Copy meta data */
    num_sources = src->num_sources;
    dst->num_sources = num_sources;
    dst->use_extended = src->use_extended;
    dst->reference_ra_rad = src->reference_ra_rad;
    dst->reference_dec_rad = src->reference_dec_rad;

    /* Copy the memory blocks */
    oskar_mem_copy_contents(dst->ra_rad, src->ra_rad,
            0, 0, num_sources, status);
    oskar_mem_copy_contents(dst->dec_rad, src->dec_rad,
            0, 0, num_sources, status);
    oskar_mem_copy_contents(dst->I, src->I, 0, 0, num_sources, status);
    oskar_mem_copy_contents(dst->Q, src->Q, 0, 0, num_sources, status);
    oskar_mem_copy_contents(dst->U, src->U, 0, 0, num_sources, status);
    oskar_mem_copy_contents(dst->V, src->V, 0, 0, num_sources, status);
    oskar_mem_copy_contents(dst->reference_freq_hz, src->reference_freq_hz,
            0, 0, num_sources, status);
    oskar_mem_copy_contents(dst->spectral_index, src->spectral_index,
            0, 0, num_sources, status);
    oskar_mem_copy_contents(dst->rm_rad, src->rm_rad,
            0, 0, num_sources, status);
    oskar_mem_copy_contents(dst->l, src->l, 0, 0, num_sources, status);
    oskar_mem_copy_contents(dst->m, src->m, 0, 0, num_sources, status);
    oskar_mem_copy_contents(dst->n, src->n, 0, 0, num_sources, status);
    oskar_mem_copy_contents(dst->fwhm_major_rad, src->fwhm_major_rad,
            0, 0, num_sources, status);
    oskar_mem_copy_contents(dst->fwhm_minor_rad, src->fwhm_minor_rad,
            0, 0, num_sources, status);
    oskar_mem_copy_contents(dst->pa_rad, src->pa_rad,
            0, 0, num_sources, status);
    oskar_mem_copy_contents(dst->gaussian_a, src->gaussian_a,
            0, 0, num_sources, status);
    oskar_mem_copy_contents(dst->gaussian_b, src->gaussian_b,
            0, 0, num_sources, status);
    oskar_mem_copy_contents(dst->gaussian_c, src->gaussian_c,
            0, 0, num_sources, status);
}
Example #2
0
static PyObject* append_file(PyObject* self, PyObject* args)
{
    oskar_Sky *h = 0, *t = 0;
    PyObject* capsule = 0;
    int status = 0;
    const char* filename = 0;
    if (!PyArg_ParseTuple(args, "Os", &capsule, &filename)) return 0;
    if (!(h = get_handle(capsule))) return 0;

    /* Load the sky model. */
    t = oskar_sky_load(filename, oskar_sky_precision(h), &status);
    oskar_sky_append(h, t, &status);
    oskar_sky_free(t, &status);

    /* Check for errors. */
    if (status)
    {
        PyErr_Format(PyExc_RuntimeError,
                "oskar_sky_load() failed with code %d (%s).",
                status, oskar_get_error_string(status));
        return 0;
    }
    return Py_BuildValue("");
}
void oskar_sky_evaluate_gaussian_source_parameters(oskar_Sky* sky,
        int zero_failed_sources, double ra0, double dec0, int* num_failed,
        int* status)
{
    int i, j, num_sources;
    int type;

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

    /* Return if memory is not on the CPU. */
    if (oskar_sky_mem_location(sky) != OSKAR_CPU)
    {
        *status = OSKAR_ERR_BAD_LOCATION;
        return;
    }

    /* Get data type and number of sources. */
    type = oskar_sky_precision(sky);
    num_sources = oskar_sky_num_sources(sky);

    /* Switch on type. */
    if (type == OSKAR_DOUBLE)
    {
        /* Double precision. */
        const double *ra_, *dec_, *maj_, *min_, *pa_;
        double *I_, *Q_, *U_, *V_, *a_, *b_, *c_;
        double cos_pa_2, sin_pa_2, sin_2pa, inv_std_min_2, inv_std_maj_2;
        double ellipse_a, ellipse_b, maj, min, pa, cos_pa, sin_pa, t;
        double l[ELLIPSE_PTS], m[ELLIPSE_PTS];
        double work1[5 * ELLIPSE_PTS], work2[5 * ELLIPSE_PTS];
        double lon[ELLIPSE_PTS], lat[ELLIPSE_PTS];
        double x[ELLIPSE_PTS], y[ELLIPSE_PTS], z[ELLIPSE_PTS];
        ra_  = oskar_mem_double_const(oskar_sky_ra_rad_const(sky), status);
        dec_ = oskar_mem_double_const(oskar_sky_dec_rad_const(sky), status);
        maj_ = oskar_mem_double_const(oskar_sky_fwhm_major_rad_const(sky), status);
        min_ = oskar_mem_double_const(oskar_sky_fwhm_minor_rad_const(sky), status);
        pa_  = oskar_mem_double_const(oskar_sky_position_angle_rad_const(sky), status);
        I_   = oskar_mem_double(oskar_sky_I(sky), status);
        Q_   = oskar_mem_double(oskar_sky_Q(sky), status);
        U_   = oskar_mem_double(oskar_sky_U(sky), status);
        V_   = oskar_mem_double(oskar_sky_V(sky), status);
        a_   = oskar_mem_double(oskar_sky_gaussian_a(sky), status);
        b_   = oskar_mem_double(oskar_sky_gaussian_b(sky), status);
        c_   = oskar_mem_double(oskar_sky_gaussian_c(sky), status);

        for (i = 0; i < num_sources; ++i)
        {
            /* Note: could do something different from the projection below
             * in the case of a line (i.e. maj or min = 0), as in this case
             * there is no ellipse to project, only two points.
             * -- This continue could then be a if() .. else() instead.
             */
            if (maj_[i] == 0.0 && min_[i] == 0.0) continue;

            /* Evaluate shape of ellipse on the l,m plane. */
            ellipse_a = maj_[i]/2.0;
            ellipse_b = min_[i]/2.0;
            cos_pa = cos(pa_[i]);
            sin_pa = sin(pa_[i]);
            for (j = 0; j < ELLIPSE_PTS; ++j)
            {
                t = j * 60.0 * M_PI / 180.0;
                l[j] = ellipse_a*cos(t)*sin_pa + ellipse_b*sin(t)*cos_pa;
                m[j] = ellipse_a*cos(t)*cos_pa - ellipse_b*sin(t)*sin_pa;
            }
            oskar_convert_relative_directions_to_lon_lat_2d_d(ELLIPSE_PTS,
                    l, m, 0.0, 0.0, lon, lat);

            /* Rotate on the sphere. */
            oskar_convert_lon_lat_to_xyz_d(ELLIPSE_PTS, lon, lat, x, y, z);
            oskar_rotate_sph_d(ELLIPSE_PTS, x, y, z, ra_[i], dec_[i]);
            oskar_convert_xyz_to_lon_lat_d(ELLIPSE_PTS, x, y, z, lon, lat);

            oskar_convert_lon_lat_to_relative_directions_2d_d(
                    ELLIPSE_PTS, lon, lat, ra0, dec0, l, m);

            /* Get new major and minor axes and position angle. */
            oskar_fit_ellipse_d(&maj, &min, &pa, ELLIPSE_PTS, l, m, work1,
                    work2, status);

            /* Check if fitting failed. */
            if (*status == OSKAR_ERR_ELLIPSE_FIT_FAILED)
            {
                if (zero_failed_sources)
                {
                    I_[i] = 0.0;
                    Q_[i] = 0.0;
                    U_[i] = 0.0;
                    V_[i] = 0.0;
                }
                ++(*num_failed);
                *status = 0;
                continue;
            }
            else if (*status) break;

            /* Evaluate ellipse parameters. */
            inv_std_maj_2 = 0.5 * (maj * maj) * M_PI_2_2_LN_2;
            inv_std_min_2 = 0.5 * (min * min) * M_PI_2_2_LN_2;
            cos_pa_2 = cos(pa) * cos(pa);
            sin_pa_2 = sin(pa) * sin(pa);
            sin_2pa  = sin(2.0 * pa);
            a_[i] = cos_pa_2*inv_std_min_2     + sin_pa_2*inv_std_maj_2;
            b_[i] = -sin_2pa*inv_std_min_2*0.5 + sin_2pa *inv_std_maj_2*0.5;
            c_[i] = sin_pa_2*inv_std_min_2     + cos_pa_2*inv_std_maj_2;
        }
    }
    else
    {
        /* Single precision. */
        const float *ra_, *dec_, *maj_, *min_, *pa_;
        float *I_, *Q_, *U_, *V_, *a_, *b_, *c_;
        float cos_pa_2, sin_pa_2, sin_2pa, inv_std_min_2, inv_std_maj_2;
        float ellipse_a, ellipse_b, maj, min, pa, cos_pa, sin_pa, t;
        float l[ELLIPSE_PTS], m[ELLIPSE_PTS];
        float work1[5 * ELLIPSE_PTS], work2[5 * ELLIPSE_PTS];
        float lon[ELLIPSE_PTS], lat[ELLIPSE_PTS];
        float x[ELLIPSE_PTS], y[ELLIPSE_PTS], z[ELLIPSE_PTS];
        ra_  = oskar_mem_float_const(oskar_sky_ra_rad_const(sky), status);
        dec_ = oskar_mem_float_const(oskar_sky_dec_rad_const(sky), status);
        maj_ = oskar_mem_float_const(oskar_sky_fwhm_major_rad_const(sky), status);
        min_ = oskar_mem_float_const(oskar_sky_fwhm_minor_rad_const(sky), status);
        pa_  = oskar_mem_float_const(oskar_sky_position_angle_rad_const(sky), status);
        I_   = oskar_mem_float(oskar_sky_I(sky), status);
        Q_   = oskar_mem_float(oskar_sky_Q(sky), status);
        U_   = oskar_mem_float(oskar_sky_U(sky), status);
        V_   = oskar_mem_float(oskar_sky_V(sky), status);
        a_   = oskar_mem_float(oskar_sky_gaussian_a(sky), status);
        b_   = oskar_mem_float(oskar_sky_gaussian_b(sky), status);
        c_   = oskar_mem_float(oskar_sky_gaussian_c(sky), status);

        for (i = 0; i < num_sources; ++i)
        {
            /* Note: could do something different from the projection below
             * in the case of a line (i.e. maj or min = 0), as in this case
             * there is no ellipse to project, only two points.
             * -- This continue could then be a if() .. else() instead.
             */
            if (maj_[i] == 0.0 && min_[i] == 0.0) continue;

            /* Evaluate shape of ellipse on the l,m plane. */
            ellipse_a = maj_[i]/2.0;
            ellipse_b = min_[i]/2.0;
            cos_pa = cos(pa_[i]);
            sin_pa = sin(pa_[i]);
            for (j = 0; j < ELLIPSE_PTS; ++j)
            {
                t = j * 60.0 * M_PI / 180.0;
                l[j] = ellipse_a*cos(t)*sin_pa + ellipse_b*sin(t)*cos_pa;
                m[j] = ellipse_a*cos(t)*cos_pa - ellipse_b*sin(t)*sin_pa;
            }
            oskar_convert_relative_directions_to_lon_lat_2d_f(ELLIPSE_PTS,
                    l, m, 0.0, 0.0, lon, lat);

            /* Rotate on the sphere. */
            oskar_convert_lon_lat_to_xyz_f(ELLIPSE_PTS, lon, lat, x, y, z);
            oskar_rotate_sph_f(ELLIPSE_PTS, x, y, z, ra_[i], dec_[i]);
            oskar_convert_xyz_to_lon_lat_f(ELLIPSE_PTS, x, y, z, lon, lat);

            oskar_convert_lon_lat_to_relative_directions_2d_f(
                    ELLIPSE_PTS, lon, lat, (float)ra0, (float)dec0, l, m);

            /* Get new major and minor axes and position angle. */
            oskar_fit_ellipse_f(&maj, &min, &pa, ELLIPSE_PTS, l, m, work1,
                    work2, status);

            /* Check if fitting failed. */
            if (*status == OSKAR_ERR_ELLIPSE_FIT_FAILED)
            {
                if (zero_failed_sources)
                {
                    I_[i] = 0.0;
                    Q_[i] = 0.0;
                    U_[i] = 0.0;
                    V_[i] = 0.0;
                }
                ++(*num_failed);
                *status = 0;
                continue;
            }
            else if (*status) break;

            /* Evaluate ellipse parameters. */
            inv_std_maj_2 = 0.5 * (maj * maj) * M_PI_2_2_LN_2;
            inv_std_min_2 = 0.5 * (min * min) * M_PI_2_2_LN_2;
            cos_pa_2 = cos(pa) * cos(pa);
            sin_pa_2 = sin(pa) * sin(pa);
            sin_2pa  = sin(2.0 * pa);
            a_[i] = cos_pa_2*inv_std_min_2     + sin_pa_2*inv_std_maj_2;
            b_[i] = -sin_2pa*inv_std_min_2*0.5 + sin_2pa *inv_std_maj_2*0.5;
            c_[i] = sin_pa_2*inv_std_min_2     + cos_pa_2*inv_std_maj_2;
        }
    }
}
Example #4
0
void oskar_evaluate_jones_Z(oskar_Jones* Z, const oskar_Sky* sky,
        const oskar_Telescope* telescope,
        const oskar_SettingsIonosphere* settings, double gast,
        double frequency_hz, oskar_WorkJonesZ* work, int* status)
{
    int i, num_sources, num_stations;
    /* Station position in ECEF frame */
    double station_x, station_y, station_z, wavelength;
    oskar_Mem *Z_station;
    int type;
    oskar_Sky* sky_cpu; /* Copy of the sky model on the CPU */

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

    /* Check data types. */
    type = oskar_sky_precision(sky);
    if (oskar_telescope_precision(telescope) != type ||
            oskar_jones_type(Z) != (type | OSKAR_COMPLEX) ||
            oskar_work_jones_z_type(work) != type)
    {
        *status = OSKAR_ERR_BAD_DATA_TYPE;
        return;
    }

    /* For now, this function requires data is on the CPU .. check this. */

    /* Resize the work array (if needed) */
    num_stations = oskar_telescope_num_stations(telescope);
    num_sources = oskar_sky_num_sources(sky);
    oskar_work_jones_z_resize(work, num_sources, status);

    /* Copy the sky model to the CPU. */
    sky_cpu = oskar_sky_create_copy(sky, OSKAR_CPU, status);

    Z_station = oskar_mem_create_alias(0, 0, 0, status);
    wavelength = 299792458.0 / frequency_hz;

    /* Evaluate the ionospheric phase screen for each station at each
     * source pierce point. */
    for (i = 0; i < num_stations; ++i)
    {
        double last, lon, lat;
        const oskar_Station* station;
        station = oskar_telescope_station_const(telescope, i);
        lon = oskar_station_lon_rad(station);
        lat = oskar_station_lat_rad(station);
        last = gast + lon;

        /* Evaluate horizontal x,y,z source positions (for which to evaluate
         * pierce points) */
        oskar_convert_relative_directions_to_enu_directions(
                work->hor_x, work->hor_y, work->hor_z, num_sources,
                oskar_sky_l_const(sky_cpu), oskar_sky_m_const(sky_cpu),
                oskar_sky_n_const(sky_cpu), last - oskar_sky_reference_ra_rad(sky_cpu),
                oskar_sky_reference_dec_rad(sky_cpu), lat, status);

        /* Obtain station coordinates in the ECEF frame. */
        evaluate_station_ECEF_coords(&station_x, &station_y, &station_z, i,
                telescope);

        /* Obtain the pierce points. */
        /* FIXME(BM) this is current hard-coded to TID height screen 0
         * this fix is only needed to support multiple screen heights. */
        oskar_evaluate_pierce_points(work->pp_lon, work->pp_lat,
                work->pp_rel_path, station_x, station_y,
                station_z, settings->TID[0].height_km * 1000., num_sources,
                work->hor_x, work->hor_y, work->hor_z, status);

        /* Evaluate TEC values for the pierce points */
        oskar_evaluate_TEC(work, num_sources, settings, gast, status);

        /* Get a pointer to the Jones matrices for the station */
        oskar_jones_get_station_pointer(Z_station, Z, i, status);

        /* Populate the Jones matrix with ionospheric phase */
        evaluate_jones_Z_station(Z_station, wavelength,
                work->total_TEC, work->hor_z, settings->min_elevation,
                num_sources, status);
    }

    oskar_sky_free(sky_cpu, status);
    oskar_mem_free(Z_station, status);
}
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_);
            }
        }
    }
}
Example #6
0
static PyObject* append_sources(PyObject* self, PyObject* args)
{
    oskar_Sky *h = 0;
    PyObject *obj[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    oskar_Mem *ra_c, *dec_c, *I_c, *Q_c, *U_c, *V_c;
    oskar_Mem *ref_c, *spix_c, *rm_c, *maj_c, *min_c, *pa_c;
    PyArrayObject *ra = 0, *dec = 0, *I = 0, *Q = 0, *U = 0, *V = 0;
    PyArrayObject *ref = 0, *spix = 0, *rm = 0, *maj = 0, *min = 0, *pa = 0;
    int status = 0, npy_type, type, flags, num_sources, old_num;

    /* Parse inputs: RA, Dec, I, Q, U, V, ref, spix, rm, maj, min, pa. */
    if (!PyArg_ParseTuple(args, "OOOOOOOOOOOOO", &obj[0],
            &obj[1], &obj[2], &obj[3], &obj[4], &obj[5], &obj[6],
            &obj[7], &obj[8], &obj[9], &obj[10], &obj[11], &obj[12]))
        return 0;
    if (!(h = get_handle(obj[0]))) return 0;

    /* Make sure input objects are arrays. Convert if required. */
    flags = NPY_ARRAY_FORCECAST | NPY_ARRAY_IN_ARRAY;
    type = oskar_sky_precision(h);
    npy_type = numpy_type_from_oskar(type);
    ra   = (PyArrayObject*) PyArray_FROM_OTF(obj[1], npy_type, flags);
    dec  = (PyArrayObject*) PyArray_FROM_OTF(obj[2], npy_type, flags);
    I    = (PyArrayObject*) PyArray_FROM_OTF(obj[3], npy_type, flags);
    Q    = (PyArrayObject*) PyArray_FROM_OTF(obj[4], npy_type, flags);
    U    = (PyArrayObject*) PyArray_FROM_OTF(obj[5], npy_type, flags);
    V    = (PyArrayObject*) PyArray_FROM_OTF(obj[6], npy_type, flags);
    ref  = (PyArrayObject*) PyArray_FROM_OTF(obj[7], npy_type, flags);
    spix = (PyArrayObject*) PyArray_FROM_OTF(obj[8], npy_type, flags);
    rm   = (PyArrayObject*) PyArray_FROM_OTF(obj[9], npy_type, flags);
    maj  = (PyArrayObject*) PyArray_FROM_OTF(obj[10], npy_type, flags);
    min  = (PyArrayObject*) PyArray_FROM_OTF(obj[11], npy_type, flags);
    pa   = (PyArrayObject*) PyArray_FROM_OTF(obj[12], npy_type, flags);
    if (!ra || !dec || !I || !Q || !U || !V ||
            !ref || !spix || !rm || !maj || !min || !pa)
        goto fail;

    /* Check size of input arrays. */
    num_sources = (int) PyArray_SIZE(I);
    if (num_sources != (int) PyArray_SIZE(ra) ||
            num_sources != (int) PyArray_SIZE(dec) ||
            num_sources != (int) PyArray_SIZE(Q) ||
            num_sources != (int) PyArray_SIZE(U) ||
            num_sources != (int) PyArray_SIZE(V) ||
            num_sources != (int) PyArray_SIZE(ref) ||
            num_sources != (int) PyArray_SIZE(spix) ||
            num_sources != (int) PyArray_SIZE(rm) ||
            num_sources != (int) PyArray_SIZE(maj) ||
            num_sources != (int) PyArray_SIZE(min) ||
            num_sources != (int) PyArray_SIZE(pa))
    {
        PyErr_SetString(PyExc_RuntimeError, "Input data dimension mismatch.");
        goto fail;
    }

    /* Pointers to input arrays. */
    ra_c = oskar_mem_create_alias_from_raw(PyArray_DATA(ra),
            type, OSKAR_CPU, num_sources, &status);
    dec_c = oskar_mem_create_alias_from_raw(PyArray_DATA(dec),
            type, OSKAR_CPU, num_sources, &status);
    I_c = oskar_mem_create_alias_from_raw(PyArray_DATA(I),
            type, OSKAR_CPU, num_sources, &status);
    Q_c = oskar_mem_create_alias_from_raw(PyArray_DATA(Q),
            type, OSKAR_CPU, num_sources, &status);
    U_c = oskar_mem_create_alias_from_raw(PyArray_DATA(U),
            type, OSKAR_CPU, num_sources, &status);
    V_c = oskar_mem_create_alias_from_raw(PyArray_DATA(V),
            type, OSKAR_CPU, num_sources, &status);
    ref_c = oskar_mem_create_alias_from_raw(PyArray_DATA(ref),
            type, OSKAR_CPU, num_sources, &status);
    spix_c = oskar_mem_create_alias_from_raw(PyArray_DATA(spix),
            type, OSKAR_CPU, num_sources, &status);
    rm_c = oskar_mem_create_alias_from_raw(PyArray_DATA(rm),
            type, OSKAR_CPU, num_sources, &status);
    maj_c = oskar_mem_create_alias_from_raw(PyArray_DATA(maj),
            type, OSKAR_CPU, num_sources, &status);
    min_c = oskar_mem_create_alias_from_raw(PyArray_DATA(min),
            type, OSKAR_CPU, num_sources, &status);
    pa_c = oskar_mem_create_alias_from_raw(PyArray_DATA(pa),
            type, OSKAR_CPU, num_sources, &status);

    /* Copy source data into the sky model. */
    old_num = oskar_sky_num_sources(h);
    oskar_sky_resize(h, old_num + num_sources, &status);
    oskar_mem_copy_contents(oskar_sky_ra_rad(h), ra_c,
            old_num, 0, num_sources, &status);
    oskar_mem_copy_contents(oskar_sky_dec_rad(h), dec_c,
            old_num, 0, num_sources, &status);
    oskar_mem_copy_contents(oskar_sky_I(h), I_c,
            old_num, 0, num_sources, &status);
    oskar_mem_copy_contents(oskar_sky_Q(h), Q_c,
            old_num, 0, num_sources, &status);
    oskar_mem_copy_contents(oskar_sky_U(h), U_c,
            old_num, 0, num_sources, &status);
    oskar_mem_copy_contents(oskar_sky_V(h), V_c,
            old_num, 0, num_sources, &status);
    oskar_mem_copy_contents(oskar_sky_reference_freq_hz(h), ref_c,
            old_num, 0, num_sources, &status);
    oskar_mem_copy_contents(oskar_sky_spectral_index(h), spix_c,
            old_num, 0, num_sources, &status);
    oskar_mem_copy_contents(oskar_sky_rotation_measure_rad(h), rm_c,
            old_num, 0, num_sources, &status);
    oskar_mem_copy_contents(oskar_sky_fwhm_major_rad(h), maj_c,
            old_num, 0, num_sources, &status);
    oskar_mem_copy_contents(oskar_sky_fwhm_minor_rad(h), min_c,
            old_num, 0, num_sources, &status);
    oskar_mem_copy_contents(oskar_sky_position_angle_rad(h), pa_c,
            old_num, 0, num_sources, &status);

    /* Free memory. */
    oskar_mem_free(ra_c, &status);
    oskar_mem_free(dec_c, &status);
    oskar_mem_free(I_c, &status);
    oskar_mem_free(Q_c, &status);
    oskar_mem_free(U_c, &status);
    oskar_mem_free(V_c, &status);
    oskar_mem_free(ref_c, &status);
    oskar_mem_free(spix_c, &status);
    oskar_mem_free(rm_c, &status);
    oskar_mem_free(maj_c, &status);
    oskar_mem_free(min_c, &status);
    oskar_mem_free(pa_c, &status);

    /* Check for errors. */
    if (status)
    {
        PyErr_Format(PyExc_RuntimeError,
                "Sky model append_sources() failed with code %d (%s).",
                status, oskar_get_error_string(status));
        goto fail;
    }

    Py_XDECREF(ra);
    Py_XDECREF(dec);
    Py_XDECREF(I);
    Py_XDECREF(Q);
    Py_XDECREF(U);
    Py_XDECREF(V);
    Py_XDECREF(ref);
    Py_XDECREF(spix);
    Py_XDECREF(rm);
    Py_XDECREF(maj);
    Py_XDECREF(min);
    Py_XDECREF(pa);
    return Py_BuildValue("");

fail:
    Py_XDECREF(ra);
    Py_XDECREF(dec);
    Py_XDECREF(I);
    Py_XDECREF(Q);
    Py_XDECREF(U);
    Py_XDECREF(V);
    Py_XDECREF(ref);
    Py_XDECREF(spix);
    Py_XDECREF(rm);
    Py_XDECREF(maj);
    Py_XDECREF(min);
    Py_XDECREF(pa);
    return 0;
}
/* Wrapper. */
void oskar_sky_scale_flux_with_frequency(oskar_Sky* sky, double frequency,
        int* status)
{
    int type, location, num_sources;

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

    /* Get the type, location and dimensions. */
    type = oskar_sky_precision(sky);
    location = oskar_sky_mem_location(sky);
    num_sources = oskar_sky_num_sources(sky);

    /* Scale the flux values. */
    if (location == OSKAR_CPU)
    {
        if (type == OSKAR_SINGLE)
            oskar_sky_scale_flux_with_frequency_f(num_sources, frequency,
                    oskar_mem_float(oskar_sky_I(sky), status),
                    oskar_mem_float(oskar_sky_Q(sky), status),
                    oskar_mem_float(oskar_sky_U(sky), status),
                    oskar_mem_float(oskar_sky_V(sky), status),
                    oskar_mem_float(oskar_sky_reference_freq_hz(sky), status),
                    oskar_mem_float_const(
                            oskar_sky_spectral_index_const(sky), status),
                    oskar_mem_float_const(
                            oskar_sky_rotation_measure_rad_const(sky), status));
        else if (type == OSKAR_DOUBLE)
            oskar_sky_scale_flux_with_frequency_d(num_sources, frequency,
                    oskar_mem_double(oskar_sky_I(sky), status),
                    oskar_mem_double(oskar_sky_Q(sky), status),
                    oskar_mem_double(oskar_sky_U(sky), status),
                    oskar_mem_double(oskar_sky_V(sky), status),
                    oskar_mem_double(oskar_sky_reference_freq_hz(sky), status),
                    oskar_mem_double_const(
                            oskar_sky_spectral_index_const(sky), status),
                    oskar_mem_double_const(
                            oskar_sky_rotation_measure_rad_const(sky), status));
        else
            *status = OSKAR_ERR_BAD_DATA_TYPE;
    }
    else if (location == OSKAR_GPU)
    {
#ifdef OSKAR_HAVE_CUDA
        if (type == OSKAR_SINGLE)
            oskar_sky_scale_flux_with_frequency_cuda_f(num_sources, frequency,
                    oskar_mem_float(oskar_sky_I(sky), status),
                    oskar_mem_float(oskar_sky_Q(sky), status),
                    oskar_mem_float(oskar_sky_U(sky), status),
                    oskar_mem_float(oskar_sky_V(sky), status),
                    oskar_mem_float(oskar_sky_reference_freq_hz(sky), status),
                    oskar_mem_float_const(
                            oskar_sky_spectral_index_const(sky), status),
                    oskar_mem_float_const(
                            oskar_sky_rotation_measure_rad_const(sky), status));
        else if (type == OSKAR_DOUBLE)
            oskar_sky_scale_flux_with_frequency_cuda_d(num_sources, frequency,
                    oskar_mem_double(oskar_sky_I(sky), status),
                    oskar_mem_double(oskar_sky_Q(sky), status),
                    oskar_mem_double(oskar_sky_U(sky), status),
                    oskar_mem_double(oskar_sky_V(sky), status),
                    oskar_mem_double(oskar_sky_reference_freq_hz(sky), status),
                    oskar_mem_double_const(
                            oskar_sky_spectral_index_const(sky), status),
                    oskar_mem_double_const(
                            oskar_sky_rotation_measure_rad_const(sky), status));
        else
            *status = OSKAR_ERR_BAD_DATA_TYPE;
        oskar_device_check_error(status);
#else
        *status = OSKAR_ERR_CUDA_NOT_AVAILABLE;
#endif
    }
    else if (location & OSKAR_CL)
    {
#ifdef OSKAR_HAVE_OPENCL
        cl_event event;
        cl_kernel k = 0;
        cl_int error, num;
        cl_uint arg = 0;
        size_t global_size, local_size;
        if (type == OSKAR_DOUBLE)
            k = oskar_cl_kernel("scale_flux_with_frequency_double");
        else if (type == OSKAR_SINGLE)
            k = oskar_cl_kernel("scale_flux_with_frequency_float");
        else
        {
            *status = OSKAR_ERR_BAD_DATA_TYPE;
            return;
        }
        if (!k)
        {
            *status = OSKAR_ERR_FUNCTION_NOT_AVAILABLE;
            return;
        }

        /* Set kernel arguments. */
        num = (cl_int) num_sources;
        error = clSetKernelArg(k, arg++, sizeof(cl_int), &num);
        if (type == OSKAR_SINGLE)
        {
            const cl_float freq = (cl_float) frequency;
            error |= clSetKernelArg(k, arg++, sizeof(cl_float), &freq);
        }
        else if (type == OSKAR_DOUBLE)
        {
            const cl_double freq = (cl_double) frequency;
            error |= clSetKernelArg(k, arg++, sizeof(cl_double), &freq);
        }
        error |= clSetKernelArg(k, arg++, sizeof(cl_mem),
                oskar_mem_cl_buffer(oskar_sky_I(sky), status));
        error |= clSetKernelArg(k, arg++, sizeof(cl_mem),
                oskar_mem_cl_buffer(oskar_sky_Q(sky), status));
        error |= clSetKernelArg(k, arg++, sizeof(cl_mem),
                oskar_mem_cl_buffer(oskar_sky_U(sky), status));
        error |= clSetKernelArg(k, arg++, sizeof(cl_mem),
                oskar_mem_cl_buffer(oskar_sky_V(sky), status));
        error |= clSetKernelArg(k, arg++, sizeof(cl_mem),
                oskar_mem_cl_buffer(oskar_sky_reference_freq_hz(sky), status));
        error |= clSetKernelArg(k, arg++, sizeof(cl_mem),
                oskar_mem_cl_buffer_const(oskar_sky_spectral_index_const(sky), status));
        error |= clSetKernelArg(k, arg++, sizeof(cl_mem),
                oskar_mem_cl_buffer_const(oskar_sky_rotation_measure_rad_const(sky), status));
        if (error != CL_SUCCESS)
        {
            *status = OSKAR_ERR_INVALID_ARGUMENT;
            return;
        }

        /* Launch kernel on current command queue. */
        local_size = oskar_cl_is_gpu() ? 256 : 128;
        global_size = ((num + local_size - 1) / local_size) * local_size;
        error = clEnqueueNDRangeKernel(oskar_cl_command_queue(), k, 1, NULL,
                &global_size, &local_size, 0, NULL, &event);
        if (error != CL_SUCCESS)
            *status = OSKAR_ERR_KERNEL_LAUNCH_FAILURE;
#else
        *status = OSKAR_ERR_OPENCL_NOT_AVAILABLE;
#endif
    }
    else
        *status = OSKAR_ERR_BAD_LOCATION;
}
void oskar_sky_append_to_set(int* set_size, oskar_Sky*** set_ptr,
        int max_sources_per_model, const oskar_Sky* model, int* status)
{
    int free_space, space_required, num_extra_models, number_to_copy;
    int i, j, type, location, from_offset;
    oskar_Sky **set;
    size_t new_size;

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

    /* Get type and location. */
    type     = oskar_sky_precision(model);
    location = oskar_sky_mem_location(model);
    if (location != OSKAR_CPU)
    {
        *status = OSKAR_ERR_BAD_LOCATION;
        return;
    }

    /* Work out if the set needs to be resized, and if so by how much. */
    free_space = (*set_size == 0) ? 0 :
            max_sources_per_model - (*set_ptr)[*set_size - 1]->num_sources;
    space_required = model->num_sources - free_space;
    num_extra_models = (space_required + max_sources_per_model - 1)
            / max_sources_per_model;

    /* Sanity check. */
    if (num_extra_models < 0)
    {
        *status = OSKAR_ERR_INVALID_ARGUMENT;
        return;
    }

    /* Resize the array of sky model handles. */
    new_size = (*set_size + num_extra_models) * sizeof(oskar_Sky*);
    *set_ptr = realloc((*set_ptr), new_size);
    set = *set_ptr;
    for (i = *set_size; i < *set_size + num_extra_models; ++i)
    {
        set[i] = oskar_sky_create(type, location,
                max_sources_per_model, status);
        /* TODO Please clarify this statement and explain why it's needed. */
        /* Set the number sources to zero as this is the number currently
         * allocated in the model. */
        set[i]->num_sources = 0;
    }

    if (*status) return;

    /* Copy sources from the model into the set. */
    /* Loop over set entries with free space and copy sources into them. */
    number_to_copy = model->num_sources;
    from_offset = 0;
    for (i = (*set_size-1 > 0) ? *set_size-1 : 0;
            i < *set_size + num_extra_models; ++i)
    {
        int n_copy, offset_dst;
        offset_dst = oskar_sky_num_sources(set[i]);
        free_space = max_sources_per_model - offset_dst;
        n_copy = MIN(free_space, number_to_copy);
        oskar_sky_copy_contents(set[i], model, offset_dst, from_offset,
                n_copy, status);
        if (*status) break;
        set[i]->num_sources = n_copy + offset_dst;
        number_to_copy     -= n_copy;
        from_offset        += n_copy;
    }

    if (*status) return;

    /* Set the use extended flag if needed. */
    for (j = (*set_size-1 > 0) ? *set_size-1 : 0;
            j < *set_size + num_extra_models; ++j)
    {
        oskar_Sky* sky = set[j];
        const oskar_Mem *major, *minor;

        /* If any source in the model is extended, set the flag. */
        major = oskar_sky_fwhm_major_rad_const(sky);
        minor = oskar_sky_fwhm_minor_rad_const(sky);
        if (type == OSKAR_DOUBLE)
        {
            const double *maj_, *min_;
            maj_ = oskar_mem_double_const(major, status);
            min_ = oskar_mem_double_const(minor, status);
            for (i = 0; i < sky->num_sources; ++i)
            {
                if (maj_[i] > 0.0 || min_[i] > 0.0)
                {
                    sky->use_extended = OSKAR_TRUE;
                    break;
                }
            }
        }
        else
        {
            const float *maj_, *min_;
            maj_ = oskar_mem_float_const(major, status);
            min_ = oskar_mem_float_const(minor, status);
            for (i = 0; i < sky->num_sources; ++i)
            {
                if (maj_[i] > 0.0 || min_[i] > 0.0)
                {
                    sky->use_extended = OSKAR_TRUE;
                    break;
                }
            }
        }
    }

    /* Update the set size */
    *set_size += num_extra_models;
}