@@ -116,8 +116,11 @@ class LagrangeApproximation(object):
116
116
n : int (property)
117
117
The number of points
118
118
119
+ References
120
+ ----------
119
121
.. [1] Berrut, J. P., & Trefethen, L. N. (2004).
120
- "Barycentric Lagrange interpolation." SIAM review, 46(3), 501-517.
122
+ "Barycentric Lagrange interpolation." SIAM review, 46(3), 501-517.
123
+ URL: https://doi.org/10.1137/S0036144502417715
121
124
"""
122
125
123
126
def __init__ (self , points , weightComputation = 'AUTO' , scaleWeights = False , scaleRef = 'MAX' , fValues = None ):
@@ -325,10 +328,11 @@ def getIntegrationMatrix(self, intervals, numQuad='FEJER'):
325
328
326
329
return PInter
327
330
328
- def getDerivationMatrix (self ):
331
+ def getDerivationMatrix (self , order = 1 ):
329
332
r"""
330
- Generate the first order derivation matrix :math:`D^{(1)}` based on the
331
- Lagrange interpolant, such that
333
+ Generate derivation matrix of first or second order (or both) based on
334
+ the Lagrange interpolant.
335
+ The first order differentiation matrix :math:`D^{(1)}` approximates
332
336
333
337
.. math::
334
338
D^{(1)} u \simeq \frac{du}{dx}
@@ -343,11 +347,48 @@ def getDerivationMatrix(self):
343
347
.. math::
344
348
D^{(1)}_{jj} = -\sum_{i \neq j} D^{(1)}_{ij}`
345
349
350
+ The second order differentiation matrix :math:`D^{(2)}` approximates
351
+
352
+ .. math::
353
+ D^{(2)} u \simeq \frac{d^2u}{dx^2}
354
+
355
+ on the interpolation points. The formula is :
356
+
357
+ .. math::
358
+ D^{(1)}_{ij} = -2\frac{w_j/w_i}{x_i-x_j}\left[
359
+ \frac{1}{x_i-x_j} + \sum_{k \neq i}\frac{w_k/w_i}{x_i-x_k}
360
+ \right]
361
+
362
+ for :math:`i \neq j` and
363
+
364
+ .. math::
365
+ D^{(2)}_{jj} = -\sum_{i \neq j} D^{(2)}_{ij}`
366
+
367
+ ⚠️ If you want a derivation matrix with many points (~1000 or more),
368
+ favor the use of weightComputation="STABLE" when initializing
369
+ the LagrangeApproximation object. If not, some (very small) weights
370
+ could be approximated by zeros, which would make the computation
371
+ of the derivation matrices fail ...
372
+
373
+ Note
374
+ ----
375
+ There is a typo in the formula for :math:`D^{(2)}` given in the paper
376
+ of Berrut and Trefethen. The formula above is the correct one.
377
+
378
+ Parameters
379
+ ----------
380
+ order : int or str, optional
381
+ The order of the derivation matrix, use "ALL" to retrieve both.
382
+ The default is 1.
383
+
346
384
Returns
347
385
-------
348
- D1 : np.2darray
349
- Derivation matrix.
386
+ D : np.2darray or tuple of np.2darray
387
+ Derivation matrix. If order="ALL", return a tuple containing all
388
+ derivations matrix in increasing derivation order.
350
389
"""
390
+ if order not in [1 , 2 , "ALL" ]:
391
+ raise NotImplementedError (f"order={ order } " )
351
392
w = self .weights
352
393
x = self .points
353
394
@@ -358,6 +399,17 @@ def getDerivationMatrix(self):
358
399
base = w [None , :]/ w [:, None ]
359
400
base *= iDiff
360
401
361
- D1 = base
362
- np .fill_diagonal (D1 , - D1 .sum (axis = - 1 ))
363
- return D1
402
+ if order in [1 , "ALL" ]:
403
+ D1 = base .copy ()
404
+ np .fill_diagonal (D1 , - D1 .sum (axis = - 1 ))
405
+ if order in [2 , "ALL" ]:
406
+ D2 = - 2 * base
407
+ D2 *= iDiff + base .sum (axis = - 1 )[:, None ]
408
+ np .fill_diagonal (D2 , - D2 .sum (axis = - 1 ))
409
+
410
+ if order == 1 :
411
+ return D1
412
+ elif order == 2 :
413
+ return D2
414
+ else :
415
+ return D1 , D2
0 commit comments