diff --git a/.buildlibrary b/.buildlibrary index ba0119b..2f68cfa 100644 --- a/.buildlibrary +++ b/.buildlibrary @@ -1,4 +1,4 @@ -ValidationKey: '2307608' +ValidationKey: '2336684' AutocreateReadme: yes AcceptedWarnings: - 'Warning: package ''.*'' was built under R version' diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml index fcd7136..7d564a1 100644 --- a/.github/workflows/check.yaml +++ b/.github/workflows/check.yaml @@ -1,5 +1,3 @@ -# Run CI for R using https://eddelbuettel.github.io/r-ci/ - name: check on: @@ -8,11 +6,6 @@ on: pull_request: branches: [main, master] -env: - USE_BSPM: "true" - _R_CHECK_FORCE_SUGGESTS_: "false" - NO_BINARY_INSTALL_R_PACKAGES: 'c("madrat", "magclass", "citation", "gms", "goxygen", "GDPuc", "roxygen2")' - jobs: check: runs-on: ubuntu-latest @@ -20,80 +13,37 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Bootstrap - run: | - sudo chown runner -R . - sudo locale-gen en_US.UTF-8 - sudo add-apt-repository -y ppa:ubuntugis/ppa - curl -OLs https://eddelbuettel.github.io/r-ci/run.sh - chmod 0755 run.sh - ./run.sh bootstrap - rm -f bspm_*.tar.gz - - - name: Enable r-universe repo, modify bspm integration - run: | - # install packages from https://pik-piam.r-universe.dev and CRAN - echo ' - options(repos = c(universe = "https://pik-piam.r-universe.dev", - CRAN = "https://cloud.r-project.org")) - ' >> .Rprofile - cat .Rprofile - # modify bspm integration to never install binary builds of PIK CRAN packages - sudo sed -i '/bspm::enable()/d' /etc/R/Rprofile.site - # need double % because of printf, %s is replaced with "$NO_BINARY_INSTALL_R_PACKAGES" (see "env:" above) - printf ' - local({ - expr <- quote({ - if (!is.null(repos)) { - noBinaryInstallRPackages <- %s - pkgs <- c(bspm::install_sys(pkgs[!pkgs %%in%% noBinaryInstallRPackages]), - pkgs[pkgs %%in%% noBinaryInstallRPackages]) - } - type <- "source" - }) - trace(utils::install.packages, expr, print = FALSE) - }) - ' "$NO_BINARY_INSTALL_R_PACKAGES" | sudo tee --append /etc/R/Rprofile.site >/dev/null - cat /etc/R/Rprofile.site - - - name: Set up Pandoc - uses: r-lib/actions/setup-pandoc@v2 + - uses: r-lib/actions/setup-pandoc@v2 - - name: Set up Python 3.9 - uses: actions/setup-python@v4 + - uses: r-lib/actions/setup-r@v2 with: - python-version: 3.9 + use-public-rspm: true + extra-repositories: "https://rse.pik-potsdam.de/r/packages" - - name: Cache R libraries - if: ${{ !env.ACT }} # skip when running locally via nektos/act - uses: pat-s/always-upload-cache@v3 + - uses: r-lib/actions/setup-r-dependencies@v2 with: - path: /usr/local/lib/R/ - key: 3-${{ runner.os }}-usr-local-lib-R-${{ hashFiles('DESCRIPTION') }} - restore-keys: | - 3-${{ runner.os }}-usr-local-lib-R- - - - name: Restore R library permissions - run: | - sudo chmod 2777 /usr/local/lib/R /usr/local/lib/R/site-library - - - name: Install dependencies - run: | - ./run.sh install_aptget libhdf5-dev libharfbuzz-dev libfribidi-dev - ./run.sh install_all - ./run.sh install_r_binary covr rstudioapi - ./run.sh install_r lucode2 + extra-packages: | + any::lucode2 + any::covr + any::madrat + any::magclass + any::citation + any::gms + any::goxygen + any::GDPuc + # piam packages also available on CRAN (madrat, magclass, citation, + # gms, goxygen, GDPuc) will usually have an outdated binary version + # available; by using extra-packages we get the newest version + + - uses: actions/setup-python@v4 + with: + python-version: 3.9 - name: Install python dependencies if applicable run: | [ -f requirements.txt ] && python -m pip install --upgrade pip wheel || true [ -f requirements.txt ] && pip install -r requirements.txt || true - - name: Remove bspm integration # to get rid of error when running install.packages - run: | - sudo sed -i '/ trace(utils::install.packages, expr, print = FALSE)/d' /etc/R/Rprofile.site - cat /etc/R/Rprofile.site - - name: Verify validation key shell: Rscript {0} run: lucode2:::validkey(stopIfInvalid = TRUE) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9c3b069..5d2e4ca 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,7 +15,7 @@ repos: - id: mixed-line-ending - repo: https://github.com/lorenzwalthert/precommit - rev: v0.3.2.9013 + rev: v0.3.2.9019 hooks: - id: parsable-R - id: deps-in-desc diff --git a/CITATION.cff b/CITATION.cff index 51c0144..44a4351 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -2,8 +2,8 @@ cff-version: 1.2.0 message: If you use this software, please cite it using the metadata from this file. type: software title: 'lpjmlkit: Toolkit for Basic LPJmL Handling' -version: 1.1.8 -date-released: '2023-07-18' +version: 1.1.9 +date-released: '2023-10-06' abstract: A collection of basic functions to facilitate the work with the Dynamic Global Vegetation Model (DGVM) Lund-Potsdam-Jena managed Land (LPJmL) hosted at the Potsdam Institute for Climate Impact Research (PIK). It provides functions for diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..52be541 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,86 @@ +# Contributing to lpjmlkit + +Thank you for your interest in contributing to *lpjmlkit*, an open-source R +package for operating LPJmL and processing related data. +We currently prefer contributions in the form of bug reports, feature requests, +and suggestions of code improvements as issues in the +[lpjmlkit GitHub repository](https://github.com/PIK-LPJmL/lpjmlkit/issues). +If you want to contribute code, please follow the instructions below. +Please note that due to our current worflow information on the authorship of +code contributions may get lost. + + +## Getting Started + +Before you start contributing to *lpjmlkit*, here are a few steps to get you +set up: + +1. Fork the [lpjmlkit GitHub repository](https://github.com/PIK-LPJmL/lpjmlkit) +to your own GitHub account. +2. Clone your forked repository to your local machine. + ```shell + git clone https://github.com/YourUsername/lpjmlkit.git + cd lpjmlkit + ``` +3. Install the package and its dependencies following the instructions in the +documentation. + +Now you're ready to start making contributions! + +## Contributing + +To contribute to *lpjmlkit*, please follow these steps: + +1. Check for existing issues in the +[**issue tracker**](https://github.com/PIK-LPJmL/lpjmlkit/issues) to see if your +contribution idea has already been discussed or reported. +2. If the issue doesn't already exist, create a **new issue** to discuss the +problem or feature you want to address. Be sure to provide as much detail as +possible to help others understand the context and purpose. +3. **Fork the repository** if you haven't already and create a **new branch** +for your contribution. +4. Make your changes in that new branch, following best practices and +adhering to the **coding style** of the project. +5. Write **unit tests** if applicable and ensure that all tests pass. +6. Submit a **pull request (PR)** referencing the issue you created earlier. +Describe your changes, and our team will review it as soon as possible. +7. All discussion threads of the PR need to be resolved before the PR can be merged. + +Your contributions will be greatly appreciated and will help make *lpjmlkit* +even better. + + +## Code Quality +We use the the [**Advanced R Style Guide**](https://style.tidyverse.org/) for R +code. + +Furthermore we use the following tools to ensure code quality: +* [**roxygen2**](https://roxygen2.r-lib.org/) for documentation. +* [**testthat**](https://testthat.r-lib.org/) for unit tests. +* [**lintr**](https://lintr.r-lib.org/) for static code analysis. + +Please make sure that your code passes all tests and static code analysis before +submitting a pull request. + +## Code of Conduct + +Please note that by contributing to *lpjmlkit*, you are expected to adhere to +our Code of Conduct. We strive to maintain a welcoming and inclusive community, +and we expect respectful and considerate behavior from all contributors: +* **Be Respectful**: Treat all community members with respect and kindness. +* **Inclusivity**: Ensure that your language and actions are inclusive and +respectful of diversity. +* **Collaboration**: Encourage a collaborative and supportive atmosphere. + +We do not tolerate: +* **Harassment**: Any form of harassment, trolling, or offensive behavior. +* **Discrimination**: Discrimination, derogatory comments, or exclusionary +practices. +* **Bullying**: Bullying or aggressive behavior towards others. + +Reporting Incidents +If you witness or experience any violations, please report them to +[jannesbr@pik-potsdam.de](mailto:jannesbr@pik-potsdam.de). +All reports will be handled confidentially and promptly. + +Thank you for being part of the *lpjmlkit* community! diff --git a/DESCRIPTION b/DESCRIPTION index 6eab2f3..979c66e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: lpjmlkit Type: Package Title: Toolkit for Basic LPJmL Handling -Version: 1.1.8 +Version: 1.1.9 Authors@R: c( person("Jannes", "Breier", , "jannesbr@pik-potsdam.de", role = c("aut", "cre"), comment = c(ORCID = "0000-0002-9055-6904")), person("Sebastian","Ostberg", , "ostberg@pik-potsdam.de", role = "aut", comment = c(ORCID = "0000-0002-2368-7015")), @@ -54,4 +54,4 @@ Suggests: sf Config/testthat/edition: 3 VignetteBuilder: knitr -Date: 2023-07-18 +Date: 2023-10-06 diff --git a/R/LPJmLMetaData.R b/R/LPJmLMetaData.R index 2c7f7e0..30bed1b 100644 --- a/R/LPJmLMetaData.R +++ b/R/LPJmLMetaData.R @@ -75,7 +75,7 @@ LPJmLMetaData <- R6::R6Class( # nolint cat( paste0(spaces, col_var( - paste0("$", print_fields) + paste0("$", print_fields) ), " ", to_char1, @@ -106,13 +106,14 @@ LPJmLMetaData <- R6::R6Class( # nolint ) cat("\n") + # Print information about subset if subsetted cat( paste0( spaces, col_var("$subset"), " ", # Color red if subset. - ifelse(self$subset, col_warn(self$subset), ""), + ifelse(self$subset, col_warn(self$subset), self$subset), "\n" ) ) @@ -170,7 +171,7 @@ LPJmLMetaData <- R6::R6Class( # nolint # Update cell fields - distinguish between character -> LPJmL C index # starting from 0 and numeric/integer -> R index starting from 1 -> -1. if (!is.null(subset$cell) || - !is.null(subset$lon) || !is.null(subset$lat)) { + !is.null(subset$lon) || !is.null(subset$lat)) { # Subset of subset$cell, subset$lon or subset$lat always have to be # accompanied by cell_dimnames. @@ -276,39 +277,39 @@ LPJmLMetaData <- R6::R6Class( # nolint "bigendian" = ifelse(x$endian == "big", TRUE, FALSE), # "descr" = tolower(x$name), # nolint "lastyear" = x$header[["firstyear"]] + - x$header[["timestep"]] * - (x$header[["nyear"]] - 1), + x$header[["timestep"]] * + (x$header[["nyear"]] - 1), "name" = ifelse(is.null(x$name), "LPJDUMMY", x$name) )) %>% `[[<-`("order", - switch(as.character(.$order), - `1` = "cellyear", - `2` = "yearcell", - `3` = "cellindex", - `4` = "cellseq", - stop( - paste( - "Invalid order value", sQuote(.$order), "in header" - ) - ) - ) - ) %>% + switch(as.character(.$order), + `1` = "cellyear", + `2` = "yearcell", + `3` = "cellindex", + `4` = "cellseq", + stop( + paste( + "Invalid order value", sQuote(.$order), "in header" + ) + ) + ) + ) %>% `[[<-`("datatype", - switch(as.character(.$datatype), - `0` = "byte", - `1` = "short", - `2` = "int", - `3` = "float", - `4` = "double", - stop( - paste( - "Invalid datatype value", sQuote(.$datatype), - "in header" - ) - ) - ) + switch(as.character(.$datatype), + `0` = "byte", + `1` = "short", + `2` = "int", + `3` = "float", + `4` = "double", + stop( + paste( + "Invalid datatype value", sQuote(.$datatype), + "in header" ) - private$init_list(header_to_meta, additional_attributes) + ) + ) + ) + private$init_list(header_to_meta, additional_attributes) } else { private$init_list(x, additional_attributes) @@ -574,19 +575,19 @@ LPJmLMetaData <- R6::R6Class( # nolint "filename" ) %>% - # Only append scalar if != 1 - append( - ifelse( - !is.null(private$.scalar), - ifelse(private$.scalar == 1, "scalar", NA), - NA - ) - ) %>% + # Only append scalar if != 1 + append( + ifelse( + !is.null(private$.scalar), + ifelse(private$.scalar == 1, "scalar", NA), + NA + ) + ) %>% - # Workaround to deal with NAs (NULL not possible in ifelse) - stats::na.omit() %>% - as.vector() %>% - return() + # Workaround to deal with NAs (NULL not possible in ifelse) + stats::na.omit() %>% + as.vector() %>% + return() }, .sim_name = NULL, @@ -681,8 +682,7 @@ LPJmLMetaData <- R6::R6Class( # nolint "name", "map", "version", - "offset" - ), + "offset"), .dimension_map = list(space_format = c("cell", "lon_lat"), time_format = c("time", "year_month_day"), diff --git a/R/read_io.R b/R/read_io.R index 2614cec..9046ddb 100644 --- a/R/read_io.R +++ b/R/read_io.R @@ -328,10 +328,10 @@ read_io <- function( # nolint:cyclocomp_linter. # Check file size expected_filesize <- unname( get_header_item(file_header, "ncell") * - get_header_item(file_header, "nbands") * - get_header_item(file_header, "nstep") * - get_header_item(file_header, "nyear") * - get_datatype(file_header)$size + start_offset + get_header_item(file_header, "nbands") * + get_header_item(file_header, "nstep") * + get_header_item(file_header, "nyear") * + get_datatype(file_header)$size + start_offset ) if (file.size(filename) != expected_filesize) { stop( @@ -345,9 +345,8 @@ read_io <- function( # nolint:cyclocomp_linter. # Check whether nbands may actually be nstep if (!silent && get_header_item(file_header, "version") < 4 && - get_header_item(file_header, "nstep") == 1 && - get_header_item(file_header, "nbands") %in% c(12, 365) - ) { + get_header_item(file_header, "nstep") == 1 && + get_header_item(file_header, "nbands") %in% c(12, 365)) { message( "read_io: Detected \"nbands = ", get_header_item(file_header, "nbands"), "\" and \"nstep = 1\". If this is a ", @@ -404,8 +403,7 @@ read_io_metadata_raw <- function(filename, file_type, band_names, firstyear = default(firstyear, 1901), nyear = default(nyear, 1), firstcell = default(firstcell, 0), - ncell = default(ncell, 67420), # Default: number of cells in global CRU - # grid + ncell = default(ncell, 67420), # Default: number of cells in global CRU grid nbands = default(nbands, 1), cellsize_lon = default(cellsize_lon, 0.5), # Default: resolution of global CRU grid @@ -586,7 +584,7 @@ read_io_metadata_meta <- function(filename, file_type, band_names, } if (!"band_names" %in% set_args && is.null(meta_data$band_names) && - !is.null(meta_data$map) && !is.null(nbands) + !is.null(meta_data$map) && !is.null(nbands) ) { if (length(meta_data$map) == nbands / 2) { # Create band_names from the map attribute that is included in meta data. @@ -741,9 +739,7 @@ read_io_data <- function( ) # Convert to read_band_order and apply subsetting along bands or cells - index <- which(!names(subset) %in% - c("day", "month", "year", "time") - ) + index <- which(!names(subset) %in% c("day", "month", "year", "time")) year_data <- aperm(year_data, perm = read_band_order) %>% # Apply any subsetting along bands or cells @@ -813,15 +809,15 @@ read_raw <- function(file_connection, data_offset, n_values, datatype, endian) { # Simple validity check for band_names check_band_names <- function(nbands, band_names) { if (!is.null(band_names) && - length(band_names) != nbands + length(band_names) != nbands ) { stop( "Provided band_names ", toString( dQuote( if (length(band_names) > 6) { - c(utils::head(band_names, n = 4), "...", - utils::tail(band_names, n = 1)) + c(utils::head(band_names, n = 4), "...", + utils::tail(band_names, n = 1)) } else { band_names } @@ -840,7 +836,7 @@ check_year_subset <- function(subset, meta_data, silent = FALSE) { if (is.numeric(subset[["year"]])) { outside_range <- which( as.integer(subset[["year"]]) < 1 | - as.integer(subset[["year"]]) > default(meta_data$nyear, 1) + as.integer(subset[["year"]]) > default(meta_data$nyear, 1) ) if (length(outside_range) > 0) { stop( diff --git a/README.md b/README.md index 9f3f396..141cbc9 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Toolkit for Basic LPJmL Handling -R package **lpjmlkit**, version **1.1.8** +R package **lpjmlkit**, version **1.1.9** [![CRAN status](https://www.r-pkg.org/badges/version/lpjmlkit)](https://cran.r-project.org/package=lpjmlkit) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.7773134.svg)](https://doi.org/10.5281/zenodo.7773134) [![R build status](https://github.com/PIK-LPJmL/lpjmlkit/workflows/check/badge.svg)](https://github.com/PIK-LPJmL/lpjmlkit/actions) [![codecov](https://codecov.io/gh/PIK-LPJmL/lpjmlkit/branch/master/graph/badge.svg)](https://app.codecov.io/gh/PIK-LPJmL/lpjmlkit) [![r-universe](https://pik-piam.r-universe.dev/badges/lpjmlkit)](https://pik-piam.r-universe.dev/builds) @@ -76,7 +76,7 @@ In case of questions / problems please contact Jannes Breier . +Breier J, Ostberg S, Wirth S, Minoli S, Stenzel F, Müller C (2023). _lpjmlkit: Toolkit for Basic LPJmL Handling_. doi: 10.5281/zenodo.7773134 (URL: https://doi.org/10.5281/zenodo.7773134), R package version 1.1.9, . A BibTeX entry for LaTeX users is @@ -85,7 +85,7 @@ A BibTeX entry for LaTeX users is title = {lpjmlkit: Toolkit for Basic LPJmL Handling}, author = {Jannes Breier and Sebastian Ostberg and Stephen Björn Wirth and Sara Minoli and Fabian Stenzel and Christoph Müller}, year = {2023}, - note = {R package version 1.1.8}, + note = {R package version 1.1.9}, doi = {10.5281/zenodo.7773134}, url = {https://github.com/PIK-LPJmL/lpjmlkit}, }