def calculate_p_center(p1_start, p2_start, p3_start, N_p1, N_p2, N_p3, dp1, dp2, dp3, ): """ Initializes the cannonical variables p1, p2 and p3 using a centered formulation. """ p1_center = af.constant(0, N_p1 * N_p2 * N_p3, len(p1_start), dtype = af.Dtype.f64) p2_center = af.constant(0, N_p1 * N_p2 * N_p3, len(p2_start), dtype = af.Dtype.f64) p3_center = af.constant(0, N_p1 * N_p2 * N_p3, len(p3_start), dtype = af.Dtype.f64) # Assigning for each species: for i in range(len(p1_start)): p1 = p1_start[i] + (0.5 + np.arange(N_p1)) * dp1[i] p2 = p2_start[i] + (0.5 + np.arange(N_p2)) * dp2[i] p3 = p3_start[i] + (0.5 + np.arange(N_p3)) * dp3[i] p2_center[:, i] = af.flat(af.to_array(np.meshgrid(p2, p1, p3)[0])) p1_center[:, i] = af.flat(af.to_array(np.meshgrid(p2, p1, p3)[1])) p3_center[:, i] = af.flat(af.to_array(np.meshgrid(p2, p1, p3)[2])) af.eval(p1_center, p2_center, p3_center) return (p1_center, p2_center, p3_center)
def calculate_q(q1_start, q2_start, N_q1, N_q2, N_g1, N_g2, dq1, dq2): i_q1 = np.arange(-N_g1, N_q1 + N_g1) i_q2 = np.arange(-N_g2, N_q2 + N_g2) q1_left_bot = q1_start + i_q1 * dq1 q2_left_bot = q2_start + i_q2 * dq2 q2_left_bot, q1_left_bot = np.meshgrid(q2_left_bot, q1_left_bot) q2_left_bot, q1_left_bot = af.to_array(q2_left_bot), af.to_array( q1_left_bot) # To bring the data structure to the default form:(N_p, N_s, N_q1, N_q2) q1_left_bot = af.reorder(q1_left_bot, 3, 2, 0, 1) q2_left_bot = af.reorder(q2_left_bot, 3, 2, 0, 1) q1_center_bot = q1_left_bot + 0.5 * dq1 q2_center_bot = q2_left_bot q1_left_center = q1_left_bot q2_left_center = q2_left_bot + 0.5 * dq2 q1_center = q1_left_bot + 0.5 * dq1 q2_center = q2_left_bot + 0.5 * dq2 ans = [[q1_left_bot, q2_left_bot], [q1_center_bot, q2_center_bot], [q1_left_center, q2_center_bot], [q1_center, q2_center]] return (ans)
def test_dump_moments(): test_obj = test() N_g = test_obj.N_ghost dump_moments(test_obj, 'test_file') h5f = h5py.File('test_file.h5', 'r') moments_read = h5f['moments'][:] h5f.close() moments_read = np.swapaxes(moments_read, 0, 1) print(moments_read.shape) print(compute_moments_imported(test_obj, 'density').shape) assert(af.sum(af.to_array(moments_read[:, :, 0]) - af.reorder(compute_moments_imported(test_obj, 'density'), 1, 2, 0 )[N_g:-N_g, N_g:-N_g] )==0 ) assert(af.sum(af.to_array(moments_read[:, :, 1]) - af.reorder(compute_moments_imported(test_obj, 'energy'), 1, 2, 0 )[N_g:-N_g, N_g:-N_g] )==0 )
def _calculate_p_center(self): """ Initializes the cannonical variables p1, p2 and p3 using a centered formulation. The size, and resolution are the same as declared under domain of the physical system object. """ p1_center = self.p1_start + (0.5 + np.arange( -self.N_ghost_p, self.N_p1 + self.N_ghost_p)) * self.dp1 p2_center = self.p2_start + (0.5 + np.arange( -self.N_ghost_p, self.N_p2 + self.N_ghost_p)) * self.dp2 p3_center = self.p3_start + (0.5 + np.arange( -self.N_ghost_p, self.N_p3 + self.N_ghost_p)) * self.dp3 p2_center, p1_center, p3_center = np.meshgrid(p2_center, p1_center, p3_center) # Flattening the arrays: p1_center = af.flat(af.to_array(p1_center)) p2_center = af.flat(af.to_array(p2_center)) p3_center = af.flat(af.to_array(p3_center)) if (self.N_species > 1): p1_center = af.tile(p1_center, 1, self.N_species) p2_center = af.tile(p2_center, 1, self.N_species) p3_center = af.tile(p3_center, 1, self.N_species) af.eval(p1_center, p2_center, p3_center) return (p1_center, p2_center, p3_center)
def _calculate_p_back(self): p1_center = self.p1_start + (0.5 + np.arange( -self.N_ghost_p, self.N_p1 + self.N_ghost_p)) * self.dp1 p2_center = self.p2_start + (0.5 + np.arange( -self.N_ghost_p, self.N_p2 + self.N_ghost_p)) * self.dp2 p3_back = self.p3_start + np.arange( -self.N_ghost_p, self.N_p3 + self.N_ghost_p) * self.dp3 p2_back, p1_back, p3_back = np.meshgrid(p2_center, p1_center, p3_center) # Flattening the arrays: p1_back = af.flat(af.to_array(p1_back)) p2_back = af.flat(af.to_array(p2_back)) p3_back = af.flat(af.to_array(p3_back)) if (self.N_species > 1): p1_back = af.tile(p1_back, 1, self.N_species) p2_back = af.tile(p2_back, 1, self.N_species) p3_back = af.tile(p3_back, 1, self.N_species) af.eval(p1_back, p2_back, p3_back) return (p1_back, p2_back, p3_back)
def _calculate_p_center(self): """ Initializes the cannonical variables p1, p2 and p3 using a centered formulation. The size, and resolution are the same as declared under domain of the physical system object. """ p1_center = \ self.p1_start + (0.5 + np.arange(0, self.N_p1, 1)) * self.dp1 p2_center = \ self.p2_start + (0.5 + np.arange(0, self.N_p2, 1)) * self.dp2 p3_center = \ self.p3_start + (0.5 + np.arange(0, self.N_p3, 1)) * self.dp3 p2_center, p1_center, p3_center = np.meshgrid(p2_center, p1_center, p3_center ) # Flattening the obtained arrays: p1_center = af.flat(af.to_array(p1_center)) p2_center = af.flat(af.to_array(p2_center)) p3_center = af.flat(af.to_array(p3_center)) # Reordering such that variation in velocity is along axis 2: # This is done to be consistent with the positionsExpanded form: p1_center = af.reorder(p1_center, 2, 3, 0, 1) p2_center = af.reorder(p2_center, 2, 3, 0, 1) p3_center = af.reorder(p3_center, 2, 3, 0, 1) af.eval(p1_center, p2_center, p3_center) return(p1_center, p2_center, p3_center)
def _calculate_q_center(self): """ Initializes the cannonical variables q1, q2 using a centered formulation. The size, and resolution are the same as declared under domain of the physical system object. Returns in q_expanded form. """ # Obtaining start coordinates for the local zone # Additionally, we also obtain the size of the local zone ((i_q1_start, i_q2_start), (N_q1_local, N_q2_local)) = self._da_f.getCorners() i_q1_center = i_q1_start + 0.5 i_q2_center = i_q2_start + 0.5 i_q1 = (i_q1_center + np.arange(-self.N_ghost_q, N_q1_local + self.N_ghost_q)) i_q2 = (i_q2_center + np.arange(-self.N_ghost_q, N_q2_local + self.N_ghost_q)) q1_center = self.q1_start + i_q1 * self.dq1 q2_center = self.q2_start + i_q2 * self.dq2 q2_center, q1_center = np.meshgrid(q2_center, q1_center) q1_center, q2_center = af.to_array(q1_center), af.to_array(q2_center) # To bring the data structure to the default form:(N_p, N_s, N_q1, N_q2) q1_center = af.reorder(q1_center, 3, 2, 0, 1) q2_center = af.reorder(q2_center, 3, 2, 0, 1) af.eval(q1_center, q2_center) return (q1_center, q2_center)
def initialize_f(q1, q2, p1, p2, p3, params): m = params.mass_particle k = params.boltzmann_constant rho = af.select(af.abs(q2) > 0.25, q1**0, 2) # Seeding the instability p1_bulk = af.reorder(p1_bulk, 1, 2, 0, 3) p1_bulk += af.to_array( np.random.rand(1, q1.shape[1], q1.shape[2]) * np.random.choice([-1, 1], size=(1, q1.shape[1], q1.shape[2]))) * 0.005 p2_bulk = af.to_array( np.random.rand(1, q1.shape[1], q1.shape[2]) * np.random.choice([-1, 1], size=(1, q1.shape[1], q1.shape[2]))) * 0.005 p1_bulk = af.reorder(p1_bulk, 2, 0, 1, 3) p2_bulk = af.reorder(p2_bulk, 2, 0, 1, 3) T = (2.5 / rho) f = rho * (m / (2 * np.pi * k * T))**(3 / 2) \ * af.exp(-m * (p1 - p1_bulk)**2 / (2 * k * T)) \ * af.exp(-m * (p2 - p2_bulk)**2 / (2 * k * T)) \ * af.exp(-m * (p3)**2 / (2 * k * T)) af.eval(f) return (f)
def __init__(self): self.f = af.to_array(np.array([0])) self.cell_centered_EM_fields = af.to_array(np.array([0])) self.yee_grid_EM_fields = af.to_array(np.array([0])) self.performance_test_flag = False
def __init__(self): self.physical_system = type('obj', (object, ), {'params': type('obj', (object, ), {'charge_electron': -1}) }) self.N_q1 = 32 self.N_q2 = 64 self.single_mode_evolution = False self.N_p1 = 2 self.N_p2 = 3 self.N_p3 = 4 self.k_q1 = 2 * np.pi * fftfreq(self.N_q1, 1 / self.N_q1) self.k_q2 = 2 * np.pi * fftfreq(self.N_q2, 1 / self.N_q2) self.k_q2, self.k_q1 = np.meshgrid(self.k_q2, self.k_q1) self.k_q2, self.k_q1 = af.to_array(self.k_q2), af.to_array(self.k_q1) self.q1 = af.to_array((0.5 + np.arange(self.N_q1)) * (1 / self.N_q1)) self.q2 = af.to_array((0.5 + np.arange(self.N_q2)) * (1 / self.N_q2)) self.q1 = af.tile(self.q1, 1, self.N_q2) self.q2 = af.tile(af.reorder(self.q2), self.N_q1, 1)
def __init__(self): self.q1_start = np.random.randint(0, 5) self.q2_start = np.random.randint(0, 5) self.q1_end = np.random.randint(5, 10) self.q2_end = np.random.randint(5, 10) self.N_q1 = np.random.randint(16, 32) self.N_q2 = np.random.randint(16, 32) self.dq1 = (self.q1_end - self.q1_start) / self.N_q1 self.dq2 = (self.q2_end - self.q2_start) / self.N_q2 N_g = self.N_ghost = np.random.randint(1, 5) self.q1 = self.q1_start \ * (0.5 + np.arange(-self.N_ghost, self.N_q1 + self.N_ghost ) ) * self.dq1 self.q2 = self.q2_start \ * (0.5 + np.arange(-self.N_ghost, self.N_q2 + self.N_ghost ) ) * self.dq2 self.q2, self.q1 = np.meshgrid(self.q2, self.q1) self.q1, self.q2 = af.to_array(self.q1), af.to_array(self.q2) self.q1 = af.reorder(self.q1, 2, 0, 1) self.q2 = af.reorder(self.q2, 2, 0, 1) self.q1 = af.tile(self.q1, 6) self.q2 = af.tile(self.q2, 6) self._da_fields = PETSc.DMDA().create([self.N_q1, self.N_q2], dof=6, stencil_width=self.N_ghost, boundary_type=('periodic', 'periodic'), stencil_type=1, ) self._glob_fields = self._da_fields.createGlobalVec() self._local_fields = self._da_fields.createLocalVec() self._glob_fields_array = self._glob_fields.getArray() self._local_fields_array = self._local_fields.getArray() self.cell_centered_EM_fields = af.constant(0, 6, self.q1.shape[1], self.q1.shape[2], dtype=af.Dtype.f64 ) self.cell_centered_EM_fields[:, N_g:-N_g, N_g:-N_g] = \ af.sin(2 * np.pi * self.q1 + 4 * np.pi * self.q2)[:, N_g:-N_g,N_g:-N_g] self.performance_test_flag = False
def test_calculate_p(): obj = test() p1, p2, p3 = calculate_p(obj) p1_expected = obj.p1_start + (0.5 + np.arange(obj.N_p1)) * obj.dp1 p2_expected = obj.p2_start + (0.5 + np.arange(obj.N_p2)) * obj.dp2 p3_expected = obj.p3_start + (0.5 + np.arange(obj.N_p3)) * obj.dp3 p2_expected, p1_expected, p3_expected = np.meshgrid(p2_expected, p1_expected, p3_expected ) p1_expected = af.reorder(af.flat(af.to_array(p1_expected)), 2, 3, 0, 1 ) p2_expected = af.reorder(af.flat(af.to_array(p2_expected)), 2, 3, 0, 1 ) p3_expected = af.reorder(af.flat(af.to_array(p3_expected)), 2, 3, 0, 1 ) assert(af.sum(af.abs(p1_expected - p1)) == 0) assert(af.sum(af.abs(p2_expected - p2)) == 0) assert(af.sum(af.abs(p3_expected - p3)) == 0)
def test_fft_poisson(): """ This function tests that the FFT solver works as intended. We take an expression for density for which the fields can be calculated analytically, and check that the numerical solution as given by the FFT solver and the analytical solution correspond well with each other. """ x_start = 0 y_start = 0 z_start = 0 x_end = 1 y_end = 2 z_end = 3 N_x = np.random.randint(16, 32) N_y = np.random.randint(16, 32) N_z = np.random.randint(16, 32) dx = (x_end - x_start) / N_x dy = (y_end - y_start) / N_y dz = (z_end - z_start) / N_z # Using a centered formulation for the grid points of x, y, z: x = x_start + (np.arange(N_x) + 0.5) * dx y = y_start + (np.arange(N_y) + 0.5) * dy z = z_start + (np.arange(N_z) + 0.5) * dz y, x, z = np.meshgrid(y, x, z) x = af.to_array(x) y = af.to_array(y) z = af.to_array(z) rho = af.sin(2 * np.pi * x + 4 * np.pi * y + 6 * np.pi * z) Ex_analytic = -(2 * np.pi) / (56 * np.pi**2) * \ af.cos(2 * np.pi * x + 4 * np.pi * y + 6 * np.pi * z) Ey_analytic = -(4 * np.pi) / (56 * np.pi**2) * \ af.cos(2 * np.pi * x + 4 * np.pi * y + 6 * np.pi * z) Ez_analytic = -(6 * np.pi) / (56 * np.pi**2) * \ af.cos(2 * np.pi * x + 4 * np.pi * y + 6 * np.pi * z) Ex_numerical, Ey_numerical, Ez_numerical = fft_poisson(rho, dx, dy, dz) # Checking that the L1 norm of error is at machine precision: Ex_err = af.sum( af.abs(Ex_numerical - Ex_analytic)) / Ex_analytic.elements() Ey_err = af.sum( af.abs(Ey_numerical - Ey_analytic)) / Ey_analytic.elements() Ez_err = af.sum( af.abs(Ez_numerical - Ez_analytic)) / Ez_analytic.elements() assert (Ex_err < 1e-14) assert (Ey_err < 1e-14) assert (Ez_err < 1e-14)
def communicate_fields(self, on_fdtd_grid=False): """ Used in communicating the values at the boundary zones for each of the local vectors among all procs.This routine is called to take care of communication(and periodic B.C's) procedures for the EM field arrays. The function is used for communicating the EM field values on the cell centered grid which is used by default. Additionally,it can also be used to communicate the values on the Yee-grid which is used by the FDTD solver. """ if (self.performance_test_flag == True): tic = af.time() # Obtaining start coordinates for the local zone # Additionally, we also obtain the size of the local zone ((i_q1_start, i_q2_start), (N_q1_local, N_q2_local)) = self._da_fields.getCorners() N_g = self.N_g # Assigning the values of the af.Array # fields quantities to the PETSc.Vec: if (on_fdtd_grid is True): flattened_global_EM_fields_array = \ af.flat(self.yee_grid_EM_fields[:, :, N_g:-N_g, N_g:-N_g]) flattened_global_EM_fields_array.to_ndarray(self._glob_fields_array) else: flattened_global_EM_fields_array = \ af.flat(self.cell_centered_EM_fields[:, :, N_g:-N_g, N_g:-N_g]) flattened_global_EM_fields_array.to_ndarray(self._glob_fields_array) # Takes care of boundary conditions and interzonal communications: self._da_fields.globalToLocal(self._glob_fields, self._local_fields) # Converting back to af.Array if (on_fdtd_grid is True): self.yee_grid_EM_fields = af.moddims( af.to_array(self._local_fields_array), 6, 1, N_q1_local + 2 * N_g, N_q2_local + 2 * N_g) af.eval(self.yee_grid_EM_fields) else: self.cell_centered_EM_fields = af.moddims( af.to_array(self._local_fields_array), 6, 1, N_q1_local + 2 * N_g, N_q2_local + 2 * N_g) af.eval(self.cell_centered_EM_fields) if (self.performance_test_flag == True): af.sync() toc = af.time() self.time_communicate_fields += toc - tic return
def Jx_Esirkepov_2D( charge_electron,\ number_of_electrons,\ positions_x ,positions_y,\ velocities_x, velocities_y,\ x_grid, y_grid,\ ghost_cells,\ length_domain_x, length_domain_y,\ dx, dy,\ dt\ ): elements = x_grid.elements() * y_grid.elements() Jx_x_indices, Jx_y_indices,\ Jx_values_at_these_indices,\ Jy_x_indices, Jy_y_indices,\ Jy_values_at_these_indices = indices_and_currents_TSC_2D(charge_electron,\ positions_x, positions_y,\ velocities_x, velocities_y,\ x_grid, y_grid,\ ghost_cells,\ length_domain_x, length_domain_y,\ dt\ ) # Current deposition using numpy's histogram input_indices = (Jx_x_indices*(y_grid.elements()) + Jx_y_indices) # Computing Jx_Yee Jx_Yee, temp = np.histogram( input_indices,\ bins=elements,\ range=(0, elements),\ weights=Jx_values_at_these_indices\ ) Jx_Yee = af.data.moddims(af.to_array(Jx_Yee), y_grid.elements(), x_grid.elements()) # Computing Jy_Yee input_indices = (Jy_x_indices*(y_grid.elements()) + Jy_y_indices) Jy_Yee, temp = np.histogram(input_indices,\ bins=elements,\ range=(0, elements),\ weights=Jy_values_at_these_indices\ ) Jy_Yee = af.data.moddims(af.to_array(Jy_Yee), y_grid.elements(), x_grid.elements()) af.eval(Jx_Yee, Jy_Yee) return Jx_Yee, Jy_Yee
def __init__(self, N): self.q1_start = 0 self.q2_start = 0 self.q1_end = 1 self.q2_end = 1 self.N_q1 = N self.N_q2 = N self.dq1 = (self.q1_end - self.q1_start) / self.N_q1 self.dq2 = (self.q2_end - self.q2_start) / self.N_q2 self.N_ghost = np.random.randint(3, 5) self.q1 = self.q1_start \ + (0.5 + np.arange(-self.N_ghost,self.N_q1 + self.N_ghost)) * self.dq1 self.q2 = self.q2_start \ + (0.5 + np.arange(-self.N_ghost,self.N_q2 + self.N_ghost)) * self.dq2 self.q2, self.q1 = np.meshgrid(self.q2, self.q1) self.q2, self.q1 = af.to_array(self.q2), af.to_array(self.q1) self.q1 = af.reorder(self.q1, 2, 0, 1) self.q2 = af.reorder(self.q2, 2, 0, 1) self.yee_grid_EM_fields = af.constant(0, 6, self.q1.shape[1], self.q1.shape[2], dtype=af.Dtype.f64) self._da_fields = PETSc.DMDA().create( [self.N_q1, self.N_q2], dof=6, stencil_width=self.N_ghost, boundary_type=('periodic', 'periodic'), stencil_type=1, ) self._glob_fields = self._da_fields.createGlobalVec() self._local_fields = self._da_fields.createLocalVec() self._glob_fields_array = self._glob_fields.getArray() self._local_fields_array = self._local_fields.getArray() self.boundary_conditions = type('obj', (object, ), { 'in_q1': 'periodic', 'in_q2': 'periodic' }) self.performance_test_flag = False
def fft_poisson(rho, dx, dy=None): """ FFT solver which returns the value of electric field. This will only work when the system being solved for has periodic boundary conditions. Parameters: ----------- rho : The 1D/2D density array obtained from calculate_density() is passed to this function. dx : Step size in the x-grid dy : Step size in the y-grid.Set to None by default to avoid conflict with the 1D case. Output: ------- E_x, E_y : Depending on the dimensionality of the system considered, either both E_x, and E_y are returned or E_x is returned. """ k_x = af.to_array(fftfreq(rho.shape[1], dx)) k_x = af.Array.as_type(k_x, af.Dtype.c64) k_y = af.to_array(fftfreq(rho.shape[0], dy)) k_x = af.tile(af.reorder(k_x), rho.shape[0], 1) k_y = af.tile(k_y, 1, rho.shape[1]) k_y = af.Array.as_type(k_y, af.Dtype.c64) rho = np.array(rho) rho_hat = fft2(rho) rho_hat = af.to_array(rho_hat) potential_hat = af.constant(0, rho.shape[0], rho.shape[1], dtype=af.Dtype.c64) potential_hat = (1 / (4 * np.pi**2 * (k_x * k_x + k_y * k_y))) * rho_hat potential_hat[0, 0] = 0 potential_hat = np.array(potential_hat) E_x_hat = -1j * 2 * np.pi * np.array(k_x) * potential_hat E_y_hat = -1j * 2 * np.pi * np.array(k_y) * potential_hat E_x = (ifft2(E_x_hat)).real E_y = (ifft2(E_y_hat)).real E_x = af.to_array(E_x) E_y = af.to_array(E_y) af.eval(E_x, E_y) return (E_x, E_y)
def __init__(self): self.physical_system = type('obj', (object, ), { 'moment_exponents': moment_exponents, 'moment_coeffs': moment_coeffs }) self.p1_start = -10 self.p2_start = -10 self.p3_start = -10 self.N_p1 = 32 self.N_p2 = 32 self.N_p3 = 32 self.dp1 = (-2 * self.p1_start) / self.N_p1 self.dp2 = (-2 * self.p2_start) / self.N_p2 self.dp3 = (-2 * self.p3_start) / self.N_p3 self.N_q1 = 16 self.N_q2 = 16 self.N_ghost = 3 self.p1 = self.p1_start + (0.5 + np.arange(self.N_p1)) * self.dp1 self.p2 = self.p2_start + (0.5 + np.arange(self.N_p2)) * self.dp2 self.p3 = self.p3_start + (0.5 + np.arange(self.N_p3)) * self.dp3 self.p2, self.p1, self.p3 = np.meshgrid(self.p2, self.p1, self.p3) self.p1 = af.flat(af.to_array(self.p1)) self.p2 = af.flat(af.to_array(self.p2)) self.p3 = af.flat(af.to_array(self.p3)) self.q1 = (-self.N_ghost + 0.5 + np.arange(self.N_q1 + 2 * self.N_ghost)) / self.N_q1 self.q2 = (-self.N_ghost + 0.5 + np.arange(self.N_q2 + 2 * self.N_ghost)) / self.N_q2 self.q2, self.q1 = np.meshgrid(self.q2, self.q1) self.q1 = af.reorder(af.to_array(self.q1), 2, 0, 1) self.q2 = af.reorder(af.to_array(self.q2), 2, 0, 1) rho = (1 + 0.01 * af.sin(2 * np.pi * self.q1 + 4 * np.pi * self.q2)) T = (1 + 0.01 * af.cos(2 * np.pi * self.q1 + 4 * np.pi * self.q2)) p1_b = 0.01 * af.exp(-10 * self.q1**2 - 10 * self.q2**2) p2_b = 0.01 * af.exp(-10 * self.q1**2 - 10 * self.q2**2) p3_b = 0.01 * af.exp(-10 * self.q1**2 - 10 * self.q2**2) self.f = maxwell_boltzmann(rho, T, p1_b, p2_b, p3_b, self.p1, self.p2, self.p3)
def fft_poisson(self, f=None): """ Solves the Poisson Equation using the FFTs: Used as a backup solver in case of low resolution runs (ie. used on a single node) with periodic boundary conditions. """ if (self.performance_test_flag == True): tic = af.time() if (self._comm.size != 1): raise Exception('FFT solver can only be used when run in serial') else: N_g = self.N_ghost rho = af.reorder( self.physical_system.params.charge_electron \ * self.compute_moments('density', f)[:, N_g:-N_g, N_g:-N_g], 1, 2, 0 ) k_q1 = fftfreq(rho.shape[0], self.dq1) k_q2 = fftfreq(rho.shape[1], self.dq2) k_q2, k_q1 = np.meshgrid(k_q2, k_q1) k_q1 = af.to_array(k_q1) k_q2 = af.to_array(k_q2) rho_hat = af.fft2(rho) potential_hat = rho_hat / (4 * np.pi**2 * (k_q1**2 + k_q2**2)) potential_hat[0, 0] = 0 E1_hat = -1j * 2 * np.pi * k_q1 * potential_hat E2_hat = -1j * 2 * np.pi * k_q2 * potential_hat # Non-inclusive of ghost-zones: E1_physical = af.reorder(af.real(af.ifft2(E1_hat)), 2, 0, 1) E2_physical = af.reorder(af.real(af.ifft2(E2_hat)), 2, 0, 1) self.cell_centered_EM_fields[0, N_g:-N_g, N_g:-N_g] = E1_physical self.cell_centered_EM_fields[1, N_g:-N_g, N_g:-N_g] = E2_physical af.eval(self.cell_centered_EM_fields) if (self.performance_test_flag == True): af.sync() toc = af.time() self.time_fieldsolver += toc - tic return
def _calculate_k(self): """ Initializes the wave numbers k_q1 and k_q2 which will be used when solving in fourier space. """ k_q1 = 2 * np.pi * fftfreq(self.N_q1, self.dq1) k_q2 = 2 * np.pi * fftfreq(self.N_q2, self.dq2) k_q2, k_q1 = np.meshgrid(k_q2, k_q1) k_q2 = af.to_array(k_q2) k_q1 = af.to_array(k_q1) af.eval(k_q1, k_q2) return(k_q1, k_q2)
def cloud_charge_deposition(charge, no_of_particles, positions_x, positions_y, x_center_grid, y_center_grid, shape_function, ghost_cells, Lx, Ly, dx, dy): elements = x_center_grid.elements() * y_center_grid.elements() rho_x_indices, rho_y_indices, rho_values_at_these_indices = shape_function( charge, positions_x, positions_y, x_center_grid, y_center_grid, ghost_cells, Lx, Ly) input_indices = (rho_x_indices * (y_center_grid.elements()) + rho_y_indices) rho, temp = np.histogram(input_indices, bins=elements, range=(0, elements), weights=rho_values_at_these_indices) rho = af.data.moddims(af.to_array(rho), y_center_grid.elements(), x_center_grid.elements()) # Periodic BC's for charge deposition rho[0, :] = rho[-1, :] + rho[0, :] rho[-1, :] = rho[0, :].copy() rho[:, 0] = rho[:, -1] + rho[:, 0] rho[:, -1] = rho[:, 0].copy() af.eval(rho) return rho
def test_calculate_q(): obj = test() q1, q2 = calculate_q_center(obj) q1_expected = obj.q1_start + \ (0.5 + np.arange(-obj.N_ghost, obj.N_q1 + obj.N_ghost)) * obj.dq1 q2_expected = obj.q2_start + \ (0.5 + np.arange(-obj.N_ghost, obj.N_q2 + obj.N_ghost)) * obj.dq2 q2_expected, q1_expected = np.meshgrid(q2_expected, q1_expected) q1_expected = af.reorder(af.to_array(q1_expected), 2, 0, 1) q2_expected = af.reorder(af.to_array(q2_expected), 2, 0, 1) assert (af.sum(af.abs(q1_expected - q1)) == 0) assert (af.sum(af.abs(q2_expected - q2)) == 0)
def load_distribution_function(self, file_name): """ This function is used to load the distribution function from the dump file that was created by dump_distribution_function. Parameters ---------- file_name : The distribution_function array will be loaded from this provided file name. Examples -------- >> solver.load_distribution_function('distribution_function') The above statemant will load the distribution function data stored in the file distribution_function.h5 into self.f """ viewer = PETSc.Viewer().createHDF5(file_name + '.h5', PETSc.Viewer.Mode.READ) self._glob_f.load(viewer) self.f_hat = 2 * fft2(af.to_array(self._glob_f_array.reshape(self.N_p1 * self.N_p2 * self.N_p3, self.N_species, self.N_q1, self.N_q2 ) ) ) / (self.N_q1 * self.N_q2) return
def load_EM_fields(self, file_name): """ This function is used to load the EM fields from the dump file that was created by dump_EM_fields. Parameters ---------- file_name : The EM_fields array will be loaded from this provided file name. Examples -------- >> solver.load_EM_fields('data_EM_fields') """ viewer = PETSc.Viewer().createHDF5(file_name + '.h5', PETSc.Viewer.Mode.READ) self.fields_solver._glob_fields.load(viewer) self.fields_solver.fields_hat = \ 2 * fft2(af.to_array(self.fields_solver._glob_fields_array.reshape(6, 1, self.N_q1, self.N_q2 ) ) ) / (self.N_q1 * self.N_q2)
def _calculate_q_center(self): """ Initializes the cannonical variables q1, q2 using a centered formulation. The size, and resolution are the same as declared under domain of the physical system object. """ q1_center = self.q1_start + (0.5 + np.arange(self.N_q1)) * self.dq1 q2_center = self.q2_start + (0.5 + np.arange(self.N_q2)) * self.dq2 q2_center, q1_center = np.meshgrid(q2_center, q1_center) q2_center = af.to_array(q2_center) q1_center = af.to_array(q1_center) af.eval(q1_center, q2_center) return(q1_center, q2_center)
def calculate_x(config): """ Returns the 2D array of x which is used in the computations of the Cheng-Knorr code. Parameters: ----------- config : Object config which is obtained by set() is passed to this file Output: ------- x : Array holding the values of x tiled along axis 1 """ N_x = config.N_x N_vel_x = config.N_vel_x N_ghost_x = config.N_ghost_x left_boundary = config.left_boundary right_boundary = config.right_boundary x = np.linspace(left_boundary, right_boundary, N_x) dx = x[1] - x[0] x_ghost_left = np.linspace(-(N_ghost_x)*dx + left_boundary, left_boundary - dx, N_ghost_x) x_ghost_right = np.linspace(right_boundary + dx, right_boundary + N_ghost_x*dx , N_ghost_x) x = np.concatenate([x_ghost_left, x, x_ghost_right]) x = af.Array.as_type(af.to_array(x), af.Dtype.f64) x = af.tile(x, 1, N_vel_x) af.eval(x) return x
def load_distribution_function(self, file_name): """ This function is used to load the distribution function from the dump file that was created by dump_distribution_function. Parameters ---------- file_name : The distribution_function array will be loaded from this provided file name. Examples -------- >> solver.load_distribution_function('distribution_function') The above statemant will load the distribution function data stored in the file distribution_function.h5 into self.f """ viewer = PETSc.Viewer().createHDF5(file_name + '.h5', PETSc.Viewer.Mode.READ, comm=self._comm ) self._glob_f.load(viewer) N_g = self.N_ghost self.f[:, N_g:-N_g, N_g:-N_g] = af.moddims(af.to_array(self._glob_f_array), self.N_p1 * self.N_p2 * self.N_p3, self.N_q1, self.N_q2 ) return
def test_dump_moments(): test_obj = test() dump_moments(test_obj, 'test_file') h5f = h5py.File('test_file.h5', 'r') moments_read = h5f['moments'][:] h5f.close() moments_read = np.swapaxes(moments_read, 0, 1) assert (af.sum( af.to_array(moments_read[:, :, 0]) - compute_moments_imported(test_obj, 'density')) == 0) assert (af.sum( af.to_array(moments_read[:, :, 1]) - compute_moments_imported(test_obj, 'energy')) == 0)
def calculate_k(N_q1, N_q2, dq1, dq2): """ Initializes the wave numbers k_q1 and k_q2 which will be used when solving in fourier space. """ k_q1 = 2 * np.pi * np.fft.fftfreq(N_q1, dq1) k_q2 = 2 * np.pi * np.fft.fftfreq(N_q2, dq2) k_q2, k_q1 = np.meshgrid(k_q2, k_q1) k_q1 = af.to_array(k_q1) k_q2 = af.to_array(k_q2) k_q1 = af.reorder(k_q1, 2, 3, 0, 1) k_q2 = af.reorder(k_q2, 2, 3, 0, 1) af.eval(k_q1, k_q2) return (k_q1, k_q2)
def Umeda_2003(charge,\ no_of_particles,\ positions_x,\ velocities_x,\ x_center_grid,\ ghost_cells,\ Lx,\ dx,\ dt\ ): ''' function set_up_perturbation(positions_x, number_particles, N_divisions,\ amplitude , k, length_domain_x\ ): ----------------------------------------------------------------------- Input variables: positions_x, number_particles, N_divisions, amplitude, k,length_domain_x positions_x: An one dimensional array of size equal to number of particles taken in the PIC code. It contains the positions of particles. number_particles: The number of electrons /macro particles N_divisions: The number of divisions considered for placing the macro particles amplitude: This is the amplitude of the density perturbation k_x: The is the wave number of the cosine density pertubation length_domain_x: This is the length of the domain in x direction ----------------------------------------------------------------------- returns: Jx This function returns a array positions_x such that there is a cosine density perturbation of the given amplitude ''' elements = x_center_grid.elements() Jx_x_indices, Jx_values_at_these_indices = Umeda_b1_deposition(charge,\ positions_x,\ velocities_x,\ x_center_grid,\ ghost_cells,\ Lx,\ dt\ ) input_indices = (Jx_x_indices) Jx, temp = np.histogram(input_indices, bins=elements, range=(0, elements), weights=Jx_values_at_these_indices) Jx = af.to_array(Jx) af.eval(Jx) return Jx
def simple_interop(verbose = False): if af.AF_NUMPY_FOUND: import numpy as np n = np.random.random((5,)) a = af.to_array(n) n2 = np.array(a) assert((n==n2).all()) n2[:] = 0 a.to_ndarray(n2) assert((n==n2).all()) n = np.random.random((5,3)) a = af.to_array(n) n2 = np.array(a) assert((n==n2).all()) n2[:] = 0 a.to_ndarray(n2) assert((n==n2).all()) n = np.random.random((5,3,2)) a = af.to_array(n) n2 = np.array(a) assert((n==n2).all()) n2[:] = 0 a.to_ndarray(n2) assert((n==n2).all()) n = np.random.random((5,3,2,2)) a = af.to_array(n) n2 = np.array(a) assert((n==n2).all()) n2[:] = 0 a.to_ndarray(n2) assert((n==n2).all()) if af.AF_PYCUDA_FOUND and af.get_active_backend() == 'cuda': import pycuda.autoinit import pycuda.gpuarray as cudaArray n = np.random.random((5,)) c = cudaArray.to_gpu(n) a = af.to_array(c) n2 = np.array(a) assert((n==n2).all()) n = np.random.random((5,3)) c = cudaArray.to_gpu(n) a = af.to_array(c) n2 = np.array(a) assert((n==n2).all()) n = np.random.random((5,3,2)) c = cudaArray.to_gpu(n) a = af.to_array(c) n2 = np.array(a) assert((n==n2).all()) n = np.random.random((5,3,2,2)) c = cudaArray.to_gpu(n) a = af.to_array(c) n2 = np.array(a) assert((n==n2).all()) if af.AF_PYOPENCL_FOUND and af.backend.name() == 'opencl': # This needs fixing upstream # https://github.com/arrayfire/arrayfire/issues/1728 # import pyopencl as cl # import pyopencl.array as clArray # ctx = cl.create_some_context() # queue = cl.CommandQueue(ctx) # n = np.random.random((5,)) # c = cl.array.to_device(queue, n) # a = af.to_array(c) # n2 = np.array(a) # assert((n==n2).all()) # n = np.random.random((5,3)) # c = cl.array.to_device(queue, n) # a = af.to_array(c) # n2 = np.array(a) # assert((n==n2).all()) # n = np.random.random((5,3,2)) # c = cl.array.to_device(queue, n) # a = af.to_array(c) # n2 = np.array(a) # assert((n==n2).all()) # n = np.random.random((5,3,2,2)) # c = cl.array.to_device(queue, n) # a = af.to_array(c) # n2 = np.array(a) # assert((n==n2).all()) pass if af.AF_NUMBA_FOUND and af.get_active_backend() == 'cuda': import numba from numba import cuda n = np.random.random((5,)) c = cuda.to_device(n) a = af.to_array(c) n2 = np.array(a) assert((n==n2).all()) n = np.random.random((5,3)) c = cuda.to_device(n) a = af.to_array(c) n2 = np.array(a) assert((n==n2).all()) n = np.random.random((5,3,2)) c = cuda.to_device(n) a = af.to_array(c) n2 = np.array(a) assert((n==n2).all()) n = np.random.random((5,3,2,2)) c = cuda.to_device(n) a = af.to_array(c) n2 = np.array(a) assert((n==n2).all())