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 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