• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

geo-engine / geoengine / 3929938005

pending completion
3929938005

push

github

GitHub
Merge #713

84930 of 96741 relevant lines covered (87.79%)

79640.1 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.07
/operators/src/processing/temporal_raster_aggregation/temporal_aggregation_operator.rs
1
use super::aggregators::{
2
    CountPixelAggregator, CountPixelAggregatorIngoringNoData, FirstPixelAggregatorIngoringNoData,
3
    LastPixelAggregatorIngoringNoData, MaxPixelAggregator, MaxPixelAggregatorIngoringNoData,
4
    MeanPixelAggregator, MeanPixelAggregatorIngoringNoData, MinPixelAggregator,
5
    MinPixelAggregatorIngoringNoData, SumPixelAggregator, SumPixelAggregatorIngoringNoData,
6
    TemporalRasterPixelAggregator,
7
};
8
use super::first_last_subquery::{
9
    first_tile_fold_future, last_tile_fold_future, TemporalRasterAggregationSubQueryNoDataOnly,
10
};
11
use crate::engine::{
12
    CreateSpan, ExecutionContext, Operator, QueryProcessor, RasterOperator, SingleRasterSource,
13
};
14
use crate::{
15
    adapters::SubQueryTileAggregator,
16
    engine::{
17
        InitializedRasterOperator, OperatorName, RasterQueryProcessor, RasterResultDescriptor,
18
        TypedRasterQueryProcessor,
19
    },
20
    error,
21
    util::Result,
22
};
23
use async_trait::async_trait;
24
use geoengine_datatypes::primitives::{RasterQueryRectangle, SpatialPartition2D, TimeInstance};
25
use geoengine_datatypes::raster::{Pixel, RasterDataType, RasterTile2D};
26
use geoengine_datatypes::{primitives::TimeStep, raster::TilingSpecification};
27
use log::debug;
28
use serde::{Deserialize, Serialize};
29
use snafu::ensure;
30
use std::marker::PhantomData;
31
use tracing::{span, Level};
32
use typetag;
33

34
#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
×
35
#[serde(rename_all = "camelCase")]
36
pub struct TemporalRasterAggregationParameters {
37
    aggregation: Aggregation,
38
    window: TimeStep,
39
    /// Define an anchor point for `window`
40
    /// If `None`, the anchor point is `1970-01-01T00:00:00Z` by default
41
    window_reference: Option<TimeInstance>,
42
    /// If specified, this will be the output type.
43
    /// If not, the output type will be the same as the input type.
44
    output_type: Option<RasterDataType>,
45
}
46

47
#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
×
48
#[serde(rename_all = "camelCase")]
49
#[serde(tag = "type")]
50
pub enum Aggregation {
51
    #[serde(rename_all = "camelCase")]
52
    Min { ignore_no_data: bool },
53
    #[serde(rename_all = "camelCase")]
54
    Max { ignore_no_data: bool },
55
    #[serde(rename_all = "camelCase")]
56
    First { ignore_no_data: bool },
57
    #[serde(rename_all = "camelCase")]
58
    Last { ignore_no_data: bool },
59
    #[serde(rename_all = "camelCase")]
60
    Mean { ignore_no_data: bool },
61
    #[serde(rename_all = "camelCase")]
62
    Sum { ignore_no_data: bool },
63
    #[serde(rename_all = "camelCase")]
64
    Count { ignore_no_data: bool },
65
}
66

67
pub type TemporalRasterAggregation =
68
    Operator<TemporalRasterAggregationParameters, SingleRasterSource>;
69

70
impl OperatorName for TemporalRasterAggregation {
71
    const TYPE_NAME: &'static str = "TemporalRasterAggregation";
72
}
73

74
#[typetag::serde]
×
75
#[async_trait]
76
impl RasterOperator for TemporalRasterAggregation {
77
    async fn _initialize(
19✔
78
        self: Box<Self>,
19✔
79
        context: &dyn ExecutionContext,
19✔
80
    ) -> Result<Box<dyn InitializedRasterOperator>> {
19✔
81
        ensure!(self.params.window.step > 0, error::WindowSizeMustNotBeZero);
19✔
82

83
        let source = self.sources.raster.initialize(context).await?;
19✔
84

85
        debug!(
19✔
86
            "Initializing TemporalRasterAggregation with {:?}.",
×
87
            &self.params
×
88
        );
89

90
        let initialized_operator = InitializedTemporalRasterAggregation {
19✔
91
            aggregation_type: self.params.aggregation,
19✔
92
            window: self.params.window,
19✔
93
            window_reference: self
19✔
94
                .params
19✔
95
                .window_reference
19✔
96
                .unwrap_or(TimeInstance::EPOCH_START),
19✔
97
            result_descriptor: source.result_descriptor().clone(),
19✔
98
            source,
19✔
99
            tiling_specification: context.tiling_specification(),
19✔
100
            output_type: self.params.output_type,
19✔
101
        };
19✔
102

19✔
103
        Ok(initialized_operator.boxed())
19✔
104
    }
38✔
105

106
    span_fn!(TemporalRasterAggregation);
×
107
}
108

109
pub struct InitializedTemporalRasterAggregation {
110
    aggregation_type: Aggregation,
111
    window: TimeStep,
112
    window_reference: TimeInstance,
113
    source: Box<dyn InitializedRasterOperator>,
114
    result_descriptor: RasterResultDescriptor,
115
    tiling_specification: TilingSpecification,
116
    output_type: Option<RasterDataType>,
117
}
118

119
impl InitializedRasterOperator for InitializedTemporalRasterAggregation {
120
    fn result_descriptor(&self) -> &RasterResultDescriptor {
×
121
        &self.result_descriptor
×
122
    }
×
123

124
    fn query_processor(&self) -> Result<TypedRasterQueryProcessor> {
19✔
125
        let source_processor = self.source.query_processor()?;
19✔
126

127
        let source_processor: TypedRasterQueryProcessor = match self.output_type {
19✔
128
            Some(RasterDataType::U8) => source_processor.into_u8().into(),
×
129
            Some(RasterDataType::U16) => source_processor.into_u16().into(),
1✔
130
            Some(RasterDataType::U32) => source_processor.into_u32().into(),
×
131
            Some(RasterDataType::U64) => source_processor.into_u64().into(),
×
132
            Some(RasterDataType::I8) => source_processor.into_i8().into(),
×
133
            Some(RasterDataType::I16) => source_processor.into_i16().into(),
×
134
            Some(RasterDataType::I32) => source_processor.into_i32().into(),
×
135
            Some(RasterDataType::I64) => source_processor.into_i64().into(),
×
136
            Some(RasterDataType::F32) => source_processor.into_f32().into(),
×
137
            Some(RasterDataType::F64) => source_processor.into_f64().into(),
×
138
            // use the same output type as the input type
139
            None => source_processor,
18✔
140
        };
141

142
        let res = call_on_generic_raster_processor!(
19✔
143
            source_processor, p =>
19✔
144
            TemporalRasterAggregationProcessor::new(
145
                self.aggregation_type,
19✔
146
                self.window,
19✔
147
                self.window_reference,
19✔
148
                p,
19✔
149
                self.tiling_specification,
19✔
150
            ).boxed()
19✔
151
            .into()
19✔
152
        );
153

154
        Ok(res)
19✔
155
    }
19✔
156
}
157

158
pub struct TemporalRasterAggregationProcessor<Q, P>
159
where
160
    Q: RasterQueryProcessor<RasterType = P>,
161
    P: Pixel,
162
{
163
    aggregation_type: Aggregation,
164
    window: TimeStep,
165
    window_reference: TimeInstance,
166
    source: Q,
167
    tiling_specification: TilingSpecification,
168
}
169

170
impl<Q, P> TemporalRasterAggregationProcessor<Q, P>
171
where
172
    Q: RasterQueryProcessor<RasterType = P>,
173
    P: Pixel,
174
{
175
    fn new(
19✔
176
        aggregation_type: Aggregation,
19✔
177
        window: TimeStep,
19✔
178
        window_reference: TimeInstance,
19✔
179
        source: Q,
19✔
180
        tiling_specification: TilingSpecification,
19✔
181
    ) -> Self {
19✔
182
        Self {
19✔
183
            aggregation_type,
19✔
184
            window,
19✔
185
            window_reference,
19✔
186
            source,
19✔
187
            tiling_specification,
19✔
188
        }
19✔
189
    }
19✔
190

191
    fn create_subquery<F: TemporalRasterPixelAggregator<P> + 'static, FoldFn>(
16✔
192
        &self,
16✔
193
        fold_fn: FoldFn,
16✔
194
    ) -> super::subquery::TemporalRasterAggregationSubQuery<FoldFn, P, F> {
16✔
195
        super::subquery::TemporalRasterAggregationSubQuery {
16✔
196
            fold_fn,
16✔
197
            step: self.window,
16✔
198
            step_reference: self.window_reference,
16✔
199
            _phantom_pixel_type: PhantomData,
16✔
200
        }
16✔
201
    }
16✔
202

203
    fn create_subquery_first<F>(
1✔
204
        &self,
1✔
205
        fold_fn: F,
1✔
206
    ) -> TemporalRasterAggregationSubQueryNoDataOnly<F, P> {
1✔
207
        TemporalRasterAggregationSubQueryNoDataOnly {
1✔
208
            fold_fn,
1✔
209
            step: self.window,
1✔
210
            step_reference: self.window_reference,
1✔
211
            _phantom_pixel_type: PhantomData,
1✔
212
        }
1✔
213
    }
1✔
214

215
    fn create_subquery_last<F>(
2✔
216
        &self,
2✔
217
        fold_fn: F,
2✔
218
    ) -> TemporalRasterAggregationSubQueryNoDataOnly<F, P> {
2✔
219
        TemporalRasterAggregationSubQueryNoDataOnly {
2✔
220
            fold_fn,
2✔
221
            step: self.window,
2✔
222
            step_reference: self.window_reference,
2✔
223
            _phantom_pixel_type: PhantomData,
2✔
224
        }
2✔
225
    }
2✔
226
}
227

228
#[async_trait]
229
impl<Q, P> QueryProcessor for TemporalRasterAggregationProcessor<Q, P>
230
where
231
    Q: QueryProcessor<Output = RasterTile2D<P>, SpatialBounds = SpatialPartition2D>,
232
    P: Pixel,
233
{
234
    type Output = RasterTile2D<P>;
235
    type SpatialBounds = SpatialPartition2D;
236

237
    #[allow(clippy::too_many_lines)]
238
    async fn _query<'a>(
19✔
239
        &'a self,
19✔
240
        query: RasterQueryRectangle,
19✔
241
        ctx: &'a dyn crate::engine::QueryContext,
19✔
242
    ) -> Result<futures::stream::BoxStream<'a, Result<Self::Output>>> {
19✔
243
        match self.aggregation_type {
19✔
244
            Aggregation::Min {
245
                ignore_no_data: true,
246
            } => Ok(self
×
247
                .create_subquery(
×
248
                    super::subquery::subquery_all_tiles_fold_fn::<
×
249
                        P,
×
250
                        MinPixelAggregatorIngoringNoData,
×
251
                    >,
×
252
                )
×
253
                .into_raster_subquery_adapter(&self.source, query, ctx, self.tiling_specification)
×
254
                .expect("no tiles must be skipped in Aggregation::Min")),
×
255
            Aggregation::Min {
256
                ignore_no_data: false,
257
            } => Ok(self
1✔
258
                .create_subquery(
1✔
259
                    super::subquery::subquery_all_tiles_fold_fn::<P, MinPixelAggregator>,
1✔
260
                )
1✔
261
                .into_raster_subquery_adapter(&self.source, query, ctx, self.tiling_specification)
1✔
262
                .expect("no tiles must be skipped in Aggregation::Min")),
1✔
263
            Aggregation::Max {
264
                ignore_no_data: true,
265
            } => Ok(self
1✔
266
                .create_subquery(
1✔
267
                    super::subquery::subquery_all_tiles_fold_fn::<
1✔
268
                        P,
1✔
269
                        MaxPixelAggregatorIngoringNoData,
1✔
270
                    >,
1✔
271
                )
1✔
272
                .into_raster_subquery_adapter(&self.source, query, ctx, self.tiling_specification)
1✔
273
                .expect("no tiles must be skipped in Aggregation::Max")),
1✔
274
            Aggregation::Max {
275
                ignore_no_data: false,
276
            } => Ok(self
3✔
277
                .create_subquery(
3✔
278
                    super::subquery::subquery_all_tiles_fold_fn::<P, MaxPixelAggregator>,
3✔
279
                )
3✔
280
                .into_raster_subquery_adapter(&self.source, query, ctx, self.tiling_specification)
3✔
281
                .expect("no tiles must be skipped in Aggregation::Max")),
3✔
282

283
            Aggregation::First {
284
                ignore_no_data: true,
285
            } => Ok(self
1✔
286
                .create_subquery(
1✔
287
                    super::subquery::subquery_all_tiles_fold_fn::<
1✔
288
                        P,
1✔
289
                        FirstPixelAggregatorIngoringNoData,
1✔
290
                    >,
1✔
291
                )
1✔
292
                .into_raster_subquery_adapter(&self.source, query, ctx, self.tiling_specification)
1✔
293
                .expect("no tiles must be skipped in Aggregation::First")),
1✔
294
            Aggregation::First {
295
                ignore_no_data: false,
296
            } => Ok(self
1✔
297
                .create_subquery_first(first_tile_fold_future::<P>)
1✔
298
                .into_raster_subquery_adapter(&self.source, query, ctx, self.tiling_specification)
1✔
299
                .expect("no tiles must be skipped in Aggregation::First")),
1✔
300
            Aggregation::Last {
301
                ignore_no_data: true,
302
            } => Ok(self
1✔
303
                .create_subquery(
1✔
304
                    super::subquery::subquery_all_tiles_fold_fn::<
1✔
305
                        P,
1✔
306
                        LastPixelAggregatorIngoringNoData,
1✔
307
                    >,
1✔
308
                )
1✔
309
                .into_raster_subquery_adapter(&self.source, query, ctx, self.tiling_specification)
1✔
310
                .expect("no tiles must be skipped in Aggregation::Last")),
1✔
311

312
            Aggregation::Last {
313
                ignore_no_data: false,
314
            } => Ok(self
2✔
315
                .create_subquery_last(last_tile_fold_future::<P>)
2✔
316
                .into_raster_subquery_adapter(&self.source, query, ctx, self.tiling_specification)
2✔
317
                .expect("no tiles must be skipped in Aggregation::Last")),
2✔
318

319
            Aggregation::Mean {
320
                ignore_no_data: true,
321
            } => Ok(self
1✔
322
                .create_subquery(
1✔
323
                    super::subquery::subquery_all_tiles_fold_fn::<
1✔
324
                        P,
1✔
325
                        MeanPixelAggregatorIngoringNoData,
1✔
326
                    >,
1✔
327
                )
1✔
328
                .into_raster_subquery_adapter(&self.source, query, ctx, self.tiling_specification)
1✔
329
                .expect("no tiles must be skipped in Aggregation::Mean")),
1✔
330

331
            Aggregation::Mean {
332
                ignore_no_data: false,
333
            } => Ok(self
1✔
334
                .create_subquery(
1✔
335
                    super::subquery::subquery_all_tiles_fold_fn::<P, MeanPixelAggregator>,
1✔
336
                )
1✔
337
                .into_raster_subquery_adapter(&self.source, query, ctx, self.tiling_specification)
1✔
338
                .expect("no tiles must be skipped in Aggregation::Mean")),
1✔
339

340
            Aggregation::Sum {
341
                ignore_no_data: true,
342
            } => Ok(self
1✔
343
                .create_subquery(
1✔
344
                    super::subquery::subquery_all_tiles_fold_fn::<
1✔
345
                        P,
1✔
346
                        SumPixelAggregatorIngoringNoData,
1✔
347
                    >,
1✔
348
                )
1✔
349
                .into_raster_subquery_adapter(&self.source, query, ctx, self.tiling_specification)
1✔
350
                .expect("no tiles must be skipped in Aggregation::Sum")),
1✔
351

352
            Aggregation::Sum {
353
                ignore_no_data: false,
354
            } => Ok(self
3✔
355
                .create_subquery(
3✔
356
                    super::subquery::subquery_all_tiles_fold_fn::<P, SumPixelAggregator>,
3✔
357
                )
3✔
358
                .into_raster_subquery_adapter(&self.source, query, ctx, self.tiling_specification)
3✔
359
                .expect("no tiles must be skipped in Aggregation::Sum")),
3✔
360

361
            Aggregation::Count {
362
                ignore_no_data: true,
363
            } => Ok(self
1✔
364
                .create_subquery(
1✔
365
                    super::subquery::subquery_all_tiles_fold_fn::<
1✔
366
                        P,
1✔
367
                        CountPixelAggregatorIngoringNoData,
1✔
368
                    >,
1✔
369
                )
1✔
370
                .into_raster_subquery_adapter(&self.source, query, ctx, self.tiling_specification)
1✔
371
                .expect("no tiles must be skipped in Aggregation::Sum")),
1✔
372

373
            Aggregation::Count {
374
                ignore_no_data: false,
375
            } => Ok(self
2✔
376
                .create_subquery(
2✔
377
                    super::subquery::subquery_all_tiles_fold_fn::<P, CountPixelAggregator>,
2✔
378
                )
2✔
379
                .into_raster_subquery_adapter(&self.source, query, ctx, self.tiling_specification)
2✔
380
                .expect("no tiles must be skipped in Aggregation::Sum")),
2✔
381
        }
