Commit 92a81575 authored by Jean-Loup Gaussen's avatar Jean-Loup Gaussen Committed by Jean-Francois Rey
Browse files

Merge GDAL API to master

parent cd7647eb
......@@ -8,3 +8,6 @@
^.*\.Rproj$
^\.Rproj\.user$
^landsepi_.*\.tar\.gz$
^src/*\.o$
^src/*\.so$
^src/Makevars$
*.Rproj*
.Rhistory
.RData
.Ruserdata
src/*.o
src/*.so
src/*.dll
src/Makevars
src/exemple/GDAL_API_exemple
src/exemple/*.o
config\.log
config\.status
landsepiDev*
.Rproj.user
nbproject/
package:
stages:
- build_test
- packages
r-build_test:
stage: build_test
tags:
- "r-base-biosp"
script:
- "Rscript -e \"pkgbuild::compile_dll()\""
- "Rscript -e \"roxygen2::roxygenize('.', roclets=c('rd', 'collate', 'namespace'))\""
- "R CMD build . --resave-data"
- "R CMD check --as-cran $(ls -rt landsepiDev_* |tail -1)"
artifacts:
paths:
- "$(ls -rt landsepiDev_*.tar.gz |tail -1)"
package-devel:
r-devel-build_test:
stage: build_test
tags:
- "r-devel-biosp"
script:
- "Rscript -e \"pkgbuild::compile_dll()\""
- "Rscript -e \"roxygen2::roxygenize('.', roclets=c('rd', 'collate', 'namespace'))\""
- "R CMD build . --resave-data"
- "R CMD check --as-cran $(ls -rt landsepiDev_* |tail -1)"
artifacts:
paths:
- "$(ls -rt landsepiDev_*.tar.gz |tail -1)"
package-Mac-base:
r-Mac-build_test:
stage: build_test
tags:
- "Mac"
- "R"
script:
- "Rscript -e \"pkgbuild::compile_dll()\""
- "Rscript -e \"roxygen2::roxygenize('.', roclets=c('rd', 'collate', 'namespace'))\""
- "R CMD build . --resave-data"
- "R CMD check --as-cran $(ls -rt landsepiDev_* |tail -1)"
artifacts:
paths:
- "$(ls -rt landsepiDev_*.tar.gz |tail -1)"
package-windows:
r-windows-build_test:
stage: build_test
tags:
- "win10"
- "R"
- "binaries"
script:
- "Rscript -e \"roxygen2::roxygenize('.',roclets=c('rd','collate','namespace'))\""
- "Rscript -e \"pkgbuild::compile_dll()\""
- "Rscript -e \"roxygen2::roxygenize('.', roclets=c('rd', 'collate', 'namespace'))\""
- "R CMD build . --resave-data"
- "R CMD INSTALL --build --force-biarch $(ls -rt landsepiDev_*.tar.gz |tail -1)"
- "R CMD check --as-cran $(ls -rt landsepiDev_* |tail -1)"
artifacts:
paths:
- "$(ls -rt landsepiDev_*.tar.gz |tail -1)"
release-win:
variables:
CI_DEBUG_TRACE: "true"
release-r:
stage: packages
tags:
- "win10"
- "R"
- "binaries"
- "r-base-biosp"
script:
- "Rscript -e \"roxygen2::roxygenize('.',roclets=c('rd','collate','namespace'))\""
- "R CMD build . --resave-data"
- "R CMD INSTALL --build --force-biarch $(ls -rt landsepiDev_*.tar.gz |tail -1)"
- "echo \"Nothing to do\""
artifacts:
paths:
- "$(ls -rt landsepiDev_*.zip |tail -1)"
- "$(ls -rt landsepiDev_* |tail -1)"
only:
- tags
dependencies:
- r-build_test
release-package:
release-win:
stage: packages
tags:
- "r-base-biosp"
- "win10"
- "R"
- "binaries"
script:
- "Rscript -e \"roxygen2::roxygenize('.', roclets=c('rd', 'collate', 'namespace'))\""
- "R CMD build . --resave-data"
- "R CMD check --as-cran $(ls -rt landsepiDev_* |tail -1)"
- "R CMD INSTALL --build --force-biarch $(ls -rt landsepiDev_*.tar.gz |tail -1)"
artifacts:
paths:
- "$(ls -rt landsepiDev_* |tail -1)"
- "$(ls -rt landsepiDev_*.zip |tail -1)"
only:
- tags
dependencies:
- r-windows-build_test
release-Mac:
stage: packages
tags:
- "Mac"
- "R"
script:
- "Rscript -e \"roxygen2::roxygenize('.', roclets=c('rd', 'collate', 'namespace'))\""
- "R CMD build . --resave-data"
- "R CMD INSTALL --build $(ls -rt landsepiDev_*.tar.gz |tail -1)"
artifacts:
paths:
- "$(ls -rt landsepiDev_*.tgz | tail -1)"
only:
- tags
dependencies:
- r-Mac-build_test
......@@ -53,9 +53,12 @@ Collate:
'multiN.R'
'AgriLand.R'
'HLIRdynamics.R'
'catch-routine-registration.R'
'demo_landsepi.R'
'landsepi.R'
'plotevolQR.R'
'simul_landsepi.R'
LinkingTo: Rcpp
LinkingTo: Rcpp, testthat
RoxygenNote: 6.1.1
Suggests:
testthat
......@@ -34,4 +34,4 @@ importFrom(sf,st_read)
importFrom(sf,st_write)
importFrom(utils,data)
importFrom(utils,write.table)
useDynLib(landsepiDev)
useDynLib(landsepiDev, .registration = TRUE)
......@@ -56,6 +56,6 @@
#' @references Rimbaud L., Papaïx J., Rey J.-F., Barrett L. G. and Thrall P. H. (2018). Assessing the durability and efficiency of landscape-based strategies to deploy plant resistance to pathogens. \emph{PLoS Computational Biology} 14(4):e1006067.
#' @export
model_landsepi <- function(timeP, landscape, dispersal, inits, val_seed, hostP, pathoP, evolP) {
invisible(.Call('_landsepiDev_model_landsepi', PACKAGE = 'landsepiDev', timeP, landscape, dispersal, inits, val_seed, hostP, pathoP, evolP))
invisible(.Call(`_landsepiDev_model_landsepi`, timeP, landscape, dispersal, inits, val_seed, hostP, pathoP, evolP))
}
# This dummy function definition is included with the package to ensure that
# 'tools::package_native_routine_registration_skeleton()' generates the required
# registration info for the 'run_testthat_tests' symbol.
(function() {
.Call("run_testthat_tests", PACKAGE = "landsepiDev")
})
......@@ -124,7 +124,7 @@
#'
#' ## (see ?simul_landsepi to help parameterise the function and simulate other scenarios)
#' }
#' @useDynLib landsepiDev
#' @useDynLib landsepiDev, .registration = TRUE
#' @import methods
#' @import graphics
#' @import stats
......
......@@ -1835,8 +1835,8 @@ $as_echo "no" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
CXXFLAGS="${CXXFLAGS} -Wall -Wextra -g -ggdb -Wconversion -O0 -fno-inline"
CPPFLAGS="${CPPFLAGS} -DDEBUG "
CXXFLAGS=" -pedantic -Wall -Wextra -g -ggdb -Wconversion -O0 -fno-inline ${CXXFLAGS}"
CPPFLAGS=" -DDEBUG ${CPPFLAGS}"
fi
# check Rcpp
......
......@@ -50,8 +50,8 @@ if test "$enable_debug" != "yes" && test "$DEBUG" != TRUE ; then
CXXFLAGS="${CXXFLAGS} -w"
else
AC_MSG_RESULT(yes)
CXXFLAGS="${CXXFLAGS} -Wall -Wextra -g -ggdb -Wconversion -O0 -fno-inline"
CPPFLAGS="${CPPFLAGS} -DDEBUG "
CXXFLAGS=" -pedantic -Wall -Wextra -g -ggdb -Wconversion -O0 -fno-inline ${CXXFLAGS}"
CPPFLAGS=" -DDEBUG ${CPPFLAGS}"
fi
# check Rcpp
......
......@@ -17,7 +17,7 @@ architecture to simulate plant response to disease.
\tabular{ll}{
Package: \tab landsepi\cr
Type: \tab Package\cr
Version: \tab 0.0.5\cr
Version: \tab 0.0.8\cr
Date: \tab 2018-11-27\cr
License: \tab GPL (>=2)\cr
}
......
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/RcppExports.R
\name{model_landsepi}
\alias{model_landsepi}
\title{Model Landscape Epidemiology & Evolution}
\usage{
model_landsepi(timeP, landscape, dispersal, inits, val_seed, hostP, pathoP,
evolP)
}
\arguments{
\item{timeP}{list of simulation parameters (number of years, number of time-steps per year)}
\item{landscape}{landscape generated through AgriLand}
\item{dispersal}{list of dispersal parameters (vectorised dispersal matrix of the pathogen, vectorised dispersal matrix of the host)}
\item{inits}{list initial conditions (initial probability of infection by the pathogen)}
\item{val_seed}{seed (for random number generation)}
\item{hostP}{list of host parameters (number of cultivars, initial planting density, maximal carrying capacity, growth rate, reproduction rate, death rate, resistance formula,
parameters of the sigmoid invasion function: kappa, sigma and s)}
\item{pathoP}{list of pathogen parameters (probability to survive the off-season, probability to reproduce via sex rather than via cloning,
infection rate, reproduction rate, average latent period duration, variance of the latent period, average infectious period duration
, variance of the infectious period duration, parameters of the sigmoid contamination function: kappa, sigma, s)}
\item{evolP}{list of evolution parameters (cost of infectivity, cost of aggressiveness, mutation rate, efficiency of major
resistance genes, efficiency of quantitative resistance, trade-off strength, number of increments of quantitative
resistance erosion, average time to expression of quantitative resistance, Variance of the time to expression of quantitative resistance,
adaptation formula)}
}
\value{
A set of binary files is generated for every year of simulation and every compartment: \itemize{
\item H: healthy hosts,
\item Hjuv: juvenile healthy hosts,
\item L: latently infected hosts,
\item I: infectious hosts,
\item R: removed hosts,
\item S: propagules.
}
Each file indicates for every time-step the number of individuals in each field, and when appropriate for each cultivar and pathotype)
}
\description{
Stochastic, spatially-explicit, demo-genetic model simulating the spread and evolution of a pathogen in a heterogeneous landscape.
}
\details{
\itemize{
\item The model is stochastic, spatially explicit (the basic spatial unit is an individual field), based on a SEIR
(‘susceptible-exposed-infectious-removed’) structure with a discrete time step. It simulates the spread and evolution
of a pathogen in an agricultural landscape, across cropping seasons split by host harvests which impose potential bottlenecks
to the pathogen.
\item A wide array of deployment strategies can be simulated: mosaics, mixtures, rotations and pyramiding of multiple
major resistance genes which affect pathogen infectivity, and up to four quantitative resistance traits.
These traits target different aggressiveness components of the pathogen, i.e. the infection rate, the duration of the latent
period and the infectious period, and the propagule production rate. Quantitative resistance may be expressed from the time of planting,
or later in the cropping season (Adult Plant Resistance or Mature Plant Resistance).
\item The genotype of cultivated plant cultivars is specified using
the "resistance formulas", i.e. a vector of size 8. the four first elements indicate whether the cultivar carries major resistance
genes #1, #2, #3 and #4, respectively. The following four elements indicate whether the cultivar carried a quantitative resistance
trait against the infection rate, the latent period duration, the sporulation rate, or the sporulation duration of the pathogen, respectively.
For example, the formula c(1,0,0,0,0,1,0,0) indicates the presence of major gene #1 and a quantitative resistance
which increases the duration of the latent period of the pathogen.
\item Initially, the pathogen is not adapted to any source of
resistance, and is only present on susceptible hosts. However, through mutation, it can evolve and may acquire infectivity
genes (which leads to breakdown of major resistance genes) or increase aggressiveness (which leads to the erosion of the
relevant quantitative resistance traits). These genes may also be reassorted via sexual reproduction.
\item Evolution of a pathogen toward infectivity or increased aggressiveness on
a resistant host is often penalised by a fitness cost on susceptible hosts. Consequently, in the present model, pathogens
carrying infectivity genes may have reduced infection rate (cost of infectivity) on susceptible hosts relative
to pathogens that do not carry these genes. Similarly, a gain in pathogen aggressiveness on quantitatively resistant hosts
is penalised by a decreased aggressiveness on susceptible hosts, leading to a trade-off.
}
}
\references{
Rimbaud L., Papaïx J., Rey J.-F., Barrett L. G. and Thrall P. H. (2018). Assessing the durability and efficiency of landscape-based strategies to deploy plant resistance to pathogens. \emph{PLoS Computational Biology} 14(4):e1006067.
}
/*
* Part of the landsepi R package.
* Copyright (C) 2017 Loup Rimbaud <loup.rimbaud@inra.fr>
* Julien Papaix <julien.papaix@inra.fr>
* Jean-François Rey <jean-francois.rey@inra.fr>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,i
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "Landscape.hpp"
#if defined(WIN32) || defined(_WIN32)
const std::string SEPARATOR = "\\";
#else
const std::string SEPARATOR = "/";
#endif
/* ------------------------------ Landscape ------------------------------ */
Landscape::Landscape(GDALDataset* dataset){
this->dataset = dataset;
}
Landscape::Landscape(const Landscape& L) : Landscape(L.dataset){ }
Landscape& Landscape::operator=(Landscape L){
std::swap(*this, L);
return *this;
}
Landscape::~Landscape(){
if(this->dataset != NULL){
GDALClose(this->dataset);
this->dataset = NULL;
}
}
/*
* Create a dataset and return a Landscape object created with this dataset.
* If the dataset type is SHAPEFILE, you need to give a path to the folder that will contain the shapefile(s), if the
* folder doesn't exist, it will be created.
* (Example: "/existing_folder" or just "new_folder")
* If the dataset type is GPKG, you need to give the path and the name of your .gpkg file, if the folder don't exist,
* it will NOT be created and the creation will fail.
* (Example: "./existing_folder/file.gpkg" or just "file.gpkg")
*
* To avoid error due to an empty dataset, a empty layer is always created with the dataset, using the name of the
* dataset or "layer" if the dataset has no name (exemple: "./" for a shapefile dataset).
*/
Landscape Landscape::createDataset(std::string path, DatasetType datasetType){
if(path.empty()){
throw "Error: you must give a directory or a file name to create a dataset";
}
if(datasetType == GPKG){
std::regex gpkg(".*\\.gpkg$");
if(!regex_match(path, gpkg)){
throw "Error: the file must end with '.gpkg' (" + path + ")";
}
}
GDALDriver* driver = getDriver(datasetType);
GDALDataset* dataset = driver->Create(path.c_str(), 0, 0, 0, GDT_Unknown, NULL);
if(dataset == NULL){
throw "Error: couldn't create the dataset in '" + path + "' using the " + driver->GetDescription() + " driver";
}
Landscape res = Landscape(dataset);
if(datasetType == GPKG){
path = splitLastOf(path, ".gpkg")[0];
}
std::string file = splitLastOf(path, SEPARATOR)[1];
if(file.empty()){
file = "layer"; // if the file name is empty, give a default name to the layer
}
res.createLayer(file);
return res;
}
/*
* Open a dataset and return a Landscape created with this dataset.
* If the dataset type is SHAPEFILE, you need to give a path to the folder that contain the shapefile(s).
* (Example: "path/to/shapefile")
* If the dataset type is GPKG, you need to give the path and the name of your .gpkg file.
* (Example: "path/to/gpkg/data.gpkg)
*/
Landscape Landscape::openDataset(std::string path, DatasetType datasetType){
if(datasetType == SHAPEFILE){
directoryExist(path);
}
std::string driver;
switch(datasetType){
case SHAPEFILE:
{
driver = "ESRI Shapefile";
break;
}
case GPKG:
{
driver = "GPKG";
break;
}
}
int flags = GDAL_OF_UPDATE | GDAL_OF_VECTOR;
const char* drivers[2] = {driver.c_str()};
GDALAllRegister();
GDALDataset* dataset = static_cast<GDALDataset*> (GDALOpenEx(path.c_str(), flags, drivers, NULL, NULL));
if(dataset == NULL){
throw "Error: the " + driver + " dataset was not found at '" + path + "'";
}
return Landscape(dataset);
}
/*
* Erase the dataset and all the files associated with it (folder, shapefiles or .gpkg).
*/
bool Landscape::eraseDataset(Landscape& landscape, DatasetType datasetType){
GDALDataset* dataset = landscape.getDataset();
if(dataset != NULL){
GDALDriver* driver = getDriver(datasetType);
std::string dataset_path = dataset->GetDescription();
landscape.getDataset()->FlushCache(); // Prevent a GPKG layer/table from being read only
if(driver->Delete(dataset_path.c_str()) == CE_Failure){
return false;
}
landscape.dataset = NULL;
}
return true;
}
/*
* Return the dataset of the landscape.
*/
GDALDataset* Landscape::getDataset(){
return this->dataset;
}
/*
* Return the number of layers belonging to the dataset.
*/
int Landscape::getLayersCount(){
return this->dataset->GetLayerCount();
}
/*
* Return the index of a layer or -1 if the layer name is not found, by using its name.
*/
int Landscape::getLayerIndex(std::string name){
for(int i = 0; i < this->getLayersCount(); i++){
if(this->getLayer(i)->GetName() == name){
return i;
}
}
return -1;
}
/*
* Return a vector that contains all the layers of the dataset.
*/
std::vector<Layer*> Landscape::getLayers(){
std::vector<Layer*> layers = std::vector<Layer*>();
for(int i = 0; i < this->dataset->GetLayerCount(); i++){
layers.push_back(this->getLayer(i));
}
return layers;
}
/*
* Return a layer by using its index or throw an error if the given index is out of range.
*/
Layer* Landscape::getLayer(int index){
outOfRange(index, 0, this->getLayersCount() - 1);
return static_cast<Layer*> (this->dataset->GetLayer(index)); // Using GDAL function
}
/*
* Return a layer by using its name or NULL if the layer name is not found.
*/
Layer* Landscape::getLayer(std::string name){
return static_cast<Layer*> (this->dataset->GetLayerByName(name.c_str()));
}
/*
* Create a new layer and add it to the dataset.
* If the dataset type is SHAPEFILE, it will create 3 files (.dbf, .shp and .shx) in the folder used during the creation
* or the opening of the dataset, the files will have the name of the layer.
* If the dataset type is GPKG, it will create a new table in the .gpkg dataset, the table will have the name of the
* layer.
*/
Layer* Landscape::createLayer(std::string name){
if(getLayer(name) != NULL){
throw "Error: couldn't create the layer '" + name + "', it already exist";
}
return static_cast<Layer*> (this->dataset->CreateLayer(name.c_str()));
}
/*
* Create a new layer by copying the features (not the fields) of another layer.
*/
Layer* Landscape::createLayerWithFeatures(std::string name, Layer* source_layer){
// Create a new layer and add it to the dataset using a copy of a source layer
Layer* dest_layer = static_cast<Layer*> (this->dataset->CopyLayer(source_layer, name.c_str()));
// Remove all the field of the new layer
while(dest_layer->GetLayerDefn()->GetFieldCount() > 0){
dest_layer->DeleteField(0);
}
return dest_layer;
}
/*
* Remove the layer from the dataset and erase the corresponding shapefiles (SHAPEFILE) or table (GPKG), by using its
* index.
*/
bool Landscape::removeLayer(int index){
outOfRange(index, 0, this->getLayersCount() - 1);
//this->getDataset()->ResetReading(); // Prevent a GPKG layer/table from being locked
if(this->dataset->DeleteLayer(index) != OGRERR_NONE){
return false;
}
return true;
}
/*
* Remove the layer from the dataset and erase the corresponding shapefiles (SHAPEFILE) or table (GPKG), by using its
* name.
*/
bool Landscape::removeLayer(std::string name){
int index = this->getLayerIndex(name);
if(index == -1){
return false;
}
return this->removeLayer(index);
}
/* ------------------------------ Layer ------------------------------ */
/*
* Return a vector that contains all the features of the layer.
*/
std::vector<Feature*> Layer::getFeatures(){
std::vector<Feature*> features;
for(int i = 0; i < this->GetFeatureCount(); i++){
features.push_back(this->getFeature(i));
}
return features;
}
/*
* Return a feature by using its index or throw an error if the given index is out of range.
*/
Feature* Layer::getFeature(int index){
outOfRange(index, 0, this->GetFeatureCount() - 1);
return static_cast<Feature*> (this->GetFeature(index));
}
/*
* Copy a existing feature and add it to the layer.
*/
Feature* Layer::addFeature(Feature* source_feature){
// If the source feature definition is not the same that the destination layer definition and if there is already a
// feature in the destination layer, then you can't add that feature because it can have different fields
if(this->GetLayerDefn() != source_feature->GetDefnRef()){
if(this->GetFeatureCount() != 0){
throw "Error: Couldn't a new feature in the layer '" + std::string(this->GetName()) + \
"' because their definitions are incompatible";
} else{
// If there is no feature in the layer, we can modify its definition and use the feature's one
int field_count = source_feature->GetFieldCount();
for(int i = 0; i < field_count; i++){
OGRFieldDefn* field_def = source_feature->GetFieldDefnRef(i);
if(i < this->GetLayerDefn()->GetFieldCount()){
// if the layer already have a field def fot this index, alter it
this->AlterFieldDefn(i, field_def, ALTER_NAME_FLAG | ALTER_TYPE_FLAG | ALTER_WIDTH_PRECISION_FLAG |
ALTER_NULLABLE_FLAG | ALTER_DEFAULT_FLAG);