Skip to content

Commit

Permalink
Added helper function get_fine_chan_freqs_hz_array to correlator cont…
Browse files Browse the repository at this point in the history
…ext and voltage context
  • Loading branch information
gsleap committed Aug 2, 2021
1 parent f0e2224 commit 405dc04
Show file tree
Hide file tree
Showing 7 changed files with 759 additions and 3 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
Changes in each release are listed below.

## 0.8.5 02-Aug-2021 (Pre-release)
* Added helper function get_fine_chan_freqs_hz_array to correlator context and voltage context.
* Added metafits_context.num_metafits_fine_chan_freqs & metafits_context.metafits_fine_chan_freqs, providing a vector of sky frequencies for all fine channels.
* Added metafits_context.volt_fine_chan_width_hz & metafits_context.num_volt_fine_chans_per_coarse to describe the voltage fine channel configuration.
* Added the above new attributes to equivalent metafits_context struct in FFI.
* Added the above new functions and attributes to equivalent structs in FFI.
* Added more badges to github README.

## 0.8.4 15-Jul-2021 (Pre-release)
Expand Down
27 changes: 27 additions & 0 deletions src/correlator_context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,33 @@ impl CorrelatorContext {
})
}

/// For a given slice of correlator coarse channel indices, return a vector of the center
/// frequencies for all the fine channels in the given coarse channels
///
/// # Arguments
///
/// * `corr_coarse_chan_indices` - a slice containing correlator coarse channel indices
/// for which you want fine channels for. Does not need to be
/// contiguous.
///
///
/// # Returns
///
/// * a vector of f64 containing the centre sky frequencies of all the fine channels for the
/// given coarse channels.
///
pub fn get_fine_chan_freqs_hz_array(&self, corr_coarse_chan_indices: &[usize]) -> Vec<f64> {
CoarseChannel::get_fine_chan_centres_array_hz(
self.mwa_version,
&corr_coarse_chan_indices
.iter()
.map(|c| self.coarse_chans[*c].clone())
.collect::<Vec<CoarseChannel>>(),
self.metafits_context.corr_fine_chan_width_hz,
self.metafits_context.num_corr_fine_chans_per_coarse,
)
}

/// Read a single timestep for a single coarse channel
/// The output visibilities are in order:
/// baseline,frequency,pol,r,i
Expand Down
65 changes: 65 additions & 0 deletions src/correlator_context/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1055,3 +1055,68 @@ fn test_get_fits_filename_and_batch_and_hdu() {
error
);
}

#[test]
fn test_context_legacy_v1_get_fine_chan_feqs_one_coarse_chan() {
// Open the test legacy file
let metafits_filename = "test_files/1101503312_1_timestep/1101503312.metafits";
let filename = "test_files/1101503312_1_timestep/1101503312_20141201210818_gpubox01_00.fits";

//
// Read the observation using mwalib
//
// Open a context and load in a test metafits and gpubox file
let gpuboxfiles = vec![filename];
let context = CorrelatorContext::new(&metafits_filename, &gpuboxfiles)
.expect("Failed to create mwalibContext");

// Get fine channel freqs
let coarse_channels: Vec<usize> = vec![0];
let fine_chan_freqs: Vec<f64> = context.get_fine_chan_freqs_hz_array(&coarse_channels);

assert_eq!(fine_chan_freqs.len(), 128);
assert!(approx_eq!(
f64,
fine_chan_freqs[0],
138_880_000.0,
F64Margin::default()
));
}

#[test]
fn test_context_legacy_v1_get_fine_chan_feqs_some_coarse_chans() {
// Open the test legacy file
let metafits_filename = "test_files/1101503312_1_timestep/1101503312.metafits";
let filename = "test_files/1101503312_1_timestep/1101503312_20141201210818_gpubox01_00.fits";

//
// Read the observation using mwalib
//
// Open a context and load in a test metafits and gpubox file
let gpuboxfiles = vec![filename];
let context = CorrelatorContext::new(&metafits_filename, &gpuboxfiles)
.expect("Failed to create mwalibContext");

// Get fine channel freqs
let coarse_channels: Vec<usize> = vec![10, 20];
let fine_chan_freqs: Vec<f64> = context.get_fine_chan_freqs_hz_array(&coarse_channels);

assert_eq!(fine_chan_freqs.len(), 256);
assert!(approx_eq!(
f64,
fine_chan_freqs[0],
151_680_000.0,
F64Margin::default()
));

assert!(
approx_eq!(
f64,
fine_chan_freqs[128],
164_480_000.0,
F64Margin::default()
),
"calc value: {}",
fine_chan_freqs[128]
);
}
202 changes: 201 additions & 1 deletion src/ffi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ This module exists purely for other languages to interface with mwalib.

