In [16]:
import os, os.path
import numpy as np
from matplotlib import pyplot as plt
%matplotlib inline
from scipy.special import sph_harm
import weave
from weave import converters
from numba import jit, vectorize, guvectorize
import numexpr
%load_ext Cython


The Cython extension is already loaded. To reload it, use:
  %reload_ext Cython

In [2]:
from colloids import boo, particles

In [3]:
path = '/data/mleocmach/Documents/Tsurusawa/0_Data_retracked/3_DenseGel/163A/2_ageing/'
pos = np.loadtxt(os.path.join(path, '163A_1415_ageing_t000.dat'), skiprows=2)
bonds = np.loadtxt(os.path.join(path, '163A_1415_ageing_t000.bonds'), dtype=int)
inside = np.min((pos-pos.min(0)>14) & (pos.max()-pos>14), -1)
ngbs = particles.bonds2ngbs(bonds, len(pos))

In [13]:
%timeit boo.weave_qlm(pos, ngbs, inside)


1 loop, best of 3: 305 ms per loop

In [4]:
%timeit boo.bonds2qlm(pos, bonds)


1 loops, best of 3: 517 ms per loop

In [22]:
import math
def python_qlm(pos, ngbs, inside, l=6):
    qlm = np.zeros([len(pos), l+1], np.complex128)
    cart = np.zeros(3)
    sph = np.zeros(3)
    for i in range(ngbs.shape[0]):
        if not inside[i]:
            continue
        nb = 0
        for j in range(ngbs.shape[1]):
            q = ngbs[i,j]
            if q < 0 or q >= len(pos):
                continue
            nb += 1
            cart[:] = pos[i] - pos[q]
            sph[0] = cart[0]*cart[0] + cart[1]*cart[1] + cart[2]*cart[2]
            if cart[2]**2 == sph[0] or sph[0]+1.0 == 1.0:
                sph[1:] = 0
            else:
                sph[0] = math.sqrt(sph[0])
                sph[1] = math.acos(cart[2]/sph[0])
                sph[2] = math.atan2(cart[1], cart[0])
                if sph[2] < 0:
                    sph[2] += 2.0*math.pi
            qlm[i] += sph_harm(
                np.arange(l+1), l, 
                sph[2], 
                sph[1]
                )
        if nb>0:
            qlm[i] /= nb
    return qlm

In [23]:
%timeit python_qlm(pos, ngbs, inside)


1 loop, best of 3: 4.28 s per loop

In [4]:
%%cython --annotate
import numpy as np
from scipy.special.cython_special cimport sph_harm
cimport numpy as np
from libc.math cimport sqrt, acos, atan2, M_PI
cimport cython

@cython.boundscheck(False) # turn off bounds-checking for entire function
@cython.wraparound(False)  # turn off negative index wrapping for entire function
@cython.cdivision(True) # turn off division by zero checking for entire function
def cython_qlm(
    np.ndarray[np.float64_t, ndim=2] pos, 
    np.ndarray[np.int64_t, ndim=2] ngbs, 
    np.ndarray[np.uint8_t, ndim=1, cast=True] inside, 
    int l=6
):
    cdef int i,j, q, nb, m, d
    cdef double r, r2, theta, phi, z
    cdef long Npos = pos.shape[0]
    cdef long Nngb = ngbs.shape[1]
    cdef np.ndarray[dtype=np.complex128_t, ndim=2] qlm = np.zeros([len(pos), l+1], np.complex128)
    #cdef np.ndarray[dtype=double, ndim=1] cart = np.zeros(3, float)
    cdef double[3] cart
    for i in range(Npos):
        if not inside[i]:
            continue
        nb = 0
        for j in range(Nngb):
            q = ngbs[i,j]
            if q < 0 or q >= Npos:
                continue
            nb += 1
            for d in range(3):
                cart[d] = pos[i,d] - pos[q,d]
            r2 = cart[0]**2 + cart[1]**2 + cart[2]**2
            if cart[2]**2 == r2 or r2+1.0 == 1.0:
                theta = 0
                phi = 0
            else:
                r = sqrt(r2)
                z = cart[2]
                phi = acos(z/r)
                theta = atan2(cart[1], cart[0])
                if theta < 0:
                    theta += 2.0*M_PI
            for m in range(l+1):
                qlm[i,m] = qlm[i,m] + sph_harm(m, l, theta, phi)
        if nb>0:
            for m in range(l+1):
                qlm[i,m] = qlm[i,m] / nb
    return qlm


Out[4]:
Cython: _cython_magic_dff929309038b07cc4cb4b3c6acc7e68.pyx

Generated by Cython 0.23.4

Yellow lines hint at Python interaction.
Click on a line that starts with a "+" to see the C code that Cython generated for it.

+01: import numpy as np
  __pyx_t_2 = __Pyx_Import(__pyx_n_s_numpy, 0, -1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_2);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_np, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* … */
  __pyx_t_2 = PyDict_New(); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_2);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 02: from scipy.special.cython_special cimport sph_harm
 03: cimport numpy as np
 04: from libc.math cimport sqrt, acos, atan2, M_PI
 05: cimport cython
 06: 
 07: @cython.boundscheck(False) # turn off bounds-checking for entire function
 08: @cython.wraparound(False)  # turn off negative index wrapping for entire function
 09: @cython.cdivision(True) # turn off division by zero checking for entire function
+10: def cython_qlm(
/* Python wrapper */
static PyObject *__pyx_pw_46_cython_magic_dff929309038b07cc4cb4b3c6acc7e68_1cython_qlm(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
static PyMethodDef __pyx_mdef_46_cython_magic_dff929309038b07cc4cb4b3c6acc7e68_1cython_qlm = {"cython_qlm", (PyCFunction)__pyx_pw_46_cython_magic_dff929309038b07cc4cb4b3c6acc7e68_1cython_qlm, METH_VARARGS|METH_KEYWORDS, 0};
static PyObject *__pyx_pw_46_cython_magic_dff929309038b07cc4cb4b3c6acc7e68_1cython_qlm(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
  PyArrayObject *__pyx_v_pos = 0;
  PyArrayObject *__pyx_v_ngbs = 0;
  PyArrayObject *__pyx_v_inside = 0;
  int __pyx_v_l;
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("cython_qlm (wrapper)", 0);
  {
    static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_pos,&__pyx_n_s_ngbs,&__pyx_n_s_inside,&__pyx_n_s_l,0};
    PyObject* values[4] = {0,0,0,0};
    if (unlikely(__pyx_kwds)) {
      Py_ssize_t kw_args;
      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
      switch (pos_args) {
        case  4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
        case  3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
        case  0: break;
        default: goto __pyx_L5_argtuple_error;
      }
      kw_args = PyDict_Size(__pyx_kwds);
      switch (pos_args) {
        case  0:
        if (likely((values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_pos)) != 0)) kw_args--;
        else goto __pyx_L5_argtuple_error;
        case  1:
        if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_ngbs)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("cython_qlm", 0, 3, 4, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
        }
        case  2:
        if (likely((values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_inside)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("cython_qlm", 0, 3, 4, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
        }
        case  3:
        if (kw_args > 0) {
          PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s_l);
          if (value) { values[3] = value; kw_args--; }
        }
      }
      if (unlikely(kw_args > 0)) {
        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "cython_qlm") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
      }
    } else {
      switch (PyTuple_GET_SIZE(__pyx_args)) {
        case  4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
        case  3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
        values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
        values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
        break;
        default: goto __pyx_L5_argtuple_error;
      }
    }
    __pyx_v_pos = ((PyArrayObject *)values[0]);
    __pyx_v_ngbs = ((PyArrayObject *)values[1]);
    __pyx_v_inside = ((PyArrayObject *)values[2]);
    if (values[3]) {
      __pyx_v_l = __Pyx_PyInt_As_int(values[3]); if (unlikely((__pyx_v_l == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
    } else {
      __pyx_v_l = ((int)6);
    }
  }
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L5_argtuple_error:;
  __Pyx_RaiseArgtupleInvalid("cython_qlm", 0, 3, 4, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
  __pyx_L3_error:;
  __Pyx_AddTraceback("_cython_magic_dff929309038b07cc4cb4b3c6acc7e68.cython_qlm", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_pos), __pyx_ptype_5numpy_ndarray, 1, "pos", 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 11; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_ngbs), __pyx_ptype_5numpy_ndarray, 1, "ngbs", 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 12; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_inside), __pyx_ptype_5numpy_ndarray, 1, "inside", 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __pyx_r = __pyx_pf_46_cython_magic_dff929309038b07cc4cb4b3c6acc7e68_cython_qlm(__pyx_self, __pyx_v_pos, __pyx_v_ngbs, __pyx_v_inside, __pyx_v_l);
  int __pyx_lineno = 0;
  const char *__pyx_filename = NULL;
  int __pyx_clineno = 0;

  /* function exit code */
  goto __pyx_L0;
  __pyx_L1_error:;
  __pyx_r = NULL;
  __pyx_L0:;
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_46_cython_magic_dff929309038b07cc4cb4b3c6acc7e68_cython_qlm(CYTHON_UNUSED PyObject *__pyx_self, PyArrayObject *__pyx_v_pos, PyArrayObject *__pyx_v_ngbs, PyArrayObject *__pyx_v_inside, int __pyx_v_l) {
  int __pyx_v_i;
  int __pyx_v_j;
  int __pyx_v_q;
  int __pyx_v_nb;
  int __pyx_v_m;
  int __pyx_v_d;
  double __pyx_v_r;
  double __pyx_v_r2;
  double __pyx_v_theta;
  double __pyx_v_phi;
  double __pyx_v_z;
  long __pyx_v_Npos;
  long __pyx_v_Nngb;
  PyArrayObject *__pyx_v_qlm = 0;
  double __pyx_v_cart[3];
  __Pyx_LocalBuf_ND __pyx_pybuffernd_inside;
  __Pyx_Buffer __pyx_pybuffer_inside;
  __Pyx_LocalBuf_ND __pyx_pybuffernd_ngbs;
  __Pyx_Buffer __pyx_pybuffer_ngbs;
  __Pyx_LocalBuf_ND __pyx_pybuffernd_pos;
  __Pyx_Buffer __pyx_pybuffer_pos;
  __Pyx_LocalBuf_ND __pyx_pybuffernd_qlm;
  __Pyx_Buffer __pyx_pybuffer_qlm;
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("cython_qlm", 0);
  __pyx_pybuffer_qlm.pybuffer.buf = NULL;
  __pyx_pybuffer_qlm.refcount = 0;
  __pyx_pybuffernd_qlm.data = NULL;
  __pyx_pybuffernd_qlm.rcbuffer = &__pyx_pybuffer_qlm;
  __pyx_pybuffer_pos.pybuffer.buf = NULL;
  __pyx_pybuffer_pos.refcount = 0;
  __pyx_pybuffernd_pos.data = NULL;
  __pyx_pybuffernd_pos.rcbuffer = &__pyx_pybuffer_pos;
  __pyx_pybuffer_ngbs.pybuffer.buf = NULL;
  __pyx_pybuffer_ngbs.refcount = 0;
  __pyx_pybuffernd_ngbs.data = NULL;
  __pyx_pybuffernd_ngbs.rcbuffer = &__pyx_pybuffer_ngbs;
  __pyx_pybuffer_inside.pybuffer.buf = NULL;
  __pyx_pybuffer_inside.refcount = 0;
  __pyx_pybuffernd_inside.data = NULL;
  __pyx_pybuffernd_inside.rcbuffer = &__pyx_pybuffer_inside;
  {
    __Pyx_BufFmt_StackElem __pyx_stack[1];
    if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_pos.rcbuffer->pybuffer, (PyObject*)__pyx_v_pos, &__Pyx_TypeInfo_nn___pyx_t_5numpy_float64_t, PyBUF_FORMAT| PyBUF_STRIDES, 2, 0, __pyx_stack) == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  }
  __pyx_pybuffernd_pos.diminfo[0].strides = __pyx_pybuffernd_pos.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_pos.diminfo[0].shape = __pyx_pybuffernd_pos.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_pos.diminfo[1].strides = __pyx_pybuffernd_pos.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_pos.diminfo[1].shape = __pyx_pybuffernd_pos.rcbuffer->pybuffer.shape[1];
  {
    __Pyx_BufFmt_StackElem __pyx_stack[1];
    if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_ngbs.rcbuffer->pybuffer, (PyObject*)__pyx_v_ngbs, &__Pyx_TypeInfo_nn___pyx_t_5numpy_int64_t, PyBUF_FORMAT| PyBUF_STRIDES, 2, 0, __pyx_stack) == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  }
  __pyx_pybuffernd_ngbs.diminfo[0].strides = __pyx_pybuffernd_ngbs.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_ngbs.diminfo[0].shape = __pyx_pybuffernd_ngbs.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_ngbs.diminfo[1].strides = __pyx_pybuffernd_ngbs.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_ngbs.diminfo[1].shape = __pyx_pybuffernd_ngbs.rcbuffer->pybuffer.shape[1];
  {
    __Pyx_BufFmt_StackElem __pyx_stack[1];
    if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_inside.rcbuffer->pybuffer, (PyObject*)__pyx_v_inside, &__Pyx_TypeInfo_nn___pyx_t_5numpy_uint8_t, PyBUF_FORMAT| PyBUF_STRIDES, 1, 1, __pyx_stack) == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  }
  __pyx_pybuffernd_inside.diminfo[0].strides = __pyx_pybuffernd_inside.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_inside.diminfo[0].shape = __pyx_pybuffernd_inside.rcbuffer->pybuffer.shape[0];
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_XDECREF(__pyx_t_2);
  __Pyx_XDECREF(__pyx_t_3);
  __Pyx_XDECREF(__pyx_t_5);
  __Pyx_XDECREF(__pyx_t_6);
  __Pyx_XDECREF(__pyx_t_7);
  { PyObject *__pyx_type, *__pyx_value, *__pyx_tb;
    __Pyx_ErrFetch(&__pyx_type, &__pyx_value, &__pyx_tb);
    __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_inside.rcbuffer->pybuffer);
    __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_ngbs.rcbuffer->pybuffer);
    __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_pos.rcbuffer->pybuffer);
    __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_qlm.rcbuffer->pybuffer);
  __Pyx_ErrRestore(__pyx_type, __pyx_value, __pyx_tb);}
  __Pyx_AddTraceback("_cython_magic_dff929309038b07cc4cb4b3c6acc7e68.cython_qlm", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  goto __pyx_L2;
  __pyx_L0:;
  __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_inside.rcbuffer->pybuffer);
  __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_ngbs.rcbuffer->pybuffer);
  __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_pos.rcbuffer->pybuffer);
  __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_qlm.rcbuffer->pybuffer);
  __pyx_L2:;
  __Pyx_XDECREF((PyObject *)__pyx_v_qlm);
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
/* … */
  __pyx_tuple__7 = PyTuple_Pack(19, __pyx_n_s_pos, __pyx_n_s_ngbs, __pyx_n_s_inside, __pyx_n_s_l, __pyx_n_s_i, __pyx_n_s_j, __pyx_n_s_q, __pyx_n_s_nb, __pyx_n_s_m, __pyx_n_s_d, __pyx_n_s_r, __pyx_n_s_r2, __pyx_n_s_theta, __pyx_n_s_phi, __pyx_n_s_z, __pyx_n_s_Npos, __pyx_n_s_Nngb, __pyx_n_s_qlm, __pyx_n_s_cart); if (unlikely(!__pyx_tuple__7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_tuple__7);
  __Pyx_GIVEREF(__pyx_tuple__7);
/* … */
  __pyx_t_2 = PyCFunction_NewEx(&__pyx_mdef_46_cython_magic_dff929309038b07cc4cb4b3c6acc7e68_1cython_qlm, NULL, __pyx_n_s_cython_magic_dff929309038b07cc4); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_2);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_cython_qlm, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 11:     np.ndarray[np.float64_t, ndim=2] pos,
 12:     np.ndarray[np.int64_t, ndim=2] ngbs,
 13:     np.ndarray[np.uint8_t, ndim=1, cast=True] inside,
 14:     int l=6
 15: ):
 16:     cdef int i,j, q, nb, m, d
 17:     cdef double r, r2, theta, phi, z
