예제 #1
0
def test_finite_diff_weights():

    d = finite_diff_weights(1, [5, 6, 7], 5)
    assert d[1][2] == [Rational(-3, 2), 2, Rational(-1, 2)]

    # Table 1, p. 702 in doi:10.1090/S0025-5718-1988-0935077-0
    # --------------------------------------------------------
    xl = [0, 1, -1, 2, -2, 3, -3, 4, -4]

    # d holds all coefficients
    d = finite_diff_weights(4, xl, S.Zero)

    # Zeroeth derivative
    for i in range(5):
        assert d[0][i] == [S.One] + [S.Zero] * 8

    # First derivative
    assert d[1][0] == [S.Zero] * 9
    assert d[1][2] == [S.Zero, S.Half, Rational(-1, 2)] + [S.Zero] * 6
    assert d[1][4] == [
        S.Zero,
        Rational(2, 3),
        Rational(-2, 3),
        Rational(-1, 12),
        Rational(1, 12)
    ] + [S.Zero] * 4
    assert d[1][6] == [
        S.Zero,
        Rational(3, 4),
        Rational(-3, 4),
        Rational(-3, 20),
        Rational(3, 20),
        Rational(1, 60),
        Rational(-1, 60)
    ] + [S.Zero] * 2
    assert d[1][8] == [
        S.Zero,
        Rational(4, 5),
        Rational(-4, 5),
        Rational(-1, 5),
        Rational(1, 5),
        Rational(4, 105),
        Rational(-4, 105),
        Rational(-1, 280),
        Rational(1, 280)
    ]

    # Second derivative
    for i in range(2):
        assert d[2][i] == [S.Zero] * 9
    assert d[2][2] == [-S(2), S.One, S.One] + [S.Zero] * 6
    assert d[2][4] == [
        Rational(-5, 2),
        Rational(4, 3),
        Rational(4, 3),
        Rational(-1, 12),
        Rational(-1, 12)
    ] + [S.Zero] * 4
    assert d[2][6] == [
        Rational(-49, 18),
        Rational(3, 2),
        Rational(3, 2),
        Rational(-3, 20),
        Rational(-3, 20),
        Rational(1, 90),
        Rational(1, 90)
    ] + [S.Zero] * 2
    assert d[2][8] == [
        Rational(-205, 72),
        Rational(8, 5),
        Rational(8, 5),
        Rational(-1, 5),
        Rational(-1, 5),
        Rational(8, 315),
        Rational(8, 315),
        Rational(-1, 560),
        Rational(-1, 560)
    ]

    # Third derivative
    for i in range(3):
        assert d[3][i] == [S.Zero] * 9
    assert d[3][4] == [S.Zero, -S.One, S.One, S.Half,
                       Rational(-1, 2)] + [S.Zero] * 4
    assert d[3][6] == [
        S.Zero,
        Rational(-13, 8),
        Rational(13, 8), S.One, -S.One,
        Rational(-1, 8),
        Rational(1, 8)
    ] + [S.Zero] * 2
    assert d[3][8] == [
        S.Zero,
        Rational(-61, 30),
        Rational(61, 30),
        Rational(169, 120),
        Rational(-169, 120),
        Rational(-3, 10),
        Rational(3, 10),
        Rational(7, 240),
        Rational(-7, 240)
    ]

    # Fourth derivative
    for i in range(4):
        assert d[4][i] == [S.Zero] * 9
    assert d[4][4] == [S(6), -S(4), -S(4), S.One, S.One] + [S.Zero] * 4
    assert d[4][6] == [
        Rational(28, 3),
        Rational(-13, 2),
        Rational(-13, 2),
        S(2),
        S(2),
        Rational(-1, 6),
        Rational(-1, 6)
    ] + [S.Zero] * 2
    assert d[4][8] == [
        Rational(91, 8),
        Rational(-122, 15),
        Rational(-122, 15),
        Rational(169, 60),
        Rational(169, 60),
        Rational(-2, 5),
        Rational(-2, 5),
        Rational(7, 240),
        Rational(7, 240)
    ]

    # Table 2, p. 703 in doi:10.1090/S0025-5718-1988-0935077-0
    # --------------------------------------------------------
    xl = [[
        j / S(2)
        for j in list(range(-i * 2 + 1, 0, 2)) + list(range(1, i * 2 + 1, 2))
    ] for i in range(1, 5)]

    # d holds all coefficients
    d = [
        finite_diff_weights({
            0: 1,
            1: 2,
            2: 4,
            3: 4
        }[i], xl[i], 0) for i in range(4)
    ]

    # Zeroth derivative
    assert d[0][0][1] == [S.Half, S.Half]
    assert d[1][0][3] == [
        Rational(-1, 16),
        Rational(9, 16),
        Rational(9, 16),
        Rational(-1, 16)
    ]
    assert d[2][0][5] == [
        Rational(3, 256),
        Rational(-25, 256),
        Rational(75, 128),
        Rational(75, 128),
        Rational(-25, 256),
        Rational(3, 256)
    ]
    assert d[3][0][7] == [
        Rational(-5, 2048),
        Rational(49, 2048),
        Rational(-245, 2048),
        Rational(1225, 2048),
        Rational(1225, 2048),
        Rational(-245, 2048),
        Rational(49, 2048),
        Rational(-5, 2048)
    ]

    # First derivative
    assert d[0][1][1] == [-S.One, S.One]
    assert d[1][1][3] == [
        Rational(1, 24),
        Rational(-9, 8),
        Rational(9, 8),
        Rational(-1, 24)
    ]
    assert d[2][1][5] == [
        Rational(-3, 640),
        Rational(25, 384),
        Rational(-75, 64),
        Rational(75, 64),
        Rational(-25, 384),
        Rational(3, 640)
    ]
    assert d[3][1][7] == [
        Rational(5, 7168),
        Rational(-49, 5120),
        Rational(245, 3072),
        Rational(-1225, 1024),
        Rational(1225, 1024),
        Rational(-245, 3072),
        Rational(49, 5120),
        Rational(-5, 7168)
    ]

    # Reasonably the rest of the table is also correct... (testing of that
    # deemed excessive at the moment)
    raises(ValueError, lambda: finite_diff_weights(-1, [1, 2]))
    raises(ValueError, lambda: finite_diff_weights(1.2, [1, 2]))
    x = symbols('x')
    raises(ValueError, lambda: finite_diff_weights(x, [1, 2]))
