1 2 /* 3 Creates a matrix class for using the Neumann-Neumann type preconditioners. 4 This stores the matrices in globally unassembled form. Each processor 5 assembles only its local Neumann problem and the parallel matrix vector 6 product is handled "implicitly". 7 8 We provide: 9 MatMult() 10 11 Currently this allows for only one subdomain per processor. 12 13 */ 14 15 #include <../src/mat/impls/is/matis.h> /*I "petscmat.h" I*/ 16 17 static PetscErrorCode MatISComputeSF_Private(Mat); 18 19 #undef __FUNCT__ 20 #define __FUNCT__ "MatISComputeSF_Private" 21 static PetscErrorCode MatISComputeSF_Private(Mat B) 22 { 23 Mat_IS *matis = (Mat_IS*)(B->data); 24 const PetscInt *gidxs; 25 PetscErrorCode ierr; 26 27 PetscFunctionBegin; 28 ierr = MatGetSize(matis->A,&matis->sf_nleaves,NULL);CHKERRQ(ierr); 29 ierr = MatGetLocalSize(B,&matis->sf_nroots,NULL);CHKERRQ(ierr); 30 ierr = PetscSFCreate(PetscObjectComm((PetscObject)B),&matis->sf);CHKERRQ(ierr); 31 ierr = ISLocalToGlobalMappingGetIndices(B->rmap->mapping,&gidxs);CHKERRQ(ierr); 32 /* PETSC_OWN_POINTER refers to ilocal which is NULL */ 33 ierr = PetscSFSetGraphLayout(matis->sf,B->rmap,matis->sf_nleaves,NULL,PETSC_OWN_POINTER,gidxs);CHKERRQ(ierr); 34 ierr = ISLocalToGlobalMappingRestoreIndices(B->rmap->mapping,&gidxs);CHKERRQ(ierr); 35 ierr = PetscMalloc2(matis->sf_nroots,&matis->sf_rootdata,matis->sf_nleaves,&matis->sf_leafdata);CHKERRQ(ierr); 36 PetscFunctionReturn(0); 37 } 38 39 #undef __FUNCT__ 40 #define __FUNCT__ "MatISSetPreallocation" 41 /*@ 42 MatISSetPreallocation - Preallocates memory for a MATIS parallel matrix. 43 44 Collective on MPI_Comm 45 46 Input Parameters: 47 + B - the matrix 48 . d_nz - number of nonzeros per row in DIAGONAL portion of local submatrix 49 (same value is used for all local rows) 50 . d_nnz - array containing the number of nonzeros in the various rows of the 51 DIAGONAL portion of the local submatrix (possibly different for each row) 52 or NULL, if d_nz is used to specify the nonzero structure. 53 The size of this array is equal to the number of local rows, i.e 'm'. 54 For matrices that will be factored, you must leave room for (and set) 55 the diagonal entry even if it is zero. 56 . o_nz - number of nonzeros per row in the OFF-DIAGONAL portion of local 57 submatrix (same value is used for all local rows). 58 - o_nnz - array containing the number of nonzeros in the various rows of the 59 OFF-DIAGONAL portion of the local submatrix (possibly different for 60 each row) or NULL, if o_nz is used to specify the nonzero 61 structure. The size of this array is equal to the number 62 of local rows, i.e 'm'. 63 64 If the *_nnz parameter is given then the *_nz parameter is ignored 65 66 Level: intermediate 67 68 Notes: This function has the same interface as the MPIAIJ preallocation routine in order to simplify the transition 69 from the asssembled format to the unassembled one. It overestimates the preallocation of MATIS local 70 matrices; for exact preallocation, the user should set the preallocation directly on local matrix objects. 71 72 .keywords: matrix 73 74 .seealso: MatCreate(), MatCreateIS(), MatMPIAIJSetPreallocation(), MatISGetLocalMat() 75 @*/ 76 PetscErrorCode MatISSetPreallocation(Mat B,PetscInt d_nz,const PetscInt d_nnz[],PetscInt o_nz,const PetscInt o_nnz[]) 77 { 78 PetscErrorCode ierr; 79 80 PetscFunctionBegin; 81 PetscValidHeaderSpecific(B,MAT_CLASSID,1); 82 PetscValidType(B,1); 83 ierr = PetscTryMethod(B,"MatISSetPreallocation_C",(Mat,PetscInt,const PetscInt[],PetscInt,const PetscInt[]),(B,d_nz,d_nnz,o_nz,o_nnz));CHKERRQ(ierr); 84 PetscFunctionReturn(0); 85 } 86 87 #undef __FUNCT__ 88 #define __FUNCT__ "MatISSetPreallocation_IS" 89 PetscErrorCode MatISSetPreallocation_IS(Mat B,PetscInt d_nz,const PetscInt d_nnz[],PetscInt o_nz,const PetscInt o_nnz[]) 90 { 91 Mat_IS *matis = (Mat_IS*)(B->data); 92 PetscInt bs,i,nlocalcols; 93 PetscErrorCode ierr; 94 95 PetscFunctionBegin; 96 if (!matis->A) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_SUP,"You should first call MatSetLocalToGlobalMapping"); 97 if (!matis->sf) { /* setup SF if not yet created and allocate rootdata and leafdata */ 98 ierr = MatISComputeSF_Private(B);CHKERRQ(ierr); 99 } 100 if (!d_nnz) { 101 for (i=0;i<matis->sf_nroots;i++) matis->sf_rootdata[i] = d_nz; 102 } else { 103 for (i=0;i<matis->sf_nroots;i++) matis->sf_rootdata[i] = d_nnz[i]; 104 } 105 if (!o_nnz) { 106 for (i=0;i<matis->sf_nroots;i++) matis->sf_rootdata[i] += o_nz; 107 } else { 108 for (i=0;i<matis->sf_nroots;i++) matis->sf_rootdata[i] += o_nnz[i]; 109 } 110 ierr = PetscSFBcastBegin(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);CHKERRQ(ierr); 111 ierr = MatGetSize(matis->A,NULL,&nlocalcols);CHKERRQ(ierr); 112 ierr = MatGetBlockSize(matis->A,&bs);CHKERRQ(ierr); 113 ierr = PetscSFBcastEnd(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);CHKERRQ(ierr); 114 for (i=0;i<matis->sf_nleaves;i++) { 115 matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i],nlocalcols); 116 } 117 ierr = MatSeqAIJSetPreallocation(matis->A,0,matis->sf_leafdata);CHKERRQ(ierr); 118 for (i=0;i<matis->sf_nleaves/bs;i++) { 119 matis->sf_leafdata[i] = matis->sf_leafdata[i*bs]/bs; 120 } 121 ierr = MatSeqBAIJSetPreallocation(matis->A,bs,0,matis->sf_leafdata);CHKERRQ(ierr); 122 for (i=0;i<matis->sf_nleaves/bs;i++) { 123 matis->sf_leafdata[i] = matis->sf_leafdata[i]-i; 124 } 125 ierr = MatSeqSBAIJSetPreallocation(matis->A,bs,0,matis->sf_leafdata);CHKERRQ(ierr); 126 PetscFunctionReturn(0); 127 } 128 129 #undef __FUNCT__ 130 #define __FUNCT__ "MatISSetMPIXAIJPreallocation_Private" 131 PETSC_EXTERN PetscErrorCode MatISSetMPIXAIJPreallocation_Private(Mat A, Mat B, PetscBool maxreduce) 132 { 133 Mat_IS *matis = (Mat_IS*)(A->data); 134 PetscInt *my_dnz,*my_onz,*dnz,*onz,*mat_ranges,*row_ownership; 135 const PetscInt *global_indices_r,*global_indices_c; 136 PetscInt i,j,bs,rows,cols; 137 PetscInt lrows,lcols; 138 PetscInt local_rows,local_cols; 139 PetscMPIInt nsubdomains; 140 PetscBool isdense,issbaij; 141 PetscErrorCode ierr; 142 143 PetscFunctionBegin; 144 ierr = MPI_Comm_size(PetscObjectComm((PetscObject)A),&nsubdomains);CHKERRQ(ierr); 145 ierr = MatGetSize(A,&rows,&cols);CHKERRQ(ierr); 146 ierr = MatGetBlockSize(A,&bs);CHKERRQ(ierr); 147 ierr = MatGetSize(matis->A,&local_rows,&local_cols);CHKERRQ(ierr); 148 ierr = PetscObjectTypeCompare((PetscObject)matis->A,MATSEQDENSE,&isdense);CHKERRQ(ierr); 149 ierr = PetscObjectTypeCompare((PetscObject)matis->A,MATSEQSBAIJ,&issbaij);CHKERRQ(ierr); 150 ierr = ISLocalToGlobalMappingGetIndices(A->rmap->mapping,&global_indices_r);CHKERRQ(ierr); 151 if (A->rmap->mapping != A->cmap->mapping) { 152 ierr = ISLocalToGlobalMappingGetIndices(A->rmap->mapping,&global_indices_c);CHKERRQ(ierr); 153 } else { 154 global_indices_c = global_indices_r; 155 } 156 157 if (issbaij) { 158 ierr = MatGetRowUpperTriangular(matis->A);CHKERRQ(ierr); 159 } 160 /* 161 An SF reduce is needed to sum up properly on shared rows. 162 Note that generally preallocation is not exact, since it overestimates nonzeros 163 */ 164 if (!matis->sf) { /* setup SF if not yet created and allocate rootdata and leafdata */ 165 ierr = MatISComputeSF_Private(A);CHKERRQ(ierr); 166 } 167 ierr = MatGetLocalSize(A,&lrows,&lcols);CHKERRQ(ierr); 168 ierr = MatPreallocateInitialize(PetscObjectComm((PetscObject)A),lrows,lcols,dnz,onz);CHKERRQ(ierr); 169 /* All processes need to compute entire row ownership */ 170 ierr = PetscMalloc1(rows,&row_ownership);CHKERRQ(ierr); 171 ierr = MatGetOwnershipRanges(A,(const PetscInt**)&mat_ranges);CHKERRQ(ierr); 172 for (i=0;i<nsubdomains;i++) { 173 for (j=mat_ranges[i];j<mat_ranges[i+1];j++) { 174 row_ownership[j] = i; 175 } 176 } 177 178 /* 179 my_dnz and my_onz contains exact contribution to preallocation from each local mat 180 then, they will be summed up properly. This way, preallocation is always sufficient 181 */ 182 ierr = PetscCalloc2(local_rows,&my_dnz,local_rows,&my_onz);CHKERRQ(ierr); 183 /* preallocation as a MATAIJ */ 184 if (isdense) { /* special case for dense local matrices */ 185 for (i=0;i<local_rows;i++) { 186 PetscInt index_row = global_indices_r[i]; 187 for (j=i;j<local_rows;j++) { 188 PetscInt owner = row_ownership[index_row]; 189 PetscInt index_col = global_indices_c[j]; 190 if (index_col > mat_ranges[owner]-1 && index_col < mat_ranges[owner+1] ) { /* diag block */ 191 my_dnz[i] += 1; 192 } else { /* offdiag block */ 193 my_onz[i] += 1; 194 } 195 /* same as before, interchanging rows and cols */ 196 if (i != j) { 197 owner = row_ownership[index_col]; 198 if (index_row > mat_ranges[owner]-1 && index_row < mat_ranges[owner+1] ) { 199 my_dnz[j] += 1; 200 } else { 201 my_onz[j] += 1; 202 } 203 } 204 } 205 } 206 } else { /* TODO: this could be optimized using MatGetRowIJ */ 207 for (i=0;i<local_rows;i++) { 208 const PetscInt *cols; 209 PetscInt ncols,index_row = global_indices_r[i]; 210 ierr = MatGetRow(matis->A,i,&ncols,&cols,NULL);CHKERRQ(ierr); 211 for (j=0;j<ncols;j++) { 212 PetscInt owner = row_ownership[index_row]; 213 PetscInt index_col = global_indices_c[cols[j]]; 214 if (index_col > mat_ranges[owner]-1 && index_col < mat_ranges[owner+1] ) { /* diag block */ 215 my_dnz[i] += 1; 216 } else { /* offdiag block */ 217 my_onz[i] += 1; 218 } 219 /* same as before, interchanging rows and cols */ 220 if (issbaij && index_col != index_row) { 221 owner = row_ownership[index_col]; 222 if (index_row > mat_ranges[owner]-1 && index_row < mat_ranges[owner+1] ) { 223 my_dnz[cols[j]] += 1; 224 } else { 225 my_onz[cols[j]] += 1; 226 } 227 } 228 } 229 ierr = MatRestoreRow(matis->A,i,&ncols,&cols,NULL);CHKERRQ(ierr); 230 } 231 } 232 if (global_indices_c != global_indices_r) { 233 ierr = ISLocalToGlobalMappingRestoreIndices(A->rmap->mapping,&global_indices_c);CHKERRQ(ierr); 234 } 235 ierr = ISLocalToGlobalMappingRestoreIndices(A->rmap->mapping,&global_indices_r);CHKERRQ(ierr); 236 ierr = PetscFree(row_ownership);CHKERRQ(ierr); 237 238 /* Reduce my_dnz and my_onz */ 239 if (maxreduce) { 240 ierr = PetscSFReduceBegin(matis->sf,MPIU_INT,my_dnz,dnz,MPI_MAX);CHKERRQ(ierr); 241 ierr = PetscSFReduceEnd(matis->sf,MPIU_INT,my_dnz,dnz,MPI_MAX);CHKERRQ(ierr); 242 ierr = PetscSFReduceBegin(matis->sf,MPIU_INT,my_onz,onz,MPI_MAX);CHKERRQ(ierr); 243 ierr = PetscSFReduceEnd(matis->sf,MPIU_INT,my_onz,onz,MPI_MAX);CHKERRQ(ierr); 244 } else { 245 ierr = PetscSFReduceBegin(matis->sf,MPIU_INT,my_dnz,dnz,MPI_SUM);CHKERRQ(ierr); 246 ierr = PetscSFReduceEnd(matis->sf,MPIU_INT,my_dnz,dnz,MPI_SUM);CHKERRQ(ierr); 247 ierr = PetscSFReduceBegin(matis->sf,MPIU_INT,my_onz,onz,MPI_SUM);CHKERRQ(ierr); 248 ierr = PetscSFReduceEnd(matis->sf,MPIU_INT,my_onz,onz,MPI_SUM);CHKERRQ(ierr); 249 } 250 ierr = PetscFree2(my_dnz,my_onz);CHKERRQ(ierr); 251 252 /* Resize preallocation if overestimated */ 253 for (i=0;i<lrows;i++) { 254 dnz[i] = PetscMin(dnz[i],lcols); 255 onz[i] = PetscMin(onz[i],cols-lcols); 256 } 257 /* set preallocation */ 258 ierr = MatMPIAIJSetPreallocation(B,0,dnz,0,onz);CHKERRQ(ierr); 259 for (i=0;i<lrows/bs;i++) { 260 dnz[i] = dnz[i*bs]/bs; 261 onz[i] = onz[i*bs]/bs; 262 } 263 ierr = MatMPIBAIJSetPreallocation(B,bs,0,dnz,0,onz);CHKERRQ(ierr); 264 ierr = MatMPISBAIJSetPreallocation(B,bs,0,dnz,0,onz);CHKERRQ(ierr); 265 ierr = MatPreallocateFinalize(dnz,onz);CHKERRQ(ierr); 266 if (issbaij) { 267 ierr = MatRestoreRowUpperTriangular(matis->A);CHKERRQ(ierr); 268 } 269 PetscFunctionReturn(0); 270 } 271 272 #undef __FUNCT__ 273 #define __FUNCT__ "MatISGetMPIXAIJ_IS" 274 PetscErrorCode MatISGetMPIXAIJ_IS(Mat mat, MatReuse reuse, Mat *M) 275 { 276 Mat_IS *matis = (Mat_IS*)(mat->data); 277 Mat local_mat; 278 /* info on mat */ 279 PetscInt bs,rows,cols,lrows,lcols; 280 PetscInt local_rows,local_cols; 281 PetscBool isdense,issbaij,isseqaij; 282 PetscMPIInt nsubdomains; 283 /* values insertion */ 284 PetscScalar *array; 285 /* work */ 286 PetscErrorCode ierr; 287 288 PetscFunctionBegin; 289 /* get info from mat */ 290 ierr = MPI_Comm_size(PetscObjectComm((PetscObject)mat),&nsubdomains);CHKERRQ(ierr); 291 if (nsubdomains == 1) { 292 if (reuse == MAT_INITIAL_MATRIX) { 293 ierr = MatDuplicate(matis->A,MAT_COPY_VALUES,&(*M));CHKERRQ(ierr); 294 } else { 295 ierr = MatCopy(matis->A,*M,SAME_NONZERO_PATTERN);CHKERRQ(ierr); 296 } 297 PetscFunctionReturn(0); 298 } 299 ierr = MatGetSize(mat,&rows,&cols);CHKERRQ(ierr); 300 ierr = MatGetBlockSize(mat,&bs);CHKERRQ(ierr); 301 ierr = MatGetLocalSize(mat,&lrows,&lcols);CHKERRQ(ierr); 302 ierr = MatGetSize(matis->A,&local_rows,&local_cols);CHKERRQ(ierr); 303 ierr = PetscObjectTypeCompare((PetscObject)matis->A,MATSEQDENSE,&isdense);CHKERRQ(ierr); 304 ierr = PetscObjectTypeCompare((PetscObject)matis->A,MATSEQAIJ,&isseqaij);CHKERRQ(ierr); 305 ierr = PetscObjectTypeCompare((PetscObject)matis->A,MATSEQSBAIJ,&issbaij);CHKERRQ(ierr); 306 307 if (reuse == MAT_INITIAL_MATRIX) { 308 MatType new_mat_type; 309 PetscBool issbaij_red; 310 311 /* determining new matrix type */ 312 ierr = MPIU_Allreduce(&issbaij,&issbaij_red,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)mat));CHKERRQ(ierr); 313 if (issbaij_red) { 314 new_mat_type = MATSBAIJ; 315 } else { 316 if (bs>1) { 317 new_mat_type = MATBAIJ; 318 } else { 319 new_mat_type = MATAIJ; 320 } 321 } 322 323 ierr = MatCreate(PetscObjectComm((PetscObject)mat),M);CHKERRQ(ierr); 324 ierr = MatSetSizes(*M,lrows,lcols,rows,cols);CHKERRQ(ierr); 325 ierr = MatSetBlockSize(*M,bs);CHKERRQ(ierr); 326 ierr = MatSetType(*M,new_mat_type);CHKERRQ(ierr); 327 ierr = MatISSetMPIXAIJPreallocation_Private(mat,*M,PETSC_FALSE);CHKERRQ(ierr); 328 } else { 329 PetscInt mbs,mrows,mcols,mlrows,mlcols; 330 /* some checks */ 331 ierr = MatGetBlockSize(*M,&mbs);CHKERRQ(ierr); 332 ierr = MatGetSize(*M,&mrows,&mcols);CHKERRQ(ierr); 333 ierr = MatGetLocalSize(*M,&mlrows,&mlcols);CHKERRQ(ierr); 334 if (mrows != rows) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong number of rows (%d != %d)",rows,mrows); 335 if (mcols != cols) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong number of cols (%d != %d)",cols,mcols); 336 if (mlrows != lrows) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong number of local rows (%d != %d)",lrows,mlrows); 337 if (mlcols != lcols) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong number of local cols (%d != %d)",lcols,mlcols); 338 if (mbs != bs) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong block size (%d != %d)",bs,mbs); 339 ierr = MatZeroEntries(*M);CHKERRQ(ierr); 340 } 341 342 if (issbaij) { 343 ierr = MatConvert(matis->A,MATSEQBAIJ,MAT_INITIAL_MATRIX,&local_mat);CHKERRQ(ierr); 344 } else { 345 ierr = PetscObjectReference((PetscObject)matis->A);CHKERRQ(ierr); 346 local_mat = matis->A; 347 } 348 349 /* Set values */ 350 ierr = MatSetLocalToGlobalMapping(*M,mat->rmap->mapping,mat->cmap->mapping);CHKERRQ(ierr); 351 if (isdense) { /* special case for dense local matrices */ 352 PetscInt i,*dummy_rows,*dummy_cols; 353 354 if (local_rows != local_cols) { 355 ierr = PetscMalloc2(local_rows,&dummy_rows,local_cols,&dummy_cols);CHKERRQ(ierr); 356 for (i=0;i<local_rows;i++) dummy_rows[i] = i; 357 for (i=0;i<local_cols;i++) dummy_cols[i] = i; 358 } else { 359 ierr = PetscMalloc1(local_rows,&dummy_rows);CHKERRQ(ierr); 360 for (i=0;i<local_rows;i++) dummy_rows[i] = i; 361 dummy_cols = dummy_rows; 362 } 363 ierr = MatSetOption(*M,MAT_ROW_ORIENTED,PETSC_FALSE);CHKERRQ(ierr); 364 ierr = MatDenseGetArray(local_mat,&array);CHKERRQ(ierr); 365 ierr = MatSetValuesLocal(*M,local_rows,dummy_rows,local_cols,dummy_cols,array,ADD_VALUES);CHKERRQ(ierr); 366 ierr = MatDenseRestoreArray(local_mat,&array);CHKERRQ(ierr); 367 if (dummy_rows != dummy_cols) { 368 ierr = PetscFree2(dummy_rows,dummy_cols);CHKERRQ(ierr); 369 } else { 370 ierr = PetscFree(dummy_rows);CHKERRQ(ierr); 371 } 372 } else if (isseqaij) { 373 PetscInt i,nvtxs,*xadj,*adjncy; 374 PetscBool done; 375 376 ierr = MatGetRowIJ(local_mat,0,PETSC_FALSE,PETSC_FALSE,&nvtxs,(const PetscInt**)&xadj,(const PetscInt**)&adjncy,&done);CHKERRQ(ierr); 377 if (!done) SETERRQ1(PetscObjectComm((PetscObject)local_mat),PETSC_ERR_PLIB,"Error in MatRestoreRowIJ called in %s\n",__FUNCT__); 378 ierr = MatSeqAIJGetArray(local_mat,&array);CHKERRQ(ierr); 379 for (i=0;i<nvtxs;i++) { 380 ierr = MatSetValuesLocal(*M,1,&i,xadj[i+1]-xadj[i],adjncy+xadj[i],array+xadj[i],ADD_VALUES);CHKERRQ(ierr); 381 } 382 ierr = MatRestoreRowIJ(local_mat,0,PETSC_FALSE,PETSC_FALSE,&nvtxs,(const PetscInt**)&xadj,(const PetscInt**)&adjncy,&done);CHKERRQ(ierr); 383 if (!done) SETERRQ1(PetscObjectComm((PetscObject)local_mat),PETSC_ERR_PLIB,"Error in MatRestoreRowIJ called in %s\n",__FUNCT__); 384 ierr = MatSeqAIJRestoreArray(local_mat,&array);CHKERRQ(ierr); 385 } else { /* very basic values insertion for all other matrix types */ 386 PetscInt i; 387 388 for (i=0;i<local_rows;i++) { 389 PetscInt j; 390 const PetscInt *local_indices_cols; 391 392 ierr = MatGetRow(local_mat,i,&j,&local_indices_cols,(const PetscScalar**)&array);CHKERRQ(ierr); 393 ierr = MatSetValuesLocal(*M,1,&i,j,local_indices_cols,array,ADD_VALUES);CHKERRQ(ierr); 394 ierr = MatRestoreRow(local_mat,i,&j,&local_indices_cols,(const PetscScalar**)&array);CHKERRQ(ierr); 395 } 396 } 397 ierr = MatAssemblyBegin(*M,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 398 ierr = MatDestroy(&local_mat);CHKERRQ(ierr); 399 ierr = MatAssemblyEnd(*M,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 400 if (isdense) { 401 ierr = MatSetOption(*M,MAT_ROW_ORIENTED,PETSC_TRUE);CHKERRQ(ierr); 402 } 403 PetscFunctionReturn(0); 404 } 405 406 #undef __FUNCT__ 407 #define __FUNCT__ "MatISGetMPIXAIJ" 408 /*@ 409 MatISGetMPIXAIJ - Converts MATIS matrix into a parallel AIJ format 410 411 Input Parameter: 412 . mat - the matrix (should be of type MATIS) 413 . reuse - either MAT_INITIAL_MATRIX or MAT_REUSE_MATRIX 414 415 Output Parameter: 416 . newmat - the matrix in AIJ format 417 418 Level: developer 419 420 Notes: mat and *newmat cannot be the same object when MAT_REUSE_MATRIX is requested. 421 422 .seealso: MATIS 423 @*/ 424 PetscErrorCode MatISGetMPIXAIJ(Mat mat, MatReuse reuse, Mat *newmat) 425 { 426 PetscErrorCode ierr; 427 428 PetscFunctionBegin; 429 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 430 PetscValidLogicalCollectiveEnum(mat,reuse,2); 431 PetscValidPointer(newmat,3); 432 if (reuse != MAT_INITIAL_MATRIX) { 433 PetscValidHeaderSpecific(*newmat,MAT_CLASSID,3); 434 PetscCheckSameComm(mat,1,*newmat,3); 435 if (mat == *newmat) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse the same matrix"); 436 } 437 ierr = PetscUseMethod(mat,"MatISGetMPIXAIJ_C",(Mat,MatReuse,Mat*),(mat,reuse,newmat));CHKERRQ(ierr); 438 PetscFunctionReturn(0); 439 } 440 441 #undef __FUNCT__ 442 #define __FUNCT__ "MatDuplicate_IS" 443 PetscErrorCode MatDuplicate_IS(Mat mat,MatDuplicateOption op,Mat *newmat) 444 { 445 PetscErrorCode ierr; 446 Mat_IS *matis = (Mat_IS*)(mat->data); 447 PetscInt bs,m,n,M,N; 448 Mat B,localmat; 449 450 PetscFunctionBegin; 451 ierr = MatGetBlockSize(mat,&bs);CHKERRQ(ierr); 452 ierr = MatGetSize(mat,&M,&N);CHKERRQ(ierr); 453 ierr = MatGetLocalSize(mat,&m,&n);CHKERRQ(ierr); 454 ierr = MatCreateIS(PetscObjectComm((PetscObject)mat),bs,m,n,M,N,mat->rmap->mapping,mat->cmap->mapping,&B);CHKERRQ(ierr); 455 ierr = MatDuplicate(matis->A,op,&localmat);CHKERRQ(ierr); 456 ierr = MatISSetLocalMat(B,localmat);CHKERRQ(ierr); 457 ierr = MatDestroy(&localmat);CHKERRQ(ierr); 458 ierr = MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 459 ierr = MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 460 *newmat = B; 461 PetscFunctionReturn(0); 462 } 463 464 #undef __FUNCT__ 465 #define __FUNCT__ "MatIsHermitian_IS" 466 PetscErrorCode MatIsHermitian_IS(Mat A,PetscReal tol,PetscBool *flg) 467 { 468 PetscErrorCode ierr; 469 Mat_IS *matis = (Mat_IS*)A->data; 470 PetscBool local_sym; 471 472 PetscFunctionBegin; 473 ierr = MatIsHermitian(matis->A,tol,&local_sym);CHKERRQ(ierr); 474 ierr = MPIU_Allreduce(&local_sym,flg,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)A));CHKERRQ(ierr); 475 PetscFunctionReturn(0); 476 } 477 478 #undef __FUNCT__ 479 #define __FUNCT__ "MatIsSymmetric_IS" 480 PetscErrorCode MatIsSymmetric_IS(Mat A,PetscReal tol,PetscBool *flg) 481 { 482 PetscErrorCode ierr; 483 Mat_IS *matis = (Mat_IS*)A->data; 484 PetscBool local_sym; 485 486 PetscFunctionBegin; 487 ierr = MatIsSymmetric(matis->A,tol,&local_sym);CHKERRQ(ierr); 488 ierr = MPIU_Allreduce(&local_sym,flg,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)A));CHKERRQ(ierr); 489 PetscFunctionReturn(0); 490 } 491 492 #undef __FUNCT__ 493 #define __FUNCT__ "MatDestroy_IS" 494 PetscErrorCode MatDestroy_IS(Mat A) 495 { 496 PetscErrorCode ierr; 497 Mat_IS *b = (Mat_IS*)A->data; 498 499 PetscFunctionBegin; 500 ierr = MatDestroy(&b->A);CHKERRQ(ierr); 501 ierr = VecScatterDestroy(&b->cctx);CHKERRQ(ierr); 502 ierr = VecScatterDestroy(&b->rctx);CHKERRQ(ierr); 503 ierr = VecDestroy(&b->x);CHKERRQ(ierr); 504 ierr = VecDestroy(&b->y);CHKERRQ(ierr); 505 ierr = PetscSFDestroy(&b->sf);CHKERRQ(ierr); 506 ierr = PetscFree2(b->sf_rootdata,b->sf_leafdata);CHKERRQ(ierr); 507 ierr = PetscFree(A->data);CHKERRQ(ierr); 508 ierr = PetscObjectChangeTypeName((PetscObject)A,0);CHKERRQ(ierr); 509 ierr = PetscObjectComposeFunction((PetscObject)A,"MatISGetLocalMat_C",NULL);CHKERRQ(ierr); 510 ierr = PetscObjectComposeFunction((PetscObject)A,"MatISSetLocalMat_C",NULL);CHKERRQ(ierr); 511 ierr = PetscObjectComposeFunction((PetscObject)A,"MatISGetMPIXAIJ_C",NULL);CHKERRQ(ierr); 512 ierr = PetscObjectComposeFunction((PetscObject)A,"MatISSetPreallocation_C",NULL);CHKERRQ(ierr); 513 PetscFunctionReturn(0); 514 } 515 516 #undef __FUNCT__ 517 #define __FUNCT__ "MatMult_IS" 518 PetscErrorCode MatMult_IS(Mat A,Vec x,Vec y) 519 { 520 PetscErrorCode ierr; 521 Mat_IS *is = (Mat_IS*)A->data; 522 PetscScalar zero = 0.0; 523 524 PetscFunctionBegin; 525 /* scatter the global vector x into the local work vector */ 526 ierr = VecScatterBegin(is->cctx,x,is->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 527 ierr = VecScatterEnd(is->cctx,x,is->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 528 529 /* multiply the local matrix */ 530 ierr = MatMult(is->A,is->x,is->y);CHKERRQ(ierr); 531 532 /* scatter product back into global memory */ 533 ierr = VecSet(y,zero);CHKERRQ(ierr); 534 ierr = VecScatterBegin(is->rctx,is->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 535 ierr = VecScatterEnd(is->rctx,is->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 536 PetscFunctionReturn(0); 537 } 538 539 #undef __FUNCT__ 540 #define __FUNCT__ "MatMultAdd_IS" 541 PetscErrorCode MatMultAdd_IS(Mat A,Vec v1,Vec v2,Vec v3) 542 { 543 Vec temp_vec; 544 PetscErrorCode ierr; 545 546 PetscFunctionBegin; /* v3 = v2 + A * v1.*/ 547 if (v3 != v2) { 548 ierr = MatMult(A,v1,v3);CHKERRQ(ierr); 549 ierr = VecAXPY(v3,1.0,v2);CHKERRQ(ierr); 550 } else { 551 ierr = VecDuplicate(v2,&temp_vec);CHKERRQ(ierr); 552 ierr = MatMult(A,v1,temp_vec);CHKERRQ(ierr); 553 ierr = VecAXPY(temp_vec,1.0,v2);CHKERRQ(ierr); 554 ierr = VecCopy(temp_vec,v3);CHKERRQ(ierr); 555 ierr = VecDestroy(&temp_vec);CHKERRQ(ierr); 556 } 557 PetscFunctionReturn(0); 558 } 559 560 #undef __FUNCT__ 561 #define __FUNCT__ "MatMultTranspose_IS" 562 PetscErrorCode MatMultTranspose_IS(Mat A,Vec y,Vec x) 563 { 564 Mat_IS *is = (Mat_IS*)A->data; 565 PetscErrorCode ierr; 566 567 PetscFunctionBegin; 568 /* scatter the global vector x into the local work vector */ 569 ierr = VecScatterBegin(is->rctx,y,is->y,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 570 ierr = VecScatterEnd(is->rctx,y,is->y,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 571 572 /* multiply the local matrix */ 573 ierr = MatMultTranspose(is->A,is->y,is->x);CHKERRQ(ierr); 574 575 /* scatter product back into global vector */ 576 ierr = VecSet(x,0);CHKERRQ(ierr); 577 ierr = VecScatterBegin(is->cctx,is->x,x,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 578 ierr = VecScatterEnd(is->cctx,is->x,x,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 579 PetscFunctionReturn(0); 580 } 581 582 #undef __FUNCT__ 583 #define __FUNCT__ "MatMultTransposeAdd_IS" 584 PetscErrorCode MatMultTransposeAdd_IS(Mat A,Vec v1,Vec v2,Vec v3) 585 { 586 Vec temp_vec; 587 PetscErrorCode ierr; 588 589 PetscFunctionBegin; /* v3 = v2 + A' * v1.*/ 590 if (v3 != v2) { 591 ierr = MatMultTranspose(A,v1,v3);CHKERRQ(ierr); 592 ierr = VecAXPY(v3,1.0,v2);CHKERRQ(ierr); 593 } else { 594 ierr = VecDuplicate(v2,&temp_vec);CHKERRQ(ierr); 595 ierr = MatMultTranspose(A,v1,temp_vec);CHKERRQ(ierr); 596 ierr = VecAXPY(temp_vec,1.0,v2);CHKERRQ(ierr); 597 ierr = VecCopy(temp_vec,v3);CHKERRQ(ierr); 598 ierr = VecDestroy(&temp_vec);CHKERRQ(ierr); 599 } 600 PetscFunctionReturn(0); 601 } 602 603 #undef __FUNCT__ 604 #define __FUNCT__ "MatView_IS" 605 PetscErrorCode MatView_IS(Mat A,PetscViewer viewer) 606 { 607 Mat_IS *a = (Mat_IS*)A->data; 608 PetscErrorCode ierr; 609 PetscViewer sviewer; 610 611 PetscFunctionBegin; 612 ierr = PetscViewerGetSubViewer(viewer,PETSC_COMM_SELF,&sviewer);CHKERRQ(ierr); 613 ierr = MatView(a->A,sviewer);CHKERRQ(ierr); 614 ierr = PetscViewerRestoreSubViewer(viewer,PETSC_COMM_SELF,&sviewer);CHKERRQ(ierr); 615 PetscFunctionReturn(0); 616 } 617 618 #undef __FUNCT__ 619 #define __FUNCT__ "MatSetLocalToGlobalMapping_IS" 620 PetscErrorCode MatSetLocalToGlobalMapping_IS(Mat A,ISLocalToGlobalMapping rmapping,ISLocalToGlobalMapping cmapping) 621 { 622 PetscErrorCode ierr; 623 PetscInt nr,rbs,nc,cbs; 624 Mat_IS *is = (Mat_IS*)A->data; 625 IS from,to; 626 Vec cglobal,rglobal; 627 628 PetscFunctionBegin; 629 PetscCheckSameComm(A,1,rmapping,2); 630 PetscCheckSameComm(A,1,cmapping,3); 631 /* Destroy any previous data */ 632 ierr = VecDestroy(&is->x);CHKERRQ(ierr); 633 ierr = VecDestroy(&is->y);CHKERRQ(ierr); 634 ierr = VecScatterDestroy(&is->rctx);CHKERRQ(ierr); 635 ierr = VecScatterDestroy(&is->cctx);CHKERRQ(ierr); 636 ierr = MatDestroy(&is->A);CHKERRQ(ierr); 637 ierr = PetscSFDestroy(&is->sf);CHKERRQ(ierr); 638 ierr = PetscFree2(is->sf_rootdata,is->sf_leafdata);CHKERRQ(ierr); 639 640 /* Setup Layout and set local to global maps */ 641 ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr); 642 ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr); 643 ierr = PetscLayoutSetISLocalToGlobalMapping(A->rmap,rmapping);CHKERRQ(ierr); 644 ierr = PetscLayoutSetISLocalToGlobalMapping(A->cmap,cmapping);CHKERRQ(ierr); 645 646 /* Create the local matrix A */ 647 ierr = ISLocalToGlobalMappingGetSize(rmapping,&nr);CHKERRQ(ierr); 648 ierr = ISLocalToGlobalMappingGetBlockSize(rmapping,&rbs);CHKERRQ(ierr); 649 ierr = ISLocalToGlobalMappingGetSize(cmapping,&nc);CHKERRQ(ierr); 650 ierr = ISLocalToGlobalMappingGetBlockSize(cmapping,&cbs);CHKERRQ(ierr); 651 ierr = MatCreate(PETSC_COMM_SELF,&is->A);CHKERRQ(ierr); 652 ierr = MatSetType(is->A,MATAIJ);CHKERRQ(ierr); 653 ierr = MatSetSizes(is->A,nr,nc,nr,nc);CHKERRQ(ierr); 654 ierr = MatSetBlockSizes(is->A,rbs,cbs);CHKERRQ(ierr); 655 ierr = MatSetOptionsPrefix(is->A,((PetscObject)A)->prefix);CHKERRQ(ierr); 656 ierr = MatAppendOptionsPrefix(is->A,"is_");CHKERRQ(ierr); 657 ierr = MatSetFromOptions(is->A);CHKERRQ(ierr); 658 659 /* Create the local work vectors */ 660 ierr = MatCreateVecs(is->A,&is->x,&is->y);CHKERRQ(ierr); 661 662 /* setup the global to local scatters */ 663 ierr = MatCreateVecs(A,&cglobal,&rglobal);CHKERRQ(ierr); 664 ierr = ISCreateStride(PETSC_COMM_SELF,nr,0,1,&to);CHKERRQ(ierr); 665 ierr = ISLocalToGlobalMappingApplyIS(rmapping,to,&from);CHKERRQ(ierr); 666 ierr = VecScatterCreate(rglobal,from,is->y,to,&is->rctx);CHKERRQ(ierr); 667 if (rmapping != cmapping) { 668 ierr = ISDestroy(&to);CHKERRQ(ierr); 669 ierr = ISDestroy(&from);CHKERRQ(ierr); 670 ierr = ISCreateStride(PETSC_COMM_SELF,nc,0,1,&to);CHKERRQ(ierr); 671 ierr = ISLocalToGlobalMappingApplyIS(cmapping,to,&from);CHKERRQ(ierr); 672 ierr = VecScatterCreate(cglobal,from,is->x,to,&is->cctx);CHKERRQ(ierr); 673 } else { 674 ierr = PetscObjectReference((PetscObject)is->rctx);CHKERRQ(ierr); 675 is->cctx = is->rctx; 676 } 677 ierr = VecDestroy(&rglobal);CHKERRQ(ierr); 678 ierr = VecDestroy(&cglobal);CHKERRQ(ierr); 679 ierr = ISDestroy(&to);CHKERRQ(ierr); 680 ierr = ISDestroy(&from);CHKERRQ(ierr); 681 PetscFunctionReturn(0); 682 } 683 684 #undef __FUNCT__ 685 #define __FUNCT__ "MatSetValues_IS" 686 PetscErrorCode MatSetValues_IS(Mat mat, PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols, const PetscScalar *values, InsertMode addv) 687 { 688 Mat_IS *is = (Mat_IS*)mat->data; 689 PetscInt rows_l[2048],cols_l[2048]; 690 PetscErrorCode ierr; 691 692 PetscFunctionBegin; 693 #if defined(PETSC_USE_DEBUG) 694 if (m > 2048 || n > 2048) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of row/column indices must be <= 2048: they are %D %D",m,n); 695 #endif 696 ierr = ISG2LMapApply(mat->rmap->mapping,m,rows,rows_l);CHKERRQ(ierr); 697 ierr = ISG2LMapApply(mat->cmap->mapping,n,cols,cols_l);CHKERRQ(ierr); 698 ierr = MatSetValues(is->A,m,rows_l,n,cols_l,values,addv);CHKERRQ(ierr); 699 PetscFunctionReturn(0); 700 } 701 702 #undef __FUNCT__ 703 #define __FUNCT__ "MatSetValuesLocal_IS" 704 PetscErrorCode MatSetValuesLocal_IS(Mat A,PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols,const PetscScalar *values,InsertMode addv) 705 { 706 PetscErrorCode ierr; 707 Mat_IS *is = (Mat_IS*)A->data; 708 709 PetscFunctionBegin; 710 ierr = MatSetValues(is->A,m,rows,n,cols,values,addv);CHKERRQ(ierr); 711 PetscFunctionReturn(0); 712 } 713 714 #undef __FUNCT__ 715 #define __FUNCT__ "MatSetValuesBlockedLocal_IS" 716 PetscErrorCode MatSetValuesBlockedLocal_IS(Mat A,PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols,const PetscScalar *values,InsertMode addv) 717 { 718 PetscErrorCode ierr; 719 Mat_IS *is = (Mat_IS*)A->data; 720 721 PetscFunctionBegin; 722 ierr = MatSetValuesBlocked(is->A,m,rows,n,cols,values,addv);CHKERRQ(ierr); 723 PetscFunctionReturn(0); 724 } 725 726 #undef __FUNCT__ 727 #define __FUNCT__ "MatZeroRows_IS" 728 PetscErrorCode MatZeroRows_IS(Mat A,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b) 729 { 730 PetscInt n_l = 0, *rows_l = NULL; 731 PetscErrorCode ierr; 732 733 PetscFunctionBegin; 734 if (x && b) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"No support"); 735 if (n) { 736 ierr = PetscMalloc1(n,&rows_l);CHKERRQ(ierr); 737 ierr = ISGlobalToLocalMappingApply(A->rmap->mapping,IS_GTOLM_DROP,n,rows,&n_l,rows_l);CHKERRQ(ierr); 738 } 739 ierr = MatZeroRowsLocal(A,n_l,rows_l,diag,x,b);CHKERRQ(ierr); 740 ierr = PetscFree(rows_l);CHKERRQ(ierr); 741 PetscFunctionReturn(0); 742 } 743 744 #undef __FUNCT__ 745 #define __FUNCT__ "MatZeroRowsLocal_IS" 746 PetscErrorCode MatZeroRowsLocal_IS(Mat A,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b) 747 { 748 Mat_IS *is = (Mat_IS*)A->data; 749 PetscErrorCode ierr; 750 PetscInt i; 751 PetscScalar *array; 752 753 PetscFunctionBegin; 754 if (x && b) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"No support"); 755 { 756 /* 757 Set up is->x as a "counting vector". This is in order to MatMult_IS 758 work properly in the interface nodes. 759 */ 760 Vec counter; 761 ierr = MatCreateVecs(A,NULL,&counter);CHKERRQ(ierr); 762 ierr = VecSet(counter,0.);CHKERRQ(ierr); 763 ierr = VecSet(is->y,1.);CHKERRQ(ierr); 764 ierr = VecScatterBegin(is->rctx,is->y,counter,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 765 ierr = VecScatterEnd(is->rctx,is->y,counter,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 766 ierr = VecScatterBegin(is->rctx,counter,is->y,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 767 ierr = VecScatterEnd(is->rctx,counter,is->y,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 768 ierr = VecDestroy(&counter);CHKERRQ(ierr); 769 } 770 if (!n) { 771 is->pure_neumann = PETSC_TRUE; 772 } else { 773 is->pure_neumann = PETSC_FALSE; 774 775 ierr = VecGetArray(is->y,&array);CHKERRQ(ierr); 776 ierr = MatZeroRows(is->A,n,rows,diag,0,0);CHKERRQ(ierr); 777 for (i=0; i<n; i++) { 778 ierr = MatSetValue(is->A,rows[i],rows[i],diag/(array[rows[i]]),INSERT_VALUES);CHKERRQ(ierr); 779 } 780 ierr = MatAssemblyBegin(is->A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 781 ierr = MatAssemblyEnd(is->A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 782 ierr = VecRestoreArray(is->y,&array);CHKERRQ(ierr); 783 } 784 PetscFunctionReturn(0); 785 } 786 787 #undef __FUNCT__ 788 #define __FUNCT__ "MatAssemblyBegin_IS" 789 PetscErrorCode MatAssemblyBegin_IS(Mat A,MatAssemblyType type) 790 { 791 Mat_IS *is = (Mat_IS*)A->data; 792 PetscErrorCode ierr; 793 794 PetscFunctionBegin; 795 ierr = MatAssemblyBegin(is->A,type);CHKERRQ(ierr); 796 PetscFunctionReturn(0); 797 } 798 799 #undef __FUNCT__ 800 #define __FUNCT__ "MatAssemblyEnd_IS" 801 PetscErrorCode MatAssemblyEnd_IS(Mat A,MatAssemblyType type) 802 { 803 Mat_IS *is = (Mat_IS*)A->data; 804 PetscErrorCode ierr; 805 806 PetscFunctionBegin; 807 ierr = MatAssemblyEnd(is->A,type);CHKERRQ(ierr); 808 PetscFunctionReturn(0); 809 } 810 811 #undef __FUNCT__ 812 #define __FUNCT__ "MatISGetLocalMat_IS" 813 PetscErrorCode MatISGetLocalMat_IS(Mat mat,Mat *local) 814 { 815 Mat_IS *is = (Mat_IS*)mat->data; 816 817 PetscFunctionBegin; 818 *local = is->A; 819 PetscFunctionReturn(0); 820 } 821 822 #undef __FUNCT__ 823 #define __FUNCT__ "MatISGetLocalMat" 824 /*@ 825 MatISGetLocalMat - Gets the local matrix stored inside a MATIS matrix. 826 827 Input Parameter: 828 . mat - the matrix 829 830 Output Parameter: 831 . local - the local matrix 832 833 Level: advanced 834 835 Notes: 836 This can be called if you have precomputed the nonzero structure of the 837 matrix and want to provide it to the inner matrix object to improve the performance 838 of the MatSetValues() operation. 839 840 This function does not increase the reference count for the local Mat. Do not destroy it and do not attempt to use 841 your reference after destroying the parent mat. 842 843 .seealso: MATIS 844 @*/ 845 PetscErrorCode MatISGetLocalMat(Mat mat,Mat *local) 846 { 847 PetscErrorCode ierr; 848 849 PetscFunctionBegin; 850 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 851 PetscValidPointer(local,2); 852 ierr = PetscUseMethod(mat,"MatISGetLocalMat_C",(Mat,Mat*),(mat,local));CHKERRQ(ierr); 853 PetscFunctionReturn(0); 854 } 855 856 #undef __FUNCT__ 857 #define __FUNCT__ "MatISSetLocalMat_IS" 858 PetscErrorCode MatISSetLocalMat_IS(Mat mat,Mat local) 859 { 860 Mat_IS *is = (Mat_IS*)mat->data; 861 PetscInt nrows,ncols,orows,ocols; 862 PetscErrorCode ierr; 863 864 PetscFunctionBegin; 865 if (is->A) { 866 ierr = MatGetSize(is->A,&orows,&ocols);CHKERRQ(ierr); 867 ierr = MatGetSize(local,&nrows,&ncols);CHKERRQ(ierr); 868 if (orows != nrows || ocols != ncols) SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Local MATIS matrix should be of size %dx%d (you passed a %dx%d matrix)\n",orows,ocols,nrows,ncols); 869 } 870 ierr = PetscObjectReference((PetscObject)local);CHKERRQ(ierr); 871 ierr = MatDestroy(&is->A);CHKERRQ(ierr); 872 is->A = local; 873 PetscFunctionReturn(0); 874 } 875 876 #undef __FUNCT__ 877 #define __FUNCT__ "MatISSetLocalMat" 878 /*@ 879 MatISSetLocalMat - Replace the local matrix stored inside a MATIS object. 880 881 Input Parameter: 882 . mat - the matrix 883 . local - the local matrix 884 885 Output Parameter: 886 887 Level: advanced 888 889 Notes: 890 This can be called if you have precomputed the local matrix and 891 want to provide it to the matrix object MATIS. 892 893 .seealso: MATIS 894 @*/ 895 PetscErrorCode MatISSetLocalMat(Mat mat,Mat local) 896 { 897 PetscErrorCode ierr; 898 899 PetscFunctionBegin; 900 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 901 PetscValidHeaderSpecific(local,MAT_CLASSID,2); 902 ierr = PetscUseMethod(mat,"MatISSetLocalMat_C",(Mat,Mat),(mat,local));CHKERRQ(ierr); 903 PetscFunctionReturn(0); 904 } 905 906 #undef __FUNCT__ 907 #define __FUNCT__ "MatZeroEntries_IS" 908 PetscErrorCode MatZeroEntries_IS(Mat A) 909 { 910 Mat_IS *a = (Mat_IS*)A->data; 911 PetscErrorCode ierr; 912 913 PetscFunctionBegin; 914 ierr = MatZeroEntries(a->A);CHKERRQ(ierr); 915 PetscFunctionReturn(0); 916 } 917 918 #undef __FUNCT__ 919 #define __FUNCT__ "MatScale_IS" 920 PetscErrorCode MatScale_IS(Mat A,PetscScalar a) 921 { 922 Mat_IS *is = (Mat_IS*)A->data; 923 PetscErrorCode ierr; 924 925 PetscFunctionBegin; 926 ierr = MatScale(is->A,a);CHKERRQ(ierr); 927 PetscFunctionReturn(0); 928 } 929 930 #undef __FUNCT__ 931 #define __FUNCT__ "MatGetDiagonal_IS" 932 PetscErrorCode MatGetDiagonal_IS(Mat A, Vec v) 933 { 934 Mat_IS *is = (Mat_IS*)A->data; 935 PetscErrorCode ierr; 936 937 PetscFunctionBegin; 938 /* get diagonal of the local matrix */ 939 ierr = MatGetDiagonal(is->A,is->y);CHKERRQ(ierr); 940 941 /* scatter diagonal back into global vector */ 942 ierr = VecSet(v,0);CHKERRQ(ierr); 943 ierr = VecScatterBegin(is->rctx,is->y,v,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 944 ierr = VecScatterEnd(is->rctx,is->y,v,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 945 PetscFunctionReturn(0); 946 } 947 948 #undef __FUNCT__ 949 #define __FUNCT__ "MatSetOption_IS" 950 PetscErrorCode MatSetOption_IS(Mat A,MatOption op,PetscBool flg) 951 { 952 Mat_IS *a = (Mat_IS*)A->data; 953 PetscErrorCode ierr; 954 955 PetscFunctionBegin; 956 ierr = MatSetOption(a->A,op,flg);CHKERRQ(ierr); 957 PetscFunctionReturn(0); 958 } 959 960 #undef __FUNCT__ 961 #define __FUNCT__ "MatCreateIS" 962 /*@ 963 MatCreateIS - Creates a "process" unassmembled matrix, it is assembled on each 964 process but not across processes. 965 966 Input Parameters: 967 + comm - MPI communicator that will share the matrix 968 . bs - block size of the matrix 969 . m,n,M,N - local and/or global sizes of the left and right vector used in matrix vector products 970 . rmap - local to global map for rows 971 - cmap - local to global map for cols 972 973 Output Parameter: 974 . A - the resulting matrix 975 976 Level: advanced 977 978 Notes: See MATIS for more details 979 m and n are NOT related to the size of the map, they are the size of the part of the vector owned 980 by that process. The sizes of rmap and cmap define the size of the local matrices. 981 If either rmap or cmap are NULL, than the matrix is assumed to be square 982 983 .seealso: MATIS, MatSetLocalToGlobalMapping() 984 @*/ 985 PetscErrorCode MatCreateIS(MPI_Comm comm,PetscInt bs,PetscInt m,PetscInt n,PetscInt M,PetscInt N,ISLocalToGlobalMapping rmap,ISLocalToGlobalMapping cmap,Mat *A) 986 { 987 PetscErrorCode ierr; 988 989 PetscFunctionBegin; 990 if (!rmap && !cmap) SETERRQ(comm,PETSC_ERR_USER,"You need to provide at least one of the mapping"); 991 ierr = MatCreate(comm,A);CHKERRQ(ierr); 992 ierr = MatSetSizes(*A,m,n,M,N);CHKERRQ(ierr); 993 ierr = MatSetBlockSize(*A,bs);CHKERRQ(ierr); 994 ierr = MatSetType(*A,MATIS);CHKERRQ(ierr); 995 ierr = MatSetUp(*A);CHKERRQ(ierr); 996 if (rmap && cmap) { 997 ierr = MatSetLocalToGlobalMapping(*A,rmap,cmap);CHKERRQ(ierr); 998 } else if (!rmap) { 999 ierr = MatSetLocalToGlobalMapping(*A,cmap,cmap);CHKERRQ(ierr); 1000 } else { 1001 ierr = MatSetLocalToGlobalMapping(*A,rmap,rmap);CHKERRQ(ierr); 1002 } 1003 PetscFunctionReturn(0); 1004 } 1005 1006 /*MC 1007 MATIS - MATIS = "is" - A matrix type to be used for using the non-overlapping domain decomposition type preconditioners (e.g. PCBDDC). 1008 This stores the matrices in globally unassembled form. Each processor 1009 assembles only its local Neumann problem and the parallel matrix vector 1010 product is handled "implicitly". 1011 1012 Operations Provided: 1013 + MatMult() 1014 . MatMultAdd() 1015 . MatMultTranspose() 1016 . MatMultTransposeAdd() 1017 . MatZeroEntries() 1018 . MatSetOption() 1019 . MatZeroRows() 1020 . MatZeroRowsLocal() 1021 . MatSetValues() 1022 . MatSetValuesLocal() 1023 . MatScale() 1024 . MatGetDiagonal() 1025 - MatSetLocalToGlobalMapping() 1026 1027 Options Database Keys: 1028 . -mat_type is - sets the matrix type to "is" during a call to MatSetFromOptions() 1029 1030 Notes: Options prefix for the inner matrix are given by -is_mat_xxx 1031 1032 You must call MatSetLocalToGlobalMapping() before using this matrix type. 1033 1034 You can do matrix preallocation on the local matrix after you obtain it with 1035 MatISGetLocalMat(); otherwise, you could use MatISSetPreallocation() 1036 1037 Level: advanced 1038 1039 .seealso: Mat, MatISGetLocalMat(), MatSetLocalToGlobalMapping(), MatISSetPreallocation(), PCBDDC 1040 1041 M*/ 1042 1043 #undef __FUNCT__ 1044 #define __FUNCT__ "MatCreate_IS" 1045 PETSC_EXTERN PetscErrorCode MatCreate_IS(Mat A) 1046 { 1047 PetscErrorCode ierr; 1048 Mat_IS *b; 1049 1050 PetscFunctionBegin; 1051 ierr = PetscNewLog(A,&b);CHKERRQ(ierr); 1052 A->data = (void*)b; 1053 1054 /* matrix ops */ 1055 ierr = PetscMemzero(A->ops,sizeof(struct _MatOps));CHKERRQ(ierr); 1056 A->ops->mult = MatMult_IS; 1057 A->ops->multadd = MatMultAdd_IS; 1058 A->ops->multtranspose = MatMultTranspose_IS; 1059 A->ops->multtransposeadd = MatMultTransposeAdd_IS; 1060 A->ops->destroy = MatDestroy_IS; 1061 A->ops->setlocaltoglobalmapping = MatSetLocalToGlobalMapping_IS; 1062 A->ops->setvalues = MatSetValues_IS; 1063 A->ops->setvalueslocal = MatSetValuesLocal_IS; 1064 A->ops->setvaluesblockedlocal = MatSetValuesBlockedLocal_IS; 1065 A->ops->zerorows = MatZeroRows_IS; 1066 A->ops->zerorowslocal = MatZeroRowsLocal_IS; 1067 A->ops->assemblybegin = MatAssemblyBegin_IS; 1068 A->ops->assemblyend = MatAssemblyEnd_IS; 1069 A->ops->view = MatView_IS; 1070 A->ops->zeroentries = MatZeroEntries_IS; 1071 A->ops->scale = MatScale_IS; 1072 A->ops->getdiagonal = MatGetDiagonal_IS; 1073 A->ops->setoption = MatSetOption_IS; 1074 A->ops->ishermitian = MatIsHermitian_IS; 1075 A->ops->issymmetric = MatIsSymmetric_IS; 1076 A->ops->duplicate = MatDuplicate_IS; 1077 1078 /* special MATIS functions */ 1079 ierr = PetscObjectComposeFunction((PetscObject)A,"MatISGetLocalMat_C",MatISGetLocalMat_IS);CHKERRQ(ierr); 1080 ierr = PetscObjectComposeFunction((PetscObject)A,"MatISSetLocalMat_C",MatISSetLocalMat_IS);CHKERRQ(ierr); 1081 ierr = PetscObjectComposeFunction((PetscObject)A,"MatISGetMPIXAIJ_C",MatISGetMPIXAIJ_IS);CHKERRQ(ierr); 1082 ierr = PetscObjectComposeFunction((PetscObject)A,"MatISSetPreallocation_C",MatISSetPreallocation_IS);CHKERRQ(ierr); 1083 ierr = PetscObjectChangeTypeName((PetscObject)A,MATIS);CHKERRQ(ierr); 1084 PetscFunctionReturn(0); 1085 } 1086