+18:     cdef long Npos = pos.shape[0]
  __pyx_v_Npos = (__pyx_v_pos->dimensions[0]);
+19:     cdef long Nngb = ngbs.shape[1]
  __pyx_v_Nngb = (__pyx_v_ngbs->dimensions[1]);
+20:     cdef np.ndarray[dtype=np.complex128_t, ndim=2] qlm = np.zeros([len(pos), l+1], np.complex128)
  __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_2);
  __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_zeros); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_3);
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_t_4 = PyObject_Length(((PyObject *)__pyx_v_pos)); if (unlikely(__pyx_t_4 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __pyx_t_2 = PyInt_FromSsize_t(__pyx_t_4); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_2);
  __pyx_t_5 = __Pyx_PyInt_From_long((__pyx_v_l + 1)); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_5);
  __pyx_t_6 = PyList_New(2); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_6);
  __Pyx_GIVEREF(__pyx_t_2);
  PyList_SET_ITEM(__pyx_t_6, 0, __pyx_t_2);
  __Pyx_GIVEREF(__pyx_t_5);
  PyList_SET_ITEM(__pyx_t_6, 1, __pyx_t_5);
  __pyx_t_2 = 0;
  __pyx_t_5 = 0;
  __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_5);
  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_complex128); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
  __pyx_t_5 = NULL;
  __pyx_t_4 = 0;
  if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_3))) {
    __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_3);
    if (likely(__pyx_t_5)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
      __Pyx_INCREF(__pyx_t_5);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_3, function);
      __pyx_t_4 = 1;
    }
  }
  __pyx_t_7 = PyTuple_New(2+__pyx_t_4); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_7);
  if (__pyx_t_5) {
    __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_5); __pyx_t_5 = NULL;
  }
  __Pyx_GIVEREF(__pyx_t_6);
  PyTuple_SET_ITEM(__pyx_t_7, 0+__pyx_t_4, __pyx_t_6);
  __Pyx_GIVEREF(__pyx_t_2);
  PyTuple_SET_ITEM(__pyx_t_7, 1+__pyx_t_4, __pyx_t_2);
  __pyx_t_6 = 0;
  __pyx_t_2 = 0;
  __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_7, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_1);
  __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_ptype_5numpy_ndarray))))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __pyx_t_8 = ((PyArrayObject *)__pyx_t_1);
  {
    __Pyx_BufFmt_StackElem __pyx_stack[1];
    if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_qlm.rcbuffer->pybuffer, (PyObject*)__pyx_t_8, &__Pyx_TypeInfo___pyx_t_double_complex, PyBUF_FORMAT| PyBUF_STRIDES| PyBUF_WRITABLE, 2, 0, __pyx_stack) == -1)) {
      __pyx_v_qlm = ((PyArrayObject *)Py_None); __Pyx_INCREF(Py_None); __pyx_pybuffernd_qlm.rcbuffer->pybuffer.buf = NULL;
      {__pyx_filename = __pyx_f[0]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    } else {__pyx_pybuffernd_qlm.diminfo[0].strides = __pyx_pybuffernd_qlm.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_qlm.diminfo[0].shape = __pyx_pybuffernd_qlm.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_qlm.diminfo[1].strides = __pyx_pybuffernd_qlm.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_qlm.diminfo[1].shape = __pyx_pybuffernd_qlm.rcbuffer->pybuffer.shape[1];
    }
  }
  __pyx_t_8 = 0;
  __pyx_v_qlm = ((PyArrayObject *)__pyx_t_1);
  __pyx_t_1 = 0;
 21:     #cdef np.ndarray[dtype=double, ndim=1] cart = np.zeros(3, float)
 22:     cdef double[3] cart
+23:     for i in range(Npos):
  __pyx_t_9 = __pyx_v_Npos;
  for (__pyx_t_10 = 0; __pyx_t_10 < __pyx_t_9; __pyx_t_10+=1) {
    __pyx_v_i = __pyx_t_10;
+24:         if not inside[i]:
    __pyx_t_11 = __pyx_v_i;
    __pyx_t_12 = ((!((*__Pyx_BufPtrStrided1d(__pyx_t_5numpy_uint8_t *, __pyx_pybuffernd_inside.rcbuffer->pybuffer.buf, __pyx_t_11, __pyx_pybuffernd_inside.diminfo[0].strides)) != 0)) != 0);
    if (__pyx_t_12) {
/* … */
    }
+25:             continue
      goto __pyx_L3_continue;
+26:         nb = 0
    __pyx_v_nb = 0;
+27:         for j in range(Nngb):
    __pyx_t_13 = __pyx_v_Nngb;
    for (__pyx_t_14 = 0; __pyx_t_14 < __pyx_t_13; __pyx_t_14+=1) {
      __pyx_v_j = __pyx_t_14;
+28:             q = ngbs[i,j]
      __pyx_t_15 = __pyx_v_i;
      __pyx_t_16 = __pyx_v_j;
      __pyx_v_q = (*__Pyx_BufPtrStrided2d(__pyx_t_5numpy_int64_t *, __pyx_pybuffernd_ngbs.rcbuffer->pybuffer.buf, __pyx_t_15, __pyx_pybuffernd_ngbs.diminfo[0].strides, __pyx_t_16, __pyx_pybuffernd_ngbs.diminfo[1].strides));
+29:             if q < 0 or q >= Npos:
      __pyx_t_17 = ((__pyx_v_q < 0) != 0);
      if (!__pyx_t_17) {
      } else {
        __pyx_t_12 = __pyx_t_17;
        goto __pyx_L9_bool_binop_done;
      }
      __pyx_t_17 = ((__pyx_v_q >= __pyx_v_Npos) != 0);
      __pyx_t_12 = __pyx_t_17;
      __pyx_L9_bool_binop_done:;
      if (__pyx_t_12) {
/* … */
      }
+30:                 continue
        goto __pyx_L6_continue;
+31:             nb += 1
      __pyx_v_nb = (__pyx_v_nb + 1);
+32:             for d in range(3):
      for (__pyx_t_18 = 0; __pyx_t_18 < 3; __pyx_t_18+=1) {
        __pyx_v_d = __pyx_t_18;
+33:                 cart[d] = pos[i,d] - pos[q,d]
        __pyx_t_19 = __pyx_v_i;
        __pyx_t_20 = __pyx_v_d;
        __pyx_t_21 = __pyx_v_q;
        __pyx_t_22 = __pyx_v_d;
        (__pyx_v_cart[__pyx_v_d]) = ((*__Pyx_BufPtrStrided2d(__pyx_t_5numpy_float64_t *, __pyx_pybuffernd_pos.rcbuffer->pybuffer.buf, __pyx_t_19, __pyx_pybuffernd_pos.diminfo[0].strides, __pyx_t_20, __pyx_pybuffernd_pos.diminfo[1].strides)) - (*__Pyx_BufPtrStrided2d(__pyx_t_5numpy_float64_t *, __pyx_pybuffernd_pos.rcbuffer->pybuffer.buf, __pyx_t_21, __pyx_pybuffernd_pos.diminfo[0].strides, __pyx_t_22, __pyx_pybuffernd_pos.diminfo[1].strides)));
      }
+34:             r2 = cart[0]**2 + cart[1]**2 + cart[2]**2
      __pyx_v_r2 = ((pow((__pyx_v_cart[0]), 2.0) + pow((__pyx_v_cart[1]), 2.0)) + pow((__pyx_v_cart[2]), 2.0));
+35:             if cart[2]**2 == r2 or r2+1.0 == 1.0:
      __pyx_t_17 = ((pow((__pyx_v_cart[2]), 2.0) == __pyx_v_r2) != 0);
      if (!__pyx_t_17) {
      } else {
        __pyx_t_12 = __pyx_t_17;
        goto __pyx_L14_bool_binop_done;
      }
      __pyx_t_17 = (((__pyx_v_r2 + 1.0) == 1.0) != 0);
      __pyx_t_12 = __pyx_t_17;
      __pyx_L14_bool_binop_done:;
      if (__pyx_t_12) {
/* … */
        goto __pyx_L13;
      }
+36:                 theta = 0
        __pyx_v_theta = 0.0;
+37:                 phi = 0
        __pyx_v_phi = 0.0;
 38:             else:
+39:                 r = sqrt(r2)
      /*else*/ {
        __pyx_v_r = sqrt(__pyx_v_r2);
+40:                 z = cart[2]
        __pyx_v_z = (__pyx_v_cart[2]);
+41:                 phi = acos(z/r)
        __pyx_v_phi = acos((__pyx_v_z / __pyx_v_r));
+42:                 theta = atan2(cart[1], cart[0])
        __pyx_v_theta = atan2((__pyx_v_cart[1]), (__pyx_v_cart[0]));
+43:                 if theta < 0:
        __pyx_t_12 = ((__pyx_v_theta < 0.0) != 0);
        if (__pyx_t_12) {
/* … */
        }
      }
      __pyx_L13:;
+44:                     theta += 2.0*M_PI
          __pyx_v_theta = (__pyx_v_theta + (2.0 * M_PI));
+45:             for m in range(l+1):
      __pyx_t_23 = (__pyx_v_l + 1);
      for (__pyx_t_18 = 0; __pyx_t_18 < __pyx_t_23; __pyx_t_18+=1) {
        __pyx_v_m = __pyx_t_18;
+46:                 qlm[i,m] = qlm[i,m] + sph_harm(m, l, theta, phi)
        __pyx_t_24 = __pyx_v_i;
        __pyx_t_25 = __pyx_v_m;
        __pyx_t_26 = __pyx_v_i;
        __pyx_t_27 = __pyx_v_m;
        *__Pyx_BufPtrStrided2d(__pyx_t_double_complex *, __pyx_pybuffernd_qlm.rcbuffer->pybuffer.buf, __pyx_t_26, __pyx_pybuffernd_qlm.diminfo[0].strides, __pyx_t_27, __pyx_pybuffernd_qlm.diminfo[1].strides) = __Pyx_c_sum((*__Pyx_BufPtrStrided2d(__pyx_t_double_complex *, __pyx_pybuffernd_qlm.rcbuffer->pybuffer.buf, __pyx_t_24, __pyx_pybuffernd_qlm.diminfo[0].strides, __pyx_t_25, __pyx_pybuffernd_qlm.diminfo[1].strides)), __pyx_fuse_1__pyx_f_5scipy_7special_14cython_special_sph_harm(__pyx_v_m, __pyx_v_l, __pyx_v_theta, __pyx_v_phi, 0));
      }
      __pyx_L6_continue:;
    }
+47:         if nb>0:
    __pyx_t_12 = ((__pyx_v_nb > 0) != 0);
    if (__pyx_t_12) {
/* … */
    }
    __pyx_L3_continue:;
  }
