Esempio n. 1
0
def lobatto_quad_multivar_poly(poly_xi_eta, N_quad, advec_var):
    '''
    '''
    shape_poly_2d = shape(poly_xi_eta)

    xi_LGL  = lagrange.LGL_points(N_quad)
    eta_LGL = lagrange.LGL_points(N_quad)

    Xi, Eta = af_meshgrid(xi_LGL, eta_LGL)

    Xi  = af.flat(Xi)
    Eta = af.flat(Eta)

    w_i = lagrange.lobatto_weights(N_quad)
    w_j = lagrange.lobatto_weights(N_quad)

    W_i, W_j = af_meshgrid(w_i, w_j)

    W_i = af.tile(af.flat(W_i), d0 = 1, d1 = shape_poly_2d[2])
    W_j = af.tile(af.flat(W_j), d0 = 1, d1 = shape_poly_2d[2])

    P_xi_eta_quad_val = af.transpose(polyval_2d(poly_xi_eta, Xi, Eta))

    integral = af.sum(W_i * W_j * P_xi_eta_quad_val, dim = 0)

    return af.transpose(integral)
def test_dy_dxi():
    '''
    This test checks the derivative :math:`\\frac{\\partial y}{\\partial \\xi}`
    calculated using the function :math:`dg_maxwell.wave_equation_2d.dy_dxi`
    for the :math:`0^{th}` element of a mesh for a circular ring. You may
    download the file from this
    :download:`link <../dg_maxwell/tests/wave_equation_2d/files/circle.msh>`.
    '''
    threshold = 1e-7

    dy_dxi_reference = af.np_to_af_array(
        utils.csv_to_numpy(
            'dg_maxwell/tests/wave_equation_2d/files/dy_dxi_data.csv'))

    nodes, elements = msh_parser.read_order_2_msh(
        'dg_maxwell/tests/wave_equation_2d/files/circle.msh')

    N_LGL = 16
    xi_LGL = lagrange.LGL_points(N_LGL)
    eta_LGL = lagrange.LGL_points(N_LGL)
    Xi = af.data.tile(af.array.transpose(xi_LGL), d0=N_LGL)
    Eta = af.data.tile(eta_LGL, d0=1, d1=N_LGL)

    dy_dxi = wave_equation_2d.dy_dxi(nodes[elements[0]][:, 1], Xi, Eta)

    check = af.abs(dy_dxi - dy_dxi_reference) < threshold

    assert af.all_true(check)
Esempio n. 3
0
def test_Li_basis_value():
    '''
    This test compares the output of the lagrange basis value calculated by the
    function ``Li_basis_value`` to the analytical value of the lagrange
    polynomials created using the same LGL points.
    The analytical values were calculated in this sage worksheet_
    
    .. _worksheet: https://goo.gl/ADyA3U
    '''
    
    threshold = 1e-11
    
    Li_value_ref = af.np_to_af_array(utils.csv_to_numpy(
        'dg_maxwell/tests/lagrange/files/Li_value.csv'))
    
    N_LGL = 8
    xi_LGL = lagrange.LGL_points(N_LGL)
    L_basis_poly1d, L_basis_af = lagrange.lagrange_polynomials(xi_LGL)
    L_basis_af = af.np_to_af_array(L_basis_af)
    
    Li_indexes = af.np_to_af_array(np.arange(3, dtype = np.int32))
    xi = af.np_to_af_array(np.linspace(-1., 1, 10))
                           
    Li_value = lagrange.Li_basis_value(L_basis_af, Li_indexes, xi)
    
    assert af.all_true(af.abs(Li_value - Li_value_ref) < threshold)
def test_interpolation():
    '''
    '''
    threshold = 8e-9
    params.N_LGL = 8

    gv = gvar.advection_variables(params.N_LGL, params.N_quad,\
                                          params.x_nodes, params.N_Elements,\
                                          params.c, params.total_time, params.wave,\
                                          params.c_x, params.c_y, params.courant,\
                                          params.mesh_file, params.total_time_2d)

    N_LGL = 8
    xi_LGL = lagrange.LGL_points(N_LGL)
    xi_i = af.flat(af.transpose(af.tile(xi_LGL, 1, N_LGL)))
    eta_j = af.tile(xi_LGL, N_LGL)
    f_ij = np.e**(xi_i + eta_j)
    interpolated_f = wave_equation_2d.lag_interpolation_2d(
        f_ij, gv.Li_Lj_coeffs)
    xi = utils.linspace(-1, 1, 8)
    eta = utils.linspace(-1, 1, 8)

    assert (af.mean(
        af.transpose(utils.polyval_2d(interpolated_f, xi, eta)) -
        np.e**(xi + eta)) < threshold)
