예제 #1
0
def f_interp_2d(self, dt):
    
    if(self.performance_test_flag == True):
        tic = af.time()

    # Defining a lambda function to perform broadcasting operations
    # This is done using af.broadcast, which allows us to perform 
    # batched operations when operating on arrays of different sizes
    addition = lambda a, b:a + b

    # af.broadcast(function, *args) performs batched operations on
    # function(*args)
    q1_center_new = af.broadcast(addition, self.q1_center, - self._A_q1 * dt)
    q2_center_new = af.broadcast(addition, self.q2_center, - self._A_q2 * dt)

    # Reordering from (dof, N_q1, N_q2) --> (N_q1, N_q2, dof)
    self.f = af.approx2(af.reorder(self.f, 1, 2, 0),
                        af.reorder(q1_center_new, 1, 2, 0),
                        af.reorder(q2_center_new, 1, 2, 0),
                        af.INTERP.BICUBIC_SPLINE, 
                        xp = af.reorder(self.q1_center, 1, 2, 0),
                        yp = af.reorder(self.q2_center, 1, 2, 0)
                       )

    # Reordering from (N_q1, N_q2, dof) --> (dof, N_q1, N_q2)
    self.f = af.reorder(self.f, 2, 0, 1)

    af.eval(self.f)

    if(self.performance_test_flag == True):
        af.sync()
        toc = af.time()
        self.time_interp2 += toc - tic

    return
예제 #2
0
def mapping_xi_to_x(x_nodes, xi):
    '''
    Maps points in :math: `\\xi` space to :math:`x` space using the formula
    :math:  `x = \\frac{1 - \\xi}{2} x_0 + \\frac{1 + \\xi}{2} x_1`
    
    Parameters
    ----------
    
    x_nodes : arrayfire.Array [2 1 1 1]
              Element nodes.
    
    xi      : arrayfire.Array [N 1 1 1]
              Value of :math: `\\xi`coordinate for which the corresponding
              :math: `x` coordinate is to be found.
    
    Returns
    -------
    x : arrayfire.Array
        :math: `x` value in the element corresponding to :math:`\\xi`.
    '''

    N_0 = (1 - xi) / 2
    N_1 = (1 + xi) / 2
    
    N0_x0 = af.broadcast(utils.multiply, N_0, x_nodes[0])
    N1_x1 = af.broadcast(utils.multiply, N_1, x_nodes[1])
    
    x = N0_x0 + N1_x1
    
    return x
예제 #3
0
def test_compute_electrostatic_fields():

    test_obj = test()
    compute_electrostatic_fields(test_obj)

    E1 = 0.5 * test_obj.N_q1 * test_obj.N_q2 * af.ifft2(test_obj.E1_hat)
    E2 = 0.5 * test_obj.N_q1 * test_obj.N_q2 * af.ifft2(test_obj.E2_hat)

    E1_analytical =   test_obj.physical_system.params.charge_electron \
                    * 2 * np.pi / (20 * np.pi**2) \
                    * (  0.01 * af.sin(2 * np.pi * test_obj.q1 + 4 * np.pi * test_obj.q2)
                       + 0.02 * af.cos(2 * np.pi * test_obj.q1 + 4 * np.pi * test_obj.q2)
                      )

    E2_analytical =   test_obj.physical_system.params.charge_electron \
                    * 4 * np.pi / (20 * np.pi**2) \
                    * (  0.01 * af.sin(2 * np.pi * test_obj.q1 + 4 * np.pi * test_obj.q2)
                       + 0.02 * af.cos(2 * np.pi * test_obj.q1 + 4 * np.pi * test_obj.q2)
                      )

    add = lambda a,b:a+b

    error_E1 = af.mean(af.abs(af.broadcast(add, E1_analytical, - E1)))
    error_E2 = af.mean(af.abs(af.broadcast(add, E2_analytical, - E2)))

    assert(error_E1 < 1e-14)
    assert(error_E2 < 1e-14)
예제 #4
0
def integrate(integrand_coeffs):
    '''
    Performs integration according to the given quadrature method
    by taking in the coefficients of the polynomial and the number of
    quadrature points.
    The number of quadrature points and the quadrature scheme are set
    in params.py module.
    
    Parameters
    ----------
    
    integrand_coeffs : arrayfire.Array [M N 1 1]
                       The coefficients of M number of polynomials of order N
                       arranged in a 2D array.
    Returns
    -------
    
    Integral : arrayfire.Array [M 1 1 1]
               The value of the definite integration performed using the
               specified quadrature method for M polynomials.

    '''

    integrand = integrand_coeffs

    if (params.scheme == 'gauss_quadrature'):
        #print('gauss_quad')

        gaussian_nodes = params.gauss_points
        Gauss_weights = params.gauss_weights

        nodes_tile = af.transpose(
            af.tile(gaussian_nodes, 1, integrand.shape[1]))
        power = af.flip(af.range(integrand.shape[1]))
        nodes_power = af.broadcast(utils.power, nodes_tile, power)
        weights_tile = af.transpose(
            af.tile(Gauss_weights, 1, integrand.shape[1]))
        nodes_weight = nodes_power * weights_tile

        value_at_gauss_nodes = af.matmul(integrand, nodes_weight)
        integral = af.sum(value_at_gauss_nodes, 1)

    if (params.scheme == 'lobatto_quadrature'):
        #print('lob_quad')

        lobatto_nodes = params.lobatto_quadrature_nodes
        Lobatto_weights = params.lobatto_weights_quadrature

        nodes_tile = af.transpose(af.tile(lobatto_nodes, 1,
                                          integrand.shape[1]))
        power = af.flip(af.range(integrand.shape[1]))
        nodes_power = af.broadcast(utils.power, nodes_tile, power)
        weights_tile = af.transpose(
            af.tile(Lobatto_weights, 1, integrand.shape[1]))
        nodes_weight = nodes_power * weights_tile

        value_at_lobatto_nodes = af.matmul(integrand, nodes_weight)
        integral = af.sum(value_at_lobatto_nodes, 1)

    return integral
예제 #5
0
def integrate_1d(polynomials, order, scheme = 'gauss'):
    '''
    Integrates single variables using the Gauss-Legendre or Gauss-Lobatto
    quadrature.

    Parameters
    ----------
    polynomials : af.Array [number_of_polynomials degree 1 1]
                  The polynomials to be integrated.

    order       : int
                  Order of the quadrature.

    scheme      : str
                  Possible options are

                  - ``gauss`` for using Gauss-Legendre quadrature
                  - ``lobatto`` for using Gauss-Lobatto quadrature

    Returns
    -------
    integral : af.Array [number_of_polynomials 1 1 1]
               The integral for the respective polynomials using the given
               quadrature scheme.
    '''
    integral = 0.0

    if scheme == 'gauss':

        N_g = order
        xi_gauss      = af.np_to_af_array(lagrange.gauss_nodes(N_g))
        gauss_weights = lagrange.gaussian_weights(N_g)

        polyval_gauss = polyval_1d(polynomials, xi_gauss)

        integral = af.sum(af.transpose(af.broadcast(multiply,
                                                    af.transpose(polyval_gauss),
                                                    gauss_weights)), dim = 1)

        return integral
        
    elif scheme == 'lobatto':
        N_l = order
        xi_lobatto      = lagrange.LGL_points(N_l)
        lobatto_weights = lagrange.lobatto_weights(N_l)

        polyval_lobatto = polyval_1d(polynomials, xi_lobatto)

        integral = af.sum(af.transpose(af.broadcast(multiply,
                                                    af.transpose(polyval_lobatto),
                                                    lobatto_weights)), dim = 1)

        return integral

    else:
        return -1.
