TEST(Mem, type_check_single) { int status = 0; oskar_Mem *mem; mem = oskar_mem_create(OSKAR_SINGLE, OSKAR_CPU, 0, &status); ASSERT_EQ(0, status) << oskar_get_error_string(status); EXPECT_EQ((int)OSKAR_FALSE, oskar_mem_is_double(mem)); EXPECT_EQ((int)OSKAR_FALSE, oskar_mem_is_complex(mem)); EXPECT_EQ((int)OSKAR_TRUE, oskar_mem_is_scalar(mem)); EXPECT_EQ((int)OSKAR_FALSE, oskar_type_is_double(OSKAR_SINGLE)); EXPECT_EQ((int)OSKAR_FALSE, oskar_type_is_complex(OSKAR_SINGLE)); EXPECT_EQ((int)OSKAR_TRUE, oskar_type_is_scalar(OSKAR_SINGLE)); oskar_mem_free(mem, &status); ASSERT_EQ(0, status) << oskar_get_error_string(status); }
TEST(Mem, type_check_double_complex) { int status = 0; oskar_Mem *mem; mem = oskar_mem_create(OSKAR_DOUBLE_COMPLEX, OSKAR_CPU, 0, &status); EXPECT_EQ((int)OSKAR_TRUE, oskar_mem_is_double(mem)); EXPECT_EQ((int)OSKAR_TRUE, oskar_mem_is_complex(mem)); EXPECT_EQ((int)OSKAR_TRUE, oskar_mem_is_scalar(mem)); EXPECT_EQ((int)OSKAR_TRUE, oskar_type_is_double(OSKAR_DOUBLE_COMPLEX)); EXPECT_EQ((int)OSKAR_TRUE, oskar_type_is_complex(OSKAR_DOUBLE_COMPLEX)); EXPECT_EQ((int)OSKAR_TRUE, oskar_type_is_scalar(OSKAR_DOUBLE_COMPLEX)); oskar_mem_free(mem, &status); ASSERT_EQ(0, status) << oskar_get_error_string(status); }
void oskar_imager_trim_image(oskar_Mem* plane, int plane_size, int image_size, int* status) { int i, num_cells, size_diff; if (*status) return; /* Get the real part only, if the plane is complex. */ if (oskar_mem_is_complex(plane)) { num_cells = plane_size * plane_size; if (oskar_mem_precision(plane) == OSKAR_DOUBLE) { double *t = oskar_mem_double(plane, status); for (i = 0; i < num_cells; ++i) t[i] = t[2 * i]; } else { float *t = oskar_mem_float(plane, status); for (i = 0; i < num_cells; ++i) t[i] = t[2 * i]; } } /* Trim to required image size. */ size_diff = plane_size - image_size; if (size_diff > 0) { char *ptr; size_t in = 0, out = 0, copy_len = 0, element_size = 0; ptr = oskar_mem_char(plane); element_size = oskar_mem_element_size(oskar_mem_precision(plane)); copy_len = element_size * image_size; in = element_size * (size_diff / 2) * (plane_size + 1); for (i = 0; i < image_size; ++i) { /* Use memmove() instead of memcpy() to allow for overlap. */ memmove(ptr + out, ptr + in, copy_len); in += plane_size * element_size; out += copy_len; } } }
void oskar_evaluate_station_beam_gaussian(oskar_Mem* beam, int num_points, const oskar_Mem* l, const oskar_Mem* m, const oskar_Mem* horizon_mask, double fwhm_rad, int* status) { int type, location; double fwhm_lm, std; /* Check if safe to proceed. */ if (*status) return; /* Get type and check consistency. */ type = oskar_mem_precision(beam); if (type != oskar_mem_type(l) || type != oskar_mem_type(m)) { *status = OSKAR_ERR_TYPE_MISMATCH; return; } if (type != OSKAR_SINGLE && type != OSKAR_DOUBLE) { *status = OSKAR_ERR_BAD_DATA_TYPE; return; } if (!oskar_mem_is_complex(beam)) { *status = OSKAR_ERR_BAD_DATA_TYPE; return; } if (fwhm_rad == 0.0) { *status = OSKAR_ERR_SETTINGS_TELESCOPE; return; } /* Get location and check consistency. */ location = oskar_mem_location(beam); if (location != oskar_mem_location(l) || location != oskar_mem_location(m)) { *status = OSKAR_ERR_LOCATION_MISMATCH; return; } /* Check that length of input arrays are consistent. */ if ((int)oskar_mem_length(l) < num_points || (int)oskar_mem_length(m) < num_points) { *status = OSKAR_ERR_DIMENSION_MISMATCH; return; } /* Resize output array if needed. */ if ((int)oskar_mem_length(beam) < num_points) oskar_mem_realloc(beam, num_points, status); /* Check if safe to proceed. */ if (*status) return; /* Compute Gaussian standard deviation from FWHM. */ fwhm_lm = sin(fwhm_rad); std = fwhm_lm / (2.0 * sqrt(2.0 * log(2.0))); if (type == OSKAR_DOUBLE) { const double *l_, *m_; l_ = oskar_mem_double_const(l, status); m_ = oskar_mem_double_const(m, status); if (location == OSKAR_CPU) { if (oskar_mem_is_scalar(beam)) { oskar_gaussian_d(oskar_mem_double2(beam, status), num_points, l_, m_, std); } else { oskar_gaussian_md(oskar_mem_double4c(beam, status), num_points, l_, m_, std); } } else { #ifdef OSKAR_HAVE_CUDA if (oskar_mem_is_scalar(beam)) { oskar_gaussian_cuda_d(oskar_mem_double2(beam, status), num_points, l_, m_, std); } else { oskar_gaussian_cuda_md(oskar_mem_double4c(beam, status), num_points, l_, m_, std); } oskar_device_check_error(status); #else *status = OSKAR_ERR_CUDA_NOT_AVAILABLE; #endif } } else /* type == OSKAR_SINGLE */ { const float *l_, *m_; l_ = oskar_mem_float_const(l, status); m_ = oskar_mem_float_const(m, status); if (location == OSKAR_CPU) { if (oskar_mem_is_scalar(beam)) { oskar_gaussian_f(oskar_mem_float2(beam, status), num_points, l_, m_, (float)std); } else { oskar_gaussian_mf(oskar_mem_float4c(beam, status), num_points, l_, m_, (float)std); } } else { #ifdef OSKAR_HAVE_CUDA if (oskar_mem_is_scalar(beam)) { oskar_gaussian_cuda_f(oskar_mem_float2(beam, status), num_points, l_, m_, (float)std); } else { oskar_gaussian_cuda_mf(oskar_mem_float4c(beam, status), num_points, l_, m_, (float)std); } oskar_device_check_error(status); #else *status = OSKAR_ERR_CUDA_NOT_AVAILABLE; #endif } } /* Blank (zero) sources below the horizon. */ oskar_blank_below_horizon(beam, horizon_mask, num_points, status); }
void oskar_mem_evaluate_relative_error(const oskar_Mem* val_approx, const oskar_Mem* val_accurate, double* min_rel_error, double* max_rel_error, double* avg_rel_error, double* std_rel_error, int* status) { int prec_approx, prec_accurate; size_t i, n; const oskar_Mem *app_ptr, *acc_ptr; oskar_Mem *approx_temp = 0, *accurate_temp = 0; double old_m = 0.0, new_m = 0.0, old_s = 0.0, new_s = 0.0; /* Check if safe to proceed. */ if (*status) return; /* Initialise outputs. */ if (max_rel_error) *max_rel_error = -DBL_MAX; if (min_rel_error) *min_rel_error = DBL_MAX; if (avg_rel_error) *avg_rel_error = DBL_MAX; if (std_rel_error) *std_rel_error = DBL_MAX; /* Type and dimension check. */ if (oskar_mem_is_matrix(val_approx) && !oskar_mem_is_matrix(val_accurate)) { *status = OSKAR_ERR_TYPE_MISMATCH; return; } if (oskar_mem_is_complex(val_approx) && !oskar_mem_is_complex(val_accurate)) { *status = OSKAR_ERR_TYPE_MISMATCH; return; } /* Get and check base types. */ prec_approx = oskar_mem_precision(val_approx); prec_accurate = oskar_mem_precision(val_accurate); if (prec_approx != OSKAR_SINGLE && prec_approx != OSKAR_DOUBLE) { *status = OSKAR_ERR_BAD_DATA_TYPE; return; } if (prec_accurate != OSKAR_SINGLE && prec_accurate != OSKAR_DOUBLE) { *status = OSKAR_ERR_BAD_DATA_TYPE; return; } /* Get number of elements to check. */ n = oskar_mem_length(val_approx) < oskar_mem_length(val_accurate) ? oskar_mem_length(val_approx) : oskar_mem_length(val_accurate); if (oskar_mem_is_matrix(val_approx)) n *= 4; /* Copy input data to temporary CPU arrays if required. */ app_ptr = val_approx; acc_ptr = val_accurate; if (oskar_mem_location(val_approx) != OSKAR_CPU) { approx_temp = oskar_mem_create_copy(val_approx, OSKAR_CPU, status); if (*status) { oskar_mem_free(approx_temp, status); return; } app_ptr = approx_temp; } if (oskar_mem_location(val_accurate) != OSKAR_CPU) { accurate_temp = oskar_mem_create_copy(val_accurate, OSKAR_CPU, status); if (*status) { oskar_mem_free(accurate_temp, status); return; } acc_ptr = accurate_temp; } /* Check numbers are the same, to appropriate precision. */ if (prec_approx == OSKAR_SINGLE && prec_accurate == OSKAR_SINGLE) { const float *approx, *accurate; approx = oskar_mem_float_const(app_ptr, status); accurate = oskar_mem_float_const(acc_ptr, status); CHECK_ELEMENTS(1e-5) } else if (prec_approx == OSKAR_DOUBLE && prec_accurate == OSKAR_SINGLE)
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_element_evaluate( const oskar_Element* model, double orientation_x, double orientation_y, int offset_points, int num_points, const oskar_Mem* x, const oskar_Mem* y, const oskar_Mem* z, double frequency_hz, oskar_Mem* theta, oskar_Mem* phi, int offset_out, oskar_Mem* output, int* status) { double dipole_length_m; if (*status) return; if (!oskar_mem_is_complex(output)) { *status = OSKAR_ERR_BAD_DATA_TYPE; return; } oskar_mem_ensure(output, offset_out + num_points, status); oskar_mem_ensure(theta, num_points, status); oskar_mem_ensure(phi, num_points, status); /* Get the element model properties. */ const int element_type = model->element_type; const int taper_type = model->taper_type; const int id = oskar_find_closest_match_d(frequency_hz, oskar_element_num_freq(model), oskar_element_freqs_hz_const(model)); dipole_length_m = model->dipole_length; if (model->dipole_length_units == OSKAR_WAVELENGTHS) dipole_length_m *= (C_0 / frequency_hz); /* Compute modified theta and phi coordinates for dipole X. */ oskar_convert_enu_directions_to_theta_phi(offset_points, num_points, x, y, z, (M_PI/2) - orientation_x, theta, phi, status); /* Check if element type is isotropic. */ if (element_type == OSKAR_ELEMENT_TYPE_ISOTROPIC) oskar_mem_set_value_real(output, 1.0, offset_out, num_points, status); /* Evaluate polarised response if output array is matrix type. */ if (oskar_mem_is_matrix(output)) { const int offset_out_real = offset_out * 8; const int offset_out_cplx = offset_out * 4; if (oskar_element_has_x_spherical_wave_data(model, id)) oskar_evaluate_spherical_wave_sum(num_points, theta, phi, model->x_lmax[id], model->x_te[id], model->x_tm[id], 4, offset_out_cplx + 0, output, status); else if (oskar_element_has_x_spline_data(model, id)) { oskar_splines_evaluate(model->x_h_re[id], num_points, theta, phi, 8, offset_out_real + 0, output, status); oskar_splines_evaluate(model->x_h_im[id], num_points, theta, phi, 8, offset_out_real + 1, output, status); oskar_splines_evaluate(model->x_v_re[id], num_points, theta, phi, 8, offset_out_real + 2, output, status); oskar_splines_evaluate(model->x_v_im[id], num_points, theta, phi, 8, offset_out_real + 3, output, status); oskar_convert_ludwig3_to_theta_phi_components(num_points, phi, 4, offset_out_cplx + 0, output, status); } else if (element_type == OSKAR_ELEMENT_TYPE_DIPOLE) oskar_evaluate_dipole_pattern(num_points, theta, phi, frequency_hz, dipole_length_m, 4, offset_out_cplx + 0, output, status); else if (element_type == OSKAR_ELEMENT_TYPE_GEOMETRIC_DIPOLE) oskar_evaluate_geometric_dipole_pattern(num_points, theta, phi, 4, offset_out_cplx + 0, output, status); /* Compute modified theta and phi coordinates for dipole Y. */ oskar_convert_enu_directions_to_theta_phi(offset_points, num_points, x, y, z, (M_PI/2) - orientation_y, theta, phi, status); if (oskar_element_has_y_spherical_wave_data(model, id)) oskar_evaluate_spherical_wave_sum(num_points, theta, phi, model->y_lmax[id], model->y_te[id], model->y_tm[id], 4, offset_out_cplx + 2, output, status); else if (oskar_element_has_y_spline_data(model, id)) { oskar_splines_evaluate(model->y_h_re[id], num_points, theta, phi, 8, offset_out_real + 4, output, status); oskar_splines_evaluate(model->y_h_im[id], num_points, theta, phi, 8, offset_out_real + 5, output, status); oskar_splines_evaluate(model->y_v_re[id], num_points, theta, phi, 8, offset_out_real + 6, output, status); oskar_splines_evaluate(model->y_v_im[id], num_points, theta, phi, 8, offset_out_real + 7, output, status); oskar_convert_ludwig3_to_theta_phi_components(num_points, phi, 4, offset_out_cplx + 2, output, status); } else if (element_type == OSKAR_ELEMENT_TYPE_DIPOLE) oskar_evaluate_dipole_pattern(num_points, theta, phi, frequency_hz, dipole_length_m, 4, offset_out_cplx + 2, output, status); else if (element_type == OSKAR_ELEMENT_TYPE_GEOMETRIC_DIPOLE) oskar_evaluate_geometric_dipole_pattern(num_points, theta, phi, 4, offset_out_cplx + 2, output, status); } else /* Scalar response. */ { const int offset_out_real = offset_out * 2; if (oskar_element_has_scalar_spline_data(model, id)) { oskar_splines_evaluate(model->scalar_re[id], num_points, theta, phi, 2, offset_out_real + 0, output, status); oskar_splines_evaluate(model->scalar_im[id], num_points, theta, phi, 2, offset_out_real + 1, output, status); } else if (element_type == OSKAR_ELEMENT_TYPE_DIPOLE) oskar_evaluate_dipole_pattern(num_points, theta, phi, frequency_hz, dipole_length_m, 1, offset_out, output, status); else if (element_type == OSKAR_ELEMENT_TYPE_GEOMETRIC_DIPOLE) oskar_evaluate_geometric_dipole_pattern(num_points, theta, phi, 1, offset_out, output, status); } /* Apply element tapering, if specified. */ if (taper_type == OSKAR_ELEMENT_TAPER_COSINE) oskar_apply_element_taper_cosine(num_points, model->cosine_power, theta, offset_out, output, status); else if (taper_type == OSKAR_ELEMENT_TAPER_GAUSSIAN) oskar_apply_element_taper_gaussian(num_points, model->gaussian_fwhm_rad, theta, offset_out, output, status); }
void oskar_mem_add_real(oskar_Mem* mem, double val, int* status) { int precision, location; size_t i, num_elements; /* Check if safe to proceed. */ if (*status) return; /* Get meta-data. */ precision = oskar_mem_precision(mem); location = oskar_mem_location(mem); /* Check for empty array. */ num_elements = oskar_mem_length(mem); if (num_elements == 0) return; /* Check location. */ if (location != OSKAR_CPU) { *status = OSKAR_ERR_BAD_LOCATION; return; } /* Get total number of elements to add. */ if (oskar_mem_is_matrix(mem)) num_elements *= 4; /* Switch on type and location. */ if (oskar_mem_is_complex(mem)) { if (precision == OSKAR_DOUBLE) { double2 *t; t = oskar_mem_double2(mem, status); for (i = 0; i < num_elements; ++i) t[i].x += val; } else if (precision == OSKAR_SINGLE) { float2 *t; t = oskar_mem_float2(mem, status); for (i = 0; i < num_elements; ++i) t[i].x += val; } else { *status = OSKAR_ERR_BAD_DATA_TYPE; } } else { if (precision == OSKAR_DOUBLE) { double *t; t = oskar_mem_double(mem, status); for (i = 0; i < num_elements; ++i) t[i] += val; } else if (precision == OSKAR_SINGLE) { float *t; t = oskar_mem_float(mem, status); for (i = 0; i < num_elements; ++i) t[i] += val; } else { *status = OSKAR_ERR_BAD_DATA_TYPE; } } }
void oskar_mem_write_fits_cube(oskar_Mem* data, const char* root_name, int width, int height, int num_planes, int i_plane, int* status) { oskar_Mem *copy = 0, *ptr = 0; size_t len, buf_len; char* fname; /* Checks. */ if (*status) return; if (oskar_mem_is_matrix(data)) { *status = OSKAR_ERR_BAD_DATA_TYPE; return; } /* Construct the filename. */ len = strlen(root_name); buf_len = 11 + len; fname = (char*) calloc(buf_len, sizeof(char)); /* Copy to host memory if necessary. */ ptr = data; if (oskar_mem_location(data) != OSKAR_CPU) { copy = oskar_mem_create_copy(ptr, OSKAR_CPU, status); ptr = copy; } /* Deal with complex data. */ if (oskar_mem_is_complex(ptr)) { oskar_Mem *temp; temp = oskar_mem_create(oskar_mem_precision(ptr), OSKAR_CPU, oskar_mem_length(ptr), status); /* Extract the real part and write it. */ SNPRINTF(fname, buf_len, "%s_REAL.fits", root_name); convert_complex(ptr, temp, 0, status); write_pixels(temp, fname, width, height, num_planes, i_plane, status); /* Extract the imaginary part and write it. */ SNPRINTF(fname, buf_len, "%s_IMAG.fits", root_name); convert_complex(ptr, temp, 1, status); write_pixels(temp, fname, width, height, num_planes, i_plane, status); oskar_mem_free(temp, status); } else { /* No conversion needed. */ if ((len >= 5) && ( !strcmp(&(root_name[len-5]), ".fits") || !strcmp(&(root_name[len-5]), ".FITS") )) { SNPRINTF(fname, buf_len, "%s", root_name); } else { SNPRINTF(fname, buf_len, "%s.fits", root_name); } write_pixels(ptr, fname, width, height, num_planes, i_plane, status); } free(fname); oskar_mem_free(copy, 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); }
void oskar_element_evaluate(const oskar_Element* model, oskar_Mem* output, double orientation_x, double orientation_y, int num_points, const oskar_Mem* x, const oskar_Mem* y, const oskar_Mem* z, double frequency_hz, oskar_Mem* theta, oskar_Mem* phi, int* status) { int element_type, taper_type, freq_id; double dipole_length_m; /* Check if safe to proceed. */ if (*status) return; /* Check that the output array is complex. */ if (!oskar_mem_is_complex(output)) { *status = OSKAR_ERR_BAD_DATA_TYPE; return; } /* Resize output array if required. */ if ((int)oskar_mem_length(output) < num_points) oskar_mem_realloc(output, num_points, status); /* Get the element model properties. */ element_type = model->element_type; taper_type = model->taper_type; dipole_length_m = model->dipole_length; if (model->dipole_length_units == OSKAR_WAVELENGTHS) dipole_length_m *= (C_0 / frequency_hz); /* Check if element type is isotropic. */ if (element_type == OSKAR_ELEMENT_TYPE_ISOTROPIC) oskar_mem_set_value_real(output, 1.0, 0, 0, status); /* Ensure there is enough space in the theta and phi work arrays. */ if ((int)oskar_mem_length(theta) < num_points) oskar_mem_realloc(theta, num_points, status); if ((int)oskar_mem_length(phi) < num_points) oskar_mem_realloc(phi, num_points, status); /* Compute modified theta and phi coordinates for dipole X. */ oskar_convert_enu_directions_to_theta_phi(num_points, x, y, z, M_PI_2 - orientation_x, theta, phi, status); /* Evaluate polarised response if output array is matrix type. */ if (oskar_mem_is_matrix(output)) { /* Check if spline data present for dipole X. */ if (oskar_element_has_x_spline_data(model)) { /* Get the frequency index. */ freq_id = oskar_find_closest_match_d(frequency_hz, oskar_element_num_freq(model), oskar_element_freqs_hz_const(model)); /* Evaluate spline pattern for dipole X. */ oskar_splines_evaluate(output, 0, 8, model->x_h_re[freq_id], num_points, theta, phi, status); oskar_splines_evaluate(output, 1, 8, model->x_h_im[freq_id], num_points, theta, phi, status); oskar_splines_evaluate(output, 2, 8, model->x_v_re[freq_id], num_points, theta, phi, status); oskar_splines_evaluate(output, 3, 8, model->x_v_im[freq_id], num_points, theta, phi, status); /* Convert from Ludwig-3 to spherical representation. */ oskar_convert_ludwig3_to_theta_phi_components(output, 0, 4, num_points, phi, status); } else if (element_type == OSKAR_ELEMENT_TYPE_DIPOLE) { /* Evaluate dipole pattern for dipole X. */ oskar_evaluate_dipole_pattern(output, num_points, theta, phi, frequency_hz, dipole_length_m, 0, 4, status); } else if (element_type == OSKAR_ELEMENT_TYPE_GEOMETRIC_DIPOLE) { /* Evaluate dipole pattern for dipole X. */ oskar_evaluate_geometric_dipole_pattern(output, num_points, theta, phi, 0, 4, status); } /* Compute modified theta and phi coordinates for dipole Y. */ oskar_convert_enu_directions_to_theta_phi(num_points, x, y, z, M_PI_2 - orientation_y, theta, phi, status); /* Check if spline data present for dipole Y. */ if (oskar_element_has_y_spline_data(model)) { /* Get the frequency index. */ freq_id = oskar_find_closest_match_d(frequency_hz, oskar_element_num_freq(model), oskar_element_freqs_hz_const(model)); /* Evaluate spline pattern for dipole Y. */ oskar_splines_evaluate(output, 4, 8, model->y_h_re[freq_id], num_points, theta, phi, status); oskar_splines_evaluate(output, 5, 8, model->y_h_im[freq_id], num_points, theta, phi, status); oskar_splines_evaluate(output, 6, 8, model->y_v_re[freq_id], num_points, theta, phi, status); oskar_splines_evaluate(output, 7, 8, model->y_v_im[freq_id], num_points, theta, phi, status); /* Convert from Ludwig-3 to spherical representation. */ oskar_convert_ludwig3_to_theta_phi_components(output, 2, 4, num_points, phi, status); } else if (element_type == OSKAR_ELEMENT_TYPE_DIPOLE) { /* Evaluate dipole pattern for dipole Y. */ oskar_evaluate_dipole_pattern(output, num_points, theta, phi, frequency_hz, dipole_length_m, 2, 4, status); } else if (element_type == OSKAR_ELEMENT_TYPE_GEOMETRIC_DIPOLE) { /* Evaluate dipole pattern for dipole Y. */ oskar_evaluate_geometric_dipole_pattern(output, num_points, theta, phi, 2, 4, status); } } /* Scalar response. */ else { /* Check if scalar spline data present. */ if (oskar_element_has_scalar_spline_data(model)) { /* Get the frequency index. */ freq_id = oskar_find_closest_match_d(frequency_hz, oskar_element_num_freq(model), oskar_element_freqs_hz_const(model)); oskar_splines_evaluate(output, 0, 2, model->scalar_re[freq_id], num_points, theta, phi, status); oskar_splines_evaluate(output, 1, 2, model->scalar_im[freq_id], num_points, theta, phi, status); } else if (element_type == OSKAR_ELEMENT_TYPE_DIPOLE) { oskar_evaluate_dipole_pattern(output, num_points, theta, phi, frequency_hz, dipole_length_m, 0, 1, status); } else if (element_type == OSKAR_ELEMENT_TYPE_GEOMETRIC_DIPOLE) { oskar_evaluate_geometric_dipole_pattern(output, num_points, theta, phi, 0, 1, status); } } /* Apply element tapering, if specified. */ if (taper_type == OSKAR_ELEMENT_TAPER_COSINE) { oskar_apply_element_taper_cosine(output, num_points, model->cosine_power, theta, status); } else if (taper_type == OSKAR_ELEMENT_TAPER_GAUSSIAN) { oskar_apply_element_taper_gaussian(output, num_points, model->gaussian_fwhm_rad, theta, status); } }
void oskar_imager_update_plane_dft(oskar_Imager* h, size_t num_vis, const oskar_Mem* uu, const oskar_Mem* vv, const oskar_Mem* ww, const oskar_Mem* amps, const oskar_Mem* weight, oskar_Mem* plane, double* plane_norm, int* status) { size_t i, num_pixels; oskar_Thread** threads = 0; ThreadArgs* args = 0; if (*status) return; /* Check the image plane. */ num_pixels = (size_t) h->image_size; num_pixels *= num_pixels; if (oskar_mem_precision(plane) != h->imager_prec) *status = OSKAR_ERR_TYPE_MISMATCH; if (oskar_mem_is_complex(plane) || oskar_mem_is_matrix(plane)) *status = OSKAR_ERR_BAD_DATA_TYPE; oskar_mem_ensure(plane, num_pixels, status); if (*status) return; /* Set up worker threads. */ const size_t num_threads = (size_t) (h->num_devices); 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].thread_id = (int) i; args[i].num_vis = (int) num_vis; args[i].uu = uu; args[i].vv = vv; args[i].ww = ww; args[i].amp = amps; args[i].weight = weight; args[i].plane = plane; } /* Set status code. */ h->status = *status; /* Start the worker threads. */ h->i_block = 0; 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; /* Update normalisation. */ if (oskar_mem_precision(weight) == OSKAR_DOUBLE) { const double* w = oskar_mem_double_const(weight, status); for (i = 0; i < num_vis; ++i) *plane_norm += w[i]; } else { const float* w = oskar_mem_float_const(weight, status); for (i = 0; i < num_vis; ++i) *plane_norm += w[i]; } }