382
    }
38✔
383
}
384

385
#[cfg(test)]
386
mod tests {
387
    use futures::stream::StreamExt;
388
    use geoengine_datatypes::{
389
        primitives::{Measurement, SpatialResolution, TimeInterval},
390
        raster::{
391
            EmptyGrid, EmptyGrid2D, Grid2D, GridOrEmpty, MaskedGrid2D, RasterDataType,
392
            TileInformation,
393
        },
394
        spatial_reference::SpatialReference,
395
        util::test::TestDefault,
396
    };
397

398
    use crate::{
399
        engine::{MockExecutionContext, MockQueryContext},
400
        mock::{MockRasterSource, MockRasterSourceParams},
401
        processing::{Expression, ExpressionParams, ExpressionSources},
402
    };
403

404
    use super::*;
405

406
    #[tokio::test]
1✔
407
    #[allow(clippy::too_many_lines)]
408
    async fn test_min() {
1✔
409
        let raster_tiles = make_raster();
1✔
410

1✔
411
        let mrs = MockRasterSource {
1✔
412
            params: MockRasterSourceParams {
1✔
413
                data: raster_tiles,
1✔
414
                result_descriptor: RasterResultDescriptor {
1✔
415
                    data_type: RasterDataType::U8,
1✔
416
                    spatial_reference: SpatialReference::epsg_4326().into(),
1✔
417
                    measurement: Measurement::Unitless,
1✔
418
                    time: None,
1✔
419
                    bbox: None,
1✔
420
                    resolution: None,
1✔
421
                },
1✔
422
            },
1✔
423
        }
1✔
424
        .boxed();
1✔
425

1✔
426
        let agg = TemporalRasterAggregation {
1✔
427
            params: TemporalRasterAggregationParameters {
1✔
428
                aggregation: Aggregation::Min {
1✔
429
                    ignore_no_data: false,
1✔
430
                },
1✔
431
                window: TimeStep {
1✔
432
                    granularity: geoengine_datatypes::primitives::TimeGranularity::Millis,
1✔
433
                    step: 20,
1✔
434
                },
1✔
435
                window_reference: None,
1✔
436
                output_type: None,
1✔
437
            },
1✔
438
            sources: SingleRasterSource { raster: mrs },
1✔
439
        }
1✔
440
        .boxed();
1✔
441

1✔
442
        let exe_ctx = MockExecutionContext::new_with_tiling_spec(TilingSpecification::new(
1✔
443
            (0., 0.).into(),
1✔
444
            [3, 2].into(),
1✔
445
        ));
1✔
446
        let query_rect = RasterQueryRectangle {
1✔
447
            spatial_bounds: SpatialPartition2D::new_unchecked((0., 3.).into(), (4., 0.).into()),
1✔
448
            time_interval: TimeInterval::new_unchecked(0, 40),
1✔
449
            spatial_resolution: SpatialResolution::one(),
1✔
450
        };
1✔
451
        let query_ctx = MockQueryContext::test_default();
1✔
452

453
        let qp = agg
1✔
454
            .initialize(&exe_ctx)
1✔
455
            .await
×
456
            .unwrap()
1✔
457
            .query_processor()
1✔
458
            .unwrap()
1✔
459
            .get_u8()
1✔
460
            .unwrap();
1✔
461

462
        let result = qp
1✔
463
            .query(query_rect, &query_ctx)
1✔
464
            .await
×
465
            .unwrap()
1✔
466
            .collect::<Vec<_>>()
1✔
467
            .await;
8✔
468

469
        assert_eq!(result.len(), 4);
1✔
470

471
        assert_eq!(
1✔
472
            result[0].as_ref().unwrap(),
1✔
473
            &RasterTile2D::new_with_tile_info(
1✔
474
                TimeInterval::new_unchecked(0, 20),
1✔
475
                TileInformation {
1✔
476
                    global_tile_position: [-1, 0].into(),
1✔
477
                    tile_size_in_pixels: [3, 2].into(),
1✔
478
                    global_geo_transform: TestDefault::test_default(),
1✔
479
                },
1✔
480
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![1, 2, 3, 4, 5, 6]).unwrap()),
1✔
481
            )
1✔
482
        );
1✔
483

484
        assert_eq!(
1✔
485
            result[1].as_ref().unwrap(),
1✔
486
            &RasterTile2D::new_with_tile_info(
1✔
487
                TimeInterval::new_unchecked(0, 20),
1✔
488
                TileInformation {
1✔
489
                    global_tile_position: [-1, 1].into(),
1✔
490
                    tile_size_in_pixels: [3, 2].into(),
1✔
491
                    global_geo_transform: TestDefault::test_default(),
1✔
492
                },
1✔
493
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![6, 5, 4, 3, 2, 1]).unwrap()),
1✔
494
            )
1✔
495
        );
1✔
496

497
        assert_eq!(
1✔
498
            result[2].as_ref().unwrap(),
1✔
499
            &RasterTile2D::new_with_tile_info(
1✔
500
                TimeInterval::new_unchecked(20, 40),
1✔
501
                TileInformation {
1✔
502
                    global_tile_position: [-1, 0].into(),
1✔
503
                    tile_size_in_pixels: [3, 2].into(),
1✔
504
                    global_geo_transform: TestDefault::test_default(),
1✔
505
                },
1✔
506
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![1, 2, 3, 4, 5, 6]).unwrap()),
1✔
507
            )
1✔
508
        );
1✔
509

510
        assert_eq!(
1✔
511
            result[3].as_ref().unwrap(),
1✔
512
            &RasterTile2D::new_with_tile_info(
1✔
513
                TimeInterval::new_unchecked(20, 40),
1✔
514
                TileInformation {
1✔
515
                    global_tile_position: [-1, 1].into(),
1✔
516
                    tile_size_in_pixels: [3, 2].into(),
1✔
517
                    global_geo_transform: TestDefault::test_default(),
1✔
518
                },
1✔
519
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![6, 5, 4, 3, 2, 1]).unwrap()),
1✔
520
            )
1✔
521
        );
1✔
522
    }
523

524
    #[tokio::test]
1✔
525
    #[allow(clippy::too_many_lines)]
526
    async fn test_max() {
1✔
527
        let raster_tiles = make_raster();
1✔
528

1✔
529
        let mrs = MockRasterSource {
1✔
530
            params: MockRasterSourceParams {
1✔
531
                data: raster_tiles,
1✔
532
                result_descriptor: RasterResultDescriptor {
1✔
533
                    data_type: RasterDataType::U8,
1✔
534
                    spatial_reference: SpatialReference::epsg_4326().into(),
1✔
535
                    measurement: Measurement::Unitless,
1✔
536
                    time: None,
1✔
537
                    bbox: None,
1✔
538
                    resolution: None,
1✔
539
                },
1✔
540
            },
1✔
541
        }
1✔
542
        .boxed();
1✔
543

1✔
544
        let agg = TemporalRasterAggregation {
1✔
545
            params: TemporalRasterAggregationParameters {
1✔
546
                aggregation: Aggregation::Max {
1✔
547
                    ignore_no_data: false,
1✔
548
                },
1✔
549
                window: TimeStep {
1✔
550
                    granularity: geoengine_datatypes::primitives::TimeGranularity::Millis,
1✔
551
                    step: 20,
1✔
552
                },
1✔
553
                window_reference: None,
1✔
554
                output_type: None,
1✔
555
            },
1✔
556
            sources: SingleRasterSource { raster: mrs },
1✔
557
        }
1✔
558
        .boxed();
1✔
559

1✔
560
        let exe_ctx = MockExecutionContext::new_with_tiling_spec(TilingSpecification::new(
1✔
561
            (0., 0.).into(),
1✔
562
            [3, 2].into(),
1✔
563
        ));
1✔
564
        let query_rect = RasterQueryRectangle {
1✔
565
            spatial_bounds: SpatialPartition2D::new_unchecked((0., 3.).into(), (4., 0.).into()),
1✔
566
            time_interval: TimeInterval::new_unchecked(0, 40),
1✔
567
            spatial_resolution: SpatialResolution::one(),
1✔
568
        };
1✔
569
        let query_ctx = MockQueryContext::test_default();
1✔
570

571
        let qp = agg
1✔
572
            .initialize(&exe_ctx)
1✔
573
            .await
×
574
            .unwrap()
1✔
575
            .query_processor()
1✔
576
            .unwrap()
1✔
577
            .get_u8()
1✔
578
            .unwrap();
1✔
579

580
        let result = qp
1✔
581
            .query(query_rect, &query_ctx)
1✔
582
            .await
×
583
            .unwrap()
1✔
584
            .collect::<Vec<_>>()
1✔
585
            .await;
8✔
586

587
        assert_eq!(result.len(), 4);
1✔
588

589
        assert_eq!(
1✔
590
            result[0].as_ref().unwrap(),
1✔
591
            &RasterTile2D::new_with_tile_info(
1✔
592
                TimeInterval::new_unchecked(0, 20),
1✔
593
                TileInformation {
1✔
594
                    global_tile_position: [-1, 0].into(),
1✔
595
                    tile_size_in_pixels: [3, 2].into(),
1✔
596
                    global_geo_transform: TestDefault::test_default(),
1✔
597
                },
1✔
598
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![12, 11, 10, 9, 8, 7]).unwrap()),
1✔
599
            )
1✔
600
        );
1✔
601

602
        assert_eq!(
1✔
603
            result[1].as_ref().unwrap(),
1✔
604
            &RasterTile2D::new_with_tile_info(
1✔
605
                TimeInterval::new_unchecked(0, 20),
1✔
606
                TileInformation {
1✔
607
                    global_tile_position: [-1, 1].into(),
1✔
608
                    tile_size_in_pixels: [3, 2].into(),
1✔
609
                    global_geo_transform: TestDefault::test_default(),
1✔
610
                },
1✔
611
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![7, 8, 9, 10, 11, 12]).unwrap()),
1✔
612
            )
1✔
613
        );
1✔
614

615
        assert_eq!(
1✔
616
            result[2].as_ref().unwrap(),
1✔
617
            &RasterTile2D::new_with_tile_info(
1✔
618
                TimeInterval::new_unchecked(20, 40),
1✔
619
                TileInformation {
1✔
620
                    global_tile_position: [-1, 0].into(),
1✔
621
                    tile_size_in_pixels: [3, 2].into(),
1✔
622
                    global_geo_transform: TestDefault::test_default(),
1✔
623
                },
1✔
624
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![12, 11, 10, 9, 8, 7]).unwrap()),
1✔
625
            )
1✔
626
        );
1✔
627

628
        assert_eq!(
1✔
629
            result[3].as_ref().unwrap(),
1✔
630
            &RasterTile2D::new_with_tile_info(
1✔
631
                TimeInterval::new_unchecked(20, 40),
1✔
632
                TileInformation {
1✔
633
                    global_tile_position: [-1, 1].into(),
1✔
634
                    tile_size_in_pixels: [3, 2].into(),
1✔
635
                    global_geo_transform: TestDefault::test_default(),
1✔
636
                },
1✔
637
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![7, 8, 9, 10, 11, 12]).unwrap()),
1✔
638
            )
1✔
639
        );
1✔
640
    }
641

642
    #[tokio::test]
1✔
643
    #[allow(clippy::too_many_lines)]
