1 2 /* 3 Creates hypre ijmatrix from PETSc matrix 4 */ 5 #include <petscsys.h> 6 #include <petsc-private/matimpl.h> /*I "petscmat.h" I*/ 7 #include <petscdmda.h> /*I "petscdmda.h" I*/ 8 #include <../src/dm/impls/da/hypre/mhyp.h> 9 10 #undef __FUNCT__ 11 #define __FUNCT__ "MatHYPRE_IJMatrixPreallocate" 12 PetscErrorCode MatHYPRE_IJMatrixPreallocate(Mat A_d, Mat A_o,HYPRE_IJMatrix ij) 13 { 14 PetscErrorCode ierr; 15 PetscInt i,n_d,n_o; 16 const PetscInt *ia_d,*ia_o; 17 PetscBool done_d=PETSC_FALSE,done_o=PETSC_FALSE; 18 PetscInt *nnz_d=PETSC_NULL,*nnz_o=PETSC_NULL; 19 20 PetscFunctionBegin; 21 if (A_d) { /* determine number of nonzero entries in local diagonal part */ 22 ierr = MatGetRowIJ(A_d,0,PETSC_FALSE,PETSC_FALSE,&n_d,&ia_d,PETSC_NULL,&done_d);CHKERRQ(ierr); 23 if (done_d) { 24 ierr = PetscMalloc(n_d*sizeof(PetscInt),&nnz_d);CHKERRQ(ierr); 25 for (i=0; i<n_d; i++) { 26 nnz_d[i] = ia_d[i+1] - ia_d[i]; 27 } 28 } 29 ierr = MatRestoreRowIJ(A_d,0,PETSC_FALSE,PETSC_FALSE,&n_d,&ia_d,PETSC_NULL,&done_d);CHKERRQ(ierr); 30 } 31 if (A_o) { /* determine number of nonzero entries in local off-diagonal part */ 32 ierr = MatGetRowIJ(A_o,0,PETSC_FALSE,PETSC_FALSE,&n_o,&ia_o,PETSC_NULL,&done_o);CHKERRQ(ierr); 33 if (done_o) { 34 ierr = PetscMalloc(n_o*sizeof(PetscInt),&nnz_o);CHKERRQ(ierr); 35 for (i=0; i<n_o; i++) { 36 nnz_o[i] = ia_o[i+1] - ia_o[i]; 37 } 38 } 39 ierr = MatRestoreRowIJ(A_o,0,PETSC_FALSE,PETSC_FALSE,&n_o,&ia_o,PETSC_NULL,&done_o);CHKERRQ(ierr); 40 } 41 if (done_d) { /* set number of nonzeros in HYPRE IJ matrix */ 42 if (!done_o) { /* only diagonal part */ 43 ierr = PetscMalloc(n_d*sizeof(PetscInt),&nnz_o);CHKERRQ(ierr); 44 for (i=0; i<n_d; i++) { 45 nnz_o[i] = 0; 46 } 47 } 48 PetscStackCallHypre(0,HYPRE_IJMatrixSetDiagOffdSizes,(ij,nnz_d,nnz_o)); 49 ierr = PetscFree(nnz_d);CHKERRQ(ierr); 50 ierr = PetscFree(nnz_o);CHKERRQ(ierr); 51 } 52 PetscFunctionReturn(0); 53 } 54 55 #undef __FUNCT__ 56 #define __FUNCT__ "MatHYPRE_IJMatrixCreate" 57 PetscErrorCode MatHYPRE_IJMatrixCreate(Mat A,HYPRE_IJMatrix *ij) 58 { 59 PetscErrorCode ierr; 60 PetscInt rstart,rend,cstart,cend; 61 62 PetscFunctionBegin; 63 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 64 PetscValidType(A,1); 65 PetscValidPointer(ij,2); 66 ierr = MatSetUp(A);CHKERRQ(ierr); 67 rstart = A->rmap->rstart; 68 rend = A->rmap->rend; 69 cstart = A->cmap->rstart; 70 cend = A->cmap->rend; 71 PetscStackCallHypre(0,HYPRE_IJMatrixCreate,(((PetscObject)A)->comm,rstart,rend-1,cstart,cend-1,ij)); 72 PetscStackCallHypre(0,HYPRE_IJMatrixSetObjectType,(*ij,HYPRE_PARCSR)); 73 { 74 PetscBool same; 75 Mat A_d,A_o; 76 const PetscInt *colmap; 77 ierr = PetscObjectTypeCompare((PetscObject)A,MATMPIAIJ,&same);CHKERRQ(ierr); 78 if (same) { 79 ierr = MatMPIAIJGetSeqAIJ(A,&A_d,&A_o,&colmap);CHKERRQ(ierr); 80 ierr = MatHYPRE_IJMatrixPreallocate(A_d,A_o,*ij);CHKERRQ(ierr); 81 PetscFunctionReturn(0); 82 } 83 ierr = PetscObjectTypeCompare((PetscObject)A,MATMPIBAIJ,&same);CHKERRQ(ierr); 84 if (same) { 85 ierr = MatMPIBAIJGetSeqBAIJ(A,&A_d,&A_o,&colmap);CHKERRQ(ierr); 86 ierr = MatHYPRE_IJMatrixPreallocate(A_d,A_o,*ij);CHKERRQ(ierr); 87 PetscFunctionReturn(0); 88 } 89 ierr = PetscObjectTypeCompare((PetscObject)A,MATSEQAIJ,&same);CHKERRQ(ierr); 90 if (same) { 91 ierr = MatHYPRE_IJMatrixPreallocate(A,PETSC_NULL,*ij);CHKERRQ(ierr); 92 PetscFunctionReturn(0); 93 } 94 ierr = PetscObjectTypeCompare((PetscObject)A,MATSEQBAIJ,&same);CHKERRQ(ierr); 95 if (same) { 96 ierr = MatHYPRE_IJMatrixPreallocate(A,PETSC_NULL,*ij);CHKERRQ(ierr); 97 PetscFunctionReturn(0); 98 } 99 } 100 PetscFunctionReturn(0); 101 } 102 103 extern PetscErrorCode MatHYPRE_IJMatrixFastCopy_MPIAIJ(Mat,HYPRE_IJMatrix); 104 extern PetscErrorCode MatHYPRE_IJMatrixFastCopy_SeqAIJ(Mat,HYPRE_IJMatrix); 105 /* 106 Copies the data over (column indices, numerical values) to hypre matrix 107 */ 108 109 #undef __FUNCT__ 110 #define __FUNCT__ "MatHYPRE_IJMatrixCopy" 111 PetscErrorCode MatHYPRE_IJMatrixCopy(Mat A,HYPRE_IJMatrix ij) 112 { 113 PetscErrorCode ierr; 114 PetscInt i,rstart,rend,ncols; 115 const PetscScalar *values; 116 const PetscInt *cols; 117 PetscBool flg; 118 119 PetscFunctionBegin; 120 ierr = PetscObjectTypeCompare((PetscObject)A,MATMPIAIJ,&flg);CHKERRQ(ierr); 121 if (flg) { 122 ierr = MatHYPRE_IJMatrixFastCopy_MPIAIJ(A,ij);CHKERRQ(ierr); 123 PetscFunctionReturn(0); 124 } 125 ierr = PetscObjectTypeCompare((PetscObject)A,MATSEQAIJ,&flg);CHKERRQ(ierr); 126 if (flg) { 127 ierr = MatHYPRE_IJMatrixFastCopy_SeqAIJ(A,ij);CHKERRQ(ierr); 128 PetscFunctionReturn(0); 129 } 130 131 ierr = PetscLogEventBegin(MAT_Convert,A,0,0,0);CHKERRQ(ierr); 132 PetscStackCallHypre(0,HYPRE_IJMatrixInitialize,(ij)); 133 ierr = MatGetOwnershipRange(A,&rstart,&rend);CHKERRQ(ierr); 134 for (i=rstart; i<rend; i++) { 135 ierr = MatGetRow(A,i,&ncols,&cols,&values);CHKERRQ(ierr); 136 PetscStackCallHypre(0,HYPRE_IJMatrixSetValues,(ij,1,&ncols,&i,cols,values)); 137 ierr = MatRestoreRow(A,i,&ncols,&cols,&values);CHKERRQ(ierr); 138 } 139 PetscStackCallHypre(0,HYPRE_IJMatrixAssemble,(ij)); 140 ierr = PetscLogEventEnd(MAT_Convert,A,0,0,0);CHKERRQ(ierr); 141 PetscFunctionReturn(0); 142 } 143 144 /* 145 This copies the CSR format directly from the PETSc data structure to the hypre 146 data structure without calls to MatGetRow() or hypre's set values. 147 148 */ 149 #include <_hypre_IJ_mv.h> 150 #include <HYPRE_IJ_mv.h> 151 #include <../src/mat/impls/aij/mpi/mpiaij.h> 152 153 #undef __FUNCT__ 154 #define __FUNCT__ "MatHYPRE_IJMatrixFastCopy_SeqAIJ" 155 PetscErrorCode MatHYPRE_IJMatrixFastCopy_SeqAIJ(Mat A,HYPRE_IJMatrix ij) 156 { 157 PetscErrorCode ierr; 158 Mat_SeqAIJ *pdiag = (Mat_SeqAIJ*)A->data; 159 160 hypre_ParCSRMatrix *par_matrix; 161 hypre_AuxParCSRMatrix *aux_matrix; 162 hypre_CSRMatrix *hdiag; 163 164 PetscFunctionBegin; 165 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 166 PetscValidType(A,1); 167 PetscValidPointer(ij,2); 168 169 ierr = PetscLogEventBegin(MAT_Convert,A,0,0,0);CHKERRQ(ierr); 170 PetscStackCallHypre(0,HYPRE_IJMatrixInitialize,(ij)); 171 par_matrix = (hypre_ParCSRMatrix*)hypre_IJMatrixObject(ij); 172 aux_matrix = (hypre_AuxParCSRMatrix*)hypre_IJMatrixTranslator(ij); 173 hdiag = hypre_ParCSRMatrixDiag(par_matrix); 174 175 /* 176 this is the Hack part where we monkey directly with the hypre datastructures 177 */ 178 ierr = PetscMemcpy(hdiag->i,pdiag->i,(A->rmap->n + 1)*sizeof(PetscInt)); 179 ierr = PetscMemcpy(hdiag->j,pdiag->j,pdiag->nz*sizeof(PetscInt)); 180 ierr = PetscMemcpy(hdiag->data,pdiag->a,pdiag->nz*sizeof(PetscScalar)); 181 182 hypre_AuxParCSRMatrixNeedAux(aux_matrix) = 0; 183 PetscStackCallHypre(0,HYPRE_IJMatrixAssemble,(ij)); 184 ierr = PetscLogEventEnd(MAT_Convert,A,0,0,0);CHKERRQ(ierr); 185 PetscFunctionReturn(0); 186 } 187 188 #undef __FUNCT__ 189 #define __FUNCT__ "MatHYPRE_IJMatrixFastCopy_MPIAIJ" 190 PetscErrorCode MatHYPRE_IJMatrixFastCopy_MPIAIJ(Mat A,HYPRE_IJMatrix ij) 191 { 192 PetscErrorCode ierr; 193 Mat_MPIAIJ *pA = (Mat_MPIAIJ*)A->data; 194 Mat_SeqAIJ *pdiag,*poffd; 195 PetscInt i,*garray = pA->garray,*jj,cstart,*pjj; 196 197 hypre_ParCSRMatrix *par_matrix; 198 hypre_AuxParCSRMatrix *aux_matrix; 199 hypre_CSRMatrix *hdiag,*hoffd; 200 201 PetscFunctionBegin; 202 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 203 PetscValidType(A,1); 204 PetscValidPointer(ij,2); 205 pdiag = (Mat_SeqAIJ*) pA->A->data; 206 poffd = (Mat_SeqAIJ*) pA->B->data; 207 /* cstart is only valid for square MPIAIJ layed out in the usual way */ 208 ierr = MatGetOwnershipRange(A,&cstart,PETSC_NULL);CHKERRQ(ierr); 209 210 ierr = PetscLogEventBegin(MAT_Convert,A,0,0,0);CHKERRQ(ierr); 211 PetscStackCallHypre(0,HYPRE_IJMatrixInitialize,(ij)); 212 par_matrix = (hypre_ParCSRMatrix*)hypre_IJMatrixObject(ij); 213 aux_matrix = (hypre_AuxParCSRMatrix*)hypre_IJMatrixTranslator(ij); 214 hdiag = hypre_ParCSRMatrixDiag(par_matrix); 215 hoffd = hypre_ParCSRMatrixOffd(par_matrix); 216 217 /* 218 this is the Hack part where we monkey directly with the hypre datastructures 219 */ 220 ierr = PetscMemcpy(hdiag->i,pdiag->i,(pA->A->rmap->n + 1)*sizeof(PetscInt)); 221 /* need to shift the diag column indices (hdiag->j) back to global numbering since hypre is expecting this */ 222 jj = hdiag->j; 223 pjj = pdiag->j; 224 for (i=0; i<pdiag->nz; i++) { 225 jj[i] = cstart + pjj[i]; 226 } 227 ierr = PetscMemcpy(hdiag->data,pdiag->a,pdiag->nz*sizeof(PetscScalar)); 228 ierr = PetscMemcpy(hoffd->i,poffd->i,(pA->A->rmap->n + 1)*sizeof(PetscInt)); 229 /* need to move the offd column indices (hoffd->j) back to global numbering since hypre is expecting this 230 If we hacked a hypre a bit more we might be able to avoid this step */ 231 jj = hoffd->j; 232 pjj = poffd->j; 233 for (i=0; i<poffd->nz; i++) { 234 jj[i] = garray[pjj[i]]; 235 } 236 ierr = PetscMemcpy(hoffd->data,poffd->a,poffd->nz*sizeof(PetscScalar)); 237 238 hypre_AuxParCSRMatrixNeedAux(aux_matrix) = 0; 239 PetscStackCallHypre(0,HYPRE_IJMatrixAssemble,(ij)); 240 ierr = PetscLogEventEnd(MAT_Convert,A,0,0,0);CHKERRQ(ierr); 241 PetscFunctionReturn(0); 242 } 243 244 /* 245 Does NOT copy the data over, instead uses DIRECTLY the pointers from the PETSc MPIAIJ format 246 247 This is UNFINISHED and does NOT work! The problem is that hypre puts the diagonal entry first 248 which will corrupt the PETSc data structure if we did this. Need a work around to this problem. 249 */ 250 #include <_hypre_IJ_mv.h> 251 #include <HYPRE_IJ_mv.h> 252 253 #undef __FUNCT__ 254 #define __FUNCT__ "MatHYPRE_IJMatrixLink" 255 PetscErrorCode MatHYPRE_IJMatrixLink(Mat A,HYPRE_IJMatrix *ij) 256 { 257 PetscErrorCode ierr; 258 PetscInt rstart,rend,cstart,cend; 259 PetscBool flg; 260 hypre_AuxParCSRMatrix *aux_matrix; 261 262 PetscFunctionBegin; 263 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 264 PetscValidType(A,1); 265 PetscValidPointer(ij,2); 266 ierr = PetscObjectTypeCompare((PetscObject)A,MATMPIAIJ,&flg);CHKERRQ(ierr); 267 if (!flg) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_SUP,"Can only use with PETSc MPIAIJ matrices"); 268 ierr = MatSetUp(A);CHKERRQ(ierr); 269 270 ierr = PetscLogEventBegin(MAT_Convert,A,0,0,0);CHKERRQ(ierr); 271 rstart = A->rmap->rstart; 272 rend = A->rmap->rend; 273 cstart = A->cmap->rstart; 274 cend = A->cmap->rend; 275 PetscStackCallHypre(0,HYPRE_IJMatrixCreate,(((PetscObject)A)->comm,rstart,rend-1,cstart,cend-1,ij)); 276 PetscStackCallHypre(0,HYPRE_IJMatrixSetObjectType,(*ij,HYPRE_PARCSR)); 277 278 PetscStackCallHypre(0,HYPRE_IJMatrixInitialize,(*ij)); 279 aux_matrix = (hypre_AuxParCSRMatrix*)hypre_IJMatrixTranslator(*ij); 280 281 hypre_AuxParCSRMatrixNeedAux(aux_matrix) = 0; 282 283 /* this is the Hack part where we monkey directly with the hypre datastructures */ 284 285 PetscStackCallHypre(0,HYPRE_IJMatrixAssemble,(*ij)); 286 ierr = PetscLogEventEnd(MAT_Convert,A,0,0,0);CHKERRQ(ierr); 287 PetscFunctionReturn(0); 288 } 289 290 /* -----------------------------------------------------------------------------------------------------------------*/ 291 292 /*MC 293 MATHYPRESTRUCT - MATHYPRESTRUCT = "hyprestruct" - A matrix type to be used for parallel sparse matrices 294 based on the hypre HYPRE_StructMatrix. 295 296 Level: intermediate 297 298 Notes: Unlike the more general support for blocks in hypre this allows only one block per process and requires the block 299 be defined by a DMDA. 300 301 The matrix needs a DMDA associated with it by either a call to MatSetDM() or if the matrix is obtained from DMCreateMatrix() 302 303 .seealso: MatCreate(), PCPFMG, MatSetDM(), DMCreateMatrix() 304 M*/ 305 306 307 #undef __FUNCT__ 308 #define __FUNCT__ "MatSetValuesLocal_HYPREStruct_3d" 309 PetscErrorCode MatSetValuesLocal_HYPREStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscInt ncol,const PetscInt icol[],const PetscScalar y[],InsertMode addv) 310 { 311 PetscErrorCode ierr; 312 PetscInt i,j,stencil,index[3],row,entries[7]; 313 const PetscScalar *values = y; 314 Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data; 315 316 PetscFunctionBegin; 317 for (i=0; i<nrow; i++) { 318 for (j=0; j<ncol; j++) { 319 stencil = icol[j] - irow[i]; 320 if (!stencil) { 321 entries[j] = 3; 322 } else if (stencil == -1) { 323 entries[j] = 2; 324 } else if (stencil == 1) { 325 entries[j] = 4; 326 } else if (stencil == -ex->gnx) { 327 entries[j] = 1; 328 } else if (stencil == ex->gnx) { 329 entries[j] = 5; 330 } else if (stencil == -ex->gnxgny) { 331 entries[j] = 0; 332 } else if (stencil == ex->gnxgny) { 333 entries[j] = 6; 334 } else SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local row %D local column %D have bad stencil %D",irow[i],icol[j],stencil); 335 } 336 row = ex->gindices[irow[i]] - ex->rstart; 337 index[0] = ex->xs + (row % ex->nx); 338 index[1] = ex->ys + ((row/ex->nx) % ex->ny); 339 index[2] = ex->zs + (row/(ex->nxny)); 340 if (addv == ADD_VALUES) { 341 PetscStackCallHypre(0,HYPRE_StructMatrixAddToValues,(ex->hmat,index,ncol,entries,(PetscScalar*)values)); 342 } else { 343 PetscStackCallHypre(0,HYPRE_StructMatrixSetValues,(ex->hmat,index,ncol,entries,(PetscScalar*)values)); 344 } 345 values += ncol; 346 } 347 PetscFunctionReturn(0); 348 } 349 350 #undef __FUNCT__ 351 #define __FUNCT__ "MatZeroRowsLocal_HYPREStruct_3d" 352 PetscErrorCode MatZeroRowsLocal_HYPREStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscScalar d,Vec x,Vec b) 353 { 354 PetscErrorCode ierr; 355 PetscInt i,index[3],row,entries[7] = {0,1,2,3,4,5,6}; 356 PetscScalar values[7]; 357 Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data; 358 359 PetscFunctionBegin; 360 if (x && b) SETERRQ(((PetscObject)mat)->comm,PETSC_ERR_SUP,"No support"); 361 ierr = PetscMemzero(values,7*sizeof(PetscScalar));CHKERRQ(ierr); 362 values[3] = d; 363 for (i=0; i<nrow; i++) { 364 row = ex->gindices[irow[i]] - ex->rstart; 365 index[0] = ex->xs + (row % ex->nx); 366 index[1] = ex->ys + ((row/ex->nx) % ex->ny); 367 index[2] = ex->zs + (row/(ex->nxny)); 368 PetscStackCallHypre(0,HYPRE_StructMatrixSetValues,(ex->hmat,index,7,entries,values)); 369 } 370 PetscStackCallHypre(0,HYPRE_StructMatrixAssemble,(ex->hmat)); 371 PetscFunctionReturn(0); 372 } 373 374 #undef __FUNCT__ 375 #define __FUNCT__ "MatZeroEntries_HYPREStruct_3d" 376 PetscErrorCode MatZeroEntries_HYPREStruct_3d(Mat mat) 377 { 378 PetscErrorCode ierr; 379 PetscInt indices[7] = {0,1,2,3,4,5,6}; 380 Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data; 381 382 PetscFunctionBegin; 383 /* hypre has no public interface to do this */ 384 PetscStackCallHypre(0,hypre_StructMatrixClearBoxValues,(ex->hmat,&ex->hbox,7,indices,0,1)); 385 PetscStackCallHypre(0,HYPRE_StructMatrixAssemble,(ex->hmat)); 386 PetscFunctionReturn(0); 387 } 388 389 #undef __FUNCT__ 390 #define __FUNCT__ "MatSetDM_HYPREStruct" 391 PetscErrorCode MatSetDM_HYPREStruct(Mat mat,DM da) 392 { 393 PetscErrorCode ierr; 394 Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data; 395 PetscInt dim,dof,sw[3],nx,ny,nz,ilower[3],iupper[3],ssize,i; 396 DMDABoundaryType px,py,pz; 397 DMDAStencilType st; 398 399 PetscFunctionBegin; 400 ex->da = da; 401 ierr = PetscObjectReference((PetscObject)da);CHKERRQ(ierr); 402 403 ierr = DMDAGetInfo(ex->da,&dim,0,0,0,0,0,0,&dof,&sw[0],&px,&py,&pz,&st);CHKERRQ(ierr); 404 ierr = DMDAGetCorners(ex->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);CHKERRQ(ierr); 405 iupper[0] += ilower[0] - 1; 406 iupper[1] += ilower[1] - 1; 407 iupper[2] += ilower[2] - 1; 408 409 /* the hypre_Box is used to zero out the matrix entries in MatZeroValues() */ 410 ex->hbox.imin[0] = ilower[0]; 411 ex->hbox.imin[1] = ilower[1]; 412 ex->hbox.imin[2] = ilower[2]; 413 ex->hbox.imax[0] = iupper[0]; 414 ex->hbox.imax[1] = iupper[1]; 415 ex->hbox.imax[2] = iupper[2]; 416 417 /* create the hypre grid object and set its information */ 418 if (dof > 1) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_SUP,"Currently only support for scalar problems"); 419 if (px || py || pz) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_SUP,"Ask us to add periodic support by calling HYPRE_StructGridSetPeriodic()"); 420 PetscStackCallHypre(0,HYPRE_StructGridCreate,(ex->hcomm,dim,&ex->hgrid)); 421 PetscStackCallHypre(0,HYPRE_StructGridSetExtents,(ex->hgrid,ilower,iupper)); 422 PetscStackCallHypre(0,HYPRE_StructGridAssemble,(ex->hgrid)); 423 424 sw[1] = sw[0]; 425 sw[2] = sw[1]; 426 PetscStackCallHypre(0,HYPRE_StructGridSetNumGhost,(ex->hgrid,sw)); 427 428 /* create the hypre stencil object and set its information */ 429 if (sw[0] > 1) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_SUP,"Ask us to add support for wider stencils"); 430 if (st == DMDA_STENCIL_BOX) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_SUP,"Ask us to add support for box stencils"); 431 if (dim == 1) { 432 PetscInt offsets[3][1] = {{-1},{0},{1}}; 433 ssize = 3; 434 PetscStackCallHypre(0,HYPRE_StructStencilCreate,(dim,ssize,&ex->hstencil)); 435 for (i=0; i<ssize; i++) { 436 PetscStackCallHypre(0,HYPRE_StructStencilSetElement,(ex->hstencil,i,offsets[i])); 437 } 438 } else if (dim == 2) { 439 PetscInt offsets[5][2] = {{0,-1},{-1,0},{0,0},{1,0},{0,1}}; 440 ssize = 5; 441 PetscStackCallHypre(0,HYPRE_StructStencilCreate,(dim,ssize,&ex->hstencil)); 442 for (i=0; i<ssize; i++) { 443 PetscStackCallHypre(0,HYPRE_StructStencilSetElement,(ex->hstencil,i,offsets[i])); 444 } 445 } else if (dim == 3) { 446 PetscInt offsets[7][3] = {{0,0,-1},{0,-1,0},{-1,0,0},{0,0,0},{1,0,0},{0,1,0},{0,0,1}}; 447 ssize = 7; 448 PetscStackCallHypre(0,HYPRE_StructStencilCreate,(dim,ssize,&ex->hstencil)); 449 for (i=0; i<ssize; i++) { 450 PetscStackCallHypre(0,HYPRE_StructStencilSetElement,(ex->hstencil,i,offsets[i])); 451 } 452 } 453 454 /* create the HYPRE vector for rhs and solution */ 455 PetscStackCallHypre(0,HYPRE_StructVectorCreate,(ex->hcomm,ex->hgrid,&ex->hb)); 456 PetscStackCallHypre(0,HYPRE_StructVectorCreate,(ex->hcomm,ex->hgrid,&ex->hx)); 457 PetscStackCallHypre(0,HYPRE_StructVectorInitialize,(ex->hb)); 458 PetscStackCallHypre(0,HYPRE_StructVectorInitialize,(ex->hx)); 459 PetscStackCallHypre(0,HYPRE_StructVectorAssemble,(ex->hb)); 460 PetscStackCallHypre(0,HYPRE_StructVectorAssemble,(ex->hx)); 461 462 /* create the hypre matrix object and set its information */ 463 PetscStackCallHypre(0,HYPRE_StructMatrixCreate,(ex->hcomm,ex->hgrid,ex->hstencil,&ex->hmat)); 464 PetscStackCallHypre(0,HYPRE_StructGridDestroy,(ex->hgrid)); 465 PetscStackCallHypre(0,HYPRE_StructStencilDestroy,(ex->hstencil)); 466 if (ex->needsinitialization) { 467 PetscStackCallHypre(0,HYPRE_StructMatrixInitialize,(ex->hmat)); 468 ex->needsinitialization = PETSC_FALSE; 469 } 470 471 /* set the global and local sizes of the matrix */ 472 ierr = DMDAGetCorners(da,0,0,0,&nx,&ny,&nz);CHKERRQ(ierr); 473 ierr = MatSetSizes(mat,dof*nx*ny*nz,dof*nx*ny*nz,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr); 474 ierr = PetscLayoutSetBlockSize(mat->rmap,1);CHKERRQ(ierr); 475 ierr = PetscLayoutSetBlockSize(mat->cmap,1);CHKERRQ(ierr); 476 ierr = PetscLayoutSetUp(mat->rmap);CHKERRQ(ierr); 477 ierr = PetscLayoutSetUp(mat->cmap);CHKERRQ(ierr); 478 479 if (dim == 3) { 480 mat->ops->setvalueslocal = MatSetValuesLocal_HYPREStruct_3d; 481 mat->ops->zerorowslocal = MatZeroRowsLocal_HYPREStruct_3d; 482 mat->ops->zeroentries = MatZeroEntries_HYPREStruct_3d; 483 ierr = MatZeroEntries_HYPREStruct_3d(mat);CHKERRQ(ierr); 484 } else SETERRQ(((PetscObject)da)->comm,PETSC_ERR_SUP,"Only support for 3d DMDA currently"); 485 486 /* get values that will be used repeatedly in MatSetValuesLocal() and MatZeroRowsLocal() repeatedly */ 487 ierr = MatGetOwnershipRange(mat,&ex->rstart,PETSC_NULL);CHKERRQ(ierr); 488 ierr = DMDAGetGlobalIndices(ex->da,PETSC_NULL,&ex->gindices);CHKERRQ(ierr); 489 ierr = DMDAGetGhostCorners(ex->da,0,0,0,&ex->gnx,&ex->gnxgny,0);CHKERRQ(ierr); 490 ex->gnxgny *= ex->gnx; 491 ierr = DMDAGetCorners(ex->da,&ex->xs,&ex->ys,&ex->zs,&ex->nx,&ex->ny,0);CHKERRQ(ierr); 492 ex->nxny = ex->nx*ex->ny; 493 PetscFunctionReturn(0); 494 } 495 496 #undef __FUNCT__ 497 #define __FUNCT__ "MatMult_HYPREStruct" 498 PetscErrorCode MatMult_HYPREStruct(Mat A,Vec x,Vec y) 499 { 500 PetscErrorCode ierr; 501 PetscScalar *xx,*yy; 502 PetscInt ilower[3],iupper[3]; 503 Mat_HYPREStruct *mx = (Mat_HYPREStruct *)(A->data); 504 505 PetscFunctionBegin; 506 ierr = DMDAGetCorners(mx->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);CHKERRQ(ierr); 507 iupper[0] += ilower[0] - 1; 508 iupper[1] += ilower[1] - 1; 509 iupper[2] += ilower[2] - 1; 510 511 /* copy x values over to hypre */ 512 PetscStackCallHypre(0,HYPRE_StructVectorSetConstantValues,(mx->hb,0.0)); 513 ierr = VecGetArray(x,&xx);CHKERRQ(ierr); 514 PetscStackCallHypre(0,HYPRE_StructVectorSetBoxValues,(mx->hb,ilower,iupper,xx)); 515 ierr = VecRestoreArray(x,&xx);CHKERRQ(ierr); 516 PetscStackCallHypre(0,HYPRE_StructVectorAssemble,(mx->hb)); 517 PetscStackCallHypre(0,HYPRE_StructMatrixMatvec,(1.0,mx->hmat,mx->hb,0.0,mx->hx)); 518 519 /* copy solution values back to PETSc */ 520 ierr = VecGetArray(y,&yy);CHKERRQ(ierr); 521 PetscStackCallHypre(0,HYPRE_StructVectorGetBoxValues,(mx->hx,ilower,iupper,yy)); 522 ierr = VecRestoreArray(y,&yy);CHKERRQ(ierr); 523 PetscFunctionReturn(0); 524 } 525 526 #undef __FUNCT__ 527 #define __FUNCT__ "MatAssemblyEnd_HYPREStruct" 528 PetscErrorCode MatAssemblyEnd_HYPREStruct(Mat mat,MatAssemblyType mode) 529 { 530 Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data; 531 PetscErrorCode ierr; 532 533 PetscFunctionBegin; 534 PetscStackCallHypre(0,HYPRE_StructMatrixAssemble,(ex->hmat)); 535 /* PetscStackCallHypre(0,HYPRE_StructMatrixPrint,("dummy",ex->hmat,0)); */ 536 PetscFunctionReturn(0); 537 } 538 539 #undef __FUNCT__ 540 #define __FUNCT__ "MatZeroEntries_HYPREStruct" 541 PetscErrorCode MatZeroEntries_HYPREStruct(Mat mat) 542 { 543 PetscFunctionBegin; 544 /* before the DMDA is set to the matrix the zero doesn't need to do anything */ 545 PetscFunctionReturn(0); 546 } 547 548 549 #undef __FUNCT__ 550 #define __FUNCT__ "MatDestroy_HYPREStruct" 551 PetscErrorCode MatDestroy_HYPREStruct(Mat mat) 552 { 553 Mat_HYPREStruct *ex = (Mat_HYPREStruct*) mat->data; 554 PetscErrorCode ierr; 555 556 PetscFunctionBegin; 557 PetscStackCallHypre(0,HYPRE_StructMatrixDestroy,(ex->hmat)); 558 PetscStackCallHypre(0,HYPRE_StructVectorDestroy,(ex->hx)); 559 PetscStackCallHypre(0,HYPRE_StructVectorDestroy,(ex->hb)); 560 PetscFunctionReturn(0); 561 } 562 563 564 EXTERN_C_BEGIN 565 #undef __FUNCT__ 566 #define __FUNCT__ "MatCreate_HYPREStruct" 567 PetscErrorCode MatCreate_HYPREStruct(Mat B) 568 { 569 Mat_HYPREStruct *ex; 570 PetscErrorCode ierr; 571 572 PetscFunctionBegin; 573 ierr = PetscNewLog(B,Mat_HYPREStruct,&ex);CHKERRQ(ierr); 574 B->data = (void*)ex; 575 B->rmap->bs = 1; 576 B->assembled = PETSC_FALSE; 577 578 B->insertmode = NOT_SET_VALUES; 579 580 B->ops->assemblyend = MatAssemblyEnd_HYPREStruct; 581 B->ops->mult = MatMult_HYPREStruct; 582 B->ops->zeroentries = MatZeroEntries_HYPREStruct; 583 B->ops->destroy = MatDestroy_HYPREStruct; 584 585 ex->needsinitialization = PETSC_TRUE; 586 587 ierr = MPI_Comm_dup(((PetscObject)B)->comm,&(ex->hcomm));CHKERRQ(ierr); 588 ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatSetDM_C","MatSetDM_HYPREStruct",MatSetDM_HYPREStruct);CHKERRQ(ierr); 589 ierr = PetscObjectChangeTypeName((PetscObject)B,MATHYPRESTRUCT);CHKERRQ(ierr); 590 PetscFunctionReturn(0); 591 } 592 EXTERN_C_END 593 594 595 /*MC 596 MATHYPRESSTRUCT - MATHYPRESSTRUCT = "hypresstruct" - A matrix type to be used for parallel sparse matrices 597 based on the hypre HYPRE_SStructMatrix. 598 599 600 Level: intermediate 601 602 Notes: Unlike hypre's general semi-struct object consisting of a collection of structured-grid objects and unstructured 603 grid objects, we will restrict the semi-struct objects to consist of only structured-grid components. 604 605 Unlike the more general support for parts and blocks in hypre this allows only one part, and one block per process and requires the block 606 be defined by a DMDA. 607 608 The matrix needs a DMDA associated with it by either a call to MatSetDM() or if the matrix is obtained from DMCreateMatrix() 609 610 M*/ 611 612 #undef __FUNCT__ 613 #define __FUNCT__ "MatSetValuesLocal_HYPRESStruct_3d" 614 PetscErrorCode MatSetValuesLocal_HYPRESStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscInt ncol,const PetscInt icol[],const PetscScalar y[],InsertMode addv) 615 { 616 PetscErrorCode ierr; 617 PetscInt i,j,stencil,index[3]; 618 const PetscScalar *values = y; 619 Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data; 620 621 PetscInt part= 0; /* Petsc sstruct interface only allows 1 part */ 622 PetscInt ordering; 623 PetscInt grid_rank, to_grid_rank; 624 PetscInt var_type, to_var_type; 625 PetscInt to_var_entry = 0; 626 627 PetscInt nvars= ex->nvars; 628 PetscInt row,*entries; 629 630 PetscFunctionBegin; 631 ierr = PetscMalloc(7*nvars*sizeof(PetscInt),&entries);CHKERRQ(ierr); 632 ordering= ex-> dofs_order; /* ordering= 0 nodal ordering 633 1 variable ordering */ 634 /* stencil entries are orderer by variables: var0_stencil0, var0_stencil1, ..., var0_stencil6, var1_stencil0, var1_stencil1, ... */ 635 636 if (!ordering) { 637 for (i=0; i<nrow; i++) { 638 grid_rank= irow[i]/nvars; 639 var_type = (irow[i] % nvars); 640 641 for (j=0; j<ncol; j++) { 642 to_grid_rank= icol[j]/nvars; 643 to_var_type = (icol[j] % nvars); 644 645 to_var_entry= to_var_entry*7; 646 entries[j]= to_var_entry; 647 648 stencil = to_grid_rank-grid_rank; 649 if (!stencil) { 650 entries[j] += 3; 651 } else if (stencil == -1) { 652 entries[j] += 2; 653 } else if (stencil == 1) { 654 entries[j] += 4; 655 } else if (stencil == -ex->gnx) { 656 entries[j] += 1; 657 } else if (stencil == ex->gnx) { 658 entries[j] += 5; 659 } else if (stencil == -ex->gnxgny) { 660 entries[j] += 0; 661 } else if (stencil == ex->gnxgny) { 662 entries[j] += 6; 663 } else SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local row %D local column %D have bad stencil %D",irow[i],icol[j],stencil); 664 } 665 666 row = ex->gindices[grid_rank] - ex->rstart; 667 index[0] = ex->xs + (row % ex->nx); 668 index[1] = ex->ys + ((row/ex->nx) % ex->ny); 669 index[2] = ex->zs + (row/(ex->nxny)); 670 671 if (addv == ADD_VALUES) { 672 PetscStackCallHypre(0,HYPRE_SStructMatrixAddToValues,(ex->ss_mat,part,index,var_type,ncol,entries,(PetscScalar*)values)); 673 } else { 674 PetscStackCallHypre(0,HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,index,var_type,ncol,entries,(PetscScalar*)values)); 675 } 676 values += ncol; 677 } 678 } else { 679 for (i=0; i<nrow; i++) { 680 var_type = irow[i]/(ex->gnxgnygnz); 681 grid_rank= irow[i] - var_type*(ex->gnxgnygnz); 682 683 for (j=0; j<ncol; j++) { 684 to_var_type = icol[j]/(ex->gnxgnygnz); 685 to_grid_rank= icol[j] - to_var_type*(ex->gnxgnygnz); 686 687 to_var_entry= to_var_entry*7; 688 entries[j]= to_var_entry; 689 690 stencil = to_grid_rank-grid_rank; 691 if (!stencil) { 692 entries[j] += 3; 693 } else if (stencil == -1) { 694 entries[j] += 2; 695 } else if (stencil == 1) { 696 entries[j] += 4; 697 } else if (stencil == -ex->gnx) { 698 entries[j] += 1; 699 } else if (stencil == ex->gnx) { 700 entries[j] += 5; 701 } else if (stencil == -ex->gnxgny) { 702 entries[j] += 0; 703 } else if (stencil == ex->gnxgny) { 704 entries[j] += 6; 705 } else SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local row %D local column %D have bad stencil %D",irow[i],icol[j],stencil); 706 } 707 708 row = ex->gindices[grid_rank] - ex->rstart; 709 index[0] = ex->xs + (row % ex->nx); 710 index[1] = ex->ys + ((row/ex->nx) % ex->ny); 711 index[2] = ex->zs + (row/(ex->nxny)); 712 713 if (addv == ADD_VALUES) { 714 PetscStackCallHypre(0,HYPRE_SStructMatrixAddToValues,(ex->ss_mat,part,index,var_type,ncol,entries,(PetscScalar*)values)); 715 } else { 716 PetscStackCallHypre(0,HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,index,var_type,ncol,entries,(PetscScalar*)values)); 717 } 718 values += ncol; 719 } 720 } 721 ierr = PetscFree(entries);CHKERRQ(ierr); 722 PetscFunctionReturn(0); 723 } 724 725 #undef __FUNCT__ 726 #define __FUNCT__ "MatZeroRowsLocal_HYPRESStruct_3d" 727 PetscErrorCode MatZeroRowsLocal_HYPRESStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscScalar d,Vec x,Vec b) 728 { 729 PetscErrorCode ierr; 730 PetscInt i,index[3]; 731 PetscScalar **values; 732 Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data; 733 734 PetscInt part= 0; /* Petsc sstruct interface only allows 1 part */ 735 PetscInt ordering= ex->dofs_order; 736 PetscInt grid_rank; 737 PetscInt var_type; 738 PetscInt nvars= ex->nvars; 739 PetscInt row,*entries; 740 741 PetscFunctionBegin; 742 if (x && b) SETERRQ(((PetscObject)mat)->comm,PETSC_ERR_SUP,"No support"); 743 ierr = PetscMalloc(7*nvars*sizeof(PetscInt),&entries);CHKERRQ(ierr); 744 745 ierr = PetscMalloc(nvars*sizeof(PetscScalar *),&values);CHKERRQ(ierr); 746 ierr = PetscMalloc(7*nvars*nvars*sizeof(PetscScalar),&values[0]);CHKERRQ(ierr); 747 for (i=1; i<nvars; i++) { 748 values[i] = values[i-1] + nvars*7; 749 } 750 751 for (i=0; i< nvars; i++) { 752 ierr = PetscMemzero(values[i],nvars*7*sizeof(PetscScalar));CHKERRQ(ierr); 753 *(values[i]+3)= d; 754 } 755 756 for (i= 0; i< nvars*7; i++) { 757 entries[i]= i; 758 } 759 760 if (!ordering) { 761 for (i=0; i<nrow; i++) { 762 grid_rank= irow[i]/nvars; 763 var_type = (irow[i] % nvars); 764 765 row = ex->gindices[grid_rank] - ex->rstart; 766 index[0] = ex->xs + (row % ex->nx); 767 index[1] = ex->ys + ((row/ex->nx) % ex->ny); 768 index[2] = ex->zs + (row/(ex->nxny)); 769 PetscStackCallHypre(0,HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,index,var_type,7*nvars,entries,values[var_type])); 770 } 771 } else { 772 for (i=0; i<nrow; i++) { 773 var_type = irow[i]/(ex->gnxgnygnz); 774 grid_rank= irow[i] - var_type*(ex->gnxgnygnz); 775 776 row = ex->gindices[grid_rank] - ex->rstart; 777 index[0] = ex->xs + (row % ex->nx); 778 index[1] = ex->ys + ((row/ex->nx) % ex->ny); 779 index[2] = ex->zs + (row/(ex->nxny)); 780 PetscStackCallHypre(0,HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,index,var_type,7*nvars,entries,values[var_type])); 781 } 782 } 783 PetscStackCallHypre(0,HYPRE_SStructMatrixAssemble,(ex->ss_mat)); 784 ierr = PetscFree(values[0]);CHKERRQ(ierr); 785 ierr = PetscFree(values);CHKERRQ(ierr); 786 ierr = PetscFree(entries);CHKERRQ(ierr); 787 PetscFunctionReturn(0); 788 } 789 790 #undef __FUNCT__ 791 #define __FUNCT__ "MatZeroEntries_HYPRESStruct_3d" 792 PetscErrorCode MatZeroEntries_HYPRESStruct_3d(Mat mat) 793 { 794 PetscErrorCode ierr; 795 Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data; 796 PetscInt nvars= ex->nvars; 797 PetscInt size; 798 PetscInt part= 0; /* only one part */ 799 800 PetscFunctionBegin; 801 size = ((ex->hbox.imax[0])-(ex->hbox.imin[0])+1)*((ex->hbox.imax[1])-(ex->hbox.imin[1])+1)*((ex->hbox.imax[2])-(ex->hbox.imin[2])+1); 802 { 803 PetscInt i,*entries,iupper[3],ilower[3]; 804 PetscScalar *values; 805 806 807 for (i= 0; i< 3; i++) { 808 ilower[i]= ex->hbox.imin[i]; 809 iupper[i]= ex->hbox.imax[i]; 810 } 811 812 ierr = PetscMalloc2(nvars*7,PetscInt,&entries,nvars*7*size,PetscScalar,&values);CHKERRQ(ierr); 813 for (i= 0; i< nvars*7; i++) { 814 entries[i]= i; 815 } 816 ierr = PetscMemzero(values,nvars*7*size*sizeof(PetscScalar));CHKERRQ(ierr); 817 818 for (i= 0; i< nvars; i++) { 819 PetscStackCallHypre(0,HYPRE_SStructMatrixSetBoxValues,(ex->ss_mat,part,ilower,iupper,i,nvars*7,entries,values)); 820 } 821 ierr = PetscFree2(entries,values);CHKERRQ(ierr); 822 } 823 PetscStackCallHypre(0,HYPRE_SStructMatrixAssemble,(ex->ss_mat)); 824 PetscFunctionReturn(0); 825 } 826 827 828 #undef __FUNCT__ 829 #define __FUNCT__ "MatSetDM_HYPRESStruct" 830 PetscErrorCode MatSetDM_HYPRESStruct(Mat mat,DM da) 831 { 832 PetscErrorCode ierr; 833 Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data; 834 PetscInt dim,dof,sw[3],nx,ny,nz; 835 PetscInt ilower[3],iupper[3],ssize,i; 836 DMDABoundaryType px,py,pz; 837 DMDAStencilType st; 838 PetscInt nparts= 1; /* assuming only one part */ 839 PetscInt part = 0; 840 841 PetscFunctionBegin; 842 ex->da = da; 843 ierr = PetscObjectReference((PetscObject)da);CHKERRQ(ierr); 844 845 ierr = DMDAGetInfo(ex->da,&dim,0,0,0,0,0,0,&dof,&sw[0],&px,&py,&pz,&st);CHKERRQ(ierr); 846 ierr = DMDAGetCorners(ex->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);CHKERRQ(ierr); 847 iupper[0] += ilower[0] - 1; 848 iupper[1] += ilower[1] - 1; 849 iupper[2] += ilower[2] - 1; 850 /* the hypre_Box is used to zero out the matrix entries in MatZeroValues() */ 851 ex->hbox.imin[0] = ilower[0]; 852 ex->hbox.imin[1] = ilower[1]; 853 ex->hbox.imin[2] = ilower[2]; 854 ex->hbox.imax[0] = iupper[0]; 855 ex->hbox.imax[1] = iupper[1]; 856 ex->hbox.imax[2] = iupper[2]; 857 858 ex->dofs_order = 0; 859 860 /* assuming that the same number of dofs on each gridpoint. Also assume all cell-centred based */ 861 ex->nvars= dof; 862 863 /* create the hypre grid object and set its information */ 864 if (px || py || pz) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_SUP,"Ask us to add periodic support by calling HYPRE_SStructGridSetPeriodic()"); 865 PetscStackCallHypre(0,HYPRE_SStructGridCreate,(ex->hcomm,dim,nparts,&ex->ss_grid)); 866 867 PetscStackCallHypre(0,HYPRE_SStructGridSetExtents,(ex->ss_grid,part,ex->hbox.imin,ex->hbox.imax)); 868 869 { 870 HYPRE_SStructVariable *vartypes; 871 ierr = PetscMalloc(ex->nvars*sizeof(HYPRE_SStructVariable),&vartypes);CHKERRQ(ierr); 872 for (i= 0; i< ex->nvars; i++) { 873 vartypes[i]= HYPRE_SSTRUCT_VARIABLE_CELL; 874 } 875 PetscStackCallHypre(0,HYPRE_SStructGridSetVariables,(ex->ss_grid, part, ex->nvars,vartypes)); 876 ierr = PetscFree(vartypes);CHKERRQ(ierr); 877 } 878 PetscStackCallHypre(0,HYPRE_SStructGridAssemble,(ex->ss_grid)); 879 880 sw[1] = sw[0]; 881 sw[2] = sw[1]; 882 /* PetscStackCallHypre(0,HYPRE_SStructGridSetNumGhost,(ex->ss_grid,sw)); */ 883 884 /* create the hypre stencil object and set its information */ 885 if (sw[0] > 1) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_SUP,"Ask us to add support for wider stencils"); 886 if (st == DMDA_STENCIL_BOX) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_SUP,"Ask us to add support for box stencils"); 887 888 if (dim == 1) { 889 PetscInt offsets[3][1] = {{-1},{0},{1}}; 890 PetscInt j, cnt; 891 892 ssize = 3*(ex->nvars); 893 PetscStackCallHypre(0,HYPRE_SStructStencilCreate,(dim,ssize,&ex->ss_stencil)); 894 cnt= 0; 895 for (i= 0; i< (ex->nvars); i++) { 896 for (j= 0; j< 3; j++) { 897 PetscStackCallHypre(0,HYPRE_SStructStencilSetEntry,(ex->ss_stencil, cnt, offsets[j], i)); 898 cnt++; 899 } 900 } 901 } else if (dim == 2) { 902 PetscInt offsets[5][2] = {{0,-1},{-1,0},{0,0},{1,0},{0,1}}; 903 PetscInt j, cnt; 904 905 ssize = 5*(ex->nvars); 906 PetscStackCallHypre(0,HYPRE_SStructStencilCreate,(dim,ssize,&ex->ss_stencil)); 907 cnt= 0; 908 for (i= 0; i< (ex->nvars); i++) { 909 for (j= 0; j< 5; j++) { 910 PetscStackCallHypre(0,HYPRE_SStructStencilSetEntry,(ex->ss_stencil, cnt, offsets[j], i)); 911 cnt++; 912 } 913 } 914 } else if (dim == 3) { 915 PetscInt offsets[7][3] = {{0,0,-1},{0,-1,0},{-1,0,0},{0,0,0},{1,0,0},{0,1,0},{0,0,1}}; 916 PetscInt j, cnt; 917 918 ssize = 7*(ex->nvars); 919 PetscStackCallHypre(0,HYPRE_SStructStencilCreate,(dim,ssize,&ex->ss_stencil)); 920 cnt= 0; 921 for (i= 0; i< (ex->nvars); i++) { 922 for (j= 0; j< 7; j++) { 923 PetscStackCallHypre(0,HYPRE_SStructStencilSetEntry,(ex->ss_stencil, cnt, offsets[j], i)); 924 cnt++; 925 } 926 } 927 } 928 929 /* create the HYPRE graph */ 930 PetscStackCallHypre(0,HYPRE_SStructGraphCreate,(ex->hcomm, ex->ss_grid, &(ex->ss_graph))); 931 932 /* set the stencil graph. Note that each variable has the same graph. This means that each 933 variable couples to all the other variable and with the same stencil pattern. */ 934 for (i= 0; i< (ex->nvars); i++) { 935 PetscStackCallHypre(0,HYPRE_SStructGraphSetStencil,(ex->ss_graph,part,i,ex->ss_stencil)); 936 } 937 PetscStackCallHypre(0,HYPRE_SStructGraphAssemble,(ex->ss_graph)); 938 939 /* create the HYPRE sstruct vectors for rhs and solution */ 940 PetscStackCallHypre(0,HYPRE_SStructVectorCreate,(ex->hcomm,ex->ss_grid,&ex->ss_b)); 941 PetscStackCallHypre(0,HYPRE_SStructVectorCreate,(ex->hcomm,ex->ss_grid,&ex->ss_x)); 942 PetscStackCallHypre(0,HYPRE_SStructVectorInitialize,(ex->ss_b)); 943 PetscStackCallHypre(0,HYPRE_SStructVectorInitialize,(ex->ss_x)); 944 PetscStackCallHypre(0,HYPRE_SStructVectorAssemble,(ex->ss_b)); 945 PetscStackCallHypre(0,HYPRE_SStructVectorAssemble,(ex->ss_x)); 946 947 /* create the hypre matrix object and set its information */ 948 PetscStackCallHypre(0,HYPRE_SStructMatrixCreate,(ex->hcomm,ex->ss_graph,&ex->ss_mat)); 949 PetscStackCallHypre(0,HYPRE_SStructGridDestroy,(ex->ss_grid)); 950 PetscStackCallHypre(0,HYPRE_SStructStencilDestroy,(ex->ss_stencil)); 951 if (ex->needsinitialization) { 952 PetscStackCallHypre(0,HYPRE_SStructMatrixInitialize,(ex->ss_mat)); 953 ex->needsinitialization = PETSC_FALSE; 954 } 955 956 /* set the global and local sizes of the matrix */ 957 ierr = DMDAGetCorners(da,0,0,0,&nx,&ny,&nz);CHKERRQ(ierr); 958 ierr = MatSetSizes(mat,dof*nx*ny*nz,dof*nx*ny*nz,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr); 959 ierr = PetscLayoutSetBlockSize(mat->rmap,1);CHKERRQ(ierr); 960 ierr = PetscLayoutSetBlockSize(mat->cmap,1);CHKERRQ(ierr); 961 ierr = PetscLayoutSetUp(mat->rmap);CHKERRQ(ierr); 962 ierr = PetscLayoutSetUp(mat->cmap);CHKERRQ(ierr); 963 964 if (dim == 3) { 965 mat->ops->setvalueslocal = MatSetValuesLocal_HYPRESStruct_3d; 966 mat->ops->zerorowslocal = MatZeroRowsLocal_HYPRESStruct_3d; 967 mat->ops->zeroentries = MatZeroEntries_HYPRESStruct_3d; 968 ierr = MatZeroEntries_HYPRESStruct_3d(mat);CHKERRQ(ierr); 969 } else SETERRQ(((PetscObject)da)->comm,PETSC_ERR_SUP,"Only support for 3d DMDA currently"); 970 971 /* get values that will be used repeatedly in MatSetValuesLocal() and MatZeroRowsLocal() repeatedly */ 972 ierr = MatGetOwnershipRange(mat,&ex->rstart,PETSC_NULL);CHKERRQ(ierr); 973 ierr = DMDAGetGlobalIndices(ex->da,PETSC_NULL,&ex->gindices);CHKERRQ(ierr); 974 ierr = DMDAGetGhostCorners(ex->da,0,0,0,&ex->gnx,&ex->gnxgny,&ex->gnxgnygnz);CHKERRQ(ierr); 975 ex->gnxgny *= ex->gnx; 976 ex->gnxgnygnz *= ex->gnxgny; 977 ierr = DMDAGetCorners(ex->da,&ex->xs,&ex->ys,&ex->zs,&ex->nx,&ex->ny,&ex->nz);CHKERRQ(ierr); 978 ex->nxny = ex->nx*ex->ny; 979 ex->nxnynz = ex->nz*ex->nxny; 980 PetscFunctionReturn(0); 981 } 982 983 #undef __FUNCT__ 984 #define __FUNCT__ "MatMult_HYPRESStruct" 985 PetscErrorCode MatMult_HYPRESStruct(Mat A,Vec x,Vec y) 986 { 987 PetscErrorCode ierr; 988 PetscScalar *xx,*yy; 989 PetscInt ilower[3],iupper[3]; 990 Mat_HYPRESStruct *mx = (Mat_HYPRESStruct *)(A->data); 991 PetscInt ordering= mx->dofs_order; 992 PetscInt nvars= mx->nvars; 993 PetscInt part= 0; 994 PetscInt size; 995 PetscInt i; 996 997 PetscFunctionBegin; 998 ierr = DMDAGetCorners(mx->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);CHKERRQ(ierr); 999 iupper[0] += ilower[0] - 1; 1000 iupper[1] += ilower[1] - 1; 1001 iupper[2] += ilower[2] - 1; 1002 1003 size= 1; 1004 for (i= 0; i< 3; i++) { 1005 size*= (iupper[i]-ilower[i]+1); 1006 } 1007 1008 /* copy x values over to hypre for variable ordering */ 1009 if (ordering) { 1010 PetscStackCallHypre(0,HYPRE_SStructVectorSetConstantValues,(mx->ss_b,0.0)); 1011 ierr = VecGetArray(x,&xx);CHKERRQ(ierr); 1012 for (i= 0; i< nvars; i++) { 1013 PetscStackCallHypre(0,HYPRE_SStructVectorSetBoxValues,(mx->ss_b,part,ilower,iupper,i,xx+(size*i))); 1014 } 1015 ierr = VecRestoreArray(x,&xx);CHKERRQ(ierr); 1016 PetscStackCallHypre(0,HYPRE_SStructVectorAssemble,(mx->ss_b)); 1017 PetscStackCallHypre(0,HYPRE_SStructMatrixMatvec,(1.0,mx->ss_mat,mx->ss_b,0.0,mx->ss_x)); 1018 1019 /* copy solution values back to PETSc */ 1020 ierr = VecGetArray(y,&yy);CHKERRQ(ierr); 1021 for (i= 0; i< nvars; i++) { 1022 PetscStackCallHypre(0,HYPRE_SStructVectorGetBoxValues,(mx->ss_x,part,ilower,iupper,i,yy+(size*i))); 1023 } 1024 ierr = VecRestoreArray(y,&yy);CHKERRQ(ierr); 1025 } else { /* nodal ordering must be mapped to variable ordering for sys_pfmg */ 1026 PetscScalar *z; 1027 PetscInt j, k; 1028 1029 ierr = PetscMalloc(nvars*size*sizeof(PetscScalar),&z);CHKERRQ(ierr); 1030 PetscStackCallHypre(0,HYPRE_SStructVectorSetConstantValues,(mx->ss_b,0.0)); 1031 ierr = VecGetArray(x,&xx);CHKERRQ(ierr); 1032 1033 /* transform nodal to hypre's variable ordering for sys_pfmg */ 1034 for (i= 0; i< size; i++) { 1035 k= i*nvars; 1036 for (j= 0; j< nvars; j++) { 1037 z[j*size+i]= xx[k+j]; 1038 } 1039 } 1040 for (i= 0; i< nvars; i++) { 1041 PetscStackCallHypre(0,HYPRE_SStructVectorSetBoxValues,(mx->ss_b,part,ilower,iupper,i,z+(size*i))); 1042 } 1043 ierr = VecRestoreArray(x,&xx);CHKERRQ(ierr); 1044 PetscStackCallHypre(0,HYPRE_SStructVectorAssemble,(mx->ss_b)); 1045 PetscStackCallHypre(0,HYPRE_SStructMatrixMatvec,(1.0,mx->ss_mat,mx->ss_b,0.0,mx->ss_x)); 1046 1047 /* copy solution values back to PETSc */ 1048 ierr = VecGetArray(y,&yy);CHKERRQ(ierr); 1049 for (i= 0; i< nvars; i++) { 1050 PetscStackCallHypre(0,HYPRE_SStructVectorGetBoxValues,(mx->ss_x,part,ilower,iupper,i,z+(size*i))); 1051 } 1052 /* transform hypre's variable ordering for sys_pfmg to nodal ordering */ 1053 for (i= 0; i< size; i++) { 1054 k= i*nvars; 1055 for (j= 0; j< nvars; j++) { 1056 yy[k+j]= z[j*size+i]; 1057 } 1058 } 1059 ierr = VecRestoreArray(y,&yy);CHKERRQ(ierr); 1060 ierr = PetscFree(z);CHKERRQ(ierr); 1061 } 1062 PetscFunctionReturn(0); 1063 } 1064 1065 #undef __FUNCT__ 1066 #define __FUNCT__ "MatAssemblyEnd_HYPRESStruct" 1067 PetscErrorCode MatAssemblyEnd_HYPRESStruct(Mat mat,MatAssemblyType mode) 1068 { 1069 Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data; 1070 PetscErrorCode ierr; 1071 1072 PetscFunctionBegin; 1073 PetscStackCallHypre(0,HYPRE_SStructMatrixAssemble,(ex->ss_mat)); 1074 PetscFunctionReturn(0); 1075 } 1076 1077 #undef __FUNCT__ 1078 #define __FUNCT__ "MatZeroEntries_HYPRESStruct" 1079 PetscErrorCode MatZeroEntries_HYPRESStruct(Mat mat) 1080 { 1081 PetscFunctionBegin; 1082 /* before the DMDA is set to the matrix the zero doesn't need to do anything */ 1083 PetscFunctionReturn(0); 1084 } 1085 1086 1087 #undef __FUNCT__ 1088 #define __FUNCT__ "MatDestroy_HYPRESStruct" 1089 PetscErrorCode MatDestroy_HYPRESStruct(Mat mat) 1090 { 1091 Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data; 1092 PetscErrorCode ierr; 1093 1094 PetscFunctionBegin; 1095 PetscStackCallHypre(0,HYPRE_SStructGraphDestroy,(ex->ss_graph)); 1096 PetscStackCallHypre(0,HYPRE_SStructMatrixDestroy,(ex->ss_mat)); 1097 PetscStackCallHypre(0,HYPRE_SStructVectorDestroy,(ex->ss_x)); 1098 PetscStackCallHypre(0,HYPRE_SStructVectorDestroy,(ex->ss_b)); 1099 PetscFunctionReturn(0); 1100 } 1101 1102 EXTERN_C_BEGIN 1103 #undef __FUNCT__ 1104 #define __FUNCT__ "MatCreate_HYPRESStruct" 1105 PetscErrorCode MatCreate_HYPRESStruct(Mat B) 1106 { 1107 Mat_HYPRESStruct *ex; 1108 PetscErrorCode ierr; 1109 1110 PetscFunctionBegin; 1111 ierr = PetscNewLog(B,Mat_HYPRESStruct,&ex);CHKERRQ(ierr); 1112 B->data = (void*)ex; 1113 B->rmap->bs = 1; 1114 B->assembled = PETSC_FALSE; 1115 1116 B->insertmode = NOT_SET_VALUES; 1117 1118 B->ops->assemblyend = MatAssemblyEnd_HYPRESStruct; 1119 B->ops->mult = MatMult_HYPRESStruct; 1120 B->ops->zeroentries = MatZeroEntries_HYPRESStruct; 1121 B->ops->destroy = MatDestroy_HYPRESStruct; 1122 1123 ex->needsinitialization = PETSC_TRUE; 1124 1125 ierr = MPI_Comm_dup(((PetscObject)B)->comm,&(ex->hcomm));CHKERRQ(ierr); 1126 ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatSetDM_C","MatSetDM_HYPRESStruct",MatSetDM_HYPRESStruct);CHKERRQ(ierr); 1127 ierr = PetscObjectChangeTypeName((PetscObject)B,MATHYPRESSTRUCT);CHKERRQ(ierr); 1128 PetscFunctionReturn(0); 1129 } 1130 EXTERN_C_END 1131 1132 1133 1134