#Creates three sample arrays with the expected dimensions,
#and runs the function by sending the three arrays as parameters

#function with dim names
dat1 <- 1 : 100
dim(dat1) <- c(time = 10, lat = 5, lon = 2)

dat2 <- rep(1:5, 2)
dim(dat2) <- c(lat = 5, lon = 2)

dat3 <- rep(1:5, each = 10)
dim(dat3) <- c(time = 10, lat = 5)

weighted <- c(1, 0.8, 0.6, 0.4, 0.2)

asd <- Apply(data = list(dat1, dat2, dat3),
             target_dims = list(c('time','lat','lon'), c('lat', 'lon'), c('time', 'lat')),
             fun = func_apply)$output1

#try function without dim names
dat1 <- 1 : 100
dim(dat1) <- c(10, 5, 2)

dat2 <- rep(1:5, 2)
dim(dat2) <- c(5, 2)

dat3 <- rep(1:5, each = 10)
dim(dat3) <- c(10, 5)

weighted <- c(1, 0.8, 0.6, 0.4, 0.2)

asd <- Apply(data = list(dat1, dat2, dat3),
             target_dims = list(c(1, 2, 3), c(1, 2), c(1, 2)),
             fun = func_apply2)$output1
#----------

# Creates one array with dimensions 'member', 'sdate', 'time', 'lat', 'lon', 'depth' with random values (no matter the length of the dimensions)
# Creates one array with dimensions 'lat' and 'lon' with random values (same length as in the first array)
# Creates one array with dimensions 'member', 'time', 'lat', 'lon', 'depth' with random values (same length as in the first array)
# Applies the function to the first array using multiApply, in a way that the function is applied to each possible combination of sub arrays of dimensions ('time', 'lat', 'lon'), ('lat', 'lon') and ('time', 'lat'), resulting in a array of dimensions 'member', 'sdate', 'time' 

dat1 <- 1 : (2 * 3 * 10 * 2 * 2 * 2)
dim(dat1) <- c(member = 2, sdate = 3, time = 10, lat = 2, lon = 2, depth = 2)
dat2 <- c(1:4)
dim(dat2) <- c(lat = 2, lon = 2)
dat3 <- 1: (2 * 10 * 2 * 2 * 2)
dim(dat3) <- c(member = 2, time = 10, lat = 2, lon = 2, depth = 2)

D1 <- Apply(data = list(dat1, dat2, dat3), 
           margins = list(c('member', 'sdate', 'depth'),c(),c('member', 'lon', 'depth')),
           fun = func_apply)$output1

D2 <- Apply(data = list(dat1, dat2, dat3),
           target_dims = list(c('time', 'lat', 'lon'), c('lat', 'lon'), c('time', 'lat')), 
           fun = func_apply)$output1

D21 <- Apply(data = list(dat1, dat2, dat3),
           target_dims = list(c('time', 'lat', 'lon'), c('lat', 'lon'), c('time', 'lat')), 
           output_dims = c('time'),
           fun = func_apply)$output1


# Creates one array with dimensions 'time', 'lat', 'lon' with random values, where each 'lat', 'lon' sub-array along the 'time' dimension has an exact copy of the 'lat', 'lon' array generated before (same length as in the first array)
# Applies the function to the arrays, replacing the second array by the new array you have just generated
# Is there any difference in the result of this Apply call with respect to the previous one? why?
dat4 <- array(dat2, dim = c(dim(dat2), time = 10))

E1 <- Apply(data = list(dat1, dat4, dat3),
            margins = list(c('member', 'sdate', 'depth'),c('time'),c('member', 'lon', 'depth')),
            fun = func_apply)$output1

E2 <- Apply(data = list(dat1, dat4, dat3),
            target_dims = list(c('time', 'lat', 'lon'), c('lat', 'lon'), c('time', 'lat')),  
            fun = func_apply)$output1
#Ans: one additional 'time=10' dimension. Each sub-array along 'time' is identical, and also identical to D2.