644
    async fn test_max_with_no_data() {
1✔
645
        let raster_tiles = make_raster(); // TODO: switch to make_raster_with_no_data?
1✔
646

1✔
647
        let mrs = MockRasterSource {
1✔
648
            params: MockRasterSourceParams {
1✔
649
                data: raster_tiles,
1✔
650
                result_descriptor: RasterResultDescriptor {
1✔
651
                    data_type: RasterDataType::U8,
1✔
652
                    spatial_reference: SpatialReference::epsg_4326().into(),
1✔
653
                    measurement: Measurement::Unitless,
1✔
654
                    time: None,
1✔
655
                    bbox: None,
1✔
656
                    resolution: None,
1✔
657
                },
1✔
658
            },
1✔
659
        }
1✔
660
        .boxed();
1✔
661

1✔
662
        let agg = TemporalRasterAggregation {
1✔
663
            params: TemporalRasterAggregationParameters {
1✔
664
                aggregation: Aggregation::Max {
1✔
665
                    ignore_no_data: false,
1✔
666
                },
1✔
667
                window: TimeStep {
1✔
668
                    granularity: geoengine_datatypes::primitives::TimeGranularity::Millis,
1✔
669
                    step: 20,
1✔
670
                },
1✔
671
                window_reference: None,
1✔
672
                output_type: None,
1✔
673
            },
1✔
674
            sources: SingleRasterSource { raster: mrs },
1✔
675
        }
1✔
676
        .boxed();
1✔
677

1✔
678
        let exe_ctx = MockExecutionContext::new_with_tiling_spec(TilingSpecification::new(
1✔
679
            (0., 0.).into(),
1✔
680
            [3, 2].into(),
1✔
681
        ));
1✔
682
        let query_rect = RasterQueryRectangle {
1✔
683
            spatial_bounds: SpatialPartition2D::new_unchecked((0., 3.).into(), (4., 0.).into()),
1✔
684
            time_interval: TimeInterval::new_unchecked(0, 40),
1✔
685
            spatial_resolution: SpatialResolution::one(),
1✔
686
        };
1✔
687
        let query_ctx = MockQueryContext::test_default();
1✔
688

689
        let qp = agg
1✔
690
            .initialize(&exe_ctx)
1✔
691
            .await
×
692
            .unwrap()
1✔
693
            .query_processor()
1✔
694
            .unwrap()
1✔
695
            .get_u8()
1✔
696
            .unwrap();
1✔
697

698
        let result = qp
1✔
699
            .query(query_rect, &query_ctx)
1✔
700
            .await
×
701
            .unwrap()
1✔
702
            .collect::<Vec<_>>()
1✔
703
            .await;
8✔
704

705
        assert_eq!(result.len(), 4);
1✔
706

707
        assert_eq!(
1✔
708
            result[0].as_ref().unwrap(),
1✔
709
            &RasterTile2D::new_with_tile_info(
1✔
710
                TimeInterval::new_unchecked(0, 20),
1✔
711
                TileInformation {
1✔
712
                    global_tile_position: [-1, 0].into(),
1✔
713
                    tile_size_in_pixels: [3, 2].into(),
1✔
714
                    global_geo_transform: TestDefault::test_default(),
1✔
715
                },
1✔
716
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![12, 11, 10, 9, 8, 7],).unwrap()),
1✔
717
            )
1✔
718
        );
1✔
719

720
        assert_eq!(
1✔
721
            result[1].as_ref().unwrap(),
1✔
722
            &RasterTile2D::new_with_tile_info(
1✔
723
                TimeInterval::new_unchecked(0, 20),
1✔
724
                TileInformation {
1✔
725
                    global_tile_position: [-1, 1].into(),
1✔
726
                    tile_size_in_pixels: [3, 2].into(),
1✔
727
                    global_geo_transform: TestDefault::test_default(),
1✔
728
                },
1✔
729
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![7, 8, 9, 10, 11, 12]).unwrap()),
1✔
730
            )
1✔
731
        );
1✔
732

733
        assert_eq!(
1✔
734
            result[2].as_ref().unwrap(),
1✔
735
            &RasterTile2D::new_with_tile_info(
1✔
736
                TimeInterval::new_unchecked(20, 40),
1✔
737
                TileInformation {
1✔
738
                    global_tile_position: [-1, 0].into(),
1✔
739
                    tile_size_in_pixels: [3, 2].into(),
1✔
740
                    global_geo_transform: TestDefault::test_default(),
1✔
741
                },
1✔
742
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![12, 11, 10, 9, 8, 7]).unwrap()),
1✔
743
            )
1✔
744
        );
1✔
745

746
        assert_eq!(
1✔
747
            result[3].as_ref().unwrap(),
1✔
748
            &RasterTile2D::new_with_tile_info(
1✔
749
                TimeInterval::new_unchecked(20, 40),
1✔
750
                TileInformation {
1✔
751
                    global_tile_position: [-1, 1].into(),
1✔
752
                    tile_size_in_pixels: [3, 2].into(),
1✔
753
                    global_geo_transform: TestDefault::test_default(),
1✔
754
                },
1✔
755
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![7, 8, 9, 10, 11, 12]).unwrap()),
1✔
756
            )
1✔
757
        );
1✔
758
    }
759

760
    #[tokio::test]
1✔
761
    #[allow(clippy::too_many_lines)]
762
    async fn test_max_with_no_data_but_ignoring_it() {
1✔
763
        let raster_tiles = make_raster(); // TODO: switch to make_raster_with_no_data?
1✔
764

1✔
765
        let mrs = MockRasterSource {
1✔
766
            params: MockRasterSourceParams {
1✔
767
                data: raster_tiles,
1✔
768
                result_descriptor: RasterResultDescriptor {
1✔
769
                    data_type: RasterDataType::U8,
1✔
770
                    spatial_reference: SpatialReference::epsg_4326().into(),
1✔
771
                    measurement: Measurement::Unitless,
1✔
772
                    time: None,
1✔
773
                    bbox: None,
1✔
774
                    resolution: None,
1✔
775
                },
1✔
776
            },
1✔
777
        }
1✔
778
        .boxed();
1✔
779

1✔
780
        let agg = TemporalRasterAggregation {
1✔
781
            params: TemporalRasterAggregationParameters {
1✔
782
                aggregation: Aggregation::Max {
1✔
783
                    ignore_no_data: true,
1✔
784
                },
1✔
785
                window: TimeStep {
1✔
786
                    granularity: geoengine_datatypes::primitives::TimeGranularity::Millis,
1✔
787
                    step: 20,
1✔
788
                },
1✔
789
                window_reference: None,
1✔
790
                output_type: None,
1✔
791
            },
1✔
792
            sources: SingleRasterSource { raster: mrs },
1✔
793
        }
1✔
794
        .boxed();
1✔
795

1✔
796
        let exe_ctx = MockExecutionContext::new_with_tiling_spec(TilingSpecification::new(
1✔
797
            (0., 0.).into(),
1✔
798
            [3, 2].into(),
1✔
799
        ));
1✔
800
        let query_rect = RasterQueryRectangle {
1✔
801
            spatial_bounds: SpatialPartition2D::new_unchecked((0., 3.).into(), (4., 0.).into()),
1✔
802
            time_interval: TimeInterval::new_unchecked(0, 40),
1✔
803
            spatial_resolution: SpatialResolution::one(),
1✔
804
        };
1✔
805
        let query_ctx = MockQueryContext::test_default();
1✔
806

807
        let qp = agg
1✔
808
            .initialize(&exe_ctx)
1✔
809
            .await
×
810
            .unwrap()
1✔
811
            .query_processor()
1✔
812
            .unwrap()
1✔
813
            .get_u8()
1✔
814
            .unwrap();
1✔
815

816
        let result = qp
1✔
817
            .query(query_rect, &query_ctx)
1✔
818
            .await
×
819
            .unwrap()
1✔
820
            .collect::<Vec<_>>()
1✔
821
            .await;
8✔
822

823
        assert_eq!(result.len(), 4);
1✔
824

825
        assert_eq!(
1✔
826
            result[0].as_ref().unwrap(),
1✔
827
            &RasterTile2D::new_with_tile_info(
1✔
828
                TimeInterval::new_unchecked(0, 20),
1✔
829
                TileInformation {
1✔
830
                    global_tile_position: [-1, 0].into(),
1✔
831
                    tile_size_in_pixels: [3, 2].into(),
1✔
832
                    global_geo_transform: TestDefault::test_default(),
1✔
833
                },
1✔
834
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![12, 11, 10, 9, 8, 7]).unwrap()),
1✔
835
            )
1✔
836
        );
1✔
837

838
        assert_eq!(
1✔
839
            result[1].as_ref().unwrap(),
1✔
840
            &RasterTile2D::new_with_tile_info(
1✔
841
                TimeInterval::new_unchecked(0, 20),
1✔
842
                TileInformation {
1✔
843
                    global_tile_position: [-1, 1].into(),
1✔
844
                    tile_size_in_pixels: [3, 2].into(),
1✔
845
                    global_geo_transform: TestDefault::test_default(),
1✔
846
                },
1✔
847
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![7, 8, 9, 10, 11, 12]).unwrap()),
1✔
848
            )
1✔
849
        );
1✔
850

851
        assert_eq!(
1✔
852
            result[2].as_ref().unwrap(),
1✔
853
            &RasterTile2D::new_with_tile_info(
1✔
854
                TimeInterval::new_unchecked(20, 40),
1✔
855
                TileInformation {
1✔
856
                    global_tile_position: [-1, 0].into(),
1✔
857
                    tile_size_in_pixels: [3, 2].into(),
1✔
858
                    global_geo_transform: TestDefault::test_default(),
1✔
859
                },
1✔
860
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![12, 11, 10, 9, 8, 7]).unwrap()),
1✔
861
            )
1✔
862
        );
1✔
863

864
        assert_eq!(
1✔
865
            result[3].as_ref().unwrap(),
1✔
866
            &RasterTile2D::new_with_tile_info(
1✔
867
                TimeInterval::new_unchecked(20, 40),
1✔
868
                TileInformation {
1✔
869
                    global_tile_position: [-1, 1].into(),
1✔
870
                    tile_size_in_pixels: [3, 2].into(),
1✔
871
                    global_geo_transform: TestDefault::test_default(),
1✔
872
                },
1✔
873
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![7, 8, 9, 10, 11, 12]).unwrap()),
1✔
874
            )
1✔
875
        );
1✔
876
    }
877

878
    #[tokio::test]
1✔
879
    #[allow(clippy::too_many_lines)]
880
    async fn test_only_no_data() {
1✔
881
        let mrs = MockRasterSource {
1✔
882
            params: MockRasterSourceParams {
1✔
883
                data: vec![RasterTile2D::new_with_tile_info(
1✔
884
                    TimeInterval::new_unchecked(0, 20),
1✔
885
                    TileInformation {
1✔
886
                        global_tile_position: [-1, 0].into(),
1✔
887
                        tile_size_in_pixels: [3, 2].into(),
1✔
888
                        global_geo_transform: TestDefault::test_default(),
1✔
889
                    },
1✔
890
                    GridOrEmpty::from(EmptyGrid2D::<u8>::new([3, 2].into())),
1✔
891
                )],
1✔
892
                result_descriptor: RasterResultDescriptor {
1✔
893
                    data_type: RasterDataType::U8,
1✔
894
                    spatial_reference: SpatialReference::epsg_4326().into(),
1✔
895
                    measurement: Measurement::Unitless,
1✔
896
                    time: None,
1✔
897
                    bbox: None,
1✔
898
                    resolution: None,
1✔
899
                },
1✔
900
            },
1✔
901
        }
1✔
902
        .boxed();
1✔
903

1✔
904
        let agg = TemporalRasterAggregation {
1✔
905
            params: TemporalRasterAggregationParameters {
1✔
906
                aggregation: Aggregation::Max {
1✔
907
                    ignore_no_data: false,
1✔
908
                },
1✔
909
                window: TimeStep {
1✔
910
                    granularity: geoengine_datatypes::primitives::TimeGranularity::Millis,
1✔
911
                    step: 20,
1✔
912
                },
1✔
913
                window_reference: None,
1✔
914
                output_type: None,
1✔
915
            },
1✔
916
            sources: SingleRasterSource { raster: mrs },
1✔
917
        }
1✔
918
        .boxed();
1✔
919

1✔
920
        let exe_ctx = MockExecutionContext::new_with_tiling_spec(TilingSpecification::new(
1✔
921
            (0., 0.).into(),
1✔
922
            [3, 2].into(),
1✔
923
        ));
1✔
924
        let query_rect = RasterQueryRectangle {
1✔
925
            spatial_bounds: SpatialPartition2D::new_unchecked((0., 3.).into(), (2., 0.).into()),
1✔
926
            time_interval: TimeInterval::new_unchecked(0, 20),
1✔
927
            spatial_resolution: SpatialResolution::one(),
1✔
928
        };
1✔
929
        let query_ctx = MockQueryContext::test_default();
1✔
930

931
        let qp = agg
1✔
932
            .initialize(&exe_ctx)
1✔
933
            .await
×
934
            .unwrap()
1✔
935
            .query_processor()
1✔
936
            .unwrap()
1✔
937
            .get_u8()
1✔
938
            .unwrap();
1✔
939

940
        let result = qp
1✔
941
            .query(query_rect, &query_ctx)
1✔
942
            .await
×
943
            .unwrap()
1✔
944
            .collect::<Vec<_>>()
1✔
945
            .await;
1✔
946

947
        assert_eq!(result.len(), 1);
1✔
948

949
        assert_eq!(
1✔
950
            result[0].as_ref().unwrap(),
1✔
951
            &RasterTile2D::new_with_tile_info(
1✔
952
                TimeInterval::new_unchecked(0, 20),
1✔
953
                TileInformation {
1✔
954
                    global_tile_position: [-1, 0].into(),
1✔
955
                    tile_size_in_pixels: [3, 2].into(),
1✔
956
                    global_geo_transform: TestDefault::test_default(),
1✔
957
                },
1✔
958
                GridOrEmpty::Empty(EmptyGrid::new([3, 2].into())),
1✔
959
            )
1✔
960
        );
1✔
961
    }
962

963
    #[tokio::test]
