#[cfg(test)]
mod tests;
use std::slice;
use super::{AnalyticBeam, AnalyticType};
use crate::ffi::{ffi_error, update_last_error};
cfg_if::cfg_if! {
if #[cfg(any(feature = "cuda", feature = "hip"))] {
use ndarray::prelude::*;
use super::AnalyticBeamGpu;
use crate::gpu::{DevicePointer, GpuFloat};
}
}
#[no_mangle]
pub unsafe extern "C" fn new_analytic_beam(
rts_style: u8,
dipole_height_metres: *const f64,
bowties_per_row: *const u8,
analytic_beam: *mut *mut AnalyticBeam,
) -> i32 {
let analytic_type = match rts_style {
0 => AnalyticType::MwaPb,
1 => AnalyticType::Rts,
_ => {
update_last_error("A value other than 0 or 1 was used for rts_style".to_string());
return 1;
}
};
let dipole_height_metres = dipole_height_metres.as_ref().copied();
let bowties_per_row = bowties_per_row.as_ref().copied();
let beam = AnalyticBeam::new_custom(
analytic_type,
dipole_height_metres.unwrap_or_else(|| analytic_type.get_default_dipole_height()),
bowties_per_row.unwrap_or(4),
);
*analytic_beam = Box::into_raw(Box::new(beam));
0
}
#[no_mangle]
pub unsafe extern "C" fn analytic_calc_jones(
analytic_beam: *mut AnalyticBeam,
az_rad: f64,
za_rad: f64,
freq_hz: u32,
delays: *const u32,
amps: *const f64,
num_amps: u32,
latitude_rad: f64,
norm_to_zenith: u8,
jones: *mut f64,
) -> i32 {
let norm_bool = match norm_to_zenith {
0 => false,
1 => true,
_ => {
update_last_error("A value other than 0 or 1 was used for norm_to_zenith".to_string());
return 1;
}
};
let beam = &*analytic_beam;
let delays_s = slice::from_raw_parts(delays, usize::from(beam.bowties_per_row).pow(2));
let amps_s = slice::from_raw_parts(amps, num_amps as usize);
match beam.calc_jones_pair(
az_rad,
za_rad,
freq_hz,
delays_s,
amps_s,
latitude_rad,
norm_bool,
) {
Ok(j) => {
let jones_buf = slice::from_raw_parts_mut(jones, 8);
jones_buf[..].copy_from_slice(&[
j[0].re, j[0].im, j[1].re, j[1].im, j[2].re, j[2].im, j[3].re, j[3].im,
]);
0
}
Err(e) => {
update_last_error(e.to_string());
1
}
}
}
#[no_mangle]
pub unsafe extern "C" fn analytic_calc_jones_array(
analytic_beam: *mut AnalyticBeam,
num_azza: u32,
az_rad: *const f64,
za_rad: *const f64,
freq_hz: u32,
delays: *const u32,
amps: *const f64,
num_amps: u32,
latitude_rad: f64,
norm_to_zenith: u8,
jones: *mut f64,
) -> i32 {
let norm_bool = match norm_to_zenith {
0 => false,
1 => true,
_ => {
update_last_error("A value other than 0 or 1 was used for norm_to_zenith".to_string());
return 1;
}
};
let beam = &*analytic_beam;
let az = slice::from_raw_parts(az_rad, num_azza as usize);
let za = slice::from_raw_parts(za_rad, num_azza as usize);
let delays_s = slice::from_raw_parts(delays, usize::from(beam.bowties_per_row).pow(2));
let amps_s = slice::from_raw_parts(amps, num_amps as usize);
let results_s = slice::from_raw_parts_mut(jones.cast(), num_azza as usize);
ffi_error!(beam.calc_jones_array_pair_inner(
az,
za,
freq_hz,
delays_s,
amps_s,
latitude_rad,
norm_bool,
results_s
));
0
}
#[no_mangle]
pub unsafe extern "C" fn free_analytic_beam(analytic_beam: *mut AnalyticBeam) {
drop(Box::from_raw(analytic_beam));
}
#[cfg(any(feature = "cuda", feature = "hip"))]
#[no_mangle]
pub unsafe extern "C" fn new_gpu_analytic_beam(
analytic_beam: *mut AnalyticBeam,
delays: *const u32,
amps: *const f64,
num_tiles: i32,
num_amps: i32,
gpu_analytic_beam: *mut *mut AnalyticBeamGpu,
) -> i32 {
let beam = &mut *analytic_beam;
let amps = ArrayView2::from_shape_ptr((num_tiles as usize, num_amps as usize), amps);
let delays = ArrayView2::from_shape_ptr(
(num_tiles as usize, usize::from(beam.bowties_per_row).pow(2)),
delays,
);
let gpu_beam = ffi_error!(beam.gpu_prepare(delays, amps));
*gpu_analytic_beam = Box::into_raw(Box::new(gpu_beam));
0
}
#[cfg(any(feature = "cuda", feature = "hip"))]
#[no_mangle]
pub unsafe extern "C" fn analytic_calc_jones_gpu(
gpu_analytic_beam: *mut AnalyticBeamGpu,
num_azza: u32,
az_rad: *const GpuFloat,
za_rad: *const GpuFloat,
num_freqs: u32,
freqs_hz: *const u32,
latitude_rad: GpuFloat,
norm_to_zenith: u8,
jones: *mut GpuFloat,
) -> i32 {
let num_azza_usize = match num_azza.try_into() {
Ok(n) => n,
Err(_) => {
update_last_error("num_azza couldn't be converted to a usize".to_string());
return 1;
}
};
let num_freqs_usize = match num_freqs.try_into() {
Ok(n) => n,
Err(_) => {
update_last_error("num_freqs couldn't be converted to a usize".to_string());
return 1;
}
};
let norm_to_zenith = match norm_to_zenith {
0 => false,
1 => true,
_ => {
update_last_error("A value other than 0 or 1 was used for norm_to_zenith".to_string());
return 1;
}
};
let beam = &mut *gpu_analytic_beam;
let az = slice::from_raw_parts(az_rad, num_azza_usize);
let za = slice::from_raw_parts(za_rad, num_azza_usize);
let freqs = slice::from_raw_parts(freqs_hz, num_freqs_usize);
let results = ArrayViewMut3::from_shape_ptr(
(
beam.num_unique_tiles as usize,
num_freqs_usize,
num_azza_usize,
),
jones.cast(),
);
ffi_error!(beam.calc_jones_pair_inner(az, za, freqs, latitude_rad, norm_to_zenith, results));
0
}
#[cfg(any(feature = "cuda", feature = "hip"))]
#[no_mangle]
pub unsafe extern "C" fn analytic_calc_jones_gpu_device(
gpu_analytic_beam: *mut AnalyticBeamGpu,
num_azza: i32,
az_rad: *const GpuFloat,
za_rad: *const GpuFloat,
num_freqs: i32,
freqs_hz: *const u32,
latitude_rad: GpuFloat,
norm_to_zenith: u8,
d_jones: *mut GpuFloat,
) -> i32 {
let num_azza_usize = if num_azza < 0 {
update_last_error("num_azza was less than 0; it must be positive".to_string());
return 1;
} else {
match num_azza.try_into() {
Ok(n) => n,
Err(_) => {
update_last_error("num_azza couldn't be converted to a usize".to_string());
return 1;
}
}
};
let num_freqs_usize = if num_freqs < 0 {
update_last_error("num_freqs was less than 0; it must be positive".to_string());
return 1;
} else {
match num_freqs.try_into() {
Ok(n) => n,
Err(_) => {
update_last_error("num_freqs couldn't be converted to a usize".to_string());
return 1;
}
}
};
let norm_to_zenith = match norm_to_zenith {
0 => false,
1 => true,
_ => {
update_last_error("A value other than 0 or 1 was used for norm_to_zenith".to_string());
return 1;
}
};
let beam = &*gpu_analytic_beam;
let az = slice::from_raw_parts(az_rad, num_azza_usize);
let za = slice::from_raw_parts(za_rad, num_azza_usize);
let freqs = slice::from_raw_parts(freqs_hz, num_freqs_usize);
let d_az = ffi_error!(DevicePointer::copy_to_device(az));
let d_za = ffi_error!(DevicePointer::copy_to_device(za));
let d_freqs = ffi_error!(DevicePointer::copy_to_device(freqs));
ffi_error!(beam.calc_jones_device_pair_inner(
d_az.get(),
d_za.get(),
num_azza,
d_freqs.get(),
num_freqs,
latitude_rad,
norm_to_zenith,
d_jones.cast()
));
0
}
#[cfg(any(feature = "cuda", feature = "hip"))]
#[no_mangle]
pub unsafe extern "C" fn analytic_calc_jones_gpu_device_inner(
gpu_analytic_beam: *mut AnalyticBeamGpu,
num_azza: i32,
d_az_rad: *const GpuFloat,
d_za_rad: *const GpuFloat,
num_freqs: i32,
d_freqs_hz: *const u32,
latitude_rad: GpuFloat,
norm_to_zenith: u8,
d_jones: *mut GpuFloat,
) -> i32 {
if num_azza < 0 {
update_last_error("num_azza was less than 0; it must be positive".to_string());
return 1;
};
if num_freqs < 0 {
update_last_error("num_freqs was less than 0; it must be positive".to_string());
return 1;
};
let norm_to_zenith = match norm_to_zenith {
0 => false,
1 => true,
_ => {
update_last_error("A value other than 0 or 1 was used for norm_to_zenith".to_string());
return 1;
}
};
let beam = &*gpu_analytic_beam;
ffi_error!(beam.calc_jones_device_pair_inner(
d_az_rad,
d_za_rad,
num_azza,
d_freqs_hz,
num_freqs,
latitude_rad,
norm_to_zenith,
d_jones.cast()
));
0
}
#[cfg(any(feature = "cuda", feature = "hip"))]
#[no_mangle]
pub unsafe extern "C" fn get_analytic_tile_map(
gpu_analytic_beam: *mut AnalyticBeamGpu,
) -> *const i32 {
let beam = &*gpu_analytic_beam;
beam.get_tile_map()
}
#[cfg(any(feature = "cuda", feature = "hip"))]
#[no_mangle]
pub unsafe extern "C" fn get_analytic_device_tile_map(
gpu_analytic_beam: *mut AnalyticBeamGpu,
) -> *const i32 {
let beam = &*gpu_analytic_beam;
beam.get_device_tile_map()
}
#[cfg(any(feature = "cuda", feature = "hip"))]
#[no_mangle]
pub unsafe extern "C" fn get_num_unique_analytic_tiles(
gpu_analytic_beam: *mut AnalyticBeamGpu,
) -> i32 {
let beam = &*gpu_analytic_beam;
beam.num_unique_tiles
}
#[cfg(any(feature = "cuda", feature = "hip"))]
#[no_mangle]
pub unsafe extern "C" fn free_gpu_analytic_beam(analytic_beam: *mut AnalyticBeamGpu) {
drop(Box::from_raw(analytic_beam));
}