# Buggy code
def sample(problem, N, M=4):
    """Generate model inputs for the Fourier Amplitude Sensitivity Test (FAST).

    Returns a NumPy matrix containing the model inputs required by the Fourier
    Amplitude sensitivity test.  The resulting matrix contains N rows and D
    columns, where D is the number of parameters.  The samples generated are
    intended to be used by :func:`SALib.analyze.fast.analyze`.

    Parameters
    ----------
    problem : dict
        The problem definition
    N : int
        The number of samples to generate
    M : int
        The interference parameter, i.e., the number of harmonics to sum in the
        Fourier series decomposition (default 4)
    """

    D = problem["num_vars"]

    omega = np.empty([D])
    omega[0] = math.floor((N - 1) / (2 * M))
    m = math.floor(omega[0] / (2 * M))

    if m >= (D - 1):
        omega[1:] = np.floor(np.linspace(1, m, D - 1))
    else:
        omega[1:] = np.arange(D - 1) % m + 1

    # Discretization of the frequency space, s
    s = (2 * math.pi / N) * np.arange(N)

    # Transformation to get points in the X space
    X = np.empty([N * D, D])
    omega2 = np.empty([D])

    for i in range(D):
        omega2[i] = omega[0]
        idx = list(range(i)) + list(range(i + 1, D))
        omega2[idx] = omega[1:]
        l = range(i * N, (i + 1) * N)

        # random phase shift on [0, 2pi) following Saltelli et al.
        # Technometrics 1999
        phi = 2 * math.pi * np.random.rand()

        for j in range(D):
            g = 0.5 + (1 / math.pi) * np.arcsin(np.sin(omega2[j] * s + phi))
            X[l, j] = g

    scale_samples(X, problem["bounds"])
    return X


# Traceback (IndexError)
SALib\sample\fast_sampler.py:39: RuntimeWarning: invalid value encountered in remainder
omega[1:] = np.arange(D - 1) % m + 1
\SALib\analyze\fast.py:70: RuntimeWarning: invalid value encountered in remainder
omega[1:] = np.arange(D - 1) % m + 1
\SALib\analyze\fast.py:88: RuntimeWarning: invalid value encountered in power
Sp = np.power(np.absolute(f[np.arange(1, int(N / 2))]) / N, 2)
Traceback (most recent call last):
File "test.py", line 17, in <module>
Si = fast.analyze(problem, Y, print_to_console=False)
File "SALib\analyze\fast.py", line 78, in analyze
Si['S1'][i] = compute_first_order(Y[l], N, M, omega[0])
File "SALib\analyze\fast.py", line 90, in compute_first_order
D1 = 2 * np.sum(Sp[np.arange(1, M + 1) * int(omega) - 1])
IndexError: index 15 is out of bounds for axis 0 with size 15

# Fixed code
def sample(problem, N, M=4):
    """Generate model inputs for the Fourier Amplitude Sensitivity Test (FAST).

    Returns a NumPy matrix containing the model inputs required by the Fourier
    Amplitude sensitivity test.  The resulting matrix contains N rows and D
    columns, where D is the number of parameters.  The samples generated are
    intended to be used by :func:`SALib.analyze.fast.analyze`.

    Parameters
    ----------
    problem : dict
        The problem definition
    N : int
        The number of samples to generate
    M : int
        The interference parameter, i.e., the number of harmonics to sum in the
        Fourier series decomposition (default 4)
    """

    if N < 4 * M**2:
        raise ValueError("""
        Sample size N > 4M^2 is required. M=4 by default.""")

    D = problem["num_vars"]

    omega = np.empty([D])
    omega[0] = math.floor((N - 1) / (2 * M))
    m = math.floor(omega[0] / (2 * M))

    if m >= (D - 1):
        omega[1:] = np.floor(np.linspace(1, m, D - 1))
    else:
        omega[1:] = np.arange(D - 1) % m + 1

    # Discretization of the frequency space, s
    s = (2 * math.pi / N) * np.arange(N)

    # Transformation to get points in the X space
    X = np.empty([N * D, D])
    omega2 = np.empty([D])

    for i in range(D):
        omega2[i] = omega[0]
        idx = list(range(i)) + list(range(i + 1, D))
        omega2[idx] = omega[1:]
        l = range(i * N, (i + 1) * N)

        # random phase shift on [0, 2pi) following Saltelli et al.
        # Technometrics 1999
        phi = 2 * math.pi * np.random.rand()

        for j in range(D):
            g = 0.5 + (1 / math.pi) * np.arcsin(np.sin(omega2[j] * s + phi))
            X[l, j] = g

    scale_samples(X, problem["bounds"])
    return X