+48:             for m in range(l+1):
      __pyx_t_13 = (__pyx_v_l + 1);
      for (__pyx_t_14 = 0; __pyx_t_14 < __pyx_t_13; __pyx_t_14+=1) {
        __pyx_v_m = __pyx_t_14;
+49:                 qlm[i,m] = qlm[i,m] / nb
        __pyx_t_28 = __pyx_v_i;
        __pyx_t_29 = __pyx_v_m;
        __pyx_t_30 = __pyx_v_i;
        __pyx_t_31 = __pyx_v_m;
        *__Pyx_BufPtrStrided2d(__pyx_t_double_complex *, __pyx_pybuffernd_qlm.rcbuffer->pybuffer.buf, __pyx_t_30, __pyx_pybuffernd_qlm.diminfo[0].strides, __pyx_t_31, __pyx_pybuffernd_qlm.diminfo[1].strides) = __Pyx_c_quot((*__Pyx_BufPtrStrided2d(__pyx_t_double_complex *, __pyx_pybuffernd_qlm.rcbuffer->pybuffer.buf, __pyx_t_28, __pyx_pybuffernd_qlm.diminfo[0].strides, __pyx_t_29, __pyx_pybuffernd_qlm.diminfo[1].strides)), __pyx_t_double_complex_from_parts(__pyx_v_nb, 0));
      }
+50:     return qlm
  __Pyx_XDECREF(__pyx_r);
  __Pyx_INCREF(((PyObject *)__pyx_v_qlm));
  __pyx_r = ((PyObject *)__pyx_v_qlm);
  goto __pyx_L0;

In [6]:
%timeit cython_qlm(pos, ngbs, inside)


1 loops, best of 3: 540 ms per loop

In [94]:
sph_harm?

In [134]:
qlm_w = boo.weave_qlm(pos, ngbs, inside)

In [201]:
qlm_c = cython_qlm(pos, ngbs, inside)

In [202]:
np.mean(np.abs(qlm_w - qlm_c)<1e-16)


Out[202]:
0.81391235399957307

In [187]:
qlm_w[0]


Out[187]:
array([ 0.04028486+0.j        ,  0.05799787+0.06639547j,
        0.04605032-0.09580622j, -0.05903408-0.0054351j ,
        0.13045725-0.20548051j, -0.18253487-0.07674777j,
        0.09087308+0.00445716j])

In [188]:
qlm_c[0]


Out[188]:
array([ 0.04028486+0.j        ,  0.05799787+0.06639547j,
        0.04605032-0.09580622j, -0.05903408-0.0054351j ,
        0.13045725-0.20548051j, -0.18253487-0.07674777j,
        0.09087308+0.00445716j])

In [183]:
sph_harm(0, 6, 3.685749891321086, 1.4481876153314692)


Out[183]:
(-0.22243770324198525+0j)

In [182]:
sph_harm?

In [117]:
from colloids import periodic

def cart2sph(cartesian):
    """Convert Cartesian coordinates [[x,y,z],] to spherical coordinates [[r,phi,theta],]
phi is cologitudinal and theta azimutal"""
    spherical = np.zeros_like(cartesian)
    #distances
    c2 = cartesian**2
    r2 = c2.sum(-1)
    spherical[:,0] = np.sqrt(r2)
    #work only on non-zero, non purely z vectors
    sel = (r2 > c2[:,0]) | (r2+1.0 > 1.0)
    x, y, z = cartesian[sel].T
    r = spherical[sel,0]
    #colatitudinal phi [0, pi[
    spherical[sel,1] = np.arccos(z/r)
    #azimutal (longitudinal) theta [0, 2pi[
    theta = np.arctan2(y, x)
    theta[theta<0] += 2*np.pi
    spherical[sel,2] = theta
    return spherical

def vect2Ylm(v, l):
    """Projects vectors v on the base of spherical harmonics of degree l."""
    spherical = cart2sph(v)
    return sph_harm(
        np.arange(l+1)[:,None], l, 
        spherical[:,2][None,:], 
        spherical[:,1][None,:]
        )

def bonds2qlm(pos, bonds, l=6, periods=-1):
    """Returns the qlm for every particle"""
    qlm = np.zeros((len(pos), l+1), np.complex128)
    #spherical harmonic coefficients for each bond
    Ylm = vect2Ylm(
        periodic.periodify(
            pos[bonds[:,0]],
            pos[bonds[:,1]],
            periods
        ),
        l
    ).T
    #bin bond into each particle belonging to it
    np.add.at(qlm, bonds[:,0], Ylm)
    np.add.at(qlm, bonds[:,1], Ylm)
    #divide by the number of bonds each particle belongs to
    Nngb = np.zeros(len(pos), int)
    np.add.at(Nngb, bonds.ravel(), 1)
    return qlm / np.maximum(1, Nngb)[:,None]

In [118]:
%timeit bonds2qlm(pos, bonds)


1 loops, best of 3: 528 ms per loop

In [115]:
from colloids import periodic
from math import acos, atan2

@jit(['float64[:,:](float64[:,:])'], nopython=True)
def cart2sph(cartesian):
    """Convert Cartesian coordinates [[x,y,z],] to spherical coordinates [[r,phi,theta],]
phi is cologitudinal and theta azimutal"""
    spherical = np.zeros_like(cartesian)
    #distances
    c2 = cartesian**2
    r2 = c2.sum(-1)
    spherical[:,0] = np.sqrt(r2)
    for i in range(len(cartesian)):
        #phi and theta are defined only on non-zero, non purely z vectors
        if r2[i] > c2[i,2] or r2[i]+1.0 > 1.0:
            #colatitudinal phi [0, pi[
            spherical[i,1] = acos(cartesian[i,2]/spherical[i,0])
            #azimutal (longitudinal) theta [0, 2pi[
            theta = atan2(cartesian[i,1], cartesian[i,0])
            if theta<0:
                theta += 2*np.pi
            spherical[i,2] = theta
    return spherical

#@jit(['complex128[:,:](float64[:,:], int64)'], nopython=True)
def vect2Ylm(v, l):
    """Projects vectors v on the base of spherical harmonics of degree l."""
    spherical = cart2sph(v)
    return sph_harm(
        np.arange(l+1)[:,None], l, 
        spherical[:,2][None,:], 
        spherical[:,1][None,:]
        )

def bonds2qlm(pos, bonds, l=6, periods=-1):
    """Returns the qlm for every particle"""
    qlm = np.zeros((len(pos), l+1), np.complex128)
    #spherical harmonic coefficients for each bond
    Ylm = vect2Ylm(
        periodic.periodify(
            pos[bonds[:,0]],
            pos[bonds[:,1]],
            periods
        ),
        l
    ).T
    #bin bond into each particle belonging to it
    np.add.at(qlm, bonds[:,0], Ylm)
    np.add.at(qlm, bonds[:,1], Ylm)
    #divide by the number of bonds each particle belongs to
    Nngb = np.zeros(len(pos), int)
    np.add.at(Nngb, bonds.ravel(), 1)
    return qlm / np.maximum(1, Nngb)[:,None]

In [116]:
%timeit bonds2qlm(pos, bonds)


1 loops, best of 3: 520 ms per loop

$w_\ell$

$$ w_\ell = \sum_{m_1+m_2+m_3=0} \left( \begin{array}{ccc} \ell & \ell & \ell \\ m_1 & m_2 & m_3 \end{array} \right) q_{\ell m_1} q_{\ell m_2} q_{\ell m_3} $$

In [5]:
qlm = boo.bonds2qlm(pos, bonds)

In [30]:
%timeit boo.wl(qlm)


10 loops, best of 3: 111 ms per loop

In [28]:
from colloids.boo import get_qlm, get_w3j
def python_wl(qlm):
    l = qlm.shape[1]-1
    w = np.zeros(qlm.shape[0])
    for m1 in range(-l, l+1):
        for m2 in range(-l, l+1):
            m3 = -m1-m2
            if -l<=m3 and m3<=l:
                w+= get_w3j(l, [m1, m2, m3]) * (get_qlm(qlm, m1) * get_qlm(qlm, m2) * get_qlm(qlm, m3)).real
    return w.real

In [29]:
%timeit python_wl(qlm)


10 loops, best of 3: 102 ms per loop

In [18]:
np.sum(boo.wl(qlm) - python_wl(qlm).real > 1e-12)


Out[18]:
0

In [23]:
@jit
def numba_wl(qlm):
    l = qlm.shape[1]-1
    w = np.zeros(qlm.shape[0])
    for m1 in range(-l, l+1):
        for m2 in range(-l, l+1):
            m3 = -m1-m2
            if -l<=m3 and m3<=l:
                w+= boo.get_w3j(l, [m1, m2, m3]) * (boo.get_qlm(qlm, m1) * boo.get_qlm(qlm, m2) * boo.get_qlm(qlm, m3)).real
    return w

In [24]:
%timeit numba_wl(qlm)


The slowest run took 7.13 times longer than the fastest. This could mean that an intermediate result is being cached 
1 loops, best of 3: 103 ms per loop

In [13]:
[len(it) for it in _w3j]


Out[13]:
[1, 4, 9, 16, 25, 36]

In [11]:
w3j = np.zeros([6,36])
w3j[0,0] = 1
w3j[1,:4] = np.sqrt([2/35., 1/70., 2/35., 3/35.])*[-1,1,1,-1]
w3j[2,:9] = np.sqrt([
        2/1001., 1/2002., 11/182., 5/1001.,
        7/286., 5/143., 14/143., 35/143., 5/143.,
        ])*[3, -3, -1/3.0, 2, 1, -1/3.0, 1/3.0, -1/3.0, 1]
w3j[3,:16] = np.sqrt([
        1/46189., 1/46189.,
        11/4199., 105/46189.,
        1/46189., 21/92378.,
        1/46189., 35/46189., 14/46189.,
        11/4199., 21/4199., 7/4199.,
        11/4199., 77/8398., 70/4199., 21/4199.
        ])*[-20, 10, 1, -2, -43/2.0, 3, 4, 2.5, -6, 2.5, -1.5, 1, 1, -1, 1, -2]
w3j[4,:25] = np.sqrt([
        10/96577., 5/193154.,
        1/965770., 14/96577.,
        1/965770., 66/482885.,
        5/193154., 3/96577., 77/482885.,
        65/14858., 5/7429., 42/37145.,
        65/14858., 0.0, 3/7429., 66/37145.,
        13/74290., 78/7429., 26/37145., 33/37145.,
        26/37145., 13/37145., 273/37145., 429/37145., 11/7429.,
        ])*[
            7, -7, -37, 6, 73, -3,
            -5, -8, 6, -1, 3, -1,
            1, 0, -3, 2, 7, -1, 3, -1,
            1, -3, 1, -1, 3]