예제 #2
0
def test_finite_diff_weights():

    d = finite_diff_weights(1, [5, 6, 7], 5)
    assert d[1][2] == [-S(3) / 2, 2, -S(1) / 2]

    # Table 1, p. 702 in doi:10.1090/S0025-5718-1988-0935077-0
    # --------------------------------------------------------
    xl = [0, 1, -1, 2, -2, 3, -3, 4, -4]

    # d holds all coefficients
    d = finite_diff_weights(4, xl, S(0))

    # Zeroeth derivative
    for i in range(5):
        assert d[0][i] == [S(1)] + [S(0)] * 8

    # First derivative
    assert d[1][0] == [S(0)] * 9
    assert d[1][2] == [S(0), S(1) / 2, -S(1) / 2] + [S(0)] * 6
    assert d[1][4] == [S(0), S(2) / 3, -S(2) / 3, -S(1) / 12,
                       S(1) / 12] + [S(0)] * 4
    assert d[1][6] == [
        S(0),
        S(3) / 4, -S(3) / 4, -S(3) / 20,
        S(3) / 20,
        S(1) / 60, -S(1) / 60
    ] + [S(0)] * 2
    assert d[1][8] == [
        S(0),
        S(4) / 5, -S(4) / 5, -S(1) / 5,
        S(1) / 5,
        S(4) / 105, -S(4) / 105, -S(1) / 280,
        S(1) / 280
    ]

    # Second derivative
    for i in range(2):
        assert d[2][i] == [S(0)] * 9
    assert d[2][2] == [-S(2), S(1), S(1)] + [S(0)] * 6
    assert d[2][4] == [-S(5) / 2,
                       S(4) / 3,
                       S(4) / 3, -S(1) / 12, -S(1) / 12] + [S(0)] * 4
    assert d[2][6] == [
        -S(49) / 18,
        S(3) / 2,
        S(3) / 2, -S(3) / 20, -S(3) / 20,
        S(1) / 90,
        S(1) / 90
    ] + [S(0)] * 2
    assert d[2][8] == [
        -S(205) / 72,
        S(8) / 5,
        S(8) / 5, -S(1) / 5, -S(1) / 5,
        S(8) / 315,
        S(8) / 315, -S(1) / 560, -S(1) / 560
    ]

    # Third derivative
    for i in range(3):
        assert d[3][i] == [S(0)] * 9
    assert d[3][4] == [S(0), -S(1), S(1), S(1) / 2, -S(1) / 2] + [S(0)] * 4
    assert d[3][6] == [
        S(0), -S(13) / 8,
        S(13) / 8,
        S(1), -S(1), -S(1) / 8,
        S(1) / 8
    ] + [S(0)] * 2
    assert d[3][8] == [
        S(0), -S(61) / 30,
        S(61) / 30,
        S(169) / 120, -S(169) / 120, -S(3) / 10,
        S(3) / 10,
        S(7) / 240, -S(7) / 240
    ]

    # Fourth derivative
    for i in range(4):
        assert d[4][i] == [S(0)] * 9
    assert d[4][4] == [S(6), -S(4), -S(4), S(1), S(1)] + [S(0)] * 4
    assert d[4][6] == [
        S(28) / 3, -S(13) / 2, -S(13) / 2,
        S(2),
        S(2), -S(1) / 6, -S(1) / 6
    ] + [S(0)] * 2
    assert d[4][8] == [
        S(91) / 8, -S(122) / 15, -S(122) / 15,
        S(169) / 60,
        S(169) / 60, -S(2) / 5, -S(2) / 5,
        S(7) / 240,
        S(7) / 240
    ]

    # Table 2, p. 703 in doi:10.1090/S0025-5718-1988-0935077-0
    # --------------------------------------------------------
    xl = [[
        j / S(2)
        for j in list(range(-i * 2 + 1, 0, 2)) + list(range(1, i * 2 + 1, 2))
    ] for i in range(1, 5)]

    # d holds all coefficients
    d = [
        finite_diff_weights({
            0: 1,
            1: 2,
            2: 4,
            3: 4
        }[i], xl[i], 0) for i in range(4)
    ]

    # Zeroth derivative
    assert d[0][0][1] == [S(1) / 2, S(1) / 2]
    assert d[1][0][3] == [-S(1) / 16, S(9) / 16, S(9) / 16, -S(1) / 16]
    assert d[2][0][5] == [
        S(3) / 256, -S(25) / 256,
        S(75) / 128,
        S(75) / 128, -S(25) / 256,
        S(3) / 256
    ]
    assert d[3][0][7] == [
        -S(5) / 2048,
        S(49) / 2048, -S(245) / 2048,
        S(1225) / 2048,
        S(1225) / 2048, -S(245) / 2048,
        S(49) / 2048, -S(5) / 2048
    ]

    # First derivative
    assert d[0][1][1] == [-S(1), S(1)]
    assert d[1][1][3] == [S(1) / 24, -S(9) / 8, S(9) / 8, -S(1) / 24]
    assert d[2][1][5] == [
        -S(3) / 640,
        S(25) / 384, -S(75) / 64,
        S(75) / 64, -S(25) / 384,
        S(3) / 640
    ]
    assert d[3][1][7] == [
        S(5) / 7168, -S(49) / 5120,
        S(245) / 3072,
        S(-1225) / 1024,
        S(1225) / 1024, -S(245) / 3072,
        S(49) / 5120, -S(5) / 7168
    ]
