From bffe7b46431b0eb2bd9be1809a60bb7fe41f99a5 Mon Sep 17 00:00:00 2001 From: Teschl <69400012+Teschl@users.noreply.github.com> Date: Wed, 23 Oct 2024 14:05:19 +0200 Subject: [PATCH 01/10] Get core acv branch --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2643c81..49e35d2 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,8 +8,8 @@ project(${SKBUILD_PROJECT_NAME} include(FetchContent) FetchContent_Declare( topotoolbox - GIT_REPOSITORY https://github.com/TopoToolbox/libtopotoolbox.git - GIT_TAG main + GIT_REPOSITORY https://github.com/Teschl/libtopotoolbox.git + GIT_TAG acv ) FetchContent_MakeAvailable(topotoolbox) From 50b820ed6d594274b9d33a2ec94a081a8dcd3bb1 Mon Sep 17 00:00:00 2001 From: Teschl <69400012+Teschl@users.noreply.github.com> Date: Tue, 29 Oct 2024 14:34:29 +0100 Subject: [PATCH 02/10] Add acv() --- src/lib/grid.cpp | 22 ++++++++++++++++++++++ src/topotoolbox/grid_object.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/src/lib/grid.cpp b/src/lib/grid.cpp index 79c7843..7e4cb77 100755 --- a/src/lib/grid.cpp +++ b/src/lib/grid.cpp @@ -222,6 +222,27 @@ void wrap_gradient8( gradient8(output_ptr, dem_ptr, cellsize, use_mp, dims_ptr); } + +// wrap_avc: +// Parameters: +// output: A NumPy array which will store the resulting gradient of each cell. +// dem: A NumPy array containing the digital elevation model. +// use_mp: A int which will decide if OpenMP will be used. +// dims: A tuple containing the number of rows and columns. +// +// This function requires the arrays to be in 'C' order. + +void wrap_acv( + py::array_t output, py::array_t dem, + int use_mp, std::tuple dims){ + + float *output_ptr = output.mutable_data(); + float *dem_ptr = dem.mutable_data(); + + std::array dims_array = {std::get<0>(dims), std::get<1>(dims)}; + ptrdiff_t *dims_ptr = dims_array.data(); + acv(output_ptr, dem_ptr, use_mp, dims_ptr); +} // Make wrap_funcname() function available as grid_funcname() to be used by // by functions in the pytopotoolbox package @@ -235,4 +256,5 @@ PYBIND11_MODULE(_grid, m) { m.def("flow_routing_d8_carve", &wrap_flow_routing_d8_carve); m.def("flow_routing_targets", &wrap_flow_routing_targets); m.def("gradient8", &wrap_gradient8); + m.def("acv", &wrap_acv); } diff --git a/src/topotoolbox/grid_object.py b/src/topotoolbox/grid_object.py index 6e249c7..648e62b 100755 --- a/src/topotoolbox/grid_object.py +++ b/src/topotoolbox/grid_object.py @@ -273,6 +273,40 @@ def gradient8(self, unit: str = 'tangent', multiprocessing: bool = True): return result + def acv(self, multiprocessing: bool = True) -> 'GridObject': + """ + The anisotropic coefficient of variation (ACV) describes the general + geometry of the local land surface and can be used to distinguish elongated + from oval land forms. + + Parameters + ---------- + multiprocessing : bool, optional + If True, use multiprocessing for computation. Default is True + + Returns + ------- + GridObject + GridObject containing the calculated anisotropic coefficient + of variation. + """ + + if multiprocessing: + use_mp = 1 + else: + use_mp = 0 + + # The acv() function uses arrays in order='C' instead of order='F' + dem = self.z.astype(np.float32, order='C') + output = np.zeros_like(dem) + + _grid.acv(output, dem, use_mp, self.shape) + + result = copy.copy(self) + result.z = output + + return result + def _gwdt_computecosts(self) -> np.ndarray: """ Compute the cost array used in the gradient-weighted distance From 8fa31078125f5cf90dbeafc123821d355bcc0d1e Mon Sep 17 00:00:00 2001 From: Teschl <69400012+Teschl@users.noreply.github.com> Date: Wed, 30 Oct 2024 13:22:44 +0100 Subject: [PATCH 03/10] Change GIt Tag to week 45 --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 49e35d2..72633d8 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,8 +8,8 @@ project(${SKBUILD_PROJECT_NAME} include(FetchContent) FetchContent_Declare( topotoolbox - GIT_REPOSITORY https://github.com/Teschl/libtopotoolbox.git - GIT_TAG acv + GIT_REPOSITORY https://github.com/TopoToolbox/libtopotoolbox.git + GIT_TAG 2024-W45 ) FetchContent_MakeAvailable(topotoolbox) From eaee22dbc44f7e1279fc1d0dc53b858fbfef3768 Mon Sep 17 00:00:00 2001 From: Teschl <69400012+Teschl@users.noreply.github.com> Date: Wed, 30 Oct 2024 13:23:31 +0100 Subject: [PATCH 04/10] Remove trailing spaces --- src/topotoolbox/grid_object.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/topotoolbox/grid_object.py b/src/topotoolbox/grid_object.py index 648e62b..edbb36f 100755 --- a/src/topotoolbox/grid_object.py +++ b/src/topotoolbox/grid_object.py @@ -276,7 +276,7 @@ def gradient8(self, unit: str = 'tangent', multiprocessing: bool = True): def acv(self, multiprocessing: bool = True) -> 'GridObject': """ The anisotropic coefficient of variation (ACV) describes the general - geometry of the local land surface and can be used to distinguish elongated + geometry of the local land surface and can be used to distinguish elongated from oval land forms. Parameters @@ -287,7 +287,7 @@ def acv(self, multiprocessing: bool = True) -> 'GridObject': Returns ------- GridObject - GridObject containing the calculated anisotropic coefficient + GridObject containing the calculated anisotropic coefficient of variation. """ From 970d2f9a1ef981f137078f4b238cac6166e9827b Mon Sep 17 00:00:00 2001 From: Teschl <69400012+Teschl@users.noreply.github.com> Date: Thu, 7 Nov 2024 15:52:50 +0100 Subject: [PATCH 05/10] Add wrapper guide --- docs/index.rst | 1 + docs/wrapping.ipynb | 73 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 docs/wrapping.ipynb diff --git a/docs/index.rst b/docs/index.rst index 8dac27c..3d6a85b 100755 --- a/docs/index.rst +++ b/docs/index.rst @@ -36,6 +36,7 @@ If you would like to contribute to pytopotoolbox, refer to the :doc:`_temp/CONTR Examples API Contributing <_temp/CONTRIBUTING> + Wrapping libtopotoolbox Indices and Tables ------------------ diff --git a/docs/wrapping.ipynb b/docs/wrapping.ipynb new file mode 100644 index 0000000..d877036 --- /dev/null +++ b/docs/wrapping.ipynb @@ -0,0 +1,73 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# How to wrap libtopotoolbox functions\n", + "\n", + "## Whats needs to be done to add a new function\n", + "\n", + "1. Add python wrapper\n", + "2. Add pybind11 wrapper\n", + "3. \n", + "\n", + "## What order arrays should be in\n", + "\n", + "We are using arrays in Fortran order (`order='F'`) instead of C order. That means the arrays are in column mayor order in memory instead of row mayor order. The " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "ename": "TypeError", + "evalue": "'list' object cannot be interpreted as an integer", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[2], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m array_c \u001b[38;5;241m=\u001b[39m \u001b[43mnp\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mndarray\u001b[49m\u001b[43m(\u001b[49m\u001b[43m[\u001b[49m\u001b[43m[\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m[\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m[\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m[\u001b[49m\u001b[43m]\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43morder\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mC\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2\u001b[0m array_f \u001b[38;5;241m=\u001b[39m np\u001b[38;5;241m.\u001b[39mndarray([[],[],[],[]], order\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mF\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", + "\u001b[0;31mTypeError\u001b[0m: 'list' object cannot be interpreted as an integer" + ] + } + ], + "source": [ + "array_c = np.ndarray([[1,2,3],[4,5,6],[7,8,9],[10,11,12]], order='C')\n", + "array_f = np.ndarray([[1,2,3],[4,5,6],[7,8,9],[10,11,12]], order='F')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 9066904128bf629011e7084924af9f4fca0b09b7 Mon Sep 17 00:00:00 2001 From: Teschl <69400012+Teschl@users.noreply.github.com> Date: Tue, 12 Nov 2024 15:25:17 +0100 Subject: [PATCH 06/10] Add wrapping guide to docs --- docs/index.rst | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 3d6a85b..d5aeaa3 100755 --- a/docs/index.rst +++ b/docs/index.rst @@ -25,7 +25,12 @@ For further documentation regarding the functionality of this package, check out Contributing ------------ -If you would like to contribute to pytopotoolbox, refer to the :doc:`_temp/CONTRIBUTING`. +If you would like to contribute to pytopotoolbox, refer to the :doc:`CONTRIBUTING.md <_temp/CONTRIBUTING>`. + +Wrapping libtopotoolbox functions +--------------------------------- + +Refer to :doc:`wrapping libtopotoolbox functions` for a quick guide on how to create new functions. .. toctree:: :maxdepth: 1 @@ -36,7 +41,7 @@ If you would like to contribute to pytopotoolbox, refer to the :doc:`_temp/CONTR Examples API Contributing <_temp/CONTRIBUTING> - Wrapping libtopotoolbox + Wrapping libtopotoolbox functions Indices and Tables ------------------ From e2d2f5d85023ca8a15d4537013f3634a41c0796d Mon Sep 17 00:00:00 2001 From: Teschl <69400012+Teschl@users.noreply.github.com> Date: Tue, 12 Nov 2024 15:25:35 +0100 Subject: [PATCH 07/10] Fix markdown support for docs --- docs/conf.py | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/conf.py b/docs/conf.py index 741d77d..0938545 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -13,6 +13,7 @@ 'sphinx.ext.viewcode', 'sphinx.ext.todo', 'nbsphinx', + 'myst_parser', ] project = 'TopoToolbox' From 43e52b887d4e758392761b82b28208ea89179b66 Mon Sep 17 00:00:00 2001 From: Teschl <69400012+Teschl@users.noreply.github.com> Date: Tue, 12 Nov 2024 16:01:51 +0100 Subject: [PATCH 08/10] Add wrapping guide to docs --- docs/wrapping.ipynb | 184 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 161 insertions(+), 23 deletions(-) diff --git a/docs/wrapping.ipynb b/docs/wrapping.ipynb index d877036..bdb369a 100644 --- a/docs/wrapping.ipynb +++ b/docs/wrapping.ipynb @@ -4,48 +4,186 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# How to wrap libtopotoolbox functions\n", + "# How to Wrap `libtopotoolbox` Functions for `pytopotoolbox`\n", "\n", - "## Whats needs to be done to add a new function\n", + "## What Needs to Be Done to Add a New Function\n", "\n", - "1. Add python wrapper\n", - "2. Add pybind11 wrapper\n", - "3. \n", + "You will need to modify content in the following directories and files:\n", "\n", + "1. **src/topotoolbox/** [Refer to the section on wrapping `pybind11` functions.](#wrapping-pybind11-functions)\n", + "\n", + "2. **src/topotoolbox/__init__.py** If you added a new file for a new class, you will need to add it here so it will be automatically imported when importing `topotoolbox`.\n", + "\n", + "3. **src/lib/** [Refer to the section on wrapping `libtopotoolbox`.](#creating-a-wrapper-for-libtopotoolbox-functions-using-pybind11)\n", + "\n", + "4. **CMakeLists.txt** If you added a new class, you will need to add a link using `target_link_libraries()`, `pybind_add_module()`, and the `install` section `install()`.\n", + "\n", + "5. **docs/api.rst** To include your function in the API documentation, add it here. Since we are using recursive autosummary, if your function is part of a class, it will automatically be added if the class is added to this file. If your function is not part of a class, you will need to add it manually.\n", + "\n", + "6. **tests/** Include tests for your function here.\n", + "\n", + "7. **examples/** If you want to provide an example as documentation for your function, create a new Jupyter notebook here. You can fill the file however you see fit, but make sure to include a section title for the file by making the first line your title and underlining it with `====`.\n", + "\n", + "8. **docs/examples.rst** If you added a new example, include it in the example gallery by adding a new line: `/_temp/name_of_your_example`\n", + "\n", + "9. **docs/conf.py** If you added a new example, you can also add a thumbnail for it here under the section `nbsphinx_thumbnails`.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Creating a wrapper for libtopotoolbox functions using pybind11\n", + "\n", + "We create a separate file for all wrappers of one class. The `src/lib/grip.cpp` will contain all wrappers for the GridObject class for example. Each file has to include the following code:\n", + "\n", + "```cpp\n", + "extern \"C\" {\n", + " #include \n", + "}\n", + "\n", + "#include \n", + "#include \n", + "\n", + "namespace py = pybind11;\n", + "```\n", + "\n", + "Create a wrapper by creating a new function, we name them void wrap_func_name() to differentiate them from the libtopotoolbox functions. In this function you create pointers for your arrays and pass them to the function you are wrapping void func_name(). We are always editing our data in place, to all function return void.\n", + "\n", + "```cpp\n", + "void wrap_func_name(py::array_t dem, std::tuple dims){\n", + " float *dem_ptr = output.mutable_data();\n", + " std::array dims_array = {std::get<0>(dims), std::get<1>(dims)};\n", + " ptrdiff_t *dims_ptr = dims_array.data();\n", + " func_name(dem_ptr, dims_ptr);\n", + "}\n", + "```\n", + "\n", + "At the end of the file we will include the function to the Pybind11 module. The module will be named after the class it's used for. For the `grid.cpp` file the module is named `_grid`.\n", + "\n", + "```cpp\n", + "PYBIND11_MODULE(_module_name_, m) {\n", + " m.def(\"function_name\", &wrap_function_name);\n", + "}\n", + "```\n", + "\n", + "When the topotoolbox package is beeing build these modules will be compiled and made available for the python wrappers." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Wrapping pybind11 functions\n", + "\n", + "Since the the pybind11 functions will only be available during the build process we always disable pylint errors when importing them into our python files. We do this so the code passes the pylint test we run in our .github/workflows and so that your IDE doesn't yell at you.\n", + "\n", + "```python\n", + "# pylint: disable=no-name-in-module\n", + "from . import _module_name # type: ignore\n", + "```\n", + "\n", + "When creating your python function you call the pybind11 wrapper like so:\n", + "\n", + "```python\n", + "_module_name.function_name()\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "## What order arrays should be in\n", "\n", - "We are using arrays in Fortran order (`order='F'`) instead of C order. That means the arrays are in column mayor order in memory instead of row mayor order. The " + "Because Matlab is using column mayor order arrays, the libtopotoolbox originally used them as well. While thats not forced for new functions anymore, the shape (dims) we pass along with our matrix has to match the matrix. How the np.ndarray.shape is layed out, it works better just to use the column mayor order instead of having two different dims for each array (one to pass to C and one to use in python)\n", + "\n", + "The following example will showcase what this means in practice." ] }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "import numpy as np" + "import numpy as np\n", + "\n", + "# creating the same array, once in C and once in F order\n", + "array_c = np.array([[1,2,3],[4,5,6],[7,8,9],[10,11,12]], order='C')\n", + "array_f = np.array([[1,2,3],[4,5,6],[7,8,9],[10,11,12]], order='F')\n", + "dims = array_f.shape\n", + "\n", + "print(f\"Both arrays will look like this when looking at them:\\n{array_c}\")\n", + "\n", + "array_c = array_c.flatten(order='C')\n", + "array_f = array_f.flatten(order='F')\n", + "print(\"\\nBut when the arrays are passed to the C function, they will be\\n\"\n", + " \"flattened into on dimension like this:\"\n", + " f\"\\nC order: {array_c}\\nF order: {array_f}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As you can see, the Column mayor order (F), will result in each column being listed after one another instead of each row being listed after another (C).\n", + "\n", + "The first element of dims[2] (generated from the np.ndarray,shape) should be the size of the dimension that changes fastest as you scan through memory, e.g. rows for column-major/'F' order and cols for row-major/'C' order.\n", + "\n", + "In our example for F order you can see that 1, 4 and 7 are next to each other on memory. They are all in different rows. Therefor rows change faster than cols so the value denoting how many rows there are should be first in the dims[2]." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, - "outputs": [ - { - "ename": "TypeError", - "evalue": "'list' object cannot be interpreted as an integer", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[2], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m array_c \u001b[38;5;241m=\u001b[39m \u001b[43mnp\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mndarray\u001b[49m\u001b[43m(\u001b[49m\u001b[43m[\u001b[49m\u001b[43m[\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m[\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m[\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m[\u001b[49m\u001b[43m]\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43morder\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mC\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2\u001b[0m array_f \u001b[38;5;241m=\u001b[39m np\u001b[38;5;241m.\u001b[39mndarray([[],[],[],[]], order\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mF\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", - "\u001b[0;31mTypeError\u001b[0m: 'list' object cannot be interpreted as an integer" - ] - } - ], + "outputs": [], + "source": [ + "print(dims)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In our example there are 4 rows and 3 columns. Since the rows are first in dims we should pass this array to the C code in F order.\n", + "\n", + "When looping trough the array we try to access the elements after another that are actually located next to each other in memory. Therefor the outer for loop should loop over dims[1] the inner over dims[0]." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for j in range(dims[1]):\n", + " for i in range(dims[0]):\n", + " location = j * dims[0] + i\n", + " print(array_f[location], end=', ')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To access neighboring cells in the same col we just need to add or subtract 1 from the index. For neighboring cells in same row we need to either add or subtract the length of one row (dims[0]) from the index. \n", + "\n", + "In our example the neighbors of 5 in memory are 2 and 8. The neigbors on the same row are 4 and 6." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ - "array_c = np.ndarray([[1,2,3],[4,5,6],[7,8,9],[10,11,12]], order='C')\n", - "array_f = np.ndarray([[1,2,3],[4,5,6],[7,8,9],[10,11,12]], order='F')" + "print(f\"array[5] = {array_f[5]}\")\n", + "print(f\"above = {array_f[5-1]}\")\n", + "print(f\"below = {array_f[5+1]}\")\n", + "print(f\"left = {array_f[5-dims[0]]}\")\n", + "print(f\"right = {array_f[5+dims[0]]}\")" ] } ], From 82a5ab236772b38ee1025948fd96d0e093af9413 Mon Sep 17 00:00:00 2001 From: Teschl <69400012+Teschl@users.noreply.github.com> Date: Tue, 12 Nov 2024 16:02:34 +0100 Subject: [PATCH 09/10] Change acv to F order --- src/topotoolbox/grid_object.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/topotoolbox/grid_object.py b/src/topotoolbox/grid_object.py index edbb36f..c556fa1 100755 --- a/src/topotoolbox/grid_object.py +++ b/src/topotoolbox/grid_object.py @@ -296,8 +296,7 @@ def acv(self, multiprocessing: bool = True) -> 'GridObject': else: use_mp = 0 - # The acv() function uses arrays in order='C' instead of order='F' - dem = self.z.astype(np.float32, order='C') + dem = self.z.astype(np.float32, order='F') output = np.zeros_like(dem) _grid.acv(output, dem, use_mp, self.shape) From db15adf4454d3066825309eeae3ceb724b4f6ef0 Mon Sep 17 00:00:00 2001 From: Teschl <69400012+Teschl@users.noreply.github.com> Date: Wed, 13 Nov 2024 13:53:32 +0100 Subject: [PATCH 10/10] Fix spelling --- docs/wrapping.ipynb | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/docs/wrapping.ipynb b/docs/wrapping.ipynb index bdb369a..fe5f9c5 100644 --- a/docs/wrapping.ipynb +++ b/docs/wrapping.ipynb @@ -4,17 +4,17 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# How to Wrap `libtopotoolbox` Functions for `pytopotoolbox`\n", + "# How to Wrap `libtopotoolbox` functions with the `pytopotoolbox`\n", "\n", "## What Needs to Be Done to Add a New Function\n", "\n", "You will need to modify content in the following directories and files:\n", "\n", - "1. **src/topotoolbox/** [Refer to the section on wrapping `pybind11` functions.](#wrapping-pybind11-functions)\n", + "1. **src/topotoolbox/** [Refer to the section on wrapping pybind11 functions.](#wrapping-pybind11-functions)\n", "\n", "2. **src/topotoolbox/__init__.py** If you added a new file for a new class, you will need to add it here so it will be automatically imported when importing `topotoolbox`.\n", "\n", - "3. **src/lib/** [Refer to the section on wrapping `libtopotoolbox`.](#creating-a-wrapper-for-libtopotoolbox-functions-using-pybind11)\n", + "3. **src/lib/** [Refer to the section on wrapping libtopotoolbox.](#creating-a-wrapper-for-libtopotoolbox-functions-using-pybind11)\n", "\n", "4. **CMakeLists.txt** If you added a new class, you will need to add a link using `target_link_libraries()`, `pybind_add_module()`, and the `install` section `install()`.\n", "\n", @@ -96,7 +96,7 @@ "source": [ "## What order arrays should be in\n", "\n", - "Because Matlab is using column mayor order arrays, the libtopotoolbox originally used them as well. While thats not forced for new functions anymore, the shape (dims) we pass along with our matrix has to match the matrix. How the np.ndarray.shape is layed out, it works better just to use the column mayor order instead of having two different dims for each array (one to pass to C and one to use in python)\n", + "Because Matlab is using column major order arrays, the libtopotoolbox originally used them as well. While thats not forced for new functions anymore, the shape (dims) we pass along with our matrix has to match the matrix. How the np.ndarray.shape is layed out, it works better just to use the column major order instead of having two different dims for each array (one to pass to C and one to use in python)\n", "\n", "The following example will showcase what this means in practice." ] @@ -127,7 +127,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "As you can see, the Column mayor order (F), will result in each column being listed after one another instead of each row being listed after another (C).\n", + "As you can see, the Column major order (F), will result in each column being listed after one another instead of each row being listed after another (C).\n", "\n", "The first element of dims[2] (generated from the np.ndarray,shape) should be the size of the dimension that changes fastest as you scan through memory, e.g. rows for column-major/'F' order and cols for row-major/'C' order.\n", "\n", @@ -185,6 +185,25 @@ "print(f\"left = {array_f[5-dims[0]]}\")\n", "print(f\"right = {array_f[5+dims[0]]}\")" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Alternative way to loop through the array:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for index in range(dims[0] * dims[1]):\n", + " col = index // dims[0] \n", + " row = index % dims[0] \n", + " print(f\"i: {index}, row: {row}, col: {col}, array[i] = {array_f[index]}\")" + ] } ], "metadata": {