w3j[5,:36] = np.sqrt([
        7/33393355., 7/33393355.,
        7/33393355., 462/6678671.,
        7/33393355., 1001/6678671.,
        1/233753485., 77/6678671., 6006/6678671.,
        1/233753485., 55/46750697., 1155/13357342.,
        1/233753485., 2926/1757545., 33/46750697., 3003/6678671.,
        119/1964315., 22/2750041., 1914/474145., 429/5500082.,
        17/13750205., 561/2750041., 77/392863., 143/27500410., 2002/392863.,
        323/723695., 1309/20677., 374/144739., 143/144739., 1001/206770.,
        323/723695., 7106/723695., 561/723695., 2431/723695., 2002/103385., 1001/103385.
        ])*[
            -126, 63, 196/3.0, -7, -259/2.0, 7/3.0,
            1097/3.0, 59/6.0, -2,
            4021/6.0, -113/2.0, 3,
            -914, 1/3.0, 48, -3,
            -7/3.0, 65/3.0, -1, 3,
            214/3.0, -3, -2/3.0, 71/3.0, -1,
            3, -1/3.0, 5/3.0, -2, 1/3.0,
            2/3.0, -1/3.0, 2, -4/3.0, 2/3.0, -1]

In [12]:
_w3j_m1_offset = np.array([0,1,2,4,6,9,12,16,20,25,30], int)

