def stencil_diff2(nr, pos, coeffs = None):
    """Create stencil matrix for a zero 2nd derivative"""

    assert(coeffs.get('a', None) is not None)
    assert(coeffs.get('b', None) is not None)
    assert(coeffs.get('c', None) is None)

    ns = np.arange(0,nr,1)
    if pos == 0:
        offsets = [-2, 0]

        # Generate subdiagonal
        def d_1(n):
            return -(n - 3.0)*(n - 2.0)**2/(n**2*(n + 1.0))

    else:
        offsets = [-1, 0]

        # Generate subdiagonal
        def d_1(n):
            return -pos*(n - 2.0)*(n - 1.0)/(n*(n + 1.0))

    # Generate diagonal
    def d0(n):
        return np.ones(n.shape)

    ds = [d_1, d0]
    diags = utils.build_diagonals(ns, -1, ds, offsets, None, False)
    diags[-1] = diags[-1][0:nr+offsets[0]]

    return spsp.diags(diags, offsets, (nr,nr+offsets[0]))
def stencil_value(nr, pos, coeffs = None):
    """Create stencil matrix for a zero boundary value"""

    assert(coeffs.get('a', None) is not None)
    assert(coeffs.get('b', None) is not None)
    assert(coeffs.get('c', None) is None)

    ns = np.arange(0,nr,1)
    if pos == 0:
        offsets = [-2, 0]
        sgn = -1.0
    else:
        offsets = [-1, 0]
        sgn = -pos 

    # Generate subdiagonal
    def d_1(n):
        return galerkin_c(n+offsets[0])*sgn

    # Generate diagonal
    def d0(n):
        return np.ones(n.shape)

    ds = [d_1, d0]
    diags = utils.build_diagonals(ns, -1, ds, offsets, None, False)
    diags[-1] = diags[-1][0:nr+offsets[0]]

    return spsp.diags(diags, offsets, (nr,nr+offsets[0]))
def stencil_insulating(nr, pos, coeffs = None):
    """Create stencil matrix for an insulating boundary"""

    assert(coeffs.get('a', None) is not None)
    assert(coeffs.get('b', None) is not None)
    assert(coeffs.get('c', None) is None)
    assert(coeffs.get('l', None) is not None)
    assert(pos == 0)

    a = coeffs['a']
    b = coeffs['b']
    l = coeffs['l']

    ns = np.arange(0,nr,1)
    offsets = [-2, -1, 0]

    # Generate 2nd subdiagonal
    def d_2(n):
        val_num = a**2*(2.0*l*(l+1.0)-2.0*(n-3.0)*n*((n-3.0)*n+5.0)-13.0)+a*b*(2.0*l+1.0)*(2.0*(n-3.0)*n+5.0)+2.0*b**2*(n**2-3.0*n+2.0)**2 
        val_den = a**2*(2.0*l*(l+1.0)-2.0*(n-1.0)*n*((n-1.0)*n+1.0)-1.0)+a*b*(2.0*l+1.0)*(2.0*(n-1.0)*n+1.0)+2.0*b**2*(n-1.0)**2.0*n**2
        val = -val_num/val_den
        for i,j in enumerate(n):
            if j == 2:
                corr_num = a*(a*(2.0*l**2+2.0*l-1.0)+2.0*b*l+b)
                corr_den = 2.0*(a**2*(2.0*l**2+2.0*l-13.0)+5.0*a*(2.0*b*l+b)+8.0*b**2)
                val[i] = -corr_num/corr_den
            if j > 2:
                break

        return val

    # Generate 1st subdiagonal
    def d_1(n):
        val_num = 4.0*a*n*((2.0*l+1.0)*a - b)
        val_den = a**2*(2.0*l*(l+1.0)-2.0*n*(n+1.0)*(n**2+n+1.0)-1.0)+a*b*(2.0*l+1.0)*(2.0*n*(n+1.0)+1.0)+2.0*b**2*n**2*(n+1.0)**2
        val = val_num/val_den
        for i,j in enumerate(n):
            if j == 1:
                corr_num = 2.0*a*(2.0*a*l+a-b)
                corr_den = a**2*(2.0*l**2+2.0*l-13.0)+5.0*a*(2.0*b*l+b)+8.0*b**2
                val[i] = corr_num/corr_den
            if j > 1:
                break

        return val

    # Generate diagonal
    def d0(n):
        return np.ones(n.shape)

    ds = [d_2, d_1, d0]
    diags = utils.build_diagonals(ns, -1, ds, offsets, None, False)
    diags[-1] = diags[-1][0:nr+offsets[0]]

    return spsp.diags(diags, offsets, (nr,nr+offsets[0]))
