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