Actual source code: ex5.c

petsc-3.3-p7 2013-05-11
  2: #define USE_FAST_MAT_SET_VALUES

  4: #include <petscsys.h>
  5: #include <petscviewer.h>

  7: #if defined(USE_FAST_MAT_SET_VALUES)
  8: #include <../src/mat/impls/aij/mpi/mpiaij.h>
  9: #define MatSetValues MatSetValues_MPIAIJ
 10: #else 
 11: #include <petscmat.h>
 12: #endif


 15: /*
 16:    Opens a separate file for each process and reads in ITS portion
 17:   of a large parallel matrix. Only requires enough memory to store
 18:   the processes portion of the matrix ONCE.

 20:     petsc-maint@mcs.anl.gov
 21: */
 24: int Mat_Parallel_Load(MPI_Comm comm,const char *name,Mat *newmat)
 25: {
 26:   Mat            A;
 27:   PetscScalar    *vals;
 29:   PetscMPIInt    rank,size;
 30:   PetscInt       i,j,rstart,rend;
 31:   PetscInt       header[4],M,N,m;
 32:   PetscInt       *ourlens,*offlens,jj,*mycols,maxnz;
 33:   PetscInt       cend,cstart,n,*rowners;
 34:   int            fd1,fd2;
 35:   PetscViewer    viewer1,viewer2;

 38:   MPI_Comm_size(comm,&size);
 39:   MPI_Comm_rank(comm,&rank);

 41:   /* Open the files; each process opens its own file */
 42:   PetscViewerBinaryOpen(PETSC_COMM_SELF,name,FILE_MODE_READ,&viewer1);
 43:   PetscViewerBinaryGetDescriptor(viewer1,&fd1);
 44:   PetscBinaryRead(fd1,(char *)header,4,PETSC_INT);

 46:   /* open the file twice so that later we can read entries from two different parts of the
 47:      file at the same time. Note that due to file caching this should not impact performance */
 48:   PetscViewerBinaryOpen(PETSC_COMM_SELF,name,FILE_MODE_READ,&viewer2);
 49:   PetscViewerBinaryGetDescriptor(viewer2,&fd2);
 50:   PetscBinaryRead(fd2,(char *)header,4,PETSC_INT);

 52:   /* error checking on files */
 53:   if (header[0] != MAT_FILE_CLASSID) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_UNEXPECTED,"not matrix object");
 54:   MPI_Allreduce(header+2,&N,1,MPI_INT,MPI_SUM,comm);
 55:   if (N != size*header[2]) SETERRQ(PETSC_COMM_SELF,1,"All files must have matrices with the same number of total columns");
 56: 
 57:   /* number of rows in matrix is sum of rows in all files */
 58:   m = header[1]; N = header[2];
 59:   MPI_Allreduce(&m,&M,1,MPI_INT,MPI_SUM,comm);

 61:   /* determine rows of matrices owned by each process */
 62:   PetscMalloc((size+1)*sizeof(PetscInt),&rowners);
 63:   MPI_Allgather(&m,1,MPIU_INT,rowners+1,1,MPIU_INT,comm);
 64:   rowners[0] = 0;
 65:   for (i=2; i<=size; i++) {
 66:     rowners[i] += rowners[i-1];
 67:   }
 68:   rstart = rowners[rank];
 69:   rend   = rowners[rank+1];
 70:   PetscFree(rowners);

 72:   /* determine column ownership if matrix is not square */
 73:   if (N != M) {
 74:     n      = N/size + ((N % size) > rank);
 75:     MPI_Scan(&n,&cend,1,MPIU_INT,MPI_SUM,comm);
 76:     cstart = cend - n;
 77:   } else {
 78:     cstart = rstart;
 79:     cend   = rend;
 80:     n      = cend - cstart;
 81:   }

 83:   /* read in local row lengths */
 84:   PetscMalloc(m*sizeof(PetscInt),&ourlens);
 85:   PetscMalloc(m*sizeof(PetscInt),&offlens);
 86:   PetscBinaryRead(fd1,ourlens,m,PETSC_INT);
 87:   PetscBinaryRead(fd2,ourlens,m,PETSC_INT);

 89:   /* determine buffer space needed for column indices of any one row*/
 90:   maxnz = 0;
 91:   for (i=0; i<m; i++) {
 92:     maxnz = PetscMax(maxnz,ourlens[i]);
 93:   }

 95:   /* allocate enough memory to hold a single row of column indices */
 96:   PetscMalloc(maxnz*sizeof(PetscInt),&mycols);

 98:   /* loop over local rows, determining number of off diagonal entries */
 99:   PetscMemzero(offlens,m*sizeof(PetscInt));
100:   for (i=0; i<m; i++) {
101:     PetscBinaryRead(fd1,mycols,ourlens[i],PETSC_INT);
102:     for (j=0; j<ourlens[i]; j++) {
103:       if (mycols[j] < cstart || mycols[j] >= cend) offlens[i]++;
104:     }
105:   }

107:   /* on diagonal entries are all that were not counted as off-diagonal */
108:   for (i=0; i<m; i++) {
109:     ourlens[i] -= offlens[i];
110:   }

112:   /* create our matrix */
113:   MatCreate(comm,&A);
114:   MatSetSizes(A,m,n,M,N);
115:   MatSetType(A,MATMPIAIJ);
116:   MatMPIAIJSetPreallocation(A,0,ourlens,0,offlens);

118:   for (i=0; i<m; i++) {
119:     ourlens[i] += offlens[i];
120:   }
121:   PetscFree(offlens);

123:   /* allocate enough memory to hold a single row of matrix values */
124:   PetscMalloc(maxnz*sizeof(PetscScalar),&vals);

126:   /* read in my part of the matrix numerical values and columns 1 row at a time and put in matrix  */
127:   jj = rstart;
128:   for (i=0; i<m; i++) {
129:     PetscBinaryRead(fd1,vals,ourlens[i],PETSC_SCALAR);
130:     PetscBinaryRead(fd2,mycols,ourlens[i],PETSC_INT);
131:     MatSetValues(A,1,&jj,ourlens[i],mycols,vals,INSERT_VALUES);
132:     jj++;
133:   }
134:   PetscFree(ourlens);
135:   PetscFree(vals);
136:   PetscFree(mycols);

138:   MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
139:   MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
140:   *newmat = A;
141:   PetscViewerDestroy(&viewer1);
142:   PetscViewerDestroy(&viewer2);
143:   return(0);
144: }

146: int main(int argc,char **args)
147: {
149:   Mat            A;
150:   char           name[1024];
151:   PetscBool      flg;

153:   PetscInitialize(&argc,&args,0,0);
154:   PetscOptionsGetString(PETSC_NULL,"-f",name,1024,&flg);
155:   if (!flg) SETERRQ(PETSC_COMM_SELF,1,"Must pass in filename with -f option");
156:   Mat_Parallel_Load(PETSC_COMM_WORLD,name,&A);
157:   MatDestroy(&A);
158:   PetscFinalize();
159:   return 0;
160: }