void oskar_interferometer_set_sky_model(oskar_Interferometer* h, const oskar_Sky* sky, int* status) { int i; if (*status || !h || !sky) return; /* Clear the old chunk set. */ for (i = 0; i < h->num_sky_chunks; ++i) oskar_sky_free(h->sky_chunks[i], status); free(h->sky_chunks); h->sky_chunks = 0; h->num_sky_chunks = 0; /* Split up the sky model into chunks and store them. */ h->num_sources_total = oskar_sky_num_sources(sky); if (h->num_sources_total > 0) oskar_sky_append_to_set(&h->num_sky_chunks, &h->sky_chunks, h->max_sources_per_chunk, sky, status); h->init_sky = 0; /* Print summary data. */ if (h->log) { oskar_log_section(h->log, 'M', "Sky model summary"); oskar_log_value(h->log, 'M', 0, "Num. sources", "%d", h->num_sources_total); oskar_log_value(h->log, 'M', 0, "Num. chunks", "%d", h->num_sky_chunks); } }
static PyObject* num_sources(PyObject* self, PyObject* args) { oskar_Sky *h = 0; PyObject* capsule = 0; if (!PyArg_ParseTuple(args, "O", &capsule)) return 0; if (!(h = get_handle(capsule))) return 0; return Py_BuildValue("i", oskar_sky_num_sources(h)); }
int benchmark(int num_stations, int num_sources, int type, int jones_type, int loc, int use_extended, int use_time_ave, int niter, std::vector<double>& times) { int status = 0; oskar_Timer* timer; timer = oskar_timer_create(loc == OSKAR_GPU ? OSKAR_TIMER_CUDA : OSKAR_TIMER_OMP); // Set up a test sky model, telescope model and Jones matrices. oskar_Telescope* tel = oskar_telescope_create(type, loc, num_stations, &status); oskar_Sky* sky = oskar_sky_create(type, loc, num_sources, &status); oskar_Jones* J = oskar_jones_create(jones_type, loc, num_stations, num_sources, &status); oskar_telescope_set_channel_bandwidth(tel, 1e6); oskar_telescope_set_time_average(tel, (double) use_time_ave); oskar_sky_set_use_extended(sky, use_extended); // Memory for visibility coordinates and output visibility slice. oskar_Mem *vis, *u, *v, *w; vis = oskar_mem_create(jones_type, loc, oskar_telescope_num_baselines(tel), &status); u = oskar_mem_create(type, loc, num_stations, &status); v = oskar_mem_create(type, loc, num_stations, &status); w = oskar_mem_create(type, loc, num_stations, &status); // Run benchmark. times.resize(niter); for (int i = 0; i < niter; ++i) { oskar_timer_start(timer); oskar_cross_correlate(vis, oskar_sky_num_sources(sky), J, sky, tel, u, v, w, 0.0, 100e6, &status); times[i] = oskar_timer_elapsed(timer); } // Free memory. oskar_mem_free(u, &status); oskar_mem_free(v, &status); oskar_mem_free(w, &status); oskar_mem_free(vis, &status); oskar_jones_free(J, &status); oskar_telescope_free(tel, &status); oskar_sky_free(sky, &status); oskar_timer_free(timer); return status; }
static void set_pixel(oskar_Sky* sky, int i, int x, int y, double val, const double crval[2], const double crpix[2], const double cdelt[2], double image_freq_hz, double spectral_index, int* status) { double ra, dec, l, m; /* Convert pixel positions to RA and Dec values. */ l = cdelt[0] * (x + 1 - crpix[0]); m = cdelt[1] * (y + 1 - crpix[1]); oskar_convert_relative_directions_to_lon_lat_2d_d(1, &l, &m, crval[0], crval[1], &ra, &dec); /* Store pixel data in sky model. */ if (oskar_sky_num_sources(sky) <= i) oskar_sky_resize(sky, i + 1000, status); oskar_sky_set_source(sky, i, ra, dec, val, 0.0, 0.0, 0.0, image_freq_hz, spectral_index, 0.0, 0.0, 0.0, 0.0, status); }
void oskar_simulator_set_sky_model(oskar_Simulator* h, const oskar_Sky* sky, int max_sources_per_chunk, int* status) { int i; if (*status) return; /* Clear the old chunk set. */ for (i = 0; i < h->num_sky_chunks; ++i) oskar_sky_free(h->sky_chunks[i], status); free(h->sky_chunks); h->sky_chunks = 0; h->num_sky_chunks = 0; /* Split up the sky model into chunks and store them. */ h->max_sources_per_chunk = max_sources_per_chunk; if (oskar_sky_num_sources(sky) > 0) oskar_sky_append_to_set(&h->num_sky_chunks, &h->sky_chunks, max_sources_per_chunk, sky, status); h->init_sky = 0; }
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); }
void oskar_simulator_run(oskar_Simulator* h, int* status) { int i, num_threads = 1, num_vis_blocks; if (*status) return; /* Check the visibilities are going somewhere. */ if (!h->vis_name #ifndef OSKAR_NO_MS && !h->ms_name #endif ) { oskar_log_error(h->log, "No output file specified."); #ifdef OSKAR_NO_MS if (h->ms_name) oskar_log_error(h->log, "OSKAR was compiled without Measurement Set support."); #endif *status = OSKAR_ERR_FILE_IO; return; } /* Initialise if required. */ oskar_simulator_check_init(h, status); /* Get the number of visibility blocks to be processed. */ num_vis_blocks = oskar_simulator_num_vis_blocks(h); /* Record memory usage. */ if (h->log && !*status) { oskar_log_section(h->log, 'M', "Initial memory usage"); #ifdef OSKAR_HAVE_CUDA for (i = 0; i < h->num_gpus; ++i) oskar_cuda_mem_log(h->log, 0, h->gpu_ids[i]); #endif system_mem_log(h->log); oskar_log_section(h->log, 'M', "Starting simulation..."); } /* Start simulation timer. */ oskar_timer_start(h->tmr_sim); /*----------------------------------------------------------------------- *-- START OF MULTITHREADED SIMULATION CODE ----------------------------- *-----------------------------------------------------------------------*/ /* Loop over blocks of observation time, running simulation and file * writing one block at a time. Simulation and file output are overlapped * by using double buffering, and a dedicated thread is used for file * output. * * Thread 0 is used for file writes. * Threads 1 to n (mapped to compute devices) do the simulation. * * Note that no write is launched on the first loop counter (as no * data are ready yet) and no simulation is performed for the last loop * counter (which corresponds to the last block + 1) as this iteration * simply writes the last block. */ #ifdef _OPENMP num_threads = h->num_devices + 1; omp_set_num_threads(num_threads); omp_set_nested(0); #else oskar_log_warning(h->log, "OpenMP not found: Using one compute device."); #endif oskar_simulator_reset_work_unit_index(h); #pragma omp parallel { int b, thread_id = 0, device_id = 0; /* Get host thread ID and device ID. */ #ifdef _OPENMP thread_id = omp_get_thread_num(); device_id = thread_id - 1; #endif /* Loop over simulation time blocks (+1, for the last write). */ for (b = 0; b < num_vis_blocks + 1; ++b) { if ((thread_id > 0 || num_threads == 1) && b < num_vis_blocks) oskar_simulator_run_block(h, b, device_id, status); if (thread_id == 0 && b > 0) { oskar_VisBlock* block; block = oskar_simulator_finalise_block(h, b - 1, status); oskar_simulator_write_block(h, block, b - 1, status); } /* Barrier 1: Reset work unit index. */ #pragma omp barrier if (thread_id == 0) oskar_simulator_reset_work_unit_index(h); /* Barrier 2: Synchronise before moving to the next block. */ #pragma omp barrier if (thread_id == 0 && b < num_vis_blocks && h->log && !*status) oskar_log_message(h->log, 'S', 0, "Block %*i/%i (%3.0f%%) " "complete. Simulation time elapsed: %.3f s", disp_width(num_vis_blocks), b+1, num_vis_blocks, 100.0 * (b+1) / (double)num_vis_blocks, oskar_timer_elapsed(h->tmr_sim)); } } /*----------------------------------------------------------------------- *-- END OF MULTITHREADED SIMULATION CODE ------------------------------- *-----------------------------------------------------------------------*/ /* Record memory usage. */ if (h->log && !*status) { oskar_log_section(h->log, 'M', "Final memory usage"); #ifdef OSKAR_HAVE_CUDA for (i = 0; i < h->num_gpus; ++i) oskar_cuda_mem_log(h->log, 0, h->gpu_ids[i]); #endif system_mem_log(h->log); } /* If there are sources in the simulation and the station beam is not * normalised to 1.0 at the phase centre, the values of noise RMS * may give a very unexpected S/N ratio! * The alternative would be to scale the noise to match the station * beam gain but that would require knowledge of the station beam * amplitude at the phase centre for each time and channel. */ if (h->log && oskar_telescope_noise_enabled(h->tel) && !*status) { int have_sources, amp_calibrated; have_sources = (h->num_sky_chunks > 0 && oskar_sky_num_sources(h->sky_chunks[0]) > 0); amp_calibrated = oskar_station_normalise_final_beam( oskar_telescope_station_const(h->tel, 0)); if (have_sources && !amp_calibrated) { const char* a = "WARNING: System noise added to visibilities"; const char* b = "without station beam normalisation enabled."; const char* c = "This will give an invalid signal to noise ratio."; oskar_log_line(h->log, 'W', ' '); oskar_log_line(h->log, 'W', '*'); oskar_log_message(h->log, 'W', -1, a); oskar_log_message(h->log, 'W', -1, b); oskar_log_message(h->log, 'W', -1, c); oskar_log_line(h->log, 'W', '*'); oskar_log_line(h->log, 'W', ' '); } } /* Record times and summarise output files. */ if (h->log && !*status) { size_t log_size = 0; char* log_data; oskar_log_set_value_width(h->log, 25); record_timing(h); oskar_log_section(h->log, 'M', "Simulation complete"); oskar_log_message(h->log, 'M', 0, "Output(s):"); if (h->vis_name) oskar_log_value(h->log, 'M', 1, "OSKAR binary file", "%s", h->vis_name); if (h->ms_name) oskar_log_value(h->log, 'M', 1, "Measurement Set", "%s", h->ms_name); /* Write simulation log to the output files. */ log_data = oskar_log_file_data(h->log, &log_size); #ifndef OSKAR_NO_MS if (h->ms) oskar_ms_add_history(h->ms, "OSKAR_LOG", log_data, log_size); #endif if (h->vis) oskar_binary_write(h->vis, OSKAR_CHAR, OSKAR_TAG_GROUP_RUN, OSKAR_TAG_RUN_LOG, 0, log_size, log_data, status); free(log_data); } /* Finalise. */ oskar_simulator_finalise(h, status); }
void oskar_simulator_run_block(oskar_Simulator* h, int block_index, int device_id, int* status) { double obs_start_mjd, dt_dump_days; int i_active, time_index_start, time_index_end; int num_channels, num_times_block, total_chunks, total_times; DeviceData* d; if (*status) return; /* Check that initialisation has happened. We can't initialise here, * as we're already multi-threaded at this point. */ if (!h->header) { *status = OSKAR_ERR_MEMORY_NOT_ALLOCATED; oskar_log_error(h->log, "Simulator not initalised. " "Call oskar_simulator_check_init() first."); return; } #ifdef _OPENMP if (!h->coords_only) { /* Disable any nested parallelism. */ omp_set_num_threads(1); omp_set_nested(0); } #endif /* Set the GPU to use. (Supposed to be a very low-overhead call.) */ if (device_id >= 0 && device_id < h->num_gpus) oskar_device_set(h->gpu_ids[device_id], status); /* Clear the visibility block. */ i_active = block_index % 2; /* Index of the active buffer. */ d = &(h->d[device_id]); oskar_timer_resume(d->tmr_compute); oskar_vis_block_clear(d->vis_block, status); /* Set the visibility block meta-data. */ total_chunks = h->num_sky_chunks; num_channels = h->num_channels; total_times = h->num_time_steps; obs_start_mjd = h->time_start_mjd_utc; dt_dump_days = h->time_inc_sec / 86400.0; time_index_start = block_index * h->max_times_per_block; time_index_end = time_index_start + h->max_times_per_block - 1; if (time_index_end >= total_times) time_index_end = total_times - 1; num_times_block = 1 + time_index_end - time_index_start; /* Set the number of active times in the block. */ oskar_vis_block_set_num_times(d->vis_block, num_times_block, status); oskar_vis_block_set_start_time_index(d->vis_block, time_index_start); /* Go though all possible work units in the block. A work unit is defined * as the simulation for one time and one sky chunk. */ while (!h->coords_only) { oskar_Sky* sky; int i_work_unit, i_chunk, i_time, i_channel, sim_time_idx; oskar_mutex_lock(h->mutex); i_work_unit = (h->work_unit_index)++; oskar_mutex_unlock(h->mutex); if ((i_work_unit >= num_times_block * total_chunks) || *status) break; /* Convert slice index to chunk/time index. */ i_chunk = i_work_unit / num_times_block; i_time = i_work_unit - i_chunk * num_times_block; sim_time_idx = time_index_start + i_time; /* Copy sky chunk to device only if different from the previous one. */ if (i_chunk != d->previous_chunk_index) { oskar_timer_resume(d->tmr_copy); oskar_sky_copy(d->chunk, h->sky_chunks[i_chunk], status); oskar_timer_pause(d->tmr_copy); } sky = h->apply_horizon_clip ? d->chunk_clip : d->chunk; /* Apply horizon clip if required. */ if (h->apply_horizon_clip) { double gast, mjd; mjd = obs_start_mjd + dt_dump_days * (sim_time_idx + 0.5); gast = oskar_convert_mjd_to_gast_fast(mjd); oskar_timer_resume(d->tmr_clip); oskar_sky_horizon_clip(d->chunk_clip, d->chunk, d->tel, gast, d->station_work, status); oskar_timer_pause(d->tmr_clip); } /* Simulate all baselines for all channels for this time and chunk. */ for (i_channel = 0; i_channel < num_channels; ++i_channel) { if (*status) break; if (h->log) { oskar_mutex_lock(h->mutex); oskar_log_message(h->log, 'S', 1, "Time %*i/%i, " "Chunk %*i/%i, Channel %*i/%i [Device %i, %i sources]", disp_width(total_times), sim_time_idx + 1, total_times, disp_width(total_chunks), i_chunk + 1, total_chunks, disp_width(num_channels), i_channel + 1, num_channels, device_id, oskar_sky_num_sources(sky)); oskar_mutex_unlock(h->mutex); } sim_baselines(h, d, sky, i_channel, i_time, sim_time_idx, status); } d->previous_chunk_index = i_chunk; } /* Copy the visibility block to host memory. */ oskar_timer_resume(d->tmr_copy); oskar_vis_block_copy(d->vis_block_cpu[i_active], d->vis_block, status); oskar_timer_pause(d->tmr_copy); oskar_timer_pause(d->tmr_compute); }
/* 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_interferometer_run(oskar_Interferometer* h, int* status) { int i, num_threads; oskar_Thread** threads = 0; ThreadArgs* args = 0; if (*status || !h) return; /* Check the visibilities are going somewhere. */ if (!h->vis_name #ifndef OSKAR_NO_MS && !h->ms_name #endif ) { oskar_log_error(h->log, "No output file specified."); #ifdef OSKAR_NO_MS if (h->ms_name) oskar_log_error(h->log, "OSKAR was compiled without Measurement Set support."); #endif *status = OSKAR_ERR_FILE_IO; return; } /* Initialise if required. */ oskar_interferometer_check_init(h, status); /* Set up worker threads. */ num_threads = h->num_devices + 1; oskar_barrier_set_num_threads(h->barrier, num_threads); threads = (oskar_Thread**) calloc(num_threads, sizeof(oskar_Thread*)); args = (ThreadArgs*) calloc(num_threads, sizeof(ThreadArgs)); for (i = 0; i < num_threads; ++i) { args[i].h = h; args[i].num_threads = num_threads; args[i].thread_id = i; } /* Record memory usage. */ if (h->log && !*status) { oskar_log_section(h->log, 'M', "Initial memory usage"); #ifdef OSKAR_HAVE_CUDA for (i = 0; i < h->num_gpus; ++i) oskar_cuda_mem_log(h->log, 0, h->gpu_ids[i]); #endif system_mem_log(h->log); oskar_log_section(h->log, 'M', "Starting simulation..."); } /* Start simulation timer. */ oskar_timer_start(h->tmr_sim); /* Set status code. */ h->status = *status; /* Start the worker threads. */ oskar_interferometer_reset_work_unit_index(h); for (i = 0; i < num_threads; ++i) threads[i] = oskar_thread_create(run_blocks, (void*)&args[i], 0); /* Wait for worker threads to finish. */ for (i = 0; i < num_threads; ++i) { oskar_thread_join(threads[i]); oskar_thread_free(threads[i]); } free(threads); free(args); /* Get status code. */ *status = h->status; /* Record memory usage. */ if (h->log && !*status) { oskar_log_section(h->log, 'M', "Final memory usage"); #ifdef OSKAR_HAVE_CUDA for (i = 0; i < h->num_gpus; ++i) oskar_cuda_mem_log(h->log, 0, h->gpu_ids[i]); #endif system_mem_log(h->log); } /* If there are sources in the simulation and the station beam is not * normalised to 1.0 at the phase centre, the values of noise RMS * may give a very unexpected S/N ratio! * The alternative would be to scale the noise to match the station * beam gain but that would require knowledge of the station beam * amplitude at the phase centre for each time and channel. */ if (h->log && oskar_telescope_noise_enabled(h->tel) && !*status) { int have_sources, amp_calibrated; have_sources = (h->num_sky_chunks > 0 && oskar_sky_num_sources(h->sky_chunks[0]) > 0); amp_calibrated = oskar_station_normalise_final_beam( oskar_telescope_station_const(h->tel, 0)); if (have_sources && !amp_calibrated) { const char* a = "WARNING: System noise added to visibilities"; const char* b = "without station beam normalisation enabled."; const char* c = "This will give an invalid signal to noise ratio."; oskar_log_line(h->log, 'W', ' '); oskar_log_line(h->log, 'W', '*'); oskar_log_message(h->log, 'W', -1, a); oskar_log_message(h->log, 'W', -1, b); oskar_log_message(h->log, 'W', -1, c); oskar_log_line(h->log, 'W', '*'); oskar_log_line(h->log, 'W', ' '); } } /* Record times and summarise output files. */ if (h->log && !*status) { size_t log_size = 0; char* log_data; oskar_log_set_value_width(h->log, 25); record_timing(h); oskar_log_section(h->log, 'M', "Simulation complete"); oskar_log_message(h->log, 'M', 0, "Output(s):"); if (h->vis_name) oskar_log_value(h->log, 'M', 1, "OSKAR binary file", "%s", h->vis_name); if (h->ms_name) oskar_log_value(h->log, 'M', 1, "Measurement Set", "%s", h->ms_name); /* Write simulation log to the output files. */ log_data = oskar_log_file_data(h->log, &log_size); #ifndef OSKAR_NO_MS if (h->ms) oskar_ms_add_history(h->ms, "OSKAR_LOG", log_data, log_size); #endif if (h->vis) oskar_binary_write(h->vis, OSKAR_CHAR, OSKAR_TAG_GROUP_RUN, OSKAR_TAG_RUN_LOG, 0, log_size, log_data, status); free(log_data); } /* Finalise. */ oskar_interferometer_finalise(h, status); }
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 runTest(int prec1, int prec2, int loc1, int loc2, int matrix, int extended, double time_average) { int num_baselines, status = 0, type; oskar_Mem *vis1, *vis2; oskar_Timer *timer1, *timer2; double time1, time2, frequency = 100e6; // Create the timers. timer1 = oskar_timer_create(loc1 == OSKAR_GPU ? OSKAR_TIMER_CUDA : OSKAR_TIMER_NATIVE); timer2 = oskar_timer_create(loc2 == OSKAR_GPU ? OSKAR_TIMER_CUDA : OSKAR_TIMER_NATIVE); // Run first part. createTestData(prec1, loc1, matrix); num_baselines = oskar_telescope_num_baselines(tel); type = prec1 | OSKAR_COMPLEX; if (matrix) type |= OSKAR_MATRIX; vis1 = oskar_mem_create(type, loc1, num_baselines, &status); oskar_mem_clear_contents(vis1, &status); ASSERT_EQ(0, status) << oskar_get_error_string(status); oskar_sky_set_use_extended(sky, extended); oskar_telescope_set_channel_bandwidth(tel, bandwidth); oskar_telescope_set_time_average(tel, time_average); oskar_timer_start(timer1); oskar_cross_correlate(vis1, oskar_sky_num_sources(sky), jones, sky, tel, u_, v_, w_, 1.0, frequency, &status); time1 = oskar_timer_elapsed(timer1); destroyTestData(); ASSERT_EQ(0, status) << oskar_get_error_string(status); // Run second part. createTestData(prec2, loc2, matrix); num_baselines = oskar_telescope_num_baselines(tel); type = prec2 | OSKAR_COMPLEX; if (matrix) type |= OSKAR_MATRIX; vis2 = oskar_mem_create(type, loc2, num_baselines, &status); oskar_mem_clear_contents(vis2, &status); ASSERT_EQ(0, status) << oskar_get_error_string(status); oskar_sky_set_use_extended(sky, extended); oskar_telescope_set_channel_bandwidth(tel, bandwidth); oskar_telescope_set_time_average(tel, time_average); oskar_timer_start(timer2); oskar_cross_correlate(vis2, oskar_sky_num_sources(sky), jones, sky, tel, u_, v_, w_, 1.0, frequency, &status); time2 = oskar_timer_elapsed(timer2); destroyTestData(); ASSERT_EQ(0, status) << oskar_get_error_string(status); // Destroy the timers. oskar_timer_free(timer1); oskar_timer_free(timer2); // Compare results. check_values(vis1, vis2); // Free memory. oskar_mem_free(vis1, &status); oskar_mem_free(vis2, &status); ASSERT_EQ(0, status) << oskar_get_error_string(status); // Record properties for test. RecordProperty("SourceType", extended ? "Gaussian" : "Point"); RecordProperty("JonesType", matrix ? "Matrix" : "Scalar"); RecordProperty("TimeSmearing", time_average == 0.0 ? "off" : "on"); RecordProperty("Prec1", prec1 == OSKAR_SINGLE ? "Single" : "Double"); RecordProperty("Loc1", loc1 == OSKAR_CPU ? "CPU" : "GPU"); RecordProperty("Time1_ms", int(time1 * 1000)); RecordProperty("Prec2", prec2 == OSKAR_SINGLE ? "Single" : "Double"); RecordProperty("Loc2", loc2 == OSKAR_CPU ? "CPU" : "GPU"); RecordProperty("Time2_ms", int(time2 * 1000)); #ifdef ALLOW_PRINTING // Print times. printf(" > %s. %s sources. Time smearing %s.\n", matrix ? "Matrix" : "Scalar", extended ? "Gaussian" : "Point", time_average == 0.0 ? "off" : "on"); printf(" %s precision %s: %.2f ms, %s precision %s: %.2f ms\n", prec1 == OSKAR_SINGLE ? "Single" : "Double", loc1 == OSKAR_CPU ? "CPU" : "GPU", time1 * 1000.0, prec2 == OSKAR_SINGLE ? "Single" : "Double", loc2 == OSKAR_CPU ? "CPU" : "GPU", time2 * 1000.0); #endif }
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; }
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; }
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; } } }
oskar_Sky* oskar_sky_load(const char* filename, int type, int* status) { int n = 0; FILE* file; char* line = 0; size_t bufsize = 0; oskar_Sky* sky; /* Check if safe to proceed. */ if (*status) return 0; /* Get the data type. */ if (type != OSKAR_SINGLE && type != OSKAR_DOUBLE) { *status = OSKAR_ERR_BAD_DATA_TYPE; return 0; } /* Open the file. */ file = fopen(filename, "r"); if (!file) { *status = OSKAR_ERR_FILE_IO; return 0; } /* Initialise the sky model. */ sky = oskar_sky_create(type, OSKAR_CPU, 0, status); /* Loop over lines in file. */ while (oskar_getline(&line, &bufsize, file) != OSKAR_ERR_EOF) { /* Set defaults. */ /* RA, Dec, I, Q, U, V, freq0, spix, RM, FWHM maj, FWHM min, PA */ double par[] = {0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.}; size_t num_param = sizeof(par) / sizeof(double); size_t num_required = 3, num_read = 0; /* Load source parameters (require at least RA, Dec, Stokes I). */ num_read = oskar_string_to_array_d(line, num_param, par); if (num_read < num_required) continue; /* Ensure enough space in arrays. */ if (oskar_sky_num_sources(sky) <= n) { oskar_sky_resize(sky, n + 100, status); if (*status) break; } if (num_read <= 9) { /* RA, Dec, I, Q, U, V, freq0, spix, RM */ oskar_sky_set_source(sky, n, par[0] * deg2rad, par[1] * deg2rad, par[2], par[3], par[4], par[5], par[6], par[7], par[8], 0.0, 0.0, 0.0, status); } else if (num_read == 11) { /* Old format, with no rotation measure. */ /* RA, Dec, I, Q, U, V, freq0, spix, FWHM maj, FWHM min, PA */ oskar_sky_set_source(sky, n, par[0] * deg2rad, par[1] * deg2rad, par[2], par[3], par[4], par[5], par[6], par[7], 0.0, par[8] * arcsec2rad, par[9] * arcsec2rad, par[10] * deg2rad, status); } else if (num_read == 12) { /* New format. */ /* RA, Dec, I, Q, U, V, freq0, spix, RM, FWHM maj, FWHM min, PA */ oskar_sky_set_source(sky, n, par[0] * deg2rad, par[1] * deg2rad, par[2], par[3], par[4], par[5], par[6], par[7], par[8], par[9] * arcsec2rad, par[10] * arcsec2rad, par[11] * deg2rad, status); } else { /* Error. */ *status = OSKAR_ERR_BAD_SKY_FILE; break; } ++n; } /* Set the size to be the actual number of elements loaded. */ oskar_sky_resize(sky, n, status); /* Free the line buffer and close the file. */ if (line) free(line); fclose(file); /* Check if an error occurred. */ if (*status) { oskar_sky_free(sky, status); sky = 0; } /* Return a handle to the sky model. */ return sky; }
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; }