Skip to content

Commit 6d70b31

Browse files
authored
fix: Cache and Stacker should keep band order for subsets (#1120)
* fix(cache):filter returned band by query.band * stacker: produce tiles with band selection stored * update cache stored bands * lint test * add debug outputs on error tiles (only in debug mode) * remove no needed method * enhance expect method * remove comment regarding TimeInstants * remove band update in stored query since bands must not change * remove redundant filterin in cache * remove and cleanup code fix MockRasterSource * back to old StackerAdapter stratey where bands are not selected * baseline stacker approach. Fix tests * improve comment * lints * add band selection logic to SimpleRasterStacker * add regular time stackerwith band selection to RasterStacker Operator * more tests and checks * lints * more lint
1 parent d30e35b commit 6d70b31

File tree

27 files changed

+1655
-5374
lines changed

27 files changed

+1655
-5374
lines changed

datatypes/src/primitives/query_rectangle.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,14 @@ impl BandSelection {
176176
pub fn is_single(&self) -> bool {
177177
self.count() == 1
178178
}
179+
180+
pub fn contains(&self, band: u32) -> bool {
181+
self.0.contains(&band)
182+
}
183+
184+
pub fn contains_all(&self, bands: &[u32]) -> bool {
185+
bands.iter().all(|band| self.contains(*band))
186+
}
179187
}
180188

181189
impl From<u32> for BandSelection {
@@ -184,6 +192,12 @@ impl From<u32> for BandSelection {
184192
}
185193
}
186194

195+
impl AsRef<[u32]> for BandSelection {
196+
fn as_ref(&self) -> &[u32] {
197+
self.as_slice()
198+
}
199+
}
200+
187201
impl TryFrom<Vec<u32>> for BandSelection {
188202
type Error = crate::error::Error;
189203

@@ -200,11 +214,19 @@ impl<const N: usize> TryFrom<[u32; N]> for BandSelection {
200214
}
201215
}
202216

217+
impl TryFrom<&[u32]> for BandSelection {
218+
type Error = crate::error::Error;
219+
220+
fn try_from(value: &[u32]) -> Result<Self, Self::Error> {
221+
Self::new(value.to_vec())
222+
}
223+
}
224+
203225
impl QueryAttributeSelection for BandSelection {}
204226

205227
#[derive(Clone, Debug, PartialEq, Serialize)]
206228
pub struct BandSelectionIter {
207-
band_selection: BandSelection,
229+
pub band_selection: BandSelection,
208230
next_index: usize,
209231
}
210232

datatypes/src/primitives/time_gap_fill_iter.rs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1364,7 +1364,7 @@ mod tests {
13641364
}
13651365

13661366
#[test]
1367-
fn time_irregular_all_caes() {
1367+
fn time_irregular_all_cases() {
13681368
let intervals = vec![
13691369
TimeInterval::new_unchecked(
13701370
TimeInstance::from_millis(15).unwrap(),
@@ -1471,4 +1471,50 @@ mod tests {
14711471
]
14721472
);
14731473
}
1474+
1475+
#[test]
1476+
fn irregular_fill_min_max_time() {
1477+
let intervals = vec![
1478+
TimeInterval::new_unchecked(
1479+
TimeInstance::from_millis(15).unwrap(),
1480+
TimeInstance::from_millis(25).unwrap(),
1481+
),
1482+
TimeInterval::new_unchecked(
1483+
TimeInstance::from_millis(45).unwrap(),
1484+
TimeInstance::from_millis(55).unwrap(),
1485+
),
1486+
];
1487+
1488+
let iter = intervals
1489+
.into_iter()
1490+
.map(|t| -> Result<TimeInterval, &str> { Ok(t) })
1491+
.try_time_irregular_range_fill(TimeInterval::default());
1492+
let result: Result<Vec<TimeInterval>, _> = iter.collect::<Result<Vec<_>, _>>();
1493+
1494+
assert_eq!(
1495+
result.unwrap(),
1496+
vec![
1497+
TimeInterval::new_unchecked(
1498+
TimeInstance::MIN,
1499+
TimeInstance::from_millis(15).unwrap()
1500+
),
1501+
TimeInterval::new_unchecked(
1502+
TimeInstance::from_millis(15).unwrap(),
1503+
TimeInstance::from_millis(25).unwrap()
1504+
),
1505+
TimeInterval::new_unchecked(
1506+
TimeInstance::from_millis(25).unwrap(),
1507+
TimeInstance::from_millis(45).unwrap()
1508+
),
1509+
TimeInterval::new_unchecked(
1510+
TimeInstance::from_millis(45).unwrap(),
1511+
TimeInstance::from_millis(55).unwrap()
1512+
),
1513+
TimeInterval::new_unchecked(
1514+
TimeInstance::from_millis(55).unwrap(),
1515+
TimeInstance::MAX
1516+
),
1517+
]
1518+
);
1519+
}
14741520
}

datatypes/src/raster/grid_spatial.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ impl GeoTransformAccess for SpatialGridDefinition {
284284
}
285285
}
286286

287-
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
287+
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq)]
288288
pub struct TilingSpatialGridDefinition {
289289
// Don't make this public to avoid leaking inner
290290
element_grid_definition: SpatialGridDefinition,

datatypes/src/raster/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ pub use raster_properties::{
5454
RasterProperties, RasterPropertiesEntry, RasterPropertiesEntryType, RasterPropertiesKey,
5555
};
5656
pub use raster_traits::{CoordinatePixelAccess, GeoTransformAccess, Raster};
57+
pub use util::{TileIdxBandCrossProductIter, TileInformationBandCrossProductIter};
5758

5859
mod arrow_conversion;
5960
mod band_names;
@@ -79,3 +80,4 @@ mod raster_traits;
7980
mod tiling;
8081
mod typed_raster_conversion;
8182
mod typed_raster_tile;
83+
mod util;

datatypes/src/raster/tiling.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::{
1010
use serde::{Deserialize, Serialize};
1111

1212
/// The static parameters required to create a `TilingStrategy`
13-
#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
13+
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq)]
1414
pub struct TilingSpecification {
1515
pub tile_size_in_pixels: GridShape2D,
1616
}

