Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit c7cd9af

Browse files
committedFeb 5, 2025
Change f32 to f64
1 parent 138b27f commit c7cd9af

17 files changed

+126
-126
lines changed
 

‎src/checks/consistency/greater_than.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::{ConsistencyCache, Error, Flag, Timeseries, TimeseriesPair};
77
/// - [`Flag::DataMissing`] if either datum is missing,
88
/// - [`Flag::Fail`] if datum1 + datum1_correction > datum2,
99
/// - [`Flag::Pass`] otherwise.
10-
pub fn greater_than(datum1: Option<f32>, datum2: Option<f32>, datum1_correction: f32) -> Flag {
10+
pub fn greater_than(datum1: Option<f64>, datum2: Option<f64>, datum1_correction: f64) -> Flag {
1111
if datum1.is_none() || datum2.is_none() {
1212
return Flag::DataMissing;
1313
}
@@ -29,7 +29,7 @@ pub fn greater_than(datum1: Option<f32>, datum2: Option<f32>, datum1_correction:
2929
/// - `cache.ratio` is not 1
3030
pub fn greater_than_cache(
3131
cache: &ConsistencyCache,
32-
correction: f32,
32+
correction: f64,
3333
) -> Result<Vec<TimeseriesPair<Flag>>, Error> {
3434
if cache.ratio != 1 {
3535
return Err(Error::InvalidInputShape(String::from(

‎src/checks/consistency/not_equal.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::{ConsistencyCache, Error, Flag, Timeseries, TimeseriesPair};
1010
/// - [`Flag::DataMissing`] if either datum is missing,
1111
/// - [`Flag::Fail`] if the difference between datum1 and datum2 is greater than threshold,
1212
/// - [`Flag::Pass`] otherwise.
13-
pub fn not_equal(datum1: Option<f32>, datum2: Option<f32>, threshold: f32) -> Flag {
13+
pub fn not_equal(datum1: Option<f64>, datum2: Option<f64>, threshold: f64) -> Flag {
1414
if datum1.is_none() || datum2.is_none() {
1515
return Flag::DataMissing;
1616
}
@@ -31,7 +31,7 @@ pub fn not_equal(datum1: Option<f32>, datum2: Option<f32>, threshold: f32) -> Fl
3131
/// - `cache.ratio` is not 1
3232
pub fn not_equal_cache(
3333
cache: &ConsistencyCache,
34-
threshold: f32,
34+
threshold: f64,
3535
) -> Result<Vec<TimeseriesPair<Flag>>, Error> {
3636
if cache.ratio != 1 {
3737
return Err(Error::InvalidInputShape(String::from(

‎src/checks/consistency/single_greater_than_any.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ use crate::{ConsistencyCache, Flag, Timeseries, TimeseriesPair};
1818
/// plus the adjustment),
1919
/// - [`Flag::Pass`] otherwise.
2020
pub fn single_greater_than_any(
21-
single: Option<f32>,
22-
sequence: &[Option<f32>],
23-
adjustment: f32,
21+
single: Option<f64>,
22+
sequence: &[Option<f64>],
23+
adjustment: f64,
2424
) -> (Flag, Vec<Flag>) {
2525
let single = match single {
2626
Some(value) => value,
@@ -67,7 +67,7 @@ pub fn single_greater_than_any(
6767
/// - `cache.ratio` is 0
6868
pub fn single_greater_than_any_cache(
6969
cache: &ConsistencyCache,
70-
adjustment: f32,
70+
adjustment: f64,
7171
) -> Vec<TimeseriesPair<Flag>> {
7272
let num_series = cache.data.len();
7373
let mut result_vec = Vec::with_capacity(num_series);

‎src/checks/consistency/single_less_than_any.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ use crate::{ConsistencyCache, Flag, Timeseries, TimeseriesPair};
1818
/// plus the adjustment),
1919
/// - [`Flag::Pass`] otherwise.
2020
pub fn single_less_than_any(
21-
single: Option<f32>,
22-
sequence: &[Option<f32>],
23-
adjustment: f32,
21+
single: Option<f64>,
22+
sequence: &[Option<f64>],
23+
adjustment: f64,
2424
) -> (Flag, Vec<Flag>) {
2525
let single = match single {
2626
Some(value) => value,
@@ -67,7 +67,7 @@ pub fn single_less_than_any(
6767
/// - `cache.ratio` is 0
6868
pub fn single_less_than_any_cache(
6969
cache: &ConsistencyCache,
70-
adjustment: f32,
70+
adjustment: f64,
7171
) -> Vec<TimeseriesPair<Flag>> {
7272
let num_series = cache.data.len();
7373
let mut result_vec = Vec::with_capacity(num_series);

‎src/checks/consistency/single_outside_sequence.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ use crate::{ConsistencyCache, Flag, Timeseries, TimeseriesPair};
1111
/// point did not satisfy the invariant.
1212
/// - [`Flag::Fail`] otherwise.
1313
pub fn single_outside_sequence(
14-
single: Option<f32>,
15-
sequence: &[Option<f32>],
16-
adjustment: f32,
14+
single: Option<f64>,
15+
sequence: &[Option<f64>],
16+
adjustment: f64,
1717
) -> Flag {
1818
let single = match single {
1919
Some(value) => value,
@@ -25,7 +25,7 @@ pub fn single_outside_sequence(
2525
// indicating if any value was missing
2626
let (minmax, missing) = sequence.iter().fold(
2727
(None, false),
28-
|acc: (Option<(f32, f32)>, bool), elem| match elem {
28+
|acc: (Option<(f64, f64)>, bool), elem| match elem {
2929
// if the element wasn't missing...
3030
Some(value) => match acc.0 {
3131
// set the minmax if there isn't already a minmax, or the element is lower
@@ -63,7 +63,7 @@ pub fn single_outside_sequence(
6363
/// - `cache.ratio` is 0
6464
pub fn single_outside_sequence_cache(
6565
cache: &ConsistencyCache,
66-
adjustment: f32,
66+
adjustment: f64,
6767
) -> Vec<TimeseriesPair<Flag>> {
6868
let num_series = cache.data.len();
6969
let mut result_vec = Vec::with_capacity(num_series);

‎src/checks/series/flatline_check.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::{util::Timeseries, DataCache, Error, Flag};
1212
/// - [`Flag::Invalid`] if `data` is empty,
1313
/// - [`Flag::Fail`] if all observations passed in are identical,
1414
/// - [`Flag::Pass`] otherwise.
15-
pub fn flatline_check(data: &[Option<f32>], threshold: f32) -> Flag {
15+
pub fn flatline_check(data: &[Option<f64>], threshold: f64) -> Flag {
1616
if data.contains(&None) {
1717
return Flag::DataMissing;
1818
}
@@ -45,7 +45,7 @@ pub fn flatline_check(data: &[Option<f32>], threshold: f32) -> Flag {
4545
pub fn flatline_check_cache(
4646
cache: &DataCache,
4747
num_points: u8,
48-
threshold: f32,
48+
threshold: f64,
4949
) -> Result<Vec<Timeseries<Flag>>, Error> {
5050
let num_series = cache.data.len();
5151
let mut result_vec = Vec::with_capacity(cache.data.len());

‎src/checks/series/monotonic_decrease_check.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::{DataCache, Error, Flag, Timeseries};
1818
/// - [`Flag::Fail`] if there are no increases between consecutive data points in the series
1919
/// AND the total decrease over the series is within the given range
2020
/// - [`Flag::Pass`] otherwise.
21-
pub fn monotonic_decrease_check(data: &[Option<f32>], lower_limit: f32, upper_limit: f32) -> Flag {
21+
pub fn monotonic_decrease_check(data: &[Option<f64>], lower_limit: f64, upper_limit: f64) -> Flag {
2222
if data.is_empty() || data.iter().any(Option::is_none) {
2323
return Flag::DataMissing;
2424
}
@@ -65,8 +65,8 @@ pub fn monotonic_decrease_check(data: &[Option<f32>], lower_limit: f32, upper_li
6565
/// - data has `num_leading_points` or `num_trailing_points` < `window_size`
6666
pub fn monotonic_decrease_check_cache(
6767
cache: &DataCache,
68-
lower_limit: f32,
69-
upper_limit: f32,
68+
lower_limit: f64,
69+
upper_limit: f64,
7070
// TODO: should this maybe be a usize? would require changing the type of num_leading_points
7171
// in DataCache
7272
window_size: u8,
@@ -138,10 +138,10 @@ mod tests {
138138

139139
#[test]
140140
fn test_monotonic_decrease_check() {
141-
let decreasing_sequence: Vec<Option<f32>> = repeat(200.)
141+
let decreasing_sequence: Vec<Option<f64>> = repeat(200.)
142142
.take(25)
143143
.enumerate()
144-
.map(|(i, val)| Some(val - (i as f32 * 0.1)))
144+
.map(|(i, val)| Some(val - (i as f64 * 0.1)))
145145
.collect();
146146
assert_eq!(
147147
monotonic_decrease_check(&decreasing_sequence.clone(), 0.7, 100.),

‎src/checks/series/spike_check.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub const SPIKE_TRAILING_PER_RUN: u8 = 1;
2121
/// - [`Flag::Fail`] if the difference (explained above) is less than 35% of the sum AND the sum
2222
/// (explained above) is greater than `max`,
2323
/// - [`Flag::Pass`] otherwise.
24-
pub fn spike_check(data: &[Option<f32>; 3], max: f32) -> Flag {
24+
pub fn spike_check(data: &[Option<f64>; 3], max: f64) -> Flag {
2525
if data.contains(&None) {
2626
return Flag::DataMissing;
2727
}
@@ -49,7 +49,7 @@ pub fn spike_check(data: &[Option<f32>; 3], max: f32) -> Flag {
4949
/// - data is invalid
5050
/// - data has `num_leading_points` <= 1
5151
/// - data has `num_trailing_points` <= 1
52-
pub fn spike_check_cache(cache: &DataCache, max: f32) -> Result<Vec<Timeseries<Flag>>, Error> {
52+
pub fn spike_check_cache(cache: &DataCache, max: f64) -> Result<Vec<Timeseries<Flag>>, Error> {
5353
let num_series = cache.data.len();
5454
let mut result_vec = Vec::with_capacity(num_series);
5555
let series_len = match cache.data.first() {

‎src/checks/series/step_check.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub const STEP_LEADING_PER_RUN: u8 = 1;
1313
/// - [`Flag::Fail`] If the absolute value of the difference between the observed value and it's
1414
/// predecessor is greater than max
1515
/// - [`Flag::Pass`] otherwise.
16-
pub fn step_check(data: &[Option<f32>; 2], max: f32) -> Flag {
16+
pub fn step_check(data: &[Option<f64>; 2], max: f64) -> Flag {
1717
if data.contains(&None) {
1818
return Flag::DataMissing;
1919
}
@@ -33,7 +33,7 @@ pub fn step_check(data: &[Option<f32>; 2], max: f32) -> Flag {
3333
///
3434
/// - data is invalid
3535
/// - data has `num_leading_points` < 1
36-
pub fn step_check_cache(cache: &DataCache, max: f32) -> Result<Vec<Timeseries<Flag>>, Error> {
36+
pub fn step_check_cache(cache: &DataCache, max: f64) -> Result<Vec<Timeseries<Flag>>, Error> {
3737
let num_series = cache.data.len();
3838
let mut result_vec = Vec::with_capacity(num_series);
3939
let series_len = match cache.data.first() {

‎src/checks/single/range_check.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{util::Timeseries, DataCache, Flag};
66
/// - [`Flag::DataMissing`] if the observation is missing,
77
/// - [`Flag::Fail`] if it is outside the upper or lower limits,
88
/// - [`Flag::Pass`] otherwise.
9-
pub fn range_check(datum: Option<f32>, lower_limit: f32, upper_limit: f32) -> Flag {
9+
pub fn range_check(datum: Option<f64>, lower_limit: f64, upper_limit: f64) -> Flag {
1010
match datum {
1111
None => Flag::DataMissing,
1212
Some(datum) => {
@@ -21,8 +21,8 @@ pub fn range_check(datum: Option<f32>, lower_limit: f32, upper_limit: f32) -> Fl
2121
/// Apply [`range_check`] to a whole [`DataCache`]
2222
pub fn range_check_cache(
2323
cache: &DataCache,
24-
lower_limit: f32,
25-
upper_limit: f32,
24+
lower_limit: f64,
25+
upper_limit: f64,
2626
) -> Vec<Timeseries<Flag>> {
2727
let num_series = cache.data.len();
2828
let mut result_vec = Vec::with_capacity(num_series);

‎src/checks/single/range_check_humidity.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::{util::Timeseries, DataCache, Flag};
77
/// - ([`Flag::Fail`], None) if humidity less than 5% or greater than 105%,
88
/// - ([`Flag::Warn`], Some(100.)) between 100% and 105%,
99
/// - ([`Flag::Pass`], None) otherwise.
10-
pub fn range_check_humidity(datum: Option<f32>) -> (Flag, Option<f32>) {
10+
pub fn range_check_humidity(datum: Option<f64>) -> (Flag, Option<f64>) {
1111
match datum {
1212
None => (Flag::DataMissing, None),
1313
Some(datum) => {
@@ -25,7 +25,7 @@ pub fn range_check_humidity(datum: Option<f32>) -> (Flag, Option<f32>) {
2525
//TODO: is this the optimal return signature for corrections?
2626
/// Apply [`range_check_humidity`] to a whole [`DataCache`]
2727
#[allow(clippy::type_complexity)]
28-
pub fn range_check_humidity_cache(cache: &DataCache) -> Vec<Timeseries<(Flag, Option<f32>)>> {
28+
pub fn range_check_humidity_cache(cache: &DataCache) -> Vec<Timeseries<(Flag, Option<f64>)>> {
2929
let num_series = cache.data.len();
3030
let mut result_vec = Vec::with_capacity(num_series);
3131
let series_len = match cache.data.first() {

‎src/checks/single/range_check_wind_direction.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::{util::Timeseries, DataCache, Flag};
88
/// - ([`Flag::Warn`], Some(value + 360)) if the value is between -20 and 0,
99
/// - ([`Flag::Warn`], Some(value - 360)) if the value is between 360 and 380,
1010
/// - ([`Flag::Pass`], None) otherwise.
11-
pub fn range_check_wind_direction(datum: Option<f32>) -> (Flag, Option<f32>) {
11+
pub fn range_check_wind_direction(datum: Option<f64>) -> (Flag, Option<f64>) {
1212
// TODO: get to the bottom of weird -3.0 handling: kvalobs code looks for a value -3.0, and
1313
// avoids flagging that if X_5 (lowest?) is also -3.0. From comments in the code, it looks like
1414
// this has to do with a special param_id?
@@ -36,7 +36,7 @@ pub fn range_check_wind_direction(datum: Option<f32>) -> (Flag, Option<f32>) {
3636
//TODO: is this the optimal return signature for corrections?
3737
/// Apply [`range_check_wind_direction`] to a whole [`DataCache`]
3838
#[allow(clippy::type_complexity)]
39-
pub fn range_check_wind_direction_cache(cache: &DataCache) -> Vec<Timeseries<(Flag, Option<f32>)>> {
39+
pub fn range_check_wind_direction_cache(cache: &DataCache) -> Vec<Timeseries<(Flag, Option<f64>)>> {
4040
let num_series = cache.data.len();
4141
let mut result_vec = Vec::with_capacity(num_series);
4242
let series_len = match cache.data.first() {

‎src/checks/single/special_values_check.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{util::Timeseries, DataCache, Flag};
66
/// - [`Flag::DataMissing`] if the observation is missing,
77
/// - [`Flag::Fail`] if it matches any of the special values
88
/// - [`Flag::Pass`] otherwise.
9-
pub fn special_values_check(datum: Option<f32>, special_values: &[f32]) -> Flag {
9+
pub fn special_values_check(datum: Option<f64>, special_values: &[f64]) -> Flag {
1010
match datum {
1111
None => Flag::DataMissing,
1212
Some(datum) => {
@@ -21,7 +21,7 @@ pub fn special_values_check(datum: Option<f32>, special_values: &[f32]) -> Flag
2121
/// Apply [`special_values_check`] to a whole [`DataCache`]
2222
pub fn special_values_check_cache(
2323
cache: &DataCache,
24-
special_values: &[f32],
24+
special_values: &[f64],
2525
) -> Vec<Timeseries<Flag>> {
2626
let num_series = cache.data.len();
2727
let mut result_vec = Vec::with_capacity(num_series);

‎src/checks/spatial/buddy_check.rs

+13-13
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,19 @@ use crate::{
88
#[derive(Debug, Clone)]
99
pub struct BuddyCheckArgs {
1010
/// Search radius in which buddies of an observation will be found. Unit: m
11-
pub radii: SingleOrVec<f32>,
11+
pub radii: SingleOrVec<f64>,
1212
/// The minimum buddies an observation can have (lest it be flagged [`Flag::Isolated`])
1313
pub min_buddies: SingleOrVec<u32>,
1414
/// The variance threshold for flagging a station. Unit: σ (standard deviations)
15-
pub threshold: f32,
15+
pub threshold: f64,
1616
/// The maximum difference in elevation for a buddy (if negative will not check for height
1717
/// difference). Unit: m
18-
pub max_elev_diff: f32,
18+
pub max_elev_diff: f64,
1919
/// Linear elevation gradient with height. Unit: ou/m (ou = unit of observation)
20-
pub elev_gradient: f32,
20+
pub elev_gradient: f64,
2121
/// If the standard deviation of values in a neighborhood are less than min_std, min_std will
2222
/// be used instead
23-
pub min_std: f32,
23+
pub min_std: f64,
2424
/// The number of iterations of buddy_check to perform before returning
2525
pub num_iterations: u32,
2626
}
@@ -54,7 +54,7 @@ pub struct BuddyCheckArgs {
5454
/// element is set to true, while all values are always used as buddies for checking the data
5555
/// quality.
5656
pub fn buddy_check(
57-
data: &[Option<f32>],
57+
data: &[Option<f64>],
5858
rtree: &SpatialTree,
5959
args: &BuddyCheckArgs,
6060
obs_to_check: Option<&[bool]>,
@@ -87,7 +87,7 @@ pub fn buddy_check(
8787
let (lat, lon, elev) = rtree.get_coords_at_index(i);
8888
let neighbours = rtree.get_neighbours(lat, lon, *args.radii.index(i), false);
8989

90-
let mut list_buddies: Vec<f32> = Vec::new();
90+
let mut list_buddies: Vec<f64> = Vec::new();
9191

9292
if neighbours.len() >= *args.min_buddies.index(i) as usize {
9393
for neighbour in neighbours {
@@ -116,17 +116,17 @@ pub fn buddy_check(
116116
}
117117

118118
if list_buddies.len() >= *args.min_buddies.index(i) as usize {
119-
let mean: f32 = list_buddies.iter().sum::<f32>() / list_buddies.len() as f32;
120-
let variance: f32 = (list_buddies.iter().map(|x| x.powi(2)).sum::<f32>()
121-
/ list_buddies.len() as f32)
119+
let mean: f64 = list_buddies.iter().sum::<f64>() / list_buddies.len() as f64;
120+
let variance: f64 = (list_buddies.iter().map(|x| x.powi(2)).sum::<f64>()
121+
/ list_buddies.len() as f64)
122122
- mean.powi(2); // TODO: use a better variance algorithm?
123123
// let std = variance.sqrt();
124-
// let std_adjusted = (variance + variance / list_buddies.len() as f32).sqrt();
124+
// let std_adjusted = (variance + variance / list_buddies.len() as f64).sqrt();
125125
// if std_adjusted < min_std {
126126
// std_adjusted = min_std
127127
// }
128128
let std_adjusted = std::cmp::max_by(
129-
(variance + variance / list_buddies.len() as f32).sqrt(),
129+
(variance + variance / list_buddies.len() as f64).sqrt(),
130130
args.min_std,
131131
|x, y| x.partial_cmp(y).unwrap_or(std::cmp::Ordering::Equal),
132132
);
@@ -174,7 +174,7 @@ pub fn buddy_check_cache(
174174

175175
for i in (cache.num_leading_points as usize)..(series_len - cache.num_trailing_points as usize)
176176
{
177-
let timeslice: Vec<Option<f32>> = cache.data.iter().map(|fs| fs.values[i]).collect();
177+
let timeslice: Vec<Option<f64>> = cache.data.iter().map(|fs| fs.values[i]).collect();
178178
let spatial_result = buddy_check(&timeslice, &cache.rtree, args, obs_to_check)?;
179179

180180
for i in 0..spatial_result.len() {

‎src/checks/spatial/sct.rs

+50-50
Original file line numberDiff line numberDiff line change
@@ -20,25 +20,25 @@ pub struct SctArgs {
2020
pub num_max: usize,
2121
// FIXME: this doc comment can be improved
2222
/// Radius in which OI will be reused. Unit: m
23-
pub inner_radius: f32,
23+
pub inner_radius: f64,
2424
/// Radius for computing OI and background. Unit: m
25-
pub outer_radius: f32,
25+
pub outer_radius: f64,
2626
/// The number of iterations of SCT to perform before returning.
2727
pub num_iterations: u32,
2828
/// Minimum number of observations to compute vertical profile.
2929
pub num_min_prof: usize,
3030
/// Minimum elevation difference to compute vertical profile. Unit: m
31-
pub min_elev_diff: f32,
31+
pub min_elev_diff: f64,
3232
/// Minimum horizontal decorrelation length. Unit: m
33-
pub min_horizontal_scale: f32,
33+
pub min_horizontal_scale: f64,
3434
/// Vertical decorrelation length. Unit: m
35-
pub vertical_scale: f32,
35+
pub vertical_scale: f64,
3636
/// Positive deviation allowed. Unit: σ (standard deviations)
37-
pub pos: SingleOrVec<f32>,
37+
pub pos: SingleOrVec<f64>,
3838
/// Negative deviation allowed. Unit: σ (standard deviations)
39-
pub neg: SingleOrVec<f32>,
39+
pub neg: SingleOrVec<f64>,
4040
/// Ratio of observation error variance to background variance.
41-
pub eps2: SingleOrVec<f32>,
41+
pub eps2: SingleOrVec<f64>,
4242
}
4343

4444
fn subset<T: Copy>(array: &[T], indices: &[usize]) -> Vec<T> {
@@ -53,16 +53,16 @@ fn subset<T: Copy>(array: &[T], indices: &[usize]) -> Vec<T> {
5353
}
5454

5555
fn compute_vertical_profile_theil_sen(
56-
elevs: &[f32],
57-
values: &[f32],
56+
elevs: &[f64],
57+
values: &[f64],
5858
num_min_prof: usize,
59-
min_elev_diff: f32,
60-
) -> Vec<f32> {
59+
min_elev_diff: f64,
60+
) -> Vec<f64> {
6161
let n = values.len();
6262

6363
// Starting value guesses
64-
let gamma: f32 = -0.0065;
65-
let mean_t: f32 = values.iter().sum::<f32>() / n as f32; // should this be f64?
64+
let gamma: f64 = -0.0065;
65+
let mean_t: f64 = values.iter().sum::<f64>() / n as f64; // should this be f64?
6666

6767
// special case when all observations have the same elevation
6868
if elevs.iter().min_by(|a, b| a.total_cmp(b)) == elevs.iter().max_by(|a, b| a.total_cmp(b)) {
@@ -81,7 +81,7 @@ fn compute_vertical_profile_theil_sen(
8181
gamma
8282
} else {
8383
let nm = n * (n - 1) / 2;
84-
let mut m: Vec<f32> = Vec::with_capacity(nm);
84+
let mut m: Vec<f64> = Vec::with_capacity(nm);
8585
for i in 0..(n - 1) {
8686
for j in (i + 1)..n {
8787
m.push(if (elevs[i] - elevs[j]).abs() < 1. {
@@ -93,7 +93,7 @@ fn compute_vertical_profile_theil_sen(
9393
}
9494
compute_quantile(0.5, &m)
9595
};
96-
let q: Vec<f32> = values
96+
let q: Vec<f64> = values
9797
.iter()
9898
.zip(elevs)
9999
.map(|(val, elev)| val - m_median * elev)
@@ -107,8 +107,8 @@ fn compute_vertical_profile_theil_sen(
107107
}
108108

109109
// TODO: replace assertions with errors or remove them
110-
fn compute_quantile(quantile: f32, array: &[f32]) -> f32 {
111-
let mut new_array: Vec<f32> = array
110+
fn compute_quantile(quantile: f64, array: &[f64]) -> f64 {
111+
let mut new_array: Vec<f64> = array
112112
.iter()
113113
.copied()
114114
.filter(|x| util::is_valid(*x))
@@ -120,12 +120,12 @@ fn compute_quantile(quantile: f32, array: &[f32]) -> f32 {
120120
assert!(n > 0);
121121

122122
// get the quantile from the sorted array
123-
let lower_index = (quantile * (n - 1) as f32).floor() as usize;
124-
let upper_index = (quantile * (n - 1) as f32).ceil() as usize;
123+
let lower_index = (quantile * (n - 1) as f64).floor() as usize;
124+
let upper_index = (quantile * (n - 1) as f64).ceil() as usize;
125125
let lower_value = new_array[lower_index];
126126
let upper_value = new_array[upper_index];
127-
let lower_quantile = lower_index as f32 / (n - 1) as f32;
128-
let upper_quantile = upper_index as f32 / (n - 1) as f32;
127+
let lower_quantile = lower_index as f64 / (n - 1) as f64;
128+
let upper_quantile = upper_index as f64 / (n - 1) as f64;
129129
let exact_q = if lower_index == upper_index {
130130
lower_value
131131
} else {
@@ -142,16 +142,16 @@ fn compute_quantile(quantile: f32, array: &[f32]) -> f32 {
142142
exact_q
143143
}
144144

145-
fn invert_matrix(input: &Mat<f32>) -> Mat<f32> {
145+
fn invert_matrix(input: &Mat<f64>) -> Mat<f64> {
146146
let lu = input.partial_piv_lu();
147147
lu.inverse()
148148
}
149149

150150
fn remove_flagged<'a>(
151151
neighbours: Vec<&'a SpatialPoint>,
152-
distances: Vec<f32>,
152+
distances: Vec<f64>,
153153
flags: &[Flag],
154-
) -> (Vec<&'a SpatialPoint>, Vec<f32>) {
154+
) -> (Vec<&'a SpatialPoint>, Vec<f64>) {
155155
let vec_length = neighbours.len();
156156
let mut neighbours_new = Vec::with_capacity(vec_length);
157157
let mut distances_new = Vec::with_capacity(vec_length);
@@ -214,7 +214,7 @@ fn remove_flagged<'a>(
214214
/// \* optional, ou = Unit of the observation, σ = Standard deviations
215215
#[allow(clippy::too_many_arguments)]
216216
pub fn sct(
217-
data: &[Option<f32>],
217+
data: &[Option<f64>],
218218
rtree: &SpatialTree,
219219
args: &SctArgs,
220220
obs_to_check: Option<&[bool]>,
@@ -369,7 +369,7 @@ pub fn sct(
369369
remove_flagged(neighbours_unfiltered, distances_unfiltered, &flags);
370370

371371
if neighbours.len() > args.num_max {
372-
let mut pairs: Vec<(&SpatialPoint, f32)> =
372+
let mut pairs: Vec<(&SpatialPoint, f64)> =
373373
neighbours.into_iter().zip(distances.into_iter()).collect();
374374
pairs.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap_or(std::cmp::Ordering::Equal));
375375

@@ -394,7 +394,7 @@ pub fn sct(
394394
let values_box = subset(data, &neighbour_indices)
395395
.into_iter()
396396
.map(|v| v.unwrap())
397-
.collect::<Vec<f32>>();
397+
.collect::<Vec<f64>>();
398398
let eps2_box = match &args.eps2 {
399399
SingleOrVec::Single(eps2_value) => SingleOrVec::Single(*eps2_value),
400400
SingleOrVec::Vec(eps2_vec) => {
@@ -411,15 +411,15 @@ pub fn sct(
411411
args.min_elev_diff,
412412
);
413413

414-
let disth: Mat<f32> = Mat::from_fn(box_size, box_size, |i, j| {
414+
let disth: Mat<f64> = Mat::from_fn(box_size, box_size, |i, j| {
415415
// TODO: remove this unwrap
416416
util::calc_distance(lats_box[i], lons_box[i], lats_box[j], lons_box[j]).unwrap()
417417
});
418-
let distz: Mat<f32> = Mat::from_fn(box_size, box_size, |i, j| {
418+
let distz: Mat<f64> = Mat::from_fn(box_size, box_size, |i, j| {
419419
(elevs_box[i] - elevs_box[j]).abs()
420420
});
421421
// TODO: remove dh, and just reduce straight into dh_mean?
422-
let dh: Vec<f32> = (0..box_size)
422+
let dh: Vec<f64> = (0..box_size)
423423
.map(|i| {
424424
let mut dh_vector = Vec::with_capacity(box_size - 1);
425425
for j in 0..box_size {
@@ -431,13 +431,13 @@ pub fn sct(
431431
})
432432
.collect();
433433

434-
let dh_mean: f32 = args
434+
let dh_mean: f64 = args
435435
.min_horizontal_scale
436-
.max(dh.into_iter().sum::<f32>() / box_size as f32);
436+
.max(dh.into_iter().sum::<f64>() / box_size as f64);
437437

438-
let mut s: Mat<f32> = Mat::from_fn(box_size, box_size, |i, j| {
439-
let value = (-0.5 * (disth.get(i, j) / dh_mean).powi(2)
440-
- 0.5 * (distz.get(i, j) / args.vertical_scale).powi(2))
438+
let mut s: Mat<f64> = Mat::from_fn(box_size, box_size, |i, j| {
439+
let value = (-0.5 * (disth.read(i, j) / dh_mean).powi(2)
440+
- 0.5 * (distz.read(i, j) / args.vertical_scale).powi(2))
441441
.exp();
442442
// weight the diagonal?? (0.5 default)
443443
if i == j {
@@ -448,7 +448,7 @@ pub fn sct(
448448
});
449449

450450
// difference between actual temp and temp from vertical profile
451-
let d: Vec<f32> = (0..box_size)
451+
let d: Vec<f64> = (0..box_size)
452452
.map(|i| values_box[i] - vertical_profile[i])
453453
.collect();
454454

@@ -465,22 +465,22 @@ pub fn sct(
465465
elem.sub_assign(eps2_box.index(i));
466466
}
467467

468-
let s_inv_d: Vec<f32> = (0..box_size)
469-
.map(|i| (0..box_size).map(|j| s_inv.get(i, j) * d[j]).sum())
468+
let s_inv_d: Vec<f64> = (0..box_size)
469+
.map(|i| (0..box_size).map(|j| s_inv.read(i, j) * d[j]).sum())
470470
.collect();
471471

472-
let ares_temp: Vec<f32> = (0..box_size)
473-
.map(|i| (0..box_size).map(|j| s.get(i, j) * s_inv_d[j]).sum())
472+
let ares_temp: Vec<f64> = (0..box_size)
473+
.map(|i| (0..box_size).map(|j| s.read(i, j) * s_inv_d[j]).sum())
474474
.collect();
475475

476-
let z_inv: Vec<f32> = (0..box_size).map(|i| 1. / s_inv.get(i, i)).collect();
476+
let z_inv: Vec<f64> = (0..box_size).map(|i| 1. / s_inv.read(i, i)).collect();
477477

478-
let ares: Vec<f32> = (0..box_size).map(|i| ares_temp[i] - d[i]).collect();
478+
let ares: Vec<f64> = (0..box_size).map(|i| ares_temp[i] - d[i]).collect();
479479

480-
let cvres: Vec<f32> = (0..box_size).map(|i| -1. * z_inv[i] * s_inv_d[i]).collect();
480+
let cvres: Vec<f64> = (0..box_size).map(|i| -1. * z_inv[i] * s_inv_d[i]).collect();
481481

482-
let sig2o = 0.01_f32
483-
.max((0..box_size).map(|i| d[i] * -1. * ares[i]).sum::<f32>() / box_size as f32);
482+
let sig2o = 0.01_f64
483+
.max((0..box_size).map(|i| d[i] * -1. * ares[i]).sum::<f64>() / box_size as f64);
484484

485485
let curr = i;
486486
for i in 0..box_size {
@@ -493,7 +493,7 @@ pub fn sct(
493493
}
494494
let dist = distances[i];
495495
if dist <= args.inner_radius {
496-
let pog: f32 = cvres[i] * ares[i] / sig2o;
496+
let pog: f64 = cvres[i] * ares[i] / sig2o;
497497
assert!(util::is_valid(pog));
498498
prob_gross_error[index] = pog.max(prob_gross_error[index]);
499499
if (cvres[i] < 0. && pog > *args.pos.index(index))
@@ -534,7 +534,7 @@ pub fn sct_cache(
534534

535535
for i in (cache.num_leading_points as usize)..(series_len - cache.num_trailing_points as usize)
536536
{
537-
let timeslice: Vec<Option<f32>> = cache.data.iter().map(|ts| ts.values[i]).collect();
537+
let timeslice: Vec<Option<f64>> = cache.data.iter().map(|ts| ts.values[i]).collect();
538538
let spatial_result = sct(&timeslice, &cache.rtree, args, obs_to_check)?;
539539

540540
for i in 0..spatial_result.len() {
@@ -584,9 +584,9 @@ mod tests {
584584
sct(
585585
&vec![Some(1.); N],
586586
&SpatialTree::from_latlons(
587-
(0..N).map(|i| ((i as f32).powi(2) * 0.001) % 1.).collect(),
587+
(0..N).map(|i| ((i as f64).powi(2) * 0.001) % 1.).collect(),
588588
(0..N)
589-
.map(|i| ((i as f32 + 1.).powi(2) * 0.001) % 1.)
589+
.map(|i| ((i as f64 + 1.).powi(2) * 0.001) % 1.)
590590
.collect(),
591591
vec![1.; N],
592592
),

‎src/util/mod.rs

+12-12
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ pub struct DataCache {
6666
/// where the first and last sections are `DataCache.num_leading_points` and
6767
/// `DataCache.num_trailing_points` long, respectively.
6868
/// The actual observations to be QCed (i.e. flagged) lie in the middle section.
69-
pub data: Vec<Timeseries<Option<f32>>>,
69+
pub data: Vec<Timeseries<Option<f64>>>,
7070
/// Time of the first observation in data
7171
///
7272
/// This means the first observation that will actually be QCed, so excluding the "leading"
@@ -93,10 +93,10 @@ pub struct DataCache {
9393
impl DataCache {
9494
/// Create a new DataCache without manually constructing the R*-tree
9595
pub fn new(
96-
data: Vec<Timeseries<Option<f32>>>,
97-
lats: Vec<f32>,
98-
lons: Vec<f32>,
99-
elevs: Vec<f32>,
96+
data: Vec<Timeseries<Option<f64>>>,
97+
lats: Vec<f64>,
98+
lons: Vec<f64>,
99+
elevs: Vec<f64>,
100100
start_time: Timestamp,
101101
period: RelativeDuration,
102102
num_leading_points: u8,
@@ -128,7 +128,7 @@ pub struct ConsistencyCache {
128128
///
129129
/// Each pair of timeseries are aligned with the other pairs on start_time and period
130130
/// `None`s represent gaps in the series.
131-
pub data: Vec<TimeseriesPair<Option<f32>>>,
131+
pub data: Vec<TimeseriesPair<Option<f64>>>,
132132
/// Time of the first observation in the timeseries
133133
///
134134
/// the first timestamp applies to the first timeseries in each pair, and so for the second
@@ -159,14 +159,14 @@ impl<T> SingleOrVec<T> {
159159
}
160160
}
161161

162-
pub(crate) const RADIUS_EARTH: f32 = 6371.0;
162+
pub(crate) const RADIUS_EARTH: f64 = 6371.0;
163163

164-
pub(crate) fn is_valid(value: f32) -> bool {
165-
!f32::is_nan(value) && !f32::is_infinite(value)
164+
pub(crate) fn is_valid(value: f64) -> bool {
165+
!f64::is_nan(value) && !f64::is_infinite(value)
166166
}
167167

168168
/// convert lat-lon to xyz coordinates
169-
pub(crate) fn convert_coordinates(lat: f32, lon: f32) -> (f32, f32, f32) {
169+
pub(crate) fn convert_coordinates(lat: f64, lon: f64) -> (f64, f64, f64) {
170170
(
171171
lat.to_radians().cos() * lon.to_radians().cos() * RADIUS_EARTH,
172172
lat.to_radians().cos() * lon.to_radians().sin() * RADIUS_EARTH,
@@ -175,7 +175,7 @@ pub(crate) fn convert_coordinates(lat: f32, lon: f32) -> (f32, f32, f32) {
175175
}
176176

177177
/// find the distance in km between two lat-lon points
178-
pub(crate) fn calc_distance(lat1: f32, lon1: f32, lat2: f32, lon2: f32) -> Result<f32, Error> {
178+
pub(crate) fn calc_distance(lat1: f64, lon1: f64, lat2: f64, lon2: f64) -> Result<f64, Error> {
179179
// lons are checked against 360 here, not 180, because some people apparently use
180180
// conventions of 0-360 and -360-0...
181181
if lat1.abs() > 90. || lat2.abs() > 90. || lon1.abs() > 360. || lon2.abs() > 360. {
@@ -204,6 +204,6 @@ pub(crate) fn calc_distance(lat1: f32, lon1: f32, lat2: f32, lon2: f32) -> Resul
204204
}
205205

206206
/// find the distance in km between two xyz points
207-
pub(crate) fn calc_distance_xyz(x0: f32, y0: f32, z0: f32, x1: f32, y1: f32, z1: f32) -> f32 {
207+
pub(crate) fn calc_distance_xyz(x0: f64, y0: f64, z0: f64, x1: f64, y1: f64, z1: f64) -> f64 {
208208
((x0 - x1) * (x0 - x1) + (y0 - y1) * (y0 - y1) + (z0 - z1) * (z0 - z1)).sqrt()
209209
}

‎src/util/spatial_tree.rs

+14-14
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,20 @@ use rstar::{primitives::GeomWithData, RTree};
33

44
/// A point in the [`SpatialTree`]
55
///
6-
/// The `[f32; 3]` represents the xyz coordinates of the point, which is used
6+
/// The `[f64; 3]` represents the xyz coordinates of the point, which is used
77
/// to spatially index, and the usize represents the index into the lats, lons,
88
/// elevs, and values arrays associated with that point.
9-
pub(crate) type SpatialPoint = GeomWithData<[f32; 3], usize>;
9+
pub(crate) type SpatialPoint = GeomWithData<[f64; 3], usize>;
1010

1111
/// An R-tree to spatially index data to spatially index data
1212
///
1313
/// This allows a data point's nearest neighbours to be found with ease
1414
#[derive(Debug, Clone)]
1515
pub struct SpatialTree {
1616
pub(crate) tree: RTree<SpatialPoint>,
17-
pub(crate) lats: Vec<f32>,
18-
pub(crate) lons: Vec<f32>,
19-
pub(crate) elevs: Vec<f32>,
17+
pub(crate) lats: Vec<f64>,
18+
pub(crate) lons: Vec<f64>,
19+
pub(crate) elevs: Vec<f64>,
2020
}
2121

2222
impl SpatialTree {
@@ -25,7 +25,7 @@ impl SpatialTree {
2525
/// The positions are specified by vectors of lats, lons, and elevs, where
2626
/// the elements from each vector at a given index together specify a
2727
/// single point in space
28-
pub fn from_latlons(lats: Vec<f32>, lons: Vec<f32>, elevs: Vec<f32>) -> Self {
28+
pub fn from_latlons(lats: Vec<f64>, lons: Vec<f64>, elevs: Vec<f64>) -> Self {
2929
//TODO: ensure vecs are the same size
3030

3131
let raw_points: Vec<SpatialPoint> = lats
@@ -50,9 +50,9 @@ impl SpatialTree {
5050

5151
pub(crate) fn get_neighbours(
5252
&self,
53-
lat: f32,
54-
lon: f32,
55-
radius: f32,
53+
lat: f64,
54+
lon: f64,
55+
radius: f64,
5656
include_match: bool,
5757
) -> Vec<&SpatialPoint> {
5858
let (x, y, z) = util::convert_coordinates(lat, lon);
@@ -69,11 +69,11 @@ impl SpatialTree {
6969

7070
pub(crate) fn get_neighbours_with_distance(
7171
&self,
72-
lat: f32,
73-
lon: f32,
74-
radius: f32,
72+
lat: f64,
73+
lon: f64,
74+
radius: f64,
7575
include_match: bool,
76-
) -> (Vec<&SpatialPoint>, Vec<f32>) {
76+
) -> (Vec<&SpatialPoint>, Vec<f64>) {
7777
let points = self.get_neighbours(lat, lon, radius, include_match);
7878
let vec_length = points.len();
7979

@@ -90,7 +90,7 @@ impl SpatialTree {
9090
(points, distances)
9191
}
9292

93-
pub(crate) fn get_coords_at_index(&self, i: usize) -> (f32, f32, f32) {
93+
pub(crate) fn get_coords_at_index(&self, i: usize) -> (f64, f64, f64) {
9494
(self.lats[i], self.lons[i], self.elevs[i])
9595
}
9696
}

0 commit comments

Comments
 (0)
Please sign in to comment.