xref: /petsc/src/mat/impls/aij/seq/hdf5/aijhdf5.c (revision 834855d6effb0d027771461c8e947ee1ce5a1e17)
12e1d0745SJose E. Roman #include <../src/mat/impls/aij/seq/aij.h>
22e1d0745SJose E. Roman #include <petsc/private/isimpl.h>
32e1d0745SJose E. Roman #include <petsc/private/vecimpl.h>
42e1d0745SJose E. Roman #include <petsclayouthdf5.h>
52e1d0745SJose E. Roman 
MatLoad_AIJ_HDF5(Mat mat,PetscViewer viewer)62e1d0745SJose E. Roman PetscErrorCode MatLoad_AIJ_HDF5(Mat mat, PetscViewer viewer)
72e1d0745SJose E. Roman {
82e1d0745SJose E. Roman   PetscViewerFormat  format;
92e1d0745SJose E. Roman   const PetscInt    *i_glob = NULL;
102e1d0745SJose E. Roman   PetscInt          *i      = NULL;
112e1d0745SJose E. Roman   const PetscInt    *j      = NULL;
122e1d0745SJose E. Roman   const PetscScalar *a      = NULL;
132e1d0745SJose E. Roman   char              *a_name = NULL, *i_name = NULL, *j_name = NULL, *c_name = NULL;
142e1d0745SJose E. Roman   const char        *mat_name = NULL;
152e1d0745SJose E. Roman   PetscInt           p, m, M, N;
162e1d0745SJose E. Roman   PetscInt           bs = mat->rmap->bs;
172e1d0745SJose E. Roman   PetscInt          *range;
182e1d0745SJose E. Roman   PetscBool          flg;
192e1d0745SJose E. Roman   IS                 is_i = NULL, is_j = NULL;
202e1d0745SJose E. Roman   Vec                vec_a = NULL;
212e1d0745SJose E. Roman   PetscLayout        jmap  = NULL;
222e1d0745SJose E. Roman   MPI_Comm           comm;
232e1d0745SJose E. Roman   PetscMPIInt        rank, size;
242e1d0745SJose E. Roman 
252e1d0745SJose E. Roman   PetscFunctionBegin;
262e1d0745SJose E. Roman   PetscCall(PetscViewerGetFormat(viewer, &format));
272e1d0745SJose E. Roman   switch (format) {
282e1d0745SJose E. Roman   case PETSC_VIEWER_HDF5_PETSC:
292e1d0745SJose E. Roman   case PETSC_VIEWER_DEFAULT:
302e1d0745SJose E. Roman   case PETSC_VIEWER_NATIVE:
312e1d0745SJose E. Roman   case PETSC_VIEWER_HDF5_MAT:
322e1d0745SJose E. Roman     break;
332e1d0745SJose E. Roman   default:
342e1d0745SJose E. Roman     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
352e1d0745SJose E. Roman   }
362e1d0745SJose E. Roman 
372e1d0745SJose E. Roman   PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
382e1d0745SJose E. Roman   PetscCallMPI(MPI_Comm_rank(comm, &rank));
392e1d0745SJose E. Roman   PetscCallMPI(MPI_Comm_size(comm, &size));
402e1d0745SJose E. Roman   PetscCall(PetscObjectGetName((PetscObject)mat, &mat_name));
412e1d0745SJose E. Roman   if (format == PETSC_VIEWER_HDF5_MAT) {
422e1d0745SJose E. Roman     PetscCall(PetscStrallocpy("jc", &i_name));
432e1d0745SJose E. Roman     PetscCall(PetscStrallocpy("ir", &j_name));
442e1d0745SJose E. Roman     PetscCall(PetscStrallocpy("data", &a_name));
452e1d0745SJose E. Roman     PetscCall(PetscStrallocpy("MATLAB_sparse", &c_name));
462e1d0745SJose E. Roman   } else {
472e1d0745SJose E. Roman     /* TODO Once corresponding MatView is implemented, change the names to i,j,a */
482e1d0745SJose E. Roman     /* TODO Maybe there could be both namings in the file, using "symbolic link" features of HDF5. */
492e1d0745SJose E. Roman     PetscCall(PetscStrallocpy("jc", &i_name));
502e1d0745SJose E. Roman     PetscCall(PetscStrallocpy("ir", &j_name));
512e1d0745SJose E. Roman     PetscCall(PetscStrallocpy("data", &a_name));
522e1d0745SJose E. Roman     PetscCall(PetscStrallocpy("MATLAB_sparse", &c_name));
532e1d0745SJose E. Roman   }
542e1d0745SJose E. Roman 
552e1d0745SJose E. Roman   PetscOptionsBegin(comm, NULL, "Options for loading matrix from HDF5", "Mat");
562e1d0745SJose E. Roman   PetscCall(PetscOptionsInt("-matload_block_size", "Set the blocksize used to store the matrix", "MatLoad", bs, &bs, &flg));
572e1d0745SJose E. Roman   PetscOptionsEnd();
582e1d0745SJose E. Roman   if (flg) PetscCall(MatSetBlockSize(mat, bs));
592e1d0745SJose E. Roman 
602e1d0745SJose E. Roman   PetscCall(PetscViewerHDF5PushGroup(viewer, mat_name));
612e1d0745SJose E. Roman   PetscCall(PetscViewerHDF5ReadAttribute(viewer, NULL, c_name, PETSC_INT, NULL, &N));
622e1d0745SJose E. Roman   PetscCall(PetscViewerHDF5ReadSizes(viewer, i_name, NULL, &M));
632e1d0745SJose E. Roman   --M; /* i has size M+1 as there is global number of nonzeros stored at the end */
642e1d0745SJose E. Roman 
652e1d0745SJose E. Roman   if (format == PETSC_VIEWER_HDF5_MAT && mat->symmetric != PETSC_BOOL3_TRUE) {
662e1d0745SJose E. Roman     /* Swap row and columns layout for unallocated matrix. I want to avoid calling MatTranspose() just to transpose sparsity pattern and layout. */
672e1d0745SJose E. Roman     PetscLayout tmp;
68*966bd95aSPierre Jolivet     PetscCheck(!mat->preallocated, comm, PETSC_ERR_SUP, "Not for preallocated matrix - we would need to transpose it here which we want to avoid");
692e1d0745SJose E. Roman     tmp       = mat->rmap;
702e1d0745SJose E. Roman     mat->rmap = mat->cmap;
712e1d0745SJose E. Roman     mat->cmap = tmp;
722e1d0745SJose E. Roman   }
732e1d0745SJose E. Roman 
742e1d0745SJose E. Roman   /* If global sizes are set, check if they are consistent with that given in the file */
752e1d0745SJose E. Roman   PetscCheck(mat->rmap->N < 0 || mat->rmap->N == M, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Inconsistent # of rows: Matrix in file has (%" PetscInt_FMT ") and input matrix has (%" PetscInt_FMT ")", mat->rmap->N, M);
762e1d0745SJose E. Roman   PetscCheck(mat->cmap->N < 0 || mat->cmap->N == N, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Inconsistent # of cols: Matrix in file has (%" PetscInt_FMT ") and input matrix has (%" PetscInt_FMT ")", mat->cmap->N, N);
772e1d0745SJose E. Roman 
782e1d0745SJose E. Roman   /* Determine ownership of all (block) rows and columns */
792e1d0745SJose E. Roman   mat->rmap->N = M;
802e1d0745SJose E. Roman   mat->cmap->N = N;
812e1d0745SJose E. Roman   PetscCall(PetscLayoutSetUp(mat->rmap));
822e1d0745SJose E. Roman   PetscCall(PetscLayoutSetUp(mat->cmap));
832e1d0745SJose E. Roman   m = mat->rmap->n;
842e1d0745SJose E. Roman 
852e1d0745SJose E. Roman   /* Read array i (array of row indices) */
862e1d0745SJose E. Roman   PetscCall(PetscMalloc1(m + 1, &i)); /* allocate i with one more position for local number of nonzeros on each rank */
872e1d0745SJose E. Roman   i[0] = i[m] = 0;                    /* make the last entry always defined - the code block below overwrites it just on last rank */
882e1d0745SJose E. Roman   if (rank == size - 1) m++;          /* in the loaded array i_glob, only the last rank has one more position with the global number of nonzeros */
892e1d0745SJose E. Roman   M++;
902e1d0745SJose E. Roman   PetscCall(ISCreate(comm, &is_i));
912e1d0745SJose E. Roman   PetscCall(PetscObjectSetName((PetscObject)is_i, i_name));
922e1d0745SJose E. Roman   PetscCall(PetscLayoutSetLocalSize(is_i->map, m));
932e1d0745SJose E. Roman   PetscCall(PetscLayoutSetSize(is_i->map, M));
942e1d0745SJose E. Roman   PetscCall(ISLoad(is_i, viewer));
952e1d0745SJose E. Roman   PetscCall(ISGetIndices(is_i, &i_glob));
962e1d0745SJose E. Roman   PetscCall(PetscArraycpy(i, i_glob, m));
972e1d0745SJose E. Roman 
982e1d0745SJose E. Roman   /* Reset m and M to the matrix sizes */
992e1d0745SJose E. Roman   m = mat->rmap->n;
1002e1d0745SJose E. Roman   M--;
1012e1d0745SJose E. Roman 
1022e1d0745SJose E. Roman   /* Create PetscLayout for j and a vectors; construct ranges first */
1032e1d0745SJose E. Roman   PetscCall(PetscMalloc1(size + 1, &range));
1042e1d0745SJose E. Roman   PetscCallMPI(MPI_Allgather(i, 1, MPIU_INT, range, 1, MPIU_INT, comm));
1052e1d0745SJose E. Roman   /* Last rank has global number of nonzeros (= length of j and a arrays) in i[m] (last i entry) so broadcast it */
1062e1d0745SJose E. Roman   range[size] = i[m];
1072e1d0745SJose E. Roman   PetscCallMPI(MPI_Bcast(&range[size], 1, MPIU_INT, size - 1, comm));
1082e1d0745SJose E. Roman   for (p = size - 1; p > 0; p--) {
1092e1d0745SJose E. Roman     if (!range[p]) range[p] = range[p + 1]; /* for ranks with 0 rows, take the value from the next processor */
1102e1d0745SJose E. Roman   }
1112e1d0745SJose E. Roman   i[m] = range[rank + 1]; /* i[m] (last i entry) is equal to next rank's offset */
1122e1d0745SJose E. Roman   /* Deduce rstart, rend, n and N from the ranges */
1132e1d0745SJose E. Roman   PetscCall(PetscLayoutCreateFromRanges(comm, range, PETSC_OWN_POINTER, 1, &jmap));
1142e1d0745SJose E. Roman 
1152e1d0745SJose E. Roman   /* Convert global to local indexing of rows */
1162e1d0745SJose E. Roman   for (p = 1; p < m + 1; ++p) i[p] -= i[0];
1172e1d0745SJose E. Roman   i[0] = 0;
1182e1d0745SJose E. Roman 
1192e1d0745SJose E. Roman   /* Read array j (array of column indices) */
1202e1d0745SJose E. Roman   PetscCall(ISCreate(comm, &is_j));
1212e1d0745SJose E. Roman   PetscCall(PetscObjectSetName((PetscObject)is_j, j_name));
1222e1d0745SJose E. Roman   PetscCall(PetscLayoutDuplicate(jmap, &is_j->map));
1232e1d0745SJose E. Roman   PetscCall(ISLoad(is_j, viewer));
1242e1d0745SJose E. Roman   PetscCall(ISGetIndices(is_j, &j));
1252e1d0745SJose E. Roman 
1262e1d0745SJose E. Roman   /* Read array a (array of values) */
1272e1d0745SJose E. Roman   PetscCall(VecCreate(comm, &vec_a));
1282e1d0745SJose E. Roman   PetscCall(PetscObjectSetName((PetscObject)vec_a, a_name));
1292e1d0745SJose E. Roman   PetscCall(PetscLayoutDuplicate(jmap, &vec_a->map));
1302e1d0745SJose E. Roman   PetscCall(VecLoad(vec_a, viewer));
1312e1d0745SJose E. Roman   PetscCall(VecGetArrayRead(vec_a, &a));
1322e1d0745SJose E. Roman 
1332e1d0745SJose E. Roman   /* populate matrix */
1342e1d0745SJose E. Roman   if (!((PetscObject)mat)->type_name) PetscCall(MatSetType(mat, MATAIJ));
1352e1d0745SJose E. Roman   PetscCall(MatSeqAIJSetPreallocationCSR(mat, i, j, a));
1362e1d0745SJose E. Roman   PetscCall(MatMPIAIJSetPreallocationCSR(mat, i, j, a));
1372e1d0745SJose E. Roman   /*
1382e1d0745SJose E. Roman   PetscCall(MatSeqBAIJSetPreallocationCSR(mat,bs,i,j,a));
1392e1d0745SJose E. Roman   PetscCall(MatMPIBAIJSetPreallocationCSR(mat,bs,i,j,a));
1402e1d0745SJose E. Roman   */
1412e1d0745SJose E. Roman 
1422e1d0745SJose E. Roman   if (format == PETSC_VIEWER_HDF5_MAT && mat->symmetric != PETSC_BOOL3_TRUE) {
1432e1d0745SJose E. Roman     /* Transpose the input matrix back */
1442e1d0745SJose E. Roman     PetscCall(MatTranspose(mat, MAT_INPLACE_MATRIX, &mat));
1452e1d0745SJose E. Roman   }
1462e1d0745SJose E. Roman 
1472e1d0745SJose E. Roman   PetscCall(PetscViewerHDF5PopGroup(viewer));
1482e1d0745SJose E. Roman   PetscCall(PetscFree(i_name));
1492e1d0745SJose E. Roman   PetscCall(PetscFree(j_name));
1502e1d0745SJose E. Roman   PetscCall(PetscFree(a_name));
1512e1d0745SJose E. Roman   PetscCall(PetscFree(c_name));
1522e1d0745SJose E. Roman   PetscCall(PetscLayoutDestroy(&jmap));
1532e1d0745SJose E. Roman   PetscCall(PetscFree(i));
1542e1d0745SJose E. Roman   PetscCall(ISRestoreIndices(is_i, &i_glob));
1552e1d0745SJose E. Roman   PetscCall(ISRestoreIndices(is_j, &j));
1562e1d0745SJose E. Roman   PetscCall(VecRestoreArrayRead(vec_a, &a));
1572e1d0745SJose E. Roman   PetscCall(ISDestroy(&is_i));
1582e1d0745SJose E. Roman   PetscCall(ISDestroy(&is_j));
1592e1d0745SJose E. Roman   PetscCall(VecDestroy(&vec_a));
1602e1d0745SJose E. Roman   PetscFunctionReturn(PETSC_SUCCESS);
1612e1d0745SJose E. Roman }
162