void oskar_evaluate_station_beam_aperture_array(oskar_Mem* beam, const oskar_Station* station, 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* status) { int start; /* Check if safe to proceed. */ if (*status) return; /* Evaluate beam immediately, without chunking, if there are no * child stations. */ if (!oskar_station_has_child(station)) { oskar_evaluate_station_beam_aperture_array_private(beam, station, num_points, x, y, z, gast, frequency_hz, work, time_index, 0, status); } else { oskar_Mem *c_beam, *c_x, *c_y, *c_z; c_beam = oskar_mem_create_alias(0, 0, 0, status); c_x = oskar_mem_create_alias(0, 0, 0, status); c_y = oskar_mem_create_alias(0, 0, 0, status); c_z = oskar_mem_create_alias(0, 0, 0, status); /* Split up list of input points into manageable chunks. */ for (start = 0; start < num_points; start += MAX_CHUNK_SIZE) { int chunk_size; /* Get size of current chunk. */ chunk_size = num_points - start; if (chunk_size > MAX_CHUNK_SIZE) chunk_size = MAX_CHUNK_SIZE; /* Get pointers to start of chunk input data. */ oskar_mem_set_alias(c_beam, beam, start, chunk_size, status); oskar_mem_set_alias(c_x, x, start, chunk_size, status); oskar_mem_set_alias(c_y, y, start, chunk_size, status); oskar_mem_set_alias(c_z, z, start, chunk_size, status); /* Start recursive call at depth 1 (depth 0 is element level). */ oskar_evaluate_station_beam_aperture_array_private(c_beam, station, chunk_size, c_x, c_y, c_z, gast, frequency_hz, work, time_index, 1, status); } /* Release handles for chunk memory. */ oskar_mem_free(c_beam, status); oskar_mem_free(c_x, status); oskar_mem_free(c_y, status); oskar_mem_free(c_z, status); } }
static void sim_baselines(oskar_Simulator* h, DeviceData* d, oskar_Sky* sky, int channel_index_block, int time_index_block, int time_index_simulation, int* status) { int num_baselines, num_stations, num_src, num_times_block, num_channels; double dt_dump_days, t_start, t_dump, gast, frequency, ra0, dec0; const oskar_Mem *x, *y, *z; oskar_Mem* alias = 0; /* Get dimensions. */ num_baselines = oskar_telescope_num_baselines(d->tel); num_stations = oskar_telescope_num_stations(d->tel); num_src = oskar_sky_num_sources(sky); num_times_block = oskar_vis_block_num_times(d->vis_block); num_channels = oskar_vis_block_num_channels(d->vis_block); /* Return if there are no sources in the chunk, * or if block time index requested is outside the valid range. */ if (num_src == 0 || time_index_block >= num_times_block) return; /* Get the time and frequency of the visibility slice being simulated. */ dt_dump_days = h->time_inc_sec / 86400.0; t_start = h->time_start_mjd_utc; t_dump = t_start + dt_dump_days * (time_index_simulation + 0.5); gast = oskar_convert_mjd_to_gast_fast(t_dump); frequency = h->freq_start_hz + channel_index_block * h->freq_inc_hz; /* Scale source fluxes with spectral index and rotation measure. */ oskar_sky_scale_flux_with_frequency(sky, frequency, status); /* Evaluate station u,v,w coordinates. */ ra0 = oskar_telescope_phase_centre_ra_rad(d->tel); dec0 = oskar_telescope_phase_centre_dec_rad(d->tel); x = oskar_telescope_station_true_x_offset_ecef_metres_const(d->tel); y = oskar_telescope_station_true_y_offset_ecef_metres_const(d->tel); z = oskar_telescope_station_true_z_offset_ecef_metres_const(d->tel); oskar_convert_ecef_to_station_uvw(num_stations, x, y, z, ra0, dec0, gast, d->u, d->v, d->w, status); /* Set dimensions of Jones matrices. */ if (d->R) oskar_jones_set_size(d->R, num_stations, num_src, status); if (d->Z) oskar_jones_set_size(d->Z, num_stations, num_src, status); oskar_jones_set_size(d->J, num_stations, num_src, status); oskar_jones_set_size(d->E, num_stations, num_src, status); oskar_jones_set_size(d->K, num_stations, num_src, status); /* Evaluate station beam (Jones E: may be matrix). */ oskar_timer_resume(d->tmr_E); oskar_evaluate_jones_E(d->E, num_src, OSKAR_RELATIVE_DIRECTIONS, oskar_sky_l(sky), oskar_sky_m(sky), oskar_sky_n(sky), d->tel, gast, frequency, d->station_work, time_index_simulation, status); oskar_timer_pause(d->tmr_E); #if 0 /* Evaluate ionospheric phase (Jones Z: scalar) and join with Jones E. * NOTE this is currently only a CPU implementation. */ if (d->Z) { oskar_evaluate_jones_Z(d->Z, num_src, sky, d->tel, &settings->ionosphere, gast, frequency, &(d->workJonesZ), status); oskar_timer_resume(d->tmr_join); oskar_jones_join(d->E, d->Z, d->E, status); oskar_timer_pause(d->tmr_join); } #endif /* Evaluate parallactic angle (Jones R: matrix), and join with Jones Z*E. * TODO Move this into station beam evaluation instead. */ if (d->R) { oskar_timer_resume(d->tmr_E); oskar_evaluate_jones_R(d->R, num_src, oskar_sky_ra_rad_const(sky), oskar_sky_dec_rad_const(sky), d->tel, gast, status); oskar_timer_pause(d->tmr_E); oskar_timer_resume(d->tmr_join); oskar_jones_join(d->R, d->E, d->R, status); oskar_timer_pause(d->tmr_join); } /* Evaluate interferometer phase (Jones K: scalar). */ oskar_timer_resume(d->tmr_K); oskar_evaluate_jones_K(d->K, num_src, oskar_sky_l_const(sky), oskar_sky_m_const(sky), oskar_sky_n_const(sky), d->u, d->v, d->w, frequency, oskar_sky_I_const(sky), h->source_min_jy, h->source_max_jy, status); oskar_timer_pause(d->tmr_K); /* Join Jones K with Jones Z*E. */ oskar_timer_resume(d->tmr_join); oskar_jones_join(d->J, d->K, d->R ? d->R : d->E, status); oskar_timer_pause(d->tmr_join); /* Create alias for auto/cross-correlations. */ oskar_timer_resume(d->tmr_correlate); alias = oskar_mem_create_alias(0, 0, 0, status); /* Auto-correlate for this time and channel. */ if (oskar_vis_block_has_auto_correlations(d->vis_block)) { oskar_mem_set_alias(alias, oskar_vis_block_auto_correlations(d->vis_block), num_stations * (num_channels * time_index_block + channel_index_block), num_stations, status); oskar_auto_correlate(alias, num_src, d->J, sky, status); } /* Cross-correlate for this time and channel. */ if (oskar_vis_block_has_cross_correlations(d->vis_block)) { oskar_mem_set_alias(alias, oskar_vis_block_cross_correlations(d->vis_block), num_baselines * (num_channels * time_index_block + channel_index_block), num_baselines, status); oskar_cross_correlate(alias, num_src, d->J, sky, d->tel, d->u, d->v, d->w, gast, frequency, status); } /* Free alias for auto/cross-correlations. */ oskar_mem_free(alias, status); oskar_timer_pause(d->tmr_correlate); }
int main(int argc, char** argv) { int status = 0; oskar::OptionParser opt("oskar_evaulate_pierce_points", oskar_version_string()); opt.add_required("settings file"); if (!opt.check_options(argc, argv)) return EXIT_FAILURE; const char* settings_file = opt.get_arg(); // Create the log. oskar_Log* log = oskar_log_create(OSKAR_LOG_MESSAGE, OSKAR_LOG_STATUS); oskar_log_message(log, 'M', 0, "Running binary %s", argv[0]); // Enum values used in writing time-freq data binary files enum OSKAR_TIME_FREQ_TAGS { TIME_IDX = 0, FREQ_IDX = 1, TIME_MJD_UTC = 2, FREQ_HZ = 3, NUM_FIELDS = 4, NUM_FIELD_TAGS = 5, HEADER_OFFSET = 10, DATA = 0, DIMS = 1, LABEL = 2, UNITS = 3, GRP = OSKAR_TAG_GROUP_TIME_FREQ_DATA }; oskar_Settings_old settings; oskar_settings_old_load(&settings, log, settings_file, &status); oskar_log_set_keep_file(log, settings.sim.keep_log_file); if (status) return status; oskar_Telescope* tel = oskar_settings_to_telescope(&settings, log, &status); oskar_Sky* sky = oskar_settings_to_sky(&settings, log, &status); // FIXME remove this restriction ... (see evaluate Z) if (settings.ionosphere.num_TID_screens != 1) return OSKAR_ERR_SETUP_FAIL; int type = settings.sim.double_precision ? OSKAR_DOUBLE : OSKAR_SINGLE; int loc = OSKAR_CPU; int num_sources = oskar_sky_num_sources(sky); oskar_Mem *hor_x, *hor_y, *hor_z; hor_x = oskar_mem_create(type, loc, num_sources, &status); hor_y = oskar_mem_create(type, loc, num_sources, &status); hor_z = oskar_mem_create(type, loc, num_sources, &status); oskar_Mem *pp_lon, *pp_lat, *pp_rel_path; int num_stations = oskar_telescope_num_stations(tel); int num_pp = num_stations * num_sources; pp_lon = oskar_mem_create(type, loc, num_pp, &status); pp_lat = oskar_mem_create(type, loc, num_pp, &status); pp_rel_path = oskar_mem_create(type, loc, num_pp, &status); // Pierce points for one station (non-owned oskar_Mem pointers) oskar_Mem *pp_st_lon, *pp_st_lat, *pp_st_rel_path; pp_st_lon = oskar_mem_create_alias(0, 0, 0, &status); pp_st_lat = oskar_mem_create_alias(0, 0, 0, &status); pp_st_rel_path = oskar_mem_create_alias(0, 0, 0, &status); int num_times = settings.obs.num_time_steps; double obs_start_mjd_utc = settings.obs.start_mjd_utc; double dt_dump = settings.obs.dt_dump_days; // Binary file meta-data std::string label1 = "pp_lon"; std::string label2 = "pp_lat"; std::string label3 = "pp_path"; std::string units = "radians"; std::string units2 = ""; oskar_Mem *dims = oskar_mem_create(OSKAR_INT, loc, 2, &status); /* FIXME is this the correct dimension order ? * FIXME get the MATLAB reader to respect dimension ordering */ oskar_mem_int(dims, &status)[0] = num_sources; oskar_mem_int(dims, &status)[1] = num_stations; const char* filename = settings.ionosphere.pierce_points.filename; oskar_Binary* h = oskar_binary_create(filename, 'w', &status); double screen_height_m = settings.ionosphere.TID->height_km * 1000.0; // printf("Number of times = %i\n", num_times); // printf("Number of stations = %i\n", num_stations); void *x_, *y_, *z_; x_ = oskar_mem_void(oskar_telescope_station_true_x_offset_ecef_metres(tel)); y_ = oskar_mem_void(oskar_telescope_station_true_y_offset_ecef_metres(tel)); z_ = oskar_mem_void(oskar_telescope_station_true_z_offset_ecef_metres(tel)); for (int t = 0; t < num_times; ++t) { double t_dump = obs_start_mjd_utc + t * dt_dump; // MJD UTC double gast = oskar_convert_mjd_to_gast_fast(t_dump + dt_dump / 2.0); for (int i = 0; i < num_stations; ++i) { const oskar_Station* station = oskar_telescope_station_const(tel, i); double lon = oskar_station_lon_rad(station); double lat = oskar_station_lat_rad(station); double alt = oskar_station_alt_metres(station); double x_ecef, y_ecef, z_ecef, x_offset, y_offset, z_offset; if (type == OSKAR_DOUBLE) { x_offset = ((double*)x_)[i]; y_offset = ((double*)y_)[i]; z_offset = ((double*)z_)[i]; } else { x_offset = (double)((float*)x_)[i]; y_offset = (double)((float*)y_)[i]; z_offset = (double)((float*)z_)[i]; } oskar_convert_offset_ecef_to_ecef(1, &x_offset, &y_offset, &z_offset, lon, lat, alt, &x_ecef, &y_ecef, &z_ecef); double last = gast + lon; if (type == OSKAR_DOUBLE) { oskar_convert_apparent_ra_dec_to_enu_directions_d(num_sources, oskar_mem_double_const(oskar_sky_ra_rad_const(sky), &status), oskar_mem_double_const(oskar_sky_dec_rad_const(sky), &status), last, lat, oskar_mem_double(hor_x, &status), oskar_mem_double(hor_y, &status), oskar_mem_double(hor_z, &status)); } else { oskar_convert_apparent_ra_dec_to_enu_directions_f(num_sources, oskar_mem_float_const(oskar_sky_ra_rad_const(sky), &status), oskar_mem_float_const(oskar_sky_dec_rad_const(sky), &status), last, lat, oskar_mem_float(hor_x, &status), oskar_mem_float(hor_y, &status), oskar_mem_float(hor_z, &status)); } int offset = i * num_sources; oskar_mem_set_alias(pp_st_lon, pp_lon, offset, num_sources, &status); oskar_mem_set_alias(pp_st_lat, pp_lat, offset, num_sources, &status); oskar_mem_set_alias(pp_st_rel_path, pp_rel_path, offset, num_sources, &status); oskar_evaluate_pierce_points(pp_st_lon, pp_st_lat, pp_st_rel_path, x_ecef, y_ecef, z_ecef, screen_height_m, num_sources, hor_x, hor_y, hor_z, &status); } // Loop over stations. if (status != 0) continue; int index = t; // could be = (num_times * f) + t if we have frequency data int num_fields = 3; int num_field_tags = 4; double freq_hz = 0.0; int freq_idx = 0; // Write the header TAGS oskar_binary_write_int(h, GRP, TIME_IDX, index, t, &status); oskar_binary_write_double(h, GRP, FREQ_IDX, index, freq_idx, &status); oskar_binary_write_double(h, GRP, TIME_MJD_UTC, index, t_dump, &status); oskar_binary_write_double(h, GRP, FREQ_HZ, index, freq_hz, &status); oskar_binary_write_int(h, GRP, NUM_FIELDS, index, num_fields, &status); oskar_binary_write_int(h, GRP, NUM_FIELD_TAGS, index, num_field_tags, &status); // Write data TAGS (fields) int field, tagID; field = 0; tagID = HEADER_OFFSET + (num_field_tags * field); oskar_binary_write_mem(h, pp_lon, GRP, tagID + DATA, index, 0, &status); oskar_binary_write_mem(h, dims, GRP, tagID + DIMS, index, 0, &status); oskar_binary_write(h, OSKAR_CHAR, GRP, tagID + LABEL, index, label1.size()+1, label1.c_str(), &status); oskar_binary_write(h, OSKAR_CHAR, GRP, tagID + UNITS, index, units.size()+1, units.c_str(), &status); field = 1; tagID = HEADER_OFFSET + (num_field_tags * field); oskar_binary_write_mem(h, pp_lat, GRP, tagID + DATA, index, 0, &status); oskar_binary_write_mem(h, dims, GRP, tagID + DIMS, index, 0, &status); oskar_binary_write(h, OSKAR_CHAR, GRP, tagID + LABEL, index, label2.size()+1, label2.c_str(), &status); oskar_binary_write(h, OSKAR_CHAR, GRP, tagID + UNITS, index, units.size()+1, units.c_str(), &status); field = 2; tagID = HEADER_OFFSET + (num_field_tags * field); oskar_binary_write_mem(h, pp_rel_path, GRP, tagID + DATA, index, 0, &status); oskar_binary_write_mem(h, dims, GRP, tagID + DIMS, index, 0, &status); oskar_binary_write(h, OSKAR_CHAR, GRP, tagID + LABEL, index, label3.size()+1, label3.c_str(), &status); oskar_binary_write(h, OSKAR_CHAR, GRP, tagID + UNITS, index, units2.size()+1, units2.c_str(), &status); } // Loop over times // Close the OSKAR binary file. oskar_binary_free(h); // clean up memory oskar_mem_free(hor_x, &status); oskar_mem_free(hor_y, &status); oskar_mem_free(hor_z, &status); oskar_mem_free(pp_lon, &status); oskar_mem_free(pp_lat, &status); oskar_mem_free(pp_rel_path, &status); oskar_mem_free(pp_st_lon, &status); oskar_mem_free(pp_st_lat, &status); oskar_mem_free(pp_st_rel_path, &status); oskar_mem_free(dims, &status); oskar_telescope_free(tel, &status); oskar_sky_free(sky, &status); // Check for errors. if (status) oskar_log_error(log, "Run failed: %s.", oskar_get_error_string(status)); oskar_log_free(log); return status; }
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); }
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); } }