1 #include <../src/mat/impls/aij/mpi/mpiaij.h> /*I "petscmat.h" I*/ 2 #include <../src/mat/impls/sell/mpi/mpisell.h> /*I "petscmat.h" I*/ 3 #include <petsc/private/vecimpl.h> 4 #include <petsc/private/isimpl.h> 5 #include <petscblaslapack.h> 6 #include <petscsf.h> 7 8 /*MC 9 MATSELL - MATSELL = "sell" - A matrix type to be used for sparse matrices. 10 11 This matrix type is identical to `MATSEQSELL` when constructed with a single process communicator, 12 and `MATMPISELL` otherwise. As a result, for single process communicators, 13 `MatSeqSELLSetPreallocation()` is supported, and similarly `MatMPISELLSetPreallocation()` is supported 14 for communicators controlling multiple processes. It is recommended that you call both of 15 the above preallocation routines for simplicity. 16 17 Options Database Keys: 18 . -mat_type sell - sets the matrix type to `MATSELL` during a call to `MatSetFromOptions()` 19 20 Level: beginner 21 22 .seealso: `Mat`, `MATAIJ`, `MATBAIJ`, `MATSBAIJ`, `MatCreateSELL()`, `MatCreateSeqSELL()`, `MATSEQSELL`, `MATMPISELL` 23 M*/ 24 25 static PetscErrorCode MatDiagonalSet_MPISELL(Mat Y, Vec D, InsertMode is) 26 { 27 Mat_MPISELL *sell = (Mat_MPISELL *)Y->data; 28 29 PetscFunctionBegin; 30 if (Y->assembled && Y->rmap->rstart == Y->cmap->rstart && Y->rmap->rend == Y->cmap->rend) { 31 PetscCall(MatDiagonalSet(sell->A, D, is)); 32 } else { 33 PetscCall(MatDiagonalSet_Default(Y, D, is)); 34 } 35 PetscFunctionReturn(PETSC_SUCCESS); 36 } 37 38 /* 39 Local utility routine that creates a mapping from the global column 40 number to the local number in the off-diagonal part of the local 41 storage of the matrix. When PETSC_USE_CTABLE is used this is scalable at 42 a slightly higher hash table cost; without it it is not scalable (each processor 43 has an order N integer array but is fast to access. 44 */ 45 PetscErrorCode MatCreateColmap_MPISELL_Private(Mat mat) 46 { 47 Mat_MPISELL *sell = (Mat_MPISELL *)mat->data; 48 PetscInt n = sell->B->cmap->n, i; 49 50 PetscFunctionBegin; 51 PetscCheck(sell->garray, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MPISELL Matrix was assembled but is missing garray"); 52 #if defined(PETSC_USE_CTABLE) 53 PetscCall(PetscHMapICreateWithSize(n, &sell->colmap)); 54 for (i = 0; i < n; i++) PetscCall(PetscHMapISet(sell->colmap, sell->garray[i] + 1, i + 1)); 55 #else 56 PetscCall(PetscCalloc1(mat->cmap->N + 1, &sell->colmap)); 57 for (i = 0; i < n; i++) sell->colmap[sell->garray[i]] = i + 1; 58 #endif 59 PetscFunctionReturn(PETSC_SUCCESS); 60 } 61 62 #define MatSetValues_SeqSELL_A_Private(row, col, value, addv, orow, ocol) \ 63 { \ 64 if (col <= lastcol1) low1 = 0; \ 65 else high1 = nrow1; \ 66 lastcol1 = col; \ 67 while (high1 - low1 > 5) { \ 68 t = (low1 + high1) / 2; \ 69 if (cp1[sliceheight * t] > col) high1 = t; \ 70 else low1 = t; \ 71 } \ 72 for (_i = low1; _i < high1; _i++) { \ 73 if (cp1[sliceheight * _i] > col) break; \ 74 if (cp1[sliceheight * _i] == col) { \ 75 if (addv == ADD_VALUES) vp1[sliceheight * _i] += value; \ 76 else vp1[sliceheight * _i] = value; \ 77 inserted = PETSC_TRUE; \ 78 goto a_noinsert; \ 79 } \ 80 } \ 81 if (value == 0.0 && ignorezeroentries) { \ 82 low1 = 0; \ 83 high1 = nrow1; \ 84 goto a_noinsert; \ 85 } \ 86 if (nonew == 1) { \ 87 low1 = 0; \ 88 high1 = nrow1; \ 89 goto a_noinsert; \ 90 } \ 91 PetscCheck(nonew != -1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Inserting a new nonzero at global row/column (%" PetscInt_FMT ", %" PetscInt_FMT ") into matrix", orow, ocol); \ 92 MatSeqXSELLReallocateSELL(A, am, 1, nrow1, a->sliidx, a->sliceheight, row / sliceheight, row, col, a->colidx, a->val, cp1, vp1, nonew, MatScalar); \ 93 /* shift up all the later entries in this row */ \ 94 for (ii = nrow1 - 1; ii >= _i; ii--) { \ 95 cp1[sliceheight * (ii + 1)] = cp1[sliceheight * ii]; \ 96 vp1[sliceheight * (ii + 1)] = vp1[sliceheight * ii]; \ 97 } \ 98 cp1[sliceheight * _i] = col; \ 99 vp1[sliceheight * _i] = value; \ 100 a->nz++; \ 101 nrow1++; \ 102 A->nonzerostate++; \ 103 a_noinsert:; \ 104 a->rlen[row] = nrow1; \ 105 } 106 107 #define MatSetValues_SeqSELL_B_Private(row, col, value, addv, orow, ocol) \ 108 { \ 109 if (col <= lastcol2) low2 = 0; \ 110 else high2 = nrow2; \ 111 lastcol2 = col; \ 112 while (high2 - low2 > 5) { \ 113 t = (low2 + high2) / 2; \ 114 if (cp2[sliceheight * t] > col) high2 = t; \ 115 else low2 = t; \ 116 } \ 117 for (_i = low2; _i < high2; _i++) { \ 118 if (cp2[sliceheight * _i] > col) break; \ 119 if (cp2[sliceheight * _i] == col) { \ 120 if (addv == ADD_VALUES) vp2[sliceheight * _i] += value; \ 121 else vp2[sliceheight * _i] = value; \ 122 inserted = PETSC_TRUE; \ 123 goto b_noinsert; \ 124 } \ 125 } \ 126 if (value == 0.0 && ignorezeroentries) { \ 127 low2 = 0; \ 128 high2 = nrow2; \ 129 goto b_noinsert; \ 130 } \ 131 if (nonew == 1) { \ 132 low2 = 0; \ 133 high2 = nrow2; \ 134 goto b_noinsert; \ 135 } \ 136 PetscCheck(nonew != -1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Inserting a new nonzero at global row/column (%" PetscInt_FMT ", %" PetscInt_FMT ") into matrix", orow, ocol); \ 137 MatSeqXSELLReallocateSELL(B, bm, 1, nrow2, b->sliidx, b->sliceheight, row / sliceheight, row, col, b->colidx, b->val, cp2, vp2, nonew, MatScalar); \ 138 /* shift up all the later entries in this row */ \ 139 for (ii = nrow2 - 1; ii >= _i; ii--) { \ 140 cp2[sliceheight * (ii + 1)] = cp2[sliceheight * ii]; \ 141 vp2[sliceheight * (ii + 1)] = vp2[sliceheight * ii]; \ 142 } \ 143 cp2[sliceheight * _i] = col; \ 144 vp2[sliceheight * _i] = value; \ 145 b->nz++; \ 146 nrow2++; \ 147 B->nonzerostate++; \ 148 b_noinsert:; \ 149 b->rlen[row] = nrow2; \ 150 } 151 152 static PetscErrorCode MatSetValues_MPISELL(Mat mat, PetscInt m, const PetscInt im[], PetscInt n, const PetscInt in[], const PetscScalar v[], InsertMode addv) 153 { 154 Mat_MPISELL *sell = (Mat_MPISELL *)mat->data; 155 PetscScalar value; 156 PetscInt i, j, rstart = mat->rmap->rstart, rend = mat->rmap->rend, shift1, shift2; 157 PetscInt cstart = mat->cmap->rstart, cend = mat->cmap->rend, row, col; 158 PetscBool roworiented = sell->roworiented; 159 160 /* Some Variables required in the macro */ 161 Mat A = sell->A; 162 Mat_SeqSELL *a = (Mat_SeqSELL *)A->data; 163 PetscBool ignorezeroentries = a->ignorezeroentries, found; 164 Mat B = sell->B; 165 Mat_SeqSELL *b = (Mat_SeqSELL *)B->data; 166 PetscInt *cp1, *cp2, ii, _i, nrow1, nrow2, low1, high1, low2, high2, t, lastcol1, lastcol2, sliceheight = a->sliceheight; 167 MatScalar *vp1, *vp2; 168 169 PetscFunctionBegin; 170 for (i = 0; i < m; i++) { 171 if (im[i] < 0) continue; 172 PetscCheck(im[i] < mat->rmap->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Row too large: row %" PetscInt_FMT " max %" PetscInt_FMT, im[i], mat->rmap->N - 1); 173 if (im[i] >= rstart && im[i] < rend) { 174 row = im[i] - rstart; 175 lastcol1 = -1; 176 shift1 = a->sliidx[row / sliceheight] + (row % sliceheight); /* starting index of the row */ 177 cp1 = PetscSafePointerPlusOffset(a->colidx, shift1); 178 vp1 = PetscSafePointerPlusOffset(a->val, shift1); 179 nrow1 = a->rlen[row]; 180 low1 = 0; 181 high1 = nrow1; 182 lastcol2 = -1; 183 shift2 = b->sliidx[row / sliceheight] + (row % sliceheight); /* starting index of the row */ 184 cp2 = PetscSafePointerPlusOffset(b->colidx, shift2); 185 vp2 = PetscSafePointerPlusOffset(b->val, shift2); 186 nrow2 = b->rlen[row]; 187 low2 = 0; 188 high2 = nrow2; 189 190 for (j = 0; j < n; j++) { 191 if (roworiented) value = v[i * n + j]; 192 else value = v[i + j * m]; 193 if (ignorezeroentries && value == 0.0 && (addv == ADD_VALUES)) continue; 194 if (in[j] >= cstart && in[j] < cend) { 195 col = in[j] - cstart; 196 MatSetValue_SeqSELL_Private(A, row, col, value, addv, im[i], in[j], cp1, vp1, lastcol1, low1, high1); /* set one value */ 197 #if defined(PETSC_HAVE_CUDA) 198 if (A->offloadmask != PETSC_OFFLOAD_UNALLOCATED && found) A->offloadmask = PETSC_OFFLOAD_CPU; 199 #endif 200 } else if (in[j] < 0) { 201 continue; 202 } else { 203 PetscCheck(in[j] < mat->cmap->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Column too large: col %" PetscInt_FMT " max %" PetscInt_FMT, in[j], mat->cmap->N - 1); 204 if (mat->was_assembled) { 205 if (!sell->colmap) PetscCall(MatCreateColmap_MPISELL_Private(mat)); 206 #if defined(PETSC_USE_CTABLE) 207 PetscCall(PetscHMapIGetWithDefault(sell->colmap, in[j] + 1, 0, &col)); 208 col--; 209 #else 210 col = sell->colmap[in[j]] - 1; 211 #endif 212 if (col < 0 && !((Mat_SeqSELL *)sell->B->data)->nonew) { 213 PetscCall(MatDisAssemble_MPISELL(mat)); 214 col = in[j]; 215 /* Reinitialize the variables required by MatSetValues_SeqSELL_B_Private() */ 216 B = sell->B; 217 b = (Mat_SeqSELL *)B->data; 218 shift2 = b->sliidx[row / sliceheight] + (row % sliceheight); /* starting index of the row */ 219 cp2 = b->colidx + shift2; 220 vp2 = b->val + shift2; 221 nrow2 = b->rlen[row]; 222 low2 = 0; 223 high2 = nrow2; 224 found = PETSC_FALSE; 225 } else { 226 PetscCheck(col >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Inserting a new nonzero at global row/column (%" PetscInt_FMT ", %" PetscInt_FMT ") into matrix", im[i], in[j]); 227 } 228 } else col = in[j]; 229 MatSetValue_SeqSELL_Private(B, row, col, value, addv, im[i], in[j], cp2, vp2, lastcol2, low2, high2); /* set one value */ 230 #if defined(PETSC_HAVE_CUDA) 231 if (B->offloadmask != PETSC_OFFLOAD_UNALLOCATED && found) B->offloadmask = PETSC_OFFLOAD_CPU; 232 #endif 233 } 234 } 235 } else { 236 PetscCheck(!mat->nooffprocentries, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Setting off process row %" PetscInt_FMT " even though MatSetOption(,MAT_NO_OFF_PROC_ENTRIES,PETSC_TRUE) was set", im[i]); 237 if (!sell->donotstash) { 238 mat->assembled = PETSC_FALSE; 239 if (roworiented) { 240 PetscCall(MatStashValuesRow_Private(&mat->stash, im[i], n, in, v + i * n, (PetscBool)(ignorezeroentries && (addv == ADD_VALUES)))); 241 } else { 242 PetscCall(MatStashValuesCol_Private(&mat->stash, im[i], n, in, v + i, m, (PetscBool)(ignorezeroentries && (addv == ADD_VALUES)))); 243 } 244 } 245 } 246 } 247 PetscFunctionReturn(PETSC_SUCCESS); 248 } 249 250 static PetscErrorCode MatGetValues_MPISELL(Mat mat, PetscInt m, const PetscInt idxm[], PetscInt n, const PetscInt idxn[], PetscScalar v[]) 251 { 252 Mat_MPISELL *sell = (Mat_MPISELL *)mat->data; 253 PetscInt i, j, rstart = mat->rmap->rstart, rend = mat->rmap->rend; 254 PetscInt cstart = mat->cmap->rstart, cend = mat->cmap->rend, row, col; 255 256 PetscFunctionBegin; 257 for (i = 0; i < m; i++) { 258 if (idxm[i] < 0) continue; /* negative row */ 259 PetscCheck(idxm[i] < mat->rmap->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Row too large: row %" PetscInt_FMT " max %" PetscInt_FMT, idxm[i], mat->rmap->N - 1); 260 if (idxm[i] >= rstart && idxm[i] < rend) { 261 row = idxm[i] - rstart; 262 for (j = 0; j < n; j++) { 263 if (idxn[j] < 0) continue; /* negative column */ 264 PetscCheck(idxn[j] < mat->cmap->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Column too large: col %" PetscInt_FMT " max %" PetscInt_FMT, idxn[j], mat->cmap->N - 1); 265 if (idxn[j] >= cstart && idxn[j] < cend) { 266 col = idxn[j] - cstart; 267 PetscCall(MatGetValues(sell->A, 1, &row, 1, &col, v + i * n + j)); 268 } else { 269 if (!sell->colmap) PetscCall(MatCreateColmap_MPISELL_Private(mat)); 270 #if defined(PETSC_USE_CTABLE) 271 PetscCall(PetscHMapIGetWithDefault(sell->colmap, idxn[j] + 1, 0, &col)); 272 col--; 273 #else 274 col = sell->colmap[idxn[j]] - 1; 275 #endif 276 if ((col < 0) || (sell->garray[col] != idxn[j])) *(v + i * n + j) = 0.0; 277 else PetscCall(MatGetValues(sell->B, 1, &row, 1, &col, v + i * n + j)); 278 } 279 } 280 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Only local values currently supported"); 281 } 282 PetscFunctionReturn(PETSC_SUCCESS); 283 } 284 285 static PetscErrorCode MatAssemblyBegin_MPISELL(Mat mat, MatAssemblyType mode) 286 { 287 Mat_MPISELL *sell = (Mat_MPISELL *)mat->data; 288 PetscInt nstash, reallocs; 289 290 PetscFunctionBegin; 291 if (sell->donotstash || mat->nooffprocentries) PetscFunctionReturn(PETSC_SUCCESS); 292 293 PetscCall(MatStashScatterBegin_Private(mat, &mat->stash, mat->rmap->range)); 294 PetscCall(MatStashGetInfo_Private(&mat->stash, &nstash, &reallocs)); 295 PetscCall(PetscInfo(sell->A, "Stash has %" PetscInt_FMT " entries, uses %" PetscInt_FMT " mallocs.\n", nstash, reallocs)); 296 PetscFunctionReturn(PETSC_SUCCESS); 297 } 298 299 PetscErrorCode MatAssemblyEnd_MPISELL(Mat mat, MatAssemblyType mode) 300 { 301 Mat_MPISELL *sell = (Mat_MPISELL *)mat->data; 302 PetscMPIInt n; 303 PetscInt i, flg; 304 PetscInt *row, *col; 305 PetscScalar *val; 306 PetscBool other_disassembled; 307 /* do not use 'b = (Mat_SeqSELL*)sell->B->data' as B can be reset in disassembly */ 308 PetscFunctionBegin; 309 if (!sell->donotstash && !mat->nooffprocentries) { 310 while (1) { 311 PetscCall(MatStashScatterGetMesg_Private(&mat->stash, &n, &row, &col, &val, &flg)); 312 if (!flg) break; 313 314 for (i = 0; i < n; i++) { /* assemble one by one */ 315 PetscCall(MatSetValues_MPISELL(mat, 1, row + i, 1, col + i, val + i, mat->insertmode)); 316 } 317 } 318 PetscCall(MatStashScatterEnd_Private(&mat->stash)); 319 } 320 #if defined(PETSC_HAVE_CUDA) 321 if (mat->offloadmask == PETSC_OFFLOAD_CPU) sell->A->offloadmask = PETSC_OFFLOAD_CPU; 322 #endif 323 PetscCall(MatAssemblyBegin(sell->A, mode)); 324 PetscCall(MatAssemblyEnd(sell->A, mode)); 325 326 /* 327 determine if any processor has disassembled, if so we must 328 also disassemble ourselves, in order that we may reassemble. 329 */ 330 /* 331 if nonzero structure of submatrix B cannot change then we know that 332 no processor disassembled thus we can skip this stuff 333 */ 334 if (!((Mat_SeqSELL *)sell->B->data)->nonew) { 335 PetscCall(MPIU_Allreduce(&mat->was_assembled, &other_disassembled, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)mat))); 336 if (mat->was_assembled && !other_disassembled) PetscCall(MatDisAssemble_MPISELL(mat)); 337 } 338 if (!mat->was_assembled && mode == MAT_FINAL_ASSEMBLY) PetscCall(MatSetUpMultiply_MPISELL(mat)); 339 #if defined(PETSC_HAVE_CUDA) 340 if (mat->offloadmask == PETSC_OFFLOAD_CPU && sell->B->offloadmask != PETSC_OFFLOAD_UNALLOCATED) sell->B->offloadmask = PETSC_OFFLOAD_CPU; 341 #endif 342 PetscCall(MatAssemblyBegin(sell->B, mode)); 343 PetscCall(MatAssemblyEnd(sell->B, mode)); 344 PetscCall(PetscFree2(sell->rowvalues, sell->rowindices)); 345 sell->rowvalues = NULL; 346 PetscCall(VecDestroy(&sell->diag)); 347 348 /* if no new nonzero locations are allowed in matrix then only set the matrix state the first time through */ 349 if ((!mat->was_assembled && mode == MAT_FINAL_ASSEMBLY) || !((Mat_SeqSELL *)sell->A->data)->nonew) { 350 PetscObjectState state = sell->A->nonzerostate + sell->B->nonzerostate; 351 PetscCall(MPIU_Allreduce(&state, &mat->nonzerostate, 1, MPIU_INT64, MPI_SUM, PetscObjectComm((PetscObject)mat))); 352 } 353 #if defined(PETSC_HAVE_CUDA) 354 mat->offloadmask = PETSC_OFFLOAD_BOTH; 355 #endif 356 PetscFunctionReturn(PETSC_SUCCESS); 357 } 358 359 static PetscErrorCode MatZeroEntries_MPISELL(Mat A) 360 { 361 Mat_MPISELL *l = (Mat_MPISELL *)A->data; 362 363 PetscFunctionBegin; 364 PetscCall(MatZeroEntries(l->A)); 365 PetscCall(MatZeroEntries(l->B)); 366 PetscFunctionReturn(PETSC_SUCCESS); 367 } 368 369 static PetscErrorCode MatMult_MPISELL(Mat A, Vec xx, Vec yy) 370 { 371 Mat_MPISELL *a = (Mat_MPISELL *)A->data; 372 PetscInt nt; 373 374 PetscFunctionBegin; 375 PetscCall(VecGetLocalSize(xx, &nt)); 376 PetscCheck(nt == A->cmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Incompatible partition of A (%" PetscInt_FMT ") and xx (%" PetscInt_FMT ")", A->cmap->n, nt); 377 PetscCall(VecScatterBegin(a->Mvctx, xx, a->lvec, INSERT_VALUES, SCATTER_FORWARD)); 378 PetscCall((*a->A->ops->mult)(a->A, xx, yy)); 379 PetscCall(VecScatterEnd(a->Mvctx, xx, a->lvec, INSERT_VALUES, SCATTER_FORWARD)); 380 PetscCall((*a->B->ops->multadd)(a->B, a->lvec, yy, yy)); 381 PetscFunctionReturn(PETSC_SUCCESS); 382 } 383 384 static PetscErrorCode MatMultDiagonalBlock_MPISELL(Mat A, Vec bb, Vec xx) 385 { 386 Mat_MPISELL *a = (Mat_MPISELL *)A->data; 387 388 PetscFunctionBegin; 389 PetscCall(MatMultDiagonalBlock(a->A, bb, xx)); 390 PetscFunctionReturn(PETSC_SUCCESS); 391 } 392 393 static PetscErrorCode MatMultAdd_MPISELL(Mat A, Vec xx, Vec yy, Vec zz) 394 { 395 Mat_MPISELL *a = (Mat_MPISELL *)A->data; 396 397 PetscFunctionBegin; 398 PetscCall(VecScatterBegin(a->Mvctx, xx, a->lvec, INSERT_VALUES, SCATTER_FORWARD)); 399 PetscCall((*a->A->ops->multadd)(a->A, xx, yy, zz)); 400 PetscCall(VecScatterEnd(a->Mvctx, xx, a->lvec, INSERT_VALUES, SCATTER_FORWARD)); 401 PetscCall((*a->B->ops->multadd)(a->B, a->lvec, zz, zz)); 402 PetscFunctionReturn(PETSC_SUCCESS); 403 } 404 405 static PetscErrorCode MatMultTranspose_MPISELL(Mat A, Vec xx, Vec yy) 406 { 407 Mat_MPISELL *a = (Mat_MPISELL *)A->data; 408 409 PetscFunctionBegin; 410 /* do nondiagonal part */ 411 PetscCall((*a->B->ops->multtranspose)(a->B, xx, a->lvec)); 412 /* do local part */ 413 PetscCall((*a->A->ops->multtranspose)(a->A, xx, yy)); 414 /* add partial results together */ 415 PetscCall(VecScatterBegin(a->Mvctx, a->lvec, yy, ADD_VALUES, SCATTER_REVERSE)); 416 PetscCall(VecScatterEnd(a->Mvctx, a->lvec, yy, ADD_VALUES, SCATTER_REVERSE)); 417 PetscFunctionReturn(PETSC_SUCCESS); 418 } 419 420 static PetscErrorCode MatIsTranspose_MPISELL(Mat Amat, Mat Bmat, PetscReal tol, PetscBool *f) 421 { 422 MPI_Comm comm; 423 Mat_MPISELL *Asell = (Mat_MPISELL *)Amat->data, *Bsell; 424 Mat Adia = Asell->A, Bdia, Aoff, Boff, *Aoffs, *Boffs; 425 IS Me, Notme; 426 PetscInt M, N, first, last, *notme, i; 427 PetscMPIInt size; 428 429 PetscFunctionBegin; 430 /* Easy test: symmetric diagonal block */ 431 Bsell = (Mat_MPISELL *)Bmat->data; 432 Bdia = Bsell->A; 433 PetscCall(MatIsTranspose(Adia, Bdia, tol, f)); 434 if (!*f) PetscFunctionReturn(PETSC_SUCCESS); 435 PetscCall(PetscObjectGetComm((PetscObject)Amat, &comm)); 436 PetscCallMPI(MPI_Comm_size(comm, &size)); 437 if (size == 1) PetscFunctionReturn(PETSC_SUCCESS); 438 439 /* Hard test: off-diagonal block. This takes a MatCreateSubMatrix. */ 440 PetscCall(MatGetSize(Amat, &M, &N)); 441 PetscCall(MatGetOwnershipRange(Amat, &first, &last)); 442 PetscCall(PetscMalloc1(N - last + first, ¬me)); 443 for (i = 0; i < first; i++) notme[i] = i; 444 for (i = last; i < M; i++) notme[i - last + first] = i; 445 PetscCall(ISCreateGeneral(MPI_COMM_SELF, N - last + first, notme, PETSC_COPY_VALUES, &Notme)); 446 PetscCall(ISCreateStride(MPI_COMM_SELF, last - first, first, 1, &Me)); 447 PetscCall(MatCreateSubMatrices(Amat, 1, &Me, &Notme, MAT_INITIAL_MATRIX, &Aoffs)); 448 Aoff = Aoffs[0]; 449 PetscCall(MatCreateSubMatrices(Bmat, 1, &Notme, &Me, MAT_INITIAL_MATRIX, &Boffs)); 450 Boff = Boffs[0]; 451 PetscCall(MatIsTranspose(Aoff, Boff, tol, f)); 452 PetscCall(MatDestroyMatrices(1, &Aoffs)); 453 PetscCall(MatDestroyMatrices(1, &Boffs)); 454 PetscCall(ISDestroy(&Me)); 455 PetscCall(ISDestroy(&Notme)); 456 PetscCall(PetscFree(notme)); 457 PetscFunctionReturn(PETSC_SUCCESS); 458 } 459 460 static PetscErrorCode MatMultTransposeAdd_MPISELL(Mat A, Vec xx, Vec yy, Vec zz) 461 { 462 Mat_MPISELL *a = (Mat_MPISELL *)A->data; 463 464 PetscFunctionBegin; 465 /* do nondiagonal part */ 466 PetscCall((*a->B->ops->multtranspose)(a->B, xx, a->lvec)); 467 /* do local part */ 468 PetscCall((*a->A->ops->multtransposeadd)(a->A, xx, yy, zz)); 469 /* add partial results together */ 470 PetscCall(VecScatterBegin(a->Mvctx, a->lvec, zz, ADD_VALUES, SCATTER_REVERSE)); 471 PetscCall(VecScatterEnd(a->Mvctx, a->lvec, zz, ADD_VALUES, SCATTER_REVERSE)); 472 PetscFunctionReturn(PETSC_SUCCESS); 473 } 474 475 /* 476 This only works correctly for square matrices where the subblock A->A is the 477 diagonal block 478 */ 479 static PetscErrorCode MatGetDiagonal_MPISELL(Mat A, Vec v) 480 { 481 Mat_MPISELL *a = (Mat_MPISELL *)A->data; 482 483 PetscFunctionBegin; 484 PetscCheck(A->rmap->N == A->cmap->N, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Supports only square matrix where A->A is diag block"); 485 PetscCheck(A->rmap->rstart == A->cmap->rstart && A->rmap->rend == A->cmap->rend, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "row partition must equal col partition"); 486 PetscCall(MatGetDiagonal(a->A, v)); 487 PetscFunctionReturn(PETSC_SUCCESS); 488 } 489 490 static PetscErrorCode MatScale_MPISELL(Mat A, PetscScalar aa) 491 { 492 Mat_MPISELL *a = (Mat_MPISELL *)A->data; 493 494 PetscFunctionBegin; 495 PetscCall(MatScale(a->A, aa)); 496 PetscCall(MatScale(a->B, aa)); 497 PetscFunctionReturn(PETSC_SUCCESS); 498 } 499 500 PetscErrorCode MatDestroy_MPISELL(Mat mat) 501 { 502 Mat_MPISELL *sell = (Mat_MPISELL *)mat->data; 503 504 PetscFunctionBegin; 505 PetscCall(PetscLogObjectState((PetscObject)mat, "Rows=%" PetscInt_FMT ", Cols=%" PetscInt_FMT, mat->rmap->N, mat->cmap->N)); 506 PetscCall(MatStashDestroy_Private(&mat->stash)); 507 PetscCall(VecDestroy(&sell->diag)); 508 PetscCall(MatDestroy(&sell->A)); 509 PetscCall(MatDestroy(&sell->B)); 510 #if defined(PETSC_USE_CTABLE) 511 PetscCall(PetscHMapIDestroy(&sell->colmap)); 512 #else 513 PetscCall(PetscFree(sell->colmap)); 514 #endif 515 PetscCall(PetscFree(sell->garray)); 516 PetscCall(VecDestroy(&sell->lvec)); 517 PetscCall(VecScatterDestroy(&sell->Mvctx)); 518 PetscCall(PetscFree2(sell->rowvalues, sell->rowindices)); 519 PetscCall(PetscFree(sell->ld)); 520 PetscCall(PetscFree(mat->data)); 521 522 PetscCall(PetscObjectChangeTypeName((PetscObject)mat, NULL)); 523 PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatStoreValues_C", NULL)); 524 PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatRetrieveValues_C", NULL)); 525 PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatIsTranspose_C", NULL)); 526 PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMPISELLSetPreallocation_C", NULL)); 527 PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatConvert_mpisell_mpiaij_C", NULL)); 528 #if defined(PETSC_HAVE_CUDA) 529 PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatConvert_mpisell_mpisellcuda_C", NULL)); 530 #endif 531 PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDiagonalScaleLocal_C", NULL)); 532 PetscFunctionReturn(PETSC_SUCCESS); 533 } 534 535 #include <petscdraw.h> 536 static PetscErrorCode MatView_MPISELL_ASCIIorDraworSocket(Mat mat, PetscViewer viewer) 537 { 538 Mat_MPISELL *sell = (Mat_MPISELL *)mat->data; 539 PetscMPIInt rank = sell->rank, size = sell->size; 540 PetscBool isdraw, iascii, isbinary; 541 PetscViewer sviewer; 542 PetscViewerFormat format; 543 544 PetscFunctionBegin; 545 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 546 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 547 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary)); 548 if (iascii) { 549 PetscCall(PetscViewerGetFormat(viewer, &format)); 550 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 551 MatInfo info; 552 PetscInt *inodes; 553 554 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)mat), &rank)); 555 PetscCall(MatGetInfo(mat, MAT_LOCAL, &info)); 556 PetscCall(MatInodeGetInodeSizes(sell->A, NULL, &inodes, NULL)); 557 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 558 if (!inodes) { 559 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Local rows %" PetscInt_FMT " nz %" PetscInt_FMT " nz alloced %" PetscInt_FMT " mem %" PetscInt_FMT ", not using I-node routines\n", rank, mat->rmap->n, (PetscInt)info.nz_used, 560 (PetscInt)info.nz_allocated, (PetscInt)info.memory)); 561 } else { 562 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Local rows %" PetscInt_FMT " nz %" PetscInt_FMT " nz alloced %" PetscInt_FMT " mem %" PetscInt_FMT ", using I-node routines\n", rank, mat->rmap->n, (PetscInt)info.nz_used, 563 (PetscInt)info.nz_allocated, (PetscInt)info.memory)); 564 } 565 PetscCall(MatGetInfo(sell->A, MAT_LOCAL, &info)); 566 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] on-diagonal part: nz %" PetscInt_FMT " \n", rank, (PetscInt)info.nz_used)); 567 PetscCall(MatGetInfo(sell->B, MAT_LOCAL, &info)); 568 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] off-diagonal part: nz %" PetscInt_FMT " \n", rank, (PetscInt)info.nz_used)); 569 PetscCall(PetscViewerFlush(viewer)); 570 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 571 PetscCall(PetscViewerASCIIPrintf(viewer, "Information on VecScatter used in matrix-vector product: \n")); 572 PetscCall(VecScatterView(sell->Mvctx, viewer)); 573 PetscFunctionReturn(PETSC_SUCCESS); 574 } else if (format == PETSC_VIEWER_ASCII_INFO) { 575 PetscInt inodecount, inodelimit, *inodes; 576 PetscCall(MatInodeGetInodeSizes(sell->A, &inodecount, &inodes, &inodelimit)); 577 if (inodes) { 578 PetscCall(PetscViewerASCIIPrintf(viewer, "using I-node (on process 0) routines: found %" PetscInt_FMT " nodes, limit used is %" PetscInt_FMT "\n", inodecount, inodelimit)); 579 } else { 580 PetscCall(PetscViewerASCIIPrintf(viewer, "not using I-node (on process 0) routines\n")); 581 } 582 PetscFunctionReturn(PETSC_SUCCESS); 583 } else if (format == PETSC_VIEWER_ASCII_FACTOR_INFO) { 584 PetscFunctionReturn(PETSC_SUCCESS); 585 } 586 } else if (isbinary) { 587 if (size == 1) { 588 PetscCall(PetscObjectSetName((PetscObject)sell->A, ((PetscObject)mat)->name)); 589 PetscCall(MatView(sell->A, viewer)); 590 } else { 591 /* PetscCall(MatView_MPISELL_Binary(mat,viewer)); */ 592 } 593 PetscFunctionReturn(PETSC_SUCCESS); 594 } else if (isdraw) { 595 PetscDraw draw; 596 PetscBool isnull; 597 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 598 PetscCall(PetscDrawIsNull(draw, &isnull)); 599 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 600 } 601 602 { 603 /* assemble the entire matrix onto first processor. */ 604 Mat A; 605 Mat_SeqSELL *Aloc; 606 PetscInt M = mat->rmap->N, N = mat->cmap->N, *acolidx, row, col, i, j; 607 MatScalar *aval; 608 PetscBool isnonzero; 609 610 PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &A)); 611 if (rank == 0) { 612 PetscCall(MatSetSizes(A, M, N, M, N)); 613 } else { 614 PetscCall(MatSetSizes(A, 0, 0, M, N)); 615 } 616 /* This is just a temporary matrix, so explicitly using MATMPISELL is probably best */ 617 PetscCall(MatSetType(A, MATMPISELL)); 618 PetscCall(MatMPISELLSetPreallocation(A, 0, NULL, 0, NULL)); 619 PetscCall(MatSetOption(A, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_FALSE)); 620 621 /* copy over the A part */ 622 Aloc = (Mat_SeqSELL *)sell->A->data; 623 acolidx = Aloc->colidx; 624 aval = Aloc->val; 625 for (i = 0; i < Aloc->totalslices; i++) { /* loop over slices */ 626 for (j = Aloc->sliidx[i]; j < Aloc->sliidx[i + 1]; j++) { 627 isnonzero = (PetscBool)((j - Aloc->sliidx[i]) / Aloc->sliceheight < Aloc->rlen[i * Aloc->sliceheight + j % Aloc->sliceheight]); 628 if (isnonzero) { /* check the mask bit */ 629 row = i * Aloc->sliceheight + j % Aloc->sliceheight + mat->rmap->rstart; 630 col = *acolidx + mat->rmap->rstart; 631 PetscCall(MatSetValues(A, 1, &row, 1, &col, aval, INSERT_VALUES)); 632 } 633 aval++; 634 acolidx++; 635 } 636 } 637 638 /* copy over the B part */ 639 Aloc = (Mat_SeqSELL *)sell->B->data; 640 acolidx = Aloc->colidx; 641 aval = Aloc->val; 642 for (i = 0; i < Aloc->totalslices; i++) { 643 for (j = Aloc->sliidx[i]; j < Aloc->sliidx[i + 1]; j++) { 644 isnonzero = (PetscBool)((j - Aloc->sliidx[i]) / Aloc->sliceheight < Aloc->rlen[i * Aloc->sliceheight + j % Aloc->sliceheight]); 645 if (isnonzero) { 646 row = i * Aloc->sliceheight + j % Aloc->sliceheight + mat->rmap->rstart; 647 col = sell->garray[*acolidx]; 648 PetscCall(MatSetValues(A, 1, &row, 1, &col, aval, INSERT_VALUES)); 649 } 650 aval++; 651 acolidx++; 652 } 653 } 654 655 PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY)); 656 PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY)); 657 /* 658 Everyone has to call to draw the matrix since the graphics waits are 659 synchronized across all processors that share the PetscDraw object 660 */ 661 PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer)); 662 if (rank == 0) { 663 PetscCall(PetscObjectSetName((PetscObject)((Mat_MPISELL *)A->data)->A, ((PetscObject)mat)->name)); 664 PetscCall(MatView_SeqSELL(((Mat_MPISELL *)A->data)->A, sviewer)); 665 } 666 PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer)); 667 PetscCall(MatDestroy(&A)); 668 } 669 PetscFunctionReturn(PETSC_SUCCESS); 670 } 671 672 static PetscErrorCode MatView_MPISELL(Mat mat, PetscViewer viewer) 673 { 674 PetscBool iascii, isdraw, issocket, isbinary; 675 676 PetscFunctionBegin; 677 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 678 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 679 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary)); 680 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSOCKET, &issocket)); 681 if (iascii || isdraw || isbinary || issocket) PetscCall(MatView_MPISELL_ASCIIorDraworSocket(mat, viewer)); 682 PetscFunctionReturn(PETSC_SUCCESS); 683 } 684 685 static PetscErrorCode MatGetGhosts_MPISELL(Mat mat, PetscInt *nghosts, const PetscInt *ghosts[]) 686 { 687 Mat_MPISELL *sell = (Mat_MPISELL *)mat->data; 688 689 PetscFunctionBegin; 690 PetscCall(MatGetSize(sell->B, NULL, nghosts)); 691 if (ghosts) *ghosts = sell->garray; 692 PetscFunctionReturn(PETSC_SUCCESS); 693 } 694 695 static PetscErrorCode MatGetInfo_MPISELL(Mat matin, MatInfoType flag, MatInfo *info) 696 { 697 Mat_MPISELL *mat = (Mat_MPISELL *)matin->data; 698 Mat A = mat->A, B = mat->B; 699 PetscLogDouble isend[5], irecv[5]; 700 701 PetscFunctionBegin; 702 info->block_size = 1.0; 703 PetscCall(MatGetInfo(A, MAT_LOCAL, info)); 704 705 isend[0] = info->nz_used; 706 isend[1] = info->nz_allocated; 707 isend[2] = info->nz_unneeded; 708 isend[3] = info->memory; 709 isend[4] = info->mallocs; 710 711 PetscCall(MatGetInfo(B, MAT_LOCAL, info)); 712 713 isend[0] += info->nz_used; 714 isend[1] += info->nz_allocated; 715 isend[2] += info->nz_unneeded; 716 isend[3] += info->memory; 717 isend[4] += info->mallocs; 718 if (flag == MAT_LOCAL) { 719 info->nz_used = isend[0]; 720 info->nz_allocated = isend[1]; 721 info->nz_unneeded = isend[2]; 722 info->memory = isend[3]; 723 info->mallocs = isend[4]; 724 } else if (flag == MAT_GLOBAL_MAX) { 725 PetscCall(MPIU_Allreduce(isend, irecv, 5, MPIU_PETSCLOGDOUBLE, MPI_MAX, PetscObjectComm((PetscObject)matin))); 726 727 info->nz_used = irecv[0]; 728 info->nz_allocated = irecv[1]; 729 info->nz_unneeded = irecv[2]; 730 info->memory = irecv[3]; 731 info->mallocs = irecv[4]; 732 } else if (flag == MAT_GLOBAL_SUM) { 733 PetscCall(MPIU_Allreduce(isend, irecv, 5, MPIU_PETSCLOGDOUBLE, MPI_SUM, PetscObjectComm((PetscObject)matin))); 734 735 info->nz_used = irecv[0]; 736 info->nz_allocated = irecv[1]; 737 info->nz_unneeded = irecv[2]; 738 info->memory = irecv[3]; 739 info->mallocs = irecv[4]; 740 } 741 info->fill_ratio_given = 0; /* no parallel LU/ILU/Cholesky */ 742 info->fill_ratio_needed = 0; 743 info->factor_mallocs = 0; 744 PetscFunctionReturn(PETSC_SUCCESS); 745 } 746 747 static PetscErrorCode MatSetOption_MPISELL(Mat A, MatOption op, PetscBool flg) 748 { 749 Mat_MPISELL *a = (Mat_MPISELL *)A->data; 750 751 PetscFunctionBegin; 752 switch (op) { 753 case MAT_NEW_NONZERO_LOCATIONS: 754 case MAT_NEW_NONZERO_ALLOCATION_ERR: 755 case MAT_UNUSED_NONZERO_LOCATION_ERR: 756 case MAT_KEEP_NONZERO_PATTERN: 757 case MAT_NEW_NONZERO_LOCATION_ERR: 758 case MAT_USE_INODES: 759 case MAT_IGNORE_ZERO_ENTRIES: 760 MatCheckPreallocated(A, 1); 761 PetscCall(MatSetOption(a->A, op, flg)); 762 PetscCall(MatSetOption(a->B, op, flg)); 763 break; 764 case MAT_ROW_ORIENTED: 765 MatCheckPreallocated(A, 1); 766 a->roworiented = flg; 767 768 PetscCall(MatSetOption(a->A, op, flg)); 769 PetscCall(MatSetOption(a->B, op, flg)); 770 break; 771 case MAT_FORCE_DIAGONAL_ENTRIES: 772 case MAT_SORTED_FULL: 773 PetscCall(PetscInfo(A, "Option %s ignored\n", MatOptions[op])); 774 break; 775 case MAT_IGNORE_OFF_PROC_ENTRIES: 776 a->donotstash = flg; 777 break; 778 case MAT_SPD: 779 case MAT_SPD_ETERNAL: 780 break; 781 case MAT_SYMMETRIC: 782 MatCheckPreallocated(A, 1); 783 PetscCall(MatSetOption(a->A, op, flg)); 784 break; 785 case MAT_STRUCTURALLY_SYMMETRIC: 786 MatCheckPreallocated(A, 1); 787 PetscCall(MatSetOption(a->A, op, flg)); 788 break; 789 case MAT_HERMITIAN: 790 MatCheckPreallocated(A, 1); 791 PetscCall(MatSetOption(a->A, op, flg)); 792 break; 793 case MAT_SYMMETRY_ETERNAL: 794 MatCheckPreallocated(A, 1); 795 PetscCall(MatSetOption(a->A, op, flg)); 796 break; 797 case MAT_STRUCTURAL_SYMMETRY_ETERNAL: 798 MatCheckPreallocated(A, 1); 799 PetscCall(MatSetOption(a->A, op, flg)); 800 break; 801 default: 802 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "unknown option %d", op); 803 } 804 PetscFunctionReturn(PETSC_SUCCESS); 805 } 806 807 static PetscErrorCode MatDiagonalScale_MPISELL(Mat mat, Vec ll, Vec rr) 808 { 809 Mat_MPISELL *sell = (Mat_MPISELL *)mat->data; 810 Mat a = sell->A, b = sell->B; 811 PetscInt s1, s2, s3; 812 813 PetscFunctionBegin; 814 PetscCall(MatGetLocalSize(mat, &s2, &s3)); 815 if (rr) { 816 PetscCall(VecGetLocalSize(rr, &s1)); 817 PetscCheck(s1 == s3, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "right vector non-conforming local size"); 818 /* Overlap communication with computation. */ 819 PetscCall(VecScatterBegin(sell->Mvctx, rr, sell->lvec, INSERT_VALUES, SCATTER_FORWARD)); 820 } 821 if (ll) { 822 PetscCall(VecGetLocalSize(ll, &s1)); 823 PetscCheck(s1 == s2, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "left vector non-conforming local size"); 824 PetscUseTypeMethod(b, diagonalscale, ll, NULL); 825 } 826 /* scale the diagonal block */ 827 PetscUseTypeMethod(a, diagonalscale, ll, rr); 828 829 if (rr) { 830 /* Do a scatter end and then right scale the off-diagonal block */ 831 PetscCall(VecScatterEnd(sell->Mvctx, rr, sell->lvec, INSERT_VALUES, SCATTER_FORWARD)); 832 PetscUseTypeMethod(b, diagonalscale, NULL, sell->lvec); 833 } 834 PetscFunctionReturn(PETSC_SUCCESS); 835 } 836 837 static PetscErrorCode MatSetUnfactored_MPISELL(Mat A) 838 { 839 Mat_MPISELL *a = (Mat_MPISELL *)A->data; 840 841 PetscFunctionBegin; 842 PetscCall(MatSetUnfactored(a->A)); 843 PetscFunctionReturn(PETSC_SUCCESS); 844 } 845 846 static PetscErrorCode MatEqual_MPISELL(Mat A, Mat B, PetscBool *flag) 847 { 848 Mat_MPISELL *matB = (Mat_MPISELL *)B->data, *matA = (Mat_MPISELL *)A->data; 849 Mat a, b, c, d; 850 PetscBool flg; 851 852 PetscFunctionBegin; 853 a = matA->A; 854 b = matA->B; 855 c = matB->A; 856 d = matB->B; 857 858 PetscCall(MatEqual(a, c, &flg)); 859 if (flg) PetscCall(MatEqual(b, d, &flg)); 860 PetscCall(MPIU_Allreduce(&flg, flag, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A))); 861 PetscFunctionReturn(PETSC_SUCCESS); 862 } 863 864 static PetscErrorCode MatCopy_MPISELL(Mat A, Mat B, MatStructure str) 865 { 866 Mat_MPISELL *a = (Mat_MPISELL *)A->data; 867 Mat_MPISELL *b = (Mat_MPISELL *)B->data; 868 869 PetscFunctionBegin; 870 /* If the two matrices don't have the same copy implementation, they aren't compatible for fast copy. */ 871 if ((str != SAME_NONZERO_PATTERN) || (A->ops->copy != B->ops->copy)) { 872 /* because of the column compression in the off-processor part of the matrix a->B, 873 the number of columns in a->B and b->B may be different, hence we cannot call 874 the MatCopy() directly on the two parts. If need be, we can provide a more 875 efficient copy than the MatCopy_Basic() by first uncompressing the a->B matrices 876 then copying the submatrices */ 877 PetscCall(MatCopy_Basic(A, B, str)); 878 } else { 879 PetscCall(MatCopy(a->A, b->A, str)); 880 PetscCall(MatCopy(a->B, b->B, str)); 881 } 882 PetscFunctionReturn(PETSC_SUCCESS); 883 } 884 885 static PetscErrorCode MatSetUp_MPISELL(Mat A) 886 { 887 PetscFunctionBegin; 888 PetscCall(MatMPISELLSetPreallocation(A, PETSC_DEFAULT, NULL, PETSC_DEFAULT, NULL)); 889 PetscFunctionReturn(PETSC_SUCCESS); 890 } 891 892 static PetscErrorCode MatConjugate_MPISELL(Mat mat) 893 { 894 PetscFunctionBegin; 895 if (PetscDefined(USE_COMPLEX)) { 896 Mat_MPISELL *sell = (Mat_MPISELL *)mat->data; 897 898 PetscCall(MatConjugate_SeqSELL(sell->A)); 899 PetscCall(MatConjugate_SeqSELL(sell->B)); 900 } 901 PetscFunctionReturn(PETSC_SUCCESS); 902 } 903 904 static PetscErrorCode MatRealPart_MPISELL(Mat A) 905 { 906 Mat_MPISELL *a = (Mat_MPISELL *)A->data; 907 908 PetscFunctionBegin; 909 PetscCall(MatRealPart(a->A)); 910 PetscCall(MatRealPart(a->B)); 911 PetscFunctionReturn(PETSC_SUCCESS); 912 } 913 914 static PetscErrorCode MatImaginaryPart_MPISELL(Mat A) 915 { 916 Mat_MPISELL *a = (Mat_MPISELL *)A->data; 917 918 PetscFunctionBegin; 919 PetscCall(MatImaginaryPart(a->A)); 920 PetscCall(MatImaginaryPart(a->B)); 921 PetscFunctionReturn(PETSC_SUCCESS); 922 } 923 924 static PetscErrorCode MatInvertBlockDiagonal_MPISELL(Mat A, const PetscScalar **values) 925 { 926 Mat_MPISELL *a = (Mat_MPISELL *)A->data; 927 928 PetscFunctionBegin; 929 PetscCall(MatInvertBlockDiagonal(a->A, values)); 930 A->factorerrortype = a->A->factorerrortype; 931 PetscFunctionReturn(PETSC_SUCCESS); 932 } 933 934 static PetscErrorCode MatSetRandom_MPISELL(Mat x, PetscRandom rctx) 935 { 936 Mat_MPISELL *sell = (Mat_MPISELL *)x->data; 937 938 PetscFunctionBegin; 939 PetscCall(MatSetRandom(sell->A, rctx)); 940 PetscCall(MatSetRandom(sell->B, rctx)); 941 PetscCall(MatAssemblyBegin(x, MAT_FINAL_ASSEMBLY)); 942 PetscCall(MatAssemblyEnd(x, MAT_FINAL_ASSEMBLY)); 943 PetscFunctionReturn(PETSC_SUCCESS); 944 } 945 946 static PetscErrorCode MatSetFromOptions_MPISELL(Mat A, PetscOptionItems *PetscOptionsObject) 947 { 948 PetscFunctionBegin; 949 PetscOptionsHeadBegin(PetscOptionsObject, "MPISELL options"); 950 PetscOptionsHeadEnd(); 951 PetscFunctionReturn(PETSC_SUCCESS); 952 } 953 954 static PetscErrorCode MatShift_MPISELL(Mat Y, PetscScalar a) 955 { 956 Mat_MPISELL *msell = (Mat_MPISELL *)Y->data; 957 Mat_SeqSELL *sell = (Mat_SeqSELL *)msell->A->data; 958 959 PetscFunctionBegin; 960 if (!Y->preallocated) { 961 PetscCall(MatMPISELLSetPreallocation(Y, 1, NULL, 0, NULL)); 962 } else if (!sell->nz) { 963 PetscInt nonew = sell->nonew; 964 PetscCall(MatSeqSELLSetPreallocation(msell->A, 1, NULL)); 965 sell->nonew = nonew; 966 } 967 PetscCall(MatShift_Basic(Y, a)); 968 PetscFunctionReturn(PETSC_SUCCESS); 969 } 970 971 static PetscErrorCode MatMissingDiagonal_MPISELL(Mat A, PetscBool *missing, PetscInt *d) 972 { 973 Mat_MPISELL *a = (Mat_MPISELL *)A->data; 974 975 PetscFunctionBegin; 976 PetscCheck(A->rmap->n == A->cmap->n, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only works for square matrices"); 977 PetscCall(MatMissingDiagonal(a->A, missing, d)); 978 if (d) { 979 PetscInt rstart; 980 PetscCall(MatGetOwnershipRange(A, &rstart, NULL)); 981 *d += rstart; 982 } 983 PetscFunctionReturn(PETSC_SUCCESS); 984 } 985 986 static PetscErrorCode MatGetDiagonalBlock_MPISELL(Mat A, Mat *a) 987 { 988 PetscFunctionBegin; 989 *a = ((Mat_MPISELL *)A->data)->A; 990 PetscFunctionReturn(PETSC_SUCCESS); 991 } 992 993 static PetscErrorCode MatStoreValues_MPISELL(Mat mat) 994 { 995 Mat_MPISELL *sell = (Mat_MPISELL *)mat->data; 996 997 PetscFunctionBegin; 998 PetscCall(MatStoreValues(sell->A)); 999 PetscCall(MatStoreValues(sell->B)); 1000 PetscFunctionReturn(PETSC_SUCCESS); 1001 } 1002 1003 static PetscErrorCode MatRetrieveValues_MPISELL(Mat mat) 1004 { 1005 Mat_MPISELL *sell = (Mat_MPISELL *)mat->data; 1006 1007 PetscFunctionBegin; 1008 PetscCall(MatRetrieveValues(sell->A)); 1009 PetscCall(MatRetrieveValues(sell->B)); 1010 PetscFunctionReturn(PETSC_SUCCESS); 1011 } 1012 1013 static PetscErrorCode MatMPISELLSetPreallocation_MPISELL(Mat B, PetscInt d_rlenmax, const PetscInt d_rlen[], PetscInt o_rlenmax, const PetscInt o_rlen[]) 1014 { 1015 Mat_MPISELL *b; 1016 1017 PetscFunctionBegin; 1018 PetscCall(PetscLayoutSetUp(B->rmap)); 1019 PetscCall(PetscLayoutSetUp(B->cmap)); 1020 b = (Mat_MPISELL *)B->data; 1021 1022 if (!B->preallocated) { 1023 /* Explicitly create 2 MATSEQSELL matrices. */ 1024 PetscCall(MatCreate(PETSC_COMM_SELF, &b->A)); 1025 PetscCall(MatSetSizes(b->A, B->rmap->n, B->cmap->n, B->rmap->n, B->cmap->n)); 1026 PetscCall(MatSetBlockSizesFromMats(b->A, B, B)); 1027 PetscCall(MatSetType(b->A, MATSEQSELL)); 1028 PetscCall(MatCreate(PETSC_COMM_SELF, &b->B)); 1029 PetscCall(MatSetSizes(b->B, B->rmap->n, B->cmap->N, B->rmap->n, B->cmap->N)); 1030 PetscCall(MatSetBlockSizesFromMats(b->B, B, B)); 1031 PetscCall(MatSetType(b->B, MATSEQSELL)); 1032 } 1033 1034 PetscCall(MatSeqSELLSetPreallocation(b->A, d_rlenmax, d_rlen)); 1035 PetscCall(MatSeqSELLSetPreallocation(b->B, o_rlenmax, o_rlen)); 1036 B->preallocated = PETSC_TRUE; 1037 B->was_assembled = PETSC_FALSE; 1038 /* 1039 critical for MatAssemblyEnd to work. 1040 MatAssemblyBegin checks it to set up was_assembled 1041 and MatAssemblyEnd checks was_assembled to determine whether to build garray 1042 */ 1043 B->assembled = PETSC_FALSE; 1044 PetscFunctionReturn(PETSC_SUCCESS); 1045 } 1046 1047 static PetscErrorCode MatDuplicate_MPISELL(Mat matin, MatDuplicateOption cpvalues, Mat *newmat) 1048 { 1049 Mat mat; 1050 Mat_MPISELL *a, *oldmat = (Mat_MPISELL *)matin->data; 1051 1052 PetscFunctionBegin; 1053 *newmat = NULL; 1054 PetscCall(MatCreate(PetscObjectComm((PetscObject)matin), &mat)); 1055 PetscCall(MatSetSizes(mat, matin->rmap->n, matin->cmap->n, matin->rmap->N, matin->cmap->N)); 1056 PetscCall(MatSetBlockSizesFromMats(mat, matin, matin)); 1057 PetscCall(MatSetType(mat, ((PetscObject)matin)->type_name)); 1058 a = (Mat_MPISELL *)mat->data; 1059 1060 mat->factortype = matin->factortype; 1061 mat->assembled = PETSC_TRUE; 1062 mat->insertmode = NOT_SET_VALUES; 1063 mat->preallocated = PETSC_TRUE; 1064 1065 a->size = oldmat->size; 1066 a->rank = oldmat->rank; 1067 a->donotstash = oldmat->donotstash; 1068 a->roworiented = oldmat->roworiented; 1069 a->rowindices = NULL; 1070 a->rowvalues = NULL; 1071 a->getrowactive = PETSC_FALSE; 1072 1073 PetscCall(PetscLayoutReference(matin->rmap, &mat->rmap)); 1074 PetscCall(PetscLayoutReference(matin->cmap, &mat->cmap)); 1075 1076 if (oldmat->colmap) { 1077 #if defined(PETSC_USE_CTABLE) 1078 PetscCall(PetscHMapIDuplicate(oldmat->colmap, &a->colmap)); 1079 #else 1080 PetscCall(PetscMalloc1(mat->cmap->N, &a->colmap)); 1081 PetscCall(PetscArraycpy(a->colmap, oldmat->colmap, mat->cmap->N)); 1082 #endif 1083 } else a->colmap = NULL; 1084 if (oldmat->garray) { 1085 PetscInt len; 1086 len = oldmat->B->cmap->n; 1087 PetscCall(PetscMalloc1(len + 1, &a->garray)); 1088 if (len) PetscCall(PetscArraycpy(a->garray, oldmat->garray, len)); 1089 } else a->garray = NULL; 1090 1091 PetscCall(VecDuplicate(oldmat->lvec, &a->lvec)); 1092 PetscCall(VecScatterCopy(oldmat->Mvctx, &a->Mvctx)); 1093 PetscCall(MatDuplicate(oldmat->A, cpvalues, &a->A)); 1094 PetscCall(MatDuplicate(oldmat->B, cpvalues, &a->B)); 1095 PetscCall(PetscFunctionListDuplicate(((PetscObject)matin)->qlist, &((PetscObject)mat)->qlist)); 1096 *newmat = mat; 1097 PetscFunctionReturn(PETSC_SUCCESS); 1098 } 1099 1100 static const struct _MatOps MatOps_Values = {MatSetValues_MPISELL, 1101 NULL, 1102 NULL, 1103 MatMult_MPISELL, 1104 /* 4*/ MatMultAdd_MPISELL, 1105 MatMultTranspose_MPISELL, 1106 MatMultTransposeAdd_MPISELL, 1107 NULL, 1108 NULL, 1109 NULL, 1110 /*10*/ NULL, 1111 NULL, 1112 NULL, 1113 MatSOR_MPISELL, 1114 NULL, 1115 /*15*/ MatGetInfo_MPISELL, 1116 MatEqual_MPISELL, 1117 MatGetDiagonal_MPISELL, 1118 MatDiagonalScale_MPISELL, 1119 NULL, 1120 /*20*/ MatAssemblyBegin_MPISELL, 1121 MatAssemblyEnd_MPISELL, 1122 MatSetOption_MPISELL, 1123 MatZeroEntries_MPISELL, 1124 /*24*/ NULL, 1125 NULL, 1126 NULL, 1127 NULL, 1128 NULL, 1129 /*29*/ MatSetUp_MPISELL, 1130 NULL, 1131 NULL, 1132 MatGetDiagonalBlock_MPISELL, 1133 NULL, 1134 /*34*/ MatDuplicate_MPISELL, 1135 NULL, 1136 NULL, 1137 NULL, 1138 NULL, 1139 /*39*/ NULL, 1140 NULL, 1141 NULL, 1142 MatGetValues_MPISELL, 1143 MatCopy_MPISELL, 1144 /*44*/ NULL, 1145 MatScale_MPISELL, 1146 MatShift_MPISELL, 1147 MatDiagonalSet_MPISELL, 1148 NULL, 1149 /*49*/ MatSetRandom_MPISELL, 1150 NULL, 1151 NULL, 1152 NULL, 1153 NULL, 1154 /*54*/ MatFDColoringCreate_MPIXAIJ, 1155 NULL, 1156 MatSetUnfactored_MPISELL, 1157 NULL, 1158 NULL, 1159 /*59*/ NULL, 1160 MatDestroy_MPISELL, 1161 MatView_MPISELL, 1162 NULL, 1163 NULL, 1164 /*64*/ NULL, 1165 NULL, 1166 NULL, 1167 NULL, 1168 NULL, 1169 /*69*/ NULL, 1170 NULL, 1171 NULL, 1172 NULL, 1173 NULL, 1174 NULL, 1175 /*75*/ MatFDColoringApply_AIJ, /* reuse AIJ function */ 1176 MatSetFromOptions_MPISELL, 1177 NULL, 1178 NULL, 1179 NULL, 1180 /*80*/ NULL, 1181 NULL, 1182 NULL, 1183 /*83*/ NULL, 1184 NULL, 1185 NULL, 1186 NULL, 1187 NULL, 1188 NULL, 1189 /*89*/ NULL, 1190 NULL, 1191 NULL, 1192 NULL, 1193 NULL, 1194 /*94*/ NULL, 1195 NULL, 1196 NULL, 1197 NULL, 1198 NULL, 1199 /*99*/ NULL, 1200 NULL, 1201 NULL, 1202 MatConjugate_MPISELL, 1203 NULL, 1204 /*104*/ NULL, 1205 MatRealPart_MPISELL, 1206 MatImaginaryPart_MPISELL, 1207 NULL, 1208 NULL, 1209 /*109*/ NULL, 1210 NULL, 1211 NULL, 1212 NULL, 1213 MatMissingDiagonal_MPISELL, 1214 /*114*/ NULL, 1215 NULL, 1216 MatGetGhosts_MPISELL, 1217 NULL, 1218 NULL, 1219 /*119*/ MatMultDiagonalBlock_MPISELL, 1220 NULL, 1221 NULL, 1222 NULL, 1223 NULL, 1224 /*124*/ NULL, 1225 NULL, 1226 MatInvertBlockDiagonal_MPISELL, 1227 NULL, 1228 NULL, 1229 /*129*/ NULL, 1230 NULL, 1231 NULL, 1232 NULL, 1233 NULL, 1234 /*134*/ NULL, 1235 NULL, 1236 NULL, 1237 NULL, 1238 NULL, 1239 /*139*/ NULL, 1240 NULL, 1241 NULL, 1242 MatFDColoringSetUp_MPIXAIJ, 1243 NULL, 1244 /*144*/ NULL, 1245 NULL, 1246 NULL, 1247 NULL, 1248 NULL, 1249 NULL, 1250 /*150*/ NULL, 1251 NULL, 1252 NULL}; 1253 1254 /*@C 1255 MatMPISELLSetPreallocation - Preallocates memory for a `MATMPISELL` sparse parallel matrix in sell format. 1256 For good matrix assembly performance the user should preallocate the matrix storage by 1257 setting the parameters `d_nz` (or `d_nnz`) and `o_nz` (or `o_nnz`). 1258 1259 Collective 1260 1261 Input Parameters: 1262 + B - the matrix 1263 . d_nz - number of nonzeros per row in DIAGONAL portion of local submatrix 1264 (same value is used for all local rows) 1265 . d_nnz - array containing the number of nonzeros in the various rows of the 1266 DIAGONAL portion of the local submatrix (possibly different for each row) 1267 or NULL (`PETSC_NULL_INTEGER` in Fortran), if `d_nz` is used to specify the nonzero structure. 1268 The size of this array is equal to the number of local rows, i.e 'm'. 1269 For matrices that will be factored, you must leave room for (and set) 1270 the diagonal entry even if it is zero. 1271 . o_nz - number of nonzeros per row in the OFF-DIAGONAL portion of local 1272 submatrix (same value is used for all local rows). 1273 - o_nnz - array containing the number of nonzeros in the various rows of the 1274 OFF-DIAGONAL portion of the local submatrix (possibly different for 1275 each row) or NULL (`PETSC_NULL_INTEGER` in Fortran), if `o_nz` is used to specify the nonzero 1276 structure. The size of this array is equal to the number 1277 of local rows, i.e 'm'. 1278 1279 Example usage: 1280 Consider the following 8x8 matrix with 34 non-zero values, that is 1281 assembled across 3 processors. Lets assume that proc0 owns 3 rows, 1282 proc1 owns 3 rows, proc2 owns 2 rows. This division can be shown 1283 as follows 1284 1285 .vb 1286 1 2 0 | 0 3 0 | 0 4 1287 Proc0 0 5 6 | 7 0 0 | 8 0 1288 9 0 10 | 11 0 0 | 12 0 1289 ------------------------------------- 1290 13 0 14 | 15 16 17 | 0 0 1291 Proc1 0 18 0 | 19 20 21 | 0 0 1292 0 0 0 | 22 23 0 | 24 0 1293 ------------------------------------- 1294 Proc2 25 26 27 | 0 0 28 | 29 0 1295 30 0 0 | 31 32 33 | 0 34 1296 .ve 1297 1298 This can be represented as a collection of submatrices as 1299 1300 .vb 1301 A B C 1302 D E F 1303 G H I 1304 .ve 1305 1306 Where the submatrices A,B,C are owned by proc0, D,E,F are 1307 owned by proc1, G,H,I are owned by proc2. 1308 1309 The 'm' parameters for proc0,proc1,proc2 are 3,3,2 respectively. 1310 The 'n' parameters for proc0,proc1,proc2 are 3,3,2 respectively. 1311 The 'M','N' parameters are 8,8, and have the same values on all procs. 1312 1313 The DIAGONAL submatrices corresponding to proc0,proc1,proc2 are 1314 submatrices [A], [E], [I] respectively. The OFF-DIAGONAL submatrices 1315 corresponding to proc0,proc1,proc2 are [BC], [DF], [GH] respectively. 1316 Internally, each processor stores the DIAGONAL part, and the OFF-DIAGONAL 1317 part as `MATSEQSELL` matrices. For example, proc1 will store [E] as a `MATSEQSELL` 1318 matrix, ans [DF] as another SeqSELL matrix. 1319 1320 When `d_nz`, `o_nz` parameters are specified, `d_nz` storage elements are 1321 allocated for every row of the local diagonal submatrix, and o_nz 1322 storage locations are allocated for every row of the OFF-DIAGONAL submat. 1323 One way to choose `d_nz` and `o_nz` is to use the max nonzerors per local 1324 rows for each of the local DIAGONAL, and the OFF-DIAGONAL submatrices. 1325 In this case, the values of d_nz,o_nz are 1326 .vb 1327 proc0 dnz = 2, o_nz = 2 1328 proc1 dnz = 3, o_nz = 2 1329 proc2 dnz = 1, o_nz = 4 1330 .ve 1331 We are allocating m*(d_nz+o_nz) storage locations for every proc. This 1332 translates to 3*(2+2)=12 for proc0, 3*(3+2)=15 for proc1, 2*(1+4)=10 1333 for proc3. i.e we are using 12+15+10=37 storage locations to store 1334 34 values. 1335 1336 When `d_nnz`, `o_nnz` parameters are specified, the storage is specified 1337 for every row, corresponding to both DIAGONAL and OFF-DIAGONAL submatrices. 1338 In the above case the values for d_nnz,o_nnz are 1339 .vb 1340 proc0 d_nnz = [2,2,2] and o_nnz = [2,2,2] 1341 proc1 d_nnz = [3,3,2] and o_nnz = [2,1,1] 1342 proc2 d_nnz = [1,1] and o_nnz = [4,4] 1343 .ve 1344 Here the space allocated is according to nz (or maximum values in the nnz 1345 if nnz is provided) for DIAGONAL and OFF-DIAGONAL submatrices, i.e (2+2+3+2)*3+(1+4)*2=37 1346 1347 Level: intermediate 1348 1349 Notes: 1350 If the *_nnz parameter is given then the *_nz parameter is ignored 1351 1352 The stored row and column indices begin with zero. 1353 1354 The parallel matrix is partitioned such that the first m0 rows belong to 1355 process 0, the next m1 rows belong to process 1, the next m2 rows belong 1356 to process 2 etc.. where m0,m1,m2... are the input parameter 'm'. 1357 1358 The DIAGONAL portion of the local submatrix of a processor can be defined 1359 as the submatrix which is obtained by extraction the part corresponding to 1360 the rows r1-r2 and columns c1-c2 of the global matrix, where r1 is the 1361 first row that belongs to the processor, r2 is the last row belonging to 1362 the this processor, and c1-c2 is range of indices of the local part of a 1363 vector suitable for applying the matrix to. This is an mxn matrix. In the 1364 common case of a square matrix, the row and column ranges are the same and 1365 the DIAGONAL part is also square. The remaining portion of the local 1366 submatrix (mxN) constitute the OFF-DIAGONAL portion. 1367 1368 If `o_nnz`, `d_nnz` are specified, then `o_nz`, and `d_nz` are ignored. 1369 1370 You can call `MatGetInfo()` to get information on how effective the preallocation was; 1371 for example the fields mallocs,nz_allocated,nz_used,nz_unneeded; 1372 You can also run with the option -info and look for messages with the string 1373 malloc in them to see if additional memory allocation was needed. 1374 1375 .seealso: `Mat`, `MatCreate()`, `MatCreateSeqSELL()`, `MatSetValues()`, `MatCreatesell()`, 1376 `MATMPISELL`, `MatGetInfo()`, `PetscSplitOwnership()`, `MATSELL` 1377 @*/ 1378 PetscErrorCode MatMPISELLSetPreallocation(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[]) 1379 { 1380 PetscFunctionBegin; 1381 PetscValidHeaderSpecific(B, MAT_CLASSID, 1); 1382 PetscValidType(B, 1); 1383 PetscTryMethod(B, "MatMPISELLSetPreallocation_C", (Mat, PetscInt, const PetscInt[], PetscInt, const PetscInt[]), (B, d_nz, d_nnz, o_nz, o_nnz)); 1384 PetscFunctionReturn(PETSC_SUCCESS); 1385 } 1386 1387 /*MC 1388 MATMPISELL - MATMPISELL = "mpisell" - A matrix type to be used for MPI sparse matrices, 1389 based on the sliced Ellpack format 1390 1391 Options Database Key: 1392 . -mat_type sell - sets the matrix type to `MATSELL` during a call to `MatSetFromOptions()` 1393 1394 Level: beginner 1395 1396 .seealso: `Mat`, `MatCreateSell()`, `MATSEQSELL`, `MATSELL`, `MATSEQAIJ`, `MATAIJ`, `MATMPIAIJ` 1397 M*/ 1398 1399 /*@C 1400 MatCreateSELL - Creates a sparse parallel matrix in `MATSELL` format. 1401 1402 Collective 1403 1404 Input Parameters: 1405 + comm - MPI communicator 1406 . m - number of local rows (or `PETSC_DECIDE` to have calculated if M is given) 1407 This value should be the same as the local size used in creating the 1408 y vector for the matrix-vector product y = Ax. 1409 . n - This value should be the same as the local size used in creating the 1410 x vector for the matrix-vector product y = Ax. (or `PETSC_DECIDE` to have 1411 calculated if `N` is given) For square matrices n is almost always `m`. 1412 . M - number of global rows (or `PETSC_DETERMINE` to have calculated if `m` is given) 1413 . N - number of global columns (or `PETSC_DETERMINE` to have calculated if `n` is given) 1414 . d_rlenmax - max number of nonzeros per row in DIAGONAL portion of local submatrix 1415 (same value is used for all local rows) 1416 . d_rlen - array containing the number of nonzeros in the various rows of the 1417 DIAGONAL portion of the local submatrix (possibly different for each row) 1418 or `NULL`, if d_rlenmax is used to specify the nonzero structure. 1419 The size of this array is equal to the number of local rows, i.e `m`. 1420 . o_rlenmax - max number of nonzeros per row in the OFF-DIAGONAL portion of local 1421 submatrix (same value is used for all local rows). 1422 - o_rlen - array containing the number of nonzeros in the various rows of the 1423 OFF-DIAGONAL portion of the local submatrix (possibly different for 1424 each row) or `NULL`, if `o_rlenmax` is used to specify the nonzero 1425 structure. The size of this array is equal to the number 1426 of local rows, i.e `m`. 1427 1428 Output Parameter: 1429 . A - the matrix 1430 1431 Options Database Key: 1432 . -mat_sell_oneindex - Internally use indexing starting at 1 1433 rather than 0. When calling `MatSetValues()`, 1434 the user still MUST index entries starting at 0! 1435 1436 Example: 1437 Consider the following 8x8 matrix with 34 non-zero values, that is 1438 assembled across 3 processors. Lets assume that proc0 owns 3 rows, 1439 proc1 owns 3 rows, proc2 owns 2 rows. This division can be shown 1440 as follows 1441 1442 .vb 1443 1 2 0 | 0 3 0 | 0 4 1444 Proc0 0 5 6 | 7 0 0 | 8 0 1445 9 0 10 | 11 0 0 | 12 0 1446 ------------------------------------- 1447 13 0 14 | 15 16 17 | 0 0 1448 Proc1 0 18 0 | 19 20 21 | 0 0 1449 0 0 0 | 22 23 0 | 24 0 1450 ------------------------------------- 1451 Proc2 25 26 27 | 0 0 28 | 29 0 1452 30 0 0 | 31 32 33 | 0 34 1453 .ve 1454 1455 This can be represented as a collection of submatrices as 1456 .vb 1457 A B C 1458 D E F 1459 G H I 1460 .ve 1461 1462 Where the submatrices A,B,C are owned by proc0, D,E,F are 1463 owned by proc1, G,H,I are owned by proc2. 1464 1465 The 'm' parameters for proc0,proc1,proc2 are 3,3,2 respectively. 1466 The 'n' parameters for proc0,proc1,proc2 are 3,3,2 respectively. 1467 The 'M','N' parameters are 8,8, and have the same values on all procs. 1468 1469 The DIAGONAL submatrices corresponding to proc0,proc1,proc2 are 1470 submatrices [A], [E], [I] respectively. The OFF-DIAGONAL submatrices 1471 corresponding to proc0,proc1,proc2 are [BC], [DF], [GH] respectively. 1472 Internally, each processor stores the DIAGONAL part, and the OFF-DIAGONAL 1473 part as `MATSEQSELL` matrices. For example, proc1 will store [E] as a `MATSEQSELL` 1474 matrix, ans [DF] as another `MATSEQSELL` matrix. 1475 1476 When d_rlenmax, o_rlenmax parameters are specified, d_rlenmax storage elements are 1477 allocated for every row of the local diagonal submatrix, and o_rlenmax 1478 storage locations are allocated for every row of the OFF-DIAGONAL submat. 1479 One way to choose d_rlenmax and o_rlenmax is to use the max nonzerors per local 1480 rows for each of the local DIAGONAL, and the OFF-DIAGONAL submatrices. 1481 In this case, the values of d_rlenmax,o_rlenmax are 1482 .vb 1483 proc0 - d_rlenmax = 2, o_rlenmax = 2 1484 proc1 - d_rlenmax = 3, o_rlenmax = 2 1485 proc2 - d_rlenmax = 1, o_rlenmax = 4 1486 .ve 1487 We are allocating m*(d_rlenmax+o_rlenmax) storage locations for every proc. This 1488 translates to 3*(2+2)=12 for proc0, 3*(3+2)=15 for proc1, 2*(1+4)=10 1489 for proc3. i.e we are using 12+15+10=37 storage locations to store 1490 34 values. 1491 1492 When `d_rlen`, `o_rlen` parameters are specified, the storage is specified 1493 for every row, corresponding to both DIAGONAL and OFF-DIAGONAL submatrices. 1494 In the above case the values for `d_nnz`, `o_nnz` are 1495 .vb 1496 proc0 - d_nnz = [2,2,2] and o_nnz = [2,2,2] 1497 proc1 - d_nnz = [3,3,2] and o_nnz = [2,1,1] 1498 proc2 - d_nnz = [1,1] and o_nnz = [4,4] 1499 .ve 1500 Here the space allocated is still 37 though there are 34 nonzeros because 1501 the allocation is always done according to rlenmax. 1502 1503 Level: intermediate 1504 1505 Notes: 1506 It is recommended that one use the `MatCreate()`, `MatSetType()` and/or `MatSetFromOptions()`, 1507 MatXXXXSetPreallocation() paradigm instead of this routine directly. 1508 [MatXXXXSetPreallocation() is, for example, `MatSeqSELLSetPreallocation()`] 1509 1510 If the *_rlen parameter is given then the *_rlenmax parameter is ignored 1511 1512 `m`, `n`, `M`, `N` parameters specify the size of the matrix, and its partitioning across 1513 processors, while `d_rlenmax`, `d_rlen`, `o_rlenmax` , `o_rlen` parameters specify the approximate 1514 storage requirements for this matrix. 1515 1516 If `PETSC_DECIDE` or `PETSC_DETERMINE` is used for a particular argument on one 1517 processor than it must be used on all processors that share the object for 1518 that argument. 1519 1520 The user MUST specify either the local or global matrix dimensions 1521 (possibly both). 1522 1523 The parallel matrix is partitioned across processors such that the 1524 first m0 rows belong to process 0, the next m1 rows belong to 1525 process 1, the next m2 rows belong to process 2 etc.. where 1526 m0,m1,m2,.. are the input parameter 'm'. i.e each processor stores 1527 values corresponding to [`m` x `N`] submatrix. 1528 1529 The columns are logically partitioned with the n0 columns belonging 1530 to 0th partition, the next n1 columns belonging to the next 1531 partition etc.. where n0,n1,n2... are the input parameter `n`. 1532 1533 The DIAGONAL portion of the local submatrix on any given processor 1534 is the submatrix corresponding to the rows and columns `m`, `n` 1535 corresponding to the given processor. i.e diagonal matrix on 1536 process 0 is [m0 x n0], diagonal matrix on process 1 is [m1 x n1] 1537 etc. The remaining portion of the local submatrix [m x (N-n)] 1538 constitute the OFF-DIAGONAL portion. The example below better 1539 illustrates this concept. 1540 1541 For a square global matrix we define each processor's diagonal portion 1542 to be its local rows and the corresponding columns (a square submatrix); 1543 each processor's off-diagonal portion encompasses the remainder of the 1544 local matrix (a rectangular submatrix). 1545 1546 If `o_rlen`, `d_rlen` are specified, then `o_rlenmax`, and `d_rlenmax` are ignored. 1547 1548 When calling this routine with a single process communicator, a matrix of 1549 type `MATSEQSELL` is returned. If a matrix of type `MATMPISELL` is desired for this 1550 type of communicator, use the construction mechanism 1551 .vb 1552 MatCreate(...,&A); 1553 MatSetType(A,MATMPISELL); 1554 MatSetSizes(A, m,n,M,N); 1555 MatMPISELLSetPreallocation(A,...); 1556 .ve 1557 1558 .seealso: `Mat`, `MATSELL`, `MatCreate()`, `MatCreateSeqSELL()`, `MatSetValues()`, `MatMPISELLSetPreallocation()`, `MatMPISELLSetPreallocationSELL()`, 1559 `MATMPISELL`, `MatCreateMPISELLWithArrays()` 1560 @*/ 1561 PetscErrorCode MatCreateSELL(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt M, PetscInt N, PetscInt d_rlenmax, const PetscInt d_rlen[], PetscInt o_rlenmax, const PetscInt o_rlen[], Mat *A) 1562 { 1563 PetscMPIInt size; 1564 1565 PetscFunctionBegin; 1566 PetscCall(MatCreate(comm, A)); 1567 PetscCall(MatSetSizes(*A, m, n, M, N)); 1568 PetscCallMPI(MPI_Comm_size(comm, &size)); 1569 if (size > 1) { 1570 PetscCall(MatSetType(*A, MATMPISELL)); 1571 PetscCall(MatMPISELLSetPreallocation(*A, d_rlenmax, d_rlen, o_rlenmax, o_rlen)); 1572 } else { 1573 PetscCall(MatSetType(*A, MATSEQSELL)); 1574 PetscCall(MatSeqSELLSetPreallocation(*A, d_rlenmax, d_rlen)); 1575 } 1576 PetscFunctionReturn(PETSC_SUCCESS); 1577 } 1578 1579 /*@C 1580 MatMPISELLGetSeqSELL - Returns the local pieces of this distributed matrix 1581 1582 Not Collective 1583 1584 Input Parameter: 1585 . A - the `MATMPISELL` matrix 1586 1587 Output Parameters: 1588 + Ad - The diagonal portion of `A` 1589 . Ao - The off-diagonal portion of `A` 1590 - colmap - An array mapping local column numbers of `Ao` to global column numbers of the parallel matrix 1591 1592 Level: advanced 1593 1594 .seealso: `Mat`, `MATSEQSELL`, `MATMPISELL` 1595 @*/ 1596 PetscErrorCode MatMPISELLGetSeqSELL(Mat A, Mat *Ad, Mat *Ao, const PetscInt *colmap[]) 1597 { 1598 Mat_MPISELL *a = (Mat_MPISELL *)A->data; 1599 PetscBool flg; 1600 1601 PetscFunctionBegin; 1602 PetscCall(PetscObjectTypeCompare((PetscObject)A, MATMPISELL, &flg)); 1603 PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "This function requires a MATMPISELL matrix as input"); 1604 if (Ad) *Ad = a->A; 1605 if (Ao) *Ao = a->B; 1606 if (colmap) *colmap = a->garray; 1607 PetscFunctionReturn(PETSC_SUCCESS); 1608 } 1609 1610 /*@C 1611 MatMPISELLGetLocalMatCondensed - Creates a `MATSEQSELL` matrix from an `MATMPISELL` matrix by 1612 taking all its local rows and NON-ZERO columns 1613 1614 Not Collective 1615 1616 Input Parameters: 1617 + A - the matrix 1618 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX` 1619 . row - index sets of rows to extract (or `NULL`) 1620 - col - index sets of columns to extract (or `NULL`) 1621 1622 Output Parameter: 1623 . A_loc - the local sequential matrix generated 1624 1625 Level: advanced 1626 1627 .seealso: `Mat`, `MATSEQSELL`, `MATMPISELL`, `MatGetOwnershipRange()`, `MatMPISELLGetLocalMat()` 1628 @*/ 1629 PetscErrorCode MatMPISELLGetLocalMatCondensed(Mat A, MatReuse scall, IS *row, IS *col, Mat *A_loc) 1630 { 1631 Mat_MPISELL *a = (Mat_MPISELL *)A->data; 1632 PetscInt i, start, end, ncols, nzA, nzB, *cmap, imark, *idx; 1633 IS isrowa, iscola; 1634 Mat *aloc; 1635 PetscBool match; 1636 1637 PetscFunctionBegin; 1638 PetscCall(PetscObjectTypeCompare((PetscObject)A, MATMPISELL, &match)); 1639 PetscCheck(match, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Requires MATMPISELL matrix as input"); 1640 PetscCall(PetscLogEventBegin(MAT_Getlocalmatcondensed, A, 0, 0, 0)); 1641 if (!row) { 1642 start = A->rmap->rstart; 1643 end = A->rmap->rend; 1644 PetscCall(ISCreateStride(PETSC_COMM_SELF, end - start, start, 1, &isrowa)); 1645 } else { 1646 isrowa = *row; 1647 } 1648 if (!col) { 1649 start = A->cmap->rstart; 1650 cmap = a->garray; 1651 nzA = a->A->cmap->n; 1652 nzB = a->B->cmap->n; 1653 PetscCall(PetscMalloc1(nzA + nzB, &idx)); 1654 ncols = 0; 1655 for (i = 0; i < nzB; i++) { 1656 if (cmap[i] < start) idx[ncols++] = cmap[i]; 1657 else break; 1658 } 1659 imark = i; 1660 for (i = 0; i < nzA; i++) idx[ncols++] = start + i; 1661 for (i = imark; i < nzB; i++) idx[ncols++] = cmap[i]; 1662 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ncols, idx, PETSC_OWN_POINTER, &iscola)); 1663 } else { 1664 iscola = *col; 1665 } 1666 if (scall != MAT_INITIAL_MATRIX) { 1667 PetscCall(PetscMalloc1(1, &aloc)); 1668 aloc[0] = *A_loc; 1669 } 1670 PetscCall(MatCreateSubMatrices(A, 1, &isrowa, &iscola, scall, &aloc)); 1671 *A_loc = aloc[0]; 1672 PetscCall(PetscFree(aloc)); 1673 if (!row) PetscCall(ISDestroy(&isrowa)); 1674 if (!col) PetscCall(ISDestroy(&iscola)); 1675 PetscCall(PetscLogEventEnd(MAT_Getlocalmatcondensed, A, 0, 0, 0)); 1676 PetscFunctionReturn(PETSC_SUCCESS); 1677 } 1678 1679 #include <../src/mat/impls/aij/mpi/mpiaij.h> 1680 1681 PetscErrorCode MatConvert_MPISELL_MPIAIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) 1682 { 1683 Mat_MPISELL *a = (Mat_MPISELL *)A->data; 1684 Mat B; 1685 Mat_MPIAIJ *b; 1686 1687 PetscFunctionBegin; 1688 PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Matrix must be assembled"); 1689 1690 if (reuse == MAT_REUSE_MATRIX) { 1691 B = *newmat; 1692 } else { 1693 PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &B)); 1694 PetscCall(MatSetType(B, MATMPIAIJ)); 1695 PetscCall(MatSetSizes(B, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N)); 1696 PetscCall(MatSetBlockSizes(B, A->rmap->bs, A->cmap->bs)); 1697 PetscCall(MatSeqAIJSetPreallocation(B, 0, NULL)); 1698 PetscCall(MatMPIAIJSetPreallocation(B, 0, NULL, 0, NULL)); 1699 } 1700 b = (Mat_MPIAIJ *)B->data; 1701 1702 if (reuse == MAT_REUSE_MATRIX) { 1703 PetscCall(MatConvert_SeqSELL_SeqAIJ(a->A, MATSEQAIJ, MAT_REUSE_MATRIX, &b->A)); 1704 PetscCall(MatConvert_SeqSELL_SeqAIJ(a->B, MATSEQAIJ, MAT_REUSE_MATRIX, &b->B)); 1705 } else { 1706 PetscCall(MatDestroy(&b->A)); 1707 PetscCall(MatDestroy(&b->B)); 1708 PetscCall(MatDisAssemble_MPISELL(A)); 1709 PetscCall(MatConvert_SeqSELL_SeqAIJ(a->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &b->A)); 1710 PetscCall(MatConvert_SeqSELL_SeqAIJ(a->B, MATSEQAIJ, MAT_INITIAL_MATRIX, &b->B)); 1711 PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY)); 1712 PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY)); 1713 PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY)); 1714 PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY)); 1715 } 1716 1717 if (reuse == MAT_INPLACE_MATRIX) { 1718 PetscCall(MatHeaderReplace(A, &B)); 1719 } else { 1720 *newmat = B; 1721 } 1722 PetscFunctionReturn(PETSC_SUCCESS); 1723 } 1724 1725 PetscErrorCode MatConvert_MPIAIJ_MPISELL(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) 1726 { 1727 Mat_MPIAIJ *a = (Mat_MPIAIJ *)A->data; 1728 Mat B; 1729 Mat_MPISELL *b; 1730 1731 PetscFunctionBegin; 1732 PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Matrix must be assembled"); 1733 1734 if (reuse == MAT_REUSE_MATRIX) { 1735 B = *newmat; 1736 } else { 1737 Mat_SeqAIJ *Aa = (Mat_SeqAIJ *)a->A->data, *Ba = (Mat_SeqAIJ *)a->B->data; 1738 PetscInt i, d_nz = 0, o_nz = 0, m = A->rmap->N, n = A->cmap->N, lm = A->rmap->n, ln = A->cmap->n; 1739 PetscInt *d_nnz, *o_nnz; 1740 PetscCall(PetscMalloc2(lm, &d_nnz, lm, &o_nnz)); 1741 for (i = 0; i < lm; i++) { 1742 d_nnz[i] = Aa->i[i + 1] - Aa->i[i]; 1743 o_nnz[i] = Ba->i[i + 1] - Ba->i[i]; 1744 if (d_nnz[i] > d_nz) d_nz = d_nnz[i]; 1745 if (o_nnz[i] > o_nz) o_nz = o_nnz[i]; 1746 } 1747 PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &B)); 1748 PetscCall(MatSetType(B, MATMPISELL)); 1749 PetscCall(MatSetSizes(B, lm, ln, m, n)); 1750 PetscCall(MatSetBlockSizes(B, A->rmap->bs, A->cmap->bs)); 1751 PetscCall(MatSeqSELLSetPreallocation(B, d_nz, d_nnz)); 1752 PetscCall(MatMPISELLSetPreallocation(B, d_nz, d_nnz, o_nz, o_nnz)); 1753 PetscCall(PetscFree2(d_nnz, o_nnz)); 1754 } 1755 b = (Mat_MPISELL *)B->data; 1756 1757 if (reuse == MAT_REUSE_MATRIX) { 1758 PetscCall(MatConvert_SeqAIJ_SeqSELL(a->A, MATSEQSELL, MAT_REUSE_MATRIX, &b->A)); 1759 PetscCall(MatConvert_SeqAIJ_SeqSELL(a->B, MATSEQSELL, MAT_REUSE_MATRIX, &b->B)); 1760 } else { 1761 PetscCall(MatDestroy(&b->A)); 1762 PetscCall(MatDestroy(&b->B)); 1763 PetscCall(MatConvert_SeqAIJ_SeqSELL(a->A, MATSEQSELL, MAT_INITIAL_MATRIX, &b->A)); 1764 PetscCall(MatConvert_SeqAIJ_SeqSELL(a->B, MATSEQSELL, MAT_INITIAL_MATRIX, &b->B)); 1765 PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY)); 1766 PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY)); 1767 PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY)); 1768 PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY)); 1769 } 1770 1771 if (reuse == MAT_INPLACE_MATRIX) { 1772 PetscCall(MatHeaderReplace(A, &B)); 1773 } else { 1774 *newmat = B; 1775 } 1776 PetscFunctionReturn(PETSC_SUCCESS); 1777 } 1778 1779 PetscErrorCode MatSOR_MPISELL(Mat matin, Vec bb, PetscReal omega, MatSORType flag, PetscReal fshift, PetscInt its, PetscInt lits, Vec xx) 1780 { 1781 Mat_MPISELL *mat = (Mat_MPISELL *)matin->data; 1782 Vec bb1 = NULL; 1783 1784 PetscFunctionBegin; 1785 if (flag == SOR_APPLY_UPPER) { 1786 PetscCall((*mat->A->ops->sor)(mat->A, bb, omega, flag, fshift, lits, 1, xx)); 1787 PetscFunctionReturn(PETSC_SUCCESS); 1788 } 1789 1790 if (its > 1 || ~flag & SOR_ZERO_INITIAL_GUESS || flag & SOR_EISENSTAT) PetscCall(VecDuplicate(bb, &bb1)); 1791 1792 if ((flag & SOR_LOCAL_SYMMETRIC_SWEEP) == SOR_LOCAL_SYMMETRIC_SWEEP) { 1793 if (flag & SOR_ZERO_INITIAL_GUESS) { 1794 PetscCall((*mat->A->ops->sor)(mat->A, bb, omega, flag, fshift, lits, 1, xx)); 1795 its--; 1796 } 1797 1798 while (its--) { 1799 PetscCall(VecScatterBegin(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD)); 1800 PetscCall(VecScatterEnd(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD)); 1801 1802 /* update rhs: bb1 = bb - B*x */ 1803 PetscCall(VecScale(mat->lvec, -1.0)); 1804 PetscCall((*mat->B->ops->multadd)(mat->B, mat->lvec, bb, bb1)); 1805 1806 /* local sweep */ 1807 PetscCall((*mat->A->ops->sor)(mat->A, bb1, omega, SOR_SYMMETRIC_SWEEP, fshift, lits, 1, xx)); 1808 } 1809 } else if (flag & SOR_LOCAL_FORWARD_SWEEP) { 1810 if (flag & SOR_ZERO_INITIAL_GUESS) { 1811 PetscCall((*mat->A->ops->sor)(mat->A, bb, omega, flag, fshift, lits, 1, xx)); 1812 its--; 1813 } 1814 while (its--) { 1815 PetscCall(VecScatterBegin(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD)); 1816 PetscCall(VecScatterEnd(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD)); 1817 1818 /* update rhs: bb1 = bb - B*x */ 1819 PetscCall(VecScale(mat->lvec, -1.0)); 1820 PetscCall((*mat->B->ops->multadd)(mat->B, mat->lvec, bb, bb1)); 1821 1822 /* local sweep */ 1823 PetscCall((*mat->A->ops->sor)(mat->A, bb1, omega, SOR_FORWARD_SWEEP, fshift, lits, 1, xx)); 1824 } 1825 } else if (flag & SOR_LOCAL_BACKWARD_SWEEP) { 1826 if (flag & SOR_ZERO_INITIAL_GUESS) { 1827 PetscCall((*mat->A->ops->sor)(mat->A, bb, omega, flag, fshift, lits, 1, xx)); 1828 its--; 1829 } 1830 while (its--) { 1831 PetscCall(VecScatterBegin(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD)); 1832 PetscCall(VecScatterEnd(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD)); 1833 1834 /* update rhs: bb1 = bb - B*x */ 1835 PetscCall(VecScale(mat->lvec, -1.0)); 1836 PetscCall((*mat->B->ops->multadd)(mat->B, mat->lvec, bb, bb1)); 1837 1838 /* local sweep */ 1839 PetscCall((*mat->A->ops->sor)(mat->A, bb1, omega, SOR_BACKWARD_SWEEP, fshift, lits, 1, xx)); 1840 } 1841 } else SETERRQ(PetscObjectComm((PetscObject)matin), PETSC_ERR_SUP, "Parallel SOR not supported"); 1842 1843 PetscCall(VecDestroy(&bb1)); 1844 1845 matin->factorerrortype = mat->A->factorerrortype; 1846 PetscFunctionReturn(PETSC_SUCCESS); 1847 } 1848 1849 #if defined(PETSC_HAVE_CUDA) 1850 PETSC_INTERN PetscErrorCode MatConvert_MPISELL_MPISELLCUDA(Mat, MatType, MatReuse, Mat *); 1851 #endif 1852 1853 /*MC 1854 MATMPISELL - MATMPISELL = "MPISELL" - A matrix type to be used for parallel sparse matrices. 1855 1856 Options Database Keys: 1857 . -mat_type mpisell - sets the matrix type to `MATMPISELL` during a call to `MatSetFromOptions()` 1858 1859 Level: beginner 1860 1861 .seealso: `Mat`, `MATSELL`, `MATSEQSELL` `MatCreateSELL()` 1862 M*/ 1863 PETSC_EXTERN PetscErrorCode MatCreate_MPISELL(Mat B) 1864 { 1865 Mat_MPISELL *b; 1866 PetscMPIInt size; 1867 1868 PetscFunctionBegin; 1869 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)B), &size)); 1870 PetscCall(PetscNew(&b)); 1871 B->data = (void *)b; 1872 B->ops[0] = MatOps_Values; 1873 B->assembled = PETSC_FALSE; 1874 B->insertmode = NOT_SET_VALUES; 1875 b->size = size; 1876 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)B), &b->rank)); 1877 /* build cache for off array entries formed */ 1878 PetscCall(MatStashCreate_Private(PetscObjectComm((PetscObject)B), 1, &B->stash)); 1879 1880 b->donotstash = PETSC_FALSE; 1881 b->colmap = NULL; 1882 b->garray = NULL; 1883 b->roworiented = PETSC_TRUE; 1884 1885 /* stuff used for matrix vector multiply */ 1886 b->lvec = NULL; 1887 b->Mvctx = NULL; 1888 1889 /* stuff for MatGetRow() */ 1890 b->rowindices = NULL; 1891 b->rowvalues = NULL; 1892 b->getrowactive = PETSC_FALSE; 1893 1894 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatStoreValues_C", MatStoreValues_MPISELL)); 1895 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatRetrieveValues_C", MatRetrieveValues_MPISELL)); 1896 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatIsTranspose_C", MatIsTranspose_MPISELL)); 1897 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatMPISELLSetPreallocation_C", MatMPISELLSetPreallocation_MPISELL)); 1898 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_mpisell_mpiaij_C", MatConvert_MPISELL_MPIAIJ)); 1899 #if defined(PETSC_HAVE_CUDA) 1900 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_mpisell_mpisellcuda_C", MatConvert_MPISELL_MPISELLCUDA)); 1901 #endif 1902 PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatDiagonalScaleLocal_C", MatDiagonalScaleLocal_MPISELL)); 1903 PetscCall(PetscObjectChangeTypeName((PetscObject)B, MATMPISELL)); 1904 PetscFunctionReturn(PETSC_SUCCESS); 1905 } 1906