From e3ada3fd4ddc02e3dbc1803245809e80302757c4 Mon Sep 17 00:00:00 2001 From: Mani Chandra Date: Tue, 26 Sep 2017 20:09:39 +0530 Subject: [PATCH 01/28] 1) Added option to get ksp to read command line arguments. Needed to add additional headers in test files for petsc to read command line arguments. 2) test_compute_electrostatic_fields.py is in flux Run with : python test_compute_electrostatic_fields.py -ksp_monitor --- .../EM_fields_solver/electrostatic.py | 1 + .../tests/test_compute_electrostatic_fields.py | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py b/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py index b23ac42d..69edd214 100644 --- a/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py +++ b/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py @@ -90,6 +90,7 @@ def compute_electrostatic_fields(self, performance_test_flag = False): ) ) + ksp.setFromOptions() ksp.solve(rho, phi) num_tries = 0 diff --git a/bolt/lib/nonlinear_solver/tests/test_compute_electrostatic_fields.py b/bolt/lib/nonlinear_solver/tests/test_compute_electrostatic_fields.py index e38b1198..f7bc7234 100644 --- a/bolt/lib/nonlinear_solver/tests/test_compute_electrostatic_fields.py +++ b/bolt/lib/nonlinear_solver/tests/test_compute_electrostatic_fields.py @@ -13,8 +13,11 @@ import numpy as np import arrayfire as af +import petsc4py, sys +petsc4py.init(sys.argv) from petsc4py import PETSc + from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ import compute_electrostatic_fields @@ -143,7 +146,10 @@ def test_compute_electrostatic_fields_2(): obj = test(N[i]) compute_electrostatic_fields(obj) - E1_expected = 0 + E1_expected = 0 * obj.q1 + + q2_minus = 0.25 + q2_plus = 0.75 E2_expected = -0.5/20 * ( af.log(af.cosh(( obj.q2 - q2_minus)*20)) - af.log(af.cosh(( obj.q2 - q2_plus )*20)) @@ -166,3 +172,6 @@ def test_compute_electrostatic_fields_2(): assert (abs(poly_E1[0] + 2) < 0.2) assert (abs(poly_E2[0] + 2) < 0.2) + + +test_compute_electrostatic_fields_2() From 3a7d3534d841ab473176505fc95af4687505e67b Mon Sep 17 00:00:00 2001 From: Mani Chandra Date: Wed, 27 Sep 2017 15:00:26 +0530 Subject: [PATCH 02/28] * Using SNES to solve Poisson equation * First attempt: managed to solve x^2 - 2 = 0 over [63, 63] grid using SNES --- .../EM_fields_solver/electrostatic.py | 196 +++++++++--------- bolt/lib/nonlinear_solver/nonlinear_solver.py | 26 ++- .../test_compute_electrostatic_fields.py | 77 +++---- 3 files changed, 154 insertions(+), 145 deletions(-) diff --git a/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py b/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py index 69edd214..8c3146d3 100644 --- a/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py +++ b/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py @@ -7,7 +7,7 @@ from numpy.fft import fftfreq -class Poisson2D(object): +class poisson_eqn(object): """ This user class is an application context for the problem at hand; It contains some parametes and frames the matrix system depending on @@ -16,38 +16,21 @@ class Poisson2D(object): using the PETSc's KSP solver methods """ - def __init__(self, obj): - self.da = obj._da_ksp - self.obj = obj - self.localX = self.da.createLocalVec() + def __init__(self, nonlinear_solver_obj): + self.da = nonlinear_solver_obj._da_snes + self.obj = nonlinear_solver_obj + self.local_phi = self.da.createLocalVec() # phi with ghost zones - def RHS(self, rho, rho_array): - rho_val = self.da.getVecArray(rho) - rho_val[:] = rho_array + def compute_residual(self, snes, phi, residual): - def mult(self, mat, X, Y): - - self.da.globalToLocal(X, self.localX) - - x = self.da.getVecArray(self.localX) - y = self.da.getVecArray(Y) - - (q1_start, q1_end), (q2_start, q2_end) = self.da.getRanges() - - for j in range(q1_start, q1_end): - for i in range(q2_start, q2_end): - u = x[j, i] # center - - u_w = x[j, i - 1] # west - u_e = x[j, i + 1] # east - u_s = x[j - 1, i] # south - u_n = x[j + 1, i] # north - - u_xx = (-u_e + 2 * u - u_w) / self.obj.dq2**2 - u_yy = (-u_n + 2 * u - u_s) / self.obj.dq1**2 - - y[j, i] = u_xx + u_yy + #self.da.globalToLocal(phi, self.local_phi) + #phi_array = self.local_phi.getArray(readonly=1) + phi_array = phi.getArray(readonly=1) + residual_array = residual.getArray(readonly=0) + + residual_array[:] = phi_array**2. - 2. + return def compute_electrostatic_fields(self, performance_test_flag = False): @@ -57,76 +40,89 @@ def compute_electrostatic_fields(self, performance_test_flag = False): # Obtaining the left-bottom corner coordinates # (lowest values of the canonical coordinates in the local zone) # Additionally, we also obtain the size of the local zone - ((i_q1_lowest, i_q2_lowest), (N_q1_local,N_q2_local)) = self._da_ksp.getCorners() - - pde = Poisson2D(self) - phi = self._da_ksp.createGlobalVec() - rho = self._da_ksp.createGlobalVec() - - phi_local = self._da_ksp.createLocalVec() - - A = PETSc.Mat().createPython([phi.getSizes(), rho.getSizes()], - comm=self._da_ksp.comm - ) - A.setPythonContext(pde) - A.setUp() - - ksp = PETSc.KSP().create() - - ksp.setOperators(A) - ksp.setType('cg') - - pc = ksp.getPC() - pc.setType('none') - - N_g = self.N_ghost - ksp.setTolerances(atol=1e-7) - pde.RHS(rho, - self.physical_system.params.charge_electron - * np.array(self.compute_moments('density')[N_g:-N_g, - N_g:-N_g - ] - - 1 - ) - ) - - ksp.setFromOptions() - ksp.solve(rho, phi) - - num_tries = 0 - while(ksp.converged is not True): - - ksp.setTolerances(atol = 10**(-6+num_tries), rtol = 10**(-6+num_tries)) - ksp.solve(rho, phi) - num_tries += 1 - - if(num_tries == 5): - raise Exception('KSP solver diverging!') - - self._da_ksp.globalToLocal(phi, phi_local) - - # Since rho was defined at (i + 0.5, j + 0.5) - # Electric Potential returned will also be at (i + 0.5, j + 0.5) - electric_potential = af.to_array(np.swapaxes(phi_local[:]. - reshape( N_q2_local - + 2 * self.N_ghost, - N_q1_local + - + 2 * self.N_ghost - ), - 0, 1 - ) - ) - - # Obtaining the values at (i+0.5, j+0.5): - self.E1 = -( af.shift(electric_potential, -1) - - af.shift(electric_potential, 1) - ) / (2 * self.dq1) - - self.E2 = -( af.shift(electric_potential, 0, -1) - - af.shift(electric_potential, 0, 1) - ) / (2 * self.dq2) - - af.eval(self.E1, self.E2) + ((i_q1_start, i_q2_start), (N_q1_local, N_q2_local)) = self._da_snes.getCorners() + + snes = PETSc.SNES().create() + pde = poisson_eqn(self) + snes.setFunction(pde.compute_residual, self.glob_residual) + + snes.setDM(self._da_snes) + snes.setFromOptions() + snes.solve(None, self.glob_phi) + + phi_array = self.glob_phi.getArray() + print("phi = ", phi_array) + + + +# pde = Poisson2D(self) +# phi = self._da_ksp.createGlobalVec() +# rho = self._da_ksp.createGlobalVec() +# +# phi_local = self._da_ksp.createLocalVec() +# +# A = PETSc.Mat().createPython([phi.getSizes(), rho.getSizes()], +# comm=self._da_ksp.comm +# ) +# A.setPythonContext(pde) +# A.setUp() +# +# ksp = PETSc.KSP().create() +# +# ksp.setOperators(A) +# ksp.setType('cg') +# +# pc = ksp.getPC() +# pc.setType('none') +# +# N_g = self.N_ghost +# ksp.setTolerances(atol=1e-7) +# pde.RHS(rho, +# self.physical_system.params.charge_electron +# * np.array(self.compute_moments('density')[N_g:-N_g, +# N_g:-N_g +# ] +# - 1 +# ) +# ) +# +# ksp.setFromOptions() +# ksp.solve(rho, phi) +# +# num_tries = 0 +# while(ksp.converged is not True): +# +# ksp.setTolerances(atol = 10**(-6+num_tries), rtol = 10**(-6+num_tries)) +# ksp.solve(rho, phi) +# num_tries += 1 +# +# if(num_tries == 5): +# raise Exception('KSP solver diverging!') +# +# self._da_ksp.globalToLocal(phi, phi_local) + +# # Since rho was defined at (i + 0.5, j + 0.5) +# # Electric Potential returned will also be at (i + 0.5, j + 0.5) +# electric_potential = af.to_array(np.swapaxes(phi_local[:]. +# reshape( N_q2_local +# + 2 * self.N_ghost, +# N_q1_local + +# + 2 * self.N_ghost +# ), +# 0, 1 +# ) +# ) +# +# # Obtaining the values at (i+0.5, j+0.5): +# self.E1 = -( af.shift(electric_potential, -1) +# - af.shift(electric_potential, 1) +# ) / (2 * self.dq1) +# +# self.E2 = -( af.shift(electric_potential, 0, -1) +# - af.shift(electric_potential, 0, 1) +# ) / (2 * self.dq2) +# +# af.eval(self.E1, self.E2) if(performance_test_flag == True): af.sync() diff --git a/bolt/lib/nonlinear_solver/nonlinear_solver.py b/bolt/lib/nonlinear_solver/nonlinear_solver.py index 677ff0ed..dc6a5871 100644 --- a/bolt/lib/nonlinear_solver/nonlinear_solver.py +++ b/bolt/lib/nonlinear_solver/nonlinear_solver.py @@ -143,16 +143,16 @@ def __init__(self, physical_system): # Additionally, a DA object also needs to be created for the KSP solver # with a DOF of 1: - self._da_ksp = PETSc.DMDA().create([self.N_q1, self.N_q2], - stencil_width = self.N_ghost, - boundary_type = (self.bc_in_q1, - self.bc_in_q2 - ), - proc_sizes = (PETSc.DECIDE, - PETSc.DECIDE - ), - stencil_type = 1, - comm = self._comm) + self._da_snes = PETSc.DMDA().create([self.N_q1, self.N_q2], + stencil_width = self.N_ghost, + boundary_type = (self.bc_in_q1, + self.bc_in_q2 + ), + proc_sizes = (PETSc.DECIDE, + PETSc.DECIDE + ), + stencil_type = 1, + comm = self._comm) self._da_dump_moments = PETSc.DMDA().create([self.N_q1, self.N_q2], dof = len(self. @@ -174,6 +174,12 @@ def __init__(self, physical_system): # the communication routines for EM fields self._glob_fields = self._da_fields.createGlobalVec() self._local_fields = self._da_fields.createLocalVec() + + self.glob_phi = self._da_snes.createGlobalVec() + self.glob_residual = self._da_snes.createGlobalVec() + self.glob_phi.set(0.) + self.glob_residual.set(0.) + # The following vector is used to dump the data to file: self._glob_moments = self._da_dump_moments.createGlobalVec() diff --git a/bolt/lib/nonlinear_solver/tests/test_compute_electrostatic_fields.py b/bolt/lib/nonlinear_solver/tests/test_compute_electrostatic_fields.py index f7bc7234..167dec30 100644 --- a/bolt/lib/nonlinear_solver/tests/test_compute_electrostatic_fields.py +++ b/bolt/lib/nonlinear_solver/tests/test_compute_electrostatic_fields.py @@ -57,7 +57,8 @@ def __init__(self, N): self.dq1 = (self.q1_end - self.q1_start) / self.N_q1 self.dq2 = (self.q2_end - self.q2_start) / self.N_q2 - self.N_ghost = np.random.randint(3, 5) + #self.N_ghost = np.random.randint(3, 5) + self.N_ghost = 3 self.q1 = self.q1_start \ + (0.5 + np.arange(-self.N_ghost, @@ -87,12 +88,15 @@ def __init__(self, N): self._comm = PETSc.COMM_WORLD.tompi4py() - self._da_ksp = PETSc.DMDA().create([self.N_q1, self.N_q2], + self._da_snes = PETSc.DMDA().create([self.N_q1, self.N_q2], stencil_width=self.N_ghost, boundary_type=('periodic', 'periodic'), stencil_type=1, - ) + ) + self.glob_residual = self._da_snes.createGlobalVec() + self.glob_phi = self._da_snes.createGlobalVec() + self.glob_phi.set(0.) compute_moments = compute_moments_sinusoidal @@ -140,38 +144,41 @@ def test_compute_electrostatic_fields_2(): error_E1 = np.zeros(5) error_E2 = np.zeros(5) - N = 2**np.arange(5, 10) - - for i in range(N.size): - obj = test(N[i]) - compute_electrostatic_fields(obj) - - E1_expected = 0 * obj.q1 - - q2_minus = 0.25 - q2_plus = 0.75 - - E2_expected = -0.5/20 * ( af.log(af.cosh(( obj.q2 - q2_minus)*20)) - - af.log(af.cosh(( obj.q2 - q2_plus )*20)) - ) - - N_g = obj.N_ghost - - error_E1[i] = af.sum(af.abs( obj.E1[N_g:-N_g, N_g:-N_g] - - E1_expected[N_g:-N_g, N_g:-N_g] - ) - ) / (obj.E1[N_g:-N_g, N_g:-N_g].elements()) - - error_E2[i] = af.sum(af.abs( obj.E2[N_g:-N_g, N_g:-N_g] - - E2_expected[N_g:-N_g, N_g:-N_g] - ) - ) / (obj.E2[N_g:-N_g, N_g:-N_g].elements()) - - poly_E1 = np.polyfit(np.log10(N), np.log10(error_E1), 1) - poly_E2 = np.polyfit(np.log10(N), np.log10(error_E2), 1) - - assert (abs(poly_E1[0] + 2) < 0.2) - assert (abs(poly_E2[0] + 2) < 0.2) + obj = test(49) + compute_electrostatic_fields(obj) + +# N = 2**np.arange(5, 10) +# +# for i in range(N.size): +# obj = test(N[i]) +# compute_electrostatic_fields(obj) +# +# E1_expected = 0 * obj.q1 +# +# q2_minus = 0.25 +# q2_plus = 0.75 +# +# E2_expected = -0.5/20 * ( af.log(af.cosh(( obj.q2 - q2_minus)*20)) +# - af.log(af.cosh(( obj.q2 - q2_plus )*20)) +# ) +# +# N_g = obj.N_ghost +# +# error_E1[i] = af.sum(af.abs( obj.E1[N_g:-N_g, N_g:-N_g] +# - E1_expected[N_g:-N_g, N_g:-N_g] +# ) +# ) / (obj.E1[N_g:-N_g, N_g:-N_g].elements()) +# +# error_E2[i] = af.sum(af.abs( obj.E2[N_g:-N_g, N_g:-N_g] +# - E2_expected[N_g:-N_g, N_g:-N_g] +# ) +# ) / (obj.E2[N_g:-N_g, N_g:-N_g].elements()) +# +# poly_E1 = np.polyfit(np.log10(N), np.log10(error_E1), 1) +# poly_E2 = np.polyfit(np.log10(N), np.log10(error_E2), 1) +# +# assert (abs(poly_E1[0] + 2) < 0.2) +# assert (abs(poly_E2[0] + 2) < 0.2) test_compute_electrostatic_fields_2() From e18df04cbcf035702352533de0b702b6197d7c4a Mon Sep 17 00:00:00 2001 From: Mani Chandra Date: Fri, 29 Sep 2017 03:32:06 +0530 Subject: [PATCH 03/28] Got residual assembly for f(x) = x^2 - 2. over [N_q1, N_q2] working with both numpy and arrarfire arrays --- .../EM_fields_solver/electrostatic.py | 46 +++++++- bolt/lib/nonlinear_solver/nonlinear_solver.py | 1 + .../test_compute_electrostatic_fields.py | 104 +++++++++++------- 3 files changed, 104 insertions(+), 47 deletions(-) diff --git a/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py b/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py index 8c3146d3..d78509b6 100644 --- a/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py +++ b/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py @@ -5,6 +5,7 @@ import arrayfire as af import numpy as np from numpy.fft import fftfreq +import sys class poisson_eqn(object): @@ -20,16 +21,51 @@ def __init__(self, nonlinear_solver_obj): self.da = nonlinear_solver_obj._da_snes self.obj = nonlinear_solver_obj self.local_phi = self.da.createLocalVec() # phi with ghost zones + self.N_ghost = self.obj.N_ghost + + ((i_q1_start, i_q2_start), (N_q1_local, N_q2_local)) = \ + self.da.getCorners() + + self.N_q1_local = N_q1_local + self.N_q2_local = N_q2_local def compute_residual(self, snes, phi, residual): - #self.da.globalToLocal(phi, self.local_phi) + self.da.globalToLocal(phi, self.local_phi) + + N_g = self.N_ghost + + # Residual assembly using numpy + phi_array = self.local_phi.getArray(readonly=1) + phi_array = phi_array.reshape([self.N_q2_local + 2*N_g, \ + self.N_q1_local + 2*N_g, 1], \ + order='A' + ) - #phi_array = self.local_phi.getArray(readonly=1) - phi_array = phi.getArray(readonly=1) residual_array = residual.getArray(readonly=0) - - residual_array[:] = phi_array**2. - 2. + residual_array = residual_array.reshape([self.N_q2_local, \ + self.N_q1_local, 1], \ + order='A' + ) + + residual_array[:, :, :] = phi_array[N_g:-N_g, N_g:-N_g, :]**2. - 2. + + # Residual assembly using arrayfire +# phi_array = self.local_phi.getArray(readonly=1) +# phi_af_array = af.to_array(phi_array) +# phi_af_array = af.moddims(phi_af_array, +# self.N_q1_local + 2*N_g, +# self.N_q2_local + 2*N_g +# ) +# +# residual_af_array = phi_af_array[N_g:-N_g, N_g:-N_g]**2. - 2. +# residual_af_array = af.moddims(residual_af_array, +# self.N_q1_local +# * self.N_q2_local +# ) +# residual_array = residual.getArray(readonly=0) +# residual_array[:] = residual_af_array.to_ndarray() + return def compute_electrostatic_fields(self, performance_test_flag = False): diff --git a/bolt/lib/nonlinear_solver/nonlinear_solver.py b/bolt/lib/nonlinear_solver/nonlinear_solver.py index dc6a5871..c95f50cf 100644 --- a/bolt/lib/nonlinear_solver/nonlinear_solver.py +++ b/bolt/lib/nonlinear_solver/nonlinear_solver.py @@ -152,6 +152,7 @@ def __init__(self, physical_system): PETSc.DECIDE ), stencil_type = 1, + dof = 1, comm = self._comm) self._da_dump_moments = PETSc.DMDA().create([self.N_q1, self.N_q2], diff --git a/bolt/lib/nonlinear_solver/tests/test_compute_electrostatic_fields.py b/bolt/lib/nonlinear_solver/tests/test_compute_electrostatic_fields.py index 167dec30..d679ff63 100644 --- a/bolt/lib/nonlinear_solver/tests/test_compute_electrostatic_fields.py +++ b/bolt/lib/nonlinear_solver/tests/test_compute_electrostatic_fields.py @@ -37,7 +37,7 @@ def compute_moments_gaussian(self, *args): return(rho) class test(object): - def __init__(self, N): + def __init__(self, N_q1, N_q2): # Creating an object with necessary attributes: self.physical_system = type('obj', (object, ), {'params': type('obj', (object, ), @@ -51,8 +51,8 @@ def __init__(self, N): self.q1_end = 1 self.q2_end = 1 - self.N_q1 = N - self.N_q2 = N + self.N_q1 = N_q1 + self.N_q2 = N_q2 self.dq1 = (self.q1_end - self.q1_start) / self.N_q1 self.dq2 = (self.q2_end - self.q2_start) / self.N_q2 @@ -93,59 +93,79 @@ def __init__(self, N): boundary_type=('periodic', 'periodic'), stencil_type=1, + dof = 1 ) self.glob_residual = self._da_snes.createGlobalVec() self.glob_phi = self._da_snes.createGlobalVec() self.glob_phi.set(0.) - compute_moments = compute_moments_sinusoidal - -def test_compute_electrostatic_fields_1(): - - error_E1 = np.zeros(5) - error_E2 = np.zeros(5) - - N = 2**np.arange(5, 10) - - for i in range(N.size): - obj = test(N[i]) - compute_electrostatic_fields(obj) - - E1_expected = (0.1 / np.pi) \ - * af.cos( 2 * np.pi * obj.q1 - + 4 * np.pi * obj.q2 - ) - - E2_expected = (0.2 / np.pi) \ - * af.cos( 2 * np.pi * obj.q1 - + 4 * np.pi * obj.q2 - ) - - N_g = obj.N_ghost - - error_E1[i] = af.sum(af.abs( obj.E1[N_g:-N_g, N_g:-N_g] - - E1_expected[N_g:-N_g, N_g:-N_g] - ) - ) / (obj.E1[N_g:-N_g, N_g:-N_g].elements()) - - error_E2[i] = af.sum(af.abs( obj.E2[N_g:-N_g, N_g:-N_g] - - E2_expected[N_g:-N_g, N_g:-N_g] - ) - ) / (obj.E2[N_g:-N_g, N_g:-N_g].elements()) + self._da_test = PETSc.DMDA().create([self.N_q1, self.N_q2], + stencil_width=self.N_ghost, + boundary_type=('ghosted', + 'ghosted'), + stencil_type=1, + dof = 1 + ) + self.glob_vec = self._da_test.createGlobalVec() - poly_E1 = np.polyfit(np.log10(N), np.log10(error_E1), 1) - poly_E2 = np.polyfit(np.log10(N), np.log10(error_E2), 1) + compute_moments = compute_moments_sinusoidal - assert (abs(poly_E1[0] + 2) < 0.2) - assert (abs(poly_E2[0] + 2) < 0.2) +#def test_compute_electrostatic_fields_1(): +# +# error_E1 = np.zeros(5) +# error_E2 = np.zeros(5) +# +# N = 2**np.arange(5, 10) +# +# for i in range(N.size): +# obj = test(N[i]) +# compute_electrostatic_fields(obj) +# +# E1_expected = (0.1 / np.pi) \ +# * af.cos( 2 * np.pi * obj.q1 +# + 4 * np.pi * obj.q2 +# ) +# +# E2_expected = (0.2 / np.pi) \ +# * af.cos( 2 * np.pi * obj.q1 +# + 4 * np.pi * obj.q2 +# ) +# +# N_g = obj.N_ghost +# +# error_E1[i] = af.sum(af.abs( obj.E1[N_g:-N_g, N_g:-N_g] +# - E1_expected[N_g:-N_g, N_g:-N_g] +# ) +# ) / (obj.E1[N_g:-N_g, N_g:-N_g].elements()) +# +# error_E2[i] = af.sum(af.abs( obj.E2[N_g:-N_g, N_g:-N_g] +# - E2_expected[N_g:-N_g, N_g:-N_g] +# ) +# ) / (obj.E2[N_g:-N_g, N_g:-N_g].elements()) +# +# poly_E1 = np.polyfit(np.log10(N), np.log10(error_E1), 1) +# poly_E2 = np.polyfit(np.log10(N), np.log10(error_E2), 1) +# +# assert (abs(poly_E1[0] + 2) < 0.2) +# assert (abs(poly_E2[0] + 2) < 0.2) def test_compute_electrostatic_fields_2(): error_E1 = np.zeros(5) error_E2 = np.zeros(5) - obj = test(49) + obj = test(14, 7) compute_electrostatic_fields(obj) +# print(obj.glob_phi.getArray().reshape([49, 35], order='A').strides) +# print(obj.glob_vec.getArray().reshape([49, 35, 10], order='A').strides) + +# obj.glob_vec.set(3.) +# local_vec = obj._da_test.createLocalVec() +# obj._da_test.globalToLocal(obj.glob_vec, local_vec) +# local_vec_array_direct = local_vec.getArray().reshape([7 + 6, 14+6, 2], +# order='c') +# print(local_vec_array_direct) +# print(local_vec_array_direct.strides) # N = 2**np.arange(5, 10) # From 1a2961e1fd72c3fce7bfeb628dc4362963defae0 Mon Sep 17 00:00:00 2001 From: Mani Chandra Date: Fri, 6 Oct 2017 16:51:55 +0530 Subject: [PATCH 04/28] Poisson solver now works with SNES. * Periodic BCs work once background density has been subtracted correctly --- .../EM_fields_solver/electrostatic.py | 210 ++++++++++++------ .../test_compute_electrostatic_fields.py | 148 ++++++------ 2 files changed, 215 insertions(+), 143 deletions(-) diff --git a/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py b/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py index d78509b6..87364fd8 100644 --- a/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py +++ b/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py @@ -5,8 +5,36 @@ import arrayfire as af import numpy as np from numpy.fft import fftfreq -import sys - +import pylab as pl + +pl.rcParams['figure.figsize'] = 17, 7.5 +pl.rcParams['figure.dpi'] = 150 +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'] = 20 +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' class poisson_eqn(object): """ @@ -22,6 +50,9 @@ def __init__(self, nonlinear_solver_obj): self.obj = nonlinear_solver_obj self.local_phi = self.da.createLocalVec() # phi with ghost zones self.N_ghost = self.obj.N_ghost + self.dq1 = self.obj.dq1 + self.dq2 = self.obj.dq2 + self.density = 0. ((i_q1_start, i_q2_start), (N_q1_local, N_q2_local)) = \ self.da.getCorners() @@ -36,7 +67,7 @@ def compute_residual(self, snes, phi, residual): N_g = self.N_ghost # Residual assembly using numpy - phi_array = self.local_phi.getArray(readonly=1) + phi_array = self.local_phi.getArray(readonly=0) phi_array = phi_array.reshape([self.N_q2_local + 2*N_g, \ self.N_q1_local + 2*N_g, 1], \ order='A' @@ -48,7 +79,37 @@ def compute_residual(self, snes, phi, residual): order='A' ) - residual_array[:, :, :] = phi_array[N_g:-N_g, N_g:-N_g, :]**2. - 2. + #phi_array[:N_g, :] = 0. + #phi_array[self.N_q2_local+N_g:, :] = 0. + #phi_array[:, :N_g] = 0. + #phi_array[:, self.N_q1_local+N_g:] = 0. + + phi_plus_x = np.roll(phi_array, shift=-1, axis=1) + phi_minus_x = np.roll(phi_array, shift=1, axis=1) + phi_plus_y = np.roll(phi_array, shift=-1, axis=0) + phi_minus_y = np.roll(phi_array, shift=1, axis=0) + + d2phi_dx2 = (phi_minus_x - 2.*phi_array + phi_plus_x)/self.dq1**2. + d2phi_dy2 = (phi_minus_y - 2.*phi_array + phi_plus_y)/self.dq2**2. + + laplacian_phi = d2phi_dx2 + d2phi_dy2 + + density_af = af.moddims(self.density, + (self.N_q1_local+2*N_g) + * (self.N_q2_local+2*N_g) + ) + density_np = density_af.to_ndarray() + density_np = density_np.reshape([self.N_q2_local + 2*N_g, \ + self.N_q1_local + 2*N_g, 1], \ + order='A' + ) + + residual_array[:, :] = \ + (laplacian_phi + density_np)[N_g:-N_g, N_g:-N_g] + +# residual_array[:, :] = \ +# (laplacian_phi + self.density)[N_g:-N_g, N_g:-N_g] + # Residual assembly using arrayfire # phi_array = self.local_phi.getArray(readonly=1) @@ -77,6 +138,8 @@ def compute_electrostatic_fields(self, performance_test_flag = False): # (lowest values of the canonical coordinates in 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_snes.getCorners() + + N_g = self.N_ghost snes = PETSc.SNES().create() pde = poisson_eqn(self) @@ -84,81 +147,80 @@ def compute_electrostatic_fields(self, performance_test_flag = False): snes.setDM(self._da_snes) snes.setFromOptions() + pde.density = self.compute_moments('density') snes.solve(None, self.glob_phi) - phi_array = self.glob_phi.getArray() - print("phi = ", phi_array) - - - -# pde = Poisson2D(self) -# phi = self._da_ksp.createGlobalVec() -# rho = self._da_ksp.createGlobalVec() -# -# phi_local = self._da_ksp.createLocalVec() -# -# A = PETSc.Mat().createPython([phi.getSizes(), rho.getSizes()], -# comm=self._da_ksp.comm -# ) -# A.setPythonContext(pde) -# A.setUp() -# -# ksp = PETSc.KSP().create() -# -# ksp.setOperators(A) -# ksp.setType('cg') -# -# pc = ksp.getPC() -# pc.setType('none') -# -# N_g = self.N_ghost -# ksp.setTolerances(atol=1e-7) -# pde.RHS(rho, -# self.physical_system.params.charge_electron -# * np.array(self.compute_moments('density')[N_g:-N_g, -# N_g:-N_g -# ] -# - 1 -# ) -# ) -# -# ksp.setFromOptions() -# ksp.solve(rho, phi) -# -# num_tries = 0 -# while(ksp.converged is not True): -# -# ksp.setTolerances(atol = 10**(-6+num_tries), rtol = 10**(-6+num_tries)) -# ksp.solve(rho, phi) -# num_tries += 1 -# -# if(num_tries == 5): -# raise Exception('KSP solver diverging!') -# -# self._da_ksp.globalToLocal(phi, phi_local) - -# # Since rho was defined at (i + 0.5, j + 0.5) -# # Electric Potential returned will also be at (i + 0.5, j + 0.5) -# electric_potential = af.to_array(np.swapaxes(phi_local[:]. -# reshape( N_q2_local -# + 2 * self.N_ghost, -# N_q1_local + -# + 2 * self.N_ghost -# ), + #phi_array = self.glob_phi.getArray() + #print("phi = ", phi_array) + #phi_array = phi_array.reshape([N_q2_local, \ + # N_q1_local, 1], \ + # order='A' + # ) + + self._da_snes.globalToLocal(self.glob_phi, pde.local_phi) + phi_local_array = pde.local_phi.getArray() + electric_potential = af.to_array(phi_local_array) + phi_local_array = phi_local_array.reshape([N_q2_local + 2*N_g, \ + N_q1_local + 2*N_g], \ + ) + density_af = af.moddims(pde.density, + (N_q1_local+2*N_g) + * (N_q2_local+2*N_g) + ) + density_np = density_af.to_ndarray() + density_np = density_np.reshape([N_q2_local + 2*N_g, \ + N_q1_local + 2*N_g], \ + ) + # Since rho was defined at (i + 0.5, j + 0.5) + # Electric Potential returned will also be at (i + 0.5, j + 0.5) +# electric_potential = af.to_array(np.swapaxes(phi_local_array, # 0, 1 # ) # ) -# -# # Obtaining the values at (i+0.5, j+0.5): -# self.E1 = -( af.shift(electric_potential, -1) -# - af.shift(electric_potential, 1) -# ) / (2 * self.dq1) -# -# self.E2 = -( af.shift(electric_potential, 0, -1) -# - af.shift(electric_potential, 0, 1) -# ) / (2 * self.dq2) -# -# af.eval(self.E1, self.E2) + + electric_potential = af.moddims(electric_potential, + N_q1_local + 2*N_g, + N_q2_local + 2*N_g + ) + + # Obtaining the values at (i+0.5, j+0.5): + self.E1 = -( af.shift(electric_potential, -1) + - af.shift(electric_potential, 1) + ) / (2 * self.dq1) + + self.E2 = -( af.shift(electric_potential, 0, -1) + - af.shift(electric_potential, 0, 1) + ) / (2 * self.dq2) + + af.eval(self.E1, self.E2) + + q2_minus = 0.25 + q2_plus = 0.75 + + E2_expected = -0.5/20 * ( af.log(af.cosh(( self.q2 - q2_minus)*20)) + - af.log(af.cosh(( self.q2 - q2_plus )*20)) + ) + + pl.subplot(121) + pl.contourf( + #np.array(self.E2)[N_g:-N_g, N_g:-N_g], 100 + density_np[N_g:-N_g, N_g:-N_g], 100 + ) + pl.colorbar() + #pl.axis('equal') + pl.title(r'Density') + #pl.title(r'$E^2_{numerical}$') + pl.subplot(122) + pl.contourf( + #np.array(E2_expected)[N_g:-N_g, N_g:-N_g], 100 + phi_local_array[N_g:-N_g, N_g:-N_g], 100 + ) + pl.colorbar() + pl.title(r'$\phi$') + #pl.title(r'$E^2_{analytic}$') + #pl.axis('equal') + pl.show() + if(performance_test_flag == True): af.sync() diff --git a/bolt/lib/nonlinear_solver/tests/test_compute_electrostatic_fields.py b/bolt/lib/nonlinear_solver/tests/test_compute_electrostatic_fields.py index d679ff63..bcb35d2d 100644 --- a/bolt/lib/nonlinear_solver/tests/test_compute_electrostatic_fields.py +++ b/bolt/lib/nonlinear_solver/tests/test_compute_electrostatic_fields.py @@ -16,13 +16,19 @@ import petsc4py, sys petsc4py.init(sys.argv) from petsc4py import PETSc +import pylab as pl from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ import compute_electrostatic_fields def compute_moments_sinusoidal(self, *args): - return (1 + af.sin(2 * np.pi * self.q1 + 4 * np.pi * self.q2)) + rho = 1. + 0.1*af.sin(2 * np.pi * self.q1 + 4 * np.pi * self.q2) + + rho_mean = af.mean(rho) + print("rho_mean = ", rho_mean) + + return(rho - rho_mean) def compute_moments_gaussian(self, *args): q2_minus = 0.25 @@ -34,7 +40,26 @@ def compute_moments_gaussian(self, *args): - af.tanh(( self.q2 - q2_plus )*regulator) ) - return(rho) +# rho = af.exp(-0.*(self.q1 - 0.5)**2./0.01 - (self.q2 - 0.5)**2./0.01) +# rho = (self.q2 - 0.5)**2. + (self.q1 - 0.5)**2. + +# rho = 1. + 0.1*af.sin(2*np.pi*self.q2) + +# sigma = 0.1 +# rho = af.exp(-(self.q1)**2./(2.*sigma**2.) -(self.q2)**2./(2.*sigma**2.)) \ +# * 1./ sigma**2. / (2. * np.pi) + + N_g = self.N_ghost + net_charge = af.sum(rho[N_g:-N_g, N_g:-N_g]) * self.dq1 * self.dq2 + + total_volume = (self.q1_end - self.q1_start) \ + * (self.q2_end - self.q2_start) + + rho_zero_net_charge = rho - net_charge/total_volume + + print("Initial net charge = ", net_charge) + + return(rho_zero_net_charge) class test(object): def __init__(self, N_q1, N_q2): @@ -45,11 +70,11 @@ def __init__(self, N_q1, N_q2): } ) - self.q1_start = 0 - self.q2_start = 0 + self.q1_start = 0. + self.q2_start = 0. - self.q1_end = 1 - self.q2_end = 1 + self.q1_end = 1. + self.q2_end = 1. self.N_q1 = N_q1 self.N_q2 = N_q2 @@ -99,26 +124,18 @@ def __init__(self, N_q1, N_q2): self.glob_phi = self._da_snes.createGlobalVec() self.glob_phi.set(0.) - self._da_test = PETSc.DMDA().create([self.N_q1, self.N_q2], - stencil_width=self.N_ghost, - boundary_type=('ghosted', - 'ghosted'), - stencil_type=1, - dof = 1 - ) - self.glob_vec = self._da_test.createGlobalVec() + compute_moments = compute_moments_gaussian - compute_moments = compute_moments_sinusoidal +def test_compute_electrostatic_fields_1(): + obj = test(70, 70) + compute_electrostatic_fields(obj) -#def test_compute_electrostatic_fields_1(): -# -# error_E1 = np.zeros(5) -# error_E2 = np.zeros(5) -# -# N = 2**np.arange(5, 10) +# N = 7*np.array([2, 4, 6, 8, 10, 12]) +# error_E1 = np.zeros(N.size) +# error_E2 = np.zeros(N.size) # # for i in range(N.size): -# obj = test(N[i]) +# obj = test(N[i], N[i]) # compute_electrostatic_fields(obj) # # E1_expected = (0.1 / np.pi) \ @@ -143,6 +160,9 @@ def __init__(self, N_q1, N_q2): # ) # ) / (obj.E2[N_g:-N_g, N_g:-N_g].elements()) # +# print("Error E1 = ", error_E1) +# print("Error E2 = ", error_E2) +# # poly_E1 = np.polyfit(np.log10(N), np.log10(error_E1), 1) # poly_E2 = np.polyfit(np.log10(N), np.log10(error_E2), 1) # @@ -151,54 +171,44 @@ def __init__(self, N_q1, N_q2): def test_compute_electrostatic_fields_2(): - error_E1 = np.zeros(5) - error_E2 = np.zeros(5) + N = 7*np.array([2, 4, 6, 8, 10, 12]) + N = 7*np.array([12]) + error_E1 = np.zeros(N.size) + error_E2 = np.zeros(N.size) - obj = test(14, 7) - compute_electrostatic_fields(obj) -# print(obj.glob_phi.getArray().reshape([49, 35], order='A').strides) -# print(obj.glob_vec.getArray().reshape([49, 35, 10], order='A').strides) - -# obj.glob_vec.set(3.) -# local_vec = obj._da_test.createLocalVec() -# obj._da_test.globalToLocal(obj.glob_vec, local_vec) -# local_vec_array_direct = local_vec.getArray().reshape([7 + 6, 14+6, 2], -# order='c') -# print(local_vec_array_direct) -# print(local_vec_array_direct.strides) - -# N = 2**np.arange(5, 10) -# -# for i in range(N.size): -# obj = test(N[i]) -# compute_electrostatic_fields(obj) -# -# E1_expected = 0 * obj.q1 -# -# q2_minus = 0.25 -# q2_plus = 0.75 -# -# E2_expected = -0.5/20 * ( af.log(af.cosh(( obj.q2 - q2_minus)*20)) -# - af.log(af.cosh(( obj.q2 - q2_plus )*20)) -# ) -# -# N_g = obj.N_ghost -# -# error_E1[i] = af.sum(af.abs( obj.E1[N_g:-N_g, N_g:-N_g] -# - E1_expected[N_g:-N_g, N_g:-N_g] -# ) -# ) / (obj.E1[N_g:-N_g, N_g:-N_g].elements()) -# -# error_E2[i] = af.sum(af.abs( obj.E2[N_g:-N_g, N_g:-N_g] -# - E2_expected[N_g:-N_g, N_g:-N_g] -# ) -# ) / (obj.E2[N_g:-N_g, N_g:-N_g].elements()) -# -# poly_E1 = np.polyfit(np.log10(N), np.log10(error_E1), 1) -# poly_E2 = np.polyfit(np.log10(N), np.log10(error_E2), 1) -# -# assert (abs(poly_E1[0] + 2) < 0.2) -# assert (abs(poly_E2[0] + 2) < 0.2) + for i in range(N.size): + obj = test(N[i], N[i]) + compute_electrostatic_fields(obj) + + E1_expected = 0 * obj.q1 + + q2_minus = 0.25 + q2_plus = 0.75 + + E2_expected = -0.5/20 * ( af.log(af.cosh(( obj.q2 - q2_minus)*20)) + - af.log(af.cosh(( obj.q2 - q2_plus )*20)) + ) + + N_g = obj.N_ghost + + error_E1[i] = af.sum(af.abs( obj.E1[N_g:-N_g, N_g:-N_g] + - E1_expected[N_g:-N_g, N_g:-N_g] + ) + ) / (obj.E1[N_g:-N_g, N_g:-N_g].elements()) + + error_E2[i] = af.sum(af.abs( obj.E2[N_g:-N_g, N_g:-N_g] + - E2_expected[N_g:-N_g, N_g:-N_g] + ) + ) / (obj.E2[N_g:-N_g, N_g:-N_g].elements()) + + print("Error E1 = ", error_E1) + print("Error E2 = ", error_E2) + + poly_E1 = np.polyfit(np.log10(N), np.log10(error_E1), 1) + poly_E2 = np.polyfit(np.log10(N), np.log10(error_E2), 1) + + assert (abs(poly_E1[0] + 2) < 0.2) + assert (abs(poly_E2[0] + 2) < 0.2) test_compute_electrostatic_fields_2() From d84a745793906cf1b366eaf05986f176d62db256 Mon Sep 17 00:00:00 2001 From: Mani Chandra Date: Tue, 10 Oct 2017 00:41:14 +0530 Subject: [PATCH 05/28] First iteration of 3D poisson solver + 2D charge density. Code in tests/ --- .../test_3D_poisson_solver_2D_density.py | 234 ++++++++++++++++++ 1 file changed, 234 insertions(+) create mode 100644 bolt/lib/nonlinear_solver/tests/test_3D_poisson_solver_2D_density.py diff --git a/bolt/lib/nonlinear_solver/tests/test_3D_poisson_solver_2D_density.py b/bolt/lib/nonlinear_solver/tests/test_3D_poisson_solver_2D_density.py new file mode 100644 index 00000000..00b82598 --- /dev/null +++ b/bolt/lib/nonlinear_solver/tests/test_3D_poisson_solver_2D_density.py @@ -0,0 +1,234 @@ + +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import petsc4py, sys +petsc4py.init(sys.argv) +from petsc4py import PETSc +import arrayfire as af +import numpy as np +import pylab as pl + +pl.rcParams['figure.figsize'] = 17, 7.5 +pl.rcParams['figure.dpi'] = 150 +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'] = 20 +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' + +comm = PETSc.COMM_WORLD.tompi4py() + +N_q1_poisson = 70 +N_q2_poisson = 70 +N_q3_poisson = 70 + +N_q1_density = 35 +N_q2_density = 35 + +N_ghost = 3 + +da_3D = PETSc.DMDA().create([N_q1_poisson, + N_q2_poisson, + N_q3_poisson], + stencil_width = N_ghost, + boundary_type = ('periodic', + 'periodic', + 'periodic' + ), + stencil_type = 1, + dof = 1, + comm = comm + ) + +glob_phi = da_3D.createGlobalVec() +local_phi = da_3D.createLocalVec() +glob_residual = da_3D.createGlobalVec() + +((i_q1_3D_start, i_q2_3D_start, i_q3_3D_start), + (N_q1_3D_local, N_q2_3D_local, N_q3_3D_local) +) = \ + da_3D.getCorners() + +q1_3D_start = -2.; q1_3D_end = 2. +q2_3D_start = -2.; q2_3D_end = 2. +q3_3D_start = 0.; q3_3D_end = 2. + +dq1_3D = (q1_3D_end - q1_3D_start) / N_q1_poisson +dq2_3D = (q2_3D_end - q2_3D_start) / N_q2_poisson +dq3_3D = (q3_3D_end - q3_3D_start) / N_q3_poisson + +i_q1_3D = ( (i_q1_3D_start + 0.5) + + np.arange(-N_ghost, N_q1_3D_local + N_ghost) + ) + +i_q2_3D = ( (i_q2_3D_start + 0.5) + + np.arange(-N_ghost, N_q2_3D_local + N_ghost) + ) + +i_q3_3D = ( (i_q3_3D_start + 0.5) + + np.arange(-N_ghost, N_q3_3D_local + N_ghost) + ) + +q1_3D = q1_3D_start + i_q1_3D * dq1_3D +q2_3D = q2_3D_start + i_q2_3D * dq2_3D +q3_3D = q3_3D_start + i_q3_3D * dq3_3D + +da_2D = PETSc.DMDA().create([N_q1_density, + N_q2_density], + stencil_width = N_ghost, + boundary_type = ('periodic', + 'periodic' + ), + stencil_type = 1, + dof = 1, + comm = comm + ) + +glob_density = da_2D.createGlobalVec() +local_density = da_2D.createLocalVec() + + +((i_q1_2D_start, i_q2_2D_start), + (N_q1_2D_local, N_q2_2D_local) +) = \ + da_2D.getCorners() + +q1_2D_start = -1.; q1_2D_end = 1. +q2_2D_start = -1.; q2_2D_end = 1. +location_in_q3 = 1. + +dq1_2D = (q1_2D_end - q1_2D_start) / N_q1_density +dq2_2D = (q2_2D_end - q2_2D_start) / N_q2_density + +i_q1_2D = ( (i_q1_2D_start + 0.5) + + np.arange(-N_ghost, N_q1_2D_local + N_ghost) + ) + +i_q2_2D = ( (i_q2_2D_start + 0.5) + + np.arange(-N_ghost, N_q2_2D_local + N_ghost) + ) + +q1_2D = q1_2D_start + i_q1_2D * dq1_2D +q2_2D = q2_2D_start + i_q2_2D * dq2_2D + +glob_density_array = glob_density.getArray(readonly=0) +glob_density_array = glob_density_array.reshape([N_q2_2D_local, \ + N_q1_2D_local, 1], \ + ) +glob_density_array[:] = 1. + +da_2D.globalToLocal(glob_density, local_density) + +density_array = local_density.getArray(readonly=0) +density_array = density_array.reshape([N_q2_2D_local + 2*N_ghost, \ + N_q1_2D_local + 2*N_ghost, 1], \ + ) + +print("rank = ", comm.rank) + +# Figure out the coordinates of the 3D phi cube of the current rank +print("q1_3D_start = ", q1_3D[N_ghost]) +print("q2_3D_start = ", q2_3D[N_ghost]) +print("q3_3D_start = ", q3_3D[N_ghost]) +print(" ") +print("q1_2D_start = ", q1_2D[N_ghost]) +print("q2_2D_start = ", q2_2D[N_ghost]) + +q1_2D_in_3D_index_start = np.where(q1_3D > q1_2D[0] - dq1_3D)[0][0] +q1_2D_in_3D_index_end = np.where(q1_3D < q1_2D[-1] + dq1_3D)[0][-1] +q2_2D_in_3D_index_start = np.where(q2_3D > q2_2D[0] - dq2_3D)[0][0] +q2_2D_in_3D_index_end = np.where(q2_3D < q2_2D[-1] + dq2_3D)[0][-1] +q3_2D_in_3D_index_start = np.where(q3_3D > location_in_q3 - dq3_3D)[0][0] +q3_2D_in_3D_index_end = np.where(q3_3D < location_in_q3 + dq3_3D)[0][-1] + +print("q1_2D_in_3D_index_start = ", q1_2D_in_3D_index_start, "q1_3D_start = ", q1_3D[q1_2D_in_3D_index_start]) +print("q1_2D_in_3D_index_end = ", q1_2D_in_3D_index_end, "q1_3D_end = ", q1_3D[q1_2D_in_3D_index_end]) +print("q2_2D_in_3D_index_start = ", q2_2D_in_3D_index_start, "q2_3D_start = ", q2_3D[q2_2D_in_3D_index_start]) +print("q2_2D_in_3D_index_end = ", q2_2D_in_3D_index_end, "q2_3D_end = ", q2_3D[q2_2D_in_3D_index_end]) +print("q3_2D_in_3D_index_start = ", q3_2D_in_3D_index_start, "q3_3D_start = ", q3_3D[q3_2D_in_3D_index_start]) +print("q3_2D_in_3D_index_end = ", q3_2D_in_3D_index_end, "q3_3D_end = ", q3_3D[q3_2D_in_3D_index_end]) + +class poisson_eqn(object): + + def __init__(self): + self.local_phi = local_phi + + def compute_residual(self, snes, phi, residual): + da_3D.globalToLocal(phi, local_phi) + + N_g = N_ghost + + phi_array = local_phi.getArray(readonly=0) + phi_array = phi_array.reshape([N_q3_3D_local + 2*N_g, \ + N_q2_3D_local + 2*N_g, \ + N_q1_3D_local + 2*N_g, 1 + ] + ) + + residual_array = residual.getArray(readonly=0) + residual_array = residual_array.reshape([N_q3_3D_local, \ + N_q2_3D_local, \ + N_q1_3D_local, 1 + ] + ) + + phi_array[:N_ghost, :, :] = 0. + phi_array[N_q1_3D_local+N_ghost:, :, :] = 0. + phi_array[:, :N_ghost, :] = 0. + phi_array[:, N_q2_3D_local+N_ghost:, :] = 0. + phi_array[:, :, :N_ghost] = 0. + phi_array[:, :, N_q3_3D_local+N_ghost:] = 0. + + phi_plus_x = np.roll(phi_array, shift=-1, axis=2) + phi_minus_x = np.roll(phi_array, shift=1, axis=2) + phi_plus_y = np.roll(phi_array, shift=-1, axis=1) + phi_minus_y = np.roll(phi_array, shift=1, axis=1) + phi_plus_z = np.roll(phi_array, shift=-1, axis=0) + phi_minus_z = np.roll(phi_array, shift=1, axis=0) + + d2phi_dx2 = (phi_minus_x - 2.*phi_array + phi_plus_x)/dq1_3D**2. + d2phi_dy2 = (phi_minus_y - 2.*phi_array + phi_plus_y)/dq2_3D**2. + d2phi_dz2 = (phi_minus_z - 2.*phi_array + phi_plus_z)/dq3_3D**2. + + laplacian_phi = d2phi_dx2 + d2phi_dy2 + d2phi_dz2 + + laplacian_phi[q3_2D_in_3D_index_start:q3_2D_in_3D_index_end, + q2_2D_in_3D_index_start:q2_2D_in_3D_index_end, + q1_2D_in_3D_index_start:q1_2D_in_3D_index_end + ] \ + += density_array + + residual_array[:, :, :] = \ + laplacian_phi[N_g:-N_g, N_g:-N_g, N_g:-N_g] + + return + +snes = PETSc.SNES().create() +pde = poisson_eqn() +snes.setFunction(pde.compute_residual, glob_residual) + +snes.setDM(da_3D) +snes.setFromOptions() +snes.solve(None, glob_phi) From cf85dc4d30d9dd037367c827ced110ea8a7d6c9d Mon Sep 17 00:00:00 2001 From: Mani Chandra Date: Tue, 10 Oct 2017 21:36:05 +0530 Subject: [PATCH 06/28] backup commit --- .../test_3D_poisson_solver_2D_density.py | 45 ++++++++++++------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/bolt/lib/nonlinear_solver/tests/test_3D_poisson_solver_2D_density.py b/bolt/lib/nonlinear_solver/tests/test_3D_poisson_solver_2D_density.py index 00b82598..947ff283 100644 --- a/bolt/lib/nonlinear_solver/tests/test_3D_poisson_solver_2D_density.py +++ b/bolt/lib/nonlinear_solver/tests/test_3D_poisson_solver_2D_density.py @@ -40,14 +40,14 @@ comm = PETSc.COMM_WORLD.tompi4py() -N_q1_poisson = 70 -N_q2_poisson = 70 -N_q3_poisson = 70 +N_q1_poisson = 69 +N_q2_poisson = 69 +N_q3_poisson = 69 -N_q1_density = 35 -N_q2_density = 35 +N_q1_density = 69 +N_q2_density = 69 -N_ghost = 3 +N_ghost = 1 da_3D = PETSc.DMDA().create([N_q1_poisson, N_q2_poisson, @@ -71,8 +71,8 @@ ) = \ da_3D.getCorners() -q1_3D_start = -2.; q1_3D_end = 2. -q2_3D_start = -2.; q2_3D_end = 2. +q1_3D_start = -1.; q1_3D_end = 1. +q2_3D_start = -1.; q2_3D_end = 1. q3_3D_start = 0.; q3_3D_end = 2. dq1_3D = (q1_3D_end - q1_3D_start) / N_q1_poisson @@ -147,6 +147,13 @@ ) print("rank = ", comm.rank) +offset = 2*N_ghost-1 +print("i_q1_local_3D = [", i_q1_3D_start, ",", i_q1_3D_start+N_q1_3D_local+offset, "]") +print("i_q2_local_3D = [", i_q2_3D_start, ",", i_q2_3D_start+N_q2_3D_local+offset, "]") +print("i_q3_local_3D = [", i_q3_3D_start, ",", i_q3_3D_start+N_q3_3D_local+offset, "]") +print(" ") +print("i_q1_local_2D = [", i_q1_2D_start, ",", i_q1_2D_start+N_q2_2D_local+offset, "]") +print("i_q2_local_2D = [", i_q2_2D_start, ",", i_q2_2D_start+N_q2_2D_local+offset, "]") # Figure out the coordinates of the 3D phi cube of the current rank print("q1_3D_start = ", q1_3D[N_ghost]) @@ -194,10 +201,10 @@ def compute_residual(self, snes, phi, residual): ] ) - phi_array[:N_ghost, :, :] = 0. - phi_array[N_q1_3D_local+N_ghost:, :, :] = 0. - phi_array[:, :N_ghost, :] = 0. - phi_array[:, N_q2_3D_local+N_ghost:, :] = 0. + #phi_array[:N_ghost, :, :] = 0. + #phi_array[N_q1_3D_local+N_ghost:, :, :] = 0. + #phi_array[:, :N_ghost, :] = 0. + #phi_array[:, N_q2_3D_local+N_ghost:, :] = 0. phi_array[:, :, :N_ghost] = 0. phi_array[:, :, N_q3_3D_local+N_ghost:] = 0. @@ -214,11 +221,15 @@ def compute_residual(self, snes, phi, residual): laplacian_phi = d2phi_dx2 + d2phi_dy2 + d2phi_dz2 - laplacian_phi[q3_2D_in_3D_index_start:q3_2D_in_3D_index_end, - q2_2D_in_3D_index_start:q2_2D_in_3D_index_end, - q1_2D_in_3D_index_start:q1_2D_in_3D_index_end - ] \ - += density_array +# laplacian_phi[q3_2D_in_3D_index_start:q3_2D_in_3D_index_end, +# q2_2D_in_3D_index_start:q2_2D_in_3D_index_end, +# q1_2D_in_3D_index_start:q1_2D_in_3D_index_end +# ] \ +# += density_array + + print(density_array.shape) + print(laplacian_phi[35:35, 0:70, 0:70].shape) +# laplacian_phi[35:35, 0:70, 0:70] += density_array residual_array[:, :, :] = \ laplacian_phi[N_g:-N_g, N_g:-N_g, N_g:-N_g] From 5cbe20142becdbe4f4883a0db1ba74442ca2e400 Mon Sep 17 00:00:00 2001 From: Mani Chandra Date: Fri, 3 Nov 2017 15:02:48 +0530 Subject: [PATCH 07/28] 3D poisson solver + 2D density in tests/ * with side gates * back gate * dielectric substrate --- .../test_3D_poisson_solver_2D_density.py | 317 ++++++++++++------ 1 file changed, 222 insertions(+), 95 deletions(-) diff --git a/bolt/lib/nonlinear_solver/tests/test_3D_poisson_solver_2D_density.py b/bolt/lib/nonlinear_solver/tests/test_3D_poisson_solver_2D_density.py index 947ff283..07decc7c 100644 --- a/bolt/lib/nonlinear_solver/tests/test_3D_poisson_solver_2D_density.py +++ b/bolt/lib/nonlinear_solver/tests/test_3D_poisson_solver_2D_density.py @@ -9,7 +9,7 @@ import numpy as np import pylab as pl -pl.rcParams['figure.figsize'] = 17, 7.5 +pl.rcParams['figure.figsize'] = 20, 7.5 pl.rcParams['figure.dpi'] = 150 pl.rcParams['image.cmap'] = 'jet' pl.rcParams['lines.linewidth'] = 1.5 @@ -40,61 +40,17 @@ comm = PETSc.COMM_WORLD.tompi4py() -N_q1_poisson = 69 -N_q2_poisson = 69 -N_q3_poisson = 69 - -N_q1_density = 69 -N_q2_density = 69 +N_q1_density = 33 +N_q2_density = 33 N_ghost = 1 -da_3D = PETSc.DMDA().create([N_q1_poisson, - N_q2_poisson, - N_q3_poisson], - stencil_width = N_ghost, - boundary_type = ('periodic', - 'periodic', - 'periodic' - ), - stencil_type = 1, - dof = 1, - comm = comm - ) - -glob_phi = da_3D.createGlobalVec() -local_phi = da_3D.createLocalVec() -glob_residual = da_3D.createGlobalVec() - -((i_q1_3D_start, i_q2_3D_start, i_q3_3D_start), - (N_q1_3D_local, N_q2_3D_local, N_q3_3D_local) -) = \ - da_3D.getCorners() +q1_2D_start = -.5; q1_2D_end = 0.5 +q2_2D_start = -.5; q2_2D_end = 0.5 +location_in_q3 = 1. -q1_3D_start = -1.; q1_3D_end = 1. -q2_3D_start = -1.; q2_3D_end = 1. q3_3D_start = 0.; q3_3D_end = 2. -dq1_3D = (q1_3D_end - q1_3D_start) / N_q1_poisson -dq2_3D = (q2_3D_end - q2_3D_start) / N_q2_poisson -dq3_3D = (q3_3D_end - q3_3D_start) / N_q3_poisson - -i_q1_3D = ( (i_q1_3D_start + 0.5) - + np.arange(-N_ghost, N_q1_3D_local + N_ghost) - ) - -i_q2_3D = ( (i_q2_3D_start + 0.5) - + np.arange(-N_ghost, N_q2_3D_local + N_ghost) - ) - -i_q3_3D = ( (i_q3_3D_start + 0.5) - + np.arange(-N_ghost, N_q3_3D_local + N_ghost) - ) - -q1_3D = q1_3D_start + i_q1_3D * dq1_3D -q2_3D = q2_3D_start + i_q2_3D * dq2_3D -q3_3D = q3_3D_start + i_q3_3D * dq3_3D - da_2D = PETSc.DMDA().create([N_q1_density, N_q2_density], stencil_width = N_ghost, @@ -115,10 +71,6 @@ ) = \ da_2D.getCorners() -q1_2D_start = -1.; q1_2D_end = 1. -q2_2D_start = -1.; q2_2D_end = 1. -location_in_q3 = 1. - dq1_2D = (q1_2D_end - q1_2D_start) / N_q1_density dq2_2D = (q2_2D_end - q2_2D_start) / N_q2_density @@ -133,20 +85,80 @@ q1_2D = q1_2D_start + i_q1_2D * dq1_2D q2_2D = q2_2D_start + i_q2_2D * dq2_2D +dq1_3D = dq1_2D +dq2_3D = dq2_2D +dq3_3D = dq1_2D + +length_multiples_q1 = 1 +length_multiples_q2 = 1 +N_q1_poisson = (2*length_multiples_q1+1)*N_q1_density +N_q2_poisson = (2*length_multiples_q2+1)*N_q2_density +N_q3_poisson = (int)((q3_3D_end - q3_3D_start) / dq1_3D) + +da_3D = PETSc.DMDA().create([N_q1_poisson, + N_q2_poisson, + N_q3_poisson], + stencil_width = N_ghost, + boundary_type = ('periodic', + 'periodic', + 'periodic' + ), + stencil_type = 1, + dof = 1, + comm = comm + ) + +glob_phi = da_3D.createGlobalVec() +local_phi = da_3D.createLocalVec() +glob_residual = da_3D.createGlobalVec() + +glob_epsilon = da_3D.createGlobalVec() +local_epsilon = da_3D.createLocalVec() + +((i_q1_3D_start, i_q2_3D_start, i_q3_3D_start), + (N_q1_3D_local, N_q2_3D_local, N_q3_3D_local) +) = \ + da_3D.getCorners() + +i_q1_3D = ( (i_q1_3D_start + 0.5) + + np.arange(-N_ghost, N_q1_3D_local + N_ghost) + ) + +i_q2_3D = ( (i_q2_3D_start + 0.5) + + np.arange(-N_ghost, N_q2_3D_local + N_ghost) + ) + +i_q3_3D = ( (i_q3_3D_start + 0.5) + + np.arange(-N_ghost, N_q3_3D_local + N_ghost) + ) + +length_q1_2d = (q1_2D_end - q1_2D_start) +length_q2_2d = (q2_2D_end - q2_2D_start) + +q1_3D = q1_2D_start - length_multiples_q1*length_q1_2d + i_q1_3D * dq1_3D +q2_3D = q2_2D_start - length_multiples_q2*length_q2_2d + i_q2_3D * dq2_3D +q3_3D = q3_3D_start + i_q3_3D * dq3_3D + glob_density_array = glob_density.getArray(readonly=0) glob_density_array = glob_density_array.reshape([N_q2_2D_local, \ - N_q1_2D_local, 1], \ + N_q1_2D_local], \ ) -glob_density_array[:] = 1. +glob_density_array[:] = -335. -da_2D.globalToLocal(glob_density, local_density) - -density_array = local_density.getArray(readonly=0) -density_array = density_array.reshape([N_q2_2D_local + 2*N_ghost, \ - N_q1_2D_local + 2*N_ghost, 1], \ +epsilon_array = local_epsilon.getArray(readonly=0) +epsilon_array = epsilon_array.reshape([N_q3_3D_local + 2*N_ghost, \ + N_q2_3D_local + 2*N_ghost, \ + N_q1_3D_local + 2*N_ghost + ] ) +epsilon_array[:] = 1. + print("rank = ", comm.rank) +print("N_q1_poisson = ", N_q1_poisson) +print("N_q2_poisson = ", N_q2_poisson) +print("N_q3_poisson = ", N_q3_poisson) + offset = 2*N_ghost-1 print("i_q1_local_3D = [", i_q1_3D_start, ",", i_q1_3D_start+N_q1_3D_local+offset, "]") print("i_q2_local_3D = [", i_q2_3D_start, ",", i_q2_3D_start+N_q2_3D_local+offset, "]") @@ -163,13 +175,14 @@ print("q1_2D_start = ", q1_2D[N_ghost]) print("q2_2D_start = ", q2_2D[N_ghost]) -q1_2D_in_3D_index_start = np.where(q1_3D > q1_2D[0] - dq1_3D)[0][0] -q1_2D_in_3D_index_end = np.where(q1_3D < q1_2D[-1] + dq1_3D)[0][-1] -q2_2D_in_3D_index_start = np.where(q2_3D > q2_2D[0] - dq2_3D)[0][0] -q2_2D_in_3D_index_end = np.where(q2_3D < q2_2D[-1] + dq2_3D)[0][-1] q3_2D_in_3D_index_start = np.where(q3_3D > location_in_q3 - dq3_3D)[0][0] q3_2D_in_3D_index_end = np.where(q3_3D < location_in_q3 + dq3_3D)[0][-1] +q1_2D_in_3D_index_start = np.where(abs(q1_3D - q1_2D[0+N_ghost] ) < 1e-10)[0][0] +q1_2D_in_3D_index_end = np.where(abs(q1_3D - q1_2D[-1-N_ghost]) < 1e-10)[0][0] +q2_2D_in_3D_index_start = np.where(abs(q2_3D - q2_2D[0+N_ghost] ) < 1e-10)[0][0] +q2_2D_in_3D_index_end = np.where(abs(q2_3D - q2_2D[-1-N_ghost]) < 1e-10)[0][0] + print("q1_2D_in_3D_index_start = ", q1_2D_in_3D_index_start, "q1_3D_start = ", q1_3D[q1_2D_in_3D_index_start]) print("q1_2D_in_3D_index_end = ", q1_2D_in_3D_index_end, "q1_3D_end = ", q1_3D[q1_2D_in_3D_index_end]) print("q2_2D_in_3D_index_start = ", q2_2D_in_3D_index_start, "q2_3D_start = ", q2_3D[q2_2D_in_3D_index_start]) @@ -177,12 +190,31 @@ print("q3_2D_in_3D_index_start = ", q3_2D_in_3D_index_start, "q3_3D_start = ", q3_3D[q3_2D_in_3D_index_start]) print("q3_2D_in_3D_index_end = ", q3_2D_in_3D_index_end, "q3_3D_end = ", q3_3D[q3_2D_in_3D_index_end]) +print(" ") +print("After ghost zone offset:") +print("q1_3D_start = ", q1_3D[q1_2D_in_3D_index_start]) +print("q1_3D_end = ", q1_3D[q1_2D_in_3D_index_end]) +print("q2_3D_start = ", q2_3D[q2_2D_in_3D_index_start]) +print("q2_3D_end = ", q2_3D[q2_2D_in_3D_index_end]) + +epsilon_array[:q3_2D_in_3D_index_start, + :, : + ] = 10. +q3_3D_data_structure = 0.*epsilon_array +for j in range(q3_3D_data_structure.shape[1]): + for i in range(q3_3D_data_structure.shape[2]): + q3_3D_data_structure[:, j, i] = q3_3D + +print("z = ", q3_3D_data_structure[q3_2D_in_3D_index_start, 0, 0]) class poisson_eqn(object): def __init__(self): self.local_phi = local_phi + self.residual_counter = 0 def compute_residual(self, snes, phi, residual): + self.residual_counter += 1 +# print("residual iter = ", self.residual_counter) da_3D.globalToLocal(phi, local_phi) N_g = N_ghost @@ -190,50 +222,114 @@ def compute_residual(self, snes, phi, residual): phi_array = local_phi.getArray(readonly=0) phi_array = phi_array.reshape([N_q3_3D_local + 2*N_g, \ N_q2_3D_local + 2*N_g, \ - N_q1_3D_local + 2*N_g, 1 + N_q1_3D_local + 2*N_g ] ) residual_array = residual.getArray(readonly=0) residual_array = residual_array.reshape([N_q3_3D_local, \ N_q2_3D_local, \ - N_q1_3D_local, 1 + N_q1_3D_local ] ) - #phi_array[:N_ghost, :, :] = 0. - #phi_array[N_q1_3D_local+N_ghost:, :, :] = 0. - #phi_array[:, :N_ghost, :] = 0. - #phi_array[:, N_q2_3D_local+N_ghost:, :] = 0. + phi_array[:N_ghost, :, :] = 0. + phi_array[N_q3_3D_local+N_ghost:, :, :] = 0. + phi_array[:, :N_ghost, :] = 0. + phi_array[:, N_q2_3D_local+N_ghost:, :] = 0. phi_array[:, :, :N_ghost] = 0. - phi_array[:, :, N_q3_3D_local+N_ghost:] = 0. - - phi_plus_x = np.roll(phi_array, shift=-1, axis=2) - phi_minus_x = np.roll(phi_array, shift=1, axis=2) - phi_plus_y = np.roll(phi_array, shift=-1, axis=1) - phi_minus_y = np.roll(phi_array, shift=1, axis=1) - phi_plus_z = np.roll(phi_array, shift=-1, axis=0) - phi_minus_z = np.roll(phi_array, shift=1, axis=0) - - d2phi_dx2 = (phi_minus_x - 2.*phi_array + phi_plus_x)/dq1_3D**2. - d2phi_dy2 = (phi_minus_y - 2.*phi_array + phi_plus_y)/dq2_3D**2. - d2phi_dz2 = (phi_minus_z - 2.*phi_array + phi_plus_z)/dq3_3D**2. - - laplacian_phi = d2phi_dx2 + d2phi_dy2 + d2phi_dz2 - -# laplacian_phi[q3_2D_in_3D_index_start:q3_2D_in_3D_index_end, -# q2_2D_in_3D_index_start:q2_2D_in_3D_index_end, -# q1_2D_in_3D_index_start:q1_2D_in_3D_index_end -# ] \ -# += density_array - - print(density_array.shape) - print(laplacian_phi[35:35, 0:70, 0:70].shape) -# laplacian_phi[35:35, 0:70, 0:70] += density_array + phi_array[:, :, N_q1_3D_local+N_ghost:] = 0. + + z = q3_3D_data_structure + z_sample = q3_3D[q3_2D_in_3D_index_start] + z_backgate = q3_3D[0] + side_wall_boundaries = (z_sample - z)/(z_sample - z_backgate) + + phi_array[:q3_2D_in_3D_index_start, :N_ghost, :] = \ + side_wall_boundaries[:q3_2D_in_3D_index_start, :N_ghost, :] + + phi_array[:q3_2D_in_3D_index_start, N_q2_3D_local+N_ghost:, :] = \ + side_wall_boundaries[:q3_2D_in_3D_index_start, N_q2_3D_local+N_ghost:, :] + + phi_array[:q3_2D_in_3D_index_start, :, :N_ghost] = \ + side_wall_boundaries[:q3_2D_in_3D_index_start, :, :N_ghost] + + phi_array[:q3_2D_in_3D_index_start, :, N_q1_3D_local+N_ghost:] = \ + side_wall_boundaries[:q3_2D_in_3D_index_start, :, N_q1_3D_local+N_ghost:] + + #Backgate +# phi_array[:N_ghost, +# q2_2D_in_3D_index_start:q2_2D_in_3D_index_end+1, +# q1_2D_in_3D_index_start:q1_2D_in_3D_index_end+1 +# ] = 1. + phi_array[:N_ghost, :, :] = 1. + + phi_plus_x = np.roll(phi_array, shift=-1, axis=2) # (i+3/2, j+1/2, k+1/2) + phi_minus_x = np.roll(phi_array, shift=1, axis=2) # (i-1/2, j+1/2, k+1/2) + phi_plus_y = np.roll(phi_array, shift=-1, axis=1) # (i+1/2, j+3/2, k+1/2) + phi_minus_y = np.roll(phi_array, shift=1, axis=1) # (i+1/2, j-1/2, k+1/2) + phi_plus_z = np.roll(phi_array, shift=-1, axis=0) # (i+1/2, j+1/2, k+3/2) + phi_minus_z = np.roll(phi_array, shift=1, axis=0) # (i+1/2, j+1/2, k+3/2) + + eps_left_edge = epsilon_array # (i, j+1/2, k+1/2) + eps_right_edge = np.roll(epsilon_array, shift=-1, axis=2) # (i+1, j+1/2, k+1/2) + + eps_bot_edge = epsilon_array # (i+1/2, j, k+1/2) + eps_top_edge = np.roll(epsilon_array, shift=-1, axis=1) # (i+1/2, j+1, k+1/2) + + eps_back_edge = epsilon_array # (i+1/2, j+1/2, k) + eps_front_edge = np.roll(epsilon_array, shift=-1, axis=0) # (i+1/2, j+1/2, k+1) + + D_left_edge = eps_left_edge * (phi_array - phi_minus_x)/dq1_3D + D_right_edge = eps_right_edge * (phi_plus_x - phi_array) /dq1_3D + + D_bot_edge = eps_bot_edge * (phi_array - phi_minus_y)/dq2_3D + D_top_edge = eps_top_edge * (phi_plus_y - phi_array )/dq2_3D + + D_back_edge = eps_back_edge * (phi_array - phi_minus_z)/dq3_3D + D_front_edge = eps_front_edge * (phi_plus_z - phi_array )/dq3_3D + + laplacian_phi = (D_right_edge - D_left_edge) /dq1_3D \ + + (D_top_edge - D_bot_edge) /dq2_3D \ + + (D_front_edge - D_back_edge) /dq3_3D + +# d2phi_dx2 = (phi_minus_x - 2.*phi_array + phi_plus_x)/dq1_3D**2. +# d2phi_dy2 = (phi_minus_y - 2.*phi_array + phi_plus_y)/dq2_3D**2. +# d2phi_dz2 = (phi_minus_z - 2.*phi_array + phi_plus_z)/dq3_3D**2. +# +# laplacian_phi = d2phi_dx2 + d2phi_dy2 + d2phi_dz2 + + laplacian_phi[q3_2D_in_3D_index_start, + q2_2D_in_3D_index_start:q2_2D_in_3D_index_end+1, + q1_2D_in_3D_index_start:q1_2D_in_3D_index_end+1 + ] \ + += glob_density_array residual_array[:, :, :] = \ laplacian_phi[N_g:-N_g, N_g:-N_g, N_g:-N_g] + #Side contacts + mid_point_q2_index = \ + (int)((q2_2D_in_3D_index_start + q2_2D_in_3D_index_end)/2) + + residual_array[q3_2D_in_3D_index_start-N_g, + mid_point_q2_index-5-N_g:mid_point_q2_index+5+1-N_g, + :q1_2D_in_3D_index_start-N_g + ] = \ + phi_array[q3_2D_in_3D_index_start, + mid_point_q2_index-5:mid_point_q2_index+5+1, + N_g:q1_2D_in_3D_index_start + ] - 0.1 + + residual_array[q3_2D_in_3D_index_start-N_g, + mid_point_q2_index-5-N_g:mid_point_q2_index+5+1-N_g, + q1_2D_in_3D_index_end+1-N_g: + ] = \ + phi_array[q3_2D_in_3D_index_start, + mid_point_q2_index-5:mid_point_q2_index+5+1, + q1_2D_in_3D_index_end+1:-N_g + ] + 0.1*0. + return snes = PETSc.SNES().create() @@ -242,4 +338,35 @@ def compute_residual(self, snes, phi, residual): snes.setDM(da_3D) snes.setFromOptions() + snes.solve(None, glob_phi) +phi_array = glob_phi.getArray() +phi_array = phi_array.reshape([N_q3_3D_local, \ + N_q2_3D_local, \ + N_q1_3D_local] + ) +pl.subplot(121) +pl.contourf( + phi_array[q3_2D_in_3D_index_start, :, :], 100, cmap='jet' + ) +pl.colorbar() +pl.title('Top View') +pl.xlabel('$x$') +pl.ylabel('$y$') +pl.gca().set_aspect('equal') + +pl.subplot(122) +pl.contourf(phi_array[:, N_q2_poisson/2, :], 100, cmap='jet') +pl.title('Side View') +pl.xlabel('$x$') +pl.ylabel('$z$') +pl.colorbar() +pl.gca().set_aspect('equal') +pl.show() + +#for n in range(10): +# +# print("====== n = ", n, "======") +# glob_density_array[:] = n +# snes.solve(None, glob_phi) +# pde.residual_counter = 0 From 6564b68aef813594f3a366d0f8500ab0c0aff803 Mon Sep 17 00:00:00 2001 From: Mani Chandra Date: Sat, 4 Nov 2017 16:20:00 +0530 Subject: [PATCH 08/28] Backup commit. --- .../EM_fields_solver/electrostatic.py | 106 ++++++++++++------ 1 file changed, 69 insertions(+), 37 deletions(-) diff --git a/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py b/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py index 87364fd8..bbdf78c6 100644 --- a/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py +++ b/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py @@ -67,16 +67,30 @@ def compute_residual(self, snes, phi, residual): N_g = self.N_ghost # Residual assembly using numpy +# phi_array = self.local_phi.getArray(readonly=0) +# phi_array = phi_array.reshape([self.N_q2_local + 2*N_g, \ +# self.N_q1_local + 2*N_g, 1], \ +# order='A' +# ) +# +# residual_array = residual.getArray(readonly=0) +# residual_array = residual_array.reshape([self.N_q2_local, \ +# self.N_q1_local, 1], \ +# order='A' +# ) + phi_array = self.local_phi.getArray(readonly=0) - phi_array = phi_array.reshape([self.N_q2_local + 2*N_g, \ - self.N_q1_local + 2*N_g, 1], \ - order='A' + phi_array = phi_array.reshape([self.N_q3_local + 2*N_g, \ + self.N_q2_local + 2*N_g, \ + self.N_q1_local + 2*N_g, 1 + ] ) residual_array = residual.getArray(readonly=0) - residual_array = residual_array.reshape([self.N_q2_local, \ - self.N_q1_local, 1], \ - order='A' + residual_array = residual_array.reshape([self.N_q3_local, \ + self.N_q2_local, \ + self.N_q1_local, 1 + ] ) #phi_array[:N_g, :] = 0. @@ -84,15 +98,33 @@ def compute_residual(self, snes, phi, residual): #phi_array[:, :N_g] = 0. #phi_array[:, self.N_q1_local+N_g:] = 0. - phi_plus_x = np.roll(phi_array, shift=-1, axis=1) - phi_minus_x = np.roll(phi_array, shift=1, axis=1) - phi_plus_y = np.roll(phi_array, shift=-1, axis=0) - phi_minus_y = np.roll(phi_array, shift=1, axis=0) +# phi_plus_x = np.roll(phi_array, shift=-1, axis=1) +# phi_minus_x = np.roll(phi_array, shift=1, axis=1) +# phi_plus_y = np.roll(phi_array, shift=-1, axis=0) +# phi_minus_y = np.roll(phi_array, shift=1, axis=0) + + phi_plus_x = np.roll(phi_array, shift=-1, axis=2) + phi_minus_x = np.roll(phi_array, shift=1, axis=2) + phi_plus_y = np.roll(phi_array, shift=-1, axis=1) + phi_minus_y = np.roll(phi_array, shift=1, axis=1) + phi_plus_z = np.roll(phi_array, shift=-1, axis=0) + phi_minus_z = np.roll(phi_array, shift=1, axis=0) d2phi_dx2 = (phi_minus_x - 2.*phi_array + phi_plus_x)/self.dq1**2. d2phi_dy2 = (phi_minus_y - 2.*phi_array + phi_plus_y)/self.dq2**2. + d2phi_dz2 = (phi_minus_z - 2.*phi_array + phi_plus_z)/self.dq3**2. - laplacian_phi = d2phi_dx2 + d2phi_dy2 + laplacian_phi = d2phi_dx2 + d2phi_dy2 + d2phi_dz2 + +# density_af = af.moddims(self.density, +# (self.N_q1_local+2*N_g) +# * (self.N_q2_local+2*N_g) +# ) +# density_np = density_af.to_ndarray() +# density_np = density_np.reshape([self.N_q2_local + 2*N_g, \ +# self.N_q1_local + 2*N_g, 1], \ +# order='A' +# ) density_af = af.moddims(self.density, (self.N_q1_local+2*N_g) @@ -194,32 +226,32 @@ def compute_electrostatic_fields(self, performance_test_flag = False): af.eval(self.E1, self.E2) - q2_minus = 0.25 - q2_plus = 0.75 - - E2_expected = -0.5/20 * ( af.log(af.cosh(( self.q2 - q2_minus)*20)) - - af.log(af.cosh(( self.q2 - q2_plus )*20)) - ) - - pl.subplot(121) - pl.contourf( - #np.array(self.E2)[N_g:-N_g, N_g:-N_g], 100 - density_np[N_g:-N_g, N_g:-N_g], 100 - ) - pl.colorbar() - #pl.axis('equal') - pl.title(r'Density') - #pl.title(r'$E^2_{numerical}$') - pl.subplot(122) - pl.contourf( - #np.array(E2_expected)[N_g:-N_g, N_g:-N_g], 100 - phi_local_array[N_g:-N_g, N_g:-N_g], 100 - ) - pl.colorbar() - pl.title(r'$\phi$') - #pl.title(r'$E^2_{analytic}$') - #pl.axis('equal') - pl.show() +# q2_minus = 0.25 +# q2_plus = 0.75 +# +# E2_expected = -0.5/20 * ( af.log(af.cosh(( self.q2 - q2_minus)*20)) +# - af.log(af.cosh(( self.q2 - q2_plus )*20)) +# ) +# +# pl.subplot(121) +# pl.contourf( +# #np.array(self.E2)[N_g:-N_g, N_g:-N_g], 100 +# density_np[N_g:-N_g, N_g:-N_g], 100 +# ) +# pl.colorbar() +# #pl.axis('equal') +# pl.title(r'Density') +# #pl.title(r'$E^2_{numerical}$') +# pl.subplot(122) +# pl.contourf( +# #np.array(E2_expected)[N_g:-N_g, N_g:-N_g], 100 +# phi_local_array[N_g:-N_g, N_g:-N_g], 100 +# ) +# pl.colorbar() +# pl.title(r'$\phi$') +# #pl.title(r'$E^2_{analytic}$') +# #pl.axis('equal') +# pl.show() if(performance_test_flag == True): From 156cb553b08204133845f8c8d5749a702f893c37 Mon Sep 17 00:00:00 2001 From: Mani Chandra Date: Tue, 28 Nov 2017 19:10:02 +0530 Subject: [PATCH 09/28] Backup commit. Self-consistent Poisson-Boltzmann solution now does not crash. --- .../EM_fields_solver/electrostatic.py | 506 ++++++++++++------ .../apply_boundary_conditions.py | 70 +++ .../interpolation_routines.py | 104 ++-- bolt/lib/nonlinear_solver/nonlinear_solver.py | 49 +- bolt/lib/nonlinear_solver/timestepper.py | 33 +- .../nonlinear_solver/timestepper_source.py | 2 +- .../electronic_boltzmann/advection_terms.py | 36 ++ .../collision_operator.py | 266 +++++++++ .../electronic_boltzmann/matrix_inverse.py | 189 +++++++ bolt/src/electronic_boltzmann/moment_defs.py | 3 + 10 files changed, 1024 insertions(+), 234 deletions(-) create mode 100644 bolt/src/electronic_boltzmann/advection_terms.py create mode 100644 bolt/src/electronic_boltzmann/collision_operator.py create mode 100644 bolt/src/electronic_boltzmann/matrix_inverse.py create mode 100644 bolt/src/electronic_boltzmann/moment_defs.py diff --git a/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py b/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py index 775bead8..bf701d9f 100644 --- a/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py +++ b/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py @@ -8,6 +8,7 @@ import numpy as np from numpy.fft import fftfreq import pylab as pl +import params pl.rcParams['figure.figsize'] = 17, 7.5 pl.rcParams['figure.dpi'] = 150 @@ -38,129 +39,302 @@ pl.rcParams['ytick.labelsize'] = 'medium' pl.rcParams['ytick.direction'] = 'in' -class poisson_eqn(object): +class poisson_eqn_3D(object): """ This user class is an application context for the problem at hand; - It contains some parametes and frames the matrix system depending on - the system state. The Poisson2D object is used by the + It contains some parameters and frames the matrix system depending on + the system state. The Poisson object is used by the compute_electrostatic_fields function in computing the electrostatic fields - using the PETSc's KSP solver methods + using the PETSc's SNES solver methods """ - def __init__(self, nonlinear_solver_obj): - self.da = nonlinear_solver_obj._da_snes + self.da_3D = nonlinear_solver_obj._da_snes + self.da_2D = nonlinear_solver_obj._da_f self.obj = nonlinear_solver_obj - self.local_phi = self.da.createLocalVec() # phi with ghost zones + self.glob_phi = self.da_3D.createGlobalVec() + self.local_phi = self.da_3D.createLocalVec() # phi with ghost zones + + self.glob_residual = self.da_3D.createGlobalVec() + self.N_ghost = self.obj.N_ghost self.dq1 = self.obj.dq1 self.dq2 = self.obj.dq2 - self.density = 0. + self.dq3 = self.obj.dq3 + + ((i_q1_2D_start, i_q2_2D_start), + (N_q1_2D_local, N_q2_2D_local) + ) = self.da_2D.getCorners() + + ((i_q1_3D_start, i_q2_3D_start, i_q3_3D_start), + (N_q1_3D_local, N_q2_3D_local, N_q3_3D_local) + ) = self.da_3D.getCorners() + + self.N_q1_2D_local = N_q1_2D_local + self.N_q2_2D_local = N_q2_2D_local - ((i_q1_start, i_q2_start), (N_q1_local, N_q2_local)) = \ - self.da.getCorners() + self.N_q1_3D_local = N_q1_3D_local + self.N_q2_3D_local = N_q2_3D_local + self.N_q3_3D_local = N_q3_3D_local + + location_in_q3 = 1. + N_g = self.N_ghost + + self.density_np = np.zeros([N_q2_2D_local + 2*N_g, + N_q1_2D_local + 2*N_g + ] + ) + # Cell centers in 3D + i_q1_3D = ( (i_q1_3D_start + 0.5) + + np.arange(-N_g, N_q1_3D_local + N_g) + ) + + i_q2_3D = ( (i_q2_3D_start + 0.5) + + np.arange(-N_g, N_q2_3D_local + N_g) + ) + + i_q3_3D = ( (i_q3_3D_start + 0.5) + + np.arange(-N_g, N_q3_3D_local + N_g) + ) + + q1_2D_start = self.obj.q1_start + q1_2D_end = self.obj.q1_end + q2_2D_start = self.obj.q2_start + q2_2D_end = self.obj.q2_end + q3_3D_start = self.obj.q3_3D_start + + # TODO: Code below is duplication of _calculate_q_center in nonlinear_solver.py + i_q1_2D = ( (i_q1_2D_start + 0.5) + + np.arange(-N_g, N_q1_2D_local + N_g) + ) + + i_q2_2D = ( (i_q2_2D_start + 0.5) + + np.arange(-N_g, N_q2_2D_local + N_g) + ) + + q1_2D = q1_2D_start + i_q1_2D * self.dq1 + q2_2D = q2_2D_start + i_q2_2D * self.dq2 + + length_q1_2d = (q1_2D_end - q1_2D_start) + length_q2_2d = (q2_2D_end - q2_2D_start) + + length_multiples_q1 = self.obj.length_multiples_q1 + length_multiples_q2 = self.obj.length_multiples_q2 + + q1_3D = q1_2D_start - length_multiples_q1*length_q1_2d + i_q1_3D * self.dq1 + q2_3D = q2_2D_start - length_multiples_q2*length_q2_2d + i_q2_3D * self.dq2 + q3_3D = q3_3D_start + i_q3_3D * self.dq3 + + self.q3_2D_in_3D_index_start = np.where(q3_3D > location_in_q3 - self.dq3)[0][0] + self.q3_2D_in_3D_index_end = np.where(q3_3D < location_in_q3 + self.dq3)[0][-1] + + self.q1_2D_in_3D_index_start = np.where(abs(q1_3D - q1_2D[N_g] ) < 1e-10)[0][0] + self.q1_2D_in_3D_index_end = np.where(abs(q1_3D - q1_2D[-1-N_g]) < 1e-10)[0][0] + self.q2_2D_in_3D_index_start = np.where(abs(q2_3D - q2_2D[N_g] ) < 1e-10)[0][0] + self.q2_2D_in_3D_index_end = np.where(abs(q2_3D - q2_2D[-1-N_g]) < 1e-10)[0][0] + + glob_epsilon = self.da_3D.createGlobalVec() + local_epsilon = self.da_3D.createLocalVec() + + epsilon_array = local_epsilon.getArray(readonly=0) + epsilon_array = epsilon_array.reshape([N_q3_3D_local + 2*N_g, \ + N_q2_3D_local + 2*N_g, \ + N_q1_3D_local + 2*N_g + ] + ) + epsilon_array[:] = 1. + epsilon_array[:self.q3_2D_in_3D_index_start, :, :] = 10. + self.epsilon_array = epsilon_array - self.N_q1_local = N_q1_local - self.N_q2_local = N_q2_local + q3_3D_data_structure = 0.*epsilon_array - def compute_residual(self, snes, phi, residual): + for j in range(q3_3D_data_structure.shape[1]): + for i in range(q3_3D_data_structure.shape[2]): + q3_3D_data_structure[:, j, i] = q3_3D + + backgate_potential = -0.001 - self.da.globalToLocal(phi, self.local_phi) + self.q3 = q3_3D_data_structure + z = self.q3 + z_sample = q3_3D[self.q3_2D_in_3D_index_start] + z_backgate = q3_3D[0] + side_wall_boundaries = \ + backgate_potential*(z_sample - z)/(z_sample - z_backgate) + + self.bc = 0.*self.q3 # 3D boundary condition array + + self.bc[:] = 0. + self.bc[:N_g, :, :] = backgate_potential # backgate + + self.bc[:self.q3_2D_in_3D_index_start, :N_g, :] = \ + side_wall_boundaries[:self.q3_2D_in_3D_index_start, :N_g, :] + + self.bc[:self.q3_2D_in_3D_index_start, N_q2_3D_local+N_g:, :] = \ + side_wall_boundaries[:self.q3_2D_in_3D_index_start, N_q2_3D_local+N_g:, :] + + self.bc[:self.q3_2D_in_3D_index_start, :, :N_g] = \ + side_wall_boundaries[:self.q3_2D_in_3D_index_start, :, :N_g] + + self.bc[:self.q3_2D_in_3D_index_start, :, N_q1_3D_local+N_g:] = \ + side_wall_boundaries[:self.q3_2D_in_3D_index_start, :, N_q1_3D_local+N_g:] + + return + + + def compute_residual(self, snes, phi, residual): + self.da_3D.globalToLocal(phi, self.local_phi) N_g = self.N_ghost - # Residual assembly using numpy -# phi_array = self.local_phi.getArray(readonly=0) -# phi_array = phi_array.reshape([self.N_q2_local + 2*N_g, \ -# self.N_q1_local + 2*N_g, 1], \ -# order='A' -# ) -# -# residual_array = residual.getArray(readonly=0) -# residual_array = residual_array.reshape([self.N_q2_local, \ -# self.N_q1_local, 1], \ -# order='A' -# ) + N_q1_2D_local = self.N_q1_2D_local + N_q2_2D_local = self.N_q2_2D_local + + N_q1_3D_local = self.N_q1_3D_local + N_q2_3D_local = self.N_q2_3D_local + N_q3_3D_local = self.N_q3_3D_local phi_array = self.local_phi.getArray(readonly=0) - phi_array = phi_array.reshape([self.N_q3_local + 2*N_g, \ - self.N_q2_local + 2*N_g, \ - self.N_q1_local + 2*N_g, 1 - ] + phi_array = phi_array.reshape([N_q3_3D_local + 2*N_g, \ + N_q2_3D_local + 2*N_g, \ + N_q1_3D_local + 2*N_g + ] ) - + residual_array = residual.getArray(readonly=0) - residual_array = residual_array.reshape([self.N_q3_local, \ - self.N_q2_local, \ - self.N_q1_local, 1 - ] + residual_array = residual_array.reshape([N_q3_3D_local, \ + N_q2_3D_local, \ + N_q1_3D_local + ] ) - - #phi_array[:N_g, :] = 0. - #phi_array[self.N_q2_local+N_g:, :] = 0. - #phi_array[:, :N_g] = 0. - #phi_array[:, self.N_q1_local+N_g:] = 0. - -# phi_plus_x = np.roll(phi_array, shift=-1, axis=1) -# phi_minus_x = np.roll(phi_array, shift=1, axis=1) -# phi_plus_y = np.roll(phi_array, shift=-1, axis=0) -# phi_minus_y = np.roll(phi_array, shift=1, axis=0) - - phi_plus_x = np.roll(phi_array, shift=-1, axis=2) - phi_minus_x = np.roll(phi_array, shift=1, axis=2) - phi_plus_y = np.roll(phi_array, shift=-1, axis=1) - phi_minus_y = np.roll(phi_array, shift=1, axis=1) - phi_plus_z = np.roll(phi_array, shift=-1, axis=0) - phi_minus_z = np.roll(phi_array, shift=1, axis=0) - - d2phi_dx2 = (phi_minus_x - 2.*phi_array + phi_plus_x)/self.dq1**2. - d2phi_dy2 = (phi_minus_y - 2.*phi_array + phi_plus_y)/self.dq2**2. - d2phi_dz2 = (phi_minus_z - 2.*phi_array + phi_plus_z)/self.dq3**2. - - laplacian_phi = d2phi_dx2 + d2phi_dy2 + d2phi_dz2 - -# density_af = af.moddims(self.density, -# (self.N_q1_local+2*N_g) -# * (self.N_q2_local+2*N_g) -# ) -# density_np = density_af.to_ndarray() -# density_np = density_np.reshape([self.N_q2_local + 2*N_g, \ -# self.N_q1_local + 2*N_g, 1], \ -# order='A' -# ) - - density_af = af.moddims(self.density, - (self.N_q1_local+2*N_g) - * (self.N_q2_local+2*N_g) - ) - density_np = density_af.to_ndarray() - density_np = density_np.reshape([self.N_q2_local + 2*N_g, \ - self.N_q1_local + 2*N_g, 1], \ - order='A' - ) - - residual_array[:, :] = \ - (laplacian_phi + density_np)[N_g:-N_g, N_g:-N_g] - -# residual_array[:, :] = \ -# (laplacian_phi + self.density)[N_g:-N_g, N_g:-N_g] - - - # Residual assembly using arrayfire -# phi_array = self.local_phi.getArray(readonly=1) -# phi_af_array = af.to_array(phi_array) -# phi_af_array = af.moddims(phi_af_array, -# self.N_q1_local + 2*N_g, -# self.N_q2_local + 2*N_g -# ) + # Boundary conditions + bc = self.bc + phi_array[:N_g, :, :] = bc[:N_g, :, :] + phi_array[N_q3_3D_local+N_g:, :, :] = bc[N_q3_3D_local+N_g:, :, :] + phi_array[:, :N_g, :] = bc[:, :N_g, :] + phi_array[:, N_q2_3D_local+N_g:, :] = bc[:, N_q2_3D_local+N_g:, :] + phi_array[:, :, :N_g] = bc[:, :, :N_g] + phi_array[:, :, N_q1_3D_local+N_g:] = bc[:, :, N_q1_3D_local+N_g:] + + + phi_plus_x = np.roll(phi_array, shift=-1, axis=2) # (i+3/2, j+1/2, k+1/2) + phi_minus_x = np.roll(phi_array, shift=1, axis=2) # (i-1/2, j+1/2, k+1/2) + phi_plus_y = np.roll(phi_array, shift=-1, axis=1) # (i+1/2, j+3/2, k+1/2) + phi_minus_y = np.roll(phi_array, shift=1, axis=1) # (i+1/2, j-1/2, k+1/2) + phi_plus_z = np.roll(phi_array, shift=-1, axis=0) # (i+1/2, j+1/2, k+3/2) + phi_minus_z = np.roll(phi_array, shift=1, axis=0) # (i+1/2, j+1/2, k+3/2) + + epsilon_array = self.epsilon_array + eps_left_edge = epsilon_array # (i, j+1/2, k+1/2) + eps_right_edge = np.roll(epsilon_array, shift=-1, axis=2) # (i+1, j+1/2, k+1/2) + + eps_bot_edge = epsilon_array # (i+1/2, j, k+1/2) + eps_top_edge = np.roll(epsilon_array, shift=-1, axis=1) # (i+1/2, j+1, k+1/2) + + eps_back_edge = epsilon_array # (i+1/2, j+1/2, k) + eps_front_edge = np.roll(epsilon_array, shift=-1, axis=0) # (i+1/2, j+1/2, k+1) + + D_left_edge = eps_left_edge * (phi_array - phi_minus_x)/self.dq1 + D_right_edge = eps_right_edge * (phi_plus_x - phi_array) /self.dq1 + + D_bot_edge = eps_bot_edge * (phi_array - phi_minus_y)/self.dq2 + D_top_edge = eps_top_edge * (phi_plus_y - phi_array )/self.dq2 + + D_back_edge = eps_back_edge * (phi_array - phi_minus_z)/self.dq3 + D_front_edge = eps_front_edge * (phi_plus_z - phi_array )/self.dq3 + + laplacian_phi = (D_right_edge - D_left_edge) /self.dq1 \ + + (D_top_edge - D_bot_edge) /self.dq2 \ + + (D_front_edge - D_back_edge) /self.dq3 + + q3_2D_in_3D_index_start = self.q3_2D_in_3D_index_start + q3_2D_in_3D_index_end = self.q3_2D_in_3D_index_end + + q1_2D_in_3D_index_start = self.q1_2D_in_3D_index_start + q1_2D_in_3D_index_end = self.q1_2D_in_3D_index_end + q2_2D_in_3D_index_start = self.q2_2D_in_3D_index_start + q2_2D_in_3D_index_end = self.q2_2D_in_3D_index_end + + laplacian_phi[q3_2D_in_3D_index_start, + q2_2D_in_3D_index_start:q2_2D_in_3D_index_end+1, + q1_2D_in_3D_index_start:q1_2D_in_3D_index_end+1 + ] \ + += \ + 4.*np.pi*params.charge_electron*self.density_np[N_g:-N_g, N_g:-N_g] + + residual_array[:, :, :] = \ + laplacian_phi[N_g:-N_g, N_g:-N_g, N_g:-N_g] + +# #Side contacts +# mid_point_q2_index = \ +# (int)((q2_2D_in_3D_index_start + q2_2D_in_3D_index_end)/2) # -# residual_af_array = phi_af_array[N_g:-N_g, N_g:-N_g]**2. - 2. -# residual_af_array = af.moddims(residual_af_array, -# self.N_q1_local -# * self.N_q2_local -# ) -# residual_array = residual.getArray(readonly=0) -# residual_array[:] = residual_af_array.to_ndarray() - +## residual_array[q3_2D_in_3D_index_start-N_g, +## mid_point_q2_index-5-N_g:mid_point_q2_index+5+1-N_g, +## :q1_2D_in_3D_index_start-N_g +## ] = \ +## phi_array[q3_2D_in_3D_index_start, +## mid_point_q2_index-5:mid_point_q2_index+5+1, +## N_g:q1_2D_in_3D_index_start +## ] - 0.1*0. +## +## residual_array[q3_2D_in_3D_index_start-N_g, +## mid_point_q2_index-5-N_g:mid_point_q2_index+5+1-N_g, +## q1_2D_in_3D_index_end+1-N_g: +## ] = \ +## phi_array[q3_2D_in_3D_index_start, +## mid_point_q2_index-5:mid_point_q2_index+5+1, +## q1_2D_in_3D_index_end+1:-N_g +## ] + 0.1*0. +# +# residual_array[q3_2D_in_3D_index_start-N_g, +# q2_2D_in_3D_index_start-N_g:q2_2D_in_3D_index_end+1-N_g, +# :q1_2D_in_3D_index_start-N_g +# ] = \ +# phi_array[q3_2D_in_3D_index_start, +# q2_2D_in_3D_index_start:q2_2D_in_3D_index_end+1, +# N_g:q1_2D_in_3D_index_start +# ] - 0.1*0. +# +# residual_array[q3_2D_in_3D_index_start-N_g, +# q2_2D_in_3D_index_start-N_g:q2_2D_in_3D_index_end+1-N_g, +# q1_2D_in_3D_index_end+1-N_g: +# ] = \ +# phi_array[q3_2D_in_3D_index_start, +# q2_2D_in_3D_index_start:q2_2D_in_3D_index_end+1, +# q1_2D_in_3D_index_end+1:-N_g +# ] + 0.1*0. + + #Side contacts + mid_point_q2_index = \ + (int)((q2_2D_in_3D_index_start + q2_2D_in_3D_index_end)/2) + + size_of_inflow = 0.25 + length_y = self.obj.q2_end - self.obj.q2_start + N_inflow_zones = (int)(size_of_inflow/length_y*self.obj.N_q2) + N_outflow_zones = N_inflow_zones + + q2_inflow_start = mid_point_q2_index-N_inflow_zones/2 + q2_inflow_end = mid_point_q2_index+N_inflow_zones/2+1 + + q2_outflow_start = mid_point_q2_index-N_outflow_zones/2 + q2_outflow_end = mid_point_q2_index+N_outflow_zones/2+1 + + residual_array[q3_2D_in_3D_index_start-N_g, + q2_inflow_start-N_g:q2_inflow_end-N_g, + :q1_2D_in_3D_index_start-N_g + ] = \ + phi_array[q3_2D_in_3D_index_start, + q2_inflow_start:q2_inflow_end, + N_g:q1_2D_in_3D_index_start + ] - 0.1*0. + + residual_array[q3_2D_in_3D_index_start-N_g, + q2_outflow_start-N_g:q2_outflow_end-N_g, + q1_2D_in_3D_index_end+1-N_g: + ] = \ + phi_array[q3_2D_in_3D_index_start, + q2_outflow_start:q2_outflow_end, + q1_2D_in_3D_index_end+1:-N_g + ] + 0.1*0. return def compute_electrostatic_fields(self): @@ -168,94 +342,72 @@ def compute_electrostatic_fields(self): if(self.performance_test_flag == True): tic = af.time() - # Obtaining the left-bottom corner coordinates - # (lowest values of the canonical coordinates in 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_snes.getCorners() - N_g = self.N_ghost - snes = PETSc.SNES().create() - pde = poisson_eqn(self) - snes.setFunction(pde.compute_residual, self.glob_residual) - - snes.setDM(self._da_snes) - snes.setFromOptions() - pde.density = self.compute_moments('density') - snes.solve(None, self.glob_phi) - - #phi_array = self.glob_phi.getArray() - #print("phi = ", phi_array) - #phi_array = phi_array.reshape([N_q2_local, \ - # N_q1_local, 1], \ - # order='A' - # ) - - self._da_snes.globalToLocal(self.glob_phi, pde.local_phi) - phi_local_array = pde.local_phi.getArray() - electric_potential = af.to_array(phi_local_array) - phi_local_array = phi_local_array.reshape([N_q2_local + 2*N_g, \ - N_q1_local + 2*N_g], \ - ) - density_af = af.moddims(pde.density, - (N_q1_local+2*N_g) - * (N_q2_local+2*N_g) + density_af = af.moddims(self.compute_moments('density'), + (self.N_q1_local+2*N_g) + * (self.N_q2_local+2*N_g) ) density_np = density_af.to_ndarray() - density_np = density_np.reshape([N_q2_local + 2*N_g, \ - N_q1_local + 2*N_g], \ - ) + self.poisson.density_np[:] =\ + density_np.reshape([self.N_q2_local+2*N_g, + self.N_q1_local+2*N_g + ] + ) + self.snes.solve(None, self.poisson.glob_phi) + + self._da_snes.globalToLocal(self.poisson.glob_phi, + self.poisson.local_phi + ) + phi_local_array = self.poisson.local_phi.getArray() + phi_local_array = \ + phi_local_array.reshape([self.poisson.N_q3_3D_local+2*N_g, + self.poisson.N_q2_3D_local+2*N_g, + self.poisson.N_q1_3D_local+2*N_g + ] + ) + + q3_2D_in_3D_index_start = self.poisson.q3_2D_in_3D_index_start + q3_2D_in_3D_index_end = self.poisson.q3_2D_in_3D_index_end + + q1_2D_in_3D_index_start = self.poisson.q1_2D_in_3D_index_start + q1_2D_in_3D_index_end = self.poisson.q1_2D_in_3D_index_end + q2_2D_in_3D_index_start = self.poisson.q2_2D_in_3D_index_start + q2_2D_in_3D_index_end = self.poisson.q2_2D_in_3D_index_end + + phi_2D_local_array = \ + phi_local_array[q3_2D_in_3D_index_start, + q2_2D_in_3D_index_start-N_g:q2_2D_in_3D_index_end+1+N_g, + q1_2D_in_3D_index_start-N_g:q1_2D_in_3D_index_end+1+N_g + ] + + phi_2D_local_array = \ + phi_2D_local_array.reshape([ (self.N_q1_local + 2*N_g) \ + *(self.N_q2_local + 2*N_g) + ] + ) + + # convert from np->af + self.phi = af.to_array(phi_2D_local_array) # Since rho was defined at (i + 0.5, j + 0.5) # Electric Potential returned will also be at (i + 0.5, j + 0.5) -# electric_potential = af.to_array(np.swapaxes(phi_local_array, -# 0, 1 -# ) -# ) - - electric_potential = af.moddims(electric_potential, - N_q1_local + 2*N_g, - N_q2_local + 2*N_g - ) - - # Obtaining the values at (i+0.5, j+0.5): - self.E1 = -( af.shift(electric_potential, -1) - - af.shift(electric_potential, 1) + self.phi = af.moddims(self.phi, + self.N_q1_local + 2*N_g, + self.N_q2_local + 2*N_g + ) + params.phi = self.phi + + # Obtaining the electric field values at (i+0.5, j+0.5): + self.E1 = -( af.shift(self.phi, -1, 0) + - af.shift(self.phi, 1, 0) ) / (2 * self.dq1) - self.E2 = -( af.shift(electric_potential, 0, -1) - - af.shift(electric_potential, 0, 1) + self.E2 = -( af.shift(self.phi, 0, -1) + - af.shift(self.phi, 0, 1) ) / (2 * self.dq2) af.eval(self.E1, self.E2) -# q2_minus = 0.25 -# q2_plus = 0.75 -# -# E2_expected = -0.5/20 * ( af.log(af.cosh(( self.q2 - q2_minus)*20)) -# - af.log(af.cosh(( self.q2 - q2_plus )*20)) -# ) -# -# pl.subplot(121) -# pl.contourf( -# #np.array(self.E2)[N_g:-N_g, N_g:-N_g], 100 -# density_np[N_g:-N_g, N_g:-N_g], 100 -# ) -# pl.colorbar() -# #pl.axis('equal') -# pl.title(r'Density') -# #pl.title(r'$E^2_{numerical}$') -# pl.subplot(122) -# pl.contourf( -# #np.array(E2_expected)[N_g:-N_g, N_g:-N_g], 100 -# phi_local_array[N_g:-N_g, N_g:-N_g], 100 -# ) -# pl.colorbar() -# pl.title(r'$\phi$') -# #pl.title(r'$E^2_{analytic}$') -# #pl.axis('equal') -# pl.show() - - if(self.performance_test_flag == True): af.sync() toc = af.time() diff --git a/bolt/lib/nonlinear_solver/apply_boundary_conditions.py b/bolt/lib/nonlinear_solver/apply_boundary_conditions.py index ab282a14..c42272ee 100644 --- a/bolt/lib/nonlinear_solver/apply_boundary_conditions.py +++ b/bolt/lib/nonlinear_solver/apply_boundary_conditions.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- +import numpy as np import arrayfire as af def apply_bcs_f(self): @@ -81,6 +82,40 @@ def apply_bcs_f(self): ) )[:N_g] + f_left = self.physical_system.boundary_conditions.\ + f_left(self.q1_center, self.q2_center, + self.p1, self.p2, self.p3, + self.physical_system.params + ) + + if(self._A_q1.shape[0] == 1): + A_q1 = af.tile(self._A_q1, + self.f.shape[0], + self.f.shape[1] + ) + + else: + A_q1 = self._A_q1 + + # Only changing inflowing characteristics: + f_left = af.select(A_q1>0, f_left, self.f) + + + # Inflow between y = [y_center(j_inflow_start), y_center(j_inflow_end)] + N_q2 = self.N_q2 + size_of_inflow = 0.25 + offset_from_center = 0. + length_y = self.q2_end - self.q2_start + N_inflow_zones = (int)(size_of_inflow/length_y*N_q2) + N_offset = (int)(abs(offset_from_center)/length_y*N_q2) + j_inflow_start = N_g + N_q2/2 - N_inflow_zones/2 \ + + np.sign(offset_from_center)*N_offset + j_inflow_end = N_g + N_q2/2 + N_inflow_zones/2 \ + + np.sign(offset_from_center)*N_offset + + self.f[:N_g, j_inflow_start:j_inflow_end] = \ + f_left[:N_g, j_inflow_start:j_inflow_end] + # If local zone includes the right physical boundary: if(i_q1_end == self.N_q1 - 1): @@ -102,6 +137,41 @@ def apply_bcs_f(self): ) )[-N_g:] + f_right = self.physical_system.boundary_conditions.\ + f_right(self.q1_center, self.q2_center, + self.p1, self.p2, self.p3, + self.physical_system.params + ) + + if(self._A_q1.shape[0] == 1): + A_q1 = af.tile(self._A_q1, + self.f.shape[0], + self.f.shape[1] + ) + + else: + A_q1 = self._A_q1 + + + # Only changing inflowing characteristics: + f_right = af.select(A_q1<0, f_right, self.f) + + # Outflow between y = [y_center(j_outflow_start), y_center(j_outflow_end)] + N_q2 = self.N_q2 + size_of_outflow = 0.25 + offset_from_center = 0. + length_y = self.q2_end - self.q2_start + N_outflow_zones = (int)(size_of_outflow/length_y*N_q2) + N_offset = (int)(abs(offset_from_center)/length_y*N_q2) + j_outflow_start = N_g + N_q2/2 - N_outflow_zones/2 \ + + np.sign(offset_from_center)*N_offset + j_outflow_end = N_g + N_q2/2 + N_outflow_zones/2 \ + + np.sign(offset_from_center)*N_offset + + self.f[-N_g:, j_outflow_start:j_outflow_end] = \ + f_right[-N_g:, j_outflow_start:j_outflow_end] + + # This is automatically handled by the PETSc function globalToLocal() elif(self.physical_system.boundary_conditions.in_q1 == 'periodic'): pass diff --git a/bolt/lib/nonlinear_solver/interpolation_routines.py b/bolt/lib/nonlinear_solver/interpolation_routines.py index 9d6d30d7..48dcc98e 100644 --- a/bolt/lib/nonlinear_solver/interpolation_routines.py +++ b/bolt/lib/nonlinear_solver/interpolation_routines.py @@ -3,6 +3,7 @@ import arrayfire as af import numpy as np +import domain def f_interp_2d(self, dt): @@ -19,12 +20,18 @@ def f_interp_2d(self, dt): q1_center_new = af.broadcast(addition, self.q1_center, - self._A_q1 * dt) q2_center_new = af.broadcast(addition, self.q2_center, - self._A_q2 * dt) +# print("q2_center_new - q2_center = ", \ +# af.sum(af.abs(q2_center_new[:, :, 1] - self.q2_center))) + + #f_old = self.f.copy() + self.f = af.approx2(self.f, q1_center_new, q2_center_new, af.INTERP.BICUBIC_SPLINE, xp = self.q1_center, yp = self.q2_center, ) af.eval(self.f) + #print("f_new - f_old = ", af.sum(af.abs(self.f - f_old))) if(self.performance_test_flag == True): af.sync() @@ -101,58 +108,89 @@ def f_interp_p_3d(self, dt): # batched operations when operating on arrays of different sizes addition = lambda a,b:a + b - # af.broadcast(function, *args) performs batched operations on - # function(*args) - p1_new = af.broadcast(addition, self.p1, - 0.5 * dt * A_p1) +# # af.broadcast(function, *args) performs batched operations on +# # function(*args) +# p1_new = af.broadcast(addition, self.p1, - 0.5 * dt * A_p1) +# p2_new = af.broadcast(addition, self.p2, - dt * A_p2) +# p3_new = af.broadcast(addition, self.p3, - dt * A_p3) +# +# p1_new = self._convert_to_p_expanded(p1_new) +# p2_new = self._convert_to_p_expanded(p2_new) +# p3_new = self._convert_to_p_expanded(p3_new) +# +# # Transforming interpolant to go from [0, N_p - 1]: +# p1_lower_boundary = self.p1_start + 0.5 * self.dp1 +# p2_lower_boundary = self.p2_start + 0.5 * self.dp2 +# p3_lower_boundary = self.p3_start + 0.5 * self.dp3 +# +# p1_interpolant = (p1_new - p1_lower_boundary) / self.dp1 +# p2_interpolant = (p2_new - p2_lower_boundary) / self.dp2 +# p3_interpolant = (p3_new - p3_lower_boundary) / self.dp3 +# +# # We perform the 3d interpolation by performing +# # individual 1d + 2d interpolations. Reordering to bring the +# # variation in values along axis 0 and axis 1 +# +# self.f = self._convert_to_p_expanded(self.f) +# +# # Changing from (Nq1*Nq2, Np1, Np2, Np3) --> (Np1, Nq1*Nq2, Np2, Np3) +# self.f = af.approx1(af.reorder(self.f), +# af.reorder(p1_interpolant), +# af.INTERP.CUBIC_SPLINE +# ) +# +# # Changing f from (Np1, Nq1*Nq2, Np2, Np3) --> (Np2, Np3, Nq1*Nq2, Np1) +# # Changing p2, p3 from (Nq1*Nq2, Np1, Np2, Np3) --> (Np2, Np3, Nq1*Nq2, Np1) +# self.f = af.approx2(af.reorder(self.f, 2, 3, 1, 0), +# af.reorder(p2_interpolant, 2, 3, 0, 1), +# af.reorder(p3_interpolant, 2, 3, 0, 1), +# af.INTERP.BICUBIC_SPLINE +# ) +# +# # Changing f from (Np2, Np3, Nq1*Nq2, Np1) --> (Np1, Nq1*Np2, Np2, Np3) +# # Changing p1 from (Nq1*Nq2, Np1, Np2, Np3) --> (Np1, Nq1*Nq2, Np2, Np3) +# self.f = af.approx1(af.reorder(self.f, 3, 2, 0, 1), +# af.reorder(p1_interpolant), +# af.INTERP.CUBIC_SPLINE, +# ) +# +# # Changing f from (Np1, Nq1*Np2, Np2, Np3) --> (Nq1*Nq2, Np1, Np2, Np3) +# self.f = af.reorder(self.f) +# self.f = self._convert_to_q_expanded(self.f) +# +# af.eval(self.f) + + + + + p1_new = af.broadcast(addition, self.p1, - dt * A_p1) p2_new = af.broadcast(addition, self.p2, - dt * A_p2) - p3_new = af.broadcast(addition, self.p3, - dt * A_p3) p1_new = self._convert_to_p_expanded(p1_new) p2_new = self._convert_to_p_expanded(p2_new) - p3_new = self._convert_to_p_expanded(p3_new) # Transforming interpolant to go from [0, N_p - 1]: p1_lower_boundary = self.p1_start + 0.5 * self.dp1 p2_lower_boundary = self.p2_start + 0.5 * self.dp2 - p3_lower_boundary = self.p3_start + 0.5 * self.dp3 p1_interpolant = (p1_new - p1_lower_boundary) / self.dp1 p2_interpolant = (p2_new - p2_lower_boundary) / self.dp2 - p3_interpolant = (p3_new - p3_lower_boundary) / self.dp3 - - # We perform the 3d interpolation by performing - # individual 1d + 2d interpolations. Reordering to bring the - # variation in values along axis 0 and axis 1 + # (Nq1, Nq2, Np1*Np2*Np3) -> (Nq1*Nq2, Np1, Np2, Np3) self.f = self._convert_to_p_expanded(self.f) - # Changing from (Nq1*Nq2, Np1, Np2, Np3) --> (Np1, Nq1*Nq2, Np2, Np3) - self.f = af.approx1(af.reorder(self.f), - af.reorder(p1_interpolant), - af.INTERP.CUBIC_SPLINE - ) - - # Changing f from (Np1, Nq1*Nq2, Np2, Np3) --> (Np2, Np3, Nq1*Nq2, Np1) - # Changing p2, p3 from (Nq1*Nq2, Np1, Np2, Np3) --> (Np2, Np3, Nq1*Nq2, Np1) - self.f = af.approx2(af.reorder(self.f, 2, 3, 1, 0), - af.reorder(p2_interpolant, 2, 3, 0, 1), - af.reorder(p3_interpolant, 2, 3, 0, 1), + # Changing f from (Nq1*Nq2, Np1, Np2, Np3) --> (Np1, Np2, Nq1*Nq2, Np3) + # Changing p1, p2 from (Nq1*Nq2, Np1, Np2, Np3) --> (Np1, Np2, Nq1*Nq2, Np3) + self.f = af.approx2(af.reorder(self.f, 1, 2, 0, 3), + af.reorder(p1_interpolant, 1, 2, 0, 3), + af.reorder(p2_interpolant, 1, 2, 0, 3), af.INTERP.BICUBIC_SPLINE ) - # Changing f from (Np2, Np3, Nq1*Nq2, Np1) --> (Np1, Nq1*Np2, Np2, Np3) - # Changing p1 from (Nq1*Nq2, Np1, Np2, Np3) --> (Np1, Nq1*Nq2, Np2, Np3) - self.f = af.approx1(af.reorder(self.f, 3, 2, 0, 1), - af.reorder(p1_interpolant), - af.INTERP.CUBIC_SPLINE, - ) - - # Changing f from (Np1, Nq1*Np2, Np2, Np3) --> (Nq1*Nq2, Np1, Np2, Np3) - self.f = af.reorder(self.f) + # Reordering from (Np1, Np2, Nq1*Nq2, Np3) -> (Nq1*Nq2, Np1, Np2, Np3) + self.f = af.reorder(self.f, 2, 0, 1, 3) self.f = self._convert_to_q_expanded(self.f) - af.eval(self.f) - if(self.performance_test_flag == True): af.sync() toc = af.time() diff --git a/bolt/lib/nonlinear_solver/nonlinear_solver.py b/bolt/lib/nonlinear_solver/nonlinear_solver.py index 24923051..7b0cd0c8 100644 --- a/bolt/lib/nonlinear_solver/nonlinear_solver.py +++ b/bolt/lib/nonlinear_solver/nonlinear_solver.py @@ -29,7 +29,7 @@ from bolt.lib.nonlinear_solver.compute_moments \ import compute_moments as compute_moments_imported from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic \ - import fft_poisson, compute_electrostatic_fields + import fft_poisson, poisson_eqn_3D, compute_electrostatic_fields # The following function is used in formatting for print: def indent(txt, stops=1): @@ -157,19 +157,50 @@ def __init__(self, physical_system): comm = self._comm ) - # Additionally, a DA object also needs to be created for the KSP solver + # Additionally, a DA object also needs to be created for the SNES solver # with a DOF of 1: - self._da_snes = PETSc.DMDA().create([self.N_q1, self.N_q2], + # TODO: Remove the following hardcoded values + self.length_multiples_q1 = 1 + self.length_multiples_q2 = 1 + self.q3_3D_start = 0.; self.q3_3D_end = 2. + self.dq3 = physical_system.dq1 + + self.N_q1_poisson = (2*self.length_multiples_q1+1)*self.N_q1 + self.N_q2_poisson = (2*self.length_multiples_q2+1)*self.N_q2 + self.N_q3_poisson = (int)((self.q3_3D_end - self.q3_3D_start) / self.dq3) + + self._da_snes = PETSc.DMDA().create([self.N_q1_poisson, + self.N_q2_poisson, + self.N_q3_poisson], stencil_width = self.N_ghost, - boundary_type = (self.bc_in_q1, - self.bc_in_q2 + boundary_type = (petsc_bc_in_q1, + petsc_bc_in_q2, + 'periodic' ), proc_sizes = (PETSc.DECIDE, + PETSc.DECIDE, PETSc.DECIDE ), stencil_type = 1, dof = 1, - comm = self._comm) + comm = self._comm + ) + self.snes = PETSc.SNES().create() + self.poisson = poisson_eqn_3D(self) + self.snes.setFunction(self.poisson.compute_residual, + self.poisson.glob_residual + ) + + self.snes.setDM(self._da_snes) + self.snes.setFromOptions() + + # Obtaining the left-bottom corner coordinates + # (lowest values of the canonical coordinates in the local zone) + ((i_q1_start, i_q2_start), (N_q1_local, N_q2_local)) = self._da_f.getCorners() + self.i_q1_start = i_q1_start + self.i_q2_start = i_q2_start + self.N_q1_local = N_q1_local + self.N_q2_local = N_q2_local self._da_dump_moments = PETSc.DMDA().create([self.N_q1, self.N_q2], dof = len(self. @@ -192,12 +223,6 @@ def __init__(self, physical_system): self._glob_fields = self._da_fields.createGlobalVec() self._local_fields = self._da_fields.createLocalVec() - self.glob_phi = self._da_snes.createGlobalVec() - self.glob_residual = self._da_snes.createGlobalVec() - self.glob_phi.set(0.) - self.glob_residual.set(0.) - - # The following vector is used to dump the data to file: self._glob_moments = self._da_dump_moments.createGlobalVec() diff --git a/bolt/lib/nonlinear_solver/timestepper.py b/bolt/lib/nonlinear_solver/timestepper.py index 2c1e8e9b..a2eaedec 100644 --- a/bolt/lib/nonlinear_solver/timestepper.py +++ b/bolt/lib/nonlinear_solver/timestepper.py @@ -359,18 +359,29 @@ def op_advect_q(self, dt): # Solving for fields/advection in velocity space: op_fields = fields_step - # Cases which lack fields: - if(self.physical_system.params.charge_electron == 0): - _lie_split_operations(self, op_advect_q, op_solve_src, dt) +# # Cases which lack fields: +# if(self.physical_system.params.charge_electron == 0): +# _lie_split_operations(self, op_advect_q, op_solve_src, dt) +# +# +# else: +# def compound_op(self, dt): +# return(_lie_split_operations(self, op1 = op_advect_q, +# op2 = op_solve_src, dt = dt +# ) +# ) +# _lie_split_operations(self, compound_op, op_fields, dt) + + op_advect_q(self, 0.25*dt) + RK2_step(self, 0.5 *dt) + op_advect_q(self, 0.25*dt) + + fields_step(self, dt) + + op_advect_q(self, 0.25*dt) + RK2_step(self, 0.5 *dt) + op_advect_q(self, 0.25*dt) - - else: - def compound_op(self, dt): - return(_lie_split_operations(self, op1 = op_advect_q, - op2 = op_solve_src, dt = dt - ) - ) - _lie_split_operations(self, compound_op, op_fields, dt) self.time_elapsed += dt diff --git a/bolt/lib/nonlinear_solver/timestepper_source.py b/bolt/lib/nonlinear_solver/timestepper_source.py index a44aaed2..301b273e 100644 --- a/bolt/lib/nonlinear_solver/timestepper_source.py +++ b/bolt/lib/nonlinear_solver/timestepper_source.py @@ -24,7 +24,7 @@ def RK2_step(self, dt): args = () # Obtaining value at midpoint(dt/2) - self.f = self.f + self._source(self.f, *args) * (dt / 2) + #self.f = self.f + self._source(self.f, *args) * (dt / 2) self.f = f_initial + self._source(self.f, *args) * dt af.eval(self.f) diff --git a/bolt/src/electronic_boltzmann/advection_terms.py b/bolt/src/electronic_boltzmann/advection_terms.py new file mode 100644 index 00000000..81ccba93 --- /dev/null +++ b/bolt/src/electronic_boltzmann/advection_terms.py @@ -0,0 +1,36 @@ +import numpy as np +import arrayfire as af + +@af.broadcast +def A_q(q1, q2, p1, p2, p3, params): + """Return the terms A_q1, A_q2.""" + + A_q1, A_q2 = params.vel_band + + return (A_q1, A_q2) + +# This can then be called inside A_p if needed: +# F1 = (params.char....)(E1 + ....) + T1(q1, q2, p1, p2, p3) + +def A_p(q1, q2, p1, p2, p3, + E1, E2, E3, B1, B2, B3, + params + ): + """Return the terms A_p1, A_p2 and A_p3.""" + e = params.charge_electron + c = params.speed_of_light + +# dp1_dt = e*(E1 + (p2*B3 - p3*B2) / c) # p1 = hcross * k1 +# dp2_dt = e*(E2 + (p3*B1 - p1*B3) / c) # p2 = hcross * k2 +# dp3_dt = e*(E3 + (p1*B2 - p2*B1) / c) # p3 = hcross * k3 + + dp1_dt = e*E1 + dp2_dt = e*E2 + dp3_dt = 0. + + #dp1_dt = 1e-5*e*0.5*(-af.tanh(100.*(q1 - 0.9)) - af.tanh(100.*(q1 - 0.1)) ) +# amplitude = 0.1 +# E1_analytic = amplitude * -(q1 - 0.5) +# dp1_dt = E1_analytic + + 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..26da713e --- /dev/null +++ b/bolt/src/electronic_boltzmann/collision_operator.py @@ -0,0 +1,266 @@ +"""Contains the function which returns the Source/Sink term.""" + +import numpy as np +import arrayfire as af +from .matrix_inverse import inverse_4x4_matrix +import domain + +# Using af.broadcast, since p1, p2, p3 are of size (1, 1, Np1*Np2*Np3) +# 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, p1, p2, p3, params): + + # 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 dp1 * dp2 + a00 = af.sum(T / denominator, 2) + a01 = af.sum((E_upper - mu) / denominator, 2) + a10 = af.sum(E_upper*T / denominator, 2) + a11 = af.sum(E_upper*(E_upper - mu) / denominator, 2) + + # 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 = af.sum(zeroth_moment, 2) + eqn_energy_conservation = af.sum(second_moment, 2) + + N_g = domain.N_ghost + error_mass_conservation = af.max(af.abs(eqn_mass_conservation)[N_g:-N_g, N_g:-N_g]) + error_energy_conservation = af.max(af.abs(eqn_energy_conservation)[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 = af.sum(zeroth_moment, 2) + eqn_energy_conservation = af.sum(second_moment, 2) + + 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(" ------------------") + + return(fermi_dirac) + +@af.broadcast +def f0_ee(f, p1, p2, p3, params): + + # 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 + phi = 0.*params.charge_electron * params.phi + + for n in range(params.collision_nonlinear_iters): + + E_upper = params.E_band + phi + k = params.boltzmann_constant + + tmp1 = (E_upper - mu_ee - p1*vel_drift_x - p2*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 * p1 / denominator + a_3 = T_ee * p2 / denominator + + af.eval(a_0, a_1, a_2, a_3) + + # TODO: Multiply with the integral measure dp1 * dp2 + a_00 = af.sum(a_0, 2) + a_01 = af.sum(a_1, 2) + a_02 = af.sum(a_2, 2) + a_03 = af.sum(a_3, 2) + + a_10 = af.sum(E_upper * a_0, 2) + a_11 = af.sum(E_upper * a_1, 2) + a_12 = af.sum(E_upper * a_2, 2) + a_13 = af.sum(E_upper * a_3, 2) + + a_20 = af.sum(p1 * a_0, 2) + a_21 = af.sum(p1 * a_1, 2) + a_22 = af.sum(p1 * a_2, 2) + a_23 = af.sum(p1 * a_3, 2) + + a_30 = af.sum(p2 * a_0, 2) + a_31 = af.sum(p2 * a_1, 2) + a_32 = af.sum(p2 * a_2, 2) + a_33 = af.sum(p2 * a_3, 2) + + 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*p1 - vel_drift_y*p2 + )/(k*T_ee) + ) + 1. + ) + af.eval(fermi_dirac) + + zeroth_moment = (f - fermi_dirac) + second_moment = E_upper*(f - fermi_dirac) + first_moment_x = p1*(f - fermi_dirac) + first_moment_y = p2*(f - fermi_dirac) + + eqn_mass_conservation = af.sum(zeroth_moment, 2) + eqn_energy_conservation = af.sum(second_moment, 2) + eqn_mom_x_conservation = af.sum(first_moment_x, 2) + eqn_mom_y_conservation = af.sum(first_moment_y, 2) + + 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(" ||residual_ee|| = ", error_norm) + + if (error_norm < 1e-13): + 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*p1 - vel_drift_y*p2 + )/(k*T_ee) + ) + 1. + ) + af.eval(fermi_dirac) + + zeroth_moment = f - fermi_dirac + second_moment = E_upper*(f - fermi_dirac) + first_moment_x = p1*(f - fermi_dirac) + first_moment_y = p2*(f - fermi_dirac) + + eqn_mass_conservation = af.sum(zeroth_moment, 2) + eqn_energy_conservation = af.sum(second_moment, 2) + eqn_mom_x_conservation = af.sum(first_moment_x, 2) + eqn_mom_y_conservation = af.sum(first_moment_y, 2) + + 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(" ||residual_ee|| = ", error_norm) + print(" ------------------") + + return(fermi_dirac) + +def RTA(f, q1, q2, p1, p2, p3, moments, params): + """Return BGK operator -(f-f0)/tau.""" + + C_f = -( f - f0_defect(f, p1, p2, p3, params) + ) / params.tau_defect(q1, q2, p1, p2, p3) \ +# -( f - f0_ee(f, p1, p2, p3, params) +# ) / params.tau_ee(q1, q2, p1, p2, p3) + # When (f - f0) is NaN. Dividing by np.inf doesn't give 0 + # WORKAROUND: + C_f = af.select(params.tau_defect(q1, q2, p1, p2, p3) == np.inf, 0, C_f) +# C_f = af.select(params.tau_ee(q1, q2, p1, p2, p3) == np.inf, 0, C_f) + + af.eval(C_f) + return(C_f) diff --git a/bolt/src/electronic_boltzmann/matrix_inverse.py b/bolt/src/electronic_boltzmann/matrix_inverse.py new file mode 100644 index 00000000..4b987180 --- /dev/null +++ b/bolt/src/electronic_boltzmann/matrix_inverse.py @@ -0,0 +1,189 @@ +import numpy as np +import arrayfire as af + +def inverse_4x4_matrix(A): +# 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) + + 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) diff --git a/bolt/src/electronic_boltzmann/moment_defs.py b/bolt/src/electronic_boltzmann/moment_defs.py new file mode 100644 index 00000000..1270a22f --- /dev/null +++ b/bolt/src/electronic_boltzmann/moment_defs.py @@ -0,0 +1,3 @@ +moment_exponents = dict(density = [0, 0, 0]) + +moment_coeffs = dict(density = [1, 0, 0]) From 48748eaa3db1b5c5a44be1ff1ee152a8e51d0f25 Mon Sep 17 00:00:00 2001 From: Mani Chandra Date: Mon, 4 Dec 2017 23:15:07 +0530 Subject: [PATCH 10/28] (1) Changed units: length scale = 1 um, time scale = 1 ps (2) Added isothermal e-ph collision operator --- .../EM_fields_solver/electrostatic.py | 14 ++-- .../EM_fields_solver/fields_step.py | 2 +- .../apply_boundary_conditions.py | 4 +- bolt/lib/nonlinear_solver/nonlinear_solver.py | 2 +- .../electronic_boltzmann/advection_terms.py | 10 +-- .../collision_operator.py | 83 ++++++++++++++++++- bolt/src/electronic_boltzmann/moment_defs.py | 5 +- 7 files changed, 103 insertions(+), 17 deletions(-) diff --git a/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py b/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py index bf701d9f..d556be4d 100644 --- a/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py +++ b/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py @@ -76,7 +76,7 @@ def __init__(self, nonlinear_solver_obj): self.N_q2_3D_local = N_q2_3D_local self.N_q3_3D_local = N_q3_3D_local - location_in_q3 = 1. + location_in_q3 = 10. N_g = self.N_ghost self.density_np = np.zeros([N_q2_2D_local + 2*N_g, @@ -141,8 +141,8 @@ def __init__(self, nonlinear_solver_obj): N_q1_3D_local + 2*N_g ] ) - epsilon_array[:] = 1. - epsilon_array[:self.q3_2D_in_3D_index_start, :, :] = 10. + epsilon_array[:] = params.epsilon0 + epsilon_array[:self.q3_2D_in_3D_index_start, :, :] = 10.*params.epsilon0 self.epsilon_array = epsilon_array q3_3D_data_structure = 0.*epsilon_array @@ -151,7 +151,7 @@ def __init__(self, nonlinear_solver_obj): for i in range(q3_3D_data_structure.shape[2]): q3_3D_data_structure[:, j, i] = q3_3D - backgate_potential = -0.001 + backgate_potential = -100. self.q3 = q3_3D_data_structure z = self.q3 @@ -258,7 +258,8 @@ def compute_residual(self, snes, phi, residual): q1_2D_in_3D_index_start:q1_2D_in_3D_index_end+1 ] \ += \ - 4.*np.pi*params.charge_electron*self.density_np[N_g:-N_g, N_g:-N_g] + -params.charge_electron \ + * self.density_np[N_g:-N_g, N_g:-N_g] / self.dq3 residual_array[:, :, :] = \ laplacian_phi[N_g:-N_g, N_g:-N_g, N_g:-N_g] @@ -307,7 +308,7 @@ def compute_residual(self, snes, phi, residual): mid_point_q2_index = \ (int)((q2_2D_in_3D_index_start + q2_2D_in_3D_index_end)/2) - size_of_inflow = 0.25 + size_of_inflow = 5. length_y = self.obj.q2_end - self.obj.q2_start N_inflow_zones = (int)(size_of_inflow/length_y*self.obj.N_q2) N_outflow_zones = N_inflow_zones @@ -354,6 +355,7 @@ def compute_electrostatic_fields(self): self.N_q1_local+2*N_g ] ) + self.snes.solve(None, self.poisson.glob_phi) self._da_snes.globalToLocal(self.poisson.glob_phi, diff --git a/bolt/lib/nonlinear_solver/EM_fields_solver/fields_step.py b/bolt/lib/nonlinear_solver/EM_fields_solver/fields_step.py index 04351f5f..ef471db4 100644 --- a/bolt/lib/nonlinear_solver/EM_fields_solver/fields_step.py +++ b/bolt/lib/nonlinear_solver/EM_fields_solver/fields_step.py @@ -20,7 +20,7 @@ def fields_step(self, dt): self._communicate_fields() elif (self.physical_system.params.fields_solver == 'electrostatic'): - compute_electrostatic_fields(self) + #compute_electrostatic_fields(self) self._communicate_fields() elif (self.physical_system.params.fields_solver == 'fdtd'): diff --git a/bolt/lib/nonlinear_solver/apply_boundary_conditions.py b/bolt/lib/nonlinear_solver/apply_boundary_conditions.py index c42272ee..67577121 100644 --- a/bolt/lib/nonlinear_solver/apply_boundary_conditions.py +++ b/bolt/lib/nonlinear_solver/apply_boundary_conditions.py @@ -103,7 +103,7 @@ def apply_bcs_f(self): # Inflow between y = [y_center(j_inflow_start), y_center(j_inflow_end)] N_q2 = self.N_q2 - size_of_inflow = 0.25 + size_of_inflow = 5. offset_from_center = 0. length_y = self.q2_end - self.q2_start N_inflow_zones = (int)(size_of_inflow/length_y*N_q2) @@ -158,7 +158,7 @@ def apply_bcs_f(self): # Outflow between y = [y_center(j_outflow_start), y_center(j_outflow_end)] N_q2 = self.N_q2 - size_of_outflow = 0.25 + size_of_outflow = 5. offset_from_center = 0. length_y = self.q2_end - self.q2_start N_outflow_zones = (int)(size_of_outflow/length_y*N_q2) diff --git a/bolt/lib/nonlinear_solver/nonlinear_solver.py b/bolt/lib/nonlinear_solver/nonlinear_solver.py index 7b0cd0c8..e9b95c8c 100644 --- a/bolt/lib/nonlinear_solver/nonlinear_solver.py +++ b/bolt/lib/nonlinear_solver/nonlinear_solver.py @@ -162,7 +162,7 @@ def __init__(self, physical_system): # TODO: Remove the following hardcoded values self.length_multiples_q1 = 1 self.length_multiples_q2 = 1 - self.q3_3D_start = 0.; self.q3_3D_end = 2. + self.q3_3D_start = 0.; self.q3_3D_end = 20. self.dq3 = physical_system.dq1 self.N_q1_poisson = (2*self.length_multiples_q1+1)*self.N_q1 diff --git a/bolt/src/electronic_boltzmann/advection_terms.py b/bolt/src/electronic_boltzmann/advection_terms.py index 81ccba93..76c56dad 100644 --- a/bolt/src/electronic_boltzmann/advection_terms.py +++ b/bolt/src/electronic_boltzmann/advection_terms.py @@ -24,13 +24,13 @@ def A_p(q1, q2, p1, p2, p3, # dp2_dt = e*(E2 + (p3*B1 - p1*B3) / c) # p2 = hcross * k2 # dp3_dt = e*(E3 + (p1*B2 - p2*B1) / c) # p3 = hcross * k3 - dp1_dt = e*E1 - dp2_dt = e*E2 + dp1_dt = 0.*-e*E1 + dp2_dt = 0.*-e*E2 dp3_dt = 0. #dp1_dt = 1e-5*e*0.5*(-af.tanh(100.*(q1 - 0.9)) - af.tanh(100.*(q1 - 0.1)) ) -# amplitude = 0.1 -# E1_analytic = amplitude * -(q1 - 0.5) -# dp1_dt = E1_analytic + amplitude = 1e-3 + E1_analytic = amplitude * -(q1 - 5.) + dp1_dt = E1_analytic 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 index 26da713e..9dd189fb 100644 --- a/bolt/src/electronic_boltzmann/collision_operator.py +++ b/bolt/src/electronic_boltzmann/collision_operator.py @@ -5,6 +5,78 @@ from .matrix_inverse import inverse_4x4_matrix import domain +@af.broadcast +def f0_defect_constant_T(f, p1, p2, p3, params): + + 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 dp1 * dp2 + a00 = af.sum(T / denominator, 2) + + fermi_dirac = 1./(af.exp( (E_upper - mu)/(k*T) ) + 1.) + af.eval(fermi_dirac) + + zeroth_moment = f - fermi_dirac + + eqn_mass_conservation = af.sum(zeroth_moment, 2) + + N_g = domain.N_ghost + error_mass_conservation = af.max(af.abs(eqn_mass_conservation)[N_g:-N_g, N_g:-N_g]) + + residual = [eqn_mass_conservation] + error_norm = np.max([af.max(af.abs(residual[0]))]) + print(" ||residual_defect|| = ", error_norm) + + 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 = af.sum(zeroth_moment, 2) + + N_g = domain.N_ghost + error_mass_conservation = af.max(af.abs(eqn_mass_conservation)[N_g:-N_g, N_g:-N_g]) + + residual = [eqn_mass_conservation] + error_norm = np.max([af.max(af.abs(residual[0]))]) + print(" ||residual_defect|| = ", error_norm) + + density_f = af.sum((f), 2) + fermi_dirac = 1./(af.exp( (E_upper - mu)/(k*T) ) + 1.) + density_fermi_dirac = af.sum(fermi_dirac, 2) + + print(" mu = ", af.mean(params.mu[N_g:-N_g, N_g:-N_g]), + "T = ", af.mean(params.T[N_g:-N_g, N_g:-N_g]), + "density_f = ", af.mean(density_f[N_g:-N_g, N_g:-N_g]), + "density_fermi_dirac = ",af.mean(density_fermi_dirac[N_g:-N_g, N_g:-N_g]) + ) + print(" ------------------") + + return(fermi_dirac) + + # Using af.broadcast, since p1, p2, p3 are of size (1, 1, Np1*Np2*Np3) # All moment quantities are of shape (Nq1, Nq2) # By wrapping with af.broadcast, we can perform batched operations @@ -90,6 +162,15 @@ def f0_defect(f, p1, p2, p3, params): af.max(af.abs(residual[1]))] ) print(" ||residual_defect|| = ", error_norm) + density_f = af.sum(f, 2) + fermi_dirac = 1./(af.exp( (E_upper - mu)/(k*T) ) + 1.) + density_fermi_dirac = af.sum(fermi_dirac, 2) + + print(" mu = ", af.mean(params.mu[N_g:-N_g, N_g:-N_g]), + "T = ", af.mean(params.T[N_g:-N_g, N_g:-N_g]), + "density_f = ", af.mean(density_f[N_g:-N_g, N_g:-N_g]), + "density_fermi_dirac = ",af.mean(density_fermi_dirac[N_g:-N_g, N_g:-N_g]) + ) print(" ------------------") return(fermi_dirac) @@ -253,7 +334,7 @@ def f0_ee(f, p1, p2, p3, params): def RTA(f, q1, q2, p1, p2, p3, moments, params): """Return BGK operator -(f-f0)/tau.""" - C_f = -( f - f0_defect(f, p1, p2, p3, params) + C_f = -( f - f0_defect_constant_T(f, p1, p2, p3, params) ) / params.tau_defect(q1, q2, p1, p2, p3) \ # -( f - f0_ee(f, p1, p2, p3, params) # ) / params.tau_ee(q1, q2, p1, p2, p3) diff --git a/bolt/src/electronic_boltzmann/moment_defs.py b/bolt/src/electronic_boltzmann/moment_defs.py index 1270a22f..03c8506f 100644 --- a/bolt/src/electronic_boltzmann/moment_defs.py +++ b/bolt/src/electronic_boltzmann/moment_defs.py @@ -1,3 +1,6 @@ +import numpy as np +import params + moment_exponents = dict(density = [0, 0, 0]) -moment_coeffs = dict(density = [1, 0, 0]) +moment_coeffs = dict(density = [4./(2.*np.pi*params.h_bar)**2., 0, 0]) From 91e53ade9a87ec72faa4f046dd477fc6efca5b36 Mon Sep 17 00:00:00 2001 From: Mani Chandra Date: Tue, 5 Dec 2017 19:20:57 +0530 Subject: [PATCH 11/28] Deleted file timestepper_source.py that crept in during merge --- .../nonlinear_solver/timestepper_source.py | 130 ------------------ 1 file changed, 130 deletions(-) delete mode 100644 bolt/lib/nonlinear_solver/timestepper_source.py diff --git a/bolt/lib/nonlinear_solver/timestepper_source.py b/bolt/lib/nonlinear_solver/timestepper_source.py deleted file mode 100644 index 301b273e..00000000 --- a/bolt/lib/nonlinear_solver/timestepper_source.py +++ /dev/null @@ -1,130 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -import arrayfire as af - - -def RK2_step(self, dt): - """ - Evolves the source/sink term specified by the user - df/dt = source_sink_term - using RK2 time stepping. - """ - if(self.performance_test_flag == True): - tic = af.time() - - f_initial = self.f # Storing the value at the start - - if (self.testing_source_flag == False): - args = (self.q1_center, self.q2_center, self.p1, self.p2, - self.p3, self.compute_moments, self.physical_system.params - ) - - else: - args = () - - # Obtaining value at midpoint(dt/2) - #self.f = self.f + self._source(self.f, *args) * (dt / 2) - self.f = f_initial + self._source(self.f, *args) * dt - - af.eval(self.f) - - if(self.performance_test_flag == True): - af.sync() - toc = af.time() - self.time_sourcets += toc - tic - - return - - -def RK4_step(self, dt): - """ - Evolves the source/sink term specified by the user - df/dt = source_sink_term - using RK4 time stepping. - """ - if(self.performance_test_flag == True): - tic = af.time() - - f_initial = self.f # Storing the value at the start - - if (self.testing_source_flag == False): - args = (self.q1_center, self.q2_center, self.p1, self.p2, - self.p3, self.compute_moments, self.physical_system.params - ) - - else: - args = () - - k1 = self._source(self.f, *args) - self.f = f_initial + 0.5 * k1 * dt - k2 = self._source(self.f, *args) - self.f = f_initial + 0.5 * k2 * dt - k3 = self._source(self.f, *args) - self.f = f_initial + k3 * dt - k4 = self._source(self.f, *args) - - self.f = f_initial + ((k1 + 2 * k2 + 2 * k3 + k4) / 6) * dt - - af.eval(self.f) - - if(self.performance_test_flag == True): - af.sync() - toc = af.time() - self.time_sourcets += toc - tic - - return - - -def RK6_step(self, dt): - """ - Evolves the source/sink term specified by the user - df/dt = source_sink_term - using RK6 time stepping. - """ - if(self.performance_test_flag == True): - tic = af.time() - - f_initial = self.f # Storing the value at the start - - if (self.testing_source_flag == False): - args = (self.q1_center, self.q2_center, self.p1, self.p2, - self.p3, self.compute_moments, self.physical_system.params - ) - - else: - args = () - - k1 = self._source(self.f, *args) - self.f = f_initial + 0.25 * k1 * dt - - k2 = self._source(self.f, *args) - self.f = f_initial + (3 / 32) * (k1 + 3 * k2) * dt - - k3 = self._source(self.f, *args) - self.f = f_initial + (12 / 2197) * (161 * k1 - 600 * k2 + 608 * k3) * dt - - k4 = self._source(self.f, *args) - self.f = f_initial + (1 / 4104) * ( 8341 * k1 - 32832 * k2 - + 29440 * k3 - 845 * k4 - ) * dt - - k5 = self._source(self.f, *args) - self.f = f_initial + (- (8 / 27) * k1 + 2 * k2 - (3544 / 2565) * k3 - + (1859 / 4104) * k4 - (11 / 40) * k5 - ) * dt - - k6 = self._source(self.f, *args) - self.f = f_initial + 1 / 5 * ( (16 / 27) * k1 + (6656 / 2565) * k3 - + (28561 / 11286) * k4 - (9 / 10) * k5 - + (2 / 11) * k6 - ) * dt - - af.eval(self.f) - - if(self.performance_test_flag == True): - af.sync() - toc = af.time() - self.time_sourcets += toc - tic - - return From 35ff5f40080479de660f604a85e25a20a52d18e6 Mon Sep 17 00:00:00 2001 From: Mani Chandra Date: Tue, 5 Dec 2017 19:21:58 +0530 Subject: [PATCH 12/28] Added graphene example problem --- .../graphene/boundary_conditions.py | 33 +++ .../electronic_boltzmann/graphene/domain.py | 21 ++ .../graphene/initialize.py | 54 ++++ .../electronic_boltzmann/graphene/main.py | 238 ++++++++++++++++++ .../electronic_boltzmann/graphene/params.py | 75 ++++++ .../electronic_boltzmann/graphene/post.py | 74 ++++++ 6 files changed, 495 insertions(+) create mode 100644 example_problems/electronic_boltzmann/graphene/boundary_conditions.py create mode 100644 example_problems/electronic_boltzmann/graphene/domain.py create mode 100644 example_problems/electronic_boltzmann/graphene/initialize.py create mode 100644 example_problems/electronic_boltzmann/graphene/main.py create mode 100644 example_problems/electronic_boltzmann/graphene/params.py create mode 100644 example_problems/electronic_boltzmann/graphene/post.py diff --git a/example_problems/electronic_boltzmann/graphene/boundary_conditions.py b/example_problems/electronic_boltzmann/graphene/boundary_conditions.py new file mode 100644 index 00000000..b8b5793b --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/boundary_conditions.py @@ -0,0 +1,33 @@ +import arrayfire as af +import domain + +in_q1 = 'mirror' +in_q2 = 'mirror' + +@af.broadcast +def f_left(q1, q2, p1, p2, p3, params): + + k = params.boltzmann_constant + E_upper = params.E_band + T = 0.*params.T + 3e-4*4. + + f = (1./(af.exp( (E_upper - 0.01)/(k*T) + ) + 1. + )) + + af.eval(f) + return(f) + +@af.broadcast +def f_right(q1, q2, p1, p2, p3, params): + + k = params.boltzmann_constant + E_upper = params.E_band + T = 0.*params.T + 3e-4*4. + + f = (1./(af.exp( (E_upper - 0.01)/(k*T) + ) + 1. + )) + + af.eval(f) + return(f) diff --git a/example_problems/electronic_boltzmann/graphene/domain.py b/example_problems/electronic_boltzmann/graphene/domain.py new file mode 100644 index 00000000..62a42b5f --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/domain.py @@ -0,0 +1,21 @@ +q1_start = 0. +q1_end = 10. +N_q1 = 28 + +q2_start = 0. +q2_end = 10. +N_q2 = 28 + +p1_start = -0.02 +p1_end = 0.02 +N_p1 = 64 + +p2_start = -0.02 +p2_end = 0.02 +N_p2 = 64 + +p3_start = -0.5 +p3_end = 0.5 +N_p3 = 1 + +N_ghost = 3 diff --git a/example_problems/electronic_boltzmann/graphene/initialize.py b/example_problems/electronic_boltzmann/graphene/initialize.py new file mode 100644 index 00000000..781ea8a9 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/initialize.py @@ -0,0 +1,54 @@ +""" +Functions which are used in assigning the I.C's to +the system. +""" + +import arrayfire as af +import numpy as np + +def initialize_f(q1, q2, p1, p2, p3, params): + + print("Initializing f") + k = params.boltzmann_constant + + params.mu = 0.*q1 + 0.01 + params.T = 0.*q1 + 3e-4*4. + 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.E_band = params.band_energy(p1, p2) + params.vel_band = params.band_velocity(p1, p2) + + E_upper = params.E_band + params.charge_electron*params.phi + + f = (1./(af.exp( (E_upper - params.vel_drift_x*p1 + - params.vel_drift_y*p2 + - 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/main.py b/example_problems/electronic_boltzmann/graphene/main.py new file mode 100644 index 00000000..7adb5005 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/main.py @@ -0,0 +1,238 @@ +import arrayfire as af +import numpy as np +import pylab as pl +import h5py +import petsc4py, sys; petsc4py.init(sys.argv) + +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 + +pl.rcParams['figure.figsize'] = 12, 7.5 +pl.rcParams['figure.dpi'] = 150 +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'] = 20 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = False +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' + + +# 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_nls = nls.compute_moments('density') + +# Time parameters: +dt = 0.1 +t_final = 1000. + +time_array = np.arange(dt, t_final + dt, dt) +#compute_electrostatic_fields(nls) +#params.mu = params.charge_electron*params.phi + +N_g = domain.N_ghost +#N_q1_local = params.mu.shape[0] - 2*N_g +#for i in range(N_g): +# params.mu[i, :] = 0.*params.mu[N_g, :] +# params.mu[N_q1_local+N_g+i, :] = 0.*params.mu[N_q1_local+N_g-1, :] + +print("mu = ", af.mean(params.mu[N_g:-N_g, N_g:-N_g]), + "phi = ", af.mean(params.phi[N_g:-N_g, N_g:-N_g]), + "density = ", af.mean(n_nls[N_g:-N_g, N_g:-N_g]) + ) + +for time_index, t0 in enumerate(time_array): + print("Time step =", time_index, ", Time =", t0) + + N_g = domain.N_ghost + mean_density = af.mean(n_nls[N_g:-N_g, N_g:-N_g]) + density_pert = n_nls - mean_density + + if (time_index%1==0): + pl.contourf(np.array(nls.q1_center)[N_g:-N_g, N_g:-N_g], \ + np.array(nls.q2_center)[N_g:-N_g, N_g:-N_g], \ + np.array(density_pert)[N_g:-N_g, N_g:-N_g], \ + 100, cmap='bwr' + ) +# pl.contourf(np.array(nls.q1_center)[N_g:-N_g, N_g:-N_g], \ +# np.array(nls.q2_center)[N_g:-N_g, N_g:-N_g], \ +# np.log10(np.array(n_nls))[N_g:-N_g, N_g:-N_g], \ +# 100, cmap='hot' +# ) + pl.title('Time = ' + "%.2f"%(t0) ) + pl.xlabel('$x$') + pl.ylabel('$y$') + pl.colorbar() + pl.gca().set_aspect('equal') + pl.savefig('/tmp/density_' + '%06d'%time_index + '.png' ) + pl.clf() + + pl.contourf(np.array(nls.q1_center), \ + np.array(nls.q2_center), \ + np.array(nls.E1), \ + 100, cmap='bwr' + ) + pl.title('Time = ' + "%.2f"%(t0) ) + pl.xlabel('$x$') + pl.ylabel('$y$') + pl.colorbar() + pl.gca().set_aspect('equal') + pl.savefig('/tmp/E1_' + '%06d'%time_index + '.png' ) + pl.clf() + + pl.contourf(np.array(nls.q1_center), \ + np.array(nls.q2_center), \ + np.array(nls.E2), \ + 100, cmap='bwr' + ) + pl.title('Time = ' + "%.2f"%(t0) ) + pl.xlabel('$x$') + pl.ylabel('$y$') + pl.colorbar() + pl.gca().set_aspect('equal') + pl.savefig('/tmp/E2_' + '%06d'%time_index + '.png' ) + pl.clf() + + f_at_desired_q = af.moddims(nls.f[N_g, N_g + nls.N_q2/2], + nls.N_p1, nls.N_p2 + ) + p1 = af.moddims(nls.p1, nls.N_p1, nls.N_p2) + p2 = af.moddims(nls.p2, nls.N_p1, nls.N_p2) + pl.contourf(np.array(p1), \ + np.array(p2), \ + np.array((f_at_desired_q)), \ + 100, cmap='bwr' + ) + pl.title('Time = ' + "%.2f"%(t0) ) + pl.xlabel('$x$') + pl.ylabel('$y$') + pl.colorbar() + pl.gca().set_aspect('equal') + pl.savefig('/tmp/f_' + '%06d'%time_index + '.png' ) + pl.clf() + +# pl.contourf(np.array(params.mu)[N_g:-N_g, N_g:-N_g].transpose(), 100, cmap='jet') +# pl.title('Time = ' + "%.2f"%(t0) ) +# pl.xlabel('$x$') +# pl.ylabel('$y$') +# pl.colorbar() +# pl.gca().set_aspect('equal') +# pl.savefig('/tmp/mu_' + '%06d'%time_index + '.png' ) +# pl.clf() +# + + nls.strang_timestep(dt) + n_nls = nls.compute_moments('density') + print("mu = ", af.mean(params.mu[N_g:-N_g, N_g:-N_g]), + "phi = ", af.mean(params.phi[N_g:-N_g, N_g:-N_g]), + "density = ", mean_density + ) + print("--------------------\n") + +##pl.contourf(np.array(params.mu)[N_g:-N_g, N_g:-N_g].transpose(), 100, cmap='jet') +#pl.contourf(np.array(n_nls)[N_g:-N_g, N_g:-N_g].transpose(), 100, cmap='jet') +#pl.title('Density') +##pl.title('$\\mu$') +#pl.xlabel('$x$') +#pl.ylabel('$y$') +#pl.colorbar() +#pl.gca().set_aspect('equal') +#pl.show() + +phi_array = nls.poisson.glob_phi.getArray() +phi_array = phi_array.reshape([nls.poisson.N_q3_3D_local, \ + nls.poisson.N_q2_3D_local, \ + nls.poisson.N_q1_3D_local] + ) +pl.rcParams['figure.figsize'] = 20, 7.5 +pl.subplot(121) +N_g = domain.N_ghost +pl.contourf( + phi_array[nls.poisson.q3_2D_in_3D_index_start, :, :], 100, cmap='jet' + ) +#pl.contourf(np.array(nls.E1)[N_g:-N_g, N_g:-N_g].transpose(), 100, cmap='jet' +# ) +pl.colorbar() +pl.title('Top View') +pl.xlabel('$x$') +pl.ylabel('$y$') +pl.gca().set_aspect('equal') + +pl.subplot(122) +pl.contourf(phi_array[:, nls.N_q2_poisson/2, :], 100, cmap='jet') +#pl.contourf(np.array(nls.E2)[N_g:-N_g, N_g:-N_g].transpose(), 100, cmap='jet') +pl.title('Side View') +pl.xlabel('$x$') +pl.ylabel('$z$') +pl.colorbar() +pl.gca().set_aspect('equal') +pl.show() + +#h5f = h5py.File('dump/0000.h5', 'w') +#h5f.create_dataset('q1', data = nls.q1_center) +#h5f.create_dataset('q2', data = nls.q2_center) +#h5f.create_dataset('n', data = n_nls) +#h5f.close() +# +#def time_evolution(): +# +# for time_index, t0 in enumerate(time_array): +# print('For Time =', t0 ) +# print('MIN(f) =', af.min(nls.f[3:-3, 3:-3])) +# print('MAX(f) =', af.max(nls.f[3:-3, 3:-3])) +# print('SUM(f) =', af.sum(nls.f[3:-3, 3:-3])) +# print() +# +# nls.strang_timestep(dt) +# n_nls = nls.compute_moments('density') +# +# h5f = h5py.File('dump/%04d'%(time_index+1) + '.h5', 'w') +# h5f.create_dataset('n', data = n_nls) +# h5f.close() +# +#time_evolution() diff --git a/example_problems/electronic_boltzmann/graphene/params.py b/example_problems/electronic_boltzmann/graphene/params.py new file mode 100644 index 00000000..bf7cac22 --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/params.py @@ -0,0 +1,75 @@ +import numpy as np +import arrayfire as af + +# 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' +fields_solver = 'electrostatic' + +# Can be defined as 'strang' and 'lie' +time_splitting = 'strang' + +# Dimensionality considered in velocity space: +p_dim = 2 + +# Number of devices(GPUs/Accelerators) on each node: +num_devices = 1 + +# Constants: +mass_particle = 0.910938356 # x 1e-30 kg +h_bar = 1.0545718e-4 # x aJ ps +boltzmann_constant = 1 +charge_electron = -0.160217662 # x aC +speed_of_light = 300 # x [um/ps] +fermi_velocity = speed_of_light/300 +epsilon0 = 8.854187817 # x [aC^2 / (aJ um) ] + +# 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 + +# Momentum quantities (will be initialized to shape = [p1*p2*p3] in initialize.py) +E_band = None +vel_band = None + +collision_nonlinear_iters = 5 + +# Variation of collisional-timescale parameter through phase space: +def tau_defect(q1, q2, p1, p2, p3): + return (af.constant(1., q1.shape[0], q2.shape[1], + p1.shape[2], dtype = af.Dtype.f64 + ) + ) + +def tau_ee(q1, q2, p1, p2, p3): + return (af.constant(np.inf, q1.shape[0], q2.shape[1], + p1.shape[2], dtype = af.Dtype.f64 + ) + ) + +def band_energy(p_x, p_y): + + p = af.sqrt(p_x**2. + p_y**2.) + + return(p*fermi_velocity) + +def band_velocity(p_x, p_y): + + 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]] + + return(upper_band_velocity) + diff --git a/example_problems/electronic_boltzmann/graphene/post.py b/example_problems/electronic_boltzmann/graphene/post.py new file mode 100644 index 00000000..04cda77b --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/post.py @@ -0,0 +1,74 @@ +import numpy as np +import pylab as pl +import h5py + +# 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'] = 20 +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' + +dt = 0.001 +t_final = 2.0 +time = np.arange(dt, t_final + dt, dt) + +h5f = h5py.File('dump/0000.h5', 'r') +q1 = h5f['q1'][:] +q2 = h5f['q2'][:] +n = h5f['n'][:] +h5f.close() + +pl.contourf(q1[3:-3, 3:-3], + q2[3:-3, 3:-3], + n[3:-3, 3:-3], + 100, + cmap = 'gist_heat' + ) +pl.title('Time = 0') +pl.xlabel(r'$x$') +pl.ylabel(r'$y$') +pl.axes().set_aspect('equal') +pl.savefig('images/0000.png') +pl.clf() + +for time_index, t0 in enumerate(time): + h5f = h5py.File('dump/%04d'%(time_index+1) + '.h5', 'r') + n = h5f['n'][:] + h5f.close() + + pl.contourf(q1[3:-3, 3:-3], + q2[3:-3, 3:-3], + n[3:-3, 3:-3], + 100, + cmap = 'gist_heat' + ) + pl.title('Time =' + str(t0)) + pl.xlabel(r'$x$') + pl.ylabel(r'$y$') + pl.axes().set_aspect('equal') + pl.savefig('images/%04d'%(time_index+1) + '.png') + pl.clf() From c8ec4147bf484e4932992ebbd6004b6b51a677a8 Mon Sep 17 00:00:00 2001 From: Mani Chandra Date: Sun, 10 Dec 2017 01:04:41 +0530 Subject: [PATCH 13/28] First working version with FVM --- .../EM_fields_solver/fields_step.py | 3 +- .../nonlinear_solver/FVM_solver/df_dt_fvm.py | 40 ++- .../reconstruction_methods/weno5.py | 3 +- .../apply_boundary_conditions.py | 270 +++++++++--------- bolt/lib/nonlinear_solver/nonlinear_solver.py | 10 +- bolt/lib/nonlinear_solver/timestep.py | 88 +++--- bolt/lib/physical_system.py | 2 +- .../electronic_boltzmann/advection_terms.py | 18 +- .../collision_operator.py | 28 +- .../graphene/boundary_conditions.py | 61 +++- .../electronic_boltzmann/graphene/domain.py | 8 +- .../graphene/initialize.py | 11 +- .../electronic_boltzmann/graphene/main.py | 199 +++++++------ .../electronic_boltzmann/graphene/params.py | 44 ++- 14 files changed, 447 insertions(+), 338 deletions(-) diff --git a/bolt/lib/nonlinear_solver/EM_fields_solver/fields_step.py b/bolt/lib/nonlinear_solver/EM_fields_solver/fields_step.py index 53ca9e1d..9e325bff 100644 --- a/bolt/lib/nonlinear_solver/EM_fields_solver/fields_step.py +++ b/bolt/lib/nonlinear_solver/EM_fields_solver/fields_step.py @@ -16,7 +16,8 @@ def fields_step(self, dt): if (self.physical_system.params.fields_solver == 'fft'): fft_poisson(self) elif (self.physical_system.params.fields_solver == 'SNES'): - compute_electrostatic_fields(self) + #compute_electrostatic_fields(self) + pass self._communicate_fields() self._apply_bcs_fields() diff --git a/bolt/lib/nonlinear_solver/FVM_solver/df_dt_fvm.py b/bolt/lib/nonlinear_solver/FVM_solver/df_dt_fvm.py index fdd97147..553e1ba6 100644 --- a/bolt/lib/nonlinear_solver/FVM_solver/df_dt_fvm.py +++ b/bolt/lib/nonlinear_solver/FVM_solver/df_dt_fvm.py @@ -75,9 +75,15 @@ def df_dt_fvm(f, self, at_n = True): if( self.physical_system.params.solver_method_in_p == 'FVM' and self.physical_system.params.charge_electron != 0 ): - if(self.physical_system.params.fields_solver == 'fft'): - - fft_poisson(self, f) + if(self.physical_system.params.fields_type == 'electrostatic'): + if(self.physical_system.params.fields_solver == 'fft'): + + fft_poisson(self, f) + + elif(self.physical_system.params.fields_solver == 'SNES'): + #compute_electrostatic_fields(self) + pass + self._communicate_fields() self._apply_bcs_fields() @@ -133,26 +139,32 @@ def df_dt_fvm(f, self, at_n = True): # Variation of p1 is along axis 0: left_plus_eps_flux_p1, right_minus_eps_flux_p1 = \ - reconstruct(self, self._convert_to_p_expanded(af.broadcast(multiply, A_p1, f)), 0, method_in_p) + reconstruct(self, + self._convert_to_p_expanded(af.broadcast(multiply, A_p1, f)), + 0, method_in_p + ) # Variation of p2 is along axis 1: bot_plus_eps_flux_p2, top_minus_eps_flux_p2 = \ - reconstruct(self, self._convert_to_p_expanded(af.broadcast(multiply, A_p2, f)), 1, method_in_p) - # Variation of p3 is along axis 2: - back_plus_eps_flux_p3, front_minus_eps_flux_p3 = \ - reconstruct(self, self._convert_to_p_expanded(af.broadcast(multiply, A_p3, f)), 2, method_in_p) + reconstruct(self, + self._convert_to_p_expanded(af.broadcast(multiply, A_p2, f)), + 1, method_in_p + ) +# # Variation of p3 is along axis 2: +# back_plus_eps_flux_p3, front_minus_eps_flux_p3 = \ +# reconstruct(self, self._convert_to_p_expanded(af.broadcast(multiply, A_p3, f)), 2, method_in_p) left_minus_eps_flux_p1 = af.shift(right_minus_eps_flux_p1, 1) bot_minus_eps_flux_p2 = af.shift(top_minus_eps_flux_p2, 0, 1) - back_minus_eps_flux_p3 = af.shift(front_minus_eps_flux_p3, 0, 0, 1) +# back_minus_eps_flux_p3 = af.shift(front_minus_eps_flux_p3, 0, 0, 1) # Obtaining the fluxes by face-averaging: left_flux_p1 = 0.5 * (left_minus_eps_flux_p1 + left_plus_eps_flux_p1) bot_flux_p2 = 0.5 * (bot_minus_eps_flux_p2 + bot_plus_eps_flux_p2) - back_flux_p3 = 0.5 * (back_minus_eps_flux_p3 + back_plus_eps_flux_p3) + # back_flux_p3 = 0.5 * (back_minus_eps_flux_p3 + back_plus_eps_flux_p3) right_flux_p1 = af.shift(left_flux_p1, -1) top_flux_p2 = af.shift(bot_flux_p2, 0, -1) - front_flux_p3 = af.shift(back_flux_p3, 0, 0, -1) +# front_flux_p3 = af.shift(back_flux_p3, 0, 0, -1) left_flux_p1 = self._convert_to_q_expanded(left_flux_p1) right_flux_p1 = self._convert_to_q_expanded(right_flux_p1) @@ -160,12 +172,12 @@ def df_dt_fvm(f, self, at_n = True): bot_flux_p2 = self._convert_to_q_expanded(bot_flux_p2) top_flux_p2 = self._convert_to_q_expanded(top_flux_p2) - back_flux_p3 = self._convert_to_q_expanded(back_flux_p3) - front_flux_p3 = self._convert_to_q_expanded(front_flux_p3) +# back_flux_p3 = self._convert_to_q_expanded(back_flux_p3) +# front_flux_p3 = self._convert_to_q_expanded(front_flux_p3) df_dt += - (right_flux_p1 - left_flux_p1)/self.dp1 \ - (top_flux_p2 - bot_flux_p2 )/self.dp2 \ - - (front_flux_p3 - back_flux_p3)/self.dp3 + #- (front_flux_p3 - back_flux_p3)/self.dp3 af.eval(df_dt) diff --git a/bolt/lib/nonlinear_solver/FVM_solver/reconstruction_methods/weno5.py b/bolt/lib/nonlinear_solver/FVM_solver/reconstruction_methods/weno5.py index 11814c23..28bf2b2a 100644 --- a/bolt/lib/nonlinear_solver/FVM_solver/reconstruction_methods/weno5.py +++ b/bolt/lib/nonlinear_solver/FVM_solver/reconstruction_methods/weno5.py @@ -75,5 +75,6 @@ def reconstruct_weno5(input_array, axis): # Reconstruction: left_value = (w1l * u1l + w2l * u2l + w3l * u3l) / denl; right_value = (w1r * u1r + w2r * u2r + w3r * u3r) / denr; - + + af.eval(left_value, right_value) return(left_value, right_value) diff --git a/bolt/lib/nonlinear_solver/apply_boundary_conditions.py b/bolt/lib/nonlinear_solver/apply_boundary_conditions.py index f2054d8f..f3b77a2a 100644 --- a/bolt/lib/nonlinear_solver/apply_boundary_conditions.py +++ b/bolt/lib/nonlinear_solver/apply_boundary_conditions.py @@ -266,146 +266,146 @@ def apply_bcs_f(self): def apply_dirichlet_bcs_fields(self, boundary): - N_g = self.N_ghost - - # These arguments are defined since they are required by all the function calls: - # So the functions can be called instead using function(*args) - args = (self.q1_center, self.q2_center, self.physical_system.params) - - if(boundary == 'left'): - E1 = self.boundary_conditions.\ - E1_left(self.cell_centered_EM_fields[0],*args)[:, :N_g] - - E2 = self.boundary_conditions.\ - E2_left(self.cell_centered_EM_fields[1],*args)[:, :N_g] - - E3 = self.boundary_conditions.\ - E3_left(self.cell_centered_EM_fields[2],*args)[:, :N_g] - - B1 = self.boundary_conditions.\ - B1_left(self.cell_centered_EM_fields[3],*args)[:, :N_g] - - B2 = self.boundary_conditions.\ - B2_left(self.cell_centered_EM_fields[4],*args)[:, :N_g] - - B3 = self.boundary_conditions.\ - B3_left(self.cell_centered_EM_fields[5],*args)[:, :N_g] - - self.cell_centered_EM_fields[:, :N_g] = \ - af.join(0, E1, E2, E3, af.join(0, B1, B2, B3)) - - elif(boundary == 'right'): - E1 = self.boundary_conditions.\ - E1_right(self.cell_centered_EM_fields[0],*args)[:, -N_g:] - - E2 = self.boundary_conditions.\ - E2_right(self.cell_centered_EM_fields[1],*args)[:, -N_g:] - - E3 = self.boundary_conditions.\ - E3_right(self.cell_centered_EM_fields[2],*args)[:, -N_g:] - - B1 = self.boundary_conditions.\ - B1_right(self.cell_centered_EM_fields[3],*args)[:, -N_g:] - - B2 = self.boundary_conditions.\ - B2_right(self.cell_centered_EM_fields[4],*args)[:, -N_g:] - - B3 = self.boundary_conditions.\ - B3_right(self.cell_centered_EM_fields[5],*args)[:, -N_g:] - - self.cell_centered_EM_fields[:, -N_g:] = \ - af.join(0, E1, E2, E3, af.join(0, B1, B2, B3)) - - elif(boundary == 'bottom'): - E1 = self.boundary_conditions.\ - E1_bottom(self.cell_centered_EM_fields[0],*args)[:, :, :N_g] - - E2 = self.boundary_conditions.\ - E2_bottom(self.cell_centered_EM_fields[1],*args)[:, :, :N_g] - - E3 = self.boundary_conditions.\ - E3_bottom(self.cell_centered_EM_fields[2],*args)[:, :, :N_g] - - B1 = self.boundary_conditions.\ - B1_bottom(self.cell_centered_EM_fields[3],*args)[:, :, :N_g] - - B2 = self.boundary_conditions.\ - B2_bottom(self.cell_centered_EM_fields[4],*args)[:, :, :N_g] - - B3 = self.boundary_conditions.\ - B3_bottom(self.cell_centered_EM_fields[5],*args)[:, :, :N_g] - - self.cell_centered_EM_fields[:, :, :N_g] = \ - af.join(0, E1, E2, E3, af.join(0, B1, B2, B3)) - - elif(boundary == 'top'): - E1 = self.boundary_conditions.\ - E1_top(self.cell_centered_EM_fields[0],*args)[:, :, -N_g:] - - E2 = self.boundary_conditions.\ - E2_top(self.cell_centered_EM_fields[1],*args)[:, :, -N_g:] - - E3 = self.boundary_conditions.\ - E3_top(self.cell_centered_EM_fields[2],*args)[:, :, -N_g:] - - B1 = self.boundary_conditions.\ - B1_top(self.cell_centered_EM_fields[3],*args)[:, :, -N_g:] - - B2 = self.boundary_conditions.\ - B2_top(self.cell_centered_EM_fields[4],*args)[:, :, -N_g:] - - B3 = self.boundary_conditions.\ - B3_top(self.cell_centered_EM_fields[5],*args)[:, :, -N_g:] - - self.cell_centered_EM_fields[:, :, -N_g:] = \ - af.join(0, E1, E2, E3, af.join(0, B1, B2, B3)) - - else: - raise Exception('Invalid choice for boundary') +# N_g = self.N_ghost +# +# # These arguments are defined since they are required by all the function calls: +# # So the functions can be called instead using function(*args) +# args = (self.q1_center, self.q2_center, self.physical_system.params) +# +# if(boundary == 'left'): +# E1 = self.boundary_conditions.\ +# E1_left(self.cell_centered_EM_fields[0],*args)[:, :N_g] +# +# E2 = self.boundary_conditions.\ +# E2_left(self.cell_centered_EM_fields[1],*args)[:, :N_g] +# +# E3 = self.boundary_conditions.\ +# E3_left(self.cell_centered_EM_fields[2],*args)[:, :N_g] +# +# B1 = self.boundary_conditions.\ +# B1_left(self.cell_centered_EM_fields[3],*args)[:, :N_g] +# +# B2 = self.boundary_conditions.\ +# B2_left(self.cell_centered_EM_fields[4],*args)[:, :N_g] +# +# B3 = self.boundary_conditions.\ +# B3_left(self.cell_centered_EM_fields[5],*args)[:, :N_g] +# +# self.cell_centered_EM_fields[:, :N_g] = \ +# af.join(0, E1, E2, E3, af.join(0, B1, B2, B3)) +# +# elif(boundary == 'right'): +# E1 = self.boundary_conditions.\ +# E1_right(self.cell_centered_EM_fields[0],*args)[:, -N_g:] +# +# E2 = self.boundary_conditions.\ +# E2_right(self.cell_centered_EM_fields[1],*args)[:, -N_g:] +# +# E3 = self.boundary_conditions.\ +# E3_right(self.cell_centered_EM_fields[2],*args)[:, -N_g:] +# +# B1 = self.boundary_conditions.\ +# B1_right(self.cell_centered_EM_fields[3],*args)[:, -N_g:] +# +# B2 = self.boundary_conditions.\ +# B2_right(self.cell_centered_EM_fields[4],*args)[:, -N_g:] +# +# B3 = self.boundary_conditions.\ +# B3_right(self.cell_centered_EM_fields[5],*args)[:, -N_g:] +# +# self.cell_centered_EM_fields[:, -N_g:] = \ +# af.join(0, E1, E2, E3, af.join(0, B1, B2, B3)) +# +# elif(boundary == 'bottom'): +# E1 = self.boundary_conditions.\ +# E1_bottom(self.cell_centered_EM_fields[0],*args)[:, :, :N_g] +# +# E2 = self.boundary_conditions.\ +# E2_bottom(self.cell_centered_EM_fields[1],*args)[:, :, :N_g] +# +# E3 = self.boundary_conditions.\ +# E3_bottom(self.cell_centered_EM_fields[2],*args)[:, :, :N_g] +# +# B1 = self.boundary_conditions.\ +# B1_bottom(self.cell_centered_EM_fields[3],*args)[:, :, :N_g] +# +# B2 = self.boundary_conditions.\ +# B2_bottom(self.cell_centered_EM_fields[4],*args)[:, :, :N_g] +# +# B3 = self.boundary_conditions.\ +# B3_bottom(self.cell_centered_EM_fields[5],*args)[:, :, :N_g] +# +# self.cell_centered_EM_fields[:, :, :N_g] = \ +# af.join(0, E1, E2, E3, af.join(0, B1, B2, B3)) +# +# elif(boundary == 'top'): +# E1 = self.boundary_conditions.\ +# E1_top(self.cell_centered_EM_fields[0],*args)[:, :, -N_g:] +# +# E2 = self.boundary_conditions.\ +# E2_top(self.cell_centered_EM_fields[1],*args)[:, :, -N_g:] +# +# E3 = self.boundary_conditions.\ +# E3_top(self.cell_centered_EM_fields[2],*args)[:, :, -N_g:] +# +# B1 = self.boundary_conditions.\ +# B1_top(self.cell_centered_EM_fields[3],*args)[:, :, -N_g:] +# +# B2 = self.boundary_conditions.\ +# B2_top(self.cell_centered_EM_fields[4],*args)[:, :, -N_g:] +# +# B3 = self.boundary_conditions.\ +# B3_top(self.cell_centered_EM_fields[5],*args)[:, :, -N_g:] +# +# self.cell_centered_EM_fields[:, :, -N_g:] = \ +# af.join(0, E1, E2, E3, af.join(0, B1, B2, B3)) +# +# else: +# raise Exception('Invalid choice for boundary') return def apply_mirror_bcs_fields(self, boundary): - 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.cell_centered_EM_fields[:, :N_g] = \ - af.flip(self.cell_centered_EM_fields[:, N_g:2 * N_g], 1) - - 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.cell_centered_EM_fields[:, -N_g:] = \ - af.flip(self.cell_centered_EM_fields[:, -2 * N_g:-N_g], 1) - - 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.cell_centered_EM_fields[:, :, :N_g] = \ - af.flip(self.cell_centered_EM_fields[:, :, N_g:2 * N_g], 2) - - 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.cell_centered_EM_fields[:, :, -N_g:] = \ - af.flip(self.cell_centered_EM_fields[:, :, -2 * N_g:-N_g], 2) - - else: - raise Exception('Invalid choice for boundary') +# 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.cell_centered_EM_fields[:, :N_g] = \ +# af.flip(self.cell_centered_EM_fields[:, N_g:2 * N_g], 1) +# +# 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.cell_centered_EM_fields[:, -N_g:] = \ +# af.flip(self.cell_centered_EM_fields[:, -2 * N_g:-N_g], 1) +# +# 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.cell_centered_EM_fields[:, :, :N_g] = \ +# af.flip(self.cell_centered_EM_fields[:, :, N_g:2 * N_g], 2) +# +# 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.cell_centered_EM_fields[:, :, -N_g:] = \ +# af.flip(self.cell_centered_EM_fields[:, :, -2 * N_g:-N_g], 2) +# +# else: +# raise Exception('Invalid choice for boundary') return diff --git a/bolt/lib/nonlinear_solver/nonlinear_solver.py b/bolt/lib/nonlinear_solver/nonlinear_solver.py index a2be238e..b66f9f20 100644 --- a/bolt/lib/nonlinear_solver/nonlinear_solver.py +++ b/bolt/lib/nonlinear_solver/nonlinear_solver.py @@ -53,7 +53,7 @@ from .utils.print_with_indent import indent from .utils.performance_timings import print_table from .compute_moments import compute_moments as compute_moments_imported -from .EM_fields_solver.electrostatic import fft_poisson +from .EM_fields_solver.electrostatic import fft_poisson, poisson_eqn_3D class nonlinear_solver(object): """ @@ -615,10 +615,10 @@ def _initialize(self, params): _apply_bcs_f = apply_boundary_conditions.apply_bcs_f _apply_bcs_fields = apply_boundary_conditions.apply_bcs_fields - strang_timestep = timestep.strang_step - lie_timestep = timestep.lie_step - swss_timestep = timestep.swss_step - jia_timestep = timestep.jia_step + strang_timestep = timestep.strang_step + lie_timestep = timestep.lie_step + swss_timestep = timestep.swss_step + jia_timestep = timestep.jia_step compute_moments = compute_moments_imported diff --git a/bolt/lib/nonlinear_solver/timestep.py b/bolt/lib/nonlinear_solver/timestep.py index f624eac7..3f1c16ae 100644 --- a/bolt/lib/nonlinear_solver/timestep.py +++ b/bolt/lib/nonlinear_solver/timestep.py @@ -26,32 +26,33 @@ def op_fvm_q(self, dt): tic = af.time() fvm_timestep_RK2(self, dt) + #self._apply_bcs_f() if(self.performance_test_flag == True): af.sync() toc = af.time() self.time_fvm_solver += toc - tic - # Solving for tau = 0 systems - if(af.any_true(self.physical_system.params.tau(self.q1_center, self.q2_center, - self.p1, self.p2, self.p3 - ) == 0 - ) - ): - if(self.performance_test_flag == True): - tic = af.time() - - self.f = self._source(self.f, self.q1_center, self.q2_center, - self.p1, self.p2, self.p3, - self.compute_moments, - self.physical_system.params, - True - ) - - if(self.performance_test_flag == True): - af.sync() - toc = af.time() - self.time_sourcets += toc - tic +# # Solving for tau = 0 systems +# if(af.any_true(self.physical_system.params.tau(self.q1_center, self.q2_center, +# self.p1, self.p2, self.p3 +# ) == 0 +# ) +# ): +# if(self.performance_test_flag == True): +# tic = af.time() +# +# self.f = self._source(self.f, self.q1_center, self.q2_center, +# self.p1, self.p2, self.p3, +# self.compute_moments, +# self.physical_system.params, +# True +# ) +# +# if(self.performance_test_flag == True): +# af.sync() +# toc = af.time() +# self.time_sourcets += toc - tic af.eval(self.f) return @@ -71,26 +72,33 @@ def op_solve_src(self, dt): if(self.performance_test_flag == True): tic = af.time() - # Solving for tau = 0 systems - if(af.any_true(self.physical_system.params.tau(self.q1_center, self.q2_center, - self.p1, self.p2, self.p3 - ) == 0 - ) - ): - self.f = self._source(self.f, self.q1_center, self.q2_center, - self.p1, self.p2, self.p3, - self.compute_moments, - self.physical_system.params, - True - ) - - else: - self.f = integrators.RK2(self._source, self.f, dt, - self.q1_center, self.q2_center, - self.p1, self.p2, self.p3, - self.compute_moments, - self.physical_system.params - ) +# # Solving for tau = 0 systems +# if(af.any_true(self.physical_system.params.tau(self.q1_center, self.q2_center, +# self.p1, self.p2, self.p3 +# ) == 0 +# ) +# ): +# self.f = self._source(self.f, self.q1_center, self.q2_center, +# self.p1, self.p2, self.p3, +# self.compute_moments, +# self.physical_system.params, +# True +# ) +# +# else: +# self.f = integrators.RK2(self._source, self.f, dt, +# self.q1_center, self.q2_center, +# self.p1, self.p2, self.p3, +# self.compute_moments, +# self.physical_system.params +# ) +# + self.f = integrators.RK2(self._source, self.f, dt, + self.q1_center, self.q2_center, + self.p1, self.p2, self.p3, + self.compute_moments, + self.physical_system.params + ) if(self.performance_test_flag == True): af.sync() diff --git a/bolt/lib/physical_system.py b/bolt/lib/physical_system.py index 2a63335e..20334e82 100644 --- a/bolt/lib/physical_system.py +++ b/bolt/lib/physical_system.py @@ -112,7 +112,7 @@ def __init__(self, if(not isinstance(moment_defs.moment_exponents, dict) or not isinstance(moment_defs.moment_coeffs, dict) ): - raise TypeError('Expected attributes of boundary_conditions \ + raise TypeError('Expected attributes of moment definitions \ to be of type dict' ) diff --git a/bolt/src/electronic_boltzmann/advection_terms.py b/bolt/src/electronic_boltzmann/advection_terms.py index 76c56dad..ea2a907c 100644 --- a/bolt/src/electronic_boltzmann/advection_terms.py +++ b/bolt/src/electronic_boltzmann/advection_terms.py @@ -1,7 +1,7 @@ -import numpy as np -import arrayfire as af +#import numpy as np +#import arrayfire as af -@af.broadcast +#@af.broadcast def A_q(q1, q2, p1, p2, p3, params): """Return the terms A_q1, A_q2.""" @@ -9,6 +9,13 @@ def A_q(q1, q2, p1, p2, p3, params): return (A_q1, A_q2) +def C_q(q1, q2, p1, p2, p3, params): + """Return the terms A_q1, A_q2.""" + + 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) @@ -29,8 +36,11 @@ def A_p(q1, q2, p1, p2, p3, dp3_dt = 0. #dp1_dt = 1e-5*e*0.5*(-af.tanh(100.*(q1 - 0.9)) - af.tanh(100.*(q1 - 0.1)) ) - amplitude = 1e-3 + amplitude = 1e-2 E1_analytic = amplitude * -(q1 - 5.) dp1_dt = E1_analytic + + #E2_analytic = amplitude * -(q2 - 5.) + #dp2_dt = E2_analytic 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 index 9dd189fb..35832658 100644 --- a/bolt/src/electronic_boltzmann/collision_operator.py +++ b/bolt/src/electronic_boltzmann/collision_operator.py @@ -20,17 +20,17 @@ def f0_defect_constant_T(f, p1, p2, p3, params): denominator = (k*T**2.*(af.exp(tmp) + 2. + af.exp(-tmp)) ) # TODO: Multiply with the integral measure dp1 * dp2 - a00 = af.sum(T / denominator, 2) + a00 = af.sum(T / denominator, 0) fermi_dirac = 1./(af.exp( (E_upper - mu)/(k*T) ) + 1.) af.eval(fermi_dirac) - zeroth_moment = f - fermi_dirac + zeroth_moment = f - fermi_dirac + 1./(af.exp( (E_upper )/(k*T) ) + 1.) - eqn_mass_conservation = af.sum(zeroth_moment, 2) + eqn_mass_conservation = af.sum(zeroth_moment, 0) N_g = domain.N_ghost - error_mass_conservation = af.max(af.abs(eqn_mass_conservation)[N_g:-N_g, N_g:-N_g]) + error_mass_conservation = af.max(af.abs(eqn_mass_conservation)[0, N_g:-N_g, N_g:-N_g]) residual = [eqn_mass_conservation] error_norm = np.max([af.max(af.abs(residual[0]))]) @@ -52,25 +52,25 @@ def f0_defect_constant_T(f, p1, p2, p3, params): fermi_dirac = 1./(af.exp( (E_upper - mu)/(k*T) ) + 1.) af.eval(fermi_dirac) - zeroth_moment = (f) - fermi_dirac + zeroth_moment = f - fermi_dirac + 1./(af.exp( (E_upper )/(k*T) ) + 1.) - eqn_mass_conservation = af.sum(zeroth_moment, 2) + eqn_mass_conservation = af.sum(zeroth_moment, 0) N_g = domain.N_ghost - error_mass_conservation = af.max(af.abs(eqn_mass_conservation)[N_g:-N_g, N_g:-N_g]) + error_mass_conservation = af.max(af.abs(eqn_mass_conservation)[0, N_g:-N_g, N_g:-N_g]) residual = [eqn_mass_conservation] error_norm = np.max([af.max(af.abs(residual[0]))]) print(" ||residual_defect|| = ", error_norm) - density_f = af.sum((f), 2) + density_f = af.sum(f, 0) fermi_dirac = 1./(af.exp( (E_upper - mu)/(k*T) ) + 1.) - density_fermi_dirac = af.sum(fermi_dirac, 2) + density_fermi_dirac = af.sum(fermi_dirac - 1./(af.exp( (E_upper )/(k*T) ) + 1.), 0) - print(" mu = ", af.mean(params.mu[N_g:-N_g, N_g:-N_g]), - "T = ", af.mean(params.T[N_g:-N_g, N_g:-N_g]), - "density_f = ", af.mean(density_f[N_g:-N_g, N_g:-N_g]), - "density_fermi_dirac = ",af.mean(density_fermi_dirac[N_g:-N_g, N_g:-N_g]) + print(" mu = ", af.mean(params.mu[0, N_g:-N_g, N_g:-N_g]), + "T = ", af.mean(params.T[0, N_g:-N_g, N_g:-N_g]), + "density_f = ", af.mean(density_f[0, N_g:-N_g, N_g:-N_g]), + "density_fermi_dirac = ",af.mean(density_fermi_dirac[0, N_g:-N_g, N_g:-N_g]) ) print(" ------------------") @@ -331,7 +331,7 @@ def f0_ee(f, p1, p2, p3, params): return(fermi_dirac) -def RTA(f, q1, q2, p1, p2, p3, moments, params): +def RTA(f, q1, q2, p1, p2, p3, moments, params, flag = False): """Return BGK operator -(f-f0)/tau.""" C_f = -( f - f0_defect_constant_T(f, p1, p2, p3, params) diff --git a/example_problems/electronic_boltzmann/graphene/boundary_conditions.py b/example_problems/electronic_boltzmann/graphene/boundary_conditions.py index b8b5793b..01cba6d1 100644 --- a/example_problems/electronic_boltzmann/graphene/boundary_conditions.py +++ b/example_problems/electronic_boltzmann/graphene/boundary_conditions.py @@ -1,33 +1,66 @@ +import numpy as np import arrayfire as af import domain -in_q1 = 'mirror' -in_q2 = 'mirror' +in_q1_left = 'mirror+dirichlet' +in_q1_right = 'mirror+dirichlet' +in_q2_bottom = 'mirror' +in_q2_top = 'mirror' @af.broadcast -def f_left(q1, q2, p1, p2, p3, params): +def f_left(f, q1, q2, p1, p2, p3, params): k = params.boltzmann_constant E_upper = params.E_band T = 0.*params.T + 3e-4*4. - f = (1./(af.exp( (E_upper - 0.01)/(k*T) - ) + 1. - )) + f_left = (1./(af.exp( (E_upper - 0.*0.01)/(k*T) ) + 1.) + ) - af.eval(f) - return(f) + # Inflow between y = [y_center(j_inflow_start), y_center(j_inflow_end)] + N_q2 = domain.N_q2 + N_g = domain.N_ghost + size_of_inflow = 5. + offset_from_center = 0. + length_y = domain.q2_end - domain.q2_start + N_inflow_zones = (int)(size_of_inflow/length_y*N_q2) + N_offset = (int)(abs(offset_from_center)/length_y*N_q2) + j_inflow_start = N_g + N_q2/2 - N_inflow_zones/2 \ + + np.sign(offset_from_center)*N_offset + j_inflow_end = N_g + N_q2/2 + N_inflow_zones/2 \ + + np.sign(offset_from_center)*N_offset + + f_left[:, :, :j_inflow_start] = f[:, :, :j_inflow_start] + f_left[:, :, j_inflow_end:] = f[:, :, j_inflow_end:] + + af.eval(f_left) + return(f_left) @af.broadcast -def f_right(q1, q2, p1, p2, p3, params): +def f_right(f, q1, q2, p1, p2, p3, params): k = params.boltzmann_constant E_upper = params.E_band T = 0.*params.T + 3e-4*4. - f = (1./(af.exp( (E_upper - 0.01)/(k*T) - ) + 1. - )) + f_right = (1./(af.exp( (E_upper - 0.*0.01)/(k*T) ) + 1.) + ) + + # Outflow between y = [y_center(j_outflow_start), y_center(j_outflow_end)] + N_q2 = domain.N_q2 + N_g = domain.N_ghost + size_of_outflow = 5. + offset_from_center = 0. + length_y = domain.q2_end - domain.q2_start + N_outflow_zones = (int)(size_of_outflow/length_y*N_q2) + N_offset = (int)(abs(offset_from_center)/length_y*N_q2) + j_outflow_start = N_g + N_q2/2 - N_outflow_zones/2 \ + + np.sign(offset_from_center)*N_offset + j_outflow_end = N_g + N_q2/2 + N_outflow_zones/2 \ + + np.sign(offset_from_center)*N_offset + + f_right[:, :, :j_outflow_start] = f[:, :, :j_outflow_start] + f_right[:, :, j_outflow_end:] = f[:, :, j_outflow_end:] - af.eval(f) - return(f) + af.eval(f_right) + return(f_right) diff --git a/example_problems/electronic_boltzmann/graphene/domain.py b/example_problems/electronic_boltzmann/graphene/domain.py index 62a42b5f..06f8457d 100644 --- a/example_problems/electronic_boltzmann/graphene/domain.py +++ b/example_problems/electronic_boltzmann/graphene/domain.py @@ -6,13 +6,13 @@ q2_end = 10. N_q2 = 28 -p1_start = -0.02 -p1_end = 0.02 -N_p1 = 64 +p1_start = -0.05 +p1_end = 0.05 +N_p1 = 375 p2_start = -0.02 p2_end = 0.02 -N_p2 = 64 +N_p2 = 150 p3_start = -0.5 p3_end = 0.5 diff --git a/example_problems/electronic_boltzmann/graphene/initialize.py b/example_problems/electronic_boltzmann/graphene/initialize.py index 781ea8a9..ea4e3f82 100644 --- a/example_problems/electronic_boltzmann/graphene/initialize.py +++ b/example_problems/electronic_boltzmann/graphene/initialize.py @@ -5,13 +5,15 @@ import arrayfire as af import numpy as np +from petsc4py import PETSc def initialize_f(q1, q2, p1, p2, p3, params): - print("Initializing f") + PETSc.Sys.Print("Initializing f") + k = params.boltzmann_constant - params.mu = 0.*q1 + 0.01 + params.mu = 0.*q1 + 0.*0.01 params.T = 0.*q1 + 3e-4*4. params.vel_drift_x = 0.*q1 params.vel_drift_y = 0.*q1 @@ -28,8 +30,8 @@ def initialize_f(q1, q2, p1, p2, p3, params): E_upper = params.E_band + params.charge_electron*params.phi f = (1./(af.exp( (E_upper - params.vel_drift_x*p1 - - params.vel_drift_y*p2 - - params.mu + - params.vel_drift_y*p2 + - params.mu )/(k*params.T) ) + 1. )) @@ -37,6 +39,7 @@ def initialize_f(q1, q2, p1, p2, p3, params): af.eval(f) return(f) + def initialize_E(q1, q2, params): E1 = 0.*q1 diff --git a/example_problems/electronic_boltzmann/graphene/main.py b/example_problems/electronic_boltzmann/graphene/main.py index 7adb5005..38a5cdd4 100644 --- a/example_problems/electronic_boltzmann/graphene/main.py +++ b/example_problems/electronic_boltzmann/graphene/main.py @@ -68,7 +68,7 @@ n_nls = nls.compute_moments('density') # Time parameters: -dt = 0.1 +dt = 0.002 t_final = 1000. time_array = np.arange(dt, t_final + dt, dt) @@ -81,29 +81,24 @@ # params.mu[i, :] = 0.*params.mu[N_g, :] # params.mu[N_q1_local+N_g+i, :] = 0.*params.mu[N_q1_local+N_g-1, :] -print("mu = ", af.mean(params.mu[N_g:-N_g, N_g:-N_g]), - "phi = ", af.mean(params.phi[N_g:-N_g, N_g:-N_g]), - "density = ", af.mean(n_nls[N_g:-N_g, N_g:-N_g]) +print("mu = ", af.mean(params.mu[0, N_g:-N_g, N_g:-N_g]), + "phi = ", af.mean(params.phi[0, N_g:-N_g, N_g:-N_g]), + "density = ", af.mean(n_nls[0, N_g:-N_g, N_g:-N_g]) ) for time_index, t0 in enumerate(time_array): print("Time step =", time_index, ", Time =", t0) N_g = domain.N_ghost - mean_density = af.mean(n_nls[N_g:-N_g, N_g:-N_g]) + mean_density = af.mean(n_nls[0, N_g:-N_g, N_g:-N_g]) density_pert = n_nls - mean_density if (time_index%1==0): - pl.contourf(np.array(nls.q1_center)[N_g:-N_g, N_g:-N_g], \ - np.array(nls.q2_center)[N_g:-N_g, N_g:-N_g], \ - np.array(density_pert)[N_g:-N_g, N_g:-N_g], \ + pl.contourf(np.array(nls.q1_center)[0, N_g:-N_g, N_g:-N_g], \ + np.array(nls.q2_center)[0, N_g:-N_g, N_g:-N_g], \ + np.array(n_nls)[0, N_g:-N_g, N_g:-N_g], \ 100, cmap='bwr' ) -# pl.contourf(np.array(nls.q1_center)[N_g:-N_g, N_g:-N_g], \ -# np.array(nls.q2_center)[N_g:-N_g, N_g:-N_g], \ -# np.log10(np.array(n_nls))[N_g:-N_g, N_g:-N_g], \ -# 100, cmap='hot' -# ) pl.title('Time = ' + "%.2f"%(t0) ) pl.xlabel('$x$') pl.ylabel('$y$') @@ -111,23 +106,10 @@ pl.gca().set_aspect('equal') pl.savefig('/tmp/density_' + '%06d'%time_index + '.png' ) pl.clf() - - pl.contourf(np.array(nls.q1_center), \ - np.array(nls.q2_center), \ - np.array(nls.E1), \ - 100, cmap='bwr' - ) - pl.title('Time = ' + "%.2f"%(t0) ) - pl.xlabel('$x$') - pl.ylabel('$y$') - pl.colorbar() - pl.gca().set_aspect('equal') - pl.savefig('/tmp/E1_' + '%06d'%time_index + '.png' ) - pl.clf() - pl.contourf(np.array(nls.q1_center), \ - np.array(nls.q2_center), \ - np.array(nls.E2), \ + pl.contourf(np.array(nls.q1_center)[0, N_g:-N_g, N_g:-N_g], \ + np.array(nls.q2_center)[0, N_g:-N_g, N_g:-N_g], \ + np.array(params.mu)[0, N_g:-N_g, N_g:-N_g], \ 100, cmap='bwr' ) pl.title('Time = ' + "%.2f"%(t0) ) @@ -135,10 +117,36 @@ pl.ylabel('$y$') pl.colorbar() pl.gca().set_aspect('equal') - pl.savefig('/tmp/E2_' + '%06d'%time_index + '.png' ) + pl.savefig('/tmp/mu_' + '%06d'%time_index + '.png' ) pl.clf() - - f_at_desired_q = af.moddims(nls.f[N_g, N_g + nls.N_q2/2], + +# pl.contourf(np.array(nls.q1_center), \ +# np.array(nls.q2_center), \ +# np.array(nls.E1), \ +# 100, cmap='bwr' +# ) +# pl.title('Time = ' + "%.2f"%(t0) ) +# pl.xlabel('$x$') +# pl.ylabel('$y$') +# pl.colorbar() +# pl.gca().set_aspect('equal') +# pl.savefig('/tmp/E1_' + '%06d'%time_index + '.png' ) +# pl.clf() +# +# pl.contourf(np.array(nls.q1_center), \ +# np.array(nls.q2_center), \ +# np.array(nls.E2), \ +# 100, cmap='bwr' +# ) +# pl.title('Time = ' + "%.2f"%(t0) ) +# pl.xlabel('$x$') +# pl.ylabel('$y$') +# pl.colorbar() +# pl.gca().set_aspect('equal') +# pl.savefig('/tmp/E2_' + '%06d'%time_index + '.png' ) +# pl.clf() +# + f_at_desired_q = af.moddims(nls.f[:, N_g, N_g + nls.N_q2/2], nls.N_p1, nls.N_p2 ) p1 = af.moddims(nls.p1, nls.N_p1, nls.N_p2) @@ -167,72 +175,83 @@ # nls.strang_timestep(dt) + + # Floors + nls.f = af.select(nls.f < 1e-13, 1e-13, nls.f) + params.mu = af.select(params.mu < 1e-13, 1e-13, params.mu) + +# f_left = nls.boundary_conditions.\ +# f_left(nls.f, nls.q1_center, nls.q2_center, +# nls.p1, nls.p2, nls.p3, +# nls.physical_system.params +# ) +# nls.f[:, -N_g:, 10:24] = f_right[:, -N_g:, 10:24] n_nls = nls.compute_moments('density') - print("mu = ", af.mean(params.mu[N_g:-N_g, N_g:-N_g]), - "phi = ", af.mean(params.phi[N_g:-N_g, N_g:-N_g]), + print("mu = ", af.mean(params.mu[0, N_g:-N_g, N_g:-N_g]), + "phi = ", af.mean(params.phi[0, N_g:-N_g, N_g:-N_g]), "density = ", mean_density ) print("--------------------\n") -##pl.contourf(np.array(params.mu)[N_g:-N_g, N_g:-N_g].transpose(), 100, cmap='jet') -#pl.contourf(np.array(n_nls)[N_g:-N_g, N_g:-N_g].transpose(), 100, cmap='jet') -#pl.title('Density') -##pl.title('$\\mu$') +###pl.contourf(np.array(params.mu)[N_g:-N_g, N_g:-N_g].transpose(), 100, cmap='jet') +##pl.contourf(np.array(n_nls)[N_g:-N_g, N_g:-N_g].transpose(), 100, cmap='jet') +##pl.title('Density') +###pl.title('$\\mu$') +##pl.xlabel('$x$') +##pl.ylabel('$y$') +##pl.colorbar() +##pl.gca().set_aspect('equal') +##pl.show() +# +#phi_array = nls.poisson.glob_phi.getArray() +#phi_array = phi_array.reshape([nls.poisson.N_q3_3D_local, \ +# nls.poisson.N_q2_3D_local, \ +# nls.poisson.N_q1_3D_local] +# ) +#pl.rcParams['figure.figsize'] = 20, 7.5 +#pl.subplot(121) +#N_g = domain.N_ghost +#pl.contourf( +# phi_array[nls.poisson.q3_2D_in_3D_index_start, :, :], 100, cmap='jet' +# ) +##pl.contourf(np.array(nls.E1)[N_g:-N_g, N_g:-N_g].transpose(), 100, cmap='jet' +## ) +#pl.colorbar() +#pl.title('Top View') #pl.xlabel('$x$') #pl.ylabel('$y$') +#pl.gca().set_aspect('equal') +# +#pl.subplot(122) +#pl.contourf(phi_array[:, nls.N_q2_poisson/2, :], 100, cmap='jet') +##pl.contourf(np.array(nls.E2)[N_g:-N_g, N_g:-N_g].transpose(), 100, cmap='jet') +#pl.title('Side View') +#pl.xlabel('$x$') +#pl.ylabel('$z$') #pl.colorbar() #pl.gca().set_aspect('equal') #pl.show() - -phi_array = nls.poisson.glob_phi.getArray() -phi_array = phi_array.reshape([nls.poisson.N_q3_3D_local, \ - nls.poisson.N_q2_3D_local, \ - nls.poisson.N_q1_3D_local] - ) -pl.rcParams['figure.figsize'] = 20, 7.5 -pl.subplot(121) -N_g = domain.N_ghost -pl.contourf( - phi_array[nls.poisson.q3_2D_in_3D_index_start, :, :], 100, cmap='jet' - ) -#pl.contourf(np.array(nls.E1)[N_g:-N_g, N_g:-N_g].transpose(), 100, cmap='jet' -# ) -pl.colorbar() -pl.title('Top View') -pl.xlabel('$x$') -pl.ylabel('$y$') -pl.gca().set_aspect('equal') - -pl.subplot(122) -pl.contourf(phi_array[:, nls.N_q2_poisson/2, :], 100, cmap='jet') -#pl.contourf(np.array(nls.E2)[N_g:-N_g, N_g:-N_g].transpose(), 100, cmap='jet') -pl.title('Side View') -pl.xlabel('$x$') -pl.ylabel('$z$') -pl.colorbar() -pl.gca().set_aspect('equal') -pl.show() - -#h5f = h5py.File('dump/0000.h5', 'w') -#h5f.create_dataset('q1', data = nls.q1_center) -#h5f.create_dataset('q2', data = nls.q2_center) -#h5f.create_dataset('n', data = n_nls) -#h5f.close() -# -#def time_evolution(): -# -# for time_index, t0 in enumerate(time_array): -# print('For Time =', t0 ) -# print('MIN(f) =', af.min(nls.f[3:-3, 3:-3])) -# print('MAX(f) =', af.max(nls.f[3:-3, 3:-3])) -# print('SUM(f) =', af.sum(nls.f[3:-3, 3:-3])) -# print() -# -# nls.strang_timestep(dt) -# n_nls = nls.compute_moments('density') -# -# h5f = h5py.File('dump/%04d'%(time_index+1) + '.h5', 'w') -# h5f.create_dataset('n', data = n_nls) -# h5f.close() # -#time_evolution() +##h5f = h5py.File('dump/0000.h5', 'w') +##h5f.create_dataset('q1', data = nls.q1_center) +##h5f.create_dataset('q2', data = nls.q2_center) +##h5f.create_dataset('n', data = n_nls) +##h5f.close() +## +##def time_evolution(): +## +## for time_index, t0 in enumerate(time_array): +## print('For Time =', t0 ) +## print('MIN(f) =', af.min(nls.f[3:-3, 3:-3])) +## print('MAX(f) =', af.max(nls.f[3:-3, 3:-3])) +## print('SUM(f) =', af.sum(nls.f[3:-3, 3:-3])) +## print() +## +## nls.strang_timestep(dt) +## n_nls = nls.compute_moments('density') +## +## h5f = h5py.File('dump/%04d'%(time_index+1) + '.h5', 'w') +## h5f.create_dataset('n', data = n_nls) +## h5f.close() +## +##time_evolution() diff --git a/example_problems/electronic_boltzmann/graphene/params.py b/example_problems/electronic_boltzmann/graphene/params.py index bf7cac22..b64ef164 100644 --- a/example_problems/electronic_boltzmann/graphene/params.py +++ b/example_problems/electronic_boltzmann/graphene/params.py @@ -8,11 +8,33 @@ fields_initialize = 'user-defined' # Can be defined as 'electrostatic' and 'fdtd' -fields_solver = 'electrostatic' +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 = 'upwind-flux' + +# Restart(Set to zero for no-restart): +t_restart = 0 + +# File-writing Parameters: +# Set to zero for no file-writing +dt_dump_f = 0.1 +dt_dump_moments = 0.01 + +# Time parameters: +N_cfl = 0.45 +t_final = 10 + # Dimensionality considered in velocity space: p_dim = 2 @@ -24,7 +46,7 @@ h_bar = 1.0545718e-4 # x aJ ps boltzmann_constant = 1 charge_electron = -0.160217662 # x aC -speed_of_light = 300 # x [um/ps] +speed_of_light = 300. # x [um/ps] fermi_velocity = speed_of_light/300 epsilon0 = 8.854187817 # x [aC^2 / (aJ um) ] @@ -44,23 +66,22 @@ collision_nonlinear_iters = 5 # Variation of collisional-timescale parameter through phase space: +@af.broadcast def tau_defect(q1, q2, p1, p2, p3): - return (af.constant(1., q1.shape[0], q2.shape[1], - p1.shape[2], dtype = af.Dtype.f64 - ) - ) + return(1. * q1**0 * p1**0) +@af.broadcast def tau_ee(q1, q2, p1, p2, p3): - return (af.constant(np.inf, q1.shape[0], q2.shape[1], - p1.shape[2], dtype = af.Dtype.f64 - ) - ) + return(np.inf * q1**0 * p1**0) def band_energy(p_x, p_y): p = af.sqrt(p_x**2. + p_y**2.) + + E_upper = p*fermi_velocity - return(p*fermi_velocity) + af.eval(E_upper) + return(E_upper) def band_velocity(p_x, p_y): @@ -71,5 +92,6 @@ def band_velocity(p_x, p_y): 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) From 414feafa968f9d2c43f7ab7770ddf7ef1d56b062 Mon Sep 17 00:00:00 2001 From: Mani Chandra Date: Thu, 21 Dec 2017 09:04:26 -0500 Subject: [PATCH 14/28] (1) Clean implementation of boundaries (2) Added rank output to print statements --- .../collision_operator.py | 16 +- .../graphene/boundary_conditions.py | 54 ++-- .../electronic_boltzmann/graphene/main.py | 274 +++++++++--------- 3 files changed, 170 insertions(+), 174 deletions(-) diff --git a/bolt/src/electronic_boltzmann/collision_operator.py b/bolt/src/electronic_boltzmann/collision_operator.py index 35832658..4d76e875 100644 --- a/bolt/src/electronic_boltzmann/collision_operator.py +++ b/bolt/src/electronic_boltzmann/collision_operator.py @@ -1,5 +1,6 @@ """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 @@ -34,7 +35,7 @@ def f0_defect_constant_T(f, p1, p2, p3, params): residual = [eqn_mass_conservation] error_norm = np.max([af.max(af.abs(residual[0]))]) - print(" ||residual_defect|| = ", error_norm) + print(" rank = ", params.rank, "||residual_defect|| = ", error_norm) res = eqn_mass_conservation dres_dmu = -a00 @@ -61,18 +62,19 @@ def f0_defect_constant_T(f, p1, p2, p3, params): residual = [eqn_mass_conservation] error_norm = np.max([af.max(af.abs(residual[0]))]) - print(" ||residual_defect|| = ", error_norm) + print(" rank = ", params.rank, "||residual_defect|| = ", error_norm) density_f = af.sum(f, 0) fermi_dirac = 1./(af.exp( (E_upper - mu)/(k*T) ) + 1.) density_fermi_dirac = af.sum(fermi_dirac - 1./(af.exp( (E_upper )/(k*T) ) + 1.), 0) - print(" mu = ", af.mean(params.mu[0, N_g:-N_g, N_g:-N_g]), - "T = ", af.mean(params.T[0, N_g:-N_g, N_g:-N_g]), - "density_f = ", af.mean(density_f[0, N_g:-N_g, N_g:-N_g]), - "density_fermi_dirac = ",af.mean(density_fermi_dirac[0, N_g:-N_g, N_g:-N_g]) + print(" rank = ", params.rank, + "mu = ", af.mean(params.mu[0, N_g:-N_g, N_g:-N_g]), + "T = ", af.mean(params.T[0, N_g:-N_g, N_g:-N_g]), + "density_f = ", af.mean(density_f[0, N_g:-N_g, N_g:-N_g]), + "density_fermi_dirac = ",af.mean(density_fermi_dirac[0, N_g:-N_g, N_g:-N_g]) ) - print(" ------------------") + PETSc.Sys.Print(" ------------------") return(fermi_dirac) diff --git a/example_problems/electronic_boltzmann/graphene/boundary_conditions.py b/example_problems/electronic_boltzmann/graphene/boundary_conditions.py index 01cba6d1..5386f1bc 100644 --- a/example_problems/electronic_boltzmann/graphene/boundary_conditions.py +++ b/example_problems/electronic_boltzmann/graphene/boundary_conditions.py @@ -13,25 +13,16 @@ def f_left(f, q1, q2, p1, p2, p3, params): k = params.boltzmann_constant E_upper = params.E_band T = 0.*params.T + 3e-4*4. - - f_left = (1./(af.exp( (E_upper - 0.*0.01)/(k*T) ) + 1.) - ) - - # Inflow between y = [y_center(j_inflow_start), y_center(j_inflow_end)] - N_q2 = domain.N_q2 - N_g = domain.N_ghost - size_of_inflow = 5. - offset_from_center = 0. - length_y = domain.q2_end - domain.q2_start - N_inflow_zones = (int)(size_of_inflow/length_y*N_q2) - N_offset = (int)(abs(offset_from_center)/length_y*N_q2) - j_inflow_start = N_g + N_q2/2 - N_inflow_zones/2 \ - + np.sign(offset_from_center)*N_offset - j_inflow_end = N_g + N_q2/2 + N_inflow_zones/2 \ - + np.sign(offset_from_center)*N_offset - f_left[:, :, :j_inflow_start] = f[:, :, :j_inflow_start] - f_left[:, :, j_inflow_end:] = f[:, :, j_inflow_end:] + fermi_dirac = (1./(af.exp( (E_upper - 0.*0.01)/(k*T) ) + 1.) + ) + + q2_contact_start = 2.5; q2_contact_end = 7.5 + cond = ((q2 >= q2_contact_start) & \ + (q2 <= q2_contact_end) \ + ) + + f_left = cond*fermi_dirac + (1 - cond)*f af.eval(f_left) return(f_left) @@ -43,24 +34,15 @@ def f_right(f, q1, q2, p1, p2, p3, params): E_upper = params.E_band T = 0.*params.T + 3e-4*4. - f_right = (1./(af.exp( (E_upper - 0.*0.01)/(k*T) ) + 1.) - ) - - # Outflow between y = [y_center(j_outflow_start), y_center(j_outflow_end)] - N_q2 = domain.N_q2 - N_g = domain.N_ghost - size_of_outflow = 5. - offset_from_center = 0. - length_y = domain.q2_end - domain.q2_start - N_outflow_zones = (int)(size_of_outflow/length_y*N_q2) - N_offset = (int)(abs(offset_from_center)/length_y*N_q2) - j_outflow_start = N_g + N_q2/2 - N_outflow_zones/2 \ - + np.sign(offset_from_center)*N_offset - j_outflow_end = N_g + N_q2/2 + N_outflow_zones/2 \ - + np.sign(offset_from_center)*N_offset - - f_right[:, :, :j_outflow_start] = f[:, :, :j_outflow_start] - f_right[:, :, j_outflow_end:] = f[:, :, j_outflow_end:] + fermi_dirac = (1./(af.exp( (E_upper - 0.*0.01)/(k*T) ) + 1.) + ) + + q2_contact_start = 2.5; q2_contact_end = 7.5 + cond = ((q2 >= q2_contact_start) & \ + (q2 <= q2_contact_end) \ + ) + + f_right = cond*fermi_dirac + (1 - cond)*f af.eval(f_right) return(f_right) diff --git a/example_problems/electronic_boltzmann/graphene/main.py b/example_problems/electronic_boltzmann/graphene/main.py index 38a5cdd4..bb7830e5 100644 --- a/example_problems/electronic_boltzmann/graphene/main.py +++ b/example_problems/electronic_boltzmann/graphene/main.py @@ -3,6 +3,7 @@ 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 @@ -23,34 +24,34 @@ import bolt.src.electronic_boltzmann.moment_defs as moment_defs -pl.rcParams['figure.figsize'] = 12, 7.5 -pl.rcParams['figure.dpi'] = 150 -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'] = 20 -pl.rcParams['font.sans-serif'] = 'serif' -pl.rcParams['text.usetex'] = False -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' +#pl.rcParams['figure.figsize'] = 12, 7.5 +#pl.rcParams['figure.dpi'] = 150 +#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'] = 20 +#pl.rcParams['font.sans-serif'] = 'serif' +#pl.rcParams['text.usetex'] = False +#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' # Defining the physical system to be solved: @@ -67,12 +68,14 @@ nls = nonlinear_solver(system) n_nls = nls.compute_moments('density') +params.rank = nls._comm.rank + # Time parameters: dt = 0.002 t_final = 1000. time_array = np.arange(dt, t_final + dt, dt) -#compute_electrostatic_fields(nls) +compute_electrostatic_fields(nls) #params.mu = params.charge_electron*params.phi N_g = domain.N_ghost @@ -81,117 +84,126 @@ # params.mu[i, :] = 0.*params.mu[N_g, :] # params.mu[N_q1_local+N_g+i, :] = 0.*params.mu[N_q1_local+N_g-1, :] -print("mu = ", af.mean(params.mu[0, N_g:-N_g, N_g:-N_g]), +print("rank = ", nls._comm.rank, " params.rank = ", params.rank, + "mu = ", af.mean(params.mu[0, N_g:-N_g, N_g:-N_g]), "phi = ", af.mean(params.phi[0, N_g:-N_g, N_g:-N_g]), "density = ", af.mean(n_nls[0, N_g:-N_g, N_g:-N_g]) ) -for time_index, t0 in enumerate(time_array): - print("Time step =", time_index, ", Time =", t0) - - N_g = domain.N_ghost - mean_density = af.mean(n_nls[0, N_g:-N_g, N_g:-N_g]) - density_pert = n_nls - mean_density - if (time_index%1==0): - pl.contourf(np.array(nls.q1_center)[0, N_g:-N_g, N_g:-N_g], \ - np.array(nls.q2_center)[0, N_g:-N_g, N_g:-N_g], \ - np.array(n_nls)[0, N_g:-N_g, N_g:-N_g], \ - 100, cmap='bwr' - ) - pl.title('Time = ' + "%.2f"%(t0) ) - pl.xlabel('$x$') - pl.ylabel('$y$') - pl.colorbar() - pl.gca().set_aspect('equal') - pl.savefig('/tmp/density_' + '%06d'%time_index + '.png' ) - pl.clf() - pl.contourf(np.array(nls.q1_center)[0, N_g:-N_g, N_g:-N_g], \ - np.array(nls.q2_center)[0, N_g:-N_g, N_g:-N_g], \ - np.array(params.mu)[0, N_g:-N_g, N_g:-N_g], \ - 100, cmap='bwr' - ) - pl.title('Time = ' + "%.2f"%(t0) ) - pl.xlabel('$x$') - pl.ylabel('$y$') - pl.colorbar() - pl.gca().set_aspect('equal') - pl.savefig('/tmp/mu_' + '%06d'%time_index + '.png' ) - pl.clf() - -# pl.contourf(np.array(nls.q1_center), \ -# np.array(nls.q2_center), \ -# np.array(nls.E1), \ -# 100, cmap='bwr' -# ) -# pl.title('Time = ' + "%.2f"%(t0) ) -# pl.xlabel('$x$') -# pl.ylabel('$y$') -# pl.colorbar() -# pl.gca().set_aspect('equal') -# pl.savefig('/tmp/E1_' + '%06d'%time_index + '.png' ) -# pl.clf() +#for time_step, t0 in enumerate(time_array): +# PETSc.Sys.Print("Time step =", time_step, ", Time =", t0) # -# pl.contourf(np.array(nls.q1_center), \ -# np.array(nls.q2_center), \ -# np.array(nls.E2), \ -# 100, cmap='bwr' -# ) -# pl.title('Time = ' + "%.2f"%(t0) ) -# pl.xlabel('$x$') -# pl.ylabel('$y$') -# pl.colorbar() -# pl.gca().set_aspect('equal') -# pl.savefig('/tmp/E2_' + '%06d'%time_index + '.png' ) -# pl.clf() +# N_g = domain.N_ghost +# mean_density = af.mean(n_nls[0, N_g:-N_g, N_g:-N_g]) +# density_pert = n_nls - mean_density +# +# dump_steps = 100 +# if (time_step%dump_steps==0): +# nls.dump_moments('dumps/density_' + '%06d'%(time_step/dump_steps) + '.h5') +# nls.dump_distribution_function('dumps/f_' + '%06d'%(time_step/dump_steps) + '.h5') # - f_at_desired_q = af.moddims(nls.f[:, N_g, N_g + nls.N_q2/2], - nls.N_p1, nls.N_p2 - ) - p1 = af.moddims(nls.p1, nls.N_p1, nls.N_p2) - p2 = af.moddims(nls.p2, nls.N_p1, nls.N_p2) - pl.contourf(np.array(p1), \ - np.array(p2), \ - np.array((f_at_desired_q)), \ - 100, cmap='bwr' - ) - pl.title('Time = ' + "%.2f"%(t0) ) - pl.xlabel('$x$') - pl.ylabel('$y$') - pl.colorbar() - pl.gca().set_aspect('equal') - pl.savefig('/tmp/f_' + '%06d'%time_index + '.png' ) - pl.clf() - -# pl.contourf(np.array(params.mu)[N_g:-N_g, N_g:-N_g].transpose(), 100, cmap='jet') -# pl.title('Time = ' + "%.2f"%(t0) ) -# pl.xlabel('$x$') -# pl.ylabel('$y$') -# pl.colorbar() -# pl.gca().set_aspect('equal') -# pl.savefig('/tmp/mu_' + '%06d'%time_index + '.png' ) -# pl.clf() +## if (time_index%1==0): +## pl.contourf(np.array(nls.q1_center)[0, N_g:-N_g, N_g:-N_g], \ +## np.array(nls.q2_center)[0, N_g:-N_g, N_g:-N_g], \ +## np.array(n_nls)[0, N_g:-N_g, N_g:-N_g], \ +## 100, cmap='bwr' +## ) +## pl.title('Time = ' + "%.2f"%(t0) ) +## pl.xlabel('$x$') +## pl.ylabel('$y$') +## pl.colorbar() +## pl.gca().set_aspect('equal') +## pl.savefig('/tmp/density_' + '%06d'%time_index + '.png' ) +## pl.clf() +## +## pl.contourf(np.array(nls.q1_center)[0, N_g:-N_g, N_g:-N_g], \ +## np.array(nls.q2_center)[0, N_g:-N_g, N_g:-N_g], \ +## np.array(params.mu)[0, N_g:-N_g, N_g:-N_g], \ +## 100, cmap='bwr' +## ) +## pl.title('Time = ' + "%.2f"%(t0) ) +## pl.xlabel('$x$') +## pl.ylabel('$y$') +## pl.colorbar() +## pl.gca().set_aspect('equal') +## pl.savefig('/tmp/mu_' + '%06d'%time_index + '.png' ) +## pl.clf() +## +### pl.contourf(np.array(nls.q1_center), \ +### np.array(nls.q2_center), \ +### np.array(nls.E1), \ +### 100, cmap='bwr' +### ) +### pl.title('Time = ' + "%.2f"%(t0) ) +### pl.xlabel('$x$') +### pl.ylabel('$y$') +### pl.colorbar() +### pl.gca().set_aspect('equal') +### pl.savefig('/tmp/E1_' + '%06d'%time_index + '.png' ) +### pl.clf() +### +### pl.contourf(np.array(nls.q1_center), \ +### np.array(nls.q2_center), \ +### np.array(nls.E2), \ +### 100, cmap='bwr' +### ) +### pl.title('Time = ' + "%.2f"%(t0) ) +### pl.xlabel('$x$') +### pl.ylabel('$y$') +### pl.colorbar() +### pl.gca().set_aspect('equal') +### pl.savefig('/tmp/E2_' + '%06d'%time_index + '.png' ) +### pl.clf() +### +## f_at_desired_q = af.moddims(nls.f[:, N_g, N_g + nls.N_q2/2], +## nls.N_p1, nls.N_p2 +## ) +## p1 = af.moddims(nls.p1, nls.N_p1, nls.N_p2) +## p2 = af.moddims(nls.p2, nls.N_p1, nls.N_p2) +## pl.contourf(np.array(p1), \ +## np.array(p2), \ +## np.array((f_at_desired_q)), \ +## 100, cmap='bwr' +## ) +## pl.title('Time = ' + "%.2f"%(t0) ) +## pl.xlabel('$x$') +## pl.ylabel('$y$') +## pl.colorbar() +## pl.gca().set_aspect('equal') +## pl.savefig('/tmp/f_' + '%06d'%time_index + '.png' ) +## pl.clf() +## +## pl.contourf(np.array(params.mu)[N_g:-N_g, N_g:-N_g].transpose(), 100, cmap='jet') +## pl.title('Time = ' + "%.2f"%(t0) ) +## pl.xlabel('$x$') +## pl.ylabel('$y$') +## pl.colorbar() +## pl.gca().set_aspect('equal') +## pl.savefig('/tmp/mu_' + '%06d'%time_index + '.png' ) +## pl.clf() +## # - - nls.strang_timestep(dt) - - # Floors - nls.f = af.select(nls.f < 1e-13, 1e-13, nls.f) - params.mu = af.select(params.mu < 1e-13, 1e-13, params.mu) - -# f_left = nls.boundary_conditions.\ -# f_left(nls.f, nls.q1_center, nls.q2_center, -# nls.p1, nls.p2, nls.p3, -# nls.physical_system.params -# ) -# nls.f[:, -N_g:, 10:24] = f_right[:, -N_g:, 10:24] - n_nls = nls.compute_moments('density') - print("mu = ", af.mean(params.mu[0, N_g:-N_g, N_g:-N_g]), - "phi = ", af.mean(params.phi[0, N_g:-N_g, N_g:-N_g]), - "density = ", mean_density - ) - print("--------------------\n") +# nls.strang_timestep(dt) +# +# # Floors +# nls.f = af.select(nls.f < 1e-13, 1e-13, nls.f) +# params.mu = af.select(params.mu < 1e-13, 1e-13, params.mu) +# +## f_left = nls.boundary_conditions.\ +## f_left(nls.f, nls.q1_center, nls.q2_center, +## nls.p1, nls.p2, nls.p3, +## nls.physical_system.params +## ) +## nls.f[:, -N_g:, 10:24] = f_right[:, -N_g:, 10:24] +# n_nls = nls.compute_moments('density') +# print("rank = ", nls._comm.rank, " params.rank = ", params.rank, +# "mu = ", af.mean(params.mu[0, N_g:-N_g, N_g:-N_g]), +# "phi = ", af.mean(params.phi[0, N_g:-N_g, N_g:-N_g]), +# "density = ", mean_density +# ) +# PETSc.Sys.Print("--------------------\n") ###pl.contourf(np.array(params.mu)[N_g:-N_g, N_g:-N_g].transpose(), 100, cmap='jet') ##pl.contourf(np.array(n_nls)[N_g:-N_g, N_g:-N_g].transpose(), 100, cmap='jet') From 43d9a73692e2e2df1f978fcc142b758be22773a7 Mon Sep 17 00:00:00 2001 From: Mani Chandra Date: Thu, 21 Dec 2017 19:42:32 +0530 Subject: [PATCH 15/28] (1) Cleaned up Poisson solver (somewhat). Works in parallel for nproc = 2, 4, [?] (2) Upwind fluxes in p space --- .../EM_fields_solver/electrostatic.py | 355 ++++++++---------- .../nonlinear_solver/FVM_solver/df_dt_fvm.py | 19 +- bolt/lib/nonlinear_solver/nonlinear_solver.py | 14 +- bolt/lib/physical_system.py | 18 +- .../electronic_boltzmann/advection_terms.py | 14 +- .../collision_operator.py | 38 +- .../electronic_boltzmann/graphene/domain.py | 16 +- .../electronic_boltzmann/graphene/main.py | 269 ++++++------- .../electronic_boltzmann/graphene/params.py | 8 +- 9 files changed, 343 insertions(+), 408 deletions(-) diff --git a/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py b/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py index eceb94fd..32808e81 100644 --- a/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py +++ b/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py @@ -7,35 +7,6 @@ import pylab as pl import params -pl.rcParams['figure.figsize'] = 17, 7.5 -pl.rcParams['figure.dpi'] = 150 -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'] = 20 -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' - class poisson_eqn_3D(object): """ This user class is an application context for the problem at hand; @@ -54,6 +25,7 @@ def __init__(self, nonlinear_solver_obj): self.glob_residual = self.da_3D.createGlobalVec() self.N_ghost = self.obj.N_ghost + self.N_ghost_poisson = self.obj.N_ghost_poisson self.dq1 = self.obj.dq1 self.dq2 = self.obj.dq2 self.dq3 = self.obj.dq3 @@ -65,6 +37,14 @@ def __init__(self, nonlinear_solver_obj): ((i_q1_3D_start, i_q2_3D_start, i_q3_3D_start), (N_q1_3D_local, N_q2_3D_local, N_q3_3D_local) ) = self.da_3D.getCorners() + + self.i_q1_3D_start = i_q1_3D_start + self.i_q2_3D_start = i_q2_3D_start + self.i_q3_3D_start = i_q3_3D_start + + self.i_q1_3D_end = i_q1_3D_start + N_q1_3D_local - 1 + self.i_q2_3D_end = i_q2_3D_start + N_q2_3D_local - 1 + self.i_q3_3D_end = i_q3_3D_start + N_q3_3D_local - 1 self.N_q1_2D_local = N_q1_2D_local self.N_q2_2D_local = N_q2_2D_local @@ -73,8 +53,9 @@ def __init__(self, nonlinear_solver_obj): self.N_q2_3D_local = N_q2_3D_local self.N_q3_3D_local = N_q3_3D_local - location_in_q3 = 10. - N_g = self.N_ghost + location_in_q3 = self.obj.location_in_q3 + N_g = self.N_ghost # Ghost zones of Boltzmann solver + N_gp = self.N_ghost_poisson # Ghost zones of Poisson solver self.density_np = np.zeros([N_q2_2D_local + 2*N_g, N_q1_2D_local + 2*N_g @@ -82,15 +63,15 @@ def __init__(self, nonlinear_solver_obj): ) # Cell centers in 3D i_q1_3D = ( (i_q1_3D_start + 0.5) - + np.arange(-N_g, N_q1_3D_local + N_g) + + np.arange(-N_gp, N_q1_3D_local + N_gp) ) i_q2_3D = ( (i_q2_3D_start + 0.5) - + np.arange(-N_g, N_q2_3D_local + N_g) + + np.arange(-N_gp, N_q2_3D_local + N_gp) ) i_q3_3D = ( (i_q3_3D_start + 0.5) - + np.arange(-N_g, N_q3_3D_local + N_g) + + np.arange(-N_gp, N_q3_3D_local + N_gp) ) q1_2D_start = self.obj.q1_start @@ -121,66 +102,103 @@ def __init__(self, nonlinear_solver_obj): q2_3D = q2_2D_start - length_multiples_q2*length_q2_2d + i_q2_3D * self.dq2 q3_3D = q3_3D_start + i_q3_3D * self.dq3 - self.q3_2D_in_3D_index_start = np.where(q3_3D > location_in_q3 - self.dq3)[0][0] - self.q3_2D_in_3D_index_end = np.where(q3_3D < location_in_q3 + self.dq3)[0][-1] - - self.q1_2D_in_3D_index_start = np.where(abs(q1_3D - q1_2D[N_g] ) < 1e-10)[0][0] - self.q1_2D_in_3D_index_end = np.where(abs(q1_3D - q1_2D[-1-N_g]) < 1e-10)[0][0] - self.q2_2D_in_3D_index_start = np.where(abs(q2_3D - q2_2D[N_g] ) < 1e-10)[0][0] - self.q2_2D_in_3D_index_end = np.where(abs(q2_3D - q2_2D[-1-N_g]) < 1e-10)[0][0] - glob_epsilon = self.da_3D.createGlobalVec() local_epsilon = self.da_3D.createLocalVec() epsilon_array = local_epsilon.getArray(readonly=0) - epsilon_array = epsilon_array.reshape([N_q3_3D_local + 2*N_g, \ - N_q2_3D_local + 2*N_g, \ - N_q1_3D_local + 2*N_g + epsilon_array = epsilon_array.reshape([N_q3_3D_local + 2*N_gp, \ + N_q2_3D_local + 2*N_gp, \ + N_q1_3D_local + 2*N_gp ] ) epsilon_array[:] = params.epsilon0 - epsilon_array[:self.q3_2D_in_3D_index_start, :, :] = 10.*params.epsilon0 + epsilon_array[q3_3D= q1_2D[N_g] - tol) \ + & (q1_3D_data_structure <= q1_2D[-1-N_g] + tol) \ + & (q2_3D_data_structure >= q2_2D[N_g] - tol) \ + & (q2_3D_data_structure <= q2_2D[-1-N_g] + tol) \ + & (q3_3D_data_structure >= location_in_q3) \ + & (q3_3D_data_structure < location_in_q3 + self.dq3) + + self.cond_2D = (q1_2D_data_structure >= q1_2D[N_g]) \ + & (q1_2D_data_structure <= q1_2D[-1-N_g]) \ + & (q2_2D_data_structure >= q2_2D[N_g]) \ + & (q2_2D_data_structure <= q2_2D[-1-N_g]) + + self.cond_3D_phi = (q1_3D_data_structure >= q1_2D[0] - tol) \ + & (q1_3D_data_structure <= q1_2D[-1] + tol) \ + & (q2_3D_data_structure >= q2_2D[0] - tol) \ + & (q2_3D_data_structure <= q2_2D[-1] + tol) \ + & (q3_3D_data_structure >= location_in_q3) \ + & (q3_3D_data_structure < location_in_q3 + self.dq3) + + contact_start = 2.5; contact_end = 7.5 + + self.cond_left_contact = \ + (q1_3D_data_structure[N_gp:-N_gp, N_gp:-N_gp, N_gp:-N_gp] < q1_2D[N_g] - tol) \ + & (q2_3D_data_structure[N_gp:-N_gp, N_gp:-N_gp, N_gp:-N_gp] > contact_start-tol) \ + & (q2_3D_data_structure[N_gp:-N_gp, N_gp:-N_gp, N_gp:-N_gp] < contact_end + tol) \ + & (q3_3D_data_structure[N_gp:-N_gp, N_gp:-N_gp, N_gp:-N_gp] > location_in_q3) \ + & (q3_3D_data_structure[N_gp:-N_gp, N_gp:-N_gp, N_gp:-N_gp] < location_in_q3 + self.dq3) + + self.cond_right_contact = \ + (q1_3D_data_structure[N_gp:-N_gp, N_gp:-N_gp, N_gp:-N_gp] > q1_2D[-1-N_g] + tol) \ + & (q2_3D_data_structure[N_gp:-N_gp, N_gp:-N_gp, N_gp:-N_gp] > contact_start-tol) \ + & (q2_3D_data_structure[N_gp:-N_gp, N_gp:-N_gp, N_gp:-N_gp] < contact_end + tol) \ + & (q3_3D_data_structure[N_gp:-N_gp, N_gp:-N_gp, N_gp:-N_gp] > location_in_q3) \ + & (q3_3D_data_structure[N_gp:-N_gp, N_gp:-N_gp, N_gp:-N_gp] < location_in_q3 + self.dq3) + + backgate_potential = -10. self.q3 = q3_3D_data_structure z = self.q3 - z_sample = q3_3D[self.q3_2D_in_3D_index_start] - z_backgate = q3_3D[0] + #z_sample = q3_3D[self.q3_2D_in_3D_index_start] + #TODO: FIX THIS ASAP + z_sample = location_in_q3 + z_backgate = q3_3D[N_gp] side_wall_boundaries = \ backgate_potential*(z_sample - z)/(z_sample - z_backgate) self.bc = 0.*self.q3 # 3D boundary condition array self.bc[:] = 0. - self.bc[:N_g, :, :] = backgate_potential # backgate + self.bc[:N_gp, :, :] = backgate_potential # backgate - self.bc[:self.q3_2D_in_3D_index_start, :N_g, :] = \ - side_wall_boundaries[:self.q3_2D_in_3D_index_start, :N_g, :] + below_sample = q3_3Daf self.phi = af.to_array(phi_2D_local_array) # Since rho was defined at (i + 0.5, j + 0.5) @@ -397,15 +336,41 @@ def compute_electrostatic_fields(self): params.phi = self.phi # Obtaining the electric field values at (i+0.5, j+0.5): - self.E1 = -( af.shift(self.phi, -1, 0) - - af.shift(self.phi, 1, 0) - ) / (2 * self.dq1) - - self.E2 = -( af.shift(self.phi, 0, -1) - - af.shift(self.phi, 0, 1) - ) / (2 * self.dq2) - - af.eval(self.E1, self.E2) + E1 = -( af.shift(self.phi, -1, 0) + - af.shift(self.phi, 1, 0) + ) / (2 * self.dq1) + + E2 = -( af.shift(self.phi, 0, -1) + - af.shift(self.phi, 0, 1) + ) / (2 * self.dq2) + + E3 = -( af.shift(self.phi, 0, 0, -1) + - af.shift(self.phi, 0, 0, 1) + ) / (2 * self.dq3) + + af.eval(E1, E2, E3) + + E1 = af.moddims(E1, + 1, + self.N_q1_local + 2*N_g, + self.N_q2_local + 2*N_g + ) + + E2 = af.moddims(E2, + 1, + self.N_q1_local + 2*N_g, + self.N_q2_local + 2*N_g + ) + + E3 = af.moddims(E3, + 1, + self.N_q1_local + 2*N_g, + self.N_q2_local + 2*N_g + ) + + self.cell_centered_EM_fields[0, :] = E1 + self.cell_centered_EM_fields[1, :] = E2 + self.cell_centered_EM_fields[2, :] = E3 if(self.performance_test_flag == True): af.sync() diff --git a/bolt/lib/nonlinear_solver/FVM_solver/df_dt_fvm.py b/bolt/lib/nonlinear_solver/FVM_solver/df_dt_fvm.py index 553e1ba6..93dfd3cd 100644 --- a/bolt/lib/nonlinear_solver/FVM_solver/df_dt_fvm.py +++ b/bolt/lib/nonlinear_solver/FVM_solver/df_dt_fvm.py @@ -1,8 +1,9 @@ import arrayfire as af from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic import fft_poisson +from bolt.lib.nonlinear_solver.EM_fields_solver.electrostatic import compute_electrostatic_fields # Importing Riemann solver used in calculating fluxes: -from .riemann_solver import riemann_solver +from .riemann_solver import riemann_solver, upwind_flux from .reconstruct import reconstruct # Equation to solve: @@ -81,7 +82,7 @@ def df_dt_fvm(f, self, at_n = True): fft_poisson(self, f) elif(self.physical_system.params.fields_solver == 'SNES'): - #compute_electrostatic_fields(self) + compute_electrostatic_fields(self) pass self._communicate_fields() @@ -158,10 +159,20 @@ def df_dt_fvm(f, self, at_n = True): # back_minus_eps_flux_p3 = af.shift(front_minus_eps_flux_p3, 0, 0, 1) # Obtaining the fluxes by face-averaging: - left_flux_p1 = 0.5 * (left_minus_eps_flux_p1 + left_plus_eps_flux_p1) - bot_flux_p2 = 0.5 * (bot_minus_eps_flux_p2 + bot_plus_eps_flux_p2) +# left_flux_p1 = 0.5 * (left_minus_eps_flux_p1 + left_plus_eps_flux_p1) +# bot_flux_p2 = 0.5 * (bot_minus_eps_flux_p2 + bot_plus_eps_flux_p2) # back_flux_p3 = 0.5 * (back_minus_eps_flux_p3 + back_plus_eps_flux_p3) + left_flux_p1 = upwind_flux(left_minus_eps_flux_p1, \ + left_plus_eps_flux_p1, \ + self._convert_to_p_expanded(A_p1) + ) + + bot_flux_p2 = upwind_flux(bot_minus_eps_flux_p2, \ + bot_plus_eps_flux_p2, \ + self._convert_to_p_expanded(A_p2) + ) + right_flux_p1 = af.shift(left_flux_p1, -1) top_flux_p2 = af.shift(bot_flux_p2, 0, -1) # front_flux_p3 = af.shift(back_flux_p3, 0, 0, -1) diff --git a/bolt/lib/nonlinear_solver/nonlinear_solver.py b/bolt/lib/nonlinear_solver/nonlinear_solver.py index b66f9f20..1c849be4 100644 --- a/bolt/lib/nonlinear_solver/nonlinear_solver.py +++ b/bolt/lib/nonlinear_solver/nonlinear_solver.py @@ -118,8 +118,9 @@ def __init__(self, physical_system, performance_test_flag = False): # Declaring the communicator: self._comm = PETSc.COMM_WORLD.tompi4py() - if(self.physical_system.params.num_devices>1): - af.set_device(self._comm.rank%self.physical_system.params.num_devices) + af.set_device(1) +# if(self.physical_system.params.num_devices>1): +# af.set_device(self._comm.rank%self.physical_system.params.num_devices) PETSc.Sys.Print('\nBackend Details for Nonlinear Solver:') @@ -213,24 +214,26 @@ def __init__(self, physical_system, performance_test_flag = False): # TODO: Remove the following hardcoded values self.length_multiples_q1 = 1 self.length_multiples_q2 = 1 + self.location_in_q3 = 10. self.q3_3D_start = 0.; self.q3_3D_end = 20. - self.dq3 = physical_system.dq1 + self.dq3 = self.dq1 self.N_q1_poisson = (2*self.length_multiples_q1+1)*self.N_q1 self.N_q2_poisson = (2*self.length_multiples_q2+1)*self.N_q2 self.N_q3_poisson = (int)((self.q3_3D_end - self.q3_3D_start) / self.dq3) + self.N_ghost_poisson = 1 self._da_snes = PETSc.DMDA().create([self.N_q1_poisson, self.N_q2_poisson, self.N_q3_poisson], - stencil_width = self.N_ghost, + stencil_width = self.N_ghost_poisson, boundary_type = (petsc_bc_in_q1, petsc_bc_in_q2, 'periodic' ), proc_sizes = (PETSc.DECIDE, PETSc.DECIDE, - PETSc.DECIDE + 1 ), stencil_type = 1, dof = 1, @@ -480,7 +483,6 @@ def _calculate_p_center(self): p1_center, p3_center ) - # Flattening the arrays: p1_center = af.flat(af.to_array(p1_center)) p2_center = af.flat(af.to_array(p2_center)) diff --git a/bolt/lib/physical_system.py b/bolt/lib/physical_system.py index 20334e82..40817d25 100644 --- a/bolt/lib/physical_system.py +++ b/bolt/lib/physical_system.py @@ -98,15 +98,15 @@ def __init__(self, raise TypeError('Expected source_or_sink to be of type function') # Checking for the types of the methods in advection_term: - attributes = [a for a in dir(advection_term) if not a.startswith('_')] - for i in range(len(attributes)): - if(isinstance(getattr(advection_term, attributes[i]), - types.FunctionType - ) is False - ): - raise TypeError('Expected attributes of advection_term \ - to be of type function' - ) +# attributes = [a for a in dir(advection_term) if not a.startswith('_')] +# for i in range(len(attributes)): +# if(isinstance(getattr(advection_term, attributes[i]), +# types.FunctionType +# ) is False +# ): +# raise TypeError('Expected attributes of advection_term \ +# to be of type function' +# ) # Checking for the data-type in moment_defs: if(not isinstance(moment_defs.moment_exponents, dict) or diff --git a/bolt/src/electronic_boltzmann/advection_terms.py b/bolt/src/electronic_boltzmann/advection_terms.py index ea2a907c..6d132c54 100644 --- a/bolt/src/electronic_boltzmann/advection_terms.py +++ b/bolt/src/electronic_boltzmann/advection_terms.py @@ -1,5 +1,5 @@ #import numpy as np -#import arrayfire as af +import arrayfire as af #@af.broadcast def A_q(q1, q2, p1, p2, p3, params): @@ -31,14 +31,14 @@ def A_p(q1, q2, p1, p2, p3, # dp2_dt = e*(E2 + (p3*B1 - p1*B3) / c) # p2 = hcross * k2 # dp3_dt = e*(E3 + (p1*B2 - p2*B1) / c) # p3 = hcross * k3 - dp1_dt = 0.*-e*E1 - dp2_dt = 0.*-e*E2 - dp3_dt = 0. + dp1_dt = -e*E1 + 0.*p1**0. + dp2_dt = -e*E2 + 0.*p1**0. + dp3_dt = 0. + 0.*p1**0. #dp1_dt = 1e-5*e*0.5*(-af.tanh(100.*(q1 - 0.9)) - af.tanh(100.*(q1 - 0.1)) ) - amplitude = 1e-2 - E1_analytic = amplitude * -(q1 - 5.) - dp1_dt = E1_analytic +# amplitude = 1e-3 +# E1_analytic = amplitude * -(q1 - 5.) +# dp1_dt = E1_analytic #E2_analytic = amplitude * -(q2 - 5.) #dp2_dt = E2_analytic diff --git a/bolt/src/electronic_boltzmann/collision_operator.py b/bolt/src/electronic_boltzmann/collision_operator.py index 4d76e875..fb8dc4e4 100644 --- a/bolt/src/electronic_boltzmann/collision_operator.py +++ b/bolt/src/electronic_boltzmann/collision_operator.py @@ -26,7 +26,7 @@ def f0_defect_constant_T(f, p1, p2, p3, params): fermi_dirac = 1./(af.exp( (E_upper - mu)/(k*T) ) + 1.) af.eval(fermi_dirac) - zeroth_moment = f - fermi_dirac + 1./(af.exp( (E_upper )/(k*T) ) + 1.) + zeroth_moment = f - fermi_dirac eqn_mass_conservation = af.sum(zeroth_moment, 0) @@ -53,7 +53,7 @@ def f0_defect_constant_T(f, p1, p2, p3, params): fermi_dirac = 1./(af.exp( (E_upper - mu)/(k*T) ) + 1.) af.eval(fermi_dirac) - zeroth_moment = f - fermi_dirac + 1./(af.exp( (E_upper )/(k*T) ) + 1.) + zeroth_moment = f - fermi_dirac eqn_mass_conservation = af.sum(zeroth_moment, 0) @@ -66,7 +66,7 @@ def f0_defect_constant_T(f, p1, p2, p3, params): density_f = af.sum(f, 0) fermi_dirac = 1./(af.exp( (E_upper - mu)/(k*T) ) + 1.) - density_fermi_dirac = af.sum(fermi_dirac - 1./(af.exp( (E_upper )/(k*T) ) + 1.), 0) + density_fermi_dirac = af.sum(fermi_dirac, 0) print(" rank = ", params.rank, "mu = ", af.mean(params.mu[0, N_g:-N_g, N_g:-N_g]), @@ -99,10 +99,10 @@ def f0_defect(f, p1, p2, p3, params): denominator = (k*T**2.*(af.exp(tmp) + 2. + af.exp(-tmp)) ) # TODO: Multiply with the integral measure dp1 * dp2 - a00 = af.sum(T / denominator, 2) - a01 = af.sum((E_upper - mu) / denominator, 2) - a10 = af.sum(E_upper*T / denominator, 2) - a11 = af.sum(E_upper*(E_upper - mu) / denominator, 2) + a00 = af.sum(T / denominator, 0) + a01 = af.sum((E_upper - mu) / denominator, 0) + a10 = af.sum(E_upper*T / denominator, 0) + a11 = af.sum(E_upper*(E_upper - mu) / denominator, 0) # Solve Ax = b # where A == Jacobian, @@ -115,12 +115,12 @@ def f0_defect(f, p1, p2, p3, params): zeroth_moment = f - fermi_dirac second_moment = E_upper*(f - fermi_dirac) - eqn_mass_conservation = af.sum(zeroth_moment, 2) - eqn_energy_conservation = af.sum(second_moment, 2) + eqn_mass_conservation = af.sum(zeroth_moment, 0) + eqn_energy_conservation = af.sum(second_moment, 0) N_g = domain.N_ghost - error_mass_conservation = af.max(af.abs(eqn_mass_conservation)[N_g:-N_g, N_g:-N_g]) - error_energy_conservation = af.max(af.abs(eqn_energy_conservation)[N_g:-N_g, N_g:-N_g]) + error_mass_conservation = af.max(af.abs(eqn_mass_conservation)[0, N_g:-N_g, N_g:-N_g]) + error_energy_conservation = af.max(af.abs(eqn_energy_conservation)[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])), @@ -156,22 +156,22 @@ def f0_defect(f, p1, p2, p3, params): zeroth_moment = f - fermi_dirac second_moment = E_upper*(f - fermi_dirac) - eqn_mass_conservation = af.sum(zeroth_moment, 2) - eqn_energy_conservation = af.sum(second_moment, 2) + eqn_mass_conservation = af.sum(zeroth_moment, 0) + eqn_energy_conservation = af.sum(second_moment, 0) 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) - density_f = af.sum(f, 2) + density_f = af.sum(f, 0) fermi_dirac = 1./(af.exp( (E_upper - mu)/(k*T) ) + 1.) - density_fermi_dirac = af.sum(fermi_dirac, 2) + density_fermi_dirac = af.sum(fermi_dirac, 0) - print(" mu = ", af.mean(params.mu[N_g:-N_g, N_g:-N_g]), - "T = ", af.mean(params.T[N_g:-N_g, N_g:-N_g]), - "density_f = ", af.mean(density_f[N_g:-N_g, N_g:-N_g]), - "density_fermi_dirac = ",af.mean(density_fermi_dirac[N_g:-N_g, N_g:-N_g]) + print(" mu = ", af.mean(params.mu[0, N_g:-N_g, N_g:-N_g]), + "T = ", af.mean(params.T[0, N_g:-N_g, N_g:-N_g]), + "density_f = ", af.mean(density_f[0, N_g:-N_g, N_g:-N_g]), + "density_fermi_dirac = ",af.mean(density_fermi_dirac[0, N_g:-N_g, N_g:-N_g]) ) print(" ------------------") diff --git a/example_problems/electronic_boltzmann/graphene/domain.py b/example_problems/electronic_boltzmann/graphene/domain.py index 06f8457d..865c2e1b 100644 --- a/example_problems/electronic_boltzmann/graphene/domain.py +++ b/example_problems/electronic_boltzmann/graphene/domain.py @@ -1,18 +1,18 @@ q1_start = 0. q1_end = 10. -N_q1 = 28 +N_q1 = 30 q2_start = 0. q2_end = 10. -N_q2 = 28 +N_q2 = 30 -p1_start = -0.05 -p1_end = 0.05 -N_p1 = 375 +p1_start = -0.01 +p1_end = 0.01 +N_p1 = 75 -p2_start = -0.02 -p2_end = 0.02 -N_p2 = 150 +p2_start = -0.01 +p2_end = 0.01 +N_p2 = 75 p3_start = -0.5 p3_end = 0.5 diff --git a/example_problems/electronic_boltzmann/graphene/main.py b/example_problems/electronic_boltzmann/graphene/main.py index bb7830e5..97b0fe00 100644 --- a/example_problems/electronic_boltzmann/graphene/main.py +++ b/example_problems/electronic_boltzmann/graphene/main.py @@ -71,150 +71,134 @@ params.rank = nls._comm.rank # Time parameters: -dt = 0.002 +#dt = 0.002*100 +dt = 0.1*1e-3 t_final = 1000. time_array = np.arange(dt, t_final + dt, dt) compute_electrostatic_fields(nls) -#params.mu = params.charge_electron*params.phi N_g = domain.N_ghost -#N_q1_local = params.mu.shape[0] - 2*N_g -#for i in range(N_g): -# params.mu[i, :] = 0.*params.mu[N_g, :] -# params.mu[N_q1_local+N_g+i, :] = 0.*params.mu[N_q1_local+N_g-1, :] print("rank = ", nls._comm.rank, " params.rank = ", params.rank, "mu = ", af.mean(params.mu[0, N_g:-N_g, N_g:-N_g]), - "phi = ", af.mean(params.phi[0, N_g:-N_g, N_g:-N_g]), + "phi = ", af.mean(params.phi[N_g:-N_g, N_g:-N_g]), "density = ", af.mean(n_nls[0, N_g:-N_g, N_g:-N_g]) + "|E1| = ", af.mean(af.abs(nls.cell_centered_EM_fields[0])), + "|E2| = ", af.mean(af.abs(nls.cell_centered_EM_fields[1])) ) - - -#for time_step, t0 in enumerate(time_array): -# PETSc.Sys.Print("Time step =", time_step, ", Time =", t0) -# -# N_g = domain.N_ghost -# mean_density = af.mean(n_nls[0, N_g:-N_g, N_g:-N_g]) -# density_pert = n_nls - mean_density +t0 = 0.0 +time_index = 0 +while t0 < t_final: + time_index = time_index + 1 + + 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]) + ) + ) + + dt_collision_constraint = 0.5*1. + + #dt = np.min(dt_force_constraint, dt_collision_constraint) + + t0 = t0 + dt + + print("Time step =", time_index, ", Time =", t0, " dt = ", + dt_force_constraint) + + N_g = domain.N_ghost + mean_density = af.mean(n_nls[0, N_g:-N_g, N_g:-N_g]) + density_pert = n_nls - mean_density + +for time_step, t0 in enumerate(time_array): + PETSc.Sys.Print("Time step =", time_step, ", Time =", t0) + + N_g = domain.N_ghost + mean_density = af.mean(n_nls[0, N_g:-N_g, N_g:-N_g]) + density_pert = n_nls - mean_density + + dump_steps = 1000 + if (time_step%dump_steps==0): + nls.dump_moments('dumps/density_' + '%06d'%(time_step/dump_steps) + '.h5') + nls.dump_distribution_function('dumps/f_' + '%06d'%(time_step/dump_steps) + '.h5') + +# if (time_index%1==0): +# pl.contourf(np.array(nls.q1_center)[0, :, :], \ +# np.array(nls.q2_center)[0, :, :], \ +# np.array(params.mu)[0, :, :], \ +# 100, cmap='bwr' +# ) +# pl.title('Time = ' + "%.2f"%(t0) ) +# pl.xlabel('$x$') +# pl.ylabel('$y$') +# pl.colorbar() +# pl.gca().set_aspect('equal') +# pl.savefig('/tmp/mu_' + '%06d'%time_index + '.png' ) +# pl.clf() # -# dump_steps = 100 -# if (time_step%dump_steps==0): -# nls.dump_moments('dumps/density_' + '%06d'%(time_step/dump_steps) + '.h5') -# nls.dump_distribution_function('dumps/f_' + '%06d'%(time_step/dump_steps) + '.h5') -# -## if (time_index%1==0): -## pl.contourf(np.array(nls.q1_center)[0, N_g:-N_g, N_g:-N_g], \ -## np.array(nls.q2_center)[0, N_g:-N_g, N_g:-N_g], \ -## np.array(n_nls)[0, N_g:-N_g, N_g:-N_g], \ -## 100, cmap='bwr' -## ) -## pl.title('Time = ' + "%.2f"%(t0) ) -## pl.xlabel('$x$') -## pl.ylabel('$y$') -## pl.colorbar() -## pl.gca().set_aspect('equal') -## pl.savefig('/tmp/density_' + '%06d'%time_index + '.png' ) -## pl.clf() -## -## pl.contourf(np.array(nls.q1_center)[0, N_g:-N_g, N_g:-N_g], \ -## np.array(nls.q2_center)[0, N_g:-N_g, N_g:-N_g], \ -## np.array(params.mu)[0, N_g:-N_g, N_g:-N_g], \ -## 100, cmap='bwr' -## ) -## pl.title('Time = ' + "%.2f"%(t0) ) -## pl.xlabel('$x$') -## pl.ylabel('$y$') -## pl.colorbar() -## pl.gca().set_aspect('equal') -## pl.savefig('/tmp/mu_' + '%06d'%time_index + '.png' ) -## pl.clf() -## -### pl.contourf(np.array(nls.q1_center), \ -### np.array(nls.q2_center), \ -### np.array(nls.E1), \ -### 100, cmap='bwr' -### ) -### pl.title('Time = ' + "%.2f"%(t0) ) -### pl.xlabel('$x$') -### pl.ylabel('$y$') -### pl.colorbar() -### pl.gca().set_aspect('equal') -### pl.savefig('/tmp/E1_' + '%06d'%time_index + '.png' ) -### pl.clf() -### -### pl.contourf(np.array(nls.q1_center), \ -### np.array(nls.q2_center), \ -### np.array(nls.E2), \ -### 100, cmap='bwr' -### ) -### pl.title('Time = ' + "%.2f"%(t0) ) -### pl.xlabel('$x$') -### pl.ylabel('$y$') -### pl.colorbar() -### pl.gca().set_aspect('equal') -### pl.savefig('/tmp/E2_' + '%06d'%time_index + '.png' ) -### pl.clf() -### -## f_at_desired_q = af.moddims(nls.f[:, N_g, N_g + nls.N_q2/2], -## nls.N_p1, nls.N_p2 -## ) -## p1 = af.moddims(nls.p1, nls.N_p1, nls.N_p2) -## p2 = af.moddims(nls.p2, nls.N_p1, nls.N_p2) -## pl.contourf(np.array(p1), \ -## np.array(p2), \ -## np.array((f_at_desired_q)), \ -## 100, cmap='bwr' -## ) -## pl.title('Time = ' + "%.2f"%(t0) ) -## pl.xlabel('$x$') -## pl.ylabel('$y$') -## pl.colorbar() -## pl.gca().set_aspect('equal') -## pl.savefig('/tmp/f_' + '%06d'%time_index + '.png' ) -## pl.clf() -## -## pl.contourf(np.array(params.mu)[N_g:-N_g, N_g:-N_g].transpose(), 100, cmap='jet') -## pl.title('Time = ' + "%.2f"%(t0) ) -## pl.xlabel('$x$') -## pl.ylabel('$y$') -## pl.colorbar() -## pl.gca().set_aspect('equal') -## pl.savefig('/tmp/mu_' + '%06d'%time_index + '.png' ) -## pl.clf() -## +# pl.contourf(np.array(nls.q1_center)[0, :, :], \ +# np.array(nls.q2_center)[0, :, :], \ +# np.array(nls.cell_centered_EM_fields)[0, :, :], \ +# 100, cmap='bwr' +# ) +# pl.title('Time = ' + "%.2f"%(t0) ) +# pl.xlabel('$x$') +# pl.ylabel('$y$') +# pl.colorbar() +# pl.gca().set_aspect('equal') +# pl.savefig('/tmp/E1_' + '%06d'%time_index + '.png' ) +# pl.clf() # -# nls.strang_timestep(dt) +# pl.contourf(np.array(nls.q1_center)[0, :, :], \ +# np.array(nls.q2_center)[0, :, :], \ +# np.array(nls.cell_centered_EM_fields)[1, :, :], \ +# 100, cmap='bwr' +# ) +# pl.title('Time = ' + "%.2f"%(t0) ) +# pl.xlabel('$x$') +# pl.ylabel('$y$') +# pl.colorbar() +# pl.gca().set_aspect('equal') +# pl.savefig('/tmp/E2_' + '%06d'%time_index + '.png' ) +# pl.clf() # -# # Floors -# nls.f = af.select(nls.f < 1e-13, 1e-13, nls.f) -# params.mu = af.select(params.mu < 1e-13, 1e-13, params.mu) -# -## f_left = nls.boundary_conditions.\ -## f_left(nls.f, nls.q1_center, nls.q2_center, -## nls.p1, nls.p2, nls.p3, -## nls.physical_system.params -## ) -## nls.f[:, -N_g:, 10:24] = f_right[:, -N_g:, 10:24] -# n_nls = nls.compute_moments('density') -# print("rank = ", nls._comm.rank, " params.rank = ", params.rank, -# "mu = ", af.mean(params.mu[0, N_g:-N_g, N_g:-N_g]), -# "phi = ", af.mean(params.phi[0, N_g:-N_g, N_g:-N_g]), -# "density = ", mean_density -# ) -# PETSc.Sys.Print("--------------------\n") +# f_at_desired_q = af.moddims(nls.f[:, N_g, N_g + nls.N_q2/2], +# nls.N_p1, nls.N_p2 +# ) +# p1 = af.moddims(nls.p1, nls.N_p1, nls.N_p2) +# p2 = af.moddims(nls.p2, nls.N_p1, nls.N_p2) +# pl.contourf(np.array(p1), \ +# np.array(p2), \ +# np.array((f_at_desired_q)), \ +# 100, cmap='bwr' +# ) +# pl.title('Time = ' + "%.2f"%(t0) ) +# pl.xlabel('$x$') +# pl.ylabel('$y$') +# pl.colorbar() +# pl.gca().set_aspect('equal') +# pl.savefig('/tmp/f_' + '%06d'%time_index + '.png' ) +# pl.clf() + + nls.strang_timestep(dt) + + # Floors + nls.f = af.select(nls.f < 1e-13, 1e-13, nls.f) + params.mu = af.select(params.mu < 1e-13, 1e-13, params.mu) + + n_nls = nls.compute_moments('density') + print("rank = ", nls._comm.rank, " params.rank = ", params.rank, + "mu = ", af.mean(params.mu[0, N_g:-N_g, N_g:-N_g]), + "phi = ", af.mean(params.phi[N_g:-N_g, N_g:-N_g]), + "density = ", mean_density, + "|E1| = ", af.mean(af.abs(nls.cell_centered_EM_fields[0])), + "|E2| = ", af.mean(af.abs(nls.cell_centered_EM_fields[1])) + ) + PETSc.Sys.Print("--------------------\n") -###pl.contourf(np.array(params.mu)[N_g:-N_g, N_g:-N_g].transpose(), 100, cmap='jet') -##pl.contourf(np.array(n_nls)[N_g:-N_g, N_g:-N_g].transpose(), 100, cmap='jet') -##pl.title('Density') -###pl.title('$\\mu$') -##pl.xlabel('$x$') -##pl.ylabel('$y$') -##pl.colorbar() -##pl.gca().set_aspect('equal') -##pl.show() -# #phi_array = nls.poisson.glob_phi.getArray() #phi_array = phi_array.reshape([nls.poisson.N_q3_3D_local, \ # nls.poisson.N_q2_3D_local, \ @@ -224,10 +208,8 @@ #pl.subplot(121) #N_g = domain.N_ghost #pl.contourf( -# phi_array[nls.poisson.q3_2D_in_3D_index_start, :, :], 100, cmap='jet' +# phi_array[nls.N_q3_poisson/2, :, :], 100, cmap='jet' # ) -##pl.contourf(np.array(nls.E1)[N_g:-N_g, N_g:-N_g].transpose(), 100, cmap='jet' -## ) #pl.colorbar() #pl.title('Top View') #pl.xlabel('$x$') @@ -236,34 +218,9 @@ # #pl.subplot(122) #pl.contourf(phi_array[:, nls.N_q2_poisson/2, :], 100, cmap='jet') -##pl.contourf(np.array(nls.E2)[N_g:-N_g, N_g:-N_g].transpose(), 100, cmap='jet') #pl.title('Side View') #pl.xlabel('$x$') #pl.ylabel('$z$') #pl.colorbar() #pl.gca().set_aspect('equal') #pl.show() -# -##h5f = h5py.File('dump/0000.h5', 'w') -##h5f.create_dataset('q1', data = nls.q1_center) -##h5f.create_dataset('q2', data = nls.q2_center) -##h5f.create_dataset('n', data = n_nls) -##h5f.close() -## -##def time_evolution(): -## -## for time_index, t0 in enumerate(time_array): -## print('For Time =', t0 ) -## print('MIN(f) =', af.min(nls.f[3:-3, 3:-3])) -## print('MAX(f) =', af.max(nls.f[3:-3, 3:-3])) -## print('SUM(f) =', af.sum(nls.f[3:-3, 3:-3])) -## print() -## -## nls.strang_timestep(dt) -## n_nls = nls.compute_moments('density') -## -## h5f = h5py.File('dump/%04d'%(time_index+1) + '.h5', 'w') -## h5f.create_dataset('n', data = n_nls) -## h5f.close() -## -##time_evolution() diff --git a/example_problems/electronic_boltzmann/graphene/params.py b/example_problems/electronic_boltzmann/graphene/params.py index b64ef164..92c4b2f2 100644 --- a/example_problems/electronic_boltzmann/graphene/params.py +++ b/example_problems/electronic_boltzmann/graphene/params.py @@ -18,8 +18,8 @@ solver_method_in_q = 'FVM' solver_method_in_p = 'FVM' -reconstruction_method_in_q = 'minmod' -reconstruction_method_in_p = 'minmod' +reconstruction_method_in_q = 'weno5' +reconstruction_method_in_p = 'weno5' riemann_solver = 'upwind-flux' @@ -63,12 +63,12 @@ E_band = None vel_band = None -collision_nonlinear_iters = 5 +collision_nonlinear_iters = 3 # Variation of collisional-timescale parameter through phase space: @af.broadcast def tau_defect(q1, q2, p1, p2, p3): - return(1. * q1**0 * p1**0) + return(1e-4 * q1**0 * p1**0) @af.broadcast def tau_ee(q1, q2, p1, p2, p3): From cc2f4418a42fba90443b2a4ca6794a8c2dba334a Mon Sep 17 00:00:00 2001 From: Mani Chandra Date: Thu, 21 Dec 2017 21:18:43 +0530 Subject: [PATCH 16/28] Fixed merge mistakes --- bolt/lib/nonlinear_solver/nonlinear_solver.py | 5 +- .../electronic_boltzmann/graphene/main.py | 46 ++++++++----------- .../electronic_boltzmann/graphene/params.py | 2 +- 3 files changed, 23 insertions(+), 30 deletions(-) diff --git a/bolt/lib/nonlinear_solver/nonlinear_solver.py b/bolt/lib/nonlinear_solver/nonlinear_solver.py index 1c849be4..40066ffa 100644 --- a/bolt/lib/nonlinear_solver/nonlinear_solver.py +++ b/bolt/lib/nonlinear_solver/nonlinear_solver.py @@ -118,9 +118,8 @@ def __init__(self, physical_system, performance_test_flag = False): # Declaring the communicator: self._comm = PETSc.COMM_WORLD.tompi4py() - af.set_device(1) -# if(self.physical_system.params.num_devices>1): -# af.set_device(self._comm.rank%self.physical_system.params.num_devices) + if(self.physical_system.params.num_devices>1): + af.set_device(self._comm.rank%self.physical_system.params.num_devices) PETSc.Sys.Print('\nBackend Details for Nonlinear Solver:') diff --git a/example_problems/electronic_boltzmann/graphene/main.py b/example_problems/electronic_boltzmann/graphene/main.py index 97b0fe00..26994c56 100644 --- a/example_problems/electronic_boltzmann/graphene/main.py +++ b/example_problems/electronic_boltzmann/graphene/main.py @@ -72,7 +72,7 @@ # Time parameters: #dt = 0.002*100 -dt = 0.1*1e-3 +dt = 1e-4 t_final = 1000. time_array = np.arange(dt, t_final + dt, dt) @@ -83,15 +83,21 @@ print("rank = ", nls._comm.rank, " params.rank = ", params.rank, "mu = ", af.mean(params.mu[0, N_g:-N_g, N_g:-N_g]), "phi = ", af.mean(params.phi[N_g:-N_g, N_g:-N_g]), - "density = ", af.mean(n_nls[0, N_g:-N_g, N_g:-N_g]) + "density = ", af.mean(n_nls[0, N_g:-N_g, N_g:-N_g]), "|E1| = ", af.mean(af.abs(nls.cell_centered_EM_fields[0])), "|E2| = ", af.mean(af.abs(nls.cell_centered_EM_fields[1])) ) -t0 = 0.0 -time_index = 0 +t0 = 0.0 +time_step = 0 while t0 < t_final: - time_index = time_index + 1 + + dump_steps = 1000 + if (time_step%dump_steps==0): + nls.dump_moments('dumps/density_' + '%06d'%(time_step/dump_steps)) + nls.dump_distribution_function('dumps/f_' + '%06d'%(time_step/dump_steps)) + + time_step = time_step + 1 dt_force_constraint = \ 0.5 * np.min(nls.dp1, nls.dp2) \ @@ -100,32 +106,20 @@ ) ) - dt_collision_constraint = 0.5*1. + dt_collision_constraint = 1e-3 #dt = np.min(dt_force_constraint, dt_collision_constraint) t0 = t0 + dt - print("Time step =", time_index, ", Time =", t0, " dt = ", - dt_force_constraint) + PETSc.Sys.Print("Time step =", time_step, ", Time =", t0, " dt = ", + dt_force_constraint + ) - N_g = domain.N_ghost - mean_density = af.mean(n_nls[0, N_g:-N_g, N_g:-N_g]) - density_pert = n_nls - mean_density - -for time_step, t0 in enumerate(time_array): - PETSc.Sys.Print("Time step =", time_step, ", Time =", t0) - - N_g = domain.N_ghost mean_density = af.mean(n_nls[0, N_g:-N_g, N_g:-N_g]) density_pert = n_nls - mean_density - dump_steps = 1000 - if (time_step%dump_steps==0): - nls.dump_moments('dumps/density_' + '%06d'%(time_step/dump_steps) + '.h5') - nls.dump_distribution_function('dumps/f_' + '%06d'%(time_step/dump_steps) + '.h5') - -# if (time_index%1==0): +# if (time_step%1==0): # pl.contourf(np.array(nls.q1_center)[0, :, :], \ # np.array(nls.q2_center)[0, :, :], \ # np.array(params.mu)[0, :, :], \ @@ -136,7 +130,7 @@ # pl.ylabel('$y$') # pl.colorbar() # pl.gca().set_aspect('equal') -# pl.savefig('/tmp/mu_' + '%06d'%time_index + '.png' ) +# pl.savefig('/tmp/mu_' + '%06d'%time_step + '.png' ) # pl.clf() # # pl.contourf(np.array(nls.q1_center)[0, :, :], \ @@ -149,7 +143,7 @@ # pl.ylabel('$y$') # pl.colorbar() # pl.gca().set_aspect('equal') -# pl.savefig('/tmp/E1_' + '%06d'%time_index + '.png' ) +# pl.savefig('/tmp/E1_' + '%06d'%time_step + '.png' ) # pl.clf() # # pl.contourf(np.array(nls.q1_center)[0, :, :], \ @@ -162,7 +156,7 @@ # pl.ylabel('$y$') # pl.colorbar() # pl.gca().set_aspect('equal') -# pl.savefig('/tmp/E2_' + '%06d'%time_index + '.png' ) +# pl.savefig('/tmp/E2_' + '%06d'%time_step + '.png' ) # pl.clf() # # f_at_desired_q = af.moddims(nls.f[:, N_g, N_g + nls.N_q2/2], @@ -180,7 +174,7 @@ # pl.ylabel('$y$') # pl.colorbar() # pl.gca().set_aspect('equal') -# pl.savefig('/tmp/f_' + '%06d'%time_index + '.png' ) +# pl.savefig('/tmp/f_' + '%06d'%time_step + '.png' ) # pl.clf() nls.strang_timestep(dt) diff --git a/example_problems/electronic_boltzmann/graphene/params.py b/example_problems/electronic_boltzmann/graphene/params.py index 92c4b2f2..253e9221 100644 --- a/example_problems/electronic_boltzmann/graphene/params.py +++ b/example_problems/electronic_boltzmann/graphene/params.py @@ -68,7 +68,7 @@ # Variation of collisional-timescale parameter through phase space: @af.broadcast def tau_defect(q1, q2, p1, p2, p3): - return(1e-4 * q1**0 * p1**0) + return(1e-3 * q1**0 * p1**0) @af.broadcast def tau_ee(q1, q2, p1, p2, p3): From 8b89d7c304ccdf979a0a777db07120e2f8b1e3ef Mon Sep 17 00:00:00 2001 From: Mani Chandra Date: Fri, 22 Dec 2017 12:14:17 -0500 Subject: [PATCH 17/28] Added job script for aimp.mat.rpi.edu --- example_problems/electronic_boltzmann/graphene/job_script | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 example_problems/electronic_boltzmann/graphene/job_script diff --git a/example_problems/electronic_boltzmann/graphene/job_script b/example_problems/electronic_boltzmann/graphene/job_script new file mode 100644 index 00000000..c99c662e --- /dev/null +++ b/example_problems/electronic_boltzmann/graphene/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 From 8341f681375b9695c834993d4efb925c2d4fd373 Mon Sep 17 00:00:00 2001 From: Mani Chandra Date: Fri, 22 Dec 2017 22:53:47 +0530 Subject: [PATCH 18/28] (1) Fixed bug in parallel SNES solver due to wrong shape of q1_2D, q2_2D (2) Added tau=0 option for defect collision operator (3) Added option to stagger Poisson solver params.electrostatic_solver_step --- .../EM_fields_solver/electrostatic.py | 6 +- .../nonlinear_solver/FVM_solver/df_dt_fvm.py | 92 ++++++++++-------- .../FVM_solver/timestep_df_dt.py | 97 ++++++++++--------- bolt/lib/nonlinear_solver/nonlinear_solver.py | 3 +- bolt/lib/nonlinear_solver/timestep.py | 44 ++++----- .../collision_operator.py | 11 ++- .../electronic_boltzmann/graphene/domain.py | 4 +- .../electronic_boltzmann/graphene/main.py | 20 ++-- .../electronic_boltzmann/graphene/params.py | 4 + 9 files changed, 151 insertions(+), 130 deletions(-) diff --git a/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py b/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py index 32808e81..cb5eeca8 100644 --- a/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py +++ b/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py @@ -118,8 +118,8 @@ def __init__(self, nonlinear_solver_obj): q2_3D_data_structure, q3_3D_data_structure, q1_3D_data_structure = \ np.meshgrid(q2_3D, q3_3D, q1_3D) - q2_2D_data_structure, q1_2D_data_structure = \ - np.meshgrid(q2_2D, q1_2D) + q1_2D_data_structure, q2_2D_data_structure = \ + np.meshgrid(q1_2D, q2_2D) tol = 1e-10 self.cond_3D = (q1_3D_data_structure >= q1_2D[N_g] - tol) \ @@ -376,7 +376,7 @@ def compute_electrostatic_fields(self): af.sync() toc = af.time() self.time_fieldsolver += toc - tic - + return diff --git a/bolt/lib/nonlinear_solver/FVM_solver/df_dt_fvm.py b/bolt/lib/nonlinear_solver/FVM_solver/df_dt_fvm.py index 93dfd3cd..96f9615a 100644 --- a/bolt/lib/nonlinear_solver/FVM_solver/df_dt_fvm.py +++ b/bolt/lib/nonlinear_solver/FVM_solver/df_dt_fvm.py @@ -5,6 +5,7 @@ # Importing Riemann solver used in calculating fluxes: from .riemann_solver import riemann_solver, upwind_flux from .reconstruct import reconstruct +import params # Equation to solve: # df/dt + d(C_q1 * f)/dq1 + d(C_q2 * f)/dq2 = C[f] @@ -77,16 +78,24 @@ def df_dt_fvm(f, self, at_n = True): and self.physical_system.params.charge_electron != 0 ): if(self.physical_system.params.fields_type == 'electrostatic'): - if(self.physical_system.params.fields_solver == 'fft'): - fft_poisson(self, f) - - elif(self.physical_system.params.fields_solver == 'SNES'): - compute_electrostatic_fields(self) - pass + if (params.time_step%params.electrostatic_solver_step==0): + + if(self.physical_system.params.fields_solver == 'fft'): + + fft_poisson(self, f) - self._communicate_fields() - self._apply_bcs_fields() + elif(self.physical_system.params.fields_solver == 'SNES'): + compute_electrostatic_fields(self) + pass + + E1 = self.cell_centered_EM_fields[0] + E2 = self.cell_centered_EM_fields[1] + E3 = self.cell_centered_EM_fields[2] + + B1 = self.cell_centered_EM_fields[3] + B2 = self.cell_centered_EM_fields[4] + B3 = self.cell_centered_EM_fields[5] # This is taken care of by the timestepper that is utilized # when FDTD is to be used with FVM in p-space @@ -98,39 +107,39 @@ def df_dt_fvm(f, self, at_n = True): invalid/not-implemented' ) - if( self.physical_system.params.fields_solver == 'fdtd' - and at_n == True - ): - - E1 = self.cell_centered_EM_fields_at_n[0] - E2 = self.cell_centered_EM_fields_at_n[1] - E3 = self.cell_centered_EM_fields_at_n[2] - - B1 = self.cell_centered_EM_fields_at_n[3] - B2 = self.cell_centered_EM_fields_at_n[4] - B3 = self.cell_centered_EM_fields_at_n[5] - - elif( self.physical_system.params.fields_solver == 'fdtd' - and at_n != False - ): - - E1 = self.cell_centered_EM_fields_at_n_plus_half[0] - E2 = self.cell_centered_EM_fields_at_n_plus_half[1] - E3 = self.cell_centered_EM_fields_at_n_plus_half[2] - - B1 = self.cell_centered_EM_fields_at_n_plus_half[3] - B2 = self.cell_centered_EM_fields_at_n_plus_half[4] - B3 = self.cell_centered_EM_fields_at_n_plus_half[5] - - else: - - E1 = self.cell_centered_EM_fields[0] - E2 = self.cell_centered_EM_fields[1] - E3 = self.cell_centered_EM_fields[2] - - B1 = self.cell_centered_EM_fields[3] - B2 = self.cell_centered_EM_fields[4] - B3 = self.cell_centered_EM_fields[5] +# if( self.physical_system.params.fields_solver == 'fdtd' +# and at_n == True +# ): +# +# E1 = self.cell_centered_EM_fields_at_n[0] +# E2 = self.cell_centered_EM_fields_at_n[1] +# E3 = self.cell_centered_EM_fields_at_n[2] +# +# B1 = self.cell_centered_EM_fields_at_n[3] +# B2 = self.cell_centered_EM_fields_at_n[4] +# B3 = self.cell_centered_EM_fields_at_n[5] +# +# elif( self.physical_system.params.fields_solver == 'fdtd' +# and at_n != False +# ): +# +# E1 = self.cell_centered_EM_fields_at_n_plus_half[0] +# E2 = self.cell_centered_EM_fields_at_n_plus_half[1] +# E3 = self.cell_centered_EM_fields_at_n_plus_half[2] +# +# B1 = self.cell_centered_EM_fields_at_n_plus_half[3] +# B2 = self.cell_centered_EM_fields_at_n_plus_half[4] +# B3 = self.cell_centered_EM_fields_at_n_plus_half[5] +# +# else: +# +# E1 = self.cell_centered_EM_fields[0] +# E2 = self.cell_centered_EM_fields[1] +# E3 = self.cell_centered_EM_fields[2] +# +# B1 = self.cell_centered_EM_fields[3] +# B2 = self.cell_centered_EM_fields[4] +# B3 = self.cell_centered_EM_fields[5] (A_p1, A_p2, A_p3) = af.broadcast(self._A_p, self.q1_center, self.q2_center, self.p1, self.p2, self.p3, @@ -189,7 +198,6 @@ def df_dt_fvm(f, self, at_n = True): df_dt += - (right_flux_p1 - left_flux_p1)/self.dp1 \ - (top_flux_p2 - bot_flux_p2 )/self.dp2 \ #- (front_flux_p3 - back_flux_p3)/self.dp3 - af.eval(df_dt) return(df_dt) diff --git a/bolt/lib/nonlinear_solver/FVM_solver/timestep_df_dt.py b/bolt/lib/nonlinear_solver/FVM_solver/timestep_df_dt.py index ff58735f..387c576d 100644 --- a/bolt/lib/nonlinear_solver/FVM_solver/timestep_df_dt.py +++ b/bolt/lib/nonlinear_solver/FVM_solver/timestep_df_dt.py @@ -11,59 +11,62 @@ def fvm_timestep_RK2(self, dt): + self._communicate_f() + self._apply_bcs_f() + f_initial = self.f self.f = self.f + df_dt_fvm(self.f, self, True) * (dt / 2) self._communicate_f() self._apply_bcs_f() - if( self.physical_system.params.charge_electron != 0 - and self.physical_system.params.fields_solver == 'fdtd' - ): - - # Will return a flattened array containing the values of - # J1,2,3 in 2D space: - self.J1 = self.physical_system.params.charge_electron \ - * self.compute_moments('mom_p1_bulk') # (i + 1/2, j + 1/2) - self.J2 = self.physical_system.params.charge_electron \ - * self.compute_moments('mom_p2_bulk') # (i + 1/2, j + 1/2) - self.J3 = self.physical_system.params.charge_electron \ - * self.compute_moments('mom_p3_bulk') # (i + 1/2, j + 1/2) - - # Obtaining the values for current density on the Yee-Grid: - self.J1 = 0.5 * (self.J1 + af.shift(self.J1, 0, 0, 1)) # (i + 1/2, j) - self.J2 = 0.5 * (self.J2 + af.shift(self.J2, 0, 1, 0)) # (i, j + 1/2) - - self.J3 = 0.25 * ( self.J3 + af.shift(self.J3, 0, 1, 0) + - + af.shift(self.J3, 0, 0, 1) - + af.shift(self.J3, 0, 1, 1) - ) # (i, j) - - # Here: - # cell_centered_EM_fields[:3] is at n - # cell_centered_EM_fields[3:] is at n+1/2 - # cell_centered_EM_fields_at_n_plus_half[3:] is at n-1/2 - - self.cell_centered_EM_fields_at_n[:3] = self.cell_centered_EM_fields[:3] - self.cell_centered_EM_fields_at_n[3:] = \ - 0.5 * ( self.cell_centered_EM_fields_at_n_plus_half[3:] - + self.cell_centered_EM_fields[3:] - ) - - - self.cell_centered_EM_fields_at_n_plus_half[3:] = self.cell_centered_EM_fields[3:] - - fdtd(self, dt) - fdtd_grid_to_ck_grid(self) - - # Here - # cell_centered_EM_fields[:3] is at n+1 - # cell_centered_EM_fields[3:] is at n+3/2 - - self.cell_centered_EM_fields_at_n_plus_half[:3] = \ - 0.5 * ( self.cell_centered_EM_fields_at_n_plus_half[:3] - + self.cell_centered_EM_fields[:3] - ) +# if( self.physical_system.params.charge_electron != 0 +# and self.physical_system.params.fields_solver == 'fdtd' +# ): +# +# # Will return a flattened array containing the values of +# # J1,2,3 in 2D space: +# self.J1 = self.physical_system.params.charge_electron \ +# * self.compute_moments('mom_p1_bulk') # (i + 1/2, j + 1/2) +# self.J2 = self.physical_system.params.charge_electron \ +# * self.compute_moments('mom_p2_bulk') # (i + 1/2, j + 1/2) +# self.J3 = self.physical_system.params.charge_electron \ +# * self.compute_moments('mom_p3_bulk') # (i + 1/2, j + 1/2) +# +# # Obtaining the values for current density on the Yee-Grid: +# self.J1 = 0.5 * (self.J1 + af.shift(self.J1, 0, 0, 1)) # (i + 1/2, j) +# self.J2 = 0.5 * (self.J2 + af.shift(self.J2, 0, 1, 0)) # (i, j + 1/2) +# +# self.J3 = 0.25 * ( self.J3 + af.shift(self.J3, 0, 1, 0) + +# + af.shift(self.J3, 0, 0, 1) +# + af.shift(self.J3, 0, 1, 1) +# ) # (i, j) +# +# # Here: +# # cell_centered_EM_fields[:3] is at n +# # cell_centered_EM_fields[3:] is at n+1/2 +# # cell_centered_EM_fields_at_n_plus_half[3:] is at n-1/2 +# +# self.cell_centered_EM_fields_at_n[:3] = self.cell_centered_EM_fields[:3] +# self.cell_centered_EM_fields_at_n[3:] = \ +# 0.5 * ( self.cell_centered_EM_fields_at_n_plus_half[3:] +# + self.cell_centered_EM_fields[3:] +# ) +# +# +# self.cell_centered_EM_fields_at_n_plus_half[3:] = self.cell_centered_EM_fields[3:] +# +# fdtd(self, dt) +# fdtd_grid_to_ck_grid(self) +# +# # Here +# # cell_centered_EM_fields[:3] is at n+1 +# # cell_centered_EM_fields[3:] is at n+3/2 +# +# self.cell_centered_EM_fields_at_n_plus_half[:3] = \ +# 0.5 * ( self.cell_centered_EM_fields_at_n_plus_half[:3] +# + self.cell_centered_EM_fields[:3] +# ) self.f = f_initial + df_dt_fvm(self.f, self, False) * dt diff --git a/bolt/lib/nonlinear_solver/nonlinear_solver.py b/bolt/lib/nonlinear_solver/nonlinear_solver.py index 40066ffa..83bde4f2 100644 --- a/bolt/lib/nonlinear_solver/nonlinear_solver.py +++ b/bolt/lib/nonlinear_solver/nonlinear_solver.py @@ -220,7 +220,8 @@ def __init__(self, physical_system, performance_test_flag = False): self.N_q1_poisson = (2*self.length_multiples_q1+1)*self.N_q1 self.N_q2_poisson = (2*self.length_multiples_q2+1)*self.N_q2 self.N_q3_poisson = (int)((self.q3_3D_end - self.q3_3D_start) / self.dq3) - self.N_ghost_poisson = 1 + self.N_ghost_poisson = self.N_ghost + #self.N_ghost_poisson = 1 self._da_snes = PETSc.DMDA().create([self.N_q1_poisson, self.N_q2_poisson, diff --git a/bolt/lib/nonlinear_solver/timestep.py b/bolt/lib/nonlinear_solver/timestep.py index 3f1c16ae..a0798421 100644 --- a/bolt/lib/nonlinear_solver/timestep.py +++ b/bolt/lib/nonlinear_solver/timestep.py @@ -19,40 +19,36 @@ # When using FVM: def op_fvm_q(self, dt): - self._communicate_f() - self._apply_bcs_f() - if(self.performance_test_flag == True): tic = af.time() fvm_timestep_RK2(self, dt) - #self._apply_bcs_f() if(self.performance_test_flag == True): af.sync() toc = af.time() self.time_fvm_solver += toc - tic -# # Solving for tau = 0 systems -# if(af.any_true(self.physical_system.params.tau(self.q1_center, self.q2_center, -# self.p1, self.p2, self.p3 -# ) == 0 -# ) -# ): -# if(self.performance_test_flag == True): -# tic = af.time() -# -# self.f = self._source(self.f, self.q1_center, self.q2_center, -# self.p1, self.p2, self.p3, -# self.compute_moments, -# self.physical_system.params, -# True -# ) -# -# if(self.performance_test_flag == True): -# af.sync() -# toc = af.time() -# self.time_sourcets += toc - tic + # Solving for tau = 0 systems + if(af.any_true(self.physical_system.params.tau(self.q1_center, self.q2_center, + self.p1, self.p2, self.p3 + ) == 0 + ) + ): + if(self.performance_test_flag == True): + tic = af.time() + + self.f = self._source(self.f, self.q1_center, self.q2_center, + self.p1, self.p2, self.p3, + self.compute_moments, + self.physical_system.params, + True + ) + + if(self.performance_test_flag == True): + af.sync() + toc = af.time() + self.time_sourcets += toc - tic af.eval(self.f) return diff --git a/bolt/src/electronic_boltzmann/collision_operator.py b/bolt/src/electronic_boltzmann/collision_operator.py index fb8dc4e4..dcca17a5 100644 --- a/bolt/src/electronic_boltzmann/collision_operator.py +++ b/bolt/src/electronic_boltzmann/collision_operator.py @@ -335,7 +335,15 @@ def f0_ee(f, p1, p2, p3, params): def RTA(f, q1, q2, p1, p2, p3, moments, params, flag = False): """Return BGK operator -(f-f0)/tau.""" + + if(af.any_true(params.tau_defect(q1, q2, p1, p2, p3) == 0)): + if (flag == False): + return(0.*f) + + f = f0_defect_constant_T(f, p1, p2, p3, params) + return(f) + C_f = -( f - f0_defect_constant_T(f, p1, p2, p3, params) ) / params.tau_defect(q1, q2, p1, p2, p3) \ # -( f - f0_ee(f, p1, p2, p3, params) @@ -344,6 +352,7 @@ def RTA(f, q1, q2, p1, p2, p3, moments, params, flag = False): # WORKAROUND: C_f = af.select(params.tau_defect(q1, q2, p1, p2, p3) == np.inf, 0, C_f) # C_f = af.select(params.tau_ee(q1, q2, p1, p2, p3) == np.inf, 0, C_f) - + af.eval(C_f) return(C_f) + diff --git a/example_problems/electronic_boltzmann/graphene/domain.py b/example_problems/electronic_boltzmann/graphene/domain.py index 865c2e1b..c02022ad 100644 --- a/example_problems/electronic_boltzmann/graphene/domain.py +++ b/example_problems/electronic_boltzmann/graphene/domain.py @@ -1,10 +1,10 @@ q1_start = 0. q1_end = 10. -N_q1 = 30 +N_q1 = 35 q2_start = 0. q2_end = 10. -N_q2 = 30 +N_q2 = 35 p1_start = -0.01 p1_end = 0.01 diff --git a/example_problems/electronic_boltzmann/graphene/main.py b/example_problems/electronic_boltzmann/graphene/main.py index 26994c56..28ebb0b7 100644 --- a/example_problems/electronic_boltzmann/graphene/main.py +++ b/example_problems/electronic_boltzmann/graphene/main.py @@ -76,6 +76,7 @@ t_final = 1000. time_array = np.arange(dt, t_final + dt, dt) +nls.f = af.select(nls.f < 1e-13, 1e-13, nls.f) compute_electrostatic_fields(nls) N_g = domain.N_ghost @@ -84,12 +85,12 @@ "mu = ", af.mean(params.mu[0, N_g:-N_g, N_g:-N_g]), "phi = ", af.mean(params.phi[N_g:-N_g, N_g:-N_g]), "density = ", af.mean(n_nls[0, N_g:-N_g, N_g:-N_g]), - "|E1| = ", af.mean(af.abs(nls.cell_centered_EM_fields[0])), - "|E2| = ", af.mean(af.abs(nls.cell_centered_EM_fields[1])) + "|E1| = ", af.mean(af.abs(nls.cell_centered_EM_fields[0, N_g:-N_g, N_g:-N_g])), + "|E2| = ", af.mean(af.abs(nls.cell_centered_EM_fields[1, N_g:-N_g, N_g:-N_g])) ) t0 = 0.0 -time_step = 0 +params.time_step = time_step = 0 while t0 < t_final: dump_steps = 1000 @@ -97,8 +98,6 @@ nls.dump_moments('dumps/density_' + '%06d'%(time_step/dump_steps)) nls.dump_distribution_function('dumps/f_' + '%06d'%(time_step/dump_steps)) - time_step = time_step + 1 - dt_force_constraint = \ 0.5 * np.min(nls.dp1, nls.dp2) \ / np.max((af.max(nls.cell_centered_EM_fields[0]), @@ -110,8 +109,6 @@ #dt = np.min(dt_force_constraint, dt_collision_constraint) - t0 = t0 + dt - PETSc.Sys.Print("Time step =", time_step, ", Time =", t0, " dt = ", dt_force_constraint ) @@ -178,18 +175,21 @@ # pl.clf() nls.strang_timestep(dt) + time_step = time_step + 1 + params.time_step = time_step + t0 = t0 + dt # Floors nls.f = af.select(nls.f < 1e-13, 1e-13, nls.f) - params.mu = af.select(params.mu < 1e-13, 1e-13, params.mu) + #params.mu = af.select(params.mu < 1e-25, 1e-25, params.mu) n_nls = nls.compute_moments('density') print("rank = ", nls._comm.rank, " params.rank = ", params.rank, "mu = ", af.mean(params.mu[0, N_g:-N_g, N_g:-N_g]), "phi = ", af.mean(params.phi[N_g:-N_g, N_g:-N_g]), "density = ", mean_density, - "|E1| = ", af.mean(af.abs(nls.cell_centered_EM_fields[0])), - "|E2| = ", af.mean(af.abs(nls.cell_centered_EM_fields[1])) + "|E1| = ", af.mean(af.abs(nls.cell_centered_EM_fields[0, N_g:-N_g, N_g:-N_g])), + "|E2| = ", af.mean(af.abs(nls.cell_centered_EM_fields[1, N_g:-N_g, N_g:-N_g])) ) PETSc.Sys.Print("--------------------\n") diff --git a/example_problems/electronic_boltzmann/graphene/params.py b/example_problems/electronic_boltzmann/graphene/params.py index 253e9221..8926740a 100644 --- a/example_problems/electronic_boltzmann/graphene/params.py +++ b/example_problems/electronic_boltzmann/graphene/params.py @@ -64,6 +64,7 @@ vel_band = None collision_nonlinear_iters = 3 +electrostatic_solver_step = 10000 # Variation of collisional-timescale parameter through phase space: @af.broadcast @@ -74,6 +75,9 @@ def tau_defect(q1, q2, p1, p2, p3): 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(p_x, p_y): p = af.sqrt(p_x**2. + p_y**2.) From 412212a4f4ad8359b9828b87669a285c28867c80 Mon Sep 17 00:00:00 2001 From: Mani Chandra Date: Sun, 24 Dec 2017 08:12:11 -0500 Subject: [PATCH 19/28] Added EM fields output --- .../electronic_boltzmann/graphene/main.py | 31 ++++-- .../electronic_boltzmann/graphene/params.py | 2 +- .../electronic_boltzmann/graphene/post.py | 104 ++++++++++++------ 3 files changed, 92 insertions(+), 45 deletions(-) diff --git a/example_problems/electronic_boltzmann/graphene/main.py b/example_problems/electronic_boltzmann/graphene/main.py index 28ebb0b7..e1111ac6 100644 --- a/example_problems/electronic_boltzmann/graphene/main.py +++ b/example_problems/electronic_boltzmann/graphene/main.py @@ -72,7 +72,7 @@ # Time parameters: #dt = 0.002*100 -dt = 1e-4 +dt = 1e-3 t_final = 1000. time_array = np.arange(dt, t_final + dt, dt) @@ -98,14 +98,21 @@ nls.dump_moments('dumps/density_' + '%06d'%(time_step/dump_steps)) nls.dump_distribution_function('dumps/f_' + '%06d'%(time_step/dump_steps)) - 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]) - ) - ) + # Dump EM fields + af.flat(nls.cell_centered_EM_fields[:, N_g:-N_g, N_g:-N_g]).to_ndarray(nls._glob_fields_array) + PETSc.Object.setName(nls._glob_fields, 'fields') + viewer = PETSc.Viewer().createHDF5('dumps/fields_' + '%06d'%(time_step/dump_steps) + '.h5', 'w', comm=nls._comm) + viewer(nls._glob_fields) - dt_collision_constraint = 1e-3 + 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]) +# ) +# ) + + dt_collision_constraint = 1e-4 #dt = np.min(dt_force_constraint, dt_collision_constraint) @@ -180,16 +187,18 @@ t0 = t0 + dt # Floors - nls.f = af.select(nls.f < 1e-13, 1e-13, nls.f) + #nls.f = af.select(nls.f < 1e-13, 1e-13, nls.f) #params.mu = af.select(params.mu < 1e-25, 1e-25, params.mu) n_nls = nls.compute_moments('density') - print("rank = ", nls._comm.rank, " params.rank = ", params.rank, + print("rank = ", nls._comm.rank, "mu = ", af.mean(params.mu[0, N_g:-N_g, N_g:-N_g]), "phi = ", af.mean(params.phi[N_g:-N_g, N_g:-N_g]), "density = ", mean_density, "|E1| = ", af.mean(af.abs(nls.cell_centered_EM_fields[0, N_g:-N_g, N_g:-N_g])), - "|E2| = ", af.mean(af.abs(nls.cell_centered_EM_fields[1, N_g:-N_g, N_g:-N_g])) + "|E2| = ", af.mean(af.abs(nls.cell_centered_EM_fields[1, N_g:-N_g, N_g:-N_g])), + "q1 = ", np.array(nls.q1_center[0, N_g, 0])[0], "q2 = ", np.array(nls.q2_center[0, 0, N_g])[0], + "N_q1_local= ", nls.N_q1_local, "N_q2_local = ", nls.N_q2_local ) PETSc.Sys.Print("--------------------\n") diff --git a/example_problems/electronic_boltzmann/graphene/params.py b/example_problems/electronic_boltzmann/graphene/params.py index 8926740a..d4a46cef 100644 --- a/example_problems/electronic_boltzmann/graphene/params.py +++ b/example_problems/electronic_boltzmann/graphene/params.py @@ -39,7 +39,7 @@ p_dim = 2 # Number of devices(GPUs/Accelerators) on each node: -num_devices = 1 +num_devices = 6 # Constants: mass_particle = 0.910938356 # x 1e-30 kg diff --git a/example_problems/electronic_boltzmann/graphene/post.py b/example_problems/electronic_boltzmann/graphene/post.py index 04cda77b..82738f74 100644 --- a/example_problems/electronic_boltzmann/graphene/post.py +++ b/example_problems/electronic_boltzmann/graphene/post.py @@ -1,6 +1,10 @@ import numpy as np -import pylab as pl import h5py +import domain +import params +import matplotlib +matplotlib.use('agg') +import pylab as pl # Optimized plot parameters to make beautiful plots: pl.rcParams['figure.figsize'] = 12, 7.5 @@ -32,43 +36,77 @@ pl.rcParams['ytick.labelsize'] = 'medium' pl.rcParams['ytick.direction'] = 'in' -dt = 0.001 -t_final = 2.0 -time = np.arange(dt, t_final + dt, dt) +#time = np.arange(0, params.t_final + params.dt_dump_moments, +# params.dt_dump_moments +# ) + +N_q1 = domain.N_q1 +N_q2 = domain.N_q2 +N_g = domain.N_ghost + +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, q1 = np.meshgrid(q2, q1) -h5f = h5py.File('dump/0000.h5', 'r') -q1 = h5f['q1'][:] -q2 = h5f['q2'][:] -n = h5f['n'][:] +#dump_index = 000424 +#h5f = h5py.File('dumps/density_' + str(dump_index) + '.h5', 'r') +h5f = h5py.File('dumps/density_000030.h5', 'r') +moments = np.swapaxes(h5f['moments'][:], 0, 1) h5f.close() -pl.contourf(q1[3:-3, 3:-3], - q2[3:-3, 3:-3], - n[3:-3, 3:-3], - 100, - cmap = 'gist_heat' - ) -pl.title('Time = 0') +density = moments[:, :] +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.axes().set_aspect('equal') -pl.savefig('images/0000.png') +pl.colorbar() +pl.savefig('images/density' + '.png') +#pl.savefig('images/%04d'%time_index + '.png') pl.clf() -for time_index, t0 in enumerate(time): - h5f = h5py.File('dump/%04d'%(time_index+1) + '.h5', 'r') - n = h5f['n'][:] - h5f.close() - pl.contourf(q1[3:-3, 3:-3], - q2[3:-3, 3:-3], - n[3:-3, 3:-3], - 100, - cmap = 'gist_heat' - ) - pl.title('Time =' + str(t0)) - pl.xlabel(r'$x$') - pl.ylabel(r'$y$') - pl.axes().set_aspect('equal') - pl.savefig('images/%04d'%(time_index+1) + '.png') - pl.clf() +h5f = h5py.File('dumps/fields_000030.h5', 'r') +fields = np.swapaxes(h5f['fields'][:], 0, 1) +h5f.close() + +E1 = fields[:, :, 0] +E2 = fields[:, :, 1] + +pl.figure(figsize=(20, 7.5)) +pl.subplot(121) +pl.contourf(q1, q2, E1, 100, cmap='bwr') +pl.title('$E_1$') +pl.xlabel(r'$x$') +pl.ylabel(r'$y$') +pl.colorbar() +pl.gca().set_aspect('equal') + +pl.subplot(122) +pl.contourf(q1, q2, E2, 100, cmap='bwr') +pl.title('$E_2$') +pl.xlabel(r'$x$') +pl.ylabel(r'$y$') +pl.colorbar() +pl.gca().set_aspect('equal') +pl.savefig('images/E_fields' + '.png') +pl.clf() + +#for time_index, t0 in enumerate(time): +# +# h5f = h5py.File('dumps/density_' + str(time_index) + '.h5', 'r') +# moments = np.swapaxes(h5f['moments'][:], 0, 1) +# h5f.close() +# +# n = moments[:, :, 0] +# +# #pl.contourf(q1, q2, n, np.linspace(0.8, 2.2, 500)) +# pl.contourf(q1, q2, n, 100) +# pl.title('Time = ' + "%.2f"%(t0)) +# pl.axes().set_aspect('equal') +# pl.xlabel(r'$x$') +# pl.ylabel(r'$y$') +# pl.colorbar() +# pl.savefig('images/%04d'%time_index + '.png') +# pl.clf() From 9a725c7e5548411741f70ef96c9b482274c5e5fa Mon Sep 17 00:00:00 2001 From: Mani Chandra Date: Fri, 19 Jan 2018 13:32:10 +0530 Subject: [PATCH 20/28] 1) Added eqbm solver 2) Moved a bunch of hard coded options into params --- .../EM_fields_solver/electrostatic.py | 80 +++-- .../nonlinear_solver/FVM_solver/df_dt_fvm.py | 2 +- bolt/lib/nonlinear_solver/file_io/load.py | 4 +- bolt/lib/nonlinear_solver/nonlinear_solver.py | 14 +- bolt/lib/nonlinear_solver/timestep.py | 76 ++--- .../electronic_boltzmann/advection_terms.py | 14 +- .../collision_operator.py | 14 +- .../graphene/boundary_conditions.py | 16 +- .../electronic_boltzmann/graphene/domain.py | 20 +- .../graphene/initialize.py | 5 +- .../electronic_boltzmann/graphene/job_script | 2 +- .../electronic_boltzmann/graphene/main.py | 283 +++++++++++++----- .../electronic_boltzmann/graphene/params.py | 52 +++- 13 files changed, 377 insertions(+), 205 deletions(-) diff --git a/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py b/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py index cb5eeca8..abf040f8 100644 --- a/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py +++ b/bolt/lib/nonlinear_solver/EM_fields_solver/electrostatic.py @@ -4,7 +4,7 @@ import arrayfire as af import numpy as np from numpy.fft import fftfreq -import pylab as pl +from bolt.lib.nonlinear_solver.FVM_solver.reconstruct import reconstruct import params class poisson_eqn_3D(object): @@ -102,6 +102,10 @@ def __init__(self, nonlinear_solver_obj): q2_3D = q2_2D_start - length_multiples_q2*length_q2_2d + i_q2_3D * self.dq2 q3_3D = q3_3D_start + i_q3_3D * self.dq3 + self.q1_3D = q1_3D + self.q2_3D = q2_3D + self.q3_3D = q3_3D + glob_epsilon = self.da_3D.createGlobalVec() local_epsilon = self.da_3D.createLocalVec() @@ -112,7 +116,8 @@ def __init__(self, nonlinear_solver_obj): ] ) epsilon_array[:] = params.epsilon0 - epsilon_array[q3_3D= location_in_q3) \ & (q3_3D_data_structure < location_in_q3 + self.dq3) - contact_start = 2.5; contact_end = 7.5 + contact_start = params.contact_start + contact_end = params.contact_end self.cond_left_contact = \ (q1_3D_data_structure[N_gp:-N_gp, N_gp:-N_gp, N_gp:-N_gp] < q1_2D[N_g] - tol) \ @@ -157,7 +163,7 @@ def __init__(self, nonlinear_solver_obj): & (q3_3D_data_structure[N_gp:-N_gp, N_gp:-N_gp, N_gp:-N_gp] > location_in_q3) \ & (q3_3D_data_structure[N_gp:-N_gp, N_gp:-N_gp, N_gp:-N_gp] < location_in_q3 + self.dq3) - backgate_potential = -10. + backgate_potential = params.backgate_potential self.q3 = q3_3D_data_structure z = self.q3 @@ -277,9 +283,40 @@ def compute_residual(self, snes, phi, residual): + (D_top_edge - D_bot_edge) /self.dq2 \ + (D_front_edge - D_back_edge) /self.dq3 - laplacian_phi[self.cond_3D] += \ - -params.charge_electron \ - * self.density_np[self.cond_2D] / self.dq3 + if (params.solve_for_equilibrium): + # solve \nabla^2 phi = -rho + # where rho = \int f_FD(mu) d^3k with mu - e * phi = const + + mu = params.global_chem_potential \ + + params.charge_electron*phi_array[self.cond_3D] + mu = af.to_array(mu) + mu = af.moddims(af.to_array(mu), + 1, + self.obj.N_q1_local, + self.obj.N_q2_local + ) + self.obj.f[:, N_g:-N_g, N_g:-N_g] = \ + params.fermi_dirac(mu, params.E_band) + + density_af = af.moddims(self.obj.compute_moments('density'), + (self.obj.N_q1_local+2*self.obj.N_ghost) + * (self.obj.N_q2_local+2*self.obj.N_ghost) + ) + density_np = density_af.to_ndarray() + density_np =\ + density_np.reshape([self.obj.N_q2_local+2*self.obj.N_ghost, + self.obj.N_q1_local+2*self.obj.N_ghost + ] + ) + + laplacian_phi[self.cond_3D] += \ + -params.charge_electron \ + * density_np[self.cond_2D] / self.dq3 + else: + # Density is an external source. Not explicitly coupled to phi. + laplacian_phi[self.cond_3D] += \ + -params.charge_electron \ + * self.density_np[self.cond_2D] / self.dq3 residual_array[:, :, :] = \ laplacian_phi[N_gp:-N_gp, N_gp:-N_gp, N_gp:-N_gp] @@ -335,20 +372,19 @@ def compute_electrostatic_fields(self): ) params.phi = self.phi - # Obtaining the electric field values at (i+0.5, j+0.5): - E1 = -( af.shift(self.phi, -1, 0) - - af.shift(self.phi, 1, 0) - ) / (2 * self.dq1) + # Obtaining the electric field values at (i+0.5, j+0.5) by first + # reconstructing phi to the edges and then differencing them. Needed + # in case phi develops large gradients - E2 = -( af.shift(self.phi, 0, -1) - - af.shift(self.phi, 0, 1) - ) / (2 * self.dq2) + method_in_q = self.physical_system.params.reconstruction_method_in_q - E3 = -( af.shift(self.phi, 0, 0, -1) - - af.shift(self.phi, 0, 0, 1) - ) / (2 * self.dq3) + phi_left, phi_right = reconstruct(self, self.phi, 0, method_in_q) + E1 = -(phi_right - phi_left)/self.dq1 - af.eval(E1, E2, E3) + phi_bottom, phi_top = reconstruct(self, self.phi, 1, method_in_q) + E2 = -(phi_top - phi_bottom)/self.dq2 + + af.eval(E1, E2) E1 = af.moddims(E1, 1, @@ -362,15 +398,9 @@ def compute_electrostatic_fields(self): self.N_q2_local + 2*N_g ) - E3 = af.moddims(E3, - 1, - self.N_q1_local + 2*N_g, - self.N_q2_local + 2*N_g - ) - self.cell_centered_EM_fields[0, :] = E1 self.cell_centered_EM_fields[1, :] = E2 - self.cell_centered_EM_fields[2, :] = E3 + self.cell_centered_EM_fields[2, :] = 0. # TODO: worry about this later if(self.performance_test_flag == True): af.sync() diff --git a/bolt/lib/nonlinear_solver/FVM_solver/df_dt_fvm.py b/bolt/lib/nonlinear_solver/FVM_solver/df_dt_fvm.py index 96f9615a..e43b3c89 100644 --- a/bolt/lib/nonlinear_solver/FVM_solver/df_dt_fvm.py +++ b/bolt/lib/nonlinear_solver/FVM_solver/df_dt_fvm.py @@ -79,7 +79,7 @@ def df_dt_fvm(f, self, at_n = True): ): if(self.physical_system.params.fields_type == 'electrostatic'): - if (params.time_step%params.electrostatic_solver_step==0): + if (params.time_step%params.electrostatic_solver_every_nth_step==0): if(self.physical_system.params.fields_solver == 'fft'): diff --git a/bolt/lib/nonlinear_solver/file_io/load.py b/bolt/lib/nonlinear_solver/file_io/load.py index ae433b2e..0b246993 100644 --- a/bolt/lib/nonlinear_solver/file_io/load.py +++ b/bolt/lib/nonlinear_solver/file_io/load.py @@ -24,7 +24,7 @@ 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 """ - viewer = PETSc.Viewer().createHDF5(file_name + '.h5', + viewer = PETSc.Viewer().createHDF5(file_name, PETSc.Viewer.Mode.READ, comm=self._comm ) @@ -33,7 +33,7 @@ def load_distribution_function(self, file_name): N_g = self.N_ghost self.f[:, N_g:-N_g, N_g:-N_g] = af.moddims(af.to_array(self._glob_f_array), self.N_p1 * self.N_p2 * self.N_p3, - self.N_q1, self.N_q2 + self.N_q1_local, self.N_q2_local ) return diff --git a/bolt/lib/nonlinear_solver/nonlinear_solver.py b/bolt/lib/nonlinear_solver/nonlinear_solver.py index 83bde4f2..76b75fcd 100644 --- a/bolt/lib/nonlinear_solver/nonlinear_solver.py +++ b/bolt/lib/nonlinear_solver/nonlinear_solver.py @@ -211,18 +211,18 @@ def __init__(self, physical_system, performance_test_flag = False): # Additionally, a DA object also needs to be created for the SNES solver # with a DOF of 1: # TODO: Remove the following hardcoded values - self.length_multiples_q1 = 1 - self.length_multiples_q2 = 1 - self.location_in_q3 = 10. - self.q3_3D_start = 0.; self.q3_3D_end = 20. + self.length_multiples_q1 = .5 + self.length_multiples_q2 = .25 self.dq3 = self.dq1 + self.location_in_q3 = 0.3 + self.q3_3D_start = 0.; self.q3_3D_end = 1.3 self.N_q1_poisson = (2*self.length_multiples_q1+1)*self.N_q1 self.N_q2_poisson = (2*self.length_multiples_q2+1)*self.N_q2 self.N_q3_poisson = (int)((self.q3_3D_end - self.q3_3D_start) / self.dq3) self.N_ghost_poisson = self.N_ghost - #self.N_ghost_poisson = 1 + PETSc.Sys.Print("dq3 = ", self.dq3, "N_q3 = ", self.N_q3_poisson) self._da_snes = PETSc.DMDA().create([self.N_q1_poisson, self.N_q2_poisson, self.N_q3_poisson], @@ -235,8 +235,8 @@ def __init__(self, physical_system, performance_test_flag = False): PETSc.DECIDE, 1 ), - stencil_type = 1, - dof = 1, + stencil_type = 0, # Star stencil + dof = 1, comm = self._comm ) self.snes = PETSc.SNES().create() diff --git a/bolt/lib/nonlinear_solver/timestep.py b/bolt/lib/nonlinear_solver/timestep.py index a0798421..7321b5a4 100644 --- a/bolt/lib/nonlinear_solver/timestep.py +++ b/bolt/lib/nonlinear_solver/timestep.py @@ -18,17 +18,7 @@ # Defining the operators: # When using FVM: def op_fvm_q(self, dt): - - if(self.performance_test_flag == True): - tic = af.time() - - fvm_timestep_RK2(self, dt) - if(self.performance_test_flag == True): - af.sync() - toc = af.time() - self.time_fvm_solver += toc - tic - # Solving for tau = 0 systems if(af.any_true(self.physical_system.params.tau(self.q1_center, self.q2_center, self.p1, self.p2, self.p3 @@ -44,12 +34,29 @@ def op_fvm_q(self, dt): self.physical_system.params, True ) + + fvm_timestep_RK2(self, dt) if(self.performance_test_flag == True): af.sync() toc = af.time() self.time_sourcets += toc - tic + af.eval(self.f) + return + + + if(self.performance_test_flag == True): + tic = af.time() + + fvm_timestep_RK2(self, dt) + + if(self.performance_test_flag == True): + af.sync() + toc = af.time() + self.time_fvm_solver += toc - tic + + af.eval(self.f) return @@ -68,34 +75,27 @@ def op_solve_src(self, dt): if(self.performance_test_flag == True): tic = af.time() -# # Solving for tau = 0 systems -# if(af.any_true(self.physical_system.params.tau(self.q1_center, self.q2_center, -# self.p1, self.p2, self.p3 -# ) == 0 -# ) -# ): -# self.f = self._source(self.f, self.q1_center, self.q2_center, -# self.p1, self.p2, self.p3, -# self.compute_moments, -# self.physical_system.params, -# True -# ) -# -# else: -# self.f = integrators.RK2(self._source, self.f, dt, -# self.q1_center, self.q2_center, -# self.p1, self.p2, self.p3, -# self.compute_moments, -# self.physical_system.params -# ) -# - self.f = integrators.RK2(self._source, self.f, dt, - self.q1_center, self.q2_center, - self.p1, self.p2, self.p3, - self.compute_moments, - self.physical_system.params - ) - + # Solving for tau = 0 systems + if(af.any_true(self.physical_system.params.tau(self.q1_center, self.q2_center, + self.p1, self.p2, self.p3 + ) == 0 + ) + ): + self.f = self._source(self.f, self.q1_center, self.q2_center, + self.p1, self.p2, self.p3, + self.compute_moments, + self.physical_system.params, + True + ) + + else: + self.f = integrators.RK2(self._source, self.f, dt, + self.q1_center, self.q2_center, + self.p1, self.p2, self.p3, + self.compute_moments, + self.physical_system.params + ) + if(self.performance_test_flag == True): af.sync() toc = af.time() diff --git a/bolt/src/electronic_boltzmann/advection_terms.py b/bolt/src/electronic_boltzmann/advection_terms.py index 6d132c54..a5fcfb5c 100644 --- a/bolt/src/electronic_boltzmann/advection_terms.py +++ b/bolt/src/electronic_boltzmann/advection_terms.py @@ -31,16 +31,8 @@ def A_p(q1, q2, p1, p2, p3, # dp2_dt = e*(E2 + (p3*B1 - p1*B3) / c) # p2 = hcross * k2 # dp3_dt = e*(E3 + (p1*B2 - p2*B1) / c) # p3 = hcross * k3 - dp1_dt = -e*E1 + 0.*p1**0. - dp2_dt = -e*E2 + 0.*p1**0. - dp3_dt = 0. + 0.*p1**0. + dp1_dt = -e*E1 + 0.*p1 + dp2_dt = -e*E2 + 0.*p1 + dp3_dt = 0. + 0.*p1 - #dp1_dt = 1e-5*e*0.5*(-af.tanh(100.*(q1 - 0.9)) - af.tanh(100.*(q1 - 0.1)) ) -# amplitude = 1e-3 -# E1_analytic = amplitude * -(q1 - 5.) -# dp1_dt = E1_analytic - - #E2_analytic = amplitude * -(q2 - 5.) - #dp2_dt = E2_analytic - 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 index dcca17a5..e8364b94 100644 --- a/bolt/src/electronic_boltzmann/collision_operator.py +++ b/bolt/src/electronic_boltzmann/collision_operator.py @@ -27,15 +27,15 @@ def f0_defect_constant_T(f, p1, p2, p3, params): af.eval(fermi_dirac) zeroth_moment = f - fermi_dirac - + eqn_mass_conservation = af.sum(zeroth_moment, 0) N_g = domain.N_ghost error_mass_conservation = af.max(af.abs(eqn_mass_conservation)[0, N_g:-N_g, N_g:-N_g]) - residual = [eqn_mass_conservation] - error_norm = np.max([af.max(af.abs(residual[0]))]) - print(" rank = ", params.rank, "||residual_defect|| = ", error_norm) + print(" rank = ", params.rank, + "||residual_defect|| = ", error_mass_conservation + ) res = eqn_mass_conservation dres_dmu = -a00 @@ -60,9 +60,9 @@ def f0_defect_constant_T(f, p1, p2, p3, params): N_g = domain.N_ghost error_mass_conservation = af.max(af.abs(eqn_mass_conservation)[0, N_g:-N_g, N_g:-N_g]) - residual = [eqn_mass_conservation] - error_norm = np.max([af.max(af.abs(residual[0]))]) - print(" rank = ", params.rank, "||residual_defect|| = ", error_norm) + print(" rank = ", params.rank, + "||residual_defect|| = ", error_mass_conservation + ) density_f = af.sum(f, 0) fermi_dirac = 1./(af.exp( (E_upper - mu)/(k*T) ) + 1.) diff --git a/example_problems/electronic_boltzmann/graphene/boundary_conditions.py b/example_problems/electronic_boltzmann/graphene/boundary_conditions.py index 5386f1bc..194eed48 100644 --- a/example_problems/electronic_boltzmann/graphene/boundary_conditions.py +++ b/example_problems/electronic_boltzmann/graphene/boundary_conditions.py @@ -12,12 +12,14 @@ def f_left(f, q1, q2, p1, p2, p3, params): k = params.boltzmann_constant E_upper = params.E_band - T = 0.*params.T + 3e-4*4. + T = params.T + mu = params.initial_mu + params.ephi_left_contact - fermi_dirac = (1./(af.exp( (E_upper - 0.*0.01)/(k*T) ) + 1.) + fermi_dirac = (1./(af.exp( (E_upper - mu)/(k*T) ) + 1.) ) - q2_contact_start = 2.5; q2_contact_end = 7.5 + q2_contact_start = params.contact_start + q2_contact_end = params.contact_end cond = ((q2 >= q2_contact_start) & \ (q2 <= q2_contact_end) \ ) @@ -32,12 +34,14 @@ def f_right(f, q1, q2, p1, p2, p3, params): k = params.boltzmann_constant E_upper = params.E_band - T = 0.*params.T + 3e-4*4. + T = params.T + mu = params.initial_mu + params.ephi_right_contact - fermi_dirac = (1./(af.exp( (E_upper - 0.*0.01)/(k*T) ) + 1.) + fermi_dirac = (1./(af.exp( (E_upper - mu)/(k*T) ) + 1.) ) - q2_contact_start = 2.5; q2_contact_end = 7.5 + q2_contact_start = params.contact_start + q2_contact_end = params.contact_end cond = ((q2 >= q2_contact_start) & \ (q2 <= q2_contact_end) \ ) diff --git a/example_problems/electronic_boltzmann/graphene/domain.py b/example_problems/electronic_boltzmann/graphene/domain.py index c02022ad..84d303a9 100644 --- a/example_problems/electronic_boltzmann/graphene/domain.py +++ b/example_problems/electronic_boltzmann/graphene/domain.py @@ -1,21 +1,21 @@ q1_start = 0. -q1_end = 10. -N_q1 = 35 +q1_end = 5. +N_q1 = 60 q2_start = 0. q2_end = 10. -N_q2 = 35 +N_q2 = 120 -p1_start = -0.01 -p1_end = 0.01 -N_p1 = 75 +p1_start = -0.08 +p1_end = 0.08 +N_p1 = 64 -p2_start = -0.01 -p2_end = 0.01 -N_p2 = 75 +p2_start = -0.08 +p2_end = 0.08 +N_p2 = 64 p3_start = -0.5 p3_end = 0.5 N_p3 = 1 -N_ghost = 3 +N_ghost = 2 diff --git a/example_problems/electronic_boltzmann/graphene/initialize.py b/example_problems/electronic_boltzmann/graphene/initialize.py index ea4e3f82..aef71ebe 100644 --- a/example_problems/electronic_boltzmann/graphene/initialize.py +++ b/example_problems/electronic_boltzmann/graphene/initialize.py @@ -10,11 +10,10 @@ def initialize_f(q1, q2, p1, p2, p3, params): PETSc.Sys.Print("Initializing f") - k = params.boltzmann_constant - params.mu = 0.*q1 + 0.*0.01 - params.T = 0.*q1 + 3e-4*4. + 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 diff --git a/example_problems/electronic_boltzmann/graphene/job_script b/example_problems/electronic_boltzmann/graphene/job_script index c99c662e..75c49d28 100644 --- a/example_problems/electronic_boltzmann/graphene/job_script +++ b/example_problems/electronic_boltzmann/graphene/job_script @@ -1,4 +1,4 @@ #!/bin/bash -#SBATCH -p gpu -n 1 --gres=gpu:1 -c1 --hint=nomultithread -t 2-00:00 +#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/main.py b/example_problems/electronic_boltzmann/graphene/main.py index e1111ac6..14d885c8 100644 --- a/example_problems/electronic_boltzmann/graphene/main.py +++ b/example_problems/electronic_boltzmann/graphene/main.py @@ -1,3 +1,4 @@ +import sys import arrayfire as af import numpy as np import pylab as pl @@ -24,34 +25,34 @@ import bolt.src.electronic_boltzmann.moment_defs as moment_defs -#pl.rcParams['figure.figsize'] = 12, 7.5 -#pl.rcParams['figure.dpi'] = 150 -#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'] = 20 -#pl.rcParams['font.sans-serif'] = 'serif' -#pl.rcParams['text.usetex'] = False -#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' +pl.rcParams['figure.figsize'] = 6, 7.5 +pl.rcParams['figure.dpi'] = 150 +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'] = 20 +pl.rcParams['font.sans-serif'] = 'serif' +pl.rcParams['text.usetex'] = False +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' # Defining the physical system to be solved: @@ -64,46 +65,141 @@ moment_defs ) +# Time parameters: +dt = params.dt +t_final = params.t_final +t0 = 0.0 # current time +params.time_step = time_step = 0 + +N_g = domain.N_ghost + # Declaring a nonlinear system object which will evolve the defined physical system: nls = nonlinear_solver(system) -n_nls = nls.compute_moments('density') - params.rank = nls._comm.rank -# Time parameters: -#dt = 0.002*100 -dt = 1e-3 -t_final = 1000. +if (params.restart): + nls.load_distribution_function(params.restart_file) -time_array = np.arange(dt, t_final + dt, dt) -nls.f = af.select(nls.f < 1e-13, 1e-13, nls.f) -compute_electrostatic_fields(nls) + viewer = PETSc.Viewer().createHDF5(params.phi_restart_file, + PETSc.Viewer.Mode.READ, + comm=nls._comm + ) + PETSc.Object.setName(nls.poisson.glob_phi, 'phi') + nls.poisson.glob_phi.load(viewer) -N_g = domain.N_ghost + params.solve_for_equilibrium = 0 + compute_electrostatic_fields(nls) + + params.mu = params.global_chem_potential + params.charge_electron*params.phi + params.mu_analytic = params.global_chem_potential + params.charge_electron*params.phi + params.mu = af.moddims(params.mu, + 1, + nls.N_q1_local + 2*N_g, + nls.N_q2_local + 2*N_g + ) +else: + if (params.solve_for_equilibrium): + PETSc.Sys.Print("=============================") + PETSc.Sys.Print("Solving for equilibrium state") + PETSc.Sys.Print("=============================") + params.solve_for_equilibrium = 1 + compute_electrostatic_fields(nls) + params.solve_for_equilibrium = 0 + + params.mu = params.global_chem_potential + params.charge_electron*params.phi + params.mu = af.moddims(params.mu, + 1, + nls.N_q1_local + 2*N_g, + nls.N_q2_local + 2*N_g + ) + + nls.f = params.fermi_dirac(params.mu, params.E_band) + + PETSc.Sys.Print("=====================") + PETSc.Sys.Print("Solution diagnostics:") + PETSc.Sys.Print("=====================") + + density = nls.compute_moments('density') + print("rank = ", params.rank, "\n", + " = ", af.mean(params.mu[0, N_g:-N_g, N_g:-N_g]), "\n", + " max(mu) = ", af.max(params.mu[0, N_g:-N_g, N_g:-N_g]), "\n", + " = ", af.mean(params.phi[N_g:-N_g, N_g:-N_g]), "\n", + " = ", af.mean(density[0, N_g:-N_g, N_g:-N_g]), "\n", + " max(n) = ", af.max(density[0, N_g:-N_g, N_g:-N_g]), "\n", + " |E1| = ", af.mean(af.abs(nls.cell_centered_EM_fields[0, N_g:-N_g, N_g:-N_g])), + "\n", + " |E2| = ", af.mean(af.abs(nls.cell_centered_EM_fields[1, N_g:-N_g, N_g:-N_g])) + ) + + PETSc.Sys.Print("===============") + PETSc.Sys.Print("Dumping data...") + PETSc.Sys.Print("===============") + + nls.dump_moments('dumps/density_eqbm') + nls.dump_distribution_function('dumps/f_eqbm') + + # Dump EM fields + af.flat(nls.cell_centered_EM_fields[:, N_g:-N_g, N_g:-N_g]).to_ndarray(nls._glob_fields_array) + PETSc.Object.setName(nls._glob_fields, 'fields') + viewer = PETSc.Viewer().createHDF5('dumps/fields_eqbm.h5', + 'w', comm=nls._comm + ) + viewer(nls._glob_fields) + + # Dump eqbm potential + PETSc.Object.setName(nls.poisson.glob_phi, 'phi') + viewer = PETSc.Viewer().createHDF5('dumps/phi_eqbm.h5', + 'w', comm=nls._comm + ) + viewer(nls.poisson.glob_phi) + + sys.exit("Terminating execution") + else: + + compute_electrostatic_fields(nls) -print("rank = ", nls._comm.rank, " params.rank = ", params.rank, - "mu = ", af.mean(params.mu[0, N_g:-N_g, N_g:-N_g]), - "phi = ", af.mean(params.phi[N_g:-N_g, N_g:-N_g]), - "density = ", af.mean(n_nls[0, N_g:-N_g, N_g:-N_g]), - "|E1| = ", af.mean(af.abs(nls.cell_centered_EM_fields[0, N_g:-N_g, N_g:-N_g])), - "|E2| = ", af.mean(af.abs(nls.cell_centered_EM_fields[1, N_g:-N_g, N_g:-N_g])) +density = nls.compute_moments('density') +print("rank = ", params.rank, "\n", + " = ", af.mean(params.mu[0, N_g:-N_g, N_g:-N_g]), "\n", + " max(mu) = ", af.max(params.mu[0, N_g:-N_g, N_g:-N_g]), "\n", + " = ", af.mean(params.phi[N_g:-N_g, N_g:-N_g]), "\n", + " = ", af.mean(density[0, N_g:-N_g, N_g:-N_g]), "\n", + " max(n) = ", af.max(density[0, N_g:-N_g, N_g:-N_g]), "\n", + " |E1| = ", af.mean(af.abs(nls.cell_centered_EM_fields[0, N_g:-N_g, N_g:-N_g])), + "\n", + " |E2| = ", af.mean(af.abs(nls.cell_centered_EM_fields[1, N_g:-N_g, N_g:-N_g])) ) -t0 = 0.0 -params.time_step = time_step = 0 +nls.f = af.select(nls.f < 1e-20, 1e-20, nls.f) while t0 < t_final: - dump_steps = 1000 + # 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 (time_step%dump_steps==0): - nls.dump_moments('dumps/density_' + '%06d'%(time_step/dump_steps)) - nls.dump_distribution_function('dumps/f_' + '%06d'%(time_step/dump_steps)) + file_number = '%06d'%(time_step/dump_steps) + PETSc.Sys.Print("====================================================") + PETSc.Sys.Print("Dumping data at time step =", time_step, + ", file number =", file_number + ) + PETSc.Sys.Print("====================================================") + nls.dump_moments('dumps/density_' + file_number) + nls.dump_distribution_function('dumps/f_' + file_number) # Dump EM fields af.flat(nls.cell_centered_EM_fields[:, N_g:-N_g, N_g:-N_g]).to_ndarray(nls._glob_fields_array) PETSc.Object.setName(nls._glob_fields, 'fields') - viewer = PETSc.Viewer().createHDF5('dumps/fields_' + '%06d'%(time_step/dump_steps) + '.h5', 'w', comm=nls._comm) + viewer = PETSc.Viewer().createHDF5('dumps/fields_' + + '%06d'%(time_step/dump_steps) + '.h5', + 'w', comm=nls._comm + ) viewer(nls._glob_fields) + dt_force_constraint = 0. # dt_force_constraint = \ # 0.5 * np.min(nls.dp1, nls.dp2) \ @@ -112,21 +208,18 @@ # ) # ) - dt_collision_constraint = 1e-4 - #dt = np.min(dt_force_constraint, dt_collision_constraint) + PETSc.Sys.Print("Time step =", time_step, ", Time =", t0) - PETSc.Sys.Print("Time step =", time_step, ", Time =", t0, " dt = ", - dt_force_constraint - ) - - mean_density = af.mean(n_nls[0, N_g:-N_g, N_g:-N_g]) - density_pert = n_nls - mean_density + mean_density = af.mean(density[0, N_g:-N_g, N_g:-N_g]) + density_pert = density - mean_density -# if (time_step%1==0): -# pl.contourf(np.array(nls.q1_center)[0, :, :], \ -# np.array(nls.q2_center)[0, :, :], \ -# np.array(params.mu)[0, :, :], \ + if (time_step%1==0): +# chemical_potential = np.array(params.mu)[0, :, :] \ +# - params.charge_electron*np.array(params.phi)[:, :] +# pl.contourf(np.array(nls.q1_center)[0, N_g:-N_g, N_g:-N_g], \ +# np.array(nls.q2_center)[0, N_g:-N_g, N_g:-N_g], \ +# np.array(params.mu)[0, N_g:-N_g, N_g:-N_g], \ # 100, cmap='bwr' # ) # pl.title('Time = ' + "%.2f"%(t0) ) @@ -135,11 +228,37 @@ # pl.colorbar() # pl.gca().set_aspect('equal') # pl.savefig('/tmp/mu_' + '%06d'%time_step + '.png' ) +# pl.clf() + + pl.contourf(np.array(nls.q1_center)[0, N_g:-N_g, N_g:-N_g], \ + np.array(nls.q2_center)[0, N_g:-N_g, N_g:-N_g], \ + np.array(density)[0, N_g:-N_g, N_g:-N_g], \ + 100, cmap='bwr' + ) + pl.title('Time = ' + "%.2f"%(t0) ) + pl.xlabel('$x$') + pl.ylabel('$y$') + pl.colorbar() + pl.gca().set_aspect('equal') + pl.savefig('/tmp/density_' + '%06d'%time_step + '.png' ) + pl.clf() + +# pl.contourf(np.array(nls.q1_center)[0, N_g:-N_g, N_g:-N_g], \ +# np.array(nls.q2_center)[0, N_g:-N_g, N_g:-N_g], \ +# np.array(params.phi)[N_g:-N_g, N_g:-N_g], \ +# 100, cmap='bwr' +# ) +# pl.title('Time = ' + "%.2f"%(t0) ) +# pl.xlabel('$x$') +# pl.ylabel('$y$') +# pl.colorbar() +# pl.gca().set_aspect('equal') +# pl.savefig('/tmp/phi_' + '%06d'%time_step + '.png' ) # pl.clf() # -# pl.contourf(np.array(nls.q1_center)[0, :, :], \ -# np.array(nls.q2_center)[0, :, :], \ -# np.array(nls.cell_centered_EM_fields)[0, :, :], \ +# pl.contourf(np.array(nls.q1_center)[0, N_g:-N_g, N_g:-N_g], \ +# np.array(nls.q2_center)[0, N_g:-N_g, N_g:-N_g], \ +# np.array(nls.cell_centered_EM_fields)[0, N_g:-N_g, N_g:-N_g], \ # 100, cmap='bwr' # ) # pl.title('Time = ' + "%.2f"%(t0) ) @@ -150,9 +269,9 @@ # pl.savefig('/tmp/E1_' + '%06d'%time_step + '.png' ) # pl.clf() # -# pl.contourf(np.array(nls.q1_center)[0, :, :], \ -# np.array(nls.q2_center)[0, :, :], \ -# np.array(nls.cell_centered_EM_fields)[1, :, :], \ +# pl.contourf(np.array(nls.q1_center)[0, N_g:-N_g, N_g:-N_g], \ +# np.array(nls.q2_center)[0, N_g:-N_g, N_g:-N_g], \ +# np.array(nls.cell_centered_EM_fields)[1, N_g:-N_g, N_g:-N_g], \ # 100, cmap='bwr' # ) # pl.title('Time = ' + "%.2f"%(t0) ) @@ -163,7 +282,7 @@ # pl.savefig('/tmp/E2_' + '%06d'%time_step + '.png' ) # pl.clf() # -# f_at_desired_q = af.moddims(nls.f[:, N_g, N_g + nls.N_q2/2], +# f_at_desired_q = af.moddims(nls.f[:, N_g, N_g + 0.*nls.N_q2/2], # nls.N_p1, nls.N_p2 # ) # p1 = af.moddims(nls.p1, nls.N_p1, nls.N_p2) @@ -187,18 +306,18 @@ t0 = t0 + dt # Floors - #nls.f = af.select(nls.f < 1e-13, 1e-13, nls.f) - #params.mu = af.select(params.mu < 1e-25, 1e-25, params.mu) - - n_nls = nls.compute_moments('density') - print("rank = ", nls._comm.rank, - "mu = ", af.mean(params.mu[0, N_g:-N_g, N_g:-N_g]), - "phi = ", af.mean(params.phi[N_g:-N_g, N_g:-N_g]), - "density = ", mean_density, - "|E1| = ", af.mean(af.abs(nls.cell_centered_EM_fields[0, N_g:-N_g, N_g:-N_g])), - "|E2| = ", af.mean(af.abs(nls.cell_centered_EM_fields[1, N_g:-N_g, N_g:-N_g])), - "q1 = ", np.array(nls.q1_center[0, N_g, 0])[0], "q2 = ", np.array(nls.q2_center[0, 0, N_g])[0], - "N_q1_local= ", nls.N_q1_local, "N_q2_local = ", nls.N_q2_local + 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, N_g:-N_g, N_g:-N_g]), "\n", + " max(mu) = ", af.max(params.mu[0, N_g:-N_g, N_g:-N_g]), "\n", + " = ", af.mean(params.phi[N_g:-N_g, N_g:-N_g]), "\n", + " = ", af.mean(density[0, N_g:-N_g, N_g:-N_g]), "\n", + " max(n) = ", af.max(density[0, N_g:-N_g, N_g:-N_g]), "\n", + " |E1| = ", af.mean(af.abs(nls.cell_centered_EM_fields[0, N_g:-N_g, N_g:-N_g])), + "\n", + " |E2| = ", af.mean(af.abs(nls.cell_centered_EM_fields[1, N_g:-N_g, N_g:-N_g])) ) PETSc.Sys.Print("--------------------\n") @@ -207,6 +326,8 @@ # nls.poisson.N_q2_3D_local, \ # nls.poisson.N_q1_3D_local] # ) +# +#q3_index = np.where(nls.poisson.q3_3D[N_g:-N_g] >= nls.location_in_q3)[0][0] #pl.rcParams['figure.figsize'] = 20, 7.5 #pl.subplot(121) #N_g = domain.N_ghost diff --git a/example_problems/electronic_boltzmann/graphene/params.py b/example_problems/electronic_boltzmann/graphene/params.py index d4a46cef..fdac6c61 100644 --- a/example_problems/electronic_boltzmann/graphene/params.py +++ b/example_problems/electronic_boltzmann/graphene/params.py @@ -18,38 +18,49 @@ solver_method_in_q = 'FVM' solver_method_in_p = 'FVM' -reconstruction_method_in_q = 'weno5' -reconstruction_method_in_p = 'weno5' +reconstruction_method_in_q = 'minmod' +reconstruction_method_in_p = 'minmod' riemann_solver = 'upwind-flux' # Restart(Set to zero for no-restart): -t_restart = 0 +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' # File-writing Parameters: -# Set to zero for no file-writing -dt_dump_f = 0.1 -dt_dump_moments = 0.01 +dump_steps = 1000 # Time parameters: -N_cfl = 0.45 -t_final = 10 +dt = 0.1 +t_final = 1000 # Dimensionality considered in velocity space: p_dim = 2 # Number of devices(GPUs/Accelerators) on each node: -num_devices = 6 +num_devices = 4 # Constants: mass_particle = 0.910938356 # x 1e-30 kg h_bar = 1.0545718e-4 # x aJ ps boltzmann_constant = 1 -charge_electron = -0.160217662 # x aC +charge_electron = 0.*-0.160217662 # x aC 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 + +initial_temperature = 12e-4 +initial_mu = 0.015 +ephi_left_contact = 1e-10 +ephi_right_contact = -1e-10 + # 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 @@ -63,13 +74,14 @@ E_band = None vel_band = None -collision_nonlinear_iters = 3 -electrostatic_solver_step = 10000 +collision_operator_nonlinear_iters = 2 +electrostatic_solver_every_nth_step = 1000000 +solve_for_equilibrium = 0 # Variation of collisional-timescale parameter through phase space: @af.broadcast def tau_defect(q1, q2, p1, p2, p3): - return(1e-3 * q1**0 * p1**0) + return(0. * q1**0 * p1**0) @af.broadcast def tau_ee(q1, q2, p1, p2, p3): @@ -99,3 +111,17 @@ def band_velocity(p_x, p_y): 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) From f1fc67a65a69cb932766d59aa482f7facf140eea Mon Sep 17 00:00:00 2001 From: Mani Chandra Date: Mon, 5 Feb 2018 19:36:01 +0530 Subject: [PATCH 21/28] ee operator modified to work with current data layout --- .../collision_operator.py | 105 +++++++++--------- .../graphene/boundary_conditions.py | 16 ++- .../electronic_boltzmann/graphene/domain.py | 12 +- .../electronic_boltzmann/graphene/main.py | 7 +- .../electronic_boltzmann/graphene/params.py | 15 +-- 5 files changed, 83 insertions(+), 72 deletions(-) diff --git a/bolt/src/electronic_boltzmann/collision_operator.py b/bolt/src/electronic_boltzmann/collision_operator.py index e8364b94..9c0e98c5 100644 --- a/bolt/src/electronic_boltzmann/collision_operator.py +++ b/bolt/src/electronic_boltzmann/collision_operator.py @@ -63,16 +63,9 @@ def f0_defect_constant_T(f, p1, p2, p3, params): print(" rank = ", params.rank, "||residual_defect|| = ", error_mass_conservation ) - - density_f = af.sum(f, 0) - fermi_dirac = 1./(af.exp( (E_upper - mu)/(k*T) ) + 1.) - density_fermi_dirac = af.sum(fermi_dirac, 0) - print(" rank = ", params.rank, "mu = ", af.mean(params.mu[0, N_g:-N_g, N_g:-N_g]), - "T = ", af.mean(params.T[0, N_g:-N_g, N_g:-N_g]), - "density_f = ", af.mean(density_f[0, N_g:-N_g, N_g:-N_g]), - "density_fermi_dirac = ",af.mean(density_fermi_dirac[0, N_g:-N_g, N_g:-N_g]) + "T = ", af.mean(params.T[0, N_g:-N_g, N_g:-N_g]) ) PETSc.Sys.Print(" ------------------") @@ -164,14 +157,8 @@ def f0_defect(f, p1, p2, p3, params): af.max(af.abs(residual[1]))] ) print(" ||residual_defect|| = ", error_norm) - density_f = af.sum(f, 0) - fermi_dirac = 1./(af.exp( (E_upper - mu)/(k*T) ) + 1.) - density_fermi_dirac = af.sum(fermi_dirac, 0) - print(" mu = ", af.mean(params.mu[0, N_g:-N_g, N_g:-N_g]), - "T = ", af.mean(params.T[0, N_g:-N_g, N_g:-N_g]), - "density_f = ", af.mean(density_f[0, N_g:-N_g, N_g:-N_g]), - "density_fermi_dirac = ",af.mean(density_fermi_dirac[0, N_g:-N_g, N_g:-N_g]) + "T = ", af.mean(params.T[0, N_g:-N_g, N_g:-N_g]) ) print(" ------------------") @@ -185,11 +172,10 @@ def f0_ee(f, p1, p2, p3, params): T_ee = params.T_ee vel_drift_x = params.vel_drift_x vel_drift_y = params.vel_drift_y - phi = 0.*params.charge_electron * params.phi for n in range(params.collision_nonlinear_iters): - E_upper = params.E_band + phi + E_upper = params.E_band k = params.boltzmann_constant tmp1 = (E_upper - mu_ee - p1*vel_drift_x - p2*vel_drift_y) @@ -204,25 +190,25 @@ def f0_ee(f, p1, p2, p3, params): af.eval(a_0, a_1, a_2, a_3) # TODO: Multiply with the integral measure dp1 * dp2 - a_00 = af.sum(a_0, 2) - a_01 = af.sum(a_1, 2) - a_02 = af.sum(a_2, 2) - a_03 = af.sum(a_3, 2) - - a_10 = af.sum(E_upper * a_0, 2) - a_11 = af.sum(E_upper * a_1, 2) - a_12 = af.sum(E_upper * a_2, 2) - a_13 = af.sum(E_upper * a_3, 2) - - a_20 = af.sum(p1 * a_0, 2) - a_21 = af.sum(p1 * a_1, 2) - a_22 = af.sum(p1 * a_2, 2) - a_23 = af.sum(p1 * a_3, 2) - - a_30 = af.sum(p2 * a_0, 2) - a_31 = af.sum(p2 * a_1, 2) - a_32 = af.sum(p2 * a_2, 2) - a_33 = af.sum(p2 * a_3, 2) + a_00 = af.sum(a_0, 0) + a_01 = af.sum(a_1, 0) + a_02 = af.sum(a_2, 0) + a_03 = af.sum(a_3, 0) + + 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 = af.sum(p1 * a_0, 0) + a_21 = af.sum(p1 * a_1, 0) + a_22 = af.sum(p1 * a_2, 0) + a_23 = af.sum(p1 * a_3, 0) + + a_30 = af.sum(p2 * a_0, 0) + a_31 = af.sum(p2 * a_1, 0) + a_32 = af.sum(p2 * a_2, 0) + a_33 = af.sum(p2 * a_3, 0) A = [ [a_00, a_01, a_02, a_03], \ [a_10, a_11, a_12, a_13], \ @@ -242,10 +228,10 @@ def f0_ee(f, p1, p2, p3, params): first_moment_x = p1*(f - fermi_dirac) first_moment_y = p2*(f - fermi_dirac) - eqn_mass_conservation = af.sum(zeroth_moment, 2) - eqn_energy_conservation = af.sum(second_moment, 2) - eqn_mom_x_conservation = af.sum(first_moment_x, 2) - eqn_mom_y_conservation = af.sum(first_moment_y, 2) + eqn_mass_conservation = af.sum(zeroth_moment, 0) + eqn_energy_conservation = af.sum(second_moment, 0) + eqn_mom_x_conservation = af.sum(first_moment_x, 0) + eqn_mom_y_conservation = af.sum(first_moment_y, 0) residual = [eqn_mass_conservation, \ eqn_energy_conservation, \ @@ -258,10 +244,16 @@ def f0_ee(f, p1, p2, p3, params): af.max(af.abs(residual[3])) ] ) - print(" ||residual_ee|| = ", error_norm) + print(" rank = ", params.rank, + "||residual_ee|| = ", error_norm + ) - if (error_norm < 1e-13): - return(fermi_dirac) +# 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 @@ -311,10 +303,10 @@ def f0_ee(f, p1, p2, p3, params): first_moment_x = p1*(f - fermi_dirac) first_moment_y = p2*(f - fermi_dirac) - eqn_mass_conservation = af.sum(zeroth_moment, 2) - eqn_energy_conservation = af.sum(second_moment, 2) - eqn_mom_x_conservation = af.sum(first_moment_x, 2) - eqn_mom_y_conservation = af.sum(first_moment_y, 2) + eqn_mass_conservation = af.sum(zeroth_moment, 0) + eqn_energy_conservation = af.sum(second_moment, 0) + eqn_mom_x_conservation = af.sum(first_moment_x, 0) + eqn_mom_y_conservation = af.sum(first_moment_y, 0) residual = [eqn_mass_conservation, \ eqn_energy_conservation, \ @@ -328,8 +320,17 @@ def f0_ee(f, p1, p2, p3, params): af.max(af.abs(residual[3])) ] ) - print(" ||residual_ee|| = ", error_norm) - print(" ------------------") + 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, N_g:-N_g, N_g:-N_g]), + "T_ee = ", af.mean(params.T_ee[0, N_g:-N_g, N_g:-N_g]), + " = ", af.mean(params.vel_drift_x[0, N_g:-N_g, N_g:-N_g]), + " = ", af.mean(params.vel_drift_y[0, N_g:-N_g, N_g:-N_g]) + ) + PETSc.Sys.Print(" ------------------") return(fermi_dirac) @@ -344,10 +345,10 @@ def RTA(f, q1, q2, p1, p2, p3, moments, params, flag = False): return(f) - C_f = -( f - f0_defect_constant_T(f, p1, p2, p3, params) + C_f = -( f - f0_defect_constant_T(f, p1, p2, p3, params) \ ) / params.tau_defect(q1, q2, p1, p2, p3) \ -# -( f - f0_ee(f, p1, p2, p3, params) -# ) / params.tau_ee(q1, q2, p1, p2, p3) + -( f - f0_ee(f, p1, p2, p3, params) + ) / params.tau_ee(q1, q2, p1, p2, p3) # When (f - f0) is NaN. Dividing by np.inf doesn't give 0 # WORKAROUND: C_f = af.select(params.tau_defect(q1, q2, p1, p2, p3) == np.inf, 0, C_f) diff --git a/example_problems/electronic_boltzmann/graphene/boundary_conditions.py b/example_problems/electronic_boltzmann/graphene/boundary_conditions.py index 194eed48..06e47a98 100644 --- a/example_problems/electronic_boltzmann/graphene/boundary_conditions.py +++ b/example_problems/electronic_boltzmann/graphene/boundary_conditions.py @@ -12,10 +12,12 @@ def f_left(f, q1, q2, p1, p2, p3, params): k = params.boltzmann_constant E_upper = params.E_band - T = params.T - mu = params.initial_mu + params.ephi_left_contact + T = params.initial_temperature + mu = params.initial_mu + + vel_drift_x = params.vel_drift_x_in - fermi_dirac = (1./(af.exp( (E_upper - mu)/(k*T) ) + 1.) + fermi_dirac = (1./(af.exp( (E_upper - vel_drift_x*p1 - mu)/(k*T) ) + 1.) ) q2_contact_start = params.contact_start @@ -34,10 +36,12 @@ def f_right(f, q1, q2, p1, p2, p3, params): k = params.boltzmann_constant E_upper = params.E_band - T = params.T - mu = params.initial_mu + params.ephi_right_contact + T = params.initial_temperature + mu = params.initial_mu + + vel_drift_x = params.vel_drift_x_out - fermi_dirac = (1./(af.exp( (E_upper - mu)/(k*T) ) + 1.) + fermi_dirac = (1./(af.exp( (E_upper - vel_drift_x*p1 - mu)/(k*T) ) + 1.) ) q2_contact_start = params.contact_start diff --git a/example_problems/electronic_boltzmann/graphene/domain.py b/example_problems/electronic_boltzmann/graphene/domain.py index 84d303a9..36ff4b4c 100644 --- a/example_problems/electronic_boltzmann/graphene/domain.py +++ b/example_problems/electronic_boltzmann/graphene/domain.py @@ -6,13 +6,13 @@ q2_end = 10. N_q2 = 120 -p1_start = -0.08 -p1_end = 0.08 -N_p1 = 64 +p1_start = -0.04 +p1_end = 0.04 +N_p1 = 32 -p2_start = -0.08 -p2_end = 0.08 -N_p2 = 64 +p2_start = -0.04 +p2_end = 0.04 +N_p2 = 32 p3_start = -0.5 p3_end = 0.5 diff --git a/example_problems/electronic_boltzmann/graphene/main.py b/example_problems/electronic_boltzmann/graphene/main.py index 14d885c8..3ac5bffc 100644 --- a/example_problems/electronic_boltzmann/graphene/main.py +++ b/example_problems/electronic_boltzmann/graphene/main.py @@ -25,7 +25,7 @@ import bolt.src.electronic_boltzmann.moment_defs as moment_defs -pl.rcParams['figure.figsize'] = 6, 7.5 +pl.rcParams['figure.figsize'] = 12, 7.5 pl.rcParams['figure.dpi'] = 150 pl.rcParams['image.cmap'] = 'jet' pl.rcParams['lines.linewidth'] = 1.5 @@ -328,6 +328,11 @@ # ) # #q3_index = np.where(nls.poisson.q3_3D[N_g:-N_g] >= nls.location_in_q3)[0][0] +#pl.plot(nls.poisson.q1_3D[N_g:-N_g], +# phi_array[q3_index, nls.poisson.N_q2_3D_local/2, :], 'o-' +# ) +#pl.show() + #pl.rcParams['figure.figsize'] = 20, 7.5 #pl.subplot(121) #N_g = domain.N_ghost diff --git a/example_problems/electronic_boltzmann/graphene/params.py b/example_problems/electronic_boltzmann/graphene/params.py index fdac6c61..a9408f0e 100644 --- a/example_problems/electronic_boltzmann/graphene/params.py +++ b/example_problems/electronic_boltzmann/graphene/params.py @@ -27,12 +27,15 @@ 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 = 1000 # Time parameters: -dt = 0.1 +dt = 0.05 t_final = 1000 # Dimensionality considered in velocity space: @@ -58,8 +61,8 @@ initial_temperature = 12e-4 initial_mu = 0.015 -ephi_left_contact = 1e-10 -ephi_right_contact = -1e-10 +vel_drift_x_in = 1e-7*fermi_velocity +vel_drift_x_out = 1e-7*fermi_velocity # Spatial quantities (will be initialized to shape = [q1, q2] in initalize.py) mu = None # chemical potential used in the e-ph operator @@ -75,17 +78,15 @@ vel_band = None collision_operator_nonlinear_iters = 2 -electrostatic_solver_every_nth_step = 1000000 -solve_for_equilibrium = 0 # Variation of collisional-timescale parameter through phase space: @af.broadcast def tau_defect(q1, q2, p1, p2, p3): - return(0. * q1**0 * p1**0) + return(np.inf * q1**0 * p1**0) @af.broadcast def tau_ee(q1, q2, p1, p2, p3): - return(np.inf * q1**0 * p1**0) + return(1. * q1**0 * p1**0) def tau(q1, q2, p1, p2, p3): return(tau_defect(q1, q2, p1, p2, p3)) From be12f7faf49fb2351c2610e13091c3c999aaf5ea Mon Sep 17 00:00:00 2001 From: Mani Chandra Date: Tue, 6 Feb 2018 17:46:18 +0530 Subject: [PATCH 22/28] (1) Added dump routines for Lagrange multipliers. (2) Added currents to moment calculations and checked that j_x = \int p_x f = n , where is the drift vel obtained from ee collision operator. --- bolt/lib/nonlinear_solver/file_io/dump.py | 31 ++++ bolt/lib/nonlinear_solver/nonlinear_solver.py | 3 + bolt/src/electronic_boltzmann/moment_defs.py | 10 +- .../electronic_boltzmann/graphene/main.py | 15 +- .../electronic_boltzmann/graphene/params.py | 2 +- .../electronic_boltzmann/graphene/post.py | 168 +++++++++++++----- 6 files changed, 173 insertions(+), 56 deletions(-) diff --git a/bolt/lib/nonlinear_solver/file_io/dump.py b/bolt/lib/nonlinear_solver/file_io/dump.py index 9b67706b..0ec6484a 100644 --- a/bolt/lib/nonlinear_solver/file_io/dump.py +++ b/bolt/lib/nonlinear_solver/file_io/dump.py @@ -5,6 +5,37 @@ import numpy as np import arrayfire as af +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().createHDF5(file_name + '.h5', 'w', comm=self._comm) + viewer(self._glob_aux) + def dump_moments(self, file_name): """ This function is used to dump variables to a file for later usage. diff --git a/bolt/lib/nonlinear_solver/nonlinear_solver.py b/bolt/lib/nonlinear_solver/nonlinear_solver.py index 76b75fcd..98b0e570 100644 --- a/bolt/lib/nonlinear_solver/nonlinear_solver.py +++ b/bolt/lib/nonlinear_solver/nonlinear_solver.py @@ -267,6 +267,8 @@ def __init__(self, physical_system, performance_test_flag = False): ), 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 @@ -626,6 +628,7 @@ def _initialize(self, params): dump_distribution_function = dump.dump_distribution_function dump_moments = dump.dump_moments + dump_aux_arrays = dump.dump_aux_arrays load_distribution_function = load.load_distribution_function print_performance_timings = print_table diff --git a/bolt/src/electronic_boltzmann/moment_defs.py b/bolt/src/electronic_boltzmann/moment_defs.py index 03c8506f..9ac8c96e 100644 --- a/bolt/src/electronic_boltzmann/moment_defs.py +++ b/bolt/src/electronic_boltzmann/moment_defs.py @@ -1,6 +1,12 @@ import numpy as np import params -moment_exponents = dict(density = [0, 0, 0]) +moment_exponents = dict(density = [0, 0, 0], + j_x = [1, 0, 0], + j_y = [0, 1, 0] + ) -moment_coeffs = dict(density = [4./(2.*np.pi*params.h_bar)**2., 0, 0]) +moment_coeffs = dict(density = [4./(2.*np.pi*params.h_bar)**2., 0, 0], + j_x = [4./(2.*np.pi*params.h_bar)**2., 0, 0], + j_y = [0, 4./(2.*np.pi*params.h_bar)**2., 0] + ) diff --git a/example_problems/electronic_boltzmann/graphene/main.py b/example_problems/electronic_boltzmann/graphene/main.py index 3ac5bffc..c2177265 100644 --- a/example_problems/electronic_boltzmann/graphene/main.py +++ b/example_problems/electronic_boltzmann/graphene/main.py @@ -135,7 +135,7 @@ PETSc.Sys.Print("Dumping data...") PETSc.Sys.Print("===============") - nls.dump_moments('dumps/density_eqbm') + nls.dump_moments('dumps/moments_eqbm') nls.dump_distribution_function('dumps/f_eqbm') # Dump EM fields @@ -182,13 +182,20 @@ dump_steps = params.dump_steps if (time_step%dump_steps==0): file_number = '%06d'%(time_step/dump_steps) - PETSc.Sys.Print("====================================================") + PETSc.Sys.Print("=====================================================") PETSc.Sys.Print("Dumping data at time step =", time_step, ", file number =", file_number ) - PETSc.Sys.Print("====================================================") - nls.dump_moments('dumps/density_' + file_number) + PETSc.Sys.Print("=====================================================") + nls.dump_moments('dumps/moments_' + 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], + 'lagrange_multipliers', + 'dumps/lagrange_multipliers_' + file_number + ) # Dump EM fields af.flat(nls.cell_centered_EM_fields[:, N_g:-N_g, N_g:-N_g]).to_ndarray(nls._glob_fields_array) diff --git a/example_problems/electronic_boltzmann/graphene/params.py b/example_problems/electronic_boltzmann/graphene/params.py index a9408f0e..b78d13a4 100644 --- a/example_problems/electronic_boltzmann/graphene/params.py +++ b/example_problems/electronic_boltzmann/graphene/params.py @@ -32,7 +32,7 @@ # File-writing Parameters: -dump_steps = 1000 +dump_steps = 10 # Time parameters: dt = 0.05 diff --git a/example_problems/electronic_boltzmann/graphene/post.py b/example_problems/electronic_boltzmann/graphene/post.py index 82738f74..85dcfa25 100644 --- a/example_problems/electronic_boltzmann/graphene/post.py +++ b/example_problems/electronic_boltzmann/graphene/post.py @@ -1,10 +1,34 @@ +import arrayfire as af import numpy as np +import glob import h5py -import domain -import params import matplotlib 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 @@ -36,10 +60,6 @@ pl.rcParams['ytick.labelsize'] = 'medium' pl.rcParams['ytick.direction'] = 'in' -#time = np.arange(0, params.t_final + params.dt_dump_moments, -# params.dt_dump_moments -# ) - N_q1 = domain.N_q1 N_q2 = domain.N_q2 N_g = domain.N_ghost @@ -49,49 +69,99 @@ q2, q1 = np.meshgrid(q2, q1) -#dump_index = 000424 -#h5f = h5py.File('dumps/density_' + str(dump_index) + '.h5', 'r') -h5f = h5py.File('dumps/density_000030.h5', 'r') -moments = np.swapaxes(h5f['moments'][:], 0, 1) -h5f.close() - -density = moments[:, :] -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.savefig('images/%04d'%time_index + '.png') -pl.clf() - - -h5f = h5py.File('dumps/fields_000030.h5', 'r') -fields = np.swapaxes(h5f['fields'][:], 0, 1) -h5f.close() - -E1 = fields[:, :, 0] -E2 = fields[:, :, 1] - -pl.figure(figsize=(20, 7.5)) -pl.subplot(121) -pl.contourf(q1, q2, E1, 100, cmap='bwr') -pl.title('$E_1$') -pl.xlabel(r'$x$') -pl.ylabel(r'$y$') -pl.colorbar() -pl.gca().set_aspect('equal') - -pl.subplot(122) -pl.contourf(q1, q2, E2, 100, cmap='bwr') -pl.title('$E_2$') -pl.xlabel(r'$x$') -pl.ylabel(r'$y$') -pl.colorbar() -pl.gca().set_aspect('equal') -pl.savefig('images/E_fields' + '.png') -pl.clf() +#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/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 + +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, q2, density, 100, cmap='bwr') + pl.title(r'Time = ' + "%.2f"%(file_number*dt*dump_interval)) + pl.axes().set_aspect('equal') + pl.xlabel(r'$x$') + pl.ylabel(r'$y$') + pl.colorbar() + pl.savefig('images/density_' + '%06d'%file_number + '.png') + pl.clf() + + h5f = h5py.File(lagrange_multiplier_files[file_number], 'r') + lagrange_multipliers = np.swapaxes(h5f['lagrange_multipliers'][:], 0, 1) + 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] + + +#h5f = h5py.File('dumps/fields_000030.h5', 'r') +#fields = np.swapaxes(h5f['fields'][:], 0, 1) +#h5f.close() +# +#E1 = fields[:, :, 0] +#E2 = fields[:, :, 1] +# +#pl.figure(figsize=(20, 7.5)) +#pl.subplot(121) +#pl.contourf(q1, q2, E1, 100, cmap='bwr') +#pl.title('$E_1$') +#pl.xlabel(r'$x$') +#pl.ylabel(r'$y$') +#pl.colorbar() +#pl.gca().set_aspect('equal') +# +#pl.subplot(122) +#pl.contourf(q1, q2, E2, 100, cmap='bwr') +#pl.title('$E_2$') +#pl.xlabel(r'$x$') +#pl.ylabel(r'$y$') +#pl.colorbar() +#pl.gca().set_aspect('equal') +#pl.savefig('images/E_fields' + '.png') +#pl.clf() #for time_index, t0 in enumerate(time): # From 4eacc7d7f66de835b15936105ce2f3a3dfca66bf Mon Sep 17 00:00:00 2001 From: Mani Chandra Date: Wed, 7 Feb 2018 08:36:40 -0500 Subject: [PATCH 23/28] Refined post-processing script --- .../electronic_boltzmann/graphene/post.py | 71 +++++-------------- 1 file changed, 16 insertions(+), 55 deletions(-) diff --git a/example_problems/electronic_boltzmann/graphene/post.py b/example_problems/electronic_boltzmann/graphene/post.py index 85dcfa25..ac26db98 100644 --- a/example_problems/electronic_boltzmann/graphene/post.py +++ b/example_problems/electronic_boltzmann/graphene/post.py @@ -31,7 +31,7 @@ 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.figsize'] = 8, 7.5 pl.rcParams['figure.dpi'] = 100 pl.rcParams['image.cmap'] = 'jet' pl.rcParams['lines.linewidth'] = 1.5 @@ -67,7 +67,7 @@ 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, q1 = np.meshgrid(q2, q1) +q2_meshgrid, q1_meshgrid = np.meshgrid(q2, q1) #dump_index = 0 #h5f = h5py.File('dumps/moments_' + '%06d'%(dump_index) + '.h5', 'r') @@ -117,17 +117,12 @@ density = moments[:, :, 0] j_x = moments[:, :, 1] j_y = moments[:, :, 2] - pl.contourf(q1, q2, density, 100, cmap='bwr') + pl.contourf(q1_meshgrid, q2_meshgrid, density, 100, cmap='bwr') pl.title(r'Time = ' + "%.2f"%(file_number*dt*dump_interval)) - pl.axes().set_aspect('equal') - pl.xlabel(r'$x$') - pl.ylabel(r'$y$') - pl.colorbar() - pl.savefig('images/density_' + '%06d'%file_number + '.png') - pl.clf() + #pl.colorbar() h5f = h5py.File(lagrange_multiplier_files[file_number], 'r') - lagrange_multipliers = np.swapaxes(h5f['lagrange_multipliers'][:], 0, 1) + lagrange_multipliers = h5f['lagrange_multipliers'][:] h5f.close() mu = lagrange_multipliers[:, :, 0] @@ -135,48 +130,14 @@ T_ee = lagrange_multipliers[:, :, 2] vel_drift_x = lagrange_multipliers[:, :, 3] vel_drift_y = lagrange_multipliers[:, :, 4] - - -#h5f = h5py.File('dumps/fields_000030.h5', 'r') -#fields = np.swapaxes(h5f['fields'][:], 0, 1) -#h5f.close() -# -#E1 = fields[:, :, 0] -#E2 = fields[:, :, 1] -# -#pl.figure(figsize=(20, 7.5)) -#pl.subplot(121) -#pl.contourf(q1, q2, E1, 100, cmap='bwr') -#pl.title('$E_1$') -#pl.xlabel(r'$x$') -#pl.ylabel(r'$y$') -#pl.colorbar() -#pl.gca().set_aspect('equal') -# -#pl.subplot(122) -#pl.contourf(q1, q2, E2, 100, cmap='bwr') -#pl.title('$E_2$') -#pl.xlabel(r'$x$') -#pl.ylabel(r'$y$') -#pl.colorbar() -#pl.gca().set_aspect('equal') -#pl.savefig('images/E_fields' + '.png') -#pl.clf() - -#for time_index, t0 in enumerate(time): -# -# h5f = h5py.File('dumps/density_' + str(time_index) + '.h5', 'r') -# moments = np.swapaxes(h5f['moments'][:], 0, 1) -# h5f.close() -# -# n = moments[:, :, 0] -# -# #pl.contourf(q1, q2, n, np.linspace(0.8, 2.2, 500)) -# pl.contourf(q1, q2, n, 100) -# pl.title('Time = ' + "%.2f"%(t0)) -# pl.axes().set_aspect('equal') -# pl.xlabel(r'$x$') -# pl.ylabel(r'$y$') -# pl.colorbar() -# pl.savefig('images/%04d'%time_index + '.png') -# pl.clf() + + 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$') + pl.ylabel(r'$y$') + pl.savefig('images/dump_' + '%06d'%file_number + '.png') + pl.clf() From 086f7b3a3e87412ec2daf98c78c631f0ab8323fc Mon Sep 17 00:00:00 2001 From: Mani Chandra Date: Sat, 10 Feb 2018 03:21:10 -0500 Subject: [PATCH 24/28] Fixed bug in RTA --- bolt/src/electronic_boltzmann/collision_operator.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bolt/src/electronic_boltzmann/collision_operator.py b/bolt/src/electronic_boltzmann/collision_operator.py index 9c0e98c5..36f50869 100644 --- a/bolt/src/electronic_boltzmann/collision_operator.py +++ b/bolt/src/electronic_boltzmann/collision_operator.py @@ -350,9 +350,7 @@ def RTA(f, q1, q2, p1, p2, p3, moments, params, flag = False): -( f - f0_ee(f, p1, p2, p3, params) ) / params.tau_ee(q1, q2, p1, p2, p3) # When (f - f0) is NaN. Dividing by np.inf doesn't give 0 - # WORKAROUND: - C_f = af.select(params.tau_defect(q1, q2, p1, p2, p3) == np.inf, 0, C_f) -# C_f = af.select(params.tau_ee(q1, q2, p1, p2, p3) == np.inf, 0, C_f) + # TODO: WORKAROUND af.eval(C_f) return(C_f) From 04255358fe895421bc27db6be3a168e196ba5640 Mon Sep 17 00:00:00 2001 From: Mani Chandra Date: Sun, 11 Feb 2018 05:37:57 -0500 Subject: [PATCH 25/28] Added AC source. Refined post-processing script. --- .../graphene/boundary_conditions.py | 8 +- .../electronic_boltzmann/graphene/job_script | 2 +- .../electronic_boltzmann/graphene/main.py | 97 ++++++++++--------- .../electronic_boltzmann/graphene/params.py | 5 +- .../electronic_boltzmann/graphene/post.py | 6 +- 5 files changed, 62 insertions(+), 56 deletions(-) diff --git a/example_problems/electronic_boltzmann/graphene/boundary_conditions.py b/example_problems/electronic_boltzmann/graphene/boundary_conditions.py index 06e47a98..de960ef8 100644 --- a/example_problems/electronic_boltzmann/graphene/boundary_conditions.py +++ b/example_problems/electronic_boltzmann/graphene/boundary_conditions.py @@ -15,7 +15,9 @@ def f_left(f, q1, q2, p1, p2, p3, params): T = params.initial_temperature mu = params.initial_mu - vel_drift_x = params.vel_drift_x_in + t = params.current_time + omega = 2. * np.pi * params.AC_freq + vel_drift_x = params.vel_drift_x_in * np.sin(omega*t) fermi_dirac = (1./(af.exp( (E_upper - vel_drift_x*p1 - mu)/(k*T) ) + 1.) ) @@ -39,7 +41,9 @@ def f_right(f, q1, q2, p1, p2, p3, params): T = params.initial_temperature mu = params.initial_mu - vel_drift_x = params.vel_drift_x_out + t = params.current_time + omega = 2. * np.pi * params.AC_freq + vel_drift_x = params.vel_drift_x_out * np.sin(omega*t) fermi_dirac = (1./(af.exp( (E_upper - vel_drift_x*p1 - mu)/(k*T) ) + 1.) ) diff --git a/example_problems/electronic_boltzmann/graphene/job_script b/example_problems/electronic_boltzmann/graphene/job_script index 75c49d28..8cb37850 100644 --- a/example_problems/electronic_boltzmann/graphene/job_script +++ b/example_problems/electronic_boltzmann/graphene/job_script @@ -1,4 +1,4 @@ #!/bin/bash -#SBATCH -p gpu -n 4 --gres=gpu:4 -c1 --hint=nomultithread -t 2-00:00 +#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) 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/main.py b/example_problems/electronic_boltzmann/graphene/main.py index c2177265..c027f4f3 100644 --- a/example_problems/electronic_boltzmann/graphene/main.py +++ b/example_problems/electronic_boltzmann/graphene/main.py @@ -25,34 +25,34 @@ import bolt.src.electronic_boltzmann.moment_defs as moment_defs -pl.rcParams['figure.figsize'] = 12, 7.5 -pl.rcParams['figure.dpi'] = 150 -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'] = 20 -pl.rcParams['font.sans-serif'] = 'serif' -pl.rcParams['text.usetex'] = False -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' +#pl.rcParams['figure.figsize'] = 12, 7.5 +#pl.rcParams['figure.dpi'] = 150 +#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'] = 20 +#pl.rcParams['font.sans-serif'] = 'serif' +#pl.rcParams['text.usetex'] = False +#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' # Defining the physical system to be solved: @@ -68,8 +68,8 @@ # Time parameters: dt = params.dt t_final = params.t_final -t0 = 0.0 # current time -params.time_step = time_step = 0 +params.current_time = t0 = 0.0 +params.time_step = time_step = 0 N_g = domain.N_ghost @@ -221,7 +221,7 @@ mean_density = af.mean(density[0, N_g:-N_g, N_g:-N_g]) density_pert = density - mean_density - if (time_step%1==0): +# if (time_step%1==0): # chemical_potential = np.array(params.mu)[0, :, :] \ # - params.charge_electron*np.array(params.phi)[:, :] # pl.contourf(np.array(nls.q1_center)[0, N_g:-N_g, N_g:-N_g], \ @@ -236,20 +236,20 @@ # pl.gca().set_aspect('equal') # pl.savefig('/tmp/mu_' + '%06d'%time_step + '.png' ) # pl.clf() - - pl.contourf(np.array(nls.q1_center)[0, N_g:-N_g, N_g:-N_g], \ - np.array(nls.q2_center)[0, N_g:-N_g, N_g:-N_g], \ - np.array(density)[0, N_g:-N_g, N_g:-N_g], \ - 100, cmap='bwr' - ) - pl.title('Time = ' + "%.2f"%(t0) ) - pl.xlabel('$x$') - pl.ylabel('$y$') - pl.colorbar() - pl.gca().set_aspect('equal') - pl.savefig('/tmp/density_' + '%06d'%time_step + '.png' ) - pl.clf() - +# +# pl.contourf(np.array(nls.q1_center)[0, N_g:-N_g, N_g:-N_g], \ +# np.array(nls.q2_center)[0, N_g:-N_g, N_g:-N_g], \ +# np.array(density)[0, N_g:-N_g, N_g:-N_g], \ +# 100, cmap='bwr' +# ) +# pl.title('Time = ' + "%.2f"%(t0) ) +# pl.xlabel('$x$') +# pl.ylabel('$y$') +# pl.colorbar() +# pl.gca().set_aspect('equal') +# pl.savefig('/tmp/density_' + '%06d'%time_step + '.png' ) +# pl.clf() +# # pl.contourf(np.array(nls.q1_center)[0, N_g:-N_g, N_g:-N_g], \ # np.array(nls.q2_center)[0, N_g:-N_g, N_g:-N_g], \ # np.array(params.phi)[N_g:-N_g, N_g:-N_g], \ @@ -308,9 +308,10 @@ # pl.clf() nls.strang_timestep(dt) - time_step = time_step + 1 - params.time_step = time_step - t0 = t0 + 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) diff --git a/example_problems/electronic_boltzmann/graphene/params.py b/example_problems/electronic_boltzmann/graphene/params.py index b78d13a4..62478386 100644 --- a/example_problems/electronic_boltzmann/graphene/params.py +++ b/example_problems/electronic_boltzmann/graphene/params.py @@ -63,6 +63,7 @@ initial_mu = 0.015 vel_drift_x_in = 1e-7*fermi_velocity vel_drift_x_out = 1e-7*fermi_velocity +AC_freq = 1./100 # ps^-1 # Spatial quantities (will be initialized to shape = [q1, q2] in initalize.py) mu = None # chemical potential used in the e-ph operator @@ -82,11 +83,11 @@ # 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) + return(1 * q1**0 * p1**0) @af.broadcast def tau_ee(q1, q2, p1, p2, p3): - return(1. * q1**0 * p1**0) + return(np.inf * q1**0 * p1**0) def tau(q1, q2, p1, p2, p3): return(tau_defect(q1, q2, p1, p2, p3)) diff --git a/example_problems/electronic_boltzmann/graphene/post.py b/example_problems/electronic_boltzmann/graphene/post.py index ac26db98..8916a073 100644 --- a/example_problems/electronic_boltzmann/graphene/post.py +++ b/example_problems/electronic_boltzmann/graphene/post.py @@ -118,7 +118,7 @@ j_x = moments[:, :, 1] j_y = moments[:, :, 2] pl.contourf(q1_meshgrid, q2_meshgrid, density, 100, cmap='bwr') - pl.title(r'Time = ' + "%.2f"%(file_number*dt*dump_interval)) + pl.title(r'Time = ' + "%.2f"%(file_number*dt*dump_interval) + " ps") #pl.colorbar() h5f = h5py.File(lagrange_multiplier_files[file_number], 'r') @@ -137,7 +137,7 @@ 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$') - pl.ylabel(r'$y$') + pl.xlabel(r'$x\;(\mu \mathrm{m})$') + pl.ylabel(r'$y\;(\mu \mathrm{m})$') pl.savefig('images/dump_' + '%06d'%file_number + '.png') pl.clf() From c6e0c7ae2472ea5428dda2a3f2309d1067566824 Mon Sep 17 00:00:00 2001 From: Mani Chandra Date: Mon, 7 May 2018 05:05:51 -0400 Subject: [PATCH 26/28] Changed Lorentz force to use band velocities. --- bolt/src/electronic_boltzmann/advection_terms.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/bolt/src/electronic_boltzmann/advection_terms.py b/bolt/src/electronic_boltzmann/advection_terms.py index a5fcfb5c..694512d0 100644 --- a/bolt/src/electronic_boltzmann/advection_terms.py +++ b/bolt/src/electronic_boltzmann/advection_terms.py @@ -26,13 +26,12 @@ def A_p(q1, q2, p1, p2, p3, """Return the terms A_p1, A_p2 and A_p3.""" e = params.charge_electron c = params.speed_of_light + B3_mean = params.B3_mean -# dp1_dt = e*(E1 + (p2*B3 - p3*B2) / c) # p1 = hcross * k1 -# dp2_dt = e*(E2 + (p3*B1 - p1*B3) / c) # p2 = hcross * k2 -# dp3_dt = e*(E3 + (p1*B2 - p2*B1) / c) # p3 = hcross * k3 + v1, v2 = params.vel_band - dp1_dt = -e*E1 + 0.*p1 - dp2_dt = -e*E2 + 0.*p1 - dp3_dt = 0. + 0.*p1 + 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) From 4664bacdbea4faf4688b8005db0f088566e3250e Mon Sep 17 00:00:00 2001 From: Mani Chandra Date: Mon, 7 May 2018 05:12:16 -0400 Subject: [PATCH 27/28] Commented out selection of inflow chars at the boundaries; not needed. --- .../nonlinear_solver/apply_boundary_conditions.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/bolt/lib/nonlinear_solver/apply_boundary_conditions.py b/bolt/lib/nonlinear_solver/apply_boundary_conditions.py index f3b77a2a..ae5d0cfa 100644 --- a/bolt/lib/nonlinear_solver/apply_boundary_conditions.py +++ b/bolt/lib/nonlinear_solver/apply_boundary_conditions.py @@ -30,8 +30,12 @@ def apply_dirichlet_bcs_f(self, boundary): self.physical_system.params ) + # NOTE: This is not necessary since the Riemann solver ensures that the + # information outflow characteristics in the ghost zones do not affect + # the numerical solution inside in the physical domain. + # # Only changing inflowing characteristics: - f_left = af.select(A_q1>0, f_left, self.f) + #f_left = af.select(A_q1>0, f_left, self.f) self.f[:, :N_g] = f_left[:, :N_g] @@ -43,7 +47,7 @@ def apply_dirichlet_bcs_f(self, boundary): ) # Only changing inflowing characteristics: - f_right = af.select(A_q1<0, f_right, self.f) + #f_right = af.select(A_q1<0, f_right, self.f) self.f[:, -N_g:] = f_right[:, -N_g:] @@ -55,7 +59,7 @@ def apply_dirichlet_bcs_f(self, boundary): ) # Only changing inflowing characteristics: - f_bottom = af.select(A_q2>0, f_bottom, self.f) + #f_bottom = af.select(A_q2>0, f_bottom, self.f) self.f[:, :, :N_g] = f_bottom[:, :, :N_g] @@ -67,7 +71,7 @@ def apply_dirichlet_bcs_f(self, boundary): ) # Only changing inflowing characteristics: - f_top = af.select(A_q2<0, f_top, self.f) + #f_top = af.select(A_q2<0, f_top, self.f) self.f[:, :, -N_g:] = f_top[:, :, -N_g:] From ed9cf5752194c9db93d292a317de76f4e803b923 Mon Sep 17 00:00:00 2001 From: Mani Chandra Date: Mon, 7 May 2018 06:10:34 -0400 Subject: [PATCH 28/28] Code backup; Need to clean up post.py --- .../graphene/boundary_conditions.py | 66 ++-- .../electronic_boltzmann/graphene/main.py | 25 +- .../electronic_boltzmann/graphene/params.py | 19 +- .../electronic_boltzmann/graphene/post.py | 293 +++++++++++++++++- 4 files changed, 364 insertions(+), 39 deletions(-) diff --git a/example_problems/electronic_boltzmann/graphene/boundary_conditions.py b/example_problems/electronic_boltzmann/graphene/boundary_conditions.py index de960ef8..fc1a9927 100644 --- a/example_problems/electronic_boltzmann/graphene/boundary_conditions.py +++ b/example_problems/electronic_boltzmann/graphene/boundary_conditions.py @@ -17,18 +17,37 @@ def f_left(f, q1, q2, p1, p2, p3, params): t = params.current_time omega = 2. * np.pi * params.AC_freq - vel_drift_x = params.vel_drift_x_in * np.sin(omega*t) + vel_drift_x_in = params.vel_drift_x_in * np.sin(omega*t) - fermi_dirac = (1./(af.exp( (E_upper - vel_drift_x*p1 - mu)/(k*T) ) + 1.) - ) + fermi_dirac_in = (1./(af.exp( (E_upper - vel_drift_x_in*p1 - 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*p1 - mu)/(k*T) ) + 1.) + ) - q2_contact_start = params.contact_start - q2_contact_end = params.contact_end - cond = ((q2 >= q2_contact_start) & \ - (q2 <= q2_contact_end) \ - ) + # 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*fermi_dirac + (1 - cond)*f + 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) @@ -43,18 +62,27 @@ def f_right(f, q1, q2, p1, p2, p3, params): t = params.current_time omega = 2. * np.pi * params.AC_freq - vel_drift_x = params.vel_drift_x_out * np.sin(omega*t) + vel_drift_x_out = params.vel_drift_x_out * np.sin(omega*t) - fermi_dirac = (1./(af.exp( (E_upper - vel_drift_x*p1 - mu)/(k*T) ) + 1.) - ) - - q2_contact_start = params.contact_start - q2_contact_end = params.contact_end - cond = ((q2 >= q2_contact_start) & \ - (q2 <= q2_contact_end) \ - ) + fermi_dirac_out = (1./(af.exp( (E_upper - vel_drift_x_out*p1 - mu)/(k*T) ) + 1.) + ) - f_right = cond*fermi_dirac + (1 - cond)*f + 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/main.py b/example_problems/electronic_boltzmann/graphene/main.py index c027f4f3..3c243bed 100644 --- a/example_problems/electronic_boltzmann/graphene/main.py +++ b/example_problems/electronic_boltzmann/graphene/main.py @@ -70,6 +70,8 @@ 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 @@ -123,7 +125,7 @@ print("rank = ", params.rank, "\n", " = ", af.mean(params.mu[0, N_g:-N_g, N_g:-N_g]), "\n", " max(mu) = ", af.max(params.mu[0, N_g:-N_g, N_g:-N_g]), "\n", - " = ", af.mean(params.phi[N_g:-N_g, N_g:-N_g]), "\n", + #" = ", af.mean(params.phi[N_g:-N_g, N_g:-N_g]), "\n", " = ", af.mean(density[0, N_g:-N_g, N_g:-N_g]), "\n", " max(n) = ", af.max(density[0, N_g:-N_g, N_g:-N_g]), "\n", " |E1| = ", af.mean(af.abs(nls.cell_centered_EM_fields[0, N_g:-N_g, N_g:-N_g])), @@ -156,13 +158,14 @@ sys.exit("Terminating execution") else: - compute_electrostatic_fields(nls) + #compute_electrostatic_fields(nls) + pass density = nls.compute_moments('density') print("rank = ", params.rank, "\n", " = ", af.mean(params.mu[0, N_g:-N_g, N_g:-N_g]), "\n", " max(mu) = ", af.max(params.mu[0, N_g:-N_g, N_g:-N_g]), "\n", - " = ", af.mean(params.phi[N_g:-N_g, N_g:-N_g]), "\n", + #" = ", af.mean(params.phi[N_g:-N_g, N_g:-N_g]), "\n", " = ", af.mean(density[0, N_g:-N_g, N_g:-N_g]), "\n", " max(n) = ", af.max(density[0, N_g:-N_g, N_g:-N_g]), "\n", " |E1| = ", af.mean(af.abs(nls.cell_centered_EM_fields[0, N_g:-N_g, N_g:-N_g])), @@ -180,15 +183,22 @@ 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'%(time_step/dump_steps) + 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("=====================================================") nls.dump_moments('dumps/moments_' + file_number) - 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, @@ -320,7 +330,7 @@ print("rank = ", params.rank, "\n", " = ", af.mean(params.mu[0, N_g:-N_g, N_g:-N_g]), "\n", " max(mu) = ", af.max(params.mu[0, N_g:-N_g, N_g:-N_g]), "\n", - " = ", af.mean(params.phi[N_g:-N_g, N_g:-N_g]), "\n", + #" = ", af.mean(params.phi[N_g:-N_g, N_g:-N_g]), "\n", " = ", af.mean(density[0, N_g:-N_g, N_g:-N_g]), "\n", " max(n) = ", af.max(density[0, N_g:-N_g, N_g:-N_g]), "\n", " |E1| = ", af.mean(af.abs(nls.cell_centered_EM_fields[0, N_g:-N_g, N_g:-N_g])), @@ -329,6 +339,9 @@ ) PETSc.Sys.Print("--------------------\n") +if (params.rank==0): + np.savetxt("dump_time_array.txt", dump_time_array) + #phi_array = nls.poisson.glob_phi.getArray() #phi_array = phi_array.reshape([nls.poisson.N_q3_3D_local, \ # nls.poisson.N_q2_3D_local, \ diff --git a/example_problems/electronic_boltzmann/graphene/params.py b/example_problems/electronic_boltzmann/graphene/params.py index 62478386..02c08f3b 100644 --- a/example_problems/electronic_boltzmann/graphene/params.py +++ b/example_problems/electronic_boltzmann/graphene/params.py @@ -35,14 +35,14 @@ dump_steps = 10 # Time parameters: -dt = 0.05 -t_final = 1000 +dt = 0.025/2 # ps +t_final = 200 # ps # Dimensionality considered in velocity space: p_dim = 2 # Number of devices(GPUs/Accelerators) on each node: -num_devices = 4 +num_devices = 6 # Constants: mass_particle = 0.910938356 # x 1e-30 kg @@ -58,13 +58,18 @@ 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-7*fermi_velocity -vel_drift_x_out = 1e-7*fermi_velocity +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 @@ -83,11 +88,11 @@ # Variation of collisional-timescale parameter through phase space: @af.broadcast def tau_defect(q1, q2, p1, p2, p3): - return(1 * q1**0 * p1**0) + return(1. * q1**0 * p1**0) @af.broadcast def tau_ee(q1, q2, p1, p2, p3): - return(np.inf * q1**0 * p1**0) + return(0.2 * q1**0 * p1**0) def tau(q1, q2, p1, p2, p3): return(tau_defect(q1, q2, p1, p2, p3)) diff --git a/example_problems/electronic_boltzmann/graphene/post.py b/example_problems/electronic_boltzmann/graphene/post.py index 8916a073..a297c6f0 100644 --- a/example_problems/electronic_boltzmann/graphene/post.py +++ b/example_problems/electronic_boltzmann/graphene/post.py @@ -1,8 +1,11 @@ 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 @@ -31,13 +34,16 @@ 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, 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'] = 20 +pl.rcParams['font.size'] = 25 pl.rcParams['font.sans-serif'] = 'serif' pl.rcParams['text.usetex'] = True pl.rcParams['axes.linewidth'] = 1.5 @@ -62,13 +68,51 @@ N_q1 = domain.N_q1 N_q2 = domain.N_q2 -N_g = domain.N_ghost +#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) @@ -99,13 +143,101 @@ #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/dumps' +#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')) +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) @@ -114,11 +246,14 @@ 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"%(file_number*dt*dump_interval) + " ps") + pl.title(r'Time = ' + "%.2f"%(time_array[file_number]) + " ps") #pl.colorbar() h5f = h5py.File(lagrange_multiplier_files[file_number], 'r') @@ -131,13 +266,157 @@ 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', +# 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) + +