Example #1
0
static void evaluate_station_beam_enu_directions(oskar_Mem* beam_pattern,
        int np, const oskar_Mem* x, const oskar_Mem* y, const oskar_Mem* z,
        const oskar_Station* station, oskar_StationWork* work,
        int time_index, double frequency_hz, double GAST, int* status)
{
    if (*status) return;

    switch (oskar_station_type(station))
    {
        case OSKAR_STATION_TYPE_AA:
        {
            oskar_evaluate_station_beam_aperture_array(beam_pattern, station,
                    np, x, y, z, GAST, frequency_hz, work, time_index, status);
            break;
        }
        case OSKAR_STATION_TYPE_ISOTROPIC:
        {
            oskar_mem_set_value_real(beam_pattern, 1.0, 0, np, status);
            break;
        }
        case OSKAR_STATION_TYPE_GAUSSIAN_BEAM:
        {
            oskar_Mem *l, *m, *n; /* Relative direction cosines */
            double fwhm, f0;
            l = oskar_station_work_enu_direction_x(work);
            m = oskar_station_work_enu_direction_y(work);
            n = oskar_station_work_enu_direction_z(work);
            compute_relative_directions(l, m, n, np, x, y, z, station, GAST,
                    status);
            fwhm = oskar_station_gaussian_beam_fwhm_rad(station);
            f0 =oskar_station_gaussian_beam_reference_freq_hz(station);
            fwhm *= f0 / frequency_hz;
            oskar_evaluate_station_beam_gaussian(beam_pattern, np, l, m, z,
                    fwhm, status);
            break;
        }
        case OSKAR_STATION_TYPE_VLA_PBCOR:
        {
            oskar_Mem *l, *m, *n; /* Relative direction cosines */
            l = oskar_station_work_enu_direction_x(work);
            m = oskar_station_work_enu_direction_y(work);
            n = oskar_station_work_enu_direction_z(work);
            compute_relative_directions(l, m, n, np, x, y, z, station, GAST,
                    status);
            oskar_evaluate_vla_beam_pbcor(beam_pattern, np, l, m, frequency_hz,
                    status);
            break;
        }
        default:
        {
            *status = OSKAR_ERR_SETTINGS_TELESCOPE;
            break;
        }
    };
}
Example #2
0
void oskar_evaluate_station_beam(oskar_Mem* beam_pattern, int num_points,
        int coord_type, oskar_Mem* x, oskar_Mem* y, oskar_Mem* z,
        double norm_ra_rad, double norm_dec_rad, const oskar_Station* station,
        oskar_StationWork* work, int time_index, double frequency_hz,
        double GAST, int* status)
{
    int normalise_final_beam;
    oskar_Mem* out;

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

    /* Set default output beam array. */
    out = beam_pattern;

    /* Check that the arrays have enough space to add an extra source at the
     * end (for normalisation). We don't want to reallocate here, since that
     * will be slow to do each time: must simply ensure that we pass input
     * arrays that are large enough.
     * The normalisation doesn't need to happen if the station has an
     * isotropic beam. */
    normalise_final_beam = oskar_station_normalise_final_beam(station) &&
            (oskar_station_type(station) != OSKAR_STATION_TYPE_ISOTROPIC);
    if (normalise_final_beam)
    {
        double c_x = 0.0, c_y = 0.0, c_z = 1.0;

        /* Increment number of points. */
        num_points++;

        /* Check the input arrays are big enough to hold the new source. */
        if ((int)oskar_mem_length(x) < num_points ||
                (int)oskar_mem_length(y) < num_points ||
                (int)oskar_mem_length(z) < num_points)
        {
            *status = OSKAR_ERR_DIMENSION_MISMATCH;
            return;
        }

        /* Set output beam array to work buffer. */
        out = oskar_station_work_normalised_beam(work, beam_pattern, status);

        /* Get the beam direction in the appropriate coordinate system. */
        /* (Direction cosines are already set to the interferometer phase
         * centre for relative directions.) */
        if (coord_type == OSKAR_ENU_DIRECTIONS)
        {
            double t_x, t_y, t_z, ha0;
            ha0 = (GAST + oskar_station_lon_rad(station)) - norm_ra_rad;
            oskar_convert_relative_directions_to_enu_directions_d(
                    &t_x, &t_y, &t_z, 1, &c_x, &c_y, &c_z, ha0, norm_dec_rad,
                    oskar_station_lat_rad(station));
            c_x = t_x;
            c_y = t_y;
            c_z = t_z;
        }

        /* Add the extra normalisation source to the end of the arrays. */
        oskar_mem_set_element_real(x, num_points-1, c_x, status);
        oskar_mem_set_element_real(y, num_points-1, c_y, status);
        oskar_mem_set_element_real(z, num_points-1, c_z, status);
    }

    /* Evaluate the station beam for the given directions. */
    if (coord_type == OSKAR_ENU_DIRECTIONS)
    {
        evaluate_station_beam_enu_directions(out, num_points, x, y, z,
                station, work, time_index, frequency_hz, GAST, status);
    }
    else if (coord_type == OSKAR_RELATIVE_DIRECTIONS)
    {
        evaluate_station_beam_relative_directions(out, num_points, x, y, z,
                station, work, time_index, frequency_hz, GAST, status);
    }
    else
    {
        *status = OSKAR_ERR_INVALID_ARGUMENT;
    }

    /* Scale beam pattern by value of the last source if required. */
    if (normalise_final_beam)
    {
        double amp = 0.0;

        /* Get the last element of the vector and convert to amplitude. */
        if (oskar_mem_is_matrix(out))
        {
            double4c val;
            val = oskar_mem_get_element_matrix(out, num_points-1, status);

            /*
             * Scale by square root of "Stokes I" autocorrelation:
             * sqrt(0.5 * [sum of resultant diagonal]).
             *
             * We have
             * [ Xa  Xb ] [ Xa*  Xc* ] = [ Xa Xa* + Xb Xb*    (don't care)   ]
             * [ Xc  Xd ] [ Xb*  Xd* ]   [  (don't care)     Xc Xc* + Xd Xd* ]
             *
             * Stokes I is completely real, so need only evaluate the real
             * part of all the multiplies. Because of the conjugate terms,
             * these become re*re + im*im.
             *
             * Need the square root because we only want the normalised value
             * for the beam itself (in isolation), not its actual
             * autocorrelation!
             */
            amp = val.a.x * val.a.x + val.a.y * val.a.y +
                    val.b.x * val.b.x + val.b.y * val.b.y +
                    val.c.x * val.c.x + val.c.y * val.c.y +
                    val.d.x * val.d.x + val.d.y * val.d.y;
            amp = sqrt(0.5 * amp);
        }
        else
        {
            double2 val;
            val = oskar_mem_get_element_complex(out, num_points-1, status);

            /* Scale by voltage. */
            amp = sqrt(val.x * val.x + val.y * val.y);
        }

        /* Scale beam array by normalisation value. */
        oskar_mem_scale_real(out, 1.0/amp, status);

        /* Copy output beam data. */
        oskar_mem_copy_contents(beam_pattern, out, 0, 0, num_points-1, status);
    }
}
void oskar_evaluate_station_beam(int num_points,
        int coord_type, oskar_Mem* x, oskar_Mem* y, oskar_Mem* z,
        double norm_ra_rad, double norm_dec_rad, const oskar_Station* station,
        oskar_StationWork* work, int time_index, double frequency_hz,
        double GAST, int offset_out, oskar_Mem* beam, int* status)
{
    oskar_Mem* out;
    const size_t num_points_orig = (size_t)num_points;
    if (*status) return;

    /* Set output beam array to work buffer. */
    out = oskar_station_work_beam_out(work, beam, num_points_orig, status);

    /* Check that the arrays have enough space to add an extra source at the
     * end (for normalisation). We don't want to reallocate here, since that
     * will be slow to do each time: must simply ensure that we pass input
     * arrays that are large enough.
     * The normalisation doesn't need to happen if the station has an
     * isotropic beam. */
    const int normalise = oskar_station_normalise_final_beam(station) &&
            (oskar_station_type(station) != OSKAR_STATION_TYPE_ISOTROPIC);
    if (normalise)
    {
        /* Increment number of points. */
        num_points++;

        /* Check the input arrays are big enough to hold the new source. */
        if ((int)oskar_mem_length(x) < num_points ||
                (int)oskar_mem_length(y) < num_points ||
                (int)oskar_mem_length(z) < num_points)
        {
            *status = OSKAR_ERR_DIMENSION_MISMATCH;
            return;
        }

        /* Get the beam direction in the appropriate coordinate system. */
        const int bypass = (coord_type != OSKAR_ENU_DIRECTIONS);
        const double ha0 = GAST + oskar_station_lon_rad(station) - norm_ra_rad;
        const double lat = oskar_station_lat_rad(station);
        oskar_convert_relative_directions_to_enu_directions(1, bypass, 0,
                1, 0, 0, 0, ha0, norm_dec_rad, lat, num_points - 1, x, y, z,
                status);
    }

    /* Evaluate the station beam for the given directions. */
    if (coord_type == OSKAR_ENU_DIRECTIONS)
        evaluate_station_beam_enu_directions(out, num_points, x, y, z,
                station, work, time_index, frequency_hz, GAST, status);
    else if (coord_type == OSKAR_RELATIVE_DIRECTIONS)
        evaluate_station_beam_relative_directions(out, num_points, x, y, z,
                station, work, time_index, frequency_hz, GAST, status);
    else
        *status = OSKAR_ERR_INVALID_ARGUMENT;

    /* Scale beam pattern by amplitude at the last source if required. */
    if (normalise)
        oskar_mem_normalise(out, 0, oskar_mem_length(out),
                num_points - 1, status);

    /* Copy output beam data. */
    oskar_mem_copy_contents(beam, out, offset_out, 0, num_points_orig, status);
}