void oskar_evaluate_station_beam_gaussian(oskar_Mem* beam,
        int num_points, const oskar_Mem* l, const oskar_Mem* m,
        const oskar_Mem* horizon_mask, double fwhm_rad, int* status)
{
    double fwhm_lm, std;
    if (*status) return;

    /* Compute Gaussian standard deviation from FWHM. */
    if (fwhm_rad == 0.0)
    {
        *status = OSKAR_ERR_SETTINGS_TELESCOPE;
        return;
    }
    fwhm_lm = sin(fwhm_rad);
    std = fwhm_lm / (2.0 * sqrt(2.0 * log(2.0)));

    /* Evaluate Gaussian. */
    oskar_gaussian_circular(num_points, l, m, std, beam, status);

    /* Blank (zero) sources below the horizon. */
    oskar_blank_below_horizon(beam, horizon_mask, num_points, status);
}
Esempio n. 2
0
void oskar_evaluate_station_beam_gaussian(oskar_Mem* beam,
        int num_points, const oskar_Mem* l, const oskar_Mem* m,
        const oskar_Mem* horizon_mask, double fwhm_rad, int* status)
{
    int type, location;
    double fwhm_lm, std;

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

    /* Get type and check consistency. */
    type = oskar_mem_precision(beam);
    if (type != oskar_mem_type(l) || type != oskar_mem_type(m))
    {
        *status = OSKAR_ERR_TYPE_MISMATCH;
        return;
    }
    if (type != OSKAR_SINGLE && type != OSKAR_DOUBLE)
    {
        *status = OSKAR_ERR_BAD_DATA_TYPE;
        return;
    }
    if (!oskar_mem_is_complex(beam))
    {
        *status = OSKAR_ERR_BAD_DATA_TYPE;
        return;
    }

    if (fwhm_rad == 0.0)
    {
        *status = OSKAR_ERR_SETTINGS_TELESCOPE;
        return;
    }

    /* Get location and check consistency. */
    location = oskar_mem_location(beam);
    if (location != oskar_mem_location(l) ||
            location != oskar_mem_location(m))
    {
        *status = OSKAR_ERR_LOCATION_MISMATCH;
        return;
    }

    /* Check that length of input arrays are consistent. */
    if ((int)oskar_mem_length(l) < num_points ||
            (int)oskar_mem_length(m) < num_points)
    {
        *status = OSKAR_ERR_DIMENSION_MISMATCH;
        return;
    }

    /* Resize output array if needed. */
    if ((int)oskar_mem_length(beam) < num_points)
        oskar_mem_realloc(beam, num_points, status);

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

    /* Compute Gaussian standard deviation from FWHM. */
    fwhm_lm = sin(fwhm_rad);
    std = fwhm_lm / (2.0 * sqrt(2.0 * log(2.0)));

    if (type == OSKAR_DOUBLE)
    {
        const double *l_, *m_;
        l_ = oskar_mem_double_const(l, status);
        m_ = oskar_mem_double_const(m, status);

        if (location == OSKAR_CPU)
        {
            if (oskar_mem_is_scalar(beam))
            {
                oskar_gaussian_d(oskar_mem_double2(beam, status),
                        num_points, l_, m_, std);
            }
            else
            {
                oskar_gaussian_md(oskar_mem_double4c(beam, status),
                        num_points, l_, m_, std);
            }
        }
        else
        {
#ifdef OSKAR_HAVE_CUDA
            if (oskar_mem_is_scalar(beam))
            {
                oskar_gaussian_cuda_d(oskar_mem_double2(beam, status),
                        num_points, l_, m_, std);
            }
            else
            {
                oskar_gaussian_cuda_md(oskar_mem_double4c(beam, status),
                        num_points, l_, m_, std);
            }
            oskar_device_check_error(status);
#else
            *status = OSKAR_ERR_CUDA_NOT_AVAILABLE;
#endif
        }
    }
    else /* type == OSKAR_SINGLE */
    {
        const float *l_, *m_;
        l_ = oskar_mem_float_const(l, status);
        m_ = oskar_mem_float_const(m, status);

        if (location == OSKAR_CPU)
        {
            if (oskar_mem_is_scalar(beam))
            {
                oskar_gaussian_f(oskar_mem_float2(beam, status), num_points,
                        l_, m_, (float)std);
            }
            else
            {
                oskar_gaussian_mf(oskar_mem_float4c(beam, status), num_points,
                        l_, m_, (float)std);
            }
        }
        else
        {
#ifdef OSKAR_HAVE_CUDA
            if (oskar_mem_is_scalar(beam))
            {
                oskar_gaussian_cuda_f(oskar_mem_float2(beam, status),
                        num_points, l_, m_, (float)std);
            }
            else
            {
                oskar_gaussian_cuda_mf(oskar_mem_float4c(beam, status),
                        num_points, l_, m_, (float)std);
            }
            oskar_device_check_error(status);
#else
            *status = OSKAR_ERR_CUDA_NOT_AVAILABLE;
#endif
        }
    }

    /* Blank (zero) sources below the horizon. */
    oskar_blank_below_horizon(beam, horizon_mask, num_points, status);
}
static void oskar_evaluate_station_beam_aperture_array_private(oskar_Mem* beam,
        const oskar_Station* s, int num_points, const oskar_Mem* x,
        const oskar_Mem* y, const oskar_Mem* z, double gast,
        double frequency_hz, oskar_StationWork* work, int time_index,
        int depth, int* status)
{
    double beam_x, beam_y, beam_z, wavenumber;
    oskar_Mem *weights, *weights_error, *theta, *phi, *array;
    int num_elements, is_3d;

    num_elements  = oskar_station_num_elements(s);
    is_3d         = oskar_station_array_is_3d(s);
    weights       = work->weights;
    weights_error = work->weights_error;
    theta         = work->theta_modified;
    phi           = work->phi_modified;
    array         = work->array_pattern;
    wavenumber    = 2.0 * M_PI * frequency_hz / 299792458.0;

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

    /* Compute direction cosines for the beam for this station. */
    oskar_evaluate_beam_horizon_direction(&beam_x, &beam_y, &beam_z, s,
            gast, status);

    /* Evaluate beam if there are no child stations. */
    if (!oskar_station_has_child(s))
    {
        /* First optimisation: A single element model type, and either a common
         * orientation for all elements within the station, or isotropic
         * elements. */
        /* Array pattern and element pattern are separable. */
        if (oskar_station_num_element_types(s) == 1 &&
                (oskar_station_common_element_orientation(s) ||
                        oskar_element_type(oskar_station_element_const(s, 0))
                        == OSKAR_ELEMENT_TYPE_ISOTROPIC) )
        {
            /* (Always) evaluate element pattern into the output beam array. */
            oskar_element_evaluate(oskar_station_element_const(s, 0), beam,
                    oskar_station_element_x_alpha_rad(s, 0) + M_PI/2.0, /* FIXME Will change: This matches the old convention. */
                    oskar_station_element_y_alpha_rad(s, 0),
                    num_points, x, y, z, frequency_hz, theta, phi, status);

            /* Check if array pattern is enabled. */
            if (oskar_station_enable_array_pattern(s))
            {
                /* Generate beamforming weights and evaluate array pattern. */
                oskar_evaluate_element_weights(weights, weights_error,
                        wavenumber, s, beam_x, beam_y, beam_z,
                        time_index, status);
                oskar_dftw(num_elements, wavenumber,
                        oskar_station_element_true_x_enu_metres_const(s),
                        oskar_station_element_true_y_enu_metres_const(s),
                        oskar_station_element_true_z_enu_metres_const(s),
                        weights, num_points, x, y, (is_3d ? z : 0), 0, array,
                        status);

                /* Normalise array response if required. */
                if (oskar_station_normalise_array_pattern(s))
                    oskar_mem_scale_real(array, 1.0 / num_elements, status);

                /* Element-wise multiply to join array and element pattern. */
                oskar_mem_multiply(beam, beam, array, num_points, status);
            }
        }

#if 0
        /* Second optimisation: Common orientation for all elements within the
         * station, but more than one element type. */
        else if (oskar_station_common_element_orientation(s))
        {
            /* Must evaluate array pattern, so check that this is enabled. */
            if (!oskar_station_enable_array_pattern(s))
            {
                *status = OSKAR_ERR_SETTINGS_TELESCOPE;
                return;
            }

            /* Call a DFT using indexed input. */
            /* TODO Not yet implemented. */
            *status = OSKAR_ERR_FUNCTION_NOT_AVAILABLE;
        }
#endif

        /* No optimisation: No common element orientation. */
        /* Can't separate array and element evaluation. */
        else
        {
            int i, num_element_types;
            oskar_Mem *element_block = 0, *element = 0;
            const int* element_type_array = 0;

            /* Must evaluate array pattern, so check that this is enabled. */
            if (!oskar_station_enable_array_pattern(s))
            {
                *status = OSKAR_ERR_SETTINGS_TELESCOPE;
                return;
            }

            /* Get sized element pattern block (at depth 0). */
            element_block = oskar_station_work_beam(work, beam,
                    num_elements * num_points, 0, status);

            /* Create alias into element block. */
            element = oskar_mem_create_alias(element_block, 0, 0, status);

            /* Loop over elements and evaluate response for each. */
            element_type_array = oskar_station_element_types_cpu_const(s);
            num_element_types = oskar_station_num_element_types(s);
            for (i = 0; i < num_elements; ++i)
            {
                int element_type_idx;
                element_type_idx = element_type_array[i];
                if (element_type_idx >= num_element_types)
                {
                    *status = OSKAR_ERR_OUT_OF_RANGE;
                    break;
                }
                oskar_mem_set_alias(element, element_block, i * num_points,
                        num_points, status);
                oskar_element_evaluate(
                        oskar_station_element_const(s, element_type_idx),
                        element,
                        oskar_station_element_x_alpha_rad(s, i) + M_PI/2.0, /* FIXME Will change: This matches the old convention. */
                        oskar_station_element_y_alpha_rad(s, i),
                        num_points, x, y, z, frequency_hz, theta, phi, status);
            }

            /* Generate beamforming weights. */
            oskar_evaluate_element_weights(weights, weights_error,
                    wavenumber, s, beam_x, beam_y, beam_z,
                    time_index, status);

            /* Use DFT to evaluate array response. */
            oskar_dftw(num_elements, wavenumber,
                    oskar_station_element_true_x_enu_metres_const(s),
                    oskar_station_element_true_y_enu_metres_const(s),
                    oskar_station_element_true_z_enu_metres_const(s),
                    weights, num_points, x, y, (is_3d ? z : 0),
                    element_block, beam, status);

            /* Free element alias. */
            oskar_mem_free(element, status);

            /* Normalise array response if required. */
            if (oskar_station_normalise_array_pattern(s))
                oskar_mem_scale_real(beam, 1.0 / num_elements, status);
        }

        /* Blank (set to zero) points below the horizon. */
        oskar_blank_below_horizon(num_points, z, beam, status);
    }

    /* If there are child stations, must first evaluate the beam for each. */
    else
    {
        int i;
        oskar_Mem* signal;

        /* Must evaluate array pattern, so check that this is enabled. */
        if (!oskar_station_enable_array_pattern(s))
        {
            *status = OSKAR_ERR_SETTINGS_TELESCOPE;
            return;
        }

        /* Get sized work array for this depth, with the correct type. */
        signal = oskar_station_work_beam(work, beam, num_elements * num_points,
                depth, status);

        /* Check if child stations are identical. */
        if (oskar_station_identical_children(s))
        {
            /* Set up the output buffer for the first station. */
            oskar_Mem* output0;
            output0 = oskar_mem_create_alias(signal, 0, num_points, status);

            /* Recursive call. */
            oskar_evaluate_station_beam_aperture_array_private(output0,
                    oskar_station_child_const(s, 0), num_points,
                    x, y, z, gast, frequency_hz, work, time_index,
                    depth + 1, status);

            /* Copy beam for child station 0 into memory for other stations. */
            for (i = 1; i < num_elements; ++i)
            {
                oskar_mem_copy_contents(signal, output0, i * num_points, 0,
                        oskar_mem_length(output0), status);
            }
            oskar_mem_free(output0, status);
        }
        else
        {
            /* Loop over child stations. */
            for (i = 0; i < num_elements; ++i)
            {
                /* Set up the output buffer for this station. */
                oskar_Mem* output;
                output = oskar_mem_create_alias(signal, i * num_points,
                        num_points, status);

                /* Recursive call. */
                oskar_evaluate_station_beam_aperture_array_private(output,
                        oskar_station_child_const(s, i), num_points,
                        x, y, z, gast, frequency_hz, work, time_index,
                        depth + 1, status);
                oskar_mem_free(output, status);
            }
        }

        /* Generate beamforming weights and form beam from child stations. */
        oskar_evaluate_element_weights(weights, weights_error, wavenumber,
                s, beam_x, beam_y, beam_z, time_index, status);
        oskar_dftw(num_elements, wavenumber,
                oskar_station_element_true_x_enu_metres_const(s),
                oskar_station_element_true_y_enu_metres_const(s),
                oskar_station_element_true_z_enu_metres_const(s),
                weights, num_points, x, y, (is_3d ? z : 0), signal, beam,
                status);

        /* Normalise array response if required. */
        if (oskar_station_normalise_array_pattern(s))
            oskar_mem_scale_real(beam, 1.0 / num_elements, status);
    }
}