From a07f03213252ac063214ba8d3b4b43d57c8a005c Mon Sep 17 00:00:00 2001 From: Alfredo Mejia-Narvaez Date: Wed, 27 Nov 2024 13:53:23 -0300 Subject: [PATCH] added basic tests & updated readmes --- README.md | 13 +------ cextern/README.txt | 9 ++--- cextern/fast_median/src/Makefile | 14 ------- cextern/fast_median/test/testfilter.py | 15 -------- cextern/fast_median/test/testfilter2.py | 46 ---------------------- cextern/fast_median/test/testfilter3.py | 51 ------------------------- tests/external/test_fast_median.py | 40 +++++++++++++++++++ 7 files changed, 45 insertions(+), 143 deletions(-) delete mode 100644 cextern/fast_median/src/Makefile delete mode 100644 cextern/fast_median/test/testfilter.py delete mode 100644 cextern/fast_median/test/testfilter2.py delete mode 100644 cextern/fast_median/test/testfilter3.py create mode 100644 tests/external/test_fast_median.py diff --git a/README.md b/README.md index 38ffe70b..59e8f926 100644 --- a/README.md +++ b/README.md @@ -63,18 +63,7 @@ To install the DRP along with its dependencies, you need to run the following st cd lvmdrp ``` -3. Optional, but recommended: compile c-code for better performance - - ```bash - pushd lvmdrp/python/cextern/fast_median/src - make - popd - ``` - This should have created a fast_median.so (Linux) or fast_median.dylib (MacOS) in the src directory. - Set environment variable `LVMDRP_LIB_DIR` if you move the shared library. If you leave it in src/, no need to set this. - We will automate this step eventually ;-) - -4. Install the DRP package in the current python environment (see [contributing](#contributing-to-lvm-drp-development) section below for a replacement of this step). Make sure you're back in the lvmdrp directory. +3. Install the DRP package in the current python environment (see [contributing](#contributing-to-lvm-drp-development) section below for a replacement of this step). Make sure you're back in the lvmdrp directory. ```bash cd lvmdrp diff --git a/cextern/README.txt b/cextern/README.txt index 90626535..4f9545c4 100644 --- a/cextern/README.txt +++ b/cextern/README.txt @@ -1,8 +1,7 @@ -C code to be compiled on setup goes here. +C++ code to generate fast_median extension goes here. -fast_median.cpp is a very fast median filter for 1d and 2d ndarrays -with float or double data. The glue code is in fast_median.py - -compile using the Makefile in src/ +fast_median.cpp, fast_median.hpp: a very fast median filter for 1d and 2d ndarrays +with float or double data. +python/lvmdrp/external/fast_median.py: python interface for fast_median extension diff --git a/cextern/fast_median/src/Makefile b/cextern/fast_median/src/Makefile deleted file mode 100644 index 2622d744..00000000 --- a/cextern/fast_median/src/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -UNAME_S := $(shell uname -s) -ifeq ($(UNAME_S),Linux) - FLAGS = -fPIC -shared -O3 -march=native - TRG = fast_median.so - COMPILER = g++ -endif -ifeq ($(UNAME_S),Darwin) - FLAGS = -dynamiclib -current_version 1.0 -compatibility_version 1.0 -O3 -march=native - TRG = fast_median.dylib - COMPILER = clang++ -endif - -all: fast_median.cpp fast_median.hpp - $(COMPILER) $(FLAGS) -o $(TRG) fast_median.cpp diff --git a/cextern/fast_median/test/testfilter.py b/cextern/fast_median/test/testfilter.py deleted file mode 100644 index 630334c8..00000000 --- a/cextern/fast_median/test/testfilter.py +++ /dev/null @@ -1,15 +0,0 @@ -import numpy as np -from fast_median import fast_median_filter_2d -from scipy.ndimage import median_filter -import time - -s = int(4000) -img = np.random.random(size=[s,s]) -img = img.astype(np.float32) - -t = time.time() -img_r = fast_median_filter_2d(img, size=(5,5)) -print(f'lib.median_filter_2d_float: {time.time()-t:.2f} s') -t = time.time() -tmp = median_filter(img, size=(5,5)) -print(f'ndimage.median_filter: {time.time()-t:.2f} s') diff --git a/cextern/fast_median/test/testfilter2.py b/cextern/fast_median/test/testfilter2.py deleted file mode 100644 index 96e2027c..00000000 --- a/cextern/fast_median/test/testfilter2.py +++ /dev/null @@ -1,46 +0,0 @@ -import ctypes -import numpy as np -from numpy.ctypeslib import ndpointer -from scipy.ndimage import median_filter - -HAVE_MEDIAN_SO = True -try: - import platform - s = platform.system() - if s=='Linux': - lib = ctypes.cdll.LoadLibrary("../src/filter.so") - elif s=='Darwin': - lib = ctypes.cdll.LoadLibrary("../src/filter.dylib") - else: - raise Exception('Unknown platform: '+s) - HAVE_MEDIAN_SO = True -except Exception: - print(Exception) - pass - -s1 = 11 -s2 = 7 -b1 = 3 -b2 = 4 -img = np.zeros((s1,s2), dtype=np.float32) -img_r = np.zeros(img.shape, dtype=np.float32) - -img = np.random.random_integers(0,10, size=(s1,s2)).astype(np.float32) - -#template -#void median_filter_2d(int x, int y, int hx, int hy, int blockhint, const T* in, T* out); - -lib.median_filter_2d_float.argtypes = (ctypes.c_int, ctypes.c_int, - ctypes.c_int, ctypes.c_int, - ctypes.c_int, - ndpointer(ctypes.c_float, flags="C_CONTIGUOUS"), - ndpointer(ctypes.c_float, flags="C_CONTIGUOUS")) - -lib.median_filter_2d_float.restype = None - -# Note we have to flip the shape and box x/y to match python's indexing -lib.median_filter_2d_float(s2, s1, b2, b1, 0, img, img_r) -img_p = median_filter(img, size=(b1,b2), mode='nearest') -print(img) -print(img_r) -print(img_p) diff --git a/cextern/fast_median/test/testfilter3.py b/cextern/fast_median/test/testfilter3.py deleted file mode 100644 index 9f3c2273..00000000 --- a/cextern/fast_median/test/testfilter3.py +++ /dev/null @@ -1,51 +0,0 @@ -import ctypes -import numpy as np -from numpy.ctypeslib import ndpointer -from scipy.ndimage import median_filter -from astropy.io import fits - -HAVE_MEDIAN_SO = True -try: - import platform - s = platform.system() - if s=='Linux': - lib = ctypes.cdll.LoadLibrary("../src/filter.so") - elif s=='Darwin': - lib = ctypes.cdll.LoadLibrary("../src/filter.dylib") - else: - raise Exception('Unknown platform: '+s) - HAVE_MEDIAN_SO = True -except Exception: - print(Exception) - pass - -#template -#void median_filter_2d(int x, int y, int hx, int hy, int blockhint, const T* in, T* out); - - - -lib.median_filter_2d_float.argtypes = (ctypes.c_int, ctypes.c_int, - ctypes.c_int, ctypes.c_int, - ctypes.c_int, - ndpointer(ctypes.c_float, flags="C_CONTIGUOUS"), - ndpointer(ctypes.c_float, flags="C_CONTIGUOUS")) - -lib.median_filter_2d_float.restype = None - -# C-ordering: last index varies most rapidly - -#// Pixel (i,j) for 0 <= i < x and 0 <= j < y is located at -#// in[j*x + i] and out[j*x + i]. - -with fits.open('/Users/droryn/Downloads/lvmSFrame-00012618.fits') as hdu: - img = hdu[1].data.astype(np.float32) - img_r = np.zeros(img.shape).astype(np.float32) - -img[~np.isfinite(img)] = 0 - -# Note we have to flip the shape and box x/y to match python's indexing -lib.median_filter_2d_float(img.shape[1], img.shape[0], 25, 3, 0, img, img_r) -fits.writeto('/Users/droryn/Downloads/img_r.fits', img_r, overwrite=True) - -img_p = median_filter(img, size=(3,25), mode='nearest') -fits.writeto('/Users/droryn/Downloads/img_p.fits', img_p, overwrite=True) diff --git a/tests/external/test_fast_median.py b/tests/external/test_fast_median.py new file mode 100644 index 00000000..24935a50 --- /dev/null +++ b/tests/external/test_fast_median.py @@ -0,0 +1,40 @@ +import numpy as np +from lvmdrp.external.fast_median import fast_median_filter_2d, fast_median_filter_1d +from scipy.ndimage import median_filter +import time +import pytest + + +def test_median_filter_1d_speed(): + np.random.seed(123) + img = np.random.random(size=100)*3 + 1000 + img = img.astype(np.float32) + + t = time.time() + img_fm = fast_median_filter_1d(img, size=5) + dt_fm = time.time()-t + + t = time.time() + img_om = median_filter(img, size=5) + dt_om = time.time()-t + + assert dt_om > dt_fm + assert img_om == pytest.approx(img_fm, rel=0.01) + + +def test_median_filter_2d_speed(): + np.random.seed(456) + img = np.random.random(size=[100,100])*3 + 1000 + img = img.astype(np.float32) + + t = time.time() + img_fm = fast_median_filter_2d(img, size=(5,5)) + dt_fm = time.time()-t + + t = time.time() + img_om = median_filter(img, size=(5,5)) + dt_om = time.time()-t + + assert dt_om > dt_fm + assert img_om == pytest.approx(img_fm, rel=0.01) +