diff --git a/.gitignore b/.gitignore index 3cccff48..549084e5 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ a.out travis.log build/ .vscode/ +.log diff --git a/CHANGELOG.md b/CHANGELOG.md index 659dac94..be0a7312 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +2022-02-11 (2.3.1) +================== + +Fix pyrichdem to import all cpp source files correctly +Clean up pyrichdem setup.py +Add .log files to .gitignore + 2022-02-09 (2.3.0) ================== diff --git a/wrappers/pyrichdem/lib/richdem b/wrappers/pyrichdem/lib/richdem index 3005c930..1b20c9fb 120000 --- a/wrappers/pyrichdem/lib/richdem +++ b/wrappers/pyrichdem/lib/richdem @@ -1 +1 @@ -../../../include/richdem \ No newline at end of file +../../../ \ No newline at end of file diff --git a/wrappers/pyrichdem/richdem/__init__.py b/wrappers/pyrichdem/richdem/__init__.py index 509bde19..a2664226 100644 --- a/wrappers/pyrichdem/richdem/__init__.py +++ b/wrappers/pyrichdem/richdem/__init__.py @@ -1,12 +1,13 @@ -import pkg_resources -import datetime import copy +import datetime import numpy as np +import pkg_resources try: import _richdem -except ImportError: +except ImportError as e: print('COULD NOT LOAD RichDEM ENGINE! NOTHING WILL WORK!') + raise e try: from osgeo import gdal @@ -90,7 +91,7 @@ def rdShow(rda, ignore_colours=[], show=True, axes=True, cmap='gray', vmin=None, if all_zoom: axins = inset_axes(ax, width=2, height=2, loc=zloc, borderpad=0) #, bbox_to_anchor=(0.9, -0.05, 1, 1), bbox_transform=ax.transAxes, borderpad=0) - axins.set_xlim(xmin=zxmin,xmax=zxmax) + axins.set_xlim(xmin=zxmin,xmax=zxmax) axins.set_ylim(ymin=zymin,ymax=zymax) plt.setp(axins.get_xticklabels(), visible=False) plt.setp(axins.get_yticklabels(), visible=False) @@ -116,8 +117,8 @@ def rdShow(rda, ignore_colours=[], show=True, axes=True, cmap='gray', vmin=None, class rdarray(np.ndarray): def __new__(cls, array, meta_obj=None, no_data=None, dtype=None, order=None, **kwargs): - obj = np.asarray(array, dtype=dtype, order=order).view(cls) - + obj = np.asarray(array, dtype=dtype, order=order).view(cls) + if meta_obj is not None: obj.metadata = copy.deepcopy(getattr(meta_obj, 'metadata', dict())) obj.no_data = copy.deepcopy(getattr(meta_obj, 'no_data', None )) @@ -155,7 +156,7 @@ def wrap(self): dtype = str(self.dtype) if not dtype in richdem_arrs: raise Exception("No equivalent RichDEM datatype.") - + rda = richdem_arrs[dtype](self) if self.no_data is None: @@ -170,7 +171,7 @@ def wrap(self): print("Warning! No geotransform defined. Choosing a standard one! (Top left cell's top let corner at <0,0>; cells are 1x1.)") rda.geotransform = np.array([0,1,0,0,0,-1], dtype='float64') - return rda + return rda def copyFromWrapped(self, wrapped): self.no_data = wrapped.noData() @@ -181,8 +182,8 @@ def copyFromWrapped(self, wrapped): class rd3array(np.ndarray): def __new__(cls, array, meta_obj=None, no_data=None, order=None, **kwargs): - obj = np.asarray(array, dtype=np.float32, order=order).view(cls) - + obj = np.asarray(array, dtype=np.float32, order=order).view(cls) + if meta_obj is not None: obj.metadata = copy.deepcopy(getattr(meta_obj, 'metadata', dict())) obj.no_data = copy.deepcopy(getattr(meta_obj, 'no_data', None )) @@ -211,7 +212,7 @@ def wrap(self): dtype = str(self.dtype) if not dtype in richdem_arrs: raise Exception("No equivalent RichDEM datatype.") - + rda = richdem_arrs[dtype](self) if self.no_data is None: @@ -226,7 +227,7 @@ def wrap(self): print("Warning! No geotransform defined. Choosing a standard one! (Top left cell's top let corner at <0,0>; cells are 1x1.)") rda.geotransform = np.array([0,1,0,0,0,-1], dtype='float64') - return rda + return rda def copyFromWrapped(self, wrapped): self.no_data = wrapped.noData() @@ -250,7 +251,7 @@ def LoadGDAL(filename, no_data=None): Returns: A RichDEM array - """ + """ if not GDAL_AVAILABLE: raise Exception("richdem.LoadGDAL() requires GDAL.") @@ -333,7 +334,7 @@ def FillDepressions( epsilon (float): If True, an epsilon gradient is imposed to all flat regions. This ensures that there is always a local gradient. in_place (bool): If True, the DEM is modified in place and there is - no return; otherwise, a new, altered DEM is returned. + no return; otherwise, a new, altered DEM is returned. topology (string): A topology indicator Returns: @@ -380,7 +381,7 @@ def BreachDepressions( Args: dem (rdarray): An elevation model in_place (bool): If True, the DEM is modified in place and there is - no return; otherwise, a new, altered DEM is returned. + no return; otherwise, a new, altered DEM is returned. topology (string): A topology indicator Returns: @@ -420,7 +421,7 @@ def ResolveFlats( Args: dem (rdarray): An elevation model in_place (bool): If True, the DEM is modified in place and there is - no return; otherwise, a new, altered DEM is returned. + no return; otherwise, a new, altered DEM is returned. Returns: DEM modified such that all flats drain. @@ -456,7 +457,7 @@ def FlowAccumulation( Args: dem (rdarray): An elevation model method (str): Flow accumulation method to use. (See below.) - exponent (float): Some methods require an exponent; refer to the + exponent (float): Some methods require an exponent; refer to the relevant publications for details. weights (rdarray): Flow accumulation weights to use. This is the amount of flow generated by each cell. If this is @@ -464,7 +465,7 @@ def FlowAccumulation( flow. in_place (bool): If True, then `weights` is modified in place. An accumulation matrix is always returned, but it will - just be a view of the modified data if `in_place` + just be a view of the modified data if `in_place` is True. =================== ============================== =========================== @@ -565,7 +566,7 @@ def FlowAccumFromProps( flow. in_place (bool): If True, then `weights` is modified in place. An accumulation matrix is always returned, but it will - just be a view of the modified data if `in_place` + just be a view of the modified data if `in_place` is True. Returns: @@ -612,7 +613,7 @@ def FlowProportions( Args: dem (rdarray): An elevation model method (str): Flow accumulation method to use. (See below.) - exponent (float): Some methods require an exponent; refer to the + exponent (float): Some methods require an exponent; refer to the relevant publications for details. =================== ============================== =========================== @@ -698,14 +699,14 @@ def TerrainAttribute( ======================= ========= Method Reference ======================= ========= - slope_riserun `Horn (1981) doi: 10.1109/PROC.1981.11918 `_ - slope_percentage `Horn (1981) doi: 10.1109/PROC.1981.11918 `_ - slope_degrees `Horn (1981) doi: 10.1109/PROC.1981.11918 `_ - slope_radians `Horn (1981) doi: 10.1109/PROC.1981.11918 `_ - aspect `Horn (1981) doi: 10.1109/PROC.1981.11918 `_ - curvature `Zevenbergen and Thorne (1987) doi: 10.1002/esp.3290120107 `_ - planform_curvature `Zevenbergen and Thorne (1987) doi: 10.1002/esp.3290120107 `_ - profile_curvature `Zevenbergen and Thorne (1987) doi: 10.1002/esp.3290120107 `_ + slope_riserun `Horn (1981) doi: 10.1109/PROC.1981.11918 `_ + slope_percentage `Horn (1981) doi: 10.1109/PROC.1981.11918 `_ + slope_degrees `Horn (1981) doi: 10.1109/PROC.1981.11918 `_ + slope_radians `Horn (1981) doi: 10.1109/PROC.1981.11918 `_ + aspect `Horn (1981) doi: 10.1109/PROC.1981.11918 `_ + curvature `Zevenbergen and Thorne (1987) doi: 10.1002/esp.3290120107 `_ + planform_curvature `Zevenbergen and Thorne (1987) doi: 10.1002/esp.3290120107 `_ + profile_curvature `Zevenbergen and Thorne (1987) doi: 10.1002/esp.3290120107 `_ ======================= ========= Returns: diff --git a/wrappers/pyrichdem/setup.py b/wrappers/pyrichdem/setup.py index 70de90cd..dbc04f8a 100644 --- a/wrappers/pyrichdem/setup.py +++ b/wrappers/pyrichdem/setup.py @@ -1,15 +1,14 @@ -from collections import defaultdict -import setuptools -from setuptools.command.build_ext import build_ext as _build_ext import glob -import datetime -import subprocess import re +import setuptools +import subprocess +from setuptools.command.build_ext import build_ext as _build_ext +from typing import Optional from pybind11.setup_helpers import Pybind11Extension -RICHDEM_COMPILE_TIME = None -RICHDEM_GIT_HASH = None +richdem_compile_time: Optional[str] = None +richdem_git_hash: Optional[str] = None #Compiler specific arguments BUILD_ARGS = { @@ -22,40 +21,40 @@ class build_ext_compiler_check(_build_ext): def build_extensions(self): compiler = self.compiler.compiler_type - print('COMPILER',compiler) + print(f'COMPILER {compiler}') args = BUILD_ARGS[compiler] for ext in self.extensions: ext.extra_compile_args = args - print('COMPILER ARGUMENTS',ext.extra_compile_args) + print(f'COMPILER ARGUMENTS: {ext.extra_compile_args}') _build_ext.build_extensions(self) -if RICHDEM_GIT_HASH is None: +if richdem_git_hash is None: try: shash = subprocess.Popen(["git log --pretty=format:'%h' -n 1"], shell=True, stderr=subprocess.STDOUT, stdout=subprocess.PIPE).stdout.readlines()[0].decode('utf8').strip() sdate = subprocess.Popen(["git log -1 --pretty='%ci'"], shell=True, stderr=subprocess.STDOUT, stdout=subprocess.PIPE).stdout.readlines()[0].decode('utf8').strip() if re.match(r'^[0-9a-z]+$', shash) and re.match(r'^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}.*$', sdate): - RICHDEM_COMPILE_TIME = sdate - RICHDEM_GIT_HASH = shash + richdem_compile_time = sdate + richdem_git_hash = shash except: print("Warning! Could not find RichDEM version. Software will still work, but reproducibility will be compromised.") pass -if RICHDEM_GIT_HASH is None: - RICHDEM_COMPILE_TIME = 'Unknown' - RICHDEM_GIT_HASH = 'Unknown' +if richdem_git_hash is None: + richdem_compile_time = 'Unknown' + richdem_git_hash = 'Unknown' -print("Using RichDEM hash={0}, time={1}".format(RICHDEM_GIT_HASH, RICHDEM_COMPILE_TIME)) +print("Using RichDEM hash={0}, time={1}".format(richdem_git_hash, richdem_compile_time)) ext_modules = [ Pybind11Extension( "_richdem", - glob.glob('src/*.cpp') + glob.glob('lib/richdem/*.cpp'), - include_dirs = ['lib/'], + sorted(glob.glob('src/*.cpp') + glob.glob('lib/richdem/src/**/*.cpp', recursive=True)), + include_dirs = ['lib/richdem/include/'], define_macros = [ - ('DOCTEST_CONFIG_DISABLE', None ), - ('RICHDEM_COMPILE_TIME', '"\\"'+RICHDEM_COMPILE_TIME+'\\""'), - ('RICHDEM_GIT_HASH', '"\\"'+RICHDEM_GIT_HASH+'\\""' ), - ('RICHDEM_LOGGING', None ), + ('DOCTEST_CONFIG_DISABLE', None), + ('RICHDEM_COMPILE_TIME', f'"\\"{richdem_compile_time}\\""'), + ('RICHDEM_GIT_HASH', f'"\\"{richdem_git_hash}\\""' ), + ('RICHDEM_LOGGING', None), ('_USE_MATH_DEFINES', None) #To ensure that `#include ` imports `M_PI` in MSVC ] ), @@ -73,7 +72,7 @@ def build_extensions(self): #TODO: https://packaging.python.org/tutorials/distributing-packages/#configuring-your-project setuptools.setup( name = 'richdem', - version = '0.3.4', + version = '0.4.0', description = 'High-Performance Terrain Analysis', long_description = long_description, url = 'https://github.com/r-barnes/richdem', @@ -93,20 +92,10 @@ def build_extensions(self): ext_modules = ext_modules, cmdclass = {'build_ext': build_ext_compiler_check}, keywords = 'GIS terrain hydrology geomorphology raster', - #packages = find_packages(exclude=['contrib', 'docs', 'tests*']), install_requires = [ "numpy>=1.7,<2; python_version > '3.4' or python_version < '3.0'", "numpy>=1.7,<1.12; python_version < '3.4' and python_version > '3.0'" ], - # extras_require = { - # ':python_version > "3.4"': [ - # 'numpy>=1.7,<2' - # ], - # ':python_version < "3.4"': [ - # 'numpy>=1.7,<1.12' - # ] - # }, - #python_requires = ' >= 2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4', #TODO: https://pypi.python.org/pypi?%3Aaction=list_classifiers classifiers = [