In [45]:
@jit#(['float64(int64, int64[:])'], nopython=True)
def get_w3j(l, ms):
    sm = np.sort(np.abs(ms))
    return w3j[l//2, _w3j_m1_offset[sm[-1]] + sm[0]]

@jit#(nopython=True)
#@guvectorize(['(complex128[:], int64[:], complex128[:])'], '(n),()->()', nopython=True)
#@vectorize(['complex128(complex128[:], int64)'], nopython=True)
def get_qlm(qlm, m):
    if m>=0:
        return qlm[...,m]
    elif (-m)%2 == 0:
        return np.conj(qlm[...,-m])
    else:
        return -np.conj(qlm[...,-m])

@jit#(nopython=True)
def wl(qlm):
    """Third order rotational invariant of the bond orientational order of l-fold symmetry
    $$ w_\ell = \sum_{m_1+m_2+m_3=0} 
			\left( \begin{array}{ccc}
				\ell & \ell & \ell \\
				m_1 & m_2 & m_3 
			\end{array} \right)
			q_{\ell m_1} q_{\ell m_2} q_{\ell m_3}
			$$"""
    l = qlm.shape[-1]-1
    w = np.zeros(qlm.shape[:-1])
    for m1 in range(-l, l+1):
        for m2 in range(-l, l+1):
            m3 = -m1-m2
            if -l<=m3 and m3<=l:
                w+= get_w3j(l, np.array([m1, m2, m3])) * (get_qlm(qlm, m1) * get_qlm(qlm, m2) * get_qlm(qlm, m3)).real
    return w

In [59]:
%timeit wl(qlm)


10 loops, best of 3: 70.9 ms per loop

In [49]:
wl(qlm[0]),wl(qlm[:1])


Out[49]:
(array(-0.00653615192457933), array([-0.00653615]))

In [69]:
reload(boo)


Out[69]:
<module 'colloids.boo' from '/data/mleocmach/src/colloids/python/colloids/boo.py'>

In [70]:
%timeit boo.wl(qlm)


The slowest run took 21.15 times longer than the fastest. This could mean that an intermediate result is being cached 
1 loops, best of 3: 71 ms per loop

BOO product


In [22]:
def boo_product(qlm1, qlm2):
    """Product between two qlm"""
    n = np.atleast_2d(numexpr.evaluate(
        """real(complex(real(a), -imag(a)) * b)""",
        {'a':qlm1, 'b':qlm2}
        ))
    p = numexpr.evaluate(
        """4*pi/(2*l+1)*(2*na + nb)""",
        {
            'na': n[:,1:].sum(-1),
            'nb': n[:,0],
            'l': n.shape[1]-1,
            'pi': np.pi
            })
    return p

In [23]:
boo_product(qlm[0], qlm[1])


Out[23]:
array([-0.09042815])

In [26]:
%timeit boo_product(qlm[0], qlm[1])


The slowest run took 4.43 times longer than the fastest. This could mean that an intermediate result is being cached 
10000 loops, best of 3: 71.1 µs per loop

In [27]:
%timeit boo_product(qlm[:1000], qlm[-1000:])


1000 loops, best of 3: 256 µs per loop

In [30]:
def numpy_boo_product(qlm1, qlm2):
    """Product between two qlm"""
    n = np.atleast_2d((qlm1 * np.conj(qlm2)).real)
    l = n.shape[1]-1
    return 4*np.pi/(2*l+1)*(2*n[:,1:].sum(-1) + n[:,0])

In [31]:
numpy_boo_product(qlm[0], qlm[1])


Out[31]:
array([-0.09042815])

In [32]:
%timeit numpy_boo_product(qlm[0], qlm[1])


The slowest run took 7.79 times longer than the fastest. This could mean that an intermediate result is being cached 
10000 loops, best of 3: 20.3 µs per loop

In [33]:
%timeit numpy_boo_product(qlm[:1000], qlm[-1000:])


The slowest run took 4.21 times longer than the fastest. This could mean that an intermediate result is being cached 
10000 loops, best of 3: 94.2 µs per loop

In [119]:
@jit([
    "float64[:](complex128[:,:], complex128[:,:])", 
    "float64[:](complex128[:], complex128[:])",
    "float64[:](complex128[:], complex128[:,:])",
    "float64[:](complex128[:,:], complex128[:])"
    ], nopython=True)
def numba_boo_product(qlm1, qlm2):
    """Product between two qlm"""
    n = np.atleast_2d((qlm1 * np.conj(qlm2)).real)
    l = n.shape[1]-1
    return 4*np.pi/(2*l+1)*(2*n[:,1:].sum(-1) + n[:,0])

In [120]:
numba_boo_product(qlm[0], qlm[1])


Out[120]:
array([-0.09042815])

In [121]:
%timeit numba_boo_product(qlm[0], qlm[1])


The slowest run took 12.54 times longer than the fastest. This could mean that an intermediate result is being cached 
100000 loops, best of 3: 3.12 µs per loop

In [122]:
%timeit numba_boo_product(qlm[:1000], qlm[-1000:])


10000 loops, best of 3: 58.6 µs per loop

In [123]:
%timeit numba_boo_product(qlm[0], qlm[-1000:])


10000 loops, best of 3: 52 µs per loop

In [124]:
%timeit numba_boo_product(qlm[:1000], qlm[-1])


10000 loops, best of 3: 47.4 µs per loop

In [125]:
from numba import guvectorize
@guvectorize(['void(complex128[:], complex128[:], float64[:])'], '(n),(n)->()', nopython=True)
def numba2_boo_product(qlm1, qlm2, prod):
    """Product between two qlm"""
    l = qlm1.shape[0]-1
    prod[0] = (qlm1[0] * qlm2[0].conjugate()).real
    for i in range(1, len(qlm1)):
        prod[0] += 2 * (qlm1[i] * qlm2[i].conjugate()).real
    prod[0] *= 4*np.pi/(2*l+1)

In [126]:
numba2_boo_product(qlm[0], qlm[1])


Out[126]:
-0.090428150978496991

In [127]:
%timeit numba2_boo_product(qlm[0], qlm[1])


The slowest run took 22.88 times longer than the fastest. This could mean that an intermediate result is being cached 
100000 loops, best of 3: 2.14 µs per loop

In [128]:
%timeit numba2_boo_product(qlm[:1000], qlm[-1000:])


The slowest run took 4.26 times longer than the fastest. This could mean that an intermediate result is being cached 
10000 loops, best of 3: 21.1 µs per loop

In [129]:
%timeit numba2_boo_product(qlm[0], qlm[-1000:])


The slowest run took 4.46 times longer than the fastest. This could mean that an intermediate result is being cached 
100000 loops, best of 3: 19.4 µs per loop

In [130]:
%timeit numba2_boo_product(qlm[:1000], qlm[-1])


The slowest run took 5.36 times longer than the fastest. This could mean that an intermediate result is being cached 
10000 loops, best of 3: 19.2 µs per loop

In [149]:
@jit(nopython=True)
def numba3_boo_product(qlm1, qlm2):
    """Product between two qlm"""
    l = qlm1.shape[-1]-1
    prod = (qlm1[...,0] * np.conj(qlm2[...,0])).real
    prod += 2 * (qlm1[...,1:] * np.conj(qlm2[...,1:])).real.sum(-1)
    return 4 * np.pi / (2 * l + 1) * prod

In [150]:
numba3_boo_product(qlm[0], qlm[1])


Out[150]:
-0.09042815097849699

In [151]:
%timeit numba3_boo_product(qlm[0], qlm[1])


The slowest run took 16.53 times longer than the fastest. This could mean that an intermediate result is being cached 
100000 loops, best of 3: 2.24 µs per loop

In [153]:
%timeit numba3_boo_product(qlm[:1000], qlm[-1000:])


10000 loops, best of 3: 86.1 µs per loop

In [147]:
%timeit numba3_boo_product(qlm[0], qlm[-1000:])


10000 loops, best of 3: 47.4 µs per loop

In [148]:
%timeit numba3_boo_product(qlm[:1000], qlm[-1])


10000 loops, best of 3: 48.8 µs per loop

$q_\ell$


In [81]:
@vectorize#(['float64(complex128)', 'float32(complex64)'])
def abs2(x):
    return x.real**2 + x.imag**2

def ql(qlm):
    """Second order rotational invariant of the bond orientational order of l-fold symmetry
    $$ q_\ell = \sqrt{\frac{4\pi}{2l+1} \sum_{m=-\ell}^{\ell} |q_{\ell m}|^2 } $$"""
    q = abs2(qlm[:,0])
    q += 2*abs2(qlm[:,1:]).sum(-1)
    l = qlm.shape[1]-1
    return np.sqrt(4*np.pi / (2*l+1) * q)

In [83]:
%timeit ql(qlm)


100 loops, best of 3: 2.02 ms per loop

In [87]:
@jit(nopython=True)
def numba_ql(qlm):
    """Second order rotational invariant of the bond orientational order of l-fold symmetry
    $$ q_\ell = \sqrt{\frac{4\pi}{2l+1} \sum_{m=-\ell}^{\ell} |q_{\ell m}|^2 } $$"""
    q = abs2(qlm[...,0])
    q += 2*abs2(qlm[...,1:]).sum(-1)
    l = qlm.shape[-1]-1
    return np.sqrt(4*np.pi / (2*l+1) * q)

In [89]:
%timeit numba_ql(qlm)


1000 loops, best of 3: 1.52 ms per loop

In [90]:
reload(boo)


Out[90]:
<module 'colloids.boo' from '/data/mleocmach/src/colloids/python/colloids/boo.py'>

In [92]:
%timeit boo.ql(qlm)


1000 loops, best of 3: 1.52 ms per loop

Coarse-graining


In [6]:
def coarsegrain_qlm(qlm, bonds, inside):
    """Coarse grain the bond orientational order on the neighbourhood of a particle
    $$Q_{\ell m}(i) = \frac{1}{N_i+1}\left( q_{\ell m}(i) +  \sum_{j=0}^{N_i} q_{\ell m}(j)\right)$$
    Returns Qlm and the mask of the valid particles
    """
    #Valid particles must be valid themselves have only valid neighbours
    inside2 = np.copy(inside)
    np.bitwise_and.at(inside2, bonds[:,0], inside[bonds[:,1]])
    np.bitwise_and.at(inside2, bonds[:,1], inside[bonds[:,0]])
    #number of neighbours
    Nngb = np.zeros(len(qlm), int)
    np.add.at(Nngb, bonds.ravel(), 1)
    #sum the boo coefficients of all the neighbours
    Qlm = np.zeros_like(qlm)
    np.add.at(Qlm, bonds[:,0], qlm[bonds[:,1]])
    np.add.at(Qlm, bonds[:,1], qlm[bonds[:,0]])
    Qlm[np.bitwise_not(inside2)] = 0
    return Qlm / np.maximum(1, Nngb)[:,None], inside2

In [7]:
Qlm, inside2 = coarsegrain_qlm(qlm, bonds, inside)

In [8]:
%timeit coarsegrain_qlm(qlm, bonds, inside)


1 loops, best of 3: 225 ms per loop

In [14]:
@jit
def numba_coarsegrain_qlm(qlm, bonds, inside):
    """Coarse grain the bond orientational order on the neighbourhood of a particle
    $$Q_{\ell m}(i) = \frac{1}{N_i+1}\left( q_{\ell m}(i) +  \sum_{j=0}^{N_i} q_{\ell m}(j)\right)$$
    Returns Qlm and the mask of the valid particles
    """
    #Valid particles must be valid themselves have only valid neighbours
    inside2 = np.copy(inside)
    np.bitwise_and.at(inside2, bonds[:,0], inside[bonds[:,1]])
    np.bitwise_and.at(inside2, bonds[:,1], inside[bonds[:,0]])
    #number of neighbours
    Nngb = np.zeros(len(qlm), int)
    np.add.at(Nngb, bonds.ravel(), 1)
    #sum the boo coefficients of all the neighbours
    Qlm = np.zeros_like(qlm)
    np.add.at(Qlm, bonds[:,0], qlm[bonds[:,1]])
    np.add.at(Qlm, bonds[:,1], qlm[bonds[:,0]])
    Qlm[np.bitwise_not(inside2)] = 0
    return Qlm / np.maximum(1, Nngb)[:,None], inside2

In [15]:
%timeit numba_coarsegrain_qlm(qlm, bonds, inside)


The slowest run took 5.83 times longer than the fastest. This could mean that an intermediate result is being cached 
1 loops, best of 3: 228 ms per loop

Spatial correlation


In [16]:
maxdist = 30.0
bounds = np.vstack((pos[inside2].min(0)+maxdist, pos[inside2].max(0)-maxdist))
is_center = (pos>bounds[0]).min(1) & (pos<bounds[1]).min(1)

In [59]:
hq, hQ, g = boo.gG_l(pos, qlm, Qlm, is_center, Nbins=250, maxdist=30.0)

In [60]:
plt.plot(hq, label='hq')
plt.plot(hQ, label='hQ')
plt.plot(g, label='g')
plt.legend()


Out[60]:
<matplotlib.legend.Legend at 0x7f7a9cb82f50>

In [71]:
good = g>1
plt.plot(np.where(good)[0], hq[good]/g[good], label='hq/g')
plt.plot(np.where(good)[0], hQ[good]/g[good], label='hQ/g')
plt.yscale('log')
plt.legend()


Out[71]:
<matplotlib.legend.Legend at 0x7f7a9cbb17d0>

In [255]:
%timeit boo.gG_l(pos, qlm, Qlm, is_center, Nbins=250, maxdist=30.0)


1 loops, best of 3: 854 ms per loop

In [66]:
maxdist = 60.0
bounds = np.vstack((pos[inside2].min(0)+maxdist, pos[inside2].max(0)-maxdist))
is_center2 = (pos>bounds[0]).min(1) & (pos<bounds[1]).min(1)

In [67]:
hq2, hQ2, g2 = boo.gG_l(pos, qlm, Qlm, is_center2, Nbins=250, maxdist=60.0)

In [68]:
plt.plot(hq2, label='hq')
plt.plot(hQ2, label='hQ')
plt.plot(g2, label='g')
plt.legend()


Out[68]:
<matplotlib.legend.Legend at 0x7f7a9ca46f50>

In [70]:
good = g2>1
plt.plot(np.where(good)[0], hq2[good]/g2[good], label='hq/g')
plt.plot(np.where(good)[0], hQ2[good]/g2[good], label='hQ/g')
plt.yscale('log')
plt.legend()


Out[70]:
<matplotlib.legend.Legend at 0x7f7a9c8fd410>

In [45]:
%timeit boo.gG_l(pos, qlm, Qlm, is_center2, Nbins=1000, maxdist=120.0)


1 loops, best of 3: 1.15 s per loop

In [106]:
from scipy.spatial import cKDTree as KDTree
from colloids.boo import boo_product

def gG_l(pos, qlms, Qlms, is_center, Nbins, maxdist):
    """Spatial correlation of the qlms and the Qlms (non normalized.
    For each particle tagged as is_center, do the cross product between their qlm, their Qlm and count, 
    then bin each quantity with respect to distance. 
    The two first sums need to be normalised by the last one.
    
     - pos is a Nxd array of coordinates, with d the dimension of space
     - qlm is a Nx(2l+1) array of boo coordinates for l-fold symmetry
     - Qlm is the coarse-grained version of qlm
     - is_center is a N array of booleans. For example all particles further away than maxdist from any edge of the box.
     - Nbins is the number of bins along r
     - maxdist is the maximum distance considered"""
    assert len(pos) == len(qlms)
    assert len(qlms) == len(Qlms)
    assert len(is_center) == len(pos)
    maxsq = float(maxdist**2)
    hQ = np.zeros(Nbins)
    hq = np.zeros(Nbins)
    g = np.zeros(Nbins, int)
    #spatial indexing
    tree = KDTree(pos, 12)
    for i in np.where(is_center)[0]:
        js = np.array(tree.query_ball_point(pos[i], maxdist))
        js = js[js!=i]
        rs = np.sqrt(np.sum((pos[js] - pos[i])**2, -1)) / maxdist * g.shape[0]
        pqs = boo_product(qlms[i][None,:], qlms[js])
        pQs = boo_product(Qlms[i][None,:], Qlms[js])
        np.add.at(g, rs.astype(int), 1)
        np.add.at(hq, rs.astype(int), pqs)
        np.add.at(hQ, rs.astype(int), pQs)
    return hq, hQ, g

In [102]:
hq1, hQ1, g1 = gG_l(pos, qlm, Qlm, is_center, Nbins=250, maxdist=30.0)

In [84]:
plt.plot(hq, label='hq')
plt.plot(hQ, label='hQ')
plt.plot(g, label='g')
plt.plot(hq1, ls=':', label='hq1')
plt.plot(hQ1, ls=':', label='hQ1')
plt.plot(g1, ls=':', label='g1')
plt.legend()


Out[84]:
<matplotlib.legend.Legend at 0x7f7a67fdf1d0>

In [86]:
np.abs(g - g1).max(), np.abs(hq - hq1).max(), np.abs(hQ - hQ1).max()


Out[86]:
(0, 1.2505552149377763e-11, 7.0485839387401938e-12)

In [96]:
%timeit gG_l(pos, qlm, Qlm, is_center, Nbins=250, maxdist=30.0)


1 loops, best of 3: 5.98 s per loop

In [92]:
%timeit boo.gG_l(pos, qlm, Qlm, is_center2, Nbins=1000, maxdist=120.0)


1 loops, best of 3: 19.3 s per loop

In [235]:
def gG_l_tree(pos, qlms, Qlms, is_center, Nbins, maxdist):
    """Spatial correlation of the qlms and the Qlms (non normalized.
    For each particle tagged as is_center, do the cross product between their qlm, their Qlm and count, 
    then bin each quantity with respect to distance. 
    The two first sums need to be normalised by the last one.
    
     - pos is a Nxd array of coordinates, with d the dimension of space
     - qlm is a Nx(2l+1) array of boo coordinates for l-fold symmetry
     - Qlm is the coarse-grained version of qlm
     - is_center is a N array of booleans. For example all particles further away than maxdist from any edge of the box.
     - Nbins is the number of bins along r
     - maxdist is the maximum distance considered"""
    assert len(pos) == len(qlms)
    assert len(qlms) == len(Qlms)
    assert len(is_center) == len(pos)
    rsq2r = np.sqrt(np.arange(Nbins**2)).astype(int)
    l2r = float((Nbins/maxdist)**2)
    #maxsq = float(maxdist**2)
    hQ = np.zeros(Nbins)
    hq = np.zeros(Nbins)
    g = np.zeros(Nbins, int)
    #spatial indexing
    tree = KDTree(pos, 12)
    centertree = KDTree(pos[is_center], 12)
    for i, js in zip(np.where(is_center)[0], centertree.query_ball_tree(tree, maxdist)):
    #for i in np.where(is_center)[0]:
        #js = np.array(tree.query_ball_point(pos[i], maxdist))
        js = np.array(js)
        js = js[js!=i]
        #rs = np.sqrt(np.sum((pos[js] - pos[i])**2, -1)) / maxdist * g.shape[0]
        #rsqs = numexpr.evaluate('sum((a-b)**2, axis=1)', {'a':pos[js], 'b':pos[i]}) * l2r
        rsqs = np.sum((pos[js] - pos[i])**2, -1) * l2r
        rs = rsq2r[rsqs.astype(int)]
        pqs = boo_product(qlms[i][None,:], qlms[js])
        #pQs = boo_product(Qlms[i][None,:], Qlms[js])
        np.add.at(g, rs, 1)
        np.add.at(hq, rs.astype(int), pqs)
        #np.add.at(hQ, rs.astype(int), pQs)
    return hq, hQ, g

In [236]:
%timeit gG_l_tree(pos, qlm, Qlm, is_center, Nbins=250, maxdist=30.0)


1 loops, best of 3: 4.16 s per loop

In [266]:
def gG_l_record(pos, qlms, Qlms, is_center, Nbins, maxdist):
    """Spatial correlation of the qlms and the Qlms (non normalized.
    For each particle tagged as is_center, do the cross product between their qlm, their Qlm and count, 
    then bin each quantity with respect to distance. 
    The two first sums need to be normalised by the last one.
    
     - pos is a Nxd array of coordinates, with d the dimension of space
     - qlm is a Nx(2l+1) array of boo coordinates for l-fold symmetry
     - Qlm is the coarse-grained version of qlm
     - is_center is a N array of booleans. For example all particles further away than maxdist from any edge of the box.
     - Nbins is the number of bins along r
     - maxdist is the maximum distance considered"""
    assert len(pos) == len(qlms)
    assert len(qlms) == len(Qlms)
    assert len(is_center) == len(pos)
    #conversion factor between indices and bins
    l2r = Nbins/maxdist
    #result containers
    hqQ = np.zeros((Nbins,2)) 
    g = np.zeros(Nbins, int)
    #spatial indexing
    tree = KDTree(pos, 12)
    centertree = KDTree(pos[is_center], 12)
    #all pairs of points closer than maxdist with their distances in a record array
    query = centertree.sparse_distance_matrix(tree, maxdist, output_type='ndarray')
    #keep only pairs where the points are distinct
    centerindex = np.where(is_center)[0]
    query['i'] = centerindex[query['i']]
    good = query['i'] != query['j']
    query = query[good]
    #binning of distances
    rs = (query['v'] * l2r).astype(int)
    np.add.at(g, rs, 1)
    #binning of boo cross products
    pqQs = np.empty((len(rs),2))
    pqQs[:,0] = boo_product(qlms[query['i']], qlms[query['j']])
    pqQs[:,1] = boo_product(Qlms[query['i']], Qlms[query['j']])
    np.add.at(hqQ, rs, pqQs)
    return hqQ[:,0], hqQ[:,1], g

In [267]:
hq3, hQ3, g3 = gG_l_record(pos, qlm, Qlm, is_center, Nbins=250, maxdist=30.0)
plt.subplot(1,3,1)
plt.plot(g)
plt.plot(g3, ls=':')
plt.subplot(1,3,2)
plt.plot(hq, label='hq')
plt.plot(hq3, ls=':', label='hq3')
plt.subplot(1,3,3)
plt.plot(hQ, label='hQ')
plt.plot(hQ3, ls=':', label='hQ3')


Out[267]:
[<matplotlib.lines.Line2D at 0x7f7a5fc74b50>]

In [268]:
%timeit gG_l_record(pos, qlm, Qlm, is_center, Nbins=250, maxdist=30.0)


1 loops, best of 3: 1.14 s per loop

In [212]:
%debug


> <ipython-input-210-923716ae9c93>(27)gG_l_record()
     26     query = centertree.sparse_distance_matrix(tree, maxdist, output_type='ndarray')
---> 27     query.i = centerindex[query.i]
     28     good = query.j != query.i

ipdb> query.dtype
dtype([('i', '<i8'), ('j', '<i8'), ('v', '<f8')], align=True)
ipdb> query['i'].shape
(962782,)
ipdb> q

In [51]:
%%cython --annotate
import numpy as np
cimport numpy as np
cimport cython
from libc.math cimport sqrt

from scipy.spatial import cKDTree as KDTree
#from scipy.spatial cimport cKDTree as KDTree
from colloids import particles, boo
from colloids.boo import boo_product

#_dtype = [('i',np.intp),('j',np.intp),('v',np.float64)]
#res_dtype = np.dtype(_dtype, align = True)
cdef packed struct ijdist:
    np.intp_t i,j
    np.float64_t v

@cython.boundscheck(False) # turn off bounds-checking for entire function
@cython.wraparound(False)  # turn off negative index wrapping for entire function
@cython.cdivision(True) # turn off division by zero checking for entire function
def cython_gG_l(
    np.ndarray[np.float64_t, ndim=2] pos, 
    qlms, Qlms, 
    is_center, 
    int Nbins, float maxdist):
    """Spatial correlation of the qlms and the Qlms (non normalized.
    For each particle tagged as is_center, do the cross product between their qlm, their Qlm and count, 
    then bin each quantity with respect to distance. 
    The two first sums need to be normalised by the last one.
    
     - pos is a Nxd array of coordinates, with d the dimension of space
     - qlm is a Nx(2l+1) array of boo coordinates for l-fold symmetry
     - Qlm is the coarse-grained version of qlm
     - is_center is a N array of booleans. For example all particles further away than maxdist from any edge of the box.
     - Nbins is the number of bins along r
     - maxdist is the maximum distance considered"""
    cdef int i,it,j,r
    cdef float rsq
    assert len(pos) == len(qlms)
    assert len(qlms) == len(Qlms)
    assert len(is_center) == len(pos)
    #cdef np.ndarray[np.int64_t, ndim=1]  rsq2r = np.sqrt(np.arange(Nbins**2)).astype(int)
    cdef float l2r = (Nbins/maxdist)#**2
    #maxsq = float(maxdist**2)
    hQ = np.zeros(Nbins)
    hq = np.zeros(Nbins)
    g = np.zeros(Nbins, int)
    #spatial indexing
    tree = KDTree(pos, 12)
    centertree = KDTree(pos[is_center], 12)
    centerindex = np.where(is_center)[0]
    cdef np.ndarray[ijdist, ndim=1] query = centertree.sparse_distance_matrix(tree, maxdist, output_type='ndarray')
    for it in range(query.shape[0]):
        i = centerindex[query[it].i]
        if i==query[it].j:
            continue
        r = int(l2r * query[it].v)
        g[r] += 1
    return hq, hQ, g


In file included from /home/mathieu/anaconda3/envs/python2/lib/python2.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1809:0,
                 from /home/mathieu/anaconda3/envs/python2/lib/python2.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:18,
                 from /home/mathieu/anaconda3/envs/python2/lib/python2.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,
                 from /data/mleocmach/.cache/ipython/cython/_cython_magic_92e8e937093c0f873c54cd3f5518d67b.c:257:
/home/mathieu/anaconda3/envs/python2/lib/python2.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:15:2: warning: #warning "Using deprecated NumPy API, disable it by " "#defining NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION" [-Wcpp]
 #warning "Using deprecated NumPy API, disable it by " \
  ^
In file included from /home/mathieu/anaconda3/envs/python2/lib/python2.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:27:0,
                 from /home/mathieu/anaconda3/envs/python2/lib/python2.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,
                 from /data/mleocmach/.cache/ipython/cython/_cython_magic_92e8e937093c0f873c54cd3f5518d67b.c:257:
/home/mathieu/anaconda3/envs/python2/lib/python2.7/site-packages/numpy/core/include/numpy/__multiarray_api.h:1453:1: warning: ‘_import_array’ defined but not used [-Wunused-function]
 _import_array(void)
 ^
Out[51]:
Cython: _cython_magic_92e8e937093c0f873c54cd3f5518d67b.pyx

Generated by Cython 0.23.4

Yellow lines hint at Python interaction.
Click on a line that starts with a "+" to see the C code that Cython generated for it.

+01: import numpy as np
  __pyx_t_1 = __Pyx_Import(__pyx_n_s_numpy, 0, -1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_np, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* … */
  __pyx_t_2 = PyDict_New(); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_2);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 02: cimport numpy as np
 03: cimport cython
 04: from libc.math cimport sqrt
 05: 
+06: from scipy.spatial import cKDTree as KDTree
  __pyx_t_1 = PyList_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_1);
  __Pyx_INCREF(__pyx_n_s_cKDTree);
  __Pyx_GIVEREF(__pyx_n_s_cKDTree);
  PyList_SET_ITEM(__pyx_t_1, 0, __pyx_n_s_cKDTree);
  __pyx_t_2 = __Pyx_Import(__pyx_n_s_scipy_spatial, __pyx_t_1, -1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_1 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_cKDTree); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_KDTree, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 07: #from scipy.spatial cimport cKDTree as KDTree
