From bc5f6ef625bae8f401a8668425754caf3e9f2ecd Mon Sep 17 00:00:00 2001
From: Hagen Wierstorf <hwierstorf@audeering.com>
Date: Mon, 16 Sep 2024 16:22:34 +0200
Subject: [PATCH 01/11] Replace Python 3.6, 3.7 with 3.9, 3.10

---
 .github/workflows/test.yml | 6 +++---
 setup.py                   | 5 +++--
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 22d7f47..d8c6554 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -9,12 +9,12 @@ jobs:
     strategy:
       matrix:
         os: [ubuntu-latest, macOS-latest, windows-latest]
-        python-version: [3.6, 3.7, 3.8]
+        python-version: [3.8, 3.9, 3.10]
 
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v4
     - name: Set up Python ${{ matrix.python-version }}
-      uses: actions/setup-python@v2
+      uses: actions/setup-python@v5
       with:
         python-version: ${{ matrix.python-version }}
     - name: Prepare Ubuntu
diff --git a/setup.py b/setup.py
index 9a7d870..94e28da 100644
--- a/setup.py
+++ b/setup.py
@@ -31,8 +31,9 @@
         "Operating System :: OS Independent",
         "Programming Language :: Python",
         "Programming Language :: Python :: 3",
-        "Programming Language :: Python :: 3.6",
-        "Programming Language :: Python :: 3.7",
+        "Programming Language :: Python :: 3.8",
+        "Programming Language :: Python :: 3.9",
+        "Programming Language :: Python :: 3.10",
         "Programming Language :: Python :: 3 :: Only",
         "Topic :: Scientific/Engineering",
     ],

From 688658e7fffcc6d12fa9ce5121beae6b5100f3ab Mon Sep 17 00:00:00 2001
From: Hagen Wierstorf <hwierstorf@audeering.com>
Date: Mon, 16 Sep 2024 16:25:21 +0200
Subject: [PATCH 02/11] Fix definition of Python version

---
 .github/workflows/test.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index d8c6554..cbea57e 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -9,7 +9,7 @@ jobs:
     strategy:
       matrix:
         os: [ubuntu-latest, macOS-latest, windows-latest]
-        python-version: [3.8, 3.9, 3.10]
+        python-version: ['3.8', '3.9', '3.10']
 
     steps:
     - uses: actions/checkout@v4

From 01b2acb6f4e3d02123c579e9bd4da5558d22fee3 Mon Sep 17 00:00:00 2001
From: Hagen Wierstorf <hwierstorf@audeering.com>
Date: Mon, 16 Sep 2024 16:31:06 +0200
Subject: [PATCH 03/11] Try to fix readthedocs config

---
 doc/readthedocs-environment.yml | 14 --------------
 readthedocs.yml                 | 12 +++++++++---
 2 files changed, 9 insertions(+), 17 deletions(-)
 delete mode 100644 doc/readthedocs-environment.yml

diff --git a/doc/readthedocs-environment.yml b/doc/readthedocs-environment.yml
deleted file mode 100644
index d5ff057..0000000
--- a/doc/readthedocs-environment.yml
+++ /dev/null
@@ -1,14 +0,0 @@
-channels:
-  - conda-forge
-dependencies:
-  - python>=3
-  - sphinx>=1.3.6
-  - sphinx_rtd_theme
-  - sphinxcontrib-bibtex
-  - numpy
-  - scipy
-  - matplotlib>=1.5
-  - ipykernel
-  - pandoc
-  - pip:
-    - nbsphinx
diff --git a/readthedocs.yml b/readthedocs.yml
index 65bb0f4..3399d82 100644
--- a/readthedocs.yml
+++ b/readthedocs.yml
@@ -1,4 +1,10 @@
-conda:
-    file: doc/readthedocs-environment.yml
+version: 2
+
+build:
+  os: ubuntu-22.04
+  tools:
+    python: 3.8
+
 python:
