context("CSTools::CST_MultiEOF tests")


##############################################

# exp1, exp2, exp03
seq <- 1 : (2 * 3 * 4 * 5 * 6 * 8)
seq3 <- 1 : (2 * 3 * 4 * 4 * 6 * 8)
mod1 <- sin( 0.7 + seq )^2 + cos( seq ^ 2 * 1.22  )
dim(mod1) <- c(dataset = 2, member = 3, sdate = 4, ftime = 5, lat = 6, lon = 8)
mod2 <- sin( seq * 2 ) ^ 3 + cos( seq ^ 2 )
dim(mod2) <- c(dataset = 2, member = 3, sdate = 4, ftime = 5, lat = 6, lon = 8)
mod3 <- cos( 0.5 + seq3 ) + sin ( seq3 ^ 2 * 0.2 )
dim(mod3) <- c(dataset = 2, member = 3, sdate = 4, ftime = 4, lat = 6, lon = 8)
lon <- seq(0, 35, 5)
lat <- seq(0, 25, 5)
exp1 <- list(data = mod1, coords = list(lat = lat, lon = lon))
exp2 <- list(data = mod2, coords = list(lat = lat, lon = lon))
exp03 <- list(data = mod3, coords = list(lat = lat, lon = lon))
attr(exp1, 'class') <- 's2dv_cube'
attr(exp2, 'class') <- 's2dv_cube'
attr(exp03, 'class') <- 's2dv_cube'
d = as.POSIXct(c("2017/01/01", "2017/01/02", "2017/01/03", "2017/01/04", "2017/01/05",
                 "2018/01/01", "2018/01/02", "2018/01/03", "2018/01/04", "2018/01/05",
                 "2019/01/01", "2019/01/02", "2019/01/03", "2019/01/04", "2019/01/05",
                 "2020/01/01", "2020/01/02", "2020/01/03", "2020/01/04", "2020/01/05"))
            
exp1$attrs$Dates = d
exp2$attrs$Dates = d
exp03$attrs$Dates = d

# dat3
exp3 <- exp03
mod3 <- cos( 0.5 + seq ) + sin( seq ^ 2  * 0.2 )
dim(mod3) <- c(dataset = 2, member = 3, sdate = 4, ftime = 5, lat = 6, lon = 8)
exp3$data <- mod3

# dat0
dat0 <- exp1
dat01 <- exp2
dat0$coords <- NULL
dat01$coords <- NULL
dat02 <- dat0
dat03 <- dat01
dat02$coords <- list(long = seq(1:4), lati = seq(1:4))
dat03$coords <- list(long = seq(1:4), lati = seq(1:4))

##############################################
test_that("1. Input checks", {
  expect_error(
    CST_MultiEOF(datalist = 1),
    paste0("Elements of the list in parameter 'datalist' must be of the class ",
           "'s2dv_cube', as output by CSTools::CST_Load.")
  )
  # Check if all dims equal
  expect_error(
    CST_MultiEOF(list(exp1, exp03)),
    "Input data fields must all have the same dimensions."
  )
  # Know spatial coordinates names
  expect_error(
    CST_MultiEOF(list(dat0, dat01)),
    paste0("Parameter 'datalist' must have 'data', 'coords' and 'attrs' elements ",
         "within the 's2dv_cube' structure.")
  )
  expect_error(
    CST_MultiEOF(list(dat02, dat03)),
    paste0("Spatial coordinate names do not match any of the names accepted by ",
           "the package. Latitudes accepted names: 'lat', 'lats', 'latitude',", 
           " 'y', 'j', 'nav_lat'. Longitudes accepted names: 'lon', 'lons',", 
           " 'longitude', 'x', 'i', 'nav_lon'.")
  )
  expect_error(
    MultiEOF(data = array(rnorm(96), dim = c(var = 2, lonss = 8, latss = 6)), 
             lon = seq(1:7), lat = seq(1:5), lon_dim = 'lonss', lat_dim = 'latss'),
    paste0("Spatial coordinate names do not match any of the names accepted by ",
           "the package.")
  )
  expect_error(
    CST_MultiEOF(list(exp1, exp2, exp3), lon_lim = c(-250, -245), lat_lim = c(10, 25)),
    "No intersection between longitude bounds and data domain.")
})  

##############################################

test_that("2. Output checks", {
  cal <- CST_MultiEOF(datalist = list(exp1, exp2, exp3), neof_composed=2)
  expect_equal(
    length(cal), 
    5
  )
  dimexp = dim(exp1$data)
  expect_equal(
    dim(cal$coeff), 
    c(dimexp["ftime"], dimexp["sdate"], eof=2, dimexp["dataset"], dimexp["member"])
  )
  expect_equal(
    dim(cal$variance), 
    c(eof = 2, dimexp["dataset"], dimexp["member"])
  )
  expect_equal(
    dim(cal$eof_pattern), 
    c(var = 3, dimexp["lon"],  dimexp["lat"], eof = 2, 
      dimexp["dataset"], dimexp["member"])
  )
  expect_equal(
    cal$variance[1, 1, 1], 
    0.2909419, 
    tolerance = .00001
  )
  expect_equal(
    cal$coeff[2, 1, 1, 1, 1], 
    0.5414261, 
    tolerance = .00001
  )
  expect_equal(
    cal$eof_pattern[1, 2, 2, 2, 1, 1], 
    0.3932484, 
    tolerance = .00001
  )
  cal <- CST_MultiEOF(list(exp1, exp2, exp3), neof_max = 5, 
                      neof_composed = 2, minvar = 0.2)
  expect_equal(
    cal$coeff[2, 1, 1, 1, 1], 
    -0.6117927, 
    tolerance = .00001
  )
  cal <- CST_MultiEOF(list(exp1, exp2, exp3), lon_lim = c(5, 30), lat_lim = c(10, 25))
  expect_equal(
    cal$coeff[2, 1, 1, 1, 1], 
    0.8539488, 
    tolerance = .00001
  )
  expect_equivalent(
    cal$lon, 
    seq(5, 30, 5)
  )
  expect_equivalent(
    cal$lat, 
    seq(10, 25, 5)
  )
  cal <- CST_MultiEOF(list(exp1, exp2, exp3), lon_lim = c(350, 15), lat_lim = c(10, 25))
  expect_equivalent(
    cal$lon, seq(0, 15, 5)
  )
  expect_equivalent(
    cal$lat, 
    seq(10, 25, 5)
  )
  cal <- CST_MultiEOF(list(exp1, exp2, exp3), lon_lim = c(-355, -345))
  expect_equivalent(
    cal$lon, 
    seq(5, 15, 5)
  )
  exp3$data[1, 1, 1, 1, 1, 1] = NaN
  expect_error(
    CST_MultiEOF(list(exp1, exp3), neof_max = 8, neof_composed=2),
    "Input data contain NA values." 
  )
})  
