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; }
void oskar_fft_exec(oskar_FFT* h, oskar_Mem* data, int* status) { oskar_Mem *data_copy = 0, *data_ptr = data; if (oskar_mem_location(data) != h->location) { data_copy = oskar_mem_create_copy(data, h->location, status); data_ptr = data_copy; } if (h->location == OSKAR_CPU) { if (h->num_dim == 1) { *status = OSKAR_ERR_FUNCTION_NOT_AVAILABLE; } else if (h->num_dim == 2) { if (h->precision == OSKAR_DOUBLE) oskar_fftpack_cfft2f(h->dim_size, h->dim_size, h->dim_size, oskar_mem_double(data_ptr, status), oskar_mem_double(h->fftpack_wsave, status), oskar_mem_double(h->fftpack_work, status)); else oskar_fftpack_cfft2f_f(h->dim_size, h->dim_size, h->dim_size, oskar_mem_float(data_ptr, status), oskar_mem_float(h->fftpack_wsave, status), oskar_mem_float(h->fftpack_work, status)); /* This step not needed for W-kernel generation, so turn it off. */ if (h->ensure_consistent_norm) oskar_mem_scale_real(data_ptr, (double)h->num_cells_total, 0, h->num_cells_total, status); } } else if (h->location == OSKAR_GPU) { #ifdef OSKAR_HAVE_CUDA if (h->precision == OSKAR_DOUBLE) cufftExecZ2Z(h->cufft_plan, (cufftDoubleComplex*) oskar_mem_void(data_ptr), (cufftDoubleComplex*) oskar_mem_void(data_ptr), CUFFT_FORWARD); else cufftExecC2C(h->cufft_plan, (cufftComplex*) oskar_mem_void(data_ptr), (cufftComplex*) oskar_mem_void(data_ptr), CUFFT_FORWARD); #endif } else *status = OSKAR_ERR_BAD_LOCATION; if (oskar_mem_location(data) != h->location) oskar_mem_copy(data, data_ptr, status); oskar_mem_free(data_copy, status); }
void oskar_imager_finalise(oskar_Imager* h, int num_output_images, oskar_Mem** output_images, int num_output_grids, oskar_Mem** output_grids, int* status) { int t, c, p, i; if (*status || !h->planes) return; /* Adjust normalisation if required. */ if (h->scale_norm_with_num_input_files) { for (i = 0; i < h->num_planes; ++i) h->plane_norm[i] /= h->num_files; } /* Copy grids to output grid planes if given. */ for (i = 0; (i < h->num_planes) && (i < num_output_grids); ++i) { oskar_mem_copy(output_grids[i], h->planes[i], status); oskar_mem_scale_real(output_grids[i], 1.0 / h->plane_norm[i], status); } /* Check if images are required. */ if (h->fits_file[0] || output_images) { /* Finalise all the planes. */ for (i = 0; i < h->num_planes; ++i) { oskar_imager_finalise_plane(h, h->planes[i], h->plane_norm[i], status); oskar_imager_trim_image(h->planes[i], h->grid_size, h->image_size, status); } /* Copy images to output image planes if given. */ for (i = 0; (i < h->num_planes) && (i < num_output_images); ++i) { memcpy(oskar_mem_void(output_images[i]), oskar_mem_void_const(h->planes[i]), h->image_size * h->image_size * oskar_mem_element_size(h->imager_prec)); } /* Write to files if required. */ for (t = 0, i = 0; t < h->im_num_times; ++t) for (c = 0; c < h->im_num_channels; ++c) for (p = 0; p < h->im_num_pols; ++p, ++i) write_plane(h, h->planes[i], t, c, p, status); } /* Reset imager memory. */ oskar_imager_reset_cache(h, status); }
void oskar_evaluate_station_beam(oskar_Mem* beam_pattern, int num_points, int coord_type, oskar_Mem* x, oskar_Mem* y, oskar_Mem* z, double norm_ra_rad, double norm_dec_rad, const oskar_Station* station, oskar_StationWork* work, int time_index, double frequency_hz, double GAST, int* status) { int normalise_final_beam; oskar_Mem* out; /* Check if safe to proceed. */ if (*status) return; /* Set default output beam array. */ out = beam_pattern; /* Check that the arrays have enough space to add an extra source at the * end (for normalisation). We don't want to reallocate here, since that * will be slow to do each time: must simply ensure that we pass input * arrays that are large enough. * The normalisation doesn't need to happen if the station has an * isotropic beam. */ normalise_final_beam = oskar_station_normalise_final_beam(station) && (oskar_station_type(station) != OSKAR_STATION_TYPE_ISOTROPIC); if (normalise_final_beam) { double c_x = 0.0, c_y = 0.0, c_z = 1.0; /* Increment number of points. */ num_points++; /* Check the input arrays are big enough to hold the new source. */ if ((int)oskar_mem_length(x) < num_points || (int)oskar_mem_length(y) < num_points || (int)oskar_mem_length(z) < num_points) { *status = OSKAR_ERR_DIMENSION_MISMATCH; return; } /* Set output beam array to work buffer. */ out = oskar_station_work_normalised_beam(work, beam_pattern, status); /* Get the beam direction in the appropriate coordinate system. */ /* (Direction cosines are already set to the interferometer phase * centre for relative directions.) */ if (coord_type == OSKAR_ENU_DIRECTIONS) { double t_x, t_y, t_z, ha0; ha0 = (GAST + oskar_station_lon_rad(station)) - norm_ra_rad; oskar_convert_relative_directions_to_enu_directions_d( &t_x, &t_y, &t_z, 1, &c_x, &c_y, &c_z, ha0, norm_dec_rad, oskar_station_lat_rad(station)); c_x = t_x; c_y = t_y; c_z = t_z; } /* Add the extra normalisation source to the end of the arrays. */ oskar_mem_set_element_real(x, num_points-1, c_x, status); oskar_mem_set_element_real(y, num_points-1, c_y, status); oskar_mem_set_element_real(z, num_points-1, c_z, status); } /* Evaluate the station beam for the given directions. */ if (coord_type == OSKAR_ENU_DIRECTIONS) { evaluate_station_beam_enu_directions(out, num_points, x, y, z, station, work, time_index, frequency_hz, GAST, status); } else if (coord_type == OSKAR_RELATIVE_DIRECTIONS) { evaluate_station_beam_relative_directions(out, num_points, x, y, z, station, work, time_index, frequency_hz, GAST, status); } else { *status = OSKAR_ERR_INVALID_ARGUMENT; } /* Scale beam pattern by value of the last source if required. */ if (normalise_final_beam) { double amp = 0.0; /* Get the last element of the vector and convert to amplitude. */ if (oskar_mem_is_matrix(out)) { double4c val; val = oskar_mem_get_element_matrix(out, num_points-1, status); /* * Scale by square root of "Stokes I" autocorrelation: * sqrt(0.5 * [sum of resultant diagonal]). * * We have * [ Xa Xb ] [ Xa* Xc* ] = [ Xa Xa* + Xb Xb* (don't care) ] * [ Xc Xd ] [ Xb* Xd* ] [ (don't care) Xc Xc* + Xd Xd* ] * * Stokes I is completely real, so need only evaluate the real * part of all the multiplies. Because of the conjugate terms, * these become re*re + im*im. * * Need the square root because we only want the normalised value * for the beam itself (in isolation), not its actual * autocorrelation! */ amp = val.a.x * val.a.x + val.a.y * val.a.y + val.b.x * val.b.x + val.b.y * val.b.y + val.c.x * val.c.x + val.c.y * val.c.y + val.d.x * val.d.x + val.d.y * val.d.y; amp = sqrt(0.5 * amp); } else { double2 val; val = oskar_mem_get_element_complex(out, num_points-1, status); /* Scale by voltage. */ amp = sqrt(val.x * val.x + val.y * val.y); } /* Scale beam array by normalisation value. */ oskar_mem_scale_real(out, 1.0/amp, status); /* Copy output beam data. */ oskar_mem_copy_contents(beam_pattern, out, 0, 0, num_points-1, status); } }
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_imager_finalise_plane(oskar_Imager* h, oskar_Mem* plane, double plane_norm, int* status) { int size, num_cells; DeviceData* d; if (*status) return; /* Apply normalisation. */ if (plane_norm > 0.0 || plane_norm < 0.0) oskar_mem_scale_real(plane, 1.0 / plane_norm, status); if (h->algorithm == OSKAR_ALGORITHM_DFT_2D || h->algorithm == OSKAR_ALGORITHM_DFT_3D) return; /* Check plane is complex type, as plane must be gridded visibilities. */ if (!oskar_mem_is_complex(plane)) { *status = OSKAR_ERR_TYPE_MISMATCH; return; } /* Make image using FFT and apply grid correction. */ size = h->grid_size; num_cells = size * size; d = &h->d[0]; if (oskar_mem_precision(plane) == OSKAR_DOUBLE) { oskar_fftphase_cd(size, size, oskar_mem_double(plane, status)); if (h->fft_on_gpu) { #ifdef OSKAR_HAVE_CUDA oskar_device_set(h->cuda_device_ids[0], status); oskar_mem_copy(d->plane_gpu, plane, status); cufftExecZ2Z(h->cufft_plan, oskar_mem_void(d->plane_gpu), oskar_mem_void(d->plane_gpu), CUFFT_FORWARD); oskar_mem_copy(plane, d->plane_gpu, status); #else *status = OSKAR_ERR_CUDA_NOT_AVAILABLE; #endif } else { oskar_fftpack_cfft2f(size, size, size, oskar_mem_double(plane, status), oskar_mem_double(h->fftpack_wsave, status), oskar_mem_double(h->fftpack_work, status)); oskar_mem_scale_real(plane, (double)num_cells, status); } oskar_fftphase_cd(size, size, oskar_mem_double(plane, status)); oskar_grid_correction_d(size, oskar_mem_double(h->corr_func, status), oskar_mem_double(plane, status)); } else { oskar_fftphase_cf(size, size, oskar_mem_float(plane, status)); if (h->fft_on_gpu) { #ifdef OSKAR_HAVE_CUDA oskar_device_set(h->cuda_device_ids[0], status); oskar_mem_copy(d->plane_gpu, plane, status); cufftExecC2C(h->cufft_plan, oskar_mem_void(d->plane_gpu), oskar_mem_void(d->plane_gpu), CUFFT_FORWARD); oskar_mem_copy(plane, d->plane_gpu, status); #else *status = OSKAR_ERR_CUDA_NOT_AVAILABLE; #endif } else { oskar_fftpack_cfft2f_f(size, size, size, oskar_mem_float(plane, status), oskar_mem_float(h->fftpack_wsave, status), oskar_mem_float(h->fftpack_work, status)); oskar_mem_scale_real(plane, (double)num_cells, status); } oskar_fftphase_cf(size, size, oskar_mem_float(plane, status)); oskar_grid_correction_f(size, oskar_mem_double(h->corr_func, status), oskar_mem_float(plane, status)); } }
void oskar_dftw( int normalise, int num_in, double wavenumber, const oskar_Mem* weights_in, const oskar_Mem* x_in, const oskar_Mem* y_in, const oskar_Mem* z_in, int offset_coord_out, int num_out, const oskar_Mem* x_out, const oskar_Mem* y_out, const oskar_Mem* z_out, const oskar_Mem* data, int offset_out, oskar_Mem* output, int* status) { if (*status) return; const int location = oskar_mem_location(output); const int type = oskar_mem_precision(output); const int is_dbl = oskar_mem_is_double(output); const int is_3d = (z_in != NULL && z_out != NULL); const int is_data = (data != NULL); const int is_matrix = oskar_mem_is_matrix(output); if (!oskar_mem_is_complex(output) || !oskar_mem_is_complex(weights_in) || oskar_mem_is_matrix(weights_in)) { *status = OSKAR_ERR_BAD_DATA_TYPE; return; } if (oskar_mem_location(weights_in) != location || oskar_mem_location(x_in) != location || oskar_mem_location(y_in) != location || oskar_mem_location(x_out) != location || oskar_mem_location(y_out) != location) { *status = OSKAR_ERR_LOCATION_MISMATCH; return; } if (oskar_mem_precision(weights_in) != type || oskar_mem_type(x_in) != type || oskar_mem_type(y_in) != type || oskar_mem_type(x_out) != type || oskar_mem_type(y_out) != type) { *status = OSKAR_ERR_TYPE_MISMATCH; return; } if (is_data) { if (oskar_mem_location(data) != location) { *status = OSKAR_ERR_LOCATION_MISMATCH; return; } if (!oskar_mem_is_complex(data) || oskar_mem_type(data) != oskar_mem_type(output) || oskar_mem_precision(data) != type) { *status = OSKAR_ERR_TYPE_MISMATCH; return; } } if (is_3d) { if (oskar_mem_location(z_in) != location || oskar_mem_location(z_out) != location) { *status = OSKAR_ERR_LOCATION_MISMATCH; return; } if (oskar_mem_type(z_in) != type || oskar_mem_type(z_out) != type) { *status = OSKAR_ERR_TYPE_MISMATCH; return; } } oskar_mem_ensure(output, (size_t) offset_out + num_out, status); if (*status) return; if (location == OSKAR_CPU) { if (is_data) { if (is_matrix) { if (is_3d) { if (is_dbl) dftw_m2m_3d_double(num_in, wavenumber, oskar_mem_double2_const(weights_in, status), oskar_mem_double_const(x_in, status), oskar_mem_double_const(y_in, status), oskar_mem_double_const(z_in, status), offset_coord_out, num_out, oskar_mem_double_const(x_out, status), oskar_mem_double_const(y_out, status), oskar_mem_double_const(z_out, status), oskar_mem_double4c_const(data, status), offset_out, oskar_mem_double4c(output, status), 0); else dftw_m2m_3d_float(num_in, (float)wavenumber, oskar_mem_float2_const(weights_in, status), oskar_mem_float_const(x_in, status), oskar_mem_float_const(y_in, status), oskar_mem_float_const(z_in, status), offset_coord_out, num_out, oskar_mem_float_const(x_out, status), oskar_mem_float_const(y_out, status), oskar_mem_float_const(z_out, status), oskar_mem_float4c_const(data, status), offset_out, oskar_mem_float4c(output, status), 0); } else { if (is_dbl) dftw_m2m_2d_double(num_in, wavenumber, oskar_mem_double2_const(weights_in, status), oskar_mem_double_const(x_in, status), oskar_mem_double_const(y_in, status), 0, offset_coord_out, num_out, oskar_mem_double_const(x_out, status), oskar_mem_double_const(y_out, status), 0, oskar_mem_double4c_const(data, status), offset_out, oskar_mem_double4c(output, status), 0); else dftw_m2m_2d_float(num_in, (float)wavenumber, oskar_mem_float2_const(weights_in, status), oskar_mem_float_const(x_in, status), oskar_mem_float_const(y_in, status), 0, offset_coord_out, num_out, oskar_mem_float_const(x_out, status), oskar_mem_float_const(y_out, status), 0, oskar_mem_float4c_const(data, status), offset_out, oskar_mem_float4c(output, status), 0); } } else { if (is_3d) { if (is_dbl) dftw_c2c_3d_double(num_in, wavenumber, oskar_mem_double2_const(weights_in, status), oskar_mem_double_const(x_in, status), oskar_mem_double_const(y_in, status), oskar_mem_double_const(z_in, status), offset_coord_out, num_out, oskar_mem_double_const(x_out, status), oskar_mem_double_const(y_out, status), oskar_mem_double_const(z_out, status), oskar_mem_double2_const(data, status), offset_out, oskar_mem_double2(output, status), 0); else dftw_c2c_3d_float(num_in, (float)wavenumber, oskar_mem_float2_const(weights_in, status), oskar_mem_float_const(x_in, status), oskar_mem_float_const(y_in, status), oskar_mem_float_const(z_in, status), offset_coord_out, num_out, oskar_mem_float_const(x_out, status), oskar_mem_float_const(y_out, status), oskar_mem_float_const(z_out, status), oskar_mem_float2_const(data, status), offset_out, oskar_mem_float2(output, status), 0); } else { if (is_dbl) dftw_c2c_2d_double(num_in, wavenumber, oskar_mem_double2_const(weights_in, status), oskar_mem_double_const(x_in, status), oskar_mem_double_const(y_in, status), 0, offset_coord_out, num_out, oskar_mem_double_const(x_out, status), oskar_mem_double_const(y_out, status), 0, oskar_mem_double2_const(data, status), offset_out, oskar_mem_double2(output, status), 0); else dftw_c2c_2d_float(num_in, (float)wavenumber, oskar_mem_float2_const(weights_in, status), oskar_mem_float_const(x_in, status), oskar_mem_float_const(y_in, status), 0, offset_coord_out, num_out, oskar_mem_float_const(x_out, status), oskar_mem_float_const(y_out, status), 0, oskar_mem_float2_const(data, status), offset_out, oskar_mem_float2(output, status), 0); } } } else { if (is_3d) { if (is_dbl) dftw_o2c_3d_double(num_in, wavenumber, oskar_mem_double2_const(weights_in, status), oskar_mem_double_const(x_in, status), oskar_mem_double_const(y_in, status), oskar_mem_double_const(z_in, status), offset_coord_out, num_out, oskar_mem_double_const(x_out, status), oskar_mem_double_const(y_out, status), oskar_mem_double_const(z_out, status), 0, offset_out, oskar_mem_double2(output, status), 0); else dftw_o2c_3d_float(num_in, (float)wavenumber, oskar_mem_float2_const(weights_in, status), oskar_mem_float_const(x_in, status), oskar_mem_float_const(y_in, status), oskar_mem_float_const(z_in, status), offset_coord_out, num_out, oskar_mem_float_const(x_out, status), oskar_mem_float_const(y_out, status), oskar_mem_float_const(z_out, status), 0, offset_out, oskar_mem_float2(output, status), 0); } else { if (is_dbl) dftw_o2c_2d_double(num_in, wavenumber, oskar_mem_double2_const(weights_in, status), oskar_mem_double_const(x_in, status), oskar_mem_double_const(y_in, status), 0, offset_coord_out, num_out, oskar_mem_double_const(x_out, status), oskar_mem_double_const(y_out, status), 0, 0, offset_out, oskar_mem_double2(output, status), 0); else dftw_o2c_2d_float(num_in, (float)wavenumber, oskar_mem_float2_const(weights_in, status), oskar_mem_float_const(x_in, status), oskar_mem_float_const(y_in, status), 0, offset_coord_out, num_out, oskar_mem_float_const(x_out, status), oskar_mem_float_const(y_out, status), 0, 0, offset_out, oskar_mem_float2(output, status), 0); } } } else { size_t local_size[] = {256, 1, 1}, global_size[] = {1, 1, 1}; const void* np = 0; const char* k = 0; int max_in_chunk; float wavenumber_f = (float) wavenumber; /* Select the kernel. */ switch (is_dbl * DBL | is_3d * D3 | is_data * DAT | is_matrix * MAT) { case D2 | FLT: k = "dftw_o2c_2d_float"; break; case D2 | DBL: k = "dftw_o2c_2d_double"; break; case D3 | FLT: k = "dftw_o2c_3d_float"; break; case D3 | DBL: k = "dftw_o2c_3d_double"; break; case D2 | FLT | DAT: k = "dftw_c2c_2d_float"; break; case D2 | DBL | DAT: k = "dftw_c2c_2d_double"; break; case D3 | FLT | DAT: k = "dftw_c2c_3d_float"; break; case D3 | DBL | DAT: k = "dftw_c2c_3d_double"; break; case D2 | FLT | DAT | MAT: k = "dftw_m2m_2d_float"; break; case D2 | DBL | DAT | MAT: k = "dftw_m2m_2d_double"; break; case D3 | FLT | DAT | MAT: k = "dftw_m2m_3d_float"; break; case D3 | DBL | DAT | MAT: k = "dftw_m2m_3d_double"; break; default: *status = OSKAR_ERR_FUNCTION_NOT_AVAILABLE; return; } if (oskar_device_is_nv(location)) local_size[0] = (size_t) get_block_size(num_out); oskar_device_check_local_size(location, 0, local_size); global_size[0] = oskar_device_global_size( (size_t) num_out, local_size[0]); /* max_in_chunk must be multiple of 16. */ max_in_chunk = is_3d ? (is_dbl ? 384 : 800) : (is_dbl ? 448 : 896); if (is_data && is_3d && !is_dbl) max_in_chunk = 768; const size_t element_size = is_dbl ? sizeof(double) : sizeof(float); const size_t local_mem_size = max_in_chunk * element_size; const size_t arg_size_local[] = { 2 * local_mem_size, 2 * local_mem_size, (is_3d ? local_mem_size : 0) }; /* Set kernel arguments. */ const oskar_Arg args[] = { {INT_SZ, &num_in}, {is_dbl ? DBL_SZ : FLT_SZ, is_dbl ? (void*)&wavenumber : (void*)&wavenumber_f}, {PTR_SZ, oskar_mem_buffer_const(weights_in)}, {PTR_SZ, oskar_mem_buffer_const(x_in)}, {PTR_SZ, oskar_mem_buffer_const(y_in)}, {PTR_SZ, is_3d ? oskar_mem_buffer_const(z_in) : &np}, {INT_SZ, &offset_coord_out}, {INT_SZ, &num_out}, {PTR_SZ, oskar_mem_buffer_const(x_out)}, {PTR_SZ, oskar_mem_buffer_const(y_out)}, {PTR_SZ, is_3d ? oskar_mem_buffer_const(z_out) : &np}, {PTR_SZ, is_data ? oskar_mem_buffer_const(data) : &np}, {INT_SZ, &offset_out}, {PTR_SZ, oskar_mem_buffer(output)}, {INT_SZ, &max_in_chunk} }; oskar_device_launch_kernel(k, location, 1, local_size, global_size, sizeof(args) / sizeof(oskar_Arg), args, sizeof(arg_size_local) / sizeof(size_t), arg_size_local, status); } if (normalise) oskar_mem_scale_real(output, 1. / num_in, offset_out, num_out, status); }
static void oskar_evaluate_station_beam_aperture_array_private(oskar_Mem* beam, const oskar_Station* s, int num_points, const oskar_Mem* x, const oskar_Mem* y, const oskar_Mem* z, double gast, double frequency_hz, oskar_StationWork* work, int time_index, int depth, int* status) { double beam_x, beam_y, beam_z, wavenumber; oskar_Mem *weights, *weights_error, *theta, *phi, *array; int num_elements, is_3d; num_elements = oskar_station_num_elements(s); is_3d = oskar_station_array_is_3d(s); weights = work->weights; weights_error = work->weights_error; theta = work->theta_modified; phi = work->phi_modified; array = work->array_pattern; wavenumber = 2.0 * M_PI * frequency_hz / 299792458.0; /* Check if safe to proceed. */ if (*status) return; /* Compute direction cosines for the beam for this station. */ oskar_evaluate_beam_horizon_direction(&beam_x, &beam_y, &beam_z, s, gast, status); /* Evaluate beam if there are no child stations. */ if (!oskar_station_has_child(s)) { /* First optimisation: A single element model type, and either a common * orientation for all elements within the station, or isotropic * elements. */ /* Array pattern and element pattern are separable. */ if (oskar_station_num_element_types(s) == 1 && (oskar_station_common_element_orientation(s) || oskar_element_type(oskar_station_element_const(s, 0)) == OSKAR_ELEMENT_TYPE_ISOTROPIC) ) { /* (Always) evaluate element pattern into the output beam array. */ oskar_element_evaluate(oskar_station_element_const(s, 0), beam, oskar_station_element_x_alpha_rad(s, 0) + M_PI/2.0, /* FIXME Will change: This matches the old convention. */ oskar_station_element_y_alpha_rad(s, 0), num_points, x, y, z, frequency_hz, theta, phi, status); /* Check if array pattern is enabled. */ if (oskar_station_enable_array_pattern(s)) { /* Generate beamforming weights and evaluate array pattern. */ oskar_evaluate_element_weights(weights, weights_error, wavenumber, s, beam_x, beam_y, beam_z, time_index, status); oskar_dftw(num_elements, wavenumber, oskar_station_element_true_x_enu_metres_const(s), oskar_station_element_true_y_enu_metres_const(s), oskar_station_element_true_z_enu_metres_const(s), weights, num_points, x, y, (is_3d ? z : 0), 0, array, status); /* Normalise array response if required. */ if (oskar_station_normalise_array_pattern(s)) oskar_mem_scale_real(array, 1.0 / num_elements, status); /* Element-wise multiply to join array and element pattern. */ oskar_mem_multiply(beam, beam, array, num_points, status); } } #if 0 /* Second optimisation: Common orientation for all elements within the * station, but more than one element type. */ else if (oskar_station_common_element_orientation(s)) { /* Must evaluate array pattern, so check that this is enabled. */ if (!oskar_station_enable_array_pattern(s)) { *status = OSKAR_ERR_SETTINGS_TELESCOPE; return; } /* Call a DFT using indexed input. */ /* TODO Not yet implemented. */ *status = OSKAR_ERR_FUNCTION_NOT_AVAILABLE; } #endif /* No optimisation: No common element orientation. */ /* Can't separate array and element evaluation. */ else { int i, num_element_types; oskar_Mem *element_block = 0, *element = 0; const int* element_type_array = 0; /* Must evaluate array pattern, so check that this is enabled. */ if (!oskar_station_enable_array_pattern(s)) { *status = OSKAR_ERR_SETTINGS_TELESCOPE; return; } /* Get sized element pattern block (at depth 0). */ element_block = oskar_station_work_beam(work, beam, num_elements * num_points, 0, status); /* Create alias into element block. */ element = oskar_mem_create_alias(element_block, 0, 0, status); /* Loop over elements and evaluate response for each. */ element_type_array = oskar_station_element_types_cpu_const(s); num_element_types = oskar_station_num_element_types(s); for (i = 0; i < num_elements; ++i) { int element_type_idx; element_type_idx = element_type_array[i]; if (element_type_idx >= num_element_types) { *status = OSKAR_ERR_OUT_OF_RANGE; break; } oskar_mem_set_alias(element, element_block, i * num_points, num_points, status); oskar_element_evaluate( oskar_station_element_const(s, element_type_idx), element, oskar_station_element_x_alpha_rad(s, i) + M_PI/2.0, /* FIXME Will change: This matches the old convention. */ oskar_station_element_y_alpha_rad(s, i), num_points, x, y, z, frequency_hz, theta, phi, status); } /* Generate beamforming weights. */ oskar_evaluate_element_weights(weights, weights_error, wavenumber, s, beam_x, beam_y, beam_z, time_index, status); /* Use DFT to evaluate array response. */ oskar_dftw(num_elements, wavenumber, oskar_station_element_true_x_enu_metres_const(s), oskar_station_element_true_y_enu_metres_const(s), oskar_station_element_true_z_enu_metres_const(s), weights, num_points, x, y, (is_3d ? z : 0), element_block, beam, status); /* Free element alias. */ oskar_mem_free(element, status); /* Normalise array response if required. */ if (oskar_station_normalise_array_pattern(s)) oskar_mem_scale_real(beam, 1.0 / num_elements, status); } /* Blank (set to zero) points below the horizon. */ oskar_blank_below_horizon(num_points, z, beam, status); } /* If there are child stations, must first evaluate the beam for each. */ else { int i; oskar_Mem* signal; /* Must evaluate array pattern, so check that this is enabled. */ if (!oskar_station_enable_array_pattern(s)) { *status = OSKAR_ERR_SETTINGS_TELESCOPE; return; } /* Get sized work array for this depth, with the correct type. */ signal = oskar_station_work_beam(work, beam, num_elements * num_points, depth, status); /* Check if child stations are identical. */ if (oskar_station_identical_children(s)) { /* Set up the output buffer for the first station. */ oskar_Mem* output0; output0 = oskar_mem_create_alias(signal, 0, num_points, status); /* Recursive call. */ oskar_evaluate_station_beam_aperture_array_private(output0, oskar_station_child_const(s, 0), num_points, x, y, z, gast, frequency_hz, work, time_index, depth + 1, status); /* Copy beam for child station 0 into memory for other stations. */ for (i = 1; i < num_elements; ++i) { oskar_mem_copy_contents(signal, output0, i * num_points, 0, oskar_mem_length(output0), status); } oskar_mem_free(output0, status); } else { /* Loop over child stations. */ for (i = 0; i < num_elements; ++i) { /* Set up the output buffer for this station. */ oskar_Mem* output; output = oskar_mem_create_alias(signal, i * num_points, num_points, status); /* Recursive call. */ oskar_evaluate_station_beam_aperture_array_private(output, oskar_station_child_const(s, i), num_points, x, y, z, gast, frequency_hz, work, time_index, depth + 1, status); oskar_mem_free(output, status); } } /* Generate beamforming weights and form beam from child stations. */ oskar_evaluate_element_weights(weights, weights_error, wavenumber, s, beam_x, beam_y, beam_z, time_index, status); oskar_dftw(num_elements, wavenumber, oskar_station_element_true_x_enu_metres_const(s), oskar_station_element_true_y_enu_metres_const(s), oskar_station_element_true_z_enu_metres_const(s), weights, num_points, x, y, (is_3d ? z : 0), signal, beam, status); /* Normalise array response if required. */ if (oskar_station_normalise_array_pattern(s)) oskar_mem_scale_real(beam, 1.0 / num_elements, status); } }