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