From d841f15f7593ae2bb9a956753409abf826a43c4d Mon Sep 17 00:00:00 2001 From: Scott Ransom Date: Sat, 22 Jun 2024 09:35:28 -0400 Subject: [PATCH 1/5] Swapped _ppgplot.c for one from Tom Marsh. Still needs work, though. --- python/ppgplot_src/_ppgplot.c | 655 ++++++++++++++++------------------ 1 file changed, 312 insertions(+), 343 deletions(-) diff --git a/python/ppgplot_src/_ppgplot.c b/python/ppgplot_src/_ppgplot.c index a2822bfa5..9648befa9 100644 --- a/python/ppgplot_src/_ppgplot.c +++ b/python/ppgplot_src/_ppgplot.c @@ -12,6 +12,7 @@ * - A few ppgplot functions have not been interfaced yet. * - The pythonic calling conventions of some functions are *not* * identical to the original PGPLOT ones. + * - added pgpt1 15/04/2008 TRM */ #include @@ -37,7 +38,7 @@ * Default values and stuff */ -#define STD_DEVICE "/XWINDOW" +#define STD_DEVICE "/XSERVE" #define DEF_XLABEL "x" #define DEF_YLABEL "y" #define DEF_PLOTLABEL "x = f(y)" @@ -66,71 +67,18 @@ static PyObject *PpgMEMErr; /**************************************************************************/ static PyObject * -tofloatvector (PyObject *o, float **v, int *vsz) +tofloatvector (PyObject *o, float **v, npy_intp *vsz) { - PyArrayObject *a1, *af1, *af2; - PyArray_Descr *descr; - npy_intp dims; - int ownedaf1=0; - - /* Check if args are arrays. */ - if (!PyArray_Check(o)) { - PyErr_SetString(PpgTYPEErr,"object is not an array"); - return(NULL); - } - a1 = (PyArrayObject *)o; - /* Check if args are vectors. */ - if (a1->nd != 1) { - PyErr_SetString(PpgTYPEErr,"object is not a vector"); - return(NULL); - } - -#ifdef DEBUG_TOARRAY - fprintf(stderr,"(tofloatvector): array type = %d\n",a1->descr->type_num); -#endif - - switch (a1->descr->type_num) { - case PyArray_FLOAT: - af1 = a1; - break; - case PyArray_CHAR: -#ifndef USE_NUMARRAY - case PyArray_UBYTE: -#endif -// case PyArray_SBYTE: - case PyArray_SHORT: - case PyArray_INT: -#ifndef USE_NUMARRAY - case PyArray_LONG: -#endif - case PyArray_DOUBLE: - if (!(af1 = (PyArrayObject *)PyArray_Cast(a1,PyArray_FLOAT))) { - PyErr_SetString(PpgTYPEErr,"cannot cast vector to floats"); - return(NULL); - } - ownedaf1 = 1; - break; - default: - PyErr_SetString(PpgTYPEErr,"cannot cast vector to floats"); - return(NULL); - break; - } - -#ifdef DEBUG_TOARRAY - fprintf(stderr,"(tofloatvector): array type = %d\n",a1->descr->type_num); -#endif - - af2 = af1; - descr = PyArray_DescrFromType(PyArray_FLOAT); - if (PyArray_AsCArray((PyObject **)&af2, (void *)v, &dims, 1, - descr) == -1) { - af2 = NULL; - } - *vsz = dims; - - if (ownedaf1) { Py_DECREF(af1); } - - return((PyObject *)af2); + /* + I have radically simplified the code here using numpy's convenience functions + TRM, 12/02/09. This avoids an irritating deprecation warning from numpy. + */ + PyArrayObject* array = NULL; + array = (PyArrayObject*) PyArray_FromAny(o, PyArray_DescrFromType(NPY_FLOAT), 1, 1, NPY_ALIGNED | NPY_C_CONTIGUOUS | NPY_FORCECAST, NULL); + if(array == NULL) return NULL; + *vsz = PyArray_Size(array); + *v = (float*) PyArray_DATA(array); + return (PyObject*)array; } /*************************************************************************/ @@ -139,21 +87,19 @@ static PyObject * tofloatmat(PyObject *o, float **m, int *nr, int *nc) { PyArrayObject *a1, *af1, *af2; - PyArray_Descr *descr; - npy_intp dims[2]; int ownedaf1=0; char **tmpdat; /* Check if args are arrays. */ if (!PyArray_Check(o)) { - PyErr_SetString(PpgTYPEErr,"object is not and array"); + PyErr_SetString(PpgTYPEErr,"object is not an array"); return(NULL); } a1 = (PyArrayObject *)o; /* Check if args are matrices. */ if (a1->nd != 2) { - PyErr_SetString(PpgTYPEErr,"object is not a matrix"); - return(NULL); + PyErr_SetString(PpgTYPEErr,"object is not a matrix"); + return(NULL); } #ifdef DEBUG_TOARRAY @@ -192,14 +138,11 @@ tofloatmat(PyObject *o, float **m, int *nr, int *nc) #endif af2 = af1; - descr = PyArray_DescrFromType(PyArray_FLOAT); - if (PyArray_AsCArray((PyObject **)&af2, (void *)&tmpdat, dims, 2, - descr) == -1) { + /* (void *) avoids irritating gcc warning about strict aliasing */ + if (PyArray_As2D((PyObject **)(void *)&af2, (char ***)&tmpdat, nr, nc, PyArray_FLOAT) == -1) { af2 = NULL; goto bailout; } - *nr = dims[0]; - *nc = dims[1]; /* WARNING: What follows is a little tricky and I dunno if I'm really allowed to do this. On the other hand it really conserves @@ -284,34 +227,34 @@ lininterp (float min, float max, int npts, float *v) static void autocal2d(float *a, int rn, int cn, - float *fg, float *bg, int nlevels, float *levels, - float *x1, float *x2, float *y1, float *y2, - float *tr) + float *fg, float *bg, int nlevels, float *levels, + float *x1, float *x2, float *y1, float *y2, + float *tr) { float dx1, dx2, dy1, dy2; /* autocalibrate intensity-range. */ if (*fg == *bg) { - minmax(a,rn*cn,bg,fg); + minmax(a,rn*cn,bg,fg); /* fprintf(stderr,"Intensity range:\n fg=%f\n bg=%f\n",*fg,*bg); */ } if ((nlevels >= 2) && (levels)) - lininterp(*bg, *fg, nlevels, levels); + lininterp(*bg, *fg, nlevels, levels); /* autocalibrate x-y range. */ if ((*x1 == *x2) || (*y1 == *y2)) cpgqwin(&dx1,&dx2,&dy1,&dy2); if (*x1 == *x2) {*x1=dx1; *x2=dx2;} if (*y1 == *y2) {*y1=dy1; *y2=dy2;} /* fprintf(stderr,"Xrange: [%f, %f]\nYrange[%f, %f]\n",*x1,*x2,*y1,*y2); */ - + /* calculate transformation vector. */ tr[2] = tr[4] = 0.0; tr[1] = (*x2 - *x1) / cn; tr[0] = *x1 - (tr[1] / 2); tr[5] = (*y2 - *y1) / rn; tr[3] = *y1 - (tr[5] / 2); - + /* fprintf(stderr,"Tansformation vector:\n"); */ /* for (i=0; i<6; fprintf(stderr," tr[%d]=%f\n",i,tr[i]),i++); */ } @@ -346,8 +289,7 @@ PYF(pgqinf) PYF(pgpoly) { int n; - int xlen; - int ylen; + npy_intp xlen, ylen; float* xpoints = NULL; float* ypoints = NULL; PyObject *xarray = NULL; @@ -359,13 +301,9 @@ PYF(pgpoly) return NULL; if(!(xa = (PyArrayObject*)tofloatvector(xarray, &xpoints, &xlen))) goto fail; if(!(ya = (PyArrayObject*)tofloatvector(yarray, &ypoints, &ylen))) goto fail; - /*for(int i = 0; i < xlen; i++) - { - printf("%i: %f,%f\n", i, xpoints - }*/ + n = xlen; - if(ylen < n) - n = ylen; + if(ylen < n) n = ylen; cpgpoly(n, xpoints, ypoints); Py_DECREF(xa); @@ -395,6 +333,7 @@ PYF(pgqvp) return Py_BuildValue("ffff", x1, x2, y1, y2); } + /* pgqvsz(units : int) return x1, x2, y1, y2 @@ -410,6 +349,18 @@ PYF(pgqvsz) return Py_BuildValue("ffff", x1, x2, y1, y2); } +/* + pgqwin() + return x1, x2, y1, y2 +*/ +PYF(pgqwin) +{ + float x1, x2, y1, y2; + cpgqwin(&x1, &x2, &y1, &y2); + + return Py_BuildValue("ffff", x1, x2, y1, y2); +} + PYF(pgsclp) { int state; @@ -455,9 +406,8 @@ PYF(pgconf) PyArrayObject *aa=NULL, *atr=NULL; float *a=NULL, *tr=NULL, c_1 = 0.0, c_2 = 0.0; - int cd=0 ,rd=0, - c1=0,c2=0,r1=0,r2=0, - trsz=0; + int cd=0 ,rd=0,c1=0,c2=0,r1=0,r2=0; + npy_intp trsz=0; if (!PyArg_ParseTuple(args,"OiiiiiiffO:pgconl", &oa, &cd, &rd, &c1, &c2, &r1, &r2, @@ -527,6 +477,26 @@ PYF(pgopen) return(Py_BuildValue("i",did)); } +PYF(pgaxis) +{ + char *opt=NULL; + float x1=0.,x2=1.,y1=0.,y2=1.,v1=0.,v2=1.,step=1.; + float dmajl=1.,dmajr=1., fmin=1., disp=0.,orient=0.; + int nsub=2; + + if (!PyArg_ParseTuple(args,"|zfffffffifffff:pgaxis", + &opt, &x1, &y1, &x2, &y2, &v1, &v2, + &step, &nsub, &dmajl, &dmajr, &fmin, + &disp, &orient)) + return(NULL); + + if (!opt) opt = "N"; + + cpgaxis(opt,x1,y1,x2,y2,v1,v2,step,nsub,dmajl,dmajr,fmin,disp,orient); + + PYRN; +} + PYF(pgslct) { int did = 0; @@ -915,7 +885,7 @@ PYF(pgctab) PyArrayObject *la = NULL, *ra = NULL, *ga = NULL, *ba = NULL; float *l = NULL, *r = NULL, *g = NULL, *b = NULL, contra = 1.0, bright = 0.5; - int nc = 0, nr=0, ng=0, nb=0; + npy_intp nc = 0, nr=0, ng=0, nb=0; if (!PyArg_ParseTuple(args,"OOOO|iff:pgctab", &lo, &ro, &go, &bo, &nc, &contra, &bright)) @@ -1022,11 +992,9 @@ PYF(pgband) float xref = 0.0, yref = 0.0, x=0.0, y=0.0; char ch = '\0'; - if (!PyArg_ParseTuple(args,"i|iff:pgband", - &mode, &i, &xref, &yref)) + if (!PyArg_ParseTuple(args,"i|iff:pgband", &mode, &i, &xref, &yref)) return(NULL); - cpgband(mode,i,xref,yref,&x,&y,&ch); return(Py_BuildValue("ffc",x,y,ch)); @@ -1342,7 +1310,7 @@ PYF(pgrect) PYF(pgline) { - int xsz, ysz; + npy_intp xsz, ysz; PyObject *op1=NULL, *op2=NULL, *o1=NULL, *o2=NULL; float *xpts, *ypts; @@ -1365,7 +1333,7 @@ PYF(pgline) PYF(pgpt) { - int xsz, ysz; + npy_intp xsz, ysz; PyObject *op1=NULL, *op2=NULL, *o1=NULL, *o2=NULL; float *xpts, *ypts; int symbol=0; @@ -1387,6 +1355,20 @@ PYF(pgpt) return(NULL); } +PYF(pgpt1) +{ + float xpt, ypt; + int symbol=0; + + if(!PyArg_ParseTuple(args, "ff|i", &xpt, &ypt, &symbol)) + return NULL; + + cpgpt1(xpt, ypt, symbol); + + PYRN; + +} + /************************************************************************/ @@ -1452,7 +1434,7 @@ PYF(pgpt) * In order to plot (map) a matrix * a[r1:r2,c1:c2] * in a viewport scaled as: - * x-axis form x1 to x2 + * x-axis from x1 to x2 * y-axis from y1 to y2 * having rows run on x and columns on run y, you have to use the * following transformation matrix: @@ -1489,36 +1471,46 @@ static PyObject * ImageMap(int color, PyObject *args) { float fg=0.0, bg=0.0, *a=NULL, *tr=NULL; - int cd=0, rd=0, c1=0, c2=0, r1=0, r2=0, rn=0, cn=0, sz=0; + int c1=0, c2=0, r1=0, r2=0, rn=0, cn=0; + npy_intp sz=0; PyObject *oa = NULL, *ot = NULL; PyArrayObject *aa = NULL, *at = NULL; - if (!PyArg_ParseTuple(args,"OiiiiiiffO:pggray", - &oa, &cd, &rd, &c1, &c2, &r1, &r2, - &fg, &bg, &ot)) - return(NULL); + if (!PyArg_ParseTuple(args,"OiiiiffO:pggray", &oa, &c1, &c2, &r1, &r2, &fg, &bg, &ot)) + return(NULL); if (!(aa =(PyArrayObject *)tofloatmat(oa, &a, &rn, &cn))) goto fail; if (!(at =(PyArrayObject *)tofloatvector(ot, &tr, &sz))) goto fail; if (sz < 6) { - PyErr_SetString(PpgTYPEErr,"pggray: invalid transform. vactor"); - goto fail; + if(color) + PyErr_SetString(PpgTYPEErr,"pgimag: invalid transform. vactor"); + else + PyErr_SetString(PpgTYPEErr,"pggray: invalid transform. vactor"); + goto fail; + } + + if(c1 >= c2 || r1 >= r2 || c2 >= cn || r2 >= rn || c1 < 0 || r1 < 0){ + if(color) + PyErr_SetString(PpgTYPEErr,"pgimag: column and/or row indices out of range"); + else + PyErr_SetString(PpgTYPEErr,"pggray: column and/or row indices out of range"); + goto fail; } if (color) - cpgimag(a, cn, rn, c1+1, c2+1, r1+1, r2+1, bg, fg, tr); + cpgimag(a, cn, rn, c1+1, c2+1, r1+1, r2+1, bg, fg, tr); else - cpggray(a, cn, rn, c1+1, c2+1, r1+1, r2+1, fg, bg, tr); + cpggray(a, cn, rn, c1+1, c2+1, r1+1, r2+1, fg, bg, tr); Py_DECREF(aa); Py_DECREF(at); PYRN; fail: - if (aa) { Py_DECREF(aa); } - if (at) { Py_DECREF(at); } + Py_XDECREF(aa); + Py_XDECREF(at); return(NULL); } @@ -1541,7 +1533,7 @@ ImageMap_s (int color, PyObject *args) if (!(aa =(PyArrayObject *)tofloatmat(oa, &a, &rn, &cn))) return(NULL); - /* Perform autocalibrations as nesecairy. */ + /* Perform autocalibrations as necessary. */ autocal2d(a, rn, cn, &fg, &bg, 5, levels, &x1, &x2, &y1, &y2, tr); if (color) @@ -1615,7 +1607,8 @@ PYF(pgerrb) PyObject *ox=NULL, *oy=NULL, *oe=NULL; PyArrayObject *ax=NULL, *ay=NULL, *ae=NULL; float *x=NULL, *y=NULL, *e=NULL, t=1.0; - int szx=0, szy=0, sze =0, dir = 0, n1; + int dir = 0, n1; + npy_intp szx=0, szy=0, sze =0; if (!PyArg_ParseTuple(args,"iOOO|f:pgerrb", &dir, &ox, &oy, &oe, &t)) return(NULL); @@ -1646,7 +1639,8 @@ PYF(pgerrx) PyObject *oy=NULL, *ox1=NULL, *ox2=NULL; PyArrayObject *ay=NULL, *ax1=NULL, *ax2=NULL; float *y=NULL, *x1=NULL, *x2=NULL, t=1.0; - int szy=0, szx1=0, szx2 =0, n1; + npy_intp szy=0, szx1=0, szx2=0; + int n1; if (!PyArg_ParseTuple(args,"OOO|f:pgerrx", &ox1, &ox2, &oy, &t)) return(NULL); @@ -1678,7 +1672,8 @@ PYF(pgerry) PyObject *ox=NULL, *oy1=NULL, *oy2=NULL; PyArrayObject *ax=NULL, *ay1=NULL, *ay2=NULL; float *x=NULL, *y1=NULL, *y2=NULL, t=1.0; - int szx=0, szy1=0, szy2 =0, n1; + npy_intp szx=0, szy1=0, szy2 =0; + int n1; if (!PyArg_ParseTuple(args,"OOO|f:pgerry", &ox, &oy1, &oy2, &t)) return(NULL); @@ -1711,25 +1706,17 @@ PYF(pghist) { PyObject *od=NULL; PyArrayObject *ad=NULL; - int - nusrpts = 0, - npts = 0, - nbin = 0, - pgflag = 0; - float - datamin=0, - datamax=0, - *data=NULL; - - if (!PyArg_ParseTuple(args,"iOffi|i:pghist", &nusrpts, &od, &datamin, - &datamax, &nbin, &pgflag)) - return(NULL); + int nbin = 0, pgflag = 1; + float datamin=0, datamax=0, *data=NULL; + npy_intp npts; + + if (!PyArg_ParseTuple(args,"Offi|i:pghist", &od, &datamin, + &datamax, &nbin, &pgflag)) + return(NULL); if (!(ad = (PyArrayObject *)tofloatvector(od,&data,&npts))) goto fail; - if (nusrpts > npts) nusrpts = npts; - - cpghist(nusrpts, data, datamin, datamax, nbin, pgflag); + cpghist(npts, data, datamin, datamax, nbin, pgflag); Py_DECREF(ad); PYRN; @@ -1743,15 +1730,10 @@ PYF(pghist_s) { PyObject *od=NULL; PyArrayObject *ad=NULL; - int - npts = 0, - nbin = 0, - pgflag = 0; - float - datamin=0, - datamax=0, - *data=NULL; - + int nbin = 0, pgflag = 0; + float datamin=0, datamax=0, *data=NULL; + npy_intp npts; + if (!PyArg_ParseTuple(args,"Oi|iff:pghist_s", &od, &nbin, &pgflag, &datamin, &datamax)) return(NULL); @@ -1776,12 +1758,9 @@ PYF(pgbin) { PyObject *ox=NULL, *od=NULL; PyArrayObject *ax=NULL, *ad=NULL; - int - szx=0, szd=0, - center = 1; - float - *x, - *data; + int center = 1; + npy_intp szx, szd; + float *x, *data; if (!PyArg_ParseTuple(args,"OO|i:pgbin", &ox, &od, ¢er)) return(NULL); @@ -1807,7 +1786,8 @@ PYF(pgbin_s) { PyObject *od=NULL; PyArrayObject *ad=NULL; - int nbin = 0, center = 1; + int center = 1; + npy_intp nbin; float x1 = 0.0, x2 = 0.0, *x, *data, dummy1, dummy2; @@ -1848,11 +1828,10 @@ PYF(pghi2d) *od=NULL, *ox=NULL, *oyl=NULL; PyArrayObject *ad=NULL, *ax=NULL, *ayl=NULL; - int - cd=0, rd=0, c1=0, c2=0, r1=0, r2=0, - ioff, center, vxsz=0, vylsz=0; + int cd=0, rd=0, c1=0, c2=0, r1=0, r2=0, ioff, center; float *md = NULL, *vx=NULL, *vyl, bias=0; + npy_intp vxsz, vylsz; if (!PyArg_ParseTuple(args,"OiiiiiiOifiO:pghi2d", &od,&cd,&rd,&c1,&c2,&r1,&r2,&ox, @@ -1876,7 +1855,7 @@ PYF(pghi2d) Py_DECREF(ax); Py_DECREF(ayl); PYRN; - + fail: if (ad) { Py_DECREF(ad); } if (ax) { Py_DECREF(ax); } @@ -1957,13 +1936,10 @@ genContours (enum pp_contour_funcs ft, PyObject *args) PyArrayObject *aa=NULL, *ac=NULL, *atr=NULL; float *a=NULL, *c=NULL, *tr=NULL, blank=0.0; - int cd=0 ,rd=0, - c1=0,c2=0,r1=0,r2=0, - csz=0, trsz=0, - nc=0; - + int cd=0, rd=0, c1=0, c2=0, r1=0, r2=0, nc=0; + npy_intp csz, trsz; if (!PyArg_ParseTuple(args,"OiiiiiiOiO|f:contour", - &oa, &cd, &rd, &c1, &c2, &r1, &r2, + &oa, &cd, &rd, &c1, &c2, &r1, &r2, &oc, &nc, &otr, &blank)) return(NULL); @@ -1977,6 +1953,7 @@ genContours (enum pp_contour_funcs ft, PyObject *args) if (abs(nc) > csz) { PyErr_SetString(PpgTYPEErr,"contour: size of cont vec < than the " "req. contours number"); + //printf("%d %d\n", nc, csz); goto fail; } if (trsz < 6) { @@ -2034,76 +2011,76 @@ genContours_s (enum pp_contour_funcs ft, PyObject *args) PyObject *oa=NULL, *oc=NULL; PyArrayObject *aa=NULL, *ac=NULL; float *a = NULL, *c = NULL, tr[6], - x1=0.0,y1=0.0,x2=0.0,y2=0.0,blank=0.0, - mn = 0.0, mx = 0.0; - int rd=0, cd=0, csz=0, nc=0, ncont=0; - + x1=0.0,y1=0.0,x2=0.0,y2=0.0,blank=0.0, + mn = 0.0, mx = 0.0; + int rd=0, cd=0, nc=0, ncont=0; + npy_intp csz; if (!PyArg_ParseTuple(args,"Oi|Offfff:contour_s", - &oa,&nc,&oc,&x1,&y1,&x2,&y2,&blank)) - return(NULL); + &oa,&nc,&oc,&x1,&x2,&y1,&y2,&blank)) + return(NULL); if (abs(nc)<1) { - PyErr_SetString(PpgTYPEErr,"_ppgplot.error: Number of contours is 0"); - return(NULL); + PyErr_SetString(PpgTYPEErr,"_ppgplot.error: Number of contours is 0"); + return(NULL); } if (!(aa = (PyArrayObject *)tofloatmat(oa, &a, &rd, &cd))) - goto fail; + goto fail; if (oc) { - if (!(ac = (PyArrayObject *)tofloatvector(oc, &c, &csz))) - goto fail; + if (!(ac = (PyArrayObject *)tofloatvector(oc, &c, &csz))) + goto fail; } else { - if (!(c = malloc(abs(nc)*sizeof(*c)))) { - PyErr_SetString(PpgTYPEErr,"_ppgplot.error: Out of mem!"); - goto fail; - } - ncont = abs(nc); + if (!(c = malloc(abs(nc)*sizeof(*c)))) { + PyErr_SetString(PpgTYPEErr,"_ppgplot.error: Out of mem!"); + goto fail; + } + ncont = abs(nc); } - /* Perform autocalibrations as nesecairy. */ + /* Perform autocalibrations as necessary. */ autocal2d(a, rd, cd, &mx, &mn, ncont, c, &x1, &x2, &y1, &y2, tr); #ifdef DEBUG_CONT_S { - int i; - fprintf(stderr,"ncontours = %d = %d\n",nc,ncont); - fprintf(stderr,"Contours:\n"); - for (i=0; i= 3 - static struct PyModuleDef ppgplotdef = { - PyModuleDef_HEAD_INIT, - "_ppgplot", /* m_name */ - "PPGPLOT Module", /* m_doc */ - -1, /* m_size */ - PpgMethods, /* m_methods */ - NULL, /* m_reload */ - NULL, /* m_traverse */ - NULL, /* m_clear */ - NULL, /* m_free */ - }; + #define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void) +#else + #define MOD_INIT(name) PyMODINIT_FUNC init##name(void) #endif -/************************************************************************/ - -static PyObject * -moduleinit(void) +MOD_INIT(_ppgplot) { PyObject *m, *d; -#if PY_MAJOR_VERSION <= 2 - m = Py_InitModule("_ppgplot", PpgMethods); +#if PY_MAJOR_VERSION >= 3 + static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "_ppgplot", + NULL, + -1, + PpgMethods, + NULL, + NULL, + NULL, + NULL, + }; + m = PyModule_Create(&moduledef); #else - m = PyModule_Create(&ppgplotdef); + m = Py_InitModule("_ppgplot", PpgMethods); #endif d = PyModule_GetDict(m); import_array(); -#if PY_MAJOR_VERSION <= 2 +#if PY_MAJOR_VERSION >= 3 + PpgIOErr = PyUnicode_FromString("_ppgplot.ioerror"); + PpgTYPEErr = PyUnicode_FromString("_ppgplot.typeerror"); + PpgMEMErr = PyUnicode_FromString("_ppgplot.memerror"); +#else PpgIOErr = PyString_FromString("_ppgplot.ioerror"); PpgTYPEErr = PyString_FromString("_ppgplot.typeerror"); PpgMEMErr = PyString_FromString("_ppgplot.memerror"); -#else - PpgIOErr = PyBytes_FromString("_ppgplot.ioerror"); - PpgTYPEErr = PyBytes_FromString("_ppgplot.typeerror"); - PpgMEMErr = PyBytes_FromString("_ppgplot.memerror"); #endif PyDict_SetItemString(d, "ioerror", PpgIOErr); PyDict_SetItemString(d, "typeerror", PpgTYPEErr); PyDict_SetItemString(d, "memerror", PpgMEMErr); +#if PY_MAJOR_VERSION >= 3 return m; +#endif } -#if PY_MAJOR_VERSION < 3 - void - init_ppgplot(void) - { - moduleinit(); - } -#else - PyMODINIT_FUNC - PyInit__ppgplot(void) - { - return moduleinit(); - } -#endif /************************************************************************/ /* End of _ppgplot.c */ /************************************************************************/ From ceeef62ec5454de28a3afd772e600686883abf55 Mon Sep 17 00:00:00 2001 From: Scott Ransom Date: Sat, 22 Jun 2024 10:47:16 -0400 Subject: [PATCH 2/5] Minor changes to strings for ppgplot --- bin/DDplan.py | 2 +- bin/single_pulse_search.py | 2 +- examplescripts/ffdot_example.py | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/bin/DDplan.py b/bin/DDplan.py index bd8095b7f..981109d80 100755 --- a/bin/DDplan.py +++ b/bin/DDplan.py @@ -373,7 +373,7 @@ def dm_steps(loDM, hiDM, obs, cohdm=0.0, numsub=0, numprocs=1, ppgplot.pgsch(1.1) ppgplot.pgsci(1) if (numsub): - ppgplot.pgmtxt("t", 1.5, 0.6/10.0, 0.5, "\(2156)\dctr\\u = %g MHz" % obs.f_ctr) + ppgplot.pgmtxt("t", 1.5, 0.6/10.0, 0.5, r"\(2156)\dctr\\u = %g MHz" % obs.f_ctr) if (dtms < 0.1): ppgplot.pgmtxt("t", 1.5, 2.8/10.0, 0.5, "dt = %g \\gms" % (dtms*1000)) else: diff --git a/bin/single_pulse_search.py b/bin/single_pulse_search.py index 1fa9d6977..a78b7a4b1 100755 --- a/bin/single_pulse_search.py +++ b/bin/single_pulse_search.py @@ -662,7 +662,7 @@ def main(): info.telescope) ppgplot.pgmtxt('T', -2.4, 0.33, 0.0, 'DEC (J2000):') ppgplot.pgmtxt('T', -2.4, 0.5, 0.0, info.DEC) - ppgplot.pgmtxt('T', -2.4, 0.73, 0.0, 'Sampling time: %.2f \gms'%\ + ppgplot.pgmtxt('T', -2.4, 0.73, 0.0, r'Sampling time: %.2f \gms'%\ (orig_dt*1e6)) # third row if info.instrument.find("pigot") >= 0: diff --git a/examplescripts/ffdot_example.py b/examplescripts/ffdot_example.py index c7cd0e521..29c169267 100644 --- a/examplescripts/ffdot_example.py +++ b/examplescripts/ffdot_example.py @@ -26,20 +26,20 @@ pffdot = presto.spectralpower(ffdot.flat) theo_max_pow = N**2.0/4.0 frp = max(pffdot) / theo_max_pow # Fraction of recovered power -print("Fraction of recovered signal power = %f" % frp) +print(f"Recovered {frp:.3f} of theoretical signal power in F-Fdot plane") a = time.perf_counter() [maxpow, rmax, zmax, rd] = presto.maximize_rz(ft, r+norm(1)[0]/5.0, z+norm(1)[0], norm=1.0) -print("Time for rz:", time.perf_counter()-a) -print(r, rmax, z, zmax, theo_max_pow, maxpow) +print(f"Time for rz optimization {time.perf_counter()-a:.3g} s") +print(f" Optimization recovered {maxpow / theo_max_pow:.3f} of theoretical signal power") a = time.perf_counter() [maxpow, rmax, zmax, wmax, rd] = presto.maximize_rzw(ft, r+norm(1)[0]/5.0, z+norm(1)[0], w+norm(1)[0]*5.0, norm=1.0) -print("Time for rzw:", time.perf_counter()-a) -print(r, rmax, z, zmax, w, wmax, theo_max_pow, maxpow) -#print "Raw power should be ~%.2e" % theo_max_pow +print(f"Time for rzw optimization {time.perf_counter()-a:.3g} s") +print(f" Optimization recovered {maxpow / theo_max_pow:.3f} of theoretical signal power") +print(" Recovered power fraction should be near 1.0.") pffdot = pffdot / theo_max_pow pffdot.shape = (np, np) rs = num.arange(np) * dr - np//2*dr From 0b7b52ab533c35cc3d4d57110530dc0abffc71b8 Mon Sep 17 00:00:00 2001 From: Scott Ransom Date: Sat, 22 Jun 2024 10:55:11 -0400 Subject: [PATCH 3/5] Fixed string escape bug --- bin/DDplan.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/DDplan.py b/bin/DDplan.py index 981109d80..fba875623 100755 --- a/bin/DDplan.py +++ b/bin/DDplan.py @@ -373,7 +373,7 @@ def dm_steps(loDM, hiDM, obs, cohdm=0.0, numsub=0, numprocs=1, ppgplot.pgsch(1.1) ppgplot.pgsci(1) if (numsub): - ppgplot.pgmtxt("t", 1.5, 0.6/10.0, 0.5, r"\(2156)\dctr\\u = %g MHz" % obs.f_ctr) + ppgplot.pgmtxt("t", 1.5, 0.6/10.0, 0.5, "\\(2156)\\dctr\\u = %g MHz" % obs.f_ctr) if (dtms < 0.1): ppgplot.pgmtxt("t", 1.5, 2.8/10.0, 0.5, "dt = %g \\gms" % (dtms*1000)) else: From 726c9e72b0e8fbc95a598f99a27aa4f83130126d Mon Sep 17 00:00:00 2001 From: Scott Ransom Date: Sat, 22 Jun 2024 11:11:43 -0400 Subject: [PATCH 4/5] Updated _ppgplot.c for Numpy v2.0 C-API and bumped to v5.0.2 --- CHANGELOG.md | 5 ++ README.md | 5 ++ meson.build | 2 +- python/meson.build | 13 +---- python/ppgplot_src/_ppgplot.c | 94 ++++++++++++++++++++-------------- python/ppgplot_src/meson.build | 2 - python/pyproject.toml | 6 +-- 7 files changed, 70 insertions(+), 57 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ec70c75f..9f0aaa062 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## Version 5.0.2: + * Updated the C wrappers for PGPLOT for the Numpy 2.0 C API + * Python v3.9 or newer is now required. + * Several minor bug fixes, including to `injectpsr.py`, thanks to @remsforian + ## Version 5.0.1: * Minor improvements over v5.0.0 * Some clarifications and improvements to the build process diff --git a/README.md b/README.md index f65b9d750..fc215a619 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,11 @@ PRESTO is a large suite of pulsar search and analysis software developed primari **PRESTO has discovered well over 1000 pulsars, including ~400 recycled and/or binary pulsars!** +## Version 5.0.2: + * Updated the C wrappers for PGPLOT for the Numpy 2.0 C API (with thanks to Tom Marsh) + * Python v3.9 or newer is now required. + * Several minor bug fixes, including to `injectpsr.py`, thanks to @remsforian + ## Version 5.0.1: * Minor improvements over v5.0.0 * Some clarifications and improvements to the build process diff --git a/meson.build b/meson.build index d0964463d..482d9fdae 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('PRESTO', 'c', - version: '5.0.1', + version: '5.0.2', license: 'GPL-2.0', default_options: [ 'buildtype=release', diff --git a/python/meson.build b/python/meson.build index 71b0a639a..06a3ea479 100644 --- a/python/meson.build +++ b/python/meson.build @@ -1,5 +1,5 @@ project('PRESTO_python', 'c', 'fortran', - version: '5.0.1', + version: '5.0.2', license: 'GPL-2.0', default_options: [ 'buildtype=release', @@ -41,17 +41,6 @@ incdir_numpy = run_command(py3, ).stdout().strip() inc_np = include_directories(incdir_numpy) - -# Don't use the deprecated NumPy C API. Define this to a fixed version instead of -# NPY_API_VERSION in order not to break compilation for released SciPy versions -# when NumPy introduces a new deprecation. Use in a meson.build file:: -# -# py3.extension_module('_name', -# 'source_fname', -# numpy_nodepr_api) -# -numpy_nodepr_api = '-DNPY_NO_DEPRECATED_API=NPY_1_9_API_VERSION' - incdir_f2py = incdir_numpy / '..' / '..' / 'f2py' / 'src' inc_f2py = include_directories(incdir_f2py) fortranobject_c = incdir_f2py / 'fortranobject.c' diff --git a/python/ppgplot_src/_ppgplot.c b/python/ppgplot_src/_ppgplot.c index 9648befa9..f13499fc9 100644 --- a/python/ppgplot_src/_ppgplot.c +++ b/python/ppgplot_src/_ppgplot.c @@ -2,17 +2,16 @@ * FILE: * _ppgplot.c * DESCRIPTION: - * ppgplot: Python / Numeric Python interface to the PGPLOT graphical - * library. - * Tested with PGPLOT 5.2, Python 2.3.1 and Numeric 23.1, on - * Linux (v2.4.x). + * ppgplot: Python / Numeric Python interface to the PGPLOT graphical library. + * Tested with PGPLOT 5.2.2, Python 3.10+, and Numpy 1.2X/2.X on Linux * AUTHOR(S): - * Nick Patavalis (npat@efault.net) + * Nick Patavalis (npat@efault.net), Tom Marsh, Scott Ransom * NOTES: * - A few ppgplot functions have not been interfaced yet. * - The pythonic calling conventions of some functions are *not* * identical to the original PGPLOT ones. * - added pgpt1 15/04/2008 TRM + * - updates to docs and for Numpy 2.0 in June 2024 by SMR */ #include @@ -74,32 +73,51 @@ tofloatvector (PyObject *o, float **v, npy_intp *vsz) TRM, 12/02/09. This avoids an irritating deprecation warning from numpy. */ PyArrayObject* array = NULL; - array = (PyArrayObject*) PyArray_FromAny(o, PyArray_DescrFromType(NPY_FLOAT), 1, 1, NPY_ALIGNED | NPY_C_CONTIGUOUS | NPY_FORCECAST, NULL); - if(array == NULL) return NULL; - *vsz = PyArray_Size(array); - *v = (float*) PyArray_DATA(array); + array = (PyArrayObject*) PyArray_FromAny(o, PyArray_DescrFromType(NPY_FLOAT), 1, 1, + NPY_ARRAY_ALIGNED | NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_FORCECAST, NULL); + if (array == NULL) return NULL; + *vsz = PyArray_Size((PyArrayObject*) array); + *v = (float*) PyArray_DATA((PyArrayObject*) array); return (PyObject*)array; } /*************************************************************************/ +//static PyObject * +//tofloatmatX(PyObject *o, float **m, npy_intp *nr, npy_intp *nc) +//{ +// /* +// This is based on the tofloatvector() changes by TRM. +// */ +// PyArrayObject* array = NULL; +// array = (PyArrayObject*) PyArray_FromAny(o, PyArray_DescrFromType(NPY_FLOAT), 1, 1, +// NPY_ARRAY_ALIGNED | NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_FORCECAST, NULL); +// if(array == NULL) return NULL; +// *vsz = PyArray_Size(array); +// *v = (float*) PyArray_DATA(array); +// return (PyObject*)array; +//} + +/*************************************************************************/ + static PyObject * tofloatmat(PyObject *o, float **m, int *nr, int *nc) { + npy_intp newdims[2]; PyArrayObject *a1, *af1, *af2; int ownedaf1=0; char **tmpdat; /* Check if args are arrays. */ if (!PyArray_Check(o)) { - PyErr_SetString(PpgTYPEErr,"object is not an array"); - return(NULL); + PyErr_SetString(PpgTYPEErr,"object is not an array"); + return(NULL); } a1 = (PyArrayObject *)o; /* Check if args are matrices. */ if (a1->nd != 2) { - PyErr_SetString(PpgTYPEErr,"object is not a matrix"); - return(NULL); + PyErr_SetString(PpgTYPEErr,"object is not a matrix"); + return(NULL); } #ifdef DEBUG_TOARRAY @@ -107,29 +125,24 @@ tofloatmat(PyObject *o, float **m, int *nr, int *nc) #endif switch (a1->descr->type_num) { - case PyArray_FLOAT: - af1 = a1; - break; - case PyArray_CHAR: -#ifndef USE_NUMARRAY - case PyArray_UBYTE: -#endif -// case PyArray_SBYTE: - case PyArray_SHORT: - case PyArray_INT: -#ifndef USE_NUMARRAY - case PyArray_LONG: -#endif - case PyArray_DOUBLE: - if (!(af1 = (PyArrayObject *)PyArray_Cast(a1,PyArray_FLOAT))) { - PyErr_SetString(PpgTYPEErr,"cannot cast matrix to floats"); - return(NULL); - } - ownedaf1 = 1; - break; + case NPY_FLOAT: + af1 = a1; + break; + case NPY_CHAR: + case NPY_UBYTE: + case NPY_SHORT: + case NPY_INT: + case NPY_LONG: + case NPY_DOUBLE: + if (!(af1 = (PyArrayObject *)PyArray_Cast(a1,NPY_FLOAT))) { + PyErr_SetString(PpgTYPEErr,"cannot cast matrix to floats"); + return(NULL); + } + ownedaf1 = 1; + break; default: - PyErr_SetString(PpgTYPEErr,"cannot cast matrix to floats"); - return(NULL); + PyErr_SetString(PpgTYPEErr,"cannot cast matrix to floats"); + return(NULL); break; } @@ -139,11 +152,14 @@ tofloatmat(PyObject *o, float **m, int *nr, int *nc) af2 = af1; /* (void *) avoids irritating gcc warning about strict aliasing */ - if (PyArray_As2D((PyObject **)(void *)&af2, (char ***)&tmpdat, nr, nc, PyArray_FLOAT) == -1) { - af2 = NULL; - goto bailout; + if (PyArray_AsCArray((PyObject **)(void *)&af2, (char ***)&tmpdat, + newdims, 2, PyArray_DescrFromType(NPY_FLOAT)) == -1) { + af2 = NULL; + goto bailout; } - + *nr = (int ) newdims[0]; + *nc = (int ) newdims[1]; + /* WARNING: What follows is a little tricky and I dunno if I'm really allowed to do this. On the other hand it really conserves time and memory! So this assert statement will make sure that diff --git a/python/ppgplot_src/meson.build b/python/ppgplot_src/meson.build index 90978fe92..50d20a197 100644 --- a/python/ppgplot_src/meson.build +++ b/python/ppgplot_src/meson.build @@ -1,5 +1,3 @@ -# Note: will need to fix Numpy API deprecation soon -SMR -# c_args: [numpy_nodepr_api, '-Wno-unused-variable'], py3.extension_module('_ppgplot', '_ppgplot.c', include_directories: inc_np, dependencies : [py3_dep, libm, pgplot, cpgplot, x11, png], diff --git a/python/pyproject.toml b/python/pyproject.toml index a866bb796..fd844643e 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -1,12 +1,12 @@ [build-system] build-backend = 'mesonpy' -requires = ['meson-python', 'numpy<2.0'] +requires = ['meson-python', 'numpy'] [project] name = 'presto' -version = '5.0.1' +version = '5.0.2' description = 'PulsaR Exploration and Search TOolkit' -requires-python = '>=3.8' +requires-python = '>=3.9' dependencies = ['numpy', 'scipy', 'astropy', 'matplotlib'] authors = [ {name = 'Scott Ransom', email = 'sransom@nrao.edu'}, From 64b66f3ffac1c4c0c04f9a451b70cff5314c662d Mon Sep 17 00:00:00 2001 From: Scott Ransom Date: Sat, 22 Jun 2024 11:15:35 -0400 Subject: [PATCH 5/5] Removed numpy C-API deprecation fix --- python/fftfit_src/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/fftfit_src/meson.build b/python/fftfit_src/meson.build index 1bb872908..9705c45b2 100644 --- a/python/fftfit_src/meson.build +++ b/python/fftfit_src/meson.build @@ -7,7 +7,7 @@ fftfit_module = custom_target('fftfit_module', py3.extension_module('fftfit', [fftfit_module, fortranobject_c, 'brent.f', 'cprof.f', 'fccf.f', 'ffft.f', 'fftfit.f'], include_directories: [inc_np, inc_f2py], - c_args: [numpy_nodepr_api, '-Wno-unused-variable'], + c_args: ['-Wno-unused-variable'], dependencies : py3_dep, link_language: 'fortran', subdir: 'presto',