1✔
964
    async fn test_first_with_no_data() {
1✔
965
        let raster_tiles = make_raster_with_no_data();
1✔
966

1✔
967
        let mrs = MockRasterSource {
1✔
968
            params: MockRasterSourceParams {
1✔
969
                data: raster_tiles,
1✔
970
                result_descriptor: RasterResultDescriptor {
1✔
971
                    data_type: RasterDataType::U8,
1✔
972
                    spatial_reference: SpatialReference::epsg_4326().into(),
1✔
973
                    measurement: Measurement::Unitless,
1✔
974
                    time: None,
1✔
975
                    bbox: None,
1✔
976
                    resolution: None,
1✔
977
                },
1✔
978
            },
1✔
979
        }
1✔
980
        .boxed();
1✔
981

1✔
982
        let agg = TemporalRasterAggregation {
1✔
983
            params: TemporalRasterAggregationParameters {
1✔
984
                aggregation: Aggregation::First {
1✔
985
                    ignore_no_data: true,
1✔
986
                },
1✔
987
                window: TimeStep {
1✔
988
                    granularity: geoengine_datatypes::primitives::TimeGranularity::Millis,
1✔
989
                    step: 30,
1✔
990
                },
1✔
991
                window_reference: None,
1✔
992
                output_type: None,
1✔
993
            },
1✔
994
            sources: SingleRasterSource { raster: mrs },
1✔
995
        }
1✔
996
        .boxed();
1✔
997

1✔
998
        let exe_ctx = MockExecutionContext::new_with_tiling_spec(TilingSpecification::new(
1✔
999
            (0., 0.).into(),
1✔
1000
            [3, 2].into(),
1✔
1001
        ));
1✔
1002
        let query_rect = RasterQueryRectangle {
1✔
1003
            spatial_bounds: SpatialPartition2D::new_unchecked((0., 3.).into(), (4., 0.).into()),
1✔
1004
            time_interval: TimeInterval::new_unchecked(0, 30),
1✔
1005
            spatial_resolution: SpatialResolution::one(),
1✔
1006
        };
1✔
1007
        let query_ctx = MockQueryContext::test_default();
1✔
1008

1009
        let qp = agg
1✔
1010
            .initialize(&exe_ctx)
1✔
1011
            .await
×
1012
            .unwrap()
1✔
1013
            .query_processor()
1✔
1014
            .unwrap()
1✔
1015
            .get_u8()
1✔
1016
            .unwrap();
1✔
1017

1018
        let result = qp
1✔
1019
            .query(query_rect, &query_ctx)
1✔
1020
            .await
×
1021
            .unwrap()
1✔
1022
            .collect::<Vec<_>>()
1✔
1023
            .await;
6✔
1024

1025
        assert_eq!(result.len(), 2);
1✔
1026

1027
        assert_eq!(
1✔
1028
            result[0].as_ref().unwrap(),
1✔
1029
            &RasterTile2D::new_with_tile_info(
1✔
1030
                TimeInterval::new_unchecked(0, 30),
1✔
1031
                TileInformation {
1✔
1032
                    global_tile_position: [-1, 0].into(),
1✔
1033
                    tile_size_in_pixels: [3, 2].into(),
1✔
1034
                    global_geo_transform: TestDefault::test_default(),
1✔
1035
                },
1✔
1036
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![7, 8, 9, 16, 11, 12]).unwrap()),
1✔
1037
            )
1✔
1038
        );
1✔
1039

1040
        assert_eq!(
1✔
1041
            result[1].as_ref().unwrap(),
1✔
1042
            &RasterTile2D::new_with_tile_info(
1✔
1043
                TimeInterval::new_unchecked(0, 30),
1✔
1044
                TileInformation {
1✔
1045
                    global_tile_position: [-1, 1].into(),
1✔
1046
                    tile_size_in_pixels: [3, 2].into(),
1✔
1047
                    global_geo_transform: TestDefault::test_default(),
1✔
1048
                },
1✔
1049
                GridOrEmpty::from(
1✔
1050
                    MaskedGrid2D::new(
1✔
1051
                        Grid2D::new([3, 2].into(), vec![1, 2, 3, 0, 5, 6]).unwrap(),
1✔
1052
                        Grid2D::new([3, 2].into(), vec![true, true, true, false, true, true])
1✔
1053
                            .unwrap()
1✔
1054
                    )
1✔
1055
                    .unwrap()
1✔
1056
                ),
1✔
1057
            )
1✔
1058
        );
1✔
1059
    }
1060

1061
    #[tokio::test]
1✔
1062
    async fn test_last_with_no_data() {
1✔
1063
        let raster_tiles = make_raster_with_no_data();
1✔
1064

1✔
1065
        let mrs = MockRasterSource {
1✔
1066
            params: MockRasterSourceParams {
1✔
1067
                data: raster_tiles,
1✔
1068
                result_descriptor: RasterResultDescriptor {
1✔
1069
                    data_type: RasterDataType::U8,
1✔
1070
                    spatial_reference: SpatialReference::epsg_4326().into(),
1✔
1071
                    measurement: Measurement::Unitless,
1✔
1072
                    time: None,
1✔
1073
                    bbox: None,
1✔
1074
                    resolution: None,
1✔
1075
                },
1✔
1076
            },
1✔
1077
        }
1✔
1078
        .boxed();
1✔
1079

1✔
1080
        let agg = TemporalRasterAggregation {
1✔
1081
            params: TemporalRasterAggregationParameters {
1✔
1082
                aggregation: Aggregation::Last {
1✔
1083
                    ignore_no_data: true,
1✔
1084
                },
1✔
1085
                window: TimeStep {
1✔
1086
                    granularity: geoengine_datatypes::primitives::TimeGranularity::Millis,
1✔
1087
                    step: 30,
1✔
1088
                },
1✔
1089
                window_reference: None,
1✔
1090
                output_type: None,
1✔
1091
            },
1✔
1092
            sources: SingleRasterSource { raster: mrs },
1✔
1093
        }
1✔
1094
        .boxed();
1✔
1095

1✔
1096
        let exe_ctx = MockExecutionContext::new_with_tiling_spec(TilingSpecification::new(
1✔
1097
            (0., 0.).into(),
1✔
1098
            [3, 2].into(),
1✔
1099
        ));
1✔
1100
        let query_rect = RasterQueryRectangle {
1✔
1101
            spatial_bounds: SpatialPartition2D::new_unchecked((0., 3.).into(), (4., 0.).into()),
1✔
1102
            time_interval: TimeInterval::new_unchecked(0, 30),
1✔
1103
            spatial_resolution: SpatialResolution::one(),
1✔
1104
        };
1✔
1105
        let query_ctx = MockQueryContext::test_default();
1✔
1106

1107
        let qp = agg
1✔
1108
            .initialize(&exe_ctx)
1✔
1109
            .await
×
1110
            .unwrap()
1✔
1111
            .query_processor()
1✔
1112
            .unwrap()
1✔
1113
            .get_u8()
1✔
1114
            .unwrap();
1✔
1115

1116
        let result = qp
1✔
1117
            .query(query_rect, &query_ctx)
1✔
1118
            .await
×
1119
            .unwrap()
1✔
1120
            .collect::<Vec<_>>()
1✔
1121
            .await;
6✔
1122

1123
        assert_eq!(result.len(), 2);
1✔
1124

1125
        assert_eq!(
1✔
1126
            result[0].as_ref().unwrap(),
1✔
1127
            &RasterTile2D::new_with_tile_info(
1✔
1128
                TimeInterval::new_unchecked(0, 30),
1✔
1129
                TileInformation {
1✔
1130
                    global_tile_position: [-1, 0].into(),
1✔
1131
                    tile_size_in_pixels: [3, 2].into(),
1✔
1132
                    global_geo_transform: TestDefault::test_default(),
1✔
1133
                },
1✔
1134
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![13, 8, 15, 16, 17, 18]).unwrap()),
1✔
1135
            )
1✔
1136
        );
1✔
1137

1138
        assert_eq!(
1✔
1139
            result[1].as_ref().unwrap(),
1✔
1140
            &RasterTile2D::new_with_tile_info(
1✔
1141
                TimeInterval::new_unchecked(0, 30),
1✔
1142
                TileInformation {
1✔
1143
                    global_tile_position: [-1, 1].into(),
1✔
1144
                    tile_size_in_pixels: [3, 2].into(),
1✔
1145
                    global_geo_transform: TestDefault::test_default(),
1✔
1146
                },
1✔
1147
                GridOrEmpty::from(
1✔
1148
                    MaskedGrid2D::new(
1✔
1149
                        Grid2D::new([3, 2].into(), vec![1, 2, 3, 0, 5, 6]).unwrap(),
1✔
1150
                        Grid2D::new([3, 2].into(), vec![true, true, true, false, true, true])
1✔
1151
                            .unwrap()
1✔
1152
                    )
1✔
1153
                    .unwrap()
1✔
1154
                ),
1✔
1155
            )
1✔
1156
        );
1✔
1157
    }
1158

1159
    #[tokio::test]
1✔
1160
    async fn test_last() {
1✔
1161
        let raster_tiles = make_raster_with_no_data();
1✔
1162

1✔
1163
        let mrs = MockRasterSource {
1✔
1164
            params: MockRasterSourceParams {
1✔
1165
                data: raster_tiles,
1✔
1166
                result_descriptor: RasterResultDescriptor {
1✔
1167
                    data_type: RasterDataType::U8,
1✔
1168
                    spatial_reference: SpatialReference::epsg_4326().into(),
1✔
1169
                    measurement: Measurement::Unitless,
1✔
1170
                    time: None,
1✔
1171
                    bbox: None,
1✔
1172
                    resolution: None,
1✔
1173
                },
1✔
1174
            },
1✔
1175
        }
1✔
1176
        .boxed();
1✔
1177

1✔
1178
        let agg = TemporalRasterAggregation {
1✔
1179
            params: TemporalRasterAggregationParameters {
1✔
1180
                aggregation: Aggregation::Last {
1✔
1181
                    ignore_no_data: false,
1✔
1182
                },
1✔
1183
                window: TimeStep {
1✔
1184
                    granularity: geoengine_datatypes::primitives::TimeGranularity::Millis,
1✔
1185
                    step: 30,
1✔
1186
                },
1✔
1187
                window_reference: None,
1✔
1188
                output_type: None,
1✔
1189
            },
1✔
1190
            sources: SingleRasterSource { raster: mrs },
1✔
1191
        }
1✔
1192
        .boxed();
1✔
1193

1✔
1194
        let exe_ctx = MockExecutionContext::new_with_tiling_spec(TilingSpecification::new(
1✔
1195
            (0., 0.).into(),
1✔
1196
            [3, 2].into(),
1✔
1197
        ));
1✔
1198
        let query_rect = RasterQueryRectangle {
1✔
1199
            spatial_bounds: SpatialPartition2D::new_unchecked((0., 3.).into(), (4., 0.).into()),
1✔
1200
            time_interval: TimeInterval::new_unchecked(0, 30),
1✔
1201
            spatial_resolution: SpatialResolution::one(),
1✔
1202
        };
1✔
1203
        let query_ctx = MockQueryContext::test_default();
1✔
1204

1205
        let qp = agg
1✔
1206
            .initialize(&exe_ctx)
1✔
1207
            .await
×
1208
            .unwrap()
1✔
1209
            .query_processor()
1✔
1210
            .unwrap()
1✔
1211
            .get_u8()
1✔
1212
            .unwrap();
1✔
1213

1214
        let result = qp
1✔
1215
            .query(query_rect, &query_ctx)
1✔
1216
            .await
×
1217
            .unwrap()
1✔
1218
            .collect::<Vec<_>>()
1✔
1219
            .await;
8✔
1220

1221
        assert_eq!(result.len(), 2);
1✔
1222

1223
        assert_eq!(
1✔
1224
            result[0].as_ref().unwrap(),
1✔
1225
            &RasterTile2D::new_with_tile_info(
1✔
1226
                TimeInterval::new_unchecked(0, 30),
1✔
1227
                TileInformation {
1✔
1228
                    global_tile_position: [-1, 0].into(),
1✔
1229
                    tile_size_in_pixels: [3, 2].into(),
1✔
1230
                    global_geo_transform: TestDefault::test_default(),
1✔
1231
                },
1✔
1232
                GridOrEmpty::from(
1✔
1233
                    MaskedGrid2D::new(
1✔
1234
                        Grid2D::new([3, 2].into(), vec![13, 42, 15, 16, 17, 18]).unwrap(),
1✔
1235
                        Grid2D::new([3, 2].into(), vec![true, false, true, true, true, true])
1✔
1236
                            .unwrap()
1✔
1237
                    )
1✔
1238
                    .unwrap()
1✔
1239
                )
1✔
1240
            )
1✔
1241
        );
1✔
1242

1243
        assert_eq!(
1✔
1244
            result[1].as_ref().unwrap(),
1✔
1245
            &RasterTile2D::new_with_tile_info(
1✔
1246
                TimeInterval::new_unchecked(0, 30),
1✔
1247
                TileInformation {
1✔
1248
                    global_tile_position: [-1, 1].into(),
1✔
1249
                    tile_size_in_pixels: [3, 2].into(),
1✔
1250
                    global_geo_transform: TestDefault::test_default(),
1✔
1251
                },
1✔
1252
                GridOrEmpty::Empty(EmptyGrid2D::new([3, 2].into()))
1✔
1253
            )
1✔
1254
        );
1✔
1255
    }
1256

1257
    #[tokio::test]
1✔
1258
    async fn test_first() {
1✔
1259
        let raster_tiles = make_raster_with_no_data();
1✔
1260

1✔
1261
        let mrs = MockRasterSource {
1✔
1262
            params: MockRasterSourceParams {
1✔
1263
                data: raster_tiles,
1✔
1264
                result_descriptor: RasterResultDescriptor {
1✔
1265
                    data_type: RasterDataType::U8,
1✔
1266
                    spatial_reference: SpatialReference::epsg_4326().into(),
1✔
1267
                    measurement: Measurement::Unitless,
1✔
1268
                    time: None,
1✔
1269
                    bbox: None,
1✔
1270
                    resolution: None,
1✔
1271
                },
1✔
1272
            },
1✔
1273
        }
1✔
1274
        .boxed();
1✔
1275

1✔
1276
        let agg = TemporalRasterAggregation {
1✔
1277
            params: TemporalRasterAggregationParameters {
1✔
1278
                aggregation: Aggregation::First {
1✔
1279
                    ignore_no_data: false,
1✔
1280
                },
1✔
1281
                window: TimeStep {
1✔
1282
                    granularity: geoengine_datatypes::primitives::TimeGranularity::Millis,
1✔
1283
                    step: 30,
1✔
1284
                },
1✔
1285
                window_reference: None,
1✔
1286
                output_type: None,
1✔
1287
            },
1✔
1288
            sources: SingleRasterSource { raster: mrs },
1✔
1289
        }
1✔
1290
        .boxed();
1✔
1291

1✔
1292
        let exe_ctx = MockExecutionContext::new_with_tiling_spec(TilingSpecification::new(
1✔
1293
            (0., 0.).into(),
1✔
1294
            [3, 2].into(),
1✔
1295
        ));
1✔
1296
        let query_rect = RasterQueryRectangle {
1✔
1297
            spatial_bounds: SpatialPartition2D::new_unchecked((0., 3.).into(), (4., 0.).into()),
1✔
1298
            time_interval: TimeInterval::new_unchecked(0, 30),
1✔
1299
            spatial_resolution: SpatialResolution::one(),
1✔
1300
        };
1✔
1301
        let query_ctx = MockQueryContext::test_default();
1✔
1302

1303
        let qp = agg
1✔
1304
            .initialize(&exe_ctx)
1✔
1305
            .await
×
1306
            .unwrap()
1✔
1307
            .query_processor()
1✔
1308
            .unwrap()
1✔
1309
            .get_u8()
1✔
1310
            .unwrap();
1✔
1311

1312
        let result = qp
1✔
1313
            .query(query_rect, &query_ctx)
1✔
1314
            .await
×
1315
            .unwrap()
1✔
1316
            .collect::<Vec<_>>()
1✔
1317
            .await;
8✔
1318

1319
        assert_eq!(result.len(), 2);
1✔
1320

1321
        assert_eq!(
1✔
1322
            result[0].as_ref().unwrap(),
1✔
1323
            &RasterTile2D::new_with_tile_info(
1✔
1324
                TimeInterval::new_unchecked(0, 30),
1✔
1325
                TileInformation {
1✔
1326
                    global_tile_position: [-1, 0].into(),
1✔
1327
                    tile_size_in_pixels: [3, 2].into(),
1✔
1328
                    global_geo_transform: TestDefault::test_default(),
1✔
1329
                },
1✔
1330
                GridOrEmpty::from(EmptyGrid2D::new([3, 2].into()))
1✔
1331
            )
1✔
1332
        );
1✔
1333

1334
        assert_eq!(
1✔
1335
            result[1].as_ref().unwrap(),
1✔
1336
            &RasterTile2D::new_with_tile_info(
1✔
1337
                TimeInterval::new_unchecked(0, 30),
1✔
1338
                TileInformation {
1✔
1339
                    global_tile_position: [-1, 1].into(),
1✔
1340
                    tile_size_in_pixels: [3, 2].into(),
1✔
1341
                    global_geo_transform: TestDefault::test_default(),
1✔
1342
                },
1✔
1343
                GridOrEmpty::from(
1✔
1344
                    MaskedGrid2D::new(
1✔
1345
                        Grid2D::new([3, 2].into(), vec![1, 2, 3, 42, 5, 6]).unwrap(),
1✔
1346
                        Grid2D::new([3, 2].into(), vec![true, true, true, false, true, true])
1✔
1347
                            .unwrap()
1✔
1348
                    )
1✔
1349
                    .unwrap()
1✔
1350
                ),
1✔
1351
            )
1✔
1352
        );
1✔
1353
    }
