Skip to content
Snippets Groups Projects
Commit 5e95d08b authored by Neha Hunka's avatar Neha Hunka
Browse files

FH_models for ERL

parent c75256da
No related branches found
No related tags found
No related merge requests found
%% Cell type:code id:7e1b7e4a-e6f5-47df-a012-1d0502e99bac tags:
``` R
###############################################################################################################
##################### FAY-HERRIOT MODELS ######################################################################
###############################################################################################################
#### The following provides the code associated with artcle (please cite):
# @article{10.1088/1748-9326/ad0b60,
# author={Hunka, Neha and Santoro, Maurizio and Armston, John and Dubayah, Ralph and McRoberts,
# Ronald and Næsset, Erik and Quegan, Shaun and Urbazaev, Mikhail and Pascual, Adrián and May,
# Paul B and Minor, David and Leitold, Veronika and Basak, Paromita and Liang, Mengyu and Melo,
# Joana and Herold, Martin and Malága, Natalia and Wilson, Sylvia and Montesinos, Patricia Durán
# and Arana, Alexs and De La Cruz Paiva, Ricardo Ernesto and Ferrand, Jeremy and Keoka,
# Somphavy and Guerra-Hernandez, Juan and Duncanson, Laura},
# title={On the NASA MAP and ESA CCI biomass maps: Aligning for uptake in the UNFCCC global stocktake},
# journal={Environmental Research Letters},
# url={http://iopscience.iop.org/article/10.1088/1748-9326/ad0b60},
# year={2023}
# }
#### Please contact authors Paul May (paul.may@sdsmt.edu) and Neha Hunka (nhunka@umd.edu) for further information
##################################################################################################################
##################################################################################################################
##################################################################################################################
```
%% Cell type:code id:8c2b15bd-ae47-4ee6-b183-931860fe969c tags:
``` R
####################################################################
# Define functions
####################################################################
round_df = function(df, digits) {
nums - vapply(df, is.numeric, FUN.VALUE = logical(1))
df[,nums] - round(df[,nums], digits = digits)
(df)
}
# Function to compute the maximum likelihood estimates (MLEs) for a Fay-Herriot model.
# The function asks for
# x = covariates,
# y = AGB map estimates,
# vardir = sampling variance of map estimates
# If the variance associated with x (i.e. NFI estimates) is available, it may be injested too, see example 2 below.
FHfit = function(y, x, vardir){
n = length(y) # sample size
x1 = cbind(rep(1,n), x) # Appends a column of 1's to the covariate matrix to allow an intercept
p = ncol(x1) # total number of regression coefficients (including the intercept)
# Below is the negative log-likelihood, dependent on log(\sigma^2),
# where \sigma^2 is the variance of the regression error
# i.e. the error that would remain even with 0 sampling error.
# The MLEs for regression coefficients are available in closed form
# GIVEN a fixed \sigma_2, so the likelihood only depends on \sigma_2.
# The log transformation is the release the strictly positive constraints
# on \sigma^2. This eases the numerical optimization with respect to \sigma^2.
nll = function(log.s2, y, x1, vardir){
s2 = exp(log.s2) # backtransform to yield \sigma_2
S = s2 + vardir # Compute the diagonal of $\Sigma$, the covariance matrix for the total error (sampling + regression error).
x1s = x1/S # Compute \Sigma^{-1}x1
ys = y/S # Compute \Sigma^{-1}y
Coefficient.hat = solve(crossprod(x1s, x1), crossprod(x1s, y)) #Use the previous two quantities to compute the GLS estimates for the regression coeffecients
res = y - x1%*%Coefficient.hat # The GLS residuals
ress = ys - x1s%*%Coefficient.hat # \Sigma^{-1} times the GLS residuals
obj = sum(log(S)) + crossprod(res, ress)[1,1] #negative log likelihood = log-determinant of the error covariance matrix + dot-product of standardized residuals
return(obj) # return the negative log-likelihood
}
# The following line computes the MLE for \sigma^2 by minimizing the negative log-likelihood.
# (minimizing negative is the same as maximizing the positive)
# A lower bound of \sigma^2 = 0.001 and an
# upper bound of \sigma^2 = the sample variance of y
# is placed to avoid potential numerical issues in the optimization.
# The upper bound is almost certainly always reasonable
# (the regression variance should be less than the total variance)
# but depending on the units, the lower bound can be changed.
# Note that if the units are Mg/ha biomass, this lower bound corresponds
# to a error standard deviation of ~0.03 Mg/ha, implausibly low for most applications...
# However, if your returned MLE for s2 (\sigma^2) is equal to the lower bound,
# you should lower this lower bound
fit = optimize(interval = c(log(0.001), # Lower bound for search
log(var(y))), # Upper bound for search
f = nll, # The function to be minimized
y = y, x1 = x1, vardir = vardir) # The variables nll() needs.
s2 = exp(fit$minimum) # Undo the log transform to yield the MLE for \sigma^2
S = s2 + vardir # Compute the diagonal of $\Sigma$, the covariance matrix for the total error (sampling + regression error).
x1s = x1/S # Compute \Sigma^{-1}x1
ys = y/S # Compute \Sigma^{-1}y
Coefficient.hat = solve(crossprod(x1s, x1), crossprod(x1s, y)) #Use the previous two quantities to compute the GLS estimates for the regression coeffecients
Coefficient.var = chol2inv(chol(crossprod(x1s, x1))) #covariance matrix of the reg. coefficients
Coefficient.sd = sqrt(diag(Coefficient.var))
p.vals = 2*pt(Coefficient.hat/Coefficient.sd, df = n-p, lower.tail = F) #p-values, computed using a t distribution
return(list(est.coefs = Coefficient.hat, coef.sds = Coefficient.sd, p.vals = p.vals, ref.var = s2))
}
```
%% Cell type:code id:d6fb0c14-be93-4b3e-b851-c1a4b66bef86 tags:
``` R
###################################################################################
# Example 1: Simulated data with variance only in the response variable (y)
###################################################################################
### Generate the data ###
set.seed(123)
n = 80 # Sample size for simulated data
intercept.true = 0 # The true intercept term
Coefficient.true = 2 # The true coefficient for x
s2.true = 25 # The true \sigma^2, i.e. the regression variance, or random effects variance
vardir = runif(n, 25, 100) # Random sampling varainces
x = runif(n, 0, 20) # Random covariates
y.true = intercept.true + x*Coefficient.true + rnorm(n, sd = sqrt(s2.true)) # Simulate y with no sampling variance
### Plot the true data and the data with sampling variance ###
par(mfrow = c(2,2))
plot(x, y.true, main = "No sampling error")
y.est = y.true + rnorm(n, sd = sqrt(vardir)) # Add the sampling variance.
plot(x, y.est, main = "With sampling error")
### Fit the model ###
sim.fit = FHfit(y = y.est, x = x, vardir = vardir)
Table = data.frame(round(sim.fit$est.coefs,digits=2), round(sim.fit$coef.sds,digits=2), round(sim.fit$est.coefs/sim.fit$coef.sds,digits=2), round(sim.fit$p.vals,digits=2))
Table <- cbind( . = rownames(Table), Table)
rownames(Table) <- 1:nrow(Table)
colnames(Table) <- c('y ~ x:','Coefficient','SE','t-value','p-value') # p-value > 0.05 indicates no significant systematic deviation
Table['y ~ x:'] <- c('Intercept','Slope')
Table <- Table[head(seq_len(ncol(Table)), -2)]
Table
### Check results against know true values ###
# The estimated regression coefficients...
sim.fit$est.coefs
# ... compared to the actual values
c(intercept.true, Coefficient.true)
# They are well within the uncertainties of each other
(sim.fit$est.coefs - c(intercept.true, Coefficient.true))/sim.fit$coef.sds
# And the estimated \sigma^2 (i.e. regression variance or random effects variance)
sim.fit$ref.var
# ... compared to actual value
s2.true
# ... looking good!
```
%% Output
A data.frame: 2 × 3
| <!--/--> | y ~ x: &lt;chr&gt; | Coefficient &lt;dbl&gt; | SE &lt;dbl&gt; |
|---|---|---|---|
| 1 | Intercept | 0.08 | 2.04 |
| 2 | Slope | 1.99 | 0.18 |
A data.frame: 2 × 3
\begin{tabular}{r|lll}
& y \textasciitilde{} x: & Coefficient & SE\\
& <chr> & <dbl> & <dbl>\\
\hline
1 & Intercept & 0.08 & 2.04\\
2 & Slope & 1.99 & 0.18\\
\end{tabular}
A matrix: 2 × 1 of type dbl
| <!----> | 0.08441531 |
| x | 1.98601957 |
A matrix: 2 × 1 of type dbl
\begin{tabular}{r|l}
& 0.08441531\\
x & 1.98601957\\
\end{tabular}
1. 0
2. 2
\begin{enumerate*}
\item 0
\item 2
\end{enumerate*}
A matrix: 2 × 1 of type dbl
| <!----> | 0.04130370 |
| x | -0.07615911 |
A matrix: 2 × 1 of type dbl
\begin{tabular}{r|l}
& 0.04130370\\
x & -0.07615911\\
\end{tabular}
25.0639250909692
25.0639250909692
25
25
%% Cell type:code id:1b3ea6fc-a7b7-4dcf-8be8-af4f0dc87df0 tags:
``` R
################################################################################
# Example 2: Simulated NFI means and AGB map means, both with estimated variance
################################################################################
data <- read.csv('/projects/my-private-bucket/Data/PAPER1_Private/NFI_MAP_AGBD_mock.csv')
data
NFI = data$NFI_AGBD_mean_estimate # Mean AGBD estimate from National Forest Inventory
NFI.var = data$NFI_AGBD_var_estimate # Variance of AGBD estimate from National Forest Inventory
MAP = data$AGBD_Map_mean_estimate # Mean AGBD estimate from EO-based map
MAP.var = data$AGBD_Map_var_estimate # Variance of AGBD estimate from EO-based map
slope = data$Slope_degrees # Estimate of topographic slope in degrees
### FH model relating MAP and NFI mean AGBD estimates
mod1 =FHfit(y = MAP-NFI, x = NULL, vardir = NFI.var + MAP.var)
Table = data.frame(round(mod1$est.coefs,digits=2), round(mod1$coef.sds,digits=2), round(mod1$est.coefs/mod1$coef.sds,digits=2), round(mod1$p.vals,digits=2))
Table <- cbind( . = rownames(Table), Table)
rownames(Table) <- 1:nrow(Table)
colnames(Table) <- c('MAP - NFI ~ null:','Coefficient','SE','t-value','p-value') # p-value > 0.05 indicates no significant systematic deviation
Table['y ~ x:'] <- c('Intercept')
Table['MAP - NFI ~ null:'] <- c('Intercept')
Table
### FH model relating difference in MAP and NFI mean AGBD estimates to terrain slope
diff = MAP - NFI
intercept = rep(1, length(MAP))
my.mod = FHfit(y = diff, x = slope, vardir = NFI.var + MAP.var)
null.mod = FHfit(y = diff, x = NULL, vardir = NFI.var + MAP.var)
R2 = 1 - my.mod$ref.var/null.mod$ref.var
Table = data.frame(round(my.mod$est.coefs,digits=2), round(my.mod$coef.sds,digits=2), round(my.mod$est.coefs/my.mod$coef.sds,digits=2), round(my.mod$p.vals,digits=2))
Table <- cbind( . = rownames(Table), Table)
rownames(Table) <- 1:nrow(Table)
colnames(Table) <- c('MAP - NFI ~ Slope:','Coefficient','SE','t-value','p-value') # p-value < 0.05 on slope shows significant influence of terrain-slope
Table['MAP - NFI ~ Slope:'] <- c('Intercept','Slope')
Table[nrow(Table) + 1,1] = "Fay-Herriot R-squared = " # R2 indicates the proportion of variation in MAP minus NFI estimated AGBD explained by terrain-slope
Table[3,2] = round(R2,digits=2)
Table[3,3:5] = ''
Table
```
%% Output
A data.frame: 114 × 6
| STRATUM_ID &lt;int&gt; | NFI_AGBD_mean_estimate &lt;dbl&gt; | NFI_AGBD_var_estimate &lt;int&gt; | AGBD_Map_mean_estimate &lt;dbl&gt; | AGBD_Map_var_estimate &lt;int&gt; | Slope_degrees &lt;int&gt; |
|---|---|---|---|---|---|
| 0 | 88.33389 | 8390 | 224.841032 | 146 | 28 |
| 1 | 76.35538 | 405 | 83.410328 | 21 | 17 |
| 2 | 75.22345 | 381 | 120.670726 | 25 | 23 |
| 3 | 61.54510 | 481 | 120.491803 | 41 | 24 |
| 4 | 53.74778 | 341 | 23.590848 | 10 | 1 |
| 5 | 40.53338 | 455 | 85.090941 | 35 | 24 |
| 6 | 38.35340 | 308 | 42.749728 | 52 | 14 |
| 7 | 34.08328 | 310 | 62.525215 | 3 | 21 |
| 8 | 11.47595 | 302 | 9.530497 | 8 | 11 |
| 9 | 8.08554 | 471 | 18.724358 | 6 | 17 |
| 10 | 3.98021 | 329 | 8.819733 | 11 | 13 |
| 11 | 255.28000 | 281 | 231.252937 | 20 | 5 |
| 12 | 205.53000 | 477 | 138.329355 | 4 | 2 |
| 13 | 147.01000 | 319 | 251.692943 | 89 | 29 |
| 14 | 100.34000 | 353 | 181.503869 | 31 | 30 |
| 15 | 17.20000 | 419 | 32.250884 | 9 | 23 |
| 16 | 242.40000 | 417 | 178.926543 | 12 | 17 |
| 17 | 253.10000 | 247 | 221.547996 | 247 | 23 |
| 18 | 161.70000 | 290 | 164.048295 | 32 | 21 |
| 19 | 135.30000 | 294 | 173.818288 | 83 | 22 |
| 20 | 98.44000 | 466 | 55.802725 | 73 | 6 |
| 21 | 145.75832 | 448 | 146.011767 | 54 | 24 |
| 22 | 104.17290 | 485 | 108.586614 | 1444 | 21 |
| 23 | 90.72966 | 375 | 117.060850 | 4026 | 21 |
| 24 | 61.73301 | 359 | 40.511025 | 185 | 17 |
| 25 | 40.98321 | 365 | 71.996413 | 156 | 17 |
| 26 | 60.07196 | 306 | 77.429700 | 919 | 21 |
| 27 | 121.86087 | 395 | 152.793676 | 461 | 27 |
| 28 | 98.65765 | 269 | 126.183206 | 120 | 27 |
| 29 | 115.17169 | 462 | 158.897071 | 3285 | 28 |
| ⋮ | ⋮ | ⋮ | ⋮ | ⋮ | ⋮ |
| 84 | 22.76055 | 323 | 31.81804 | 29 | 16 |
| 85 | 22.11428 | 375 | 48.10163 | 618 | 19 |
| 86 | 166.42153 | 444 | 109.17943 | 16 | 20 |
| 87 | 107.72769 | 434 | 77.73533 | 39 | 18 |
| 88 | 114.85776 | 246 | 89.92191 | 609 | 19 |
| 89 | 143.19344 | 390 | 106.27367 | 65 | 16 |
| 90 | 117.51548 | 268 | 119.11776 | 148 | 17 |
| 91 | 65.92355 | 253 | 108.08782 | 1359 | 13 |
| 92 | 138.88643 | 358 | 140.11918 | 505 | 21 |
| 93 | 126.08928 | 202 | 143.54333 | 160 | 18 |
| 94 | 173.04908 | 329 | 171.54238 | 631 | 22 |
| 95 | 144.88942 | 244 | 151.58180 | 186 | 20 |
| 96 | 53.46020 | 244 | 63.50853 | 859 | 19 |
| 97 | 47.53277 | 317 | 60.91211 | 56 | 17 |
| 98 | 55.31501 | 319 | 65.97939 | 2429 | 19 |
| 99 | 105.67049 | 270 | 97.08879 | 17 | 21 |
| 100 | 102.61734 | 229 | 96.95680 | 273 | 21 |
| 101 | 88.80730 | 239 | 85.82969 | 822 | 17 |
| 102 | 78.34547 | 431 | 87.10983 | 166 | 21 |
| 103 | 66.54380 | 435 | 83.32995 | 56 | 16 |
| 104 | 78.47648 | 353 | 84.68644 | 549 | 15 |
| 105 | 87.89833 | 254 | 79.65267 | 69 | 25 |
| 106 | 106.65287 | 463 | 91.04976 | 29 | 24 |
| 107 | 72.07227 | 266 | 90.89109 | 1702 | 26 |
| 108 | 220.67900 | 319 | 257.83470 | 2186 | 22 |
| 109 | 152.65600 | 441 | 251.42361 | 924 | 21 |
| 110 | 129.93800 | 205 | 180.36685 | 55 | 20 |
| 111 | 64.77900 | 292 | 146.44842 | 1765 | 15 |
| 112 | 231.45082 | 393 | 187.31929 | 27 | 11 |
| 113 | 173.72852 | 237 | 169.26756 | 10 | 11 |
A data.frame: 114 × 6
\begin{tabular}{llllll}
STRATUM\_ID & NFI\_AGBD\_mean\_estimate & NFI\_AGBD\_var\_estimate & AGBD\_Map\_mean\_estimate & AGBD\_Map\_var\_estimate & Slope\_degrees\\
<int> & <dbl> & <int> & <dbl> & <int> & <int>\\
\hline
0 & 88.33389 & 8390 & 224.841032 & 146 & 28\\
1 & 76.35538 & 405 & 83.410328 & 21 & 17\\
2 & 75.22345 & 381 & 120.670726 & 25 & 23\\
3 & 61.54510 & 481 & 120.491803 & 41 & 24\\
4 & 53.74778 & 341 & 23.590848 & 10 & 1\\
5 & 40.53338 & 455 & 85.090941 & 35 & 24\\
6 & 38.35340 & 308 & 42.749728 & 52 & 14\\
7 & 34.08328 & 310 & 62.525215 & 3 & 21\\
8 & 11.47595 & 302 & 9.530497 & 8 & 11\\
9 & 8.08554 & 471 & 18.724358 & 6 & 17\\
10 & 3.98021 & 329 & 8.819733 & 11 & 13\\
11 & 255.28000 & 281 & 231.252937 & 20 & 5\\
12 & 205.53000 & 477 & 138.329355 & 4 & 2\\
13 & 147.01000 & 319 & 251.692943 & 89 & 29\\
14 & 100.34000 & 353 & 181.503869 & 31 & 30\\
15 & 17.20000 & 419 & 32.250884 & 9 & 23\\
16 & 242.40000 & 417 & 178.926543 & 12 & 17\\
17 & 253.10000 & 247 & 221.547996 & 247 & 23\\
18 & 161.70000 & 290 & 164.048295 & 32 & 21\\
19 & 135.30000 & 294 & 173.818288 & 83 & 22\\
20 & 98.44000 & 466 & 55.802725 & 73 & 6\\
21 & 145.75832 & 448 & 146.011767 & 54 & 24\\
22 & 104.17290 & 485 & 108.586614 & 1444 & 21\\
23 & 90.72966 & 375 & 117.060850 & 4026 & 21\\
24 & 61.73301 & 359 & 40.511025 & 185 & 17\\
25 & 40.98321 & 365 & 71.996413 & 156 & 17\\
26 & 60.07196 & 306 & 77.429700 & 919 & 21\\
27 & 121.86087 & 395 & 152.793676 & 461 & 27\\
28 & 98.65765 & 269 & 126.183206 & 120 & 27\\
29 & 115.17169 & 462 & 158.897071 & 3285 & 28\\
⋮ & ⋮ & ⋮ & ⋮ & ⋮ & ⋮\\
84 & 22.76055 & 323 & 31.81804 & 29 & 16\\
85 & 22.11428 & 375 & 48.10163 & 618 & 19\\
86 & 166.42153 & 444 & 109.17943 & 16 & 20\\
87 & 107.72769 & 434 & 77.73533 & 39 & 18\\
88 & 114.85776 & 246 & 89.92191 & 609 & 19\\
89 & 143.19344 & 390 & 106.27367 & 65 & 16\\
90 & 117.51548 & 268 & 119.11776 & 148 & 17\\
91 & 65.92355 & 253 & 108.08782 & 1359 & 13\\
92 & 138.88643 & 358 & 140.11918 & 505 & 21\\
93 & 126.08928 & 202 & 143.54333 & 160 & 18\\
94 & 173.04908 & 329 & 171.54238 & 631 & 22\\
95 & 144.88942 & 244 & 151.58180 & 186 & 20\\
96 & 53.46020 & 244 & 63.50853 & 859 & 19\\
97 & 47.53277 & 317 & 60.91211 & 56 & 17\\
98 & 55.31501 & 319 & 65.97939 & 2429 & 19\\
99 & 105.67049 & 270 & 97.08879 & 17 & 21\\
100 & 102.61734 & 229 & 96.95680 & 273 & 21\\
101 & 88.80730 & 239 & 85.82969 & 822 & 17\\
102 & 78.34547 & 431 & 87.10983 & 166 & 21\\
103 & 66.54380 & 435 & 83.32995 & 56 & 16\\
104 & 78.47648 & 353 & 84.68644 & 549 & 15\\
105 & 87.89833 & 254 & 79.65267 & 69 & 25\\
106 & 106.65287 & 463 & 91.04976 & 29 & 24\\
107 & 72.07227 & 266 & 90.89109 & 1702 & 26\\
108 & 220.67900 & 319 & 257.83470 & 2186 & 22\\
109 & 152.65600 & 441 & 251.42361 & 924 & 21\\
110 & 129.93800 & 205 & 180.36685 & 55 & 20\\
111 & 64.77900 & 292 & 146.44842 & 1765 & 15\\
112 & 231.45082 & 393 & 187.31929 & 27 & 11\\
113 & 173.72852 & 237 & 169.26756 & 10 & 11\\
\end{tabular}
A data.frame: 1 × 6
A data.frame: 1 × 5
| <!--/--> | MAP - NFI ~ null: &lt;chr&gt; | Coefficient &lt;dbl&gt; | SE &lt;dbl&gt; | t-value &lt;dbl&gt; | p-value &lt;dbl&gt; | y ~ x: &lt;chr&gt; |
|---|---|---|---|---|---|---|
| 1 | 1 | -7.28 | 3.17 | -2.3 | 1.98 | Intercept |
A data.frame: 1 × 6
\begin{tabular}{r|llllll}
& MAP - NFI \textasciitilde{} null: & Coefficient & SE & t-value & p-value & y \textasciitilde{} x:\\
& <chr> & <dbl> & <dbl> & <dbl> & <dbl> & <chr>\\
| <!--/--> | MAP - NFI ~ null: &lt;chr&gt; | Coefficient &lt;dbl&gt; | SE &lt;dbl&gt; | t-value &lt;dbl&gt; | p-value &lt;dbl&gt; |
|---|---|---|---|---|---|
| 1 | Intercept | -7.28 | 3.17 | -2.3 | 1.98 |
A data.frame: 1 × 5
\begin{tabular}{r|lllll}
& MAP - NFI \textasciitilde{} null: & Coefficient & SE & t-value & p-value\\
& <chr> & <dbl> & <dbl> & <dbl> & <dbl>\\
\hline
1 & 1 & -7.28 & 3.17 & -2.3 & 1.98 & Intercept\\
1 & Intercept & -7.28 & 3.17 & -2.3 & 1.98\\
\end{tabular}
A data.frame: 3 × 5
| <!--/--> | MAP - NFI ~ Slope: &lt;chr&gt; | Coefficient &lt;dbl&gt; | SE &lt;chr&gt; | t-value &lt;chr&gt; | p-value &lt;chr&gt; |
|---|---|---|---|---|---|
| 1 | <!----> | -55.91 | 7.45 | -7.5 | 2 |
| 2 | x | 3.02 | 0.43 | 6.96 | 0 |
| 1 | Intercept | -55.91 | 7.45 | -7.5 | 2 |
| 2 | Slope | 3.02 | 0.43 | 6.96 | 0 |
| 3 | Fay-Herriot R-squared = | 0.62 | <!----> | <!----> | <!----> |
A data.frame: 3 × 5
\begin{tabular}{r|lllll}
& MAP - NFI \textasciitilde{} Slope: & Coefficient & SE & t-value & p-value\\
& <chr> & <dbl> & <chr> & <chr> & <chr>\\
\hline
1 & & -55.91 & 7.45 & -7.5 & 2\\
2 & x & 3.02 & 0.43 & 6.96 & 0\\
1 & Intercept & -55.91 & 7.45 & -7.5 & 2\\
2 & Slope & 3.02 & 0.43 & 6.96 & 0\\
3 & Fay-Herriot R-squared = & 0.62 & & & \\
\end{tabular}
%% Cell type:code id:6257d66f-bc09-4b04-ae4a-6477dcca9afb tags:
``` R
```
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment