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=NULL,*nnz_o=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,NULL,&done_d);CHKERRQ(ierr); 23 if (done_d) { 24 ierr = PetscMalloc1(n_d,&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,NULL,&ia_d,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,NULL,&done_o);CHKERRQ(ierr); 33 if (done_o) { 34 ierr = PetscMalloc1(n_o,&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,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 = PetscMalloc1(n_d,&nnz_o);CHKERRQ(ierr); 44 for (i=0; i<n_d; i++) { 45 nnz_o[i] = 0; 46 } 47 } 48 PetscStackCallStandard(HYPRE_IJMatrixSetDiagOffdSizes,(ij,(HYPRE_Int *)nnz_d,(HYPRE_Int *)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,(PetscObjectComm((PetscObject)A),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,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,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,(HYPRE_Int *)&ncols,(HYPRE_Int *)&i,(HYPRE_Int *)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,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 = (PetscInt*)hdiag->j; 223 pjj = (PetscInt*)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 = (PetscInt*) hoffd->j; 230 pjj = (PetscInt*) 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(PetscObjectComm((PetscObject)A),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,(PetscObjectComm((PetscObject)A),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,(HYPRE_Int *)index,ncol,(HYPRE_Int *)entries,(PetscScalar*)values)); 338 } else { 339 PetscStackCallStandard(HYPRE_StructMatrixSetValues,(ex->hmat,(HYPRE_Int *)index,ncol,(HYPRE_Int *)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(PetscObjectComm((PetscObject)mat),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,(HYPRE_Int *)index,7,(HYPRE_Int *)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,(HYPRE_Int *)indices,0,1)); 381 PetscStackCallStandard(HYPRE_StructMatrixAssemble,(ex->hmat)); 382 PetscFunctionReturn(0); 383 } 384 385 #undef __FUNCT__ 386 #define __FUNCT__ "MatSetupDM_HYPREStruct" 387 static 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 DMBoundaryType px,py,pz; 393 DMDAStencilType st; 394 ISLocalToGlobalMapping ltog; 395 396 PetscFunctionBegin; 397 ex->da = da; 398 ierr = PetscObjectReference((PetscObject)da);CHKERRQ(ierr); 399 400 ierr = DMDAGetInfo(ex->da,&dim,0,0,0,0,0,0,&dof,&sw[0],&px,&py,&pz,&st);CHKERRQ(ierr); 401 ierr = DMDAGetCorners(ex->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);CHKERRQ(ierr); 402 iupper[0] += ilower[0] - 1; 403 iupper[1] += ilower[1] - 1; 404 iupper[2] += ilower[2] - 1; 405 406 /* the hypre_Box is used to zero out the matrix entries in MatZeroValues() */ 407 ex->hbox.imin[0] = ilower[0]; 408 ex->hbox.imin[1] = ilower[1]; 409 ex->hbox.imin[2] = ilower[2]; 410 ex->hbox.imax[0] = iupper[0]; 411 ex->hbox.imax[1] = iupper[1]; 412 ex->hbox.imax[2] = iupper[2]; 413 414 /* create the hypre grid object and set its information */ 415 if (dof > 1) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Currently only support for scalar problems"); 416 if (px || py || pz) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add periodic support by calling HYPRE_StructGridSetPeriodic()"); 417 PetscStackCallStandard(HYPRE_StructGridCreate,(ex->hcomm,dim,&ex->hgrid)); 418 PetscStackCallStandard(HYPRE_StructGridSetExtents,(ex->hgrid,(HYPRE_Int *)ilower,(HYPRE_Int *)iupper)); 419 PetscStackCallStandard(HYPRE_StructGridAssemble,(ex->hgrid)); 420 421 sw[1] = sw[0]; 422 sw[2] = sw[1]; 423 PetscStackCallStandard(HYPRE_StructGridSetNumGhost,(ex->hgrid,(HYPRE_Int *)sw)); 424 425 /* create the hypre stencil object and set its information */ 426 if (sw[0] > 1) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add support for wider stencils"); 427 if (st == DMDA_STENCIL_BOX) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add support for box stencils"); 428 if (dim == 1) { 429 PetscInt offsets[3][1] = {{-1},{0},{1}}; 430 ssize = 3; 431 PetscStackCallStandard(HYPRE_StructStencilCreate,(dim,ssize,&ex->hstencil)); 432 for (i=0; i<ssize; i++) { 433 PetscStackCallStandard(HYPRE_StructStencilSetElement,(ex->hstencil,i,(HYPRE_Int *)offsets[i])); 434 } 435 } else if (dim == 2) { 436 PetscInt offsets[5][2] = {{0,-1},{-1,0},{0,0},{1,0},{0,1}}; 437 ssize = 5; 438 PetscStackCallStandard(HYPRE_StructStencilCreate,(dim,ssize,&ex->hstencil)); 439 for (i=0; i<ssize; i++) { 440 PetscStackCallStandard(HYPRE_StructStencilSetElement,(ex->hstencil,i,(HYPRE_Int *)offsets[i])); 441 } 442 } else if (dim == 3) { 443 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}}; 444 ssize = 7; 445 PetscStackCallStandard(HYPRE_StructStencilCreate,(dim,ssize,&ex->hstencil)); 446 for (i=0; i<ssize; i++) { 447 PetscStackCallStandard(HYPRE_StructStencilSetElement,(ex->hstencil,i,(HYPRE_Int *)offsets[i])); 448 } 449 } 450 451 /* create the HYPRE vector for rhs and solution */ 452 PetscStackCallStandard(HYPRE_StructVectorCreate,(ex->hcomm,ex->hgrid,&ex->hb)); 453 PetscStackCallStandard(HYPRE_StructVectorCreate,(ex->hcomm,ex->hgrid,&ex->hx)); 454 PetscStackCallStandard(HYPRE_StructVectorInitialize,(ex->hb)); 455 PetscStackCallStandard(HYPRE_StructVectorInitialize,(ex->hx)); 456 PetscStackCallStandard(HYPRE_StructVectorAssemble,(ex->hb)); 457 PetscStackCallStandard(HYPRE_StructVectorAssemble,(ex->hx)); 458 459 /* create the hypre matrix object and set its information */ 460 PetscStackCallStandard(HYPRE_StructMatrixCreate,(ex->hcomm,ex->hgrid,ex->hstencil,&ex->hmat)); 461 PetscStackCallStandard(HYPRE_StructGridDestroy,(ex->hgrid)); 462 PetscStackCallStandard(HYPRE_StructStencilDestroy,(ex->hstencil)); 463 if (ex->needsinitialization) { 464 PetscStackCallStandard(HYPRE_StructMatrixInitialize,(ex->hmat)); 465 ex->needsinitialization = PETSC_FALSE; 466 } 467 468 /* set the global and local sizes of the matrix */ 469 ierr = DMDAGetCorners(da,0,0,0,&nx,&ny,&nz);CHKERRQ(ierr); 470 ierr = MatSetSizes(mat,dof*nx*ny*nz,dof*nx*ny*nz,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr); 471 ierr = PetscLayoutSetBlockSize(mat->rmap,1);CHKERRQ(ierr); 472 ierr = PetscLayoutSetBlockSize(mat->cmap,1);CHKERRQ(ierr); 473 ierr = PetscLayoutSetUp(mat->rmap);CHKERRQ(ierr); 474 ierr = PetscLayoutSetUp(mat->cmap);CHKERRQ(ierr); 475 476 if (dim == 3) { 477 mat->ops->setvalueslocal = MatSetValuesLocal_HYPREStruct_3d; 478 mat->ops->zerorowslocal = MatZeroRowsLocal_HYPREStruct_3d; 479 mat->ops->zeroentries = MatZeroEntries_HYPREStruct_3d; 480 481 ierr = MatZeroEntries_HYPREStruct_3d(mat);CHKERRQ(ierr); 482 } else SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Only support for 3d DMDA currently"); 483 484 /* get values that will be used repeatedly in MatSetValuesLocal() and MatZeroRowsLocal() repeatedly */ 485 ierr = MatGetOwnershipRange(mat,&ex->rstart,NULL);CHKERRQ(ierr); 486 ierr = DMGetLocalToGlobalMapping(ex->da,<og);CHKERRQ(ierr); 487 ierr = ISLocalToGlobalMappingGetIndices(ltog, (const PetscInt **) &ex->gindices);CHKERRQ(ierr); 488 ierr = DMDAGetGhostCorners(ex->da,0,0,0,&ex->gnx,&ex->gnxgny,0);CHKERRQ(ierr); 489 ex->gnxgny *= ex->gnx; 490 ierr = DMDAGetCorners(ex->da,&ex->xs,&ex->ys,&ex->zs,&ex->nx,&ex->ny,0);CHKERRQ(ierr); 491 ex->nxny = ex->nx*ex->ny; 492 PetscFunctionReturn(0); 493 } 494 495 #undef __FUNCT__ 496 #define __FUNCT__ "MatMult_HYPREStruct" 497 PetscErrorCode MatMult_HYPREStruct(Mat A,Vec x,Vec y) 498 { 499 PetscErrorCode ierr; 500 PetscScalar *xx,*yy; 501 PetscInt ilower[3],iupper[3]; 502 Mat_HYPREStruct *mx = (Mat_HYPREStruct*)(A->data); 503 504 PetscFunctionBegin; 505 ierr = DMDAGetCorners(mx->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);CHKERRQ(ierr); 506 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 PetscStackCallStandard(HYPRE_StructVectorSetConstantValues,(mx->hb,0.0)); 513 ierr = VecGetArray(x,&xx);CHKERRQ(ierr); 514 PetscStackCallStandard(HYPRE_StructVectorSetBoxValues,(mx->hb,(HYPRE_Int *)ilower,(HYPRE_Int *)iupper,xx)); 515 ierr = VecRestoreArray(x,&xx);CHKERRQ(ierr); 516 PetscStackCallStandard(HYPRE_StructVectorAssemble,(mx->hb)); 517 PetscStackCallStandard(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 PetscStackCallStandard(HYPRE_StructVectorGetBoxValues,(mx->hx,(HYPRE_Int *)ilower,(HYPRE_Int *)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 PetscStackCallStandard(HYPRE_StructMatrixAssemble,(ex->hmat)); 535 /* PetscStackCallStandard(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 PetscStackCallStandard(HYPRE_StructMatrixDestroy,(ex->hmat)); 558 PetscStackCallStandard(HYPRE_StructVectorDestroy,(ex->hx)); 559 PetscStackCallStandard(HYPRE_StructVectorDestroy,(ex->hb)); 560 PetscFunctionReturn(0); 561 } 562 563 564 #undef __FUNCT__ 565 #define __FUNCT__ "MatCreate_HYPREStruct" 566 PETSC_EXTERN PetscErrorCode MatCreate_HYPREStruct(Mat B) 567 { 568 Mat_HYPREStruct *ex; 569 PetscErrorCode ierr; 570 571 PetscFunctionBegin; 572 ierr = PetscNewLog(B,&ex);CHKERRQ(ierr); 573 B->data = (void*)ex; 574 B->rmap->bs = 1; 575 B->assembled = PETSC_FALSE; 576 577 B->insertmode = NOT_SET_VALUES; 578 579 B->ops->assemblyend = MatAssemblyEnd_HYPREStruct; 580 B->ops->mult = MatMult_HYPREStruct; 581 B->ops->zeroentries = MatZeroEntries_HYPREStruct; 582 B->ops->destroy = MatDestroy_HYPREStruct; 583 584 ex->needsinitialization = PETSC_TRUE; 585 586 ierr = MPI_Comm_dup(PetscObjectComm((PetscObject)B),&(ex->hcomm));CHKERRQ(ierr); 587 ierr = PetscObjectComposeFunction((PetscObject)B,"MatSetupDM_C",MatSetupDM_HYPREStruct);CHKERRQ(ierr); 588 ierr = PetscObjectChangeTypeName((PetscObject)B,MATHYPRESTRUCT);CHKERRQ(ierr); 589 PetscFunctionReturn(0); 590 } 591 592 /*MC 593 MATHYPRESSTRUCT - MATHYPRESSTRUCT = "hypresstruct" - A matrix type to be used for parallel sparse matrices 594 based on the hypre HYPRE_SStructMatrix. 595 596 597 Level: intermediate 598 599 Notes: Unlike hypre's general semi-struct object consisting of a collection of structured-grid objects and unstructured 600 grid objects, we will restrict the semi-struct objects to consist of only structured-grid components. 601 602 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 603 be defined by a DMDA. 604 605 The matrix needs a DMDA associated with it by either a call to MatSetupDM() or if the matrix is obtained from DMCreateMatrix() 606 607 M*/ 608 609 #undef __FUNCT__ 610 #define __FUNCT__ "MatSetValuesLocal_HYPRESStruct_3d" 611 PetscErrorCode MatSetValuesLocal_HYPRESStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscInt ncol,const PetscInt icol[],const PetscScalar y[],InsertMode addv) 612 { 613 PetscErrorCode ierr; 614 PetscInt i,j,stencil,index[3]; 615 const PetscScalar *values = y; 616 Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data; 617 618 PetscInt part = 0; /* Petsc sstruct interface only allows 1 part */ 619 PetscInt ordering; 620 PetscInt grid_rank, to_grid_rank; 621 PetscInt var_type, to_var_type; 622 PetscInt to_var_entry = 0; 623 624 PetscInt nvars= ex->nvars; 625 PetscInt row,*entries; 626 627 PetscFunctionBegin; 628 ierr = PetscMalloc1(7*nvars,&entries);CHKERRQ(ierr); 629 ordering= ex->dofs_order; /* ordering= 0 nodal ordering 630 1 variable ordering */ 631 /* stencil entries are orderer by variables: var0_stencil0, var0_stencil1, ..., var0_stencil6, var1_stencil0, var1_stencil1, ... */ 632 633 if (!ordering) { 634 for (i=0; i<nrow; i++) { 635 grid_rank= irow[i]/nvars; 636 var_type = (irow[i] % nvars); 637 638 for (j=0; j<ncol; j++) { 639 to_grid_rank= icol[j]/nvars; 640 to_var_type = (icol[j] % nvars); 641 642 to_var_entry= to_var_entry*7; 643 entries[j] = to_var_entry; 644 645 stencil = to_grid_rank-grid_rank; 646 if (!stencil) { 647 entries[j] += 3; 648 } else if (stencil == -1) { 649 entries[j] += 2; 650 } else if (stencil == 1) { 651 entries[j] += 4; 652 } else if (stencil == -ex->gnx) { 653 entries[j] += 1; 654 } else if (stencil == ex->gnx) { 655 entries[j] += 5; 656 } else if (stencil == -ex->gnxgny) { 657 entries[j] += 0; 658 } else if (stencil == ex->gnxgny) { 659 entries[j] += 6; 660 } else SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local row %D local column %D have bad stencil %D",irow[i],icol[j],stencil); 661 } 662 663 row = ex->gindices[grid_rank] - ex->rstart; 664 index[0] = ex->xs + (row % ex->nx); 665 index[1] = ex->ys + ((row/ex->nx) % ex->ny); 666 index[2] = ex->zs + (row/(ex->nxny)); 667 668 if (addv == ADD_VALUES) { 669 PetscStackCallStandard(HYPRE_SStructMatrixAddToValues,(ex->ss_mat,part,(HYPRE_Int *)index,var_type,ncol,(HYPRE_Int *)entries,(PetscScalar*)values)); 670 } else { 671 PetscStackCallStandard(HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,(HYPRE_Int *)index,var_type,ncol,(HYPRE_Int *)entries,(PetscScalar*)values)); 672 } 673 values += ncol; 674 } 675 } else { 676 for (i=0; i<nrow; i++) { 677 var_type = irow[i]/(ex->gnxgnygnz); 678 grid_rank= irow[i] - var_type*(ex->gnxgnygnz); 679 680 for (j=0; j<ncol; j++) { 681 to_var_type = icol[j]/(ex->gnxgnygnz); 682 to_grid_rank= icol[j] - to_var_type*(ex->gnxgnygnz); 683 684 to_var_entry= to_var_entry*7; 685 entries[j] = to_var_entry; 686 687 stencil = to_grid_rank-grid_rank; 688 if (!stencil) { 689 entries[j] += 3; 690 } else if (stencil == -1) { 691 entries[j] += 2; 692 } else if (stencil == 1) { 693 entries[j] += 4; 694 } else if (stencil == -ex->gnx) { 695 entries[j] += 1; 696 } else if (stencil == ex->gnx) { 697 entries[j] += 5; 698 } else if (stencil == -ex->gnxgny) { 699 entries[j] += 0; 700 } else if (stencil == ex->gnxgny) { 701 entries[j] += 6; 702 } else SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local row %D local column %D have bad stencil %D",irow[i],icol[j],stencil); 703 } 704 705 row = ex->gindices[grid_rank] - ex->rstart; 706 index[0] = ex->xs + (row % ex->nx); 707 index[1] = ex->ys + ((row/ex->nx) % ex->ny); 708 index[2] = ex->zs + (row/(ex->nxny)); 709 710 if (addv == ADD_VALUES) { 711 PetscStackCallStandard(HYPRE_SStructMatrixAddToValues,(ex->ss_mat,part,(HYPRE_Int *)index,var_type,ncol,(HYPRE_Int *)entries,(PetscScalar*)values)); 712 } else { 713 PetscStackCallStandard(HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,(HYPRE_Int *)index,var_type,ncol,(HYPRE_Int *)entries,(PetscScalar*)values)); 714 } 715 values += ncol; 716 } 717 } 718 ierr = PetscFree(entries);CHKERRQ(ierr); 719 PetscFunctionReturn(0); 720 } 721 722 #undef __FUNCT__ 723 #define __FUNCT__ "MatZeroRowsLocal_HYPRESStruct_3d" 724 PetscErrorCode MatZeroRowsLocal_HYPRESStruct_3d(Mat mat,PetscInt nrow,const PetscInt irow[],PetscScalar d,Vec x,Vec b) 725 { 726 PetscErrorCode ierr; 727 PetscInt i,index[3]; 728 PetscScalar **values; 729 Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data; 730 731 PetscInt part = 0; /* Petsc sstruct interface only allows 1 part */ 732 PetscInt ordering = ex->dofs_order; 733 PetscInt grid_rank; 734 PetscInt var_type; 735 PetscInt nvars= ex->nvars; 736 PetscInt row,*entries; 737 738 PetscFunctionBegin; 739 if (x && b) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"No support"); 740 ierr = PetscMalloc1(7*nvars,&entries);CHKERRQ(ierr); 741 742 ierr = PetscMalloc1(nvars,&values);CHKERRQ(ierr); 743 ierr = PetscMalloc1(7*nvars*nvars,&values[0]);CHKERRQ(ierr); 744 for (i=1; i<nvars; i++) { 745 values[i] = values[i-1] + nvars*7; 746 } 747 748 for (i=0; i< nvars; i++) { 749 ierr = PetscMemzero(values[i],nvars*7*sizeof(PetscScalar));CHKERRQ(ierr); 750 *(values[i]+3) = d; 751 } 752 753 for (i= 0; i< nvars*7; i++) entries[i] = i; 754 755 if (!ordering) { 756 for (i=0; i<nrow; i++) { 757 grid_rank = irow[i] / nvars; 758 var_type =(irow[i] % nvars); 759 760 row = ex->gindices[grid_rank] - ex->rstart; 761 index[0] = ex->xs + (row % ex->nx); 762 index[1] = ex->ys + ((row/ex->nx) % ex->ny); 763 index[2] = ex->zs + (row/(ex->nxny)); 764 PetscStackCallStandard(HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,(HYPRE_Int *)index,var_type,7*nvars,(HYPRE_Int *)entries,values[var_type])); 765 } 766 } else { 767 for (i=0; i<nrow; i++) { 768 var_type = irow[i]/(ex->gnxgnygnz); 769 grid_rank= irow[i] - var_type*(ex->gnxgnygnz); 770 771 row = ex->gindices[grid_rank] - ex->rstart; 772 index[0] = ex->xs + (row % ex->nx); 773 index[1] = ex->ys + ((row/ex->nx) % ex->ny); 774 index[2] = ex->zs + (row/(ex->nxny)); 775 PetscStackCallStandard(HYPRE_SStructMatrixSetValues,(ex->ss_mat,part,(HYPRE_Int *)index,var_type,7*nvars,(HYPRE_Int *)entries,values[var_type])); 776 } 777 } 778 PetscStackCallStandard(HYPRE_SStructMatrixAssemble,(ex->ss_mat)); 779 ierr = PetscFree(values[0]);CHKERRQ(ierr); 780 ierr = PetscFree(values);CHKERRQ(ierr); 781 ierr = PetscFree(entries);CHKERRQ(ierr); 782 PetscFunctionReturn(0); 783 } 784 785 #undef __FUNCT__ 786 #define __FUNCT__ "MatZeroEntries_HYPRESStruct_3d" 787 PetscErrorCode MatZeroEntries_HYPRESStruct_3d(Mat mat) 788 { 789 PetscErrorCode ierr; 790 Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data; 791 PetscInt nvars= ex->nvars; 792 PetscInt size; 793 PetscInt part= 0; /* only one part */ 794 795 PetscFunctionBegin; 796 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); 797 { 798 PetscInt i,*entries,iupper[3],ilower[3]; 799 PetscScalar *values; 800 801 802 for (i= 0; i< 3; i++) { 803 ilower[i]= ex->hbox.imin[i]; 804 iupper[i]= ex->hbox.imax[i]; 805 } 806 807 ierr = PetscMalloc2(nvars*7,&entries,nvars*7*size,&values);CHKERRQ(ierr); 808 for (i= 0; i< nvars*7; i++) entries[i]= i; 809 ierr = PetscMemzero(values,nvars*7*size*sizeof(PetscScalar));CHKERRQ(ierr); 810 811 for (i= 0; i< nvars; i++) { 812 PetscStackCallStandard(HYPRE_SStructMatrixSetBoxValues,(ex->ss_mat,part,(HYPRE_Int *)ilower,(HYPRE_Int *)iupper,i,nvars*7,(HYPRE_Int *)entries,values)); 813 } 814 ierr = PetscFree2(entries,values);CHKERRQ(ierr); 815 } 816 PetscStackCallStandard(HYPRE_SStructMatrixAssemble,(ex->ss_mat)); 817 PetscFunctionReturn(0); 818 } 819 820 821 #undef __FUNCT__ 822 #define __FUNCT__ "MatSetupDM_HYPRESStruct" 823 static PetscErrorCode MatSetupDM_HYPRESStruct(Mat mat,DM da) 824 { 825 PetscErrorCode ierr; 826 Mat_HYPRESStruct *ex = (Mat_HYPRESStruct*) mat->data; 827 PetscInt dim,dof,sw[3],nx,ny,nz; 828 PetscInt ilower[3],iupper[3],ssize,i; 829 DMBoundaryType px,py,pz; 830 DMDAStencilType st; 831 PetscInt nparts= 1; /* assuming only one part */ 832 PetscInt part = 0; 833 ISLocalToGlobalMapping ltog; 834 PetscFunctionBegin; 835 ex->da = da; 836 ierr = PetscObjectReference((PetscObject)da);CHKERRQ(ierr); 837 838 ierr = DMDAGetInfo(ex->da,&dim,0,0,0,0,0,0,&dof,&sw[0],&px,&py,&pz,&st);CHKERRQ(ierr); 839 ierr = DMDAGetCorners(ex->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);CHKERRQ(ierr); 840 iupper[0] += ilower[0] - 1; 841 iupper[1] += ilower[1] - 1; 842 iupper[2] += ilower[2] - 1; 843 /* the hypre_Box is used to zero out the matrix entries in MatZeroValues() */ 844 ex->hbox.imin[0] = ilower[0]; 845 ex->hbox.imin[1] = ilower[1]; 846 ex->hbox.imin[2] = ilower[2]; 847 ex->hbox.imax[0] = iupper[0]; 848 ex->hbox.imax[1] = iupper[1]; 849 ex->hbox.imax[2] = iupper[2]; 850 851 ex->dofs_order = 0; 852 853 /* assuming that the same number of dofs on each gridpoint. Also assume all cell-centred based */ 854 ex->nvars= dof; 855 856 /* create the hypre grid object and set its information */ 857 if (px || py || pz) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add periodic support by calling HYPRE_SStructGridSetPeriodic()"); 858 PetscStackCallStandard(HYPRE_SStructGridCreate,(ex->hcomm,dim,nparts,&ex->ss_grid)); 859 860 PetscStackCallStandard(HYPRE_SStructGridSetExtents,(ex->ss_grid,part,ex->hbox.imin,ex->hbox.imax)); 861 862 { 863 HYPRE_SStructVariable *vartypes; 864 ierr = PetscMalloc1(ex->nvars,&vartypes);CHKERRQ(ierr); 865 for (i= 0; i< ex->nvars; i++) vartypes[i]= HYPRE_SSTRUCT_VARIABLE_CELL; 866 PetscStackCallStandard(HYPRE_SStructGridSetVariables,(ex->ss_grid, part, ex->nvars,vartypes)); 867 ierr = PetscFree(vartypes);CHKERRQ(ierr); 868 } 869 PetscStackCallStandard(HYPRE_SStructGridAssemble,(ex->ss_grid)); 870 871 sw[1] = sw[0]; 872 sw[2] = sw[1]; 873 /* PetscStackCallStandard(HYPRE_SStructGridSetNumGhost,(ex->ss_grid,sw)); */ 874 875 /* create the hypre stencil object and set its information */ 876 if (sw[0] > 1) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add support for wider stencils"); 877 if (st == DMDA_STENCIL_BOX) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Ask us to add support for box stencils"); 878 879 if (dim == 1) { 880 PetscInt offsets[3][1] = {{-1},{0},{1}}; 881 PetscInt j, cnt; 882 883 ssize = 3*(ex->nvars); 884 PetscStackCallStandard(HYPRE_SStructStencilCreate,(dim,ssize,&ex->ss_stencil)); 885 cnt= 0; 886 for (i = 0; i < (ex->nvars); i++) { 887 for (j = 0; j < 3; j++) { 888 PetscStackCallStandard(HYPRE_SStructStencilSetEntry,(ex->ss_stencil, cnt, (HYPRE_Int *)offsets[j], i)); 889 cnt++; 890 } 891 } 892 } else if (dim == 2) { 893 PetscInt offsets[5][2] = {{0,-1},{-1,0},{0,0},{1,0},{0,1}}; 894 PetscInt j, cnt; 895 896 ssize = 5*(ex->nvars); 897 PetscStackCallStandard(HYPRE_SStructStencilCreate,(dim,ssize,&ex->ss_stencil)); 898 cnt= 0; 899 for (i= 0; i< (ex->nvars); i++) { 900 for (j= 0; j< 5; j++) { 901 PetscStackCallStandard(HYPRE_SStructStencilSetEntry,(ex->ss_stencil, cnt, (HYPRE_Int *)offsets[j], i)); 902 cnt++; 903 } 904 } 905 } else if (dim == 3) { 906 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}}; 907 PetscInt j, cnt; 908 909 ssize = 7*(ex->nvars); 910 PetscStackCallStandard(HYPRE_SStructStencilCreate,(dim,ssize,&ex->ss_stencil)); 911 cnt= 0; 912 for (i= 0; i< (ex->nvars); i++) { 913 for (j= 0; j< 7; j++) { 914 PetscStackCallStandard(HYPRE_SStructStencilSetEntry,(ex->ss_stencil, cnt, (HYPRE_Int *)offsets[j], i)); 915 cnt++; 916 } 917 } 918 } 919 920 /* create the HYPRE graph */ 921 PetscStackCallStandard(HYPRE_SStructGraphCreate,(ex->hcomm, ex->ss_grid, &(ex->ss_graph))); 922 923 /* set the stencil graph. Note that each variable has the same graph. This means that each 924 variable couples to all the other variable and with the same stencil pattern. */ 925 for (i= 0; i< (ex->nvars); i++) { 926 PetscStackCallStandard(HYPRE_SStructGraphSetStencil,(ex->ss_graph,part,i,ex->ss_stencil)); 927 } 928 PetscStackCallStandard(HYPRE_SStructGraphAssemble,(ex->ss_graph)); 929 930 /* create the HYPRE sstruct vectors for rhs and solution */ 931 PetscStackCallStandard(HYPRE_SStructVectorCreate,(ex->hcomm,ex->ss_grid,&ex->ss_b)); 932 PetscStackCallStandard(HYPRE_SStructVectorCreate,(ex->hcomm,ex->ss_grid,&ex->ss_x)); 933 PetscStackCallStandard(HYPRE_SStructVectorInitialize,(ex->ss_b)); 934 PetscStackCallStandard(HYPRE_SStructVectorInitialize,(ex->ss_x)); 935 PetscStackCallStandard(HYPRE_SStructVectorAssemble,(ex->ss_b)); 936 PetscStackCallStandard(HYPRE_SStructVectorAssemble,(ex->ss_x)); 937 938 /* create the hypre matrix object and set its information */ 939 PetscStackCallStandard(HYPRE_SStructMatrixCreate,(ex->hcomm,ex->ss_graph,&ex->ss_mat)); 940 PetscStackCallStandard(HYPRE_SStructGridDestroy,(ex->ss_grid)); 941 PetscStackCallStandard(HYPRE_SStructStencilDestroy,(ex->ss_stencil)); 942 if (ex->needsinitialization) { 943 PetscStackCallStandard(HYPRE_SStructMatrixInitialize,(ex->ss_mat)); 944 ex->needsinitialization = PETSC_FALSE; 945 } 946 947 /* set the global and local sizes of the matrix */ 948 ierr = DMDAGetCorners(da,0,0,0,&nx,&ny,&nz);CHKERRQ(ierr); 949 ierr = MatSetSizes(mat,dof*nx*ny*nz,dof*nx*ny*nz,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr); 950 ierr = PetscLayoutSetBlockSize(mat->rmap,1);CHKERRQ(ierr); 951 ierr = PetscLayoutSetBlockSize(mat->cmap,1);CHKERRQ(ierr); 952 ierr = PetscLayoutSetUp(mat->rmap);CHKERRQ(ierr); 953 ierr = PetscLayoutSetUp(mat->cmap);CHKERRQ(ierr); 954 955 if (dim == 3) { 956 mat->ops->setvalueslocal = MatSetValuesLocal_HYPRESStruct_3d; 957 mat->ops->zerorowslocal = MatZeroRowsLocal_HYPRESStruct_3d; 958 mat->ops->zeroentries = MatZeroEntries_HYPRESStruct_3d; 959 960 ierr = MatZeroEntries_HYPRESStruct_3d(mat);CHKERRQ(ierr); 961 } else SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Only support for 3d DMDA currently"); 962 963 /* get values that will be used repeatedly in MatSetValuesLocal() and MatZeroRowsLocal() repeatedly */ 964 ierr = MatGetOwnershipRange(mat,&ex->rstart,NULL);CHKERRQ(ierr); 965 ierr = DMGetLocalToGlobalMapping(ex->da,<og);CHKERRQ(ierr); 966 ierr = ISLocalToGlobalMappingGetIndices(ltog, (const PetscInt **) &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,(HYPRE_Int *)ilower,(HYPRE_Int *)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,(HYPRE_Int *)ilower,(HYPRE_Int *)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 = PetscMalloc1(nvars*size,&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,(HYPRE_Int *)ilower,(HYPRE_Int *)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,(HYPRE_Int *)ilower,(HYPRE_Int *)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 #undef __FUNCT__ 1093 #define __FUNCT__ "MatCreate_HYPRESStruct" 1094 PETSC_EXTERN PetscErrorCode MatCreate_HYPRESStruct(Mat B) 1095 { 1096 Mat_HYPRESStruct *ex; 1097 PetscErrorCode ierr; 1098 1099 PetscFunctionBegin; 1100 ierr = PetscNewLog(B,&ex);CHKERRQ(ierr); 1101 B->data = (void*)ex; 1102 B->rmap->bs = 1; 1103 B->assembled = PETSC_FALSE; 1104 1105 B->insertmode = NOT_SET_VALUES; 1106 1107 B->ops->assemblyend = MatAssemblyEnd_HYPRESStruct; 1108 B->ops->mult = MatMult_HYPRESStruct; 1109 B->ops->zeroentries = MatZeroEntries_HYPRESStruct; 1110 B->ops->destroy = MatDestroy_HYPRESStruct; 1111 1112 ex->needsinitialization = PETSC_TRUE; 1113 1114 ierr = MPI_Comm_dup(PetscObjectComm((PetscObject)B),&(ex->hcomm));CHKERRQ(ierr); 1115 ierr = PetscObjectComposeFunction((PetscObject)B,"MatSetupDM_C",MatSetupDM_HYPRESStruct);CHKERRQ(ierr); 1116 ierr = PetscObjectChangeTypeName((PetscObject)B,MATHYPRESSTRUCT);CHKERRQ(ierr); 1117 PetscFunctionReturn(0); 1118 } 1119 1120 1121 1122