1354

1355
    #[tokio::test]
1✔
1356
    async fn test_mean_nodata() {
1✔
1357
        let raster_tiles = make_raster_with_no_data();
1✔
1358

1✔
1359
        let mrs = MockRasterSource {
1✔
1360
            params: MockRasterSourceParams {
1✔
1361
                data: raster_tiles,
1✔
1362
                result_descriptor: RasterResultDescriptor {
1✔
1363
                    data_type: RasterDataType::U8,
1✔
1364
                    spatial_reference: SpatialReference::epsg_4326().into(),
1✔
1365
                    measurement: Measurement::Unitless,
1✔
1366
                    time: None,
1✔
1367
                    bbox: None,
1✔
1368
                    resolution: None,
1✔
1369
                },
1✔
1370
            },
1✔
1371
        }
1✔
1372
        .boxed();
1✔
1373

1✔
1374
        let agg = TemporalRasterAggregation {
1✔
1375
            params: TemporalRasterAggregationParameters {
1✔
1376
                aggregation: Aggregation::Mean {
1✔
1377
                    ignore_no_data: false,
1✔
1378
                },
1✔
1379
                window: TimeStep {
1✔
1380
                    granularity: geoengine_datatypes::primitives::TimeGranularity::Millis,
1✔
1381
                    step: 30,
1✔
1382
                },
1✔
1383
                window_reference: None,
1✔
1384
                output_type: None,
1✔
1385
            },
1✔
1386
            sources: SingleRasterSource { raster: mrs },
1✔
1387
        }
1✔
1388
        .boxed();
1✔
1389

1✔
1390
        let exe_ctx = MockExecutionContext::new_with_tiling_spec(TilingSpecification::new(
1✔
1391
            (0., 0.).into(),
1✔
1392
            [3, 2].into(),
1✔
1393
        ));
1✔
1394
        let query_rect = RasterQueryRectangle {
1✔
1395
            spatial_bounds: SpatialPartition2D::new_unchecked((0., 3.).into(), (4., 0.).into()),
1✔
1396
            time_interval: TimeInterval::new_unchecked(0, 30),
1✔
1397
            spatial_resolution: SpatialResolution::one(),
1✔
1398
        };
1✔
1399
        let query_ctx = MockQueryContext::test_default();
1✔
1400

1401
        let qp = agg
1✔
1402
            .initialize(&exe_ctx)
1✔
1403
            .await
×
1404
            .unwrap()
1✔
1405
            .query_processor()
1✔
1406
            .unwrap()
1✔
1407
            .get_u8()
1✔
1408
            .unwrap();
1✔
1409

1410
        let result = qp
1✔
1411
            .raster_query(query_rect, &query_ctx)
1✔
1412
            .await
×
1413
            .unwrap()
1✔
1414
            .collect::<Vec<_>>()
1✔
1415
            .await;
6✔
1416

1417
        assert_eq!(result.len(), 2);
1✔
1418

1419
        assert_eq!(
1✔
1420
            result[0].as_ref().unwrap(),
1✔
1421
            &RasterTile2D::new_with_tile_info(
1✔
1422
                TimeInterval::new_unchecked(0, 30),
1✔
1423
                TileInformation {
1✔
1424
                    global_tile_position: [-1, 0].into(),
1✔
1425
                    tile_size_in_pixels: [3, 2].into(),
1✔
1426
                    global_geo_transform: TestDefault::test_default(),
1✔
1427
                },
1✔
1428
                GridOrEmpty::from(EmptyGrid2D::new([3, 2].into()))
1✔
1429
            )
1✔
1430
        );
1✔
1431

1432
        assert_eq!(
1✔
1433
            result[1].as_ref().unwrap(),
1✔
1434
            &RasterTile2D::new_with_tile_info(
1✔
1435
                TimeInterval::new_unchecked(0, 30),
1✔
1436
                TileInformation {
1✔
1437
                    global_tile_position: [-1, 1].into(),
1✔
1438
                    tile_size_in_pixels: [3, 2].into(),
1✔
1439
                    global_geo_transform: TestDefault::test_default(),
1✔
1440
                },
1✔
1441
                GridOrEmpty::from(
1✔
1442
                    MaskedGrid2D::new(
1✔
1443
                        Grid2D::new([3, 2].into(), vec![1, 2, 3, 0, 5, 6]).unwrap(),
1✔
1444
                        Grid2D::new([3, 2].into(), vec![true, true, true, false, true, true])
1✔
1445
                            .unwrap()
1✔
1446
                    )
1✔
1447
                    .unwrap()
1✔
1448
                ),
1✔
1449
            )
1✔
1450
        );
1✔
1451
    }
1452

1453
    #[tokio::test]
1✔
1454
    async fn test_mean_ignore_nodata() {
1✔
1455
        let raster_tiles = make_raster_with_no_data();
1✔
1456

1✔
1457
        let mrs = MockRasterSource {
1✔
1458
            params: MockRasterSourceParams {
1✔
1459
                data: raster_tiles,
1✔
1460
                result_descriptor: RasterResultDescriptor {
1✔
1461
                    data_type: RasterDataType::U8,
1✔
1462
                    spatial_reference: SpatialReference::epsg_4326().into(),
1✔
1463
                    measurement: Measurement::Unitless,
1✔
1464
                    time: None,
1✔
1465
                    bbox: None,
1✔
1466
                    resolution: None,
1✔
1467
                },
1✔
1468
            },
1✔
1469
        }
1✔
1470
        .boxed();
1✔
1471

1✔
1472
        let agg = TemporalRasterAggregation {
1✔
1473
            params: TemporalRasterAggregationParameters {
1✔
1474
                aggregation: Aggregation::Mean {
1✔
1475
                    ignore_no_data: true,
1✔
1476
                },
1✔
1477
                window: TimeStep {
1✔
1478
                    granularity: geoengine_datatypes::primitives::TimeGranularity::Millis,
1✔
1479
                    step: 30,
1✔
1480
                },
1✔
1481
                window_reference: None,
1✔
1482
                output_type: None,
1✔
1483
            },
1✔
1484
            sources: SingleRasterSource { raster: mrs },
1✔
1485
        }
1✔
1486
        .boxed();
1✔
1487

1✔
1488
        let exe_ctx = MockExecutionContext::new_with_tiling_spec(TilingSpecification::new(
1✔
1489
            (0., 0.).into(),
1✔
1490
            [3, 2].into(),
1✔
1491
        ));
1✔
1492
        let query_rect = RasterQueryRectangle {
1✔
1493
            spatial_bounds: SpatialPartition2D::new_unchecked((0., 3.).into(), (4., 0.).into()),
1✔
1494
            time_interval: TimeInterval::new_unchecked(0, 30),
1✔
1495
            spatial_resolution: SpatialResolution::one(),
1✔
1496
        };
1✔
1497
        let query_ctx = MockQueryContext::test_default();
1✔
1498

1499
        let qp = agg
1✔
1500
            .initialize(&exe_ctx)
1✔
1501
            .await
×
1502
            .unwrap()
1✔
1503
            .query_processor()
1✔
1504
            .unwrap()
1✔
1505
            .get_u8()
1✔
1506
            .unwrap();
1✔
1507

1508
        let result = qp
1✔
1509
            .raster_query(query_rect, &query_ctx)
1✔
1510
            .await
×
1511
            .unwrap()
1✔
1512
            .collect::<Vec<_>>()
1✔
1513
            .await;
6✔
1514

1515
        assert_eq!(result.len(), 2);
1✔
1516

1517
        assert_eq!(
1✔
1518
            result[0].as_ref().unwrap(),
1✔
1519
            &RasterTile2D::new_with_tile_info(
1✔
1520
                TimeInterval::new_unchecked(0, 30),
1✔
1521
                TileInformation {
1✔
1522
                    global_tile_position: [-1, 0].into(),
1✔
1523
                    tile_size_in_pixels: [3, 2].into(),
1✔
1524
                    global_geo_transform: TestDefault::test_default(),
1✔
1525
                },
1✔
1526
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![10, 8, 12, 16, 14, 15]).unwrap())
1✔
1527
            )
1✔
1528
        );
1✔
1529

1530
        assert_eq!(
1✔
1531
            result[1].as_ref().unwrap(),
1✔
1532
            &RasterTile2D::new_with_tile_info(
1✔
1533
                TimeInterval::new_unchecked(0, 30),
1✔
1534
                TileInformation {
1✔
1535
                    global_tile_position: [-1, 1].into(),
1✔
1536
                    tile_size_in_pixels: [3, 2].into(),
1✔
1537
                    global_geo_transform: TestDefault::test_default(),
1✔
1538
                },
1✔
1539
                GridOrEmpty::from(
1✔
1540
                    MaskedGrid2D::new(
1✔
1541
                        Grid2D::new([3, 2].into(), vec![1, 2, 3, 0, 5, 6]).unwrap(),
1✔
1542
                        Grid2D::new([3, 2].into(), vec![true, true, true, false, true, true])
1✔
1543
                            .unwrap()
1✔
1544
                    )
1✔
1545
                    .unwrap()
1✔
1546
                ),
1✔
1547
            )
1✔
1548
        );
1✔
1549
    }
1550

1551
    #[tokio::test]
1✔
1552
    #[allow(clippy::too_many_lines)]
1553
    async fn test_sum_without_nodata() {
1✔
1554
        let operator = TemporalRasterAggregation {
1✔
1555
            params: TemporalRasterAggregationParameters {
1✔
1556
                aggregation: Aggregation::Sum {
1✔
1557
                    ignore_no_data: false,
1✔
1558
                },
1✔
1559
                window: TimeStep {
1✔
1560
                    granularity: geoengine_datatypes::primitives::TimeGranularity::Millis,
1✔
1561
                    step: 20,
1✔
1562
                },
1✔
1563
                window_reference: Some(TimeInstance::from_millis(0).unwrap()),
1✔
1564
                output_type: None,
1✔
1565
            },
1✔
1566
            sources: SingleRasterSource {
1✔
1567
                raster: MockRasterSource {
1✔
1568
                    params: MockRasterSourceParams {
1✔
1569
                        data: make_raster(),
1✔
1570
                        result_descriptor: RasterResultDescriptor {
1✔
1571
                            data_type: RasterDataType::U8,
1✔
1572
                            spatial_reference: SpatialReference::epsg_4326().into(),
1✔
1573
                            measurement: Measurement::Unitless,
1✔
1574
                            time: None,
1✔
1575
                            bbox: None,
1✔
1576
                            resolution: None,
1✔
1577
                        },
1✔
1578
                    },
1✔
1579
                }
1✔
1580
                .boxed(),
1✔
1581
            },
1✔
1582
        }
1✔
1583
        .boxed();
1✔
1584

1✔
1585
        let exe_ctx = MockExecutionContext::new_with_tiling_spec(TilingSpecification::new(
1✔
1586
            (0., 0.).into(),
1✔
1587
            [3, 2].into(),
1✔
1588
        ));
1✔
1589
        let query_rect = RasterQueryRectangle {
1✔
1590
            spatial_bounds: SpatialPartition2D::new_unchecked((0., 3.).into(), (4., 0.).into()),
1✔
1591
            time_interval: TimeInterval::new_unchecked(0, 30),
1✔
1592
            spatial_resolution: SpatialResolution::one(),
1✔
1593
        };
1✔
1594
        let query_ctx = MockQueryContext::test_default();
1✔
1595

1596
        let query_processor = operator
1✔
1597
            .initialize(&exe_ctx)
1✔
1598
            .await
×
1599
            .unwrap()
1✔
1600
            .query_processor()
1✔
1601
            .unwrap()
1✔
1602
            .get_u8()
1✔
1603
            .unwrap();
1✔
1604

1605
        let result = query_processor
1✔
1606
            .raster_query(query_rect, &query_ctx)
1✔
1607
            .await
×
1608
            .unwrap()
1✔
1609
            .map(Result::unwrap)
1✔
1610
            .collect::<Vec<_>>()
1✔
1611
            .await;
8✔
1612

1613
        assert_eq!(
1✔
1614
            result,
1✔
1615
            [
1✔
1616
                RasterTile2D::new_with_tile_info(
1✔
1617
                    TimeInterval::new_unchecked(0, 20),
1✔
1618
                    TileInformation {
1✔
1619
                        global_tile_position: [-1, 0].into(),
1✔
1620
                        tile_size_in_pixels: [3, 2].into(),
1✔
1621
                        global_geo_transform: TestDefault::test_default(),
1✔
1622
                    },
1✔
1623
                    Grid2D::new([3, 2].into(), vec![13, 13, 13, 13, 13, 13])
1✔
1624
                        .unwrap()
1✔
1625
                        .into()
1✔
1626
                ),
1✔
1627
                RasterTile2D::new_with_tile_info(
1✔
1628
                    TimeInterval::new_unchecked(0, 20),
1✔
1629
                    TileInformation {
1✔
1630
                        global_tile_position: [-1, 1].into(),
1✔
1631
                        tile_size_in_pixels: [3, 2].into(),
1✔
1632
                        global_geo_transform: TestDefault::test_default(),
1✔
1633
                    },
1✔
1634
                    Grid2D::new([3, 2].into(), vec![13, 13, 13, 13, 13, 13])
1✔
1635
                        .unwrap()
1✔
1636
                        .into(),
1✔
1637
                ),
1✔
1638
                RasterTile2D::new_with_tile_info(
1✔
1639
                    TimeInterval::new_unchecked(20, 40),
1✔
1640
                    TileInformation {
1✔
1641
                        global_tile_position: [-1, 0].into(),
1✔
1642
                        tile_size_in_pixels: [3, 2].into(),
1✔
1643
                        global_geo_transform: TestDefault::test_default(),
1✔
1644
                    },
1✔
1645
                    Grid2D::new([3, 2].into(), vec![13, 13, 13, 13, 13, 13])
1✔
1646
                        .unwrap()
1✔
1647
                        .into(),
1✔
1648
                ),
1✔
1649
                RasterTile2D::new_with_tile_info(
1✔
1650
                    TimeInterval::new_unchecked(20, 40),
1✔
1651
                    TileInformation {
1✔
1652
                        global_tile_position: [-1, 1].into(),
1✔
1653
                        tile_size_in_pixels: [3, 2].into(),
1✔
1654
                        global_geo_transform: TestDefault::test_default(),
1✔
1655
                    },
1✔
1656
                    Grid2D::new([3, 2].into(), vec![13, 13, 13, 13, 13, 13])
1✔
1657
                        .unwrap()
1✔
1658
                        .into(),
1✔
1659
                )
1✔
1660
            ]
1✔
1661
        );
1✔
1662
    }
