Rave objectified the wrwp generator and added the first tests jenkins-beamb-2
authorAnders Henja <anders@henjab.se>
Wed, 18 Sep 2013 10:30:30 +0000 (12:30 +0200)
committerAnders Henja <anders@henjab.se>
Wed, 18 Sep 2013 10:30:30 +0000 (12:30 +0200)
bin/wrwp_main.c
lib/wrwp.c
lib/wrwp.h
pywrwp/pywrwp.c
pywrwp/pywrwp.h [new file with mode: 0644]
test/pytest/WrwpTest.py

index 4aefd03..512b0ef 100644 (file)
@@ -18,10 +18,11 @@ along with HLHDF.  If not, see <http://www.gnu.org/licenses/>.
 
 /** Main function for deriving weather radar wind and reflectivity profiles
  * @file
- * @author Günther Haase, SMHI
+ * @author G�nther Haase, SMHI
  * @date 2011-11-29
  */
 int main (int argc,char *argv[]) {
+#ifdef KALLE
        RaveIO_t* raveio = RaveIO_open (argv[1]);
        PolarVolume_t* inobj = NULL;
        PolarVolume_t* result = NULL;
@@ -54,6 +55,6 @@ int main (int argc,char *argv[]) {
        RAVE_OBJECT_RELEASE (raveio);
        RAVE_OBJECT_RELEASE (inobj);
        RAVE_OBJECT_RELEASE (result);
-
+#endif
        exit (0);
 }
index cfae612..4eee9e5 100644 (file)
@@ -23,9 +23,123 @@ along with HLHDF.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "wrwp.h"
+#include "rave_debug.h"
+#include "rave_alloc.h"
+#include <string.h>
 
-PolarVolume_t* wrwp(PolarVolume_t* inobj) {
-       PolarVolume_t* result = NULL;
+/**
+ * Represents one wrwp generator
+ */
+struct _Wrwp_t {
+  RAVE_OBJECT_HEAD /** Always on top */
+  int dz; /**< Height interval for deriving a profile [m] */
+  int hmax; /**< Maximum height of the profile [m] */
+  int dmin; /**< Minimum distance for deriving a profile [m] */
+  int dmax; /**< Maximum distance for deriving a profile [m]*/
+  double emin; /**< Minimum elevation angle [deg] */
+  double vmin; /**< Radial velocity threshold [m/s] */
+};
+
+/*@{ Private functions */
+/**
+ * Constructor
+ */
+static int Wrwp_constructor(RaveCoreObject* obj)
+{
+  Wrwp_t* wrwp = (Wrwp_t*)obj;
+  wrwp->hmax = HMAX;
+  wrwp->dz = DZ;
+  wrwp->dmin = DMIN;
+  wrwp->dmax = DMAX;
+  wrwp->emin = EMIN;
+  wrwp->vmin = VMIN;
+  return 1;
+}
+
+/**
+ * Destructor
+ */
+static void Wrwp_destructor(RaveCoreObject* obj)
+{
+}
+
+/*@} End of Private functions */
+
+/*@{ Interface functions */
+void Wrwp_setDZ(Wrwp_t* self, int dz)
+{
+  RAVE_ASSERT((self != NULL), "self == NULL");
+  self->dz = dz;
+}
+
+int Wrwp_getDZ(Wrwp_t* self)
+{
+  RAVE_ASSERT((self != NULL), "self == NULL");
+  return self->dz;
+}
+
+void Wrwp_setHMAX(Wrwp_t* self, int hmax)
+{
+  RAVE_ASSERT((self != NULL), "self == NULL");
+  self->hmax = hmax;
+}
+
+int Wrwp_getHMAX(Wrwp_t* self)
+{
+  RAVE_ASSERT((self != NULL), "self == NULL");
+  return self->hmax;
+}
+
+void Wrwp_setDMIN(Wrwp_t* self, int dmin)
+{
+  RAVE_ASSERT((self != NULL), "self == NULL");
+  self->dmin = dmin;
+}
+
+int Wrwp_getDMIN(Wrwp_t* self)
+{
+  RAVE_ASSERT((self != NULL), "self == NULL");
+  return self->dmin;
+}
+
+void Wrwp_setDMAX(Wrwp_t* self, int dmax)
+{
+  RAVE_ASSERT((self != NULL), "self == NULL");
+  self->dmax = dmax;
+}
+
+int Wrwp_getDMAX(Wrwp_t* self)
+{
+  RAVE_ASSERT((self != NULL), "self == NULL");
+  return self->dmax;
+}
+
+void Wrwp_setEMIN(Wrwp_t* self, double emin)
+{
+  RAVE_ASSERT((self != NULL), "self == NULL");
+  self->emin = emin;
+}
+
+double Wrwp_getEMIN(Wrwp_t* self)
+{
+  RAVE_ASSERT((self != NULL), "self == NULL");
+  return self->emin;
+}
+
+void Wrwp_setVMIN(Wrwp_t* self, double vmin)
+{
+  RAVE_ASSERT((self != NULL), "self == NULL");
+  self->vmin = vmin;
+}
+
+double Wrwp_getVMIN(Wrwp_t* self)
+{
+  RAVE_ASSERT((self != NULL), "self == NULL");
+  return self->vmin;
+}
+
+VerticalProfile_t* Wrwp_generate(Wrwp_t* self, PolarVolume_t* inobj) {
+  VerticalProfile_t* result = NULL;
        PolarScan_t* scan = NULL;
        PolarScanParam_t* vrad = NULL;
        PolarScanParam_t* dbz = NULL;
@@ -36,12 +150,12 @@ PolarVolume_t* wrwp(PolarVolume_t* inobj) {
        double d, h;
        double alpha, beta, gamma, vvel, vdir, vstd, zsum, zmean, zstd;
 
-       result = RAVE_OBJECT_COPY (inobj);
+       result = RAVE_OBJECT_NEW (&VerticalProfile_TYPE);
        polnav = RAVE_OBJECT_NEW (&PolarNavigator_TYPE);
        nscans = PolarVolume_getNumberOfScans (inobj);
 
        // loop over atmospheric layers
-       for (iz=0; iz<HMAX; iz+=DZ) {
+       for (iz=0; iz<self->hmax; iz+=self->dz) {
 
                /* allocate memory and initialize with zeros */
                double *A = RAVE_CALLOC ((size_t)(NOR*NOC), sizeof (double));
@@ -79,8 +193,8 @@ PolarVolume_t* wrwp(PolarVolume_t* inobj) {
                                        for (ib=0; ib<nbins; ib++) {
                                                PolarNavigator_reToDh (polnav, (ib+0.5)*rscale, elangle, &d, &h);
                                                PolarScanParam_getValue (vrad, ib, ir, &val);
-                                               if ((h>=iz) && (h<iz+DZ) && (d>=DMIN) && (d<=DMAX) && (elangle*RAD2DEG>=EMIN) &&
-                                                       (val!=nodata) && (val!=undetect) && (abs(offset+gain*val)>=VMIN)) {
+                                               if ((h>=iz) && (h<iz+self->dz) && (d>=self->dmin) && (d<=self->dmax) && (elangle*RAD2DEG>=self->emin) &&
+                                                       (val!=nodata) && (val!=undetect) && (abs(offset+gain*val)>=self->vmin)) {
                                                        *(v+nv) = offset+gain*val;
                                                        *(az+nv) = 360./nrays*ir*DEG2RAD;
                                                        *(A+nv*NOC) = sin(*(az+nv));
@@ -105,7 +219,7 @@ PolarVolume_t* wrwp(PolarVolume_t* inobj) {
                                        for (ib=0; ib<nbins; ib++) {
                                                PolarNavigator_reToDh (polnav, (ib+0.5)*rscale, elangle, &d, &h);
                                                PolarScanParam_getValue (dbz, ib, ir, &val);
-                                               if ((h>=iz) && (h<iz+DZ) && (d>=DMIN) && (d<=DMAX) && (elangle*RAD2DEG>=EMIN) &&
+                                               if ((h>=iz) && (h<iz+self->dz) && (d>=self->dmin) && (d<=self->dmax) && (elangle*RAD2DEG>=self->emin) &&
                                                        (val!=nodata) && (val!=undetect)) {
                                                        *(z+nz) = dBZ2Z (offset+gain*val);
                                                        zsum = zsum + *(z+nz);
@@ -165,16 +279,27 @@ PolarVolume_t* wrwp(PolarVolume_t* inobj) {
                }
 
                if ((nv<NMIN) || (nz<NMIN))
-                       printf("%6d %6d %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f \n", iz+DZ/2, 0, -9999., -9999., -9999., -9999., -9999., -9999.);
+                       printf("%6d %6d %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f \n", iz+self->dz/2, 0, -9999., -9999., -9999., -9999., -9999., -9999.);
                else
-                       printf("%6d %6d %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f \n", iz+DZ/2, nv, vvel, vstd, vdir, -9999., zmean, zstd);
+                       printf("%6d %6d %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f \n", iz+self->dz/2, nv, vvel, vstd, vdir, -9999., zmean, zstd);
 
                RAVE_FREE (A);
                RAVE_FREE (b);
                RAVE_FREE (v);
                RAVE_FREE (z);
                RAVE_FREE (az);
-
        }
+
+  RAVE_OBJECT_RELEASE(polnav);
        return result;
 }
+
+/*@} End of Interface functions */
+
+RaveCoreObjectType Wrwp_TYPE = {
+    "Wrwp",
+    sizeof(Wrwp_t),
+    Wrwp_constructor,
+    Wrwp_destructor
+};
+
index b3571ea..ffcdfa6 100644 (file)
@@ -33,6 +33,7 @@ along with HLHDF.  If not, see <http://www.gnu.org/licenses/>.
 #include "rave_io.h"
 #include "cartesian.h"
 #include "polarvolume.h"
+#include "vertical_profile.h"
 #include "projectionregistry.h"
 #include "arearegistry.h"
 #include "projection.h"
@@ -57,18 +58,112 @@ along with HLHDF.  If not, see <http://www.gnu.org/licenses/>.
 #define LDB        NRHS            /* Leading dimension of the array specified for b */
 #define DMIN       4000            /* Minimum distance for deriving a profile [m] */
 #define DMAX       40000           /* Maximum distance for deriving a profile [m] */
-#define DZ         200             /* Height interval for deriving a profile [m] */
-#define HMAX       12000           /* Maximum height of the profile [m] */
 #define NMIN       36              /* Minimum sample size */
 #define EMIN       2.5             /* Minimum elevation angle [deg] */
 #define VMIN       2.0             /* Radial velocity threshold [m/s] */
+#define DZ         200             /* Height interval for deriving a profile [m] */
+#define HMAX       12000           /* Maximum height of the profile [m] */
+
+/**
+ * Defines a weather radar wind product generator
+ */
+typedef struct _Wrwp_t Wrwp_t;
+
+/**
+ * Type definition to use when creating a rave object.
+ */
+extern RaveCoreObjectType Wrwp_TYPE;
 
+/**
+ * Sets the height interval for deriving a profile [m]
+ * @param[in] self - self
+ * @param[in] dz - the height interval
+ */
+void Wrwp_setDZ(Wrwp_t* self, int dz);
+
+/**
+ * Returns the height interval for deriving a profile [m]
+ * @param[in] self - self
+ * @return the height interval (default value is DZ)
+ */
+int Wrwp_getDZ(Wrwp_t* self);
+
+/**
+ * Sets maximum height of the profile [m]
+ * @param[in] self - self
+ * @param[in] hmax - maximum height of the profile [m]
+ */
+void Wrwp_setHMAX(Wrwp_t* self, int hmax);
+
+/**
+ * Returns maximum height of the profile [m]
+ * @param[in] self - self
+ * @return maximum height of the profile (default is HMAX)
+ */
+int Wrwp_getHMAX(Wrwp_t* self);
+
+/**
+ * Sets minimum distance for deriving a profile [m]
+ * @param[in] self - self
+ * @param[in] dmin - minimum distance for deriving a profile [m]
+ */
+void Wrwp_setDMIN(Wrwp_t* self, int dmin);
+
+/**
+ * Returns minimum distance for deriving a profile [m]
+ * @param[in] self - self
+ * @return minimum distance for deriving a profile [m] (default DMIN)
+ */
+int Wrwp_getDMIN(Wrwp_t* self);
+
+/**
+ * Sets maximum distance for deriving a profile [m]
+ * @param[in] self - self
+ * @param[in] dmax - maximum distance for deriving a profile [m]
+ */
+void Wrwp_setDMAX(Wrwp_t* self, int dmax);
+
+/**
+ * Returns maximum distance for deriving a profile [m]
+ * @param[in] self - self
+ * @return maximum distance for deriving a profile [m] (default DMAX)
+ */
+int Wrwp_getDMAX(Wrwp_t* self);
+
+/**
+ * Sets minimum elevation angle [deg]
+ * @param[in] self - self
+ * @param[in] emin - minimum elevation angle [deg]
+ */
+void Wrwp_setEMIN(Wrwp_t* self, double emin);
+
+/**
+ * Returns minimum elevation angle [deg]
+ * @param[in] self - self
+ * @return Minimum elevation angle [deg] (default EMIN)
+ */
+double Wrwp_getEMIN(Wrwp_t* self);
+
+/**
+ * Sets radial velocity threshold [m/s]
+ * @param[in] self - self
+ * @param[in] vmin - radial velocity threshold [m/s]
+ */
+void Wrwp_setVMIN(Wrwp_t* self, double vmin);
+
+/**
+ * Returns radial velocity threshold [m/s]
+ * @param[in] self - self
+ * @return Radial velocity threshold [m/s] (default VMIN)
+ */
+double Wrwp_getVMIN(Wrwp_t* self);
 
 /**
  * Function for deriving wind and reflectivity profiles from polar volume data
- * @param[in] source - input volume
- * @returns PolarVolume_t* object containing the wind profile
+ * @param[in] self - self
+ * @param[in] iobj - input volume
+ * @returns the wind profile
  */
-PolarVolume_t* wrwp(PolarVolume_t* inobj);
+VerticalProfile_t* Wrwp_generate(Wrwp_t* self, PolarVolume_t* inobj);
 
 #endif
index 499c27a..aa3be93 100644 (file)
@@ -25,6 +25,10 @@ along with baltrad-wrwp.  If not, see <http://www.gnu.org/licenses/>.
 #include <math.h>
 #include <stdio.h>
 #include <string.h>
+
+#define PYWRWP_MODULE /**< include correct part of pywrwp.h */
+#include "pywrwp.h"
+
 #include <pypolarvolume.h>
 #include <pyverticalprofile.h>
 #include "wrwp.h"
@@ -56,8 +60,94 @@ PYRAVE_DEBUG_MODULE("_wrwp");
  */
 static PyObject* ErrorObject;
 
+
 /*@{ Weather radar wind profiles */
-static PyObject* _pywrwp_wrwp(PyObject* self, PyObject* args)
+
+/**
+ * Returns the native Wrwp_t instance.
+ * @param[in] pywrwp - the python wrwp instance
+ * @returns the native wrwp instance.
+ */
+static Wrwp_t*
+PyWrwp_GetNative(PyWrwp* pywrwp)
+{
+  RAVE_ASSERT((pywrwp != NULL), "pywrwp == NULL");
+  return RAVE_OBJECT_COPY(pywrwp->wrwp);
+}
+
+/**
+ * Creates a python wrwp from a native wrwp or will create an
+ * initial native wrwp if p is NULL.
+ * @param[in] p - the native wrwp (or NULL)
+ * @returns the python wrwp product generator.
+ */
+static PyWrwp*
+PyWrwp_New(Wrwp_t* p)
+{
+  PyWrwp* result = NULL;
+  Wrwp_t* cp = NULL;
+
+  if (p == NULL) {
+    cp = RAVE_OBJECT_NEW(&Wrwp_TYPE);
+    if (cp == NULL) {
+      RAVE_CRITICAL0("Failed to allocate memory for wrwp.");
+      raiseException_returnNULL(PyExc_MemoryError, "Failed to allocate memory for wrwp.");
+    }
+  } else {
+    cp = RAVE_OBJECT_COPY(p);
+    result = RAVE_OBJECT_GETBINDING(p); // If p already have a binding, then this should only be increfed.
+    if (result != NULL) {
+      Py_INCREF(result);
+    }
+  }
+
+  if (result == NULL) {
+    result = PyObject_NEW(PyWrwp, &PyWrwp_Type);
+    if (result != NULL) {
+      PYRAVE_DEBUG_OBJECT_CREATED;
+      result->wrwp = RAVE_OBJECT_COPY(cp);
+      RAVE_OBJECT_BIND(result->wrwp, result);
+    } else {
+      RAVE_CRITICAL0("Failed to create PyWrwp instance");
+      raiseException_gotoTag(done, PyExc_MemoryError, "Failed to allocate memory for PyWrwp.");
+    }
+  }
+
+done:
+  RAVE_OBJECT_RELEASE(cp);
+  return result;
+}
+
+/**
+ * Deallocates the wrwp generator
+ * @param[in] obj the object to deallocate.
+ */
+static void _pywrwp_dealloc(PyWrwp* obj)
+{
+  /*Nothing yet*/
+  if (obj == NULL) {
+    return;
+  }
+  PYRAVE_DEBUG_OBJECT_DESTROYED;
+  RAVE_OBJECT_UNBIND(obj->wrwp, obj);
+  RAVE_OBJECT_RELEASE(obj->wrwp);
+  PyObject_Del(obj);
+}
+
+/**
+ * Creates a new instance of the wrwp generator.
+ * @param[in] self this instance.
+ * @param[in] args arguments for creation (NOT USED).
+ * @return the object on success, otherwise NULL
+ */
+static PyObject* _pywrwp_new(PyObject* self, PyObject* args)
+{
+  PyWrwp* result = PyWrwp_New(NULL);
+  return (PyObject*)result;
+}
+
+
+static PyObject* _pywrwp_generate(PyWrwp* self, PyObject* args)
 {
        PyObject* obj = NULL;
        //PyPolarVolume* pyobj = NULL;
@@ -72,36 +162,170 @@ static PyObject* _pywrwp_wrwp(PyObject* self, PyObject* args)
        return NULL;
 }
 
+/**
+ * All methods a wrwp generator can have
+ */
+static struct PyMethodDef _pywrwp_methods[] =
+{
+  {"generate", (PyCFunction)_pywrwp_generate, 1},
+/*
+  {"method", NULL},
+  {"ppi", (PyCFunction) _pytransform_ppi, 1},
+  {"cappi", (PyCFunction) _pytransform_cappi, 1},
+  {"pcappi", (PyCFunction) _pytransform_pcappi, 1},
+  {"ctoscan", (PyCFunction) _pytransform_ctoscan, 1},
+  {"ctop", (PyCFunction) _pytransform_ctop, 1},
+  {"fillGap", (PyCFunction) _pytransform_fillGap, 1},*/
+  {NULL, NULL } /* sentinel */
+};
+
+/**
+ * Returns the specified attribute in the wrwp generator
+ * @param[in] self - the wrwp generator
+ */
+static PyObject* _pywrwp_getattr(PyWrwp* self, char* name)
+{
+  PyObject* res = NULL;
+  if (strcmp("dz", name) == 0) {
+    return PyInt_FromLong(Wrwp_getDZ(self->wrwp));
+  } else if (strcmp("hmax", name) == 0) {
+    return PyInt_FromLong(Wrwp_getHMAX(self->wrwp));
+  } else if (strcmp("dmin", name) == 0) {
+    return PyInt_FromLong(Wrwp_getDMIN(self->wrwp));
+  } else if (strcmp("dmax", name) == 0) {
+    return PyInt_FromLong(Wrwp_getDMAX(self->wrwp));
+  } else if (strcmp("emin", name) == 0) {
+    return PyFloat_FromDouble(Wrwp_getEMIN(self->wrwp));
+  } else if (strcmp("vmin", name) == 0) {
+    return PyFloat_FromDouble(Wrwp_getVMIN(self->wrwp));
+  }
+  res = Py_FindMethod(_pywrwp_methods, (PyObject*) self, name);
+  if (res)
+    return res;
+
+  PyErr_Clear();
+  PyErr_SetString(PyExc_AttributeError, name);
+  return NULL;
+}
+
+/**
+ * Returns the specified attribute in the wrwp generator
+ */
+static int _pywrwp_setattr(PyWrwp* self, char* name, PyObject* val)
+{
+  int result = -1;
+  if (name == NULL) {
+    goto done;
+  }
+  if (strcmp("dz", name) == 0) {
+    if (PyInt_Check(val)) {
+      Wrwp_setDZ(self->wrwp, PyInt_AsLong(val));
+    } else {
+      raiseException_gotoTag(done, PyExc_TypeError, "dz must be an integer");
+    }
+  } else if (strcmp("hmax", name) == 0) {
+    if (PyInt_Check(val)) {
+      Wrwp_setHMAX(self->wrwp, PyInt_AsLong(val));
+    } else {
+      raiseException_gotoTag(done, PyExc_TypeError, "hmax must be an integer");
+    }
+  } else if (strcmp("dmin", name) == 0) {
+    if (PyInt_Check(val)) {
+      Wrwp_setDMIN(self->wrwp, PyInt_AsLong(val));
+    } else {
+      raiseException_gotoTag(done, PyExc_TypeError, "dmin must be an integer");
+    }
+  } else if (strcmp("dmax", name) == 0) {
+    if (PyInt_Check(val)) {
+      Wrwp_setDMAX(self->wrwp, PyInt_AsLong(val));
+    } else {
+      raiseException_gotoTag(done, PyExc_TypeError, "dmax must be an integer");
+    }
+  } else if (strcmp("emin", name) == 0) {
+    if (PyFloat_Check(val)) {
+      Wrwp_setEMIN(self->wrwp, PyFloat_AsDouble(val));
+    } else if (PyInt_Check(val)) {
+      Wrwp_setEMIN(self->wrwp, (double)PyInt_AsLong(val));
+    } else {
+      raiseException_gotoTag(done, PyExc_TypeError, "emin must be an integer or a float");
+    }
+  } else if (strcmp("vmin", name) == 0) {
+    if (PyFloat_Check(val)) {
+      Wrwp_setVMIN(self->wrwp, PyFloat_AsDouble(val));
+    } else if (PyInt_Check(val)) {
+      Wrwp_setVMIN(self->wrwp, (double)PyInt_AsLong(val));
+    } else {
+      raiseException_gotoTag(done, PyExc_TypeError, "vmin must be an integer or a float");
+    }
+  }
+
+  result = 0;
+done:
+  return result;
+}
 /*@} End of Weather radar wind profiles */
 
+/*@{ Type definitions */
+PyTypeObject PyWrwp_Type =
+{
+  PyObject_HEAD_INIT(NULL)0, /*ob_size*/
+  "WrwpCore", /*tp_name*/
+  sizeof(PyWrwp), /*tp_size*/
+  0, /*tp_itemsize*/
+  /* methods */
+  (destructor)_pywrwp_dealloc, /*tp_dealloc*/
+  0, /*tp_print*/
+  (getattrfunc)_pywrwp_getattr, /*tp_getattr*/
+  (setattrfunc)_pywrwp_setattr, /*tp_setattr*/
+  0, /*tp_compare*/
+  0, /*tp_repr*/
+  0, /*tp_as_number */
+  0,
+  0, /*tp_as_mapping */
+  0 /*tp_hash*/
+};
+
+/*@} End of Type definitions */
+
 /// --------------------------------------------------------------------
 /// Module setup
 /// --------------------------------------------------------------------
 /*@{ Module setup */
 static PyMethodDef functions[] = {
-  {"wrwp", (PyCFunction)_pywrwp_wrwp, 1},
+  {"new", (PyCFunction)_pywrwp_new, 1},
   {NULL,NULL} /*Sentinel*/
 };
 
-/**
- * Initializes polar volume.
- */
-void init_wrwp(void)
+PyMODINIT_FUNC
+init_wrwp(void)
 {
-  PyObject *module=NULL;
+  PyObject *module=NULL,*dictionary=NULL;
+  static void *PyWrwp_API[PyWrwp_API_pointers];
+  PyObject *c_api_object = NULL;
+  PyWrwp_Type.ob_type = &PyType_Type;
 
   module = Py_InitModule("_wrwp", functions);
   if (module == NULL) {
     return;
   }
+  PyWrwp_API[PyWrwp_Type_NUM] = (void*)&PyWrwp_Type;
+  PyWrwp_API[PyWrwp_GetNative_NUM] = (void *)PyWrwp_GetNative;
+  PyWrwp_API[PyWrwp_New_NUM] = (void*)PyWrwp_New;
+
+  c_api_object = PyCObject_FromVoidPtr((void *)PyWrwp_API, NULL);
+
+  if (c_api_object != NULL) {
+    PyModule_AddObject(module, "_C_API", c_api_object);
+  }
+
+  dictionary = PyModule_GetDict(module);
   ErrorObject = PyString_FromString("_wrwp.error");
-  if (ErrorObject == NULL || PyDict_SetItemString(PyModule_GetDict(module), "error", ErrorObject) != 0) {
+  if (ErrorObject == NULL || PyDict_SetItemString(dictionary, "error", ErrorObject) != 0) {
     Py_FatalError("Can't define _wrwp.error");
   }
 
-  import_array(); /*To make sure I get access to Numeric*/
+  import_array();
   import_pypolarvolume();
-  import_pyverticalprofile();
   PYRAVE_DEBUG_INITIALIZE;
 }
 /*@} End of Module setup */
diff --git a/pywrwp/pywrwp.h b/pywrwp/pywrwp.h
new file mode 100644 (file)
index 0000000..528107a
--- /dev/null
@@ -0,0 +1,119 @@
+/* --------------------------------------------------------------------
+Copyright (C) 2013 Swedish Meteorological and Hydrological Institute, SMHI,
+
+This file is part of baltrad-wrwp.
+
+baltrad-wrwp is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+baltrad-wrwp is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with baltrad-wrwp.  If not, see <http://www.gnu.org/licenses/>.
+------------------------------------------------------------------------*/
+/**
+ * Python version of the WRWP API.
+ * @file
+ * @author Anders Henja (Swedish Meteorological and Hydrological Institute, SMHI)
+ * @date 2013-09-18
+ */
+#ifndef PYWRWP_H
+#define PYWRWP_H
+#include <Python.h>
+#include "wrwp.h"
+
+/**
+ * The wrwp generator
+ */
+typedef struct {
+  PyObject_HEAD /*Always has to be on top*/
+  Wrwp_t* wrwp;  /**< the c-api wrwp generator */
+} PyWrwp;
+
+#define PyWrwp_Type_NUM 0                     /**< index for Type */
+
+#define PyWrwp_GetNative_NUM 1                /**< index for GetNative fp */
+#define PyWrwp_GetNative_RETURN Wrwp_t*       /**< Return type for GetNative */
+#define PyWrwp_GetNative_PROTO (PyWrwp*)      /**< Argument prototype for GetNative */
+
+#define PyWrwp_New_NUM 2                      /**< index for New fp */
+#define PyWrwp_New_RETURN PyWrwp*             /**< Return type for New */
+#define PyWrwp_New_PROTO (Wrwp_t*)            /**< Argument prototype for New */
+
+#define PyWrwp_API_pointers 3                 /**< total number of C API pointers */
+
+#ifdef PYWRWP_MODULE
+/** declared in pywrwp module */
+extern PyTypeObject PyWrwp_Type;
+
+/** checks if the object is a PyWrwp type or not */
+#define PyWrwp_Check(op) ((op)->ob_type == &PyWrwp_Type)
+
+/** Prototype for PyWrwp modules GetNative function */
+static PyWrwp_GetNative_RETURN PyWrwp_GetNative PyWrwp_GetNative_PROTO;
+
+/** Prototype for PyWrwp modules New function */
+static PyWrwp_New_RETURN PyWrwp_New PyWrwp_New_PROTO;
+
+#else
+/** static pointer containing the pointers to function pointers and other definitions */
+static void **PyWrwp_API;
+
+/**
+ * Returns a pointer to the internal polar scan, remember to release the reference
+ * when done with the object. (RAVE_OBJECT_RELEASE).
+ */
+#define PyWrwp_GetNative \
+  (*(PyWrwp_GetNative_RETURN (*)PyWrwp_GetNative_PROTO) PyWrwp_API[PyWrwp_GetNative_NUM])
+
+/**
+ * Creates a new polar scan instance. Release this object with Py_DECREF.
+ * @param[in] wrwp - the Wrwp_t intance.
+ * @returns the PyWrwp instance.
+ */
+#define PyWrwp_New \
+  (*(PyWrwp_New_RETURN (*)PyWrwp_New_PROTO) PyWrwp_API[PyWrwp_New_NUM])
+
+/**
+ * Checks if the object is a python wrwp generator.
+ */
+#define PyWrwp_Check(op) \
+   ((op)->ob_type == (PyTypeObject *)PyWrwp_API[PyWrwp_Type_NUM])
+
+/**
+ * Imports the PyWrwp module (like import _wrwp in python).
+ */
+static int
+import_pywrwp(void)
+{
+  PyObject *module;
+  PyObject *c_api_object;
+
+  module = PyImport_ImportModule("_wrwp");
+  if (module == NULL) {
+    return -1;
+  }
+
+  c_api_object = PyObject_GetAttrString(module, "_C_API");
+  if (c_api_object == NULL) {
+    Py_DECREF(module);
+    return -1;
+  }
+  if (PyCObject_Check(c_api_object)) {
+    PyWrwp_API = (void **)PyCObject_AsVoidPtr(c_api_object);
+  }
+  Py_DECREF(c_api_object);
+  Py_DECREF(module);
+  return 0;
+}
+
+#endif
+
+
+
+#endif /* PYWRWP_H */
index 846ab6e..1917bb4 100644 (file)
@@ -25,6 +25,7 @@ Tests the wrwp module.
 '''
 
 import unittest
+import string
 import _wrwp
 import _helpers
 
@@ -35,8 +36,73 @@ class WrwpTest(unittest.TestCase):
   def tearDown(self):
     pass
 
-  def testWrwp(self):
-    pass
+  def test_new(self):
+    obj = _wrwp.new()
+    self.assertNotEqual(-1, string.find(`type(obj)`, "WrwpCore"))
+
+  def test_dz(self):
+    obj = _wrwp.new()
+    self.assertEquals(200, obj.dz)
+    obj.dz = 100
+    self.assertEquals(100, obj.dz)
+    try:
+      obj.dz = 200.0
+      self.fail("Expected TypeError")
+    except TypeError, e:
+      pass
+    self.assertEquals(100, obj.dz)
+
+  def test_hmax(self):
+    obj = _wrwp.new()
+    self.assertEquals(12000, obj.hmax)
+    obj.hmax = 100
+    self.assertEquals(100, obj.hmax)
+    try:
+      obj.hmax = 200.0
+      self.fail("Expected TypeError")
+    except TypeError, e:
+      pass
+    self.assertEquals(100, obj.hmax)
+
+  def test_dmin(self):
+    obj = _wrwp.new()
+    self.assertEquals(4000, obj.dmin)
+    obj.dmin = 100
+    self.assertEquals(100, obj.dmin)
+    try:
+      obj.dmin = 200.0
+      self.fail("Expected TypeError")
+    except TypeError, e:
+      pass
+    self.assertEquals(100, obj.dmin)
+    
+  def test_dmax(self):
+    obj = _wrwp.new()
+    self.assertEquals(40000, obj.dmax)
+    obj.dmax = 100
+    self.assertEquals(100, obj.dmax)
+    try:
+      obj.dmax = 200.0
+      self.fail("Expected TypeError")
+    except TypeError, e:
+      pass
+    self.assertEquals(100, obj.dmax)
+
+  def test_emin(self):
+    obj = _wrwp.new()
+    self.assertAlmostEquals(2.5, obj.emin, 4)
+    obj.emin = 3.5
+    self.assertAlmostEquals(3.5, obj.emin, 4)
+    obj.emin = 4
+    self.assertAlmostEquals(4.0, obj.emin, 4)
 
+  def test_vmin(self):
+    obj = _wrwp.new()
+    self.assertAlmostEquals(2.0, obj.vmin, 4)
+    obj.vmin = 3.5
+    self.assertAlmostEquals(3.5, obj.vmin, 4)
+    obj.vmin = 4
+    self.assertAlmostEquals(4.0, obj.vmin, 4)
+    
 if __name__ == "__main__":
   unittest.main()
\ No newline at end of file