M = 4 # number of elements Nnodes = M + 1 # number of nodes x0 = 0.0 # position of first node xL = x0 + L # position of last node mesh_ratio = 1.0 # mesh ratio = size last element / size of first element deltaX = L / M # assume uniform nodal spacing # -------------------------- Boundary conditions --------------------- boundCondLoc = [0, M] # the nodal location of boundary conditions boundCondValue = [2.0, 0.0] # and the values of the boundary conditions # -------------------------- Mesh generation ------------------------ nodalCoords = meshGrading.getGradedMesh(x0, xL, M, mesh_ratio) nodArray = array(nodalCoords) # create an array (useful functions) # -------------------------- NR procedure ------------------------ tolerance = 1.0e-8 error = 1.0 iterationCount = 0 K = zeros((Nnodes, Nnodes)) # create the K matrix RHS = zeros((Nnodes, 1)) # create the RHS vector psi_n = zeros((Nnodes, 1), dtype=float) # create initial guess for psi psi_n = psi_n + 0.0 for n in boundCondLoc:
def main(dopingConc, appliedVoltage, plotting): # the main function that runs our code # pass in: doping Conc, applied V (LHS) and plotting flag Na = dopingConc phi_n = kT/q * math.log( Na / ni ) # quasi fermi levels phi_p = phi_n L = 100.0e-7 # length of semiconductor (cm) # -------------------------- Mesh parameters ------------------------- M = 100 # number of elements x0 = 0.0 # position of first node xL = x0 + L # position of last node mesh_ratio = 1.0 # mesh ratio = size last element / size of first element # -------------------------- Boundary conditions --------------------- boundCond = array([[0, appliedVoltage], [M, 0.0]]) # the nodal location of boundary conditions # -------------------------- Mesh generation ------------------------ nodalCoords = meshGrading.getGradedMesh(x0, xL, M, mesh_ratio) nodArray = array(nodalCoords) # create an array (useful functions) # -------------------------- Node connectivity ------------------------- # we need to know which nodes are connected to which elements connectivity = zeros((M,2)) for element in range(M): connectivity[element,0] = element connectivity[element,1] = element + 1 # -------------------------- psi interpolation -------------------------- def getPsi_n(element, localXi): globalNode1 = connectivity[element,0] # global node num of local node 1 globalNode2 = connectivity[element,1] # global node num of local node 2 psi = shapeFunctions.N1(localXi) * psi_n[globalNode1] \ + shapeFunctions.N2(localXi) * psi_n[globalNode2] return psi # -------------------------- NR + matrix setup ------------------------- # The Newton-Raphson procedure requires an initial guess to allow the # increment (Delta psi) to be found. We simply make this vector zero while # making sure to satisfy the boundary conditions iteration = 0 # iteration number is zero at start residualRef = 0.0 # the reference residual (put psi_n = {0}) in function residual = 0.0 # the residual for the present iteration residualRatio = 1.0 # simply the ratio of residual / residualRef residualPlotValues = zeros((20, M+1)) tolerance = 1e-6 # the NR tolerance max_iterations = 1000 psi_n = zeros((size(nodArray), 1),dtype=float) psi_n = psi_n + 0.0 for n in boundCond: psi_n[n[0]] = n[1] # set the initial guess to satisfy BCs # NR ITERATION LOOP while residualRatio > tolerance: if iteration > max_iterations: print "max no. of iterations reached" break T = zeros((M+1, M+1)) # zero Tangent matrix Mass = zeros((M+1, M+1)) K = zeros((M+1, M+1)) # zero K matrix Fb = zeros((M+1,1)) # zero body force vector # -------------------------- Matrix computation ------------------------- numGPs = 2 # define num. Gauss points gpt,gwt = gaussNodes.gaussNodes(numGPs) # gauss points and weights for element in range(M): nodes = connectivity[element] # get nodes for current element x1 = nodArray[nodes[0]] # the node coords for element x2 = nodArray[nodes[1]] length = abs(x2 - x1) # length of element # STIFFNESS MATRIX COMPUTATION (analytical expression) K_el = 1.0 / length * array([[1,-1],[-1,1]]) * epsilon # NUMERICAL INTEGRATION (mass matrix, body force vector) m11 = m12 = 0.0 # initialise mass matrix terms fb1 = fb2 = 0.0 # initialise body force terms for gp in range(numGPs): gxi = gpt[gp] gw = gwt[gp] psi = getPsi_n(element, gxi) E = forcingTerm.E(psi, q, epsilon, phi_n, phi_p, kT, ni, Na) Ederiv = forcingTerm.Ederiv(psi, q, epsilon, phi_n, phi_p, kT, ni, Na) #print E, Ederiv N1 = shapeFunctions.N1(gxi) N2 = shapeFunctions.N2(gxi) detJacob = length / 2.0 # MASS MATRIX COMPUTATION m11 = m11 + N1 * Ederiv * N1 * gw * detJacob m12 = m12 + N1 * Ederiv * N2 * gw * detJacob # BODY FORCE COMPUTATION fb1 = fb1 + N1 * E * gw * detJacob fb2 = fb2 + N2 * E * gw * detJacob #gp = 2 # .............. end loop over Gauss points M_el = array([[m11, m12], [m12, m11]]) Fb_el = array([[fb1],[fb2]]) #print K_el, M_el, Fb_el # now put the element matrices in the global matrices for i in range(size(nodes)): globali = connectivity[element,i] Fb[globali] = Fb[globali] + Fb_el[i] for j in range(size(nodes)): globalj = connectivity[element,j] T[globali,globalj] = T[globali,globalj] + K_el[i,j] + M_el[i,j] K[globali,globalj] = K[globali,globalj] + K_el[i,j] Mass[globali,globalj] = Mass[globali,globalj] + M_el[i,j] # .............. end loop over elements # -------------------------- Solution ---------------------------------- RHS = -dot(K, psi_n) - Fb if iteration == 0: for term in RHS: # reference residual residualRef = residualRef + term**2 residualRef = residualRef**0.5 for i in boundCond[:,0]: # apply boundary conditions for j in range(size(nodArray)): T[i,j] = 0.0 T[i, i] = 1.0 RHS[i] = 0.0 #if iteration < 20: RHS[0] = 0.1 solution = solve(T,RHS) # solve the system of equations for term in range(size(solution)): # get the new solution using the increment #if term in boundCond[:,0]: #continue psi_n[term] = psi_n[term] + solution[term] # -------------------------- Residual ---------------------------------- residual = 0.0 # calculate the residual and if on first iteration, the for term in RHS: # reference residual residual = residual + term**2 residual = residual**0.5 residualRatio = residual / residualRef if iteration < 20: for term in range(size(RHS)): residualPlotValues[iteration, term] = RHS[term] print iteration, residualRatio #pylab.plot(nodArray, RHS) #pylab.savefig('Resiudal_plot.eps') #pylab.show() iteration = iteration + 1 # .............. end loop over NR iteration psiList = zeros(size(psi_n)) for term in range(size(psi_n)): psiList[term] = psi_n[term,0] # -------------------------- Plotting --------------------------------- if(plotting): y = zeros(size(nodArray,0)) # array of zeros for plotting #pylab.plot(nodArray, y, 'ko-') # plot the mesh #pylab.plot(nodArray, psiList, 'ko-') #pylab.show() for count in range(10): # residual plotting pylab.plot(nodArray[0:10], residualPlotValues[count,0:10], label='iteration %s' % count) pylab.xlabel('x') pylab.ylabel('residual') pylab.legend() pylab.savefig('residual_6GP_potential_2V.eps') pylab.show() # .............. main functionhttp://matplotlib.sourceforge.net/ return nodArray, psiList