1663

1664
    #[tokio::test]
1✔
1665
    async fn test_sum_nodata() {
1✔
1666
        let raster_tiles = make_raster_with_no_data();
1✔
1667

1✔
1668
        let mrs = MockRasterSource {
1✔
1669
            params: MockRasterSourceParams {
1✔
1670
                data: raster_tiles,
1✔
1671
                result_descriptor: RasterResultDescriptor {
1✔
1672
                    data_type: RasterDataType::U8,
1✔
1673
                    spatial_reference: SpatialReference::epsg_4326().into(),
1✔
1674
                    measurement: Measurement::Unitless,
1✔
1675
                    time: None,
1✔
1676
                    bbox: None,
1✔
1677
                    resolution: None,
1✔
1678
                },
1✔
1679
            },
1✔
1680
        }
1✔
1681
        .boxed();
1✔
1682

1✔
1683
        let agg = TemporalRasterAggregation {
1✔
1684
            params: TemporalRasterAggregationParameters {
1✔
1685
                aggregation: Aggregation::Sum {
1✔
1686
                    ignore_no_data: false,
1✔
1687
                },
1✔
1688
                window: TimeStep {
1✔
1689
                    granularity: geoengine_datatypes::primitives::TimeGranularity::Millis,
1✔
1690
                    step: 30,
1✔
1691
                },
1✔
1692
                window_reference: None,
1✔
1693
                output_type: None,
1✔
1694
            },
1✔
1695
            sources: SingleRasterSource { raster: mrs },
1✔
1696
        }
1✔
1697
        .boxed();
1✔
1698

1✔
1699
        let exe_ctx = MockExecutionContext::new_with_tiling_spec(TilingSpecification::new(
1✔
1700
            (0., 0.).into(),
1✔
1701
            [3, 2].into(),
1✔
1702
        ));
1✔
1703
        let query_rect = RasterQueryRectangle {
1✔
1704
            spatial_bounds: SpatialPartition2D::new_unchecked((0., 3.).into(), (4., 0.).into()),
1✔
1705
            time_interval: TimeInterval::new_unchecked(0, 30),
1✔
1706
            spatial_resolution: SpatialResolution::one(),
1✔
1707
        };
1✔
1708
        let query_ctx = MockQueryContext::test_default();
1✔
1709

1710
        let qp = agg
1✔
1711
            .initialize(&exe_ctx)
1✔
1712
            .await
×
1713
            .unwrap()
1✔
1714
            .query_processor()
1✔
1715
            .unwrap()
1✔
1716
            .get_u8()
1✔
1717
            .unwrap();
1✔
1718

1719
        let result = qp
1✔
1720
            .raster_query(query_rect, &query_ctx)
1✔
1721
            .await
×
1722
            .unwrap()
1✔
1723
            .collect::<Vec<_>>()
1✔
1724
            .await;
6✔
1725

1726
        assert_eq!(result.len(), 2);
1✔
1727

1728
        assert_eq!(
1✔
1729
            result[0].as_ref().unwrap(),
1✔
1730
            &RasterTile2D::new_with_tile_info(
1✔
1731
                TimeInterval::new_unchecked(0, 30),
1✔
1732
                TileInformation {
1✔
1733
                    global_tile_position: [-1, 0].into(),
1✔
1734
                    tile_size_in_pixels: [3, 2].into(),
1✔
1735
                    global_geo_transform: TestDefault::test_default(),
1✔
1736
                },
1✔
1737
                GridOrEmpty::from(EmptyGrid2D::new([3, 2].into()))
1✔
1738
            )
1✔
1739
        );
1✔
1740

1741
        assert_eq!(
1✔
1742
            result[1].as_ref().unwrap(),
1✔
1743
            &RasterTile2D::new_with_tile_info(
1✔
1744
                TimeInterval::new_unchecked(0, 30),
1✔
1745
                TileInformation {
1✔
1746
                    global_tile_position: [-1, 1].into(),
1✔
1747
                    tile_size_in_pixels: [3, 2].into(),
1✔
1748
                    global_geo_transform: TestDefault::test_default(),
1✔
1749
                },
1✔
1750
                GridOrEmpty::from(
1✔
1751
                    MaskedGrid2D::new(
1✔
1752
                        Grid2D::new([3, 2].into(), vec![1, 2, 3, 0, 5, 6]).unwrap(),
1✔
1753
                        Grid2D::new([3, 2].into(), vec![true, true, true, false, true, true])
1✔
1754
                            .unwrap()
1✔
1755
                    )
1✔
1756
                    .unwrap()
1✔
1757
                ),
1✔
1758
            )
1✔
1759
        );
1✔
1760
    }
1761

1762
    #[tokio::test]
1✔
1763
    async fn test_sum_ignore_nodata() {
1✔
1764
        let raster_tiles = make_raster_with_no_data();
1✔
1765

1✔
1766
        let mrs = MockRasterSource {
1✔
1767
            params: MockRasterSourceParams {
1✔
1768
                data: raster_tiles,
1✔
1769
                result_descriptor: RasterResultDescriptor {
1✔
1770
                    data_type: RasterDataType::U8,
1✔
1771
                    spatial_reference: SpatialReference::epsg_4326().into(),
1✔
1772
                    measurement: Measurement::Unitless,
1✔
1773
                    time: None,
1✔
1774
                    bbox: None,
1✔
1775
                    resolution: None,
1✔
1776
                },
1✔
1777
            },
1✔
1778
        }
1✔
1779
        .boxed();
1✔
1780

1✔
1781
        let agg = TemporalRasterAggregation {
1✔
1782
            params: TemporalRasterAggregationParameters {
1✔
1783
                aggregation: Aggregation::Sum {
1✔
1784
                    ignore_no_data: true,
1✔
1785
                },
1✔
1786
                window: TimeStep {
1✔
1787
                    granularity: geoengine_datatypes::primitives::TimeGranularity::Millis,
1✔
1788
                    step: 30,
1✔
1789
                },
1✔
1790
                window_reference: None,
1✔
1791
                output_type: None,
1✔
1792
            },
1✔
1793
            sources: SingleRasterSource { raster: mrs },
1✔
1794
        }
1✔
1795
        .boxed();
1✔
1796

1✔
1797
        let exe_ctx = MockExecutionContext::new_with_tiling_spec(TilingSpecification::new(
1✔
1798
            (0., 0.).into(),
1✔
1799
            [3, 2].into(),
1✔
1800
        ));
1✔
1801
        let query_rect = RasterQueryRectangle {
1✔
1802
            spatial_bounds: SpatialPartition2D::new_unchecked((0., 3.).into(), (4., 0.).into()),
1✔
1803
            time_interval: TimeInterval::new_unchecked(0, 30),
1✔
1804
            spatial_resolution: SpatialResolution::one(),
1✔
1805
        };
1✔
1806
        let query_ctx = MockQueryContext::test_default();
1✔
1807

1808
        let qp = agg
1✔
1809
            .initialize(&exe_ctx)
1✔
1810
            .await
×
1811
            .unwrap()
1✔
1812
            .query_processor()
1✔
1813
            .unwrap()
1✔
1814
            .get_u8()
1✔
1815
            .unwrap();
1✔
1816

1817
        let result = qp
1✔
1818
            .raster_query(query_rect, &query_ctx)
1✔
1819
            .await
×
1820
            .unwrap()
1✔
1821
            .collect::<Vec<_>>()
1✔
1822
            .await;
6✔
1823

1824
        assert_eq!(result.len(), 2);
1✔
1825

1826
        assert_eq!(
1✔
1827
            result[0].as_ref().unwrap(),
1✔
1828
            &RasterTile2D::new_with_tile_info(
1✔
1829
                TimeInterval::new_unchecked(0, 30),
1✔
1830
                TileInformation {
1✔
1831
                    global_tile_position: [-1, 0].into(),
1✔
1832
                    tile_size_in_pixels: [3, 2].into(),
1✔
1833
                    global_geo_transform: TestDefault::test_default(),
1✔
1834
                },
1✔
1835
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![20, 8, 24, 16, 28, 30]).unwrap())
1✔
1836
            )
1✔
1837
        );
1✔
1838

1839
        assert_eq!(
1✔
1840
            result[1].as_ref().unwrap(),
1✔
1841
            &RasterTile2D::new_with_tile_info(
1✔
1842
                TimeInterval::new_unchecked(0, 30),
1✔
1843
                TileInformation {
1✔
1844
                    global_tile_position: [-1, 1].into(),
1✔
1845
                    tile_size_in_pixels: [3, 2].into(),
1✔
1846
                    global_geo_transform: TestDefault::test_default(),
1✔
1847
                },
1✔
1848
                GridOrEmpty::from(
1✔
1849
                    MaskedGrid2D::new(
1✔
1850
                        Grid2D::new([3, 2].into(), vec![1, 2, 3, 0, 5, 6]).unwrap(),
1✔
1851
                        Grid2D::new([3, 2].into(), vec![true, true, true, false, true, true])
1✔
1852
                            .unwrap()
1✔
1853
                    )
1✔
1854
                    .unwrap()
1✔
1855
                ),
1✔
1856
            )
1✔
1857
        );
1✔
1858
    }
1859

1860
    #[tokio::test]
1✔
1861
    #[allow(clippy::too_many_lines)]
1862
    async fn test_sum_with_larger_data_type() {
1✔
1863
        let operator = TemporalRasterAggregation {
1✔
1864
            params: TemporalRasterAggregationParameters {
1✔
1865
                aggregation: Aggregation::Sum {
1✔
1866
                    ignore_no_data: false,
1✔
1867
                },
1✔
1868
                window: TimeStep {
1✔
1869
                    granularity: geoengine_datatypes::primitives::TimeGranularity::Millis,
1✔
1870
                    step: 20,
1✔
1871
                },
1✔
1872
                window_reference: Some(TimeInstance::from_millis(0).unwrap()),
1✔
1873
                output_type: Some(RasterDataType::U16),
1✔
1874
            },
1✔
1875
            sources: SingleRasterSource {
1✔
1876
                raster: Expression {
1✔
1877
                    params: ExpressionParams {
1✔
1878
                        expression: "20 * A".to_string(),
1✔
1879
                        output_type: RasterDataType::U8,
1✔
1880
                        output_measurement: Some(Measurement::Unitless),
1✔
1881
                        map_no_data: true,
1✔
1882
                    },
1✔
1883
                    sources: ExpressionSources::new_a(
1✔
1884
                        MockRasterSource {
1✔
1885
                            params: MockRasterSourceParams {
1✔
1886
                                data: make_raster(),
1✔
1887
                                result_descriptor: RasterResultDescriptor {
1✔
1888
                                    data_type: RasterDataType::U8,
1✔
1889
                                    spatial_reference: SpatialReference::epsg_4326().into(),
1✔
1890
                                    measurement: Measurement::Unitless,
1✔
1891
                                    time: None,
1✔
1892
                                    bbox: None,
1✔
1893
                                    resolution: None,
1✔
1894
                                },
1✔
1895
                            },
1✔
1896
                        }
1✔
1897
                        .boxed(),
1✔
1898
                    ),
1✔
1899
                }
1✔
1900
                .boxed(),
1✔
1901
            },
1✔
1902
        }
1✔
1903
        .boxed();
1✔
1904

1✔
1905
        let exe_ctx = MockExecutionContext::new_with_tiling_spec(TilingSpecification::new(
1✔
1906
            (0., 0.).into(),
1✔
1907
            [3, 2].into(),
1✔
1908
        ));
1✔
1909
        let query_rect = RasterQueryRectangle {
1✔
1910
            spatial_bounds: SpatialPartition2D::new_unchecked((0., 3.).into(), (4., 0.).into()),
1✔
1911
            time_interval: TimeInterval::new_unchecked(0, 30),
1✔
1912
            spatial_resolution: SpatialResolution::one(),
1✔
1913
        };
1✔
1914
        let query_ctx = MockQueryContext::test_default();
1✔
1915

1916
        let query_processor = operator
1✔
1917
            .initialize(&exe_ctx)
1✔
1918
            .await
×
1919
            .unwrap()
1✔
1920
            .query_processor()
1✔
1921
            .unwrap()
1✔
1922
            .get_u16()
1✔
1923
            .unwrap();
1✔
1924

1925
        let result = query_processor
1✔
1926
            .raster_query(query_rect, &query_ctx)
1✔
1927
            .await
×
1928
            .unwrap()
1✔
1929
            .map(Result::unwrap)
1✔
1930
            .collect::<Vec<_>>()
1✔
1931
            .await;
32✔
1932

1933
        assert_eq!(
1✔
1934
            result,
1✔
1935
            [
1✔
1936
                RasterTile2D::new_with_tile_info(
1✔
1937
                    TimeInterval::new_unchecked(0, 20),
1✔
1938
                    TileInformation {
1✔
1939
                        global_tile_position: [-1, 0].into(),
1✔
1940
                        tile_size_in_pixels: [3, 2].into(),
1✔
1941
                        global_geo_transform: TestDefault::test_default(),
1✔
1942
                    },
1✔
1943
                    Grid2D::new(
1✔
1944
                        [3, 2].into(),
1✔
1945
                        vec![13 * 20, 13 * 20, 13 * 20, 13 * 20, 13 * 20, 13 * 20]
1✔
1946
                    )
1✔
1947
                    .unwrap()
1✔
1948
                    .into()
1✔
1949
                ),
1✔
1950
                RasterTile2D::new_with_tile_info(
1✔
1951
                    TimeInterval::new_unchecked(0, 20),
1✔
1952
                    TileInformation {
1✔
1953
                        global_tile_position: [-1, 1].into(),
1✔
1954
                        tile_size_in_pixels: [3, 2].into(),
1✔
1955
                        global_geo_transform: TestDefault::test_default(),
1✔
1956
                    },
1✔
1957
                    Grid2D::new(
1✔
1958
                        [3, 2].into(),
1✔
1959
                        vec![13 * 20, 13 * 20, 13 * 20, 13 * 20, 13 * 20, 13 * 20]
1✔
1960
                    )
1✔
1961
                    .unwrap()
1✔
1962
                    .into(),
1✔
1963
                ),
1✔
1964
                RasterTile2D::new_with_tile_info(
1✔
1965
                    TimeInterval::new_unchecked(20, 40),
1✔
1966
                    TileInformation {
1✔
1967
                        global_tile_position: [-1, 0].into(),
1✔
1968
                        tile_size_in_pixels: [3, 2].into(),
1✔
1969
                        global_geo_transform: TestDefault::test_default(),
1✔
1970
                    },
1✔
1971
                    Grid2D::new(
1✔
1972
                        [3, 2].into(),
1✔
1973
                        vec![13 * 20, 13 * 20, 13 * 20, 13 * 20, 13 * 20, 13 * 20]
1✔
1974
                    )
1✔
1975
                    .unwrap()
1✔
1976
                    .into(),
1✔
1977
                ),
1✔
1978
                RasterTile2D::new_with_tile_info(
1✔
1979
                    TimeInterval::new_unchecked(20, 40),
1✔
1980
                    TileInformation {
1✔
1981
                        global_tile_position: [-1, 1].into(),
1✔
1982
                        tile_size_in_pixels: [3, 2].into(),
1✔
1983
                        global_geo_transform: TestDefault::test_default(),
1✔
1984
                    },
1✔
1985
                    Grid2D::new(
1✔
1986
                        [3, 2].into(),
1✔
1987
                        vec![13 * 20, 13 * 20, 13 * 20, 13 * 20, 13 * 20, 13 * 20]
1✔
1988
                    )
1✔
1989
                    .unwrap()
1✔
1990
                    .into(),
1✔
1991
                )
1✔
1992
            ]
1✔
1993
        );
1✔
1994
    }