예제 #3
0
def test_finite_diff_weights():

    d = finite_diff_weights(1, [5, 6, 7], 5)
    assert d[1][2] == [-S(3)/2, 2, -S(1)/2]

    # Table 1, p. 702 in doi:10.1090/S0025-5718-1988-0935077-0
    # --------------------------------------------------------
    # x = [[0], [-1, 0, 1], ...]
    xl = [[j for j in range(-i, i+1)] for i in range(0, 5)]

    # d holds all coefficients
    d = [finite_diff_weights({0: 0, 1: 2, 2: 4, 3: 4, 4: 4}[i],
                             xl[i], 0) for i in range(5)]

    # Zeroeth derivative
    assert d[0][0][0] == [S(1)]

    # First derivative
    assert d[1][1][2] == [-S(1)/2, S(0), S(1)/2]
    assert d[2][1][4] == [S(1)/12, -S(2)/3, S(0), S(2)/3, -S(1)/12]
    assert d[3][1][6] == [-S(1)/60, S(3)/20, -S(3)/4, S(0), S(3)/4, -S(3)/20,
                          S(1)/60]
    assert d[4][1][8] == [S(1)/280, -S(4)/105, S(1)/5, -S(4)/5, S(0), S(4)/5,
                          -S(1)/5, S(4)/105, -S(1)/280]

    # Second derivative
    assert d[1][2][2] == [S(1), -S(2), S(1)]
    assert d[2][2][4] == [-S(1)/12, S(4)/3, -S(5)/2, S(4)/3, -S(1)/12]
    assert d[3][2][6] == [S(1)/90, -S(3)/20, S(3)/2, -S(49)/18, S(3)/2,
                          -S(3)/20, S(1)/90]
    assert d[4][2][8] == [-S(1)/560, S(8)/315, -S(1)/5, S(8)/5, -S(205)/72,
                          S(8)/5, -S(1)/5, S(8)/315, -S(1)/560]

    # Third derivative
    assert d[2][3][4] == [-S(1)/2, S(1), S(0), -S(1), S(1)/2]
    assert d[3][3][6] == [S(1)/8, -S(1), S(13)/8, S(0), -S(13)/8, S(1),
                          -S(1)/8]
    assert d[4][3][8] == [-S(7)/240, S(3)/10, -S(169)/120, S(61)/30, S(0),
                          -S(61)/30, S(169)/120, -S(3)/10, S(7)/240]

    # Fourth derivative
    assert d[2][4][4] == [S(1), -S(4), S(6), -S(4), S(1)]
    assert d[3][4][6] == [-S(1)/6, S(2), -S(13)/2, S(28)/3, -S(13)/2, S(2),
                          -S(1)/6]
    assert d[4][4][8] == [S(7)/240, -S(2)/5, S(169)/60, -S(122)/15, S(91)/8,
                          -S(122)/15, S(169)/60, -S(2)/5, S(7)/240]

    # Table 2, p. 703 in doi:10.1090/S0025-5718-1988-0935077-0
    # --------------------------------------------------------
    xl = [[j/S(2) for j in list(range(-i*2+1, 0, 2))+list(range(1, i*2+1, 2))]
          for i in range(1, 5)]

    # d holds all coefficients
    d = [finite_diff_weights({0: 1, 1: 2, 2: 4, 3: 4}[i], xl[i], 0) for
         i in range(4)]

    # Zeroth derivative
    assert d[0][0][1] == [S(1)/2, S(1)/2]
    assert d[1][0][3] == [-S(1)/16, S(9)/16, S(9)/16, -S(1)/16]
    assert d[2][0][5] == [S(3)/256, -S(25)/256, S(75)/128, S(75)/128,
                          -S(25)/256, S(3)/256]
    assert d[3][0][7] == [-S(5)/2048, S(49)/2048, -S(245)/2048, S(1225)/2048,
                          S(1225)/2048, -S(245)/2048, S(49)/2048, -S(5)/2048]

    # First derivative
    assert d[0][1][1] == [-S(1), S(1)]
    assert d[1][1][3] == [S(1)/24, -S(9)/8, S(9)/8, -S(1)/24]
    assert d[2][1][5] == [-S(3)/640, S(25)/384, -S(75)/64, S(75)/64,
                          -S(25)/384, S(3)/640]
    assert d[3][1][7] == [S(5)/7168, -S(49)/5120,  S(245)/3072, S(-1225)/1024,
                          S(1225)/1024, -S(245)/3072, S(49)/5120, -S(5)/7168]