예제 #6
0
def compute_electrostatic_fields(self, f=None, f_hat=None):
    """
    Computes the electrostatic fields by making use of the
    Poisson equation: div^2 phi = rho
    """

    if (self.single_mode_evolution == True):

        # Intializing for the electrostatic Case:
        delta_rho_hat = self.compute_moments('density', f)
        delta_phi_hat =   self.physical_system.params.charge_electron \
                        * delta_rho_hat/(  self.physical_system.params.k_q1**2
                                         + self.physical_system.params.k_q2**2
                                        )

        self.delta_E1_hat = -delta_phi_hat * (1j *
                                              self.physical_system.params.k_q1)
        self.delta_E2_hat = -delta_phi_hat * (1j *
                                              self.physical_system.params.k_q2)
        self.delta_E3_hat = 0

        self.delta_B1_hat = 0
        self.delta_B2_hat = 0
        self.delta_B3_hat = 0

    else:

        rho_hat = 2 * af.fft2(self.compute_moments('density', f=f, f_hat=f_hat)) \
                    / (self.N_q1 * self.N_q2) # Scaling Appropriately

        # Defining lambda functions to perform broadcasting operations:
        # This is done using af.broadcast, which allows us to perform
        # batched operations when operating on arrays of different sizes:
        divide = lambda a, b: a / b
        multiply = lambda a, b: a * b

        # af.broadcast(function, *args) performs batched operations on
        # function(*args):
        phi_hat = self.physical_system.params.charge_electron * \
                  af.broadcast(divide, rho_hat,
                               (self.k_q1**2 + self.k_q2**2)
                              )

        # Setting the background electric potential to zero:
        phi_hat[0, 0] = 0

        # Tiling to make phi_hat of positionsExpanded form:
        phi_hat = af.tile(phi_hat, 1, 1, self.N_p1 * self.N_p2 * self.N_p3)

        self.E1_hat = af.broadcast(multiply, -phi_hat, (1j * self.k_q1))
        self.E2_hat = af.broadcast(multiply, -phi_hat, (1j * self.k_q2))

        af.eval(self.E1_hat, self.E2_hat)

    return
예제 #7
0
def _decision_af(signal, symbols, precision=16):
    """
    Make symbol decisions on  signal array  onto symbols. Arrayfire function.

    Parameters
    ----------
    signal : array_like
        input signal array
    symbols : array_like
        array of symbols to decide onto
    precision : int, optional
        bit precision either 16 for complex128 or 8 for complex 64

    Returns
    -------
    out : array_like
        array of decided symbols

    """
    global NMAX
    if precision == 16:
        prec_dtype = np.complex128
    elif precision == 8:
        prec_dtype = np.complex64
    else:
        raise ValueError(
            "Precision has to be either 16 for double complex or 8 for single complex"
        )
    Nmax = NMAX // len(symbols.flatten()) // 16
    L = signal.flatten().shape[0]
    sig = af.np_to_af_array(signal.flatten().astype(prec_dtype))
    sym = af.transpose(af.np_to_af_array(symbols.flatten().astype(prec_dtype)))
    tmp = af.constant(0, L, dtype=af.Dtype.c64)
    if L < Nmax:
        v, idx = af.imin(af.abs(af.broadcast(lambda x, y: x - y, sig, sym)),
                         dim=1)
        tmp = af.transpose(sym)[idx]
    else:
        steps = L // Nmax
        rem = L % Nmax
        for i in range(steps):
            v, idx = af.imin(af.abs(
                af.broadcast(lambda x, y: x - y, sig[i * Nmax:(i + 1) * Nmax],
                             sym)),
                             dim=1)
            tmp[i * Nmax:(i + 1) * Nmax] = af.transpose(sym)[idx]
        v, idx = af.imin(af.abs(
            af.broadcast(lambda x, y: x - y, sig[steps * Nmax:], sym)),
                         dim=1)
        tmp[steps * Nmax:] = af.transpose(sym)[idx]
    return np.array(tmp)
예제 #8
0
def trial_dx_deta(x_nodes, xi, eta):
    '''
    '''

    dN_0_deta = -(eta - xi - 1) * (0.25 * xi - 0.25) \
                - (eta + 1) * (0.25 * xi - 0.25)
    dN_1_deta = -2 * eta * (-0.5 * xi + 0.5)
    dN_2_deta = -(eta + xi + 1) * (0.25 * xi - 0.25) \
                - (eta - 1) * (0.25 * xi - 0.25)
    dN_3_deta = 0.5 * xi**2 - 0.5
    dN_4_deta = -(eta - xi + 1) * (-0.25 * xi - 0.25) \
                - (eta - 1) * (-0.25 * xi - 0.25)
    dN_5_deta = -2 * eta * (0.5 * xi + 0.5)
    dN_6_deta = -(eta + xi - 1) * (-0.25 * xi - 0.25) \
                - (eta + 1) * (-0.25 * xi - 0.25)
    dN_7_deta = -0.5 * xi**2 + 0.5

    dx_deta = af.broadcast(utils.multiply, dN_0_deta, x_nodes[0, :, :]) \
            + af.broadcast(utils.multiply, dN_1_deta, x_nodes[1, :, :]) \
            + af.broadcast(utils.multiply, dN_2_deta, x_nodes[2, :, :]) \
            + af.broadcast(utils.multiply, dN_3_deta, x_nodes[3, :, :]) \
            + af.broadcast(utils.multiply, dN_4_deta, x_nodes[4, :, :]) \
            + af.broadcast(utils.multiply, dN_5_deta, x_nodes[5, :, :]) \
            + af.broadcast(utils.multiply, dN_6_deta, x_nodes[6, :, :]) \
            + af.broadcast(utils.multiply, dN_7_deta, x_nodes[7, :, :])

    return dx_deta