1995

1996
    #[tokio::test]
1✔
1997
    #[allow(clippy::too_many_lines)]
1998
    async fn test_count_without_nodata() {
1✔
1999
        let operator = TemporalRasterAggregation {
1✔
2000
            params: TemporalRasterAggregationParameters {
1✔
2001
                aggregation: Aggregation::Count {
1✔
2002
                    ignore_no_data: false,
1✔
2003
                },
1✔
2004
                window: TimeStep {
1✔
2005
                    granularity: geoengine_datatypes::primitives::TimeGranularity::Millis,
1✔
2006
                    step: 20,
1✔
2007
                },
1✔
2008
                window_reference: Some(TimeInstance::from_millis(0).unwrap()),
1✔
2009
                output_type: None,
1✔
2010
            },
1✔
2011
            sources: SingleRasterSource {
1✔
2012
                raster: MockRasterSource {
1✔
2013
                    params: MockRasterSourceParams {
1✔
2014
                        data: make_raster(),
1✔
2015
                        result_descriptor: RasterResultDescriptor {
1✔
2016
                            data_type: RasterDataType::U8,
1✔
2017
                            spatial_reference: SpatialReference::epsg_4326().into(),
1✔
2018
                            measurement: Measurement::Unitless,
1✔
2019
                            time: None,
1✔
2020
                            bbox: None,
1✔
2021
                            resolution: None,
1✔
2022
                        },
1✔
2023
                    },
1✔
2024
                }
1✔
2025
                .boxed(),
1✔
2026
            },
1✔
2027
        }
1✔
2028
        .boxed();
1✔
2029

1✔
2030
        let exe_ctx = MockExecutionContext::new_with_tiling_spec(TilingSpecification::new(
1✔
2031
            (0., 0.).into(),
1✔
2032
            [3, 2].into(),
1✔
2033
        ));
1✔
2034
        let query_rect = RasterQueryRectangle {
1✔
2035
            spatial_bounds: SpatialPartition2D::new_unchecked((0., 3.).into(), (4., 0.).into()),
1✔
2036
            time_interval: TimeInterval::new_unchecked(0, 30),
1✔
2037
            spatial_resolution: SpatialResolution::one(),
1✔
2038
        };
1✔
2039
        let query_ctx = MockQueryContext::test_default();
1✔
2040

2041
        let query_processor = operator
1✔
2042
            .initialize(&exe_ctx)
1✔
2043
            .await
×
2044
            .unwrap()
1✔
2045
            .query_processor()
1✔
2046
            .unwrap()
1✔
2047
            .get_u8()
1✔
2048
            .unwrap();
1✔
2049

2050
        let result = query_processor
1✔
2051
            .raster_query(query_rect, &query_ctx)
1✔
2052
            .await
×
2053
            .unwrap()
1✔
2054
            .map(Result::unwrap)
1✔
2055
            .collect::<Vec<_>>()
1✔
2056
            .await;
8✔
2057

2058
        assert_eq!(
1✔
2059
            result,
1✔
2060
            [
1✔
2061
                RasterTile2D::new_with_tile_info(
1✔
2062
                    TimeInterval::new_unchecked(0, 20),
1✔
2063
                    TileInformation {
1✔
2064
                        global_tile_position: [-1, 0].into(),
1✔
2065
                        tile_size_in_pixels: [3, 2].into(),
1✔
2066
                        global_geo_transform: TestDefault::test_default(),
1✔
2067
                    },
1✔
2068
                    Grid2D::new([3, 2].into(), vec![2, 2, 2, 2, 2, 2])
1✔
2069
                        .unwrap()
1✔
2070
                        .into()
1✔
2071
                ),
1✔
2072
                RasterTile2D::new_with_tile_info(
1✔
2073
                    TimeInterval::new_unchecked(0, 20),
1✔
2074
                    TileInformation {
1✔
2075
                        global_tile_position: [-1, 1].into(),
1✔
2076
                        tile_size_in_pixels: [3, 2].into(),
1✔
2077
                        global_geo_transform: TestDefault::test_default(),
1✔
2078
                    },
1✔
2079
                    Grid2D::new([3, 2].into(), vec![2, 2, 2, 2, 2, 2])
1✔
2080
                        .unwrap()
1✔
2081
                        .into(),
1✔
2082
                ),
1✔
2083
                RasterTile2D::new_with_tile_info(
1✔
2084
                    TimeInterval::new_unchecked(20, 40),
1✔
2085
                    TileInformation {
1✔
2086
                        global_tile_position: [-1, 0].into(),
1✔
2087
                        tile_size_in_pixels: [3, 2].into(),
1✔
2088
                        global_geo_transform: TestDefault::test_default(),
1✔
2089
                    },
1✔
2090
                    Grid2D::new([3, 2].into(), vec![2, 2, 2, 2, 2, 2])
1✔
2091
                        .unwrap()
1✔
2092
                        .into(),
1✔
2093
                ),
1✔
2094
                RasterTile2D::new_with_tile_info(
1✔
2095
                    TimeInterval::new_unchecked(20, 40),
1✔
2096
                    TileInformation {
1✔
2097
                        global_tile_position: [-1, 1].into(),
1✔
2098
                        tile_size_in_pixels: [3, 2].into(),
1✔
2099
                        global_geo_transform: TestDefault::test_default(),
1✔
2100
                    },
1✔
2101
                    Grid2D::new([3, 2].into(), vec![2, 2, 2, 2, 2, 2])
1✔
2102
                        .unwrap()
1✔
2103
                        .into(),
1✔
2104
                )
1✔
2105
            ]
1✔
2106
        );
1✔
2107
    }
2108

2109
    #[tokio::test]
1✔
2110
    async fn test_count_nodata() {
1✔
2111
        let raster_tiles = make_raster_with_no_data();
1✔
2112

1✔
2113
        let mrs = MockRasterSource {
1✔
2114
            params: MockRasterSourceParams {
1✔
2115
                data: raster_tiles,
1✔
2116
                result_descriptor: RasterResultDescriptor {
1✔
2117
                    data_type: RasterDataType::U8,
1✔
2118
                    spatial_reference: SpatialReference::epsg_4326().into(),
1✔
2119
                    measurement: Measurement::Unitless,
1✔
2120
                    time: None,
1✔
2121
                    bbox: None,
1✔
2122
                    resolution: None,
1✔
2123
                },
1✔
2124
            },
1✔
2125
        }
1✔
2126
        .boxed();
1✔
2127

1✔
2128
        let agg = TemporalRasterAggregation {
1✔
2129
            params: TemporalRasterAggregationParameters {
1✔
2130
                aggregation: Aggregation::Count {
1✔
2131
                    ignore_no_data: false,
1✔
2132
                },
1✔
2133
                window: TimeStep {
1✔
2134
                    granularity: geoengine_datatypes::primitives::TimeGranularity::Millis,
1✔
2135
                    step: 30,
1✔
2136
                },
1✔
2137
                window_reference: None,
1✔
2138
                output_type: None,
1✔
2139
            },
1✔
2140
            sources: SingleRasterSource { raster: mrs },
1✔
2141
        }
1✔
2142
        .boxed();
1✔
2143

1✔
2144
        let exe_ctx = MockExecutionContext::new_with_tiling_spec(TilingSpecification::new(
1✔
2145
            (0., 0.).into(),
1✔
2146
            [3, 2].into(),
1✔
2147
        ));
1✔
2148
        let query_rect = RasterQueryRectangle {
1✔
2149
            spatial_bounds: SpatialPartition2D::new_unchecked((0., 3.).into(), (4., 0.).into()),
1✔
2150
            time_interval: TimeInterval::new_unchecked(0, 30),
1✔
2151
            spatial_resolution: SpatialResolution::one(),
1✔
2152
        };
1✔
2153
        let query_ctx = MockQueryContext::test_default();
1✔
2154

2155
        let qp = agg
1✔
2156
            .initialize(&exe_ctx)
1✔
2157
            .await
×
2158
            .unwrap()
1✔
2159
            .query_processor()
1✔
2160
            .unwrap()
1✔
2161
            .get_u8()
1✔
2162
            .unwrap();
1✔
2163

2164
        let result = qp
1✔
2165
            .raster_query(query_rect, &query_ctx)
1✔
2166
            .await
×
2167
            .unwrap()
1✔
2168
            .collect::<Vec<_>>()
1✔
2169
            .await;
6✔
2170

2171
        assert_eq!(result.len(), 2);
1✔
2172

2173
        assert_eq!(
1✔
2174
            result[0].as_ref().unwrap(),
1✔
2175
            &RasterTile2D::new_with_tile_info(
1✔
2176
                TimeInterval::new_unchecked(0, 30),
1✔
2177
                TileInformation {
1✔
2178
                    global_tile_position: [-1, 0].into(),
1✔
2179
                    tile_size_in_pixels: [3, 2].into(),
1✔
2180
                    global_geo_transform: TestDefault::test_default(),
1✔
2181
                },
1✔
2182
                GridOrEmpty::from(EmptyGrid2D::new([3, 2].into()))
1✔
2183
            )
1✔
2184
        );
1✔
2185

2186
        assert_eq!(
1✔
2187
            result[1].as_ref().unwrap(),
1✔
2188
            &RasterTile2D::new_with_tile_info(
1✔
2189
                TimeInterval::new_unchecked(0, 30),
1✔
2190
                TileInformation {
1✔
2191
                    global_tile_position: [-1, 1].into(),
1✔
2192
                    tile_size_in_pixels: [3, 2].into(),
1✔
2193
                    global_geo_transform: TestDefault::test_default(),
1✔
2194
                },
1✔
2195
                GridOrEmpty::from(
1✔
2196
                    MaskedGrid2D::new(
1✔
2197
                        Grid2D::new([3, 2].into(), vec![1, 1, 1, 0, 1, 1]).unwrap(),
1✔
2198
                        Grid2D::new([3, 2].into(), vec![true, true, true, false, true, true])
1✔
2199
                            .unwrap()
1✔
2200
                    )
1✔
2201
                    .unwrap()
1✔
2202
                ),
1✔
2203
            )
1✔
2204
        );
1✔
2205
    }
2206

2207
    #[tokio::test]
1✔
2208
    async fn test_count_ignore_nodata() {
1✔
2209
        let raster_tiles = make_raster_with_no_data();
1✔
2210

1✔
2211
        let mrs = MockRasterSource {
1✔
2212
            params: MockRasterSourceParams {
1✔
2213
                data: raster_tiles,
1✔
2214
                result_descriptor: RasterResultDescriptor {
1✔
2215
                    data_type: RasterDataType::U8,
1✔
2216
                    spatial_reference: SpatialReference::epsg_4326().into(),
1✔
2217
                    measurement: Measurement::Unitless,
1✔
2218
                    time: None,
1✔
2219
                    bbox: None,
1✔
2220
                    resolution: None,
1✔
2221
                },
1✔
2222
            },
1✔
2223
        }
1✔
2224
        .boxed();
1✔
2225

1✔
2226
        let agg = TemporalRasterAggregation {
1✔
2227
            params: TemporalRasterAggregationParameters {
1✔
2228
                aggregation: Aggregation::Count {
1✔
2229
                    ignore_no_data: true,
1✔
2230
                },
1✔
2231
                window: TimeStep {
1✔
2232
                    granularity: geoengine_datatypes::primitives::TimeGranularity::Millis,
1✔
2233
                    step: 30,
1✔
2234
                },
1✔
2235
                window_reference: None,
1✔
2236
                output_type: None,
1✔
2237
            },
1✔
2238
            sources: SingleRasterSource { raster: mrs },
1✔
2239
        }
1✔
2240
        .boxed();
1✔
2241

1✔
2242
        let exe_ctx = MockExecutionContext::new_with_tiling_spec(TilingSpecification::new(
1✔
2243
            (0., 0.).into(),
1✔
2244
            [3, 2].into(),
1✔
2245
        ));
1✔
2246
        let query_rect = RasterQueryRectangle {
1✔
2247
            spatial_bounds: SpatialPartition2D::new_unchecked((0., 3.).into(), (4., 0.).into()),
1✔
2248
            time_interval: TimeInterval::new_unchecked(0, 30),
1✔
2249
            spatial_resolution: SpatialResolution::one(),
1✔
2250
        };
1✔
2251
        let query_ctx = MockQueryContext::test_default();
1✔
2252

2253
        let qp = agg
1✔
2254
            .initialize(&exe_ctx)
1✔
2255
            .await
×
2256
            .unwrap()
1✔
2257
            .query_processor()
1✔
2258
            .unwrap()
1✔
2259
            .get_u8()
1✔
2260
            .unwrap();
1✔
2261

2262
        let result = qp
1✔
2263
            .raster_query(query_rect, &query_ctx)
1✔
2264
            .await
×
2265
            .unwrap()
1✔
2266
            .collect::<Vec<_>>()
1✔
2267
            .await;
6✔
2268

2269
        assert_eq!(result.len(), 2);
1✔
2270

2271
        assert_eq!(
1✔
2272
            result[0].as_ref().unwrap(),
1✔
2273
            &RasterTile2D::new_with_tile_info(
1✔
2274
                TimeInterval::new_unchecked(0, 30),
1✔
2275
                TileInformation {
1✔
2276
                    global_tile_position: [-1, 0].into(),
1✔
2277
                    tile_size_in_pixels: [3, 2].into(),
1✔
2278
                    global_geo_transform: TestDefault::test_default(),
1✔
2279
                },
1✔
2280
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![2, 1, 2, 1, 2, 2]).unwrap())
1✔
2281
            )
