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