-    pip_install: true
+  install:
+    - requirements: doc/requirements.txt

From d66e7414853c807a7af58c34a0a460c518414e1f Mon Sep 17 00:00:00 2001
From: Hagen Wierstorf <hwierstorf@audeering.com>
Date: Mon, 16 Sep 2024 16:32:28 +0200
Subject: [PATCH 04/11] Fix Python version in readthedocs config

---
 readthedocs.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/readthedocs.yml b/readthedocs.yml
index 3399d82..360fead 100644
--- a/readthedocs.yml
+++ b/readthedocs.yml
@@ -3,7 +3,7 @@ version: 2
 build:
   os: ubuntu-22.04
   tools:
-    python: 3.8
+    python: "3.8"
 
 python:
   install:

From 59a7ed54e1e7e213be59cbd9b8e7caa029f844db Mon Sep 17 00:00:00 2001
From: Hagen Wierstorf <hwierstorf@audeering.com>
Date: Mon, 16 Sep 2024 16:36:13 +0200
Subject: [PATCH 05/11] Replace removed inner1d

---
 sfs/util.py | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/sfs/util.py b/sfs/util.py
index c15358f..de2ead5 100644
--- a/sfs/util.py
+++ b/sfs/util.py
@@ -6,7 +6,6 @@
 
 import collections
 import numpy as np
-from numpy.core.umath_tests import inner1d
 from scipy.special import spherical_jn, spherical_yn
 from . import default
 
@@ -576,7 +575,7 @@ def source_selection_point(n0, x0, xs):
     x0 = asarray_of_rows(x0)
     xs = asarray_1d(xs)
     ds = x0 - xs
-    return inner1d(ds, n0) >= default.selection_tolerance
+    return _inner1d(ds, n0) >= default.selection_tolerance
 
 
 def source_selection_line(n0, x0, xs):
@@ -598,7 +597,7 @@ def source_selection_focused(ns, x0, xs):
     xs = asarray_1d(xs)
     ns = normalize_vector(ns)
     ds = xs - x0
-    return inner1d(ns, ds) >= default.selection_tolerance
+    return _inner1d(ns, ds) >= default.selection_tolerance
 
 
 def source_selection_all(N):
@@ -646,3 +645,8 @@ def max_order_spherical_harmonics(N):
 
     """
     return int(np.sqrt(N) - 1)
+
+
+def _inner1d(arr1, arr2):
+    # https://github.com/numpy/numpy/issues/10815#issuecomment-376847774
+    return (arr1 * arr2).sum(axis=1)

From 559249ea30fec72b8b3cb6803f2d2a9be29220f2 Mon Sep 17 00:00:00 2001
From: Hagen Wierstorf <hwierstorf@audeering.com>
Date: Mon, 16 Sep 2024 16:43:12 +0200
Subject: [PATCH 06/11] Try changes from #179

---
 sfs/plot2d.py | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/sfs/plot2d.py b/sfs/plot2d.py
index efadb9c..804c365 100644
--- a/sfs/plot2d.py
+++ b/sfs/plot2d.py
@@ -18,13 +18,17 @@ def _register_cmap_clip(name, original_cmap, alpha):
         cmap = LinearSegmentedColormap.from_list(name, cdata)
     cmap.set_over([alpha * c + 1 - alpha for c in cmap(1.0)[:3]])
     cmap.set_under([alpha * c + 1 - alpha for c in cmap(0.0)[:3]])
-    _plt.cm.register_cmap(cmap=cmap)
+    _plt.colormaps.register(cmap=cmap)
 
 
 # The 'coolwarm' colormap is based on the paper
 # "Diverging Color Maps for Scientific Visualization" by Kenneth Moreland
 # http://www.sandia.gov/~kmorel/documents/ColorMaps/
-_register_cmap_clip('coolwarm_clip', 'coolwarm', 0.7)
+# already registered in MPL 3.9.0
+try:
+    _register_cmap_clip('coolwarm_clip', 'coolwarm', 0.7)
+except ImportError:
+    pass
 
 
 def _register_cmap_transparent(name, color):
@@ -36,7 +40,7 @@ def _register_cmap_transparent(name, color):
              'blue': ((0, blue, blue), (1, blue, blue)),
              'alpha': ((0, 0, 0), (1, 1, 1))}
     cmap = LinearSegmentedColormap(name, cdict)
-    _plt.cm.register_cmap(cmap=cmap)
+    _plt.colormaps.register(cmap=cmap)
 
 
 _register_cmap_transparent('blacktransparent', 'black')

From 21f25aca0be4b570fc069d556dab315de605f9ca Mon Sep 17 00:00:00 2001
From: Hagen Wierstorf <hwierstorf@audeering.com>
Date: Mon, 16 Sep 2024 16:47:06 +0200
Subject: [PATCH 07/11] Fix remaining inner1d errors

---
 sfs/fd/wfs.py | 13 ++++++-------
 sfs/td/wfs.py | 11 +++++------
 2 files changed, 11 insertions(+), 13 deletions(-)

diff --git a/sfs/fd/wfs.py b/sfs/fd/wfs.py
index 44fb2c6..840b59e 100644
--- a/sfs/fd/wfs.py
+++ b/sfs/fd/wfs.py
@@ -32,7 +32,6 @@ def plot(d, selection, secondary_source):
 
 """
 import numpy as _np
