Skip to content

Commit

Permalink
Tests and issue #90
Browse files Browse the repository at this point in the history
  • Loading branch information
maroba committed Dec 21, 2024
1 parent 53f3134 commit b62dd51
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 32 deletions.
13 changes: 13 additions & 0 deletions findiff/findiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ def __init__(self, axis, order, spacing, acc):

def __call__(self, f):
self.validate_f(f)
if np.issubdtype(f.dtype, np.integer):
f = f.astype(np.float64)

npts = f.shape[self.axis]
fd = np.zeros_like(f)
num_bndry_points = len(self.center["coefficients"]) // 2
Expand Down Expand Up @@ -177,6 +180,12 @@ def __init__(self, axis, order, spacing, acc):

def __call__(self, f):
self.validate_f(f)
if np.issubdtype(f.dtype, np.integer):
f = f.astype(np.float64)

if np.issubdtype(f.dtype, np.integer):
f = f.astype(np.float64)

fd = np.zeros_like(f)
for off, coef in zip(self.coefs["offsets"], self.coefs["coefficients"]):
fd += coef * np.roll(f, -off, axis=self.axis)
Expand Down Expand Up @@ -212,7 +221,11 @@ def __init__(self, axis, order, coords, acc):
def __call__(self, y):
"""The core function to take a partial derivative on a non-uniform grid"""

if np.issubdtype(y.dtype, np.integer):
y = y.astype(np.float64)

order, dim = self.order, self.axis

yd = np.zeros_like(y)

