xref: /petsc/src/mat/impls/elemental/matelem.cxx (revision cedd07cade5cbdfdad435c8172b7ec8972d9cd8d)
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 
19d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatView_Elemental(Mat A, PetscViewer viewer)
20d71ae5a4SJacob Faibussowitsch {
21db31f6deSJed Brown   Mat_Elemental *a = (Mat_Elemental *)A->data;
22db31f6deSJed Brown   PetscBool      iascii;
23db31f6deSJed Brown 
24db31f6deSJed Brown   PetscFunctionBegin;
259566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
26db31f6deSJed Brown   if (iascii) {
27db31f6deSJed Brown     PetscViewerFormat format;
289566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
29db31f6deSJed Brown     if (format == PETSC_VIEWER_ASCII_INFO) {
3079673f7bSHong Zhang       /* call elemental viewing function */
319566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "Elemental run parameters:\n"));
3263a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  allocated entries=%zu\n", (*a->emat).AllocatedMemory()));
339566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  grid height=%d, grid width=%d\n", (*a->emat).Grid().Height(), (*a->emat).Grid().Width()));
344fe7bbcaSHong Zhang       if (format == PETSC_VIEWER_ASCII_FACTOR_INFO) {
3579673f7bSHong Zhang         /* call elemental viewing function */
369566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PetscObjectComm((PetscObject)viewer), "test matview_elemental 2\n"));
374fe7bbcaSHong Zhang       }
3879673f7bSHong Zhang 
39db31f6deSJed Brown     } else if (format == PETSC_VIEWER_DEFAULT) {
409566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
41e8146892SSatish Balay       El::Print(*a->emat, "Elemental matrix (cyclic ordering)");
429566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
43834d3fecSHong Zhang       if (A->factortype == MAT_FACTOR_NONE) {
4461119200SXuan Zhou         Mat Adense;
459566063dSJacob Faibussowitsch         PetscCall(MatConvert(A, MATDENSE, MAT_INITIAL_MATRIX, &Adense));
469566063dSJacob Faibussowitsch         PetscCall(MatView(Adense, viewer));
479566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&Adense));
48834d3fecSHong Zhang       }
49ce94432eSBarry Smith     } else SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Format");
50d2daa67eSHong Zhang   } else {
515cb544a0SHong Zhang     /* convert to dense format and call MatView() */
5261119200SXuan Zhou     Mat Adense;
539566063dSJacob Faibussowitsch     PetscCall(MatConvert(A, MATDENSE, MAT_INITIAL_MATRIX, &Adense));
549566063dSJacob Faibussowitsch     PetscCall(MatView(Adense, viewer));
559566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Adense));
56d2daa67eSHong Zhang   }
57db31f6deSJed Brown   PetscFunctionReturn(0);
58db31f6deSJed Brown }
59db31f6deSJed Brown 
60d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetInfo_Elemental(Mat A, MatInfoType flag, MatInfo *info)
61d71ae5a4SJacob Faibussowitsch {
6215767789SHong Zhang   Mat_Elemental *a = (Mat_Elemental *)A->data;
6315767789SHong Zhang 
64180a43e4SHong Zhang   PetscFunctionBegin;
655cb544a0SHong Zhang   info->block_size = 1.0;
6615767789SHong Zhang 
6715767789SHong Zhang   if (flag == MAT_LOCAL) {
683966268fSBarry Smith     info->nz_allocated = (*a->emat).AllocatedMemory(); /* locally allocated */
6915767789SHong Zhang     info->nz_used      = info->nz_allocated;
7015767789SHong Zhang   } else if (flag == MAT_GLOBAL_MAX) {
711c2dc1cbSBarry Smith     //PetscCall(MPIU_Allreduce(isend,irecv,5,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)matin)));
7215767789SHong Zhang     /* see MatGetInfo_MPIAIJ() for getting global info->nz_allocated! */
7315767789SHong Zhang     //SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP," MAT_GLOBAL_MAX not written yet");
7415767789SHong Zhang   } else if (flag == MAT_GLOBAL_SUM) {
7515767789SHong Zhang     //SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP," MAT_GLOBAL_SUM not written yet");
763966268fSBarry Smith     info->nz_allocated = (*a->emat).AllocatedMemory(); /* locally allocated */
7715767789SHong Zhang     info->nz_used      = info->nz_allocated;           /* assume Elemental does accurate allocation */
781c2dc1cbSBarry Smith     //PetscCall(MPIU_Allreduce(isend,irecv,1,MPIU_REAL,MPIU_SUM,PetscObjectComm((PetscObject)A)));
7915767789SHong Zhang     //PetscPrintf(PETSC_COMM_SELF,"    ... [%d] locally allocated %g\n",rank,info->nz_allocated);
8015767789SHong Zhang   }
8115767789SHong Zhang 
8215767789SHong Zhang   info->nz_unneeded       = 0.0;
833966268fSBarry Smith   info->assemblies        = A->num_ass;
8415767789SHong Zhang   info->mallocs           = 0;
854dfa11a4SJacob Faibussowitsch   info->memory            = 0; /* REVIEW ME */
8615767789SHong Zhang   info->fill_ratio_given  = 0; /* determined by Elemental */
8715767789SHong Zhang   info->fill_ratio_needed = 0;
8815767789SHong Zhang   info->factor_mallocs    = 0;
89180a43e4SHong Zhang   PetscFunctionReturn(0);
90180a43e4SHong Zhang }
91180a43e4SHong Zhang 
92d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSetOption_Elemental(Mat A, MatOption op, PetscBool flg)
93d71ae5a4SJacob Faibussowitsch {
9432d7a744SHong Zhang   Mat_Elemental *a = (Mat_Elemental *)A->data;
9532d7a744SHong Zhang 
9632d7a744SHong Zhang   PetscFunctionBegin;
9732d7a744SHong Zhang   switch (op) {
9832d7a744SHong Zhang   case MAT_NEW_NONZERO_LOCATIONS:
9932d7a744SHong Zhang   case MAT_NEW_NONZERO_LOCATION_ERR:
10032d7a744SHong Zhang   case MAT_NEW_NONZERO_ALLOCATION_ERR:
101891a0571SHong Zhang   case MAT_SYMMETRIC:
102071fcb05SBarry Smith   case MAT_SORTED_FULL:
103d71ae5a4SJacob Faibussowitsch   case MAT_HERMITIAN:
104d71ae5a4SJacob Faibussowitsch     break;
105d71ae5a4SJacob Faibussowitsch   case MAT_ROW_ORIENTED:
106d71ae5a4SJacob Faibussowitsch     a->roworiented = flg;
107d71ae5a4SJacob Faibussowitsch     break;
108d71ae5a4SJacob Faibussowitsch   default:
109d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "unknown option %s", MatOptions[op]);
11032d7a744SHong Zhang   }
11132d7a744SHong Zhang   PetscFunctionReturn(0);
11232d7a744SHong Zhang }
11332d7a744SHong Zhang 
114d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValues_Elemental(Mat A, PetscInt nr, const PetscInt *rows, PetscInt nc, const PetscInt *cols, const PetscScalar *vals, InsertMode imode)
115d71ae5a4SJacob Faibussowitsch {
116db31f6deSJed Brown   Mat_Elemental *a = (Mat_Elemental *)A->data;
117fbbcb730SJack Poulson   PetscInt       i, j, rrank, ridx, crank, cidx, erow, ecol, numQueues = 0;
118db31f6deSJed Brown 
119db31f6deSJed Brown   PetscFunctionBegin;
120fbbcb730SJack Poulson   // TODO: Initialize matrix to all zeros?
121fbbcb730SJack Poulson 
122fbbcb730SJack Poulson   // Count the number of queues from this process
12332d7a744SHong Zhang   if (a->roworiented) {
124db31f6deSJed Brown     for (i = 0; i < nr; i++) {
125db31f6deSJed Brown       if (rows[i] < 0) continue;
126db31f6deSJed Brown       P2RO(A, 0, rows[i], &rrank, &ridx);
127db31f6deSJed Brown       RO2E(A, 0, rrank, ridx, &erow);
128aed4548fSBarry Smith       PetscCheck(rrank >= 0 && ridx >= 0 && erow >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Incorrect row translation");
129db31f6deSJed Brown       for (j = 0; j < nc; j++) {
130db31f6deSJed Brown         if (cols[j] < 0) continue;
131db31f6deSJed Brown         P2RO(A, 1, cols[j], &crank, &cidx);
132db31f6deSJed Brown         RO2E(A, 1, crank, cidx, &ecol);
133aed4548fSBarry Smith         PetscCheck(crank >= 0 && cidx >= 0 && ecol >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Incorrect col translation");
134fbbcb730SJack Poulson         if (!a->emat->IsLocal(erow, ecol)) { /* off-proc entry */
135fbbcb730SJack Poulson           /* printf("Will later remotely update (%d,%d)\n",erow,ecol); */
13608401ef6SPierre Jolivet           PetscCheck(imode == ADD_VALUES, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only ADD_VALUES to off-processor entry is supported");
137fbbcb730SJack Poulson           ++numQueues;
138aae2c449SHong Zhang           continue;
139ed36708cSHong Zhang         }
140fbbcb730SJack Poulson         /* printf("Locally updating (%d,%d)\n",erow,ecol); */
141db31f6deSJed Brown         switch (imode) {
142d71ae5a4SJacob Faibussowitsch         case INSERT_VALUES:
143d71ae5a4SJacob Faibussowitsch           a->emat->Set(erow, ecol, (PetscElemScalar)vals[i * nc + j]);
144d71ae5a4SJacob Faibussowitsch           break;
145d71ae5a4SJacob Faibussowitsch         case ADD_VALUES:
146d71ae5a4SJacob Faibussowitsch           a->emat->Update(erow, ecol, (PetscElemScalar)vals[i * nc + j]);
147d71ae5a4SJacob Faibussowitsch           break;
148d71ae5a4SJacob Faibussowitsch         default:
149d71ae5a4SJacob Faibussowitsch           SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "No support for InsertMode %d", (int)imode);
150db31f6deSJed Brown         }
151db31f6deSJed Brown       }
152db31f6deSJed Brown     }
153fbbcb730SJack Poulson 
154fbbcb730SJack Poulson     /* printf("numQueues=%d\n",numQueues); */
155fbbcb730SJack Poulson     a->emat->Reserve(numQueues);
156fbbcb730SJack Poulson     for (i = 0; i < nr; i++) {
157fbbcb730SJack Poulson       if (rows[i] < 0) continue;
158fbbcb730SJack Poulson       P2RO(A, 0, rows[i], &rrank, &ridx);
159fbbcb730SJack Poulson       RO2E(A, 0, rrank, ridx, &erow);
160fbbcb730SJack Poulson       for (j = 0; j < nc; j++) {
161fbbcb730SJack Poulson         if (cols[j] < 0) continue;
162fbbcb730SJack Poulson         P2RO(A, 1, cols[j], &crank, &cidx);
163fbbcb730SJack Poulson         RO2E(A, 1, crank, cidx, &ecol);
164fbbcb730SJack Poulson         if (!a->emat->IsLocal(erow, ecol)) { /*off-proc entry*/
165fbbcb730SJack Poulson           /* printf("Queueing remotely update of (%d,%d)\n",erow,ecol); */
166fbbcb730SJack Poulson           a->emat->QueueUpdate(erow, ecol, vals[i * nc + j]);
167fbbcb730SJack Poulson         }
168fbbcb730SJack Poulson       }
169fbbcb730SJack Poulson     }
17032d7a744SHong Zhang   } else { /* columnoriented */
17132d7a744SHong Zhang     for (j = 0; j < nc; j++) {
17232d7a744SHong Zhang       if (cols[j] < 0) continue;
17332d7a744SHong Zhang       P2RO(A, 1, cols[j], &crank, &cidx);
17432d7a744SHong Zhang       RO2E(A, 1, crank, cidx, &ecol);
175aed4548fSBarry Smith       PetscCheck(crank >= 0 && cidx >= 0 && ecol >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Incorrect col translation");
17632d7a744SHong Zhang       for (i = 0; i < nr; i++) {
17732d7a744SHong Zhang         if (rows[i] < 0) continue;
17832d7a744SHong Zhang         P2RO(A, 0, rows[i], &rrank, &ridx);
17932d7a744SHong Zhang         RO2E(A, 0, rrank, ridx, &erow);
180aed4548fSBarry Smith         PetscCheck(rrank >= 0 && ridx >= 0 && erow >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Incorrect row translation");
18132d7a744SHong Zhang         if (!a->emat->IsLocal(erow, ecol)) { /* off-proc entry */
18232d7a744SHong Zhang           /* printf("Will later remotely update (%d,%d)\n",erow,ecol); */
18308401ef6SPierre Jolivet           PetscCheck(imode == ADD_VALUES, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only ADD_VALUES to off-processor entry is supported");
18432d7a744SHong Zhang           ++numQueues;
18532d7a744SHong Zhang           continue;
18632d7a744SHong Zhang         }
18732d7a744SHong Zhang         /* printf("Locally updating (%d,%d)\n",erow,ecol); */
18832d7a744SHong Zhang         switch (imode) {
189d71ae5a4SJacob Faibussowitsch         case INSERT_VALUES:
190d71ae5a4SJacob Faibussowitsch           a->emat->Set(erow, ecol, (PetscElemScalar)vals[i + j * nr]);
191d71ae5a4SJacob Faibussowitsch           break;
192d71ae5a4SJacob Faibussowitsch         case ADD_VALUES:
193d71ae5a4SJacob Faibussowitsch           a->emat->Update(erow, ecol, (PetscElemScalar)vals[i + j * nr]);
194d71ae5a4SJacob Faibussowitsch           break;
195d71ae5a4SJacob Faibussowitsch         default:
196d71ae5a4SJacob Faibussowitsch           SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "No support for InsertMode %d", (int)imode);
19732d7a744SHong Zhang         }
19832d7a744SHong Zhang       }
19932d7a744SHong Zhang     }
20032d7a744SHong Zhang 
20132d7a744SHong Zhang     /* printf("numQueues=%d\n",numQueues); */
20232d7a744SHong Zhang     a->emat->Reserve(numQueues);
20332d7a744SHong Zhang     for (j = 0; j < nc; j++) {
20432d7a744SHong Zhang       if (cols[j] < 0) continue;
20532d7a744SHong Zhang       P2RO(A, 1, cols[j], &crank, &cidx);
20632d7a744SHong Zhang       RO2E(A, 1, crank, cidx, &ecol);
20732d7a744SHong Zhang 
20832d7a744SHong Zhang       for (i = 0; i < nr; i++) {
20932d7a744SHong Zhang         if (rows[i] < 0) continue;
21032d7a744SHong Zhang         P2RO(A, 0, rows[i], &rrank, &ridx);
21132d7a744SHong Zhang         RO2E(A, 0, rrank, ridx, &erow);
21232d7a744SHong Zhang         if (!a->emat->IsLocal(erow, ecol)) { /*off-proc entry*/
21332d7a744SHong Zhang           /* printf("Queueing remotely update of (%d,%d)\n",erow,ecol); */
21432d7a744SHong Zhang           a->emat->QueueUpdate(erow, ecol, vals[i + j * nr]);
21532d7a744SHong Zhang         }
21632d7a744SHong Zhang       }
21732d7a744SHong Zhang     }
21832d7a744SHong Zhang   }
219db31f6deSJed Brown   PetscFunctionReturn(0);
220db31f6deSJed Brown }
221db31f6deSJed Brown 
222d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMult_Elemental(Mat A, Vec X, Vec Y)
223d71ae5a4SJacob Faibussowitsch {
224db31f6deSJed Brown   Mat_Elemental         *a = (Mat_Elemental *)A->data;
225e6dea9dbSXuan Zhou   const PetscElemScalar *x;
226e6dea9dbSXuan Zhou   PetscElemScalar       *y;
227df311e6cSXuan Zhou   PetscElemScalar        one = 1, zero = 0;
228db31f6deSJed Brown 
229db31f6deSJed Brown   PetscFunctionBegin;
2309566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(X, (const PetscScalar **)&x));
2319566063dSJacob Faibussowitsch   PetscCall(VecGetArray(Y, (PetscScalar **)&y));
232db31f6deSJed Brown   { /* Scoping so that constructor is called before pointer is returned */
233e8146892SSatish Balay     El::DistMatrix<PetscElemScalar, El::VC, El::STAR> xe, ye;
2340c18141cSBarry Smith     xe.LockedAttach(A->cmap->N, 1, *a->grid, 0, 0, x, A->cmap->n);
2350c18141cSBarry Smith     ye.Attach(A->rmap->N, 1, *a->grid, 0, 0, y, A->rmap->n);
236e8146892SSatish Balay     El::Gemv(El::NORMAL, one, *a->emat, xe, zero, ye);
237db31f6deSJed Brown   }
2389566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(X, (const PetscScalar **)&x));
2399566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(Y, (PetscScalar **)&y));
240db31f6deSJed Brown   PetscFunctionReturn(0);
241db31f6deSJed Brown }
242db31f6deSJed Brown 
243d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_Elemental(Mat A, Vec X, Vec Y)
244d71ae5a4SJacob Faibussowitsch {
2459426833fSXuan Zhou   Mat_Elemental         *a = (Mat_Elemental *)A->data;
246df311e6cSXuan Zhou   const PetscElemScalar *x;
247df311e6cSXuan Zhou   PetscElemScalar       *y;
248e6dea9dbSXuan Zhou   PetscElemScalar        one = 1, zero = 0;
2499426833fSXuan Zhou 
2509426833fSXuan Zhou   PetscFunctionBegin;
2519566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(X, (const PetscScalar **)&x));
2529566063dSJacob Faibussowitsch   PetscCall(VecGetArray(Y, (PetscScalar **)&y));
2539426833fSXuan Zhou   { /* Scoping so that constructor is called before pointer is returned */
254e8146892SSatish Balay     El::DistMatrix<PetscElemScalar, El::VC, El::STAR> xe, ye;
2550c18141cSBarry Smith     xe.LockedAttach(A->rmap->N, 1, *a->grid, 0, 0, x, A->rmap->n);
2560c18141cSBarry Smith     ye.Attach(A->cmap->N, 1, *a->grid, 0, 0, y, A->cmap->n);
257e8146892SSatish Balay     El::Gemv(El::TRANSPOSE, one, *a->emat, xe, zero, ye);
2589426833fSXuan Zhou   }
2599566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(X, (const PetscScalar **)&x));
2609566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(Y, (PetscScalar **)&y));
2619426833fSXuan Zhou   PetscFunctionReturn(0);
2629426833fSXuan Zhou }
2639426833fSXuan Zhou 
264d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultAdd_Elemental(Mat A, Vec X, Vec Y, Vec Z)
265d71ae5a4SJacob Faibussowitsch {
266db31f6deSJed Brown   Mat_Elemental         *a = (Mat_Elemental *)A->data;
267df311e6cSXuan Zhou   const PetscElemScalar *x;
268df311e6cSXuan Zhou   PetscElemScalar       *z;
269e6dea9dbSXuan Zhou   PetscElemScalar        one = 1;
270db31f6deSJed Brown 
271db31f6deSJed Brown   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));
275db31f6deSJed Brown   { /* 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->cmap->N, 1, *a->grid, 0, 0, x, A->cmap->n);
2780c18141cSBarry Smith     ze.Attach(A->rmap->N, 1, *a->grid, 0, 0, z, A->rmap->n);
279e8146892SSatish Balay     El::Gemv(El::NORMAL, one, *a->emat, xe, one, ze);
280db31f6deSJed Brown   }
2819566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(X, (const PetscScalar **)&x));
2829566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(Z, (PetscScalar **)&z));
283db31f6deSJed Brown   PetscFunctionReturn(0);
284db31f6deSJed Brown }
285db31f6deSJed Brown 
286d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_Elemental(Mat A, Vec X, Vec Y, Vec Z)
287d71ae5a4SJacob Faibussowitsch {
288e883f9d5SXuan Zhou   Mat_Elemental         *a = (Mat_Elemental *)A->data;
289df311e6cSXuan Zhou   const PetscElemScalar *x;
290df311e6cSXuan Zhou   PetscElemScalar       *z;
291e6dea9dbSXuan Zhou   PetscElemScalar        one = 1;
292e883f9d5SXuan Zhou 
293e883f9d5SXuan Zhou   PetscFunctionBegin;
2949566063dSJacob Faibussowitsch   if (Y != Z) PetscCall(VecCopy(Y, Z));
2959566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(X, (const PetscScalar **)&x));
2969566063dSJacob Faibussowitsch   PetscCall(VecGetArray(Z, (PetscScalar **)&z));
297e883f9d5SXuan Zhou   { /* Scoping so that constructor is called before pointer is returned */
298e8146892SSatish Balay     El::DistMatrix<PetscElemScalar, El::VC, El::STAR> xe, ze;
2990c18141cSBarry Smith     xe.LockedAttach(A->rmap->N, 1, *a->grid, 0, 0, x, A->rmap->n);
3000c18141cSBarry Smith     ze.Attach(A->cmap->N, 1, *a->grid, 0, 0, z, A->cmap->n);
301e8146892SSatish Balay     El::Gemv(El::TRANSPOSE, one, *a->emat, xe, one, ze);
302e883f9d5SXuan Zhou   }
3039566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(X, (const PetscScalar **)&x));
3049566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(Z, (PetscScalar **)&z));
305e883f9d5SXuan Zhou   PetscFunctionReturn(0);
306e883f9d5SXuan Zhou }
307e883f9d5SXuan Zhou 
308d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMatMultNumeric_Elemental(Mat A, Mat B, Mat C)
309d71ae5a4SJacob Faibussowitsch {
310c1d1b975SXuan Zhou   Mat_Elemental  *a   = (Mat_Elemental *)A->data;
311c1d1b975SXuan Zhou   Mat_Elemental  *b   = (Mat_Elemental *)B->data;
3129a9e8502SHong Zhang   Mat_Elemental  *c   = (Mat_Elemental *)C->data;
313e6dea9dbSXuan Zhou   PetscElemScalar one = 1, zero = 0;
314c1d1b975SXuan Zhou 
315c1d1b975SXuan Zhou   PetscFunctionBegin;
316aae2c449SHong Zhang   { /* Scoping so that constructor is called before pointer is returned */
317e8146892SSatish Balay     El::Gemm(El::NORMAL, El::NORMAL, one, *a->emat, *b->emat, zero, *c->emat);
318aae2c449SHong Zhang   }
3199a9e8502SHong Zhang   C->assembled = PETSC_TRUE;
3209a9e8502SHong Zhang   PetscFunctionReturn(0);
3219a9e8502SHong Zhang }
3229a9e8502SHong Zhang 
323*cedd07caSPierre Jolivet PetscErrorCode MatMatMultSymbolic_Elemental(Mat A, Mat B, PetscReal, Mat Ce)
324d71ae5a4SJacob Faibussowitsch {
3259a9e8502SHong Zhang   PetscFunctionBegin;
3269566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(Ce, A->rmap->n, B->cmap->n, PETSC_DECIDE, PETSC_DECIDE));
3279566063dSJacob Faibussowitsch   PetscCall(MatSetType(Ce, MATELEMENTAL));
3289566063dSJacob Faibussowitsch   PetscCall(MatSetUp(Ce));
3294222ddf1SHong Zhang   Ce->ops->matmultnumeric = MatMatMultNumeric_Elemental;
330c1d1b975SXuan Zhou   PetscFunctionReturn(0);
331c1d1b975SXuan Zhou }
332c1d1b975SXuan Zhou 
333d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMatTransposeMultNumeric_Elemental(Mat A, Mat B, Mat C)
334d71ae5a4SJacob Faibussowitsch {
335df311e6cSXuan Zhou   Mat_Elemental  *a   = (Mat_Elemental *)A->data;
336df311e6cSXuan Zhou   Mat_Elemental  *b   = (Mat_Elemental *)B->data;
337df311e6cSXuan Zhou   Mat_Elemental  *c   = (Mat_Elemental *)C->data;
338e6dea9dbSXuan Zhou   PetscElemScalar one = 1, zero = 0;
339df311e6cSXuan Zhou 
340df311e6cSXuan Zhou   PetscFunctionBegin;
341df311e6cSXuan Zhou   { /* Scoping so that constructor is called before pointer is returned */
342e8146892SSatish Balay     El::Gemm(El::NORMAL, El::TRANSPOSE, one, *a->emat, *b->emat, zero, *c->emat);
343df311e6cSXuan Zhou   }
344df311e6cSXuan Zhou   C->assembled = PETSC_TRUE;
345df311e6cSXuan Zhou   PetscFunctionReturn(0);
346df311e6cSXuan Zhou }
347df311e6cSXuan Zhou 
348*cedd07caSPierre Jolivet static PetscErrorCode MatMatTransposeMultSymbolic_Elemental(Mat A, Mat B, PetscReal, Mat C)
349d71ae5a4SJacob Faibussowitsch {
350df311e6cSXuan Zhou   PetscFunctionBegin;
3519566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(C, A->rmap->n, B->rmap->n, PETSC_DECIDE, PETSC_DECIDE));
3529566063dSJacob Faibussowitsch   PetscCall(MatSetType(C, MATELEMENTAL));
3539566063dSJacob Faibussowitsch   PetscCall(MatSetUp(C));
354df311e6cSXuan Zhou   PetscFunctionReturn(0);
355df311e6cSXuan Zhou }
356df311e6cSXuan Zhou 
3574222ddf1SHong Zhang /* --------------------------------------- */
358d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSetFromOptions_Elemental_AB(Mat C)
359d71ae5a4SJacob Faibussowitsch {
3604222ddf1SHong Zhang   PetscFunctionBegin;
3614222ddf1SHong Zhang   C->ops->matmultsymbolic = MatMatMultSymbolic_Elemental;
3624222ddf1SHong Zhang   C->ops->productsymbolic = MatProductSymbolic_AB;
3634222ddf1SHong Zhang   PetscFunctionReturn(0);
3644222ddf1SHong Zhang }
3654222ddf1SHong Zhang 
366d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSetFromOptions_Elemental_ABt(Mat C)
367d71ae5a4SJacob Faibussowitsch {
3684222ddf1SHong Zhang   PetscFunctionBegin;
3694222ddf1SHong Zhang   C->ops->mattransposemultsymbolic = MatMatTransposeMultSymbolic_Elemental;
3704222ddf1SHong Zhang   C->ops->productsymbolic          = MatProductSymbolic_ABt;
3714222ddf1SHong Zhang   PetscFunctionReturn(0);
3724222ddf1SHong Zhang }
3734222ddf1SHong Zhang 
374d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatProductSetFromOptions_Elemental(Mat C)
375d71ae5a4SJacob Faibussowitsch {
3764222ddf1SHong Zhang   Mat_Product *product = C->product;
3774222ddf1SHong Zhang 
3784222ddf1SHong Zhang   PetscFunctionBegin;
3794222ddf1SHong Zhang   switch (product->type) {
380d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_AB:
381d71ae5a4SJacob Faibussowitsch     PetscCall(MatProductSetFromOptions_Elemental_AB(C));
382d71ae5a4SJacob Faibussowitsch     break;
383d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_ABt:
384d71ae5a4SJacob Faibussowitsch     PetscCall(MatProductSetFromOptions_Elemental_ABt(C));
385d71ae5a4SJacob Faibussowitsch     break;
386d71ae5a4SJacob Faibussowitsch   default:
387d71ae5a4SJacob Faibussowitsch     break;
3884222ddf1SHong Zhang   }
3894222ddf1SHong Zhang   PetscFunctionReturn(0);
3904222ddf1SHong Zhang }
391f6e5db1bSPierre Jolivet 
392d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMatMultNumeric_Elemental_MPIDense(Mat A, Mat B, Mat C)
393d71ae5a4SJacob Faibussowitsch {
394f6e5db1bSPierre Jolivet   Mat Be, Ce;
395f6e5db1bSPierre Jolivet 
396f6e5db1bSPierre Jolivet   PetscFunctionBegin;
3979566063dSJacob Faibussowitsch   PetscCall(MatConvert(B, MATELEMENTAL, MAT_INITIAL_MATRIX, &Be));
3989566063dSJacob Faibussowitsch   PetscCall(MatMatMult(A, Be, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &Ce));
3999566063dSJacob Faibussowitsch   PetscCall(MatConvert(Ce, MATMPIDENSE, MAT_REUSE_MATRIX, &C));
4009566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Be));
4019566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Ce));
402f6e5db1bSPierre Jolivet   PetscFunctionReturn(0);
403f6e5db1bSPierre Jolivet }
404f6e5db1bSPierre Jolivet 
405*cedd07caSPierre Jolivet PetscErrorCode MatMatMultSymbolic_Elemental_MPIDense(Mat A, Mat B, PetscReal, Mat C)
406d71ae5a4SJacob Faibussowitsch {
407f6e5db1bSPierre Jolivet   PetscFunctionBegin;
4089566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(C, A->rmap->n, B->cmap->n, PETSC_DECIDE, PETSC_DECIDE));
4099566063dSJacob Faibussowitsch   PetscCall(MatSetType(C, MATMPIDENSE));
4109566063dSJacob Faibussowitsch   PetscCall(MatSetUp(C));
411f6e5db1bSPierre Jolivet   C->ops->matmultnumeric = MatMatMultNumeric_Elemental_MPIDense;
412f6e5db1bSPierre Jolivet   PetscFunctionReturn(0);
413f6e5db1bSPierre Jolivet }
414f6e5db1bSPierre Jolivet 
415d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductSetFromOptions_Elemental_MPIDense_AB(Mat C)
416d71ae5a4SJacob Faibussowitsch {
417f6e5db1bSPierre Jolivet   PetscFunctionBegin;
418f6e5db1bSPierre Jolivet   C->ops->matmultsymbolic = MatMatMultSymbolic_Elemental_MPIDense;
419f6e5db1bSPierre Jolivet   C->ops->productsymbolic = MatProductSymbolic_AB;
420f6e5db1bSPierre Jolivet   PetscFunctionReturn(0);
421f6e5db1bSPierre Jolivet }
422f6e5db1bSPierre Jolivet 
423d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductSetFromOptions_Elemental_MPIDense(Mat C)
424d71ae5a4SJacob Faibussowitsch {
425f6e5db1bSPierre Jolivet   Mat_Product *product = C->product;
426f6e5db1bSPierre Jolivet 
427f6e5db1bSPierre Jolivet   PetscFunctionBegin;
42848a46eb9SPierre Jolivet   if (product->type == MATPRODUCT_AB) PetscCall(MatProductSetFromOptions_Elemental_MPIDense_AB(C));
429f6e5db1bSPierre Jolivet   PetscFunctionReturn(0);
430f6e5db1bSPierre Jolivet }
4314222ddf1SHong Zhang /* --------------------------------------- */
4324222ddf1SHong Zhang 
433d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_Elemental(Mat A, Vec D)
434d71ae5a4SJacob Faibussowitsch {
435a9d89745SXuan Zhou   PetscInt        i, nrows, ncols, nD, rrank, ridx, crank, cidx;
436a9d89745SXuan Zhou   Mat_Elemental  *a = (Mat_Elemental *)A->data;
437a9d89745SXuan Zhou   PetscElemScalar v;
438ce94432eSBarry Smith   MPI_Comm        comm;
43961119200SXuan Zhou 
44061119200SXuan Zhou   PetscFunctionBegin;
4419566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
4429566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &nrows, &ncols));
443a9d89745SXuan Zhou   nD = nrows > ncols ? ncols : nrows;
444a9d89745SXuan Zhou   for (i = 0; i < nD; i++) {
445a9d89745SXuan Zhou     PetscInt erow, ecol;
446a9d89745SXuan Zhou     P2RO(A, 0, i, &rrank, &ridx);
447a9d89745SXuan Zhou     RO2E(A, 0, rrank, ridx, &erow);
448aed4548fSBarry Smith     PetscCheck(rrank >= 0 && ridx >= 0 && erow >= 0, comm, PETSC_ERR_PLIB, "Incorrect row translation");
449a9d89745SXuan Zhou     P2RO(A, 1, i, &crank, &cidx);
450a9d89745SXuan Zhou     RO2E(A, 1, crank, cidx, &ecol);
451aed4548fSBarry Smith     PetscCheck(crank >= 0 && cidx >= 0 && ecol >= 0, comm, PETSC_ERR_PLIB, "Incorrect col translation");
452a9d89745SXuan Zhou     v = a->emat->Get(erow, ecol);
4539566063dSJacob Faibussowitsch     PetscCall(VecSetValues(D, 1, &i, (PetscScalar *)&v, INSERT_VALUES));
454ade3cc5eSXuan Zhou   }
4559566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(D));
4569566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(D));
45761119200SXuan Zhou   PetscFunctionReturn(0);
45861119200SXuan Zhou }
45961119200SXuan Zhou 
460d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_Elemental(Mat X, Vec L, Vec R)
461d71ae5a4SJacob Faibussowitsch {
462ade3cc5eSXuan Zhou   Mat_Elemental         *x = (Mat_Elemental *)X->data;
463ade3cc5eSXuan Zhou   const PetscElemScalar *d;
464ade3cc5eSXuan Zhou 
465ade3cc5eSXuan Zhou   PetscFunctionBegin;
4669065cd98SJed Brown   if (R) {
4679566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(R, (const PetscScalar **)&d));
468e8146892SSatish Balay     El::DistMatrix<PetscElemScalar, El::VC, El::STAR> de;
4690c18141cSBarry Smith     de.LockedAttach(X->cmap->N, 1, *x->grid, 0, 0, d, X->cmap->n);
470e8146892SSatish Balay     El::DiagonalScale(El::RIGHT, El::NORMAL, de, *x->emat);
4719566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(R, (const PetscScalar **)&d));
4729065cd98SJed Brown   }
4739065cd98SJed Brown   if (L) {
4749566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(L, (const PetscScalar **)&d));
475e8146892SSatish Balay     El::DistMatrix<PetscElemScalar, El::VC, El::STAR> de;
4760c18141cSBarry Smith     de.LockedAttach(X->rmap->N, 1, *x->grid, 0, 0, d, X->rmap->n);
477e8146892SSatish Balay     El::DiagonalScale(El::LEFT, El::NORMAL, de, *x->emat);
4789566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(L, (const PetscScalar **)&d));
479ade3cc5eSXuan Zhou   }
480ade3cc5eSXuan Zhou   PetscFunctionReturn(0);
481ade3cc5eSXuan Zhou }
482ade3cc5eSXuan Zhou 
483*cedd07caSPierre Jolivet static PetscErrorCode MatMissingDiagonal_Elemental(Mat, PetscBool *missing, PetscInt *)
484d71ae5a4SJacob Faibussowitsch {
48534fa46e1SFrancesco Ballarin   PetscFunctionBegin;
48634fa46e1SFrancesco Ballarin   *missing = PETSC_FALSE;
48734fa46e1SFrancesco Ballarin   PetscFunctionReturn(0);
48834fa46e1SFrancesco Ballarin }
48934fa46e1SFrancesco Ballarin 
490d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_Elemental(Mat X, PetscScalar a)
491d71ae5a4SJacob Faibussowitsch {
49265b78793SXuan Zhou   Mat_Elemental *x = (Mat_Elemental *)X->data;
49365b78793SXuan Zhou 
49465b78793SXuan Zhou   PetscFunctionBegin;
495e8146892SSatish Balay   El::Scale((PetscElemScalar)a, *x->emat);
49665b78793SXuan Zhou   PetscFunctionReturn(0);
49765b78793SXuan Zhou }
49865b78793SXuan Zhou 
499f82baa17SHong Zhang /*
500f82baa17SHong Zhang   MatAXPY - Computes Y = a*X + Y.
501f82baa17SHong Zhang */
502*cedd07caSPierre Jolivet static PetscErrorCode MatAXPY_Elemental(Mat Y, PetscScalar a, Mat X, MatStructure)
503d71ae5a4SJacob Faibussowitsch {
504e09a3074SHong Zhang   Mat_Elemental *x = (Mat_Elemental *)X->data;
505e09a3074SHong Zhang   Mat_Elemental *y = (Mat_Elemental *)Y->data;
506e09a3074SHong Zhang 
507e09a3074SHong Zhang   PetscFunctionBegin;
508e8146892SSatish Balay   El::Axpy((PetscElemScalar)a, *x->emat, *y->emat);
5099566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)Y));
510e09a3074SHong Zhang   PetscFunctionReturn(0);
511e09a3074SHong Zhang }
512e09a3074SHong Zhang 
513*cedd07caSPierre Jolivet static PetscErrorCode MatCopy_Elemental(Mat A, Mat B, MatStructure)
514d71ae5a4SJacob Faibussowitsch {
515d6223691SXuan Zhou   Mat_Elemental *a = (Mat_Elemental *)A->data;
516d6223691SXuan Zhou   Mat_Elemental *b = (Mat_Elemental *)B->data;
517d6223691SXuan Zhou 
518d6223691SXuan Zhou   PetscFunctionBegin;
519e8146892SSatish Balay   El::Copy(*a->emat, *b->emat);
5209566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)B));
521d6223691SXuan Zhou   PetscFunctionReturn(0);
522d6223691SXuan Zhou }
523d6223691SXuan Zhou 
524d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_Elemental(Mat A, MatDuplicateOption op, Mat *B)
525d71ae5a4SJacob Faibussowitsch {
526df311e6cSXuan Zhou   Mat            Be;
527ce94432eSBarry Smith   MPI_Comm       comm;
528df311e6cSXuan Zhou   Mat_Elemental *a = (Mat_Elemental *)A->data;
529df311e6cSXuan Zhou 
530df311e6cSXuan Zhou   PetscFunctionBegin;
5319566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
5329566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &Be));
5339566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(Be, A->rmap->n, A->cmap->n, PETSC_DECIDE, PETSC_DECIDE));
5349566063dSJacob Faibussowitsch   PetscCall(MatSetType(Be, MATELEMENTAL));
5359566063dSJacob Faibussowitsch   PetscCall(MatSetUp(Be));
536df311e6cSXuan Zhou   *B = Be;
537df311e6cSXuan Zhou   if (op == MAT_COPY_VALUES) {
538df311e6cSXuan Zhou     Mat_Elemental *b = (Mat_Elemental *)Be->data;
539e8146892SSatish Balay     El::Copy(*a->emat, *b->emat);
540df311e6cSXuan Zhou   }
541df311e6cSXuan Zhou   Be->assembled = PETSC_TRUE;
542df311e6cSXuan Zhou   PetscFunctionReturn(0);
543df311e6cSXuan Zhou }
544df311e6cSXuan Zhou 
545d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatTranspose_Elemental(Mat A, MatReuse reuse, Mat *B)
546d71ae5a4SJacob Faibussowitsch {
547ec8cb81fSBarry Smith   Mat            Be = *B;
548ce94432eSBarry Smith   MPI_Comm       comm;
5494fe7bbcaSHong Zhang   Mat_Elemental *a = (Mat_Elemental *)A->data, *b;
550d6223691SXuan Zhou 
551d6223691SXuan Zhou   PetscFunctionBegin;
5527fb60732SBarry Smith   if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B));
5539566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
5545cb544a0SHong Zhang   /* Only out-of-place supported */
5555f80ce2aSJacob Faibussowitsch   PetscCheck(reuse != MAT_INPLACE_MATRIX, comm, PETSC_ERR_SUP, "Only out-of-place supported");
5565262d616SXuan Zhou   if (reuse == MAT_INITIAL_MATRIX) {
5579566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, &Be));
5589566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(Be, A->cmap->n, A->rmap->n, PETSC_DECIDE, PETSC_DECIDE));
5599566063dSJacob Faibussowitsch     PetscCall(MatSetType(Be, MATELEMENTAL));
5609566063dSJacob Faibussowitsch     PetscCall(MatSetUp(Be));
5615262d616SXuan Zhou     *B = Be;
5625262d616SXuan Zhou   }
5634fe7bbcaSHong Zhang   b = (Mat_Elemental *)Be->data;
564e8146892SSatish Balay   El::Transpose(*a->emat, *b->emat);
5655262d616SXuan Zhou   Be->assembled = PETSC_TRUE;
566d6223691SXuan Zhou   PetscFunctionReturn(0);
567d6223691SXuan Zhou }
568d6223691SXuan Zhou 
569d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatConjugate_Elemental(Mat A)
570d71ae5a4SJacob Faibussowitsch {
571dfcb0403SXuan Zhou   Mat_Elemental *a = (Mat_Elemental *)A->data;
572dfcb0403SXuan Zhou 
573dfcb0403SXuan Zhou   PetscFunctionBegin;
574e8146892SSatish Balay   El::Conjugate(*a->emat);
575dfcb0403SXuan Zhou   PetscFunctionReturn(0);
576dfcb0403SXuan Zhou }
577dfcb0403SXuan Zhou 
578d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatHermitianTranspose_Elemental(Mat A, MatReuse reuse, Mat *B)
579d71ae5a4SJacob Faibussowitsch {
580ec8cb81fSBarry Smith   Mat            Be = *B;
581ce94432eSBarry Smith   MPI_Comm       comm;
5824a29722dSXuan Zhou   Mat_Elemental *a = (Mat_Elemental *)A->data, *b;
5834a29722dSXuan Zhou 
5844a29722dSXuan Zhou   PetscFunctionBegin;
5859566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
5865cb544a0SHong Zhang   /* Only out-of-place supported */
5874a29722dSXuan Zhou   if (reuse == MAT_INITIAL_MATRIX) {
5889566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, &Be));
5899566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(Be, A->cmap->n, A->rmap->n, PETSC_DECIDE, PETSC_DECIDE));
5909566063dSJacob Faibussowitsch     PetscCall(MatSetType(Be, MATELEMENTAL));
5919566063dSJacob Faibussowitsch     PetscCall(MatSetUp(Be));
5924a29722dSXuan Zhou     *B = Be;
5934a29722dSXuan Zhou   }
5944a29722dSXuan Zhou   b = (Mat_Elemental *)Be->data;
595e8146892SSatish Balay   El::Adjoint(*a->emat, *b->emat);
5964a29722dSXuan Zhou   Be->assembled = PETSC_TRUE;
5974a29722dSXuan Zhou   PetscFunctionReturn(0);
5984a29722dSXuan Zhou }
5994a29722dSXuan Zhou 
600d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSolve_Elemental(Mat A, Vec B, Vec X)
601d71ae5a4SJacob Faibussowitsch {
6021f881ff8SXuan Zhou   Mat_Elemental   *a = (Mat_Elemental *)A->data;
603df311e6cSXuan Zhou   PetscElemScalar *x;
604ea394475SSatish Balay   PetscInt         pivoting = a->pivoting;
6051f881ff8SXuan Zhou 
6061f881ff8SXuan Zhou   PetscFunctionBegin;
6079566063dSJacob Faibussowitsch   PetscCall(VecCopy(B, X));
6089566063dSJacob Faibussowitsch   PetscCall(VecGetArray(X, (PetscScalar **)&x));
609ea394475SSatish Balay 
610e8146892SSatish Balay   El::DistMatrix<PetscElemScalar, El::VC, El::STAR> xe;
6110c18141cSBarry Smith   xe.Attach(A->rmap->N, 1, *a->grid, 0, 0, x, A->rmap->n);
612e8146892SSatish Balay   El::DistMatrix<PetscElemScalar, El::MC, El::MR> xer(xe);
613fc54b460SXuan Zhou   switch (A->factortype) {
614fc54b460SXuan Zhou   case MAT_FACTOR_LU:
615ea394475SSatish Balay     if (pivoting == 0) {
616e8146892SSatish Balay       El::lu::SolveAfter(El::NORMAL, *a->emat, xer);
617ea394475SSatish Balay     } else if (pivoting == 1) {
618ea394475SSatish Balay       El::lu::SolveAfter(El::NORMAL, *a->emat, *a->P, xer);
619ea394475SSatish Balay     } else { /* pivoting == 2 */
620ea394475SSatish Balay       El::lu::SolveAfter(El::NORMAL, *a->emat, *a->P, *a->Q, xer);
6211f881ff8SXuan Zhou     }
622fc54b460SXuan Zhou     break;
623d71ae5a4SJacob Faibussowitsch   case MAT_FACTOR_CHOLESKY:
624d71ae5a4SJacob Faibussowitsch     El::cholesky::SolveAfter(El::UPPER, El::NORMAL, *a->emat, xer);
625d71ae5a4SJacob Faibussowitsch     break;
626d71ae5a4SJacob Faibussowitsch   default:
627d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unfactored Matrix or Unsupported MatFactorType");
628d71ae5a4SJacob Faibussowitsch     break;
6291f881ff8SXuan Zhou   }
630ea394475SSatish Balay   El::Copy(xer, xe);
631ea394475SSatish Balay 
6329566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(X, (PetscScalar **)&x));
6331f881ff8SXuan Zhou   PetscFunctionReturn(0);
6341f881ff8SXuan Zhou }
6351f881ff8SXuan Zhou 
636d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSolveAdd_Elemental(Mat A, Vec B, Vec Y, Vec X)
637d71ae5a4SJacob Faibussowitsch {
638df311e6cSXuan Zhou   PetscFunctionBegin;
6399566063dSJacob Faibussowitsch   PetscCall(MatSolve_Elemental(A, B, X));
6409566063dSJacob Faibussowitsch   PetscCall(VecAXPY(X, 1, Y));
641df311e6cSXuan Zhou   PetscFunctionReturn(0);
642df311e6cSXuan Zhou }
643df311e6cSXuan Zhou 
644d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMatSolve_Elemental(Mat A, Mat B, Mat X)
645d71ae5a4SJacob Faibussowitsch {
6461f0e42cfSHong Zhang   Mat_Elemental *a = (Mat_Elemental *)A->data;
64742ba530cSPierre Jolivet   Mat_Elemental *x;
64842ba530cSPierre Jolivet   Mat            C;
649ea394475SSatish Balay   PetscInt       pivoting = a->pivoting;
65042ba530cSPierre Jolivet   PetscBool      flg;
65142ba530cSPierre Jolivet   MatType        type;
6521f0e42cfSHong Zhang 
653ae844d54SHong Zhang   PetscFunctionBegin;
6549566063dSJacob Faibussowitsch   PetscCall(MatGetType(X, &type));
6559566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(type, MATELEMENTAL, &flg));
65642ba530cSPierre Jolivet   if (!flg) {
6579566063dSJacob Faibussowitsch     PetscCall(MatConvert(B, MATELEMENTAL, MAT_INITIAL_MATRIX, &C));
65842ba530cSPierre Jolivet     x = (Mat_Elemental *)C->data;
65942ba530cSPierre Jolivet   } else {
66042ba530cSPierre Jolivet     x = (Mat_Elemental *)X->data;
66142ba530cSPierre Jolivet     El::Copy(*((Mat_Elemental *)B->data)->emat, *x->emat);
66242ba530cSPierre Jolivet   }
663fc54b460SXuan Zhou   switch (A->factortype) {
664fc54b460SXuan Zhou   case MAT_FACTOR_LU:
665ea394475SSatish Balay     if (pivoting == 0) {
666e8146892SSatish Balay       El::lu::SolveAfter(El::NORMAL, *a->emat, *x->emat);
667ea394475SSatish Balay     } else if (pivoting == 1) {
668ea394475SSatish Balay       El::lu::SolveAfter(El::NORMAL, *a->emat, *a->P, *x->emat);
669ea394475SSatish Balay     } else {
670ea394475SSatish Balay       El::lu::SolveAfter(El::NORMAL, *a->emat, *a->P, *a->Q, *x->emat);
671d6223691SXuan Zhou     }
672fc54b460SXuan Zhou     break;
673d71ae5a4SJacob Faibussowitsch   case MAT_FACTOR_CHOLESKY:
674d71ae5a4SJacob Faibussowitsch     El::cholesky::SolveAfter(El::UPPER, El::NORMAL, *a->emat, *x->emat);
675d71ae5a4SJacob Faibussowitsch     break;
676d71ae5a4SJacob Faibussowitsch   default:
677d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unfactored Matrix or Unsupported MatFactorType");
678d71ae5a4SJacob Faibussowitsch     break;
679fc54b460SXuan Zhou   }
68042ba530cSPierre Jolivet   if (!flg) {
6819566063dSJacob Faibussowitsch     PetscCall(MatConvert(C, type, MAT_REUSE_MATRIX, &X));
6829566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&C));
68342ba530cSPierre Jolivet   }
684ae844d54SHong Zhang   PetscFunctionReturn(0);
685ae844d54SHong Zhang }
686ae844d54SHong Zhang 
687*cedd07caSPierre Jolivet static PetscErrorCode MatLUFactor_Elemental(Mat A, IS, IS, const MatFactorInfo *)
688d71ae5a4SJacob Faibussowitsch {
6897c920d81SXuan Zhou   Mat_Elemental *a        = (Mat_Elemental *)A->data;
690ea394475SSatish Balay   PetscInt       pivoting = a->pivoting;
6917c920d81SXuan Zhou 
692ae844d54SHong Zhang   PetscFunctionBegin;
693ea394475SSatish Balay   if (pivoting == 0) {
694e8146892SSatish Balay     El::LU(*a->emat);
695ea394475SSatish Balay   } else if (pivoting == 1) {
696ea394475SSatish Balay     El::LU(*a->emat, *a->P);
697ea394475SSatish Balay   } else {
698ea394475SSatish Balay     El::LU(*a->emat, *a->P, *a->Q);
699d6223691SXuan Zhou   }
7001293973dSHong Zhang   A->factortype = MAT_FACTOR_LU;
701834d3fecSHong Zhang   A->assembled  = PETSC_TRUE;
702f6224b95SHong Zhang 
7039566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->solvertype));
7049566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(MATSOLVERELEMENTAL, &A->solvertype));
705ae844d54SHong Zhang   PetscFunctionReturn(0);
706ae844d54SHong Zhang }
707ae844d54SHong Zhang 
708d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatLUFactorNumeric_Elemental(Mat F, Mat A, const MatFactorInfo *info)
709d71ae5a4SJacob Faibussowitsch {
710d7c3f9d8SHong Zhang   PetscFunctionBegin;
7119566063dSJacob Faibussowitsch   PetscCall(MatCopy(A, F, SAME_NONZERO_PATTERN));
7129566063dSJacob Faibussowitsch   PetscCall(MatLUFactor_Elemental(F, 0, 0, info));
713d7c3f9d8SHong Zhang   PetscFunctionReturn(0);
714d7c3f9d8SHong Zhang }
715d7c3f9d8SHong Zhang 
716*cedd07caSPierre Jolivet static PetscErrorCode MatLUFactorSymbolic_Elemental(Mat, Mat, IS, IS, const MatFactorInfo *)
717d71ae5a4SJacob Faibussowitsch {
718d7c3f9d8SHong Zhang   PetscFunctionBegin;
719d8304050SJose E. Roman   /* F is created and allocated by MatGetFactor_elemental_petsc(), skip this routine. */
720d7c3f9d8SHong Zhang   PetscFunctionReturn(0);
721d7c3f9d8SHong Zhang }
722d7c3f9d8SHong Zhang 
723*cedd07caSPierre Jolivet static PetscErrorCode MatCholeskyFactor_Elemental(Mat A, IS, const MatFactorInfo *)
724d71ae5a4SJacob Faibussowitsch {
72545cf121fSXuan Zhou   Mat_Elemental                                    *a = (Mat_Elemental *)A->data;
726e8146892SSatish Balay   El::DistMatrix<PetscElemScalar, El::MC, El::STAR> d;
72745cf121fSXuan Zhou 
72845cf121fSXuan Zhou   PetscFunctionBegin;
729e8146892SSatish Balay   El::Cholesky(El::UPPER, *a->emat);
730fc54b460SXuan Zhou   A->factortype = MAT_FACTOR_CHOLESKY;
731834d3fecSHong Zhang   A->assembled  = PETSC_TRUE;
732f6224b95SHong Zhang 
7339566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->solvertype));
7349566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(MATSOLVERELEMENTAL, &A->solvertype));
73545cf121fSXuan Zhou   PetscFunctionReturn(0);
73645cf121fSXuan Zhou }
73745cf121fSXuan Zhou 
738d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCholeskyFactorNumeric_Elemental(Mat F, Mat A, const MatFactorInfo *info)
739d71ae5a4SJacob Faibussowitsch {
740cb76c1d8SXuan Zhou   PetscFunctionBegin;
7419566063dSJacob Faibussowitsch   PetscCall(MatCopy(A, F, SAME_NONZERO_PATTERN));
7429566063dSJacob Faibussowitsch   PetscCall(MatCholeskyFactor_Elemental(F, 0, info));
743cb76c1d8SXuan Zhou   PetscFunctionReturn(0);
74479673f7bSHong Zhang }
745cb76c1d8SXuan Zhou 
746*cedd07caSPierre Jolivet static PetscErrorCode MatCholeskyFactorSymbolic_Elemental(Mat, Mat, IS, const MatFactorInfo *)
747d71ae5a4SJacob Faibussowitsch {
74879673f7bSHong Zhang   PetscFunctionBegin;
749d8304050SJose E. Roman   /* F is created and allocated by MatGetFactor_elemental_petsc(), skip this routine. */
75079673f7bSHong Zhang   PetscFunctionReturn(0);
75179673f7bSHong Zhang }
75279673f7bSHong Zhang 
753*cedd07caSPierre Jolivet PetscErrorCode MatFactorGetSolverType_elemental_elemental(Mat, MatSolverType *type)
754d71ae5a4SJacob Faibussowitsch {
75515767789SHong Zhang   PetscFunctionBegin;
75615767789SHong Zhang   *type = MATSOLVERELEMENTAL;
75715767789SHong Zhang   PetscFunctionReturn(0);
75815767789SHong Zhang }
75915767789SHong Zhang 
760d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetFactor_elemental_elemental(Mat A, MatFactorType ftype, Mat *F)
761d71ae5a4SJacob Faibussowitsch {
7621293973dSHong Zhang   Mat B;
7631293973dSHong Zhang 
7641293973dSHong Zhang   PetscFunctionBegin;
7651293973dSHong Zhang   /* Create the factorization matrix */
7669566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &B));
7679566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(B, A->rmap->n, A->cmap->n, PETSC_DECIDE, PETSC_DECIDE));
7689566063dSJacob Faibussowitsch   PetscCall(MatSetType(B, MATELEMENTAL));
7699566063dSJacob Faibussowitsch   PetscCall(MatSetUp(B));
7701293973dSHong Zhang   B->factortype      = ftype;
77166e17bc3SBarry Smith   B->trivialsymbolic = PETSC_TRUE;
7729566063dSJacob Faibussowitsch   PetscCall(PetscFree(B->solvertype));
7739566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(MATSOLVERELEMENTAL, &B->solvertype));
77400c67f3bSHong Zhang 
7759566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatFactorGetSolverType_C", MatFactorGetSolverType_elemental_elemental));
7761293973dSHong Zhang   *F = B;
7771293973dSHong Zhang   PetscFunctionReturn(0);
7781293973dSHong Zhang }
7791293973dSHong Zhang 
780d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatSolverTypeRegister_Elemental(void)
781d71ae5a4SJacob Faibussowitsch {
78242c9c57cSBarry Smith   PetscFunctionBegin;
7839566063dSJacob Faibussowitsch   PetscCall(MatSolverTypeRegister(MATSOLVERELEMENTAL, MATELEMENTAL, MAT_FACTOR_LU, MatGetFactor_elemental_elemental));
7849566063dSJacob Faibussowitsch   PetscCall(MatSolverTypeRegister(MATSOLVERELEMENTAL, MATELEMENTAL, MAT_FACTOR_CHOLESKY, MatGetFactor_elemental_elemental));
78542c9c57cSBarry Smith   PetscFunctionReturn(0);
78642c9c57cSBarry Smith }
78742c9c57cSBarry Smith 
788d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNorm_Elemental(Mat A, NormType type, PetscReal *nrm)
789d71ae5a4SJacob Faibussowitsch {
7901f881ff8SXuan Zhou   Mat_Elemental *a = (Mat_Elemental *)A->data;
7911f881ff8SXuan Zhou 
7921f881ff8SXuan Zhou   PetscFunctionBegin;
7931f881ff8SXuan Zhou   switch (type) {
794d71ae5a4SJacob Faibussowitsch   case NORM_1:
795d71ae5a4SJacob Faibussowitsch     *nrm = El::OneNorm(*a->emat);
796d71ae5a4SJacob Faibussowitsch     break;
797d71ae5a4SJacob Faibussowitsch   case NORM_FROBENIUS:
798d71ae5a4SJacob Faibussowitsch     *nrm = El::FrobeniusNorm(*a->emat);
799d71ae5a4SJacob Faibussowitsch     break;
800d71ae5a4SJacob Faibussowitsch   case NORM_INFINITY:
801d71ae5a4SJacob Faibussowitsch     *nrm = El::InfinityNorm(*a->emat);
802d71ae5a4SJacob Faibussowitsch     break;
803d71ae5a4SJacob Faibussowitsch   default:
804d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Unsupported norm type");
8051f881ff8SXuan Zhou   }
8061f881ff8SXuan Zhou   PetscFunctionReturn(0);
8071f881ff8SXuan Zhou }
8081f881ff8SXuan Zhou 
809d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroEntries_Elemental(Mat A)
810d71ae5a4SJacob Faibussowitsch {
8115262d616SXuan Zhou   Mat_Elemental *a = (Mat_Elemental *)A->data;
8125262d616SXuan Zhou 
8135262d616SXuan Zhou   PetscFunctionBegin;
814e8146892SSatish Balay   El::Zero(*a->emat);
8155262d616SXuan Zhou   PetscFunctionReturn(0);
8165262d616SXuan Zhou }
8175262d616SXuan Zhou 
818d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetOwnershipIS_Elemental(Mat A, IS *rows, IS *cols)
819d71ae5a4SJacob Faibussowitsch {
820db31f6deSJed Brown   Mat_Elemental *a = (Mat_Elemental *)A->data;
821db31f6deSJed Brown   PetscInt       i, m, shift, stride, *idx;
822db31f6deSJed Brown 
823db31f6deSJed Brown   PetscFunctionBegin;
824db31f6deSJed Brown   if (rows) {
825db31f6deSJed Brown     m      = a->emat->LocalHeight();
826db31f6deSJed Brown     shift  = a->emat->ColShift();
827db31f6deSJed Brown     stride = a->emat->ColStride();
8289566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(m, &idx));
829db31f6deSJed Brown     for (i = 0; i < m; i++) {
830db31f6deSJed Brown       PetscInt rank, offset;
831db31f6deSJed Brown       E2RO(A, 0, shift + i * stride, &rank, &offset);
832db31f6deSJed Brown       RO2P(A, 0, rank, offset, &idx[i]);
833db31f6deSJed Brown     }
8349566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, idx, PETSC_OWN_POINTER, rows));
835db31f6deSJed Brown   }
836db31f6deSJed Brown   if (cols) {
837db31f6deSJed Brown     m      = a->emat->LocalWidth();
838db31f6deSJed Brown     shift  = a->emat->RowShift();
839db31f6deSJed Brown     stride = a->emat->RowStride();
8409566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(m, &idx));
841db31f6deSJed Brown     for (i = 0; i < m; i++) {
842db31f6deSJed Brown       PetscInt rank, offset;
843db31f6deSJed Brown       E2RO(A, 1, shift + i * stride, &rank, &offset);
844db31f6deSJed Brown       RO2P(A, 1, rank, offset, &idx[i]);
845db31f6deSJed Brown     }
8469566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, idx, PETSC_OWN_POINTER, cols));
847db31f6deSJed Brown   }
848db31f6deSJed Brown   PetscFunctionReturn(0);
849db31f6deSJed Brown }
850db31f6deSJed Brown 
851*cedd07caSPierre Jolivet static PetscErrorCode MatConvert_Elemental_Dense(Mat A, MatType, MatReuse reuse, Mat *B)
852d71ae5a4SJacob Faibussowitsch {
8532ef0cf24SXuan Zhou   Mat             Bmpi;
854af295397SXuan Zhou   Mat_Elemental  *a = (Mat_Elemental *)A->data;
855ce94432eSBarry Smith   MPI_Comm        comm;
856fa9e26c8SHong Zhang   IS              isrows, iscols;
857fa9e26c8SHong Zhang   PetscInt        rrank, ridx, crank, cidx, nrows, ncols, i, j, erow, ecol, elrow, elcol;
858fa9e26c8SHong Zhang   const PetscInt *rows, *cols;
859df311e6cSXuan Zhou   PetscElemScalar v;
860fa9e26c8SHong Zhang   const El::Grid &grid = a->emat->Grid();
861af295397SXuan Zhou 
862af295397SXuan Zhou   PetscFunctionBegin;
8639566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
864a000e53bSHong Zhang 
865de0a22f0SHong Zhang   if (reuse == MAT_REUSE_MATRIX) {
866de0a22f0SHong Zhang     Bmpi = *B;
867de0a22f0SHong Zhang   } else {
8689566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, &Bmpi));
8699566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(Bmpi, A->rmap->n, A->cmap->n, PETSC_DECIDE, PETSC_DECIDE));
8709566063dSJacob Faibussowitsch     PetscCall(MatSetType(Bmpi, MATDENSE));
8719566063dSJacob Faibussowitsch     PetscCall(MatSetUp(Bmpi));
872de0a22f0SHong Zhang   }
873fa9e26c8SHong Zhang 
874fa9e26c8SHong Zhang   /* Get local entries of A */
8759566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipIS(A, &isrows, &iscols));
8769566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(isrows, &nrows));
8779566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(isrows, &rows));
8789566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(iscols, &ncols));
8799566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(iscols, &cols));
880fa9e26c8SHong Zhang 
88157299f2fSHong Zhang   if (a->roworiented) {
8822ef0cf24SXuan Zhou     for (i = 0; i < nrows; i++) {
883fa9e26c8SHong Zhang       P2RO(A, 0, rows[i], &rrank, &ridx); /* convert indices between PETSc <-> (Rank,Offset) <-> Elemental */
8842ef0cf24SXuan Zhou       RO2E(A, 0, rrank, ridx, &erow);
885aed4548fSBarry Smith       PetscCheck(rrank >= 0 && ridx >= 0 && erow >= 0, comm, PETSC_ERR_PLIB, "Incorrect row translation");
8862ef0cf24SXuan Zhou       for (j = 0; j < ncols; j++) {
887fa9e26c8SHong Zhang         P2RO(A, 1, cols[j], &crank, &cidx);
8882ef0cf24SXuan Zhou         RO2E(A, 1, crank, cidx, &ecol);
889aed4548fSBarry Smith         PetscCheck(crank >= 0 && cidx >= 0 && ecol >= 0, comm, PETSC_ERR_PLIB, "Incorrect col translation");
890fa9e26c8SHong Zhang 
891fa9e26c8SHong Zhang         elrow = erow / grid.MCSize(); /* Elemental local row index */
892fa9e26c8SHong Zhang         elcol = ecol / grid.MRSize(); /* Elemental local column index */
893fa9e26c8SHong Zhang         v     = a->emat->GetLocal(elrow, elcol);
8949566063dSJacob Faibussowitsch         PetscCall(MatSetValues(Bmpi, 1, &rows[i], 1, &cols[j], (PetscScalar *)&v, INSERT_VALUES));
8952ef0cf24SXuan Zhou       }
8962ef0cf24SXuan Zhou     }
89757299f2fSHong Zhang   } else { /* column-oriented */
89857299f2fSHong Zhang     for (j = 0; j < ncols; j++) {
89957299f2fSHong Zhang       P2RO(A, 1, cols[j], &crank, &cidx);
90057299f2fSHong Zhang       RO2E(A, 1, crank, cidx, &ecol);
901aed4548fSBarry Smith       PetscCheck(crank >= 0 && cidx >= 0 && ecol >= 0, comm, PETSC_ERR_PLIB, "Incorrect col translation");
90257299f2fSHong Zhang       for (i = 0; i < nrows; i++) {
90357299f2fSHong Zhang         P2RO(A, 0, rows[i], &rrank, &ridx); /* convert indices between PETSc <-> (Rank,Offset) <-> Elemental */
90457299f2fSHong Zhang         RO2E(A, 0, rrank, ridx, &erow);
905aed4548fSBarry Smith         PetscCheck(rrank >= 0 && ridx >= 0 && erow >= 0, comm, PETSC_ERR_PLIB, "Incorrect row translation");
90657299f2fSHong Zhang 
90757299f2fSHong Zhang         elrow = erow / grid.MCSize(); /* Elemental local row index */
90857299f2fSHong Zhang         elcol = ecol / grid.MRSize(); /* Elemental local column index */
90957299f2fSHong Zhang         v     = a->emat->GetLocal(elrow, elcol);
9109566063dSJacob Faibussowitsch         PetscCall(MatSetValues(Bmpi, 1, &rows[i], 1, &cols[j], (PetscScalar *)&v, INSERT_VALUES));
91157299f2fSHong Zhang       }
91257299f2fSHong Zhang     }
91357299f2fSHong Zhang   }
9149566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(Bmpi, MAT_FINAL_ASSEMBLY));
9159566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(Bmpi, MAT_FINAL_ASSEMBLY));
916511c6705SHong Zhang   if (reuse == MAT_INPLACE_MATRIX) {
9179566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &Bmpi));
918c4ad791aSXuan Zhou   } else {
919c4ad791aSXuan Zhou     *B = Bmpi;
920c4ad791aSXuan Zhou   }
9219566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&isrows));
9229566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&iscols));
923af295397SXuan Zhou   PetscFunctionReturn(0);
924af295397SXuan Zhou }
925af295397SXuan Zhou 
926*cedd07caSPierre Jolivet PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_Elemental(Mat A, MatType, MatReuse reuse, Mat *newmat)
927d71ae5a4SJacob Faibussowitsch {
928af8000cdSHong Zhang   Mat                mat_elemental;
929af8000cdSHong Zhang   PetscInt           M = A->rmap->N, N = A->cmap->N, row, ncols;
930af8000cdSHong Zhang   const PetscInt    *cols;
931af8000cdSHong Zhang   const PetscScalar *vals;
932af8000cdSHong Zhang 
933af8000cdSHong Zhang   PetscFunctionBegin;
934bdeae278SStefano Zampini   if (reuse == MAT_REUSE_MATRIX) {
935bdeae278SStefano Zampini     mat_elemental = *newmat;
9369566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(mat_elemental));
937bdeae278SStefano Zampini   } else {
9389566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &mat_elemental));
9399566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(mat_elemental, PETSC_DECIDE, PETSC_DECIDE, M, N));
9409566063dSJacob Faibussowitsch     PetscCall(MatSetType(mat_elemental, MATELEMENTAL));
9419566063dSJacob Faibussowitsch     PetscCall(MatSetUp(mat_elemental));
942bdeae278SStefano Zampini   }
943af8000cdSHong Zhang   for (row = 0; row < M; row++) {
9449566063dSJacob Faibussowitsch     PetscCall(MatGetRow(A, row, &ncols, &cols, &vals));
945bdeae278SStefano Zampini     /* PETSc-Elemental interface uses axpy for setting off-processor entries, only ADD_VALUES is allowed */
9469566063dSJacob Faibussowitsch     PetscCall(MatSetValues(mat_elemental, 1, &row, ncols, cols, vals, ADD_VALUES));
9479566063dSJacob Faibussowitsch     PetscCall(MatRestoreRow(A, row, &ncols, &cols, &vals));
948af8000cdSHong Zhang   }
9499566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat_elemental, MAT_FINAL_ASSEMBLY));
9509566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat_elemental, MAT_FINAL_ASSEMBLY));
951af8000cdSHong Zhang 
952511c6705SHong Zhang   if (reuse == MAT_INPLACE_MATRIX) {
9539566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &mat_elemental));
954af8000cdSHong Zhang   } else {
955af8000cdSHong Zhang     *newmat = mat_elemental;
956af8000cdSHong Zhang   }
957af8000cdSHong Zhang   PetscFunctionReturn(0);
958af8000cdSHong Zhang }
959af8000cdSHong Zhang 
960*cedd07caSPierre Jolivet PETSC_INTERN PetscErrorCode MatConvert_MPIAIJ_Elemental(Mat A, MatType, MatReuse reuse, Mat *newmat)
961d71ae5a4SJacob Faibussowitsch {
9625d7652ecSHong Zhang   Mat                mat_elemental;
9635d7652ecSHong Zhang   PetscInt           row, ncols, rstart = A->rmap->rstart, rend = A->rmap->rend, j;
9645d7652ecSHong Zhang   const PetscInt    *cols;
9655d7652ecSHong Zhang   const PetscScalar *vals;
9665d7652ecSHong Zhang 
9675d7652ecSHong Zhang   PetscFunctionBegin;
968bdeae278SStefano Zampini   if (reuse == MAT_REUSE_MATRIX) {
969bdeae278SStefano Zampini     mat_elemental = *newmat;
9709566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(mat_elemental));
971bdeae278SStefano Zampini   } else {
9729566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &mat_elemental));
9739566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(mat_elemental, PETSC_DECIDE, PETSC_DECIDE, A->rmap->N, A->cmap->N));
9749566063dSJacob Faibussowitsch     PetscCall(MatSetType(mat_elemental, MATELEMENTAL));
9759566063dSJacob Faibussowitsch     PetscCall(MatSetUp(mat_elemental));
976bdeae278SStefano Zampini   }
9775d7652ecSHong Zhang   for (row = rstart; row < rend; row++) {
9789566063dSJacob Faibussowitsch     PetscCall(MatGetRow(A, row, &ncols, &cols, &vals));
9795d7652ecSHong Zhang     for (j = 0; j < ncols; j++) {
980bdeae278SStefano Zampini       /* PETSc-Elemental interface uses axpy for setting off-processor entries, only ADD_VALUES is allowed */
9819566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mat_elemental, 1, &row, 1, &cols[j], &vals[j], ADD_VALUES));
9825d7652ecSHong Zhang     }
9839566063dSJacob Faibussowitsch     PetscCall(MatRestoreRow(A, row, &ncols, &cols, &vals));
9845d7652ecSHong Zhang   }
9859566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat_elemental, MAT_FINAL_ASSEMBLY));
9869566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat_elemental, MAT_FINAL_ASSEMBLY));
9875d7652ecSHong Zhang 
988511c6705SHong Zhang   if (reuse == MAT_INPLACE_MATRIX) {
9899566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &mat_elemental));
9905d7652ecSHong Zhang   } else {
9915d7652ecSHong Zhang     *newmat = mat_elemental;
9925d7652ecSHong Zhang   }
9935d7652ecSHong Zhang   PetscFunctionReturn(0);
9945d7652ecSHong Zhang }
9955d7652ecSHong Zhang 
996*cedd07caSPierre Jolivet PETSC_INTERN PetscErrorCode MatConvert_SeqSBAIJ_Elemental(Mat A, MatType, MatReuse reuse, Mat *newmat)
997d71ae5a4SJacob Faibussowitsch {
9986214f412SHong Zhang   Mat                mat_elemental;
9996214f412SHong Zhang   PetscInt           M = A->rmap->N, N = A->cmap->N, row, ncols, j;
10006214f412SHong Zhang   const PetscInt    *cols;
10016214f412SHong Zhang   const PetscScalar *vals;
10026214f412SHong Zhang 
10036214f412SHong Zhang   PetscFunctionBegin;
1004bdeae278SStefano Zampini   if (reuse == MAT_REUSE_MATRIX) {
1005bdeae278SStefano Zampini     mat_elemental = *newmat;
10069566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(mat_elemental));
1007bdeae278SStefano Zampini   } else {
10089566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &mat_elemental));
10099566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(mat_elemental, PETSC_DECIDE, PETSC_DECIDE, M, N));
10109566063dSJacob Faibussowitsch     PetscCall(MatSetType(mat_elemental, MATELEMENTAL));
10119566063dSJacob Faibussowitsch     PetscCall(MatSetUp(mat_elemental));
1012bdeae278SStefano Zampini   }
10139566063dSJacob Faibussowitsch   PetscCall(MatGetRowUpperTriangular(A));
10146214f412SHong Zhang   for (row = 0; row < M; row++) {
10159566063dSJacob Faibussowitsch     PetscCall(MatGetRow(A, row, &ncols, &cols, &vals));
1016bdeae278SStefano Zampini     /* PETSc-Elemental interface uses axpy for setting off-processor entries, only ADD_VALUES is allowed */
10179566063dSJacob Faibussowitsch     PetscCall(MatSetValues(mat_elemental, 1, &row, ncols, cols, vals, ADD_VALUES));
10186214f412SHong Zhang     for (j = 0; j < ncols; j++) { /* lower triangular part */
1019eb1ec7c1SStefano Zampini       PetscScalar v;
10206214f412SHong Zhang       if (cols[j] == row) continue;
1021b94d7dedSBarry Smith       v = A->hermitian == PETSC_BOOL3_TRUE ? PetscConj(vals[j]) : vals[j];
10229566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mat_elemental, 1, &cols[j], 1, &row, &v, ADD_VALUES));
10236214f412SHong Zhang     }
10249566063dSJacob Faibussowitsch     PetscCall(MatRestoreRow(A, row, &ncols, &cols, &vals));
10256214f412SHong Zhang   }
10269566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowUpperTriangular(A));
10279566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat_elemental, MAT_FINAL_ASSEMBLY));
10289566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat_elemental, MAT_FINAL_ASSEMBLY));
10296214f412SHong Zhang 
1030511c6705SHong Zhang   if (reuse == MAT_INPLACE_MATRIX) {
10319566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &mat_elemental));
10326214f412SHong Zhang   } else {
10336214f412SHong Zhang     *newmat = mat_elemental;
10346214f412SHong Zhang   }
10356214f412SHong Zhang   PetscFunctionReturn(0);
10366214f412SHong Zhang }
10376214f412SHong Zhang 
1038*cedd07caSPierre Jolivet PETSC_INTERN PetscErrorCode MatConvert_MPISBAIJ_Elemental(Mat A, MatType, MatReuse reuse, Mat *newmat)
1039d71ae5a4SJacob Faibussowitsch {
10406214f412SHong Zhang   Mat                mat_elemental;
10416214f412SHong Zhang   PetscInt           M = A->rmap->N, N = A->cmap->N, row, ncols, j, rstart = A->rmap->rstart, rend = A->rmap->rend;
10426214f412SHong Zhang   const PetscInt    *cols;
10436214f412SHong Zhang   const PetscScalar *vals;
10446214f412SHong Zhang 
10456214f412SHong Zhang   PetscFunctionBegin;
1046bdeae278SStefano Zampini   if (reuse == MAT_REUSE_MATRIX) {
1047bdeae278SStefano Zampini     mat_elemental = *newmat;
10489566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(mat_elemental));
1049bdeae278SStefano Zampini   } else {
10509566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &mat_elemental));
10519566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(mat_elemental, PETSC_DECIDE, PETSC_DECIDE, M, N));
10529566063dSJacob Faibussowitsch     PetscCall(MatSetType(mat_elemental, MATELEMENTAL));
10539566063dSJacob Faibussowitsch     PetscCall(MatSetUp(mat_elemental));
1054bdeae278SStefano Zampini   }
10559566063dSJacob Faibussowitsch   PetscCall(MatGetRowUpperTriangular(A));
10566214f412SHong Zhang   for (row = rstart; row < rend; row++) {
10579566063dSJacob Faibussowitsch     PetscCall(MatGetRow(A, row, &ncols, &cols, &vals));
1058bdeae278SStefano Zampini     /* PETSc-Elemental interface uses axpy for setting off-processor entries, only ADD_VALUES is allowed */
10599566063dSJacob Faibussowitsch     PetscCall(MatSetValues(mat_elemental, 1, &row, ncols, cols, vals, ADD_VALUES));
10606214f412SHong Zhang     for (j = 0; j < ncols; j++) { /* lower triangular part */
1061eb1ec7c1SStefano Zampini       PetscScalar v;
10626214f412SHong Zhang       if (cols[j] == row) continue;
1063b94d7dedSBarry Smith       v = A->hermitian == PETSC_BOOL3_TRUE ? PetscConj(vals[j]) : vals[j];
10649566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mat_elemental, 1, &cols[j], 1, &row, &v, ADD_VALUES));
10656214f412SHong Zhang     }
10669566063dSJacob Faibussowitsch     PetscCall(MatRestoreRow(A, row, &ncols, &cols, &vals));
10676214f412SHong Zhang   }
10689566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowUpperTriangular(A));
10699566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat_elemental, MAT_FINAL_ASSEMBLY));
10709566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat_elemental, MAT_FINAL_ASSEMBLY));
10716214f412SHong Zhang 
1072511c6705SHong Zhang   if (reuse == MAT_INPLACE_MATRIX) {
10739566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &mat_elemental));
10746214f412SHong Zhang   } else {
10756214f412SHong Zhang     *newmat = mat_elemental;
10766214f412SHong Zhang   }
10776214f412SHong Zhang   PetscFunctionReturn(0);
10786214f412SHong Zhang }
10796214f412SHong Zhang 
1080d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_Elemental(Mat A)
1081d71ae5a4SJacob Faibussowitsch {
1082db31f6deSJed Brown   Mat_Elemental      *a = (Mat_Elemental *)A->data;
10835e9f5b67SHong Zhang   Mat_Elemental_Grid *commgrid;
10845e9f5b67SHong Zhang   PetscBool           flg;
10855e9f5b67SHong Zhang   MPI_Comm            icomm;
1086db31f6deSJed Brown 
1087db31f6deSJed Brown   PetscFunctionBegin;
1088db31f6deSJed Brown   delete a->emat;
1089ea394475SSatish Balay   delete a->P;
1090ea394475SSatish Balay   delete a->Q;
10915e9f5b67SHong Zhang 
1092e8146892SSatish Balay   El::mpi::Comm cxxcomm(PetscObjectComm((PetscObject)A));
10939566063dSJacob Faibussowitsch   PetscCall(PetscCommDuplicate(cxxcomm.comm, &icomm, NULL));
10949566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_get_attr(icomm, Petsc_Elemental_keyval, (void **)&commgrid, (int *)&flg));
10955e9f5b67SHong Zhang   if (--commgrid->grid_refct == 0) {
10965e9f5b67SHong Zhang     delete commgrid->grid;
10979566063dSJacob Faibussowitsch     PetscCall(PetscFree(commgrid));
10989566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_free_keyval(&Petsc_Elemental_keyval));
10995e9f5b67SHong Zhang   }
11009566063dSJacob Faibussowitsch   PetscCall(PetscCommDestroy(&icomm));
11019566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatGetOwnershipIS_C", NULL));
11029566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatFactorGetSolverType_C", NULL));
11039566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_elemental_mpidense_C", NULL));
11049566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->data));
1105db31f6deSJed Brown   PetscFunctionReturn(0);
1106db31f6deSJed Brown }
1107db31f6deSJed Brown 
1108d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSetUp_Elemental(Mat A)
1109d71ae5a4SJacob Faibussowitsch {
1110db31f6deSJed Brown   Mat_Elemental *a = (Mat_Elemental *)A->data;
1111f19600a0SHong Zhang   MPI_Comm       comm;
1112db31f6deSJed Brown   PetscMPIInt    rsize, csize;
1113f19600a0SHong Zhang   PetscInt       n;
1114db31f6deSJed Brown 
1115db31f6deSJed Brown   PetscFunctionBegin;
11169566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->rmap));
11179566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->cmap));
1118db31f6deSJed Brown 
1119d8304050SJose E. Roman   /* Check if local row and column sizes are equally distributed.
1120f19600a0SHong Zhang      Jed: Elemental uses "element" cyclic ordering so the sizes need to match that
1121f19600a0SHong Zhang      exactly.  The strategy in MatElemental is for PETSc to implicitly permute to block ordering (like would be returned by
1122d8304050SJose E. Roman      PetscSplitOwnership(comm,&n,&N), at which point Elemental matrices can act on PETSc vectors without redistributing the vectors. */
11239566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
1124f19600a0SHong Zhang   n = PETSC_DECIDE;
11259566063dSJacob Faibussowitsch   PetscCall(PetscSplitOwnership(comm, &n, &A->rmap->N));
11265f80ce2aSJacob 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);
1127f19600a0SHong Zhang 
1128f19600a0SHong Zhang   n = PETSC_DECIDE;
11299566063dSJacob Faibussowitsch   PetscCall(PetscSplitOwnership(comm, &n, &A->cmap->N));
11305f80ce2aSJacob 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);
1131f19600a0SHong Zhang 
11322f613bf5SBarry Smith   a->emat->Resize(A->rmap->N, A->cmap->N);
1133e8146892SSatish Balay   El::Zero(*a->emat);
1134db31f6deSJed Brown 
11359566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(A->rmap->comm, &rsize));
11369566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(A->cmap->comm, &csize));
11375f80ce2aSJacob Faibussowitsch   PetscCheck(csize == rsize, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Cannot use row and column communicators of different sizes");
1138db31f6deSJed Brown   a->commsize = rsize;
11399371c9d4SSatish Balay   a->mr[0]    = A->rmap->N % rsize;
11409371c9d4SSatish Balay   if (!a->mr[0]) a->mr[0] = rsize;
11419371c9d4SSatish Balay   a->mr[1] = A->cmap->N % csize;
11429371c9d4SSatish Balay   if (!a->mr[1]) a->mr[1] = csize;
1143db31f6deSJed Brown   a->m[0] = A->rmap->N / rsize + (a->mr[0] != rsize);
1144db31f6deSJed Brown   a->m[1] = A->cmap->N / csize + (a->mr[1] != csize);
1145db31f6deSJed Brown   PetscFunctionReturn(0);
1146db31f6deSJed Brown }
1147db31f6deSJed Brown 
1148*cedd07caSPierre Jolivet PetscErrorCode MatAssemblyBegin_Elemental(Mat A, MatAssemblyType)
1149d71ae5a4SJacob Faibussowitsch {
1150aae2c449SHong Zhang   Mat_Elemental *a = (Mat_Elemental *)A->data;
1151aae2c449SHong Zhang 
1152aae2c449SHong Zhang   PetscFunctionBegin;
1153fbbcb730SJack Poulson   /* printf("Calling ProcessQueues\n"); */
1154fbbcb730SJack Poulson   a->emat->ProcessQueues();
1155fbbcb730SJack Poulson   /* printf("Finished ProcessQueues\n"); */
1156aae2c449SHong Zhang   PetscFunctionReturn(0);
1157aae2c449SHong Zhang }
1158aae2c449SHong Zhang 
1159*cedd07caSPierre Jolivet PetscErrorCode MatAssemblyEnd_Elemental(Mat, MatAssemblyType)
1160d71ae5a4SJacob Faibussowitsch {
1161aae2c449SHong Zhang   PetscFunctionBegin;
1162aae2c449SHong Zhang   /* Currently does nothing */
1163aae2c449SHong Zhang   PetscFunctionReturn(0);
1164aae2c449SHong Zhang }
1165aae2c449SHong Zhang 
1166d71ae5a4SJacob Faibussowitsch PetscErrorCode MatLoad_Elemental(Mat newMat, PetscViewer viewer)
1167d71ae5a4SJacob Faibussowitsch {
11687b30e0f1SHong Zhang   Mat      Adense, Ae;
11697b30e0f1SHong Zhang   MPI_Comm comm;
11707b30e0f1SHong Zhang 
11717b30e0f1SHong Zhang   PetscFunctionBegin;
11729566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)newMat, &comm));
11739566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &Adense));
11749566063dSJacob Faibussowitsch   PetscCall(MatSetType(Adense, MATDENSE));
11759566063dSJacob Faibussowitsch   PetscCall(MatLoad(Adense, viewer));
11769566063dSJacob Faibussowitsch   PetscCall(MatConvert(Adense, MATELEMENTAL, MAT_INITIAL_MATRIX, &Ae));
11779566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Adense));
11789566063dSJacob Faibussowitsch   PetscCall(MatHeaderReplace(newMat, &Ae));
11797b30e0f1SHong Zhang   PetscFunctionReturn(0);
11807b30e0f1SHong Zhang }
11817b30e0f1SHong Zhang 
118240d92e34SHong Zhang /* -------------------------------------------------------------------*/
11839371c9d4SSatish Balay static struct _MatOps MatOps_Values = {MatSetValues_Elemental,
118440d92e34SHong Zhang                                        0,
118540d92e34SHong Zhang                                        0,
118640d92e34SHong Zhang                                        MatMult_Elemental,
118740d92e34SHong Zhang                                        /* 4*/ MatMultAdd_Elemental,
11889426833fSXuan Zhou                                        MatMultTranspose_Elemental,
1189e883f9d5SXuan Zhou                                        MatMultTransposeAdd_Elemental,
119040d92e34SHong Zhang                                        MatSolve_Elemental,
1191df311e6cSXuan Zhou                                        MatSolveAdd_Elemental,
11922ef15aa2SHong Zhang                                        0,
11932ef15aa2SHong Zhang                                        /*10*/ 0,
119440d92e34SHong Zhang                                        MatLUFactor_Elemental,
119540d92e34SHong Zhang                                        MatCholeskyFactor_Elemental,
119640d92e34SHong Zhang                                        0,
119740d92e34SHong Zhang                                        MatTranspose_Elemental,
119840d92e34SHong Zhang                                        /*15*/ MatGetInfo_Elemental,
119940d92e34SHong Zhang                                        0,
120061119200SXuan Zhou                                        MatGetDiagonal_Elemental,
1201ade3cc5eSXuan Zhou                                        MatDiagonalScale_Elemental,
120240d92e34SHong Zhang                                        MatNorm_Elemental,
120340d92e34SHong Zhang                                        /*20*/ MatAssemblyBegin_Elemental,
120440d92e34SHong Zhang                                        MatAssemblyEnd_Elemental,
120532d7a744SHong Zhang                                        MatSetOption_Elemental,
120640d92e34SHong Zhang                                        MatZeroEntries_Elemental,
120740d92e34SHong Zhang                                        /*24*/ 0,
120840d92e34SHong Zhang                                        MatLUFactorSymbolic_Elemental,
120940d92e34SHong Zhang                                        MatLUFactorNumeric_Elemental,
121040d92e34SHong Zhang                                        MatCholeskyFactorSymbolic_Elemental,
121140d92e34SHong Zhang                                        MatCholeskyFactorNumeric_Elemental,
121240d92e34SHong Zhang                                        /*29*/ MatSetUp_Elemental,
121340d92e34SHong Zhang                                        0,
121440d92e34SHong Zhang                                        0,
121540d92e34SHong Zhang                                        0,
121640d92e34SHong Zhang                                        0,
1217df311e6cSXuan Zhou                                        /*34*/ MatDuplicate_Elemental,
121840d92e34SHong Zhang                                        0,
121940d92e34SHong Zhang                                        0,
122040d92e34SHong Zhang                                        0,
122140d92e34SHong Zhang                                        0,
122240d92e34SHong Zhang                                        /*39*/ MatAXPY_Elemental,
122340d92e34SHong Zhang                                        0,
122440d92e34SHong Zhang                                        0,
122540d92e34SHong Zhang                                        0,
122640d92e34SHong Zhang                                        MatCopy_Elemental,
122740d92e34SHong Zhang                                        /*44*/ 0,
122840d92e34SHong Zhang                                        MatScale_Elemental,
12297d68702bSBarry Smith                                        MatShift_Basic,
123040d92e34SHong Zhang                                        0,
123140d92e34SHong Zhang                                        0,
123240d92e34SHong Zhang                                        /*49*/ 0,
123340d92e34SHong Zhang                                        0,
123440d92e34SHong Zhang                                        0,
123540d92e34SHong Zhang                                        0,
123640d92e34SHong Zhang                                        0,
123740d92e34SHong Zhang                                        /*54*/ 0,
123840d92e34SHong Zhang                                        0,
123940d92e34SHong Zhang                                        0,
124040d92e34SHong Zhang                                        0,
124140d92e34SHong Zhang                                        0,
124240d92e34SHong Zhang                                        /*59*/ 0,
124340d92e34SHong Zhang                                        MatDestroy_Elemental,
124440d92e34SHong Zhang                                        MatView_Elemental,
124540d92e34SHong Zhang                                        0,
124640d92e34SHong Zhang                                        0,
124740d92e34SHong Zhang                                        /*64*/ 0,
124840d92e34SHong Zhang                                        0,
124940d92e34SHong Zhang                                        0,
125040d92e34SHong Zhang                                        0,
125140d92e34SHong Zhang                                        0,
125240d92e34SHong Zhang                                        /*69*/ 0,
125340d92e34SHong Zhang                                        0,
12542ef0cf24SXuan Zhou                                        MatConvert_Elemental_Dense,
125540d92e34SHong Zhang                                        0,
125640d92e34SHong Zhang                                        0,
125740d92e34SHong Zhang                                        /*74*/ 0,
125840d92e34SHong Zhang                                        0,
125940d92e34SHong Zhang                                        0,
126040d92e34SHong Zhang                                        0,
126140d92e34SHong Zhang                                        0,
126240d92e34SHong Zhang                                        /*79*/ 0,
126340d92e34SHong Zhang                                        0,
126440d92e34SHong Zhang                                        0,
126540d92e34SHong Zhang                                        0,
12667b30e0f1SHong Zhang                                        MatLoad_Elemental,
126740d92e34SHong Zhang                                        /*84*/ 0,
126840d92e34SHong Zhang                                        0,
126940d92e34SHong Zhang                                        0,
127040d92e34SHong Zhang                                        0,
127140d92e34SHong Zhang                                        0,
12724222ddf1SHong Zhang                                        /*89*/ 0,
12734222ddf1SHong Zhang                                        0,
127440d92e34SHong Zhang                                        MatMatMultNumeric_Elemental,
127540d92e34SHong Zhang                                        0,
127640d92e34SHong Zhang                                        0,
127740d92e34SHong Zhang                                        /*94*/ 0,
12784222ddf1SHong Zhang                                        0,
12794222ddf1SHong Zhang                                        0,
1280df311e6cSXuan Zhou                                        MatMatTransposeMultNumeric_Elemental,
128140d92e34SHong Zhang                                        0,
12824222ddf1SHong Zhang                                        /*99*/ MatProductSetFromOptions_Elemental,
128340d92e34SHong Zhang                                        0,
128440d92e34SHong Zhang                                        0,
1285dfcb0403SXuan Zhou                                        MatConjugate_Elemental,
128640d92e34SHong Zhang                                        0,
128740d92e34SHong Zhang                                        /*104*/ 0,
128840d92e34SHong Zhang                                        0,
128940d92e34SHong Zhang                                        0,
129040d92e34SHong Zhang                                        0,
129140d92e34SHong Zhang                                        0,
129240d92e34SHong Zhang                                        /*109*/ MatMatSolve_Elemental,
129340d92e34SHong Zhang                                        0,
129440d92e34SHong Zhang                                        0,
129540d92e34SHong Zhang                                        0,
129634fa46e1SFrancesco Ballarin                                        MatMissingDiagonal_Elemental,
129740d92e34SHong Zhang                                        /*114*/ 0,
129840d92e34SHong Zhang                                        0,
129940d92e34SHong Zhang                                        0,
130040d92e34SHong Zhang                                        0,
130140d92e34SHong Zhang                                        0,
130240d92e34SHong Zhang                                        /*119*/ 0,
13034a29722dSXuan Zhou                                        MatHermitianTranspose_Elemental,
130440d92e34SHong Zhang                                        0,
130540d92e34SHong Zhang                                        0,
130640d92e34SHong Zhang                                        0,
130740d92e34SHong Zhang                                        /*124*/ 0,
130840d92e34SHong Zhang                                        0,
130940d92e34SHong Zhang                                        0,
131040d92e34SHong Zhang                                        0,
131140d92e34SHong Zhang                                        0,
131240d92e34SHong Zhang                                        /*129*/ 0,
131340d92e34SHong Zhang                                        0,
131440d92e34SHong Zhang                                        0,
131540d92e34SHong Zhang                                        0,
131640d92e34SHong Zhang                                        0,
131740d92e34SHong Zhang                                        /*134*/ 0,
131840d92e34SHong Zhang                                        0,
131940d92e34SHong Zhang                                        0,
132040d92e34SHong Zhang                                        0,
13214222ddf1SHong Zhang                                        0,
13224222ddf1SHong Zhang                                        0,
13234222ddf1SHong Zhang                                        /*140*/ 0,
13244222ddf1SHong Zhang                                        0,
13254222ddf1SHong Zhang                                        0,
13264222ddf1SHong Zhang                                        0,
13274222ddf1SHong Zhang                                        0,
13284222ddf1SHong Zhang                                        /*145*/ 0,
13294222ddf1SHong Zhang                                        0,
133099a7f59eSMark Adams                                        0,
133199a7f59eSMark Adams                                        0,
13327fb60732SBarry Smith                                        0,
1333ed6168d8SPierre Jolivet                                        /*150*/ 0,
1334ed6168d8SPierre Jolivet                                        0};
133540d92e34SHong Zhang 
1336ed36708cSHong Zhang /*MC
1337ed36708cSHong Zhang    MATELEMENTAL = "elemental" - A matrix type for dense matrices using the Elemental package
1338ed36708cSHong Zhang 
1339c2b89b5dSBarry Smith   Use ./configure --download-elemental to install PETSc to use Elemental
1340c2b89b5dSBarry Smith 
1341ed36708cSHong Zhang    Options Database Keys:
13425cc86fc1SJed Brown + -mat_type elemental - sets the matrix type to "elemental" during a call to MatSetFromOptions()
134389bba20eSBarry Smith . -pc_factor_mat_solver_type elemental - to use this direct solver with the option -pc_type lu
13445cc86fc1SJed Brown - -mat_elemental_grid_height - sets Grid Height for 2D cyclic ordering of internal matrix
1345ed36708cSHong Zhang 
1346ed36708cSHong Zhang   Level: beginner
1347ed36708cSHong Zhang 
134889bba20eSBarry Smith   Note:
134989bba20eSBarry Smith    Note unlike most matrix formats, this format does not store all the matrix entries for a contiguous
135089bba20eSBarry Smith    range of rows on an MPI rank. Use `MatGetOwnershipIS()` to determine what values are stored on
135189bba20eSBarry Smith    the given rank.
135289bba20eSBarry Smith 
135389bba20eSBarry Smith .seealso: `MATDENSE`, `MATSCALAPACK`, `MatGetOwnershipIS()`
1354ed36708cSHong Zhang M*/
13554a29722dSXuan Zhou 
1356d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_Elemental(Mat A)
1357d71ae5a4SJacob Faibussowitsch {
1358db31f6deSJed Brown   Mat_Elemental      *a;
13595682a260SJack Poulson   PetscBool           flg, flg1;
13605e9f5b67SHong Zhang   Mat_Elemental_Grid *commgrid;
13615e9f5b67SHong Zhang   MPI_Comm            icomm;
13625682a260SJack Poulson   PetscInt            optv1;
1363db31f6deSJed Brown 
1364db31f6deSJed Brown   PetscFunctionBegin;
13659566063dSJacob Faibussowitsch   PetscCall(PetscMemcpy(A->ops, &MatOps_Values, sizeof(struct _MatOps)));
136640d92e34SHong Zhang   A->insertmode = NOT_SET_VALUES;
1367db31f6deSJed Brown 
13684dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&a));
1369db31f6deSJed Brown   A->data = (void *)a;
1370db31f6deSJed Brown 
1371db31f6deSJed Brown   /* Set up the elemental matrix */
1372e8146892SSatish Balay   El::mpi::Comm cxxcomm(PetscObjectComm((PetscObject)A));
13735e9f5b67SHong Zhang 
13745e9f5b67SHong Zhang   /* Grid needs to be shared between multiple Mats on the same communicator, implement by attribute caching on the MPI_Comm */
13755e9f5b67SHong Zhang   if (Petsc_Elemental_keyval == MPI_KEYVAL_INVALID) {
13769566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Elemental_keyval, (void *)0));
13779566063dSJacob Faibussowitsch     PetscCall(PetscCitationsRegister(ElementalCitation, &ElementalCite));
13785e9f5b67SHong Zhang   }
13799566063dSJacob Faibussowitsch   PetscCall(PetscCommDuplicate(cxxcomm.comm, &icomm, NULL));
13809566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_get_attr(icomm, Petsc_Elemental_keyval, (void **)&commgrid, (int *)&flg));
13815e9f5b67SHong Zhang   if (!flg) {
13824dfa11a4SJacob Faibussowitsch     PetscCall(PetscNew(&commgrid));
13835cb544a0SHong Zhang 
1384d0609cedSBarry Smith     PetscOptionsBegin(PetscObjectComm((PetscObject)A), ((PetscObject)A)->prefix, "Elemental Options", "Mat");
1385e8146892SSatish Balay     /* displayed default grid sizes (CommSize,1) are set by us arbitrarily until El::Grid() is called */
13869566063dSJacob Faibussowitsch     PetscCall(PetscOptionsInt("-mat_elemental_grid_height", "Grid Height", "None", El::mpi::Size(cxxcomm), &optv1, &flg1));
13875682a260SJack Poulson     if (flg1) {
1388aed4548fSBarry 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));
1389e8146892SSatish Balay       commgrid->grid = new El::Grid(cxxcomm, optv1); /* use user-provided grid height */
13902ef0cf24SXuan Zhou     } else {
1391e8146892SSatish Balay       commgrid->grid = new El::Grid(cxxcomm); /* use Elemental default grid sizes */
1392da0640a4SHong Zhang       /* printf("new commgrid->grid = %p\n",commgrid->grid);  -- memory leak revealed by valgrind? */
1393ed667823SXuan Zhou     }
13945e9f5b67SHong Zhang     commgrid->grid_refct = 1;
13959566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_set_attr(icomm, Petsc_Elemental_keyval, (void *)commgrid));
1396ea394475SSatish Balay 
1397ea394475SSatish Balay     a->pivoting = 1;
13989566063dSJacob Faibussowitsch     PetscCall(PetscOptionsInt("-mat_elemental_pivoting", "Pivoting", "None", a->pivoting, &a->pivoting, NULL));
1399ea394475SSatish Balay 
1400d0609cedSBarry Smith     PetscOptionsEnd();
14015e9f5b67SHong Zhang   } else {
14025e9f5b67SHong Zhang     commgrid->grid_refct++;
14035e9f5b67SHong Zhang   }
14049566063dSJacob Faibussowitsch   PetscCall(PetscCommDestroy(&icomm));
14055e9f5b67SHong Zhang   a->grid        = commgrid->grid;
1406e8146892SSatish Balay   a->emat        = new El::DistMatrix<PetscElemScalar>(*a->grid);
140732d7a744SHong Zhang   a->roworiented = PETSC_TRUE;
1408db31f6deSJed Brown 
14099566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatGetOwnershipIS_C", MatGetOwnershipIS_Elemental));
14109566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_elemental_mpidense_C", MatProductSetFromOptions_Elemental_MPIDense));
14119566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATELEMENTAL));
1412db31f6deSJed Brown   PetscFunctionReturn(0);
1413db31f6deSJed Brown }
1414