[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