# Creates on array with dimensions 'time', 'lat', 'lon' with random values, where each 'lat', 'lon' sub-array along the 'time' dimension has different values (same length as in the first array)
# Applies the function to the arrays, replacing the second array by the new array you have just generated
# Is there any difference in the result of this Apply call with respect to the previous one? why?
dat5 <- c(dat2, abs(rnorm(4 * 9, 1, 2)))
dim(dat5) <- c(lat = 2, lon = 2, time = 10)

F2 <- Apply(data = list(dat1, dat5, dat3),
            target_dims = list(c('time', 'lat', 'lon'), c('lat', 'lon'), c('time', 'lat')),
            fun = func_apply)$output1
           

# Applies the function to the original arrays, sending the parameter 'revert_order = TRUE' to the atomic function, and the parameter 'na.rm = TRUE' to the mean() function inside the atomic function
G2 <- Apply(data = list(dat1, dat2, dat3),
           target_dims = list(c('time', 'lat', 'lon'), c('lat', 'lon'), c('time', 'lat')),
           fun = func_apply, revert_order = TRUE, na.rm = TRUE)$output1

# Change the order of the dimensions of the created arrays with aperm(), preserving the original arrays
# Change the order of the dimensions of the created arrays with .aperm2(), preserving the original arrays
# What is the difference between these?
# Apply the function to the arrays returned by .aperm2. Did it work? Is the result identical?

dat1_v2 <- aperm(dat1, c(6,5,4,3,2,1)) 
dat1_v3 <- s2dverification:::.aperm2(dat1, c(6,5,4,3,2,1))
#Ans: aperm() does not return the names of dimension. .aperm2() does.

H2 <- Apply(data = list(dat1_v3, dat1_v3, dat1_v3),
           target_dims = list(c('time', 'lat', 'lon'), c('lat', 'lon'), c('time', 'lat')),
           fun = func_apply)$output1
#Ans: The results are the same (reorder of the dimension required).


# Compare the wall clock time spent in the apply before reordering the arrays and the time spent in the apply after reordering the arrays
D2 <- Apply(data = list(dat1, dat1, dat1),
           target_dims = list(c('time', 'lat', 'lon'), c('lat', 'lon'), c('time', 'lat')),
           fun = func_apply)$output1
start_time <- Sys.time()
end_time <- Sys.time()
time_origin <- end_time - start_time
message('The consuming time of original arrays: ', time_origin)

H2 <- Apply(data = list(dat1_v3, dat1_v3, dat1_v3),
           target_dims = list(c('time', 'lat', 'lon'), c('lat', 'lon'), c('time', 'lat')),
           fun = func_apply)$output1
start_time <- Sys.time()
end_time <- Sys.time()
time_reorder <- end_time - start_time
message('The consuming time of reordering arrays: ', time_reorder)

# Compare the peak RAM memory consumption of both executions using the peakRAM package in the R v3.3 UNIX module (module load R/3.3.....)
peakRAM(Apply(data = list(dat1, dat1, dat1),
           target_dims = list(c('time', 'lat', 'lon'), c('lat', 'lon'), c('time', 'lat')),
           fun = func_apply)$output1
       )

peakRAM(Apply(data = list(dat1_v3, dat1_v3, dat1_v3),
           target_dims = list(c('time', 'lat', 'lon'), c('lat', 'lon'), c('time', 'lat')),
           fun = func_apply)$output1
       )

# Remove the dimension names of the three arrays and manage to apply the function with multiApply using numeric indices.
dat1_nodim <- 1 : (2 * 3 * 10 * 2 * 2 * 2)
dim(dat1_nodim) <- c(2, 3, 10, 2, 2, 2)
dat2_nodim <- c(1:4)
dim(dat2_nodim) <- c(2, 2)
dat3_nodim <- 1: (2 * 10 * 2 * 2 * 2)
dim(dat3_nodim) <- c(2, 10, 2, 2, 2)

I2 <- Apply(data = list(dat1_nodim, dat2_nodim, dat3_nodim),
           target_dims = list(c(3, 4, 5), c(1, 2), c(2, 3)),
           fun = func_apply2)$output1


I3 <- Apply(data = list(dat1, dat1, dat1),
           target_dims = list(c(3, 4, 5), c(4, 5), c(3, 4)),
           fun = func_apply2)$output1