Esempio n. 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.
Esempio n. 6
0
def test_integrate_1d():
    '''
    Tests the ``integrate_1d`` by comparing the integral agains the
    analytically calculated integral. The polynomials to be integrated
    are all the Lagrange polynomials obtained for the LGL points.
    
    The analytical integral is calculated in this `sage worksheet`_
    
    .. _sage worksheet: https://goo.gl/1uYyNJ
    '''

    threshold = 1e-12

    N_LGL = 8
    xi_LGL = lagrange.LGL_points(N_LGL)
    eta_LGL = lagrange.LGL_points(N_LGL)
    _, Li_xi = lagrange.lagrange_polynomials(xi_LGL)
    _, Lj_eta = lagrange.lagrange_polynomials(eta_LGL)

    Li_xi = af.np_to_af_array(Li_xi)
    Lp_xi = Li_xi.copy()

    Li_Lp = utils.poly1d_product(Li_xi, Lp_xi)

    test_integral_gauss = utils.integrate_1d(Li_Lp, order=9, scheme='gauss')

    test_integral_lobatto = utils.integrate_1d(Li_Lp,
                                               order=N_LGL + 1,
                                               scheme='lobatto')

    ref_integral = af.np_to_af_array(
        np.array([
            0.0333333333333, 0.196657278667, 0.318381179651, 0.384961541681,
            0.384961541681, 0.318381179651, 0.196657278667, 0.0333333333333
        ]))

    diff_gauss = af.abs(ref_integral - test_integral_gauss)
    diff_lobatto = af.abs(ref_integral - test_integral_lobatto)

    assert af.all_true(diff_gauss < threshold) and af.all_true(
        diff_lobatto < threshold)
Esempio n. 7
0
def Li_Lj_coeffs(N_LGL):
    '''
    '''
    xi_LGL = lagrange.LGL_points(N_LGL)
    lagrange_coeffs = af.np_to_af_array(
        lagrange.lagrange_polynomials(xi_LGL)[1])

    Li_xi = af.moddims(af.tile(af.reorder(lagrange_coeffs, 1, 2, 0), 1, N_LGL),
                       N_LGL, 1, N_LGL**2)

    Lj_eta = af.tile(af.reorder(lagrange_coeffs, 1, 2, 0), 1, 1, N_LGL)

    Li_Lj_coeffs = utils.polynomial_product_coeffs(Li_xi, Lj_eta)

    return Li_Lj_coeffs
Esempio n. 8
0
def test_LGL_points():
    '''
    Comparing the LGL nodes obtained by LGL_points with
    the reference nodes for N = 6
    '''
    reference_nodes  = \
        af.np_to_af_array(np.array([-1.,                 -0.7650553239294647,\
                                    -0.28523151648064504, 0.28523151648064504,\
                                     0.7650553239294647,  1. \
                                   ] \
                                  ) \
                         )

    calculated_nodes = (lagrange.LGL_points(6))
    assert (af.max(af.abs(reference_nodes - calculated_nodes)) <= 1e-14)
Esempio n. 9
0
def time_evolution(gv):
    '''
    '''
    # Creating a folder to store hdf5 files. If it doesn't exist.
    results_directory = 'results/xi_eta_2d_hdf5_%02d' % (int(params.N_LGL))
    if not os.path.exists(results_directory):
        os.makedirs(results_directory)

    A_inverse = af.np_to_af_array(
        np.linalg.inv(np.array(A_matrix_xi_eta(params.N_LGL, gv))))
    xi_LGL = lagrange.LGL_points(params.N_LGL)
    xi_i = af.flat(af.transpose(af.tile(xi_LGL, 1, params.N_LGL)))
    eta_j = af.tile(xi_LGL, params.N_LGL)

    u_init_2d = gv.u_e_ij
    delta_t = gv.delta_t_2d
    time = gv.time
    u = u_init_2d
    time = gv.time_2d

    for i in trange(0, time.shape[0]):
        L1_norm = af.mean(af.abs(u_init_2d - u))

        if (L1_norm >= 100):
            print(L1_norm)
            break
        if (i % 10) == 0:
            h5file = h5py.File(
                'results/xi_eta_2d_hdf5_%02d/dump_timestep_%06d' %
                (int(params.N_LGL), int(i)) + '.hdf5', 'w')
            dset = h5file.create_dataset('u_i', data=u, dtype='d')

            dset[:, :] = u[:, :]

        u += RK4_timestepping(A_inverse, u, delta_t, gv)

    return L1_norm
