diff --git a/bolt/lib/nonlinear/boundaries.py b/bolt/lib/nonlinear/boundaries.py index 3d2d5a47..d8b7dab9 100644 --- a/bolt/lib/nonlinear/boundaries.py +++ b/bolt/lib/nonlinear/boundaries.py @@ -224,10 +224,10 @@ def apply_dirichlet_bcs_f(self, boundary): return -def apply_mirror_bcs_f(self, boundary): +def apply_mirror_bcs_f_cartesian(self, boundary): """ Applies mirror boundary conditions along boundary specified - for the distribution function + for the distribution function when momentum space is on a cartesian grid Parameters ---------- @@ -310,6 +310,108 @@ def apply_mirror_bcs_f(self, boundary): return +def apply_mirror_bcs_f_polar2D(self, boundary): + """ + Applies mirror boundary conditions along boundary specified + for the distribution function when momentum space is on a 2D polar grid + + Parameters + ---------- + boundary: str + Boundary along which the boundary condition is to be applied. + """ + + N_g = self.N_ghost + + if(boundary == 'left'): + # x-0-x-0-x-0-|-0-x-0-x-0-x-.... + # 0 1 2 3 4 5 + # For mirror boundary conditions: + # 0 = 5; 1 = 4; 2 = 3; + self.f[:, :, :N_g] = af.flip(self.f[:, :, N_g:2 * N_g], 2) + + # For a particle moving with initial momentum at an angle \theta + # with the x-axis, a collision with the left boundary changes + # the angle of momentum after reflection to (pi - \theta) + # To do this, we split the array into to equal halves, + # flip each of the halves along the p_theta axis and then + # join the two flipped halves together. + + N_theta = self.N_p2 + + tmp1 = self._convert_to_p_expanded(self.f)[:, :N_theta/2, :, :] + tmp1 = af.flip(tmp1, 1) + tmp2 = self._convert_to_p_expanded(self.f)[:, N_theta/2:, :, :] + tmp2 = af.flip(tmp2, 1) + tmp = af.join(1, tmp1, tmp2) + + self.f[:, :, :N_g] = \ + self._convert_to_q_expanded(tmp)[:, :, :N_g] + + elif(boundary == 'right'): + # ...-x-0-x-0-x-0-|-0-x-0-x-0-x + # -6 -5 -4 -3 -2 -1 + # For mirror boundary conditions: + # -1 = -6; -2 = -5; -3 = -4; + self.f[:, :, -N_g:] = af.flip(self.f[:, :, -2 * N_g:-N_g], 2) + + # For a particle moving with initial momentum at an angle \theta + # with the x-axis, a collision with the right boundary changes + # the angle of momentum after reflection to (pi - \theta) + # To do this, we split the array into to equal halves, + # flip each of the halves along the p_theta axis and then + # join the two flipped halves together. + + N_theta = self.N_p2 + + tmp1 = self._convert_to_p_expanded(self.f)[:, :N_theta/2, :, :] + tmp1 = af.flip(tmp1, 1) + tmp2 = self._convert_to_p_expanded(self.f)[:, N_theta/2:, :, :] + tmp2 = af.flip(tmp2, 1) + tmp = af.join(1, tmp1, tmp2) + + self.f[:, :, -N_g:] = \ + self._convert_to_q_expanded(tmp)[:, :, -N_g:] + + elif(boundary == 'bottom'): + # x-0-x-0-x-0-|-0-x-0-x-0-x-.... + # 0 1 2 3 4 5 + # For mirror boundary conditions: + # 0 = 5; 1 = 4; 2 = 3; + self.f[:, :, :, :N_g] = af.flip(self.f[:, :, :, N_g:2 * N_g], 3) + + # For a particle moving with initial momentum at an angle \theta + # with the x-axis, a collision with the bottom boundary changes + # the angle of momentum after reflection to (2*pi - \theta) = (-\theta) + # To do this we flip the axis that contains the variation in p_theta + self.f[:, :, :, :N_g] = \ + self._convert_to_q_expanded(af.flip(self._convert_to_p_expanded(self.f), + 1 + ) + )[:, :, :, :N_g] + + elif(boundary == 'top'): + # ...-x-0-x-0-x-0-|-0-x-0-x-0-x + # -6 -5 -4 -3 -2 -1 + # For mirror boundary conditions: + # -1 = -6; -2 = -5; -3 = -4; + self.f[:, :, :, -N_g:] = af.flip(self.f[:, :, :, -2 * N_g:-N_g], 3) + + # For a particle moving with initial momentum at an angle \theta + # with the x-axis, a collision with the top boundary changes + # the angle of momentum after reflection to (2*pi - \theta) = (-\theta) + # To do this we flip the axis that contains the variation in p_theta + self.f[:, :, :, -N_g:] = \ + self._convert_to_q_expanded(af.flip(self._convert_to_p_expanded(self.f), + 1 + ) + )[:, :, :, -N_g:] + + else: + raise Exception('Invalid choice for boundary') + + return + def apply_bcs_f(self): """ Applies boundary conditions to the distribution function as specified by @@ -332,14 +434,26 @@ def apply_bcs_f(self): apply_dirichlet_bcs_f(self, 'left') elif(self.boundary_conditions.in_q1_left == 'mirror'): - apply_mirror_bcs_f(self, 'left') + if (self.physical_system.params.p_space_grid == 'cartesian'): + apply_mirror_bcs_f_cartesian(self, 'left') + elif (self.physical_system.params.p_space_grid == 'polar2D'): + apply_mirror_bcs_f_polar2D(self, 'left') + else : + raise NotImplementedError('Unsupported coordinate system in p_space') elif(self.boundary_conditions.in_q1_left == 'mirror+dirichlet'): - apply_mirror_bcs_f(self, 'left') + if (self.physical_system.params.p_space_grid == 'cartesian'): + apply_mirror_bcs_f_cartesian(self, 'left') + elif (self.physical_system.params.p_space_grid == 'polar2D'): + apply_mirror_bcs_f_polar2D(self, 'left') + else : + raise NotImplementedError('Unsupported coordinate system in p_space') apply_dirichlet_bcs_f(self, 'left') # This is automatically handled by the PETSc function globalToLocal() - elif(self.boundary_conditions.in_q1_left == 'periodic'): + elif( self.boundary_conditions.in_q1_left == 'periodic' + or self.boundary_conditions.in_q1_left == 'none' # no ghost zones (1D) + ): pass elif(self.boundary_conditions.in_q1_left == 'shearing-box'): @@ -355,14 +469,26 @@ def apply_bcs_f(self): apply_dirichlet_bcs_f(self, 'right') elif(self.boundary_conditions.in_q1_right == 'mirror'): - apply_mirror_bcs_f(self, 'right') + if (self.physical_system.params.p_space_grid == 'cartesian'): + apply_mirror_bcs_f_cartesian(self, 'right') + elif (self.physical_system.params.p_space_grid == 'polar2D'): + apply_mirror_bcs_f_polar2D(self, 'right') + else: + raise NotImplementedError('Unsupported coordinate system in p_space') elif(self.boundary_conditions.in_q1_right == 'mirror+dirichlet'): - apply_mirror_bcs_f(self, 'right') + if (self.physical_system.params.p_space_grid == 'cartesian'): + apply_mirror_bcs_f_cartesian(self, 'right') + elif (self.physical_system.params.p_space_grid == 'polar2D'): + apply_mirror_bcs_f_polar2D(self, 'right') + else: + raise NotImplementedError('Unsupported coordinate system in p_space') apply_dirichlet_bcs_f(self, 'right') - + # This is automatically handled by the PETSc function globalToLocal() - elif(self.boundary_conditions.in_q1_right == 'periodic'): + elif( self.boundary_conditions.in_q1_right == 'periodic' + or self.boundary_conditions.in_q1_right == 'none' # no ghost zones (1D) + ): pass elif(self.boundary_conditions.in_q1_right == 'shearing-box'): @@ -378,14 +504,26 @@ def apply_bcs_f(self): apply_dirichlet_bcs_f(self, 'bottom') elif(self.boundary_conditions.in_q2_bottom == 'mirror'): - apply_mirror_bcs_f(self, 'bottom') + if (self.physical_system.params.p_space_grid =='cartesian'): + apply_mirror_bcs_f_cartesian(self, 'bottom') + elif (self.physical_system.params.p_space_grid == 'polar2D'): + apply_mirror_bcs_f_polar2D(self, 'bottom') + else: + raise NotImplementedError('Unsupported coordinate system in p_space') elif(self.boundary_conditions.in_q2_bottom == 'mirror+dirichlet'): - apply_mirror_bcs_f(self, 'bottom') + if (self.physical_system.params.p_space_grid == 'cartesian'): + apply_mirror_bcs_f_cartesian(self, 'bottom') + elif (self.physical_system.params.p_space_grid == 'polar2D'): + apply_mirror_bcs_f_polar2D(self, 'bottom') + else: + raise NotImplementedError('Unsupported coordinate system in p_space') apply_dirichlet_bcs_f(self, 'bottom') # This is automatically handled by the PETSc function globalToLocal() - elif(self.boundary_conditions.in_q2_bottom == 'periodic'): + elif( self.boundary_conditions.in_q2_bottom == 'periodic' + or self.boundary_conditions.in_q2_bottom == 'none' # no ghost zones (1D) + ): pass elif(self.boundary_conditions.in_q2_bottom == 'shearing-box'): @@ -401,14 +539,26 @@ def apply_bcs_f(self): apply_dirichlet_bcs_f(self, 'top') elif(self.boundary_conditions.in_q2_top == 'mirror'): - apply_mirror_bcs_f(self, 'top') + if (self.physical_system.params.p_space_grid == 'cartesian'): + apply_mirror_bcs_f_cartesian(self, 'top') + elif (self.physical_system.params.p_space_grid == 'polar2D'): + apply_mirror_bcs_f_polar2D(self, 'top') + else: + raise NotImplementedError('Unsupported coordinate system in p_space') elif(self.boundary_conditions.in_q2_top == 'mirror+dirichlet'): - apply_mirror_bcs_f(self, 'top') + if (self.physical_system.params.p_space_grid == 'cartesian'): + apply_mirror_bcs_f_cartesian(self, 'top') + elif (self.physical_system.params.p_space_grid == 'polar2D'): + apply_mirror_bcs_f_polar2D(self, 'top') + else: + raise NotImplementedError('Unsupported coordinate system in p_space') apply_dirichlet_bcs_f(self, 'top') # This is automatically handled by the PETSc function globalToLocal() - elif(self.boundary_conditions.in_q2_top == 'periodic'): + elif( self.boundary_conditions.in_q2_top == 'periodic' + or self.boundary_conditions.in_q2_top == 'none' # no ghost zones (1D) + ): pass elif(self.boundary_conditions.in_q2_top == 'shearing-box'): diff --git a/bolt/lib/nonlinear/communicate.py b/bolt/lib/nonlinear/communicate.py index eed144e7..1322cbe7 100644 --- a/bolt/lib/nonlinear/communicate.py +++ b/bolt/lib/nonlinear/communicate.py @@ -2,6 +2,8 @@ # -*- coding: utf-8 -*- import arrayfire as af +from bolt.lib.utils.af_petsc_conversion import af_to_petsc_glob_array +from bolt.lib.utils.af_petsc_conversion import petsc_local_array_to_af def communicate_f(self): """ @@ -14,43 +16,19 @@ def communicate_f(self): 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_f.getCorners() - - N_g = self.N_ghost - - # Assigning the local array only when Dirichlet - # boundary conditions are applied. This is needed since - # only inflowing characteristics are to be changed by - # the apply boundary conditions function. - - if( self.boundary_conditions.in_q1_left == 'dirichlet' - or self.boundary_conditions.in_q1_right == 'dirichlet' - or self.boundary_conditions.in_q2_bottom == 'dirichlet' - or self.boundary_conditions.in_q2_top == 'dirichlet' - ): - af.flat(self.f).to_ndarray(self._local_f_array) - - # Global value is non-inclusive of the ghost-zones: - af.flat(self.f[:, :, N_g:-N_g, N_g:-N_g]).to_ndarray(self._glob_f_array) + # Transfer data from af.Array to PETSc.Vec + af_to_petsc_glob_array(self, self.f, self._glob_f_array) # The following function takes care of interzonal communications # Additionally, it also automatically applies periodic BCs when necessary self._da_f.globalToLocal(self._glob_f, self._local_f) # Converting back from PETSc.Vec to af.Array: - f_flattened = af.to_array(self._local_f_array) - self.f = af.moddims(f_flattened, - self.N_p1 - * self.N_p2 - * self.N_p3, - self.N_species, - N_q1_local + 2 * N_g, - N_q2_local + 2 * N_g - ) - - af.eval(self.f) + self.f = petsc_local_array_to_af(self, + self.N_p1*self.N_p2*self.N_p3, + self.N_species, + self._local_f_array + ) if(self.performance_test_flag == True): af.sync() @@ -59,7 +37,6 @@ def communicate_f(self): return - def communicate_fields(self, on_fdtd_grid = False): """ Used in communicating the values at the boundary zones for each of @@ -72,46 +49,26 @@ def communicate_fields(self, on_fdtd_grid = False): 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) - + tmp_array = self.yee_grid_EM_fields 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) + tmp_array = self.cell_centered_EM_fields + + af_to_petsc_glob_array(self, tmp_array, 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) + tmp_array = petsc_local_array_to_af(self, 6, 1, self._local_fields_array) + if(on_fdtd_grid is True): + self.yee_grid_EM_fields = tmp_array 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 - ) + self.cell_centered_EM_fields = tmp_array - af.eval(self.cell_centered_EM_fields) - if(self.performance_test_flag == True): af.sync() toc = af.time() diff --git a/bolt/lib/nonlinear/compute_moments.py b/bolt/lib/nonlinear/compute_moments.py index 17b2ff8d..e66dbcf2 100644 --- a/bolt/lib/nonlinear/compute_moments.py +++ b/bolt/lib/nonlinear/compute_moments.py @@ -38,10 +38,12 @@ def compute_moments(self, moment_name, f=None): 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.dp3 * self.dp2 * self.dp1 + ), f, p1, p2, p3, self.physical_system.params.integral_measure ) af.eval(moment) diff --git a/bolt/lib/nonlinear/fields/boundaries.py b/bolt/lib/nonlinear/fields/boundaries.py index 0bd08761..4d3d555e 100644 --- a/bolt/lib/nonlinear/fields/boundaries.py +++ b/bolt/lib/nonlinear/fields/boundaries.py @@ -595,7 +595,9 @@ def apply_bcs_fields(self, on_fdtd_grid = False): apply_dirichlet_bcs_fields(self, 'left', on_fdtd_grid) # This is automatically handled by the PETSc function globalToLocal() - elif(self.boundary_conditions.in_q1_left == 'periodic'): + elif( self.boundary_conditions.in_q1_left == 'periodic' + or self.boundary_conditions.in_q1_left == 'none' + ): pass elif(self.boundary_conditions.in_q1_left == 'shearing-box'): @@ -618,7 +620,9 @@ def apply_bcs_fields(self, on_fdtd_grid = False): apply_dirichlet_bcs_fields(self, 'right', on_fdtd_grid) # This is automatically handled by the PETSc function globalToLocal() - elif(self.boundary_conditions.in_q1_right == 'periodic'): + elif( self.boundary_conditions.in_q1_right == 'periodic' + or self.boundary_conditions.in_q1_right == 'none' + ): pass elif(self.boundary_conditions.in_q1_right == 'shearing-box'): @@ -641,7 +645,9 @@ def apply_bcs_fields(self, on_fdtd_grid = False): apply_dirichlet_bcs_fields(self, 'bottom', on_fdtd_grid) # This is automatically handled by the PETSc function globalToLocal() - elif(self.boundary_conditions.in_q2_bottom == 'periodic'): + elif( self.boundary_conditions.in_q2_bottom == 'periodic' + or self.boundary_conditions.in_q2_bottom == 'none' + ): pass elif(self.boundary_conditions.in_q2_bottom == 'shearing-box'): @@ -664,7 +670,9 @@ def apply_bcs_fields(self, on_fdtd_grid = False): apply_dirichlet_bcs_fields(self, 'top', on_fdtd_grid) # This is automatically handled by the PETSc function globalToLocal() - elif(self.boundary_conditions.in_q2_top == 'periodic'): + elif( self.boundary_conditions.in_q2_top == 'periodic' + or self.boundary_conditions.in_q2_top == 'none' + ): pass elif(self.boundary_conditions.in_q2_top == 'shearing-box'): diff --git a/bolt/lib/nonlinear/fields/fields.py b/bolt/lib/nonlinear/fields/fields.py index 0e6f9f7e..e0769619 100644 --- a/bolt/lib/nonlinear/fields/fields.py +++ b/bolt/lib/nonlinear/fields/fields.py @@ -12,13 +12,13 @@ from .electrostatic.fft import fft_poisson from .electrodynamic.fdtd_explicit import fdtd -from bolt.lib.utils.calculate_q import \ - calculate_q_center, calculate_q_left_center, \ - calculate_q_center_bot, calculate_q_left_bot +from bolt.lib.utils.calculate_q import calculate_q +from bolt.lib.utils.af_petsc_conversion import af_to_petsc_glob_array +from bolt.lib.utils.af_petsc_conversion import petsc_local_array_to_af class fields_solver(object): - - # Computing divB on cell edges + + # Computing divB at cell corners (i, j) def compute_divB(self): B1 = self.yee_grid_EM_fields[3] # (i + 1/2, j) @@ -27,10 +27,11 @@ def compute_divB(self): B1_minus_q1 = af.shift(B1, 0, 0, 1) # (i - 1/2, j) B2_minus_q2 = af.shift(B2, 0, 0, 0, 1) # (i, j - 1/2) - divB = (B1 - B1_minus_q1) / self.dq1 + (B2 - B2_minus_q2) / self.dq2 # (i, j) + divB = (B1 - B1_minus_q1)/self.dq1 + (B2 - B2_minus_q2)/self.dq2 # (i, j) + return(divB) - # Computing divE at cell centers + # Computing divE at cell centers (i+1/2, j+1/2) def compute_divE(self): communicate.communicate_fields(self, True) @@ -41,36 +42,38 @@ def compute_divE(self): E1_plus_q1 = af.shift(E1, 0, 0, -1) # (i + 1, j + 1/2) E2_plus_q2 = af.shift(E2, 0, 0, 0, -1) # (i + 1/2, j + 1) - divE = (E1_plus_q1 - E1) / self.dq1 + (E2_plus_q2 - E2) / self.dq2 # (i + 1/2, j + 1/2) + divE = (E1_plus_q1 - E1)/self.dq1 + (E2_plus_q2 - E2)/self.dq2 # (i + 1/2, j + 1/2) return(divE) def check_maxwells_contraint_equations(self, rho): - N_g = self.N_g - PETSc.Sys.Print("Initial Maxwell's Constraints:") - mean_divB = af.mean(af.abs(self.compute_divB()[:, :, N_g:-N_g, N_g:-N_g])) - PETSc.Sys.Print('MEAN(|divB|) =', mean_divB) + divB_error = af.abs(self.compute_divB()) + af_to_petsc_glob_array(self, divB_error, self._glob_divB_error_array) - rho_by_eps = rho / self.params.eps + PETSc.Sys.Print('MAX(|divB|) =', self._glob_divB_error.max()) + + # TODO: What the is going on here? rho_b?? + rho_by_eps = rho #/ self.params.dielectric_epsilon rho_b = af.mean(rho_by_eps) # background - divE = self.compute_divE() - mean_gauss_law = af.mean(af.abs((divE- rho_by_eps + rho_b)[:, :, N_g:-N_g, N_g:-N_g])) - PETSc.Sys.Print('MEAN(|divE-rho|) =', mean_gauss_law) + divE_error = self.compute_divE() - rho_by_eps + rho_b + + af_to_petsc_glob_array(self, divE_error, self._glob_divE_error_array) + PETSc.Sys.Print('MAX(|divE-rho|) =', self._glob_divE_error.max()) # Appropriately raising exceptions: # Checking for ∇.B = 0 - try: - assert(mean_divB < 1e-10) - except: - raise SystemExit('divB contraint isn\'t preserved') - - # Checking for ∇.E = ρ/ε: - # TODO: Need to look into this further: - # try: - # assert(mean_gauss_law < 1e-7) - # except: - # raise SystemExit('divE - rho/epsilon contraint isn\'t preserved') - +# try: +# assert(mean_divB < params.divB_tol) +# except: +# raise SystemExit('divB contraint isn\'t preserved') +# +# # Checking for ∇.E = ρ/ε: +# # TODO: Need to look into this further: +# try: +# assert(mean_gauss_law < params.divE_tol) +# except: +# raise SystemExit('divE - rho/epsilon contraint isn\'t preserved') +# def __init__(self, physical_system, rho_initial, performance_test_flag = False): """ Constructor for the fields_solver object, which takes in the physical system @@ -99,7 +102,7 @@ def __init__(self, physical_system, rho_initial, performance_test_flag = False): self.N_q1 = physical_system.N_q1 self.N_q2 = physical_system.N_q2 - self.N_g = physical_system.N_ghost + self.N_ghost = self.N_g = physical_system.N_ghost self.dq1 = physical_system.dq1 self.dq2 = physical_system.dq2 @@ -121,8 +124,8 @@ def __init__(self, physical_system, rho_initial, performance_test_flag = False): self.time_elapsed = 0 - petsc_bc_in_q1 = 'ghosted' - petsc_bc_in_q2 = 'ghosted' + petsc_bc_in_q1 = 'ghosted'; self.N_g1 = self.N_ghost + petsc_bc_in_q2 = 'ghosted'; self.N_g2 = self.N_ghost # Only for periodic boundary conditions or shearing-box boundary conditions # do the boundary conditions passed to the DA need to be changed. PETSc @@ -143,6 +146,12 @@ def __init__(self, physical_system, rho_initial, performance_test_flag = False): ): petsc_bc_in_q2 = 'periodic' + if(self.boundary_conditions.in_q1_left == 'none'): + petsc_bc_in_q1 = 'none'; self.N_g1 = 0 + + if(self.boundary_conditions.in_q2_bottom == 'none'): + petsc_bc_in_q2 = 'none'; self.N_g2 = 0 + nproc_in_q1 = PETSc.DECIDE nproc_in_q2 = PETSc.DECIDE @@ -170,38 +179,64 @@ def __init__(self, physical_system, rho_initial, performance_test_flag = False): comm = self._comm ) - - # 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() - - self.q1_center, self.q2_center = \ - calculate_q_center(self.q1_start + i_q1_start * self.dq1, - self.q2_start + i_q2_start * self.dq2, - N_q1_local, N_q2_local, self.N_g, - self.dq1, self.dq2 - ) - - self.q1_left_center, self.q2_left_center = \ - calculate_q_left_center(self.q1_start + i_q1_start * self.dq1, - self.q2_start + i_q2_start * self.dq2, - N_q1_local, N_q2_local, self.N_g, - self.dq1, self.dq2 - ) - - self.q1_center_bot, self.q2_center_bot = \ - calculate_q_center_bot(self.q1_start + i_q1_start * self.dq1, - self.q2_start + i_q2_start * self.dq2, - N_q1_local, N_q2_local, self.N_g, - self.dq1, self.dq2 - ) - - self.q1_left_bot, self.q2_left_bot = \ - calculate_q_left_bot(self.q1_start + i_q1_start * self.dq1, - self.q2_start + i_q2_start * self.dq2, - N_q1_local, N_q2_local, self.N_g, - self.dq1, self.dq2 - ) + # Make to da to create aux vecs, such as holding random numbers, + # storing errors etc + self._da_aux = PETSc.DMDA().create([self.N_q1, self.N_q2], + dof = 1, + stencil_width = self.N_g, + boundary_type = (petsc_bc_in_q1, + petsc_bc_in_q2 + ), + proc_sizes = (nproc_in_q1, + nproc_in_q2 + ), + stencil_type = 1, + comm = self._comm + ) + + # Get start (corner) indices of the local zone wrt global ordering and its size + ((_i_q1_start, _i_q2_start), (_N_q1_local, _N_q2_local)) = \ + self._da_fields.getCorners() + + # Coordinates of the local zone in a global coord system + self.q1_start_local = self.q1_start + _i_q1_start * self.dq1 + self.q2_start_local = self.q2_start + _i_q2_start * self.dq2 + + self.N_q1_local = _N_q1_local + self.N_q2_local = _N_q2_local + + self.N_q1_local_with_Ng = _N_q1_local + 2*self.N_g1 + self.N_q2_local_with_Ng = _N_q2_local + 2*self.N_g2 + + # Indexing vars used through out + self.i_q1_start = self.N_g1; self.i_q1_end = -self.N_g1 + self.i_q2_start = self.N_g2; self.i_q2_end = -self.N_g2 + if (self.N_g1 == 0): + self.i_q1_end = 1 + + if (self.N_g2 == 0): + self.i_q2_end = 1 + + # Obtaining the array values of spatial coordinates: + q_left_bot, q_center_bot, q_left_center, q_center = \ + calculate_q(self.q1_start_local, + self.q2_start_local, + self.N_q1_local, self.N_q2_local, + self.N_g1, self.N_g2, + self.dq1, self.dq2 + ) + + self.q1_left_bot = q_left_bot[0] + self.q2_left_bot = q_left_bot[1] + + self.q1_center_bot = q_center_bot[0] + self.q2_center_bot = q_center_bot[1] + + self.q1_left_center = q_left_center[0] + self.q2_left_center = q_left_center[1] + + self.q1_center = q_center[0] + self.q2_center = q_center[1] # The following global and local vectors are used in # the communication routines for EM fields @@ -212,7 +247,27 @@ def __init__(self, physical_system, rho_initial, performance_test_flag = False): self._local_fields_array = self._local_fields.getArray() PETSc.Object.setName(self._glob_fields, 'EM_fields') + + self._glob_divB_error = self._da_aux.createGlobalVec() + self._glob_divE_error = self._da_aux.createGlobalVec() + + self._glob_divB_error_array = self._glob_divB_error.getArray() + self._glob_divE_error_array = self._glob_divE_error.getArray() + # Create a random number vec to use when needed, e.g, initial conditions + self._glob_random = self._da_aux.createGlobalVec() + self._glob_random.setRandom() + self._glob_random_array = self._glob_random.getArray() + + self._local_random = self._da_aux.createLocalVec() + self._da_aux.globalToLocal(self._glob_random, self._local_random) + self._local_random_array = self._local_random.getArray() + + self.random_vals = petsc_local_array_to_af(self, 1, 1, self._local_random_array) + # Inject random_vals into params so that it can be used for + # initialization + self.params.random_vals = self.random_vals + # Alternating upon each call to get_fields for FVM: # This ensures that the fields are staggerred correctly in time: self.at_n = True @@ -376,37 +431,33 @@ def _initialize(self, rho_initial): The initial charge density array that's passed to an electrostatic solver for initialization """ - # 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() - # Following quantities are cell-centered (i + 0.5, j + 0.5): # Electric fields are defined at the n-th timestep: # Magnetic fields are defined at the (n-1/2)-th timestep: self.cell_centered_EM_fields = af.constant(0, 6, 1, - N_q1_local + 2 * self.N_g, - N_q2_local + 2 * self.N_g, + self.N_q1_local_with_Ng, + self.N_q2_local_with_Ng, dtype=af.Dtype.f64 ) # Field values at n-th timestep: self.cell_centered_EM_fields_at_n = af.constant(0, 6, 1, - N_q1_local + 2 * self.N_g, - N_q2_local + 2 * self.N_g, + self.N_q1_local_with_Ng, + self.N_q2_local_with_Ng, dtype=af.Dtype.f64 ) # Field values at (n+1/2)-th timestep: self.cell_centered_EM_fields_at_n_plus_half = af.constant(0, 6, 1, - N_q1_local + 2 * self.N_g, - N_q2_local + 2 * self.N_g, + self.N_q1_local_with_Ng, + self.N_q2_local_with_Ng, dtype=af.Dtype.f64 ) # Declaring the arrays which store data on the yee grid for FDTD: self.yee_grid_EM_fields = af.constant(0, 6, 1, - N_q1_local + 2 * self.N_g, - N_q2_local + 2 * self.N_g, + self.N_q1_local_with_Ng, + self.N_q2_local_with_Ng, dtype=af.Dtype.f64 ) @@ -471,7 +522,6 @@ def cell_centered_grid_to_yee_grid(self, fields_to_transform = None): + af.shift(B3, 0, 0, 1, 1) ) # (i, j) - af.eval(self.yee_grid_EM_fields) return def yee_grid_to_cell_centered_grid(self, fields_to_transform = None): @@ -504,7 +554,6 @@ def yee_grid_to_cell_centered_grid(self, fields_to_transform = None): + af.shift(B3_yee, 0, 0, -1, -1) ) - af.eval(self.cell_centered_EM_fields) return def compute_electrostatic_fields(self, rho): @@ -516,8 +565,6 @@ def compute_electrostatic_fields(self, rho): communicate.communicate_fields(self) apply_bcs_fields(self) - # ADD SNES BELOW - def evolve_electrodynamic_fields(self, J1, J2, J3, dt): """ Evolve the fields using FDTD. diff --git a/bolt/lib/nonlinear/file_io/dump.py b/bolt/lib/nonlinear/file_io/dump.py index a80cfc2d..9caa7a41 100644 --- a/bolt/lib/nonlinear/file_io/dump.py +++ b/bolt/lib/nonlinear/file_io/dump.py @@ -3,8 +3,40 @@ from petsc4py import PETSc import numpy as np -import h5py import arrayfire as af +from bolt.lib.utils.af_petsc_conversion import af_to_petsc_glob_array + +def dump_aux_arrays(self, arrays, name, file_name): + + if (self.dump_aux_arrays_initial_call): + self._da_aux_arrays = PETSc.DMDA().create([self.N_q1, self.N_q2], + dof = len(arrays), + proc_sizes = (PETSc.DECIDE, + PETSc.DECIDE + ), + comm = self._comm + ) + self._glob_aux = self._da_aux_arrays.createGlobalVec() + self._glob_aux_array = self._glob_aux.getArray() + + self.dump_aux_arrays_initial_call = 0 + + N_g = self.N_ghost + + for i in range(len(arrays)): + if (i==0): + array_to_dump = arrays[0][:, :, N_g:-N_g, N_g:-N_g] + else: + array_to_dump = af.join(0, array_to_dump, + arrays[i][:, :, + N_g:-N_g, + N_g:-N_g] + ) + + af.flat(array_to_dump).to_ndarray(self._glob_aux_array) + PETSc.Object.setName(self._glob_aux, name) + viewer = PETSc.Viewer().createBinary(file_name + '.bin', 'w', comm=self._comm) + viewer(self._glob_aux) def dump_moments(self, file_name): """ @@ -66,35 +98,32 @@ def dump_moments(self, file_name): attributes = [a for a in dir(self.physical_system.moments) if not a.startswith('_')] - # Removing utility functions: - if('integral_over_v' in attributes): - attributes.remove('integral_over_v') + # Removing utility functions and imported modules: + if('integral_over_p' in attributes): + attributes.remove('integral_over_p') + if('params' in attributes): + attributes.remove('params') + if('af' in attributes): + attributes.remove('af') + for i in range(len(attributes)): + print("i = ", i, attributes[i]) for i in range(len(attributes)): + #print("i = ", i, attributes[i]) if(i == 0): - array_to_dump = self.compute_moments(attributes[i])[:, :, N_g:-N_g,N_g:-N_g] + array_to_dump = self.compute_moments(attributes[i]) else: array_to_dump = af.join(1, array_to_dump, - self.compute_moments(attributes[i])[:, :, N_g:-N_g, N_g:-N_g] + self.compute_moments(attributes[i]) ) af.eval(array_to_dump) - af.flat(array_to_dump).to_ndarray(self._glob_moments_array) - viewer = PETSc.Viewer().createHDF5(file_name + '.h5', 'w', comm=self._comm) - viewer(self._glob_moments) - - # Following segment shows discrepancy due to buggy behaviour of af.mean - # Reported in https://github.com/QuazarTech/Bolt/issues/46 - # print("MEAN_n for species 1(RAW DATA):", af.mean(array_to_dump[:, 0, :, :])) - # print("MEAN_n for species 2(RAW DATA):", af.mean(array_to_dump[:, 1, :, :])) - - # h5f = h5py.File(file_name + '.h5', 'r') - # mom = np.swapaxes(h5f['moments'][:], 0, 1) - # h5f.close() + + af_to_petsc_glob_array(self, array_to_dump, self._glob_moments_array) - # print("MEAN_n for species 1(DUMP DATA):", np.mean(mom[:, :, 0])) - # print("MEAN_n for species 2(DUMP DATA):", np.mean(mom[:, :, 1])) + viewer = PETSc.Viewer().createBinary(file_name + '.bin', 'w', comm=self._comm) + viewer(self._glob_moments) def dump_distribution_function(self, file_name): """ @@ -138,16 +167,9 @@ def dump_distribution_function(self, file_name): >> solver.load_distribution_function('distribution_function') """ - N_g = self.N_ghost - - N_q1_local = self.f.shape[2] - N_q2_local = self.f.shape[3] - array_to_dump = self.f - - array_to_dump = af.flat(array_to_dump[:, :, N_g:-N_g, N_g:-N_g]) - array_to_dump.to_ndarray(self._glob_f_array) - viewer = PETSc.Viewer().createHDF5(file_name + '.h5', 'w', comm=self._comm) + af_to_petsc_glob_array(self, self.f, self._glob_f_array) + viewer = PETSc.Viewer().createBinary(file_name + '.bin', 'w', comm=self._comm) viewer(self._glob_f) return @@ -206,13 +228,13 @@ def dump_EM_fields(self, file_name): >> solver.load_EM_fields('data_EM_fields') """ - N_g = self.N_ghost - flattened_global_EM_fields_array = \ - af.flat(self.fields_solver.yee_grid_EM_fields[:, :, N_g:-N_g, N_g:-N_g]) - flattened_global_EM_fields_array.to_ndarray(self.fields_solver._glob_fields_array) - - viewer = PETSc.Viewer().createHDF5(file_name + '.h5', 'w', comm=self._comm) + af_to_petsc_glob_array(self, + self.fields_solver.yee_grid_EM_fields, + self.fields_solver._glob_fields_array + ) + + viewer = PETSc.Viewer().createBinary(file_name + '.bin', 'w', comm=self._comm) viewer(self.fields_solver._glob_fields) return diff --git a/bolt/lib/nonlinear/file_io/load.py b/bolt/lib/nonlinear/file_io/load.py index 95281bff..aabbc60b 100644 --- a/bolt/lib/nonlinear/file_io/load.py +++ b/bolt/lib/nonlinear/file_io/load.py @@ -5,6 +5,8 @@ import numpy as np import arrayfire as af +from bolt.lib.utils.af_petsc_conversion import petsc_local_array_to_af + def load_distribution_function(self, file_name): """ This function is used to load the distribution function from the @@ -24,22 +26,19 @@ def load_distribution_function(self, file_name): The above statemant will load the distribution function data stored in the file distribution_function.h5 into self.f """ - # 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() - viewer = PETSc.Viewer().createHDF5(file_name + '.h5', - PETSc.Viewer.Mode.READ, - comm=self._comm - ) + viewer = PETSc.Viewer().createBinary(file_name + '.bin', + PETSc.Viewer.Mode.READ, + comm=self._comm + ) self._glob_f.load(viewer) - N_g = self.N_ghost + self._da_f.globalToLocal(self._glob_f, self._local_f) - # Reassigning back the distribution function: - 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_species, N_q1_local, N_q2_local - ) + self.f = petsc_local_array_to_af(self, + self.N_p1*self.N_p2*self.N_p3, + self.N_species, + self._local_f_array + ) return @@ -62,23 +61,19 @@ def load_EM_fields(self, file_name): The above statemant will load the EM fields data stored in the file data_EM_fields.h5 into self.cell_centered_EM_fields """ - viewer = PETSc.Viewer().createHDF5(file_name + '.h5', - PETSc.Viewer.Mode.READ, - comm=self._comm - ) + viewer = PETSc.Viewer().createBinary(file_name + '.bin', + PETSc.Viewer.Mode.READ, + comm=self._comm + ) self.fields_solver._glob_fields.load(viewer) - # 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.fields_solver._da_fields.getCorners() - - N_g = self.N_ghost + self.fields_solver._da_fields.globalToLocal(self.fields_solver._glob_fields, + self.fields_solver._local_fields + ) - self.fields_solver.yee_grid_EM_fields[:, :, N_g:-N_g, N_g:-N_g] = \ - af.moddims(af.to_array(self.fields_solver._glob_fields_array), - 6, 1, N_q1_local, N_q2_local - ) + self.fields_solver.yee_grid_EM_fields = \ + petsc_local_array_to_af(self, 6, 1, self.fields_solver._local_fields_array) self.fields_solver.yee_grid_to_cell_centered_grid() return diff --git a/bolt/lib/nonlinear/finite_volume/df_dt_fvm.py b/bolt/lib/nonlinear/finite_volume/df_dt_fvm.py index 6e70a642..78e29dc0 100644 --- a/bolt/lib/nonlinear/finite_volume/df_dt_fvm.py +++ b/bolt/lib/nonlinear/finite_volume/df_dt_fvm.py @@ -88,9 +88,7 @@ def df_dt_fvm(f, self, term_to_return = 'all'): df_dt += - (right_flux - left_flux) / self.dq1 \ - (top_flux - bot_flux ) / self.dq2 \ - if( self.physical_system.params.source_enabled == True - and self.physical_system.params.instantaneous_collisions != True - ): + if(self.physical_system.params.source_enabled == True): df_dt += self._source(f, self.time_elapsed, self.q1_center, self.q2_center, self.p1_center, self.p2_center, self.p3_center, @@ -104,7 +102,7 @@ def df_dt_fvm(f, self, term_to_return = 'all'): if( self.physical_system.params.fields_type == 'electrodynamic' and self.fields_solver.at_n == False ): - + #TODO: Remove hybrid_model from lib and put into src if(self.physical_system.params.hybrid_model_enabled == True): communicate_fields(self.fields_solver, True) diff --git a/bolt/lib/nonlinear/finite_volume/fvm_operator.py b/bolt/lib/nonlinear/finite_volume/fvm_operator.py index 83622019..ab90b6dd 100644 --- a/bolt/lib/nonlinear/finite_volume/fvm_operator.py +++ b/bolt/lib/nonlinear/finite_volume/fvm_operator.py @@ -18,11 +18,9 @@ def timestep_fvm(self, dt): dt : double Time-step size to evolve the system """ - # self.fields_solver.check_maxwells_contraint_equations(af.sum(-10 * self.compute_moments('density'), 1)) - # rho_n = -1 * self.compute_moments('density') - # rho_n[0, 1] = -1 * rho_n[0, 1] - # rho_n = af.sum(rho_n, 1) + self._communicate_f() + self._apply_bcs_f() f_initial = self.f # this is f^{n} self.f = self.f + df_dt_fvm(self.f, self) * (dt / 2) # this is f{n+1/2} @@ -34,66 +32,14 @@ def timestep_fvm(self, dt): # there df_dt() is the function that returns df / dt self.f = f_initial + df_dt_fvm(self.f, self) * dt - # self.count += 1 - - # rho_n_plus_one = -1 * self.compute_moments('density') - # rho_n_plus_one[0, 1] = -1 * rho_n_plus_one[0, 1] - # rho_n_plus_one = af.sum(rho_n_plus_one, 1) - - # drho_dt = (rho_n_plus_one - rho_n) / dt - - # J1 = self.fields_solver.J1 - # J2 = self.fields_solver.J2 - - # J1_plus_q1 = af.shift(self.fields_solver.J1, 0, 0, -1) - # J2_plus_q2 = af.shift(self.fields_solver.J2, 0, 0, 0, -1) - - # divJ = (J1_plus_q1 - J1) / self.dq1 + (J2_plus_q2 - J2) / self.dq2 - - # print(af.mean(af.abs(drho_dt + divJ)[:, :, 4:-4, 4:-4])) - - # print(af.sum(af.abs(af.sum(((self.f - f_initial)*0 / dt + - # 0*multiply(self.p1_center, (af.shift(self.f_left, 0, 0, -1) - self.f_left) / self.dq1) + - # multiply(-10 * self.fields_solver.cell_centered_EM_fields[0], (self.f_right_p1 - self.f_left_p1) / self.dp1)), 1 - # ) - # ) - # ) - # ) - - # self.data[self.count] = af.sum(af.abs(af.sum(((self.f - f_initial) / dt + - # multiply(self.p1_center, (af.shift(self.f_left, 0, 0, -1) - self.f_left) / self.dq1) + - # multiply(-10 * self.fields_solver.cell_centered_EM_fields_at_n[0], (self.f_right_p1 - self.f_left_p1) / self.dp1)), 0 - # ) - # ) - # ) - - # print(self.data[self.count]) - # print(af.sum(af.abs(multiply(-10 * self.fields_solver.cell_centered_EM_fields_at_n[0], (self.f[-1] - self.f[0]) / self.dp1)))) - -def update_for_instantaneous_collisions(self, dt): - - self.f = self._source(self.f, self.time_elapsed, - self.q1_center, self.q2_center, - self.p1_center, self.p2_center, self.p3_center, - self.compute_moments, - self.physical_system.params, - True - ) - return def op_fvm(self, dt): - self._communicate_f() - self._apply_bcs_f() - if(self.performance_test_flag == True): tic = af.time() - if(self.physical_system.params.instantaneous_collisions == True): - split.strang(self, timestep_fvm, update_for_instantaneous_collisions, dt) - else: - timestep_fvm(self, dt) + timestep_fvm(self, dt) af.eval(self.f) if(self.performance_test_flag == True): diff --git a/bolt/lib/nonlinear/nonlinear_solver.py b/bolt/lib/nonlinear/nonlinear_solver.py index ed46382f..123a3de3 100644 --- a/bolt/lib/nonlinear/nonlinear_solver.py +++ b/bolt/lib/nonlinear/nonlinear_solver.py @@ -44,13 +44,10 @@ from bolt.lib.utils.performance_timings import print_table from bolt.lib.utils.broadcasted_primitive_operations import multiply -from bolt.lib.utils.calculate_q import \ - calculate_q_center, calculate_q_left_center, \ - calculate_q_center_bot, calculate_q_left_bot +from bolt.lib.utils.calculate_q import calculate_q -from bolt.lib.utils.calculate_p import \ - calculate_p_center, calculate_p_left, \ - calculate_p_bottom, calculate_p_back +from bolt.lib.utils.calculate_p import calculate_p_center +from bolt.lib.utils.calculate_p import calculate_p_corner from .compute_moments import compute_moments as compute_moments_imported from .fields.fields import fields_solver @@ -130,8 +127,9 @@ def __init__(self, physical_system, performance_test_flag = False): af.set_device(self._comm.rank%self.physical_system.params.num_devices) # Getting number of species: - N_s = self.N_species = len(physical_system.params.mass) + N_s = self.N_species = self.physical_system.N_species + # TODO: Remove mass and charge from lib if(type(physical_system.params.mass) == list): # Having a temporary copy of the lists to copy to af.Array: list_mass = physical_system.params.mass.copy() @@ -176,8 +174,8 @@ def __init__(self, physical_system, performance_test_flag = False): self.time_apply_bcs_f = 0 self.time_communicate_f = 0 - petsc_bc_in_q1 = 'ghosted' - petsc_bc_in_q2 = 'ghosted' + petsc_bc_in_q1 = 'ghosted'; self.N_g1 = self.N_ghost + petsc_bc_in_q2 = 'ghosted'; self.N_g2 = self.N_ghost # Only for periodic boundary conditions or shearing-box boundary conditions # do the boundary conditions passed to the DA need to be changed. PETSc @@ -196,6 +194,12 @@ def __init__(self, physical_system, performance_test_flag = False): ): petsc_bc_in_q2 = 'periodic' + if(self.boundary_conditions.in_q1_left == 'none'): + petsc_bc_in_q1 = 'none'; self.N_g1 = 0 + + if(self.boundary_conditions.in_q2_bottom == 'none'): + petsc_bc_in_q2 = 'none'; self.N_g2 = 0 + if(self.boundary_conditions.in_q1_left == 'periodic'): try: assert(self.boundary_conditions.in_q1_right == 'periodic') @@ -228,6 +232,22 @@ def __init__(self, physical_system, performance_test_flag = False): both the boundaries of a particular axis' ) + if(self.boundary_conditions.in_q1_left == 'none'): + try: + assert(self.boundary_conditions.in_q1_right == 'none') + except: + raise Exception('NONE boundary conditions need to be applied to \ + both the boundaries of a particular axis' + ) + + if(self.boundary_conditions.in_q2_bottom == 'none'): + try: + assert(self.boundary_conditions.in_q2_top == 'none') + except: + raise Exception('NONE boundary conditions need to be applied to \ + both the boundaries of a particular axis' + ) + nproc_in_q1 = PETSc.DECIDE nproc_in_q2 = PETSc.DECIDE @@ -269,13 +289,17 @@ def __init__(self, physical_system, performance_test_flag = False): self._da_dump_moments = PETSc.DMDA().create([self.N_q1, self.N_q2], dof = self.N_species - * len(attributes), + * (len(attributes)-3), # don't count af, integral_over_p, and params in moments.py proc_sizes = (nproc_in_q1, nproc_in_q2 ), comm = self._comm ) + # For dumping aux arrays: + self.dump_aux_arrays_initial_call = 1 + + # Creation of the local and global vectors from the DA: # This is for the distribution function self._glob_f = self._da_f.createGlobalVec() @@ -294,33 +318,48 @@ def __init__(self, physical_system, performance_test_flag = False): PETSc.Object.setName(self._glob_f, 'distribution_function') PETSc.Object.setName(self._glob_moments, 'moments') - # 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() - # Obtaining the end coordinates for the local zone - (i_q1_end, i_q2_end) = (i_q1_start + N_q1_local - 1, i_q2_start + N_q2_local - 1) - - # Obtaining the array values of the cannonical variables: - self.q1_center, self.q2_center = \ - calculate_q_center(self.q1_start + i_q1_start * self.dq1, - self.q2_start + i_q2_start * self.dq2, - N_q1_local, N_q2_local, N_g, - self.dq1, self.dq2 - ) + # Indexing vars used through out + self.i_q1_start = self.N_g1; self.i_q1_end = -self.N_g1 + self.i_q2_start = self.N_g2; self.i_q2_end = -self.N_g2 + if (self.N_g1 == 0): + self.i_q1_end = 1 - self.q1_left_center, self.q2_left_center = \ - calculate_q_left_center(self.q1_start + i_q1_start * self.dq1, - self.q2_start + i_q2_start * self.dq2, - N_q1_local, N_q2_local, self.N_ghost, - self.dq1, self.dq2 - ) - - self.q1_center_bot, self.q2_center_bot = \ - calculate_q_center_bot(self.q1_start + i_q1_start * self.dq1, - self.q2_start + i_q2_start * self.dq2, - N_q1_local, N_q2_local, self.N_ghost, - self.dq1, self.dq2 - ) + if (self.N_g2 == 0): + self.i_q2_end = 1 + + # Get start (corner) indices of the local zone wrt global ordering and its size + ((_i_q1_start, _i_q2_start), (_N_q1_local, _N_q2_local)) = self._da_f.getCorners() + + # Coordinates of the local zone in a global coord system + self.q1_start_local = self.q1_start + _i_q1_start * self.dq1 + self.q2_start_local = self.q2_start + _i_q2_start * self.dq2 + + self.N_q1_local = _N_q1_local + self.N_q2_local = _N_q2_local + + self.N_q1_local_with_Ng = _N_q1_local + 2*self.N_g1 + self.N_q2_local_with_Ng = _N_q2_local + 2*self.N_g2 + + # Obtaining the array values of spatial coordinates: + q_left_bot, q_center_bot, q_left_center, q_center = \ + calculate_q(self.q1_start_local, + self.q2_start_local, + self.N_q1_local, self.N_q2_local, + self.N_g1, self.N_g2, + self.dq1, self.dq2 + ) + + self.q1_left_bot = q_left_bot[0] + self.q2_left_bot = q_left_bot[1] + + self.q1_center_bot = q_center_bot[0] + self.q2_center_bot = q_center_bot[1] + + self.q1_left_center = q_left_center[0] + self.q2_left_center = q_left_center[1] + + self.q1_center = q_center[0] + self.q2_center = q_center[1] self.p1_center, self.p2_center, self.p3_center = \ calculate_p_center(self.p1_start, self.p2_start, self.p3_start, @@ -328,30 +367,19 @@ def __init__(self, physical_system, performance_test_flag = False): self.dp1, self.dp2, self.dp3, ) - self.p1_left, self.p2_left, self.p3_left = \ - calculate_p_left(self.p1_start, self.p2_start, self.p3_start, - self.N_p1, self.N_p2, self.N_p3, - self.dp1, self.dp2, self.dp3, - ) - - self.p1_bottom, self.p2_bottom, self.p3_bottom = \ - calculate_p_bottom(self.p1_start, self.p2_start, self.p3_start, + self.p1_left, self.p2_bottom, self.p3_back = \ + calculate_p_corner(self.p1_start, self.p2_start, self.p3_start, self.N_p1, self.N_p2, self.N_p3, self.dp1, self.dp2, self.dp3, ) - self.p1_back, self.p2_back, self.p3_back = \ - calculate_p_back(self.p1_start, self.p2_start, self.p3_start, - self.N_p1, self.N_p2, self.N_p3, - self.dp1, self.dp2, self.dp3, - ) - - # Converting dp1, dp2, dp3 to af.Array: + # Need to convert the lists dp1, dp2, dp3 to af.Arrays for vector + # computations to work self.dp1 = af.moddims(af.to_array(np.array(self.dp1)), 1, self.N_species) self.dp2 = af.moddims(af.to_array(np.array(self.dp2)), 1, self.N_species) self.dp3 = af.moddims(af.to_array(np.array(self.dp3)), 1, self.N_species) - # Converting p_start and p_end to af.Array: + # Need to do the same for the p1_start/end lists. self.p1_start = af.moddims(af.to_array(self.p1_start), 1, self.N_species) self.p2_start = af.moddims(af.to_array(self.p2_start), 1, self.N_species) self.p3_start = af.moddims(af.to_array(self.p3_start), 1, self.N_species) @@ -360,47 +388,21 @@ def __init__(self, physical_system, performance_test_flag = False): self.p2_end = af.moddims(af.to_array(self.p2_end), 1, self.N_species) self.p3_end = af.moddims(af.to_array(self.p3_end), 1, self.N_species) + self.p2_left = self.p2_center + self.p3_left = self.p3_center + + self.p1_bottom = self.p1_center + self.p3_bottom = self.p3_center + + self.p1_back = self.p1_center + self.p2_back = self.p2_center + # Initialize according to initial condition provided by user: self._initialize(physical_system.params) # Initializing a variable to track time-elapsed: self.time_elapsed = 0 - # Applying dirichlet boundary conditions: - # Arguments that are passing to the called functions: - args = (self.f, self.time_elapsed, self.q1_center, self.q2_center, - self.p1_center, self.p2_center, self.p3_center, - self.physical_system.params - ) - - if(self.physical_system.boundary_conditions.in_q1_left == 'dirichlet'): - # If local zone includes the left physical boundary: - if(i_q1_start == 0): - self.f[:, :, :N_g] = self.boundary_conditions.\ - f_left(*args)[:, :, :N_g] - - if(self.physical_system.boundary_conditions.in_q1_right == 'dirichlet'): - # If local zone includes the right physical boundary: - if(i_q1_end == self.N_q1 - 1): - self.f[:, :, -N_g:] = self.boundary_conditions.\ - f_right(*args)[:, :, -N_g:] - - if(self.physical_system.boundary_conditions.in_q2_bottom == 'dirichlet'): - # If local zone includes the bottom physical boundary: - if(i_q2_start == 0): - self.f[:, :, :, :N_g] = self.boundary_conditions.\ - f_bot(*args)[:, :, :, :N_g] - - if(self.physical_system.boundary_conditions.in_q2_top == 'dirichlet'): - # If local zone includes the top physical boundary: - if(i_q2_end == self.N_q2 - 1): - self.f[:, :, :, -N_g:] = self.boundary_conditions.\ - f_top(*args)[:, :, :, -N_g:] - - # Assigning the value to the PETSc Vecs(for dump at t = 0): - (af.flat(self.f)).to_ndarray(self._local_f_array) - (af.flat(self.f[:, :, N_g:-N_g, N_g:-N_g])).to_ndarray(self._glob_f_array) - # Assigning the function objects to methods of the solver: self._A_q = physical_system.A_q self._C_q = physical_system.C_q @@ -418,26 +420,22 @@ def _convert_to_q_expanded(self, array): which can be used such that the computations may carried out along all dimensions necessary: - q_expanded form:(N_p1 * N_p2 * N_p3, N_s, N_q1, N_q2) - p_expanded form:(N_p1, N_p2, N_p3, N_s * N_q1 * N_q2) + q_expanded form:(N_p1 * N_p2 * N_p3, N_species, N_q1, N_q2) + p_expanded form:(N_p1, N_p2, N_p3, N_species * N_q1 * N_q2) This function converts the input array from p_expanded to 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() array = af.moddims(array, self.N_p1 * self.N_p2 * self.N_p3, self.N_species, - (N_q1_local + 2 * self.N_ghost), - (N_q2_local + 2 * self.N_ghost) + self.N_q1_local_with_Ng, + self.N_q2_local_with_Ng ) - af.eval(array) return (array) def _convert_to_p_expanded(self, array): @@ -447,24 +445,20 @@ def _convert_to_p_expanded(self, array): which can be used such that the computations may carried out along all dimensions necessary: - q_expanded form:(N_p1 * N_p2 * N_p3, N_s, N_q1, N_q2) - p_expanded form:(N_p1, N_p2, N_p3, N_s * N_q1 * N_q2) + q_expanded form:(N_p1 * N_p2 * N_p3, N_species, N_q1, N_q2) + p_expanded form:(N_p1, N_p2, N_p3, N_species * N_q1 * N_q2) This function converts the input array from q_expanded to p_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() - + array = af.moddims(array, self.N_p1, self.N_p2, self.N_p3, self.N_species - * (N_q1_local + 2 * self.N_ghost) - * (N_q2_local + 2 * self.N_ghost) + * self.N_q1_local_with_Ng + * self.N_q2_local_with_Ng ) - af.eval(array) return (array) def _initialize(self, params): @@ -506,8 +500,7 @@ def _initialize(self, params): ) # Injection of solver functions into class as methods: - _communicate_f = communicate.\ - communicate_f + _communicate_f = communicate.communicate_f _apply_bcs_f = boundaries.apply_bcs_f strang_timestep = timestep.strang_step @@ -519,6 +512,7 @@ def _initialize(self, params): dump_distribution_function = dump.dump_distribution_function dump_moments = dump.dump_moments + dump_aux_arrays = dump.dump_aux_arrays dump_EM_fields = dump.dump_EM_fields load_distribution_function = load.load_distribution_function diff --git a/bolt/lib/nonlinear/tests/test_petsc_IO.py b/bolt/lib/nonlinear/tests/test_petsc_IO.py new file mode 100644 index 00000000..9ec92f03 --- /dev/null +++ b/bolt/lib/nonlinear/tests/test_petsc_IO.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Importing dependencies: +import sys, petsc4py +petsc4py.init(sys.argv) + +from petsc4py import PETSc +import numpy as np + +N_p1 = 64 +N_p2 = 64 +N_p3 = 64 +N_q1 = 96 +N_q2 = 64 + +N_ghost = 3 + +da_dump_f = PETSc.DMDA().create([N_q1, N_q2], # Spatial resolution + dof = (N_p1*N_p2*N_p3), # number of variables + stencil_width = N_ghost + ) + +glob_f = da_dump_f.createGlobalVec() # PETSc vec +PETSc.Object.setName(glob_f, 'distribution_function') + +# Get a numpy array from the PETSc vec +glob_f_array = glob_f.getArray() + +# Work with the numpy array. For example, +# time_step(glob_f_array) + +# Now dump the data. First create a PETSc Binary MPIIO viewer. +viewer = PETSc.Viewer().createBinary('binary_using_petsc.bin', 'w', comm=PETSc.COMM_WORLD) + +# Finally dump. Note that glob_f_array is linked to glob_f. +viewer(glob_f) + +# Now try with a PETSc HDF5 viewer. +viewer = PETSc.Viewer().createHDF5('hdf5_using_petsc.h5', 'w', comm=PETSc.COMM_WORLD) +viewer(glob_f) + diff --git a/bolt/lib/physical_system.py b/bolt/lib/physical_system.py index e17d64da..9fc21738 100644 --- a/bolt/lib/physical_system.py +++ b/bolt/lib/physical_system.py @@ -111,6 +111,7 @@ def __init__(self, # Finding the number of species: N_species = len(params.charge) + self.N_species = N_species try: assert(len(params.mass) == len(params.charge)) diff --git a/bolt/lib/utils/af_petsc_conversion.py b/bolt/lib/utils/af_petsc_conversion.py new file mode 100644 index 00000000..7f59d624 --- /dev/null +++ b/bolt/lib/utils/af_petsc_conversion.py @@ -0,0 +1,38 @@ +import arrayfire as af + +def af_to_petsc_glob_array(domain_metadata, af_array, glob_array): + + # domaint_metadata obj should contain the following + i_q1_start = domain_metadata.i_q1_start # start index of bulk domain + i_q1_end = domain_metadata.i_q1_end # end index, before ghost zones + + i_q2_start = domain_metadata.i_q2_start + i_q2_end = domain_metadata.i_q2_end + + tmp_array = af.flat(af_array[:, :, + i_q1_start:i_q1_end, + i_q2_start:i_q2_end + ] + ) + + tmp_array.to_ndarray(glob_array) + + return + +def petsc_local_array_to_af(domain_metadata, + N_vars_axis_0, + N_vars_axis_1, + local_array + ): + + flat_af_array = af.to_array(local_array) + + #resize to the appropriate shape + af_array = af.moddims(flat_af_array, + N_vars_axis_0, + N_vars_axis_1, + domain_metadata.N_q1_local_with_Ng, + domain_metadata.N_q2_local_with_Ng + ) + + return(af_array) diff --git a/bolt/lib/utils/calculate_p.py b/bolt/lib/utils/calculate_p.py index a69f5ec4..79b3bfbb 100644 --- a/bolt/lib/utils/calculate_p.py +++ b/bolt/lib/utils/calculate_p.py @@ -4,6 +4,32 @@ import numpy as np import arrayfire as af + +def calculate_p_corner(p1_start, p2_start, p3_start, + N_p1, N_p2, N_p3, + dp1, dp2, dp3, + ): + """ + Initializes the cannonical variables p1, p2 and p3 at the corners of the + momentum space grid zone + """ + p1_corner = af.constant(0, N_p1 * N_p2 * N_p3, len(p1_start), dtype = af.Dtype.f64) + p2_corner = af.constant(0, N_p1 * N_p2 * N_p3, len(p2_start), dtype = af.Dtype.f64) + p3_corner = 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] + (np.arange(N_p1)) * dp1[i] + p2 = p2_start[i] + (np.arange(N_p2)) * dp2[i] + p3 = p3_start[i] + (np.arange(N_p3)) * dp3[i] + + p2_corner[:, i] = af.flat(af.to_array(np.meshgrid(p2, p1, p3)[0])) + p1_corner[:, i] = af.flat(af.to_array(np.meshgrid(p2, p1, p3)[1])) + p3_corner[:, i] = af.flat(af.to_array(np.meshgrid(p2, p1, p3)[2])) + + return (p1_corner, p2_corner, p3_corner) + def calculate_p_center(p1_start, p2_start, p3_start, N_p1, N_p2, N_p3, dp1, dp2, dp3, @@ -29,69 +55,3 @@ def calculate_p_center(p1_start, p2_start, p3_start, af.eval(p1_center, p2_center, p3_center) return (p1_center, p2_center, p3_center) - -def calculate_p_left(p1_start, p2_start, p3_start, - N_p1, N_p2, N_p3, - dp1, dp2, dp3, - ): - p1_left = af.constant(0, N_p1 * N_p2 * N_p3, len(p1_start), dtype = af.Dtype.f64) - p2_left = af.constant(0, N_p1 * N_p2 * N_p3, len(p2_start), dtype = af.Dtype.f64) - p3_left = 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] + 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_left[:, i] = af.flat(af.to_array(np.meshgrid(p2, p1, p3)[0])) - p1_left[:, i] = af.flat(af.to_array(np.meshgrid(p2, p1, p3)[1])) - p3_left[:, i] = af.flat(af.to_array(np.meshgrid(p2, p1, p3)[2])) - - af.eval(p1_left, p2_left, p3_left) - return (p1_left, p2_left, p3_left) - -def calculate_p_bottom(p1_start, p2_start, p3_start, - N_p1, N_p2, N_p3, - dp1, dp2, dp3, - ): - p1_bottom = af.constant(0, N_p1 * N_p2 * N_p3, len(p1_start), dtype = af.Dtype.f64) - p2_bottom = af.constant(0, N_p1 * N_p2 * N_p3, len(p2_start), dtype = af.Dtype.f64) - p3_bottom = 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] + np.arange(N_p2) * dp2[i] - p3 = p3_start[i] + (0.5 + np.arange(N_p3)) * dp3[i] - - p2_bottom[:, i] = af.flat(af.to_array(np.meshgrid(p2, p1, p3)[0])) - p1_bottom[:, i] = af.flat(af.to_array(np.meshgrid(p2, p1, p3)[1])) - p3_bottom[:, i] = af.flat(af.to_array(np.meshgrid(p2, p1, p3)[2])) - - af.eval(p1_bottom, p2_bottom, p3_bottom) - return (p1_bottom, p2_bottom, p3_bottom) - -def calculate_p_back(p1_start, p2_start, p3_start, - N_p1, N_p2, N_p3, - dp1, dp2, dp3, - ): - p2_back = af.constant(0, N_p1 * N_p2 * N_p3, len(p1_start), dtype = af.Dtype.f64) - p1_back = af.constant(0, N_p1 * N_p2 * N_p3, len(p2_start), dtype = af.Dtype.f64) - p3_back = 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] + np.arange(N_p3) * dp3[i] - - p2_back[:, i] = af.flat(af.to_array(np.meshgrid(p2, p1, p3)[0])) - p1_back[:, i] = af.flat(af.to_array(np.meshgrid(p2, p1, p3)[1])) - p3_back[:, i] = af.flat(af.to_array(np.meshgrid(p2, p1, p3)[2])) - - af.eval(p1_back, p2_back, p3_back) - return (p1_back, p2_back, p3_back) diff --git a/bolt/lib/utils/calculate_q.py b/bolt/lib/utils/calculate_q.py index 18a106d3..e6207aad 100644 --- a/bolt/lib/utils/calculate_q.py +++ b/bolt/lib/utils/calculate_q.py @@ -4,81 +4,14 @@ import numpy as np import arrayfire as af -def calculate_q_center(q1_start, q2_start, - N_q1, N_q2, N_g, - dq1, dq2 - ): - """ - Initializes the cannonical variables q1, q2 using a centered - formulation. +def calculate_q(q1_start, q2_start, + N_q1, N_q2, + N_g1, N_g2, + dq1, dq2 + ): - Returns in q_expanded form. - """ - i_q1 = (0.5 + np.arange(-N_g, N_q1 + N_g)) - i_q2 = (0.5 + np.arange(-N_g, N_q2 + N_g)) - - q1_center = q1_start + i_q1 * dq1 - q2_center = q2_start + i_q2 * 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 calculate_q_left_center(q1_start, q2_start, - N_q1, N_q2, N_g, - dq1, dq2 - ): - - i_q1 = np.arange(-N_g, N_q1 + N_g) - i_q2 = (0.5 + np.arange(-N_g, N_q2 + N_g)) - - q1_left_center = q1_start + i_q1 * dq1 - q2_left_center = q2_start + i_q2 * dq2 - - q2_left_center, q1_left_center = np.meshgrid(q2_left_center, q1_left_center) - q2_left_center, q1_left_center = af.to_array(q2_left_center), af.to_array(q1_left_center) - - # To bring the data structure to the default form:(N_p, N_s, N_q1, N_q2) - q1_left_center = af.reorder(q1_left_center, 3, 2, 0, 1) - q2_left_center = af.reorder(q2_left_center, 3, 2, 0, 1) - - af.eval(q1_left_center, q2_left_center) - return (q1_left_center, q2_left_center) - -def calculate_q_center_bot(q1_start, q2_start, - N_q1, N_q2, N_g, - dq1, dq2 - ): - - i_q1 = (0.5 + np.arange(-N_g, N_q1 + N_g)) - i_q2 = np.arange(-N_g, N_q2 + N_g) - - q1_center_bot = q1_start + i_q1 * dq1 - q2_center_bot = q2_start + i_q2 * dq2 - - q2_center_bot, q1_center_bot = np.meshgrid(q2_center_bot, q1_center_bot) - q2_center_bot, q1_center_bot = af.to_array(q2_center_bot), af.to_array(q1_center_bot) - - # To bring the data structure to the default form:(N_p, N_s, N_q1, N_q2) - q1_center_bot = af.reorder(q1_center_bot, 3, 2, 0, 1) - q2_center_bot = af.reorder(q2_center_bot, 3, 2, 0, 1) - - af.eval(q1_center_bot, q2_center_bot) - return (q1_center_bot, q2_center_bot) - -def calculate_q_left_bot(q1_start, q2_start, - N_q1, N_q2, N_g, - dq1, dq2 - ): - - i_q1 = np.arange(-N_g, N_q1 + N_g) - i_q2 = np.arange(-N_g, N_q2 + N_g) + 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 @@ -90,5 +23,19 @@ def calculate_q_left_bot(q1_start, q2_start, q1_left_bot = af.reorder(q1_left_bot, 3, 2, 0, 1) q2_left_bot = af.reorder(q2_left_bot, 3, 2, 0, 1) - af.eval(q1_left_bot, q2_left_bot) - return (q1_left_bot, q2_left_bot) + 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) diff --git a/bolt/lib/utils/parallel_reduction_ops.py b/bolt/lib/utils/parallel_reduction_ops.py new file mode 100644 index 00000000..68fb3bec --- /dev/null +++ b/bolt/lib/utils/parallel_reduction_ops.py @@ -0,0 +1,28 @@ +import numpy as np +from petsc4py import PETSc +from mpi4py import MPI + +def global_mean(af_array): + local_mean = np.mean(np.array(af_array)) + comm = PETSc.COMM_WORLD.tompi4py() + + global_mean = comm.allreduce(sendobj=local_mean, op=MPI.SUM) \ + / comm.size + + return global_mean + +def global_min(af_array): + local_min = np.min(np.array(af_array)) + comm = PETSc.COMM_WORLD.tompi4py() + + global_min = comm.allreduce(sendobj=local_min, op=MPI.MIN) + + return global_min + +def global_max(af_array): + local_max = np.min(np.array(af_array)) + comm = PETSc.COMM_WORLD.tompi4py() + + global_max = comm.allreduce(sendobj=local_min, op=MPI.MAX) + + return global_max diff --git a/bolt/lib/utils/restart_latest.py b/bolt/lib/utils/restart_latest.py new file mode 100644 index 00000000..5ca2ed51 --- /dev/null +++ b/bolt/lib/utils/restart_latest.py @@ -0,0 +1,32 @@ +# The following function is used to return _f for the latest output +def latest_output(path): + """ + This function looks in the dump_f folder in the provided path + directory and identifies the latest dump file. + WARNING this function is currently unsafe for corrupted dump files, which + can occur in particular if an allocation expires while the code is writing + to disk. + """ + import numpy as np + import glob + import os + dump_f_names = np.sort(glob.glob(os.path.join(path, 'dump_f/t=*.bin'))) + + ndumps = dump_f_names.size + + if(ndumps > 0): + latest_f = dump_f_names[ndumps-1].rsplit('.',1)[0] + time_elapsed = float(latest_f.rsplit('/',1)[1][2:]) + return latest_f, time_elapsed + else: + return None, None + +def format_time(time): + """ + This function formats a time value given as an integer or a float and + returns a string appropriately padded with zeros. + Right now format is [8].[6]. + """ + x = float(time) + return (str(x).split('.')[0].zfill(8) + '.' + + str(x).split('.')[1].ljust(6, '0')) diff --git a/bolt/src/electronic_boltzmann/advection_terms.py b/bolt/src/electronic_boltzmann/advection_terms.py new file mode 100644 index 00000000..46940cb9 --- /dev/null +++ b/bolt/src/electronic_boltzmann/advection_terms.py @@ -0,0 +1,176 @@ +#import numpy as np +import arrayfire as af + +""" +Here we define the advection terms for the +nonrelativistic Boltzmann equation. + +The equation that we are solving is: + df/dt + v_x * df/dq1 + v_y * df/dy ++ e/m * (E + v X B)_x * df/dv_x ++ e/m * (E + v X B)_y * df/dv_y ++ e/m * (E + v X B)_y * df/dv_z = 0 + +In the solver framework this can be described using: + q1 = x ; q2 = y + p1 = v1 = v_x; p2 = v2 = v_y; p3 = v3 = v_z + A_q1 = C_q1 = v_x = v1 + A_q2 = C_q2 = v_y = v2 + A_v1 = C_v1 = e/m * (E_x + v_y * B_z - v_z * B_y) = e/m * (E1 + v2 * B3 - v3 * B2) + A_v2 = C_v2 = e/m * (E_y + v_z * B_x - v_x * B_z) = e/m * (E2 + v3 * B1 - v1 * B3) + A_v3 = C_v3 = e/m * (E_z + v_x * B_y - v_y * B_x) = e/m * (E3 + v1 * B2 - v2 * B1) + +""" + +def A_q(t, q1, q2, p1, p2, p3, params): + """ + Return the terms A_q1, A_q2. + + Parameters: + ----------- + t : Time elapsed + + q1 : The array that holds data for the q1 dimension in q-space + shape:(1, 1, N_q1, N_q2) + + q2 : The array that holds data for the q2 dimension in q-space + shape:(1, 1, N_q1, N_q2) + + v1 : The array that holds data for the v1 dimension in v-space + shape:(N_v, N_s, 1, 1) + + v2 : The array that holds data for the v2 dimension in v-space + shape:(N_v, N_s, 1, 1) + + v3 : The array that holds data for the v3 dimension in v-space + shape:(N_v, N_s, 1, 1) + + params: The parameters file/object that is originally declared by the user. + This can be used to inject other functions/attributes into the function + """ + + A_q1, A_q2 = params.vel_band + + return (A_q1, A_q2) + +def C_q(t, q1, q2, p1, p2, p3, params): + """ + Return the terms C_q1, C_q2. + + Parameters: + ----------- + t : Time elapsed + + q1 : The array that holds data for the q1 dimension in q-space + shape:(1, 1, N_q1, N_q2) + + q2 : The array that holds data for the q2 dimension in q-space + shape:(1, 1, N_q1, N_q2) + + v1 : The array that holds data for the v1 dimension in v-space + shape:(N_v, N_s, 1, 1) + + v2 : The array that holds data for the v2 dimension in v-space + shape:(N_v, N_s, 1, 1) + + v3 : The array that holds data for the v3 dimension in v-space + shape:(N_v, N_s, 1, 1) + + params: The parameters file/object that is originally declared by the user. + This can be used to inject other functions/attributes into the function + + """ + C_q1, C_q2 = params.vel_band + + return (C_q1, C_q2) + +# This can then be called inside A_p if needed: +# F1 = (params.char....)(E1 + ....) + T1(q1, q2, p1, p2, p3) + +def A_p(t, q1, q2, p1, p2, p3, + E1, E2, E3, B1, B2, B3, + params + ): + """ + Return the terms A_v1, A_v2 and A_v3. + + Parameters: + ----------- + t : Time elapsed + + q1 : The array that holds data for the q1 dimension in q-space + shape:(1, 1, N_q1, N_q2) + + q2 : The array that holds data for the q2 dimension in q-space + shape:(1, 1, N_q1, N_q2) + + v1 : The array that holds data for the v1 dimension in v-space + shape:(N_v, N_s, 1, 1) + + v2 : The array that holds data for the v2 dimension in v-space + shape:(N_v, N_s, 1, 1) + + v3 : The array that holds data for the v3 dimension in v-space + shape:(N_v, N_s, 1, 1) + + fields_solver: The solver object whose method get_fields() is used to + obtain the EM field quantities + + params: The parameters file/object that is originally declared by the user. + This can be used to inject other functions/attributes into the function + """ + e = params.charge_electron + c = params.speed_of_light + B3_mean = params.B3_mean + + v1, v2 = params.vel_band + + dp1_dt = e*(E1 + v2*B3_mean/c) # p1 = hcross * k1 + dp2_dt = e*(E2 - v1*B3_mean/c) # p2 = hcross * k2 + dp3_dt = 0.*p1 + + return (dp1_dt, dp2_dt, dp3_dt) + +def C_p(t, q1, q2, p1, p2, p3, + E1, E2, E3, B1, B2, B3, + params + ): + """ + Return the terms C_v1, C_v2 and C_v3. + + Parameters: + ----------- + t : Time elapsed + + q1 : The array that holds data for the q1 dimension in q-space + shape:(1, 1, N_q1, N_q2) + + q2 : The array that holds data for the q2 dimension in q-space + shape:(1, 1, N_q1, N_q2) + + v1 : The array that holds data for the v1 dimension in v-space + shape:(N_v, N_s, 1, 1) + + v2 : The array that holds data for the v2 dimension in v-space + shape:(N_v, N_s, 1, 1) + + v3 : The array that holds data for the v3 dimension in v-space + shape:(N_v, N_s, 1, 1) + + fields_solver: The solver object whose method get_fields() is used to + obtain the EM field quantities + + params: The parameters file/object that is originally declared by the user. + This can be used to inject other functions/attributes into the function + """ + e = params.charge_electron + c = params.speed_of_light + B3_mean = params.B3_mean + + v1, v2 = params.vel_band + + dp1_dt = e*(E1 + v2*B3_mean/c) # p1 = hcross * k1 + dp2_dt = e*(E2 - v1*B3_mean/c) # p2 = hcross * k2 + dp3_dt = 0.*p1 + + return (dp1_dt, dp2_dt, dp3_dt) diff --git a/bolt/src/electronic_boltzmann/collision_operator.py b/bolt/src/electronic_boltzmann/collision_operator.py new file mode 100644 index 00000000..42c94f19 --- /dev/null +++ b/bolt/src/electronic_boltzmann/collision_operator.py @@ -0,0 +1,88 @@ +"""Contains the function which returns the Source/Sink term.""" + +from petsc4py import PETSc +import numpy as np +import arrayfire as af + +#from bolt.lib.nonlinear.compute_moments import compute_moments + +from .f_local_equilibrium import f0_ee, f0_defect +from .f_local_equilibrium_zero_T import f0_ee_constant_T, f0_defect_constant_T + +from .matrix_inverse import inverse_4x4_matrix +from .matrix_inverse import inverse_3x3_matrix +from bolt.src.utils.integral_over_p import integral_over_p + +import domain + + +def RTA(f, t, q1, q2, p1, p2, p3, moments, params, flag = False): + """ + Return RTA (Relaxation Time Approximation) operator + - (f-f0_D)/tau_D - (f-f0_ee)/tau_ee + + Parameters: + ----------- + f : Distribution function array + shape:(N_v, N_s, N_q1, N_q2) + + t : Time elapsed + + q1 : The array that holds data for the q1 dimension in q-space + shape:(1, 1, N_q1, N_q2) + + q2 : The array that holds data for the q2 dimension in q-space + shape:(1, 1, N_q1, N_q2) + + p1 : The array that holds data for the v1 dimension in v-space + shape:(N_v, N_s, 1, 1) + + p2 : The array that holds data for the v2 dimension in v-space + shape:(N_v, N_s, 1, 1) + + p3 : The array that holds data for the v3 dimension in v-space + shape:(N_v, N_s, 1, 1) + + params: The parameters file/object that is originally declared by the user. + This can be used to inject other functions/attributes into the function + + flag: Toggle used for evaluating tau = 0 cases need to be evaluated. When set to True, this + function is made to return f0, thus setting f = f0 wherever tau = 0 + """ + + p_x, p_y = params.p_x, params.p_y + p_z = p3 + + #if(af.any_true(params.tau_defect(q1, q2, p_x, p_y, p_z) == 0)): + # if (flag == False): + # return(0.*f) + # + # f = f0_defect_constant_T(f, p_x, p_y, p_z, params) + # + # return(f) + + if (params.disable_collision_op): + # Activate the following line to disable the collision operator + C_f = 0.*f + else: + # Activate the following lines to enable normal operation of collision + # operator + if (params.p_dim==1): + C_f = -( f - f0_defect_constant_T(f, p_x, p_y, p_z, params) \ + ) / params.tau_defect(q1, q2, p_x, p_y, p_z) \ + -( f - f0_ee_constant_T(f, p_x, p_y, p_z, params) + ) / params.tau_ee(q1, q2, p_x, p_y, p_z) + + elif (params.p_dim==2): + C_f = -( f - f0_defect(f, p_x, p_y, p_z, params) \ + ) / params.tau_defect(q1, q2, p_x, p_y, p_z) \ + -( f - f0_ee_constant_T(f, p_x, p_y, p_z, params) + ) / params.tau_ee(q1, q2, p_x, p_y, p_z) + + # When (f - f0) is NaN. Dividing by np.inf doesn't give 0 + # TODO: WORKAROUND + + + af.eval(C_f) + return(C_f) + diff --git a/bolt/src/electronic_boltzmann/f_local_equilibrium.py b/bolt/src/electronic_boltzmann/f_local_equilibrium.py new file mode 100644 index 00000000..c28bcc15 --- /dev/null +++ b/bolt/src/electronic_boltzmann/f_local_equilibrium.py @@ -0,0 +1,317 @@ +"""Contains the function which returns the Source/Sink term.""" + +from petsc4py import PETSc +import numpy as np +import arrayfire as af + +from .matrix_inverse import inverse_4x4_matrix +from .matrix_inverse import inverse_3x3_matrix +from bolt.src.utils.integral_over_p import integral_over_p + +import domain + + +# Using af.broadcast, since p_x, p_y, p_z are of size (1, 1, Np_x*Np_y*Np_z) +# All moment quantities are of shape (Nq1, Nq2) +# By wrapping with af.broadcast, we can perform batched operations +# on arrays of different sizes. +@af.broadcast +def f0_defect(f, p_x, p_y, p_z, params): + """ + Return the local equilibrium distribution corresponding to the tau_D + relaxation time. + Parameters: + ----------- + f : Distribution function array + shape:(N_v, N_s, N_q1, N_q2) + + p_x : The array that holds data for the v1 dimension in v-space + shape:(N_v, N_s, 1, 1) + + p_y : The array that holds data for the v2 dimension in v-space + shape:(N_v, N_s, 1, 1) + + p_z : The array that holds data for the v3 dimension in v-space + shape:(N_v, N_s, 1, 1) + + params: The parameters file/object that is originally declared by the user. + This can be used to inject other functions/attributes into the function + + """ + + # Initial guess + mu = params.mu + T = params.T + + for n in range(params.collision_nonlinear_iters): + + E_upper = params.E_band + k = params.boltzmann_constant + + tmp = ((E_upper - mu)/(k*T)) + denominator = (k*T**2.*(af.exp(tmp) + 2. + af.exp(-tmp)) ) + + # TODO: Multiply with the integral measure dp_x * dp_y + a00 = integral_over_p(T / denominator, params.integral_measure) + a01 = integral_over_p((E_upper - mu) / denominator, params.integral_measure) + a10 = integral_over_p(E_upper*T / denominator, params.integral_measure) + a11 = integral_over_p(E_upper*(E_upper - mu) / denominator, params.integral_measure) + + # Solve Ax = b + # where A == Jacobian, + # x == delta guess (correction to guess), + # b = -residual + + fermi_dirac = 1./(af.exp( (E_upper - mu)/(k*T) ) + 1.) + af.eval(fermi_dirac) + + zeroth_moment = f - fermi_dirac + second_moment = E_upper*(f - fermi_dirac) + + eqn_mass_conservation = integral_over_p(zeroth_moment, params.integral_measure) + eqn_energy_conservation = integral_over_p(second_moment, params.integral_measure) + + N_g = domain.N_ghost + error_mass_conservation = af.max(af.abs(eqn_mass_conservation)[0, 0, N_g:-N_g, N_g:-N_g]) + error_energy_conservation = af.max(af.abs(eqn_energy_conservation)[0, 0, N_g:-N_g, N_g:-N_g]) + + residual = [eqn_mass_conservation, eqn_energy_conservation] + error_norm = np.max([af.max(af.abs(residual[0])), + af.max(af.abs(residual[1]))] + ) + print(" ||residual_defect|| = ", error_norm) + +# if (error_norm < 1e-9): +# params.mu = mu +# params.T = T +# return(fermi_dirac) + + b0 = eqn_mass_conservation + b1 = eqn_energy_conservation + + det = a01*a10 - a00*a11 + delta_mu = -(a11*b0 - a01*b1)/det + delta_T = (a10*b0 - a00*b1)/det + + mu = mu + delta_mu + T = T + delta_T + + af.eval(mu, T) + + # Solved for (mu, T). Now store in params + params.mu = mu + params.T = T + + # Print final residual + fermi_dirac = 1./(af.exp( (E_upper - mu)/(k*T) ) + 1.) + af.eval(fermi_dirac) + + zeroth_moment = f - fermi_dirac + second_moment = E_upper*(f - fermi_dirac) + + eqn_mass_conservation = integral_over_p(zeroth_moment, params.integral_measure) + eqn_energy_conservation = integral_over_p(second_moment, params.integral_measure) + + residual = [eqn_mass_conservation, eqn_energy_conservation] + error_norm = np.max([af.max(af.abs(residual[0])), + af.max(af.abs(residual[1]))] + ) + print(" ||residual_defect|| = ", error_norm) + print(" mu = ", af.mean(params.mu[0, 0, N_g:-N_g, N_g:-N_g]), + "T = ", af.mean(params.T[0, 0, N_g:-N_g, N_g:-N_g]) + ) + print(" ------------------") + + return(fermi_dirac) + +@af.broadcast +def f0_ee(f, p_x, p_y, p_z, params): + """ + Return the local equilibrium distribution corresponding to the tau_ee + relaxation time. + Parameters: + ----------- + f : Distribution function array + shape:(N_v, N_s, N_q1, N_q2) + + p_x : The array that holds data for the v1 dimension in v-space + shape:(N_v, N_s, 1, 1) + + p_y : The array that holds data for the v2 dimension in v-space + shape:(N_v, N_s, 1, 1) + + p_z : The array that holds data for the v3 dimension in v-space + shape:(N_v, N_s, 1, 1) + + params: The parameters file/object that is originally declared by the user. + This can be used to inject other functions/attributes into the function + + """ + + # Initial guess + mu_ee = params.mu_ee + T_ee = params.T_ee + vel_drift_x = params.vel_drift_x + vel_drift_y = params.vel_drift_y + + for n in range(params.collision_nonlinear_iters): + + E_upper = params.E_band + k = params.boltzmann_constant + + tmp1 = (E_upper - mu_ee - p_x*vel_drift_x - p_y*vel_drift_y) + tmp = (tmp1/(k*T_ee)) + denominator = (k*T_ee**2.*(af.exp(tmp) + 2. + af.exp(-tmp)) ) + + a_0 = T_ee / denominator + a_1 = tmp1 / denominator + a_2 = T_ee * p_x / denominator + a_3 = T_ee * p_y / denominator + + af.eval(a_0, a_1, a_2, a_3) + + # TODO: Multiply with the integral measure dp_x * dp_y + a_00 = integral_over_p(a_0, params.integral_measure) + a_01 = integral_over_p(a_1, params.integral_measure) + a_02 = integral_over_p(a_2, params.integral_measure) + a_03 = integral_over_p(a_3, params.integral_measure) + + a_10 = integral_over_p(E_upper * a_0, params.integral_measure) + a_11 = integral_over_p(E_upper * a_1, params.integral_measure) + a_12 = integral_over_p(E_upper * a_2, params.integral_measure) + a_13 = integral_over_p(E_upper * a_3, params.integral_measure) + + a_20 = integral_over_p(p_x * a_0, params.integral_measure) + a_21 = integral_over_p(p_x * a_1, params.integral_measure) + a_22 = integral_over_p(p_x * a_2, params.integral_measure) + a_23 = integral_over_p(p_x * a_3, params.integral_measure) + + a_30 = integral_over_p(p_y * a_0, params.integral_measure) + a_31 = integral_over_p(p_y * a_1, params.integral_measure) + a_32 = integral_over_p(p_y * a_2, params.integral_measure) + a_33 = integral_over_p(p_y * a_3, params.integral_measure) + + A = [ [a_00, a_01, a_02, a_03], \ + [a_10, a_11, a_12, a_13], \ + [a_20, a_21, a_22, a_23], \ + [a_30, a_31, a_32, a_33] \ + ] + + fermi_dirac = 1./(af.exp( ( E_upper - mu_ee + - vel_drift_x*p_x - vel_drift_y*p_y + )/(k*T_ee) + ) + 1. + ) + af.eval(fermi_dirac) + + zeroth_moment = (f - fermi_dirac) + second_moment = E_upper*(f - fermi_dirac) + first_moment_x = p_x*(f - fermi_dirac) + first_moment_y = p_y*(f - fermi_dirac) + + eqn_mass_conservation = integral_over_p(zeroth_moment, params.integral_measure) + eqn_energy_conservation = integral_over_p(second_moment, params.integral_measure) + eqn_mom_x_conservation = integral_over_p(first_moment_x, params.integral_measure) + eqn_mom_y_conservation = integral_over_p(first_moment_y, params.integral_measure) + + residual = [eqn_mass_conservation, \ + eqn_energy_conservation, \ + eqn_mom_x_conservation, \ + eqn_mom_y_conservation] + + error_norm = np.max([af.max(af.abs(residual[0])), + af.max(af.abs(residual[1])), + af.max(af.abs(residual[2])), + af.max(af.abs(residual[3])) + ] + ) + print(" rank = ", params.rank, + "||residual_ee|| = ", error_norm + ) + +# if (error_norm < 1e-13): +# params.mu_ee = mu_ee +# params.T_ee = T_ee +# params.vel_drift_x = vel_drift_x +# params.vel_drift_y = vel_drift_y +# return(fermi_dirac) + + b_0 = eqn_mass_conservation + b_1 = eqn_energy_conservation + b_2 = eqn_mom_x_conservation + b_3 = eqn_mom_y_conservation + b = [b_0, b_1, b_2, b_3] + + # Solve Ax = b + # where A == Jacobian, + # x == delta guess (correction to guess), + # b = -residual + + A_inv = inverse_4x4_matrix(A) + + x_0 = A_inv[0][0]*b[0] + A_inv[0][1]*b[1] + A_inv[0][2]*b[2] + A_inv[0][3]*b[3] + x_1 = A_inv[1][0]*b[0] + A_inv[1][1]*b[1] + A_inv[1][2]*b[2] + A_inv[1][3]*b[3] + x_2 = A_inv[2][0]*b[0] + A_inv[2][1]*b[1] + A_inv[2][2]*b[2] + A_inv[2][3]*b[3] + x_3 = A_inv[3][0]*b[0] + A_inv[3][1]*b[1] + A_inv[3][2]*b[2] + A_inv[3][3]*b[3] + + delta_mu = x_0 + delta_T = x_1 + delta_vx = x_2 + delta_vy = x_3 + + mu_ee = mu_ee + delta_mu + T_ee = T_ee + delta_T + vel_drift_x = vel_drift_x + delta_vx + vel_drift_y = vel_drift_y + delta_vy + + af.eval(mu_ee, T_ee, vel_drift_x, vel_drift_y) + + # Solved for (mu_ee, T_ee, vel_drift_x, vel_drift_y). Now store in params + params.mu_ee = mu_ee + params.T_ee = T_ee + params.vel_drift_x = vel_drift_x + params.vel_drift_y = vel_drift_y + + fermi_dirac = 1./(af.exp( ( E_upper - mu_ee + - vel_drift_x*p_x - vel_drift_y*p_y + )/(k*T_ee) + ) + 1. + ) + af.eval(fermi_dirac) + + zeroth_moment = f - fermi_dirac + second_moment = E_upper*(f - fermi_dirac) + first_moment_x = p_x*(f - fermi_dirac) + first_moment_y = p_y*(f - fermi_dirac) + + eqn_mass_conservation = integral_over_p(zeroth_moment, params.integral_measure) + eqn_energy_conservation = integral_over_p(second_moment, params.integral_measure) + eqn_mom_x_conservation = integral_over_p(first_moment_x, params.integral_measure) + eqn_mom_y_conservation = integral_over_p(first_moment_y, params.integral_measure) + + residual = [eqn_mass_conservation, \ + eqn_energy_conservation, \ + eqn_mom_x_conservation, \ + eqn_mom_y_conservation + ] + + error_norm = np.max([af.max(af.abs(residual[0])), + af.max(af.abs(residual[1])), + af.max(af.abs(residual[2])), + af.max(af.abs(residual[3])) + ] + ) + print(" rank = ", params.rank, + "||residual_ee|| = ", error_norm + ) + N_g = domain.N_ghost + print(" rank = ", params.rank, + "mu_ee = ", af.mean(params.mu_ee[0, 0, N_g:-N_g, N_g:-N_g]), + "T_ee = ", af.mean(params.T_ee[0, 0, N_g:-N_g, N_g:-N_g]), + " = ", af.mean(params.vel_drift_x[0, 0, N_g:-N_g, N_g:-N_g]), + " = ", af.mean(params.vel_drift_y[0, 0, N_g:-N_g, N_g:-N_g]) + ) + PETSc.Sys.Print(" ------------------") + + return(fermi_dirac) + diff --git a/bolt/src/electronic_boltzmann/f_local_equilibrium_zero_T.py b/bolt/src/electronic_boltzmann/f_local_equilibrium_zero_T.py new file mode 100644 index 00000000..32eccbf1 --- /dev/null +++ b/bolt/src/electronic_boltzmann/f_local_equilibrium_zero_T.py @@ -0,0 +1,292 @@ +"""Contains the function which returns the Source/Sink term.""" + +from petsc4py import PETSc +import numpy as np +import arrayfire as af + +from .matrix_inverse import inverse_4x4_matrix +from .matrix_inverse import inverse_3x3_matrix + +from bolt.src.utils.integral_over_p import integral_over_p + +import domain + +@af.broadcast +def f0_defect_constant_T(f, p_x, p_y, p_z, params): + """ + Return the local equilibrium distribution corresponding to the tau_D + relaxation time when lattice temperature, T, is set to constant. + Parameters: + ----------- + f : Distribution function array + shape:(N_v, N_s, N_q1, N_q2) + + p_x : The array that holds data for the v1 dimension in v-space + shape:(N_v, N_s, 1, 1) + + p_y : The array that holds data for the v2 dimension in v-space + shape:(N_v, N_s, 1, 1) + + p_z : The array that holds data for the v3 dimension in v-space + shape:(N_v, N_s, 1, 1) + + params: The parameters file/object that is originally declared by the user. + This can be used to inject other functions/attributes into the function + + """ + + mu = params.mu + T = params.T + + for n in range(params.collision_nonlinear_iters): + + E_upper = params.E_band + k = params.boltzmann_constant + + tmp = ((E_upper - mu)/(k*T)) + denominator = (k*T**2.*(af.exp(tmp) + 2. + af.exp(-tmp)) ) + + # TODO: Multiply with the integral measure dp_x * dp_y + a00 = integral_over_p(T/denominator, params.integral_measure) + + fermi_dirac = 1./(af.exp( (E_upper - mu)/(k*T) ) + 1.) + af.eval(fermi_dirac) + + zeroth_moment = f - fermi_dirac + + eqn_mass_conservation = integral_over_p(zeroth_moment, + params.integral_measure + ) + + N_g = domain.N_ghost + error_mass_conservation = af.max(af.abs(eqn_mass_conservation)[0, 0, N_g:-N_g, N_g:-N_g]) + + print(" rank = ", params.rank, + "||residual_defect|| = ", error_mass_conservation + ) + + res = eqn_mass_conservation + dres_dmu = -a00 + + delta_mu = -res/dres_dmu + + mu = mu + delta_mu + + af.eval(mu) + + # Solved for mu. Now store in params + params.mu = mu + + # Print final residual + fermi_dirac = 1./(af.exp( (E_upper - mu)/(k*T) ) + 1.) + af.eval(fermi_dirac) + + zeroth_moment = f - fermi_dirac + + eqn_mass_conservation = integral_over_p(zeroth_moment, + params.integral_measure + ) + + N_g = domain.N_ghost + error_mass_conservation = af.max(af.abs(eqn_mass_conservation)[0, 0, N_g:-N_g, N_g:-N_g]) + + print(" rank = ", params.rank, + "||residual_defect|| = ", error_mass_conservation + ) + print(" rank = ", params.rank, + "mu = ", af.mean(params.mu[0, 0, N_g:-N_g, N_g:-N_g]), + "T = ", af.mean(params.T[0, 0, N_g:-N_g, N_g:-N_g]) + ) + PETSc.Sys.Print(" ------------------") + + return(fermi_dirac) + + +@af.broadcast +def f0_ee_constant_T(f, p_x, p_y, p_z, params): + """ + Return the local equilibrium distribution corresponding to the tau_ee + relaxation time when lattice temperature, T, is set to constant. + Parameters: + ----------- + f : Distribution function array + shape:(N_v, N_s, N_q1, N_q2) + + p_x : The array that holds data for the v1 dimension in v-space + shape:(N_v, N_s, 1, 1) + + p_y : The array that holds data for the v2 dimension in v-space + shape:(N_v, N_s, 1, 1) + + p_z : The array that holds data for the v3 dimension in v-space + shape:(N_v, N_s, 1, 1) + + params: The parameters file/object that is originally declared by the user. + This can be used to inject other functions/attributes into the function + + """ + + # Initial guess + mu_ee = params.mu_ee + T_ee = params.T_ee + vel_drift_x = params.vel_drift_x + vel_drift_y = params.vel_drift_y + + for n in range(params.collision_nonlinear_iters): + + E_upper = params.E_band + k = params.boltzmann_constant + + tmp1 = (E_upper - mu_ee - p_x*vel_drift_x - p_y*vel_drift_y) + tmp = (tmp1/(k*T_ee)) + denominator = (k*T_ee**2.*(af.exp(tmp) + 2. + af.exp(-tmp)) ) + + a_0 = T_ee / denominator + a_1 = tmp1 / denominator + a_2 = T_ee * p_x / denominator + a_3 = T_ee * p_y / denominator + + af.eval(a_0, a_1, a_2, a_3) + + + # TODO: Multiply with the integral measure dp_x * dp_y + a_00 = integral_over_p(a_0, params.integral_measure) + ##a_01 = af.sum(a_1, 0) + a_02 = integral_over_p(a_2, params.integral_measure) + a_03 = integral_over_p(a_3, params.integral_measure) + + #a_10 = af.sum(E_upper * a_0, 0) + #a_11 = af.sum(E_upper * a_1, 0) + #a_12 = af.sum(E_upper * a_2, 0) + #a_13 = af.sum(E_upper * a_3, 0) + + a_20 = integral_over_p(p_x * a_0, params.integral_measure) + ##a_21 = af.sum(p_x * a_1, 0) + a_22 = integral_over_p(p_x * a_2, params.integral_measure) + a_23 = integral_over_p(p_x * a_3, params.integral_measure) + + a_30 = integral_over_p(p_y * a_0, params.integral_measure) + ##a_31 = af.sum(p_y * a_1, 0) + a_32 = integral_over_p(p_y * a_2, params.integral_measure) + a_33 = integral_over_p(p_y * a_3, params.integral_measure) + + A = [ [a_00, a_02, a_03], \ + [a_20, a_22, a_23], \ + [a_30, a_32, a_33] \ + ] + + + fermi_dirac = 1./(af.exp( ( E_upper - mu_ee + - vel_drift_x*p_x - vel_drift_y*p_y + )/(k*T_ee) + ) + 1. + ) + af.eval(fermi_dirac) + + zeroth_moment = (f - fermi_dirac) + #second_moment = E_upper*(f - fermi_dirac) + first_moment_x = p_x*(f - fermi_dirac) + first_moment_y = p_y*(f - fermi_dirac) + + eqn_mass_conservation = integral_over_p(zeroth_moment, params.integral_measure) + #eqn_energy_conservation = af.sum(second_moment, 0) + eqn_mom_x_conservation = integral_over_p(first_moment_x, params.integral_measure) + eqn_mom_y_conservation = integral_over_p(first_moment_y, params.integral_measure) + + residual = [eqn_mass_conservation, \ + eqn_mom_x_conservation, \ + eqn_mom_y_conservation] + + error_norm = np.max([af.max(af.abs(residual[0])), + af.max(af.abs(residual[1])), + af.max(af.abs(residual[2])) + ] + ) + print(" rank = ", params.rank, + "||residual_ee|| = ", error_norm + ) + +# if (error_norm < 1e-13): +# params.mu_ee = mu_ee +# params.T_ee = T_ee +# params.vel_drift_x = vel_drift_x +# params.vel_drift_y = vel_drift_y +# return(fermi_dirac) + + b_0 = eqn_mass_conservation + #b_1 = eqn_energy_conservation + b_2 = eqn_mom_x_conservation + b_3 = eqn_mom_y_conservation + b = [b_0, b_2, b_3] + + # Solve Ax = b + # where A == Jacobian, + # x == delta guess (correction to guess), + # b = -residual + + A_inv = inverse_3x3_matrix(A) + + x_0 = A_inv[0][0]*b[0] + A_inv[0][1]*b[1] + A_inv[0][2]*b[2] + #x_1 = A_inv[1][0]*b[0] + A_inv[1][1]*b[1] + A_inv[1][2]*b[2] + A_inv[1][3]*b[3] + x_2 = A_inv[1][0]*b[0] + A_inv[1][1]*b[1] + A_inv[1][2]*b[2] + x_3 = A_inv[2][0]*b[0] + A_inv[2][1]*b[1] + A_inv[2][2]*b[2] + + delta_mu = x_0 + #delta_T = x_1 + delta_vx = x_2 + delta_vy = x_3 + + mu_ee = mu_ee + delta_mu + #T_ee = T_ee + delta_T + vel_drift_x = vel_drift_x + delta_vx + vel_drift_y = vel_drift_y + delta_vy + + af.eval(mu_ee, vel_drift_x, vel_drift_y) + + # Solved for (mu_ee, T_ee, vel_drift_x, vel_drift_y). Now store in params + params.mu_ee = mu_ee + #params.T_ee = T_ee + params.vel_drift_x = vel_drift_x + params.vel_drift_y = vel_drift_y + + fermi_dirac = 1./(af.exp( ( E_upper - mu_ee + - vel_drift_x*p_x - vel_drift_y*p_y + )/(k*T_ee) + ) + 1. + ) + af.eval(fermi_dirac) + + zeroth_moment = f - fermi_dirac + #second_moment = E_upper*(f - fermi_dirac) + first_moment_x = p_x*(f - fermi_dirac) + first_moment_y = p_y*(f - fermi_dirac) + + eqn_mass_conservation = integral_over_p(zeroth_moment, params.integral_measure) + #eqn_energy_conservation = af.sum(second_moment, 0) + eqn_mom_x_conservation = integral_over_p(first_moment_x, params.integral_measure) + eqn_mom_y_conservation = integral_over_p(first_moment_y, params.integral_measure) + + residual = [eqn_mass_conservation, \ + eqn_mom_x_conservation, \ + eqn_mom_y_conservation + ] + + error_norm = np.max([af.max(af.abs(residual[0])), + af.max(af.abs(residual[1])), + af.max(af.abs(residual[2])) + ] + ) + print(" rank = ", params.rank, + "||residual_ee|| = ", error_norm + ) + N_g = domain.N_ghost + print(" rank = ", params.rank, + "mu_ee = ", af.mean(params.mu_ee[0, 0, N_g:-N_g, N_g:-N_g]), + "T_ee = ", af.mean(params.T_ee[0, 0, N_g:-N_g, N_g:-N_g]), + " = ", af.mean(params.vel_drift_x[0, 0, N_g:-N_g, N_g:-N_g]), + " = ", af.mean(params.vel_drift_y[0, 0, N_g:-N_g, N_g:-N_g]) + ) + PETSc.Sys.Print(" ------------------") + + return(fermi_dirac) + diff --git a/bolt/src/electronic_boltzmann/matrix_inverse.py b/bolt/src/electronic_boltzmann/matrix_inverse.py new file mode 100644 index 00000000..ea1282a3 --- /dev/null +++ b/bolt/src/electronic_boltzmann/matrix_inverse.py @@ -0,0 +1,286 @@ +import numpy as np +import arrayfire as af + +def inverse_4x4_matrix(A): + """ + Return the inverse of a 4x4 matrix. + Parameters: + ----------- + A : Array to be inverted + shape:(4, 4) + """ + +# TO TEST: +# A_test = np.random.rand(4, 4) +# A_inv_test = np.linalg.inv(A_test) +# A_inv = np.array(inverse_4x4_matrix(A_test)) +# print("err = ", np.max(np.abs(A_inv - A_inv_test))) + + + det = \ + A[0][0]*A[1][1]*A[2][2]*A[3][3] \ + + A[0][0]*A[1][2]*A[2][3]*A[3][1] \ + + A[0][0]*A[1][3]*A[2][1]*A[3][2] \ + + A[0][1]*A[1][0]*A[2][3]*A[3][2] \ + + A[0][1]*A[1][2]*A[2][0]*A[3][3] \ + + A[0][1]*A[1][3]*A[2][2]*A[3][0] \ + + A[0][2]*A[1][0]*A[2][1]*A[3][3] \ + + A[0][2]*A[1][1]*A[2][3]*A[3][0] \ + + A[0][2]*A[1][3]*A[2][0]*A[3][1] \ + + A[0][3]*A[1][0]*A[2][2]*A[3][1] \ + + A[0][3]*A[1][1]*A[2][0]*A[3][2] \ + + A[0][3]*A[1][2]*A[2][1]*A[3][0] \ + - A[0][0]*A[1][1]*A[2][3]*A[3][2] \ + - A[0][0]*A[1][2]*A[2][1]*A[3][3] \ + - A[0][0]*A[1][3]*A[2][2]*A[3][1] \ + - A[0][1]*A[1][0]*A[2][2]*A[3][3] \ + - A[0][1]*A[1][2]*A[2][3]*A[3][0] \ + - A[0][1]*A[1][3]*A[2][0]*A[3][2] \ + - A[0][2]*A[1][0]*A[2][3]*A[3][1] \ + - A[0][2]*A[1][1]*A[2][0]*A[3][3] \ + - A[0][2]*A[1][3]*A[2][1]*A[3][0] \ + - A[0][3]*A[1][0]*A[2][1]*A[3][2] \ + - A[0][3]*A[1][1]*A[2][2]*A[3][0] \ + - A[0][3]*A[1][2]*A[2][0]*A[3][1] + + af.eval(det) + + #TODO : Raise an exception if the matrix is singular + + A_inv = [[0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0] + ] + + A_inv[0][0] = \ + ( A[1][1]*A[2][2]*A[3][3] + + A[1][2]*A[2][3]*A[3][1] + + A[1][3]*A[2][1]*A[3][2] + - A[1][1]*A[2][3]*A[3][2] + - A[1][2]*A[2][1]*A[3][3] + - A[1][3]*A[2][2]*A[3][1])/det + + A_inv[0][1] = \ + ( A[0][1]*A[2][3]*A[3][2] + + A[0][2]*A[2][1]*A[3][3] + + A[0][3]*A[2][2]*A[3][1] + - A[0][1]*A[2][2]*A[3][3] + - A[0][2]*A[2][3]*A[3][1] + - A[0][3]*A[2][1]*A[3][2])/det + + A_inv[0][2] = \ + ( A[0][1]*A[1][2]*A[3][3] + + A[0][2]*A[1][3]*A[3][1] + + A[0][3]*A[1][1]*A[3][2] + - A[0][1]*A[1][3]*A[3][2] + - A[0][2]*A[1][1]*A[3][3] + - A[0][3]*A[1][2]*A[3][1])/det + + A_inv[0][3] = \ + ( A[0][1]*A[1][3]*A[2][2] + + A[0][2]*A[1][1]*A[2][3] + + A[0][3]*A[1][2]*A[2][1] + - A[0][1]*A[1][2]*A[2][3] + - A[0][2]*A[1][3]*A[2][1] + - A[0][3]*A[1][1]*A[2][2])/det + + # b21 + A_inv[1][0] = \ + ( A[1][0]*A[2][3]*A[3][2] + + A[1][2]*A[2][0]*A[3][3] + + A[1][3]*A[2][2]*A[3][0] + - A[1][0]*A[2][2]*A[3][3] + - A[1][2]*A[2][3]*A[3][0] + - A[1][3]*A[2][0]*A[3][2])/det + + A_inv[1][1] = \ + ( A[0][0]*A[2][2]*A[3][3] + + A[0][2]*A[2][3]*A[3][0] + + A[0][3]*A[2][0]*A[3][2] + - A[0][0]*A[2][3]*A[3][2] + - A[0][2]*A[2][0]*A[3][3] + - A[0][3]*A[2][2]*A[3][0])/det + + A_inv[1][2] = \ + ( A[0][0]*A[1][3]*A[3][2] + + A[0][2]*A[1][0]*A[3][3] + + A[0][3]*A[1][2]*A[3][0] + - A[0][0]*A[1][2]*A[3][3] + - A[0][2]*A[1][3]*A[3][0] + - A[0][3]*A[1][0]*A[3][2])/det + + A_inv[1][3] = \ + ( A[0][0]*A[1][2]*A[2][3] + + A[0][2]*A[1][3]*A[2][0] + + A[0][3]*A[1][0]*A[2][2] + - A[0][0]*A[1][3]*A[2][2] + - A[0][2]*A[1][0]*A[2][3] + - A[0][3]*A[1][2]*A[2][0])/det + + # b31 + A_inv[2][0] = \ + ( A[1][0]*A[2][1]*A[3][3] + + A[1][1]*A[2][3]*A[3][0] + + A[1][3]*A[2][0]*A[3][1] + - A[1][0]*A[2][3]*A[3][1] + - A[1][1]*A[2][0]*A[3][3] + - A[1][3]*A[2][1]*A[3][0])/det + + # b32 + A_inv[2][1] = \ + ( A[0][0]*A[2][3]*A[3][1] + + A[0][1]*A[2][0]*A[3][3] + + A[0][3]*A[2][1]*A[3][0] + - A[0][0]*A[2][1]*A[3][3] + - A[0][1]*A[2][3]*A[3][0] + - A[0][3]*A[2][0]*A[3][1])/det + + A_inv[2][2] = \ + ( A[0][0]*A[1][1]*A[3][3] + + A[0][1]*A[1][3]*A[3][0] + + A[0][3]*A[1][0]*A[3][1] + - A[0][0]*A[1][3]*A[3][1] + - A[0][1]*A[1][0]*A[3][3] + - A[0][3]*A[1][1]*A[3][0])/det + + A_inv[2][3] = \ + ( A[0][0]*A[1][3]*A[2][1] + + A[0][1]*A[1][0]*A[2][3] + + A[0][3]*A[1][1]*A[2][0] + - A[0][0]*A[1][1]*A[2][3] + - A[0][1]*A[1][3]*A[2][0] + - A[0][3]*A[1][0]*A[2][1])/det + + # b41 + A_inv[3][0] = \ + ( A[1][0]*A[2][2]*A[3][1] + + A[1][1]*A[2][0]*A[3][2] + + A[1][2]*A[2][1]*A[3][0] + - A[1][0]*A[2][1]*A[3][2] + - A[1][1]*A[2][2]*A[3][0] + - A[1][2]*A[2][0]*A[3][1])/det + + # b42 + A_inv[3][1] = \ + ( A[0][0]*A[2][1]*A[3][2] + + A[0][1]*A[2][2]*A[3][0] + + A[0][2]*A[2][0]*A[3][1] + - A[0][0]*A[2][2]*A[3][1] + - A[0][1]*A[2][0]*A[3][2] + - A[0][2]*A[2][1]*A[3][0])/det + + # b43 + A_inv[3][2] = \ + ( A[0][0]*A[1][2]*A[3][1] + + A[0][1]*A[1][0]*A[3][2] + + A[0][2]*A[1][1]*A[3][0] + - A[0][0]*A[1][1]*A[3][2] + - A[0][1]*A[1][2]*A[3][0] + - A[0][2]*A[1][0]*A[3][1])/det + + A_inv[3][3] = \ + ( A[0][0]*A[1][1]*A[2][2] + + A[0][1]*A[1][2]*A[2][0] + + A[0][2]*A[1][0]*A[2][1] + - A[0][0]*A[1][2]*A[2][1] + - A[0][1]*A[1][0]*A[2][2] + - A[0][2]*A[1][1]*A[2][0])/det + + arrays_to_be_evaled = \ + [A_inv[0][0], A_inv[0][1], A_inv[0][2], A_inv[0][3], \ + A_inv[1][0], A_inv[1][1], A_inv[1][2], A_inv[1][3], \ + A_inv[2][0], A_inv[2][1], A_inv[2][2], A_inv[2][3], \ + A_inv[3][0], A_inv[3][1], A_inv[3][2], A_inv[3][3] \ + ] + + af.eval(*arrays_to_be_evaled) + + return(A_inv) + + +def inverse_3x3_matrix(A): + """ + Return the inverse of a 3x3 matrix. + Parameters: + ----------- + A : Array to be inverted + shape:(3, 3) + """ + +# TO TEST: +# A_test = np.random.rand(3, 3) +# A_inv_test = np.linalg.inv(A_test) +# A_inv = np.array(inverse_3x3_matrix(A_test)) +# print("err = ", np.max(np.abs(A_inv - A_inv_test))) + + + det = \ + A[0][0]*A[1][1]*A[2][2] \ + - A[0][0]*A[1][2]*A[2][1] \ + - A[0][1]*A[1][0]*A[2][2] \ + + A[0][1]*A[1][2]*A[2][0] \ + + A[0][2]*A[1][0]*A[2][1] \ + - A[0][2]*A[1][1]*A[2][0] \ + + af.eval(det) + + #TODO : Raise an exception if the matrix is singular + + A_inv = [[0, 0, 0], \ + [0, 0, 0], \ + [0, 0, 0] \ + ] + + cofactors = [[0, 0, 0], \ + [0, 0, 0], \ + [0, 0, 0] \ + ] + + adjoint = [[0, 0, 0], \ + [0, 0, 0], \ + [0, 0, 0] \ + ] + + cofactors[0][0] = +(A[1][1]*A[2][2] - A[1][2]*A[2][1]) + cofactors[0][1] = -(A[1][0]*A[2][2] - A[1][2]*A[2][0]) + cofactors[0][2] = +(A[1][0]*A[2][1] - A[1][1]*A[2][0]) + cofactors[1][0] = -(A[0][1]*A[2][2] - A[0][2]*A[2][1]) + cofactors[1][1] = +(A[0][0]*A[2][2] - A[0][2]*A[2][0]) + cofactors[1][2] = -(A[0][0]*A[2][1] - A[0][1]*A[2][0]) + cofactors[2][0] = +(A[0][1]*A[1][2] - A[0][2]*A[1][1]) + cofactors[2][1] = -(A[0][0]*A[1][2] - A[0][2]*A[1][0]) + cofactors[2][2] = +(A[0][0]*A[1][1] - A[0][1]*A[1][0]) + + adjoint[0][0] = cofactors[0][0] + adjoint[0][1] = cofactors[1][0] + adjoint[0][2] = cofactors[2][0] + adjoint[1][0] = cofactors[0][1] + adjoint[1][1] = cofactors[1][1] + adjoint[1][2] = cofactors[2][1] + adjoint[2][0] = cofactors[0][2] + adjoint[2][1] = cofactors[1][2] + adjoint[2][2] = cofactors[2][2] + + + A_inv[0][0] = adjoint[0][0]/det + A_inv[0][1] = adjoint[0][1]/det + A_inv[0][2] = adjoint[0][2]/det + A_inv[1][0] = adjoint[1][0]/det + A_inv[1][1] = adjoint[1][1]/det + A_inv[1][2] = adjoint[1][2]/det + A_inv[2][0] = adjoint[2][0]/det + A_inv[2][1] = adjoint[2][1]/det + A_inv[2][2] = adjoint[2][2]/det + + + arrays_to_be_evaled = \ + [A_inv[0][0], A_inv[0][1], A_inv[0][2], \ + A_inv[1][0], A_inv[1][1], A_inv[1][2], \ + A_inv[2][0], A_inv[2][1], A_inv[2][2] \ + ] + + af.eval(*arrays_to_be_evaled) + + return(A_inv) + diff --git a/bolt/src/electronic_boltzmann/matrix_inverse_test.py b/bolt/src/electronic_boltzmann/matrix_inverse_test.py new file mode 100644 index 00000000..a628031b --- /dev/null +++ b/bolt/src/electronic_boltzmann/matrix_inverse_test.py @@ -0,0 +1,96 @@ +import numpy as np +import arrayfire as af + +def inverse_3x3_matrix(A): +# TO TEST: +# A_test = np.random.rand(3, 3) +# A_inv_test = np.linalg.inv(A_test) +# A_inv = np.array(inverse_3x3_matrix(A_test)) +# print("err = ", np.max(np.abs(A_inv - A_inv_test))) + + + det = \ + A[0][0]*A[1][1]*A[2][2] \ + - A[0][0]*A[1][2]*A[2][1] \ + - A[0][1]*A[1][0]*A[2][2] \ + + A[0][1]*A[1][2]*A[2][0] \ + + A[0][2]*A[1][0]*A[2][1] \ + - A[0][2]*A[1][1]*A[2][0] \ + + #af.eval(det) + + #TODO : Raise an exception if the matrix is singular + #print ('determinant : ') + #print (det) + + A_inv = [[0, 0, 0], \ + [0, 0, 0], \ + [0, 0, 0] \ + ] + + cofactors = [[0, 0, 0], \ + [0, 0, 0], \ + [0, 0, 0] \ + ] + + adjoint = [[0, 0, 0], \ + [0, 0, 0], \ + [0, 0, 0] \ + ] + + cofactors[0][0] = +(A[1][1]*A[2][2] - A[1][2]*A[2][1]) + cofactors[0][1] = -(A[1][0]*A[2][2] - A[1][2]*A[2][0]) + cofactors[0][2] = +(A[1][0]*A[2][1] - A[1][1]*A[2][0]) + cofactors[1][0] = -(A[0][1]*A[2][2] - A[0][2]*A[2][1]) + cofactors[1][1] = +(A[0][0]*A[2][2] - A[0][2]*A[2][0]) + cofactors[1][2] = -(A[0][0]*A[2][1] - A[0][1]*A[2][0]) + cofactors[2][0] = +(A[0][1]*A[1][2] - A[0][2]*A[1][1]) + cofactors[2][1] = -(A[0][0]*A[1][2] - A[0][2]*A[1][0]) + cofactors[2][2] = +(A[0][0]*A[1][1] - A[0][1]*A[1][0]) + + adjoint[0][0] = cofactors[0][0] + adjoint[0][1] = cofactors[1][0] + adjoint[0][2] = cofactors[2][0] + adjoint[1][0] = cofactors[0][1] + adjoint[1][1] = cofactors[1][1] + adjoint[1][2] = cofactors[2][1] + adjoint[2][0] = cofactors[0][2] + adjoint[2][1] = cofactors[1][2] + adjoint[2][2] = cofactors[2][2] + + + A_inv = adjoint/det + + #A_inv[0][1] = adjoint[0][1]/det + + #A_inv[0][2] = adjoint[0][2]/det + + #A_inv[1][0] = adjoint[1][0]/det + # + #A_inv[1][1] = adjoint[1][1]/det + + #A_inv[1][2] = adjoint[1][2]/det + + #A_inv[2][0] = adjoint[2][0]/det + + #A_inv[2][1] = adjoint[2][1]/det + + #A_inv[2][2] = adjoint[2][2]/det + + + arrays_to_be_evaled = \ + [A_inv[0][0], A_inv[0][1], A_inv[0][2], \ + A_inv[1][0], A_inv[1][1], A_inv[1][2], \ + A_inv[2][0], A_inv[2][1], A_inv[2][2] \ + ] + + #af.eval(*arrays_to_be_evaled) + + return(A_inv) +def main(): + A_test = np.random.rand(3, 3) + A_inv_test = np.linalg.inv(A_test) + A_inv = np.array(inverse_3x3_matrix(A_test)) + print("err = ", A_inv - A_inv_test) + +main() diff --git a/bolt/src/electronic_boltzmann/moments.py b/bolt/src/electronic_boltzmann/moments.py new file mode 100644 index 00000000..42cf0a32 --- /dev/null +++ b/bolt/src/electronic_boltzmann/moments.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import arrayfire as af + +from bolt.src.utils.integral_over_p import integral_over_p + +import params + +def density(f, p1, p2, p3, integral_measure): + theta = af.atan(params.p_y / params.p_x) + p_f = params.fermi_momentum_magnitude(theta) + return(integral_over_p(f+p_f/2, integral_measure)) + +def j_x(f, p1, p2, p3, integral_measure): + theta = af.atan(params.p_y / params.p_x) + p_f = params.fermi_momentum_magnitude(theta) + return(integral_over_p(f * params.fermi_velocity * params.p_x/p_f, integral_measure)) + +def j_y(f, p1, p2, p3, integral_measure): + theta = af.atan(params.p_y / params.p_x) + p_f = params.fermi_momentum_magnitude(theta) + return(integral_over_p(f * params.fermi_velocity * params.p_y/p_f, integral_measure)) diff --git a/bolt/src/electronic_boltzmann/utils/polygon.py b/bolt/src/electronic_boltzmann/utils/polygon.py new file mode 100644 index 00000000..51db41e6 --- /dev/null +++ b/bolt/src/electronic_boltzmann/utils/polygon.py @@ -0,0 +1,22 @@ +import arrayfire as af +import numpy as np + +def polygon(n, theta, rotation = 0, shift = 0): + ''' + Returns a polygon of unit edge length on a polar coordinate system. + Inputs : + + n : number of sides of the polygon + thera : the angle grid + rotation : initial rotation + shift : initial shift in center ##TODO + ''' + + numerator = np.cos(np.pi/n) + denominator = af.cos((theta - rotation) - (2*np.pi/n)*af.floor((n*(theta - rotation) + np.pi)/(2*np.pi))) + + result = numerator/denominator + + return (result) + + diff --git a/bolt/src/electronic_boltzmann/utils/unit_vectors.py b/bolt/src/electronic_boltzmann/utils/unit_vectors.py new file mode 100644 index 00000000..d0803deb --- /dev/null +++ b/bolt/src/electronic_boltzmann/utils/unit_vectors.py @@ -0,0 +1,220 @@ +import arrayfire as af +import numpy as np + + +def normal_to_circle_unit_vec(theta): + + vel_x = 0.*theta + vel_y = 0.*theta + + # (1) + start_theta = 0.0 + end_theta = np.pi/3 + mid_theta = 0.5*(end_theta + start_theta) + indices = ((theta >= start_theta) & (theta < end_theta)) + vel_x = (1-indices)*vel_x + indices*af.cos(theta) + vel_y = (1-indices)*vel_y + indices*af.sin(theta) + #(1-indices) is equivalent to complementing indices + + + # (2) + start_theta = np.pi/3 + end_theta = 2*np.pi/3 + mid_theta = 0.5*(end_theta + start_theta) + indices = ((theta >= start_theta) & (theta < end_theta)) + vel_x = (1-indices)*vel_x + indices*af.cos(theta) + vel_y = (1-indices)*vel_y + indices*af.sin(theta) + + # (3) + start_theta = 2*np.pi/3 + end_theta = np.pi + mid_theta = 0.5*(end_theta + start_theta) + indices = ((theta >= start_theta) & (theta < end_theta)) + vel_x = (1-indices)*vel_x + indices*af.cos(theta) + vel_y = (1-indices)*vel_y + indices*af.sin(theta) + + # (4) + start_theta = -np.pi + end_theta = -2*np.pi/3 + mid_theta = 0.5*(end_theta + start_theta) + indices = ((theta >= start_theta) & (theta < end_theta)) + vel_x = (1-indices)*vel_x + indices*af.cos(theta) + vel_y = (1-indices)*vel_y + indices*af.sin(theta) + + # (5) + start_theta = -2*np.pi/3 + end_theta = -np.pi/3 + mid_theta = 0.5*(end_theta + start_theta) + indices = ((theta >= start_theta) & (theta < end_theta)) + vel_x = (1-indices)*vel_x + indices*af.cos(theta) + vel_y = (1-indices)*vel_y + indices*af.sin(theta) + + # (6) + start_theta = -np.pi/3 + end_theta = 0 + mid_theta = 0.5*(end_theta + start_theta) + indices = ((theta >= start_theta) & (theta < end_theta)) + vel_x = (1-indices)*vel_x + indices*af.cos(theta) + vel_y = (1-indices)*vel_y + indices*af.sin(theta) + + return ([vel_x, vel_y]) + + +def normal_to_hexagon_unit_vec(theta): + + vel_x = 0.*theta + vel_y = 0.*theta + +# +# 2*pi/3 pi/3 +# #%%%%%%%%%%%%%%%%%%%* +# . . , * +# ( & (2) # . +# . . . ( +# / & # +# , (3) , . (1) ( +# pi / & & +# /------------------/------------------( 0 +# -pi . # # . +# / (4) / (6) # +# * % # +# * , # # +# * ( (5) / +# ,, %( +# ##################### +# -2*pi/3 -pi/3 +# + + # (1) + start_theta = 0.0 + end_theta = np.pi/3 + mid_theta = 0.5*(end_theta + start_theta) + indices = ((theta >= start_theta) & (theta < end_theta)) + vel_x = (1-indices)*vel_x + indices*np.cos(mid_theta) + vel_y = (1-indices)*vel_y + indices*np.sin(mid_theta) + + # (2) + start_theta = np.pi/3 + end_theta = 2*np.pi/3 + mid_theta = 0.5*(end_theta + start_theta) + indices = ((theta >= start_theta) & (theta < end_theta)) + vel_x = (1-indices)*vel_x + indices*np.cos(mid_theta) + vel_y = (1-indices)*vel_y + indices*np.sin(mid_theta) + + # (3) + start_theta = 2*np.pi/3 + end_theta = np.pi + mid_theta = 0.5*(end_theta + start_theta) + indices = ((theta >= start_theta) & (theta < end_theta)) + vel_x = (1-indices)*vel_x + indices*np.cos(mid_theta) + vel_y = (1-indices)*vel_y + indices*np.sin(mid_theta) + + # (4) + start_theta = -np.pi + end_theta = -2*np.pi/3 + mid_theta = 0.5*(end_theta + start_theta) + indices = ((theta >= start_theta) & (theta < end_theta)) + vel_x = (1-indices)*vel_x + indices*np.cos(mid_theta) + vel_y = (1-indices)*vel_y + indices*np.sin(mid_theta) + + # (5) + start_theta = -2*np.pi/3 + end_theta = -np.pi/3 + mid_theta = 0.5*(end_theta + start_theta) + indices = ((theta >= start_theta) & (theta < end_theta)) + vel_x = (1-indices)*vel_x + indices*np.cos(mid_theta) + vel_y = (1-indices)*vel_y + indices*np.sin(mid_theta) + + # (6) + start_theta = -np.pi/3 + end_theta = 0 + mid_theta = 0.5*(end_theta + start_theta) + indices = ((theta >= start_theta) & (theta < end_theta)) + vel_x = (1-indices)*vel_x + indices*np.cos(mid_theta) + vel_y = (1-indices)*vel_y + indices*np.sin(mid_theta) + + return ([vel_x, vel_y]) + + +def normal_to_hexagon_unit_vec_rotated(theta): + + vel_x = 0.*theta + vel_y = 0.*theta + +# pi/2 +# (@@ +# &@ @ @( +# @# @ %@ +# 5pi/6 .@, (3) @ (2) .@. pi/6 +# @ *@ @ @/ ,* +# @ @( @ /@ ,* +# pi @ (4) %@@@& (1) ,* +# -pi @ .@, @ .@, ,* +# @ %@ @ @& ,* +# @ @( (5) @ (6) /@ ,* +# /@ @ %@ -pi/6 +#-5pi/6 @/ @ @( +# &@ @ *@ +# . +# -pi/2 + + # (1) + start_theta = -np.pi/6 + end_theta = np.pi/6 + mid_theta = 0.5*(end_theta + start_theta) + indices = ((theta >= start_theta) & (theta < end_theta)) + vel_x = (1-indices)*vel_x + indices*np.cos(mid_theta) + vel_y = (1-indices)*vel_y + indices*np.sin(mid_theta) + + # (2) + start_theta = np.pi/6 + end_theta = np.pi/2 + mid_theta = 0.5*(end_theta + start_theta) + indices = ((theta >= start_theta) & (theta < end_theta)) + vel_x = (1-indices)*vel_x + indices*np.cos(mid_theta) + vel_y = (1-indices)*vel_y + indices*np.sin(mid_theta) + + # (3) + start_theta = np.pi/2 + end_theta = 5*np.pi/6 + mid_theta = 0.5*(end_theta + start_theta) + indices = ((theta >= start_theta) & (theta < end_theta)) + vel_x = (1-indices)*vel_x + indices*np.cos(mid_theta) + vel_y = (1-indices)*vel_y + indices*np.sin(mid_theta) + + + # Sector 4 needs to be handled as a special case, because the domain + # of theta ranges from -pi to pi. There is a break within sector 4. + # (4)a + start_theta = 5*np.pi/6 + end_theta = np.pi + mid_theta = np.pi#0.5*(end_theta + start_theta) + indices = ((theta >= start_theta) & (theta < end_theta)) + vel_x = (1-indices)*vel_x + indices*np.cos(mid_theta) + vel_y = (1-indices)*vel_y + indices*np.sin(mid_theta) + + # (4)b + start_theta = -np.pi + end_theta = -5*np.pi/6 + mid_theta = -np.pi#0.5*(end_theta + start_theta) + indices = ((theta >= start_theta) & (theta < end_theta)) + vel_x = (1-indices)*vel_x + indices*np.cos(mid_theta) + vel_y = (1-indices)*vel_y + indices*np.sin(mid_theta) + + # (5) + start_theta = -5*np.pi/6 + end_theta = -np.pi/2 + mid_theta = 0.5*(end_theta + start_theta) + indices = ((theta >= start_theta) & (theta < end_theta)) + vel_x = (1-indices)*vel_x + indices*np.cos(mid_theta) + vel_y = (1-indices)*vel_y + indices*np.sin(mid_theta) + + # (6) + start_theta = -np.pi/2 + end_theta = -np.pi/6 + mid_theta = 0.5*(end_theta + start_theta) + indices = ((theta >= start_theta) & (theta < end_theta)) + vel_x = (1-indices)*vel_x + indices*np.cos(mid_theta) + vel_y = (1-indices)*vel_y + indices*np.sin(mid_theta) + + return ([vel_x, vel_y]) diff --git a/bolt/src/utils/integral_over_p.py b/bolt/src/utils/integral_over_p.py new file mode 100644 index 00000000..324a18f8 --- /dev/null +++ b/bolt/src/utils/integral_over_p.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import arrayfire as af + +def integral_over_p(array, integral_measure): + return(af.sum(array*integral_measure, 0)) diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/README.txt b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/README.txt new file mode 100644 index 00000000..ddb0d8b5 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/README.txt @@ -0,0 +1,12 @@ +To switch between 1D/2D polar and cartesian momentum space, the following changes need +to be made : + + +1. domain + - Change p2_start, p2_end and N_p2 +2. params + - Change p_space_grid + - Change p_dim (if switching between 1D and 2D representation in p-space) +3. initialize : No change +4. main : No change +5. boundary_conditions : No change diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/boundary_conditions.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/boundary_conditions.py new file mode 100644 index 00000000..762f5e79 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/boundary_conditions.py @@ -0,0 +1,107 @@ +import numpy as np +import arrayfire as af +import domain + +in_q1_left = 'mirror+dirichlet' +in_q1_right = 'mirror+dirichlet' +in_q2_bottom = 'mirror' +in_q2_top = 'mirror' + +@af.broadcast +def f_left(f, t, q1, q2, p1, p2, p3, params): + + k = params.boltzmann_constant + E_upper = params.E_band + T = params.initial_temperature + mu = params.initial_mu + + t = params.current_time + omega = 2. * np.pi * params.AC_freq + vel_drift_x_in = params.vel_drift_x_in + + if (params.p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (params.p_space_grid == 'polar2D'): + p_x = p1 * af.cos(p2) + p_y = p1 * af.sin(p2) + else: + raise NotImplementedError('Unsupported coordinate system in p_space') + + + fermi_dirac_in = (1./(af.exp( (E_upper - vel_drift_x_in*p_x - mu)/(k*T) ) + 1.) + ) + + if (params.contact_geometry=="straight"): + # Contacts on either side of the device + + q2_contact_start = params.contact_start + q2_contact_end = params.contact_end + + cond = ((q2 >= q2_contact_start) & \ + (q2 <= q2_contact_end) \ + ) + + f_left = cond*fermi_dirac_in + (1 - cond)*f + + elif (params.contact_geometry=="turn_around"): + # Contacts on the same side of the device + + vel_drift_x_out = -params.vel_drift_x_in * np.sin(omega*t) + + fermi_dirac_out = (1./(af.exp( (E_upper - vel_drift_x_out*p_x - mu)/(k*T) ) + 1.) + ) + + # TODO: set these parameters in params.py + cond_in = ((q2 >= 3.5) & (q2 <= 4.5)) + cond_out = ((q2 >= 5.5) & (q2 <= 6.5)) + + f_left = cond_in*fermi_dirac_in + cond_out*fermi_dirac_out \ + + (1 - cond_in)*(1 - cond_out)*f + + af.eval(f_left) + return(f_left) + +@af.broadcast +def f_right(f, t, q1, q2, p1, p2, p3, params): + + k = params.boltzmann_constant + E_upper = params.E_band + T = params.initial_temperature + mu = params.initial_mu + + t = params.current_time + omega = 2. * np.pi * params.AC_freq + vel_drift_x_out = params.vel_drift_x_out + + if (params.p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (params.p_space_grid == 'polar2D'): + p_x = p1 * af.cos(p2) + p_y = p1 * af.sin(p2) + else: + raise NotImplementedError('Unsupported coordinate system in p_space') + + fermi_dirac_out = (1./(af.exp( (E_upper - vel_drift_x_out*p_x - mu)/(k*T) ) + 1.) + ) + + if (params.contact_geometry=="straight"): + # Contacts on either side of the device + + q2_contact_start = params.contact_start + q2_contact_end = params.contact_end + + cond = ((q2 >= q2_contact_start) & \ + (q2 <= q2_contact_end) \ + ) + + f_right = cond*fermi_dirac_out + (1 - cond)*f + + elif (params.contact_geometry=="turn_around"): + # Contacts on the same side of the device + + f_right = f + + af.eval(f_right) + return(f_right) diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/domain.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/domain.py new file mode 100644 index 00000000..7d095de5 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/domain.py @@ -0,0 +1,65 @@ +import numpy as np +import params + +q1_start = 0. +q1_end = 1.0 +N_q1 = 72 + +q2_start = 0. +q2_end = 5.0 +N_q2 = 360 + +# If N_p1 > 1, mirror boundary conditions require p1 to be +# symmetric about zero +# TODO : Check and fix discrepancy between this and the claim +# that p1_center = mu in polar representation +N_p1 = 1 # Set equal to 1 for 1D polar + +# In the cartesian representation of momentum space, +# p1 = p_x (magnitude of momentum) +# p1_start and p1_end are set such that p1_center is 0 + +# Uncomment the following for the cartesian representation of momentum space +#p1_start = [-0.04] +#p1_end = [0.04] + + +# In the 2D polar representation of momentum space, +# p1 = p_r (magnitude of momentum) +# p1_start and p1_end are set such that p1_center is mu + +# Uncomment the following for the 2D polar representation of momentum space +#p1_start = [params.initial_mu - \ +# 16.*params.boltzmann_constant*params.initial_temperature] +#p1_end = [params.initial_mu + \ +# 16.*params.boltzmann_constant*params.initial_temperature] + +# Uncomment the following for the 1D polar representation of momentum space +p1_start = [0.5*params.initial_mu] +p1_end = [1.5*params.initial_mu] + + +# If N_p2 > 1, mirror boundary conditions require p2 to be +# symmetric about zero +N_p2 = 8192 + +# In the cartesian representation of momentum space, +# p2 = p_y (magnitude of momentum) +# p2_start and p2_end are set such that p2_center is 0 +#p2_start = [-0.04] +#p2_end = [0.04] + +# In the 2D polar representation of momentum space, +# p2 = p_theta (angle of momentum) +# N_p_theta MUST be even. +p2_start = [-np.pi] +p2_end = [np.pi] + +# If N_p3 > 1, mirror boundary conditions require p3 to be +# symmetric about zero + +p3_start = [-0.5] +p3_end = [0.5] +N_p3 = 1 + +N_ghost = 2 diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/dump_time_array.txt b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/dump_time_array.txt new file mode 100644 index 00000000..05955907 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/dump_time_array.txt @@ -0,0 +1 @@ +0.000000000000000000e+00 diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/edge_potential.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/edge_potential.py new file mode 100644 index 00000000..b50b3bf5 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/edge_potential.py @@ -0,0 +1,161 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 12, 7.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +# Left needs to be near source, right sensor near drain +sensor_1_left_start = 5.5 # um +sensor_1_left_end = 10.0 # um + +sensor_1_right_start = 5.5 # um +sensor_1_right_end = 10.0 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +sensor_2_left_start = 6.5 # um +sensor_2_left_end = 7.5 # um + +sensor_2_right_start = 6.5 # um +sensor_2_right_end = 7.5 # um + +sensor_2_left_indices = (q2 > sensor_2_left_start ) & (q2 < sensor_2_left_end) +sensor_2_right_indices = (q2 > sensor_2_right_start) & (q2 < sensor_2_right_end) + +filepath = \ +'/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_1.0_tau_ee_0.2_tau_eph_0.5/dumps' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +sensor_1_signal_array = [] +#sensor_2_signal_array = [] +#print("Reading sensor signal...") +print("Loading data...") +density = [] +edge_density = [] +for file_number, dump_file in enumerate(moment_files): + + print("File number = ", file_number, ' of ', moment_files.size) + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + density.append(moments[:, :, 0]) + edge_density.append(density[file_number][0, sensor_1_left_indices]) + +density = np.array(density) +edge_density = np.array(edge_density) + +mean_density = np.mean(density) +max_density = np.max(density) +min_density = np.min(density) + +np.savetxt("edge_density.txt", edge_density) + +print("Dumping data...") +for file_number in yt.parallel_objects(range(density.shape[0])): + + print("File number = ", file_number, ' of ', moment_files.size) + + pl.semilogy(q2[sensor_1_left_indices], + density[file_number][0, sensor_1_left_indices], + ) + #pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.title(r'Time = ' + "%.2f"%(file_number*dt*dump_interval) + " ps") + + pl.xlim([sensor_1_left_start, sensor_1_left_end]) + #pl.ylim([min_density-mean_density, max_density-mean_density]) + #pl.ylim([0., np.log(max_density)]) + + #pl.gca().set_aspect('equal') + #pl.xlabel(r'$x\;(\mu \mathrm{m})$') + #pl.ylabel(r'$y\;(\mu \mathrm{m})$') + + #pl.suptitle('$\\tau_\mathrm{mc} = \infty$ ps, $\\tau_\mathrm{mr} = 3.0$ ps') + #pl.savefig('images/dump_' + '%06d'%file_number + '.png') + pl.savefig('images/density_' + '%06d'%file_number + '.png') + pl.clf() + + + diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/enstrophy.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/enstrophy.py new file mode 100644 index 00000000..aeab5a28 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/enstrophy.py @@ -0,0 +1,142 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +filepath = \ +'/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_1.0_tau_ee_0.2_tau_eph_0.5/dumps' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +kinetic_energy_array = [] +enstrophy_array = [] +print("Reading kinetic energy and enstrophy signals...") +for file_number, dump_file in enumerate(moment_files): + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + + h5f = h5py.File(lagrange_multiplier_files[file_number], 'r') + lagrange_multipliers = h5f['lagrange_multipliers'][:] + h5f.close() + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + + dq1 = (domain.q1_end - domain.q1_start)/domain.N_q1 + dq2 = (domain.q2_end - domain.q2_start)/domain.N_q2 + + dvx_dx, dvx_dy = np.gradient(j_x/density, dq1, dq2) + dvy_dx, dvy_dy = np.gradient(j_y/density, dq1, dq2) + + vorticity = dvy_dx - dvx_dy + + kinetic_energy = 0.5 * np.sum(vel_drift_x**2 + vel_drift_y**2) * dq1 * dq2 + kinetic_energy_array.append(kinetic_energy) + + enstrophy = np.sum(vorticity**2) * dq1 * dq2 + enstrophy_array.append(enstrophy) + +time_array = np.loadtxt("dump_time_array.txt") +half_time = (int)(time_array.size/2) + +kinetic_energy_normalized = \ + kinetic_energy_array/np.max(np.abs(kinetic_energy_array[half_time:])) +enstrophy_normalized = \ + enstrophy_array/np.max(np.abs(enstrophy_array[half_time:])) + + +pl.plot(time_array, kinetic_energy_normalized) +pl.plot(time_array, enstrophy_normalized) +pl.axhline(0, color='black', linestyle='--') + +pl.legend(['Kinetic Energy', 'Enstrophy'], loc=1) +pl.xlabel(r'Time (ps)') +pl.xlim([0, 200]) +pl.ylim([-0.1, 1.1]) + +pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 1.0$ ps') +pl.savefig('vorticity_images/iv' + '.png') +pl.clf() + + diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/initialize.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/initialize.py new file mode 100644 index 00000000..fb8e8c88 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/initialize.py @@ -0,0 +1,67 @@ +""" +Functions which are used in assigning the I.C's to +the system. +""" + +import arrayfire as af +import numpy as np +from petsc4py import PETSc + +def initialize_f(q1, q2, p1, p2, p3, params): + + PETSc.Sys.Print("Initializing f") + k = params.boltzmann_constant + + params.mu = 0.*q1 + params.initial_mu + params.T = 0.*q1 + params.initial_temperature + params.vel_drift_x = 0.*q1 + params.vel_drift_y = 0.*q1 + params.phi = 0.*q1 + + params.mu_ee = params.mu.copy() + params.T_ee = params.T.copy() + params.vel_drift_x = 0.*q1 + 0e-3 + params.vel_drift_y = 0.*q1 + 0e-3 + params.j_x = 0.*q1 + params.j_y = 0.*q1 + + params.E_band = params.band_energy(p1, p2) + params.vel_band = params.band_velocity(p1, p2) + + E_upper = params.E_band + params.charge[0]*params.phi + + if (params.p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (params.p_space_grid == 'polar2D'): + p_x = p1 * af.cos(p2) + p_y = p1 * af.sin(p2) + else: + raise NotImplementedError('Unsupported coordinate system in p_space') + + f = (1./(af.exp( (E_upper - params.vel_drift_x*p_x + - params.vel_drift_y*p_y + - params.mu + )/(k*params.T) + ) + 1. + )) + + af.eval(f) + return(f) + + +def initialize_E(q1, q2, params): + + E1 = 0.*q1 + E2 = 0.*q1 + E3 = 0.*q1 + + return(E1, E2, E3) + +def initialize_B(q1, q2, params): + + B1 = 0.*q1 + B2 = 0.*q1 + B3 = 0.*q1 + + return(B1, B2, B3) diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/job_script b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/job_script new file mode 100644 index 00000000..75c49d28 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/job_script @@ -0,0 +1,4 @@ +#!/bin/bash +#SBATCH -p gpu -n 4 --gres=gpu:4 -c1 --hint=nomultithread -t 2-00:00 +# (Note: use one MPI process per gpu, update both gres and -n together; max 6) +time mpirun python main.py -snes_monitor -snes_max_it 1 -snes_lag_jacobian_persists TRUE -snes_lag_jacobian 1000000 -snes_atol 1e-50 -snes_rtol 1e-50 > output.txt diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/main.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/main.py new file mode 100644 index 00000000..3742ff81 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/main.py @@ -0,0 +1,134 @@ +import sys +import arrayfire as af +import numpy as np +import pylab as pl +#import h5py +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear.nonlinear_solver \ + import nonlinear_solver +#from bolt.lib.nonlinear.fields.fields.fields \ +# import fields_solver.compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + + +# Defining the physical system to be solved: +system = physical_system(domain, + boundary_conditions, + params, + initialize, + advection_terms, + collision_operator.RTA, + moment_defs + ) + +# Time parameters: +dt = params.dt +t_final = params.t_final +params.current_time = t0 = 0.0 +params.time_step = time_step = 0 +dump_counter = 0 +dump_time_array = [] + +N_g = domain.N_ghost + +# Declaring a nonlinear system object which will evolve the defined physical system: +nls = nonlinear_solver(system) +params.rank = nls._comm.rank + +if (params.restart): + nls.load_distribution_function(params.restart_file) + +density = nls.compute_moments('density') +print("rank = ", params.rank, "\n", + " = ", af.mean(params.mu[0, 0, N_g:-N_g, N_g:-N_g]), "\n", + " max(mu) = ", af.max(params.mu[0, 0, N_g:-N_g, N_g:-N_g]), "\n", + " = ", af.mean(density[0, 0, N_g:-N_g, N_g:-N_g]), "\n", + " max(n) = ", af.max(density[0, 0, N_g:-N_g, N_g:-N_g]), "\n" + ) + +nls.f = af.select(nls.f < 1e-20, 1e-20, nls.f) +while t0 < t_final: + + # Refine to machine error + if (time_step==0): + params.collision_nonlinear_iters = 10 + else: + params.collision_nonlinear_iters = params.collision_operator_nonlinear_iters + + dump_steps = params.dump_steps + # Uncomment if need to dump more frequently during a desired time interval + #if (params.current_time > 149. and params.current_time < 154): + # dump_steps = 1 + #else: + # dump_steps = params.dump_steps + if (time_step%dump_steps==0): + file_number = '%06d'%dump_counter + dump_counter = dump_counter + 1 + dump_time_array.append(params.current_time) + PETSc.Sys.Print("=====================================================") + PETSc.Sys.Print("Dumping data at time step =", time_step, + ", file number =", file_number + ) + PETSc.Sys.Print("=====================================================") + if (params.rank==0): + np.savetxt("dump_time_array.txt", dump_time_array) + + nls.dump_moments('dumps/moments_' + file_number) + + if (time_step==0): + nls.dump_distribution_function('dumps/f_' + file_number) + + #nls.dump_distribution_function('dumps/f_' + file_number) + nls.dump_aux_arrays([params.mu, + params.mu_ee, + params.T_ee, + params.vel_drift_x, params.vel_drift_y, + params.j_x, params.j_y], + 'lagrange_multipliers', + 'dumps/lagrange_multipliers_' + file_number + ) + + dt_force_constraint = 0. +# dt_force_constraint = \ +# 0.5 * np.min(nls.dp1, nls.dp2) \ +# / np.max((af.max(nls.cell_centered_EM_fields[0]), +# af.max(nls.cell_centered_EM_fields[1]) +# ) +# ) + + PETSc.Sys.Print("Time step =", time_step, ", Time =", t0) + + nls.strang_timestep(dt) + t0 = t0 + dt + time_step = time_step + 1 + params.time_step = time_step + params.current_time = t0 + + # Floors + nls.f = af.select(nls.f < 1e-20, 1e-20, nls.f) + + density = nls.compute_moments('density') + print("rank = ", params.rank, "\n", + " = ", af.mean(params.mu[0, 0, N_g:-N_g, N_g:-N_g]), "\n", + " max(mu) = ", af.max(params.mu[0, 0, N_g:-N_g, N_g:-N_g]), "\n", + " = ", af.mean(density[0, 0, N_g:-N_g, N_g:-N_g]), "\n", + " max(n) = ", af.max(density[0, 0, N_g:-N_g, N_g:-N_g]), "\n" + ) + PETSc.Sys.Print("--------------------\n") + +nls.dump_distribution_function('dumps/f_laststep') diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/momentum_space_movie.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/momentum_space_movie.py new file mode 100644 index 00000000..1de644d7 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/momentum_space_movie.py @@ -0,0 +1,134 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import os +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1_start = domain.q1_start +q1_end = domain.q1_end +q2_start = domain.q2_start +q2_end = domain.q2_end + +q1 = q1_start + (0.5 + np.arange(N_q1)) * (q1_end - q1_start)/N_q1 +q2 = q2_start + (0.5 + np.arange(N_q2)) * (q2_end - q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 + +p1_start = domain.p1_start +p1_end = domain.p1_end +p2_start = domain.p2_start +p2_end = domain.p2_end + +p1 = p1_start[0] + (0.5 + np.arange(N_p1)) * (p1_end[0] - p1_start[0])/N_p1 +p2 = p2_start[0] + (0.5 + np.arange(N_p2)) * (p2_end[0] - p2_start[0])/N_p2 + +p1_meshgrid, p2_meshgrid = np.meshgrid(p1, p2) + +p_x = p1_meshgrid * np.cos(p2_meshgrid) +p_y = p1_meshgrid * np.sin(p2_meshgrid) + +#p2_meshgrid, p1_meshgrid = np.meshgrid(p2, p1) + +io = PetscBinaryIO.PetscBinaryIO() + +filepath = os.getcwd() + "/dumps" +moment_files = np.sort(glob.glob(filepath+'/moment*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) +dist_func_files = np.sort(glob.glob(filepath+'/f_*.bin')) + +dist_func_bg_file = dist_func_files[0] +dist_func_file = dist_func_files[-1] + +dist_func_background = io.readBinaryFile(dist_func_bg_file) +#dist_func_background = dist_func_background[0].reshape(N_q2, N_q1, N_p2, N_p1) +dist_func_background = dist_func_background[0].reshape(N_q1, N_q2, 1, 1, N_p2, N_p1) +dist_func = io.readBinaryFile(dist_func_file) + +print (dist_func[0].shape) + +dist_func = dist_func[0].reshape(N_q1, N_q2, 1, 1, N_p2, N_p1) + + +N = 7 +for index_1 in range(N): + for index_2 in range(N): + + q1_position = int(N_q1*((index_1/N)+(1/(2*N)))) + q2_position = int(N_q2*((index_2/N)+(1/(2*N)))) + + #a = np.max((dist_func - dist_func_background)[q2_position, q1_position, :, :]) + #b = np.abs(np.min((dist_func - dist_func_background)[q2_position, q1_position, :, :])) + #norm_factor = np.maximum(a, b) + #f_at_desired_q = \ + # np.reshape((dist_func-dist_func_background)[q2_position, q1_position, :, :], + # [N_p2, N_p1])/norm_factor + + f_at_desired_q = np.reshape((dist_func - \ + dist_func_background)[q1_position, q2_position, :], + [N_p2, N_p1] + ) + pl.contourf(p1_meshgrid, p2_meshgrid, f_at_desired_q, 100, cmap='bwr') + + #np.savetxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2), f_at_desired_q) + #f = np.loadtxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2)) + + + #pl.contourf(p_x, p_y, f_at_desired_q, 100, cmap='bwr') + #pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.xlabel('$p_x$') + pl.ylabel('$p_y$') + pl.gca().set_aspect('equal') + pl.savefig('images/dist_func_at_a_point_%d_%d.png'%(index_1, index_2)) + pl.clf() + diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/momentum_space_movie_zero_T.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/momentum_space_movie_zero_T.py new file mode 100644 index 00000000..74a2cdcb --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/momentum_space_movie_zero_T.py @@ -0,0 +1,160 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import os +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain +import params + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_s = len(params.mass) # Number of species + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1_start = domain.q1_start +q1_end = domain.q1_end +q2_start = domain.q2_start +q2_end = domain.q2_end + +q1 = q1_start + (0.5 + np.arange(N_q1)) * (q1_end - q1_start)/N_q1 +q2 = q2_start + (0.5 + np.arange(N_q2)) * (q2_end - q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 +N_p3 = domain.N_p3 + +p1_start = domain.p1_start +p1_end = domain.p1_end +p2_start = domain.p2_start +p2_end = domain.p2_end + +p1 = p1_start[0] + (0.5 + np.arange(N_p1)) * (p1_end[0] - p1_start[0])/N_p1 +p2 = p2_start[0] + (0.5 + np.arange(N_p2)) * (p2_end[0] - p2_start[0])/N_p2 + +p1_meshgrid, p2_meshgrid = np.meshgrid(p1, p2) + +p_x = p1_meshgrid * np.cos(p2_meshgrid) +p_y = p1_meshgrid * np.sin(p2_meshgrid) + +#p2_meshgrid, p1_meshgrid = np.meshgrid(p2, p1) + +io = PetscBinaryIO.PetscBinaryIO() + +filepath = os.getcwd() + "/dumps" +moment_files = np.sort(glob.glob(filepath+'/moment*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) +dist_func_files = np.sort(glob.glob(filepath+'/f_*.bin')) + +dist_func_bg_file = dist_func_files[0] +dist_func_file = dist_func_files[-1] + +dist_func_background = io.readBinaryFile(dist_func_bg_file) +#dist_func_background = dist_func_background[0].reshape(N_q2, N_q1, N_p2, N_p1) +dist_func_background = dist_func_background[0].reshape(N_q1, N_q2, N_s, N_p3, N_p2, N_p1) +dist_func = io.readBinaryFile(dist_func_file) + +print (dist_func[0].shape) + +dist_func = dist_func[0].reshape(N_q1, N_q2, N_s, N_p3, N_p2, N_p1) + + +N = 7 +for index_1 in range(N): + for index_2 in range(N): + + q1_position = int(N_q1*((index_1/N)+(1/(2*N)))) + q2_position = int(N_q2*((index_2/N)+(1/(2*N)))) + + a = np.max((dist_func - dist_func_background)[q1_position, q2_position, :, :]) + b = np.abs(np.min((dist_func - dist_func_background)[q1_position, q2_position, :, :])) + norm_factor = np.maximum(a, b) + f_at_desired_q = \ + np.reshape((dist_func-\ + dist_func_background)[q1_position, q2_position, :, :],\ + [N_p2, N_p1])/norm_factor + + np.savetxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2), f_at_desired_q) + f = np.loadtxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2)) + + #f_at_desired_q = np.reshape((dist_func - \ + # dist_func_background)[q1_position, q2_position, :], + # [N_p2, N_p1] + # ) + + print ("f at desired q : ", dist_func[q1_position, q2_position, :].shape) + print ("norm : ", norm_factor) + + + radius = f.copy() + theta = p2.copy() + + x = (radius + 5.)*np.cos(theta) + y = (radius + 5.)*np.sin(theta) + + x_bg = 5*np.cos(theta) + y_bg = 5*np.sin(theta) + + print ('p2 : ', p2.shape) + #pl.plot(p2, f_at_desired_q) + pl.plot(x, y, color='r', linestyle = '-', lw=2) + pl.plot(x_bg, y_bg, color='k', alpha=0.4, lw=2) + #pl.contourf(p1_meshgrid, p2_meshgrid, f_at_desired_q, 100, cmap='bwr') + + #np.savetxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2), f_at_desired_q) + #f = np.loadtxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2)) + + + #pl.contourf(p_x, p_y, f_at_desired_q, 100, cmap='bwr') + #pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.xlabel('$p_x$') + pl.ylabel('$p_y$') + #pl.gca().set_aspect('equal') + pl.savefig('images/dist_func_at_a_point_%d_%d.png'%(index_1, index_2)) + pl.clf() + diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/movie.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/movie.py new file mode 100644 index 00000000..dbae5848 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/movie.py @@ -0,0 +1,162 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import os +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain +import boundary_conditions +import params +import initialize + + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 + +p1 = domain.p1_start[0] + (0.5 + np.arange(N_p1)) * (domain.p1_end[0] - \ + domain.p1_start[0])/N_p1 +p2 = domain.p2_start[0] + (0.5 + np.arange(N_p2)) * (domain.p2_end[0] - \ + domain.p2_start[0])/N_p2 + +print ('Momentum space : ', p1[-1], p2[int(N_p2/2)]) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +# Left needs to be near source, right sensor near drain +sensor_1_left_start = 8.5 # um +sensor_1_left_end = 9.5 # um + +sensor_1_right_start = 8.5 # um +sensor_1_right_end = 9.5 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +sensor_2_left_start = 6.5 # um +sensor_2_left_end = 7.5 # um + +sensor_2_right_start = 6.5 # um +sensor_2_right_end = 7.5 # um + +sensor_2_left_indices = (q2 > sensor_2_left_start ) & (q2 < sensor_2_left_end) +sensor_2_right_indices = (q2 > sensor_2_right_start) & (q2 < sensor_2_right_end) + +#filepath = \ +#'/home/mchandra/gitansh/bolt_master/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/dumps' +filepath = os.getcwd() + "/dumps" +moment_files = np.sort(glob.glob(filepath+'/moment*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.bin')) + +print ("moment files : ", moment_files.size) +print ("lagrange multiplier files : ", lagrange_multiplier_files.size) + +dt = params.dt +dump_interval = params.dump_steps + +time_array = np.loadtxt("dump_time_array.txt") + +io = PetscBinaryIO.PetscBinaryIO() + +for file_number, dump_file in yt.parallel_objects(enumerate(moment_files)): + + print("file number = ", file_number, "of ", moment_files.size) + + moments = io.readBinaryFile(dump_file) + moments = moments[0].reshape(N_q2, N_q1, 3) + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + + lagrange_multipliers = \ + io.readBinaryFile(lagrange_multiplier_files[file_number]) + lagrange_multipliers = lagrange_multipliers[0].reshape(N_q2, N_q1, 7) + #h5f = h5py.File(lagrange_multiplier_files[file_number], 'r') + #lagrange_multipliers = h5f['lagrange_multipliers'][:] + #h5f.close() + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + + print (vel_drift_x.shape) + print (density.shape) + + pl.contourf(q1_meshgrid, q2_meshgrid, density.T, 100, cmap='bwr') + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.streamplot(q1, q2, + vel_drift_x, vel_drift_y, + density=2, color='k', + linewidth=0.7, arrowsize=1 + ) + + pl.xlim([q1[0], q1[-1]]) + pl.ylim([q2[0], q2[-1]]) + + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + pl.ylabel(r'$y\;(\mu \mathrm{m})$') + pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 1.0$ ps') + pl.savefig('images/dump_' + '%06d'%file_number + '.png') + pl.clf() + diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/params.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/params.py new file mode 100644 index 00000000..62b9a907 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/params.py @@ -0,0 +1,167 @@ +import numpy as np +import arrayfire as af + +instantaneous_collisions = False #TODO : Remove from lib +hybrid_model_enabled = False #TODO : Remove from lib +source_enabled = True +disable_collision_op = False + +fields_enabled = False +# Can be defined as 'electrostatic', 'user-defined'. +# The initial conditions need to be specified under initialize +# Ensure that the initial conditions specified satisfy +# Maxwell's constraint equations +fields_initialize = 'user-defined' + +# Can be defined as 'electrostatic' and 'fdtd' +# To turn feedback from Electric fields on, set fields_solver = 'LCA' +# and set charge_electron +fields_type = 'electrostatic' +fields_solver = 'SNES' + +# Can be defined as 'strang' and 'lie' +time_splitting = 'strang' + +# Method in q-space +solver_method_in_q = 'FVM' +solver_method_in_p = 'FVM' + +reconstruction_method_in_q = 'minmod' +reconstruction_method_in_p = 'minmod' + +riemann_solver_in_q = 'upwind-flux' +riemann_solver_in_p = 'upwind-flux' + +# Restart(Set to zero for no-restart): +restart = 0 +restart_file = '/home/mani/work/quazar_research/bolt/example_problems/electronic_boltzmann/graphene/dumps/f_eqbm.h5' +phi_restart_file = '/home/mani/work/quazar_research/bolt/example_problems/electronic_boltzmann/graphene/dumps/phi_eqbm.h5' +electrostatic_solver_every_nth_step = 1000000 +solve_for_equilibrium = 0 + + +# File-writing Parameters: +dump_steps = 5 + +# Time parameters: +dt = 0.025/4 # ps +t_final = 300. # ps + +# Dimensionality considered in velocity space: +p_dim = 1 +p_space_grid = 'polar2D' # Supports 'cartesian' or 'polar2D' grids +# Set p-space start and end points accordingly in domain.py + +# Number of devices(GPUs/Accelerators) on each node: +num_devices = 4 + +# Constants: +mass_particle = 0.910938356 # x 1e-30 kg +h_bar = 1.0545718e-4 # x aJ ps +boltzmann_constant = 1 +charge = [0.*-0.160217662] # x aC +mass = [0.] #TODO : Not used in electronic_boltzmann + # Remove from lib +speed_of_light = 300. # x [um/ps] +fermi_velocity = speed_of_light/300 +epsilon0 = 8.854187817 # x [aC^2 / (aJ um) ] + +epsilon_relative = 3.9 # SiO2 +backgate_potential = -10 # V +global_chem_potential = 0.03 +contact_start = 0.0 # um +contact_end = 0.25 # um +contact_geometry = "straight" # Contacts on either side of the device + # For contacts on the same side, use + # contact_geometry = "turn_around" + +initial_temperature = 12e-5 +initial_mu = 0.015 +vel_drift_x_in = 1e-3*fermi_velocity +vel_drift_x_out = 1e-3*fermi_velocity +AC_freq = 1./100 # ps^-1 + +B3_mean = 1. # T + +# Spatial quantities (will be initialized to shape = [q1, q2] in initalize.py) +mu = None # chemical potential used in the e-ph operator +T = None # Electron temperature used in the e-ph operator +mu_ee = None # chemical potential used in the e-e operator +T_ee = None # Electron temperature used in the e-e operator +vel_drift_x = None +vel_drift_y = None +j_x = None +j_y = None +phi = None # Electric potential in the plane of graphene sheet + +# Momentum quantities (will be initialized to shape = [p1*p2*p3] in initialize.py) +E_band = None +vel_band = None + +collision_operator_nonlinear_iters = 2 + +# Variation of collisional-timescale parameter through phase space: +@af.broadcast +def tau_defect(q1, q2, p1, p2, p3): + return(np.inf * q1**0 * p1**0) + +@af.broadcast +def tau_ee(q1, q2, p1, p2, p3): + return(np.inf * q1**0 * p1**0) + +def tau(q1, q2, p1, p2, p3): + return(tau_defect(q1, q2, p1, p2, p3)) + +def band_energy(p1, p2): + + if (p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (p_space_grid == 'polar2D'): + p_x = p1 * af.cos(p2) + p_y = p1 * af.sin(p2) + else : + raise NotImplementedError('Unsupported coordinate system in p_space') + + p = af.sqrt(p_x**2. + p_y**2.) + + E_upper = p*fermi_velocity + + af.eval(E_upper) + return(E_upper) + +def band_velocity(p1, p2): + + if (p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (p_space_grid == 'polar2D'): + p_x = p1 * af.cos(p2) + p_y = p1 * af.sin(p2) + else : + raise NotImplementedError('Unsupported coordinate system in p_space') + + p = af.sqrt(p_x**2. + p_y**2.) + p_hat = [p_x / (p + 1e-20), p_y / (p + 1e-20)] + + v_f = fermi_velocity + + upper_band_velocity = [ v_f * p_hat[0], v_f * p_hat[1]] + + af.eval(upper_band_velocity[0], upper_band_velocity[1]) + return(upper_band_velocity) + +@af.broadcast +def fermi_dirac(mu, E_band): + + k = boltzmann_constant + T = initial_temperature + + f = (1./(af.exp( (E_band - mu + )/(k*T) + ) + 1. + ) + ) + + af.eval(f) + return(f) diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/phase_vs_y.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/phase_vs_y.py new file mode 100644 index 00000000..fc6ac364 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/phase_vs_y.py @@ -0,0 +1,180 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +from scipy.optimize import curve_fit +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 12, 7.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +def sin_curve_fit(t, A, tau): + return A*np.sin(2*np.pi*AC_freq*(t + tau )) + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +# Left needs to be near source, right sensor near drain +sensor_1_left_start = 5.5 # um +sensor_1_left_end = 10.0 # um + +sensor_1_right_start = 5.5 # um +sensor_1_right_end = 10.0 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +filepath = \ + '/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_2.5_tau_ee_inf_tau_eph_2.5/dumps' + +AC_freq = 1./100.0 +time_period = 1/AC_freq +t_final = params.t_final +transient_time = t_final/2. + +time = np.loadtxt(filepath + "/../dump_time_array.txt") +edge_density = np.loadtxt(filepath + "/../edge_density.txt") +q2 = np.loadtxt(filepath + "/../q2_edge.txt") + +N_spatial = edge_density.shape[1] + +transient_index = int((transient_time/t_final)*time.size) + +drive = np.sin(2*np.pi*AC_freq*time) +nsamples = drive.size +dt_corr = np.linspace(-time[-1] + time[0],\ + time[-1] - time[0], 2*nsamples-1) + +# Discarding transients +q = q2.size/2 +time_half = time[transient_index:] +drive_half = drive[transient_index:] + +# Plotting signals at edge +norm_0 = np.max(edge_density[transient_index:, 0]) +norm_1 = np.max(edge_density[transient_index:, -1]) + +pl.plot(time, drive, color='black', linestyle='--') +pl.ylim([-1.1, 1.1]) +pl.xlim([0,200]) +pl.xlabel('$\mathrm{Time\;(s)}$') + +for i in range(N_spatial): + norm_i = np.max(edge_density[transient_index:, i]) + pl.plot(time, edge_density[:, i]/norm_i) + +pl.savefig('images/signals.png') +pl.clf() + +phase_shift_corr_array = [] +phase_shift_fitting_array = []\ + +for i in range(N_spatial): + print ('index : ', i) + signal_1 = edge_density[:, i] + norm_1 = np.max(signal_1[transient_index:]) + signal_1_normalized = signal_1/norm_1 + + # Calculate phase_shifts using scipy.correlate + corr = correlate(drive, signal_1_normalized) + time_shift_corr = dt_corr[corr.argmax()] + phase_shift_corr = 2*np.pi*(((0.5 + time_shift_corr/time_period) % 1.0) - 0.5) + + # Calculate phase_shifts using scipy.curve_fit + popt, pcov = curve_fit(sin_curve_fit, time[transient_index:],\ + signal_1_normalized[transient_index:]) + time_shift_fitting = popt[1]%(time_period/2.0) + phase_shift_fitting = 2*np.pi*(((0.5 + time_shift_fitting/time_period) % 1.0) - 0.5) + + phase_shift_corr_array.append(phase_shift_corr) + phase_shift_fitting_array.append(phase_shift_fitting) + +phase_shift_corr_array = np.array(phase_shift_corr_array) +phase_shift_fitting_array = np.array(phase_shift_fitting_array) + +# Plot +pl.ylabel('$\mathrm{\phi}$') +pl.xlabel('$\mathrm{y\ \mu m}$') + +pl.plot(q2, phase_shift_corr_array, '-o', label='$\mathrm{corr}$') +pl.plot(q2, phase_shift_fitting_array, '-o', label='$\mathrm{fit}$') + +pl.title('$\mathrm{2.5 \\times 10,\ \\tau_{ee} = \infty,\ \\tau_{eph} = 2.5}$') +pl.legend(loc='best') + +#pl.axvspan(sensor_1_left_start, sensor_1_left_end, color = 'k', alpha = 0.1) +#pl.axvspan(sensor_2_left_start, sensor_2_left_end, color = 'k', alpha = 0.1) + +pl.savefig('images/phase_vs_y.png') +pl.clf() + diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/post.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/post.py new file mode 100644 index 00000000..a297c6f0 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/post.py @@ -0,0 +1,422 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +#pl.rcParams['figure.figsize'] = 8, 7.5 +pl.rcParams['figure.figsize'] = 8, 8 +#pl.rcParams['figure.figsize'] = 17, 9.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +#pl.rcParams['lines.linewidth'] = 3 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 +#N_q1 = 120 +#N_q2 = 240 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +#source_start = 3.5; source_end = 4.5 +#drain_start = 5.5; drain_end = 6.5 + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +sensor_1_left_start = 8.5 # um +sensor_1_left_end = 9.5 # um + +sensor_1_right_start = 8.5 # um +sensor_1_right_end = 9.5 # um + +# Left needs to be near source, right sensor near drain +#sensor_1_left_start = 1.5 # um +#sensor_1_left_end = 2.5 # um + +#sensor_1_right_start = 7.5 # um +#sensor_1_right_end = 8.5 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +sensor_2_left_start = 6.5 # um +sensor_2_left_end = 7.5 # um + +sensor_2_right_start = 6.5 # um +sensor_2_right_end = 7.5 # um + +sensor_2_left_indices = (q2 > sensor_2_left_start ) & (q2 < sensor_2_left_end) +sensor_2_right_indices = (q2 > sensor_2_right_start) & (q2 < sensor_2_right_end) + +#dump_index = 0 +#h5f = h5py.File('dumps/moments_' + '%06d'%(dump_index) + '.h5', 'r') +#moments = np.swapaxes(h5f['moments'][:], 0, 1) +#h5f.close() +# +#density = moments[:, :, 0] +#j_x = moments[:, :, 1] +#j_y = moments[:, :, 2] +#pl.contourf(q1, q2, density, 100) +##pl.title('Time = ' + "%.2f"%(t0)) +#pl.axes().set_aspect('equal') +#pl.xlabel(r'$x$') +#pl.ylabel(r'$y$') +#pl.colorbar() +#pl.savefig('images/density' + '.png') +#pl.clf() +# +#h5f = h5py.File('dumps/lagrange_multipliers_' + '%06d'%(dump_index) + '.h5', 'r') +#lagrange_multipliers = np.swapaxes(h5f['lagrange_multipliers'][:], 0, 1) +#h5f.close() +# +#print("lagrange_multipliers.shape = ", lagrange_multipliers.shape) +#mu = lagrange_multipliers[:, :, 0] +#mu_ee = lagrange_multipliers[:, :, 1] +#T_ee = lagrange_multipliers[:, :, 2] +#vel_drift_x = lagrange_multipliers[:, :, 3] +#vel_drift_y = lagrange_multipliers[:, :, 4] +#j_x_prime = density*vel_drift_x +#print("err = ", np.mean(np.abs(j_x_prime - j_x))) + +#filepath = \ +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/geom_1/DC/tau_D_50_tau_ee_0.2' +#dump_file= np.sort(glob.glob(filepath+'/moment*.h5'))[-1] +# +#h5f = h5py.File(dump_file, 'r') +#moments = np.swapaxes(h5f['moments'][:], 0, 1) +#h5f.close() +# +#density = moments[:, :, 0] +#np.savetxt('paper_plots/density_tau_D_50_tau_ee_0.2.txt', density) +#np.savetxt('paper_plots/q2_DC_tau_D_50_tau_ee_0.2.txt', q2) +##pl.plot(q2[q2>source_end], density[0, q2>source_end]-np.mean(density)) +# +#filepath = \ +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/geom_1/DC/tau_D_5_tau_ee_0.2' +#dump_file= np.sort(glob.glob(filepath+'/moment*.h5'))[-1] +# +# +#h5f = h5py.File(dump_file, 'r') +#moments = np.swapaxes(h5f['moments'][:], 0, 1) +#h5f.close() +# +#density = moments[:, :, 0] +#np.savetxt('paper_plots/density_tau_D_5_tau_ee_0.2.txt', density) +#np.savetxt('paper_plots/q2_DC_tau_D_5_tau_ee_0.2.txt', q2) +# +#filepath = \ +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/geom_1/DC/tau_D_10_tau_ee_0.2' +#dump_file= np.sort(glob.glob(filepath+'/moment*.h5'))[-1] +# +#N_q1 = 120 +#N_q2 = 240 +# +#q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +#q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 +# +#h5f = h5py.File(dump_file, 'r') +#moments = np.swapaxes(h5f['moments'][:], 0, 1) +#h5f.close() +# +#density = moments[:, :, 0] +#np.savetxt('paper_plots/density_tau_D_10_tau_ee_0.2.txt', density) +#np.savetxt('paper_plots/q2_DC_tau_D_10_tau_ee_0.2.txt', q2) + + +#pl.plot(q2[q2>source_end], density[0, q2>source_end]-np.mean(density)) +#pl.axhline(0, color='black', linestyle='--') +#pl.legend(['$\\tau_{ee}=0.2$ ps, $\\tau_{e-ph}=50$ ps', +# '$\\tau_{ee}=0.2$ ps, $\\tau_{e-ph}=10$ ps'], loc='lower right') +#pl.xlabel(r'$x\;(\mu \mathrm{m})$') +#pl.ylabel(r'$R\; (\mathrm{a.u.})$') +#pl.xlim(xmin=(source_end+0.1)) +#pl.savefig('paper_plots/DC.png') + +filepath = \ +'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/dumps_tau_D_1_tau_ee_0.2_movie' +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/geom_1/55_GHz/tau_D_5_tau_ee_0.2' +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/dumps_AC_10_Ghz_tau_D_10_tau_ee_1_geom_2/' +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/dumps_tau_D_2_tau_ee_1_AC/' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +sensor_1_signal_array = [] +print("Reading sensor signal...") +for file_number, dump_file in enumerate(moment_files): + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + density = moments[:, :, 0] + + source = np.mean(density[0, source_indices]) + drain = np.mean(density[-1, drain_indices]) + + sensor_1_left = np.mean(density[0, sensor_1_left_indices] ) + sensor_1_right = np.mean(density[-1, sensor_1_right_indices]) + + sensor_1_signal = sensor_1_left - sensor_1_right + + sensor_1_signal_array.append(sensor_1_signal) + +time_array = np.loadtxt("dump_time_array.txt") +AC_freq = 1./100 +input_signal_array = np.sin(2.*np.pi*AC_freq*time_array) +sensor_1_signal_array = np.array(sensor_1_signal_array) +half_time = (int)(time_array.size/2) +sensor_normalized = \ + sensor_1_signal_array/np.max(np.abs(sensor_1_signal_array[half_time:])) + +pl.rcParams['figure.figsize'] = 10, 8 +for file_number, dump_file in yt.parallel_objects(enumerate(moment_files)): + + print("file number = ", file_number, "of ", moment_files.size) + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + gs = gridspec.GridSpec(3, 2) + pl.subplot(gs[:, 0]) + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + pl.contourf(q1_meshgrid, q2_meshgrid, density, 100, cmap='bwr') + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + #pl.colorbar() + + h5f = h5py.File(lagrange_multiplier_files[file_number], 'r') + lagrange_multipliers = h5f['lagrange_multipliers'][:] + h5f.close() + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + +# pl.streamplot(q1[(int)(N_q1/2):], q2, +# vel_drift_x[:, (int)(N_q1/2):], vel_drift_y[:, (int)(N_q1/2):], +# density=2, color='blue', +# linewidth=0.7, arrowsize=1 +# ) + pl.streamplot(q1, q2, + vel_drift_x, vel_drift_y, + density=2, color='blue', + linewidth=0.7, arrowsize=1 + ) +# pl.streamplot(q1, q2, +# vel_drift_x, vel_drift_y, +# density=3, color='blue', +# linewidth=0.8, arrowsize=1.1 +# ) + pl.xlim([domain.q1_start, domain.q1_end]) + pl.ylim([domain.q2_start, domain.q2_end]) + #pl.ylim([0, 5]) + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + pl.ylabel(r'$y\;(\mu \mathrm{m})$') + + pl.gca().annotate("+", xy=(-0.07, .9), xycoords=("axes fraction"), + ha="center", va="center", size=30, + bbox=dict(fc="white")) + pl.gca().annotate("-", xy=(1.05, .9), xycoords=("axes fraction"), + ha="center", va="center", size=30, + bbox=dict(fc="white", pad=6.5)) + + + pl.subplot(gs[1, 1]) + + pl.plot(time_array, input_signal_array) + pl.plot(time_array, sensor_normalized) + pl.axhline(0, color='black', linestyle='--') + pl.axvline(time_array[file_number], color='black', alpha=0.75) + pl.legend(['Source $I(t)$', 'Measured $V(t)$'], loc=(0.04, 1.125)) + pl.xlabel(r'Time (ps)') + pl.xlim([100, 200]) + pl.ylim([-1.1, 1.1]) + + + pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 1$ ps') + #pl.tight_layout() + pl.savefig('images/dump_' + '%06d'%file_number + '.png') + #pl.savefig('paper_plots/DC.png') + pl.clf() + + +#time_array = [] +#input_signal_array = [] +#sensor_1_signal_array = [] +#sensor_2_signal_array = [] +#for file_number, dump_file in enumerate(moment_files): +# +# print("file number = ", file_number, "of ", moment_files.size) +# +# h5f = h5py.File(dump_file, 'r') +# moments = np.swapaxes(h5f['moments'][:], 0, 1) +# h5f.close() +# +# density = moments[:, :, 0] +# +# source = np.mean(density[0, source_indices]) +# drain = np.mean(density[-1, drain_indices]) +# +# sensor_1_left = np.mean(density[0, sensor_1_left_indices] ) +# sensor_1_right = np.mean(density[-1, sensor_1_right_indices]) +# #sensor_1_right = np.mean(density[0, sensor_1_right_indices]) +# +# sensor_2_left = np.mean(density[0, sensor_2_left_indices] ) +# sensor_2_right = np.mean(density[-1, sensor_2_right_indices]) +# +# #sensor_1_left = density[0, q2>source_end] +# #sensor_1_right = density[-1, q2>source_end] +# +# input_signal = source - drain +# sensor_1_signal = sensor_1_left - sensor_1_right +# sensor_2_signal = sensor_2_left - sensor_2_right +# +# time_array.append(file_number*dt*dump_interval) +# input_signal_array.append(input_signal) +# sensor_1_signal_array.append(sensor_1_signal) +# sensor_2_signal_array.append(sensor_2_signal) +# +##pl.rcParams['figure.figsize'] = 12, 8 +## +#AC_freq = 5.5/100 +#time_array = np.array(time_array) +#input_signal_array = np.sin(2.*np.pi*AC_freq*time_array) +#sensor_1_signal_array = np.array(sensor_1_signal_array) +###np.savetxt('drive.txt', input_signal_array) +##np.savetxt('paper_plots/sensor_tau_ee_0.2_tau_D_5.txt', sensor_1_signal_array) +##np.savetxt('time.txt', time_array) +## +##print("sensor.shape = ", sensor_1_signal_array.shape) +##sensor_2_signal_array = np.array(sensor_2_signal_array) +## +#half_time = (int)(time_array.size/2) +#pl.plot(time_array, input_signal_array/np.max(input_signal_array[half_time:])) +#pl.plot(time_array, +# sensor_1_signal_array/np.max(sensor_1_signal_array[half_time:]) +# ) +##pl.plot(time_array, +## sensor_2_signal_array/np.max(sensor_2_signal_array[half_time:]) +## ) +#pl.xlabel(r"Time (ps)") +#pl.ylim([-1.1, 1.1]) +#pl.legend(['Input', 'Sensor 1', 'Sensor 2']) +#pl.savefig('paper_plots/IV_55_Ghz_tau_ee_0.2_tau_D_5.png') +##half_time = 0 +#input_normalized = input_signal_array[half_time:]/np.max(input_signal_array[half_time:]) +#sensor_normalized = sensor_1_signal_array[half_time:]/np.max(sensor_1_signal_array[half_time:]) +# +## Calculate the phase diff. Copied from: +## https://stackoverflow.com/questions/6157791/find-phase-difference-between-two-inharmonic-waves +#corr = correlate(input_normalized, sensor_normalized) +#nsamples = input_normalized.size +#time_corr = time_array[half_time:] +#dt_corr = np.linspace(-time_corr[-1] + time_corr[0], +# time_corr[-1] - time_corr[0], 2*nsamples-1) +#time_shift = dt_corr[corr.argmax()] +# +## force the phase shift to be in [-pi:pi] +#period = 1./AC_freq +#phase_diff = 2*np.pi*(((0.5 + time_shift/period) % 1.0) - 0.5) +#print("density.shape = ", density.shape) +#print("Phase diff = ", phase_diff) + +#phase_vs_x = [] +#for i in range(sensor_1_signal_array[0, :].size): +# signal = sensor_1_signal_array[:, i] +# corr = correlate(input_signal_array, signal) +# nsamples = input_signal_array.size +# half_time = 0 +# time_corr = time_array[half_time:] +# dt_corr = np.linspace(-time_corr[-1] + time_corr[0], +# time_corr[-1] - time_corr[0], +# 2*nsamples-1 +# ) +# time_shift = dt_corr[corr.argmax()] +# +# # force the phase shift to be in [-pi:pi] +# period = 1./params.AC_freq +# phase_diff = 2*np.pi*(((0.5 + time_shift/period) % 1.0) - 0.5) +# phase_vs_x.append(phase_diff) +# +#phase_vs_x = np.array(phase_vs_x) +#print("phase_vs_x.shape = ", phase_vs_x.shape) +#np.savetxt("paper_plots/phase_vs_x_tau_ee_0.2_tau_D_1.txt", phase_vs_x) +#np.savetxt("paper_plots/q2_tau_ee_0.2_tau_D_1.txt", q2) +#print("density.shape = ", density.shape) + + diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/signals.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/signals.py new file mode 100644 index 00000000..62104908 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/signals.py @@ -0,0 +1,171 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +# Left needs to be near source, right sensor near drain +sensor_1_left_start = 8.5 # um +sensor_1_left_end = 9.5 # um + +sensor_1_right_start = 8.5 # um +sensor_1_right_end = 9.5 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +sensor_2_left_start = 6.5 # um +sensor_2_left_end = 7.5 # um + +sensor_2_right_start = 6.5 # um +sensor_2_right_end = 7.5 # um + +sensor_2_left_indices = (q2 > sensor_2_left_start ) & (q2 < sensor_2_left_end) +sensor_2_right_indices = (q2 > sensor_2_right_start) & (q2 < sensor_2_right_end) + +filepath = \ +'/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_1.0_tau_ee_0.2_tau_eph_0.5/dumps' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +sensor_1_signal_array = [] +print("Reading sensor signal...") +for file_number, dump_file in enumerate(moment_files): + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + density = moments[:, :, 0] + + source = np.mean(density[0, source_indices]) + drain = np.mean(density[-1, drain_indices]) + + sensor_1_left = np.mean(density[0, sensor_1_left_indices] ) + sensor_1_right = np.mean(density[-1, sensor_1_right_indices]) + + sensor_1_signal = sensor_1_left - sensor_1_right + + sensor_1_signal_array.append(sensor_1_signal) + +time_array = np.loadtxt("dump_time_array.txt") +AC_freq = 1./100 +input_signal_array = np.sin(2.*np.pi*AC_freq*time_array) +sensor_1_signal_array = np.array(sensor_1_signal_array) +half_time = (int)(time_array.size/2) + +input_normalized = \ + input_signal_array/np.max(np.abs(input_signal_array[half_time:])) +sensor_normalized = \ + sensor_1_signal_array/np.max(np.abs(sensor_1_signal_array[half_time:])) + +# Calculate the phase difference between input_signal_array and sensor_normalized +# Code copied from : +# https:/stackoverflow.com/questions/6157791/find-phase-difference-between-two-inharmonic-waves + +corr = correlate(input_normalized, sensor_normalized) +nsamples = input_normalized.size +time_corr = time_array[half_time:] +dt_corr = np.linspace(-time_corr[-1] + time_corr[0], + time_corr[-1] - time_corr[0], 2*nsamples-1) +time_shift = dt_corr[corr.argmax()] + +#Force the phase shift to be in [-pi:pi] +period = 1./AC_freq +phase_diff = 2*np.pi*(((0.5 + time_shift/period) % 1.0) - 0.5) + +pl.plot(time_array, input_signal_array) +pl.plot(time_array, sensor_normalized) +pl.axhline(0, color='black', linestyle='--') + +pl.legend(['Source $I(t)$', 'Measured $V(t)$'], loc=1) +pl.text(135, 1.14, '$\phi : %.2f \; rad$' %phase_diff) +pl.xlabel(r'Time (ps)') +pl.xlim([0, 200]) +pl.ylim([-1.1, 1.1]) + +pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 0.5$ ps') +pl.savefig('images/iv' + '.png') +pl.clf() + + diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/submit_post b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/submit_post new file mode 100644 index 00000000..f27a05ef --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/submit_post @@ -0,0 +1,29 @@ +#!/bin/bash +#SBATCH -t 16:00:00 # walltime +#SBATCH -N 8 # Number of nodes +#SBATCH -n 32 # Number of MPI ranks +#SBATCH -o out_%j # Pathname of stdout +#SBATCH -e err_%j # Pathname of stderr +#SBATCH -A w19_mcpgpu # Allocation +#SBATCH --qos=standard # QoS (standard, interactive, standby, large*, long*, high*) + # See https://hpc.lanl.gov/scheduling_policies +#SBATCH --mail-user=mc0710@gmail.com +#SBATCH --mail-type=BEGIN +#SBATCH --mail-type=END +#SBATCH --mail-type=FAIL + +module list +pwd +date + +# Arrayfire library +export AF_PATH=/usr/projects/p18_ebhlight3d/arrayfire/arrayfire_install +export PETSC_DIR=/usr/projects/p18_ebhlight3d/petsc_3.10.0_install +export LD_LIBRARY_PATH=$AF_PATH/lib64:$LD_LIBRARY_PATH + +# Bolt as library +export PYTHONPATH=$PYTHONPATH:/users/manic/bolt_master + +source activate /usr/projects/p18_ebhlight3d/bolt_env_2019.1/ + +srun python main.py diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/vorticity.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/vorticity.py new file mode 100644 index 00000000..2f494c60 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.0_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/vorticity.py @@ -0,0 +1,136 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +filepath = \ +'/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_1.0_tau_ee_0.2_tau_eph_0.5/dumps' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +time_array = np.loadtxt("dump_time_array.txt") +half_time = (int)(time_array.size/2) + +for file_number, dump_file in yt.parallel_objects(enumerate(moment_files)): + + print("file number = ", file_number, "of ", moment_files.size) + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + + h5f = h5py.File(lagrange_multiplier_files[file_number], 'r') + lagrange_multipliers = h5f['lagrange_multipliers'][:] + h5f.close() + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + + + dq1 = (domain.q1_end - domain.q1_start)/domain.N_q1 + dq2 = (domain.q2_end - domain.q2_start)/domain.N_q2 + + dvx_dx, dvx_dy = np.gradient(j_x/density, dq1, dq2) + dvy_dx, dvy_dy = np.gradient(j_y/density, dq1, dq2) + + vorticity = dvy_dx - dvx_dy + + pl.contourf(q1_meshgrid, q2_meshgrid, vorticity, 100, cmap='bwr') + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + + pl.streamplot(q1, q2, + vel_drift_x, vel_drift_y, + density=2, color='blue', + linewidth=0.7, arrowsize=1 + ) + + pl.xlim([domain.q1_start, domain.q1_end]) + pl.ylim([domain.q2_start, domain.q2_end]) + + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + pl.ylabel(r'$y\;(\mu \mathrm{m})$') + pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 1.0$ ps') + pl.savefig('vorticity_images/dump_' + '%06d'%file_number + '.png') + pl.clf() + diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/PetscBinaryIO.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/PetscBinaryIO.py new file mode 100644 index 00000000..fd0e48e9 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/PetscBinaryIO.py @@ -0,0 +1,479 @@ +"""PetscBinaryIO +=============== + +Provides + 1. PETSc-named objects Vec, Mat, and IS that inherit numpy.ndarray + 2. A class to read and write these objects from PETSc binary files. + +The standard usage of this module should look like: + + >>> import PetscBinaryIO + >>> io = PetscBinaryIO.PetscBinaryIO() + >>> objects = io.readBinaryFile('file.dat') + +or + + >>> import PetscBinaryIO + >>> import numpy + >>> vec = numpy.array([1., 2., 3.]).view(PetscBinaryIO.Vec) + >>> io = PetscBinaryIO.PetscBinaryIO() + >>> io.writeBinaryFile('file.dat', [vec,]) + +to read in objects one at a time use such as + + >>> import PetscBinaryIO + >>> io = PetscBinaryIO.PetscBinaryIO() + >>> fh = open('file.dat') + >>> objecttype = io.readObjectType(fh) + >>> if objecttype == 'Vec': + >>> v = io.readVec(fh) + + Note that one must read in the object type first and then call readVec(), readMat() etc. + + +See also PetscBinaryIO.__doc__ and methods therein. +""" + +import numpy as np +import functools + +try: + basestring # Python-2 has basestring as a common parent of unicode and str +except NameError: + basestring = str # Python-3 is unicode through and through + +def update_wrapper_with_doc(wrapper, wrapped): + """Similar to functools.update_wrapper, but also gets the wrapper's __doc__ string""" + wdoc = wrapper.__doc__ + + functools.update_wrapper(wrapper, wrapped) + if wdoc is not None: + if wrapper.__doc__ is None: + wrapper.__doc__ = wdoc + else: + wrapper.__doc__ = wrapper.__doc__ + wdoc + return wrapper + +def wraps_with_doc(wrapped): + """Similar to functools.wraps, but also gets the wrapper's __doc__ string""" + return functools.partial(update_wrapper_with_doc, wrapped=wrapped) + +def decorate_with_conf(f): + """Decorates methods to take kwargs for precisions.""" + @wraps_with_doc(f) + def decorated_f(self, *args, **kwargs): + """ + Additional kwargs: + precision: 'single', 'double', 'longlong' for scalars + indices: '32bit', '64bit' integer size + complexscalars: True/False + + Note these are set in order of preference: + 1. kwargs if given here + 2. PetscBinaryIO class __init__ arguments + 3. PETSC_DIR/PETSC_ARCH defaults + """ + + changed = False + old_precision = self.precision + old_indices = self.indices + old_complexscalars = self.complexscalars + + try: + self.precision = kwargs.pop('precision') + except KeyError: + pass + else: + changed = True + + try: + self.indices = kwargs.pop('indices') + except KeyError: + pass + else: + changed = True + + try: + self.complexscalars = kwargs.pop('complexscalars') + except KeyError: + pass + else: + changed = True + + if changed: + self._update_dtypes() + + result = f(self, *args, **kwargs) + + if changed: + self.precision = old_precision + self.indices = old_indices + self.complexscalars = old_complexscalars + self._update_dtypes() + + return result + return decorated_f + + +class DoneWithFile(Exception): pass + + +class Vec(np.ndarray): + """Vec represented as 1D numpy array + + The best way to instantiate this class for use with writeBinaryFile() + is through the numpy view method: + + vec = numpy.array([1,2,3]).view(Vec) + """ + _classid = 1211214 + + +class MatDense(np.matrix): + """Mat represented as 2D numpy array + + The best way to instantiate this class for use with writeBinaryFile() + is through the numpy view method: + + mat = numpy.array([[1,0],[0,1]]).view(Mat) + """ + _classid = 1211216 + + +class MatSparse(tuple): + """Mat represented as CSR tuple ((M, N), (rowindices, col, val)) + + This should be instantiated from a tuple: + + mat = MatSparse( ((M,N), (rowindices,col,val)) ) + """ + _classid = 1211216 + def __repr__(self): + return 'MatSparse: %s'%super(MatSparse, self).__repr__() + + +class IS(np.ndarray): + """IS represented as 1D numpy array + + The best way to instantiate this class for use with writeBinaryFile() + is through the numpy "view" method: + + an_is = numpy.array([3,4,5]).view(IS) + """ + _classid = 1211218 + + +class PetscBinaryIO(object): + """Reader/Writer class for PETSc binary files. + + Note that by default, precisions for both scalars and indices, as well as + complex scalars, are picked up from the PETSC_DIR/PETSC_ARCH configuration + as set by environmental variables. + + Alternatively, defaults can be overridden at class instantiation, or for + a given method call. + """ + + _classid = {1211216:'Mat', + 1211214:'Vec', + 1211218:'IS', + 1211219:'Bag'} + + def __init__(self, precision=None, indices=None, complexscalars=None): + if (precision is None) or (indices is None) or (complexscalars is None): + import petsc_conf + defaultprecision, defaultindices, defaultcomplexscalars = petsc_conf.get_conf() + if precision is None: + if defaultprecision is None: + precision = 'double' + else: + precision = defaultprecision + + if indices is None: + if defaultindices is None: + indices = '32bit' + else: + indices = defaultindices + + if complexscalars is None: + if defaultcomplexscalars is None: + complexscalars = False + else: + complexscalars = defaultcomplexscalars + + self.precision = precision + self.indices = indices + self.complexscalars = complexscalars + self._update_dtypes() + + def _update_dtypes(self): + if self.indices == '64bit': + self._inttype = np.dtype('>i8') + else: + self._inttype = np.dtype('>i4') + + if self.precision == 'longlong': + nbyte = 16 + elif self.precision == 'single': + nbyte = 4 + else: + nbyte = 8 + + if self.complexscalars: + name = 'c' + nbyte = nbyte * 2 # complex scalar takes twice as many bytes + else: + name = 'f' + + self._scalartype = '>{0}{1}'.format(name, nbyte) + + @decorate_with_conf + def readVec(self, fh): + """Reads a PETSc Vec from a binary file handle, must be called after readObjectType().""" + + nz = np.fromfile(fh, dtype=self._inttype, count=1)[0] + try: + vals = np.fromfile(fh, dtype=self._scalartype, count=nz) + except MemoryError: + raise IOError('Inconsistent or invalid Vec data in file') + if (len(vals) is 0): + raise IOError('Inconsistent or invalid Vec data in file') + return vals.view(Vec) + + @decorate_with_conf + def writeVec(self, fh, vec): + """Writes a PETSc Vec to a binary file handle.""" + + metadata = np.array([Vec._classid, len(vec)], dtype=self._inttype) + metadata.tofile(fh) + vec.astype(self._scalartype).tofile(fh) + return + + @decorate_with_conf + def readMatSparse(self, fh): + """Reads a PETSc Mat, returning a sparse representation of the data. Must be called after readObjectType() + + (M,N), (I,J,V) = readMatSparse(fid) + + Input: + fid : file handle to open binary file. + Output: + M,N : matrix size + I,J : arrays of row and column for each nonzero + V: nonzero value + """ + + try: + M,N,nz = np.fromfile(fh, dtype=self._inttype, count=3) + I = np.empty(M+1, dtype=self._inttype) + I[0] = 0 + rownz = np.fromfile(fh, dtype=self._inttype, count=M) + np.cumsum(rownz, out=I[1:]) + assert I[-1] == nz + + J = np.fromfile(fh, dtype=self._inttype, count=nz) + assert len(J) == nz + V = np.fromfile(fh, dtype=self._scalartype, count=nz) + assert len(V) == nz + except (AssertionError, MemoryError, IndexError): + raise IOError('Inconsistent or invalid Mat data in file') + + return MatSparse(((M, N), (I, J, V))) + + @decorate_with_conf + def writeMatSparse(self, fh, mat): + """Writes a Mat into a PETSc binary file handle""" + + ((M,N), (I,J,V)) = mat + metadata = np.array([MatSparse._classid,M,N,I[-1]], dtype=self._inttype) + rownz = I[1:] - I[:-1] + + assert len(J.shape) == len(V.shape) == len(I.shape) == 1 + assert len(J) == len(V) == I[-1] == rownz.sum() + assert (rownz > -1).all() + + metadata.tofile(fh) + rownz.astype(self._inttype).tofile(fh) + J.astype(self._inttype).tofile(fh) + V.astype(self._scalartype).tofile(fh) + return + + @decorate_with_conf + def readMatDense(self, fh): + """Reads a PETSc Mat, returning a dense represention of the data, must be called after readObjectType()""" + + try: + M,N,nz = np.fromfile(fh, dtype=self._inttype, count=3) + I = np.empty(M+1, dtype=self._inttype) + I[0] = 0 + rownz = np.fromfile(fh, dtype=self._inttype, count=M) + np.cumsum(rownz, out=I[1:]) + assert I[-1] == nz + + J = np.fromfile(fh, dtype=self._inttype, count=nz) + assert len(J) == nz + V = np.fromfile(fh, dtype=self._scalartype, count=nz) + assert len(V) == nz + + except (AssertionError, MemoryError, IndexError): + raise IOError('Inconsistent or invalid Mat data in file') + + mat = np.zeros((M,N), dtype=self._scalartype) + for row in range(M): + rstart, rend = I[row:row+2] + mat[row, J[rstart:rend]] = V[rstart:rend] + return mat.view(MatDense) + + @decorate_with_conf + def readMatSciPy(self, fh): + from scipy.sparse import csr_matrix + (M, N), (I, J, V) = self.readMatSparse(fh) + return csr_matrix((V, J, I), shape=(M, N)) + + @decorate_with_conf + def writeMatSciPy(self, fh, mat): + from scipy.sparse import csr_matrix + if hasattr(mat, 'tocsr'): + mat = mat.tocsr() + assert isinstance(mat, csr_matrix) + V = mat.data + M,N = mat.shape + J = mat.indices + I = mat.indptr + return self.writeMatSparse(fh, (mat.shape, (mat.indptr,mat.indices,mat.data))) + + @decorate_with_conf + def readMat(self, fh, mattype='sparse'): + """Reads a PETSc Mat from binary file handle, must be called after readObjectType() + + optional mattype: 'sparse" or 'dense' + + See also: readMatSparse, readMatDense + """ + + if mattype == 'sparse': + return self.readMatSparse(fh) + elif mattype == 'dense': + return self.readMatDense(fh) + elif mattype == 'scipy.sparse': + return self.readMatSciPy(fh) + else: + raise RuntimeError('Invalid matrix type requested: choose sparse/dense/scipy.sparse') + + @decorate_with_conf + def readIS(self, fh): + """Reads a PETSc Index Set from binary file handle, must be called after readObjectType()""" + + try: + nz = np.fromfile(fh, dtype=self._inttype, count=1)[0] + v = np.fromfile(fh, dtype=self._inttype, count=nz) + assert len(v) == nz + except (MemoryError,IndexError): + raise IOError('Inconsistent or invalid IS data in file') + return v.view(IS) + + @decorate_with_conf + def writeIS(self, fh, anis): + """Writes a PETSc IS to binary file handle.""" + + metadata = np.array([IS._classid, len(anis)], dtype=self._inttype) + metadata.tofile(fh) + anis.astype(self._inttype).tofile(fh) + return + + @decorate_with_conf + def readObjectType(self, fid): + """Returns the next object type as a string in the file""" + try: + header = np.fromfile(fid, dtype=self._inttype, count=1)[0] + except (MemoryError, IndexError): + raise DoneWithFile + try: + objecttype = self._classid[header] + except KeyError: + raise IOError('Invalid PetscObject CLASSID or object not implemented for python') + return objecttype + + @decorate_with_conf + def readBinaryFile(self, fid, mattype='sparse'): + """Reads a PETSc binary file, returning a tuple of the contained objects. + + objects = self.readBinaryFile(fid, **kwargs) + + Input: + fid : either file name or handle to an open binary file. + + Output: + objects : tuple of objects representing the data in numpy arrays. + + Optional: + mattype : + 'sparse': Return matrices as raw CSR: (M, N), (row, col, val). + 'dense': Return matrices as MxN numpy arrays. + 'scipy.sparse': Return matrices as scipy.sparse objects. + """ + + close = False + + if isinstance(fid, basestring): + fid = open(fid, 'rb') + close = True + + objects = [] + try: + while True: + objecttype = self.readObjectType(fid) + + if objecttype == 'Vec': + objects.append(self.readVec(fid)) + elif objecttype == 'IS': + objects.append(self.readIS(fid)) + elif objecttype == 'Mat': + objects.append(self.readMat(fid,mattype)) + elif objecttype == 'Bag': + raise NotImplementedError('Bag Reader not yet implemented') + except DoneWithFile: + pass + finally: + if close: + fid.close() + + return tuple(objects) + + @decorate_with_conf + def writeBinaryFile(self, fid, objects): + """Writes a PETSc binary file containing the objects given. + + readBinaryFile(fid, objects) + + Input: + fid : either file handle to an open binary file, or filename. + objects : list of objects representing the data in numpy arrays, + which must be of type Vec, IS, MatSparse, or MatSciPy. + """ + close = False + if isinstance(fid, basestring): + fid = open(fid, 'wb') + close = True + + for petscobj in objects: + if (isinstance(petscobj, Vec)): + self.writeVec(fid, petscobj) + elif (isinstance(petscobj, IS)): + self.writeIS(fid, petscobj) + elif (isinstance(petscobj, MatSparse)): + self.writeMatSparse(fid, petscobj) + elif (isinstance(petscobj, MatDense)): + if close: + fid.close() + raise NotImplementedError('Writing a dense matrix is not yet supported') + else: + try: + self.writeMatSciPy(fid, petscobj) + except AssertionError: + if close: + fid.close() + raise TypeError('Object %s is not a valid PETSc object'%(petscobj.__repr__())) + if close: + fid.close() + return diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/README.txt b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/README.txt new file mode 100644 index 00000000..ddb0d8b5 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/README.txt @@ -0,0 +1,12 @@ +To switch between 1D/2D polar and cartesian momentum space, the following changes need +to be made : + + +1. domain + - Change p2_start, p2_end and N_p2 +2. params + - Change p_space_grid + - Change p_dim (if switching between 1D and 2D representation in p-space) +3. initialize : No change +4. main : No change +5. boundary_conditions : No change diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/boundary_conditions.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/boundary_conditions.py new file mode 100644 index 00000000..762f5e79 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/boundary_conditions.py @@ -0,0 +1,107 @@ +import numpy as np +import arrayfire as af +import domain + +in_q1_left = 'mirror+dirichlet' +in_q1_right = 'mirror+dirichlet' +in_q2_bottom = 'mirror' +in_q2_top = 'mirror' + +@af.broadcast +def f_left(f, t, q1, q2, p1, p2, p3, params): + + k = params.boltzmann_constant + E_upper = params.E_band + T = params.initial_temperature + mu = params.initial_mu + + t = params.current_time + omega = 2. * np.pi * params.AC_freq + vel_drift_x_in = params.vel_drift_x_in + + if (params.p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (params.p_space_grid == 'polar2D'): + p_x = p1 * af.cos(p2) + p_y = p1 * af.sin(p2) + else: + raise NotImplementedError('Unsupported coordinate system in p_space') + + + fermi_dirac_in = (1./(af.exp( (E_upper - vel_drift_x_in*p_x - mu)/(k*T) ) + 1.) + ) + + if (params.contact_geometry=="straight"): + # Contacts on either side of the device + + q2_contact_start = params.contact_start + q2_contact_end = params.contact_end + + cond = ((q2 >= q2_contact_start) & \ + (q2 <= q2_contact_end) \ + ) + + f_left = cond*fermi_dirac_in + (1 - cond)*f + + elif (params.contact_geometry=="turn_around"): + # Contacts on the same side of the device + + vel_drift_x_out = -params.vel_drift_x_in * np.sin(omega*t) + + fermi_dirac_out = (1./(af.exp( (E_upper - vel_drift_x_out*p_x - mu)/(k*T) ) + 1.) + ) + + # TODO: set these parameters in params.py + cond_in = ((q2 >= 3.5) & (q2 <= 4.5)) + cond_out = ((q2 >= 5.5) & (q2 <= 6.5)) + + f_left = cond_in*fermi_dirac_in + cond_out*fermi_dirac_out \ + + (1 - cond_in)*(1 - cond_out)*f + + af.eval(f_left) + return(f_left) + +@af.broadcast +def f_right(f, t, q1, q2, p1, p2, p3, params): + + k = params.boltzmann_constant + E_upper = params.E_band + T = params.initial_temperature + mu = params.initial_mu + + t = params.current_time + omega = 2. * np.pi * params.AC_freq + vel_drift_x_out = params.vel_drift_x_out + + if (params.p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (params.p_space_grid == 'polar2D'): + p_x = p1 * af.cos(p2) + p_y = p1 * af.sin(p2) + else: + raise NotImplementedError('Unsupported coordinate system in p_space') + + fermi_dirac_out = (1./(af.exp( (E_upper - vel_drift_x_out*p_x - mu)/(k*T) ) + 1.) + ) + + if (params.contact_geometry=="straight"): + # Contacts on either side of the device + + q2_contact_start = params.contact_start + q2_contact_end = params.contact_end + + cond = ((q2 >= q2_contact_start) & \ + (q2 <= q2_contact_end) \ + ) + + f_right = cond*fermi_dirac_out + (1 - cond)*f + + elif (params.contact_geometry=="turn_around"): + # Contacts on the same side of the device + + f_right = f + + af.eval(f_right) + return(f_right) diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/domain.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/domain.py new file mode 100644 index 00000000..816e0075 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/domain.py @@ -0,0 +1,65 @@ +import numpy as np +import params + +q1_start = 0. +q1_end = 1.0 +N_q1 = 72 + +q2_start = 0. +q2_end = 5.25 +N_q2 = 378 + +# If N_p1 > 1, mirror boundary conditions require p1 to be +# symmetric about zero +# TODO : Check and fix discrepancy between this and the claim +# that p1_center = mu in polar representation +N_p1 = 1 # Set equal to 1 for 1D polar + +# In the cartesian representation of momentum space, +# p1 = p_x (magnitude of momentum) +# p1_start and p1_end are set such that p1_center is 0 + +# Uncomment the following for the cartesian representation of momentum space +#p1_start = [-0.04] +#p1_end = [0.04] + + +# In the 2D polar representation of momentum space, +# p1 = p_r (magnitude of momentum) +# p1_start and p1_end are set such that p1_center is mu + +# Uncomment the following for the 2D polar representation of momentum space +#p1_start = [params.initial_mu - \ +# 16.*params.boltzmann_constant*params.initial_temperature] +#p1_end = [params.initial_mu + \ +# 16.*params.boltzmann_constant*params.initial_temperature] + +# Uncomment the following for the 1D polar representation of momentum space +p1_start = [0.5*params.initial_mu] +p1_end = [1.5*params.initial_mu] + + +# If N_p2 > 1, mirror boundary conditions require p2 to be +# symmetric about zero +N_p2 = 4096 + +# In the cartesian representation of momentum space, +# p2 = p_y (magnitude of momentum) +# p2_start and p2_end are set such that p2_center is 0 +#p2_start = [-0.04] +#p2_end = [0.04] + +# In the 2D polar representation of momentum space, +# p2 = p_theta (angle of momentum) +# N_p_theta MUST be even. +p2_start = [-np.pi] +p2_end = [np.pi] + +# If N_p3 > 1, mirror boundary conditions require p3 to be +# symmetric about zero + +p3_start = [-0.5] +p3_end = [0.5] +N_p3 = 1 + +N_ghost = 2 diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/dump_time_array.txt b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/dump_time_array.txt new file mode 100644 index 00000000..fbfd5621 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/dump_time_array.txt @@ -0,0 +1,135 @@ +2.344375000000000497e+01 +2.345625000000000426e+01 +2.346875000000000355e+01 +2.348125000000000284e+01 +2.349375000000000213e+01 +2.350625000000000497e+01 +2.351875000000000426e+01 +2.353125000000000355e+01 +2.354375000000000284e+01 +2.355625000000000213e+01 +2.356875000000000497e+01 +2.358125000000000426e+01 +2.359375000000000355e+01 +2.360625000000000284e+01 +2.361875000000000213e+01 +2.363125000000000497e+01 +2.364375000000000426e+01 +2.365625000000000355e+01 +2.366875000000000284e+01 +2.368125000000000213e+01 +2.369375000000000497e+01 +2.370625000000000426e+01 +2.371875000000000355e+01 +2.373125000000000284e+01 +2.374375000000000213e+01 +2.375625000000000497e+01 +2.376875000000000426e+01 +2.378125000000000355e+01 +2.379375000000000284e+01 +2.380625000000000213e+01 +2.381875000000000497e+01 +2.383125000000000426e+01 +2.384375000000000355e+01 +2.385625000000000284e+01 +2.386875000000000213e+01 +2.388125000000000497e+01 +2.389375000000000426e+01 +2.390625000000000355e+01 +2.391875000000000284e+01 +2.393125000000000213e+01 +2.394375000000000497e+01 +2.395625000000000426e+01 +2.396875000000000355e+01 +2.398125000000000284e+01 +2.399375000000000213e+01 +2.400625000000000497e+01 +2.401875000000000426e+01 +2.403125000000000355e+01 +2.404375000000000284e+01 +2.405625000000000213e+01 +2.406875000000000497e+01 +2.408125000000000426e+01 +2.409375000000000355e+01 +2.410625000000000284e+01 +2.411875000000000213e+01 +2.413125000000000497e+01 +2.414375000000000426e+01 +2.415625000000000355e+01 +2.416875000000000284e+01 +2.418125000000000213e+01 +2.419375000000000497e+01 +2.420625000000000426e+01 +2.421875000000000355e+01 +2.423125000000000284e+01 +2.424375000000000213e+01 +2.425625000000000497e+01 +2.426875000000000426e+01 +2.428125000000000355e+01 +2.429375000000000284e+01 +2.430625000000000213e+01 +2.431875000000000497e+01 +2.433125000000000426e+01 +2.434375000000000355e+01 +2.435625000000000284e+01 +2.436875000000000213e+01 +2.438125000000000497e+01 +2.439375000000000426e+01 +2.440625000000000355e+01 +2.441875000000000284e+01 +2.443125000000000213e+01 +2.444375000000000497e+01 +2.445625000000000426e+01 +2.446875000000000355e+01 +2.448125000000000284e+01 +2.449375000000000213e+01 +2.450625000000000497e+01 +2.451875000000000426e+01 +2.453125000000000355e+01 +2.454375000000000284e+01 +2.455625000000000213e+01 +2.456875000000000497e+01 +2.458125000000000426e+01 +2.459375000000000355e+01 +2.460625000000000284e+01 +2.461875000000000213e+01 +2.463125000000000497e+01 +2.464375000000000426e+01 +2.465625000000000355e+01 +2.466875000000000284e+01 +2.468125000000000213e+01 +2.469375000000000497e+01 +2.470625000000000426e+01 +2.471875000000000355e+01 +2.473125000000000284e+01 +2.474375000000000213e+01 +2.475625000000000497e+01 +2.476875000000000426e+01 +2.478125000000000355e+01 +2.479375000000000284e+01 +2.480625000000000213e+01 +2.481875000000000497e+01 +2.483125000000000426e+01 +2.484375000000000355e+01 +2.485625000000000284e+01 +2.486875000000000213e+01 +2.488125000000000497e+01 +2.489375000000000426e+01 +2.490625000000000355e+01 +2.491875000000000284e+01 +2.493125000000000213e+01 +2.494375000000000497e+01 +2.495625000000000426e+01 +2.496875000000000355e+01 +2.498125000000000284e+01 +2.499375000000000213e+01 +2.500625000000000497e+01 +2.501875000000000426e+01 +2.503125000000000355e+01 +2.504375000000000284e+01 +2.505625000000000213e+01 +2.506875000000000497e+01 +2.508125000000000426e+01 +2.509375000000000355e+01 +2.510625000000000284e+01 +2.511875000000000213e+01 diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/edge_potential.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/edge_potential.py new file mode 100644 index 00000000..b50b3bf5 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/edge_potential.py @@ -0,0 +1,161 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 12, 7.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +# Left needs to be near source, right sensor near drain +sensor_1_left_start = 5.5 # um +sensor_1_left_end = 10.0 # um + +sensor_1_right_start = 5.5 # um +sensor_1_right_end = 10.0 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +sensor_2_left_start = 6.5 # um +sensor_2_left_end = 7.5 # um + +sensor_2_right_start = 6.5 # um +sensor_2_right_end = 7.5 # um + +sensor_2_left_indices = (q2 > sensor_2_left_start ) & (q2 < sensor_2_left_end) +sensor_2_right_indices = (q2 > sensor_2_right_start) & (q2 < sensor_2_right_end) + +filepath = \ +'/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_1.0_tau_ee_0.2_tau_eph_0.5/dumps' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +sensor_1_signal_array = [] +#sensor_2_signal_array = [] +#print("Reading sensor signal...") +print("Loading data...") +density = [] +edge_density = [] +for file_number, dump_file in enumerate(moment_files): + + print("File number = ", file_number, ' of ', moment_files.size) + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + density.append(moments[:, :, 0]) + edge_density.append(density[file_number][0, sensor_1_left_indices]) + +density = np.array(density) +edge_density = np.array(edge_density) + +mean_density = np.mean(density) +max_density = np.max(density) +min_density = np.min(density) + +np.savetxt("edge_density.txt", edge_density) + +print("Dumping data...") +for file_number in yt.parallel_objects(range(density.shape[0])): + + print("File number = ", file_number, ' of ', moment_files.size) + + pl.semilogy(q2[sensor_1_left_indices], + density[file_number][0, sensor_1_left_indices], + ) + #pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.title(r'Time = ' + "%.2f"%(file_number*dt*dump_interval) + " ps") + + pl.xlim([sensor_1_left_start, sensor_1_left_end]) + #pl.ylim([min_density-mean_density, max_density-mean_density]) + #pl.ylim([0., np.log(max_density)]) + + #pl.gca().set_aspect('equal') + #pl.xlabel(r'$x\;(\mu \mathrm{m})$') + #pl.ylabel(r'$y\;(\mu \mathrm{m})$') + + #pl.suptitle('$\\tau_\mathrm{mc} = \infty$ ps, $\\tau_\mathrm{mr} = 3.0$ ps') + #pl.savefig('images/dump_' + '%06d'%file_number + '.png') + pl.savefig('images/density_' + '%06d'%file_number + '.png') + pl.clf() + + + diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/enstrophy.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/enstrophy.py new file mode 100644 index 00000000..aeab5a28 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/enstrophy.py @@ -0,0 +1,142 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +filepath = \ +'/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_1.0_tau_ee_0.2_tau_eph_0.5/dumps' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +kinetic_energy_array = [] +enstrophy_array = [] +print("Reading kinetic energy and enstrophy signals...") +for file_number, dump_file in enumerate(moment_files): + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + + h5f = h5py.File(lagrange_multiplier_files[file_number], 'r') + lagrange_multipliers = h5f['lagrange_multipliers'][:] + h5f.close() + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + + dq1 = (domain.q1_end - domain.q1_start)/domain.N_q1 + dq2 = (domain.q2_end - domain.q2_start)/domain.N_q2 + + dvx_dx, dvx_dy = np.gradient(j_x/density, dq1, dq2) + dvy_dx, dvy_dy = np.gradient(j_y/density, dq1, dq2) + + vorticity = dvy_dx - dvx_dy + + kinetic_energy = 0.5 * np.sum(vel_drift_x**2 + vel_drift_y**2) * dq1 * dq2 + kinetic_energy_array.append(kinetic_energy) + + enstrophy = np.sum(vorticity**2) * dq1 * dq2 + enstrophy_array.append(enstrophy) + +time_array = np.loadtxt("dump_time_array.txt") +half_time = (int)(time_array.size/2) + +kinetic_energy_normalized = \ + kinetic_energy_array/np.max(np.abs(kinetic_energy_array[half_time:])) +enstrophy_normalized = \ + enstrophy_array/np.max(np.abs(enstrophy_array[half_time:])) + + +pl.plot(time_array, kinetic_energy_normalized) +pl.plot(time_array, enstrophy_normalized) +pl.axhline(0, color='black', linestyle='--') + +pl.legend(['Kinetic Energy', 'Enstrophy'], loc=1) +pl.xlabel(r'Time (ps)') +pl.xlim([0, 200]) +pl.ylim([-0.1, 1.1]) + +pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 1.0$ ps') +pl.savefig('vorticity_images/iv' + '.png') +pl.clf() + + diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/fft.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/fft.py new file mode 100644 index 00000000..88fd9e17 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/fft.py @@ -0,0 +1,177 @@ +print ("Execution started, loading libs...") + +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import os +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +#import yt +#yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain +import boundary_conditions +import params +import initialize + + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +#from bolt.lib.physical_system import physical_system + +#from bolt.lib.nonlinear_solver.nonlinear_solver \ +# import nonlinear_solver +#from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ +# import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +#import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +#import bolt.src.electronic_boltzmann.collision_operator \ +# as collision_operator + +#import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 12, 7.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +print ("Loaded libs") + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 + +p1 = domain.p1_start[0] + (0.5 + np.arange(N_p1)) * (domain.p1_end[0] - \ + domain.p1_start[0])/N_p1 +p2 = domain.p2_start[0] + (0.5 + np.arange(N_p2)) * (domain.p2_end[0] - \ + domain.p2_start[0])/N_p2 + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +probe_1_indices = (q2 < source_end) + + +#Dump files +filepath = '.' +moment_files = np.sort(glob.glob(filepath+'/dump_moments/*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/dump_lagrange_multipliers/*.bin')) + + +print ("Moment files size : ", moment_files.size) +skip_files = 60000 + +moment_files = moment_files[skip_files:] +lagrange_multiplier_files = lagrange_multiplier_files[skip_files:] + +dt = params.dt +dump_interval = params.dump_steps + +#time_array = np.loadtxt("dump_time_array.txt") + +time_array = dump_interval * dt * np.arange(0, moment_files.size, 1) + +io = PetscBinaryIO.PetscBinaryIO() + +left_edge_density = [] +right_edge_density = [] +left_edge_current = [] + +for file_number, dump_file in enumerate(moment_files): + + dump_file = moment_files[file_number] + print (dump_file) + + moments = io.readBinaryFile(dump_file) + moments = moments[0].reshape(N_q2, N_q1, 3) + + print("file number = ", file_number, "of ", moment_files.size, "shape = ", moments.shape) + + density = moments[:, :, 0] + + + left_edge_density.append(density[:, 0]) + right_edge_density.append(density[:, -1]) + + +# lagrange_multipliers = \ +# io.readBinaryFile(lagrange_multiplier_files[file_number]) +# lagrange_multipliers = lagrange_multipliers[0].reshape(N_q2, N_q1, 7) + +# print("file number = ", file_number, "of ", lagrange_multiplier_files.size, +# "shape = ", lagrange_multipliers.shape) + +# j_x = lagrange_multipliers[:, :, 5] +# j_y = lagrange_multipliers[:, :, 6] + +# j_mag = (j_x**2. + j_y**2.)**0.5 + +# left_edge_current.append(j_mag[:, 0]) + + +voltage_left = np.array(left_edge_density) +voltage_right = np.array(right_edge_density) +#current_left = np.array(left_edge_current) + +print("Left : ", voltage_left.shape) + +np.savez_compressed("voltages_L_1.0_5.25_tau_ee_inf_tau_eph_inf.txt", + left=voltage_left, right=voltage_right) +#np.savez_compressed('current_L_1.0_5.25_tau_ee_inf_tau_eph_inf.txt', +# current=current_left) + diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/initialize.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/initialize.py new file mode 100644 index 00000000..fb8e8c88 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/initialize.py @@ -0,0 +1,67 @@ +""" +Functions which are used in assigning the I.C's to +the system. +""" + +import arrayfire as af +import numpy as np +from petsc4py import PETSc + +def initialize_f(q1, q2, p1, p2, p3, params): + + PETSc.Sys.Print("Initializing f") + k = params.boltzmann_constant + + params.mu = 0.*q1 + params.initial_mu + params.T = 0.*q1 + params.initial_temperature + params.vel_drift_x = 0.*q1 + params.vel_drift_y = 0.*q1 + params.phi = 0.*q1 + + params.mu_ee = params.mu.copy() + params.T_ee = params.T.copy() + params.vel_drift_x = 0.*q1 + 0e-3 + params.vel_drift_y = 0.*q1 + 0e-3 + params.j_x = 0.*q1 + params.j_y = 0.*q1 + + params.E_band = params.band_energy(p1, p2) + params.vel_band = params.band_velocity(p1, p2) + + E_upper = params.E_band + params.charge[0]*params.phi + + if (params.p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (params.p_space_grid == 'polar2D'): + p_x = p1 * af.cos(p2) + p_y = p1 * af.sin(p2) + else: + raise NotImplementedError('Unsupported coordinate system in p_space') + + f = (1./(af.exp( (E_upper - params.vel_drift_x*p_x + - params.vel_drift_y*p_y + - params.mu + )/(k*params.T) + ) + 1. + )) + + af.eval(f) + return(f) + + +def initialize_E(q1, q2, params): + + E1 = 0.*q1 + E2 = 0.*q1 + E3 = 0.*q1 + + return(E1, E2, E3) + +def initialize_B(q1, q2, params): + + B1 = 0.*q1 + B2 = 0.*q1 + B3 = 0.*q1 + + return(B1, B2, B3) diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/job_script b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/job_script new file mode 100644 index 00000000..75c49d28 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/job_script @@ -0,0 +1,4 @@ +#!/bin/bash +#SBATCH -p gpu -n 4 --gres=gpu:4 -c1 --hint=nomultithread -t 2-00:00 +# (Note: use one MPI process per gpu, update both gres and -n together; max 6) +time mpirun python main.py -snes_monitor -snes_max_it 1 -snes_lag_jacobian_persists TRUE -snes_lag_jacobian 1000000 -snes_atol 1e-50 -snes_rtol 1e-50 > output.txt diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/main.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/main.py new file mode 100644 index 00000000..53340b02 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/main.py @@ -0,0 +1,173 @@ +import os +import arrayfire as af +import numpy as np +import math +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +from mpi4py import MPI +MPI.WTIME_IS_GLOBAL=True + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear.nonlinear_solver \ + import nonlinear_solver +#from bolt.lib.nonlinear.fields.fields.fields \ +# import fields_solver.compute_electrostatic_fields +from bolt.lib.utils.restart_latest import latest_output, format_time + +import domain +import boundary_conditions +import initialize +import params + +import bolt.src.electronic_boltzmann.advection_terms \ + as advection_terms +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator +import bolt.src.electronic_boltzmann.moment_defs \ + as moment_defs + + +# Create required folders if they do not exist already +#if not os.path.isdir("dump_f"): +# os.system("mkdir dump_f") +#if not os.path.isdir("dump_moments"): +# os.system("mkdir dump_moments") +#if not os.path.isdir("dump_lagrange_multipliers"): +# os.system("mkdir dump_lagrange_multipliers") +#if not os.path.isdir("images"): +# os.system("mkdir images") + + +# Defining the physical system to be solved: +system = physical_system(domain, + boundary_conditions, + params, + initialize, + advection_terms, + collision_operator.RTA, + moment_defs + ) + +# Declaring a nonlinear system object which will evolve the defined physical system: +nls = nonlinear_solver(system) +N_g = domain.N_ghost +params.rank = nls._comm.rank + +# Time parameters: +dt = params.dt +t_final = params.t_final +params.current_time = t0 = 0.0 +params.time_step = time_step = 0 +dump_counter = 0 +dump_time_array = [] + + +using_latest_restart = False +if(params.latest_restart == True): + latest_f, time_elapsed = latest_output('') + print("Latest restart time elapsed : ", time_elapsed, latest_f) + if(latest_f is not None and time_elapsed is not None): + nls.load_distribution_function(latest_f) + using_latest_restart = True + + +if using_latest_restart == False: + if(params.t_restart == 0 or params.latest_restart == True): + time_elapsed = 0 + formatted_time = format_time(time_elapsed) + nls.dump_distribution_function('dump_f/t=' + formatted_time) + nls.dump_moments('dump_moments/t=' + formatted_time) + nls.dump_aux_arrays([params.mu, + params.mu_ee, + params.T_ee, + params.vel_drift_x, params.vel_drift_y, + params.j_x, params.j_y], + 'lagrange_multipliers', + 'dump_lagrange_multipliers/t=' + formatted_time + ) + else: + time_elapsed = params.t_restart + formatted_time = format_time(time_elapsed) + nls.load_distribution_function('dump_f/t=' + formatted_time) + +# Checking that the file writing intervals are greater than dt: +assert(params.dt_dump_f > dt) +assert(params.dt_dump_moments > dt) +assert(params.dt_dump_fields > dt) + + +#if (params.restart): +# nls.load_distribution_function(params.restart_file) + +density = nls.compute_moments('density') +print("rank = ", params.rank, "\n", + " = ", af.mean(params.mu[0, 0, N_g:-N_g, N_g:-N_g]), "\n", + " max(mu) = ", af.max(params.mu[0, 0, N_g:-N_g, N_g:-N_g]), "\n", + " = ", af.mean(density[0, 0, N_g:-N_g, N_g:-N_g]), "\n", + " max(n) = ", af.max(density[0, 0, N_g:-N_g, N_g:-N_g]), "\n" + ) + +nls.f = af.select(nls.f < 1e-20, 1e-20, nls.f) +while(time_elapsed < t_final): + + # Refine to machine error + if (time_step==0): + params.collision_nonlinear_iters = 10 + else: + params.collision_nonlinear_iters = params.collision_operator_nonlinear_iters + + dump_steps = params.dump_steps + + if(params.dt_dump_moments != 0): + # We step by delta_dt to get the values at dt_dump + delta_dt = (1 - math.modf(time_elapsed/params.dt_dump_moments)[0]) \ + * params.dt_dump_moments + + print ("delta_dt - dt : ", delta_dt, dt) + + if((delta_dt-dt)<1e-5): + nls.strang_timestep(delta_dt) + time_elapsed += delta_dt + formatted_time = format_time(time_elapsed) + dump_time_array.append(params.current_time) + PETSc.Sys.Print("=====================================================") + PETSc.Sys.Print("Dumping data at time step =", time_step) + PETSc.Sys.Print("=====================================================") + if (params.rank==0): + np.savetxt("dump_time_array.txt", dump_time_array) + nls.dump_moments('dump_moments/t=' + formatted_time) + nls.dump_aux_arrays([params.mu, + params.mu_ee, + params.T_ee, + params.vel_drift_x, params.vel_drift_y, + params.j_x, params.j_y], + 'lagrange_multipliers', + 'dump_lagrange_multipliers/t=' + formatted_time + ) + + if(math.modf(time_elapsed/params.dt_dump_f)[0] < 1e-12): + formatted_time = format_time(time_elapsed) + nls.dump_distribution_function('dump_f/t=' + formatted_time) + + PETSc.Sys.Print("Time step =", time_step, ", Time =", time_elapsed) + + nls.strang_timestep(dt) + time_elapsed = time_elapsed + dt + time_step = time_step + 1 + params.time_step = time_step + params.current_time = time_elapsed + + # Floors + nls.f = af.select(nls.f < 1e-20, 1e-20, nls.f) + + density = nls.compute_moments('density') + print("rank = ", params.rank, "\n", + " = ", af.mean(params.mu[0, 0, N_g:-N_g, N_g:-N_g]), "\n", + " max(mu) = ", af.max(params.mu[0, 0, N_g:-N_g, N_g:-N_g]), "\n", + " = ", af.mean(density[0, 0, N_g:-N_g, N_g:-N_g]), "\n", + " max(n) = ", af.max(density[0, 0, N_g:-N_g, N_g:-N_g]), "\n" + ) + PETSc.Sys.Print("--------------------\n") + +nls.dump_distribution_function('dump_f/f_laststep') diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/momentum_space_movie.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/momentum_space_movie.py new file mode 100644 index 00000000..1de644d7 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/momentum_space_movie.py @@ -0,0 +1,134 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import os +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1_start = domain.q1_start +q1_end = domain.q1_end +q2_start = domain.q2_start +q2_end = domain.q2_end + +q1 = q1_start + (0.5 + np.arange(N_q1)) * (q1_end - q1_start)/N_q1 +q2 = q2_start + (0.5 + np.arange(N_q2)) * (q2_end - q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 + +p1_start = domain.p1_start +p1_end = domain.p1_end +p2_start = domain.p2_start +p2_end = domain.p2_end + +p1 = p1_start[0] + (0.5 + np.arange(N_p1)) * (p1_end[0] - p1_start[0])/N_p1 +p2 = p2_start[0] + (0.5 + np.arange(N_p2)) * (p2_end[0] - p2_start[0])/N_p2 + +p1_meshgrid, p2_meshgrid = np.meshgrid(p1, p2) + +p_x = p1_meshgrid * np.cos(p2_meshgrid) +p_y = p1_meshgrid * np.sin(p2_meshgrid) + +#p2_meshgrid, p1_meshgrid = np.meshgrid(p2, p1) + +io = PetscBinaryIO.PetscBinaryIO() + +filepath = os.getcwd() + "/dumps" +moment_files = np.sort(glob.glob(filepath+'/moment*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) +dist_func_files = np.sort(glob.glob(filepath+'/f_*.bin')) + +dist_func_bg_file = dist_func_files[0] +dist_func_file = dist_func_files[-1] + +dist_func_background = io.readBinaryFile(dist_func_bg_file) +#dist_func_background = dist_func_background[0].reshape(N_q2, N_q1, N_p2, N_p1) +dist_func_background = dist_func_background[0].reshape(N_q1, N_q2, 1, 1, N_p2, N_p1) +dist_func = io.readBinaryFile(dist_func_file) + +print (dist_func[0].shape) + +dist_func = dist_func[0].reshape(N_q1, N_q2, 1, 1, N_p2, N_p1) + + +N = 7 +for index_1 in range(N): + for index_2 in range(N): + + q1_position = int(N_q1*((index_1/N)+(1/(2*N)))) + q2_position = int(N_q2*((index_2/N)+(1/(2*N)))) + + #a = np.max((dist_func - dist_func_background)[q2_position, q1_position, :, :]) + #b = np.abs(np.min((dist_func - dist_func_background)[q2_position, q1_position, :, :])) + #norm_factor = np.maximum(a, b) + #f_at_desired_q = \ + # np.reshape((dist_func-dist_func_background)[q2_position, q1_position, :, :], + # [N_p2, N_p1])/norm_factor + + f_at_desired_q = np.reshape((dist_func - \ + dist_func_background)[q1_position, q2_position, :], + [N_p2, N_p1] + ) + pl.contourf(p1_meshgrid, p2_meshgrid, f_at_desired_q, 100, cmap='bwr') + + #np.savetxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2), f_at_desired_q) + #f = np.loadtxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2)) + + + #pl.contourf(p_x, p_y, f_at_desired_q, 100, cmap='bwr') + #pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.xlabel('$p_x$') + pl.ylabel('$p_y$') + pl.gca().set_aspect('equal') + pl.savefig('images/dist_func_at_a_point_%d_%d.png'%(index_1, index_2)) + pl.clf() + diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/momentum_space_movie_zero_T.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/momentum_space_movie_zero_T.py new file mode 100644 index 00000000..74a2cdcb --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/momentum_space_movie_zero_T.py @@ -0,0 +1,160 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import os +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain +import params + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_s = len(params.mass) # Number of species + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1_start = domain.q1_start +q1_end = domain.q1_end +q2_start = domain.q2_start +q2_end = domain.q2_end + +q1 = q1_start + (0.5 + np.arange(N_q1)) * (q1_end - q1_start)/N_q1 +q2 = q2_start + (0.5 + np.arange(N_q2)) * (q2_end - q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 +N_p3 = domain.N_p3 + +p1_start = domain.p1_start +p1_end = domain.p1_end +p2_start = domain.p2_start +p2_end = domain.p2_end + +p1 = p1_start[0] + (0.5 + np.arange(N_p1)) * (p1_end[0] - p1_start[0])/N_p1 +p2 = p2_start[0] + (0.5 + np.arange(N_p2)) * (p2_end[0] - p2_start[0])/N_p2 + +p1_meshgrid, p2_meshgrid = np.meshgrid(p1, p2) + +p_x = p1_meshgrid * np.cos(p2_meshgrid) +p_y = p1_meshgrid * np.sin(p2_meshgrid) + +#p2_meshgrid, p1_meshgrid = np.meshgrid(p2, p1) + +io = PetscBinaryIO.PetscBinaryIO() + +filepath = os.getcwd() + "/dumps" +moment_files = np.sort(glob.glob(filepath+'/moment*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) +dist_func_files = np.sort(glob.glob(filepath+'/f_*.bin')) + +dist_func_bg_file = dist_func_files[0] +dist_func_file = dist_func_files[-1] + +dist_func_background = io.readBinaryFile(dist_func_bg_file) +#dist_func_background = dist_func_background[0].reshape(N_q2, N_q1, N_p2, N_p1) +dist_func_background = dist_func_background[0].reshape(N_q1, N_q2, N_s, N_p3, N_p2, N_p1) +dist_func = io.readBinaryFile(dist_func_file) + +print (dist_func[0].shape) + +dist_func = dist_func[0].reshape(N_q1, N_q2, N_s, N_p3, N_p2, N_p1) + + +N = 7 +for index_1 in range(N): + for index_2 in range(N): + + q1_position = int(N_q1*((index_1/N)+(1/(2*N)))) + q2_position = int(N_q2*((index_2/N)+(1/(2*N)))) + + a = np.max((dist_func - dist_func_background)[q1_position, q2_position, :, :]) + b = np.abs(np.min((dist_func - dist_func_background)[q1_position, q2_position, :, :])) + norm_factor = np.maximum(a, b) + f_at_desired_q = \ + np.reshape((dist_func-\ + dist_func_background)[q1_position, q2_position, :, :],\ + [N_p2, N_p1])/norm_factor + + np.savetxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2), f_at_desired_q) + f = np.loadtxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2)) + + #f_at_desired_q = np.reshape((dist_func - \ + # dist_func_background)[q1_position, q2_position, :], + # [N_p2, N_p1] + # ) + + print ("f at desired q : ", dist_func[q1_position, q2_position, :].shape) + print ("norm : ", norm_factor) + + + radius = f.copy() + theta = p2.copy() + + x = (radius + 5.)*np.cos(theta) + y = (radius + 5.)*np.sin(theta) + + x_bg = 5*np.cos(theta) + y_bg = 5*np.sin(theta) + + print ('p2 : ', p2.shape) + #pl.plot(p2, f_at_desired_q) + pl.plot(x, y, color='r', linestyle = '-', lw=2) + pl.plot(x_bg, y_bg, color='k', alpha=0.4, lw=2) + #pl.contourf(p1_meshgrid, p2_meshgrid, f_at_desired_q, 100, cmap='bwr') + + #np.savetxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2), f_at_desired_q) + #f = np.loadtxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2)) + + + #pl.contourf(p_x, p_y, f_at_desired_q, 100, cmap='bwr') + #pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.xlabel('$p_x$') + pl.ylabel('$p_y$') + #pl.gca().set_aspect('equal') + pl.savefig('images/dist_func_at_a_point_%d_%d.png'%(index_1, index_2)) + pl.clf() + diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/movie.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/movie.py new file mode 100644 index 00000000..98c072e5 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/movie.py @@ -0,0 +1,188 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import os +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +from matplotlib import transforms, colors +matplotlib.use('agg') +import pylab as pl +#import yt +#yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain +import boundary_conditions +import params +import initialize + + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 + +p1 = domain.p1_start[0] + (0.5 + np.arange(N_p1)) * (domain.p1_end[0] - \ + domain.p1_start[0])/N_p1 +p2 = domain.p2_start[0] + (0.5 + np.arange(N_p2)) * (domain.p2_end[0] - \ + domain.p2_start[0])/N_p2 + +print ('Momentum space : ', p1[-1], p2[int(N_p2/2)]) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +# Left needs to be near source, right sensor near drain +sensor_1_left_start = 8.5 # um +sensor_1_left_end = 9.5 # um + +sensor_1_right_start = 8.5 # um +sensor_1_right_end = 9.5 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +sensor_2_left_start = 6.5 # um +sensor_2_left_end = 7.5 # um + +sensor_2_right_start = 6.5 # um +sensor_2_right_end = 7.5 # um + +sensor_2_left_indices = (q2 > sensor_2_left_start ) & (q2 < sensor_2_left_end) +sensor_2_right_indices = (q2 > sensor_2_right_start) & (q2 < sensor_2_right_end) + +#filepath = \ +#'/home/mchandra/gitansh/bolt_master/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/dumps' +filepath = "." +moment_files = np.sort(glob.glob(filepath+'/dump_moments/*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/dump_lagrange_multipliers/*.bin')) + +print ("moment files : ", moment_files.size) +print ("lagrange multiplier files : ", lagrange_multiplier_files.size) + +dt = params.dt +dump_interval = params.dump_steps + +time_array = np.loadtxt("dump_time_array.txt") + +io = PetscBinaryIO.PetscBinaryIO() + +for file_number, dump_file in enumerate(moment_files): + + file_number = -1 + print("file number = ", file_number, "of ", moment_files.size) + + moments = io.readBinaryFile(moment_files[file_number]) + moments = moments[0].reshape(N_q2, N_q1, 3) + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + + lagrange_multipliers = \ + io.readBinaryFile(lagrange_multiplier_files[file_number]) + lagrange_multipliers = lagrange_multipliers[0].reshape(N_q2, N_q1, 7) + #h5f = h5py.File(lagrange_multiplier_files[file_number], 'r') + #lagrange_multipliers = h5f['lagrange_multipliers'][:] + #h5f.close() + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 5] + vel_drift_y = lagrange_multipliers[:, :, 6] + + print (vel_drift_x.shape) + print (density.shape) + + l = 5.25 + pl.figure(figsize=(7.5*1.5, 1.5*25.0*l/6.5)) + base = pl.gca().transData + rot = transforms.Affine2D().rotate_deg(0) + + delta_n = density - np.mean(density) + + pl.contourf(q1, q2, delta_n, 200, + norm=colors.SymLogNorm(linthresh=delta_n.max()/20), cmap='bwr', + transform = rot + base) + + pl.streamplot(q1, q2, vel_drift_x, vel_drift_y, + density=1.4*l, color='black', + linewidth=1, arrowsize=1.5, transform = rot + base + ) + + pl.yticks([0, 5.]) + pl.xticks([]) + + pl.xlim([q1[0], q1[-1]]) + pl.ylim([q2[0], q2[-1]]) + + pl.gca().set_aspect('equal') + + #pl.contourf(q1_meshgrid, q2_meshgrid, density.T, 100, cmap='bwr') + #pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + #pl.streamplot(q1, q2, + # vel_drift_x, vel_drift_y, + # density=2, color='k', + # linewidth=0.7, arrowsize=1 + # ) + + #pl.xlim([q1[0], q1[-1]]) + #pl.ylim([q2[0], q2[-1]]) + + #pl.gca().set_aspect('equal') + #pl.xlabel(r'$x\;(\mu \mathrm{m})$') + #pl.ylabel(r'$y\;(\mu \mathrm{m})$') + #pl.suptitle('$\\tau_\mathrm{mc} = \infty$, $\\tau_\mathrm{mr} = \infty$') + pl.savefig('images/dump_' + '%06d'%file_number + '.png') + pl.clf() + diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/params.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/params.py new file mode 100644 index 00000000..cdc54d17 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/params.py @@ -0,0 +1,174 @@ +import numpy as np +import arrayfire as af + +instantaneous_collisions = False #TODO : Remove from lib +hybrid_model_enabled = False #TODO : Remove from lib +source_enabled = True +disable_collision_op = False + +fields_enabled = False +# Can be defined as 'electrostatic', 'user-defined'. +# The initial conditions need to be specified under initialize +# Ensure that the initial conditions specified satisfy +# Maxwell's constraint equations +fields_initialize = 'user-defined' + +# Can be defined as 'electrostatic' and 'fdtd' +# To turn feedback from Electric fields on, set fields_solver = 'LCA' +# and set charge_electron +fields_type = 'electrostatic' +fields_solver = 'SNES' + +# Can be defined as 'strang' and 'lie' +time_splitting = 'strang' + +# Method in q-space +solver_method_in_q = 'FVM' +solver_method_in_p = 'FVM' + +reconstruction_method_in_q = 'minmod' +reconstruction_method_in_p = 'minmod' + +riemann_solver_in_q = 'upwind-flux' +riemann_solver_in_p = 'upwind-flux' + +# Restart(Set to zero for no-restart): +restart = 0 +restart_file = '/home/mani/work/quazar_research/bolt/example_problems/electronic_boltzmann/graphene/dumps/f_eqbm.h5' +phi_restart_file = '/home/mani/work/quazar_research/bolt/example_problems/electronic_boltzmann/graphene/dumps/phi_eqbm.h5' +electrostatic_solver_every_nth_step = 1000000 +solve_for_equilibrium = 0 + + +# Time parameters: +dt = 0.025/4 # ps +t_final = 5000. # ps + +# File-writing Parameters: +dump_steps = 1 +# Set to zero for no file-writing +dt_dump_f = 100*dt #ps +# ALWAYS set dump moments and dump fields at same frequency: +dt_dump_moments = dt_dump_fields = 5*dt #ps + +# Dimensionality considered in velocity space: +p_dim = 1 +p_space_grid = 'polar2D' # Supports 'cartesian' or 'polar2D' grids +# Set p-space start and end points accordingly in domain.py + +# Number of devices(GPUs/Accelerators) on each node: +num_devices = 4 + +# Constants: +mass_particle = 0.910938356 # x 1e-30 kg +h_bar = 1.0545718e-4 # x aJ ps +boltzmann_constant = 1 +charge = [0.*-0.160217662] # x aC +mass = [0.] #TODO : Not used in electronic_boltzmann + # Remove from lib +speed_of_light = 300. # x [um/ps] +fermi_velocity = speed_of_light/300 +epsilon0 = 8.854187817 # x [aC^2 / (aJ um) ] + +epsilon_relative = 3.9 # SiO2 +backgate_potential = -10 # V +global_chem_potential = 0.03 +contact_start = 0.0 # um +contact_end = 0.25 # um +contact_geometry = "straight" # Contacts on either side of the device + # For contacts on the same side, use + # contact_geometry = "turn_around" + +initial_temperature = 12e-5 +initial_mu = 0.015 +vel_drift_x_in = 1e-3*fermi_velocity +vel_drift_x_out = 1e-3*fermi_velocity +AC_freq = 1./100 # ps^-1 + +B3_mean = 1. # T + +# Spatial quantities (will be initialized to shape = [q1, q2] in initalize.py) +mu = None # chemical potential used in the e-ph operator +T = None # Electron temperature used in the e-ph operator +mu_ee = None # chemical potential used in the e-e operator +T_ee = None # Electron temperature used in the e-e operator +vel_drift_x = None +vel_drift_y = None +j_x = None +j_y = None +phi = None # Electric potential in the plane of graphene sheet + +# Momentum quantities (will be initialized to shape = [p1*p2*p3] in initialize.py) +E_band = None +vel_band = None + +collision_operator_nonlinear_iters = 2 + +latest_restart = True +t_restart = 0 + +# Variation of collisional-timescale parameter through phase space: +@af.broadcast +def tau_defect(q1, q2, p1, p2, p3): + return(np.inf * q1**0 * p1**0) + +@af.broadcast +def tau_ee(q1, q2, p1, p2, p3): + return(np.inf * q1**0 * p1**0) + +def tau(q1, q2, p1, p2, p3): + return(tau_defect(q1, q2, p1, p2, p3)) + +def band_energy(p1, p2): + + if (p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (p_space_grid == 'polar2D'): + p_x = p1 * af.cos(p2) + p_y = p1 * af.sin(p2) + else : + raise NotImplementedError('Unsupported coordinate system in p_space') + + p = af.sqrt(p_x**2. + p_y**2.) + + E_upper = p*fermi_velocity + + af.eval(E_upper) + return(E_upper) + +def band_velocity(p1, p2): + + if (p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (p_space_grid == 'polar2D'): + p_x = p1 * af.cos(p2) + p_y = p1 * af.sin(p2) + else : + raise NotImplementedError('Unsupported coordinate system in p_space') + + p = af.sqrt(p_x**2. + p_y**2.) + p_hat = [p_x / (p + 1e-20), p_y / (p + 1e-20)] + + v_f = fermi_velocity + + upper_band_velocity = [ v_f * p_hat[0], v_f * p_hat[1]] + + af.eval(upper_band_velocity[0], upper_band_velocity[1]) + return(upper_band_velocity) + +@af.broadcast +def fermi_dirac(mu, E_band): + + k = boltzmann_constant + T = initial_temperature + + f = (1./(af.exp( (E_band - mu + )/(k*T) + ) + 1. + ) + ) + + af.eval(f) + return(f) diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/petsc_conf.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/petsc_conf.py new file mode 100644 index 00000000..fe935a3c --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/petsc_conf.py @@ -0,0 +1,74 @@ +import warnings + +def get_conf(): + """Parses various PETSc configuration/include files to get data types. + + precision, indices, complexscalars = get_conf() + + Output: + precision: 'single', 'double', 'longlong' indicates precision of PetscScalar + indices: '32', '64' indicates bit-size of PetscInt + complex: True/False indicates whether PetscScalar is complex or not. + """ + + import sys, os + precision = None + indices = None + complexscalars = None + + if 'PETSC_DIR' in os.environ: + petscdir = os.environ['PETSC_DIR'] + else: + warnings.warn('PETSC_DIR env not set - unable to locate PETSc installation, using defaults') + return None, None, None + + if os.path.isfile(os.path.join(petscdir,'lib','petsc','conf','petscrules')): + # found prefix install + petscvariables = os.path.join(petscdir,'lib','petsc','conf','petscvariables') + petscconfinclude = os.path.join(petscdir,'include','petscconf.h') + else: + if 'PETSC_ARCH' in os.environ: + petscarch = os.environ['PETSC_ARCH'] + if os.path.isfile(os.path.join(petscdir,petscarch,'lib','petsc','conf','petscrules')): + # found legacy install + petscvariables = os.path.join(petscdir,petscarch,'lib','petsc','conf','petscvariables') + petscconfinclude = os.path.join(petscdir,petscarch,'include','petscconf.h') + else: + warnings.warn('Unable to locate PETSc installation in specified PETSC_DIR/PETSC_ARCH, using defaults') + return None, None, None + else: + warnings.warn('PETSC_ARCH env not set or incorrect PETSC_DIR is given - unable to locate PETSc installation, using defaults') + return None, None, None + + try: + fid = open(petscvariables, 'r') + except IOError: + warnings.warn('Nonexistent or invalid PETSc installation, using defaults') + return None, None, None + else: + for line in fid: + if line.startswith('PETSC_PRECISION'): + precision = line.strip().split('=')[1].strip('\n').strip() + + fid.close() + + try: + fid = open(petscconfinclude, 'r') + except IOError: + warnings.warn('Nonexistent or invalid PETSc installation, using defaults') + return None, None, None + else: + for line in fid: + if line.startswith('#define PETSC_USE_64BIT_INDICES 1'): + indices = '64bit' + elif line.startswith('#define PETSC_USE_COMPLEX 1'): + complexscalars = True + + if indices is None: + indices = '32bit' + if complexscalars is None: + complexscalars = False + fid.close() + + return precision, indices, complexscalars + diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/phase_vs_y.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/phase_vs_y.py new file mode 100644 index 00000000..fc6ac364 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/phase_vs_y.py @@ -0,0 +1,180 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +from scipy.optimize import curve_fit +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 12, 7.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +def sin_curve_fit(t, A, tau): + return A*np.sin(2*np.pi*AC_freq*(t + tau )) + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +# Left needs to be near source, right sensor near drain +sensor_1_left_start = 5.5 # um +sensor_1_left_end = 10.0 # um + +sensor_1_right_start = 5.5 # um +sensor_1_right_end = 10.0 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +filepath = \ + '/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_2.5_tau_ee_inf_tau_eph_2.5/dumps' + +AC_freq = 1./100.0 +time_period = 1/AC_freq +t_final = params.t_final +transient_time = t_final/2. + +time = np.loadtxt(filepath + "/../dump_time_array.txt") +edge_density = np.loadtxt(filepath + "/../edge_density.txt") +q2 = np.loadtxt(filepath + "/../q2_edge.txt") + +N_spatial = edge_density.shape[1] + +transient_index = int((transient_time/t_final)*time.size) + +drive = np.sin(2*np.pi*AC_freq*time) +nsamples = drive.size +dt_corr = np.linspace(-time[-1] + time[0],\ + time[-1] - time[0], 2*nsamples-1) + +# Discarding transients +q = q2.size/2 +time_half = time[transient_index:] +drive_half = drive[transient_index:] + +# Plotting signals at edge +norm_0 = np.max(edge_density[transient_index:, 0]) +norm_1 = np.max(edge_density[transient_index:, -1]) + +pl.plot(time, drive, color='black', linestyle='--') +pl.ylim([-1.1, 1.1]) +pl.xlim([0,200]) +pl.xlabel('$\mathrm{Time\;(s)}$') + +for i in range(N_spatial): + norm_i = np.max(edge_density[transient_index:, i]) + pl.plot(time, edge_density[:, i]/norm_i) + +pl.savefig('images/signals.png') +pl.clf() + +phase_shift_corr_array = [] +phase_shift_fitting_array = []\ + +for i in range(N_spatial): + print ('index : ', i) + signal_1 = edge_density[:, i] + norm_1 = np.max(signal_1[transient_index:]) + signal_1_normalized = signal_1/norm_1 + + # Calculate phase_shifts using scipy.correlate + corr = correlate(drive, signal_1_normalized) + time_shift_corr = dt_corr[corr.argmax()] + phase_shift_corr = 2*np.pi*(((0.5 + time_shift_corr/time_period) % 1.0) - 0.5) + + # Calculate phase_shifts using scipy.curve_fit + popt, pcov = curve_fit(sin_curve_fit, time[transient_index:],\ + signal_1_normalized[transient_index:]) + time_shift_fitting = popt[1]%(time_period/2.0) + phase_shift_fitting = 2*np.pi*(((0.5 + time_shift_fitting/time_period) % 1.0) - 0.5) + + phase_shift_corr_array.append(phase_shift_corr) + phase_shift_fitting_array.append(phase_shift_fitting) + +phase_shift_corr_array = np.array(phase_shift_corr_array) +phase_shift_fitting_array = np.array(phase_shift_fitting_array) + +# Plot +pl.ylabel('$\mathrm{\phi}$') +pl.xlabel('$\mathrm{y\ \mu m}$') + +pl.plot(q2, phase_shift_corr_array, '-o', label='$\mathrm{corr}$') +pl.plot(q2, phase_shift_fitting_array, '-o', label='$\mathrm{fit}$') + +pl.title('$\mathrm{2.5 \\times 10,\ \\tau_{ee} = \infty,\ \\tau_{eph} = 2.5}$') +pl.legend(loc='best') + +#pl.axvspan(sensor_1_left_start, sensor_1_left_end, color = 'k', alpha = 0.1) +#pl.axvspan(sensor_2_left_start, sensor_2_left_end, color = 'k', alpha = 0.1) + +pl.savefig('images/phase_vs_y.png') +pl.clf() + diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/post.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/post.py new file mode 100644 index 00000000..a297c6f0 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/post.py @@ -0,0 +1,422 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +#pl.rcParams['figure.figsize'] = 8, 7.5 +pl.rcParams['figure.figsize'] = 8, 8 +#pl.rcParams['figure.figsize'] = 17, 9.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +#pl.rcParams['lines.linewidth'] = 3 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 +#N_q1 = 120 +#N_q2 = 240 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +#source_start = 3.5; source_end = 4.5 +#drain_start = 5.5; drain_end = 6.5 + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +sensor_1_left_start = 8.5 # um +sensor_1_left_end = 9.5 # um + +sensor_1_right_start = 8.5 # um +sensor_1_right_end = 9.5 # um + +# Left needs to be near source, right sensor near drain +#sensor_1_left_start = 1.5 # um +#sensor_1_left_end = 2.5 # um + +#sensor_1_right_start = 7.5 # um +#sensor_1_right_end = 8.5 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +sensor_2_left_start = 6.5 # um +sensor_2_left_end = 7.5 # um + +sensor_2_right_start = 6.5 # um +sensor_2_right_end = 7.5 # um + +sensor_2_left_indices = (q2 > sensor_2_left_start ) & (q2 < sensor_2_left_end) +sensor_2_right_indices = (q2 > sensor_2_right_start) & (q2 < sensor_2_right_end) + +#dump_index = 0 +#h5f = h5py.File('dumps/moments_' + '%06d'%(dump_index) + '.h5', 'r') +#moments = np.swapaxes(h5f['moments'][:], 0, 1) +#h5f.close() +# +#density = moments[:, :, 0] +#j_x = moments[:, :, 1] +#j_y = moments[:, :, 2] +#pl.contourf(q1, q2, density, 100) +##pl.title('Time = ' + "%.2f"%(t0)) +#pl.axes().set_aspect('equal') +#pl.xlabel(r'$x$') +#pl.ylabel(r'$y$') +#pl.colorbar() +#pl.savefig('images/density' + '.png') +#pl.clf() +# +#h5f = h5py.File('dumps/lagrange_multipliers_' + '%06d'%(dump_index) + '.h5', 'r') +#lagrange_multipliers = np.swapaxes(h5f['lagrange_multipliers'][:], 0, 1) +#h5f.close() +# +#print("lagrange_multipliers.shape = ", lagrange_multipliers.shape) +#mu = lagrange_multipliers[:, :, 0] +#mu_ee = lagrange_multipliers[:, :, 1] +#T_ee = lagrange_multipliers[:, :, 2] +#vel_drift_x = lagrange_multipliers[:, :, 3] +#vel_drift_y = lagrange_multipliers[:, :, 4] +#j_x_prime = density*vel_drift_x +#print("err = ", np.mean(np.abs(j_x_prime - j_x))) + +#filepath = \ +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/geom_1/DC/tau_D_50_tau_ee_0.2' +#dump_file= np.sort(glob.glob(filepath+'/moment*.h5'))[-1] +# +#h5f = h5py.File(dump_file, 'r') +#moments = np.swapaxes(h5f['moments'][:], 0, 1) +#h5f.close() +# +#density = moments[:, :, 0] +#np.savetxt('paper_plots/density_tau_D_50_tau_ee_0.2.txt', density) +#np.savetxt('paper_plots/q2_DC_tau_D_50_tau_ee_0.2.txt', q2) +##pl.plot(q2[q2>source_end], density[0, q2>source_end]-np.mean(density)) +# +#filepath = \ +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/geom_1/DC/tau_D_5_tau_ee_0.2' +#dump_file= np.sort(glob.glob(filepath+'/moment*.h5'))[-1] +# +# +#h5f = h5py.File(dump_file, 'r') +#moments = np.swapaxes(h5f['moments'][:], 0, 1) +#h5f.close() +# +#density = moments[:, :, 0] +#np.savetxt('paper_plots/density_tau_D_5_tau_ee_0.2.txt', density) +#np.savetxt('paper_plots/q2_DC_tau_D_5_tau_ee_0.2.txt', q2) +# +#filepath = \ +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/geom_1/DC/tau_D_10_tau_ee_0.2' +#dump_file= np.sort(glob.glob(filepath+'/moment*.h5'))[-1] +# +#N_q1 = 120 +#N_q2 = 240 +# +#q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +#q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 +# +#h5f = h5py.File(dump_file, 'r') +#moments = np.swapaxes(h5f['moments'][:], 0, 1) +#h5f.close() +# +#density = moments[:, :, 0] +#np.savetxt('paper_plots/density_tau_D_10_tau_ee_0.2.txt', density) +#np.savetxt('paper_plots/q2_DC_tau_D_10_tau_ee_0.2.txt', q2) + + +#pl.plot(q2[q2>source_end], density[0, q2>source_end]-np.mean(density)) +#pl.axhline(0, color='black', linestyle='--') +#pl.legend(['$\\tau_{ee}=0.2$ ps, $\\tau_{e-ph}=50$ ps', +# '$\\tau_{ee}=0.2$ ps, $\\tau_{e-ph}=10$ ps'], loc='lower right') +#pl.xlabel(r'$x\;(\mu \mathrm{m})$') +#pl.ylabel(r'$R\; (\mathrm{a.u.})$') +#pl.xlim(xmin=(source_end+0.1)) +#pl.savefig('paper_plots/DC.png') + +filepath = \ +'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/dumps_tau_D_1_tau_ee_0.2_movie' +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/geom_1/55_GHz/tau_D_5_tau_ee_0.2' +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/dumps_AC_10_Ghz_tau_D_10_tau_ee_1_geom_2/' +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/dumps_tau_D_2_tau_ee_1_AC/' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +sensor_1_signal_array = [] +print("Reading sensor signal...") +for file_number, dump_file in enumerate(moment_files): + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + density = moments[:, :, 0] + + source = np.mean(density[0, source_indices]) + drain = np.mean(density[-1, drain_indices]) + + sensor_1_left = np.mean(density[0, sensor_1_left_indices] ) + sensor_1_right = np.mean(density[-1, sensor_1_right_indices]) + + sensor_1_signal = sensor_1_left - sensor_1_right + + sensor_1_signal_array.append(sensor_1_signal) + +time_array = np.loadtxt("dump_time_array.txt") +AC_freq = 1./100 +input_signal_array = np.sin(2.*np.pi*AC_freq*time_array) +sensor_1_signal_array = np.array(sensor_1_signal_array) +half_time = (int)(time_array.size/2) +sensor_normalized = \ + sensor_1_signal_array/np.max(np.abs(sensor_1_signal_array[half_time:])) + +pl.rcParams['figure.figsize'] = 10, 8 +for file_number, dump_file in yt.parallel_objects(enumerate(moment_files)): + + print("file number = ", file_number, "of ", moment_files.size) + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + gs = gridspec.GridSpec(3, 2) + pl.subplot(gs[:, 0]) + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + pl.contourf(q1_meshgrid, q2_meshgrid, density, 100, cmap='bwr') + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + #pl.colorbar() + + h5f = h5py.File(lagrange_multiplier_files[file_number], 'r') + lagrange_multipliers = h5f['lagrange_multipliers'][:] + h5f.close() + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + +# pl.streamplot(q1[(int)(N_q1/2):], q2, +# vel_drift_x[:, (int)(N_q1/2):], vel_drift_y[:, (int)(N_q1/2):], +# density=2, color='blue', +# linewidth=0.7, arrowsize=1 +# ) + pl.streamplot(q1, q2, + vel_drift_x, vel_drift_y, + density=2, color='blue', + linewidth=0.7, arrowsize=1 + ) +# pl.streamplot(q1, q2, +# vel_drift_x, vel_drift_y, +# density=3, color='blue', +# linewidth=0.8, arrowsize=1.1 +# ) + pl.xlim([domain.q1_start, domain.q1_end]) + pl.ylim([domain.q2_start, domain.q2_end]) + #pl.ylim([0, 5]) + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + pl.ylabel(r'$y\;(\mu \mathrm{m})$') + + pl.gca().annotate("+", xy=(-0.07, .9), xycoords=("axes fraction"), + ha="center", va="center", size=30, + bbox=dict(fc="white")) + pl.gca().annotate("-", xy=(1.05, .9), xycoords=("axes fraction"), + ha="center", va="center", size=30, + bbox=dict(fc="white", pad=6.5)) + + + pl.subplot(gs[1, 1]) + + pl.plot(time_array, input_signal_array) + pl.plot(time_array, sensor_normalized) + pl.axhline(0, color='black', linestyle='--') + pl.axvline(time_array[file_number], color='black', alpha=0.75) + pl.legend(['Source $I(t)$', 'Measured $V(t)$'], loc=(0.04, 1.125)) + pl.xlabel(r'Time (ps)') + pl.xlim([100, 200]) + pl.ylim([-1.1, 1.1]) + + + pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 1$ ps') + #pl.tight_layout() + pl.savefig('images/dump_' + '%06d'%file_number + '.png') + #pl.savefig('paper_plots/DC.png') + pl.clf() + + +#time_array = [] +#input_signal_array = [] +#sensor_1_signal_array = [] +#sensor_2_signal_array = [] +#for file_number, dump_file in enumerate(moment_files): +# +# print("file number = ", file_number, "of ", moment_files.size) +# +# h5f = h5py.File(dump_file, 'r') +# moments = np.swapaxes(h5f['moments'][:], 0, 1) +# h5f.close() +# +# density = moments[:, :, 0] +# +# source = np.mean(density[0, source_indices]) +# drain = np.mean(density[-1, drain_indices]) +# +# sensor_1_left = np.mean(density[0, sensor_1_left_indices] ) +# sensor_1_right = np.mean(density[-1, sensor_1_right_indices]) +# #sensor_1_right = np.mean(density[0, sensor_1_right_indices]) +# +# sensor_2_left = np.mean(density[0, sensor_2_left_indices] ) +# sensor_2_right = np.mean(density[-1, sensor_2_right_indices]) +# +# #sensor_1_left = density[0, q2>source_end] +# #sensor_1_right = density[-1, q2>source_end] +# +# input_signal = source - drain +# sensor_1_signal = sensor_1_left - sensor_1_right +# sensor_2_signal = sensor_2_left - sensor_2_right +# +# time_array.append(file_number*dt*dump_interval) +# input_signal_array.append(input_signal) +# sensor_1_signal_array.append(sensor_1_signal) +# sensor_2_signal_array.append(sensor_2_signal) +# +##pl.rcParams['figure.figsize'] = 12, 8 +## +#AC_freq = 5.5/100 +#time_array = np.array(time_array) +#input_signal_array = np.sin(2.*np.pi*AC_freq*time_array) +#sensor_1_signal_array = np.array(sensor_1_signal_array) +###np.savetxt('drive.txt', input_signal_array) +##np.savetxt('paper_plots/sensor_tau_ee_0.2_tau_D_5.txt', sensor_1_signal_array) +##np.savetxt('time.txt', time_array) +## +##print("sensor.shape = ", sensor_1_signal_array.shape) +##sensor_2_signal_array = np.array(sensor_2_signal_array) +## +#half_time = (int)(time_array.size/2) +#pl.plot(time_array, input_signal_array/np.max(input_signal_array[half_time:])) +#pl.plot(time_array, +# sensor_1_signal_array/np.max(sensor_1_signal_array[half_time:]) +# ) +##pl.plot(time_array, +## sensor_2_signal_array/np.max(sensor_2_signal_array[half_time:]) +## ) +#pl.xlabel(r"Time (ps)") +#pl.ylim([-1.1, 1.1]) +#pl.legend(['Input', 'Sensor 1', 'Sensor 2']) +#pl.savefig('paper_plots/IV_55_Ghz_tau_ee_0.2_tau_D_5.png') +##half_time = 0 +#input_normalized = input_signal_array[half_time:]/np.max(input_signal_array[half_time:]) +#sensor_normalized = sensor_1_signal_array[half_time:]/np.max(sensor_1_signal_array[half_time:]) +# +## Calculate the phase diff. Copied from: +## https://stackoverflow.com/questions/6157791/find-phase-difference-between-two-inharmonic-waves +#corr = correlate(input_normalized, sensor_normalized) +#nsamples = input_normalized.size +#time_corr = time_array[half_time:] +#dt_corr = np.linspace(-time_corr[-1] + time_corr[0], +# time_corr[-1] - time_corr[0], 2*nsamples-1) +#time_shift = dt_corr[corr.argmax()] +# +## force the phase shift to be in [-pi:pi] +#period = 1./AC_freq +#phase_diff = 2*np.pi*(((0.5 + time_shift/period) % 1.0) - 0.5) +#print("density.shape = ", density.shape) +#print("Phase diff = ", phase_diff) + +#phase_vs_x = [] +#for i in range(sensor_1_signal_array[0, :].size): +# signal = sensor_1_signal_array[:, i] +# corr = correlate(input_signal_array, signal) +# nsamples = input_signal_array.size +# half_time = 0 +# time_corr = time_array[half_time:] +# dt_corr = np.linspace(-time_corr[-1] + time_corr[0], +# time_corr[-1] - time_corr[0], +# 2*nsamples-1 +# ) +# time_shift = dt_corr[corr.argmax()] +# +# # force the phase shift to be in [-pi:pi] +# period = 1./params.AC_freq +# phase_diff = 2*np.pi*(((0.5 + time_shift/period) % 1.0) - 0.5) +# phase_vs_x.append(phase_diff) +# +#phase_vs_x = np.array(phase_vs_x) +#print("phase_vs_x.shape = ", phase_vs_x.shape) +#np.savetxt("paper_plots/phase_vs_x_tau_ee_0.2_tau_D_1.txt", phase_vs_x) +#np.savetxt("paper_plots/q2_tau_ee_0.2_tau_D_1.txt", q2) +#print("density.shape = ", density.shape) + + diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/signals.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/signals.py new file mode 100644 index 00000000..62104908 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/signals.py @@ -0,0 +1,171 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +# Left needs to be near source, right sensor near drain +sensor_1_left_start = 8.5 # um +sensor_1_left_end = 9.5 # um + +sensor_1_right_start = 8.5 # um +sensor_1_right_end = 9.5 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +sensor_2_left_start = 6.5 # um +sensor_2_left_end = 7.5 # um + +sensor_2_right_start = 6.5 # um +sensor_2_right_end = 7.5 # um + +sensor_2_left_indices = (q2 > sensor_2_left_start ) & (q2 < sensor_2_left_end) +sensor_2_right_indices = (q2 > sensor_2_right_start) & (q2 < sensor_2_right_end) + +filepath = \ +'/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_1.0_tau_ee_0.2_tau_eph_0.5/dumps' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +sensor_1_signal_array = [] +print("Reading sensor signal...") +for file_number, dump_file in enumerate(moment_files): + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + density = moments[:, :, 0] + + source = np.mean(density[0, source_indices]) + drain = np.mean(density[-1, drain_indices]) + + sensor_1_left = np.mean(density[0, sensor_1_left_indices] ) + sensor_1_right = np.mean(density[-1, sensor_1_right_indices]) + + sensor_1_signal = sensor_1_left - sensor_1_right + + sensor_1_signal_array.append(sensor_1_signal) + +time_array = np.loadtxt("dump_time_array.txt") +AC_freq = 1./100 +input_signal_array = np.sin(2.*np.pi*AC_freq*time_array) +sensor_1_signal_array = np.array(sensor_1_signal_array) +half_time = (int)(time_array.size/2) + +input_normalized = \ + input_signal_array/np.max(np.abs(input_signal_array[half_time:])) +sensor_normalized = \ + sensor_1_signal_array/np.max(np.abs(sensor_1_signal_array[half_time:])) + +# Calculate the phase difference between input_signal_array and sensor_normalized +# Code copied from : +# https:/stackoverflow.com/questions/6157791/find-phase-difference-between-two-inharmonic-waves + +corr = correlate(input_normalized, sensor_normalized) +nsamples = input_normalized.size +time_corr = time_array[half_time:] +dt_corr = np.linspace(-time_corr[-1] + time_corr[0], + time_corr[-1] - time_corr[0], 2*nsamples-1) +time_shift = dt_corr[corr.argmax()] + +#Force the phase shift to be in [-pi:pi] +period = 1./AC_freq +phase_diff = 2*np.pi*(((0.5 + time_shift/period) % 1.0) - 0.5) + +pl.plot(time_array, input_signal_array) +pl.plot(time_array, sensor_normalized) +pl.axhline(0, color='black', linestyle='--') + +pl.legend(['Source $I(t)$', 'Measured $V(t)$'], loc=1) +pl.text(135, 1.14, '$\phi : %.2f \; rad$' %phase_diff) +pl.xlabel(r'Time (ps)') +pl.xlim([0, 200]) +pl.ylim([-1.1, 1.1]) + +pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 0.5$ ps') +pl.savefig('images/iv' + '.png') +pl.clf() + + diff --git a/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/vorticity.py b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/vorticity.py new file mode 100644 index 00000000..2f494c60 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_vel_1e-3/vorticity.py @@ -0,0 +1,136 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +filepath = \ +'/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_1.0_tau_ee_0.2_tau_eph_0.5/dumps' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +time_array = np.loadtxt("dump_time_array.txt") +half_time = (int)(time_array.size/2) + +for file_number, dump_file in yt.parallel_objects(enumerate(moment_files)): + + print("file number = ", file_number, "of ", moment_files.size) + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + + h5f = h5py.File(lagrange_multiplier_files[file_number], 'r') + lagrange_multipliers = h5f['lagrange_multipliers'][:] + h5f.close() + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + + + dq1 = (domain.q1_end - domain.q1_start)/domain.N_q1 + dq2 = (domain.q2_end - domain.q2_start)/domain.N_q2 + + dvx_dx, dvx_dy = np.gradient(j_x/density, dq1, dq2) + dvy_dx, dvy_dy = np.gradient(j_y/density, dq1, dq2) + + vorticity = dvy_dx - dvx_dy + + pl.contourf(q1_meshgrid, q2_meshgrid, vorticity, 100, cmap='bwr') + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + + pl.streamplot(q1, q2, + vel_drift_x, vel_drift_y, + density=2, color='blue', + linewidth=0.7, arrowsize=1 + ) + + pl.xlim([domain.q1_start, domain.q1_end]) + pl.ylim([domain.q2_start, domain.q2_end]) + + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + pl.ylabel(r'$y\;(\mu \mathrm{m})$') + pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 1.0$ ps') + pl.savefig('vorticity_images/dump_' + '%06d'%file_number + '.png') + pl.clf() + diff --git a/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/PetscBinaryIO.py b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/PetscBinaryIO.py new file mode 100755 index 00000000..fd0e48e9 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/PetscBinaryIO.py @@ -0,0 +1,479 @@ +"""PetscBinaryIO +=============== + +Provides + 1. PETSc-named objects Vec, Mat, and IS that inherit numpy.ndarray + 2. A class to read and write these objects from PETSc binary files. + +The standard usage of this module should look like: + + >>> import PetscBinaryIO + >>> io = PetscBinaryIO.PetscBinaryIO() + >>> objects = io.readBinaryFile('file.dat') + +or + + >>> import PetscBinaryIO + >>> import numpy + >>> vec = numpy.array([1., 2., 3.]).view(PetscBinaryIO.Vec) + >>> io = PetscBinaryIO.PetscBinaryIO() + >>> io.writeBinaryFile('file.dat', [vec,]) + +to read in objects one at a time use such as + + >>> import PetscBinaryIO + >>> io = PetscBinaryIO.PetscBinaryIO() + >>> fh = open('file.dat') + >>> objecttype = io.readObjectType(fh) + >>> if objecttype == 'Vec': + >>> v = io.readVec(fh) + + Note that one must read in the object type first and then call readVec(), readMat() etc. + + +See also PetscBinaryIO.__doc__ and methods therein. +""" + +import numpy as np +import functools + +try: + basestring # Python-2 has basestring as a common parent of unicode and str +except NameError: + basestring = str # Python-3 is unicode through and through + +def update_wrapper_with_doc(wrapper, wrapped): + """Similar to functools.update_wrapper, but also gets the wrapper's __doc__ string""" + wdoc = wrapper.__doc__ + + functools.update_wrapper(wrapper, wrapped) + if wdoc is not None: + if wrapper.__doc__ is None: + wrapper.__doc__ = wdoc + else: + wrapper.__doc__ = wrapper.__doc__ + wdoc + return wrapper + +def wraps_with_doc(wrapped): + """Similar to functools.wraps, but also gets the wrapper's __doc__ string""" + return functools.partial(update_wrapper_with_doc, wrapped=wrapped) + +def decorate_with_conf(f): + """Decorates methods to take kwargs for precisions.""" + @wraps_with_doc(f) + def decorated_f(self, *args, **kwargs): + """ + Additional kwargs: + precision: 'single', 'double', 'longlong' for scalars + indices: '32bit', '64bit' integer size + complexscalars: True/False + + Note these are set in order of preference: + 1. kwargs if given here + 2. PetscBinaryIO class __init__ arguments + 3. PETSC_DIR/PETSC_ARCH defaults + """ + + changed = False + old_precision = self.precision + old_indices = self.indices + old_complexscalars = self.complexscalars + + try: + self.precision = kwargs.pop('precision') + except KeyError: + pass + else: + changed = True + + try: + self.indices = kwargs.pop('indices') + except KeyError: + pass + else: + changed = True + + try: + self.complexscalars = kwargs.pop('complexscalars') + except KeyError: + pass + else: + changed = True + + if changed: + self._update_dtypes() + + result = f(self, *args, **kwargs) + + if changed: + self.precision = old_precision + self.indices = old_indices + self.complexscalars = old_complexscalars + self._update_dtypes() + + return result + return decorated_f + + +class DoneWithFile(Exception): pass + + +class Vec(np.ndarray): + """Vec represented as 1D numpy array + + The best way to instantiate this class for use with writeBinaryFile() + is through the numpy view method: + + vec = numpy.array([1,2,3]).view(Vec) + """ + _classid = 1211214 + + +class MatDense(np.matrix): + """Mat represented as 2D numpy array + + The best way to instantiate this class for use with writeBinaryFile() + is through the numpy view method: + + mat = numpy.array([[1,0],[0,1]]).view(Mat) + """ + _classid = 1211216 + + +class MatSparse(tuple): + """Mat represented as CSR tuple ((M, N), (rowindices, col, val)) + + This should be instantiated from a tuple: + + mat = MatSparse( ((M,N), (rowindices,col,val)) ) + """ + _classid = 1211216 + def __repr__(self): + return 'MatSparse: %s'%super(MatSparse, self).__repr__() + + +class IS(np.ndarray): + """IS represented as 1D numpy array + + The best way to instantiate this class for use with writeBinaryFile() + is through the numpy "view" method: + + an_is = numpy.array([3,4,5]).view(IS) + """ + _classid = 1211218 + + +class PetscBinaryIO(object): + """Reader/Writer class for PETSc binary files. + + Note that by default, precisions for both scalars and indices, as well as + complex scalars, are picked up from the PETSC_DIR/PETSC_ARCH configuration + as set by environmental variables. + + Alternatively, defaults can be overridden at class instantiation, or for + a given method call. + """ + + _classid = {1211216:'Mat', + 1211214:'Vec', + 1211218:'IS', + 1211219:'Bag'} + + def __init__(self, precision=None, indices=None, complexscalars=None): + if (precision is None) or (indices is None) or (complexscalars is None): + import petsc_conf + defaultprecision, defaultindices, defaultcomplexscalars = petsc_conf.get_conf() + if precision is None: + if defaultprecision is None: + precision = 'double' + else: + precision = defaultprecision + + if indices is None: + if defaultindices is None: + indices = '32bit' + else: + indices = defaultindices + + if complexscalars is None: + if defaultcomplexscalars is None: + complexscalars = False + else: + complexscalars = defaultcomplexscalars + + self.precision = precision + self.indices = indices + self.complexscalars = complexscalars + self._update_dtypes() + + def _update_dtypes(self): + if self.indices == '64bit': + self._inttype = np.dtype('>i8') + else: + self._inttype = np.dtype('>i4') + + if self.precision == 'longlong': + nbyte = 16 + elif self.precision == 'single': + nbyte = 4 + else: + nbyte = 8 + + if self.complexscalars: + name = 'c' + nbyte = nbyte * 2 # complex scalar takes twice as many bytes + else: + name = 'f' + + self._scalartype = '>{0}{1}'.format(name, nbyte) + + @decorate_with_conf + def readVec(self, fh): + """Reads a PETSc Vec from a binary file handle, must be called after readObjectType().""" + + nz = np.fromfile(fh, dtype=self._inttype, count=1)[0] + try: + vals = np.fromfile(fh, dtype=self._scalartype, count=nz) + except MemoryError: + raise IOError('Inconsistent or invalid Vec data in file') + if (len(vals) is 0): + raise IOError('Inconsistent or invalid Vec data in file') + return vals.view(Vec) + + @decorate_with_conf + def writeVec(self, fh, vec): + """Writes a PETSc Vec to a binary file handle.""" + + metadata = np.array([Vec._classid, len(vec)], dtype=self._inttype) + metadata.tofile(fh) + vec.astype(self._scalartype).tofile(fh) + return + + @decorate_with_conf + def readMatSparse(self, fh): + """Reads a PETSc Mat, returning a sparse representation of the data. Must be called after readObjectType() + + (M,N), (I,J,V) = readMatSparse(fid) + + Input: + fid : file handle to open binary file. + Output: + M,N : matrix size + I,J : arrays of row and column for each nonzero + V: nonzero value + """ + + try: + M,N,nz = np.fromfile(fh, dtype=self._inttype, count=3) + I = np.empty(M+1, dtype=self._inttype) + I[0] = 0 + rownz = np.fromfile(fh, dtype=self._inttype, count=M) + np.cumsum(rownz, out=I[1:]) + assert I[-1] == nz + + J = np.fromfile(fh, dtype=self._inttype, count=nz) + assert len(J) == nz + V = np.fromfile(fh, dtype=self._scalartype, count=nz) + assert len(V) == nz + except (AssertionError, MemoryError, IndexError): + raise IOError('Inconsistent or invalid Mat data in file') + + return MatSparse(((M, N), (I, J, V))) + + @decorate_with_conf + def writeMatSparse(self, fh, mat): + """Writes a Mat into a PETSc binary file handle""" + + ((M,N), (I,J,V)) = mat + metadata = np.array([MatSparse._classid,M,N,I[-1]], dtype=self._inttype) + rownz = I[1:] - I[:-1] + + assert len(J.shape) == len(V.shape) == len(I.shape) == 1 + assert len(J) == len(V) == I[-1] == rownz.sum() + assert (rownz > -1).all() + + metadata.tofile(fh) + rownz.astype(self._inttype).tofile(fh) + J.astype(self._inttype).tofile(fh) + V.astype(self._scalartype).tofile(fh) + return + + @decorate_with_conf + def readMatDense(self, fh): + """Reads a PETSc Mat, returning a dense represention of the data, must be called after readObjectType()""" + + try: + M,N,nz = np.fromfile(fh, dtype=self._inttype, count=3) + I = np.empty(M+1, dtype=self._inttype) + I[0] = 0 + rownz = np.fromfile(fh, dtype=self._inttype, count=M) + np.cumsum(rownz, out=I[1:]) + assert I[-1] == nz + + J = np.fromfile(fh, dtype=self._inttype, count=nz) + assert len(J) == nz + V = np.fromfile(fh, dtype=self._scalartype, count=nz) + assert len(V) == nz + + except (AssertionError, MemoryError, IndexError): + raise IOError('Inconsistent or invalid Mat data in file') + + mat = np.zeros((M,N), dtype=self._scalartype) + for row in range(M): + rstart, rend = I[row:row+2] + mat[row, J[rstart:rend]] = V[rstart:rend] + return mat.view(MatDense) + + @decorate_with_conf + def readMatSciPy(self, fh): + from scipy.sparse import csr_matrix + (M, N), (I, J, V) = self.readMatSparse(fh) + return csr_matrix((V, J, I), shape=(M, N)) + + @decorate_with_conf + def writeMatSciPy(self, fh, mat): + from scipy.sparse import csr_matrix + if hasattr(mat, 'tocsr'): + mat = mat.tocsr() + assert isinstance(mat, csr_matrix) + V = mat.data + M,N = mat.shape + J = mat.indices + I = mat.indptr + return self.writeMatSparse(fh, (mat.shape, (mat.indptr,mat.indices,mat.data))) + + @decorate_with_conf + def readMat(self, fh, mattype='sparse'): + """Reads a PETSc Mat from binary file handle, must be called after readObjectType() + + optional mattype: 'sparse" or 'dense' + + See also: readMatSparse, readMatDense + """ + + if mattype == 'sparse': + return self.readMatSparse(fh) + elif mattype == 'dense': + return self.readMatDense(fh) + elif mattype == 'scipy.sparse': + return self.readMatSciPy(fh) + else: + raise RuntimeError('Invalid matrix type requested: choose sparse/dense/scipy.sparse') + + @decorate_with_conf + def readIS(self, fh): + """Reads a PETSc Index Set from binary file handle, must be called after readObjectType()""" + + try: + nz = np.fromfile(fh, dtype=self._inttype, count=1)[0] + v = np.fromfile(fh, dtype=self._inttype, count=nz) + assert len(v) == nz + except (MemoryError,IndexError): + raise IOError('Inconsistent or invalid IS data in file') + return v.view(IS) + + @decorate_with_conf + def writeIS(self, fh, anis): + """Writes a PETSc IS to binary file handle.""" + + metadata = np.array([IS._classid, len(anis)], dtype=self._inttype) + metadata.tofile(fh) + anis.astype(self._inttype).tofile(fh) + return + + @decorate_with_conf + def readObjectType(self, fid): + """Returns the next object type as a string in the file""" + try: + header = np.fromfile(fid, dtype=self._inttype, count=1)[0] + except (MemoryError, IndexError): + raise DoneWithFile + try: + objecttype = self._classid[header] + except KeyError: + raise IOError('Invalid PetscObject CLASSID or object not implemented for python') + return objecttype + + @decorate_with_conf + def readBinaryFile(self, fid, mattype='sparse'): + """Reads a PETSc binary file, returning a tuple of the contained objects. + + objects = self.readBinaryFile(fid, **kwargs) + + Input: + fid : either file name or handle to an open binary file. + + Output: + objects : tuple of objects representing the data in numpy arrays. + + Optional: + mattype : + 'sparse': Return matrices as raw CSR: (M, N), (row, col, val). + 'dense': Return matrices as MxN numpy arrays. + 'scipy.sparse': Return matrices as scipy.sparse objects. + """ + + close = False + + if isinstance(fid, basestring): + fid = open(fid, 'rb') + close = True + + objects = [] + try: + while True: + objecttype = self.readObjectType(fid) + + if objecttype == 'Vec': + objects.append(self.readVec(fid)) + elif objecttype == 'IS': + objects.append(self.readIS(fid)) + elif objecttype == 'Mat': + objects.append(self.readMat(fid,mattype)) + elif objecttype == 'Bag': + raise NotImplementedError('Bag Reader not yet implemented') + except DoneWithFile: + pass + finally: + if close: + fid.close() + + return tuple(objects) + + @decorate_with_conf + def writeBinaryFile(self, fid, objects): + """Writes a PETSc binary file containing the objects given. + + readBinaryFile(fid, objects) + + Input: + fid : either file handle to an open binary file, or filename. + objects : list of objects representing the data in numpy arrays, + which must be of type Vec, IS, MatSparse, or MatSciPy. + """ + close = False + if isinstance(fid, basestring): + fid = open(fid, 'wb') + close = True + + for petscobj in objects: + if (isinstance(petscobj, Vec)): + self.writeVec(fid, petscobj) + elif (isinstance(petscobj, IS)): + self.writeIS(fid, petscobj) + elif (isinstance(petscobj, MatSparse)): + self.writeMatSparse(fid, petscobj) + elif (isinstance(petscobj, MatDense)): + if close: + fid.close() + raise NotImplementedError('Writing a dense matrix is not yet supported') + else: + try: + self.writeMatSciPy(fid, petscobj) + except AssertionError: + if close: + fid.close() + raise TypeError('Object %s is not a valid PETSc object'%(petscobj.__repr__())) + if close: + fid.close() + return diff --git a/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/README.txt b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/README.txt new file mode 100644 index 00000000..ddb0d8b5 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/README.txt @@ -0,0 +1,12 @@ +To switch between 1D/2D polar and cartesian momentum space, the following changes need +to be made : + + +1. domain + - Change p2_start, p2_end and N_p2 +2. params + - Change p_space_grid + - Change p_dim (if switching between 1D and 2D representation in p-space) +3. initialize : No change +4. main : No change +5. boundary_conditions : No change diff --git a/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/boundary_conditions.py b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/boundary_conditions.py new file mode 100644 index 00000000..d0c61e57 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/boundary_conditions.py @@ -0,0 +1,123 @@ +import numpy as np +import arrayfire as af +import domain + +in_q1_left = 'mirror+dirichlet' +in_q1_right = 'mirror+dirichlet' +in_q2_bottom = 'mirror' +in_q2_top = 'mirror' + +@af.broadcast +def f_left(f, t, q1, q2, p1, p2, p3, params): + + k = params.boltzmann_constant + E_upper = params.E_band + T = params.initial_temperature + mu = params.initial_mu + + t = params.current_time + omega = 2. * np.pi * params.AC_freq + + if (params.source_type == 'AC'): + vel_drift_x_in = params.vel_drift_x_in * np.sin(omega*t) + elif (params.source_type == 'DC'): + vel_drift_x_in = params.vel_drift_x_in + else: + raise NotImplementedError('Unsupported source_type') + + if (params.p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (params.p_space_grid == 'polar2D'): + p_x = p1 * af.cos(p2) + p_y = p1 * af.sin(p2) + else: + raise NotImplementedError('Unsupported coordinate system in p_space') + + + fermi_dirac_in = (1./(af.exp( (E_upper - vel_drift_x_in*p_x - mu)/(k*T) ) + 1.) + ) + + if (params.contact_geometry=="straight"): + # Contacts on either side of the device + + q2_contact_start = params.contact_start + q2_contact_end = params.contact_end + + cond = ((q2 >= q2_contact_start) & \ + (q2 <= q2_contact_end) \ + ) + + f_left = cond*fermi_dirac_in + (1 - cond)*f + + elif (params.contact_geometry=="turn_around"): + # Contacts on the same side of the device + + if (params.source_type == 'AC'): + vel_drift_x_out = -params.vel_drift_x_in * np.sin(omega*t) + elif (params.source_type == 'DC'): + vel_drift_x_out = -params.vel_drift_x_in + else: + raise NotImplementedError('Unsupported source_type') + + fermi_dirac_out = (1./(af.exp( (E_upper - vel_drift_x_out*p_x - mu)/(k*T) ) + 1.) + ) + + # TODO: set these parameters in params.py + cond_in = ((q2 >= 3.5) & (q2 <= 4.5)) + cond_out = ((q2 >= 5.5) & (q2 <= 6.5)) + + f_left = cond_in*fermi_dirac_in + cond_out*fermi_dirac_out \ + + (1 - cond_in)*(1 - cond_out)*f + + af.eval(f_left) + return(f_left) + +@af.broadcast +def f_right(f, t, q1, q2, p1, p2, p3, params): + + k = params.boltzmann_constant + E_upper = params.E_band + T = params.initial_temperature + mu = params.initial_mu + + t = params.current_time + omega = 2. * np.pi * params.AC_freq + if (params.source_type == 'AC'): + vel_drift_x_out = params.vel_drift_x_out * np.sin(omega*t) + elif (params.source_type == 'DC'): + vel_drift_x_out = params.vel_drift_x_out + else: + raise NotImplementedError('Unsupported source_type') + + if (params.p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (params.p_space_grid == 'polar2D'): + p_x = p1 * af.cos(p2) + p_y = p1 * af.sin(p2) + else: + raise NotImplementedError('Unsupported coordinate system in p_space') + + fermi_dirac_out = (1./(af.exp( (E_upper - vel_drift_x_out*p_x - mu)/(k*T) ) + 1.) + ) + + if (params.contact_geometry=="straight"): + # Contacts on either side of the device + + q2_contact_start = params.contact_start + q2_contact_end = params.contact_end + + cond = ((q2 >= q2_contact_start) & \ + (q2 <= q2_contact_end) \ + ) + + f_right = cond*fermi_dirac_out + (1 - cond)*f + + elif (params.contact_geometry=="turn_around"): + # Contacts on the same side of the device + + f_right = f + + af.eval(f_right) + return(f_right) diff --git a/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/domain.py b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/domain.py new file mode 100644 index 00000000..bb840d77 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/domain.py @@ -0,0 +1,65 @@ +import numpy as np +import params + +q1_start = 0. +q1_end = 5.0 +N_q1 = 20 + +q2_start = 0. +q2_end = 10. +N_q2 = 40 + +# If N_p1 > 1, mirror boundary conditions require p1 to be +# symmetric about zero +# TODO : Check and fix discrepancy between this and the claim +# that p1_center = mu in polar representation +N_p1 = 1 # Set equal to 1 for 1D polar + +# In the cartesian representation of momentum space, +# p1 = p_x (magnitude of momentum) +# p1_start and p1_end are set such that p1_center is 0 + +# Uncomment the following for the cartesian representation of momentum space +#p1_start = [-0.04] +#p1_end = [0.04] + + +# In the 2D polar representation of momentum space, +# p1 = p_r (magnitude of momentum) +# p1_start and p1_end are set such that p1_center is mu + +# Uncomment the following for the 2D polar representation of momentum space +#p1_start = [params.initial_mu - \ +# 16.*params.boltzmann_constant*params.initial_temperature] +#p1_end = [params.initial_mu + \ +# 16.*params.boltzmann_constant*params.initial_temperature] + +# Uncomment the following for the 1D polar representation of momentum space +p1_start = [0.5*params.initial_mu] +p1_end = [1.5*params.initial_mu] + + +# If N_p2 > 1, mirror boundary conditions require p2 to be +# symmetric about zero +N_p2 = 1024 + +# In the cartesian representation of momentum space, +# p2 = p_y (magnitude of momentum) +# p2_start and p2_end are set such that p2_center is 0 +#p2_start = [-0.04] +#p2_end = [0.04] + +# In the 2D polar representation of momentum space, +# p2 = p_theta (angle of momentum) +# N_p_theta MUST be even. +p2_start = [-np.pi] +p2_end = [np.pi] + +# If N_p3 > 1, mirror boundary conditions require p3 to be +# symmetric about zero + +p3_start = [-0.5] +p3_end = [0.5] +N_p3 = 1 + +N_ghost = 2 diff --git a/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/edge_potential.py b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/edge_potential.py new file mode 100644 index 00000000..b50b3bf5 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/edge_potential.py @@ -0,0 +1,161 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 12, 7.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +# Left needs to be near source, right sensor near drain +sensor_1_left_start = 5.5 # um +sensor_1_left_end = 10.0 # um + +sensor_1_right_start = 5.5 # um +sensor_1_right_end = 10.0 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +sensor_2_left_start = 6.5 # um +sensor_2_left_end = 7.5 # um + +sensor_2_right_start = 6.5 # um +sensor_2_right_end = 7.5 # um + +sensor_2_left_indices = (q2 > sensor_2_left_start ) & (q2 < sensor_2_left_end) +sensor_2_right_indices = (q2 > sensor_2_right_start) & (q2 < sensor_2_right_end) + +filepath = \ +'/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_1.0_tau_ee_0.2_tau_eph_0.5/dumps' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +sensor_1_signal_array = [] +#sensor_2_signal_array = [] +#print("Reading sensor signal...") +print("Loading data...") +density = [] +edge_density = [] +for file_number, dump_file in enumerate(moment_files): + + print("File number = ", file_number, ' of ', moment_files.size) + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + density.append(moments[:, :, 0]) + edge_density.append(density[file_number][0, sensor_1_left_indices]) + +density = np.array(density) +edge_density = np.array(edge_density) + +mean_density = np.mean(density) +max_density = np.max(density) +min_density = np.min(density) + +np.savetxt("edge_density.txt", edge_density) + +print("Dumping data...") +for file_number in yt.parallel_objects(range(density.shape[0])): + + print("File number = ", file_number, ' of ', moment_files.size) + + pl.semilogy(q2[sensor_1_left_indices], + density[file_number][0, sensor_1_left_indices], + ) + #pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.title(r'Time = ' + "%.2f"%(file_number*dt*dump_interval) + " ps") + + pl.xlim([sensor_1_left_start, sensor_1_left_end]) + #pl.ylim([min_density-mean_density, max_density-mean_density]) + #pl.ylim([0., np.log(max_density)]) + + #pl.gca().set_aspect('equal') + #pl.xlabel(r'$x\;(\mu \mathrm{m})$') + #pl.ylabel(r'$y\;(\mu \mathrm{m})$') + + #pl.suptitle('$\\tau_\mathrm{mc} = \infty$ ps, $\\tau_\mathrm{mr} = 3.0$ ps') + #pl.savefig('images/dump_' + '%06d'%file_number + '.png') + pl.savefig('images/density_' + '%06d'%file_number + '.png') + pl.clf() + + + diff --git a/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/enstrophy.py b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/enstrophy.py new file mode 100644 index 00000000..aeab5a28 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/enstrophy.py @@ -0,0 +1,142 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +filepath = \ +'/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_1.0_tau_ee_0.2_tau_eph_0.5/dumps' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +kinetic_energy_array = [] +enstrophy_array = [] +print("Reading kinetic energy and enstrophy signals...") +for file_number, dump_file in enumerate(moment_files): + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + + h5f = h5py.File(lagrange_multiplier_files[file_number], 'r') + lagrange_multipliers = h5f['lagrange_multipliers'][:] + h5f.close() + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + + dq1 = (domain.q1_end - domain.q1_start)/domain.N_q1 + dq2 = (domain.q2_end - domain.q2_start)/domain.N_q2 + + dvx_dx, dvx_dy = np.gradient(j_x/density, dq1, dq2) + dvy_dx, dvy_dy = np.gradient(j_y/density, dq1, dq2) + + vorticity = dvy_dx - dvx_dy + + kinetic_energy = 0.5 * np.sum(vel_drift_x**2 + vel_drift_y**2) * dq1 * dq2 + kinetic_energy_array.append(kinetic_energy) + + enstrophy = np.sum(vorticity**2) * dq1 * dq2 + enstrophy_array.append(enstrophy) + +time_array = np.loadtxt("dump_time_array.txt") +half_time = (int)(time_array.size/2) + +kinetic_energy_normalized = \ + kinetic_energy_array/np.max(np.abs(kinetic_energy_array[half_time:])) +enstrophy_normalized = \ + enstrophy_array/np.max(np.abs(enstrophy_array[half_time:])) + + +pl.plot(time_array, kinetic_energy_normalized) +pl.plot(time_array, enstrophy_normalized) +pl.axhline(0, color='black', linestyle='--') + +pl.legend(['Kinetic Energy', 'Enstrophy'], loc=1) +pl.xlabel(r'Time (ps)') +pl.xlim([0, 200]) +pl.ylim([-0.1, 1.1]) + +pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 1.0$ ps') +pl.savefig('vorticity_images/iv' + '.png') +pl.clf() + + diff --git a/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/initialize.py b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/initialize.py new file mode 100644 index 00000000..fb8e8c88 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/initialize.py @@ -0,0 +1,67 @@ +""" +Functions which are used in assigning the I.C's to +the system. +""" + +import arrayfire as af +import numpy as np +from petsc4py import PETSc + +def initialize_f(q1, q2, p1, p2, p3, params): + + PETSc.Sys.Print("Initializing f") + k = params.boltzmann_constant + + params.mu = 0.*q1 + params.initial_mu + params.T = 0.*q1 + params.initial_temperature + params.vel_drift_x = 0.*q1 + params.vel_drift_y = 0.*q1 + params.phi = 0.*q1 + + params.mu_ee = params.mu.copy() + params.T_ee = params.T.copy() + params.vel_drift_x = 0.*q1 + 0e-3 + params.vel_drift_y = 0.*q1 + 0e-3 + params.j_x = 0.*q1 + params.j_y = 0.*q1 + + params.E_band = params.band_energy(p1, p2) + params.vel_band = params.band_velocity(p1, p2) + + E_upper = params.E_band + params.charge[0]*params.phi + + if (params.p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (params.p_space_grid == 'polar2D'): + p_x = p1 * af.cos(p2) + p_y = p1 * af.sin(p2) + else: + raise NotImplementedError('Unsupported coordinate system in p_space') + + f = (1./(af.exp( (E_upper - params.vel_drift_x*p_x + - params.vel_drift_y*p_y + - params.mu + )/(k*params.T) + ) + 1. + )) + + af.eval(f) + return(f) + + +def initialize_E(q1, q2, params): + + E1 = 0.*q1 + E2 = 0.*q1 + E3 = 0.*q1 + + return(E1, E2, E3) + +def initialize_B(q1, q2, params): + + B1 = 0.*q1 + B2 = 0.*q1 + B3 = 0.*q1 + + return(B1, B2, B3) diff --git a/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/job_script b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/job_script new file mode 100644 index 00000000..75c49d28 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/job_script @@ -0,0 +1,4 @@ +#!/bin/bash +#SBATCH -p gpu -n 4 --gres=gpu:4 -c1 --hint=nomultithread -t 2-00:00 +# (Note: use one MPI process per gpu, update both gres and -n together; max 6) +time mpirun python main.py -snes_monitor -snes_max_it 1 -snes_lag_jacobian_persists TRUE -snes_lag_jacobian 1000000 -snes_atol 1e-50 -snes_rtol 1e-50 > output.txt diff --git a/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/main.py b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/main.py new file mode 100644 index 00000000..87233fcd --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/main.py @@ -0,0 +1,171 @@ +import os +import arrayfire as af +import numpy as np +import math +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +from mpi4py import MPI +MPI.WTIME_IS_GLOBAL=True + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear.nonlinear_solver \ + import nonlinear_solver +#from bolt.lib.nonlinear.fields.fields.fields \ +# import fields_solver.compute_electrostatic_fields +from bolt.lib.utils.restart_latest import latest_output, format_time + +import domain +import boundary_conditions +import initialize +import params + +import bolt.src.electronic_boltzmann.advection_terms \ + as advection_terms +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator +import bolt.src.electronic_boltzmann.moment_defs \ + as moment_defs + + +# Create required folders if they do not exist already +#if not os.path.isdir("dump_f"): +# os.system("mkdir dump_f") +#if not os.path.isdir("dump_moments"): +# os.system("mkdir dump_moments") +#if not os.path.isdir("dump_lagrange_multipliers"): +# os.system("mkdir dump_lagrange_multipliers") +#if not os.path.isdir("images"): +# os.system("mkdir images") + + +# Defining the physical system to be solved: +system = physical_system(domain, + boundary_conditions, + params, + initialize, + advection_terms, + collision_operator.RTA, + moment_defs + ) + +# Declaring a nonlinear system object which will evolve the defined physical system: +nls = nonlinear_solver(system) +N_g = domain.N_ghost +params.rank = nls._comm.rank + +# Time parameters: +dt = params.dt +t_final = params.t_final +params.current_time = time_elapsed = 0.0 +params.time_step = time_step = 0 +dump_counter = 0 +dump_time_array = [] + + +using_latest_restart = False +if(params.latest_restart == True): + latest_f, time_elapsed = latest_output('') + print(time_elapsed) + if(latest_f is not None and time_elapsed is not None): + nls.load_distribution_function(latest_f) + using_latest_restart = True + + +if using_latest_restart == False: + if(params.t_restart == 0 or params.latest_restart == True): + time_elapsed = 0 + formatted_time = format_time(time_elapsed) + nls.dump_distribution_function('dump_f/t=' + formatted_time) + nls.dump_moments('dump_moments/t=' + formatted_time) + nls.dump_aux_arrays([params.mu, + params.mu_ee, + params.T_ee, + params.vel_drift_x, params.vel_drift_y, + params.j_x, params.j_y], + 'lagrange_multipliers', + 'dump_lagrange_multipliers/t=' + formatted_time + ) + dump_time_array.append(time_elapsed) + if (params.rank==0): + np.savetxt("dump_time_array.txt", dump_time_array) + else: + time_elapsed = params.t_restart + formatted_time = format_time(time_elapsed) + nls.load_distribution_function('dump_f/t=' + formatted_time) + +# Checking that the file writing intervals are greater than dt: +assert(params.dt_dump_f > dt) +assert(params.dt_dump_moments > dt) +assert(params.dt_dump_fields > dt) + + +#if (params.restart): +# nls.load_distribution_function(params.restart_file) + +density = nls.compute_moments('density') +print("rank = ", params.rank, "\n", + " = ", af.mean(params.mu[0, 0, N_g:-N_g, N_g:-N_g]), "\n", + " max(mu) = ", af.max(params.mu[0, 0, N_g:-N_g, N_g:-N_g]), "\n", + " = ", af.mean(density[0, 0, N_g:-N_g, N_g:-N_g]), "i\n", + " max(n) = ", af.max(density[0, 0, N_g:-N_g, N_g:-N_g]), "\n" + ) + +nls.f = af.select(nls.f < 1e-20, 1e-20, nls.f) +while(time_elapsed < t_final): + + # Refine to machine error + if (time_step==0): + params.collision_nonlinear_iters = 10 + else: + params.collision_nonlinear_iters = params.collision_operator_nonlinear_iters + + dump_steps = params.dump_steps + + if(params.dt_dump_moments != 0): + # We step by delta_dt to get the values at dt_dump + delta_dt = (1 - math.modf(time_elapsed/params.dt_dump_moments)[0]) \ + * params.dt_dump_moments + + if((delta_dt-dt)<1e-5): + nls.strang_timestep(delta_dt) + time_elapsed += delta_dt + formatted_time = format_time(time_elapsed) + nls.dump_moments('dump_moments/t=' + formatted_time) + nls.dump_aux_arrays([params.mu, + params.mu_ee, + params.T_ee, + params.vel_drift_x, params.vel_drift_y, + params.j_x, params.j_y], + 'lagrange_multipliers', + 'dump_lagrange_multipliers/t=' + formatted_time + ) + dump_time_array.append(time_elapsed) + if (params.rank==0): + np.savetxt("dump_time_array.txt", dump_time_array) + + if(math.modf(time_elapsed/params.dt_dump_f)[0] < 1e-12): + formatted_time = format_time(time_elapsed) + nls.dump_distribution_function('dump_f/t=' + formatted_time) + + PETSc.Sys.Print("Time step =", time_step, ", Time =", time_elapsed) + + nls.strang_timestep(dt) + time_elapsed = time_elapsed + dt + time_step = time_step + 1 + params.time_step = time_step + params.current_time = time_elapsed + + # Floors + nls.f = af.select(nls.f < 1e-20, 1e-20, nls.f) + + density = nls.compute_moments('density') + print("rank = ", params.rank, "\n", + " = ", af.mean(params.mu[0, 0, N_g:-N_g, N_g:-N_g]), "\n", + " max(mu) = ", af.max(params.mu[0, 0, N_g:-N_g, N_g:-N_g]), "\n", + " = ", af.mean(density[0, 0, N_g:-N_g, N_g:-N_g]), "\n", + " max(n) = ", af.max(density[0, 0, N_g:-N_g, N_g:-N_g]), "\n" + ) + PETSc.Sys.Print("--------------------\n") + +nls.dump_distribution_function('dump_f/f_laststep') diff --git a/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/momentum_space_movie.py b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/momentum_space_movie.py new file mode 100644 index 00000000..1de644d7 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/momentum_space_movie.py @@ -0,0 +1,134 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import os +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1_start = domain.q1_start +q1_end = domain.q1_end +q2_start = domain.q2_start +q2_end = domain.q2_end + +q1 = q1_start + (0.5 + np.arange(N_q1)) * (q1_end - q1_start)/N_q1 +q2 = q2_start + (0.5 + np.arange(N_q2)) * (q2_end - q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 + +p1_start = domain.p1_start +p1_end = domain.p1_end +p2_start = domain.p2_start +p2_end = domain.p2_end + +p1 = p1_start[0] + (0.5 + np.arange(N_p1)) * (p1_end[0] - p1_start[0])/N_p1 +p2 = p2_start[0] + (0.5 + np.arange(N_p2)) * (p2_end[0] - p2_start[0])/N_p2 + +p1_meshgrid, p2_meshgrid = np.meshgrid(p1, p2) + +p_x = p1_meshgrid * np.cos(p2_meshgrid) +p_y = p1_meshgrid * np.sin(p2_meshgrid) + +#p2_meshgrid, p1_meshgrid = np.meshgrid(p2, p1) + +io = PetscBinaryIO.PetscBinaryIO() + +filepath = os.getcwd() + "/dumps" +moment_files = np.sort(glob.glob(filepath+'/moment*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) +dist_func_files = np.sort(glob.glob(filepath+'/f_*.bin')) + +dist_func_bg_file = dist_func_files[0] +dist_func_file = dist_func_files[-1] + +dist_func_background = io.readBinaryFile(dist_func_bg_file) +#dist_func_background = dist_func_background[0].reshape(N_q2, N_q1, N_p2, N_p1) +dist_func_background = dist_func_background[0].reshape(N_q1, N_q2, 1, 1, N_p2, N_p1) +dist_func = io.readBinaryFile(dist_func_file) + +print (dist_func[0].shape) + +dist_func = dist_func[0].reshape(N_q1, N_q2, 1, 1, N_p2, N_p1) + + +N = 7 +for index_1 in range(N): + for index_2 in range(N): + + q1_position = int(N_q1*((index_1/N)+(1/(2*N)))) + q2_position = int(N_q2*((index_2/N)+(1/(2*N)))) + + #a = np.max((dist_func - dist_func_background)[q2_position, q1_position, :, :]) + #b = np.abs(np.min((dist_func - dist_func_background)[q2_position, q1_position, :, :])) + #norm_factor = np.maximum(a, b) + #f_at_desired_q = \ + # np.reshape((dist_func-dist_func_background)[q2_position, q1_position, :, :], + # [N_p2, N_p1])/norm_factor + + f_at_desired_q = np.reshape((dist_func - \ + dist_func_background)[q1_position, q2_position, :], + [N_p2, N_p1] + ) + pl.contourf(p1_meshgrid, p2_meshgrid, f_at_desired_q, 100, cmap='bwr') + + #np.savetxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2), f_at_desired_q) + #f = np.loadtxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2)) + + + #pl.contourf(p_x, p_y, f_at_desired_q, 100, cmap='bwr') + #pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.xlabel('$p_x$') + pl.ylabel('$p_y$') + pl.gca().set_aspect('equal') + pl.savefig('images/dist_func_at_a_point_%d_%d.png'%(index_1, index_2)) + pl.clf() + diff --git a/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/momentum_space_movie_zero_T.py b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/momentum_space_movie_zero_T.py new file mode 100644 index 00000000..664bb2ce --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/momentum_space_movie_zero_T.py @@ -0,0 +1,164 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import os +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain +import params + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_s = len(params.mass) # Number of species + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1_start = domain.q1_start +q1_end = domain.q1_end +q2_start = domain.q2_start +q2_end = domain.q2_end + +q1 = q1_start + (0.5 + np.arange(N_q1)) * (q1_end - q1_start)/N_q1 +q2 = q2_start + (0.5 + np.arange(N_q2)) * (q2_end - q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 +N_p3 = domain.N_p3 + +p1_start = domain.p1_start +p1_end = domain.p1_end +p2_start = domain.p2_start +p2_end = domain.p2_end + +p1 = p1_start[0] + (0.5 + np.arange(N_p1)) * (p1_end[0] - p1_start[0])/N_p1 +p2 = p2_start[0] + (0.5 + np.arange(N_p2)) * (p2_end[0] - p2_start[0])/N_p2 + +p1_meshgrid, p2_meshgrid = np.meshgrid(p1, p2) + +p_x = p1_meshgrid * np.cos(p2_meshgrid) +p_y = p1_meshgrid * np.sin(p2_meshgrid) + +#p2_meshgrid, p1_meshgrid = np.meshgrid(p2, p1) + +io = PetscBinaryIO.PetscBinaryIO() + +filepath = os.getcwd() + "/dumps" +moment_files = np.sort(glob.glob(filepath+'/moment*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) +dist_func_files = np.sort(glob.glob(filepath+'/f_*.bin')) + +dist_func_bg_file = dist_func_files[0] +dist_func_file = dist_func_files[-1] + +dist_func_background = io.readBinaryFile(dist_func_bg_file) +#dist_func_background = dist_func_background[0].reshape(N_q2, N_q1, N_p2, N_p1) +dist_func_background = dist_func_background[0].reshape(N_q2, N_q1, N_s, N_p3, N_p2, N_p1) +dist_func = io.readBinaryFile(dist_func_file) + +print (dist_func[0].shape) + +dist_func = dist_func[0].reshape(N_q2, N_q1, N_s, N_p3, N_p2, N_p1) + + +N = 7 +for index_1 in range(N): + for index_2 in range(N): + + q1_position = int(N_q1*((index_1/N)+(1/(2*N)))) + q2_position = int(N_q2*((index_2/N)+(1/(2*N)))) + + a = np.max((dist_func - dist_func_background)[q2_position, q1_position, :, :]) + b = np.abs(np.min((dist_func - dist_func_background)[q2_position, q1_position, :, :])) + norm_factor = np.maximum(a, b) + f_at_desired_q = \ + np.reshape((dist_func-\ + dist_func_background)[q2_position, q1_position, :, :],\ + [N_p2, N_p1])/norm_factor + + np.savetxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2), f_at_desired_q) + f = np.loadtxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2)) + + #f_at_desired_q = np.reshape((dist_func - \ + # dist_func_background)[q1_position, q2_position, :], + # [N_p2, N_p1] + # ) + + #print ("f at desired q : ", dist_func[q1_position, q2_position, :].shape) + print ("norm : ", norm_factor) + + + radius = f.copy() + theta = p2.copy() + + x = (radius + 5.)*np.cos(theta) + y = (radius + 5.)*np.sin(theta) + + x_bg = 5*np.cos(theta) + y_bg = 5*np.sin(theta) + + print ('p2 : ', p2.shape) + #pl.plot(p2, f_at_desired_q) + pl.plot(x, y, color='r', linestyle = '-', lw=3) + pl.plot(x_bg, y_bg, color='k', alpha=0.5, lw=3) + #pl.contourf(p1_meshgrid, p2_meshgrid, f_at_desired_q, 100, cmap='bwr') + + #np.savetxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2), f_at_desired_q) + #f = np.loadtxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2)) + + + #pl.contourf(p_x, p_y, f_at_desired_q, 100, cmap='bwr') + #pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.xlabel('$p_x$') + pl.ylabel('$p_y$') + + pl.xlim([-6.5, 6.5]) + pl.ylim([-6.5, 6.5]) + + pl.gca().set_aspect('equal') + pl.savefig('images/dist_func_at_a_point_%d_%d.png'%(index_1, index_2)) + pl.clf() + diff --git a/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/movie.py b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/movie.py new file mode 100644 index 00000000..dbae5848 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/movie.py @@ -0,0 +1,162 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import os +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain +import boundary_conditions +import params +import initialize + + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 + +p1 = domain.p1_start[0] + (0.5 + np.arange(N_p1)) * (domain.p1_end[0] - \ + domain.p1_start[0])/N_p1 +p2 = domain.p2_start[0] + (0.5 + np.arange(N_p2)) * (domain.p2_end[0] - \ + domain.p2_start[0])/N_p2 + +print ('Momentum space : ', p1[-1], p2[int(N_p2/2)]) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +# Left needs to be near source, right sensor near drain +sensor_1_left_start = 8.5 # um +sensor_1_left_end = 9.5 # um + +sensor_1_right_start = 8.5 # um +sensor_1_right_end = 9.5 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +sensor_2_left_start = 6.5 # um +sensor_2_left_end = 7.5 # um + +sensor_2_right_start = 6.5 # um +sensor_2_right_end = 7.5 # um + +sensor_2_left_indices = (q2 > sensor_2_left_start ) & (q2 < sensor_2_left_end) +sensor_2_right_indices = (q2 > sensor_2_right_start) & (q2 < sensor_2_right_end) + +#filepath = \ +#'/home/mchandra/gitansh/bolt_master/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/dumps' +filepath = os.getcwd() + "/dumps" +moment_files = np.sort(glob.glob(filepath+'/moment*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.bin')) + +print ("moment files : ", moment_files.size) +print ("lagrange multiplier files : ", lagrange_multiplier_files.size) + +dt = params.dt +dump_interval = params.dump_steps + +time_array = np.loadtxt("dump_time_array.txt") + +io = PetscBinaryIO.PetscBinaryIO() + +for file_number, dump_file in yt.parallel_objects(enumerate(moment_files)): + + print("file number = ", file_number, "of ", moment_files.size) + + moments = io.readBinaryFile(dump_file) + moments = moments[0].reshape(N_q2, N_q1, 3) + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + + lagrange_multipliers = \ + io.readBinaryFile(lagrange_multiplier_files[file_number]) + lagrange_multipliers = lagrange_multipliers[0].reshape(N_q2, N_q1, 7) + #h5f = h5py.File(lagrange_multiplier_files[file_number], 'r') + #lagrange_multipliers = h5f['lagrange_multipliers'][:] + #h5f.close() + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + + print (vel_drift_x.shape) + print (density.shape) + + pl.contourf(q1_meshgrid, q2_meshgrid, density.T, 100, cmap='bwr') + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.streamplot(q1, q2, + vel_drift_x, vel_drift_y, + density=2, color='k', + linewidth=0.7, arrowsize=1 + ) + + pl.xlim([q1[0], q1[-1]]) + pl.ylim([q2[0], q2[-1]]) + + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + pl.ylabel(r'$y\;(\mu \mathrm{m})$') + pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 1.0$ ps') + pl.savefig('images/dump_' + '%06d'%file_number + '.png') + pl.clf() + diff --git a/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/params.py b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/params.py new file mode 100644 index 00000000..09e1298f --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/params.py @@ -0,0 +1,177 @@ +import numpy as np +import arrayfire as af + +instantaneous_collisions = False #TODO : Remove from lib +hybrid_model_enabled = False #TODO : Remove from lib +source_enabled = True +disable_collision_op = False + +fields_enabled = False +# Can be defined as 'electrostatic', 'user-defined'. +# The initial conditions need to be specified under initialize +# Ensure that the initial conditions specified satisfy +# Maxwell's constraint equations +fields_initialize = 'user-defined' + +# Can be defined as 'electrostatic' and 'fdtd' +# To turn feedback from Electric fields on, set fields_solver = 'LCA' +# and set charge_electron +fields_type = 'electrostatic' +fields_solver = 'SNES' + +# Can be defined as 'strang' and 'lie' +time_splitting = 'strang' + +# Method in q-space +solver_method_in_q = 'FVM' +solver_method_in_p = 'FVM' + +reconstruction_method_in_q = 'minmod' +reconstruction_method_in_p = 'minmod' + +riemann_solver_in_q = 'upwind-flux' +riemann_solver_in_p = 'upwind-flux' + +# Restart(Set to zero for no-restart): +restart = 0 +restart_file = '/home/mani/work/quazar_research/bolt/example_problems/electronic_boltzmann/graphene/dumps/f_eqbm.h5' +phi_restart_file = '/home/mani/work/quazar_research/bolt/example_problems/electronic_boltzmann/graphene/dumps/phi_eqbm.h5' +electrostatic_solver_every_nth_step = 1000000 +solve_for_equilibrium = 0 + + +# File-writing Parameters: +dump_steps = 10 +# Set to zero for no file-writing +dt_dump_f = 100 #ps +# ALWAYS set dump moments and dump fields at same frequency: +dt_dump_moments = dt_dump_fields = 10 #ps + + +# Time parameters: +dt = 0.025/2 # ps +t_final = 200. # ps + +# Dimensionality considered in velocity space: +p_dim = 1 +p_space_grid = 'polar2D' # Supports 'cartesian' or 'polar2D' grids +# Set p-space start and end points accordingly in domain.py + +# Number of devices(GPUs/Accelerators) on each node: +num_devices = 6 + +# Constants: +mass_particle = 0.910938356 # x 1e-30 kg +h_bar = 1.0545718e-4 # x aJ ps +boltzmann_constant = 1 +charge = [0.*-0.160217662] # x aC +mass = [0.] #TODO : Not used in electronic_boltzmann + # Remove from lib +speed_of_light = 300. # x [um/ps] +fermi_velocity = speed_of_light/300 +epsilon0 = 8.854187817 # x [aC^2 / (aJ um) ] + +epsilon_relative = 3.9 # SiO2 +backgate_potential = -10 # V +global_chem_potential = 0.03 +contact_start = 4.5 # um +contact_end = 5.5 # um +contact_geometry = "straight" # Contacts on either side of the device + # For contacts on the same side, use + # contact_geometry = "turn_around" + +initial_temperature = 12e-4 +initial_mu = 0.015 +vel_drift_x_in = 1e-4*fermi_velocity +vel_drift_x_out = 1e-4*fermi_velocity +source_type = 'AC' # Select 'AC' or 'DC' +AC_freq = 1./100 # ps^-1 (only for AC) + +B3_mean = 1. # T + +# Spatial quantities (will be initialized to shape = [q1, q2] in initalize.py) +mu = None # chemical potential used in the e-ph operator +T = None # Electron temperature used in the e-ph operator +mu_ee = None # chemical potential used in the e-e operator +T_ee = None # Electron temperature used in the e-e operator +vel_drift_x = None +vel_drift_y = None +j_x = None +j_y = None +phi = None # Electric potential in the plane of graphene sheet + +# Momentum quantities (will be initialized to shape = [p1*p2*p3] in initialize.py) +E_band = None +vel_band = None + +collision_operator_nonlinear_iters = 2 + +# Variation of collisional-timescale parameter through phase space: +@af.broadcast +def tau_defect(q1, q2, p1, p2, p3): + return(1.0 * q1**0 * p1**0) + +@af.broadcast +def tau_ee(q1, q2, p1, p2, p3): + return(0.2 * q1**0 * p1**0) + +def tau(q1, q2, p1, p2, p3): + return(tau_defect(q1, q2, p1, p2, p3)) + +def band_energy(p1, p2): + + if (p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (p_space_grid == 'polar2D'): + p_x = p1 * af.cos(p2) + p_y = p1 * af.sin(p2) + else : + raise NotImplementedError('Unsupported coordinate system in p_space') + + p = af.sqrt(p_x**2. + p_y**2.) + + E_upper = p*fermi_velocity + + af.eval(E_upper) + return(E_upper) + +def band_velocity(p1, p2): + + if (p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (p_space_grid == 'polar2D'): + p_x = p1 * af.cos(p2) + p_y = p1 * af.sin(p2) + else : + raise NotImplementedError('Unsupported coordinate system in p_space') + + p = af.sqrt(p_x**2. + p_y**2.) + p_hat = [p_x / (p + 1e-20), p_y / (p + 1e-20)] + + v_f = fermi_velocity + + upper_band_velocity = [ v_f * p_hat[0], v_f * p_hat[1]] + + af.eval(upper_band_velocity[0], upper_band_velocity[1]) + return(upper_band_velocity) + +# Restart(Set to zero for no-restart): +latest_restart = True +t_restart = 0 + +@af.broadcast +def fermi_dirac(mu, E_band): + + k = boltzmann_constant + T = initial_temperature + + f = (1./(af.exp( (E_band - mu + )/(k*T) + ) + 1. + ) + ) + + af.eval(f) + return(f) diff --git a/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/petsc_conf.py b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/petsc_conf.py new file mode 100755 index 00000000..22781ed2 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/petsc_conf.py @@ -0,0 +1,73 @@ +import warnings + +def get_conf(): + """Parses various PETSc configuration/include files to get data types. + + precision, indices, complexscalars = get_conf() + + Output: + precision: 'single', 'double', 'longlong' indicates precision of PetscScalar + indices: '32', '64' indicates bit-size of PetscInt + complex: True/False indicates whether PetscScalar is complex or not. + """ + + import sys, os + precision = None + indices = None + complexscalars = None + + if 'PETSC_DIR' in os.environ: + petscdir = os.environ['PETSC_DIR'] + else: + warnings.warn('PETSC_DIR env not set - unable to locate PETSc installation, using defaults') + return None, None, None + + if os.path.isfile(os.path.join(petscdir,'lib','petsc','conf','petscrules')): + # found prefix install + petscvariables = os.path.join(petscdir,'lib','petsc','conf','petscvariables') + petscconfinclude = os.path.join(petscdir,'include','petscconf.h') + else: + if 'PETSC_ARCH' in os.environ: + petscarch = os.environ['PETSC_ARCH'] + if os.path.isfile(os.path.join(petscdir,petscarch,'lib','petsc','conf','petscrules')): + # found legacy install + petscvariables = os.path.join(petscdir,petscarch,'lib','petsc','conf','petscvariables') + petscconfinclude = os.path.join(petscdir,petscarch,'include','petscconf.h') + else: + warnings.warn('Unable to locate PETSc installation in specified PETSC_DIR/PETSC_ARCH, using defaults') + return None, None, None + else: + warnings.warn('PETSC_ARCH env not set or incorrect PETSC_DIR is given - unable to locate PETSc installation, using defaults') + return None, None, None + + try: + fid = open(petscvariables, 'r') + except IOError: + warnings.warn('Nonexistent or invalid PETSc installation, using defaults') + return None, None, None + else: + for line in fid: + if line.startswith('PETSC_PRECISION'): + precision = line.strip().split('=')[1].strip('\n').strip() + + fid.close() + + try: + fid = open(petscconfinclude, 'r') + except IOError: + warnings.warn('Nonexistent or invalid PETSc installation, using defaults') + return None, None, None + else: + for line in fid: + if line.startswith('#define PETSC_USE_64BIT_INDICES 1'): + indices = '64bit' + elif line.startswith('#define PETSC_USE_COMPLEX 1'): + complexscalars = True + + if indices is None: + indices = '32bit' + if complexscalars is None: + complexscalars = False + fid.close() + + return precision, indices, complexscalars diff --git a/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/phase_vs_y.py b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/phase_vs_y.py new file mode 100644 index 00000000..fc6ac364 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/phase_vs_y.py @@ -0,0 +1,180 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +from scipy.optimize import curve_fit +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 12, 7.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +def sin_curve_fit(t, A, tau): + return A*np.sin(2*np.pi*AC_freq*(t + tau )) + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +# Left needs to be near source, right sensor near drain +sensor_1_left_start = 5.5 # um +sensor_1_left_end = 10.0 # um + +sensor_1_right_start = 5.5 # um +sensor_1_right_end = 10.0 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +filepath = \ + '/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_2.5_tau_ee_inf_tau_eph_2.5/dumps' + +AC_freq = 1./100.0 +time_period = 1/AC_freq +t_final = params.t_final +transient_time = t_final/2. + +time = np.loadtxt(filepath + "/../dump_time_array.txt") +edge_density = np.loadtxt(filepath + "/../edge_density.txt") +q2 = np.loadtxt(filepath + "/../q2_edge.txt") + +N_spatial = edge_density.shape[1] + +transient_index = int((transient_time/t_final)*time.size) + +drive = np.sin(2*np.pi*AC_freq*time) +nsamples = drive.size +dt_corr = np.linspace(-time[-1] + time[0],\ + time[-1] - time[0], 2*nsamples-1) + +# Discarding transients +q = q2.size/2 +time_half = time[transient_index:] +drive_half = drive[transient_index:] + +# Plotting signals at edge +norm_0 = np.max(edge_density[transient_index:, 0]) +norm_1 = np.max(edge_density[transient_index:, -1]) + +pl.plot(time, drive, color='black', linestyle='--') +pl.ylim([-1.1, 1.1]) +pl.xlim([0,200]) +pl.xlabel('$\mathrm{Time\;(s)}$') + +for i in range(N_spatial): + norm_i = np.max(edge_density[transient_index:, i]) + pl.plot(time, edge_density[:, i]/norm_i) + +pl.savefig('images/signals.png') +pl.clf() + +phase_shift_corr_array = [] +phase_shift_fitting_array = []\ + +for i in range(N_spatial): + print ('index : ', i) + signal_1 = edge_density[:, i] + norm_1 = np.max(signal_1[transient_index:]) + signal_1_normalized = signal_1/norm_1 + + # Calculate phase_shifts using scipy.correlate + corr = correlate(drive, signal_1_normalized) + time_shift_corr = dt_corr[corr.argmax()] + phase_shift_corr = 2*np.pi*(((0.5 + time_shift_corr/time_period) % 1.0) - 0.5) + + # Calculate phase_shifts using scipy.curve_fit + popt, pcov = curve_fit(sin_curve_fit, time[transient_index:],\ + signal_1_normalized[transient_index:]) + time_shift_fitting = popt[1]%(time_period/2.0) + phase_shift_fitting = 2*np.pi*(((0.5 + time_shift_fitting/time_period) % 1.0) - 0.5) + + phase_shift_corr_array.append(phase_shift_corr) + phase_shift_fitting_array.append(phase_shift_fitting) + +phase_shift_corr_array = np.array(phase_shift_corr_array) +phase_shift_fitting_array = np.array(phase_shift_fitting_array) + +# Plot +pl.ylabel('$\mathrm{\phi}$') +pl.xlabel('$\mathrm{y\ \mu m}$') + +pl.plot(q2, phase_shift_corr_array, '-o', label='$\mathrm{corr}$') +pl.plot(q2, phase_shift_fitting_array, '-o', label='$\mathrm{fit}$') + +pl.title('$\mathrm{2.5 \\times 10,\ \\tau_{ee} = \infty,\ \\tau_{eph} = 2.5}$') +pl.legend(loc='best') + +#pl.axvspan(sensor_1_left_start, sensor_1_left_end, color = 'k', alpha = 0.1) +#pl.axvspan(sensor_2_left_start, sensor_2_left_end, color = 'k', alpha = 0.1) + +pl.savefig('images/phase_vs_y.png') +pl.clf() + diff --git a/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/post.py b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/post.py new file mode 100644 index 00000000..a297c6f0 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/post.py @@ -0,0 +1,422 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +#pl.rcParams['figure.figsize'] = 8, 7.5 +pl.rcParams['figure.figsize'] = 8, 8 +#pl.rcParams['figure.figsize'] = 17, 9.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +#pl.rcParams['lines.linewidth'] = 3 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 +#N_q1 = 120 +#N_q2 = 240 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +#source_start = 3.5; source_end = 4.5 +#drain_start = 5.5; drain_end = 6.5 + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +sensor_1_left_start = 8.5 # um +sensor_1_left_end = 9.5 # um + +sensor_1_right_start = 8.5 # um +sensor_1_right_end = 9.5 # um + +# Left needs to be near source, right sensor near drain +#sensor_1_left_start = 1.5 # um +#sensor_1_left_end = 2.5 # um + +#sensor_1_right_start = 7.5 # um +#sensor_1_right_end = 8.5 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +sensor_2_left_start = 6.5 # um +sensor_2_left_end = 7.5 # um + +sensor_2_right_start = 6.5 # um +sensor_2_right_end = 7.5 # um + +sensor_2_left_indices = (q2 > sensor_2_left_start ) & (q2 < sensor_2_left_end) +sensor_2_right_indices = (q2 > sensor_2_right_start) & (q2 < sensor_2_right_end) + +#dump_index = 0 +#h5f = h5py.File('dumps/moments_' + '%06d'%(dump_index) + '.h5', 'r') +#moments = np.swapaxes(h5f['moments'][:], 0, 1) +#h5f.close() +# +#density = moments[:, :, 0] +#j_x = moments[:, :, 1] +#j_y = moments[:, :, 2] +#pl.contourf(q1, q2, density, 100) +##pl.title('Time = ' + "%.2f"%(t0)) +#pl.axes().set_aspect('equal') +#pl.xlabel(r'$x$') +#pl.ylabel(r'$y$') +#pl.colorbar() +#pl.savefig('images/density' + '.png') +#pl.clf() +# +#h5f = h5py.File('dumps/lagrange_multipliers_' + '%06d'%(dump_index) + '.h5', 'r') +#lagrange_multipliers = np.swapaxes(h5f['lagrange_multipliers'][:], 0, 1) +#h5f.close() +# +#print("lagrange_multipliers.shape = ", lagrange_multipliers.shape) +#mu = lagrange_multipliers[:, :, 0] +#mu_ee = lagrange_multipliers[:, :, 1] +#T_ee = lagrange_multipliers[:, :, 2] +#vel_drift_x = lagrange_multipliers[:, :, 3] +#vel_drift_y = lagrange_multipliers[:, :, 4] +#j_x_prime = density*vel_drift_x +#print("err = ", np.mean(np.abs(j_x_prime - j_x))) + +#filepath = \ +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/geom_1/DC/tau_D_50_tau_ee_0.2' +#dump_file= np.sort(glob.glob(filepath+'/moment*.h5'))[-1] +# +#h5f = h5py.File(dump_file, 'r') +#moments = np.swapaxes(h5f['moments'][:], 0, 1) +#h5f.close() +# +#density = moments[:, :, 0] +#np.savetxt('paper_plots/density_tau_D_50_tau_ee_0.2.txt', density) +#np.savetxt('paper_plots/q2_DC_tau_D_50_tau_ee_0.2.txt', q2) +##pl.plot(q2[q2>source_end], density[0, q2>source_end]-np.mean(density)) +# +#filepath = \ +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/geom_1/DC/tau_D_5_tau_ee_0.2' +#dump_file= np.sort(glob.glob(filepath+'/moment*.h5'))[-1] +# +# +#h5f = h5py.File(dump_file, 'r') +#moments = np.swapaxes(h5f['moments'][:], 0, 1) +#h5f.close() +# +#density = moments[:, :, 0] +#np.savetxt('paper_plots/density_tau_D_5_tau_ee_0.2.txt', density) +#np.savetxt('paper_plots/q2_DC_tau_D_5_tau_ee_0.2.txt', q2) +# +#filepath = \ +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/geom_1/DC/tau_D_10_tau_ee_0.2' +#dump_file= np.sort(glob.glob(filepath+'/moment*.h5'))[-1] +# +#N_q1 = 120 +#N_q2 = 240 +# +#q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +#q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 +# +#h5f = h5py.File(dump_file, 'r') +#moments = np.swapaxes(h5f['moments'][:], 0, 1) +#h5f.close() +# +#density = moments[:, :, 0] +#np.savetxt('paper_plots/density_tau_D_10_tau_ee_0.2.txt', density) +#np.savetxt('paper_plots/q2_DC_tau_D_10_tau_ee_0.2.txt', q2) + + +#pl.plot(q2[q2>source_end], density[0, q2>source_end]-np.mean(density)) +#pl.axhline(0, color='black', linestyle='--') +#pl.legend(['$\\tau_{ee}=0.2$ ps, $\\tau_{e-ph}=50$ ps', +# '$\\tau_{ee}=0.2$ ps, $\\tau_{e-ph}=10$ ps'], loc='lower right') +#pl.xlabel(r'$x\;(\mu \mathrm{m})$') +#pl.ylabel(r'$R\; (\mathrm{a.u.})$') +#pl.xlim(xmin=(source_end+0.1)) +#pl.savefig('paper_plots/DC.png') + +filepath = \ +'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/dumps_tau_D_1_tau_ee_0.2_movie' +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/geom_1/55_GHz/tau_D_5_tau_ee_0.2' +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/dumps_AC_10_Ghz_tau_D_10_tau_ee_1_geom_2/' +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/dumps_tau_D_2_tau_ee_1_AC/' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +sensor_1_signal_array = [] +print("Reading sensor signal...") +for file_number, dump_file in enumerate(moment_files): + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + density = moments[:, :, 0] + + source = np.mean(density[0, source_indices]) + drain = np.mean(density[-1, drain_indices]) + + sensor_1_left = np.mean(density[0, sensor_1_left_indices] ) + sensor_1_right = np.mean(density[-1, sensor_1_right_indices]) + + sensor_1_signal = sensor_1_left - sensor_1_right + + sensor_1_signal_array.append(sensor_1_signal) + +time_array = np.loadtxt("dump_time_array.txt") +AC_freq = 1./100 +input_signal_array = np.sin(2.*np.pi*AC_freq*time_array) +sensor_1_signal_array = np.array(sensor_1_signal_array) +half_time = (int)(time_array.size/2) +sensor_normalized = \ + sensor_1_signal_array/np.max(np.abs(sensor_1_signal_array[half_time:])) + +pl.rcParams['figure.figsize'] = 10, 8 +for file_number, dump_file in yt.parallel_objects(enumerate(moment_files)): + + print("file number = ", file_number, "of ", moment_files.size) + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + gs = gridspec.GridSpec(3, 2) + pl.subplot(gs[:, 0]) + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + pl.contourf(q1_meshgrid, q2_meshgrid, density, 100, cmap='bwr') + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + #pl.colorbar() + + h5f = h5py.File(lagrange_multiplier_files[file_number], 'r') + lagrange_multipliers = h5f['lagrange_multipliers'][:] + h5f.close() + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + +# pl.streamplot(q1[(int)(N_q1/2):], q2, +# vel_drift_x[:, (int)(N_q1/2):], vel_drift_y[:, (int)(N_q1/2):], +# density=2, color='blue', +# linewidth=0.7, arrowsize=1 +# ) + pl.streamplot(q1, q2, + vel_drift_x, vel_drift_y, + density=2, color='blue', + linewidth=0.7, arrowsize=1 + ) +# pl.streamplot(q1, q2, +# vel_drift_x, vel_drift_y, +# density=3, color='blue', +# linewidth=0.8, arrowsize=1.1 +# ) + pl.xlim([domain.q1_start, domain.q1_end]) + pl.ylim([domain.q2_start, domain.q2_end]) + #pl.ylim([0, 5]) + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + pl.ylabel(r'$y\;(\mu \mathrm{m})$') + + pl.gca().annotate("+", xy=(-0.07, .9), xycoords=("axes fraction"), + ha="center", va="center", size=30, + bbox=dict(fc="white")) + pl.gca().annotate("-", xy=(1.05, .9), xycoords=("axes fraction"), + ha="center", va="center", size=30, + bbox=dict(fc="white", pad=6.5)) + + + pl.subplot(gs[1, 1]) + + pl.plot(time_array, input_signal_array) + pl.plot(time_array, sensor_normalized) + pl.axhline(0, color='black', linestyle='--') + pl.axvline(time_array[file_number], color='black', alpha=0.75) + pl.legend(['Source $I(t)$', 'Measured $V(t)$'], loc=(0.04, 1.125)) + pl.xlabel(r'Time (ps)') + pl.xlim([100, 200]) + pl.ylim([-1.1, 1.1]) + + + pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 1$ ps') + #pl.tight_layout() + pl.savefig('images/dump_' + '%06d'%file_number + '.png') + #pl.savefig('paper_plots/DC.png') + pl.clf() + + +#time_array = [] +#input_signal_array = [] +#sensor_1_signal_array = [] +#sensor_2_signal_array = [] +#for file_number, dump_file in enumerate(moment_files): +# +# print("file number = ", file_number, "of ", moment_files.size) +# +# h5f = h5py.File(dump_file, 'r') +# moments = np.swapaxes(h5f['moments'][:], 0, 1) +# h5f.close() +# +# density = moments[:, :, 0] +# +# source = np.mean(density[0, source_indices]) +# drain = np.mean(density[-1, drain_indices]) +# +# sensor_1_left = np.mean(density[0, sensor_1_left_indices] ) +# sensor_1_right = np.mean(density[-1, sensor_1_right_indices]) +# #sensor_1_right = np.mean(density[0, sensor_1_right_indices]) +# +# sensor_2_left = np.mean(density[0, sensor_2_left_indices] ) +# sensor_2_right = np.mean(density[-1, sensor_2_right_indices]) +# +# #sensor_1_left = density[0, q2>source_end] +# #sensor_1_right = density[-1, q2>source_end] +# +# input_signal = source - drain +# sensor_1_signal = sensor_1_left - sensor_1_right +# sensor_2_signal = sensor_2_left - sensor_2_right +# +# time_array.append(file_number*dt*dump_interval) +# input_signal_array.append(input_signal) +# sensor_1_signal_array.append(sensor_1_signal) +# sensor_2_signal_array.append(sensor_2_signal) +# +##pl.rcParams['figure.figsize'] = 12, 8 +## +#AC_freq = 5.5/100 +#time_array = np.array(time_array) +#input_signal_array = np.sin(2.*np.pi*AC_freq*time_array) +#sensor_1_signal_array = np.array(sensor_1_signal_array) +###np.savetxt('drive.txt', input_signal_array) +##np.savetxt('paper_plots/sensor_tau_ee_0.2_tau_D_5.txt', sensor_1_signal_array) +##np.savetxt('time.txt', time_array) +## +##print("sensor.shape = ", sensor_1_signal_array.shape) +##sensor_2_signal_array = np.array(sensor_2_signal_array) +## +#half_time = (int)(time_array.size/2) +#pl.plot(time_array, input_signal_array/np.max(input_signal_array[half_time:])) +#pl.plot(time_array, +# sensor_1_signal_array/np.max(sensor_1_signal_array[half_time:]) +# ) +##pl.plot(time_array, +## sensor_2_signal_array/np.max(sensor_2_signal_array[half_time:]) +## ) +#pl.xlabel(r"Time (ps)") +#pl.ylim([-1.1, 1.1]) +#pl.legend(['Input', 'Sensor 1', 'Sensor 2']) +#pl.savefig('paper_plots/IV_55_Ghz_tau_ee_0.2_tau_D_5.png') +##half_time = 0 +#input_normalized = input_signal_array[half_time:]/np.max(input_signal_array[half_time:]) +#sensor_normalized = sensor_1_signal_array[half_time:]/np.max(sensor_1_signal_array[half_time:]) +# +## Calculate the phase diff. Copied from: +## https://stackoverflow.com/questions/6157791/find-phase-difference-between-two-inharmonic-waves +#corr = correlate(input_normalized, sensor_normalized) +#nsamples = input_normalized.size +#time_corr = time_array[half_time:] +#dt_corr = np.linspace(-time_corr[-1] + time_corr[0], +# time_corr[-1] - time_corr[0], 2*nsamples-1) +#time_shift = dt_corr[corr.argmax()] +# +## force the phase shift to be in [-pi:pi] +#period = 1./AC_freq +#phase_diff = 2*np.pi*(((0.5 + time_shift/period) % 1.0) - 0.5) +#print("density.shape = ", density.shape) +#print("Phase diff = ", phase_diff) + +#phase_vs_x = [] +#for i in range(sensor_1_signal_array[0, :].size): +# signal = sensor_1_signal_array[:, i] +# corr = correlate(input_signal_array, signal) +# nsamples = input_signal_array.size +# half_time = 0 +# time_corr = time_array[half_time:] +# dt_corr = np.linspace(-time_corr[-1] + time_corr[0], +# time_corr[-1] - time_corr[0], +# 2*nsamples-1 +# ) +# time_shift = dt_corr[corr.argmax()] +# +# # force the phase shift to be in [-pi:pi] +# period = 1./params.AC_freq +# phase_diff = 2*np.pi*(((0.5 + time_shift/period) % 1.0) - 0.5) +# phase_vs_x.append(phase_diff) +# +#phase_vs_x = np.array(phase_vs_x) +#print("phase_vs_x.shape = ", phase_vs_x.shape) +#np.savetxt("paper_plots/phase_vs_x_tau_ee_0.2_tau_D_1.txt", phase_vs_x) +#np.savetxt("paper_plots/q2_tau_ee_0.2_tau_D_1.txt", q2) +#print("density.shape = ", density.shape) + + diff --git a/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/signals.py b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/signals.py new file mode 100644 index 00000000..62104908 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/signals.py @@ -0,0 +1,171 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +# Left needs to be near source, right sensor near drain +sensor_1_left_start = 8.5 # um +sensor_1_left_end = 9.5 # um + +sensor_1_right_start = 8.5 # um +sensor_1_right_end = 9.5 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +sensor_2_left_start = 6.5 # um +sensor_2_left_end = 7.5 # um + +sensor_2_right_start = 6.5 # um +sensor_2_right_end = 7.5 # um + +sensor_2_left_indices = (q2 > sensor_2_left_start ) & (q2 < sensor_2_left_end) +sensor_2_right_indices = (q2 > sensor_2_right_start) & (q2 < sensor_2_right_end) + +filepath = \ +'/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_1.0_tau_ee_0.2_tau_eph_0.5/dumps' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +sensor_1_signal_array = [] +print("Reading sensor signal...") +for file_number, dump_file in enumerate(moment_files): + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + density = moments[:, :, 0] + + source = np.mean(density[0, source_indices]) + drain = np.mean(density[-1, drain_indices]) + + sensor_1_left = np.mean(density[0, sensor_1_left_indices] ) + sensor_1_right = np.mean(density[-1, sensor_1_right_indices]) + + sensor_1_signal = sensor_1_left - sensor_1_right + + sensor_1_signal_array.append(sensor_1_signal) + +time_array = np.loadtxt("dump_time_array.txt") +AC_freq = 1./100 +input_signal_array = np.sin(2.*np.pi*AC_freq*time_array) +sensor_1_signal_array = np.array(sensor_1_signal_array) +half_time = (int)(time_array.size/2) + +input_normalized = \ + input_signal_array/np.max(np.abs(input_signal_array[half_time:])) +sensor_normalized = \ + sensor_1_signal_array/np.max(np.abs(sensor_1_signal_array[half_time:])) + +# Calculate the phase difference between input_signal_array and sensor_normalized +# Code copied from : +# https:/stackoverflow.com/questions/6157791/find-phase-difference-between-two-inharmonic-waves + +corr = correlate(input_normalized, sensor_normalized) +nsamples = input_normalized.size +time_corr = time_array[half_time:] +dt_corr = np.linspace(-time_corr[-1] + time_corr[0], + time_corr[-1] - time_corr[0], 2*nsamples-1) +time_shift = dt_corr[corr.argmax()] + +#Force the phase shift to be in [-pi:pi] +period = 1./AC_freq +phase_diff = 2*np.pi*(((0.5 + time_shift/period) % 1.0) - 0.5) + +pl.plot(time_array, input_signal_array) +pl.plot(time_array, sensor_normalized) +pl.axhline(0, color='black', linestyle='--') + +pl.legend(['Source $I(t)$', 'Measured $V(t)$'], loc=1) +pl.text(135, 1.14, '$\phi : %.2f \; rad$' %phase_diff) +pl.xlabel(r'Time (ps)') +pl.xlim([0, 200]) +pl.ylim([-1.1, 1.1]) + +pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 0.5$ ps') +pl.savefig('images/iv' + '.png') +pl.clf() + + diff --git a/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/vorticity.py b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/vorticity.py new file mode 100644 index 00000000..2f494c60 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/vorticity.py @@ -0,0 +1,136 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +filepath = \ +'/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_1.0_tau_ee_0.2_tau_eph_0.5/dumps' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +time_array = np.loadtxt("dump_time_array.txt") +half_time = (int)(time_array.size/2) + +for file_number, dump_file in yt.parallel_objects(enumerate(moment_files)): + + print("file number = ", file_number, "of ", moment_files.size) + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + + h5f = h5py.File(lagrange_multiplier_files[file_number], 'r') + lagrange_multipliers = h5f['lagrange_multipliers'][:] + h5f.close() + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + + + dq1 = (domain.q1_end - domain.q1_start)/domain.N_q1 + dq2 = (domain.q2_end - domain.q2_start)/domain.N_q2 + + dvx_dx, dvx_dy = np.gradient(j_x/density, dq1, dq2) + dvy_dx, dvy_dy = np.gradient(j_y/density, dq1, dq2) + + vorticity = dvy_dx - dvx_dy + + pl.contourf(q1_meshgrid, q2_meshgrid, vorticity, 100, cmap='bwr') + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + + pl.streamplot(q1, q2, + vel_drift_x, vel_drift_y, + density=2, color='blue', + linewidth=0.7, arrowsize=1 + ) + + pl.xlim([domain.q1_start, domain.q1_end]) + pl.ylim([domain.q2_start, domain.q2_end]) + + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + pl.ylabel(r'$y\;(\mu \mathrm{m})$') + pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 1.0$ ps') + pl.savefig('vorticity_images/dump_' + '%06d'%file_number + '.png') + pl.clf() + diff --git a/example_problems/electronic_boltzmann/graphene/post/momentum_space_movie.py b/example_problems/electronic_boltzmann/graphene/post/momentum_space_movie.py new file mode 100644 index 00000000..f82105ea --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/post/momentum_space_movie.py @@ -0,0 +1,112 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +import domain +import boundary_conditions +import params +import initialize + + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - \ + domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - \ + domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 + +p1 = domain.p1_start[0] + (0.5 + np.arange(N_p1)) * (domain.p1_end[0] - \ + domain.p1_start[0])/N_p1 +p2 = domain.p2_start[0] + (0.5 + np.arange(N_p2)) * (domain.p2_end[0] - \ + domain.p2_start[0])/N_p2 + +p2_meshgrid, p1_meshgrid = np.meshgrid(p2, p1) + +filepath = \ +'/home/mchandra/gitansh/bolt_master/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/dumps' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) +distribution_function_files = np.sort(glob.glob(filepath+'/f_*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +time_array = np.loadtxt("dump_time_array.txt") + +h5f = h5py.File(distribution_function_files[0], 'r') +dist_func_background = h5f['distribution_function'][:] +h5f.close() + +q1_position = 10 +q2_position = 100 + +for file_number, dump_file in yt.parallel_objects(enumerate(distribution_function_files)): + + print("file number = ", file_number, "of ", distribution_function_files.size) + + h5f = h5py.File(distribution_function_files[file_number], 'r') + dist_func = h5f['distribution_function'][:] + h5f.close() + + + f_at_desired_q = np.reshape((dist_func - dist_func_background)[q2_position, q1_position, :], + [N_p1, N_p2] + ) + pl.contourf(p1_meshgrid, p2_meshgrid, f_at_desired_q, 100, cmap='bwr') + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.xlabel('$p_x$') + pl.ylabel('$p_y$') + pl.gca().set_aspect('equal') + pl.colorbar() + pl.savefig('images/dist_func_' + '%06d'%file_number + '.png') + pl.clf() + diff --git a/example_problems/electronic_boltzmann/graphene/post/movie.py b/example_problems/electronic_boltzmann/graphene/post/movie.py new file mode 100644 index 00000000..44c4aaee --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/post/movie.py @@ -0,0 +1,142 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +import domain +import boundary_conditions +import params +import initialize + + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +# Left needs to be near source, right sensor near drain +sensor_1_left_start = 8.5 # um +sensor_1_left_end = 9.5 # um + +sensor_1_right_start = 8.5 # um +sensor_1_right_end = 9.5 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +sensor_2_left_start = 6.5 # um +sensor_2_left_end = 7.5 # um + +sensor_2_right_start = 6.5 # um +sensor_2_right_end = 7.5 # um + +sensor_2_left_indices = (q2 > sensor_2_left_start ) & (q2 < sensor_2_left_end) +sensor_2_right_indices = (q2 > sensor_2_right_start) & (q2 < sensor_2_right_end) + +filepath = \ +'/home/mchandra/gitansh/bolt_master/example_problems/electronic_boltzmann/graphene/L_5.0_10.0_tau_ee_0.2_tau_eph_1.0/dumps' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +time_array = np.loadtxt("dump_time_array.txt") + +for file_number, dump_file in yt.parallel_objects(enumerate(moment_files)): + + print("file number = ", file_number, "of ", moment_files.size) + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + + pl.contourf(q1_meshgrid, q2_meshgrid, density, 100, cmap='bwr') + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + + + h5f = h5py.File(lagrange_multiplier_files[file_number], 'r') + lagrange_multipliers = h5f['lagrange_multipliers'][:] + h5f.close() + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + + pl.streamplot(q1, q2, + vel_drift_x, vel_drift_y, + density=2, color='blue', + linewidth=0.7, arrowsize=1 + ) + + pl.xlim([q1[0], q1[-1]]) + pl.ylim([q2[0], q2[-1]]) + + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + pl.ylabel(r'$y\;(\mu \mathrm{m})$') + pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 1.0$ ps') + pl.savefig('images/dump_' + '%06d'%file_number + '.png') + pl.clf() + diff --git a/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/PetscBinaryIO.py b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/PetscBinaryIO.py new file mode 100755 index 00000000..fd0e48e9 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/PetscBinaryIO.py @@ -0,0 +1,479 @@ +"""PetscBinaryIO +=============== + +Provides + 1. PETSc-named objects Vec, Mat, and IS that inherit numpy.ndarray + 2. A class to read and write these objects from PETSc binary files. + +The standard usage of this module should look like: + + >>> import PetscBinaryIO + >>> io = PetscBinaryIO.PetscBinaryIO() + >>> objects = io.readBinaryFile('file.dat') + +or + + >>> import PetscBinaryIO + >>> import numpy + >>> vec = numpy.array([1., 2., 3.]).view(PetscBinaryIO.Vec) + >>> io = PetscBinaryIO.PetscBinaryIO() + >>> io.writeBinaryFile('file.dat', [vec,]) + +to read in objects one at a time use such as + + >>> import PetscBinaryIO + >>> io = PetscBinaryIO.PetscBinaryIO() + >>> fh = open('file.dat') + >>> objecttype = io.readObjectType(fh) + >>> if objecttype == 'Vec': + >>> v = io.readVec(fh) + + Note that one must read in the object type first and then call readVec(), readMat() etc. + + +See also PetscBinaryIO.__doc__ and methods therein. +""" + +import numpy as np +import functools + +try: + basestring # Python-2 has basestring as a common parent of unicode and str +except NameError: + basestring = str # Python-3 is unicode through and through + +def update_wrapper_with_doc(wrapper, wrapped): + """Similar to functools.update_wrapper, but also gets the wrapper's __doc__ string""" + wdoc = wrapper.__doc__ + + functools.update_wrapper(wrapper, wrapped) + if wdoc is not None: + if wrapper.__doc__ is None: + wrapper.__doc__ = wdoc + else: + wrapper.__doc__ = wrapper.__doc__ + wdoc + return wrapper + +def wraps_with_doc(wrapped): + """Similar to functools.wraps, but also gets the wrapper's __doc__ string""" + return functools.partial(update_wrapper_with_doc, wrapped=wrapped) + +def decorate_with_conf(f): + """Decorates methods to take kwargs for precisions.""" + @wraps_with_doc(f) + def decorated_f(self, *args, **kwargs): + """ + Additional kwargs: + precision: 'single', 'double', 'longlong' for scalars + indices: '32bit', '64bit' integer size + complexscalars: True/False + + Note these are set in order of preference: + 1. kwargs if given here + 2. PetscBinaryIO class __init__ arguments + 3. PETSC_DIR/PETSC_ARCH defaults + """ + + changed = False + old_precision = self.precision + old_indices = self.indices + old_complexscalars = self.complexscalars + + try: + self.precision = kwargs.pop('precision') + except KeyError: + pass + else: + changed = True + + try: + self.indices = kwargs.pop('indices') + except KeyError: + pass + else: + changed = True + + try: + self.complexscalars = kwargs.pop('complexscalars') + except KeyError: + pass + else: + changed = True + + if changed: + self._update_dtypes() + + result = f(self, *args, **kwargs) + + if changed: + self.precision = old_precision + self.indices = old_indices + self.complexscalars = old_complexscalars + self._update_dtypes() + + return result + return decorated_f + + +class DoneWithFile(Exception): pass + + +class Vec(np.ndarray): + """Vec represented as 1D numpy array + + The best way to instantiate this class for use with writeBinaryFile() + is through the numpy view method: + + vec = numpy.array([1,2,3]).view(Vec) + """ + _classid = 1211214 + + +class MatDense(np.matrix): + """Mat represented as 2D numpy array + + The best way to instantiate this class for use with writeBinaryFile() + is through the numpy view method: + + mat = numpy.array([[1,0],[0,1]]).view(Mat) + """ + _classid = 1211216 + + +class MatSparse(tuple): + """Mat represented as CSR tuple ((M, N), (rowindices, col, val)) + + This should be instantiated from a tuple: + + mat = MatSparse( ((M,N), (rowindices,col,val)) ) + """ + _classid = 1211216 + def __repr__(self): + return 'MatSparse: %s'%super(MatSparse, self).__repr__() + + +class IS(np.ndarray): + """IS represented as 1D numpy array + + The best way to instantiate this class for use with writeBinaryFile() + is through the numpy "view" method: + + an_is = numpy.array([3,4,5]).view(IS) + """ + _classid = 1211218 + + +class PetscBinaryIO(object): + """Reader/Writer class for PETSc binary files. + + Note that by default, precisions for both scalars and indices, as well as + complex scalars, are picked up from the PETSC_DIR/PETSC_ARCH configuration + as set by environmental variables. + + Alternatively, defaults can be overridden at class instantiation, or for + a given method call. + """ + + _classid = {1211216:'Mat', + 1211214:'Vec', + 1211218:'IS', + 1211219:'Bag'} + + def __init__(self, precision=None, indices=None, complexscalars=None): + if (precision is None) or (indices is None) or (complexscalars is None): + import petsc_conf + defaultprecision, defaultindices, defaultcomplexscalars = petsc_conf.get_conf() + if precision is None: + if defaultprecision is None: + precision = 'double' + else: + precision = defaultprecision + + if indices is None: + if defaultindices is None: + indices = '32bit' + else: + indices = defaultindices + + if complexscalars is None: + if defaultcomplexscalars is None: + complexscalars = False + else: + complexscalars = defaultcomplexscalars + + self.precision = precision + self.indices = indices + self.complexscalars = complexscalars + self._update_dtypes() + + def _update_dtypes(self): + if self.indices == '64bit': + self._inttype = np.dtype('>i8') + else: + self._inttype = np.dtype('>i4') + + if self.precision == 'longlong': + nbyte = 16 + elif self.precision == 'single': + nbyte = 4 + else: + nbyte = 8 + + if self.complexscalars: + name = 'c' + nbyte = nbyte * 2 # complex scalar takes twice as many bytes + else: + name = 'f' + + self._scalartype = '>{0}{1}'.format(name, nbyte) + + @decorate_with_conf + def readVec(self, fh): + """Reads a PETSc Vec from a binary file handle, must be called after readObjectType().""" + + nz = np.fromfile(fh, dtype=self._inttype, count=1)[0] + try: + vals = np.fromfile(fh, dtype=self._scalartype, count=nz) + except MemoryError: + raise IOError('Inconsistent or invalid Vec data in file') + if (len(vals) is 0): + raise IOError('Inconsistent or invalid Vec data in file') + return vals.view(Vec) + + @decorate_with_conf + def writeVec(self, fh, vec): + """Writes a PETSc Vec to a binary file handle.""" + + metadata = np.array([Vec._classid, len(vec)], dtype=self._inttype) + metadata.tofile(fh) + vec.astype(self._scalartype).tofile(fh) + return + + @decorate_with_conf + def readMatSparse(self, fh): + """Reads a PETSc Mat, returning a sparse representation of the data. Must be called after readObjectType() + + (M,N), (I,J,V) = readMatSparse(fid) + + Input: + fid : file handle to open binary file. + Output: + M,N : matrix size + I,J : arrays of row and column for each nonzero + V: nonzero value + """ + + try: + M,N,nz = np.fromfile(fh, dtype=self._inttype, count=3) + I = np.empty(M+1, dtype=self._inttype) + I[0] = 0 + rownz = np.fromfile(fh, dtype=self._inttype, count=M) + np.cumsum(rownz, out=I[1:]) + assert I[-1] == nz + + J = np.fromfile(fh, dtype=self._inttype, count=nz) + assert len(J) == nz + V = np.fromfile(fh, dtype=self._scalartype, count=nz) + assert len(V) == nz + except (AssertionError, MemoryError, IndexError): + raise IOError('Inconsistent or invalid Mat data in file') + + return MatSparse(((M, N), (I, J, V))) + + @decorate_with_conf + def writeMatSparse(self, fh, mat): + """Writes a Mat into a PETSc binary file handle""" + + ((M,N), (I,J,V)) = mat + metadata = np.array([MatSparse._classid,M,N,I[-1]], dtype=self._inttype) + rownz = I[1:] - I[:-1] + + assert len(J.shape) == len(V.shape) == len(I.shape) == 1 + assert len(J) == len(V) == I[-1] == rownz.sum() + assert (rownz > -1).all() + + metadata.tofile(fh) + rownz.astype(self._inttype).tofile(fh) + J.astype(self._inttype).tofile(fh) + V.astype(self._scalartype).tofile(fh) + return + + @decorate_with_conf + def readMatDense(self, fh): + """Reads a PETSc Mat, returning a dense represention of the data, must be called after readObjectType()""" + + try: + M,N,nz = np.fromfile(fh, dtype=self._inttype, count=3) + I = np.empty(M+1, dtype=self._inttype) + I[0] = 0 + rownz = np.fromfile(fh, dtype=self._inttype, count=M) + np.cumsum(rownz, out=I[1:]) + assert I[-1] == nz + + J = np.fromfile(fh, dtype=self._inttype, count=nz) + assert len(J) == nz + V = np.fromfile(fh, dtype=self._scalartype, count=nz) + assert len(V) == nz + + except (AssertionError, MemoryError, IndexError): + raise IOError('Inconsistent or invalid Mat data in file') + + mat = np.zeros((M,N), dtype=self._scalartype) + for row in range(M): + rstart, rend = I[row:row+2] + mat[row, J[rstart:rend]] = V[rstart:rend] + return mat.view(MatDense) + + @decorate_with_conf + def readMatSciPy(self, fh): + from scipy.sparse import csr_matrix + (M, N), (I, J, V) = self.readMatSparse(fh) + return csr_matrix((V, J, I), shape=(M, N)) + + @decorate_with_conf + def writeMatSciPy(self, fh, mat): + from scipy.sparse import csr_matrix + if hasattr(mat, 'tocsr'): + mat = mat.tocsr() + assert isinstance(mat, csr_matrix) + V = mat.data + M,N = mat.shape + J = mat.indices + I = mat.indptr + return self.writeMatSparse(fh, (mat.shape, (mat.indptr,mat.indices,mat.data))) + + @decorate_with_conf + def readMat(self, fh, mattype='sparse'): + """Reads a PETSc Mat from binary file handle, must be called after readObjectType() + + optional mattype: 'sparse" or 'dense' + + See also: readMatSparse, readMatDense + """ + + if mattype == 'sparse': + return self.readMatSparse(fh) + elif mattype == 'dense': + return self.readMatDense(fh) + elif mattype == 'scipy.sparse': + return self.readMatSciPy(fh) + else: + raise RuntimeError('Invalid matrix type requested: choose sparse/dense/scipy.sparse') + + @decorate_with_conf + def readIS(self, fh): + """Reads a PETSc Index Set from binary file handle, must be called after readObjectType()""" + + try: + nz = np.fromfile(fh, dtype=self._inttype, count=1)[0] + v = np.fromfile(fh, dtype=self._inttype, count=nz) + assert len(v) == nz + except (MemoryError,IndexError): + raise IOError('Inconsistent or invalid IS data in file') + return v.view(IS) + + @decorate_with_conf + def writeIS(self, fh, anis): + """Writes a PETSc IS to binary file handle.""" + + metadata = np.array([IS._classid, len(anis)], dtype=self._inttype) + metadata.tofile(fh) + anis.astype(self._inttype).tofile(fh) + return + + @decorate_with_conf + def readObjectType(self, fid): + """Returns the next object type as a string in the file""" + try: + header = np.fromfile(fid, dtype=self._inttype, count=1)[0] + except (MemoryError, IndexError): + raise DoneWithFile + try: + objecttype = self._classid[header] + except KeyError: + raise IOError('Invalid PetscObject CLASSID or object not implemented for python') + return objecttype + + @decorate_with_conf + def readBinaryFile(self, fid, mattype='sparse'): + """Reads a PETSc binary file, returning a tuple of the contained objects. + + objects = self.readBinaryFile(fid, **kwargs) + + Input: + fid : either file name or handle to an open binary file. + + Output: + objects : tuple of objects representing the data in numpy arrays. + + Optional: + mattype : + 'sparse': Return matrices as raw CSR: (M, N), (row, col, val). + 'dense': Return matrices as MxN numpy arrays. + 'scipy.sparse': Return matrices as scipy.sparse objects. + """ + + close = False + + if isinstance(fid, basestring): + fid = open(fid, 'rb') + close = True + + objects = [] + try: + while True: + objecttype = self.readObjectType(fid) + + if objecttype == 'Vec': + objects.append(self.readVec(fid)) + elif objecttype == 'IS': + objects.append(self.readIS(fid)) + elif objecttype == 'Mat': + objects.append(self.readMat(fid,mattype)) + elif objecttype == 'Bag': + raise NotImplementedError('Bag Reader not yet implemented') + except DoneWithFile: + pass + finally: + if close: + fid.close() + + return tuple(objects) + + @decorate_with_conf + def writeBinaryFile(self, fid, objects): + """Writes a PETSc binary file containing the objects given. + + readBinaryFile(fid, objects) + + Input: + fid : either file handle to an open binary file, or filename. + objects : list of objects representing the data in numpy arrays, + which must be of type Vec, IS, MatSparse, or MatSciPy. + """ + close = False + if isinstance(fid, basestring): + fid = open(fid, 'wb') + close = True + + for petscobj in objects: + if (isinstance(petscobj, Vec)): + self.writeVec(fid, petscobj) + elif (isinstance(petscobj, IS)): + self.writeIS(fid, petscobj) + elif (isinstance(petscobj, MatSparse)): + self.writeMatSparse(fid, petscobj) + elif (isinstance(petscobj, MatDense)): + if close: + fid.close() + raise NotImplementedError('Writing a dense matrix is not yet supported') + else: + try: + self.writeMatSciPy(fid, petscobj) + except AssertionError: + if close: + fid.close() + raise TypeError('Object %s is not a valid PETSc object'%(petscobj.__repr__())) + if close: + fid.close() + return diff --git a/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/README.txt b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/README.txt new file mode 100644 index 00000000..057b5bb9 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/README.txt @@ -0,0 +1,16 @@ +To switch between 1D/2D polar and cartesian momentum space, the following changes need +to be made : + + +1. domain + - Change p2_start, p2_end and N_p2 +2. params + - Change p_space_grid + - Change p_dim (if switching between 1D and 2D representation in p-space) +3. initialize : No change +4. main : No change +i5. boundary_conditions : No change + + + +PdCoO2 works only with the polar2D grid in momentum space for the moment. diff --git a/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/boundary_conditions.py b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/boundary_conditions.py new file mode 100644 index 00000000..762f5e79 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/boundary_conditions.py @@ -0,0 +1,107 @@ +import numpy as np +import arrayfire as af +import domain + +in_q1_left = 'mirror+dirichlet' +in_q1_right = 'mirror+dirichlet' +in_q2_bottom = 'mirror' +in_q2_top = 'mirror' + +@af.broadcast +def f_left(f, t, q1, q2, p1, p2, p3, params): + + k = params.boltzmann_constant + E_upper = params.E_band + T = params.initial_temperature + mu = params.initial_mu + + t = params.current_time + omega = 2. * np.pi * params.AC_freq + vel_drift_x_in = params.vel_drift_x_in + + if (params.p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (params.p_space_grid == 'polar2D'): + p_x = p1 * af.cos(p2) + p_y = p1 * af.sin(p2) + else: + raise NotImplementedError('Unsupported coordinate system in p_space') + + + fermi_dirac_in = (1./(af.exp( (E_upper - vel_drift_x_in*p_x - mu)/(k*T) ) + 1.) + ) + + if (params.contact_geometry=="straight"): + # Contacts on either side of the device + + q2_contact_start = params.contact_start + q2_contact_end = params.contact_end + + cond = ((q2 >= q2_contact_start) & \ + (q2 <= q2_contact_end) \ + ) + + f_left = cond*fermi_dirac_in + (1 - cond)*f + + elif (params.contact_geometry=="turn_around"): + # Contacts on the same side of the device + + vel_drift_x_out = -params.vel_drift_x_in * np.sin(omega*t) + + fermi_dirac_out = (1./(af.exp( (E_upper - vel_drift_x_out*p_x - mu)/(k*T) ) + 1.) + ) + + # TODO: set these parameters in params.py + cond_in = ((q2 >= 3.5) & (q2 <= 4.5)) + cond_out = ((q2 >= 5.5) & (q2 <= 6.5)) + + f_left = cond_in*fermi_dirac_in + cond_out*fermi_dirac_out \ + + (1 - cond_in)*(1 - cond_out)*f + + af.eval(f_left) + return(f_left) + +@af.broadcast +def f_right(f, t, q1, q2, p1, p2, p3, params): + + k = params.boltzmann_constant + E_upper = params.E_band + T = params.initial_temperature + mu = params.initial_mu + + t = params.current_time + omega = 2. * np.pi * params.AC_freq + vel_drift_x_out = params.vel_drift_x_out + + if (params.p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (params.p_space_grid == 'polar2D'): + p_x = p1 * af.cos(p2) + p_y = p1 * af.sin(p2) + else: + raise NotImplementedError('Unsupported coordinate system in p_space') + + fermi_dirac_out = (1./(af.exp( (E_upper - vel_drift_x_out*p_x - mu)/(k*T) ) + 1.) + ) + + if (params.contact_geometry=="straight"): + # Contacts on either side of the device + + q2_contact_start = params.contact_start + q2_contact_end = params.contact_end + + cond = ((q2 >= q2_contact_start) & \ + (q2 <= q2_contact_end) \ + ) + + f_right = cond*fermi_dirac_out + (1 - cond)*f + + elif (params.contact_geometry=="turn_around"): + # Contacts on the same side of the device + + f_right = f + + af.eval(f_right) + return(f_right) diff --git a/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/check.py b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/check.py new file mode 100644 index 00000000..71fe46ef --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/check.py @@ -0,0 +1,42 @@ +import numpy as np +import params +import arrayfire as af +import pylab as pl + +import domain + +from bolt.src.electronic_boltzmann.utils.polygon import polygon + +p2_start = -np.pi +p2_end = np.pi +N_p2 = domain.N_p2 +theta = \ + p2_start + (0.5 + np.arange(N_p2))*(p2_end - p2_start)/N_p2 + +theta = af.from_ndarray(theta) + +hexa = polygon(6, theta, rotation = np.pi/6) +hexa = hexa.to_ndarray() + +#pl.polar(theta, hexa) + +#pl.plot(theta, hexa * np.cos(theta)) +#pl.plot(theta, hexa * np.sin(theta)) + +pl.gca().set_aspect(1) +pl.plot(hexa*np.cos(theta), hexa*np.sin(theta)) + +#p_hat_0_old = np.loadtxt("P_hat_0_old.txt") +#p_hat_1_old = np.loadtxt("P_hat_1_old.txt") + +#p_hat_0 = np.loadtxt("P_hat_0.txt") +#p_hat_1 = np.loadtxt("P_hat_1.txt") + +#pl.plot(theta, p_hat_0_old) +#pl.plot(theta, p_hat_1_old) + +#pl.plot(theta, p_hat_0, '--') +#pl.plot(theta, p_hat_1, '--') + + +pl.savefig("images/test.png") diff --git a/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/domain.py b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/domain.py new file mode 100644 index 00000000..96ac75e4 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/domain.py @@ -0,0 +1,67 @@ +import numpy as np +import params + +q1_start = 0. +q1_end = 1.0 +N_q1 = 20 + +q2_start = 0. +q2_end = 1.25 +N_q2 = 25 + +# If N_p1 > 1, mirror boundary conditions require p1 to be +# symmetric about zero +# TODO : Check and fix discrepancy between this and the claim +# that p1_center = mu in polar representation +N_p1 = 1 # Set equal to 1 for 1D polar + +# In the cartesian representation of momentum space, +# p1 = p_x (magnitude of momentum) +# p1_start and p1_end are set such that p1_center is 0 + +# Uncomment the following for the cartesian representation of momentum space +#p1_start = [-0.04] +#p1_end = [0.04] + + +# In the 2D polar representation of momentum space, +# p1 = p_r (magnitude of momentum) +# p1_start and p1_end are set such that p1_center is mu + +# Uncomment the following for the 2D polar representation of momentum space +#p1_start = [params.initial_mu - \ +# 16.*params.boltzmann_constant*params.initial_temperature] +#p1_end = [params.initial_mu + \ +# 16.*params.boltzmann_constant*params.initial_temperature] + +# Uncomment the following for the 1D polar representation of momentum space +p1_start = [0.5*params.initial_mu/params.fermi_velocity] +p1_end = [1.5*params.initial_mu/params.fermi_velocity] + + +# If N_p2 > 1, mirror boundary conditions require p2 to be +# symmetric about zero +N_p2 = 2048 + +# In the cartesian representation of momentum space, +# p2 = p_y (magnitude of momentum) +# p2_start and p2_end are set such that p2_center is 0 +#p2_start = [-0.04] +#p2_end = [0.04] + +# In the 2D polar representation of momentum space, +# p2 = p_theta (angle of momentum) +# N_p_theta MUST be even. +#p2_start = [-np.pi] +#p2_end = [np.pi] +p2_start = [-3.14159265359] +p2_end = [3.14159265359] + +# If N_p3 > 1, mirror boundary conditions require p3 to be +# symmetric about zero + +p3_start = [-0.5] +p3_end = [0.5] +N_p3 = 1 + +N_ghost = 2 diff --git a/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/edge_density.py b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/edge_density.py new file mode 100644 index 00000000..3697590e --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/edge_density.py @@ -0,0 +1,122 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +#import yt +#yt.enable_parallelism() +import os + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +import PetscBinaryIO + +import domain +import boundary_conditions +import params +import initialize + + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +# Left needs to be near source, right sensor near drain +sensor_1_left_start = 8.5 # um +sensor_1_left_end = 9.5 # um + +sensor_1_right_start = 8.5 # um +sensor_1_right_end = 9.5 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +io = PetscBinaryIO.PetscBinaryIO() + +filepath = os.getcwd() +moment_files = np.sort(glob.glob(filepath+'/dump_moments/*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/dump_lagrange_multipliers/*.bin')) + +dt = params.dt +dump_interval = params.dump_steps + +sensor_1_signal_array = [] +print("Reading sensor signal...") +for file_number, dump_file in enumerate(moment_files): + + moments = io.readBinaryFile(dump_file) + moments = moments[0].reshape(N_q2, N_q1, 3) + + density = moments[:, :, 0] + + source = np.mean(density[source_indices, 0]) + drain = np.mean(density[drain_indices, -1]) + + sensor_1_left = np.mean(density[0, 0]) + sensor_1_right = np.mean(density[0, -1]) + + sensor_1_signal = sensor_1_left - sensor_1_right + + sensor_1_signal_array.append(sensor_1_signal) + +time_array = np.loadtxt("dump_time_array.txt") +AC_freq = 1./100 +input_signal_array = np.sin(2.*np.pi*AC_freq*time_array) +sensor_1_signal_array = np.array(sensor_1_signal_array) +half_time = (int)(time_array.size/2) + +input_normalized = \ + input_signal_array/np.max(np.abs(input_signal_array[half_time:])) +sensor_normalized = \ + sensor_1_signal_array#/np.max(np.abs(sensor_1_signal_array[half_time:])) + diff --git a/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/edge_potential.py b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/edge_potential.py new file mode 100644 index 00000000..b50b3bf5 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/edge_potential.py @@ -0,0 +1,161 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 12, 7.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +# Left needs to be near source, right sensor near drain +sensor_1_left_start = 5.5 # um +sensor_1_left_end = 10.0 # um + +sensor_1_right_start = 5.5 # um +sensor_1_right_end = 10.0 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +sensor_2_left_start = 6.5 # um +sensor_2_left_end = 7.5 # um + +sensor_2_right_start = 6.5 # um +sensor_2_right_end = 7.5 # um + +sensor_2_left_indices = (q2 > sensor_2_left_start ) & (q2 < sensor_2_left_end) +sensor_2_right_indices = (q2 > sensor_2_right_start) & (q2 < sensor_2_right_end) + +filepath = \ +'/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_1.0_tau_ee_0.2_tau_eph_0.5/dumps' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +sensor_1_signal_array = [] +#sensor_2_signal_array = [] +#print("Reading sensor signal...") +print("Loading data...") +density = [] +edge_density = [] +for file_number, dump_file in enumerate(moment_files): + + print("File number = ", file_number, ' of ', moment_files.size) + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + density.append(moments[:, :, 0]) + edge_density.append(density[file_number][0, sensor_1_left_indices]) + +density = np.array(density) +edge_density = np.array(edge_density) + +mean_density = np.mean(density) +max_density = np.max(density) +min_density = np.min(density) + +np.savetxt("edge_density.txt", edge_density) + +print("Dumping data...") +for file_number in yt.parallel_objects(range(density.shape[0])): + + print("File number = ", file_number, ' of ', moment_files.size) + + pl.semilogy(q2[sensor_1_left_indices], + density[file_number][0, sensor_1_left_indices], + ) + #pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.title(r'Time = ' + "%.2f"%(file_number*dt*dump_interval) + " ps") + + pl.xlim([sensor_1_left_start, sensor_1_left_end]) + #pl.ylim([min_density-mean_density, max_density-mean_density]) + #pl.ylim([0., np.log(max_density)]) + + #pl.gca().set_aspect('equal') + #pl.xlabel(r'$x\;(\mu \mathrm{m})$') + #pl.ylabel(r'$y\;(\mu \mathrm{m})$') + + #pl.suptitle('$\\tau_\mathrm{mc} = \infty$ ps, $\\tau_\mathrm{mr} = 3.0$ ps') + #pl.savefig('images/dump_' + '%06d'%file_number + '.png') + pl.savefig('images/density_' + '%06d'%file_number + '.png') + pl.clf() + + + diff --git a/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/enstrophy.py b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/enstrophy.py new file mode 100644 index 00000000..aeab5a28 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/enstrophy.py @@ -0,0 +1,142 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +filepath = \ +'/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_1.0_tau_ee_0.2_tau_eph_0.5/dumps' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +kinetic_energy_array = [] +enstrophy_array = [] +print("Reading kinetic energy and enstrophy signals...") +for file_number, dump_file in enumerate(moment_files): + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + + h5f = h5py.File(lagrange_multiplier_files[file_number], 'r') + lagrange_multipliers = h5f['lagrange_multipliers'][:] + h5f.close() + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + + dq1 = (domain.q1_end - domain.q1_start)/domain.N_q1 + dq2 = (domain.q2_end - domain.q2_start)/domain.N_q2 + + dvx_dx, dvx_dy = np.gradient(j_x/density, dq1, dq2) + dvy_dx, dvy_dy = np.gradient(j_y/density, dq1, dq2) + + vorticity = dvy_dx - dvx_dy + + kinetic_energy = 0.5 * np.sum(vel_drift_x**2 + vel_drift_y**2) * dq1 * dq2 + kinetic_energy_array.append(kinetic_energy) + + enstrophy = np.sum(vorticity**2) * dq1 * dq2 + enstrophy_array.append(enstrophy) + +time_array = np.loadtxt("dump_time_array.txt") +half_time = (int)(time_array.size/2) + +kinetic_energy_normalized = \ + kinetic_energy_array/np.max(np.abs(kinetic_energy_array[half_time:])) +enstrophy_normalized = \ + enstrophy_array/np.max(np.abs(enstrophy_array[half_time:])) + + +pl.plot(time_array, kinetic_energy_normalized) +pl.plot(time_array, enstrophy_normalized) +pl.axhline(0, color='black', linestyle='--') + +pl.legend(['Kinetic Energy', 'Enstrophy'], loc=1) +pl.xlabel(r'Time (ps)') +pl.xlim([0, 200]) +pl.ylim([-0.1, 1.1]) + +pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 1.0$ ps') +pl.savefig('vorticity_images/iv' + '.png') +pl.clf() + + diff --git a/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/initialize.py b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/initialize.py new file mode 100644 index 00000000..c2ee7948 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/initialize.py @@ -0,0 +1,99 @@ +""" +Functions which are used in assigning the I.C's to +the system. +""" + +import arrayfire as af +import numpy as np +from petsc4py import PETSc + +import domain + +def initialize_f(q1, q2, p1, p2, p3, params): + + PETSc.Sys.Print("Initializing f") + k = params.boltzmann_constant + + params.mu = 0.*q1 + params.initial_mu + params.T = 0.*q1 + params.initial_temperature + params.vel_drift_x = 0.*q1 + params.vel_drift_y = 0.*q1 + + params.mu_ee = params.mu.copy() + params.T_ee = params.T.copy() + params.vel_drift_x = 0.*q1 + 0e-3 + params.vel_drift_y = 0.*q1 + 0e-3 + + params.p_x, params.p_y = params.get_p_x_and_p_y(p1, p2) + params.E_band = params.band_energy(p1, p2) + params.vel_band = params.band_velocity(p1, p2) + + # Evaluating velocity space resolution for each species: + dp1 = []; dp2 = []; dp3 = [] + N_p1 = domain.N_p1; N_p2 = domain.N_p2; N_p3 = domain.N_p3 + p1_start = domain.p1_start; p1_end = domain.p1_end + p2_start = domain.p2_start; p2_end = domain.p2_end + p3_start = domain.p3_start; p3_end = domain.p3_end + + N_species = len(params.mass) + for i in range(N_species): + dp1.append((p1_end[i] - p1_start[i]) / N_p1) + dp2.append((p2_end[i] - p2_start[i]) / N_p2) + dp3.append((p3_end[i] - p3_start[i]) / N_p3) + + + theta = af.atan(params.p_y / params.p_x) + p_f = params.fermi_momentum_magnitude(theta) + + if (params.p_space_grid == 'cartesian'): + dp_x = dp1[0]; dp_y = dp2[0]; dp_z = dp3[0] + params.integral_measure = \ + (4./(2.*np.pi*params.h_bar)**2) * dp_z * dp_y * dp_x + + elif (params.p_space_grid == 'polar2D'): + # In polar2D coordinates, p1 = radius and p2 = theta + # Integral : \int delta(r - r_F) F(r, theta) r dr dtheta + r = p1; theta = p2 + dp_r = dp1[0]; dp_theta = dp2[0] + + if (params.zero_temperature): + # Assumption : F(r, theta) = delta(r-r_F)*F(theta) + params.integral_measure = \ + (4./(2.*np.pi*params.h_bar)**2) * p_f * dp_theta + + else: + params.integral_measure = \ + (4./(2.*np.pi*params.h_bar)**2) * r * dp_r * dp_theta + + + else : + raise NotImplementedError('Unsupported coordinate system in p_space') + + + + f = (1./(af.exp( (params.E_band - params.vel_drift_x*params.p_x + - params.vel_drift_y*params.p_y + - params.mu + )/(k*params.T) + ) + 1. + )) + + af.eval(f) + return(f) + + +def initialize_E(q1, q2, params): + + E1 = 0.*q1 + E2 = 0.*q1 + E3 = 0.*q1 + + return(E1, E2, E3) + +def initialize_B(q1, q2, params): + + B1 = 0.*q1 + B2 = 0.*q1 + B3 = 0.*q1 + + return(B1, B2, B3) diff --git a/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/job_script b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/job_script new file mode 100644 index 00000000..c99c662e --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/job_script @@ -0,0 +1,4 @@ +#!/bin/bash +#SBATCH -p gpu -n 1 --gres=gpu:1 -c1 --hint=nomultithread -t 2-00:00 +# (Note: use one MPI process per gpu, update both gres and -n together; max 6) +time mpirun python main.py -snes_monitor -snes_max_it 1 -snes_lag_jacobian_persists TRUE -snes_lag_jacobian 1000000 -snes_atol 1e-50 -snes_rtol 1e-50 > output.txt diff --git a/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/main.py b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/main.py new file mode 100644 index 00000000..09596215 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/main.py @@ -0,0 +1,172 @@ +import os +import arrayfire as af +import numpy as np +import math +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +from mpi4py import MPI +MPI.WTIME_IS_GLOBAL=True + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear.nonlinear_solver \ + import nonlinear_solver +#from bolt.lib.nonlinear.fields.fields.fields \ +# import fields_solver.compute_electrostatic_fields +from bolt.lib.utils.restart_latest import latest_output, format_time + +import domain +import boundary_conditions +import initialize +import params + +import bolt.src.electronic_boltzmann.advection_terms \ + as advection_terms +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator +import bolt.src.electronic_boltzmann.moments \ + as moments + + +# Create required folders if they do not exist already +#if not os.path.isdir("dump_f"): +# os.system("mkdir dump_f") +#if not os.path.isdir("dump_moments"): +# os.system("mkdir dump_moments") +#if not os.path.isdir("dump_lagrange_multipliers"): +# os.system("mkdir dump_lagrange_multipliers") +#if not os.path.isdir("images"): +# os.system("mkdir images") + + +# Defining the physical system to be solved: +system = physical_system(domain, + boundary_conditions, + params, + initialize, + advection_terms, + collision_operator.RTA, + moments + ) + +# Declaring a nonlinear system object which will evolve the defined physical system: +nls = nonlinear_solver(system) +N_g = domain.N_ghost +params.rank = nls._comm.rank + +# Time parameters: +dt = params.dt +t_final = params.t_final +params.current_time = time_elapsed = 0.0 +params.time_step = time_step = 0 +dump_counter = 0 +dump_time_array = [] + + +using_latest_restart = False +if(params.latest_restart == True): + latest_f, time_elapsed = latest_output('') + print(time_elapsed) + if(latest_f is not None and time_elapsed is not None): + nls.load_distribution_function(latest_f) + dump_time_array = np.loadtxt("dump_time_array.txt").tolist() + using_latest_restart = True + + +if using_latest_restart == False: + if(params.t_restart == 0 or params.latest_restart == True): + time_elapsed = 0 + formatted_time = format_time(time_elapsed) + nls.dump_distribution_function('dump_f/t=' + formatted_time) + nls.dump_moments('dump_moments/t=' + formatted_time) + nls.dump_aux_arrays([params.mu, + params.mu_ee, + params.T_ee, + params.vel_drift_x, params.vel_drift_y + ], + 'lagrange_multipliers', + 'dump_lagrange_multipliers/t=' + formatted_time + ) + dump_time_array.append(time_elapsed) + if (params.rank==0): + np.savetxt("dump_time_array.txt", dump_time_array) + else: + time_elapsed = params.t_restart + formatted_time = format_time(time_elapsed) + nls.load_distribution_function('dump_f/t=' + formatted_time) + +# Checking that the file writing intervals are greater than dt: +assert(params.dt_dump_f >= dt) +assert(params.dt_dump_moments >= dt) +assert(params.dt_dump_fields >= dt) + + +#if (params.restart): +# nls.load_distribution_function(params.restart_file) + +density = nls.compute_moments('density') +print("rank = ", params.rank, "\n", + " = ", af.mean(params.mu[0, 0, N_g:-N_g, N_g:-N_g]), "\n", + " max(mu) = ", af.max(params.mu[0, 0, N_g:-N_g, N_g:-N_g]), "\n", + " = ", af.mean(density[0, 0, N_g:-N_g, N_g:-N_g]), "i\n", + " max(n) = ", af.max(density[0, 0, N_g:-N_g, N_g:-N_g]), "\n" + ) + +nls.f = af.select(nls.f < 1e-20, 1e-20, nls.f) +while(time_elapsed < t_final): + + # Refine to machine error + if (time_step==0): + params.collision_nonlinear_iters = 10 + else: + params.collision_nonlinear_iters = params.collision_operator_nonlinear_iters + + dump_steps = params.dump_steps + + if(params.dt_dump_moments != 0): + # We step by delta_dt to get the values at dt_dump + delta_dt = (1 - math.modf(time_elapsed/params.dt_dump_moments)[0]) \ + * params.dt_dump_moments + + if((delta_dt-dt)<1e-5): + nls.strang_timestep(delta_dt) + time_elapsed += delta_dt + formatted_time = format_time(time_elapsed) + nls.dump_moments('dump_moments/t=' + formatted_time) + nls.dump_aux_arrays([params.mu, + params.mu_ee, + params.T_ee, + params.vel_drift_x, params.vel_drift_y + ], + 'lagrange_multipliers', + 'dump_lagrange_multipliers/t=' + formatted_time + ) + dump_time_array.append(time_elapsed) + if (params.rank==0): + np.savetxt("dump_time_array.txt", dump_time_array) + + if(math.modf(time_elapsed/params.dt_dump_f)[0] < 1e-12): + formatted_time = format_time(time_elapsed) + nls.dump_distribution_function('dump_f/t=' + formatted_time) + + PETSc.Sys.Print("Time step =", time_step, ", Time =", time_elapsed) + + nls.strang_timestep(dt) + time_elapsed = time_elapsed + dt + time_step = time_step + 1 + params.time_step = time_step + params.current_time = time_elapsed + + # Floors + nls.f = af.select(nls.f < 1e-20, 1e-20, nls.f) + + density = nls.compute_moments('density') + print("rank = ", params.rank, "\n", + " = ", af.mean(params.mu[0, 0, N_g:-N_g, N_g:-N_g]), "\n", + " max(mu) = ", af.max(params.mu[0, 0, N_g:-N_g, N_g:-N_g]), "\n", + " = ", af.mean(density[0, 0, N_g:-N_g, N_g:-N_g]), "\n", + " max(n) = ", af.max(density[0, 0, N_g:-N_g, N_g:-N_g]), "\n" + ) + PETSc.Sys.Print("--------------------\n") + +#nls.dump_distribution_function('dump_f/t_laststep') diff --git a/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/momentum_space_movie.py b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/momentum_space_movie.py new file mode 100644 index 00000000..1de644d7 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/momentum_space_movie.py @@ -0,0 +1,134 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import os +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1_start = domain.q1_start +q1_end = domain.q1_end +q2_start = domain.q2_start +q2_end = domain.q2_end + +q1 = q1_start + (0.5 + np.arange(N_q1)) * (q1_end - q1_start)/N_q1 +q2 = q2_start + (0.5 + np.arange(N_q2)) * (q2_end - q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 + +p1_start = domain.p1_start +p1_end = domain.p1_end +p2_start = domain.p2_start +p2_end = domain.p2_end + +p1 = p1_start[0] + (0.5 + np.arange(N_p1)) * (p1_end[0] - p1_start[0])/N_p1 +p2 = p2_start[0] + (0.5 + np.arange(N_p2)) * (p2_end[0] - p2_start[0])/N_p2 + +p1_meshgrid, p2_meshgrid = np.meshgrid(p1, p2) + +p_x = p1_meshgrid * np.cos(p2_meshgrid) +p_y = p1_meshgrid * np.sin(p2_meshgrid) + +#p2_meshgrid, p1_meshgrid = np.meshgrid(p2, p1) + +io = PetscBinaryIO.PetscBinaryIO() + +filepath = os.getcwd() + "/dumps" +moment_files = np.sort(glob.glob(filepath+'/moment*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) +dist_func_files = np.sort(glob.glob(filepath+'/f_*.bin')) + +dist_func_bg_file = dist_func_files[0] +dist_func_file = dist_func_files[-1] + +dist_func_background = io.readBinaryFile(dist_func_bg_file) +#dist_func_background = dist_func_background[0].reshape(N_q2, N_q1, N_p2, N_p1) +dist_func_background = dist_func_background[0].reshape(N_q1, N_q2, 1, 1, N_p2, N_p1) +dist_func = io.readBinaryFile(dist_func_file) + +print (dist_func[0].shape) + +dist_func = dist_func[0].reshape(N_q1, N_q2, 1, 1, N_p2, N_p1) + + +N = 7 +for index_1 in range(N): + for index_2 in range(N): + + q1_position = int(N_q1*((index_1/N)+(1/(2*N)))) + q2_position = int(N_q2*((index_2/N)+(1/(2*N)))) + + #a = np.max((dist_func - dist_func_background)[q2_position, q1_position, :, :]) + #b = np.abs(np.min((dist_func - dist_func_background)[q2_position, q1_position, :, :])) + #norm_factor = np.maximum(a, b) + #f_at_desired_q = \ + # np.reshape((dist_func-dist_func_background)[q2_position, q1_position, :, :], + # [N_p2, N_p1])/norm_factor + + f_at_desired_q = np.reshape((dist_func - \ + dist_func_background)[q1_position, q2_position, :], + [N_p2, N_p1] + ) + pl.contourf(p1_meshgrid, p2_meshgrid, f_at_desired_q, 100, cmap='bwr') + + #np.savetxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2), f_at_desired_q) + #f = np.loadtxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2)) + + + #pl.contourf(p_x, p_y, f_at_desired_q, 100, cmap='bwr') + #pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.xlabel('$p_x$') + pl.ylabel('$p_y$') + pl.gca().set_aspect('equal') + pl.savefig('images/dist_func_at_a_point_%d_%d.png'%(index_1, index_2)) + pl.clf() + diff --git a/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/momentum_space_movie_debug.py b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/momentum_space_movie_debug.py new file mode 100644 index 00000000..0b2c719d --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/momentum_space_movie_debug.py @@ -0,0 +1,182 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import os +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +#import yt +#yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain +import params + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_s = len(params.mass) # Number of species + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1_start = domain.q1_start +q1_end = domain.q1_end +q2_start = domain.q2_start +q2_end = domain.q2_end + +q1 = q1_start + (0.5 + np.arange(N_q1)) * (q1_end - q1_start)/N_q1 +q2 = q2_start + (0.5 + np.arange(N_q2)) * (q2_end - q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 +N_p3 = domain.N_p3 + +p1_start = domain.p1_start +p1_end = domain.p1_end +p2_start = domain.p2_start +p2_end = domain.p2_end + +p1 = p1_start[0] + (0.5 + np.arange(N_p1)) * (p1_end[0] - p1_start[0])/N_p1 +p2 = p2_start[0] + (0.5 + np.arange(N_p2)) * (p2_end[0] - p2_start[0])/N_p2 + +p1_meshgrid, p2_meshgrid = np.meshgrid(p1, p2) + +p_x = p1_meshgrid * np.cos(p2_meshgrid) +p_y = p1_meshgrid * np.sin(p2_meshgrid) + +#p2_meshgrid, p1_meshgrid = np.meshgrid(p2, p1) + +io = PetscBinaryIO.PetscBinaryIO() + +filepath = os.getcwd() +moment_files = np.sort(glob.glob(filepath+'/dump_moments/*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/dump_lagrange_multipliers/*.bin')) +dist_func_files = np.sort(glob.glob(filepath+'/dump_f/*.bin')) + +#moment_files = np.sort(glob.glob(filepath+'/dumps/moments*.bin')) +#lagrange_multiplier_files = \ +# np.sort(glob.glob(filepath+'/dumps/lagrange_multipliers*.bin')) +#dist_func_files = np.sort(glob.glob(filepath+'/dumps/f*.bin')) + +dist_func_bg_file = dist_func_files[0] +dist_func_file = dist_func_files[-1] + +print(dist_func_bg_file) +print(dist_func_file) + +dist_func_background = io.readBinaryFile(dist_func_bg_file) +#dist_func_background = dist_func_background[0].reshape(N_q2, N_q1, N_p2, N_p1) +dist_func_background = dist_func_background[0].reshape(N_q2, N_q1, N_s, N_p3, N_p2, N_p1) +dist_func = io.readBinaryFile(dist_func_file) + +print (dist_func[0].shape) + +dist_func = dist_func[0].reshape(N_q2, N_q1, N_s, N_p3, N_p2, N_p1) + +time_array = np.loadtxt("dump_time_array.txt") +file_number = -1 + +N = 7 +for index_1 in range(1): + for index_2 in range(N_q2): + + q1_position = index_1 + q2_position = index_2 + + a = np.max((dist_func - dist_func_background)[q2_position, q1_position, :, :]) + b = np.abs(np.min((dist_func - dist_func_background)[q2_position, q1_position, :, :])) + norm_factor = 1.#np.maximum(a, b) + f_at_desired_q = \ + np.reshape((dist_func - \ + dist_func_background)[q2_position, q1_position, :, :],\ + [N_p2, N_p1])/norm_factor + + im = pl.plot(p2, f_at_desired_q) + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.ylabel('$f$') + pl.xlabel('$p_{\\theta}$') + #pl.tight_layout() + pl.savefig('images/dist_func_at_a_point_%d_%d.png'%(index_1, index_2)) + pl.clf() + + np.savetxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2), f_at_desired_q) + f = np.loadtxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2)) + + #f_at_desired_q = np.reshape((dist_func - \ + # dist_func_background)[q1_position, q2_position, :], + # [N_p2, N_p1] + # ) + + #print ("f at desired q : ", dist_func[q1_position, q2_position, :].shape) + print ("norm : ", norm_factor) + + + radius = f.copy() + theta = p2.copy() + + x = (radius + 5.)*np.cos(theta) + y = (radius + 5.)*np.sin(theta) + + x_bg = 5*np.cos(theta) + y_bg = 5*np.sin(theta) + + print ('p2 : ', p2.shape) + #pl.plot(p2, f_at_desired_q) + pl.plot(x, y, color='r', linestyle = '-', lw=3) + pl.plot(x_bg, y_bg, color='k', alpha=0.5, lw=3) + #pl.contourf(p1_meshgrid, p2_meshgrid, f_at_desired_q, 100, cmap='bwr') + + #np.savetxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2), f_at_desired_q) + #f = np.loadtxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2)) + + + #pl.contourf(p_x, p_y, f_at_desired_q, 100, cmap='bwr') + #pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.xlabel('$p_x$') + pl.ylabel('$p_y$') + + pl.xlim([-6.5, 6.5]) + pl.ylim([-6.5, 6.5]) + + pl.gca().set_aspect('equal') + #pl.savefig('images/dist_func_at_a_point_%d_%d.png'%(index_1, index_2)) + pl.clf() + diff --git a/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/momentum_space_movie_zero_T.py b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/momentum_space_movie_zero_T.py new file mode 100644 index 00000000..0d9b3d71 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/momentum_space_movie_zero_T.py @@ -0,0 +1,182 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import os +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +#import yt +#yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain +import params + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_s = len(params.mass) # Number of species + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1_start = domain.q1_start +q1_end = domain.q1_end +q2_start = domain.q2_start +q2_end = domain.q2_end + +q1 = q1_start + (0.5 + np.arange(N_q1)) * (q1_end - q1_start)/N_q1 +q2 = q2_start + (0.5 + np.arange(N_q2)) * (q2_end - q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 +N_p3 = domain.N_p3 + +p1_start = domain.p1_start +p1_end = domain.p1_end +p2_start = domain.p2_start +p2_end = domain.p2_end + +p1 = p1_start[0] + (0.5 + np.arange(N_p1)) * (p1_end[0] - p1_start[0])/N_p1 +p2 = p2_start[0] + (0.5 + np.arange(N_p2)) * (p2_end[0] - p2_start[0])/N_p2 + +p1_meshgrid, p2_meshgrid = np.meshgrid(p1, p2) + +p_x = p1_meshgrid * np.cos(p2_meshgrid) +p_y = p1_meshgrid * np.sin(p2_meshgrid) + +#p2_meshgrid, p1_meshgrid = np.meshgrid(p2, p1) + +io = PetscBinaryIO.PetscBinaryIO() + +filepath = os.getcwd() +moment_files = np.sort(glob.glob(filepath+'/dump_moments/*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/dump_lagrange_multipliers/*.bin')) +dist_func_files = np.sort(glob.glob(filepath+'/dump_f/*.bin')) + +#moment_files = np.sort(glob.glob(filepath+'/dumps/moments*.bin')) +#lagrange_multiplier_files = \ +# np.sort(glob.glob(filepath+'/dumps/lagrange_multipliers*.bin')) +#dist_func_files = np.sort(glob.glob(filepath+'/dumps/f*.bin')) + +dist_func_bg_file = dist_func_files[0] +dist_func_file = dist_func_files[-1] + +print(dist_func_bg_file) +print(dist_func_file) + +dist_func_background = io.readBinaryFile(dist_func_bg_file) +#dist_func_background = dist_func_background[0].reshape(N_q2, N_q1, N_p2, N_p1) +dist_func_background = dist_func_background[0].reshape(N_q2, N_q1, N_s, N_p3, N_p2, N_p1) +dist_func = io.readBinaryFile(dist_func_file) + +print (dist_func[0].shape) + +dist_func = dist_func[0].reshape(N_q2, N_q1, N_s, N_p3, N_p2, N_p1) + +time_array = np.loadtxt("dump_time_array.txt") +file_number = -1 + +N = 7 +for index_1 in range(N): + for index_2 in range(N): + + q1_position = int(N_q1*((index_1/N)+(1/(2*N)))) + q2_position = int(N_q2*((index_2/N)+(1/(2*N)))) + + a = np.max((dist_func - dist_func_background)[q2_position, q1_position, :, :]) + b = np.abs(np.min((dist_func - dist_func_background)[q2_position, q1_position, :, :])) + norm_factor = 1.#np.maximum(a, b) + f_at_desired_q = \ + np.reshape((dist_func-\ + dist_func_background)[q2_position, q1_position, :, :],\ + [N_p2, N_p1])/norm_factor + + im = pl.plot(p2, f_at_desired_q) + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.ylabel('$f$') + pl.xlabel('$p_{\\theta}$') + #pl.tight_layout() + #pl.savefig('images/dist_func_at_a_point_%d_%d.png'%(index_1, index_2)) + pl.clf() + + np.savetxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2), f_at_desired_q) + f = np.loadtxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2)) + + #f_at_desired_q = np.reshape((dist_func - \ + # dist_func_background)[q1_position, q2_position, :], + # [N_p2, N_p1] + # ) + + #print ("f at desired q : ", dist_func[q1_position, q2_position, :].shape) + print ("norm : ", norm_factor) + + + radius = f.copy() + theta = p2.copy() + + x = (radius + 5.)*np.cos(theta) + y = (radius + 5.)*np.sin(theta) + + x_bg = 5*np.cos(theta) + y_bg = 5*np.sin(theta) + + print ('p2 : ', p2.shape) + #pl.plot(p2, f_at_desired_q) + pl.plot(x, y, color='r', linestyle = '-', lw=3) + pl.plot(x_bg, y_bg, color='k', alpha=0.5, lw=3) + #pl.contourf(p1_meshgrid, p2_meshgrid, f_at_desired_q, 100, cmap='bwr') + + #np.savetxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2), f_at_desired_q) + #f = np.loadtxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2)) + + + #pl.contourf(p_x, p_y, f_at_desired_q, 100, cmap='bwr') + #pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.xlabel('$p_x$') + pl.ylabel('$p_y$') + + pl.xlim([-6.5, 6.5]) + pl.ylim([-6.5, 6.5]) + + pl.gca().set_aspect('equal') + pl.savefig('images/dist_func_at_a_point_%d_%d.png'%(index_1, index_2)) + pl.clf() + diff --git a/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/movie.py b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/movie.py new file mode 100644 index 00000000..29cb0531 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/movie.py @@ -0,0 +1,125 @@ +#import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import os +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +#import yt +#yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain +#import boundary_conditions +#import params +#import initialize + + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 + +p1 = domain.p1_start[0] + (0.5 + np.arange(N_p1)) * (domain.p1_end[0] - \ + domain.p1_start[0])/N_p1 +p2 = domain.p2_start[0] + (0.5 + np.arange(N_p2)) * (domain.p2_end[0] - \ + domain.p2_start[0])/N_p2 + + +filepath = os.getcwd() +moment_files = np.sort(glob.glob(filepath+'/dump_moments/*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/dump_lagrange_multipliers/*.bin')) + +print ("moment files : ", moment_files.size) +print ("lagrange multiplier files : ", lagrange_multiplier_files.size) + + +time_array = np.loadtxt("dump_time_array.txt") + +io = PetscBinaryIO.PetscBinaryIO() + +for file_number, dump_file in enumerate(moment_files[:]): + + #file_number = -1 + print("file number = ", file_number, "of ", moment_files.size) + + moments = io.readBinaryFile(moment_files[file_number]) + moments = moments[0].reshape(N_q2, N_q1, 3) + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + + lagrange_multipliers = \ + io.readBinaryFile(lagrange_multiplier_files[file_number]) + lagrange_multipliers = lagrange_multipliers[0].reshape(N_q2, N_q1, 5) + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + + + pl.contourf(q1_meshgrid, q2_meshgrid, density.T, 100, cmap='bwr') + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.streamplot(q1, q2, + vel_drift_x, vel_drift_y, + density=2, color='k', + linewidth=0.7, arrowsize=1 + ) + + pl.xlim([q1[0], q1[-1]]) + pl.ylim([q2[0], q2[-1]]) + + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + pl.ylabel(r'$y\;(\mu \mathrm{m})$') + pl.suptitle('$\\tau_\mathrm{mc} = \infty$, $\\tau_\mathrm{mr} = \infty$') + pl.savefig('images/dump_' + '%06d'%file_number + '.png') + pl.clf() + diff --git a/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/params.py b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/params.py new file mode 100644 index 00000000..288d9f64 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/params.py @@ -0,0 +1,279 @@ +import numpy as np +import arrayfire as af + +from bolt.src.electronic_boltzmann.utils.polygon import polygon +from bolt.src.electronic_boltzmann.utils.unit_vectors import normal_to_hexagon_unit_vec + +instantaneous_collisions = False #TODO : Remove from lib +hybrid_model_enabled = False #TODO : Remove from lib +source_enabled = True +disable_collision_op = False + +fields_enabled = False +# Can be defined as 'electrostatic', 'user-defined'. +# The initial conditions need to be specified under initialize +# Ensure that the initial conditions specified satisfy +# Maxwell's constraint equations +fields_initialize = 'user-defined' + +# Can be defined as 'electrostatic' and 'fdtd' +# To turn feedback from Electric fields on, set fields_solver = 'LCA' +# and set charge_electron +fields_type = 'electrostatic' +fields_solver = 'SNES' + +# Can be defined as 'strang' and 'lie' +time_splitting = 'strang' + +# Method in q-space +solver_method_in_q = 'FVM' +solver_method_in_p = 'FVM' + +reconstruction_method_in_q = 'minmod' +reconstruction_method_in_p = 'minmod' + +riemann_solver_in_q = 'upwind-flux' +riemann_solver_in_p = 'upwind-flux' + +electrostatic_solver_every_nth_step = 1000000 + + +# Time parameters: +dt = 0.025/4 # ps +t_final = 25. # ps + + +# File-writing Parameters: +dump_steps = 5 +dump_dist_after = 1600 +# Set to zero for no file-writing +dt_dump_f = 1000*dt #ps +# ALWAYS set dump moments and dump fields at same frequency: +dt_dump_moments = dt_dump_fields = 5*dt #ps + + +# Dimensionality considered in velocity space: +p_dim = 1 +p_space_grid = 'polar2D' # Supports 'cartesian' or 'polar2D' grids +# Set p-space start and end points accordingly in domain.py +#TODO : Use only polar2D for PdCoO2 + + +zero_temperature = (p_dim==1) +dispersion = 'quadratic' # 'linear' or 'quadratic' +fermi_surface_shape = 'hexagon' # Supports 'circle' or 'hexagon' + + +# Number of devices(GPUs/Accelerators) on each node: +num_devices = 6 + +# Constants: +mass_particle = 0.910938356 # x 1e-30 kg +h_bar = 1.0545718e-4 # x aJ ps +boltzmann_constant = 1 +charge = [0.*-0.160217662] # x aC +mass = [0.] #TODO : Not used in electronic_boltzmann + # Remove from lib +speed_of_light = 300. # x [um/ps] +fermi_velocity = speed_of_light/300 +epsilon0 = 8.854187817 # x [aC^2 / (aJ um) ] + +epsilon_relative = 3.9 # SiO2 +backgate_potential = -10 # V +global_chem_potential = 0.03 +contact_start = 0.0 # um +contact_end = 0.25 # um +contact_geometry = "straight" # Contacts on either side of the device + # For contacts on the same side, use + # contact_geometry = "turn_around" + +initial_temperature = 12e-4 +initial_mu = 0.015 +vel_drift_x_in = 1e-4*fermi_velocity +vel_drift_x_out = 1e-4*fermi_velocity +AC_freq = 1./100 # ps^-1 + +B3_mean = 1. # T + +# Spatial quantities (will be initialized to shape = [q1, q2] in initalize.py) +mu = None # chemical potential used in the e-ph operator +T = None # Electron temperature used in the e-ph operator +mu_ee = None # chemical potential used in the e-e operator +T_ee = None # Electron temperature used in the e-e operator +vel_drift_x = None +vel_drift_y = None +phi = None # Electric potential in the plane of graphene sheet +p_x = None +p_y = None +#integral_measure = None + +# Momentum quantities (will be initialized to shape = [p1*p2*p3] in initialize.py) +E_band = None +vel_band = None + +collision_operator_nonlinear_iters = 2 + +# Variation of collisional-timescale parameter through phase space: +@af.broadcast +def tau_defect(q1, q2, p1, p2, p3): + return(np.inf * q1**0 * p1**0) + +@af.broadcast +def tau_ee(q1, q2, p1, p2, p3): + return(np.inf * q1**0 * p1**0) + +def tau(q1, q2, p1, p2, p3): + return(tau_defect(q1, q2, p1, p2, p3)) + + +def fermi_momentum_magnitude(theta): + if (fermi_surface_shape == 'circle'): + p_f = initial_mu/fermi_velocity # Fermi momentum + + elif (fermi_surface_shape == 'hexagon'): + n = 6 # No. of sides of polygon + p_f = (initial_mu/fermi_velocity) * polygon(n, theta, rotation = np.pi/6) + # Note : Rotation by pi/6 results in a hexagon with horizontal top & bottom edges + #TODO : If cartesian coordinates are being used, convert to polar to calculate p_f + else : + raise NotImplementedError('Unsupported shape of fermi surface') + return(p_f) + + +def band_energy(p1, p2): + # Note :This function is only meant to be called once to initialize E_band + + if (p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (p_space_grid == 'polar2D'): + # In polar2D coordinates, p1 = radius and p2 = theta + r = p1 + theta = p2 + p_x = r * af.cos(theta) + p_y = r * af.sin(theta) + else : + raise NotImplementedError('Unsupported coordinate system in p_space') + + p = af.sqrt(p_x**2. + p_y**2.) + if (dispersion == 'linear'): + + E_upper = p*fermi_velocity + + elif (dispersion == 'quadratic'): + + m = effective_mass(p1, p2) + E_upper = p**2/(2.*m) + + if (zero_temperature): + + E_upper = initial_mu * p**0. + + af.eval(E_upper) + return(E_upper) + + +def effective_mass(p1, p2): + + if (p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + + theta = af.atan(p_y/p_x) + + elif (p_space_grid == 'polar2D'): + # In polar2D coordinates, p1 = radius and p2 = theta + r = p1; theta = p2 + else : + raise NotImplementedError('Unsupported coordinate system in p_space') + + if (fermi_surface_shape == 'hexagon'): + + n = 6 # No. of side of polygon + mass = mass_particle * polygon(n, theta, rotation = np.pi/6) + # Note : Rotation by pi/6 results in a hexagon with horizontal top & bottom edges + + elif (fermi_surface_shape == 'circle'): + + # For now, just return the free electron mass + mass = mass_particle + + return(mass) + +def band_velocity(p1, p2): + # Note :This function is only meant to be called once to initialize the vel vectors + + if (p_space_grid == 'cartesian'): + p_x_local = p1 + p_y_local = p2 + + theta = af.atan(p_y_local/p_x_local) + + elif (p_space_grid == 'polar2D'): + # In polar2D coordinates, p1 = radius and p2 = theta + r = p1; theta = p2 + else : + raise NotImplementedError('Unsupported coordinate system in p_space') + + p = af.sqrt(p_x**2. + p_y**2.) + p_hat = [p_x / (p + 1e-20), p_y / (p + 1e-20)] + + if (fermi_surface_shape == 'circle'): + + v_f_hat = p_hat + + elif (fermi_surface_shape == 'hexagon'): + + v_f_hat = normal_to_hexagon_unit_vec(theta) + + # Quadratic dispersion + m = effective_mass(p1, p2) + v_f = p/m + + if (dispersion == 'linear' or zero_temperature): + + v_f = fermi_velocity + + upper_band_velocity = [v_f * v_f_hat[0], v_f * v_f_hat[1]] + + return(upper_band_velocity) + +def get_p_x_and_p_y(p1, p2): + + if (p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (p_space_grid == 'polar2D'): + # In polar2D coordinates, p1 = radius and p2 = theta + r = p1; theta = p2 + + if (zero_temperature): + # Get p_x and p_y at the Fermi surface + r = fermi_momentum_magnitude(theta) + + p_x = r * af.cos(theta) + p_y = r * af.sin(theta) + + else : + raise NotImplementedError('Unsupported coordinate system in p_space') + + return([p_x, p_y]) + +# Restart(Set to zero for no-restart): +latest_restart = True +t_restart = 0 + +@af.broadcast +def fermi_dirac(mu, E_band): + + k = boltzmann_constant + T = initial_temperature + + f = (1./(af.exp( (E_band - mu + )/(k*T) + ) + 1. + ) + ) + + af.eval(f) + return(f) diff --git a/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/petsc_conf.py b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/petsc_conf.py new file mode 100755 index 00000000..22781ed2 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/petsc_conf.py @@ -0,0 +1,73 @@ +import warnings + +def get_conf(): + """Parses various PETSc configuration/include files to get data types. + + precision, indices, complexscalars = get_conf() + + Output: + precision: 'single', 'double', 'longlong' indicates precision of PetscScalar + indices: '32', '64' indicates bit-size of PetscInt + complex: True/False indicates whether PetscScalar is complex or not. + """ + + import sys, os + precision = None + indices = None + complexscalars = None + + if 'PETSC_DIR' in os.environ: + petscdir = os.environ['PETSC_DIR'] + else: + warnings.warn('PETSC_DIR env not set - unable to locate PETSc installation, using defaults') + return None, None, None + + if os.path.isfile(os.path.join(petscdir,'lib','petsc','conf','petscrules')): + # found prefix install + petscvariables = os.path.join(petscdir,'lib','petsc','conf','petscvariables') + petscconfinclude = os.path.join(petscdir,'include','petscconf.h') + else: + if 'PETSC_ARCH' in os.environ: + petscarch = os.environ['PETSC_ARCH'] + if os.path.isfile(os.path.join(petscdir,petscarch,'lib','petsc','conf','petscrules')): + # found legacy install + petscvariables = os.path.join(petscdir,petscarch,'lib','petsc','conf','petscvariables') + petscconfinclude = os.path.join(petscdir,petscarch,'include','petscconf.h') + else: + warnings.warn('Unable to locate PETSc installation in specified PETSC_DIR/PETSC_ARCH, using defaults') + return None, None, None + else: + warnings.warn('PETSC_ARCH env not set or incorrect PETSC_DIR is given - unable to locate PETSc installation, using defaults') + return None, None, None + + try: + fid = open(petscvariables, 'r') + except IOError: + warnings.warn('Nonexistent or invalid PETSc installation, using defaults') + return None, None, None + else: + for line in fid: + if line.startswith('PETSC_PRECISION'): + precision = line.strip().split('=')[1].strip('\n').strip() + + fid.close() + + try: + fid = open(petscconfinclude, 'r') + except IOError: + warnings.warn('Nonexistent or invalid PETSc installation, using defaults') + return None, None, None + else: + for line in fid: + if line.startswith('#define PETSC_USE_64BIT_INDICES 1'): + indices = '64bit' + elif line.startswith('#define PETSC_USE_COMPLEX 1'): + complexscalars = True + + if indices is None: + indices = '32bit' + if complexscalars is None: + complexscalars = False + fid.close() + + return precision, indices, complexscalars diff --git a/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/phase_vs_y.py b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/phase_vs_y.py new file mode 100644 index 00000000..fc6ac364 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/phase_vs_y.py @@ -0,0 +1,180 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +from scipy.optimize import curve_fit +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 12, 7.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +def sin_curve_fit(t, A, tau): + return A*np.sin(2*np.pi*AC_freq*(t + tau )) + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +# Left needs to be near source, right sensor near drain +sensor_1_left_start = 5.5 # um +sensor_1_left_end = 10.0 # um + +sensor_1_right_start = 5.5 # um +sensor_1_right_end = 10.0 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +filepath = \ + '/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_2.5_tau_ee_inf_tau_eph_2.5/dumps' + +AC_freq = 1./100.0 +time_period = 1/AC_freq +t_final = params.t_final +transient_time = t_final/2. + +time = np.loadtxt(filepath + "/../dump_time_array.txt") +edge_density = np.loadtxt(filepath + "/../edge_density.txt") +q2 = np.loadtxt(filepath + "/../q2_edge.txt") + +N_spatial = edge_density.shape[1] + +transient_index = int((transient_time/t_final)*time.size) + +drive = np.sin(2*np.pi*AC_freq*time) +nsamples = drive.size +dt_corr = np.linspace(-time[-1] + time[0],\ + time[-1] - time[0], 2*nsamples-1) + +# Discarding transients +q = q2.size/2 +time_half = time[transient_index:] +drive_half = drive[transient_index:] + +# Plotting signals at edge +norm_0 = np.max(edge_density[transient_index:, 0]) +norm_1 = np.max(edge_density[transient_index:, -1]) + +pl.plot(time, drive, color='black', linestyle='--') +pl.ylim([-1.1, 1.1]) +pl.xlim([0,200]) +pl.xlabel('$\mathrm{Time\;(s)}$') + +for i in range(N_spatial): + norm_i = np.max(edge_density[transient_index:, i]) + pl.plot(time, edge_density[:, i]/norm_i) + +pl.savefig('images/signals.png') +pl.clf() + +phase_shift_corr_array = [] +phase_shift_fitting_array = []\ + +for i in range(N_spatial): + print ('index : ', i) + signal_1 = edge_density[:, i] + norm_1 = np.max(signal_1[transient_index:]) + signal_1_normalized = signal_1/norm_1 + + # Calculate phase_shifts using scipy.correlate + corr = correlate(drive, signal_1_normalized) + time_shift_corr = dt_corr[corr.argmax()] + phase_shift_corr = 2*np.pi*(((0.5 + time_shift_corr/time_period) % 1.0) - 0.5) + + # Calculate phase_shifts using scipy.curve_fit + popt, pcov = curve_fit(sin_curve_fit, time[transient_index:],\ + signal_1_normalized[transient_index:]) + time_shift_fitting = popt[1]%(time_period/2.0) + phase_shift_fitting = 2*np.pi*(((0.5 + time_shift_fitting/time_period) % 1.0) - 0.5) + + phase_shift_corr_array.append(phase_shift_corr) + phase_shift_fitting_array.append(phase_shift_fitting) + +phase_shift_corr_array = np.array(phase_shift_corr_array) +phase_shift_fitting_array = np.array(phase_shift_fitting_array) + +# Plot +pl.ylabel('$\mathrm{\phi}$') +pl.xlabel('$\mathrm{y\ \mu m}$') + +pl.plot(q2, phase_shift_corr_array, '-o', label='$\mathrm{corr}$') +pl.plot(q2, phase_shift_fitting_array, '-o', label='$\mathrm{fit}$') + +pl.title('$\mathrm{2.5 \\times 10,\ \\tau_{ee} = \infty,\ \\tau_{eph} = 2.5}$') +pl.legend(loc='best') + +#pl.axvspan(sensor_1_left_start, sensor_1_left_end, color = 'k', alpha = 0.1) +#pl.axvspan(sensor_2_left_start, sensor_2_left_end, color = 'k', alpha = 0.1) + +pl.savefig('images/phase_vs_y.png') +pl.clf() + diff --git a/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/post.py b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/post.py new file mode 100644 index 00000000..a297c6f0 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/post.py @@ -0,0 +1,422 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +#pl.rcParams['figure.figsize'] = 8, 7.5 +pl.rcParams['figure.figsize'] = 8, 8 +#pl.rcParams['figure.figsize'] = 17, 9.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +#pl.rcParams['lines.linewidth'] = 3 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 +#N_q1 = 120 +#N_q2 = 240 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +#source_start = 3.5; source_end = 4.5 +#drain_start = 5.5; drain_end = 6.5 + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +sensor_1_left_start = 8.5 # um +sensor_1_left_end = 9.5 # um + +sensor_1_right_start = 8.5 # um +sensor_1_right_end = 9.5 # um + +# Left needs to be near source, right sensor near drain +#sensor_1_left_start = 1.5 # um +#sensor_1_left_end = 2.5 # um + +#sensor_1_right_start = 7.5 # um +#sensor_1_right_end = 8.5 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +sensor_2_left_start = 6.5 # um +sensor_2_left_end = 7.5 # um + +sensor_2_right_start = 6.5 # um +sensor_2_right_end = 7.5 # um + +sensor_2_left_indices = (q2 > sensor_2_left_start ) & (q2 < sensor_2_left_end) +sensor_2_right_indices = (q2 > sensor_2_right_start) & (q2 < sensor_2_right_end) + +#dump_index = 0 +#h5f = h5py.File('dumps/moments_' + '%06d'%(dump_index) + '.h5', 'r') +#moments = np.swapaxes(h5f['moments'][:], 0, 1) +#h5f.close() +# +#density = moments[:, :, 0] +#j_x = moments[:, :, 1] +#j_y = moments[:, :, 2] +#pl.contourf(q1, q2, density, 100) +##pl.title('Time = ' + "%.2f"%(t0)) +#pl.axes().set_aspect('equal') +#pl.xlabel(r'$x$') +#pl.ylabel(r'$y$') +#pl.colorbar() +#pl.savefig('images/density' + '.png') +#pl.clf() +# +#h5f = h5py.File('dumps/lagrange_multipliers_' + '%06d'%(dump_index) + '.h5', 'r') +#lagrange_multipliers = np.swapaxes(h5f['lagrange_multipliers'][:], 0, 1) +#h5f.close() +# +#print("lagrange_multipliers.shape = ", lagrange_multipliers.shape) +#mu = lagrange_multipliers[:, :, 0] +#mu_ee = lagrange_multipliers[:, :, 1] +#T_ee = lagrange_multipliers[:, :, 2] +#vel_drift_x = lagrange_multipliers[:, :, 3] +#vel_drift_y = lagrange_multipliers[:, :, 4] +#j_x_prime = density*vel_drift_x +#print("err = ", np.mean(np.abs(j_x_prime - j_x))) + +#filepath = \ +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/geom_1/DC/tau_D_50_tau_ee_0.2' +#dump_file= np.sort(glob.glob(filepath+'/moment*.h5'))[-1] +# +#h5f = h5py.File(dump_file, 'r') +#moments = np.swapaxes(h5f['moments'][:], 0, 1) +#h5f.close() +# +#density = moments[:, :, 0] +#np.savetxt('paper_plots/density_tau_D_50_tau_ee_0.2.txt', density) +#np.savetxt('paper_plots/q2_DC_tau_D_50_tau_ee_0.2.txt', q2) +##pl.plot(q2[q2>source_end], density[0, q2>source_end]-np.mean(density)) +# +#filepath = \ +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/geom_1/DC/tau_D_5_tau_ee_0.2' +#dump_file= np.sort(glob.glob(filepath+'/moment*.h5'))[-1] +# +# +#h5f = h5py.File(dump_file, 'r') +#moments = np.swapaxes(h5f['moments'][:], 0, 1) +#h5f.close() +# +#density = moments[:, :, 0] +#np.savetxt('paper_plots/density_tau_D_5_tau_ee_0.2.txt', density) +#np.savetxt('paper_plots/q2_DC_tau_D_5_tau_ee_0.2.txt', q2) +# +#filepath = \ +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/geom_1/DC/tau_D_10_tau_ee_0.2' +#dump_file= np.sort(glob.glob(filepath+'/moment*.h5'))[-1] +# +#N_q1 = 120 +#N_q2 = 240 +# +#q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +#q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 +# +#h5f = h5py.File(dump_file, 'r') +#moments = np.swapaxes(h5f['moments'][:], 0, 1) +#h5f.close() +# +#density = moments[:, :, 0] +#np.savetxt('paper_plots/density_tau_D_10_tau_ee_0.2.txt', density) +#np.savetxt('paper_plots/q2_DC_tau_D_10_tau_ee_0.2.txt', q2) + + +#pl.plot(q2[q2>source_end], density[0, q2>source_end]-np.mean(density)) +#pl.axhline(0, color='black', linestyle='--') +#pl.legend(['$\\tau_{ee}=0.2$ ps, $\\tau_{e-ph}=50$ ps', +# '$\\tau_{ee}=0.2$ ps, $\\tau_{e-ph}=10$ ps'], loc='lower right') +#pl.xlabel(r'$x\;(\mu \mathrm{m})$') +#pl.ylabel(r'$R\; (\mathrm{a.u.})$') +#pl.xlim(xmin=(source_end+0.1)) +#pl.savefig('paper_plots/DC.png') + +filepath = \ +'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/dumps_tau_D_1_tau_ee_0.2_movie' +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/geom_1/55_GHz/tau_D_5_tau_ee_0.2' +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/dumps_AC_10_Ghz_tau_D_10_tau_ee_1_geom_2/' +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/dumps_tau_D_2_tau_ee_1_AC/' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +sensor_1_signal_array = [] +print("Reading sensor signal...") +for file_number, dump_file in enumerate(moment_files): + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + density = moments[:, :, 0] + + source = np.mean(density[0, source_indices]) + drain = np.mean(density[-1, drain_indices]) + + sensor_1_left = np.mean(density[0, sensor_1_left_indices] ) + sensor_1_right = np.mean(density[-1, sensor_1_right_indices]) + + sensor_1_signal = sensor_1_left - sensor_1_right + + sensor_1_signal_array.append(sensor_1_signal) + +time_array = np.loadtxt("dump_time_array.txt") +AC_freq = 1./100 +input_signal_array = np.sin(2.*np.pi*AC_freq*time_array) +sensor_1_signal_array = np.array(sensor_1_signal_array) +half_time = (int)(time_array.size/2) +sensor_normalized = \ + sensor_1_signal_array/np.max(np.abs(sensor_1_signal_array[half_time:])) + +pl.rcParams['figure.figsize'] = 10, 8 +for file_number, dump_file in yt.parallel_objects(enumerate(moment_files)): + + print("file number = ", file_number, "of ", moment_files.size) + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + gs = gridspec.GridSpec(3, 2) + pl.subplot(gs[:, 0]) + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + pl.contourf(q1_meshgrid, q2_meshgrid, density, 100, cmap='bwr') + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + #pl.colorbar() + + h5f = h5py.File(lagrange_multiplier_files[file_number], 'r') + lagrange_multipliers = h5f['lagrange_multipliers'][:] + h5f.close() + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + +# pl.streamplot(q1[(int)(N_q1/2):], q2, +# vel_drift_x[:, (int)(N_q1/2):], vel_drift_y[:, (int)(N_q1/2):], +# density=2, color='blue', +# linewidth=0.7, arrowsize=1 +# ) + pl.streamplot(q1, q2, + vel_drift_x, vel_drift_y, + density=2, color='blue', + linewidth=0.7, arrowsize=1 + ) +# pl.streamplot(q1, q2, +# vel_drift_x, vel_drift_y, +# density=3, color='blue', +# linewidth=0.8, arrowsize=1.1 +# ) + pl.xlim([domain.q1_start, domain.q1_end]) + pl.ylim([domain.q2_start, domain.q2_end]) + #pl.ylim([0, 5]) + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + pl.ylabel(r'$y\;(\mu \mathrm{m})$') + + pl.gca().annotate("+", xy=(-0.07, .9), xycoords=("axes fraction"), + ha="center", va="center", size=30, + bbox=dict(fc="white")) + pl.gca().annotate("-", xy=(1.05, .9), xycoords=("axes fraction"), + ha="center", va="center", size=30, + bbox=dict(fc="white", pad=6.5)) + + + pl.subplot(gs[1, 1]) + + pl.plot(time_array, input_signal_array) + pl.plot(time_array, sensor_normalized) + pl.axhline(0, color='black', linestyle='--') + pl.axvline(time_array[file_number], color='black', alpha=0.75) + pl.legend(['Source $I(t)$', 'Measured $V(t)$'], loc=(0.04, 1.125)) + pl.xlabel(r'Time (ps)') + pl.xlim([100, 200]) + pl.ylim([-1.1, 1.1]) + + + pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 1$ ps') + #pl.tight_layout() + pl.savefig('images/dump_' + '%06d'%file_number + '.png') + #pl.savefig('paper_plots/DC.png') + pl.clf() + + +#time_array = [] +#input_signal_array = [] +#sensor_1_signal_array = [] +#sensor_2_signal_array = [] +#for file_number, dump_file in enumerate(moment_files): +# +# print("file number = ", file_number, "of ", moment_files.size) +# +# h5f = h5py.File(dump_file, 'r') +# moments = np.swapaxes(h5f['moments'][:], 0, 1) +# h5f.close() +# +# density = moments[:, :, 0] +# +# source = np.mean(density[0, source_indices]) +# drain = np.mean(density[-1, drain_indices]) +# +# sensor_1_left = np.mean(density[0, sensor_1_left_indices] ) +# sensor_1_right = np.mean(density[-1, sensor_1_right_indices]) +# #sensor_1_right = np.mean(density[0, sensor_1_right_indices]) +# +# sensor_2_left = np.mean(density[0, sensor_2_left_indices] ) +# sensor_2_right = np.mean(density[-1, sensor_2_right_indices]) +# +# #sensor_1_left = density[0, q2>source_end] +# #sensor_1_right = density[-1, q2>source_end] +# +# input_signal = source - drain +# sensor_1_signal = sensor_1_left - sensor_1_right +# sensor_2_signal = sensor_2_left - sensor_2_right +# +# time_array.append(file_number*dt*dump_interval) +# input_signal_array.append(input_signal) +# sensor_1_signal_array.append(sensor_1_signal) +# sensor_2_signal_array.append(sensor_2_signal) +# +##pl.rcParams['figure.figsize'] = 12, 8 +## +#AC_freq = 5.5/100 +#time_array = np.array(time_array) +#input_signal_array = np.sin(2.*np.pi*AC_freq*time_array) +#sensor_1_signal_array = np.array(sensor_1_signal_array) +###np.savetxt('drive.txt', input_signal_array) +##np.savetxt('paper_plots/sensor_tau_ee_0.2_tau_D_5.txt', sensor_1_signal_array) +##np.savetxt('time.txt', time_array) +## +##print("sensor.shape = ", sensor_1_signal_array.shape) +##sensor_2_signal_array = np.array(sensor_2_signal_array) +## +#half_time = (int)(time_array.size/2) +#pl.plot(time_array, input_signal_array/np.max(input_signal_array[half_time:])) +#pl.plot(time_array, +# sensor_1_signal_array/np.max(sensor_1_signal_array[half_time:]) +# ) +##pl.plot(time_array, +## sensor_2_signal_array/np.max(sensor_2_signal_array[half_time:]) +## ) +#pl.xlabel(r"Time (ps)") +#pl.ylim([-1.1, 1.1]) +#pl.legend(['Input', 'Sensor 1', 'Sensor 2']) +#pl.savefig('paper_plots/IV_55_Ghz_tau_ee_0.2_tau_D_5.png') +##half_time = 0 +#input_normalized = input_signal_array[half_time:]/np.max(input_signal_array[half_time:]) +#sensor_normalized = sensor_1_signal_array[half_time:]/np.max(sensor_1_signal_array[half_time:]) +# +## Calculate the phase diff. Copied from: +## https://stackoverflow.com/questions/6157791/find-phase-difference-between-two-inharmonic-waves +#corr = correlate(input_normalized, sensor_normalized) +#nsamples = input_normalized.size +#time_corr = time_array[half_time:] +#dt_corr = np.linspace(-time_corr[-1] + time_corr[0], +# time_corr[-1] - time_corr[0], 2*nsamples-1) +#time_shift = dt_corr[corr.argmax()] +# +## force the phase shift to be in [-pi:pi] +#period = 1./AC_freq +#phase_diff = 2*np.pi*(((0.5 + time_shift/period) % 1.0) - 0.5) +#print("density.shape = ", density.shape) +#print("Phase diff = ", phase_diff) + +#phase_vs_x = [] +#for i in range(sensor_1_signal_array[0, :].size): +# signal = sensor_1_signal_array[:, i] +# corr = correlate(input_signal_array, signal) +# nsamples = input_signal_array.size +# half_time = 0 +# time_corr = time_array[half_time:] +# dt_corr = np.linspace(-time_corr[-1] + time_corr[0], +# time_corr[-1] - time_corr[0], +# 2*nsamples-1 +# ) +# time_shift = dt_corr[corr.argmax()] +# +# # force the phase shift to be in [-pi:pi] +# period = 1./params.AC_freq +# phase_diff = 2*np.pi*(((0.5 + time_shift/period) % 1.0) - 0.5) +# phase_vs_x.append(phase_diff) +# +#phase_vs_x = np.array(phase_vs_x) +#print("phase_vs_x.shape = ", phase_vs_x.shape) +#np.savetxt("paper_plots/phase_vs_x_tau_ee_0.2_tau_D_1.txt", phase_vs_x) +#np.savetxt("paper_plots/q2_tau_ee_0.2_tau_D_1.txt", q2) +#print("density.shape = ", density.shape) + + diff --git a/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/signals.py b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/signals.py new file mode 100644 index 00000000..979640c3 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/signals.py @@ -0,0 +1,166 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +#import yt +#yt.enable_parallelism() +import os + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +import PetscBinaryIO + +import domain +import boundary_conditions +import params +import initialize + + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +# Left needs to be near source, right sensor near drain +sensor_1_left_start = 8.5 # um +sensor_1_left_end = 9.5 # um + +sensor_1_right_start = 8.5 # um +sensor_1_right_end = 9.5 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +sensor_2_left_start = 6.5 # um +sensor_2_left_end = 7.5 # um + +sensor_2_right_start = 6.5 # um +sensor_2_right_end = 7.5 # um + +sensor_2_left_indices = (q2 > sensor_2_left_start ) & (q2 < sensor_2_left_end) +sensor_2_right_indices = (q2 > sensor_2_right_start) & (q2 < sensor_2_right_end) + +io = PetscBinaryIO.PetscBinaryIO() + +filepath = os.getcwd() +#filepath = '/home/mchandra/gitansh/zero_T/example_problems/electronic_boltzmann/graphene/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC' +moment_files = np.sort(glob.glob(filepath+'/dump_moments/*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/dump_lagrange_multipliers/*.bin')) + +#moment_files = np.sort(glob.glob(filepath+'/dumps/moments*.bin')) +#lagrange_multiplier_files = \ +# np.sort(glob.glob(filepath+'/dumps/lagrange_multipliers*.bin')) + +dt = params.dt +dump_interval = params.dump_steps + +sensor_1_signal_array = [] +print("Reading sensor signal...") +for file_number, dump_file in enumerate(moment_files): + + moments = io.readBinaryFile(dump_file) + moments = moments[0].reshape(N_q2, N_q1, 3) + + density = moments[:, :, 0] + + source = np.mean(density[source_indices, 0]) + drain = np.mean(density[drain_indices, -1]) + + sensor_1_left = np.mean(density[0, 0]) + sensor_1_right = np.mean(density[0, -1]) + + sensor_1_signal = sensor_1_left - sensor_1_right + + sensor_1_signal_array.append(sensor_1_signal) + +time_array = np.loadtxt("dump_time_array.txt") +AC_freq = 1./100 +input_signal_array = np.sin(2.*np.pi*AC_freq*time_array) +sensor_1_signal_array = np.array(sensor_1_signal_array) +half_time = (int)(time_array.size/2) + +input_normalized = \ + input_signal_array/np.max(np.abs(input_signal_array[half_time:])) +sensor_normalized = \ + sensor_1_signal_array#/np.max(np.abs(sensor_1_signal_array[half_time:])) + +# Calculate the phase difference between input_signal_array and sensor_normalized +# Code copied from : +# https:/stackoverflow.com/questions/6157791/find-phase-difference-between-two-inharmonic-waves + +#corr = correlate(input_normalized, sensor_normalized) +#nsamples = input_normalized.size +#time_corr = time_array[half_time:] +#dt_corr = np.linspace(-time_corr[-1] + time_corr[0], +# time_corr[-1] - time_corr[0], 2*nsamples-1) +#time_shift = dt_corr[corr.argmax()] + +#Force the phase shift to be in [-pi:pi] +#period = 1./AC_freq +#phase_diff = 2*np.pi*(((0.5 + time_shift/period) % 1.0) - 0.5) + +#pl.plot(time_array, input_signal_array) +pl.plot(time_array, sensor_normalized) +#pl.axhline(0, color='black', linestyle='--') + +#pl.legend(['Source $I(t)$', 'Measured $V(t)$'], loc=1) +#pl.text(135, 1.14, '$\phi : %.2f \; rad$' %phase_diff) +pl.xlabel(r'Time (ps)') +#pl.xlim([0, 200]) +#pl.ylim([-1.1, 1.1]) + +pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 0.5$ ps') +pl.savefig('images/iv' + '.png') +pl.clf() + + diff --git a/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/vorticity.py b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/vorticity.py new file mode 100644 index 00000000..2f494c60 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC/vorticity.py @@ -0,0 +1,136 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +filepath = \ +'/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_1.0_tau_ee_0.2_tau_eph_0.5/dumps' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +time_array = np.loadtxt("dump_time_array.txt") +half_time = (int)(time_array.size/2) + +for file_number, dump_file in yt.parallel_objects(enumerate(moment_files)): + + print("file number = ", file_number, "of ", moment_files.size) + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + + h5f = h5py.File(lagrange_multiplier_files[file_number], 'r') + lagrange_multipliers = h5f['lagrange_multipliers'][:] + h5f.close() + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + + + dq1 = (domain.q1_end - domain.q1_start)/domain.N_q1 + dq2 = (domain.q2_end - domain.q2_start)/domain.N_q2 + + dvx_dx, dvx_dy = np.gradient(j_x/density, dq1, dq2) + dvy_dx, dvy_dy = np.gradient(j_y/density, dq1, dq2) + + vorticity = dvy_dx - dvx_dy + + pl.contourf(q1_meshgrid, q2_meshgrid, vorticity, 100, cmap='bwr') + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + + pl.streamplot(q1, q2, + vel_drift_x, vel_drift_y, + density=2, color='blue', + linewidth=0.7, arrowsize=1 + ) + + pl.xlim([domain.q1_start, domain.q1_end]) + pl.ylim([domain.q2_start, domain.q2_end]) + + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + pl.ylabel(r'$y\;(\mu \mathrm{m})$') + pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 1.0$ ps') + pl.savefig('vorticity_images/dump_' + '%06d'%file_number + '.png') + pl.clf() + diff --git a/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/PetscBinaryIO.py b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/PetscBinaryIO.py new file mode 100755 index 00000000..fd0e48e9 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/PetscBinaryIO.py @@ -0,0 +1,479 @@ +"""PetscBinaryIO +=============== + +Provides + 1. PETSc-named objects Vec, Mat, and IS that inherit numpy.ndarray + 2. A class to read and write these objects from PETSc binary files. + +The standard usage of this module should look like: + + >>> import PetscBinaryIO + >>> io = PetscBinaryIO.PetscBinaryIO() + >>> objects = io.readBinaryFile('file.dat') + +or + + >>> import PetscBinaryIO + >>> import numpy + >>> vec = numpy.array([1., 2., 3.]).view(PetscBinaryIO.Vec) + >>> io = PetscBinaryIO.PetscBinaryIO() + >>> io.writeBinaryFile('file.dat', [vec,]) + +to read in objects one at a time use such as + + >>> import PetscBinaryIO + >>> io = PetscBinaryIO.PetscBinaryIO() + >>> fh = open('file.dat') + >>> objecttype = io.readObjectType(fh) + >>> if objecttype == 'Vec': + >>> v = io.readVec(fh) + + Note that one must read in the object type first and then call readVec(), readMat() etc. + + +See also PetscBinaryIO.__doc__ and methods therein. +""" + +import numpy as np +import functools + +try: + basestring # Python-2 has basestring as a common parent of unicode and str +except NameError: + basestring = str # Python-3 is unicode through and through + +def update_wrapper_with_doc(wrapper, wrapped): + """Similar to functools.update_wrapper, but also gets the wrapper's __doc__ string""" + wdoc = wrapper.__doc__ + + functools.update_wrapper(wrapper, wrapped) + if wdoc is not None: + if wrapper.__doc__ is None: + wrapper.__doc__ = wdoc + else: + wrapper.__doc__ = wrapper.__doc__ + wdoc + return wrapper + +def wraps_with_doc(wrapped): + """Similar to functools.wraps, but also gets the wrapper's __doc__ string""" + return functools.partial(update_wrapper_with_doc, wrapped=wrapped) + +def decorate_with_conf(f): + """Decorates methods to take kwargs for precisions.""" + @wraps_with_doc(f) + def decorated_f(self, *args, **kwargs): + """ + Additional kwargs: + precision: 'single', 'double', 'longlong' for scalars + indices: '32bit', '64bit' integer size + complexscalars: True/False + + Note these are set in order of preference: + 1. kwargs if given here + 2. PetscBinaryIO class __init__ arguments + 3. PETSC_DIR/PETSC_ARCH defaults + """ + + changed = False + old_precision = self.precision + old_indices = self.indices + old_complexscalars = self.complexscalars + + try: + self.precision = kwargs.pop('precision') + except KeyError: + pass + else: + changed = True + + try: + self.indices = kwargs.pop('indices') + except KeyError: + pass + else: + changed = True + + try: + self.complexscalars = kwargs.pop('complexscalars') + except KeyError: + pass + else: + changed = True + + if changed: + self._update_dtypes() + + result = f(self, *args, **kwargs) + + if changed: + self.precision = old_precision + self.indices = old_indices + self.complexscalars = old_complexscalars + self._update_dtypes() + + return result + return decorated_f + + +class DoneWithFile(Exception): pass + + +class Vec(np.ndarray): + """Vec represented as 1D numpy array + + The best way to instantiate this class for use with writeBinaryFile() + is through the numpy view method: + + vec = numpy.array([1,2,3]).view(Vec) + """ + _classid = 1211214 + + +class MatDense(np.matrix): + """Mat represented as 2D numpy array + + The best way to instantiate this class for use with writeBinaryFile() + is through the numpy view method: + + mat = numpy.array([[1,0],[0,1]]).view(Mat) + """ + _classid = 1211216 + + +class MatSparse(tuple): + """Mat represented as CSR tuple ((M, N), (rowindices, col, val)) + + This should be instantiated from a tuple: + + mat = MatSparse( ((M,N), (rowindices,col,val)) ) + """ + _classid = 1211216 + def __repr__(self): + return 'MatSparse: %s'%super(MatSparse, self).__repr__() + + +class IS(np.ndarray): + """IS represented as 1D numpy array + + The best way to instantiate this class for use with writeBinaryFile() + is through the numpy "view" method: + + an_is = numpy.array([3,4,5]).view(IS) + """ + _classid = 1211218 + + +class PetscBinaryIO(object): + """Reader/Writer class for PETSc binary files. + + Note that by default, precisions for both scalars and indices, as well as + complex scalars, are picked up from the PETSC_DIR/PETSC_ARCH configuration + as set by environmental variables. + + Alternatively, defaults can be overridden at class instantiation, or for + a given method call. + """ + + _classid = {1211216:'Mat', + 1211214:'Vec', + 1211218:'IS', + 1211219:'Bag'} + + def __init__(self, precision=None, indices=None, complexscalars=None): + if (precision is None) or (indices is None) or (complexscalars is None): + import petsc_conf + defaultprecision, defaultindices, defaultcomplexscalars = petsc_conf.get_conf() + if precision is None: + if defaultprecision is None: + precision = 'double' + else: + precision = defaultprecision + + if indices is None: + if defaultindices is None: + indices = '32bit' + else: + indices = defaultindices + + if complexscalars is None: + if defaultcomplexscalars is None: + complexscalars = False + else: + complexscalars = defaultcomplexscalars + + self.precision = precision + self.indices = indices + self.complexscalars = complexscalars + self._update_dtypes() + + def _update_dtypes(self): + if self.indices == '64bit': + self._inttype = np.dtype('>i8') + else: + self._inttype = np.dtype('>i4') + + if self.precision == 'longlong': + nbyte = 16 + elif self.precision == 'single': + nbyte = 4 + else: + nbyte = 8 + + if self.complexscalars: + name = 'c' + nbyte = nbyte * 2 # complex scalar takes twice as many bytes + else: + name = 'f' + + self._scalartype = '>{0}{1}'.format(name, nbyte) + + @decorate_with_conf + def readVec(self, fh): + """Reads a PETSc Vec from a binary file handle, must be called after readObjectType().""" + + nz = np.fromfile(fh, dtype=self._inttype, count=1)[0] + try: + vals = np.fromfile(fh, dtype=self._scalartype, count=nz) + except MemoryError: + raise IOError('Inconsistent or invalid Vec data in file') + if (len(vals) is 0): + raise IOError('Inconsistent or invalid Vec data in file') + return vals.view(Vec) + + @decorate_with_conf + def writeVec(self, fh, vec): + """Writes a PETSc Vec to a binary file handle.""" + + metadata = np.array([Vec._classid, len(vec)], dtype=self._inttype) + metadata.tofile(fh) + vec.astype(self._scalartype).tofile(fh) + return + + @decorate_with_conf + def readMatSparse(self, fh): + """Reads a PETSc Mat, returning a sparse representation of the data. Must be called after readObjectType() + + (M,N), (I,J,V) = readMatSparse(fid) + + Input: + fid : file handle to open binary file. + Output: + M,N : matrix size + I,J : arrays of row and column for each nonzero + V: nonzero value + """ + + try: + M,N,nz = np.fromfile(fh, dtype=self._inttype, count=3) + I = np.empty(M+1, dtype=self._inttype) + I[0] = 0 + rownz = np.fromfile(fh, dtype=self._inttype, count=M) + np.cumsum(rownz, out=I[1:]) + assert I[-1] == nz + + J = np.fromfile(fh, dtype=self._inttype, count=nz) + assert len(J) == nz + V = np.fromfile(fh, dtype=self._scalartype, count=nz) + assert len(V) == nz + except (AssertionError, MemoryError, IndexError): + raise IOError('Inconsistent or invalid Mat data in file') + + return MatSparse(((M, N), (I, J, V))) + + @decorate_with_conf + def writeMatSparse(self, fh, mat): + """Writes a Mat into a PETSc binary file handle""" + + ((M,N), (I,J,V)) = mat + metadata = np.array([MatSparse._classid,M,N,I[-1]], dtype=self._inttype) + rownz = I[1:] - I[:-1] + + assert len(J.shape) == len(V.shape) == len(I.shape) == 1 + assert len(J) == len(V) == I[-1] == rownz.sum() + assert (rownz > -1).all() + + metadata.tofile(fh) + rownz.astype(self._inttype).tofile(fh) + J.astype(self._inttype).tofile(fh) + V.astype(self._scalartype).tofile(fh) + return + + @decorate_with_conf + def readMatDense(self, fh): + """Reads a PETSc Mat, returning a dense represention of the data, must be called after readObjectType()""" + + try: + M,N,nz = np.fromfile(fh, dtype=self._inttype, count=3) + I = np.empty(M+1, dtype=self._inttype) + I[0] = 0 + rownz = np.fromfile(fh, dtype=self._inttype, count=M) + np.cumsum(rownz, out=I[1:]) + assert I[-1] == nz + + J = np.fromfile(fh, dtype=self._inttype, count=nz) + assert len(J) == nz + V = np.fromfile(fh, dtype=self._scalartype, count=nz) + assert len(V) == nz + + except (AssertionError, MemoryError, IndexError): + raise IOError('Inconsistent or invalid Mat data in file') + + mat = np.zeros((M,N), dtype=self._scalartype) + for row in range(M): + rstart, rend = I[row:row+2] + mat[row, J[rstart:rend]] = V[rstart:rend] + return mat.view(MatDense) + + @decorate_with_conf + def readMatSciPy(self, fh): + from scipy.sparse import csr_matrix + (M, N), (I, J, V) = self.readMatSparse(fh) + return csr_matrix((V, J, I), shape=(M, N)) + + @decorate_with_conf + def writeMatSciPy(self, fh, mat): + from scipy.sparse import csr_matrix + if hasattr(mat, 'tocsr'): + mat = mat.tocsr() + assert isinstance(mat, csr_matrix) + V = mat.data + M,N = mat.shape + J = mat.indices + I = mat.indptr + return self.writeMatSparse(fh, (mat.shape, (mat.indptr,mat.indices,mat.data))) + + @decorate_with_conf + def readMat(self, fh, mattype='sparse'): + """Reads a PETSc Mat from binary file handle, must be called after readObjectType() + + optional mattype: 'sparse" or 'dense' + + See also: readMatSparse, readMatDense + """ + + if mattype == 'sparse': + return self.readMatSparse(fh) + elif mattype == 'dense': + return self.readMatDense(fh) + elif mattype == 'scipy.sparse': + return self.readMatSciPy(fh) + else: + raise RuntimeError('Invalid matrix type requested: choose sparse/dense/scipy.sparse') + + @decorate_with_conf + def readIS(self, fh): + """Reads a PETSc Index Set from binary file handle, must be called after readObjectType()""" + + try: + nz = np.fromfile(fh, dtype=self._inttype, count=1)[0] + v = np.fromfile(fh, dtype=self._inttype, count=nz) + assert len(v) == nz + except (MemoryError,IndexError): + raise IOError('Inconsistent or invalid IS data in file') + return v.view(IS) + + @decorate_with_conf + def writeIS(self, fh, anis): + """Writes a PETSc IS to binary file handle.""" + + metadata = np.array([IS._classid, len(anis)], dtype=self._inttype) + metadata.tofile(fh) + anis.astype(self._inttype).tofile(fh) + return + + @decorate_with_conf + def readObjectType(self, fid): + """Returns the next object type as a string in the file""" + try: + header = np.fromfile(fid, dtype=self._inttype, count=1)[0] + except (MemoryError, IndexError): + raise DoneWithFile + try: + objecttype = self._classid[header] + except KeyError: + raise IOError('Invalid PetscObject CLASSID or object not implemented for python') + return objecttype + + @decorate_with_conf + def readBinaryFile(self, fid, mattype='sparse'): + """Reads a PETSc binary file, returning a tuple of the contained objects. + + objects = self.readBinaryFile(fid, **kwargs) + + Input: + fid : either file name or handle to an open binary file. + + Output: + objects : tuple of objects representing the data in numpy arrays. + + Optional: + mattype : + 'sparse': Return matrices as raw CSR: (M, N), (row, col, val). + 'dense': Return matrices as MxN numpy arrays. + 'scipy.sparse': Return matrices as scipy.sparse objects. + """ + + close = False + + if isinstance(fid, basestring): + fid = open(fid, 'rb') + close = True + + objects = [] + try: + while True: + objecttype = self.readObjectType(fid) + + if objecttype == 'Vec': + objects.append(self.readVec(fid)) + elif objecttype == 'IS': + objects.append(self.readIS(fid)) + elif objecttype == 'Mat': + objects.append(self.readMat(fid,mattype)) + elif objecttype == 'Bag': + raise NotImplementedError('Bag Reader not yet implemented') + except DoneWithFile: + pass + finally: + if close: + fid.close() + + return tuple(objects) + + @decorate_with_conf + def writeBinaryFile(self, fid, objects): + """Writes a PETSc binary file containing the objects given. + + readBinaryFile(fid, objects) + + Input: + fid : either file handle to an open binary file, or filename. + objects : list of objects representing the data in numpy arrays, + which must be of type Vec, IS, MatSparse, or MatSciPy. + """ + close = False + if isinstance(fid, basestring): + fid = open(fid, 'wb') + close = True + + for petscobj in objects: + if (isinstance(petscobj, Vec)): + self.writeVec(fid, petscobj) + elif (isinstance(petscobj, IS)): + self.writeIS(fid, petscobj) + elif (isinstance(petscobj, MatSparse)): + self.writeMatSparse(fid, petscobj) + elif (isinstance(petscobj, MatDense)): + if close: + fid.close() + raise NotImplementedError('Writing a dense matrix is not yet supported') + else: + try: + self.writeMatSciPy(fid, petscobj) + except AssertionError: + if close: + fid.close() + raise TypeError('Object %s is not a valid PETSc object'%(petscobj.__repr__())) + if close: + fid.close() + return diff --git a/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/boundary_conditions.py b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/boundary_conditions.py new file mode 100644 index 00000000..ce33f043 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/boundary_conditions.py @@ -0,0 +1,107 @@ +import numpy as np +import arrayfire as af +import domain + +in_q1_left = 'mirror' +in_q1_right = 'mirror' +in_q2_bottom = 'mirror+dirichlet' +in_q2_top = 'mirror+dirichlet' + +@af.broadcast +def f_top(f, t, q1, q2, p1, p2, p3, params): + + k = params.boltzmann_constant + E_upper = params.E_band + T = params.initial_temperature + mu = params.initial_mu + + t = params.current_time + omega = 2. * np.pi * params.AC_freq + vel_drift_y_in = -params.vel_drift_x_in + + if (params.p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (params.p_space_grid == 'polar2D'): + p_x = p1 * af.cos(p2) + p_y = p1 * af.sin(p2) + else: + raise NotImplementedError('Unsupported coordinate system in p_space') + + + fermi_dirac_in = (1./(af.exp( (E_upper - vel_drift_y_in*p_y - mu)/(k*T) ) + 1.) + ) + + if (params.contact_geometry=="straight"): + # Contacts on either side of the device + + q1_contact_start = params.contact_start + q1_contact_end = params.contact_end + + cond = ((q1 >= q1_contact_start) & \ + (q1 <= q1_contact_end) \ + ) + + f_left = cond*fermi_dirac_in + (1 - cond)*f + + elif (params.contact_geometry=="turn_around"): + # Contacts on the same side of the device + + vel_drift_x_out = -params.vel_drift_x_in * np.sin(omega*t) + + fermi_dirac_out = (1./(af.exp( (E_upper - vel_drift_x_out*p_x - mu)/(k*T) ) + 1.) + ) + + # TODO: set these parameters in params.py + cond_in = ((q2 >= 3.5) & (q2 <= 4.5)) + cond_out = ((q2 >= 5.5) & (q2 <= 6.5)) + + f_left = cond_in*fermi_dirac_in + cond_out*fermi_dirac_out \ + + (1 - cond_in)*(1 - cond_out)*f + + af.eval(f_left) + return(f_left) + +@af.broadcast +def f_bottom(f, t, q1, q2, p1, p2, p3, params): + + k = params.boltzmann_constant + E_upper = params.E_band + T = params.initial_temperature + mu = params.initial_mu + + t = params.current_time + omega = 2. * np.pi * params.AC_freq + vel_drift_y_out = -params.vel_drift_x_out + + if (params.p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (params.p_space_grid == 'polar2D'): + p_x = p1 * af.cos(p2) + p_y = p1 * af.sin(p2) + else: + raise NotImplementedError('Unsupported coordinate system in p_space') + + fermi_dirac_out = (1./(af.exp( (E_upper - vel_drift_y_out*p_y - mu)/(k*T) ) + 1.) + ) + + if (params.contact_geometry=="straight"): + # Contacts on either side of the device + + q1_contact_start = params.contact_start + q1_contact_end = params.contact_end + + cond = ((q1 >= q1_contact_start) & \ + (q1 <= q1_contact_end) \ + ) + + f_right = cond*fermi_dirac_out + (1 - cond)*f + + elif (params.contact_geometry=="turn_around"): + # Contacts on the same side of the device + + f_right = f + + af.eval(f_right) + return(f_right) diff --git a/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/check.py b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/check.py new file mode 100644 index 00000000..71fe46ef --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/check.py @@ -0,0 +1,42 @@ +import numpy as np +import params +import arrayfire as af +import pylab as pl + +import domain + +from bolt.src.electronic_boltzmann.utils.polygon import polygon + +p2_start = -np.pi +p2_end = np.pi +N_p2 = domain.N_p2 +theta = \ + p2_start + (0.5 + np.arange(N_p2))*(p2_end - p2_start)/N_p2 + +theta = af.from_ndarray(theta) + +hexa = polygon(6, theta, rotation = np.pi/6) +hexa = hexa.to_ndarray() + +#pl.polar(theta, hexa) + +#pl.plot(theta, hexa * np.cos(theta)) +#pl.plot(theta, hexa * np.sin(theta)) + +pl.gca().set_aspect(1) +pl.plot(hexa*np.cos(theta), hexa*np.sin(theta)) + +#p_hat_0_old = np.loadtxt("P_hat_0_old.txt") +#p_hat_1_old = np.loadtxt("P_hat_1_old.txt") + +#p_hat_0 = np.loadtxt("P_hat_0.txt") +#p_hat_1 = np.loadtxt("P_hat_1.txt") + +#pl.plot(theta, p_hat_0_old) +#pl.plot(theta, p_hat_1_old) + +#pl.plot(theta, p_hat_0, '--') +#pl.plot(theta, p_hat_1, '--') + + +pl.savefig("images/test.png") diff --git a/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/cleanup.py b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/cleanup.py new file mode 100644 index 00000000..21ce5c08 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/cleanup.py @@ -0,0 +1,29 @@ +import os +import numpy as np +import glob + +# TODO : Set t_final and number of gpus in jobscript depending on device size +start_index = 3.00 +end_index = 3.5001 +step = 0.1 + + +for index in np.arange(start_index, end_index, step): + print (index) + filepath = \ + '/home/mchandra/gitansh/bolt_master/example_problems/electronic_boltzmann/pdcoo2/L_1.0_%.2f_tau_ee_inf_tau_eph_inf_DC_rotated'%index + + # List all dump_f files + dist_func_files = np.sort(glob.glob(filepath+'/dump_f/*.bin')) + dist_func_info_files = np.sort(glob.glob(filepath+'/dump_f/*.bin.info')) + + # Save first and last files + os.system("mkdir " + filepath + "/dump_f/save") + os.system("mv " + str(dist_func_files[0]) + " " + filepath+"/dump_f/save/.") + os.system("mv " + str(dist_func_files[-1]) + " " + filepath+"/dump_f/save/.") + os.system("mv " + str(dist_func_info_files[0]) + " " + filepath+"/dump_f/save/.") + os.system("mv " + str(dist_func_info_files[-1]) + " " + filepath+"/dump_f/save/.") + os.system("rm " + filepath + "/dump_f/t*") + + # Remove all files in dump_f except first and last dist funcs + #os.system("rm " + filepath+"/output.txt") diff --git a/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/domain.py b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/domain.py new file mode 100644 index 00000000..857e1bfe --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/domain.py @@ -0,0 +1,66 @@ +import numpy as np +import params + +q2_start = 0. +q2_end = 1.0 +N_q2 = 40 + +q1_start = 0. +N_q1 = int(N_q2*q1_end/q2_end) + +# If N_p1 > 1, mirror boundary conditions require p1 to be +# symmetric about zero +# TODO : Check and fix discrepancy between this and the claim +# that p1_center = mu in polar representation +N_p1 = 1 # Set equal to 1 for 1D polar + +# In the cartesian representation of momentum space, +# p1 = p_x (magnitude of momentum) +# p1_start and p1_end are set such that p1_center is 0 + +# Uncomment the following for the cartesian representation of momentum space +#p1_start = [-0.04] +#p1_end = [0.04] + + +# In the 2D polar representation of momentum space, +# p1 = p_r (magnitude of momentum) +# p1_start and p1_end are set such that p1_center is mu + +# Uncomment the following for the 2D polar representation of momentum space +#p1_start = [params.initial_mu - \ +# 16.*params.boltzmann_constant*params.initial_temperature] +#p1_end = [params.initial_mu + \ +# 16.*params.boltzmann_constant*params.initial_temperature] + +# Uncomment the following for the 1D polar representation of momentum space +p1_start = [0.5*params.initial_mu/params.fermi_velocity] +p1_end = [1.5*params.initial_mu/params.fermi_velocity] + + +# If N_p2 > 1, mirror boundary conditions require p2 to be +# symmetric about zero +N_p2 = 2048 + +# In the cartesian representation of momentum space, +# p2 = p_y (magnitude of momentum) +# p2_start and p2_end are set such that p2_center is 0 +#p2_start = [-0.04] +#p2_end = [0.04] + +# In the 2D polar representation of momentum space, +# p2 = p_theta (angle of momentum) +# N_p_theta MUST be even. +#p2_start = [-np.pi] +#p2_end = [np.pi] +p2_start = [-3.14159265359] +p2_end = [3.14159265359] + +# If N_p3 > 1, mirror boundary conditions require p3 to be +# symmetric about zero + +p3_start = [-0.5] +p3_end = [0.5] +N_p3 = 1 + +N_ghost = 2 diff --git a/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/edge_density.py b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/edge_density.py new file mode 100644 index 00000000..3697590e --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/edge_density.py @@ -0,0 +1,122 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +#import yt +#yt.enable_parallelism() +import os + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +import PetscBinaryIO + +import domain +import boundary_conditions +import params +import initialize + + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +# Left needs to be near source, right sensor near drain +sensor_1_left_start = 8.5 # um +sensor_1_left_end = 9.5 # um + +sensor_1_right_start = 8.5 # um +sensor_1_right_end = 9.5 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +io = PetscBinaryIO.PetscBinaryIO() + +filepath = os.getcwd() +moment_files = np.sort(glob.glob(filepath+'/dump_moments/*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/dump_lagrange_multipliers/*.bin')) + +dt = params.dt +dump_interval = params.dump_steps + +sensor_1_signal_array = [] +print("Reading sensor signal...") +for file_number, dump_file in enumerate(moment_files): + + moments = io.readBinaryFile(dump_file) + moments = moments[0].reshape(N_q2, N_q1, 3) + + density = moments[:, :, 0] + + source = np.mean(density[source_indices, 0]) + drain = np.mean(density[drain_indices, -1]) + + sensor_1_left = np.mean(density[0, 0]) + sensor_1_right = np.mean(density[0, -1]) + + sensor_1_signal = sensor_1_left - sensor_1_right + + sensor_1_signal_array.append(sensor_1_signal) + +time_array = np.loadtxt("dump_time_array.txt") +AC_freq = 1./100 +input_signal_array = np.sin(2.*np.pi*AC_freq*time_array) +sensor_1_signal_array = np.array(sensor_1_signal_array) +half_time = (int)(time_array.size/2) + +input_normalized = \ + input_signal_array/np.max(np.abs(input_signal_array[half_time:])) +sensor_normalized = \ + sensor_1_signal_array#/np.max(np.abs(sensor_1_signal_array[half_time:])) + diff --git a/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/edge_potential.py b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/edge_potential.py new file mode 100644 index 00000000..c32ff136 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/edge_potential.py @@ -0,0 +1,113 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import os +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +#import yt +#yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + + +import domain +import boundary_conditions +import params +import initialize + +import PetscBinaryIO +io = PetscBinaryIO.PetscBinaryIO() + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 12, 7.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +# Left needs to be near source, right sensor near drain +sensor_1_left_start = 0.25 # um +sensor_1_left_end = 5.0 # um + +sensor_1_right_start = 0.25 # um +sensor_1_right_end = 5.0 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +filepath = os.getcwd() +moment_files = np.sort(glob.glob(filepath+'/dump_moments/*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/dump_lagrange_multipliers/*.bin')) + +dt = params.dt +dump_interval = params.dump_steps + + +file_number = -1 +print("file number = ", file_number, "of ", moment_files.size) + +moments = io.readBinaryFile(moment_files[file_number]) +moments = moments[0].reshape(N_q2, N_q1, 3) + +density = moments[:, :, 0] +j_x = moments[:, :, 1] +j_y = moments[:, :, 2] + +density = density - np.mean(density) + +left_edge = 0 +pl.plot(q2[sensor_1_left_indices], density[sensor_1_left_indices, left_edge]) + +pl.ylabel('$\delta$n') +pl.xlabel('y ($\mu$m)') + +pl.savefig("images/iv.png") + + + diff --git a/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/enstrophy.py b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/enstrophy.py new file mode 100644 index 00000000..aeab5a28 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/enstrophy.py @@ -0,0 +1,142 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +filepath = \ +'/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_1.0_tau_ee_0.2_tau_eph_0.5/dumps' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +kinetic_energy_array = [] +enstrophy_array = [] +print("Reading kinetic energy and enstrophy signals...") +for file_number, dump_file in enumerate(moment_files): + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + + h5f = h5py.File(lagrange_multiplier_files[file_number], 'r') + lagrange_multipliers = h5f['lagrange_multipliers'][:] + h5f.close() + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + + dq1 = (domain.q1_end - domain.q1_start)/domain.N_q1 + dq2 = (domain.q2_end - domain.q2_start)/domain.N_q2 + + dvx_dx, dvx_dy = np.gradient(j_x/density, dq1, dq2) + dvy_dx, dvy_dy = np.gradient(j_y/density, dq1, dq2) + + vorticity = dvy_dx - dvx_dy + + kinetic_energy = 0.5 * np.sum(vel_drift_x**2 + vel_drift_y**2) * dq1 * dq2 + kinetic_energy_array.append(kinetic_energy) + + enstrophy = np.sum(vorticity**2) * dq1 * dq2 + enstrophy_array.append(enstrophy) + +time_array = np.loadtxt("dump_time_array.txt") +half_time = (int)(time_array.size/2) + +kinetic_energy_normalized = \ + kinetic_energy_array/np.max(np.abs(kinetic_energy_array[half_time:])) +enstrophy_normalized = \ + enstrophy_array/np.max(np.abs(enstrophy_array[half_time:])) + + +pl.plot(time_array, kinetic_energy_normalized) +pl.plot(time_array, enstrophy_normalized) +pl.axhline(0, color='black', linestyle='--') + +pl.legend(['Kinetic Energy', 'Enstrophy'], loc=1) +pl.xlabel(r'Time (ps)') +pl.xlim([0, 200]) +pl.ylim([-0.1, 1.1]) + +pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 1.0$ ps') +pl.savefig('vorticity_images/iv' + '.png') +pl.clf() + + diff --git a/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/fire_job_batch.py b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/fire_job_batch.py new file mode 100644 index 00000000..44d81a4d --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/fire_job_batch.py @@ -0,0 +1,47 @@ +import os +import numpy as np + +# TODO : Set t_final and number of gpus in jobscript depending on device size +start_index = 1.50 + 0.025 +end_index = 1.5751 +step = 0.05 + +current_filepath = \ + '/home/mchandra/gitansh/bolt_master/example_problems/electronic_boltzmann/pdcoo2/ref_rotated' +source_filepath = \ + '/home/mchandra/gitansh/bolt_master/example_problems/electronic_boltzmann/pdcoo2/ref_rotated' + +for index in np.arange(start_index, end_index, step): + filepath = \ + '/home/mchandra/gitansh/bolt_master/example_problems/electronic_boltzmann/pdcoo2/L_1.0_%.3f_tau_ee_inf_tau_eph_inf_DC_rotated'%index + + # If folder does not exist, make one and add all files from source folder + + if not os.path.isdir(filepath): + os.mkdir(filepath) + os.mkdir(filepath+"/dump_f") + os.mkdir(filepath+"/dump_moments") + os.mkdir(filepath+"/dump_lagrange_multipliers") + os.mkdir(filepath+"/images") + + os.system("cp " + source_filepath + "/* " + filepath+"/.") + + # Change required files + # Code copied from here : + # https://stackoverflow.com/questions/4454298/prepend-a-line-to-an-existing-file-in-python + + f = open(filepath + "/domain.py", "r") + old = f.read() # read everything in the file + f.close() + + f = open(filepath + "/domain.py", "w") + f.write("q1_end = " + str(index) + " \n") + f.write(old) + f.close() + + # Schedule job after changing to run directory so that generated slurm file + # is stored in that directory + os.chdir(filepath) + os.system("sbatch job_script") + os.chdir(current_filepath) # Return to job firing script's directory + diff --git a/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/initialize.py b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/initialize.py new file mode 100644 index 00000000..c2ee7948 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/initialize.py @@ -0,0 +1,99 @@ +""" +Functions which are used in assigning the I.C's to +the system. +""" + +import arrayfire as af +import numpy as np +from petsc4py import PETSc + +import domain + +def initialize_f(q1, q2, p1, p2, p3, params): + + PETSc.Sys.Print("Initializing f") + k = params.boltzmann_constant + + params.mu = 0.*q1 + params.initial_mu + params.T = 0.*q1 + params.initial_temperature + params.vel_drift_x = 0.*q1 + params.vel_drift_y = 0.*q1 + + params.mu_ee = params.mu.copy() + params.T_ee = params.T.copy() + params.vel_drift_x = 0.*q1 + 0e-3 + params.vel_drift_y = 0.*q1 + 0e-3 + + params.p_x, params.p_y = params.get_p_x_and_p_y(p1, p2) + params.E_band = params.band_energy(p1, p2) + params.vel_band = params.band_velocity(p1, p2) + + # Evaluating velocity space resolution for each species: + dp1 = []; dp2 = []; dp3 = [] + N_p1 = domain.N_p1; N_p2 = domain.N_p2; N_p3 = domain.N_p3 + p1_start = domain.p1_start; p1_end = domain.p1_end + p2_start = domain.p2_start; p2_end = domain.p2_end + p3_start = domain.p3_start; p3_end = domain.p3_end + + N_species = len(params.mass) + for i in range(N_species): + dp1.append((p1_end[i] - p1_start[i]) / N_p1) + dp2.append((p2_end[i] - p2_start[i]) / N_p2) + dp3.append((p3_end[i] - p3_start[i]) / N_p3) + + + theta = af.atan(params.p_y / params.p_x) + p_f = params.fermi_momentum_magnitude(theta) + + if (params.p_space_grid == 'cartesian'): + dp_x = dp1[0]; dp_y = dp2[0]; dp_z = dp3[0] + params.integral_measure = \ + (4./(2.*np.pi*params.h_bar)**2) * dp_z * dp_y * dp_x + + elif (params.p_space_grid == 'polar2D'): + # In polar2D coordinates, p1 = radius and p2 = theta + # Integral : \int delta(r - r_F) F(r, theta) r dr dtheta + r = p1; theta = p2 + dp_r = dp1[0]; dp_theta = dp2[0] + + if (params.zero_temperature): + # Assumption : F(r, theta) = delta(r-r_F)*F(theta) + params.integral_measure = \ + (4./(2.*np.pi*params.h_bar)**2) * p_f * dp_theta + + else: + params.integral_measure = \ + (4./(2.*np.pi*params.h_bar)**2) * r * dp_r * dp_theta + + + else : + raise NotImplementedError('Unsupported coordinate system in p_space') + + + + f = (1./(af.exp( (params.E_band - params.vel_drift_x*params.p_x + - params.vel_drift_y*params.p_y + - params.mu + )/(k*params.T) + ) + 1. + )) + + af.eval(f) + return(f) + + +def initialize_E(q1, q2, params): + + E1 = 0.*q1 + E2 = 0.*q1 + E3 = 0.*q1 + + return(E1, E2, E3) + +def initialize_B(q1, q2, params): + + B1 = 0.*q1 + B2 = 0.*q1 + B3 = 0.*q1 + + return(B1, B2, B3) diff --git a/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/job_script b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/job_script new file mode 100644 index 00000000..374fd6c1 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/job_script @@ -0,0 +1,4 @@ +#!/bin/bash +#SBATCH -p gpu -n 2 --gres=gpu:2 -c1 --hint=nomultithread -t 2-00:00 +# (Note: use one MPI process per gpu, update both gres and -n together; max 6) +export PYTHONPATH=/home/mchandra/gitansh/bolt_master; time mpirun python main.py > output.txt diff --git a/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/main.py b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/main.py new file mode 100644 index 00000000..09596215 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/main.py @@ -0,0 +1,172 @@ +import os +import arrayfire as af +import numpy as np +import math +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +from mpi4py import MPI +MPI.WTIME_IS_GLOBAL=True + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear.nonlinear_solver \ + import nonlinear_solver +#from bolt.lib.nonlinear.fields.fields.fields \ +# import fields_solver.compute_electrostatic_fields +from bolt.lib.utils.restart_latest import latest_output, format_time + +import domain +import boundary_conditions +import initialize +import params + +import bolt.src.electronic_boltzmann.advection_terms \ + as advection_terms +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator +import bolt.src.electronic_boltzmann.moments \ + as moments + + +# Create required folders if they do not exist already +#if not os.path.isdir("dump_f"): +# os.system("mkdir dump_f") +#if not os.path.isdir("dump_moments"): +# os.system("mkdir dump_moments") +#if not os.path.isdir("dump_lagrange_multipliers"): +# os.system("mkdir dump_lagrange_multipliers") +#if not os.path.isdir("images"): +# os.system("mkdir images") + + +# Defining the physical system to be solved: +system = physical_system(domain, + boundary_conditions, + params, + initialize, + advection_terms, + collision_operator.RTA, + moments + ) + +# Declaring a nonlinear system object which will evolve the defined physical system: +nls = nonlinear_solver(system) +N_g = domain.N_ghost +params.rank = nls._comm.rank + +# Time parameters: +dt = params.dt +t_final = params.t_final +params.current_time = time_elapsed = 0.0 +params.time_step = time_step = 0 +dump_counter = 0 +dump_time_array = [] + + +using_latest_restart = False +if(params.latest_restart == True): + latest_f, time_elapsed = latest_output('') + print(time_elapsed) + if(latest_f is not None and time_elapsed is not None): + nls.load_distribution_function(latest_f) + dump_time_array = np.loadtxt("dump_time_array.txt").tolist() + using_latest_restart = True + + +if using_latest_restart == False: + if(params.t_restart == 0 or params.latest_restart == True): + time_elapsed = 0 + formatted_time = format_time(time_elapsed) + nls.dump_distribution_function('dump_f/t=' + formatted_time) + nls.dump_moments('dump_moments/t=' + formatted_time) + nls.dump_aux_arrays([params.mu, + params.mu_ee, + params.T_ee, + params.vel_drift_x, params.vel_drift_y + ], + 'lagrange_multipliers', + 'dump_lagrange_multipliers/t=' + formatted_time + ) + dump_time_array.append(time_elapsed) + if (params.rank==0): + np.savetxt("dump_time_array.txt", dump_time_array) + else: + time_elapsed = params.t_restart + formatted_time = format_time(time_elapsed) + nls.load_distribution_function('dump_f/t=' + formatted_time) + +# Checking that the file writing intervals are greater than dt: +assert(params.dt_dump_f >= dt) +assert(params.dt_dump_moments >= dt) +assert(params.dt_dump_fields >= dt) + + +#if (params.restart): +# nls.load_distribution_function(params.restart_file) + +density = nls.compute_moments('density') +print("rank = ", params.rank, "\n", + " = ", af.mean(params.mu[0, 0, N_g:-N_g, N_g:-N_g]), "\n", + " max(mu) = ", af.max(params.mu[0, 0, N_g:-N_g, N_g:-N_g]), "\n", + " = ", af.mean(density[0, 0, N_g:-N_g, N_g:-N_g]), "i\n", + " max(n) = ", af.max(density[0, 0, N_g:-N_g, N_g:-N_g]), "\n" + ) + +nls.f = af.select(nls.f < 1e-20, 1e-20, nls.f) +while(time_elapsed < t_final): + + # Refine to machine error + if (time_step==0): + params.collision_nonlinear_iters = 10 + else: + params.collision_nonlinear_iters = params.collision_operator_nonlinear_iters + + dump_steps = params.dump_steps + + if(params.dt_dump_moments != 0): + # We step by delta_dt to get the values at dt_dump + delta_dt = (1 - math.modf(time_elapsed/params.dt_dump_moments)[0]) \ + * params.dt_dump_moments + + if((delta_dt-dt)<1e-5): + nls.strang_timestep(delta_dt) + time_elapsed += delta_dt + formatted_time = format_time(time_elapsed) + nls.dump_moments('dump_moments/t=' + formatted_time) + nls.dump_aux_arrays([params.mu, + params.mu_ee, + params.T_ee, + params.vel_drift_x, params.vel_drift_y + ], + 'lagrange_multipliers', + 'dump_lagrange_multipliers/t=' + formatted_time + ) + dump_time_array.append(time_elapsed) + if (params.rank==0): + np.savetxt("dump_time_array.txt", dump_time_array) + + if(math.modf(time_elapsed/params.dt_dump_f)[0] < 1e-12): + formatted_time = format_time(time_elapsed) + nls.dump_distribution_function('dump_f/t=' + formatted_time) + + PETSc.Sys.Print("Time step =", time_step, ", Time =", time_elapsed) + + nls.strang_timestep(dt) + time_elapsed = time_elapsed + dt + time_step = time_step + 1 + params.time_step = time_step + params.current_time = time_elapsed + + # Floors + nls.f = af.select(nls.f < 1e-20, 1e-20, nls.f) + + density = nls.compute_moments('density') + print("rank = ", params.rank, "\n", + " = ", af.mean(params.mu[0, 0, N_g:-N_g, N_g:-N_g]), "\n", + " max(mu) = ", af.max(params.mu[0, 0, N_g:-N_g, N_g:-N_g]), "\n", + " = ", af.mean(density[0, 0, N_g:-N_g, N_g:-N_g]), "\n", + " max(n) = ", af.max(density[0, 0, N_g:-N_g, N_g:-N_g]), "\n" + ) + PETSc.Sys.Print("--------------------\n") + +#nls.dump_distribution_function('dump_f/t_laststep') diff --git a/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/momentum_space_movie.py b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/momentum_space_movie.py new file mode 100644 index 00000000..1de644d7 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/momentum_space_movie.py @@ -0,0 +1,134 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import os +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1_start = domain.q1_start +q1_end = domain.q1_end +q2_start = domain.q2_start +q2_end = domain.q2_end + +q1 = q1_start + (0.5 + np.arange(N_q1)) * (q1_end - q1_start)/N_q1 +q2 = q2_start + (0.5 + np.arange(N_q2)) * (q2_end - q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 + +p1_start = domain.p1_start +p1_end = domain.p1_end +p2_start = domain.p2_start +p2_end = domain.p2_end + +p1 = p1_start[0] + (0.5 + np.arange(N_p1)) * (p1_end[0] - p1_start[0])/N_p1 +p2 = p2_start[0] + (0.5 + np.arange(N_p2)) * (p2_end[0] - p2_start[0])/N_p2 + +p1_meshgrid, p2_meshgrid = np.meshgrid(p1, p2) + +p_x = p1_meshgrid * np.cos(p2_meshgrid) +p_y = p1_meshgrid * np.sin(p2_meshgrid) + +#p2_meshgrid, p1_meshgrid = np.meshgrid(p2, p1) + +io = PetscBinaryIO.PetscBinaryIO() + +filepath = os.getcwd() + "/dumps" +moment_files = np.sort(glob.glob(filepath+'/moment*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) +dist_func_files = np.sort(glob.glob(filepath+'/f_*.bin')) + +dist_func_bg_file = dist_func_files[0] +dist_func_file = dist_func_files[-1] + +dist_func_background = io.readBinaryFile(dist_func_bg_file) +#dist_func_background = dist_func_background[0].reshape(N_q2, N_q1, N_p2, N_p1) +dist_func_background = dist_func_background[0].reshape(N_q1, N_q2, 1, 1, N_p2, N_p1) +dist_func = io.readBinaryFile(dist_func_file) + +print (dist_func[0].shape) + +dist_func = dist_func[0].reshape(N_q1, N_q2, 1, 1, N_p2, N_p1) + + +N = 7 +for index_1 in range(N): + for index_2 in range(N): + + q1_position = int(N_q1*((index_1/N)+(1/(2*N)))) + q2_position = int(N_q2*((index_2/N)+(1/(2*N)))) + + #a = np.max((dist_func - dist_func_background)[q2_position, q1_position, :, :]) + #b = np.abs(np.min((dist_func - dist_func_background)[q2_position, q1_position, :, :])) + #norm_factor = np.maximum(a, b) + #f_at_desired_q = \ + # np.reshape((dist_func-dist_func_background)[q2_position, q1_position, :, :], + # [N_p2, N_p1])/norm_factor + + f_at_desired_q = np.reshape((dist_func - \ + dist_func_background)[q1_position, q2_position, :], + [N_p2, N_p1] + ) + pl.contourf(p1_meshgrid, p2_meshgrid, f_at_desired_q, 100, cmap='bwr') + + #np.savetxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2), f_at_desired_q) + #f = np.loadtxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2)) + + + #pl.contourf(p_x, p_y, f_at_desired_q, 100, cmap='bwr') + #pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.xlabel('$p_x$') + pl.ylabel('$p_y$') + pl.gca().set_aspect('equal') + pl.savefig('images/dist_func_at_a_point_%d_%d.png'%(index_1, index_2)) + pl.clf() + diff --git a/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/momentum_space_movie_debug.py b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/momentum_space_movie_debug.py new file mode 100644 index 00000000..0b2c719d --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/momentum_space_movie_debug.py @@ -0,0 +1,182 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import os +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +#import yt +#yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain +import params + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_s = len(params.mass) # Number of species + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1_start = domain.q1_start +q1_end = domain.q1_end +q2_start = domain.q2_start +q2_end = domain.q2_end + +q1 = q1_start + (0.5 + np.arange(N_q1)) * (q1_end - q1_start)/N_q1 +q2 = q2_start + (0.5 + np.arange(N_q2)) * (q2_end - q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 +N_p3 = domain.N_p3 + +p1_start = domain.p1_start +p1_end = domain.p1_end +p2_start = domain.p2_start +p2_end = domain.p2_end + +p1 = p1_start[0] + (0.5 + np.arange(N_p1)) * (p1_end[0] - p1_start[0])/N_p1 +p2 = p2_start[0] + (0.5 + np.arange(N_p2)) * (p2_end[0] - p2_start[0])/N_p2 + +p1_meshgrid, p2_meshgrid = np.meshgrid(p1, p2) + +p_x = p1_meshgrid * np.cos(p2_meshgrid) +p_y = p1_meshgrid * np.sin(p2_meshgrid) + +#p2_meshgrid, p1_meshgrid = np.meshgrid(p2, p1) + +io = PetscBinaryIO.PetscBinaryIO() + +filepath = os.getcwd() +moment_files = np.sort(glob.glob(filepath+'/dump_moments/*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/dump_lagrange_multipliers/*.bin')) +dist_func_files = np.sort(glob.glob(filepath+'/dump_f/*.bin')) + +#moment_files = np.sort(glob.glob(filepath+'/dumps/moments*.bin')) +#lagrange_multiplier_files = \ +# np.sort(glob.glob(filepath+'/dumps/lagrange_multipliers*.bin')) +#dist_func_files = np.sort(glob.glob(filepath+'/dumps/f*.bin')) + +dist_func_bg_file = dist_func_files[0] +dist_func_file = dist_func_files[-1] + +print(dist_func_bg_file) +print(dist_func_file) + +dist_func_background = io.readBinaryFile(dist_func_bg_file) +#dist_func_background = dist_func_background[0].reshape(N_q2, N_q1, N_p2, N_p1) +dist_func_background = dist_func_background[0].reshape(N_q2, N_q1, N_s, N_p3, N_p2, N_p1) +dist_func = io.readBinaryFile(dist_func_file) + +print (dist_func[0].shape) + +dist_func = dist_func[0].reshape(N_q2, N_q1, N_s, N_p3, N_p2, N_p1) + +time_array = np.loadtxt("dump_time_array.txt") +file_number = -1 + +N = 7 +for index_1 in range(1): + for index_2 in range(N_q2): + + q1_position = index_1 + q2_position = index_2 + + a = np.max((dist_func - dist_func_background)[q2_position, q1_position, :, :]) + b = np.abs(np.min((dist_func - dist_func_background)[q2_position, q1_position, :, :])) + norm_factor = 1.#np.maximum(a, b) + f_at_desired_q = \ + np.reshape((dist_func - \ + dist_func_background)[q2_position, q1_position, :, :],\ + [N_p2, N_p1])/norm_factor + + im = pl.plot(p2, f_at_desired_q) + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.ylabel('$f$') + pl.xlabel('$p_{\\theta}$') + #pl.tight_layout() + pl.savefig('images/dist_func_at_a_point_%d_%d.png'%(index_1, index_2)) + pl.clf() + + np.savetxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2), f_at_desired_q) + f = np.loadtxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2)) + + #f_at_desired_q = np.reshape((dist_func - \ + # dist_func_background)[q1_position, q2_position, :], + # [N_p2, N_p1] + # ) + + #print ("f at desired q : ", dist_func[q1_position, q2_position, :].shape) + print ("norm : ", norm_factor) + + + radius = f.copy() + theta = p2.copy() + + x = (radius + 5.)*np.cos(theta) + y = (radius + 5.)*np.sin(theta) + + x_bg = 5*np.cos(theta) + y_bg = 5*np.sin(theta) + + print ('p2 : ', p2.shape) + #pl.plot(p2, f_at_desired_q) + pl.plot(x, y, color='r', linestyle = '-', lw=3) + pl.plot(x_bg, y_bg, color='k', alpha=0.5, lw=3) + #pl.contourf(p1_meshgrid, p2_meshgrid, f_at_desired_q, 100, cmap='bwr') + + #np.savetxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2), f_at_desired_q) + #f = np.loadtxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2)) + + + #pl.contourf(p_x, p_y, f_at_desired_q, 100, cmap='bwr') + #pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.xlabel('$p_x$') + pl.ylabel('$p_y$') + + pl.xlim([-6.5, 6.5]) + pl.ylim([-6.5, 6.5]) + + pl.gca().set_aspect('equal') + #pl.savefig('images/dist_func_at_a_point_%d_%d.png'%(index_1, index_2)) + pl.clf() + diff --git a/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/momentum_space_movie_zero_T.py b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/momentum_space_movie_zero_T.py new file mode 100644 index 00000000..b13ab52d --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/momentum_space_movie_zero_T.py @@ -0,0 +1,193 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import os +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +#import yt +#yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +from bolt.src.electronic_boltzmann.utils.polygon import polygon + +import domain +import params + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_s = len(params.mass) # Number of species + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1_start = domain.q1_start +q1_end = domain.q1_end +q2_start = domain.q2_start +q2_end = domain.q2_end + +q1 = q1_start + (0.5 + np.arange(N_q1)) * (q1_end - q1_start)/N_q1 +q2 = q2_start + (0.5 + np.arange(N_q2)) * (q2_end - q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 +N_p3 = domain.N_p3 + +p1_start = domain.p1_start +p1_end = domain.p1_end +p2_start = domain.p2_start +p2_end = domain.p2_end + +p1 = p1_start[0] + (0.5 + np.arange(N_p1)) * (p1_end[0] - p1_start[0])/N_p1 +p2 = p2_start[0] + (0.5 + np.arange(N_p2)) * (p2_end[0] - p2_start[0])/N_p2 + +p1_meshgrid, p2_meshgrid = np.meshgrid(p1, p2) + +p_x = p1_meshgrid * np.cos(p2_meshgrid) +p_y = p1_meshgrid * np.sin(p2_meshgrid) + +#p2_meshgrid, p1_meshgrid = np.meshgrid(p2, p1) + +io = PetscBinaryIO.PetscBinaryIO() + +filepath = os.getcwd() +moment_files = np.sort(glob.glob(filepath+'/dump_moments/*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/dump_lagrange_multipliers/*.bin')) +dist_func_files = np.sort(glob.glob(filepath+'/dump_f/*.bin')) + +#moment_files = np.sort(glob.glob(filepath+'/dumps/moments*.bin')) +#lagrange_multiplier_files = \ +# np.sort(glob.glob(filepath+'/dumps/lagrange_multipliers*.bin')) +#dist_func_files = np.sort(glob.glob(filepath+'/dumps/f*.bin')) + +dist_func_bg_file = dist_func_files[0] +dist_func_file = dist_func_files[-1] + +print(dist_func_bg_file) +print(dist_func_file) + +dist_func_background = io.readBinaryFile(dist_func_bg_file) +#dist_func_background = dist_func_background[0].reshape(N_q2, N_q1, N_p2, N_p1) +dist_func_background = dist_func_background[0].reshape(N_q2, N_q1, N_s, N_p3, N_p2, N_p1) +dist_func = io.readBinaryFile(dist_func_file) + +print (dist_func[0].shape) + +dist_func = dist_func[0].reshape(N_q2, N_q1, N_s, N_p3, N_p2, N_p1) + +time_array = np.loadtxt("dump_time_array.txt") +file_number = -1 + +N = 7 +for index_1 in range(N): + for index_2 in range(N): + + q1_position = int(N_q1*((index_1/N)+(1/(2*N)))) + q2_position = int(N_q2*((index_2/N)+(1/(2*N)))) + + a = np.max((dist_func - dist_func_background)[q2_position, q1_position, :, :]) + b = np.abs(np.min((dist_func - dist_func_background)[q2_position, q1_position, :, :])) + norm_factor = np.maximum(a, b) + f_at_desired_q = \ + np.reshape((dist_func-\ + dist_func_background)[q2_position, q1_position, :, :],\ + [N_p2, N_p1])/norm_factor + + im = pl.plot(p2, f_at_desired_q) + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.ylabel('$f$') + pl.xlabel('$p_{\\theta}$') + #pl.tight_layout() + #pl.savefig('images/dist_func_at_a_point_%d_%d.png'%(index_1, index_2)) + pl.clf() + + np.savetxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2), f_at_desired_q) + f = np.loadtxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2)) + + #f_at_desired_q = np.reshape((dist_func - \ + # dist_func_background)[q1_position, q2_position, :], + # [N_p2, N_p1] + # ) + + #print ("f at desired q : ", dist_func[q1_position, q2_position, :].shape) + print ("norm : ", norm_factor) + + + radius = f.copy() + theta = p2.copy() + + n = 6 # Number of sides of polygon + r_bg = 5. + + weight = polygon(n, af.from_ndarray(theta), rotation = np.pi/6).to_ndarray() + + x = (radius + r_bg)*np.cos(theta) * weight + y = (radius + r_bg)*np.sin(theta) * weight + + x_bg = r_bg*np.cos(theta)* weight + y_bg = r_bg*np.sin(theta)* weight + + # To remove the discontinuity at -pi/pi + x = np.insert(x, -1, x[0]) + y = np.insert(y, -1, y[0]) + + print ('p2 : ', p2.shape) + #pl.plot(p2, f_at_desired_q) + pl.plot(x, y, color='r', linestyle = '-', lw=3) + pl.plot(x_bg, y_bg, color='k', alpha=0.5, lw=3) + #pl.contourf(p1_meshgrid, p2_meshgrid, f_at_desired_q, 100, cmap='bwr') + + #np.savetxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2), f_at_desired_q) + #f = np.loadtxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2)) + + + #pl.contourf(p_x, p_y, f_at_desired_q, 100, cmap='bwr') + #pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.xlabel('$p_x$') + pl.ylabel('$p_y$') + + pl.xlim([-6.3, 6.3]) + pl.ylim([-6.3, 6.3]) + + pl.gca().set_aspect('equal') + pl.savefig('images/dist_func_at_a_point_%d_%d.png'%(index_1, index_2)) + pl.clf() + diff --git a/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/movie.py b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/movie.py new file mode 100644 index 00000000..b227ac0e --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/movie.py @@ -0,0 +1,147 @@ +#import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import os +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +#import yt +#yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain +#import boundary_conditions +#import params +#import initialize + + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 12, 7.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 + +p1 = domain.p1_start[0] + (0.5 + np.arange(N_p1)) * (domain.p1_end[0] - \ + domain.p1_start[0])/N_p1 +p2 = domain.p2_start[0] + (0.5 + np.arange(N_p2)) * (domain.p2_end[0] - \ + domain.p2_start[0])/N_p2 + + +filepath = os.getcwd() +moment_files = np.sort(glob.glob(filepath+'/dump_moments/*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/dump_lagrange_multipliers/*.bin')) + +print ("moment files : ", moment_files.size) +print ("lagrange multiplier files : ", lagrange_multiplier_files.size) + + +time_array = np.loadtxt("dump_time_array.txt") + +io = PetscBinaryIO.PetscBinaryIO() + +for file_number, dump_file in enumerate(moment_files[:]): + + file_number = -1 + print("file number = ", file_number, "of ", moment_files.size) + + moments = io.readBinaryFile(moment_files[file_number]) + moments = moments[0].reshape(N_q2, N_q1, 3) + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + + lagrange_multipliers = \ + io.readBinaryFile(lagrange_multiplier_files[file_number]) + lagrange_multipliers = lagrange_multipliers[0].reshape(N_q2, N_q1, 5) + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + + #print (j_x.shape, vel_drift_x.shape, density.shape) + +# pl.subplot(121) + pl.contourf(q1_meshgrid, q2_meshgrid, density.T, 100, cmap='bwr') + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.streamplot(q1, q2, + vel_drift_x, vel_drift_y, + density=2, color='k', + linewidth=0.7, arrowsize=1 + ) + + pl.xlim([q1[0], q1[-1]]) + pl.ylim([q2[0], q2[-1]]) + + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + pl.ylabel(r'$y\;(\mu \mathrm{m})$') + #pl.colorbar() + +# pl.subplot(122) +# pl.contourf(q1_meshgrid, q2_meshgrid, density.T, 100, cmap='bwr') +# pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") +# pl.streamplot(q1, q2, +# j_x, j_y, +# density=2, color='k', +# linewidth=0.7, arrowsize=1 +# ) +# +# pl.xlim([q1[0], q1[-1]]) +# pl.ylim([q2[0], q2[-1]]) +# +# pl.gca().set_aspect('equal') +# pl.xlabel(r'$x\;(\mu \mathrm{m})$') +# #pl.ylabel(r'$y\;(\mu \mathrm{m})$') + #pl.colorbar() + + #pl.tight_layout() + pl.suptitle('$\\tau_\mathrm{mc} = \infty$, $\\tau_\mathrm{mr} = \infty$') + pl.savefig('images/dump_' + '%06d'%file_number + '.png') + pl.clf() + diff --git a/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/movie_overplot.py b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/movie_overplot.py new file mode 100644 index 00000000..0504d6e8 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/movie_overplot.py @@ -0,0 +1,160 @@ +#import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import os +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +#import yt +#yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain +#import boundary_conditions +#import params +#import initialize + + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 12, 7.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 + +p1 = domain.p1_start[0] + (0.5 + np.arange(N_p1)) * (domain.p1_end[0] - \ + domain.p1_start[0])/N_p1 +p2 = domain.p2_start[0] + (0.5 + np.arange(N_p2)) * (domain.p2_end[0] - \ + domain.p2_start[0])/N_p2 + + +filepath = os.getcwd() +moment_files = np.sort(glob.glob(filepath+'/dump_moments/*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/dump_lagrange_multipliers/*.bin')) + +print ("moment files : ", moment_files.size) +print ("lagrange multiplier files : ", lagrange_multiplier_files.size) + + +filepath = os.getcwd() + '/../L_1.0_5.25_tau_ee_inf_tau_eph_inf_DC_rotated_fermi' +moment_files_2 = np.sort(glob.glob(filepath+'/dump_moments/*.bin')) +lagrange_multiplier_files_2 = \ + np.sort(glob.glob(filepath+'/dump_lagrange_multipliers/*.bin')) + +time_array = np.loadtxt("dump_time_array.txt") + +io = PetscBinaryIO.PetscBinaryIO() + +for file_number, dump_file in enumerate(moment_files[:]): + + #file_number = -1 + print("file number = ", file_number, "of ", moment_files.size) + + moments = io.readBinaryFile(moment_files[file_number]) + moments = moments[0].reshape(N_q2, N_q1, 3) + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + + lagrange_multipliers = \ + io.readBinaryFile(lagrange_multiplier_files[file_number]) + lagrange_multipliers = lagrange_multipliers[0].reshape(N_q2, N_q1, 5) + + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + + moments = io.readBinaryFile(moment_files_2[file_number]) + moments = moments[0].reshape(N_q1, N_q2, 3) + + density_2 = moments[:, :, 0].T + j_x_2 = moments[:, :, 1].T + j_y_2 = moments[:, :, 2].T + + lagrange_multipliers = \ + io.readBinaryFile(lagrange_multiplier_files_2[file_number]) + lagrange_multipliers = lagrange_multipliers[0].reshape(N_q1, N_q2, 5) + + vel_drift_x_2 = lagrange_multipliers[:, :, 3].T + vel_drift_y_2 = lagrange_multipliers[:, :, 4].T + + + pl.subplot(211) + pl.contourf(q1_meshgrid, q2_meshgrid, density.T, 100, cmap='bwr') + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.streamplot(q1, q2, + vel_drift_x, vel_drift_y, + density=2, color='k', + linewidth=0.7, arrowsize=1 + ) + + pl.xlim([q1[0], q1[-1]]) + pl.ylim([q2[0], q2[-1]]) + + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + pl.ylabel(r'$y\;(\mu \mathrm{m})$') + + pl.subplot(212) + pl.contourf(q1_meshgrid, q2_meshgrid, density_2.T, 100, cmap='bwr') + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.streamplot(q1, q2, + vel_drift_x_2, vel_drift_y_2, + density=2, color='k', + linewidth=0.7, arrowsize=1 + ) + + pl.xlim([q1[0], q1[-1]]) + pl.ylim([q2[0], q2[-1]]) + + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + pl.ylabel(r'$y\;(\mu \mathrm{m})$') + + #pl.tight_layout() + pl.suptitle('$\\tau_\mathrm{mc} = \infty$, $\\tau_\mathrm{mr} = \infty$') + pl.savefig('images/dump_' + '%06d'%file_number + '.png') + pl.clf() + diff --git a/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/params.py b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/params.py new file mode 100644 index 00000000..e656b1ee --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/params.py @@ -0,0 +1,279 @@ +import numpy as np +import arrayfire as af + +from bolt.src.electronic_boltzmann.utils.polygon import polygon +from bolt.src.electronic_boltzmann.utils.unit_vectors import normal_to_hexagon_unit_vec + +instantaneous_collisions = False #TODO : Remove from lib +hybrid_model_enabled = False #TODO : Remove from lib +source_enabled = True +disable_collision_op = False + +fields_enabled = False +# Can be defined as 'electrostatic', 'user-defined'. +# The initial conditions need to be specified under initialize +# Ensure that the initial conditions specified satisfy +# Maxwell's constraint equations +fields_initialize = 'user-defined' + +# Can be defined as 'electrostatic' and 'fdtd' +# To turn feedback from Electric fields on, set fields_solver = 'LCA' +# and set charge_electron +fields_type = 'electrostatic' +fields_solver = 'SNES' + +# Can be defined as 'strang' and 'lie' +time_splitting = 'strang' + +# Method in q-space +solver_method_in_q = 'FVM' +solver_method_in_p = 'FVM' + +reconstruction_method_in_q = 'minmod' +reconstruction_method_in_p = 'minmod' + +riemann_solver_in_q = 'upwind-flux' +riemann_solver_in_p = 'upwind-flux' + +electrostatic_solver_every_nth_step = 1000000 + + +# Time parameters: +dt = 0.025/4 # ps +t_final = 100. # ps + + +# File-writing Parameters: +dump_steps = 5 +dump_dist_after = 1600 +# Set to zero for no file-writing +dt_dump_f = 10000*dt #ps +# ALWAYS set dump moments and dump fields at same frequency: +dt_dump_moments = dt_dump_fields = 5*dt #ps + + +# Dimensionality considered in velocity space: +p_dim = 1 +p_space_grid = 'polar2D' # Supports 'cartesian' or 'polar2D' grids +# Set p-space start and end points accordingly in domain.py +#TODO : Use only polar2D for PdCoO2 + + +zero_temperature = (p_dim==1) +dispersion = 'quadratic' # 'linear' or 'quadratic' +fermi_surface_shape = 'hexagon' # Supports 'circle' or 'hexagon' + + +# Number of devices(GPUs/Accelerators) on each node: +num_devices = 6 + +# Constants: +mass_particle = 0.910938356 # x 1e-30 kg +h_bar = 1.0545718e-4 # x aJ ps +boltzmann_constant = 1 +charge = [0.*-0.160217662] # x aC +mass = [0.] #TODO : Not used in electronic_boltzmann + # Remove from lib +speed_of_light = 300. # x [um/ps] +fermi_velocity = speed_of_light/300 +epsilon0 = 8.854187817 # x [aC^2 / (aJ um) ] + +epsilon_relative = 3.9 # SiO2 +backgate_potential = -10 # V +global_chem_potential = 0.03 +contact_start = 0.0 # um +contact_end = 0.25 # um +contact_geometry = "straight" # Contacts on either side of the device + # For contacts on the same side, use + # contact_geometry = "turn_around" + +initial_temperature = 12e-4 +initial_mu = 0.015 +vel_drift_x_in = 1e-4*fermi_velocity +vel_drift_x_out = 1e-4*fermi_velocity +AC_freq = 1./100 # ps^-1 + +B3_mean = 1. # T + +# Spatial quantities (will be initialized to shape = [q1, q2] in initalize.py) +mu = None # chemical potential used in the e-ph operator +T = None # Electron temperature used in the e-ph operator +mu_ee = None # chemical potential used in the e-e operator +T_ee = None # Electron temperature used in the e-e operator +vel_drift_x = None +vel_drift_y = None +phi = None # Electric potential in the plane of graphene sheet +p_x = None +p_y = None +#integral_measure = None + +# Momentum quantities (will be initialized to shape = [p1*p2*p3] in initialize.py) +E_band = None +vel_band = None + +collision_operator_nonlinear_iters = 2 + +# Variation of collisional-timescale parameter through phase space: +@af.broadcast +def tau_defect(q1, q2, p1, p2, p3): + return(np.inf * q1**0 * p1**0) + +@af.broadcast +def tau_ee(q1, q2, p1, p2, p3): + return(np.inf * q1**0 * p1**0) + +def tau(q1, q2, p1, p2, p3): + return(tau_defect(q1, q2, p1, p2, p3)) + + +def fermi_momentum_magnitude(theta): + if (fermi_surface_shape == 'circle'): + p_f = initial_mu/fermi_velocity # Fermi momentum + + elif (fermi_surface_shape == 'hexagon'): + n = 6 # No. of sides of polygon + p_f = (initial_mu/fermi_velocity) * polygon(n, theta, rotation = np.pi/6) + # Note : Rotation by pi/6 results in a hexagon with horizontal top & bottom edges + #TODO : If cartesian coordinates are being used, convert to polar to calculate p_f + else : + raise NotImplementedError('Unsupported shape of fermi surface') + return(p_f) + + +def band_energy(p1, p2): + # Note :This function is only meant to be called once to initialize E_band + + if (p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (p_space_grid == 'polar2D'): + # In polar2D coordinates, p1 = radius and p2 = theta + r = p1 + theta = p2 + p_x = r * af.cos(theta) + p_y = r * af.sin(theta) + else : + raise NotImplementedError('Unsupported coordinate system in p_space') + + p = af.sqrt(p_x**2. + p_y**2.) + if (dispersion == 'linear'): + + E_upper = p*fermi_velocity + + elif (dispersion == 'quadratic'): + + m = effective_mass(p1, p2) + E_upper = p**2/(2.*m) + + if (zero_temperature): + + E_upper = initial_mu * p**0. + + af.eval(E_upper) + return(E_upper) + + +def effective_mass(p1, p2): + + if (p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + + theta = af.atan(p_y/p_x) + + elif (p_space_grid == 'polar2D'): + # In polar2D coordinates, p1 = radius and p2 = theta + r = p1; theta = p2 + else : + raise NotImplementedError('Unsupported coordinate system in p_space') + + if (fermi_surface_shape == 'hexagon'): + + n = 6 # No. of side of polygon + mass = mass_particle * polygon(n, theta, rotation = np.pi/6) + # Note : Rotation by pi/6 results in a hexagon with horizontal top & bottom edges + + elif (fermi_surface_shape == 'circle'): + + # For now, just return the free electron mass + mass = mass_particle + + return(mass) + +def band_velocity(p1, p2): + # Note :This function is only meant to be called once to initialize the vel vectors + + if (p_space_grid == 'cartesian'): + p_x_local = p1 + p_y_local = p2 + + theta = af.atan(p_y_local/p_x_local) + + elif (p_space_grid == 'polar2D'): + # In polar2D coordinates, p1 = radius and p2 = theta + r = p1; theta = p2 + else : + raise NotImplementedError('Unsupported coordinate system in p_space') + + p = af.sqrt(p_x**2. + p_y**2.) + p_hat = [p_x / (p + 1e-20), p_y / (p + 1e-20)] + + if (fermi_surface_shape == 'circle'): + + v_f_hat = p_hat + + elif (fermi_surface_shape == 'hexagon'): + + v_f_hat = normal_to_hexagon_unit_vec(theta) + + # Quadratic dispersion + m = effective_mass(p1, p2) + v_f = p/m + + if (dispersion == 'linear' or zero_temperature): + + v_f = fermi_velocity + + upper_band_velocity = [v_f * v_f_hat[0], v_f * v_f_hat[1]] + + return(upper_band_velocity) + +def get_p_x_and_p_y(p1, p2): + + if (p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (p_space_grid == 'polar2D'): + # In polar2D coordinates, p1 = radius and p2 = theta + r = p1; theta = p2 + + if (zero_temperature): + # Get p_x and p_y at the Fermi surface + r = fermi_momentum_magnitude(theta) + + p_x = r * af.cos(theta) + p_y = r * af.sin(theta) + + else : + raise NotImplementedError('Unsupported coordinate system in p_space') + + return([p_x, p_y]) + +# Restart(Set to zero for no-restart): +latest_restart = True +t_restart = 0 + +@af.broadcast +def fermi_dirac(mu, E_band): + + k = boltzmann_constant + T = initial_temperature + + f = (1./(af.exp( (E_band - mu + )/(k*T) + ) + 1. + ) + ) + + af.eval(f) + return(f) diff --git a/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/petsc_conf.py b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/petsc_conf.py new file mode 100755 index 00000000..22781ed2 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/petsc_conf.py @@ -0,0 +1,73 @@ +import warnings + +def get_conf(): + """Parses various PETSc configuration/include files to get data types. + + precision, indices, complexscalars = get_conf() + + Output: + precision: 'single', 'double', 'longlong' indicates precision of PetscScalar + indices: '32', '64' indicates bit-size of PetscInt + complex: True/False indicates whether PetscScalar is complex or not. + """ + + import sys, os + precision = None + indices = None + complexscalars = None + + if 'PETSC_DIR' in os.environ: + petscdir = os.environ['PETSC_DIR'] + else: + warnings.warn('PETSC_DIR env not set - unable to locate PETSc installation, using defaults') + return None, None, None + + if os.path.isfile(os.path.join(petscdir,'lib','petsc','conf','petscrules')): + # found prefix install + petscvariables = os.path.join(petscdir,'lib','petsc','conf','petscvariables') + petscconfinclude = os.path.join(petscdir,'include','petscconf.h') + else: + if 'PETSC_ARCH' in os.environ: + petscarch = os.environ['PETSC_ARCH'] + if os.path.isfile(os.path.join(petscdir,petscarch,'lib','petsc','conf','petscrules')): + # found legacy install + petscvariables = os.path.join(petscdir,petscarch,'lib','petsc','conf','petscvariables') + petscconfinclude = os.path.join(petscdir,petscarch,'include','petscconf.h') + else: + warnings.warn('Unable to locate PETSc installation in specified PETSC_DIR/PETSC_ARCH, using defaults') + return None, None, None + else: + warnings.warn('PETSC_ARCH env not set or incorrect PETSC_DIR is given - unable to locate PETSc installation, using defaults') + return None, None, None + + try: + fid = open(petscvariables, 'r') + except IOError: + warnings.warn('Nonexistent or invalid PETSc installation, using defaults') + return None, None, None + else: + for line in fid: + if line.startswith('PETSC_PRECISION'): + precision = line.strip().split('=')[1].strip('\n').strip() + + fid.close() + + try: + fid = open(petscconfinclude, 'r') + except IOError: + warnings.warn('Nonexistent or invalid PETSc installation, using defaults') + return None, None, None + else: + for line in fid: + if line.startswith('#define PETSC_USE_64BIT_INDICES 1'): + indices = '64bit' + elif line.startswith('#define PETSC_USE_COMPLEX 1'): + complexscalars = True + + if indices is None: + indices = '32bit' + if complexscalars is None: + complexscalars = False + fid.close() + + return precision, indices, complexscalars diff --git a/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/phase_vs_y.py b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/phase_vs_y.py new file mode 100644 index 00000000..fc6ac364 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/phase_vs_y.py @@ -0,0 +1,180 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +from scipy.optimize import curve_fit +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 12, 7.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +def sin_curve_fit(t, A, tau): + return A*np.sin(2*np.pi*AC_freq*(t + tau )) + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +# Left needs to be near source, right sensor near drain +sensor_1_left_start = 5.5 # um +sensor_1_left_end = 10.0 # um + +sensor_1_right_start = 5.5 # um +sensor_1_right_end = 10.0 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +filepath = \ + '/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_2.5_tau_ee_inf_tau_eph_2.5/dumps' + +AC_freq = 1./100.0 +time_period = 1/AC_freq +t_final = params.t_final +transient_time = t_final/2. + +time = np.loadtxt(filepath + "/../dump_time_array.txt") +edge_density = np.loadtxt(filepath + "/../edge_density.txt") +q2 = np.loadtxt(filepath + "/../q2_edge.txt") + +N_spatial = edge_density.shape[1] + +transient_index = int((transient_time/t_final)*time.size) + +drive = np.sin(2*np.pi*AC_freq*time) +nsamples = drive.size +dt_corr = np.linspace(-time[-1] + time[0],\ + time[-1] - time[0], 2*nsamples-1) + +# Discarding transients +q = q2.size/2 +time_half = time[transient_index:] +drive_half = drive[transient_index:] + +# Plotting signals at edge +norm_0 = np.max(edge_density[transient_index:, 0]) +norm_1 = np.max(edge_density[transient_index:, -1]) + +pl.plot(time, drive, color='black', linestyle='--') +pl.ylim([-1.1, 1.1]) +pl.xlim([0,200]) +pl.xlabel('$\mathrm{Time\;(s)}$') + +for i in range(N_spatial): + norm_i = np.max(edge_density[transient_index:, i]) + pl.plot(time, edge_density[:, i]/norm_i) + +pl.savefig('images/signals.png') +pl.clf() + +phase_shift_corr_array = [] +phase_shift_fitting_array = []\ + +for i in range(N_spatial): + print ('index : ', i) + signal_1 = edge_density[:, i] + norm_1 = np.max(signal_1[transient_index:]) + signal_1_normalized = signal_1/norm_1 + + # Calculate phase_shifts using scipy.correlate + corr = correlate(drive, signal_1_normalized) + time_shift_corr = dt_corr[corr.argmax()] + phase_shift_corr = 2*np.pi*(((0.5 + time_shift_corr/time_period) % 1.0) - 0.5) + + # Calculate phase_shifts using scipy.curve_fit + popt, pcov = curve_fit(sin_curve_fit, time[transient_index:],\ + signal_1_normalized[transient_index:]) + time_shift_fitting = popt[1]%(time_period/2.0) + phase_shift_fitting = 2*np.pi*(((0.5 + time_shift_fitting/time_period) % 1.0) - 0.5) + + phase_shift_corr_array.append(phase_shift_corr) + phase_shift_fitting_array.append(phase_shift_fitting) + +phase_shift_corr_array = np.array(phase_shift_corr_array) +phase_shift_fitting_array = np.array(phase_shift_fitting_array) + +# Plot +pl.ylabel('$\mathrm{\phi}$') +pl.xlabel('$\mathrm{y\ \mu m}$') + +pl.plot(q2, phase_shift_corr_array, '-o', label='$\mathrm{corr}$') +pl.plot(q2, phase_shift_fitting_array, '-o', label='$\mathrm{fit}$') + +pl.title('$\mathrm{2.5 \\times 10,\ \\tau_{ee} = \infty,\ \\tau_{eph} = 2.5}$') +pl.legend(loc='best') + +#pl.axvspan(sensor_1_left_start, sensor_1_left_end, color = 'k', alpha = 0.1) +#pl.axvspan(sensor_2_left_start, sensor_2_left_end, color = 'k', alpha = 0.1) + +pl.savefig('images/phase_vs_y.png') +pl.clf() + diff --git a/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/post.py b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/post.py new file mode 100644 index 00000000..a297c6f0 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/post.py @@ -0,0 +1,422 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +#pl.rcParams['figure.figsize'] = 8, 7.5 +pl.rcParams['figure.figsize'] = 8, 8 +#pl.rcParams['figure.figsize'] = 17, 9.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +#pl.rcParams['lines.linewidth'] = 3 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 +#N_q1 = 120 +#N_q2 = 240 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +#source_start = 3.5; source_end = 4.5 +#drain_start = 5.5; drain_end = 6.5 + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +sensor_1_left_start = 8.5 # um +sensor_1_left_end = 9.5 # um + +sensor_1_right_start = 8.5 # um +sensor_1_right_end = 9.5 # um + +# Left needs to be near source, right sensor near drain +#sensor_1_left_start = 1.5 # um +#sensor_1_left_end = 2.5 # um + +#sensor_1_right_start = 7.5 # um +#sensor_1_right_end = 8.5 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +sensor_2_left_start = 6.5 # um +sensor_2_left_end = 7.5 # um + +sensor_2_right_start = 6.5 # um +sensor_2_right_end = 7.5 # um + +sensor_2_left_indices = (q2 > sensor_2_left_start ) & (q2 < sensor_2_left_end) +sensor_2_right_indices = (q2 > sensor_2_right_start) & (q2 < sensor_2_right_end) + +#dump_index = 0 +#h5f = h5py.File('dumps/moments_' + '%06d'%(dump_index) + '.h5', 'r') +#moments = np.swapaxes(h5f['moments'][:], 0, 1) +#h5f.close() +# +#density = moments[:, :, 0] +#j_x = moments[:, :, 1] +#j_y = moments[:, :, 2] +#pl.contourf(q1, q2, density, 100) +##pl.title('Time = ' + "%.2f"%(t0)) +#pl.axes().set_aspect('equal') +#pl.xlabel(r'$x$') +#pl.ylabel(r'$y$') +#pl.colorbar() +#pl.savefig('images/density' + '.png') +#pl.clf() +# +#h5f = h5py.File('dumps/lagrange_multipliers_' + '%06d'%(dump_index) + '.h5', 'r') +#lagrange_multipliers = np.swapaxes(h5f['lagrange_multipliers'][:], 0, 1) +#h5f.close() +# +#print("lagrange_multipliers.shape = ", lagrange_multipliers.shape) +#mu = lagrange_multipliers[:, :, 0] +#mu_ee = lagrange_multipliers[:, :, 1] +#T_ee = lagrange_multipliers[:, :, 2] +#vel_drift_x = lagrange_multipliers[:, :, 3] +#vel_drift_y = lagrange_multipliers[:, :, 4] +#j_x_prime = density*vel_drift_x +#print("err = ", np.mean(np.abs(j_x_prime - j_x))) + +#filepath = \ +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/geom_1/DC/tau_D_50_tau_ee_0.2' +#dump_file= np.sort(glob.glob(filepath+'/moment*.h5'))[-1] +# +#h5f = h5py.File(dump_file, 'r') +#moments = np.swapaxes(h5f['moments'][:], 0, 1) +#h5f.close() +# +#density = moments[:, :, 0] +#np.savetxt('paper_plots/density_tau_D_50_tau_ee_0.2.txt', density) +#np.savetxt('paper_plots/q2_DC_tau_D_50_tau_ee_0.2.txt', q2) +##pl.plot(q2[q2>source_end], density[0, q2>source_end]-np.mean(density)) +# +#filepath = \ +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/geom_1/DC/tau_D_5_tau_ee_0.2' +#dump_file= np.sort(glob.glob(filepath+'/moment*.h5'))[-1] +# +# +#h5f = h5py.File(dump_file, 'r') +#moments = np.swapaxes(h5f['moments'][:], 0, 1) +#h5f.close() +# +#density = moments[:, :, 0] +#np.savetxt('paper_plots/density_tau_D_5_tau_ee_0.2.txt', density) +#np.savetxt('paper_plots/q2_DC_tau_D_5_tau_ee_0.2.txt', q2) +# +#filepath = \ +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/geom_1/DC/tau_D_10_tau_ee_0.2' +#dump_file= np.sort(glob.glob(filepath+'/moment*.h5'))[-1] +# +#N_q1 = 120 +#N_q2 = 240 +# +#q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +#q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 +# +#h5f = h5py.File(dump_file, 'r') +#moments = np.swapaxes(h5f['moments'][:], 0, 1) +#h5f.close() +# +#density = moments[:, :, 0] +#np.savetxt('paper_plots/density_tau_D_10_tau_ee_0.2.txt', density) +#np.savetxt('paper_plots/q2_DC_tau_D_10_tau_ee_0.2.txt', q2) + + +#pl.plot(q2[q2>source_end], density[0, q2>source_end]-np.mean(density)) +#pl.axhline(0, color='black', linestyle='--') +#pl.legend(['$\\tau_{ee}=0.2$ ps, $\\tau_{e-ph}=50$ ps', +# '$\\tau_{ee}=0.2$ ps, $\\tau_{e-ph}=10$ ps'], loc='lower right') +#pl.xlabel(r'$x\;(\mu \mathrm{m})$') +#pl.ylabel(r'$R\; (\mathrm{a.u.})$') +#pl.xlim(xmin=(source_end+0.1)) +#pl.savefig('paper_plots/DC.png') + +filepath = \ +'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/dumps_tau_D_1_tau_ee_0.2_movie' +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/geom_1/55_GHz/tau_D_5_tau_ee_0.2' +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/dumps_AC_10_Ghz_tau_D_10_tau_ee_1_geom_2/' +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/dumps_tau_D_2_tau_ee_1_AC/' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +sensor_1_signal_array = [] +print("Reading sensor signal...") +for file_number, dump_file in enumerate(moment_files): + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + density = moments[:, :, 0] + + source = np.mean(density[0, source_indices]) + drain = np.mean(density[-1, drain_indices]) + + sensor_1_left = np.mean(density[0, sensor_1_left_indices] ) + sensor_1_right = np.mean(density[-1, sensor_1_right_indices]) + + sensor_1_signal = sensor_1_left - sensor_1_right + + sensor_1_signal_array.append(sensor_1_signal) + +time_array = np.loadtxt("dump_time_array.txt") +AC_freq = 1./100 +input_signal_array = np.sin(2.*np.pi*AC_freq*time_array) +sensor_1_signal_array = np.array(sensor_1_signal_array) +half_time = (int)(time_array.size/2) +sensor_normalized = \ + sensor_1_signal_array/np.max(np.abs(sensor_1_signal_array[half_time:])) + +pl.rcParams['figure.figsize'] = 10, 8 +for file_number, dump_file in yt.parallel_objects(enumerate(moment_files)): + + print("file number = ", file_number, "of ", moment_files.size) + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + gs = gridspec.GridSpec(3, 2) + pl.subplot(gs[:, 0]) + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + pl.contourf(q1_meshgrid, q2_meshgrid, density, 100, cmap='bwr') + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + #pl.colorbar() + + h5f = h5py.File(lagrange_multiplier_files[file_number], 'r') + lagrange_multipliers = h5f['lagrange_multipliers'][:] + h5f.close() + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + +# pl.streamplot(q1[(int)(N_q1/2):], q2, +# vel_drift_x[:, (int)(N_q1/2):], vel_drift_y[:, (int)(N_q1/2):], +# density=2, color='blue', +# linewidth=0.7, arrowsize=1 +# ) + pl.streamplot(q1, q2, + vel_drift_x, vel_drift_y, + density=2, color='blue', + linewidth=0.7, arrowsize=1 + ) +# pl.streamplot(q1, q2, +# vel_drift_x, vel_drift_y, +# density=3, color='blue', +# linewidth=0.8, arrowsize=1.1 +# ) + pl.xlim([domain.q1_start, domain.q1_end]) + pl.ylim([domain.q2_start, domain.q2_end]) + #pl.ylim([0, 5]) + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + pl.ylabel(r'$y\;(\mu \mathrm{m})$') + + pl.gca().annotate("+", xy=(-0.07, .9), xycoords=("axes fraction"), + ha="center", va="center", size=30, + bbox=dict(fc="white")) + pl.gca().annotate("-", xy=(1.05, .9), xycoords=("axes fraction"), + ha="center", va="center", size=30, + bbox=dict(fc="white", pad=6.5)) + + + pl.subplot(gs[1, 1]) + + pl.plot(time_array, input_signal_array) + pl.plot(time_array, sensor_normalized) + pl.axhline(0, color='black', linestyle='--') + pl.axvline(time_array[file_number], color='black', alpha=0.75) + pl.legend(['Source $I(t)$', 'Measured $V(t)$'], loc=(0.04, 1.125)) + pl.xlabel(r'Time (ps)') + pl.xlim([100, 200]) + pl.ylim([-1.1, 1.1]) + + + pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 1$ ps') + #pl.tight_layout() + pl.savefig('images/dump_' + '%06d'%file_number + '.png') + #pl.savefig('paper_plots/DC.png') + pl.clf() + + +#time_array = [] +#input_signal_array = [] +#sensor_1_signal_array = [] +#sensor_2_signal_array = [] +#for file_number, dump_file in enumerate(moment_files): +# +# print("file number = ", file_number, "of ", moment_files.size) +# +# h5f = h5py.File(dump_file, 'r') +# moments = np.swapaxes(h5f['moments'][:], 0, 1) +# h5f.close() +# +# density = moments[:, :, 0] +# +# source = np.mean(density[0, source_indices]) +# drain = np.mean(density[-1, drain_indices]) +# +# sensor_1_left = np.mean(density[0, sensor_1_left_indices] ) +# sensor_1_right = np.mean(density[-1, sensor_1_right_indices]) +# #sensor_1_right = np.mean(density[0, sensor_1_right_indices]) +# +# sensor_2_left = np.mean(density[0, sensor_2_left_indices] ) +# sensor_2_right = np.mean(density[-1, sensor_2_right_indices]) +# +# #sensor_1_left = density[0, q2>source_end] +# #sensor_1_right = density[-1, q2>source_end] +# +# input_signal = source - drain +# sensor_1_signal = sensor_1_left - sensor_1_right +# sensor_2_signal = sensor_2_left - sensor_2_right +# +# time_array.append(file_number*dt*dump_interval) +# input_signal_array.append(input_signal) +# sensor_1_signal_array.append(sensor_1_signal) +# sensor_2_signal_array.append(sensor_2_signal) +# +##pl.rcParams['figure.figsize'] = 12, 8 +## +#AC_freq = 5.5/100 +#time_array = np.array(time_array) +#input_signal_array = np.sin(2.*np.pi*AC_freq*time_array) +#sensor_1_signal_array = np.array(sensor_1_signal_array) +###np.savetxt('drive.txt', input_signal_array) +##np.savetxt('paper_plots/sensor_tau_ee_0.2_tau_D_5.txt', sensor_1_signal_array) +##np.savetxt('time.txt', time_array) +## +##print("sensor.shape = ", sensor_1_signal_array.shape) +##sensor_2_signal_array = np.array(sensor_2_signal_array) +## +#half_time = (int)(time_array.size/2) +#pl.plot(time_array, input_signal_array/np.max(input_signal_array[half_time:])) +#pl.plot(time_array, +# sensor_1_signal_array/np.max(sensor_1_signal_array[half_time:]) +# ) +##pl.plot(time_array, +## sensor_2_signal_array/np.max(sensor_2_signal_array[half_time:]) +## ) +#pl.xlabel(r"Time (ps)") +#pl.ylim([-1.1, 1.1]) +#pl.legend(['Input', 'Sensor 1', 'Sensor 2']) +#pl.savefig('paper_plots/IV_55_Ghz_tau_ee_0.2_tau_D_5.png') +##half_time = 0 +#input_normalized = input_signal_array[half_time:]/np.max(input_signal_array[half_time:]) +#sensor_normalized = sensor_1_signal_array[half_time:]/np.max(sensor_1_signal_array[half_time:]) +# +## Calculate the phase diff. Copied from: +## https://stackoverflow.com/questions/6157791/find-phase-difference-between-two-inharmonic-waves +#corr = correlate(input_normalized, sensor_normalized) +#nsamples = input_normalized.size +#time_corr = time_array[half_time:] +#dt_corr = np.linspace(-time_corr[-1] + time_corr[0], +# time_corr[-1] - time_corr[0], 2*nsamples-1) +#time_shift = dt_corr[corr.argmax()] +# +## force the phase shift to be in [-pi:pi] +#period = 1./AC_freq +#phase_diff = 2*np.pi*(((0.5 + time_shift/period) % 1.0) - 0.5) +#print("density.shape = ", density.shape) +#print("Phase diff = ", phase_diff) + +#phase_vs_x = [] +#for i in range(sensor_1_signal_array[0, :].size): +# signal = sensor_1_signal_array[:, i] +# corr = correlate(input_signal_array, signal) +# nsamples = input_signal_array.size +# half_time = 0 +# time_corr = time_array[half_time:] +# dt_corr = np.linspace(-time_corr[-1] + time_corr[0], +# time_corr[-1] - time_corr[0], +# 2*nsamples-1 +# ) +# time_shift = dt_corr[corr.argmax()] +# +# # force the phase shift to be in [-pi:pi] +# period = 1./params.AC_freq +# phase_diff = 2*np.pi*(((0.5 + time_shift/period) % 1.0) - 0.5) +# phase_vs_x.append(phase_diff) +# +#phase_vs_x = np.array(phase_vs_x) +#print("phase_vs_x.shape = ", phase_vs_x.shape) +#np.savetxt("paper_plots/phase_vs_x_tau_ee_0.2_tau_D_1.txt", phase_vs_x) +#np.savetxt("paper_plots/q2_tau_ee_0.2_tau_D_1.txt", q2) +#print("density.shape = ", density.shape) + + diff --git a/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/signals.py b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/signals.py new file mode 100644 index 00000000..7f7ba1e7 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/signals.py @@ -0,0 +1,123 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import os +import sys +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +from matplotlib.collections import LineCollection +from matplotlib import transforms, colors +matplotlib.use('agg') +import pylab as pl +#import yt +#yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain +#import boundary_conditions +import params +#import initialize +#import coords + + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 12, 7.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +io = PetscBinaryIO.PetscBinaryIO() + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 + +p1 = domain.p1_start[0] + (0.5 + np.arange(N_p1)) * (domain.p1_end[0] - \ + domain.p1_start[0])/N_p1 +p2 = domain.p2_start[0] + (0.5 + np.arange(N_p2)) * (domain.p2_end[0] - \ + domain.p2_start[0])/N_p2 + +print ('Momentum space : ', p1[-1], p2[int(N_p2/2)]) + +filepath = os.getcwd() +moment_files = np.sort(glob.glob(filepath+'/dump_moments/*.bin')) + +print ("moment files : ", moment_files.size) + +time_step = params.dt +dump_step = params.dt_dump_moments + +#time_array = np.loadtxt(filepath+"/dump_time_array.txt") +time_array = dump_step * np.arange(0, moment_files.size, 1) + +q1_index = 0; q2_index = (q2 < .25) + +sensor_1_array = [] +for file_number, dump_file in enumerate(moment_files[:]): + + #file_number = -1 + print("file number = ", file_number, "of ", moment_files.size) + + moments = io.readBinaryFile(moment_files[file_number]) + moments = moments[0].reshape(N_q2, N_q1, 3) + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + + signal = np.mean(density[q2_index, q1_index]) + + sensor_1_array.append(signal) + +sensor_1_array = np.array(sensor_1_array) + +time_indices = time_array > 300 + +pl.plot(time_array[time_indices], sensor_1_array[time_indices] - np.mean(sensor_1_array[time_indices])) +pl.ylim([1e-8, -1e-8]) + +#pl.gca().set_aspect('equal') +pl.ylabel(r'$n$') +pl.xlabel(r'Time (ps)') +pl.suptitle('$\\tau_\mathrm{mc} = \infty$, $\\tau_\mathrm{mr} = \infty$ ps') +pl.savefig('images/iv.png') +pl.clf() + diff --git a/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/time_series.py b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/time_series.py new file mode 100644 index 00000000..f004d47c --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/time_series.py @@ -0,0 +1,140 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import os +import sys +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +from matplotlib.collections import LineCollection +from matplotlib import transforms, colors +matplotlib.use('agg') +import pylab as pl +#import yt +#yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain +#import boundary_conditions +import params +#import initialize +#import coords + + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 12, 7.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +io = PetscBinaryIO.PetscBinaryIO() + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 + +p1 = domain.p1_start[0] + (0.5 + np.arange(N_p1)) * (domain.p1_end[0] - \ + domain.p1_start[0])/N_p1 +p2 = domain.p2_start[0] + (0.5 + np.arange(N_p2)) * (domain.p2_end[0] - \ + domain.p2_start[0])/N_p2 + +print ('Momentum space : ', p1[-1], p2[int(N_p2/2)]) + +heights = np.arange(0.25, 0.351, 0.025) +heights_1 = np.arange(0.375, 0.4751, 0.025) +heights_2 = np.arange(0.500, 0.601, 0.025) +heights_3 = np.arange(0.650, 1.801, 0.025) +heights_4 = np.arange(1.800, 2.850, 0.05) +heights_5 = np.arange(3.000, 3.5001, 0.25) +heights = np.append(heights, heights_1) +heights = np.append(heights, heights_2) +heights = np.append(heights, heights_3) +heights = np.append(heights, heights_4) +heights = np.append(heights, heights_5) + +for index in heights: + filepath = \ + '/home/mchandra/gitansh/bolt_master/example_problems/electronic_boltzmann/pdcoo2/L_1.0_%.3f_tau_ee_inf_tau_eph_inf_DC_rotated'%index + + moment_files = np.sort(glob.glob(filepath+'/dump_moments/*.bin')) + + #print ("moment files : ", moment_files.size) + + q1_end = index + + N_q2 = domain.N_q2 + N_q1 = int(N_q2*q1_end/domain.q2_end) + + q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (q1_end - domain.q1_start)/N_q1 + q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + + q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + + dump_step = params.dt_dump_moments + + #time_array = np.loadtxt(filepath+"/dump_time_array.txt") + time_array = dump_step * np.arange(0, moment_files.size, 1) + + print("Index : ", index, ", moment files : ", moment_files.size) + + q1_index = 0; q2_index = (q2 < .25) + + #sensor_1_array = [] + #for file_number, dump_file in enumerate(moment_files[:]): + + # #file_number = -1 + # print("file number = ", file_number, "of ", moment_files.size) + + # moments = io.readBinaryFile(moment_files[file_number]) + # moments = moments[0].reshape(N_q2, N_q1, 3) + + # density = moments[:, :, 0] + # j_x = moments[:, :, 1] + # j_y = moments[:, :, 2] + + # signal = np.mean(density[q2_index, q1_index]) + + # sensor_1_array.append(signal) + + #sensor_1_array = np.array(sensor_1_array) + + #time_indices = time_array > 300 + + #pl.plot(time_array[time_indices], sensor_1_array[time_indices] - np.mean(sensor_1_array[time_indices])) + #pl.ylim([1e-8, -1e-8]) + + #pl.gca().set_aspect('equal') + #pl.ylabel(r'$n$') + #pl.xlabel(r'Time (ps)') + #pl.suptitle('$\\tau_\mathrm{mc} = \infty$, $\\tau_\mathrm{mr} = \infty$ ps') + #pl.savefig('images/iv.png') + #pl.clf() + diff --git a/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/vorticity.py b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/vorticity.py new file mode 100644 index 00000000..2f494c60 --- /dev/null +++ b/example_problems/electronic_boltzmann/pdcoo2/ref_rotated/vorticity.py @@ -0,0 +1,136 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +filepath = \ +'/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_1.0_tau_ee_0.2_tau_eph_0.5/dumps' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +time_array = np.loadtxt("dump_time_array.txt") +half_time = (int)(time_array.size/2) + +for file_number, dump_file in yt.parallel_objects(enumerate(moment_files)): + + print("file number = ", file_number, "of ", moment_files.size) + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + + h5f = h5py.File(lagrange_multiplier_files[file_number], 'r') + lagrange_multipliers = h5f['lagrange_multipliers'][:] + h5f.close() + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + + + dq1 = (domain.q1_end - domain.q1_start)/domain.N_q1 + dq2 = (domain.q2_end - domain.q2_start)/domain.N_q2 + + dvx_dx, dvx_dy = np.gradient(j_x/density, dq1, dq2) + dvy_dx, dvy_dy = np.gradient(j_y/density, dq1, dq2) + + vorticity = dvy_dx - dvx_dy + + pl.contourf(q1_meshgrid, q2_meshgrid, vorticity, 100, cmap='bwr') + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + + pl.streamplot(q1, q2, + vel_drift_x, vel_drift_y, + density=2, color='blue', + linewidth=0.7, arrowsize=1 + ) + + pl.xlim([domain.q1_start, domain.q1_end]) + pl.ylim([domain.q2_start, domain.q2_end]) + + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + pl.ylabel(r'$y\;(\mu \mathrm{m})$') + pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 1.0$ ps') + pl.savefig('vorticity_images/dump_' + '%06d'%file_number + '.png') + pl.clf() + diff --git a/example_problems/electronic_boltzmann/test_compute_moments/PetscBinaryIO.py b/example_problems/electronic_boltzmann/test_compute_moments/PetscBinaryIO.py new file mode 100755 index 00000000..fd0e48e9 --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments/PetscBinaryIO.py @@ -0,0 +1,479 @@ +"""PetscBinaryIO +=============== + +Provides + 1. PETSc-named objects Vec, Mat, and IS that inherit numpy.ndarray + 2. A class to read and write these objects from PETSc binary files. + +The standard usage of this module should look like: + + >>> import PetscBinaryIO + >>> io = PetscBinaryIO.PetscBinaryIO() + >>> objects = io.readBinaryFile('file.dat') + +or + + >>> import PetscBinaryIO + >>> import numpy + >>> vec = numpy.array([1., 2., 3.]).view(PetscBinaryIO.Vec) + >>> io = PetscBinaryIO.PetscBinaryIO() + >>> io.writeBinaryFile('file.dat', [vec,]) + +to read in objects one at a time use such as + + >>> import PetscBinaryIO + >>> io = PetscBinaryIO.PetscBinaryIO() + >>> fh = open('file.dat') + >>> objecttype = io.readObjectType(fh) + >>> if objecttype == 'Vec': + >>> v = io.readVec(fh) + + Note that one must read in the object type first and then call readVec(), readMat() etc. + + +See also PetscBinaryIO.__doc__ and methods therein. +""" + +import numpy as np +import functools + +try: + basestring # Python-2 has basestring as a common parent of unicode and str +except NameError: + basestring = str # Python-3 is unicode through and through + +def update_wrapper_with_doc(wrapper, wrapped): + """Similar to functools.update_wrapper, but also gets the wrapper's __doc__ string""" + wdoc = wrapper.__doc__ + + functools.update_wrapper(wrapper, wrapped) + if wdoc is not None: + if wrapper.__doc__ is None: + wrapper.__doc__ = wdoc + else: + wrapper.__doc__ = wrapper.__doc__ + wdoc + return wrapper + +def wraps_with_doc(wrapped): + """Similar to functools.wraps, but also gets the wrapper's __doc__ string""" + return functools.partial(update_wrapper_with_doc, wrapped=wrapped) + +def decorate_with_conf(f): + """Decorates methods to take kwargs for precisions.""" + @wraps_with_doc(f) + def decorated_f(self, *args, **kwargs): + """ + Additional kwargs: + precision: 'single', 'double', 'longlong' for scalars + indices: '32bit', '64bit' integer size + complexscalars: True/False + + Note these are set in order of preference: + 1. kwargs if given here + 2. PetscBinaryIO class __init__ arguments + 3. PETSC_DIR/PETSC_ARCH defaults + """ + + changed = False + old_precision = self.precision + old_indices = self.indices + old_complexscalars = self.complexscalars + + try: + self.precision = kwargs.pop('precision') + except KeyError: + pass + else: + changed = True + + try: + self.indices = kwargs.pop('indices') + except KeyError: + pass + else: + changed = True + + try: + self.complexscalars = kwargs.pop('complexscalars') + except KeyError: + pass + else: + changed = True + + if changed: + self._update_dtypes() + + result = f(self, *args, **kwargs) + + if changed: + self.precision = old_precision + self.indices = old_indices + self.complexscalars = old_complexscalars + self._update_dtypes() + + return result + return decorated_f + + +class DoneWithFile(Exception): pass + + +class Vec(np.ndarray): + """Vec represented as 1D numpy array + + The best way to instantiate this class for use with writeBinaryFile() + is through the numpy view method: + + vec = numpy.array([1,2,3]).view(Vec) + """ + _classid = 1211214 + + +class MatDense(np.matrix): + """Mat represented as 2D numpy array + + The best way to instantiate this class for use with writeBinaryFile() + is through the numpy view method: + + mat = numpy.array([[1,0],[0,1]]).view(Mat) + """ + _classid = 1211216 + + +class MatSparse(tuple): + """Mat represented as CSR tuple ((M, N), (rowindices, col, val)) + + This should be instantiated from a tuple: + + mat = MatSparse( ((M,N), (rowindices,col,val)) ) + """ + _classid = 1211216 + def __repr__(self): + return 'MatSparse: %s'%super(MatSparse, self).__repr__() + + +class IS(np.ndarray): + """IS represented as 1D numpy array + + The best way to instantiate this class for use with writeBinaryFile() + is through the numpy "view" method: + + an_is = numpy.array([3,4,5]).view(IS) + """ + _classid = 1211218 + + +class PetscBinaryIO(object): + """Reader/Writer class for PETSc binary files. + + Note that by default, precisions for both scalars and indices, as well as + complex scalars, are picked up from the PETSC_DIR/PETSC_ARCH configuration + as set by environmental variables. + + Alternatively, defaults can be overridden at class instantiation, or for + a given method call. + """ + + _classid = {1211216:'Mat', + 1211214:'Vec', + 1211218:'IS', + 1211219:'Bag'} + + def __init__(self, precision=None, indices=None, complexscalars=None): + if (precision is None) or (indices is None) or (complexscalars is None): + import petsc_conf + defaultprecision, defaultindices, defaultcomplexscalars = petsc_conf.get_conf() + if precision is None: + if defaultprecision is None: + precision = 'double' + else: + precision = defaultprecision + + if indices is None: + if defaultindices is None: + indices = '32bit' + else: + indices = defaultindices + + if complexscalars is None: + if defaultcomplexscalars is None: + complexscalars = False + else: + complexscalars = defaultcomplexscalars + + self.precision = precision + self.indices = indices + self.complexscalars = complexscalars + self._update_dtypes() + + def _update_dtypes(self): + if self.indices == '64bit': + self._inttype = np.dtype('>i8') + else: + self._inttype = np.dtype('>i4') + + if self.precision == 'longlong': + nbyte = 16 + elif self.precision == 'single': + nbyte = 4 + else: + nbyte = 8 + + if self.complexscalars: + name = 'c' + nbyte = nbyte * 2 # complex scalar takes twice as many bytes + else: + name = 'f' + + self._scalartype = '>{0}{1}'.format(name, nbyte) + + @decorate_with_conf + def readVec(self, fh): + """Reads a PETSc Vec from a binary file handle, must be called after readObjectType().""" + + nz = np.fromfile(fh, dtype=self._inttype, count=1)[0] + try: + vals = np.fromfile(fh, dtype=self._scalartype, count=nz) + except MemoryError: + raise IOError('Inconsistent or invalid Vec data in file') + if (len(vals) is 0): + raise IOError('Inconsistent or invalid Vec data in file') + return vals.view(Vec) + + @decorate_with_conf + def writeVec(self, fh, vec): + """Writes a PETSc Vec to a binary file handle.""" + + metadata = np.array([Vec._classid, len(vec)], dtype=self._inttype) + metadata.tofile(fh) + vec.astype(self._scalartype).tofile(fh) + return + + @decorate_with_conf + def readMatSparse(self, fh): + """Reads a PETSc Mat, returning a sparse representation of the data. Must be called after readObjectType() + + (M,N), (I,J,V) = readMatSparse(fid) + + Input: + fid : file handle to open binary file. + Output: + M,N : matrix size + I,J : arrays of row and column for each nonzero + V: nonzero value + """ + + try: + M,N,nz = np.fromfile(fh, dtype=self._inttype, count=3) + I = np.empty(M+1, dtype=self._inttype) + I[0] = 0 + rownz = np.fromfile(fh, dtype=self._inttype, count=M) + np.cumsum(rownz, out=I[1:]) + assert I[-1] == nz + + J = np.fromfile(fh, dtype=self._inttype, count=nz) + assert len(J) == nz + V = np.fromfile(fh, dtype=self._scalartype, count=nz) + assert len(V) == nz + except (AssertionError, MemoryError, IndexError): + raise IOError('Inconsistent or invalid Mat data in file') + + return MatSparse(((M, N), (I, J, V))) + + @decorate_with_conf + def writeMatSparse(self, fh, mat): + """Writes a Mat into a PETSc binary file handle""" + + ((M,N), (I,J,V)) = mat + metadata = np.array([MatSparse._classid,M,N,I[-1]], dtype=self._inttype) + rownz = I[1:] - I[:-1] + + assert len(J.shape) == len(V.shape) == len(I.shape) == 1 + assert len(J) == len(V) == I[-1] == rownz.sum() + assert (rownz > -1).all() + + metadata.tofile(fh) + rownz.astype(self._inttype).tofile(fh) + J.astype(self._inttype).tofile(fh) + V.astype(self._scalartype).tofile(fh) + return + + @decorate_with_conf + def readMatDense(self, fh): + """Reads a PETSc Mat, returning a dense represention of the data, must be called after readObjectType()""" + + try: + M,N,nz = np.fromfile(fh, dtype=self._inttype, count=3) + I = np.empty(M+1, dtype=self._inttype) + I[0] = 0 + rownz = np.fromfile(fh, dtype=self._inttype, count=M) + np.cumsum(rownz, out=I[1:]) + assert I[-1] == nz + + J = np.fromfile(fh, dtype=self._inttype, count=nz) + assert len(J) == nz + V = np.fromfile(fh, dtype=self._scalartype, count=nz) + assert len(V) == nz + + except (AssertionError, MemoryError, IndexError): + raise IOError('Inconsistent or invalid Mat data in file') + + mat = np.zeros((M,N), dtype=self._scalartype) + for row in range(M): + rstart, rend = I[row:row+2] + mat[row, J[rstart:rend]] = V[rstart:rend] + return mat.view(MatDense) + + @decorate_with_conf + def readMatSciPy(self, fh): + from scipy.sparse import csr_matrix + (M, N), (I, J, V) = self.readMatSparse(fh) + return csr_matrix((V, J, I), shape=(M, N)) + + @decorate_with_conf + def writeMatSciPy(self, fh, mat): + from scipy.sparse import csr_matrix + if hasattr(mat, 'tocsr'): + mat = mat.tocsr() + assert isinstance(mat, csr_matrix) + V = mat.data + M,N = mat.shape + J = mat.indices + I = mat.indptr + return self.writeMatSparse(fh, (mat.shape, (mat.indptr,mat.indices,mat.data))) + + @decorate_with_conf + def readMat(self, fh, mattype='sparse'): + """Reads a PETSc Mat from binary file handle, must be called after readObjectType() + + optional mattype: 'sparse" or 'dense' + + See also: readMatSparse, readMatDense + """ + + if mattype == 'sparse': + return self.readMatSparse(fh) + elif mattype == 'dense': + return self.readMatDense(fh) + elif mattype == 'scipy.sparse': + return self.readMatSciPy(fh) + else: + raise RuntimeError('Invalid matrix type requested: choose sparse/dense/scipy.sparse') + + @decorate_with_conf + def readIS(self, fh): + """Reads a PETSc Index Set from binary file handle, must be called after readObjectType()""" + + try: + nz = np.fromfile(fh, dtype=self._inttype, count=1)[0] + v = np.fromfile(fh, dtype=self._inttype, count=nz) + assert len(v) == nz + except (MemoryError,IndexError): + raise IOError('Inconsistent or invalid IS data in file') + return v.view(IS) + + @decorate_with_conf + def writeIS(self, fh, anis): + """Writes a PETSc IS to binary file handle.""" + + metadata = np.array([IS._classid, len(anis)], dtype=self._inttype) + metadata.tofile(fh) + anis.astype(self._inttype).tofile(fh) + return + + @decorate_with_conf + def readObjectType(self, fid): + """Returns the next object type as a string in the file""" + try: + header = np.fromfile(fid, dtype=self._inttype, count=1)[0] + except (MemoryError, IndexError): + raise DoneWithFile + try: + objecttype = self._classid[header] + except KeyError: + raise IOError('Invalid PetscObject CLASSID or object not implemented for python') + return objecttype + + @decorate_with_conf + def readBinaryFile(self, fid, mattype='sparse'): + """Reads a PETSc binary file, returning a tuple of the contained objects. + + objects = self.readBinaryFile(fid, **kwargs) + + Input: + fid : either file name or handle to an open binary file. + + Output: + objects : tuple of objects representing the data in numpy arrays. + + Optional: + mattype : + 'sparse': Return matrices as raw CSR: (M, N), (row, col, val). + 'dense': Return matrices as MxN numpy arrays. + 'scipy.sparse': Return matrices as scipy.sparse objects. + """ + + close = False + + if isinstance(fid, basestring): + fid = open(fid, 'rb') + close = True + + objects = [] + try: + while True: + objecttype = self.readObjectType(fid) + + if objecttype == 'Vec': + objects.append(self.readVec(fid)) + elif objecttype == 'IS': + objects.append(self.readIS(fid)) + elif objecttype == 'Mat': + objects.append(self.readMat(fid,mattype)) + elif objecttype == 'Bag': + raise NotImplementedError('Bag Reader not yet implemented') + except DoneWithFile: + pass + finally: + if close: + fid.close() + + return tuple(objects) + + @decorate_with_conf + def writeBinaryFile(self, fid, objects): + """Writes a PETSc binary file containing the objects given. + + readBinaryFile(fid, objects) + + Input: + fid : either file handle to an open binary file, or filename. + objects : list of objects representing the data in numpy arrays, + which must be of type Vec, IS, MatSparse, or MatSciPy. + """ + close = False + if isinstance(fid, basestring): + fid = open(fid, 'wb') + close = True + + for petscobj in objects: + if (isinstance(petscobj, Vec)): + self.writeVec(fid, petscobj) + elif (isinstance(petscobj, IS)): + self.writeIS(fid, petscobj) + elif (isinstance(petscobj, MatSparse)): + self.writeMatSparse(fid, petscobj) + elif (isinstance(petscobj, MatDense)): + if close: + fid.close() + raise NotImplementedError('Writing a dense matrix is not yet supported') + else: + try: + self.writeMatSciPy(fid, petscobj) + except AssertionError: + if close: + fid.close() + raise TypeError('Object %s is not a valid PETSc object'%(petscobj.__repr__())) + if close: + fid.close() + return diff --git a/example_problems/electronic_boltzmann/test_compute_moments/boundary_conditions.py b/example_problems/electronic_boltzmann/test_compute_moments/boundary_conditions.py new file mode 100644 index 00000000..762f5e79 --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments/boundary_conditions.py @@ -0,0 +1,107 @@ +import numpy as np +import arrayfire as af +import domain + +in_q1_left = 'mirror+dirichlet' +in_q1_right = 'mirror+dirichlet' +in_q2_bottom = 'mirror' +in_q2_top = 'mirror' + +@af.broadcast +def f_left(f, t, q1, q2, p1, p2, p3, params): + + k = params.boltzmann_constant + E_upper = params.E_band + T = params.initial_temperature + mu = params.initial_mu + + t = params.current_time + omega = 2. * np.pi * params.AC_freq + vel_drift_x_in = params.vel_drift_x_in + + if (params.p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (params.p_space_grid == 'polar2D'): + p_x = p1 * af.cos(p2) + p_y = p1 * af.sin(p2) + else: + raise NotImplementedError('Unsupported coordinate system in p_space') + + + fermi_dirac_in = (1./(af.exp( (E_upper - vel_drift_x_in*p_x - mu)/(k*T) ) + 1.) + ) + + if (params.contact_geometry=="straight"): + # Contacts on either side of the device + + q2_contact_start = params.contact_start + q2_contact_end = params.contact_end + + cond = ((q2 >= q2_contact_start) & \ + (q2 <= q2_contact_end) \ + ) + + f_left = cond*fermi_dirac_in + (1 - cond)*f + + elif (params.contact_geometry=="turn_around"): + # Contacts on the same side of the device + + vel_drift_x_out = -params.vel_drift_x_in * np.sin(omega*t) + + fermi_dirac_out = (1./(af.exp( (E_upper - vel_drift_x_out*p_x - mu)/(k*T) ) + 1.) + ) + + # TODO: set these parameters in params.py + cond_in = ((q2 >= 3.5) & (q2 <= 4.5)) + cond_out = ((q2 >= 5.5) & (q2 <= 6.5)) + + f_left = cond_in*fermi_dirac_in + cond_out*fermi_dirac_out \ + + (1 - cond_in)*(1 - cond_out)*f + + af.eval(f_left) + return(f_left) + +@af.broadcast +def f_right(f, t, q1, q2, p1, p2, p3, params): + + k = params.boltzmann_constant + E_upper = params.E_band + T = params.initial_temperature + mu = params.initial_mu + + t = params.current_time + omega = 2. * np.pi * params.AC_freq + vel_drift_x_out = params.vel_drift_x_out + + if (params.p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (params.p_space_grid == 'polar2D'): + p_x = p1 * af.cos(p2) + p_y = p1 * af.sin(p2) + else: + raise NotImplementedError('Unsupported coordinate system in p_space') + + fermi_dirac_out = (1./(af.exp( (E_upper - vel_drift_x_out*p_x - mu)/(k*T) ) + 1.) + ) + + if (params.contact_geometry=="straight"): + # Contacts on either side of the device + + q2_contact_start = params.contact_start + q2_contact_end = params.contact_end + + cond = ((q2 >= q2_contact_start) & \ + (q2 <= q2_contact_end) \ + ) + + f_right = cond*fermi_dirac_out + (1 - cond)*f + + elif (params.contact_geometry=="turn_around"): + # Contacts on the same side of the device + + f_right = f + + af.eval(f_right) + return(f_right) diff --git a/example_problems/electronic_boltzmann/test_compute_moments/check.py b/example_problems/electronic_boltzmann/test_compute_moments/check.py new file mode 100644 index 00000000..71fe46ef --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments/check.py @@ -0,0 +1,42 @@ +import numpy as np +import params +import arrayfire as af +import pylab as pl + +import domain + +from bolt.src.electronic_boltzmann.utils.polygon import polygon + +p2_start = -np.pi +p2_end = np.pi +N_p2 = domain.N_p2 +theta = \ + p2_start + (0.5 + np.arange(N_p2))*(p2_end - p2_start)/N_p2 + +theta = af.from_ndarray(theta) + +hexa = polygon(6, theta, rotation = np.pi/6) +hexa = hexa.to_ndarray() + +#pl.polar(theta, hexa) + +#pl.plot(theta, hexa * np.cos(theta)) +#pl.plot(theta, hexa * np.sin(theta)) + +pl.gca().set_aspect(1) +pl.plot(hexa*np.cos(theta), hexa*np.sin(theta)) + +#p_hat_0_old = np.loadtxt("P_hat_0_old.txt") +#p_hat_1_old = np.loadtxt("P_hat_1_old.txt") + +#p_hat_0 = np.loadtxt("P_hat_0.txt") +#p_hat_1 = np.loadtxt("P_hat_1.txt") + +#pl.plot(theta, p_hat_0_old) +#pl.plot(theta, p_hat_1_old) + +#pl.plot(theta, p_hat_0, '--') +#pl.plot(theta, p_hat_1, '--') + + +pl.savefig("images/test.png") diff --git a/example_problems/electronic_boltzmann/test_compute_moments/domain.py b/example_problems/electronic_boltzmann/test_compute_moments/domain.py new file mode 100644 index 00000000..96ac75e4 --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments/domain.py @@ -0,0 +1,67 @@ +import numpy as np +import params + +q1_start = 0. +q1_end = 1.0 +N_q1 = 20 + +q2_start = 0. +q2_end = 1.25 +N_q2 = 25 + +# If N_p1 > 1, mirror boundary conditions require p1 to be +# symmetric about zero +# TODO : Check and fix discrepancy between this and the claim +# that p1_center = mu in polar representation +N_p1 = 1 # Set equal to 1 for 1D polar + +# In the cartesian representation of momentum space, +# p1 = p_x (magnitude of momentum) +# p1_start and p1_end are set such that p1_center is 0 + +# Uncomment the following for the cartesian representation of momentum space +#p1_start = [-0.04] +#p1_end = [0.04] + + +# In the 2D polar representation of momentum space, +# p1 = p_r (magnitude of momentum) +# p1_start and p1_end are set such that p1_center is mu + +# Uncomment the following for the 2D polar representation of momentum space +#p1_start = [params.initial_mu - \ +# 16.*params.boltzmann_constant*params.initial_temperature] +#p1_end = [params.initial_mu + \ +# 16.*params.boltzmann_constant*params.initial_temperature] + +# Uncomment the following for the 1D polar representation of momentum space +p1_start = [0.5*params.initial_mu/params.fermi_velocity] +p1_end = [1.5*params.initial_mu/params.fermi_velocity] + + +# If N_p2 > 1, mirror boundary conditions require p2 to be +# symmetric about zero +N_p2 = 2048 + +# In the cartesian representation of momentum space, +# p2 = p_y (magnitude of momentum) +# p2_start and p2_end are set such that p2_center is 0 +#p2_start = [-0.04] +#p2_end = [0.04] + +# In the 2D polar representation of momentum space, +# p2 = p_theta (angle of momentum) +# N_p_theta MUST be even. +#p2_start = [-np.pi] +#p2_end = [np.pi] +p2_start = [-3.14159265359] +p2_end = [3.14159265359] + +# If N_p3 > 1, mirror boundary conditions require p3 to be +# symmetric about zero + +p3_start = [-0.5] +p3_end = [0.5] +N_p3 = 1 + +N_ghost = 2 diff --git a/example_problems/electronic_boltzmann/test_compute_moments/edge_density.py b/example_problems/electronic_boltzmann/test_compute_moments/edge_density.py new file mode 100644 index 00000000..3697590e --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments/edge_density.py @@ -0,0 +1,122 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +#import yt +#yt.enable_parallelism() +import os + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +import PetscBinaryIO + +import domain +import boundary_conditions +import params +import initialize + + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +# Left needs to be near source, right sensor near drain +sensor_1_left_start = 8.5 # um +sensor_1_left_end = 9.5 # um + +sensor_1_right_start = 8.5 # um +sensor_1_right_end = 9.5 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +io = PetscBinaryIO.PetscBinaryIO() + +filepath = os.getcwd() +moment_files = np.sort(glob.glob(filepath+'/dump_moments/*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/dump_lagrange_multipliers/*.bin')) + +dt = params.dt +dump_interval = params.dump_steps + +sensor_1_signal_array = [] +print("Reading sensor signal...") +for file_number, dump_file in enumerate(moment_files): + + moments = io.readBinaryFile(dump_file) + moments = moments[0].reshape(N_q2, N_q1, 3) + + density = moments[:, :, 0] + + source = np.mean(density[source_indices, 0]) + drain = np.mean(density[drain_indices, -1]) + + sensor_1_left = np.mean(density[0, 0]) + sensor_1_right = np.mean(density[0, -1]) + + sensor_1_signal = sensor_1_left - sensor_1_right + + sensor_1_signal_array.append(sensor_1_signal) + +time_array = np.loadtxt("dump_time_array.txt") +AC_freq = 1./100 +input_signal_array = np.sin(2.*np.pi*AC_freq*time_array) +sensor_1_signal_array = np.array(sensor_1_signal_array) +half_time = (int)(time_array.size/2) + +input_normalized = \ + input_signal_array/np.max(np.abs(input_signal_array[half_time:])) +sensor_normalized = \ + sensor_1_signal_array#/np.max(np.abs(sensor_1_signal_array[half_time:])) + diff --git a/example_problems/electronic_boltzmann/test_compute_moments/edge_potential.py b/example_problems/electronic_boltzmann/test_compute_moments/edge_potential.py new file mode 100644 index 00000000..b50b3bf5 --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments/edge_potential.py @@ -0,0 +1,161 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 12, 7.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +# Left needs to be near source, right sensor near drain +sensor_1_left_start = 5.5 # um +sensor_1_left_end = 10.0 # um + +sensor_1_right_start = 5.5 # um +sensor_1_right_end = 10.0 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +sensor_2_left_start = 6.5 # um +sensor_2_left_end = 7.5 # um + +sensor_2_right_start = 6.5 # um +sensor_2_right_end = 7.5 # um + +sensor_2_left_indices = (q2 > sensor_2_left_start ) & (q2 < sensor_2_left_end) +sensor_2_right_indices = (q2 > sensor_2_right_start) & (q2 < sensor_2_right_end) + +filepath = \ +'/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_1.0_tau_ee_0.2_tau_eph_0.5/dumps' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +sensor_1_signal_array = [] +#sensor_2_signal_array = [] +#print("Reading sensor signal...") +print("Loading data...") +density = [] +edge_density = [] +for file_number, dump_file in enumerate(moment_files): + + print("File number = ", file_number, ' of ', moment_files.size) + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + density.append(moments[:, :, 0]) + edge_density.append(density[file_number][0, sensor_1_left_indices]) + +density = np.array(density) +edge_density = np.array(edge_density) + +mean_density = np.mean(density) +max_density = np.max(density) +min_density = np.min(density) + +np.savetxt("edge_density.txt", edge_density) + +print("Dumping data...") +for file_number in yt.parallel_objects(range(density.shape[0])): + + print("File number = ", file_number, ' of ', moment_files.size) + + pl.semilogy(q2[sensor_1_left_indices], + density[file_number][0, sensor_1_left_indices], + ) + #pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.title(r'Time = ' + "%.2f"%(file_number*dt*dump_interval) + " ps") + + pl.xlim([sensor_1_left_start, sensor_1_left_end]) + #pl.ylim([min_density-mean_density, max_density-mean_density]) + #pl.ylim([0., np.log(max_density)]) + + #pl.gca().set_aspect('equal') + #pl.xlabel(r'$x\;(\mu \mathrm{m})$') + #pl.ylabel(r'$y\;(\mu \mathrm{m})$') + + #pl.suptitle('$\\tau_\mathrm{mc} = \infty$ ps, $\\tau_\mathrm{mr} = 3.0$ ps') + #pl.savefig('images/dump_' + '%06d'%file_number + '.png') + pl.savefig('images/density_' + '%06d'%file_number + '.png') + pl.clf() + + + diff --git a/example_problems/electronic_boltzmann/test_compute_moments/enstrophy.py b/example_problems/electronic_boltzmann/test_compute_moments/enstrophy.py new file mode 100644 index 00000000..aeab5a28 --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments/enstrophy.py @@ -0,0 +1,142 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +filepath = \ +'/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_1.0_tau_ee_0.2_tau_eph_0.5/dumps' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +kinetic_energy_array = [] +enstrophy_array = [] +print("Reading kinetic energy and enstrophy signals...") +for file_number, dump_file in enumerate(moment_files): + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + + h5f = h5py.File(lagrange_multiplier_files[file_number], 'r') + lagrange_multipliers = h5f['lagrange_multipliers'][:] + h5f.close() + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + + dq1 = (domain.q1_end - domain.q1_start)/domain.N_q1 + dq2 = (domain.q2_end - domain.q2_start)/domain.N_q2 + + dvx_dx, dvx_dy = np.gradient(j_x/density, dq1, dq2) + dvy_dx, dvy_dy = np.gradient(j_y/density, dq1, dq2) + + vorticity = dvy_dx - dvx_dy + + kinetic_energy = 0.5 * np.sum(vel_drift_x**2 + vel_drift_y**2) * dq1 * dq2 + kinetic_energy_array.append(kinetic_energy) + + enstrophy = np.sum(vorticity**2) * dq1 * dq2 + enstrophy_array.append(enstrophy) + +time_array = np.loadtxt("dump_time_array.txt") +half_time = (int)(time_array.size/2) + +kinetic_energy_normalized = \ + kinetic_energy_array/np.max(np.abs(kinetic_energy_array[half_time:])) +enstrophy_normalized = \ + enstrophy_array/np.max(np.abs(enstrophy_array[half_time:])) + + +pl.plot(time_array, kinetic_energy_normalized) +pl.plot(time_array, enstrophy_normalized) +pl.axhline(0, color='black', linestyle='--') + +pl.legend(['Kinetic Energy', 'Enstrophy'], loc=1) +pl.xlabel(r'Time (ps)') +pl.xlim([0, 200]) +pl.ylim([-0.1, 1.1]) + +pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 1.0$ ps') +pl.savefig('vorticity_images/iv' + '.png') +pl.clf() + + diff --git a/example_problems/electronic_boltzmann/test_compute_moments/initialize.py b/example_problems/electronic_boltzmann/test_compute_moments/initialize.py new file mode 100644 index 00000000..c0d986bf --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments/initialize.py @@ -0,0 +1,98 @@ +""" +Functions which are used in assigning the I.C's to +the system. +""" + +import arrayfire as af +import numpy as np +from petsc4py import PETSc + +import domain + +def initialize_f(q1, q2, p1, p2, p3, params): + + PETSc.Sys.Print("Initializing f") + k = params.boltzmann_constant + + params.mu = 0.*q1 + params.initial_mu + params.T = 0.*q1 + params.initial_temperature + params.vel_drift_x = 0.*params.vel_drift_x_in + 0.*q1 + params.vel_drift_y = 0.*q1 + + print (params.vel_drift_x) + params.mu_ee = params.mu.copy() + params.T_ee = params.T.copy() + + params.p_x, params.p_y = params.get_p_x_and_p_y(p1, p2) + params.E_band = params.band_energy(p1, p2) + params.vel_band = params.band_velocity(p1, p2) + + # Evaluating velocity space resolution for each species: + dp1 = []; dp2 = []; dp3 = [] + N_p1 = domain.N_p1; N_p2 = domain.N_p2; N_p3 = domain.N_p3 + p1_start = domain.p1_start; p1_end = domain.p1_end + p2_start = domain.p2_start; p2_end = domain.p2_end + p3_start = domain.p3_start; p3_end = domain.p3_end + + N_species = len(params.mass) + for i in range(N_species): + dp1.append((p1_end[i] - p1_start[i]) / N_p1) + dp2.append((p2_end[i] - p2_start[i]) / N_p2) + dp3.append((p3_end[i] - p3_start[i]) / N_p3) + + + theta = af.atan(params.p_y / params.p_x) + p_f = params.fermi_momentum_magnitude(theta) + + if (params.p_space_grid == 'cartesian'): + dp_x = dp1[0]; dp_y = dp2[0]; dp_z = dp3[0] + params.integral_measure = \ + (4./(2.*np.pi*params.h_bar)**2) * dp_z * dp_y * dp_x + + elif (params.p_space_grid == 'polar2D'): + # In polar2D coordinates, p1 = radius and p2 = theta + # Integral : \int delta(r - r_F) F(r, theta) r dr dtheta + r = p1; theta = p2 + dp_r = dp1[0]; dp_theta = dp2[0] + + if (params.zero_temperature): + # Assumption : F(r, theta) = delta(r-r_F)*F(theta) + params.integral_measure = \ + (4./(2.*np.pi*params.h_bar)**2) * p_f * dp_theta + + else: + params.integral_measure = \ + (4./(2.*np.pi*params.h_bar)**2) * r * dp_r * dp_theta + + + else : + raise NotImplementedError('Unsupported coordinate system in p_space') + + + + f = (1./(af.exp( (params.E_band - params.vel_drift_x*params.p_x + - params.vel_drift_y*params.p_y + - params.mu + )/(k*params.T) + ) + 1. + )) + + af.eval(f) + return(f) + + +def initialize_E(q1, q2, params): + + E1 = 0.*q1 + E2 = 0.*q1 + E3 = 0.*q1 + + return(E1, E2, E3) + +def initialize_B(q1, q2, params): + + B1 = 0.*q1 + B2 = 0.*q1 + B3 = 0.*q1 + + return(B1, B2, B3) diff --git a/example_problems/electronic_boltzmann/test_compute_moments/main.py b/example_problems/electronic_boltzmann/test_compute_moments/main.py new file mode 100644 index 00000000..fa5ff601 --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments/main.py @@ -0,0 +1,57 @@ +import os +import arrayfire as af +import numpy as np +import math +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +from mpi4py import MPI +MPI.WTIME_IS_GLOBAL=True + +from bolt.lib.physical_system import physical_system +from bolt.lib.nonlinear.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.utils.restart_latest import latest_output, format_time + +import domain +import boundary_conditions +import initialize +import params + +import bolt.src.electronic_boltzmann.advection_terms \ + as advection_terms +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator +import bolt.src.electronic_boltzmann.moments \ + as moments + +from bolt.lib.nonlinear.compute_moments import compute_moments +from bolt.lib.utils.calculate_q import calculate_q + + +# Defining the physical system to be solved: +system = physical_system(domain, + boundary_conditions, + params, + initialize, + advection_terms, + collision_operator.RTA, + moments + ) + +# Declaring a nonlinear system object which will evolve the defined physical system: +nls = nonlinear_solver(system) +N_g = domain.N_ghost +params.rank = nls._comm.rank + + +nls.dump_moments('dump_moments/moments') +nls.dump_aux_arrays([params.mu, + params.mu_ee, + params.T_ee, + params.vel_drift_x, params.vel_drift_y + ], + 'lagrange_multipliers', + 'dump_lagrange_multipliers/lagrange_multipliers' + ) +nls.dump_distribution_function('dump_f/f') + diff --git a/example_problems/electronic_boltzmann/test_compute_moments/momentum_space_movie.py b/example_problems/electronic_boltzmann/test_compute_moments/momentum_space_movie.py new file mode 100644 index 00000000..1de644d7 --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments/momentum_space_movie.py @@ -0,0 +1,134 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import os +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1_start = domain.q1_start +q1_end = domain.q1_end +q2_start = domain.q2_start +q2_end = domain.q2_end + +q1 = q1_start + (0.5 + np.arange(N_q1)) * (q1_end - q1_start)/N_q1 +q2 = q2_start + (0.5 + np.arange(N_q2)) * (q2_end - q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 + +p1_start = domain.p1_start +p1_end = domain.p1_end +p2_start = domain.p2_start +p2_end = domain.p2_end + +p1 = p1_start[0] + (0.5 + np.arange(N_p1)) * (p1_end[0] - p1_start[0])/N_p1 +p2 = p2_start[0] + (0.5 + np.arange(N_p2)) * (p2_end[0] - p2_start[0])/N_p2 + +p1_meshgrid, p2_meshgrid = np.meshgrid(p1, p2) + +p_x = p1_meshgrid * np.cos(p2_meshgrid) +p_y = p1_meshgrid * np.sin(p2_meshgrid) + +#p2_meshgrid, p1_meshgrid = np.meshgrid(p2, p1) + +io = PetscBinaryIO.PetscBinaryIO() + +filepath = os.getcwd() + "/dumps" +moment_files = np.sort(glob.glob(filepath+'/moment*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) +dist_func_files = np.sort(glob.glob(filepath+'/f_*.bin')) + +dist_func_bg_file = dist_func_files[0] +dist_func_file = dist_func_files[-1] + +dist_func_background = io.readBinaryFile(dist_func_bg_file) +#dist_func_background = dist_func_background[0].reshape(N_q2, N_q1, N_p2, N_p1) +dist_func_background = dist_func_background[0].reshape(N_q1, N_q2, 1, 1, N_p2, N_p1) +dist_func = io.readBinaryFile(dist_func_file) + +print (dist_func[0].shape) + +dist_func = dist_func[0].reshape(N_q1, N_q2, 1, 1, N_p2, N_p1) + + +N = 7 +for index_1 in range(N): + for index_2 in range(N): + + q1_position = int(N_q1*((index_1/N)+(1/(2*N)))) + q2_position = int(N_q2*((index_2/N)+(1/(2*N)))) + + #a = np.max((dist_func - dist_func_background)[q2_position, q1_position, :, :]) + #b = np.abs(np.min((dist_func - dist_func_background)[q2_position, q1_position, :, :])) + #norm_factor = np.maximum(a, b) + #f_at_desired_q = \ + # np.reshape((dist_func-dist_func_background)[q2_position, q1_position, :, :], + # [N_p2, N_p1])/norm_factor + + f_at_desired_q = np.reshape((dist_func - \ + dist_func_background)[q1_position, q2_position, :], + [N_p2, N_p1] + ) + pl.contourf(p1_meshgrid, p2_meshgrid, f_at_desired_q, 100, cmap='bwr') + + #np.savetxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2), f_at_desired_q) + #f = np.loadtxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2)) + + + #pl.contourf(p_x, p_y, f_at_desired_q, 100, cmap='bwr') + #pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.xlabel('$p_x$') + pl.ylabel('$p_y$') + pl.gca().set_aspect('equal') + pl.savefig('images/dist_func_at_a_point_%d_%d.png'%(index_1, index_2)) + pl.clf() + diff --git a/example_problems/electronic_boltzmann/test_compute_moments/momentum_space_movie_debug.py b/example_problems/electronic_boltzmann/test_compute_moments/momentum_space_movie_debug.py new file mode 100644 index 00000000..0b2c719d --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments/momentum_space_movie_debug.py @@ -0,0 +1,182 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import os +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +#import yt +#yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain +import params + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_s = len(params.mass) # Number of species + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1_start = domain.q1_start +q1_end = domain.q1_end +q2_start = domain.q2_start +q2_end = domain.q2_end + +q1 = q1_start + (0.5 + np.arange(N_q1)) * (q1_end - q1_start)/N_q1 +q2 = q2_start + (0.5 + np.arange(N_q2)) * (q2_end - q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 +N_p3 = domain.N_p3 + +p1_start = domain.p1_start +p1_end = domain.p1_end +p2_start = domain.p2_start +p2_end = domain.p2_end + +p1 = p1_start[0] + (0.5 + np.arange(N_p1)) * (p1_end[0] - p1_start[0])/N_p1 +p2 = p2_start[0] + (0.5 + np.arange(N_p2)) * (p2_end[0] - p2_start[0])/N_p2 + +p1_meshgrid, p2_meshgrid = np.meshgrid(p1, p2) + +p_x = p1_meshgrid * np.cos(p2_meshgrid) +p_y = p1_meshgrid * np.sin(p2_meshgrid) + +#p2_meshgrid, p1_meshgrid = np.meshgrid(p2, p1) + +io = PetscBinaryIO.PetscBinaryIO() + +filepath = os.getcwd() +moment_files = np.sort(glob.glob(filepath+'/dump_moments/*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/dump_lagrange_multipliers/*.bin')) +dist_func_files = np.sort(glob.glob(filepath+'/dump_f/*.bin')) + +#moment_files = np.sort(glob.glob(filepath+'/dumps/moments*.bin')) +#lagrange_multiplier_files = \ +# np.sort(glob.glob(filepath+'/dumps/lagrange_multipliers*.bin')) +#dist_func_files = np.sort(glob.glob(filepath+'/dumps/f*.bin')) + +dist_func_bg_file = dist_func_files[0] +dist_func_file = dist_func_files[-1] + +print(dist_func_bg_file) +print(dist_func_file) + +dist_func_background = io.readBinaryFile(dist_func_bg_file) +#dist_func_background = dist_func_background[0].reshape(N_q2, N_q1, N_p2, N_p1) +dist_func_background = dist_func_background[0].reshape(N_q2, N_q1, N_s, N_p3, N_p2, N_p1) +dist_func = io.readBinaryFile(dist_func_file) + +print (dist_func[0].shape) + +dist_func = dist_func[0].reshape(N_q2, N_q1, N_s, N_p3, N_p2, N_p1) + +time_array = np.loadtxt("dump_time_array.txt") +file_number = -1 + +N = 7 +for index_1 in range(1): + for index_2 in range(N_q2): + + q1_position = index_1 + q2_position = index_2 + + a = np.max((dist_func - dist_func_background)[q2_position, q1_position, :, :]) + b = np.abs(np.min((dist_func - dist_func_background)[q2_position, q1_position, :, :])) + norm_factor = 1.#np.maximum(a, b) + f_at_desired_q = \ + np.reshape((dist_func - \ + dist_func_background)[q2_position, q1_position, :, :],\ + [N_p2, N_p1])/norm_factor + + im = pl.plot(p2, f_at_desired_q) + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.ylabel('$f$') + pl.xlabel('$p_{\\theta}$') + #pl.tight_layout() + pl.savefig('images/dist_func_at_a_point_%d_%d.png'%(index_1, index_2)) + pl.clf() + + np.savetxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2), f_at_desired_q) + f = np.loadtxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2)) + + #f_at_desired_q = np.reshape((dist_func - \ + # dist_func_background)[q1_position, q2_position, :], + # [N_p2, N_p1] + # ) + + #print ("f at desired q : ", dist_func[q1_position, q2_position, :].shape) + print ("norm : ", norm_factor) + + + radius = f.copy() + theta = p2.copy() + + x = (radius + 5.)*np.cos(theta) + y = (radius + 5.)*np.sin(theta) + + x_bg = 5*np.cos(theta) + y_bg = 5*np.sin(theta) + + print ('p2 : ', p2.shape) + #pl.plot(p2, f_at_desired_q) + pl.plot(x, y, color='r', linestyle = '-', lw=3) + pl.plot(x_bg, y_bg, color='k', alpha=0.5, lw=3) + #pl.contourf(p1_meshgrid, p2_meshgrid, f_at_desired_q, 100, cmap='bwr') + + #np.savetxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2), f_at_desired_q) + #f = np.loadtxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2)) + + + #pl.contourf(p_x, p_y, f_at_desired_q, 100, cmap='bwr') + #pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.xlabel('$p_x$') + pl.ylabel('$p_y$') + + pl.xlim([-6.5, 6.5]) + pl.ylim([-6.5, 6.5]) + + pl.gca().set_aspect('equal') + #pl.savefig('images/dist_func_at_a_point_%d_%d.png'%(index_1, index_2)) + pl.clf() + diff --git a/example_problems/electronic_boltzmann/test_compute_moments/momentum_space_movie_zero_T.py b/example_problems/electronic_boltzmann/test_compute_moments/momentum_space_movie_zero_T.py new file mode 100644 index 00000000..0dae45a6 --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments/momentum_space_movie_zero_T.py @@ -0,0 +1,183 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import os +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +#import yt +#yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain +import params + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_s = len(params.mass) # Number of species + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1_start = domain.q1_start +q1_end = domain.q1_end +q2_start = domain.q2_start +q2_end = domain.q2_end + +q1 = q1_start + (0.5 + np.arange(N_q1)) * (q1_end - q1_start)/N_q1 +q2 = q2_start + (0.5 + np.arange(N_q2)) * (q2_end - q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 +N_p3 = domain.N_p3 + +p1_start = domain.p1_start +p1_end = domain.p1_end +p2_start = domain.p2_start +p2_end = domain.p2_end + +p1 = p1_start[0] + (0.5 + np.arange(N_p1)) * (p1_end[0] - p1_start[0])/N_p1 +p2 = p2_start[0] + (0.5 + np.arange(N_p2)) * (p2_end[0] - p2_start[0])/N_p2 + +p1_meshgrid, p2_meshgrid = np.meshgrid(p1, p2) + +p_x = p1_meshgrid * np.cos(p2_meshgrid) +p_y = p1_meshgrid * np.sin(p2_meshgrid) + +#p2_meshgrid, p1_meshgrid = np.meshgrid(p2, p1) + +io = PetscBinaryIO.PetscBinaryIO() + +filepath = os.getcwd() +moment_files = np.sort(glob.glob(filepath+'/dump_moments/*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/dump_lagrange_multipliers/*.bin')) +dist_func_files = np.sort(glob.glob(filepath+'/dump_f/*.bin')) + +#moment_files = np.sort(glob.glob(filepath+'/dumps/moments*.bin')) +#lagrange_multiplier_files = \ +# np.sort(glob.glob(filepath+'/dumps/lagrange_multipliers*.bin')) +#dist_func_files = np.sort(glob.glob(filepath+'/dumps/f*.bin')) + +dist_func_bg_file = dist_func_files[0] +dist_func_file = dist_func_files[-1] + +print(dist_func_bg_file) +print(dist_func_file) + +dist_func_background = io.readBinaryFile(dist_func_bg_file) +#dist_func_background = dist_func_background[0].reshape(N_q2, N_q1, N_p2, N_p1) +dist_func_background = dist_func_background[0].reshape(N_q2, N_q1, N_s, N_p3, N_p2, N_p1) +dist_func = io.readBinaryFile(dist_func_file) + +print (dist_func[0].shape) + +dist_func = dist_func[0].reshape(N_q2, N_q1, N_s, N_p3, N_p2, N_p1) +dist_func_background = np.mean(dist_func) + +time_array = np.loadtxt("dump_time_array.txt") +file_number = -1 + +N = 7 +for index_1 in range(N): + for index_2 in range(N): + + q1_position = int(N_q1*((index_1/N)+(1/(2*N)))) + q2_position = int(N_q2*((index_2/N)+(1/(2*N)))) + + a = np.max((dist_func - dist_func_background)[q2_position, q1_position, :, :]) + b = np.abs(np.min((dist_func - dist_func_background)[q2_position, q1_position, :, :])) + norm_factor = np.maximum(a, b) + f_at_desired_q = \ + np.reshape((dist_func-\ + dist_func_background)[q2_position, q1_position, :, :],\ + [N_p2, N_p1])/norm_factor + + im = pl.plot(p2, f_at_desired_q) + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.ylabel('$f$') + pl.xlabel('$p_{\\theta}$') + #pl.tight_layout() + #pl.savefig('images/dist_func_at_a_point_%d_%d.png'%(index_1, index_2)) + pl.clf() + + np.savetxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2), f_at_desired_q) + f = np.loadtxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2)) + + #f_at_desired_q = np.reshape((dist_func - \ + # dist_func_background)[q1_position, q2_position, :], + # [N_p2, N_p1] + # ) + + #print ("f at desired q : ", dist_func[q1_position, q2_position, :].shape) + print ("norm : ", norm_factor) + + + radius = f.copy() + theta = p2.copy() + + x = (radius + 5.)*np.cos(theta) + y = (radius + 5.)*np.sin(theta) + + x_bg = 5*np.cos(theta) + y_bg = 5*np.sin(theta) + + print ('p2 : ', p2.shape) + #pl.plot(p2, f_at_desired_q) + pl.plot(x, y, color='r', linestyle = '-', lw=3) + pl.plot(x_bg, y_bg, color='k', alpha=0.5, lw=3) + #pl.contourf(p1_meshgrid, p2_meshgrid, f_at_desired_q, 100, cmap='bwr') + + #np.savetxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2), f_at_desired_q) + #f = np.loadtxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2)) + + + #pl.contourf(p_x, p_y, f_at_desired_q, 100, cmap='bwr') + #pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.xlabel('$p_x$') + pl.ylabel('$p_y$') + + pl.xlim([-6.5, 6.5]) + pl.ylim([-6.5, 6.5]) + + pl.gca().set_aspect('equal') + pl.savefig('images/dist_func_at_a_point_%d_%d.png'%(index_1, index_2)) + pl.clf() + diff --git a/example_problems/electronic_boltzmann/test_compute_moments/movie.py b/example_problems/electronic_boltzmann/test_compute_moments/movie.py new file mode 100644 index 00000000..e335f680 --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments/movie.py @@ -0,0 +1,169 @@ +#import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import os +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +#import yt +#yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain +#import boundary_conditions +#import params +#import initialize + + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 12, 7.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 + +p1 = domain.p1_start[0] + (0.5 + np.arange(N_p1)) * (domain.p1_end[0] - \ + domain.p1_start[0])/N_p1 +p2 = domain.p2_start[0] + (0.5 + np.arange(N_p2)) * (domain.p2_end[0] - \ + domain.p2_start[0])/N_p2 + + +filepath = os.getcwd() +moment_files = np.sort(glob.glob(filepath+'/dump_moments/*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/dump_lagrange_multipliers/*.bin')) + +print ("moment files : ", moment_files.size) +print ("lagrange multiplier files : ", lagrange_multiplier_files.size) + + +time_array = np.loadtxt("dump_time_array.txt") + +io = PetscBinaryIO.PetscBinaryIO() + +for file_number, dump_file in enumerate(moment_files[::-1]): + + file_number = -1 + print("file number = ", file_number, "of ", moment_files.size) + + moments = io.readBinaryFile(moment_files[file_number]) + moments = moments[0].reshape(N_q2, N_q1, 3) + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + + lagrange_multipliers = \ + io.readBinaryFile(lagrange_multiplier_files[file_number]) + lagrange_multipliers = lagrange_multipliers[0].reshape(N_q2, N_q1, 5) + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + + #print (j_x.shape, vel_drift_x.shape, density.shape) + + pl.subplot(221) + pl.contourf(q1_meshgrid, q2_meshgrid, density.T, 100, cmap='bwr') + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.streamplot(q1, q2, + vel_drift_x, vel_drift_y, + density=2, color='k', + linewidth=0.7, arrowsize=1 + ) + + pl.xlim([q1[0], q1[-1]]) + pl.ylim([q2[0], q2[-1]]) + + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + pl.ylabel(r'$y\;(\mu \mathrm{m})$') + #pl.colorbar() + + pl.subplot(222) + pl.contourf(q1_meshgrid, q2_meshgrid, density.T, 100, cmap='bwr') + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.streamplot(q1, q2, + j_x, j_y, + density=2, color='k', + linewidth=0.7, arrowsize=1 + ) + + pl.xlim([q1[0], q1[-1]]) + pl.ylim([q2[0], q2[-1]]) + + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + #pl.ylabel(r'$y\;(\mu \mathrm{m})$') + #pl.colorbar() + + pl.subplot(223) + pl.contourf(q1_meshgrid, q2_meshgrid, (j_x - density*vel_drift_x).T, 100, cmap='bwr') + + pl.xlim([q1[0], q1[-1]]) + pl.ylim([q2[0], q2[-1]]) + + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + pl.ylabel(r'$y\;(\mu \mathrm{m})$') + pl.colorbar() + + pl.subplot(224) + pl.contourf(q1_meshgrid, q2_meshgrid, (j_y - density*vel_drift_y).T, 100, cmap='bwr') + + pl.xlim([q1[0], q1[-1]]) + pl.ylim([q2[0], q2[-1]]) + + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + #pl.ylabel(r'$y\;(\mu \mathrm{m})$') + pl.colorbar() + + #pl.tight_layout() + pl.suptitle('$\\tau_\mathrm{mc} = \infty$, $\\tau_\mathrm{mr} = \infty$') + pl.savefig('images/dump_' + '%06d'%file_number + '.png') + pl.clf() + diff --git a/example_problems/electronic_boltzmann/test_compute_moments/params.py b/example_problems/electronic_boltzmann/test_compute_moments/params.py new file mode 100644 index 00000000..fd53d7cb --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments/params.py @@ -0,0 +1,279 @@ +import numpy as np +import arrayfire as af + +from bolt.src.electronic_boltzmann.utils.polygon import polygon +from bolt.src.electronic_boltzmann.utils.unit_vectors import normal_to_hexagon_unit_vec + +instantaneous_collisions = False #TODO : Remove from lib +hybrid_model_enabled = False #TODO : Remove from lib +source_enabled = True +disable_collision_op = False + +fields_enabled = False +# Can be defined as 'electrostatic', 'user-defined'. +# The initial conditions need to be specified under initialize +# Ensure that the initial conditions specified satisfy +# Maxwell's constraint equations +fields_initialize = 'user-defined' + +# Can be defined as 'electrostatic' and 'fdtd' +# To turn feedback from Electric fields on, set fields_solver = 'LCA' +# and set charge_electron +fields_type = 'electrostatic' +fields_solver = 'SNES' + +# Can be defined as 'strang' and 'lie' +time_splitting = 'strang' + +# Method in q-space +solver_method_in_q = 'FVM' +solver_method_in_p = 'FVM' + +reconstruction_method_in_q = 'minmod' +reconstruction_method_in_p = 'minmod' + +riemann_solver_in_q = 'upwind-flux' +riemann_solver_in_p = 'upwind-flux' + +electrostatic_solver_every_nth_step = 1000000 + + +# Time parameters: +dt = 0.025/4 # ps +t_final = 25. # ps + + +# File-writing Parameters: +dump_steps = 5 +dump_dist_after = 1600 +# Set to zero for no file-writing +dt_dump_f = 1000*dt #ps +# ALWAYS set dump moments and dump fields at same frequency: +dt_dump_moments = dt_dump_fields = 5*dt #ps + + +# Dimensionality considered in velocity space: +p_dim = 1 +p_space_grid = 'polar2D' # Supports 'cartesian' or 'polar2D' grids +# Set p-space start and end points accordingly in domain.py +#TODO : Use only polar2D for PdCoO2 + + +zero_temperature = (p_dim==1) +dispersion = 'linear' # 'linear' or 'quadratic' +fermi_surface_shape = 'circle' # Supports 'circle' or 'hexagon' + + +# Number of devices(GPUs/Accelerators) on each node: +num_devices = 6 + +# Constants: +mass_particle = 0.910938356 # x 1e-30 kg +h_bar = 1.0545718e-4 # x aJ ps +boltzmann_constant = 1 +charge = [0.*-0.160217662] # x aC +mass = [0.] #TODO : Not used in electronic_boltzmann + # Remove from lib +speed_of_light = 300. # x [um/ps] +fermi_velocity = speed_of_light/300 +epsilon0 = 8.854187817 # x [aC^2 / (aJ um) ] + +epsilon_relative = 3.9 # SiO2 +backgate_potential = -10 # V +global_chem_potential = 0.03 +contact_start = 0.0 # um +contact_end = 0.25 # um +contact_geometry = "straight" # Contacts on either side of the device + # For contacts on the same side, use + # contact_geometry = "turn_around" + +initial_temperature = 12e-5 +initial_mu = 0.015 +vel_drift_x_in = 1e-4*fermi_velocity +vel_drift_x_out = 1e-4*fermi_velocity +AC_freq = 1./100 # ps^-1 + +B3_mean = 1. # T + +# Spatial quantities (will be initialized to shape = [q1, q2] in initalize.py) +mu = None # chemical potential used in the e-ph operator +T = None # Electron temperature used in the e-ph operator +mu_ee = None # chemical potential used in the e-e operator +T_ee = None # Electron temperature used in the e-e operator +vel_drift_x = None +vel_drift_y = None +phi = None # Electric potential in the plane of graphene sheet +p_x = None +p_y = None +#integral_measure = None + +# Momentum quantities (will be initialized to shape = [p1*p2*p3] in initialize.py) +E_band = None +vel_band = None + +collision_operator_nonlinear_iters = 2 + +# Variation of collisional-timescale parameter through phase space: +@af.broadcast +def tau_defect(q1, q2, p1, p2, p3): + return(np.inf * q1**0 * p1**0) + +@af.broadcast +def tau_ee(q1, q2, p1, p2, p3): + return(np.inf * q1**0 * p1**0) + +def tau(q1, q2, p1, p2, p3): + return(tau_defect(q1, q2, p1, p2, p3)) + + +def fermi_momentum_magnitude(theta): + if (fermi_surface_shape == 'circle'): + p_f = initial_mu/fermi_velocity # Fermi momentum + + elif (fermi_surface_shape == 'hexagon'): + n = 6 # No. of sides of polygon + p_f = (initial_mu/fermi_velocity) * polygon(n, theta, rotation = np.pi/6) + # Note : Rotation by pi/6 results in a hexagon with horizontal top & bottom edges + #TODO : If cartesian coordinates are being used, convert to polar to calculate p_f + else : + raise NotImplementedError('Unsupported shape of fermi surface') + return(p_f) + + +def band_energy(p1, p2): + # Note :This function is only meant to be called once to initialize E_band + + if (p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (p_space_grid == 'polar2D'): + # In polar2D coordinates, p1 = radius and p2 = theta + r = p1 + theta = p2 + p_x = r * af.cos(theta) + p_y = r * af.sin(theta) + else : + raise NotImplementedError('Unsupported coordinate system in p_space') + + p = af.sqrt(p_x**2. + p_y**2.) + if (dispersion == 'linear'): + + E_upper = p*fermi_velocity + + elif (dispersion == 'quadratic'): + + m = effective_mass(p1, p2) + E_upper = p**2/(2.*m) + + if (zero_temperature): + + E_upper = initial_mu * p**0. + + af.eval(E_upper) + return(E_upper) + + +def effective_mass(p1, p2): + + if (p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + + theta = af.atan(p_y/p_x) + + elif (p_space_grid == 'polar2D'): + # In polar2D coordinates, p1 = radius and p2 = theta + r = p1; theta = p2 + else : + raise NotImplementedError('Unsupported coordinate system in p_space') + + if (fermi_surface_shape == 'hexagon'): + + n = 6 # No. of side of polygon + mass = mass_particle * polygon(n, theta, rotation = np.pi/6) + # Note : Rotation by pi/6 results in a hexagon with horizontal top & bottom edges + + elif (fermi_surface_shape == 'circle'): + + # For now, just return the free electron mass + mass = mass_particle + + return(mass) + +def band_velocity(p1, p2): + # Note :This function is only meant to be called once to initialize the vel vectors + + if (p_space_grid == 'cartesian'): + p_x_local = p1 + p_y_local = p2 + + theta = af.atan(p_y_local/p_x_local) + + elif (p_space_grid == 'polar2D'): + # In polar2D coordinates, p1 = radius and p2 = theta + r = p1; theta = p2 + else : + raise NotImplementedError('Unsupported coordinate system in p_space') + + p = af.sqrt(p_x**2. + p_y**2.) + p_hat = [p_x / (p + 1e-20), p_y / (p + 1e-20)] + + if (fermi_surface_shape == 'circle'): + + v_f_hat = p_hat + + elif (fermi_surface_shape == 'hexagon'): + + v_f_hat = normal_to_hexagon_unit_vec(theta) + + # Quadratic dispersion + m = effective_mass(p1, p2) + v_f = p/m + + if (dispersion == 'linear' or zero_temperature): + + v_f = fermi_velocity + + upper_band_velocity = [v_f * v_f_hat[0], v_f * v_f_hat[1]] + + return(upper_band_velocity) + +def get_p_x_and_p_y(p1, p2): + + if (p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (p_space_grid == 'polar2D'): + # In polar2D coordinates, p1 = radius and p2 = theta + r = p1; theta = p2 + + if (zero_temperature): + # Get p_x and p_y at the Fermi surface + r = fermi_momentum_magnitude(theta) + + p_x = r * af.cos(theta) + p_y = r * af.sin(theta) + + else : + raise NotImplementedError('Unsupported coordinate system in p_space') + + return([p_x, p_y]) + +# Restart(Set to zero for no-restart): +latest_restart = True +t_restart = 0 + +@af.broadcast +def fermi_dirac(mu, E_band): + + k = boltzmann_constant + T = initial_temperature + + f = (1./(af.exp( (E_band - mu + )/(k*T) + ) + 1. + ) + ) + + af.eval(f) + return(f) diff --git a/example_problems/electronic_boltzmann/test_compute_moments/petsc_conf.py b/example_problems/electronic_boltzmann/test_compute_moments/petsc_conf.py new file mode 100755 index 00000000..22781ed2 --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments/petsc_conf.py @@ -0,0 +1,73 @@ +import warnings + +def get_conf(): + """Parses various PETSc configuration/include files to get data types. + + precision, indices, complexscalars = get_conf() + + Output: + precision: 'single', 'double', 'longlong' indicates precision of PetscScalar + indices: '32', '64' indicates bit-size of PetscInt + complex: True/False indicates whether PetscScalar is complex or not. + """ + + import sys, os + precision = None + indices = None + complexscalars = None + + if 'PETSC_DIR' in os.environ: + petscdir = os.environ['PETSC_DIR'] + else: + warnings.warn('PETSC_DIR env not set - unable to locate PETSc installation, using defaults') + return None, None, None + + if os.path.isfile(os.path.join(petscdir,'lib','petsc','conf','petscrules')): + # found prefix install + petscvariables = os.path.join(petscdir,'lib','petsc','conf','petscvariables') + petscconfinclude = os.path.join(petscdir,'include','petscconf.h') + else: + if 'PETSC_ARCH' in os.environ: + petscarch = os.environ['PETSC_ARCH'] + if os.path.isfile(os.path.join(petscdir,petscarch,'lib','petsc','conf','petscrules')): + # found legacy install + petscvariables = os.path.join(petscdir,petscarch,'lib','petsc','conf','petscvariables') + petscconfinclude = os.path.join(petscdir,petscarch,'include','petscconf.h') + else: + warnings.warn('Unable to locate PETSc installation in specified PETSC_DIR/PETSC_ARCH, using defaults') + return None, None, None + else: + warnings.warn('PETSC_ARCH env not set or incorrect PETSC_DIR is given - unable to locate PETSc installation, using defaults') + return None, None, None + + try: + fid = open(petscvariables, 'r') + except IOError: + warnings.warn('Nonexistent or invalid PETSc installation, using defaults') + return None, None, None + else: + for line in fid: + if line.startswith('PETSC_PRECISION'): + precision = line.strip().split('=')[1].strip('\n').strip() + + fid.close() + + try: + fid = open(petscconfinclude, 'r') + except IOError: + warnings.warn('Nonexistent or invalid PETSc installation, using defaults') + return None, None, None + else: + for line in fid: + if line.startswith('#define PETSC_USE_64BIT_INDICES 1'): + indices = '64bit' + elif line.startswith('#define PETSC_USE_COMPLEX 1'): + complexscalars = True + + if indices is None: + indices = '32bit' + if complexscalars is None: + complexscalars = False + fid.close() + + return precision, indices, complexscalars diff --git a/example_problems/electronic_boltzmann/test_compute_moments/phase_vs_y.py b/example_problems/electronic_boltzmann/test_compute_moments/phase_vs_y.py new file mode 100644 index 00000000..fc6ac364 --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments/phase_vs_y.py @@ -0,0 +1,180 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +from scipy.optimize import curve_fit +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 12, 7.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +def sin_curve_fit(t, A, tau): + return A*np.sin(2*np.pi*AC_freq*(t + tau )) + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +# Left needs to be near source, right sensor near drain +sensor_1_left_start = 5.5 # um +sensor_1_left_end = 10.0 # um + +sensor_1_right_start = 5.5 # um +sensor_1_right_end = 10.0 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +filepath = \ + '/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_2.5_tau_ee_inf_tau_eph_2.5/dumps' + +AC_freq = 1./100.0 +time_period = 1/AC_freq +t_final = params.t_final +transient_time = t_final/2. + +time = np.loadtxt(filepath + "/../dump_time_array.txt") +edge_density = np.loadtxt(filepath + "/../edge_density.txt") +q2 = np.loadtxt(filepath + "/../q2_edge.txt") + +N_spatial = edge_density.shape[1] + +transient_index = int((transient_time/t_final)*time.size) + +drive = np.sin(2*np.pi*AC_freq*time) +nsamples = drive.size +dt_corr = np.linspace(-time[-1] + time[0],\ + time[-1] - time[0], 2*nsamples-1) + +# Discarding transients +q = q2.size/2 +time_half = time[transient_index:] +drive_half = drive[transient_index:] + +# Plotting signals at edge +norm_0 = np.max(edge_density[transient_index:, 0]) +norm_1 = np.max(edge_density[transient_index:, -1]) + +pl.plot(time, drive, color='black', linestyle='--') +pl.ylim([-1.1, 1.1]) +pl.xlim([0,200]) +pl.xlabel('$\mathrm{Time\;(s)}$') + +for i in range(N_spatial): + norm_i = np.max(edge_density[transient_index:, i]) + pl.plot(time, edge_density[:, i]/norm_i) + +pl.savefig('images/signals.png') +pl.clf() + +phase_shift_corr_array = [] +phase_shift_fitting_array = []\ + +for i in range(N_spatial): + print ('index : ', i) + signal_1 = edge_density[:, i] + norm_1 = np.max(signal_1[transient_index:]) + signal_1_normalized = signal_1/norm_1 + + # Calculate phase_shifts using scipy.correlate + corr = correlate(drive, signal_1_normalized) + time_shift_corr = dt_corr[corr.argmax()] + phase_shift_corr = 2*np.pi*(((0.5 + time_shift_corr/time_period) % 1.0) - 0.5) + + # Calculate phase_shifts using scipy.curve_fit + popt, pcov = curve_fit(sin_curve_fit, time[transient_index:],\ + signal_1_normalized[transient_index:]) + time_shift_fitting = popt[1]%(time_period/2.0) + phase_shift_fitting = 2*np.pi*(((0.5 + time_shift_fitting/time_period) % 1.0) - 0.5) + + phase_shift_corr_array.append(phase_shift_corr) + phase_shift_fitting_array.append(phase_shift_fitting) + +phase_shift_corr_array = np.array(phase_shift_corr_array) +phase_shift_fitting_array = np.array(phase_shift_fitting_array) + +# Plot +pl.ylabel('$\mathrm{\phi}$') +pl.xlabel('$\mathrm{y\ \mu m}$') + +pl.plot(q2, phase_shift_corr_array, '-o', label='$\mathrm{corr}$') +pl.plot(q2, phase_shift_fitting_array, '-o', label='$\mathrm{fit}$') + +pl.title('$\mathrm{2.5 \\times 10,\ \\tau_{ee} = \infty,\ \\tau_{eph} = 2.5}$') +pl.legend(loc='best') + +#pl.axvspan(sensor_1_left_start, sensor_1_left_end, color = 'k', alpha = 0.1) +#pl.axvspan(sensor_2_left_start, sensor_2_left_end, color = 'k', alpha = 0.1) + +pl.savefig('images/phase_vs_y.png') +pl.clf() + diff --git a/example_problems/electronic_boltzmann/test_compute_moments/post.py b/example_problems/electronic_boltzmann/test_compute_moments/post.py new file mode 100644 index 00000000..a297c6f0 --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments/post.py @@ -0,0 +1,422 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +#pl.rcParams['figure.figsize'] = 8, 7.5 +pl.rcParams['figure.figsize'] = 8, 8 +#pl.rcParams['figure.figsize'] = 17, 9.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +#pl.rcParams['lines.linewidth'] = 3 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 +#N_q1 = 120 +#N_q2 = 240 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +#source_start = 3.5; source_end = 4.5 +#drain_start = 5.5; drain_end = 6.5 + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +sensor_1_left_start = 8.5 # um +sensor_1_left_end = 9.5 # um + +sensor_1_right_start = 8.5 # um +sensor_1_right_end = 9.5 # um + +# Left needs to be near source, right sensor near drain +#sensor_1_left_start = 1.5 # um +#sensor_1_left_end = 2.5 # um + +#sensor_1_right_start = 7.5 # um +#sensor_1_right_end = 8.5 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +sensor_2_left_start = 6.5 # um +sensor_2_left_end = 7.5 # um + +sensor_2_right_start = 6.5 # um +sensor_2_right_end = 7.5 # um + +sensor_2_left_indices = (q2 > sensor_2_left_start ) & (q2 < sensor_2_left_end) +sensor_2_right_indices = (q2 > sensor_2_right_start) & (q2 < sensor_2_right_end) + +#dump_index = 0 +#h5f = h5py.File('dumps/moments_' + '%06d'%(dump_index) + '.h5', 'r') +#moments = np.swapaxes(h5f['moments'][:], 0, 1) +#h5f.close() +# +#density = moments[:, :, 0] +#j_x = moments[:, :, 1] +#j_y = moments[:, :, 2] +#pl.contourf(q1, q2, density, 100) +##pl.title('Time = ' + "%.2f"%(t0)) +#pl.axes().set_aspect('equal') +#pl.xlabel(r'$x$') +#pl.ylabel(r'$y$') +#pl.colorbar() +#pl.savefig('images/density' + '.png') +#pl.clf() +# +#h5f = h5py.File('dumps/lagrange_multipliers_' + '%06d'%(dump_index) + '.h5', 'r') +#lagrange_multipliers = np.swapaxes(h5f['lagrange_multipliers'][:], 0, 1) +#h5f.close() +# +#print("lagrange_multipliers.shape = ", lagrange_multipliers.shape) +#mu = lagrange_multipliers[:, :, 0] +#mu_ee = lagrange_multipliers[:, :, 1] +#T_ee = lagrange_multipliers[:, :, 2] +#vel_drift_x = lagrange_multipliers[:, :, 3] +#vel_drift_y = lagrange_multipliers[:, :, 4] +#j_x_prime = density*vel_drift_x +#print("err = ", np.mean(np.abs(j_x_prime - j_x))) + +#filepath = \ +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/geom_1/DC/tau_D_50_tau_ee_0.2' +#dump_file= np.sort(glob.glob(filepath+'/moment*.h5'))[-1] +# +#h5f = h5py.File(dump_file, 'r') +#moments = np.swapaxes(h5f['moments'][:], 0, 1) +#h5f.close() +# +#density = moments[:, :, 0] +#np.savetxt('paper_plots/density_tau_D_50_tau_ee_0.2.txt', density) +#np.savetxt('paper_plots/q2_DC_tau_D_50_tau_ee_0.2.txt', q2) +##pl.plot(q2[q2>source_end], density[0, q2>source_end]-np.mean(density)) +# +#filepath = \ +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/geom_1/DC/tau_D_5_tau_ee_0.2' +#dump_file= np.sort(glob.glob(filepath+'/moment*.h5'))[-1] +# +# +#h5f = h5py.File(dump_file, 'r') +#moments = np.swapaxes(h5f['moments'][:], 0, 1) +#h5f.close() +# +#density = moments[:, :, 0] +#np.savetxt('paper_plots/density_tau_D_5_tau_ee_0.2.txt', density) +#np.savetxt('paper_plots/q2_DC_tau_D_5_tau_ee_0.2.txt', q2) +# +#filepath = \ +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/geom_1/DC/tau_D_10_tau_ee_0.2' +#dump_file= np.sort(glob.glob(filepath+'/moment*.h5'))[-1] +# +#N_q1 = 120 +#N_q2 = 240 +# +#q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +#q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 +# +#h5f = h5py.File(dump_file, 'r') +#moments = np.swapaxes(h5f['moments'][:], 0, 1) +#h5f.close() +# +#density = moments[:, :, 0] +#np.savetxt('paper_plots/density_tau_D_10_tau_ee_0.2.txt', density) +#np.savetxt('paper_plots/q2_DC_tau_D_10_tau_ee_0.2.txt', q2) + + +#pl.plot(q2[q2>source_end], density[0, q2>source_end]-np.mean(density)) +#pl.axhline(0, color='black', linestyle='--') +#pl.legend(['$\\tau_{ee}=0.2$ ps, $\\tau_{e-ph}=50$ ps', +# '$\\tau_{ee}=0.2$ ps, $\\tau_{e-ph}=10$ ps'], loc='lower right') +#pl.xlabel(r'$x\;(\mu \mathrm{m})$') +#pl.ylabel(r'$R\; (\mathrm{a.u.})$') +#pl.xlim(xmin=(source_end+0.1)) +#pl.savefig('paper_plots/DC.png') + +filepath = \ +'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/dumps_tau_D_1_tau_ee_0.2_movie' +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/geom_1/55_GHz/tau_D_5_tau_ee_0.2' +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/dumps_AC_10_Ghz_tau_D_10_tau_ee_1_geom_2/' +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/dumps_tau_D_2_tau_ee_1_AC/' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +sensor_1_signal_array = [] +print("Reading sensor signal...") +for file_number, dump_file in enumerate(moment_files): + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + density = moments[:, :, 0] + + source = np.mean(density[0, source_indices]) + drain = np.mean(density[-1, drain_indices]) + + sensor_1_left = np.mean(density[0, sensor_1_left_indices] ) + sensor_1_right = np.mean(density[-1, sensor_1_right_indices]) + + sensor_1_signal = sensor_1_left - sensor_1_right + + sensor_1_signal_array.append(sensor_1_signal) + +time_array = np.loadtxt("dump_time_array.txt") +AC_freq = 1./100 +input_signal_array = np.sin(2.*np.pi*AC_freq*time_array) +sensor_1_signal_array = np.array(sensor_1_signal_array) +half_time = (int)(time_array.size/2) +sensor_normalized = \ + sensor_1_signal_array/np.max(np.abs(sensor_1_signal_array[half_time:])) + +pl.rcParams['figure.figsize'] = 10, 8 +for file_number, dump_file in yt.parallel_objects(enumerate(moment_files)): + + print("file number = ", file_number, "of ", moment_files.size) + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + gs = gridspec.GridSpec(3, 2) + pl.subplot(gs[:, 0]) + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + pl.contourf(q1_meshgrid, q2_meshgrid, density, 100, cmap='bwr') + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + #pl.colorbar() + + h5f = h5py.File(lagrange_multiplier_files[file_number], 'r') + lagrange_multipliers = h5f['lagrange_multipliers'][:] + h5f.close() + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + +# pl.streamplot(q1[(int)(N_q1/2):], q2, +# vel_drift_x[:, (int)(N_q1/2):], vel_drift_y[:, (int)(N_q1/2):], +# density=2, color='blue', +# linewidth=0.7, arrowsize=1 +# ) + pl.streamplot(q1, q2, + vel_drift_x, vel_drift_y, + density=2, color='blue', + linewidth=0.7, arrowsize=1 + ) +# pl.streamplot(q1, q2, +# vel_drift_x, vel_drift_y, +# density=3, color='blue', +# linewidth=0.8, arrowsize=1.1 +# ) + pl.xlim([domain.q1_start, domain.q1_end]) + pl.ylim([domain.q2_start, domain.q2_end]) + #pl.ylim([0, 5]) + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + pl.ylabel(r'$y\;(\mu \mathrm{m})$') + + pl.gca().annotate("+", xy=(-0.07, .9), xycoords=("axes fraction"), + ha="center", va="center", size=30, + bbox=dict(fc="white")) + pl.gca().annotate("-", xy=(1.05, .9), xycoords=("axes fraction"), + ha="center", va="center", size=30, + bbox=dict(fc="white", pad=6.5)) + + + pl.subplot(gs[1, 1]) + + pl.plot(time_array, input_signal_array) + pl.plot(time_array, sensor_normalized) + pl.axhline(0, color='black', linestyle='--') + pl.axvline(time_array[file_number], color='black', alpha=0.75) + pl.legend(['Source $I(t)$', 'Measured $V(t)$'], loc=(0.04, 1.125)) + pl.xlabel(r'Time (ps)') + pl.xlim([100, 200]) + pl.ylim([-1.1, 1.1]) + + + pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 1$ ps') + #pl.tight_layout() + pl.savefig('images/dump_' + '%06d'%file_number + '.png') + #pl.savefig('paper_plots/DC.png') + pl.clf() + + +#time_array = [] +#input_signal_array = [] +#sensor_1_signal_array = [] +#sensor_2_signal_array = [] +#for file_number, dump_file in enumerate(moment_files): +# +# print("file number = ", file_number, "of ", moment_files.size) +# +# h5f = h5py.File(dump_file, 'r') +# moments = np.swapaxes(h5f['moments'][:], 0, 1) +# h5f.close() +# +# density = moments[:, :, 0] +# +# source = np.mean(density[0, source_indices]) +# drain = np.mean(density[-1, drain_indices]) +# +# sensor_1_left = np.mean(density[0, sensor_1_left_indices] ) +# sensor_1_right = np.mean(density[-1, sensor_1_right_indices]) +# #sensor_1_right = np.mean(density[0, sensor_1_right_indices]) +# +# sensor_2_left = np.mean(density[0, sensor_2_left_indices] ) +# sensor_2_right = np.mean(density[-1, sensor_2_right_indices]) +# +# #sensor_1_left = density[0, q2>source_end] +# #sensor_1_right = density[-1, q2>source_end] +# +# input_signal = source - drain +# sensor_1_signal = sensor_1_left - sensor_1_right +# sensor_2_signal = sensor_2_left - sensor_2_right +# +# time_array.append(file_number*dt*dump_interval) +# input_signal_array.append(input_signal) +# sensor_1_signal_array.append(sensor_1_signal) +# sensor_2_signal_array.append(sensor_2_signal) +# +##pl.rcParams['figure.figsize'] = 12, 8 +## +#AC_freq = 5.5/100 +#time_array = np.array(time_array) +#input_signal_array = np.sin(2.*np.pi*AC_freq*time_array) +#sensor_1_signal_array = np.array(sensor_1_signal_array) +###np.savetxt('drive.txt', input_signal_array) +##np.savetxt('paper_plots/sensor_tau_ee_0.2_tau_D_5.txt', sensor_1_signal_array) +##np.savetxt('time.txt', time_array) +## +##print("sensor.shape = ", sensor_1_signal_array.shape) +##sensor_2_signal_array = np.array(sensor_2_signal_array) +## +#half_time = (int)(time_array.size/2) +#pl.plot(time_array, input_signal_array/np.max(input_signal_array[half_time:])) +#pl.plot(time_array, +# sensor_1_signal_array/np.max(sensor_1_signal_array[half_time:]) +# ) +##pl.plot(time_array, +## sensor_2_signal_array/np.max(sensor_2_signal_array[half_time:]) +## ) +#pl.xlabel(r"Time (ps)") +#pl.ylim([-1.1, 1.1]) +#pl.legend(['Input', 'Sensor 1', 'Sensor 2']) +#pl.savefig('paper_plots/IV_55_Ghz_tau_ee_0.2_tau_D_5.png') +##half_time = 0 +#input_normalized = input_signal_array[half_time:]/np.max(input_signal_array[half_time:]) +#sensor_normalized = sensor_1_signal_array[half_time:]/np.max(sensor_1_signal_array[half_time:]) +# +## Calculate the phase diff. Copied from: +## https://stackoverflow.com/questions/6157791/find-phase-difference-between-two-inharmonic-waves +#corr = correlate(input_normalized, sensor_normalized) +#nsamples = input_normalized.size +#time_corr = time_array[half_time:] +#dt_corr = np.linspace(-time_corr[-1] + time_corr[0], +# time_corr[-1] - time_corr[0], 2*nsamples-1) +#time_shift = dt_corr[corr.argmax()] +# +## force the phase shift to be in [-pi:pi] +#period = 1./AC_freq +#phase_diff = 2*np.pi*(((0.5 + time_shift/period) % 1.0) - 0.5) +#print("density.shape = ", density.shape) +#print("Phase diff = ", phase_diff) + +#phase_vs_x = [] +#for i in range(sensor_1_signal_array[0, :].size): +# signal = sensor_1_signal_array[:, i] +# corr = correlate(input_signal_array, signal) +# nsamples = input_signal_array.size +# half_time = 0 +# time_corr = time_array[half_time:] +# dt_corr = np.linspace(-time_corr[-1] + time_corr[0], +# time_corr[-1] - time_corr[0], +# 2*nsamples-1 +# ) +# time_shift = dt_corr[corr.argmax()] +# +# # force the phase shift to be in [-pi:pi] +# period = 1./params.AC_freq +# phase_diff = 2*np.pi*(((0.5 + time_shift/period) % 1.0) - 0.5) +# phase_vs_x.append(phase_diff) +# +#phase_vs_x = np.array(phase_vs_x) +#print("phase_vs_x.shape = ", phase_vs_x.shape) +#np.savetxt("paper_plots/phase_vs_x_tau_ee_0.2_tau_D_1.txt", phase_vs_x) +#np.savetxt("paper_plots/q2_tau_ee_0.2_tau_D_1.txt", q2) +#print("density.shape = ", density.shape) + + diff --git a/example_problems/electronic_boltzmann/test_compute_moments/signals.py b/example_problems/electronic_boltzmann/test_compute_moments/signals.py new file mode 100644 index 00000000..979640c3 --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments/signals.py @@ -0,0 +1,166 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +#import yt +#yt.enable_parallelism() +import os + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +import PetscBinaryIO + +import domain +import boundary_conditions +import params +import initialize + + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +# Left needs to be near source, right sensor near drain +sensor_1_left_start = 8.5 # um +sensor_1_left_end = 9.5 # um + +sensor_1_right_start = 8.5 # um +sensor_1_right_end = 9.5 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +sensor_2_left_start = 6.5 # um +sensor_2_left_end = 7.5 # um + +sensor_2_right_start = 6.5 # um +sensor_2_right_end = 7.5 # um + +sensor_2_left_indices = (q2 > sensor_2_left_start ) & (q2 < sensor_2_left_end) +sensor_2_right_indices = (q2 > sensor_2_right_start) & (q2 < sensor_2_right_end) + +io = PetscBinaryIO.PetscBinaryIO() + +filepath = os.getcwd() +#filepath = '/home/mchandra/gitansh/zero_T/example_problems/electronic_boltzmann/graphene/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC' +moment_files = np.sort(glob.glob(filepath+'/dump_moments/*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/dump_lagrange_multipliers/*.bin')) + +#moment_files = np.sort(glob.glob(filepath+'/dumps/moments*.bin')) +#lagrange_multiplier_files = \ +# np.sort(glob.glob(filepath+'/dumps/lagrange_multipliers*.bin')) + +dt = params.dt +dump_interval = params.dump_steps + +sensor_1_signal_array = [] +print("Reading sensor signal...") +for file_number, dump_file in enumerate(moment_files): + + moments = io.readBinaryFile(dump_file) + moments = moments[0].reshape(N_q2, N_q1, 3) + + density = moments[:, :, 0] + + source = np.mean(density[source_indices, 0]) + drain = np.mean(density[drain_indices, -1]) + + sensor_1_left = np.mean(density[0, 0]) + sensor_1_right = np.mean(density[0, -1]) + + sensor_1_signal = sensor_1_left - sensor_1_right + + sensor_1_signal_array.append(sensor_1_signal) + +time_array = np.loadtxt("dump_time_array.txt") +AC_freq = 1./100 +input_signal_array = np.sin(2.*np.pi*AC_freq*time_array) +sensor_1_signal_array = np.array(sensor_1_signal_array) +half_time = (int)(time_array.size/2) + +input_normalized = \ + input_signal_array/np.max(np.abs(input_signal_array[half_time:])) +sensor_normalized = \ + sensor_1_signal_array#/np.max(np.abs(sensor_1_signal_array[half_time:])) + +# Calculate the phase difference between input_signal_array and sensor_normalized +# Code copied from : +# https:/stackoverflow.com/questions/6157791/find-phase-difference-between-two-inharmonic-waves + +#corr = correlate(input_normalized, sensor_normalized) +#nsamples = input_normalized.size +#time_corr = time_array[half_time:] +#dt_corr = np.linspace(-time_corr[-1] + time_corr[0], +# time_corr[-1] - time_corr[0], 2*nsamples-1) +#time_shift = dt_corr[corr.argmax()] + +#Force the phase shift to be in [-pi:pi] +#period = 1./AC_freq +#phase_diff = 2*np.pi*(((0.5 + time_shift/period) % 1.0) - 0.5) + +#pl.plot(time_array, input_signal_array) +pl.plot(time_array, sensor_normalized) +#pl.axhline(0, color='black', linestyle='--') + +#pl.legend(['Source $I(t)$', 'Measured $V(t)$'], loc=1) +#pl.text(135, 1.14, '$\phi : %.2f \; rad$' %phase_diff) +pl.xlabel(r'Time (ps)') +#pl.xlim([0, 200]) +#pl.ylim([-1.1, 1.1]) + +pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 0.5$ ps') +pl.savefig('images/iv' + '.png') +pl.clf() + + diff --git a/example_problems/electronic_boltzmann/test_compute_moments/test.py b/example_problems/electronic_boltzmann/test_compute_moments/test.py new file mode 100644 index 00000000..bfe5688a --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments/test.py @@ -0,0 +1,137 @@ +#import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import os +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +#import yt +#yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain +#import boundary_conditions +#import params +#import initialize + + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 12, 7.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 + +p1 = domain.p1_start[0] + (0.5 + np.arange(N_p1)) * (domain.p1_end[0] - \ + domain.p1_start[0])/N_p1 +p2 = domain.p2_start[0] + (0.5 + np.arange(N_p2)) * (domain.p2_end[0] - \ + domain.p2_start[0])/N_p2 + + +filepath = os.getcwd() +moment_files = np.sort(glob.glob(filepath+'/dump_moments/*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/dump_lagrange_multipliers/*.bin')) + +print ("moment files : ", moment_files.size) +print ("lagrange multiplier files : ", lagrange_multiplier_files.size) + + +time_array = np.loadtxt("dump_time_array.txt") + +io = PetscBinaryIO.PetscBinaryIO() + +for file_number, dump_file in enumerate(moment_files[:]): + + #file_number = -1 + print("file number = ", file_number, "of ", moment_files.size) + + moments = io.readBinaryFile(moment_files[file_number]) + moments = moments[0].reshape(N_q2, N_q1, 3) + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + + lagrange_multipliers = \ + io.readBinaryFile(lagrange_multiplier_files[file_number]) + lagrange_multipliers = lagrange_multipliers[0].reshape(N_q2, N_q1, 5) + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + + print (vel_drift_x) + print (j_x, density) + + + pl.subplot(121) + pl.contourf(q1_meshgrid, q2_meshgrid, (j_x - density*vel_drift_x).T, 100, cmap='bwr') + + pl.xlim([q1[0], q1[-1]]) + pl.ylim([q2[0], q2[-1]]) + + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + pl.ylabel(r'$y\;(\mu \mathrm{m})$') + pl.colorbar() + + pl.subplot(122) + pl.contourf(q1_meshgrid, q2_meshgrid, (j_y - density*vel_drift_y).T, 100, cmap='bwr') + + pl.xlim([q1[0], q1[-1]]) + pl.ylim([q2[0], q2[-1]]) + + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + #pl.ylabel(r'$y\;(\mu \mathrm{m})$') + pl.colorbar() + + pl.tight_layout() + pl.suptitle('$\\tau_\mathrm{mc} = \infty$, $\\tau_\mathrm{mr} = \infty$') + pl.savefig('images/dump.png') + pl.clf() + diff --git a/example_problems/electronic_boltzmann/test_compute_moments/vorticity.py b/example_problems/electronic_boltzmann/test_compute_moments/vorticity.py new file mode 100644 index 00000000..2f494c60 --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments/vorticity.py @@ -0,0 +1,136 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +filepath = \ +'/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_1.0_tau_ee_0.2_tau_eph_0.5/dumps' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +time_array = np.loadtxt("dump_time_array.txt") +half_time = (int)(time_array.size/2) + +for file_number, dump_file in yt.parallel_objects(enumerate(moment_files)): + + print("file number = ", file_number, "of ", moment_files.size) + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + + h5f = h5py.File(lagrange_multiplier_files[file_number], 'r') + lagrange_multipliers = h5f['lagrange_multipliers'][:] + h5f.close() + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + + + dq1 = (domain.q1_end - domain.q1_start)/domain.N_q1 + dq2 = (domain.q2_end - domain.q2_start)/domain.N_q2 + + dvx_dx, dvx_dy = np.gradient(j_x/density, dq1, dq2) + dvy_dx, dvy_dy = np.gradient(j_y/density, dq1, dq2) + + vorticity = dvy_dx - dvx_dy + + pl.contourf(q1_meshgrid, q2_meshgrid, vorticity, 100, cmap='bwr') + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + + pl.streamplot(q1, q2, + vel_drift_x, vel_drift_y, + density=2, color='blue', + linewidth=0.7, arrowsize=1 + ) + + pl.xlim([domain.q1_start, domain.q1_end]) + pl.ylim([domain.q2_start, domain.q2_end]) + + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + pl.ylabel(r'$y\;(\mu \mathrm{m})$') + pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 1.0$ ps') + pl.savefig('vorticity_images/dump_' + '%06d'%file_number + '.png') + pl.clf() + diff --git a/example_problems/electronic_boltzmann/test_compute_moments_cartesian/PetscBinaryIO.py b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/PetscBinaryIO.py new file mode 100755 index 00000000..fd0e48e9 --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/PetscBinaryIO.py @@ -0,0 +1,479 @@ +"""PetscBinaryIO +=============== + +Provides + 1. PETSc-named objects Vec, Mat, and IS that inherit numpy.ndarray + 2. A class to read and write these objects from PETSc binary files. + +The standard usage of this module should look like: + + >>> import PetscBinaryIO + >>> io = PetscBinaryIO.PetscBinaryIO() + >>> objects = io.readBinaryFile('file.dat') + +or + + >>> import PetscBinaryIO + >>> import numpy + >>> vec = numpy.array([1., 2., 3.]).view(PetscBinaryIO.Vec) + >>> io = PetscBinaryIO.PetscBinaryIO() + >>> io.writeBinaryFile('file.dat', [vec,]) + +to read in objects one at a time use such as + + >>> import PetscBinaryIO + >>> io = PetscBinaryIO.PetscBinaryIO() + >>> fh = open('file.dat') + >>> objecttype = io.readObjectType(fh) + >>> if objecttype == 'Vec': + >>> v = io.readVec(fh) + + Note that one must read in the object type first and then call readVec(), readMat() etc. + + +See also PetscBinaryIO.__doc__ and methods therein. +""" + +import numpy as np +import functools + +try: + basestring # Python-2 has basestring as a common parent of unicode and str +except NameError: + basestring = str # Python-3 is unicode through and through + +def update_wrapper_with_doc(wrapper, wrapped): + """Similar to functools.update_wrapper, but also gets the wrapper's __doc__ string""" + wdoc = wrapper.__doc__ + + functools.update_wrapper(wrapper, wrapped) + if wdoc is not None: + if wrapper.__doc__ is None: + wrapper.__doc__ = wdoc + else: + wrapper.__doc__ = wrapper.__doc__ + wdoc + return wrapper + +def wraps_with_doc(wrapped): + """Similar to functools.wraps, but also gets the wrapper's __doc__ string""" + return functools.partial(update_wrapper_with_doc, wrapped=wrapped) + +def decorate_with_conf(f): + """Decorates methods to take kwargs for precisions.""" + @wraps_with_doc(f) + def decorated_f(self, *args, **kwargs): + """ + Additional kwargs: + precision: 'single', 'double', 'longlong' for scalars + indices: '32bit', '64bit' integer size + complexscalars: True/False + + Note these are set in order of preference: + 1. kwargs if given here + 2. PetscBinaryIO class __init__ arguments + 3. PETSC_DIR/PETSC_ARCH defaults + """ + + changed = False + old_precision = self.precision + old_indices = self.indices + old_complexscalars = self.complexscalars + + try: + self.precision = kwargs.pop('precision') + except KeyError: + pass + else: + changed = True + + try: + self.indices = kwargs.pop('indices') + except KeyError: + pass + else: + changed = True + + try: + self.complexscalars = kwargs.pop('complexscalars') + except KeyError: + pass + else: + changed = True + + if changed: + self._update_dtypes() + + result = f(self, *args, **kwargs) + + if changed: + self.precision = old_precision + self.indices = old_indices + self.complexscalars = old_complexscalars + self._update_dtypes() + + return result + return decorated_f + + +class DoneWithFile(Exception): pass + + +class Vec(np.ndarray): + """Vec represented as 1D numpy array + + The best way to instantiate this class for use with writeBinaryFile() + is through the numpy view method: + + vec = numpy.array([1,2,3]).view(Vec) + """ + _classid = 1211214 + + +class MatDense(np.matrix): + """Mat represented as 2D numpy array + + The best way to instantiate this class for use with writeBinaryFile() + is through the numpy view method: + + mat = numpy.array([[1,0],[0,1]]).view(Mat) + """ + _classid = 1211216 + + +class MatSparse(tuple): + """Mat represented as CSR tuple ((M, N), (rowindices, col, val)) + + This should be instantiated from a tuple: + + mat = MatSparse( ((M,N), (rowindices,col,val)) ) + """ + _classid = 1211216 + def __repr__(self): + return 'MatSparse: %s'%super(MatSparse, self).__repr__() + + +class IS(np.ndarray): + """IS represented as 1D numpy array + + The best way to instantiate this class for use with writeBinaryFile() + is through the numpy "view" method: + + an_is = numpy.array([3,4,5]).view(IS) + """ + _classid = 1211218 + + +class PetscBinaryIO(object): + """Reader/Writer class for PETSc binary files. + + Note that by default, precisions for both scalars and indices, as well as + complex scalars, are picked up from the PETSC_DIR/PETSC_ARCH configuration + as set by environmental variables. + + Alternatively, defaults can be overridden at class instantiation, or for + a given method call. + """ + + _classid = {1211216:'Mat', + 1211214:'Vec', + 1211218:'IS', + 1211219:'Bag'} + + def __init__(self, precision=None, indices=None, complexscalars=None): + if (precision is None) or (indices is None) or (complexscalars is None): + import petsc_conf + defaultprecision, defaultindices, defaultcomplexscalars = petsc_conf.get_conf() + if precision is None: + if defaultprecision is None: + precision = 'double' + else: + precision = defaultprecision + + if indices is None: + if defaultindices is None: + indices = '32bit' + else: + indices = defaultindices + + if complexscalars is None: + if defaultcomplexscalars is None: + complexscalars = False + else: + complexscalars = defaultcomplexscalars + + self.precision = precision + self.indices = indices + self.complexscalars = complexscalars + self._update_dtypes() + + def _update_dtypes(self): + if self.indices == '64bit': + self._inttype = np.dtype('>i8') + else: + self._inttype = np.dtype('>i4') + + if self.precision == 'longlong': + nbyte = 16 + elif self.precision == 'single': + nbyte = 4 + else: + nbyte = 8 + + if self.complexscalars: + name = 'c' + nbyte = nbyte * 2 # complex scalar takes twice as many bytes + else: + name = 'f' + + self._scalartype = '>{0}{1}'.format(name, nbyte) + + @decorate_with_conf + def readVec(self, fh): + """Reads a PETSc Vec from a binary file handle, must be called after readObjectType().""" + + nz = np.fromfile(fh, dtype=self._inttype, count=1)[0] + try: + vals = np.fromfile(fh, dtype=self._scalartype, count=nz) + except MemoryError: + raise IOError('Inconsistent or invalid Vec data in file') + if (len(vals) is 0): + raise IOError('Inconsistent or invalid Vec data in file') + return vals.view(Vec) + + @decorate_with_conf + def writeVec(self, fh, vec): + """Writes a PETSc Vec to a binary file handle.""" + + metadata = np.array([Vec._classid, len(vec)], dtype=self._inttype) + metadata.tofile(fh) + vec.astype(self._scalartype).tofile(fh) + return + + @decorate_with_conf + def readMatSparse(self, fh): + """Reads a PETSc Mat, returning a sparse representation of the data. Must be called after readObjectType() + + (M,N), (I,J,V) = readMatSparse(fid) + + Input: + fid : file handle to open binary file. + Output: + M,N : matrix size + I,J : arrays of row and column for each nonzero + V: nonzero value + """ + + try: + M,N,nz = np.fromfile(fh, dtype=self._inttype, count=3) + I = np.empty(M+1, dtype=self._inttype) + I[0] = 0 + rownz = np.fromfile(fh, dtype=self._inttype, count=M) + np.cumsum(rownz, out=I[1:]) + assert I[-1] == nz + + J = np.fromfile(fh, dtype=self._inttype, count=nz) + assert len(J) == nz + V = np.fromfile(fh, dtype=self._scalartype, count=nz) + assert len(V) == nz + except (AssertionError, MemoryError, IndexError): + raise IOError('Inconsistent or invalid Mat data in file') + + return MatSparse(((M, N), (I, J, V))) + + @decorate_with_conf + def writeMatSparse(self, fh, mat): + """Writes a Mat into a PETSc binary file handle""" + + ((M,N), (I,J,V)) = mat + metadata = np.array([MatSparse._classid,M,N,I[-1]], dtype=self._inttype) + rownz = I[1:] - I[:-1] + + assert len(J.shape) == len(V.shape) == len(I.shape) == 1 + assert len(J) == len(V) == I[-1] == rownz.sum() + assert (rownz > -1).all() + + metadata.tofile(fh) + rownz.astype(self._inttype).tofile(fh) + J.astype(self._inttype).tofile(fh) + V.astype(self._scalartype).tofile(fh) + return + + @decorate_with_conf + def readMatDense(self, fh): + """Reads a PETSc Mat, returning a dense represention of the data, must be called after readObjectType()""" + + try: + M,N,nz = np.fromfile(fh, dtype=self._inttype, count=3) + I = np.empty(M+1, dtype=self._inttype) + I[0] = 0 + rownz = np.fromfile(fh, dtype=self._inttype, count=M) + np.cumsum(rownz, out=I[1:]) + assert I[-1] == nz + + J = np.fromfile(fh, dtype=self._inttype, count=nz) + assert len(J) == nz + V = np.fromfile(fh, dtype=self._scalartype, count=nz) + assert len(V) == nz + + except (AssertionError, MemoryError, IndexError): + raise IOError('Inconsistent or invalid Mat data in file') + + mat = np.zeros((M,N), dtype=self._scalartype) + for row in range(M): + rstart, rend = I[row:row+2] + mat[row, J[rstart:rend]] = V[rstart:rend] + return mat.view(MatDense) + + @decorate_with_conf + def readMatSciPy(self, fh): + from scipy.sparse import csr_matrix + (M, N), (I, J, V) = self.readMatSparse(fh) + return csr_matrix((V, J, I), shape=(M, N)) + + @decorate_with_conf + def writeMatSciPy(self, fh, mat): + from scipy.sparse import csr_matrix + if hasattr(mat, 'tocsr'): + mat = mat.tocsr() + assert isinstance(mat, csr_matrix) + V = mat.data + M,N = mat.shape + J = mat.indices + I = mat.indptr + return self.writeMatSparse(fh, (mat.shape, (mat.indptr,mat.indices,mat.data))) + + @decorate_with_conf + def readMat(self, fh, mattype='sparse'): + """Reads a PETSc Mat from binary file handle, must be called after readObjectType() + + optional mattype: 'sparse" or 'dense' + + See also: readMatSparse, readMatDense + """ + + if mattype == 'sparse': + return self.readMatSparse(fh) + elif mattype == 'dense': + return self.readMatDense(fh) + elif mattype == 'scipy.sparse': + return self.readMatSciPy(fh) + else: + raise RuntimeError('Invalid matrix type requested: choose sparse/dense/scipy.sparse') + + @decorate_with_conf + def readIS(self, fh): + """Reads a PETSc Index Set from binary file handle, must be called after readObjectType()""" + + try: + nz = np.fromfile(fh, dtype=self._inttype, count=1)[0] + v = np.fromfile(fh, dtype=self._inttype, count=nz) + assert len(v) == nz + except (MemoryError,IndexError): + raise IOError('Inconsistent or invalid IS data in file') + return v.view(IS) + + @decorate_with_conf + def writeIS(self, fh, anis): + """Writes a PETSc IS to binary file handle.""" + + metadata = np.array([IS._classid, len(anis)], dtype=self._inttype) + metadata.tofile(fh) + anis.astype(self._inttype).tofile(fh) + return + + @decorate_with_conf + def readObjectType(self, fid): + """Returns the next object type as a string in the file""" + try: + header = np.fromfile(fid, dtype=self._inttype, count=1)[0] + except (MemoryError, IndexError): + raise DoneWithFile + try: + objecttype = self._classid[header] + except KeyError: + raise IOError('Invalid PetscObject CLASSID or object not implemented for python') + return objecttype + + @decorate_with_conf + def readBinaryFile(self, fid, mattype='sparse'): + """Reads a PETSc binary file, returning a tuple of the contained objects. + + objects = self.readBinaryFile(fid, **kwargs) + + Input: + fid : either file name or handle to an open binary file. + + Output: + objects : tuple of objects representing the data in numpy arrays. + + Optional: + mattype : + 'sparse': Return matrices as raw CSR: (M, N), (row, col, val). + 'dense': Return matrices as MxN numpy arrays. + 'scipy.sparse': Return matrices as scipy.sparse objects. + """ + + close = False + + if isinstance(fid, basestring): + fid = open(fid, 'rb') + close = True + + objects = [] + try: + while True: + objecttype = self.readObjectType(fid) + + if objecttype == 'Vec': + objects.append(self.readVec(fid)) + elif objecttype == 'IS': + objects.append(self.readIS(fid)) + elif objecttype == 'Mat': + objects.append(self.readMat(fid,mattype)) + elif objecttype == 'Bag': + raise NotImplementedError('Bag Reader not yet implemented') + except DoneWithFile: + pass + finally: + if close: + fid.close() + + return tuple(objects) + + @decorate_with_conf + def writeBinaryFile(self, fid, objects): + """Writes a PETSc binary file containing the objects given. + + readBinaryFile(fid, objects) + + Input: + fid : either file handle to an open binary file, or filename. + objects : list of objects representing the data in numpy arrays, + which must be of type Vec, IS, MatSparse, or MatSciPy. + """ + close = False + if isinstance(fid, basestring): + fid = open(fid, 'wb') + close = True + + for petscobj in objects: + if (isinstance(petscobj, Vec)): + self.writeVec(fid, petscobj) + elif (isinstance(petscobj, IS)): + self.writeIS(fid, petscobj) + elif (isinstance(petscobj, MatSparse)): + self.writeMatSparse(fid, petscobj) + elif (isinstance(petscobj, MatDense)): + if close: + fid.close() + raise NotImplementedError('Writing a dense matrix is not yet supported') + else: + try: + self.writeMatSciPy(fid, petscobj) + except AssertionError: + if close: + fid.close() + raise TypeError('Object %s is not a valid PETSc object'%(petscobj.__repr__())) + if close: + fid.close() + return diff --git a/example_problems/electronic_boltzmann/test_compute_moments_cartesian/boundary_conditions.py b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/boundary_conditions.py new file mode 100644 index 00000000..762f5e79 --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/boundary_conditions.py @@ -0,0 +1,107 @@ +import numpy as np +import arrayfire as af +import domain + +in_q1_left = 'mirror+dirichlet' +in_q1_right = 'mirror+dirichlet' +in_q2_bottom = 'mirror' +in_q2_top = 'mirror' + +@af.broadcast +def f_left(f, t, q1, q2, p1, p2, p3, params): + + k = params.boltzmann_constant + E_upper = params.E_band + T = params.initial_temperature + mu = params.initial_mu + + t = params.current_time + omega = 2. * np.pi * params.AC_freq + vel_drift_x_in = params.vel_drift_x_in + + if (params.p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (params.p_space_grid == 'polar2D'): + p_x = p1 * af.cos(p2) + p_y = p1 * af.sin(p2) + else: + raise NotImplementedError('Unsupported coordinate system in p_space') + + + fermi_dirac_in = (1./(af.exp( (E_upper - vel_drift_x_in*p_x - mu)/(k*T) ) + 1.) + ) + + if (params.contact_geometry=="straight"): + # Contacts on either side of the device + + q2_contact_start = params.contact_start + q2_contact_end = params.contact_end + + cond = ((q2 >= q2_contact_start) & \ + (q2 <= q2_contact_end) \ + ) + + f_left = cond*fermi_dirac_in + (1 - cond)*f + + elif (params.contact_geometry=="turn_around"): + # Contacts on the same side of the device + + vel_drift_x_out = -params.vel_drift_x_in * np.sin(omega*t) + + fermi_dirac_out = (1./(af.exp( (E_upper - vel_drift_x_out*p_x - mu)/(k*T) ) + 1.) + ) + + # TODO: set these parameters in params.py + cond_in = ((q2 >= 3.5) & (q2 <= 4.5)) + cond_out = ((q2 >= 5.5) & (q2 <= 6.5)) + + f_left = cond_in*fermi_dirac_in + cond_out*fermi_dirac_out \ + + (1 - cond_in)*(1 - cond_out)*f + + af.eval(f_left) + return(f_left) + +@af.broadcast +def f_right(f, t, q1, q2, p1, p2, p3, params): + + k = params.boltzmann_constant + E_upper = params.E_band + T = params.initial_temperature + mu = params.initial_mu + + t = params.current_time + omega = 2. * np.pi * params.AC_freq + vel_drift_x_out = params.vel_drift_x_out + + if (params.p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (params.p_space_grid == 'polar2D'): + p_x = p1 * af.cos(p2) + p_y = p1 * af.sin(p2) + else: + raise NotImplementedError('Unsupported coordinate system in p_space') + + fermi_dirac_out = (1./(af.exp( (E_upper - vel_drift_x_out*p_x - mu)/(k*T) ) + 1.) + ) + + if (params.contact_geometry=="straight"): + # Contacts on either side of the device + + q2_contact_start = params.contact_start + q2_contact_end = params.contact_end + + cond = ((q2 >= q2_contact_start) & \ + (q2 <= q2_contact_end) \ + ) + + f_right = cond*fermi_dirac_out + (1 - cond)*f + + elif (params.contact_geometry=="turn_around"): + # Contacts on the same side of the device + + f_right = f + + af.eval(f_right) + return(f_right) diff --git a/example_problems/electronic_boltzmann/test_compute_moments_cartesian/check.py b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/check.py new file mode 100644 index 00000000..71fe46ef --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/check.py @@ -0,0 +1,42 @@ +import numpy as np +import params +import arrayfire as af +import pylab as pl + +import domain + +from bolt.src.electronic_boltzmann.utils.polygon import polygon + +p2_start = -np.pi +p2_end = np.pi +N_p2 = domain.N_p2 +theta = \ + p2_start + (0.5 + np.arange(N_p2))*(p2_end - p2_start)/N_p2 + +theta = af.from_ndarray(theta) + +hexa = polygon(6, theta, rotation = np.pi/6) +hexa = hexa.to_ndarray() + +#pl.polar(theta, hexa) + +#pl.plot(theta, hexa * np.cos(theta)) +#pl.plot(theta, hexa * np.sin(theta)) + +pl.gca().set_aspect(1) +pl.plot(hexa*np.cos(theta), hexa*np.sin(theta)) + +#p_hat_0_old = np.loadtxt("P_hat_0_old.txt") +#p_hat_1_old = np.loadtxt("P_hat_1_old.txt") + +#p_hat_0 = np.loadtxt("P_hat_0.txt") +#p_hat_1 = np.loadtxt("P_hat_1.txt") + +#pl.plot(theta, p_hat_0_old) +#pl.plot(theta, p_hat_1_old) + +#pl.plot(theta, p_hat_0, '--') +#pl.plot(theta, p_hat_1, '--') + + +pl.savefig("images/test.png") diff --git a/example_problems/electronic_boltzmann/test_compute_moments_cartesian/domain.py b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/domain.py new file mode 100644 index 00000000..e6aebf7c --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/domain.py @@ -0,0 +1,65 @@ +import numpy as np +import params + +q1_start = 0. +q1_end = 1.0 +N_q1 = 20 + +q2_start = 0. +q2_end = 1.25 +N_q2 = 25 + +# If N_p1 > 1, mirror boundary conditions require p1 to be +# symmetric about zero +# TODO : Check and fix discrepancy between this and the claim +# that p1_center = mu in polar representation +N_p1 = 128 # Set equal to 1 for 1D polar + +# In the cartesian representation of momentum space, +# p1 = p_x (magnitude of momentum) +# p1_start and p1_end are set such that p1_center is 0 + +# Uncomment the following for the cartesian representation of momentum space +p1_start = [-0.04] +p1_end = [0.04] + + +# In the 2D polar representation of momentum space, +# p1 = p_r (magnitude of momentum) +# p1_start and p1_end are set such that p1_center is mu + +# Uncomment the following for the 2D polar representation of momentum space +#p1_start = [params.initial_mu - \ +# 16.*params.boltzmann_constant*params.initial_temperature] +#p1_end = [params.initial_mu + \ +# 16.*params.boltzmann_constant*params.initial_temperature] + +# Uncomment the following for the 1D polar representation of momentum space +#p1_start = [0.5*params.initial_mu/params.fermi_velocity] +#p1_end = [1.5*params.initial_mu/params.fermi_velocity] + + +# If N_p2 > 1, mirror boundary conditions require p2 to be +# symmetric about zero +N_p2 = 128 + +# In the cartesian representation of momentum space, +# p2 = p_y (magnitude of momentum) +# p2_start and p2_end are set such that p2_center is 0 +p2_start = [-0.04] +p2_end = [0.04] + +# In the 2D polar representation of momentum space, +# p2 = p_theta (angle of momentum) +# N_p_theta MUST be even. +#p2_start = [-np.pi] +#p2_end = [np.pi] + +# If N_p3 > 1, mirror boundary conditions require p3 to be +# symmetric about zero + +p3_start = [-0.5] +p3_end = [0.5] +N_p3 = 1 + +N_ghost = 2 diff --git a/example_problems/electronic_boltzmann/test_compute_moments_cartesian/edge_density.py b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/edge_density.py new file mode 100644 index 00000000..3697590e --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/edge_density.py @@ -0,0 +1,122 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +#import yt +#yt.enable_parallelism() +import os + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +import PetscBinaryIO + +import domain +import boundary_conditions +import params +import initialize + + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +# Left needs to be near source, right sensor near drain +sensor_1_left_start = 8.5 # um +sensor_1_left_end = 9.5 # um + +sensor_1_right_start = 8.5 # um +sensor_1_right_end = 9.5 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +io = PetscBinaryIO.PetscBinaryIO() + +filepath = os.getcwd() +moment_files = np.sort(glob.glob(filepath+'/dump_moments/*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/dump_lagrange_multipliers/*.bin')) + +dt = params.dt +dump_interval = params.dump_steps + +sensor_1_signal_array = [] +print("Reading sensor signal...") +for file_number, dump_file in enumerate(moment_files): + + moments = io.readBinaryFile(dump_file) + moments = moments[0].reshape(N_q2, N_q1, 3) + + density = moments[:, :, 0] + + source = np.mean(density[source_indices, 0]) + drain = np.mean(density[drain_indices, -1]) + + sensor_1_left = np.mean(density[0, 0]) + sensor_1_right = np.mean(density[0, -1]) + + sensor_1_signal = sensor_1_left - sensor_1_right + + sensor_1_signal_array.append(sensor_1_signal) + +time_array = np.loadtxt("dump_time_array.txt") +AC_freq = 1./100 +input_signal_array = np.sin(2.*np.pi*AC_freq*time_array) +sensor_1_signal_array = np.array(sensor_1_signal_array) +half_time = (int)(time_array.size/2) + +input_normalized = \ + input_signal_array/np.max(np.abs(input_signal_array[half_time:])) +sensor_normalized = \ + sensor_1_signal_array#/np.max(np.abs(sensor_1_signal_array[half_time:])) + diff --git a/example_problems/electronic_boltzmann/test_compute_moments_cartesian/edge_potential.py b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/edge_potential.py new file mode 100644 index 00000000..b50b3bf5 --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/edge_potential.py @@ -0,0 +1,161 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 12, 7.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +# Left needs to be near source, right sensor near drain +sensor_1_left_start = 5.5 # um +sensor_1_left_end = 10.0 # um + +sensor_1_right_start = 5.5 # um +sensor_1_right_end = 10.0 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +sensor_2_left_start = 6.5 # um +sensor_2_left_end = 7.5 # um + +sensor_2_right_start = 6.5 # um +sensor_2_right_end = 7.5 # um + +sensor_2_left_indices = (q2 > sensor_2_left_start ) & (q2 < sensor_2_left_end) +sensor_2_right_indices = (q2 > sensor_2_right_start) & (q2 < sensor_2_right_end) + +filepath = \ +'/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_1.0_tau_ee_0.2_tau_eph_0.5/dumps' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +sensor_1_signal_array = [] +#sensor_2_signal_array = [] +#print("Reading sensor signal...") +print("Loading data...") +density = [] +edge_density = [] +for file_number, dump_file in enumerate(moment_files): + + print("File number = ", file_number, ' of ', moment_files.size) + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + density.append(moments[:, :, 0]) + edge_density.append(density[file_number][0, sensor_1_left_indices]) + +density = np.array(density) +edge_density = np.array(edge_density) + +mean_density = np.mean(density) +max_density = np.max(density) +min_density = np.min(density) + +np.savetxt("edge_density.txt", edge_density) + +print("Dumping data...") +for file_number in yt.parallel_objects(range(density.shape[0])): + + print("File number = ", file_number, ' of ', moment_files.size) + + pl.semilogy(q2[sensor_1_left_indices], + density[file_number][0, sensor_1_left_indices], + ) + #pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.title(r'Time = ' + "%.2f"%(file_number*dt*dump_interval) + " ps") + + pl.xlim([sensor_1_left_start, sensor_1_left_end]) + #pl.ylim([min_density-mean_density, max_density-mean_density]) + #pl.ylim([0., np.log(max_density)]) + + #pl.gca().set_aspect('equal') + #pl.xlabel(r'$x\;(\mu \mathrm{m})$') + #pl.ylabel(r'$y\;(\mu \mathrm{m})$') + + #pl.suptitle('$\\tau_\mathrm{mc} = \infty$ ps, $\\tau_\mathrm{mr} = 3.0$ ps') + #pl.savefig('images/dump_' + '%06d'%file_number + '.png') + pl.savefig('images/density_' + '%06d'%file_number + '.png') + pl.clf() + + + diff --git a/example_problems/electronic_boltzmann/test_compute_moments_cartesian/enstrophy.py b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/enstrophy.py new file mode 100644 index 00000000..aeab5a28 --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/enstrophy.py @@ -0,0 +1,142 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +filepath = \ +'/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_1.0_tau_ee_0.2_tau_eph_0.5/dumps' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +kinetic_energy_array = [] +enstrophy_array = [] +print("Reading kinetic energy and enstrophy signals...") +for file_number, dump_file in enumerate(moment_files): + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + + h5f = h5py.File(lagrange_multiplier_files[file_number], 'r') + lagrange_multipliers = h5f['lagrange_multipliers'][:] + h5f.close() + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + + dq1 = (domain.q1_end - domain.q1_start)/domain.N_q1 + dq2 = (domain.q2_end - domain.q2_start)/domain.N_q2 + + dvx_dx, dvx_dy = np.gradient(j_x/density, dq1, dq2) + dvy_dx, dvy_dy = np.gradient(j_y/density, dq1, dq2) + + vorticity = dvy_dx - dvx_dy + + kinetic_energy = 0.5 * np.sum(vel_drift_x**2 + vel_drift_y**2) * dq1 * dq2 + kinetic_energy_array.append(kinetic_energy) + + enstrophy = np.sum(vorticity**2) * dq1 * dq2 + enstrophy_array.append(enstrophy) + +time_array = np.loadtxt("dump_time_array.txt") +half_time = (int)(time_array.size/2) + +kinetic_energy_normalized = \ + kinetic_energy_array/np.max(np.abs(kinetic_energy_array[half_time:])) +enstrophy_normalized = \ + enstrophy_array/np.max(np.abs(enstrophy_array[half_time:])) + + +pl.plot(time_array, kinetic_energy_normalized) +pl.plot(time_array, enstrophy_normalized) +pl.axhline(0, color='black', linestyle='--') + +pl.legend(['Kinetic Energy', 'Enstrophy'], loc=1) +pl.xlabel(r'Time (ps)') +pl.xlim([0, 200]) +pl.ylim([-0.1, 1.1]) + +pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 1.0$ ps') +pl.savefig('vorticity_images/iv' + '.png') +pl.clf() + + diff --git a/example_problems/electronic_boltzmann/test_compute_moments_cartesian/initialize.py b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/initialize.py new file mode 100644 index 00000000..ef1bc936 --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/initialize.py @@ -0,0 +1,98 @@ +""" +Functions which are used in assigning the I.C's to +the system. +""" + +import arrayfire as af +import numpy as np +from petsc4py import PETSc + +import domain + +def initialize_f(q1, q2, p1, p2, p3, params): + + PETSc.Sys.Print("Initializing f") + k = params.boltzmann_constant + + params.mu = 0.*q1 + params.initial_mu + params.T = 0.*q1 + params.initial_temperature + params.vel_drift_x = 1.*params.vel_drift_x_in + 0.*q1 + params.vel_drift_y = 0.*q1 + + #print (params.vel_drift_x) + params.mu_ee = params.mu.copy() + params.T_ee = params.T.copy() + + params.p_x, params.p_y = params.get_p_x_and_p_y(p1, p2) + params.E_band = params.band_energy(p1, p2) + params.vel_band = params.band_velocity(p1, p2) + + # Evaluating velocity space resolution for each species: + dp1 = []; dp2 = []; dp3 = [] + N_p1 = domain.N_p1; N_p2 = domain.N_p2; N_p3 = domain.N_p3 + p1_start = domain.p1_start; p1_end = domain.p1_end + p2_start = domain.p2_start; p2_end = domain.p2_end + p3_start = domain.p3_start; p3_end = domain.p3_end + + N_species = len(params.mass) + for i in range(N_species): + dp1.append((p1_end[i] - p1_start[i]) / N_p1) + dp2.append((p2_end[i] - p2_start[i]) / N_p2) + dp3.append((p3_end[i] - p3_start[i]) / N_p3) + + + theta = af.atan(params.p_y / params.p_x) + p_f = params.fermi_momentum_magnitude(theta) + + if (params.p_space_grid == 'cartesian'): + dp_x = dp1[0]; dp_y = dp2[0]; dp_z = dp3[0] + params.integral_measure = \ + (4./(2.*np.pi*params.h_bar)**2) * dp_z * dp_y * dp_x + + elif (params.p_space_grid == 'polar2D'): + # In polar2D coordinates, p1 = radius and p2 = theta + # Integral : \int delta(r - r_F) F(r, theta) r dr dtheta + r = p1; theta = p2 + dp_r = dp1[0]; dp_theta = dp2[0] + + if (params.zero_temperature): + # Assumption : F(r, theta) = delta(r-r_F)*F(theta) + params.integral_measure = \ + (4./(2.*np.pi*params.h_bar)**2) * p_f * dp_theta + + else: + params.integral_measure = \ + (4./(2.*np.pi*params.h_bar)**2) * r * dp_r * dp_theta + + + else : + raise NotImplementedError('Unsupported coordinate system in p_space') + + + + f = (1./(af.exp( (params.E_band - params.vel_drift_x*params.p_x + - params.vel_drift_y*params.p_y + - params.mu + )/(k*params.T) + ) + 1. + )) + + af.eval(f) + return(f) + + +def initialize_E(q1, q2, params): + + E1 = 0.*q1 + E2 = 0.*q1 + E3 = 0.*q1 + + return(E1, E2, E3) + +def initialize_B(q1, q2, params): + + B1 = 0.*q1 + B2 = 0.*q1 + B3 = 0.*q1 + + return(B1, B2, B3) diff --git a/example_problems/electronic_boltzmann/test_compute_moments_cartesian/main.py b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/main.py new file mode 100644 index 00000000..fa5ff601 --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/main.py @@ -0,0 +1,57 @@ +import os +import arrayfire as af +import numpy as np +import math +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +from mpi4py import MPI +MPI.WTIME_IS_GLOBAL=True + +from bolt.lib.physical_system import physical_system +from bolt.lib.nonlinear.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.utils.restart_latest import latest_output, format_time + +import domain +import boundary_conditions +import initialize +import params + +import bolt.src.electronic_boltzmann.advection_terms \ + as advection_terms +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator +import bolt.src.electronic_boltzmann.moments \ + as moments + +from bolt.lib.nonlinear.compute_moments import compute_moments +from bolt.lib.utils.calculate_q import calculate_q + + +# Defining the physical system to be solved: +system = physical_system(domain, + boundary_conditions, + params, + initialize, + advection_terms, + collision_operator.RTA, + moments + ) + +# Declaring a nonlinear system object which will evolve the defined physical system: +nls = nonlinear_solver(system) +N_g = domain.N_ghost +params.rank = nls._comm.rank + + +nls.dump_moments('dump_moments/moments') +nls.dump_aux_arrays([params.mu, + params.mu_ee, + params.T_ee, + params.vel_drift_x, params.vel_drift_y + ], + 'lagrange_multipliers', + 'dump_lagrange_multipliers/lagrange_multipliers' + ) +nls.dump_distribution_function('dump_f/f') + diff --git a/example_problems/electronic_boltzmann/test_compute_moments_cartesian/momentum_space_movie.py b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/momentum_space_movie.py new file mode 100644 index 00000000..d003e39a --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/momentum_space_movie.py @@ -0,0 +1,138 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import os +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +#import yt +#yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain +import params + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1_start = domain.q1_start +q1_end = domain.q1_end +q2_start = domain.q2_start +q2_end = domain.q2_end + +q1 = q1_start + (0.5 + np.arange(N_q1)) * (q1_end - q1_start)/N_q1 +q2 = q2_start + (0.5 + np.arange(N_q2)) * (q2_end - q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 +N_p3 = domain.N_p3 + +p1_start = domain.p1_start +p1_end = domain.p1_end +p2_start = domain.p2_start +p2_end = domain.p2_end + +p1 = p1_start[0] + (0.5 + np.arange(N_p1)) * (p1_end[0] - p1_start[0])/N_p1 +p2 = p2_start[0] + (0.5 + np.arange(N_p2)) * (p2_end[0] - p2_start[0])/N_p2 + +p1_meshgrid, p2_meshgrid = np.meshgrid(p1, p2) + +p_x = p1_meshgrid * np.cos(p2_meshgrid) +p_y = p1_meshgrid * np.sin(p2_meshgrid) + +#p2_meshgrid, p1_meshgrid = np.meshgrid(p2, p1) + +N_s = len(params.mass) + +io = PetscBinaryIO.PetscBinaryIO() + +filepath = os.getcwd() +moment_files = np.sort(glob.glob(filepath+'/dump_moments/*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/dump_lagrange_multipliers/.bin')) +dist_func_files = np.sort(glob.glob(filepath+'/dump_f/*.bin')) + +dist_func_bg_file = dist_func_files[0] +dist_func_file = dist_func_files[-1] + +dist_func_background = io.readBinaryFile(dist_func_bg_file) +#dist_func_background = dist_func_background[0].reshape(N_q2, N_q1, N_p2, N_p1) +dist_func_background = dist_func_background[0].reshape(N_q2, N_q1, N_s, N_p3, N_p2, N_p1) +dist_func = io.readBinaryFile(dist_func_file) + +print (dist_func[0].shape) + +dist_func = dist_func[0].reshape(N_q2, N_q1, N_s, N_p3, N_p2, N_p1) +dist_func_backgrouind = np.mean(dist_func) + +N = 7 +for index_1 in range(N): + for index_2 in range(N): + + q1_position = int(N_q1*((index_1/N)+(1/(2*N)))) + q2_position = int(N_q2*((index_2/N)+(1/(2*N)))) + + #a = np.max((dist_func - dist_func_background)[q2_position, q1_position, :, :]) + #b = np.abs(np.min((dist_func - dist_func_background)[q2_position, q1_position, :, :])) + #norm_factor = np.maximum(a, b) + #f_at_desired_q = \ + # np.reshape((dist_func-dist_func_background)[q2_position, q1_position, :, :], + # [N_p2, N_p1])/norm_factor + print ((dist_func - dist_func_background).shape) + f_at_desired_q = np.reshape((dist_func - \ + dist_func_background)[q2_position, q1_position, :], + [N_p2, N_p1] + ) + pl.contourf(p1_meshgrid, p2_meshgrid, f_at_desired_q, 100, cmap='bwr') + + #np.savetxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2), f_at_desired_q) + #f = np.loadtxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2)) + + + #pl.contourf(p_x, p_y, f_at_desired_q, 100, cmap='bwr') + #pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.xlabel('$p_x$') + pl.ylabel('$p_y$') + pl.gca().set_aspect('equal') + pl.savefig('images/dist_func_at_a_point_%d_%d.png'%(index_1, index_2)) + pl.clf() + diff --git a/example_problems/electronic_boltzmann/test_compute_moments_cartesian/momentum_space_movie_debug.py b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/momentum_space_movie_debug.py new file mode 100644 index 00000000..0b2c719d --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/momentum_space_movie_debug.py @@ -0,0 +1,182 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import os +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +#import yt +#yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain +import params + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_s = len(params.mass) # Number of species + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1_start = domain.q1_start +q1_end = domain.q1_end +q2_start = domain.q2_start +q2_end = domain.q2_end + +q1 = q1_start + (0.5 + np.arange(N_q1)) * (q1_end - q1_start)/N_q1 +q2 = q2_start + (0.5 + np.arange(N_q2)) * (q2_end - q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 +N_p3 = domain.N_p3 + +p1_start = domain.p1_start +p1_end = domain.p1_end +p2_start = domain.p2_start +p2_end = domain.p2_end + +p1 = p1_start[0] + (0.5 + np.arange(N_p1)) * (p1_end[0] - p1_start[0])/N_p1 +p2 = p2_start[0] + (0.5 + np.arange(N_p2)) * (p2_end[0] - p2_start[0])/N_p2 + +p1_meshgrid, p2_meshgrid = np.meshgrid(p1, p2) + +p_x = p1_meshgrid * np.cos(p2_meshgrid) +p_y = p1_meshgrid * np.sin(p2_meshgrid) + +#p2_meshgrid, p1_meshgrid = np.meshgrid(p2, p1) + +io = PetscBinaryIO.PetscBinaryIO() + +filepath = os.getcwd() +moment_files = np.sort(glob.glob(filepath+'/dump_moments/*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/dump_lagrange_multipliers/*.bin')) +dist_func_files = np.sort(glob.glob(filepath+'/dump_f/*.bin')) + +#moment_files = np.sort(glob.glob(filepath+'/dumps/moments*.bin')) +#lagrange_multiplier_files = \ +# np.sort(glob.glob(filepath+'/dumps/lagrange_multipliers*.bin')) +#dist_func_files = np.sort(glob.glob(filepath+'/dumps/f*.bin')) + +dist_func_bg_file = dist_func_files[0] +dist_func_file = dist_func_files[-1] + +print(dist_func_bg_file) +print(dist_func_file) + +dist_func_background = io.readBinaryFile(dist_func_bg_file) +#dist_func_background = dist_func_background[0].reshape(N_q2, N_q1, N_p2, N_p1) +dist_func_background = dist_func_background[0].reshape(N_q2, N_q1, N_s, N_p3, N_p2, N_p1) +dist_func = io.readBinaryFile(dist_func_file) + +print (dist_func[0].shape) + +dist_func = dist_func[0].reshape(N_q2, N_q1, N_s, N_p3, N_p2, N_p1) + +time_array = np.loadtxt("dump_time_array.txt") +file_number = -1 + +N = 7 +for index_1 in range(1): + for index_2 in range(N_q2): + + q1_position = index_1 + q2_position = index_2 + + a = np.max((dist_func - dist_func_background)[q2_position, q1_position, :, :]) + b = np.abs(np.min((dist_func - dist_func_background)[q2_position, q1_position, :, :])) + norm_factor = 1.#np.maximum(a, b) + f_at_desired_q = \ + np.reshape((dist_func - \ + dist_func_background)[q2_position, q1_position, :, :],\ + [N_p2, N_p1])/norm_factor + + im = pl.plot(p2, f_at_desired_q) + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.ylabel('$f$') + pl.xlabel('$p_{\\theta}$') + #pl.tight_layout() + pl.savefig('images/dist_func_at_a_point_%d_%d.png'%(index_1, index_2)) + pl.clf() + + np.savetxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2), f_at_desired_q) + f = np.loadtxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2)) + + #f_at_desired_q = np.reshape((dist_func - \ + # dist_func_background)[q1_position, q2_position, :], + # [N_p2, N_p1] + # ) + + #print ("f at desired q : ", dist_func[q1_position, q2_position, :].shape) + print ("norm : ", norm_factor) + + + radius = f.copy() + theta = p2.copy() + + x = (radius + 5.)*np.cos(theta) + y = (radius + 5.)*np.sin(theta) + + x_bg = 5*np.cos(theta) + y_bg = 5*np.sin(theta) + + print ('p2 : ', p2.shape) + #pl.plot(p2, f_at_desired_q) + pl.plot(x, y, color='r', linestyle = '-', lw=3) + pl.plot(x_bg, y_bg, color='k', alpha=0.5, lw=3) + #pl.contourf(p1_meshgrid, p2_meshgrid, f_at_desired_q, 100, cmap='bwr') + + #np.savetxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2), f_at_desired_q) + #f = np.loadtxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2)) + + + #pl.contourf(p_x, p_y, f_at_desired_q, 100, cmap='bwr') + #pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.xlabel('$p_x$') + pl.ylabel('$p_y$') + + pl.xlim([-6.5, 6.5]) + pl.ylim([-6.5, 6.5]) + + pl.gca().set_aspect('equal') + #pl.savefig('images/dist_func_at_a_point_%d_%d.png'%(index_1, index_2)) + pl.clf() + diff --git a/example_problems/electronic_boltzmann/test_compute_moments_cartesian/momentum_space_movie_zero_T.py b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/momentum_space_movie_zero_T.py new file mode 100644 index 00000000..0dae45a6 --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/momentum_space_movie_zero_T.py @@ -0,0 +1,183 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import os +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +#import yt +#yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain +import params + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_s = len(params.mass) # Number of species + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1_start = domain.q1_start +q1_end = domain.q1_end +q2_start = domain.q2_start +q2_end = domain.q2_end + +q1 = q1_start + (0.5 + np.arange(N_q1)) * (q1_end - q1_start)/N_q1 +q2 = q2_start + (0.5 + np.arange(N_q2)) * (q2_end - q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 +N_p3 = domain.N_p3 + +p1_start = domain.p1_start +p1_end = domain.p1_end +p2_start = domain.p2_start +p2_end = domain.p2_end + +p1 = p1_start[0] + (0.5 + np.arange(N_p1)) * (p1_end[0] - p1_start[0])/N_p1 +p2 = p2_start[0] + (0.5 + np.arange(N_p2)) * (p2_end[0] - p2_start[0])/N_p2 + +p1_meshgrid, p2_meshgrid = np.meshgrid(p1, p2) + +p_x = p1_meshgrid * np.cos(p2_meshgrid) +p_y = p1_meshgrid * np.sin(p2_meshgrid) + +#p2_meshgrid, p1_meshgrid = np.meshgrid(p2, p1) + +io = PetscBinaryIO.PetscBinaryIO() + +filepath = os.getcwd() +moment_files = np.sort(glob.glob(filepath+'/dump_moments/*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/dump_lagrange_multipliers/*.bin')) +dist_func_files = np.sort(glob.glob(filepath+'/dump_f/*.bin')) + +#moment_files = np.sort(glob.glob(filepath+'/dumps/moments*.bin')) +#lagrange_multiplier_files = \ +# np.sort(glob.glob(filepath+'/dumps/lagrange_multipliers*.bin')) +#dist_func_files = np.sort(glob.glob(filepath+'/dumps/f*.bin')) + +dist_func_bg_file = dist_func_files[0] +dist_func_file = dist_func_files[-1] + +print(dist_func_bg_file) +print(dist_func_file) + +dist_func_background = io.readBinaryFile(dist_func_bg_file) +#dist_func_background = dist_func_background[0].reshape(N_q2, N_q1, N_p2, N_p1) +dist_func_background = dist_func_background[0].reshape(N_q2, N_q1, N_s, N_p3, N_p2, N_p1) +dist_func = io.readBinaryFile(dist_func_file) + +print (dist_func[0].shape) + +dist_func = dist_func[0].reshape(N_q2, N_q1, N_s, N_p3, N_p2, N_p1) +dist_func_background = np.mean(dist_func) + +time_array = np.loadtxt("dump_time_array.txt") +file_number = -1 + +N = 7 +for index_1 in range(N): + for index_2 in range(N): + + q1_position = int(N_q1*((index_1/N)+(1/(2*N)))) + q2_position = int(N_q2*((index_2/N)+(1/(2*N)))) + + a = np.max((dist_func - dist_func_background)[q2_position, q1_position, :, :]) + b = np.abs(np.min((dist_func - dist_func_background)[q2_position, q1_position, :, :])) + norm_factor = np.maximum(a, b) + f_at_desired_q = \ + np.reshape((dist_func-\ + dist_func_background)[q2_position, q1_position, :, :],\ + [N_p2, N_p1])/norm_factor + + im = pl.plot(p2, f_at_desired_q) + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.ylabel('$f$') + pl.xlabel('$p_{\\theta}$') + #pl.tight_layout() + #pl.savefig('images/dist_func_at_a_point_%d_%d.png'%(index_1, index_2)) + pl.clf() + + np.savetxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2), f_at_desired_q) + f = np.loadtxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2)) + + #f_at_desired_q = np.reshape((dist_func - \ + # dist_func_background)[q1_position, q2_position, :], + # [N_p2, N_p1] + # ) + + #print ("f at desired q : ", dist_func[q1_position, q2_position, :].shape) + print ("norm : ", norm_factor) + + + radius = f.copy() + theta = p2.copy() + + x = (radius + 5.)*np.cos(theta) + y = (radius + 5.)*np.sin(theta) + + x_bg = 5*np.cos(theta) + y_bg = 5*np.sin(theta) + + print ('p2 : ', p2.shape) + #pl.plot(p2, f_at_desired_q) + pl.plot(x, y, color='r', linestyle = '-', lw=3) + pl.plot(x_bg, y_bg, color='k', alpha=0.5, lw=3) + #pl.contourf(p1_meshgrid, p2_meshgrid, f_at_desired_q, 100, cmap='bwr') + + #np.savetxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2), f_at_desired_q) + #f = np.loadtxt('data/f_vs_theta_%d_%d.txt'%(index_1, index_2)) + + + #pl.contourf(p_x, p_y, f_at_desired_q, 100, cmap='bwr') + #pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.xlabel('$p_x$') + pl.ylabel('$p_y$') + + pl.xlim([-6.5, 6.5]) + pl.ylim([-6.5, 6.5]) + + pl.gca().set_aspect('equal') + pl.savefig('images/dist_func_at_a_point_%d_%d.png'%(index_1, index_2)) + pl.clf() + diff --git a/example_problems/electronic_boltzmann/test_compute_moments_cartesian/movie.py b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/movie.py new file mode 100644 index 00000000..e335f680 --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/movie.py @@ -0,0 +1,169 @@ +#import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import os +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +#import yt +#yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain +#import boundary_conditions +#import params +#import initialize + + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 12, 7.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 + +p1 = domain.p1_start[0] + (0.5 + np.arange(N_p1)) * (domain.p1_end[0] - \ + domain.p1_start[0])/N_p1 +p2 = domain.p2_start[0] + (0.5 + np.arange(N_p2)) * (domain.p2_end[0] - \ + domain.p2_start[0])/N_p2 + + +filepath = os.getcwd() +moment_files = np.sort(glob.glob(filepath+'/dump_moments/*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/dump_lagrange_multipliers/*.bin')) + +print ("moment files : ", moment_files.size) +print ("lagrange multiplier files : ", lagrange_multiplier_files.size) + + +time_array = np.loadtxt("dump_time_array.txt") + +io = PetscBinaryIO.PetscBinaryIO() + +for file_number, dump_file in enumerate(moment_files[::-1]): + + file_number = -1 + print("file number = ", file_number, "of ", moment_files.size) + + moments = io.readBinaryFile(moment_files[file_number]) + moments = moments[0].reshape(N_q2, N_q1, 3) + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + + lagrange_multipliers = \ + io.readBinaryFile(lagrange_multiplier_files[file_number]) + lagrange_multipliers = lagrange_multipliers[0].reshape(N_q2, N_q1, 5) + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + + #print (j_x.shape, vel_drift_x.shape, density.shape) + + pl.subplot(221) + pl.contourf(q1_meshgrid, q2_meshgrid, density.T, 100, cmap='bwr') + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.streamplot(q1, q2, + vel_drift_x, vel_drift_y, + density=2, color='k', + linewidth=0.7, arrowsize=1 + ) + + pl.xlim([q1[0], q1[-1]]) + pl.ylim([q2[0], q2[-1]]) + + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + pl.ylabel(r'$y\;(\mu \mathrm{m})$') + #pl.colorbar() + + pl.subplot(222) + pl.contourf(q1_meshgrid, q2_meshgrid, density.T, 100, cmap='bwr') + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + pl.streamplot(q1, q2, + j_x, j_y, + density=2, color='k', + linewidth=0.7, arrowsize=1 + ) + + pl.xlim([q1[0], q1[-1]]) + pl.ylim([q2[0], q2[-1]]) + + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + #pl.ylabel(r'$y\;(\mu \mathrm{m})$') + #pl.colorbar() + + pl.subplot(223) + pl.contourf(q1_meshgrid, q2_meshgrid, (j_x - density*vel_drift_x).T, 100, cmap='bwr') + + pl.xlim([q1[0], q1[-1]]) + pl.ylim([q2[0], q2[-1]]) + + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + pl.ylabel(r'$y\;(\mu \mathrm{m})$') + pl.colorbar() + + pl.subplot(224) + pl.contourf(q1_meshgrid, q2_meshgrid, (j_y - density*vel_drift_y).T, 100, cmap='bwr') + + pl.xlim([q1[0], q1[-1]]) + pl.ylim([q2[0], q2[-1]]) + + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + #pl.ylabel(r'$y\;(\mu \mathrm{m})$') + pl.colorbar() + + #pl.tight_layout() + pl.suptitle('$\\tau_\mathrm{mc} = \infty$, $\\tau_\mathrm{mr} = \infty$') + pl.savefig('images/dump_' + '%06d'%file_number + '.png') + pl.clf() + diff --git a/example_problems/electronic_boltzmann/test_compute_moments_cartesian/params.py b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/params.py new file mode 100644 index 00000000..bab1fba5 --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/params.py @@ -0,0 +1,279 @@ +import numpy as np +import arrayfire as af + +from bolt.src.electronic_boltzmann.utils.polygon import polygon +from bolt.src.electronic_boltzmann.utils.unit_vectors import normal_to_hexagon_unit_vec + +instantaneous_collisions = False #TODO : Remove from lib +hybrid_model_enabled = False #TODO : Remove from lib +source_enabled = True +disable_collision_op = False + +fields_enabled = False +# Can be defined as 'electrostatic', 'user-defined'. +# The initial conditions need to be specified under initialize +# Ensure that the initial conditions specified satisfy +# Maxwell's constraint equations +fields_initialize = 'user-defined' + +# Can be defined as 'electrostatic' and 'fdtd' +# To turn feedback from Electric fields on, set fields_solver = 'LCA' +# and set charge_electron +fields_type = 'electrostatic' +fields_solver = 'SNES' + +# Can be defined as 'strang' and 'lie' +time_splitting = 'strang' + +# Method in q-space +solver_method_in_q = 'FVM' +solver_method_in_p = 'FVM' + +reconstruction_method_in_q = 'minmod' +reconstruction_method_in_p = 'minmod' + +riemann_solver_in_q = 'upwind-flux' +riemann_solver_in_p = 'upwind-flux' + +electrostatic_solver_every_nth_step = 1000000 + + +# Time parameters: +dt = 0.025/4 # ps +t_final = 25. # ps + + +# File-writing Parameters: +dump_steps = 5 +dump_dist_after = 1600 +# Set to zero for no file-writing +dt_dump_f = 1000*dt #ps +# ALWAYS set dump moments and dump fields at same frequency: +dt_dump_moments = dt_dump_fields = 5*dt #ps + + +# Dimensionality considered in velocity space: +p_dim = 2 +p_space_grid = 'cartesian' # Supports 'cartesian' or 'polar2D' grids +# Set p-space start and end points accordingly in domain.py +#TODO : Use only polar2D for PdCoO2 + + +zero_temperature = (p_dim==1) +dispersion = 'linear' # 'linear' or 'quadratic' +fermi_surface_shape = 'circle' # Supports 'circle' or 'hexagon' + + +# Number of devices(GPUs/Accelerators) on each node: +num_devices = 6 + +# Constants: +mass_particle = 0.910938356 # x 1e-30 kg +h_bar = 1.0545718e-4 # x aJ ps +boltzmann_constant = 1 +charge = [0.*-0.160217662] # x aC +mass = [0.] #TODO : Not used in electronic_boltzmann + # Remove from lib +speed_of_light = 300. # x [um/ps] +fermi_velocity = speed_of_light/300 +epsilon0 = 8.854187817 # x [aC^2 / (aJ um) ] + +epsilon_relative = 3.9 # SiO2 +backgate_potential = -10 # V +global_chem_potential = 0.03 +contact_start = 0.0 # um +contact_end = 0.25 # um +contact_geometry = "straight" # Contacts on either side of the device + # For contacts on the same side, use + # contact_geometry = "turn_around" + +initial_temperature = 1e-3#12e-5 +initial_mu = 0.015 +vel_drift_x_in = 1e-4*fermi_velocity +vel_drift_x_out = 1e-4*fermi_velocity +AC_freq = 1./100 # ps^-1 + +B3_mean = 1. # T + +# Spatial quantities (will be initialized to shape = [q1, q2] in initalize.py) +mu = None # chemical potential used in the e-ph operator +T = None # Electron temperature used in the e-ph operator +mu_ee = None # chemical potential used in the e-e operator +T_ee = None # Electron temperature used in the e-e operator +vel_drift_x = None +vel_drift_y = None +phi = None # Electric potential in the plane of graphene sheet +p_x = None +p_y = None +#integral_measure = None + +# Momentum quantities (will be initialized to shape = [p1*p2*p3] in initialize.py) +E_band = None +vel_band = None + +collision_operator_nonlinear_iters = 2 + +# Variation of collisional-timescale parameter through phase space: +@af.broadcast +def tau_defect(q1, q2, p1, p2, p3): + return(np.inf * q1**0 * p1**0) + +@af.broadcast +def tau_ee(q1, q2, p1, p2, p3): + return(np.inf * q1**0 * p1**0) + +def tau(q1, q2, p1, p2, p3): + return(tau_defect(q1, q2, p1, p2, p3)) + + +def fermi_momentum_magnitude(theta): + if (fermi_surface_shape == 'circle'): + p_f = initial_mu/fermi_velocity # Fermi momentum + + elif (fermi_surface_shape == 'hexagon'): + n = 6 # No. of sides of polygon + p_f = (initial_mu/fermi_velocity) * polygon(n, theta, rotation = np.pi/6) + # Note : Rotation by pi/6 results in a hexagon with horizontal top & bottom edges + #TODO : If cartesian coordinates are being used, convert to polar to calculate p_f + else : + raise NotImplementedError('Unsupported shape of fermi surface') + return(p_f) + + +def band_energy(p1, p2): + # Note :This function is only meant to be called once to initialize E_band + + if (p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (p_space_grid == 'polar2D'): + # In polar2D coordinates, p1 = radius and p2 = theta + r = p1 + theta = p2 + p_x = r * af.cos(theta) + p_y = r * af.sin(theta) + else : + raise NotImplementedError('Unsupported coordinate system in p_space') + + p = af.sqrt(p_x**2. + p_y**2.) + if (dispersion == 'linear'): + + E_upper = p*fermi_velocity + + elif (dispersion == 'quadratic'): + + m = effective_mass(p1, p2) + E_upper = p**2/(2.*m) + + if (zero_temperature): + + E_upper = initial_mu * p**0. + + af.eval(E_upper) + return(E_upper) + + +def effective_mass(p1, p2): + + if (p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + + theta = af.atan(p_y/p_x) + + elif (p_space_grid == 'polar2D'): + # In polar2D coordinates, p1 = radius and p2 = theta + r = p1; theta = p2 + else : + raise NotImplementedError('Unsupported coordinate system in p_space') + + if (fermi_surface_shape == 'hexagon'): + + n = 6 # No. of side of polygon + mass = mass_particle * polygon(n, theta, rotation = np.pi/6) + # Note : Rotation by pi/6 results in a hexagon with horizontal top & bottom edges + + elif (fermi_surface_shape == 'circle'): + + # For now, just return the free electron mass + mass = mass_particle + + return(mass) + +def band_velocity(p1, p2): + # Note :This function is only meant to be called once to initialize the vel vectors + + if (p_space_grid == 'cartesian'): + p_x_local = p1 + p_y_local = p2 + + theta = af.atan(p_y_local/p_x_local) + + elif (p_space_grid == 'polar2D'): + # In polar2D coordinates, p1 = radius and p2 = theta + r = p1; theta = p2 + else : + raise NotImplementedError('Unsupported coordinate system in p_space') + + p = af.sqrt(p_x**2. + p_y**2.) + p_hat = [p_x / (p + 1e-20), p_y / (p + 1e-20)] + + if (fermi_surface_shape == 'circle'): + + v_f_hat = p_hat + + elif (fermi_surface_shape == 'hexagon'): + + v_f_hat = normal_to_hexagon_unit_vec(theta) + + # Quadratic dispersion + m = effective_mass(p1, p2) + v_f = p/m + + if (dispersion == 'linear' or zero_temperature): + + v_f = fermi_velocity + + upper_band_velocity = [v_f * v_f_hat[0], v_f * v_f_hat[1]] + + return(upper_band_velocity) + +def get_p_x_and_p_y(p1, p2): + + if (p_space_grid == 'cartesian'): + p_x = p1 + p_y = p2 + elif (p_space_grid == 'polar2D'): + # In polar2D coordinates, p1 = radius and p2 = theta + r = p1; theta = p2 + + if (zero_temperature): + # Get p_x and p_y at the Fermi surface + r = fermi_momentum_magnitude(theta) + + p_x = r * af.cos(theta) + p_y = r * af.sin(theta) + + else : + raise NotImplementedError('Unsupported coordinate system in p_space') + + return([p_x, p_y]) + +# Restart(Set to zero for no-restart): +latest_restart = True +t_restart = 0 + +@af.broadcast +def fermi_dirac(mu, E_band): + + k = boltzmann_constant + T = initial_temperature + + f = (1./(af.exp( (E_band - mu + )/(k*T) + ) + 1. + ) + ) + + af.eval(f) + return(f) diff --git a/example_problems/electronic_boltzmann/test_compute_moments_cartesian/petsc_conf.py b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/petsc_conf.py new file mode 100755 index 00000000..22781ed2 --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/petsc_conf.py @@ -0,0 +1,73 @@ +import warnings + +def get_conf(): + """Parses various PETSc configuration/include files to get data types. + + precision, indices, complexscalars = get_conf() + + Output: + precision: 'single', 'double', 'longlong' indicates precision of PetscScalar + indices: '32', '64' indicates bit-size of PetscInt + complex: True/False indicates whether PetscScalar is complex or not. + """ + + import sys, os + precision = None + indices = None + complexscalars = None + + if 'PETSC_DIR' in os.environ: + petscdir = os.environ['PETSC_DIR'] + else: + warnings.warn('PETSC_DIR env not set - unable to locate PETSc installation, using defaults') + return None, None, None + + if os.path.isfile(os.path.join(petscdir,'lib','petsc','conf','petscrules')): + # found prefix install + petscvariables = os.path.join(petscdir,'lib','petsc','conf','petscvariables') + petscconfinclude = os.path.join(petscdir,'include','petscconf.h') + else: + if 'PETSC_ARCH' in os.environ: + petscarch = os.environ['PETSC_ARCH'] + if os.path.isfile(os.path.join(petscdir,petscarch,'lib','petsc','conf','petscrules')): + # found legacy install + petscvariables = os.path.join(petscdir,petscarch,'lib','petsc','conf','petscvariables') + petscconfinclude = os.path.join(petscdir,petscarch,'include','petscconf.h') + else: + warnings.warn('Unable to locate PETSc installation in specified PETSC_DIR/PETSC_ARCH, using defaults') + return None, None, None + else: + warnings.warn('PETSC_ARCH env not set or incorrect PETSC_DIR is given - unable to locate PETSc installation, using defaults') + return None, None, None + + try: + fid = open(petscvariables, 'r') + except IOError: + warnings.warn('Nonexistent or invalid PETSc installation, using defaults') + return None, None, None + else: + for line in fid: + if line.startswith('PETSC_PRECISION'): + precision = line.strip().split('=')[1].strip('\n').strip() + + fid.close() + + try: + fid = open(petscconfinclude, 'r') + except IOError: + warnings.warn('Nonexistent or invalid PETSc installation, using defaults') + return None, None, None + else: + for line in fid: + if line.startswith('#define PETSC_USE_64BIT_INDICES 1'): + indices = '64bit' + elif line.startswith('#define PETSC_USE_COMPLEX 1'): + complexscalars = True + + if indices is None: + indices = '32bit' + if complexscalars is None: + complexscalars = False + fid.close() + + return precision, indices, complexscalars diff --git a/example_problems/electronic_boltzmann/test_compute_moments_cartesian/phase_vs_y.py b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/phase_vs_y.py new file mode 100644 index 00000000..fc6ac364 --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/phase_vs_y.py @@ -0,0 +1,180 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +from scipy.optimize import curve_fit +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 12, 7.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +def sin_curve_fit(t, A, tau): + return A*np.sin(2*np.pi*AC_freq*(t + tau )) + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +# Left needs to be near source, right sensor near drain +sensor_1_left_start = 5.5 # um +sensor_1_left_end = 10.0 # um + +sensor_1_right_start = 5.5 # um +sensor_1_right_end = 10.0 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +filepath = \ + '/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_2.5_tau_ee_inf_tau_eph_2.5/dumps' + +AC_freq = 1./100.0 +time_period = 1/AC_freq +t_final = params.t_final +transient_time = t_final/2. + +time = np.loadtxt(filepath + "/../dump_time_array.txt") +edge_density = np.loadtxt(filepath + "/../edge_density.txt") +q2 = np.loadtxt(filepath + "/../q2_edge.txt") + +N_spatial = edge_density.shape[1] + +transient_index = int((transient_time/t_final)*time.size) + +drive = np.sin(2*np.pi*AC_freq*time) +nsamples = drive.size +dt_corr = np.linspace(-time[-1] + time[0],\ + time[-1] - time[0], 2*nsamples-1) + +# Discarding transients +q = q2.size/2 +time_half = time[transient_index:] +drive_half = drive[transient_index:] + +# Plotting signals at edge +norm_0 = np.max(edge_density[transient_index:, 0]) +norm_1 = np.max(edge_density[transient_index:, -1]) + +pl.plot(time, drive, color='black', linestyle='--') +pl.ylim([-1.1, 1.1]) +pl.xlim([0,200]) +pl.xlabel('$\mathrm{Time\;(s)}$') + +for i in range(N_spatial): + norm_i = np.max(edge_density[transient_index:, i]) + pl.plot(time, edge_density[:, i]/norm_i) + +pl.savefig('images/signals.png') +pl.clf() + +phase_shift_corr_array = [] +phase_shift_fitting_array = []\ + +for i in range(N_spatial): + print ('index : ', i) + signal_1 = edge_density[:, i] + norm_1 = np.max(signal_1[transient_index:]) + signal_1_normalized = signal_1/norm_1 + + # Calculate phase_shifts using scipy.correlate + corr = correlate(drive, signal_1_normalized) + time_shift_corr = dt_corr[corr.argmax()] + phase_shift_corr = 2*np.pi*(((0.5 + time_shift_corr/time_period) % 1.0) - 0.5) + + # Calculate phase_shifts using scipy.curve_fit + popt, pcov = curve_fit(sin_curve_fit, time[transient_index:],\ + signal_1_normalized[transient_index:]) + time_shift_fitting = popt[1]%(time_period/2.0) + phase_shift_fitting = 2*np.pi*(((0.5 + time_shift_fitting/time_period) % 1.0) - 0.5) + + phase_shift_corr_array.append(phase_shift_corr) + phase_shift_fitting_array.append(phase_shift_fitting) + +phase_shift_corr_array = np.array(phase_shift_corr_array) +phase_shift_fitting_array = np.array(phase_shift_fitting_array) + +# Plot +pl.ylabel('$\mathrm{\phi}$') +pl.xlabel('$\mathrm{y\ \mu m}$') + +pl.plot(q2, phase_shift_corr_array, '-o', label='$\mathrm{corr}$') +pl.plot(q2, phase_shift_fitting_array, '-o', label='$\mathrm{fit}$') + +pl.title('$\mathrm{2.5 \\times 10,\ \\tau_{ee} = \infty,\ \\tau_{eph} = 2.5}$') +pl.legend(loc='best') + +#pl.axvspan(sensor_1_left_start, sensor_1_left_end, color = 'k', alpha = 0.1) +#pl.axvspan(sensor_2_left_start, sensor_2_left_end, color = 'k', alpha = 0.1) + +pl.savefig('images/phase_vs_y.png') +pl.clf() + diff --git a/example_problems/electronic_boltzmann/test_compute_moments_cartesian/post.py b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/post.py new file mode 100644 index 00000000..a297c6f0 --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/post.py @@ -0,0 +1,422 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +#pl.rcParams['figure.figsize'] = 8, 7.5 +pl.rcParams['figure.figsize'] = 8, 8 +#pl.rcParams['figure.figsize'] = 17, 9.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +#pl.rcParams['lines.linewidth'] = 3 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 +#N_q1 = 120 +#N_q2 = 240 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +#source_start = 3.5; source_end = 4.5 +#drain_start = 5.5; drain_end = 6.5 + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +sensor_1_left_start = 8.5 # um +sensor_1_left_end = 9.5 # um + +sensor_1_right_start = 8.5 # um +sensor_1_right_end = 9.5 # um + +# Left needs to be near source, right sensor near drain +#sensor_1_left_start = 1.5 # um +#sensor_1_left_end = 2.5 # um + +#sensor_1_right_start = 7.5 # um +#sensor_1_right_end = 8.5 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +sensor_2_left_start = 6.5 # um +sensor_2_left_end = 7.5 # um + +sensor_2_right_start = 6.5 # um +sensor_2_right_end = 7.5 # um + +sensor_2_left_indices = (q2 > sensor_2_left_start ) & (q2 < sensor_2_left_end) +sensor_2_right_indices = (q2 > sensor_2_right_start) & (q2 < sensor_2_right_end) + +#dump_index = 0 +#h5f = h5py.File('dumps/moments_' + '%06d'%(dump_index) + '.h5', 'r') +#moments = np.swapaxes(h5f['moments'][:], 0, 1) +#h5f.close() +# +#density = moments[:, :, 0] +#j_x = moments[:, :, 1] +#j_y = moments[:, :, 2] +#pl.contourf(q1, q2, density, 100) +##pl.title('Time = ' + "%.2f"%(t0)) +#pl.axes().set_aspect('equal') +#pl.xlabel(r'$x$') +#pl.ylabel(r'$y$') +#pl.colorbar() +#pl.savefig('images/density' + '.png') +#pl.clf() +# +#h5f = h5py.File('dumps/lagrange_multipliers_' + '%06d'%(dump_index) + '.h5', 'r') +#lagrange_multipliers = np.swapaxes(h5f['lagrange_multipliers'][:], 0, 1) +#h5f.close() +# +#print("lagrange_multipliers.shape = ", lagrange_multipliers.shape) +#mu = lagrange_multipliers[:, :, 0] +#mu_ee = lagrange_multipliers[:, :, 1] +#T_ee = lagrange_multipliers[:, :, 2] +#vel_drift_x = lagrange_multipliers[:, :, 3] +#vel_drift_y = lagrange_multipliers[:, :, 4] +#j_x_prime = density*vel_drift_x +#print("err = ", np.mean(np.abs(j_x_prime - j_x))) + +#filepath = \ +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/geom_1/DC/tau_D_50_tau_ee_0.2' +#dump_file= np.sort(glob.glob(filepath+'/moment*.h5'))[-1] +# +#h5f = h5py.File(dump_file, 'r') +#moments = np.swapaxes(h5f['moments'][:], 0, 1) +#h5f.close() +# +#density = moments[:, :, 0] +#np.savetxt('paper_plots/density_tau_D_50_tau_ee_0.2.txt', density) +#np.savetxt('paper_plots/q2_DC_tau_D_50_tau_ee_0.2.txt', q2) +##pl.plot(q2[q2>source_end], density[0, q2>source_end]-np.mean(density)) +# +#filepath = \ +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/geom_1/DC/tau_D_5_tau_ee_0.2' +#dump_file= np.sort(glob.glob(filepath+'/moment*.h5'))[-1] +# +# +#h5f = h5py.File(dump_file, 'r') +#moments = np.swapaxes(h5f['moments'][:], 0, 1) +#h5f.close() +# +#density = moments[:, :, 0] +#np.savetxt('paper_plots/density_tau_D_5_tau_ee_0.2.txt', density) +#np.savetxt('paper_plots/q2_DC_tau_D_5_tau_ee_0.2.txt', q2) +# +#filepath = \ +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/geom_1/DC/tau_D_10_tau_ee_0.2' +#dump_file= np.sort(glob.glob(filepath+'/moment*.h5'))[-1] +# +#N_q1 = 120 +#N_q2 = 240 +# +#q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +#q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 +# +#h5f = h5py.File(dump_file, 'r') +#moments = np.swapaxes(h5f['moments'][:], 0, 1) +#h5f.close() +# +#density = moments[:, :, 0] +#np.savetxt('paper_plots/density_tau_D_10_tau_ee_0.2.txt', density) +#np.savetxt('paper_plots/q2_DC_tau_D_10_tau_ee_0.2.txt', q2) + + +#pl.plot(q2[q2>source_end], density[0, q2>source_end]-np.mean(density)) +#pl.axhline(0, color='black', linestyle='--') +#pl.legend(['$\\tau_{ee}=0.2$ ps, $\\tau_{e-ph}=50$ ps', +# '$\\tau_{ee}=0.2$ ps, $\\tau_{e-ph}=10$ ps'], loc='lower right') +#pl.xlabel(r'$x\;(\mu \mathrm{m})$') +#pl.ylabel(r'$R\; (\mathrm{a.u.})$') +#pl.xlim(xmin=(source_end+0.1)) +#pl.savefig('paper_plots/DC.png') + +filepath = \ +'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/dumps_tau_D_1_tau_ee_0.2_movie' +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/geom_1/55_GHz/tau_D_5_tau_ee_0.2' +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/dumps_AC_10_Ghz_tau_D_10_tau_ee_1_geom_2/' +#'/home/mchandra/bolt/example_problems/electronic_boltzmann/graphene/dumps_tau_D_2_tau_ee_1_AC/' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +sensor_1_signal_array = [] +print("Reading sensor signal...") +for file_number, dump_file in enumerate(moment_files): + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + density = moments[:, :, 0] + + source = np.mean(density[0, source_indices]) + drain = np.mean(density[-1, drain_indices]) + + sensor_1_left = np.mean(density[0, sensor_1_left_indices] ) + sensor_1_right = np.mean(density[-1, sensor_1_right_indices]) + + sensor_1_signal = sensor_1_left - sensor_1_right + + sensor_1_signal_array.append(sensor_1_signal) + +time_array = np.loadtxt("dump_time_array.txt") +AC_freq = 1./100 +input_signal_array = np.sin(2.*np.pi*AC_freq*time_array) +sensor_1_signal_array = np.array(sensor_1_signal_array) +half_time = (int)(time_array.size/2) +sensor_normalized = \ + sensor_1_signal_array/np.max(np.abs(sensor_1_signal_array[half_time:])) + +pl.rcParams['figure.figsize'] = 10, 8 +for file_number, dump_file in yt.parallel_objects(enumerate(moment_files)): + + print("file number = ", file_number, "of ", moment_files.size) + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + gs = gridspec.GridSpec(3, 2) + pl.subplot(gs[:, 0]) + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + pl.contourf(q1_meshgrid, q2_meshgrid, density, 100, cmap='bwr') + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + #pl.colorbar() + + h5f = h5py.File(lagrange_multiplier_files[file_number], 'r') + lagrange_multipliers = h5f['lagrange_multipliers'][:] + h5f.close() + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + +# pl.streamplot(q1[(int)(N_q1/2):], q2, +# vel_drift_x[:, (int)(N_q1/2):], vel_drift_y[:, (int)(N_q1/2):], +# density=2, color='blue', +# linewidth=0.7, arrowsize=1 +# ) + pl.streamplot(q1, q2, + vel_drift_x, vel_drift_y, + density=2, color='blue', + linewidth=0.7, arrowsize=1 + ) +# pl.streamplot(q1, q2, +# vel_drift_x, vel_drift_y, +# density=3, color='blue', +# linewidth=0.8, arrowsize=1.1 +# ) + pl.xlim([domain.q1_start, domain.q1_end]) + pl.ylim([domain.q2_start, domain.q2_end]) + #pl.ylim([0, 5]) + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + pl.ylabel(r'$y\;(\mu \mathrm{m})$') + + pl.gca().annotate("+", xy=(-0.07, .9), xycoords=("axes fraction"), + ha="center", va="center", size=30, + bbox=dict(fc="white")) + pl.gca().annotate("-", xy=(1.05, .9), xycoords=("axes fraction"), + ha="center", va="center", size=30, + bbox=dict(fc="white", pad=6.5)) + + + pl.subplot(gs[1, 1]) + + pl.plot(time_array, input_signal_array) + pl.plot(time_array, sensor_normalized) + pl.axhline(0, color='black', linestyle='--') + pl.axvline(time_array[file_number], color='black', alpha=0.75) + pl.legend(['Source $I(t)$', 'Measured $V(t)$'], loc=(0.04, 1.125)) + pl.xlabel(r'Time (ps)') + pl.xlim([100, 200]) + pl.ylim([-1.1, 1.1]) + + + pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 1$ ps') + #pl.tight_layout() + pl.savefig('images/dump_' + '%06d'%file_number + '.png') + #pl.savefig('paper_plots/DC.png') + pl.clf() + + +#time_array = [] +#input_signal_array = [] +#sensor_1_signal_array = [] +#sensor_2_signal_array = [] +#for file_number, dump_file in enumerate(moment_files): +# +# print("file number = ", file_number, "of ", moment_files.size) +# +# h5f = h5py.File(dump_file, 'r') +# moments = np.swapaxes(h5f['moments'][:], 0, 1) +# h5f.close() +# +# density = moments[:, :, 0] +# +# source = np.mean(density[0, source_indices]) +# drain = np.mean(density[-1, drain_indices]) +# +# sensor_1_left = np.mean(density[0, sensor_1_left_indices] ) +# sensor_1_right = np.mean(density[-1, sensor_1_right_indices]) +# #sensor_1_right = np.mean(density[0, sensor_1_right_indices]) +# +# sensor_2_left = np.mean(density[0, sensor_2_left_indices] ) +# sensor_2_right = np.mean(density[-1, sensor_2_right_indices]) +# +# #sensor_1_left = density[0, q2>source_end] +# #sensor_1_right = density[-1, q2>source_end] +# +# input_signal = source - drain +# sensor_1_signal = sensor_1_left - sensor_1_right +# sensor_2_signal = sensor_2_left - sensor_2_right +# +# time_array.append(file_number*dt*dump_interval) +# input_signal_array.append(input_signal) +# sensor_1_signal_array.append(sensor_1_signal) +# sensor_2_signal_array.append(sensor_2_signal) +# +##pl.rcParams['figure.figsize'] = 12, 8 +## +#AC_freq = 5.5/100 +#time_array = np.array(time_array) +#input_signal_array = np.sin(2.*np.pi*AC_freq*time_array) +#sensor_1_signal_array = np.array(sensor_1_signal_array) +###np.savetxt('drive.txt', input_signal_array) +##np.savetxt('paper_plots/sensor_tau_ee_0.2_tau_D_5.txt', sensor_1_signal_array) +##np.savetxt('time.txt', time_array) +## +##print("sensor.shape = ", sensor_1_signal_array.shape) +##sensor_2_signal_array = np.array(sensor_2_signal_array) +## +#half_time = (int)(time_array.size/2) +#pl.plot(time_array, input_signal_array/np.max(input_signal_array[half_time:])) +#pl.plot(time_array, +# sensor_1_signal_array/np.max(sensor_1_signal_array[half_time:]) +# ) +##pl.plot(time_array, +## sensor_2_signal_array/np.max(sensor_2_signal_array[half_time:]) +## ) +#pl.xlabel(r"Time (ps)") +#pl.ylim([-1.1, 1.1]) +#pl.legend(['Input', 'Sensor 1', 'Sensor 2']) +#pl.savefig('paper_plots/IV_55_Ghz_tau_ee_0.2_tau_D_5.png') +##half_time = 0 +#input_normalized = input_signal_array[half_time:]/np.max(input_signal_array[half_time:]) +#sensor_normalized = sensor_1_signal_array[half_time:]/np.max(sensor_1_signal_array[half_time:]) +# +## Calculate the phase diff. Copied from: +## https://stackoverflow.com/questions/6157791/find-phase-difference-between-two-inharmonic-waves +#corr = correlate(input_normalized, sensor_normalized) +#nsamples = input_normalized.size +#time_corr = time_array[half_time:] +#dt_corr = np.linspace(-time_corr[-1] + time_corr[0], +# time_corr[-1] - time_corr[0], 2*nsamples-1) +#time_shift = dt_corr[corr.argmax()] +# +## force the phase shift to be in [-pi:pi] +#period = 1./AC_freq +#phase_diff = 2*np.pi*(((0.5 + time_shift/period) % 1.0) - 0.5) +#print("density.shape = ", density.shape) +#print("Phase diff = ", phase_diff) + +#phase_vs_x = [] +#for i in range(sensor_1_signal_array[0, :].size): +# signal = sensor_1_signal_array[:, i] +# corr = correlate(input_signal_array, signal) +# nsamples = input_signal_array.size +# half_time = 0 +# time_corr = time_array[half_time:] +# dt_corr = np.linspace(-time_corr[-1] + time_corr[0], +# time_corr[-1] - time_corr[0], +# 2*nsamples-1 +# ) +# time_shift = dt_corr[corr.argmax()] +# +# # force the phase shift to be in [-pi:pi] +# period = 1./params.AC_freq +# phase_diff = 2*np.pi*(((0.5 + time_shift/period) % 1.0) - 0.5) +# phase_vs_x.append(phase_diff) +# +#phase_vs_x = np.array(phase_vs_x) +#print("phase_vs_x.shape = ", phase_vs_x.shape) +#np.savetxt("paper_plots/phase_vs_x_tau_ee_0.2_tau_D_1.txt", phase_vs_x) +#np.savetxt("paper_plots/q2_tau_ee_0.2_tau_D_1.txt", q2) +#print("density.shape = ", density.shape) + + diff --git a/example_problems/electronic_boltzmann/test_compute_moments_cartesian/signals.py b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/signals.py new file mode 100644 index 00000000..979640c3 --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/signals.py @@ -0,0 +1,166 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +#import yt +#yt.enable_parallelism() +import os + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +import PetscBinaryIO + +import domain +import boundary_conditions +import params +import initialize + + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +source_start = params.contact_start +source_end = params.contact_end + +drain_start = params.contact_start +drain_end = params.contact_end + +source_indices = (q2 > source_start) & (q2 < source_end) +drain_indices = (q2 > drain_start) & (q2 < drain_end ) + +# Left needs to be near source, right sensor near drain +sensor_1_left_start = 8.5 # um +sensor_1_left_end = 9.5 # um + +sensor_1_right_start = 8.5 # um +sensor_1_right_end = 9.5 # um + +sensor_1_left_indices = (q2 > sensor_1_left_start ) & (q2 < sensor_1_left_end) +sensor_1_right_indices = (q2 > sensor_1_right_start) & (q2 < sensor_1_right_end) + +sensor_2_left_start = 6.5 # um +sensor_2_left_end = 7.5 # um + +sensor_2_right_start = 6.5 # um +sensor_2_right_end = 7.5 # um + +sensor_2_left_indices = (q2 > sensor_2_left_start ) & (q2 < sensor_2_left_end) +sensor_2_right_indices = (q2 > sensor_2_right_start) & (q2 < sensor_2_right_end) + +io = PetscBinaryIO.PetscBinaryIO() + +filepath = os.getcwd() +#filepath = '/home/mchandra/gitansh/zero_T/example_problems/electronic_boltzmann/graphene/L_1.0_1.25_tau_ee_inf_tau_eph_inf_DC' +moment_files = np.sort(glob.glob(filepath+'/dump_moments/*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/dump_lagrange_multipliers/*.bin')) + +#moment_files = np.sort(glob.glob(filepath+'/dumps/moments*.bin')) +#lagrange_multiplier_files = \ +# np.sort(glob.glob(filepath+'/dumps/lagrange_multipliers*.bin')) + +dt = params.dt +dump_interval = params.dump_steps + +sensor_1_signal_array = [] +print("Reading sensor signal...") +for file_number, dump_file in enumerate(moment_files): + + moments = io.readBinaryFile(dump_file) + moments = moments[0].reshape(N_q2, N_q1, 3) + + density = moments[:, :, 0] + + source = np.mean(density[source_indices, 0]) + drain = np.mean(density[drain_indices, -1]) + + sensor_1_left = np.mean(density[0, 0]) + sensor_1_right = np.mean(density[0, -1]) + + sensor_1_signal = sensor_1_left - sensor_1_right + + sensor_1_signal_array.append(sensor_1_signal) + +time_array = np.loadtxt("dump_time_array.txt") +AC_freq = 1./100 +input_signal_array = np.sin(2.*np.pi*AC_freq*time_array) +sensor_1_signal_array = np.array(sensor_1_signal_array) +half_time = (int)(time_array.size/2) + +input_normalized = \ + input_signal_array/np.max(np.abs(input_signal_array[half_time:])) +sensor_normalized = \ + sensor_1_signal_array#/np.max(np.abs(sensor_1_signal_array[half_time:])) + +# Calculate the phase difference between input_signal_array and sensor_normalized +# Code copied from : +# https:/stackoverflow.com/questions/6157791/find-phase-difference-between-two-inharmonic-waves + +#corr = correlate(input_normalized, sensor_normalized) +#nsamples = input_normalized.size +#time_corr = time_array[half_time:] +#dt_corr = np.linspace(-time_corr[-1] + time_corr[0], +# time_corr[-1] - time_corr[0], 2*nsamples-1) +#time_shift = dt_corr[corr.argmax()] + +#Force the phase shift to be in [-pi:pi] +#period = 1./AC_freq +#phase_diff = 2*np.pi*(((0.5 + time_shift/period) % 1.0) - 0.5) + +#pl.plot(time_array, input_signal_array) +pl.plot(time_array, sensor_normalized) +#pl.axhline(0, color='black', linestyle='--') + +#pl.legend(['Source $I(t)$', 'Measured $V(t)$'], loc=1) +#pl.text(135, 1.14, '$\phi : %.2f \; rad$' %phase_diff) +pl.xlabel(r'Time (ps)') +#pl.xlim([0, 200]) +#pl.ylim([-1.1, 1.1]) + +pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 0.5$ ps') +pl.savefig('images/iv' + '.png') +pl.clf() + + diff --git a/example_problems/electronic_boltzmann/test_compute_moments_cartesian/test.py b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/test.py new file mode 100644 index 00000000..89e69811 --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/test.py @@ -0,0 +1,138 @@ +#import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import os +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +#import yt +#yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc +import PetscBinaryIO + +import domain +#import boundary_conditions +#import params +#import initialize + + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 12, 7.5 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 + +p1 = domain.p1_start[0] + (0.5 + np.arange(N_p1)) * (domain.p1_end[0] - \ + domain.p1_start[0])/N_p1 +p2 = domain.p2_start[0] + (0.5 + np.arange(N_p2)) * (domain.p2_end[0] - \ + domain.p2_start[0])/N_p2 + + +filepath = os.getcwd() +moment_files = np.sort(glob.glob(filepath+'/dump_moments/*.bin')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/dump_lagrange_multipliers/*.bin')) + +print ("moment files : ", moment_files.size) +print ("lagrange multiplier files : ", lagrange_multiplier_files.size) + + +time_array = np.loadtxt("dump_time_array.txt") + +io = PetscBinaryIO.PetscBinaryIO() + +for file_number, dump_file in enumerate(moment_files[:]): + + #file_number = -1 + print("file number = ", file_number, "of ", moment_files.size) + + moments = io.readBinaryFile(moment_files[file_number]) + moments = moments[0].reshape(N_q2, N_q1, 3) + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + + lagrange_multipliers = \ + io.readBinaryFile(lagrange_multiplier_files[file_number]) + lagrange_multipliers = lagrange_multipliers[0].reshape(N_q2, N_q1, 5) + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + + print (vel_drift_x) + print (j_x, density) + print (j_x/density) + + + pl.subplot(121) + pl.contourf(q1_meshgrid, q2_meshgrid, (j_x - density*vel_drift_x).T, 100, cmap='bwr') + + pl.xlim([q1[0], q1[-1]]) + pl.ylim([q2[0], q2[-1]]) + + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + pl.ylabel(r'$y\;(\mu \mathrm{m})$') + pl.colorbar() + + pl.subplot(122) + pl.contourf(q1_meshgrid, q2_meshgrid, (j_y - density*vel_drift_y).T, 100, cmap='bwr') + + pl.xlim([q1[0], q1[-1]]) + pl.ylim([q2[0], q2[-1]]) + + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + #pl.ylabel(r'$y\;(\mu \mathrm{m})$') + pl.colorbar() + + pl.tight_layout() + pl.suptitle('$\\tau_\mathrm{mc} = \infty$, $\\tau_\mathrm{mr} = \infty$') + pl.savefig('images/dump.png') + pl.clf() + diff --git a/example_problems/electronic_boltzmann/test_compute_moments_cartesian/vorticity.py b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/vorticity.py new file mode 100644 index 00000000..2f494c60 --- /dev/null +++ b/example_problems/electronic_boltzmann/test_compute_moments_cartesian/vorticity.py @@ -0,0 +1,136 @@ +import arrayfire as af +import numpy as np +from scipy.signal import correlate +import glob +import h5py +import matplotlib +import matplotlib.gridspec as gridspec +import matplotlib.patches as patches +matplotlib.use('agg') +import pylab as pl +import yt +yt.enable_parallelism() + +import petsc4py, sys; petsc4py.init(sys.argv) +from petsc4py import PETSc + +from bolt.lib.physical_system import physical_system + +from bolt.lib.nonlinear_solver.nonlinear_solver \ + import nonlinear_solver +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ + import compute_electrostatic_fields + +import domain +import boundary_conditions +import params +import initialize + +import bolt.src.electronic_boltzmann.advection_terms as advection_terms + +import bolt.src.electronic_boltzmann.collision_operator \ + as collision_operator + +import bolt.src.electronic_boltzmann.moment_defs as moment_defs + +# Optimized plot parameters to make beautiful plots: +pl.rcParams['figure.figsize'] = 8, 8 +pl.rcParams['figure.dpi'] = 100 +pl.rcParams['image.cmap'] = 'jet' +pl.rcParams['lines.linewidth'] = 1.5 +pl.rcParams['font.family'] = 'serif' +pl.rcParams['font.weight'] = 'bold' +pl.rcParams['font.size'] = 25 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = True +pl.rcParams['axes.linewidth'] = 1.5 +pl.rcParams['axes.titlesize'] = 'medium' +pl.rcParams['axes.labelsize'] = 'medium' + +pl.rcParams['xtick.major.size'] = 8 +pl.rcParams['xtick.minor.size'] = 4 +pl.rcParams['xtick.major.pad'] = 8 +pl.rcParams['xtick.minor.pad'] = 8 +pl.rcParams['xtick.color'] = 'k' +pl.rcParams['xtick.labelsize'] = 'medium' +pl.rcParams['xtick.direction'] = 'in' + +pl.rcParams['ytick.major.size'] = 8 +pl.rcParams['ytick.minor.size'] = 4 +pl.rcParams['ytick.major.pad'] = 8 +pl.rcParams['ytick.minor.pad'] = 8 +pl.rcParams['ytick.color'] = 'k' +pl.rcParams['ytick.labelsize'] = 'medium' +pl.rcParams['ytick.direction'] = 'in' + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 + +q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * (domain.q1_end - domain.q1_start)/N_q1 +q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * (domain.q2_end - domain.q2_start)/N_q2 + +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) + +filepath = \ +'/home/mchandra/gitansh/bolt/example_problems/electronic_boltzmann/graphene/L_1.0_tau_ee_0.2_tau_eph_0.5/dumps' +moment_files = np.sort(glob.glob(filepath+'/moment*.h5')) +lagrange_multiplier_files = \ + np.sort(glob.glob(filepath+'/lagrange_multipliers*.h5')) + +dt = params.dt +dump_interval = params.dump_steps + +time_array = np.loadtxt("dump_time_array.txt") +half_time = (int)(time_array.size/2) + +for file_number, dump_file in yt.parallel_objects(enumerate(moment_files)): + + print("file number = ", file_number, "of ", moment_files.size) + + h5f = h5py.File(dump_file, 'r') + moments = np.swapaxes(h5f['moments'][:], 0, 1) + h5f.close() + + + density = moments[:, :, 0] + j_x = moments[:, :, 1] + j_y = moments[:, :, 2] + + h5f = h5py.File(lagrange_multiplier_files[file_number], 'r') + lagrange_multipliers = h5f['lagrange_multipliers'][:] + h5f.close() + + mu = lagrange_multipliers[:, :, 0] + mu_ee = lagrange_multipliers[:, :, 1] + T_ee = lagrange_multipliers[:, :, 2] + vel_drift_x = lagrange_multipliers[:, :, 3] + vel_drift_y = lagrange_multipliers[:, :, 4] + + + dq1 = (domain.q1_end - domain.q1_start)/domain.N_q1 + dq2 = (domain.q2_end - domain.q2_start)/domain.N_q2 + + dvx_dx, dvx_dy = np.gradient(j_x/density, dq1, dq2) + dvy_dx, dvy_dy = np.gradient(j_y/density, dq1, dq2) + + vorticity = dvy_dx - dvx_dy + + pl.contourf(q1_meshgrid, q2_meshgrid, vorticity, 100, cmap='bwr') + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") + + pl.streamplot(q1, q2, + vel_drift_x, vel_drift_y, + density=2, color='blue', + linewidth=0.7, arrowsize=1 + ) + + pl.xlim([domain.q1_start, domain.q1_end]) + pl.ylim([domain.q2_start, domain.q2_end]) + + pl.gca().set_aspect('equal') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + pl.ylabel(r'$y\;(\mu \mathrm{m})$') + pl.suptitle('$\\tau_\mathrm{mc} = 0.2$ ps, $\\tau_\mathrm{mr} = 1.0$ ps') + pl.savefig('vorticity_images/dump_' + '%06d'%file_number + '.png') + pl.clf() + diff --git a/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/boundary_conditions.py b/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/boundary_conditions.py index 50c18b3a..deed2e10 100644 --- a/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/boundary_conditions.py +++ b/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/boundary_conditions.py @@ -1,5 +1,5 @@ -in_q1_left = 'periodic' -in_q1_right = 'periodic' +in_q1_left = 'none' +in_q1_right = 'none' in_q2_bottom = 'periodic' in_q2_top = 'periodic' diff --git a/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/domain.py b/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/domain.py index 6d376da1..3b6e1d5e 100644 --- a/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/domain.py +++ b/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/domain.py @@ -2,7 +2,7 @@ q1_start = 0 q1_end = L_x -N_q1 = 3 +N_q1 = 1 q2_start = 0 q2_end = L_y @@ -20,4 +20,4 @@ p3_end = [ v_max_e, v_max_i] N_p3 = 32 -N_ghost = 3 +N_ghost = 2 diff --git a/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/fire_job_batch.py b/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/fire_job_batch.py new file mode 100644 index 00000000..88e082bd --- /dev/null +++ b/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/fire_job_batch.py @@ -0,0 +1,53 @@ +import os +import numpy as np + +tau_start = 0.1 #* t0 +tau_end = 100. #* t0 +tau_step = 10. #* t0 + +source_filepath = \ + '/home/mchandra/bolt_master/bolt/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D' +job_script_file = 'job_script_gpu3001' # Can also be empty +run_filepath = \ + '/home/mchandra/bolt_master/bolt/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/tau_' + +submit_jobs = False # Be careful! + +for tau in np.arange(tau_start, tau_end, tau_step): + filepath = run_filepath + str(tau) + + # If folder does not exist, make one and add all files from source folder + + if not os.path.isdir(filepath): + os.makedirs(filepath) + os.makedirs(filepath+"/dump_f") + os.makedirs(filepath+"/dump_fields") + os.makedirs(filepath+"/dump_moments") + os.makedirs(filepath+"/images") + + os.system("cp " + (source_filepath + "/*.py ") + + (source_filepath + "/" + job_script_file) + + " " + filepath + "/." + ) + + # Change required files + # Code copied from here : + # https://stackoverflow.com/questions/4454298/prepend-a-line-to-an-existing-file-in-python + + f = open(filepath + "/params.py", "r") + old = f.read() # read everything in the file + f.close() + + f = open(filepath + "/params.py", "w") + f.write("tau_collisions = " + str(tau) + " \n") + f.write(old) + f.close() + + # Schedule job after changing to run directory so that generated slurm file + # is stored in that directory + os.chdir(filepath) + + if (submit_jobs): + os.system("sbatch " + job_script_file) + + os.chdir(source_filepath) # Return to job firing script's directory diff --git a/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/initialize.py b/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/initialize.py index 8b7336a0..35ca8e28 100644 --- a/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/initialize.py +++ b/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/initialize.py @@ -47,12 +47,9 @@ def initialize_E(q1, q2, params): return(E1, E2, E3) def initialize_B(q1, q2, params): - + # Seeding with random fluctuation: - B1 = params.B1 * af.randu(q1.shape[0], q1.shape[1], - q1.shape[2], q1.shape[3], - dtype = af.Dtype.f64 - ) + B1 = params.B1 * params.random_vals B2 = 0 * q1**0 B3 = 0 * q1**0 diff --git a/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/job_script_gpu3001 b/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/job_script_gpu3001 new file mode 100644 index 00000000..3c8976fe --- /dev/null +++ b/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/job_script_gpu3001 @@ -0,0 +1,4 @@ +#!/bin/bash +#SBATCH -p gpu -n 4 --gres=gpu:4 -c1 --hint=nomultithread -t 2-00:00 +# (Note: use one MPI process per gpu, update both gres and -n together; max 6) +time mpirun python main.py > output.txt diff --git a/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/main.py b/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/main.py index 552543d4..fe6eff5f 100644 --- a/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/main.py +++ b/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/main.py @@ -7,6 +7,7 @@ from bolt.lib.physical_system import physical_system from bolt.lib.nonlinear.nonlinear_solver import nonlinear_solver +from bolt.lib.utils.parallel_reduction_ops import global_min, global_mean import domain import boundary_conditions @@ -42,33 +43,36 @@ if(params.t_restart == 0): time_elapsed = 0 - nls.dump_distribution_function('dump_f/t=0.000') - nls.dump_moments('dump_moments/t=0.000') - nls.dump_EM_fields('dump_fields/t=0.000') + nls.dump_distribution_function('dump_f/t=0.000000') + nls.dump_moments('dump_moments/t=0.000000') + nls.dump_EM_fields('dump_fields/t=0.000000') else: time_elapsed = params.t_restart - nls.load_distribution_function('dump_f/t=' + '%.3f'%time_elapsed) - nls.load_EM_fields('dump_fields/t=' + '%.3f'%time_elapsed) + nls.load_distribution_function('dump_f/t=' + '%.6f'%time_elapsed) + nls.load_EM_fields('dump_fields/t=' + '%.6f'%time_elapsed) # Checking that the file writing intervals are greater than dt: assert(params.dt_dump_f > dt) assert(params.dt_dump_moments > dt) assert(params.dt_dump_fields > dt) -print('Printing the minimum of the distribution functions for electrons and ions:') -print('f_min_electron:', af.min(nls.f[:, 0, :, :])) -print('f_min_ion:', af.min(nls.f[:, 1, :, :])) +PETSc.Sys.Print('\nMinimum of the distribution functions for electrons and ions:') +PETSc.Sys.Print('Electrons:', global_min(nls.f[:, 0, :, :])) +PETSc.Sys.Print('Ions :', global_min(nls.f[:, 1, :, :])) +PETSc.Sys.Print('\n') -print('MEAN DENSITY') +PETSc.Sys.Print('MEAN DENSITY') n = nls.compute_moments('density') -print('For electrons:', np.mean(np.array(n[:, 0, :, :]))) -print('For ions:', np.mean(np.array(n[:, 1, :, :]))) +PETSc.Sys.Print('Electrons:', global_mean(n[:, 0, :, :])) +PETSc.Sys.Print('Ions :', global_mean(n[:, 1, :, :])) +PETSc.Sys.Print('\n') -print('MEAN ENERGY(PER UNIT MASS)') +PETSc.Sys.Print('MEAN ENERGY (PER UNIT MASS)') E = nls.compute_moments('energy') -print('For electrons:', np.mean(np.array(E[:, 0, :, :]))) -print('For ions:', np.mean(np.array(E[:, 1, :, :]))) +PETSc.Sys.Print('Electrons:', global_mean(E[:, 0, :, :])) +PETSc.Sys.Print('Ions :', global_mean(E[:, 1, :, :])) +PETSc.Sys.Print('\n') timing_data = [] while(abs(time_elapsed - params.t_final) > 1e-12): @@ -87,19 +91,15 @@ if((delta_dt-dt)<1e-5): nls.strang_timestep(delta_dt) time_elapsed += delta_dt - nls.dump_moments('dump_moments/t=' + '%.3f'%time_elapsed) - nls.dump_EM_fields('dump_fields/t=' + '%.3f'%time_elapsed) + nls.dump_moments('dump_moments/t=' + '%.6f'%time_elapsed) + nls.dump_EM_fields('dump_fields/t=' + '%.6f'%time_elapsed) if(math.modf(time_elapsed/params.dt_dump_f)[0] < 1e-12): - nls.dump_distribution_function('dump_f/t=' + '%.3f'%time_elapsed) + nls.dump_distribution_function('dump_f/t=' + '%.6f'%time_elapsed) - PETSc.Sys.Print('Computing For Time =', time_elapsed / params.t0, "|t0| units(t0)") - PETSc.Sys.Print('Time Taken For Timestep =', toc - tic) + PETSc.Sys.Print('Time =', format(time_elapsed / params.t0, '.4f'), + 't0, dt = ', format(dt / params.t0, '.4f'), + 't0, time taken = ', format(toc - tic, '.4f'), 'secs' + ) timing_data.append(toc - tic) - -# Writing the timing data to file: -import h5py -h5f = h5py.File('timing_data.h5', 'w') -h5f.create_dataset('time_taken', data = np.array(timing_data)) -h5f.close() diff --git a/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/params.py b/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/params.py index 2790466f..9a9750b2 100644 --- a/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/params.py +++ b/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/params.py @@ -21,10 +21,10 @@ riemann_solver_in_q = 'upwind-flux' riemann_solver_in_p = 'upwind-flux' -# Alternate set of units to consider(from discussion with Mani): +# Alternate set of units to consider: # Temperature isn't a very good base unit # Set v0 = 1(that is velocity is a base unit) -# Set T0 = 1/2 m0 v0^2 / k_B, and set T = εT0; ε = small number +# Set T0 = 1/2 m0 v0^2 / k_B, and set T = eps * T0;eps = small number # B0 is set the same way as before; B0 = sqrt(n_background * m0) * u_b # Units: l0, t0, m0, e0, n0, T0, v0, B0, E0 @@ -139,7 +139,7 @@ # Time parameters: N_cfl = 0.125 -t_final = 400 * t0 +t_final = 500 * t0 PETSc.Sys.Print("==================================================") PETSc.Sys.Print(" Length Scales of the System ") @@ -183,8 +183,7 @@ # Switch for solver components: fields_enabled = True -source_enabled = False -instantaneous_collisions = False +source_enabled = True hybrid_model_enabled = False # File-writing Parameters: @@ -194,9 +193,9 @@ dt_dump_moments = dt_dump_fields = 0.1 * t0 # Restart(Set to zero for no-restart): -t_restart = 200 * t0 +t_restart = 0 * t0 # Variation of collisional-timescale parameter through phase space: @af.broadcast def tau(q1, q2, p1, p2, p3): - return (np.inf * t0 * p1**0 * q1**0) + return (tau_collisions * t0 * p1**0 * q1**0) diff --git a/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/post.py b/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/post.py index 8f466387..ffd294e2 100644 --- a/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/post.py +++ b/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/post.py @@ -2,8 +2,8 @@ import matplotlib matplotlib.use('agg') import pylab as pl +from petsc4py import PETSc -import h5py import domain import params @@ -39,8 +39,14 @@ N_q1 = domain.N_q1 N_q2 = domain.N_q2 +N_p1 = domain.N_p1 +N_p2 = domain.N_p2 +N_p3 = domain.N_p3 N_g = domain.N_ghost +# Finding the number of species, by looking at the number of elements in mass: +N_s = len(params.mass) + dq1 = (domain.q1_end - domain.q1_start) / N_q1 dq2 = (domain.q2_end - domain.q2_start) / N_q2 @@ -49,8 +55,69 @@ q2, q1 = np.meshgrid(q2, q1) -# Finding the number of species, by looking at the number of elements in mass: -N_s = len(params.mass) +dp1 = []; dp2 = []; dp3 = [] +p1 = []; p2 = []; p3 = [] +for s in range(N_s): + dp1.append((domain.p1_end[s] - domain.p1_start[s]) / domain.N_p1) + dp2.append((domain.p2_end[s] - domain.p2_start[s]) / domain.N_p2) + dp3.append((domain.p3_end[s] - domain.p3_start[s]) / domain.N_p3) + + p1.append(domain.p1_start[s] + (0.5 + np.arange(domain.N_p1)) * dp1[s]) + p2.append(domain.p2_start[s] + (0.5 + np.arange(domain.N_p2)) * dp2[s]) + p3.append(domain.p3_start[s] + (0.5 + np.arange(domain.N_p3)) * dp3[s]) + +p1 = np.array(p1) +p2 = np.array(p2) +p3 = np.array(p3) + +da_fields = PETSc.DMDA().create([domain.N_q1, domain.N_q2], + dof=(6), stencil_width=0 + ) +fields_vec = da_fields.createGlobalVec() + +da_moments = PETSc.DMDA().create([domain.N_q1, domain.N_q2], + dof=(22), stencil_width=0 + ) +moments_vec = da_moments.createGlobalVec() + +da_f = PETSc.DMDA().create([domain.N_q1, domain.N_q2], + dof=(N_s*N_p1*N_p2*N_p3), stencil_width=0 + ) +f_vec = da_f.createGlobalVec() + +def return_f(file_name): + """ + Returns the distribution function in the desired format of + (q1, q2, p1, p2, p3), when the file that is written by the + dump_distribution_function is passed as the argument + + Parameters + ---------- + + file_name : str + Pass the name of the file that needs to be read as + a string. This should be the file that is written by + dump_distribution_function + + N_s: int + Pass the species that is in consideration. For instance when + the run is carried out for 2 species, passing N_s = 0 returns + the distribution function for the first species while N_s = 1 + returns the distribution function of the second species. + """ + + # When written using the routine dump_distribution_function, + # distribution function gets written in the format (q2, q1, p1 * p2 * p3 * Ns) + viewer = PETSc.Viewer().createBinary(file_name, + PETSc.Viewer.Mode.READ, + ) + + f_vec.load(viewer) + f = da_f.getVecArray(f_vec) # [N_q1, N_q2, N_p1*N_p2*N_p3*N_s] + + f = np.array(f[:]).reshape([N_q1, N_q2, N_s, N_p3, N_p2, N_p1]) + + return f def return_moment_to_be_plotted(name, moments): """ @@ -227,6 +294,16 @@ def return_field_to_be_plotted(name, fields): else: raise Exception('Not valid!') +da_fields = PETSc.DMDA().create([domain.N_q1, domain.N_q2], + dof=(6), stencil_width=0 + ) +fields_vec = da_fields.createGlobalVec() + +da_moments = PETSc.DMDA().create([domain.N_q1, domain.N_q2], + dof=(22), stencil_width=0 + ) +moments_vec = da_moments.createGlobalVec() + # Traversal to determine the maximum and minimum: def determine_min_max(name, time_array): """ @@ -252,16 +329,30 @@ def determine_min_max(name, time_array): for time_index, t0 in enumerate(time_array): if(name in ['E1', 'E2', 'E3', 'B1', 'B2', 'B3']): - h5f = h5py.File('dump_fields/t=%.3f'%(t0) + '.h5', 'r') - fields = np.swapaxes(h5f['EM_fields'][:], 0, 1) - h5f.close() + + fields_file = 'dump_fields/t=%.6f'%(t0) + '.bin' + + # Load fields + viewer = PETSc.Viewer().createBinary(fields_file, + PETSc.Viewer.Mode.READ, + ) + + fields_vec.load(viewer) + fields = da_fields.getVecArray(fields_vec) # [N_q1, N_q2, N_fields] array = return_field_to_be_plotted(name, fields) else: - h5f = h5py.File('dump_moments/t=%.3f'%(t0) + '.h5', 'r') - moments = np.swapaxes(h5f['moments'][:], 0, 1) - h5f.close() + + moments_file = 'dump_moments/t=%.6f'%(t0) + '.bin' + + # Load moments + viewer = PETSc.Viewer().createBinary(moments_file, + PETSc.Viewer.Mode.READ, + ) + + moments_vec.load(viewer) + moments = da_moments.getVecArray(moments_vec) # [N_q1, N_q2, N_moments] array = return_moment_to_be_plotted(name, moments) diff --git a/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/post_1d.py b/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/post_1d.py index bdb1fe14..efd061ab 100644 --- a/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/post_1d.py +++ b/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/post_1d.py @@ -1,21 +1,26 @@ import numpy as np +import time import matplotlib +matplotlib.use('agg') import pylab as pl +from petsc4py import PETSc -import h5py import domain import params -from post import return_moment_to_be_plotted, return_field_to_be_plotted, determine_min_max, q1, q2 +from post import return_moment_to_be_plotted +from post import return_field_to_be_plotted +from post import determine_min_max, q1, q2 +from post import da_moments, da_fields, moments_vec, fields_vec # Optimized plot parameters to make beautiful plots: -pl.rcParams['figure.figsize'] = 9, 4 -pl.rcParams['figure.dpi'] = 300 +pl.rcParams['figure.figsize'] = 18, 8 +pl.rcParams['figure.dpi'] = 100 pl.rcParams['image.cmap'] = 'jet' pl.rcParams['lines.linewidth'] = 1.5 pl.rcParams['font.family'] = 'serif' pl.rcParams['font.weight'] = 'bold' -pl.rcParams['font.size'] = 30 +pl.rcParams['font.size'] = 25 pl.rcParams['font.sans-serif'] = 'serif' pl.rcParams['text.usetex'] = True pl.rcParams['axes.linewidth'] = 1.5 @@ -38,68 +43,148 @@ pl.rcParams['ytick.labelsize'] = 'medium' pl.rcParams['ytick.direction'] = 'in' -time_array = np.arange(0, params.t_final + params.dt_dump_moments, +t_final = 180 * params.t0 +time_array = np.arange(0, t_final + params.dt_dump_moments, params.dt_dump_moments ) -n_min, n_max = determine_min_max('density', time_array) -v1_min, v1_max = determine_min_max('v1', time_array) +print("Determining limits...") +n_min, n_max = determine_min_max('density', time_array) +v1_min, v1_max = determine_min_max('v1', time_array) T_min, T_max = determine_min_max('temperature', time_array) -B1_min, B1_max = determine_min_max('B1', time_array) +B1_min, B1_max = determine_min_max('B1', time_array) -for time_index, t0 in enumerate(time_array): - - h5f = h5py.File('dump_moments/t=%.3f'%(t0) + '.h5', 'r') - # dump_moments writes files in the structure (q2, q1, N_s) - # But the post-processing functions require it in the form (q1, q2, N_s) - # By using swapaxes we change (q2, q1, N_s) --> (q1, q2, N_s) - moments = np.swapaxes(h5f['moments'][:], 0, 1) - h5f.close() - - h5f = h5py.File('dump_fields/t=%.3f'%(t0) + '.h5', 'r') - # dump_EM_fields writes files in the structure (q2, q1, N_s) - # But the post-processing functions require it in the form (q1, q2, N_s) - # By using swapaxes we change (q2, q1, N_s) --> (q1, q2, N_s) - fields = np.swapaxes(h5f['EM_fields'][:], 0, 1) - h5f.close() +def make_plot(moments, fields, time_sim=0, + fig=None, + line1_ax1=None, line2_ax1=None, + line1_ax2=None, line2_ax2=None, + line1_ax3=None, line2_ax3=None, + line1_ax4=None, file_name=None + ): n = return_moment_to_be_plotted('density', moments) v1 = return_moment_to_be_plotted('v1', moments) T = return_moment_to_be_plotted('temperature', moments) B1 = return_field_to_be_plotted('B1', fields) - fig = pl.figure() - - ax1 = fig.add_subplot(2, 2, 1) - ax1.plot(q2[0, :], n[0, :, 0], color = 'C0', label = 'Electrons') - ax1.plot(q2[0, :], n[0, :, 1], '--', color = 'C3', label = 'Ions') - ax1.legend() - ax1.set_xlabel(r'$y(l_s)$') - ax1.set_ylabel(r'$n(n_0)$') - ax1.set_ylim([0.95 * n_min, 1.05 * n_max]) - - ax2 = fig.add_subplot(2, 2, 2) - ax2.plot(q2[0, :], v1[0, :, 0] / params.v0, color = 'C0') - ax2.plot(q2[0, :], v1[0, :, 1] / params.v0, '--', color = 'C3') - ax2.set_xlabel(r'$y(l_s)$') - ax2.set_ylabel(r'$v_x(v_0)$') - ax2.set_ylim([1.05 * v1_min / params.v0, 1.05 * v1_max / params.v0]) - - ax3 = fig.add_subplot(2, 2, 3) - ax3.plot(q2[0, :], T[0, :, 0] / params.T0, color = 'C0') - ax3.plot(q2[0, :], T[0, :, 1] / params.T0, '--', color = 'C3') - ax3.set_xlabel(r'$y(l_s)$') - ax3.set_ylabel(r'$T(T_0)$') - ax3.set_ylim([0.95 * T_min / params.T0, 1.05 * T_max / params.T0]) - - ax4 = fig.add_subplot(2, 2, 4) - ax4.plot(q2[0, :], B1[0, :] / params.B0) - ax4.set_xlabel(r'$y(l_s)$') - ax4.set_ylabel(r'$B_x(\sqrt{n_0 m_0} v_0)$') - ax4.set_ylim([0.95 * B1_min / params.B0, 1.05 * B1_max / params.B0]) - - # fig.tight_layout() - fig.suptitle('Time = %.2f'%(t0 / params.t0)+r'$\omega_c^{-1}$=%.2f'%(t0 * params.plasma_frequency)+r'$\omega_p^{-1}$') - pl.savefig('images/%04d'%time_index + '.png') - pl.close(fig) - pl.clf() + if (fig==None): + fig = pl.figure() + + ax1 = fig.add_subplot(2, 2, 1) + line1_ax1, = ax1.plot(q2[0, :], n[0, :, 0], color = 'C0', label = 'Electrons') + line2_ax1, = ax1.plot(q2[0, :], n[0, :, 1], '--', color = 'C3', label = 'Ions') + ax1.legend() + ax1.set_ylabel(r'$n$') + ax1.set_ylim([0.95 * n_min, 1.05 * n_max]) + ax1.set_xticks([]) + + ax2 = fig.add_subplot(2, 2, 2) + line1_ax2, = ax2.plot(q2[0, :], v1[0, :, 0] / params.v0, color = 'C0') + line2_ax2, = ax2.plot(q2[0, :], v1[0, :, 1] / params.v0, '--', color = 'C3') + ax2.set_ylabel(r'$v_x$') + ax2.set_ylim([1.05 * v1_min / params.v0, 1.05 * v1_max / params.v0]) + ax2.set_xticks([]) + + ax3 = fig.add_subplot(2, 2, 3) + line1_ax3, = ax3.plot(q2[0, :], T[0, :, 0] / params.T0, color = 'C0') + line2_ax3, = ax3.plot(q2[0, :], T[0, :, 1] / params.T0, '--', color = 'C3') + ax3.set_xlabel(r'$y$') + ax3.set_ylabel(r'$T$') + ax3.set_ylim([0.95 * T_min / params.T0, 1.05 * T_max / params.T0]) + + ax4 = fig.add_subplot(2, 2, 4) + line1_ax4, = ax4.plot(q2[0, :], B1[0, :] / params.B0) + ax4.set_xlabel(r'$y$') + ax4.set_ylabel(r'$B_x$') + ax4.set_ylim([0.95 * B1_min / params.B0, 1.05 * B1_max / params.B0]) + + pl.subplots_adjust(hspace=0.01) + + return (fig, line1_ax1, line2_ax1, \ + line1_ax2, line2_ax2, \ + line1_ax3, line2_ax3, \ + line1_ax4 \ + ) + + else: + + line1_ax1.set_ydata(n[0, :, 0]) + line2_ax1.set_ydata(n[0, :, 1]) + + line1_ax2.set_ydata(v1[0, :, 0] / params.v0) + line2_ax2.set_ydata(v1[0, :, 1] / params.v0) + + line1_ax3.set_ydata(T[0, :, 0] / params.T0) + line2_ax3.set_ydata(T[0, :, 1] / params.T0) + + line1_ax4.set_ydata(B1[0, :] / params.B0) + + fig.suptitle('Time = %.2f'%(time_sim / + params.t0)+r'$\omega_c^{-1}$=%.2f'%(time_sim * params.plasma_frequency)+r'$\omega_p^{-1}$') + pl.savefig(file_name) + + + +for time_index, time_sim in enumerate(time_array[:1]): + + print("Setting the figure...") + + moments_file = 'dump_moments/t=%.6f'%(time_sim) + '.bin' + fields_file = 'dump_fields/t=%.6f'%(time_sim) + '.bin' + + # Load moments + viewer = PETSc.Viewer().createBinary(moments_file, + PETSc.Viewer.Mode.READ, + ) + + moments_vec.load(viewer) + moments = da_moments.getVecArray(moments_vec) # [N_q1, N_q2, N_moments] + + # Load fields + viewer = PETSc.Viewer().createBinary(fields_file, + PETSc.Viewer.Mode.READ, + ) + + fields_vec.load(viewer) + fields = da_fields.getVecArray(fields_vec) # [N_q1, N_q2, N_fields] + + fig, line1_ax1, line2_ax1, \ + line1_ax2, line2_ax2, \ + line1_ax3, line2_ax3, \ + line1_ax4 = make_plot(moments, fields) + +for time_index, time_sim in enumerate(time_array): + + t_start = time.time() + + moments_file = 'dump_moments/t=%.6f'%(time_sim) + '.bin' + fields_file = 'dump_fields/t=%.6f'%(time_sim) + '.bin' + + # Load moments + viewer = PETSc.Viewer().createBinary(moments_file, + PETSc.Viewer.Mode.READ, + ) + + moments_vec.load(viewer) + moments = da_moments.getVecArray(moments_vec) # [N_q1, N_q2, N_moments] + + # Load fields + viewer = PETSc.Viewer().createBinary(fields_file, + PETSc.Viewer.Mode.READ, + ) + + fields_vec.load(viewer) + fields = da_fields.getVecArray(fields_vec) # [N_q1, N_q2, N_fields] + + file_name = 'images/%06d'%time_index + '.png' + make_plot(moments, fields, time_sim, fig, + line1_ax1, line2_ax1, + line1_ax2, line2_ax2, + line1_ax3, line2_ax3, + line1_ax4, file_name + ) + + print("file = ", time_index, + ", time taken = ", format(time.time() - t_start, '.4f'), " secs" + ) + diff --git a/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/post_f.py b/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/post_f.py index ce7584e5..2e388354 100644 --- a/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/post_f.py +++ b/example_problems/nonrelativistic_boltzmann/instabilities/collisionless_shock/1D/post_f.py @@ -3,13 +3,14 @@ matplotlib.use('agg') import pylab as pl -import h5py import domain import params +from post import p1, p2, p3, return_f + # Optimized plot parameters to make beautiful plots: pl.rcParams['figure.figsize'] = 15, 10 -pl.rcParams['figure.dpi'] = 300 +pl.rcParams['figure.dpi'] = 100 pl.rcParams['image.cmap'] = 'jet' pl.rcParams['lines.linewidth'] = 1.5 pl.rcParams['font.family'] = 'serif' @@ -37,94 +38,58 @@ pl.rcParams['ytick.labelsize'] = 'medium' pl.rcParams['ytick.direction'] = 'in' -N_q1 = domain.N_q1 -N_q2 = domain.N_q2 -N_p1 = domain.N_p1 -N_p2 = domain.N_p2 -N_p3 = domain.N_p3 -N_g = domain.N_ghost - -dq1 = (domain.q1_end - domain.q1_start) / N_q1 -dq2 = (domain.q2_end - domain.q2_start) / N_q2 - -q1 = domain.q1_start + (0.5 + np.arange(N_q1)) * dq1 -q2 = domain.q2_start + (0.5 + np.arange(N_q2)) * dq2 - -def return_f_species(file_name, N_s = 0): - """ - Returns the distribution function in the desired format of - (q1, q2, p1, p2, p3), when the file that is written by the - dump_distribution_function is passed as the argument - - Parameters - ---------- - - file_name : str - Pass the name of the file that needs to be read as - a string. This should be the file that is written by - dump_distribution_function - - N_s: int - Pass the species that is in consideration. For instance when - the run is carried out for 2 species, passing N_s = 0 returns - the distribution function for the first species while N_s = 1 - returns the distribution function of the second species. - """ - - # When written using the routine dump_distribution_function, - # distribution function gets written in the format (q2, q1, p1 * p2 * p3 * Ns) - h5f = h5py.File(file_name, 'r') - # Making this (q2, q1, p1 * p2 * p3 * Ns) --> (q1, q2, p1 * p2 * p3 * Ns) - f = np.swapaxes(h5f['distribution_function'][:], 0, 1) - h5f.close() - - # Finding the distribution function for the species in consideration: - f = f[:, :, N_s * N_p1 * N_p2 * N_p3:(N_s + 1) * N_p1 * N_p2 * N_p3] - # Reshaping this from (q1, q2, p1 * p2 * p3) --> (q1, q2, p1, p2, p3) - f = f.reshape(N_q1, N_q2, N_p1, N_p2, N_p3) - - return f - -# Set this to 0 for electrons, 1 for ions: -N_s = 0 - -dp1 = (domain.p1_end[N_s] - domain.p1_start[N_s]) / N_p1 -dp2 = (domain.p2_end[N_s] - domain.p2_start[N_s]) / N_p2 -dp3 = (domain.p3_end[N_s] - domain.p3_start[N_s]) / N_p3 - -p1 = domain.p1_start[N_s] + (0.5 + np.arange(N_p1)) * dp1 -p2 = domain.p2_start[N_s] + (0.5 + np.arange(N_p2)) * dp2 -p3 = domain.p3_start[N_s] + (0.5 + np.arange(N_p3)) * dp3 - -# We want to see the distribution function variation as a function of (p1, p2) -# Hence we take a meshgrid of (p1, p2) -p1, p2 = np.meshgrid(p1, p2) - -# Declaration of the time array: -time_array = np.arange(0, params.t_final + params.dt_dump_f, - params.dt_dump_f - ) # Getting the distribution function at t = 0: # Since we want to visualize variation in (p1, p2), we will be averaging all other quantities: # (q1, q2, p1, p2, p3) --> (p1, p2) # (0, 1 , 2 , 3 , 4 ) # Hence we need to average along axes 0, 1 and 4: -f0 = np.mean(return_f_species('dump_f/t=0.000.h5', N_s), (0, 1, 4)) - -for time_index, t0 in enumerate(time_array): - - # Getting the distribution function at t = 0: - # Since we want to visualize variation in (p1, p2), we will be averaging all other quantities: - # (q1, q2, p1, p2, p3) --> (p1, p2) - # (0, 1 , 2 , 3 , 4 ) - # Hence we need to average along axes 0, 1 and 4: - f = np.mean(return_f_species('dump_f/t=%.3f'%(t0) + '.h5', N_s), (0, 1, 4)) - - pl.contourf(p1 / params.v0, p2 / params.v0, abs(f - f0), 100) - pl.xlabel(r'$v_x / v_A$') - pl.ylabel(r'$v_y / v_A$') - pl.title('Time = %.2f'%(t0 / params.t0)+r'$\omega_c^{-1}$') - pl.savefig('images_f/%04d'%time_index + '.png') - pl.colorbar() - pl.clf() +f0 = return_f('dump_f/t=0.000000.bin') # [N_q1, N_q2, N_s, N_p3, N_p2, N_p1] + +species = 0 + +fig = pl.figure(figsize=(18, 6)) +ax1 = fig.add_subplot(131) +f0_avged = np.mean(f0, (0, 1, 3)) +p2_tmp, p1_tmp = np.meshgrid(p2[species], p1[species]) +ax1.contourf(p1_tmp/params.v0, p2_tmp/params.v0, f0_avged[species].transpose(), 100) +ax1.set_aspect('equal') +ax1.set_xlabel('$v_1$') +ax1.set_ylabel('$v_2$') + +ax2 = fig.add_subplot(132) +f0_avged = np.mean(f0, (0, 1, 4)) +p3_tmp, p1_tmp = np.meshgrid(p3[species], p1[species]) +ax2.contourf(p1_tmp/params.v0, p3_tmp/params.v0, f0_avged[species].transpose(), 100) +ax2.set_yticks([]) +ax2.set_aspect('equal') +ax2.set_xlabel('$v_1$') +ax2.set_ylabel('$v_3$') + +ax3 = fig.add_subplot(133) +f0_avged = np.mean(f0, (0, 1, 5)) +p2_tmp, p3_tmp = np.meshgrid(p2[species], p3[species]) +ax3.contourf(p3_tmp / params.v0, p2_tmp / params.v0, f0_avged[species], 100) +ax3.set_yticks([]) +ax3.set_aspect('equal') +ax3.set_xlabel('$v_3$') +ax3.set_ylabel('$v_2$') + +pl.savefig('images/test_f.png') + +#for time_index, t0 in enumerate(time_array): +# +# # Getting the distribution function at t = 0: +# # Since we want to visualize variation in (p1, p2), we will be averaging all other quantities: +# # (q1, q2, p1, p2, p3) --> (p1, p2) +# # (0, 1 , 2 , 3 , 4 ) +# # Hence we need to average along axes 0, 1 and 4: +# f = np.mean(return_f_species('dump_f/t=%.3f'%(t0) + '.h5', N_s), (0, 1, 4)) +# +# pl.contourf(p1 / params.v0, p2 / params.v0, abs(f - f0), 100) +# pl.xlabel(r'$v_x / v_A$') +# pl.ylabel(r'$v_y / v_A$') +# pl.title('Time = %.2f'%(t0 / params.t0)+r'$\omega_c^{-1}$') +# pl.savefig('images_f/%04d'%time_index + '.png') +# pl.colorbar() +# pl.clf()