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)
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)
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.
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)
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
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)
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
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\
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
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
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