xref: /petsc/src/mat/impls/elemental/matelem.cxx (revision 2065540a855ff9f9c49aa4d22d544ff2b07d8a79)
1 #include <petsc/private/petscelemental.h>
2 
3 const char ElementalCitation[] = "@Article{Elemental2012,\n"
4 "  author  = {Jack Poulson and Bryan Marker and Jeff R. Hammond and Nichols A. Romero and Robert {v}an~{d}e~{G}eijn},\n"
5 "  title   = {Elemental: A New Framework for Distributed Memory Dense Matrix Computations},\n"
6 "  journal = {{ACM} Transactions on Mathematical Software},\n"
7 "  volume  = {39},\n"
8 "  number  = {2},\n"
9 "  year    = {2013}\n"
10 "}\n";
11 static PetscBool ElementalCite = PETSC_FALSE;
12 
13 /*
14     The variable Petsc_Elemental_keyval is used to indicate an MPI attribute that
15   is attached to a communicator, in this case the attribute is a Mat_Elemental_Grid
16 */
17 static PetscMPIInt Petsc_Elemental_keyval = MPI_KEYVAL_INVALID;
18 
19 static PetscErrorCode MatView_Elemental(Mat A,PetscViewer viewer)
20 {
21   PetscErrorCode ierr;
22   Mat_Elemental  *a = (Mat_Elemental*)A->data;
23   PetscBool      iascii;
24 
25   PetscFunctionBegin;
26   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
27   if (iascii) {
28     PetscViewerFormat format;
29     ierr = PetscViewerGetFormat(viewer,&format);CHKERRQ(ierr);
30     if (format == PETSC_VIEWER_ASCII_INFO) {
31       /* call elemental viewing function */
32       ierr = PetscViewerASCIIPrintf(viewer,"Elemental run parameters:\n");CHKERRQ(ierr);
33       ierr = PetscViewerASCIIPrintf(viewer,"  allocated entries=%d\n",(*a->emat).AllocatedMemory());CHKERRQ(ierr);
34       ierr = PetscViewerASCIIPrintf(viewer,"  grid height=%d, grid width=%d\n",(*a->emat).Grid().Height(),(*a->emat).Grid().Width());CHKERRQ(ierr);
35       if (format == PETSC_VIEWER_ASCII_FACTOR_INFO) {
36         /* call elemental viewing function */
37         ierr = PetscPrintf(PetscObjectComm((PetscObject)viewer),"test matview_elemental 2\n");CHKERRQ(ierr);
38       }
39 
40     } else if (format == PETSC_VIEWER_DEFAULT) {
41       ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr);
42       El::Print( *a->emat, "Elemental matrix (cyclic ordering)");
43       ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr);
44       if (A->factortype == MAT_FACTOR_NONE){
45         Mat Adense;
46         ierr = MatConvert(A,MATDENSE,MAT_INITIAL_MATRIX,&Adense);CHKERRQ(ierr);
47         ierr = MatView(Adense,viewer);CHKERRQ(ierr);
48         ierr = MatDestroy(&Adense);CHKERRQ(ierr);
49       }
50     } else SETERRQ(PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"Format");
51   } else {
52     /* convert to dense format and call MatView() */
53     Mat Adense;
54     ierr = MatConvert(A,MATDENSE,MAT_INITIAL_MATRIX,&Adense);CHKERRQ(ierr);
55     ierr = MatView(Adense,viewer);CHKERRQ(ierr);
56     ierr = MatDestroy(&Adense);CHKERRQ(ierr);
57   }
58   PetscFunctionReturn(0);
59 }
60 
61 static PetscErrorCode MatGetInfo_Elemental(Mat A,MatInfoType flag,MatInfo *info)
62 {
63   Mat_Elemental  *a = (Mat_Elemental*)A->data;
64 
65   PetscFunctionBegin;
66   info->block_size = 1.0;
67 
68   if (flag == MAT_LOCAL) {
69     info->nz_allocated   = (*a->emat).AllocatedMemory(); /* locally allocated */
70     info->nz_used        = info->nz_allocated;
71   } else if (flag == MAT_GLOBAL_MAX) {
72     //ierr = MPIU_Allreduce(isend,irecv,5,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)matin));CHKERRMPI(ierr);
73     /* see MatGetInfo_MPIAIJ() for getting global info->nz_allocated! */
74     //SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP," MAT_GLOBAL_MAX not written yet");
75   } else if (flag == MAT_GLOBAL_SUM) {
76     //SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP," MAT_GLOBAL_SUM not written yet");
77     info->nz_allocated   = (*a->emat).AllocatedMemory(); /* locally allocated */
78     info->nz_used        = info->nz_allocated; /* assume Elemental does accurate allocation */
79     //ierr = MPIU_Allreduce(isend,irecv,1,MPIU_REAL,MPIU_SUM,PetscObjectComm((PetscObject)A));CHKERRMPI(ierr);
80     //PetscPrintf(PETSC_COMM_SELF,"    ... [%d] locally allocated %g\n",rank,info->nz_allocated);
81   }
82 
83   info->nz_unneeded       = 0.0;
84   info->assemblies        = A->num_ass;
85   info->mallocs           = 0;
86   info->memory            = ((PetscObject)A)->mem;
87   info->fill_ratio_given  = 0; /* determined by Elemental */
88   info->fill_ratio_needed = 0;
89   info->factor_mallocs    = 0;
90   PetscFunctionReturn(0);
91 }
92 
93 PetscErrorCode MatSetOption_Elemental(Mat A,MatOption op,PetscBool flg)
94 {
95   Mat_Elemental  *a = (Mat_Elemental*)A->data;
96 
97   PetscFunctionBegin;
98   switch (op) {
99   case MAT_NEW_NONZERO_LOCATIONS:
100   case MAT_NEW_NONZERO_LOCATION_ERR:
101   case MAT_NEW_NONZERO_ALLOCATION_ERR:
102   case MAT_SYMMETRIC:
103   case MAT_SORTED_FULL:
104   case MAT_HERMITIAN:
105     break;
106   case MAT_ROW_ORIENTED:
107     a->roworiented = flg;
108     break;
109   default:
110     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"unknown option %s",MatOptions[op]);
111   }
112   PetscFunctionReturn(0);
113 }
114 
115 static PetscErrorCode MatSetValues_Elemental(Mat A,PetscInt nr,const PetscInt *rows,PetscInt nc,const PetscInt *cols,const PetscScalar *vals,InsertMode imode)
116 {
117   Mat_Elemental  *a = (Mat_Elemental*)A->data;
118   PetscInt       i,j,rrank,ridx,crank,cidx,erow,ecol,numQueues=0;
119 
120   PetscFunctionBegin;
121   // TODO: Initialize matrix to all zeros?
122 
123   // Count the number of queues from this process
124   if (a->roworiented) {
125     for (i=0; i<nr; i++) {
126       if (rows[i] < 0) continue;
127       P2RO(A,0,rows[i],&rrank,&ridx);
128       RO2E(A,0,rrank,ridx,&erow);
129       if (rrank < 0 || ridx < 0 || erow < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Incorrect row translation");
130       for (j=0; j<nc; j++) {
131         if (cols[j] < 0) continue;
132         P2RO(A,1,cols[j],&crank,&cidx);
133         RO2E(A,1,crank,cidx,&ecol);
134         if (crank < 0 || cidx < 0 || ecol < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Incorrect col translation");
135         if (!a->emat->IsLocal(erow,ecol)){ /* off-proc entry */
136           /* printf("Will later remotely update (%d,%d)\n",erow,ecol); */
137           if (imode != ADD_VALUES) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Only ADD_VALUES to off-processor entry is supported");
138           ++numQueues;
139           continue;
140         }
141         /* printf("Locally updating (%d,%d)\n",erow,ecol); */
142         switch (imode) {
143         case INSERT_VALUES: a->emat->Set(erow,ecol,(PetscElemScalar)vals[i*nc+j]); break;
144         case ADD_VALUES: a->emat->Update(erow,ecol,(PetscElemScalar)vals[i*nc+j]); break;
145         default: SETERRQ1(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"No support for InsertMode %d",(int)imode);
146         }
147       }
148     }
149 
150     /* printf("numQueues=%d\n",numQueues); */
151     a->emat->Reserve( numQueues);
152     for (i=0; i<nr; i++) {
153       if (rows[i] < 0) continue;
154       P2RO(A,0,rows[i],&rrank,&ridx);
155       RO2E(A,0,rrank,ridx,&erow);
156       for (j=0; j<nc; j++) {
157         if (cols[j] < 0) continue;
158         P2RO(A,1,cols[j],&crank,&cidx);
159         RO2E(A,1,crank,cidx,&ecol);
160         if (!a->emat->IsLocal(erow,ecol)) { /*off-proc entry*/
161           /* printf("Queueing remotely update of (%d,%d)\n",erow,ecol); */
162           a->emat->QueueUpdate( erow, ecol, vals[i*nc+j]);
163         }
164       }
165     }
166   } else { /* columnoriented */
167     for (j=0; j<nc; j++) {
168       if (cols[j] < 0) continue;
169       P2RO(A,1,cols[j],&crank,&cidx);
170       RO2E(A,1,crank,cidx,&ecol);
171       if (crank < 0 || cidx < 0 || ecol < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Incorrect col translation");
172       for (i=0; i<nr; i++) {
173         if (rows[i] < 0) continue;
174         P2RO(A,0,rows[i],&rrank,&ridx);
175         RO2E(A,0,rrank,ridx,&erow);
176         if (rrank < 0 || ridx < 0 || erow < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Incorrect row translation");
177         if (!a->emat->IsLocal(erow,ecol)){ /* off-proc entry */
178           /* printf("Will later remotely update (%d,%d)\n",erow,ecol); */
179           if (imode != ADD_VALUES) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Only ADD_VALUES to off-processor entry is supported");
180           ++numQueues;
181           continue;
182         }
183         /* printf("Locally updating (%d,%d)\n",erow,ecol); */
184         switch (imode) {
185         case INSERT_VALUES: a->emat->Set(erow,ecol,(PetscElemScalar)vals[i+j*nr]); break;
186         case ADD_VALUES: a->emat->Update(erow,ecol,(PetscElemScalar)vals[i+j*nr]); break;
187         default: SETERRQ1(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"No support for InsertMode %d",(int)imode);
188         }
189       }
190     }
191 
192     /* printf("numQueues=%d\n",numQueues); */
193     a->emat->Reserve( numQueues);
194     for (j=0; j<nc; j++) {
195       if (cols[j] < 0) continue;
196       P2RO(A,1,cols[j],&crank,&cidx);
197       RO2E(A,1,crank,cidx,&ecol);
198 
199       for (i=0; i<nr; i++) {
200         if (rows[i] < 0) continue;
201         P2RO(A,0,rows[i],&rrank,&ridx);
202         RO2E(A,0,rrank,ridx,&erow);
203         if (!a->emat->IsLocal(erow,ecol)) { /*off-proc entry*/
204           /* printf("Queueing remotely update of (%d,%d)\n",erow,ecol); */
205           a->emat->QueueUpdate( erow, ecol, vals[i+j*nr]);
206         }
207       }
208     }
209   }
210   PetscFunctionReturn(0);
211 }
212 
213 static PetscErrorCode MatMult_Elemental(Mat A,Vec X,Vec Y)
214 {
215   Mat_Elemental         *a = (Mat_Elemental*)A->data;
216   PetscErrorCode        ierr;
217   const PetscElemScalar *x;
218   PetscElemScalar       *y;
219   PetscElemScalar       one = 1,zero = 0;
220 
221   PetscFunctionBegin;
222   ierr = VecGetArrayRead(X,(const PetscScalar **)&x);CHKERRQ(ierr);
223   ierr = VecGetArray(Y,(PetscScalar **)&y);CHKERRQ(ierr);
224   { /* Scoping so that constructor is called before pointer is returned */
225     El::DistMatrix<PetscElemScalar,El::VC,El::STAR> xe, ye;
226     xe.LockedAttach(A->cmap->N,1,*a->grid,0,0,x,A->cmap->n);
227     ye.Attach(A->rmap->N,1,*a->grid,0,0,y,A->rmap->n);
228     El::Gemv(El::NORMAL,one,*a->emat,xe,zero,ye);
229   }
230   ierr = VecRestoreArrayRead(X,(const PetscScalar **)&x);CHKERRQ(ierr);
231   ierr = VecRestoreArray(Y,(PetscScalar **)&y);CHKERRQ(ierr);
232   PetscFunctionReturn(0);
233 }
234 
235 static PetscErrorCode MatMultTranspose_Elemental(Mat A,Vec X,Vec Y)
236 {
237   Mat_Elemental         *a = (Mat_Elemental*)A->data;
238   PetscErrorCode        ierr;
239   const PetscElemScalar *x;
240   PetscElemScalar       *y;
241   PetscElemScalar       one = 1,zero = 0;
242 
243   PetscFunctionBegin;
244   ierr = VecGetArrayRead(X,(const PetscScalar **)&x);CHKERRQ(ierr);
245   ierr = VecGetArray(Y,(PetscScalar **)&y);CHKERRQ(ierr);
246   { /* Scoping so that constructor is called before pointer is returned */
247     El::DistMatrix<PetscElemScalar,El::VC,El::STAR> xe, ye;
248     xe.LockedAttach(A->rmap->N,1,*a->grid,0,0,x,A->rmap->n);
249     ye.Attach(A->cmap->N,1,*a->grid,0,0,y,A->cmap->n);
250     El::Gemv(El::TRANSPOSE,one,*a->emat,xe,zero,ye);
251   }
252   ierr = VecRestoreArrayRead(X,(const PetscScalar **)&x);CHKERRQ(ierr);
253   ierr = VecRestoreArray(Y,(PetscScalar **)&y);CHKERRQ(ierr);
254   PetscFunctionReturn(0);
255 }
256 
257 static PetscErrorCode MatMultAdd_Elemental(Mat A,Vec X,Vec Y,Vec Z)
258 {
259   Mat_Elemental         *a = (Mat_Elemental*)A->data;
260   PetscErrorCode        ierr;
261   const PetscElemScalar *x;
262   PetscElemScalar       *z;
263   PetscElemScalar       one = 1;
264 
265   PetscFunctionBegin;
266   if (Y != Z) {ierr = VecCopy(Y,Z);CHKERRQ(ierr);}
267   ierr = VecGetArrayRead(X,(const PetscScalar **)&x);CHKERRQ(ierr);
268   ierr = VecGetArray(Z,(PetscScalar **)&z);CHKERRQ(ierr);
269   { /* Scoping so that constructor is called before pointer is returned */
270     El::DistMatrix<PetscElemScalar,El::VC,El::STAR> xe, ze;
271     xe.LockedAttach(A->cmap->N,1,*a->grid,0,0,x,A->cmap->n);
272     ze.Attach(A->rmap->N,1,*a->grid,0,0,z,A->rmap->n);
273     El::Gemv(El::NORMAL,one,*a->emat,xe,one,ze);
274   }
275   ierr = VecRestoreArrayRead(X,(const PetscScalar **)&x);CHKERRQ(ierr);
276   ierr = VecRestoreArray(Z,(PetscScalar **)&z);CHKERRQ(ierr);
277   PetscFunctionReturn(0);
278 }
279 
280 static PetscErrorCode MatMultTransposeAdd_Elemental(Mat A,Vec X,Vec Y,Vec Z)
281 {
282   Mat_Elemental         *a = (Mat_Elemental*)A->data;
283   PetscErrorCode        ierr;
284   const PetscElemScalar *x;
285   PetscElemScalar       *z;
286   PetscElemScalar       one = 1;
287 
288   PetscFunctionBegin;
289   if (Y != Z) {ierr = VecCopy(Y,Z);CHKERRQ(ierr);}
290   ierr = VecGetArrayRead(X,(const PetscScalar **)&x);CHKERRQ(ierr);
291   ierr = VecGetArray(Z,(PetscScalar **)&z);CHKERRQ(ierr);
292   { /* Scoping so that constructor is called before pointer is returned */
293     El::DistMatrix<PetscElemScalar,El::VC,El::STAR> xe, ze;
294     xe.LockedAttach(A->rmap->N,1,*a->grid,0,0,x,A->rmap->n);
295     ze.Attach(A->cmap->N,1,*a->grid,0,0,z,A->cmap->n);
296     El::Gemv(El::TRANSPOSE,one,*a->emat,xe,one,ze);
297   }
298   ierr = VecRestoreArrayRead(X,(const PetscScalar **)&x);CHKERRQ(ierr);
299   ierr = VecRestoreArray(Z,(PetscScalar **)&z);CHKERRQ(ierr);
300   PetscFunctionReturn(0);
301 }
302 
303 PetscErrorCode MatMatMultNumeric_Elemental(Mat A,Mat B,Mat C)
304 {
305   Mat_Elemental    *a = (Mat_Elemental*)A->data;
306   Mat_Elemental    *b = (Mat_Elemental*)B->data;
307   Mat_Elemental    *c = (Mat_Elemental*)C->data;
308   PetscElemScalar  one = 1,zero = 0;
309 
310   PetscFunctionBegin;
311   { /* Scoping so that constructor is called before pointer is returned */
312     El::Gemm(El::NORMAL,El::NORMAL,one,*a->emat,*b->emat,zero,*c->emat);
313   }
314   C->assembled = PETSC_TRUE;
315   PetscFunctionReturn(0);
316 }
317 
318 PetscErrorCode MatMatMultSymbolic_Elemental(Mat A,Mat B,PetscReal fill,Mat Ce)
319 {
320   PetscErrorCode ierr;
321 
322   PetscFunctionBegin;
323   ierr = MatSetSizes(Ce,A->rmap->n,B->cmap->n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
324   ierr = MatSetType(Ce,MATELEMENTAL);CHKERRQ(ierr);
325   ierr = MatSetUp(Ce);CHKERRQ(ierr);
326   Ce->ops->matmultnumeric = MatMatMultNumeric_Elemental;
327   PetscFunctionReturn(0);
328 }
329 
330 static PetscErrorCode MatMatTransposeMultNumeric_Elemental(Mat A,Mat B,Mat C)
331 {
332   Mat_Elemental      *a = (Mat_Elemental*)A->data;
333   Mat_Elemental      *b = (Mat_Elemental*)B->data;
334   Mat_Elemental      *c = (Mat_Elemental*)C->data;
335   PetscElemScalar    one = 1,zero = 0;
336 
337   PetscFunctionBegin;
338   { /* Scoping so that constructor is called before pointer is returned */
339     El::Gemm(El::NORMAL,El::TRANSPOSE,one,*a->emat,*b->emat,zero,*c->emat);
340   }
341   C->assembled = PETSC_TRUE;
342   PetscFunctionReturn(0);
343 }
344 
345 static PetscErrorCode MatMatTransposeMultSymbolic_Elemental(Mat A,Mat B,PetscReal fill,Mat C)
346 {
347   PetscErrorCode ierr;
348 
349   PetscFunctionBegin;
350   ierr = MatSetSizes(C,A->rmap->n,B->rmap->n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
351   ierr = MatSetType(C,MATELEMENTAL);CHKERRQ(ierr);
352   ierr = MatSetUp(C);CHKERRQ(ierr);
353   PetscFunctionReturn(0);
354 }
355 
356 /* --------------------------------------- */
357 static PetscErrorCode MatProductSetFromOptions_Elemental_AB(Mat C)
358 {
359   PetscFunctionBegin;
360   C->ops->matmultsymbolic = MatMatMultSymbolic_Elemental;
361   C->ops->productsymbolic = MatProductSymbolic_AB;
362   PetscFunctionReturn(0);
363 }
364 
365 static PetscErrorCode MatProductSetFromOptions_Elemental_ABt(Mat C)
366 {
367   PetscFunctionBegin;
368   C->ops->mattransposemultsymbolic = MatMatTransposeMultSymbolic_Elemental;
369   C->ops->productsymbolic          = MatProductSymbolic_ABt;
370   PetscFunctionReturn(0);
371 }
372 
373 PETSC_INTERN PetscErrorCode MatProductSetFromOptions_Elemental(Mat C)
374 {
375   PetscErrorCode ierr;
376   Mat_Product    *product = C->product;
377 
378   PetscFunctionBegin;
379   switch (product->type) {
380   case MATPRODUCT_AB:
381     ierr = MatProductSetFromOptions_Elemental_AB(C);CHKERRQ(ierr);
382     break;
383   case MATPRODUCT_ABt:
384     ierr = MatProductSetFromOptions_Elemental_ABt(C);CHKERRQ(ierr);
385     break;
386   default:
387     break;
388   }
389   PetscFunctionReturn(0);
390 }
391 
392 PetscErrorCode MatMatMultNumeric_Elemental_MPIDense(Mat A,Mat B,Mat C)
393 {
394   Mat            Be,Ce;
395   PetscErrorCode ierr;
396 
397   PetscFunctionBegin;
398   ierr = MatConvert(B,MATELEMENTAL,MAT_INITIAL_MATRIX,&Be);CHKERRQ(ierr);
399   ierr = MatMatMult(A,Be,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&Ce);CHKERRQ(ierr);
400   ierr = MatConvert(Ce,MATMPIDENSE,MAT_REUSE_MATRIX,&C);CHKERRQ(ierr);
401   ierr = MatDestroy(&Be);CHKERRQ(ierr);
402   ierr = MatDestroy(&Ce);CHKERRQ(ierr);
403   PetscFunctionReturn(0);
404 }
405 
406 PetscErrorCode MatMatMultSymbolic_Elemental_MPIDense(Mat A,Mat B,PetscReal fill,Mat C)
407 {
408   PetscErrorCode ierr;
409 
410   PetscFunctionBegin;
411   ierr = MatSetSizes(C,A->rmap->n,B->cmap->n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
412   ierr = MatSetType(C,MATMPIDENSE);CHKERRQ(ierr);
413   ierr = MatSetUp(C);CHKERRQ(ierr);
414   C->ops->matmultnumeric = MatMatMultNumeric_Elemental_MPIDense;
415   PetscFunctionReturn(0);
416 }
417 
418 PetscErrorCode MatProductSetFromOptions_Elemental_MPIDense_AB(Mat C)
419 {
420   PetscFunctionBegin;
421   C->ops->matmultsymbolic = MatMatMultSymbolic_Elemental_MPIDense;
422   C->ops->productsymbolic = MatProductSymbolic_AB;
423   PetscFunctionReturn(0);
424 }
425 
426 PetscErrorCode MatProductSetFromOptions_Elemental_MPIDense(Mat C)
427 {
428   PetscErrorCode ierr;
429   Mat_Product    *product = C->product;
430 
431   PetscFunctionBegin;
432   if (product->type == MATPRODUCT_AB) {
433     ierr = MatProductSetFromOptions_Elemental_MPIDense_AB(C);CHKERRQ(ierr);
434   }
435   PetscFunctionReturn(0);
436 }
437 /* --------------------------------------- */
438 
439 static PetscErrorCode MatGetDiagonal_Elemental(Mat A,Vec D)
440 {
441   PetscInt        i,nrows,ncols,nD,rrank,ridx,crank,cidx;
442   Mat_Elemental   *a = (Mat_Elemental*)A->data;
443   PetscErrorCode  ierr;
444   PetscElemScalar v;
445   MPI_Comm        comm;
446 
447   PetscFunctionBegin;
448   ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr);
449   ierr = MatGetSize(A,&nrows,&ncols);CHKERRQ(ierr);
450   nD = nrows>ncols ? ncols : nrows;
451   for (i=0; i<nD; i++) {
452     PetscInt erow,ecol;
453     P2RO(A,0,i,&rrank,&ridx);
454     RO2E(A,0,rrank,ridx,&erow);
455     if (rrank < 0 || ridx < 0 || erow < 0) SETERRQ(comm,PETSC_ERR_PLIB,"Incorrect row translation");
456     P2RO(A,1,i,&crank,&cidx);
457     RO2E(A,1,crank,cidx,&ecol);
458     if (crank < 0 || cidx < 0 || ecol < 0) SETERRQ(comm,PETSC_ERR_PLIB,"Incorrect col translation");
459     v = a->emat->Get(erow,ecol);
460     ierr = VecSetValues(D,1,&i,(PetscScalar*)&v,INSERT_VALUES);CHKERRQ(ierr);
461   }
462   ierr = VecAssemblyBegin(D);CHKERRQ(ierr);
463   ierr = VecAssemblyEnd(D);CHKERRQ(ierr);
464   PetscFunctionReturn(0);
465 }
466 
467 static PetscErrorCode MatDiagonalScale_Elemental(Mat X,Vec L,Vec R)
468 {
469   Mat_Elemental         *x = (Mat_Elemental*)X->data;
470   const PetscElemScalar *d;
471   PetscErrorCode        ierr;
472 
473   PetscFunctionBegin;
474   if (R) {
475     ierr = VecGetArrayRead(R,(const PetscScalar **)&d);CHKERRQ(ierr);
476     El::DistMatrix<PetscElemScalar,El::VC,El::STAR> de;
477     de.LockedAttach(X->cmap->N,1,*x->grid,0,0,d,X->cmap->n);
478     El::DiagonalScale(El::RIGHT,El::NORMAL,de,*x->emat);
479     ierr = VecRestoreArrayRead(R,(const PetscScalar **)&d);CHKERRQ(ierr);
480   }
481   if (L) {
482     ierr = VecGetArrayRead(L,(const PetscScalar **)&d);CHKERRQ(ierr);
483     El::DistMatrix<PetscElemScalar,El::VC,El::STAR> de;
484     de.LockedAttach(X->rmap->N,1,*x->grid,0,0,d,X->rmap->n);
485     El::DiagonalScale(El::LEFT,El::NORMAL,de,*x->emat);
486     ierr = VecRestoreArrayRead(L,(const PetscScalar **)&d);CHKERRQ(ierr);
487   }
488   PetscFunctionReturn(0);
489 }
490 
491 static PetscErrorCode MatMissingDiagonal_Elemental(Mat A,PetscBool *missing,PetscInt *d)
492 {
493   PetscFunctionBegin;
494   *missing = PETSC_FALSE;
495   PetscFunctionReturn(0);
496 }
497 
498 static PetscErrorCode MatScale_Elemental(Mat X,PetscScalar a)
499 {
500   Mat_Elemental  *x = (Mat_Elemental*)X->data;
501 
502   PetscFunctionBegin;
503   El::Scale((PetscElemScalar)a,*x->emat);
504   PetscFunctionReturn(0);
505 }
506 
507 /*
508   MatAXPY - Computes Y = a*X + Y.
509 */
510 static PetscErrorCode MatAXPY_Elemental(Mat Y,PetscScalar a,Mat X,MatStructure str)
511 {
512   Mat_Elemental  *x = (Mat_Elemental*)X->data;
513   Mat_Elemental  *y = (Mat_Elemental*)Y->data;
514   PetscErrorCode ierr;
515 
516   PetscFunctionBegin;
517   El::Axpy((PetscElemScalar)a,*x->emat,*y->emat);
518   ierr = PetscObjectStateIncrease((PetscObject)Y);CHKERRQ(ierr);
519   PetscFunctionReturn(0);
520 }
521 
522 static PetscErrorCode MatCopy_Elemental(Mat A,Mat B,MatStructure str)
523 {
524   Mat_Elemental *a=(Mat_Elemental*)A->data;
525   Mat_Elemental *b=(Mat_Elemental*)B->data;
526   PetscErrorCode ierr;
527 
528   PetscFunctionBegin;
529   El::Copy(*a->emat,*b->emat);
530   ierr = PetscObjectStateIncrease((PetscObject)B);CHKERRQ(ierr);
531   PetscFunctionReturn(0);
532 }
533 
534 static PetscErrorCode MatDuplicate_Elemental(Mat A,MatDuplicateOption op,Mat *B)
535 {
536   Mat            Be;
537   MPI_Comm       comm;
538   Mat_Elemental  *a=(Mat_Elemental*)A->data;
539   PetscErrorCode ierr;
540 
541   PetscFunctionBegin;
542   ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr);
543   ierr = MatCreate(comm,&Be);CHKERRQ(ierr);
544   ierr = MatSetSizes(Be,A->rmap->n,A->cmap->n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
545   ierr = MatSetType(Be,MATELEMENTAL);CHKERRQ(ierr);
546   ierr = MatSetUp(Be);CHKERRQ(ierr);
547   *B = Be;
548   if (op == MAT_COPY_VALUES) {
549     Mat_Elemental *b=(Mat_Elemental*)Be->data;
550     El::Copy(*a->emat,*b->emat);
551   }
552   Be->assembled = PETSC_TRUE;
553   PetscFunctionReturn(0);
554 }
555 
556 static PetscErrorCode MatTranspose_Elemental(Mat A,MatReuse reuse,Mat *B)
557 {
558   Mat            Be = *B;
559   PetscErrorCode ierr;
560   MPI_Comm       comm;
561   Mat_Elemental  *a = (Mat_Elemental*)A->data, *b;
562 
563   PetscFunctionBegin;
564   ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr);
565   /* Only out-of-place supported */
566   if (reuse == MAT_INPLACE_MATRIX) SETERRQ(comm,PETSC_ERR_SUP,"Only out-of-place supported");
567   if (reuse == MAT_INITIAL_MATRIX) {
568     ierr = MatCreate(comm,&Be);CHKERRQ(ierr);
569     ierr = MatSetSizes(Be,A->cmap->n,A->rmap->n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
570     ierr = MatSetType(Be,MATELEMENTAL);CHKERRQ(ierr);
571     ierr = MatSetUp(Be);CHKERRQ(ierr);
572     *B = Be;
573   }
574   b = (Mat_Elemental*)Be->data;
575   El::Transpose(*a->emat,*b->emat);
576   Be->assembled = PETSC_TRUE;
577   PetscFunctionReturn(0);
578 }
579 
580 static PetscErrorCode MatConjugate_Elemental(Mat A)
581 {
582   Mat_Elemental  *a = (Mat_Elemental*)A->data;
583 
584   PetscFunctionBegin;
585   El::Conjugate(*a->emat);
586   PetscFunctionReturn(0);
587 }
588 
589 static PetscErrorCode MatHermitianTranspose_Elemental(Mat A,MatReuse reuse,Mat *B)
590 {
591   Mat            Be = *B;
592   PetscErrorCode ierr;
593   MPI_Comm       comm;
594   Mat_Elemental  *a = (Mat_Elemental*)A->data, *b;
595 
596   PetscFunctionBegin;
597   ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr);
598   /* Only out-of-place supported */
599   if (reuse == MAT_INITIAL_MATRIX){
600     ierr = MatCreate(comm,&Be);CHKERRQ(ierr);
601     ierr = MatSetSizes(Be,A->cmap->n,A->rmap->n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
602     ierr = MatSetType(Be,MATELEMENTAL);CHKERRQ(ierr);
603     ierr = MatSetUp(Be);CHKERRQ(ierr);
604     *B = Be;
605   }
606   b = (Mat_Elemental*)Be->data;
607   El::Adjoint(*a->emat,*b->emat);
608   Be->assembled = PETSC_TRUE;
609   PetscFunctionReturn(0);
610 }
611 
612 static PetscErrorCode MatSolve_Elemental(Mat A,Vec B,Vec X)
613 {
614   Mat_Elemental     *a = (Mat_Elemental*)A->data;
615   PetscErrorCode    ierr;
616   PetscElemScalar   *x;
617   PetscInt          pivoting = a->pivoting;
618 
619   PetscFunctionBegin;
620   ierr = VecCopy(B,X);CHKERRQ(ierr);
621   ierr = VecGetArray(X,(PetscScalar **)&x);CHKERRQ(ierr);
622 
623   El::DistMatrix<PetscElemScalar,El::VC,El::STAR> xe;
624   xe.Attach(A->rmap->N,1,*a->grid,0,0,x,A->rmap->n);
625   El::DistMatrix<PetscElemScalar,El::MC,El::MR> xer(xe);
626   switch (A->factortype) {
627   case MAT_FACTOR_LU:
628     if (pivoting == 0) {
629       El::lu::SolveAfter(El::NORMAL,*a->emat,xer);
630     } else if (pivoting == 1) {
631       El::lu::SolveAfter(El::NORMAL,*a->emat,*a->P,xer);
632     } else { /* pivoting == 2 */
633       El::lu::SolveAfter(El::NORMAL,*a->emat,*a->P,*a->Q,xer);
634     }
635     break;
636   case MAT_FACTOR_CHOLESKY:
637     El::cholesky::SolveAfter(El::UPPER,El::NORMAL,*a->emat,xer);
638     break;
639   default:
640     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unfactored Matrix or Unsupported MatFactorType");
641     break;
642   }
643   El::Copy(xer,xe);
644 
645   ierr = VecRestoreArray(X,(PetscScalar **)&x);CHKERRQ(ierr);
646   PetscFunctionReturn(0);
647 }
648 
649 static PetscErrorCode MatSolveAdd_Elemental(Mat A,Vec B,Vec Y,Vec X)
650 {
651   PetscErrorCode    ierr;
652 
653   PetscFunctionBegin;
654   ierr = MatSolve_Elemental(A,B,X);CHKERRQ(ierr);
655   ierr = VecAXPY(X,1,Y);CHKERRQ(ierr);
656   PetscFunctionReturn(0);
657 }
658 
659 static PetscErrorCode MatMatSolve_Elemental(Mat A,Mat B,Mat X)
660 {
661   Mat_Elemental  *a = (Mat_Elemental*)A->data;
662   Mat_Elemental  *x;
663   Mat            C;
664   PetscInt       pivoting = a->pivoting;
665   PetscBool      flg;
666   MatType        type;
667   PetscErrorCode ierr;
668 
669   PetscFunctionBegin;
670   ierr = MatGetType(X,&type);CHKERRQ(ierr);
671   ierr = PetscStrcmp(type,MATELEMENTAL,&flg);CHKERRQ(ierr);
672   if (!flg) {
673     ierr = MatConvert(B,MATELEMENTAL,MAT_INITIAL_MATRIX,&C);CHKERRQ(ierr);
674     x = (Mat_Elemental*)C->data;
675   } else {
676     x = (Mat_Elemental*)X->data;
677     El::Copy(*((Mat_Elemental*)B->data)->emat,*x->emat);
678   }
679   switch (A->factortype) {
680   case MAT_FACTOR_LU:
681     if (pivoting == 0) {
682       El::lu::SolveAfter(El::NORMAL,*a->emat,*x->emat);
683     } else if (pivoting == 1) {
684       El::lu::SolveAfter(El::NORMAL,*a->emat,*a->P,*x->emat);
685     } else {
686       El::lu::SolveAfter(El::NORMAL,*a->emat,*a->P,*a->Q,*x->emat);
687     }
688     break;
689   case MAT_FACTOR_CHOLESKY:
690     El::cholesky::SolveAfter(El::UPPER,El::NORMAL,*a->emat,*x->emat);
691     break;
692   default:
693     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unfactored Matrix or Unsupported MatFactorType");
694     break;
695   }
696   if (!flg) {
697     ierr = MatConvert(C,type,MAT_REUSE_MATRIX,&X);CHKERRQ(ierr);
698     ierr = MatDestroy(&C);CHKERRQ(ierr);
699   }
700   PetscFunctionReturn(0);
701 }
702 
703 static PetscErrorCode MatLUFactor_Elemental(Mat A,IS row,IS col,const MatFactorInfo *info)
704 {
705   Mat_Elemental  *a = (Mat_Elemental*)A->data;
706   PetscErrorCode ierr;
707   PetscInt       pivoting = a->pivoting;
708 
709   PetscFunctionBegin;
710   if (pivoting == 0) {
711     El::LU(*a->emat);
712   } else if (pivoting == 1) {
713     El::LU(*a->emat,*a->P);
714   } else {
715     El::LU(*a->emat,*a->P,*a->Q);
716   }
717   A->factortype = MAT_FACTOR_LU;
718   A->assembled  = PETSC_TRUE;
719 
720   ierr = PetscFree(A->solvertype);CHKERRQ(ierr);
721   ierr = PetscStrallocpy(MATSOLVERELEMENTAL,&A->solvertype);CHKERRQ(ierr);
722   PetscFunctionReturn(0);
723 }
724 
725 static PetscErrorCode  MatLUFactorNumeric_Elemental(Mat F,Mat A,const MatFactorInfo *info)
726 {
727   PetscErrorCode ierr;
728 
729   PetscFunctionBegin;
730   ierr = MatCopy(A,F,SAME_NONZERO_PATTERN);CHKERRQ(ierr);
731   ierr = MatLUFactor_Elemental(F,0,0,info);CHKERRQ(ierr);
732   PetscFunctionReturn(0);
733 }
734 
735 static PetscErrorCode  MatLUFactorSymbolic_Elemental(Mat F,Mat A,IS r,IS c,const MatFactorInfo *info)
736 {
737   PetscFunctionBegin;
738   /* F is created and allocated by MatGetFactor_elemental_petsc(), skip this routine. */
739   PetscFunctionReturn(0);
740 }
741 
742 static PetscErrorCode MatCholeskyFactor_Elemental(Mat A,IS perm,const MatFactorInfo *info)
743 {
744   Mat_Elemental  *a = (Mat_Elemental*)A->data;
745   El::DistMatrix<PetscElemScalar,El::MC,El::STAR> d;
746   PetscErrorCode ierr;
747 
748   PetscFunctionBegin;
749   El::Cholesky(El::UPPER,*a->emat);
750   A->factortype = MAT_FACTOR_CHOLESKY;
751   A->assembled  = PETSC_TRUE;
752 
753   ierr = PetscFree(A->solvertype);CHKERRQ(ierr);
754   ierr = PetscStrallocpy(MATSOLVERELEMENTAL,&A->solvertype);CHKERRQ(ierr);
755   PetscFunctionReturn(0);
756 }
757 
758 static PetscErrorCode MatCholeskyFactorNumeric_Elemental(Mat F,Mat A,const MatFactorInfo *info)
759 {
760   PetscErrorCode ierr;
761 
762   PetscFunctionBegin;
763   ierr = MatCopy(A,F,SAME_NONZERO_PATTERN);CHKERRQ(ierr);
764   ierr = MatCholeskyFactor_Elemental(F,0,info);CHKERRQ(ierr);
765   PetscFunctionReturn(0);
766 }
767 
768 static PetscErrorCode MatCholeskyFactorSymbolic_Elemental(Mat F,Mat A,IS perm,const MatFactorInfo *info)
769 {
770   PetscFunctionBegin;
771   /* F is created and allocated by MatGetFactor_elemental_petsc(), skip this routine. */
772   PetscFunctionReturn(0);
773 }
774 
775 PetscErrorCode MatFactorGetSolverType_elemental_elemental(Mat A,MatSolverType *type)
776 {
777   PetscFunctionBegin;
778   *type = MATSOLVERELEMENTAL;
779   PetscFunctionReturn(0);
780 }
781 
782 static PetscErrorCode MatGetFactor_elemental_elemental(Mat A,MatFactorType ftype,Mat *F)
783 {
784   Mat            B;
785   PetscErrorCode ierr;
786 
787   PetscFunctionBegin;
788   /* Create the factorization matrix */
789   ierr = MatCreate(PetscObjectComm((PetscObject)A),&B);CHKERRQ(ierr);
790   ierr = MatSetSizes(B,A->rmap->n,A->cmap->n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
791   ierr = MatSetType(B,MATELEMENTAL);CHKERRQ(ierr);
792   ierr = MatSetUp(B);CHKERRQ(ierr);
793   B->factortype = ftype;
794   ierr = PetscFree(B->solvertype);CHKERRQ(ierr);
795   ierr = PetscStrallocpy(MATSOLVERELEMENTAL,&B->solvertype);CHKERRQ(ierr);
796 
797   ierr = PetscObjectComposeFunction((PetscObject)B,"MatFactorGetSolverType_C",MatFactorGetSolverType_elemental_elemental);CHKERRQ(ierr);
798   *F            = B;
799   PetscFunctionReturn(0);
800 }
801 
802 PETSC_EXTERN PetscErrorCode MatSolverTypeRegister_Elemental(void)
803 {
804   PetscErrorCode ierr;
805 
806   PetscFunctionBegin;
807   ierr = MatSolverTypeRegister(MATSOLVERELEMENTAL,MATELEMENTAL,        MAT_FACTOR_LU,MatGetFactor_elemental_elemental);CHKERRQ(ierr);
808   ierr = MatSolverTypeRegister(MATSOLVERELEMENTAL,MATELEMENTAL,        MAT_FACTOR_CHOLESKY,MatGetFactor_elemental_elemental);CHKERRQ(ierr);
809   PetscFunctionReturn(0);
810 }
811 
812 static PetscErrorCode MatNorm_Elemental(Mat A,NormType type,PetscReal *nrm)
813 {
814   Mat_Elemental *a=(Mat_Elemental*)A->data;
815 
816   PetscFunctionBegin;
817   switch (type){
818   case NORM_1:
819     *nrm = El::OneNorm(*a->emat);
820     break;
821   case NORM_FROBENIUS:
822     *nrm = El::FrobeniusNorm(*a->emat);
823     break;
824   case NORM_INFINITY:
825     *nrm = El::InfinityNorm(*a->emat);
826     break;
827   default:
828     SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Unsupported norm type");
829   }
830   PetscFunctionReturn(0);
831 }
832 
833 static PetscErrorCode MatZeroEntries_Elemental(Mat A)
834 {
835   Mat_Elemental *a=(Mat_Elemental*)A->data;
836 
837   PetscFunctionBegin;
838   El::Zero(*a->emat);
839   PetscFunctionReturn(0);
840 }
841 
842 static PetscErrorCode MatGetOwnershipIS_Elemental(Mat A,IS *rows,IS *cols)
843 {
844   Mat_Elemental  *a = (Mat_Elemental*)A->data;
845   PetscErrorCode ierr;
846   PetscInt       i,m,shift,stride,*idx;
847 
848   PetscFunctionBegin;
849   if (rows) {
850     m = a->emat->LocalHeight();
851     shift = a->emat->ColShift();
852     stride = a->emat->ColStride();
853     ierr = PetscMalloc1(m,&idx);CHKERRQ(ierr);
854     for (i=0; i<m; i++) {
855       PetscInt rank,offset;
856       E2RO(A,0,shift+i*stride,&rank,&offset);
857       RO2P(A,0,rank,offset,&idx[i]);
858     }
859     ierr = ISCreateGeneral(PETSC_COMM_SELF,m,idx,PETSC_OWN_POINTER,rows);CHKERRQ(ierr);
860   }
861   if (cols) {
862     m = a->emat->LocalWidth();
863     shift = a->emat->RowShift();
864     stride = a->emat->RowStride();
865     ierr = PetscMalloc1(m,&idx);CHKERRQ(ierr);
866     for (i=0; i<m; i++) {
867       PetscInt rank,offset;
868       E2RO(A,1,shift+i*stride,&rank,&offset);
869       RO2P(A,1,rank,offset,&idx[i]);
870     }
871     ierr = ISCreateGeneral(PETSC_COMM_SELF,m,idx,PETSC_OWN_POINTER,cols);CHKERRQ(ierr);
872   }
873   PetscFunctionReturn(0);
874 }
875 
876 static PetscErrorCode MatConvert_Elemental_Dense(Mat A,MatType newtype,MatReuse reuse,Mat *B)
877 {
878   Mat                Bmpi;
879   Mat_Elemental      *a = (Mat_Elemental*)A->data;
880   MPI_Comm           comm;
881   PetscErrorCode     ierr;
882   IS                 isrows,iscols;
883   PetscInt           rrank,ridx,crank,cidx,nrows,ncols,i,j,erow,ecol,elrow,elcol;
884   const PetscInt     *rows,*cols;
885   PetscElemScalar    v;
886   const El::Grid     &grid = a->emat->Grid();
887 
888   PetscFunctionBegin;
889   ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr);
890 
891   if (reuse == MAT_REUSE_MATRIX) {
892     Bmpi = *B;
893   } else {
894     ierr = MatCreate(comm,&Bmpi);CHKERRQ(ierr);
895     ierr = MatSetSizes(Bmpi,A->rmap->n,A->cmap->n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
896     ierr = MatSetType(Bmpi,MATDENSE);CHKERRQ(ierr);
897     ierr = MatSetUp(Bmpi);CHKERRQ(ierr);
898   }
899 
900   /* Get local entries of A */
901   ierr = MatGetOwnershipIS(A,&isrows,&iscols);CHKERRQ(ierr);
902   ierr = ISGetLocalSize(isrows,&nrows);CHKERRQ(ierr);
903   ierr = ISGetIndices(isrows,&rows);CHKERRQ(ierr);
904   ierr = ISGetLocalSize(iscols,&ncols);CHKERRQ(ierr);
905   ierr = ISGetIndices(iscols,&cols);CHKERRQ(ierr);
906 
907   if (a->roworiented) {
908     for (i=0; i<nrows; i++) {
909       P2RO(A,0,rows[i],&rrank,&ridx); /* convert indices between PETSc <-> (Rank,Offset) <-> Elemental */
910       RO2E(A,0,rrank,ridx,&erow);
911       if (rrank < 0 || ridx < 0 || erow < 0) SETERRQ(comm,PETSC_ERR_PLIB,"Incorrect row translation");
912       for (j=0; j<ncols; j++) {
913         P2RO(A,1,cols[j],&crank,&cidx);
914         RO2E(A,1,crank,cidx,&ecol);
915         if (crank < 0 || cidx < 0 || ecol < 0) SETERRQ(comm,PETSC_ERR_PLIB,"Incorrect col translation");
916 
917         elrow = erow / grid.MCSize(); /* Elemental local row index */
918         elcol = ecol / grid.MRSize(); /* Elemental local column index */
919         v = a->emat->GetLocal(elrow,elcol);
920         ierr = MatSetValues(Bmpi,1,&rows[i],1,&cols[j],(PetscScalar *)&v,INSERT_VALUES);CHKERRQ(ierr);
921       }
922     }
923   } else { /* column-oriented */
924     for (j=0; j<ncols; j++) {
925       P2RO(A,1,cols[j],&crank,&cidx);
926       RO2E(A,1,crank,cidx,&ecol);
927       if (crank < 0 || cidx < 0 || ecol < 0) SETERRQ(comm,PETSC_ERR_PLIB,"Incorrect col translation");
928       for (i=0; i<nrows; i++) {
929         P2RO(A,0,rows[i],&rrank,&ridx); /* convert indices between PETSc <-> (Rank,Offset) <-> Elemental */
930         RO2E(A,0,rrank,ridx,&erow);
931         if (rrank < 0 || ridx < 0 || erow < 0) SETERRQ(comm,PETSC_ERR_PLIB,"Incorrect row translation");
932 
933         elrow = erow / grid.MCSize(); /* Elemental local row index */
934         elcol = ecol / grid.MRSize(); /* Elemental local column index */
935         v = a->emat->GetLocal(elrow,elcol);
936         ierr = MatSetValues(Bmpi,1,&rows[i],1,&cols[j],(PetscScalar *)&v,INSERT_VALUES);CHKERRQ(ierr);
937       }
938     }
939   }
940   ierr = MatAssemblyBegin(Bmpi,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
941   ierr = MatAssemblyEnd(Bmpi,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
942   if (reuse == MAT_INPLACE_MATRIX) {
943     ierr = MatHeaderReplace(A,&Bmpi);CHKERRQ(ierr);
944   } else {
945     *B = Bmpi;
946   }
947   ierr = ISDestroy(&isrows);CHKERRQ(ierr);
948   ierr = ISDestroy(&iscols);CHKERRQ(ierr);
949   PetscFunctionReturn(0);
950 }
951 
952 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_Elemental(Mat A, MatType newtype,MatReuse reuse,Mat *newmat)
953 {
954   Mat               mat_elemental;
955   PetscErrorCode    ierr;
956   PetscInt          M=A->rmap->N,N=A->cmap->N,row,ncols;
957   const PetscInt    *cols;
958   const PetscScalar *vals;
959 
960   PetscFunctionBegin;
961   if (reuse == MAT_REUSE_MATRIX) {
962     mat_elemental = *newmat;
963     ierr = MatZeroEntries(mat_elemental);CHKERRQ(ierr);
964   } else {
965     ierr = MatCreate(PetscObjectComm((PetscObject)A), &mat_elemental);CHKERRQ(ierr);
966     ierr = MatSetSizes(mat_elemental,PETSC_DECIDE,PETSC_DECIDE,M,N);CHKERRQ(ierr);
967     ierr = MatSetType(mat_elemental,MATELEMENTAL);CHKERRQ(ierr);
968     ierr = MatSetUp(mat_elemental);CHKERRQ(ierr);
969   }
970   for (row=0; row<M; row++) {
971     ierr = MatGetRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr);
972     /* PETSc-Elemental interface uses axpy for setting off-processor entries, only ADD_VALUES is allowed */
973     ierr = MatSetValues(mat_elemental,1,&row,ncols,cols,vals,ADD_VALUES);CHKERRQ(ierr);
974     ierr = MatRestoreRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr);
975   }
976   ierr = MatAssemblyBegin(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
977   ierr = MatAssemblyEnd(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
978 
979   if (reuse == MAT_INPLACE_MATRIX) {
980     ierr = MatHeaderReplace(A,&mat_elemental);CHKERRQ(ierr);
981   } else {
982     *newmat = mat_elemental;
983   }
984   PetscFunctionReturn(0);
985 }
986 
987 PETSC_INTERN PetscErrorCode MatConvert_MPIAIJ_Elemental(Mat A, MatType newtype,MatReuse reuse,Mat *newmat)
988 {
989   Mat               mat_elemental;
990   PetscErrorCode    ierr;
991   PetscInt          row,ncols,rstart=A->rmap->rstart,rend=A->rmap->rend,j;
992   const PetscInt    *cols;
993   const PetscScalar *vals;
994 
995   PetscFunctionBegin;
996   if (reuse == MAT_REUSE_MATRIX) {
997     mat_elemental = *newmat;
998     ierr = MatZeroEntries(mat_elemental);CHKERRQ(ierr);
999   } else {
1000     ierr = MatCreate(PetscObjectComm((PetscObject)A), &mat_elemental);CHKERRQ(ierr);
1001     ierr = MatSetSizes(mat_elemental,PETSC_DECIDE,PETSC_DECIDE,A->rmap->N,A->cmap->N);CHKERRQ(ierr);
1002     ierr = MatSetType(mat_elemental,MATELEMENTAL);CHKERRQ(ierr);
1003     ierr = MatSetUp(mat_elemental);CHKERRQ(ierr);
1004   }
1005   for (row=rstart; row<rend; row++) {
1006     ierr = MatGetRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr);
1007     for (j=0; j<ncols; j++) {
1008       /* PETSc-Elemental interface uses axpy for setting off-processor entries, only ADD_VALUES is allowed */
1009       ierr = MatSetValues(mat_elemental,1,&row,1,&cols[j],&vals[j],ADD_VALUES);CHKERRQ(ierr);
1010     }
1011     ierr = MatRestoreRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr);
1012   }
1013   ierr = MatAssemblyBegin(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1014   ierr = MatAssemblyEnd(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1015 
1016   if (reuse == MAT_INPLACE_MATRIX) {
1017     ierr = MatHeaderReplace(A,&mat_elemental);CHKERRQ(ierr);
1018   } else {
1019     *newmat = mat_elemental;
1020   }
1021   PetscFunctionReturn(0);
1022 }
1023 
1024 PETSC_INTERN PetscErrorCode MatConvert_SeqSBAIJ_Elemental(Mat A, MatType newtype,MatReuse reuse,Mat *newmat)
1025 {
1026   Mat               mat_elemental;
1027   PetscErrorCode    ierr;
1028   PetscInt          M=A->rmap->N,N=A->cmap->N,row,ncols,j;
1029   const PetscInt    *cols;
1030   const PetscScalar *vals;
1031 
1032   PetscFunctionBegin;
1033   if (reuse == MAT_REUSE_MATRIX) {
1034     mat_elemental = *newmat;
1035     ierr = MatZeroEntries(mat_elemental);CHKERRQ(ierr);
1036   } else {
1037     ierr = MatCreate(PetscObjectComm((PetscObject)A), &mat_elemental);CHKERRQ(ierr);
1038     ierr = MatSetSizes(mat_elemental,PETSC_DECIDE,PETSC_DECIDE,M,N);CHKERRQ(ierr);
1039     ierr = MatSetType(mat_elemental,MATELEMENTAL);CHKERRQ(ierr);
1040     ierr = MatSetUp(mat_elemental);CHKERRQ(ierr);
1041   }
1042   ierr = MatGetRowUpperTriangular(A);CHKERRQ(ierr);
1043   for (row=0; row<M; row++) {
1044     ierr = MatGetRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr);
1045     /* PETSc-Elemental interface uses axpy for setting off-processor entries, only ADD_VALUES is allowed */
1046     ierr = MatSetValues(mat_elemental,1,&row,ncols,cols,vals,ADD_VALUES);CHKERRQ(ierr);
1047     for (j=0; j<ncols; j++) { /* lower triangular part */
1048       PetscScalar v;
1049       if (cols[j] == row) continue;
1050       v    = A->hermitian ? PetscConj(vals[j]) : vals[j];
1051       ierr = MatSetValues(mat_elemental,1,&cols[j],1,&row,&v,ADD_VALUES);CHKERRQ(ierr);
1052     }
1053     ierr = MatRestoreRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr);
1054   }
1055   ierr = MatRestoreRowUpperTriangular(A);CHKERRQ(ierr);
1056   ierr = MatAssemblyBegin(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1057   ierr = MatAssemblyEnd(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1058 
1059   if (reuse == MAT_INPLACE_MATRIX) {
1060     ierr = MatHeaderReplace(A,&mat_elemental);CHKERRQ(ierr);
1061   } else {
1062     *newmat = mat_elemental;
1063   }
1064   PetscFunctionReturn(0);
1065 }
1066 
1067 PETSC_INTERN PetscErrorCode MatConvert_MPISBAIJ_Elemental(Mat A, MatType newtype,MatReuse reuse,Mat *newmat)
1068 {
1069   Mat               mat_elemental;
1070   PetscErrorCode    ierr;
1071   PetscInt          M=A->rmap->N,N=A->cmap->N,row,ncols,j,rstart=A->rmap->rstart,rend=A->rmap->rend;
1072   const PetscInt    *cols;
1073   const PetscScalar *vals;
1074 
1075   PetscFunctionBegin;
1076   if (reuse == MAT_REUSE_MATRIX) {
1077     mat_elemental = *newmat;
1078     ierr = MatZeroEntries(mat_elemental);CHKERRQ(ierr);
1079   } else {
1080     ierr = MatCreate(PetscObjectComm((PetscObject)A), &mat_elemental);CHKERRQ(ierr);
1081     ierr = MatSetSizes(mat_elemental,PETSC_DECIDE,PETSC_DECIDE,M,N);CHKERRQ(ierr);
1082     ierr = MatSetType(mat_elemental,MATELEMENTAL);CHKERRQ(ierr);
1083     ierr = MatSetUp(mat_elemental);CHKERRQ(ierr);
1084   }
1085   ierr = MatGetRowUpperTriangular(A);CHKERRQ(ierr);
1086   for (row=rstart; row<rend; row++) {
1087     ierr = MatGetRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr);
1088     /* PETSc-Elemental interface uses axpy for setting off-processor entries, only ADD_VALUES is allowed */
1089     ierr = MatSetValues(mat_elemental,1,&row,ncols,cols,vals,ADD_VALUES);CHKERRQ(ierr);
1090     for (j=0; j<ncols; j++) { /* lower triangular part */
1091       PetscScalar v;
1092       if (cols[j] == row) continue;
1093       v    = A->hermitian ? PetscConj(vals[j]) : vals[j];
1094       ierr = MatSetValues(mat_elemental,1,&cols[j],1,&row,&v,ADD_VALUES);CHKERRQ(ierr);
1095     }
1096     ierr = MatRestoreRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr);
1097   }
1098   ierr = MatRestoreRowUpperTriangular(A);CHKERRQ(ierr);
1099   ierr = MatAssemblyBegin(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1100   ierr = MatAssemblyEnd(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1101 
1102   if (reuse == MAT_INPLACE_MATRIX) {
1103     ierr = MatHeaderReplace(A,&mat_elemental);CHKERRQ(ierr);
1104   } else {
1105     *newmat = mat_elemental;
1106   }
1107   PetscFunctionReturn(0);
1108 }
1109 
1110 static PetscErrorCode MatDestroy_Elemental(Mat A)
1111 {
1112   Mat_Elemental      *a = (Mat_Elemental*)A->data;
1113   PetscErrorCode     ierr;
1114   Mat_Elemental_Grid *commgrid;
1115   PetscBool          flg;
1116   MPI_Comm           icomm;
1117 
1118   PetscFunctionBegin;
1119   delete a->emat;
1120   delete a->P;
1121   delete a->Q;
1122 
1123   El::mpi::Comm cxxcomm(PetscObjectComm((PetscObject)A));
1124   ierr = PetscCommDuplicate(cxxcomm.comm,&icomm,NULL);CHKERRQ(ierr);
1125   ierr = MPI_Comm_get_attr(icomm,Petsc_Elemental_keyval,(void**)&commgrid,(int*)&flg);CHKERRMPI(ierr);
1126   if (--commgrid->grid_refct == 0) {
1127     delete commgrid->grid;
1128     ierr = PetscFree(commgrid);CHKERRQ(ierr);
1129     ierr = MPI_Comm_free_keyval(&Petsc_Elemental_keyval);CHKERRMPI(ierr);
1130   }
1131   ierr = PetscCommDestroy(&icomm);CHKERRQ(ierr);
1132   ierr = PetscObjectComposeFunction((PetscObject)A,"MatGetOwnershipIS_C",NULL);CHKERRQ(ierr);
1133   ierr = PetscObjectComposeFunction((PetscObject)A,"MatFactorGetSolverType_C",NULL);CHKERRQ(ierr);
1134   ierr = PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_elemental_mpidense_C",NULL);CHKERRQ(ierr);
1135   ierr = PetscFree(A->data);CHKERRQ(ierr);
1136   PetscFunctionReturn(0);
1137 }
1138 
1139 PetscErrorCode MatSetUp_Elemental(Mat A)
1140 {
1141   Mat_Elemental  *a = (Mat_Elemental*)A->data;
1142   PetscErrorCode ierr;
1143   MPI_Comm       comm;
1144   PetscMPIInt    rsize,csize;
1145   PetscInt       n;
1146 
1147   PetscFunctionBegin;
1148   ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr);
1149   ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr);
1150 
1151   /* Check if local row and column sizes are equally distributed.
1152      Jed: Elemental uses "element" cyclic ordering so the sizes need to match that
1153      exactly.  The strategy in MatElemental is for PETSc to implicitly permute to block ordering (like would be returned by
1154      PetscSplitOwnership(comm,&n,&N), at which point Elemental matrices can act on PETSc vectors without redistributing the vectors. */
1155   ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr);
1156   n = PETSC_DECIDE;
1157   ierr = PetscSplitOwnership(comm,&n,&A->rmap->N);CHKERRQ(ierr);
1158   if (n != A->rmap->n) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Local row size %D of ELEMENTAL matrix must be equally distributed",A->rmap->n);
1159 
1160   n = PETSC_DECIDE;
1161   ierr = PetscSplitOwnership(comm,&n,&A->cmap->N);CHKERRQ(ierr);
1162   if (n != A->cmap->n) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Local column size %D of ELEMENTAL matrix must be equally distributed",A->cmap->n);
1163 
1164   a->emat->Resize(A->rmap->N,A->cmap->N);CHKERRQ(ierr);
1165   El::Zero(*a->emat);
1166 
1167   ierr = MPI_Comm_size(A->rmap->comm,&rsize);CHKERRMPI(ierr);
1168   ierr = MPI_Comm_size(A->cmap->comm,&csize);CHKERRMPI(ierr);
1169   if (csize != rsize) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_INCOMP,"Cannot use row and column communicators of different sizes");
1170   a->commsize = rsize;
1171   a->mr[0] = A->rmap->N % rsize; if (!a->mr[0]) a->mr[0] = rsize;
1172   a->mr[1] = A->cmap->N % csize; if (!a->mr[1]) a->mr[1] = csize;
1173   a->m[0]  = A->rmap->N / rsize + (a->mr[0] != rsize);
1174   a->m[1]  = A->cmap->N / csize + (a->mr[1] != csize);
1175   PetscFunctionReturn(0);
1176 }
1177 
1178 PetscErrorCode MatAssemblyBegin_Elemental(Mat A, MatAssemblyType type)
1179 {
1180   Mat_Elemental  *a = (Mat_Elemental*)A->data;
1181 
1182   PetscFunctionBegin;
1183   /* printf("Calling ProcessQueues\n"); */
1184   a->emat->ProcessQueues();
1185   /* printf("Finished ProcessQueues\n"); */
1186   PetscFunctionReturn(0);
1187 }
1188 
1189 PetscErrorCode MatAssemblyEnd_Elemental(Mat A, MatAssemblyType type)
1190 {
1191   PetscFunctionBegin;
1192   /* Currently does nothing */
1193   PetscFunctionReturn(0);
1194 }
1195 
1196 PetscErrorCode MatLoad_Elemental(Mat newMat, PetscViewer viewer)
1197 {
1198   PetscErrorCode ierr;
1199   Mat            Adense,Ae;
1200   MPI_Comm       comm;
1201 
1202   PetscFunctionBegin;
1203   ierr = PetscObjectGetComm((PetscObject)newMat,&comm);CHKERRQ(ierr);
1204   ierr = MatCreate(comm,&Adense);CHKERRQ(ierr);
1205   ierr = MatSetType(Adense,MATDENSE);CHKERRQ(ierr);
1206   ierr = MatLoad(Adense,viewer);CHKERRQ(ierr);
1207   ierr = MatConvert(Adense, MATELEMENTAL, MAT_INITIAL_MATRIX,&Ae);CHKERRQ(ierr);
1208   ierr = MatDestroy(&Adense);CHKERRQ(ierr);
1209   ierr = MatHeaderReplace(newMat,&Ae);CHKERRQ(ierr);
1210   PetscFunctionReturn(0);
1211 }
1212 
1213 /* -------------------------------------------------------------------*/
1214 static struct _MatOps MatOps_Values = {
1215        MatSetValues_Elemental,
1216        0,
1217        0,
1218        MatMult_Elemental,
1219 /* 4*/ MatMultAdd_Elemental,
1220        MatMultTranspose_Elemental,
1221        MatMultTransposeAdd_Elemental,
1222        MatSolve_Elemental,
1223        MatSolveAdd_Elemental,
1224        0,
1225 /*10*/ 0,
1226        MatLUFactor_Elemental,
1227        MatCholeskyFactor_Elemental,
1228        0,
1229        MatTranspose_Elemental,
1230 /*15*/ MatGetInfo_Elemental,
1231        0,
1232        MatGetDiagonal_Elemental,
1233        MatDiagonalScale_Elemental,
1234        MatNorm_Elemental,
1235 /*20*/ MatAssemblyBegin_Elemental,
1236        MatAssemblyEnd_Elemental,
1237        MatSetOption_Elemental,
1238        MatZeroEntries_Elemental,
1239 /*24*/ 0,
1240        MatLUFactorSymbolic_Elemental,
1241        MatLUFactorNumeric_Elemental,
1242        MatCholeskyFactorSymbolic_Elemental,
1243        MatCholeskyFactorNumeric_Elemental,
1244 /*29*/ MatSetUp_Elemental,
1245        0,
1246        0,
1247        0,
1248        0,
1249 /*34*/ MatDuplicate_Elemental,
1250        0,
1251        0,
1252        0,
1253        0,
1254 /*39*/ MatAXPY_Elemental,
1255        0,
1256        0,
1257        0,
1258        MatCopy_Elemental,
1259 /*44*/ 0,
1260        MatScale_Elemental,
1261        MatShift_Basic,
1262        0,
1263        0,
1264 /*49*/ 0,
1265        0,
1266        0,
1267        0,
1268        0,
1269 /*54*/ 0,
1270        0,
1271        0,
1272        0,
1273        0,
1274 /*59*/ 0,
1275        MatDestroy_Elemental,
1276        MatView_Elemental,
1277        0,
1278        0,
1279 /*64*/ 0,
1280        0,
1281        0,
1282        0,
1283        0,
1284 /*69*/ 0,
1285        0,
1286        MatConvert_Elemental_Dense,
1287        0,
1288        0,
1289 /*74*/ 0,
1290        0,
1291        0,
1292        0,
1293        0,
1294 /*79*/ 0,
1295        0,
1296        0,
1297        0,
1298        MatLoad_Elemental,
1299 /*84*/ 0,
1300        0,
1301        0,
1302        0,
1303        0,
1304 /*89*/ 0,
1305        0,
1306        MatMatMultNumeric_Elemental,
1307        0,
1308        0,
1309 /*94*/ 0,
1310        0,
1311        0,
1312        MatMatTransposeMultNumeric_Elemental,
1313        0,
1314 /*99*/ MatProductSetFromOptions_Elemental,
1315        0,
1316        0,
1317        MatConjugate_Elemental,
1318        0,
1319 /*104*/0,
1320        0,
1321        0,
1322        0,
1323        0,
1324 /*109*/MatMatSolve_Elemental,
1325        0,
1326        0,
1327        0,
1328        MatMissingDiagonal_Elemental,
1329 /*114*/0,
1330        0,
1331        0,
1332        0,
1333        0,
1334 /*119*/0,
1335        MatHermitianTranspose_Elemental,
1336        0,
1337        0,
1338        0,
1339 /*124*/0,
1340        0,
1341        0,
1342        0,
1343        0,
1344 /*129*/0,
1345        0,
1346        0,
1347        0,
1348        0,
1349 /*134*/0,
1350        0,
1351        0,
1352        0,
1353        0,
1354        0,
1355 /*140*/0,
1356        0,
1357        0,
1358        0,
1359        0,
1360 /*145*/0,
1361        0,
1362        0
1363 };
1364 
1365 /*MC
1366    MATELEMENTAL = "elemental" - A matrix type for dense matrices using the Elemental package
1367 
1368   Use ./configure --download-elemental to install PETSc to use Elemental
1369 
1370   Use -pc_type lu -pc_factor_mat_solver_type elemental to use this direct solver
1371 
1372    Options Database Keys:
1373 + -mat_type elemental - sets the matrix type to "elemental" during a call to MatSetFromOptions()
1374 - -mat_elemental_grid_height - sets Grid Height for 2D cyclic ordering of internal matrix
1375 
1376   Level: beginner
1377 
1378 .seealso: MATDENSE
1379 M*/
1380 
1381 PETSC_EXTERN PetscErrorCode MatCreate_Elemental(Mat A)
1382 {
1383   Mat_Elemental      *a;
1384   PetscErrorCode     ierr;
1385   PetscBool          flg,flg1;
1386   Mat_Elemental_Grid *commgrid;
1387   MPI_Comm           icomm;
1388   PetscInt           optv1;
1389 
1390   PetscFunctionBegin;
1391   ierr = PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr);
1392   A->insertmode = NOT_SET_VALUES;
1393 
1394   ierr = PetscNewLog(A,&a);CHKERRQ(ierr);
1395   A->data = (void*)a;
1396 
1397   /* Set up the elemental matrix */
1398   El::mpi::Comm cxxcomm(PetscObjectComm((PetscObject)A));
1399 
1400   /* Grid needs to be shared between multiple Mats on the same communicator, implement by attribute caching on the MPI_Comm */
1401   if (Petsc_Elemental_keyval == MPI_KEYVAL_INVALID) {
1402     ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN,MPI_COMM_NULL_DELETE_FN,&Petsc_Elemental_keyval,(void*)0);CHKERRMPI(ierr);
1403     ierr = PetscCitationsRegister(ElementalCitation,&ElementalCite);CHKERRQ(ierr);
1404   }
1405   ierr = PetscCommDuplicate(cxxcomm.comm,&icomm,NULL);CHKERRQ(ierr);
1406   ierr = MPI_Comm_get_attr(icomm,Petsc_Elemental_keyval,(void**)&commgrid,(int*)&flg);CHKERRMPI(ierr);
1407   if (!flg) {
1408     ierr = PetscNewLog(A,&commgrid);CHKERRQ(ierr);
1409 
1410     ierr = PetscOptionsBegin(PetscObjectComm((PetscObject)A),((PetscObject)A)->prefix,"Elemental Options","Mat");CHKERRQ(ierr);
1411     /* displayed default grid sizes (CommSize,1) are set by us arbitrarily until El::Grid() is called */
1412     ierr = PetscOptionsInt("-mat_elemental_grid_height","Grid Height","None",El::mpi::Size(cxxcomm),&optv1,&flg1);CHKERRQ(ierr);
1413     if (flg1) {
1414       if (El::mpi::Size(cxxcomm) % optv1) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_INCOMP,"Grid Height %D must evenly divide CommSize %D",optv1,(PetscInt)El::mpi::Size(cxxcomm));
1415       commgrid->grid = new El::Grid(cxxcomm,optv1); /* use user-provided grid height */
1416     } else {
1417       commgrid->grid = new El::Grid(cxxcomm); /* use Elemental default grid sizes */
1418       /* printf("new commgrid->grid = %p\n",commgrid->grid);  -- memory leak revealed by valgrind? */
1419     }
1420     commgrid->grid_refct = 1;
1421     ierr = MPI_Comm_set_attr(icomm,Petsc_Elemental_keyval,(void*)commgrid);CHKERRMPI(ierr);
1422 
1423     a->pivoting    = 1;
1424     ierr = PetscOptionsInt("-mat_elemental_pivoting","Pivoting","None",a->pivoting,&a->pivoting,NULL);CHKERRQ(ierr);
1425 
1426     ierr = PetscOptionsEnd();CHKERRQ(ierr);
1427   } else {
1428     commgrid->grid_refct++;
1429   }
1430   ierr = PetscCommDestroy(&icomm);CHKERRQ(ierr);
1431   a->grid        = commgrid->grid;
1432   a->emat        = new El::DistMatrix<PetscElemScalar>(*a->grid);
1433   a->roworiented = PETSC_TRUE;
1434 
1435   ierr = PetscObjectComposeFunction((PetscObject)A,"MatGetOwnershipIS_C",MatGetOwnershipIS_Elemental);CHKERRQ(ierr);
1436   ierr = PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_elemental_mpidense_C",MatProductSetFromOptions_Elemental_MPIDense);CHKERRQ(ierr);
1437   ierr = PetscObjectChangeTypeName((PetscObject)A,MATELEMENTAL);CHKERRQ(ierr);
1438   PetscFunctionReturn(0);
1439 }
1440