Beam blockage with caching, etc hudson-beamb-17-SUCCESS
authorAnders Henja <anders@baltrad.eu>
Mon, 2 Jan 2012 17:31:03 +0000 (18:31 +0100)
committerAnders Henja <anders@baltrad.eu>
Mon, 2 Jan 2012 17:31:03 +0000 (18:31 +0100)
15 files changed:
.gitignore
INSTALL [new file with mode: 0644]
Makefile
configure
configure.in
lib/Makefile
lib/bbtopography.c
lib/beamb.c
lib/beamblockage.c
lib/beamblockage.h
lib/beamblockagemap.c
pybeamb/Makefile
pybeamb/pybeamblockage.c
test/pytest/PyBeamBlockageTest.py
test/pytest/fixtures/sevil_0.5_20111223T0000Z.h5 [new file with mode: 0644]

index 1b45321..bd0c90b 100644 (file)
@@ -7,3 +7,5 @@
 *.pyc
 Debug
 
+lib/config.h
+def.mk
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..004a051
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,31 @@
+INSTALL instructions for
+BEAM BLOCKAGE MODULE
+  BEAMB
+
+Anders Henja and Lars Norin
+Swedish Meteorological and Hydrological Institute
+
+January 2012
+
+BEAMB is completly dependent on a working RAVE installation so refer
+to RAVEs installation instructions before installing BEAMB.
+
+When you have successfully installed RAVE, you should only need to perform
+the traditional configure, make, make install.
+
+%> ./configure --prefix=/opt/n2/beamb --with-rave=/opt/n2/rave
+%> make
+%> make test
+%> make install
+
+Since beamb keeps a cache with the beam blockage classification, you might want
+to specify an alternative location of the cache-files. The default location is
+<prefix>/var/cache/beamb (/opt/baltrad/beamb/var/cache/beamb). 
+But can be changed by specifying the --localstatedir=<cachedir>. Be aware that
+cache/beamb is always appended to the cache path which means that
+the following configure call:
+
+%> ./configure ... --localstatedir=/var
+
+would create a directory called /var/cache/beamb during installation.
+
index 1f84bb4..1e1cbc6 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -66,7 +66,5 @@ distclean:
        $(MAKE) -C lib distclean
        $(MAKE) -C pybeamb distclean
        $(MAKE) -C data distclean
-       #$(MAKE) -C doxygen distclean
-       #$(MAKE) -C config distclean
-       #$(MAKE) -C test/pytest distclean
+       $(MAKE) -C test/pytest distclean
        @\rm -f *~ config.log config.status def.mk
index 0ecd0ae..019aee9 100755 (executable)
--- a/configure
+++ b/configure
@@ -2742,7 +2742,7 @@ if [ "$HLHDF_SZLIB_LIB" != "" ]; then
   LD_PRINTOUT=$LD_PRINTOUT:`echo "$HLHDF_SZLIB_LIB" | sed -e"s/[ \t]*-L//"`
 fi
 
-BEAMB_CACHE_DIR=`echo $localstatedir`/cache
+BEAMB_CACHE_DIR=`echo $localstatedir`/cache/beamb
 
 
 
index 9e3fc86..d30653a 100644 (file)
@@ -180,7 +180,7 @@ if [[ "$HLHDF_SZLIB_LIB" != "" ]]; then
   LD_PRINTOUT=$LD_PRINTOUT:`echo "$HLHDF_SZLIB_LIB" | sed -e"s/[[ \t]]*-L//"`
 fi
 
-BEAMB_CACHE_DIR=`echo $localstatedir`/cache
+BEAMB_CACHE_DIR=`echo $localstatedir`/cache/beamb
 
 AC_SUBST(RAVE_ROOT_DIR)
 AC_SUBST(RAVE_INCLUDE_FLAG)
index fc995bd..706837a 100644 (file)
@@ -74,6 +74,7 @@ $(TARGET): $(DEPDIR) $(OBJECTS)
 install:
        @mkdir -p ${prefix}/include/
        @mkdir -p ${prefix}/lib/
