DORIS

Struct DORIS 

Source
pub struct DORIS {
    pub header: Header,
    pub record: Record,
    pub production: Option<ProductionAttributes>,
}
Expand description

DORIS is composed of a Header and a Record section.

use std::str::FromStr;
use doris_rs::prelude::*;

let doris = DORIS::from_gzip_file("data/DOR/V3/cs2rx18164.gz")
    .unwrap();

assert_eq!(doris.header.satellite, "CRYOSAT-2");

let agency = "CNES".to_string(); // Agency / producer
let program = "Expert".to_string(); // Software name
let run_by = "CNES".to_string(); // Operator
let date = "20180614 090016 UTC".to_string(); // Date of production
let observer = "SPA_BN1_4.7P1".to_string(); // Operator

assert_eq!(doris.header.program, Some(program));
assert_eq!(doris.header.run_by, Some(run_by));
assert_eq!(doris.header.date, Some(date)); // currently not interpreted
assert_eq!(doris.header.observer, Some(observer));
assert_eq!(doris.header.agency, Some(agency));

assert!(doris.header.doi.is_none());
assert!(doris.header.license.is_none());

let observables = vec![
   Observable::UnambiguousPhaseRange(Frequency::DORIS1), // phase, in meters of prop.
   Observable::UnambiguousPhaseRange(Frequency::DORIS2),
   Observable::PseudoRange(Frequency::DORIS1), // decoded pseudo range
   Observable::PseudoRange(Frequency::DORIS2),
   Observable::Power(Frequency::DORIS1), // received power
   Observable::Power(Frequency::DORIS2), // received power
   Observable::FrequencyRatio,           // f1/f2 ratio (=drift image)
   Observable::Pressure,                 // pressure, at ground station level (hPa)
   Observable::Temperature,              // temperature, at ground station level (°C)
   Observable::HumidityRate,             // saturation rate, at ground station level (%)
];

assert_eq!(doris.header.observables, observables);

assert_eq!(doris.header.ground_stations.len(), 53); // network

// Stations helper
let site_matcher = Matcher::Site("TOULOUSE");

let toulouse = GroundStation::default()
    .with_domes(DOMES::from_str("10003S005").unwrap())
    .with_site_name("TOULOUSE") // site name
    .with_site_label("TLSB")    // site label/mnemonic
    .with_unique_id(13)         // file dependent
    .with_frequency_shift(0)    // f1/f2 site shift for this day
    .with_beacon_revision(3);   // DORIS 3rd generation

// helper
assert_eq!(doris.ground_station(site_matcher), Some(toulouse));

Fields§

§header: Header

Header gives general information

§record: Record

Record gives the actual file content

§production: Option<ProductionAttributes>

ProductionAttributes is attached to files that were named according to the standard conventions.

Implementations§

Source§

impl DORIS

Source

pub fn new(header: Header, record: Record) -> DORIS

Builds a new DORIS struct from given Header and Record sections.

Source

pub fn with_header(&self, header: Header) -> Self

Copy and return this DORIS with updated Header.

Source

pub fn replace_header(&mut self, header: Header)

Replace Header with mutable access.

Source

pub fn with_record(&self, record: Record) -> Self

Copies and returns a DORIS with updated Record

Source

pub fn replace_record(&mut self, record: Record)

Replace Record with mutable access.

Source

pub fn parse<R: Read>(reader: &mut BufReader<R>) -> Result<Self, ParsingError>

Parse DORIS content by consuming BufReader (efficient buffered reader).

Source

pub fn format<W: Write>( &self, writer: &mut BufWriter<W>, ) -> Result<(), FormattingError>

Format DORIS into writable I/O using efficient buffered writer and following standard specifications. This is the mirror operation of Self::parse.

Source

pub fn from_file<P: AsRef<Path>>(path: P) -> Result<DORIS, ParsingError>

Parses DORIS from local readable file.

Source

pub fn to_file<P: AsRef<Path>>(&self, path: P) -> Result<(), FormattingError>

Dumps DORIS into writable local file (as readable ASCII UTF-8) using efficient buffered formatting. This is the mirror operation of Self::from_file.

use doris_rs::prelude::*;