1✔
2282
        );
1✔
2283

2284
        assert_eq!(
1✔
2285
            result[1].as_ref().unwrap(),
1✔
2286
            &RasterTile2D::new_with_tile_info(
1✔
2287
                TimeInterval::new_unchecked(0, 30),
1✔
2288
                TileInformation {
1✔
2289
                    global_tile_position: [-1, 1].into(),
1✔
2290
                    tile_size_in_pixels: [3, 2].into(),
1✔
2291
                    global_geo_transform: TestDefault::test_default(),
1✔
2292
                },
1✔
2293
                GridOrEmpty::from(
1✔
2294
                    MaskedGrid2D::new(
1✔
2295
                        Grid2D::new([3, 2].into(), vec![1, 1, 1, 0, 1, 1]).unwrap(),
1✔
2296
                        Grid2D::new([3, 2].into(), vec![true, true, true, false, true, true])
1✔
2297
                            .unwrap()
1✔
2298
                    )
1✔
2299
                    .unwrap()
1✔
2300
                ),
1✔
2301
            )
1✔
2302
        );
1✔
2303
    }
2304

2305
    #[tokio::test]
1✔
2306
    async fn test_query_not_aligned_with_window_reference() {
1✔
2307
        let raster_tiles = make_raster();
1✔
2308

1✔
2309
        let mrs = MockRasterSource {
1✔
2310
            params: MockRasterSourceParams {
1✔
2311
                data: raster_tiles,
1✔
2312
                result_descriptor: RasterResultDescriptor {
1✔
2313
                    data_type: RasterDataType::U8,
1✔
2314
                    spatial_reference: SpatialReference::epsg_4326().into(),
1✔
2315
                    measurement: Measurement::Unitless,
1✔
2316
                    time: None,
1✔
2317
                    bbox: None,
1✔
2318
                    resolution: None,
1✔
2319
                },
1✔
2320
            },
1✔
2321
        }
1✔
2322
        .boxed();
1✔
2323

1✔
2324
        let agg = TemporalRasterAggregation {
1✔
2325
            params: TemporalRasterAggregationParameters {
1✔
2326
                aggregation: Aggregation::Last {
1✔
2327
                    ignore_no_data: false,
1✔
2328
                },
1✔
2329
                window: TimeStep {
1✔
2330
                    granularity: geoengine_datatypes::primitives::TimeGranularity::Millis,
1✔
2331
                    step: 30,
1✔
2332
                },
1✔
2333
                window_reference: Some(TimeInstance::EPOCH_START),
1✔
2334
                output_type: None,
1✔
2335
            },
1✔
2336
            sources: SingleRasterSource { raster: mrs },
1✔
2337
        }
1✔
2338
        .boxed();
1✔
2339

1✔
2340
        let exe_ctx = MockExecutionContext::new_with_tiling_spec(TilingSpecification::new(
1✔
2341
            (0., 0.).into(),
1✔
2342
            [3, 2].into(),
1✔
2343
        ));
1✔
2344
        let query_rect = RasterQueryRectangle {
1✔
2345
            spatial_bounds: SpatialPartition2D::new_unchecked((0., 3.).into(), (4., 0.).into()),
1✔
2346
            time_interval: TimeInterval::new_unchecked(5, 5),
1✔
2347
            spatial_resolution: SpatialResolution::one(),
1✔
2348
        };
1✔
2349
        let query_ctx = MockQueryContext::test_default();
1✔
2350

2351
        let qp = agg
1✔
2352
            .initialize(&exe_ctx)
1✔
2353
            .await
×
2354
            .unwrap()
1✔
2355
            .query_processor()
1✔
2356
            .unwrap()
1✔
2357
            .get_u8()
1✔
2358
            .unwrap();
1✔
2359

2360
        let result = qp
1✔
2361
            .query(query_rect, &query_ctx)
1✔
2362
            .await
×
2363
            .unwrap()
1✔
2364
            .collect::<Vec<_>>()
1✔
2365
            .await;
8✔
2366

2367
        assert_eq!(result.len(), 2);
1✔
2368
        assert_eq!(
1✔
2369
            result[0].as_ref().unwrap(),
1✔
2370
            &RasterTile2D::new_with_tile_info(
1✔
2371
                TimeInterval::new_unchecked(0, 30),
1✔
2372
                TileInformation {
1✔
2373
                    global_tile_position: [-1, 0].into(),
1✔
2374
                    tile_size_in_pixels: [3, 2].into(),
1✔
2375
                    global_geo_transform: TestDefault::test_default(),
1✔
2376
                },
1✔
2377
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![1, 2, 3, 4, 5, 6]).unwrap()),
1✔
2378
            )
1✔
2379
        );
1✔
2380

2381
        assert_eq!(
1✔
2382
            result[1].as_ref().unwrap(),
1✔
2383
            &RasterTile2D::new_with_tile_info(
1✔
2384
                TimeInterval::new_unchecked(0, 30),
1✔
2385
                TileInformation {
1✔
2386
                    global_tile_position: [-1, 1].into(),
1✔
2387
                    tile_size_in_pixels: [3, 2].into(),
1✔
2388
                    global_geo_transform: TestDefault::test_default(),
1✔
2389
                },
1✔
2390
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![7, 8, 9, 10, 11, 12]).unwrap()),
1✔
2391
            )
1✔
2392
        );
1✔
2393
    }
2394

2395
    fn make_raster() -> Vec<geoengine_datatypes::raster::RasterTile2D<u8>> {
8✔
2396
        let raster_tiles = vec![
8✔
2397
            RasterTile2D::new_with_tile_info(
8✔
2398
                TimeInterval::new_unchecked(0, 10),
8✔
2399
                TileInformation {
8✔
2400
                    global_tile_position: [-1, 0].into(),
8✔
2401
                    tile_size_in_pixels: [3, 2].into(),
8✔
2402
                    global_geo_transform: TestDefault::test_default(),
8✔
2403
                },
8✔
2404
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![1, 2, 3, 4, 5, 6]).unwrap()),
8✔
2405
            ),
8✔
2406
            RasterTile2D::new_with_tile_info(
8✔
2407
                TimeInterval::new_unchecked(0, 10),
8✔
2408
                TileInformation {
8✔
2409
                    global_tile_position: [-1, 1].into(),
8✔
2410
                    tile_size_in_pixels: [3, 2].into(),
8✔
2411
                    global_geo_transform: TestDefault::test_default(),
8✔
2412
                },
8✔
2413
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![7, 8, 9, 10, 11, 12]).unwrap()),
8✔
2414
            ),
8✔
2415
            RasterTile2D::new_with_tile_info(
8✔
2416
                TimeInterval::new_unchecked(10, 20),
8✔
2417
                TileInformation {
8✔
2418
                    global_tile_position: [-1, 0].into(),
8✔
2419
                    tile_size_in_pixels: [3, 2].into(),
8✔
2420
                    global_geo_transform: TestDefault::test_default(),
8✔
2421
                },
8✔
2422
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![12, 11, 10, 9, 8, 7]).unwrap()),
8✔
2423
            ),
8✔
2424
            RasterTile2D::new_with_tile_info(
8✔
2425
                TimeInterval::new_unchecked(10, 20),
8✔
2426
                TileInformation {
8✔
2427
                    global_tile_position: [-1, 1].into(),
8✔
2428
                    tile_size_in_pixels: [3, 2].into(),
8✔
2429
                    global_geo_transform: TestDefault::test_default(),
8✔
2430
                },
8✔
2431
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![6, 5, 4, 3, 2, 1]).unwrap()),
8✔
2432
            ),
8✔
2433
            RasterTile2D::new_with_tile_info(
8✔
2434
                TimeInterval::new_unchecked(20, 30),
8✔
2435
                TileInformation {
8✔
2436
                    global_tile_position: [-1, 0].into(),
8✔
2437
                    tile_size_in_pixels: [3, 2].into(),
8✔
2438
                    global_geo_transform: TestDefault::test_default(),
8✔
2439
                },
8✔
2440
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![1, 2, 3, 4, 5, 6]).unwrap()),
8✔
2441
            ),
8✔
2442
            RasterTile2D::new_with_tile_info(
8✔
2443
                TimeInterval::new_unchecked(20, 30),
8✔
2444
                TileInformation {
8✔
2445
                    global_tile_position: [-1, 1].into(),
8✔
2446
                    tile_size_in_pixels: [3, 2].into(),
8✔
2447
                    global_geo_transform: TestDefault::test_default(),
8✔
2448
                },
8✔
2449
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![7, 8, 9, 10, 11, 12]).unwrap()),
8✔
2450
            ),
8✔
2451
            RasterTile2D::new_with_tile_info(
8✔
2452
                TimeInterval::new_unchecked(30, 40),
8✔
2453
                TileInformation {
8✔
2454
                    global_tile_position: [-1, 0].into(),
8✔
2455
                    tile_size_in_pixels: [3, 2].into(),
8✔
2456
                    global_geo_transform: TestDefault::test_default(),
8✔
2457
                },
8✔
2458
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![12, 11, 10, 9, 8, 7]).unwrap()),
8✔
2459
            ),
8✔
2460
            RasterTile2D::new_with_tile_info(
8✔
2461
                TimeInterval::new_unchecked(30, 40),
8✔
2462
                TileInformation {
8✔
2463
                    global_tile_position: [-1, 1].into(),
8✔
2464
                    tile_size_in_pixels: [3, 2].into(),
8✔
2465
                    global_geo_transform: TestDefault::test_default(),
8✔
2466
                },
8✔
2467
                GridOrEmpty::from(Grid2D::new([3, 2].into(), vec![6, 5, 4, 3, 2, 1]).unwrap()),
8✔
2468
            ),
8✔
2469
        ];
8✔
2470
        raster_tiles
8✔
2471
    }
8✔
2472

2473
    fn make_raster_with_no_data() -> Vec<geoengine_datatypes::raster::RasterTile2D<u8>> {
10✔
2474
        let raster_tiles = vec![
10✔
2475
            RasterTile2D::new_with_tile_info(
10✔
2476
                TimeInterval::new_unchecked(0, 10),
10✔
2477
                TileInformation {
10✔
2478
                    global_tile_position: [-1, 0].into(),
10✔
2479
                    tile_size_in_pixels: [3, 2].into(),
10✔
2480
                    global_geo_transform: TestDefault::test_default(),
10✔
2481
                },
10✔
2482
                GridOrEmpty::from(EmptyGrid2D::new([3, 2].into())),
10✔
2483
            ),
10✔
2484
            RasterTile2D::new_with_tile_info(
10✔
2485
                TimeInterval::new_unchecked(0, 10),
10✔
2486
                TileInformation {
10✔
2487
                    global_tile_position: [-1, 1].into(),
10✔
2488
                    tile_size_in_pixels: [3, 2].into(),
10✔
2489
                    global_geo_transform: TestDefault::test_default(),
10✔
2490
                },
10✔
2491
                GridOrEmpty::from(
10✔
2492
                    MaskedGrid2D::new(
10✔
2493
                        Grid2D::new([3, 2].into(), vec![1, 2, 3, 42, 5, 6]).unwrap(),
10✔
2494
                        Grid2D::new([3, 2].into(), vec![true, true, true, false, true, true])
10✔
2495
                            .unwrap(),
10✔
2496
                    )
10✔
2497
                    .unwrap(),
10✔
2498
                ),
10✔
2499
            ),
10✔
2500
            RasterTile2D::new_with_tile_info(
10✔
2501
                TimeInterval::new_unchecked(10, 20),
10✔
2502
                TileInformation {
10✔
2503
                    global_tile_position: [-1, 0].into(),
10✔
2504
                    tile_size_in_pixels: [3, 2].into(),
10✔
2505
                    global_geo_transform: TestDefault::test_default(),
10✔
2506
                },
10✔
2507
                GridOrEmpty::from(
10✔
2508
                    MaskedGrid2D::new(
10✔
2509
                        Grid2D::new([3, 2].into(), vec![7, 8, 9, 42, 11, 12]).unwrap(),
10✔
2510
                        Grid2D::new([3, 2].into(), vec![true, true, true, false, true, true])
10✔
2511
                            .unwrap(),
10✔
2512
                    )
10✔
2513
                    .unwrap(),
10✔
2514
                ),
10✔
2515
            ),
10✔
2516
            RasterTile2D::new_with_tile_info(
10✔
2517
                TimeInterval::new_unchecked(10, 20),
10✔
2518
                TileInformation {
10✔
2519
                    global_tile_position: [-1, 1].into(),
10✔
2520
                    tile_size_in_pixels: [3, 2].into(),
10✔
2521
                    global_geo_transform: TestDefault::test_default(),
10✔
2522
                },
10✔
2523
                GridOrEmpty::from(EmptyGrid2D::new([3, 2].into())),
10✔
2524
            ),
10✔
2525
            RasterTile2D::new_with_tile_info(
10✔
2526
                TimeInterval::new_unchecked(20, 30),
10✔
2527
                TileInformation {
10✔
2528
                    global_tile_position: [-1, 0].into(),
10✔
2529
                    tile_size_in_pixels: [3, 2].into(),
10✔
2530
                    global_geo_transform: TestDefault::test_default(),
10✔
2531
                },
10✔
2532
                GridOrEmpty::from(
10✔
2533
                    MaskedGrid2D::new(
10✔
2534
                        Grid2D::new([3, 2].into(), vec![13, 42, 15, 16, 17, 18]).unwrap(),
10✔
2535
                        Grid2D::new([3, 2].into(), vec![true, false, true, true, true, true])
10✔
2536
                            .unwrap(),
10✔
2537
                    )
10✔
2538
                    .unwrap(),
10✔
2539
                ),
10✔
2540
            ),
10✔
2541
            RasterTile2D::new_with_tile_info(
10✔
2542
                TimeInterval::new_unchecked(20, 30),
10✔
2543
                TileInformation {
10✔
2544
                    global_tile_position: [-1, 1].into(),
10✔
2545
                    tile_size_in_pixels: [3, 2].into(),
10✔
2546
                    global_geo_transform: TestDefault::test_default(),
10✔
2547
                },
10✔
2548
                GridOrEmpty::from(EmptyGrid2D::new([3, 2].into())),
10✔
2549
            ),
10✔
2550
        ];
10✔
2551
        raster_tiles
10✔
2552
    }
10✔
2553
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc