Пример #1
0
static void oskar_telescope_set_station_type_p(oskar_Station* station, int type)
{
    oskar_station_set_station_type(station, type);
    if (oskar_station_has_child(station))
    {
        int i, num_elements;
        num_elements = oskar_station_num_elements(station);
        for (i = 0; i < num_elements; ++i)
        {
            oskar_telescope_set_station_type_p(
                    oskar_station_child(station, i), type);
        }
    }
}
Пример #2
0
void oskar_evaluate_element_weights(oskar_Mem* weights,
        oskar_Mem* weights_error, double wavenumber,
        const oskar_Station* station, double x_beam, double y_beam,
        double z_beam, int time_index, int* status)
{
    int num_elements;

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

    /* Resize weights and weights error work arrays if required. */
    num_elements = oskar_station_num_elements(station);
    if ((int)oskar_mem_length(weights) < num_elements)
        oskar_mem_realloc(weights, num_elements, status);
    if ((int)oskar_mem_length(weights_error) < num_elements)
        oskar_mem_realloc(weights_error, num_elements, status);

    /* Generate DFT weights. */
    oskar_evaluate_element_weights_dft(weights, num_elements, wavenumber,
            oskar_station_element_measured_x_enu_metres_const(station),
            oskar_station_element_measured_y_enu_metres_const(station),
            oskar_station_element_measured_z_enu_metres_const(station),
            x_beam, y_beam, z_beam, status);

    /* Apply time-variable errors. */
    if (oskar_station_apply_element_errors(station))
    {
        /* Generate weights errors. */
        oskar_evaluate_element_weights_errors(num_elements,
                oskar_station_element_gain_const(station),
                oskar_station_element_gain_error_const(station),
                oskar_station_element_phase_offset_rad_const(station),
                oskar_station_element_phase_error_rad_const(station),
                oskar_station_seed_time_variable_errors(station), time_index,
                oskar_station_unique_id(station), weights_error, status);

        /* Modify the weights (complex multiply with error vector). */
        oskar_mem_element_multiply(0, weights, weights_error,
                num_elements, status);
    }

    /* Modify the weights using the provided apodisation values. */
    if (oskar_station_apply_element_weight(station))
    {
        oskar_mem_element_multiply(0, weights,
                oskar_station_element_weight_const(station), num_elements,
                status);
    }
}
Пример #3
0
static void oskar_telescope_set_gaussian_station_beam_p(oskar_Station* station,
        double fwhm_rad, double ref_freq_hz)
{
    oskar_station_set_gaussian_beam_values(station, fwhm_rad, ref_freq_hz);
    if (oskar_station_has_child(station))
    {
        int i, num_elements;
        num_elements = oskar_station_num_elements(station);
        for (i = 0; i < num_elements; ++i)
        {
            oskar_telescope_set_gaussian_station_beam_p(
                    oskar_station_child(station, i), fwhm_rad, ref_freq_hz);
        }
    }
}
Пример #4
0
static void max_station_size_and_depth(const oskar_Station* s,
        int* max_elements, int* max_depth, int depth)
{
    int i, num_elements;
    num_elements = oskar_station_num_elements(s);
    *max_elements = num_elements > *max_elements ? num_elements : *max_elements;
    *max_depth = depth > *max_depth ? depth : *max_depth;
    if (oskar_station_has_child(s))
    {
        for (i = 0; i < num_elements; ++i)
        {
            max_station_size_and_depth(oskar_station_child_const(s, i),
                    max_elements, max_depth, depth + 1);
        }
    }
}
Пример #5
0
static void oskar_telescope_set_station_phase_centre(oskar_Station* station,
        int coord_type, double ra_rad, double dec_rad)
{
    oskar_station_set_phase_centre(station, coord_type, ra_rad, dec_rad);
    if (oskar_station_has_child(station))
    {
        int i, num_elements;
        num_elements = oskar_station_num_elements(station);
        for (i = 0; i < num_elements; ++i)
        {
            oskar_telescope_set_station_phase_centre(
                    oskar_station_child(station, i),
                    coord_type, ra_rad, dec_rad);
        }
    }
}
Пример #6
0
static void set_child_station_locations(oskar_Station* s,
        const oskar_Station* parent)
{
    if (parent)
    {
        oskar_station_set_position(s,
                oskar_station_lon_rad(parent),
                oskar_station_lat_rad(parent),
                oskar_station_alt_metres(parent));
    }

    /* Recursively set data for child stations. */
    if (oskar_station_has_child(s))
    {
        int i, num_elements;
        num_elements = oskar_station_num_elements(s);
        for (i = 0; i < num_elements; ++i)
            set_child_station_locations(oskar_station_child(s, i), s);
    }
}
Пример #7
0
void oskar_station_load_layout(oskar_Station* station, const char* filename,
        int* status)
{
    /* Declare the line buffer and counter. */
    char* line = NULL;
    size_t bufsize = 0;
    int n = 0, type = 0, old_size = 0;
    FILE* file;

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

    /* Check type. */
    type = oskar_station_precision(station);
    if (type != OSKAR_SINGLE && type != OSKAR_DOUBLE)
    {
        *status = OSKAR_ERR_BAD_DATA_TYPE;
        return;
    }

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

    /* Get the size of the station before loading the data. */
    old_size = oskar_station_num_elements(station);

    /* Loop over each line in the file. */
    while (oskar_getline(&line, &bufsize, file) != OSKAR_ERR_EOF)
    {
        /* Declare parameter array. */
        /* x, y, z, delta x, delta y, delta z */
        double par[] = {0., 0., 0., 0., 0., 0.};
        size_t num_par = sizeof(par) / sizeof(double);

        /* Load element data. */
        if (oskar_string_to_array_d(line, num_par, par) < 2) continue;

        /* Ensure the station model is big enough. */
        if (oskar_station_num_elements(station) <= n)
        {
            oskar_station_resize(station, n + 100, status);
            if (*status) break;
        }

        /* Get "true" coordinates ([3, 4, 5]) from "measured" coordinates. */
        par[3] += par[0];
        par[4] += par[1];
        par[5] += par[2];

        /* Store the data. */
        oskar_station_set_element_coords(station, n, &par[0], &par[3], status);

        /* Increment element counter. */
        ++n;
    }

    /* Record number of elements loaded, if the station wasn't sized before. */
    if (old_size == 0)
    {
        oskar_station_resize(station, n, status);
    }
    else
    {
        /* Consistency check. */
        if (n != old_size)
            *status = OSKAR_ERR_DIMENSION_MISMATCH;
    }

    /* Free the line buffer and close the file. */
    if (line) free(line);
    fclose(file);
}
oskar_Station* oskar_station_create_copy(const oskar_Station* src,
        int location, int* status)
{
    int i = 0;
    oskar_Station* model = 0;

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

    /* Create the new model. */
    model = oskar_station_create(oskar_station_precision(src), location,
            oskar_station_num_elements(src), status);

    /* Set meta-data. */
    model->unique_id = src->unique_id;
    model->precision = src->precision;
    model->mem_location = location;

    /* Copy common station parameters. */
    model->station_type = src->station_type;
    model->normalise_final_beam = src->normalise_final_beam;
    model->lon_rad = src->lon_rad;
    model->lat_rad = src->lat_rad;
    model->alt_metres = src->alt_metres;
    model->pm_x_rad = src->pm_x_rad;
    model->pm_y_rad = src->pm_y_rad;
    model->beam_lon_rad = src->beam_lon_rad;
    model->beam_lat_rad = src->beam_lat_rad;
    model->beam_coord_type = src->beam_coord_type;
    oskar_mem_copy(model->noise_freq_hz, src->noise_freq_hz, status);
    oskar_mem_copy(model->noise_rms_jy, src->noise_rms_jy, status);

    /* Copy aperture array data, except num_element_types (done later). */
    model->identical_children = src->identical_children;
    model->num_elements = src->num_elements;
    model->normalise_array_pattern = src->normalise_array_pattern;
    model->enable_array_pattern = src->enable_array_pattern;
    model->common_element_orientation = src->common_element_orientation;
    model->array_is_3d = src->array_is_3d;
    model->apply_element_errors = src->apply_element_errors;
    model->apply_element_weight = src->apply_element_weight;
    model->seed_time_variable_errors = src->seed_time_variable_errors;
    model->num_permitted_beams = src->num_permitted_beams;

    /* Copy Gaussian station beam data. */
    model->gaussian_beam_fwhm_rad = src->gaussian_beam_fwhm_rad;
    model->gaussian_beam_reference_freq_hz = src->gaussian_beam_reference_freq_hz;

    /* Copy memory blocks. */
    oskar_mem_copy(model->element_true_x_enu_metres,
            src->element_true_x_enu_metres, status);
    oskar_mem_copy(model->element_true_y_enu_metres,
            src->element_true_y_enu_metres, status);
    oskar_mem_copy(model->element_true_z_enu_metres,
            src->element_true_z_enu_metres, status);
    oskar_mem_copy(model->element_measured_x_enu_metres,
            src->element_measured_x_enu_metres, status);
    oskar_mem_copy(model->element_measured_y_enu_metres,
            src->element_measured_y_enu_metres, status);
    oskar_mem_copy(model->element_measured_z_enu_metres,
            src->element_measured_z_enu_metres, status);
    oskar_mem_copy(model->element_weight, src->element_weight, status);
    oskar_mem_copy(model->element_gain, src->element_gain, status);
    oskar_mem_copy(model->element_gain_error, src->element_gain_error, status);
    oskar_mem_copy(model->element_phase_offset_rad,
            src->element_phase_offset_rad, status);
    oskar_mem_copy(model->element_phase_error_rad,
            src->element_phase_error_rad, status);
    oskar_mem_copy(model->element_x_alpha_cpu,
            src->element_x_alpha_cpu, status);
    oskar_mem_copy(model->element_x_beta_cpu,
            src->element_x_beta_cpu, status);
    oskar_mem_copy(model->element_x_gamma_cpu,
            src->element_x_gamma_cpu, status);
    oskar_mem_copy(model->element_y_alpha_cpu,
            src->element_y_alpha_cpu, status);
    oskar_mem_copy(model->element_y_beta_cpu,
            src->element_y_beta_cpu, status);
    oskar_mem_copy(model->element_y_gamma_cpu,
            src->element_y_gamma_cpu, status);
    oskar_mem_copy(model->element_types, src->element_types, status);
    oskar_mem_copy(model->element_types_cpu, src->element_types_cpu, status);
    oskar_mem_copy(model->element_mount_types_cpu, src->element_mount_types_cpu, status);
    oskar_mem_copy(model->permitted_beam_az_rad, src->permitted_beam_az_rad, status);
    oskar_mem_copy(model->permitted_beam_el_rad, src->permitted_beam_el_rad, status);

    /* Copy element models, if set. */
    if (oskar_station_has_element(src))
    {
        /* Ensure enough space for element model data. */
        oskar_station_resize_element_types(model, src->num_element_types,
                status);

        /* Copy the element model data. */
        for (i = 0; i < src->num_element_types; ++i)
        {
            oskar_element_copy(model->element[i], src->element[i], status);
        }
    }

    /* Recursively copy child stations. */
    if (oskar_station_has_child(src))
    {
        model->child = malloc(src->num_elements * sizeof(oskar_Station*));
        if (!model->child)
        {
            *status = OSKAR_ERR_MEMORY_ALLOC_FAILURE;
            return model;
        }

        for (i = 0; i < src->num_elements; ++i)
        {
            model->child[i] = oskar_station_create_copy(
                    oskar_station_child_const(src, i), location, status);
        }
    }

    return model;
}
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);
    }
}