datatypes/src/raster/util.rs

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
use crate::{
2+
primitives::{BandSelection, BandSelectionIter},
3+
raster::{GridBoundingBox2D, GridIdx2D, GridIdx2DIter, TileInformation, TileInformationIter},
4+
};
5+
6+
#[derive(Clone, Debug)]
7+
pub struct TileIdxBandCrossProductIter {
8+
tile_iter: GridIdx2DIter,
9+
band_iter: BandSelectionIter, // TODO: maybe change this to actual attributes from ResultDescriptor not the Selection?
10+
current_tile: Option<GridIdx2D>,
11+
}
12+
13+
impl TileIdxBandCrossProductIter {
14+
pub fn new(tile_iter: GridIdx2DIter, band_iter: BandSelectionIter) -> Self {
15+
let mut tile_iter = tile_iter;
16+
let current_tile = tile_iter.next();
17+
Self {
18+
tile_iter,
19+
band_iter,
20+
current_tile,
21+
}
22+
}
23+
24+
pub fn grid_bounds(&self) -> GridBoundingBox2D {
25+
self.tile_iter.grid_bounds
26+
}
27+
28+
pub fn band_selection(&self) -> &BandSelection {
29+
&self.band_iter.band_selection
30+
}
31+
32+
pub fn with_grid_bounds_and_selection(
33+
bounds: GridBoundingBox2D,
34+
band_selection: BandSelection,
35+
) -> Self {
36+
let tile_iter = GridIdx2DIter::new(&bounds);
37+
let band_iter = BandSelectionIter::new(band_selection);
38+
Self::new(tile_iter, band_iter)
39+
}
40+
41+
pub fn reset(&mut self) {
42+
self.band_iter.reset();
43+
self.tile_iter.reset();
44+
self.current_tile = self.tile_iter.next();
45+
}
46+
}
47+
48+
impl Iterator for TileIdxBandCrossProductIter {
49+
type Item = (GridIdx2D, u32);
50+
51+
fn next(&mut self) -> Option<Self::Item> {
52+
let current_t = self.current_tile;
53+
54+
match (current_t, self.band_iter.next()) {
55+
(None, _) => None,
56+
(Some(t), Some(b)) => Some((t, b)),
57+
(Some(_t), None) => {
58+
self.band_iter.reset();
59+
self.current_tile = self.tile_iter.next();
60+
self.current_tile.map(|t| {
61+
(
62+
t,
63+
self.band_iter
64+
.next()
65+
.expect("There must be at least one band"),
66+
)
67+
})
68+
}
69+
}
70+
}
71+
}
72+
73+
#[derive(Clone, Debug)]
74+
pub struct TileInformationBandCrossProductIter {
75+
tile_iter: TileInformationIter,
76+
band_iter: BandSelectionIter,
77+
current_tile: Option<TileInformation>,
78+
}
79+
80+
impl TileInformationBandCrossProductIter {
81+
pub fn new(tile_iter: TileInformationIter, band_iter: BandSelectionIter) -> Self {
82+
let mut tile_iter = tile_iter;
83+
let current_tile = tile_iter.next();
84+
Self {
85+
tile_iter,
86+
band_iter,
87+
current_tile,
88+
}
89+
}
90+
91+
pub fn reset(&mut self) {
92+
self.band_iter.reset();
93+
self.tile_iter.reset();
94+
self.current_tile = self.tile_iter.next();
95+
}
96+
}
97+
98+
impl Iterator for TileInformationBandCrossProductIter {
99+
type Item = (TileInformation, u32);
100+
101+
fn next(&mut self) -> Option<Self::Item> {
102+
let current_t = self.current_tile;
103+
104+
match (current_t, self.band_iter.next()) {
105+
(None, _) => None,
106+
(Some(t), Some(b)) => Some((t, b)),
107+
(Some(_t), None) => {
108+
self.band_iter.reset();
109+
self.current_tile = self.tile_iter.next();
110+
self.current_tile.map(|t| {
111+
(
112+
t,
113+
self.band_iter
114+
.next()
115+
.expect("There must be at least one band"),
116+
)
117+
})
118+
}
119+
}
120+
}
121+
}

