Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add implementation using Numpy C UFunc API #3

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ following, but feel free to add other methods::
* ``cython`` - a pure Cython-based wrapper
* ``c_numpy`` - a pure C (with Numpy API) wrapper
* ``c_auto`` - a hand-written vectorized C wrapper with an auto-generated Python wrapper from the vectorized C wrappers.
* ``c_ufunc`` - a pure C using the Numpy UFunc API wrapper
187 changes: 187 additions & 0 deletions c_ufunc/c_ufunc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
#include "Python.h"
#include "numpy/arrayobject.h"
#include "numpy/ufuncobject.h"

#include "numpy/npy_3kcompat.h"

#include "numpy/npy_math.h"

#include "erfa.h"

typedef npy_intp intp;

static void
increment_ufunc(intp ndim, char **args, intp *steps)
{
intp i;
for (i = 0; i < ndim; ++i) {
*(args[i]) += steps[i];
}
}

#define BEGIN_LOOP \
intp dN = *dimensions++; \
intp N; \
for (N = 0; N < dN; N++) { \

#define END_LOOP(x) \
increment_ufunc((x), args, steps); \
} \

/*
*****************************************************************************
** UFUNC LOOPS **
*****************************************************************************
*/

/*///////////////////////////////////////////////////////////////////////////
eraAtco13
*/

static void
eraAtco13_wrapper(char **args, intp *dimensions, intp *steps, void *extra)
{
int ret;

BEGIN_LOOP
ret = eraAtco13(
*(double *)args[0],
*(double *)args[1],
*(double *)args[2],
*(double *)args[3],
*(double *)args[4],
*(double *)args[5],
*(double *)args[6],
*(double *)args[7],
*(double *)args[8],
*(double *)args[9],
*(double *)args[10],
*(double *)args[11],
*(double *)args[12],
*(double *)args[13],
*(double *)args[14],
*(double *)args[15],
*(double *)args[16],
*(double *)args[17],
(double *)args[18],
(double *)args[19],
(double *)args[20],
(double *)args[21],
(double *)args[22],
(double *)args[23]);
if (ret > 0) {
PyErr_SetString(PyExc_ValueError, "dubious year");
return;
} else if (ret < 0) {
PyErr_SetString(PyExc_ValueError, "unacceptable date");
return;
}
END_LOOP(24)
}

static PyUFuncGenericFunction eraAtco13_functions[] = { eraAtco13_wrapper };
static void *eraAtco13_data[] = {NULL};
static char eraAtco13_types[] = {
NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE,
NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE,
NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE,
NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE };


static void
eraD2dtf_wrapper(char **args, intp *dimensions, intp *steps, void *extra)
{
int ret;
int ihmsf[4];

BEGIN_LOOP
ret = eraD2dtf(
(char *)args[0],
*(int *)args[1],
*(double *)args[2],
*(double *)args[3],
(int *)args[4],
(int *)args[5],
(int *)args[6],
ihmsf);

if (ret > 0) {
PyErr_SetString(PyExc_ValueError, "dubious year");
return;
} else if (ret < 0) {
PyErr_SetString(PyExc_ValueError, "unacceptable date");
return;
}

*(int *)args[7] = ihmsf[0];
*(int *)args[8] = ihmsf[1];
*(int *)args[9] = ihmsf[2];
*(int *)args[10] = ihmsf[3];
END_LOOP(11)
}

static PyUFuncGenericFunction eraD2dtf_functions[] = { eraD2dtf_wrapper };
static void *eraD2dtf_data[] = {NULL};
static char eraD2dtf_types[] = {
NPY_STRING, NPY_INT, NPY_DOUBLE, NPY_DOUBLE, NPY_INT, NPY_INT, NPY_INT,
NPY_INT, NPY_INT, NPY_INT, NPY_INT };


/*///////////////////////////////////////////////////////////////////////////
module level
*/

#if defined(NPY_PY3K)
static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT,
"c_ufunc",
NULL,
-1,
NULL,
NULL,
NULL,
NULL,
NULL
};
#endif

#if defined(NPY_PY3K)
#define RETVAL m
PyObject *PyInit_c_ufunc(void)
#else
#define RETVAL
PyMODINIT_FUNC
initc_ufunc(void)
#endif
{
PyObject *m;
PyObject *d;
PyObject *f;

#if defined(NPY_PY3K)
m = PyModule_Create(&moduledef);
#else
m = Py_InitModule("c_ufunc", NULL);
#endif
if (m == NULL)
return RETVAL;

import_array();
import_ufunc();

d = PyModule_GetDict(m);

f = PyUFunc_FromFuncAndData(
eraAtco13_functions, eraAtco13_data, eraAtco13_types, 1, 18, 6,
PyUFunc_None, "eraAtco13", "eraAtco13", 0);
PyDict_SetItemString(d, "atco13", f);
Py_DECREF(f);

f = PyUFunc_FromFuncAndData(
eraD2dtf_functions, eraD2dtf_data, eraD2dtf_types, 1, 4, 7,
PyUFunc_None, "eraD2dtf", "eraD2dtf", 0);
PyDict_SetItemString(d, "eraD2dtf", f);
Py_DECREF(f);

return RETVAL;
}
19 changes: 19 additions & 0 deletions c_ufunc/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from distutils.core import setup
from distutils.extension import Extension

import numpy as np

try:
numpy_include = np.get_include()
except AttributeError:
numpy_include = np.get_numpy_include()

setup(name='c_ufunc',
ext_modules=[
Extension(
'c_ufunc',
['c_ufunc.c'],
libraries=['erfa'],
include_dirs=[numpy_include]
)],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: I think this is missing the numpy include path?

)