Skip to content

Commit 666981b

Browse files
authored
Merge pull request #16 from davidklehr/main
Add the R UDF of spline interpolation
2 parents 3b2471f + ea53aeb commit 666981b

File tree

2 files changed

+155
-0
lines changed

2 files changed

+155
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
force_rstats_init <- function(dates, sensors, bandnames){
2+
3+
# Year which should be reconstructed
4+
year_to_interpolate <- 2023
5+
# Days to predict in this year and the intervall: 60 to 330 (1st March to 26th November)
6+
DOYs_to_predict <- seq(60,330,by =10)
7+
dates_to_predict <- as.Date(paste(year_to_interpolate, DOYs_to_predict), format = "%Y %j")
8+
9+
band_names <- paste(substr(as.character(dates_to_predict),1,4),substr(as.character(dates_to_predict),6,7),substr(as.character(dates_to_predict),9,10), sep ="")
10+
return(band_names)
11+
}
12+
13+
force_rstats_pixel <- function(inarray, dates, sensors, bandnames, nproc){
14+
15+
# Year which should be interpolated (same like above)
16+
year_to_interpolate <- 2023
17+
# Days to predict in this yearand the intervall: 60 to 330 (1st March to 26th November)
18+
DOYs_to_predict <- seq(60,330,by =10)
19+
dates_to_predict <- as.Date(paste(year_to_interpolate, DOYs_to_predict), format = "%Y %j")
20+
21+
# spline variables
22+
# smoothing factor for the spline reconstruction
23+
smooth_fac <- 0.5
24+
# Bolton's variable of maximum weight to assing for the predessesor years
25+
# the year of reconstruction has a wheight of 1
26+
max_weight <- 0.2
27+
28+
# cumulate the DOY to the year of interpolation
29+
# start year 2015 (example), because of Sentinel 2 launch date, for e.g. Landsat adjust to your time span
30+
start_year <- 2015
31+
DOYs_to_predict <- (year_to_interpolate - start_year) * 365 + DOYs_to_predict
32+
33+
tryCatch({
34+
# grap FORCE no-data case
35+
if (all(is.na(inarray[,1]))){
36+
return(rep(-9999,length(DOYs_to_predict)))
37+
}
38+
39+
# calculate cumulative DOYs for the input data
40+
DOYs <- as.numeric(format(dates, "%j"))
41+
years <- as.numeric(substr(as.character(dates),1,4))
42+
cumulative_DOYs <- (years - start_year) * 365 + DOYs
43+
44+
# join the data to a dataframe
45+
df <- data.frame(x=cumulative_DOYs,y=inarray[,1])
46+
47+
# ------- 1.1 calcualte Mean Function --------------
48+
euc.dist <- function(x1, x2) sqrt(sum((x1 - x2) ^ 2))
49+
50+
# define Start and endpoints for the three spline reconstuctions
51+
DOY_borders_year <- c((year_to_interpolate-start_year)*365 - 180, (year_to_interpolate-start_year+1)*365+180)
52+
DOY_borders_b <- c((year_to_interpolate-start_year-1)*365 - 180, (year_to_interpolate-start_year)*365+180)
53+
DOY_borders_bb <- c((year_to_interpolate-start_year-2)*365 - 180, (year_to_interpolate-start_year-1)*365+180)
54+
55+
# create dataframes for reconstuction
56+
data_year <- na.exclude(df[df$x %in% seq(DOY_borders_year[1],DOY_borders_year[2]),c(1,2)])
57+
data_b <- na.exclude(df[df$x %in% seq(DOY_borders_b[1] ,DOY_borders_b[2]),c(1,2)])
58+
data_bb <- na.exclude(df[df$x %in% seq(DOY_borders_bb[1],DOY_borders_bb[2]),c(1,2)])
59+
60+
# calculate spline model for year of reconstruction and predict
61+
DOYs_target_year <- seq(DOY_borders_year[1],DOY_borders_year[2])
62+
tryCatch({
63+
eval( spline_model_year <<- smooth.spline(data_year$x,data_year$y, spar =smooth_fac) )
64+
eval( predict_year <<- predict(spline_model_year, x = DOYs_target_year)$y )
65+
}, error = function(err) {
66+
return(rep(-9999,length(DOYs_to_predict)))
67+
})
68+
69+
#calculate d_max
70+
mean_year <- mean(na.exclude(data_year$y))
71+
mean_prediction <- rep(mean_year,length(DOYs_target_year))
72+
d_max = euc.dist(mean_prediction, predict_year) / 10000
73+
74+
75+
# --------- 1.2 spline for precessor years ------------
76+
# one year before
77+
# predict with DOYs of year of reconstruction, for difference calculation
78+
# between the two spline reconstructions
79+
tryCatch({
80+
eval( spline_model_b <<- smooth.spline(data_b$x+365,data_b$y, spar =smooth_fac) )
81+
eval( predict_b <<- predict(spline_model_b, x = DOYs_target_year)$y )
82+
}, error = function(err) {
83+
return(rep(-9999,length(DOYs_to_predict)))
84+
})
85+
d_b = euc.dist(predict_year, predict_b) / 10000
86+
87+
# two years before
88+
# predict with DOYs of year of reconstruction, for difference calculation
89+
# between the two spline reconstructions
90+
tryCatch({
91+
eval( spline_model_bb <<- smooth.spline(data_bb$x+(365*2),data_bb$y, spar =smooth_fac) )
92+
eval( predict_bb <<- predict(spline_model_bb, x = DOYs_target_year)$y )
93+
}, error = function(err) {
94+
return(rep(-9999,length(DOYs_to_predict)))
95+
})
96+
d_bb = euc.dist(predict_year, predict_bb) / 10000
97+
98+
# ---------- 1.3 Calculate weights -------------------
99+
# one year before
100+
if (d_max != 0) {
101+
weight_b = max_weight*(1-(d_b/d_max))
102+
if (weight_b < 0){
103+
weight_b = 0
104+
}
105+
} else {weight_b = 0}
106+
107+
# two years before
108+
if (d_max != 0) {
109+
weight_bb = max_weight*(1-(d_bb/d_max))
110+
if (weight_bb < 0){
111+
weight_bb = 0
112+
}
113+
} else {weight_bb = 0}
114+
115+
#----------- 1.4 apply weights and calculate weighted spline --------------
116+
# combine the time series to one year and assign weights to the new data points
117+
combined_x <- c(data_year$x , (data_b$x+365)[weight_b>0] , (data_bb$x + (365*2))[weight_bb>0])
118+
combined_y <- c(data_year$y , data_b$y[weight_b>0] , data_bb$y[weight_bb>0])
119+
vec_weights <- c(rep(1,length(data_year$x)),
120+
rep(weight_b,length(data_b$x))[weight_b>0],
121+
rep(weight_bb,length(data_bb$x))[weight_bb>0])
122+
123+
# calculate weighted spline
124+
tryCatch({
125+
eval( spline_model_combined <<- smooth.spline(x=combined_x, y=combined_y, w = vec_weights , spar =smooth_fac) )
126+
eval( predict_combined <<- predict(spline_model_combined, x = DOYs_to_predict)$y )
127+
}, error = function(err) {
128+
return(rep(-9999,length(DOYs_to_predict)))
129+
})
130+
return(predict_combined)
131+
132+
}, error = function(err) {
133+
return(rep(-9999,length(DOYs_to_predict)))
134+
})
135+
}
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Time series reconstruction for forest using splines
2+
3+
&copy;
4+
Copyright 2024, David Klehr
5+
6+
## Run with
7+
8+
- program: ``force-higher-level``
9+
- submodule: ``TSA``
10+
- DATE_RANGE: ``xxxx-07-01 yyyy-06-31``
11+
* xxxx = three years before your target year
12+
* yyyy = one year after your target year
13+
* e.g. for target year 2022: ``2019-07-01 2023-06-31``
14+
- UDF type: ``RSTATS_TYPE = PIXEL``
15+
- required parameters:``none``
16+
- required R libraries: ``none``
17+
18+
## References
19+
20+
- Bolton, D.K., Gray, J.M., Melaas, E.K., Moon, M., Eklundh, L., Friedl, M.A., 2020. **Continental-scale land surface phenology from harmonized Landsat 8 and Sentinel-2 imagery**. *Remote Sensing of Environment 240*, 111685. https://doi.org/10.1016/j.rse.2020.111685.

0 commit comments

Comments
 (0)