openforis-whisp 3.0.0a7__py3-none-any.whl → 3.0.0a9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- openforis_whisp/advanced_stats.py +247 -175
- openforis_whisp/datasets.py +414 -19
- openforis_whisp/parameters/lookup_gee_datasets.csv +194 -171
- openforis_whisp/reformat.py +8 -6
- openforis_whisp/risk.py +113 -29
- {openforis_whisp-3.0.0a7.dist-info → openforis_whisp-3.0.0a9.dist-info}/METADATA +38 -124
- {openforis_whisp-3.0.0a7.dist-info → openforis_whisp-3.0.0a9.dist-info}/RECORD +9 -9
- {openforis_whisp-3.0.0a7.dist-info → openforis_whisp-3.0.0a9.dist-info}/WHEEL +1 -1
- {openforis_whisp-3.0.0a7.dist-info/licenses → openforis_whisp-3.0.0a9.dist-info}/LICENSE +0 -0
openforis_whisp/datasets.py
CHANGED
|
@@ -373,15 +373,25 @@ def g_esri_2020_2023_crop_prep():
|
|
|
373
373
|
#### disturbances by year
|
|
374
374
|
|
|
375
375
|
# RADD_year_2019 to RADD_year_< current year >
|
|
376
|
+
# Coverage: Primary humid tropical forest areas of South America, sub-Saharan Africa,
|
|
377
|
+
# and insular Southeast Asia at 10m spatial resolution.
|
|
378
|
+
# Available from January 2019 to present for Africa,
|
|
379
|
+
# and from January 2020 to present for South America and Southeast Asia.
|
|
376
380
|
def g_radd_year_prep():
|
|
377
|
-
|
|
378
|
-
|
|
381
|
+
"""
|
|
382
|
+
RADD alerts per year as multiband image.
|
|
383
|
+
Each band is binary (1 = alert detected).
|
|
384
|
+
Coverage: Primary humid tropical forest areas of South America, sub-Saharan Africa,
|
|
385
|
+
and insular Southeast Asia at 10m spatial resolution.
|
|
386
|
+
Available from January 2019 to present for Africa,
|
|
387
|
+
and from January 2020 to present for South America and Southeast Asia.
|
|
388
|
+
"""
|
|
379
389
|
radd = ee.ImageCollection("projects/radar-wur/raddalert/v1")
|
|
380
390
|
radd_date = (
|
|
381
391
|
radd.filterMetadata("layer", "contains", "alert").select("Date").mosaic()
|
|
382
392
|
)
|
|
383
393
|
start_year = 19
|
|
384
|
-
current_year =
|
|
394
|
+
current_year = CURRENT_YEAR_2DIGIT
|
|
385
395
|
|
|
386
396
|
def make_band(year, img_stack):
|
|
387
397
|
start = year * 1000
|
|
@@ -584,27 +594,412 @@ def g_radd_before_2020_prep():
|
|
|
584
594
|
).selfMask()
|
|
585
595
|
|
|
586
596
|
|
|
587
|
-
#
|
|
588
|
-
|
|
589
|
-
#
|
|
597
|
+
# DIST_after_2020
|
|
598
|
+
|
|
599
|
+
# DIST alerts are for all veg types so masked by EUFO forest 2020
|
|
600
|
+
# NB alerts only for 2024 onwards (in GEE at least, available for 2023 ofrom the GLAD site)
|
|
601
|
+
# for conistency using "...after_2020..." terminology.
|
|
602
|
+
def g_glad_dist_after_2020_prep():
|
|
603
|
+
|
|
604
|
+
# no need to filter by date as all dates are later than 2023
|
|
605
|
+
|
|
606
|
+
# Load the vegetation disturbance collections
|
|
607
|
+
VEGDISTSTATUS = ee.ImageCollection(
|
|
608
|
+
"projects/glad/HLSDIST/current/VEG-DIST-STATUS"
|
|
609
|
+
).mosaic()
|
|
610
|
+
|
|
611
|
+
# Key for high-confidence alerts (values 3, 6, 7, 8)
|
|
612
|
+
high_conf_values = [3, 6, 7, 8]
|
|
613
|
+
|
|
614
|
+
# Create high-confidence mask
|
|
615
|
+
dist_high_conf = VEGDISTSTATUS.remap(
|
|
616
|
+
high_conf_values, [1] * len(high_conf_values), 0
|
|
617
|
+
)
|
|
618
|
+
|
|
619
|
+
return dist_high_conf.updateMask(g_jrc_gfc_2020_prep()).rename(
|
|
620
|
+
"DIST_after_2020"
|
|
621
|
+
) # Mask alerts to forest and rename band
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
# # DIST_alert_2024 to DIST_alert_< current year >
|
|
625
|
+
# # Notes:
|
|
626
|
+
# # 1) so far only available for 2024 onwards in GEE
|
|
627
|
+
# # 2) masked alerts (as dist alerts are for all vegetation) to JRC EUFO 2020 layer, as close to EUDR definition
|
|
628
|
+
|
|
629
|
+
|
|
630
|
+
def g_glad_dist_year_prep():
|
|
631
|
+
"""
|
|
632
|
+
GLAD DIST alerts per year as multiband image.
|
|
633
|
+
Each band is binary (1 = high-confidence disturbance alert).
|
|
634
|
+
Uses VEG-DIST-DATE to filter by year, VEG-DIST-STATUS for confidence.
|
|
635
|
+
Masked to EUFO 2020 forest.
|
|
636
|
+
Note: Only available from 2024 onwards.
|
|
637
|
+
Fully server-side using ee.List.iterate (no Python for loop).
|
|
638
|
+
"""
|
|
639
|
+
# Load the vegetation disturbance collections
|
|
640
|
+
# Vegetation disturbance status (0-8, class flag, 8-bit)
|
|
641
|
+
VEGDISTSTATUS = ee.ImageCollection(
|
|
642
|
+
"projects/glad/HLSDIST/current/VEG-DIST-STATUS"
|
|
643
|
+
).mosaic()
|
|
644
|
+
# Initial vegetation disturbance date (>0: days since 2020-12-31, 16-bit)
|
|
645
|
+
VEGDISTDATE = ee.ImageCollection(
|
|
646
|
+
"projects/glad/HLSDIST/current/VEG-DIST-DATE"
|
|
647
|
+
).mosaic()
|
|
648
|
+
|
|
649
|
+
# Key for high-confidence alerts (values 3, 6, 7, 8)
|
|
650
|
+
# 3 = <50% loss, high confidence, ongoing
|
|
651
|
+
# 6 = ≥50% loss, high confidence, ongoing
|
|
652
|
+
# 7 = <50% loss, high confidence, finished
|
|
653
|
+
# 8 = ≥50% loss, high confidence, finished
|
|
654
|
+
high_conf_values = [3, 6, 7, 8]
|
|
655
|
+
dist_high_conf = VEGDISTSTATUS.remap(
|
|
656
|
+
high_conf_values, [1] * len(high_conf_values), 0
|
|
657
|
+
)
|
|
658
|
+
|
|
659
|
+
# Year range: 2024 to current year
|
|
660
|
+
start_year = 2024
|
|
661
|
+
end_year = CURRENT_YEAR
|
|
662
|
+
|
|
663
|
+
# Reference date for day offset calculation (2020-12-31)
|
|
664
|
+
ref_date = ee.Date("2020-12-31")
|
|
665
|
+
|
|
666
|
+
# Create first band (2024)
|
|
667
|
+
first_year = ee.Number(start_year)
|
|
668
|
+
first_start_days = ee.Date.fromYMD(first_year, 1, 1).difference(ref_date, "day")
|
|
669
|
+
first_end_days = ee.Date.fromYMD(first_year.add(1), 1, 1).difference(
|
|
670
|
+
ref_date, "day"
|
|
671
|
+
)
|
|
672
|
+
first_year_mask = VEGDISTDATE.gte(first_start_days).And(
|
|
673
|
+
VEGDISTDATE.lt(first_end_days)
|
|
674
|
+
)
|
|
675
|
+
first_band_name = ee.String("DIST_year_").cat(first_year.format("%d"))
|
|
676
|
+
first_band = (
|
|
677
|
+
first_year_mask.updateMask(dist_high_conf).rename(first_band_name).selfMask()
|
|
678
|
+
)
|
|
679
|
+
|
|
680
|
+
# Server-side iteration to add remaining years
|
|
681
|
+
years = ee.List.sequence(start_year + 1, end_year)
|
|
682
|
+
|
|
683
|
+
def add_year_band(year, img_stack):
|
|
684
|
+
year_num = ee.Number(year)
|
|
685
|
+
start_days = ee.Date.fromYMD(year_num, 1, 1).difference(ref_date, "day")
|
|
686
|
+
end_days = ee.Date.fromYMD(year_num.add(1), 1, 1).difference(ref_date, "day")
|
|
687
|
+
year_mask = VEGDISTDATE.gte(start_days).And(VEGDISTDATE.lt(end_days))
|
|
688
|
+
band_name = ee.String("DIST_year_").cat(year_num.format("%d"))
|
|
689
|
+
year_band = year_mask.updateMask(dist_high_conf).rename(band_name).selfMask()
|
|
690
|
+
return ee.Image(img_stack).addBands(year_band)
|
|
691
|
+
|
|
692
|
+
img_stack = ee.Image(years.iterate(add_year_band, first_band))
|
|
693
|
+
|
|
694
|
+
# Mask to EUFO 2020 forest
|
|
695
|
+
return img_stack.updateMask(g_jrc_gfc_2020_prep())
|
|
696
|
+
|
|
697
|
+
|
|
698
|
+
# GLAD-L (GLAD Landsat) Alerts
|
|
699
|
+
# Coverage: Entire tropics (30°N to 30°S) from January 1, 2018 to present,
|
|
700
|
+
# and from 2015 to present for select countries in the Amazon, Congo Basin,
|
|
701
|
+
# and insular Southeast Asia.
|
|
702
|
+
# Uses confidence bands per year where values >= 2 are confirmed alerts
|
|
703
|
+
# Asset paths per year:
|
|
704
|
+
# 2021: projects/glad/alert/2021final (conf21)
|
|
705
|
+
# 2022: projects/glad/alert/2022final (conf22)
|
|
706
|
+
# 2023: projects/glad/alert/2023final (conf23)
|
|
707
|
+
# 2024: NOT AVAILABLE
|
|
708
|
+
# 2025+: projects/glad/alert/UpdResult (conf25, conf26, etc.)
|
|
709
|
+
# More info: https://glad.umd.edu/dataset/glad-forest-alerts
|
|
710
|
+
|
|
711
|
+
|
|
712
|
+
# GLAD-L_after_2020 (combined alerts from 2021 to current year, excluding 2024)
|
|
713
|
+
def g_glad_l_after_2020_prep():
|
|
714
|
+
"""
|
|
715
|
+
GLAD Landsat alerts after 2020 (combined from 2021 onwards).
|
|
716
|
+
Uses confidence bands with threshold >= 2 for confirmed alerts.
|
|
717
|
+
Note: 2024 data is not available.
|
|
718
|
+
"""
|
|
719
|
+
# Load yearly assets and combine into single multiband image
|
|
720
|
+
glad_combined = (
|
|
721
|
+
ee.ImageCollection("projects/glad/alert/2021final")
|
|
722
|
+
.mosaic()
|
|
723
|
+
.select("conf21")
|
|
724
|
+
.addBands(
|
|
725
|
+
ee.ImageCollection("projects/glad/alert/2022final")
|
|
726
|
+
.mosaic()
|
|
727
|
+
.select("conf22")
|
|
728
|
+
)
|
|
729
|
+
.addBands(
|
|
730
|
+
ee.ImageCollection("projects/glad/alert/2023final")
|
|
731
|
+
.mosaic()
|
|
732
|
+
.select("conf23")
|
|
733
|
+
)
|
|
734
|
+
.addBands(
|
|
735
|
+
ee.ImageCollection("projects/glad/alert/UpdResult")
|
|
736
|
+
.mosaic()
|
|
737
|
+
.select(["conf25", "conf26"])
|
|
738
|
+
)
|
|
739
|
+
)
|
|
740
|
+
|
|
741
|
+
# Combine alerts from all available years (confidence >= 2)
|
|
742
|
+
# 2024 not available
|
|
743
|
+
combined_alerts = (
|
|
744
|
+
glad_combined.select("conf21")
|
|
745
|
+
.gte(2)
|
|
746
|
+
.Or(glad_combined.select("conf22").gte(2))
|
|
747
|
+
.Or(glad_combined.select("conf23").gte(2))
|
|
748
|
+
.Or(glad_combined.select("conf25").gte(2))
|
|
749
|
+
.Or(glad_combined.select("conf26").gte(2))
|
|
750
|
+
)
|
|
751
|
+
|
|
752
|
+
return combined_alerts.rename("GLAD-L_after_2020").selfMask()
|
|
753
|
+
|
|
590
754
|
|
|
591
|
-
#
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
755
|
+
# GLAD-L_before_2020 (combined alerts from 2017 to 2020)
|
|
756
|
+
def g_glad_l_before_2020_prep():
|
|
757
|
+
"""
|
|
758
|
+
GLAD Landsat alerts before 2020 (combined from 2017-2020 inclusive).
|
|
759
|
+
Uses confidence bands with threshold >= 2 for confirmed alerts.
|
|
760
|
+
Note: 2015 and 2016 assets are not available in GEE.
|
|
761
|
+
Coverage: Tropics (30°N to 30°S).
|
|
762
|
+
"""
|
|
763
|
+
# Load yearly assets and combine
|
|
764
|
+
glad_combined = (
|
|
765
|
+
ee.ImageCollection("projects/glad/alert/2017final")
|
|
766
|
+
.mosaic()
|
|
767
|
+
.select("conf17")
|
|
768
|
+
.addBands(
|
|
769
|
+
ee.ImageCollection("projects/glad/alert/2018final")
|
|
770
|
+
.mosaic()
|
|
771
|
+
.select("conf18")
|
|
772
|
+
)
|
|
773
|
+
.addBands(
|
|
774
|
+
ee.ImageCollection("projects/glad/alert/2019final")
|
|
775
|
+
.mosaic()
|
|
776
|
+
.select("conf19")
|
|
777
|
+
)
|
|
778
|
+
.addBands(
|
|
779
|
+
ee.ImageCollection("projects/glad/alert/2020final")
|
|
780
|
+
.mosaic()
|
|
781
|
+
.select("conf20")
|
|
782
|
+
)
|
|
783
|
+
)
|
|
595
784
|
|
|
596
|
-
#
|
|
597
|
-
|
|
785
|
+
# Combine alerts from all available years (confidence >= 2)
|
|
786
|
+
combined_alerts = (
|
|
787
|
+
glad_combined.select("conf17")
|
|
788
|
+
.gte(2)
|
|
789
|
+
.Or(glad_combined.select("conf18").gte(2))
|
|
790
|
+
.Or(glad_combined.select("conf19").gte(2))
|
|
791
|
+
.Or(glad_combined.select("conf20").gte(2))
|
|
792
|
+
)
|
|
598
793
|
|
|
599
|
-
|
|
600
|
-
# dist_high_conf = VEGDISTSTATUS.remap(
|
|
601
|
-
# high_conf_values, [1] * len(high_conf_values), 0
|
|
602
|
-
# )
|
|
794
|
+
return combined_alerts.rename("GLAD-L_before_2020").selfMask()
|
|
603
795
|
|
|
604
|
-
# return dist_high_conf.updateMask(jrc_gfc_2020_prep()).rename(
|
|
605
|
-
# "DIST_after_2020"
|
|
606
|
-
# ) # Mask alerts to forest and rename band
|
|
607
796
|
|
|
797
|
+
# GLAD-L timeseries - multiband image with one band per year
|
|
798
|
+
def g_glad_l_year_prep():
|
|
799
|
+
"""
|
|
800
|
+
GLAD Landsat alerts per year as multiband image.
|
|
801
|
+
Each band is binary (1 = alert with confidence >= 2).
|
|
802
|
+
Coverage: Entire tropics (30°N to 30°S) from January 1, 2018 to present,
|
|
803
|
+
and from 2017 to present for select countries in the Amazon,
|
|
804
|
+
Congo Basin, and insular Southeast Asia.
|
|
805
|
+
Note: 2015 and 2016 assets are not available in GEE.
|
|
806
|
+
Note: 2024 data is not available.
|
|
807
|
+
Includes years from 2017 onwards.
|
|
808
|
+
"""
|
|
809
|
+
# Build multiband image with all available years
|
|
810
|
+
# Years 2017-2023 use YYYYfinal assets, 2025+ use UpdResult
|
|
811
|
+
# Note: 2015final and 2016final assets do not exist in GEE
|
|
812
|
+
img_stack = (
|
|
813
|
+
# 2017
|
|
814
|
+
ee.ImageCollection("projects/glad/alert/2017final")
|
|
815
|
+
.mosaic()
|
|
816
|
+
.select("conf17")
|
|
817
|
+
.gte(2)
|
|
818
|
+
.rename("GLAD-L_year_2017")
|
|
819
|
+
.selfMask()
|
|
820
|
+
# 2018
|
|
821
|
+
.addBands(
|
|
822
|
+
ee.ImageCollection("projects/glad/alert/2018final")
|
|
823
|
+
.mosaic()
|
|
824
|
+
.select("conf18")
|
|
825
|
+
.gte(2)
|
|
826
|
+
.rename("GLAD-L_year_2018")
|
|
827
|
+
.selfMask()
|
|
828
|
+
)
|
|
829
|
+
# 2019
|
|
830
|
+
.addBands(
|
|
831
|
+
ee.ImageCollection("projects/glad/alert/2019final")
|
|
832
|
+
.mosaic()
|
|
833
|
+
.select("conf19")
|
|
834
|
+
.gte(2)
|
|
835
|
+
.rename("GLAD-L_year_2019")
|
|
836
|
+
.selfMask()
|
|
837
|
+
)
|
|
838
|
+
# 2020
|
|
839
|
+
.addBands(
|
|
840
|
+
ee.ImageCollection("projects/glad/alert/2020final")
|
|
841
|
+
.mosaic()
|
|
842
|
+
.select("conf20")
|
|
843
|
+
.gte(2)
|
|
844
|
+
.rename("GLAD-L_year_2020")
|
|
845
|
+
.selfMask()
|
|
846
|
+
)
|
|
847
|
+
# 2021
|
|
848
|
+
.addBands(
|
|
849
|
+
ee.ImageCollection("projects/glad/alert/2021final")
|
|
850
|
+
.mosaic()
|
|
851
|
+
.select("conf21")
|
|
852
|
+
.gte(2)
|
|
853
|
+
.rename("GLAD-L_year_2021")
|
|
854
|
+
.selfMask()
|
|
855
|
+
)
|
|
856
|
+
# 2022
|
|
857
|
+
.addBands(
|
|
858
|
+
ee.ImageCollection("projects/glad/alert/2022final")
|
|
859
|
+
.mosaic()
|
|
860
|
+
.select("conf22")
|
|
861
|
+
.gte(2)
|
|
862
|
+
.rename("GLAD-L_year_2022")
|
|
863
|
+
.selfMask()
|
|
864
|
+
)
|
|
865
|
+
# 2023
|
|
866
|
+
.addBands(
|
|
867
|
+
ee.ImageCollection("projects/glad/alert/2023final")
|
|
868
|
+
.mosaic()
|
|
869
|
+
.select("conf23")
|
|
870
|
+
.gte(2)
|
|
871
|
+
.rename("GLAD-L_year_2023")
|
|
872
|
+
.selfMask()
|
|
873
|
+
)
|
|
874
|
+
# 2024 NOT AVAILABLE
|
|
875
|
+
# 2025
|
|
876
|
+
.addBands(
|
|
877
|
+
ee.ImageCollection("projects/glad/alert/UpdResult")
|
|
878
|
+
.mosaic()
|
|
879
|
+
.select("conf25")
|
|
880
|
+
.gte(2)
|
|
881
|
+
.rename("GLAD-L_year_2025")
|
|
882
|
+
.selfMask()
|
|
883
|
+
)
|
|
884
|
+
# 2026
|
|
885
|
+
.addBands(
|
|
886
|
+
ee.ImageCollection("projects/glad/alert/UpdResult")
|
|
887
|
+
.mosaic()
|
|
888
|
+
.select("conf26")
|
|
889
|
+
.gte(2)
|
|
890
|
+
.rename("GLAD-L_year_2026")
|
|
891
|
+
.selfMask()
|
|
892
|
+
)
|
|
893
|
+
)
|
|
894
|
+
|
|
895
|
+
return img_stack
|
|
896
|
+
|
|
897
|
+
|
|
898
|
+
# GLAD-S2 (GLAD Sentinel-2) Alerts
|
|
899
|
+
# GLAD-S2_after_2020 (combined alerts from 2021 to current year)
|
|
900
|
+
def g_glad_s2_after_2020_prep():
|
|
901
|
+
"""
|
|
902
|
+
GLAD Sentinel-2 alerts after 2020 (filtered and combined from 2021 onwards - original data starts 2019).
|
|
903
|
+
Uses alert band with threshold >= 2 for confirmed alerts.
|
|
904
|
+
Coverage: Primary humid tropical forest within Amazon basin region.
|
|
905
|
+
https://glad.umd.edu/dataset/glad-forest-alerts
|
|
906
|
+
"""
|
|
907
|
+
col = "projects/glad/S2alert"
|
|
908
|
+
s2alert = ee.Image(col + "/alert")
|
|
909
|
+
alert_date = ee.Image(col + "/alertDate")
|
|
910
|
+
|
|
911
|
+
# Date encoding: days since 2019-01-01
|
|
912
|
+
# 2020-12-31 = 730 days (end of 2020)
|
|
913
|
+
days_end_2020 = 730
|
|
914
|
+
|
|
915
|
+
# Filter alerts after 2020 with confidence >= 2
|
|
916
|
+
# - alert: confidence band (0-4, where 4 is highest confidence)
|
|
917
|
+
alerts_after_2020 = s2alert.gte(2).And(alert_date.gt(days_end_2020))
|
|
918
|
+
|
|
919
|
+
return alerts_after_2020.rename("GLAD-S2_after_2020").selfMask()
|
|
920
|
+
|
|
921
|
+
|
|
922
|
+
# GLAD-S2_before_2020 (combined alerts from 2019 to 2020)
|
|
923
|
+
def g_glad_s2_before_2020_prep():
|
|
924
|
+
"""
|
|
925
|
+
GLAD Sentinel-2 alerts before 2020 (from 2019-01-01 to 2020-12-31 inclusive).
|
|
926
|
+
Uses alert band with threshold >= 2 for confirmed alerts.
|
|
927
|
+
Coverage: Primary humid tropical forest within Amazon basin region.
|
|
928
|
+
Note: Data starts from 2019.
|
|
929
|
+
"""
|
|
930
|
+
col = "projects/glad/S2alert"
|
|
931
|
+
s2alert = ee.Image(col + "/alert")
|
|
932
|
+
alert_date = ee.Image(col + "/alertDate")
|
|
933
|
+
|
|
934
|
+
# Date encoding: days since 2019-01-01
|
|
935
|
+
# 2019-01-01 = 0, 2020-12-31 = 730 days
|
|
936
|
+
days_end_2020 = 730
|
|
937
|
+
|
|
938
|
+
# Filter alerts up to end of 2020 with confidence >= 2
|
|
939
|
+
alerts_before_2020 = s2alert.gte(2).And(alert_date.lte(days_end_2020))
|
|
940
|
+
|
|
941
|
+
return alerts_before_2020.rename("GLAD-S2_before_2020").selfMask()
|
|
942
|
+
|
|
943
|
+
|
|
944
|
+
# GLAD-S2 timeseries - multiband image with one band per year
|
|
945
|
+
def g_glad_s2_year_prep():
|
|
946
|
+
"""
|
|
947
|
+
GLAD Sentinel-2 alerts per year as multiband image.
|
|
948
|
+
Each band is binary (1 = alert with confidence >= 2).
|
|
949
|
+
Coverage: Primary humid tropical forest areas of South America
|
|
950
|
+
from January 2019 to present.
|
|
951
|
+
Date encoding: days since 2019-01-01.
|
|
952
|
+
Includes years from 2019 onwards.
|
|
953
|
+
"""
|
|
954
|
+
col = "projects/glad/S2alert"
|
|
955
|
+
s2alert = ee.Image(col + "/alert")
|
|
956
|
+
alert_date = ee.Image(col + "/alertDate")
|
|
957
|
+
|
|
958
|
+
# Confidence threshold for confirmed alerts
|
|
959
|
+
confirmed = s2alert.gte(2)
|
|
960
|
+
|
|
961
|
+
# Date encoding: days since 2019-01-01
|
|
962
|
+
# Year boundaries (days since 2019-01-01):
|
|
963
|
+
# 2019-01-01 = 0, 2020-01-01 = 365, 2021-01-01 = 731, 2022-01-01 = 1096
|
|
964
|
+
# 2023-01-01 = 1461, 2024-01-01 = 1827, 2025-01-01 = 2192, 2026-01-01 = 2557
|
|
965
|
+
ref_date = ee.Date("2019-01-01")
|
|
966
|
+
|
|
967
|
+
# Build multiband image with available years (data starts 2019)
|
|
968
|
+
start_year = 2019
|
|
969
|
+
end_year = CURRENT_YEAR
|
|
970
|
+
|
|
971
|
+
# Create first band (2019)
|
|
972
|
+
first_year = ee.Number(start_year)
|
|
973
|
+
first_start_days = ee.Date.fromYMD(first_year, 1, 1).difference(ref_date, "day")
|
|
974
|
+
first_end_days = ee.Date.fromYMD(first_year.add(1), 1, 1).difference(
|
|
975
|
+
ref_date, "day"
|
|
976
|
+
)
|
|
977
|
+
first_year_mask = alert_date.gte(first_start_days).And(
|
|
978
|
+
alert_date.lt(first_end_days)
|
|
979
|
+
)
|
|
980
|
+
first_band_name = ee.String("GLAD-S2_year_").cat(first_year.format("%d"))
|
|
981
|
+
first_band = (
|
|
982
|
+
confirmed.updateMask(first_year_mask).rename(first_band_name).selfMask()
|
|
983
|
+
)
|
|
984
|
+
|
|
985
|
+
# Server-side iteration to add remaining years
|
|
986
|
+
years = ee.List.sequence(start_year + 1, end_year)
|
|
987
|
+
|
|
988
|
+
def add_year_band(year, img_stack):
|
|
989
|
+
year_num = ee.Number(year)
|
|
990
|
+
start_days = ee.Date.fromYMD(year_num, 1, 1).difference(ref_date, "day")
|
|
991
|
+
end_days = ee.Date.fromYMD(year_num.add(1), 1, 1).difference(ref_date, "day")
|
|
992
|
+
year_mask = alert_date.gte(start_days).And(alert_date.lt(end_days))
|
|
993
|
+
band_name = ee.String("GLAD-S2_year_").cat(year_num.format("%d"))
|
|
994
|
+
year_band = confirmed.updateMask(year_mask).rename(band_name).selfMask()
|
|
995
|
+
return ee.Image(img_stack).addBands(year_band)
|
|
996
|
+
|
|
997
|
+
img_stack = ee.Image(years.iterate(add_year_band, first_band))
|
|
998
|
+
|
|
999
|
+
return img_stack
|
|
1000
|
+
|
|
1001
|
+
|
|
1002
|
+
#### disturbances combined (split into before and after 2020)
|
|
608
1003
|
|
|
609
1004
|
# TMF_deg_before_2020
|
|
610
1005
|
def g_tmf_deg_before_2020_prep():
|