예제 #4
0
def diff_matrix_1d(grid_size, difference_order=4, periodic_boundary=False):
    """
    Return a differentiation matrices associated with derivative operators up to 2nd order on the line
    The derivative is calculated with respect to the equispaced grid.
    The integration region is assumed to be the unit interval [0,1] (1. is droped in case of periodic bc)
    The differentiation matrices are sparsed.
    
    Parameters 
    ----------
    grid_size : int nx
    difference_order : int default=4
        Controls order of the approximation of finite difference, sets the size of the stencil
        The endpoint derivatives are calculated with larger stencil for better accuracy
    peryodic_boundary: boolean, default=False
        Sets whether periodic boundary conditions are imposed
    
    Returns
    ----------
    List of differentiation matrices of size nx X nx of rising order including identity. 
    I.e. [1, dx, d2x]
    
    References
    ---------------
    Uses sympy.calculus.finite_diff.finite_diff_weights
    """
    #----------------Check input------------------
    if any(type(inp) != int for inp in (grid_size, difference_order)):
        raise ValueError("grid_size and difference_order must be integers")
    if type(periodic_boundary) != bool:
        raise ValueError("periodic_boundary must be boolean")

    if difference_order + 2 > grid_size:
        raise ValueError("Stencil is larger then the whole grid")

    #-------------Body------------------

    h0 = int(difference_order / 2)  #This is a number of neighbours

    # evaluate the size of grid spacing
    if periodic_boundary == False:
        dh = 1. / (grid_size - 1)
    elif periodic_boundary == True:
        dh = 1. / grid_size

    #calculate a set of derivative weights with various offset and single out the central one
    #the endpoint derivatives are calculated with larger stencil for better accuracy
    weights_all = []
    for offset in range(-h0, h0 + 1, 1):
        if offset == 0:
            stencil = [S(i) for i in range(-h0, h0 + 1)]
            weights_all.append(
                np.array(finite_diff_weights(2, stencil, offset),
                         dtype=float)[:, -1])
        if offset < 0:
            stencil = [S(i) for i in range(2 * h0 + 2)]
            weights_all.append(
                np.array(finite_diff_weights(2, stencil, h0 + offset),
                         dtype=float)[:, -1])
        if offset > 0:
            stencil = [S(i) for i in range(2 * h0 + 2)]
            weights_all.append(
                np.array(finite_diff_weights(2, stencil, h0 + 1 + offset),
                         dtype=float)[:, -1])

    weights_center = weights_all[h0]

    #write a diff matrix of order 0 (identity) to the list
    diff_mats = [sparse.identity(grid_size)]

    #create the matrices for 1st and 2nd derivatives
    #non-periodic boundary
    if periodic_boundary == False:
        for deriv in range(1, 3):
            #away from the boundaries the central derivatives fill the diagonal
            weights = weights_center[deriv]
            diags = np.broadcast_to(weights,
                                    (grid_size, 2 * h0 + 1)).transpose()
            in_mat = sparse.dia_matrix((diags, range(2 * h0 + 1)),
                                       shape=(grid_size - (2 * h0), grid_size))

            #near the bottom (beginnig of the grid) use one-sided derivatives in the left part of matrix, fill with zeros to the right
            bottom_mat_right = sparse.dia_matrix(
                (h0, grid_size - (2 * h0 + 2)))
            bottom_mat_left = np.zeros((h0, 2 * h0 + 2))
            for dist in range(h0):
                bottom_mat_left[dist] = weights_all[dist][deriv]
            bottom_mat = sparse.hstack([bottom_mat_left, bottom_mat_right])

            #same near top, fill with zeros to the left
            top_mat_left = sparse.dia_matrix((h0, grid_size - (2 * h0 + 2)))
            top_mat_right = np.zeros((h0, 2 * h0 + 2))
            for dist in range(-h0, 0):
                top_mat_right[dist] = weights_all[2 * h0 + 1 + dist][deriv]
            top_mat = sparse.hstack([top_mat_left, top_mat_right])

            full_mat = sparse.vstack([bottom_mat, in_mat, top_mat])

            diff_mats.append(full_mat.multiply(dh**(-deriv)))

    #Periodic boundary
    if periodic_boundary == True:
        for deriv in range(1, 3):
            #the central derivatives fill the diagonal plus show up in the corners
            weights = weights_center[deriv]
            diags = np.broadcast_to(weights,
                                    (grid_size, 2 * h0 + 1)).transpose()
            diags = np.vstack((diags[h0 + 1:], diags, diags[:h0]))
            offsets = list(range(-grid_size + 1, h0 + 1 - grid_size)) + list(
                range(-h0, h0 + 1)) + list(range(-h0 + grid_size, grid_size))
            full_mat = sparse.dia_matrix((diags, offsets),
                                         shape=(grid_size, grid_size))

            diff_mats.append(full_mat.multiply(dh**(-deriv)))

    return diff_mats