[R] Fast evaluation of functions in 3D domains

Duncan Murdoch murdoch.duncan at gmail.com
Wed Mar 25 13:18:11 CET 2015


On 25/03/2015 7:55 AM, Lluis.Hurtado at uv.es wrote:
> Dear all,
> 
> Finally I have tried three different options to integrate a function in a 3D volume. Here 
> I show a test example. The volume is the box [0,100] x [0,100] x [0,100] and the 
> function is
> 
> nfw(d) = 4/((d/5)*(1+(d/5))^2)
> 
> where d is the distance between each point in the box to the point (50,50,40).
> 
> 1-Grid of thick 1 in R (10^6 points)
> 
>> model <- function(x) 
> {
>    d <- sqrt((x[,1]-50)^2 + (x[,2]-50)^2 + (x[,3]-40)^2)
>    r <- 4.0/((d/5)*(1+(d/5))^2)
>    r
> } 
>> sum(model(x))
> [1] 10287.52
>> system.time(sum(model(x)))
>    user  system elapsed 
>   0.052   0.003   0.053 
> 
> 2-Grid with thick 1 in C++ calling from R. Function model_cpp is a function written in 
> C++ reproducing model function as above. (10^6 points)
> 
>> model <- function(x)
>   {
>   	param <- c(50,50,40,5)
>   	.Call('model_cpp',x[,1],x[,2],x[,3],param)
>   }
>>  sum(model(x))
> [1] 10287.52
>> system.time(sum(model(x)))
>    user  system elapsed 
>   0.028   0.000   0.028 
> 
> 3-cubature. Mr Tom Jagger kindly proposed to use cubature package:
> http://cran.r-project.org/web/packages/cubature/cubature.pdf
> 
>> model <- function(x) 
> +  {
> +     d <- sqrt((x[1]-50)^2 + (x[2]-50)^2 + (x[3]-40)^2)
> +     r <- 4.0/((d/5)*(1+(d/5))^2)
> +     r
> +   }
>> adaptIntegrate(model, rep(0,3), rep(100,3), tol=1e-4)
> $integral
> [1] 10303.16
> 
> $error
> [1] 1.029888
> 
> $functionEvaluations
> [1] 48609
> 
> $returnCode
> [1] 0
> 
>> system.time(adaptIntegrate(model, rep(0,3), rep(100,3), tol=1e-4))
>    user  system elapsed 
>   0.232   0.002   0.246
> 
> As you can see the second option is the fastest, but the third one is probably more 
> accurate. 
> 
> The function nfw(d) has an analytical primitive when integrated in a sphere If now we 
> reproduce the calculations for cases 1 and 2 in a sphere (named R) of radius 40 
> centered in (50,50,40), the first two methods give me the following result:
> 
> sum(model(R))
> [1] 8204.711
> 
> while the exact solution is
> 
>> 16*pi*(5^3)*(log(5+40) - log(5) - 40/(40+5))
> [1] 8220.516
> 
> However, I can not try the same with cubature since the code is prepared only to be 
> used in hypercubes.

I don't know how well the cubature package would deal with the
discontinuity, but a simple way to integrate over a sphere would be to
set the function value to zero outside of it.  Just change

r <- 4.0/((d/5)*(1+(d/5))^2)

to

r <- ifelse(d < 40, 4.0/((d/5)*(1+(d/5))^2), 0)

Duncan Murdoch

> 
> As I am using non integrable functions I could try to increase the density of the grid 
> and see if I can obtain accurate results before reaching high time costs or study how 
> important is to reach that accuracy, it may be not that important for my algorithm. 
> 
> Anyway, thank you all for you time and ideas.
> 
> Lluís Hurtado
> IFCA
> 
>>
>> On Mar 23, 2015, at 3:44 AM, <Lluis.Hurtado at uv.es> <Lluis.Hurtado at uv.es> wrote:
>>
>>> Dear all,
>>>
>>> I am currently working with the spatstat package with 3D samples. I am trying to 
>>> evaluate a non analytical function over the window that encloses the sample and I 
>>> need to know which is the fastest way of doing it.
>>>
>>> The function input is a 3 coordinate position in the window (x,y,z) and a list of 
>>> parameters (a,b,c). The output is a numerical value. 
>>>
>>> n <- function(x,y,z,a,b,c)
>>
>> Perhaps:
>>
>> dfrm <- as.data.frame.table(your_volume_matrix) 
>> n.out <- with(dfrm,  mapply( n, x=x, y=y, z=z, MoreArgs=list(a=a,b=b,c=c) ) _
>> dim(n.out) <- dim(your_volume_matrix)
>>
>> You don't describe the form of this "3 coordinate position in the window (x,y,z)" so 
> perhaps the arguments will need to be extracted. I took a WAG at one approach. If 
> it's not in long-form, you need configure the array indices for either a volume or 
> surface into a dataframe, perhaps with `expand.grid` or `as.data.frame.table`.
>>
>>  You also don't describe the sort of integration you imagine. Why not a simple sum 
> of that result divided by the volume? I cannot imagine any faster procedure .
>>
>>
>>> But I need to do it over the whole volume.
>>>
>>> For 2 dimensions it can be done with
>>>
>>> A <- as.im(function,window,parameters)
>>> norm <- integral.im(A)
>>>
>>> For 3 dimensions I have tried to pass an array of a grid covering the window (like 
> a 
>>> quadrature scheme) and then summing up the output array, but I would like to 
> know if 
>>> there is any faster way of integrating the function.
>>>
>>> Thank you very much,
>>>
>>> Lluís Hurtado
>>> IFCA
>>> www.ifca.unican.es
>>>
>>> ______________________________________________
>>> 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-guidehtml
>>> and provide commented, minimal, self-contained, reproducible code.
>>
>> David Winsemius
>> Alameda, CA, USA
>>
>>
>>
> 
> 
> --
> Lluís Hurtado-Gil
> Observatori Astronòmic. Universitat de València.
> Edifici Instituts d'Investigació. Parc Científic.
> C/ Catedrático Agustín Escardino n°7
> Campus Burjassot-Paterna
> 46980 Paterna València (Spain).
> 
> ______________________________________________
> 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.
>



More information about the R-help mailing list