-from numpy.core.umath_tests import inner1d as _inner1d
 from scipy.special import hankel2 as _hankel2
 
 from . import secondary_source_line as _secondary_source_line
@@ -91,7 +90,7 @@ def line_2d(omega, x0, n0, xs, *, c=None):
     k = _util.wavenumber(omega, c)
     ds = x0 - xs
     r = _np.linalg.norm(ds, axis=1)
-    d = -1j/2 * k * _inner1d(ds, n0) / r * _hankel2(1, k * r)
+    d = -1j/2 * k * _util._inner1d(ds, n0) / r * _hankel2(1, k * r)
     selection = _util.source_selection_line(n0, x0, xs)
     return d, selection, _secondary_source_line(omega, c)
 
@@ -147,7 +146,7 @@ def _point(omega, x0, n0, xs, *, c=None):
     k = _util.wavenumber(omega, c)
     ds = x0 - xs
     r = _np.linalg.norm(ds, axis=1)
-    d = 1j * k * _inner1d(ds, n0) / r ** (3 / 2) * _np.exp(-1j * k * r)
+    d = 1j * k * _util._inner1d(ds, n0) / r ** (3 / 2) * _np.exp(-1j * k * r)
     selection = _util.source_selection_point(n0, x0, xs)
     return d, selection, _secondary_source_point(omega, c)
 
@@ -234,7 +233,7 @@ def point_25d(omega, x0, n0, xs, xref=[0, 0, 0], c=None, omalias=None):
         preeq_25d(omega, omalias, c) *
         _np.sqrt(8 * _np.pi) *
         _np.sqrt((r * s) / (r + s)) *
-        _inner1d(n0, ds) / s *
+        _util._inner1d(n0, ds) / s *
         _np.exp(-1j * k * s) / (4 * _np.pi * s))
     selection = _util.source_selection_point(n0, x0, xs)
     return d, selection, _secondary_source_point(omega, c)
@@ -316,7 +315,7 @@ def point_25d_legacy(omega, x0, n0, xs, xref=[0, 0, 0], c=None, omalias=None):
     r = _np.linalg.norm(ds, axis=1)
     d = (
         preeq_25d(omega, omalias, c) *
-        _np.sqrt(_np.linalg.norm(xref - x0)) * _inner1d(ds, n0) /
+        _np.sqrt(_np.linalg.norm(xref - x0)) * _util._inner1d(ds, n0) /
         r ** (3 / 2) * _np.exp(-1j * k * r))
     selection = _util.source_selection_point(n0, x0, xs)
     return d, selection, _secondary_source_point(omega, c)
