context("Transform: check with cdo")
# This unit test checks different border situations: normal regional that doesn't touch the borders,
# global situation that uses all the grids, or one side reaches the border.

# Compare the results with cdo. The example script is as below:
#library(easyNCDF)
#path <- "/esarchive/exp/ecmwf/system5_m1/monthly_mean/tas_f6h/tas_20000101.nc"
#file <- NcOpen(path)
#arr <- NcToArray(file,
#                 dim_indices = list(time = 1, ensemble = 1,
#                                    latitude = 1:640, longitude = 1:1296),
#                 vars_to_read = 'tas')
#lats <- NcToArray(file,
#                  dim_indices = list(latitude = 1:640), vars_to_read = 'latitude')
#lons <- NcToArray(file,
#                  dim_indices = list(longitude = 1:1296), vars_to_read = 'longitude')
#NcClose(file)
#
#dim(arr)
#dim(lats)
#arr2 <- s2dv::CDORemap(arr, lons = as.vector(lons), lats = as.vector(lats),
#                       grid = 'r100x50', method = 'con', crop = c(10,20,20,40))
#dim(arr2$data_array)

# The result of cdo is from CDO version 1.9.8.

test_that("1. normal regional situation", {

lons.min <- 10
lons.max <- 20
lats.min <- 20
lats.max <- 40

suppressWarnings(
exp <- Start(dat = '/esarchive/exp/ecmwf/system5_m1/monthly_mean/$var$_f6h/$var$_$sdate$.nc',
             var = 'tas',
             sdate = '20000101',
             ensemble = indices(1),
             time = indices(1),
             latitude = values(list(lats.min, lats.max)),
             latitude_reorder = Sort(),
             longitude = values(list(lons.min, lons.max)),
             longitude_reorder = CircularSort(0, 360),
             transform = CDORemapper,
             transform_params = list(grid = 'r100x50',
                                     method = 'con',
                                     crop = c(lons.min, lons.max, lats.min, lats.max)),
             transform_vars = c('latitude', 'longitude'),
             transform_extra_cells = 8,
             synonims = list(latitude = c('lat', 'latitude'),
                             longitude = c('longitude', 'lon')),
             return_vars = list(latitude = NULL, 
                                longitude = NULL,
                                time = 'sdate'),
             retrieve = T)
)
expect_equal(
dim(drop(exp)),
c(latitude = 5, longitude = 3)
)
expect_equal(
drop(exp)[, 1],
c(284.9907, 282.9883, 281.2574, 284.1387, 285.6547),
tolerance = 0.0001
)
expect_equal(
drop(exp)[, 2],
c(285.4820, 282.9362, 282.6088, 287.3716, 285.0194),
tolerance = 0.0001
)
expect_equal(
drop(exp)[, 3],
c(286.1208, 284.3523, 285.9198, 287.7389, 286.1099),
tolerance = 0.0001
) 

})

# The result is consistent with cdo result, using all the grid points to transform
# and crop the region.
# drop(exp)[, ]
#         [,1]     [,2]     [,3]
#[1,] 284.9907 285.4820 286.1208
#[2,] 282.9883 282.9362 284.3523
#[3,] 281.2574 282.6088 285.9198
#[4,] 284.1387 287.3716 287.7389
#[5,] 285.6547 285.0194 286.1099

#------------------------------------------------

test_that("2. global situation", {

lons.min <- 0
lons.max <- 359.9
lats.min <- 20
lats.max <- 40

suppressWarnings(
exp <- Start(dat = '/esarchive/exp/ecmwf/system5_m1/monthly_mean/$var$_f6h/$var$_$sdate$.nc',
             var = 'tas',
             sdate = '20000101',
             ensemble = indices(1),
             time = indices(1),
             latitude = values(list(lats.min, lats.max)),
             latitude_reorder = Sort(),
             longitude = values(list(lons.min, lons.max)),
             longitude_reorder = CircularSort(0, 360),
             transform = CDORemapper,
             transform_params = list(grid = 'r100x50',
                                     method = 'con',
                                     crop = c(lons.min, lons.max, lats.min, lats.max)),
             transform_vars = c('latitude', 'longitude'),
             transform_extra_cells = 8,
             synonims = list(latitude = c('lat', 'latitude'),
                             longitude = c('longitude', 'lon')),
             return_vars = list(latitude = NULL, 
                                longitude = NULL,
                                time = 'sdate'),
             retrieve = T)
)
expect_equal(
dim(drop(exp)),
c(latitude = 5, longitude = 100)
)
expect_equal(
drop(exp)[, 1],
c(286.4231, 283.8847, 280.4234, 277.7688, 284.3575),
tolerance = 0.0001
)
expect_equal(
drop(exp)[, 2],
c(288.0916, 283.9386, 280.9974, 278.4432, 284.8728),
tolerance = 0.0001
)
expect_equal(
drop(exp)[, 100],
c(285.9373, 283.6340, 280.6685, 279.6016, 279.5081),
tolerance = 0.0001
)
expect_equal(
drop(exp)[, 99],
c(286.3033, 283.8651, 279.9846, 285.0679, 282.6013),
tolerance = 0.0001
)

})

