xref: /petsc/src/mat/impls/elemental/matelem.cxx (revision 4dfa11a44d5adf2389f1d3acbc8f3c1116dc6c3a)
11673f470SJose E. Roman #include <petsc/private/petscelemental.h>
2db31f6deSJed Brown 
327e75052SPierre Jolivet const char       ElementalCitation[] = "@Article{Elemental2012,\n"
427e75052SPierre Jolivet                                        "  author  = {Jack Poulson and Bryan Marker and Jeff R. Hammond and Nichols A. Romero and Robert {v}an~{d}e~{G}eijn},\n"
527e75052SPierre Jolivet                                        "  title   = {Elemental: A New Framework for Distributed Memory Dense Matrix Computations},\n"
627e75052SPierre Jolivet                                        "  journal = {{ACM} Transactions on Mathematical Software},\n"
727e75052SPierre Jolivet                                        "  volume  = {39},\n"
827e75052SPierre Jolivet                                        "  number  = {2},\n"
927e75052SPierre Jolivet                                        "  year    = {2013}\n"
1027e75052SPierre Jolivet                                        "}\n";
1127e75052SPierre Jolivet static PetscBool ElementalCite       = PETSC_FALSE;
1227e75052SPierre Jolivet 
135e9f5b67SHong Zhang /*
145e9f5b67SHong Zhang     The variable Petsc_Elemental_keyval is used to indicate an MPI attribute that
155e9f5b67SHong Zhang   is attached to a communicator, in this case the attribute is a Mat_Elemental_Grid
165e9f5b67SHong Zhang */
175e9f5b67SHong Zhang static PetscMPIInt Petsc_Elemental_keyval = MPI_KEYVAL_INVALID;
185e9f5b67SHong Zhang 
199371c9d4SSatish Balay static PetscErrorCode MatView_Elemental(Mat A, PetscViewer viewer) {
20db31f6deSJed Brown   Mat_Elemental *a = (Mat_Elemental *)A->data;
21db31f6deSJed Brown   PetscBool      iascii;
22db31f6deSJed Brown 
23db31f6deSJed Brown   PetscFunctionBegin;
249566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
25db31f6deSJed Brown   if (iascii) {
26db31f6deSJed Brown     PetscViewerFormat format;
279566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
28db31f6deSJed Brown     if (format == PETSC_VIEWER_ASCII_INFO) {
2979673f7bSHong Zhang       /* call elemental viewing function */
309566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "Elemental run parameters:\n"));
3163a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  allocated entries=%zu\n", (*a->emat).AllocatedMemory()));
329566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  grid height=%d, grid width=%d\n", (*a->emat).Grid().Height(), (*a->emat).Grid().Width()));
334fe7bbcaSHong Zhang       if (format == PETSC_VIEWER_ASCII_FACTOR_INFO) {
3479673f7bSHong Zhang         /* call elemental viewing function */
359566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PetscObjectComm((PetscObject)viewer), "test matview_elemental 2\n"));
364fe7bbcaSHong Zhang       }
3779673f7bSHong Zhang 
38db31f6deSJed Brown     } else if (format == PETSC_VIEWER_DEFAULT) {
399566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
40e8146892SSatish Balay       El::Print(*a->emat, "Elemental matrix (cyclic ordering)");
419566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
42834d3fecSHong Zhang       if (A->factortype == MAT_FACTOR_NONE) {
4361119200SXuan Zhou         Mat Adense;
449566063dSJacob Faibussowitsch         PetscCall(MatConvert(A, MATDENSE, MAT_INITIAL_MATRIX, &Adense));
459566063dSJacob Faibussowitsch         PetscCall(MatView(Adense, viewer));
469566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&Adense));
47834d3fecSHong Zhang       }
48ce94432eSBarry Smith     } else SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Format");
49d2daa67eSHong Zhang   } else {
505cb544a0SHong Zhang     /* convert to dense format and call MatView() */
5161119200SXuan Zhou     Mat Adense;
529566063dSJacob Faibussowitsch     PetscCall(MatConvert(A, MATDENSE, MAT_INITIAL_MATRIX, &Adense));
539566063dSJacob Faibussowitsch     PetscCall(MatView(Adense, viewer));
549566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Adense));
55d2daa67eSHong Zhang   }
56db31f6deSJed Brown   PetscFunctionReturn(0);
57db31f6deSJed Brown }
58db31f6deSJed Brown 
599371c9d4SSatish Balay static PetscErrorCode MatGetInfo_Elemental(Mat A, MatInfoType flag, MatInfo *info) {
6015767789SHong Zhang   Mat_Elemental *a = (Mat_Elemental *)A->data;
6115767789SHong Zhang 
62180a43e4SHong Zhang   PetscFunctionBegin;
635cb544a0SHong Zhang   info->block_size = 1.0;
6415767789SHong Zhang 
6515767789SHong Zhang   if (flag == MAT_LOCAL) {
663966268fSBarry Smith     info->nz_allocated = (*a->emat).AllocatedMemory(); /* locally allocated */
6715767789SHong Zhang     info->nz_used      = info->nz_allocated;
6815767789SHong Zhang   } else if (flag == MAT_GLOBAL_MAX) {
691c2dc1cbSBarry Smith     //PetscCall(MPIU_Allreduce(isend,irecv,5,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)matin)));
7015767789SHong Zhang     /* see MatGetInfo_MPIAIJ() for getting global info->nz_allocated! */
7115767789SHong Zhang     //SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP," MAT_GLOBAL_MAX not written yet");
7215767789SHong Zhang   } else if (flag == MAT_GLOBAL_SUM) {
7315767789SHong Zhang     //SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP," MAT_GLOBAL_SUM not written yet");
743966268fSBarry Smith     info->nz_allocated = (*a->emat).AllocatedMemory(); /* locally allocated */
7515767789SHong Zhang     info->nz_used      = info->nz_allocated;           /* assume Elemental does accurate allocation */
761c2dc1cbSBarry Smith     //PetscCall(MPIU_Allreduce(isend,irecv,1,MPIU_REAL,MPIU_SUM,PetscObjectComm((PetscObject)A)));
7715767789SHong Zhang     //PetscPrintf(PETSC_COMM_SELF,"    ... [%d] locally allocated %g\n",rank,info->nz_allocated);
7815767789SHong Zhang   }
7915767789SHong Zhang 
8015767789SHong Zhang   info->nz_unneeded       = 0.0;
813966268fSBarry Smith   info->assemblies        = A->num_ass;
8215767789SHong Zhang   info->mallocs           = 0;
83*4dfa11a4SJacob Faibussowitsch   info->memory            = 0; /* REVIEW ME */
8415767789SHong Zhang   info->fill_ratio_given  = 0; /* determined by Elemental */
8515767789SHong Zhang   info->fill_ratio_needed = 0;
8615767789SHong Zhang   info->factor_mallocs    = 0;
87180a43e4SHong Zhang   PetscFunctionReturn(0);
88180a43e4SHong Zhang }
89180a43e4SHong Zhang 
909371c9d4SSatish Balay PetscErrorCode MatSetOption_Elemental(Mat A, MatOption op, PetscBool flg) {
9132d7a744SHong Zhang   Mat_Elemental *a = (Mat_Elemental *)A->data;
9232d7a744SHong Zhang 
9332d7a744SHong Zhang   PetscFunctionBegin;
9432d7a744SHong Zhang   switch (op) {
9532d7a744SHong Zhang   case MAT_NEW_NONZERO_LOCATIONS:
9632d7a744SHong Zhang   case MAT_NEW_NONZERO_LOCATION_ERR:
9732d7a744SHong Zhang   case MAT_NEW_NONZERO_ALLOCATION_ERR:
98891a0571SHong Zhang   case MAT_SYMMETRIC:
99071fcb05SBarry Smith   case MAT_SORTED_FULL:
1009371c9d4SSatish Balay   case MAT_HERMITIAN: break;
1019371c9d4SSatish Balay   case MAT_ROW_ORIENTED: a->roworiented = flg; break;
1029371c9d4SSatish Balay   default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "unknown option %s", MatOptions[op]);
10332d7a744SHong Zhang   }
10432d7a744SHong Zhang   PetscFunctionReturn(0);
10532d7a744SHong Zhang }
10632d7a744SHong Zhang 
1079371c9d4SSatish Balay static PetscErrorCode MatSetValues_Elemental(Mat A, PetscInt nr, const PetscInt *rows, PetscInt nc, const PetscInt *cols, const PetscScalar *vals, InsertMode imode) {
108db31f6deSJed Brown   Mat_Elemental *a = (Mat_Elemental *)A->data;
109fbbcb730SJack Poulson   PetscInt       i, j, rrank, ridx, crank, cidx, erow, ecol, numQueues = 0;
110db31f6deSJed Brown 
111db31f6deSJed Brown   PetscFunctionBegin;
112fbbcb730SJack Poulson   // TODO: Initialize matrix to all zeros?
113fbbcb730SJack Poulson 
114fbbcb730SJack Poulson   // Count the number of queues from this process
11532d7a744SHong Zhang   if (a->roworiented) {
116db31f6deSJed Brown     for (i = 0; i < nr; i++) {
117db31f6deSJed Brown       if (rows[i] < 0) continue;
118db31f6deSJed Brown       P2RO(A, 0, rows[i], &rrank, &ridx);
119db31f6deSJed Brown       RO2E(A, 0, rrank, ridx, &erow);
120aed4548fSBarry Smith       PetscCheck(rrank >= 0 && ridx >= 0 && erow >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Incorrect row translation");
121db31f6deSJed Brown       for (j = 0; j < nc; j++) {
122db31f6deSJed Brown         if (cols[j] < 0) continue;
123db31f6deSJed Brown         P2RO(A, 1, cols[j], &crank, &cidx);
124db31f6deSJed Brown         RO2E(A, 1, crank, cidx, &ecol);
125aed4548fSBarry Smith         PetscCheck(crank >= 0 && cidx >= 0 && ecol >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Incorrect col translation");
126fbbcb730SJack Poulson         if (!a->emat->IsLocal(erow, ecol)) { /* off-proc entry */
127fbbcb730SJack Poulson           /* printf("Will later remotely update (%d,%d)\n",erow,ecol); */
12808401ef6SPierre Jolivet           PetscCheck(imode == ADD_VALUES, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only ADD_VALUES to off-processor entry is supported");
129fbbcb730SJack Poulson           ++numQueues;
130aae2c449SHong Zhang           continue;
131ed36708cSHong Zhang         }
132fbbcb730SJack Poulson         /* printf("Locally updating (%d,%d)\n",erow,ecol); */
133db31f6deSJed Brown         switch (imode) {
134fbbcb730SJack Poulson         case INSERT_VALUES: a->emat->Set(erow, ecol, (PetscElemScalar)vals[i * nc + j]); break;
135fbbcb730SJack Poulson         case ADD_VALUES: a->emat->Update(erow, ecol, (PetscElemScalar)vals[i * nc + j]); break;
13698921bdaSJacob Faibussowitsch         default: SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "No support for InsertMode %d", (int)imode);
137db31f6deSJed Brown         }
138db31f6deSJed Brown       }
139db31f6deSJed Brown     }
140fbbcb730SJack Poulson 
141fbbcb730SJack Poulson     /* printf("numQueues=%d\n",numQueues); */
142fbbcb730SJack Poulson     a->emat->Reserve(numQueues);
143fbbcb730SJack Poulson     for (i = 0; i < nr; i++) {
144fbbcb730SJack Poulson       if (rows[i] < 0) continue;
145fbbcb730SJack Poulson       P2RO(A, 0, rows[i], &rrank, &ridx);
146fbbcb730SJack Poulson       RO2E(A, 0, rrank, ridx, &erow);
147fbbcb730SJack Poulson       for (j = 0; j < nc; j++) {
148fbbcb730SJack Poulson         if (cols[j] < 0) continue;
149fbbcb730SJack Poulson         P2RO(A, 1, cols[j], &crank, &cidx);
150fbbcb730SJack Poulson         RO2E(A, 1, crank, cidx, &ecol);
151fbbcb730SJack Poulson         if (!a->emat->IsLocal(erow, ecol)) { /*off-proc entry*/
152fbbcb730SJack Poulson           /* printf("Queueing remotely update of (%d,%d)\n",erow,ecol); */
153fbbcb730SJack Poulson           a->emat->QueueUpdate(erow, ecol, vals[i * nc + j]);
154fbbcb730SJack Poulson         }
155fbbcb730SJack Poulson       }
156fbbcb730SJack Poulson     }
15732d7a744SHong Zhang   } else { /* columnoriented */
15832d7a744SHong Zhang     for (j = 0; j < nc; j++) {
15932d7a744SHong Zhang       if (cols[j] < 0) continue;
16032d7a744SHong Zhang       P2RO(A, 1, cols[j], &crank, &cidx);
16132d7a744SHong Zhang       RO2E(A, 1, crank, cidx, &ecol);
162aed4548fSBarry Smith       PetscCheck(crank >= 0 && cidx >= 0 && ecol >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Incorrect col translation");
16332d7a744SHong Zhang       for (i = 0; i < nr; i++) {
16432d7a744SHong Zhang         if (rows[i] < 0) continue;
16532d7a744SHong Zhang         P2RO(A, 0, rows[i], &rrank, &ridx);
16632d7a744SHong Zhang         RO2E(A, 0, rrank, ridx, &erow);
167aed4548fSBarry Smith         PetscCheck(rrank >= 0 && ridx >= 0 && erow >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Incorrect row translation");
16832d7a744SHong Zhang         if (!a->emat->IsLocal(erow, ecol)) { /* off-proc entry */
16932d7a744SHong Zhang           /* printf("Will later remotely update (%d,%d)\n",erow,ecol); */
17008401ef6SPierre Jolivet           PetscCheck(imode == ADD_VALUES, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only ADD_VALUES to off-processor entry is supported");
17132d7a744SHong Zhang           ++numQueues;
17232d7a744SHong Zhang           continue;
17332d7a744SHong Zhang         }
17432d7a744SHong Zhang         /* printf("Locally updating (%d,%d)\n",erow,ecol); */
17532d7a744SHong Zhang         switch (imode) {
17632d7a744SHong Zhang         case INSERT_VALUES: a->emat->Set(erow, ecol, (PetscElemScalar)vals[i + j * nr]); break;
17732d7a744SHong Zhang         case ADD_VALUES: a->emat->Update(erow, ecol, (PetscElemScalar)vals[i + j * nr]); break;
17898921bdaSJacob Faibussowitsch         default: SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "No support for InsertMode %d", (int)imode);
17932d7a744SHong Zhang         }
18032d7a744SHong Zhang       }
18132d7a744SHong Zhang     }
18232d7a744SHong Zhang 
18332d7a744SHong Zhang     /* printf("numQueues=%d\n",numQueues); */
18432d7a744SHong Zhang     a->emat->Reserve(numQueues);
18532d7a744SHong Zhang     for (j = 0; j < nc; j++) {
18632d7a744SHong Zhang       if (cols[j] < 0) continue;
18732d7a744SHong Zhang       P2RO(A, 1, cols[j], &crank, &cidx);
18832d7a744SHong Zhang       RO2E(A, 1, crank, cidx, &ecol);
18932d7a744SHong Zhang 
19032d7a744SHong Zhang       for (i = 0; i < nr; i++) {
19132d7a744SHong Zhang         if (rows[i] < 0) continue;
19232d7a744SHong Zhang         P2RO(A, 0, rows[i], &rrank, &ridx);
19332d7a744SHong Zhang         RO2E(A, 0, rrank, ridx, &erow);
19432d7a744SHong Zhang         if (!a->emat->IsLocal(erow, ecol)) { /*off-proc entry*/
19532d7a744SHong Zhang           /* printf("Queueing remotely update of (%d,%d)\n",erow,ecol); */
19632d7a744SHong Zhang           a->emat->QueueUpdate(erow, ecol, vals[i + j * nr]);
19732d7a744SHong Zhang         }
19832d7a744SHong Zhang       }
19932d7a744SHong Zhang     }
20032d7a744SHong Zhang   }
201db31f6deSJed Brown   PetscFunctionReturn(0);
202db31f6deSJed Brown }
203db31f6deSJed Brown 
2049371c9d4SSatish Balay static PetscErrorCode MatMult_Elemental(Mat A, Vec X, Vec Y) {
205db31f6deSJed Brown   Mat_Elemental         *a = (Mat_Elemental *)A->data;
206e6dea9dbSXuan Zhou   const PetscElemScalar *x;
207e6dea9dbSXuan Zhou   PetscElemScalar       *y;
208df311e6cSXuan Zhou   PetscElemScalar        one = 1, zero = 0;
209db31f6deSJed Brown 
210db31f6deSJed Brown   PetscFunctionBegin;
2119566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(X, (const PetscScalar **)&x));
2129566063dSJacob Faibussowitsch   PetscCall(VecGetArray(Y, (PetscScalar **)&y));
213db31f6deSJed Brown   { /* Scoping so that constructor is called before pointer is returned */
214e8146892SSatish Balay     El::DistMatrix<PetscElemScalar, El::VC, El::STAR> xe, ye;
2150c18141cSBarry Smith     xe.LockedAttach(A->cmap->N, 1, *a->grid, 0, 0, x, A->cmap->n);
2160c18141cSBarry Smith     ye.Attach(A->rmap->N, 1, *a->grid, 0, 0, y, A->rmap->n);
217e8146892SSatish Balay     El::Gemv(El::NORMAL, one, *a->emat, xe, zero, ye);
218db31f6deSJed Brown   }
2199566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(X, (const PetscScalar **)&x));
2209566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(Y, (PetscScalar **)&y));
221db31f6deSJed Brown   PetscFunctionReturn(0);
222db31f6deSJed Brown }
223db31f6deSJed Brown 
2249371c9d4SSatish Balay static PetscErrorCode MatMultTranspose_Elemental(Mat A, Vec X, Vec Y) {
2259426833fSXuan Zhou   Mat_Elemental         *a = (Mat_Elemental *)A->data;
226df311e6cSXuan Zhou   const PetscElemScalar *x;
227df311e6cSXuan Zhou   PetscElemScalar       *y;
228e6dea9dbSXuan Zhou   PetscElemScalar        one = 1, zero = 0;
2299426833fSXuan Zhou 
2309426833fSXuan Zhou   PetscFunctionBegin;
2319566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(X, (const PetscScalar **)&x));
2329566063dSJacob Faibussowitsch   PetscCall(VecGetArray(Y, (PetscScalar **)&y));
2339426833fSXuan Zhou   { /* Scoping so that constructor is called before pointer is returned */
234e8146892SSatish Balay     El::DistMatrix<PetscElemScalar, El::VC, El::STAR> xe, ye;
2350c18141cSBarry Smith     xe.LockedAttach(A->rmap->N, 1, *a->grid, 0, 0, x, A->rmap->n);
2360c18141cSBarry Smith     ye.Attach(A->cmap->N, 1, *a->grid, 0, 0, y, A->cmap->n);
237e8146892SSatish Balay     El::Gemv(El::TRANSPOSE, one, *a->emat, xe, zero, ye);
2389426833fSXuan Zhou   }
2399566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(X, (const PetscScalar **)&x));
2409566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(Y, (PetscScalar **)&y));
2419426833fSXuan Zhou   PetscFunctionReturn(0);
2429426833fSXuan Zhou }
2439426833fSXuan Zhou 
2449371c9d4SSatish Balay static PetscErrorCode MatMultAdd_Elemental(Mat A, Vec X, Vec Y, Vec Z) {
245db31f6deSJed Brown   Mat_Elemental         *a = (Mat_Elemental *)A->data;
246df311e6cSXuan Zhou   const PetscElemScalar *x;
247df311e6cSXuan Zhou   PetscElemScalar       *z;
248e6dea9dbSXuan Zhou   PetscElemScalar        one = 1;
249db31f6deSJed Brown 
250db31f6deSJed Brown   PetscFunctionBegin;
2519566063dSJacob Faibussowitsch   if (Y != Z) PetscCall(VecCopy(Y, Z));
2529566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(X, (const PetscScalar **)&x));
2539566063dSJacob Faibussowitsch   PetscCall(VecGetArray(Z, (PetscScalar **)&z));
254db31f6deSJed Brown   { /* Scoping so that constructor is called before pointer is returned */
255e8146892SSatish Balay     El::DistMatrix<PetscElemScalar, El::VC, El::STAR> xe, ze;
2560c18141cSBarry Smith     xe.LockedAttach(A->cmap->N, 1, *a->grid, 0, 0, x, A->cmap->n);
2570c18141cSBarry Smith     ze.Attach(A->rmap->N, 1, *a->grid, 0, 0, z, A->rmap->n);
258e8146892SSatish Balay     El::Gemv(El::NORMAL, one, *a->emat, xe, one, ze);
259db31f6deSJed Brown   }
2609566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(X, (const PetscScalar **)&x));
2619566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(Z, (PetscScalar **)&z));
262db31f6deSJed Brown   PetscFunctionReturn(0);
263db31f6deSJed Brown }
264db31f6deSJed Brown 
2659371c9d4SSatish Balay static PetscErrorCode MatMultTransposeAdd_Elemental(Mat A, Vec X, Vec Y, Vec Z) {
266e883f9d5SXuan Zhou   Mat_Elemental         *a = (Mat_Elemental *)A->data;
267df311e6cSXuan Zhou   const PetscElemScalar *x;
268df311e6cSXuan Zhou   PetscElemScalar       *z;
269e6dea9dbSXuan Zhou   PetscElemScalar        one = 1;
270e883f9d5SXuan Zhou 
271e883f9d5SXuan Zhou   PetscFunctionBegin;
2729566063dSJacob Faibussowitsch   if (Y != Z) PetscCall(VecCopy(Y, Z));
2739566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(X, (const PetscScalar **)&x));
2749566063dSJacob Faibussowitsch   PetscCall(VecGetArray(Z, (PetscScalar **)&z));
275e883f9d5SXuan Zhou   { /* Scoping so that constructor is called before pointer is returned */
276e8146892SSatish Balay     El::DistMatrix<PetscElemScalar, El::VC, El::STAR> xe, ze;
2770c18141cSBarry Smith     xe.LockedAttach(A->rmap->N, 1, *a->grid, 0, 0, x, A->rmap->n);
2780c18141cSBarry Smith     ze.Attach(A->cmap->N, 1, *a->grid, 0, 0, z, A->cmap->n);
279e8146892SSatish Balay     El::Gemv(El::TRANSPOSE, one, *a->emat, xe, one, ze);
280e883f9d5SXuan Zhou   }
2819566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(X, (const PetscScalar **)&x));
2829566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(Z, (PetscScalar **)&z));
283e883f9d5SXuan Zhou   PetscFunctionReturn(0);
284e883f9d5SXuan Zhou }
285e883f9d5SXuan Zhou 
2869371c9d4SSatish Balay PetscErrorCode MatMatMultNumeric_Elemental(Mat A, Mat B, Mat C) {
287c1d1b975SXuan Zhou   Mat_Elemental  *a   = (Mat_Elemental *)A->data;
288c1d1b975SXuan Zhou   Mat_Elemental  *b   = (Mat_Elemental *)B->data;
2899a9e8502SHong Zhang   Mat_Elemental  *c   = (Mat_Elemental *)C->data;
290e6dea9dbSXuan Zhou   PetscElemScalar one = 1, zero = 0;
291c1d1b975SXuan Zhou 
292c1d1b975SXuan Zhou   PetscFunctionBegin;
293aae2c449SHong Zhang   { /* Scoping so that constructor is called before pointer is returned */
294e8146892SSatish Balay     El::Gemm(El::NORMAL, El::NORMAL, one, *a->emat, *b->emat, zero, *c->emat);
295aae2c449SHong Zhang   }
2969a9e8502SHong Zhang   C->assembled = PETSC_TRUE;
2979a9e8502SHong Zhang   PetscFunctionReturn(0);
2989a9e8502SHong Zhang }
2999a9e8502SHong Zhang 
3009371c9d4SSatish Balay PetscErrorCode MatMatMultSymbolic_Elemental(Mat A, Mat B, PetscReal fill, Mat Ce) {
3019a9e8502SHong Zhang   PetscFunctionBegin;
3029566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(Ce, A->rmap->n, B->cmap->n, PETSC_DECIDE, PETSC_DECIDE));
3039566063dSJacob Faibussowitsch   PetscCall(MatSetType(Ce, MATELEMENTAL));
3049566063dSJacob Faibussowitsch   PetscCall(MatSetUp(Ce));
3054222ddf1SHong Zhang   Ce->ops->matmultnumeric = MatMatMultNumeric_Elemental;
306c1d1b975SXuan Zhou   PetscFunctionReturn(0);
307c1d1b975SXuan Zhou }
308c1d1b975SXuan Zhou 
3099371c9d4SSatish Balay static PetscErrorCode MatMatTransposeMultNumeric_Elemental(Mat A, Mat B, Mat C) {
310df311e6cSXuan Zhou   Mat_Elemental  *a   = (Mat_Elemental *)A->data;
311df311e6cSXuan Zhou   Mat_Elemental  *b   = (Mat_Elemental *)B->data;
312df311e6cSXuan Zhou   Mat_Elemental  *c   = (Mat_Elemental *)C->data;
313e6dea9dbSXuan Zhou   PetscElemScalar one = 1, zero = 0;
314df311e6cSXuan Zhou 
315df311e6cSXuan Zhou   PetscFunctionBegin;
316df311e6cSXuan Zhou   { /* Scoping so that constructor is called before pointer is returned */
317e8146892SSatish Balay     El::Gemm(El::NORMAL, El::TRANSPOSE, one, *a->emat, *b->emat, zero, *c->emat);
318df311e6cSXuan Zhou   }
319df311e6cSXuan Zhou   C->assembled = PETSC_TRUE;
320df311e6cSXuan Zhou   PetscFunctionReturn(0);
321df311e6cSXuan Zhou }
322df311e6cSXuan Zhou 
3239371c9d4SSatish Balay static PetscErrorCode MatMatTransposeMultSymbolic_Elemental(Mat A, Mat B, PetscReal fill, Mat C) {
324df311e6cSXuan Zhou   PetscFunctionBegin;
3259566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(C, A->rmap->n, B->rmap->n, PETSC_DECIDE, PETSC_DECIDE));
3269566063dSJacob Faibussowitsch   PetscCall(MatSetType(C, MATELEMENTAL));
3279566063dSJacob Faibussowitsch   PetscCall(MatSetUp(C));
328df311e6cSXuan Zhou   PetscFunctionReturn(0);
329df311e6cSXuan Zhou }
330df311e6cSXuan Zhou 
3314222ddf1SHong Zhang /* --------------------------------------- */
3329371c9d4SSatish Balay static PetscErrorCode MatProductSetFromOptions_Elemental_AB(Mat C) {
3334222ddf1SHong Zhang   PetscFunctionBegin;
3344222ddf1SHong Zhang   C->ops->matmultsymbolic = MatMatMultSymbolic_Elemental;
3354222ddf1SHong Zhang   C->ops->productsymbolic = MatProductSymbolic_AB;
3364222ddf1SHong Zhang   PetscFunctionReturn(0);
3374222ddf1SHong Zhang }
3384222ddf1SHong Zhang 
3399371c9d4SSatish Balay static PetscErrorCode MatProductSetFromOptions_Elemental_ABt(Mat C) {
3404222ddf1SHong Zhang   PetscFunctionBegin;
3414222ddf1SHong Zhang   C->ops->mattransposemultsymbolic = MatMatTransposeMultSymbolic_Elemental;
3424222ddf1SHong Zhang   C->ops->productsymbolic          = MatProductSymbolic_ABt;
3434222ddf1SHong Zhang   PetscFunctionReturn(0);
3444222ddf1SHong Zhang }
3454222ddf1SHong Zhang 
3469371c9d4SSatish Balay PETSC_INTERN PetscErrorCode MatProductSetFromOptions_Elemental(Mat C) {
3474222ddf1SHong Zhang   Mat_Product *product = C->product;
3484222ddf1SHong Zhang 
3494222ddf1SHong Zhang   PetscFunctionBegin;
3504222ddf1SHong Zhang   switch (product->type) {
3519371c9d4SSatish Balay   case MATPRODUCT_AB: PetscCall(MatProductSetFromOptions_Elemental_AB(C)); break;
3529371c9d4SSatish Balay   case MATPRODUCT_ABt: PetscCall(MatProductSetFromOptions_Elemental_ABt(C)); break;
3539371c9d4SSatish Balay   default: break;
3544222ddf1SHong Zhang   }
3554222ddf1SHong Zhang   PetscFunctionReturn(0);
3564222ddf1SHong Zhang }
357f6e5db1bSPierre Jolivet 
3589371c9d4SSatish Balay PetscErrorCode MatMatMultNumeric_Elemental_MPIDense(Mat A, Mat B, Mat C) {
359f6e5db1bSPierre Jolivet   Mat Be, Ce;
360f6e5db1bSPierre Jolivet 
361f6e5db1bSPierre Jolivet   PetscFunctionBegin;
3629566063dSJacob Faibussowitsch   PetscCall(MatConvert(B, MATELEMENTAL, MAT_INITIAL_MATRIX, &Be));
3639566063dSJacob Faibussowitsch   PetscCall(MatMatMult(A, Be, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &Ce));
3649566063dSJacob Faibussowitsch   PetscCall(MatConvert(Ce, MATMPIDENSE, MAT_REUSE_MATRIX, &C));
3659566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Be));
3669566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Ce));
367f6e5db1bSPierre Jolivet   PetscFunctionReturn(0);
368f6e5db1bSPierre Jolivet }
369f6e5db1bSPierre Jolivet 
3709371c9d4SSatish Balay PetscErrorCode MatMatMultSymbolic_Elemental_MPIDense(Mat A, Mat B, PetscReal fill, Mat C) {
371f6e5db1bSPierre Jolivet   PetscFunctionBegin;
3729566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(C, A->rmap->n, B->cmap->n, PETSC_DECIDE, PETSC_DECIDE));
3739566063dSJacob Faibussowitsch   PetscCall(MatSetType(C, MATMPIDENSE));
3749566063dSJacob Faibussowitsch   PetscCall(MatSetUp(C));
375f6e5db1bSPierre Jolivet   C->ops->matmultnumeric = MatMatMultNumeric_Elemental_MPIDense;
376f6e5db1bSPierre Jolivet   PetscFunctionReturn(0);
377f6e5db1bSPierre Jolivet }
378f6e5db1bSPierre Jolivet 
3799371c9d4SSatish Balay PetscErrorCode MatProductSetFromOptions_Elemental_MPIDense_AB(Mat C) {
380f6e5db1bSPierre Jolivet   PetscFunctionBegin;
381f6e5db1bSPierre Jolivet   C->ops->matmultsymbolic = MatMatMultSymbolic_Elemental_MPIDense;
382f6e5db1bSPierre Jolivet   C->ops->productsymbolic = MatProductSymbolic_AB;
383f6e5db1bSPierre Jolivet   PetscFunctionReturn(0);
384f6e5db1bSPierre Jolivet }
385f6e5db1bSPierre Jolivet 
3869371c9d4SSatish Balay PetscErrorCode MatProductSetFromOptions_Elemental_MPIDense(Mat C) {
387f6e5db1bSPierre Jolivet   Mat_Product *product = C->product;
388f6e5db1bSPierre Jolivet 
389f6e5db1bSPierre Jolivet   PetscFunctionBegin;
39048a46eb9SPierre Jolivet   if (product->type == MATPRODUCT_AB) PetscCall(MatProductSetFromOptions_Elemental_MPIDense_AB(C));
391f6e5db1bSPierre Jolivet   PetscFunctionReturn(0);
392f6e5db1bSPierre Jolivet }
3934222ddf1SHong Zhang /* --------------------------------------- */
3944222ddf1SHong Zhang 
3959371c9d4SSatish Balay static PetscErrorCode MatGetDiagonal_Elemental(Mat A, Vec D) {
396a9d89745SXuan Zhou   PetscInt        i, nrows, ncols, nD, rrank, ridx, crank, cidx;
397a9d89745SXuan Zhou   Mat_Elemental  *a = (Mat_Elemental *)A->data;
398a9d89745SXuan Zhou   PetscElemScalar v;
399ce94432eSBarry Smith   MPI_Comm        comm;
40061119200SXuan Zhou 
40161119200SXuan Zhou   PetscFunctionBegin;
4029566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
4039566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &nrows, &ncols));
404a9d89745SXuan Zhou   nD = nrows > ncols ? ncols : nrows;
405a9d89745SXuan Zhou   for (i = 0; i < nD; i++) {
406a9d89745SXuan Zhou     PetscInt erow, ecol;
407a9d89745SXuan Zhou     P2RO(A, 0, i, &rrank, &ridx);
408a9d89745SXuan Zhou     RO2E(A, 0, rrank, ridx, &erow);
409aed4548fSBarry Smith     PetscCheck(rrank >= 0 && ridx >= 0 && erow >= 0, comm, PETSC_ERR_PLIB, "Incorrect row translation");
410a9d89745SXuan Zhou     P2RO(A, 1, i, &crank, &cidx);
411a9d89745SXuan Zhou     RO2E(A, 1, crank, cidx, &ecol);
412aed4548fSBarry Smith     PetscCheck(crank >= 0 && cidx >= 0 && ecol >= 0, comm, PETSC_ERR_PLIB, "Incorrect col translation");
413a9d89745SXuan Zhou     v = a->emat->Get(erow, ecol);
4149566063dSJacob Faibussowitsch     PetscCall(VecSetValues(D, 1, &i, (PetscScalar *)&v, INSERT_VALUES));
415ade3cc5eSXuan Zhou   }
4169566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(D));
4179566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(D));
41861119200SXuan Zhou   PetscFunctionReturn(0);
41961119200SXuan Zhou }
42061119200SXuan Zhou 
4219371c9d4SSatish Balay static PetscErrorCode MatDiagonalScale_Elemental(Mat X, Vec L, Vec R) {
422ade3cc5eSXuan Zhou   Mat_Elemental         *x = (Mat_Elemental *)X->data;
423ade3cc5eSXuan Zhou   const PetscElemScalar *d;
424ade3cc5eSXuan Zhou 
425ade3cc5eSXuan Zhou   PetscFunctionBegin;
4269065cd98SJed Brown   if (R) {
4279566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(R, (const PetscScalar **)&d));
428e8146892SSatish Balay     El::DistMatrix<PetscElemScalar, El::VC, El::STAR> de;
4290c18141cSBarry Smith     de.LockedAttach(X->cmap->N, 1, *x->grid, 0, 0, d, X->cmap->n);
430e8146892SSatish Balay     El::DiagonalScale(El::RIGHT, El::NORMAL, de, *x->emat);
4319566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(R, (const PetscScalar **)&d));
4329065cd98SJed Brown   }
4339065cd98SJed Brown   if (L) {
4349566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(L, (const PetscScalar **)&d));
435e8146892SSatish Balay     El::DistMatrix<PetscElemScalar, El::VC, El::STAR> de;
4360c18141cSBarry Smith     de.LockedAttach(X->rmap->N, 1, *x->grid, 0, 0, d, X->rmap->n);
437e8146892SSatish Balay     El::DiagonalScale(El::LEFT, El::NORMAL, de, *x->emat);
4389566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(L, (const PetscScalar **)&d));
439ade3cc5eSXuan Zhou   }
440ade3cc5eSXuan Zhou   PetscFunctionReturn(0);
441ade3cc5eSXuan Zhou }
442ade3cc5eSXuan Zhou 
4439371c9d4SSatish Balay static PetscErrorCode MatMissingDiagonal_Elemental(Mat A, PetscBool *missing, PetscInt *d) {
44434fa46e1SFrancesco Ballarin   PetscFunctionBegin;
44534fa46e1SFrancesco Ballarin   *missing = PETSC_FALSE;
44634fa46e1SFrancesco Ballarin   PetscFunctionReturn(0);
44734fa46e1SFrancesco Ballarin }
44834fa46e1SFrancesco Ballarin 
4499371c9d4SSatish Balay static PetscErrorCode MatScale_Elemental(Mat X, PetscScalar a) {
45065b78793SXuan Zhou   Mat_Elemental *x = (Mat_Elemental *)X->data;
45165b78793SXuan Zhou 
45265b78793SXuan Zhou   PetscFunctionBegin;
453e8146892SSatish Balay   El::Scale((PetscElemScalar)a, *x->emat);
45465b78793SXuan Zhou   PetscFunctionReturn(0);
45565b78793SXuan Zhou }
45665b78793SXuan Zhou 
457f82baa17SHong Zhang /*
458f82baa17SHong Zhang   MatAXPY - Computes Y = a*X + Y.
459f82baa17SHong Zhang */
4609371c9d4SSatish Balay static PetscErrorCode MatAXPY_Elemental(Mat Y, PetscScalar a, Mat X, MatStructure str) {
461e09a3074SHong Zhang   Mat_Elemental *x = (Mat_Elemental *)X->data;
462e09a3074SHong Zhang   Mat_Elemental *y = (Mat_Elemental *)Y->data;
463e09a3074SHong Zhang 
464e09a3074SHong Zhang   PetscFunctionBegin;
465e8146892SSatish Balay   El::Axpy((PetscElemScalar)a, *x->emat, *y->emat);
4669566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)Y));
467e09a3074SHong Zhang   PetscFunctionReturn(0);
468e09a3074SHong Zhang }
469e09a3074SHong Zhang 
4709371c9d4SSatish Balay static PetscErrorCode MatCopy_Elemental(Mat A, Mat B, MatStructure str) {
471d6223691SXuan Zhou   Mat_Elemental *a = (Mat_Elemental *)A->data;
472d6223691SXuan Zhou   Mat_Elemental *b = (Mat_Elemental *)B->data;
473d6223691SXuan Zhou 
474d6223691SXuan Zhou   PetscFunctionBegin;
475e8146892SSatish Balay   El::Copy(*a->emat, *b->emat);
4769566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)B));
477d6223691SXuan Zhou   PetscFunctionReturn(0);
478d6223691SXuan Zhou }
479d6223691SXuan Zhou 
4809371c9d4SSatish Balay static PetscErrorCode MatDuplicate_Elemental(Mat A, MatDuplicateOption op, Mat *B) {
481df311e6cSXuan Zhou   Mat            Be;
482ce94432eSBarry Smith   MPI_Comm       comm;
483df311e6cSXuan Zhou   Mat_Elemental *a = (Mat_Elemental *)A->data;
484df311e6cSXuan Zhou 
485df311e6cSXuan Zhou   PetscFunctionBegin;
4869566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
4879566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &Be));
4889566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(Be, A->rmap->n, A->cmap->n, PETSC_DECIDE, PETSC_DECIDE));
4899566063dSJacob Faibussowitsch   PetscCall(MatSetType(Be, MATELEMENTAL));
4909566063dSJacob Faibussowitsch   PetscCall(MatSetUp(Be));
491df311e6cSXuan Zhou   *B = Be;
492df311e6cSXuan Zhou   if (op == MAT_COPY_VALUES) {
493df311e6cSXuan Zhou     Mat_Elemental *b = (Mat_Elemental *)Be->data;
494e8146892SSatish Balay     El::Copy(*a->emat, *b->emat);
495df311e6cSXuan Zhou   }
496df311e6cSXuan Zhou   Be->assembled = PETSC_TRUE;
497df311e6cSXuan Zhou   PetscFunctionReturn(0);
498df311e6cSXuan Zhou }
499df311e6cSXuan Zhou 
5009371c9d4SSatish Balay static PetscErrorCode MatTranspose_Elemental(Mat A, MatReuse reuse, Mat *B) {
501ec8cb81fSBarry Smith   Mat            Be = *B;
502ce94432eSBarry Smith   MPI_Comm       comm;
5034fe7bbcaSHong Zhang   Mat_Elemental *a = (Mat_Elemental *)A->data, *b;
504d6223691SXuan Zhou 
505d6223691SXuan Zhou   PetscFunctionBegin;
5067fb60732SBarry Smith   if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B));
5079566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
5085cb544a0SHong Zhang   /* Only out-of-place supported */
5095f80ce2aSJacob Faibussowitsch   PetscCheck(reuse != MAT_INPLACE_MATRIX, comm, PETSC_ERR_SUP, "Only out-of-place supported");
5105262d616SXuan Zhou   if (reuse == MAT_INITIAL_MATRIX) {
5119566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, &Be));
5129566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(Be, A->cmap->n, A->rmap->n, PETSC_DECIDE, PETSC_DECIDE));
5139566063dSJacob Faibussowitsch     PetscCall(MatSetType(Be, MATELEMENTAL));
5149566063dSJacob Faibussowitsch     PetscCall(MatSetUp(Be));
5155262d616SXuan Zhou     *B = Be;
5165262d616SXuan Zhou   }
5174fe7bbcaSHong Zhang   b = (Mat_Elemental *)Be->data;
518e8146892SSatish Balay   El::Transpose(*a->emat, *b->emat);
5195262d616SXuan Zhou   Be->assembled = PETSC_TRUE;
520d6223691SXuan Zhou   PetscFunctionReturn(0);
521d6223691SXuan Zhou }
522d6223691SXuan Zhou 
5239371c9d4SSatish Balay static PetscErrorCode MatConjugate_Elemental(Mat A) {
524dfcb0403SXuan Zhou   Mat_Elemental *a = (Mat_Elemental *)A->data;
525dfcb0403SXuan Zhou 
526dfcb0403SXuan Zhou   PetscFunctionBegin;
527e8146892SSatish Balay   El::Conjugate(*a->emat);
528dfcb0403SXuan Zhou   PetscFunctionReturn(0);
529dfcb0403SXuan Zhou }
530dfcb0403SXuan Zhou 
5319371c9d4SSatish Balay static PetscErrorCode MatHermitianTranspose_Elemental(Mat A, MatReuse reuse, Mat *B) {
532ec8cb81fSBarry Smith   Mat            Be = *B;
533ce94432eSBarry Smith   MPI_Comm       comm;
5344a29722dSXuan Zhou   Mat_Elemental *a = (Mat_Elemental *)A->data, *b;
5354a29722dSXuan Zhou 
5364a29722dSXuan Zhou   PetscFunctionBegin;
5379566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
5385cb544a0SHong Zhang   /* Only out-of-place supported */
5394a29722dSXuan Zhou   if (reuse == MAT_INITIAL_MATRIX) {
5409566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, &Be));
5419566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(Be, A->cmap->n, A->rmap->n, PETSC_DECIDE, PETSC_DECIDE));
5429566063dSJacob Faibussowitsch     PetscCall(MatSetType(Be, MATELEMENTAL));
5439566063dSJacob Faibussowitsch     PetscCall(MatSetUp(Be));
5444a29722dSXuan Zhou     *B = Be;
5454a29722dSXuan Zhou   }
5464a29722dSXuan Zhou   b = (Mat_Elemental *)Be->data;
547e8146892SSatish Balay   El::Adjoint(*a->emat, *b->emat);
5484a29722dSXuan Zhou   Be->assembled = PETSC_TRUE;
5494a29722dSXuan Zhou   PetscFunctionReturn(0);
5504a29722dSXuan Zhou }
5514a29722dSXuan Zhou 
5529371c9d4SSatish Balay static PetscErrorCode MatSolve_Elemental(Mat A, Vec B, Vec X) {
5531f881ff8SXuan Zhou   Mat_Elemental   *a = (Mat_Elemental *)A->data;
554df311e6cSXuan Zhou   PetscElemScalar *x;
555ea394475SSatish Balay   PetscInt         pivoting = a->pivoting;
5561f881ff8SXuan Zhou 
5571f881ff8SXuan Zhou   PetscFunctionBegin;
5589566063dSJacob Faibussowitsch   PetscCall(VecCopy(B, X));
5599566063dSJacob Faibussowitsch   PetscCall(VecGetArray(X, (PetscScalar **)&x));
560ea394475SSatish Balay 
561e8146892SSatish Balay   El::DistMatrix<PetscElemScalar, El::VC, El::STAR> xe;
5620c18141cSBarry Smith   xe.Attach(A->rmap->N, 1, *a->grid, 0, 0, x, A->rmap->n);
563e8146892SSatish Balay   El::DistMatrix<PetscElemScalar, El::MC, El::MR> xer(xe);
564fc54b460SXuan Zhou   switch (A->factortype) {
565fc54b460SXuan Zhou   case MAT_FACTOR_LU:
566ea394475SSatish Balay     if (pivoting == 0) {
567e8146892SSatish Balay       El::lu::SolveAfter(El::NORMAL, *a->emat, xer);
568ea394475SSatish Balay     } else if (pivoting == 1) {
569ea394475SSatish Balay       El::lu::SolveAfter(El::NORMAL, *a->emat, *a->P, xer);
570ea394475SSatish Balay     } else { /* pivoting == 2 */
571ea394475SSatish Balay       El::lu::SolveAfter(El::NORMAL, *a->emat, *a->P, *a->Q, xer);
5721f881ff8SXuan Zhou     }
573fc54b460SXuan Zhou     break;
5749371c9d4SSatish Balay   case MAT_FACTOR_CHOLESKY: El::cholesky::SolveAfter(El::UPPER, El::NORMAL, *a->emat, xer); break;
5759371c9d4SSatish Balay   default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unfactored Matrix or Unsupported MatFactorType"); break;
5761f881ff8SXuan Zhou   }
577ea394475SSatish Balay   El::Copy(xer, xe);
578ea394475SSatish Balay 
5799566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(X, (PetscScalar **)&x));
5801f881ff8SXuan Zhou   PetscFunctionReturn(0);
5811f881ff8SXuan Zhou }
5821f881ff8SXuan Zhou 
5839371c9d4SSatish Balay static PetscErrorCode MatSolveAdd_Elemental(Mat A, Vec B, Vec Y, Vec X) {
584df311e6cSXuan Zhou   PetscFunctionBegin;
5859566063dSJacob Faibussowitsch   PetscCall(MatSolve_Elemental(A, B, X));
5869566063dSJacob Faibussowitsch   PetscCall(VecAXPY(X, 1, Y));
587df311e6cSXuan Zhou   PetscFunctionReturn(0);
588df311e6cSXuan Zhou }
589df311e6cSXuan Zhou 
5909371c9d4SSatish Balay static PetscErrorCode MatMatSolve_Elemental(Mat A, Mat B, Mat X) {
5911f0e42cfSHong Zhang   Mat_Elemental *a = (Mat_Elemental *)A->data;
59242ba530cSPierre Jolivet   Mat_Elemental *x;
59342ba530cSPierre Jolivet   Mat            C;
594ea394475SSatish Balay   PetscInt       pivoting = a->pivoting;
59542ba530cSPierre Jolivet   PetscBool      flg;
59642ba530cSPierre Jolivet   MatType        type;
5971f0e42cfSHong Zhang 
598ae844d54SHong Zhang   PetscFunctionBegin;
5999566063dSJacob Faibussowitsch   PetscCall(MatGetType(X, &type));
6009566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(type, MATELEMENTAL, &flg));
60142ba530cSPierre Jolivet   if (!flg) {
6029566063dSJacob Faibussowitsch     PetscCall(MatConvert(B, MATELEMENTAL, MAT_INITIAL_MATRIX, &C));
60342ba530cSPierre Jolivet     x = (Mat_Elemental *)C->data;
60442ba530cSPierre Jolivet   } else {
60542ba530cSPierre Jolivet     x = (Mat_Elemental *)X->data;
60642ba530cSPierre Jolivet     El::Copy(*((Mat_Elemental *)B->data)->emat, *x->emat);
60742ba530cSPierre Jolivet   }
608fc54b460SXuan Zhou   switch (A->factortype) {
609fc54b460SXuan Zhou   case MAT_FACTOR_LU:
610ea394475SSatish Balay     if (pivoting == 0) {
611e8146892SSatish Balay       El::lu::SolveAfter(El::NORMAL, *a->emat, *x->emat);
612ea394475SSatish Balay     } else if (pivoting == 1) {
613ea394475SSatish Balay       El::lu::SolveAfter(El::NORMAL, *a->emat, *a->P, *x->emat);
614ea394475SSatish Balay     } else {
615ea394475SSatish Balay       El::lu::SolveAfter(El::NORMAL, *a->emat, *a->P, *a->Q, *x->emat);
616d6223691SXuan Zhou     }
617fc54b460SXuan Zhou     break;
6189371c9d4SSatish Balay   case MAT_FACTOR_CHOLESKY: El::cholesky::SolveAfter(El::UPPER, El::NORMAL, *a->emat, *x->emat); break;
6199371c9d4SSatish Balay   default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unfactored Matrix or Unsupported MatFactorType"); break;
620fc54b460SXuan Zhou   }
62142ba530cSPierre Jolivet   if (!flg) {
6229566063dSJacob Faibussowitsch     PetscCall(MatConvert(C, type, MAT_REUSE_MATRIX, &X));
6239566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&C));
62442ba530cSPierre Jolivet   }
625ae844d54SHong Zhang   PetscFunctionReturn(0);
626ae844d54SHong Zhang }
627ae844d54SHong Zhang 
6289371c9d4SSatish Balay static PetscErrorCode MatLUFactor_Elemental(Mat A, IS row, IS col, const MatFactorInfo *info) {
6297c920d81SXuan Zhou   Mat_Elemental *a        = (Mat_Elemental *)A->data;
630ea394475SSatish Balay   PetscInt       pivoting = a->pivoting;
6317c920d81SXuan Zhou 
632ae844d54SHong Zhang   PetscFunctionBegin;
633ea394475SSatish Balay   if (pivoting == 0) {
634e8146892SSatish Balay     El::LU(*a->emat);
635ea394475SSatish Balay   } else if (pivoting == 1) {
636ea394475SSatish Balay     El::LU(*a->emat, *a->P);
637ea394475SSatish Balay   } else {
638ea394475SSatish Balay     El::LU(*a->emat, *a->P, *a->Q);
639d6223691SXuan Zhou   }
6401293973dSHong Zhang   A->factortype = MAT_FACTOR_LU;
641834d3fecSHong Zhang   A->assembled  = PETSC_TRUE;
642f6224b95SHong Zhang 
6439566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->solvertype));
6449566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(MATSOLVERELEMENTAL, &A->solvertype));
645ae844d54SHong Zhang   PetscFunctionReturn(0);
646ae844d54SHong Zhang }
647ae844d54SHong Zhang 
6489371c9d4SSatish Balay static PetscErrorCode MatLUFactorNumeric_Elemental(Mat F, Mat A, const MatFactorInfo *info) {
649d7c3f9d8SHong Zhang   PetscFunctionBegin;
6509566063dSJacob Faibussowitsch   PetscCall(MatCopy(A, F, SAME_NONZERO_PATTERN));
6519566063dSJacob Faibussowitsch   PetscCall(MatLUFactor_Elemental(F, 0, 0, info));
652d7c3f9d8SHong Zhang   PetscFunctionReturn(0);
653d7c3f9d8SHong Zhang }
654d7c3f9d8SHong Zhang 
6559371c9d4SSatish Balay static PetscErrorCode MatLUFactorSymbolic_Elemental(Mat F, Mat A, IS r, IS c, const MatFactorInfo *info) {
656d7c3f9d8SHong Zhang   PetscFunctionBegin;
657d8304050SJose E. Roman   /* F is created and allocated by MatGetFactor_elemental_petsc(), skip this routine. */
658d7c3f9d8SHong Zhang   PetscFunctionReturn(0);
659d7c3f9d8SHong Zhang }
660d7c3f9d8SHong Zhang 
6619371c9d4SSatish Balay static PetscErrorCode MatCholeskyFactor_Elemental(Mat A, IS perm, const MatFactorInfo *info) {
66245cf121fSXuan Zhou   Mat_Elemental                                    *a = (Mat_Elemental *)A->data;
663e8146892SSatish Balay   El::DistMatrix<PetscElemScalar, El::MC, El::STAR> d;
66445cf121fSXuan Zhou 
66545cf121fSXuan Zhou   PetscFunctionBegin;
666e8146892SSatish Balay   El::Cholesky(El::UPPER, *a->emat);
667fc54b460SXuan Zhou   A->factortype = MAT_FACTOR_CHOLESKY;
668834d3fecSHong Zhang   A->assembled  = PETSC_TRUE;
669f6224b95SHong Zhang 
6709566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->solvertype));
6719566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(MATSOLVERELEMENTAL, &A->solvertype));
67245cf121fSXuan Zhou   PetscFunctionReturn(0);
67345cf121fSXuan Zhou }
67445cf121fSXuan Zhou 
6759371c9d4SSatish Balay static PetscErrorCode MatCholeskyFactorNumeric_Elemental(Mat F, Mat A, const MatFactorInfo *info) {
676cb76c1d8SXuan Zhou   PetscFunctionBegin;
6779566063dSJacob Faibussowitsch   PetscCall(MatCopy(A, F, SAME_NONZERO_PATTERN));
6789566063dSJacob Faibussowitsch   PetscCall(MatCholeskyFactor_Elemental(F, 0, info));
679cb76c1d8SXuan Zhou   PetscFunctionReturn(0);
68079673f7bSHong Zhang }
681cb76c1d8SXuan Zhou 
6829371c9d4SSatish Balay static PetscErrorCode MatCholeskyFactorSymbolic_Elemental(Mat F, Mat A, IS perm, const MatFactorInfo *info) {
68379673f7bSHong Zhang   PetscFunctionBegin;
684d8304050SJose E. Roman   /* F is created and allocated by MatGetFactor_elemental_petsc(), skip this routine. */
68579673f7bSHong Zhang   PetscFunctionReturn(0);
68679673f7bSHong Zhang }
68779673f7bSHong Zhang 
6889371c9d4SSatish Balay PetscErrorCode MatFactorGetSolverType_elemental_elemental(Mat A, MatSolverType *type) {
68915767789SHong Zhang   PetscFunctionBegin;
69015767789SHong Zhang   *type = MATSOLVERELEMENTAL;
69115767789SHong Zhang   PetscFunctionReturn(0);
69215767789SHong Zhang }
69315767789SHong Zhang 
6949371c9d4SSatish Balay static PetscErrorCode MatGetFactor_elemental_elemental(Mat A, MatFactorType ftype, Mat *F) {
6951293973dSHong Zhang   Mat B;
6961293973dSHong Zhang 
6971293973dSHong Zhang   PetscFunctionBegin;
6981293973dSHong Zhang   /* Create the factorization matrix */
6999566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &B));
7009566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(B, A->rmap->n, A->cmap->n, PETSC_DECIDE, PETSC_DECIDE));
7019566063dSJacob Faibussowitsch   PetscCall(MatSetType(B, MATELEMENTAL));
7029566063dSJacob Faibussowitsch   PetscCall(MatSetUp(B));
7031293973dSHong Zhang   B->factortype      = ftype;
70466e17bc3SBarry Smith   B->trivialsymbolic = PETSC_TRUE;
7059566063dSJacob Faibussowitsch   PetscCall(PetscFree(B->solvertype));
7069566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(MATSOLVERELEMENTAL, &B->solvertype));
70700c67f3bSHong Zhang 
7089566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatFactorGetSolverType_C", MatFactorGetSolverType_elemental_elemental));
7091293973dSHong Zhang   *F = B;
7101293973dSHong Zhang   PetscFunctionReturn(0);
7111293973dSHong Zhang }
7121293973dSHong Zhang 
7139371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode MatSolverTypeRegister_Elemental(void) {
71442c9c57cSBarry Smith   PetscFunctionBegin;
7159566063dSJacob Faibussowitsch   PetscCall(MatSolverTypeRegister(MATSOLVERELEMENTAL, MATELEMENTAL, MAT_FACTOR_LU, MatGetFactor_elemental_elemental));
7169566063dSJacob Faibussowitsch   PetscCall(MatSolverTypeRegister(MATSOLVERELEMENTAL, MATELEMENTAL, MAT_FACTOR_CHOLESKY, MatGetFactor_elemental_elemental));
71742c9c57cSBarry Smith   PetscFunctionReturn(0);
71842c9c57cSBarry Smith }
71942c9c57cSBarry Smith 
7209371c9d4SSatish Balay static PetscErrorCode MatNorm_Elemental(Mat A, NormType type, PetscReal *nrm) {
7211f881ff8SXuan Zhou   Mat_Elemental *a = (Mat_Elemental *)A->data;
7221f881ff8SXuan Zhou 
7231f881ff8SXuan Zhou   PetscFunctionBegin;
7241f881ff8SXuan Zhou   switch (type) {
7259371c9d4SSatish Balay   case NORM_1: *nrm = El::OneNorm(*a->emat); break;
7269371c9d4SSatish Balay   case NORM_FROBENIUS: *nrm = El::FrobeniusNorm(*a->emat); break;
7279371c9d4SSatish Balay   case NORM_INFINITY: *nrm = El::InfinityNorm(*a->emat); break;
7289371c9d4SSatish Balay   default: SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Unsupported norm type");
7291f881ff8SXuan Zhou   }
7301f881ff8SXuan Zhou   PetscFunctionReturn(0);
7311f881ff8SXuan Zhou }
7321f881ff8SXuan Zhou 
7339371c9d4SSatish Balay static PetscErrorCode MatZeroEntries_Elemental(Mat A) {
7345262d616SXuan Zhou   Mat_Elemental *a = (Mat_Elemental *)A->data;
7355262d616SXuan Zhou 
7365262d616SXuan Zhou   PetscFunctionBegin;
737e8146892SSatish Balay   El::Zero(*a->emat);
7385262d616SXuan Zhou   PetscFunctionReturn(0);
7395262d616SXuan Zhou }
7405262d616SXuan Zhou 
7419371c9d4SSatish Balay static PetscErrorCode MatGetOwnershipIS_Elemental(Mat A, IS *rows, IS *cols) {
742db31f6deSJed Brown   Mat_Elemental *a = (Mat_Elemental *)A->data;
743db31f6deSJed Brown   PetscInt       i, m, shift, stride, *idx;
744db31f6deSJed Brown 
745db31f6deSJed Brown   PetscFunctionBegin;
746db31f6deSJed Brown   if (rows) {
747db31f6deSJed Brown     m      = a->emat->LocalHeight();
748db31f6deSJed Brown     shift  = a->emat->ColShift();
749db31f6deSJed Brown     stride = a->emat->ColStride();
7509566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(m, &idx));
751db31f6deSJed Brown     for (i = 0; i < m; i++) {
752db31f6deSJed Brown       PetscInt rank, offset;
753db31f6deSJed Brown       E2RO(A, 0, shift + i * stride, &rank, &offset);
754db31f6deSJed Brown       RO2P(A, 0, rank, offset, &idx[i]);
755db31f6deSJed Brown     }
7569566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, idx, PETSC_OWN_POINTER, rows));
757db31f6deSJed Brown   }
758db31f6deSJed Brown   if (cols) {
759db31f6deSJed Brown     m      = a->emat->LocalWidth();
760db31f6deSJed Brown     shift  = a->emat->RowShift();
761db31f6deSJed Brown     stride = a->emat->RowStride();
7629566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(m, &idx));
763db31f6deSJed Brown     for (i = 0; i < m; i++) {
764db31f6deSJed Brown       PetscInt rank, offset;
765db31f6deSJed Brown       E2RO(A, 1, shift + i * stride, &rank, &offset);
766db31f6deSJed Brown       RO2P(A, 1, rank, offset, &idx[i]);
767db31f6deSJed Brown     }
7689566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, idx, PETSC_OWN_POINTER, cols));
769db31f6deSJed Brown   }
770db31f6deSJed Brown   PetscFunctionReturn(0);
771db31f6deSJed Brown }
772db31f6deSJed Brown 
7739371c9d4SSatish Balay static PetscErrorCode MatConvert_Elemental_Dense(Mat A, MatType newtype, MatReuse reuse, Mat *B) {
7742ef0cf24SXuan Zhou   Mat             Bmpi;
775af295397SXuan Zhou   Mat_Elemental  *a = (Mat_Elemental *)A->data;
776ce94432eSBarry Smith   MPI_Comm        comm;
777fa9e26c8SHong Zhang   IS              isrows, iscols;
778fa9e26c8SHong Zhang   PetscInt        rrank, ridx, crank, cidx, nrows, ncols, i, j, erow, ecol, elrow, elcol;
779fa9e26c8SHong Zhang   const PetscInt *rows, *cols;
780df311e6cSXuan Zhou   PetscElemScalar v;
781fa9e26c8SHong Zhang   const El::Grid &grid = a->emat->Grid();
782af295397SXuan Zhou 
783af295397SXuan Zhou   PetscFunctionBegin;
7849566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
785a000e53bSHong Zhang 
786de0a22f0SHong Zhang   if (reuse == MAT_REUSE_MATRIX) {
787de0a22f0SHong Zhang     Bmpi = *B;
788de0a22f0SHong Zhang   } else {
7899566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, &Bmpi));
7909566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(Bmpi, A->rmap->n, A->cmap->n, PETSC_DECIDE, PETSC_DECIDE));
7919566063dSJacob Faibussowitsch     PetscCall(MatSetType(Bmpi, MATDENSE));
7929566063dSJacob Faibussowitsch     PetscCall(MatSetUp(Bmpi));
793de0a22f0SHong Zhang   }
794fa9e26c8SHong Zhang 
795fa9e26c8SHong Zhang   /* Get local entries of A */
7969566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipIS(A, &isrows, &iscols));
7979566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(isrows, &nrows));
7989566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(isrows, &rows));
7999566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(iscols, &ncols));
8009566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(iscols, &cols));
801fa9e26c8SHong Zhang 
80257299f2fSHong Zhang   if (a->roworiented) {
8032ef0cf24SXuan Zhou     for (i = 0; i < nrows; i++) {
804fa9e26c8SHong Zhang       P2RO(A, 0, rows[i], &rrank, &ridx); /* convert indices between PETSc <-> (Rank,Offset) <-> Elemental */
8052ef0cf24SXuan Zhou       RO2E(A, 0, rrank, ridx, &erow);
806aed4548fSBarry Smith       PetscCheck(rrank >= 0 && ridx >= 0 && erow >= 0, comm, PETSC_ERR_PLIB, "Incorrect row translation");
8072ef0cf24SXuan Zhou       for (j = 0; j < ncols; j++) {
808fa9e26c8SHong Zhang         P2RO(A, 1, cols[j], &crank, &cidx);
8092ef0cf24SXuan Zhou         RO2E(A, 1, crank, cidx, &ecol);
810aed4548fSBarry Smith         PetscCheck(crank >= 0 && cidx >= 0 && ecol >= 0, comm, PETSC_ERR_PLIB, "Incorrect col translation");
811fa9e26c8SHong Zhang 
812fa9e26c8SHong Zhang         elrow = erow / grid.MCSize(); /* Elemental local row index */
813fa9e26c8SHong Zhang         elcol = ecol / grid.MRSize(); /* Elemental local column index */
814fa9e26c8SHong Zhang         v     = a->emat->GetLocal(elrow, elcol);
8159566063dSJacob Faibussowitsch         PetscCall(MatSetValues(Bmpi, 1, &rows[i], 1, &cols[j], (PetscScalar *)&v, INSERT_VALUES));
8162ef0cf24SXuan Zhou       }
8172ef0cf24SXuan Zhou     }
81857299f2fSHong Zhang   } else { /* column-oriented */
81957299f2fSHong Zhang     for (j = 0; j < ncols; j++) {
82057299f2fSHong Zhang       P2RO(A, 1, cols[j], &crank, &cidx);
82157299f2fSHong Zhang       RO2E(A, 1, crank, cidx, &ecol);
822aed4548fSBarry Smith       PetscCheck(crank >= 0 && cidx >= 0 && ecol >= 0, comm, PETSC_ERR_PLIB, "Incorrect col translation");
82357299f2fSHong Zhang       for (i = 0; i < nrows; i++) {
82457299f2fSHong Zhang         P2RO(A, 0, rows[i], &rrank, &ridx); /* convert indices between PETSc <-> (Rank,Offset) <-> Elemental */
82557299f2fSHong Zhang         RO2E(A, 0, rrank, ridx, &erow);
826aed4548fSBarry Smith         PetscCheck(rrank >= 0 && ridx >= 0 && erow >= 0, comm, PETSC_ERR_PLIB, "Incorrect row translation");
82757299f2fSHong Zhang 
82857299f2fSHong Zhang         elrow = erow / grid.MCSize(); /* Elemental local row index */
82957299f2fSHong Zhang         elcol = ecol / grid.MRSize(); /* Elemental local column index */
83057299f2fSHong Zhang         v     = a->emat->GetLocal(elrow, elcol);
8319566063dSJacob Faibussowitsch         PetscCall(MatSetValues(Bmpi, 1, &rows[i], 1, &cols[j], (PetscScalar *)&v, INSERT_VALUES));
83257299f2fSHong Zhang       }
83357299f2fSHong Zhang     }
83457299f2fSHong Zhang   }
8359566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(Bmpi, MAT_FINAL_ASSEMBLY));
8369566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(Bmpi, MAT_FINAL_ASSEMBLY));
837511c6705SHong Zhang   if (reuse == MAT_INPLACE_MATRIX) {
8389566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &Bmpi));
839c4ad791aSXuan Zhou   } else {
840c4ad791aSXuan Zhou     *B = Bmpi;
841c4ad791aSXuan Zhou   }
8429566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&isrows));
8439566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&iscols));
844af295397SXuan Zhou   PetscFunctionReturn(0);
845af295397SXuan Zhou }
846af295397SXuan Zhou 
8479371c9d4SSatish Balay PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_Elemental(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) {
848af8000cdSHong Zhang   Mat                mat_elemental;
849af8000cdSHong Zhang   PetscInt           M = A->rmap->N, N = A->cmap->N, row, ncols;
850af8000cdSHong Zhang   const PetscInt    *cols;
851af8000cdSHong Zhang   const PetscScalar *vals;
852af8000cdSHong Zhang 
853af8000cdSHong Zhang   PetscFunctionBegin;
854bdeae278SStefano Zampini   if (reuse == MAT_REUSE_MATRIX) {
855bdeae278SStefano Zampini     mat_elemental = *newmat;
8569566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(mat_elemental));
857bdeae278SStefano Zampini   } else {
8589566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &mat_elemental));
8599566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(mat_elemental, PETSC_DECIDE, PETSC_DECIDE, M, N));
8609566063dSJacob Faibussowitsch     PetscCall(MatSetType(mat_elemental, MATELEMENTAL));
8619566063dSJacob Faibussowitsch     PetscCall(MatSetUp(mat_elemental));
862bdeae278SStefano Zampini   }
863af8000cdSHong Zhang   for (row = 0; row < M; row++) {
8649566063dSJacob Faibussowitsch     PetscCall(MatGetRow(A, row, &ncols, &cols, &vals));
865bdeae278SStefano Zampini     /* PETSc-Elemental interface uses axpy for setting off-processor entries, only ADD_VALUES is allowed */
8669566063dSJacob Faibussowitsch     PetscCall(MatSetValues(mat_elemental, 1, &row, ncols, cols, vals, ADD_VALUES));
8679566063dSJacob Faibussowitsch     PetscCall(MatRestoreRow(A, row, &ncols, &cols, &vals));
868af8000cdSHong Zhang   }
8699566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat_elemental, MAT_FINAL_ASSEMBLY));
8709566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat_elemental, MAT_FINAL_ASSEMBLY));
871af8000cdSHong Zhang 
872511c6705SHong Zhang   if (reuse == MAT_INPLACE_MATRIX) {
8739566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &mat_elemental));
874af8000cdSHong Zhang   } else {
875af8000cdSHong Zhang     *newmat = mat_elemental;
876af8000cdSHong Zhang   }
877af8000cdSHong Zhang   PetscFunctionReturn(0);
878af8000cdSHong Zhang }
879af8000cdSHong Zhang 
8809371c9d4SSatish Balay PETSC_INTERN PetscErrorCode MatConvert_MPIAIJ_Elemental(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) {
8815d7652ecSHong Zhang   Mat                mat_elemental;
8825d7652ecSHong Zhang   PetscInt           row, ncols, rstart = A->rmap->rstart, rend = A->rmap->rend, j;
8835d7652ecSHong Zhang   const PetscInt    *cols;
8845d7652ecSHong Zhang   const PetscScalar *vals;
8855d7652ecSHong Zhang 
8865d7652ecSHong Zhang   PetscFunctionBegin;
887bdeae278SStefano Zampini   if (reuse == MAT_REUSE_MATRIX) {
888bdeae278SStefano Zampini     mat_elemental = *newmat;
8899566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(mat_elemental));
890bdeae278SStefano Zampini   } else {
8919566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &mat_elemental));
8929566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(mat_elemental, PETSC_DECIDE, PETSC_DECIDE, A->rmap->N, A->cmap->N));
8939566063dSJacob Faibussowitsch     PetscCall(MatSetType(mat_elemental, MATELEMENTAL));
8949566063dSJacob Faibussowitsch     PetscCall(MatSetUp(mat_elemental));
895bdeae278SStefano Zampini   }
8965d7652ecSHong Zhang   for (row = rstart; row < rend; row++) {
8979566063dSJacob Faibussowitsch     PetscCall(MatGetRow(A, row, &ncols, &cols, &vals));
8985d7652ecSHong Zhang     for (j = 0; j < ncols; j++) {
899bdeae278SStefano Zampini       /* PETSc-Elemental interface uses axpy for setting off-processor entries, only ADD_VALUES is allowed */
9009566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mat_elemental, 1, &row, 1, &cols[j], &vals[j], ADD_VALUES));
9015d7652ecSHong Zhang     }
9029566063dSJacob Faibussowitsch     PetscCall(MatRestoreRow(A, row, &ncols, &cols, &vals));
9035d7652ecSHong Zhang   }
9049566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat_elemental, MAT_FINAL_ASSEMBLY));
9059566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat_elemental, MAT_FINAL_ASSEMBLY));
9065d7652ecSHong Zhang 
907511c6705SHong Zhang   if (reuse == MAT_INPLACE_MATRIX) {
9089566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &mat_elemental));
9095d7652ecSHong Zhang   } else {
9105d7652ecSHong Zhang     *newmat = mat_elemental;
9115d7652ecSHong Zhang   }
9125d7652ecSHong Zhang   PetscFunctionReturn(0);
9135d7652ecSHong Zhang }
9145d7652ecSHong Zhang 
9159371c9d4SSatish Balay PETSC_INTERN PetscErrorCode MatConvert_SeqSBAIJ_Elemental(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) {
9166214f412SHong Zhang   Mat                mat_elemental;
9176214f412SHong Zhang   PetscInt           M = A->rmap->N, N = A->cmap->N, row, ncols, j;
9186214f412SHong Zhang   const PetscInt    *cols;
9196214f412SHong Zhang   const PetscScalar *vals;
9206214f412SHong Zhang 
9216214f412SHong Zhang   PetscFunctionBegin;
922bdeae278SStefano Zampini   if (reuse == MAT_REUSE_MATRIX) {
923bdeae278SStefano Zampini     mat_elemental = *newmat;
9249566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(mat_elemental));
925bdeae278SStefano Zampini   } else {
9269566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &mat_elemental));
9279566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(mat_elemental, PETSC_DECIDE, PETSC_DECIDE, M, N));
9289566063dSJacob Faibussowitsch     PetscCall(MatSetType(mat_elemental, MATELEMENTAL));
9299566063dSJacob Faibussowitsch     PetscCall(MatSetUp(mat_elemental));
930bdeae278SStefano Zampini   }
9319566063dSJacob Faibussowitsch   PetscCall(MatGetRowUpperTriangular(A));
9326214f412SHong Zhang   for (row = 0; row < M; row++) {
9339566063dSJacob Faibussowitsch     PetscCall(MatGetRow(A, row, &ncols, &cols, &vals));
934bdeae278SStefano Zampini     /* PETSc-Elemental interface uses axpy for setting off-processor entries, only ADD_VALUES is allowed */
9359566063dSJacob Faibussowitsch     PetscCall(MatSetValues(mat_elemental, 1, &row, ncols, cols, vals, ADD_VALUES));
9366214f412SHong Zhang     for (j = 0; j < ncols; j++) { /* lower triangular part */
937eb1ec7c1SStefano Zampini       PetscScalar v;
9386214f412SHong Zhang       if (cols[j] == row) continue;
939b94d7dedSBarry Smith       v = A->hermitian == PETSC_BOOL3_TRUE ? PetscConj(vals[j]) : vals[j];
9409566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mat_elemental, 1, &cols[j], 1, &row, &v, ADD_VALUES));
9416214f412SHong Zhang     }
9429566063dSJacob Faibussowitsch     PetscCall(MatRestoreRow(A, row, &ncols, &cols, &vals));
9436214f412SHong Zhang   }
9449566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowUpperTriangular(A));
9459566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat_elemental, MAT_FINAL_ASSEMBLY));
9469566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat_elemental, MAT_FINAL_ASSEMBLY));
9476214f412SHong Zhang 
948511c6705SHong Zhang   if (reuse == MAT_INPLACE_MATRIX) {
9499566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &mat_elemental));
9506214f412SHong Zhang   } else {
9516214f412SHong Zhang     *newmat = mat_elemental;
9526214f412SHong Zhang   }
9536214f412SHong Zhang   PetscFunctionReturn(0);
9546214f412SHong Zhang }
9556214f412SHong Zhang 
9569371c9d4SSatish Balay PETSC_INTERN PetscErrorCode MatConvert_MPISBAIJ_Elemental(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) {
9576214f412SHong Zhang   Mat                mat_elemental;
9586214f412SHong Zhang   PetscInt           M = A->rmap->N, N = A->cmap->N, row, ncols, j, rstart = A->rmap->rstart, rend = A->rmap->rend;
9596214f412SHong Zhang   const PetscInt    *cols;
9606214f412SHong Zhang   const PetscScalar *vals;
9616214f412SHong Zhang 
9626214f412SHong Zhang   PetscFunctionBegin;
963bdeae278SStefano Zampini   if (reuse == MAT_REUSE_MATRIX) {
964bdeae278SStefano Zampini     mat_elemental = *newmat;
9659566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(mat_elemental));
966bdeae278SStefano Zampini   } else {
9679566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &mat_elemental));
9689566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(mat_elemental, PETSC_DECIDE, PETSC_DECIDE, M, N));
9699566063dSJacob Faibussowitsch     PetscCall(MatSetType(mat_elemental, MATELEMENTAL));
9709566063dSJacob Faibussowitsch     PetscCall(MatSetUp(mat_elemental));
971bdeae278SStefano Zampini   }
9729566063dSJacob Faibussowitsch   PetscCall(MatGetRowUpperTriangular(A));
9736214f412SHong Zhang   for (row = rstart; row < rend; row++) {
9749566063dSJacob Faibussowitsch     PetscCall(MatGetRow(A, row, &ncols, &cols, &vals));
975bdeae278SStefano Zampini     /* PETSc-Elemental interface uses axpy for setting off-processor entries, only ADD_VALUES is allowed */
9769566063dSJacob Faibussowitsch     PetscCall(MatSetValues(mat_elemental, 1, &row, ncols, cols, vals, ADD_VALUES));
9776214f412SHong Zhang     for (j = 0; j < ncols; j++) { /* lower triangular part */
978eb1ec7c1SStefano Zampini       PetscScalar v;
9796214f412SHong Zhang       if (cols[j] == row) continue;
980b94d7dedSBarry Smith       v = A->hermitian == PETSC_BOOL3_TRUE ? PetscConj(vals[j]) : vals[j];
9819566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mat_elemental, 1, &cols[j], 1, &row, &v, ADD_VALUES));
9826214f412SHong Zhang     }
9839566063dSJacob Faibussowitsch     PetscCall(MatRestoreRow(A, row, &ncols, &cols, &vals));
9846214f412SHong Zhang   }
9859566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowUpperTriangular(A));
9869566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat_elemental, MAT_FINAL_ASSEMBLY));
9879566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat_elemental, MAT_FINAL_ASSEMBLY));
9886214f412SHong Zhang 
989511c6705SHong Zhang   if (reuse == MAT_INPLACE_MATRIX) {
9909566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &mat_elemental));
9916214f412SHong Zhang   } else {
9926214f412SHong Zhang     *newmat = mat_elemental;
9936214f412SHong Zhang   }
9946214f412SHong Zhang   PetscFunctionReturn(0);
9956214f412SHong Zhang }
9966214f412SHong Zhang 
9979371c9d4SSatish Balay static PetscErrorCode MatDestroy_Elemental(Mat A) {
998db31f6deSJed Brown   Mat_Elemental      *a = (Mat_Elemental *)A->data;
9995e9f5b67SHong Zhang   Mat_Elemental_Grid *commgrid;
10005e9f5b67SHong Zhang   PetscBool           flg;
10015e9f5b67SHong Zhang   MPI_Comm            icomm;
1002db31f6deSJed Brown 
1003db31f6deSJed Brown   PetscFunctionBegin;
1004db31f6deSJed Brown   delete a->emat;
1005ea394475SSatish Balay   delete a->P;
1006ea394475SSatish Balay   delete a->Q;
10075e9f5b67SHong Zhang 
1008e8146892SSatish Balay   El::mpi::Comm cxxcomm(PetscObjectComm((PetscObject)A));
10099566063dSJacob Faibussowitsch   PetscCall(PetscCommDuplicate(cxxcomm.comm, &icomm, NULL));
10109566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_get_attr(icomm, Petsc_Elemental_keyval, (void **)&commgrid, (int *)&flg));
10115e9f5b67SHong Zhang   if (--commgrid->grid_refct == 0) {
10125e9f5b67SHong Zhang     delete commgrid->grid;
10139566063dSJacob Faibussowitsch     PetscCall(PetscFree(commgrid));
10149566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_free_keyval(&Petsc_Elemental_keyval));
10155e9f5b67SHong Zhang   }
10169566063dSJacob Faibussowitsch   PetscCall(PetscCommDestroy(&icomm));
10179566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatGetOwnershipIS_C", NULL));
10189566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatFactorGetSolverType_C", NULL));
10199566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_elemental_mpidense_C", NULL));
10209566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->data));
1021db31f6deSJed Brown   PetscFunctionReturn(0);
1022db31f6deSJed Brown }
1023db31f6deSJed Brown 
10249371c9d4SSatish Balay PetscErrorCode MatSetUp_Elemental(Mat A) {
1025db31f6deSJed Brown   Mat_Elemental *a = (Mat_Elemental *)A->data;
1026f19600a0SHong Zhang   MPI_Comm       comm;
1027db31f6deSJed Brown   PetscMPIInt    rsize, csize;
1028f19600a0SHong Zhang   PetscInt       n;
1029db31f6deSJed Brown 
1030db31f6deSJed Brown   PetscFunctionBegin;
10319566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->rmap));
10329566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->cmap));
1033db31f6deSJed Brown 
1034d8304050SJose E. Roman   /* Check if local row and column sizes are equally distributed.
1035f19600a0SHong Zhang      Jed: Elemental uses "element" cyclic ordering so the sizes need to match that
1036f19600a0SHong Zhang      exactly.  The strategy in MatElemental is for PETSc to implicitly permute to block ordering (like would be returned by
1037d8304050SJose E. Roman      PetscSplitOwnership(comm,&n,&N), at which point Elemental matrices can act on PETSc vectors without redistributing the vectors. */
10389566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
1039f19600a0SHong Zhang   n = PETSC_DECIDE;
10409566063dSJacob Faibussowitsch   PetscCall(PetscSplitOwnership(comm, &n, &A->rmap->N));
10415f80ce2aSJacob Faibussowitsch   PetscCheck(n == A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Local row size %" PetscInt_FMT " of ELEMENTAL matrix must be equally distributed", A->rmap->n);
1042f19600a0SHong Zhang 
1043f19600a0SHong Zhang   n = PETSC_DECIDE;
10449566063dSJacob Faibussowitsch   PetscCall(PetscSplitOwnership(comm, &n, &A->cmap->N));
10455f80ce2aSJacob Faibussowitsch   PetscCheck(n == A->cmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Local column size %" PetscInt_FMT " of ELEMENTAL matrix must be equally distributed", A->cmap->n);
1046f19600a0SHong Zhang 
10472f613bf5SBarry Smith   a->emat->Resize(A->rmap->N, A->cmap->N);
1048e8146892SSatish Balay   El::Zero(*a->emat);
1049db31f6deSJed Brown 
10509566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(A->rmap->comm, &rsize));
10519566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(A->cmap->comm, &csize));
10525f80ce2aSJacob Faibussowitsch   PetscCheck(csize == rsize, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Cannot use row and column communicators of different sizes");
1053db31f6deSJed Brown   a->commsize = rsize;
10549371c9d4SSatish Balay   a->mr[0]    = A->rmap->N % rsize;
10559371c9d4SSatish Balay   if (!a->mr[0]) a->mr[0] = rsize;
10569371c9d4SSatish Balay   a->mr[1] = A->cmap->N % csize;
10579371c9d4SSatish Balay   if (!a->mr[1]) a->mr[1] = csize;
1058db31f6deSJed Brown   a->m[0] = A->rmap->N / rsize + (a->mr[0] != rsize);
1059db31f6deSJed Brown   a->m[1] = A->cmap->N / csize + (a->mr[1] != csize);
1060db31f6deSJed Brown   PetscFunctionReturn(0);
1061db31f6deSJed Brown }
1062db31f6deSJed Brown 
10639371c9d4SSatish Balay PetscErrorCode MatAssemblyBegin_Elemental(Mat A, MatAssemblyType type) {
1064aae2c449SHong Zhang   Mat_Elemental *a = (Mat_Elemental *)A->data;
1065aae2c449SHong Zhang 
1066aae2c449SHong Zhang   PetscFunctionBegin;
1067fbbcb730SJack Poulson   /* printf("Calling ProcessQueues\n"); */
1068fbbcb730SJack Poulson   a->emat->ProcessQueues();
1069fbbcb730SJack Poulson   /* printf("Finished ProcessQueues\n"); */
1070aae2c449SHong Zhang   PetscFunctionReturn(0);
1071aae2c449SHong Zhang }
1072aae2c449SHong Zhang 
10739371c9d4SSatish Balay PetscErrorCode MatAssemblyEnd_Elemental(Mat A, MatAssemblyType type) {
1074aae2c449SHong Zhang   PetscFunctionBegin;
1075aae2c449SHong Zhang   /* Currently does nothing */
1076aae2c449SHong Zhang   PetscFunctionReturn(0);
1077aae2c449SHong Zhang }
1078aae2c449SHong Zhang 
10799371c9d4SSatish Balay PetscErrorCode MatLoad_Elemental(Mat newMat, PetscViewer viewer) {
10807b30e0f1SHong Zhang   Mat      Adense, Ae;
10817b30e0f1SHong Zhang   MPI_Comm comm;
10827b30e0f1SHong Zhang 
10837b30e0f1SHong Zhang   PetscFunctionBegin;
10849566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)newMat, &comm));
10859566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &Adense));
10869566063dSJacob Faibussowitsch   PetscCall(MatSetType(Adense, MATDENSE));
10879566063dSJacob Faibussowitsch   PetscCall(MatLoad(Adense, viewer));
10889566063dSJacob Faibussowitsch   PetscCall(MatConvert(Adense, MATELEMENTAL, MAT_INITIAL_MATRIX, &Ae));
10899566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Adense));
10909566063dSJacob Faibussowitsch   PetscCall(MatHeaderReplace(newMat, &Ae));
10917b30e0f1SHong Zhang   PetscFunctionReturn(0);
10927b30e0f1SHong Zhang }
10937b30e0f1SHong Zhang 
109440d92e34SHong Zhang /* -------------------------------------------------------------------*/
10959371c9d4SSatish Balay static struct _MatOps MatOps_Values = {MatSetValues_Elemental,
109640d92e34SHong Zhang                                        0,
109740d92e34SHong Zhang                                        0,
109840d92e34SHong Zhang                                        MatMult_Elemental,
109940d92e34SHong Zhang                                        /* 4*/ MatMultAdd_Elemental,
11009426833fSXuan Zhou                                        MatMultTranspose_Elemental,
1101e883f9d5SXuan Zhou                                        MatMultTransposeAdd_Elemental,
110240d92e34SHong Zhang                                        MatSolve_Elemental,
1103df311e6cSXuan Zhou                                        MatSolveAdd_Elemental,
11042ef15aa2SHong Zhang                                        0,
11052ef15aa2SHong Zhang                                        /*10*/ 0,
110640d92e34SHong Zhang                                        MatLUFactor_Elemental,
110740d92e34SHong Zhang                                        MatCholeskyFactor_Elemental,
110840d92e34SHong Zhang                                        0,
110940d92e34SHong Zhang                                        MatTranspose_Elemental,
111040d92e34SHong Zhang                                        /*15*/ MatGetInfo_Elemental,
111140d92e34SHong Zhang                                        0,
111261119200SXuan Zhou                                        MatGetDiagonal_Elemental,
1113ade3cc5eSXuan Zhou                                        MatDiagonalScale_Elemental,
111440d92e34SHong Zhang                                        MatNorm_Elemental,
111540d92e34SHong Zhang                                        /*20*/ MatAssemblyBegin_Elemental,
111640d92e34SHong Zhang                                        MatAssemblyEnd_Elemental,
111732d7a744SHong Zhang                                        MatSetOption_Elemental,
111840d92e34SHong Zhang                                        MatZeroEntries_Elemental,
111940d92e34SHong Zhang                                        /*24*/ 0,
112040d92e34SHong Zhang                                        MatLUFactorSymbolic_Elemental,
112140d92e34SHong Zhang                                        MatLUFactorNumeric_Elemental,
112240d92e34SHong Zhang                                        MatCholeskyFactorSymbolic_Elemental,
112340d92e34SHong Zhang                                        MatCholeskyFactorNumeric_Elemental,
112440d92e34SHong Zhang                                        /*29*/ MatSetUp_Elemental,
112540d92e34SHong Zhang                                        0,
112640d92e34SHong Zhang                                        0,
112740d92e34SHong Zhang                                        0,
112840d92e34SHong Zhang                                        0,
1129df311e6cSXuan Zhou                                        /*34*/ MatDuplicate_Elemental,
113040d92e34SHong Zhang                                        0,
113140d92e34SHong Zhang                                        0,
113240d92e34SHong Zhang                                        0,
113340d92e34SHong Zhang                                        0,
113440d92e34SHong Zhang                                        /*39*/ MatAXPY_Elemental,
113540d92e34SHong Zhang                                        0,
113640d92e34SHong Zhang                                        0,
113740d92e34SHong Zhang                                        0,
113840d92e34SHong Zhang                                        MatCopy_Elemental,
113940d92e34SHong Zhang                                        /*44*/ 0,
114040d92e34SHong Zhang                                        MatScale_Elemental,
11417d68702bSBarry Smith                                        MatShift_Basic,
114240d92e34SHong Zhang                                        0,
114340d92e34SHong Zhang                                        0,
114440d92e34SHong Zhang                                        /*49*/ 0,
114540d92e34SHong Zhang                                        0,
114640d92e34SHong Zhang                                        0,
114740d92e34SHong Zhang                                        0,
114840d92e34SHong Zhang                                        0,
114940d92e34SHong Zhang                                        /*54*/ 0,
115040d92e34SHong Zhang                                        0,
115140d92e34SHong Zhang                                        0,
115240d92e34SHong Zhang                                        0,
115340d92e34SHong Zhang                                        0,
115440d92e34SHong Zhang                                        /*59*/ 0,
115540d92e34SHong Zhang                                        MatDestroy_Elemental,
115640d92e34SHong Zhang                                        MatView_Elemental,
115740d92e34SHong Zhang                                        0,
115840d92e34SHong Zhang                                        0,
115940d92e34SHong Zhang                                        /*64*/ 0,
116040d92e34SHong Zhang                                        0,
116140d92e34SHong Zhang                                        0,
116240d92e34SHong Zhang                                        0,
116340d92e34SHong Zhang                                        0,
116440d92e34SHong Zhang                                        /*69*/ 0,
116540d92e34SHong Zhang                                        0,
11662ef0cf24SXuan Zhou                                        MatConvert_Elemental_Dense,
116740d92e34SHong Zhang                                        0,
116840d92e34SHong Zhang                                        0,
116940d92e34SHong Zhang                                        /*74*/ 0,
117040d92e34SHong Zhang                                        0,
117140d92e34SHong Zhang                                        0,
117240d92e34SHong Zhang                                        0,
117340d92e34SHong Zhang                                        0,
117440d92e34SHong Zhang                                        /*79*/ 0,
117540d92e34SHong Zhang                                        0,
117640d92e34SHong Zhang                                        0,
117740d92e34SHong Zhang                                        0,
11787b30e0f1SHong Zhang                                        MatLoad_Elemental,
117940d92e34SHong Zhang                                        /*84*/ 0,
118040d92e34SHong Zhang                                        0,
118140d92e34SHong Zhang                                        0,
118240d92e34SHong Zhang                                        0,
118340d92e34SHong Zhang                                        0,
11844222ddf1SHong Zhang                                        /*89*/ 0,
11854222ddf1SHong Zhang                                        0,
118640d92e34SHong Zhang                                        MatMatMultNumeric_Elemental,
118740d92e34SHong Zhang                                        0,
118840d92e34SHong Zhang                                        0,
118940d92e34SHong Zhang                                        /*94*/ 0,
11904222ddf1SHong Zhang                                        0,
11914222ddf1SHong Zhang                                        0,
1192df311e6cSXuan Zhou                                        MatMatTransposeMultNumeric_Elemental,
119340d92e34SHong Zhang                                        0,
11944222ddf1SHong Zhang                                        /*99*/ MatProductSetFromOptions_Elemental,
119540d92e34SHong Zhang                                        0,
119640d92e34SHong Zhang                                        0,
1197dfcb0403SXuan Zhou                                        MatConjugate_Elemental,
119840d92e34SHong Zhang                                        0,
119940d92e34SHong Zhang                                        /*104*/ 0,
120040d92e34SHong Zhang                                        0,
120140d92e34SHong Zhang                                        0,
120240d92e34SHong Zhang                                        0,
120340d92e34SHong Zhang                                        0,
120440d92e34SHong Zhang                                        /*109*/ MatMatSolve_Elemental,
120540d92e34SHong Zhang                                        0,
120640d92e34SHong Zhang                                        0,
120740d92e34SHong Zhang                                        0,
120834fa46e1SFrancesco Ballarin                                        MatMissingDiagonal_Elemental,
120940d92e34SHong Zhang                                        /*114*/ 0,
121040d92e34SHong Zhang                                        0,
121140d92e34SHong Zhang                                        0,
121240d92e34SHong Zhang                                        0,
121340d92e34SHong Zhang                                        0,
121440d92e34SHong Zhang                                        /*119*/ 0,
12154a29722dSXuan Zhou                                        MatHermitianTranspose_Elemental,
121640d92e34SHong Zhang                                        0,
121740d92e34SHong Zhang                                        0,
121840d92e34SHong Zhang                                        0,
121940d92e34SHong Zhang                                        /*124*/ 0,
122040d92e34SHong Zhang                                        0,
122140d92e34SHong Zhang                                        0,
122240d92e34SHong Zhang                                        0,
122340d92e34SHong Zhang                                        0,
122440d92e34SHong Zhang                                        /*129*/ 0,
122540d92e34SHong Zhang                                        0,
122640d92e34SHong Zhang                                        0,
122740d92e34SHong Zhang                                        0,
122840d92e34SHong Zhang                                        0,
122940d92e34SHong Zhang                                        /*134*/ 0,
123040d92e34SHong Zhang                                        0,
123140d92e34SHong Zhang                                        0,
123240d92e34SHong Zhang                                        0,
12334222ddf1SHong Zhang                                        0,
12344222ddf1SHong Zhang                                        0,
12354222ddf1SHong Zhang                                        /*140*/ 0,
12364222ddf1SHong Zhang                                        0,
12374222ddf1SHong Zhang                                        0,
12384222ddf1SHong Zhang                                        0,
12394222ddf1SHong Zhang                                        0,
12404222ddf1SHong Zhang                                        /*145*/ 0,
12414222ddf1SHong Zhang                                        0,
124299a7f59eSMark Adams                                        0,
124399a7f59eSMark Adams                                        0,
12447fb60732SBarry Smith                                        0,
12459371c9d4SSatish Balay                                        /*150*/ 0};
124640d92e34SHong Zhang 
1247ed36708cSHong Zhang /*MC
1248ed36708cSHong Zhang    MATELEMENTAL = "elemental" - A matrix type for dense matrices using the Elemental package
1249ed36708cSHong Zhang 
1250c2b89b5dSBarry Smith   Use ./configure --download-elemental to install PETSc to use Elemental
1251c2b89b5dSBarry Smith 
1252ed36708cSHong Zhang    Options Database Keys:
12535cc86fc1SJed Brown + -mat_type elemental - sets the matrix type to "elemental" during a call to MatSetFromOptions()
125489bba20eSBarry Smith . -pc_factor_mat_solver_type elemental - to use this direct solver with the option -pc_type lu
12555cc86fc1SJed Brown - -mat_elemental_grid_height - sets Grid Height for 2D cyclic ordering of internal matrix
1256ed36708cSHong Zhang 
1257ed36708cSHong Zhang   Level: beginner
1258ed36708cSHong Zhang 
125989bba20eSBarry Smith   Note:
126089bba20eSBarry Smith    Note unlike most matrix formats, this format does not store all the matrix entries for a contiguous
126189bba20eSBarry Smith    range of rows on an MPI rank. Use `MatGetOwnershipIS()` to determine what values are stored on
126289bba20eSBarry Smith    the given rank.
126389bba20eSBarry Smith 
126489bba20eSBarry Smith .seealso: `MATDENSE`, `MATSCALAPACK`, `MatGetOwnershipIS()`
1265ed36708cSHong Zhang M*/
12664a29722dSXuan Zhou 
12679371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode MatCreate_Elemental(Mat A) {
1268db31f6deSJed Brown   Mat_Elemental      *a;
12695682a260SJack Poulson   PetscBool           flg, flg1;
12705e9f5b67SHong Zhang   Mat_Elemental_Grid *commgrid;
12715e9f5b67SHong Zhang   MPI_Comm            icomm;
12725682a260SJack Poulson   PetscInt            optv1;
1273db31f6deSJed Brown 
1274db31f6deSJed Brown   PetscFunctionBegin;
12759566063dSJacob Faibussowitsch   PetscCall(PetscMemcpy(A->ops, &MatOps_Values, sizeof(struct _MatOps)));
127640d92e34SHong Zhang   A->insertmode = NOT_SET_VALUES;
1277db31f6deSJed Brown 
1278*4dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&a));
1279db31f6deSJed Brown   A->data = (void *)a;
1280db31f6deSJed Brown 
1281db31f6deSJed Brown   /* Set up the elemental matrix */
1282e8146892SSatish Balay   El::mpi::Comm cxxcomm(PetscObjectComm((PetscObject)A));
12835e9f5b67SHong Zhang 
12845e9f5b67SHong Zhang   /* Grid needs to be shared between multiple Mats on the same communicator, implement by attribute caching on the MPI_Comm */
12855e9f5b67SHong Zhang   if (Petsc_Elemental_keyval == MPI_KEYVAL_INVALID) {
12869566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Elemental_keyval, (void *)0));
12879566063dSJacob Faibussowitsch     PetscCall(PetscCitationsRegister(ElementalCitation, &ElementalCite));
12885e9f5b67SHong Zhang   }
12899566063dSJacob Faibussowitsch   PetscCall(PetscCommDuplicate(cxxcomm.comm, &icomm, NULL));
12909566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_get_attr(icomm, Petsc_Elemental_keyval, (void **)&commgrid, (int *)&flg));
12915e9f5b67SHong Zhang   if (!flg) {
1292*4dfa11a4SJacob Faibussowitsch     PetscCall(PetscNew(&commgrid));
12935cb544a0SHong Zhang 
1294d0609cedSBarry Smith     PetscOptionsBegin(PetscObjectComm((PetscObject)A), ((PetscObject)A)->prefix, "Elemental Options", "Mat");
1295e8146892SSatish Balay     /* displayed default grid sizes (CommSize,1) are set by us arbitrarily until El::Grid() is called */
12969566063dSJacob Faibussowitsch     PetscCall(PetscOptionsInt("-mat_elemental_grid_height", "Grid Height", "None", El::mpi::Size(cxxcomm), &optv1, &flg1));
12975682a260SJack Poulson     if (flg1) {
1298aed4548fSBarry Smith       PetscCheck((El::mpi::Size(cxxcomm) % optv1) == 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Grid Height %" PetscInt_FMT " must evenly divide CommSize %" PetscInt_FMT, optv1, (PetscInt)El::mpi::Size(cxxcomm));
1299e8146892SSatish Balay       commgrid->grid = new El::Grid(cxxcomm, optv1); /* use user-provided grid height */
13002ef0cf24SXuan Zhou     } else {
1301e8146892SSatish Balay       commgrid->grid = new El::Grid(cxxcomm); /* use Elemental default grid sizes */
1302da0640a4SHong Zhang       /* printf("new commgrid->grid = %p\n",commgrid->grid);  -- memory leak revealed by valgrind? */
1303ed667823SXuan Zhou     }
13045e9f5b67SHong Zhang     commgrid->grid_refct = 1;
13059566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_set_attr(icomm, Petsc_Elemental_keyval, (void *)commgrid));
1306ea394475SSatish Balay 
1307ea394475SSatish Balay     a->pivoting = 1;
13089566063dSJacob Faibussowitsch     PetscCall(PetscOptionsInt("-mat_elemental_pivoting", "Pivoting", "None", a->pivoting, &a->pivoting, NULL));
1309ea394475SSatish Balay 
1310d0609cedSBarry Smith     PetscOptionsEnd();
13115e9f5b67SHong Zhang   } else {
13125e9f5b67SHong Zhang     commgrid->grid_refct++;
13135e9f5b67SHong Zhang   }
13149566063dSJacob Faibussowitsch   PetscCall(PetscCommDestroy(&icomm));
13155e9f5b67SHong Zhang   a->grid        = commgrid->grid;
1316e8146892SSatish Balay   a->emat        = new El::DistMatrix<PetscElemScalar>(*a->grid);
131732d7a744SHong Zhang   a->roworiented = PETSC_TRUE;
1318db31f6deSJed Brown 
13199566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatGetOwnershipIS_C", MatGetOwnershipIS_Elemental));
13209566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_elemental_mpidense_C", MatProductSetFromOptions_Elemental_MPIDense));
13219566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATELEMENTAL));
1322db31f6deSJed Brown   PetscFunctionReturn(0);
1323db31f6deSJed Brown }
1324