void oskar_beam_pattern_set_telescope_model(oskar_BeamPattern* h, const oskar_Telescope* model, int* status) { if (*status) return; /* Check the model is not empty. */ if (oskar_telescope_num_stations(model) == 0) { oskar_log_error(h->log, "Telescope model is empty."); *status = OSKAR_ERR_SETTINGS_TELESCOPE; return; } /* Remove any existing telescope model, and copy the new one. */ oskar_telescope_free(h->tel, status); h->tel = oskar_telescope_create_copy(model, OSKAR_CPU, status); h->pol_mode = oskar_telescope_pol_mode(h->tel); h->phase_centre_deg[0] = oskar_telescope_phase_centre_ra_rad(h->tel) * 180.0 / M_PI; h->phase_centre_deg[1] = oskar_telescope_phase_centre_dec_rad(h->tel) * 180.0 / M_PI; /* Analyse the telescope model. */ oskar_telescope_analyse(h->tel, status); if (h->log) oskar_telescope_log_summary(h->tel, h->log, status); }
void oskar_imager_set_num_planes(oskar_Imager* h, int* status) { int i; if (*status || h->num_planes > 0) return; if (h->num_sel_freqs == 0) { oskar_log_error(h->log, "Input visibility channel frequencies not set."); *status = OSKAR_ERR_OUT_OF_RANGE; return; } /* Set image meta-data. */ h->num_im_channels = h->chan_snaps ? h->num_sel_freqs : 1; h->im_freqs = (double*) realloc(h->im_freqs, h->num_im_channels * sizeof(double)); if (h->chan_snaps) { for (i = 0; i < h->num_sel_freqs; ++i) h->im_freqs[i] = h->sel_freqs[i]; } else { h->im_freqs[0] = 0.0; for (i = 0; i < h->num_sel_freqs; ++i) h->im_freqs[0] += h->sel_freqs[i]; h->im_freqs[0] /= h->num_sel_freqs; } h->num_planes = h->num_im_channels * h->num_im_pols; }
TEST(Log, special_methods) { /*oskar_log_create(OSKAR_LOG_NONE, OSKAR_LOG_DEBUG);*/ oskar_log_set_term_priority(OSKAR_LOG_DEBUG); oskar_log_warning("This is a warning"); oskar_log_error("This is an error"); oskar_log_section('M', "This is a section"); oskar_log_section('W', "This is a warning section"); oskar_log_section('D', "This is a debug section"); }
int main(int argc, char** argv) { int status = 0; oskar::OptionParser opt("oskar_convert_geodetic_to_ecef", oskar_version_string()); opt.set_description("Converts geodetic longitude/latitude/altitude to " "Cartesian ECEF coordinates. Assumes WGS84 ellipsoid."); opt.add_required("input file", "Path to file containing input coordinates. " "Angles must be in degrees."); if (!opt.check_options(argc, argv)) return OSKAR_FAIL; const char* filename = opt.get_arg(); // Load the input file. oskar_Mem *lon = oskar_mem_create(OSKAR_DOUBLE, OSKAR_CPU, 0, &status); oskar_Mem *lat = oskar_mem_create(OSKAR_DOUBLE, OSKAR_CPU, 0, &status); oskar_Mem *alt = oskar_mem_create(OSKAR_DOUBLE, OSKAR_CPU, 0, &status); size_t num_points = oskar_mem_load_ascii(filename, 3, &status, lon, "", lat, "", alt, "0.0"); oskar_mem_scale_real(lon, M_PI / 180.0, &status); oskar_mem_scale_real(lat, M_PI / 180.0, &status); // Convert coordinates. oskar_Mem *x = oskar_mem_create(OSKAR_DOUBLE, OSKAR_CPU, num_points, &status); oskar_Mem *y = oskar_mem_create(OSKAR_DOUBLE, OSKAR_CPU, num_points, &status); oskar_Mem *z = oskar_mem_create(OSKAR_DOUBLE, OSKAR_CPU, num_points, &status); oskar_convert_geodetic_spherical_to_ecef(num_points, oskar_mem_double_const(lon, &status), oskar_mem_double_const(lat, &status), oskar_mem_double_const(alt, &status), oskar_mem_double(x, &status), oskar_mem_double(y, &status), oskar_mem_double(z, &status)); // Print converted coordinates. oskar_mem_save_ascii(stdout, 3, num_points, &status, x, y, z); // Clean up. oskar_mem_free(lon, &status); oskar_mem_free(lat, &status); oskar_mem_free(alt, &status); oskar_mem_free(x, &status); oskar_mem_free(y, &status); oskar_mem_free(z, &status); if (status) { oskar_log_error(0, oskar_get_error_string(status)); return status; } return 0; }
TEST(Log, special_methods) { oskar_Log* log = 0; /*log = oskar_log_create(OSKAR_LOG_WARNING, OSKAR_LOG_DEBUG);*/ oskar_log_warning(log, "This is a warning"); oskar_log_error(log, "This is an error"); oskar_log_section(log, 'M', "This is a section!"); oskar_log_section(log, 'W', "This is a warning section!"); oskar_log_section(log, 'D', "This is a warning section!"); if (log) oskar_log_free(log); }
void oskar_simulator_check_init(oskar_Simulator* h, int* status) { if (*status) return; /* Check that the telescope model has been set. */ if (!h->tel) { oskar_log_error(h->log, "Telescope model not set."); *status = OSKAR_ERR_SETTINGS_TELESCOPE; return; } /* Create the visibility header if required. */ if (!h->header) set_up_vis_header(h, status); /* Calculate source parameters if required. */ if (!h->init_sky) { int i, num_failed = 0; double ra0, dec0; /* Compute source direction cosines relative to phase centre. */ ra0 = oskar_telescope_phase_centre_ra_rad(h->tel); dec0 = oskar_telescope_phase_centre_dec_rad(h->tel); for (i = 0; i < h->num_sky_chunks; ++i) { oskar_sky_evaluate_relative_directions(h->sky_chunks[i], ra0, dec0, status); /* Evaluate extended source parameters. */ oskar_sky_evaluate_gaussian_source_parameters(h->sky_chunks[i], h->zero_failed_gaussians, ra0, dec0, &num_failed, status); } if (num_failed > 0) { if (h->zero_failed_gaussians) oskar_log_warning(h->log, "Gaussian ellipse solution failed " "for %i sources. These will have their fluxes " "set to zero.", num_failed); else oskar_log_warning(h->log, "Gaussian ellipse solution failed " "for %i sources. These will be simulated " "as point sources.", num_failed); } h->init_sky = 1; } /* Check that each compute device has been set up. */ set_up_device_data(h, status); }
void oskar_beam_pattern_check_init(oskar_BeamPattern* h, int* status) { if (*status) return; /* Check that the telescope model has been set. */ if (!h->tel) { oskar_log_error(h->log, "Telescope model not set."); *status = OSKAR_ERR_SETTINGS_TELESCOPE; return; } /* Check that each compute device has been set up. */ set_up_host_data(h, status); set_up_device_data(h, status); }
int main(int argc, char** argv) { int error = 0; oskar::OptionParser opt("oskar_fits_image_to_sky_model", oskar_version_string()); opt.set_description("Converts a FITS image to an OSKAR sky model. A number " "of options are provided to control how much of the image is used " "to make the sky model."); opt.add_required("FITS file", "The input FITS image to convert."); opt.add_required("sky model file", "The output OSKAR sky model file name to save."); opt.add_flag("-s", "Spectral index. This is the spectral index that will " "be given to each pixel in the output sky model.", 1, "0.0"); opt.add_flag("-f", "Minimum allowed fraction of image peak. Pixel values " "below this fraction will be ignored.", 1, "0.0"); opt.add_flag("-n", "Noise floor in units of original image. " "Pixels below this value will be ignored.", 1, "0.0"); if (!opt.check_options(argc, argv)) return EXIT_FAILURE; // Parse command line. double spectral_index = 0.0; double min_peak_fraction = 0.0; double min_abs_val = 0.0; opt.get("-f")->getDouble(min_peak_fraction); opt.get("-n")->getDouble(min_abs_val); opt.get("-s")->getDouble(spectral_index); // Load the FITS image data. oskar_Sky* sky = oskar_sky_from_fits_file(OSKAR_DOUBLE, opt.get_arg(0), min_peak_fraction, min_abs_val, "Jy/beam", 0, 0.0, spectral_index, &error); // Write out the sky model. oskar_sky_save(opt.get_arg(1), sky, &error); if (error) { oskar_log_error(0, oskar_get_error_string(error)); return error; } oskar_sky_free(sky, &error); return 0; }
void oskar_simulator_set_gpus(oskar_Simulator* h, int num, int* ids, int* status) { int i, num_gpus_avail; if (*status) return; free_device_data(h, status); num_gpus_avail = oskar_device_count(status); if (*status) return; if (num < 0) { h->num_gpus = num_gpus_avail; h->gpu_ids = (int*) realloc(h->gpu_ids, h->num_gpus * sizeof(int)); for (i = 0; i < h->num_gpus; ++i) h->gpu_ids[i] = i; } else if (num > 0) { if (num > num_gpus_avail) { oskar_log_error(h->log, "More GPUs were requested than found."); *status = OSKAR_ERR_COMPUTE_DEVICES; return; } h->num_gpus = num; h->gpu_ids = (int*) realloc(h->gpu_ids, h->num_gpus * sizeof(int)); for (i = 0; i < h->num_gpus; ++i) h->gpu_ids[i] = ids[i]; } else /* num == 0 */ { free(h->gpu_ids); h->gpu_ids = 0; h->num_gpus = 0; } for (i = 0; i < h->num_gpus; ++i) { oskar_device_set(h->gpu_ids[i], status); if (*status) return; } }
int main(int argc, char** argv) { oskar::OptionParser opt("oskar_cuda_system_info", oskar_version_string()); opt.set_description("Display a summary of the available CUDA capability"); if (!opt.check_options(argc, argv)) return EXIT_FAILURE; // Create the CUDA info structure. int error = 0; oskar_CudaInfo* info = oskar_cuda_info_create(&error); if (error) { oskar_log_error(0, "Could not determine CUDA system information (%s)", oskar_get_error_string(error)); oskar_cuda_info_free(info); return error; } // Log the CUDA system info. oskar_cuda_info_log(NULL, info); oskar_cuda_info_free(info); return 0; }
void oskar_simulator_set_telescope_model(oskar_Simulator* h, const oskar_Telescope* model, int* status) { if (*status) return; /* Check the model is not empty. */ if (oskar_telescope_num_stations(model) == 0) { oskar_log_error(h->log, "Telescope model is empty."); *status = OSKAR_ERR_SETTINGS_TELESCOPE; return; } /* Remove any existing telescope model, and copy the new one. */ oskar_telescope_free(h->tel, status); h->tel = oskar_telescope_create_copy(model, OSKAR_CPU, status); /* Analyse the telescope model. */ oskar_telescope_analyse(h->tel, status); if (h->log) oskar_telescope_log_summary(h->tel, h->log, status); }
static void set_up_host_data(oskar_BeamPattern* h, int *status) { int i, k; size_t j; if (*status) return; /* Set up pixel positions. */ oskar_beam_pattern_generate_coordinates(h, OSKAR_SPHERICAL_TYPE_EQUATORIAL, status); /* Work out how many pixel chunks have to be processed. */ h->num_chunks = (h->num_pixels + h->max_chunk_size - 1) / h->max_chunk_size; /* Create scratch arrays for output pixel data. */ if (!h->pix) { h->pix = oskar_mem_create(h->prec, OSKAR_CPU, h->max_chunk_size, status); h->ctemp = oskar_mem_create(h->prec | OSKAR_COMPLEX, OSKAR_CPU, h->max_chunk_size, status); } /* Get the contents of the log at this point so we can write a * reasonable file header. Replace newlines with zeros. */ h->settings_log_length = 0; free(h->settings_log); h->settings_log = oskar_log_file_data(h->log, &h->settings_log_length); for (j = 0; j < h->settings_log_length; ++j) { if (h->settings_log[j] == '\n') h->settings_log[j] = 0; if (h->settings_log[j] == '\r') h->settings_log[j] = ' '; } /* Return if data products already exist. */ if (h->data_products) return; /* Create a file for each requested data product. */ /* Voltage amplitude and phase can only be generated if there is * no averaging. */ if (h->separate_time_and_channel) { /* Create station-level data products. */ for (i = 0; i < h->num_active_stations; ++i) { /* Text file. */ if (h->voltage_raw_txt) new_text_file(h, RAW_COMPLEX, -1, -1, i, 0, 0, status); if (h->voltage_amp_txt) { if (h->pol_mode == OSKAR_POL_MODE_SCALAR) new_text_file(h, AMP, -1, -1, i, 0, 0, status); else for (k = XX; k <= YY; ++k) new_text_file(h, AMP, -1, k, i, 0, 0, status); } if (h->voltage_phase_txt) { if (h->pol_mode == OSKAR_POL_MODE_SCALAR) new_text_file(h, PHASE, -1, -1, i, 0, 0, status); else for (k = XX; k <= YY; ++k) new_text_file(h, PHASE, -1, k, i, 0, 0, status); } if (h->ixr_txt && h->pol_mode == OSKAR_POL_MODE_FULL) new_text_file(h, IXR, -1, -1, i, 0, 0, status); /* Can only create images if coordinates are on a grid. */ if (h->coord_grid_type != 'B') continue; /* FITS file. */ if (h->voltage_amp_fits) { if (h->pol_mode == OSKAR_POL_MODE_SCALAR) new_fits_file(h, AMP, -1, -1, i, 0, 0, status); else for (k = XX; k <= YY; ++k) new_fits_file(h, AMP, -1, k, i, 0, 0, status); } if (h->voltage_phase_fits) { if (h->pol_mode == OSKAR_POL_MODE_SCALAR) new_fits_file(h, PHASE, -1, -1, i, 0, 0, status); else for (k = XX; k <= YY; ++k) new_fits_file(h, PHASE, -1, k, i, 0, 0, status); } if (h->ixr_fits && h->pol_mode == OSKAR_POL_MODE_FULL) new_fits_file(h, IXR, -1, -1, i, 0, 0, status); } } /* Create data products that can be averaged. */ if (h->separate_time_and_channel) create_averaged_products(h, 0, 0, status); if (h->average_time_and_channel) create_averaged_products(h, 1, 1, status); if (h->average_single_axis == 'C') create_averaged_products(h, 0, 1, status); else if (h->average_single_axis == 'T') create_averaged_products(h, 1, 0, status); /* Check that at least one output file will be generated. */ if (h->num_data_products == 0 && !*status) { *status = OSKAR_ERR_FILE_IO; oskar_log_error(h->log, "No output file(s) selected."); } }
static void set_up_device_data(oskar_BeamPattern* h, int* status) { int i, beam_type, max_src, max_size, auto_power, cross_power, raw_data; if (*status) return; /* Get local variables. */ max_src = h->max_chunk_size; max_size = h->num_active_stations * max_src; beam_type = h->prec | OSKAR_COMPLEX; if (h->pol_mode == OSKAR_POL_MODE_FULL) beam_type |= OSKAR_MATRIX; raw_data = h->ixr_txt || h->ixr_fits || h->voltage_raw_txt || h->voltage_amp_txt || h->voltage_phase_txt || h->voltage_amp_fits || h->voltage_phase_fits; auto_power = h->auto_power_fits || h->auto_power_txt; cross_power = h->cross_power_raw_txt || h->cross_power_amp_fits || h->cross_power_phase_fits || h->cross_power_amp_txt || h->cross_power_phase_txt; /* Expand the number of devices to the number of selected GPUs, * if required. */ if (h->num_devices < h->num_gpus) oskar_beam_pattern_set_num_devices(h, h->num_gpus); for (i = 0; i < h->num_devices; ++i) { int dev_loc, i_stokes; DeviceData* d = &h->d[i]; if (*status) break; /* Select the device. */ if (i < h->num_gpus) { oskar_device_set(h->gpu_ids[i], status); dev_loc = OSKAR_GPU; } else { dev_loc = OSKAR_CPU; } /* Device memory. */ d->previous_chunk_index = -1; if (!d->tel) { d->jones_data = oskar_mem_create(beam_type, dev_loc, max_size, status); d->x = oskar_mem_create(h->prec, dev_loc, 1 + max_src, status); d->y = oskar_mem_create(h->prec, dev_loc, 1 + max_src, status); d->z = oskar_mem_create(h->prec, dev_loc, 1 + max_src, status); d->tel = oskar_telescope_create_copy(h->tel, dev_loc, status); d->work = oskar_station_work_create(h->prec, dev_loc, status); } /* Host memory. */ if (!d->jones_data_cpu[0] && raw_data) { d->jones_data_cpu[0] = oskar_mem_create(beam_type, OSKAR_CPU, max_size, status); d->jones_data_cpu[1] = oskar_mem_create(beam_type, OSKAR_CPU, max_size, status); } /* Auto-correlation beam output arrays. */ for (i_stokes = 0; i_stokes < 4; ++i_stokes) { if (!h->stokes[i_stokes]) continue; if (!d->auto_power[i_stokes] && auto_power) { /* Device memory. */ d->auto_power[i_stokes] = oskar_mem_create(beam_type, dev_loc, max_size, status); /* Host memory. */ d->auto_power_cpu[i_stokes][0] = oskar_mem_create( beam_type, OSKAR_CPU, max_size, status); d->auto_power_cpu[i_stokes][1] = oskar_mem_create( beam_type, OSKAR_CPU, max_size, status); if (h->average_single_axis == 'T') d->auto_power_time_avg[i_stokes] = oskar_mem_create( beam_type, OSKAR_CPU, max_size, status); if (h->average_single_axis == 'C') d->auto_power_channel_avg[i_stokes] = oskar_mem_create( beam_type, OSKAR_CPU, max_size, status); if (h->average_time_and_channel) d->auto_power_channel_and_time_avg[i_stokes] = oskar_mem_create(beam_type, OSKAR_CPU, max_size, status); } /* Cross-correlation beam output arrays. */ if (!d->cross_power[i_stokes] && cross_power) { if (h->num_active_stations < 2) { oskar_log_error(h->log, "Cannot create cross-power beam " "using less than two active stations."); *status = OSKAR_ERR_INVALID_ARGUMENT; break; } /* Device memory. */ d->cross_power[i_stokes] = oskar_mem_create( beam_type, dev_loc, max_src, status); /* Host memory. */ d->cross_power_cpu[i_stokes][0] = oskar_mem_create( beam_type, OSKAR_CPU, max_src, status); d->cross_power_cpu[i_stokes][1] = oskar_mem_create( beam_type, OSKAR_CPU, max_src, status); if (h->average_single_axis == 'T') d->cross_power_time_avg[i_stokes] = oskar_mem_create( beam_type, OSKAR_CPU, max_src, status); if (h->average_single_axis == 'C') d->cross_power_channel_avg[i_stokes] = oskar_mem_create( beam_type, OSKAR_CPU, max_src, status); if (h->average_time_and_channel) d->cross_power_channel_and_time_avg[i_stokes] = oskar_mem_create(beam_type, OSKAR_CPU, max_src, status); } if (d->auto_power[i_stokes]) oskar_mem_clear_contents(d->auto_power[i_stokes], status); if (d->cross_power[i_stokes]) oskar_mem_clear_contents(d->cross_power[i_stokes], status); } /* Timers. */ if (!d->tmr_compute) d->tmr_compute = oskar_timer_create(OSKAR_TIMER_NATIVE); } }
TEST(Log, oskar_log_error) { oskar_log_error("This is an error"); }
void oskar_convert_brightness_to_jy(oskar_Mem* data, double beam_area_pixels, double pixel_area_sr, double frequency_hz, double min_peak_fraction, double min_abs_val, const char* reported_map_units, const char* default_map_units, int override_input_units, int* status) { static const double k_B = 1.3806488e-23; /* Boltzmann constant. */ double lambda, peak = 0.0, peak_min = 0.0, scaling = 1.0, val = 0.0; const char* unit_str = 0; int i = 0, num_pixels, units = 0, type; if (*status) return; /* Filter and find peak of image. */ num_pixels = (int) oskar_mem_length(data); type = oskar_mem_precision(data); if (type == OSKAR_SINGLE) { float *img = oskar_mem_float(data, status); for (i = 0; i < num_pixels; ++i) { val = img[i]; if (val > peak) peak = val; } peak_min = peak * min_peak_fraction; for (i = 0; i < num_pixels; ++i) { val = img[i]; if (val < peak_min || val < min_abs_val) img[i] = 0.0; } } else { double *img = oskar_mem_double(data, status); for (i = 0; i < num_pixels; ++i) { val = img[i]; if (val > peak) peak = val; } peak_min = peak * min_peak_fraction; for (i = 0; i < num_pixels; ++i) { val = img[i]; if (val < peak_min || val < min_abs_val) img[i] = 0.0; } } /* Find brightness units. */ unit_str = (!reported_map_units || override_input_units) ? default_map_units : reported_map_units; if (!strncmp(unit_str, "JY/BEAM", 7) || !strncmp(unit_str, "Jy/beam", 7)) units = JY_BEAM; else if (!strncmp(unit_str, "JY/PIXEL", 8) || !strncmp(unit_str, "Jy/pixel", 8)) units = JY_PIXEL; else if (!strncmp(unit_str, "mK", 2)) units = MK; else if (!strncmp(unit_str, "K", 1)) units = K; else *status = OSKAR_ERR_BAD_UNITS; /* Check if we need to convert the pixel values. */ if (units == JY_BEAM) { if (beam_area_pixels == 0.0) { oskar_log_error("Need beam area for maps in Jy/beam."); *status = OSKAR_ERR_BAD_UNITS; } else scaling = 1.0 / beam_area_pixels; } else if (units == K || units == MK) { if (units == MK) scaling = 1e-3; /* Convert milli-Kelvin to Kelvin. */ /* Convert temperature to Jansky per pixel. */ /* Brightness temperature to flux density conversion: * http://www.iram.fr/IRAMFR/IS/IS2002/html_1/node187.html */ /* Multiply by 2.0 * k_B * pixel_area * 10^26 / lambda^2. */ lambda = 299792458.0 / frequency_hz; scaling *= (2.0 * k_B * pixel_area_sr * 1e26 / (lambda*lambda)); } /* Scale pixels into Jy. */ if (scaling != 1.0) oskar_mem_scale_real(data, scaling, 0, oskar_mem_length(data), status); }
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); }
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_imager_read_coords_ms(oskar_Imager* h, const char* filename, int i_file, int num_files, int* percent_done, int* percent_next, int* status) { #ifndef OSKAR_NO_MS oskar_MeasurementSet* ms; oskar_Mem *uvw, *u, *v, *w, *weight, *time_centroid; int num_channels, num_stations, num_baselines, num_pols; int start_row, num_rows; double *uvw_, *u_, *v_, *w_; if (*status) return; /* Read the header. */ ms = oskar_ms_open(filename); if (!ms) { *status = OSKAR_ERR_FILE_IO; return; } num_rows = (int) oskar_ms_num_rows(ms); num_stations = (int) oskar_ms_num_stations(ms); num_baselines = num_stations * (num_stations - 1) / 2; num_pols = (int) oskar_ms_num_pols(ms); num_channels = (int) oskar_ms_num_channels(ms); /* Set visibility meta-data. */ oskar_imager_set_vis_frequency(h, oskar_ms_freq_start_hz(ms), oskar_ms_freq_inc_hz(ms), num_channels); oskar_imager_set_vis_phase_centre(h, oskar_ms_phase_centre_ra_rad(ms) * 180/M_PI, oskar_ms_phase_centre_dec_rad(ms) * 180/M_PI); /* Create arrays. */ uvw = oskar_mem_create(OSKAR_DOUBLE, OSKAR_CPU, 3 * num_baselines, status); u = oskar_mem_create(OSKAR_DOUBLE, OSKAR_CPU, num_baselines, status); v = oskar_mem_create(OSKAR_DOUBLE, OSKAR_CPU, num_baselines, status); w = oskar_mem_create(OSKAR_DOUBLE, OSKAR_CPU, num_baselines, status); weight = oskar_mem_create(OSKAR_SINGLE, OSKAR_CPU, num_baselines * num_pols, status); time_centroid = oskar_mem_create(OSKAR_DOUBLE, OSKAR_CPU, num_baselines, status); uvw_ = oskar_mem_double(uvw, status); u_ = oskar_mem_double(u, status); v_ = oskar_mem_double(v, status); w_ = oskar_mem_double(w, status); /* Loop over visibility blocks. */ for (start_row = 0; start_row < num_rows; start_row += num_baselines) { int i, block_size; size_t allocated, required; if (*status) break; /* Read coordinates and weights from Measurement Set. */ oskar_timer_resume(h->tmr_read); block_size = num_rows - start_row; if (block_size > num_baselines) block_size = num_baselines; allocated = oskar_mem_length(uvw) * oskar_mem_element_size(oskar_mem_type(uvw)); oskar_ms_read_column(ms, "UVW", start_row, block_size, allocated, oskar_mem_void(uvw), &required, status); allocated = oskar_mem_length(weight) * oskar_mem_element_size(oskar_mem_type(weight)); oskar_ms_read_column(ms, "WEIGHT", start_row, block_size, allocated, oskar_mem_void(weight), &required, status); allocated = oskar_mem_length(time_centroid) * oskar_mem_element_size(oskar_mem_type(time_centroid)); oskar_ms_read_column(ms, "TIME_CENTROID", start_row, block_size, allocated, oskar_mem_void(time_centroid), &required, status); /* Split up baseline coordinates. */ for (i = 0; i < block_size; ++i) { u_[i] = uvw_[3*i + 0]; v_[i] = uvw_[3*i + 1]; w_[i] = uvw_[3*i + 2]; } /* Update the imager with the data. */ oskar_timer_pause(h->tmr_read); oskar_imager_update(h, block_size, 0, num_channels - 1, num_pols, u, v, w, 0, weight, time_centroid, status); *percent_done = (int) round(100.0 * ( (start_row + block_size) / (double)(num_rows * 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(uvw, status); oskar_mem_free(u, status); oskar_mem_free(v, status); oskar_mem_free(w, status); oskar_mem_free(weight, status); oskar_mem_free(time_centroid, status); oskar_ms_close(ms); #else (void) filename; (void) i_file; (void) num_files; (void) percent_done; (void) percent_next; oskar_log_error(h->log, "OSKAR was compiled without Measurement Set support."); *status = OSKAR_ERR_FUNCTION_NOT_AVAILABLE; #endif }
TEST(Log, oskar_log_error) { oskar_Log* log = 0; oskar_log_error(log, "This is an error."); if (log) oskar_log_free(log); }
void oskar_settings_load_observation(oskar_SettingsObservation* obs, oskar_Log* log, const char* filename, int* status) { QByteArray t; QSettings s(QString(filename), QSettings::IniFormat); if (*status) return; s.beginGroup("observation"); { // Get observation start time as MJD(UTC). QString str_st = s.value("start_time_utc").toString(); if (str_st.size() > 0 && !str_st.contains(":")) { bool ok = false; obs->start_mjd_utc = str_st.toDouble(&ok); if (!ok) { oskar_log_error(log, "Invalid string for 'start_time_utc'."); *status = OSKAR_ERR_INVALID_ARGUMENT; return; } } else { const char* format_strings[] = { "d-M-yyyy h:m:s.z", // British style "d-M-yyyy h:m:s", "yyyy/M/d/h:m:s.z", // CASA style "yyyy/M/d/h:m:s", "yyyy-MM-dd h:m:s.z", // International style "yyyy-MM-dd h:m:s", "yyyy-MM-ddTh:m:s.z", // ISO date style "yyyy-MM-ddTh:m:s", }; QDateTime st; int i = 0, num_formats = sizeof(format_strings) / sizeof(char*); for (i = 0; i < num_formats; ++i) { st = QDateTime::fromString(str_st, format_strings[i]); if (st.isValid()) break; } if (i == num_formats) { oskar_log_error(log, "Invalid string for 'start_time_utc'."); *status = OSKAR_ERR_INVALID_ARGUMENT; return; } int year = st.date().year(); int month = st.date().month(); int day = st.date().day(); int hour = st.time().hour(); int minute = st.time().minute(); double second = st.time().second() + st.time().msec() / 1000.0; // Compute start time as MJD(UTC). double day_fraction = (hour + (minute / 60.0) + (second / 3600.0)) / 24.0; obs->start_mjd_utc = convert_date_time_to_mjd(year, month, day, day_fraction); } // Get number of time steps. obs->num_time_steps = s.value("num_time_steps", 1).toInt(); // Get observation length, either as number of seconds, or as a string. QString length = s.value("length").toString(); if (length.size() > 0 && !length.contains(":")) { bool ok = false; obs->length_sec = length.toDouble(&ok); if (!ok) { oskar_log_error(log, "Invalid time string for 'length'"); *status = OSKAR_ERR_INVALID_ARGUMENT; return; } } else { QTime len = QTime::fromString(length, "h:m:s.z"); if (!len.isValid()) { len = QTime::fromString(length, "h:m:s"); if (!len.isValid()) { oskar_log_error(log, "Invalid time string for 'length' " "(format must be hh:mm:ss.z)."); *status = OSKAR_ERR_INVALID_ARGUMENT; return; } } obs->length_sec = len.hour() * 3600.0 + len.minute() * 60.0 + len.second() + len.msec() / 1000.0; } obs->length_days = obs->length_sec / 86400.0; } s.endGroup(); // Range checks. if (obs->num_time_steps <= 0) obs->num_time_steps = 1; // Compute interval obs->dt_dump_days = obs->length_days / obs->num_time_steps; }
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; }