use crate::*;
use gpubox_files::GpuboxError;
use libc::{c_char, c_float, c_uchar, c_uint, c_ulong, size_t};
use libc::{c_char, c_double, c_float, c_uchar, c_uint, c_ulong, size_t};
use std::ffi::*;
use std::mem;
use std::slice;
Expand Down Expand Up @@ -602,6 +602,206 @@ pub unsafe extern "C" fn mwalib_correlator_context_read_by_frequency(
}
}

/// For a given slice of correlator coarse channel indices, return a vector of the center
/// frequencies for all the fine channels in the given coarse channels
///
/// # Arguments
///
/// * `correlator_context_ptr` - pointer to an already populated `CorrelatorContext` object.
///
/// * `corr_coarse_chan_indices_array_ptr` - a pointer to an array containing correlator coarse channel indices
/// for which you want fine channels for. Does not need to be
/// contiguous.
///
/// * `corr_coarse_chan_indices_array_len` - length of `corr_coarse_chan_indices_array_ptr`.
///
/// * `out_fine_chan_freq_array_ptr` - pointer to caller-owned and allocated array of doubles to write frequencies into.
///
/// * `out_fine_chan_freq_array_len` - length of `out_fine_chan_freq_array_ptr`.
///
/// * `error_message` - pointer to already allocated buffer for any error messages to be returned to the caller.
///
/// * `error_message_length` - length of error_message char* buffer.
///
///
/// # Safety
/// * `error_message` *must* point to an already allocated char* buffer for any error messages.
/// * `correlator_context_ptr` must point to a populated object from the `mwalib_correlator_context_new` function.
/// * Caller *must* call `mwalib_correlator_context_free_read_buffer` function to release the rust memory.
#[no_mangle]
pub unsafe extern "C" fn mwalib_correlator_context_get_fine_chan_freqs_hz_array(
correlator_context_ptr: *mut CorrelatorContext,
corr_coarse_chan_indices_array_ptr: *mut size_t,
corr_coarse_chan_indices_array_len: size_t,
out_fine_chan_freq_array_ptr: *mut c_double,
out_fine_chan_freq_array_len: size_t,
error_message: *const c_char,
error_message_length: size_t,
) -> i32 {
// Load the previously-initialised context and buffer structs. Exit if
// either of these are null.
let corr_context = if correlator_context_ptr.is_null() {
set_error_message(
"mwalib_correlator_context_get_fine_chan_freqs_hz_array() ERROR: null pointer for correlator_context_ptr passed in",
error_message as *mut u8,
error_message_length,
);
return MWALIB_FAILURE;
} else {
&mut *correlator_context_ptr
};

// Don't do anything if the input pointer is null.
if corr_coarse_chan_indices_array_ptr.is_null() {
set_error_message(
"mwalib_correlator_context_get_fine_chan_freqs_hz_array() ERROR: null pointer for corr_coarse_chan_indices_array_ptr passed in",
error_message as *mut u8,
error_message_length,
);
return MWALIB_FAILURE;
}

// Get input buffer ready to be passed into rust method
let input_coarse_chan_indices = slice::from_raw_parts_mut(
corr_coarse_chan_indices_array_ptr,
corr_coarse_chan_indices_array_len,
);

// Don't do anything if the buffer pointer is null.
if out_fine_chan_freq_array_ptr.is_null() {
set_error_message(
"mwalib_correlator_context_get_fine_chan_freqs_hz_array() ERROR: null pointer for out_fine_chan_freq_array_ptr passed in",
error_message as *mut u8,
error_message_length,
);
return MWALIB_FAILURE;
}

// Get output buffer ready
let output_slice =
slice::from_raw_parts_mut(out_fine_chan_freq_array_ptr, out_fine_chan_freq_array_len);

// Sanity check the length
let expected_output_len = corr_coarse_chan_indices_array_len
* corr_context.metafits_context.num_corr_fine_chans_per_coarse;
if output_slice.len() != expected_output_len {
set_error_message(
&format!("mwalib_correlator_context_get_fine_chan_freqs_hz_array() ERROR: number of elements in out_fine_chan_freq_array_ptr does not match expected value {}", expected_output_len),
error_message as *mut u8,
error_message_length,
);
return MWALIB_FAILURE;
}

// Read data into provided buffer
let fine_chans = corr_context.get_fine_chan_freqs_hz_array(input_coarse_chan_indices);

// Write the fine chans back into the provided array
output_slice.clone_from_slice(&fine_chans);

MWALIB_SUCCESS
}

