Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Context improvements #209

Merged
merged 18 commits into from
Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 16 additions & 16 deletions rinex-cli/src/analysis/sampling.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
use crate::graph::PlotContext;
use itertools::Itertools;
use plotly::Histogram; //.sorted()
use rinex::prelude::RnxContext;
use plotly::Histogram;
use rinex::prelude::{ProductType, RnxContext};

/*
* Sampling histogram
*/
pub fn histogram(ctx: &RnxContext, plot_ctx: &mut PlotContext) {
plot_ctx.add_timedomain_plot("Sampling Histogram", "Count");
if let Some(data) = ctx.obs_data() {
let histogram = data.sampling_histogram().sorted();
let durations: Vec<_> = histogram.clone().map(|(dt, _)| dt.to_string()).collect();
let populations: Vec<_> = histogram.clone().map(|(_, pop)| pop.to_string()).collect();
let histogram = Histogram::new_xy(durations, populations).name("Sampling Histogram");
plot_ctx.add_trace(histogram);
}
// Run similar analysis on NAV context
if let Some(data) = &ctx.nav_data() {
let histogram = data.sampling_histogram().sorted();
let durations: Vec<_> = histogram.clone().map(|(dt, _)| dt.to_string()).collect();
let populations: Vec<_> = histogram.clone().map(|(_, pop)| pop.to_string()).collect();
let histogram = Histogram::new_xy(durations, populations).name("(NAV) Sampling Histogram");
plot_ctx.add_trace(histogram);
for product in [
ProductType::Observation,
ProductType::MeteoObservation,
ProductType::BroadcastNavigation,
ProductType::HighPrecisionClock,
ProductType::Ionex,
] {
if let Some(data) = ctx.rinex(product) {
let histogram = data.sampling_histogram().sorted();
let durations: Vec<_> = histogram.clone().map(|(dt, _)| dt.to_string()).collect();
let populations: Vec<_> = histogram.clone().map(|(_, pop)| pop.to_string()).collect();
let histogram = Histogram::new_xy(durations, populations).name(&format!("{}", product));
plot_ctx.add_trace(histogram);
}
}
}
109 changes: 7 additions & 102 deletions rinex-cli/src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ use std::{
};

use clap::{value_parser, Arg, ArgAction, ArgMatches, ColorChoice, Command};
use map_3d::{ecef2geodetic, geodetic2ecef, rad2deg, Ellipsoid};
use rinex::prelude::*;
use walkdir::WalkDir;

use crate::{fops::open_with_web_browser, Error};

use map_3d::{geodetic2ecef, Ellipsoid};

// identification mode
mod identify;
// graph mode
Expand Down Expand Up @@ -54,6 +54,9 @@ pub struct Context {
/// $WORKSPACE is either manually definedd by CLI or we create it (as is).
/// $PRIMARYFILE is determined from the most major file contained in the dataset.
pub workspace: PathBuf,
/// Context name is derived from the primary file loaded in Self,
/// and mostly used in session products generation.
pub name: String,
/// (RX) reference position to be used in further analysis.
/// It is either (priority order is important)
/// 1. manually defined by CLI
Expand All @@ -68,7 +71,7 @@ impl Context {
*/
pub fn context_stem(data: &RnxContext) -> String {
let ctx_major_stem: &str = data
.rinex_path()
.primary_path()
.expect("failed to determine a context name")
.file_stem()
.expect("failed to determine a context name")
Expand Down Expand Up @@ -111,104 +114,6 @@ impl Context {
open_with_web_browser(path.to_string_lossy().as_ref());
}
}
/*
* Creates File/Data context defined by user.
* Regroups all provided files/folders,
*/
pub fn from_cli(cli: &Cli) -> Result<Self, Error> {
let mut data = RnxContext::default();
let max_depth = match cli.matches.get_one::<u8>("depth") {
Some(value) => *value as usize,
None => 5usize,
};

/* load all directories recursively, one by one */
for dir in cli.input_directories() {
let walkdir = WalkDir::new(dir).max_depth(max_depth);
for entry in walkdir.into_iter().filter_map(|e| e.ok()) {
if !entry.path().is_dir() {
let path = entry.path();
let ret = data.load(&path.to_path_buf());
if ret.is_err() {
warn!(
"failed to load \"{}\": {}",
path.display(),
ret.err().unwrap()
);
}
}
}
}
// load individual files, if any
for filepath in cli.input_files() {
let ret = data.load(&Path::new(filepath).to_path_buf());
if ret.is_err() {
warn!("failed to load \"{}\": {}", filepath, ret.err().unwrap());
}
}
let data_stem = Self::context_stem(&data);
let data_position = data.ground_position();
Ok(Self {
data,
quiet: cli.matches.get_flag("quiet"),
workspace: {
let path = match std::env::var("RINEX_WORKSPACE") {
Ok(path) => Path::new(&path).join(data_stem).to_path_buf(),
_ => match cli.matches.get_one::<PathBuf>("workspace") {
Some(base_dir) => Path::new(base_dir).join(data_stem).to_path_buf(),
None => Path::new("WORKSPACE").join(data_stem).to_path_buf(),
},
};
// make sure the workspace is viable and exists, otherwise panic
create_dir_all(&path).unwrap_or_else(|e| {
panic!(
"failed to create session workspace \"{}\": {:?}",
path.display(),
e
)
});
info!("session workspace is \"{}\"", path.to_string_lossy());
path
},
rx_ecef: {
match cli.manual_position() {
Some((x, y, z)) => {
let (mut lat, mut lon, _) = ecef2geodetic(x, y, z, Ellipsoid::WGS84);
lat = rad2deg(lat);
lon = rad2deg(lon);
info!(
"using manually defined position: {:?} [ECEF] (lat={:.5}°, lon={:.5}°",
(x, y, z),
lat,
lon
);
Some((x, y, z))
},
None => {
if let Some(data_pos) = data_position {
let (x, y, z) = data_pos.to_ecef_wgs84();
let (mut lat, mut lon, _) = ecef2geodetic(x, y, z, Ellipsoid::WGS84);
lat = rad2deg(lat);
lon = rad2deg(lon);
info!(
"position defined in dataset: {:?} [ECEF] (lat={:.5}°, lon={:.5}°",
(x, y, z),
lat,
lon
);
Some((x, y, z))
} else {
// this is not a problem in basic opmodes,
// but will most likely prevail advanced opmodes.
// Let the user know.
warn!("no RX position defined");
None
}
},
}
},
})
}
}

impl Cli {
Expand All @@ -219,7 +124,7 @@ impl Cli {
Command::new("rinex-cli")
.author("Guillaume W. Bres, <[email protected]>")
.version(env!("CARGO_PKG_VERSION"))
.about("RINEX post processing (command line)")
.about("RINEX post processing")
.arg_required_else_help(true)
.color(ColorChoice::Always)
.arg(Arg::new("filepath")
Expand Down
2 changes: 1 addition & 1 deletion rinex-cli/src/cli/split.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub fn subcommand() -> Command {
.short_flag('s')
.long_flag("split")
.arg_required_else_help(true)
.about("Split input files at specified Epoch.")
.about("Split input file(s) at specified Epoch")
.arg(
Arg::new("split")
.value_parser(value_parser!(Epoch))
Expand Down
Loading
Loading