2

I am a newbie with cython and trying to convert a python class to cython. I don't know how I should define argument z in instance Da, in the way that it can deal with both numpy.array or just a single float number.

cdef class Cosmology(object):
    cdef double omega_m, omega_lam, omega_c  

    def __init__(self,double omega_m=0.3,double omega_lam=0.7):
        self.omega_m = omega_m
        self.omega_lam = omega_lam
        self.omega_c = (1. - omega_m - omega_lam)


    cpdef double a(self, double z):
        cdef double a
        return 1./(1+z)

    cpdef double E(self, double a):
        cdef double E
        return (self.omega_m*a**(-3) + self.omega_c*a**(-2) + self.omega_lam)**0.5

    cpdef double __angKernel(self, double x):
        cdef __angKernel:
        """Integration kernel"""
        return self.E(x**-1)**-1

    cpdef double Da(self, double z, double z_ref=0):
        cdef double Da
        if isinstance(z, np.ndarray):
            da = np.zeros_like(z)
            for i in range(len(da)):
                da[i] = self.Da(z[i], z_ref)
            return da
        else:
            if z < 0:
                raise ValueError("Redshift z must not be negative")
            if z < z_ref:
                raise ValueError("Redshift z must not be smaller than the reference redshift")

            d = integrate.quad(self.__angKernel, z_ref+1, z+1,epsrel=1.e-6, epsabs=1.e-12)
            rk = (abs(self.omega_c))**0.5
            if (rk*d[0] > 0.01):
                if self.omega_c > 0:
                    d[0] = sinh(rk*d[0])/rk
                if self.omega_c < 0:
                    d[0] = sin(rk*d[0])/rk
            return d[0]/(1+z)

I also wonder whether I convert all the arguments correctly into cython argument? I want to change my original python code to improve the speed of calculation. One of the bottleneck in my code I reckon, should be integrate.quad. Is there any substitution for this function in cython which helps to speed up the performance of my code?

cdef class halo_positions(object):
     cdef double x = None
     cdef double y = None
     def __init__(self,numpy.ndarray[double, ndim=1] positions):
         self.x = positions[0]
         self.y = positions[1]

And if I want to pass an array to halo_positions instance is it a right way to do it?

Dalek
  • 4,168
  • 11
  • 48
  • 100

1 Answers1

1

If your class is defined as cdef it will be accessible only in Cython (not in Python) making it unnecessary and not efficient to use cpdef and def for the class methods. You can convert them all to cdef.

When you tell that z is double, it will accept only a double. If you want this argument to be of two different types, you should keep its type undeclared, but this will directly affect the loop performance when z is a ndarray.

Alternatively you could use double * and pass the size of it, when the size is 1 it is a double, when the size is >1 an array. The function would be:

cdef double Da(self, int size, double *z, double z_ref=0):
    if size>1:
        da = np.zeros(size)
        for i in range(size):
            da[i] = self.Da(1, &z[i], z_ref)
        return da
    else:
        if z[0] < 0:
            raise ValueError("Redshift z must not be negative")
        if z[0] < z_ref:
            raise ValueError("Redshift z must not be smaller than the reference redshift")

        d = integrate.quad(self.__angKernel, z_ref+1, z[0]+1,
                           epsrel=1.e-6, epsabs=1.e-12)
        rk = (abs(self.omega_c))**0.5
        if (rk*d[0] > 0.01):
            if self.omega_c > 0:
                d[0] = sinh(rk*d[0])/rk
            if self.omega_c < 0:
                d[0] = sin(rk*d[0])/rk
        return d[0]/(1+z[0])
Saullo G. P. Castro
  • 56,802
  • 26
  • 179
  • 234
  • so I assume I have to declare `double rk` and what about `epsrel` and `epsabs`. My other question is whether the scipy integral can be substitute with something equivalent in cython? Because so far I think that is why the speed of my code is very low. – Dalek Jun 06 '14 at 23:25
  • @Dalek you actually have to questions, the first one is commented in this answer. For the second one, if I understood, do you want to integrate a vector valued function? ([like in this question](http://stackoverflow.com/q/17070333/832621)) – Saullo G. P. Castro Jun 07 '14 at 07:24
  • @Dalek `epsrel` and `epsabs` are tolerances for the numerical integration error, the lower these values the more precise the numerical integration gets... – Saullo G. P. Castro Jun 07 '14 at 07:25
  • Indeed `z` is actually a `1D` array with the shape of (1500,) and I need to integrate over each component of this array in a loop with `range(24000)`, so the speed of my code is very low so that is why I want to convert it to cython. – Dalek Jun 07 '14 at 07:38
  • @Dalek I have an implementation using a Trapezoidal rule or an nth-order polynomial rule to perform such vector valued integration, [check this answer here](http://stackoverflow.com/a/17522695/832621) – Saullo G. P. Castro Jun 07 '14 at 08:17
  • in the example you have given it seems it computes an array of functions, however my problem is to give an array of points for one given function. In addition I don't quite understand how you define the lower and upper limit of integral – Dalek Jun 07 '14 at 09:55
  • @Dalek the integration limits are defined in `xs = np.linspace(0.,20.,33)`... let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/55246/discussion-between-saullo-castro-and-dalek). – Saullo G. P. Castro Jun 07 '14 at 09:58
  • The example you sent me, you integrated over different function with the same interval my problem is that I want to integrate over same function with different input parameter 24000 times with different upper integration limits which changes in a loop for like 1500 points. Is there any way to optimize it, since I want to use this again in `Markov Chain Monte Carlo`. – Dalek Jun 08 '14 at 08:21
  • @Dalek, this seems to be a different question than the one you originally asked, you could create this new question giving more details about the integration that you want... – Saullo G. P. Castro Jun 08 '14 at 08:29
  • I will write another question. – Dalek Jun 08 '14 at 08:36