Esempio n. 10
0
volume_integral_scheme = 'lobatto_quadrature'

# The number quadrature points to be used for integration.
N_quad     = 8

# Wave speed.
c          = 1.0

# The total time for which the wave is to be evolved by the simulation. 
total_time = 2.01

# The c_lax to be used in the Lax-Friedrichs flux.
c_lax      = abs(c)

# Array containing the LGL points in xi space.
xi_LGL     = lagrange.LGL_points(N_LGL)

#Calculates the weights for the lagrange interpolation 
weight_arr = lagrange.weight_arr_fun(xi_LGL)

# N_Gauss number of Gauss nodes.
gauss_points               = af.np_to_af_array(lagrange.gauss_nodes(N_quad))

# The Gaussian weights.
gauss_weights              = lagrange.gaussian_weights(N_quad)

# The lobatto nodes to be used for integration.
lobatto_quadrature_nodes   = lagrange.LGL_points(N_quad)

# The lobatto weights to be used for integration.
lobatto_weights_quadrature = lagrange.lobatto_weights\
Esempio n. 11
0
def A_matrix(N_LGL, advec_var):
    '''
    Calculates the tensor product for the given ``params.N_LGL``.
    A tensor product element is given by:

    .. math:: [A^{pq}_{ij}] = \\iint L_p(\\xi) L_q(\\eta) \\
                                     L_i(\\xi) L_j(\\eta) d\\xi d\\eta

    This function finds :math:`L_p(\\xi) L_i(\\xi)` and
    :math:`L_q(\\eta) L_j(\\eta)` and passes it to the ``integrate_2d``
    function.

    Returns
    -------
    A : af.Array [N_LGL^2 N_LGL^2 1 1]
        The tensor product.
    '''
    xi_LGL = lagrange.LGL_points(N_LGL)
    lagrange_coeffs = af.np_to_af_array(
        lagrange.lagrange_polynomials(xi_LGL)[1])

    xi_LGL = lagrange.LGL_points(N_LGL)
    eta_LGL = lagrange.LGL_points(N_LGL)

    _, Lp_xi = lagrange.lagrange_polynomials(xi_LGL)
    _, Lq_eta = lagrange.lagrange_polynomials(eta_LGL)
    Lp_xi = af.np_to_af_array(Lp_xi)
    Lq_eta = af.np_to_af_array(Lq_eta)
    Li_xi = Lp_xi.copy()
    Lj_eta = Lq_eta.copy()

    Lp_xi_tp = af.reorder(Lp_xi, d0=2, d1=0, d2=1)
    Lp_xi_tp = af.tile(Lp_xi_tp, d0=N_LGL * N_LGL * N_LGL)
    Lp_xi_tp = af.moddims(Lp_xi_tp,
                          d0=N_LGL * N_LGL * N_LGL * N_LGL,
                          d1=1,
                          d2=N_LGL)
    Lp_xi_tp = af.reorder(Lp_xi_tp, d0=0, d1=2, d2=1)

    Lq_eta_tp = af.reorder(Lq_eta, d0=0, d1=2, d2=1)
    Lq_eta_tp = af.tile(Lq_eta_tp, d0=N_LGL, d1=N_LGL * N_LGL)
    Lq_eta_tp = af.moddims(af.transpose(Lq_eta_tp),
                           d0=N_LGL * N_LGL * N_LGL * N_LGL,
                           d1=1,
                           d2=N_LGL)
    Lq_eta_tp = af.reorder(Lq_eta_tp, d0=0, d1=2, d2=1)

    Li_xi_tp = af.reorder(Li_xi, d0=2, d1=0, d2=1)
    Li_xi_tp = af.tile(Li_xi_tp, d0=N_LGL)
    Li_xi_tp = af.moddims(Li_xi_tp, d0=N_LGL * N_LGL, d1=1, d2=N_LGL)
    Li_xi_tp = af.reorder(Li_xi_tp, d0=0, d1=2, d2=1)
    Li_xi_tp = af.tile(Li_xi_tp, d0=N_LGL * N_LGL)

    Lj_eta_tp = af.reorder(Lj_eta, d0=0, d1=2, d2=1)
    Lj_eta_tp = af.tile(Lj_eta_tp, d0=N_LGL)
    Lj_eta_tp = af.reorder(Lj_eta_tp, d0=0, d1=2, d2=1)
    Lj_eta_tp = af.tile(Lj_eta_tp, d0=N_LGL * N_LGL)

    Lp_Li_tp = utils.poly1d_product(Lp_xi_tp, Li_xi_tp)
    Lq_Lj_tp = utils.poly1d_product(Lq_eta_tp, Lj_eta_tp)

    Lp_Li_Lq_Lj_tp = utils.polynomial_product_coeffs(
        af.reorder(Lp_Li_tp, d0=1, d1=2, d2=0),
        af.reorder(Lq_Lj_tp, d0=1, d1=2, d2=0))

    A = utils.integrate_2d_multivar_poly(Lp_Li_Lq_Lj_tp, params.N_quad,
                                         'gauss', advec_var)

    A = af.moddims(A, d0=N_LGL * N_LGL, d1=N_LGL * N_LGL)

    return A
