use crate::gpubox_files::GpuboxTimeMap;
use crate::misc;
use crate::voltage_files::VoltageFileTimeMap;
use crate::{MWAVersion, MetafitsContext};
use crate::{MWA_VCS_LEGACY_RECOMBINED_FILE_SECONDS, MWA_VCS_MWAXV2_SUBFILE_SECONDS};
use std::fmt;
pub mod ffi;
#[cfg(test)]
mod test;
#[cfg(any(feature = "python", feature = "python-stubgen"))]
use pyo3::prelude::*;
#[cfg(feature = "python-stubgen")]
use pyo3_stub_gen_derive::gen_stub_pyclass;
#[cfg_attr(feature = "python-stubgen", gen_stub_pyclass)]
#[cfg_attr(
any(feature = "python", feature = "python-stubgen"),
pyclass(get_all, set_all, from_py_object)
)]
#[derive(Clone, Debug)]
pub struct TimeStep {
pub unix_time_ms: u64,
pub gps_time_ms: u64,
}
impl TimeStep {
pub(crate) fn new(unix_time_ms: u64, gps_time_ms: u64) -> Self {
TimeStep {
unix_time_ms,
gps_time_ms,
}
}
pub(crate) fn populate_correlator_timesteps(
gpubox_time_map: &GpuboxTimeMap,
metafits_timesteps: &[TimeStep],
scheduled_starttime_gps_ms: u64,
scheduled_starttime_unix_ms: u64,
corr_int_time_ms: u64,
) -> Option<Vec<Self>> {
if gpubox_time_map.is_empty() {
return None;
}
let mut timesteps: Vec<TimeStep> = Vec::new();
for (unix_time_ms, _) in gpubox_time_map.iter() {
let gps_time_ms = misc::convert_unixtime_to_gpstime(
*unix_time_ms,
scheduled_starttime_gps_ms,
scheduled_starttime_unix_ms,
);
timesteps.push(Self::new(*unix_time_ms, gps_time_ms));
}
Some(TimeStep::populate_metafits_provided_superset_of_timesteps(
timesteps,
metafits_timesteps,
scheduled_starttime_gps_ms,
scheduled_starttime_unix_ms,
corr_int_time_ms,
))
}
pub(crate) fn populate_voltage_timesteps(
voltage_time_map: &VoltageFileTimeMap,
metafits_timesteps: &[TimeStep],
scheduled_starttime_gps_ms: u64,
scheduled_starttime_unix_ms: u64,
voltage_timestep_duration_ms: u64,
) -> Option<Vec<Self>> {
if voltage_time_map.is_empty() {
return None;
}
let mut timesteps: Vec<TimeStep> = Vec::new();
for (gps_time_seconds, _) in voltage_time_map.iter() {
let unix_time_ms = misc::convert_gpstime_to_unixtime(
*gps_time_seconds * 1000,
scheduled_starttime_gps_ms,
scheduled_starttime_unix_ms,
);
timesteps.push(Self::new(unix_time_ms, *gps_time_seconds * 1000));
}
Some(TimeStep::populate_metafits_provided_superset_of_timesteps(
timesteps,
metafits_timesteps,
scheduled_starttime_gps_ms,
scheduled_starttime_unix_ms,
voltage_timestep_duration_ms,
))
}
fn populate_metafits_provided_superset_of_timesteps(
provided_timesteps: Vec<TimeStep>,
metafits_timesteps: &[TimeStep],
scheduled_starttime_gps_ms: u64,
scheduled_starttime_unix_ms: u64,
timestep_duration_ms: u64,
) -> Vec<TimeStep> {
let mut timesteps: Vec<TimeStep> = provided_timesteps;
let first_data_timestep_unix_ms: u64 = timesteps[0].unix_time_ms;
let last_data_timestep_unix_ms: u64 = timesteps[timesteps.len() - 1].unix_time_ms;
if first_data_timestep_unix_ms > metafits_timesteps[0].unix_time_ms {
let mut current_timestep_unix_ms: u64 =
first_data_timestep_unix_ms - timestep_duration_ms;
while current_timestep_unix_ms >= metafits_timesteps[0].unix_time_ms {
let gps_time_ms = misc::convert_unixtime_to_gpstime(
current_timestep_unix_ms,
scheduled_starttime_gps_ms,
scheduled_starttime_unix_ms,
);
timesteps.push(Self::new(current_timestep_unix_ms, gps_time_ms));
current_timestep_unix_ms -= timestep_duration_ms;
}
}
if last_data_timestep_unix_ms
< metafits_timesteps[metafits_timesteps.len() - 1].unix_time_ms
{
let mut current_timestep_unix_ms: u64 =
last_data_timestep_unix_ms + timestep_duration_ms;
while current_timestep_unix_ms
<= metafits_timesteps[metafits_timesteps.len() - 1].unix_time_ms
{
let gps_time_ms = misc::convert_unixtime_to_gpstime(
current_timestep_unix_ms,
scheduled_starttime_gps_ms,
scheduled_starttime_unix_ms,
);
timesteps.push(Self::new(current_timestep_unix_ms, gps_time_ms));
current_timestep_unix_ms += timestep_duration_ms;
}
}
timesteps.sort_by_key(|t| t.unix_time_ms);
for timestep_unix_time_ms in (timesteps[0].unix_time_ms
..timesteps[timesteps.len() - 1].unix_time_ms)
.step_by(timestep_duration_ms as usize)
{
if !×teps
.iter()
.any(|t| t.unix_time_ms == timestep_unix_time_ms)
{
let gps_time_ms = misc::convert_unixtime_to_gpstime(
timestep_unix_time_ms,
scheduled_starttime_gps_ms,
scheduled_starttime_unix_ms,
);
timesteps.push(Self::new(timestep_unix_time_ms, gps_time_ms));
}
}
timesteps.sort_by_key(|t| t.unix_time_ms);
timesteps
}
pub(crate) fn populate_timesteps(
metafits_context: &MetafitsContext,
mwa_version: MWAVersion,
start_gps_time_ms: u64,
duration_ms: u64,
scheduled_starttime_gps_ms: u64,
scheduled_starttime_unix_ms: u64,
) -> Vec<Self> {
let mut timesteps_vec: Vec<Self> = vec![];
let interval_ms: u64 = match mwa_version {
MWAVersion::CorrOldLegacy
| MWAVersion::CorrLegacy
| MWAVersion::CorrMWAXv2
| MWAVersion::CorrBeamformerMWAXv2 => metafits_context.corr_int_time_ms,
MWAVersion::VCSLegacyRecombined => MWA_VCS_LEGACY_RECOMBINED_FILE_SECONDS * 1000,
MWAVersion::VCSMWAXv2 => MWA_VCS_MWAXV2_SUBFILE_SECONDS * 1000,
MWAVersion::BeamformerMWAXv2 => {
return timesteps_vec;
}
};
for gps_time in
(start_gps_time_ms..start_gps_time_ms + duration_ms).step_by(interval_ms as usize)
{
let unix_time_ms = misc::convert_gpstime_to_unixtime(
gps_time,
scheduled_starttime_gps_ms,
scheduled_starttime_unix_ms,
);
timesteps_vec.push(Self::new(unix_time_ms, gps_time));
}
timesteps_vec
}
pub(crate) fn get_timstep_indicies(
all_timesteps: &[Self],
start_unix_time_ms: u64,
end_unix_time_ms: u64,
) -> Vec<usize> {
let mut timestep_indices: Vec<usize> = all_timesteps
.iter()
.filter(|f| f.unix_time_ms >= start_unix_time_ms && f.unix_time_ms < end_unix_time_ms)
.map(|t| {
all_timesteps
.iter()
.position(|v| v.unix_time_ms == t.unix_time_ms)
.unwrap()
})
.collect();
timestep_indices.sort_unstable();
timestep_indices
}
}
impl fmt::Display for TimeStep {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"unix={:.3}, gps={:.3}",
self.unix_time_ms as f64 / 1000.,
self.gps_time_ms as f64 / 1000.,
)
}
}