[R] vectorization of rolling function
Arnaud Duranel
arnaud.duranel.09 at ucl.ac.uk
Mon Dec 8 10:51:19 CET 2014
Great, many thanks for your help Jeff.
Apologies for the HTML format, I'll be more careful next time.
Arnaud
On 08/12/2014 08:25, Jeff Newmiller wrote:
> Please don't post in HTML... you may not recognize it, but the
> receiving end does not necessarily (and in this case did not) look
> like the sending end, and the cleanup can impede answers you are
> hoping to get.
>
> In many cases, loops can be vectorized. However, near as I can tell
> this is an example of an algorithm that simply needs a loop [1].
>
> One bit of advice: the coredata function is horribly slow. Just
> converting your time series objects to numeric vectors for the purpose
> of this computation sped up the algorithm by 500x on 10000 point
> series. Converting it to inline C++ as below sped it up by yet another
> factor of 40x. 20000x is nothing to sneeze at.
>
> #######
> ## optional temporary setup for windows
> ## assumes you have installed Rtools
> gcc <- "C:\\Rtools\\bin"
> rtools <- "C:\\Rtools\\gcc-4.6.3\\bin"
> path <- strsplit(Sys.getenv("PATH"), ";")[[1]]
> new_path <- c(rtools, gcc, path)
> new_path <- new_path[!duplicated(tolower(new_path))]
> Sys.setenv(PATH = paste(new_path, collapse = ";"))
> ## end of optional
>
> library(Rcpp)
>
> cppFunction(
> "DataFrame EvapSimRcpp( NumericVector RR
> , NumericVector ETmax
> , const double Smax
> , const double initialStorage ) {
> int n = RR.size();
>
> // create empty time-series to fill
> // effective rainfall (i.e. rainfall minus intercepted rainfall)
> NumericVector RReff( n );
> // intercepted rainfall( n );
> NumericVector Rint( n );
> // residual potential evapotranspiration (ie ETmax minus
> // evaporation from interception)
> NumericVector ETres( n, NA_REAL );
> double evap;
>
> // volume of water in interception storage at start of
> // computation
> double storage = initialStorage;
>
> for ( int i=0; i<n; i++ ) {
> // compute interception capacity for time step i (maximum
> // interception capacity minus any water intercepted but not
> // evaporated during previous time-step).
> Rint[ i ] = Smax - storage;
> // compute intercepted rainfall: equal to rainfall if smaller
> // than interception capacity, and to interception capacity if
> // larger.
> if ( RR[ i ] < Rint[ i ] ) Rint[ i ] = RR[ i ];
> // compute effective rainfall (rainfall minus intercepted
> // rainfall).
> RReff[ i ] = RR[ i ] - Rint[ i ];
> // update interception storage: initial interception storage +
> // intercepted
> // rainfall.
> storage = storage + Rint[ i ];
> // compute evaporation from interception storage: equal to
> // potential evapotranspiration if the latter is smaller than
> // interception storage, and to interception storage if larger.
> if ( storage > ETmax[ i ] )
> evap = ETmax[ i ];
> else
> evap = storage;
> // compute residual potentiel evapotranspiration: potential
> // evapotranspiration minus evaporation from interception
> // storage.
> ETres[ i ] = ETmax[ i ] - evap;
> // update interception storage, to be carried over to next
> // time-step: interception storage minus evaporation from
> // interception storage.
> storage = storage - evap;
> }
> DataFrame DF = DataFrame::create( Named( \"int\" ) = Rint
> , Named( \"RReff\" ) = RReff
> , Named( \"ETres\" ) = ETres
> );
> return DF;
> }
> ")
>
> # Assumes your initial variables are already defined
> EvapSimRcpp( RR, ETmax, Smax, 0 )
>
> #######
>
> [1]
> http://stackoverflow.com/questions/7153586/can-i-vectorize-a-calculation-which-depends-on-previous-elements
>
> On Sat, 6 Dec 2014, A Duranel wrote:
>
>> Hello
>> I use R to run a simple model of rainfall interception by vegetation:
>> rainfall falls on vegetation, some is retained by the vegetation
>> (part of
>> which can evaporate), the rest falls on the ground (quite crude but very
>> similar to those used in SWAT or MikeSHE, for the hydrologists among
>> you).
>> It uses a loop on zoo time-series of rainfall and potential
>> evapotranspiration. Unfortunately I did not find a way to vectorize
>> it and
>> it takes ages to run on long datasets. Could anybody help me to make
>> it run
>> faster?
>>
>> library(zoo)
>> set.seed(1)
>> # artificial potential evapotranspiration time-series
>> ETmax<-zoo(runif(10, min=1, max=6), c(1:10))
>> # artificial rainfall time-series
>> RR<-zoo(runif(10, min=0, max=6), c(1:10))
>>
>> ## create empty time-series to fill
>> # effective rainfall (i.e. rainfall minus intercepted rainfall)
>> RReff<-zoo(NA, c(1:10))
>> # intercepted rainfall
>> int<-zoo(NA, c(1:10))
>> # residual potential evapotranspiration (ie ETmax minus evaporation from
>> interception)
>> ETres<-zoo(NA, c(1:10))
>>
>> # define maximum interception storage capacity (maximum volume of
>> rainfall
>> that can be intercepted per time step, provided the interception
>> store is
>> empty at start of time-step)
>> Smax<-3
>> # volume of water in interception storage at start of computation
>> storage<-0
>>
>> for (i in 1:length(ETmax)) {
>> # compute interception capacity for time step i (maximum interception
>> capacity minus any water intercepted but not evaporated during previous
>> time-step).
>> int[i]<-Smax-storage
>> # compute intercepted rainfall: equal to rainfall if smaller than
>> interception capacity, and to interception capacity if larger.
>> if(RR[i]<int[i]) int[i]<-RR[i]
>> # compute effective rainfall (rainfall minus intercepted rainfall).
>> RReff[i]<-RR[i]-int[i]
>> # update interception storage: initial interception storage +
>> intercepted
>> rainfall.
>> storage<-storage+coredata(int[i])
>> # compute evaporation from interception storage: equal to potential
>> evapotranspiration if the latter is smaller than interception
>> storage, and
>> to interception storage if larger.
>> if(storage>coredata(ETmax[i])) evap<-coredata(ETmax[i]) else
>> evap<-storage
>> # compute residual potentiel evapotranspiration: potential
>> evapotranspiration minus evaporation from interception storage.
>> ETres[i]<-ETmax[i]-evap
>> # update interception storage, to be carried over to next time-step:
>> interception storage minus evaporation from interception storage.
>> storage<-storage-evap
>> }
>>
>> Many thanks for your help!
>>
>> Arnaud
>> UCL Department of Geography, UK
>>
>>
>>
>> --
>> View this message in context:
>> http://r.789695.n4.nabble.com/vectorization-of-rolling-function-tp4700487.html
>> Sent from the R help mailing list archive at Nabble.com.
>>
>> ______________________________________________
>> R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see
>> https://stat.ethz.ch/mailman/listinfo/r-help
>> PLEASE do read the posting guide
>> http://www.R-project.org/posting-guide.html
>> and provide commented, minimal, self-contained, reproducible code.
>>
>
> ---------------------------------------------------------------------------
>
> Jeff Newmiller The ..... ..... Go
> Live...
> DCN:<jdnewmil at dcn.davis.ca.us> Basics: ##.#. ##.#. Live Go...
> Live: OO#.. Dead: OO#.. Playing
> Research Engineer (Solar/Batteries O.O#. #.O#. with
> /Software/Embedded Controllers) .OO#. .OO#.
> rocks...1k
> ---------------------------------------------------------------------------
>
> .
>
More information about the R-help
mailing list