def PoissonSolveFem(xmax,nelx,no,bval,dens): bdcon=array([1,1,1,1,1,1]) # these bc's to for non zero Dirichlet tx=linspace(0.0,1.0,nelx+1) # nodes quadratically scaled around origin! t2=tx**2 tm=(-t2).tolist() tm.reverse() t=array(tm[:-1]+t2.tolist()) print t x=y=z=t*xmax print x print y print z box=fem3d(x,y,z,no,bdcon) def v(xx,yy,zz): val=0.0 return val def w(xx,yy,zz): return 1.0 def IsOnBoundary(x,y,z): # this function returns True if (x,y,z) is on the Boundary if (abs(x) == xmax or abs(y) ==xmax or abs(z) == xmax): val= True else: val= False return val def bval1(x,y,z): # returns phi (x,y,z) for (x,y,z) on the boundary # but otherwise zero if IsOnBoundary(x,y,z): return bval(x,y,z) else: return 0.0 box.calc_mat(v,w) nodes=box.gn # K=box.All # Matrix representing negative Laplace operator U=box.Mll # Overlap matrix between basis functions N0=K.shape[0] # Order of matrix including boundary DOF # rho is density at points of FEM grid rho=array([dens(x,y,z) for (x,y,z) in nodes]) # mask is needed for pysparse mask=array([1-IsOnBoundary(x,y,z) for (x,y,z) in nodes]) bcv=array([bval1(x,y,z) for (x,y,z) in nodes]) K0bcv=empty(N0) # convert K to sparse skyline format K0=K.to_sss() # calculate ( K_{01}+K_{11}) c_1 K0.matvec(bcv,K0bcv) # modify matrix K to implement Boundary Condition # all rows and columns corresponding to boundary nodes are deleted from the matrix K.delete_rowcols(mask) N1=K.shape[0] # Order of matrix without boundary dof's print K.shape # create new list of global nodes as newnodes=array([nodes[i] for i in range(N0) if mask[i] ==1 ]) # create indices for new nodes in old nodes ii=zeros(N1,"i") j=0 for i in range(N0): if mask[i] == 1: ii[j]=i j=j+1 # convert K to compressed sparse row format K1=K.to_csr() # convert U to sparse skyline format M=U.to_sss() b=empty(N0) # calculate U rho on whole domain including boundary M.matvec(rho,b) b=b-K0bcv # project on interior space yielding RHS of (8) b1=array([ b[i] for i in range(N0) if mask[i] == 1 ]) pot=empty(N1) t0=time() # calculate LU factorization using the superlu module from pysparse LU=superlu.factorize(K1) t1=time() print "time taken for factorization of K1:", t1-t0 t0=time() LU.solve(b1,pot) t1=time() print "time taken to solve Laplace equation using LU Decomposition :", t1-t0 pot0=empty(N0) # the following code fills the vector pot0 with the boundary values # of the potential at the corresponding positions for i in range(N0): if mask[i] ==0: x,y,z=nodes[i] pot0[i]=bval(x,y,z) pot0[ii]=pot # making use of the interpolation functionality provided by fem3d # define a function that returns the values at of the resulting potential # at the points defined by (xi[k],yi[k],zi[k]) def potf(xi,yi,zi): return box.wave(xi,yi,zi,pot0) # the following lines define xi,yi,zi along a line with constant y and z-values # from -xmax to xmax xi=linspace(-xmax,xmax,1001) yi=zi=zeros(1001,"i") poti=potf(xi,yi,zi) #open file to write potential values to pfile=open("pot_direct_xmax=%f_nel=%d_no=%d.dat" % (xmax,2*nelx,no), "w") print >> pfile, "# N0=",N0, "N1=",N1 for x,p in zip(xi,poti): print >> pfile, x,p,p-exactpot(x,0,0) pfile.close()
def PoissonSolveFem(xmax,nelx,no,bval,dens): bdcon=array([1,1,1,1,1,1]) # these bc's to for non zero Dirichlet tx=linspace(0.0,1.0,nelx+1) # nodes quadratically scaled around origin! t2=tx**2 tm=(-t2).tolist() tm.reverse() t=array(tm[:-1]+t2.tolist()) print t x=y=z=t*xmax print x print y print z # Calculate global Gauss Legendre Grid xgl,wgl=NodesToGLGrid(x) gp=array(list_prod(xgl,xgl,xgl)) tmp=array(list_prod(wgl,wgl,wgl)) gwts=array([xw*yw*zw for xw,yw,zw in zip(tmp[:,0],tmp[:,1],tmp[:,2])]) # box=fem3d(x,y,z,no,bdcon) def v(xx,yy,zz): val=0.0 return val def w(xx,yy,zz): return 1.0 def IsOnBoundary(x,y,z): # this function returns True if (x,y,z) is on the Boundary if (abs(x) == xmax or abs(y) ==xmax or abs(z) == xmax): val= True else: val= False return val def bval1(x,y,z): # returns phi (x,y,z) for (x,y,z) on the boundary # but otherwise zero if IsOnBoundary(x,y,z): return bval(x,y,z) else: return 0.0 box.calc_mat(v,w) nodes=box.gn # K=box.All # Matrix representing negative Laplace operator U=box.Mll # Overlap matrix between basis functions N0=K.shape[0] # Order of matrix including boundary DOF # rho is density at points of FEM grid rho=array([dens(x,y,z) for (x,y,z) in nodes]) # mask is needed for pysparse mask=array([1-IsOnBoundary(x,y,z) for (x,y,z) in nodes]) bcv=array([bval1(x,y,z) for (x,y,z) in nodes]) K0bcv=empty(N0) # convert K to sparse skyline format K0=K.to_sss() # calculate ( K_{01}+K_{11}) c_1 K0.matvec(bcv,K0bcv) # modify matrix K to implement Boundary Condition # all rows and columns corresponding to boundary nodes are deleted from the matrix K.delete_rowcols(mask) N1=K.shape[0] # Order of matrix without boundary DOF print K.shape # create new list of global nodes as newnodes=array([nodes[i] for i in range(N0) if mask[i] ==1 ]) # create indices for new nodes in old nodes ii=zeros(N1,"i") j=0 for i in range(N0): if mask[i] == 1: ii[j]=i j=j+1 # convert K to sparse skyline format K1=K.to_sss() # convert U to sparse skyline format M=U.to_sss() b=empty(N0) # calculate U r on whole domain including boundary M.matvec(rho,b) b=b-K0bcv # project on interior space yielding RHS of (8) b1=array([ b[i] for i in range(N0) if mask[i] == 1 ]) pot=empty(N1) # specify parameters for iterative solver maxit=20000 tol=1e-15 # call qmrs from pysparse.itsolvers t0=time() info,iter,relres=itsolvers.qmrs(K1,b1,pot,tol,maxit) t1=time() print info,iter,relres print "time taken to solve Laplace equation using LU Decomposition :", t1-t0 pot0=empty(N0) # the following code fills the vector pot0 with the boundary values # of the potential at the corresponding positions for i in range(N0): if mask[i] ==0: x,y,z=nodes[i] pot0[i]=bval(x,y,z) pot0[ii]=pot def potf(xi,yi,zi): return box.wave(xi,yi,zi,pot0) def gradpotf(xi,yi,zi): return box.gradwave(xi,yi,zi,pot0) # first plot resulting pot along a line xi=linspace(-xmax,xmax,1001) yi=zi=zeros(1001,"i") poti=potf(xi,yi,zi) dpoti=poti-array([exactpot(xx,0,0) for xx in xi]) hx=2*xmax/1000.0 errsq=2*hx*pi*sum(xi**2*dpoti**2) err=sqrt(errsq) # the following evaluates the potential at all points of the # Gauss-Legendre Grid and also evaluates the difference # to the exact solution as well as the norm of the error pot3atgp=potf(gp[:,0],gp[:,1],gp[:,2]) dpot3atgp=pot3atgp-array([exactpot(xx,yy,zz) for xx,yy,zz in zip(gp[:,0],gp[:,1],gp[:,2])]) errsq3d=sum(gwts*dpot3atgp**2) err3d=sqrt(errsq3d) # Test gradient at point (1.0,1.0,1.0) and compare with grad of exact solution print "GRADIENT at 1,1,1:",gradpotf([1.0,],[1.0,],[1.0,]),gradexactpot(1.0,1.0,1.0) # the same as above but now for the gradient of the potential in comparison to the # gradient of the exact solution tmp1=array(gradpotf(gp[:,0],gp[:,1],gp[:,2])) tmp2=array(gradexactpot(gp[:,0],gp[:,1],gp[:,2])) tmp=tmp1-tmp2 errgradsq=sum(gwts*(tmp[0]**2+tmp[1]**2+tmp[2]**2)) errgrad=sqrt(errgradsq) # open file to which the 1D plot is written pfile=open("pot_xmax=%f_nel=%d_no=%d.dat" % (xmax,2*nelx,no), "w") print >> pfile, "#","N0=",N0, "N1=",N1, "ERR=",err ,"ERR3=",err3d, "ERRGRAD=",errgrad for x,p,dp in zip(xi,poti,dpoti): print >> pfile, x,p,dp pfile.close() # now prepare plot in the plane z=0 xi=yi=linspace(-xmax,xmax,129) xyz=array(list_prod(xi,yi,[0.0,])) poti2d=potf(xyz[:,0],xyz[:,1],xyz[:,2]) dpoti2d=poti2d-array([exactpot(xx,yy,0) for xx,yy in zip(xyz[:,0],xyz[:,1])]) tmp1=array(gradpotf(xyz[:,0],xyz[:,1],xyz[:,2])) tmp2=array(gradexactpot(xyz[:,0],xyz[:,1],xyz[:,2])) tmp=tmp1-tmp2 dgrad2d=tmp[0]**2+tmp[1]**2+tmp[2]**2 # open file to which the surface plot is written pfile=open("pot2d_xmax=%f_nel=%d_no=%d.dat" % (xmax,2*nelx,no), "w") print >> pfile, "#","N0=",N0, "N1=",N1 i=0 for p,pot,dp,dg in zip(xyz,poti2d,dpoti2d,dgrad2d): x,y,z=p print >> pfile, x,y,pot,pot-exactpot(x,y,z),dp,dg i=i+1 if i % 129 == 0: print >> pfile pfile.close()