Esempio n. 12
0
def change_parameters(LGL, Elements, quad, wave='sin'):
    '''
    Changes the parameters of the simulation. Used only for convergence tests.
    Parameters
    ----------
    LGL      : int
               The new N_LGL.
    Elements : int
               The new N_Elements.
    '''
    # The domain of the function.
    params.x_nodes = af.np_to_af_array(np.array([-1., 1.]))

    # The number of LGL points into which an element is split.
    params.N_LGL = LGL

    # Number of elements the domain is to be divided into.
    params.N_Elements = Elements

    # The number quadrature points to be used for integration.
    params.N_quad = quad

    # Array containing the LGL points in xi space.
    params.xi_LGL = lagrange.LGL_points(params.N_LGL)

    # The weights of the lgl points
    params.weight_arr = lagrange.weight_arr_fun(params.xi_LGL)

    # N_Gauss number of Gauss nodes.
    params.gauss_points  = af.np_to_af_array(lagrange.gauss_nodes\
                                                    (params.N_quad))
    # The Gaussian weights.
    params.gauss_weights = lagrange.gaussian_weights(params.N_quad)

    # The lobatto nodes to be used for integration.
    params.lobatto_quadrature_nodes = lagrange.LGL_points(params.N_quad)

    # The lobatto weights to be used for integration.
    params.lobatto_weights_quadrature = lagrange.lobatto_weights\
                                        (params.N_quad)

    #The b matrix
    params.b_matrix = lagrange.b_matrix_eval()

    # A list of the Lagrange polynomials in poly1d form.
    #params.lagrange_product = lagrange.product_lagrange_poly(params.xi_LGL)

    # An array containing the coefficients of the lagrange basis polynomials.
    params.lagrange_coeffs  = af.np_to_af_array(\
                              lagrange.lagrange_polynomials(params.xi_LGL)[1])

    # Refer corresponding functions.
    params.lagrange_basis_value = lagrange.lagrange_function_value\
                                           (params.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
    params.diff_pow = (af.flip(af.transpose(af.range(params.N_LGL - 1) + 1),
                               1))
    params.dl_dxi_coeffs = (af.broadcast(utils.multiply,
                                         params.lagrange_coeffs[:, :-1],
                                         params.diff_pow))

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

    params.element_size    = af.sum((params.x_nodes[1] - params.x_nodes[0])\
                                                        / params.N_Elements)
    params.elements_xi_LGL = af.constant(0, params.N_Elements, params.N_LGL)
    params.elements        = utils.linspace(af.sum(params.x_nodes[0]),
                             af.sum(params.x_nodes[1] - params.element_size),\
                                                            params.N_Elements)
    params.np_element_array   = np.concatenate((af.transpose(params.elements),
                                   af.transpose(params.elements +\
                                                       params.element_size)))

    params.element_mesh_nodes = utils.linspace(af.sum(params.x_nodes[0]),
                                        af.sum(params.x_nodes[1]),\
                                               params.N_Elements + 1)

    params.element_array = af.transpose(af.np_to_af_array\
                                       (params.np_element_array))
    params.element_LGL   = wave_equation.mapping_xi_to_x(af.transpose\
                                          (params.element_array), params.xi_LGL)

    # The minimum distance between 2 mapped LGL points.
    params.delta_x = af.min(
        (params.element_LGL - af.shift(params.element_LGL, 1, 0))[1:, :])

    # dx_dxi for elements of equal size.
    params. dx_dxi = af.mean(wave_equation.dx_dxi_numerical((params.element_mesh_nodes[0 : 2]),\
                                   params.xi_LGL))

    # The value of time-step.
    params.delta_t = params.delta_x / (4 * params.c)

    # Array of timesteps seperated by delta_t.
    params.time = utils.linspace(
        0,
        int(params.total_time / params.delta_t) * params.delta_t,
        int(params.total_time / params.delta_t))

    # Initializing the amplitudes. Change u_init to required initial conditions.
    if (wave == 'sin'):
        params.u_init = af.sin(2 * np.pi * params.element_LGL)

    if (wave == 'gaussian'):
        params.u_init = np.e**(-(params.element_LGL)**2 / 0.4**2)

    params.u          = af.constant(0, params.N_LGL, params.N_Elements, params.time.shape[0],\
                                     dtype = af.Dtype.f64)
    params.u[:, :, 0] = params.u_init

    return
Esempio n. 13
0
    def __init__(self, N_LGL, N_quad, x_nodes, N_elements, c, total_time, wave,
                 c_x, c_y, courant, mesh_file, total_time_2d):
        '''
        Initializes the variables using the user parameters.
        
        Parameters
        ----------
        N_LGL : int
                Number of LGL points(for both :math:`2D` and :math:`1D` wave
                equation solver).
        N_quad : int
                 Number of the quadrature points to use in Gauss-Lobatto or
                 Gauss-Legendre quadrature.
        x_nodes : af.Array [2 1 1 1]
                  :math:`x` nodes for the :math:`1D` wave equation elements.
                  
        N_elements : int
                     Number of elements in a :math:`1D` domain.
                     
        c : float64
            Wave speed for 1D wave equation.
            
        total_time : float64
                     Total time for which :math:`1D` wave equation is to be
                     evolved.
                     
        wave : str
               Used to set u_init to ``sin`` or ``cos``.
               
        c_x : float64
              :math:`x` component of wave speed for a :math:`2D` wave.
              
        c_y : float64
              :math:`y` component of wave speed for a :math:`2D` wave.
              
        courant : float64
                  Courant parameter used for the time evolution of the wave.
                  
        mesh_file : str
                    Path of the mesh file for the 2D wave equation.
                    
        total_time_2d : float64
                        Total time for which the wave is to propogated.
        
        Returns
        -------
        None
        '''

        self.xi_LGL = lagrange.LGL_points(N_LGL)

        # N_Gauss number of Gauss nodes.
        self.gauss_points = af.np_to_af_array(lagrange.gauss_nodes(N_quad))

        # The Gaussian weights.
        self.gauss_weights = lagrange.gaussian_weights(N_quad)

        # The lobatto nodes to be used for integration.
        self.lobatto_quadrature_nodes = lagrange.LGL_points(N_quad)

        # The lobatto weights to be used for integration.
        self.lobatto_weights_quadrature = lagrange.lobatto_weights(N_quad)

        # An array containing the coefficients of the lagrange basis polynomials.
        self.lagrange_coeffs = lagrange.lagrange_polynomial_coeffs(self.xi_LGL)

        self.lagrange_basis_value = lagrange.lagrange_function_value(
            self.lagrange_coeffs, self.xi_LGL)

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

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

        self.np_element_array = np.concatenate(
            (af.transpose(self.elements),
             af.transpose(self.elements + self.element_size)))

        self.element_mesh_nodes = utils.linspace(af.sum(x_nodes[0]),
                                                 af.sum(x_nodes[1]),
                                                 N_elements + 1)

        self.element_array = af.transpose(
            af.interop.np_to_af_array(self.np_element_array))
        self.element_LGL = wave_equation.mapping_xi_to_x(
            af.transpose(self.element_array), self.xi_LGL)

        # The minimum distance between 2 mapped LGL points.
        self.delta_x = af.min(
            (self.element_LGL - af.shift(self.element_LGL, 1, 0))[1:, :])

        # dx_dxi for elements of equal size.
        self.dx_dxi = af.mean(
            wave_equation.dx_dxi_numerical(self.element_mesh_nodes[0:2],
                                           self.xi_LGL))

        # The value of time-step.
        self.delta_t = self.delta_x / (4 * c)

        # Array of timesteps seperated by delta_t.
        self.time = utils.linspace(
            0,
            int(total_time / self.delta_t) * self.delta_t,
            int(total_time / self.delta_t))

        # Initializing the amplitudes. Change u_init to required initial conditions.
        if (wave == 'sin'):
            self.u_init = af.sin(2 * np.pi * self.element_LGL)

        if (wave == 'gaussian'):
            self.u_init = np.e**(-(self.element_LGL)**2 / 0.4**2)

        self.test_array = af.np_to_af_array(np.array(self.u_init))

        # The parameters below are for 2D advection
        # -----------------------------------------

        ########################################################################
        #######################2D Wave Equation#################################
        ########################################################################

        self.xi_i = af.flat(af.transpose(af.tile(self.xi_LGL, 1, N_LGL)))
        self.eta_j = af.tile(self.xi_LGL, N_LGL)

        self.dLp_xi_ij = af.moddims(
            af.reorder(
                af.tile(utils.polyval_1d(self.dl_dxi_coeffs, self.xi_i), 1, 1,
                        N_LGL), 1, 2, 0), N_LGL**2, 1, N_LGL**2)
        self.Lp_xi_ij = af.moddims(
            af.reorder(
                af.tile(utils.polyval_1d(self.lagrange_coeffs, self.xi_i), 1,
                        1, N_LGL), 1, 2, 0), N_LGL**2, 1, N_LGL**2)

        self.dLq_eta_ij = af.tile(
            af.reorder(utils.polyval_1d(self.dl_dxi_coeffs, self.eta_j), 1, 2,
                       0), 1, 1, N_LGL)

        self.Lq_eta_ij = af.tile(
            af.reorder(utils.polyval_1d(self.lagrange_coeffs, self.eta_j), 1,
                       2, 0), 1, 1, N_LGL)

        self.dLp_Lq = self.Lq_eta_ij * self.dLp_xi_ij
        self.dLq_Lp = self.Lp_xi_ij * self.dLq_eta_ij

        self.Li_Lj_coeffs = wave_equation_2d.Li_Lj_coeffs(N_LGL)

        self.delta_y = self.delta_x

        self.delta_t_2d = courant * self.delta_x * self.delta_y \
                        / (self.delta_x * c_x + self.delta_y * c_y)

        self.c_lax_2d_x = c_x
        self.c_lax_2d_y = c_y

        self.nodes, self.elements = msh_parser.read_order_2_msh(mesh_file)

        self.x_e_ij = af.np_to_af_array(
            np.zeros([N_LGL * N_LGL, len(self.elements)]))
        self.y_e_ij = af.np_to_af_array(
            np.zeros([N_LGL * N_LGL, len(self.elements)]))

        for element_tag, element in enumerate(self.elements):
            self.x_e_ij[:, element_tag] = isoparam.isoparam_x_2D(
                self.nodes[element, 0], self.xi_i, self.eta_j)
            self.y_e_ij[:, element_tag] = isoparam.isoparam_y_2D(
                self.nodes[element, 1], self.xi_i, self.eta_j)

        self.u_e_ij = af.sin(self.x_e_ij * 2 * np.pi + self.y_e_ij * 4 * np.pi)

        # Array of timesteps seperated by delta_t.
        self.time_2d = utils.linspace(
            0,
            int(total_time_2d / self.delta_t_2d) * self.delta_t_2d,
            int(total_time_2d / self.delta_t_2d))
        self.sqrt_det_g = wave_equation_2d.sqrt_det_g(self.nodes[self.elements[0]][:, 0], \
                        self.nodes[self.elements[0]][:, 1], np.array(self.xi_i), np.array(self.eta_j))

        self.elements_nodes = (af.reorder(
            af.transpose(af.np_to_af_array(self.nodes[self.elements[:]])), 0,
            2, 1))

        self.sqrt_g = af.reorder(wave_equation_2d.trial_sqrt_det_g(self.elements_nodes[:, 0, :],\
                      self.elements_nodes[:, 1, :], self.xi_i, self.eta_j), 0, 2, 1)

        return