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