From 3e583418ec8e682abd22d521e3053d55a7720898 Mon Sep 17 00:00:00 2001 From: Scott Havens Date: Wed, 14 Apr 2021 10:19:13 -0600 Subject: [PATCH] Github actions and horizon OSX fix (#10) * gh action template yml * fix flake8 call * install topocalc to build C code * try with tox * install tox * tox env * run setup.py test * os matrix * cleanup * coverage * coverage try 2 * coverage try 3 * cibuildwheel for linux osx * seperate build wheels workflow * wrong directory * fixing build-wheels * fixing build-wheels * wheel dependancy on unittest * cap numpy * cc env * cython capy * cython 0.28.X doesn't work * gcc version print * specify gcc alias * testing with ubuntu * cc testing * updating setup.py for cc overwrite * full test * moved all actions to one file * moved all actions to one file * restructuring * fixing * removing O3 flag * gcc version * removed slopef/b functions and was more explicit * updated setup.py for cython language directive and simplified topo_core.pyx * dist in slope int to double more explicit * viewf test more verbose * up nangles for viewf test * viewf test for osx * upping osx tolerance * updating setup.py to be like smrf's * move cython to dev requirement and see if osx will use c code instead * pyx bool to bint * viewf test assert all close * double declaration * wrong c type * debugging and cleanupy * c typingy * relaxed osx viewf test * hypot * zeros * gcc * refactor c code a bit * add linux * more print * just horizon * hor1f was going 1 index too far * remove debug * cleanup * delete travis.yml * action on * updated action on * updating README --- .github/workflows/python-package.yml | 153 ++++++++++++ .travis.yml | 97 -------- README.md | 3 +- notebooks/viewf_theory.ipynb | 97 ++------ requirements.txt | 1 - requirements_dev.txt | 2 +- setup.py | 41 ++-- topocalc/core_c/hor1d.c | 83 +++---- topocalc/core_c/topo_core.c | 333 +++++++++++---------------- topocalc/core_c/topo_core.h | 2 +- topocalc/core_c/topo_core.pyx | 24 +- topocalc/horizon.py | 1 + topocalc/tests/test_viewf.py | 45 ++-- tox.ini | 7 - 14 files changed, 419 insertions(+), 470 deletions(-) create mode 100644 .github/workflows/python-package.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml new file mode 100644 index 0000000..a953a83 --- /dev/null +++ b/.github/workflows/python-package.yml @@ -0,0 +1,153 @@ +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: Unittest, flake8, coverage + +# Run action on pull requests +# Run on a published release and push to Pypi +on: + pull_request: + branches: [ main ] + release: + types: [published] + +jobs: + + flake8: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.7' + + - name: Install dependencies + run: | + python3 -m pip install --upgrade pip + python3 -m pip install flake8 + + - name: Lint with flake8 + run: | + flake8 topocalc + + coverage: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.7' + + - name: Install dependencies + run: | + python3 -m pip install --upgrade pip + python3 -m pip install coverage coveralls PyYAML + python3 -m pip install -r requirements.txt + + - name: Run coverage + run: | + make coveralls + + + unittest: + needs: [flake8, coverage] + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + python-version: [3.6, 3.7, 3.8, 3.9] + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v2 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python3 -m pip install --upgrade pip + python3 -m pip install -r requirements.txt + + - name: Run unittests + run: | + python3 setup.py test + + build_wheels: + needs: unittest + name: Build wheels on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-20.04, macos-10.15] + + steps: + - uses: actions/checkout@v2 + + - uses: actions/setup-python@v2 + name: Install Python + with: + python-version: '3.8' + + - name: Build wheels + uses: joerick/cibuildwheel@v1.10.0 + env: + CIBW_SOME_OPTION: value + CIBW_TEST_REQUIRES: nose + CIBW_TEST_COMMAND: "nosetests -vv --exe topocalc" + CIBW_BUILD: "cp3*-manylinux_x86_64 cp3*-macosx_x86_64" + CIBW_SKIP: "?p27* pp* ?p35" + CIBW_BUILD_VERBOSITY: 3 + CIBW_BEFORE_BUILD: "pip install -r requirements.txt" + + - uses: actions/upload-artifact@v2 + with: + path: ./wheelhouse/*.whl + + build_sdist: + needs: unittest + name: Build source distribution + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - uses: actions/setup-python@v2 + name: Install Python + with: + python-version: '3.8' + + - name: Install dependencies + run: | + python3 -m pip install --upgrade pip + python3 -m pip install -r requirements.txt + + - name: Build sdist + run: python setup.py sdist --formats=gztar + + - uses: actions/upload-artifact@v2 + with: + path: dist/*.tar.gz + + upload_pypi: + needs: [build_wheels, build_sdist] + runs-on: ubuntu-latest + # upload to PyPI on every tag starting with 'v' + # if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/v') + # alternatively, to publish when a GitHub Release is created, use the following rule: + if: github.event_name == 'release' && github.event.action == 'published' + steps: + - uses: actions/download-artifact@v2 + with: + name: artifact + path: dist + + - uses: pypa/gh-action-pypi-publish@master + with: + user: __token__ + password: ${{ secrets.pypi_password }} + # To test: repository_url: https://test.pypi.org/legacy/ diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 4feb3d5..0000000 --- a/.travis.yml +++ /dev/null @@ -1,97 +0,0 @@ -# test stage will test all branches against: -# - linux python 3.5, 3.6, 3.7, 3.8 -# - osx python 3.7 -# -# deploy stage builds and test the wheels when jobs is -# - pull request -# - main branch -# - tagged commit, only this will be uploaded to pypi - -services: - - docker - -stages: - - name: test - if: type = pull_request OR branch = main OR tag IS present AND repo = USDA-ARS-NWRC/topocalc - - name: deploy - if: type = pull_request OR branch = main OR tag IS present AND repo = USDA-ARS-NWRC/topocalc - -env: - global: - - CIBW_TEST_REQUIRES=nose - - CIBW_TEST_COMMAND="nosetests -vv --exe topocalc" - - CIBW_BUILD="cp3*-manylinux_x86_64 cp3*-macosx_x86_64" - - CIBW_SKIP="?p27* pp*" - - CIBW_BUILD_VERBOSITY=3 - - CIBW_BEFORE_BUILD="pip install -r requirements.txt" - - TWINE_USERNAME=__token__ - # Note: TWINE_PASSWORD is set to a PyPI API token in Travis settings - -# defining the unittest jobs -unittest: &unittest - stage: test - os: linux - dist: xenial - language: python - install: - - pip install -U tox-travis coveralls - - pip install -r requirements.txt - script: tox - -# build the wheels with cibuildwheel -ci-build-wheels: &ci-build-wheels - stage: deploy - services: docker - os: linux - dist: xenial - language: python - install: python3 -m pip install cibuildwheel==1.3.0 - script: travis/build.sh - -jobs: - include: - # test stage - - <<: *unittest - python: 3.5 - env: TOXENV=py35 - addons: - apt: - packages: - - libnetcdf-dev - - gcc - - - <<: *unittest - python: 3.6 - env: TOXENV=py36,flake8,coverage - - - <<: *unittest - python: 3.7 - env: TOXENV=py37 - - - <<: *unittest - python: 3.8 - env: TOXENV=py38 - - - <<: *unittest - os: osx - osx_image: xcode11.2 # Python 3.7.4 running on macOS 10.14.4 - language: shell - env: TOXENV=py37 - - # Deploy source distribution - - stage: deploy - name: Deploy source distribution - language: python - python: 3.6 - install: skip - script: travis/build-sdist.sh - - # Deploy on linux - - <<: *ci-build-wheels - name: Build and deploy Linux wheels - - # Deploy on osx - - <<: *ci-build-wheels - name: Build and deploy macOS wheels - os: osx - language: shell diff --git a/README.md b/README.md index 0a06345..19331c7 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # topocalc [![Pypi version](https://img.shields.io/pypi/v/topocalc.svg)](https://pypi.python.org/pypi/topocalc) -[![Build Status](https://travis-ci.com/USDA-ARS-NWRC/topocalc.svg?branch=main)](https://travis-ci.com/USDA-ARS-NWRC/topocalc) [![Coverage Status](https://coveralls.io/repos/github/USDA-ARS-NWRC/topocalc/badge.svg?branch=main)](https://coveralls.io/github/USDA-ARS-NWRC/topocalc?branch=main) [![Maintainability](https://api.codeclimate.com/v1/badges/20930fef2e7b7fe91dd3/maintainability)](https://codeclimate.com/github/USDA-ARS-NWRC/topocalc/maintainability) @@ -55,7 +54,7 @@ The sky view factor (`svf`) is the amount of the sky that is visible to a partic ## Installation -> **NOTE**: `topocalc` has only been tested for Python 3.5 to 3.8 on Linux and MacOSX environments. +> **NOTE**: `topocalc` has only been tested for Python 3.6 to 3.9 on Linux and MacOSX environments. If building from source, topocalc must be compiled with `gcc`, `clang` will not work if on MacOS. To install: diff --git a/notebooks/viewf_theory.ipynb b/notebooks/viewf_theory.ipynb index 78b076e..1e84f34 100644 --- a/notebooks/viewf_theory.ipynb +++ b/notebooks/viewf_theory.ipynb @@ -10,7 +10,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -34,32 +34,9 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "dem = np.ones((50, 50))\n", "dem[:, :25] = 100000\n", @@ -73,22 +50,9 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "# Create the IPW image and run IPW viewf then plot\n", "csys = 'UTM'\n", @@ -152,32 +116,9 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "dem = np.ones((50, 50))\n", "dem[:, :20] = 100000\n", @@ -192,22 +133,9 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "# Create the IPW image and run IPW viewf then plot\n", "csys = 'UTM'\n", @@ -260,6 +188,13 @@ "\n", "plt.show()\n" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/requirements.txt b/requirements.txt index bfad398..1a712e6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,4 @@ numpy>=1.15 Click>=7.0 -Cython>=0.28.4 spatialnc>=0.2.12 setuptools_scm<4.2 \ No newline at end of file diff --git a/requirements_dev.txt b/requirements_dev.txt index 467360b..3fa551a 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -1,9 +1,9 @@ -r requirements.txt +Cython>=0.29 netCDF4>=1.2.9 wheel==0.33.6 watchdog==0.9.0 flake8==3.7.8 -tox==3.14.0 coverage Sphinx==1.8.5 twine==1.14.0 diff --git a/setup.py b/setup.py index 486ab73..7e9baf1 100644 --- a/setup.py +++ b/setup.py @@ -3,15 +3,29 @@ import os import numpy -from Cython.Distutils import build_ext from setuptools import Extension, find_packages, setup +from setuptools.command.build_ext import build_ext as _build_ext + +# Test if compiling with cython or using the C source +try: + from Cython.Distutils import build_ext as _build_ext +except ImportError: + USE_CYTHON = False +else: + USE_CYTHON = True + +print('Using Cython {}'.format(USE_CYTHON)) +ext = '.pyx' if USE_CYTHON else '.c' + + +class build_ext(_build_ext): + def finalize_options(self): + _build_ext.finalize_options(self) + with open('README.md') as readme_file: readme = readme_file.read() -# with open('HISTORY.md') as history_file: -# history = history_file.read() - with open('requirements.txt') as requirements_file: requirements = requirements_file.read() @@ -19,8 +33,9 @@ test_requirements = [] -# force the compiler to use gcc -os.environ["CC"] = "gcc" +# Give user option to specify their local compiler name +if "CC" not in os.environ: + os.environ["CC"] = "gcc" cmdclass = {'build_ext': build_ext} ext_modules = [] @@ -36,25 +51,23 @@ "hor1d.c", ]], include_dirs=[numpy.get_include()], - extra_compile_args=['-O3'], - extra_link_args=['-O3'], ), ] setup( - author="Scott Havens", - author_email='scott.havens@ars.usda.gov', - python_requires='>=3.5', + author="USDA ARS NWRC", + author_email='snow@ars.usda.gov', + python_requires='>=3.6', classifiers=[ 'Development Status :: 2 - Pre-Alpha', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Natural Language :: English', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9' ], description="Topo calculations like gradient and sky view", entry_points={ @@ -67,9 +80,6 @@ long_description=readme, long_description_content_type="text/markdown", include_package_data=True, - # package_data={ - # 'topocalc': ['*.pyx', '*.pxd', '*.c', '*.h'], - # }, keywords='topocalc', name='topocalc', packages=find_packages(include=['topocalc', 'topocalc.*']), @@ -79,7 +89,6 @@ cmdclass=cmdclass, ext_modules=ext_modules, url='https://github.com/USDA-ARS-NWRC/topocalc', - # version='0.1.0', use_scm_version={ "local_scheme": "no-local-version" }, diff --git a/topocalc/core_c/hor1d.c b/topocalc/core_c/hor1d.c index c4f3fe4..bc06636 100644 --- a/topocalc/core_c/hor1d.c +++ b/topocalc/core_c/hor1d.c @@ -8,19 +8,12 @@ #include #include "topo_core.h" -#define SLOPEF(i, j, zi, zj) \ - (((zj) <= (zi)) ? 0 : ((zj) - (zi)) / ((float)((j) - (i)))) - -#define SLOPEB(i, j, zi, zj) \ - (((zj) <= (zi)) ? 0 : ((zj) - (zi)) / ((float)((i) - (j)))) - void hor2d( int nrows, /* rows of elevations array */ int ncols, /* columns of elevations array */ double *z, /* elevations */ double delta, /* spacing */ bool forward, /* forward function */ - int *h, /* horizon function */ double *hcos) /* cosines of angles to horizon */ { int i, j; /* loop index */ @@ -83,10 +76,11 @@ int hor1f( { double slope_ik; /* slope i to k */ double max_slope; /* max slope value */ - double max_point; /* point with max horizon */ + int max_point; /* point with max horizon */ double zi; /* z[i] */ int i; /* current point index */ int k; /* search point index */ + double dist; /* difference between i and k */ /* * end point is its own horizon in forward direction; first point is @@ -99,12 +93,12 @@ int hor1f( * beginning. For backward direction, loop runs from * next-to-beginning forward to end. */ - for (i = n - 1; i >= 0; --i) + for (i = n - 2; i >= 0; --i) { zi = z[i]; /* assume the point is it's own horizon at first*/ - max_slope = 0; + max_slope = 0.0; max_point = i; /* @@ -113,23 +107,27 @@ int hor1f( * this differs from the original in that the original started * with the next to adjacent point */ - for (k = i + 1; k <= n; k++) + for (k = i + 1; k < n; k++) { - /* - * Slope from the current point to the kth point + * Only look at points higher than the starting point */ - slope_ik = SLOPEF(i, k, zi, z[k]); - /* - * Compare each kth point against the maximum slope - * already found. If it's slope is greater than the previous - * horizon, then it's found a new horizon - */ - if (slope_ik > max_slope) + if (z[k] > zi) { - max_slope = slope_ik; - max_point = k; + dist = (double)(k - i); + slope_ik = (z[k] - zi) / dist; + + /* + * Compare each kth point against the maximum slope + * already found. If it's slope is greater than the previous + * horizon, then it's found a new horizon + */ + if (slope_ik > max_slope) + { + max_slope = slope_ik; + max_point = k; + } } } @@ -149,10 +147,11 @@ int hor1b( { double slope_ik; /* slope i to k */ double max_slope; /* max slope value */ - double max_point; /* point with max horizon */ + int max_point; /* point with max horizon */ double zi; /* z[i] */ int i; /* current point index */ int k; /* search point index */ + double dist; /* difference between i and k */ /* * end point is its own horizon in forward direction; first point is @@ -170,7 +169,7 @@ int hor1b( zi = z[i]; /* assume the point is it's own horizon at first*/ - max_slope = 0; + max_slope = 0.0; max_point = i; /* @@ -183,19 +182,23 @@ int hor1b( { /* - * Slope from the current point to the kth point - */ - slope_ik = SLOPEB(i, k, zi, z[k]); - - /* - * Compare each kth point against the maximum slope - * already found. If it's slope is greater than the previous - * horizon, then it's found a new horizon + * Only look at points higher than the starting point */ - if (slope_ik > max_slope) + if (z[k] > zi) { - max_slope = slope_ik; - max_point = k; + dist = (double)(i - k); + slope_ik = (z[k] - zi) / dist; + + /* + * Compare each kth point against the maximum slope + * already found. If it's slope is greater than the previous + * horizon, then it's found a new horizon + */ + if (slope_ik > max_slope) + { + max_slope = slope_ik; + max_point = k; + } } } @@ -219,7 +222,7 @@ void horval( int *h, /* horizon function */ double *hcos) /* cosines of angles to horizon */ { - int d; /* difference in indices */ + double d; /* difference in indices */ int i; /* index of point */ int j; /* index of horizon point */ double diff; /* elevation difference */ @@ -229,21 +232,21 @@ void horval( /* # grid points to horizon */ j = h[i]; - d = j - i; + d = (double)(j - i); /* point is its own horizon */ if (d == 0) { - *hcos++ = 0; + hcos[i] = 0; } - /* else need to calculate sine */ + /* else need to calculate cosine */ else { if (d < 0) d = -d; diff = z[j] - z[i]; - *hcos++ = diff / (double)hypot(diff, d * delta); + hcos[i] = diff / (double)hypot(diff, d * delta); } } } \ No newline at end of file diff --git a/topocalc/core_c/topo_core.c b/topocalc/core_c/topo_core.c index e61647c..af4df81 100644 --- a/topocalc/core_c/topo_core.c +++ b/topocalc/core_c/topo_core.c @@ -1610,8 +1610,6 @@ static PyTypeObject *__pyx_ptype_5numpy_ndarray = 0; static PyTypeObject *__pyx_ptype_5numpy_ufunc = 0; static CYTHON_INLINE int __pyx_f_5numpy_import_array(void); /*proto*/ -/* Module declarations from 'libcpp' */ - /* Module declarations from 'topocalc.core_c.topo_core' */ static __Pyx_TypeInfo __Pyx_TypeInfo_double = { "double", NULL, sizeof(double), { 0 }, 0, 'R', 0, 0 }; static __Pyx_TypeInfo __Pyx_TypeInfo_int = { "int", NULL, sizeof(int), { 0 }, 0, IS_UNSIGNED(int) ? 'U' : 'I', IS_UNSIGNED(int), 0 }; @@ -1644,6 +1642,7 @@ static const char __pyx_k_c_hor2d[] = "c_hor2d"; static const char __pyx_k_float64[] = "float64"; static const char __pyx_k_forward[] = "forward"; static const char __pyx_k_spacing[] = "spacing"; +static const char __pyx_k_cspacing[] = "cspacing"; static const char __pyx_k_ImportError[] = "ImportError"; static const char __pyx_k_ascontiguousarray[] = "ascontiguousarray"; static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; @@ -1658,6 +1657,7 @@ static PyObject *__pyx_n_s_c_hor1d; static PyObject *__pyx_n_s_c_hor2d; static PyObject *__pyx_n_s_c_int; static PyObject *__pyx_n_s_cline_in_traceback; +static PyObject *__pyx_n_s_cspacing; static PyObject *__pyx_n_s_ctypes; static PyObject *__pyx_n_s_dtype; static PyObject *__pyx_n_s_empty; @@ -1682,8 +1682,8 @@ static PyObject *__pyx_n_s_topocalc_core_c_topo_core; static PyObject *__pyx_kp_s_topocalc_core_c_topo_core_pyx; static PyObject *__pyx_n_s_z; static PyObject *__pyx_n_s_z_arr; -static PyObject *__pyx_pf_8topocalc_6core_c_9topo_core_c_hor1d(CYTHON_UNUSED PyObject *__pyx_self, PyArrayObject *__pyx_v_z, double __pyx_v_spacing, bool __pyx_v_forward, PyArrayObject *__pyx_v_hcos); /* proto */ -static PyObject *__pyx_pf_8topocalc_6core_c_9topo_core_2c_hor2d(CYTHON_UNUSED PyObject *__pyx_self, PyArrayObject *__pyx_v_z, double __pyx_v_spacing, bool __pyx_v_forward, PyArrayObject *__pyx_v_hcos); /* proto */ +static PyObject *__pyx_pf_8topocalc_6core_c_9topo_core_c_hor1d(CYTHON_UNUSED PyObject *__pyx_self, PyArrayObject *__pyx_v_z, double __pyx_v_spacing, int __pyx_v_forward, PyArrayObject *__pyx_v_hcos); /* proto */ +static PyObject *__pyx_pf_8topocalc_6core_c_9topo_core_2c_hor2d(CYTHON_UNUSED PyObject *__pyx_self, PyArrayObject *__pyx_v_z, double __pyx_v_spacing, int __pyx_v_forward, PyArrayObject *__pyx_v_hcos); /* proto */ static PyObject *__pyx_tuple_; static PyObject *__pyx_tuple__2; static PyObject *__pyx_tuple__3; @@ -1692,12 +1692,12 @@ static PyObject *__pyx_codeobj__4; static PyObject *__pyx_codeobj__6; /* Late includes */ -/* "topocalc/core_c/topo_core.pyx":28 +/* "topocalc/core_c/topo_core.pyx":29 * @cython.wraparound(False) * # https://github.com/cython/cython/wiki/tutorials-NumpyPointerToC * def c_hor1d(np.ndarray[double, mode="c", ndim=1] z, # <<<<<<<<<<<<<< * double spacing, - * bool forward, + * bint forward, */ /* Python wrapper */ @@ -1707,7 +1707,7 @@ static PyMethodDef __pyx_mdef_8topocalc_6core_c_9topo_core_1c_hor1d = {"c_hor1d" static PyObject *__pyx_pw_8topocalc_6core_c_9topo_core_1c_hor1d(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { PyArrayObject *__pyx_v_z = 0; double __pyx_v_spacing; - bool __pyx_v_forward; + int __pyx_v_forward; PyArrayObject *__pyx_v_hcos = 0; int __pyx_lineno = 0; const char *__pyx_filename = NULL; @@ -1742,23 +1742,23 @@ static PyObject *__pyx_pw_8topocalc_6core_c_9topo_core_1c_hor1d(PyObject *__pyx_ case 1: if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_spacing)) != 0)) kw_args--; else { - __Pyx_RaiseArgtupleInvalid("c_hor1d", 1, 4, 4, 1); __PYX_ERR(0, 28, __pyx_L3_error) + __Pyx_RaiseArgtupleInvalid("c_hor1d", 1, 4, 4, 1); __PYX_ERR(0, 29, __pyx_L3_error) } CYTHON_FALLTHROUGH; case 2: if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_forward)) != 0)) kw_args--; else { - __Pyx_RaiseArgtupleInvalid("c_hor1d", 1, 4, 4, 2); __PYX_ERR(0, 28, __pyx_L3_error) + __Pyx_RaiseArgtupleInvalid("c_hor1d", 1, 4, 4, 2); __PYX_ERR(0, 29, __pyx_L3_error) } CYTHON_FALLTHROUGH; case 3: if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_hcos)) != 0)) kw_args--; else { - __Pyx_RaiseArgtupleInvalid("c_hor1d", 1, 4, 4, 3); __PYX_ERR(0, 28, __pyx_L3_error) + __Pyx_RaiseArgtupleInvalid("c_hor1d", 1, 4, 4, 3); __PYX_ERR(0, 29, __pyx_L3_error) } } if (unlikely(kw_args > 0)) { - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "c_hor1d") < 0)) __PYX_ERR(0, 28, __pyx_L3_error) + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "c_hor1d") < 0)) __PYX_ERR(0, 29, __pyx_L3_error) } } else if (PyTuple_GET_SIZE(__pyx_args) != 4) { goto __pyx_L5_argtuple_error; @@ -1769,20 +1769,20 @@ static PyObject *__pyx_pw_8topocalc_6core_c_9topo_core_1c_hor1d(PyObject *__pyx_ values[3] = PyTuple_GET_ITEM(__pyx_args, 3); } __pyx_v_z = ((PyArrayObject *)values[0]); - __pyx_v_spacing = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_spacing == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 29, __pyx_L3_error) - __pyx_v_forward = __Pyx_PyObject_IsTrue(values[2]); if (unlikely((__pyx_v_forward == ((bool)-1)) && PyErr_Occurred())) __PYX_ERR(0, 30, __pyx_L3_error) + __pyx_v_spacing = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_spacing == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 30, __pyx_L3_error) + __pyx_v_forward = __Pyx_PyObject_IsTrue(values[2]); if (unlikely((__pyx_v_forward == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 31, __pyx_L3_error) __pyx_v_hcos = ((PyArrayObject *)values[3]); } goto __pyx_L4_argument_unpacking_done; __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("c_hor1d", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 28, __pyx_L3_error) + __Pyx_RaiseArgtupleInvalid("c_hor1d", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 29, __pyx_L3_error) __pyx_L3_error:; __Pyx_AddTraceback("topocalc.core_c.topo_core.c_hor1d", __pyx_clineno, __pyx_lineno, __pyx_filename); __Pyx_RefNannyFinishContext(); return NULL; __pyx_L4_argument_unpacking_done:; - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_z), __pyx_ptype_5numpy_ndarray, 1, "z", 0))) __PYX_ERR(0, 28, __pyx_L1_error) - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_hcos), __pyx_ptype_5numpy_ndarray, 1, "hcos", 0))) __PYX_ERR(0, 31, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_z), __pyx_ptype_5numpy_ndarray, 1, "z", 0))) __PYX_ERR(0, 29, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_hcos), __pyx_ptype_5numpy_ndarray, 1, "hcos", 0))) __PYX_ERR(0, 32, __pyx_L1_error) __pyx_r = __pyx_pf_8topocalc_6core_c_9topo_core_c_hor1d(__pyx_self, __pyx_v_z, __pyx_v_spacing, __pyx_v_forward, __pyx_v_hcos); /* function exit code */ @@ -1794,7 +1794,7 @@ static PyObject *__pyx_pw_8topocalc_6core_c_9topo_core_1c_hor1d(PyObject *__pyx_ return __pyx_r; } -static PyObject *__pyx_pf_8topocalc_6core_c_9topo_core_c_hor1d(CYTHON_UNUSED PyObject *__pyx_self, PyArrayObject *__pyx_v_z, double __pyx_v_spacing, bool __pyx_v_forward, PyArrayObject *__pyx_v_hcos) { +static PyObject *__pyx_pf_8topocalc_6core_c_9topo_core_c_hor1d(CYTHON_UNUSED PyObject *__pyx_self, PyArrayObject *__pyx_v_z, double __pyx_v_spacing, int __pyx_v_forward, PyArrayObject *__pyx_v_hcos) { int __pyx_v_n; PyArrayObject *__pyx_v_z_arr = 0; PyArrayObject *__pyx_v_h = 0; @@ -1845,16 +1845,16 @@ static PyObject *__pyx_pf_8topocalc_6core_c_9topo_core_c_hor1d(CYTHON_UNUSED PyO __pyx_pybuffernd_hcos.rcbuffer = &__pyx_pybuffer_hcos; { __Pyx_BufFmt_StackElem __pyx_stack[1]; - if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_z.rcbuffer->pybuffer, (PyObject*)__pyx_v_z, &__Pyx_TypeInfo_double, PyBUF_FORMAT| PyBUF_C_CONTIGUOUS, 1, 0, __pyx_stack) == -1)) __PYX_ERR(0, 28, __pyx_L1_error) + if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_z.rcbuffer->pybuffer, (PyObject*)__pyx_v_z, &__Pyx_TypeInfo_double, PyBUF_FORMAT| PyBUF_C_CONTIGUOUS, 1, 0, __pyx_stack) == -1)) __PYX_ERR(0, 29, __pyx_L1_error) } __pyx_pybuffernd_z.diminfo[0].strides = __pyx_pybuffernd_z.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_z.diminfo[0].shape = __pyx_pybuffernd_z.rcbuffer->pybuffer.shape[0]; { __Pyx_BufFmt_StackElem __pyx_stack[1]; - if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_hcos.rcbuffer->pybuffer, (PyObject*)__pyx_v_hcos, &__Pyx_TypeInfo_double, PyBUF_FORMAT| PyBUF_C_CONTIGUOUS, 1, 0, __pyx_stack) == -1)) __PYX_ERR(0, 28, __pyx_L1_error) + if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_hcos.rcbuffer->pybuffer, (PyObject*)__pyx_v_hcos, &__Pyx_TypeInfo_double, PyBUF_FORMAT| PyBUF_C_CONTIGUOUS, 1, 0, __pyx_stack) == -1)) __PYX_ERR(0, 29, __pyx_L1_error) } __pyx_pybuffernd_hcos.diminfo[0].strides = __pyx_pybuffernd_hcos.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_hcos.diminfo[0].shape = __pyx_pybuffernd_hcos.rcbuffer->pybuffer.shape[0]; - /* "topocalc/core_c/topo_core.pyx":46 + /* "topocalc/core_c/topo_core.pyx":47 * * cdef int n * n = z.shape[0] # <<<<<<<<<<<<<< @@ -1863,38 +1863,38 @@ static PyObject *__pyx_pf_8topocalc_6core_c_9topo_core_c_hor1d(CYTHON_UNUSED PyO */ __pyx_v_n = (__pyx_v_z->dimensions[0]); - /* "topocalc/core_c/topo_core.pyx":50 + /* "topocalc/core_c/topo_core.pyx":51 * # convert the z array to C * cdef np.ndarray[double, mode="c", ndim=1] z_arr * z_arr = np.ascontiguousarray(z, dtype=np.float64) # <<<<<<<<<<<<<< * * # integer array for horizon index */ - __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 50, __pyx_L1_error) + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 51, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); - __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_ascontiguousarray); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 50, __pyx_L1_error) + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_ascontiguousarray); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 51, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 50, __pyx_L1_error) + __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 51, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); __Pyx_INCREF(((PyObject *)__pyx_v_z)); __Pyx_GIVEREF(((PyObject *)__pyx_v_z)); PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_v_z)); - __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 50, __pyx_L1_error) + __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 51, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_3); - __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 50, __pyx_L1_error) + __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 51, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_4); - __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_float64); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 50, __pyx_L1_error) + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_float64); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 51, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_5); __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_dtype, __pyx_t_5) < 0) __PYX_ERR(0, 50, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_dtype, __pyx_t_5) < 0) __PYX_ERR(0, 51, __pyx_L1_error) __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_1, __pyx_t_3); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 50, __pyx_L1_error) + __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_1, __pyx_t_3); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 51, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_5); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (!(likely(((__pyx_t_5) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_5, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 50, __pyx_L1_error) + if (!(likely(((__pyx_t_5) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_5, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 51, __pyx_L1_error) __pyx_t_6 = ((PyArrayObject *)__pyx_t_5); { __Pyx_BufFmt_StackElem __pyx_stack[1]; @@ -1911,57 +1911,57 @@ static PyObject *__pyx_pf_8topocalc_6core_c_9topo_core_c_hor1d(CYTHON_UNUSED PyO __pyx_t_8 = __pyx_t_9 = __pyx_t_10 = 0; } __pyx_pybuffernd_z_arr.diminfo[0].strides = __pyx_pybuffernd_z_arr.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_z_arr.diminfo[0].shape = __pyx_pybuffernd_z_arr.rcbuffer->pybuffer.shape[0]; - if (unlikely(__pyx_t_7 < 0)) __PYX_ERR(0, 50, __pyx_L1_error) + if (unlikely(__pyx_t_7 < 0)) __PYX_ERR(0, 51, __pyx_L1_error) } __pyx_t_6 = 0; __pyx_v_z_arr = ((PyArrayObject *)__pyx_t_5); __pyx_t_5 = 0; - /* "topocalc/core_c/topo_core.pyx":53 + /* "topocalc/core_c/topo_core.pyx":54 * * # integer array for horizon index * cdef np.ndarray[int, ndim=1, mode='c'] h = np.empty((n,), dtype = ctypes.c_int) # <<<<<<<<<<<<<< * * # call the hor1f C function */ - __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 53, __pyx_L1_error) + __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 54, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_5); - __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_empty); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 53, __pyx_L1_error) + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_empty); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 54, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_n); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 53, __pyx_L1_error) + __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_n); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 54, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_5); - __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 53, __pyx_L1_error) + __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 54, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_5); __pyx_t_5 = 0; - __pyx_t_5 = PyTuple_New(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 53, __pyx_L1_error) + __pyx_t_5 = PyTuple_New(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 54, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_5); __Pyx_GIVEREF(__pyx_t_1); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 53, __pyx_L1_error) + __pyx_t_1 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 54, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_ctypes); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 53, __pyx_L1_error) + __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_ctypes); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 54, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_2); - __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_c_int); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 53, __pyx_L1_error) + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_c_int); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 54, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_4); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_dtype, __pyx_t_4) < 0) __PYX_ERR(0, 53, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_dtype, __pyx_t_4) < 0) __PYX_ERR(0, 54, __pyx_L1_error) __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_5, __pyx_t_1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 53, __pyx_L1_error) + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_5, __pyx_t_1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 54, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_4); __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - if (!(likely(((__pyx_t_4) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_4, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 53, __pyx_L1_error) + if (!(likely(((__pyx_t_4) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_4, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 54, __pyx_L1_error) __pyx_t_11 = ((PyArrayObject *)__pyx_t_4); { __Pyx_BufFmt_StackElem __pyx_stack[1]; if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_h.rcbuffer->pybuffer, (PyObject*)__pyx_t_11, &__Pyx_TypeInfo_int, PyBUF_FORMAT| PyBUF_C_CONTIGUOUS, 1, 0, __pyx_stack) == -1)) { __pyx_v_h = ((PyArrayObject *)Py_None); __Pyx_INCREF(Py_None); __pyx_pybuffernd_h.rcbuffer->pybuffer.buf = NULL; - __PYX_ERR(0, 53, __pyx_L1_error) + __PYX_ERR(0, 54, __pyx_L1_error) } else {__pyx_pybuffernd_h.diminfo[0].strides = __pyx_pybuffernd_h.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_h.diminfo[0].shape = __pyx_pybuffernd_h.rcbuffer->pybuffer.shape[0]; } } @@ -1969,7 +1969,7 @@ static PyObject *__pyx_pf_8topocalc_6core_c_9topo_core_c_hor1d(CYTHON_UNUSED PyO __pyx_v_h = ((PyArrayObject *)__pyx_t_4); __pyx_t_4 = 0; - /* "topocalc/core_c/topo_core.pyx":56 + /* "topocalc/core_c/topo_core.pyx":57 * * # call the hor1f C function * if forward: # <<<<<<<<<<<<<< @@ -1979,7 +1979,7 @@ static PyObject *__pyx_pf_8topocalc_6core_c_9topo_core_c_hor1d(CYTHON_UNUSED PyO __pyx_t_12 = (__pyx_v_forward != 0); if (__pyx_t_12) { - /* "topocalc/core_c/topo_core.pyx":57 + /* "topocalc/core_c/topo_core.pyx":58 * # call the hor1f C function * if forward: * hor1f(n, &z_arr[0], &h[0]) # <<<<<<<<<<<<<< @@ -1990,7 +1990,7 @@ static PyObject *__pyx_pf_8topocalc_6core_c_9topo_core_c_hor1d(CYTHON_UNUSED PyO __pyx_t_14 = 0; hor1f(__pyx_v_n, (&(*__Pyx_BufPtrCContig1d(double *, __pyx_pybuffernd_z_arr.rcbuffer->pybuffer.buf, __pyx_t_13, __pyx_pybuffernd_z_arr.diminfo[0].strides))), (&(*__Pyx_BufPtrCContig1d(int *, __pyx_pybuffernd_h.rcbuffer->pybuffer.buf, __pyx_t_14, __pyx_pybuffernd_h.diminfo[0].strides)))); - /* "topocalc/core_c/topo_core.pyx":56 + /* "topocalc/core_c/topo_core.pyx":57 * * # call the hor1f C function * if forward: # <<<<<<<<<<<<<< @@ -2000,7 +2000,7 @@ static PyObject *__pyx_pf_8topocalc_6core_c_9topo_core_c_hor1d(CYTHON_UNUSED PyO goto __pyx_L3; } - /* "topocalc/core_c/topo_core.pyx":59 + /* "topocalc/core_c/topo_core.pyx":60 * hor1f(n, &z_arr[0], &h[0]) * else: * hor1b(n, &z_arr[0], &h[0]) # <<<<<<<<<<<<<< @@ -2014,7 +2014,7 @@ static PyObject *__pyx_pf_8topocalc_6core_c_9topo_core_c_hor1d(CYTHON_UNUSED PyO } __pyx_L3:; - /* "topocalc/core_c/topo_core.pyx":62 + /* "topocalc/core_c/topo_core.pyx":63 * * # call the horval C function * horval(n, &z_arr[0], spacing, &h[0], &hcos[0]) # <<<<<<<<<<<<<< @@ -2026,12 +2026,12 @@ static PyObject *__pyx_pf_8topocalc_6core_c_9topo_core_c_hor1d(CYTHON_UNUSED PyO __pyx_t_15 = 0; horval(__pyx_v_n, (&(*__Pyx_BufPtrCContig1d(double *, __pyx_pybuffernd_z_arr.rcbuffer->pybuffer.buf, __pyx_t_13, __pyx_pybuffernd_z_arr.diminfo[0].strides))), __pyx_v_spacing, (&(*__Pyx_BufPtrCContig1d(int *, __pyx_pybuffernd_h.rcbuffer->pybuffer.buf, __pyx_t_14, __pyx_pybuffernd_h.diminfo[0].strides))), (&(*__Pyx_BufPtrCContig1d(double *, __pyx_pybuffernd_hcos.rcbuffer->pybuffer.buf, __pyx_t_15, __pyx_pybuffernd_hcos.diminfo[0].strides)))); - /* "topocalc/core_c/topo_core.pyx":28 + /* "topocalc/core_c/topo_core.pyx":29 * @cython.wraparound(False) * # https://github.com/cython/cython/wiki/tutorials-NumpyPointerToC * def c_hor1d(np.ndarray[double, mode="c", ndim=1] z, # <<<<<<<<<<<<<< * double spacing, - * bool forward, + * bint forward, */ /* function exit code */ @@ -2068,12 +2068,12 @@ static PyObject *__pyx_pf_8topocalc_6core_c_9topo_core_c_hor1d(CYTHON_UNUSED PyO return __pyx_r; } -/* "topocalc/core_c/topo_core.pyx":67 +/* "topocalc/core_c/topo_core.pyx":68 * @cython.wraparound(False) * # https://github.com/cython/cython/wiki/tutorials-NumpyPointerToC * def c_hor2d(np.ndarray[double, mode="c", ndim=2] z, # <<<<<<<<<<<<<< * double spacing, - * bool forward, + * bint forward, */ /* Python wrapper */ @@ -2083,7 +2083,7 @@ static PyMethodDef __pyx_mdef_8topocalc_6core_c_9topo_core_3c_hor2d = {"c_hor2d" static PyObject *__pyx_pw_8topocalc_6core_c_9topo_core_3c_hor2d(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { PyArrayObject *__pyx_v_z = 0; double __pyx_v_spacing; - bool __pyx_v_forward; + int __pyx_v_forward; PyArrayObject *__pyx_v_hcos = 0; int __pyx_lineno = 0; const char *__pyx_filename = NULL; @@ -2118,23 +2118,23 @@ static PyObject *__pyx_pw_8topocalc_6core_c_9topo_core_3c_hor2d(PyObject *__pyx_ case 1: if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_spacing)) != 0)) kw_args--; else { - __Pyx_RaiseArgtupleInvalid("c_hor2d", 1, 4, 4, 1); __PYX_ERR(0, 67, __pyx_L3_error) + __Pyx_RaiseArgtupleInvalid("c_hor2d", 1, 4, 4, 1); __PYX_ERR(0, 68, __pyx_L3_error) } CYTHON_FALLTHROUGH; case 2: if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_forward)) != 0)) kw_args--; else { - __Pyx_RaiseArgtupleInvalid("c_hor2d", 1, 4, 4, 2); __PYX_ERR(0, 67, __pyx_L3_error) + __Pyx_RaiseArgtupleInvalid("c_hor2d", 1, 4, 4, 2); __PYX_ERR(0, 68, __pyx_L3_error) } CYTHON_FALLTHROUGH; case 3: if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_hcos)) != 0)) kw_args--; else { - __Pyx_RaiseArgtupleInvalid("c_hor2d", 1, 4, 4, 3); __PYX_ERR(0, 67, __pyx_L3_error) + __Pyx_RaiseArgtupleInvalid("c_hor2d", 1, 4, 4, 3); __PYX_ERR(0, 68, __pyx_L3_error) } } if (unlikely(kw_args > 0)) { - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "c_hor2d") < 0)) __PYX_ERR(0, 67, __pyx_L3_error) + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "c_hor2d") < 0)) __PYX_ERR(0, 68, __pyx_L3_error) } } else if (PyTuple_GET_SIZE(__pyx_args) != 4) { goto __pyx_L5_argtuple_error; @@ -2145,20 +2145,20 @@ static PyObject *__pyx_pw_8topocalc_6core_c_9topo_core_3c_hor2d(PyObject *__pyx_ values[3] = PyTuple_GET_ITEM(__pyx_args, 3); } __pyx_v_z = ((PyArrayObject *)values[0]); - __pyx_v_spacing = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_spacing == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 68, __pyx_L3_error) - __pyx_v_forward = __Pyx_PyObject_IsTrue(values[2]); if (unlikely((__pyx_v_forward == ((bool)-1)) && PyErr_Occurred())) __PYX_ERR(0, 69, __pyx_L3_error) + __pyx_v_spacing = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_spacing == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 69, __pyx_L3_error) + __pyx_v_forward = __Pyx_PyObject_IsTrue(values[2]); if (unlikely((__pyx_v_forward == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 70, __pyx_L3_error) __pyx_v_hcos = ((PyArrayObject *)values[3]); } goto __pyx_L4_argument_unpacking_done; __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("c_hor2d", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 67, __pyx_L3_error) + __Pyx_RaiseArgtupleInvalid("c_hor2d", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 68, __pyx_L3_error) __pyx_L3_error:; __Pyx_AddTraceback("topocalc.core_c.topo_core.c_hor2d", __pyx_clineno, __pyx_lineno, __pyx_filename); __Pyx_RefNannyFinishContext(); return NULL; __pyx_L4_argument_unpacking_done:; - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_z), __pyx_ptype_5numpy_ndarray, 1, "z", 0))) __PYX_ERR(0, 67, __pyx_L1_error) - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_hcos), __pyx_ptype_5numpy_ndarray, 1, "hcos", 0))) __PYX_ERR(0, 70, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_z), __pyx_ptype_5numpy_ndarray, 1, "z", 0))) __PYX_ERR(0, 68, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_hcos), __pyx_ptype_5numpy_ndarray, 1, "hcos", 0))) __PYX_ERR(0, 71, __pyx_L1_error) __pyx_r = __pyx_pf_8topocalc_6core_c_9topo_core_2c_hor2d(__pyx_self, __pyx_v_z, __pyx_v_spacing, __pyx_v_forward, __pyx_v_hcos); /* function exit code */ @@ -2170,14 +2170,12 @@ static PyObject *__pyx_pw_8topocalc_6core_c_9topo_core_3c_hor2d(PyObject *__pyx_ return __pyx_r; } -static PyObject *__pyx_pf_8topocalc_6core_c_9topo_core_2c_hor2d(CYTHON_UNUSED PyObject *__pyx_self, PyArrayObject *__pyx_v_z, double __pyx_v_spacing, bool __pyx_v_forward, PyArrayObject *__pyx_v_hcos) { +static PyObject *__pyx_pf_8topocalc_6core_c_9topo_core_2c_hor2d(CYTHON_UNUSED PyObject *__pyx_self, PyArrayObject *__pyx_v_z, double __pyx_v_spacing, int __pyx_v_forward, PyArrayObject *__pyx_v_hcos) { int __pyx_v_nrows; int __pyx_v_ncols; - bool __pyx_v_fwd; + double __pyx_v_cspacing; + int __pyx_v_fwd; PyArrayObject *__pyx_v_z_arr = 0; - PyArrayObject *__pyx_v_h = 0; - __Pyx_LocalBuf_ND __pyx_pybuffernd_h; - __Pyx_Buffer __pyx_pybuffer_h; __Pyx_LocalBuf_ND __pyx_pybuffernd_hcos; __Pyx_Buffer __pyx_pybuffer_hcos; __Pyx_LocalBuf_ND __pyx_pybuffernd_z; @@ -2196,13 +2194,10 @@ static PyObject *__pyx_pf_8topocalc_6core_c_9topo_core_2c_hor2d(CYTHON_UNUSED Py PyObject *__pyx_t_8 = NULL; PyObject *__pyx_t_9 = NULL; PyObject *__pyx_t_10 = NULL; - PyArrayObject *__pyx_t_11 = NULL; + Py_ssize_t __pyx_t_11; Py_ssize_t __pyx_t_12; Py_ssize_t __pyx_t_13; Py_ssize_t __pyx_t_14; - Py_ssize_t __pyx_t_15; - Py_ssize_t __pyx_t_16; - Py_ssize_t __pyx_t_17; int __pyx_lineno = 0; const char *__pyx_filename = NULL; int __pyx_clineno = 0; @@ -2211,10 +2206,6 @@ static PyObject *__pyx_pf_8topocalc_6core_c_9topo_core_2c_hor2d(CYTHON_UNUSED Py __pyx_pybuffer_z_arr.refcount = 0; __pyx_pybuffernd_z_arr.data = NULL; __pyx_pybuffernd_z_arr.rcbuffer = &__pyx_pybuffer_z_arr; - __pyx_pybuffer_h.pybuffer.buf = NULL; - __pyx_pybuffer_h.refcount = 0; - __pyx_pybuffernd_h.data = NULL; - __pyx_pybuffernd_h.rcbuffer = &__pyx_pybuffer_h; __pyx_pybuffer_z.pybuffer.buf = NULL; __pyx_pybuffer_z.refcount = 0; __pyx_pybuffernd_z.data = NULL; @@ -2225,74 +2216,83 @@ static PyObject *__pyx_pf_8topocalc_6core_c_9topo_core_2c_hor2d(CYTHON_UNUSED Py __pyx_pybuffernd_hcos.rcbuffer = &__pyx_pybuffer_hcos; { __Pyx_BufFmt_StackElem __pyx_stack[1]; - if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_z.rcbuffer->pybuffer, (PyObject*)__pyx_v_z, &__Pyx_TypeInfo_double, PyBUF_FORMAT| PyBUF_C_CONTIGUOUS, 2, 0, __pyx_stack) == -1)) __PYX_ERR(0, 67, __pyx_L1_error) + if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_z.rcbuffer->pybuffer, (PyObject*)__pyx_v_z, &__Pyx_TypeInfo_double, PyBUF_FORMAT| PyBUF_C_CONTIGUOUS, 2, 0, __pyx_stack) == -1)) __PYX_ERR(0, 68, __pyx_L1_error) } __pyx_pybuffernd_z.diminfo[0].strides = __pyx_pybuffernd_z.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_z.diminfo[0].shape = __pyx_pybuffernd_z.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_z.diminfo[1].strides = __pyx_pybuffernd_z.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_z.diminfo[1].shape = __pyx_pybuffernd_z.rcbuffer->pybuffer.shape[1]; { __Pyx_BufFmt_StackElem __pyx_stack[1]; - if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_hcos.rcbuffer->pybuffer, (PyObject*)__pyx_v_hcos, &__Pyx_TypeInfo_double, PyBUF_FORMAT| PyBUF_C_CONTIGUOUS, 2, 0, __pyx_stack) == -1)) __PYX_ERR(0, 67, __pyx_L1_error) + if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_hcos.rcbuffer->pybuffer, (PyObject*)__pyx_v_hcos, &__Pyx_TypeInfo_double, PyBUF_FORMAT| PyBUF_C_CONTIGUOUS, 2, 0, __pyx_stack) == -1)) __PYX_ERR(0, 68, __pyx_L1_error) } __pyx_pybuffernd_hcos.diminfo[0].strides = __pyx_pybuffernd_hcos.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_hcos.diminfo[0].shape = __pyx_pybuffernd_hcos.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_hcos.diminfo[1].strides = __pyx_pybuffernd_hcos.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_hcos.diminfo[1].shape = __pyx_pybuffernd_hcos.rcbuffer->pybuffer.shape[1]; - /* "topocalc/core_c/topo_core.pyx":84 - * cdef int nrows - * cdef int ncols - * nrows = z.shape[0] # <<<<<<<<<<<<<< - * ncols = z.shape[1] + /* "topocalc/core_c/topo_core.pyx":83 + * """ * + * cdef int nrows = z.shape[0] # <<<<<<<<<<<<<< + * cdef int ncols = z.shape[1] + * cdef double cspacing = spacing */ __pyx_v_nrows = (__pyx_v_z->dimensions[0]); - /* "topocalc/core_c/topo_core.pyx":85 - * cdef int ncols - * nrows = z.shape[0] - * ncols = z.shape[1] # <<<<<<<<<<<<<< + /* "topocalc/core_c/topo_core.pyx":84 + * + * cdef int nrows = z.shape[0] + * cdef int ncols = z.shape[1] # <<<<<<<<<<<<<< + * cdef double cspacing = spacing * - * cdef bool fwd */ __pyx_v_ncols = (__pyx_v_z->dimensions[1]); - /* "topocalc/core_c/topo_core.pyx":88 + /* "topocalc/core_c/topo_core.pyx":85 + * cdef int nrows = z.shape[0] + * cdef int ncols = z.shape[1] + * cdef double cspacing = spacing # <<<<<<<<<<<<<< + * + * cdef bint fwd = forward + */ + __pyx_v_cspacing = __pyx_v_spacing; + + /* "topocalc/core_c/topo_core.pyx":87 + * cdef double cspacing = spacing * - * cdef bool fwd - * fwd = forward # <<<<<<<<<<<<<< + * cdef bint fwd = forward # <<<<<<<<<<<<<< * * # convert the z array to C */ __pyx_v_fwd = __pyx_v_forward; - /* "topocalc/core_c/topo_core.pyx":92 + /* "topocalc/core_c/topo_core.pyx":91 * # convert the z array to C * cdef np.ndarray[double, mode="c", ndim=2] z_arr * z_arr = np.ascontiguousarray(z, dtype=np.float64) # <<<<<<<<<<<<<< * - * # integer array for horizon index + * # call the hor2d C function */ - __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 92, __pyx_L1_error) + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 91, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); - __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_ascontiguousarray); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 92, __pyx_L1_error) + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_ascontiguousarray); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 91, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 92, __pyx_L1_error) + __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 91, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); __Pyx_INCREF(((PyObject *)__pyx_v_z)); __Pyx_GIVEREF(((PyObject *)__pyx_v_z)); PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_v_z)); - __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 92, __pyx_L1_error) + __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 91, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_3); - __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 92, __pyx_L1_error) + __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 91, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_4); - __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_float64); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 92, __pyx_L1_error) + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_float64); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 91, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_5); __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_dtype, __pyx_t_5) < 0) __PYX_ERR(0, 92, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_dtype, __pyx_t_5) < 0) __PYX_ERR(0, 91, __pyx_L1_error) __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_1, __pyx_t_3); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 92, __pyx_L1_error) + __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_1, __pyx_t_3); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 91, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_5); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (!(likely(((__pyx_t_5) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_5, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 92, __pyx_L1_error) + if (!(likely(((__pyx_t_5) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_5, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 91, __pyx_L1_error) __pyx_t_6 = ((PyArrayObject *)__pyx_t_5); { __Pyx_BufFmt_StackElem __pyx_stack[1]; @@ -2309,89 +2309,30 @@ static PyObject *__pyx_pf_8topocalc_6core_c_9topo_core_2c_hor2d(CYTHON_UNUSED Py __pyx_t_8 = __pyx_t_9 = __pyx_t_10 = 0; } __pyx_pybuffernd_z_arr.diminfo[0].strides = __pyx_pybuffernd_z_arr.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_z_arr.diminfo[0].shape = __pyx_pybuffernd_z_arr.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_z_arr.diminfo[1].strides = __pyx_pybuffernd_z_arr.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_z_arr.diminfo[1].shape = __pyx_pybuffernd_z_arr.rcbuffer->pybuffer.shape[1]; - if (unlikely(__pyx_t_7 < 0)) __PYX_ERR(0, 92, __pyx_L1_error) + if (unlikely(__pyx_t_7 < 0)) __PYX_ERR(0, 91, __pyx_L1_error) } __pyx_t_6 = 0; __pyx_v_z_arr = ((PyArrayObject *)__pyx_t_5); __pyx_t_5 = 0; - /* "topocalc/core_c/topo_core.pyx":95 - * - * # integer array for horizon index - * cdef np.ndarray[int, ndim=2, mode='c'] h = np.empty((nrows,ncols), dtype = ctypes.c_int) # <<<<<<<<<<<<<< - * - * # call the hor2d C function - */ - __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 95, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_empty); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 95, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_nrows); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 95, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_ncols); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 95, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 95, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_GIVEREF(__pyx_t_5); - PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_5); - __Pyx_GIVEREF(__pyx_t_1); - PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_t_1); - __pyx_t_5 = 0; - __pyx_t_1 = 0; - __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 95, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_GIVEREF(__pyx_t_2); - PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_2); - __pyx_t_2 = 0; - __pyx_t_2 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 95, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_n_s_ctypes); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 95, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_c_int); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 95, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_dtype, __pyx_t_4) < 0) __PYX_ERR(0, 95, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_1, __pyx_t_2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 95, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - if (!(likely(((__pyx_t_4) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_4, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 95, __pyx_L1_error) - __pyx_t_11 = ((PyArrayObject *)__pyx_t_4); - { - __Pyx_BufFmt_StackElem __pyx_stack[1]; - if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_h.rcbuffer->pybuffer, (PyObject*)__pyx_t_11, &__Pyx_TypeInfo_int, PyBUF_FORMAT| PyBUF_C_CONTIGUOUS, 2, 0, __pyx_stack) == -1)) { - __pyx_v_h = ((PyArrayObject *)Py_None); __Pyx_INCREF(Py_None); __pyx_pybuffernd_h.rcbuffer->pybuffer.buf = NULL; - __PYX_ERR(0, 95, __pyx_L1_error) - } else {__pyx_pybuffernd_h.diminfo[0].strides = __pyx_pybuffernd_h.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_h.diminfo[0].shape = __pyx_pybuffernd_h.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_h.diminfo[1].strides = __pyx_pybuffernd_h.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_h.diminfo[1].shape = __pyx_pybuffernd_h.rcbuffer->pybuffer.shape[1]; - } - } - __pyx_t_11 = 0; - __pyx_v_h = ((PyArrayObject *)__pyx_t_4); - __pyx_t_4 = 0; - - /* "topocalc/core_c/topo_core.pyx":98 + /* "topocalc/core_c/topo_core.pyx":94 * * # call the hor2d C function - * hor2d(nrows, ncols, &z_arr[0,0], spacing, fwd, &h[0,0], &hcos[0,0]) # <<<<<<<<<<<<<< + * hor2d(nrows, ncols, &z_arr[0,0], cspacing, fwd, &hcos[0,0]) # <<<<<<<<<<<<<< * */ + __pyx_t_11 = 0; __pyx_t_12 = 0; __pyx_t_13 = 0; __pyx_t_14 = 0; - __pyx_t_15 = 0; - __pyx_t_16 = 0; - __pyx_t_17 = 0; - hor2d(__pyx_v_nrows, __pyx_v_ncols, (&(*__Pyx_BufPtrCContig2d(double *, __pyx_pybuffernd_z_arr.rcbuffer->pybuffer.buf, __pyx_t_12, __pyx_pybuffernd_z_arr.diminfo[0].strides, __pyx_t_13, __pyx_pybuffernd_z_arr.diminfo[1].strides))), __pyx_v_spacing, __pyx_v_fwd, (&(*__Pyx_BufPtrCContig2d(int *, __pyx_pybuffernd_h.rcbuffer->pybuffer.buf, __pyx_t_14, __pyx_pybuffernd_h.diminfo[0].strides, __pyx_t_15, __pyx_pybuffernd_h.diminfo[1].strides))), (&(*__Pyx_BufPtrCContig2d(double *, __pyx_pybuffernd_hcos.rcbuffer->pybuffer.buf, __pyx_t_16, __pyx_pybuffernd_hcos.diminfo[0].strides, __pyx_t_17, __pyx_pybuffernd_hcos.diminfo[1].strides)))); + hor2d(__pyx_v_nrows, __pyx_v_ncols, (&(*__Pyx_BufPtrCContig2d(double *, __pyx_pybuffernd_z_arr.rcbuffer->pybuffer.buf, __pyx_t_11, __pyx_pybuffernd_z_arr.diminfo[0].strides, __pyx_t_12, __pyx_pybuffernd_z_arr.diminfo[1].strides))), __pyx_v_cspacing, __pyx_v_fwd, (&(*__Pyx_BufPtrCContig2d(double *, __pyx_pybuffernd_hcos.rcbuffer->pybuffer.buf, __pyx_t_13, __pyx_pybuffernd_hcos.diminfo[0].strides, __pyx_t_14, __pyx_pybuffernd_hcos.diminfo[1].strides)))); - /* "topocalc/core_c/topo_core.pyx":67 + /* "topocalc/core_c/topo_core.pyx":68 * @cython.wraparound(False) * # https://github.com/cython/cython/wiki/tutorials-NumpyPointerToC * def c_hor2d(np.ndarray[double, mode="c", ndim=2] z, # <<<<<<<<<<<<<< * double spacing, - * bool forward, + * bint forward, */ /* function exit code */ @@ -2407,7 +2348,6 @@ static PyObject *__pyx_pf_8topocalc_6core_c_9topo_core_2c_hor2d(CYTHON_UNUSED Py __Pyx_PyThreadState_declare __Pyx_PyThreadState_assign __Pyx_ErrFetch(&__pyx_type, &__pyx_value, &__pyx_tb); - __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_h.rcbuffer->pybuffer); __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_hcos.rcbuffer->pybuffer); __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_z.rcbuffer->pybuffer); __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_z_arr.rcbuffer->pybuffer); @@ -2416,13 +2356,11 @@ static PyObject *__pyx_pf_8topocalc_6core_c_9topo_core_2c_hor2d(CYTHON_UNUSED Py __pyx_r = NULL; goto __pyx_L2; __pyx_L0:; - __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_h.rcbuffer->pybuffer); __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_hcos.rcbuffer->pybuffer); __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_z.rcbuffer->pybuffer); __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_z_arr.rcbuffer->pybuffer); __pyx_L2:; __Pyx_XDECREF((PyObject *)__pyx_v_z_arr); - __Pyx_XDECREF((PyObject *)__pyx_v_h); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; @@ -3323,6 +3261,7 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { {&__pyx_n_s_c_hor2d, __pyx_k_c_hor2d, sizeof(__pyx_k_c_hor2d), 0, 0, 1, 1}, {&__pyx_n_s_c_int, __pyx_k_c_int, sizeof(__pyx_k_c_int), 0, 0, 1, 1}, {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, + {&__pyx_n_s_cspacing, __pyx_k_cspacing, sizeof(__pyx_k_cspacing), 0, 0, 1, 1}, {&__pyx_n_s_ctypes, __pyx_k_ctypes, sizeof(__pyx_k_ctypes), 0, 0, 1, 1}, {&__pyx_n_s_dtype, __pyx_k_dtype, sizeof(__pyx_k_dtype), 0, 0, 1, 1}, {&__pyx_n_s_empty, __pyx_k_empty, sizeof(__pyx_k_empty), 0, 0, 1, 1}, @@ -3382,29 +3321,29 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { __Pyx_GOTREF(__pyx_tuple__2); __Pyx_GIVEREF(__pyx_tuple__2); - /* "topocalc/core_c/topo_core.pyx":28 + /* "topocalc/core_c/topo_core.pyx":29 * @cython.wraparound(False) * # https://github.com/cython/cython/wiki/tutorials-NumpyPointerToC * def c_hor1d(np.ndarray[double, mode="c", ndim=1] z, # <<<<<<<<<<<<<< * double spacing, - * bool forward, + * bint forward, */ - __pyx_tuple__3 = PyTuple_Pack(7, __pyx_n_s_z, __pyx_n_s_spacing, __pyx_n_s_forward, __pyx_n_s_hcos, __pyx_n_s_n, __pyx_n_s_z_arr, __pyx_n_s_h); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(0, 28, __pyx_L1_error) + __pyx_tuple__3 = PyTuple_Pack(7, __pyx_n_s_z, __pyx_n_s_spacing, __pyx_n_s_forward, __pyx_n_s_hcos, __pyx_n_s_n, __pyx_n_s_z_arr, __pyx_n_s_h); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(0, 29, __pyx_L1_error) __Pyx_GOTREF(__pyx_tuple__3); __Pyx_GIVEREF(__pyx_tuple__3); - __pyx_codeobj__4 = (PyObject*)__Pyx_PyCode_New(4, 0, 7, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__3, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_topocalc_core_c_topo_core_pyx, __pyx_n_s_c_hor1d, 28, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__4)) __PYX_ERR(0, 28, __pyx_L1_error) + __pyx_codeobj__4 = (PyObject*)__Pyx_PyCode_New(4, 0, 7, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__3, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_topocalc_core_c_topo_core_pyx, __pyx_n_s_c_hor1d, 29, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__4)) __PYX_ERR(0, 29, __pyx_L1_error) - /* "topocalc/core_c/topo_core.pyx":67 + /* "topocalc/core_c/topo_core.pyx":68 * @cython.wraparound(False) * # https://github.com/cython/cython/wiki/tutorials-NumpyPointerToC * def c_hor2d(np.ndarray[double, mode="c", ndim=2] z, # <<<<<<<<<<<<<< * double spacing, - * bool forward, + * bint forward, */ - __pyx_tuple__5 = PyTuple_Pack(9, __pyx_n_s_z, __pyx_n_s_spacing, __pyx_n_s_forward, __pyx_n_s_hcos, __pyx_n_s_nrows, __pyx_n_s_ncols, __pyx_n_s_fwd, __pyx_n_s_z_arr, __pyx_n_s_h); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(0, 67, __pyx_L1_error) + __pyx_tuple__5 = PyTuple_Pack(9, __pyx_n_s_z, __pyx_n_s_spacing, __pyx_n_s_forward, __pyx_n_s_hcos, __pyx_n_s_nrows, __pyx_n_s_ncols, __pyx_n_s_cspacing, __pyx_n_s_fwd, __pyx_n_s_z_arr); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(0, 68, __pyx_L1_error) __Pyx_GOTREF(__pyx_tuple__5); __Pyx_GIVEREF(__pyx_tuple__5); - __pyx_codeobj__6 = (PyObject*)__Pyx_PyCode_New(4, 0, 9, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__5, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_topocalc_core_c_topo_core_pyx, __pyx_n_s_c_hor2d, 67, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__6)) __PYX_ERR(0, 67, __pyx_L1_error) + __pyx_codeobj__6 = (PyObject*)__Pyx_PyCode_New(4, 0, 9, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__5, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_topocalc_core_c_topo_core_pyx, __pyx_n_s_c_hor2d, 68, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__6)) __PYX_ERR(0, 68, __pyx_L1_error) __Pyx_RefNannyFinishContext(); return 0; __pyx_L1_error:; @@ -3718,67 +3657,67 @@ if (!__Pyx_RefNanny) { if (__Pyx_patch_abc() < 0) __PYX_ERR(0, 1, __pyx_L1_error) #endif - /* "topocalc/core_c/topo_core.pyx":8 + /* "topocalc/core_c/topo_core.pyx":9 * * import cython * import numpy as np # <<<<<<<<<<<<<< * cimport numpy as np * import ctypes */ - __pyx_t_1 = __Pyx_Import(__pyx_n_s_numpy, 0, -1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 8, __pyx_L1_error) + __pyx_t_1 = __Pyx_Import(__pyx_n_s_numpy, 0, -1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 9, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); - if (PyDict_SetItem(__pyx_d, __pyx_n_s_np, __pyx_t_1) < 0) __PYX_ERR(0, 8, __pyx_L1_error) + if (PyDict_SetItem(__pyx_d, __pyx_n_s_np, __pyx_t_1) < 0) __PYX_ERR(0, 9, __pyx_L1_error) __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "topocalc/core_c/topo_core.pyx":10 + /* "topocalc/core_c/topo_core.pyx":11 * import numpy as np * cimport numpy as np * import ctypes # <<<<<<<<<<<<<< * # from cpython cimport bool - * from libcpp cimport bool + * # from libcpp cimport bool */ - __pyx_t_1 = __Pyx_Import(__pyx_n_s_ctypes, 0, -1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 10, __pyx_L1_error) + __pyx_t_1 = __Pyx_Import(__pyx_n_s_ctypes, 0, -1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 11, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); - if (PyDict_SetItem(__pyx_d, __pyx_n_s_ctypes, __pyx_t_1) < 0) __PYX_ERR(0, 10, __pyx_L1_error) + if (PyDict_SetItem(__pyx_d, __pyx_n_s_ctypes, __pyx_t_1) < 0) __PYX_ERR(0, 11, __pyx_L1_error) __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "topocalc/core_c/topo_core.pyx":17 + /* "topocalc/core_c/topo_core.pyx":18 * # Numpy must be initialized. When using numpy from C or Cython you must * # _always_ do that, or you will have segfaults * np.import_array() # <<<<<<<<<<<<<< * * cdef extern from "topo_core.h": */ - __pyx_t_2 = __pyx_f_5numpy_import_array(); if (unlikely(__pyx_t_2 == ((int)-1))) __PYX_ERR(0, 17, __pyx_L1_error) + __pyx_t_2 = __pyx_f_5numpy_import_array(); if (unlikely(__pyx_t_2 == ((int)-1))) __PYX_ERR(0, 18, __pyx_L1_error) - /* "topocalc/core_c/topo_core.pyx":28 + /* "topocalc/core_c/topo_core.pyx":29 * @cython.wraparound(False) * # https://github.com/cython/cython/wiki/tutorials-NumpyPointerToC * def c_hor1d(np.ndarray[double, mode="c", ndim=1] z, # <<<<<<<<<<<<<< * double spacing, - * bool forward, + * bint forward, */ - __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_8topocalc_6core_c_9topo_core_1c_hor1d, NULL, __pyx_n_s_topocalc_core_c_topo_core); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 28, __pyx_L1_error) + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_8topocalc_6core_c_9topo_core_1c_hor1d, NULL, __pyx_n_s_topocalc_core_c_topo_core); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 29, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); - if (PyDict_SetItem(__pyx_d, __pyx_n_s_c_hor1d, __pyx_t_1) < 0) __PYX_ERR(0, 28, __pyx_L1_error) + if (PyDict_SetItem(__pyx_d, __pyx_n_s_c_hor1d, __pyx_t_1) < 0) __PYX_ERR(0, 29, __pyx_L1_error) __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "topocalc/core_c/topo_core.pyx":67 + /* "topocalc/core_c/topo_core.pyx":68 * @cython.wraparound(False) * # https://github.com/cython/cython/wiki/tutorials-NumpyPointerToC * def c_hor2d(np.ndarray[double, mode="c", ndim=2] z, # <<<<<<<<<<<<<< * double spacing, - * bool forward, + * bint forward, */ - __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_8topocalc_6core_c_9topo_core_3c_hor2d, NULL, __pyx_n_s_topocalc_core_c_topo_core); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 67, __pyx_L1_error) + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_8topocalc_6core_c_9topo_core_3c_hor2d, NULL, __pyx_n_s_topocalc_core_c_topo_core); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 68, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); - if (PyDict_SetItem(__pyx_d, __pyx_n_s_c_hor2d, __pyx_t_1) < 0) __PYX_ERR(0, 67, __pyx_L1_error) + if (PyDict_SetItem(__pyx_d, __pyx_n_s_c_hor2d, __pyx_t_1) < 0) __PYX_ERR(0, 68, __pyx_L1_error) __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; /* "topocalc/core_c/topo_core.pyx":1 * # cython: embedsignature=True # <<<<<<<<<<<<<< + * # distutils: language=3 * """ - * C implementation of some radiation functions */ __pyx_t_1 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); diff --git a/topocalc/core_c/topo_core.h b/topocalc/core_c/topo_core.h index 06b9f67..6915db5 100644 --- a/topocalc/core_c/topo_core.h +++ b/topocalc/core_c/topo_core.h @@ -4,4 +4,4 @@ int hor1f(int n, double *z, int *h); int hor1b(int n, double *z, int *h); void horval(int n, double *z, double delta, int *h, double *hcos); -void hor2d(int n, int m, double *z, double delta, bool forward, int *h, double *hcos); \ No newline at end of file +void hor2d(int n, int m, double *z, double delta, bool forward, double *hcos); \ No newline at end of file diff --git a/topocalc/core_c/topo_core.pyx b/topocalc/core_c/topo_core.pyx index fc4824c..e211026 100644 --- a/topocalc/core_c/topo_core.pyx +++ b/topocalc/core_c/topo_core.pyx @@ -1,4 +1,5 @@ # cython: embedsignature=True +# distutils: language=3 """ C implementation of some radiation functions """ @@ -9,7 +10,7 @@ import numpy as np cimport numpy as np import ctypes # from cpython cimport bool -from libcpp cimport bool +# from libcpp cimport bool # Numpy must be initialized. When using numpy from C or Cython you must @@ -20,14 +21,14 @@ cdef extern from "topo_core.h": void hor1f(int n, double *z, int *h); void hor1b(int n, double *z, int *h); void horval(int n, double *z, double delta, int *h, double *hcos); - void hor2d(int n, int m, double *z, double delta, bool forward, int *h, double *hcos); + void hor2d(int n, int m, double *z, double delta, bint forward, double *hcos); @cython.boundscheck(False) @cython.wraparound(False) # https://github.com/cython/cython/wiki/tutorials-NumpyPointerToC def c_hor1d(np.ndarray[double, mode="c", ndim=1] z, double spacing, - bool forward, + bint forward, np.ndarray[double, mode="c", ndim=1] hcos): """ Call the function hor1f in hor1f.c @@ -66,7 +67,7 @@ def c_hor1d(np.ndarray[double, mode="c", ndim=1] z, # https://github.com/cython/cython/wiki/tutorials-NumpyPointerToC def c_hor2d(np.ndarray[double, mode="c", ndim=2] z, double spacing, - bool forward, + bint forward, np.ndarray[double, mode="c", ndim=2] hcos): """ Call the function hor1f in hor1f.c @@ -79,21 +80,16 @@ def c_hor2d(np.ndarray[double, mode="c", ndim=2] z, hcos: cosine angle of horizon array changed in place """ - cdef int nrows - cdef int ncols - nrows = z.shape[0] - ncols = z.shape[1] + cdef int nrows = z.shape[0] + cdef int ncols = z.shape[1] + cdef double cspacing = spacing - cdef bool fwd - fwd = forward + cdef bint fwd = forward # convert the z array to C cdef np.ndarray[double, mode="c", ndim=2] z_arr z_arr = np.ascontiguousarray(z, dtype=np.float64) - # integer array for horizon index - cdef np.ndarray[int, ndim=2, mode='c'] h = np.empty((nrows,ncols), dtype = ctypes.c_int) - # call the hor2d C function - hor2d(nrows, ncols, &z_arr[0,0], spacing, fwd, &h[0,0], &hcos[0,0]) + hor2d(nrows, ncols, &z_arr[0,0], cspacing, fwd, &hcos[0,0]) diff --git a/topocalc/horizon.py b/topocalc/horizon.py index c403864..4fc9e28 100644 --- a/topocalc/horizon.py +++ b/topocalc/horizon.py @@ -159,6 +159,7 @@ def hor2d_c(z, spacing, fwd=True): z = np.ascontiguousarray(z) h = np.zeros_like(z) + topo_core.c_hor2d(z, spacing, fwd, h) # if not fwd: diff --git a/topocalc/tests/test_viewf.py b/topocalc/tests/test_viewf.py index f99457e..a8528de 100644 --- a/topocalc/tests/test_viewf.py +++ b/topocalc/tests/test_viewf.py @@ -1,6 +1,7 @@ #!/usr/bin/env python import unittest +from sys import platform import numpy as np @@ -16,20 +17,37 @@ def test_theory_edge(self): dem = np.ones((50, 50)) dem[:, :25] = 100000 - svf, tvf = viewf(dem, spacing=10) + svf, tvf = viewf(dem, spacing=10, nangles=360) # The top should all be ones with 100% sky view - self.assertTrue( - np.array_equal(svf[:, :24], - np.ones_like(svf[:, :24])) - ) - - # The edge should be 50% or 0.5 svf - np.testing.assert_allclose( - svf[:, 25], - 0.5 * np.ones_like(svf[:, 25]), - atol=1e-3 - ) + # OSX seems to have some difficulty with the edge + # where linux does not. It is close to 1 but not quite + if platform == 'darwin': + np.testing.assert_allclose( + svf[:, :24], + np.ones_like(svf[:, :24]), + atol=1e-2 + ) + + # The edge should be 50% or 0.5 svf + np.testing.assert_allclose( + svf[:, 25], + 0.5 * np.ones_like(svf[:, 25]), + atol=1e-2 + ) + + else: + np.testing.assert_array_equal( + svf[:, :24], + np.ones_like(svf[:, :24]) + ) + + # The edge should be 50% or 0.5 svf + np.testing.assert_allclose( + svf[:, 25], + 0.5 * np.ones_like(svf[:, 25]), + atol=1e-3 + ) def test_viewf_errors_dem(self): """Test viewf dem errors""" @@ -39,7 +57,8 @@ def test_viewf_errors_dem(self): def test_viewf_errors_angles(self): """Test viewf nangles errors""" - self.assertRaises(ValueError, viewf, np.ones((10, 1)), 10, nangles=10) + self.assertRaises(ValueError, viewf, np.ones( + (10, 1)), 10, nangles=10) def test_viewf_errors_sin_slope(self): """Test viewf sin_slope errors""" diff --git a/tox.ini b/tox.ini index 3b49093..8fee6ad 100644 --- a/tox.ini +++ b/tox.ini @@ -1,13 +1,6 @@ [tox] envlist = py35, py36, py37, py38, flake8, coverage -[travis] -python = - 3.8: py38 - 3.7: py37 - 3.6: py36, flake8, coverage - 3.5: py35 - [testenv:flake8] basepython = python deps =