let doris = DORIS::from_gzip_file("data/DOR/V3/cs2rx18164.gz")
    .unwrap();

doris.to_file("demo.txt")
    .unwrap();

let parsed = DORIS::from_file("demo.txt")
    .unwrap();

assert_eq!(parsed.header.satellite, "CRYOSAT-2");
assert_eq!(parsed.header.ground_stations.len(), 53); // Network
Source

pub fn from_gzip_file<P: AsRef<Path>>(path: P) -> Result<DORIS, ParsingError>

Available on crate feature flate2 only.

Parses DORIS from local gzip compressed file.

use std::str::FromStr;
use doris_rs::prelude::*;

let doris = DORIS::from_gzip_file("data/DOR/V3/cs2rx18164.gz")
    .unwrap();

assert_eq!(doris.header.satellite, "CRYOSAT-2");

let agency = "CNES".to_string(); // Agency / producer
let program = "Expert".to_string(); // Software name
let run_by = "CNES".to_string(); // Operator
let date = "20180614 090016 UTC".to_string(); // Date of production
let observer = "SPA_BN1_4.7P1".to_string(); // Operator

assert_eq!(doris.header.program, Some(program));
assert_eq!(doris.header.run_by, Some(run_by));
assert_eq!(doris.header.date, Some(date)); // currently not interpreted
assert_eq!(doris.header.observer, Some(observer));
assert_eq!(doris.header.agency, Some(agency));

assert!(doris.header.doi.is_none());
assert!(doris.header.license.is_none());

let observables = vec![
   Observable::UnambiguousPhaseRange(Frequency::DORIS1), // phase, in meters of prop.
   Observable::UnambiguousPhaseRange(Frequency::DORIS2),
   Observable::PseudoRange(Frequency::DORIS1), // decoded pseudo range
   Observable::PseudoRange(Frequency::DORIS2),
   Observable::Power(Frequency::DORIS1), // received power
   Observable::Power(Frequency::DORIS2), // received power
   Observable::FrequencyRatio,           // f1/f2 ratio (=drift image)
   Observable::Pressure,                 // pressure, at ground station level (hPa)
   Observable::Temperature,              // temperature, at ground station level (°C)
   Observable::HumidityRate,             // saturation rate, at ground station level (%)
];

assert_eq!(doris.header.observables, observables);

assert_eq!(doris.header.ground_stations.len(), 53); // network

// Stations helper
let site_matcher = Matcher::Site("TOULOUSE");

let toulouse = GroundStation::default()
    .with_domes(DOMES::from_str("10003S005").unwrap())
    .with_site_name("TOULOUSE") // site name
    .with_site_label("TLSB")    // site label/mnemonic
    .with_unique_id(13)         // file dependent
    .with_frequency_shift(0)    // f1/f2 site shift for this day
    .with_beacon_revision(3);   // DORIS 3rd generation

// helper
assert_eq!(doris.ground_station(site_matcher), Some(toulouse));
Source

pub fn to_gzip_file<P: AsRef<Path>>( &self, path: P, ) -> Result<(), FormattingError>

Available on crate feature flate2 only.

Dumps and gzip encodes DORIS into writable local file, using efficient buffered formatting. This is the mirror operation of Self::from_gzip_file.

use doris_rs::prelude::*;

let doris = DORIS::from_gzip_file("data/DOR/V3/cs2rx18164.gz")
    .unwrap();

doris.to_gzip_file("demo.gz")
    .unwrap();

let parsed = DORIS::from_gzip_file("demo.gz")
    .unwrap();

assert_eq!(parsed.header.satellite, "CRYOSAT-2");
assert_eq!(parsed.header.ground_stations.len(), 53); // Network
Source

pub fn is_merged(&self) -> bool

Determines whether this structure results of combining several structures into a single one. This is determined by the presence of a custom yet somewhat standardized Header comment.

Source

pub fn ground_station<'a>(&self, matcher: Matcher<'a>) -> Option<GroundStation>

Returns GroundStation information for matching site

Source

pub fn satellite_clock_offset_iter( &self, ) -> Box<dyn Iterator<Item = (Epoch, ClockOffset)> + '_>

