xref: /petsc/src/mat/impls/hypre/mhypre.c (revision 65f8aed5f7eaa1e2ef2ddeffe666264e0669c876)
1 
2 /*
3     Creates hypre ijmatrix from PETSc matrix
4 */
5 
6 #include <petscmathypre.h>
7 #include <petsc/private/matimpl.h>
8 #include <../src/mat/impls/hypre/mhypre.h>
9 #include <../src/mat/impls/aij/mpi/mpiaij.h>
10 #include <../src/vec/vec/impls/hypre/vhyp.h>
11 #include <HYPRE.h>
12 #include <HYPRE_utilities.h>
13 #include <_hypre_parcsr_ls.h>
14 #include <_hypre_sstruct_ls.h>
15 
16 PETSC_INTERN PetscErrorCode MatPtAP_IS_XAIJ(Mat,Mat,MatReuse,PetscReal,Mat*);
17 
18 static PetscErrorCode MatHYPRE_CreateFromMat(Mat,Mat_HYPRE*);
19 static PetscErrorCode MatHYPRE_IJMatrixPreallocate(Mat,Mat,HYPRE_IJMatrix);
20 static PetscErrorCode MatHYPRE_IJMatrixFastCopy_MPIAIJ(Mat,HYPRE_IJMatrix);
21 static PetscErrorCode MatHYPRE_IJMatrixFastCopy_SeqAIJ(Mat,HYPRE_IJMatrix);
22 static PetscErrorCode MatHYPRE_MultKernel_Private(Mat,Vec,Vec,PetscBool);
23 static PetscErrorCode hypre_array_destroy(void*);
24 PetscErrorCode MatSetValues_HYPRE(Mat, PetscInt,const PetscInt[],PetscInt,const PetscInt[],const PetscScalar[],InsertMode ins);
25 
26 static PetscErrorCode MatHYPRE_IJMatrixPreallocate(Mat A_d, Mat A_o, HYPRE_IJMatrix ij)
27 {
28   PetscErrorCode ierr;
29   PetscInt       i,n_d,n_o;
30   const PetscInt *ia_d,*ia_o;
31   PetscBool      done_d=PETSC_FALSE,done_o=PETSC_FALSE;
32   PetscInt       *nnz_d=NULL,*nnz_o=NULL;
33 
34   PetscFunctionBegin;
35   if (A_d) { /* determine number of nonzero entries in local diagonal part */
36     ierr = MatGetRowIJ(A_d,0,PETSC_FALSE,PETSC_FALSE,&n_d,&ia_d,NULL,&done_d);CHKERRQ(ierr);
37     if (done_d) {
38       ierr = PetscMalloc1(n_d,&nnz_d);CHKERRQ(ierr);
39       for (i=0; i<n_d; i++) {
40         nnz_d[i] = ia_d[i+1] - ia_d[i];
41       }
42     }
43     ierr = MatRestoreRowIJ(A_d,0,PETSC_FALSE,PETSC_FALSE,NULL,&ia_d,NULL,&done_d);CHKERRQ(ierr);
44   }
45   if (A_o) { /* determine number of nonzero entries in local off-diagonal part */
46     ierr = MatGetRowIJ(A_o,0,PETSC_FALSE,PETSC_FALSE,&n_o,&ia_o,NULL,&done_o);CHKERRQ(ierr);
47     if (done_o) {
48       ierr = PetscMalloc1(n_o,&nnz_o);CHKERRQ(ierr);
49       for (i=0; i<n_o; i++) {
50         nnz_o[i] = ia_o[i+1] - ia_o[i];
51       }
52     }
53     ierr = MatRestoreRowIJ(A_o,0,PETSC_FALSE,PETSC_FALSE,&n_o,&ia_o,NULL,&done_o);CHKERRQ(ierr);
54   }
55   if (done_d) {    /* set number of nonzeros in HYPRE IJ matrix */
56     if (!done_o) { /* only diagonal part */
57       ierr = PetscMalloc1(n_d,&nnz_o);CHKERRQ(ierr);
58       for (i=0; i<n_d; i++) {
59         nnz_o[i] = 0;
60       }
61     }
62     PetscStackCallStandard(HYPRE_IJMatrixSetDiagOffdSizes,(ij,(HYPRE_Int *)nnz_d,(HYPRE_Int *)nnz_o));
63     ierr = PetscFree(nnz_d);CHKERRQ(ierr);
64     ierr = PetscFree(nnz_o);CHKERRQ(ierr);
65   }
66   PetscFunctionReturn(0);
67 }
68 
69 static PetscErrorCode MatHYPRE_CreateFromMat(Mat A, Mat_HYPRE *hA)
70 {
71   PetscErrorCode ierr;
72   PetscInt       rstart,rend,cstart,cend;
73 
74   PetscFunctionBegin;
75   ierr   = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr);
76   ierr   = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr);
77   rstart = A->rmap->rstart;
78   rend   = A->rmap->rend;
79   cstart = A->cmap->rstart;
80   cend   = A->cmap->rend;
81   PetscStackCallStandard(HYPRE_IJMatrixCreate,(hA->comm,rstart,rend-1,cstart,cend-1,&hA->ij));
82   PetscStackCallStandard(HYPRE_IJMatrixSetObjectType,(hA->ij,HYPRE_PARCSR));
83   {
84     PetscBool      same;
85     Mat            A_d,A_o;
86     const PetscInt *colmap;
87     ierr = PetscObjectTypeCompare((PetscObject)A,MATMPIAIJ,&same);CHKERRQ(ierr);
88     if (same) {
89       ierr = MatMPIAIJGetSeqAIJ(A,&A_d,&A_o,&colmap);CHKERRQ(ierr);
90       ierr = MatHYPRE_IJMatrixPreallocate(A_d,A_o,hA->ij);CHKERRQ(ierr);
91       PetscFunctionReturn(0);
92     }
93     ierr = PetscObjectTypeCompare((PetscObject)A,MATMPIBAIJ,&same);CHKERRQ(ierr);
94     if (same) {
95       ierr = MatMPIBAIJGetSeqBAIJ(A,&A_d,&A_o,&colmap);CHKERRQ(ierr);
96       ierr = MatHYPRE_IJMatrixPreallocate(A_d,A_o,hA->ij);CHKERRQ(ierr);
97       PetscFunctionReturn(0);
98     }
99     ierr = PetscObjectTypeCompare((PetscObject)A,MATSEQAIJ,&same);CHKERRQ(ierr);
100     if (same) {
101       ierr = MatHYPRE_IJMatrixPreallocate(A,NULL,hA->ij);CHKERRQ(ierr);
102       PetscFunctionReturn(0);
103     }
104     ierr = PetscObjectTypeCompare((PetscObject)A,MATSEQBAIJ,&same);CHKERRQ(ierr);
105     if (same) {
106       ierr = MatHYPRE_IJMatrixPreallocate(A,NULL,hA->ij);CHKERRQ(ierr);
107       PetscFunctionReturn(0);
108     }
109   }
110   PetscFunctionReturn(0);
111 }
112 
113 static PetscErrorCode MatHYPRE_IJMatrixCopy(Mat A, HYPRE_IJMatrix ij)
114 {
115   PetscErrorCode    ierr;
116   PetscInt          i,rstart,rend,ncols,nr,nc;
117   const PetscScalar *values;
118   const PetscInt    *cols;
119   PetscBool         flg;
120 
121   PetscFunctionBegin;
122   ierr = PetscObjectTypeCompare((PetscObject)A,MATMPIAIJ,&flg);CHKERRQ(ierr);
123   ierr = MatGetSize(A,&nr,&nc);CHKERRQ(ierr);
124   if (flg && nr == nc) {
125     ierr = MatHYPRE_IJMatrixFastCopy_MPIAIJ(A,ij);CHKERRQ(ierr);
126     PetscFunctionReturn(0);
127   }
128   ierr = PetscObjectTypeCompare((PetscObject)A,MATSEQAIJ,&flg);CHKERRQ(ierr);
129   if (flg) {
130     ierr = MatHYPRE_IJMatrixFastCopy_SeqAIJ(A,ij);CHKERRQ(ierr);
131     PetscFunctionReturn(0);
132   }
133 
134   PetscStackCallStandard(HYPRE_IJMatrixInitialize,(ij));
135   ierr = MatGetOwnershipRange(A,&rstart,&rend);CHKERRQ(ierr);
136   for (i=rstart; i<rend; i++) {
137     ierr = MatGetRow(A,i,&ncols,&cols,&values);CHKERRQ(ierr);
138     if (ncols) {
139       PetscStackCallStandard(HYPRE_IJMatrixSetValues,(ij,1,(HYPRE_Int *)&ncols,(HYPRE_Int *)&i,(HYPRE_Int *)cols,values));
140     }
141     ierr = MatRestoreRow(A,i,&ncols,&cols,&values);CHKERRQ(ierr);
142   }
143   PetscFunctionReturn(0);
144 }
145 
146 static PetscErrorCode MatHYPRE_IJMatrixFastCopy_SeqAIJ(Mat A, HYPRE_IJMatrix ij)
147 {
148   PetscErrorCode        ierr;
149   Mat_SeqAIJ            *pdiag = (Mat_SeqAIJ*)A->data;
150   HYPRE_Int             type;
151   hypre_ParCSRMatrix    *par_matrix;
152   hypre_AuxParCSRMatrix *aux_matrix;
153   hypre_CSRMatrix       *hdiag;
154 
155   PetscFunctionBegin;
156   PetscStackCallStandard(HYPRE_IJMatrixInitialize,(ij));
157   PetscStackCallStandard(HYPRE_IJMatrixGetObjectType,(ij,&type));
158   if (type != HYPRE_PARCSR) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Only HYPRE_PARCSR is supported");
159   PetscStackCallStandard(HYPRE_IJMatrixGetObject,(ij,(void**)&par_matrix));
160   hdiag = hypre_ParCSRMatrixDiag(par_matrix);
161   /*
162        this is the Hack part where we monkey directly with the hypre datastructures
163   */
164   ierr = PetscMemcpy(hdiag->i,pdiag->i,(A->rmap->n + 1)*sizeof(PetscInt));
165   ierr = PetscMemcpy(hdiag->j,pdiag->j,pdiag->nz*sizeof(PetscInt));
166   ierr = PetscMemcpy(hdiag->data,pdiag->a,pdiag->nz*sizeof(PetscScalar));
167 
168   aux_matrix = (hypre_AuxParCSRMatrix*)hypre_IJMatrixTranslator(ij);
169   hypre_AuxParCSRMatrixNeedAux(aux_matrix) = 0;
170   PetscFunctionReturn(0);
171 }
172 
173 static PetscErrorCode MatHYPRE_IJMatrixFastCopy_MPIAIJ(Mat A, HYPRE_IJMatrix ij)
174 {
175   PetscErrorCode        ierr;
176   Mat_MPIAIJ            *pA = (Mat_MPIAIJ*)A->data;
177   Mat_SeqAIJ            *pdiag,*poffd;
178   PetscInt              i,*garray = pA->garray,*jj,cstart,*pjj;
179   HYPRE_Int             type;
180   hypre_ParCSRMatrix    *par_matrix;
181   hypre_AuxParCSRMatrix *aux_matrix;
182   hypre_CSRMatrix       *hdiag,*hoffd;
183 
184   PetscFunctionBegin;
185   pdiag = (Mat_SeqAIJ*) pA->A->data;
186   poffd = (Mat_SeqAIJ*) pA->B->data;
187   /* cstart is only valid for square MPIAIJ layed out in the usual way */
188   ierr = MatGetOwnershipRange(A,&cstart,NULL);CHKERRQ(ierr);
189 
190   PetscStackCallStandard(HYPRE_IJMatrixInitialize,(ij));
191   PetscStackCallStandard(HYPRE_IJMatrixGetObjectType,(ij,&type));
192   if (type != HYPRE_PARCSR) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Only HYPRE_PARCSR is supported");
193   PetscStackCallStandard(HYPRE_IJMatrixGetObject,(ij,(void**)&par_matrix));
194   hdiag = hypre_ParCSRMatrixDiag(par_matrix);
195   hoffd = hypre_ParCSRMatrixOffd(par_matrix);
196 
197   /*
198        this is the Hack part where we monkey directly with the hypre datastructures
199   */
200   ierr = PetscMemcpy(hdiag->i,pdiag->i,(pA->A->rmap->n + 1)*sizeof(PetscInt));
201   /* need to shift the diag column indices (hdiag->j) back to global numbering since hypre is expecting this */
202   jj  = (PetscInt*)hdiag->j;
203   pjj = (PetscInt*)pdiag->j;
204   for (i=0; i<pdiag->nz; i++) jj[i] = cstart + pjj[i];
205   ierr = PetscMemcpy(hdiag->data,pdiag->a,pdiag->nz*sizeof(PetscScalar));
206   ierr = PetscMemcpy(hoffd->i,poffd->i,(pA->A->rmap->n + 1)*sizeof(PetscInt));
207   /* need to move the offd column indices (hoffd->j) back to global numbering since hypre is expecting this
208      If we hacked a hypre a bit more we might be able to avoid this step */
209   jj  = (PetscInt*) hoffd->j;
210   pjj = (PetscInt*) poffd->j;
211   for (i=0; i<poffd->nz; i++) jj[i] = garray[pjj[i]];
212   ierr = PetscMemcpy(hoffd->data,poffd->a,poffd->nz*sizeof(PetscScalar));
213 
214   aux_matrix = (hypre_AuxParCSRMatrix*)hypre_IJMatrixTranslator(ij);
215   hypre_AuxParCSRMatrixNeedAux(aux_matrix) = 0;
216   PetscFunctionReturn(0);
217 }
218 
219 static PetscErrorCode MatConvert_HYPRE_IS(Mat A, MatType mtype, MatReuse reuse, Mat* B)
220 {
221   Mat_HYPRE*             mhA = (Mat_HYPRE*)(A->data);
222   Mat                    lA;
223   ISLocalToGlobalMapping rl2g,cl2g;
224   IS                     is;
225   hypre_ParCSRMatrix     *hA;
226   hypre_CSRMatrix        *hdiag,*hoffd;
227   MPI_Comm               comm;
228   PetscScalar            *hdd,*hod,*aa,*data;
229   HYPRE_Int              *col_map_offd,*hdi,*hdj,*hoi,*hoj;
230   PetscInt               *ii,*jj,*iptr,*jptr;
231   PetscInt               cum,dr,dc,oc,str,stc,nnz,i,jd,jo,M,N;
232   HYPRE_Int              type;
233   PetscErrorCode         ierr;
234 
235   PetscFunctionBegin;
236   comm = PetscObjectComm((PetscObject)A);
237   PetscStackCallStandard(HYPRE_IJMatrixGetObjectType,(mhA->ij,&type));
238   if (type != HYPRE_PARCSR) SETERRQ(comm,PETSC_ERR_SUP,"Only HYPRE_PARCSR is supported");
239   PetscStackCallStandard(HYPRE_IJMatrixGetObject,(mhA->ij,(void**)&hA));
240   M     = hypre_ParCSRMatrixGlobalNumRows(hA);
241   N     = hypre_ParCSRMatrixGlobalNumCols(hA);
242   str   = hypre_ParCSRMatrixFirstRowIndex(hA);
243   stc   = hypre_ParCSRMatrixFirstColDiag(hA);
244   hdiag = hypre_ParCSRMatrixDiag(hA);
245   hoffd = hypre_ParCSRMatrixOffd(hA);
246   dr    = hypre_CSRMatrixNumRows(hdiag);
247   dc    = hypre_CSRMatrixNumCols(hdiag);
248   nnz   = hypre_CSRMatrixNumNonzeros(hdiag);
249   hdi   = hypre_CSRMatrixI(hdiag);
250   hdj   = hypre_CSRMatrixJ(hdiag);
251   hdd   = hypre_CSRMatrixData(hdiag);
252   oc    = hypre_CSRMatrixNumCols(hoffd);
253   nnz  += hypre_CSRMatrixNumNonzeros(hoffd);
254   hoi   = hypre_CSRMatrixI(hoffd);
255   hoj   = hypre_CSRMatrixJ(hoffd);
256   hod   = hypre_CSRMatrixData(hoffd);
257   if (reuse != MAT_REUSE_MATRIX) {
258     PetscInt *aux;
259 
260     /* generate l2g maps for rows and cols */
261     ierr = ISCreateStride(comm,dr,str,1,&is);CHKERRQ(ierr);
262     ierr = ISLocalToGlobalMappingCreateIS(is,&rl2g);CHKERRQ(ierr);
263     ierr = ISDestroy(&is);CHKERRQ(ierr);
264     col_map_offd = hypre_ParCSRMatrixColMapOffd(hA);
265     ierr = PetscMalloc1(dc+oc,&aux);CHKERRQ(ierr);
266     for (i=0; i<dc; i++) aux[i] = i+stc;
267     for (i=0; i<oc; i++) aux[i+dc] = col_map_offd[i];
268     ierr = ISCreateGeneral(comm,dc+oc,aux,PETSC_OWN_POINTER,&is);CHKERRQ(ierr);
269     ierr = ISLocalToGlobalMappingCreateIS(is,&cl2g);CHKERRQ(ierr);
270     ierr = ISDestroy(&is);CHKERRQ(ierr);
271     /* create MATIS object */
272     ierr = MatCreate(comm,B);CHKERRQ(ierr);
273     ierr = MatSetSizes(*B,dr,dc,M,N);CHKERRQ(ierr);
274     ierr = MatSetType(*B,MATIS);CHKERRQ(ierr);
275     ierr = MatSetLocalToGlobalMapping(*B,rl2g,cl2g);CHKERRQ(ierr);
276     ierr = ISLocalToGlobalMappingDestroy(&rl2g);CHKERRQ(ierr);
277     ierr = ISLocalToGlobalMappingDestroy(&cl2g);CHKERRQ(ierr);
278 
279     /* allocate CSR for local matrix */
280     ierr = PetscMalloc1(dr+1,&iptr);CHKERRQ(ierr);
281     ierr = PetscMalloc1(nnz,&jptr);CHKERRQ(ierr);
282     ierr = PetscMalloc1(nnz,&data);CHKERRQ(ierr);
283   } else {
284     PetscInt  nr;
285     PetscBool done;
286     ierr = MatISGetLocalMat(*B,&lA);CHKERRQ(ierr);
287     ierr = MatGetRowIJ(lA,0,PETSC_FALSE,PETSC_FALSE,&nr,(const PetscInt**)&iptr,(const PetscInt**)&jptr,&done);CHKERRQ(ierr);
288     if (nr != dr) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot reuse mat: invalid number of rows in local mat! %D != %D",nr,dr);
289     if (iptr[nr] < nnz) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot reuse mat: invalid number of nonzeros in local mat! reuse %D requested %D",iptr[nr],nnz);
290     ierr = MatSeqAIJGetArray(lA,&data);CHKERRQ(ierr);
291   }
292   /* merge local matrices */
293   ii   = iptr;
294   jj   = jptr;
295   aa   = data;
296   *ii  = *(hdi++) + *(hoi++);
297   for (jd=0,jo=0,cum=0; *ii<nnz; cum++) {
298     PetscScalar *aold = aa;
299     PetscInt    *jold = jj,nc = jd+jo;
300     for (; jd<*hdi; jd++) { *jj++ = *hdj++;      *aa++ = *hdd++; }
301     for (; jo<*hoi; jo++) { *jj++ = *hoj++ + dc; *aa++ = *hod++; }
302     *(++ii) = *(hdi++) + *(hoi++);
303     ierr = PetscSortIntWithScalarArray(jd+jo-nc,jold,aold);CHKERRQ(ierr);
304   }
305   for (; cum<dr; cum++) *(++ii) = nnz;
306   if (reuse != MAT_REUSE_MATRIX) {
307     Mat_SeqAIJ* a;
308 
309     ierr = MatCreateSeqAIJWithArrays(PETSC_COMM_SELF,dr,dc+oc,iptr,jptr,data,&lA);CHKERRQ(ierr);
310     ierr = MatISSetLocalMat(*B,lA);CHKERRQ(ierr);
311     /* hack SeqAIJ */
312     a          = (Mat_SeqAIJ*)(lA->data);
313     a->free_a  = PETSC_TRUE;
314     a->free_ij = PETSC_TRUE;
315     ierr = MatDestroy(&lA);CHKERRQ(ierr);
316   }
317   ierr = MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
318   ierr = MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
319   if (reuse == MAT_INPLACE_MATRIX) {
320     ierr = MatHeaderReplace(A,B);CHKERRQ(ierr);
321   }
322   PetscFunctionReturn(0);
323 }
324 
325 PETSC_INTERN PetscErrorCode MatConvert_AIJ_HYPRE(Mat A, MatType type, MatReuse reuse, Mat *B)
326 {
327   Mat_HYPRE      *hB;
328   MPI_Comm       comm = PetscObjectComm((PetscObject)A);
329   PetscErrorCode ierr;
330 
331   PetscFunctionBegin;
332   if (reuse == MAT_INPLACE_MATRIX) SETERRQ(comm,PETSC_ERR_SUP,"Unsupported MAT_INPLACE_MATRIX");
333   if (reuse == MAT_REUSE_MATRIX) {
334     /* always destroy the old matrix and create a new memory;
335        hope this does not churn the memory too much. The problem
336        is I do not know if it is possible to put the matrix back to
337        its initial state so that we can directly copy the values
338        the second time through. */
339     hB = (Mat_HYPRE*)((*B)->data);
340     PetscStackCallStandard(HYPRE_IJMatrixDestroy,(hB->ij));
341   } else {
342     ierr = MatCreate(comm,B);CHKERRQ(ierr);
343     ierr = MatSetType(*B,MATHYPRE);CHKERRQ(ierr);
344     ierr = MatSetSizes(*B,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N);CHKERRQ(ierr);
345     hB   = (Mat_HYPRE*)((*B)->data);
346   }
347   ierr = MatHYPRE_CreateFromMat(A,hB);CHKERRQ(ierr);
348   ierr = MatHYPRE_IJMatrixCopy(A,hB->ij);CHKERRQ(ierr);
349   (*B)->preallocated = PETSC_TRUE;
350   ierr = MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
351   ierr = MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
352   PetscFunctionReturn(0);
353 }
354 
355 static PetscErrorCode MatConvert_HYPRE_AIJ(Mat A, MatType mtype, MatReuse reuse, Mat *B)
356 {
357   Mat_HYPRE          *hA = (Mat_HYPRE*)A->data;
358   hypre_ParCSRMatrix *parcsr;
359   hypre_CSRMatrix    *hdiag,*hoffd;
360   MPI_Comm           comm;
361   PetscScalar        *da,*oa,*aptr;
362   PetscInt           *dii,*djj,*oii,*ojj,*iptr;
363   PetscInt           i,dnnz,onnz,m,n;
364   HYPRE_Int          type;
365   PetscMPIInt        size;
366   PetscErrorCode     ierr;
367 
368   PetscFunctionBegin;
369   comm = PetscObjectComm((PetscObject)A);
370   PetscStackCallStandard(HYPRE_IJMatrixGetObjectType,(hA->ij,&type));
371   if (type != HYPRE_PARCSR) SETERRQ(comm,PETSC_ERR_SUP,"Only HYPRE_PARCSR is supported");
372   if (reuse == MAT_REUSE_MATRIX) {
373     PetscBool ismpiaij,isseqaij;
374     ierr = PetscObjectTypeCompare((PetscObject)*B,MATMPIAIJ,&ismpiaij);CHKERRQ(ierr);
375     ierr = PetscObjectBaseTypeCompare((PetscObject)*B,MATSEQAIJ,&isseqaij);CHKERRQ(ierr);
376     if (!ismpiaij && !isseqaij) SETERRQ(comm,PETSC_ERR_SUP,"Only MATMPIAIJ or MATSEQAIJ are supported");
377   }
378   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
379 
380   PetscStackCallStandard(HYPRE_IJMatrixGetObject,(hA->ij,(void**)&parcsr));
381   hdiag = hypre_ParCSRMatrixDiag(parcsr);
382   hoffd = hypre_ParCSRMatrixOffd(parcsr);
383   m     = hypre_CSRMatrixNumRows(hdiag);
384   n     = hypre_CSRMatrixNumCols(hdiag);
385   dnnz  = hypre_CSRMatrixNumNonzeros(hdiag);
386   onnz  = hypre_CSRMatrixNumNonzeros(hoffd);
387   if (reuse == MAT_INITIAL_MATRIX) {
388     ierr = PetscMalloc1(m+1,&dii);CHKERRQ(ierr);
389     ierr = PetscMalloc1(dnnz,&djj);CHKERRQ(ierr);
390     ierr = PetscMalloc1(dnnz,&da);CHKERRQ(ierr);
391   } else if (reuse == MAT_REUSE_MATRIX) {
392     PetscInt  nr;
393     PetscBool done;
394     if (size > 1) {
395       Mat_MPIAIJ *b = (Mat_MPIAIJ*)((*B)->data);
396 
397       ierr = MatGetRowIJ(b->A,0,PETSC_FALSE,PETSC_FALSE,&nr,(const PetscInt**)&dii,(const PetscInt**)&djj,&done);CHKERRQ(ierr);
398       if (nr != m) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot reuse mat: invalid number of local rows in diag part! %D != %D",nr,m);
399       if (dii[nr] < dnnz) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot reuse mat: invalid number of nonzeros in diag part! reuse %D hypre %D",dii[nr],dnnz);
400       ierr = MatSeqAIJGetArray(b->A,&da);CHKERRQ(ierr);
401     } else {
402       ierr = MatGetRowIJ(*B,0,PETSC_FALSE,PETSC_FALSE,&nr,(const PetscInt**)&dii,(const PetscInt**)&djj,&done);CHKERRQ(ierr);
403       if (nr != m) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot reuse mat: invalid number of local rows! %D != %D",nr,m);
404       if (dii[nr] < dnnz) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot reuse mat: invalid number of nonzeros! reuse %D hypre %D",dii[nr],dnnz);
405       ierr = MatSeqAIJGetArray(*B,&da);CHKERRQ(ierr);
406     }
407   } else { /* MAT_INPLACE_MATRIX */
408     dii = (PetscInt*)hypre_CSRMatrixI(hdiag);
409     djj = (PetscInt*)hypre_CSRMatrixJ(hdiag);
410     da  = hypre_CSRMatrixData(hdiag);
411   }
412   ierr = PetscMemcpy(dii,hypre_CSRMatrixI(hdiag),(m+1)*sizeof(PetscInt));CHKERRQ(ierr);
413   ierr = PetscMemcpy(djj,hypre_CSRMatrixJ(hdiag),dnnz*sizeof(PetscInt));CHKERRQ(ierr);
414   ierr = PetscMemcpy(da,hypre_CSRMatrixData(hdiag),dnnz*sizeof(PetscScalar));CHKERRQ(ierr);
415   iptr = djj;
416   aptr = da;
417   for (i=0; i<m; i++) {
418     PetscInt nc = dii[i+1]-dii[i];
419     ierr = PetscSortIntWithScalarArray(nc,iptr,aptr);CHKERRQ(ierr);
420     iptr += nc;
421     aptr += nc;
422   }
423   if (size > 1) {
424     HYPRE_Int *offdj,*coffd;
425 
426     if (reuse == MAT_INITIAL_MATRIX) {
427       ierr = PetscMalloc1(m+1,&oii);CHKERRQ(ierr);
428       ierr = PetscMalloc1(onnz,&ojj);CHKERRQ(ierr);
429       ierr = PetscMalloc1(onnz,&oa);CHKERRQ(ierr);
430     } else if (reuse == MAT_REUSE_MATRIX) {
431       Mat_MPIAIJ *b = (Mat_MPIAIJ*)((*B)->data);
432       PetscInt   nr,hr = hypre_CSRMatrixNumRows(hoffd);
433       PetscBool  done;
434 
435       ierr = MatGetRowIJ(b->B,0,PETSC_FALSE,PETSC_FALSE,&nr,(const PetscInt**)&oii,(const PetscInt**)&ojj,&done);CHKERRQ(ierr);
436       if (nr != hr) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot reuse mat: invalid number of local rows in offdiag part! %D != %D",nr,hr);
437       if (oii[nr] < onnz) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot reuse mat: invalid number of nonzeros in offdiag part! reuse %D hypre %D",oii[nr],onnz);
438       ierr = MatSeqAIJGetArray(b->B,&oa);CHKERRQ(ierr);
439     } else { /* MAT_INPLACE_MATRIX */
440       oii = (PetscInt*)hypre_CSRMatrixI(hoffd);
441       ojj = (PetscInt*)hypre_CSRMatrixJ(hoffd);
442       oa  = hypre_CSRMatrixData(hoffd);
443     }
444     ierr  = PetscMemcpy(oii,hypre_CSRMatrixI(hoffd),(m+1)*sizeof(PetscInt));CHKERRQ(ierr);
445     offdj = hypre_CSRMatrixJ(hoffd);
446     coffd = hypre_ParCSRMatrixColMapOffd(parcsr);
447     for (i=0; i<onnz; i++) ojj[i] = coffd[offdj[i]];
448     ierr = PetscMemcpy(oa,hypre_CSRMatrixData(hoffd),onnz*sizeof(PetscScalar));CHKERRQ(ierr);
449     iptr = ojj;
450     aptr = oa;
451     for (i=0; i<m; i++) {
452        PetscInt nc = oii[i+1]-oii[i];
453        ierr = PetscSortIntWithScalarArray(nc,iptr,aptr);CHKERRQ(ierr);
454        iptr += nc;
455        aptr += nc;
456     }
457     if (reuse == MAT_INITIAL_MATRIX) {
458       Mat_MPIAIJ *b;
459       Mat_SeqAIJ *d,*o;
460 
461       ierr = MatCreateMPIAIJWithSplitArrays(comm,m,n,PETSC_DECIDE,PETSC_DECIDE,dii,djj,da,oii,ojj,oa,B);CHKERRQ(ierr);
462       /* hack MPIAIJ */
463       b          = (Mat_MPIAIJ*)((*B)->data);
464       d          = (Mat_SeqAIJ*)b->A->data;
465       o          = (Mat_SeqAIJ*)b->B->data;
466       d->free_a  = PETSC_TRUE;
467       d->free_ij = PETSC_TRUE;
468       o->free_a  = PETSC_TRUE;
469       o->free_ij = PETSC_TRUE;
470     } else if (reuse == MAT_INPLACE_MATRIX) {
471       Mat T;
472       ierr = MatCreateMPIAIJWithSplitArrays(comm,m,n,PETSC_DECIDE,PETSC_DECIDE,dii,djj,da,oii,ojj,oa,&T);CHKERRQ(ierr);
473       hypre_CSRMatrixI(hdiag)    = NULL;
474       hypre_CSRMatrixJ(hdiag)    = NULL;
475       hypre_CSRMatrixData(hdiag) = NULL;
476       hypre_CSRMatrixI(hoffd)    = NULL;
477       hypre_CSRMatrixJ(hoffd)    = NULL;
478       hypre_CSRMatrixData(hoffd) = NULL;
479       ierr = MatHeaderReplace(A,&T);CHKERRQ(ierr);
480     }
481   } else {
482     oii  = NULL;
483     ojj  = NULL;
484     oa   = NULL;
485     if (reuse == MAT_INITIAL_MATRIX) {
486       Mat_SeqAIJ* b;
487       ierr = MatCreateSeqAIJWithArrays(comm,m,n,dii,djj,da,B);CHKERRQ(ierr);
488       /* hack SeqAIJ */
489       b          = (Mat_SeqAIJ*)((*B)->data);
490       b->free_a  = PETSC_TRUE;
491       b->free_ij = PETSC_TRUE;
492     } else if (reuse == MAT_INPLACE_MATRIX) {
493       Mat T;
494       ierr = MatCreateSeqAIJWithArrays(comm,m,n,dii,djj,da,&T);CHKERRQ(ierr);
495       hypre_CSRMatrixI(hdiag)    = NULL;
496       hypre_CSRMatrixJ(hdiag)    = NULL;
497       hypre_CSRMatrixData(hdiag) = NULL;
498       ierr = MatHeaderReplace(A,&T);CHKERRQ(ierr);
499     }
500   }
501 
502   /* we have to use hypre_Tfree to free the arrays */
503   if (reuse == MAT_INPLACE_MATRIX) {
504     void *ptrs[6] = {dii,djj,da,oii,ojj,oa};
505     const char *names[6] = {"_hypre_csr_dii",
506                             "_hypre_csr_djj",
507                             "_hypre_csr_da",
508                             "_hypre_csr_oii",
509                             "_hypre_csr_ojj",
510                             "_hypre_csr_oa"};
511     for (i=0; i<6; i++) {
512       PetscContainer c;
513 
514       ierr = PetscContainerCreate(comm,&c);CHKERRQ(ierr);
515       ierr = PetscContainerSetPointer(c,ptrs[i]);CHKERRQ(ierr);
516       ierr = PetscContainerSetUserDestroy(c,hypre_array_destroy);CHKERRQ(ierr);
517       ierr = PetscObjectCompose((PetscObject)(*B),names[i],(PetscObject)c);CHKERRQ(ierr);
518       ierr = PetscContainerDestroy(&c);CHKERRQ(ierr);
519     }
520   }
521   PetscFunctionReturn(0);
522 }
523 
524 static PetscErrorCode MatAIJGetParCSR_Private(Mat A, hypre_ParCSRMatrix **hA)
525 {
526   hypre_ParCSRMatrix *tA;
527   hypre_CSRMatrix    *hdiag,*hoffd;
528   Mat_SeqAIJ         *diag,*offd;
529   PetscInt           *garray,noffd,dnnz,onnz,*row_starts,*col_starts;
530   MPI_Comm           comm = PetscObjectComm((PetscObject)A);
531   PetscBool          ismpiaij,isseqaij;
532   PetscErrorCode     ierr;
533 
534   PetscFunctionBegin;
535   ierr = PetscObjectTypeCompare((PetscObject)A,MATMPIAIJ,&ismpiaij);CHKERRQ(ierr);
536   ierr = PetscObjectBaseTypeCompare((PetscObject)A,MATSEQAIJ,&isseqaij);CHKERRQ(ierr);
537   if (!ismpiaij && !isseqaij) SETERRQ1(comm,PETSC_ERR_SUP,"Unsupported type %s",((PetscObject)A)->type);
538   if (ismpiaij) {
539     Mat_MPIAIJ *a = (Mat_MPIAIJ*)(A->data);
540 
541     diag   = (Mat_SeqAIJ*)a->A->data;
542     offd   = (Mat_SeqAIJ*)a->B->data;
543     garray = a->garray;
544     noffd  = a->B->cmap->N;
545     dnnz   = diag->nz;
546     onnz   = offd->nz;
547   } else {
548     diag   = (Mat_SeqAIJ*)A->data;
549     offd   = NULL;
550     garray = NULL;
551     noffd  = 0;
552     dnnz   = diag->nz;
553     onnz   = 0;
554   }
555 
556   /* create a temporary ParCSR */
557   if (HYPRE_AssumedPartitionCheck()) {
558     PetscMPIInt myid;
559 
560     ierr       = MPI_Comm_rank(comm,&myid);CHKERRQ(ierr);
561     row_starts = A->rmap->range + myid;
562     col_starts = A->cmap->range + myid;
563   } else {
564     row_starts = A->rmap->range;
565     col_starts = A->cmap->range;
566   }
567   tA = hypre_ParCSRMatrixCreate(comm,A->rmap->N,A->cmap->N,(HYPRE_Int*)row_starts,(HYPRE_Int*)col_starts,noffd,dnnz,onnz);
568   hypre_ParCSRMatrixSetRowStartsOwner(tA,0);
569   hypre_ParCSRMatrixSetColStartsOwner(tA,0);
570 
571   /* set diagonal part */
572   hdiag = hypre_ParCSRMatrixDiag(tA);
573   hypre_CSRMatrixI(hdiag)           = (HYPRE_Int*)diag->i;
574   hypre_CSRMatrixJ(hdiag)           = (HYPRE_Int*)diag->j;
575   hypre_CSRMatrixData(hdiag)        = diag->a;
576   hypre_CSRMatrixNumNonzeros(hdiag) = diag->nz;
577   hypre_CSRMatrixSetRownnz(hdiag);
578   hypre_CSRMatrixSetDataOwner(hdiag,0);
579 
580   /* set offdiagonal part */
581   hoffd = hypre_ParCSRMatrixOffd(tA);
582   if (offd) {
583     hypre_CSRMatrixI(hoffd)           = (HYPRE_Int*)offd->i;
584     hypre_CSRMatrixJ(hoffd)           = (HYPRE_Int*)offd->j;
585     hypre_CSRMatrixData(hoffd)        = offd->a;
586     hypre_CSRMatrixNumNonzeros(hoffd) = offd->nz;
587     hypre_CSRMatrixSetRownnz(hoffd);
588     hypre_CSRMatrixSetDataOwner(hoffd,0);
589     hypre_ParCSRMatrixSetNumNonzeros(tA);
590     hypre_ParCSRMatrixColMapOffd(tA) = (HYPRE_Int*)garray;
591   }
592   *hA = tA;
593   PetscFunctionReturn(0);
594 }
595 
596 static PetscErrorCode MatAIJRestoreParCSR_Private(Mat A, hypre_ParCSRMatrix **hA)
597 {
598   hypre_CSRMatrix    *hdiag,*hoffd;
599 
600   PetscFunctionBegin;
601   hdiag = hypre_ParCSRMatrixDiag(*hA);
602   hoffd = hypre_ParCSRMatrixOffd(*hA);
603   /* set pointers to NULL before destroying tA */
604   hypre_CSRMatrixI(hdiag)           = NULL;
605   hypre_CSRMatrixJ(hdiag)           = NULL;
606   hypre_CSRMatrixData(hdiag)        = NULL;
607   hypre_CSRMatrixI(hoffd)           = NULL;
608   hypre_CSRMatrixJ(hoffd)           = NULL;
609   hypre_CSRMatrixData(hoffd)        = NULL;
610   hypre_ParCSRMatrixColMapOffd(*hA) = NULL;
611   hypre_ParCSRMatrixDestroy(*hA);
612   *hA = NULL;
613   PetscFunctionReturn(0);
614 }
615 
616 /* calls RAP from BoomerAMG:
617    the resulting ParCSR will not own the column and row starts
618    It looks like we don't need to have the diagonal entries
619    ordered first in the rows of the diagonal part
620    for boomerAMGBuildCoarseOperator to work */
621 static PetscErrorCode MatHYPRE_ParCSR_RAP(hypre_ParCSRMatrix *hR, hypre_ParCSRMatrix *hA,hypre_ParCSRMatrix *hP, hypre_ParCSRMatrix **hRAP)
622 {
623   PetscErrorCode ierr;
624   HYPRE_Int      P_owns_col_starts,R_owns_row_starts;
625 
626   PetscFunctionBegin;
627   P_owns_col_starts = hypre_ParCSRMatrixOwnsColStarts(hP);
628   R_owns_row_starts = hypre_ParCSRMatrixOwnsRowStarts(hR);
629   PetscStackCallStandard(hypre_BoomerAMGBuildCoarseOperator,(hR,hA,hP,hRAP));
630   PetscStackCallStandard(hypre_ParCSRMatrixSetNumNonzeros,(*hRAP));
631   /* hypre_BoomerAMGBuildCoarseOperator steals the col_starts from P and the row_starts from R */
632   hypre_ParCSRMatrixSetRowStartsOwner(*hRAP,0);
633   hypre_ParCSRMatrixSetColStartsOwner(*hRAP,0);
634   if (P_owns_col_starts) hypre_ParCSRMatrixSetColStartsOwner(hP,1);
635   if (R_owns_row_starts) hypre_ParCSRMatrixSetRowStartsOwner(hR,1);
636   PetscFunctionReturn(0);
637 }
638 
639 static PetscErrorCode MatPtAPNumeric_AIJ_AIJ_wHYPRE(Mat A,Mat P,Mat C)
640 {
641   Mat                B;
642   hypre_ParCSRMatrix *hA,*hP,*hPtAP;
643   PetscErrorCode     ierr;
644 
645   PetscFunctionBegin;
646   ierr = MatAIJGetParCSR_Private(A,&hA);CHKERRQ(ierr);
647   ierr = MatAIJGetParCSR_Private(P,&hP);CHKERRQ(ierr);
648   ierr = MatHYPRE_ParCSR_RAP(hP,hA,hP,&hPtAP);CHKERRQ(ierr);
649   ierr = MatCreateFromParCSR(hPtAP,MATAIJ,PETSC_OWN_POINTER,&B);CHKERRQ(ierr);
650   ierr = MatHeaderMerge(C,&B);CHKERRQ(ierr);
651   ierr = MatAIJRestoreParCSR_Private(A,&hA);CHKERRQ(ierr);
652   ierr = MatAIJRestoreParCSR_Private(P,&hP);CHKERRQ(ierr);
653   PetscFunctionReturn(0);
654 }
655 
656 PETSC_INTERN PetscErrorCode MatPtAPSymbolic_AIJ_AIJ_wHYPRE(Mat A,Mat P,PetscReal fill,Mat *C)
657 {
658   PetscErrorCode ierr;
659 
660   PetscFunctionBegin;
661   ierr                   = MatCreate(PetscObjectComm((PetscObject)A),C);CHKERRQ(ierr);
662   ierr                   = MatSetType(*C,MATAIJ);CHKERRQ(ierr);
663   (*C)->ops->ptapnumeric = MatPtAPNumeric_AIJ_AIJ_wHYPRE;
664   PetscFunctionReturn(0);
665 }
666 
667 static PetscErrorCode MatPtAPNumeric_AIJ_HYPRE(Mat A,Mat P,Mat C)
668 {
669   Mat                B;
670   Mat_HYPRE          *hP;
671   hypre_ParCSRMatrix *hA = NULL,*Pparcsr,*ptapparcsr;
672   HYPRE_Int          type;
673   MPI_Comm           comm = PetscObjectComm((PetscObject)A);
674   PetscBool          ishypre;
675   PetscErrorCode     ierr;
676 
677   PetscFunctionBegin;
678   ierr = PetscObjectTypeCompare((PetscObject)P,MATHYPRE,&ishypre);CHKERRQ(ierr);
679   if (!ishypre) SETERRQ1(comm,PETSC_ERR_USER,"P should be of type %s",MATHYPRE);
680   hP = (Mat_HYPRE*)P->data;
681   PetscStackCallStandard(HYPRE_IJMatrixGetObjectType,(hP->ij,&type));
682   if (type != HYPRE_PARCSR) SETERRQ(comm,PETSC_ERR_SUP,"Only HYPRE_PARCSR is supported");
683   PetscStackCallStandard(HYPRE_IJMatrixGetObject,(hP->ij,(void**)&Pparcsr));
684 
685   ierr = MatAIJGetParCSR_Private(A,&hA);CHKERRQ(ierr);
686   ierr = MatHYPRE_ParCSR_RAP(Pparcsr,hA,Pparcsr,&ptapparcsr);CHKERRQ(ierr);
687   ierr = MatAIJRestoreParCSR_Private(A,&hA);CHKERRQ(ierr);
688 
689   /* create temporary matrix and merge to C */
690   ierr = MatCreateFromParCSR(ptapparcsr,((PetscObject)C)->type_name,PETSC_OWN_POINTER,&B);CHKERRQ(ierr);
691   ierr = MatHeaderMerge(C,&B);CHKERRQ(ierr);
692   PetscFunctionReturn(0);
693 }
694 
695 static PetscErrorCode MatPtAP_AIJ_HYPRE(Mat A,Mat P,MatReuse scall,PetscReal fill,Mat *C)
696 {
697   PetscErrorCode ierr;
698 
699   PetscFunctionBegin;
700   if (scall == MAT_INITIAL_MATRIX) {
701     const char *deft = MATAIJ;
702     char       type[256];
703     PetscBool  flg;
704 
705     ierr = PetscObjectOptionsBegin((PetscObject)A);CHKERRQ(ierr);
706     ierr = PetscOptionsFList("-matptap_hypre_outtype","Matrix type",NULL,MatList,deft,type,256,&flg);CHKERRQ(ierr);
707     ierr = PetscOptionsEnd();CHKERRQ(ierr);
708     ierr = PetscLogEventBegin(MAT_PtAPSymbolic,A,P,0,0);CHKERRQ(ierr);
709     ierr = MatCreate(PetscObjectComm((PetscObject)A),C);CHKERRQ(ierr);
710     if (flg) {
711       ierr = MatSetType(*C,type);CHKERRQ(ierr);
712     } else {
713       ierr = MatSetType(*C,deft);CHKERRQ(ierr);
714     }
715     (*C)->ops->ptapnumeric = MatPtAPNumeric_AIJ_HYPRE;
716     ierr = PetscLogEventEnd(MAT_PtAPSymbolic,A,P,0,0);CHKERRQ(ierr);
717   }
718   ierr = PetscLogEventBegin(MAT_PtAPNumeric,A,P,0,0);CHKERRQ(ierr);
719   ierr = (*(*C)->ops->ptapnumeric)(A,P,*C);CHKERRQ(ierr);
720   ierr = PetscLogEventEnd(MAT_PtAPNumeric,A,P,0,0);CHKERRQ(ierr);
721   PetscFunctionReturn(0);
722 }
723 
724 static PetscErrorCode MatPtAPNumeric_HYPRE_HYPRE(Mat A,Mat P,Mat C)
725 {
726   Mat                B;
727   hypre_ParCSRMatrix *Aparcsr,*Pparcsr,*ptapparcsr;
728   Mat_HYPRE          *hA,*hP;
729   PetscBool          ishypre;
730   HYPRE_Int          type;
731   PetscErrorCode     ierr;
732 
733   PetscFunctionBegin;
734   ierr = PetscObjectTypeCompare((PetscObject)P,MATHYPRE,&ishypre);CHKERRQ(ierr);
735   if (!ishypre) SETERRQ1(PetscObjectComm((PetscObject)P),PETSC_ERR_USER,"P should be of type %s",MATHYPRE);
736   ierr = PetscObjectTypeCompare((PetscObject)A,MATHYPRE,&ishypre);CHKERRQ(ierr);
737   if (!ishypre) SETERRQ1(PetscObjectComm((PetscObject)A),PETSC_ERR_USER,"A should be of type %s",MATHYPRE);
738   hA = (Mat_HYPRE*)A->data;
739   hP = (Mat_HYPRE*)P->data;
740   PetscStackCallStandard(HYPRE_IJMatrixGetObjectType,(hA->ij,&type));
741   if (type != HYPRE_PARCSR) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Only HYPRE_PARCSR is supported");
742   PetscStackCallStandard(HYPRE_IJMatrixGetObjectType,(hP->ij,&type));
743   if (type != HYPRE_PARCSR) SETERRQ(PetscObjectComm((PetscObject)P),PETSC_ERR_SUP,"Only HYPRE_PARCSR is supported");
744   PetscStackCallStandard(HYPRE_IJMatrixGetObject,(hA->ij,(void**)&Aparcsr));
745   PetscStackCallStandard(HYPRE_IJMatrixGetObject,(hP->ij,(void**)&Pparcsr));
746   ierr = MatHYPRE_ParCSR_RAP(Pparcsr,Aparcsr,Pparcsr,&ptapparcsr);CHKERRQ(ierr);
747   ierr = MatCreateFromParCSR(ptapparcsr,MATHYPRE,PETSC_OWN_POINTER,&B);CHKERRQ(ierr);
748   ierr = MatHeaderMerge(C,&B);CHKERRQ(ierr);
749   PetscFunctionReturn(0);
750 }
751 
752 static PetscErrorCode MatPtAP_HYPRE_HYPRE(Mat A,Mat P,MatReuse scall,PetscReal fill,Mat *C)
753 {
754   PetscErrorCode ierr;
755 
756   PetscFunctionBegin;
757   if (scall == MAT_INITIAL_MATRIX) {
758     ierr = PetscLogEventBegin(MAT_PtAPSymbolic,A,P,0,0);CHKERRQ(ierr);
759     ierr                   = MatCreate(PetscObjectComm((PetscObject)A),C);CHKERRQ(ierr);
760     ierr                   = MatSetType(*C,MATHYPRE);CHKERRQ(ierr);
761     (*C)->ops->ptapnumeric = MatPtAPNumeric_HYPRE_HYPRE;
762     ierr = PetscLogEventEnd(MAT_PtAPSymbolic,A,P,0,0);CHKERRQ(ierr);
763   }
764   ierr = PetscLogEventBegin(MAT_PtAPNumeric,A,P,0,0);CHKERRQ(ierr);
765   ierr = (*(*C)->ops->ptapnumeric)(A,P,*C);CHKERRQ(ierr);
766   ierr = PetscLogEventEnd(MAT_PtAPNumeric,A,P,0,0);CHKERRQ(ierr);
767   PetscFunctionReturn(0);
768 }
769 
770 /* calls hypre_ParMatmul
771    hypre_ParMatMul uses hypre_ParMatrixCreate with the communicator of hA
772    hypre_ParMatrixCreate does not duplicate the communicator
773    It looks like we don't need to have the diagonal entries
774    ordered first in the rows of the diagonal part
775    for boomerAMGBuildCoarseOperator to work */
776 static PetscErrorCode MatHYPRE_ParCSR_MatMatMult(hypre_ParCSRMatrix *hA, hypre_ParCSRMatrix *hB, hypre_ParCSRMatrix **hAB)
777 {
778   PetscFunctionBegin;
779   PetscStackPush("hypre_ParMatmul");
780   *hAB = hypre_ParMatmul(hA,hB);
781   PetscStackPop;
782   PetscFunctionReturn(0);
783 }
784 
785 static PetscErrorCode MatMatMultNumeric_AIJ_AIJ_wHYPRE(Mat A,Mat B,Mat C)
786 {
787   Mat                D;
788   hypre_ParCSRMatrix *hA,*hB,*hAB = NULL;
789   PetscErrorCode     ierr;
790 
791   PetscFunctionBegin;
792   ierr = MatAIJGetParCSR_Private(A,&hA);CHKERRQ(ierr);
793   ierr = MatAIJGetParCSR_Private(B,&hB);CHKERRQ(ierr);
794   ierr = MatHYPRE_ParCSR_MatMatMult(hA,hB,&hAB);CHKERRQ(ierr);
795   ierr = MatCreateFromParCSR(hAB,MATAIJ,PETSC_OWN_POINTER,&D);CHKERRQ(ierr);
796   ierr = MatHeaderMerge(C,&D);CHKERRQ(ierr);
797   ierr = MatAIJRestoreParCSR_Private(A,&hA);CHKERRQ(ierr);
798   ierr = MatAIJRestoreParCSR_Private(B,&hB);CHKERRQ(ierr);
799   PetscFunctionReturn(0);
800 }
801 
802 PETSC_INTERN PetscErrorCode MatMatMultSymbolic_AIJ_AIJ_wHYPRE(Mat A,Mat B,PetscReal fill,Mat *C)
803 {
804   PetscErrorCode ierr;
805 
806   PetscFunctionBegin;
807   ierr                      = MatCreate(PetscObjectComm((PetscObject)A),C);CHKERRQ(ierr);
808   ierr                      = MatSetType(*C,MATAIJ);CHKERRQ(ierr);
809   (*C)->ops->matmultnumeric = MatMatMultNumeric_AIJ_AIJ_wHYPRE;
810   PetscFunctionReturn(0);
811 }
812 
813 static PetscErrorCode MatMatMultNumeric_HYPRE_HYPRE(Mat A,Mat B,Mat C)
814 {
815   Mat                D;
816   hypre_ParCSRMatrix *Aparcsr,*Bparcsr,*ABparcsr = NULL;
817   Mat_HYPRE          *hA,*hB;
818   PetscBool          ishypre;
819   HYPRE_Int          type;
820   PetscErrorCode     ierr;
821 
822   PetscFunctionBegin;
823   ierr = PetscObjectTypeCompare((PetscObject)B,MATHYPRE,&ishypre);CHKERRQ(ierr);
824   if (!ishypre) SETERRQ1(PetscObjectComm((PetscObject)B),PETSC_ERR_USER,"B should be of type %s",MATHYPRE);
825   ierr = PetscObjectTypeCompare((PetscObject)A,MATHYPRE,&ishypre);CHKERRQ(ierr);
826   if (!ishypre) SETERRQ1(PetscObjectComm((PetscObject)A),PETSC_ERR_USER,"A should be of type %s",MATHYPRE);
827   hA = (Mat_HYPRE*)A->data;
828   hB = (Mat_HYPRE*)B->data;
829   PetscStackCallStandard(HYPRE_IJMatrixGetObjectType,(hA->ij,&type));
830   if (type != HYPRE_PARCSR) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Only HYPRE_PARCSR is supported");
831   PetscStackCallStandard(HYPRE_IJMatrixGetObjectType,(hB->ij,&type));
832   if (type != HYPRE_PARCSR) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_SUP,"Only HYPRE_PARCSR is supported");
833   PetscStackCallStandard(HYPRE_IJMatrixGetObject,(hA->ij,(void**)&Aparcsr));
834   PetscStackCallStandard(HYPRE_IJMatrixGetObject,(hB->ij,(void**)&Bparcsr));
835   ierr = MatHYPRE_ParCSR_MatMatMult(Aparcsr,Bparcsr,&ABparcsr);CHKERRQ(ierr);
836   ierr = MatCreateFromParCSR(ABparcsr,MATHYPRE,PETSC_OWN_POINTER,&D);CHKERRQ(ierr);
837   /* need to use HeaderReplace because HeaderMerge messes up with the communicator */
838   ierr = MatHeaderReplace(C,&D);CHKERRQ(ierr);
839   C->ops->matmultnumeric = MatMatMultNumeric_HYPRE_HYPRE;
840   PetscFunctionReturn(0);
841 }
842 
843 static PetscErrorCode MatMatMult_HYPRE_HYPRE(Mat A,Mat B,MatReuse scall,PetscReal fill,Mat *C)
844 {
845   PetscErrorCode ierr;
846 
847   PetscFunctionBegin;
848   if (scall == MAT_INITIAL_MATRIX) {
849     ierr = PetscLogEventBegin(MAT_MatMultSymbolic,A,B,0,0);CHKERRQ(ierr);
850     ierr                      = MatCreate(PetscObjectComm((PetscObject)A),C);CHKERRQ(ierr);
851     ierr                      = MatSetType(*C,MATHYPRE);CHKERRQ(ierr);
852     (*C)->ops->matmultnumeric = MatMatMultNumeric_HYPRE_HYPRE;
853     ierr = PetscLogEventEnd(MAT_MatMultSymbolic,A,B,0,0);CHKERRQ(ierr);
854   }
855   ierr = PetscLogEventBegin(MAT_MatMultNumeric,A,B,0,0);CHKERRQ(ierr);
856   ierr = (*(*C)->ops->matmultnumeric)(A,B,*C);CHKERRQ(ierr);
857   ierr = PetscLogEventEnd(MAT_MatMultNumeric,A,B,0,0);CHKERRQ(ierr);
858   PetscFunctionReturn(0);
859 }
860 
861 PETSC_INTERN PetscErrorCode MatTransposeMatMatMultNumeric_AIJ_AIJ_AIJ_wHYPRE(Mat A,Mat B,Mat C,Mat D)
862 {
863   Mat                E;
864   hypre_ParCSRMatrix *hA,*hB,*hC,*hABC;
865   PetscErrorCode     ierr;
866 
867   PetscFunctionBegin;
868   ierr = MatAIJGetParCSR_Private(A,&hA);CHKERRQ(ierr);
869   ierr = MatAIJGetParCSR_Private(B,&hB);CHKERRQ(ierr);
870   ierr = MatAIJGetParCSR_Private(C,&hC);CHKERRQ(ierr);
871   ierr = MatHYPRE_ParCSR_RAP(hA,hB,hC,&hABC);CHKERRQ(ierr);
872   ierr = MatCreateFromParCSR(hABC,MATAIJ,PETSC_OWN_POINTER,&E);CHKERRQ(ierr);
873   ierr = MatHeaderMerge(D,&E);CHKERRQ(ierr);
874   ierr = MatAIJRestoreParCSR_Private(A,&hA);CHKERRQ(ierr);
875   ierr = MatAIJRestoreParCSR_Private(B,&hB);CHKERRQ(ierr);
876   ierr = MatAIJRestoreParCSR_Private(C,&hC);CHKERRQ(ierr);
877   PetscFunctionReturn(0);
878 }
879 
880 PETSC_INTERN PetscErrorCode MatTransposeMatMatMultSymbolic_AIJ_AIJ_AIJ_wHYPRE(Mat A,Mat B,Mat C,PetscReal fill,Mat *D)
881 {
882   PetscErrorCode ierr;
883 
884   PetscFunctionBegin;
885   ierr = MatCreate(PetscObjectComm((PetscObject)A),D);CHKERRQ(ierr);
886   ierr = MatSetType(*D,MATAIJ);CHKERRQ(ierr);
887   PetscFunctionReturn(0);
888 }
889 
890 static PetscErrorCode MatMultTranspose_HYPRE(Mat A, Vec x, Vec y)
891 {
892   PetscErrorCode ierr;
893 
894   PetscFunctionBegin;
895   ierr = MatHYPRE_MultKernel_Private(A,x,y,PETSC_TRUE);CHKERRQ(ierr);
896   PetscFunctionReturn(0);
897 }
898 
899 static PetscErrorCode MatMult_HYPRE(Mat A, Vec x, Vec y)
900 {
901   PetscErrorCode ierr;
902 
903   PetscFunctionBegin;
904   ierr = MatHYPRE_MultKernel_Private(A,x,y,PETSC_FALSE);CHKERRQ(ierr);
905   PetscFunctionReturn(0);
906 }
907 
908 static PetscErrorCode MatHYPRE_MultKernel_Private(Mat A, Vec x, Vec y, PetscBool trans)
909 {
910   Mat_HYPRE          *hA = (Mat_HYPRE*)A->data;
911   hypre_ParCSRMatrix *parcsr;
912   hypre_ParVector    *hx,*hy;
913   PetscScalar        *ax,*ay,*sax,*say;
914   PetscErrorCode     ierr;
915 
916   PetscFunctionBegin;
917   PetscStackCallStandard(HYPRE_IJMatrixGetObject,(hA->ij,(void**)&parcsr));
918   PetscStackCallStandard(HYPRE_IJVectorGetObject,(hA->x,(void**)&hx));
919   PetscStackCallStandard(HYPRE_IJVectorGetObject,(hA->b,(void**)&hy));
920   ierr = VecGetArrayRead(x,(const PetscScalar**)&ax);CHKERRQ(ierr);
921   ierr = VecGetArray(y,&ay);CHKERRQ(ierr);
922   if (trans) {
923     VecHYPRE_ParVectorReplacePointer(hA->x,ay,say);
924     VecHYPRE_ParVectorReplacePointer(hA->b,ax,sax);
925     hypre_ParCSRMatrixMatvecT(1.,parcsr,hy,0.,hx);
926     VecHYPRE_ParVectorReplacePointer(hA->x,say,ay);
927     VecHYPRE_ParVectorReplacePointer(hA->b,sax,ax);
928   } else {
929     VecHYPRE_ParVectorReplacePointer(hA->x,ax,sax);
930     VecHYPRE_ParVectorReplacePointer(hA->b,ay,say);
931     hypre_ParCSRMatrixMatvec(1.,parcsr,hx,0.,hy);
932     VecHYPRE_ParVectorReplacePointer(hA->x,sax,ax);
933     VecHYPRE_ParVectorReplacePointer(hA->b,say,ay);
934   }
935   ierr = VecRestoreArrayRead(x,(const PetscScalar**)&ax);CHKERRQ(ierr);
936   ierr = VecRestoreArray(y,&ay);CHKERRQ(ierr);
937   PetscFunctionReturn(0);
938 }
939 
940 static PetscErrorCode MatDestroy_HYPRE(Mat A)
941 {
942   Mat_HYPRE      *hA = (Mat_HYPRE*)A->data;
943   PetscErrorCode ierr;
944 
945   PetscFunctionBegin;
946   if (hA->x) PetscStackCallStandard(HYPRE_IJVectorDestroy,(hA->x));
947   if (hA->b) PetscStackCallStandard(HYPRE_IJVectorDestroy,(hA->b));
948   if (hA->ij) {
949     if (!hA->inner_free) hypre_IJMatrixObject(hA->ij) = NULL;
950     PetscStackCallStandard(HYPRE_IJMatrixDestroy,(hA->ij));
951   }
952   if (hA->comm) { ierr = MPI_Comm_free(&hA->comm);CHKERRQ(ierr); }
953 
954   ierr = MatStashDestroy_Private(&A->stash);CHKERRQ(ierr);
955 
956   ierr = PetscFree(hA->array);CHKERRQ(ierr);
957 
958   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_hypre_aij_C",NULL);CHKERRQ(ierr);
959   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_hypre_is_C",NULL);CHKERRQ(ierr);
960   ierr = PetscObjectComposeFunction((PetscObject)A,"MatPtAP_seqaij_hypre_C",NULL);CHKERRQ(ierr);
961   ierr = PetscObjectComposeFunction((PetscObject)A,"MatPtAP_mpiaij_hypre_C",NULL);CHKERRQ(ierr);
962   ierr = PetscObjectComposeFunction((PetscObject)A,"MatHYPRESetPreallocation_C",NULL);CHKERRQ(ierr);
963   ierr = PetscObjectComposeFunction((PetscObject)A,"MatHYPREGetParCSR_C",NULL);CHKERRQ(ierr);
964   ierr = PetscObjectComposeFunction((PetscObject)A,"MatPtAP_is_hypre_C",NULL);CHKERRQ(ierr);
965   ierr = PetscFree(A->data);CHKERRQ(ierr);
966   PetscFunctionReturn(0);
967 }
968 
969 static PetscErrorCode MatSetUp_HYPRE(Mat A)
970 {
971   PetscErrorCode ierr;
972 
973   PetscFunctionBegin;
974   ierr = MatHYPRESetPreallocation(A,PETSC_DEFAULT,NULL,PETSC_DEFAULT,NULL);CHKERRQ(ierr);
975   PetscFunctionReturn(0);
976 }
977 
978 
979 static PetscErrorCode MatAssemblyEnd_HYPRE(Mat A, MatAssemblyType mode)
980 {
981   Mat_HYPRE          *hA = (Mat_HYPRE*)A->data;
982   Vec                x,b;
983   PetscMPIInt        n;
984   PetscInt           i,j,rstart,ncols,flg;
985   PetscInt           *row,*col;
986   PetscScalar        *val;
987   PetscErrorCode     ierr;
988 
989   PetscFunctionBegin;
990   if (mode == MAT_FLUSH_ASSEMBLY) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"MAT_FLUSH_ASSEMBLY currently not supported with MATHYPRE");
991 
992   if (!A->nooffprocentries) {
993     while (1) {
994       ierr = MatStashScatterGetMesg_Private(&A->stash,&n,&row,&col,&val,&flg);CHKERRQ(ierr);
995       if (!flg) break;
996 
997       for (i=0; i<n; ) {
998         /* Now identify the consecutive vals belonging to the same row */
999         for (j=i,rstart=row[j]; j<n; j++) {
1000           if (row[j] != rstart) break;
1001         }
1002         if (j < n) ncols = j-i;
1003         else       ncols = n-i;
1004         /* Now assemble all these values with a single function call */
1005         ierr = MatSetValues_HYPRE(A,1,row+i,ncols,col+i,val+i,A->insertmode);CHKERRQ(ierr);
1006 
1007         i = j;
1008       }
1009     }
1010     ierr = MatStashScatterEnd_Private(&A->stash);CHKERRQ(ierr);
1011   }
1012 
1013   PetscStackCallStandard(HYPRE_IJMatrixAssemble,(hA->ij));
1014   if (hA->x) PetscFunctionReturn(0);
1015   ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr);
1016   ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr);
1017   ierr = VecCreateMPIWithArray(PetscObjectComm((PetscObject)A),1,A->cmap->n,A->cmap->N,NULL,&x);CHKERRQ(ierr);
1018   ierr = VecCreateMPIWithArray(PetscObjectComm((PetscObject)A),1,A->rmap->n,A->rmap->N,NULL,&b);CHKERRQ(ierr);
1019   ierr = VecHYPRE_IJVectorCreate(x,&hA->x);CHKERRQ(ierr);
1020   ierr = VecHYPRE_IJVectorCreate(b,&hA->b);CHKERRQ(ierr);
1021   ierr = VecDestroy(&x);CHKERRQ(ierr);
1022   ierr = VecDestroy(&b);CHKERRQ(ierr);
1023   PetscFunctionReturn(0);
1024 }
1025 
1026 static PetscErrorCode MatGetArray_HYPRE(Mat A, PetscInt size, void **array)
1027 {
1028   Mat_HYPRE          *hA = (Mat_HYPRE*)A->data;
1029   PetscErrorCode     ierr;
1030 
1031   PetscFunctionBegin;
1032   if (!hA->available) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Temporary space is in use");
1033 
1034   if (hA->size >= size) *array = hA->array;
1035   else {
1036     ierr = PetscFree(hA->array);CHKERRQ(ierr);
1037     hA->size = size;
1038     ierr = PetscMalloc(hA->size,&hA->array);CHKERRQ(ierr);
1039     *array = hA->array;
1040   }
1041 
1042   hA->available = PETSC_FALSE;
1043   PetscFunctionReturn(0);
1044 }
1045 
1046 static PetscErrorCode MatRestoreArray_HYPRE(Mat A, void **array)
1047 {
1048   Mat_HYPRE          *hA = (Mat_HYPRE*)A->data;
1049 
1050   PetscFunctionBegin;
1051   *array = NULL;
1052   hA->available = PETSC_TRUE;
1053   PetscFunctionReturn(0);
1054 }
1055 
1056 
1057 PetscErrorCode MatSetValues_HYPRE(Mat A, PetscInt nr, const PetscInt rows[], PetscInt nc, const PetscInt cols[], const PetscScalar v[], InsertMode ins)
1058 {
1059   Mat_HYPRE          *hA = (Mat_HYPRE*)A->data;
1060   PetscScalar        *vals = (PetscScalar *)v;
1061   PetscScalar        *sscr;
1062   PetscInt           *cscr[2];
1063   PetscInt           i,nzc;
1064   void               *array = NULL;
1065   PetscErrorCode     ierr;
1066 
1067   PetscFunctionBegin;
1068   ierr = MatGetArray_HYPRE(A,sizeof(PetscInt)*(2*nc)+sizeof(PetscScalar)*nc*nr,&array);CHKERRQ(ierr);
1069   cscr[0] = (PetscInt*)array;
1070   cscr[1] = ((PetscInt*)array)+nc;
1071   sscr = (PetscScalar*)(((PetscInt*)array)+nc*2);
1072   for (i=0,nzc=0;i<nc;i++) {
1073     if (cols[i] >= 0) {
1074       cscr[0][nzc  ] = cols[i];
1075       cscr[1][nzc++] = i;
1076     }
1077   }
1078   if (!nzc) {
1079     ierr = MatRestoreArray_HYPRE(A,&array);CHKERRQ(ierr);
1080     PetscFunctionReturn(0);
1081   }
1082 
1083   if (ins == ADD_VALUES) {
1084     for (i=0;i<nr;i++) {
1085       if (rows[i] >= 0 && nzc) {
1086         PetscInt j;
1087         for (j=0;j<nzc;j++) sscr[j] = vals[cscr[1][j]];
1088         PetscStackCallStandard(HYPRE_IJMatrixAddToValues,(hA->ij,1,(HYPRE_Int*)&nzc,(HYPRE_Int*)(rows+i),(HYPRE_Int*)cscr[0],sscr));
1089       }
1090       vals += nc;
1091     }
1092   } else { /* INSERT_VALUES */
1093 
1094     PetscInt rst,ren;
1095     ierr = MatGetOwnershipRange(A,&rst,&ren);CHKERRQ(ierr);
1096 
1097     for (i=0;i<nr;i++) {
1098       if (rows[i] >= 0 && nzc) {
1099         PetscInt j;
1100         for (j=0;j<nzc;j++) sscr[j] = vals[cscr[1][j]];
1101         /* nonlocal values */
1102         if (rows[i] < rst || rows[i] >= ren) { ierr = MatStashValuesRow_Private(&A->stash,rows[i],nzc,cscr[0],sscr, PETSC_FALSE);CHKERRQ(ierr); }
1103         /* local values */
1104         else PetscStackCallStandard(HYPRE_IJMatrixSetValues,(hA->ij,1,(HYPRE_Int*)&nzc,(HYPRE_Int*)(rows+i),(HYPRE_Int*)cscr[0],sscr));
1105       }
1106       vals += nc;
1107     }
1108   }
1109 
1110   ierr = MatRestoreArray_HYPRE(A,&array);CHKERRQ(ierr);
1111   PetscFunctionReturn(0);
1112 }
1113 
1114 static PetscErrorCode MatHYPRESetPreallocation_HYPRE(Mat A, PetscInt dnz, const PetscInt dnnz[], PetscInt onz, const PetscInt onnz[])
1115 {
1116   Mat_HYPRE          *hA = (Mat_HYPRE*)A->data;
1117   HYPRE_Int          *hdnnz,*honnz;
1118   PetscInt           i,rs,re,cs,ce,bs;
1119   PetscMPIInt        size;
1120   PetscErrorCode     ierr;
1121 
1122   PetscFunctionBegin;
1123   ierr = MatGetBlockSize(A,&bs);CHKERRQ(ierr);
1124   ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr);
1125   ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr);
1126   rs   = A->rmap->rstart;
1127   re   = A->rmap->rend;
1128   cs   = A->cmap->rstart;
1129   ce   = A->cmap->rend;
1130   if (!hA->ij) {
1131     PetscStackCallStandard(HYPRE_IJMatrixCreate,(hA->comm,rs,re-1,cs,ce-1,&hA->ij));
1132     PetscStackCallStandard(HYPRE_IJMatrixSetObjectType,(hA->ij,HYPRE_PARCSR));
1133   } else {
1134     HYPRE_Int hrs,hre,hcs,hce;
1135     PetscStackCallStandard(HYPRE_IJMatrixGetLocalRange,(hA->ij,&hrs,&hre,&hcs,&hce));
1136     if (hre-hrs+1 != re -rs) SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Inconsistent local rows: IJMatrix [%D,%D), PETSc [%D,%d)",hrs,hre+1,rs,re);
1137     if (hce-hcs+1 != ce -cs) SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Inconsistent local cols: IJMatrix [%D,%D), PETSc [%D,%d)",hcs,hce+1,cs,ce);
1138   }
1139   PetscStackCallStandard(HYPRE_IJMatrixInitialize,(hA->ij));
1140 
1141   if (dnz == PETSC_DEFAULT || dnz == PETSC_DECIDE) dnz = 10*bs;
1142   if (onz == PETSC_DEFAULT || onz == PETSC_DECIDE) onz = 10*bs;
1143 
1144   if (!dnnz) {
1145     ierr = PetscMalloc1(A->rmap->n,&hdnnz);CHKERRQ(ierr);
1146     for (i=0;i<A->rmap->n;i++) hdnnz[i] = dnz;
1147   } else {
1148     hdnnz = (HYPRE_Int*)dnnz;
1149   }
1150   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)A),&size);CHKERRQ(ierr);
1151   if (size > 1) {
1152     if (!onnz) {
1153       ierr = PetscMalloc1(A->rmap->n,&honnz);CHKERRQ(ierr);
1154       for (i=0;i<A->rmap->n;i++) honnz[i] = onz;
1155     } else {
1156       honnz = (HYPRE_Int*)onnz;
1157     }
1158     PetscStackCallStandard(HYPRE_IJMatrixSetDiagOffdSizes,(hA->ij,hdnnz,honnz));
1159   } else {
1160     honnz = NULL;
1161     PetscStackCallStandard(HYPRE_IJMatrixSetRowSizes,(hA->ij,hdnnz));
1162   }
1163   if (!dnnz) {
1164     ierr = PetscFree(hdnnz);CHKERRQ(ierr);
1165   }
1166   if (!onnz && honnz) {
1167     ierr = PetscFree(honnz);CHKERRQ(ierr);
1168   }
1169   A->preallocated = PETSC_TRUE;
1170 
1171   /* SetDiagOffdSizes sets hypre_AuxParCSRMatrixNeedAux(aux_matrix) = 0 */
1172   {
1173     hypre_AuxParCSRMatrix *aux_matrix;
1174     aux_matrix = (hypre_AuxParCSRMatrix*)hypre_IJMatrixTranslator(hA->ij);
1175     hypre_AuxParCSRMatrixNeedAux(aux_matrix) = 1;
1176   }
1177   PetscFunctionReturn(0);
1178 }
1179 
1180 /*@C
1181    MatHYPRESetPreallocation - Preallocates memory for a sparse parallel matrix in HYPRE IJ format
1182 
1183    Collective on Mat
1184 
1185    Input Parameters:
1186 +  A - the matrix
1187 .  dnz  - number of nonzeros per row in DIAGONAL portion of local submatrix
1188           (same value is used for all local rows)
1189 .  dnnz - array containing the number of nonzeros in the various rows of the
1190           DIAGONAL portion of the local submatrix (possibly different for each row)
1191           or NULL (PETSC_NULL_INTEGER in Fortran), if d_nz is used to specify the nonzero structure.
1192           The size of this array is equal to the number of local rows, i.e 'm'.
1193           For matrices that will be factored, you must leave room for (and set)
1194           the diagonal entry even if it is zero.
1195 .  onz  - number of nonzeros per row in the OFF-DIAGONAL portion of local
1196           submatrix (same value is used for all local rows).
1197 -  onnz - array containing the number of nonzeros in the various rows of the
1198           OFF-DIAGONAL portion of the local submatrix (possibly different for
1199           each row) or NULL (PETSC_NULL_INTEGER in Fortran), if o_nz is used to specify the nonzero
1200           structure. The size of this array is equal to the number
1201           of local rows, i.e 'm'.
1202 
1203    Notes:
1204     If the *nnz parameter is given then the *nz parameter is ignored; for sequential matrices, onz and onnz are ignored.
1205 
1206    Level: intermediate
1207 
1208 .keywords: matrix, aij, compressed row, sparse, parallel
1209 
1210 .seealso: MatCreate(), MatMPIAIJSetPreallocation, MATHYPRE
1211 @*/
1212 PetscErrorCode MatHYPRESetPreallocation(Mat A, PetscInt dnz, const PetscInt dnnz[], PetscInt onz, const PetscInt onnz[])
1213 {
1214   PetscErrorCode ierr;
1215 
1216   PetscFunctionBegin;
1217   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1218   PetscValidType(A,1);
1219   ierr = PetscTryMethod(A,"MatHYPRESetPreallocation_C",(Mat,PetscInt,const PetscInt[],PetscInt,const PetscInt[]),(A,dnz,dnnz,onz,onnz));CHKERRQ(ierr);
1220   PetscFunctionReturn(0);
1221 }
1222 
1223 /*
1224    MatCreateFromParCSR - Creates a matrix from a hypre_ParCSRMatrix
1225 
1226    Collective
1227 
1228    Input Parameters:
1229 +  vparcsr  - the pointer to the hypre_ParCSRMatrix
1230 .  mtype    - matrix type to be created. Currently MATAIJ, MATIS and MATHYPRE are supported.
1231 -  copymode - PETSc copying options
1232 
1233    Output Parameter:
1234 .  A  - the matrix
1235 
1236    Level: intermediate
1237 
1238 .seealso: MatHYPRE, PetscCopyMode
1239 */
1240 PETSC_EXTERN PetscErrorCode MatCreateFromParCSR(hypre_ParCSRMatrix *vparcsr, MatType mtype, PetscCopyMode copymode, Mat* A)
1241 {
1242   Mat                   T;
1243   Mat_HYPRE             *hA;
1244   hypre_ParCSRMatrix    *parcsr;
1245   MPI_Comm              comm;
1246   PetscInt              rstart,rend,cstart,cend,M,N;
1247   PetscBool             isseqaij,ismpiaij,isaij,ishyp,isis;
1248   PetscErrorCode        ierr;
1249 
1250   PetscFunctionBegin;
1251   parcsr = (hypre_ParCSRMatrix *)vparcsr;
1252   comm   = hypre_ParCSRMatrixComm(parcsr);
1253   ierr   = PetscStrcmp(mtype,MATSEQAIJ,&isseqaij);CHKERRQ(ierr);
1254   ierr   = PetscStrcmp(mtype,MATMPIAIJ,&ismpiaij);CHKERRQ(ierr);
1255   ierr   = PetscStrcmp(mtype,MATAIJ,&isaij);CHKERRQ(ierr);
1256   ierr   = PetscStrcmp(mtype,MATHYPRE,&ishyp);CHKERRQ(ierr);
1257   ierr   = PetscStrcmp(mtype,MATIS,&isis);CHKERRQ(ierr);
1258   isaij  = (PetscBool)(isseqaij || ismpiaij || isaij);
1259   if (!isaij && !ishyp && !isis) SETERRQ6(comm,PETSC_ERR_SUP,"Unsupported MatType %s! Supported types are %s, %s, %s, %s, and %s",mtype,MATAIJ,MATSEQAIJ,MATMPIAIJ,MATIS,MATHYPRE);
1260   if (ishyp && copymode == PETSC_COPY_VALUES) SETERRQ(comm,PETSC_ERR_SUP,"Unsupported copymode PETSC_COPY_VALUES");
1261 
1262   /* access ParCSRMatrix */
1263   rstart = hypre_ParCSRMatrixFirstRowIndex(parcsr);
1264   rend   = hypre_ParCSRMatrixLastRowIndex(parcsr);
1265   cstart = hypre_ParCSRMatrixFirstColDiag(parcsr);
1266   cend   = hypre_ParCSRMatrixLastColDiag(parcsr);
1267   M      = hypre_ParCSRMatrixGlobalNumRows(parcsr);
1268   N      = hypre_ParCSRMatrixGlobalNumCols(parcsr);
1269 
1270   /* fix for empty local rows/columns */
1271   if (rend < rstart) rend = rstart;
1272   if (cend < cstart) cend = cstart;
1273 
1274   /* create PETSc matrix with MatHYPRE */
1275   ierr = MatCreate(comm,&T);CHKERRQ(ierr);
1276   ierr = MatSetSizes(T,rend-rstart+1,cend-cstart+1,M,N);CHKERRQ(ierr);
1277   ierr = MatSetType(T,MATHYPRE);CHKERRQ(ierr);
1278   hA   = (Mat_HYPRE*)(T->data);
1279 
1280   /* create HYPRE_IJMatrix */
1281   PetscStackCallStandard(HYPRE_IJMatrixCreate,(hA->comm,rstart,rend-1,cstart,cend-1,&hA->ij));
1282 
1283   /* set ParCSR object */
1284   PetscStackCallStandard(HYPRE_IJMatrixSetObjectType,(hA->ij,HYPRE_PARCSR));
1285   hypre_IJMatrixObject(hA->ij) = parcsr;
1286   T->preallocated = PETSC_TRUE;
1287 
1288   /* set assembled flag */
1289   hypre_IJMatrixAssembleFlag(hA->ij) = 1;
1290   PetscStackCallStandard(HYPRE_IJMatrixInitialize,(hA->ij));
1291   if (ishyp) {
1292     PetscMPIInt myid = 0;
1293 
1294     /* make sure we always have row_starts and col_starts available */
1295     if (HYPRE_AssumedPartitionCheck()) {
1296       ierr = MPI_Comm_rank(comm,&myid);CHKERRQ(ierr);
1297     }
1298     if (!hypre_ParCSRMatrixOwnsColStarts(parcsr)) {
1299       PetscLayout map;
1300 
1301       ierr = MatGetLayouts(T,NULL,&map);CHKERRQ(ierr);
1302       ierr = PetscLayoutSetUp(map);CHKERRQ(ierr);
1303       hypre_ParCSRMatrixColStarts(parcsr) = (HYPRE_Int*)(map->range + myid);
1304     }
1305     if (!hypre_ParCSRMatrixOwnsRowStarts(parcsr)) {
1306       PetscLayout map;
1307 
1308       ierr = MatGetLayouts(T,&map,NULL);CHKERRQ(ierr);
1309       ierr = PetscLayoutSetUp(map);CHKERRQ(ierr);
1310       hypre_ParCSRMatrixRowStarts(parcsr) = (HYPRE_Int*)(map->range + myid);
1311     }
1312     /* prevent from freeing the pointer */
1313     if (copymode == PETSC_USE_POINTER) hA->inner_free = PETSC_FALSE;
1314     *A   = T;
1315     ierr = MatAssemblyBegin(*A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1316     ierr = MatAssemblyEnd(*A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1317   } else if (isaij) {
1318     if (copymode != PETSC_OWN_POINTER) {
1319       /* prevent from freeing the pointer */
1320       hA->inner_free = PETSC_FALSE;
1321       ierr = MatConvert_HYPRE_AIJ(T,MATAIJ,MAT_INITIAL_MATRIX,A);CHKERRQ(ierr);
1322       ierr = MatDestroy(&T);CHKERRQ(ierr);
1323     } else { /* AIJ return type with PETSC_OWN_POINTER */
1324       ierr = MatConvert_HYPRE_AIJ(T,MATAIJ,MAT_INPLACE_MATRIX,&T);CHKERRQ(ierr);
1325       *A   = T;
1326     }
1327   } else if (isis) {
1328     ierr = MatConvert_HYPRE_IS(T,MATIS,MAT_INITIAL_MATRIX,A);CHKERRQ(ierr);
1329     if (copymode != PETSC_OWN_POINTER) hA->inner_free = PETSC_FALSE;
1330     ierr = MatDestroy(&T);CHKERRQ(ierr);
1331   }
1332   PetscFunctionReturn(0);
1333 }
1334 
1335 static PetscErrorCode MatHYPREGetParCSR_HYPRE(Mat A, hypre_ParCSRMatrix **parcsr)
1336 {
1337   Mat_HYPRE*            hA = (Mat_HYPRE*)A->data;
1338   HYPRE_Int             type;
1339   PetscErrorCode        ierr;
1340 
1341   PetscFunctionBegin;
1342   if (!hA->ij) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"HYPRE_IJMatrix not present");
1343   PetscStackCallStandard(HYPRE_IJMatrixGetObjectType,(hA->ij,&type));
1344   if (type != HYPRE_PARCSR) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"HYPRE_IJMatrix is not of type HYPRE_PARCSR");
1345   PetscStackCallStandard(HYPRE_IJMatrixGetObject,(hA->ij,(void**)parcsr));
1346   PetscFunctionReturn(0);
1347 }
1348 
1349 /*
1350    MatHYPREGetParCSR - Gets the pointer to the ParCSR matrix
1351 
1352    Not collective
1353 
1354    Input Parameters:
1355 +  A  - the MATHYPRE object
1356 
1357    Output Parameter:
1358 .  parcsr  - the pointer to the hypre_ParCSRMatrix
1359 
1360    Level: intermediate
1361 
1362 .seealso: MatHYPRE, PetscCopyMode
1363 */
1364 PetscErrorCode MatHYPREGetParCSR(Mat A, hypre_ParCSRMatrix **parcsr)
1365 {
1366   PetscErrorCode ierr;
1367 
1368   PetscFunctionBegin;
1369   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1370   PetscValidType(A,1);
1371   ierr = PetscUseMethod(A,"MatHYPREGetParCSR_C",(Mat,hypre_ParCSRMatrix**),(A,parcsr));CHKERRQ(ierr);
1372   PetscFunctionReturn(0);
1373 }
1374 
1375 static PetscErrorCode MatMissingDiagonal_HYPRE(Mat A, PetscBool *missing, PetscInt *dd)
1376 {
1377   hypre_ParCSRMatrix *parcsr;
1378   hypre_CSRMatrix    *ha;
1379   PetscInt           rst;
1380   PetscErrorCode     ierr;
1381 
1382   PetscFunctionBegin;
1383   if (A->rmap->n != A->cmap->n) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Not implemented with non-square diagonal blocks");
1384   ierr = MatGetOwnershipRange(A,&rst,NULL);CHKERRQ(ierr);
1385   ierr = MatHYPREGetParCSR_HYPRE(A,&parcsr);CHKERRQ(ierr);
1386   if (missing) *missing = PETSC_FALSE;
1387   if (dd) *dd = -1;
1388   ha = hypre_ParCSRMatrixDiag(parcsr);
1389   if (ha) {
1390     PetscInt  size,i;
1391     HYPRE_Int *ii,*jj;
1392 
1393     size = hypre_CSRMatrixNumRows(ha);
1394     ii   = hypre_CSRMatrixI(ha);
1395     jj   = hypre_CSRMatrixJ(ha);
1396     for (i = 0; i < size; i++) {
1397       PetscInt  j;
1398       PetscBool found = PETSC_FALSE;
1399 
1400       for (j = ii[i]; j < ii[i+1] && !found; j++)
1401         found = (jj[j] == i) ? PETSC_TRUE : PETSC_FALSE;
1402 
1403       if (!found) {
1404         PetscInfo1(A,"Matrix is missing local diagonal entry %D\n",i);
1405         if (missing) *missing = PETSC_TRUE;
1406         if (dd) *dd = i+rst;
1407         PetscFunctionReturn(0);
1408       }
1409     }
1410     if (!size) {
1411       PetscInfo(A,"Matrix has no diagonal entries therefore is missing diagonal\n");
1412       if (missing) *missing = PETSC_TRUE;
1413       if (dd) *dd = rst;
1414     }
1415   } else {
1416     PetscInfo(A,"Matrix has no diagonal entries therefore is missing diagonal\n");
1417     if (missing) *missing = PETSC_TRUE;
1418     if (dd) *dd = rst;
1419   }
1420   PetscFunctionReturn(0);
1421 }
1422 
1423 static PetscErrorCode MatScale_HYPRE(Mat A, PetscScalar s)
1424 {
1425   hypre_ParCSRMatrix *parcsr;
1426   hypre_CSRMatrix    *ha;
1427   PetscErrorCode     ierr;
1428 
1429   PetscFunctionBegin;
1430   ierr  = MatHYPREGetParCSR_HYPRE(A,&parcsr);CHKERRQ(ierr);
1431   /* diagonal part */
1432   ha = hypre_ParCSRMatrixDiag(parcsr);
1433   if (ha) {
1434     PetscInt    size,i;
1435     HYPRE_Int   *ii;
1436     PetscScalar *a;
1437 
1438     size = hypre_CSRMatrixNumRows(ha);
1439     a    = hypre_CSRMatrixData(ha);
1440     ii   = hypre_CSRMatrixI(ha);
1441     for (i = 0; i < ii[size]; i++) a[i] *= s;
1442   }
1443   /* offdiagonal part */
1444   ha = hypre_ParCSRMatrixOffd(parcsr);
1445   if (ha) {
1446     PetscInt    size,i;
1447     HYPRE_Int   *ii;
1448     PetscScalar *a;
1449 
1450     size = hypre_CSRMatrixNumRows(ha);
1451     a    = hypre_CSRMatrixData(ha);
1452     ii   = hypre_CSRMatrixI(ha);
1453     for (i = 0; i < ii[size]; i++) a[i] *= s;
1454   }
1455   PetscFunctionReturn(0);
1456 }
1457 
1458 static PetscErrorCode MatZeroRowsColumns_HYPRE(Mat A, PetscInt numRows, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
1459 {
1460   hypre_ParCSRMatrix *parcsr;
1461   HYPRE_Int          *lrows;
1462   PetscInt           rst,ren,i;
1463   PetscErrorCode     ierr;
1464 
1465   PetscFunctionBegin;
1466   if (x || b) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"To be implemented");
1467   ierr = MatHYPREGetParCSR_HYPRE(A,&parcsr);CHKERRQ(ierr);
1468   ierr = PetscMalloc1(numRows,&lrows);CHKERRQ(ierr);
1469   ierr = MatGetOwnershipRange(A,&rst,&ren);CHKERRQ(ierr);
1470   for (i=0;i<numRows;i++) {
1471     if (rows[i] < rst || rows[i] >= ren)
1472       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Non-local rows not yet supported");
1473     lrows[i] = rows[i] - rst;
1474   }
1475   PetscStackCallStandard(hypre_ParCSRMatrixEliminateRowsCols,(parcsr,numRows,lrows));
1476   ierr = PetscFree(lrows);CHKERRQ(ierr);
1477   PetscFunctionReturn(0);
1478 }
1479 
1480 static PetscErrorCode MatZeroEntries_HYPRE_CSRMatrix(hypre_CSRMatrix *ha)
1481 {
1482   PetscErrorCode      ierr;
1483 
1484   PetscFunctionBegin;
1485   if (ha) {
1486     HYPRE_Int     *ii, size;
1487     HYPRE_Complex *a;
1488 
1489     size = hypre_CSRMatrixNumRows(ha);
1490     a    = hypre_CSRMatrixData(ha);
1491     ii   = hypre_CSRMatrixI(ha);
1492 
1493     if (a) { ierr = PetscMemzero(a,(ii[size])*sizeof(HYPRE_Complex));CHKERRQ(ierr); }
1494   }
1495   PetscFunctionReturn(0);
1496 }
1497 
1498 PetscErrorCode MatZeroEntries_HYPRE(Mat A)
1499 {
1500   hypre_ParCSRMatrix  *parcsr;
1501   PetscErrorCode      ierr;
1502 
1503   PetscFunctionBegin;
1504   ierr = MatHYPREGetParCSR_HYPRE(A,&parcsr);CHKERRQ(ierr);
1505   /* diagonal part */
1506   ierr = MatZeroEntries_HYPRE_CSRMatrix(hypre_ParCSRMatrixDiag(parcsr));CHKERRQ(ierr);
1507   /* off-diagonal part */
1508   ierr = MatZeroEntries_HYPRE_CSRMatrix(hypre_ParCSRMatrixOffd(parcsr));CHKERRQ(ierr);
1509   PetscFunctionReturn(0);
1510 }
1511 
1512 
1513 static PetscErrorCode MatZeroRows_HYPRE_CSRMatrix(hypre_CSRMatrix *hA,PetscInt N,const PetscInt rows[],PetscScalar diag)
1514 {
1515   PetscInt        ii, jj, ibeg, iend, irow;
1516   PetscInt        *i, *j;
1517   PetscScalar     *a;
1518 
1519   PetscFunctionBegin;
1520 
1521   if (!hA) PetscFunctionReturn(0);
1522 
1523   i = (PetscInt*) hypre_CSRMatrixI(hA);
1524   j = (PetscInt*) hypre_CSRMatrixJ(hA);
1525   a = hypre_CSRMatrixData(hA);
1526 
1527   for (ii = 0; ii < N; ii++) {
1528     irow = rows[ii];
1529     ibeg = i[irow];
1530     iend = i[irow+1];
1531     for (jj = ibeg; jj < iend; jj++)
1532       if (j[jj] == irow) a[jj] = diag;
1533       else a[jj] = 0.0;
1534    }
1535 
1536    PetscFunctionReturn(0);
1537 }
1538 
1539 PetscErrorCode MatZeroRows_HYPRE(Mat A,PetscInt N,const PetscInt rows[],PetscScalar diag,Vec x,Vec b)
1540 {
1541   hypre_ParCSRMatrix  *parcsr;
1542   PetscInt            *lrows,len;
1543   PetscErrorCode      ierr;
1544 
1545   PetscFunctionBegin;
1546   if (x || b) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Does not support to modify the solution and the right hand size \n");
1547   /* retrieve the internal matrix */
1548   ierr = MatHYPREGetParCSR_HYPRE(A,&parcsr);CHKERRQ(ierr);
1549   /* get locally owned rows */
1550   ierr = MatZeroRowsMapLocal_Private(A,N,rows,&len,&lrows);CHKERRQ(ierr);
1551   /* zero diagonal part */
1552   ierr = MatZeroRows_HYPRE_CSRMatrix(hypre_ParCSRMatrixDiag(parcsr),len,lrows,diag);CHKERRQ(ierr);
1553   /* zero off-diagonal part */
1554   ierr = MatZeroRows_HYPRE_CSRMatrix(hypre_ParCSRMatrixOffd(parcsr),len,lrows,0.0);CHKERRQ(ierr);
1555 
1556   ierr = PetscFree(lrows);CHKERRQ(ierr);
1557   PetscFunctionReturn(0);
1558 }
1559 
1560 
1561 PetscErrorCode MatAssemblyBegin_HYPRE(Mat mat,MatAssemblyType mode)
1562 {
1563   PetscErrorCode ierr;
1564 
1565   PetscFunctionBegin;
1566   if (mat->nooffprocentries) PetscFunctionReturn(0);
1567 
1568   ierr = MatStashScatterBegin_Private(mat,&mat->stash,mat->rmap->range);CHKERRQ(ierr);
1569   PetscFunctionReturn(0);
1570 }
1571 
1572 PetscErrorCode MatGetRow_HYPRE(Mat A,PetscInt row,PetscInt *nz,PetscInt **idx,PetscScalar **v)
1573 {
1574   hypre_ParCSRMatrix  *parcsr;
1575   PetscErrorCode      ierr;
1576 
1577   PetscFunctionBegin;
1578   /* retrieve the internal matrix */
1579   ierr = MatHYPREGetParCSR_HYPRE(A,&parcsr);CHKERRQ(ierr);
1580   /* call HYPRE API */
1581   PetscStackCallStandard(HYPRE_ParCSRMatrixGetRow,(parcsr,row,(HYPRE_Int*)nz,(HYPRE_Int**)idx,v));
1582   PetscFunctionReturn(0);
1583 }
1584 
1585 PetscErrorCode MatRestoreRow_HYPRE(Mat A,PetscInt row,PetscInt *nz,PetscInt **idx,PetscScalar **v)
1586 {
1587   hypre_ParCSRMatrix  *parcsr;
1588   PetscErrorCode      ierr;
1589 
1590   PetscFunctionBegin;
1591   /* retrieve the internal matrix */
1592   ierr = MatHYPREGetParCSR_HYPRE(A,&parcsr);CHKERRQ(ierr);
1593   /* call HYPRE API */
1594   PetscStackCallStandard(HYPRE_ParCSRMatrixRestoreRow,(parcsr,row,(HYPRE_Int*)nz,(HYPRE_Int**)idx,v));
1595   PetscFunctionReturn(0);
1596 }
1597 
1598 
1599 
1600 PetscErrorCode MatGetValues_HYPRE(Mat A,PetscInt m,const PetscInt idxm[],PetscInt n,const PetscInt idxn[],PetscScalar v[])
1601 {
1602   HYPRE_IJMatrix     *hIJ = (HYPRE_IJMatrix*)A->data;
1603   PetscErrorCode      ierr;
1604   PetscInt            i;
1605   PetscFunctionBegin;
1606   if (!m || !n) PetscFunctionReturn(0);
1607 
1608   /* Ignore negative row indices
1609    * And negative column indices should be automatically ignored in hypre
1610    * */
1611   for (i=0; i<m; i++)
1612     if (idxm[i] >= 0) PetscStackCallStandard(HYPRE_IJMatrixGetValues,(*hIJ,1,(HYPRE_Int*)&n,(HYPRE_Int*)&idxm[i],(HYPRE_Int*)idxn,&v[i*n]));
1613 
1614   PetscFunctionReturn(0);
1615 }
1616 
1617 
1618 /*MC
1619    MATHYPRE - MATHYPRE = "hypre" - A matrix type to be used for sequential and parallel sparse matrices
1620           based on the hypre IJ interface.
1621 
1622    Level: intermediate
1623 
1624 .seealso: MatCreate()
1625 M*/
1626 
1627 PETSC_EXTERN PetscErrorCode MatCreate_HYPRE(Mat B)
1628 {
1629   Mat_HYPRE      *hB;
1630   PetscErrorCode ierr;
1631 
1632   PetscFunctionBegin;
1633   ierr           = PetscNewLog(B,&hB);CHKERRQ(ierr);
1634   hB->inner_free = PETSC_TRUE;
1635   hB->available  = PETSC_TRUE;
1636   hB->size       = 0;
1637   hB->array      = NULL;
1638 
1639   B->data       = (void*)hB;
1640   B->rmap->bs   = 1;
1641   B->assembled  = PETSC_FALSE;
1642 
1643   ierr = PetscMemzero(B->ops,sizeof(struct _MatOps));CHKERRQ(ierr);
1644   B->ops->mult            = MatMult_HYPRE;
1645   B->ops->multtranspose   = MatMultTranspose_HYPRE;
1646   B->ops->setup           = MatSetUp_HYPRE;
1647   B->ops->destroy         = MatDestroy_HYPRE;
1648 
1649   /* build cache for off array entries formed */
1650   ierr = MatStashCreate_Private(PetscObjectComm((PetscObject)B),1,&B->stash);CHKERRQ(ierr);
1651   B->ops->assemblyend     = MatAssemblyEnd_HYPRE;
1652   B->ops->assemblybegin   = MatAssemblyBegin_HYPRE;
1653 
1654   B->ops->ptap            = MatPtAP_HYPRE_HYPRE;
1655   B->ops->matmult         = MatMatMult_HYPRE_HYPRE;
1656   B->ops->setvalues       = MatSetValues_HYPRE;
1657   B->ops->missingdiagonal = MatMissingDiagonal_HYPRE;
1658   B->ops->scale           = MatScale_HYPRE;
1659   B->ops->zerorowscolumns = MatZeroRowsColumns_HYPRE;
1660   B->ops->zeroentries     = MatZeroEntries_HYPRE;
1661   B->ops->zerorows        = MatZeroRows_HYPRE;
1662   B->ops->getrow          = MatGetRow_HYPRE;
1663   B->ops->restorerow      = MatRestoreRow_HYPRE;
1664   B->ops->getvalues       = MatGetValues_HYPRE;
1665 
1666   ierr = MPI_Comm_dup(PetscObjectComm((PetscObject)B),&hB->comm);CHKERRQ(ierr);
1667   ierr = PetscObjectChangeTypeName((PetscObject)B,MATHYPRE);CHKERRQ(ierr);
1668   ierr = PetscObjectComposeFunction((PetscObject)B,"MatConvert_hypre_aij_C",MatConvert_HYPRE_AIJ);CHKERRQ(ierr);
1669   ierr = PetscObjectComposeFunction((PetscObject)B,"MatConvert_hypre_is_C",MatConvert_HYPRE_IS);CHKERRQ(ierr);
1670   ierr = PetscObjectComposeFunction((PetscObject)B,"MatPtAP_seqaij_hypre_C",MatPtAP_AIJ_HYPRE);CHKERRQ(ierr);
1671   ierr = PetscObjectComposeFunction((PetscObject)B,"MatPtAP_mpiaij_hypre_C",MatPtAP_AIJ_HYPRE);CHKERRQ(ierr);
1672   ierr = PetscObjectComposeFunction((PetscObject)B,"MatHYPRESetPreallocation_C",MatHYPRESetPreallocation_HYPRE);CHKERRQ(ierr);
1673   ierr = PetscObjectComposeFunction((PetscObject)B,"MatHYPREGetParCSR_C",MatHYPREGetParCSR_HYPRE);CHKERRQ(ierr);
1674   ierr = PetscObjectComposeFunction((PetscObject)B,"MatPtAP_is_hypre_C",MatPtAP_IS_XAIJ);CHKERRQ(ierr);
1675   PetscFunctionReturn(0);
1676 }
1677 
1678 static PetscErrorCode hypre_array_destroy(void *ptr)
1679 {
1680    PetscFunctionBegin;
1681    hypre_TFree(ptr,HYPRE_MEMORY_HOST);
1682    PetscFunctionReturn(0);
1683 }
1684