xref: /petsc/src/mat/impls/adj/mpi/mpiadj.c (revision 8e3a54c0662fee99ad69f33e814fb6a3f3eef16b)
1b97cf49bSBarry Smith /*
2b97cf49bSBarry Smith     Defines the basic matrix operations for the ADJ adjacency list matrix data-structure.
3b97cf49bSBarry Smith */
4e37d9405SJed Brown #include <../src/mat/impls/adj/mpi/mpiadj.h> /*I "petscmat.h" I*/
5841d17a1SFande Kong #include <petscsf.h>
6b97cf49bSBarry Smith 
740244768SBarry Smith /*
82ef1f0ffSBarry Smith   The interface should be easy to use for both MatCreateSubMatrix (parallel sub-matrix) and MatCreateSubMatrices (sequential sub-matrices)
92ef1f0ffSBarry Smith */
10d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrix_MPIAdj_data(Mat adj, IS irows, IS icols, PetscInt **sadj_xadj, PetscInt **sadj_adjncy, PetscInt **sadj_values)
11d71ae5a4SJacob Faibussowitsch {
12131c27b5Sprj-   PetscInt        nlrows_is, icols_n, i, j, nroots, nleaves, rlocalindex, *ncols_send, *ncols_recv;
1340244768SBarry Smith   PetscInt        nlrows_mat, *adjncy_recv, Ncols_recv, Ncols_send, *xadj_recv, *values_recv;
14e895ccc0SFande Kong   PetscInt       *ncols_recv_offsets, loc, rnclos, *sadjncy, *sxadj, *svalues;
1540244768SBarry Smith   const PetscInt *irows_indices, *icols_indices, *xadj, *adjncy;
16131c27b5Sprj-   PetscMPIInt     owner;
1740244768SBarry Smith   Mat_MPIAdj     *a = (Mat_MPIAdj *)adj->data;
1840244768SBarry Smith   PetscLayout     rmap;
1940244768SBarry Smith   MPI_Comm        comm;
2040244768SBarry Smith   PetscSF         sf;
2140244768SBarry Smith   PetscSFNode    *iremote;
2240244768SBarry Smith   PetscBool       done;
2340244768SBarry Smith 
2440244768SBarry Smith   PetscFunctionBegin;
259566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)adj, &comm));
269566063dSJacob Faibussowitsch   PetscCall(MatGetLayouts(adj, &rmap, NULL));
279566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(irows, &nlrows_is));
289566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(irows, &irows_indices));
299566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nlrows_is, &iremote));
3040244768SBarry Smith   /* construct sf graph*/
3140244768SBarry Smith   nleaves = nlrows_is;
3240244768SBarry Smith   for (i = 0; i < nlrows_is; i++) {
3340244768SBarry Smith     owner       = -1;
3440244768SBarry Smith     rlocalindex = -1;
359566063dSJacob Faibussowitsch     PetscCall(PetscLayoutFindOwnerIndex(rmap, irows_indices[i], &owner, &rlocalindex));
3640244768SBarry Smith     iremote[i].rank  = owner;
3740244768SBarry Smith     iremote[i].index = rlocalindex;
3840244768SBarry Smith   }
399566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(adj, 0, PETSC_FALSE, PETSC_FALSE, &nlrows_mat, &xadj, &adjncy, &done));
409566063dSJacob Faibussowitsch   PetscCall(PetscCalloc4(nlrows_mat, &ncols_send, nlrows_is, &xadj_recv, nlrows_is + 1, &ncols_recv_offsets, nlrows_is, &ncols_recv));
4140244768SBarry Smith   nroots = nlrows_mat;
42ad540459SPierre Jolivet   for (i = 0; i < nlrows_mat; i++) ncols_send[i] = xadj[i + 1] - xadj[i];
439566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, &sf));
449566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(sf, nroots, nleaves, NULL, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
459566063dSJacob Faibussowitsch   PetscCall(PetscSFSetType(sf, PETSCSFBASIC));
469566063dSJacob Faibussowitsch   PetscCall(PetscSFSetFromOptions(sf));
479566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(sf, MPIU_INT, ncols_send, ncols_recv, MPI_REPLACE));
489566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(sf, MPIU_INT, ncols_send, ncols_recv, MPI_REPLACE));
499566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(sf, MPIU_INT, xadj, xadj_recv, MPI_REPLACE));
509566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(sf, MPIU_INT, xadj, xadj_recv, MPI_REPLACE));
519566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&sf));
5240244768SBarry Smith   Ncols_recv = 0;
5340244768SBarry Smith   for (i = 0; i < nlrows_is; i++) {
5440244768SBarry Smith     Ncols_recv += ncols_recv[i];
5540244768SBarry Smith     ncols_recv_offsets[i + 1] = ncols_recv[i] + ncols_recv_offsets[i];
5640244768SBarry Smith   }
5740244768SBarry Smith   Ncols_send = 0;
58ad540459SPierre Jolivet   for (i = 0; i < nlrows_mat; i++) Ncols_send += ncols_send[i];
599566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(Ncols_recv, &iremote));
609566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(Ncols_recv, &adjncy_recv));
6140244768SBarry Smith   nleaves    = Ncols_recv;
6240244768SBarry Smith   Ncols_recv = 0;
6340244768SBarry Smith   for (i = 0; i < nlrows_is; i++) {
649566063dSJacob Faibussowitsch     PetscCall(PetscLayoutFindOwner(rmap, irows_indices[i], &owner));
6540244768SBarry Smith     for (j = 0; j < ncols_recv[i]; j++) {
6640244768SBarry Smith       iremote[Ncols_recv].rank    = owner;
6740244768SBarry Smith       iremote[Ncols_recv++].index = xadj_recv[i] + j;
6840244768SBarry Smith     }
6940244768SBarry Smith   }
709566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(irows, &irows_indices));
7140244768SBarry Smith   /*if we need to deal with edge weights ???*/
729566063dSJacob Faibussowitsch   if (a->useedgeweights) PetscCall(PetscCalloc1(Ncols_recv, &values_recv));
7340244768SBarry Smith   nroots = Ncols_send;
749566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, &sf));
759566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(sf, nroots, nleaves, NULL, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
769566063dSJacob Faibussowitsch   PetscCall(PetscSFSetType(sf, PETSCSFBASIC));
779566063dSJacob Faibussowitsch   PetscCall(PetscSFSetFromOptions(sf));
789566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(sf, MPIU_INT, adjncy, adjncy_recv, MPI_REPLACE));
799566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(sf, MPIU_INT, adjncy, adjncy_recv, MPI_REPLACE));
80e895ccc0SFande Kong   if (a->useedgeweights) {
819566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(sf, MPIU_INT, a->values, values_recv, MPI_REPLACE));
829566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(sf, MPIU_INT, a->values, values_recv, MPI_REPLACE));
8340244768SBarry Smith   }
849566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&sf));
859566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(adj, 0, PETSC_FALSE, PETSC_FALSE, &nlrows_mat, &xadj, &adjncy, &done));
869566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(icols, &icols_n));
879566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(icols, &icols_indices));
8840244768SBarry Smith   rnclos = 0;
8940244768SBarry Smith   for (i = 0; i < nlrows_is; i++) {
9040244768SBarry Smith     for (j = ncols_recv_offsets[i]; j < ncols_recv_offsets[i + 1]; j++) {
919566063dSJacob Faibussowitsch       PetscCall(PetscFindInt(adjncy_recv[j], icols_n, icols_indices, &loc));
9240244768SBarry Smith       if (loc < 0) {
9340244768SBarry Smith         adjncy_recv[j] = -1;
94e895ccc0SFande Kong         if (a->useedgeweights) values_recv[j] = -1;
9540244768SBarry Smith         ncols_recv[i]--;
9640244768SBarry Smith       } else {
9740244768SBarry Smith         rnclos++;
9840244768SBarry Smith       }
9940244768SBarry Smith     }
10040244768SBarry Smith   }
1019566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(icols, &icols_indices));
1029566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(rnclos, &sadjncy));
1039566063dSJacob Faibussowitsch   if (a->useedgeweights) PetscCall(PetscCalloc1(rnclos, &svalues));
1049566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nlrows_is + 1, &sxadj));
10540244768SBarry Smith   rnclos = 0;
10640244768SBarry Smith   for (i = 0; i < nlrows_is; i++) {
10740244768SBarry Smith     for (j = ncols_recv_offsets[i]; j < ncols_recv_offsets[i + 1]; j++) {
10840244768SBarry Smith       if (adjncy_recv[j] < 0) continue;
10940244768SBarry Smith       sadjncy[rnclos] = adjncy_recv[j];
110e895ccc0SFande Kong       if (a->useedgeweights) svalues[rnclos] = values_recv[j];
11140244768SBarry Smith       rnclos++;
11240244768SBarry Smith     }
11340244768SBarry Smith   }
114ad540459SPierre Jolivet   for (i = 0; i < nlrows_is; i++) sxadj[i + 1] = sxadj[i] + ncols_recv[i];
1159371c9d4SSatish Balay   if (sadj_xadj) {
1169371c9d4SSatish Balay     *sadj_xadj = sxadj;
1179371c9d4SSatish Balay   } else PetscCall(PetscFree(sxadj));
1189371c9d4SSatish Balay   if (sadj_adjncy) {
1199371c9d4SSatish Balay     *sadj_adjncy = sadjncy;
1209371c9d4SSatish Balay   } else PetscCall(PetscFree(sadjncy));
12140244768SBarry Smith   if (sadj_values) {
1229371c9d4SSatish Balay     if (a->useedgeweights) *sadj_values = svalues;
1239371c9d4SSatish Balay     else *sadj_values = NULL;
12440244768SBarry Smith   } else {
1259566063dSJacob Faibussowitsch     if (a->useedgeweights) PetscCall(PetscFree(svalues));
12640244768SBarry Smith   }
1279566063dSJacob Faibussowitsch   PetscCall(PetscFree4(ncols_send, xadj_recv, ncols_recv_offsets, ncols_recv));
1289566063dSJacob Faibussowitsch   PetscCall(PetscFree(adjncy_recv));
1299566063dSJacob Faibussowitsch   if (a->useedgeweights) PetscCall(PetscFree(values_recv));
1303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13140244768SBarry Smith }
13240244768SBarry Smith 
133d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrices_MPIAdj_Private(Mat mat, PetscInt n, const IS irow[], const IS icol[], PetscBool subcomm, MatReuse scall, Mat *submat[])
134d71ae5a4SJacob Faibussowitsch {
13540244768SBarry Smith   PetscInt        i, irow_n, icol_n, *sxadj, *sadjncy, *svalues;
13640244768SBarry Smith   PetscInt       *indices, nindx, j, k, loc;
13740244768SBarry Smith   PetscMPIInt     issame;
13840244768SBarry Smith   const PetscInt *irow_indices, *icol_indices;
13940244768SBarry Smith   MPI_Comm        scomm_row, scomm_col, scomm_mat;
14040244768SBarry Smith 
14140244768SBarry Smith   PetscFunctionBegin;
14240244768SBarry Smith   nindx = 0;
14340244768SBarry Smith   /*
14440244768SBarry Smith    * Estimate a maximum number for allocating memory
14540244768SBarry Smith    */
14640244768SBarry Smith   for (i = 0; i < n; i++) {
1479566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(irow[i], &irow_n));
1489566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(icol[i], &icol_n));
14940244768SBarry Smith     nindx = nindx > (irow_n + icol_n) ? nindx : (irow_n + icol_n);
15040244768SBarry Smith   }
1519566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nindx, &indices));
15240244768SBarry Smith   /* construct a submat */
153252a1336SBarry Smith   //  if (scall == MAT_INITIAL_MATRIX) PetscCall(PetscMalloc1(n,submat));
1546a7b62d2SBarry Smith 
15540244768SBarry Smith   for (i = 0; i < n; i++) {
15640244768SBarry Smith     if (subcomm) {
1579566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetComm((PetscObject)irow[i], &scomm_row));
1589566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetComm((PetscObject)icol[i], &scomm_col));
1599566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_compare(scomm_row, scomm_col, &issame));
16008401ef6SPierre Jolivet       PetscCheck(issame == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "row index set must have the same comm as the col index set");
1619566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_compare(scomm_row, PETSC_COMM_SELF, &issame));
16208401ef6SPierre Jolivet       PetscCheck(issame != MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, " can not use PETSC_COMM_SELF as comm when extracting a parallel submatrix");
16340244768SBarry Smith     } else {
16440244768SBarry Smith       scomm_row = PETSC_COMM_SELF;
16540244768SBarry Smith     }
16640244768SBarry Smith     /*get sub-matrix data*/
1679371c9d4SSatish Balay     sxadj   = NULL;
1689371c9d4SSatish Balay     sadjncy = NULL;
1699371c9d4SSatish Balay     svalues = NULL;
1709566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix_MPIAdj_data(mat, irow[i], icol[i], &sxadj, &sadjncy, &svalues));
1719566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(irow[i], &irow_n));
1729566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(icol[i], &icol_n));
1739566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(irow[i], &irow_indices));
1749566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(indices, irow_indices, irow_n));
1759566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(irow[i], &irow_indices));
1769566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(icol[i], &icol_indices));
177*8e3a54c0SPierre Jolivet     PetscCall(PetscArraycpy(PetscSafePointerPlusOffset(indices, irow_n), icol_indices, icol_n));
1789566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(icol[i], &icol_indices));
17940244768SBarry Smith     nindx = irow_n + icol_n;
1809566063dSJacob Faibussowitsch     PetscCall(PetscSortRemoveDupsInt(&nindx, indices));
18140244768SBarry Smith     /* renumber columns */
18240244768SBarry Smith     for (j = 0; j < irow_n; j++) {
18340244768SBarry Smith       for (k = sxadj[j]; k < sxadj[j + 1]; k++) {
1849566063dSJacob Faibussowitsch         PetscCall(PetscFindInt(sadjncy[k], nindx, indices, &loc));
18508401ef6SPierre Jolivet         PetscCheck(loc >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "can not find col %" PetscInt_FMT, sadjncy[k]);
18640244768SBarry Smith         sadjncy[k] = loc;
18740244768SBarry Smith       }
18840244768SBarry Smith     }
18940244768SBarry Smith     if (scall == MAT_INITIAL_MATRIX) {
1909566063dSJacob Faibussowitsch       PetscCall(MatCreateMPIAdj(scomm_row, irow_n, icol_n, sxadj, sadjncy, svalues, submat[i]));
19140244768SBarry Smith     } else {
19240244768SBarry Smith       Mat         sadj = *(submat[i]);
19340244768SBarry Smith       Mat_MPIAdj *sa   = (Mat_MPIAdj *)((sadj)->data);
1949566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetComm((PetscObject)sadj, &scomm_mat));
1959566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_compare(scomm_row, scomm_mat, &issame));
19608401ef6SPierre Jolivet       PetscCheck(issame == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "submatrix  must have the same comm as the col index set");
1979566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(sa->i, sxadj, irow_n + 1));
1989566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(sa->j, sadjncy, sxadj[irow_n]));
1999566063dSJacob Faibussowitsch       if (svalues) PetscCall(PetscArraycpy(sa->values, svalues, sxadj[irow_n]));
2009566063dSJacob Faibussowitsch       PetscCall(PetscFree(sxadj));
2019566063dSJacob Faibussowitsch       PetscCall(PetscFree(sadjncy));
202252a1336SBarry Smith       PetscCall(PetscFree(svalues));
20340244768SBarry Smith     }
20440244768SBarry Smith   }
2059566063dSJacob Faibussowitsch   PetscCall(PetscFree(indices));
2063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20740244768SBarry Smith }
20840244768SBarry Smith 
209d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatricesMPI_MPIAdj(Mat mat, PetscInt n, const IS irow[], const IS icol[], MatReuse scall, Mat *submat[])
210d71ae5a4SJacob Faibussowitsch {
21140244768SBarry Smith   /*get sub-matrices across a sub communicator */
21240244768SBarry Smith   PetscFunctionBegin;
2139566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrices_MPIAdj_Private(mat, n, irow, icol, PETSC_TRUE, scall, submat));
2143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21540244768SBarry Smith }
21640244768SBarry Smith 
217d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrices_MPIAdj(Mat mat, PetscInt n, const IS irow[], const IS icol[], MatReuse scall, Mat *submat[])
218d71ae5a4SJacob Faibussowitsch {
21940244768SBarry Smith   PetscFunctionBegin;
22040244768SBarry Smith   /*get sub-matrices based on PETSC_COMM_SELF */
2219566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrices_MPIAdj_Private(mat, n, irow, icol, PETSC_FALSE, scall, submat));
2223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22340244768SBarry Smith }
22440244768SBarry Smith 
225d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatView_MPIAdj_ASCII(Mat A, PetscViewer viewer)
226d71ae5a4SJacob Faibussowitsch {
2273eda8832SBarry Smith   Mat_MPIAdj       *a = (Mat_MPIAdj *)A->data;
228d0f46423SBarry Smith   PetscInt          i, j, m = A->rmap->n;
2292dcb1b2aSMatthew Knepley   const char       *name;
230ce1411ecSBarry Smith   PetscViewerFormat format;
231b97cf49bSBarry Smith 
232433994e6SBarry Smith   PetscFunctionBegin;
2339566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetName((PetscObject)A, &name));
2349566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(viewer, &format));
235fb9695e5SSatish Balay   if (format == PETSC_VIEWER_ASCII_INFO) {
2363ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
237f7d195e4SLawrence Mitchell   } else {
238f7d195e4SLawrence Mitchell     PetscCheck(format != PETSC_VIEWER_ASCII_MATLAB, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "MATLAB format not supported");
2399566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
2409566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
241b97cf49bSBarry Smith     for (i = 0; i < m; i++) {
2429566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "row %" PetscInt_FMT ":", i + A->rmap->rstart));
243b97cf49bSBarry Smith       for (j = a->i[i]; j < a->i[i + 1]; j++) {
2440170919eSFande Kong         if (a->values) {
2459566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%" PetscInt_FMT ", %" PetscInt_FMT ") ", a->j[j], a->values[j]));
2460170919eSFande Kong         } else {
2479566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT " ", a->j[j]));
2480752156aSBarry Smith         }
2490170919eSFande Kong       }
2509566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
251b97cf49bSBarry Smith     }
2529566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
2539566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
2549566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
2557b23a99aSBarry Smith   }
2563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
257b97cf49bSBarry Smith }
258b97cf49bSBarry Smith 
259d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatView_MPIAdj(Mat A, PetscViewer viewer)
260d71ae5a4SJacob Faibussowitsch {
261ace3abfcSBarry Smith   PetscBool iascii;
262b97cf49bSBarry Smith 
263433994e6SBarry Smith   PetscFunctionBegin;
2649566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
2651baa6e33SBarry Smith   if (iascii) PetscCall(MatView_MPIAdj_ASCII(A, viewer));
2663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
267b97cf49bSBarry Smith }
268b97cf49bSBarry Smith 
269d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_MPIAdj(Mat mat)
270d71ae5a4SJacob Faibussowitsch {
2713eda8832SBarry Smith   Mat_MPIAdj *a = (Mat_MPIAdj *)mat->data;
27294d884c6SBarry Smith 
27394d884c6SBarry Smith   PetscFunctionBegin;
2743ba16761SJacob Faibussowitsch   PetscCall(PetscLogObjectState((PetscObject)mat, "Rows=%" PetscInt_FMT ", Cols=%" PetscInt_FMT ", NZ=%" PetscInt_FMT, mat->rmap->n, mat->cmap->n, a->nz));
2759566063dSJacob Faibussowitsch   PetscCall(PetscFree(a->diag));
2760400557aSBarry Smith   if (a->freeaij) {
27714196391SBarry Smith     if (a->freeaijwithfree) {
27814196391SBarry Smith       if (a->i) free(a->i);
27914196391SBarry Smith       if (a->j) free(a->j);
28014196391SBarry Smith     } else {
2819566063dSJacob Faibussowitsch       PetscCall(PetscFree(a->i));
2829566063dSJacob Faibussowitsch       PetscCall(PetscFree(a->j));
2839566063dSJacob Faibussowitsch       PetscCall(PetscFree(a->values));
28414196391SBarry Smith     }
2850400557aSBarry Smith   }
2869566063dSJacob Faibussowitsch   PetscCall(PetscFree(a->rowvalues));
2879566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->data));
2889566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)mat, NULL));
2899566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMPIAdjSetPreallocation_C", NULL));
2909566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMPIAdjCreateNonemptySubcommMat_C", NULL));
2912e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMPIAdjToSeq_C", NULL));
292252a1336SBarry Smith   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMPIAdjToSeqRankZero_C", NULL));
2933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
294b97cf49bSBarry Smith }
295b97cf49bSBarry Smith 
296d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetOption_MPIAdj(Mat A, MatOption op, PetscBool flg)
297d71ae5a4SJacob Faibussowitsch {
2983eda8832SBarry Smith   Mat_MPIAdj *a = (Mat_MPIAdj *)A->data;
299b97cf49bSBarry Smith 
300433994e6SBarry Smith   PetscFunctionBegin;
30112c028f9SKris Buschelman   switch (op) {
30277e54ba9SKris Buschelman   case MAT_SYMMETRIC:
30312c028f9SKris Buschelman   case MAT_STRUCTURALLY_SYMMETRIC:
3049a4540c5SBarry Smith   case MAT_HERMITIAN:
305d71ae5a4SJacob Faibussowitsch   case MAT_SPD:
306d71ae5a4SJacob Faibussowitsch     a->symmetric = flg;
307d71ae5a4SJacob Faibussowitsch     break;
3089a4540c5SBarry Smith   case MAT_SYMMETRY_ETERNAL:
309b94d7dedSBarry Smith   case MAT_STRUCTURAL_SYMMETRY_ETERNAL:
310d71ae5a4SJacob Faibussowitsch   case MAT_SPD_ETERNAL:
311d71ae5a4SJacob Faibussowitsch     break;
312d71ae5a4SJacob Faibussowitsch   default:
313d71ae5a4SJacob Faibussowitsch     PetscCall(PetscInfo(A, "Option %s ignored\n", MatOptions[op]));
314d71ae5a4SJacob Faibussowitsch     break;
315b97cf49bSBarry Smith   }
3163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
317b97cf49bSBarry Smith }
318b97cf49bSBarry Smith 
319d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetRow_MPIAdj(Mat A, PetscInt row, PetscInt *nz, PetscInt **idx, PetscScalar **v)
320d71ae5a4SJacob Faibussowitsch {
3213eda8832SBarry Smith   Mat_MPIAdj *a = (Mat_MPIAdj *)A->data;
322b97cf49bSBarry Smith 
323433994e6SBarry Smith   PetscFunctionBegin;
324d0f46423SBarry Smith   row -= A->rmap->rstart;
325aed4548fSBarry Smith   PetscCheck(row >= 0 && row < A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Row out of range");
326b97cf49bSBarry Smith   *nz = a->i[row + 1] - a->i[row];
3272b1d8763SJed Brown   if (v) {
3282b1d8763SJed Brown     PetscInt j;
3292b1d8763SJed Brown     if (a->rowvalues_alloc < *nz) {
3309566063dSJacob Faibussowitsch       PetscCall(PetscFree(a->rowvalues));
3312b1d8763SJed Brown       a->rowvalues_alloc = PetscMax(a->rowvalues_alloc * 2, *nz);
3329566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(a->rowvalues_alloc, &a->rowvalues));
333b97cf49bSBarry Smith     }
334ad540459SPierre Jolivet     for (j = 0; j < *nz; j++) a->rowvalues[j] = a->values ? a->values[a->i[row] + j] : 1.0;
3352b1d8763SJed Brown     *v = (*nz) ? a->rowvalues : NULL;
336b97cf49bSBarry Smith   }
33792b6f2a0SJed Brown   if (idx) *idx = (*nz) ? a->j + a->i[row] : NULL;
3383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
339b97cf49bSBarry Smith }
340b97cf49bSBarry Smith 
341d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatRestoreRow_MPIAdj(Mat A, PetscInt row, PetscInt *nz, PetscInt **idx, PetscScalar **v)
342d71ae5a4SJacob Faibussowitsch {
343433994e6SBarry Smith   PetscFunctionBegin;
3443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
345b97cf49bSBarry Smith }
346b97cf49bSBarry Smith 
347d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatEqual_MPIAdj(Mat A, Mat B, PetscBool *flg)
348d71ae5a4SJacob Faibussowitsch {
3493eda8832SBarry Smith   Mat_MPIAdj *a = (Mat_MPIAdj *)A->data, *b = (Mat_MPIAdj *)B->data;
350ace3abfcSBarry Smith   PetscBool   flag;
351b97cf49bSBarry Smith 
352433994e6SBarry Smith   PetscFunctionBegin;
353b97cf49bSBarry Smith   /* If the  matrix dimensions are not equal,or no of nonzeros */
354ad540459SPierre Jolivet   if ((A->rmap->n != B->rmap->n) || (a->nz != b->nz)) flag = PETSC_FALSE;
355b97cf49bSBarry Smith 
356b97cf49bSBarry Smith   /* if the a->i are the same */
3579566063dSJacob Faibussowitsch   PetscCall(PetscArraycmp(a->i, b->i, A->rmap->n + 1, &flag));
358b97cf49bSBarry Smith 
359b97cf49bSBarry Smith   /* if a->j are the same */
3609566063dSJacob Faibussowitsch   PetscCall(PetscMemcmp(a->j, b->j, (a->nz) * sizeof(PetscInt), &flag));
361b97cf49bSBarry Smith 
3621c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&flag, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
3633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
364b97cf49bSBarry Smith }
365b97cf49bSBarry Smith 
366d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetRowIJ_MPIAdj(Mat A, PetscInt oshift, PetscBool symmetric, PetscBool blockcompressed, PetscInt *m, const PetscInt *inia[], const PetscInt *inja[], PetscBool *done)
367d71ae5a4SJacob Faibussowitsch {
368b24ad042SBarry Smith   PetscInt    i;
3696cd91f64SBarry Smith   Mat_MPIAdj *a  = (Mat_MPIAdj *)A->data;
3701a83f524SJed Brown   PetscInt  **ia = (PetscInt **)inia, **ja = (PetscInt **)inja;
3716cd91f64SBarry Smith 
3726cd91f64SBarry Smith   PetscFunctionBegin;
373d0f46423SBarry Smith   *m    = A->rmap->n;
3746cd91f64SBarry Smith   *ia   = a->i;
3756cd91f64SBarry Smith   *ja   = a->j;
3766cd91f64SBarry Smith   *done = PETSC_TRUE;
377d42735a1SBarry Smith   if (oshift) {
378ad540459SPierre Jolivet     for (i = 0; i < (*ia)[*m]; i++) (*ja)[i]++;
379d42735a1SBarry Smith     for (i = 0; i <= (*m); i++) (*ia)[i]++;
380d42735a1SBarry Smith   }
3813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
382d42735a1SBarry Smith }
383d42735a1SBarry Smith 
384d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatRestoreRowIJ_MPIAdj(Mat A, PetscInt oshift, PetscBool symmetric, PetscBool blockcompressed, PetscInt *m, const PetscInt *inia[], const PetscInt *inja[], PetscBool *done)
385d71ae5a4SJacob Faibussowitsch {
386b24ad042SBarry Smith   PetscInt    i;
387d42735a1SBarry Smith   Mat_MPIAdj *a  = (Mat_MPIAdj *)A->data;
3881a83f524SJed Brown   PetscInt  **ia = (PetscInt **)inia, **ja = (PetscInt **)inja;
389d42735a1SBarry Smith 
390d42735a1SBarry Smith   PetscFunctionBegin;
391aed4548fSBarry Smith   PetscCheck(!ia || a->i == *ia, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "ia passed back is not one obtained with MatGetRowIJ()");
392aed4548fSBarry Smith   PetscCheck(!ja || a->j == *ja, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "ja passed back is not one obtained with MatGetRowIJ()");
393d42735a1SBarry Smith   if (oshift) {
39428b400f6SJacob Faibussowitsch     PetscCheck(ia, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "If oshift then you must passed in inia[] argument");
39528b400f6SJacob Faibussowitsch     PetscCheck(ja, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "If oshift then you must passed in inja[] argument");
396d42735a1SBarry Smith     for (i = 0; i <= (*m); i++) (*ia)[i]--;
397ad540459SPierre Jolivet     for (i = 0; i < (*ia)[*m]; i++) (*ja)[i]--;
398d42735a1SBarry Smith   }
3993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4006cd91f64SBarry Smith }
401b97cf49bSBarry Smith 
40266976f2fSJacob Faibussowitsch static PetscErrorCode MatConvertFrom_MPIAdj(Mat A, MatType type, MatReuse reuse, Mat *newmat)
403d71ae5a4SJacob Faibussowitsch {
40417667f90SBarry Smith   Mat                B;
40517667f90SBarry Smith   PetscInt           i, m, N, nzeros = 0, *ia, *ja, len, rstart, cnt, j, *a;
40617667f90SBarry Smith   const PetscInt    *rj;
40717667f90SBarry Smith   const PetscScalar *ra;
40817667f90SBarry Smith   MPI_Comm           comm;
40917667f90SBarry Smith 
41017667f90SBarry Smith   PetscFunctionBegin;
4119566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, NULL, &N));
4129566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &m, NULL));
4139566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(A, &rstart, NULL));
41417667f90SBarry Smith 
41517667f90SBarry Smith   /* count the number of nonzeros per row */
41617667f90SBarry Smith   for (i = 0; i < m; i++) {
4179566063dSJacob Faibussowitsch     PetscCall(MatGetRow(A, i + rstart, &len, &rj, NULL));
4185ee9ba1cSJed Brown     for (j = 0; j < len; j++) {
4199371c9d4SSatish Balay       if (rj[j] == i + rstart) {
4209371c9d4SSatish Balay         len--;
4219371c9d4SSatish Balay         break;
4229371c9d4SSatish Balay       } /* don't count diagonal */
4235ee9ba1cSJed Brown     }
42417667f90SBarry Smith     nzeros += len;
4259566063dSJacob Faibussowitsch     PetscCall(MatRestoreRow(A, i + rstart, &len, &rj, NULL));
42617667f90SBarry Smith   }
42717667f90SBarry Smith 
42817667f90SBarry Smith   /* malloc space for nonzeros */
4299566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nzeros + 1, &a));
4309566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(N + 1, &ia));
4319566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nzeros + 1, &ja));
43217667f90SBarry Smith 
43317667f90SBarry Smith   nzeros = 0;
43417667f90SBarry Smith   ia[0]  = 0;
43517667f90SBarry Smith   for (i = 0; i < m; i++) {
4369566063dSJacob Faibussowitsch     PetscCall(MatGetRow(A, i + rstart, &len, &rj, &ra));
43717667f90SBarry Smith     cnt = 0;
43817667f90SBarry Smith     for (j = 0; j < len; j++) {
4395ee9ba1cSJed Brown       if (rj[j] != i + rstart) { /* if not diagonal */
44017667f90SBarry Smith         a[nzeros + cnt]    = (PetscInt)PetscAbsScalar(ra[j]);
44117667f90SBarry Smith         ja[nzeros + cnt++] = rj[j];
44217667f90SBarry Smith       }
4435ee9ba1cSJed Brown     }
4449566063dSJacob Faibussowitsch     PetscCall(MatRestoreRow(A, i + rstart, &len, &rj, &ra));
44517667f90SBarry Smith     nzeros += cnt;
44617667f90SBarry Smith     ia[i + 1] = nzeros;
44717667f90SBarry Smith   }
44817667f90SBarry Smith 
4499566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
4509566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &B));
4519566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(B, m, PETSC_DETERMINE, PETSC_DETERMINE, N));
4529566063dSJacob Faibussowitsch   PetscCall(MatSetType(B, type));
4539566063dSJacob Faibussowitsch   PetscCall(MatMPIAdjSetPreallocation(B, ia, ja, a));
45417667f90SBarry Smith 
455511c6705SHong Zhang   if (reuse == MAT_INPLACE_MATRIX) {
4569566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
45717667f90SBarry Smith   } else {
45817667f90SBarry Smith     *newmat = B;
45917667f90SBarry Smith   }
4603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
46117667f90SBarry Smith }
46217667f90SBarry Smith 
46366976f2fSJacob Faibussowitsch static PetscErrorCode MatSetValues_MPIAdj(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode im)
464d71ae5a4SJacob Faibussowitsch {
4656a09307cSBarry Smith   Mat_MPIAdj *adj = (Mat_MPIAdj *)A->data;
4666a09307cSBarry Smith   PetscInt    rStart, rEnd, cStart, cEnd;
4676a09307cSBarry Smith 
4686a09307cSBarry Smith   PetscFunctionBegin;
4696a09307cSBarry Smith   PetscCheck(!adj->i, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Matrix is already assembled, cannot change its values");
4706a09307cSBarry Smith   PetscCall(MatGetOwnershipRange(A, &rStart, &rEnd));
4716a09307cSBarry Smith   PetscCall(MatGetOwnershipRangeColumn(A, &cStart, &cEnd));
4726a09307cSBarry Smith   if (!adj->ht) {
4736a09307cSBarry Smith     PetscCall(PetscHSetIJCreate(&adj->ht));
4746a09307cSBarry Smith     PetscCall(MatStashCreate_Private(PetscObjectComm((PetscObject)A), 1, &A->stash));
4756a09307cSBarry Smith     PetscCall(PetscLayoutSetUp(A->rmap));
4766a09307cSBarry Smith     PetscCall(PetscLayoutSetUp(A->cmap));
4776a09307cSBarry Smith   }
4786a09307cSBarry Smith   for (PetscInt r = 0; r < m; ++r) {
4796a09307cSBarry Smith     PetscHashIJKey key;
4806a09307cSBarry Smith 
4816a09307cSBarry Smith     key.i = rows[r];
4826a09307cSBarry Smith     if (key.i < 0) continue;
4836a09307cSBarry Smith     if ((key.i < rStart) || (key.i >= rEnd)) {
4846a09307cSBarry Smith       PetscCall(MatStashValuesRow_Private(&A->stash, key.i, n, cols, values, PETSC_FALSE));
4856a09307cSBarry Smith     } else {
4866a09307cSBarry Smith       for (PetscInt c = 0; c < n; ++c) {
4876a09307cSBarry Smith         key.j = cols[c];
4886a09307cSBarry Smith         if (key.j < 0 || key.i == key.j) continue;
4896a09307cSBarry Smith         PetscCall(PetscHSetIJAdd(adj->ht, key));
4906a09307cSBarry Smith       }
4916a09307cSBarry Smith     }
4926a09307cSBarry Smith   }
4933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4946a09307cSBarry Smith }
4956a09307cSBarry Smith 
49666976f2fSJacob Faibussowitsch static PetscErrorCode MatAssemblyBegin_MPIAdj(Mat A, MatAssemblyType type)
497d71ae5a4SJacob Faibussowitsch {
4986a09307cSBarry Smith   PetscInt    nstash, reallocs;
4996a09307cSBarry Smith   Mat_MPIAdj *adj = (Mat_MPIAdj *)A->data;
5006a09307cSBarry Smith 
5016a09307cSBarry Smith   PetscFunctionBegin;
5026a09307cSBarry Smith   if (!adj->ht) {
5036a09307cSBarry Smith     PetscCall(PetscHSetIJCreate(&adj->ht));
5046a09307cSBarry Smith     PetscCall(PetscLayoutSetUp(A->rmap));
5056a09307cSBarry Smith     PetscCall(PetscLayoutSetUp(A->cmap));
5066a09307cSBarry Smith   }
5076a09307cSBarry Smith   PetscCall(MatStashScatterBegin_Private(A, &A->stash, A->rmap->range));
5086a09307cSBarry Smith   PetscCall(MatStashGetInfo_Private(&A->stash, &nstash, &reallocs));
5096a09307cSBarry Smith   PetscCall(PetscInfo(A, "Stash has %" PetscInt_FMT " entries, uses %" PetscInt_FMT " mallocs.\n", nstash, reallocs));
5103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5116a09307cSBarry Smith }
5126a09307cSBarry Smith 
51366976f2fSJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_MPIAdj(Mat A, MatAssemblyType type)
514d71ae5a4SJacob Faibussowitsch {
5156a09307cSBarry Smith   PetscScalar   *val;
5166a09307cSBarry Smith   PetscInt      *row, *col, m, rstart, *rowstarts;
5176a09307cSBarry Smith   PetscInt       i, j, ncols, flg, nz;
5186a09307cSBarry Smith   PetscMPIInt    n;
5196a09307cSBarry Smith   Mat_MPIAdj    *adj = (Mat_MPIAdj *)A->data;
5206a09307cSBarry Smith   PetscHashIter  hi;
5216a09307cSBarry Smith   PetscHashIJKey key;
5226a09307cSBarry Smith   PetscHSetIJ    ht = adj->ht;
5236a09307cSBarry Smith 
5246a09307cSBarry Smith   PetscFunctionBegin;
5256a09307cSBarry Smith   while (1) {
5266a09307cSBarry Smith     PetscCall(MatStashScatterGetMesg_Private(&A->stash, &n, &row, &col, &val, &flg));
5276a09307cSBarry Smith     if (!flg) break;
5286a09307cSBarry Smith 
5296a09307cSBarry Smith     for (i = 0; i < n;) {
5306a09307cSBarry Smith       /* Identify the consecutive vals belonging to the same row */
5316a09307cSBarry Smith       for (j = i, rstart = row[j]; j < n; j++) {
5326a09307cSBarry Smith         if (row[j] != rstart) break;
5336a09307cSBarry Smith       }
5346a09307cSBarry Smith       if (j < n) ncols = j - i;
5356a09307cSBarry Smith       else ncols = n - i;
5366a09307cSBarry Smith       /* Set all these values with a single function call */
5376a09307cSBarry Smith       PetscCall(MatSetValues_MPIAdj(A, 1, row + i, ncols, col + i, val + i, INSERT_VALUES));
5386a09307cSBarry Smith       i = j;
5396a09307cSBarry Smith     }
5406a09307cSBarry Smith   }
5416a09307cSBarry Smith   PetscCall(MatStashScatterEnd_Private(&A->stash));
5426a09307cSBarry Smith   PetscCall(MatStashDestroy_Private(&A->stash));
5436a09307cSBarry Smith 
5446a09307cSBarry Smith   PetscCall(MatGetLocalSize(A, &m, NULL));
5456a09307cSBarry Smith   PetscCall(MatGetOwnershipRange(A, &rstart, NULL));
5466a09307cSBarry Smith   PetscCall(PetscCalloc1(m + 1, &rowstarts));
5476a09307cSBarry Smith   PetscHashIterBegin(ht, hi);
5486a09307cSBarry Smith   for (; !PetscHashIterAtEnd(ht, hi);) {
5496a09307cSBarry Smith     PetscHashIterGetKey(ht, hi, key);
5506a09307cSBarry Smith     rowstarts[key.i - rstart + 1]++;
5516a09307cSBarry Smith     PetscHashIterNext(ht, hi);
5526a09307cSBarry Smith   }
553ad540459SPierre Jolivet   for (i = 1; i < m + 1; i++) rowstarts[i] = rowstarts[i - 1] + rowstarts[i];
5546a09307cSBarry Smith 
5556a09307cSBarry Smith   PetscCall(PetscHSetIJGetSize(ht, &nz));
5566a09307cSBarry Smith   PetscCall(PetscMalloc1(nz, &col));
5576a09307cSBarry Smith   PetscHashIterBegin(ht, hi);
5586a09307cSBarry Smith   for (; !PetscHashIterAtEnd(ht, hi);) {
5596a09307cSBarry Smith     PetscHashIterGetKey(ht, hi, key);
5606a09307cSBarry Smith     col[rowstarts[key.i - rstart]++] = key.j;
5616a09307cSBarry Smith     PetscHashIterNext(ht, hi);
5626a09307cSBarry Smith   }
5636a09307cSBarry Smith   PetscCall(PetscHSetIJDestroy(&ht));
564ad540459SPierre Jolivet   for (i = m; i > 0; i--) rowstarts[i] = rowstarts[i - 1];
5656a09307cSBarry Smith   rowstarts[0] = 0;
5666a09307cSBarry Smith 
56748a46eb9SPierre Jolivet   for (PetscInt i = 0; i < m; i++) PetscCall(PetscSortInt(rowstarts[i + 1] - rowstarts[i], &col[rowstarts[i]]));
5686a09307cSBarry Smith 
5696a09307cSBarry Smith   adj->i       = rowstarts;
5706a09307cSBarry Smith   adj->j       = col;
571252a1336SBarry Smith   adj->nz      = rowstarts[m];
5726a09307cSBarry Smith   adj->freeaij = PETSC_TRUE;
5733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5746a09307cSBarry Smith }
5756a09307cSBarry Smith 
5766a09307cSBarry Smith static struct _MatOps MatOps_Values = {MatSetValues_MPIAdj,
5773eda8832SBarry Smith                                        MatGetRow_MPIAdj,
5783eda8832SBarry Smith                                        MatRestoreRow_MPIAdj,
579f4259b30SLisandro Dalcin                                        NULL,
580f4259b30SLisandro Dalcin                                        /* 4*/ NULL,
581f4259b30SLisandro Dalcin                                        NULL,
582f4259b30SLisandro Dalcin                                        NULL,
583f4259b30SLisandro Dalcin                                        NULL,
584f4259b30SLisandro Dalcin                                        NULL,
585f4259b30SLisandro Dalcin                                        NULL,
586f4259b30SLisandro Dalcin                                        /*10*/ NULL,
587f4259b30SLisandro Dalcin                                        NULL,
588f4259b30SLisandro Dalcin                                        NULL,
589f4259b30SLisandro Dalcin                                        NULL,
590f4259b30SLisandro Dalcin                                        NULL,
591f4259b30SLisandro Dalcin                                        /*15*/ NULL,
5923eda8832SBarry Smith                                        MatEqual_MPIAdj,
593f4259b30SLisandro Dalcin                                        NULL,
594f4259b30SLisandro Dalcin                                        NULL,
595f4259b30SLisandro Dalcin                                        NULL,
5966a09307cSBarry Smith                                        /*20*/ MatAssemblyBegin_MPIAdj,
5976a09307cSBarry Smith                                        MatAssemblyEnd_MPIAdj,
5983eda8832SBarry Smith                                        MatSetOption_MPIAdj,
599f4259b30SLisandro Dalcin                                        NULL,
600f4259b30SLisandro Dalcin                                        /*24*/ NULL,
601f4259b30SLisandro Dalcin                                        NULL,
602f4259b30SLisandro Dalcin                                        NULL,
603f4259b30SLisandro Dalcin                                        NULL,
604f4259b30SLisandro Dalcin                                        NULL,
605f4259b30SLisandro Dalcin                                        /*29*/ NULL,
606f4259b30SLisandro Dalcin                                        NULL,
607f4259b30SLisandro Dalcin                                        NULL,
608f4259b30SLisandro Dalcin                                        NULL,
609f4259b30SLisandro Dalcin                                        NULL,
610f4259b30SLisandro Dalcin                                        /*34*/ NULL,
611f4259b30SLisandro Dalcin                                        NULL,
612f4259b30SLisandro Dalcin                                        NULL,
613f4259b30SLisandro Dalcin                                        NULL,
614f4259b30SLisandro Dalcin                                        NULL,
615f4259b30SLisandro Dalcin                                        /*39*/ NULL,
6167dae84e0SHong Zhang                                        MatCreateSubMatrices_MPIAdj,
617f4259b30SLisandro Dalcin                                        NULL,
618f4259b30SLisandro Dalcin                                        NULL,
619f4259b30SLisandro Dalcin                                        NULL,
620f4259b30SLisandro Dalcin                                        /*44*/ NULL,
621f4259b30SLisandro Dalcin                                        NULL,
6227d68702bSBarry Smith                                        MatShift_Basic,
623f4259b30SLisandro Dalcin                                        NULL,
624f4259b30SLisandro Dalcin                                        NULL,
625f4259b30SLisandro Dalcin                                        /*49*/ NULL,
6266cd91f64SBarry Smith                                        MatGetRowIJ_MPIAdj,
627d42735a1SBarry Smith                                        MatRestoreRowIJ_MPIAdj,
628f4259b30SLisandro Dalcin                                        NULL,
629f4259b30SLisandro Dalcin                                        NULL,
630f4259b30SLisandro Dalcin                                        /*54*/ NULL,
631f4259b30SLisandro Dalcin                                        NULL,
632f4259b30SLisandro Dalcin                                        NULL,
633f4259b30SLisandro Dalcin                                        NULL,
634f4259b30SLisandro Dalcin                                        NULL,
635f4259b30SLisandro Dalcin                                        /*59*/ NULL,
636b9b97703SBarry Smith                                        MatDestroy_MPIAdj,
637b9b97703SBarry Smith                                        MatView_MPIAdj,
63817667f90SBarry Smith                                        MatConvertFrom_MPIAdj,
639f4259b30SLisandro Dalcin                                        NULL,
640f4259b30SLisandro Dalcin                                        /*64*/ NULL,
641f4259b30SLisandro Dalcin                                        NULL,
642f4259b30SLisandro Dalcin                                        NULL,
643f4259b30SLisandro Dalcin                                        NULL,
644f4259b30SLisandro Dalcin                                        NULL,
645f4259b30SLisandro Dalcin                                        /*69*/ NULL,
646f4259b30SLisandro Dalcin                                        NULL,
647f4259b30SLisandro Dalcin                                        NULL,
648f4259b30SLisandro Dalcin                                        NULL,
649f4259b30SLisandro Dalcin                                        NULL,
650f4259b30SLisandro Dalcin                                        /*74*/ NULL,
651f4259b30SLisandro Dalcin                                        NULL,
652f4259b30SLisandro Dalcin                                        NULL,
653f4259b30SLisandro Dalcin                                        NULL,
654f4259b30SLisandro Dalcin                                        NULL,
655f4259b30SLisandro Dalcin                                        /*79*/ NULL,
656f4259b30SLisandro Dalcin                                        NULL,
657f4259b30SLisandro Dalcin                                        NULL,
658f4259b30SLisandro Dalcin                                        NULL,
659f4259b30SLisandro Dalcin                                        NULL,
660f4259b30SLisandro Dalcin                                        /*84*/ NULL,
661f4259b30SLisandro Dalcin                                        NULL,
662f4259b30SLisandro Dalcin                                        NULL,
663f4259b30SLisandro Dalcin                                        NULL,
664f4259b30SLisandro Dalcin                                        NULL,
665f4259b30SLisandro Dalcin                                        /*89*/ NULL,
666f4259b30SLisandro Dalcin                                        NULL,
667f4259b30SLisandro Dalcin                                        NULL,
668f4259b30SLisandro Dalcin                                        NULL,
669f4259b30SLisandro Dalcin                                        NULL,
670f4259b30SLisandro Dalcin                                        /*94*/ NULL,
671f4259b30SLisandro Dalcin                                        NULL,
672f4259b30SLisandro Dalcin                                        NULL,
673f4259b30SLisandro Dalcin                                        NULL,
674f4259b30SLisandro Dalcin                                        NULL,
675f4259b30SLisandro Dalcin                                        /*99*/ NULL,
676f4259b30SLisandro Dalcin                                        NULL,
677f4259b30SLisandro Dalcin                                        NULL,
678f4259b30SLisandro Dalcin                                        NULL,
679f4259b30SLisandro Dalcin                                        NULL,
680f4259b30SLisandro Dalcin                                        /*104*/ NULL,
681f4259b30SLisandro Dalcin                                        NULL,
682f4259b30SLisandro Dalcin                                        NULL,
683f4259b30SLisandro Dalcin                                        NULL,
684f4259b30SLisandro Dalcin                                        NULL,
685f4259b30SLisandro Dalcin                                        /*109*/ NULL,
686f4259b30SLisandro Dalcin                                        NULL,
687f4259b30SLisandro Dalcin                                        NULL,
688f4259b30SLisandro Dalcin                                        NULL,
689f4259b30SLisandro Dalcin                                        NULL,
690f4259b30SLisandro Dalcin                                        /*114*/ NULL,
691f4259b30SLisandro Dalcin                                        NULL,
692f4259b30SLisandro Dalcin                                        NULL,
693f4259b30SLisandro Dalcin                                        NULL,
694f4259b30SLisandro Dalcin                                        NULL,
695f4259b30SLisandro Dalcin                                        /*119*/ NULL,
696f4259b30SLisandro Dalcin                                        NULL,
697f4259b30SLisandro Dalcin                                        NULL,
698f4259b30SLisandro Dalcin                                        NULL,
699f4259b30SLisandro Dalcin                                        NULL,
700f4259b30SLisandro Dalcin                                        /*124*/ NULL,
701f4259b30SLisandro Dalcin                                        NULL,
702f4259b30SLisandro Dalcin                                        NULL,
703f4259b30SLisandro Dalcin                                        NULL,
7047dae84e0SHong Zhang                                        MatCreateSubMatricesMPI_MPIAdj,
705f4259b30SLisandro Dalcin                                        /*129*/ NULL,
706f4259b30SLisandro Dalcin                                        NULL,
707f4259b30SLisandro Dalcin                                        NULL,
708f4259b30SLisandro Dalcin                                        NULL,
709f4259b30SLisandro Dalcin                                        NULL,
710f4259b30SLisandro Dalcin                                        /*134*/ NULL,
711f4259b30SLisandro Dalcin                                        NULL,
712f4259b30SLisandro Dalcin                                        NULL,
713f4259b30SLisandro Dalcin                                        NULL,
714f4259b30SLisandro Dalcin                                        NULL,
715f4259b30SLisandro Dalcin                                        /*139*/ NULL,
716f4259b30SLisandro Dalcin                                        NULL,
717d70f29a3SPierre Jolivet                                        NULL,
718d70f29a3SPierre Jolivet                                        NULL,
719d70f29a3SPierre Jolivet                                        NULL,
720d70f29a3SPierre Jolivet                                        /*144*/ NULL,
721d70f29a3SPierre Jolivet                                        NULL,
722d70f29a3SPierre Jolivet                                        NULL,
72399a7f59eSMark Adams                                        NULL,
72499a7f59eSMark Adams                                        NULL,
7257fb60732SBarry Smith                                        NULL,
726dec0b466SHong Zhang                                        /*150*/ NULL,
727dec0b466SHong Zhang                                        NULL};
728b97cf49bSBarry Smith 
729d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMPIAdjSetPreallocation_MPIAdj(Mat B, PetscInt *i, PetscInt *j, PetscInt *values)
730d71ae5a4SJacob Faibussowitsch {
731a23d5eceSKris Buschelman   Mat_MPIAdj *b = (Mat_MPIAdj *)B->data;
732e895ccc0SFande Kong   PetscBool   useedgeweights;
733a23d5eceSKris Buschelman 
734a23d5eceSKris Buschelman   PetscFunctionBegin;
7359566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(B->rmap));
7369566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(B->cmap));
7379371c9d4SSatish Balay   if (values) useedgeweights = PETSC_TRUE;
7389371c9d4SSatish Balay   else useedgeweights = PETSC_FALSE;
739e895ccc0SFande Kong   /* Make everybody knows if they are using edge weights or not */
7401c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce((int *)&useedgeweights, (int *)&b->useedgeweights, 1, MPI_INT, MPI_MAX, PetscObjectComm((PetscObject)B)));
74158ec18a5SLisandro Dalcin 
74276bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
74376bd3646SJed Brown     PetscInt ii;
74476bd3646SJed Brown 
74508401ef6SPierre Jolivet     PetscCheck(i[0] == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "First i[] index must be zero, instead it is %" PetscInt_FMT, i[0]);
746d0f46423SBarry Smith     for (ii = 1; ii < B->rmap->n; ii++) {
747aed4548fSBarry Smith       PetscCheck(i[ii] >= 0 && i[ii] >= i[ii - 1], PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "i[%" PetscInt_FMT "]=%" PetscInt_FMT " index is out of range: i[%" PetscInt_FMT "]=%" PetscInt_FMT, ii, i[ii], ii - 1, i[ii - 1]);
748a23d5eceSKris Buschelman     }
749ad540459SPierre Jolivet     for (ii = 0; ii < i[B->rmap->n]; ii++) PetscCheck(j[ii] >= 0 && j[ii] < B->cmap->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Column index %" PetscInt_FMT " out of range %" PetscInt_FMT, ii, j[ii]);
75076bd3646SJed Brown   }
751a23d5eceSKris Buschelman   b->j      = j;
752a23d5eceSKris Buschelman   b->i      = i;
753a23d5eceSKris Buschelman   b->values = values;
754a23d5eceSKris Buschelman 
755d0f46423SBarry Smith   b->nz        = i[B->rmap->n];
756f4259b30SLisandro Dalcin   b->diag      = NULL;
757a23d5eceSKris Buschelman   b->symmetric = PETSC_FALSE;
758a23d5eceSKris Buschelman   b->freeaij   = PETSC_TRUE;
759a23d5eceSKris Buschelman 
7606a09307cSBarry Smith   B->ops->assemblybegin = NULL;
7616a09307cSBarry Smith   B->ops->assemblyend   = NULL;
7629566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
7639566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
7646a09307cSBarry Smith   PetscCall(MatStashDestroy_Private(&B->stash));
7653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
766a23d5eceSKris Buschelman }
767b97cf49bSBarry Smith 
768d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMPIAdjCreateNonemptySubcommMat_MPIAdj(Mat A, Mat *B)
769d71ae5a4SJacob Faibussowitsch {
7709a3665c6SJed Brown   Mat_MPIAdj     *a = (Mat_MPIAdj *)A->data;
7719a3665c6SJed Brown   const PetscInt *ranges;
7729a3665c6SJed Brown   MPI_Comm        acomm, bcomm;
7739a3665c6SJed Brown   MPI_Group       agroup, bgroup;
7749a3665c6SJed Brown   PetscMPIInt     i, rank, size, nranks, *ranks;
7759a3665c6SJed Brown 
7769a3665c6SJed Brown   PetscFunctionBegin;
7770298fd71SBarry Smith   *B = NULL;
7789566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &acomm));
7799566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(acomm, &size));
7809566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(acomm, &rank));
7819566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRanges(A, &ranges));
7829a3665c6SJed Brown   for (i = 0, nranks = 0; i < size; i++) {
7839a3665c6SJed Brown     if (ranges[i + 1] - ranges[i] > 0) nranks++;
7849a3665c6SJed Brown   }
7859a3665c6SJed Brown   if (nranks == size) { /* All ranks have a positive number of rows, so we do not need to create a subcomm; */
7869566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)A));
7879a3665c6SJed Brown     *B = A;
7883ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
7899a3665c6SJed Brown   }
7909a3665c6SJed Brown 
7919566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nranks, &ranks));
7929a3665c6SJed Brown   for (i = 0, nranks = 0; i < size; i++) {
7939a3665c6SJed Brown     if (ranges[i + 1] - ranges[i] > 0) ranks[nranks++] = i;
7949a3665c6SJed Brown   }
7959566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_group(acomm, &agroup));
7969566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Group_incl(agroup, nranks, ranks, &bgroup));
7979566063dSJacob Faibussowitsch   PetscCall(PetscFree(ranks));
7989566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_create(acomm, bgroup, &bcomm));
7999566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Group_free(&agroup));
8009566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Group_free(&bgroup));
8019a3665c6SJed Brown   if (bcomm != MPI_COMM_NULL) {
8029a3665c6SJed Brown     PetscInt    m, N;
8039a3665c6SJed Brown     Mat_MPIAdj *b;
8049566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(A, &m, NULL));
8059566063dSJacob Faibussowitsch     PetscCall(MatGetSize(A, NULL, &N));
8069566063dSJacob Faibussowitsch     PetscCall(MatCreateMPIAdj(bcomm, m, N, a->i, a->j, a->values, B));
8079a3665c6SJed Brown     b          = (Mat_MPIAdj *)(*B)->data;
8089a3665c6SJed Brown     b->freeaij = PETSC_FALSE;
8099566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_free(&bcomm));
8109a3665c6SJed Brown   }
8113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8129a3665c6SJed Brown }
8139a3665c6SJed Brown 
81466976f2fSJacob Faibussowitsch static PetscErrorCode MatMPIAdjToSeq_MPIAdj(Mat A, Mat *B)
815d71ae5a4SJacob Faibussowitsch {
816b44e7856SBarry Smith   PetscInt    M, N, *II, *J, NZ, nz, m, nzstart, i;
817b44e7856SBarry Smith   PetscInt   *Values = NULL;
818b44e7856SBarry Smith   Mat_MPIAdj *adj    = (Mat_MPIAdj *)A->data;
819b44e7856SBarry Smith   PetscMPIInt mnz, mm, *allnz, *allm, size, *dispnz, *dispm;
820b44e7856SBarry Smith 
821b44e7856SBarry Smith   PetscFunctionBegin;
8229566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
8239566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, &N));
8249566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &m, NULL));
825b44e7856SBarry Smith   nz = adj->nz;
82608401ef6SPierre Jolivet   PetscCheck(adj->i[m] == nz, PETSC_COMM_SELF, PETSC_ERR_PLIB, "nz %" PetscInt_FMT " not correct i[m] %" PetscInt_FMT, nz, adj->i[m]);
827712fec58SPierre Jolivet   PetscCall(MPIU_Allreduce(&nz, &NZ, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A)));
828d4e69552SBarry Smith 
8299566063dSJacob Faibussowitsch   PetscCall(PetscMPIIntCast(nz, &mnz));
8309566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(size, &allnz, size, &dispnz));
8319566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allgather(&mnz, 1, MPI_INT, allnz, 1, MPI_INT, PetscObjectComm((PetscObject)A)));
8329371c9d4SSatish Balay   dispnz[0] = 0;
8339371c9d4SSatish Balay   for (i = 1; i < size; i++) dispnz[i] = dispnz[i - 1] + allnz[i - 1];
834b44e7856SBarry Smith   if (adj->values) {
8359566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(NZ, &Values));
8369566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Allgatherv(adj->values, mnz, MPIU_INT, Values, allnz, dispnz, MPIU_INT, PetscObjectComm((PetscObject)A)));
837b44e7856SBarry Smith   }
8389566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(NZ, &J));
8399566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allgatherv(adj->j, mnz, MPIU_INT, J, allnz, dispnz, MPIU_INT, PetscObjectComm((PetscObject)A)));
8409566063dSJacob Faibussowitsch   PetscCall(PetscFree2(allnz, dispnz));
8419566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Scan(&nz, &nzstart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A)));
842b44e7856SBarry Smith   nzstart -= nz;
843b44e7856SBarry Smith   /* shift the i[] values so they will be correct after being received */
844b44e7856SBarry Smith   for (i = 0; i < m; i++) adj->i[i] += nzstart;
8459566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(M + 1, &II));
8469566063dSJacob Faibussowitsch   PetscCall(PetscMPIIntCast(m, &mm));
8479566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(size, &allm, size, &dispm));
8489566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allgather(&mm, 1, MPI_INT, allm, 1, MPI_INT, PetscObjectComm((PetscObject)A)));
8499371c9d4SSatish Balay   dispm[0] = 0;
8509371c9d4SSatish Balay   for (i = 1; i < size; i++) dispm[i] = dispm[i - 1] + allm[i - 1];
8519566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allgatherv(adj->i, mm, MPIU_INT, II, allm, dispm, MPIU_INT, PetscObjectComm((PetscObject)A)));
8529566063dSJacob Faibussowitsch   PetscCall(PetscFree2(allm, dispm));
853b44e7856SBarry Smith   II[M] = NZ;
854b44e7856SBarry Smith   /* shift the i[] values back */
855b44e7856SBarry Smith   for (i = 0; i < m; i++) adj->i[i] -= nzstart;
8569566063dSJacob Faibussowitsch   PetscCall(MatCreateMPIAdj(PETSC_COMM_SELF, M, N, II, J, Values, B));
8573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
858b44e7856SBarry Smith }
859b44e7856SBarry Smith 
86066976f2fSJacob Faibussowitsch static PetscErrorCode MatMPIAdjToSeqRankZero_MPIAdj(Mat A, Mat *B)
861d71ae5a4SJacob Faibussowitsch {
862252a1336SBarry Smith   PetscInt    M, N, *II, *J, NZ, nz, m, nzstart, i;
863252a1336SBarry Smith   PetscInt   *Values = NULL;
864252a1336SBarry Smith   Mat_MPIAdj *adj    = (Mat_MPIAdj *)A->data;
865252a1336SBarry Smith   PetscMPIInt mnz, mm, *allnz = NULL, *allm, size, *dispnz, *dispm, rank;
866252a1336SBarry Smith 
867252a1336SBarry Smith   PetscFunctionBegin;
868252a1336SBarry Smith   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
869252a1336SBarry Smith   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
870252a1336SBarry Smith   PetscCall(MatGetSize(A, &M, &N));
871252a1336SBarry Smith   PetscCall(MatGetLocalSize(A, &m, NULL));
872252a1336SBarry Smith   nz = adj->nz;
873252a1336SBarry Smith   PetscCheck(adj->i[m] == nz, PETSC_COMM_SELF, PETSC_ERR_PLIB, "nz %" PetscInt_FMT " not correct i[m] %" PetscInt_FMT, nz, adj->i[m]);
874712fec58SPierre Jolivet   PetscCall(MPIU_Allreduce(&nz, &NZ, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A)));
875252a1336SBarry Smith 
876252a1336SBarry Smith   PetscCall(PetscMPIIntCast(nz, &mnz));
877252a1336SBarry Smith   if (!rank) PetscCall(PetscMalloc2(size, &allnz, size, &dispnz));
878252a1336SBarry Smith   PetscCallMPI(MPI_Gather(&mnz, 1, MPI_INT, allnz, 1, MPI_INT, 0, PetscObjectComm((PetscObject)A)));
879252a1336SBarry Smith   if (!rank) {
8809371c9d4SSatish Balay     dispnz[0] = 0;
8819371c9d4SSatish Balay     for (i = 1; i < size; i++) dispnz[i] = dispnz[i - 1] + allnz[i - 1];
882252a1336SBarry Smith     if (adj->values) {
883252a1336SBarry Smith       PetscCall(PetscMalloc1(NZ, &Values));
884252a1336SBarry Smith       PetscCallMPI(MPI_Gatherv(adj->values, mnz, MPIU_INT, Values, allnz, dispnz, MPIU_INT, 0, PetscObjectComm((PetscObject)A)));
885252a1336SBarry Smith     }
886252a1336SBarry Smith     PetscCall(PetscMalloc1(NZ, &J));
887252a1336SBarry Smith     PetscCallMPI(MPI_Gatherv(adj->j, mnz, MPIU_INT, J, allnz, dispnz, MPIU_INT, 0, PetscObjectComm((PetscObject)A)));
888252a1336SBarry Smith     PetscCall(PetscFree2(allnz, dispnz));
889252a1336SBarry Smith   } else {
890252a1336SBarry Smith     if (adj->values) PetscCallMPI(MPI_Gatherv(adj->values, mnz, MPIU_INT, NULL, NULL, NULL, MPIU_INT, 0, PetscObjectComm((PetscObject)A)));
891252a1336SBarry Smith     PetscCallMPI(MPI_Gatherv(adj->j, mnz, MPIU_INT, NULL, NULL, NULL, MPIU_INT, 0, PetscObjectComm((PetscObject)A)));
892252a1336SBarry Smith   }
893252a1336SBarry Smith   PetscCallMPI(MPI_Scan(&nz, &nzstart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A)));
894252a1336SBarry Smith   nzstart -= nz;
895252a1336SBarry Smith   /* shift the i[] values so they will be correct after being received */
896252a1336SBarry Smith   for (i = 0; i < m; i++) adj->i[i] += nzstart;
897252a1336SBarry Smith   PetscCall(PetscMPIIntCast(m, &mm));
898252a1336SBarry Smith   if (!rank) {
899252a1336SBarry Smith     PetscCall(PetscMalloc1(M + 1, &II));
900252a1336SBarry Smith     PetscCall(PetscMalloc2(size, &allm, size, &dispm));
901252a1336SBarry Smith     PetscCallMPI(MPI_Gather(&mm, 1, MPI_INT, allm, 1, MPI_INT, 0, PetscObjectComm((PetscObject)A)));
9029371c9d4SSatish Balay     dispm[0] = 0;
9039371c9d4SSatish Balay     for (i = 1; i < size; i++) dispm[i] = dispm[i - 1] + allm[i - 1];
904252a1336SBarry Smith     PetscCallMPI(MPI_Gatherv(adj->i, mm, MPIU_INT, II, allm, dispm, MPIU_INT, 0, PetscObjectComm((PetscObject)A)));
905252a1336SBarry Smith     PetscCall(PetscFree2(allm, dispm));
906252a1336SBarry Smith     II[M] = NZ;
907252a1336SBarry Smith   } else {
908252a1336SBarry Smith     PetscCallMPI(MPI_Gather(&mm, 1, MPI_INT, NULL, 1, MPI_INT, 0, PetscObjectComm((PetscObject)A)));
909252a1336SBarry Smith     PetscCallMPI(MPI_Gatherv(adj->i, mm, MPIU_INT, NULL, NULL, NULL, MPIU_INT, 0, PetscObjectComm((PetscObject)A)));
910252a1336SBarry Smith   }
911252a1336SBarry Smith   /* shift the i[] values back */
912252a1336SBarry Smith   for (i = 0; i < m; i++) adj->i[i] -= nzstart;
913252a1336SBarry Smith   if (!rank) PetscCall(MatCreateMPIAdj(PETSC_COMM_SELF, M, N, II, J, Values, B));
9143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
915252a1336SBarry Smith }
916252a1336SBarry Smith 
9179a3665c6SJed Brown /*@
91811a5261eSBarry Smith   MatMPIAdjCreateNonemptySubcommMat - create the same `MATMPIADJ` matrix on a subcommunicator containing only processes owning a positive number of rows
9199a3665c6SJed Brown 
9209a3665c6SJed Brown   Collective
9219a3665c6SJed Brown 
9224165533cSJose E. Roman   Input Parameter:
9232ef1f0ffSBarry Smith . A - original `MATMPIADJ` matrix
9249a3665c6SJed Brown 
9254165533cSJose E. Roman   Output Parameter:
9262ef1f0ffSBarry Smith . B - matrix on subcommunicator, `NULL` on ranks that owned zero rows of `A`
9279a3665c6SJed Brown 
9289a3665c6SJed Brown   Level: developer
9299a3665c6SJed Brown 
9309a3665c6SJed Brown   Note:
9319a3665c6SJed Brown   This function is mostly useful for internal use by mesh partitioning packages that require that every process owns at least one row.
9329a3665c6SJed Brown 
9332ef1f0ffSBarry Smith   The matrix `B` should be destroyed with `MatDestroy()`. The arrays are not copied, so `B` should be destroyed before `A` is destroyed.
9349a3665c6SJed Brown 
9351cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATMPIADJ`, `MatCreateMPIAdj()`
9369a3665c6SJed Brown @*/
937d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMPIAdjCreateNonemptySubcommMat(Mat A, Mat *B)
938d71ae5a4SJacob Faibussowitsch {
9399a3665c6SJed Brown   PetscFunctionBegin;
9409a3665c6SJed Brown   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
941cac4c232SBarry Smith   PetscUseMethod(A, "MatMPIAdjCreateNonemptySubcommMat_C", (Mat, Mat *), (A, B));
9423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9439a3665c6SJed Brown }
9449a3665c6SJed Brown 
9450bad9183SKris Buschelman /*MC
946fafad747SKris Buschelman    MATMPIADJ - MATMPIADJ = "mpiadj" - A matrix type to be used for distributed adjacency matrices,
9470bad9183SKris Buschelman    intended for use constructing orderings and partitionings.
9480bad9183SKris Buschelman 
9490bad9183SKris Buschelman   Level: beginner
9500bad9183SKris Buschelman 
95111a5261eSBarry Smith   Note:
95211a5261eSBarry Smith     You can provide values to the matrix using `MatMPIAdjSetPreallocation()`, `MatCreateMPIAdj()`, or
95311a5261eSBarry Smith     by calling `MatSetValues()` and `MatAssemblyBegin()` followed by `MatAssemblyEnd()`
9546a09307cSBarry Smith 
9551cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreateMPIAdj()`, `MatMPIAdjSetPreallocation()`, `MatSetValues()`
9560bad9183SKris Buschelman M*/
957d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_MPIAdj(Mat B)
958d71ae5a4SJacob Faibussowitsch {
959273d9f13SBarry Smith   Mat_MPIAdj *b;
960273d9f13SBarry Smith 
961273d9f13SBarry Smith   PetscFunctionBegin;
9624dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&b));
963b0a32e0cSBarry Smith   B->data         = (void *)b;
964aea10558SJacob Faibussowitsch   B->ops[0]       = MatOps_Values;
965273d9f13SBarry Smith   B->assembled    = PETSC_FALSE;
9666a09307cSBarry Smith   B->preallocated = PETSC_TRUE; /* so that MatSetValues() may be used */
967273d9f13SBarry Smith 
9689566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatMPIAdjSetPreallocation_C", MatMPIAdjSetPreallocation_MPIAdj));
9699566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatMPIAdjCreateNonemptySubcommMat_C", MatMPIAdjCreateNonemptySubcommMat_MPIAdj));
9709566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatMPIAdjToSeq_C", MatMPIAdjToSeq_MPIAdj));
971252a1336SBarry Smith   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatMPIAdjToSeqRankZero_C", MatMPIAdjToSeqRankZero_MPIAdj));
9729566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)B, MATMPIADJ));
9733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
974273d9f13SBarry Smith }
975273d9f13SBarry Smith 
976a23d5eceSKris Buschelman /*@C
97711a5261eSBarry Smith   MatMPIAdjToSeq - Converts an parallel `MATMPIADJ` matrix to complete `MATMPIADJ` on each process (needed by sequential partitioner)
978b44e7856SBarry Smith 
979d083f849SBarry Smith   Logically Collective
980b44e7856SBarry Smith 
981b44e7856SBarry Smith   Input Parameter:
982b44e7856SBarry Smith . A - the matrix
983b44e7856SBarry Smith 
984b44e7856SBarry Smith   Output Parameter:
985b44e7856SBarry Smith . B - the same matrix on all processes
986b44e7856SBarry Smith 
987b44e7856SBarry Smith   Level: intermediate
988b44e7856SBarry Smith 
9891cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATMPIADJ`, `MatCreate()`, `MatCreateMPIAdj()`, `MatSetValues()`, `MatMPIAdjToSeqRankZero()`
990b44e7856SBarry Smith @*/
991d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMPIAdjToSeq(Mat A, Mat *B)
992d71ae5a4SJacob Faibussowitsch {
993b44e7856SBarry Smith   PetscFunctionBegin;
994cac4c232SBarry Smith   PetscUseMethod(A, "MatMPIAdjToSeq_C", (Mat, Mat *), (A, B));
9953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
996b44e7856SBarry Smith }
997b44e7856SBarry Smith 
998b44e7856SBarry Smith /*@C
99911a5261eSBarry Smith   MatMPIAdjToSeqRankZero - Converts an parallel `MATMPIADJ` matrix to complete `MATMPIADJ` on rank zero (needed by sequential partitioner)
1000252a1336SBarry Smith 
1001252a1336SBarry Smith   Logically Collective
1002252a1336SBarry Smith 
1003252a1336SBarry Smith   Input Parameter:
1004252a1336SBarry Smith . A - the matrix
1005252a1336SBarry Smith 
1006252a1336SBarry Smith   Output Parameter:
1007252a1336SBarry Smith . B - the same matrix on rank zero, not set on other ranks
1008252a1336SBarry Smith 
1009252a1336SBarry Smith   Level: intermediate
1010252a1336SBarry Smith 
101111a5261eSBarry Smith   Note:
1012252a1336SBarry Smith   This routine has the advantage on systems with multiple ranks per node since only one copy of the matrix
1013252a1336SBarry Smith   is stored on the first node, instead of the number of ranks copies. This can allow partitioning much larger
1014d5b43468SJose E. Roman   parallel graph sequentially.
1015252a1336SBarry Smith 
10161cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATMPIADJ`, `MatCreate()`, `MatCreateMPIAdj()`, `MatSetValues()`, `MatMPIAdjToSeq()`
1017252a1336SBarry Smith @*/
1018d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMPIAdjToSeqRankZero(Mat A, Mat *B)
1019d71ae5a4SJacob Faibussowitsch {
1020252a1336SBarry Smith   PetscFunctionBegin;
1021252a1336SBarry Smith   PetscUseMethod(A, "MatMPIAdjToSeqRankZero_C", (Mat, Mat *), (A, B));
10223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1023252a1336SBarry Smith }
1024252a1336SBarry Smith 
1025252a1336SBarry Smith /*@C
1026a23d5eceSKris Buschelman   MatMPIAdjSetPreallocation - Sets the array used for storing the matrix elements
1027a23d5eceSKris Buschelman 
1028d083f849SBarry Smith   Logically Collective
1029a23d5eceSKris Buschelman 
1030a23d5eceSKris Buschelman   Input Parameters:
1031fe59aa6dSJacob Faibussowitsch + B      - the matrix
10322ef1f0ffSBarry Smith . i      - the indices into `j` for the start of each row
1033a23d5eceSKris Buschelman . j      - the column indices for each row (sorted for each row).
10342ef1f0ffSBarry Smith        The indices in `i` and `j` start with zero (NOT with one).
10352ef1f0ffSBarry Smith - values - [use `NULL` if not provided] edge weights
1036a23d5eceSKris Buschelman 
1037a23d5eceSKris Buschelman   Level: intermediate
1038a23d5eceSKris Buschelman 
1039fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateMPIAdj()`, `MatSetValues()`, `MATMPIADJ`
1040a23d5eceSKris Buschelman @*/
1041d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMPIAdjSetPreallocation(Mat B, PetscInt *i, PetscInt *j, PetscInt *values)
1042d71ae5a4SJacob Faibussowitsch {
1043273d9f13SBarry Smith   PetscFunctionBegin;
1044cac4c232SBarry Smith   PetscTryMethod(B, "MatMPIAdjSetPreallocation_C", (Mat, PetscInt *, PetscInt *, PetscInt *), (B, i, j, values));
10453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1046273d9f13SBarry Smith }
1047273d9f13SBarry Smith 
1048b97cf49bSBarry Smith /*@C
10493eda8832SBarry Smith   MatCreateMPIAdj - Creates a sparse matrix representing an adjacency list.
1050b97cf49bSBarry Smith   The matrix does not have numerical values associated with it, but is
1051b97cf49bSBarry Smith   intended for ordering (to reduce bandwidth etc) and partitioning.
1052b97cf49bSBarry Smith 
1053d083f849SBarry Smith   Collective
1054ef5ee4d1SLois Curfman McInnes 
1055b97cf49bSBarry Smith   Input Parameters:
1056c2e958feSBarry Smith + comm   - MPI communicator
10570752156aSBarry Smith . m      - number of local rows
105858ec18a5SLisandro Dalcin . N      - number of global columns
10592ef1f0ffSBarry Smith . i      - the indices into `j` for the start of each row
1060329f5518SBarry Smith . j      - the column indices for each row (sorted for each row).
1061fe59aa6dSJacob Faibussowitsch - values - the values
1062b97cf49bSBarry Smith 
1063b97cf49bSBarry Smith   Output Parameter:
1064b97cf49bSBarry Smith . A - the matrix
1065b97cf49bSBarry Smith 
106615091d37SBarry Smith   Level: intermediate
106715091d37SBarry Smith 
106895452b02SPatrick Sanan   Notes:
1069fe59aa6dSJacob Faibussowitsch   The indices in `i` and `j` start with zero (NOT with one).
1070fe59aa6dSJacob Faibussowitsch 
10712ef1f0ffSBarry Smith   You must NOT free the `i`, `values` and `j` arrays yourself. PETSc will free them
107211a5261eSBarry Smith   when the matrix is destroyed; you must allocate them with `PetscMalloc()`. If you
107311a5261eSBarry Smith   call from Fortran you need not create the arrays with `PetscMalloc()`.
10746a09307cSBarry Smith 
10756a09307cSBarry Smith   You should not include the matrix diagonals.
1076b97cf49bSBarry Smith 
1077e3f7e1d6Svictorle   If you already have a matrix, you can create its adjacency matrix by a call
107811a5261eSBarry Smith   to `MatConvert()`, specifying a type of `MATMPIADJ`.
1079ededeb1aSvictorle 
108011a5261eSBarry Smith   Possible values for `MatSetOption()` - `MAT_STRUCTURALLY_SYMMETRIC`
1081b97cf49bSBarry Smith 
10821cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatConvert()`, `MatGetOrdering()`, `MATMPIADJ`, `MatMPIAdjSetPreallocation()`
1083b97cf49bSBarry Smith @*/
1084d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateMPIAdj(MPI_Comm comm, PetscInt m, PetscInt N, PetscInt *i, PetscInt *j, PetscInt *values, Mat *A)
1085d71ae5a4SJacob Faibussowitsch {
1086433994e6SBarry Smith   PetscFunctionBegin;
10879566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, A));
10889566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*A, m, PETSC_DETERMINE, PETSC_DETERMINE, N));
10899566063dSJacob Faibussowitsch   PetscCall(MatSetType(*A, MATMPIADJ));
10909566063dSJacob Faibussowitsch   PetscCall(MatMPIAdjSetPreallocation(*A, i, j, values));
10913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1092b97cf49bSBarry Smith }
1093