Returns measurement satellite ClockOffset Iterator for all Epochs, in chronological order

use doris_rs::prelude::*;

let doris = DORIS::from_gzip_file("data/DOR/V3/cs2rx18164.gz")
    .unwrap();

assert_eq!(doris.header.satellite, "CRYOSAT-2");

for (i, (epoch, clock_offset)) in doris.satellite_clock_offset_iter().enumerate() {

    assert_eq!(clock_offset.extrapolated, false); // actual measurement

    if i == 0 {
        assert_eq!(clock_offset.offset.to_seconds(), -4.326631626);
    } else if i == 10 {
        assert_eq!(clock_offset.offset.to_seconds(), -4.326631711);
    }
}
Source

pub fn sampling_histogram( &self, ) -> Box<dyn Iterator<Item = (Duration, usize)> + '_>

Returns histogram analysis of the sampling period, as (Duration, population usize) tuple.

use doris_rs::prelude::*;
use itertools::Itertools;

let doris = DORIS::from_gzip_file("data/DOR/V3/cs2rx18164.gz")
    .unwrap();

// requires more than 2 measurements
let (sampling_period, population) = doris.sampling_histogram()
    .sorted()
    .nth(0) // dominant
    .unwrap();

assert_eq!(sampling_period, Duration::from_seconds(3.0));
Source

pub fn dominant_sampling_period(&self) -> Option<Duration>

Studies actual measurement rate and returns the highest value in the histogram as the dominant sampling rate

use doris_rs::prelude::*;
use itertools::Itertools;

let doris = DORIS::from_gzip_file("data/DOR/V3/cs2rx18164.gz")
    .unwrap();

// requires more than 2 measurements
let sampling_period = doris.dominant_sampling_period()
    .unwrap();

assert_eq!(sampling_period, Duration::from_seconds(3.0));
Source

pub fn standard_filename(&self) -> String

Generates (guesses) a standardized (uppercase) filename from this actual DORIS data set. This is particularly useful when initiated from a file that did not follow standard naming conventions.

use doris_rs::prelude::*;

// parse standard file
let doris = DORIS::from_gzip_file("data/DOR/V3/cs2rx18164.gz")
    .unwrap();

assert_eq!(doris.standard_filename(), "CS2RX18164.gz");

// Dump using random name
doris.to_file("example.txt")
    .unwrap();

// parse back & use
let parsed = DORIS::from_file("example.txt")
    .unwrap();

assert_eq!(parsed.header.satellite, "CRYOSAT-2");

// when coming from non standard names,
// all fields are deduced from actual content.
assert_eq!(parsed.standard_filename(), "CRYOS18164");
Source

pub fn substract(&self, rhs: &Self) -> Self

Copies and returns new DORIS that is the result of ground station observation differentiation. See [Self::observations_substract_mut] for more information.

use doris_rs::prelude::*;

let parsed = DORIS::from_gzip_file("data/DOR/V3/cs2rx18164.gz")
    .unwrap();

// basic example, this will produce a NULL DORIS.
// Standard use case is to use a synchronous observation of the
// same network.
let residuals = parsed.substract(&parsed);

// dump
residuals.to_file("residuals.txt")
    .unwrap();
Source

pub fn substract_mut(&mut self, rhs: &Self)

Substract (in place) this DORIS file to another, creating a “residual” DORIS file. All synchronous measurements of matching stations are substracted to one another. Satellite clock offset is preserved. All other stations observations (non-synchronous, no remote counter part) are dropped: you are left with residual content only after this operation.

Trait Implementations§

Source§

impl Clone for DORIS

Source§

fn clone(&self) -> DORIS

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for DORIS

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for DORIS

Source§

fn default() -> DORIS

Returns the “default value” for a type. Read more
Source§

impl PartialEq for DORIS

Source§

fn eq(&self, other: &DORIS) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl StructuralPartialEq for DORIS

Auto Trait Implementations§

§

impl Freeze for DORIS

§

impl RefUnwindSafe for DORIS

§

impl Send for DORIS

§

impl Sync for DORIS

§

impl Unpin for DORIS

§

impl UnwindSafe for DORIS

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.