+08: from colloids import particles, boo
  __pyx_t_2 = PyList_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_INCREF(__pyx_n_s_particles);
  __Pyx_GIVEREF(__pyx_n_s_particles);
  PyList_SET_ITEM(__pyx_t_2, 0, __pyx_n_s_particles);
  __Pyx_INCREF(__pyx_n_s_boo);
  __Pyx_GIVEREF(__pyx_n_s_boo);
  PyList_SET_ITEM(__pyx_t_2, 1, __pyx_n_s_boo);
  __pyx_t_1 = __Pyx_Import(__pyx_n_s_colloids, __pyx_t_2, -1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_1);
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_1, __pyx_n_s_particles); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_2);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_particles, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_1, __pyx_n_s_boo); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_2);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_boo, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+09: from colloids.boo import boo_product
  __pyx_t_1 = PyList_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_1);
  __Pyx_INCREF(__pyx_n_s_boo_product);
  __Pyx_GIVEREF(__pyx_n_s_boo_product);
  PyList_SET_ITEM(__pyx_t_1, 0, __pyx_n_s_boo_product);
  __pyx_t_2 = __Pyx_Import(__pyx_n_s_colloids_boo, __pyx_t_1, -1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_1 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_boo_product); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_boo_product, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 10: 
 11: #_dtype = [('i',np.intp),('j',np.intp),('v',np.float64)]
 12: #res_dtype = np.dtype(_dtype, align = True)
 13: cdef packed struct ijdist:
 14:     np.intp_t i,j
 15:     np.float64_t v
 16: 
 17: @cython.boundscheck(False) # turn off bounds-checking for entire function
 18: @cython.wraparound(False)  # turn off negative index wrapping for entire function
 19: @cython.cdivision(True) # turn off division by zero checking for entire function