@@ -499,7 +498,7 @@ def _focused(omega, x0, n0, xs, ns, *, c=None):
     k = _util.wavenumber(omega, c)
     ds = x0 - xs
     r = _np.linalg.norm(ds, axis=1)
-    d = 1j * k * _inner1d(ds, n0) / r ** (3 / 2) * _np.exp(1j * k * r)
+    d = 1j * k * _util._inner1d(ds, n0) / r ** (3 / 2) * _np.exp(1j * k * r)
     selection = _util.source_selection_focused(ns, x0, xs)
     return d, selection, _secondary_source_point(omega, c)
 
@@ -569,7 +568,7 @@ def focused_25d(omega, x0, n0, xs, ns, *, xref=[0, 0, 0], c=None,
     r = _np.linalg.norm(ds, axis=1)
     d = (
         preeq_25d(omega, omalias, c) *
-        _np.sqrt(_np.linalg.norm(xref - x0)) * _inner1d(ds, n0) /
+        _np.sqrt(_np.linalg.norm(xref - x0)) * _util._inner1d(ds, n0) /
         r ** (3 / 2) * _np.exp(1j * k * r))
     selection = _util.source_selection_focused(ns, x0, xs)
     return d, selection, _secondary_source_point(omega, c)
diff --git a/sfs/td/wfs.py b/sfs/td/wfs.py
index 3b59301..3e11208 100644
--- a/sfs/td/wfs.py
+++ b/sfs/td/wfs.py
@@ -44,7 +44,6 @@ def plot(d, selection, secondary_source, t=0):
 
 """
 import numpy as _np
-from numpy.core.umath_tests import inner1d as _inner1d
 
 from . import apply_delays as _apply_delays
 from . import secondary_source_point as _secondary_source_point
@@ -119,8 +118,8 @@ def plane_25d(x0, n0, n=[0, 1, 0], xref=[0, 0, 0], c=None):
     n = _util.normalize_vector(n)
     xref = _util.asarray_1d(xref)
     g0 = _np.sqrt(2 * _np.pi * _np.linalg.norm(xref - x0, axis=1))
-    delays = _inner1d(n, x0) / c
-    weights = 2 * g0 * _inner1d(n, n0)
+    delays = _util._inner1d(n, x0) / c
+    weights = 2 * g0 * _util._inner1d(n, n0)
     selection = _util.source_selection_plane(n0, n)
     return delays, weights, selection, _secondary_source_point(c)
 
@@ -208,7 +207,7 @@ def point_25d(x0, n0, xs, xref=[0, 0, 0], c=None):
     g0 *= _np.sqrt((x0xs_n*x0xref_n)/(x0xs_n+x0xref_n))
 
     delays = x0xs_n/c
-    weights = g0*_inner1d(x0xs, n0)
+    weights = g0 * _util._inner1d(x0xs, n0)
     selection = _util.source_selection_point(n0, x0, xs)
     return delays, weights, selection, _secondary_source_point(c)
 
@@ -296,7 +295,7 @@ def point_25d_legacy(x0, n0, xs, xref=[0, 0, 0], c=None):
     ds = x0 - xs
     r = _np.linalg.norm(ds, axis=1)
     delays = r/c
-    weights = g0 * _inner1d(ds, n0) / (2 * _np.pi * r**(3/2))
+    weights = g0 * _util._inner1d(ds, n0) / (2 * _np.pi * r**(3/2))
     selection = _util.source_selection_point(n0, x0, xs)
     return delays, weights, selection, _secondary_source_point(c)
 
@@ -379,7 +378,7 @@ def focused_25d(x0, n0, xs, ns, xref=[0, 0, 0], c=None):
     g0 = _np.sqrt(_np.linalg.norm(xref - x0, axis=1)
                   / (_np.linalg.norm(xref - x0, axis=1) + r))
     delays = -r/c
-    weights = g0 * _inner1d(ds, n0) / (2 * _np.pi * r**(3/2))
+    weights = g0 * _util._inner1d(ds, n0) / (2 * _np.pi * r**(3/2))
     selection = _util.source_selection_focused(ns, x0, xs)
     return delays, weights, selection, _secondary_source_point(c)
 

From 0edc08562565365afe339b5e5485c5b7f97c22e7 Mon Sep 17 00:00:00 2001
From: Hagen Wierstorf <hwierstorf@audeering.com>
Date: Mon, 16 Sep 2024 16:50:35 +0200
Subject: [PATCH 08/11] Fix ptp() error

---
 sfs/plot2d.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sfs/plot2d.py b/sfs/plot2d.py
index 804c365..47f41a5 100644
--- a/sfs/plot2d.py
+++ b/sfs/plot2d.py
@@ -289,8 +289,8 @@ def amplitude(p, grid, *, xnorm=None, cmap='coolwarm_clip',
     elif plotting_plane == 'yz':
         x, y = grid[[1, 2]]
 
-    dx = 0.5 * x.ptp() / p.shape[0]
-    dy = 0.5 * y.ptp() / p.shape[1]
+    dx = 0.5 * np.ptp(x) / p.shape[0]
+    dy = 0.5 * np.ptp(y) / p.shape[1]
 
     if ax is None:
         ax = _plt.gca()

From 8a9ec73fa996085378cf727e03ea88fdc311f21e Mon Sep 17 00:00:00 2001
From: Hagen Wierstorf <hwierstorf@audeering.com>
Date: Mon, 16 Sep 2024 16:54:27 +0200
Subject: [PATCH 09/11] Don't limit numpy version

---
 setup.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/setup.py b/setup.py
index 94e28da..e0f0188 100644
--- a/setup.py
+++ b/setup.py
@@ -13,7 +13,7 @@
     version=__version__,
     packages=find_packages(),
     install_requires=[
-        'numpy!=1.11.0',  # https://github.com/sfstoolbox/sfs-python/issues/11
+        'numpy',
         'scipy',
     ],
     author="SFS Toolbox Developers",

From edc1a614101a45ce19c094133c693bcb4ec6d180 Mon Sep 17 00:00:00 2001
From: Hagen Wierstorf <hwierstorf@audeering.com>
Date: Mon, 16 Sep 2024 16:55:35 +0200
Subject: [PATCH 10/11] Fix _np import

---
 sfs/plot2d.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sfs/plot2d.py b/sfs/plot2d.py
index 47f41a5..63f6996 100644
--- a/sfs/plot2d.py
+++ b/sfs/plot2d.py
@@ -289,8 +289,8 @@ def amplitude(p, grid, *, xnorm=None, cmap='coolwarm_clip',
     elif plotting_plane == 'yz':
         x, y = grid[[1, 2]]
 
-    dx = 0.5 * np.ptp(x) / p.shape[0]
-    dy = 0.5 * np.ptp(y) / p.shape[1]
+    dx = 0.5 * _np.ptp(x) / p.shape[0]
+    dy = 0.5 * _np.ptp(y) / p.shape[1]
 
     if ax is None:
         ax = _plt.gca()

From b503c13844b49946cf47d029ccfbe1a4f27f13d3 Mon Sep 17 00:00:00 2001
From: Hagen Wierstorf <hwierstorf@audeering.com>
Date: Mon, 16 Sep 2024 16:58:17 +0200
Subject: [PATCH 11/11] Try to fix readthedocs config

---
 readthedocs.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/readthedocs.yml b/readthedocs.yml
index 360fead..7ff6f6a 100644
--- a/readthedocs.yml
+++ b/readthedocs.yml
@@ -7,4 +7,5 @@ build:
 
 python:
   install:
+    - requirements: requirements.txt
     - requirements: doc/requirements.txt