def stencil_rdiffdivr(nr, pos, coeffs = None):
    """Create stencil matrix for a zero r D 1/r derivative"""

    assert(coeffs.get('a', None) is not None)
    assert(coeffs.get('b', None) is not None)
    assert(coeffs.get('c', None) is None)
    assert(pos == 0)

    a = coeffs['a']
    b = coeffs['b']

    ns = np.arange(0,nr,1)
    offsets = [-2, -1, 0]

    # Generate 2nd subdiagonal
    def d_2(n):
        #val_num = a**2*((n - 3.0)**2*n**2 - 2.0) - b**2*(n**2 - 3.0*n + 2.0)**2
        #val_den = -a**2*((n - 2.0)*n - 1.0)*(n**2 - 2.0) + b**2*(n - 1.0)**2*n**2
        val_num = (n - 2.0)*(b**2*(n - 2.0)*(n - 1.0) - a**2*(n - 3.0)*n)
        val_den = n*(a**2*(n - 2.0)*(n + 1.0) - b**2*(n - 1.0)*n)
        val = val_num/val_den
        for i,j in enumerate(n):
            if j == 2:
                #val[i] = a**2/(2.0*a**2 + 4.0*b**2)
                val[i] = 0
            if j > 2:
                break

        return val

    # Generate 1st subdiagonal
    def d_1(n):
        #val_num = -8.0*a*b*n
        #val_den = a**2*(n**2 - 2.0)*(n*(n + 2.0) - 1.0) - b**2*n**2*(n + 1.0)**2
        val_num = -4.0*a*b
        val_den = (n + 1.0)*(a**2*(n**2 + n - 2.0) - b**2*n*(n + 1.0))
        val = val_num/val_den
        for i,j in enumerate(n):
            if j == 1:
                #val[i] = 2.0*a*b/(a**2 + 2.0*b**2)
                val[i] = a/(2.0*b)
            if j > 1:
                break

        return val

    # Generate diagonal
    def d0(n):
        return np.ones(n.shape)

    ds = [d_2, d_1, d0]
    diags = utils.build_diagonals(ns, -1, ds, offsets, None, False)
    diags[-1] = diags[-1][0:nr+offsets[0]]

    return spsp.diags(diags, offsets, (nr,nr+offsets[0]))
def stencil_value_diff2(nr, pos, coeffs = None):
    """Create stencil matrix for a zero boundary value and a zero 2nd derivative"""

    assert(coeffs.get('a', None) is not None)
    assert(coeffs.get('b', None) is not None)
    assert(coeffs.get('c', None) is None)
    assert(pos == 0)

    ns = np.arange(0,nr,1)
    offsets = [-4, -2, 0]

    # Generate 2nd subdiagonal
    def d_2(n):
        val_num = (n - 3.0)*(2.0*n**2 - 12.0*n + 19.0)
        val_den = (n - 1.0)*(2.0*n**2 - 4.0*n + 3.0)
        val = val_num/val_den
        for i,j in enumerate(n):
            if j == 4:
                val[i] = 1.0/38.0
            if j > 4:
                break

        return val

    # Generate 1st subdiagonal
    def d_1(n):
        val_num = -2.0*n*(2.0*n**2 + 7.0)
        val_den = (n + 1.0)*(2.0*n**2 + 4.0*n + 3.0)
        val = val_num/val_den
        for i,j in enumerate(n):
            if j == 2:
                val[i] = -10.0/19.0
            if j > 2:
                break

        return val

    # Generate diagonal
    def d0(n):
        return np.ones(n.shape)

    ds = [d_2, d_1, d0]
    diags = utils.build_diagonals(ns, -1, ds, offsets, None, False)
    diags[-1] = diags[-1][0:nr+offsets[0]]

    return spsp.diags(diags, offsets, (nr,nr+offsets[0]))