Added first draft of ropo support hudson-bRack-8-SUCCESS
authorAnders Henja <anders@pclx006.(none)>
Thu, 1 Sep 2011 15:49:03 +0000 (17:49 +0200)
committerAnders Henja <anders@pclx006.(none)>
Thu, 1 Sep 2011 15:49:03 +0000 (17:49 +0200)
12 files changed:
pyrack/pyfmiimage.c
pyrack/pyropo.c
rack/bin/ropo.c
rack/bin/ropo_help.c
rack/bin/ropo_help.h [new file with mode: 0644]
rack/ropo/rave_fmi_image.c
rack/ropo/rave_fmi_image.h
test/pytest/FmiImageTest.py [new file with mode: 0644]
test/pytest/PyRopoTest.py [new file with mode: 0644]
test/pytest/RackTestSuite.py
test/pytest/fixtures/pvol_rix.h5 [new file with mode: 0644]
test/pytest/fixtures/pvol_seang_20090501T120000Z.h5 [new file with mode: 0644]

index 9f2bd21..354f7f1 100644 (file)
@@ -181,6 +181,40 @@ static PyObject* _pyfmiimage_fromRave(PyObject* self, PyObject* args)
   return (PyObject*)result;
 }
 
+/**
+ * Returns the sweep count
+ * @param[in] self - self
+ * @param[in] args - N/A
+ * @return the number of sweeps
+ */
+static PyObject* _pyfmiimage_getSweepCount(PyFmiImage* self, PyObject* args)
+{
+  return PyInt_FromLong(RaveFmiImage_getSweepCount(self->image));
+}
+
+/**
+ * Returns the rave polar volume
+ * @param[in] self - self
+ * @param[in] args - a string specifying quantity. Default is DBZH.
+ * @return the rave polar volume
+ */
+static PyObject* _pyfmiimage_toRave(PyFmiImage* self, PyObject* args)
+{
+  char* quantity = NULL;
+  PolarVolume_t* volume = NULL;
+  PyObject* result = NULL;
+
+  if (!PyArg_ParseTuple(args, "|s", &quantity)) {
+    return NULL;
+  }
+  volume = RaveFmiImage_toRave(self->image, quantity);
+  if (volume != NULL) {
+    result = (PyObject*)PyPolarVolume_New(volume);
+  }
+
+  return result;
+}
+
 /*@} End Of FmiImage */
 
 /**
@@ -188,6 +222,8 @@ static PyObject* _pyfmiimage_fromRave(PyObject* self, PyObject* args)
  */
 static struct PyMethodDef _pyfmiimage_methods[] =
 {
+  {"getSweepCount", (PyCFunction)_pyfmiimage_getSweepCount, 1},
+  {"toRave", (PyCFunction)_pyfmiimage_toRave, 1},
   /*{"longitude", NULL},
   {"getDistance", (PyCFunction) _pypolarvolume_getDistance, 1},*/
     /*
index c50eb5c..0e7a742 100644 (file)
@@ -27,9 +27,19 @@ along with bRack.  If not, see <http://www.gnu.org/licenses/>.
 #include <math.h>
 #include <stdio.h>
 #include <string.h>
+#include <rack/ropo/fmi_util.h>
+#include <rack/ropo/fmi_image.h>
+#include <rack/ropo/fmi_image_filter.h>
+#include <rack/ropo/fmi_image_filter_line.h>
+#include <rack/ropo/fmi_image_histogram.h>
+#include <rack/ropo/fmi_image_filter_speck.h>
+#include <rack/ropo/fmi_image_filter_morpho.h>
+#include <rack/ropo/fmi_image_restore.h>
+#include <rack/ropo/fmi_meteosat.h>
+#include <rack/ropo/fmi_radar_image.h>
 
 #include "pyrave_debug.h"
-
+#include "pyfmiimage.h"
 
 /**
  * Debug this module
@@ -54,16 +64,206 @@ PYRAVE_DEBUG_MODULE("_pyropo");
 static PyObject *ErrorObject;
 
 /*@{ Functions */
+static void _pyropointernal_update_classification(FmiImage *prob,FmiImage *master_prob,FmiImage *mark,Byte marker)
+{
+  register int i;
+  for (i = 0; i < prob->volume;i++) {
+    if (prob->array[i] >= master_prob->array[i]) {
+      if (mark != NULL) {
+        mark->array[i]=marker;
+      }
+      master_prob->array[i]=prob->array[i];
+    }
+  }
+}
+
+static PyObject* _pyropo_speck(PyObject* self, PyObject* args)
+{
+  PyObject* inptr = NULL;
+  PyObject* result = NULL;
+  PyFmiImage* image = NULL;
+  RaveFmiImage_t* prob = NULL;
+  FmiImage* sourceSweep = NULL; /* Do not release, internal memory */
+  FmiImage* probSweep = NULL;   /* Do not release, internal memory */
+
+  int sweep = 0;
+  int intensity = 0, sz = 0; /* min DBZ, max area */
+  if (!PyArg_ParseTuple(args, "Oii|i", &inptr, &intensity, &sz, &sweep)) {
+    return NULL;
+  }
+
+  if (!PyFmiImage_Check(inptr)) {
+    raiseException_returnNULL(PyExc_TypeError, "speck takes FmiImages as input");
+  }
+  image = (PyFmiImage*)inptr;
+  sourceSweep = RaveFmiImage_getSweep(image->image, sweep);
+  if (sourceSweep == NULL) {
+    raiseException_returnNULL(PyExc_TypeError, "Input fmi image does not contain that sweep");
+  }
+
+  prob = RaveFmiImage_new(1);
+  if (prob == NULL) {
+    return NULL;
+  }
+  probSweep = RaveFmiImage_getSweep(prob, 0);
+  detect_specks(sourceSweep, probSweep, intensity, histogram_area);
+  semisigmoid_image(probSweep, sz);
+  invert_image(probSweep);
+  translate_intensity(probSweep, 255, 0);
+
+  result = (PyObject*)PyFmiImage_New(prob, 0);
+  RAVE_OBJECT_RELEASE(prob);
+  return result;
+}
+
+static PyObject* _pyropo_emitter(PyObject* self, PyObject* args)
+{
+  PyObject* inptr = NULL;
+  PyObject* result = NULL;
+  PyFmiImage* image = NULL;
+  RaveFmiImage_t* prob = NULL;
+  FmiImage* sourceSweep = NULL; /* Do not release, internal memory */
+  FmiImage* probSweep = NULL;   /* Do not release, internal memory */
+
+  int sweep = 0;
+  int intensity = 0, sz = 0; /* min DBZ, max area */
+  if (!PyArg_ParseTuple(args, "Oii|i", &inptr, &intensity, &sz, &sweep)) {
+    return NULL;
+  }
+
+  if (!PyFmiImage_Check(inptr)) {
+    raiseException_returnNULL(PyExc_TypeError, "speck takes FmiImages as input");
+  }
+  image = (PyFmiImage*)inptr;
+  sourceSweep = RaveFmiImage_getSweep(image->image, sweep);
+  if (sourceSweep == NULL) {
+    raiseException_returnNULL(PyExc_TypeError, "Input fmi image does not contain that sweep");
+  }
+
+  prob = RaveFmiImage_new(1);
+  if (prob == NULL) {
+    return NULL;
+  }
+  probSweep = RaveFmiImage_getSweep(prob, 0);
+  detect_emitters(sourceSweep, probSweep, intensity, sz);
+
+  result = (PyObject*)PyFmiImage_New(prob, 0);
+  RAVE_OBJECT_RELEASE(prob);
+  return result;
+}
+
+static PyObject* _pyropo_restore(PyObject* self, PyObject* args)
+{
+  PyObject* sweepptr = NULL;
+  PyObject* inprobabilityptr = NULL;
+  PyFmiImage* sweep = NULL;
+  PyFmiImage* probability = NULL;
+  RaveFmiImage_t* resultimage = NULL;
+  PyObject* result = NULL;
+  FmiImage* sourceSweep = NULL; /* Do not release, internal memory */
+  FmiImage* probabilitySweep = NULL; /* Do not release, internal memory */
+  int threshold = 255;
+  int sweepnr = 0;
+
+  if (!PyArg_ParseTuple(args, "OOi|i", &sweepptr, &inprobabilityptr, &threshold, &sweepnr)) {
+    return NULL;
+  }
+
+  if (!PyFmiImage_Check(sweepptr) || !PyFmiImage_Check(inprobabilityptr)) {
+    raiseException_returnNULL(PyExc_TypeError, "restore takes sweep, probability field and threshold as input");
+  }
+  sweep = (PyFmiImage*)sweepptr;
+  probability = (PyFmiImage*)inprobabilityptr;
+
+  sourceSweep = RaveFmiImage_getSweep(sweep->image, sweepnr);
+  if (sourceSweep == NULL) {
+    raiseException_returnNULL(PyExc_TypeError, "Input fmi image does not contain that sweep");
+  }
+  probabilitySweep = RaveFmiImage_getSweep(probability->image, 0);
+  if (probabilitySweep == NULL) {
+    raiseException_returnNULL(PyExc_TypeError, "Probability field is empty");
+  }
+
+  resultimage = RaveFmiImage_new(1);
+  if (resultimage == NULL) {
+    return NULL;
+  }
+
+  restore_image(sourceSweep, RaveFmiImage_getSweep(resultimage, 0), probabilitySweep, threshold);
+
+  result = (PyObject*)PyFmiImage_New(resultimage, 0);
+  RAVE_OBJECT_RELEASE(resultimage);
+  return result;
+}
+
+static PyObject* _pyropo_update_classification(PyObject* self, PyObject* args)
+{
+  PyObject *classificationptr = NULL, *probabilityptr = NULL, *targetprobabilityptr = NULL;
+  PyFmiImage *classification = NULL, *probability = NULL, *targetprobability = NULL;
+  FmiImage *cSweep = NULL, *pSweep = NULL, *tSweep = NULL;
+
+  FmiRadarPGMCode marker = CLEAR;
+
+  if (!PyArg_ParseTuple(args, "OOi|O", &probabilityptr, &targetprobabilityptr, &marker, &classificationptr)) {
+    return NULL;
+  }
+
+  if (!PyFmiImage_Check(probabilityptr) || !PyFmiImage_Check(targetprobabilityptr)) {
+    raiseException_returnNULL(PyExc_TypeError, "Input types must be either OOi|O with probfield, targetprobfield, marker, classification field");
+  }
+  if (classificationptr != NULL && !PyFmiImage_Check(classificationptr)) {
+    raiseException_returnNULL(PyExc_TypeError, "Input types must be either OOi|O with probfield, targetprobfield, marker, classification field");
+  }
+  classification = (PyFmiImage*)classificationptr;
+  probability = (PyFmiImage*)probabilityptr;
+  targetprobability = (PyFmiImage*)targetprobabilityptr;
+
+  if (RaveFmiImage_getSweepCount(probability->image) != 1 ||
+      RaveFmiImage_getSweepCount(targetprobability->image) != 1 ||
+      (classification != NULL && RaveFmiImage_getSweepCount(targetprobability->image) != 1)) {
+    raiseException_returnNULL(PyExc_TypeError, "Input types must be either OOi|O with probfield, targetprobfield, marker, classification field with sweep count 1");
+  }
+  if (classification != NULL) {
+    cSweep = RaveFmiImage_getSweep(classification->image, 0);
+  }
+  pSweep = RaveFmiImage_getSweep(probability->image, 0);
+  tSweep = RaveFmiImage_getSweep(targetprobability->image, 0);
+
+  canonize_image(pSweep, cSweep);
+  canonize_image(pSweep, tSweep);
+
+  _pyropointernal_update_classification(pSweep, tSweep, cSweep, marker);
+
+  Py_RETURN_NONE;
+}
 
 /*@} End of Functions */
 
 /*@{ Module setup */
 static PyMethodDef functions[] = {
-  /*{"rave2fmiimage", (PyCFunction)_pyropo_rave2fmiimage, 1},
-  {"fmiimage2rave", (PyCFunction)_pyropo_fmiimage2rave, 1},*/
+  {"speck", (PyCFunction)_pyropo_speck, 1},
+  {"emitter", (PyCFunction)_pyropo_emitter, 1},
+  {"restore", (PyCFunction)_pyropo_restore, 1},
+  {"update_classification", (PyCFunction)_pyropo_update_classification, 1},
   {NULL,NULL} /*Sentinel*/
 };
 
+/**
+ * Adds constants to the dictionary (probably the modules dictionary).
+ * @param[in] dictionary - the dictionary the long should be added to
+ * @param[in] name - the name of the constant
+ * @param[in] value - the value
+ */
+static void add_long_constant(PyObject* dictionary, const char* name, long value)
+{
+  PyObject* tmp = NULL;
+  tmp = PyInt_FromLong(value);
+  if (tmp != NULL) {
+    PyDict_SetItemString(dictionary, name, tmp);
+  }
+  Py_XDECREF(tmp);
+}
+
 PyMODINIT_FUNC
 init_ropo(void)
 {
@@ -80,6 +280,27 @@ init_ropo(void)
   if (ErrorObject == NULL || PyDict_SetItemString(dictionary, "error", ErrorObject) != 0) {
     Py_FatalError("Can't define _ropo.error");
   }
+
+  add_long_constant(dictionary, "FmiRadarPGMCode_CLEAR", CLEAR);
+  add_long_constant(dictionary, "FmiRadarPGMCode_CUTOFF", CUTOFF);
+  add_long_constant(dictionary, "FmiRadarPGMCode_BIOMET", BIOMET);
+  add_long_constant(dictionary, "FmiRadarPGMCode_SHIP", SHIP);
+  add_long_constant(dictionary, "FmiRadarPGMCode_SUN", SUN);
+  add_long_constant(dictionary, "FmiRadarPGMCode_EMITTER", EMITTER);
+  add_long_constant(dictionary, "FmiRadarPGMCode_EMITTER2", EMITTER2);
+  add_long_constant(dictionary, "FmiRadarPGMCode_CLUTTER", CLUTTER);
+  add_long_constant(dictionary, "FmiRadarPGMCode_CLUTTER2", CLUTTER2);
+  add_long_constant(dictionary, "FmiRadarPGMCode_SPECK", SPECK);
+  add_long_constant(dictionary, "FmiRadarPGMCode_DOPPLER", DOPPLER);
+  add_long_constant(dictionary, "FmiRadarPGMCode_GROUND", GROUND);
+  add_long_constant(dictionary, "FmiRadarPGMCode_METEOSAT", METEOSAT);
+  add_long_constant(dictionary, "FmiRadarPGMCode_EMITTER3", EMITTER3);
+  add_long_constant(dictionary, "FmiRadarPGMCode_DATA_MIN", DATA_MIN);
+  add_long_constant(dictionary, "FmiRadarPGMCode_DATA_MAX", DATA_MAX);
+  add_long_constant(dictionary, "FmiRadarPGMCode_NO_DATA", NO_DATA);
+
+  import_fmiimage();
+
 /*
   import_pypolarvolume();
   import_pypolarscan();
index e995384..0236908 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <polarvolume.h>
 #include <rack/ropo/ropo_hdf.h>
+#include "rack/bin/ropo_help.h"
 PolarVolume_t * template;
 
 Byte LAST_FILTER;
index 438c87e..bdfee7e 100644 (file)
@@ -1,3 +1,7 @@
+#include <stdio.h>
+
+void ropo_help(void)
+{
 printf("RADAR IMAGE INPUT \n");
 printf(" sweeps:\n");
 printf("  sweep1.pgm [sweep2.pgm ... sweepN.pgm]\n");
@@ -45,18 +49,18 @@ printf("           50           20 \n");
 printf(" -emitter <MIN_DBZ> <LENGTH>   Filter unity-width emitter lines\n");
 printf("            10dbz      4 \n");
 printf(" -emitter0 <MIN_DBZ> <min_length> <max_width>   Filter emitter lines\n");
-printf(" -emitter0  -20dBZ       8bins        2°           \n");
+printf(" -emitter0  -20dBZ       8bins        2�           \n");
 printf(" -emitter2 <MIN_DBZ> <LENGTH> <width>   Filter emitter lines\n");
-printf("              -10dbz 4bins 2°\n");
-printf("              -10dbz 3bins 3°\n");
+printf("              -10dbz 4bins 2�\n");
+printf("              -10dbz 3bins 3�\n");
 printf(" -emitter2 <MIN_DBZ> <LENGTH> <width>   Filter emitter lines\n");
 printf("               10        4        2 \n");
 printf(" -sun      <MIN_DBZ>  <min_length> <max_thickness>      Remove sun \n");
 printf("            -20dBZ        100           3\n");
 printf(" -sun2   <MIN_DBZ>  <min_length> <max_thickness> <azimuth> <elevation>   Remove sun \n");
-printf("           -20dBZ        100          3             45°        2°\n");
+printf("           -20dBZ        100          3             45�        2�\n");
 printf(" -doppler <filename> <WIDTH> <HEIGHT> <threshold>   Remove doppler anomalies\n");
-printf(" -doppler file.pgm 1bins 1° 128   Remove doppler anomalies\n");
+printf(" -doppler file.pgm 1bins 1� 128   Remove doppler anomalies\n");
 printf(" sampling\n");
 printf("  -SVc x y     Volume dbz's, cartesian coords\n");
 printf("  -SVp r phi   Volume dbz's, polar coords\n");
@@ -101,3 +105,4 @@ printf("     m    gray, marked, ppm\n");
 printf("     h    gray, hdf5\n");
 printf("DEBUGGING <0=nothing ... 5 everything> (dump info and intermed. res. images)\n");
 printf(" -debug <n>  \n");
+}
diff --git a/rack/bin/ropo_help.h b/rack/bin/ropo_help.h
new file mode 100644 (file)
index 0000000..453f2bc
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * ropo_help.h
+ *
+ *  Created on: Sep 1, 2011
+ *      Author: anders
+ */
+
+#ifndef ROPO_HELP_H
+#define ROPO_HELP_H
+
+/**
+ * Prints the help text for ropo
+ */
+void ropo_help(void);
+
+#endif /* ROPO_HELP_H */
index 3c8f708..c90c38d 100644 (file)
@@ -49,6 +49,10 @@ static int RaveFmiImage_constructor(RaveCoreObject* obj)
   return 1;
 }
 
+/**
+ * Releases all memory allocated in the fmi image.
+ * @param[in] img - the rave fmi image to reset
+ */
 static void RaveFmiImageInternal_resetImage(RaveFmiImage_t* img)
 {
   int i = 0;
@@ -116,6 +120,8 @@ static int RaveFmiImageInternal_getSweepCount(PolarVolume_t* volume, const char*
 static int RaveFmiImageInternal_scanToFmiImage(PolarScan_t* scan, const char* quantity, FmiImage* image)
 {
   int i = 0, j = 0;
+  int result = 0;
+  PolarScanParam_t* param = NULL;
 
   RAVE_ASSERT((scan != NULL), "scan == NULL");
   RAVE_ASSERT((image != NULL), "image == NULL");
@@ -123,25 +129,134 @@ static int RaveFmiImageInternal_scanToFmiImage(PolarScan_t* scan, const char* qu
   image->width=PolarScan_getNbins(scan);
   image->height=PolarScan_getNrays(scan);
   image->bin_depth=PolarScan_getRscale(scan);
-  image->elevation_angle=PolarScan_getElangle(scan);
+  image->elevation_angle=PolarScan_getElangle(scan) * 180.0 / M_PI; /* elangles in degrees for ropo */
   image->max_value=255;
   image->channels=1;
 
   initialize_image(image);
 
+  if (quantity == NULL) {
+    param = PolarScan_getParameter(scan, "DBZH");
+  } else {
+    param = PolarScan_getParameter(scan, quantity);
+  }
+
+  if (param == NULL) {
+    RAVE_WARNING1("Failed to extract parameter %s from scan", quantity);
+    goto done;
+  }
+  if (PolarScanParam_getDataType(param) != RaveDataType_CHAR &&
+      PolarScanParam_getDataType(param) != RaveDataType_UCHAR) {
+    RAVE_WARNING0("FmiImages can only support 8-bit data");
+    goto done;
+  }
+
   for (j = 0; j < image->height; j++) {
     for (i = 0; i < image->width; i++) {
       double value = 0.0;
-      if (quantity == NULL) {
-        PolarScan_getValue(scan, i, j, &value);
-      } else {
-        PolarScan_getParameterValue(scan, quantity, i, j, &value);
-      }
-      put_pixel(image, i, j, 0, (Byte)(value+0.5));
+      PolarScanParam_getValue(param, i, j, &value);
+      put_pixel(image, i, j, 0, (Byte)(value)); // why + 0.5 ?
     }
   }
 
-  return 1;
+  result = 1;
+done:
+  RAVE_OBJECT_RELEASE(param);
+  return result;
+}
+
+/**
+ * Converts a rave field into a fmi image
+ * @param[in] field - the rave field
+ * @param[in] image - the image to be filled
+ * @return 1 on success otherwise 0
+ */
+static int RaveFmiImageInternal_fieldToFmiImage(RaveField_t* field, FmiImage* image)
+{
+  int i = 0, j = 0;
+  int result = 0;
+
+  RAVE_ASSERT((field != NULL), "field == NULL");
+  RAVE_ASSERT((image != NULL), "image == NULL");
+
+  image->width=RaveField_getXsize(field);
+  image->height=RaveField_getYsize(field);
+  image->channels=1;
+
+  initialize_image(image);
+
+  if (RaveField_getDataType(field) != RaveDataType_CHAR &&
+      RaveField_getDataType(field) != RaveDataType_UCHAR) {
+    RAVE_WARNING0("FmiImages can only support 8-bit data");
+    goto done;
+  }
+
+  for (j = 0; j < image->height; j++) {
+    for (i = 0; i < image->width; i++) {
+      double value = 0.0;
+      RaveField_getValue(field, i, j, &value);
+      put_pixel(image, i, j, 0, (Byte)(value)); // why + 0.5 ?
+    }
+  }
+
+  result = 1;
+done:
+  return result;
+}
+
+/**
+ * Creates a polar scan from an fmi image.
+ * @param[in] image - the fmi image
+ * @param[in] quantity - the quantity of the parameter. If null, default is DBZH.
+ * @return the polar scan on success otherwise NULL
+ */
+static PolarScan_t* RaveFmiImageInternal_fmiImageToScan(FmiImage* image, const char* quantity)
+{
+  PolarScan_t* scan = NULL;
+  PolarScan_t* result = NULL;
+  PolarScanParam_t* param = NULL;
+  int ray = 0, bin = 0;
+  RAVE_ASSERT((image != NULL), "image == NULL");
+
+  scan = RAVE_OBJECT_NEW(&PolarScan_TYPE);
+  param = RAVE_OBJECT_NEW(&PolarScanParam_TYPE);
+  if (scan == NULL || param == NULL) {
+    RAVE_CRITICAL0("Failed to allocate memory for polar scan");
+    goto done;
+  }
+
+  PolarScanParam_setGain(param, 1.0);
+  PolarScanParam_setOffset(param, 0.0);
+  PolarScanParam_setNodata(param, 255.0);
+  PolarScanParam_setUndetect(param, 0.0);
+  if (quantity != NULL) {
+    PolarScanParam_setQuantity(param, quantity);
+  } else {
+    PolarScanParam_setQuantity(param, "DBZH");
+  }
+  if (!PolarScanParam_createData(param, image->width, image->height, RaveDataType_UCHAR)) {
+    RAVE_CRITICAL0("Failed to allocate memory for data");
+    goto done;
+  }
+
+  for (ray = 0; ray < image->height; ray++) {
+    for (bin = 0; bin < image->width; bin++) {
+      PolarScanParam_setValue(param, bin, ray, (double)get_pixel(image, bin, ray, 0));
+    }
+  }
+  if (!PolarScan_addParameter(scan, param)) {
+    RAVE_CRITICAL0("Failed to add parameter to scan");
+    goto done;
+  }
+  PolarScan_setRscale(scan, image->bin_depth);
+  PolarScan_setElangle(scan, image->elevation_angle * M_PI / 180.0);
+  PolarScan_setRstart(scan, 0.0);
+
+  result = RAVE_OBJECT_COPY(scan);
+done:
+  RAVE_OBJECT_RELEASE(scan);
+  RAVE_OBJECT_RELEASE(param);
+  return result;
 }
 
 /*@} End of Private functions */
@@ -151,12 +266,16 @@ int RaveFmiImage_initialize(RaveFmiImage_t* self, int sweepCount)
 {
   int result = 0;
   RAVE_ASSERT((self != NULL), "self == NULL");
-  FmiImage* images = new_image(sweepCount);
-  if (images != NULL) {
-    RaveFmiImageInternal_resetImage(self);
-    self->image = images;
-    self->sweepCount = sweepCount;
-    result = 1;
+  if (sweepCount <= 0) {
+    RAVE_ERROR0("You can not initialize a fmi image with sweepCount <= 0");
+  } else {
+    FmiImage* images = new_image(sweepCount);
+    if (images != NULL) {
+      RaveFmiImageInternal_resetImage(self);
+      self->image = images;
+      self->sweepCount = sweepCount;
+      result = 1;
+    }
   }
   return result;
 }
@@ -173,14 +292,49 @@ FmiImage* RaveFmiImage_getImage(RaveFmiImage_t* self)
   return self->image;
 }
 
+FmiImage* RaveFmiImage_getSweep(RaveFmiImage_t* self, int sweep)
+{
+  RAVE_ASSERT((self != NULL), "self == NULL");
+  if (sweep >= 0 && sweep < self->sweepCount) {
+    return &self->image[sweep];
+  }
+  return NULL;
+}
+
 PolarVolume_t* RaveFmiImage_toRave(RaveFmiImage_t* self, const char* quantity)
 {
-  /*PolarVolume_t* result = NULL;
-  PolarVolume_t* volume = NULL;*/
+  PolarVolume_t* result = NULL;
+  PolarVolume_t* volume = NULL;
+  PolarScan_t* scan = NULL;
+
+  int i = 0;
 
   RAVE_ASSERT((self != NULL), "self == NULL");
 
-  return NULL;
+  volume = RAVE_OBJECT_NEW(&PolarVolume_TYPE);
+  if (volume == NULL) {
+    RAVE_CRITICAL0("Failed to create volume");
+    goto done;
+  }
+
+  for (i = 0; i < self->sweepCount; i++) {
+    scan = RaveFmiImageInternal_fmiImageToScan(&self->image[i], quantity);
+    if (scan == NULL) {
+      RAVE_CRITICAL0("Failed to convert image to scan");
+      goto done;
+    }
+    if (!PolarVolume_addScan(volume, scan)) {
+      RAVE_CRITICAL0("Failed to add scan to volume");
+      goto done;
+    }
+    RAVE_OBJECT_RELEASE(scan);
+  }
+
+  result = RAVE_OBJECT_COPY(volume);
+done:
+  RAVE_OBJECT_RELEASE(scan);
+  RAVE_OBJECT_RELEASE(volume);
+  return result;
 }
 
 RaveFmiImage_t* RaveFmiImage_new(int sweepCount)
@@ -194,7 +348,7 @@ RaveFmiImage_t* RaveFmiImage_new(int sweepCount)
   return result;
 }
 
-RaveFmiImage_t* RaveFmiImage_fromRave(PolarVolume_t* volume, const char* quantity)
+RaveFmiImage_t* RaveFmiImage_fromPolarVolume(PolarVolume_t* volume, const char* quantity)
 {
   int sweepCount = 0;
   int nrScans = 0;
@@ -239,7 +393,70 @@ done:
   return result;
 }
 
+RaveFmiImage_t* RaveFmiImage_fromPolarScan(PolarScan_t* scan, const char* quantity)
+{
+  RaveFmiImage_t* image = NULL;
+  RaveFmiImage_t* result = NULL;
+
+  RAVE_ASSERT((scan != NULL), "scan == NULL");
+
+  image = RaveFmiImage_new(1);
+  if (image == NULL) {
+    RAVE_CRITICAL0("Failed to create fmi image");
+    goto done;
+  }
+
+  if (quantity == NULL || PolarScan_hasParameter(scan, quantity)) {
+    if (!RaveFmiImageInternal_scanToFmiImage(scan, quantity, &image->image[0])) {
+      RAVE_ERROR0("Failed to convert scan to fmi image");
+      goto done;
+    }
+  }
+
+  result = RAVE_OBJECT_COPY(image);
+done:
+  RAVE_OBJECT_RELEASE(image);
+  return result;
+}
+
+RaveFmiImage_t* RaveFmiImage_fromRaveField(RaveField_t* field)
+{
+  RaveFmiImage_t* image = NULL;
+  RaveFmiImage_t* result = NULL;
+
+  RAVE_ASSERT((field != NULL), "field == NULL");
 
+  image = RaveFmiImage_new(1);
+  if (image == NULL) {
+    RAVE_CRITICAL0("Failed to create fmi image");
+    goto done;
+  }
+
+  if (!RaveFmiImageInternal_fieldToFmiImage(field, &image->image[0])) {
+    RAVE_ERROR0("Failed to convert rave field to fmi image");
+    goto done;
+  }
+
+  result = RAVE_OBJECT_COPY(image);
+done:
+  RAVE_OBJECT_RELEASE(image);
+  return result;
+}
+
+RaveFmiImage_t* RaveFmiImage_fromRave(RaveCoreObject* object, const char* quantity)
+{
+  RAVE_ASSERT((object != NULL), "object == NULL");
+  if (RAVE_OBJECT_CHECK_TYPE(object, &PolarVolume_TYPE)) {
+    return RaveFmiImage_fromPolarVolume((PolarVolume_t*)object, quantity);
+  } else if (RAVE_OBJECT_CHECK_TYPE(object, &PolarScan_TYPE)) {
+    return RaveFmiImage_fromPolarScan((PolarScan_t*)object, quantity);
+  } else if (RAVE_OBJECT_CHECK_TYPE(object, &RaveField_TYPE)) {
+    return RaveFmiImage_fromRaveField((RaveField_t*)object);
+  } else {
+    RAVE_ERROR1("RaveFmiImage_fromRave does not support %s", object->roh_type->name);
+  }
+  return NULL;
+}
 
 /*@} End of Interface functions */
 RaveCoreObjectType RaveFmiImage_TYPE = {
index 73ae5d8..e0789e3 100644 (file)
@@ -29,6 +29,7 @@ along with bRack.  If not, see <http://www.gnu.org/licenses/>.
 #include "rack/ropo/fmi_image.h"
 #include "rave_object.h"
 #include "polarvolume.h"
+#include "polarscan.h"
 
 /**
  * Defines a RaveFmiImage
@@ -44,7 +45,7 @@ extern RaveCoreObjectType RaveFmiImage_TYPE;
  * Initializes the rave image with the specific number of sweeps.
  * @see \ref RaveFmiImage_new for short cut version
  * @param[in] self - self
- * @param[in] sweepCount - number of sweeps this image should consist of
+ * @param[in] sweepCount - number of sweeps this image should consist of > 0
  * @return 1 on success otherwise 0
  */
 int RaveFmiImage_initialize(RaveFmiImage_t* self, int sweepCount);
@@ -64,6 +65,14 @@ int RaveFmiImage_getSweepCount(RaveFmiImage_t* self);
 FmiImage* RaveFmiImage_getImage(RaveFmiImage_t* self);
 
 /**
+ * Returns the internal sweep pointer.
+ * @param[in] self - self
+ * @param[in] sweep - the sweep index
+ * @return the sweep at specified index
+ */
+FmiImage* RaveFmiImage_getSweep(RaveFmiImage_t* self, int sweep);
+
+/**
  * Creates a polar volume from a fmi image
  * @param[in] self - self
  * @param[in] quantity - the quantity to be set for the parameters (may be NULL)
@@ -73,7 +82,7 @@ PolarVolume_t* RaveFmiImage_toRave(RaveFmiImage_t* self, const char* quantity);
 
 /**
  * Creates a rave fmi image with specified number of sweeps
- * @param[in] sweepCount - the number of sweeps
+ * @param[in] sweepCount - the number of sweeps > 0
  * @return the fmi image on success otherwise NULL
  */
 RaveFmiImage_t* RaveFmiImage_new(int sweepCount);
@@ -82,8 +91,32 @@ RaveFmiImage_t* RaveFmiImage_new(int sweepCount);
  * Creates a fmi image from a polar volume
  * @param[in] volume - the polar volume
  * @param[in] quantity - the quantity to use for building the fmi image (NULL == default parameter)
- * @return 1 on success otherwise 0
+ * @return the object on success otherwise NULL
+ */
+RaveFmiImage_t* RaveFmiImage_fromPolarVolume(PolarVolume_t* volume, const char* quantity);
+
+/**
+ * Creates a fmi image from a polar scan
+ * @param[in] scan - the polar scan
+ * @param[in] quantity - the quantity to use for building the fmi image (NULL == default parameter)
+ * @return the object on success otherwise NULL
+ */
+RaveFmiImage_t* RaveFmiImage_fromPolarScan(PolarScan_t* scan, const char* quantity);
+
+/**
+ * Creates a fmi image from a rave field
+ * @param[in] field - the rave field
+ * @return the object on success otherwise NULL
+ */
+RaveFmiImage_t* RaveFmiImage_fromRaveField(RaveField_t* field);
+
+/**
+ * Creates a fmi image from a rave object. Currently supported object types
+ * are. PolarVolume_t, PolarScan_t and RaveField_t
+ * @param[in] object - the object to generate an fmi image from
+ * @param[in] quantity - the specific quantity (NULL == default parameter if applicable)
+ * @return the object on success otherwise NULL
  */
-RaveFmiImage_t* RaveFmiImage_fromRave(PolarVolume_t* volume, const char* quantity);
+RaveFmiImage_t* RaveFmiImage_fromRave(RaveCoreObject* object, const char* quantity);
 
 #endif /* RAVE_FMI_IMAGE_H */
diff --git a/test/pytest/FmiImageTest.py b/test/pytest/FmiImageTest.py
new file mode 100644 (file)
index 0000000..6aa6ab7
--- /dev/null
@@ -0,0 +1,42 @@
+'''
+Created on Sep 1, 2011
+
+@author: anders
+'''
+import unittest
+import string
+import _raveio
+import _fmiimage
+
+class FmiImageTest(unittest.TestCase):
+  PVOL_TESTFILE="fixtures/pvol_seang_20090501T120000Z.h5"
+
+  def setUp(self):
+    pass
+
+  def tearDown(self):
+    pass
+
+  def testFromRave(self):
+    a = _raveio.open(self.PVOL_TESTFILE)
+    b = _fmiimage.fromRave(a.object)
+    self.assertNotEqual(-1, string.find(`type(b)`, "FmiImageCore"))
+    self.assertEqual(10, b.getSweepCount())
+
+  def testFromRave_withQuantity(self):
+    a = _raveio.open(self.PVOL_TESTFILE)
+    b = _fmiimage.fromRave(a.object, "DBZH")
+    self.assertNotEqual(-1, string.find(`type(b)`, "FmiImageCore"))
+    self.assertEqual(10, b.getSweepCount())
+  
+  def testToRave(self):
+    a = _raveio.open(self.PVOL_TESTFILE).object
+    b = _fmiimage.fromRave(a, "DBZH")
+    c = b.toRave("DBZH")
+    self.assertEqual(a.getNumberOfScans(), c.getNumberOfScans())
+    self.assertAlmostEqual(a.getScan(0).elangle, c.getScan(0).elangle, 4)
+    self.assertTrue(c.getScan(0).hasParameter("DBZH"))
+    
+if __name__ == "__main__":
+  #import sys;sys.argv = ['', 'Test.testName']
+  unittest.main()
\ No newline at end of file
diff --git a/test/pytest/PyRopoTest.py b/test/pytest/PyRopoTest.py
new file mode 100644 (file)
index 0000000..96dc384
--- /dev/null
@@ -0,0 +1,83 @@
+'''
+Created on Sep 1, 2011
+
+@author: anders
+'''
+import unittest
+
+import _fmiimage
+import _raveio
+import _ropo
+import os
+class PyRopoTest(unittest.TestCase):
+  PVOL_TESTFILE="fixtures/pvol_seang_20090501T120000Z.h5"
+  PVOL_RIX_TESTFILE="fixtures/pvol_rix.h5"
+  
+  TEMPORARY_FILE="ropotest_file1.h5"
+  TEMPORARY_FILE2="ropotest_file2.h5"
+  
+  def setUp(self):
+    if os.path.isfile(self.TEMPORARY_FILE):
+      os.unlink(self.TEMPORARY_FILE)
+    if os.path.isfile(self.TEMPORARY_FILE2):
+      os.unlink(self.TEMPORARY_FILE2)
+
+  def tearDown(self):
+    pass
+    #if os.path.isfile(self.TEMPORARY_FILE):
+    #  os.unlink(self.TEMPORARY_FILE)
+    #if os.path.isfile(self.TEMPORARY_FILE2):
+    #  os.unlink(self.TEMPORARY_FILE2)  
+      
+  def XtestSpeck(self):
+    a = _raveio.open(self.PVOL_RIX_TESTFILE).object
+    b = _fmiimage.fromRave(a, "DBZH")
+    c = _ropo.speck(b, -20, 5);
+    
+    output = _raveio.new()
+    output.object = c.toRave()
+    output.filename = self.TEMPORARY_FILE
+    output.save()
+
+  def XtestEmitter(self):
+    a = _raveio.open(self.PVOL_RIX_TESTFILE).object
+    b = _fmiimage.fromRave(a, "DBZH")
+    c = _ropo.emitter(b, 3, 6);
+    
+    output = _raveio.new()
+    output.object = c.toRave()
+    output.filename = self.TEMPORARY_FILE
+    output.save()
+
+  def testRestore(self):
+    a = _raveio.open(self.PVOL_RIX_TESTFILE).object
+    b = _fmiimage.fromRave(a, "DBZH")
+    c = _ropo.emitter(b, 3, 6)
+    c = _ropo.restore(b, c, 10)
+    
+    output = _raveio.new()
+    output.object = c.toRave()
+    output.filename = self.TEMPORARY_FILE
+    output.save()
+  
+  def testUpdateClassification(self):
+    a = _raveio.open(self.PVOL_RIX_TESTFILE).object
+    b = _fmiimage.fromRave(a, "DBZH")
+    speck = _ropo.speck(b, -20, 5);
+    emitter = _ropo.emitter(b, 3, 6)
+    
+    masterprob = _fmiimage.new(1)
+    classification = _fmiimage.new(1)
+    _ropo.update_classification(speck, masterprob, _ropo.FmiRadarPGMCode_SPECK, classification)
+    _ropo.update_classification(emitter, masterprob, _ropo.FmiRadarPGMCode_EMITTER, classification)
+    
+    c = _ropo.restore(b, masterprob, 10) # To get image cleaned up by accumulated probability
+    
+    output = _raveio.new()
+    output.object = c.toRave()
+    output.filename = self.TEMPORARY_FILE
+    output.save()
+      
+if __name__ == "__main__":
+  #import sys;sys.argv = ['', 'Test.testName']
+  unittest.main()
\ No newline at end of file
index 2c5d009..83e2330 100644 (file)
@@ -25,7 +25,9 @@ Test suite for bRack
 '''
 import unittest
 
-from RaveRackTest import *
+#from RaveRackTest import *
+from FmiImageTest import *
+from PyRopoTest import *
 
 if __name__ == "__main__":
   unittest.main()
\ No newline at end of file
diff --git a/test/pytest/fixtures/pvol_rix.h5 b/test/pytest/fixtures/pvol_rix.h5
new file mode 100644 (file)
index 0000000..9c17e31
Binary files /dev/null and b/test/pytest/fixtures/pvol_rix.h5 differ
diff --git a/test/pytest/fixtures/pvol_seang_20090501T120000Z.h5 b/test/pytest/fixtures/pvol_seang_20090501T120000Z.h5
new file mode 100644 (file)
index 0000000..18c187e
Binary files /dev/null and b/test/pytest/fixtures/pvol_seang_20090501T120000Z.h5 differ