Skip to content

Commit 84c731c

Browse files
committed
TL: added derivation matrix for LagrangeApproximation + bump version to 0.1.14
1 parent e40692b commit 84c731c

File tree

4 files changed

+59
-7
lines changed

4 files changed

+59
-7
lines changed

CITATION.cff

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ authors:
1616
orcid: https://orcid.org/0000-0002-3879-1210
1717
affiliation: "Jülich Supercomputing Centre, Forschungszentrum Jülich GmbH, 52425 Jülich, Germany"
1818

19-
version: 0.1.13
19+
version: 0.1.14
2020
doi: 10.5281/zenodo.11956479
21-
date-released: 2024-11-13
21+
date-released: 2024-11-29
2222
keywords:
2323
- "time integration"
2424
- "spectral deferred corrections"

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "qmat"
7-
version = "0.1.13"
7+
version = "0.1.14"
88
description = "Generation of Q-coefficients for Spectral Deferred Corrections (and other time-integration methods ...)"
99
dependencies = [
1010
"numpy",

qmat/lagrange.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,3 +324,40 @@ def getIntegrationMatrix(self, intervals, numQuad='FEJER'):
324324
PInter = integrand.sum(axis=-1).T
325325

326326
return PInter
327+
328+
def getDerivationMatrix(self):
329+
r"""
330+
Generate the first order derivation matrix :math:`D^{(1)}` based on the
331+
Lagrange interpolant, such that
332+
333+
.. math::
334+
D^{(1)} u \simeq \frac{du}{dx}
335+
336+
on the interpolation points. The formula is :
337+
338+
.. math::
339+
D^{(1)}_{ij} = \frac{w_j/w_i}{x_i-x_j}
340+
341+
for :math:`i \neq j` and
342+
343+
.. math::
344+
D^{(1)}_{jj} = -\sum_{i \neq j} D^{(1)}_{ij}`
345+
346+
Returns
347+
-------
348+
D1 : np.2darray
349+
Derivation matrix.
350+
"""
351+
w = self.weights
352+
x = self.points
353+
354+
with np.errstate(divide='ignore'):
355+
iDiff = 1 / (x[:, None] - x[None, :])
356+
iDiff[np.isinf(iDiff)] = 0
357+
358+
base = w[None, :]/w[:, None]
359+
base *= iDiff
360+
361+
D1 = base
362+
np.fill_diagonal(D1, -D1.sum(axis=-1))
363+
return D1

tests/test_2_lagrange.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def testAsymptoticWeightsSTABLE(pType, scaleRef):
4949
def testInterpolation(nNodes, weightComputation):
5050
nodes = np.sort(np.random.rand(nNodes))
5151
approx = LagrangeApproximation(nodes, weightComputation=weightComputation)
52-
52+
5353
times = np.random.rand(nNodes*2)
5454
P = approx.getInterpolationMatrix(times)
5555

@@ -66,7 +66,7 @@ def testEvaluation(nNodes, weightComputation):
6666
times = np.random.rand(nNodes*2)
6767
polyCoeffs = np.random.rand(nNodes)
6868
polyValues = np.polyval(polyCoeffs, nodes)
69-
69+
7070
approx = LagrangeApproximation(nodes, weightComputation=weightComputation, fValues=polyValues)
7171
P = approx.getInterpolationMatrix(times)
7272
refEvals = P @ polyValues
@@ -76,7 +76,7 @@ def testEvaluation(nNodes, weightComputation):
7676

7777
polyEvals = approx(t=times)
7878
assert np.allclose(polyEvals, refEvals)
79-
79+
8080

8181
@pytest.mark.parametrize("numQuad", ["LEGENDRE_NUMPY", "LEGENDRE_SCIPY", "FEJER"])
8282
@pytest.mark.parametrize("weightComputation", ["AUTO", "FAST", "STABLE", "CHEBFUN"])
@@ -92,4 +92,19 @@ def testIntegration(nNodes, weightComputation, numQuad):
9292
polyNodes = np.polyval(polyCoeffs, nodes)
9393
polyInteg = np.polyval(np.polyint(polyCoeffs), times) - np.polyval(np.polyint(polyCoeffs), 0)
9494

95-
assert np.allclose(polyInteg, P @ polyNodes)
95+
assert np.allclose(polyInteg, P @ polyNodes)
96+
97+
98+
@pytest.mark.parametrize("weightComputation", ["AUTO", "FAST", "STABLE", "CHEBFUN"])
99+
@pytest.mark.parametrize("nNodes", nNodeTests)
100+
def testDerivation(nNodes, weightComputation):
101+
nodes = np.sort(np.random.rand(nNodes))
102+
approx = LagrangeApproximation(nodes, weightComputation=weightComputation)
103+
104+
D = approx.getDerivationMatrix()
105+
106+
polyCoeffs = np.random.rand(nNodes)
107+
polyNodes = np.polyval(polyCoeffs, nodes)
108+
polyDeriv = np.polyval(np.polyder(polyCoeffs), nodes)
109+
110+
assert np.allclose(polyDeriv, D @ polyNodes)

0 commit comments

Comments
 (0)