datatypes/src/util/test.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
use float_cmp::approx_eq;
22

3-
use crate::raster::{
4-
EmptyGrid, GeoTransform, Grid, GridIndexAccess, GridOrEmpty, GridSize, MaskedGrid, Pixel,
5-
RasterTile2D, grid_idx_iter_2d,
3+
use crate::{
4+
primitives::TimeInterval,
5+
raster::{
6+
EmptyGrid, GeoTransform, Grid, GridIdx2D, GridIndexAccess, GridOrEmpty, GridSize,
7+
MaskedGrid, Pixel, RasterTile2D, grid_idx_iter_2d,
8+
},
69
};
710
use std::panic;
811

@@ -103,6 +106,10 @@ pub fn assert_eq_two_list_of_tiles<P: Pixel>(
103106
list_b: &[RasterTile2D<P>],
104107
compare_cache_hint: bool,
105108
) {
109+
fn tile_pos<T>(tile: &RasterTile2D<T>) -> (TimeInterval, GridIdx2D, u32) {
110+
(tile.time, tile.tile_position, tile.band)
111+
}
112+
106113
assert_eq!(
107114
list_a.len(),
108115
list_b.len(),
@@ -156,10 +163,12 @@ pub fn assert_eq_two_list_of_tiles<P: Pixel>(
156163
assert_eq!(
157164
a.grid_array.is_empty(),
158165
b.grid_array.is_empty(),
159-
"grid shape of tile {} input_a is_empty: {:?}, input_b is_empty: {:?}",
166+
"grid shape of tile {} input_a is_empty: {:?}, input_b is_empty: {:?}, a info: {:?}, b info: {:?}",
160167
i,
161168
a.grid_array.is_empty(),
162169
b.grid_array.is_empty(),
170+
tile_pos(a),
171+
tile_pos(b)
163172
);
164173
if !a.grid_array.is_empty() {
165174
let mat_a = a.grid_array.clone().into_materialized_masked_grid();

operators/src/adapters/mod.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,22 @@ mod band_extractor;
22
mod feature_collection_merger;
33
mod raster_stacker;
44
mod raster_subquery;
5-
mod raster_time;
65
mod raster_time_substream;
76
mod simple_raster_stacker;
8-
mod sparse_tiles_fill_adapter;
97
mod stream_statistics_adapter;
108
mod time_stream_merge;
119

1210
use band_extractor::BandExtractor;
1311
pub use feature_collection_merger::FeatureCollectionChunkMerger;
14-
pub use raster_stacker::{RasterStackerAdapter, RasterStackerSource};
12+
pub use raster_stacker::{
13+
PartialQueryRect, QueryWrapper, RasterStackerAdapter, RasterStackerSource,
14+
};
1515
pub use raster_subquery::{
1616
FoldTileAccu, FoldTileAccuMut, RasterSubQueryAdapter, SubQueryTileAggregator,
1717
TileReprojectionSubQuery, TileReprojectionSubqueryGridInfo, fold_by_coordinate_lookup_future,
1818
};
19-
pub use raster_time::{QueryWrapper, Queryable, RasterArrayTimeAdapter, RasterTimeAdapter};
2019
pub use simple_raster_stacker::{
21-
SimpleRasterStackerAdapter, SimpleRasterStackerSource, stack_individual_aligned_raster_bands,
22-
};
23-
pub(crate) use sparse_tiles_fill_adapter::{
24-
FillerTileCacheExpirationStrategy, FillerTimeBounds, SparseTilesFillAdapter,
25-
SparseTilesFillAdapterError,
20+
SimpleRasterStackerAdapter, SimpleRasterStackerError, SimpleRasterStackerSource,
2621
};
2722
pub use stream_statistics_adapter::StreamStatisticsAdapter;
2823
pub use time_stream_merge::TimeIntervalStreamMerge;

0 commit comments

Comments
 (0)