def DDGnlpoisson_new (idata,xaxis,sinodes,Vin,nin,pin,toll,maxit,verbose,fi_e,fi_h,model,Vt,surface,fi_stat,iteration,ns): ## Set some useful constants dampit = 10 dampcoeff = 5 ## Convert grid info to FEM form #Ndiricheletnodes= 2 nodes = xaxis sielements=np.zeros(len(sinodes)-1) sielements[:] = sinodes[1:len(sinodes)] n_max = len(nodes) #totdofs = n_max - Ndiricheletnodes elements=np.zeros((n_max-1,2)) elements[:,0]= np.arange(0,n_max-1) elements[:,1]=np.arange(1,n_max) Nelements=np.size(elements[:,0]) BCnodes= n_max normr=np.zeros(maxit+1) """ print("nodes=",nodes) print("sielements=",sielements) print("n_max=",n_max) print("elements=",elements) print("Nelements=",Nelements) print("BCnodes=",BCnodes) check_point_8 """ ## Initialization V = Vin EF = 0.0 if iteration == 1: # Determination of the Fermi Level EF = 0.0 V = np.zeros(n_max) n, p, V = equi_np_fi( iteration, idata.dop, idata.Ppz_Psp, n_max, idata.ni, model, Vt, surface ) fi_stat = V else: if model.N_wells_virtual - 2 != 0: n, p, fi_non, EF = equi_np_fi3( V, idata.wfh_general, idata.wfe_general, model, idata.E_state_general, idata.E_statec_general, idata.meff_state_general, idata.meff_statec_general, n_max, idata.ni*ns, ) else: n = np.exp(V) p = np.exp(-V) n=n*idata.ni p=p*idata.ni """ print("sinodes=",sinodes) print("n=",n) print("p=",p) check_point_9 """ if (sinodes[0]==0): n[1]=nin[0] p[1]=pin[0] if (sinodes[n_max-1]==n_max-1): n[n_max-1]=nin[n_max-1] p[n_max-1]=pin[n_max-1] ## Compute LHS matrices l22=idata.l2*np.ones(Nelements) L = Ucomplap (nodes,n_max,elements,Nelements,l22) ## Compute Mv = ( n + p) Mv = np.zeros(n_max) Mv[sinodes] = (n + p) Cv = np.ones(Nelements) M = Ucompmass (nodes,n_max,elements,Nelements,Mv,Cv) ## Compute RHS vector Tv0 = np.zeros(n_max) Tv0[sinodes] = (n - p -idata.dop-idata.Ppz_Psp) Cv= np.ones(Nelements) T0 = Ucompconst (nodes,n_max,elements,Nelements,Tv0,Cv) """ print('L=',L) print('M=',M) print('T0=',T0) check_point_10 """ ## Build LHS matrix and RHS of the linear system for 1st Newton step A=np.zeros((n_max,n_max)) R=np.zeros(n_max) Anew=np.zeros((n_max,n_max)) Rnew=np.zeros(n_max) A = L + M LV=np.dot(np.array(L) , V) R = LV +T0 ## Apply boundary conditions """ print('A=',A) print('R=',R) check_point_11 """ A=np.delete(A, [0,BCnodes-1], 0) A=np.delete(A, [0,BCnodes-1], 1) R=np.delete(R, [0,BCnodes-1], 0) normr[0] = np.linalg.norm(R,np.inf) relresnorm = 1 reldVnorm = 1 normrnew = normr[0] ## Start of the newton cycle for newtit in range(1,maxit): if verbose: print("\n newton iteration: %d, reldVnorm = %f"%(newtit,reldVnorm)) cc= np.linalg.solve(A, -R)#, rcond=None)[0] dV=np.zeros(n_max) dV[1:n_max-1] =cc ## Start of the damping procedure tk = 1 for dit in range(1,dampit): if verbose: print("\n damping iteration: %d, residual norm = %f"%(dit,normrnew)) Vnew = V + tk * dV if iteration == 1: n = np.exp(Vnew)*idata.ni p = np.exp(-Vnew)*idata.ni else: if model.N_wells_virtual - 2 != 0: n, p, fi_non, EF = equi_np_fi3( Vnew, idata.wfh_general, idata.wfe_general, model, idata.E_state_general, idata.E_statec_general, idata.meff_state_general, idata.meff_statec_general, n_max, idata.ni*ns, ) else: n = np.exp(Vnew) p = np.exp(-Vnew) n=n*idata.ni p=p*idata.ni if (sinodes[0]==0): n[0]=nin[0] p[0]=pin[0] if (sinodes[n_max-1]==n_max-1): n[n_max-1]=nin[n_max-1] p[n_max-1]=pin[n_max-1] ## Compute LHS matrices Mv = np.zeros(n_max) Mv[sinodes] = (n + p) Cv = np.ones(Nelements) #Cv[sielements]= 1 M = Ucompmass (nodes,n_max,elements,Nelements,Mv,Cv) ## Compute RHS vector (-residual) Tv0 = np.zeros(n_max) Tv0[sinodes] = (n - p -idata.dop-idata.Ppz_Psp) Cv= np.ones(Nelements) Cv = np.ones(Nelements) #Cv[sielements]= 1 T0 = Ucompconst (nodes,n_max,elements,Nelements,Tv0,Cv) """ print('L=',L) print('M=',M) print('T0=',T0) check_point_12 """ ## Build LHS matrix and RHS of the linear system for 1st Newton step Anew = L + M LVnew=np.dot(np.array(L) , Vnew) Rnew = LVnew +T0 """ print('Anew=',Anew) print('Rnew=',Rnew) check_point_13 """ ## Apply boundary conditions Anew=np.delete(Anew, [0,BCnodes-1], 0) Anew=np.delete(Anew, [0,BCnodes-1], 1) Rnew=np.delete(Rnew, [0,BCnodes-1], 0) if ((dit>1) and (np.linalg.norm(Rnew,np.inf) >= np.linalg.norm(R,np.inf))): if verbose: print("\nexiting damping cycle \n") break else: A = Anew R = Rnew ## Compute | R_{k+1} | for the convergence test normrnew= np.linalg.norm(R,np.inf) ## Check if more damping is needed if (normrnew > normr[newtit]): tk = tk/dampcoeff else: if verbose: print("\nexiting damping cycle because residual norm = %f \n"%normrnew) break V= Vnew normr[newtit+1] = normrnew dVnorm= np.linalg.norm(tk*dV,np.inf) ## Check if convergence has been reached reldVnorm = dVnorm / np.linalg.norm(V,np.inf) if (reldVnorm <= toll): if(verbose): print("\nexiting newton cycle because reldVnorm= %f \n"%reldVnorm) break res = normr niter = newtit return [V,n,p,fi_stat]#,res,niter
def DDNnewtonmap (ni,fi_e,fi_h,xaxis,idata,toll,maxit,verbose,model,Vt): odata = idata n_max = len(xaxis) fi_n=np.zeros(n_max) fi_p=np.zeros(n_max) Nelements=n_max-1 elements=np.zeros((n_max-1,2)) elements[:,0]= np.arange(0,n_max-1) elements[:,1]=np.arange(1,n_max) BCnodesp = [0,n_max-1] BCnodesp1 = [n_max,2*n_max-1] BCnodesp2 = [2*n_max,3*n_max-1] BCnodes_=np.zeros((3,2)) BCnodes_[0,:]=BCnodesp BCnodes_[1,:]=BCnodesp1 BCnodes_[2,:]=BCnodesp2 BCnodes=BCnodes_.flatten() totaldofs= n_max-2 dampcoef = 10 maxdamp = 2 nrm_du_old=1. V = odata.V n = odata.n p = odata.p dop = idata.dop Ppz_Psp=idata.Ppz_Psp ## Create the complete unknown vector u = np.hstack(([V, n, p])) if model.N_wells_virtual-2!=0 and config.quantum_effect: fi_n,fi_p =equi_np_fi222(ni,idata,fi_e,fi_h,V,Vt,idata.wfh_general,idata.wfe_general,model,idata.E_state_general,idata.E_statec_general,idata.meff_state_general,idata.meff_statec_general,n_max,n,p) ## Build fem matrices L = Ucomplap (xaxis,n_max,elements,Nelements,idata.l2*np.ones(Nelements)) M = Ucompmass (xaxis,n_max,elements,Nelements,np.ones(n_max),np.ones(Nelements)) DDn = Uscharfettergummel(xaxis,n_max,elements,Nelements,idata.mun,1,V+fi_n) DDp = Uscharfettergummel(xaxis,n_max,elements,Nelements,idata.mup,1,-V-fi_p) ## Initialise RHS denomsrh = idata.TAUN0 * (p + idata.theta) + idata.TAUP0 * (n + idata.theta) factauger = idata.Cn * n + idata.Cp * p fact = (1 / denomsrh + factauger) r1 = np.dot(np.array(L) , V) + np.dot(np.array(M) , (n - p - dop-Ppz_Psp)) r2 = np.dot(np.array(DDn) , n)+ np.dot(np.array(M) , (p * n - idata.theta** 2) * fact) r3 = np.dot(np.array(DDp) , p)+ np.dot(np.array(M) , (p * n - idata.theta** 2) * fact) RHS=-np.hstack(( r1, r2, r3)) ## Apply BCs RHS=np.delete(RHS, BCnodes, 0) nrm = np.linalg.norm(RHS,np.inf) res=np.zeros(maxit) res[0] = nrm ## Begin Newton Cycle for count in range (0, maxit): if verbose: print ("Newton Iteration Number:%d\n"%count) Ln = Ucomplap (xaxis,n_max,elements,Nelements,Umediaarmonica(idata.mun*n)) Lp = Ucomplap (xaxis,n_max,elements,Nelements,Umediaarmonica(idata.mup*p)) Mn = Ucompmass (xaxis,n_max,elements,Nelements,np.ones(n_max),n[0:n_max-1]*fact[0:n_max-1]) Mp = Ucompmass (xaxis,n_max,elements,Nelements,np.ones(n_max),p[0:n_max-1]*fact[0:n_max-1]) Z = np.zeros((n_max,n_max)) DDn = Uscharfettergummel(xaxis,n_max,elements,Nelements,idata.mun,1,V+fi_n) DDp = Uscharfettergummel(xaxis,n_max,elements,Nelements,idata.mup,1,-V-fi_p) A = L #A11 B = M #A12 C =-M #A13 DDD =-Ln #A21 E = DDn+Mp#A22 F = Z+Mn #A23 G = Lp #A31 H = Z+Mp #A32 I = DDp+Mn#A33 ## Build LHS LHS= np.asarray(np.bmat([(A, B, C),(DDD, E, F),(G, H, I)])) ## Apply BCs LHS=np.delete(LHS, BCnodes, 0) LHS=np.delete(LHS, BCnodes, 1) ## Solve the linearised system dutmp= np.linalg.solve(LHS, RHS)#, rcond=None)[0] dv = dutmp[0:totaldofs] dn = dutmp[totaldofs:2*totaldofs] dp = dutmp[2*totaldofs:3*totaldofs] du=np.hstack((0,dv,0,0,dn,0,0,dp,0)) ## Check Convergence nrm_u = np.linalg.norm(u,np.inf) nrm_du = np.linalg.norm(du,np.inf) ratio = nrm_du/nrm_u if verbose: print ("ratio = %e\n"% ratio) if (ratio <= toll): V = u[0:n_max] n = u[n_max:2*n_max] p = u[2*n_max:len(u)] res[count] = nrm break ## Begin damping cycle tj = 1 if model.N_wells_virtual-2!=0 and config.quantum_effect: fi_n,fi_p =equi_np_fi222(ni,idata,fi_e,fi_h,V,Vt,idata.wfh_general,idata.wfe_general,model,idata.E_state_general,idata.E_statec_general,idata.meff_state_general,idata.meff_statec_general,n_max,n,p) for cc in range( 1,maxdamp): if verbose: print ("damping iteration number:%d\n"%cc) print ("reference residual norm:%f\n"%nrm) ## Update the unknown vector utmp = u + tj*du Vnew = utmp[0:n_max] nnew = utmp[n_max:2*n_max] pnew = utmp[2*n_max:len(utmp)] ## Try a new RHS DDn = Uscharfettergummel(xaxis,n_max,elements,Nelements,idata.mun,1,Vnew+fi_n) DDp = Uscharfettergummel(xaxis,n_max,elements,Nelements,idata.mup,1,-Vnew-fi_p) r1 = np.dot(np.array(L) , V) + np.dot(np.array(M) , (nnew - pnew - dop-Ppz_Psp)) r2 = np.dot(np.array(DDn) , nnew)+ np.dot(np.array(M) , (pnew * nnew - idata.theta** 2) * fact) r3 = np.dot(np.array(DDp) , pnew) + np.dot(np.array(M) , (pnew * nnew - idata.theta** 2) * fact) RHS=-np.hstack(( r1, r2, r3)) ## Apply BCs RHS=np.delete(RHS, BCnodes, 0) nrmtmp=np.linalg.norm(RHS,np.inf) ## Update the damping coefficient if verbose: print("residual norm:%f\n\n"%nrmtmp) if (nrmtmp>nrm): tj = tj/(dampcoef*cc) if verbose: print ("\ndamping coefficients = %f"%tj) else: break nrm_du = np.linalg.norm(tj*du,np.inf) u = utmp if (count>0): ratio = nrm_du/nrm_du_old if (ratio<.005): V = u[0:n_max] n = u[n_max:2*n_max] p = u[2*n_max:len(u)] res[count] = nrm break nrm = nrmtmp res[count] = nrm ## Convert result vector into distinct output vectors V = u[0:n_max] n = u[n_max:2*n_max] p = u[2*n_max:len(u)] nrm_du_old = nrm_du odata.V = V odata.n = n odata.p = p it = count return [odata,it,res]
def DDGelectron_driftdiffusion(psi, xaxis, ng, p, ni, TAUN0, TAUP0, mun, fi_e, fi_h, model, Vt, idata): nodes = xaxis n_max = len(nodes) """ n=np.zeros(n_max) p=np.zeros(n_max) """ fi_n = np.zeros(n_max) fi_p = np.zeros(n_max) elements = np.zeros((n_max - 1, 2)) elements[:, 0] = np.arange(0, n_max - 1) elements[:, 1] = np.arange(1, n_max) Nelements = np.size(elements[:, 0]) BCnodes = [0, n_max - 1] nl = ng[0] nr = ng[n_max - 1] h = nodes[1:n_max] - nodes[0:n_max - 1] c = 1 / h """ print("c=",c) print("h=",h) print("nr=",nr) print("nl=",nl) print("BCnodes=",BCnodes) print("Nelements=",Nelements) print("elements=",elements) print("n_max=",n_max) print("nodes=",nodes) check_point_15 """ if model.N_wells_virtual - 2 != 0 and config.quantum_effect: fi_n, fi_p = equi_np_fi222( ni, idata, fi_e, fi_h, psi, Vt, idata.wfh_general, idata.wfe_general, model, idata.E_state_general, idata.E_statec_general, idata.meff_state_general, idata.meff_statec_general, n_max, idata.n, p) Bneg = Ubernoulli( -(psi[1:n_max] - psi[0:n_max - 1]) - (fi_n[1:n_max] - fi_n[0:n_max - 1]), 1) Bpos = Ubernoulli((psi[1:n_max] - psi[0:n_max - 1]) + (fi_p[1:n_max] - fi_p[0:n_max - 1]), 1) """ print("Bneg=",Bneg) print("Bpos=",Bpos) check_point_16 """ d0 = np.zeros(n_max) d0[0] = c[0] * Bneg[0] d0[n_max - 1] = c[len(c) - 1] * Bpos[len(Bpos) - 1] d0[1:n_max - 1] = c[0:len(c) - 1] * Bpos[0:len(Bpos) - 1] + c[1:len(c)] * Bneg[1:len(Bneg)] d1 = np.zeros(n_max) d1[0] = n_max d1[1:n_max] = -c * Bpos dm1 = np.zeros(n_max) dm1[n_max - 1] = n_max dm1[0:n_max - 1] = -c * Bneg """ print("d0=",d0) print("d1=",d1) print("dm1=",dm1) check_point_17 """ A = sp.spdiags([dm1, d0, d1], np.array([-1, 0, 1]), n_max, n_max).todense() b = np.zeros(n_max) #%- A * ng ## SRH Recombination term SRHD = TAUP0 * (ng + ni) + TAUN0 * (p + ni) SRHL = p / SRHD SRHR = ni**2 / SRHD ASRH = Ucompmass(nodes, n_max, elements, Nelements, SRHL, np.ones(Nelements)) bSRH = Ucompconst(nodes, n_max, elements, Nelements, SRHR, np.ones(Nelements)) """ print("ASRH=",ASRH) print("bSRH=",bSRH) check_point_18 """ A = A + ASRH b = b + bSRH """ print("A=",A) print("b=",b) check_point_19 """ ## Boundary conditions b = np.delete(b, BCnodes, 0) b[0] = -A[1, 0] * nl b[len(b) - 1] = -A[n_max - 2, n_max - 1] * nr A = np.delete(A, BCnodes, 0) A = np.delete(A, BCnodes, 1) nn = np.linalg.solve(A, b) n = np.zeros(n_max) n[1:n_max - 1] = nn n[0] = nl n[len(n) - 1] = nr """ print("BCnodes=",BCnodes) print("A=",A) print("b=",b) print("n=",n) check_point_20 """ return n
def DDGhole_driftdiffusion(psi,xaxis,pg,n,ni,TAUN0,TAUP0,mup,fi_e,fi_h,model,Vt,idata): nodes = xaxis n_max =len(nodes) """ n=np.zeros(n_max) p=np.zeros(n_max) """ fi_n=np.zeros(n_max) fi_p=np.zeros(n_max) elements=np.zeros((n_max-1,2)) elements[:,0]= np.arange(0,n_max-1) elements[:,1]=np.arange(1,n_max) Nelements=np.size(elements[:,0]) BCnodes= [0,n_max-1] pl = pg[0] pr = pg[n_max-1] h=nodes[1:len(nodes)]-nodes[0:len(nodes)-1] c=1/h if model.N_wells_virtual-2!=0 and config.quantum_effect: fi_n,fi_p =equi_np_fi222(ni,idata,fi_e,fi_h,psi,Vt,idata.wfh_general,idata.wfe_general,model,idata.E_state_general,idata.E_statec_general,idata.meff_state_general,idata.meff_statec_general,n_max,n,idata.p) Bneg=Ubernoulli(-(psi[1:n_max]-psi[0:n_max-1])-(fi_n[1:n_max]-fi_n[0:n_max-1]),1) Bpos=Ubernoulli( (psi[1:n_max]-psi[0:n_max-1])+(fi_p[1:n_max]-fi_p[0:n_max-1]),1) d0=np.zeros(n_max) d0[0]=c[0]*Bneg[0] d0[n_max-1]=c[len(c)-1]*Bpos[len(Bpos)-1] d0[1:n_max-1]=c[0:len(c)-1]*Bpos[0:len(Bpos)-1]+c[1:len(c)]*Bneg[1:len(Bneg)] d1 = np.zeros(n_max) d1[0]=n_max d1[1:n_max]=-c* Bneg dm1 = np.zeros(n_max) dm1[n_max-1]=n_max dm1[0:n_max-1]=-c* Bpos A = sp.spdiags([dm1, d0, d1],np.array([-1,0,1]),n_max,n_max).todense() b = np.zeros(n_max)#%- A * ng ## SRH Recombination term SRHD = TAUP0 * (n + ni) + TAUN0 * (pg + ni) SRHL = n / SRHD SRHR = ni**2 / SRHD ASRH = Ucompmass (nodes,n_max,elements,Nelements,SRHL,np.ones(Nelements)) bSRH = Ucompconst (nodes,n_max,elements,Nelements,SRHR,np.ones(Nelements)) A = A + ASRH b = b + bSRH ## Boundary conditions b=np.delete(b, BCnodes, 0) b[0] = - A[1,0] * pl b[len(b)-1] = - A[n_max-2,n_max-1] * pr A=np.delete(A, BCnodes, 0) A=np.delete(A, BCnodes, 1) pp= np.linalg.solve(A,b) p=np.zeros(n_max) p[1:n_max-1]=pp p[0]=pl p[len(p)-1]=pr return p