#> drop(arr2$data_array)[,1:3]
#         [,1]     [,2]     [,3]
#[1,] 286.4231 288.0916 285.7435
#[2,] 283.8847 283.9386 283.1867
#[3,] 280.4234 280.9974 281.7465
#[4,] 277.7688 278.4432 280.2615
#[5,] 284.3575 284.8728 284.6408
#> drop(arr2$data_array)[,98:100]
#         [,1]     [,2]     [,3]
#[1,] 286.4648 286.3033 285.9373
#[2,] 285.5226 283.8651 283.6340
#[3,] 287.8567 279.9846 280.6685
#[4,] 288.6723 285.0679 279.6016
#[5,] 286.8253 282.6013 279.5081

#-----------------------------------------------

test_that("3. left side too close to border", {

lons.min <- 0
lons.max <- 20
lats.min <- 20
lats.max <- 40

suppressWarnings(
exp <- Start(dat = '/esarchive/exp/ecmwf/system5_m1/monthly_mean/$var$_f6h/$var$_$sdate$.nc',
             var = 'tas',
             sdate = '20000101',
             ensemble = indices(1),
             time = indices(1),
             latitude = values(list(lats.min, lats.max)),
             latitude_reorder = Sort(),
             longitude = values(list(lons.min, lons.max)),
             longitude_reorder = CircularSort(0, 360),
             transform = CDORemapper,
             transform_params = list(grid = 'r100x50',
                                     method = 'con',
                                     crop = c(lons.min, lons.max, lats.min, lats.max)),
             transform_vars = c('latitude', 'longitude'),
             transform_extra_cells = 8,
             synonims = list(latitude = c('lat', 'latitude'),
                             longitude = c('longitude', 'lon')),
             return_vars = list(latitude = NULL, 
                                longitude = NULL,
                                time = 'sdate'),
             retrieve = T)
)
expect_equal(
dim(drop(exp)),
c(latitude = 5, longitude = 6)
)
expect_equal(
drop(exp)[, 1],
c(286.4231, 283.8847, 280.4234, 277.7688, 284.3575),
tolerance = 0.0001
)
expect_equal(
drop(exp)[, 2],
c(288.0916, 283.9386, 280.9974, 278.4432, 284.8728),
tolerance = 0.0001
)
expect_equal(
drop(exp)[, 3],
c(285.7436, 283.1867, 281.7465, 280.2615, 284.6408),
tolerance = 0.0001
)
expect_equal(
drop(exp)[, 4],
c(284.9907, 282.9883, 281.2574, 284.1387, 285.6547),
tolerance = 0.0001
)
expect_equal(
drop(exp)[, 5],
c(285.4820, 282.9362, 282.6088, 287.3716, 285.0194),
tolerance = 0.0001
)
expect_equal(
drop(exp)[, 6],
c(286.1208, 284.3523, 285.9198, 287.7389, 286.1099),
tolerance = 0.0001
) 

})


#drop(arr2$data_array)[,]
#         [,1]     [,2]     [,3]     [,4]     [,5]     [,6]
#[1,] 286.4231 288.0916 285.7435 284.9907 285.4820 286.1208
#[2,] 283.8847 283.9386 283.1867 282.9882 282.9362 284.3523
#[3,] 280.4234 280.9974 281.7465 281.2574 282.6088 285.9198
#[4,] 277.7688 278.4432 280.2615 284.1387 287.3716 287.7389
#[5,] 284.3575 284.8728 284.6408 285.6547 285.0194 286.1099