예제 #9
0
def check_error(params):
    error = np.zeros(N.size)

    for i in range(N.size):
        domain.N_p1 = int(N[i])
        domain.N_p2 = int(N[i])
        # Defining the physical system to be solved:
        system = physical_system(domain, boundary_conditions, params,
                                 initialize, advection_terms,
                                 collision_operator.BGK, moment_defs)

        # Declaring a linear system object which will evolve the defined physical system:
        nls = nonlinear_solver(system)
        N_g = nls.N_ghost_q

        # Time parameters:
        dt = 0.01 * 32 / nls.N_p1
        t_final = 0.2

        time_array = np.arange(dt, t_final + dt, dt)

        # Since only the p = 1 mode is excited:

        E1 = nls.cell_centered_EM_fields_at_n[0]
        E2 = nls.cell_centered_EM_fields_at_n[1]
        E3 = nls.cell_centered_EM_fields_at_n[2]

        B1 = nls.cell_centered_EM_fields_at_n[3]
        B2 = nls.cell_centered_EM_fields_at_n[4]
        B3 = nls.cell_centered_EM_fields_at_n[5]

        (A_p1, A_p2,
         A_p3) = af.broadcast(nls._A_p, nls.q1_center, nls.q2_center,
                              nls.p1_center, nls.p2_center, nls.p3_center, E1,
                              E2, E3, B1, B2, B3, nls.physical_system.params)

        f_analytic = af.broadcast(initialize.initialize_f, nls.q1_center,
                                  nls.q2_center,
                                  addition(nls.p1_center, -A_p1 * t_final),
                                  addition(nls.p2_center, -A_p2 * t_final),
                                  nls.p3_center, nls.physical_system.params)

        for time_index, t0 in enumerate(time_array):
            nls.strang_timestep(dt)

        error[i] = af.mean(af.abs(nls.f - f_analytic))

    return (error)
