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