+20: def cython_gG_l(
/* Python wrapper */
static PyObject *__pyx_pw_46_cython_magic_92e8e937093c0f873c54cd3f5518d67b_1cython_gG_l(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
static char __pyx_doc_46_cython_magic_92e8e937093c0f873c54cd3f5518d67b_cython_gG_l[] = "Spatial correlation of the qlms and the Qlms (non normalized.\n    For each particle tagged as is_center, do the cross product between their qlm, their Qlm and count, \n    then bin each quantity with respect to distance. \n    The two first sums need to be normalised by the last one.\n    \n     - pos is a Nxd array of coordinates, with d the dimension of space\n     - qlm is a Nx(2l+1) array of boo coordinates for l-fold symmetry\n     - Qlm is the coarse-grained version of qlm\n     - is_center is a N array of booleans. For example all particles further away than maxdist from any edge of the box.\n     - Nbins is the number of bins along r\n     - maxdist is the maximum distance considered";
static PyMethodDef __pyx_mdef_46_cython_magic_92e8e937093c0f873c54cd3f5518d67b_1cython_gG_l = {"cython_gG_l", (PyCFunction)__pyx_pw_46_cython_magic_92e8e937093c0f873c54cd3f5518d67b_1cython_gG_l, METH_VARARGS|METH_KEYWORDS, __pyx_doc_46_cython_magic_92e8e937093c0f873c54cd3f5518d67b_cython_gG_l};
static PyObject *__pyx_pw_46_cython_magic_92e8e937093c0f873c54cd3f5518d67b_1cython_gG_l(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
  PyArrayObject *__pyx_v_pos = 0;
  PyObject *__pyx_v_qlms = 0;
  PyObject *__pyx_v_Qlms = 0;
  PyObject *__pyx_v_is_center = 0;
  int __pyx_v_Nbins;
  float __pyx_v_maxdist;
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("cython_gG_l (wrapper)", 0);
  {
    static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_pos,&__pyx_n_s_qlms,&__pyx_n_s_Qlms,&__pyx_n_s_is_center,&__pyx_n_s_Nbins,&__pyx_n_s_maxdist,0};
    PyObject* values[6] = {0,0,0,0,0,0};
    if (unlikely(__pyx_kwds)) {
      Py_ssize_t kw_args;
      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
      switch (pos_args) {
        case  6: values[5] = PyTuple_GET_ITEM(__pyx_args, 5);
        case  5: values[4] = PyTuple_GET_ITEM(__pyx_args, 4);
        case  4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
        case  3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
        case  0: break;
        default: goto __pyx_L5_argtuple_error;
      }
      kw_args = PyDict_Size(__pyx_kwds);
      switch (pos_args) {
        case  0:
        if (likely((values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_pos)) != 0)) kw_args--;
        else goto __pyx_L5_argtuple_error;
        case  1:
        if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_qlms)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("cython_gG_l", 1, 6, 6, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
        }
        case  2:
        if (likely((values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_Qlms)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("cython_gG_l", 1, 6, 6, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
        }
        case  3:
        if (likely((values[3] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_is_center)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("cython_gG_l", 1, 6, 6, 3); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
        }
        case  4:
        if (likely((values[4] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_Nbins)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("cython_gG_l", 1, 6, 6, 4); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
        }
        case  5:
        if (likely((values[5] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_maxdist)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("cython_gG_l", 1, 6, 6, 5); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
        }
      }
      if (unlikely(kw_args > 0)) {
        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "cython_gG_l") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
      }
    } else if (PyTuple_GET_SIZE(__pyx_args) != 6) {
      goto __pyx_L5_argtuple_error;
    } else {
      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
      values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
      values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
      values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
      values[4] = PyTuple_GET_ITEM(__pyx_args, 4);
      values[5] = PyTuple_GET_ITEM(__pyx_args, 5);
    }
    __pyx_v_pos = ((PyArrayObject *)values[0]);
    __pyx_v_qlms = values[1];
    __pyx_v_Qlms = values[2];
    __pyx_v_is_center = values[3];
    __pyx_v_Nbins = __Pyx_PyInt_As_int(values[4]); if (unlikely((__pyx_v_Nbins == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 24; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
    __pyx_v_maxdist = __pyx_PyFloat_AsFloat(values[5]); if (unlikely((__pyx_v_maxdist == (float)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 24; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
  }
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L5_argtuple_error:;
  __Pyx_RaiseArgtupleInvalid("cython_gG_l", 1, 6, 6, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
  __pyx_L3_error:;
  __Pyx_AddTraceback("_cython_magic_92e8e937093c0f873c54cd3f5518d67b.cython_gG_l", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_pos), __pyx_ptype_5numpy_ndarray, 1, "pos", 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 21; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __pyx_r = __pyx_pf_46_cython_magic_92e8e937093c0f873c54cd3f5518d67b_cython_gG_l(__pyx_self, __pyx_v_pos, __pyx_v_qlms, __pyx_v_Qlms, __pyx_v_is_center, __pyx_v_Nbins, __pyx_v_maxdist);
  int __pyx_lineno = 0;
  const char *__pyx_filename = NULL;
  int __pyx_clineno = 0;

  /* function exit code */
  goto __pyx_L0;
  __pyx_L1_error:;
  __pyx_r = NULL;
  __pyx_L0:;
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_46_cython_magic_92e8e937093c0f873c54cd3f5518d67b_cython_gG_l(CYTHON_UNUSED PyObject *__pyx_self, PyArrayObject *__pyx_v_pos, PyObject *__pyx_v_qlms, PyObject *__pyx_v_Qlms, PyObject *__pyx_v_is_center, int __pyx_v_Nbins, float __pyx_v_maxdist) {
  int __pyx_v_i;
  int __pyx_v_it;
  int __pyx_v_r;
  float __pyx_v_l2r;
  PyObject *__pyx_v_hQ = NULL;
  PyObject *__pyx_v_hq = NULL;
  PyObject *__pyx_v_g = NULL;
  PyObject *__pyx_v_tree = NULL;
  PyObject *__pyx_v_centertree = NULL;
  PyObject *__pyx_v_centerindex = NULL;
  PyArrayObject *__pyx_v_query = 0;
  __Pyx_LocalBuf_ND __pyx_pybuffernd_pos;
  __Pyx_Buffer __pyx_pybuffer_pos;
  __Pyx_LocalBuf_ND __pyx_pybuffernd_query;
  __Pyx_Buffer __pyx_pybuffer_query;
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("cython_gG_l", 0);
  __pyx_pybuffer_query.pybuffer.buf = NULL;
  __pyx_pybuffer_query.refcount = 0;
  __pyx_pybuffernd_query.data = NULL;
  __pyx_pybuffernd_query.rcbuffer = &__pyx_pybuffer_query;
  __pyx_pybuffer_pos.pybuffer.buf = NULL;
  __pyx_pybuffer_pos.refcount = 0;
  __pyx_pybuffernd_pos.data = NULL;
  __pyx_pybuffernd_pos.rcbuffer = &__pyx_pybuffer_pos;
  {
    __Pyx_BufFmt_StackElem __pyx_stack[1];
    if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_pos.rcbuffer->pybuffer, (PyObject*)__pyx_v_pos, &__Pyx_TypeInfo_nn___pyx_t_5numpy_float64_t, PyBUF_FORMAT| PyBUF_STRIDES, 2, 0, __pyx_stack) == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  }
  __pyx_pybuffernd_pos.diminfo[0].strides = __pyx_pybuffernd_pos.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_pos.diminfo[0].shape = __pyx_pybuffernd_pos.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_pos.diminfo[1].strides = __pyx_pybuffernd_pos.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_pos.diminfo[1].shape = __pyx_pybuffernd_pos.rcbuffer->pybuffer.shape[1];
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_3);
  __Pyx_XDECREF(__pyx_t_4);
  __Pyx_XDECREF(__pyx_t_5);
  __Pyx_XDECREF(__pyx_t_6);
  __Pyx_XDECREF(__pyx_t_7);
  { PyObject *__pyx_type, *__pyx_value, *__pyx_tb;
    __Pyx_ErrFetch(&__pyx_type, &__pyx_value, &__pyx_tb);
    __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_pos.rcbuffer->pybuffer);
    __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_query.rcbuffer->pybuffer);
  __Pyx_ErrRestore(__pyx_type, __pyx_value, __pyx_tb);}
  __Pyx_AddTraceback("_cython_magic_92e8e937093c0f873c54cd3f5518d67b.cython_gG_l", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  goto __pyx_L2;
  __pyx_L0:;
  __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_pos.rcbuffer->pybuffer);
  __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_query.rcbuffer->pybuffer);
  __pyx_L2:;
  __Pyx_XDECREF(__pyx_v_hQ);
  __Pyx_XDECREF(__pyx_v_hq);
  __Pyx_XDECREF(__pyx_v_g);
  __Pyx_XDECREF(__pyx_v_tree);
  __Pyx_XDECREF(__pyx_v_centertree);
  __Pyx_XDECREF(__pyx_v_centerindex);
  __Pyx_XDECREF((PyObject *)__pyx_v_query);
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
/* … */
  __pyx_tuple__7 = PyTuple_Pack(19, __pyx_n_s_pos, __pyx_n_s_qlms, __pyx_n_s_Qlms, __pyx_n_s_is_center, __pyx_n_s_Nbins, __pyx_n_s_maxdist, __pyx_n_s_i, __pyx_n_s_it, __pyx_n_s_j, __pyx_n_s_r, __pyx_n_s_rsq, __pyx_n_s_l2r, __pyx_n_s_hQ, __pyx_n_s_hq, __pyx_n_s_g, __pyx_n_s_tree, __pyx_n_s_centertree, __pyx_n_s_centerindex, __pyx_n_s_query); if (unlikely(!__pyx_tuple__7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_tuple__7);
  __Pyx_GIVEREF(__pyx_tuple__7);
/* … */
  __pyx_t_2 = PyCFunction_NewEx(&__pyx_mdef_46_cython_magic_92e8e937093c0f873c54cd3f5518d67b_1cython_gG_l, NULL, __pyx_n_s_cython_magic_92e8e937093c0f873c); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_2);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_cython_gG_l, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 21:     np.ndarray[np.float64_t, ndim=2] pos,
 22:     qlms, Qlms,
 23:     is_center,
 24:     int Nbins, float maxdist):
 25:     """Spatial correlation of the qlms and the Qlms (non normalized.
 26:     For each particle tagged as is_center, do the cross product between their qlm, their Qlm and count, 
 27:     then bin each quantity with respect to distance. 
 28:     The two first sums need to be normalised by the last one.
 29:     
 30:      - pos is a Nxd array of coordinates, with d the dimension of space
 31:      - qlm is a Nx(2l+1) array of boo coordinates for l-fold symmetry
 32:      - Qlm is the coarse-grained version of qlm
 33:      - is_center is a N array of booleans. For example all particles further away than maxdist from any edge of the box.
 34:      - Nbins is the number of bins along r
 35:      - maxdist is the maximum distance considered"""
 36:     cdef int i,it,j,r
 37:     cdef float rsq
+38:     assert len(pos) == len(qlms)
  #ifndef CYTHON_WITHOUT_ASSERTIONS
  if (unlikely(!Py_OptimizeFlag)) {
    __pyx_t_1 = PyObject_Length(((PyObject *)__pyx_v_pos)); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __pyx_t_2 = PyObject_Length(__pyx_v_qlms); if (unlikely(__pyx_t_2 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    if (unlikely(!((__pyx_t_1 == __pyx_t_2) != 0))) {
      PyErr_SetNone(PyExc_AssertionError);
      {__pyx_filename = __pyx_f[0]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    }
  }
  #endif
+39:     assert len(qlms) == len(Qlms)
  #ifndef CYTHON_WITHOUT_ASSERTIONS
  if (unlikely(!Py_OptimizeFlag)) {
    __pyx_t_2 = PyObject_Length(__pyx_v_qlms); if (unlikely(__pyx_t_2 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 39; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __pyx_t_1 = PyObject_Length(__pyx_v_Qlms); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 39; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    if (unlikely(!((__pyx_t_2 == __pyx_t_1) != 0))) {
      PyErr_SetNone(PyExc_AssertionError);
      {__pyx_filename = __pyx_f[0]; __pyx_lineno = 39; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    }
  }
  #endif
+40:     assert len(is_center) == len(pos)
  #ifndef CYTHON_WITHOUT_ASSERTIONS
  if (unlikely(!Py_OptimizeFlag)) {
    __pyx_t_1 = PyObject_Length(__pyx_v_is_center); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __pyx_t_2 = PyObject_Length(((PyObject *)__pyx_v_pos)); if (unlikely(__pyx_t_2 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    if (unlikely(!((__pyx_t_1 == __pyx_t_2) != 0))) {
      PyErr_SetNone(PyExc_AssertionError);
      {__pyx_filename = __pyx_f[0]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    }
  }
  #endif
 41:     #cdef np.ndarray[np.int64_t, ndim=1]  rsq2r = np.sqrt(np.arange(Nbins**2)).astype(int)
+42:     cdef float l2r = (Nbins/maxdist)#**2
  __pyx_v_l2r = (__pyx_v_Nbins / __pyx_v_maxdist);
 43:     #maxsq = float(maxdist**2)
+44:     hQ = np.zeros(Nbins)
  __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_4);
  __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_zeros); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_5);
  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
  __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_Nbins); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_4);
  __pyx_t_6 = NULL;
  if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_5))) {
    __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_5);
    if (likely(__pyx_t_6)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5);
      __Pyx_INCREF(__pyx_t_6);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_5, function);
    }
  }
  if (!__pyx_t_6) {
    __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_4); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
    __Pyx_GOTREF(__pyx_t_3);
  } else {
    __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_GOTREF(__pyx_t_7);
    __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __pyx_t_6 = NULL;
    __Pyx_GIVEREF(__pyx_t_4);
    PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_4);
    __pyx_t_4 = 0;
    __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_7, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_GOTREF(__pyx_t_3);
    __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
  }
  __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
  __pyx_v_hQ = __pyx_t_3;
  __pyx_t_3 = 0;
+45:     hq = np.zeros(Nbins)
  __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_5);
  __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_zeros); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_7);
  __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
  __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_Nbins); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_5);
  __pyx_t_4 = NULL;
  if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_7))) {
    __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_7);
    if (likely(__pyx_t_4)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7);
      __Pyx_INCREF(__pyx_t_4);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_7, function);
    }
  }
  if (!__pyx_t_4) {
    __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_5); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
    __Pyx_GOTREF(__pyx_t_3);
  } else {
    __pyx_t_6 = PyTuple_New(1+1); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_GOTREF(__pyx_t_6);
    __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_4); __pyx_t_4 = NULL;
    __Pyx_GIVEREF(__pyx_t_5);
    PyTuple_SET_ITEM(__pyx_t_6, 0+1, __pyx_t_5);
    __pyx_t_5 = 0;
    __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_6, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_GOTREF(__pyx_t_3);
    __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
  }
  __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
  __pyx_v_hq = __pyx_t_3;
  __pyx_t_3 = 0;
+46:     g = np.zeros(Nbins, int)
  __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 46; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_7);
  __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_zeros); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 46; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_6);
  __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
  __pyx_t_7 = __Pyx_PyInt_From_int(__pyx_v_Nbins); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 46; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_7);
  __pyx_t_5 = NULL;
  __pyx_t_2 = 0;
  if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_6))) {
    __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_6);
    if (likely(__pyx_t_5)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6);
      __Pyx_INCREF(__pyx_t_5);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_6, function);
      __pyx_t_2 = 1;
    }
  }
  __pyx_t_4 = PyTuple_New(2+__pyx_t_2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 46; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_4);
  if (__pyx_t_5) {
    __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_5); __pyx_t_5 = NULL;
  }
  __Pyx_GIVEREF(__pyx_t_7);
  PyTuple_SET_ITEM(__pyx_t_4, 0+__pyx_t_2, __pyx_t_7);
  __Pyx_INCREF(((PyObject *)(&PyInt_Type)));
  __Pyx_GIVEREF(((PyObject *)(&PyInt_Type)));
  PyTuple_SET_ITEM(__pyx_t_4, 1+__pyx_t_2, ((PyObject *)(&PyInt_Type)));
  __pyx_t_7 = 0;
  __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_4, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 46; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_3);
  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
  __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
  __pyx_v_g = __pyx_t_3;
  __pyx_t_3 = 0;
 47:     #spatial indexing
+48:     tree = KDTree(pos, 12)
  __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_KDTree); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 48; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_6);
  __pyx_t_4 = NULL;
  __pyx_t_2 = 0;
  if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_6))) {
    __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_6);
    if (likely(__pyx_t_4)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6);
      __Pyx_INCREF(__pyx_t_4);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_6, function);
      __pyx_t_2 = 1;
    }
  }
  __pyx_t_7 = PyTuple_New(2+__pyx_t_2); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 48; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_7);
  if (__pyx_t_4) {
    __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_4); __pyx_t_4 = NULL;
  }
  __Pyx_INCREF(((PyObject *)__pyx_v_pos));
  __Pyx_GIVEREF(((PyObject *)__pyx_v_pos));
  PyTuple_SET_ITEM(__pyx_t_7, 0+__pyx_t_2, ((PyObject *)__pyx_v_pos));
  __Pyx_INCREF(__pyx_int_12);
  __Pyx_GIVEREF(__pyx_int_12);
  PyTuple_SET_ITEM(__pyx_t_7, 1+__pyx_t_2, __pyx_int_12);
  __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_7, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 48; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_3);
  __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
  __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
  __pyx_v_tree = __pyx_t_3;
  __pyx_t_3 = 0;
+49:     centertree = KDTree(pos[is_center], 12)
  __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_KDTree); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_6);
  __pyx_t_7 = PyObject_GetItem(((PyObject *)__pyx_v_pos), __pyx_v_is_center); if (unlikely(__pyx_t_7 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
  __Pyx_GOTREF(__pyx_t_7);
  __pyx_t_4 = NULL;
  __pyx_t_2 = 0;
  if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_6))) {
    __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_6);
    if (likely(__pyx_t_4)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6);
      __Pyx_INCREF(__pyx_t_4);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_6, function);
      __pyx_t_2 = 1;
    }
  }
  __pyx_t_5 = PyTuple_New(2+__pyx_t_2); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_5);
  if (__pyx_t_4) {
    __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_4); __pyx_t_4 = NULL;
  }
  __Pyx_GIVEREF(__pyx_t_7);
  PyTuple_SET_ITEM(__pyx_t_5, 0+__pyx_t_2, __pyx_t_7);
  __Pyx_INCREF(__pyx_int_12);
  __Pyx_GIVEREF(__pyx_int_12);
  PyTuple_SET_ITEM(__pyx_t_5, 1+__pyx_t_2, __pyx_int_12);
  __pyx_t_7 = 0;
  __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_5, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_3);
  __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
  __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
  __pyx_v_centertree = __pyx_t_3;
  __pyx_t_3 = 0;
