1*2e1d0745SJose E. Roman #include <../src/mat/impls/aij/seq/aij.h> 2*2e1d0745SJose E. Roman #include <petsc/private/isimpl.h> 3*2e1d0745SJose E. Roman #include <petsc/private/vecimpl.h> 4*2e1d0745SJose E. Roman #include <petsclayouthdf5.h> 5*2e1d0745SJose E. Roman 6*2e1d0745SJose E. Roman PetscErrorCode MatLoad_AIJ_HDF5(Mat mat, PetscViewer viewer) 7*2e1d0745SJose E. Roman { 8*2e1d0745SJose E. Roman PetscViewerFormat format; 9*2e1d0745SJose E. Roman const PetscInt *i_glob = NULL; 10*2e1d0745SJose E. Roman PetscInt *i = NULL; 11*2e1d0745SJose E. Roman const PetscInt *j = NULL; 12*2e1d0745SJose E. Roman const PetscScalar *a = NULL; 13*2e1d0745SJose E. Roman char *a_name = NULL, *i_name = NULL, *j_name = NULL, *c_name = NULL; 14*2e1d0745SJose E. Roman const char *mat_name = NULL; 15*2e1d0745SJose E. Roman PetscInt p, m, M, N; 16*2e1d0745SJose E. Roman PetscInt bs = mat->rmap->bs; 17*2e1d0745SJose E. Roman PetscInt *range; 18*2e1d0745SJose E. Roman PetscBool flg; 19*2e1d0745SJose E. Roman IS is_i = NULL, is_j = NULL; 20*2e1d0745SJose E. Roman Vec vec_a = NULL; 21*2e1d0745SJose E. Roman PetscLayout jmap = NULL; 22*2e1d0745SJose E. Roman MPI_Comm comm; 23*2e1d0745SJose E. Roman PetscMPIInt rank, size; 24*2e1d0745SJose E. Roman 25*2e1d0745SJose E. Roman PetscFunctionBegin; 26*2e1d0745SJose E. Roman PetscCall(PetscViewerGetFormat(viewer, &format)); 27*2e1d0745SJose E. Roman switch (format) { 28*2e1d0745SJose E. Roman case PETSC_VIEWER_HDF5_PETSC: 29*2e1d0745SJose E. Roman case PETSC_VIEWER_DEFAULT: 30*2e1d0745SJose E. Roman case PETSC_VIEWER_NATIVE: 31*2e1d0745SJose E. Roman case PETSC_VIEWER_HDF5_MAT: 32*2e1d0745SJose E. Roman break; 33*2e1d0745SJose E. Roman default: 34*2e1d0745SJose E. Roman SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 35*2e1d0745SJose E. Roman } 36*2e1d0745SJose E. Roman 37*2e1d0745SJose E. Roman PetscCall(PetscObjectGetComm((PetscObject)mat, &comm)); 38*2e1d0745SJose E. Roman PetscCallMPI(MPI_Comm_rank(comm, &rank)); 39*2e1d0745SJose E. Roman PetscCallMPI(MPI_Comm_size(comm, &size)); 40*2e1d0745SJose E. Roman PetscCall(PetscObjectGetName((PetscObject)mat, &mat_name)); 41*2e1d0745SJose E. Roman if (format == PETSC_VIEWER_HDF5_MAT) { 42*2e1d0745SJose E. Roman PetscCall(PetscStrallocpy("jc", &i_name)); 43*2e1d0745SJose E. Roman PetscCall(PetscStrallocpy("ir", &j_name)); 44*2e1d0745SJose E. Roman PetscCall(PetscStrallocpy("data", &a_name)); 45*2e1d0745SJose E. Roman PetscCall(PetscStrallocpy("MATLAB_sparse", &c_name)); 46*2e1d0745SJose E. Roman } else { 47*2e1d0745SJose E. Roman /* TODO Once corresponding MatView is implemented, change the names to i,j,a */ 48*2e1d0745SJose E. Roman /* TODO Maybe there could be both namings in the file, using "symbolic link" features of HDF5. */ 49*2e1d0745SJose E. Roman PetscCall(PetscStrallocpy("jc", &i_name)); 50*2e1d0745SJose E. Roman PetscCall(PetscStrallocpy("ir", &j_name)); 51*2e1d0745SJose E. Roman PetscCall(PetscStrallocpy("data", &a_name)); 52*2e1d0745SJose E. Roman PetscCall(PetscStrallocpy("MATLAB_sparse", &c_name)); 53*2e1d0745SJose E. Roman } 54*2e1d0745SJose E. Roman 55*2e1d0745SJose E. Roman PetscOptionsBegin(comm, NULL, "Options for loading matrix from HDF5", "Mat"); 56*2e1d0745SJose E. Roman PetscCall(PetscOptionsInt("-matload_block_size", "Set the blocksize used to store the matrix", "MatLoad", bs, &bs, &flg)); 57*2e1d0745SJose E. Roman PetscOptionsEnd(); 58*2e1d0745SJose E. Roman if (flg) PetscCall(MatSetBlockSize(mat, bs)); 59*2e1d0745SJose E. Roman 60*2e1d0745SJose E. Roman PetscCall(PetscViewerHDF5PushGroup(viewer, mat_name)); 61*2e1d0745SJose E. Roman PetscCall(PetscViewerHDF5ReadAttribute(viewer, NULL, c_name, PETSC_INT, NULL, &N)); 62*2e1d0745SJose E. Roman PetscCall(PetscViewerHDF5ReadSizes(viewer, i_name, NULL, &M)); 63*2e1d0745SJose E. Roman --M; /* i has size M+1 as there is global number of nonzeros stored at the end */ 64*2e1d0745SJose E. Roman 65*2e1d0745SJose E. Roman if (format == PETSC_VIEWER_HDF5_MAT && mat->symmetric != PETSC_BOOL3_TRUE) { 66*2e1d0745SJose E. Roman /* Swap row and columns layout for unallocated matrix. I want to avoid calling MatTranspose() just to transpose sparsity pattern and layout. */ 67*2e1d0745SJose E. Roman if (!mat->preallocated) { 68*2e1d0745SJose E. Roman PetscLayout tmp; 69*2e1d0745SJose E. Roman tmp = mat->rmap; 70*2e1d0745SJose E. Roman mat->rmap = mat->cmap; 71*2e1d0745SJose E. Roman mat->cmap = tmp; 72*2e1d0745SJose E. Roman } else SETERRQ(comm, PETSC_ERR_SUP, "Not for preallocated matrix - we would need to transpose it here which we want to avoid"); 73*2e1d0745SJose E. Roman } 74*2e1d0745SJose E. Roman 75*2e1d0745SJose E. Roman /* If global sizes are set, check if they are consistent with that given in the file */ 76*2e1d0745SJose 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); 77*2e1d0745SJose 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); 78*2e1d0745SJose E. Roman 79*2e1d0745SJose E. Roman /* Determine ownership of all (block) rows and columns */ 80*2e1d0745SJose E. Roman mat->rmap->N = M; 81*2e1d0745SJose E. Roman mat->cmap->N = N; 82*2e1d0745SJose E. Roman PetscCall(PetscLayoutSetUp(mat->rmap)); 83*2e1d0745SJose E. Roman PetscCall(PetscLayoutSetUp(mat->cmap)); 84*2e1d0745SJose E. Roman m = mat->rmap->n; 85*2e1d0745SJose E. Roman 86*2e1d0745SJose E. Roman /* Read array i (array of row indices) */ 87*2e1d0745SJose E. Roman PetscCall(PetscMalloc1(m + 1, &i)); /* allocate i with one more position for local number of nonzeros on each rank */ 88*2e1d0745SJose E. Roman i[0] = i[m] = 0; /* make the last entry always defined - the code block below overwrites it just on last rank */ 89*2e1d0745SJose 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 */ 90*2e1d0745SJose E. Roman M++; 91*2e1d0745SJose E. Roman PetscCall(ISCreate(comm, &is_i)); 92*2e1d0745SJose E. Roman PetscCall(PetscObjectSetName((PetscObject)is_i, i_name)); 93*2e1d0745SJose E. Roman PetscCall(PetscLayoutSetLocalSize(is_i->map, m)); 94*2e1d0745SJose E. Roman PetscCall(PetscLayoutSetSize(is_i->map, M)); 95*2e1d0745SJose E. Roman PetscCall(ISLoad(is_i, viewer)); 96*2e1d0745SJose E. Roman PetscCall(ISGetIndices(is_i, &i_glob)); 97*2e1d0745SJose E. Roman PetscCall(PetscArraycpy(i, i_glob, m)); 98*2e1d0745SJose E. Roman 99*2e1d0745SJose E. Roman /* Reset m and M to the matrix sizes */ 100*2e1d0745SJose E. Roman m = mat->rmap->n; 101*2e1d0745SJose E. Roman M--; 102*2e1d0745SJose E. Roman 103*2e1d0745SJose E. Roman /* Create PetscLayout for j and a vectors; construct ranges first */ 104*2e1d0745SJose E. Roman PetscCall(PetscMalloc1(size + 1, &range)); 105*2e1d0745SJose E. Roman PetscCallMPI(MPI_Allgather(i, 1, MPIU_INT, range, 1, MPIU_INT, comm)); 106*2e1d0745SJose E. Roman /* Last rank has global number of nonzeros (= length of j and a arrays) in i[m] (last i entry) so broadcast it */ 107*2e1d0745SJose E. Roman range[size] = i[m]; 108*2e1d0745SJose E. Roman PetscCallMPI(MPI_Bcast(&range[size], 1, MPIU_INT, size - 1, comm)); 109*2e1d0745SJose E. Roman for (p = size - 1; p > 0; p--) { 110*2e1d0745SJose E. Roman if (!range[p]) range[p] = range[p + 1]; /* for ranks with 0 rows, take the value from the next processor */ 111*2e1d0745SJose E. Roman } 112*2e1d0745SJose E. Roman i[m] = range[rank + 1]; /* i[m] (last i entry) is equal to next rank's offset */ 113*2e1d0745SJose E. Roman /* Deduce rstart, rend, n and N from the ranges */ 114*2e1d0745SJose E. Roman PetscCall(PetscLayoutCreateFromRanges(comm, range, PETSC_OWN_POINTER, 1, &jmap)); 115*2e1d0745SJose E. Roman 116*2e1d0745SJose E. Roman /* Convert global to local indexing of rows */ 117*2e1d0745SJose E. Roman for (p = 1; p < m + 1; ++p) i[p] -= i[0]; 118*2e1d0745SJose E. Roman i[0] = 0; 119*2e1d0745SJose E. Roman 120*2e1d0745SJose E. Roman /* Read array j (array of column indices) */ 121*2e1d0745SJose E. Roman PetscCall(ISCreate(comm, &is_j)); 122*2e1d0745SJose E. Roman PetscCall(PetscObjectSetName((PetscObject)is_j, j_name)); 123*2e1d0745SJose E. Roman PetscCall(PetscLayoutDuplicate(jmap, &is_j->map)); 124*2e1d0745SJose E. Roman PetscCall(ISLoad(is_j, viewer)); 125*2e1d0745SJose E. Roman PetscCall(ISGetIndices(is_j, &j)); 126*2e1d0745SJose E. Roman 127*2e1d0745SJose E. Roman /* Read array a (array of values) */ 128*2e1d0745SJose E. Roman PetscCall(VecCreate(comm, &vec_a)); 129*2e1d0745SJose E. Roman PetscCall(PetscObjectSetName((PetscObject)vec_a, a_name)); 130*2e1d0745SJose E. Roman PetscCall(PetscLayoutDuplicate(jmap, &vec_a->map)); 131*2e1d0745SJose E. Roman PetscCall(VecLoad(vec_a, viewer)); 132*2e1d0745SJose E. Roman PetscCall(VecGetArrayRead(vec_a, &a)); 133*2e1d0745SJose E. Roman 134*2e1d0745SJose E. Roman /* populate matrix */ 135*2e1d0745SJose E. Roman if (!((PetscObject)mat)->type_name) PetscCall(MatSetType(mat, MATAIJ)); 136*2e1d0745SJose E. Roman PetscCall(MatSeqAIJSetPreallocationCSR(mat, i, j, a)); 137*2e1d0745SJose E. Roman PetscCall(MatMPIAIJSetPreallocationCSR(mat, i, j, a)); 138*2e1d0745SJose E. Roman /* 139*2e1d0745SJose E. Roman PetscCall(MatSeqBAIJSetPreallocationCSR(mat,bs,i,j,a)); 140*2e1d0745SJose E. Roman PetscCall(MatMPIBAIJSetPreallocationCSR(mat,bs,i,j,a)); 141*2e1d0745SJose E. Roman */ 142*2e1d0745SJose E. Roman 143*2e1d0745SJose E. Roman if (format == PETSC_VIEWER_HDF5_MAT && mat->symmetric != PETSC_BOOL3_TRUE) { 144*2e1d0745SJose E. Roman /* Transpose the input matrix back */ 145*2e1d0745SJose E. Roman PetscCall(MatTranspose(mat, MAT_INPLACE_MATRIX, &mat)); 146*2e1d0745SJose E. Roman } 147*2e1d0745SJose E. Roman 148*2e1d0745SJose E. Roman PetscCall(PetscViewerHDF5PopGroup(viewer)); 149*2e1d0745SJose E. Roman PetscCall(PetscFree(i_name)); 150*2e1d0745SJose E. Roman PetscCall(PetscFree(j_name)); 151*2e1d0745SJose E. Roman PetscCall(PetscFree(a_name)); 152*2e1d0745SJose E. Roman PetscCall(PetscFree(c_name)); 153*2e1d0745SJose E. Roman PetscCall(PetscLayoutDestroy(&jmap)); 154*2e1d0745SJose E. Roman PetscCall(PetscFree(i)); 155*2e1d0745SJose E. Roman PetscCall(ISRestoreIndices(is_i, &i_glob)); 156*2e1d0745SJose E. Roman PetscCall(ISRestoreIndices(is_j, &j)); 157*2e1d0745SJose E. Roman PetscCall(VecRestoreArrayRead(vec_a, &a)); 158*2e1d0745SJose E. Roman PetscCall(ISDestroy(&is_i)); 159*2e1d0745SJose E. Roman PetscCall(ISDestroy(&is_j)); 160*2e1d0745SJose E. Roman PetscCall(VecDestroy(&vec_a)); 161*2e1d0745SJose E. Roman PetscFunctionReturn(PETSC_SUCCESS); 162*2e1d0745SJose E. Roman } 163