@@ -290,3 +290,210 @@ def normalize_expression(expression):
290
290
assert (
291
291
normalized_generated == normalized_expected
292
292
), f"Expected { expected_expressions } , but got { generated_expressions } "
293
+
294
+
295
+ def test_level4 (urban_shape ):
296
+
297
+ level_3_4 = np .array (
298
+ [
299
+ [
300
+ [110 , 110 , 110 , 110 , 110 , 110 ],
301
+ [110 , 110 , 110 , 110 , 110 , 110 ],
302
+ [110 , 110 , 110 , 110 , 110 , 110 ],
303
+ [110 , 110 , 110 , 110 , 110 , 110 ],
304
+ ]
305
+ ],
306
+ dtype = "uint8" ,
307
+ )
308
+
309
+ cultivated = np .array (
310
+ [
311
+ [
312
+ [111 , 111 , 111 , 111 , 111 , 111 ],
313
+ [111 , 111 , 111 , 111 , 111 , 111 ],
314
+ [112 , 112 , 112 , 112 , 112 , 112 ],
315
+ [112 , 112 , 112 , 112 , 112 , 112 ],
316
+ ]
317
+ ],
318
+ dtype = "uint8" ,
319
+ )
320
+
321
+ urban = np .array (
322
+ [
323
+ [
324
+ [255 , 255 , 255 , 255 , 255 , 255 ],
325
+ [255 , 255 , 255 , 255 , 255 , 255 ],
326
+ [255 , 255 , 255 , 255 , 255 , 255 ],
327
+ [255 , 255 , 255 , 255 , 255 , 255 ],
328
+ ]
329
+ ],
330
+ dtype = "uint8" ,
331
+ )
332
+
333
+ woody = np .array (
334
+ [
335
+ [
336
+ [113 , 114 , 113 , 113 , 113 , 113 ],
337
+ [113 , 114 , 114 , 114 , 114 , 114 ],
338
+ [113 , 114 , 113 , 113 , 113 , 113 ],
339
+ [113 , 114 , 114 , 114 , 114 , 114 ],
340
+ ]
341
+ ],
342
+ dtype = "uint8" ,
343
+ )
344
+
345
+ pv_pc_50 = np .array (
346
+ [
347
+ [
348
+ [np .nan , np .nan , 66 , 41 , 21 , 5 ],
349
+ [3 , 66 , 41 , 21 , 5 , 3 ],
350
+ [np .nan , np .nan , 66 , 41 , 21 , 5 ],
351
+ [3 , 66 , 41 , 21 , 5 , 3 ],
352
+ ]
353
+ ],
354
+ dtype = "float32" ,
355
+ )
356
+
357
+ water_season = np .array (
358
+ [
359
+ [
360
+ [255 , 255 , 255 , 255 , 255 , 255 ],
361
+ [255 , 255 , 255 , 255 , 255 , 255 ],
362
+ [255 , 255 , 255 , 255 , 255 , 255 ],
363
+ [255 , 255 , 255 , 255 , 255 , 255 ],
364
+ ]
365
+ ],
366
+ dtype = "uint8" ,
367
+ )
368
+
369
+ water_frequency = np .array (
370
+ [
371
+ [
372
+ [np .nan , np .nan , np .nan , np .nan , np .nan , np .nan ],
373
+ [np .nan , np .nan , np .nan , np .nan , np .nan , np .nan ],
374
+ [np .nan , np .nan , np .nan , np .nan , np .nan , np .nan ],
375
+ [np .nan , np .nan , np .nan , np .nan , np .nan , np .nan ],
376
+ ]
377
+ ],
378
+ dtype = "float32" ,
379
+ )
380
+
381
+ bs_pc_50 = np .array (
382
+ [
383
+ [
384
+ [np .nan , np .nan , np .nan , np .nan , np .nan , np .nan ],
385
+ [np .nan , np .nan , np .nan , np .nan , np .nan , np .nan ],
386
+ [np .nan , np .nan , np .nan , np .nan , np .nan , np .nan ],
387
+ [np .nan , np .nan , np .nan , np .nan , np .nan , np .nan ],
388
+ ]
389
+ ],
390
+ dtype = "float32" ,
391
+ )
392
+
393
+ tuples = [
394
+ (np .datetime64 ("2000-01-01T00" ), np .datetime64 ("2000-01-01" )),
395
+ ]
396
+ index = pd .MultiIndex .from_tuples (tuples , names = ["time" , "solar_day" ])
397
+
398
+ affine = Affine .translation (10 , 0 ) * Affine .scale (
399
+ (20 - 10 ) / level_3_4 .shape [2 ], (5 - 0 ) / level_3_4 .shape [1 ]
400
+ )
401
+ geobox = GeoBox (
402
+ crs = "epsg:3577" ,
403
+ affine = affine ,
404
+ width = level_3_4 .shape [2 ],
405
+ height = level_3_4 .shape [1 ],
406
+ )
407
+ coords = geobox .xr_coords ()
408
+
409
+ data_vars = {
410
+ "level_3_4" : xr .DataArray (
411
+ da .from_array (level_3_4 , chunks = (1 , - 1 , - 1 )),
412
+ dims = ("spec" , "y" , "x" ),
413
+ attrs = {"nodata" : 255 },
414
+ ),
415
+ "artificial_surface" : xr .DataArray (
416
+ da .from_array (urban , chunks = (1 , - 1 , - 1 )),
417
+ dims = ("spec" , "y" , "x" ),
418
+ attrs = {"nodata" : 255 },
419
+ ),
420
+ "cultivated" : xr .DataArray (
421
+ da .from_array (cultivated , chunks = (1 , - 1 , - 1 )),
422
+ dims = ("spec" , "y" , "x" ),
423
+ attrs = {"nodata" : 255 },
424
+ ),
425
+ "woody" : xr .DataArray (
426
+ da .from_array (woody , chunks = (1 , - 1 , - 1 )),
427
+ dims = ("spec" , "y" , "x" ),
428
+ attrs = {"nodata" : 255 },
429
+ ),
430
+ "pv_pc_50" : xr .DataArray (
431
+ da .from_array (pv_pc_50 , chunks = (1 , - 1 , - 1 )),
432
+ dims = ("spec" , "y" , "x" ),
433
+ attrs = {"nodata" : 255 },
434
+ ),
435
+ "bs_pc_50" : xr .DataArray (
436
+ da .from_array (bs_pc_50 , chunks = (1 , - 1 , - 1 )),
437
+ dims = ("spec" , "y" , "x" ),
438
+ attrs = {"nodata" : 255 },
439
+ ),
440
+ "water_frequency" : xr .DataArray (
441
+ da .from_array (water_frequency , chunks = (1 , - 1 , - 1 )),
442
+ dims = ("spec" , "y" , "x" ),
443
+ attrs = {"nodata" : 255 },
444
+ ),
445
+ "water_season" : xr .DataArray (
446
+ da .from_array (water_season , chunks = (1 , - 1 , - 1 )),
447
+ dims = ("spec" , "y" , "x" ),
448
+ attrs = {"nodata" : 255 },
449
+ ),
450
+ }
451
+
452
+ xx = xr .Dataset (data_vars = data_vars , coords = coords )
453
+ xx = xx .assign_coords (xr .Coordinates .from_pandas_multiindex (index , "spec" ))
454
+
455
+ expected_l4 = np .array (
456
+ [
457
+ [2 , 3 , 9 , 10 , 11 , 12 ],
458
+ [13 , 14 , 15 , 16 , 17 , 18 ],
459
+ [20 , 21 , 27 , 28 , 29 , 30 ],
460
+ [31 , 32 , 33 , 34 , 35 , 36 ],
461
+ ],
462
+ dtype = "uint8" ,
463
+ )
464
+
465
+ expected_l3 = np .array (
466
+ [
467
+ [111 , 111 , 111 , 111 , 111 , 111 ],
468
+ [111 , 111 , 111 , 111 , 111 , 111 ],
469
+ [112 , 112 , 112 , 112 , 112 , 112 ],
470
+ [112 , 112 , 112 , 112 , 112 , 112 ],
471
+ ],
472
+ dtype = "uint8" ,
473
+ )
474
+
475
+ stats_l4 = StatsLccsLevel4 (
476
+ measurements = ["level3" , "level4" ],
477
+ class_def_path = "s3://dea-public-data-dev/lccs_validation/c3/data_to_plot/"
478
+ "lccs_colour_scheme_golden_dark_au_c3.csv" ,
479
+ class_condition = {
480
+ "level3" : ["level1" , "artificial_surface" , "cultivated" ],
481
+ "level4" : [
482
+ "level1" ,
483
+ "level3" ,
484
+ "woody" ,
485
+ "water_season" ,
486
+ "water_frequency" ,
487
+ "pv_pc_50" ,
488
+ "bs_pc_50" ,
489
+ ],
490
+ },
491
+ data_var_condition = {"level1" : "level_3_4" },
492
+ urban_mask = urban_shape ,
493
+ filter_expression = "mock > 9" ,
494
+ mask_threshold = 0.3 ,
495
+ )
496
+ ds = stats_l4 .reduce (xx )
497
+
498
+ assert (ds .level3 .compute () == expected_l3 ).all ()
499
+ assert (ds .level4 .compute () == expected_l4 ).all ()
0 commit comments