test_that("4. right side too close to border", {

lons.min <- 350
lons.max <- 359
lats.min <- 20
lats.max <- 40

suppressWarnings(
exp <- Start(dat = '/esarchive/exp/ecmwf/system5_m1/monthly_mean/$var$_f6h/$var$_$sdate$.nc',
             var = 'tas',
             sdate = '20000101',
             ensemble = indices(1),
             time = indices(1),
             latitude = values(list(lats.min, lats.max)),
             latitude_reorder = Sort(),
             longitude = values(list(lons.min, lons.max)),
             longitude_reorder = CircularSort(0, 360),
             transform = CDORemapper,
             transform_params = list(grid = 'r100x50',
                                     method = 'con',
                                     crop = c(lons.min, lons.max, lats.min, lats.max)),
             transform_vars = c('latitude', 'longitude'),
             transform_extra_cells = 8,
             synonims = list(latitude = c('lat', 'latitude'),
                             longitude = c('longitude', 'lon')),
             return_vars = list(latitude = NULL, 
                                longitude = NULL,
                                time = 'sdate'),
             retrieve = T)
)
expect_equal(
dim(drop(exp)),
c(latitude = 5, longitude = 2)
)
expect_equal(
drop(exp)[, 1],
c(286.3033, 283.8651, 279.9846, 285.0679, 282.6013),
tolerance = 0.0001
)
expect_equal(
drop(exp)[, 2],
c(285.9373, 283.6340, 280.6685, 279.6016, 279.5081),
tolerance = 0.0001
)

})

#> drop(arr2$data_array)[,]
#         [,1]     [,2]
#[1,] 286.3033 285.9373
#[2,] 283.8651 283.6340
#[3,] 279.9846 280.6685
#[4,] 285.0679 279.6016
#[5,] 282.6013 279.5081

#--------------------------------------------------

test_that("5. across meridian", {

lons.min <- 170
lons.max <- 190
lats.min <- 20
lats.max <- 40

suppressWarnings(
exp <- Start(dat = '/esarchive/exp/ecmwf/system5_m1/monthly_mean/$var$_f6h/$var$_$sdate$.nc',
             var = 'tas',
             sdate = '20000101',
             ensemble = indices(1),
             time = indices(1),
             latitude = values(list(lats.min, lats.max)),
             latitude_reorder = Sort(),
             longitude = values(list(lons.min, lons.max)),
             longitude_reorder = CircularSort(-180, 180),
             transform = CDORemapper,
             transform_params = list(grid = 'r100x50',
                                     method = 'con',
                                     crop = c(lons.min, lons.max, lats.min, lats.max)),
             transform_vars = c('latitude', 'longitude'),
             transform_extra_cells = 8,
             synonims = list(latitude = c('lat', 'latitude'),
                             longitude = c('longitude', 'lon')),
             return_vars = list(latitude = NULL,
                                longitude = NULL,
                                time = 'sdate'),
             retrieve = T)
)
expect_equal(
dim(drop(exp)),
c(latitude = 5, longitude = 5)
)
expect_equal(
drop(exp)[, 1],
c(295.9371, 294.0865, 291.8104, 289.0014, 284.9630),
tolerance = 0.0001
)
expect_equal(
drop(exp)[, 2],
c(296.2407, 294.4130, 291.8895, 289.5334, 285.7766),
tolerance = 0.0001
)
expect_equal(
drop(exp)[, 3],
c(296.2065, 294.4305, 291.9352, 289.5931, 286.0924),
tolerance = 0.0001
)
expect_equal(
drop(exp)[, 4],
c(295.7689, 293.6672, 291.2874, 288.4160, 284.6429),
tolerance = 0.0001
)
expect_equal(
drop(exp)[, 5],
c(295.8033, 293.8032, 291.5909, 288.5543, 284.6293),
tolerance = 0.0001
)

})

# cdo result is [170:190]; Start() is [-180:-170; 170:180].
# So drop(exp)[, 1:3] == drop(arr2$data_array)[, 3:5].
#drop(arr2$data_array)[,]
#         [,1]     [,2]     [,3]     [,4]     [,5]
#[1,] 295.7689 295.8034 295.9371 296.2407 296.2065
#[2,] 293.6672 293.8032 294.0865 294.4130 294.4306
#[3,] 291.2874 291.5910 291.8104 291.8895 291.9352
#[4,] 288.4159 288.5543 289.0014 289.5334 289.5931
#[5,] 284.6429 284.6293 284.9630 285.7766 286.0924