+       @mkdir -p ${BEAMB_CACHE_DIR}
        @cp -v -f *.h ${prefix}/include/
        @cp -v -f $(TARGET) ${prefix}/lib/
 
index 55cf1da..6fc9935 100644 (file)
@@ -263,6 +263,7 @@ int BBTopography_getValueAtLonLat(BBTopography_t* self, double lon, double lat,
 
   ci = (lon - self->ulxmap)/self->xdim;
   ri = (self->ulymap - lat)/self->ydim;
+
   if (RaveData2D_getValue(self->data, ci, ri, &nv)) {
     *v = nv;
     result = 1;
index 68d94d7..b8af09a 100644 (file)
@@ -92,6 +92,12 @@ int main(void)
         radar[1] = 12.826024108; /* Longitude [degrees] */
         radar[2] = 163.61;       /* Altitude [m] */
     }
+    else if (strcmp(radar_name,"vil") == 0)
+    {
+      radar[0] = 58.1059;      /* Latitude [degrees] */
+      radar[1] = 15.9363;      /* Longitude [degrees] */
+      radar[2] = 223.0;        /* Altitude [m] */
+    }
     else
     {
         printf("Unknown radar. Exiting.");
index b9c826e..5a5d828 100644 (file)
@@ -31,6 +31,8 @@ along with beamb.  If not, see <http://www.gnu.org/licenses/>.
 #include "math.h"
 #include <string.h>
 #include "config.h"
+#include "hlhdf.h"
+#include "odim_io_utilities.h"
 
 /**
  * Represents the beam blockage algorithm
@@ -39,6 +41,7 @@ struct _BeamBlockage_t {
   RAVE_OBJECT_HEAD /** Always on top */
   BeamBlockageMap_t* mapper; /**< the topography reader */
   char* cachedir;            /**< the cache directory */
+  int rewritecache;         /**< if cache should be recreated */
 };
 
 /*@{ Private functions */
@@ -50,6 +53,7 @@ static int BeamBlockage_constructor(RaveCoreObject* obj)
   BeamBlockage_t* self = (BeamBlockage_t*)obj;
   self->cachedir = NULL;
   self->mapper = RAVE_OBJECT_NEW(&BeamBlockageMap_TYPE);
+  self->rewritecache = 0;
 
   if (self->mapper == NULL || !BeamBlockage_setCacheDirectory(self, BEAMB_CACHE_DIR)) {
          goto error;
@@ -82,6 +86,7 @@ static int BeamBlockage_copyconstructor(RaveCoreObject* obj, RaveCoreObject* src
   BeamBlockage_t* src = (BeamBlockage_t*)srcobj;
   this->mapper = RAVE_OBJECT_CLONE(src->mapper);
   this->cachedir = NULL;
+  this->rewritecache = src->rewritecache;
 
   if (this->mapper == NULL || !BeamBlockage_setCacheDirectory(this, src->cachedir)) {
     goto error;
@@ -171,11 +176,12 @@ static void BeamBlockageInternal_cummax(double* p, long nlen)
  *
  * @param[in] self - self
  * @param[in] scan - scan
+ * @param[in] dblim - Limit of Gaussian approximation of main lobe
  * @param[in] filename - the allocated array where the filename should be written
  * @param[in] len - the length of the allocated array
  * @return 1 on success otherwise 0
  */
-static int BeamBlockageInternal_createCacheFilename(BeamBlockage_t* self, PolarScan_t* scan, char* filename, int len)
+static int BeamBlockageInternal_createCacheFilename(BeamBlockage_t* self, PolarScan_t* scan, double dblim, char* filename, int len)
 {
   int result = 0;
   double lat, lon, height, bw, elangle, rscale, rstart;
@@ -197,12 +203,12 @@ static int BeamBlockageInternal_createCacheFilename(BeamBlockage_t* self, PolarS
 
   if (self->cachedir == NULL) {
     elen = snprintf(filename, len,
-                    "%.2f_%.2f_%.0f_%.2f_%ld_%ld_%.2f_%.2f_%.2f.h5\n",
-                    lon, lat, height, elangle, nrays, nbins, rscale, rstart, bw);
+                    "%.2f_%.2f_%.0f_%.2f_%ld_%ld_%.2f_%.2f_%.2f_%.2f.h5",
+                    lon, lat, height, elangle, nrays, nbins, rscale, rstart, bw, dblim);
   } else {
     elen = snprintf(filename, len,
-                    "%s/%.2f_%.2f_%.0f_%.2f_%ld_%ld_%.2f_%.2f_%.2f.h5\n",
-                    self->cachedir, lon, lat, height, elangle, nrays, nbins, rscale, rstart, bw);
+                    "%s/%.2f_%.2f_%.0f_%.2f_%ld_%ld_%.2f_%.2f_%.2f_%.2f.h5",
+                    self->cachedir, lon, lat, height, elangle, nrays, nbins, rscale, rstart, bw, dblim);
   }
 
   if (elen >= len) {
@@ -215,27 +221,137 @@ done:
   return result;
 }
 
+static int BeamBlockageInternal_addMetaInformation(RaveField_t* field, double gain, double offset)
+{
+  RaveAttribute_t* attribute = NULL;
+  int result = 0;
+
+  attribute = RaveAttributeHelp_createString("how/task", "se.smhi.detector.beamblockage");
+  if (attribute == NULL || !RaveField_addAttribute(field, attribute)) {
+    RAVE_ERROR0("Failed to add how/task");
+    goto done;
+  }
+  RAVE_OBJECT_RELEASE(attribute);
+
+  attribute = RaveAttributeHelp_createDouble("what/gain", gain);
+  if (attribute == NULL || !RaveField_addAttribute(field, attribute)) {
+    RAVE_ERROR0("Failed to add what/gain");
+    goto done;
+  }
+  RAVE_OBJECT_RELEASE(attribute);
+
+  attribute = RaveAttributeHelp_createDouble("what/offset", offset);
+  if (attribute == NULL || !RaveField_addAttribute(field, attribute)) {
+    RAVE_ERROR0("Failed to add what/offset");
+    goto done;
+  }
+  RAVE_OBJECT_RELEASE(attribute);
+
+  result = 1;
+done:
+  RAVE_OBJECT_RELEASE(attribute);
+  return result;
+}
+
 /**
  * Returns a cached file matching the given scan if there is one.
  * @param[in] self - self
  * @param[in] scan - the scan
+ * @param[in] dblim - Limit of Gaussian approximation of main lobe
  */
-static RaveField_t* BeamBlockageInternal_getCachedFile(BeamBlockage_t* self, PolarScan_t* scan)
+static RaveField_t* BeamBlockageInternal_getCachedFile(BeamBlockage_t* self, PolarScan_t* scan, double dblim)
 {
   RaveField_t* result = NULL;
+  HL_NodeList* nodelist = NULL;
 
   RAVE_ASSERT((self != NULL), "self == NULL");
   RAVE_ASSERT((scan != NULL), "scan == NULL");
 
   if (self->cachedir != NULL) {
     char filename[512];
-    if (!BeamBlockageInternal_createCacheFilename(self, scan, filename, 512)) {
+    if (!BeamBlockageInternal_createCacheFilename(self, scan, dblim, filename, 512)) {
       goto done;
     }
-    fprintf(stderr, "FILENAME: %s\n", filename);
+
+    if(HL_isHDF5File(filename)) {
+      nodelist =  HLNodeList_read(filename);
+      if (nodelist == NULL) {
+        RAVE_ERROR1("Failed to read hdf5 file %s", filename);
+        goto done;
+      }
+      HLNodeList_selectAllNodes(nodelist);
+      if (!HLNodeList_fetchMarkedNodes(nodelist)) {
+        RAVE_ERROR1("Failed to load hdf5 file '%s'", filename);
+        goto done;
+      }
+
+      result = OdimIoUtilities_loadField(nodelist, "/beamb_field");
+    }
   }
 
 done:
+  HLNodeList_free(nodelist);
+  return result;
+}
+
+/**
+ * Writes a rave field to the cache. There is no particular file properties or
+ * compressions used.
+ * @param[in] self - self
+ * @param[in] scan - the scan
+ * @param[in] field - the rave field
+ * @param[in] dblim - Limit of Gaussian approximation of main lobe
+ * @return 1 on success otherwise 0
+ */
+static int BeamBlockageInternal_writeCachedFile(BeamBlockage_t* self, PolarScan_t* scan, RaveField_t* field, double dblim)
+{
+  int result = 0;
+  HL_NodeList* nodelist = NULL;
+  HL_Compression* compression = NULL;
+  HL_FileCreationProperty* property = NULL;
+
+  RAVE_ASSERT((self != NULL), "self == NULL");
+  RAVE_ASSERT((scan != NULL), "scan == NULL");
+  RAVE_ASSERT((field != NULL), "field == NULL");
+
+  if (self->cachedir != NULL) {
+    char filename[512];
+    if (!BeamBlockageInternal_createCacheFilename(self, scan, dblim, filename, 512)) {
+      goto done;
+    }
+    compression = HLCompression_new(CT_ZLIB);
+    property = HLFileCreationProperty_new();
+    nodelist = HLNodeList_new();
+
+    if (nodelist == NULL || compression == NULL || property == NULL) {
+      RAVE_ERROR0("Failed to create necessary hlhdf objects");
+      goto done;
+    }
+    compression->level = (int)6;
+    property->userblock = (hsize_t)0;
+    property->sizes.sizeof_size = (size_t)4;
+    property->sizes.sizeof_addr = (size_t)4;
+    property->sym_k.ik = (int)1;
+    property->sym_k.lk = (int)1;
+    property->istore_k = (long)1;
+    property->meta_block_size = (long)0;
+
+    result = OdimIoUtilities_addRaveField(field, nodelist, "/beamb_field");
+    if (result == 1) {
+      result = HLNodeList_setFileName(nodelist, filename);
+    }
+    if (result == 1) {
+      result = HLNodeList_write(nodelist, property, compression);
+    }
+  } else {
+    result = 1; /* We always succeed when there is no cache file to be written */
+  }
+
+done:
+  HLCompression_free(compression);
+  HLFileCreationProperty_free(property);
+  HLNodeList_free(nodelist);
+
   return result;
 }
 
@@ -281,6 +397,17 @@ const char* BeamBlockage_getCacheDirectory(BeamBlockage_t* self)
   return (const char*)self->cachedir;
 }
 
+void BeamBlockage_setRewriteCache(BeamBlockage_t* self, int recreateCache)
+{
+  RAVE_ASSERT((self != NULL), "self == NULL");
+  self->rewritecache = recreateCache;
+}
+
+int BeamBlockage_getRewriteCache(BeamBlockage_t* self)
+{
+  return self->rewritecache;
+}
+
 RaveField_t* BeamBlockage_getBlockage(BeamBlockage_t* self, PolarScan_t* scan, double dBlim)
 {
   RaveField_t *field = NULL, *result = NULL;
@@ -296,13 +423,23 @@ RaveField_t* BeamBlockage_getBlockage(BeamBlockage_t* self, PolarScan_t* scan, d
   double c, elLim, bb_tot;
   double elBlock = 0.0;
 
+  /* We want range to be between 0 - 255 as unsigned char */
+  double gain = 1 / 255.0;
+  double offset = 0.0;
+
   RAVE_ASSERT((self != NULL), "self == NULL");
 
   if (scan == NULL) {
     return NULL;
   }
 
-  BeamBlockageInternal_getCachedFile(self, scan);
+  if (self->rewritecache == 0) {
+    /* If we want to recreate cache, there is no meaning to read the cached file */
+    field = BeamBlockageInternal_getCachedFile(self, scan, dBlim);
+    if (field != NULL) {
+      return field; /* We already have what we want so return before we do anything else */
+    }
+  }
 
   navigator = PolarScan_getNavigator(scan);
   if (navigator == NULL) {
@@ -324,7 +461,7 @@ RaveField_t* BeamBlockage_getBlockage(BeamBlockage_t* self, PolarScan_t* scan, d
   nrays = PolarScan_getNrays(scan);
 
   field = RAVE_OBJECT_NEW(&RaveField_TYPE);
-  if (field == NULL || !RaveField_createData(field, nbins, nrays, RaveDataType_DOUBLE)) {
+  if (field == NULL || !RaveField_createData(field, nbins, nrays, RaveDataType_UCHAR)) {
     goto done;
   }
 
@@ -337,8 +474,8 @@ RaveField_t* BeamBlockage_getBlockage(BeamBlockage_t* self, PolarScan_t* scan, d
   R = 1.0/((1.0/RE) + PolarNavigator_getDndh(navigator));
   height = PolarNavigator_getAlt0(navigator);
 
-  beamwidth = PolarScan_getBeamwidth(scan);
-  elangle = PolarScan_getElangle(scan);
+  beamwidth = PolarScan_getBeamwidth(scan) * 180.0 / M_PI;
+  elangle = PolarScan_getElangle(scan) * 180.0 / M_PI;
 
   /* Width of Gaussian */
   c = -((beamwidth/2.0)*(beamwidth/2.0))/log(0.5);
@@ -354,8 +491,6 @@ RaveField_t* BeamBlockage_getBlockage(BeamBlockage_t* self, PolarScan_t* scan, d
       double v = 0.0;
       BBTopography_getValue(topo, bi, ri, &v);
       phi[bi] = asin((((v+R)*(v+R)) - (groundRange[bi]*groundRange[bi]) - ((R+height)*(R+height))) / (2*groundRange[bi]*(R+height)));
-      //fprintf(stderr, "ri=%d, bi=%d => phi(%d) = %f\n", ri, bi, bi, phi[bi]);
-      //phi[j] = asin((pow(v + R, 2) - pow(groundRange[bi],2) - pow(R + height,2) ) / (2*groundRange[bi]*(R+height)));
     }
     BeamBlockageInternal_cummax(phi, nbins);
 
@@ -369,12 +504,24 @@ RaveField_t* BeamBlockage_getBlockage(BeamBlockage_t* self, PolarScan_t* scan, d
         elBlock = elangle + elLim;
       }
       bbval = -1.0/2.0 * sqrt(M_PI * c) * (erf((elangle - elBlock)/sqrt(c)) - erf(elLim/sqrt(c)))/bb_tot;
+      if (bbval < 0.0) {
+        bbval = 0.0;
+      } else if (bbval > 1.0) {
+        bbval = 1.0;
+      }
+      bbval = (bbval - offset) / gain;
       RaveField_setValue(field, bi, ri, bbval);
-      /*bb[i*ri+j] = -1./2. * sqrt(M_PI*c) * ( erf( (el-elBlock[i*ri+j]) / \
-                      sqrt(c) ) - erf( (el-(el-elLim))/sqrt(c) ) ) / bb_tot; */
     }
   }
 
+  if (!BeamBlockageInternal_addMetaInformation(field, gain, offset)) {
+    goto done;
+  }
+
+  if (!BeamBlockageInternal_writeCachedFile(self, scan, field, dBlim)) {
+    RAVE_ERROR0("Failed to generate cache file");
+  }
+
   result = RAVE_OBJECT_COPY(field);
 done:
   RAVE_OBJECT_RELEASE(navigator);
index eccf31e..f923129 100644 (file)
@@ -74,10 +74,25 @@ int BeamBlockage_setCacheDirectory(BeamBlockage_t* self, const char* cachedir);
 const char* BeamBlockage_getCacheDirectory(BeamBlockage_t* self);
 
 /**
+ * Sets if the cache should be recreated all the time. (Default 0)
+ * @param[in] self - self
+ * @param[in] recreateCache - if cache should be recreated, defaults to 0 which is no
+ */
+void BeamBlockage_setRewriteCache(BeamBlockage_t* self, int recreateCache);
+
+/**
+ * Returns if the cache is recreated each time.
+ * @param[in] self - self
+ * @return if cache is recreated or not. Defaults to 0 which is no
+ */
+int BeamBlockage_getRewriteCache(BeamBlockage_t* self);
+
+/**
  * Gets the blockage for the provided scan.
  * @param[in] self - self
  * @param[in] scan - the scan to check blockage
- * @param[in] dBlim -
+ * @param[in] dBlim - Limit of Gaussian approximation of main lobe
+ *
  * @return the beam blockage field
  */
 RaveField_t* BeamBlockage_getBlockage(BeamBlockage_t* self, PolarScan_t* scan, double dBlim);
index 6ba1910..91c4809 100644 (file)
@@ -173,7 +173,9 @@ static BBTopography_t* BeamBlockageMapInternal_readHeader(BeamBlockageMap_t* sel
     goto done;
   }
 
-  if (!BBTopography_createData(field, ncols, nrows, RaveDataType_SHORT));
+  if (!BBTopography_createData(field, ncols, nrows, RaveDataType_SHORT)) {
+    goto done;
+  }
 
   result = RAVE_OBJECT_COPY(field);
 done:
@@ -241,7 +243,8 @@ static int BeamBlockageMapInternal_fillData(BeamBlockageMap_t* self, const char*
 
   for (col = 0; col < ncols; col++) {
     for (row = 0; row < nrows; row++) {
-      BBTopography_setValue(field, col, row, (double)ntohs((short)(tmp[row*ncols + col])));
+      short temp = ntohs(tmp[row*ncols + col]);
+      BBTopography_setValue(field, col, row, temp);
     }
   }
 
@@ -317,7 +320,12 @@ static BBTopography_t* BeamBlockageMapInternal_createMappedTopography(BeamBlocka
       if (PolarScan_getLonLatFromIndex(scan, bi, ri, &lonval, &latval)) {
         double v = 0.0;
         BBTopography_getValueAtLonLat(topo, lonval, latval, &v);
-        BBTopography_setValue(field, bi, ri, v);
+        /* According to original code, no values < 0 are allowed */
+        if (v < 0.0) {
+          BBTopography_setValue(field, bi, ri, 0.0);
+        } else {
+          BBTopography_setValue(field, bi, ri, v);
+        }
       }
     }
   }
index dc2b9c1..02b83fa 100644 (file)
@@ -44,7 +44,7 @@ LDFLAGS+= $(EXPAT_LIB_DIR)
 EXPAT_LIBRARY=-lexpat
 endif
 
-LIBRARIES=-lhlhdf -lproj  $(EXPAT_LIBRARY) -lravetransform -lravepyapi -lbeamb
+LIBRARIES= -lbeamb -lravetransform -lravepyapi -lhlhdf -lproj $(EXPAT_LIBRARY)
 
 # --------------------------------------------------------------------
 # Fixed definitions
index d6e280a..a9edd09 100644 (file)
@@ -180,6 +180,8 @@ static PyObject* _pybeamblockage_getBlockage(PyBeamBlockage* self, PyObject* arg
 static struct PyMethodDef _pybeamblockage_methods[] =
 {
   {"topo30dir", NULL},
+  {"cachedir", NULL},
+  {"rewritecache", NULL},
   {"getBlockage", (PyCFunction)_pybeamblockage_getBlockage, 1},
   {NULL, NULL} /* sentinel */
 };
@@ -198,6 +200,16 @@ static PyObject* _pybeamblockage_getattr(PyBeamBlockage* self, char* name)
     } else {
       Py_RETURN_NONE;
     }
+  } else if (strcmp("cachedir", name) == 0) {
+    const char* str = BeamBlockage_getCacheDirectory(self->beamb);
+    if (str != NULL) {
+      return PyString_FromString(str);
+    } else {
+      Py_RETURN_NONE;
+    }
+  } else if (strcmp("rewritecache", name) == 0) {
+    int val = BeamBlockage_getRewriteCache(self->beamb);
+    return PyBool_FromLong(val);
   }
 
   res = Py_FindMethod(_pybeamblockage_methods, (PyObject*) self, name);
@@ -229,6 +241,22 @@ static int _pybeamblockage_setattr(PyBeamBlockage* self, char* name, PyObject* v
     } else {
       raiseException_gotoTag(done, PyExc_ValueError, "topo30dir must be a string or None");
     }
+  } else if (strcmp("cachedir", name) == 0) {
+    if (PyString_Check(val)) {
+      if (!BeamBlockage_setCacheDirectory(self->beamb, PyString_AsString(val))) {
+        raiseException_gotoTag(done, PyExc_ValueError, "cachedir must be a string or None");
+      }
+    } else if (val == Py_None) {
+      BeamBlockage_setCacheDirectory(self->beamb, NULL);
+    } else {
+      raiseException_gotoTag(done, PyExc_ValueError, "cachedir must be a string or None");
+    }
+  } else if (strcmp("rewritecache", name) == 0) {
+    if (PyBool_Check(val)) {
+      BeamBlockage_setRewriteCache(self->beamb, val == Py_True?1:0);
+    } else {
+      raiseException_gotoTag(done, PyExc_ValueError, "rewritecache must be a boolean");
+    }
   } else {
     raiseException_gotoTag(done, PyExc_AttributeError, name);
   }
index 52c0ed7..33209e5 100644 (file)
@@ -29,15 +29,32 @@ import _raveio
 import _beamblockage
 import os, string
 import _rave
+import numpy
 
 class PyBeamBlockageTest(unittest.TestCase):
   SCAN_FILENAME = "fixtures/scan_sevil_20100702T113200Z.h5"
+  FIXTURE_2 = "fixtures/sevil_0.5_20111223T0000Z.h5"
+  
+  CACHEFILE_1 = "/tmp/15.94_58.11_222_40.00_420_120_1000.00_0.00_0.90_-20.00.h5"
+  CACHEFILE_2 = "/tmp/15.94_58.11_223_0.50_420_120_2000.00_0.00_0.90_-20.00.h5"
+  CACHEFILE_3 = "/tmp/15.94_58.11_223_0.50_420_120_2000.00_0.00_0.90_-25.00.h5"
+  
   def setUp(self):
-    pass    
-
+    if os.path.isfile(self.CACHEFILE_1):
+      os.unlink(self.CACHEFILE_1)
+    if os.path.isfile(self.CACHEFILE_2):
+      os.unlink(self.CACHEFILE_2)
+    if os.path.isfile(self.CACHEFILE_3):
+      os.unlink(self.CACHEFILE_3)
+      
   def tearDown(self):
-    pass
-  
+    if os.path.isfile(self.CACHEFILE_1):
+      os.unlink(self.CACHEFILE_1)
+    if os.path.isfile(self.CACHEFILE_2):
+      os.unlink(self.CACHEFILE_2)
+    if os.path.isfile(self.CACHEFILE_3):
+      os.unlink(self.CACHEFILE_3)
+        
   def testNew(self):
     a = _beamblockage.new()
     self.assertNotEqual(-1, string.find(`type(a)`, "BeamBlockageCore"))
@@ -47,6 +64,12 @@ class PyBeamBlockageTest(unittest.TestCase):
     self.assertEquals(None, a.topo30dir)
     a.topo30dir="/tmp"
     self.assertEquals("/tmp", a.topo30dir)
+
+  def testCachedir(self):
+    a = _beamblockage.new()
+    self.assertTrue(a.cachedir != None)
+    a.cachedir="/tmp"
+    self.assertEquals("/tmp", a.cachedir)
   
   def testReadTopo30(self):
     a = _beamblockage.new()
@@ -55,11 +78,93 @@ class PyBeamBlockageTest(unittest.TestCase):
   def test_getBlockage(self):
     a = _beamblockage.new()
     a.topo30dir="../../data/gtopo30"
+    a.cachedir=None # No caching
     scan = _raveio.open(self.SCAN_FILENAME).object
     result = a.getBlockage(scan, -20.0);
-    print `result.getData()`
+    self.assertFalse(os.path.isfile(self.CACHEFILE_1))
+
+    self.assertEquals(_rave.RaveDataType_UCHAR, result.datatype)
+    self.assertAlmostEquals(0.0, result.getAttribute("what/offset"), 4)
+    self.assertAlmostEquals(1/255.0, result.getAttribute("what/gain"), 4)
+    self.assertEquals(scan.nbins, result.xsize)
+    self.assertEquals(scan.nrays, result.ysize)
+
+  def test_getBlockage_caching(self):
+    a = _beamblockage.new()
+    a.topo30dir="../../data/gtopo30"
+    a.cachedir="/tmp"
+    scan = _raveio.open(self.SCAN_FILENAME).object
+
+    self.assertFalse(os.path.isfile(self.CACHEFILE_1))
     
-  
+    result = a.getBlockage(scan, -20.0);
+    
+    self.assertTrue(os.path.isfile(self.CACHEFILE_1))
+
+    self.assertEquals(_rave.RaveDataType_UCHAR, result.datatype)
+    self.assertAlmostEquals(0.0, result.getAttribute("what/offset"), 4)
+    self.assertAlmostEquals(1/255.0, result.getAttribute("what/gain"), 4)
+    self.assertEquals(scan.nbins, result.xsize)
+    self.assertEquals(scan.nrays, result.ysize)
+    
+  def test_getBlockage2(self):
+    a = _beamblockage.new()
+    a.topo30dir="../../data/gtopo30"
+    a.cachedir="/tmp"
+    scan = _raveio.open(self.FIXTURE_2).object
+    result = a.getBlockage(scan, -20.0);
+    self.assertEquals(_rave.RaveDataType_UCHAR, result.datatype)
+    self.assertAlmostEquals(0.0, result.getAttribute("what/offset"), 4)
+    self.assertAlmostEquals(1/255.0, result.getAttribute("what/gain"), 4)
+    self.assertEquals(scan.nbins, result.xsize)
+    self.assertEquals(scan.nrays, result.ysize)
+
+  def test_getBlockage2_keep_cache(self):
+    a = _beamblockage.new()
+    a.topo30dir="../../data/gtopo30"
+    a.cachedir="/tmp"
+    scan = _raveio.open(self.FIXTURE_2).object
+    result = a.getBlockage(scan, -20.0);
+
+    self.assertTrue(os.path.isfile(self.CACHEFILE_2))
+    c2stat = os.stat(self.CACHEFILE_2)
+
+    result = a.getBlockage(scan, -20.0);
+    c2stat_n = os.stat(self.CACHEFILE_2)
+
+    self.assertEquals(c2stat.st_ctime, c2stat_n.st_ctime)
+    self.assertEquals(c2stat.st_mtime, c2stat_n.st_mtime)
+    
+  def test_getBlockage2_recreate_cache(self):
+    a = _beamblockage.new()
+    a.topo30dir="../../data/gtopo30"
+    a.cachedir="/tmp"
+    a.rewritecache=True
+    scan = _raveio.open(self.FIXTURE_2).object
+    result = a.getBlockage(scan, -20.0);
+
+    self.assertTrue(os.path.isfile(self.CACHEFILE_2))
+    c2stat = os.stat(self.CACHEFILE_2)
+
+    result = a.getBlockage(scan, -20.0);
+    c2stat_n = os.stat(self.CACHEFILE_2)
+
+    self.assertNotEquals(c2stat.st_ctime, c2stat_n.st_ctime)
+    self.assertNotEquals(c2stat.st_mtime, c2stat_n.st_mtime)    
+
+  def test_getBlockage2_different_dblim(self):
+    a = _beamblockage.new()
+    a.topo30dir="../../data/gtopo30"
+    a.cachedir="/tmp"
+    a.rewritecache=True
+    scan = _raveio.open(self.FIXTURE_2).object
+    result1 = a.getBlockage(scan, -20.0);
+    result2 = a.getBlockage(scan, -25.0);
+
+    self.assertTrue(os.path.isfile(self.CACHEFILE_2))
+    self.assertTrue(os.path.isfile(self.CACHEFILE_3))
+    c2stat = os.stat(self.CACHEFILE_2)
+
 if __name__ == "__main__":
   #import sys;sys.argv = ['', 'Test.testName']
   unittest.main()
\ No newline at end of file
diff --git a/test/pytest/fixtures/sevil_0.5_20111223T0000Z.h5 b/test/pytest/fixtures/sevil_0.5_20111223T0000Z.h5
new file mode 100644 (file)
index 0000000..c613605
Binary files /dev/null and b/test/pytest/fixtures/sevil_0.5_20111223T0000Z.h5 differ