예제 #10
0
 def _meanObject(self, obj, adjoint=False):
     """
     function to bin the object by factor of slice_binning_factor
     """
     if self.slice_binning_factor == 1:
         return obj
     assert self.shape[2] >= 1
     if adjoint:
         obj_out = af.constant(0.0,
                               self._shape_full[0],
                               self._shape_full[1],
                               self._shape_full[2],
                               dtype=af_complex_datatype)
         for idx in range((self.shape[2] - 1) * self.slice_binning_factor,
                          -1, -self.slice_binning_factor):
             idx_slice = slice(
                 idx,
                 np.min([obj_out.shape[2],
                         idx + self.slice_binning_factor]))
             obj_out[:, :, idx_slice] = af.broadcast(
                 self.assign_broadcast, obj_out[:, :, idx_slice],
                 obj[:, :, idx // self.slice_binning_factor])
     else:
         obj_out = af.constant(0.0,
                               self.shape[0],
                               self.shape[1],
                               self.shape[2],
                               dtype=af_complex_datatype)
         for idx in range(0, obj.shape[2], self.slice_binning_factor):
             idx_slice = slice(
                 idx,
                 np.min([obj.shape[2], idx + self.slice_binning_factor]))
             obj_out[:, :, idx // self.slice_binning_factor] = af.mean(
                 obj[:, :, idx_slice], dim=2)
     return obj_out
예제 #11
0
def multivariable_poly_value(poly_2d, x, y):
    '''
    '''
    polynomial_coeffs = af.transpose(af.moddims(poly_2d, poly_2d.shape[0] ** 2, poly_2d.shape[2]))

    power_index     = af.flip(af.np_to_af_array(np.arange(poly_2d.shape[0])))
    x_power_indices = af.flat(af.transpose(af.tile(power_index, 1, poly_2d.shape[0])))
    y_power_indices = af.tile(power_index, poly_2d.shape[0])

    x_power = af.broadcast(power, af.transpose(x), x_power_indices)
    y_power = af.broadcast(power, af.transpose(y), y_power_indices)

    polynomial_value = af.matmul(polynomial_coeffs, x_power * y_power)


    return polynomial_value
예제 #12
0
def polyval_2d(poly_2d, xi, eta):
    '''
    '''
    poly_2d_shape = poly_2d.shape
    poly_xy = af.tile(poly_2d, d0 = 1, d1 = 1, d2 = 1, d3 = xi.shape[0])
    poly_xy_shape = poly_xy.shape
    # print(poly_xy)

    xi_power = af.flip(af.range(poly_xy_shape[1], dtype = af.Dtype.u32))
    xi_power = af.tile(af.transpose(xi_power), d0 = poly_xy_shape[0])
    xi_power = af.tile(xi_power, d0 = 1, d1 = 1, d2 = xi.shape[0])

    eta_power = af.flip(af.range(poly_xy_shape[0], dtype = af.Dtype.u32))
    eta_power = af.tile(eta_power, d0 = 1, d1 = poly_xy_shape[1])
    eta_power = af.tile(eta_power, d0 = 1, d1 = 1, d2 = eta.shape[0])

    Xi = af.reorder(xi, d0 = 2, d1 = 1, d2 = 0)
    Xi = af.tile(Xi, d0 = poly_xy_shape[0], d1 = poly_xy_shape[1])
    Xi = af.pow(Xi, xi_power)
    Xi = af.reorder(Xi, d0 = 0, d1 = 1, d2 = 3, d3 = 2)
    # print(Xi)

    Eta = af.reorder(eta, d0 = 2, d1 = 1, d2 = 0)
    Eta = af.tile(Eta, d0 = poly_xy_shape[0], d1 = poly_xy_shape[1])
    Eta = af.pow(Eta, eta_power)
    Eta = af.reorder(Eta, d0 = 0, d1 = 1, d2 = 3, d3 = 2)
    # print(Eta)

    Xi_Eta = Xi * Eta

    poly_val = af.broadcast(multiply, poly_xy, Xi_Eta)
    poly_val = af.sum(af.sum(poly_val, dim = 1), dim = 0)
    poly_val = af.reorder(poly_val, d0 = 2, d1 = 3, d2 = 0, d3 = 1)

    return poly_val
예제 #13
0
def lagrange_interpolation(fn_i):
    '''
    Finds the general interpolation of a function.
    
    Parameters
    ----------
    fn_i : af.Array [N N_LGL 1 1]
           Value of :math:`N` functions at the LGL points.
    
    Returns
    -------
    lagrange_interpolation : af.Array [N N_LGL 1 1]
                             :math:`N` interpolated polynomials for
                             :math:`N` functions.
    '''

    fn_i = af.transpose(af.reorder(fn_i, d0=2, d1=1, d2=0))
    lagrange_interpolation = af.broadcast(utils.multiply,
                                          params.lagrange_coeffs, fn_i)
    lagrange_interpolation = af.reorder(af.sum(lagrange_interpolation, dim=0),
                                        d0=2,
                                        d1=1,
                                        d2=0)

    return lagrange_interpolation
예제 #14
0
def lagrange_interpolation_u(u, gv):
    '''
    Calculates the coefficients of the Lagrange interpolation using
    the value of u at the mapped LGL points in the domain.
    The interpolation using the Lagrange basis polynomials is given by
    :math:`L_i(\\xi) u_i(\\xi)`
    Where L_i are the Lagrange basis polynomials and u_i is the value
    of u at the LGL points.
    
    Parameters
    ----------
    u : arrayfire.Array [N_LGL N_Elements 1 1]
        The value of u at the mapped LGL points.
        
    Returns
    -------
    lagrange_interpolated_coeffs : arrayfire.Array[1 N_LGL N_Elements 1]
                                   The coefficients of the polynomials obtained
                                   by Lagrange interpolation. Each polynomial
                                   is of order N_LGL - 1.
    '''
    lagrange_coeffs_tile = af.tile(gv.lagrange_coeffs, 1, 1,\
                                               params.N_Elements)
    reordered_u = af.reorder(u, 0, 2, 1)

    lagrange_interpolated_coeffs = af.sum(af.broadcast(utils.multiply,\
                                             reordered_u, lagrange_coeffs_tile), 0)

    return lagrange_interpolated_coeffs
예제 #15
0
def _bps_idx_af(E, angles, symbols, N):
    global NMAX
    prec_dtype = E.dtype
    Ntestangles = angles.shape[1]
    Nmax = NMAX // Ntestangles // symbols.shape[0] // 16
    L = E.shape[0]
    EE = E[:, np.newaxis] * np.exp(1.j * angles)
    syms = af.np_to_af_array(symbols.astype(prec_dtype).reshape(1, 1, -1))
    idxnd = np.zeros(L, dtype=np.int32)
    if L <= Nmax + N:
        Eaf = af.np_to_af_array(EE.astype(prec_dtype))
        tmp = af.min(af.abs(af.broadcast(lambda x, y: x - y, Eaf[0:L, :],
                                         syms))**2,
                     dim=2)
        cs = _movavg_af(tmp, 2 * N, axis=0)
        val, idx = af.imin(cs, dim=1)
        idxnd[N:-N] = np.array(idx)
    else:
        K = L // Nmax
        R = L % Nmax
        if R < N:
            R = R + Nmax
            K -= 1
        Eaf = af.np_to_af_array(EE[0:Nmax + N].astype(prec_dtype))
        tmp = af.min(af.abs(af.broadcast(lambda x, y: x - y, Eaf, syms))**2,
                     dim=2)
        tt = np.array(tmp)
        cs = _movavg_af(tmp, 2 * N, axis=0)
        val, idx = af.imin(cs, dim=1)
        idxnd[N:Nmax] = np.array(idx)
        for i in range(1, K):
            Eaf = af.np_to_af_array(EE[i * Nmax - N:(i + 1) * Nmax + N].astype(
                np.complex128))
            tmp = af.min(af.abs(af.broadcast(lambda x, y: x - y, Eaf,
                                             syms))**2,
                         dim=2)
            cs = _movavg_af(tmp, 2 * N, axis=0)
            val, idx = af.imin(cs, dim=1)
            idxnd[i * Nmax:(i + 1) * Nmax] = np.array(idx)
        Eaf = af.np_to_af_array(EE[K * Nmax - N:K * Nmax + R].astype(
            np.complex128))
        tmp = af.min(af.abs(af.broadcast(lambda x, y: x - y, Eaf, syms))**2,
                     dim=2)
        cs = _movavg_af(tmp, 2 * N, axis=0)
        val, idx = af.imin(cs, dim=1)
        idxnd[K * Nmax:-N] = np.array(idx)
    return idxnd
예제 #16
0
def _soft_l_value_demapper_af(rx_symbs, M, snr, bits_map):
    num_bits = int(np.log2(M))
    N = rx_symbs.shape[0]
    k = bits_map.shape[1]
    sig = af.np_to_af_array(rx_symbs)
    bit_mtx = af.moddims(af.np_to_af_array(bits_map), 1, num_bits, k, 2)
    tmp = af.sum(af.broadcast(lambda x,y: af.exp(-snr*af.abs(x-y)**2), bit_mtx, sig), dim=2)
    lvl = af.log(tmp[:,:,:,1]) - af.log(tmp[:,:,:,0])
    return np.array(lvl)
예제 #17
0
def check_error(params):

    error = np.zeros(N.size)

    for i in range(N.size):
        af.device_gc()

        domain.N_q1 = int(N[i])
        domain.N_p1 = int(N[i])
 
        # Defining the physical system to be solved:
        system = physical_system(domain,
                                 boundary_conditions,
                                 params,
                                 initialize,
                                 advection_terms,
                                 collision_operator.BGK,
                                 moments
                                )

        # Declaring a linear system object which will evolve the defined physical system:
        nls = nonlinear_solver(system)
        N_g = nls.N_ghost

        # Time parameters:
        dt      = 0.001 * 32/nls.N_q1
        t_final = 0.1

        time_array  = np.arange(dt, t_final + dt, dt)
        f_reference = af.broadcast(initialize.initialize_f,
                                   af.broadcast(lambda a, b:a+b, nls.q1_center, - nls.p1_center * t_final), 
                                   nls.q2_center, nls.p1_center, nls.p2_center, nls.p3_center, params
                                  )

        for time_index, t0 in enumerate(time_array):
            nls.strang_timestep(dt)

        error[i] = af.mean(af.abs(  nls.f[:, :, N_g:-N_g, N_g:-N_g] 
                                  - f_reference[:, :, N_g:-N_g, N_g:-N_g]
                                 )
                          )

    return(error)
예제 #18
0
def check_error(params):
    error = np.zeros(N.size)

    for i in range(N.size):
        domain.N_p1 = int(N[i])
        domain.N_p2 = int(N[i])
        domain.N_p3 = int(N[i])

        # Defining the physical system to be solved:
        system = physical_system(domain, boundary_conditions, params,
                                 initialize, advection_terms,
                                 collision_operator.BGK, moments)

        # Declaring a linear system object which will evolve the defined physical system:
        nls = nonlinear_solver(system)

        # Time parameters:
        dt = 0.0001 * 32 / nls.N_p1
        t_final = 0.2

        time_array = np.arange(dt, t_final + dt, dt)

        if (time_array[-1] > t_final):
            time_array = np.delete(time_array, -1)

        # Finding final resting point of the blob:
        E1 = nls.fields_solver.cell_centered_EM_fields[0]
        E2 = nls.fields_solver.cell_centered_EM_fields[1]
        E3 = nls.fields_solver.cell_centered_EM_fields[2]

        B1 = nls.fields_solver.cell_centered_EM_fields[3]
        B2 = nls.fields_solver.cell_centered_EM_fields[4]
        B3 = nls.fields_solver.cell_centered_EM_fields[5]

        sol = odeint(dp_dt,
                     np.array([0, 0, 0]),
                     time_array,
                     args=(af.mean(E1), af.mean(E2), af.mean(E3), af.mean(B1),
                           af.mean(B2), af.mean(B3), af.sum(params.charge[0]),
                           af.sum(params.mass[0])),
                     atol=1e-12,
                     rtol=1e-12)

        f_reference = af.broadcast(initialize.initialize_f, nls.q1_center,
                                   nls.q2_center, nls.p1_center - sol[-1, 0],
                                   nls.p2_center - sol[-1, 1],
                                   nls.p3_center - sol[-1, 2], params)

        for time_index, t0 in enumerate(time_array):
            nls.strang_timestep(dt)

        error[i] = af.mean(af.abs(nls.f - f_reference))

    return (error)
예제 #19
0
파일: _array.py 프로젝트: eeeedgar/model_1
def _binary_method(rhs, func, broadcast: bool = False) -> 'ndarray':
    _verify_operand(rhs)
    argument = None
    if isinstance(rhs, ndarray):
        argument = rhs._af_array
    else:
        argument = rhs

    if broadcast:
        new_af_array = af.broadcast(func, argument)
    else:
        new_af_array = func(argument)
    return ndarray(new_af_array)
예제 #20
0
def f_interp_2d(self, dt):
    """
    Performs 2D interpolation in the q-space to solve for the equation:
    
    df/dt + A_q1 df/dq1 + A_q2 df/dq2 = 0

    This is done by backtracing the characteristic curves
    and interpolating at the origin of the characteristics.

    Parameters
    ----------

    dt : double
         Time-step size to evolve the system
    """
    if(self.performance_test_flag == True):
        tic = af.time()

    A_q1, A_q2 = af.broadcast(self._A_q, self.f, self.time_elapsed, 
                              self.q1_center, self.q2_center,
                              self.p1_center, self.p2_center, self.p3_center,
                              self.physical_system.params
                             )

    # Using the add method wrapped with af.broadcast
    q1_center_new = add(self.q1_center, - A_q1 * dt)
    q2_center_new = add(self.q2_center, - A_q2 * dt)

    # Reordering from (dof, N_s, N_q1, N_q2) --> (N_q1, N_q2, N_s, dof)
    # NOTE: To be changed after the implementation of axes specific 
    # interpolation operators gets completed from ArrayFire's end.
    # Ref:https://github.com/arrayfire/arrayfire/issues/1955
    self.f = af.approx2(af.reorder(self.f, 2, 3, 1, 0),
                        af.reorder(q1_center_new, 2, 3, 1, 0),
                        af.reorder(q2_center_new, 2, 3, 1, 0),
                        af.INTERP.BICUBIC_SPLINE, 
                        xp = af.reorder(self.q1_center, 2, 3, 1, 0),
                        yp = af.reorder(self.q2_center, 2, 3, 1, 0)
                       )

    # Reordering from (N_q1, N_q2, N_s, dof) --> (dof, N_s, N_q1, N_q2)
    self.f = af.reorder(self.f, 3, 2, 0, 1)

    af.eval(self.f)

    if(self.performance_test_flag == True):
        af.sync()
        toc = af.time()
        self.time_interp2 += toc - tic

    return
예제 #21
0
def check_error(params):
    error = np.zeros(N.size)

    for i in range(N.size):
        domain.N_p1 = int(N[i])
        # Defining the physical system to be solved:
        system = physical_system(domain, boundary_conditions, params,
                                 initialize, advection_terms,
                                 collision_operator.BGK, moments)

        # Declaring a linear system object which will evolve the defined physical system:
        nls = nonlinear_solver(system)

        # Time parameters:
        dt = 0.01 * 32 / nls.N_p1
        t_final = 0.2

        time_array = np.arange(dt, t_final + dt, dt)

        (A_p1, A_p2,
         A_p3) = af.broadcast(nls._A_p, nls.f, 0, nls.q1_center, nls.q2_center,
                              nls.p1_center, nls.p2_center, nls.p3_center,
                              nls.fields_solver, nls.physical_system.params)

        f_analytic = af.broadcast(initialize.initialize_f, nls.q1_center,
                                  nls.q2_center,
                                  add(nls.p1_center, -A_p1 * t_final),
                                  add(nls.p2_center, -A_p2 * t_final),
                                  nls.p3_center, nls.physical_system.params)

        for time_index, t0 in enumerate(time_array):
            nls.strang_timestep(dt)

        error[i] = af.mean(af.abs(nls.f - f_analytic))

    return (error)
예제 #22
0
    def _initialize(self, params):
        """
        Called when the solver object is declared. This function is
        used to initialize the distribution function, and the field
        quantities using the options as provided by the user. The
        quantities are then mapped to the fourier basis by taking FFTs.
        The independant modes are then evolved by using the linear
        solver.

        Parameters:
        -----------
        params: The parameters file/object that is originally declared 
                by the user.

        """
        # af.broadcast(function, *args) performs batched
        # operations on function(*args):
        f = af.broadcast(self.physical_system.initial_conditions.\
                         initialize_f, self.q1_center, self.q2_center,
                         self.p1, self.p2, self.p3, params
                        )

        # Taking FFT:
        self.f_hat = fft2(f)

        # Since (k_q1, k_q2) = (0, 0) will give the background distribution:
        # The division by (self.N_q1 * self.N_q2) is performed since the FFT
        # at (0, 0) returns (amplitude * (self.N_q1 * self.N_q2))
        self.f_background = af.abs(self.f_hat[:, :, 0,
                                              0]) / (self.N_q1 * self.N_q2)

        # Calculating derivatives of the background distribution function:
        self._calculate_dfdp_background()

        # Scaling Appropriately:
        # Except the case of (0, 0) the FFT returns
        # (0.5 * amplitude * (self.N_q1 * self.N_q2)):
        self.f_hat = 2 * self.f_hat / (self.N_q1 * self.N_q2)

        rho_initial = multiply(self.physical_system.params.charge,
                               self.compute_moments('density'))

        self.fields_solver = fields_solver(self.q1_center, self.q2_center,
                                           self.k_q1, self.k_q2,
                                           self.physical_system.params,
                                           rho_initial)

        return
예제 #23
0
def volume_integral(u, advec_var):
    '''
    Vectorize, p, q, moddims.
    '''
    dLp_xi_ij_Lq_eta_ij = advec_var.dLp_Lq
    dLq_eta_ij_Lp_xi_ij = advec_var.dLq_Lp
    dxi_dx = 10.
    deta_dy = 10.
    jacobian = 100.
    c_x = params.c_x
    c_y = params.c_y

    if (params.volume_integrand_scheme_2d == 'Lobatto'
            and params.N_LGL == params.N_quad):
        w_i = af.flat(
            af.transpose(
                af.tile(advec_var.lobatto_weights_quadrature, 1,
                        params.N_LGL)))
        w_j = af.tile(advec_var.lobatto_weights_quadrature, params.N_LGL)
        wi_wj_dLp_xi = af.broadcast(utils.multiply, w_i * w_j,
                                    advec_var.dLp_Lq)
        volume_integrand_ij_1_sp = c_x * dxi_dx * af.broadcast(utils.multiply,\
                                               wi_wj_dLp_xi, u) / jacobian
        wi_wj_dLq_eta = af.broadcast(utils.multiply, w_i * w_j,
                                     advec_var.dLq_Lp)
        volume_integrand_ij_2_sp = c_y * deta_dy * af.broadcast(utils.multiply,\
                                               wi_wj_dLq_eta, u) / jacobian

        volume_integral = af.reorder(
            af.sum(volume_integrand_ij_1_sp + volume_integrand_ij_2_sp, 0), 2,
            1, 0)

    else:
        volume_integrand_ij_1 = c_x * dxi_dx * af.broadcast(utils.multiply,\
                                        dLp_xi_ij_Lq_eta_ij,\
                                        u) / jacobian

        volume_integrand_ij_2 = c_y * deta_dy * af.broadcast(utils.multiply,\
                                        dLq_eta_ij_Lp_xi_ij,\
                                        u) / jacobian

        volume_integrand_ij = af.moddims(volume_integrand_ij_1 + volume_integrand_ij_2, params.N_LGL ** 2,\
                                         (params.N_LGL ** 2) * 100)

        lagrange_interpolation = af.moddims(
            wave_equation_2d.lag_interpolation_2d(volume_integrand_ij,
                                                  advec_var.Li_Lj_coeffs),
            params.N_LGL, params.N_LGL, params.N_LGL**2 * 100)

        volume_integrand_total = utils.integrate_2d_multivar_poly(lagrange_interpolation[:, :, :],\
                                                    params.N_quad,'gauss', advec_var)
        volume_integral = af.transpose(
            af.moddims(volume_integrand_total, 100, params.N_LGL**2))

    return volume_integral
예제 #24
0
def compute_moments(self, moment_name, f=None):
    """
    Used in computing the moments of the distribution function.
    The moment definitions which are passed to physical system
    are used in computing these moment quantities.

    Parameters
    ----------

    moments_name : str
                   Pass the moment name which needs to be computed.
                   It must be noted that this needs to be defined by the
                   user under moments under src and passed to the 
                   physical_system object.
    
    f: af.Array
       Pass this argument as well when you want to compute the 
       moments of the input array and not the one stored by the state vector
       of the object.

    Examples
    --------
    
    >> solver.compute_moments('density')

    The above line will lookup the definition for 'density' and calculate the same
    accordingly
    """
    p1 = self.p1_center
    p2 = self.p2_center
    p3 = self.p3_center

    if (f is None):
        f = self.f

    #measure = (4./(2.*np.pi*self.physical_system.params.h_bar)**2) * self.dp3 * self.dp2 * self.dp1

    moment = af.broadcast(getattr(self.physical_system.moments,
                                  moment_name), f, p1, p2, p3,
                          self.physical_system.params.integral_measure)

    af.eval(moment)
    return (moment)
예제 #25
0
def trial_dx_dxi(x_nodes, xi, eta):
    '''
    '''

    dN_0_dxi = -0.25 * eta**2 + (0.5 * eta + 0.5) * xi - 0.25 * eta
    dN_1_dxi = 0.5 * eta**2 - 0.5
    dN_2_dxi = -0.25 * eta**2 + (-0.5 * eta + 0.5) * xi + 0.25 * eta
    dN_3_dxi = (eta - 1.0) * xi
    dN_4_dxi = 0.25 * eta**2 + (-0.5 * eta + 0.5) * xi - 0.25 * eta
    dN_5_dxi = -0.5 * eta**2 + 0.5
    dN_6_dxi = 0.25 * eta**2 + (0.5 * eta + 0.5) * xi + 0.25 * eta
    dN_7_dxi = (-1.0 * eta - 1.0) * xi

    dx_dxi = af.broadcast(utils.multiply, dN_0_dxi, x_nodes[0]) \
           + af.broadcast(utils.multiply, dN_1_dxi, x_nodes[1]) \
           + af.broadcast(utils.multiply, dN_2_dxi, x_nodes[2]) \
           + af.broadcast(utils.multiply, dN_3_dxi, x_nodes[3]) \
           + af.broadcast(utils.multiply, dN_4_dxi, x_nodes[4]) \
           + af.broadcast(utils.multiply, dN_5_dxi, x_nodes[5]) \
           + af.broadcast(utils.multiply, dN_6_dxi, x_nodes[6]) \
           + af.broadcast(utils.multiply, dN_7_dxi, x_nodes[7])

    return dx_dxi
예제 #26
0
def volume_integral(u, gv):
    '''
    Vectorize, p, q, moddims.
    '''
    dLp_xi_ij_Lq_eta_ij = gv.dLp_Lq
    dLq_eta_ij_Lp_xi_ij = gv.dLq_Lp

    if (params.volume_integrand_scheme_2d == 'Lobatto'
            and params.N_LGL == params.N_quad):
        w_i = af.flat(
            af.transpose(
                af.tile(gv.lobatto_weights_quadrature, 1, params.N_LGL)))
        w_j = af.tile(gv.lobatto_weights_quadrature, params.N_LGL)
        wi_wj_dLp_xi = af.broadcast(utils.multiply, w_i * w_j, gv.dLp_Lq)
        volume_integrand_ij_1_sp = af.broadcast(utils.multiply,\
                                               wi_wj_dLp_xi, F_xi(u, gv) * gv.sqrt_g)
        wi_wj_dLq_eta = af.broadcast(utils.multiply, w_i * w_j, gv.dLq_Lp)
        volume_integrand_ij_2_sp = af.broadcast(utils.multiply,\
                                               wi_wj_dLq_eta, F_eta(u, gv) * gv.sqrt_g)

        volume_integral = af.reorder(
            af.sum(volume_integrand_ij_1_sp + volume_integrand_ij_2_sp, 0), 2,
            1, 0)

    else:  # NEEDS TO BE CHANGED
        volume_integrand_ij_1 = af.broadcast(utils.multiply,\
                                        dLp_xi_ij_Lq_eta_ij,\
                                        F_xi(u, gv))

        volume_integrand_ij_2 = af.broadcast(utils.multiply,\
                                             dLq_eta_ij_Lp_xi_ij,\
                                             F_eta(u, gv))

        volume_integrand_ij = af.moddims((volume_integrand_ij_1 + volume_integrand_ij_2)\
                                        * np.mean(gv.sqrt_det_g), params.N_LGL ** 2,\
                                         (params.N_LGL ** 2) * 100)

        lagrange_interpolation = af.moddims(
            lag_interpolation_2d(volume_integrand_ij, gv.Li_Lj_coeffs),
            params.N_LGL, params.N_LGL, params.N_LGL**2 * 100)

        volume_integrand_total = utils.integrate_2d_multivar_poly(lagrange_interpolation[:, :, :],\
                                                    params.N_quad,'gauss', gv)
        volume_integral = af.transpose(
            af.moddims(volume_integrand_total, 100, params.N_LGL**2))

    return volume_integral
예제 #27
0
    def _initialize(self, params):
        """
        Called when the solver object is declared. This function is
        used to initialize the distribution function, using the options
        as provided by the user.

        Parameters
        ----------

        params : module
                 params contains all details of which methods to use
                 in addition to useful physical constant. Additionally, 
                 it can also be used to inject methods which need to be 
                 used inside some solver routine

        """
        # Initializing with the provided I.C's:
        # af.broadcast, allows us to perform batched operations 
        # when operating on arrays of different sizes
        # af.broadcast(function, *args) performs batched 
        # operations on function(*args)
        self.f = af.broadcast(self.physical_system.initial_conditions.\
                              initialize_f, self.q1_center, self.q2_center,
                              self.p1_center, self.p2_center, self.p3_center, params
                             )

        self.f_initial = self.f

        if(self.physical_system.params.fields_enabled):
            
            rho_initial = multiply(self.physical_system.params.charge,
                                   self.compute_moments('density')
                                  )
            
            self.fields_solver = fields_solver(self.physical_system, rho_initial, 
                                               self.performance_test_flag
                                              )
예제 #28
0
def lag_interpolation_2d(u_e_ij, Li_Lj_coeffs):
    '''
    Does the lagrange interpolation of a function.
    
    Parameters
    ----------
    
    u_e_ij : af.Array [N_LGL^2 N_elements 1 1]
             Value of the function calculated at the :math:`(\\xi_i, \\eta_j)`
             points in this form
             
             .. math:: \\xi_i = [\\xi_0, \\xi_0, ..., \\xi_0, \\xi_1, \\
                       ... ..., \\xi_N]
             .. math:: \\eta_j = [\\eta_0, \\eta_1, ..., \\eta_N, \\
                       \\eta_0, ... ..., \\eta_N]

    N_LGL : int
            Number of LGL points

    Returns
    -------
    interpolated_f : af.Array [N_LGL N_LGL N_elements 1]
                     Interpolation polynomials for ``N_elements`` elements.
    '''
    Li_xi_Lj_eta_coeffs = af.tile(Li_Lj_coeffs,
                                  d0=1,
                                  d1=1,
                                  d2=1,
                                  d3=utils.shape(u_e_ij)[1])
    u_e_ij = af.reorder(u_e_ij, 2, 3, 0, 1)

    f_ij_Li_Lj_coeffs = af.broadcast(utils.multiply, u_e_ij,
                                     Li_xi_Lj_eta_coeffs)
    interpolated_f = af.reorder(af.sum(f_ij_Li_Lj_coeffs, 2), 0, 1, 3, 2)

    return interpolated_f
예제 #29
0
# An array containing the coefficients of the lagrange basis polynomials.
lagrange_coeffs            = af.np_to_af_array(\
                                lagrange.lagrange_polynomials(xi_LGL)[1])

# Refer corresponding functions.
lagrange_basis_value = lagrange.lagrange_function_value(lagrange_coeffs)


# While evaluating the volume integral using N_LGL
# lobatto quadrature points, The integration can be vectorized
# and in this case the coefficients of the differential of the
# Lagrange polynomials is required


diff_pow      = (af.flip(af.transpose(af.range(N_LGL - 1) + 1), 1))
dl_dxi_coeffs = (af.broadcast(utils.multiply, lagrange_coeffs[:, :-1], diff_pow))

# Obtaining an array consisting of the LGL points mapped onto the elements.

element_size    = af.sum((x_nodes[1] - x_nodes[0]) / N_Elements)
elements_xi_LGL = af.constant(0, N_Elements, N_LGL)
elements        = utils.linspace(af.sum(x_nodes[0]),
                  af.sum(x_nodes[1] - element_size), N_Elements)

np_element_array   = np.concatenate((af.transpose(elements),
                                     af.transpose(elements + element_size)))
element_mesh_nodes = utils.linspace(af.sum(x_nodes[0]),
                                    af.sum(x_nodes[1]),
                                    N_Elements + 1)

element_array = af.transpose(af.interop.np_to_af_array(np_element_array))
예제 #30
0
def simple_arith(verbose = False):
    display_func = _util.display_func(verbose)
    print_func   = _util.print_func(verbose)

    a = af.randu(3,3,dtype=af.Dtype.u32)
    b = af.constant(4, 3, 3, dtype=af.Dtype.u32)
    display_func(a)
    display_func(b)

    c = a + b
    d = a
    d += b

    display_func(c)
    display_func(d)
    display_func(a + 2)
    display_func(3 + a)


    c = a - b
    d = a
    d -= b

    display_func(c)
    display_func(d)
    display_func(a - 2)
    display_func(3 - a)

    c = a * b
    d = a
    d *= b

    display_func(c * 2)
    display_func(3 * d)
    display_func(a * 2)
    display_func(3 * a)

    c = a / b
    d = a
    d /= b

    display_func(c / 2.0)
    display_func(3.0 / d)
    display_func(a / 2)
    display_func(3 / a)

    c = a % b
    d = a
    d %= b

    display_func(c % 2.0)
    display_func(3.0 % d)
    display_func(a % 2)
    display_func(3 % a)

    c = a ** b
    d = a
    d **= b

    display_func(c ** 2.0)
    display_func(3.0 ** d)
    display_func(a ** 2)
    display_func(3 ** a)

    display_func(a < b)
    display_func(a < 0.5)
    display_func(0.5 < a)

    display_func(a <= b)
    display_func(a <= 0.5)
    display_func(0.5 <= a)

    display_func(a > b)
    display_func(a > 0.5)
    display_func(0.5 > a)

    display_func(a >= b)
    display_func(a >= 0.5)
    display_func(0.5 >= a)

    display_func(a != b)
    display_func(a != 0.5)
    display_func(0.5 != a)

    display_func(a == b)
    display_func(a == 0.5)
    display_func(0.5 == a)

    display_func(a & b)
    display_func(a & 2)
    c = a
    c &= 2
    display_func(c)

    display_func(a | b)
    display_func(a | 2)
    c = a
    c |= 2
    display_func(c)

    display_func(a >> b)
    display_func(a >> 2)
    c = a
    c >>= 2
    display_func(c)

    display_func(a << b)
    display_func(a << 2)
    c = a
    c <<= 2
    display_func(c)

    display_func(-a)
    display_func(+a)
    display_func(~a)
    display_func(a)

    display_func(af.cast(a, af.Dtype.c32))
    display_func(af.maxof(a,b))
    display_func(af.minof(a,b))
    display_func(af.rem(a,b))

    a = af.randu(3,3) - 0.5
    b = af.randu(3,3) - 0.5

    display_func(af.abs(a))
    display_func(af.arg(a))
    display_func(af.sign(a))
    display_func(af.round(a))
    display_func(af.trunc(a))
    display_func(af.floor(a))
    display_func(af.ceil(a))
    display_func(af.hypot(a, b))
    display_func(af.sin(a))
    display_func(af.cos(a))
    display_func(af.tan(a))
    display_func(af.asin(a))
    display_func(af.acos(a))
    display_func(af.atan(a))
    display_func(af.atan2(a, b))

    c = af.cplx(a)
    d = af.cplx(a,b)
    display_func(c)
    display_func(d)
    display_func(af.real(d))
    display_func(af.imag(d))
    display_func(af.conjg(d))

    display_func(af.sinh(a))
    display_func(af.cosh(a))
    display_func(af.tanh(a))
    display_func(af.asinh(a))
    display_func(af.acosh(a))
    display_func(af.atanh(a))

    a = af.abs(a)
    b = af.abs(b)

    display_func(af.root(a, b))
    display_func(af.pow(a, b))
    display_func(af.pow2(a))
    display_func(af.exp(a))
    display_func(af.expm1(a))
    display_func(af.erf(a))
    display_func(af.erfc(a))
    display_func(af.log(a))
    display_func(af.log1p(a))
    display_func(af.log10(a))
    display_func(af.log2(a))
    display_func(af.sqrt(a))
    display_func(af.cbrt(a))

    a = af.round(5 * af.randu(3,3) - 1)
    b = af.round(5 * af.randu(3,3) - 1)

    display_func(af.factorial(a))
    display_func(af.tgamma(a))
    display_func(af.lgamma(a))
    display_func(af.iszero(a))
    display_func(af.isinf(a/b))
    display_func(af.isnan(a/a))

    a = af.randu(5, 1)
    b = af.randu(1, 5)
    c = af.broadcast(lambda x,y: x+y, a, b)
    display_func(a)
    display_func(b)
    display_func(c)

    @af.broadcast
    def test_add(aa, bb):
        return aa + bb

    display_func(test_add(a, b))
af.display(af.erfc(a))
af.display(af.log(a))
af.display(af.log1p(a))
af.display(af.log10(a))
af.display(af.log2(a))
af.display(af.sqrt(a))
af.display(af.cbrt(a))

a = af.round(5 * af.randu(3,3) - 1)
b = af.round(5 * af.randu(3,3) - 1)

af.display(af.factorial(a))
af.display(af.tgamma(a))
af.display(af.lgamma(a))
af.display(af.iszero(a))
af.display(af.isinf(a/b))
af.display(af.isnan(a/a))

a = af.randu(5, 1)
b = af.randu(1, 5)
c = af.broadcast(lambda x,y: x+y, a, b)
af.display(a)
af.display(b)
af.display(c)

@af.broadcast
def test_add(aa, bb):
    return aa + bb

af.display(test_add(a, b))
예제 #32
0
def volume_integral_flux(u_n):
    '''
    Calculates the volume integral of flux in the wave equation.
    :math:`\\int_{-1}^1 f(u) \\frac{d L_p}{d\\xi} d\\xi`
    This will give N values of flux integral as p varies from 0 to N - 1.
    
    This integral is carried out using the analytical form of the integrand
    obtained as a linear combination of Lagrange basis polynomials.
    This integrand is the used in the integrate() function.
    Calculation of volume integral flux using N_LGL Lobatto quadrature points
    can be vectorized and is much faster.
    
    Parameters
    ----------
    u : arrayfire.Array [N_LGL N_Elements M 1]
        Amplitude of the wave at the mapped LGL nodes of each element. This
        function can computer flux for :math:`M` :math:`u`.
            
    Returns
    -------
    flux_integral : arrayfire.Array [N_LGL N_Elements M 1]
                    Value of the volume integral flux. It contains the integral
                    of all N_LGL * N_Element integrands.
    '''
    shape_u_n = utils.shape(u_n)
    
    # The coefficients of dLp / d\xi
    diff_lag_coeff  = params.dl_dxi_coeffs

    lobatto_nodes   = params.lobatto_quadrature_nodes
    Lobatto_weights = params.lobatto_weights_quadrature

    #nodes_tile   = af.transpose(af.tile(lobatto_nodes, 1, diff_lag_coeff.shape[1]))
    #power        = af.flip(af.range(diff_lag_coeff.shape[1]))
    #power_tile   = af.tile(power, 1, params.N_quad)
    #nodes_power  = nodes_tile ** power_tile
    #weights_tile = af.transpose(af.tile(Lobatto_weights, 1, diff_lag_coeff.shape[1]))
    #nodes_weight = nodes_power * weights_tile

    #dLp_dxi      = af.matmul(diff_lag_coeff, nodes_weight)
    
    dLp_dxi      = af.np_to_af_array(params.b_matrix)


    # The first option to calculate the volume integral term, directly uses
    # the Lobatto quadrature instead of using the integrate() function by
    # passing the coefficients of the Lagrange interpolated polynomial.
    if(params.volume_integral_scheme == 'lobatto_quadrature' \
        and params.N_quad == params.N_LGL):

        # Flux using u_n, reordered to 1 X N_LGL X N_Elements array.
        F_u_n                  = af.reorder(flux_x(u_n), 3, 0, 1, 2)
        F_u_n = af.tile(F_u_n, d0 = params.N_LGL)

        # Multiplying with dLp / d\xi
        integral_expansion     = af.broadcast(utils.multiply,
                                            dLp_dxi, F_u_n)

    #     # Using the quadrature rule.
        flux_integral = af.sum(integral_expansion, 1)

        flux_integral = af.reorder(flux_integral, 0, 2, 3, 1)

    # Using the integrate() function to calculate the volume integral term
    # by passing the Lagrange interpolated polynomial.
    else:
        #print('option3')
        analytical_flux_coeffs = af.transpose(af.moddims(u_n,
                                                        d0 = params.N_LGL,
                                                        d1 = params.N_Elements \
                                                            * shape_u_n[2]))
        
        analytical_flux_coeffs = flux_x(
            lagrange.lagrange_interpolation(analytical_flux_coeffs))
        analytical_flux_coeffs = af.transpose(
            af.moddims(af.transpose(analytical_flux_coeffs),
                       d0 = params.N_LGL, d1 = params.N_Elements,
                       d2 = shape_u_n[2]))
        
        analytical_flux_coeffs = af.reorder(analytical_flux_coeffs,
                                            d0 = 3, d1 = 1, d2 = 0, d3 = 2)
        analytical_flux_coeffs = af.tile(analytical_flux_coeffs,
                                         d0 = params.N_LGL)
        analytical_flux_coeffs = af.moddims(
            af.transpose(analytical_flux_coeffs),
            d0 = params.N_LGL,
            d1 = params.N_LGL * params.N_Elements, d2 = 1,
            d3 = shape_u_n[2])
        
        analytical_flux_coeffs = af.moddims(
            analytical_flux_coeffs, d0 = params.N_LGL,
            d1 = params.N_LGL * params.N_Elements * shape_u_n[2],
            d2 = 1, d3 = 1)
        
        analytical_flux_coeffs = af.transpose(analytical_flux_coeffs)

        dl_dxi_coefficients    = af.tile(af.tile(params.dl_dxi_coeffs,
                                                 d0 = params.N_Elements), \
                                         d0 = shape_u_n[2])

        volume_int_coeffs = utils.poly1d_product(dl_dxi_coefficients,
                                                analytical_flux_coeffs)
        
        flux_integral = lagrange.integrate(volume_int_coeffs)
        flux_integral = af.moddims(af.transpose(flux_integral),
                                   d0 = params.N_LGL,
                                   d1 = params.N_Elements,
                                   d2 = shape_u_n[2])

    return flux_integral