test_that("6. normal case; [-180, 180]", {
# The lon range is too close to border for the original longitude [0, 360], but 
# is normal case for [-180, 180]. In zzz.R, it is counted as normal case, and the
# result is the same as 3.
lons.min <- 0
lons.max <- 20
lats.min <- 20
lats.max <- 40

suppressWarnings(
exp <- Start(dat = '/esarchive/exp/ecmwf/system5_m1/monthly_mean/$var$_f6h/$var$_$sdate$.nc',
             var = 'tas',
             sdate = '20000101',
             ensemble = indices(1),
             time = indices(1),
             latitude = values(list(lats.min, lats.max)),
             latitude_reorder = Sort(),
             longitude = values(list(lons.min, lons.max)),
             longitude_reorder = CircularSort(-180, 180),
             transform = CDORemapper,
             transform_params = list(grid = 'r100x50',
                                     method = 'con',
                                     crop = c(lons.min, lons.max, lats.min, lats.max)),
             transform_vars = c('latitude', 'longitude'),
             transform_extra_cells = 8,
             synonims = list(latitude = c('lat', 'latitude'),
                             longitude = c('longitude', 'lon')),
             return_vars = list(latitude = NULL,
                                longitude = NULL,
                                time = 'sdate'),
             retrieve = T)
)
expect_equal(
dim(drop(exp)),
c(latitude = 5, longitude = 6)
)
expect_equal(
drop(exp)[, 1],
c(286.4231, 283.8847, 280.4234, 277.7688, 284.3575),
tolerance = 0.0001
)
expect_equal(
drop(exp)[, 2],
c(288.0916, 283.9386, 280.9974, 278.4432, 284.8728),
tolerance = 0.0001
)
expect_equal(
drop(exp)[, 3],
c(285.7436, 283.1867, 281.7465, 280.2615, 284.6408),
tolerance = 0.0001
)
expect_equal(
drop(exp)[, 4],
c(284.9907, 282.9883, 281.2574, 284.1387, 285.6547),
tolerance = 0.0001
)
expect_equal(
drop(exp)[, 5],
c(285.4820, 282.9362, 282.6088, 287.3716, 285.0194),
tolerance = 0.0001
)
expect_equal(
drop(exp)[, 6],
c(286.1208, 284.3523, 285.9198, 287.7389, 286.1099),
tolerance = 0.0001
)

})

#----------------------------------------------------------

test_that("6. left side too close to border; [-180, 180]", {
# The lon range is too close to border for the original longitude [0, 360], but 
# is normal case for [-180, 180]. In zzz.R, it is counted as normal case, and the
# result is the same as 3.
lons.min <- -179
lons.max <- -170
lats.min <- 20
lats.max <- 40

suppressWarnings(
exp <- Start(dat = '/esarchive/exp/ecmwf/system5_m1/monthly_mean/$var$_f6h/$var$_$sdate$.nc',
             var = 'tas',
             sdate = '20000101',
             ensemble = indices(1),
             time = indices(1),
             latitude = values(list(lats.min, lats.max)),
             latitude_reorder = Sort(),
             longitude = values(list(lons.min, lons.max)),
             longitude_reorder = CircularSort(-180, 180),
             transform = CDORemapper,
             transform_params = list(grid = 'r100x50',
                                     method = 'con',
                                     crop = c(lons.min, lons.max, lats.min, lats.max)),
             transform_vars = c('latitude', 'longitude'),
             transform_extra_cells = 8,
             synonims = list(latitude = c('lat', 'latitude'),
                             longitude = c('longitude', 'lon')),
             return_vars = list(latitude = NULL,
                                longitude = NULL,
                                time = 'sdate'),
             retrieve = T)
)
expect_equal(
dim(drop(exp)),
c(latitude = 5, longitude = 2)
)
expect_equal(
drop(exp)[, 1],
c(296.2407, 294.4130, 291.8895, 289.5334, 285.7766),
tolerance = 0.0001
)
expect_equal(
drop(exp)[, 2],
c(296.2065, 294.4305, 291.9352, 289.5931, 286.0924),
tolerance = 0.0001
)

})

# cdo result is [181:190]
#> drop(arr2$data_array)[,]
#         [,1]     [,2]
#[1,] 296.2407 296.2065
#[2,] 294.4130 294.4306
#[3,] 291.8895 291.9352
#[4,] 289.5334 289.5931
#[5,] 285.7766 286.0924