ndims = len(y.shape)
Expand Down
26 changes: 20 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ build-backend = "setuptools.build_meta"
[project]
name = "findiff"
authors = [
{name = "Matthias Baer"},
{ name = "Matthias Baer" },
]
maintainers = [
{name = "Matthias Baer", email="matthias.r.baer@googlemail.com"},
{ name = "Matthias Baer", email = "matthias.r.baer@googlemail.com" },
]
description = "A Python package for finite difference derivatives in any number of dimensions."
readme = "README.md"
license = {text = "MIT"}
license = { text = "MIT" }
dependencies = [
"numpy",
"scipy",
Expand Down Expand Up @@ -47,6 +47,20 @@ include = ["findiff"]
[tool.setuptools.dynamic]
version = { attr = "findiff.__version__" }

[tool.pytest.ini_options]
addopts = [
"--strict-markers"
]
testpaths = "tests"
markers = [
"functional: Functional tests for stuff that the user would do",
"one_dimensional: Tests in 1D",
"periodic: Tests for periodic boundary conditions",
"invalid_args: Tests for invalid argument handling",
"default_args: Tests for default argument handling",
"grid_spec: Marker to construct grid data by fixtures"
]

[tool.coverage]
run.source_pkgs = ["findiff", "tests"]
run.branch = true
Expand Down Expand Up @@ -96,9 +110,9 @@ commands = [
[tool.ruff]
line-length = 88
lint.extend-select = [
"B", # flake8-bugbear
"I", # isort
"UP", # pyupgrade
"B", # flake8-bugbear
"I", # isort
"UP", # pyupgrade
]
extend-exclude = [
"docs/source/**/*.ipynb",
Expand Down
9 changes: 0 additions & 9 deletions pytest.ini

This file was deleted.

8 changes: 6 additions & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,18 @@ def grid_data(request):
raise ValueError("Grid data marker not defined")
shape = m.kwargs["shape"]
edges = m.kwargs["edges"]
endpoints = m.kwargs.get("endpoints", [True] * len(shape))

if len(shape) == 1:
x = np.linspace(*edges, shape[0])
x = np.linspace(*edges, shape[0], endpoint=endpoints[0])
dx = x[1] - x[0]
return x, dx

axes = tuple(
[np.linspace(edges[k][0], edges[k][1], shape[k]) for k in range(len(shape))]
[
np.linspace(edges[k][0], edges[k][1], shape[k], endpoint=endpoints[k])
for k in range(len(shape))
]
)
coords = np.meshgrid(*axes, indexing="ij")
spacings = [axes[k][1] - axes[k][0] for k in range(len(shape))]
Expand Down
21 changes: 21 additions & 0 deletions tests/test_bugs.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import numpy as np
import pytest
from numpy.testing import assert_array_almost_equal

import findiff
from findiff import FinDiff
from findiff.coefs import coefficients_non_uni


def test_findiff_should_raise_exception_when_applied_to_unevaluated_function():
Expand Down Expand Up @@ -141,3 +143,22 @@ def assert_dict_almost_equal(first, second):
assert first[k] == pytest.approx(0, abs=1.0e-8)
for k in set(second) - set(first):
assert 0 == pytest.approx(second[k], abs=1.0e-8)


class TestIssue90:

def test_reproduce_issue90(self):

x = np.array([0.0, 1.0, 1.5, 3.5, 4.0, 6.0])
f1 = np.array([1, 2, 4, 7, 11, 16])
f2 = np.sin(x)

d_dx = FinDiff(0, x, acc=2)
df_dx1 = d_dx(f1)
df_dx2 = d_dx(f2)

grad1 = np.gradient(f1, x, edge_order=2)
grad2 = np.gradient(f2, x, edge_order=2)

assert_array_almost_equal(df_dx2, grad2)
assert_array_almost_equal(df_dx1, grad1)
10 changes: 0 additions & 10 deletions tests/test_diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,6 @@
from findiff import Diff, Identity


def test_partial_d_dx_periodic():
x = np.linspace(0, 2 * np.pi, 200, endpoint=False)
dx = x[1] - x[0]
f = np.sin(x)
expected = np.cos(x)
actual = Diff(0, dx, periodic=True, acc=4)(f)

assert_array_almost_equal(expected, actual)


def test_partial_d2_dx2_matrix_periodic():
dx = 1
expected = np.array(
Expand Down
20 changes: 15 additions & 5 deletions tests/test_functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
class TestDiff_1D:

@pytest.mark.grid_spec(shape=(101,), edges=(0, 1))
def test_diff_1d(self, grid_data):
def test_diff(self, grid_data):
x, dx = grid_data

u = x**2
Expand All @@ -23,7 +23,7 @@ def test_diff_1d(self, grid_data):
assert_array_almost_equal(expected, actual)

@pytest.mark.grid_spec(shape=(101,), edges=(0, 1))
def test_diff_1d_deferred(self, grid_data):
def test_diff_deferred(self, grid_data):
x, dx = grid_data

u = x**2
Expand All @@ -35,15 +35,15 @@ def test_diff_1d_deferred(self, grid_data):

assert_array_almost_equal(expected, actual)

def test_diff_1d_deferred_called_too_early(self):
def test_diff_deferred_called_too_early(self):
u = np.zeros(10)
fd = Diff(0)
with pytest.raises(TypeError, match="Unknown axis type."):
fd(u)

@pytest.mark.default_args
@pytest.mark.grid_spec(shape=(101,), edges=(0, 1))
def test_diff_1d_defaults(self, grid_data):
def test_diff_defaults(self, grid_data):
x, dx = grid_data

u = x**2
Expand All @@ -56,10 +56,20 @@ def test_diff_1d_defaults(self, grid_data):
assert_array_almost_equal(expected, actual)

@pytest.mark.invalid_args
def test_diff_1d_invalid_args(self):
def test_diff_invalid_args(self):

with pytest.raises(ValueError, match="Dimension must be >= 0"):
Diff(-1, 1)

with pytest.raises(ValueError, match="Spacing must be > 0."):
Diff(0, -1)

@pytest.mark.periodic
@pytest.mark.grid_spec(shape=[200], edges=(0, 2 * np.pi), endpoints=[False])
def test_diff_periodic(self, grid_data):
x, dx = grid_data
f = np.sin(x)

actual = Diff(0, dx, periodic=True, acc=4)(f)

assert_array_almost_equal(np.cos(x), actual)

0 comments on commit b62dd51

Please sign in to comment.