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