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