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
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
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)
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
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 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
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)
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
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)
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
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
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
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
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
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
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)
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)
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)
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)
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
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)
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
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
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)
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
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
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 )
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
# 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))
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))
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