Commits (152)
.*\.git$ .*\.git$
.*\.gitignore$ .*\.gitignore$
.*\.gitlab$
.*\.tar.gz$ .*\.tar.gz$
.*\.pdf$ .*\.pdf$
./.nc$ ./.nc$
.*^(?!data)\.RData$ .*^(?!data)\.RData$
.*\.gitlab-ci.yml$ .*\.gitlab-ci.yml$
.lintr
^tests$ ^tests$
#^inst/doc$ #^inst/doc$
^inst/doc/UseCase2_PrecipitationDownscaling_RainFARM_RF100\.R$ ^inst/doc/usecase/UseCase2_PrecipitationDownscaling_RainFARM_RF100\.R$
^inst/doc/UseCase1_WindEvent_March2018\.R$ ^inst/doc/usecase/UseCase1_WindEvent_March2018\.R$
^inst/doc/UseCase2_PrecipitationDownscaling_RainFARM_RF4\.R$ ^inst/doc/usecase/UseCase2_PrecipitationDownscaling_RainFARM_RF4\.R$
^inst/doc/UseCase3_data_preparation_SCHEME_model\.R$ ^inst/doc/usecase/UseCase3_data_preparation_SCHEME_model\.R$
^inst/doc/launch_UseCase2_PrecipitationDownscaling_RF4\.sh$ ^inst/doc/usecase/launch_UseCase2_PrecipitationDownscaling_RF4\.sh$
...@@ -9,3 +9,10 @@ build: ...@@ -9,3 +9,10 @@ build:
- R CMD build --resave-data . - R CMD build --resave-data .
- R CMD check --as-cran --no-manual --run-donttest CSTools_*.tar.gz - R CMD check --as-cran --no-manual --run-donttest CSTools_*.tar.gz
- R -e 'covr::package_coverage()' - R -e 'covr::package_coverage()'
lint-check:
stage: build
script:
- module load R/4.1.2-foss-2015a-bare
- echo "Run lintr on the package..."
- Rscript -e 'lintr::lint_package(path = ".")'
linters: linters_with_tags( # lintr_3.1.1
tags = c("package_development", "readability", "best_practices"),
line_length_linter = line_length_linter(100L),
T_and_F_symbol_linter = NULL,
quotes_linter = NULL,
commented_code_linter = NULL,
implicit_integer_linter = NULL,
vector_logic_linter = NULL,
extraction_operator_linter = NULL,
function_left_parentheses_linter = NULL,
semicolon_linter = NULL,
indentation_linter = NULL,
unnecessary_nested_if_linter = NULL,
if_not_else_linter = NULL,
object_length_linter = NULL,
infix_spaces_linter(exclude_operators = "~")
)
exclusions: list(
"inst",
"R/AnalogsPred_train.R",
"R/BEI_PDFBest.R",
"R/BEI_Weights.R",
"R/CST_AdamontAnalog.R",
"R/CST_AdamontQQCorr.R",
"R/Analogs.R",
"R/CST_AnalogsPredictors.R",
"R/CST_BEI_Weighting.R",
"R/CST_CategoricalEnsCombination.R",
"R/CST_DynBiasCorrection.R",
"R/CST_EnsClustering.R",
"R/PlotCombinedMap.R",
"R/PlotForecastPDF.R",
"R/PlotMostLikelyQuantileMap.R",
"R/PlotPDFsOLE.R",
"R/PlotTriangles4Categories.R",
"R/PlotWeeklyClim.R",
"tests/testthat/",
"tests/testthat.R"
)
Package: CSTools Package: CSTools
Title: Assessing Skill of Climate Forecasts on Seasonal-to-Decadal Timescales Title: Assessing Skill of Climate Forecasts on Seasonal-to-Decadal Timescales
Version: 5.0.1 Version: 5.2.0
Authors@R: c( Authors@R: c(
person("Nuria", "Perez-Zanon", , "nuria.perez@bsc.es", role = "aut", comment = c(ORCID = "0000-0001-8568-3071")), person("Nuria", "Perez-Zanon", , "nuria.perez@bsc.es", role = "aut", comment = c(ORCID = "0000-0001-8568-3071")),
person("Louis-Philippe", "Caron", , "louis-philippe.caron@bsc.es", role = "aut", comment = c(ORCID = "0000-0001-5221-0147")), person("Louis-Philippe", "Caron", , "louis-philippe.caron@bsc.es", role = "aut", comment = c(ORCID = "0000-0001-5221-0147")),
...@@ -62,6 +62,7 @@ Depends: ...@@ -62,6 +62,7 @@ Depends:
easyVerification easyVerification
Imports: Imports:
s2dv, s2dv,
startR,
rainfarmr, rainfarmr,
multiApply (>= 2.1.1), multiApply (>= 2.1.1),
ClimProjDiags, ClimProjDiags,
...@@ -78,17 +79,17 @@ Imports: ...@@ -78,17 +79,17 @@ Imports:
utils, utils,
verification, verification,
lubridate, lubridate,
scales scales,
easyNCDF
Suggests: Suggests:
zeallot, zeallot,
testthat, testthat,
knitr, knitr,
markdown, markdown,
rmarkdown, rmarkdown
startR
VignetteBuilder: knitr VignetteBuilder: knitr
License: GPL-3 License: GPL-3
Encoding: UTF-8 Encoding: UTF-8
LazyData: true LazyData: true
RoxygenNote: 7.2.0 RoxygenNote: 7.2.3
Config/testthat/edition: 3 Config/testthat/edition: 3
...@@ -19,6 +19,7 @@ export(CST_BEI_Weighting) ...@@ -19,6 +19,7 @@ export(CST_BEI_Weighting)
export(CST_BiasCorrection) export(CST_BiasCorrection)
export(CST_Calibration) export(CST_Calibration)
export(CST_CategoricalEnsCombination) export(CST_CategoricalEnsCombination)
export(CST_ChangeDimNames)
export(CST_DynBiasCorrection) export(CST_DynBiasCorrection)
export(CST_EnsClustering) export(CST_EnsClustering)
export(CST_InsertDim) export(CST_InsertDim)
...@@ -69,6 +70,7 @@ export(s2dv_cube) ...@@ -69,6 +70,7 @@ export(s2dv_cube)
export(training_analogs) export(training_analogs)
import(RColorBrewer) import(RColorBrewer)
import(abind) import(abind)
import(easyNCDF)
import(ggplot2) import(ggplot2)
import(lubridate) import(lubridate)
import(multiApply) import(multiApply)
......
# CSTools 5.2.0 (Release date: 25-01-2024)
### Development
- New function CST_ChangeDimNames
- CST_SplitDim: added dimension names and split also Dates
- CST_SaveExp: save time bounds and global attributes; improved code
### Other
- Updated README
- Added citation file
# CSTools 5.1.1 (Release date: 19-10-2023)
### Fixes
- Added startR namespace in all CST_Start calls of the vignettes and sample data.
# CSTools 5.1.0 (Release date: 17-10-2023)
### Fixes
- Calibration() show warnings in atomic function when multiple cores are used.
- PlotForecastPDF fix background color in different machines.
- Correct CST_Subset indices for metadata.
- CST_Analogs: Add sdate_dim parameter and improve initial checks.
- Remove CST_Anomaly repeated checks in order to accept no member dimensions in obs.
- CST_SaveExp developments: improve warning, save metadata correctly.
- Improve print method in order that time_bounds are correctly displayed.
### Development
- PlotWeeklyClim to allow years outside the reference period.
- PlotWeeklyClim to allow setting y limits.
- New function CST_Start().
- PlotCombinedMap() has upper triangle_end; the color bars can have different breaks.
- New print method.
- CST_MultiEOF development treat spatial NAs.
- Correct PlotCombinedMap error.
- Substitute mentions of CST_Load by CST_Start.
- Modify necessary vignettes to the use of CST_Start.
# CSTools 5.0.1 (Release date: 06-06-2023) # CSTools 5.0.1 (Release date: 06-06-2023)
- Resubmit to CRAN because it was archived due to dependency issue - Resubmit to CRAN because it was archived due to dependency issue
**Fixes** ### Fixes
- Standardize the coordinates of 's2dv_cube' by setting the coordinates to vectors with NULL dimensions - Standardize the coordinates of 's2dv_cube' by setting the coordinates to vectors with NULL dimensions
- Include a check for SaveExp output filenames that only contain date information - Include a check for SaveExp output filenames that only contain date information
- In SaveExp the dates parameter is allowed to have additional time dimensions of length 1 - In SaveExp the dates parameter is allowed to have additional time dimensions of length 1
- Removed dot from the internal function named mergedatasets() used in CST_CategoricalEnsCombination - Removed dot from the internal function named mergedatasets() used in CST_CategoricalEnsCombination
**New Features** ### Development
- New parameter 'startdates' in CST_SaveExp used to manually decide the name of the output files - New parameter 'startdates' in CST_SaveExp used to manually decide the name of the output files
**Other** ### Other
- Switch to testthat version 3 - Switch to testthat version 3
# CSTools 5.0.0 (Release date: 05-04-2023) # CSTools 5.0.0 (Release date: 05-04-2023)
**Fixes**
### Fixes
- Correct vignettes: Analogs, MultiModelSkill and MultivarRMSE - Correct vignettes: Analogs, MultiModelSkill and MultivarRMSE
- Add 'ncores' to s2dv function calls in CST_Anomaly - Add 'ncores' to s2dv function calls in CST_Anomaly
- Reduce computing time of examples and tests and improve documentation - Reduce computing time of examples and tests and improve documentation
**New features** ### Development
- Add dat_dim parameter in CST_BiasCorrection and CST_Calibration - Add dat_dim parameter in CST_BiasCorrection and CST_Calibration
- New plotting function for case studies temporal visualisation: PlotWeeklyClim - New plotting function for case studies temporal visualisation: PlotWeeklyClim
- Deprecate indices in dim_anom parameter of CST_Anomaly - Deprecate indices in dim_anom parameter of CST_Anomaly
...@@ -31,26 +70,28 @@ ...@@ -31,26 +70,28 @@
- New color set in PlotForecastPDF Vitigeoss colors - New color set in PlotForecastPDF Vitigeoss colors
- New function CST_InsertDim - New function CST_InsertDim
**Other** ### Other
- Added contribution from ArticXchange project due to PlotWeeklyClim - Added contribution from ArticXchange project due to PlotWeeklyClim
- Update NEWS.md with the correct format - Update NEWS.md with the correct format
- Change Licence - Change Licence
# CSTools 4.1.1 (Release date: 10-11-2022) # CSTools 4.1.1 (Release date: 10-11-2022)
**Fixes**
### Fixes
- CST_Analogs corrected input of ClimProjDiags::Subset() - CST_Analogs corrected input of ClimProjDiags::Subset()
- PlotCombinedMap corrected use of 'cex_bar_titles' parameter - PlotCombinedMap corrected use of 'cex_bar_titles' parameter
- CST_Anomaly added 'memb_dim', 'dat_dim' and 'ftime_dim' and improved use for 'dim_anom' parameters - CST_Anomaly added 'memb_dim', 'dat_dim' and 'ftime_dim' and improved use for 'dim_anom' parameters
# CSTools 4.1.0 (Release date: 25-10-2022) # CSTools 4.1.0 (Release date: 25-10-2022)
**New features**
### Development
- Dependency on package 's2dverification' is changed to 's2dv' - Dependency on package 's2dverification' is changed to 's2dv'
- CST_BiasCorrection new parameters 'memb_dim', 'sdate_dim', 'ncores' - CST_BiasCorrection new parameters 'memb_dim', 'sdate_dim', 'ncores'
- CST_Calibration is able to calibrate forecast with new parameter 'exp_cor' - CST_Calibration is able to calibrate forecast with new parameter 'exp_cor'
- CST_QuantileMapping uses cross-validation and provides option to remove NAs; new parameters 'memb_dim', 'sdate_dim', 'window_dim' and 'na.rm'; 'sample_dim' and 'sample_length' are removed - CST_QuantileMapping uses cross-validation and provides option to remove NAs; new parameters 'memb_dim', 'sdate_dim', 'window_dim' and 'na.rm'; 'sample_dim' and 'sample_length' are removed
- s2dv_cube() new parameter 'time_dim' - s2dv_cube() new parameter 'time_dim'
**Fixes** ### Fixes
- as.s2dv_cube() detects latitude and longitude structure in startR_array object - as.s2dv_cube() detects latitude and longitude structure in startR_array object
- Data correction: 'lonlat_data' is renamed to 'lonlat_temp'; 'lonlat_prec' is corrected by one-day shift - Data correction: 'lonlat_data' is renamed to 'lonlat_temp'; 'lonlat_prec' is corrected by one-day shift
- Typo and parameter correction in vignette 'MostLikelyTercile_vignette' - Typo and parameter correction in vignette 'MostLikelyTercile_vignette'
...@@ -58,20 +99,22 @@ ...@@ -58,20 +99,22 @@
- PlotMostLikelyQuantileMap() works with s2dv::PlotLayout - PlotMostLikelyQuantileMap() works with s2dv::PlotLayout
# CSTools 4.0.1 (Release date: 05-10-2021) # CSTools 4.0.1 (Release date: 05-10-2021)
**New features**
### Development
- Dynamical Bias Correction method: `CST_ProxiesAttractors` and `CST_DynBiasCorrection` (optionally `Predictability`) - Dynamical Bias Correction method: `CST_ProxiesAttractors` and `CST_DynBiasCorrection` (optionally `Predictability`)
- CST_BiasCorrection and BiasCorrection allows to calibrate a forecast given the calibration in the hindcast by using parameter 'exp_cor' - CST_BiasCorrection and BiasCorrection allows to calibrate a forecast given the calibration in the hindcast by using parameter 'exp_cor'
- Use cases - Use cases
- CST_SaveExp includes parameter extra_string - CST_SaveExp includes parameter extra_string
- PlotCombinedMap includes parameter cex_bar_titles - PlotCombinedMap includes parameter cex_bar_titles
**Fixes** ### Fixes
- Calibration retains correlation absolute value - Calibration retains correlation absolute value
- Calibration fixed when cal.methodi == rpc-based, apply_to == sign, eval.method == 'leave-one-out' and the correlation is not significant - Calibration fixed when cal.methodi == rpc-based, apply_to == sign, eval.method == 'leave-one-out' and the correlation is not significant
- PlotMostLikelyQuantileMap reoder latitudes of an array provided in 'dots' parameter - PlotMostLikelyQuantileMap reoder latitudes of an array provided in 'dots' parameter
# CSTools 4.0.0 (Release date: 23-02-2021) # CSTools 4.0.0 (Release date: 23-02-2021)
**New features**
### Development
- ADAMONT downscaling method: requires CST_AdamontAnalogs and CST_AdamontQQCor functions - ADAMONT downscaling method: requires CST_AdamontAnalogs and CST_AdamontQQCor functions
- Analogs method using Predictors: requires training_analogs and CST_AnalogsPredictors - Analogs method using Predictors: requires training_analogs and CST_AnalogsPredictors
- PlotPDFsOLE includes parameters to modify legend style - PlotPDFsOLE includes parameters to modify legend style
...@@ -88,7 +131,7 @@ ...@@ -88,7 +131,7 @@
- Analogs vignette - Analogs vignette
- Data Storage and retrieval vignette - Data Storage and retrieval vignette
**Fixes** ### Fixes
- PlotForecastPDF correctly displays terciles labels - PlotForecastPDF correctly displays terciles labels
- CST_SaveExp correctly save time units - CST_SaveExp correctly save time units
- CST_SplitDims returns ordered output following ascending order provided in indices when it is numeric - CST_SplitDims returns ordered output following ascending order provided in indices when it is numeric
...@@ -100,7 +143,8 @@ ...@@ -100,7 +143,8 @@
- Decrease package size compresing vignettes figures and removing areave_data sample - Decrease package size compresing vignettes figures and removing areave_data sample
# CSTools 3.1.0 (Release date: 02-07-2020) # CSTools 3.1.0 (Release date: 02-07-2020)
**New features**
### Development
- EnsClustering vignette - EnsClustering vignette
- EnsClustering has a new parameter 'time_dim' - EnsClustering has a new parameter 'time_dim'
- CST_BiasCorrection has na.rm paramter - CST_BiasCorrection has na.rm paramter
...@@ -111,7 +155,7 @@ ...@@ -111,7 +155,7 @@
- CST_RFTemp/RF_Temp functions available for downscaling temperature - CST_RFTemp/RF_Temp functions available for downscaling temperature
- Weather Regimes vignette - Weather Regimes vignette
**Fixes** ### Fixes
- CST_Anomaly handles exp, obs or both - CST_Anomaly handles exp, obs or both
- PlotForecastPDF vignette displays figures correctly - PlotForecastPDF vignette displays figures correctly
- Calibration function is exposed to users - Calibration function is exposed to users
...@@ -123,17 +167,19 @@ ...@@ -123,17 +167,19 @@
- CST_SaveExp uses multiApply and save time dimension correctly - CST_SaveExp uses multiApply and save time dimension correctly
# CSTools 3.0.0 (Release date: 10-02-2020) # CSTools 3.0.0 (Release date: 10-02-2020)
**New features**
### Development
- CST_MergeDims and MergeDims - CST_MergeDims and MergeDims
- Version working with R 3.4.2 - Version working with R 3.4.2
- PlotForecastPDF handles independent terciles, extremes and observations for each panel - PlotForecastPDF handles independent terciles, extremes and observations for each panel
**Fixes** ### Fixes
- CST_Calibration handles missing values - CST_Calibration handles missing values
- BEI functions handle missing values - BEI functions handle missing values
# CSTools 2.0.0 (Release date: 25-11-2019) # CSTools 2.0.0 (Release date: 25-11-2019)
**New features**
### Development
- CST_Analogs Analogs downscaling method, - CST_Analogs Analogs downscaling method,
- CST_MultiEOFS for multiple variables, - CST_MultiEOFS for multiple variables,
- Ensemble Clustering, - Ensemble Clustering,
...@@ -151,13 +197,14 @@ ...@@ -151,13 +197,14 @@
- Adding reference to S2S4E H2020 project into the DESCRIPTION file - Adding reference to S2S4E H2020 project into the DESCRIPTION file
- Adding NEWS.md file - Adding NEWS.md file
**Fixes** ### Fixes
- Minor fix in CST_BiasCorrection when checking parameter 'obs' - Minor fix in CST_BiasCorrection when checking parameter 'obs'
- Minor fix in data lonlat_prec to be of class 's2dv_cube' - Minor fix in data lonlat_prec to be of class 's2dv_cube'
- Minor fix in RainFARM vignette - Minor fix in RainFARM vignette
### CSTools 1.0.1 (Release date: 19-06-2019) ### CSTools 1.0.1 (Release date: 19-06-2019)
**Fixes and new features**
### Fixes and development
- Correcting test of PlotForecastPDF for compatibility with ggplot2 release - Correcting test of PlotForecastPDF for compatibility with ggplot2 release
- New function PlotCombinedMap - New function PlotCombinedMap
- Adding reference to MEDSCOPE ERA4CS Project into the DESCRIPTION file - Adding reference to MEDSCOPE ERA4CS Project into the DESCRIPTION file
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
#'This function has not constrains of specific regions, variables to downscale, #'This function has not constrains of specific regions, variables to downscale,
#'or data to be used (seasonal forecast data, climate projections data, #'or data to be used (seasonal forecast data, climate projections data,
#'reanalyses data). The regrid into a finner scale is done interpolating with #'reanalyses data). The regrid into a finner scale is done interpolating with
#'CST_Load. Then, this interpolation is corrected selecting the analogs in the #'CST_Start. Then, this interpolation is corrected selecting the analogs in the
#'large and local scale in based of the observations. The function is an #'large and local scale in based of the observations. The function is an
#'adapted version of the method of Yiou et al 2013. For an advanced search of #'adapted version of the method of Yiou et al 2013. For an advanced search of
#'Analogs (multiple Analogs, different criterias, further information from the #'Analogs (multiple Analogs, different criterias, further information from the
...@@ -54,6 +54,8 @@ ...@@ -54,6 +54,8 @@
#' analog of parameter 'expVar'. #' analog of parameter 'expVar'.
#'@param obsVar An 's2dv_cube' containing the field of the same variable as the #'@param obsVar An 's2dv_cube' containing the field of the same variable as the
#' passed in parameter 'expVar' for the same region. #' passed in parameter 'expVar' for the same region.
#'@param sdate_dim A character string indicating the name of the start date
#' dimension. By default, it is set to 'sdate'.
#'@param region A vector of length four indicating the minimum longitude, the #'@param region A vector of length four indicating the minimum longitude, the
#' maximum longitude, the minimum latitude and the maximum latitude. #' maximum longitude, the minimum latitude and the maximum latitude.
#'@param criteria A character string indicating the criteria to be used for the #'@param criteria A character string indicating the criteria to be used for the
...@@ -77,7 +79,8 @@ ...@@ -77,7 +79,8 @@
#' and dates are taken from element \code{$attrs$Dates} from expL. #' and dates are taken from element \code{$attrs$Dates} from expL.
#'@param time_obsL A character string indicating the date of the observations #'@param time_obsL A character string indicating the date of the observations
#' in the date format (i.e. "yyyy-mm-dd"). By default it is NULL and dates are #' in the date format (i.e. "yyyy-mm-dd"). By default it is NULL and dates are
#' taken from element \code{$attrs$Dates} from obsL. #' taken from element \code{$attrs$Dates} from obsL. It must have time
#' dimensions.
#'@param region A vector of length four indicating the minimum longitude, #'@param region A vector of length four indicating the minimum longitude,
#' the maximum longitude, the minimum latitude and the maximum latitude. #' the maximum longitude, the minimum latitude and the maximum latitude.
#'@param nAnalogs Number of Analogs to be selected to apply the criterias #'@param nAnalogs Number of Analogs to be selected to apply the criterias
...@@ -101,8 +104,7 @@ ...@@ -101,8 +104,7 @@
#' best analog, for instance for downscaling. #' best analog, for instance for downscaling.
#'@param ncores The number of cores to use in parallel computation #'@param ncores The number of cores to use in parallel computation
#' #'
#'@seealso \code{\link{CST_Load}}, \code{\link[s2dv]{Load}} and #'@seealso \code{\link{CST_Start}}, \code{\link[startR]{Start}}
#'\code{\link[s2dv]{CDORemap}}
#' #'
#'@return An 's2dv_cube' object containing an array with the dowscaled values of #'@return An 's2dv_cube' object containing an array with the dowscaled values of
#'the best analogs in element 'data'. If 'AnalogsInfo' is TRUE, 'data' is a list #'the best analogs in element 'data'. If 'AnalogsInfo' is TRUE, 'data' is a list
...@@ -117,6 +119,7 @@ ...@@ -117,6 +119,7 @@
#' format = "%d-%m-%y") #' format = "%d-%m-%y")
#'dim(time_obsL) <- c(time = 10) #'dim(time_obsL) <- c(time = 10)
#'time_expL <- time_obsL[1] #'time_expL <- time_obsL[1]
#'dim(time_expL) <- c(time = 1)
#'lon <- seq(-1, 5, 1.5) #'lon <- seq(-1, 5, 1.5)
#'lat <- seq(30, 35, 1.5) #'lat <- seq(30, 35, 1.5)
#'coords <- list(lon = seq(-1, 5, 1.5), lat = seq(30, 35, 1.5)) #'coords <- list(lon = seq(-1, 5, 1.5), lat = seq(30, 35, 1.5))
...@@ -131,9 +134,11 @@ ...@@ -131,9 +134,11 @@
#' #'
#'@import multiApply #'@import multiApply
#'@import abind #'@import abind
#'@import s2dv
#'@importFrom ClimProjDiags SelBox Subset #'@importFrom ClimProjDiags SelBox Subset
#'@export #'@export
CST_Analogs <- function(expL, obsL, expVar = NULL, obsVar = NULL, region = NULL, CST_Analogs <- function(expL, obsL, expVar = NULL, obsVar = NULL,
sdate_dim = 'sdate', region = NULL,
criteria = 'Large_dist', excludeTime = NULL, criteria = 'Large_dist', excludeTime = NULL,
time_expL = NULL, time_obsL = NULL, time_expL = NULL, time_obsL = NULL,
nAnalogs = NULL, AnalogsInfo = FALSE, nAnalogs = NULL, AnalogsInfo = FALSE,
...@@ -141,16 +146,13 @@ CST_Analogs <- function(expL, obsL, expVar = NULL, obsVar = NULL, region = NULL, ...@@ -141,16 +146,13 @@ CST_Analogs <- function(expL, obsL, expVar = NULL, obsVar = NULL, region = NULL,
# Check 's2dv_cube' # Check 's2dv_cube'
if (!inherits(expL, "s2dv_cube") || !inherits(obsL, "s2dv_cube")) { if (!inherits(expL, "s2dv_cube") || !inherits(obsL, "s2dv_cube")) {
stop("Parameter 'expL' and 'obsL' must be of the class 's2dv_cube', ", stop("Parameter 'expL' and 'obsL' must be of the class 's2dv_cube'.")
"as output by CSTools::CST_Load.")
} }
if (!is.null(expVar) && !inherits(expVar, "s2dv_cube")) { if (!is.null(expVar) && !inherits(expVar, "s2dv_cube")) {
stop("Parameter 'expVar' must be of the class 's2dv_cube', ", stop("Parameter 'expVar' must be of the class 's2dv_cube'.")
"as output by CSTools::CST_Load.")
} }
if (!is.null(obsVar) && !inherits(obsVar, "s2dv_cube")) { if (!is.null(obsVar) && !inherits(obsVar, "s2dv_cube")) {
stop("Parameter 'obsVar' must be of the class 's2dv_cube', ", stop("Parameter 'obsVar' must be of the class 's2dv_cube'.")
"as output by CSTools::CST_Load.")
} }
# Check 'obsL' object structure # Check 'obsL' object structure
...@@ -215,7 +217,8 @@ CST_Analogs <- function(expL, obsL, expVar = NULL, obsVar = NULL, region = NULL, ...@@ -215,7 +217,8 @@ CST_Analogs <- function(expL, obsL, expVar = NULL, obsVar = NULL, region = NULL,
lonL = as.vector(obsL$coords[[lon_name]]), lonL = as.vector(obsL$coords[[lon_name]]),
latL = as.vector(obsL$coords[[lat_name]]), latL = as.vector(obsL$coords[[lat_name]]),
expVar = expVar$data, expVar = expVar$data,
obsVar = obsVar$data, criteria = criteria, obsVar = obsVar$data, sdate_dim = sdate_dim,
criteria = criteria,
excludeTime = excludeTime, region = region, excludeTime = excludeTime, region = region,
lonVar = as.vector(lonVar), latVar = as.vector(latVar), lonVar = as.vector(lonVar), latVar = as.vector(latVar),
nAnalogs = nAnalogs, AnalogsInfo = AnalogsInfo, nAnalogs = nAnalogs, AnalogsInfo = AnalogsInfo,
...@@ -228,6 +231,7 @@ CST_Analogs <- function(expL, obsL, expVar = NULL, obsVar = NULL, region = NULL, ...@@ -228,6 +231,7 @@ CST_Analogs <- function(expL, obsL, expVar = NULL, obsVar = NULL, region = NULL,
} }
expL$data <- res expL$data <- res
expL$dims <- dim(res)
if (!is.null(obsL$coords[[lon_name]]) | !is.null(obsL$coords[[lat_name]])) { if (!is.null(obsL$coords[[lon_name]]) | !is.null(obsL$coords[[lat_name]])) {
if (is.null(region)) { if (is.null(region)) {
...@@ -285,7 +289,7 @@ CST_Analogs <- function(expL, obsL, expVar = NULL, obsVar = NULL, region = NULL, ...@@ -285,7 +289,7 @@ CST_Analogs <- function(expL, obsL, expVar = NULL, obsVar = NULL, region = NULL,
#'ones. This function has not constrains of specific regions, variables to #'ones. This function has not constrains of specific regions, variables to
#'downscale, or data to be used (seasonal forecast data, climate projections #'downscale, or data to be used (seasonal forecast data, climate projections
#'data, reanalyses data). The regrid into a finner scale is done interpolating #'data, reanalyses data). The regrid into a finner scale is done interpolating
#'with CST_Load. Then, this interpolation is corrected selecting the analogs in #'with CST_Start. Then, this interpolation is corrected selecting the analogs in
#'the large and local scale in based of the observations. The function is an #'the large and local scale in based of the observations. The function is an
#'adapted version of the method of Yiou et al 2013. #'adapted version of the method of Yiou et al 2013.
#' #'
...@@ -308,10 +312,12 @@ CST_Analogs <- function(expL, obsL, expVar = NULL, obsVar = NULL, region = NULL, ...@@ -308,10 +312,12 @@ CST_Analogs <- function(expL, obsL, expVar = NULL, obsVar = NULL, region = NULL,
#' the same latitudinal and longitudinal dimensions as parameter 'expL' and a #' the same latitudinal and longitudinal dimensions as parameter 'expL' and a
#' single temporal dimension with the maximum number of available observations. #' single temporal dimension with the maximum number of available observations.
#'@param time_obsL A character string indicating the date of the observations #'@param time_obsL A character string indicating the date of the observations
#' in the format "dd-mm-yyyy". Reference time to search for analogs. #' in the format "dd-mm-yyyy". Reference time to search for analogs. It must
#' have time dimensions.
#'@param time_expL An array of N named dimensions (coinciding with time #'@param time_expL An array of N named dimensions (coinciding with time
#' dimensions in expL) of character string(s) indicating the date(s) of the #' dimensions in expL) of character string(s) indicating the date(s) of the
#' experiment in the format "dd-mm-yyyy". Time(s) to find the analogs. #' experiment in the format "dd-mm-yyyy". Time(s) to find the analogs. If it
#' is not an scalar it must have named dimensions.
#'@param lonL A vector containing the longitude of parameter 'expL'. #'@param lonL A vector containing the longitude of parameter 'expL'.
#'@param latL A vector containing the latitude of parameter 'expL'. #'@param latL A vector containing the latitude of parameter 'expL'.
#'@param excludeTime An array of N named dimensions (coinciding with time #'@param excludeTime An array of N named dimensions (coinciding with time
...@@ -326,6 +332,8 @@ CST_Analogs <- function(expL, obsL, expVar = NULL, obsVar = NULL, region = NULL, ...@@ -326,6 +332,8 @@ CST_Analogs <- function(expL, obsL, expVar = NULL, obsVar = NULL, region = NULL,
#' function will be the analog of parameter 'expVar'. #' function will be the analog of parameter 'expVar'.
#'@param obsVar An array of N named dimensions containing the field of the #'@param obsVar An array of N named dimensions containing the field of the
#' same variable as the passed in parameter 'expVar' for the same region. #' same variable as the passed in parameter 'expVar' for the same region.
#'@param sdate_dim A character string indicating the name of the start date
#' dimension. By default, it is set to 'sdate'.
#'@param AnalogsInfo A logical value. If it is TRUE it returns a list #'@param AnalogsInfo A logical value. If it is TRUE it returns a list
#' with two elements: 1) the downscaled field and #' with two elements: 1) the downscaled field and
#' 2) the AnalogsInfo which contains: a) the number of the best #' 2) the AnalogsInfo which contains: a) the number of the best
...@@ -372,6 +380,7 @@ CST_Analogs <- function(expL, obsL, expVar = NULL, obsVar = NULL, region = NULL, ...@@ -372,6 +380,7 @@ CST_Analogs <- function(expL, obsL, expVar = NULL, obsVar = NULL, region = NULL,
#'obsSLP <- c(rnorm(1:180), expSLP * 1.2) #'obsSLP <- c(rnorm(1:180), expSLP * 1.2)
#'dim(obsSLP) <- c(time = 10, lat = 4, lon = 5) #'dim(obsSLP) <- c(time = 10, lat = 4, lon = 5)
#'time_obsSLP <- paste(rep("01", 10), rep("01", 10), 1994 : 2003, sep = "-") #'time_obsSLP <- paste(rep("01", 10), rep("01", 10), 1994 : 2003, sep = "-")
#'dim(time_obsSLP) <- c(time = 10)
#'downscale_field <- Analogs(expL = expSLP, obsL = obsSLP, #'downscale_field <- Analogs(expL = expSLP, obsL = obsSLP,
#' time_obsL = time_obsSLP,time_expL = "01-01-1994") #' time_obsL = time_obsSLP,time_expL = "01-01-1994")
#' #'
...@@ -417,11 +426,12 @@ CST_Analogs <- function(expL, obsL, expVar = NULL, obsVar = NULL, region = NULL, ...@@ -417,11 +426,12 @@ CST_Analogs <- function(expL, obsL, expVar = NULL, obsVar = NULL, region = NULL,
#' AnalogsInfo = TRUE) #' AnalogsInfo = TRUE)
#'@import multiApply #'@import multiApply
#'@import abind #'@import abind
#'@import s2dv
#'@importFrom ClimProjDiags SelBox Subset #'@importFrom ClimProjDiags SelBox Subset
#'@export #'@export
Analogs <- function(expL, obsL, time_obsL, time_expL = NULL, Analogs <- function(expL, obsL, time_obsL, time_expL = NULL,
lonL = NULL, latL = NULL, expVar = NULL, lonL = NULL, latL = NULL, expVar = NULL, obsVar = NULL,
obsVar = NULL, criteria = "Large_dist", sdate_dim = 'sdate', criteria = "Large_dist",
excludeTime = NULL, lonVar = NULL, latVar = NULL, excludeTime = NULL, lonVar = NULL, latVar = NULL,
region = NULL, nAnalogs = NULL, region = NULL, nAnalogs = NULL,
AnalogsInfo = FALSE, ncores = NULL) { AnalogsInfo = FALSE, ncores = NULL) {
...@@ -536,12 +546,61 @@ Analogs <- function(expL, obsL, time_obsL, time_expL = NULL, ...@@ -536,12 +546,61 @@ Analogs <- function(expL, obsL, time_obsL, time_expL = NULL,
} }
if (!inherits(time_obsL, "character")) { if (!inherits(time_obsL, "character")) {
warning('imposing time_obsL to be a character') warning('imposing time_obsL to be a character')
dims_time_obsL <- dim(time_obsL)
time_obsL <- format(as.Date(time_obsL), '%d-%m-%Y') time_obsL <- format(as.Date(time_obsL), '%d-%m-%Y')
dim(time_obsL) <- dims_time_obsL
} }
if (!inherits(time_expL, "character")) { if (!inherits(time_expL, "character")) {
warning('imposing time_expL to be a character') warning('imposing time_expL to be a character')
dims_time_expL <- dim(time_expL)
time_expL <- format(as.Date(time_expL), '%d-%m-%Y') time_expL <- format(as.Date(time_expL), '%d-%m-%Y')
dim(time_expL) <- dims_time_expL
} }
# time_obsL, time_expL (2)
if (is.null(names(dim(time_obsL)))) {
stop("Parameter 'time_obsL' must have named dimensions.")
}
if (!is.character(sdate_dim)) {
stop("Parameter 'sdate_dim' must be a character string.")
}
if (!sdate_dim %in% names(dim(time_obsL))) {
if (length(dim(time_obsL)) == 1) {
dim(time_obsL) <- c(dim(time_obsL), sdate = 1)
} else {
stop("Parameters 'time_obsL' must have 'sdate_dim' dimension name. ",
"If it has multiple time dimensions.")
}
}
if (length(time_expL) != 1) {
if (is.null(names(dim(time_expL)))) {
stop("Parameter 'time_expL' must have named dimensions.")
}
} else {
dim(time_expL) <- 1
}
if (!sdate_dim %in% names(dim(time_expL))) {
if (length(dim(time_expL)) == 1) {
dim(time_expL) <- c(dim(time_expL), sdate = 1)
} else {
stop("Parameters 'time_expL' must have 'sdate_dim' dimension name. ",
"If it has multiple time dimensions.")
}
}
if (length(dim(time_obsL)) == 2) {
if (which(sdate_dim %in% names(dim(time_obsL))) == 1) {
time_obsL <- Reorder(time_obsL, c(2,1))
}
} else {
warning("Parameter 'time_obsL' should have forecast time and start date dimension in this order.")
}
if (length(dim(time_expL)) == 2) {
if (which(sdate_dim %in% names(dim(time_expL))) == 1) {
time_expL <- Reorder(time_expL, c(2,1))
}
} else {
warning("Parameter 'time_expL' should have forecast time and start date dimension in this order.")
}
# excludeTime # excludeTime
if (!is.null(excludeTime)) { if (!is.null(excludeTime)) {
if (!inherits(excludeTime, "character")) { if (!inherits(excludeTime, "character")) {
...@@ -549,23 +608,7 @@ Analogs <- function(expL, obsL, time_obsL, time_expL = NULL, ...@@ -549,23 +608,7 @@ Analogs <- function(expL, obsL, time_obsL, time_expL = NULL,
excludeTime <- format(as.Date(excludeTime),'%d-%m-%Y') excludeTime <- format(as.Date(excludeTime),'%d-%m-%Y')
} }
} }
# time_obsL # obsVar, expVar
if (is.null(time_obsL)) {
stop("Parameter 'time_obsL' cannot be NULL")
}
if (any(names(dim(obsL)) %in% 'ftime')) {
if (any(names(dim(obsL)) %in% 'time')) {
stop("Multiple temporal dimensions ('ftime' and 'time') found",
"in parameter 'obsL'.")
} else {
time_pos_obsL <- which(names(dim(obsL)) == 'ftime')
names(dim(obsL))[time_pos_obsL] <- 'time'
if (any(names(dim(expL)) %in% 'ftime')) {
time_pos_expL <- which(names(dim(expL)) == 'ftime')
names(dim(expL))[time_pos_expL] <- 'time'
}
}
}
if (!is.null(obsVar)) { if (!is.null(obsVar)) {
if (any(names(dim(obsVar)) %in% 'ftime')) { if (any(names(dim(obsVar)) %in% 'ftime')) {
if (any(names(dim(obsVar)) %in% 'time')) { if (any(names(dim(obsVar)) %in% 'time')) {
...@@ -581,6 +624,20 @@ Analogs <- function(expL, obsL, time_obsL, time_expL = NULL, ...@@ -581,6 +624,20 @@ Analogs <- function(expL, obsL, time_obsL, time_expL = NULL,
} }
} }
} }
# obsL
if (any(names(dim(obsL)) %in% 'ftime')) {
if (any(names(dim(obsL)) %in% 'time')) {
stop("Multiple temporal dimensions ('ftime' and 'time') found",
"in parameter 'obsL'.")
} else {
time_pos_obsL <- which(names(dim(obsL)) == 'ftime')
names(dim(obsL))[time_pos_obsL] <- 'time'
if (any(names(dim(expL)) %in% 'ftime')) {
time_pos_expL <- which(names(dim(expL)) == 'ftime')
names(dim(expL))[time_pos_expL] <- 'time'
}
}
}
if ((any(names(dim(obsL)) %in% 'sdate')) && if ((any(names(dim(obsL)) %in% 'sdate')) &&
(any(names(dim(obsL)) %in% 'time'))) { (any(names(dim(obsL)) %in% 'time'))) {
dims_obsL <- dim(obsL) dims_obsL <- dim(obsL)
...@@ -604,7 +661,7 @@ Analogs <- function(expL, obsL, time_obsL, time_expL = NULL, ...@@ -604,7 +661,7 @@ Analogs <- function(expL, obsL, time_obsL, time_expL = NULL,
if (any(names(dim(obsL)) %in% 'time')) { if (any(names(dim(obsL)) %in% 'time')) {
dims_obsL <- dim(obsL) dims_obsL <- dim(obsL)
pos_time <- which(names(dim(obsL)) == 'time') pos_time <- which(names(dim(obsL)) == 'time')
if(length(time_obsL) != dim(obsL)[pos_time]) { if (length(time_obsL) != dim(obsL)[pos_time]) {
stop("'time_obsL' and 'obsL' must have same length in the temporal stop("'time_obsL' and 'obsL' must have same length in the temporal
dimension.") dimension.")
} }
...@@ -618,6 +675,7 @@ Analogs <- function(expL, obsL, time_obsL, time_expL = NULL, ...@@ -618,6 +675,7 @@ Analogs <- function(expL, obsL, time_obsL, time_expL = NULL,
} }
} }
} }
# obsVar
if (!is.null(obsVar)) { if (!is.null(obsVar)) {
if (any(names(dim(obsVar)) %in% 'sdate')) { if (any(names(dim(obsVar)) %in% 'sdate')) {
if (any(names(dim(obsVar)) %in% 'time')) { if (any(names(dim(obsVar)) %in% 'time')) {
......
...@@ -9,10 +9,10 @@ ...@@ -9,10 +9,10 @@
#'computation is carried out independently for experimental and observational #'computation is carried out independently for experimental and observational
#'data products. #'data products.
#' #'
#'@param exp An object of class \code{s2dv_cube} as returned by \code{CST_Load} #'@param exp An object of class \code{s2dv_cube} as returned by \code{CST_Start}
#' function, containing the seasonal forecast experiment data in the element #' function, containing the seasonal forecast experiment data in the element
#' named \code{$data}. #' named \code{$data}.
#'@param obs An object of class \code{s2dv_cube} as returned by \code{CST_Load} #'@param obs An object of class \code{s2dv_cube} as returned by \code{CST_Start}
#' function, containing the observed data in the element named \code{$data}. #' function, containing the observed data in the element named \code{$data}.
#'@param dim_anom A character string indicating the name of the dimension #'@param dim_anom A character string indicating the name of the dimension
#' along which the climatology will be computed. The default value is 'sdate'. #' along which the climatology will be computed. The default value is 'sdate'.
...@@ -57,7 +57,7 @@ ...@@ -57,7 +57,7 @@
#'anom <- CST_Anomaly(exp = exp, obs = obs, cross = FALSE, memb = TRUE) #'anom <- CST_Anomaly(exp = exp, obs = obs, cross = FALSE, memb = TRUE)
#' #'
#'@seealso \code{\link[s2dv]{Ano_CrossValid}}, \code{\link[s2dv]{Clim}} and #'@seealso \code{\link[s2dv]{Ano_CrossValid}}, \code{\link[s2dv]{Clim}} and
#'\code{\link{CST_Load}} #'\code{\link{CST_Start}}
#' #'
#'@import multiApply #'@import multiApply
#'@importFrom s2dv InsertDim Clim Ano_CrossValid Reorder #'@importFrom s2dv InsertDim Clim Ano_CrossValid Reorder
...@@ -69,8 +69,7 @@ CST_Anomaly <- function(exp = NULL, obs = NULL, dim_anom = 'sdate', ...@@ -69,8 +69,7 @@ CST_Anomaly <- function(exp = NULL, obs = NULL, dim_anom = 'sdate',
# Check 's2dv_cube' # Check 's2dv_cube'
if (!inherits(exp, 's2dv_cube') & !is.null(exp) || if (!inherits(exp, 's2dv_cube') & !is.null(exp) ||
!inherits(obs, 's2dv_cube') & !is.null(obs)) { !inherits(obs, 's2dv_cube') & !is.null(obs)) {
stop("Parameter 'exp' and 'obs' must be of the class 's2dv_cube', ", stop("Parameter 'exp' and 'obs' must be of the class 's2dv_cube'.")
"as output by CSTools::CST_Load.")
} }
# exp and obs # exp and obs
if (is.null(exp$data) & is.null(obs$data)) { if (is.null(exp$data) & is.null(obs$data)) {
...@@ -91,13 +90,10 @@ CST_Anomaly <- function(exp = NULL, obs = NULL, dim_anom = 'sdate', ...@@ -91,13 +90,10 @@ CST_Anomaly <- function(exp = NULL, obs = NULL, dim_anom = 'sdate',
any(is.null(names(dim(obs$data))))| any(nchar(names(dim(obs$data))) == 0)) { any(is.null(names(dim(obs$data))))| any(nchar(names(dim(obs$data))) == 0)) {
stop("Parameter 'exp' and 'obs' must have dimension names in element 'data'.") stop("Parameter 'exp' and 'obs' must have dimension names in element 'data'.")
} }
if (!all(names(dim(exp$data)) %in% names(dim(obs$data))) |
!all(names(dim(obs$data)) %in% names(dim(exp$data)))) {
stop("Parameter 'exp' and 'obs' must have same dimension names in element 'data'.")
}
dim_exp <- dim(exp$data) dim_exp <- dim(exp$data)
dim_obs <- dim(obs$data) dim_obs <- dim(obs$data)
dimnames_data <- names(dim_exp) dimnames_exp <- names(dim_exp)
dimnames_obs <- names(dim_obs)
# dim_anom # dim_anom
if (!is.character(dim_anom)) { if (!is.character(dim_anom)) {
stop("Parameter 'dim_anom' must be a character string.") stop("Parameter 'dim_anom' must be a character string.")
...@@ -129,19 +125,12 @@ CST_Anomaly <- function(exp = NULL, obs = NULL, dim_anom = 'sdate', ...@@ -129,19 +125,12 @@ CST_Anomaly <- function(exp = NULL, obs = NULL, dim_anom = 'sdate',
if (!is.character(memb_dim) | length(memb_dim) > 1) { if (!is.character(memb_dim) | length(memb_dim) > 1) {
stop("Parameter 'memb_dim' must be a character string.") stop("Parameter 'memb_dim' must be a character string.")
} }
if (!memb_dim %in% names(dim_exp) | !memb_dim %in% names(dim_obs)) {
stop("Parameter 'memb_dim' is not found in 'exp' or in 'obs' dimension.")
}
} }
# dat_dim # dat_dim
if (!is.null(dat_dim)) { if (!is.null(dat_dim)) {
if (!is.character(dat_dim)) { if (!is.character(dat_dim)) {
stop("Parameter 'dat_dim' must be a character vector.") stop("Parameter 'dat_dim' must be a character vector.")
} }
if (!all(dat_dim %in% names(dim_exp)) | !all(dat_dim %in% names(dim_obs))) {
stop("Parameter 'dat_dim' is not found in 'exp' or 'obs' dimension in element 'data'. ",
"Set it as NULL if there is no dataset dimension.")
}
} }
# filter_span # filter_span
if (!is.null(filter_span)) { if (!is.null(filter_span)) {
...@@ -161,7 +150,7 @@ CST_Anomaly <- function(exp = NULL, obs = NULL, dim_anom = 'sdate', ...@@ -161,7 +150,7 @@ CST_Anomaly <- function(exp = NULL, obs = NULL, dim_anom = 'sdate',
if (!is.character(ftime_dim)) { if (!is.character(ftime_dim)) {
stop("Parameter 'ftime_dim' must be a character string.") stop("Parameter 'ftime_dim' must be a character string.")
} }
if (!ftime_dim %in% names(dim_exp) | !memb_dim %in% names(dim_obs)) { if (!ftime_dim %in% names(dim_exp) | !ftime_dim %in% names(dim_obs)) {
stop("Parameter 'ftime_dim' is not found in 'exp' or in 'obs' dimension in element 'data'.") stop("Parameter 'ftime_dim' is not found in 'exp' or in 'obs' dimension in element 'data'.")
} }
} }
...@@ -206,15 +195,17 @@ CST_Anomaly <- function(exp = NULL, obs = NULL, dim_anom = 'sdate', ...@@ -206,15 +195,17 @@ CST_Anomaly <- function(exp = NULL, obs = NULL, dim_anom = 'sdate',
ano <- NULL ano <- NULL
# Permuting back dimensions to original order # Permuting back dimensions to original order
clim_exp <- Reorder(clim_exp, dimnames_data) clim_exp <- Reorder(clim_exp, dimnames_exp)
clim_obs <- Reorder(clim_obs, dimnames_data) clim_obs <- Reorder(clim_obs, dimnames_obs)
ano$exp <- exp$data - clim_exp ano$exp <- exp$data - clim_exp
ano$obs <- obs$data - clim_obs ano$obs <- obs$data - clim_obs
} }
exp$data <- ano$exp exp$data <- ano$exp
exp$dims <- dim(ano$exp)
obs$data <- ano$obs obs$data <- ano$obs
obs$dims <- dim(ano$obs)
# Outputs # Outputs
# ~~~~~~~~~ # ~~~~~~~~~
......
...@@ -5,14 +5,14 @@ ...@@ -5,14 +5,14 @@
#'described in Torralba et al. (2017). The adjusted forecasts have an equivalent #'described in Torralba et al. (2017). The adjusted forecasts have an equivalent
#'standard deviation and mean to that of the reference dataset. #'standard deviation and mean to that of the reference dataset.
#' #'
#'@param exp An object of class \code{s2dv_cube} as returned by \code{CST_Load} #'@param exp An object of class \code{s2dv_cube} as returned by \code{CST_Start}
#' function, containing the seasonal forecast experiment data in the element #' function, containing the seasonal forecast experiment data in the element
#' named \code{$data} with at least time and member dimensions. #' named \code{$data} with at least time and member dimensions.
#'@param obs An object of class \code{s2dv_cube} as returned by \code{CST_Load} #'@param obs An object of class \code{s2dv_cube} as returned by \code{CST_Start}
#' function, containing the observed data in the element named \code{$data} #' function, containing the observed data in the element named \code{$data}
#' with at least time dimension. #' with at least time dimension.
#'@param exp_cor An object of class \code{s2dv_cube} as returned by #'@param exp_cor An object of class \code{s2dv_cube} as returned by
#' \code{CST_Load} function, containing the seasonal forecast experiment to be #' \code{CST_Start} function, containing the seasonal forecast experiment to be
#' corrected with at least time dimension. If it is NULL, the 'exp' forecast #' corrected with at least time dimension. If it is NULL, the 'exp' forecast
#' will be corrected. If there is only one corrected dataset, it should not #' will be corrected. If there is only one corrected dataset, it should not
#' have dataset dimension. If there is a corresponding corrected dataset for #' have dataset dimension. If there is a corresponding corrected dataset for
...@@ -44,9 +44,9 @@ ...@@ -44,9 +44,9 @@
#' #'
#'@examples #'@examples
#'mod1 <- 1 : (1 * 3 * 4 * 5 * 6 * 7) #'mod1 <- 1 : (1 * 3 * 4 * 5 * 6 * 7)
#'dim(mod1) <- c(dataset = 1, member = 3, sdate = 4, ftime = 5, lat = 6, lon = 7) #'dim(mod1) <- c(dataset = 1, member = 3, sdate = 4, time = 5, lat = 6, lon = 7)
#'obs1 <- 1 : (1 * 1 * 4 * 5 * 6 * 7) #'obs1 <- 1 : (1 * 1 * 4 * 5 * 6 * 7)
#'dim(obs1) <- c(dataset = 1, member = 1, sdate = 4, ftime = 5, lat = 6, lon = 7) #'dim(obs1) <- c(dataset = 1, member = 1, sdate = 4, time = 5, lat = 6, lon = 7)
#'lon <- seq(0, 30, 5) #'lon <- seq(0, 30, 5)
#'lat <- seq(0, 25, 5) #'lat <- seq(0, 25, 5)
#'coords <- list(lat = lat, lon = lon) #'coords <- list(lat = lat, lon = lon)
...@@ -134,9 +134,9 @@ CST_BiasCorrection <- function(exp, obs, exp_cor = NULL, na.rm = FALSE, ...@@ -134,9 +134,9 @@ CST_BiasCorrection <- function(exp, obs, exp_cor = NULL, na.rm = FALSE,
#' #'
#'@examples #'@examples
#'mod1 <- 1 : (1 * 3 * 4 * 5 * 6 * 7) #'mod1 <- 1 : (1 * 3 * 4 * 5 * 6 * 7)
#'dim(mod1) <- c(dataset = 1, member = 3, sdate = 4, ftime = 5, lat = 6, lon = 7) #'dim(mod1) <- c(dataset = 1, member = 3, sdate = 4, time = 5, lat = 6, lon = 7)
#'obs1 <- 1 : (1 * 1 * 4 * 5 * 6 * 7) #'obs1 <- 1 : (1 * 1 * 4 * 5 * 6 * 7)
#'dim(obs1) <- c(dataset = 1, member = 1, sdate = 4, ftime = 5, lat = 6, lon = 7) #'dim(obs1) <- c(dataset = 1, member = 1, sdate = 4, time = 5, lat = 6, lon = 7)
#'a <- BiasCorrection(exp = mod1, obs = obs1) #'a <- BiasCorrection(exp = mod1, obs = obs1)
#'@import multiApply #'@import multiApply
#'@export #'@export
......
...@@ -18,16 +18,16 @@ ...@@ -18,16 +18,16 @@
#'(2014). It is equivalent to function \code{Calibration} but for objects #'(2014). It is equivalent to function \code{Calibration} but for objects
#'of class \code{s2dv_cube}. #'of class \code{s2dv_cube}.
#' #'
#'@param exp An object of class \code{s2dv_cube} as returned by \code{CST_Load} #'@param exp An object of class \code{s2dv_cube} as returned by \code{CST_Start}
#' function with at least 'sdate' and 'member' dimensions, containing the #' function with at least 'sdate' and 'member' dimensions, containing the
#' seasonal hindcast experiment data in the element named \code{data}. The #' seasonal hindcast experiment data in the element named \code{data}. The
#' hindcast is used to calibrate the forecast in case the forecast is provided; #' hindcast is used to calibrate the forecast in case the forecast is provided;
#' if not, the same hindcast will be calibrated instead. #' if not, the same hindcast will be calibrated instead.
#'@param obs An object of class \code{s2dv_cube} as returned by \code{CST_Load} #'@param obs An object of class \code{s2dv_cube} as returned by \code{CST_Start}
#' function with at least 'sdate' dimension, containing the observed data in #' function with at least 'sdate' dimension, containing the observed data in
#' the element named \code{$data}. #' the element named \code{$data}.
#'@param exp_cor An optional object of class \code{s2dv_cube} as returned by #'@param exp_cor An optional object of class \code{s2dv_cube} as returned by
#' \code{CST_Load} function with at least 'sdate' and 'member' dimensions, #' \code{CST_Start} function with at least 'sdate' and 'member' dimensions,
#' containing the seasonal forecast experiment data in the element named #' containing the seasonal forecast experiment data in the element named
#' \code{data}. If the forecast is provided, it will be calibrated using the #' \code{data}. If the forecast is provided, it will be calibrated using the
#' hindcast and observations; if not, the hindcast will be calibrated instead. #' hindcast and observations; if not, the hindcast will be calibrated instead.
...@@ -106,7 +106,7 @@ ...@@ -106,7 +106,7 @@
#'Quarterly Journal of the Royal Meteorological Society, 141(688), 807-818. #'Quarterly Journal of the Royal Meteorological Society, 141(688), 807-818.
#'\doi{10.1002/qj.2397} #'\doi{10.1002/qj.2397}
#' #'
#'@seealso \code{\link{CST_Load}} #'@seealso \code{\link{CST_Start}}
#' #'
#'@examples #'@examples
#'# Example 1: #'# Example 1:
...@@ -287,7 +287,7 @@ CST_Calibration <- function(exp, obs, exp_cor = NULL, cal.method = "mse_min", ...@@ -287,7 +287,7 @@ CST_Calibration <- function(exp, obs, exp_cor = NULL, cal.method = "mse_min",
#'Quarterly Journal of the Royal Meteorological Society, 141(688), 807-818. #'Quarterly Journal of the Royal Meteorological Society, 141(688), 807-818.
#'\doi{10.1002/qj.2397} #'\doi{10.1002/qj.2397}
#' #'
#'@seealso \code{\link{CST_Load}} #'@seealso \code{\link{CST_Start}}
#' #'
#'@examples #'@examples
#'mod1 <- 1 : (1 * 3 * 4 * 5 * 6 * 7) #'mod1 <- 1 : (1 * 3 * 4 * 5 * 6 * 7)
......
#'Change the name of one or more dimensions for an object of class s2dv_cube
#'
#'Change the names of the dimensions specified in 'original_names' to the names
#'in 'new_names'. The coordinate names and the dimensions of any attributes
#'are also modified accordingly.
#'
#'@author Agudetse Roures Victoria, \email{victoria.agudetse@bsc.es}
#'
#'@param data An object of class \code{s2dv_cube} whose dimension names
#' should be changed.
#'@param original_names A single character string or a vector indicating the
#' dimensions to be renamed.
#'@param new_names A single character string or a vector indicating the new
#' dimension names, in the same order as the dimensions in 'original_names'.
#'
#'@return An object of class \code{s2dv_cube} with similar data, coordinates and
#'attributes as the \code{data} input, but with modified dimension names.
#'
#'@examples
#'# Example with sample data:
#'# Check original dimensions and coordinates
#'lonlat_temp$exp$dims
#'names(lonlat_temp$exp$coords)
#'dim(lonlat_temp$exp$attrs$Dates)
#'# Change 'dataset' to 'dat' and 'ftime' to 'time'
#'exp <- CST_ChangeDimNames(lonlat_temp$exp,
#' original_names = c("dataset", "ftime"),
#' new_names = c("dat", "time"))
#'# Check new dimensions and coordinates
#'exp$dims
#'names(exp$coords)
#'dim(exp$attrs$Dates)
#'
#'@export
CST_ChangeDimNames <- function(data, original_names, new_names) {
if (!inherits(data, "s2dv_cube")) {
stop("Parameter 'data' must be an object of class 's2dv_cube'.")
}
if (!is.character(original_names)) {
stop("Parameter 'original_names' must be a character string or a ",
"vector of character strings.")
}
if (!is.character(new_names)) {
stop("Parameter 'new_names' must be a character string or a ",
"vector of character strings.")
}
if (!(length(original_names) == length(new_names))) {
stop("The number of dimension names in 'new_names' must be the same ",
"as in 'original_names'.")
}
if (!all(original_names %in% names(data$dims))) {
stop("Some of the dimensions in 'original_names' could not be found in ",
"'data'.")
}
for (index in 1:length(original_names)) {
original_name <- original_names[index]
new_name <- new_names[index]
# Step 1: Change dims
names(data$dims)[which(names(data$dims) == original_name)] <- new_name
# Step 2: Change coords
names(data$coords)[which(names(data$coords) == original_name)] <- new_name
# Step 3: Change attrs
# 3.1 - Dates
if (original_name %in% names(dim(data$attrs$Dates))) {
names(dim(data$attrs$Dates))[which(names(dim(data$attrs$Dates))
== original_name)] <- new_name
}
# 3.2 - Variable metadata
if (original_name %in% names(data$attrs$Variable$metadata)) {
names(data$attrs$Variable$metadata)[which(names(data$attrs$Variable$metadata)
== original_name)] <- new_name
}
# 3.3 - Source files
if (original_name %in% names(dim(data$attrs$source_files))) {
names(dim(data$attrs$source_files))[which(names(dim(data$attrs$source_files))
== original_name)] <- new_name
}
}
# Change data dimnames after renaming all dimensions
dim(data$data) <- data$dims
if (!is.null(attributes(data$data)$dimensions)) {
attributes(data$data)$dimensions <- names(data$dims)
}
# Change $Dates 'dim' attribute
attr(attributes(data$attrs$Dates)$dim, "names") <- names(dim(data$attrs$Dates))
return(data)
}
...@@ -15,8 +15,6 @@ ...@@ -15,8 +15,6 @@
#' \code{merge_dims} will be used. #' \code{merge_dims} will be used.
#'@param na.rm A logical indicating if the NA values should be removed or not. #'@param na.rm A logical indicating if the NA values should be removed or not.
#' #'
#'@import abind
#'@importFrom ClimProjDiags Subset
#'@examples #'@examples
#'data <- 1 : c(2 * 3 * 4 * 5 * 6 * 7) #'data <- 1 : c(2 * 3 * 4 * 5 * 6 * 7)
#'dim(data) <- c(time = 7, lat = 2, lon = 3, monthly = 4, member = 6, #'dim(data) <- c(time = 7, lat = 2, lon = 3, monthly = 4, member = 6,
...@@ -33,11 +31,35 @@ CST_MergeDims <- function(data, merge_dims = c('ftime', 'monthly'), ...@@ -33,11 +31,35 @@ CST_MergeDims <- function(data, merge_dims = c('ftime', 'monthly'),
rename_dim = NULL, na.rm = FALSE) { rename_dim = NULL, na.rm = FALSE) {
# Check 's2dv_cube' # Check 's2dv_cube'
if (!inherits(data, 's2dv_cube')) { if (!inherits(data, 's2dv_cube')) {
stop("Parameter 'data' must be of the class 's2dv_cube', ", stop("Parameter 'data' must be of the class 's2dv_cube'.")
"as output by CSTools::CST_Load.")
} }
if (is.null(rename_dim)) {
rename_dim <- merge_dims[1]
}
# data
data$data <- MergeDims(data$data, merge_dims = merge_dims, data$data <- MergeDims(data$data, merge_dims = merge_dims,
rename_dim = rename_dim, na.rm = na.rm) rename_dim = rename_dim, na.rm = na.rm)
# dims
data$dims <- dim(data$data)
# rename_dim
if (length(rename_dim) > 1) {
rename_dim <- as.character(rename_dim[1])
}
# coords
data$coords[merge_dims] <- NULL
data$coords[[rename_dim]] <- 1:dim(data$data)[rename_dim]
attr(data$coords[[rename_dim]], 'indices') <- TRUE
# attrs
if (all(merge_dims %in% names(dim(data$attrs$Dates)))) {
data$attrs$Dates <- MergeDims(data$attrs$Dates, merge_dims = merge_dims,
rename_dim = rename_dim, na.rm = na.rm)
} else if (any(merge_dims %in% names(dim(data$attrs$Dates)))) {
warning("The dimensions of 'Dates' array will be different from ",
"the temporal dimensions in 'data'. Parameter 'merge_dims' ",
"only includes one temporal dimension of 'Dates'.")
}
return(data) return(data)
} }
#'Function to Split Dimension #'Function to Split Dimension
...@@ -56,12 +78,12 @@ CST_MergeDims <- function(data, merge_dims = c('ftime', 'monthly'), ...@@ -56,12 +78,12 @@ CST_MergeDims <- function(data, merge_dims = c('ftime', 'monthly'),
#' \code{merge_dims} will be used. #' \code{merge_dims} will be used.
#'@param na.rm A logical indicating if the NA values should be removed or not. #'@param na.rm A logical indicating if the NA values should be removed or not.
#' #'
#'@import abind
#'@importFrom ClimProjDiags Subset
#'@examples #'@examples
#'data <- 1 : 20 #'data <- 1 : 20
#'dim(data) <- c(time = 10, lat = 2) #'dim(data) <- c(time = 10, lat = 2)
#'new_data <- MergeDims(data, merge_dims = c('time', 'lat')) #'new_data <- MergeDims(data, merge_dims = c('time', 'lat'))
#'@import abind
#'@importFrom ClimProjDiags Subset
#'@export #'@export
MergeDims <- function(data, merge_dims = c('time', 'monthly'), MergeDims <- function(data, merge_dims = c('time', 'monthly'),
rename_dim = NULL, na.rm = FALSE) { rename_dim = NULL, na.rm = FALSE) {
......
...@@ -58,13 +58,11 @@ CST_QuantileMapping <- function(exp, obs, exp_cor = NULL, sdate_dim = 'sdate', ...@@ -58,13 +58,11 @@ CST_QuantileMapping <- function(exp, obs, exp_cor = NULL, sdate_dim = 'sdate',
ncores = NULL, ...) { ncores = NULL, ...) {
# Check 's2dv_cube' # Check 's2dv_cube'
if (!inherits(exp, 's2dv_cube') || !inherits(obs, 's2dv_cube')) { if (!inherits(exp, 's2dv_cube') || !inherits(obs, 's2dv_cube')) {
stop("Parameter 'exp' and 'obs' must be of the class 's2dv_cube', ", stop("Parameter 'exp' and 'obs' must be of the class 's2dv_cube'.")
"as output by CSTools::CST_Load.")
} }
if (!is.null(exp_cor)) { if (!is.null(exp_cor)) {
if (!inherits(exp_cor, 's2dv_cube')) { if (!inherits(exp_cor, 's2dv_cube')) {
stop("Parameter 'exp_cor' must be of the class 's2dv_cube', ", stop("Parameter 'exp_cor' must be of the class 's2dv_cube'.")
"as output by CSTools::CST_Load.")
} }
} }
......
...@@ -144,7 +144,7 @@ CST_RFTemp <- function(data, oro, xlim = NULL, ylim = NULL, lapse = 6.5, ...@@ -144,7 +144,7 @@ CST_RFTemp <- function(data, oro, xlim = NULL, ylim = NULL, lapse = 6.5,
#'The output grid can be irregularly spaced in lon and/or lat. #'The output grid can be irregularly spaced in lon and/or lat.
#'@references Method described in ERA4CS MEDSCOPE milestone M3.2: #'@references Method described in ERA4CS MEDSCOPE milestone M3.2:
#'High-quality climate prediction data available to WP4 here: #'High-quality climate prediction data available to WP4 here:
#'\ url{https://www.medscope-project.eu/the-project/deliverables-reports/} #'\url{https://www.medscope-project.eu/the-project/deliverables-reports/}
#'and in H2020 ECOPOTENTIAL Deliverable No. 8.1: #'and in H2020 ECOPOTENTIAL Deliverable No. 8.1:
#'High resolution (1-10 km) climate, land use and ocean change scenarios here: #'High resolution (1-10 km) climate, land use and ocean change scenarios here:
#'\url{https://ec.europa.eu/research/participants/documents/downloadPublic?documentIds=080166e5b6cd2324&appId=PPGMS}. #'\url{https://ec.europa.eu/research/participants/documents/downloadPublic?documentIds=080166e5b6cd2324&appId=PPGMS}.
......
...@@ -4,64 +4,88 @@ ...@@ -4,64 +4,88 @@
#' #'
#'@description This function allows to divide and save a object of class #'@description This function allows to divide and save a object of class
#''s2dv_cube' into a NetCDF file, allowing to reload the saved data using #''s2dv_cube' into a NetCDF file, allowing to reload the saved data using
#'\code{Start} function from StartR package. If the original 's2dv_cube' object #'\code{CST_Start} or \code{CST_Load} functions. It also allows to save any
#'has been created from \code{CST_Load()}, then it can be reloaded with #''s2dv_cube' object that follows the NetCDF attributes conventions.
#'\code{Load()}.
#' #'
#'@param data An object of class \code{s2dv_cube}. #'@param data An object of class \code{s2dv_cube}.
#'@param destination A character string containing the directory name in which #'@param destination A character string containing the directory name in which
#' to save the data. NetCDF file for each starting date are saved into the #' to save the data. NetCDF file for each starting date are saved into the
#' folder tree: \cr #' folder tree: 'destination/Dataset/variable/'. By default the function
#' destination/Dataset/variable/. By default the function #' saves the data into the working directory.
#' creates and saves the data into the working directory.
#'@param sdate_dim A character string indicating the name of the start date #'@param sdate_dim A character string indicating the name of the start date
#' dimension. By default, it is set to 'sdate'. It can be NULL if there is no #' dimension. By default, it is set to 'sdate'. It can be NULL if there is no
#' start date dimension. #' start date dimension.
#'@param ftime_dim A character string indicating the name of the forecast time #'@param ftime_dim A character string indicating the name of the forecast time
#' dimension. By default, it is set to 'time'. It can be NULL if there is no #' dimension. If 'Dates' are used, it can't be NULL. If there is no forecast
#' forecast time dimension. #' time dimension, 'Dates' will be set to NULL and will not be used. By
#' default, it is set to 'time'.
#'@param dat_dim A character string indicating the name of dataset dimension. #'@param dat_dim A character string indicating the name of dataset dimension.
#' By default, it is set to 'dataset'. It can be NULL if there is no dataset #' It can be NULL if there is no dataset dimension. By default, it is set to
#' dimension. #' 'dataset'.
#'@param var_dim A character string indicating the name of variable dimension. #'@param var_dim A character string indicating the name of variable dimension.
#' By default, it is set to 'var'. It can be NULL if there is no variable #' It can be NULL if there is no variable dimension. By default, it is set to
#' dimension. #' 'var'.
#'@param memb_dim A character string indicating the name of the member dimension. #'@param memb_dim A character string indicating the name of the member
#' By default, it is set to 'member'. It can be NULL if there is no member #' dimension. It can be NULL if there is no member dimension. By default, it is
#' dimension. #' set to 'member'.
#'@param startdates A vector of dates that will be used for the filenames #'@param startdates A vector of dates that will be used for the filenames
#' when saving the data in multiple files. It must be a vector of the same #' when saving the data in multiple files (single_file = FALSE). It must be a
#' length as the start date dimension of data. It must be a vector of class #' vector of the same length as the start date dimension of data. It must be a
#' \code{Dates}, \code{'POSIXct'} or character with lenghts between 1 and 10. #' vector of class \code{Dates}, \code{'POSIXct'} or character with lenghts
#' If it is NULL, the coordinate corresponding the the start date dimension or #' between 1 and 10. If it is NULL, the coordinate corresponding the the start
#' the first Date of each time step will be used as the name of the files. #' date dimension or the first Date of each time step will be used as the name
#' It is NULL by default. #' of the files. It is NULL by default.
#'@param single_file A logical value indicating if all object is saved in a #'@param single_file A logical value indicating if all object is saved in a
#' single file (TRUE) or in multiple files (FALSE). When it is FALSE, #' single file (TRUE) or in multiple files (FALSE). When it is FALSE,
#' the array is separated for Datasets, variable and start date. It is FALSE #' the array is separated for datasets, variable and start date. When there are
#' by default. #' no specified time dimensions, the data will be saved in a single file by
#'@param extra_string A character string to be include as part of the file name, #' default. The output file name when 'single_file' is TRUE is a character
#' for instance, to identify member or realization. It would be added to the #' string containing: '<var>_<first_sdate>_<last_sdate>.nc'; when it is FALSE,
#' file name between underscore characters. #' it is '<var>_<sdate>.nc'. It is FALSE by default.
#'@param drop_dims (optional) A vector of character strings indicating the
#' dimension names of length 1 that need to be dropped in order that they don't
#' appear in the netCDF file. Only is allowed to drop dimensions that are not
#' used in the computation. The dimensions used in the computation are the ones
#' specified in: sdate_dim, ftime_dim, dat_dim, var_dim and memb_dim. It is
#' NULL by default.
#'@param extra_string (Optional) A character string to be included as part of
#' the file name, for instance, to identify member or realization. When
#' single_file is TRUE, the 'extra_string' will substitute all the default
#' file name; when single_file is FALSE, the 'extra_string' will be added
#' in the file name as: '<var>_<extra_string>_<sdate>.nc'. It is NULL by
#' default.
#'@param units_hours_since (Optional) A logical value only available for the
#' case: 'Dates' have forecast time and start date dimension, 'single_file' is
#' TRUE and 'time_bounds' are not used. When it is TRUE, it saves the forecast
#' time with units of 'hours since'; if it is FALSE, the time units will be a
#' number of time steps with its corresponding frequency (e.g. n days, n months
#' or n hours). It is FALSE by default.
#'@param global_attrs (Optional) A list with elements containing the global
#' attributes to be saved in the NetCDF.
#' #'
#'@return Multiple or single NetCDF files containing the data array.\cr #'@return Multiple or single NetCDF files containing the data array.\cr
#'\item{\code{single_file = TRUE}}{ #'\item{\code{single_file is TRUE}}{
#' All data is saved in a single file located in the specified destination #' All data is saved in a single file located in the specified destination
#' path with the following name: #' path with the following name (by default):
#' <variable_name>_<extra_string>_<first_sdate>_<last_sdate>.nc. Multiple #' '<variable_name>_<first_sdate>_<last_sdate>.nc'. Multiple variables
#' variables are saved separately in the same file. The forecast time units #' are saved separately in the same file. The forecast time units
#' is extracted from the frequency of the time steps (hours, days, months). #' are calculated from each start date (if sdate_dim is not NULL) or from
#' The first value of forecast time is 1. If no frequency is found, the units #' the time step. If 'units_hours_since' is TRUE, the forecast time units
#' will be 'hours since' each start date and the time steps are assumed to be #' will be 'hours since <each start date>'. If 'units_hours_since' is FALSE,
#' equally spaced. #' the forecast time units are extracted from the frequency of the time steps
#' (hours, days, months); if no frequency is found, the units will be ’hours
#' since’. When the time units are 'hours since' the time ateps are assumed to
#' be equally spaced.
#'} #'}
#'\item{\code{single_file = FALSE}}{ #'\item{\code{single_file is FALSE}}{
#' The data array is subset and stored into multiple files. Each file #' The data array is subset and stored into multiple files. Each file
#' contains the data subset for each start date, variable and dataset. Files #' contains the data subset for each start date, variable and dataset. Files
#' with different variables and Datasets are stored in separated directories #' with different variables and datasets are stored in separated directories
#' within the following directory tree: destination/Dataset/variable/. #' within the following directory tree: 'destination/Dataset/variable/'.
#' The name of each file will be: #' The name of each file will be by default: '<variable_name>_<sdate>.nc'.
#' <variable_name>_<extra_string>_<sdate>.nc. #' The forecast time units are calculated from each start date (if sdate_dim
#' is not NULL) or from the time step. The forecast time units will be 'hours
#' since <each start date>'.
#'} #'}
#' #'
#'@seealso \code{\link[startR]{Start}}, \code{\link{as.s2dv_cube}} and #'@seealso \code{\link[startR]{Start}}, \code{\link{as.s2dv_cube}} and
...@@ -69,26 +93,21 @@ ...@@ -69,26 +93,21 @@
#' #'
#'@examples #'@examples
#'\dontrun{ #'\dontrun{
#'data <- lonlat_temp$exp #'data <- lonlat_temp_st$exp
#'destination <- "./" #'CST_SaveExp(data = data, ftime_dim = 'ftime', var_dim = 'var',
#'CST_SaveExp(data = data, destination = destination, ftime_dim = 'ftime', #' dat_dim = 'dataset', sdate_dim = 'sdate')
#' var_dim = NULL, ftime_dim = 'ftime', var_dim = NULL)
#'} #'}
#' #'
#'@import ncdf4
#'@importFrom s2dv Reorder
#'@importFrom ClimProjDiags Subset
#'@import multiApply
#'@export #'@export
CST_SaveExp <- function(data, destination = "./", sdate_dim = 'sdate', CST_SaveExp <- function(data, destination = "./", startdates = NULL,
ftime_dim = 'time', dat_dim = 'dataset', sdate_dim = 'sdate', ftime_dim = 'time',
var_dim = 'var', memb_dim = 'member', memb_dim = 'member', dat_dim = 'dataset',
startdates = NULL, single_file = FALSE, var_dim = 'var', drop_dims = NULL,
extra_string = NULL) { single_file = FALSE, extra_string = NULL,
global_attrs = NULL, units_hours_since = FALSE) {
# Check 's2dv_cube' # Check 's2dv_cube'
if (!inherits(data, 's2dv_cube')) { if (!inherits(data, 's2dv_cube')) {
stop("Parameter 'data' must be of the class 's2dv_cube', ", stop("Parameter 'data' must be of the class 's2dv_cube'.")
"as output by CSTools::CST_Load.")
} }
# Check object structure # Check object structure
if (!all(c('data', 'attrs') %in% names(data))) { if (!all(c('data', 'attrs') %in% names(data))) {
...@@ -98,22 +117,11 @@ CST_SaveExp <- function(data, destination = "./", sdate_dim = 'sdate', ...@@ -98,22 +117,11 @@ CST_SaveExp <- function(data, destination = "./", sdate_dim = 'sdate',
if (!inherits(data$attrs, 'list')) { if (!inherits(data$attrs, 'list')) {
stop("Level 'attrs' must be a list with at least 'Dates' element.") stop("Level 'attrs' must be a list with at least 'Dates' element.")
} }
if (!all(c('coords') %in% names(data))) {
warning("Element 'coords' not found. No coordinates will be used.")
}
# metadata # metadata
if (is.null(data$attrs$Variable$metadata)) { if (!is.null(data$attrs$Variable$metadata)) {
warning("No metadata found in element Variable from attrs.")
} else {
if (!inherits(data$attrs$Variable$metadata, 'list')) { if (!inherits(data$attrs$Variable$metadata, 'list')) {
stop("Element metadata from Variable element in attrs must be a list.") stop("Element metadata from Variable element in attrs must be a list.")
} }
if (!any(names(data$attrs$Variable$metadata) %in% names(data$coords))) {
warning("Metadata is not found for any coordinate.")
} else if (!any(names(data$attrs$Variable$metadata) %in%
data$attrs$Variable$varName)) {
warning("Metadata is not found for any variable.")
}
} }
# Dates # Dates
if (is.null(data$attrs$Dates)) { if (is.null(data$attrs$Dates)) {
...@@ -127,49 +135,31 @@ CST_SaveExp <- function(data, destination = "./", sdate_dim = 'sdate', ...@@ -127,49 +135,31 @@ CST_SaveExp <- function(data, destination = "./", sdate_dim = 'sdate',
if (!is.character(sdate_dim)) { if (!is.character(sdate_dim)) {
stop("Parameter 'sdate_dim' must be a character string.") stop("Parameter 'sdate_dim' must be a character string.")
} }
if (length(sdate_dim) > 1) {
warning("Parameter 'sdate_dim' has length greater than 1 and ",
"only the first element will be used.")
sdate_dim <- sdate_dim[1]
}
} else if (length(dim(data$attrs$Dates)) == 1) {
sdate_dim <- 'sdate'
dim(data$data) <- c(sdate = 1, dim(data$data))
data$dims <- dim(data$data)
dim(data$attrs$Dates) <- c(sdate = 1, dim(data$attrs$Dates))
data$coords[[sdate_dim]] <- data$attrs$Dates[1]
} }
# startdates # startdates
if (is.null(startdates)) { if (is.null(startdates)) {
startdates <- data$coords[[sdate_dim]] if (is.character(data$coords[[sdate_dim]])) {
} else {
if (!is.character(startdates)) {
warning(paste0("Parameter 'startdates' is not a character string, ",
"it will not be used."))
startdates <- data$coords[[sdate_dim]] startdates <- data$coords[[sdate_dim]]
} }
if (!is.null(sdate_dim)) {
if (dim(data$data)[sdate_dim] != length(startdates)) {
warning(paste0("Parameter 'startdates' doesn't have the same length ",
"as dimension '", sdate_dim,"', it will not be used."))
startdates <- data$coords[[sdate_dim]]
}
}
} }
SaveExp(data = data$data, SaveExp(data = data$data,
destination = destination, destination = destination,
Dates = data$attrs$Dates,
coords = data$coords, coords = data$coords,
Dates = data$attrs$Dates,
time_bounds = data$attrs$time_bounds,
startdates = startdates,
varname = data$attrs$Variable$varName, varname = data$attrs$Variable$varName,
metadata = data$attrs$Variable$metadata, metadata = data$attrs$Variable$metadata,
Datasets = data$attrs$Datasets, Datasets = data$attrs$Datasets,
startdates = startdates, sdate_dim = sdate_dim, ftime_dim = ftime_dim,
dat_dim = dat_dim, sdate_dim = sdate_dim, memb_dim = memb_dim,
ftime_dim = ftime_dim, var_dim = var_dim, dat_dim = dat_dim, var_dim = var_dim,
memb_dim = memb_dim, drop_dims = drop_dims,
single_file = single_file,
extra_string = extra_string, extra_string = extra_string,
single_file = single_file) global_attrs = global_attrs,
units_hours_since = units_hours_since)
} }
#'Save a multidimensional array with metadata to data in NetCDF format #'Save a multidimensional array with metadata to data in NetCDF format
#'@description This function allows to save a data array with metadata into a #'@description This function allows to save a data array with metadata into a
...@@ -182,13 +172,26 @@ CST_SaveExp <- function(data, destination = "./", sdate_dim = 'sdate', ...@@ -182,13 +172,26 @@ CST_SaveExp <- function(data, destination = "./", sdate_dim = 'sdate',
#'@param data A multi-dimensional array with named dimensions. #'@param data A multi-dimensional array with named dimensions.
#'@param destination A character string indicating the path where to store the #'@param destination A character string indicating the path where to store the
#' NetCDF files. #' NetCDF files.
#'@param Dates A named array of dates with the corresponding sdate and forecast
#' time dimension.
#'@param coords A named list with elements of the coordinates corresponding to #'@param coords A named list with elements of the coordinates corresponding to
#' the dimensions of the data parameter. The names and length of each element #' the dimensions of the data parameter. The names and length of each element
#' must correspond to the names of the dimensions. If any coordinate is not #' must correspond to the names of the dimensions. If any coordinate is not
#' provided, it is set as an index vector with the values from 1 to the length #' provided, it is set as an index vector with the values from 1 to the length
#' of the corresponding dimension. #' of the corresponding dimension.
#'@param Dates A named array of dates with the corresponding sdate and forecast
#' time dimension. If there is no sdate_dim, you can set it to NULL.
#' It must have ftime_dim dimension.
#'@param time_bounds (Optional) A list of two arrays of dates containing
#' the lower (first array) and the upper (second array) time bounds
#' corresponding to Dates. Each array must have the same dimensions as Dates.
#' If 'Dates' parameter is NULL, 'time_bounds' are not used. It is NULL by
#' default.
#'@param startdates A vector of dates that will be used for the filenames
#' when saving the data in multiple files (single_file = FALSE). It must be a
#' vector of the same length as the start date dimension of data. It must be a
#' vector of class \code{Dates}, \code{'POSIXct'} or character with lenghts
#' between 1 and 10. If it is NULL, the coordinate corresponding the the start
#' date dimension or the first Date of each time step will be used as the name
#' of the files. It is NULL by default.
#'@param varname A character string indicating the name of the variable to be #'@param varname A character string indicating the name of the variable to be
#' saved. #' saved.
#'@param metadata A named list where each element is a variable containing the #'@param metadata A named list where each element is a variable containing the
...@@ -196,12 +199,6 @@ CST_SaveExp <- function(data, destination = "./", sdate_dim = 'sdate', ...@@ -196,12 +199,6 @@ CST_SaveExp <- function(data, destination = "./", sdate_dim = 'sdate',
#' lists for each variable. #' lists for each variable.
#'@param Datasets A vector of character string indicating the names of the #'@param Datasets A vector of character string indicating the names of the
#' datasets. #' datasets.
#'@param startdates A vector of dates that will be used for the filenames
#' when saving the data in multiple files. It must be a vector of the same
#' length as the start date dimension of data. It must be a vector of class
#' \code{Dates}, \code{'POSIXct'} or character with lenghts between 1 and 10.
#' If it is NULL, the first Date of each time step will be used as the name of
#' the files. It is NULL by default.
#'@param sdate_dim A character string indicating the name of the start date #'@param sdate_dim A character string indicating the name of the start date
#' dimension. By default, it is set to 'sdate'. It can be NULL if there is no #' dimension. By default, it is set to 'sdate'. It can be NULL if there is no
#' start date dimension. #' start date dimension.
...@@ -214,64 +211,89 @@ CST_SaveExp <- function(data, destination = "./", sdate_dim = 'sdate', ...@@ -214,64 +211,89 @@ CST_SaveExp <- function(data, destination = "./", sdate_dim = 'sdate',
#'@param var_dim A character string indicating the name of variable dimension. #'@param var_dim A character string indicating the name of variable dimension.
#' By default, it is set to 'var'. It can be NULL if there is no variable #' By default, it is set to 'var'. It can be NULL if there is no variable
#' dimension. #' dimension.
#'@param memb_dim A character string indicating the name of the member dimension. #'@param memb_dim A character string indicating the name of the member
#' By default, it is set to 'member'. It can be NULL if there is no member #' dimension. By default, it is set to 'member'. It can be NULL if there is no
#' dimension. #' member dimension.
#'@param drop_dims (optional) A vector of character strings indicating the
#' dimension names of length 1 that need to be dropped in order that they don't
#' appear in the netCDF file. Only is allowed to drop dimensions that are not
#' used in the computation. The dimensions used in the computation are the ones
#' specified in: sdate_dim, ftime_dim, dat_dim, var_dim and memb_dim. It is
#' NULL by default.
#'@param single_file A logical value indicating if all object is saved in a #'@param single_file A logical value indicating if all object is saved in a
#' unique file (TRUE) or in separated directories (FALSE). When it is FALSE, #' single file (TRUE) or in multiple files (FALSE). When it is FALSE,
#' the array is separated for Datasets, variable and start date. It is FALSE #' the array is separated for datasets, variable and start date. When there are
#' by default. #' no specified time dimensions, the data will be saved in a single file by
#'@param extra_string A character string to be include as part of the file name, #' default. The output file name when 'single_file' is TRUE is a character
#' for instance, to identify member or realization. It would be added to the #' string containing: '<var>_<first_sdate>_<last_sdate>.nc'; when it is FALSE,
#' file name between underscore characters. #' it is '<var>_<sdate>.nc'. It is FALSE by default.
#'@param extra_string (Optional) A character string to be included as part of
#' the file name, for instance, to identify member or realization. When
#' single_file is TRUE, the 'extra_string' will substitute all the default
#' file name; when single_file is FALSE, the 'extra_string' will be added
#' in the file name as: '<var>_<extra_string>_<sdate>.nc'. It is NULL by
#' default.
#'@param global_attrs (Optional) A list with elements containing the global
#' attributes to be saved in the NetCDF.
#'@param units_hours_since (Optional) A logical value only available for the
#' case: Dates have forecast time and start date dimension, single_file is
#' TRUE and 'time_bounds' is NULL. When it is TRUE, it saves the forecast time
#' with units of 'hours since'; if it is FALSE, the time units will be a number
#' of time steps with its corresponding frequency (e.g. n days, n months or n
#' hours). It is FALSE by default.
#' #'
#'@return Multiple or single NetCDF files containing the data array.\cr #'@return Multiple or single NetCDF files containing the data array.\cr
#'\item{\code{single_file = TRUE}}{ #'\item{\code{single_file is TRUE}}{
#' All data is saved in a single file located in the specified destination #' All data is saved in a single file located in the specified destination
#' path with the following name: #' path with the following name (by default):
#' <variable_name>_<extra_string>_<first_sdate>_<last_sdate>.nc. Multiple #' '<variable_name>_<first_sdate>_<last_sdate>.nc'. Multiple variables
#' variables are saved separately in the same file. The forecast time units #' are saved separately in the same file. The forecast time units
#' is extracted from the frequency of the time steps (hours, days, months). #' are calculated from each start date (if sdate_dim is not NULL) or from
#' The first value of forecast time is 1. If no frequency is found, the units #' the time step. If 'units_hours_since' is TRUE, the forecast time units
#' will be 'hours since' each start date and the time steps are assumed to be #' will be 'hours since <each start date>'. If 'units_hours_since' is FALSE,
#' equally spaced. #' the forecast time units are extracted from the frequency of the time steps
#' (hours, days, months); if no frequency is found, the units will be ’hours
#' since’. When the time units are 'hours since' the time ateps are assumed to
#' be equally spaced.
#'} #'}
#'\item{\code{single_file = FALSE}}{ #'\item{\code{single_file is FALSE}}{
#' The data array is subset and stored into multiple files. Each file #' The data array is subset and stored into multiple files. Each file
#' contains the data subset for each start date, variable and dataset. Files #' contains the data subset for each start date, variable and dataset. Files
#' with different variables and Datasets are stored in separated directories #' with different variables and datasets are stored in separated directories
#' within the following directory tree: destination/Dataset/variable/. #' within the following directory tree: 'destination/Dataset/variable/'.
#' The name of each file will be: #' The name of each file will be by default: '<variable_name>_<sdate>.nc'.
#' <variable_name>_<extra_string>_<sdate>.nc. #' The forecast time units are calculated from each start date (if sdate_dim
#' is not NULL) or from the time step. The forecast time units will be 'hours
#' since <each start date>'.
#'} #'}
#' #'
#'@examples #'@examples
#'\dontrun{ #'\dontrun{
#'data <- lonlat_temp$exp$data #'data <- lonlat_temp_st$exp$data
#'lon <- lonlat_temp$exp$coords$lon #'lon <- lonlat_temp_st$exp$coords$lon
#'lat <- lonlat_temp$exp$coords$lat #'lat <- lonlat_temp_st$exp$coords$lat
#'coords <- list(lon = lon, lat = lat) #'coords <- list(lon = lon, lat = lat)
#'Datasets <- lonlat_temp$exp$attrs$Datasets #'Datasets <- lonlat_temp_st$exp$attrs$Datasets
#'varname <- 'tas' #'varname <- 'tas'
#'Dates <- lonlat_temp$exp$attrs$Dates #'Dates <- lonlat_temp_st$exp$attrs$Dates
#'destination = './' #'metadata <- lonlat_temp_st$exp$attrs$Variable$metadata
#'metadata <- lonlat_temp$exp$attrs$Variable$metadata #'SaveExp(data = data, coords = coords, Datasets = Datasets, varname = varname,
#'SaveExp(data = data, destination = destination, coords = coords, #' Dates = Dates, metadata = metadata, single_file = TRUE,
#' Datasets = Datasets, varname = varname, Dates = Dates, #' ftime_dim = 'ftime', var_dim = 'var', dat_dim = 'dataset')
#' metadata = metadata, single_file = TRUE, ftime_dim = 'ftime',
#' var_dim = NULL)
#'} #'}
#' #'
#'@import ncdf4 #'@import easyNCDF
#'@importFrom s2dv Reorder #'@importFrom s2dv Reorder
#'@import multiApply #'@import multiApply
#'@importFrom ClimProjDiags Subset #'@importFrom ClimProjDiags Subset
#'@export #'@export
SaveExp <- function(data, destination = "./", Dates = NULL, coords = NULL, SaveExp <- function(data, destination = "./", coords = NULL,
Dates = NULL, time_bounds = NULL, startdates = NULL,
varname = NULL, metadata = NULL, Datasets = NULL, varname = NULL, metadata = NULL, Datasets = NULL,
startdates = NULL, dat_dim = 'dataset', sdate_dim = 'sdate', sdate_dim = 'sdate', ftime_dim = 'time',
ftime_dim = 'time', var_dim = 'var', memb_dim = 'member', memb_dim = 'member', dat_dim = 'dataset', var_dim = 'var',
single_file = FALSE, extra_string = NULL) { drop_dims = NULL, single_file = FALSE, extra_string = NULL,
global_attrs = NULL, units_hours_since = FALSE) {
## Initial checks ## Initial checks
# data # data
if (is.null(data)) { if (is.null(data)) {
...@@ -281,45 +303,47 @@ SaveExp <- function(data, destination = "./", Dates = NULL, coords = NULL, ...@@ -281,45 +303,47 @@ SaveExp <- function(data, destination = "./", Dates = NULL, coords = NULL,
if (is.null(dimnames)) { if (is.null(dimnames)) {
stop("Parameter 'data' must be an array with named dimensions.") stop("Parameter 'data' must be an array with named dimensions.")
} }
if (!is.null(attributes(data)$dimensions)) {
attributes(data)$dimensions <- NULL
}
# destination # destination
if (!is.character(destination) | length(destination) > 1) { if (!is.character(destination) | length(destination) > 1) {
stop("Parameter 'destination' must be a character string of one element ", stop("Parameter 'destination' must be a character string of one element ",
"indicating the name of the file (including the folder if needed) ", "indicating the name of the file (including the folder if needed) ",
"where the data will be saved.") "where the data will be saved.")
} }
# Dates # drop_dims
if (!is.null(Dates)) { if (!is.null(drop_dims)) {
if (!inherits(Dates, "POSIXct") & !inherits(Dates, "Date")) { if (!is.character(drop_dims) | any(!drop_dims %in% names(dim(data)))) {
stop("Parameter 'Dates' must be of 'POSIXct' or 'Dates' class.") warning("Parameter 'drop_dims' must be character string containing ",
} "the data dimension names to be dropped. It will not be used.")
if (is.null(dim(Dates))) { } else if (!all(dim(data)[drop_dims] %in% 1)) {
stop("Parameter 'Dates' must have dimension names.") warning("Parameter 'drop_dims' can only contain dimension names ",
"that are of length 1. It will not be used.")
} else if (any(drop_dims %in% c(ftime_dim, sdate_dim, dat_dim, memb_dim, var_dim))) {
warning("Parameter 'drop_dims' contains dimensions used in the computation. ",
"It will not be used.")
drop_dims <- NULL
} else {
data <- Subset(x = data, along = drop_dims,
indices = lapply(1:length(drop_dims), function(x) 1),
drop = 'selected')
dimnames <- names(dim(data))
} }
} }
# coords # coords
if (!is.null(coords)) { if (!is.null(coords)) {
if (!all(names(coords) %in% dimnames)) { if (!inherits(coords, 'list')) {
coords <- coords[-which(!names(coords) %in% dimnames)] stop("Parameter 'coords' must be a named list of coordinates.")
} }
for (i_coord in dimnames) { if (is.null(names(coords))) {
if (i_coord %in% names(coords)) { stop("Parameter 'coords' must have names corresponding to coordinates.")
if (length(coords[[i_coord]]) != dim(data)[i_coord]) {
warning(paste0("Coordinate '", i_coord, "' has different lenght as ",
"its dimension and it will not be used."))
coords[[i_coord]] <- 1:dim(data)[i_coord]
}
} else {
warning(paste0("Coordinate '", i_coord, "' is not provided ",
"and it will be set as index in element coords."))
coords[[i_coord]] <- 1:dim(data)[i_coord]
}
} }
} else { } else {
coords <- sapply(dimnames, function(x) 1:dim(data)[x]) coords <- sapply(dimnames, function(x) 1:dim(data)[x])
} }
# varname # varname
if (is.null(varname)) { if (is.null(varname)) {
warning("Parameter 'varname' is NULL. It will be assigned to 'X'.")
varname <- 'X' varname <- 'X'
} else if (length(varname) > 1) { } else if (length(varname) > 1) {
multiple_vars <- TRUE multiple_vars <- TRUE
...@@ -330,11 +354,6 @@ SaveExp <- function(data, destination = "./", Dates = NULL, coords = NULL, ...@@ -330,11 +354,6 @@ SaveExp <- function(data, destination = "./", Dates = NULL, coords = NULL,
stop("Parameter 'varname' must be a character string with the ", stop("Parameter 'varname' must be a character string with the ",
"variable names.") "variable names.")
} }
# metadata
if (is.null(metadata)) {
warning("Parameter 'metadata' is not provided so the metadata saved ",
"will be incomplete.")
}
# single_file # single_file
if (!inherits(single_file, 'logical')) { if (!inherits(single_file, 'logical')) {
warning("Parameter 'single_file' must be a logical value. It will be ", warning("Parameter 'single_file' must be a logical value. It will be ",
...@@ -347,27 +366,22 @@ SaveExp <- function(data, destination = "./", Dates = NULL, coords = NULL, ...@@ -347,27 +366,22 @@ SaveExp <- function(data, destination = "./", Dates = NULL, coords = NULL,
stop("Parameter 'extra_string' must be a character string.") stop("Parameter 'extra_string' must be a character string.")
} }
} }
# global_attrs
if (!is.null(global_attrs)) {
if (!inherits(global_attrs, 'list')) {
stop("Parameter 'global_attrs' must be a list.")
}
}
## Dimensions checks ## Dimensions checks
# Spatial coordinates # Spatial coordinates
if (!any(dimnames %in% .KnownLonNames()) | if (!any(dimnames %in% .KnownLonNames()) |
!any(dimnames %in% .KnownLatNames())) { !any(dimnames %in% .KnownLatNames())) {
warning("Spatial coordinates not found.")
lon_dim <- NULL lon_dim <- NULL
lat_dim <- NULL lat_dim <- NULL
} else { } else {
lon_dim <- dimnames[which(dimnames %in% .KnownLonNames())] lon_dim <- dimnames[which(dimnames %in% .KnownLonNames())]
lat_dim <- dimnames[which(dimnames %in% .KnownLatNames())] lat_dim <- dimnames[which(dimnames %in% .KnownLatNames())]
if (length(lon_dim) > 1) {
warning("Found more than one longitudinal dimension. Only the first one ",
"will be used.")
lon_dim <- lon_dim[1]
}
if (length(lat_dim) > 1) {
warning("Found more than one latitudinal dimension. Only the first one ",
"will be used.")
lat_dim <- lat_dim[1]
}
} }
# ftime_dim # ftime_dim
if (!is.null(ftime_dim)) { if (!is.null(ftime_dim)) {
...@@ -375,12 +389,8 @@ SaveExp <- function(data, destination = "./", Dates = NULL, coords = NULL, ...@@ -375,12 +389,8 @@ SaveExp <- function(data, destination = "./", Dates = NULL, coords = NULL,
stop("Parameter 'ftime_dim' must be a character string.") stop("Parameter 'ftime_dim' must be a character string.")
} }
if (!all(ftime_dim %in% dimnames)) { if (!all(ftime_dim %in% dimnames)) {
stop("Parameter 'ftime_dim' is not found in 'data' dimension.") stop("Parameter 'ftime_dim' is not found in 'data' dimension. Set it ",
} "as NULL if there is no forecast time dimension.")
if (length(ftime_dim) > 1) {
warning("Parameter 'ftime_dim' has length greater than 1 and ",
"only the first element will be used.")
ftime_dim <- ftime_dim[1]
} }
} }
# sdate_dim # sdate_dim
...@@ -388,11 +398,6 @@ SaveExp <- function(data, destination = "./", Dates = NULL, coords = NULL, ...@@ -388,11 +398,6 @@ SaveExp <- function(data, destination = "./", Dates = NULL, coords = NULL,
if (!is.character(sdate_dim)) { if (!is.character(sdate_dim)) {
stop("Parameter 'sdate_dim' must be a character string.") stop("Parameter 'sdate_dim' must be a character string.")
} }
if (length(sdate_dim) > 1) {
warning("Parameter 'sdate_dim' has length greater than 1 and ",
"only the first element will be used.")
sdate_dim <- sdate_dim[1]
}
if (!all(sdate_dim %in% dimnames)) { if (!all(sdate_dim %in% dimnames)) {
stop("Parameter 'sdate_dim' is not found in 'data' dimension.") stop("Parameter 'sdate_dim' is not found in 'data' dimension.")
} }
...@@ -416,11 +421,6 @@ SaveExp <- function(data, destination = "./", Dates = NULL, coords = NULL, ...@@ -416,11 +421,6 @@ SaveExp <- function(data, destination = "./", Dates = NULL, coords = NULL,
stop("Parameter 'dat_dim' is not found in 'data' dimension. Set it ", stop("Parameter 'dat_dim' is not found in 'data' dimension. Set it ",
"as NULL if there is no Datasets dimension.") "as NULL if there is no Datasets dimension.")
} }
if (length(dat_dim) > 1) {
warning("Parameter 'dat_dim' has length greater than 1 and ",
"only the first element will be used.")
dat_dim <- dat_dim[1]
}
n_datasets <- dim(data)[dat_dim] n_datasets <- dim(data)[dat_dim]
} else { } else {
n_datasets <- 1 n_datasets <- 1
...@@ -434,11 +434,6 @@ SaveExp <- function(data, destination = "./", Dates = NULL, coords = NULL, ...@@ -434,11 +434,6 @@ SaveExp <- function(data, destination = "./", Dates = NULL, coords = NULL,
stop("Parameter 'var_dim' is not found in 'data' dimension. Set it ", stop("Parameter 'var_dim' is not found in 'data' dimension. Set it ",
"as NULL if there is no variable dimension.") "as NULL if there is no variable dimension.")
} }
if (length(var_dim) > 1) {
warning("Parameter 'var_dim' has length greater than 1 and ",
"only the first element will be used.")
var_dim <- var_dim[1]
}
n_vars <- dim(data)[var_dim] n_vars <- dim(data)[var_dim]
} else { } else {
n_vars <- 1 n_vars <- 1
...@@ -453,30 +448,121 @@ SaveExp <- function(data, destination = "./", Dates = NULL, coords = NULL, ...@@ -453,30 +448,121 @@ SaveExp <- function(data, destination = "./", Dates = NULL, coords = NULL,
single_file <- TRUE single_file <- TRUE
} }
} }
# Dates dimension check # Dates (1): initial checks
if (!is.null(Dates)) { if (!is.null(Dates)) {
if (all(names(dim(Dates)) == c(ftime_dim, sdate_dim)) | if (!any(inherits(Dates, "POSIXct"), inherits(Dates, "Date"))) {
all(names(dim(Dates)) == c(sdate_dim, ftime_dim))) { stop("Parameter 'Dates' must be of 'POSIXct' or 'Dates' class.")
if (is.null(startdates)) { }
startdates <- Subset(Dates, along = ftime_dim, 1, drop = 'selected') if (is.null(dim(Dates))) {
} else if ((!inherits(startdates, "POSIXct") & !inherits(startdates, "Date")) && stop("Parameter 'Dates' must have dimension names.")
(!is.character(startdates) | (any(nchar(startdates) > 10) | any(nchar(startdates) < 1)))) { }
warning("Parameter 'startdates' should be a character string containing ", if (all(is.null(ftime_dim), is.null(sdate_dim))) {
"the start dates in the format 'yyyy-mm-dd', 'yyyymmdd', 'yyyymm', ", warning("Parameters 'ftime_dim' and 'sdate_dim' can't both be NULL ",
"'POSIXct' or 'Dates' class. Files will be named with Dates instead.") "if 'Dates' are used. 'Dates' will not be used.")
startdates <- Subset(Dates, along = ftime_dim, 1, drop = 'selected') Dates <- NULL
if (!is.null(format(startdates, "%Y%m%d"))) { }
startdates <- format(startdates, "%Y%m%d") # sdate_dim in Dates
} if (!is.null(sdate_dim)) {
if (!sdate_dim %in% names(dim(Dates))) {
warning("Parameter 'sdate_dim' is not found in 'Dates' dimension. ",
"Dates will not be used.")
Dates <- NULL
}
}
# ftime_dim in Dates
if (!is.null(ftime_dim)) {
if (!ftime_dim %in% names(dim(Dates))) {
warning("Parameter 'ftime_dim' is not found in 'Dates' dimension. ",
"Dates will not be used.")
Dates <- NULL
} }
} else if (all(dim(Dates)[!names(dim(Dates)) %in% c(ftime_dim, sdate_dim)] == 1)) { }
dim(Dates) <- dim(Dates)[names(dim(Dates)) %in% c(ftime_dim, sdate_dim)] }
# time_bounds
if (!is.null(time_bounds)) {
if (!inherits(time_bounds, 'list')) {
stop("Parameter 'time_bounds' must be a list with two dates arrays.")
}
time_bounds_dims <- lapply(time_bounds, function(x) dim(x))
if (!identical(time_bounds_dims[[1]], time_bounds_dims[[2]])) {
stop("Parameter 'time_bounds' must have 2 arrays with same dimensions.")
}
if (is.null(Dates)) {
time_bounds <- NULL
} else { } else {
stop("Parameter 'Dates' must have start date dimension and ", name_tb <- sort(names(time_bounds_dims[[1]]))
"forecast time dimension.") name_dt <- sort(names(dim(Dates)))
if (!identical(dim(Dates)[name_dt], time_bounds_dims[[1]][name_tb])) {
stop(paste0("Parameter 'Dates' and 'time_bounds' must have same length ",
"of all dimensions."))
}
}
}
# Dates (2): Check dimensions
if (!is.null(Dates)) {
if (any(dim(Dates)[!names(dim(Dates)) %in% c(ftime_dim, sdate_dim)] != 1)) {
stop("Parameter 'Dates' can have only 'sdate_dim' and 'ftime_dim' ",
"dimensions of length greater than 1.")
}
# drop dimensions of length 1 different from sdate_dim and ftime_dim
dim(Dates) <- dim(Dates)[names(dim(Dates)) %in% c(ftime_dim, sdate_dim)]
# add ftime if needed
if (is.null(ftime_dim)) {
warning("A 'time' dimension of length 1 will be added to 'Dates'.")
dim(Dates) <- c(time = 1, dim(Dates))
dim(data) <- c(time = 1, dim(data))
dimnames <- names(dim(data))
ftime_dim <- 'time'
if (!is.null(time_bounds)) {
time_bounds <- lapply(time_bounds, function(x) {
dim(x) <- c(time = 1, dim(x))
return(x)
})
}
units_hours_since <- TRUE
}
# add sdate if needed
if (is.null(sdate_dim)) {
if (!single_file) {
dim(Dates) <- c(dim(Dates), sdate = 1)
dim(data) <- c(dim(data), sdate = 1)
dimnames <- names(dim(data))
sdate_dim <- 'sdate'
if (!is.null(time_bounds)) {
time_bounds <- lapply(time_bounds, function(x) {
dim(x) <- c(dim(x), sdate = 1)
return(x)
})
}
if (!is.null(startdates)) {
if (length(startdates) != 1) {
warning("Parameter 'startdates' must be of length 1 if 'sdate_dim' is NULL.",
"They won't be used.")
startdates <- NULL
}
}
}
units_hours_since <- TRUE
} }
} }
# startdates # startdates
if (!is.null(Dates)) {
# check startdates
if (is.null(startdates)) {
startdates <- Subset(Dates, along = ftime_dim, 1, drop = 'selected')
} else if (any(nchar(startdates) > 10, nchar(startdates) < 1)) {
warning("Parameter 'startdates' should be a character string containing ",
"the start dates in the format 'yyyy-mm-dd', 'yyyymmdd', 'yyyymm', ",
"'POSIXct' or 'Dates' class. Files will be named with Dates instead.")
startdates <- Subset(Dates, along = ftime_dim, 1, drop = 'selected')
}
} else if (!single_file) {
warning("Dates must be provided if 'data' must be saved in separated files. ",
"All data will be saved in a single file.")
single_file <- TRUE
}
# startdates
if (is.null(startdates)) { if (is.null(startdates)) {
if (is.null(sdate_dim)) { if (is.null(sdate_dim)) {
startdates <- 'XXX' startdates <- 'XXX'
...@@ -484,20 +570,21 @@ SaveExp <- function(data, destination = "./", Dates = NULL, coords = NULL, ...@@ -484,20 +570,21 @@ SaveExp <- function(data, destination = "./", Dates = NULL, coords = NULL,
startdates <- rep('XXX', dim(data)[sdate_dim]) startdates <- rep('XXX', dim(data)[sdate_dim])
} }
} else { } else {
if (is.null(sdate_dim)) { if (any(inherits(startdates, "POSIXct"), inherits(startdates, "Date"))) {
if (length(startdates) != 1) { startdates <- format(startdates, "%Y%m%d")
warning("Parameter 'startdates' has length more than 1. Only first ", }
"value will be used.") if (!is.null(sdate_dim)) {
startdates <- startdates[[1]] if (dim(data)[sdate_dim] != length(startdates)) {
warning(paste0("Parameter 'startdates' doesn't have the same length ",
"as dimension '", sdate_dim,"', it will not be used."))
startdates <- Subset(Dates, along = ftime_dim, 1, drop = 'selected')
startdates <- format(startdates, "%Y%m%d")
} }
} }
} }
# Datasets # Datasets
if (is.null(Datasets)) { if (is.null(Datasets)) {
if (!single_file) {
warning("Parameter 'Datasets' is NULL. Files will be saved with a ",
"directory name of 'XXX'.")
}
Datasets <- rep('XXX', n_datasets ) Datasets <- rep('XXX', n_datasets )
} }
if (inherits(Datasets, 'list')) { if (inherits(Datasets, 'list')) {
...@@ -513,128 +600,74 @@ SaveExp <- function(data, destination = "./", Dates = NULL, coords = NULL, ...@@ -513,128 +600,74 @@ SaveExp <- function(data, destination = "./", Dates = NULL, coords = NULL,
Datasets <- Datasets[1:n_datasets] Datasets <- Datasets[1:n_datasets]
} }
## NetCDF dimensions definition
excluded_dims <- var_dim
if (!is.null(Dates)) {
excluded_dims <- c(excluded_dims, sdate_dim, ftime_dim)
}
if (!single_file) {
excluded_dims <- c(excluded_dims, dat_dim)
}
## Unknown dimensions check ## Unknown dimensions check
alldims <- c(dat_dim, var_dim, sdate_dim, lon_dim, lat_dim, memb_dim, ftime_dim) alldims <- c(dat_dim, var_dim, sdate_dim, lon_dim, lat_dim, ftime_dim, memb_dim)
if (!all(dimnames %in% alldims)) { if (!all(dimnames %in% alldims)) {
unknown_dims <- dimnames[which(!dimnames %in% alldims)] unknown_dims <- dimnames[which(!dimnames %in% alldims)]
# warning("Detected unknown dimension: ", paste(unknown_dims, collapse = ', '))
memb_dim <- c(memb_dim, unknown_dims) memb_dim <- c(memb_dim, unknown_dims)
alldims <- c(dat_dim, var_dim, sdate_dim, lon_dim, lat_dim, memb_dim, ftime_dim)
}
# Reorder
if (any(dimnames != alldims)) {
data <- Reorder(data, alldims)
dimnames <- names(dim(data))
if (!is.null(attr(data, 'dimensions'))) {
attr(data, 'dimensions') <- dimnames
}
} }
## NetCDF dimensions definition filedims <- c(dat_dim, var_dim, sdate_dim, lon_dim, lat_dim, ftime_dim, memb_dim)
defined_dims <- NULL filedims <- filedims[which(!filedims %in% excluded_dims)]
extra_info_dim <- NULL
if (is.null(Dates)) { # Delete unneded coords
filedims <- dimnames[which(!dimnames %in% c(dat_dim, var_dim))] coords[c(names(coords)[!names(coords) %in% filedims])] <- NULL
} else { out_coords <- NULL
filedims <- dimnames[which(!dimnames %in% c(dat_dim, var_dim, sdate_dim, ftime_dim))]
}
for (i_coord in filedims) { for (i_coord in filedims) {
dim_info <- list()
# vals # vals
if (i_coord %in% names(coords)) { if (i_coord %in% names(coords)) {
if (is.numeric(coords[[i_coord]])) { if (length(coords[[i_coord]]) != dim(data)[i_coord]) {
dim_info[['vals']] <- as.vector(coords[[i_coord]]) warning(paste0("Coordinate '", i_coord, "' has different lenght as ",
"its dimension and it will not be used."))
out_coords[[i_coord]] <- 1:dim(data)[i_coord]
} else if (is.numeric(coords[[i_coord]])) {
out_coords[[i_coord]] <- as.vector(coords[[i_coord]])
} else { } else {
dim_info[['vals']] <- 1:dim(data)[i_coord] out_coords[[i_coord]] <- 1:dim(data)[i_coord]
} }
} else { } else {
dim_info[['vals']] <- 1:dim(data)[i_coord] out_coords[[i_coord]] <- 1:dim(data)[i_coord]
} }
# name dim(out_coords[[i_coord]]) <- dim(data)[i_coord]
dim_info[['name']] <- i_coord
# len
dim_info[['len']] <- as.numeric(dim(data)[i_coord])
# unlim
dim_info[['unlim']] <- FALSE
# create_dimvar
dim_info[['create_dimvar']] <- TRUE
## metadata ## metadata
if (i_coord %in% names(metadata)) { if (i_coord %in% names(metadata)) {
if ('variables' %in% names(attributes(metadata[[i_coord]]))) { if ('variables' %in% names(attributes(metadata[[i_coord]]))) {
# from Start: 'lon' or 'lat' # from Start: 'lon' or 'lat'
attrs <- attributes(metadata[[i_coord]])[['variables']][[i_coord]] attrs <- attributes(metadata[[i_coord]])[['variables']]
i_coord_info <- attrs[!sapply(attrs, inherits, 'list')] attrs[[i_coord]]$dim <- NULL
attr(out_coords[[i_coord]], 'variables') <- attrs
} else if (inherits(metadata[[i_coord]], 'list')) { } else if (inherits(metadata[[i_coord]], 'list')) {
# from Start and Load: main var # from Start and Load: main var
i_coord_info <- metadata[[i_coord]] attr(out_coords[[i_coord]], 'variables') <- list(metadata[[i_coord]])
names(attributes(out_coords[[i_coord]])$variables) <- i_coord
} else if (!is.null(attributes(metadata[[i_coord]]))) { } else if (!is.null(attributes(metadata[[i_coord]]))) {
# from Load # from Load
i_coord_info <- attributes(metadata[[i_coord]]) attrs <- attributes(metadata[[i_coord]])
} else { # We remove because some attributes can't be saved
stop("Metadata is not correct.") attrs <- NULL
attr(out_coords[[i_coord]], 'variables') <- list(attrs)
names(attributes(out_coords[[i_coord]])$variables) <- i_coord
} }
# len }
if ('size' %in% names(i_coord_info)) {
if (i_coord_info[['size']] != dim(data)[i_coord]) {
dim_info[['original_len']] <- i_coord_info[['size']]
i_coord_info[['size']] <- NULL
}
}
# units
if (!('units' %in% names(i_coord_info))) {
dim_info[['units']] <- ''
} else {
dim_info[['units']] <- i_coord_info[['units']]
i_coord_info[['units']] <- NULL
}
# calendar
if (!('calendar' %in% names(i_coord_info))) {
dim_info[['calendar']] <- NA
} else {
dim_info[['calendar']] <- i_coord_info[['calendar']]
i_coord_info[['calendar']] <- NULL
}
# longname
if ('long_name' %in% names(i_coord_info)) {
dim_info[['longname']] <- i_coord_info[['long_name']]
i_coord_info[['long_name']] <- NULL
} else if ('longname' %in% names(i_coord_info)) {
dim_info[['longname']] <- i_coord_info[['longname']]
i_coord_info[['longname']] <- NULL
} else {
if (i_coord %in% .KnownLonNames()) {
dim_info[['longname']] <- 'longitude'
} else if (i_coord %in% .KnownLatNames()) {
dim_info[['longname']] <- 'latitude'
}
}
# extra information
if (!is.null(names(i_coord_info))) {
extra_info_dim[[i_coord]] <- i_coord_info
}
} else {
# units
dim_info[['units']] <- "adim"
# longname
dim_info[['longname']] <- i_coord
# calendar
dim_info[['calendar']] <- NA
}
new_dim <- list(ncdim_def(name = dim_info[['name']], units = dim_info[['units']],
vals = dim_info[['vals']], unlim = dim_info[['unlim']],
create_dimvar = dim_info[['create_dimvar']],
calendar = dim_info[['calendar']],
longname = dim_info[['longname']]))
names(new_dim) <- i_coord
defined_dims <- c(defined_dims, new_dim)
} }
defined_vars <- list()
if (!single_file) { if (!single_file) {
for (i in 1:n_datasets) { for (i in 1:n_datasets) {
path <- file.path(destination, Datasets[i], varname) path <- file.path(destination, Datasets[i], varname)
for (j in 1:n_vars) { for (j in 1:n_vars) {
dir.create(path[j], recursive = TRUE) if (!dir.exists(path[j])) {
dir.create(path[j], recursive = TRUE)
}
startdates <- gsub("-", "", startdates) startdates <- gsub("-", "", startdates)
dim(startdates) <- c(length(startdates)) dim(startdates) <- c(length(startdates))
names(dim(startdates)) <- sdate_dim names(dim(startdates)) <- sdate_dim
...@@ -647,293 +680,240 @@ SaveExp <- function(data, destination = "./", Dates = NULL, coords = NULL, ...@@ -647,293 +680,240 @@ SaveExp <- function(data, destination = "./", Dates = NULL, coords = NULL,
} else { } else {
data_subset <- Subset(data, c(dat_dim, var_dim), list(i, j), drop = 'selected') data_subset <- Subset(data, c(dat_dim, var_dim), list(i, j), drop = 'selected')
} }
target <- names(dim(data_subset))[which(!names(dim(data_subset)) %in% c(sdate_dim, ftime_dim))]
target_dims_data <- c(target, ftime_dim)
if (is.null(Dates)) { if (is.null(Dates)) {
input_data <- list(data_subset, startdates) input_data <- list(data_subset, startdates)
target_dims <- list(c(lon_dim, lat_dim, memb_dim, ftime_dim), NULL) target_dims <- list(target_dims_data, NULL)
} else if (!is.null(time_bounds)) {
input_data <- list(data_subset, startdates, Dates,
time_bounds[[1]], time_bounds[[2]])
target_dims = list(target_dims_data, NULL,
ftime_dim, ftime_dim, ftime_dim)
} else { } else {
input_data <- list(data_subset, startdates, Dates) input_data <- list(data_subset, startdates, Dates)
target_dims = list(c(lon_dim, lat_dim, memb_dim, ftime_dim), NULL, ftime_dim) target_dims = list(target_dims_data, NULL, ftime_dim)
} }
Apply(data = input_data, Apply(data = input_data,
target_dims = target_dims, target_dims = target_dims,
fun = .saveExp, fun = .saveexp,
destination = path[j], destination = path[j],
defined_dims = defined_dims, coords = out_coords,
ftime_dim = ftime_dim, ftime_dim = ftime_dim,
varname = varname[j], varname = varname[j],
metadata_var = metadata[[varname[j]]], metadata_var = metadata[[varname[j]]],
extra_info_dim = extra_info_dim, extra_string = extra_string,
extra_string = extra_string) global_attrs = global_attrs)
} }
} }
} else { } else {
# Datasets definition # time_bnds
# From here if (!is.null(time_bounds)) {
if (!is.null(dat_dim)) { time_bnds <- c(time_bounds[[1]], time_bounds[[2]])
new_dim <- list(ncdim_def(name = dat_dim, units = "adim", }
vals = 1 : dim(data)[dat_dim], # Dates
longname = 'Datasets', create_dimvar = TRUE)) remove_metadata_dim <- TRUE
names(new_dim) <- dat_dim
defined_dims <- c(new_dim, defined_dims)
extra_info_dim[[dat_dim]] <- list(Datasets = paste(Datasets, collapse = ', '))
}
first_sdate <- last_sdate <- NULL
if (!is.null(Dates)) { if (!is.null(Dates)) {
# sdate definition if (is.null(sdate_dim)) {
sdates <- Subset(Dates, along = ftime_dim, 1, drop = 'selected') sdates <- Dates[1]
differ <- as.numeric((sdates - sdates[1])/3600) # ftime definition
new_dim <- list(ncdim_def(name = sdate_dim, units = paste('hours since', sdates[1]), leadtimes <- as.numeric(difftime(Dates, sdates, units = "hours"))
vals = differ, } else {
longname = sdate_dim, create_dimvar = TRUE)) # sdate definition
names(new_dim) <- sdate_dim sdates <- Subset(Dates, along = ftime_dim, 1, drop = 'selected')
defined_dims <- c(defined_dims, new_dim) differ <- as.numeric(difftime(sdates, sdates[1], units = "hours"))
first_sdate <- sdates[1] dim(differ) <- dim(data)[sdate_dim]
last_sdate <- sdates[length(sdates)] differ <- list(differ)
# ftime definition names(differ) <- sdate_dim
Dates <- Reorder(Dates, c(ftime_dim, sdate_dim)) out_coords <- c(differ, out_coords)
differ_ftime <- apply(Dates, 2, function(x){as.numeric((x - x[1])/3600)}) attrs <- list(units = paste('hours since', sdates[1]),
dim(differ_ftime) <- dim(Dates) calendar = 'proleptic_gregorian', longname = sdate_dim)
differ_ftime_subset <- Subset(differ_ftime, along = sdate_dim, 1, drop = 'selected') attr(out_coords[[sdate_dim]], 'variables')[[sdate_dim]] <- attrs
if (all(apply(differ_ftime, 1, function(x){length(unique(x)) == 1}))) { # ftime definition
if (all(diff(differ_ftime_subset/24) == 1)) { Dates <- Reorder(Dates, c(ftime_dim, sdate_dim))
differ_ftime <- array(dim = dim(Dates))
for (i in 1:length(sdates)) {
differ_ftime[, i] <- as.numeric(difftime(Dates[, i], Dates[1, i],
units = "hours"))
}
dim(differ_ftime) <- dim(Dates)
leadtimes <- Subset(differ_ftime, along = sdate_dim, 1, drop = 'selected')
if (!all(apply(differ_ftime, 1, function(x){length(unique(x)) == 1}))) {
warning("Time steps are not equal for all start dates. Only ",
"forecast time values for the first start date will be saved ",
"correctly.")
}
}
if (all(!units_hours_since, is.null(time_bounds))) {
if (all(diff(leadtimes/24) == 1)) {
# daily values # daily values
dim_time <- list(ncdim_def(name = ftime_dim, units = 'days', units <- 'days'
vals = round(differ_ftime_subset/24) + 1, leadtimes_vals <- round(leadtimes/24) + 1
calendar = 'proleptic_gregorian', } else if (all(diff(leadtimes/24) %in% c(28, 29, 30, 31))) {
longname = ftime_dim, unlim = TRUE))
names(dim_time) <- ftime_dim
defined_dims <- c(defined_dims, dim_time)
} else if (all(diff(differ_ftime_subset/24) %in% c(28, 29, 30, 31))) {
# monthly values # monthly values
dim_time <- list(ncdim_def(name = ftime_dim, units = 'months', units <- 'months'
vals = round(differ_ftime_subset/730) + 1, leadtimes_vals <- round(leadtimes/(30.437*24)) + 1
calendar = 'proleptic_gregorian',
longname = ftime_dim, unlim = TRUE))
names(dim_time) <- ftime_dim
defined_dims <- c(defined_dims, dim_time)
} else { } else {
# other frequency # other frequency
dim_time <- list(ncdim_def(name = ftime_dim, units = 'hours', units <- 'hours'
vals = differ_ftime_subset + 1, leadtimes_vals <- leadtimes + 1
calendar = 'proleptic_gregorian',
longname = ftime_dim, unlim = TRUE))
names(dim_time) <- ftime_dim
defined_dims <- c(defined_dims, dim_time)
} }
} else { } else {
warning("Time steps are not equal for all start dates. Only ", units <- paste('hours since', paste(sdates, collapse = ', '))
"forecast time values for the first start date will be saved ", leadtimes_vals <- leadtimes
"correctly.")
dim_time <- list(ncdim_def(name = ftime_dim,
units = paste('hours since',
paste(sdates, collapse = ', ')),
vals = differ_ftime_subset,
calendar = 'proleptic_gregorian',
longname = ftime_dim, unlim = TRUE))
names(dim_time) <- ftime_dim
defined_dims <- c(defined_dims, dim_time)
} }
}
# Add time_bnds
if (!is.null(time_bounds)) {
if (is.null(sdate_dim)) {
sdates <- Dates[1]
time_bnds <- c(time_bounds[[1]], time_bounds[[2]])
leadtimes_bnds <- as.numeric(difftime(time_bnds, sdates, units = "hours"))
dim(leadtimes_bnds) <- c(dim(Dates), bnds = 2)
} else {
# assuming they have sdate and ftime
time_bnds <- lapply(time_bounds, function(x) {
x <- Reorder(x, c(ftime_dim, sdate_dim))
return(x)
})
time_bnds <- c(time_bounds[[1]], time_bounds[[2]])
dim(time_bnds) <- c(dim(Dates), bnds = 2)
differ_bnds <- array(dim = c(dim(time_bnds)))
for (i in 1:length(sdates)) {
differ_bnds[, i, ] <- as.numeric(difftime(time_bnds[, i, ], Dates[1, i],
units = "hours"))
}
# NOTE (TODO): Add a warning when they are not equally spaced?
leadtimes_bnds <- Subset(differ_bnds, along = sdate_dim, 1, drop = 'selected')
}
# Add time_bnds
leadtimes_bnds <- Reorder(leadtimes_bnds, c('bnds', ftime_dim))
leadtimes_bnds <- list(leadtimes_bnds)
names(leadtimes_bnds) <- 'time_bnds'
out_coords <- c(leadtimes_bnds, out_coords)
attrs <- list(units = paste('hours since', paste(sdates, collapse = ', ')),
calendar = 'proleptic_gregorian',
long_name = 'time bounds', unlim = FALSE)
attr(out_coords[['time_bnds']], 'variables')$time_bnds <- attrs
}
# Add ftime var
dim(leadtimes_vals) <- dim(data)[ftime_dim]
leadtimes_vals <- list(leadtimes_vals)
names(leadtimes_vals) <- ftime_dim
out_coords <- c(leadtimes_vals, out_coords)
attrs <- list(units = units, calendar = 'proleptic_gregorian',
longname = ftime_dim,
dim = list(list(name = ftime_dim, unlim = TRUE)))
if (!is.null(time_bounds)) {
attrs$bounds = 'time_bnds'
}
attr(out_coords[[ftime_dim]], 'variables')[[ftime_dim]] <- attrs
for (j in 1:n_vars) {
remove_metadata_dim <- FALSE
metadata[[varname[j]]]$dim <- list(list(name = ftime_dim, unlim = TRUE))
}
# Reorder ftime_dim to last
if (length(dim(data)) != which(names(dim(data)) == ftime_dim)) {
order <- c(names(dim(data))[which(!names(dim(data)) %in% c(ftime_dim))], ftime_dim)
data <- Reorder(data, order)
}
}
# var definition # var definition
defined_vars <- list()
extra_info_var <- NULL extra_info_var <- NULL
for (j in 1:n_vars) { for (j in 1:n_vars) {
var_info <- list() varname_j <- varname[j]
i_var_info <- metadata[[varname[j]]][!sapply(metadata[[varname[j]]], inherits, 'list')] metadata_j <- metadata[[varname_j]]
## Define metadata if (is.null(var_dim)) {
# name out_coords[[varname_j]] <- data
var_info[['name']] <- varname[j]
# units
if ('units' %in% names(i_var_info)) {
var_info[['units']] <- i_var_info[['units']]
i_var_info[['units']] <- NULL
} else { } else {
var_info[['units']] <- '' out_coords[[varname_j]] <- Subset(data, var_dim, j, drop = 'selected')
} }
# dim if (!is.null(metadata_j)) {
var_info[['dim']] <- defined_dims if (remove_metadata_dim) metadata_j$dim <- NULL
# missval attr(out_coords[[varname_j]], 'variables') <- list(metadata_j)
if ('missval' %in% names(i_var_info)) { names(attributes(out_coords[[varname_j]])$variables) <- varname_j
var_info[['missval']] <- i_var_info[['missval']]
i_var_info[['missval']] <- NULL
} else {
var_info[['missval']] <- NULL
} }
# longname # Add global attributes
if (any(c('longname', 'long_name') %in% names(i_var_info))) { if (!is.null(global_attrs)) {
longname <- names(i_var_info)[which(names(i_var_info) %in% c('longname', 'long_name'))] attributes(out_coords[[varname_j]])$global_attrs <- global_attrs
var_info[['longname']] <- i_var_info[[longname]]
i_var_info[[longname]] <- NULL
} else {
var_info[['longname']] <- varname[j]
} }
# prec
if ('prec' %in% names(i_var_info)) {
var_info[['prec']] <- i_var_info[['prec']]
i_var_info[['prec']] <- NULL
} else {
prec <- typeof(data)
if (prec == 'character') {
var_info[['prec']] <- 'char'
}
if (any(prec %in% c('short', 'float', 'double', 'integer', 'char', 'byte'))) {
var_info[['prec']] <- prec
} else {
var_info[['prec']] <- 'double'
}
}
# extra information
if (!is.null(names(i_var_info))) {
extra_info_var[[varname[j]]] <- i_var_info
}
new_var <- list(ncvar_def(name = var_info[['name']],
units = var_info[['units']],
dim = var_info[['dim']],
missval = var_info[['missval']],
longname = var_info[['longname']],
prec = var_info[['prec']]))
names(new_var) <- varname[j]
defined_vars <- c(defined_vars, new_var)
} }
if (is.null(extra_string)) { if (is.null(extra_string)) {
first_sdate <- startdates[1]
last_sdate <- startdates[length(startdates)]
gsub("-", "", first_sdate) gsub("-", "", first_sdate)
file_name <- paste0(paste(c(varname, file_name <- paste0(paste(c(varname,
gsub("-", "", first_sdate), gsub("-", "", first_sdate),
gsub("-", "", last_sdate)), gsub("-", "", last_sdate)),
collapse = '_'), ".nc") collapse = '_'), ".nc")
} else { } else {
file_name <- paste0(paste(c(varname, extra_string, nc <- substr(extra_string, nchar(extra_string)-2, nchar(extra_string))
gsub("-", "", first_sdate), if (nc == ".nc") {
gsub("-", "", last_sdate)), file_name <- extra_string
collapse = '_'), ".nc") } else {
} file_name <- paste0(extra_string, ".nc")
full_filename <- file.path(destination, file_name)
file_nc <- nc_create(full_filename, defined_vars)
if (is.null(var_dim)) {
ncvar_put(file_nc, varname, vals = data)
} else {
for (j in 1:n_vars) {
ncvar_put(file_nc, defined_vars[[j]]$name,
vals = Subset(data, var_dim, j, drop = 'selected'))
}
}
# Additional dimension attributes
for (dim in names(defined_dims)) {
if (dim %in% names(extra_info_dim)) {
for (info_dim in names(extra_info_dim[[dim]])) {
ncatt_put(file_nc, dim, info_dim, as.character(extra_info_dim[[dim]][[info_dim]]))
}
}
}
# Additional dimension attributes
for (var in names(defined_vars)) {
if (var %in% names(extra_info_var)) {
for (info_var in names(extra_info_var[[var]])) {
ncatt_put(file_nc, var, info_var, as.character(extra_info_var[[var]][[info_var]]))
}
} }
} }
nc_close(file_nc) full_filename <- file.path(destination, file_name)
ArrayToNc(out_coords, full_filename)
} }
} }
.saveExp <- function(data, startdates = NULL, dates = NULL, destination = "./", .saveexp <- function(data, coords, destination = "./",
defined_dims, ftime_dim = 'time', varname = 'var', startdates = NULL, dates = NULL,
metadata_var = NULL, extra_info_dim = NULL, time_bnds1 = NULL, time_bnds2 = NULL,
extra_string = NULL) { ftime_dim = 'time', varname = 'var',
# ftime_dim metadata_var = NULL, extra_string = NULL,
global_attrs = NULL) {
remove_metadata_dim <- TRUE
if (!is.null(dates)) { if (!is.null(dates)) {
differ <- as.numeric((dates - dates[1])/3600) if (!any(is.null(time_bnds1), is.null(time_bnds2))) {
dim_time <- list(ncdim_def(name = ftime_dim, units = paste('hours since', dates[1]), time_bnds <- c(time_bnds1, time_bnds2)
vals = differ, calendar = 'proleptic_gregorian', time_bnds <- as.numeric(difftime(time_bnds, dates[1], units = "hours"))
longname = ftime_dim, unlim = TRUE)) dim(time_bnds) <- c(dim(data)[ftime_dim], bnds = 2)
names(dim_time) <- ftime_dim time_bnds <- Reorder(time_bnds, c('bnds', ftime_dim))
defined_dims <- c(defined_dims, dim_time) time_bnds <- list(time_bnds)
names(time_bnds) <- 'time_bnds'
coords <- c(time_bnds, coords)
attrs <- list(units = paste('hours since', dates[1]),
calendar = 'proleptic_gregorian',
longname = 'time bounds')
attr(coords[['time_bnds']], 'variables')$time_bnds <- attrs
}
# Add ftime_dim
differ <- as.numeric(difftime(dates, dates[1], units = "hours"))
dim(differ) <- dim(data)[ftime_dim]
differ <- list(differ)
names(differ) <- ftime_dim
coords <- c(differ, coords)
attrs <- list(units = paste('hours since', dates[1]),
calendar = 'proleptic_gregorian',
longname = ftime_dim,
dim = list(list(name = ftime_dim, unlim = TRUE)))
if (!is.null(time_bnds1)) {
attrs$bounds = 'time_bnds'
}
attr(coords[[ftime_dim]], 'variables')[[ftime_dim]] <- attrs
metadata_var$dim <- list(list(name = ftime_dim, unlim = TRUE))
remove_metadata_dim <- FALSE
}
# Add data
coords[[varname]] <- data
if (!is.null(metadata_var)) {
if (remove_metadata_dim) metadata_var$dim <- NULL
attr(coords[[varname]], 'variables') <- list(metadata_var)
names(attributes(coords[[varname]])$variables) <- varname
}
# Add global attributes
if (!is.null(global_attrs)) {
attributes(coords[[varname]])$global_attrs <- global_attrs
} }
## Define var metadata
var_info <- NULL
extra_info_var <- NULL
i_var_info <- metadata_var[!sapply(metadata_var, inherits, 'list')]
# name
var_info[['name']] <- varname
# units
if ('units' %in% names(i_var_info)) {
var_info[['units']] <- i_var_info[['units']]
i_var_info[['units']] <- NULL
} else {
var_info[['units']] <- ''
}
# dim
var_info[['dim']] <- defined_dims
# missval
if ('missval' %in% names(i_var_info)) {
var_info[['missval']] <- i_var_info[['missval']]
i_var_info[['missval']] <- NULL
} else {
var_info[['missval']] <- NULL
}
# longname
if (any(c('longname', 'long_name') %in% names(i_var_info))) {
longname <- names(i_var_info)[which(names(i_var_info) %in% c('longname', 'long_name'))]
var_info[['longname']] <- i_var_info[[longname]]
i_var_info[[longname]] <- NULL
} else {
var_info[['longname']] <- varname
}
# prec
if ('prec' %in% names(i_var_info)) {
var_info[['prec']] <- i_var_info[['prec']]
i_var_info[['prec']] <- NULL
} else {
prec <- typeof(data)
if (prec == 'character') {
var_info[['prec']] <- 'char'
}
if (any(prec %in% c('short', 'float', 'double', 'integer', 'char', 'byte'))) {
var_info[['prec']] <- prec
} else {
var_info[['prec']] <- 'double'
}
}
# extra information
if (!is.null(names(i_var_info))) {
extra_info_var <- i_var_info
}
datanc <- ncvar_def(name = var_info[['name']],
units = var_info[['units']],
dim = var_info[['dim']],
missval = var_info[['missval']],
longname = var_info[['longname']],
prec = var_info[['prec']])
if (is.null(extra_string)) { if (is.null(extra_string)) {
file_name <- paste0(varname, "_", startdates, ".nc") file_name <- paste0(varname, "_", startdates, ".nc")
} else { } else {
file_name <- paste0(varname, "_", extra_string, "_", startdates, ".nc") file_name <- paste0(varname, "_", extra_string, "_", startdates, ".nc")
} }
full_filename <- file.path(destination, file_name) full_filename <- file.path(destination, file_name)
file_nc <- nc_create(full_filename, datanc) ArrayToNc(coords, full_filename)
ncvar_put(file_nc, datanc, data) }
\ No newline at end of file
# Additional attributes
for (dim in names(defined_dims)) {
if (dim %in% names(extra_info_dim)) {
for (info_dim in names(extra_info_dim[[dim]])) {
ncatt_put(file_nc, dim, info_dim, as.character(extra_info_dim[[dim]][[info_dim]]))
}
}
}
# Additional dimension attributes
if (!is.null(extra_info_var)) {
for (info_var in names(extra_info_var)) {
ncatt_put(file_nc, varname, info_var, as.character(extra_info_var[[info_var]]))
}
}
nc_close(file_nc)
}
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
#' #'
#'@param data A 's2dv_cube' object #'@param data A 's2dv_cube' object
#'@param split_dim A character string indicating the name of the dimension to #'@param split_dim A character string indicating the name of the dimension to
#' split. #' split. It is set as 'time' by default.
#'@param indices A vector of numeric indices or dates. If left at NULL, the #'@param indices A vector of numeric indices or dates. If left at NULL, the
#' dates provided in the s2dv_cube object (element Dates) will be used. #' dates provided in the s2dv_cube object (element Dates) will be used.
#'@param freq A character string indicating the frequency: by 'day', 'month' and #'@param freq A character string indicating the frequency: by 'day', 'month' and
...@@ -21,6 +21,12 @@ ...@@ -21,6 +21,12 @@
#' dimension. #' dimension.
#'@param insert_ftime An integer indicating the number of time steps to add at #'@param insert_ftime An integer indicating the number of time steps to add at
#' the begining of the time series. #' the begining of the time series.
#'@param ftime_dim A character string indicating the name of the forecast time
#' dimension. It is set as 'time' by default.
#'@param sdate_dim A character string indicating the name of the start date
#' dimension. It is set as 'sdate' by default.
#'@param return_indices A logical value that if it is TRUE, the indices
#' used in splitting the dimension will be returned. It is FALSE by default.
#' #'
#'@details Parameter 'insert_ftime' has been included for the case of using #'@details Parameter 'insert_ftime' has been included for the case of using
#'daily data, requiring split the temporal dimensions by months (or similar) and #'daily data, requiring split the temporal dimensions by months (or similar) and
...@@ -51,63 +57,97 @@ ...@@ -51,63 +57,97 @@
#'new_data <- CST_SplitDim(data, indices = time, freq = 'year') #'new_data <- CST_SplitDim(data, indices = time, freq = 'year')
#'@import abind #'@import abind
#'@importFrom ClimProjDiags Subset #'@importFrom ClimProjDiags Subset
#'@importFrom s2dv Reorder
#'@export #'@export
CST_SplitDim <- function(data, split_dim = 'time', indices = NULL, CST_SplitDim <- function(data, split_dim = 'time', indices = NULL,
freq = 'monthly', new_dim_name = NULL, freq = 'monthly', new_dim_name = NULL,
insert_ftime = NULL) { insert_ftime = NULL, ftime_dim = 'time',
sdate_dim = 'sdate', return_indices = FALSE) {
# Check 's2dv_cube' # Check 's2dv_cube'
if (!inherits(data, 's2dv_cube')) { if (!inherits(data, 's2dv_cube')) {
stop("Parameter 'data' must be of the class 's2dv_cube', ", stop("Parameter 'data' must be of the class 's2dv_cube'.")
"as output by CSTools::CST_Load.")
} }
if (!is.null(insert_ftime)) { if (!is.null(insert_ftime)) {
if (!is.numeric(insert_ftime)) { if (!is.numeric(insert_ftime)) {
stop("Parameter 'insert_ftime' should be an integer.") stop("Parameter 'insert_ftime' should be an integer.")
}
if (length(insert_ftime) > 1) {
warning("Parameter 'insert_ftime' must be of length 1, and only the",
" first element will be used.")
insert_ftime <- insert_ftime[1]
}
# Check Dates
if (is.null(dim(data$attrs$Dates))) {
warning("Parameter 'Dates' must have dimensions, 'insert_ftime' won't ",
"be used.")
insert_ftime <- NULL
}
}
if (!is.null(insert_ftime)) {
# adding NAs at the begining of the data in ftime dim
ftimedim <- which(names(dim(data$data)) == ftime_dim)
dims <- dim(data$data)
dims[ftimedim] <- insert_ftime
empty_array <- array(NA, dims)
data$data <- abind(empty_array, data$data, along = ftimedim)
names(dim(data$data)) <- names(dims)
# Reorder dates
data$attrs$Dates <- Reorder(data$attrs$Dates, c(ftime_dim, sdate_dim))
dates <- data$attrs$Dates
dates_subset <- Subset(dates, sdate_dim, 1)
# adding dates to Dates for the new NAs introduced
if ((dates_subset[2] - dates_subset[1]) == 1) {
timefreq <- 'days'
} else { } else {
if (length(insert_ftime) > 1) { timefreq <- 'months'
warning("Parameter 'insert_ftime' must be of length 1, and only the", warning("Time frequency of forecast time is considered monthly.")
" first element will be used.")
insert_ftime <- insert_ftime[1]
}
# adding NAs at the begining of the data in ftime dim
ftimedim <- which(names(dim(data$data)) == 'ftime')
dims <- dim(data$data)
dims[ftimedim] <- insert_ftime
empty_array <- array(NA, dims)
data$data <- abind(empty_array, data$data, along = ftimedim)
names(dim(data$data)) <- names(dims)
# adding dates to Dates for the new NAs introduced
if ((data$attrs$Dates[2] - data$attrs$Dates[1]) == 1) {
timefreq <- 'days'
} else {
timefreq <- 'months'
warning("Time frequency of forecast time is considered monthly.")
}
start <- data$attrs$Dates
dim(start) <- c(ftime = length(start)/dims['sdate'], sdate = dims['sdate'])
# new <- array(NA, prod(dim(data$data)[c('ftime', 'sdate')]))
# Pending fix transform to UTC when concatenaiting
data$attrs$Dates <- do.call(c, lapply(1:dim(start)[2], function(x) {
seq(start[1,x] - as.difftime(insert_ftime,
units = timefreq),
start[dim(start)[1],x], by = timefreq, tz = "UTC")}))
} }
dim(dates) <- c(length(dates)/dims[sdate_dim], dims[sdate_dim])
names(dim(dates)) <- c(ftime_dim, sdate_dim)
# new <- array(NA, prod(dim(data$data)[c('ftime', 'sdate')]))
# Pending fix transform to UTC when concatenaiting
data$attrs$Dates <- do.call(c, lapply(1:dim(dates)[2], function(x) {
seq(dates[1,x] - as.difftime(insert_ftime,
units = timefreq),
dates[dim(dates)[1],x], by = timefreq, tz = "UTC")}))
} }
if (is.null(indices)) { if (is.null(indices)) {
if (any(split_dim %in% c('ftime', 'time', 'sdate'))) { if (any(split_dim %in% c(ftime_dim, sdate_dim))) {
indices <- data$attrs$Dates indices <- data$attrs$Dates
if (any(names(dim(data$data)) %in% 'sdate')) { if (any(names(dim(data$data)) %in% sdate_dim)) {
if (!any(names(dim(data$data)) %in% split_dim)) { if (!any(names(dim(data$data)) %in% split_dim)) {
stop("Parameter 'split_dims' must be one of the dimension ", stop("Parameter 'split_dims' must be one of the dimension ",
"names in parameter 'data'.") "names in parameter 'data'.")
} }
indices <- indices[1 : dim(data$data)[which(names(dim(data$data)) == split_dim)]] indices <- indices[1:dim(data$data)[which(names(dim(data$data)) == split_dim)]]
} }
} }
} }
data$data <- SplitDim(data$data, split_dim = split_dim, indices = indices, # Call the function
freq = freq, new_dim_name = new_dim_name) res <- SplitDim(data = data$data, split_dim = split_dim,
return(data) indices = indices, freq = freq,
new_dim_name = new_dim_name,
dates = data$attrs$Dates,
return_indices = return_indices)
if (inherits(res, 'list')) {
data$data <- res$data
# Split dim on Dates
if (!is.null(res$dates)) {
data$attrs$Dates <- res$dates
}
} else {
data$data <- res
}
data$dims <- dim(data$data)
# Coordinates
# TO DO: Subset splitted coordinate and add the new dimension coordinate.
if (return_indices) {
return(list(data = data, indices = res$indices))
} else {
return(data)
}
} }
#'Function to Split Dimension #'Function to Split Dimension
#' #'
...@@ -129,6 +169,11 @@ CST_SplitDim <- function(data, split_dim = 'time', indices = NULL, ...@@ -129,6 +169,11 @@ CST_SplitDim <- function(data, split_dim = 'time', indices = NULL,
#' the length in which to subset the dimension. #' the length in which to subset the dimension.
#'@param new_dim_name A character string indicating the name of the new #'@param new_dim_name A character string indicating the name of the new
#' dimension. #' dimension.
#'@param dates An optional parameter containing an array of dates of class
#' 'POSIXct' with the corresponding time dimensions of 'data'. It is NULL
#' by default.
#'@param return_indices A logical value that if it is TRUE, the indices
#' used in splitting the dimension will be returned. It is FALSE by default.
#'@examples #'@examples
#'data <- 1 : 20 #'data <- 1 : 20
#'dim(data) <- c(time = 10, lat = 2) #'dim(data) <- c(time = 10, lat = 2)
...@@ -145,7 +190,8 @@ CST_SplitDim <- function(data, split_dim = 'time', indices = NULL, ...@@ -145,7 +190,8 @@ CST_SplitDim <- function(data, split_dim = 'time', indices = NULL,
#'@importFrom ClimProjDiags Subset #'@importFrom ClimProjDiags Subset
#'@export #'@export
SplitDim <- function(data, split_dim = 'time', indices, freq = 'monthly', SplitDim <- function(data, split_dim = 'time', indices, freq = 'monthly',
new_dim_name = NULL) { new_dim_name = NULL, dates = NULL,
return_indices = FALSE) {
# check data # check data
if (is.null(data)) { if (is.null(data)) {
stop("Parameter 'data' cannot be NULL.") stop("Parameter 'data' cannot be NULL.")
...@@ -167,7 +213,7 @@ SplitDim <- function(data, split_dim = 'time', indices, freq = 'monthly', ...@@ -167,7 +213,7 @@ SplitDim <- function(data, split_dim = 'time', indices, freq = 'monthly',
"one and only the first element will be used.") "one and only the first element will be used.")
} }
if (!any(names(dims) %in% split_dim)) { if (!any(names(dims) %in% split_dim)) {
stop("Parameter 'split_dims' must be one of the dimension ", stop("Parameter 'split_dim' must be one of the dimension ",
"names in parameter 'data'.") "names in parameter 'data'.")
} }
pos_split <- which(names(dims) == split_dim) pos_split <- which(names(dims) == split_dim)
...@@ -210,8 +256,8 @@ SplitDim <- function(data, split_dim = 'time', indices, freq = 'monthly', ...@@ -210,8 +256,8 @@ SplitDim <- function(data, split_dim = 'time', indices, freq = 'monthly',
}) })
if ('try-error' %in% class(indices) | if ('try-error' %in% class(indices) |
sum(is.na(indices)) == length(indices)) { sum(is.na(indices)) == length(indices)) {
stop("Dates provided in parameter 'indices' must be of class", stop("Dates provided in parameter 'indices' must be of class ",
" 'POSIXct' or convertable to 'POSIXct'.") "'POSIXct' or convertable to 'POSIXct'.")
} }
} }
} }
...@@ -230,7 +276,7 @@ SplitDim <- function(data, split_dim = 'time', indices, freq = 'monthly', ...@@ -230,7 +276,7 @@ SplitDim <- function(data, split_dim = 'time', indices, freq = 'monthly',
} else if (freq == 'year') { } else if (freq == 'year') {
indices <- as.numeric(strftime(indices, format = "%Y")) indices <- as.numeric(strftime(indices, format = "%Y"))
repited <- unique(indices) repited <- unique(indices)
} else if (freq == 'monthly' ) { } else if (freq == 'monthly') {
indices <- as.numeric(strftime(indices, format = "%m%Y")) indices <- as.numeric(strftime(indices, format = "%m%Y"))
repited <- unique(indices) repited <- unique(indices)
} else { } else {
...@@ -255,15 +301,41 @@ SplitDim <- function(data, split_dim = 'time', indices, freq = 'monthly', ...@@ -255,15 +301,41 @@ SplitDim <- function(data, split_dim = 'time', indices, freq = 'monthly',
data <- lapply(repited, function(x) {rebuild(x, data, along = split_dim, data <- lapply(repited, function(x) {rebuild(x, data, along = split_dim,
indices = indices, max_times)}) indices = indices, max_times)})
data <- abind(data, along = length(dims) + 1) data <- abind(data, along = length(dims) + 1)
if (is.character(freq)) {
names(dim(data)) <- c(names(dims), freq) # Add new dim name
} else { if (is.null(new_dim_name)) {
names(dim(data)) <- c(names(dims), 'index') if (is.character(freq)) {
new_dim_name <- freq
} else {
new_dim_name <- 'index'
}
} }
if (!is.null(new_dim_name)) { names(dim(data)) <- c(names(dims), new_dim_name)
names(dim(data)) <- c(names(dims), new_dim_name)
# Split also Dates
dates_exist <- FALSE
if (!is.null(dates)) {
if (any(split_dim %in% names(dim(dates)))) {
datesdims <- dim(dates)
dates <- lapply(repited, function(x) {rebuild(x, dates, along = split_dim,
indices = indices, max_times)})
dates <- abind(dates, along = length(datesdims) + 1)
dates <- as.POSIXct(dates, origin = '1970-01-01', tz = "UTC")
names(dim(dates)) <- c(names(datesdims), new_dim_name)
}
dates_exist <- TRUE
}
# Return objects
if (all(dates_exist, return_indices)) {
return(list(data = data, dates = dates, indices = indices))
} else if (all(dates_exist, !return_indices)) {
return(list(data = data, dates = dates))
} else if (all(!dates_exist, return_indices)) {
return(list(data = data, indices = indices))
} else {
return(data)
} }
return(data)
} }
rebuild <- function(x, data, along, indices, max_times) { rebuild <- function(x, data, along, indices, max_times) {
......
...@@ -9,7 +9,10 @@ ...@@ -9,7 +9,10 @@
#'`s2dv_cube` object. #'`s2dv_cube` object.
#' #'
#'It receives any number of parameters (`...`) that are automatically forwarded #'It receives any number of parameters (`...`) that are automatically forwarded
#'to the `startR::Start` function. See details in `?startR::Start`. #'to the `startR::Start` function. See details in `?startR::Start`. The
#'auxiliary functions used to define dimensions need to be called within the
#'startR namespace (e.g. startR::indices(), startR::values(), startR::Sort(),
#'startR::CircularSort(), startR::CDORemapper(), ...).
#' #'
#'@param ... Parameters that are automatically forwarded to the `startR::Start` #'@param ... Parameters that are automatically forwarded to the `startR::Start`
#' function. See details in `?startR::Start`. #' function. See details in `?startR::Start`.
......
...@@ -79,15 +79,15 @@ CST_Subset <- function(x, along, indices, drop = FALSE, var_dim = NULL, ...@@ -79,15 +79,15 @@ CST_Subset <- function(x, along, indices, drop = FALSE, var_dim = NULL,
} }
# Subset data # Subset data
x$data <- ClimProjDiags::Subset(x$data, along = along, x$data <- Subset(x$data, along = along,
indices = indices, indices = indices,
drop = drop) drop = drop)
# Adjust dimensions # Adjust dimensions
x$dims <- dim(x$data) x$dims <- dim(x$data)
# Adjust coordinates # Adjust coordinates
for (dimension in 1:length(along)) { for (dimension in 1:length(along)) {
dim_name <- along[dimension] dim_name <- along[dimension]
index <- indices[[dimension]] index <- indices[dimension]
# Only rename coordinates that have not been dropped # Only rename coordinates that have not been dropped
if (dim_name %in% names(x$dims)) { if (dim_name %in% names(x$dims)) {
# Subset coordinate by indices # Subset coordinate by indices
...@@ -113,10 +113,10 @@ CST_Subset <- function(x, along, indices, drop = FALSE, var_dim = NULL, ...@@ -113,10 +113,10 @@ CST_Subset <- function(x, along, indices, drop = FALSE, var_dim = NULL,
} }
if ((!is.null(x$attrs$source_files)) && if ((!is.null(x$attrs$source_files)) &&
(dim_name %in% names(dim(x$attrs$source_files)))) { (dim_name %in% names(dim(x$attrs$source_files)))) {
x$attrs$source_files <- ClimProjDiags::Subset(x$attrs$source_files, x$attrs$source_files <- Subset(x$attrs$source_files,
along = dim_name, along = dim_name,
indices = index, indices = index,
drop = drop) drop = drop)
} }
} }
# Remove metadata from variables that were dropped # Remove metadata from variables that were dropped
...@@ -128,10 +128,10 @@ CST_Subset <- function(x, along, indices, drop = FALSE, var_dim = NULL, ...@@ -128,10 +128,10 @@ CST_Subset <- function(x, along, indices, drop = FALSE, var_dim = NULL,
if (!(length(time_along) == 0)) { if (!(length(time_along) == 0)) {
time_indices <- indices[match(time_along, along)] time_indices <- indices[match(time_along, along)]
original_dates <- x$attrs$Dates original_dates <- x$attrs$Dates
x$attrs$Dates <- ClimProjDiags::Subset(x$attrs$Dates, x$attrs$Dates <- Subset(x$attrs$Dates,
along = time_along, along = time_along,
indices = time_indices, indices = time_indices,
drop = drop) drop = drop)
} }
# Subset metadata # Subset metadata
for (variable in 1:length(names(x$attrs$Variable$metadata))) { for (variable in 1:length(names(x$attrs$Variable$metadata))) {
...@@ -150,12 +150,12 @@ CST_Subset <- function(x, along, indices, drop = FALSE, var_dim = NULL, ...@@ -150,12 +150,12 @@ CST_Subset <- function(x, along, indices, drop = FALSE, var_dim = NULL,
# Function to subset with attributes # Function to subset with attributes
.subset_with_attrs <- function(x, ...) { .subset_with_attrs <- function(x, ...) {
args_subset <- list(...) args_subset <- list(...)
if (is.null(dim(x)) | length(dim(x)) == 1) { if (any(is.null(dim(x)), length(dim(x)) == 1)) {
l <- x[args_subset[['indices']]] l <- x[args_subset[['indices']][[1]]]
} else { } else {
l <- ClimProjDiags::Subset(x, along = args_subset[['along']], l <- Subset(x, along = args_subset[['along']],
indices = args_subset[['indices']], indices = args_subset[['indices']],
drop = args_subset[['drop']]) drop = args_subset[['drop']])
} }
attr.names <- names(attributes(x)) attr.names <- names(attributes(x))
attr.names <- attr.names[attr.names != 'names'] attr.names <- attr.names[attr.names != 'names']
......
...@@ -72,8 +72,7 @@ CST_WeatherRegimes <- function(data, ncenters = NULL, ...@@ -72,8 +72,7 @@ CST_WeatherRegimes <- function(data, ncenters = NULL,
ncores = NULL) { ncores = NULL) {
# Check 's2dv_cube' # Check 's2dv_cube'
if (!inherits(data, 's2dv_cube')) { if (!inherits(data, 's2dv_cube')) {
stop("Parameter 'data' must be of the class 's2dv_cube', ", stop("Parameter 'data' must be of the class 's2dv_cube'.")
"as output by CSTools::CST_Load.")
} }
# Check 'exp' object structure # Check 'exp' object structure
if (!all(c('data', 'coords') %in% names(data))) { if (!all(c('data', 'coords') %in% names(data))) {
......
...@@ -35,6 +35,35 @@ ...@@ -35,6 +35,35 @@
#' colour bar will be automatically interpolated to match the number of breaks. #' colour bar will be automatically interpolated to match the number of breaks.
#' Each item in this list can be named, and the name will be used as title for #' Each item in this list can be named, and the name will be used as title for
#' the corresponding colour bar (equivalent to the parameter 'bar_titles'). #' the corresponding colour bar (equivalent to the parameter 'bar_titles').
#'@param bar_limits Parameter from s2dv::ColorBar. Vector of two numeric values
#' with the extremes of the range of values represented in the colour bar. If
#' 'var_limits' go beyond this interval, the drawing of triangle extremes is
#' triggered at the corresponding sides, painted in 'col_inf' and 'col_sup'.
#' Either of them can be set as NA and will then take as value the
#' corresponding extreme in 'var_limits' (hence a triangle end won't be
#' triggered for these sides). Takes as default the extremes of 'brks' if
#' available, else the same values as 'var_limits'.
#'@param triangle_ends Parameter from s2dv::ColorBar. Vector of two logical
#' elements, indicating whether to force the drawing of triangle ends at each
#' of the extremes of the colour bar. This choice is automatically made from
#' the provided 'brks', 'bar_limits', 'var_limits', 'col_inf' and 'col_sup',
#' but the behaviour can be manually forced to draw or not to draw the triangle
#' ends with this parameter. If 'cols' is provided, 'col_inf' and 'col_sup'
#' will take priority over 'triangle_ends' when deciding whether to draw the
#' triangle ends or not.
#'@param col_inf Parameter from s2dv::ColorBar. Colour to fill the inferior
#' triangle end with. Useful if specifying colours manually with parameter
#' 'cols', to specify the colour and to trigger the drawing of the lower
#' extreme triangle, or if 'cols' is not specified, to replace the colour
#' automatically generated by ColorBar().
#'@param col_sup Parameter from s2dv::ColorBar. Colour to fill the superior
#' triangle end with. Useful if specifying colours manually with parameter
#' 'cols', to specify the colour and to trigger the drawing of the upper
#' extreme triangle, or if 'cols' is not specified, to replace the colour
#' automatically generated by ColorBar().
#'@param bar_extra_margin Parameter from s2dv::ColorBar. Extra margins to be
#' added around the colour bar, in the format c(y1, x1, y2, x2). The units are
#' margin lines. Takes rep(0, 4) by default.
#'@param col_unknown_map Colour to use to paint the grid cells for which a map #'@param col_unknown_map Colour to use to paint the grid cells for which a map
#' is not possible to be chosen according to 'map_select_fun' or for those #' is not possible to be chosen according to 'map_select_fun' or for those
#' values that go beyond 'display_range'. Takes the value 'white' by default. #' values that go beyond 'display_range'. Takes the value 'white' by default.
......