/* Wrapper. */ void oskar_convert_ludwig3_to_theta_phi_components(oskar_Mem* vec, int offset, int stride, int num_points, const oskar_Mem* phi, int* status) { int type, location; /* Check if safe to proceed. */ if (*status) return; /* Check that the vector component data is in matrix form. */ if (!oskar_mem_is_matrix(vec)) { *status = OSKAR_ERR_TYPE_MISMATCH; return; } /* Get data type and location. */ type = oskar_mem_type(phi); location = oskar_mem_location(phi); /* Convert vector representation from Ludwig-3 to spherical. */ if (type == OSKAR_SINGLE) { float2 *h_theta, *v_phi; const float *phi_; h_theta = oskar_mem_float2(vec, status) + offset; v_phi = oskar_mem_float2(vec, status) + offset + 1; phi_ = oskar_mem_float_const(phi, status); if (location == OSKAR_GPU) { #ifdef OSKAR_HAVE_CUDA oskar_convert_ludwig3_to_theta_phi_components_cuda_f(num_points, h_theta, v_phi, phi_, stride); oskar_device_check_error(status); #else *status = OSKAR_ERR_CUDA_NOT_AVAILABLE; #endif } else if (location == OSKAR_CPU) { oskar_convert_ludwig3_to_theta_phi_components_f(num_points, h_theta, v_phi, phi_, stride); } } else if (type == OSKAR_DOUBLE) { double2 *h_theta, *v_phi; const double *phi_; h_theta = oskar_mem_double2(vec, status) + offset; v_phi = oskar_mem_double2(vec, status) + offset + 1; phi_ = oskar_mem_double_const(phi, status); if (location == OSKAR_GPU) { #ifdef OSKAR_HAVE_CUDA oskar_convert_ludwig3_to_theta_phi_components_cuda_d(num_points, h_theta, v_phi, phi_, stride); oskar_device_check_error(status); #else *status = OSKAR_ERR_CUDA_NOT_AVAILABLE; #endif } else if (location == OSKAR_CPU) { oskar_convert_ludwig3_to_theta_phi_components_d(num_points, h_theta, v_phi, phi_, stride); } } else *status = OSKAR_ERR_BAD_DATA_TYPE; }
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_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_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_auto_correlate(oskar_Mem* vis, int n_sources, const oskar_Jones* J, const oskar_Sky* sky, int* status) { int jones_type, base_type, location, matrix_type, n_stations; /* Check if safe to proceed. */ if (*status) return; /* Get the data dimensions. */ n_stations = oskar_jones_num_stations(J); /* Check data locations. */ location = oskar_sky_mem_location(sky); if (oskar_jones_mem_location(J) != location || oskar_mem_location(vis) != location) { *status = OSKAR_ERR_LOCATION_MISMATCH; return; } /* Check for consistent data types. */ jones_type = oskar_jones_type(J); base_type = oskar_sky_precision(sky); matrix_type = oskar_type_is_matrix(jones_type) && oskar_mem_is_matrix(vis); if (oskar_mem_precision(vis) != base_type || oskar_type_precision(jones_type) != base_type) { *status = OSKAR_ERR_TYPE_MISMATCH; return; } if (oskar_mem_type(vis) != jones_type) { *status = OSKAR_ERR_TYPE_MISMATCH; return; } /* If neither single or double precision, return error. */ if (base_type != OSKAR_SINGLE && base_type != OSKAR_DOUBLE) { *status = OSKAR_ERR_BAD_DATA_TYPE; return; } /* Check the input dimensions. */ if (oskar_jones_num_sources(J) < n_sources) { *status = OSKAR_ERR_DIMENSION_MISMATCH; return; } /* Select kernel. */ if (base_type == OSKAR_DOUBLE) { const double *I_, *Q_, *U_, *V_; I_ = oskar_mem_double_const(oskar_sky_I_const(sky), status); Q_ = oskar_mem_double_const(oskar_sky_Q_const(sky), status); U_ = oskar_mem_double_const(oskar_sky_U_const(sky), status); V_ = oskar_mem_double_const(oskar_sky_V_const(sky), status); if (matrix_type) { double4c *vis_; const double4c *J_; vis_ = oskar_mem_double4c(vis, status); J_ = oskar_jones_double4c_const(J, status); if (location == OSKAR_GPU) { #ifdef OSKAR_HAVE_CUDA oskar_auto_correlate_cuda_d(n_sources, n_stations, J_, I_, Q_, U_, V_, vis_); oskar_device_check_error(status); #else *status = OSKAR_ERR_CUDA_NOT_AVAILABLE; #endif } else /* CPU */ { oskar_auto_correlate_omp_d(n_sources, n_stations, J_, I_, Q_, U_, V_, vis_); } } else /* Scalar version. */ { double2 *vis_; const double2 *J_; vis_ = oskar_mem_double2(vis, status); J_ = oskar_jones_double2_const(J, status); if (location == OSKAR_GPU) { #ifdef OSKAR_HAVE_CUDA oskar_auto_correlate_scalar_cuda_d(n_sources, n_stations, J_, I_, vis_); oskar_device_check_error(status); #else *status = OSKAR_ERR_CUDA_NOT_AVAILABLE; #endif } else /* CPU */ { oskar_auto_correlate_scalar_omp_d(n_sources, n_stations, J_, I_, vis_); } } } else /* Single precision. */ { const float *I_, *Q_, *U_, *V_; I_ = oskar_mem_float_const(oskar_sky_I_const(sky), status); Q_ = oskar_mem_float_const(oskar_sky_Q_const(sky), status); U_ = oskar_mem_float_const(oskar_sky_U_const(sky), status); V_ = oskar_mem_float_const(oskar_sky_V_const(sky), status); if (matrix_type) { float4c *vis_; const float4c *J_; vis_ = oskar_mem_float4c(vis, status); J_ = oskar_jones_float4c_const(J, status); if (location == OSKAR_GPU) { #ifdef OSKAR_HAVE_CUDA oskar_auto_correlate_cuda_f(n_sources, n_stations, J_, I_, Q_, U_, V_, vis_); oskar_device_check_error(status); #else *status = OSKAR_ERR_CUDA_NOT_AVAILABLE; #endif } else /* CPU */ { oskar_auto_correlate_omp_f(n_sources, n_stations, J_, I_, Q_, U_, V_, vis_); } } else /* Scalar version. */ { float2 *vis_; const float2 *J_; vis_ = oskar_mem_float2(vis, status); J_ = oskar_jones_float2_const(J, status); if (location == OSKAR_GPU) { #ifdef OSKAR_HAVE_CUDA oskar_auto_correlate_scalar_cuda_f(n_sources, n_stations, J_, I_, vis_); oskar_device_check_error(status); #else *status = OSKAR_ERR_CUDA_NOT_AVAILABLE; #endif } else /* CPU */ { oskar_auto_correlate_scalar_omp_f(n_sources, n_stations, J_, I_, vis_); } } } }
void oskar_convert_ludwig3_to_theta_phi_components( int num_points, const oskar_Mem* phi, int stride, int offset, oskar_Mem* vec, int* status) { if (*status) return; const int type = oskar_mem_type(phi); const int location = oskar_mem_location(phi); const int off_h = offset, off_v = offset + 1; if (!oskar_mem_is_matrix(vec)) { *status = OSKAR_ERR_TYPE_MISMATCH; return; } if (location == OSKAR_CPU) { if (type == OSKAR_SINGLE) convert_ludwig3_to_theta_phi_float( num_points, oskar_mem_float_const(phi, status), stride, off_h, off_v, oskar_mem_float2(vec, status), oskar_mem_float2(vec, status)); else if (type == OSKAR_DOUBLE) convert_ludwig3_to_theta_phi_double( num_points, oskar_mem_double_const(phi, status), stride, off_h, off_v, oskar_mem_double2(vec, status), oskar_mem_double2(vec, status)); else *status = OSKAR_ERR_BAD_DATA_TYPE; } else { size_t local_size[] = {256, 1, 1}, global_size[] = {1, 1, 1}; const char* k = 0; if (type == OSKAR_SINGLE) k = "convert_ludwig3_to_theta_phi_float"; else if (type == OSKAR_DOUBLE) k = "convert_ludwig3_to_theta_phi_double"; else { *status = OSKAR_ERR_BAD_DATA_TYPE; return; } oskar_device_check_local_size(location, 0, local_size); global_size[0] = oskar_device_global_size( (size_t) num_points, local_size[0]); const oskar_Arg args[] = { {INT_SZ, &num_points}, {PTR_SZ, oskar_mem_buffer_const(phi)}, {INT_SZ, &stride}, {INT_SZ, &off_h}, {INT_SZ, &off_v}, {PTR_SZ, oskar_mem_buffer(vec)}, {PTR_SZ, oskar_mem_buffer(vec)} }; oskar_device_launch_kernel(k, location, 1, local_size, global_size, sizeof(args) / sizeof(oskar_Arg), args, 0, 0, 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]; } }