xref: /petsc/src/mat/impls/elemental/matelem.cxx (revision df311e6cf50cfd15707132919f4c4e1a4c3dc824)
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    Input Arguments:
17 .  path - the dynamic library path or PETSC_NULL
18 
19    Level: developer
20 
21 .seealso: MATELEMENTAL, PetscElementalFinalizePackage()
22 @*/
23 PetscErrorCode PetscElementalInitializePackage(const char *path)
24 {
25   PetscErrorCode ierr;
26 
27   PetscFunctionBegin;
28   if (elem::Initialized()) PetscFunctionReturn(0);
29   { /* 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 */
30     int zero = 0;
31     char **nothing = 0;
32     elem::Initialize(zero,nothing);
33   }
34   ierr = PetscRegisterFinalize(PetscElementalFinalizePackage);CHKERRQ(ierr);
35   PetscFunctionReturn(0);
36 }
37 
38 #undef __FUNCT__
39 #define __FUNCT__ "PetscElementalFinalizePackage"
40 /*@C
41    PetscElementalFinalizePackage - Finalize Elemental package
42 
43    Logically Collective
44 
45    Level: developer
46 
47 .seealso: MATELEMENTAL, PetscElementalInitializePackage()
48 @*/
49 PetscErrorCode PetscElementalFinalizePackage(void)
50 {
51 
52   PetscFunctionBegin;
53   elem::Finalize();
54   PetscFunctionReturn(0);
55 }
56 
57 /* Sets Elemental options from the options database */
58 #undef __FUNCT__
59 #define __FUNCT__ "PetscSetElementalFromOptions"
60 PetscErrorCode PetscSetElementalFromOptions(Mat A)
61 {
62   //Mat_Elemental  *a = (Mat_Elemental*)A->data;
63   PetscErrorCode ierr;
64   //PetscInt       optv1,optv2;
65   //PetscBool      flg;
66 
67   PetscFunctionBegin;
68   ierr = PetscOptionsBegin(((PetscObject)A)->comm,((PetscObject)A)->prefix,"Elemental Options","Mat");CHKERRQ(ierr);
69   //ierr = PetscOptionsInt("-mat_elemental_grid_height","Gird Height","None",(*a->emat).Grid().Height(),&optv1,&flg);CHKERRQ(ierr);
70   //ierr = PetscOptionsInt("-mat_elemental_grid_width","Gird Width","None",(*a->emat).Grid().Width(),&optv2,&flg);CHKERRQ(ierr);
71   //if (flg) (*a->emat).Grid().ResizeTo(optv1,optv2);
72   // ierr = PetscOptionsInt("-mat_mumps_icntl_2","ICNTL(2): output stream for diagnostic printing, statistics, and warning","None",mumps->id.ICNTL(2),&icntl,&flg);CHKERRQ(ierr);
73   // if (flg) mumps->id.ICNTL(2) = icntl;
74   // ierr = PetscOptionsInt("-mat_mumps_icntl_3","ICNTL(3): output stream for global information, collected on the host","None",mumps->id.ICNTL(3),&icntl,&flg);CHKERRQ(ierr);
75   // if (flg) mumps->id.ICNTL(3) = icntl;
76 
77 
78   PetscOptionsEnd();
79   PetscFunctionReturn(0);
80 }
81 
82 #undef __FUNCT__
83 #define __FUNCT__ "MatView_Elemental"
84 static PetscErrorCode MatView_Elemental(Mat A,PetscViewer viewer)
85 {
86   PetscErrorCode ierr;
87   Mat_Elemental  *a = (Mat_Elemental*)A->data;
88   PetscBool      iascii;
89 
90   PetscFunctionBegin;
91   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
92   if (iascii) {
93     PetscViewerFormat format;
94     ierr = PetscViewerGetFormat(viewer,&format);CHKERRQ(ierr);
95     if (format == PETSC_VIEWER_ASCII_INFO) {
96       /* call elemental viewing function */
97       ierr = PetscViewerASCIIPrintf(viewer,"Elemental run parameters:\n");CHKERRQ(ierr);
98       ierr = PetscViewerASCIIPrintf(viewer,"  allocated entries=%d\n",(*a->emat).AllocatedMemory());CHKERRQ(ierr);
99       ierr = PetscViewerASCIIPrintf(viewer,"  grid height=%d, grid width=%d\n",(*a->emat).Grid().Height(),(*a->emat).Grid().Width());CHKERRQ(ierr);
100       if (format == PETSC_VIEWER_ASCII_FACTOR_INFO) {
101         /* call elemental viewing function */
102         ierr = PetscPrintf(((PetscObject)viewer)->comm,"test matview_elemental 2\n");CHKERRQ(ierr);
103       }
104 
105     } else if (format == PETSC_VIEWER_DEFAULT) {
106       ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr);
107       ierr = PetscObjectPrintClassNamePrefixType((PetscObject)A,viewer,"Matrix Object");CHKERRQ(ierr);
108       a->emat->Print("Elemental matrix (cyclic ordering)");
109       ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr);
110       if (A->factortype == MAT_FACTOR_NONE){
111         Mat Aaij;
112         ierr = PetscPrintf(((PetscObject)viewer)->comm,"Elemental matrix (explicit ordering)\n");CHKERRQ(ierr);
113         ierr = MatComputeExplicitOperator(A,&Aaij);CHKERRQ(ierr);
114         ierr = MatView(Aaij,viewer);CHKERRQ(ierr);
115         ierr = MatDestroy(&Aaij);CHKERRQ(ierr);
116       }
117     } else SETERRQ(((PetscObject)viewer)->comm,PETSC_ERR_SUP,"Format");
118   } else {
119     /* convert to aij/mpidense format and call MatView() */
120     Mat Aaij;
121     ierr = PetscPrintf(((PetscObject)viewer)->comm,"Elemental matrix (explicit ordering)\n");CHKERRQ(ierr);
122     ierr = MatComputeExplicitOperator(A,&Aaij);CHKERRQ(ierr);
123     ierr = MatView(Aaij,viewer);CHKERRQ(ierr);
124     ierr = MatDestroy(&Aaij);CHKERRQ(ierr);
125   }
126   PetscFunctionReturn(0);
127 }
128 
129 #undef __FUNCT__
130 #define __FUNCT__ "MatGetInfo_Elemental"
131 static PetscErrorCode MatGetInfo_Elemental(Mat F,MatInfoType flag,MatInfo *info)
132 {
133   PetscFunctionBegin;
134   /* this routine is called by PCSetUp_LU(). It does nothing yet. */
135   PetscFunctionReturn(0);
136 }
137 
138 #undef __FUNCT__
139 #define __FUNCT__ "MatSetValues_Elemental"
140 static PetscErrorCode MatSetValues_Elemental(Mat A,PetscInt nr,const PetscInt *rows,PetscInt nc,const PetscInt *cols,const PetscElemScalar *vals,InsertMode imode)
141 {
142   PetscErrorCode ierr;
143   Mat_Elemental  *a = (Mat_Elemental*)A->data;
144   PetscMPIInt    rank;
145   PetscInt       i,j,rrank,ridx,crank,cidx;
146 
147   PetscFunctionBegin;
148   ierr = MPI_Comm_rank(((PetscObject)A)->comm,&rank);CHKERRQ(ierr);
149 
150   const elem::Grid &grid = a->emat->Grid();
151   for (i=0; i<nr; i++) {
152     PetscInt erow,ecol,elrow,elcol;
153     if (rows[i] < 0) continue;
154     P2RO(A,0,rows[i],&rrank,&ridx);
155     RO2E(A,0,rrank,ridx,&erow);
156     if (rrank < 0 || ridx < 0 || erow < 0) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_PLIB,"Incorrect row translation");
157     for (j=0; j<nc; j++) {
158       if (cols[j] < 0) continue;
159       P2RO(A,1,cols[j],&crank,&cidx);
160       RO2E(A,1,crank,cidx,&ecol);
161       if (crank < 0 || cidx < 0 || ecol < 0) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_PLIB,"Incorrect col translation");
162       if (erow % grid.MCSize() != grid.MCRank() || ecol % grid.MRSize() != grid.MRRank()){ /* off-proc entry */
163         if (imode != ADD_VALUES) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Only ADD_VALUES to off-processor entry is supported");
164         /* 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); */
165         a->esubmat->Set(0,0, vals[i*nc+j]);
166         a->interface->Axpy(1.0,*(a->esubmat),erow,ecol);
167         continue;
168       }
169       elrow = erow / grid.MCSize();
170       elcol = ecol / grid.MRSize();
171       switch (imode) {
172       case INSERT_VALUES: a->emat->SetLocal(elrow,elcol,vals[i*nc+j]); break;
173       case ADD_VALUES: a->emat->UpdateLocal(elrow,elcol,vals[i*nc+j]); break;
174       default: SETERRQ1(((PetscObject)A)->comm,PETSC_ERR_SUP,"No support for InsertMode %d",(int)imode);
175       }
176     }
177   }
178   PetscFunctionReturn(0);
179 }
180 
181 #undef __FUNCT__
182 #define __FUNCT__ "MatMult_Elemental"
183 static PetscErrorCode MatMult_Elemental(Mat A,Vec X,Vec Y)
184 {
185   Mat_Elemental     *a = (Mat_Elemental*)A->data;
186   PetscErrorCode    ierr;
187   const PetscElemScalar *x;
188   PetscElemScalar       *y;
189   PetscElemScalar       one = 1,zero = 0;
190 
191   PetscFunctionBegin;
192   ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
193   ierr = VecGetArray(Y,&y);CHKERRQ(ierr);
194   { /* Scoping so that constructor is called before pointer is returned */
195     elem::DistMatrix<PetscElemScalar,elem::VC,elem::STAR> xe(A->cmap->N,1,0,x,A->cmap->n,*a->grid);
196     elem::DistMatrix<PetscElemScalar,elem::VC,elem::STAR> ye(A->rmap->N,1,0,y,A->rmap->n,*a->grid);
197     elem::Gemv(elem::NORMAL,one,*a->emat,xe,zero,ye);
198   }
199   ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
200   ierr = VecRestoreArray(Y,&y);CHKERRQ(ierr);
201   PetscFunctionReturn(0);
202 }
203 
204 #undef __FUNCT__
205 #define __FUNCT__ "MatMultTranspose_Elemental"
206 static PetscErrorCode MatMultTranspose_Elemental(Mat A,Vec X,Vec Y)
207 {
208   Mat_Elemental     *a = (Mat_Elemental*)A->data;
209   PetscErrorCode    ierr;
210   const PetscElemScalar *x;
211   PetscElemScalar       *y;
212   PetscScalar       one = 1,zero = 0;
213 
214   PetscFunctionBegin;
215   ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
216   ierr = VecGetArray(Y,&y);CHKERRQ(ierr);
217   { /* Scoping so that constructor is called before pointer is returned */
218     elem::DistMatrix<PetscElemScalar,elem::VC,elem::STAR> xe(A->rmap->N,1,0,x,A->rmap->n,*a->grid);
219     elem::DistMatrix<PetscElemScalar,elem::VC,elem::STAR> ye(A->cmap->N,1,0,y,A->cmap->n,*a->grid);
220     elem::Gemv(elem::TRANSPOSE,one,*a->emat,xe,zero,ye);
221   }
222   ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
223   ierr = VecRestoreArray(Y,&y);CHKERRQ(ierr);
224   PetscFunctionReturn(0);
225 }
226 
227 #undef __FUNCT__
228 #define __FUNCT__ "MatMultAdd_Elemental"
229 static PetscErrorCode MatMultAdd_Elemental(Mat A,Vec X,Vec Y,Vec Z)
230 {
231   Mat_Elemental     *a = (Mat_Elemental*)A->data;
232   PetscErrorCode    ierr;
233   const PetscElemScalar *x;
234   PetscElemScalar       *z;
235   PetscScalar       one = 1.0;
236 
237   PetscFunctionBegin;
238   if (Y != Z) {ierr = VecCopy(Y,Z);CHKERRQ(ierr);}
239   ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
240   ierr = VecGetArray(Z,&z);CHKERRQ(ierr);
241   { /* Scoping so that constructor is called before pointer is returned */
242     elem::DistMatrix<PetscElemScalar,elem::VC,elem::STAR> xe(A->cmap->N,1,0,x,A->cmap->n,*a->grid);
243     elem::DistMatrix<PetscElemScalar,elem::VC,elem::STAR> ze(A->rmap->N,1,0,z,A->rmap->n,*a->grid);
244     elem::Gemv(elem::NORMAL,one,*a->emat,xe,one,ze);
245   }
246   ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
247   ierr = VecRestoreArray(Z,&z);CHKERRQ(ierr);
248   PetscFunctionReturn(0);
249 }
250 
251 #undef __FUNCT__
252 #define __FUNCT__ "MatMultTransposeAdd_Elemental"
253 static PetscErrorCode MatMultTransposeAdd_Elemental(Mat A,Vec X,Vec Y,Vec Z)
254 {
255   Mat_Elemental     *a = (Mat_Elemental*)A->data;
256   PetscErrorCode    ierr;
257   const PetscElemScalar *x;
258   PetscElemScalar       *z;
259   PetscScalar       one = 1.0;
260 
261   PetscFunctionBegin;
262   if (Y != Z) {ierr = VecCopy(Y,Z);CHKERRQ(ierr);}
263   ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
264   ierr = VecGetArray(Z,&z);CHKERRQ(ierr);
265   { /* Scoping so that constructor is called before pointer is returned */
266     elem::DistMatrix<PetscElemScalar,elem::VC,elem::STAR> xe(A->rmap->N,1,0,x,A->rmap->n,*a->grid);
267     elem::DistMatrix<PetscElemScalar,elem::VC,elem::STAR> ze(A->cmap->N,1,0,z,A->cmap->n,*a->grid);
268     elem::Gemv(elem::TRANSPOSE,one,*a->emat,xe,one,ze);
269   }
270   ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
271   ierr = VecRestoreArray(Z,&z);CHKERRQ(ierr);
272   PetscFunctionReturn(0);
273 }
274 
275 #undef __FUNCT__
276 #define __FUNCT__ "MatMatMultNumeric_Elemental"
277 static PetscErrorCode MatMatMultNumeric_Elemental(Mat A,Mat B,Mat C)
278 {
279   Mat_Elemental  *a = (Mat_Elemental*)A->data;
280   Mat_Elemental  *b = (Mat_Elemental*)B->data;
281   Mat_Elemental  *c = (Mat_Elemental*)C->data;
282   PetscScalar    one = 1.0,zero = 0.0;
283 
284   PetscFunctionBegin;
285   { /* Scoping so that constructor is called before pointer is returned */
286     elem::Gemm(elem::NORMAL,elem::NORMAL,one,*a->emat,*b->emat,zero,*c->emat);
287   }
288   C->assembled = PETSC_TRUE;
289   PetscFunctionReturn(0);
290 }
291 
292 #undef __FUNCT__
293 #define __FUNCT__ "MatMatMultSymbolic_Elemental"
294 static PetscErrorCode MatMatMultSymbolic_Elemental(Mat A,Mat B,PetscReal fill,Mat *C)
295 {
296   PetscErrorCode ierr;
297   Mat            Ce;
298   MPI_Comm       comm=((PetscObject)A)->comm;
299 
300   PetscFunctionBegin;
301   ierr = MatCreate(comm,&Ce);CHKERRQ(ierr);
302   ierr = MatSetSizes(Ce,A->rmap->n,B->cmap->n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
303   ierr = MatSetType(Ce,MATELEMENTAL);CHKERRQ(ierr);
304   ierr = MatSetUp(Ce);CHKERRQ(ierr);
305   *C = Ce;
306   PetscFunctionReturn(0);
307 }
308 
309 #undef __FUNCT__
310 #define __FUNCT__ "MatMatMult_Elemental"
311 static PetscErrorCode MatMatMult_Elemental(Mat A,Mat B,MatReuse scall,PetscReal fill,Mat *C)
312 {
313   PetscErrorCode ierr;
314 
315   PetscFunctionBegin;
316   if (scall == MAT_INITIAL_MATRIX){
317     ierr = PetscLogEventBegin(MAT_MatMultSymbolic,A,B,0,0);CHKERRQ(ierr);
318     ierr = MatMatMultSymbolic_Elemental(A,B,1.0,C);CHKERRQ(ierr);
319     ierr = PetscLogEventEnd(MAT_MatMultSymbolic,A,B,0,0);CHKERRQ(ierr);
320   }
321   ierr = PetscLogEventBegin(MAT_MatMultNumeric,A,B,0,0);CHKERRQ(ierr);
322   ierr = MatMatMultNumeric_Elemental(A,B,*C);CHKERRQ(ierr);
323   ierr = PetscLogEventEnd(MAT_MatMultNumeric,A,B,0,0);CHKERRQ(ierr);
324   PetscFunctionReturn(0);
325 }
326 
327 #undef __FUNCT__
328 #define __FUNCT__ "MatMatTransposeMultNumeric_Elemental"
329 static PetscErrorCode MatMatTransposeMultNumeric_Elemental(Mat A,Mat B,Mat C)
330 {
331   Mat_Elemental  *a = (Mat_Elemental*)A->data;
332   Mat_Elemental  *b = (Mat_Elemental*)B->data;
333   Mat_Elemental  *c = (Mat_Elemental*)C->data;
334   PetscScalar    one = 1.0,zero = 0.0;
335 
336   PetscFunctionBegin;
337   { /* Scoping so that constructor is called before pointer is returned */
338     elem::Gemm(elem::NORMAL,elem::TRANSPOSE,one,*a->emat,*b->emat,zero,*c->emat);
339   }
340   C->assembled = PETSC_TRUE;
341   PetscFunctionReturn(0);
342 }
343 
344 #undef __FUNCT__
345 #define __FUNCT__ "MatMatTransposeMultSymbolic_Elemental"
346 static PetscErrorCode MatMatTransposeMultSymbolic_Elemental(Mat A,Mat B,PetscReal fill,Mat *C)
347 {
348   PetscErrorCode ierr;
349   Mat            Ce;
350   MPI_Comm       comm=((PetscObject)A)->comm;
351 
352   PetscFunctionBegin;
353   ierr = MatCreate(comm,&Ce);CHKERRQ(ierr);
354   ierr = MatSetSizes(Ce,A->rmap->n,B->rmap->n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
355   ierr = MatSetType(Ce,MATELEMENTAL);CHKERRQ(ierr);
356   ierr = MatSetUp(Ce);CHKERRQ(ierr);
357   *C = Ce;
358   PetscFunctionReturn(0);
359 }
360 
361 #undef __FUNCT__
362 #define __FUNCT__ "MatMatTransposeMult_Elemental"
363 static PetscErrorCode MatMatTransposeMult_Elemental(Mat A,Mat B,MatReuse scall,PetscReal fill,Mat *C)
364 {
365   PetscErrorCode ierr;
366 
367   PetscFunctionBegin;
368   if (scall == MAT_INITIAL_MATRIX){
369     ierr = PetscLogEventBegin(MAT_MatTransposeMultSymbolic,A,B,0,0);CHKERRQ(ierr);
370     ierr = MatMatMultSymbolic_Elemental(A,B,1.0,C);CHKERRQ(ierr);
371     ierr = PetscLogEventEnd(MAT_MatTransposeMultSymbolic,A,B,0,0);CHKERRQ(ierr);
372   }
373   ierr = PetscLogEventBegin(MAT_MatTransposeMultNumeric,A,B,0,0);CHKERRQ(ierr);
374   ierr = MatMatTransposeMultNumeric_Elemental(A,B,*C);CHKERRQ(ierr);
375   ierr = PetscLogEventEnd(MAT_MatTransposeMultNumeric,A,B,0,0);CHKERRQ(ierr);
376   PetscFunctionReturn(0);
377 }
378 
379 #undef __FUNCT__
380 #define __FUNCT__ "MatScale_Elemental"
381 static PetscErrorCode MatScale_Elemental(Mat X,PetscElemScalar a)
382 {
383   Mat_Elemental  *x = (Mat_Elemental*)X->data;
384 
385   PetscFunctionBegin;
386   elem::Scal(a,*x->emat);
387   PetscFunctionReturn(0);
388 }
389 
390 #undef __FUNCT__
391 #define __FUNCT__ "MatAXPY_Elemental"
392 static PetscErrorCode MatAXPY_Elemental(Mat Y,PetscElemScalar a,Mat X,MatStructure str)
393 {
394   Mat_Elemental  *x = (Mat_Elemental*)X->data;
395   Mat_Elemental  *y = (Mat_Elemental*)Y->data;
396 
397   PetscFunctionBegin;
398   elem::Axpy(a,*x->emat,*y->emat);
399   PetscFunctionReturn(0);
400 }
401 
402 #undef __FUNCT__
403 #define __FUNCT__ "MatCopy_Elemental"
404 static PetscErrorCode MatCopy_Elemental(Mat A,Mat B,MatStructure str)
405 {
406   Mat_Elemental *a=(Mat_Elemental*)A->data;
407   Mat_Elemental *b=(Mat_Elemental*)B->data;
408 
409   PetscFunctionBegin;
410   elem::Copy(*a->emat,*b->emat);
411   PetscFunctionReturn(0);
412 }
413 
414 #undef __FUNCT__
415 #define __FUNCT__ "MatDuplicate_Elemental"
416 static PetscErrorCode MatDuplicate_Elemental(Mat A,MatDuplicateOption op,Mat *B)
417 {
418   Mat            Be;
419   MPI_Comm       comm=((PetscObject)A)->comm;
420   Mat_Elemental  *a=(Mat_Elemental*)A->data;
421   PetscErrorCode ierr;
422 
423   PetscFunctionBegin;
424   ierr = MatCreate(comm,&Be);CHKERRQ(ierr);
425   ierr = MatSetSizes(Be,A->rmap->n,A->cmap->n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
426   ierr = MatSetType(Be,MATELEMENTAL);CHKERRQ(ierr);
427   ierr = MatSetUp(Be);CHKERRQ(ierr);
428   *B = Be;
429   if (op == MAT_COPY_VALUES) {
430     Mat_Elemental *b=(Mat_Elemental*)Be->data;
431     elem::Copy(*a->emat,*b->emat);
432   }
433   Be->assembled = PETSC_TRUE;
434   PetscFunctionReturn(0);
435 }
436 
437 #undef __FUNCT__
438 #define __FUNCT__ "MatTranspose_Elemental"
439 static PetscErrorCode MatTranspose_Elemental(Mat A,MatReuse reuse,Mat *B)
440 {
441   /* Only out-of-place supported */
442   Mat            Be;
443   PetscErrorCode ierr;
444   MPI_Comm       comm=((PetscObject)A)->comm;
445   Mat_Elemental  *a = (Mat_Elemental*)A->data, *b;
446 
447   PetscFunctionBegin;
448   if (reuse == MAT_INITIAL_MATRIX){
449     ierr = MatCreate(comm,&Be);CHKERRQ(ierr);
450     ierr = MatSetSizes(Be,A->cmap->n,A->rmap->n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
451     ierr = MatSetType(Be,MATELEMENTAL);CHKERRQ(ierr);
452     ierr = MatSetUp(Be);CHKERRQ(ierr);
453     *B = Be;
454   }
455   b = (Mat_Elemental*)Be->data;
456   elem::Transpose(*a->emat,*b->emat);
457   Be->assembled = PETSC_TRUE;
458   PetscFunctionReturn(0);
459 }
460 
461 #undef __FUNCT__
462 #define __FUNCT__ "MatSolve_Elemental"
463 static PetscErrorCode MatSolve_Elemental(Mat A,Vec B,Vec X)
464 {
465   Mat_Elemental     *a = (Mat_Elemental*)A->data;
466   PetscErrorCode    ierr;
467   PetscElemScalar       *x;
468 
469   PetscFunctionBegin;
470   ierr = VecCopy(B,X);CHKERRQ(ierr);
471   ierr = VecGetArray(X,&x);CHKERRQ(ierr);
472   elem::DistMatrix<PetscElemScalar,elem::VC,elem::STAR> xe(A->rmap->N,1,0,x,A->rmap->n,*a->grid);
473   elem::DistMatrix<PetscElemScalar,elem::MC,elem::MR> xer = xe;
474   switch (A->factortype) {
475   case MAT_FACTOR_LU:
476     if ((*a->pivot).AllocatedMemory()) {
477       elem::SolveAfterLU(elem::NORMAL,*a->emat,*a->pivot,xer);
478       elem::Copy(xer,xe);
479     } else {
480       elem::SolveAfterLU(elem::NORMAL,*a->emat,xer);
481       elem::Copy(xer,xe);
482     }
483     break;
484   case MAT_FACTOR_CHOLESKY:
485     elem::SolveAfterCholesky(elem::UPPER,elem::NORMAL,*a->emat,xer);
486     elem::Copy(xer,xe);
487     break;
488   default:
489     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unfactored Matrix or Unsupported MatFactorType");
490     break;
491   }
492   ierr = VecRestoreArray(X,&x);CHKERRQ(ierr);
493   PetscFunctionReturn(0);
494 }
495 
496 #undef __FUNCT__
497 #define __FUNCT__ "MatSolveAdd_Elemental"
498 static PetscErrorCode MatSolveAdd_Elemental(Mat A,Vec B,Vec Y,Vec X)
499 {
500   PetscErrorCode    ierr;
501 
502   PetscFunctionBegin;
503   ierr = MatSolve_Elemental(A,B,X);CHKERRQ(ierr);
504   ierr = VecAXPY(X,1.0,Y);CHKERRQ(ierr);
505   PetscFunctionReturn(0);
506 }
507 
508 #undef __FUNCT__
509 #define __FUNCT__ "MatMatSolve_Elemental"
510 static PetscErrorCode MatMatSolve_Elemental(Mat A,Mat B,Mat X)
511 {
512   Mat_Elemental *a=(Mat_Elemental*)A->data;
513   Mat_Elemental *b=(Mat_Elemental*)B->data;
514   Mat_Elemental *x=(Mat_Elemental*)X->data;
515 
516   PetscFunctionBegin;
517   elem::Copy(*b->emat,*x->emat);
518   switch (A->factortype) {
519   case MAT_FACTOR_LU:
520     if ((*a->pivot).AllocatedMemory()) {
521       elem::SolveAfterLU(elem::NORMAL,*a->emat,*a->pivot,*x->emat);
522     } else {
523       elem::SolveAfterLU(elem::NORMAL,*a->emat,*x->emat);
524     }
525     break;
526   case MAT_FACTOR_CHOLESKY:
527     elem::SolveAfterCholesky(elem::UPPER,elem::NORMAL,*a->emat,*x->emat);
528     break;
529   default:
530     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unfactored Matrix or Unsupported MatFactorType");
531     break;
532   }
533   PetscFunctionReturn(0);
534 }
535 
536 #undef __FUNCT__
537 #define __FUNCT__ "MatLUFactor_Elemental"
538 static PetscErrorCode MatLUFactor_Elemental(Mat A,IS row,IS col,const MatFactorInfo *info)
539 {
540   Mat_Elemental  *a = (Mat_Elemental*)A->data;
541 
542   PetscFunctionBegin;
543   if (info->dtcol){
544     elem::LU(*a->emat,*a->pivot);
545   } else {
546     elem::LU(*a->emat);
547   }
548   A->factortype = MAT_FACTOR_LU;
549   A->assembled  = PETSC_TRUE;
550   PetscFunctionReturn(0);
551 }
552 
553 #undef __FUNCT__
554 #define __FUNCT__ "MatLUFactorNumeric_Elemental"
555 static PetscErrorCode  MatLUFactorNumeric_Elemental(Mat F,Mat A,const MatFactorInfo *info)
556 {
557   PetscErrorCode ierr;
558 
559   PetscFunctionBegin;
560   ierr = MatCopy(A,F,SAME_NONZERO_PATTERN);CHKERRQ(ierr);
561   ierr = MatLUFactor_Elemental(F,0,0,info);CHKERRQ(ierr);
562   PetscFunctionReturn(0);
563 }
564 
565 #undef __FUNCT__
566 #define __FUNCT__ "MatLUFactorSymbolic_Elemental"
567 static PetscErrorCode  MatLUFactorSymbolic_Elemental(Mat F,Mat A,IS r,IS c,const MatFactorInfo *info)
568 {
569   PetscFunctionBegin;
570   /* F is create and allocated by MatGetFactor_elemental_petsc(), skip this routine. */
571   PetscFunctionReturn(0);
572 }
573 
574 #undef __FUNCT__
575 #define __FUNCT__ "MatCholeskyFactor_Elemental"
576 static PetscErrorCode MatCholeskyFactor_Elemental(Mat A,IS perm,const MatFactorInfo *info)
577 {
578   Mat_Elemental  *a = (Mat_Elemental*)A->data;
579   elem::DistMatrix<PetscElemScalar,elem::MC,elem::STAR> d;
580 
581   PetscFunctionBegin;
582   elem::Cholesky(elem::UPPER,*a->emat);
583   // if (info->dtcol){
584   //   /* A = U^T * U for SPD Matrix A */
585   //   printf("Cholesky Factorization for SPD Matrices...\n");
586   //   elem::Cholesky(elem::UPPER,*a->emat);
587   // } else {
588   //   /* A = U^T * D * U * for Symmetric Matrix A */
589   //   printf("LDL^T Factorization for Symmetric Matrices.\n");
590   //   printf("This routine does not pivot. Use with caution.\n");
591   //   elem::LDLT(*a->emat,d);
592   // }
593   A->factortype = MAT_FACTOR_CHOLESKY;
594   A->assembled  = PETSC_TRUE;
595   PetscFunctionReturn(0);
596 }
597 
598 #undef __FUNCT__
599 #define __FUNCT__ "MatCholeskyFactorNumeric_Elemental"
600 static PetscErrorCode MatCholeskyFactorNumeric_Elemental(Mat F,Mat A,const MatFactorInfo *info)
601 {
602   PetscErrorCode ierr;
603 
604   PetscFunctionBegin;
605   ierr = MatCopy(A,F,SAME_NONZERO_PATTERN);CHKERRQ(ierr);
606   ierr = MatCholeskyFactor_Elemental(F,0,info);CHKERRQ(ierr);
607   PetscFunctionReturn(0);
608 }
609 
610 #undef __FUNCT__
611 #define __FUNCT__ "MatCholeskyFactorSymbolic_Elemental"
612 static PetscErrorCode MatCholeskyFactorSymbolic_Elemental(Mat F,Mat A,IS perm,const MatFactorInfo *info)
613 {
614   PetscFunctionBegin;
615   /* F is create and allocated by MatGetFactor_elemental_petsc(), skip this routine. */
616   PetscFunctionReturn(0);
617 }
618 
619 #undef __FUNCT__
620 #define __FUNCT__ "MatGetFactor_elemental_petsc"
621 PETSC_EXTERN_C PetscErrorCode MatGetFactor_elemental_petsc(Mat A,MatFactorType ftype,Mat *F)
622 {
623   Mat            B;
624   PetscErrorCode ierr;
625 
626   PetscFunctionBegin;
627   /* Create the factorization matrix */
628   ierr = MatCreate(((PetscObject)A)->comm,&B);CHKERRQ(ierr);
629   ierr = MatSetSizes(B,A->rmap->n,A->cmap->n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
630   ierr = MatSetType(B,MATELEMENTAL);CHKERRQ(ierr);
631   ierr = MatSetUp(B);CHKERRQ(ierr);
632   B->factortype = ftype;
633   *F            = B;
634   PetscFunctionReturn(0);
635 }
636 
637 #undef __FUNCT__
638 #define __FUNCT__ "MatNorm_Elemental"
639 static PetscErrorCode MatNorm_Elemental(Mat A,NormType type,PetscReal *nrm)
640 {
641   Mat_Elemental *a=(Mat_Elemental*)A->data;
642 
643   PetscFunctionBegin;
644   switch (type){
645   case NORM_1:
646     *nrm = elem::Norm(*a->emat,elem::ONE_NORM);
647     break;
648   case NORM_FROBENIUS:
649     *nrm = elem::Norm(*a->emat,elem::FROBENIUS_NORM);
650     break;
651   case NORM_INFINITY:
652     *nrm = elem::Norm(*a->emat,elem::INFINITY_NORM);
653     break;
654   default:
655     printf("Error: unsupported norm type!\n");
656   }
657   PetscFunctionReturn(0);
658 }
659 
660 #undef __FUNCT__
661 #define __FUNCT__ "MatZeroEntries_Elemental"
662 static PetscErrorCode MatZeroEntries_Elemental(Mat A)
663 {
664   Mat_Elemental *a=(Mat_Elemental*)A->data;
665 
666   PetscFunctionBegin;
667   elem::Zero(*a->emat);
668   PetscFunctionReturn(0);
669 }
670 
671 EXTERN_C_BEGIN
672 #undef __FUNCT__
673 #define __FUNCT__ "MatGetOwnershipIS_Elemental"
674 static PetscErrorCode MatGetOwnershipIS_Elemental(Mat A,IS *rows,IS *cols)
675 {
676   Mat_Elemental  *a = (Mat_Elemental*)A->data;
677   PetscErrorCode ierr;
678   PetscInt       i,m,shift,stride,*idx;
679 
680   PetscFunctionBegin;
681   if (rows) {
682     m = a->emat->LocalHeight();
683     shift = a->emat->ColShift();
684     stride = a->emat->ColStride();
685     ierr = PetscMalloc(m*sizeof(PetscInt),&idx);CHKERRQ(ierr);
686     for (i=0; i<m; i++) {
687       PetscInt rank,offset;
688       E2RO(A,0,shift+i*stride,&rank,&offset);
689       RO2P(A,0,rank,offset,&idx[i]);
690     }
691     ierr = ISCreateGeneral(PETSC_COMM_SELF,m,idx,PETSC_OWN_POINTER,rows);CHKERRQ(ierr);
692   }
693   if (cols) {
694     m = a->emat->LocalWidth();
695     shift = a->emat->RowShift();
696     stride = a->emat->RowStride();
697     ierr = PetscMalloc(m*sizeof(PetscInt),&idx);CHKERRQ(ierr);
698     for (i=0; i<m; i++) {
699       PetscInt rank,offset;
700       E2RO(A,1,shift+i*stride,&rank,&offset);
701       RO2P(A,1,rank,offset,&idx[i]);
702     }
703     ierr = ISCreateGeneral(PETSC_COMM_SELF,m,idx,PETSC_OWN_POINTER,cols);CHKERRQ(ierr);
704   }
705   PetscFunctionReturn(0);
706 }
707 EXTERN_C_END
708 
709 #undef __FUNCT__
710 #define __FUNCT__ "MatConvert_Elemental_Dense"
711 static PetscErrorCode MatConvert_Elemental_Dense(Mat A,const MatType newtype,MatReuse reuse,Mat *B)
712 {
713   Mat                Bmpi;
714   Mat_Elemental      *a = (Mat_Elemental*)A->data;
715   MPI_Comm           comm=((PetscObject)A)->comm;
716   PetscErrorCode     ierr;
717   PetscInt           rrank,ridx,crank,cidx,nrows,ncols,i,j;
718   PetscElemScalar        v;
719 
720   PetscFunctionBegin;
721   if (strcmp(newtype,MATDENSE) && strcmp(newtype,MATSEQDENSE) && strcmp(newtype,MATMPIDENSE)) {
722     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unsupported New MatType: must be MATDENSE, MATSEQDENSE or MATMPIDENSE");
723   }
724   if (1){
725     ierr = MatCreate(comm,&Bmpi);CHKERRQ(ierr);
726     ierr = MatSetSizes(Bmpi,A->rmap->n,A->cmap->n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
727     ierr = MatSetType(Bmpi,MATDENSE);CHKERRQ(ierr);
728     ierr = MatSetUp(Bmpi);CHKERRQ(ierr);
729   }
730   ierr = MatGetSize(A,&nrows,&ncols);CHKERRQ(ierr);
731   for (i=0; i<nrows; i++) {
732     PetscInt erow,ecol;
733     P2RO(A,0,i,&rrank,&ridx);
734     RO2E(A,0,rrank,ridx,&erow);
735     if (rrank < 0 || ridx < 0 || erow < 0) SETERRQ(comm,PETSC_ERR_PLIB,"Incorrect row translation");
736     for (j=0; j<ncols; j++) {
737       P2RO(A,1,j,&crank,&cidx);
738       RO2E(A,1,crank,cidx,&ecol);
739       if (crank < 0 || cidx < 0 || ecol < 0) SETERRQ(comm,PETSC_ERR_PLIB,"Incorrect col translation");
740       v = a->emat->Get(erow,ecol);
741       ierr = MatSetValues(Bmpi,1,&i,1,&j,&v,INSERT_VALUES);CHKERRQ(ierr);
742     }
743   }
744   ierr = MatAssemblyBegin(Bmpi,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
745   ierr = MatAssemblyEnd(Bmpi,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
746   if (reuse == MAT_REUSE_MATRIX) {
747     //*B = Bmpi;
748     //MatDestroy(&A);
749     ierr = MatHeaderReplace(A,Bmpi);CHKERRQ(ierr);
750   } else {
751     *B = Bmpi;
752   }
753   PetscFunctionReturn(0);
754 }
755 
756 #undef __FUNCT__
757 #define __FUNCT__ "MatDestroy_Elemental"
758 static PetscErrorCode MatDestroy_Elemental(Mat A)
759 {
760   Mat_Elemental      *a = (Mat_Elemental*)A->data;
761   PetscErrorCode     ierr;
762   Mat_Elemental_Grid *commgrid;
763   PetscBool          flg;
764   MPI_Comm           icomm;
765 
766   PetscFunctionBegin;
767   a->interface->Detach();
768   delete a->interface;
769   delete a->esubmat;
770   delete a->emat;
771 
772   elem::mpi::Comm cxxcomm(((PetscObject)A)->comm);
773   ierr = PetscCommDuplicate(cxxcomm,&icomm,PETSC_NULL);CHKERRQ(ierr);
774   ierr = MPI_Attr_get(icomm,Petsc_Elemental_keyval,(void**)&commgrid,(int*)&flg);CHKERRQ(ierr);
775   if (--commgrid->grid_refct == 0) {
776     delete commgrid->grid;
777     ierr = PetscFree(commgrid);CHKERRQ(ierr);
778   }
779   ierr = PetscCommDestroy(&icomm);CHKERRQ(ierr);
780   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatGetOwnershipIS_C","",PETSC_NULL);CHKERRQ(ierr);
781   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatGetFactor_petsc_C","",PETSC_NULL);CHKERRQ(ierr);
782   ierr = PetscFree(A->data);CHKERRQ(ierr);
783   PetscFunctionReturn(0);
784 }
785 
786 #undef __FUNCT__
787 #define __FUNCT__ "MatSetUp_Elemental"
788 PetscErrorCode MatSetUp_Elemental(Mat A)
789 {
790   Mat_Elemental  *a = (Mat_Elemental*)A->data;
791   PetscErrorCode ierr;
792   PetscMPIInt    rsize,csize;
793 
794   PetscFunctionBegin;
795   ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr);
796   ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr);
797 
798   a->emat->ResizeTo(A->rmap->N,A->cmap->N);CHKERRQ(ierr);
799   elem::Zero(*a->emat);
800 
801   ierr = MPI_Comm_size(A->rmap->comm,&rsize);CHKERRQ(ierr);
802   ierr = MPI_Comm_size(A->cmap->comm,&csize);CHKERRQ(ierr);
803   if (csize != rsize) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_INCOMP,"Cannot use row and column communicators of different sizes");
804   a->commsize = rsize;
805   a->mr[0] = A->rmap->N % rsize; if (!a->mr[0]) a->mr[0] = rsize;
806   a->mr[1] = A->cmap->N % csize; if (!a->mr[1]) a->mr[1] = csize;
807   a->m[0] = A->rmap->N / rsize + (a->mr[0] != rsize);
808   a->m[1] = A->cmap->N / csize + (a->mr[1] != csize);
809   PetscFunctionReturn(0);
810 }
811 
812 #undef __FUNCT__
813 #define __FUNCT__ "MatAssemblyBegin_Elemental"
814 PetscErrorCode MatAssemblyBegin_Elemental(Mat A, MatAssemblyType type)
815 {
816   Mat_Elemental  *a = (Mat_Elemental*)A->data;
817 
818   PetscFunctionBegin;
819   a->interface->Detach();
820   a->interface->Attach(elem::LOCAL_TO_GLOBAL,*(a->emat));
821   PetscFunctionReturn(0);
822 }
823 
824 #undef __FUNCT__
825 #define __FUNCT__ "MatAssemblyEnd_Elemental"
826 PetscErrorCode MatAssemblyEnd_Elemental(Mat A, MatAssemblyType type)
827 {
828   PetscFunctionBegin;
829   /* Currently does nothing */
830   PetscFunctionReturn(0);
831 }
832 
833 /* -------------------------------------------------------------------*/
834 static struct _MatOps MatOps_Values = {
835        MatSetValues_Elemental,
836        0,
837        0,
838        MatMult_Elemental,
839 /* 4*/ MatMultAdd_Elemental,
840        MatMultTranspose_Elemental,
841        MatMultTransposeAdd_Elemental,
842        MatSolve_Elemental,
843        MatSolveAdd_Elemental,
844        0, //MatSolveTranspose_Elemental,
845 /*10*/ 0, //MatSolveTransposeAdd_Elemental,
846        MatLUFactor_Elemental,
847        MatCholeskyFactor_Elemental,
848        0,
849        MatTranspose_Elemental,
850 /*15*/ MatGetInfo_Elemental,
851        0,
852        0,
853        0,
854        MatNorm_Elemental,
855 /*20*/ MatAssemblyBegin_Elemental,
856        MatAssemblyEnd_Elemental,
857        0, //MatSetOption_Elemental,
858        MatZeroEntries_Elemental,
859 /*24*/ 0,
860        MatLUFactorSymbolic_Elemental,
861        MatLUFactorNumeric_Elemental,
862        MatCholeskyFactorSymbolic_Elemental,
863        MatCholeskyFactorNumeric_Elemental,
864 /*29*/ MatSetUp_Elemental,
865        0,
866        0,
867        0,
868        0,
869 /*34*/ MatDuplicate_Elemental,
870        0,
871        0,
872        0,
873        0,
874 /*39*/ MatAXPY_Elemental,
875        0,
876        0,
877        0,
878        MatCopy_Elemental,
879 /*44*/ 0,
880        MatScale_Elemental,
881        0,
882        0,
883        0,
884 /*49*/ 0,
885        0,
886        0,
887        0,
888        0,
889 /*54*/ 0,
890        0,
891        0,
892        0,
893        0,
894 /*59*/ 0,
895        MatDestroy_Elemental,
896        MatView_Elemental,
897        0,
898        0,
899 /*64*/ 0,
900        0,
901        0,
902        0,
903        0,
904 /*69*/ 0,
905        0,
906        MatConvert_Elemental_Dense,
907        0,
908        0,
909 /*74*/ 0,
910        0,
911        0,
912        0,
913        0,
914 /*79*/ 0,
915        0,
916        0,
917        0,
918        0,
919 /*84*/ 0,
920        0,
921        0,
922        0,
923        0,
924 /*89*/ MatMatMult_Elemental,
925        MatMatMultSymbolic_Elemental,
926        MatMatMultNumeric_Elemental,
927        0,
928        0,
929 /*94*/ 0,
930        MatMatTransposeMult_Elemental,
931        MatMatTransposeMultSymbolic_Elemental,
932        MatMatTransposeMultNumeric_Elemental,
933        0,
934 /*99*/ 0,
935        0,
936        0,
937        0,
938        0,
939 /*104*/0,
940        0,
941        0,
942        0,
943        0,
944 /*109*/MatMatSolve_Elemental,
945        0,
946        0,
947        0,
948        0,
949 /*114*/0,
950        0,
951        0,
952        0,
953        0,
954 /*119*/0,
955        0,
956        0,
957        0,
958        0,
959 /*124*/0,
960        0,
961        0,
962        0,
963        0,
964 /*129*/0,
965        0,
966        0,
967        0,
968        0,
969 /*134*/0,
970        0,
971        0,
972        0,
973        0
974 };
975 
976 /*MC
977    MATELEMENTAL = "elemental" - A matrix type for dense matrices using the Elemental package
978 
979    Options Database Keys:
980 . -mat_type elemental - sets the matrix type to "elemental" during a call to MatSetFromOptions()
981 
982   Level: beginner
983 
984 .seealso: MATDENSE,MatCreateElemental()
985 M*/
986 EXTERN_C_BEGIN
987 #undef __FUNCT__
988 #define __FUNCT__ "MatCreate_Elemental"
989 PETSC_EXTERN_C PetscErrorCode MatCreate_Elemental(Mat A)
990 {
991   Mat_Elemental      *a;
992   PetscErrorCode     ierr;
993   PetscBool          flg,flg1,flg2;
994   Mat_Elemental_Grid *commgrid;
995   MPI_Comm           icomm;
996   PetscInt           optv1,optv2;
997 
998   PetscFunctionBegin;
999   ierr = PetscElementalInitializePackage(PETSC_NULL);CHKERRQ(ierr);
1000   ierr = PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr);
1001   A->insertmode = NOT_SET_VALUES;
1002 
1003   ierr = PetscNewLog(A,Mat_Elemental,&a);CHKERRQ(ierr);
1004   A->data = (void*)a;
1005 
1006   /* Set up the elemental matrix */
1007   elem::mpi::Comm cxxcomm(((PetscObject)A)->comm);
1008   ierr = PetscOptionsBegin(((PetscObject)A)->comm,((PetscObject)A)->prefix,"Elemental Options","Mat");CHKERRQ(ierr);
1009 
1010   /* Grid needs to be shared between multiple Mats on the same communicator, implement by attribute caching on the MPI_Comm */
1011   if (Petsc_Elemental_keyval == MPI_KEYVAL_INVALID) {
1012     ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,MPI_NULL_DELETE_FN,&Petsc_Elemental_keyval,(void*)0);
1013   }
1014   ierr = PetscCommDuplicate(cxxcomm,&icomm,PETSC_NULL);CHKERRQ(ierr);
1015   ierr = MPI_Attr_get(icomm,Petsc_Elemental_keyval,(void**)&commgrid,(int*)&flg);CHKERRQ(ierr);
1016   if (!flg) {
1017     ierr = PetscNewLog(A,Mat_Elemental_Grid,&commgrid);CHKERRQ(ierr);
1018     ierr = PetscOptionsInt("-mat_elemental_grid_height","Grid Height","None",elem::mpi::CommSize(cxxcomm),&optv1,&flg1);CHKERRQ(ierr);
1019     ierr = PetscOptionsInt("-mat_elemental_grid_width","Grid Width","None",1,&optv2,&flg2);CHKERRQ(ierr);
1020     if (flg1 || flg2) {
1021       if (optv1*optv2 != elem::mpi::CommSize(cxxcomm)) {
1022         SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_INCOMP,"Grid Height times Grid Width must equal CommSize");
1023       }
1024       commgrid->grid = new elem::Grid(cxxcomm,optv1,optv2);
1025     } else {
1026       commgrid->grid = new elem::Grid(cxxcomm);
1027     }
1028     commgrid->grid_refct = 1;
1029     ierr = MPI_Attr_put(icomm,Petsc_Elemental_keyval,(void*)commgrid);CHKERRQ(ierr);
1030   } else {
1031     commgrid->grid_refct++;
1032   }
1033   ierr = PetscCommDestroy(&icomm);CHKERRQ(ierr);
1034   a->grid      = commgrid->grid;
1035   a->emat      = new elem::DistMatrix<PetscElemScalar>(*a->grid);
1036   a->esubmat   = new elem::Matrix<PetscElemScalar>(1,1);
1037   a->interface = new elem::AxpyInterface<PetscElemScalar>;
1038   a->pivot     = new elem::DistMatrix<PetscInt,elem::VC,elem::STAR>;
1039 
1040   /* build cache for off array entries formed */
1041   a->interface->Attach(elem::LOCAL_TO_GLOBAL,*(a->emat));
1042 
1043   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatGetOwnershipIS_C","MatGetOwnershipIS_Elemental",MatGetOwnershipIS_Elemental);CHKERRQ(ierr);
1044   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatGetFactor_petsc_C","MatGetFactor_elemental_petsc",MatGetFactor_elemental_petsc);CHKERRQ(ierr);
1045 
1046   ierr = PetscObjectChangeTypeName((PetscObject)A,MATELEMENTAL);CHKERRQ(ierr);
1047   PetscOptionsEnd();
1048   PetscFunctionReturn(0);
1049 }
1050 EXTERN_C_END
1051