+50:     centerindex = np.where(is_center)[0]
  __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_6);
  __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_where); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_5);
  __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
  __pyx_t_6 = NULL;
  if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_5))) {
    __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_5);
    if (likely(__pyx_t_6)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5);
      __Pyx_INCREF(__pyx_t_6);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_5, function);
    }
  }
  if (!__pyx_t_6) {
    __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_v_is_center); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_GOTREF(__pyx_t_3);
  } else {
    __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_GOTREF(__pyx_t_7);
    __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __pyx_t_6 = NULL;
    __Pyx_INCREF(__pyx_v_is_center);
    __Pyx_GIVEREF(__pyx_v_is_center);
    PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_v_is_center);
    __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_7, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_GOTREF(__pyx_t_3);
    __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
  }
  __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
  __pyx_t_5 = __Pyx_GetItemInt(__pyx_t_3, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 0); if (unlikely(__pyx_t_5 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
  __Pyx_GOTREF(__pyx_t_5);
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  __pyx_v_centerindex = __pyx_t_5;
  __pyx_t_5 = 0;
+51:     cdef np.ndarray[ijdist, ndim=1] query = centertree.sparse_distance_matrix(tree, maxdist, output_type='ndarray')
  __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_centertree, __pyx_n_s_sparse_distance_matrix); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_5);
  __pyx_t_3 = PyFloat_FromDouble(__pyx_v_maxdist); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_3);
  __pyx_t_7 = PyTuple_New(2); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_7);
  __Pyx_INCREF(__pyx_v_tree);
  __Pyx_GIVEREF(__pyx_v_tree);
  PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_v_tree);
  __Pyx_GIVEREF(__pyx_t_3);
  PyTuple_SET_ITEM(__pyx_t_7, 1, __pyx_t_3);
  __pyx_t_3 = 0;
  __pyx_t_3 = PyDict_New(); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_3);
  if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_output_type, __pyx_n_s_ndarray) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_7, __pyx_t_3); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_6);
  __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
  __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  if (!(likely(((__pyx_t_6) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_6, __pyx_ptype_5numpy_ndarray))))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __pyx_t_8 = ((PyArrayObject *)__pyx_t_6);
  {
    __Pyx_BufFmt_StackElem __pyx_stack[2];
    if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_query.rcbuffer->pybuffer, (PyObject*)__pyx_t_8, &__Pyx_TypeInfo_nn_struct___pyx_t_46_cython_magic_92e8e937093c0f873c54cd3f5518d67b_ijdist, PyBUF_FORMAT| PyBUF_STRIDES, 1, 0, __pyx_stack) == -1)) {
      __pyx_v_query = ((PyArrayObject *)Py_None); __Pyx_INCREF(Py_None); __pyx_pybuffernd_query.rcbuffer->pybuffer.buf = NULL;
      {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    } else {__pyx_pybuffernd_query.diminfo[0].strides = __pyx_pybuffernd_query.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_query.diminfo[0].shape = __pyx_pybuffernd_query.rcbuffer->pybuffer.shape[0];
    }
  }
  __pyx_t_8 = 0;
  __pyx_v_query = ((PyArrayObject *)__pyx_t_6);
  __pyx_t_6 = 0;
+52:     for it in range(query.shape[0]):
  __pyx_t_9 = (__pyx_v_query->dimensions[0]);
  for (__pyx_t_10 = 0; __pyx_t_10 < __pyx_t_9; __pyx_t_10+=1) {
    __pyx_v_it = __pyx_t_10;
+53:         i = centerindex[query[it].i]
    __pyx_t_11 = __pyx_v_it;
    __pyx_t_12 = (*__Pyx_BufPtrStrided1d(struct __pyx_t_46_cython_magic_92e8e937093c0f873c54cd3f5518d67b_ijdist *, __pyx_pybuffernd_query.rcbuffer->pybuffer.buf, __pyx_t_11, __pyx_pybuffernd_query.diminfo[0].strides)).i;
    __pyx_t_6 = __Pyx_GetItemInt(__pyx_v_centerindex, __pyx_t_12, __pyx_t_5numpy_intp_t, 1, __Pyx_PyInt_From_Py_intptr_t, 0, 0, 0); if (unlikely(__pyx_t_6 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
    __Pyx_GOTREF(__pyx_t_6);
    __pyx_t_13 = __Pyx_PyInt_As_int(__pyx_t_6); if (unlikely((__pyx_t_13 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
    __pyx_v_i = __pyx_t_13;
+54:         if i==query[it].j:
    __pyx_t_14 = __pyx_v_it;
    __pyx_t_15 = ((__pyx_v_i == (*__Pyx_BufPtrStrided1d(struct __pyx_t_46_cython_magic_92e8e937093c0f873c54cd3f5518d67b_ijdist *, __pyx_pybuffernd_query.rcbuffer->pybuffer.buf, __pyx_t_14, __pyx_pybuffernd_query.diminfo[0].strides)).j) != 0);
    if (__pyx_t_15) {
/* … */
    }
+55:             continue
      goto __pyx_L3_continue;
+56:         r = int(l2r * query[it].v)
    __pyx_t_16 = __pyx_v_it;
    __pyx_v_r = ((int)(__pyx_v_l2r * (*__Pyx_BufPtrStrided1d(struct __pyx_t_46_cython_magic_92e8e937093c0f873c54cd3f5518d67b_ijdist *, __pyx_pybuffernd_query.rcbuffer->pybuffer.buf, __pyx_t_16, __pyx_pybuffernd_query.diminfo[0].strides)).v));
+57:         g[r] += 1
    __pyx_t_13 = __pyx_v_r;
    __pyx_t_6 = __Pyx_GetItemInt(__pyx_v_g, __pyx_t_13, int, 1, __Pyx_PyInt_From_int, 0, 0, 0); if (unlikely(__pyx_t_6 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 57; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
    __Pyx_GOTREF(__pyx_t_6);
    __pyx_t_3 = __Pyx_PyInt_AddObjC(__pyx_t_6, __pyx_int_1, 1, 1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 57; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_GOTREF(__pyx_t_3);
    __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
    if (unlikely(__Pyx_SetItemInt(__pyx_v_g, __pyx_t_13, __pyx_t_3, int, 1, __Pyx_PyInt_From_int, 0, 0, 0) < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 57; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    __pyx_L3_continue:;
  }
+58:     return hq, hQ, g
  __Pyx_XDECREF(__pyx_r);
  __pyx_t_3 = PyTuple_New(3); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 58; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __Pyx_GOTREF(__pyx_t_3);
  __Pyx_INCREF(__pyx_v_hq);
  __Pyx_GIVEREF(__pyx_v_hq);
  PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_v_hq);
  __Pyx_INCREF(__pyx_v_hQ);
  __Pyx_GIVEREF(__pyx_v_hQ);
  PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_v_hQ);
  __Pyx_INCREF(__pyx_v_g);
  __Pyx_GIVEREF(__pyx_v_g);
  PyTuple_SET_ITEM(__pyx_t_3, 2, __pyx_v_g);
  __pyx_r = __pyx_t_3;
  __pyx_t_3 = 0;
  goto __pyx_L0;

In [52]:
%timeit cython_gG_l(pos, qlm, Qlm, is_center, Nbins=250, maxdist=30.0)


1 loops, best of 3: 591 ms per loop

Test the final version


In [104]:
reload(boo)


Out[104]:
<module 'colloids.boo' from '/data/mleocmach/src/colloids/python/colloids/boo.py'>

In [105]:
hqQ, g = boo.gG_l(pos, [qlm, Qlm], is_center, Nbins=250, maxdist=30.0)

In [106]:
plt.subplot(1,3,1)
plt.plot(g)
plt.subplot(1,3,2)
plt.plot(hqQ[:,0], label='hq')
plt.subplot(1,3,3)
plt.plot(hqQ[:,1], label='hQ')


Out[106]:
[<matplotlib.lines.Line2D at 0x7fe6b6967750>]

In [107]:
%timeit boo.gG_l(pos, [qlm, Qlm], is_center, Nbins=250, maxdist=30.0)


1 loops, best of 3: 1.43 s per loop

Periodic gl


In [7]:


In [ ]:
hq, g = boo.steinhardt_g_l(pos, bonds, is_center, 250, maxdist)


<weave: compiling>
running build_ext
running build_src
build_src
building extension "sc_9f01faf03310551256b2637495b4f3a20" sources
build_src: building npy-pkg config files
customize UnixCCompiler
customize UnixCCompiler using build_ext
customize UnixCCompiler
customize UnixCCompiler using build_ext
building 'sc_9f01faf03310551256b2637495b4f3a20' extension
compiling C++ sources
C compiler: g++ -pthread -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -fPIC

compile options: '-I/home/mathieu/anaconda3/envs/python2/lib/python2.7/site-packages/weave -I/home/mathieu/anaconda3/envs/python2/lib/python2.7/site-packages/weave/scxx -I/home/mathieu/anaconda3/envs/python2/lib/python2.7/site-packages/weave/blitz -I/home/mathieu/anaconda3/envs/python2/lib/python2.7/site-packages/numpy/core/include -I/home/mathieu/anaconda3/envs/python2/include/python2.7 -c'
extra options: '-O3 -fopenmp'
g++: /data/mleocmach/.cache/scipy/python27_compiled/sc_9f01faf03310551256b2637495b4f3a20.cpp
In file included from /home/mathieu/anaconda3/envs/python2/lib/python2.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1809:0,
                 from /home/mathieu/anaconda3/envs/python2/lib/python2.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:18,
                 from /home/mathieu/anaconda3/envs/python2/lib/python2.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,
                 from /data/mleocmach/.cache/scipy/python27_compiled/sc_9f01faf03310551256b2637495b4f3a20.cpp:23:
/home/mathieu/anaconda3/envs/python2/lib/python2.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:15:2: warning: #warning "Using deprecated NumPy API, disable it by " "#defining NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION" [-Wcpp]
 #warning "Using deprecated NumPy API, disable it by " \
  ^
In file included from /home/mathieu/anaconda3/envs/python2/lib/python2.7/site-packages/weave/blitz/blitz/array-impl.h:37:0,
                 from /home/mathieu/anaconda3/envs/python2/lib/python2.7/site-packages/weave/blitz/blitz/array.h:26,
                 from /data/mleocmach/.cache/scipy/python27_compiled/sc_9f01faf03310551256b2637495b4f3a20.cpp:11:
/home/mathieu/anaconda3/envs/python2/lib/python2.7/site-packages/weave/blitz/blitz/range.h: In member function ‘bool blitz::Range::isAscendingContiguous() const’:
/home/mathieu/anaconda3/envs/python2/lib/python2.7/site-packages/weave/blitz/blitz/range.h:120:34: warning: suggest parentheses around ‘&&’ within ‘||’ [-Wparentheses]
         return ((first_ < last_) && (stride_ == 1) || (first_ == last_));
                                  ^
g++ -pthread -shared -L/home/mathieu/anaconda3/envs/python2/lib -Wl,-rpath=/home/mathieu/anaconda3/envs/python2/lib,--no-as-needed /tmp/scipy-mleocmach-M6Rrzc/python27_intermediate/compiler_73e1e6bdaf1b884dd65f999e9cce0dbf/data/mleocmach/.cache/scipy/python27_compiled/sc_9f01faf03310551256b2637495b4f3a20.o /tmp/scipy-mleocmach-M6Rrzc/python27_intermediate/compiler_73e1e6bdaf1b884dd65f999e9cce0dbf/home/mathieu/anaconda3/envs/python2/lib/python2.7/site-packages/weave/scxx/weave_imp.o -L/home/mathieu/anaconda3/envs/python2/lib -lpython2.7 -o /data/mleocmach/.cache/scipy/python27_compiled/sc_9f01faf03310551256b2637495b4f3a20.so -lgomp

In [ ]: