PETSc是Portable, ExtensibleToolkit for Scientific Computation的缩写,是美国能源部开发的科学计算可移植扩展工具包,其基于MPI实现在分布式内存环境下实现偏微分方程和线性方程组的求解。
对于线性方程组的求解,PETSc提供了较为全面的迭代方法求解,尤其是基于Krylov方法的各种迭代方法及各种预处理方法。在PETSc中,支持的krylov方法可通过KspSetType进行设置,具体支持的KspType如下:
typedef const char *KSPType;
在上面的方法中,有限元求解中常用的CG,Bicgstab,Gmres均有涉及。同时,当ksptype为preonly时,表明方程组不采用迭代求解,只采用预处理方法直接求解方程组,因此此时实际上就实现了线性方程组的直接法求解。
对于预处理方法,PETSc支持的方法如下:
typedef const char *PCType;
在PETSc提供的上述方法的基础上,我们可以进行各种求解方法的求解测试,从而获得各种求解方法面对各种问题的具体性能。
另外一方面,在PETSc中,通过Mat和Vec定义的矩阵和向量可以依据具体insert的值自动组装成整体矩阵或者向量,这对于稀疏矩阵线性方程组的求解具有十分重要的意义。例如,在固体力学有限元求解中,如果手动组装稀疏矩阵存储的刚度矩阵,实际上需要依据单元节点连接获得节点的邻接矩阵从而确定每行的非零元素个数与位置。而如果采用PETSc,则可以直接定义整体刚度矩阵的Mat,再将各个单元的单元刚度矩阵逐个insert进整体刚度矩阵的Mat,PETSc就会自动形成最终的整体稀疏刚度矩阵。另外,在求解时对于矩阵和向量PETSc会自动进行MPI进程分割完成最终求解。
以下是一个从文件中读取矩阵和向量并求解AX=B的例子:
static char help[]="linear solve";#include <petscmat.h>#include <petscksp.h>#undef __FUNCT__#define __FUNCT__ "main"int main(int argc,char **args){Mat A;Vec b,u,u_tmp,x;char Ain[PETSC_MAX_PATH_LEN],rhs[PETSC_MAX_PATH_LEN];PetscErrorCode ierr;int m,n,nz,dummy;PetscInt i,col,row,rstart,rend,rstart1,rend1;;PetscScalar val;FILE *Afile,*bfile;PetscViewer view;PetscBool ***_A,***_b,***;PetscMPIInt size,rank;int shift;KSP ksp;PC pc;*)0,help);ierr = MPI_Comm_size(PETSC_COMM_WORLD,&size);CHKERRQ(ierr);ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank);CHKERRQ(ierr);ierr = PetscOptionsGetString(PETSC_NULL,PETSC_NULL,"-Ain",Ain,PETSC_MAX_PATH_LEN,&***_A);CHKERRQ(ierr);if (***) shift = 0;if (***_A){ierr = PetscPrintf(PETSC_COMM_WORLD,"\n Read matrix in ascii format ...\n");CHKERRQ(ierr);Afile=fopen(Ain,"r");%d %d\n",&m,&n,&nz);= PetscPrintf(PETSC_COMM_WORLD,"m: %d, n: %d, nz: %d \n", m,n,nz);CHKERRQ(ierr);if (m != n) SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_ARG_SIZ, "Number of rows, cols must be same for this example\n");ierr = MatCreate(PETSC_COMM_WORLD,&A);CHKERRQ(ierr);ierr = MatSetSizes(A,PETSC_DECIDE,PETSC_DECIDE,m,n);CHKERRQ(ierr);ierr = MatSetFromOptions(A);CHKERRQ(ierr);PetscCall(MatSetUp(A));ierr = MatGetOwnershipRange(A,&rstart,&rend);CHKERRQ(ierr);printf("\nThis is process %d reading from %d to %d ...\n",rank,rstart,rend-1);for (i=0; i<nz; i++) {%d %le\n",&row,&col,(double*)&val);if (row>=rstart && row<rend)ierr = MatSetValues(A,1,&row,1,&col,&val,INSERT_VALUES);CHKERRQ(ierr);}ierr = MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);ierr = MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);fflush(stdout);fclose(Afile);}ierr = PetscOptionsGetString(PETSC_NULL,PETSC_NULL,"-rhs",rhs,PETSC_MAX_PATH_LEN,&***_b);CHKERRQ(ierr);ierr = PetscOptionsGetString(PETSC_NULL,PETSC_NULL,"-rhs",rhs,PETSC_MAX_PATH_LEN,&***_b);CHKERRQ(ierr);if (***_b){ierr = VecCreate(PETSC_COMM_WORLD,&b);CHKERRQ(ierr);ierr = VecSetSizes(b,PETSC_DECIDE,n);CHKERRQ(ierr);ierr = VecSetFromOptions(b);CHKERRQ(ierr);ierr = VecGetOwnershipRange(b,&rstart1,&rend1);CHKERRQ(ierr);printf("\nThis is process %d reading from %d to %d ...\n",rank,rstart1,rend1-1);bfile = fopen(rhs,"r");for (i=0; i<n; i++) {%le\n",&dummy,(double*)&val);if (dummy>=rstart1 && dummy<rend1)ierr = VecSetValues(b,1,&i,&val,INSERT_VALUES);CHKERRQ(ierr);}ierr = VecAssemblyBegin(b);CHKERRQ(ierr);ierr = VecAssemblyEnd(b);CHKERRQ(ierr);fflush(stdout);fclose(bfile);}= PetsfcPrint(PETSC_COMM_WORLD,"\n Write matrix in binary to 'matrix.dat' ...\n");CHKERRQ(ierr);ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,"matrix.dat",FILE_MODE_WRITE,&view);CHKERRQ(ierr);ierr = MatView(A,view);CHKERRQ(ierr);if (***_b){ierr = PetscPrintf(PETSC_COMM_WORLD,"\n Write rhs in binary to 'matrix.dat' ...\n");CHKERRQ(ierr);ierr = VecView(b,view);CHKERRQ(ierr);}ierr = MatDestroy(&A);CHKERRQ(ierr);if (***_b) {ierr = VecDestroy(&b);CHKERRQ(ierr);}ierr = PetscViewerDestroy(&view);CHKERRQ(ierr);*/&x));PetscLogDouble start_time,end_time,time;PetscTime(&start_time);&ksp));A, A));&pc));PCJACOBI));PetscCall(KSPSetType(ksp,KSPCG));1.e-6, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT));PetscCall(KSPSetFromOptions(ksp));b, x));PetscTime(&end_time);time = end_time - start_time;"\n%-15s%-7.5f seconds\n", "Average time:",time );VecView(x,PETSC_VIEWER_STDOUT_WORLD));PetscCall(KSPDestroy(&ksp));PetscCall(VecDestroy(&x));PetscCall(MatDestroy(&A));ierr = PetscFinalize();return 0;}
具体的运行命令如下:
mpiexec -n 10 ./solve -Ain mat1.txt -rhs vec1.txt其中mat1.txt的文件格式采用COO(第一行是行数,列数和非0元素个数):

Vec1.txt的文件格式如下(第1列是行号,第二列是数值):

最终结果:

以上,就是PETSc的简单介绍和一个简单例子,感谢您的阅读!
【完】