/// For a given slice of voltage coarse channel indices, return a vector of the center
/// frequencies for all the fine channels in the given coarse channels
///
/// # Arguments
///
/// * `voltage_context_ptr` - pointer to an already populated `VoltageContext` object.
///
/// * `corr_coarse_chan_indices_array_ptr` - a pointer to an array containing correlator coarse channel indices
/// for which you want fine channels for. Does not need to be
/// contiguous.
///
/// * `corr_coarse_chan_indices_array_len` - length of `corr_coarse_chan_indices_array_ptr`.
///
/// * `out_fine_chan_freq_array_ptr` - pointer to caller-owned and allocated array of doubles to write frequencies into.
///
/// * `out_fine_chan_freq_array_len` - length of `out_fine_chan_freq_array_ptr`.
///
/// * `error_message` - pointer to already allocated buffer for any error messages to be returned to the caller.
///
/// * `error_message_length` - length of error_message char* buffer.
///
///
/// # Safety
/// * `error_message` *must* point to an already allocated char* buffer for any error messages.
/// * `correlator_context_ptr` must point to a populated object from the `mwalib_correlator_context_new` function.
/// * Caller *must* call `mwalib_correlator_context_free_read_buffer` function to release the rust memory.
#[no_mangle]
pub unsafe extern "C" fn mwalib_voltage_context_get_fine_chan_freqs_hz_array(
voltage_context_ptr: *mut VoltageContext,
volt_coarse_chan_indices_array_ptr: *mut size_t,
volt_coarse_chan_indices_array_len: size_t,
out_fine_chan_freq_array_ptr: *mut c_double,
out_fine_chan_freq_array_len: size_t,
error_message: *const c_char,
error_message_length: size_t,
) -> i32 {
// Load the previously-initialised context and buffer structs. Exit if
// either of these are null.
let volt_context = if voltage_context_ptr.is_null() {
set_error_message(
"mwalib_voltage_context_get_fine_chan_freqs_hz_array() ERROR: null pointer for voltage_context_ptr passed in",
error_message as *mut u8,
error_message_length,
);
return MWALIB_FAILURE;
} else {
&mut *voltage_context_ptr
};

// Don't do anything if the input pointer is null.
if volt_coarse_chan_indices_array_ptr.is_null() {
set_error_message(
"mwalib_voltage_context_get_fine_chan_freqs_hz_array() ERROR: null pointer for volt_coarse_chan_indices_array_ptr passed in",
error_message as *mut u8,
error_message_length,
);
return MWALIB_FAILURE;
}

// Get input buffer ready to be passed into rust method
let input_coarse_chan_indices = slice::from_raw_parts_mut(
volt_coarse_chan_indices_array_ptr,
volt_coarse_chan_indices_array_len,
);

// Don't do anything if the buffer pointer is null.
if out_fine_chan_freq_array_ptr.is_null() {
set_error_message(
"mwalib_voltage_context_get_fine_chan_freqs_hz_array() ERROR: null pointer for out_fine_chan_freq_array_ptr passed in",
error_message as *mut u8,
error_message_length,
);
return MWALIB_FAILURE;
}

// Get output buffer ready
let output_slice =
slice::from_raw_parts_mut(out_fine_chan_freq_array_ptr, out_fine_chan_freq_array_len);

// Sanity check the length
let expected_output_len = volt_coarse_chan_indices_array_len
* volt_context.metafits_context.num_corr_fine_chans_per_coarse;
if output_slice.len() != expected_output_len {
set_error_message(
&format!("mwalib_voltage_context_get_fine_chan_freqs_hz_array() ERROR: number of elements in out_fine_chan_freq_array_ptr does not match expected value {}", expected_output_len),
error_message as *mut u8,
error_message_length,
);
return MWALIB_FAILURE;
}

// Read data into provided buffer
let fine_chans = volt_context.get_fine_chan_freqs_hz_array(input_coarse_chan_indices);

// Write the fine chans back into the provided array
output_slice.clone_from_slice(&fine_chans);

MWALIB_SUCCESS
}

/// Free a previously-allocated `CorrelatorContext` struct (and it's members).
///
/// # Arguments
Expand Down
Loading

0 comments on commit 405dc04

Please sign in to comment.